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