]> git.ipfire.org Git - thirdparty/squid.git/blobdiff - src/ChunkedCodingParser.cc
SourceFormat Enforcement
[thirdparty/squid.git] / src / ChunkedCodingParser.cc
index ebd2bd781fee7d8d0003213595e6c0e092a922a6..f9ab4ab92df0b92f54145dfce583f06c77955429 100644 (file)
@@ -1,10 +1,13 @@
 #include "squid.h"
-#include "Parsing.h"
-#include "TextException.h"
+#include "base/TextException.h"
 #include "ChunkedCodingParser.h"
+#include "Debug.h"
 #include "MemBuf.h"
+#include "Parsing.h"
 
-ChunkedCodingParser::Step ChunkedCodingParser::psChunkBeg = &ChunkedCodingParser::parseChunkBeg;
+ChunkedCodingParser::Step ChunkedCodingParser::psChunkSize = &ChunkedCodingParser::parseChunkSize;
+ChunkedCodingParser::Step ChunkedCodingParser::psUnusedChunkExtension = &ChunkedCodingParser::parseUnusedChunkExtension;
+ChunkedCodingParser::Step ChunkedCodingParser::psLastChunkExtension = &ChunkedCodingParser::parseLastChunkExtension;
 ChunkedCodingParser::Step ChunkedCodingParser::psChunkBody = &ChunkedCodingParser::parseChunkBody;
 ChunkedCodingParser::Step ChunkedCodingParser::psChunkEnd = &ChunkedCodingParser::parseChunkEnd;
 ChunkedCodingParser::Step ChunkedCodingParser::psTrailer = &ChunkedCodingParser::parseTrailer;
@@ -17,10 +20,12 @@ ChunkedCodingParser::ChunkedCodingParser()
 
 void ChunkedCodingParser::reset()
 {
-    theStep = psChunkBeg;
+    theStep = psChunkSize;
     theChunkSize = theLeftBodySize = 0;
     doNeedMoreData = false;
     theIn = theOut = NULL;
+    useOriginBody = -1;
+    inQuoted = inSlashed = false;
 }
 
 bool ChunkedCodingParser::parse(MemBuf *rawData, MemBuf *parsedContent)
@@ -56,35 +61,47 @@ bool ChunkedCodingParser::mayContinue() const
     return !needsMoreData() && !needsMoreSpace() && theStep != psMessageEnd;
 }
 
-void ChunkedCodingParser::parseChunkBeg()
+void ChunkedCodingParser::parseChunkSize()
 {
     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;
-            }
+    const char *p = theIn->content();
+    while (p < theIn->space() && xisxdigit(*p)) ++p;
+    if (p >= theIn->space()) {
+        doNeedMoreData = true;
+        return;
+    }
 
-            theIn->consume(crlfEnd);
-            theChunkSize = theLeftBodySize = size;
-            debugs(94,7, "found chunk: " << theChunkSize);
-            theStep = theChunkSize == 0 ? psTrailer : psChunkBody;
-            return;
+    int64_t size = -1;
+    if (StringToInt64(theIn->content(), size, &p, 16)) {
+        if (size < 0)
+            throw TexcHere("negative chunk size");
+
+        theChunkSize = theLeftBodySize = size;
+        debugs(94,7, "found chunk: " << theChunkSize);
+        // parse chunk extensions only in the last-chunk
+        if (theChunkSize)
+            theStep = psUnusedChunkExtension;
+        else {
+            theIn->consume(p - theIn->content());
+            theStep = psLastChunkExtension;
         }
-
+    } else
         throw TexcHere("corrupted chunk size");
-    }
+}
 
-    doNeedMoreData = true;
+void ChunkedCodingParser::parseUnusedChunkExtension()
+{
+    size_t crlfBeg = 0;
+    size_t crlfEnd = 0;
+    if (findCrlf(crlfBeg, crlfEnd, inQuoted, inSlashed)) {
+        inQuoted = inSlashed = false;
+        theIn->consume(crlfEnd);
+        theStep = theChunkSize ? psChunkBody : psTrailer;
+    } else {
+        theIn->consume(theIn->contentSize());
+        doNeedMoreData = true;
+    }
 }
 
 void ChunkedCodingParser::parseChunkBody()
@@ -116,13 +133,13 @@ void ChunkedCodingParser::parseChunkEnd()
 
     if (findCrlf(crlfBeg, crlfEnd)) {
         if (crlfBeg != 0) {
-            throw TexcHere("found data bewteen chunk end and CRLF");
+            throw TexcHere("found data between chunk end and CRLF");
             return;
         }
 
         theIn->consume(crlfEnd);
         theChunkSize = 0; // done with the current chunk
-        theStep = psChunkBeg;
+        theStep = psChunkSize;
         return;
     }
 
@@ -143,9 +160,11 @@ void ChunkedCodingParser::parseTrailerHeader()
     size_t crlfEnd = 0;
 
     if (findCrlf(crlfBeg, crlfEnd)) {
-        if (crlfBeg > 0)
 
-            ; //theTrailer.append(theIn->content(), crlfEnd);
+#if TRAILERS_ARE_SUPPORTED
+        if (crlfBeg > 0)
+            theTrailer.append(theIn->content(), crlfEnd);
+#endif
 
         theIn->consume(crlfEnd);
 
@@ -164,8 +183,17 @@ void ChunkedCodingParser::parseMessageEnd()
     Must(false); // Should(), really
 }
 
-// finds next CRLF
+/// Finds next CRLF. Does not store parsing state.
 bool ChunkedCodingParser::findCrlf(size_t &crlfBeg, size_t &crlfEnd)
+{
+    bool quoted = false;
+    bool slashed = false;
+    return findCrlf(crlfBeg, crlfEnd, quoted, slashed);
+}
+
+/// Finds next CRLF. Parsing state stored in quoted and slashed
+/// parameters. Incremental: can resume when more data is available.
+bool ChunkedCodingParser::findCrlf(size_t &crlfBeg, size_t &crlfEnd, bool &quoted, bool &slashed)
 {
     // XXX: This code was copied, with permission, from another software.
     // There is a similar and probably better code inside httpHeaderParse
@@ -177,8 +205,6 @@ bool ChunkedCodingParser::findCrlf(size_t &crlfBeg, size_t &crlfEnd)
     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) {
@@ -192,17 +218,15 @@ bool ChunkedCodingParser::findCrlf(size_t &crlfBeg, size_t &crlfEnd)
         if (quoted) {
             if (c == '\\')
                 slashed = true;
-            else
-                if (c == '"')
-                    quoted = false;
+            else if (c == '"')
+                quoted = false;
 
             continue;
-        } else
-            if (c == '"') {
-                quoted = true;
-                crOff = -1;
-                continue;
-            }
+        } else if (c == '"') {
+            quoted = true;
+            crOff = -1;
+            continue;
+        }
 
         if (crOff < 0) { // looking for the first CR or LF
 
@@ -230,3 +254,49 @@ bool ChunkedCodingParser::findCrlf(size_t &crlfBeg, size_t &crlfEnd)
     return false;
 }
 
+// chunk-extension= *( ";" chunk-ext-name [ "=" chunk-ext-val ] )
+void ChunkedCodingParser::parseLastChunkExtension()
+{
+    size_t crlfBeg = 0;
+    size_t crlfEnd = 0;
+
+    if (!findCrlf(crlfBeg, crlfEnd)) {
+        doNeedMoreData = true;
+        return;
+    }
+
+    const char *const startExt = theIn->content();
+    const char *const endExt = theIn->content() + crlfBeg;
+
+    // chunk-extension starts at startExt and ends with LF at endEx
+    for (const char *p = startExt; p < endExt;) {
+
+        while (*p == ' ' || *p == '\t') ++p; // skip spaces before ';'
+
+        if (*p++ != ';') // each ext name=value pair is preceded with ';'
+            break;
+
+        while (*p == ' ' || *p == '\t') ++p; // skip spaces before name
+
+        if (p >= endExt)
+            break; // malformed extension: ';' without ext name=value pair
+
+        const int extSize = endExt - p;
+        // TODO: we need debugData() stream manipulator to dump data
+        debugs(94,7, "Found chunk extension; size=" << extSize);
+
+        // TODO: support implied *LWS around '='
+        if (extSize > 18 && strncmp(p, "use-original-body=", 18) == 0) {
+            (void)StringToInt64(p+18, useOriginBody, &p, 10);
+            debugs(94, 3, HERE << "use-original-body=" << useOriginBody);
+            break; // remove to support more than just use-original-body
+        } else {
+            debugs(94, 5, HERE << "skipping unknown chunk extension");
+            // TODO: support quoted-string chunk-ext-val
+            while (p < endExt && *p != ';') ++p; // skip until the next ';'
+        }
+    }
+
+    theIn->consume(crlfEnd);
+    theStep = theChunkSize ? psChunkBody : psTrailer;
+}