Mercurial > hg > nginx-vendor-1-0
comparison src/http/ngx_http_parse.c @ 0:f0b350454894 NGINX_0_1_0
nginx 0.1.0
*) The first public version.
author | Igor Sysoev <http://sysoev.ru> |
---|---|
date | Mon, 04 Oct 2004 00:00:00 +0400 |
parents | |
children | cc9f381affaa |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:f0b350454894 |
---|---|
1 | |
2 /* | |
3 * Copyright (C) Igor Sysoev | |
4 */ | |
5 | |
6 | |
7 #include <ngx_config.h> | |
8 #include <ngx_core.h> | |
9 #include <ngx_http.h> | |
10 | |
11 | |
12 ngx_int_t ngx_http_parse_request_line(ngx_http_request_t *r, ngx_buf_t *b) | |
13 { | |
14 u_char ch, *p, *m; | |
15 enum { | |
16 sw_start = 0, | |
17 sw_method, | |
18 sw_space_after_method, | |
19 sw_spaces_before_uri, | |
20 sw_schema, | |
21 sw_schema_slash, | |
22 sw_schema_slash_slash, | |
23 sw_host, | |
24 sw_port, | |
25 sw_after_slash_in_uri, | |
26 sw_check_uri, | |
27 sw_uri, | |
28 sw_http_09, | |
29 sw_http_H, | |
30 sw_http_HT, | |
31 sw_http_HTT, | |
32 sw_http_HTTP, | |
33 sw_first_major_digit, | |
34 sw_major_digit, | |
35 sw_first_minor_digit, | |
36 sw_minor_digit, | |
37 sw_almost_done, | |
38 sw_done | |
39 } state; | |
40 | |
41 state = r->state; | |
42 p = b->pos; | |
43 | |
44 while (p < b->last && state < sw_done) { | |
45 ch = *p++; | |
46 | |
47 /* gcc 2.95.2 and msvc 6.0 compile this switch as an jump table */ | |
48 | |
49 switch (state) { | |
50 | |
51 /* HTTP methods: GET, HEAD, POST */ | |
52 case sw_start: | |
53 r->request_start = p - 1; | |
54 | |
55 if (ch == CR || ch == LF) { | |
56 break; | |
57 } | |
58 | |
59 if (ch < 'A' || ch > 'Z') { | |
60 return NGX_HTTP_PARSE_INVALID_METHOD; | |
61 } | |
62 | |
63 state = sw_method; | |
64 break; | |
65 | |
66 case sw_method: | |
67 if (ch == ' ') { | |
68 r->method_end = p - 1; | |
69 m = r->request_start; | |
70 | |
71 if (r->method_end - m == 3) { | |
72 | |
73 if (m[0] == 'G' && m[1] == 'E' && m[2] == 'T') { | |
74 r->method = NGX_HTTP_GET; | |
75 } | |
76 | |
77 } else if (r->method_end - m == 4) { | |
78 | |
79 if (m[0] == 'P' && m[1] == 'O' | |
80 && m[2] == 'T' && m[3] == 'T') | |
81 { | |
82 r->method = NGX_HTTP_POST; | |
83 | |
84 } else if (m[0] == 'H' && m[1] == 'E' | |
85 && m[2] == 'A' && m[3] == 'D') | |
86 { | |
87 r->method = NGX_HTTP_HEAD; | |
88 } | |
89 } | |
90 | |
91 state = sw_spaces_before_uri; | |
92 break; | |
93 } | |
94 | |
95 if (ch < 'A' || ch > 'Z') { | |
96 return NGX_HTTP_PARSE_INVALID_METHOD; | |
97 } | |
98 | |
99 break; | |
100 | |
101 /* single space after method */ | |
102 case sw_space_after_method: | |
103 switch (ch) { | |
104 case ' ': | |
105 state = sw_spaces_before_uri; | |
106 break; | |
107 default: | |
108 return NGX_HTTP_PARSE_INVALID_METHOD; | |
109 } | |
110 break; | |
111 | |
112 /* space* before URI */ | |
113 case sw_spaces_before_uri: | |
114 switch (ch) { | |
115 case '/': | |
116 r->uri_start = p - 1; | |
117 state = sw_after_slash_in_uri; | |
118 break; | |
119 case ' ': | |
120 break; | |
121 default: | |
122 if ((ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z')) { | |
123 r->schema_start = p - 1; | |
124 state = sw_schema; | |
125 break; | |
126 } | |
127 return NGX_HTTP_PARSE_INVALID_REQUEST; | |
128 } | |
129 break; | |
130 | |
131 case sw_schema: | |
132 switch (ch) { | |
133 case ':': | |
134 r->schema_end = p - 1; | |
135 state = sw_schema_slash; | |
136 break; | |
137 default: | |
138 if ((ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z')) { | |
139 break; | |
140 } | |
141 return NGX_HTTP_PARSE_INVALID_REQUEST; | |
142 } | |
143 break; | |
144 | |
145 case sw_schema_slash: | |
146 switch (ch) { | |
147 case '/': | |
148 state = sw_schema_slash_slash; | |
149 break; | |
150 default: | |
151 return NGX_HTTP_PARSE_INVALID_REQUEST; | |
152 } | |
153 break; | |
154 | |
155 case sw_schema_slash_slash: | |
156 switch (ch) { | |
157 case '/': | |
158 r->host_start = p - 1; | |
159 state = sw_host; | |
160 break; | |
161 default: | |
162 return NGX_HTTP_PARSE_INVALID_REQUEST; | |
163 } | |
164 break; | |
165 | |
166 case sw_host: | |
167 switch (ch) { | |
168 case ':': | |
169 r->host_end = p - 1; | |
170 state = sw_port; | |
171 break; | |
172 case '/': | |
173 r->host_end = p - 1; | |
174 r->uri_start = p - 1; | |
175 state = sw_after_slash_in_uri; | |
176 break; | |
177 default: | |
178 if ((ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z') | |
179 || (ch >= '0' && ch <= '9') || ch == '.' || ch == '-') | |
180 { | |
181 break; | |
182 } | |
183 return NGX_HTTP_PARSE_INVALID_REQUEST; | |
184 } | |
185 break; | |
186 | |
187 case sw_port: | |
188 switch (ch) { | |
189 case '/': | |
190 r->port_end = p - 1; | |
191 r->uri_start = p - 1; | |
192 state = sw_after_slash_in_uri; | |
193 break; | |
194 default: | |
195 if (ch < '0' && ch > '9') { | |
196 return NGX_HTTP_PARSE_INVALID_REQUEST; | |
197 } | |
198 break; | |
199 } | |
200 break; | |
201 | |
202 /* check "/.", "//", and "%" in URI */ | |
203 case sw_after_slash_in_uri: | |
204 switch (ch) { | |
205 case CR: | |
206 r->uri_end = p - 1; | |
207 r->http_minor = 9; | |
208 state = sw_almost_done; | |
209 break; | |
210 case LF: | |
211 r->uri_end = p - 1; | |
212 r->http_minor = 9; | |
213 state = sw_done; | |
214 break; | |
215 case ' ': | |
216 r->uri_end = p - 1; | |
217 state = sw_http_09; | |
218 break; | |
219 case '.': | |
220 case '%': | |
221 r->complex_uri = 1; | |
222 state = sw_uri; | |
223 break; | |
224 case '/': | |
225 r->complex_uri = 1; | |
226 break; | |
227 case '?': | |
228 r->args_start = p; | |
229 state = sw_uri; | |
230 break; | |
231 default: | |
232 state = sw_check_uri; | |
233 break; | |
234 } | |
235 break; | |
236 | |
237 /* check "/" and "%" in URI */ | |
238 case sw_check_uri: | |
239 switch (ch) { | |
240 case CR: | |
241 r->uri_end = p - 1; | |
242 r->http_minor = 9; | |
243 state = sw_almost_done; | |
244 break; | |
245 case LF: | |
246 r->uri_end = p - 1; | |
247 r->http_minor = 9; | |
248 state = sw_done; | |
249 break; | |
250 case ' ': | |
251 r->uri_end = p - 1; | |
252 state = sw_http_09; | |
253 break; | |
254 case '.': | |
255 r->uri_ext = p; | |
256 break; | |
257 case '/': | |
258 r->uri_ext = NULL; | |
259 state = sw_after_slash_in_uri; | |
260 break; | |
261 case '%': | |
262 r->complex_uri = 1; | |
263 state = sw_uri; | |
264 break; | |
265 case '?': | |
266 r->args_start = p; | |
267 state = sw_uri; | |
268 break; | |
269 } | |
270 break; | |
271 | |
272 /* URI */ | |
273 case sw_uri: | |
274 switch (ch) { | |
275 case CR: | |
276 r->uri_end = p - 1; | |
277 r->http_minor = 9; | |
278 state = sw_almost_done; | |
279 break; | |
280 case LF: | |
281 r->uri_end = p - 1; | |
282 r->http_minor = 9; | |
283 state = sw_done; | |
284 break; | |
285 case ' ': | |
286 r->uri_end = p - 1; | |
287 state = sw_http_09; | |
288 break; | |
289 } | |
290 break; | |
291 | |
292 /* space+ after URI */ | |
293 case sw_http_09: | |
294 switch (ch) { | |
295 case ' ': | |
296 break; | |
297 case CR: | |
298 r->http_minor = 9; | |
299 state = sw_almost_done; | |
300 break; | |
301 case LF: | |
302 r->http_minor = 9; | |
303 state = sw_done; | |
304 break; | |
305 case 'H': | |
306 state = sw_http_H; | |
307 break; | |
308 default: | |
309 return NGX_HTTP_PARSE_INVALID_REQUEST; | |
310 } | |
311 break; | |
312 | |
313 case sw_http_H: | |
314 switch (ch) { | |
315 case 'T': | |
316 state = sw_http_HT; | |
317 break; | |
318 default: | |
319 return NGX_HTTP_PARSE_INVALID_REQUEST; | |
320 } | |
321 break; | |
322 | |
323 case sw_http_HT: | |
324 switch (ch) { | |
325 case 'T': | |
326 state = sw_http_HTT; | |
327 break; | |
328 default: | |
329 return NGX_HTTP_PARSE_INVALID_REQUEST; | |
330 } | |
331 break; | |
332 | |
333 case sw_http_HTT: | |
334 switch (ch) { | |
335 case 'P': | |
336 state = sw_http_HTTP; | |
337 break; | |
338 default: | |
339 return NGX_HTTP_PARSE_INVALID_REQUEST; | |
340 } | |
341 break; | |
342 | |
343 case sw_http_HTTP: | |
344 switch (ch) { | |
345 case '/': | |
346 state = sw_first_major_digit; | |
347 break; | |
348 default: | |
349 return NGX_HTTP_PARSE_INVALID_REQUEST; | |
350 } | |
351 break; | |
352 | |
353 /* first digit of major HTTP version */ | |
354 case sw_first_major_digit: | |
355 if (ch < '1' || ch > '9') { | |
356 return NGX_HTTP_PARSE_INVALID_REQUEST; | |
357 } | |
358 | |
359 r->http_major = ch - '0'; | |
360 state = sw_major_digit; | |
361 break; | |
362 | |
363 /* major HTTP version or dot */ | |
364 case sw_major_digit: | |
365 if (ch == '.') { | |
366 state = sw_first_minor_digit; | |
367 break; | |
368 } | |
369 | |
370 if (ch < '0' || ch > '9') { | |
371 return NGX_HTTP_PARSE_INVALID_REQUEST; | |
372 } | |
373 | |
374 r->http_major = r->http_major * 10 + ch - '0'; | |
375 break; | |
376 | |
377 /* first digit of minor HTTP version */ | |
378 case sw_first_minor_digit: | |
379 if (ch < '0' || ch > '9') { | |
380 return NGX_HTTP_PARSE_INVALID_REQUEST; | |
381 } | |
382 | |
383 r->http_minor = ch - '0'; | |
384 state = sw_minor_digit; | |
385 break; | |
386 | |
387 /* minor HTTP version or end of request line */ | |
388 case sw_minor_digit: | |
389 if (ch == CR) { | |
390 state = sw_almost_done; | |
391 break; | |
392 } | |
393 | |
394 if (ch == LF) { | |
395 state = sw_done; | |
396 break; | |
397 } | |
398 | |
399 if (ch < '0' || ch > '9') { | |
400 return NGX_HTTP_PARSE_INVALID_REQUEST; | |
401 } | |
402 | |
403 r->http_minor = r->http_minor * 10 + ch - '0'; | |
404 break; | |
405 | |
406 /* end of request line */ | |
407 case sw_almost_done: | |
408 r->request_end = p - 2; | |
409 switch (ch) { | |
410 case LF: | |
411 state = sw_done; | |
412 break; | |
413 default: | |
414 return NGX_HTTP_PARSE_INVALID_REQUEST; | |
415 } | |
416 break; | |
417 | |
418 /* suppress warning */ | |
419 case sw_done: | |
420 break; | |
421 } | |
422 } | |
423 | |
424 b->pos = p; | |
425 | |
426 if (state == sw_done) { | |
427 if (r->request_end == NULL) { | |
428 r->request_end = p - 1; | |
429 } | |
430 | |
431 r->http_version = r->http_major * 1000 + r->http_minor; | |
432 r->state = sw_start; | |
433 | |
434 if (r->http_version == 9 && r->method != NGX_HTTP_GET) { | |
435 return NGX_HTTP_PARSE_INVALID_09_METHOD; | |
436 } | |
437 | |
438 return NGX_OK; | |
439 | |
440 } else { | |
441 r->state = state; | |
442 return NGX_AGAIN; | |
443 } | |
444 } | |
445 | |
446 | |
447 ngx_int_t ngx_http_parse_header_line(ngx_http_request_t *r, ngx_buf_t *b) | |
448 { | |
449 u_char c, ch, *p; | |
450 enum { | |
451 sw_start = 0, | |
452 sw_name, | |
453 sw_space_before_value, | |
454 sw_value, | |
455 sw_space_after_value, | |
456 sw_almost_done, | |
457 sw_header_almost_done, | |
458 sw_ignore_line, | |
459 sw_done, | |
460 sw_header_done | |
461 } state; | |
462 | |
463 state = r->state; | |
464 p = b->pos; | |
465 | |
466 while (p < b->last && state < sw_done) { | |
467 ch = *p++; | |
468 | |
469 switch (state) { | |
470 | |
471 /* first char */ | |
472 case sw_start: | |
473 switch (ch) { | |
474 case CR: | |
475 r->header_end = p - 1; | |
476 state = sw_header_almost_done; | |
477 break; | |
478 case LF: | |
479 r->header_end = p - 1; | |
480 state = sw_header_done; | |
481 break; | |
482 default: | |
483 state = sw_name; | |
484 r->header_name_start = p - 1; | |
485 | |
486 c = (u_char) (ch | 0x20); | |
487 if (c >= 'a' && c <= 'z') { | |
488 break; | |
489 } | |
490 | |
491 if (ch == '-' || ch == '_' || ch == '~' || ch == '.') { | |
492 break; | |
493 } | |
494 | |
495 if (ch >= '0' && ch <= '9') { | |
496 break; | |
497 } | |
498 | |
499 return NGX_HTTP_PARSE_INVALID_HEADER; | |
500 | |
501 } | |
502 break; | |
503 | |
504 /* header name */ | |
505 case sw_name: | |
506 c = (u_char) (ch | 0x20); | |
507 if (c >= 'a' && c <= 'z') { | |
508 break; | |
509 } | |
510 | |
511 if (ch == ':') { | |
512 r->header_name_end = p - 1; | |
513 state = sw_space_before_value; | |
514 break; | |
515 } | |
516 | |
517 if (ch == '-' || ch == '_' || ch == '~' || ch == '.') { | |
518 break; | |
519 } | |
520 | |
521 if (ch >= '0' && ch <= '9') { | |
522 break; | |
523 } | |
524 | |
525 /* IIS can send duplicate "HTTP/1.1 ..." lines */ | |
526 if (ch == '/' | |
527 && r->proxy | |
528 && p - r->header_start == 5 | |
529 && ngx_strncmp(r->header_start, "HTTP", 4) == 0) | |
530 { | |
531 state = sw_ignore_line; | |
532 break; | |
533 } | |
534 | |
535 return NGX_HTTP_PARSE_INVALID_HEADER; | |
536 | |
537 /* space* before header value */ | |
538 case sw_space_before_value: | |
539 switch (ch) { | |
540 case ' ': | |
541 break; | |
542 case CR: | |
543 r->header_start = r->header_end = p - 1; | |
544 state = sw_almost_done; | |
545 break; | |
546 case LF: | |
547 r->header_start = r->header_end = p - 1; | |
548 state = sw_done; | |
549 break; | |
550 default: | |
551 r->header_start = p - 1; | |
552 state = sw_value; | |
553 break; | |
554 } | |
555 break; | |
556 | |
557 /* header value */ | |
558 case sw_value: | |
559 switch (ch) { | |
560 case ' ': | |
561 r->header_end = p - 1; | |
562 state = sw_space_after_value; | |
563 break; | |
564 case CR: | |
565 r->header_end = p - 1; | |
566 state = sw_almost_done; | |
567 break; | |
568 case LF: | |
569 r->header_end = p - 1; | |
570 state = sw_done; | |
571 break; | |
572 } | |
573 break; | |
574 | |
575 /* space* before end of header line */ | |
576 case sw_space_after_value: | |
577 switch (ch) { | |
578 case ' ': | |
579 break; | |
580 case CR: | |
581 state = sw_almost_done; | |
582 break; | |
583 case LF: | |
584 state = sw_done; | |
585 break; | |
586 default: | |
587 state = sw_value; | |
588 break; | |
589 } | |
590 break; | |
591 | |
592 /* ignore header line */ | |
593 case sw_ignore_line: | |
594 switch (ch) { | |
595 case LF: | |
596 state = sw_start; | |
597 break; | |
598 default: | |
599 break; | |
600 } | |
601 break; | |
602 | |
603 /* end of header line */ | |
604 case sw_almost_done: | |
605 switch (ch) { | |
606 case LF: | |
607 state = sw_done; | |
608 break; | |
609 default: | |
610 return NGX_HTTP_PARSE_INVALID_HEADER; | |
611 } | |
612 break; | |
613 | |
614 /* end of header */ | |
615 case sw_header_almost_done: | |
616 switch (ch) { | |
617 case LF: | |
618 state = sw_header_done; | |
619 break; | |
620 default: | |
621 return NGX_HTTP_PARSE_INVALID_HEADER; | |
622 } | |
623 break; | |
624 | |
625 /* suppress warning */ | |
626 case sw_done: | |
627 case sw_header_done: | |
628 break; | |
629 } | |
630 } | |
631 | |
632 b->pos = p; | |
633 | |
634 if (state == sw_done) { | |
635 r->state = sw_start; | |
636 return NGX_OK; | |
637 | |
638 } else if (state == sw_header_done) { | |
639 r->state = sw_start; | |
640 return NGX_HTTP_PARSE_HEADER_DONE; | |
641 | |
642 } else { | |
643 r->state = state; | |
644 return NGX_AGAIN; | |
645 } | |
646 } | |
647 | |
648 | |
649 ngx_int_t ngx_http_parse_complex_uri(ngx_http_request_t *r) | |
650 { | |
651 u_char c, ch, decoded, *p, *u; | |
652 enum { | |
653 sw_usual = 0, | |
654 sw_slash, | |
655 sw_dot, | |
656 sw_dot_dot, | |
657 #if (WIN32) | |
658 sw_dot_dot_dot, | |
659 #endif | |
660 sw_quoted, | |
661 sw_quoted_second | |
662 } state, quoted_state; | |
663 | |
664 decoded = '\0'; | |
665 quoted_state = sw_usual; | |
666 | |
667 state = sw_usual; | |
668 p = r->uri_start; | |
669 u = r->uri.data; | |
670 r->uri_ext = NULL; | |
671 | |
672 ch = *p++; | |
673 | |
674 while (p < r->uri_start + r->uri.len + 1) { | |
675 | |
676 ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
677 "s:%d in:'%x:%c', out:'%c'", state, ch, ch, *u); | |
678 | |
679 switch (state) { | |
680 case sw_usual: | |
681 switch(ch) { | |
682 case '/': | |
683 r->uri_ext = NULL; | |
684 state = sw_slash; | |
685 *u++ = ch; | |
686 break; | |
687 case '%': | |
688 quoted_state = state; | |
689 state = sw_quoted; | |
690 break; | |
691 case '.': | |
692 r->uri_ext = u + 1; | |
693 default: | |
694 *u++ = ch; | |
695 break; | |
696 } | |
697 ch = *p++; | |
698 break; | |
699 | |
700 case sw_slash: | |
701 switch(ch) { | |
702 case '/': | |
703 break; | |
704 case '.': | |
705 state = sw_dot; | |
706 *u++ = ch; | |
707 break; | |
708 case '%': | |
709 quoted_state = state; | |
710 state = sw_quoted; | |
711 break; | |
712 default: | |
713 state = sw_usual; | |
714 *u++ = ch; | |
715 break; | |
716 } | |
717 ch = *p++; | |
718 break; | |
719 | |
720 case sw_dot: | |
721 switch(ch) { | |
722 case '/': | |
723 state = sw_slash; | |
724 u--; | |
725 break; | |
726 case '.': | |
727 state = sw_dot_dot; | |
728 *u++ = ch; | |
729 break; | |
730 case '%': | |
731 quoted_state = state; | |
732 state = sw_quoted; | |
733 break; | |
734 default: | |
735 state = sw_usual; | |
736 *u++ = ch; | |
737 break; | |
738 } | |
739 ch = *p++; | |
740 break; | |
741 | |
742 case sw_dot_dot: | |
743 switch(ch) { | |
744 case '/': | |
745 state = sw_slash; | |
746 u -= 4; | |
747 if (u < r->uri.data) { | |
748 return NGX_HTTP_PARSE_INVALID_REQUEST; | |
749 } | |
750 while (*(u - 1) != '/') { | |
751 u--; | |
752 } | |
753 break; | |
754 case '%': | |
755 quoted_state = state; | |
756 state = sw_quoted; | |
757 break; | |
758 #if (WIN32) | |
759 case '.': | |
760 state = sw_dot_dot_dot; | |
761 *u++ = ch; | |
762 break; | |
763 #endif | |
764 default: | |
765 state = sw_usual; | |
766 *u++ = ch; | |
767 break; | |
768 } | |
769 ch = *p++; | |
770 break; | |
771 | |
772 #if (WIN32) | |
773 case sw_dot_dot_dot: | |
774 switch(ch) { | |
775 case '/': | |
776 state = sw_slash; | |
777 u -= 5; | |
778 if (u < r->uri.data) { | |
779 return NGX_HTTP_PARSE_INVALID_REQUEST; | |
780 } | |
781 while (*u != '/') { | |
782 u--; | |
783 } | |
784 if (u < r->uri.data) { | |
785 return NGX_HTTP_PARSE_INVALID_REQUEST; | |
786 } | |
787 while (*(u - 1) != '/') { | |
788 u--; | |
789 } | |
790 break; | |
791 case '%': | |
792 quoted_state = state; | |
793 state = sw_quoted; | |
794 break; | |
795 default: | |
796 state = sw_usual; | |
797 *u++ = ch; | |
798 break; | |
799 } | |
800 ch = *p++; | |
801 break; | |
802 #endif | |
803 | |
804 case sw_quoted: | |
805 if (ch >= '0' && ch <= '9') { | |
806 decoded = (u_char) (ch - '0'); | |
807 state = sw_quoted_second; | |
808 ch = *p++; | |
809 break; | |
810 } | |
811 | |
812 c = (u_char) (ch | 0x20); | |
813 if (c >= 'a' && c <= 'f') { | |
814 decoded = (u_char) (c - 'a' + 10); | |
815 state = sw_quoted_second; | |
816 ch = *p++; | |
817 break; | |
818 } | |
819 | |
820 return NGX_HTTP_PARSE_INVALID_REQUEST; | |
821 | |
822 case sw_quoted_second: | |
823 if (ch >= '0' && ch <= '9') { | |
824 ch = (u_char) ((decoded << 4) + ch - '0'); | |
825 if (ch == '%') { | |
826 state = sw_usual; | |
827 *u++ = ch; | |
828 ch = *p++; | |
829 break; | |
830 } | |
831 state = quoted_state; | |
832 break; | |
833 } | |
834 | |
835 c = (u_char) (ch | 0x20); | |
836 if (c >= 'a' && c <= 'f') { | |
837 ch = (u_char) ((decoded << 4) + c - 'a' + 10); | |
838 if (ch == '%') { | |
839 state = sw_usual; | |
840 *u++ = ch; | |
841 ch = *p++; | |
842 break; | |
843 } | |
844 state = quoted_state; | |
845 break; | |
846 } | |
847 | |
848 return NGX_HTTP_PARSE_INVALID_REQUEST; | |
849 } | |
850 } | |
851 | |
852 r->uri.len = u - r->uri.data; | |
853 r->uri.data[r->uri.len] = '\0'; | |
854 | |
855 if (r->uri_ext) { | |
856 r->exten.len = u - r->uri_ext; | |
857 | |
858 if (!(r->exten.data = ngx_palloc(r->pool, r->exten.len + 1))) { | |
859 return NGX_HTTP_INTERNAL_SERVER_ERROR; | |
860 } | |
861 | |
862 ngx_cpystrn(r->exten.data, r->uri_ext, r->exten.len + 1); | |
863 } | |
864 | |
865 r->uri_ext = NULL; | |
866 | |
867 return NGX_OK; | |
868 } |