TeChunkedParser.cc
Go to the documentation of this file.
1 /*
2  * Copyright (C) 1996-2017 The Squid Software Foundation and contributors
3  *
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.
7  */
8 
9 #include "squid.h"
10 #include "base/TextException.h"
11 #include "Debug.h"
13 #include "http/one/Tokenizer.h"
14 #include "http/ProtocolVersion.h"
15 #include "MemBuf.h"
16 #include "Parsing.h"
17 #include "SquidConfig.h"
18 
20 {
21  // chunked encoding only exists in HTTP/1.1
23 
24  clear();
25 }
26 
27 void
29 {
30  parsingStage_ = Http1::HTTP_PARSE_NONE;
31  buf_.clear();
32  theChunkSize = theLeftBodySize = 0;
33  theOut = NULL;
34  useOriginBody = -1;
35 }
36 
37 bool
39 {
40  buf_ = aBuf; // sync buffers first so calls to remaining() work properly if nothing done.
41 
42  if (buf_.isEmpty()) // nothing to do (yet)
43  return false;
44 
45  debugs(74, DBG_DATA, "Parse buf={length=" << aBuf.length() << ", data='" << aBuf << "'}");
46 
47  Must(!buf_.isEmpty() && theOut);
48 
49  if (parsingStage_ == Http1::HTTP_PARSE_NONE)
50  parsingStage_ = Http1::HTTP_PARSE_CHUNK_SZ;
51 
52  Http1::Tokenizer tok(buf_);
53 
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
57  do {
58 
59  if (parsingStage_ == Http1::HTTP_PARSE_CHUNK_EXT && !parseChunkExtension(tok, theChunkSize))
60  return false;
61 
62  if (parsingStage_ == Http1::HTTP_PARSE_CHUNK && !parseChunkBody(tok))
63  return false;
64 
65  if (parsingStage_ == Http1::HTTP_PARSE_MIME && !grabMimeBlock("Trailers", 64*1024 /* 64KB max */))
66  return false;
67 
68  // loop for as many chunks as we can
69  } while (parsingStage_ == Http1::HTTP_PARSE_CHUNK_SZ && parseChunkSize(tok));
70 
71  return !needsMoreData() && !needsMoreSpace();
72 }
73 
74 bool
76 {
77  assert(theOut);
78  return parsingStage_ == Http1::HTTP_PARSE_CHUNK && !theOut->hasPotentialSpace();
79 }
80 
82 bool
84 {
85  Must(theChunkSize <= 0); // Should(), really
86 
87  int64_t size = -1;
88  if (tok.int64(size, 16, false) && !tok.atEnd()) {
89  if (size < 0)
90  throw TexcHere("negative chunk size");
91 
92  theChunkSize = theLeftBodySize = size;
93  debugs(94,7, "found chunk: " << theChunkSize);
94  buf_ = tok.remaining(); // parse checkpoint
95  parsingStage_ = Http1::HTTP_PARSE_CHUNK_EXT;
96  return true;
97 
98  } else if (tok.atEnd()) {
99  return false; // need more data
100  }
101 
102  // else error
103  throw TexcHere("corrupted chunk size");
104  return false; // should not be reachable
105 }
106 
117 bool
119 {
120  SBuf ext;
121  SBuf value;
122  while (
123  ParseBws(tok) && // Bug 4492: IBM_HTTP_Server sends SP after chunk-size
124  tok.skip(';') &&
125  ParseBws(tok) && // Bug 4492: ICAP servers send SP before chunk-ext-name
126  tok.prefix(ext, CharacterSet::TCHAR)) { // chunk-ext-name
127 
128  // whole value part is optional. if no '=' expect next chunk-ext
129  if (ParseBws(tok) && tok.skip('=') && ParseBws(tok)) {
130 
131  if (!skipKnown) {
132  if (ext.cmp("use-original-body",17) == 0 && tok.int64(useOriginBody, 10)) {
133  debugs(94, 3, "Found chunk extension " << ext << "=" << useOriginBody);
134  buf_ = tok.remaining(); // parse checkpoint
135  continue;
136  }
137  }
138 
139  debugs(94, 5, "skipping unknown chunk extension " << ext);
140 
141  // unknown might have a value token or quoted-string
142  if (tok.quotedStringOrToken(value) && !tok.atEnd()) {
143  buf_ = tok.remaining(); // parse checkpoint
144  continue;
145  }
146 
147  // otherwise need more data OR corrupt syntax
148  break;
149  }
150 
151  if (!tok.atEnd())
152  buf_ = tok.remaining(); // parse checkpoint (unless there might be more token name)
153  }
154 
155  if (skipLineTerminator(tok)) {
156  buf_ = tok.remaining(); // checkpoint
157  // non-0 chunk means data, 0-size means optional Trailer follows
158  parsingStage_ = theChunkSize ? Http1::HTTP_PARSE_CHUNK : Http1::HTTP_PARSE_MIME;
159  return true;
160  }
161 
162  return false;
163 }
164 
165 bool
167 {
168  if (theLeftBodySize > 0) {
169  buf_ = tok.remaining(); // sync buffers before buf_ use
170 
171  // TODO fix type mismatches and casting for these
172  const size_t availSize = min(theLeftBodySize, (uint64_t)buf_.length());
173  const size_t safeSize = min(availSize, (size_t)theOut->potentialSpaceSize());
174 
175  theOut->append(buf_.rawContent(), safeSize);
176  buf_.consume(safeSize);
177  theLeftBodySize -= safeSize;
178 
179  tok.reset(buf_); // sync buffers after consume()
180  }
181 
182  if (theLeftBodySize == 0)
183  return parseChunkEnd(tok);
184  else
185  Must(needsMoreData() || needsMoreSpace());
186 
187  return true;
188 }
189 
190 bool
192 {
193  Must(theLeftBodySize == 0); // Should(), really
194 
195  if (skipLineTerminator(tok)) {
196  buf_ = tok.remaining(); // parse checkpoint
197  theChunkSize = 0; // done with the current chunk
198  parsingStage_ = Http1::HTTP_PARSE_CHUNK_SZ;
199  return true;
200  }
201 
202  return false;
203 }
204 
AnyP::ProtocolVersion msgProtocol_
what protocol label has been found in the first line (if any)
Definition: Parser.h:152
AnyP::ProtocolVersion ProtocolVersion(unsigned int aMajor, unsigned int aMinor)
HTTP version label information.
#define assert(EX)
Definition: assert.h:17
bool ParseBws(Tokenizer &tok)
Definition: Parser.cc:276
bool parseChunkEnd(Http1::Tokenizer &tok)
Definition: SBuf.h:87
HTTP/1 mime-header block.
Definition: Parser.h:27
static const CharacterSet TCHAR
Definition: CharacterSet.h:102
size_type length() const
Returns the number of bytes stored in SBuf.
Definition: SBuf.h:405
#define debugs(SECTION, LEVEL, CONTENT)
Definition: Debug.h:123
bool parseChunkBody(Http1::Tokenizer &tok)
initialized, but nothing usefully parsed yet
Definition: Parser.h:22
bool atEnd() const
whether the end of the buffer has been reached
Definition: Tokenizer.h:41
HTTP/1.1 chunked encoding chunk-data.
Definition: Parser.h:26
Definition: parse.c:160
void reset(const SBuf &newBuf)
reinitialize processing for a new buffer
Definition: Tokenizer.h:47
bool parseChunkSize(Http1::Tokenizer &tok)
RFC 7230 section 4.1 chunk-size.
bool skip(const SBuf &tokenToSkip)
Definition: Tokenizer.cc:160
#define Must(cond)
Definition: TextException.h:89
virtual bool parse(const SBuf &)
bool prefix(SBuf &returnedToken, const CharacterSet &tokenChars, SBuf::size_type limit=SBuf::npos)
Definition: Tokenizer.cc:79
bool quotedStringOrToken(SBuf &value, const bool http1p0=false)
Definition: Tokenizer.cc:25
const SBuf & remaining() const
the remaining unprocessed section of buffer
Definition: Tokenizer.h:44
int cmp(const SBuf &S, const size_type n) const
shorthand version for compare()
Definition: SBuf.h:265
HTTP/1.1 chunked encoding chunk-ext.
Definition: Parser.h:25
#define TexcHere(msg)
Definition: TextException.h:81
bool parseChunkExtension(Http1::Tokenizer &tok, bool skipKnown)
#define DBG_DATA
Definition: Debug.h:47
HTTP/1.1 chunked encoding chunk-size.
Definition: Parser.h:24
#define NULL
Definition: types.h:166
int size
Definition: ModDevPoll.cc:77
A const & min(A const &lhs, A const &rhs)
bool int64(int64_t &result, int base=0, bool allowSign=true, SBuf::size_type limit=SBuf::npos)
Definition: Tokenizer.cc:209

 

Introduction

Documentation

Support

Miscellaneous

Web Site Translations

Mirrors