]> git.ipfire.org Git - thirdparty/squid.git/blame - src/ICAP/ChunkedCodingParser.cc
Author: wessels & Christos Tsantilas
[thirdparty/squid.git] / src / ICAP / ChunkedCodingParser.cc
CommitLineData
774c051c 1#include "squid.h"
2#include "Parsing.h"
3#include "TextException.h"
4#include "ChunkedCodingParser.h"
5#include "MemBuf.h"
6
7ChunkedCodingParser::Step ChunkedCodingParser::psChunkBeg = &ChunkedCodingParser::parseChunkBeg;
8ChunkedCodingParser::Step ChunkedCodingParser::psChunkBody = &ChunkedCodingParser::parseChunkBody;
9ChunkedCodingParser::Step ChunkedCodingParser::psChunkEnd = &ChunkedCodingParser::parseChunkEnd;
10ChunkedCodingParser::Step ChunkedCodingParser::psTrailer = &ChunkedCodingParser::parseTrailer;
11ChunkedCodingParser::Step ChunkedCodingParser::psMessageEnd = &ChunkedCodingParser::parseMessageEnd;
12
13ChunkedCodingParser::ChunkedCodingParser()
14{
15 reset();
16}
17
18void ChunkedCodingParser::reset()
19{
20 theStep = psChunkBeg;
21 theChunkSize = theLeftBodySize = 0;
22 doNeedMoreData = false;
23 sawIeof = false;
24 theIn = theOut = NULL;
25}
26
27bool ChunkedCodingParser::parse(MemBuf *rawData, MemBuf *parsedContent)
28{
29 Must(rawData && parsedContent);
30 theIn = rawData;
31 theOut = parsedContent;
32
33 // we must reset this all the time so that mayContinue() lets us
34 // output more content if we stopped due to needsMoreSpace() before
35 doNeedMoreData = !theIn->hasContent();
36
37 while (mayContinue()) {
38 (this->*theStep)();
39 }
40
41 return theStep == psMessageEnd;
42}
43
44bool ChunkedCodingParser::needsMoreData() const
45{
46 return doNeedMoreData;
47}
48
49bool ChunkedCodingParser::needsMoreSpace() const
50{
51 assert(theOut);
52 return theStep == psChunkBody && !theOut->hasPotentialSpace();
53}
54
55bool ChunkedCodingParser::mayContinue() const
56{
57 return !needsMoreData() && !needsMoreSpace() && theStep != psMessageEnd;
58}
59
60void ChunkedCodingParser::parseChunkBeg()
61{
62 Must(theChunkSize <= 0); // Should(), really
63
64 size_t crlfBeg = 0;
65 size_t crlfEnd = 0;
66
67 if (findCrlf(crlfBeg, crlfEnd)) {
c99de607 68 debugs(93,7, "found chunk-size end: " << crlfBeg << "-" << crlfEnd);
47f6e231 69 int64_t size = -1;
774c051c 70 const char *p = 0;
71
47f6e231 72 if (StringToInt64(theIn->content(), size, &p, 16)) {
774c051c 73 if (size < 0) {
74 throw TexcHere("negative chunk size");
75 return;
76 }
77
78 // check for ieof chunk extension in the last-chunk
79 if (size == 0 && p && *p++ == ';') {
80 const char *e = theIn->content() + crlfBeg; // end of extension
81
e4755e29 82 while (p < e && xisspace(*p))
774c051c 83 ++p; // skip space
84
85 sawIeof = e - p >= 4 &&
86 strncmp(p, "ieof", 4) == 0 &&
e4755e29 87 xisspace(p[4]);
774c051c 88 }
89
90 theIn->consume(crlfEnd);
91 theChunkSize = theLeftBodySize = size;
c99de607 92 debugs(93,7, "found chunk: " << theChunkSize);
774c051c 93 theStep = theChunkSize == 0 ? psTrailer : psChunkBody;
94 return;
95 }
96
97 throw TexcHere("corrupted chunk size");
98 }
99
100 doNeedMoreData = true;
101}
102
103void ChunkedCodingParser::parseChunkBody()
104{
105 Must(theLeftBodySize > 0); // Should, really
106
47f6e231 107 const size_t availSize = XMIN(theLeftBodySize, (uint64_t)theIn->contentSize());
774c051c 108 const size_t safeSize = XMIN(availSize, (size_t)theOut->potentialSpaceSize());
109
110 doNeedMoreData = availSize < theLeftBodySize;
111 // and we may also need more space
112
113 theOut->append(theIn->content(), safeSize);
114 theIn->consume(safeSize);
115 theLeftBodySize -= safeSize;
116
117 if (theLeftBodySize == 0)
118 theStep = psChunkEnd;
119 else
120 Must(needsMoreData() || needsMoreSpace());
121}
122
123void ChunkedCodingParser::parseChunkEnd()
124{
125 Must(theLeftBodySize == 0); // Should(), really
126
127 size_t crlfBeg = 0;
128 size_t crlfEnd = 0;
129
130 if (findCrlf(crlfBeg, crlfEnd)) {
131 if (crlfBeg != 0) {
132 throw TexcHere("found data bewteen chunk end and CRLF");
133 return;
134 }
135
136 theIn->consume(crlfEnd);
137 theChunkSize = 0; // done with the current chunk
138 theStep = psChunkBeg;
139 return;
140 }
141
142 doNeedMoreData = true;
143}
144
145void ChunkedCodingParser::parseTrailer()
146{
147 Must(theChunkSize == 0); // Should(), really
148
149 while (mayContinue())
150 parseTrailerHeader();
151}
152
153void ChunkedCodingParser::parseTrailerHeader()
154{
155 size_t crlfBeg = 0;
156 size_t crlfEnd = 0;
157
158 if (findCrlf(crlfBeg, crlfEnd)) {
159 if (crlfBeg > 0)
160
161 ; //theTrailer.append(theIn->content(), crlfEnd);
162
163 theIn->consume(crlfEnd);
164
165 if (crlfBeg == 0)
166 theStep = psMessageEnd;
167
168 return;
169 }
170
171 doNeedMoreData = true;
172}
173
174void ChunkedCodingParser::parseMessageEnd()
175{
176 // termination step, should not be called
177 Must(false); // Should(), really
178}
179
180// finds next CRLF
181bool ChunkedCodingParser::findCrlf(size_t &crlfBeg, size_t &crlfEnd)
182{
183 // XXX: This code was copied, with permission, from another software.
184 // There is a similar and probably better code inside httpHeaderParse
185 // but it seems difficult to isolate due to parsing-unrelated bloat.
186 // Such isolation should probably be done before this class is used
187 // for handling of traffic "more external" than ICAP.
188
189 const char *buf = theIn->content();
190 size_t size = theIn->contentSize();
191
192 ssize_t crOff = -1;
193 bool quoted = false;
194 bool slashed = false;
195
196 for (size_t i = 0; i < size; ++i) {
197 if (slashed) {
198 slashed = false;
199 continue;
200 }
201
202 const char c = buf[i];
203
204 // handle quoted strings
205 if (quoted) {
206 if (c == '\\')
207 slashed = true;
208 else
209 if (c == '"')
210 quoted = false;
211
212 continue;
213 } else
214 if (c == '"') {
215 quoted = true;
216 crOff = -1;
217 continue;
218 }
219
220 if (crOff < 0) { // looking for the first CR or LF
221
222 if (c == '\n') {
223 crlfBeg = i;
224 crlfEnd = ++i;
225 return true;
226 }
227
228 if (c == '\r')
229 crOff = i;
230 } else { // skipping CRs, looking for the first LF
231
232 if (c == '\n') {
233 crlfBeg = crOff;
234 crlfEnd = ++i;
235 return true;
236 }
237
238 if (c != '\r')
239 crOff = -1;
240 }
241 }
242
243 return false;
244}
245