comparison src/http/ngx_http_parse.c @ 7:b5481d6fbbd4

nginx-0.0.1-2002-08-29-20:59:54 import
author Igor Sysoev <igor@sysoev.ru>
date Thu, 29 Aug 2002 16:59:54 +0000
parents d220029ac7f3
children 6f58641241bb
comparison
equal deleted inserted replaced
6:669801705ab1 7:b5481d6fbbd4
1 1
2 #include <ngx_config.h> 2 #include <ngx_config.h>
3 #include <ngx_core.h>
3 #include <ngx_http.h> 4 #include <ngx_http.h>
4 5
5 int ngx_read_http_request_line(ngx_http_request_t *r) 6 int ngx_read_http_request_line(ngx_http_request_t *r)
6 { 7 {
7 char ch; 8 char ch;
8 char *buff = r->buff->buff; 9 char *p = r->header_in->pos.mem;
9 char *p = r->buff->pos;
10 enum { 10 enum {
11 rl_start = 0, 11 sw_start = 0,
12 rl_space_after_method, 12 sw_space_after_method,
13 rl_spaces_before_uri, 13 sw_spaces_before_uri,
14 rl_after_slash_in_uri, 14 sw_after_slash_in_uri,
15 rl_check_uri, 15 sw_check_uri,
16 rl_uri, 16 sw_uri,
17 rl_http_09, 17 sw_http_09,
18 rl_http_version, 18 sw_http_version,
19 rl_first_major_digit, 19 sw_first_major_digit,
20 rl_major_digit, 20 sw_major_digit,
21 rl_first_minor_digit, 21 sw_first_minor_digit,
22 rl_minor_digit, 22 sw_minor_digit,
23 rl_almost_done, 23 sw_almost_done,
24 rl_done 24 sw_done
25 } state = r->state; 25 } state = r->state;
26 26
27 while (p < r->buff->last && state < rl_done) { 27 while (p < r->header_in->last.mem && state < sw_done) {
28 ch = *p++; 28 ch = *p++;
29 29
30 /* 30 /*
31 printf("\nstate: %d, pos: %x, end: %x, char: '%c' buf: %s", 31 printf("\nstate: %d, pos: %x, end: %x, char: '%c' buf: %s",
32 state, p, r->buff->last, ch, p); 32 state, p, r->header_in->last, ch, p);
33 */ 33 */
34 34
35 /* GCC complie it as jump table */ 35 /* GCC compiles switch as jump table */
36 36
37 switch (state) { 37 switch (state) {
38 38
39 /* HTTP methods: GET, HEAD, POST */ 39 /* HTTP methods: GET, HEAD, POST */
40 case rl_start: 40 case sw_start:
41 switch (ch) { 41 switch (ch) {
42 case 'G': 42 case 'G':
43 if (p + 1 >= r->buff->last) 43 if (p + 1 >= r->header_in->last.mem)
44 return 0; 44 return NGX_AGAIN;
45 45
46 if (*p != 'E' || *(p + 1) != 'T') 46 if (*p != 'E' || *(p + 1) != 'T')
47 return NGX_HTTP_INVALID_METHOD; 47 return NGX_HTTP_INVALID_METHOD;
48 48
49 r->method = NGX_HTTP_GET; 49 r->method = NGX_HTTP_GET;
50 p += 2; 50 p += 2;
51 break; 51 break;
52 52
53 case 'H': 53 case 'H':
54 if (p + 2 >= r->buff->last) 54 if (p + 2 >= r->header_in->last.mem)
55 return 0; 55 return NGX_AGAIN;
56 56
57 if (*p != 'E' || *(p + 1) != 'A' || *(p + 2) != 'D') 57 if (*p != 'E' || *(p + 1) != 'A' || *(p + 2) != 'D')
58 return NGX_HTTP_INVALID_METHOD; 58 return NGX_HTTP_INVALID_METHOD;
59 59
60 r->method = NGX_HTTP_HEAD; 60 r->method = NGX_HTTP_HEAD;
61 p += 3; 61 p += 3;
62 break; 62 break;
63 63
64 case 'P': 64 case 'P':
65 if (p + 2 >= r->buff->last) 65 if (p + 2 >= r->header_in->last.mem)
66 return 0; 66 return NGX_AGAIN;
67 67
68 if (*p != 'O' || *(p + 1) != 'S' || *(p + 2) != 'T') 68 if (*p != 'O' || *(p + 1) != 'S' || *(p + 2) != 'T')
69 return NGX_HTTP_INVALID_METHOD; 69 return NGX_HTTP_INVALID_METHOD;
70 70
71 r->method = NGX_HTTP_POST; 71 r->method = NGX_HTTP_POST;
74 74
75 default: 75 default:
76 return NGX_HTTP_INVALID_METHOD; 76 return NGX_HTTP_INVALID_METHOD;
77 } 77 }
78 78
79 state = rl_space_after_method; 79 state = sw_space_after_method;
80 break; 80 break;
81 81
82 /* single space after method */ 82 /* single space after method */
83 case rl_space_after_method: 83 case sw_space_after_method:
84 switch (ch) { 84 switch (ch) {
85 case ' ': 85 case ' ':
86 state = rl_spaces_before_uri; 86 state = sw_spaces_before_uri;
87 break; 87 break;
88 default: 88 default:
89 return NGX_HTTP_INVALID_METHOD; 89 return NGX_HTTP_INVALID_METHOD;
90 } 90 }
91 break; 91 break;
92 92
93 /* space* before URI */ 93 /* space* before URI */
94 case rl_spaces_before_uri: 94 case sw_spaces_before_uri:
95 switch (ch) { 95 switch (ch) {
96 case '/': 96 case '/':
97 r->uri_start = p - 1; 97 r->uri_start = p - 1;
98 state = rl_after_slash_in_uri; 98 state = sw_after_slash_in_uri;
99 break; 99 break;
100 case ' ': 100 case ' ':
101 break; 101 break;
102 default: 102 default:
103 r->unusual_uri = 1; 103 r->unusual_uri = 1;
104 r->uri_start = p - 1; 104 r->uri_start = p - 1;
105 state = rl_uri; 105 state = sw_uri;
106 break; 106 break;
107 } 107 }
108 break; 108 break;
109 109
110 /* check dot after slash */ 110 /* check dot after slash */
111 case rl_after_slash_in_uri: 111 case sw_after_slash_in_uri:
112 switch (ch) { 112 switch (ch) {
113 case CR: 113 case CR:
114 r->uri_end = p - 1; 114 r->uri_end = p - 1;
115 r->http_minor = 9; 115 r->http_minor = 9;
116 state = rl_almost_done; 116 state = sw_almost_done;
117 break; 117 break;
118 case LF: 118 case LF:
119 r->uri_end = p - 1; 119 r->uri_end = p - 1;
120 r->http_minor = 9; 120 r->http_minor = 9;
121 state = rl_done; 121 state = sw_done;
122 break; 122 break;
123 case ' ': 123 case ' ':
124 r->uri_end = p - 1; 124 r->uri_end = p - 1;
125 state = rl_http_09; 125 state = sw_http_09;
126 break; 126 break;
127 case '.': 127 case '.':
128 r->complex_uri = 1; 128 r->complex_uri = 1;
129 state = rl_uri; 129 state = sw_uri;
130 break; 130 break;
131 case '/': 131 case '/':
132 r->complex_uri = 1; 132 r->complex_uri = 1;
133 state = rl_uri; 133 state = sw_uri;
134 break; 134 break;
135 case '?': 135 case '?':
136 r->args_start = p; 136 r->args_start = p;
137 state = rl_uri; 137 state = sw_uri;
138 break; 138 break;
139 default: 139 default:
140 state = rl_check_uri; 140 state = sw_check_uri;
141 break; 141 break;
142 } 142 }
143 break; 143 break;
144 144
145 /* check slash in URI */ 145 /* check slash in URI */
146 case rl_check_uri: 146 case sw_check_uri:
147 switch (ch) { 147 switch (ch) {
148 case CR: 148 case CR:
149 r->uri_end = p - 1; 149 r->uri_end = p - 1;
150 r->http_minor = 9; 150 r->http_minor = 9;
151 state = rl_almost_done; 151 state = sw_almost_done;
152 break; 152 break;
153 case LF: 153 case LF:
154 r->uri_end = p - 1; 154 r->uri_end = p - 1;
155 r->http_minor = 9; 155 r->http_minor = 9;
156 state = rl_done; 156 state = sw_done;
157 break; 157 break;
158 case ' ': 158 case ' ':
159 r->uri_end = p - 1; 159 r->uri_end = p - 1;
160 state = rl_http_09; 160 state = sw_http_09;
161 break; 161 break;
162 case '.': 162 case '.':
163 r->uri_ext = p; 163 r->uri_ext = p;
164 break; 164 break;
165 case '/': 165 case '/':
166 r->uri_ext = NULL; 166 r->uri_ext = NULL;
167 state = rl_after_slash_in_uri; 167 state = sw_after_slash_in_uri;
168 break; 168 break;
169 case '?': 169 case '?':
170 r->args_start = p; 170 r->args_start = p;
171 state = rl_uri; 171 state = sw_uri;
172 break; 172 break;
173 } 173 }
174 break; 174 break;
175 175
176 /* URI */ 176 /* URI */
177 case rl_uri: 177 case sw_uri:
178 switch (ch) { 178 switch (ch) {
179 case CR: 179 case CR:
180 r->uri_end = p - 1; 180 r->uri_end = p - 1;
181 r->http_minor = 9; 181 r->http_minor = 9;
182 state = rl_almost_done; 182 state = sw_almost_done;
183 break; 183 break;
184 case LF: 184 case LF:
185 r->uri_end = p - 1; 185 r->uri_end = p - 1;
186 r->http_minor = 9; 186 r->http_minor = 9;
187 state = rl_done; 187 state = sw_done;
188 break; 188 break;
189 case ' ': 189 case ' ':
190 r->uri_end = p - 1; 190 r->uri_end = p - 1;
191 state = rl_http_09; 191 state = sw_http_09;
192 break; 192 break;
193 } 193 }
194 break; 194 break;
195 195
196 /* space+ after URI */ 196 /* space+ after URI */
197 case rl_http_09: 197 case sw_http_09:
198 switch (ch) { 198 switch (ch) {
199 case ' ': 199 case ' ':
200 break; 200 break;
201 case CR: 201 case CR:
202 r->http_minor = 9; 202 r->http_minor = 9;
203 state = rl_almost_done; 203 state = sw_almost_done;
204 break; 204 break;
205 case LF: 205 case LF:
206 r->http_minor = 9; 206 r->http_minor = 9;
207 state = rl_done; 207 state = sw_done;
208 break; 208 break;
209 case 'H': 209 case 'H':
210 state = rl_http_version; 210 state = sw_http_version;
211 break; 211 break;
212 default: 212 default:
213 return NGX_HTTP_INVALID_REQUEST; 213 return NGX_HTTP_INVALID_REQUEST;
214 } 214 }
215 break; 215 break;
216 216
217 /* TTP/ */ 217 /* TTP/ */
218 case rl_http_version: 218 case sw_http_version:
219 if (p + 2 >= r->buff->last) { 219 if (p + 2 >= r->header_in->last.mem) {
220 r->state = rl_http_version; 220 r->state = sw_http_version;
221 r->buff->pos = p - 1; 221 r->header_in->pos.mem = p - 1;
222 return 0; 222 return NGX_AGAIN;
223 } 223 }
224 224
225 if (ch != 'T' || *p != 'T' || *(p + 1) != 'P' || *(p + 2) != '/') 225 if (ch != 'T' || *p != 'T' || *(p + 1) != 'P' || *(p + 2) != '/')
226 return NGX_HTTP_INVALID_REQUEST; 226 return NGX_HTTP_INVALID_REQUEST;
227 227
228 p += 3; 228 p += 3;
229 state = rl_first_major_digit; 229 state = sw_first_major_digit;
230 break; 230 break;
231 231
232 /* first digit of major HTTP version */ 232 /* first digit of major HTTP version */
233 case rl_first_major_digit: 233 case sw_first_major_digit:
234 if (ch < '1' || ch > '9') 234 if (ch < '1' || ch > '9')
235 return NGX_HTTP_INVALID_REQUEST; 235 return NGX_HTTP_INVALID_REQUEST;
236 236
237 r->http_major = ch - '0'; 237 r->http_major = ch - '0';
238 state = rl_major_digit; 238 state = sw_major_digit;
239 break; 239 break;
240 240
241 /* major HTTP version or dot */ 241 /* major HTTP version or dot */
242 case rl_major_digit: 242 case sw_major_digit:
243 if (ch == '.') { 243 if (ch == '.') {
244 state = rl_first_minor_digit; 244 state = sw_first_minor_digit;
245 break; 245 break;
246 } 246 }
247 247
248 if (ch < '0' || ch > '9') 248 if (ch < '0' || ch > '9')
249 return NGX_HTTP_INVALID_REQUEST; 249 return NGX_HTTP_INVALID_REQUEST;
250 250
251 r->http_major = r->http_major * 10 + ch - '0'; 251 r->http_major = r->http_major * 10 + ch - '0';
252 break; 252 break;
253 253
254 /* first digit of minor HTTP version */ 254 /* first digit of minor HTTP version */
255 case rl_first_minor_digit: 255 case sw_first_minor_digit:
256 if (ch < '0' || ch > '9') 256 if (ch < '0' || ch > '9')
257 return NGX_HTTP_INVALID_REQUEST; 257 return NGX_HTTP_INVALID_REQUEST;
258 258
259 r->http_minor = ch - '0'; 259 r->http_minor = ch - '0';
260 260
261 state = rl_minor_digit; 261 state = sw_minor_digit;
262 break; 262 break;
263 263
264 /* minor HTTP version or end of request line */ 264 /* minor HTTP version or end of request line */
265 case rl_minor_digit: 265 case sw_minor_digit:
266 if (ch == CR) { 266 if (ch == CR) {
267 state = rl_almost_done; 267 state = sw_almost_done;
268 break; 268 break;
269 } 269 }
270 270
271 if (ch == LF) { 271 if (ch == LF) {
272 state = rl_done; 272 state = sw_done;
273 break; 273 break;
274 } 274 }
275 275
276 if (ch < '0' || ch > '9') 276 if (ch < '0' || ch > '9')
277 return NGX_HTTP_INVALID_REQUEST; 277 return NGX_HTTP_INVALID_REQUEST;
278 278
279 r->http_minor = r->http_minor * 10 + ch - '0'; 279 r->http_minor = r->http_minor * 10 + ch - '0';
280 break; 280 break;
281 281
282 /* end of request line */ 282 /* end of request line */
283 case rl_almost_done: 283 case sw_almost_done:
284 switch (ch) { 284 switch (ch) {
285 case LF: 285 case LF:
286 state = rl_done; 286 state = sw_done;
287 break; 287 break;
288 default: 288 default:
289 return NGX_HTTP_INVALID_METHOD; 289 return NGX_HTTP_INVALID_REQUEST;
290 } 290 }
291 break; 291 break;
292 } 292 }
293 } 293 }
294 294
295 r->buff->pos = p; 295 r->header_in->pos.mem = p;
296 296
297 if (state == rl_done) { 297 if (state == sw_done) {
298 r->http_version = r->http_major * 1000 + r->http_minor; 298 r->http_version = r->http_major * 1000 + r->http_minor;
299 r->state = rl_start; 299 r->state = sw_start;
300 return 1; 300 if (r->http_version == 9 && r->method == NGX_HTTP_HEAD)
301 return NGX_HTTP_INVALID_HEAD;
302 else
303 return NGX_OK;
301 } else { 304 } else {
302 r->state = state; 305 r->state = state;
303 return 0; 306 return NGX_AGAIN;
304 } 307 }
305 } 308 }
306 309
307 int ngx_read_http_header_line(ngx_http_request_t *r) 310 int ngx_read_http_header_line(ngx_http_request_t *r)
308 { 311 {
309 char c, ch; 312 char c, ch;
310 char *buff = r->buff->buff; 313 char *p = r->header_in->pos.mem;
311 char *p = r->buff->pos;
312 enum { 314 enum {
313 hl_start = 0, 315 sw_start = 0,
314 hl_name, 316 sw_name,
315 hl_space_before_value, 317 sw_space_before_value,
316 hl_value, 318 sw_value,
317 hl_space_after_value, 319 sw_space_after_value,
318 hl_almost_done, 320 sw_almost_done,
319 header_almost_done, 321 sw_header_almost_done,
320 hl_done, 322 sw_done,
321 header_done 323 sw_header_done
322 } state = r->state; 324 } state = r->state;
323 325
324 while (p < r->buff->last && state < hl_done) { 326 while (p < r->header_in->last.mem && state < sw_done) {
325 ch = *p++; 327 ch = *p++;
326 328
327 /* 329 /*
328 printf("\nstate: %d, pos: %x, end: %x, char: '%c' buf: %s", 330 printf("\nstate: %d, pos: %x, end: %x, char: '%c' buf: %s",
329 state, p, r->buff->last, ch, p); 331 state, p, r->header_in->last.mem, ch, p);
330 */ 332 */
331 333
332 switch (state) { 334 switch (state) {
333 335
334 /* first char */ 336 /* first char */
335 case hl_start: 337 case sw_start:
336 switch (ch) { 338 switch (ch) {
337 case CR: 339 case CR:
338 r->header_end = p - 1; 340 r->header_end = p - 1;
339 state = header_almost_done; 341 state = sw_header_almost_done;
340 break; 342 break;
341 case LF: 343 case LF:
342 r->header_end = p - 1; 344 r->header_end = p - 1;
343 state = header_done; 345 state = sw_header_done;
344 break; 346 break;
345 default: 347 default:
346 state = hl_name; 348 state = sw_name;
347 r->header_name_start = p - 1; 349 r->header_name_start = p - 1;
348 350
349 c = ch | 0x20; 351 c = ch | 0x20;
350 if (c >= 'a' && c <= 'z') 352 if (c >= 'a' && c <= 'z')
351 break; 353 break;
360 362
361 } 363 }
362 break; 364 break;
363 365
364 /* header name */ 366 /* header name */
365 case hl_name: 367 case sw_name:
366 c = ch | 0x20; 368 c = ch | 0x20;
367 if (c >= 'a' && c <= 'z') 369 if (c >= 'a' && c <= 'z')
368 break; 370 break;
369 371
370 if (ch == ':') { 372 if (ch == ':') {
371 r->header_name_end = p - 1; 373 r->header_name_end = p - 1;
372 state = hl_space_before_value; 374 state = sw_space_before_value;
373 break; 375 break;
374 } 376 }
375 377
376 if (ch == '-') 378 if (ch == '-')
377 break; 379 break;
380 break; 382 break;
381 383
382 return NGX_HTTP_INVALID_HEADER; 384 return NGX_HTTP_INVALID_HEADER;
383 385
384 /* space* before header value */ 386 /* space* before header value */
385 case hl_space_before_value: 387 case sw_space_before_value:
386 switch (ch) { 388 switch (ch) {
387 case ' ': 389 case ' ':
388 break; 390 break;
389 case CR: 391 case CR:
390 r->header_start = r->header_end = p - 1; 392 r->header_start = r->header_end = p - 1;
391 state = hl_almost_done; 393 state = sw_almost_done;
392 break; 394 break;
393 case LF: 395 case LF:
394 r->header_start = r->header_end = p - 1; 396 r->header_start = r->header_end = p - 1;
395 state = hl_done; 397 state = sw_done;
396 break; 398 break;
397 default: 399 default:
398 r->header_start = p - 1; 400 r->header_start = p - 1;
399 state = hl_value; 401 state = sw_value;
400 break; 402 break;
401 } 403 }
402 break; 404 break;
403 405
404 /* header value */ 406 /* header value */
405 case hl_value: 407 case sw_value:
406 switch (ch) { 408 switch (ch) {
407 case ' ': 409 case ' ':
408 r->header_end = p - 1; 410 r->header_end = p - 1;
409 state = hl_space_after_value; 411 state = sw_space_after_value;
410 break; 412 break;
411 case CR: 413 case CR:
412 r->header_end = p - 1; 414 r->header_end = p - 1;
413 state = hl_almost_done; 415 state = sw_almost_done;
414 break; 416 break;
415 case LF: 417 case LF:
416 r->header_end = p - 1; 418 r->header_end = p - 1;
417 state = hl_done; 419 state = sw_done;
418 break; 420 break;
419 } 421 }
420 break; 422 break;
421 423
422 /* space* before end of header line */ 424 /* space* before end of header line */
423 case hl_space_after_value: 425 case sw_space_after_value:
424 switch (ch) { 426 switch (ch) {
425 case ' ': 427 case ' ':
426 break; 428 break;
427 case CR: 429 case CR:
428 state = hl_almost_done; 430 state = sw_almost_done;
429 break; 431 break;
430 case LF: 432 case LF:
431 state = hl_done; 433 state = sw_done;
432 break; 434 break;
433 default: 435 default:
434 state = hl_value; 436 state = sw_value;
435 break; 437 break;
436 } 438 }
437 break; 439 break;
438 440
439 /* end of header line */ 441 /* end of header line */
440 case hl_almost_done: 442 case sw_almost_done:
441 switch (ch) { 443 switch (ch) {
442 case LF: 444 case LF:
443 state = hl_done; 445 state = sw_done;
444 break; 446 break;
445 default: 447 default:
446 return NGX_HTTP_INVALID_HEADER; 448 return NGX_HTTP_INVALID_HEADER;
447 } 449 }
448 break; 450 break;
449 451
450 /* end of header */ 452 /* end of header */
451 case header_almost_done: 453 case sw_header_almost_done:
452 switch (ch) { 454 switch (ch) {
453 case LF: 455 case LF:
454 state = header_done; 456 state = sw_header_done;
455 break; 457 break;
456 default: 458 default:
457 return NGX_HTTP_INVALID_HEADER; 459 return NGX_HTTP_INVALID_HEADER;
458 } 460 }
459 break; 461 break;
460 } 462 }
461 } 463 }
462 464
463 r->buff->pos = p; 465 r->header_in->pos.mem = p;
464 466
465 if (state == hl_done) { 467 if (state == sw_done) {
466 r->state = hl_start; 468 r->state = sw_start;
467 return 1; 469 return NGX_OK;
468 } else if (state == header_done) { 470 } else if (state == sw_header_done) {
469 r->state = hl_start; 471 r->state = sw_start;
470 return 2; 472 return NGX_HTTP_HEADER_DONE;
471 } else { 473 } else {
472 r->state = state; 474 r->state = state;
473 return 0; 475 return NGX_AGAIN;
474 } 476 }
475 } 477 }