]>
git.ipfire.org Git - thirdparty/squid.git/blob - src/http/one/TeChunkedParser.cc
2 * Copyright (C) 1996-2017 The Squid Software Foundation and contributors
4 * Squid software is distributed under GPLv2+ license and includes
5 * contributions from numerous individuals and organizations.
6 * Please see the COPYING and CONTRIBUTORS files for details.
10 #include "base/TextException.h"
12 #include "http/one/TeChunkedParser.h"
13 #include "http/one/Tokenizer.h"
14 #include "http/ProtocolVersion.h"
17 #include "SquidConfig.h"
19 Http::One::TeChunkedParser::TeChunkedParser()
21 // chunked encoding only exists in HTTP/1.1
22 Http1::Parser::msgProtocol_
= Http::ProtocolVersion(1,1);
28 Http::One::TeChunkedParser::clear()
30 parsingStage_
= Http1::HTTP_PARSE_NONE
;
32 theChunkSize
= theLeftBodySize
= 0;
38 Http::One::TeChunkedParser::parse(const SBuf
&aBuf
)
40 buf_
= aBuf
; // sync buffers first so calls to remaining() work properly if nothing done.
42 if (buf_
.isEmpty()) // nothing to do (yet)
45 debugs(74, DBG_DATA
, "Parse buf={length=" << aBuf
.length() << ", data='" << aBuf
<< "'}");
47 Must(!buf_
.isEmpty() && theOut
);
49 if (parsingStage_
== Http1::HTTP_PARSE_NONE
)
50 parsingStage_
= Http1::HTTP_PARSE_CHUNK_SZ
;
52 Http1::Tokenizer
tok(buf_
);
54 // loop for as many chunks as we can
55 // use do-while instead of while so that we can incrementally
56 // restart in the middle of a chunk/frame
59 if (parsingStage_
== Http1::HTTP_PARSE_CHUNK_EXT
&& !parseChunkExtension(tok
, theChunkSize
))
62 if (parsingStage_
== Http1::HTTP_PARSE_CHUNK
&& !parseChunkBody(tok
))
65 if (parsingStage_
== Http1::HTTP_PARSE_MIME
&& !grabMimeBlock("Trailers", 64*1024 /* 64KB max */))
68 // loop for as many chunks as we can
69 } while (parsingStage_
== Http1::HTTP_PARSE_CHUNK_SZ
&& parseChunkSize(tok
));
71 return !needsMoreData() && !needsMoreSpace();
75 Http::One::TeChunkedParser::needsMoreSpace() const
78 return parsingStage_
== Http1::HTTP_PARSE_CHUNK
&& !theOut
->hasPotentialSpace();
81 /// RFC 7230 section 4.1 chunk-size
83 Http::One::TeChunkedParser::parseChunkSize(Http1::Tokenizer
&tok
)
85 Must(theChunkSize
<= 0); // Should(), really
88 if (tok
.int64(size
, 16, false) && !tok
.atEnd()) {
90 throw TexcHere("negative chunk size");
92 theChunkSize
= theLeftBodySize
= size
;
93 debugs(94,7, "found chunk: " << theChunkSize
);
94 buf_
= tok
.remaining(); // parse checkpoint
95 parsingStage_
= Http1::HTTP_PARSE_CHUNK_EXT
;
98 } else if (tok
.atEnd()) {
99 return false; // need more data
103 throw TexcHere("corrupted chunk size");
104 return false; // should not be reachable
108 * Parses a set of RFC 7230 section 4.1.1 chunk-ext
109 * http://tools.ietf.org/html/rfc7230#section-4.1.1
111 * chunk-ext = *( ";" chunk-ext-name [ "=" chunk-ext-val ] )
112 * chunk-ext-name = token
113 * chunk-ext-val = token / quoted-string
115 * ICAP 'use-original-body=N' extension is supported.
118 Http::One::TeChunkedParser::parseChunkExtension(Http1::Tokenizer
&tok
, bool skipKnown
)
120 // Bug 4492: IBM_HTTP_Server sends SP padding
121 if (auto n
= tok
.skipAll(CharacterSet::SP
)) {
122 debugs(94, 3, "skipping " << n
<< " spurious whitespace at start of chunk extension");
127 while (tok
.skip(';') && tok
.prefix(ext
, CharacterSet::TCHAR
)) {
129 // whole value part is optional. if no '=' expect next chunk-ext
133 if (ext
.cmp("use-original-body",17) == 0 && tok
.int64(useOriginBody
, 10)) {
134 debugs(94, 3, "Found chunk extension " << ext
<< "=" << useOriginBody
);
135 buf_
= tok
.remaining(); // parse checkpoint
140 debugs(94, 5, "skipping unknown chunk extension " << ext
);
142 // unknown might have a value token or quoted-string
143 if (tok
.quotedStringOrToken(value
) && !tok
.atEnd()) {
144 buf_
= tok
.remaining(); // parse checkpoint
148 // otherwise need more data OR corrupt syntax
153 buf_
= tok
.remaining(); // parse checkpoint (unless there might be more token name)
156 if (skipLineTerminator(tok
)) {
157 buf_
= tok
.remaining(); // checkpoint
158 // non-0 chunk means data, 0-size means optional Trailer follows
159 parsingStage_
= theChunkSize
? Http1::HTTP_PARSE_CHUNK
: Http1::HTTP_PARSE_MIME
;
167 Http::One::TeChunkedParser::parseChunkBody(Http1::Tokenizer
&tok
)
169 if (theLeftBodySize
> 0) {
170 buf_
= tok
.remaining(); // sync buffers before buf_ use
172 // TODO fix type mismatches and casting for these
173 const size_t availSize
= min(theLeftBodySize
, (uint64_t)buf_
.length());
174 const size_t safeSize
= min(availSize
, (size_t)theOut
->potentialSpaceSize());
176 theOut
->append(buf_
.rawContent(), safeSize
);
177 buf_
.consume(safeSize
);
178 theLeftBodySize
-= safeSize
;
180 tok
.reset(buf_
); // sync buffers after consume()
183 if (theLeftBodySize
== 0)
184 return parseChunkEnd(tok
);
186 Must(needsMoreData() || needsMoreSpace());
192 Http::One::TeChunkedParser::parseChunkEnd(Http1::Tokenizer
&tok
)
194 Must(theLeftBodySize
== 0); // Should(), really
196 if (skipLineTerminator(tok
)) {
197 buf_
= tok
.remaining(); // parse checkpoint
198 theChunkSize
= 0; // done with the current chunk
199 parsingStage_
= Http1::HTTP_PARSE_CHUNK_SZ
;