3 * Copyright (C) Igor Sysoev
4 * Copyright (C) Nginx, Inc.
8 #include <ngx_config.h>
13 static uint32_t usual
[] = {
14 0xffffdbfe, /* 1111 1111 1111 1111 1101 1011 1111 1110 */
16 /* ?>=< ;:98 7654 3210 /.-, +*)( '&%$ #"! */
17 0x7fff37d6, /* 0111 1111 1111 1111 0011 0111 1101 0110 */
19 /* _^]\ [ZYX WVUT SRQP ONML KJIH GFED CBA@ */
21 0xefffffff, /* 1110 1111 1111 1111 1111 1111 1111 1111 */
23 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
26 /* ~}| {zyx wvut srqp onml kjih gfed cba` */
27 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
29 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
30 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
31 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
32 0xffffffff /* 1111 1111 1111 1111 1111 1111 1111 1111 */
36 #if (NGX_HAVE_LITTLE_ENDIAN && NGX_HAVE_NONALIGNED)
38 #define ngx_str3_cmp(m, c0, c1, c2, c3) \
39 *(uint32_t *) m == ((c3 << 24) | (c2 << 16) | (c1 << 8) | c0)
41 #define ngx_str3Ocmp(m, c0, c1, c2, c3) \
42 *(uint32_t *) m == ((c3 << 24) | (c2 << 16) | (c1 << 8) | c0)
44 #define ngx_str4cmp(m, c0, c1, c2, c3) \
45 *(uint32_t *) m == ((c3 << 24) | (c2 << 16) | (c1 << 8) | c0)
47 #define ngx_str5cmp(m, c0, c1, c2, c3, c4) \
48 *(uint32_t *) m == ((c3 << 24) | (c2 << 16) | (c1 << 8) | c0) \
51 #define ngx_str6cmp(m, c0, c1, c2, c3, c4, c5) \
52 *(uint32_t *) m == ((c3 << 24) | (c2 << 16) | (c1 << 8) | c0) \
53 && (((uint32_t *) m)[1] & 0xffff) == ((c5 << 8) | c4)
55 #define ngx_str7_cmp(m, c0, c1, c2, c3, c4, c5, c6, c7) \
56 *(uint32_t *) m == ((c3 << 24) | (c2 << 16) | (c1 << 8) | c0) \
57 && ((uint32_t *) m)[1] == ((c7 << 24) | (c6 << 16) | (c5 << 8) | c4)
59 #define ngx_str8cmp(m, c0, c1, c2, c3, c4, c5, c6, c7) \
60 *(uint32_t *) m == ((c3 << 24) | (c2 << 16) | (c1 << 8) | c0) \
61 && ((uint32_t *) m)[1] == ((c7 << 24) | (c6 << 16) | (c5 << 8) | c4)
63 #define ngx_str9cmp(m, c0, c1, c2, c3, c4, c5, c6, c7, c8) \
64 *(uint32_t *) m == ((c3 << 24) | (c2 << 16) | (c1 << 8) | c0) \
65 && ((uint32_t *) m)[1] == ((c7 << 24) | (c6 << 16) | (c5 << 8) | c4) \
68 #else /* !(NGX_HAVE_LITTLE_ENDIAN && NGX_HAVE_NONALIGNED) */
70 #define ngx_str3_cmp(m, c0, c1, c2, c3) \
71 m[0] == c0 && m[1] == c1 && m[2] == c2
73 #define ngx_str3Ocmp(m, c0, c1, c2, c3) \
74 m[0] == c0 && m[2] == c2 && m[3] == c3
76 #define ngx_str4cmp(m, c0, c1, c2, c3) \
77 m[0] == c0 && m[1] == c1 && m[2] == c2 && m[3] == c3
79 #define ngx_str5cmp(m, c0, c1, c2, c3, c4) \
80 m[0] == c0 && m[1] == c1 && m[2] == c2 && m[3] == c3 && m[4] == c4
82 #define ngx_str6cmp(m, c0, c1, c2, c3, c4, c5) \
83 m[0] == c0 && m[1] == c1 && m[2] == c2 && m[3] == c3 \
84 && m[4] == c4 && m[5] == c5
86 #define ngx_str7_cmp(m, c0, c1, c2, c3, c4, c5, c6, c7) \
87 m[0] == c0 && m[1] == c1 && m[2] == c2 && m[3] == c3 \
88 && m[4] == c4 && m[5] == c5 && m[6] == c6
90 #define ngx_str8cmp(m, c0, c1, c2, c3, c4, c5, c6, c7) \
91 m[0] == c0 && m[1] == c1 && m[2] == c2 && m[3] == c3 \
92 && m[4] == c4 && m[5] == c5 && m[6] == c6 && m[7] == c7
94 #define ngx_str9cmp(m, c0, c1, c2, c3, c4, c5, c6, c7, c8) \
95 m[0] == c0 && m[1] == c1 && m[2] == c2 && m[3] == c3 \
96 && m[4] == c4 && m[5] == c5 && m[6] == c6 && m[7] == c7 && m[8] == c8
101 /* gcc, icc, msvc and others compile these switches as an jump table */
104 ngx_http_parse_request_line(ngx_http_request_t
*r
, ngx_buf_t
*b
)
106 u_char c
, ch
, *p
, *m
;
110 sw_spaces_before_uri
,
113 sw_schema_slash_slash
,
120 sw_after_slash_in_uri
,
122 sw_check_uri_http_09
,
129 sw_first_major_digit
,
131 sw_first_minor_digit
,
133 sw_spaces_after_digit
,
139 for (p
= b
->pos
; p
< b
->last
; p
++) {
144 /* HTTP methods: GET, HEAD, POST */
146 r
->request_start
= p
;
148 if (ch
== CR
|| ch
== LF
) {
152 if ((ch
< 'A' || ch
> 'Z') && ch
!= '_') {
153 return NGX_HTTP_PARSE_INVALID_METHOD
;
161 r
->method_end
= p
- 1;
162 m
= r
->request_start
;
167 if (ngx_str3_cmp(m
, 'G', 'E', 'T', ' ')) {
168 r
->method
= NGX_HTTP_GET
;
172 if (ngx_str3_cmp(m
, 'P', 'U', 'T', ' ')) {
173 r
->method
= NGX_HTTP_PUT
;
182 if (ngx_str3Ocmp(m
, 'P', 'O', 'S', 'T')) {
183 r
->method
= NGX_HTTP_POST
;
187 if (ngx_str3Ocmp(m
, 'C', 'O', 'P', 'Y')) {
188 r
->method
= NGX_HTTP_COPY
;
192 if (ngx_str3Ocmp(m
, 'M', 'O', 'V', 'E')) {
193 r
->method
= NGX_HTTP_MOVE
;
197 if (ngx_str3Ocmp(m
, 'L', 'O', 'C', 'K')) {
198 r
->method
= NGX_HTTP_LOCK
;
204 if (ngx_str4cmp(m
, 'H', 'E', 'A', 'D')) {
205 r
->method
= NGX_HTTP_HEAD
;
213 if (ngx_str5cmp(m
, 'M', 'K', 'C', 'O', 'L')) {
214 r
->method
= NGX_HTTP_MKCOL
;
217 if (ngx_str5cmp(m
, 'P', 'A', 'T', 'C', 'H')) {
218 r
->method
= NGX_HTTP_PATCH
;
221 if (ngx_str5cmp(m
, 'T', 'R', 'A', 'C', 'E')) {
222 r
->method
= NGX_HTTP_TRACE
;
228 if (ngx_str6cmp(m
, 'D', 'E', 'L', 'E', 'T', 'E')) {
229 r
->method
= NGX_HTTP_DELETE
;
233 if (ngx_str6cmp(m
, 'U', 'N', 'L', 'O', 'C', 'K')) {
234 r
->method
= NGX_HTTP_UNLOCK
;
241 if (ngx_str7_cmp(m
, 'O', 'P', 'T', 'I', 'O', 'N', 'S', ' '))
243 r
->method
= NGX_HTTP_OPTIONS
;
249 if (ngx_str8cmp(m
, 'P', 'R', 'O', 'P', 'F', 'I', 'N', 'D'))
251 r
->method
= NGX_HTTP_PROPFIND
;
258 'P', 'R', 'O', 'P', 'P', 'A', 'T', 'C', 'H'))
260 r
->method
= NGX_HTTP_PROPPATCH
;
266 state
= sw_spaces_before_uri
;
270 if ((ch
< 'A' || ch
> 'Z') && ch
!= '_') {
271 return NGX_HTTP_PARSE_INVALID_METHOD
;
276 /* space* before URI */
277 case sw_spaces_before_uri
:
281 state
= sw_after_slash_in_uri
;
285 c
= (u_char
) (ch
| 0x20);
286 if (c
>= 'a' && c
<= 'z') {
296 return NGX_HTTP_PARSE_INVALID_REQUEST
;
302 c
= (u_char
) (ch
| 0x20);
303 if (c
>= 'a' && c
<= 'z') {
310 state
= sw_schema_slash
;
313 return NGX_HTTP_PARSE_INVALID_REQUEST
;
317 case sw_schema_slash
:
320 state
= sw_schema_slash_slash
;
323 return NGX_HTTP_PARSE_INVALID_REQUEST
;
327 case sw_schema_slash_slash
:
330 state
= sw_host_start
;
333 return NGX_HTTP_PARSE_INVALID_REQUEST
;
342 state
= sw_host_ip_literal
;
352 c
= (u_char
) (ch
| 0x20);
353 if (c
>= 'a' && c
<= 'z') {
357 if ((ch
>= '0' && ch
<= '9') || ch
== '.' || ch
== '-') {
373 state
= sw_after_slash_in_uri
;
377 * use single "/" from request line to preserve pointers,
378 * if request line will be copied to large client buffer
380 r
->uri_start
= r
->schema_end
+ 1;
381 r
->uri_end
= r
->schema_end
+ 2;
382 state
= sw_host_http_09
;
385 return NGX_HTTP_PARSE_INVALID_REQUEST
;
389 case sw_host_ip_literal
:
391 if (ch
>= '0' && ch
<= '9') {
395 c
= (u_char
) (ch
| 0x20);
396 if (c
>= 'a' && c
<= 'z') {
426 return NGX_HTTP_PARSE_INVALID_REQUEST
;
431 if (ch
>= '0' && ch
<= '9') {
439 state
= sw_after_slash_in_uri
;
444 * use single "/" from request line to preserve pointers,
445 * if request line will be copied to large client buffer
447 r
->uri_start
= r
->schema_end
+ 1;
448 r
->uri_end
= r
->schema_end
+ 2;
449 state
= sw_host_http_09
;
452 return NGX_HTTP_PARSE_INVALID_REQUEST
;
456 /* space+ after "http://host[:port] " */
457 case sw_host_http_09
:
463 state
= sw_almost_done
;
469 r
->http_protocol
.data
= p
;
473 return NGX_HTTP_PARSE_INVALID_REQUEST
;
478 /* check "/.", "//", "%", and "\" (Win32) in URI */
479 case sw_after_slash_in_uri
:
481 if (usual
[ch
>> 5] & (1 << (ch
& 0x1f))) {
482 state
= sw_check_uri
;
489 state
= sw_check_uri_http_09
;
494 state
= sw_almost_done
;
519 r
->args_start
= p
+ 1;
530 return NGX_HTTP_PARSE_INVALID_REQUEST
;
532 state
= sw_check_uri
;
537 /* check "/", "%" and "\" (Win32) in URI */
540 if (usual
[ch
>> 5] & (1 << (ch
& 0x1f))) {
547 if (r
->uri_ext
== p
) {
554 state
= sw_after_slash_in_uri
;
561 state
= sw_check_uri_http_09
;
566 state
= sw_almost_done
;
575 state
= sw_after_slash_in_uri
;
583 r
->args_start
= p
+ 1;
594 return NGX_HTTP_PARSE_INVALID_REQUEST
;
598 /* space+ after URI */
599 case sw_check_uri_http_09
:
605 state
= sw_almost_done
;
611 r
->http_protocol
.data
= p
;
616 state
= sw_check_uri
;
625 if (usual
[ch
>> 5] & (1 << (ch
& 0x1f))) {
637 state
= sw_almost_done
;
647 return NGX_HTTP_PARSE_INVALID_REQUEST
;
651 /* space+ after URI */
658 state
= sw_almost_done
;
664 r
->http_protocol
.data
= p
;
680 return NGX_HTTP_PARSE_INVALID_REQUEST
;
690 return NGX_HTTP_PARSE_INVALID_REQUEST
;
697 state
= sw_http_HTTP
;
700 return NGX_HTTP_PARSE_INVALID_REQUEST
;
707 state
= sw_first_major_digit
;
710 return NGX_HTTP_PARSE_INVALID_REQUEST
;
714 /* first digit of major HTTP version */
715 case sw_first_major_digit
:
716 if (ch
< '1' || ch
> '9') {
717 return NGX_HTTP_PARSE_INVALID_REQUEST
;
720 r
->http_major
= ch
- '0';
721 state
= sw_major_digit
;
724 /* major HTTP version or dot */
727 state
= sw_first_minor_digit
;
731 if (ch
< '0' || ch
> '9') {
732 return NGX_HTTP_PARSE_INVALID_REQUEST
;
735 r
->http_major
= r
->http_major
* 10 + ch
- '0';
738 /* first digit of minor HTTP version */
739 case sw_first_minor_digit
:
740 if (ch
< '0' || ch
> '9') {
741 return NGX_HTTP_PARSE_INVALID_REQUEST
;
744 r
->http_minor
= ch
- '0';
745 state
= sw_minor_digit
;
748 /* minor HTTP version or end of request line */
751 state
= sw_almost_done
;
760 state
= sw_spaces_after_digit
;
764 if (ch
< '0' || ch
> '9') {
765 return NGX_HTTP_PARSE_INVALID_REQUEST
;
768 r
->http_minor
= r
->http_minor
* 10 + ch
- '0';
771 case sw_spaces_after_digit
:
776 state
= sw_almost_done
;
781 return NGX_HTTP_PARSE_INVALID_REQUEST
;
785 /* end of request line */
787 r
->request_end
= p
- 1;
792 return NGX_HTTP_PARSE_INVALID_REQUEST
;
806 if (r
->request_end
== NULL
) {
810 r
->http_version
= r
->http_major
* 1000 + r
->http_minor
;
813 if (r
->http_version
== 9 && r
->method
!= NGX_HTTP_GET
) {
814 return NGX_HTTP_PARSE_INVALID_09_METHOD
;
822 ngx_http_parse_header_line(ngx_http_request_t
*r
, ngx_buf_t
*b
,
823 ngx_uint_t allow_underscores
)
830 sw_space_before_value
,
832 sw_space_after_value
,
835 sw_header_almost_done
838 /* the last '\0' is not needed because string is zero terminated */
840 static u_char lowcase
[] =
841 "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
842 "\0\0\0\0\0\0\0\0\0\0\0\0\0-\0\0" "0123456789\0\0\0\0\0\0"
843 "\0abcdefghijklmnopqrstuvwxyz\0\0\0\0\0"
844 "\0abcdefghijklmnopqrstuvwxyz\0\0\0\0\0"
845 "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
846 "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
847 "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
848 "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
851 hash
= r
->header_hash
;
852 i
= r
->lowcase_index
;
854 for (p
= b
->pos
; p
< b
->last
; p
++) {
861 r
->header_name_start
= p
;
862 r
->invalid_header
= 0;
867 state
= sw_header_almost_done
;
878 hash
= ngx_hash(0, c
);
879 r
->lowcase_header
[0] = c
;
885 return NGX_HTTP_PARSE_INVALID_HEADER
;
888 r
->invalid_header
= 1;
900 hash
= ngx_hash(hash
, c
);
901 r
->lowcase_header
[i
++] = c
;
902 i
&= (NGX_HTTP_LC_HEADER_LEN
- 1);
907 if (allow_underscores
) {
908 hash
= ngx_hash(hash
, ch
);
909 r
->lowcase_header
[i
++] = ch
;
910 i
&= (NGX_HTTP_LC_HEADER_LEN
- 1);
913 r
->invalid_header
= 1;
920 r
->header_name_end
= p
;
921 state
= sw_space_before_value
;
926 r
->header_name_end
= p
;
929 state
= sw_almost_done
;
934 r
->header_name_end
= p
;
940 /* IIS may send the duplicate "HTTP/1.1 ..." lines */
943 && p
- r
->header_name_start
== 4
944 && ngx_strncmp(r
->header_name_start
, "HTTP", 4) == 0)
946 state
= sw_ignore_line
;
951 return NGX_HTTP_PARSE_INVALID_HEADER
;
954 r
->invalid_header
= 1;
958 /* space* before header value */
959 case sw_space_before_value
:
966 state
= sw_almost_done
;
973 return NGX_HTTP_PARSE_INVALID_HEADER
;
986 state
= sw_space_after_value
;
990 state
= sw_almost_done
;
996 return NGX_HTTP_PARSE_INVALID_HEADER
;
1000 /* space* before end of header line */
1001 case sw_space_after_value
:
1006 state
= sw_almost_done
;
1011 return NGX_HTTP_PARSE_INVALID_HEADER
;
1018 /* ignore header line */
1019 case sw_ignore_line
:
1029 /* end of header line */
1030 case sw_almost_done
:
1037 return NGX_HTTP_PARSE_INVALID_HEADER
;
1042 case sw_header_almost_done
:
1047 return NGX_HTTP_PARSE_INVALID_HEADER
;
1054 r
->header_hash
= hash
;
1055 r
->lowcase_index
= i
;
1062 r
->state
= sw_start
;
1063 r
->header_hash
= hash
;
1064 r
->lowcase_index
= i
;
1071 r
->state
= sw_start
;
1073 return NGX_HTTP_PARSE_HEADER_DONE
;
1078 ngx_http_parse_uri(ngx_http_request_t
*r
)
1083 sw_after_slash_in_uri
,
1090 for (p
= r
->uri_start
; p
!= r
->uri_end
; p
++) {
1102 state
= sw_after_slash_in_uri
;
1105 /* check "/.", "//", "%", and "\" (Win32) in URI */
1106 case sw_after_slash_in_uri
:
1108 if (usual
[ch
>> 5] & (1 << (ch
& 0x1f))) {
1109 state
= sw_check_uri
;
1115 r
->space_in_uri
= 1;
1116 state
= sw_check_uri
;
1137 r
->args_start
= p
+ 1;
1148 state
= sw_check_uri
;
1153 /* check "/", "%" and "\" (Win32) in URI */
1156 if (usual
[ch
>> 5] & (1 << (ch
& 0x1f))) {
1163 if (r
->uri_ext
== p
) {
1170 state
= sw_after_slash_in_uri
;
1176 r
->space_in_uri
= 1;
1181 state
= sw_after_slash_in_uri
;
1189 r
->args_start
= p
+ 1;
1205 if (usual
[ch
>> 5] & (1 << (ch
& 0x1f))) {
1211 r
->space_in_uri
= 1;
1226 ngx_http_parse_complex_uri(ngx_http_request_t
*r
, ngx_uint_t merge_slashes
)
1228 u_char c
, ch
, decoded
, *p
, *u
;
1236 } state
, quoted_state
;
1238 #if (NGX_SUPPRESS_WARN)
1240 quoted_state
= sw_usual
;
1247 r
->args_start
= NULL
;
1251 while (p
<= r
->uri_end
) {
1254 * we use "ch = *p++" inside the cycle, but this operation is safe,
1255 * because after the URI there is always at least one character:
1259 ngx_log_debug4(NGX_LOG_DEBUG_HTTP
, r
->connection
->log
, 0,
1260 "s:%d in:'%Xd:%c', out:'%c'", state
, ch
, ch
, *u
);
1266 if (usual
[ch
>> 5] & (1 << (ch
& 0x1f))) {
1275 if (u
- 2 >= r
->uri
.data
1276 && *(u
- 1) == '.' && *(u
- 2) != '.')
1283 if (p
== r
->uri_start
+ r
->uri
.len
) {
1286 * we omit the last "\" to cause redirect because
1287 * the browsers do not treat "\" as "/" in relative URL path
1299 if (u
- 2 >= r
->uri
.data
1300 && *(u
- 1) == '.' && *(u
- 2) != '.')
1310 quoted_state
= state
;
1335 if (usual
[ch
>> 5] & (1 << (ch
& 0x1f))) {
1348 if (!merge_slashes
) {
1357 quoted_state
= state
;
1378 if (usual
[ch
>> 5] & (1 << (ch
& 0x1f))) {
1398 quoted_state
= state
;
1419 if (usual
[ch
>> 5] & (1 << (ch
& 0x1f))) {
1434 if (u
< r
->uri
.data
) {
1435 return NGX_HTTP_PARSE_INVALID_REQUEST
;
1445 quoted_state
= state
;
1467 if (ch
>= '0' && ch
<= '9') {
1468 decoded
= (u_char
) (ch
- '0');
1469 state
= sw_quoted_second
;
1474 c
= (u_char
) (ch
| 0x20);
1475 if (c
>= 'a' && c
<= 'f') {
1476 decoded
= (u_char
) (c
- 'a' + 10);
1477 state
= sw_quoted_second
;
1482 return NGX_HTTP_PARSE_INVALID_REQUEST
;
1484 case sw_quoted_second
:
1485 if (ch
>= '0' && ch
<= '9') {
1486 ch
= (u_char
) ((decoded
<< 4) + ch
- '0');
1488 if (ch
== '%' || ch
== '#') {
1494 } else if (ch
== '\0') {
1495 return NGX_HTTP_PARSE_INVALID_REQUEST
;
1498 state
= quoted_state
;
1502 c
= (u_char
) (ch
| 0x20);
1503 if (c
>= 'a' && c
<= 'f') {
1504 ch
= (u_char
) ((decoded
<< 4) + c
- 'a' + 10);
1512 } else if (ch
== '+') {
1516 state
= quoted_state
;
1520 return NGX_HTTP_PARSE_INVALID_REQUEST
;
1526 r
->uri
.len
= u
- r
->uri
.data
;
1529 r
->exten
.len
= u
- r
->uri_ext
;
1530 r
->exten
.data
= r
->uri_ext
;
1539 while (p
< r
->uri_end
) {
1544 r
->args
.len
= p
- 1 - r
->args_start
;
1545 r
->args
.data
= r
->args_start
;
1546 r
->args_start
= NULL
;
1551 r
->uri
.len
= u
- r
->uri
.data
;
1554 r
->exten
.len
= u
- r
->uri_ext
;
1555 r
->exten
.data
= r
->uri_ext
;
1565 ngx_http_parse_status_line(ngx_http_request_t
*r
, ngx_buf_t
*b
,
1566 ngx_http_status_t
*status
)
1576 sw_first_major_digit
,
1578 sw_first_minor_digit
,
1581 sw_space_after_status
,
1588 for (p
= b
->pos
; p
< b
->last
; p
++) {
1637 state
= sw_first_major_digit
;
1644 /* the first digit of major HTTP version */
1645 case sw_first_major_digit
:
1646 if (ch
< '1' || ch
> '9') {
1650 r
->http_major
= ch
- '0';
1651 state
= sw_major_digit
;
1654 /* the major HTTP version or dot */
1655 case sw_major_digit
:
1657 state
= sw_first_minor_digit
;
1661 if (ch
< '0' || ch
> '9') {
1665 r
->http_major
= r
->http_major
* 10 + ch
- '0';
1668 /* the first digit of minor HTTP version */
1669 case sw_first_minor_digit
:
1670 if (ch
< '0' || ch
> '9') {
1674 r
->http_minor
= ch
- '0';
1675 state
= sw_minor_digit
;
1678 /* the minor HTTP version or the end of the request line */
1679 case sw_minor_digit
:
1685 if (ch
< '0' || ch
> '9') {
1689 r
->http_minor
= r
->http_minor
* 10 + ch
- '0';
1692 /* HTTP status code */
1698 if (ch
< '0' || ch
> '9') {
1702 status
->code
= status
->code
* 10 + ch
- '0';
1704 if (++status
->count
== 3) {
1705 state
= sw_space_after_status
;
1706 status
->start
= p
- 2;
1711 /* space or end of line */
1712 case sw_space_after_status
:
1715 state
= sw_status_text
;
1717 case '.': /* IIS may send 403.1, 403.2, etc */
1718 state
= sw_status_text
;
1721 state
= sw_almost_done
;
1730 /* any text until end of line */
1731 case sw_status_text
:
1734 state
= sw_almost_done
;
1742 /* end of status line */
1743 case sw_almost_done
:
1744 status
->end
= p
- 1;
1763 if (status
->end
== NULL
) {
1767 status
->http_version
= r
->http_major
* 1000 + r
->http_minor
;
1768 r
->state
= sw_start
;
1775 ngx_http_parse_unsafe_uri(ngx_http_request_t
*r
, ngx_str_t
*uri
,
1776 ngx_str_t
*args
, ngx_uint_t
*flags
)
1784 if (len
== 0 || p
[0] == '?') {
1788 if (p
[0] == '.' && len
== 3 && p
[1] == '.' && (ngx_path_separator(p
[2]))) {
1792 for ( /* void */ ; len
; len
--) {
1796 if (usual
[ch
>> 5] & (1 << (ch
& 0x1f))) {
1801 args
->len
= len
- 1;
1812 if (ngx_path_separator(ch
) && len
> 2) {
1816 if (p
[0] == '.' && p
[1] == '.' && ngx_path_separator(p
[2])) {
1826 if (*flags
& NGX_HTTP_LOG_UNSAFE
) {
1827 ngx_log_error(NGX_LOG_ERR
, r
->connection
->log
, 0,
1828 "unsafe URI \"%V\" was detected", uri
);
1836 ngx_http_parse_multi_header_lines(ngx_array_t
*headers
, ngx_str_t
*name
,
1840 u_char
*start
, *last
, *end
, ch
;
1841 ngx_table_elt_t
**h
;
1845 for (i
= 0; i
< headers
->nelts
; i
++) {
1847 ngx_log_debug2(NGX_LOG_DEBUG_HTTP
, headers
->pool
->log
, 0,
1848 "parse header: \"%V: %V\"", &h
[i
]->key
, &h
[i
]->value
);
1850 if (name
->len
> h
[i
]->value
.len
) {
1854 start
= h
[i
]->value
.data
;
1855 end
= h
[i
]->value
.data
+ h
[i
]->value
.len
;
1857 while (start
< end
) {
1859 if (ngx_strncasecmp(start
, name
->data
, name
->len
) != 0) {
1863 for (start
+= name
->len
; start
< end
&& *start
== ' '; start
++) {
1867 if (value
== NULL
) {
1868 if (start
== end
|| *start
== ',') {
1875 if (start
== end
|| *start
++ != '=') {
1876 /* the invalid header value */
1880 while (start
< end
&& *start
== ' ') { start
++; }
1882 for (last
= start
; last
< end
&& *last
!= ';'; last
++) {
1886 value
->len
= last
- start
;
1887 value
->data
= start
;
1893 while (start
< end
) {
1895 if (ch
== ';' || ch
== ',') {
1900 while (start
< end
&& *start
== ' ') { start
++; }
1904 return NGX_DECLINED
;
1909 ngx_http_arg(ngx_http_request_t
*r
, u_char
*name
, size_t len
, ngx_str_t
*value
)
1913 if (r
->args
.len
== 0) {
1914 return NGX_DECLINED
;
1918 last
= p
+ r
->args
.len
;
1920 for ( /* void */ ; p
< last
; p
++) {
1922 /* we need '=' after name, so drop one char from last */
1924 p
= ngx_strlcasestrn(p
, last
- 1, name
, len
- 1);
1927 return NGX_DECLINED
;
1930 if ((p
== r
->args
.data
|| *(p
- 1) == '&') && *(p
+ len
) == '=') {
1932 value
->data
= p
+ len
+ 1;
1934 p
= ngx_strlchr(p
, last
, '&');
1937 p
= r
->args
.data
+ r
->args
.len
;
1940 value
->len
= p
- value
->data
;
1946 return NGX_DECLINED
;
1951 ngx_http_split_args(ngx_http_request_t
*r
, ngx_str_t
*uri
, ngx_str_t
*args
)
1955 last
= uri
->data
+ uri
->len
;
1957 p
= ngx_strlchr(uri
->data
, last
, '?');
1960 uri
->len
= p
- uri
->data
;
1962 args
->len
= last
- p
;
1972 ngx_http_parse_chunked(ngx_http_request_t
*r
, ngx_buf_t
*b
,
1973 ngx_http_chunked_t
*ctx
)
1981 sw_chunk_extension_almost_done
,
1984 sw_after_data_almost_done
,
1985 sw_last_chunk_extension
,
1986 sw_last_chunk_extension_almost_done
,
1988 sw_trailer_almost_done
,
1990 sw_trailer_header_almost_done
1995 if (state
== sw_chunk_data
&& ctx
->size
== 0) {
1996 state
= sw_after_data
;
2001 for (pos
= b
->pos
; pos
< b
->last
; pos
++) {
2005 ngx_log_debug2(NGX_LOG_DEBUG_HTTP
, r
->connection
->log
, 0,
2006 "http chunked byte: %02Xd s:%d", ch
, state
);
2010 case sw_chunk_start
:
2011 if (ch
>= '0' && ch
<= '9') {
2012 state
= sw_chunk_size
;
2013 ctx
->size
= ch
- '0';
2017 c
= (u_char
) (ch
| 0x20);
2019 if (c
>= 'a' && c
<= 'f') {
2020 state
= sw_chunk_size
;
2021 ctx
->size
= c
- 'a' + 10;
2028 if (ch
>= '0' && ch
<= '9') {
2029 ctx
->size
= ctx
->size
* 16 + (ch
- '0');
2033 c
= (u_char
) (ch
| 0x20);
2035 if (c
>= 'a' && c
<= 'f') {
2036 ctx
->size
= ctx
->size
* 16 + (c
- 'a' + 10);
2040 if (ctx
->size
== 0) {
2044 state
= sw_last_chunk_extension_almost_done
;
2052 state
= sw_last_chunk_extension
;
2063 state
= sw_chunk_extension_almost_done
;
2066 state
= sw_chunk_data
;
2071 state
= sw_chunk_extension
;
2079 case sw_chunk_extension
:
2082 state
= sw_chunk_extension_almost_done
;
2085 state
= sw_chunk_data
;
2089 case sw_chunk_extension_almost_done
:
2091 state
= sw_chunk_data
;
2103 state
= sw_after_data_almost_done
;
2106 state
= sw_chunk_start
;
2110 case sw_after_data_almost_done
:
2112 state
= sw_chunk_start
;
2117 case sw_last_chunk_extension
:
2120 state
= sw_last_chunk_extension_almost_done
;
2127 case sw_last_chunk_extension_almost_done
:
2137 state
= sw_trailer_almost_done
;
2142 state
= sw_trailer_header
;
2146 case sw_trailer_almost_done
:
2152 case sw_trailer_header
:
2155 state
= sw_trailer_header_almost_done
;
2162 case sw_trailer_header_almost_done
:
2179 case sw_chunk_start
:
2180 ctx
->length
= 3 /* "0" LF LF */;
2183 ctx
->length
= 2 /* LF LF */
2184 + (ctx
->size
? ctx
->size
+ 4 /* LF "0" LF LF */ : 0);
2186 case sw_chunk_extension
:
2187 case sw_chunk_extension_almost_done
:
2188 ctx
->length
= 1 /* LF */ + ctx
->size
+ 4 /* LF "0" LF LF */;
2191 ctx
->length
= ctx
->size
+ 4 /* LF "0" LF LF */;
2194 case sw_after_data_almost_done
:
2195 ctx
->length
= 4 /* LF "0" LF LF */;
2197 case sw_last_chunk_extension
:
2198 case sw_last_chunk_extension_almost_done
:
2199 ctx
->length
= 2 /* LF LF */;
2202 case sw_trailer_almost_done
:
2203 ctx
->length
= 1 /* LF */;
2205 case sw_trailer_header
:
2206 case sw_trailer_header_almost_done
:
2207 ctx
->length
= 2 /* LF LF */;