--- /dev/null
+#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
+
+/*
+ * $Id: ChunkedCodingParser.h,v 1.1 2007/12/26 22:33:32 hno 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
+#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
+#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 */