1 #include <stddef.h>
2 #include "gatling.h"
3
4 #ifdef SUPPORT_PROXY
5
httpstream_initstate(struct httpstreamstate * hss)6 void httpstream_initstate(struct httpstreamstate* hss) {
7 hss->state=HSS_HEADER;
8 hss->bytesleft=0;
9 hss->type=DONTKNOW;
10 }
11
httpstream_update(struct httpstreamstate * hss,char c)12 int httpstream_update(struct httpstreamstate* hss,char c) {
13 switch (hss->state) {
14
15 case HSS_HEADER_CRLF:
16 if (c=='\r') {
17 hss->state=HSS_HEADER_CRLFCR;
18 break;
19 }
20 goto new_header_line;
21 // else fall through
22
23 case HSS_HEADER:
24 if (hss->type == DONTKNOW) {
25 if (c=='H') hss->type=RESPONSE_MAYBE;
26 else if (c=='P') hss->type=POSTREQUEST;
27 else hss->type=REQUEST;
28 }
29 else if (hss->type == RESPONSE_MAYBE) {
30 if (c=='T')
31 hss->type=RESPONSE; /* "HTTP/2.0 OK" */
32 else
33 hss->type=REQUEST; /* "HEAD /foo HTTP/1.1" */
34 }
35 new_header_line:
36 if ((c|0x20)=='c') hss->state=HSS_HEADER_C;
37 else if ((c|0x20)=='t') hss->state=HSS_HEADER_T;
38 else {
39 shared:
40 if (c=='\r') hss->state=HSS_HEADER_CR;
41 else hss->state=HSS_HEADER_OTHER;
42 }
43 break;
44
45 case HSS_HEADER_C:
46 if ((c|0x20)=='o') { hss->state=HSS_HEADER_CO; break; }
47 else goto shared;
48
49 case HSS_HEADER_CO:
50 if ((c|0x20)=='n') { hss->state=HSS_HEADER_CON; break; }
51 else goto shared;
52
53 case HSS_HEADER_CON:
54 if ((c|0x20)=='t') { hss->state=HSS_HEADER_CONT; break; }
55 else goto shared;
56
57 case HSS_HEADER_CONT:
58 if ((c|0x20)=='e') { hss->state=HSS_HEADER_CONTE; break; }
59 else goto shared;
60
61 case HSS_HEADER_CONTE:
62 if ((c|0x20)=='n') { hss->state=HSS_HEADER_CONTEN; break; }
63 else goto shared;
64
65 case HSS_HEADER_CONTEN:
66 if ((c|0x20)=='t') { hss->state=HSS_HEADER_CONTENT; break; }
67 else goto shared;
68
69 case HSS_HEADER_CONTENT:
70 if (c=='-') { hss->state=HSS_HEADER_CONTENT_; break; }
71 else goto shared;
72
73 case HSS_HEADER_CONTENT_:
74 if ((c|0x20)=='l') { hss->state=HSS_HEADER_CONTENT_L; break; }
75 else goto shared;
76
77 case HSS_HEADER_CONTENT_L:
78 if ((c|0x20)=='e') { hss->state=HSS_HEADER_CONTENT_LE; break; }
79 else goto shared;
80
81 case HSS_HEADER_CONTENT_LE:
82 if ((c|0x20)=='n') { hss->state=HSS_HEADER_CONTENT_LEN; break; }
83 else goto shared;
84
85 case HSS_HEADER_CONTENT_LEN:
86 if ((c|0x20)=='g') { hss->state=HSS_HEADER_CONTENT_LENG; break; }
87 else goto shared;
88
89 case HSS_HEADER_CONTENT_LENG:
90 if ((c|0x20)=='t') { hss->state=HSS_HEADER_CONTENT_LENGT; break; }
91 else goto shared;
92
93 case HSS_HEADER_CONTENT_LENGT:
94 if ((c|0x20)=='h') { hss->state=HSS_HEADER_CONTENT_LENGTH; break; }
95 else goto shared;
96
97 case HSS_HEADER_CONTENT_LENGTH:
98 if (c==':') { hss->state=HSS_HEADER_CONTENT_LENGTH_; break; }
99 else goto shared;
100
101 case HSS_HEADER_CONTENT_LENGTH_:
102 if (c==' '||c=='\t') break; // skip whitespace without changing state
103 if (c>='0' && c<='9') { hss->bytesleft=c-'0'; hss->state=HSS_HEADER_CONTENT_LENGTH_NUM; break; }
104 else goto shared;
105
106 case HSS_HEADER_CONTENT_LENGTH_NUM:
107 // printf("<bs=%ld, c=%c, bs=%ld>",hss->bytesleft,c,hss->bytesleft*10+c-'0');
108 if (c>='0' && c<='9') { hss->bytesleft=hss->bytesleft*10+c-'0'; break; }
109 else if (c!='\r') hss->bytesleft=UNKNOWN;
110 goto shared;
111
112 case HSS_HEADER_T:
113 if ((c|0x20)=='r') { hss->state=HSS_HEADER_TR; break; }
114 else goto shared;
115
116 case HSS_HEADER_TR:
117 if ((c|0x20)=='a') { hss->state=HSS_HEADER_TRA; break; }
118 else goto shared;
119
120 case HSS_HEADER_TRA:
121 if ((c|0x20)=='n') { hss->state=HSS_HEADER_TRAN; break; }
122 else goto shared;
123
124 case HSS_HEADER_TRAN:
125 if ((c|0x20)=='s') { hss->state=HSS_HEADER_TRANS; break; }
126 else goto shared;
127
128 case HSS_HEADER_TRANS:
129 if ((c|0x20)=='f') { hss->state=HSS_HEADER_TRANSF; break; }
130 else goto shared;
131
132 case HSS_HEADER_TRANSF:
133 if ((c|0x20)=='e') { hss->state=HSS_HEADER_TRANSFE; break; }
134 else goto shared;
135
136 case HSS_HEADER_TRANSFE:
137 if ((c|0x20)=='r') { hss->state=HSS_HEADER_TRANSFER; break; }
138 else goto shared;
139
140 case HSS_HEADER_TRANSFER:
141 if (c=='-') { hss->state=HSS_HEADER_TRANSFER_; break; }
142 else goto shared;
143
144 case HSS_HEADER_TRANSFER_:
145 if ((c|0x20)=='e') { hss->state=HSS_HEADER_TRANSFER_E; break; }
146 else goto shared;
147
148 case HSS_HEADER_TRANSFER_E:
149 if ((c|0x20)=='n') { hss->state=HSS_HEADER_TRANSFER_EN; break; }
150 else goto shared;
151
152 case HSS_HEADER_TRANSFER_EN:
153 if ((c|0x20)=='c') { hss->state=HSS_HEADER_TRANSFER_ENC; break; }
154 else goto shared;
155
156 case HSS_HEADER_TRANSFER_ENC:
157 if ((c|0x20)=='o') { hss->state=HSS_HEADER_TRANSFER_ENCO; break; }
158 else goto shared;
159
160 case HSS_HEADER_TRANSFER_ENCO:
161 if ((c|0x20)=='d') { hss->state=HSS_HEADER_TRANSFER_ENCOD; break; }
162 else goto shared;
163
164 case HSS_HEADER_TRANSFER_ENCOD:
165 if ((c|0x20)=='i') { hss->state=HSS_HEADER_TRANSFER_ENCODI; break; }
166 else goto shared;
167
168 case HSS_HEADER_TRANSFER_ENCODI:
169 if ((c|0x20)=='n') { hss->state=HSS_HEADER_TRANSFER_ENCODIN; break; }
170 else goto shared;
171
172 case HSS_HEADER_TRANSFER_ENCODIN:
173 if ((c|0x20)=='g') { hss->state=HSS_HEADER_TRANSFER_ENCODING; break; }
174 else goto shared;
175
176 case HSS_HEADER_TRANSFER_ENCODING:
177 if (c==':') { hss->state=HSS_HEADER_TRANSFER_ENCODING_; break; }
178 else goto shared;
179
180 case HSS_HEADER_TRANSFER_ENCODING_:
181 if (c==' ' || c=='\t') break; /* skip whitespace */
182 if ((c|0x20)=='c') { hss->state=HSS_HEADER_TRANSFER_ENCODING_C; break; }
183 else goto shared;
184
185 case HSS_HEADER_TRANSFER_ENCODING_C:
186 if ((c|0x20)=='h') { hss->state=HSS_HEADER_TRANSFER_ENCODING_CH; break; }
187 else goto shared;
188
189 case HSS_HEADER_TRANSFER_ENCODING_CH:
190 if ((c|0x20)=='u') { hss->state=HSS_HEADER_TRANSFER_ENCODING_CHU; break; }
191 else goto shared;
192
193 case HSS_HEADER_TRANSFER_ENCODING_CHU:
194 if ((c|0x20)=='n') { hss->state=HSS_HEADER_TRANSFER_ENCODING_CHUN; break; }
195 else goto shared;
196
197 case HSS_HEADER_TRANSFER_ENCODING_CHUN:
198 if ((c|0x20)=='k') { hss->state=HSS_HEADER_TRANSFER_ENCODING_CHUNK; break; }
199 else goto shared;
200
201 case HSS_HEADER_TRANSFER_ENCODING_CHUNK:
202 if ((c|0x20)=='e') { hss->state=HSS_HEADER_TRANSFER_ENCODING_CHUNKE; break; }
203 else goto shared;
204
205 case HSS_HEADER_TRANSFER_ENCODING_CHUNKE:
206 if ((c|0x20)=='d') { hss->state=HSS_HEADER_TRANSFER_ENCODING_CHUNKED; break; }
207 else goto shared;
208
209 case HSS_HEADER_TRANSFER_ENCODING_CHUNKED:
210 hss->state=HSS_HEADER_OTHER;
211 if (c==' ' || c=='\t' || c==';' || c=='\r' || c=='\n')
212 hss->bytesleft=CHUNKED;
213 goto shared;
214
215 case HSS_HEADER_OTHER:
216 goto shared;
217
218 case HSS_HEADER_CR:
219 if (c=='\n') { hss->state=HSS_HEADER_CRLF; break; }
220 else goto shared;
221
222 case HSS_HEADER_CRLFCR:
223 if (c=='\n') {
224 // end of header found.
225 if (hss->type==REQUEST) {
226 // if it's a GET request, ignore content-length and chunked
227 // encoding.
228 hss->bytesleft=0;
229 hss->state=HSS_DONE;
230 return 1;
231 }
232 // Now we either have found a content-length or the chunked
233 // encoding marker or neither.
234 if (hss->bytesleft==CHUNKED) {
235 // chunked encoding; read chunked header next.
236 hss->state=HSS_HEADER_CHUNKED_CRLF;
237 } else if (hss->bytesleft==UNKNOWN || hss->bytesleft==0) {
238 // neither chunked encoding nor content length
239 // only way to end the stream is to drop the connection
240 hss->state=HSS_INFINITE;
241 } else {
242 // found positive content length
243 hss->state=HSS_KNOWLENGTH;
244 }
245 break;
246 }
247 else goto shared;
248
249 case HSS_KNOWLENGTH:
250 if (--hss->bytesleft==0) {
251 hss->state=HSS_DONE;
252 return 1;
253 }
254 break;
255
256 case HSS_HEADER_CHUNKED:
257 if (c=='\r')
258 hss->state=HSS_HEADER_CHUNKED_CR;
259 break;
260
261 case HSS_HEADER_CHUNKED_CR:
262 if (c=='\n')
263 hss->state=HSS_HEADER_CHUNKED_CRLF;
264 break;
265
266 case HSS_HEADER_CHUNKED_CRLF:
267 hss->bytesleft=0;
268 // fall through
269 case HSS_HEADER_CHUNKED_CRLF_NUM:
270 if (c>='0' && c<='9')
271 hss->bytesleft=hss->bytesleft*10+c-'0';
272 else if (c>='a' && c<='f')
273 hss->bytesleft=hss->bytesleft*10+c-'a'+10;
274 else if (c>='A' && c<='F')
275 hss->bytesleft=hss->bytesleft*10+c-'A'+10;
276 else if (c=='\r' && hss->state==HSS_HEADER_CHUNKED_CRLF_NUM) {
277 hss->state=HSS_HEADER_CHUNKED_CRLF_NUM_CR;
278 break;
279 }
280 // printf("[bl=%d]",hss->bytesleft);
281 hss->state=HSS_HEADER_CHUNKED_CRLF_NUM;
282 break;
283
284 case HSS_HEADER_CHUNKED_CRLF_NUM_CR:
285 if (c=='\n') {
286 if (hss->bytesleft==0) {
287 hss->state=HSS_DONE;
288 return 1;
289 }
290 hss->state=HSS_KNOWLENGTH_CHUNKED;
291 }
292 break;
293
294 case HSS_KNOWLENGTH_CHUNKED:
295 if (--hss->bytesleft==0)
296 /* chunk is done; read next one */
297 hss->state=HSS_HEADER_CHUNKED;
298 break;
299
300 case HSS_INFINITE:
301 break;
302
303 case HSS_DONE:
304 return 1;
305 }
306 return 0;
307 }
308
httpstream(struct httpstreamstate * hss,const char * buf,size_t len)309 size_t httpstream(struct httpstreamstate* hss,
310 const char* buf, size_t len) {
311 // buf is part of a http request or reply
312 // this is meant to be called from a proxy loop that keeps reading
313 // data from a socket and writing it to another socket. For each
314 // chunk of data that is coming in, the code calls this function on
315 // each chunk. This function then parses the chunk and says how many
316 // bytes in it belong to the http stream. Basically, it will return
317 // len until the stream is finished (request + POST data received or
318 // reply + content data received).
319
320 size_t i;
321 if (hss->state==HSS_DONE)
322 return 0;
323 for (i=0; i<len; ++i)
324 if (httpstream_update(hss,buf[i]))
325 return i+1;
326 return len;
327 }
328
329 #if NEED_MAIN
330 #include <stdio.h>
331
main()332 int main() {
333 struct httpstreamstate hss;
334 // char buf[]="POST / HTTP/1.0\r\nHost: localhost:80\r\nTransfer-Encoding: chunked\r\n\r\n5\r\nfnord\r\n0\r\nhalali";
335 char buf[10000];
336 size_t i,l;
337 FILE* f;
338 f=fopen("/tmp/a/blubber","r");
339 l=fread(buf,1,sizeof(buf),f);
340 httpstream_initstate(&hss);
341
342 for (i=0; i<l; ++i) {
343 printf("%c",buf[i]);
344 if (httpstream_update(&hss,buf[i]))
345 break;
346 printf("[%d,bl=%ld]",hss.state,hss.bytesleft);
347 }
348
349 httpstream_initstate(&hss);
350 printf("%zu\n",httpstream(&hss,buf,l));
351
352 return 0;
353 }
354 #endif
355
356 #endif
357