--------------------- PatchSet 6616 Date: 2008/01/22 11:15:27 Author: serassio Branch: nt Tag: (none) Log: Manually merge of missing changes from HEAD. May be a crashed cvsmerge ? Members: src/ChunkedCodingParser.cc:1.2.4.1->1.2.4.2 src/ChunkedCodingParser.h:1.2.4.1->1.2.4.2 src/TextException.cc:1.2.4.1->1.2.4.2 src/TextException.h:1.2.4.1->1.2.4.2 --- /dev/null Wed Jan 23 01:24:23 2008 +++ squid3/src/ChunkedCodingParser.cc Wed Jan 23 01:24:23 2008 @@ -0,0 +1,232 @@ +#include "squid.h" +#include "Parsing.h" +#include "TextException.h" +#include "ChunkedCodingParser.h" +#include "MemBuf.h" + +ChunkedCodingParser::Step ChunkedCodingParser::psChunkBeg = &ChunkedCodingParser::parseChunkBeg; +ChunkedCodingParser::Step ChunkedCodingParser::psChunkBody = &ChunkedCodingParser::parseChunkBody; +ChunkedCodingParser::Step ChunkedCodingParser::psChunkEnd = &ChunkedCodingParser::parseChunkEnd; +ChunkedCodingParser::Step ChunkedCodingParser::psTrailer = &ChunkedCodingParser::parseTrailer; +ChunkedCodingParser::Step ChunkedCodingParser::psMessageEnd = &ChunkedCodingParser::parseMessageEnd; + +ChunkedCodingParser::ChunkedCodingParser() +{ + reset(); +} + +void ChunkedCodingParser::reset() +{ + theStep = psChunkBeg; + theChunkSize = theLeftBodySize = 0; + doNeedMoreData = false; + theIn = theOut = NULL; +} + +bool ChunkedCodingParser::parse(MemBuf *rawData, MemBuf *parsedContent) +{ + Must(rawData && parsedContent); + theIn = rawData; + theOut = parsedContent; + + // we must reset this all the time so that mayContinue() lets us + // output more content if we stopped due to needsMoreSpace() before + doNeedMoreData = !theIn->hasContent(); + + while (mayContinue()) { + (this->*theStep)(); + } + + return theStep == psMessageEnd; +} + +bool ChunkedCodingParser::needsMoreData() const +{ + return doNeedMoreData; +} + +bool ChunkedCodingParser::needsMoreSpace() const +{ + assert(theOut); + return theStep == psChunkBody && !theOut->hasPotentialSpace(); +} + +bool ChunkedCodingParser::mayContinue() const +{ + return !needsMoreData() && !needsMoreSpace() && theStep != psMessageEnd; +} + +void ChunkedCodingParser::parseChunkBeg() +{ + Must(theChunkSize <= 0); // Should(), really + + size_t crlfBeg = 0; + size_t crlfEnd = 0; + + if (findCrlf(crlfBeg, crlfEnd)) { + debugs(94,7, "found chunk-size end: " << crlfBeg << "-" << crlfEnd); + int64_t size = -1; + const char *p = 0; + + if (StringToInt64(theIn->content(), size, &p, 16)) { + if (size < 0) { + throw TexcHere("negative chunk size"); + return; + } + + theIn->consume(crlfEnd); + theChunkSize = theLeftBodySize = size; + debugs(94,7, "found chunk: " << theChunkSize); + theStep = theChunkSize == 0 ? psTrailer : psChunkBody; + return; + } + + throw TexcHere("corrupted chunk size"); + } + + doNeedMoreData = true; +} + +void ChunkedCodingParser::parseChunkBody() +{ + Must(theLeftBodySize > 0); // Should, really + + const size_t availSize = XMIN(theLeftBodySize, (uint64_t)theIn->contentSize()); + const size_t safeSize = XMIN(availSize, (size_t)theOut->potentialSpaceSize()); + + doNeedMoreData = availSize < theLeftBodySize; + // and we may also need more space + + theOut->append(theIn->content(), safeSize); + theIn->consume(safeSize); + theLeftBodySize -= safeSize; + + if (theLeftBodySize == 0) + theStep = psChunkEnd; + else + Must(needsMoreData() || needsMoreSpace()); +} + +void ChunkedCodingParser::parseChunkEnd() +{ + Must(theLeftBodySize == 0); // Should(), really + + size_t crlfBeg = 0; + size_t crlfEnd = 0; + + if (findCrlf(crlfBeg, crlfEnd)) { + if (crlfBeg != 0) { + throw TexcHere("found data bewteen chunk end and CRLF"); + return; + } + + theIn->consume(crlfEnd); + theChunkSize = 0; // done with the current chunk + theStep = psChunkBeg; + return; + } + + doNeedMoreData = true; +} + +void ChunkedCodingParser::parseTrailer() +{ + Must(theChunkSize == 0); // Should(), really + + while (mayContinue()) + parseTrailerHeader(); +} + +void ChunkedCodingParser::parseTrailerHeader() +{ + size_t crlfBeg = 0; + size_t crlfEnd = 0; + + if (findCrlf(crlfBeg, crlfEnd)) { + if (crlfBeg > 0) + + ; //theTrailer.append(theIn->content(), crlfEnd); + + theIn->consume(crlfEnd); + + if (crlfBeg == 0) + theStep = psMessageEnd; + + return; + } + + doNeedMoreData = true; +} + +void ChunkedCodingParser::parseMessageEnd() +{ + // termination step, should not be called + Must(false); // Should(), really +} + +// finds next CRLF +bool ChunkedCodingParser::findCrlf(size_t &crlfBeg, size_t &crlfEnd) +{ + // XXX: This code was copied, with permission, from another software. + // There is a similar and probably better code inside httpHeaderParse + // but it seems difficult to isolate due to parsing-unrelated bloat. + // Such isolation should probably be done before this class is used + // for handling of traffic "more external" than ICAP. + + const char *buf = theIn->content(); + size_t size = theIn->contentSize(); + + ssize_t crOff = -1; + bool quoted = false; + bool slashed = false; + + for (size_t i = 0; i < size; ++i) { + if (slashed) { + slashed = false; + continue; + } + + const char c = buf[i]; + + // handle quoted strings + if (quoted) { + if (c == '\\') + slashed = true; + else + if (c == '"') + quoted = false; + + continue; + } else + if (c == '"') { + quoted = true; + crOff = -1; + continue; + } + + if (crOff < 0) { // looking for the first CR or LF + + if (c == '\n') { + crlfBeg = i; + crlfEnd = ++i; + return true; + } + + if (c == '\r') + crOff = i; + } else { // skipping CRs, looking for the first LF + + if (c == '\n') { + crlfBeg = crOff; + crlfEnd = ++i; + return true; + } + + if (c != '\r') + crOff = -1; + } + } + + return false; +} + --- /dev/null Wed Jan 23 01:24:23 2008 +++ squid3/src/ChunkedCodingParser.h Wed Jan 23 01:24:23 2008 @@ -0,0 +1,89 @@ + +/* + * $Id: ChunkedCodingParser.h,v 1.2.4.2 2008/01/22 11:15:27 serassio Exp $ + * + * SQUID Web Proxy Cache http://www.squid-cache.org/ + * ---------------------------------------------------------- + * + * Squid is the result of efforts by numerous individuals from + * the Internet community; see the CONTRIBUTORS file for full + * details. Many organizations have provided support for Squid's + * development; see the SPONSORS file for full details. Squid is + * Copyrighted (C) 2001 by the Regents of the University of + * California; see the COPYRIGHT file for full details. Squid + * incorporates software developed and/or copyrighted by other + * sources; see the CREDITS file for full details. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA. + * + */ + +#ifndef SQUID_CHUNKEDCODINGPARSER_H +#define SQUID_CHUNKEDCODINGPARSER_H + +#include "RefCount.h" + +// ChunkedCodingParser is an incremental parser for chunked transfer coding +// used by HTTP and ICAP. The parser shovels content bytes from the raw +// input buffer into the content output buffer, both caller-supplied. +// Ignores chunk extensions except for ICAP's ieof. +// Has a trailer-handling placeholder. + +class ChunkedCodingParser +{ + +public: + ChunkedCodingParser(); + + void reset(); + + // true = complete success; false == needs more data + bool parse(MemBuf *rawData, MemBuf *parsedContent); // throws on error + + bool needsMoreData() const; + bool needsMoreSpace() const; + +private: + typedef void (ChunkedCodingParser::*Step)(); + +private: + bool mayContinue() const; + + void parseChunkBeg(); + void parseChunkBody(); + void parseChunkEnd(); + void parseTrailer(); + void parseTrailerHeader(); + void parseMessageEnd(); + + bool findCrlf(size_t &crlfBeg, size_t &crlfEnd); + +private: + static Step psChunkBeg; + static Step psChunkBody; + static Step psChunkEnd; + static Step psTrailer; + static Step psMessageEnd; + + MemBuf *theIn; + MemBuf *theOut; + + Step theStep; + uint64_t theChunkSize; + uint64_t theLeftBodySize; + bool doNeedMoreData; +}; + +#endif /* SQUID_CHUNKEDCODINGPARSER_H */ --- /dev/null Wed Jan 23 01:24:23 2008 +++ squid3/src/TextException.cc Wed Jan 23 01:24:23 2008 @@ -0,0 +1,27 @@ +#include "squid.h" +#include "TextException.h" + +TextException::TextException(const char *aMsg, const char *aFileName, int aLineNo): + message(xstrdup(aMsg)), theFileName(aFileName), theLineNo(aLineNo) +{} + +TextException::~TextException() +{ + xfree(message); +} + +void Throw(const char *message, const char *fileName, int lineNo) +{ + + // or should we let the exception recepient print the exception instead? + + if (fileName) { + debugs(0, 3, fileName << ':' << lineNo << ": exception" << + (message ? ": " : ".") << (message ? message : "")); + } else { + debugs(0, 3, "exception" << + (message ? ": " : ".") << (message ? message : "")); + } + + throw TextException(message, fileName, lineNo); +} --- /dev/null Wed Jan 23 01:24:23 2008 +++ squid3/src/TextException.h Wed Jan 23 01:24:23 2008 @@ -0,0 +1,46 @@ +#ifndef SQUID__TEXTEXCEPTION_H +#define SQUID__TEXTEXCEPTION_H + +// Origin: xstd/TextException + + +// simple exception to report custom errors +// we may want to change the interface to be able to report system errors + +class TextException +{ + +public: + TextException(const char *aMessage, const char *aFileName = 0, int aLineNo = -1); + ~TextException(); + + // ostream &print(ostream &os) const; + +public: + char *message; // read-only + +protected: + // optional location information + const char *theFileName; + int theLineNo; +}; + +//inline +//ostream &operator <<(ostream &os, const TextException &exx) { +// return exx.print(os); +//} + +#if !defined(TexcHere) +# define TexcHere(msg) TextException((msg), __FILE__, __LINE__) +#endif + +extern void Throw(const char *message, const char *fileName, int lineNo); + +// Must(condition) is like assert(condition) but throws an exception instead +#if !defined(Must) +# define Must(cond) ((cond) ? \ + (void)0 : \ + (void)Throw(#cond, __FILE__, __LINE__)) +#endif + +#endif /* SQUID__TEXTEXCEPTION_H */