3 * Copyright (C) Igor Sysoev
7 #include <ngx_config.h>
12 ngx_int_t
ngx_http_parse_request_line(ngx_http_request_t
*r
, ngx_buf_t
*b
)
18 sw_space_after_method
,
22 sw_schema_slash_slash
,
25 sw_after_slash_in_uri
,
42 for (p
= b
->pos
; p
< b
->last
; p
++) {
45 /* gcc 2.95.2 and msvc 6.0 compile this switch as an jump table */
49 /* HTTP methods: GET, HEAD, POST */
53 if (ch
== CR
|| ch
== LF
) {
57 if (ch
< 'A' || ch
> 'Z') {
58 return NGX_HTTP_PARSE_INVALID_METHOD
;
71 if (m
[0] == 'G' && m
[1] == 'E' && m
[2] == 'T') {
72 r
->method
= NGX_HTTP_GET
;
75 } else if (p
- m
== 4) {
77 if (m
[0] == 'P' && m
[1] == 'O'
78 && m
[2] == 'S' && m
[3] == 'T')
80 r
->method
= NGX_HTTP_POST
;
82 } else if (m
[0] == 'H' && m
[1] == 'E'
83 && m
[2] == 'A' && m
[3] == 'D')
85 r
->method
= NGX_HTTP_HEAD
;
89 state
= sw_spaces_before_uri
;
93 if (ch
< 'A' || ch
> 'Z') {
94 return NGX_HTTP_PARSE_INVALID_METHOD
;
99 /* single space after method */
100 case sw_space_after_method
:
103 state
= sw_spaces_before_uri
;
106 return NGX_HTTP_PARSE_INVALID_METHOD
;
110 /* space* before URI */
111 case sw_spaces_before_uri
:
112 if ((ch
>= 'A' && ch
<= 'Z') || (ch
>= 'a' && ch
<= 'z')) {
121 state
= sw_after_slash_in_uri
;
126 return NGX_HTTP_PARSE_INVALID_REQUEST
;
131 if ((ch
>= 'A' && ch
<= 'Z') || (ch
>= 'a' && ch
<= 'z')) {
138 state
= sw_schema_slash
;
141 return NGX_HTTP_PARSE_INVALID_REQUEST
;
145 case sw_schema_slash
:
148 state
= sw_schema_slash_slash
;
151 return NGX_HTTP_PARSE_INVALID_REQUEST
;
155 case sw_schema_slash_slash
:
162 return NGX_HTTP_PARSE_INVALID_REQUEST
;
167 if ((ch
>= 'A' && ch
<= 'Z') || (ch
>= 'a' && ch
<= 'z')
168 || (ch
>= '0' && ch
<= '9') || ch
== '.' || ch
== '-')
181 state
= sw_after_slash_in_uri
;
184 return NGX_HTTP_PARSE_INVALID_REQUEST
;
189 if (ch
>= '0' && ch
<= '9') {
197 state
= sw_after_slash_in_uri
;
200 return NGX_HTTP_PARSE_INVALID_REQUEST
;
204 /* check "/.", "//", "%", and "\" (Win32) in URI */
205 case sw_after_slash_in_uri
:
207 if ((ch
>= 'a' && ch
<= 'z')
208 || (ch
>= 'A' && ch
<= 'Z')
209 || (ch
>= '0' && ch
<= '9'))
211 state
= sw_check_uri
;
223 state
= sw_almost_done
;
248 r
->args_start
= p
+ 1;
258 state
= sw_check_uri
;
263 /* check "/", "%" and "\" (Win32) in URI */
266 if ((ch
>= 'a' && ch
<= 'z')
267 || (ch
>= 'A' && ch
<= 'Z')
268 || (ch
>= '0' && ch
<= '9'))
276 state
= sw_after_slash_in_uri
;
288 state
= sw_almost_done
;
297 state
= sw_after_slash_in_uri
;
308 r
->args_start
= p
+ 1;
327 state
= sw_almost_done
;
342 /* space+ after URI */
349 state
= sw_almost_done
;
355 r
->http_protocol
.data
= p
;
359 return NGX_HTTP_PARSE_INVALID_REQUEST
;
369 return NGX_HTTP_PARSE_INVALID_REQUEST
;
379 return NGX_HTTP_PARSE_INVALID_REQUEST
;
386 state
= sw_http_HTTP
;
389 return NGX_HTTP_PARSE_INVALID_REQUEST
;
396 state
= sw_first_major_digit
;
399 return NGX_HTTP_PARSE_INVALID_REQUEST
;
403 /* first digit of major HTTP version */
404 case sw_first_major_digit
:
405 if (ch
< '1' || ch
> '9') {
406 return NGX_HTTP_PARSE_INVALID_REQUEST
;
409 r
->http_major
= ch
- '0';
410 state
= sw_major_digit
;
413 /* major HTTP version or dot */
416 state
= sw_first_minor_digit
;
420 if (ch
< '0' || ch
> '9') {
421 return NGX_HTTP_PARSE_INVALID_REQUEST
;
424 r
->http_major
= r
->http_major
* 10 + ch
- '0';
427 /* first digit of minor HTTP version */
428 case sw_first_minor_digit
:
429 if (ch
< '0' || ch
> '9') {
430 return NGX_HTTP_PARSE_INVALID_REQUEST
;
433 r
->http_minor
= ch
- '0';
434 state
= sw_minor_digit
;
437 /* minor HTTP version or end of request line */
440 state
= sw_almost_done
;
448 if (ch
< '0' || ch
> '9') {
449 return NGX_HTTP_PARSE_INVALID_REQUEST
;
452 r
->http_minor
= r
->http_minor
* 10 + ch
- '0';
455 /* end of request line */
457 r
->request_end
= p
- 1;
462 return NGX_HTTP_PARSE_INVALID_REQUEST
;
477 if (r
->request_end
== NULL
) {
481 r
->http_version
= r
->http_major
* 1000 + r
->http_minor
;
484 if (r
->http_version
== 9 && r
->method
!= NGX_HTTP_GET
) {
485 return NGX_HTTP_PARSE_INVALID_09_METHOD
;
492 ngx_int_t
ngx_http_parse_header_line(ngx_http_request_t
*r
, ngx_buf_t
*b
)
498 sw_space_before_value
,
500 sw_space_after_value
,
502 sw_header_almost_done
,
508 for (p
= b
->pos
; p
< b
->last
; p
++) {
518 state
= sw_header_almost_done
;
525 r
->header_name_start
= p
;
527 c
= (u_char
) (ch
| 0x20);
528 if (c
>= 'a' && c
<= 'z') {
532 if (ch
== '-' || ch
== '_' || ch
== '~' || ch
== '.') {
536 if (ch
>= '0' && ch
<= '9') {
540 return NGX_HTTP_PARSE_INVALID_HEADER
;
547 c
= (u_char
) (ch
| 0x20);
548 if (c
>= 'a' && c
<= 'z') {
553 r
->header_name_end
= p
;
554 state
= sw_space_before_value
;
558 if (ch
== '-' || ch
== '_' || ch
== '~' || ch
== '.') {
562 if (ch
>= '0' && ch
<= '9') {
566 /* IIS may send the duplicate "HTTP/1.1 ..." lines */
569 && p
- r
->header_start
== 4
570 && ngx_strncmp(r
->header_start
, "HTTP", 4) == 0)
572 state
= sw_ignore_line
;
576 return NGX_HTTP_PARSE_INVALID_HEADER
;
578 /* space* before header value */
579 case sw_space_before_value
:
584 r
->header_start
= r
->header_end
= p
;
585 state
= sw_almost_done
;
588 r
->header_start
= r
->header_end
= p
;
602 state
= sw_space_after_value
;
606 state
= sw_almost_done
;
614 /* space* before end of header line */
615 case sw_space_after_value
:
620 state
= sw_almost_done
;
630 /* ignore header line */
641 /* end of header line */
647 return NGX_HTTP_PARSE_INVALID_HEADER
;
652 case sw_header_almost_done
:
657 return NGX_HTTP_PARSE_INVALID_HEADER
;
680 return NGX_HTTP_PARSE_HEADER_DONE
;
684 ngx_int_t
ngx_http_parse_complex_uri(ngx_http_request_t
*r
)
686 u_char c
, ch
, decoded
, *p
, *u
;
699 } state
, quoted_state
;
701 #if (NGX_SUPPRESS_WARN)
703 quoted_state
= sw_usual
;
710 r
->args_start
= NULL
;
714 while (p
<= r
->uri_end
) {
717 * we use "ch = *p++" inside the cycle, but this operation is safe,
718 * because after the URI there is always at least one charcter:
722 ngx_log_debug4(NGX_LOG_DEBUG_HTTP
, r
->connection
->log
, 0,
723 "s:%d in:'%Xd:%c', out:'%c'", state
, ch
, ch
, *u
);
732 if (p
== r
->uri_start
+ r
->uri
.len
) {
735 * we omit the last "\" to cause redirect because
736 * the browsers do not treat "\" as "/" in relative URL path
752 quoted_state
= state
;
777 state
= sw_colon_slash
;
782 state
= sw_colon_slash
;
789 quoted_state
= state
;
820 quoted_state
= state
;
847 quoted_state
= state
;
876 quoted_state
= state
;
899 if (u
< r
->uri
.data
) {
900 return NGX_HTTP_PARSE_INVALID_REQUEST
;
902 while (*(u
- 1) != '/') {
907 quoted_state
= state
;
915 state
= sw_dot_dot_dot
;
934 if (u
< r
->uri
.data
) {
935 return NGX_HTTP_PARSE_INVALID_REQUEST
;
940 if (u
< r
->uri
.data
) {
941 return NGX_HTTP_PARSE_INVALID_REQUEST
;
943 while (*(u
- 1) != '/') {
948 quoted_state
= state
;
961 if (ch
>= '0' && ch
<= '9') {
962 decoded
= (u_char
) (ch
- '0');
963 state
= sw_quoted_second
;
968 c
= (u_char
) (ch
| 0x20);
969 if (c
>= 'a' && c
<= 'f') {
970 decoded
= (u_char
) (c
- 'a' + 10);
971 state
= sw_quoted_second
;
976 return NGX_HTTP_PARSE_INVALID_REQUEST
;
978 case sw_quoted_second
:
979 if (ch
>= '0' && ch
<= '9') {
980 ch
= (u_char
) ((decoded
<< 4) + ch
- '0');
995 state
= quoted_state
;
999 c
= (u_char
) (ch
| 0x20);
1000 if (c
>= 'a' && c
<= 'f') {
1001 ch
= (u_char
) ((decoded
<< 4) + c
- 'a' + 10);
1006 state
= quoted_state
;
1010 return NGX_HTTP_PARSE_INVALID_REQUEST
;
1016 r
->uri
.len
= u
- r
->uri
.data
;
1017 r
->uri
.data
[r
->uri
.len
] = '\0';
1020 r
->exten
.len
= u
- r
->uri_ext
;
1021 r
->exten
.data
= r
->uri_ext
;