#include "ChunkedCodingParser.h"
#include "MemBuf.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;
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)
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;
- }
-
- // to allow chunk extensions in any chunk, remove this size check
- if (size == 0) // is this the last-chunk?
- parseChunkExtension(p, theIn->content() + crlfBeg);
+ 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()
theIn->consume(crlfEnd);
theChunkSize = 0; // done with the current chunk
- theStep = psChunkBeg;
+ theStep = psChunkSize;
return;
}
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 "ed, bool &slashed)
{
// XXX: This code was copied, with permission, from another software.
// There is a similar and probably better code inside httpHeaderParse
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) {
}
// chunk-extension= *( ";" chunk-ext-name [ "=" chunk-ext-val ] )
-void ChunkedCodingParser::parseChunkExtension(const char *startExt, const char *endExt)
+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 ';'
- return;
+ break;
while (*p == ' ' || *p == '\t') ++p; // skip spaces before name
if (p >= endExt)
- return; // malformed extension: ';' without ext name=value pair
+ break; // malformed extension: ';' without ext name=value pair
const int extSize = endExt - p;
// TODO: we need debugData() stream manipulator to dump data
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);
- return; // remove to support more than just use-original-body
+ 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;
}