]> git.ipfire.org Git - thirdparty/squid.git/commitdiff
Add new files omitted from chunked
authorAmos Jeffries <squid3@treenet.co.nz>
Fri, 8 May 2009 02:52:22 +0000 (14:52 +1200)
committerAmos Jeffries <squid3@treenet.co.nz>
Fri, 8 May 2009 02:52:22 +0000 (14:52 +1200)
src/ChunkedCodingParser.cc [new file with mode: 0644]
src/ChunkedCodingParser.h [new file with mode: 0644]
src/TextException.cc [new file with mode: 0644]
src/TextException.h [new file with mode: 0644]

diff --git a/src/ChunkedCodingParser.cc b/src/ChunkedCodingParser.cc
new file mode 100644 (file)
index 0000000..a3ef03f
--- /dev/null
@@ -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;
+}
+
diff --git a/src/ChunkedCodingParser.h b/src/ChunkedCodingParser.h
new file mode 100644 (file)
index 0000000..7eef57a
--- /dev/null
@@ -0,0 +1,89 @@
+
+/*
+ * $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 */
diff --git a/src/TextException.cc b/src/TextException.cc
new file mode 100644 (file)
index 0000000..3300e20
--- /dev/null
@@ -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);
+}
diff --git a/src/TextException.h b/src/TextException.h
new file mode 100644 (file)
index 0000000..3a78dad
--- /dev/null
@@ -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 */