blob: f31df7b1f0e63303195a5be8982bd023dc0d7a57 [file] [log] [blame]
Igor Sysoev0c331d92002-08-15 17:20:26 +00001
Igor Sysoevd90282d2004-09-28 08:34:51 +00002/*
Igor Sysoevff8da912004-09-29 16:00:49 +00003 * Copyright (C) Igor Sysoev
Igor Sysoevd90282d2004-09-28 08:34:51 +00004 */
5
6
Igor Sysoev0c331d92002-08-15 17:20:26 +00007#include <ngx_config.h>
Igor Sysoev016b8522002-08-29 16:59:54 +00008#include <ngx_core.h>
Igor Sysoev0c331d92002-08-15 17:20:26 +00009#include <ngx_http.h>
10
Igor Sysoev59cf56c2004-09-07 15:29:22 +000011
Igor Sysoevbc808a72006-10-31 12:27:32 +000012static uint32_t usual[] = {
Igor Sysoevb5c75dc2006-10-28 14:36:44 +000013 0xffffdbfe, /* 1111 1111 1111 1111 1101 1011 1111 1110 */
Igor Sysoev0359ba82006-10-28 12:04:43 +000014
Igor Sysoevb5c75dc2006-10-28 14:36:44 +000015 /* ?>=< ;:98 7654 3210 /.-, +*)( '&%$ #"! */
16 0x7fff37d6, /* 0111 1111 1111 1111 0011 0111 1101 0110 */
Igor Sysoev0359ba82006-10-28 12:04:43 +000017
Igor Sysoevb5c75dc2006-10-28 14:36:44 +000018 /* _^]\ [ZYX WVUT SRQP ONML KJIH GFED CBA@ */
Igor Sysoevaddd3c82006-10-30 20:36:54 +000019#if (NGX_WIN32)
Igor Sysoevb5c75dc2006-10-28 14:36:44 +000020 0xefffffff, /* 1110 1111 1111 1111 1111 1111 1111 1111 */
Igor Sysoevaddd3c82006-10-30 20:36:54 +000021#else
22 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
23#endif
Igor Sysoev0359ba82006-10-28 12:04:43 +000024
Igor Sysoevb5c75dc2006-10-28 14:36:44 +000025 /* ~}| {zyx wvut srqp onml kjih gfed cba` */
26 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
Igor Sysoev0359ba82006-10-28 12:04:43 +000027
Igor Sysoevb5c75dc2006-10-28 14:36:44 +000028 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};
Igor Sysoev0359ba82006-10-28 12:04:43 +000033
34
Igor Sysoev544e9f12007-05-07 06:27:14 +000035#if (NGX_HAVE_LITTLE_ENDIAN && NGX_HAVE_NONALIGNED)
36
37#define ngx_str3_cmp(m, c0, c1, c2, c3) \
38 *(uint32_t *) m == ((c3 << 24) | (c2 << 16) | (c1 << 8) | c0)
39
40#define ngx_str3Ocmp(m, c0, c1, c2, c3) \
41 *(uint32_t *) m == ((c3 << 24) | (c2 << 16) | (c1 << 8) | c0)
42
43#define ngx_str4cmp(m, c0, c1, c2, c3) \
44 *(uint32_t *) m == ((c3 << 24) | (c2 << 16) | (c1 << 8) | c0)
45
46#define ngx_str5cmp(m, c0, c1, c2, c3, c4) \
47 *(uint32_t *) m == ((c3 << 24) | (c2 << 16) | (c1 << 8) | c0) \
48 && m[4] == c4
49
50#define ngx_str6cmp(m, c0, c1, c2, c3, c4, c5) \
51 *(uint32_t *) m == ((c3 << 24) | (c2 << 16) | (c1 << 8) | c0) \
52 && (((uint32_t *) m)[1] & 0xffff) == ((c5 << 8) | c4)
53
54#define ngx_str7_cmp(m, c0, c1, c2, c3, c4, c5, c6, c7) \
55 *(uint32_t *) m == ((c3 << 24) | (c2 << 16) | (c1 << 8) | c0) \
56 && ((uint32_t *) m)[1] == ((c7 << 24) | (c6 << 16) | (c5 << 8) | c4)
57
58#define ngx_str8cmp(m, c0, c1, c2, c3, c4, c5, c6, c7) \
59 *(uint32_t *) m == ((c3 << 24) | (c2 << 16) | (c1 << 8) | c0) \
60 && ((uint32_t *) m)[1] == ((c7 << 24) | (c6 << 16) | (c5 << 8) | c4)
61
62#define ngx_str9cmp(m, c0, c1, c2, c3, c4, c5, c6, c7, c8) \
63 *(uint32_t *) m == ((c3 << 24) | (c2 << 16) | (c1 << 8) | c0) \
64 && ((uint32_t *) m)[1] == ((c7 << 24) | (c6 << 16) | (c5 << 8) | c4) \
65 && m[8] == c8
66
67#else /* !(NGX_HAVE_LITTLE_ENDIAN && NGX_HAVE_NONALIGNED) */
68
69#define ngx_str3_cmp(m, c0, c1, c2, c3) \
70 m[0] == c0 && m[1] == c1 && m[2] == c2
71
72#define ngx_str3Ocmp(m, c0, c1, c2, c3) \
73 m[0] == c0 && m[2] == c2 && m[3] == c3
74
75#define ngx_str4cmp(m, c0, c1, c2, c3) \
76 m[0] == c0 && m[1] == c1 && m[2] == c2 && m[3] == c3
77
78#define ngx_str5cmp(m, c0, c1, c2, c3, c4) \
79 m[0] == c0 && m[1] == c1 && m[2] == c2 && m[3] == c3 && m[4] == c4
80
81#define ngx_str6cmp(m, c0, c1, c2, c3, c4, c5) \
82 m[0] == c0 && m[1] == c1 && m[2] == c2 && m[3] == c3 \
83 && m[4] == c4 && m[5] == c5
84
85#define ngx_str7_cmp(m, c0, c1, c2, c3, c4, c5, c6, c7) \
86 m[0] == c0 && m[1] == c1 && m[2] == c2 && m[3] == c3 \
87 && m[4] == c4 && m[5] == c5 && m[6] == c6
88
89#define ngx_str8cmp(m, c0, c1, c2, c3, c4, c5, c6, c7) \
90 m[0] == c0 && m[1] == c1 && m[2] == c2 && m[3] == c3 \
91 && m[4] == c4 && m[5] == c5 && m[6] == c6 && m[7] == c7
92
93#define ngx_str9cmp(m, c0, c1, c2, c3, c4, c5, c6, c7, c8) \
94 m[0] == c0 && m[1] == c1 && m[2] == c2 && m[3] == c3 \
95 && m[4] == c4 && m[5] == c5 && m[6] == c6 && m[7] == c7 && m[8] == c8
96
97#endif
98
99
Igor Sysoev3338cfd2006-05-11 14:43:47 +0000100/* gcc, icc, msvc and others compile these switches as an jump table */
101
Igor Sysoev899b44e2005-05-12 14:58:06 +0000102ngx_int_t
103ngx_http_parse_request_line(ngx_http_request_t *r, ngx_buf_t *b)
Igor Sysoev0c331d92002-08-15 17:20:26 +0000104{
Igor Sysoev02f742b2005-04-08 15:18:55 +0000105 u_char c, ch, *p, *m;
Igor Sysoev0c331d92002-08-15 17:20:26 +0000106 enum {
Igor Sysoev016b8522002-08-29 16:59:54 +0000107 sw_start = 0,
Igor Sysoeva3677242004-04-14 05:57:36 +0000108 sw_method,
Igor Sysoev016b8522002-08-29 16:59:54 +0000109 sw_spaces_before_uri,
Igor Sysoeva3677242004-04-14 05:57:36 +0000110 sw_schema,
111 sw_schema_slash,
112 sw_schema_slash_slash,
113 sw_host,
114 sw_port,
Igor Sysoev016b8522002-08-29 16:59:54 +0000115 sw_after_slash_in_uri,
116 sw_check_uri,
117 sw_uri,
118 sw_http_09,
Igor Sysoeva9830112003-05-19 16:39:14 +0000119 sw_http_H,
120 sw_http_HT,
121 sw_http_HTT,
122 sw_http_HTTP,
Igor Sysoev016b8522002-08-29 16:59:54 +0000123 sw_first_major_digit,
124 sw_major_digit,
125 sw_first_minor_digit,
126 sw_minor_digit,
Igor Sysoev81924e82007-10-26 11:34:10 +0000127 sw_spaces_after_digit,
Igor Sysoev02025fd2005-01-18 13:03:58 +0000128 sw_almost_done
Igor Sysoev481b6432002-12-04 16:29:40 +0000129 } state;
130
131 state = r->state;
Igor Sysoev0c331d92002-08-15 17:20:26 +0000132
Igor Sysoev02025fd2005-01-18 13:03:58 +0000133 for (p = b->pos; p < b->last; p++) {
134 ch = *p;
Igor Sysoev0c331d92002-08-15 17:20:26 +0000135
Igor Sysoev0c331d92002-08-15 17:20:26 +0000136 switch (state) {
137
138 /* HTTP methods: GET, HEAD, POST */
Igor Sysoev016b8522002-08-29 16:59:54 +0000139 case sw_start:
Igor Sysoev02025fd2005-01-18 13:03:58 +0000140 r->request_start = p;
Igor Sysoev3d062ad2003-03-05 06:37:42 +0000141
Igor Sysoev732a2712004-04-21 18:54:33 +0000142 if (ch == CR || ch == LF) {
143 break;
144 }
145
Igor Sysoeva3677242004-04-14 05:57:36 +0000146 if (ch < 'A' || ch > 'Z') {
Igor Sysoev1af7c822002-09-13 14:47:42 +0000147 return NGX_HTTP_PARSE_INVALID_METHOD;
Igor Sysoev0c331d92002-08-15 17:20:26 +0000148 }
Igor Sysoeva3677242004-04-14 05:57:36 +0000149
150 state = sw_method;
Igor Sysoeva9830112003-05-19 16:39:14 +0000151 break;
Igor Sysoev0c331d92002-08-15 17:20:26 +0000152
Igor Sysoeva3677242004-04-14 05:57:36 +0000153 case sw_method:
154 if (ch == ' ') {
Igor Sysoev899b44e2005-05-12 14:58:06 +0000155 r->method_end = p - 1;
Igor Sysoeva3677242004-04-14 05:57:36 +0000156 m = r->request_start;
Igor Sysoeva9830112003-05-19 16:39:14 +0000157
Igor Sysoev4ecb4d72006-04-21 12:06:44 +0000158 switch (p - m) {
Igor Sysoeva9830112003-05-19 16:39:14 +0000159
Igor Sysoev4ecb4d72006-04-21 12:06:44 +0000160 case 3:
Igor Sysoev544e9f12007-05-07 06:27:14 +0000161 if (ngx_str3_cmp(m, 'G', 'E', 'T', ' ')) {
Igor Sysoeva3677242004-04-14 05:57:36 +0000162 r->method = NGX_HTTP_GET;
Igor Sysoev8365f732006-11-14 12:43:48 +0000163 break;
Igor Sysoeva3677242004-04-14 05:57:36 +0000164 }
Igor Sysoev8365f732006-11-14 12:43:48 +0000165
Igor Sysoev544e9f12007-05-07 06:27:14 +0000166 if (ngx_str3_cmp(m, 'P', 'U', 'T', ' ')) {
Igor Sysoev8365f732006-11-14 12:43:48 +0000167 r->method = NGX_HTTP_PUT;
168 break;
169 }
170
Igor Sysoev4ecb4d72006-04-21 12:06:44 +0000171 break;
Igor Sysoeva9830112003-05-19 16:39:14 +0000172
Igor Sysoev4ecb4d72006-04-21 12:06:44 +0000173 case 4:
Igor Sysoev8365f732006-11-14 12:43:48 +0000174 if (m[1] == 'O') {
Igor Sysoeva9830112003-05-19 16:39:14 +0000175
Igor Sysoev544e9f12007-05-07 06:27:14 +0000176 if (ngx_str3Ocmp(m, 'P', 'O', 'S', 'T')) {
Igor Sysoev8365f732006-11-14 12:43:48 +0000177 r->method = NGX_HTTP_POST;
178 break;
179 }
180
Igor Sysoev544e9f12007-05-07 06:27:14 +0000181 if (ngx_str3Ocmp(m, 'C', 'O', 'P', 'Y')) {
Igor Sysoev8365f732006-11-14 12:43:48 +0000182 r->method = NGX_HTTP_COPY;
183 break;
184 }
185
Igor Sysoev544e9f12007-05-07 06:27:14 +0000186 if (ngx_str3Ocmp(m, 'M', 'O', 'V', 'E')) {
Igor Sysoev8365f732006-11-14 12:43:48 +0000187 r->method = NGX_HTTP_MOVE;
188 break;
189 }
190
Igor Sysoev544e9f12007-05-07 06:27:14 +0000191 if (ngx_str3Ocmp(m, 'L', 'O', 'C', 'K')) {
Igor Sysoev8365f732006-11-14 12:43:48 +0000192 r->method = NGX_HTTP_LOCK;
193 break;
194 }
195
196 } else {
197
Igor Sysoev544e9f12007-05-07 06:27:14 +0000198 if (ngx_str4cmp(m, 'H', 'E', 'A', 'D')) {
Igor Sysoev8365f732006-11-14 12:43:48 +0000199 r->method = NGX_HTTP_HEAD;
200 break;
201 }
Igor Sysoeva3677242004-04-14 05:57:36 +0000202 }
Igor Sysoev8365f732006-11-14 12:43:48 +0000203
Igor Sysoev4ecb4d72006-04-21 12:06:44 +0000204 break;
Igor Sysoev8a2b2fb2006-04-14 09:53:38 +0000205
Igor Sysoev4ecb4d72006-04-21 12:06:44 +0000206 case 5:
Igor Sysoev544e9f12007-05-07 06:27:14 +0000207 if (ngx_str5cmp(m, 'M', 'K', 'C', 'O', 'L')) {
Igor Sysoev7bdb7202006-04-19 15:30:56 +0000208 r->method = NGX_HTTP_MKCOL;
209 }
Igor Sysoev8365f732006-11-14 12:43:48 +0000210
Igor Sysoev544e9f12007-05-07 06:27:14 +0000211 if (ngx_str5cmp(m, 'T', 'R', 'A', 'C', 'E')) {
Igor Sysoev3e933d22007-03-30 18:59:26 +0000212 r->method = NGX_HTTP_TRACE;
213 }
214
Igor Sysoev4ecb4d72006-04-21 12:06:44 +0000215 break;
Igor Sysoev7bdb7202006-04-19 15:30:56 +0000216
Igor Sysoev4ecb4d72006-04-21 12:06:44 +0000217 case 6:
Igor Sysoev544e9f12007-05-07 06:27:14 +0000218 if (ngx_str6cmp(m, 'D', 'E', 'L', 'E', 'T', 'E')) {
Igor Sysoev8a2b2fb2006-04-14 09:53:38 +0000219 r->method = NGX_HTTP_DELETE;
Igor Sysoev8365f732006-11-14 12:43:48 +0000220 break;
Igor Sysoev8a2b2fb2006-04-14 09:53:38 +0000221 }
Igor Sysoev8365f732006-11-14 12:43:48 +0000222
Igor Sysoev544e9f12007-05-07 06:27:14 +0000223 if (ngx_str6cmp(m, 'U', 'N', 'L', 'O', 'C', 'K')) {
Igor Sysoev8365f732006-11-14 12:43:48 +0000224 r->method = NGX_HTTP_UNLOCK;
225 break;
226 }
227
228 break;
229
230 case 7:
Igor Sysoev544e9f12007-05-07 06:27:14 +0000231 if (ngx_str7_cmp(m, 'O', 'P', 'T', 'I', 'O', 'N', 'S', ' '))
Igor Sysoev8365f732006-11-14 12:43:48 +0000232 {
233 r->method = NGX_HTTP_OPTIONS;
234 }
235
236 break;
237
238 case 8:
Igor Sysoev544e9f12007-05-07 06:27:14 +0000239 if (ngx_str8cmp(m, 'P', 'R', 'O', 'P', 'F', 'I', 'N', 'D'))
Igor Sysoev8365f732006-11-14 12:43:48 +0000240 {
241 r->method = NGX_HTTP_PROPFIND;
242 }
243
244 break;
245
246 case 9:
Igor Sysoev544e9f12007-05-07 06:27:14 +0000247 if (ngx_str9cmp(m,
248 'P', 'R', 'O', 'P', 'P', 'A', 'T', 'C', 'H'))
Igor Sysoev8365f732006-11-14 12:43:48 +0000249 {
250 r->method = NGX_HTTP_PROPPATCH;
251 }
252
Igor Sysoev4ecb4d72006-04-21 12:06:44 +0000253 break;
Igor Sysoeva3677242004-04-14 05:57:36 +0000254 }
Igor Sysoeva9830112003-05-19 16:39:14 +0000255
Igor Sysoeva3677242004-04-14 05:57:36 +0000256 state = sw_spaces_before_uri;
Igor Sysoeva9830112003-05-19 16:39:14 +0000257 break;
Igor Sysoeva9830112003-05-19 16:39:14 +0000258 }
Igor Sysoeva9830112003-05-19 16:39:14 +0000259
Igor Sysoeva3677242004-04-14 05:57:36 +0000260 if (ch < 'A' || ch > 'Z') {
Igor Sysoeva9830112003-05-19 16:39:14 +0000261 return NGX_HTTP_PARSE_INVALID_METHOD;
262 }
Igor Sysoeva3677242004-04-14 05:57:36 +0000263
Igor Sysoev0c331d92002-08-15 17:20:26 +0000264 break;
265
Igor Sysoev0c331d92002-08-15 17:20:26 +0000266 /* space* before URI */
Igor Sysoev016b8522002-08-29 16:59:54 +0000267 case sw_spaces_before_uri:
Igor Sysoev02f742b2005-04-08 15:18:55 +0000268
Igor Sysoeve23b4842006-10-28 10:47:11 +0000269 if (ch == '/' ){
270 r->uri_start = p;
271 state = sw_after_slash_in_uri;
272 break;
273 }
274
Igor Sysoev02f742b2005-04-08 15:18:55 +0000275 c = (u_char) (ch | 0x20);
Igor Sysoev7b190b42005-06-07 15:56:31 +0000276 if (c >= 'a' && c <= 'z') {
Igor Sysoev1ebfead2005-02-16 13:40:36 +0000277 r->schema_start = p;
278 state = sw_schema;
279 break;
280 }
281
Igor Sysoev0c331d92002-08-15 17:20:26 +0000282 switch (ch) {
Igor Sysoev0c331d92002-08-15 17:20:26 +0000283 case ' ':
284 break;
285 default:
Igor Sysoeva3677242004-04-14 05:57:36 +0000286 return NGX_HTTP_PARSE_INVALID_REQUEST;
287 }
288 break;
289
290 case sw_schema:
Igor Sysoev02f742b2005-04-08 15:18:55 +0000291
292 c = (u_char) (ch | 0x20);
Igor Sysoev7b190b42005-06-07 15:56:31 +0000293 if (c >= 'a' && c <= 'z') {
Igor Sysoev1ebfead2005-02-16 13:40:36 +0000294 break;
295 }
296
Igor Sysoeva3677242004-04-14 05:57:36 +0000297 switch (ch) {
298 case ':':
Igor Sysoev02025fd2005-01-18 13:03:58 +0000299 r->schema_end = p;
Igor Sysoeva3677242004-04-14 05:57:36 +0000300 state = sw_schema_slash;
301 break;
302 default:
Igor Sysoeva3677242004-04-14 05:57:36 +0000303 return NGX_HTTP_PARSE_INVALID_REQUEST;
304 }
305 break;
306
307 case sw_schema_slash:
308 switch (ch) {
309 case '/':
310 state = sw_schema_slash_slash;
311 break;
312 default:
313 return NGX_HTTP_PARSE_INVALID_REQUEST;
314 }
315 break;
316
317 case sw_schema_slash_slash:
318 switch (ch) {
319 case '/':
Igor Sysoev95ead462006-11-23 20:20:23 +0000320 r->host_start = p + 1;
Igor Sysoeva3677242004-04-14 05:57:36 +0000321 state = sw_host;
322 break;
323 default:
324 return NGX_HTTP_PARSE_INVALID_REQUEST;
325 }
326 break;
327
328 case sw_host:
Igor Sysoev02f742b2005-04-08 15:18:55 +0000329
330 c = (u_char) (ch | 0x20);
Igor Sysoev7b190b42005-06-07 15:56:31 +0000331 if (c >= 'a' && c <= 'z') {
Igor Sysoev02f742b2005-04-08 15:18:55 +0000332 break;
333 }
334
Igor Sysoeve9b78092006-10-31 12:30:24 +0000335 if ((ch >= '0' && ch <= '9') || ch == '.' || ch == '-') {
Igor Sysoev1ebfead2005-02-16 13:40:36 +0000336 break;
337 }
338
Igor Sysoev4c5207f2007-10-18 11:33:31 +0000339 r->host_end = p;
340
Igor Sysoeva3677242004-04-14 05:57:36 +0000341 switch (ch) {
342 case ':':
Igor Sysoeva3677242004-04-14 05:57:36 +0000343 state = sw_port;
344 break;
345 case '/':
Igor Sysoev02025fd2005-01-18 13:03:58 +0000346 r->uri_start = p;
Igor Sysoeva3677242004-04-14 05:57:36 +0000347 state = sw_after_slash_in_uri;
348 break;
Igor Sysoev4c5207f2007-10-18 11:33:31 +0000349 case ' ':
350 /*
351 * use single "/" from request line to preserve pointers,
352 * if request line will be copied to large client buffer
353 */
354 r->uri_start = r->schema_end + 1;
355 r->uri_end = r->schema_end + 2;
356 state = sw_http_09;
357 break;
Igor Sysoeva3677242004-04-14 05:57:36 +0000358 default:
Igor Sysoeva3677242004-04-14 05:57:36 +0000359 return NGX_HTTP_PARSE_INVALID_REQUEST;
360 }
361 break;
362
363 case sw_port:
Igor Sysoev1ebfead2005-02-16 13:40:36 +0000364 if (ch >= '0' && ch <= '9') {
365 break;
366 }
367
Igor Sysoeva3677242004-04-14 05:57:36 +0000368 switch (ch) {
369 case '/':
Igor Sysoev02025fd2005-01-18 13:03:58 +0000370 r->port_end = p;
371 r->uri_start = p;
Igor Sysoeva3677242004-04-14 05:57:36 +0000372 state = sw_after_slash_in_uri;
373 break;
Igor Sysoev4c5207f2007-10-18 11:33:31 +0000374 case ' ':
375 r->port_end = p;
376 /*
377 * use single "/" from request line to preserve pointers,
378 * if request line will be copied to large client buffer
379 */
380 r->uri_start = r->schema_end + 1;
381 r->uri_end = r->schema_end + 2;
382 state = sw_http_09;
383 break;
Igor Sysoeva3677242004-04-14 05:57:36 +0000384 default:
Igor Sysoev1ebfead2005-02-16 13:40:36 +0000385 return NGX_HTTP_PARSE_INVALID_REQUEST;
Igor Sysoev0c331d92002-08-15 17:20:26 +0000386 }
387 break;
388
Igor Sysoev1b735832004-11-11 14:07:14 +0000389 /* check "/.", "//", "%", and "\" (Win32) in URI */
Igor Sysoev016b8522002-08-29 16:59:54 +0000390 case sw_after_slash_in_uri:
Igor Sysoev1ebfead2005-02-16 13:40:36 +0000391
Igor Sysoev0359ba82006-10-28 12:04:43 +0000392 if (usual[ch >> 5] & (1 << (ch & 0x1f))) {
Igor Sysoev1ebfead2005-02-16 13:40:36 +0000393 state = sw_check_uri;
394 break;
395 }
396
Igor Sysoev0c331d92002-08-15 17:20:26 +0000397 switch (ch) {
Igor Sysoev1ebfead2005-02-16 13:40:36 +0000398 case ' ':
399 r->uri_end = p;
400 state = sw_http_09;
401 break;
Igor Sysoev0c331d92002-08-15 17:20:26 +0000402 case CR:
Igor Sysoev02025fd2005-01-18 13:03:58 +0000403 r->uri_end = p;
Igor Sysoev0c331d92002-08-15 17:20:26 +0000404 r->http_minor = 9;
Igor Sysoev016b8522002-08-29 16:59:54 +0000405 state = sw_almost_done;
Igor Sysoev0c331d92002-08-15 17:20:26 +0000406 break;
407 case LF:
Igor Sysoev02025fd2005-01-18 13:03:58 +0000408 r->uri_end = p;
Igor Sysoev0c331d92002-08-15 17:20:26 +0000409 r->http_minor = 9;
Igor Sysoev02025fd2005-01-18 13:03:58 +0000410 goto done;
Igor Sysoev0c331d92002-08-15 17:20:26 +0000411 case '.':
412 r->complex_uri = 1;
Igor Sysoev016b8522002-08-29 16:59:54 +0000413 state = sw_uri;
Igor Sysoev0c331d92002-08-15 17:20:26 +0000414 break;
Igor Sysoev924bd792004-10-11 15:07:03 +0000415 case '%':
416 r->quoted_uri = 1;
417 state = sw_uri;
418 break;
Igor Sysoev1ebfead2005-02-16 13:40:36 +0000419 case '/':
420 r->complex_uri = 1;
421 state = sw_uri;
422 break;
Igor Sysoev1b735832004-11-11 14:07:14 +0000423#if (NGX_WIN32)
424 case '\\':
425 r->complex_uri = 1;
Igor Sysoev1ebfead2005-02-16 13:40:36 +0000426 state = sw_uri;
Igor Sysoev1b735832004-11-11 14:07:14 +0000427 break;
428#endif
Igor Sysoev1ebfead2005-02-16 13:40:36 +0000429 case '?':
430 r->args_start = p + 1;
431 state = sw_uri;
Igor Sysoev0c331d92002-08-15 17:20:26 +0000432 break;
Igor Sysoevb80a7f42006-10-28 10:15:31 +0000433 case '#':
434 r->complex_uri = 1;
435 state = sw_uri;
436 break;
Igor Sysoev805d9db2005-02-03 19:33:37 +0000437 case '+':
438 r->plus_in_uri = 1;
439 break;
Igor Sysoev1ebfead2005-02-16 13:40:36 +0000440 case '\0':
441 r->zero_in_uri = 1;
Igor Sysoev0c331d92002-08-15 17:20:26 +0000442 break;
443 default:
Igor Sysoev016b8522002-08-29 16:59:54 +0000444 state = sw_check_uri;
Igor Sysoev0c331d92002-08-15 17:20:26 +0000445 break;
446 }
447 break;
448
Igor Sysoev1b735832004-11-11 14:07:14 +0000449 /* check "/", "%" and "\" (Win32) in URI */
Igor Sysoev016b8522002-08-29 16:59:54 +0000450 case sw_check_uri:
Igor Sysoev1ebfead2005-02-16 13:40:36 +0000451
Igor Sysoev0359ba82006-10-28 12:04:43 +0000452 if (usual[ch >> 5] & (1 << (ch & 0x1f))) {
Igor Sysoev1ebfead2005-02-16 13:40:36 +0000453 break;
454 }
455
Igor Sysoev0c331d92002-08-15 17:20:26 +0000456 switch (ch) {
Igor Sysoev1ebfead2005-02-16 13:40:36 +0000457 case '/':
458 r->uri_ext = NULL;
459 state = sw_after_slash_in_uri;
460 break;
461 case '.':
462 r->uri_ext = p + 1;
463 break;
464 case ' ':
465 r->uri_end = p;
466 state = sw_http_09;
467 break;
Igor Sysoev0c331d92002-08-15 17:20:26 +0000468 case CR:
Igor Sysoev02025fd2005-01-18 13:03:58 +0000469 r->uri_end = p;
Igor Sysoev0c331d92002-08-15 17:20:26 +0000470 r->http_minor = 9;
Igor Sysoev016b8522002-08-29 16:59:54 +0000471 state = sw_almost_done;
Igor Sysoev0c331d92002-08-15 17:20:26 +0000472 break;
473 case LF:
Igor Sysoev02025fd2005-01-18 13:03:58 +0000474 r->uri_end = p;
Igor Sysoev0c331d92002-08-15 17:20:26 +0000475 r->http_minor = 9;
Igor Sysoev02025fd2005-01-18 13:03:58 +0000476 goto done;
Igor Sysoev1b735832004-11-11 14:07:14 +0000477#if (NGX_WIN32)
478 case '\\':
479 r->complex_uri = 1;
480 state = sw_after_slash_in_uri;
481 break;
482#endif
Igor Sysoev7578ec92003-06-02 15:24:30 +0000483 case '%':
Igor Sysoev924bd792004-10-11 15:07:03 +0000484 r->quoted_uri = 1;
Igor Sysoev7578ec92003-06-02 15:24:30 +0000485 state = sw_uri;
486 break;
Igor Sysoev0c331d92002-08-15 17:20:26 +0000487 case '?':
Igor Sysoev02025fd2005-01-18 13:03:58 +0000488 r->args_start = p + 1;
Igor Sysoev016b8522002-08-29 16:59:54 +0000489 state = sw_uri;
Igor Sysoev0c331d92002-08-15 17:20:26 +0000490 break;
Igor Sysoevb80a7f42006-10-28 10:15:31 +0000491 case '#':
492 r->complex_uri = 1;
493 state = sw_uri;
494 break;
Igor Sysoevef809b82006-06-28 16:00:26 +0000495 case '+':
496 r->plus_in_uri = 1;
497 break;
Igor Sysoev1ebfead2005-02-16 13:40:36 +0000498 case '\0':
499 r->zero_in_uri = 1;
500 break;
Igor Sysoev0c331d92002-08-15 17:20:26 +0000501 }
502 break;
503
504 /* URI */
Igor Sysoev016b8522002-08-29 16:59:54 +0000505 case sw_uri:
Igor Sysoev0359ba82006-10-28 12:04:43 +0000506
507 if (usual[ch >> 5] & (1 << (ch & 0x1f))) {
508 break;
509 }
510
Igor Sysoev0c331d92002-08-15 17:20:26 +0000511 switch (ch) {
Igor Sysoev1ebfead2005-02-16 13:40:36 +0000512 case ' ':
513 r->uri_end = p;
514 state = sw_http_09;
515 break;
Igor Sysoev0c331d92002-08-15 17:20:26 +0000516 case CR:
Igor Sysoev02025fd2005-01-18 13:03:58 +0000517 r->uri_end = p;
Igor Sysoev0c331d92002-08-15 17:20:26 +0000518 r->http_minor = 9;
Igor Sysoev016b8522002-08-29 16:59:54 +0000519 state = sw_almost_done;
Igor Sysoev0c331d92002-08-15 17:20:26 +0000520 break;
521 case LF:
Igor Sysoev02025fd2005-01-18 13:03:58 +0000522 r->uri_end = p;
Igor Sysoev0c331d92002-08-15 17:20:26 +0000523 r->http_minor = 9;
Igor Sysoev02025fd2005-01-18 13:03:58 +0000524 goto done;
Igor Sysoevb80a7f42006-10-28 10:15:31 +0000525 case '#':
526 r->complex_uri = 1;
527 break;
Igor Sysoev1ebfead2005-02-16 13:40:36 +0000528 case '\0':
529 r->zero_in_uri = 1;
Igor Sysoev0c331d92002-08-15 17:20:26 +0000530 break;
531 }
532 break;
533
534 /* space+ after URI */
Igor Sysoev016b8522002-08-29 16:59:54 +0000535 case sw_http_09:
Igor Sysoev0c331d92002-08-15 17:20:26 +0000536 switch (ch) {
537 case ' ':
538 break;
539 case CR:
540 r->http_minor = 9;
Igor Sysoev016b8522002-08-29 16:59:54 +0000541 state = sw_almost_done;
Igor Sysoev0c331d92002-08-15 17:20:26 +0000542 break;
543 case LF:
544 r->http_minor = 9;
Igor Sysoev02025fd2005-01-18 13:03:58 +0000545 goto done;
Igor Sysoev0c331d92002-08-15 17:20:26 +0000546 case 'H':
Igor Sysoev02025fd2005-01-18 13:03:58 +0000547 r->http_protocol.data = p;
Igor Sysoeva9830112003-05-19 16:39:14 +0000548 state = sw_http_H;
Igor Sysoev0c331d92002-08-15 17:20:26 +0000549 break;
550 default:
Igor Sysoev1af7c822002-09-13 14:47:42 +0000551 return NGX_HTTP_PARSE_INVALID_REQUEST;
Igor Sysoev0c331d92002-08-15 17:20:26 +0000552 }
553 break;
554
Igor Sysoeva9830112003-05-19 16:39:14 +0000555 case sw_http_H:
556 switch (ch) {
557 case 'T':
558 state = sw_http_HT;
559 break;
560 default:
Igor Sysoev1af7c822002-09-13 14:47:42 +0000561 return NGX_HTTP_PARSE_INVALID_REQUEST;
Igor Sysoev4e9393a2003-01-09 05:36:00 +0000562 }
Igor Sysoeva9830112003-05-19 16:39:14 +0000563 break;
Igor Sysoev0c331d92002-08-15 17:20:26 +0000564
Igor Sysoeva9830112003-05-19 16:39:14 +0000565 case sw_http_HT:
566 switch (ch) {
567 case 'T':
568 state = sw_http_HTT;
569 break;
570 default:
571 return NGX_HTTP_PARSE_INVALID_REQUEST;
572 }
573 break;
574
575 case sw_http_HTT:
576 switch (ch) {
577 case 'P':
578 state = sw_http_HTTP;
579 break;
580 default:
581 return NGX_HTTP_PARSE_INVALID_REQUEST;
582 }
583 break;
584
585 case sw_http_HTTP:
586 switch (ch) {
587 case '/':
588 state = sw_first_major_digit;
589 break;
590 default:
591 return NGX_HTTP_PARSE_INVALID_REQUEST;
592 }
Igor Sysoev0c331d92002-08-15 17:20:26 +0000593 break;
594
595 /* first digit of major HTTP version */
Igor Sysoev016b8522002-08-29 16:59:54 +0000596 case sw_first_major_digit:
Igor Sysoev4e9393a2003-01-09 05:36:00 +0000597 if (ch < '1' || ch > '9') {
Igor Sysoev1af7c822002-09-13 14:47:42 +0000598 return NGX_HTTP_PARSE_INVALID_REQUEST;
Igor Sysoev4e9393a2003-01-09 05:36:00 +0000599 }
Igor Sysoev0c331d92002-08-15 17:20:26 +0000600
601 r->http_major = ch - '0';
Igor Sysoev016b8522002-08-29 16:59:54 +0000602 state = sw_major_digit;
Igor Sysoev0c331d92002-08-15 17:20:26 +0000603 break;
604
605 /* major HTTP version or dot */
Igor Sysoev016b8522002-08-29 16:59:54 +0000606 case sw_major_digit:
Igor Sysoev0c331d92002-08-15 17:20:26 +0000607 if (ch == '.') {
Igor Sysoev016b8522002-08-29 16:59:54 +0000608 state = sw_first_minor_digit;
Igor Sysoev0c331d92002-08-15 17:20:26 +0000609 break;
610 }
611
Igor Sysoev4e9393a2003-01-09 05:36:00 +0000612 if (ch < '0' || ch > '9') {
Igor Sysoev1af7c822002-09-13 14:47:42 +0000613 return NGX_HTTP_PARSE_INVALID_REQUEST;
Igor Sysoev4e9393a2003-01-09 05:36:00 +0000614 }
Igor Sysoev0c331d92002-08-15 17:20:26 +0000615
616 r->http_major = r->http_major * 10 + ch - '0';
617 break;
618
619 /* first digit of minor HTTP version */
Igor Sysoev016b8522002-08-29 16:59:54 +0000620 case sw_first_minor_digit:
Igor Sysoev4e9393a2003-01-09 05:36:00 +0000621 if (ch < '0' || ch > '9') {
Igor Sysoev1af7c822002-09-13 14:47:42 +0000622 return NGX_HTTP_PARSE_INVALID_REQUEST;
Igor Sysoev4e9393a2003-01-09 05:36:00 +0000623 }
Igor Sysoev0c331d92002-08-15 17:20:26 +0000624
625 r->http_minor = ch - '0';
Igor Sysoev016b8522002-08-29 16:59:54 +0000626 state = sw_minor_digit;
Igor Sysoev0c331d92002-08-15 17:20:26 +0000627 break;
628
629 /* minor HTTP version or end of request line */
Igor Sysoev016b8522002-08-29 16:59:54 +0000630 case sw_minor_digit:
Igor Sysoev0c331d92002-08-15 17:20:26 +0000631 if (ch == CR) {
Igor Sysoev016b8522002-08-29 16:59:54 +0000632 state = sw_almost_done;
Igor Sysoev0c331d92002-08-15 17:20:26 +0000633 break;
634 }
635
636 if (ch == LF) {
Igor Sysoev02025fd2005-01-18 13:03:58 +0000637 goto done;
Igor Sysoev0c331d92002-08-15 17:20:26 +0000638 }
639
Igor Sysoev81924e82007-10-26 11:34:10 +0000640 if (ch == ' ') {
641 state = sw_spaces_after_digit;
642 break;
643 }
644
Igor Sysoev4e9393a2003-01-09 05:36:00 +0000645 if (ch < '0' || ch > '9') {
Igor Sysoev1af7c822002-09-13 14:47:42 +0000646 return NGX_HTTP_PARSE_INVALID_REQUEST;
Igor Sysoev4e9393a2003-01-09 05:36:00 +0000647 }
Igor Sysoev0c331d92002-08-15 17:20:26 +0000648
649 r->http_minor = r->http_minor * 10 + ch - '0';
650 break;
651
Igor Sysoev81924e82007-10-26 11:34:10 +0000652 case sw_spaces_after_digit:
653 switch (ch) {
654 case ' ':
655 break;
656 case CR:
657 state = sw_almost_done;
658 break;
659 case LF:
660 goto done;
661 default:
662 return NGX_HTTP_PARSE_INVALID_REQUEST;
663 }
664 break;
665
Igor Sysoev0c331d92002-08-15 17:20:26 +0000666 /* end of request line */
Igor Sysoev016b8522002-08-29 16:59:54 +0000667 case sw_almost_done:
Igor Sysoev02025fd2005-01-18 13:03:58 +0000668 r->request_end = p - 1;
Igor Sysoev0c331d92002-08-15 17:20:26 +0000669 switch (ch) {
670 case LF:
Igor Sysoev02025fd2005-01-18 13:03:58 +0000671 goto done;
Igor Sysoev0c331d92002-08-15 17:20:26 +0000672 default:
Igor Sysoev1af7c822002-09-13 14:47:42 +0000673 return NGX_HTTP_PARSE_INVALID_REQUEST;
Igor Sysoev0c331d92002-08-15 17:20:26 +0000674 }
Igor Sysoev0c331d92002-08-15 17:20:26 +0000675 }
676 }
677
Igor Sysoevdd888c42004-09-21 05:38:28 +0000678 b->pos = p;
Igor Sysoev02025fd2005-01-18 13:03:58 +0000679 r->state = state;
Igor Sysoev0c331d92002-08-15 17:20:26 +0000680
Igor Sysoev02025fd2005-01-18 13:03:58 +0000681 return NGX_AGAIN;
Igor Sysoev4e9393a2003-01-09 05:36:00 +0000682
Igor Sysoev02025fd2005-01-18 13:03:58 +0000683done:
Igor Sysoev4e9393a2003-01-09 05:36:00 +0000684
Igor Sysoev02025fd2005-01-18 13:03:58 +0000685 b->pos = p + 1;
Igor Sysoev4e9393a2003-01-09 05:36:00 +0000686
Igor Sysoev02025fd2005-01-18 13:03:58 +0000687 if (r->request_end == NULL) {
688 r->request_end = p;
Igor Sysoev0c331d92002-08-15 17:20:26 +0000689 }
Igor Sysoev02025fd2005-01-18 13:03:58 +0000690
691 r->http_version = r->http_major * 1000 + r->http_minor;
692 r->state = sw_start;
693
694 if (r->http_version == 9 && r->method != NGX_HTTP_GET) {
695 return NGX_HTTP_PARSE_INVALID_09_METHOD;
696 }
697
698 return NGX_OK;
Igor Sysoev0c331d92002-08-15 17:20:26 +0000699}
700
Igor Sysoevc2bba092003-11-28 17:41:47 +0000701
Igor Sysoev899b44e2005-05-12 14:58:06 +0000702ngx_int_t
Igor Sysoev753792e2008-09-24 14:02:50 +0000703ngx_http_parse_header_line(ngx_http_request_t *r, ngx_buf_t *b,
704 ngx_uint_t allow_underscores)
Igor Sysoev0c331d92002-08-15 17:20:26 +0000705{
Igor Sysoev02f742b2005-04-08 15:18:55 +0000706 u_char c, ch, *p;
Igor Sysoev3338cfd2006-05-11 14:43:47 +0000707 ngx_uint_t hash, i;
Igor Sysoevc2bba092003-11-28 17:41:47 +0000708 enum {
Igor Sysoev016b8522002-08-29 16:59:54 +0000709 sw_start = 0,
710 sw_name,
711 sw_space_before_value,
712 sw_value,
713 sw_space_after_value,
Igor Sysoev4d656dc2005-03-22 16:02:46 +0000714 sw_ignore_line,
Igor Sysoev016b8522002-08-29 16:59:54 +0000715 sw_almost_done,
Igor Sysoev4d656dc2005-03-22 16:02:46 +0000716 sw_header_almost_done
Igor Sysoev481b6432002-12-04 16:29:40 +0000717 } state;
718
Igor Sysoevbb8bbb72006-10-17 12:47:14 +0000719 /* the last '\0' is not needed because string is zero terminated */
720
Igor Sysoev3338cfd2006-05-11 14:43:47 +0000721 static u_char lowcase[] =
722 "\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"
723 "\0\0\0\0\0\0\0\0\0\0\0\0\0-\0\0" "0123456789\0\0\0\0\0\0"
Igor Sysoev753792e2008-09-24 14:02:50 +0000724 "\0abcdefghijklmnopqrstuvwxyz\0\0\0\0\0"
Igor Sysoev3338cfd2006-05-11 14:43:47 +0000725 "\0abcdefghijklmnopqrstuvwxyz\0\0\0\0\0"
726 "\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"
727 "\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"
728 "\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"
Igor Sysoevbb8bbb72006-10-17 12:47:14 +0000729 "\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";
Igor Sysoev3338cfd2006-05-11 14:43:47 +0000730
Igor Sysoev481b6432002-12-04 16:29:40 +0000731 state = r->state;
Igor Sysoev02f742b2005-04-08 15:18:55 +0000732 hash = r->header_hash;
Igor Sysoev3338cfd2006-05-11 14:43:47 +0000733 i = r->lowcase_index;
Igor Sysoev0c331d92002-08-15 17:20:26 +0000734
Igor Sysoev02025fd2005-01-18 13:03:58 +0000735 for (p = b->pos; p < b->last; p++) {
736 ch = *p;
Igor Sysoev0c331d92002-08-15 17:20:26 +0000737
Igor Sysoev0c331d92002-08-15 17:20:26 +0000738 switch (state) {
739
740 /* first char */
Igor Sysoev016b8522002-08-29 16:59:54 +0000741 case sw_start:
Igor Sysoev3362b8d2005-05-14 18:42:03 +0000742 r->invalid_header = 0;
743
Igor Sysoev0c331d92002-08-15 17:20:26 +0000744 switch (ch) {
745 case CR:
Igor Sysoev02025fd2005-01-18 13:03:58 +0000746 r->header_end = p;
Igor Sysoev016b8522002-08-29 16:59:54 +0000747 state = sw_header_almost_done;
Igor Sysoev0c331d92002-08-15 17:20:26 +0000748 break;
749 case LF:
Igor Sysoev02025fd2005-01-18 13:03:58 +0000750 r->header_end = p;
751 goto header_done;
Igor Sysoev0c331d92002-08-15 17:20:26 +0000752 default:
Igor Sysoev016b8522002-08-29 16:59:54 +0000753 state = sw_name;
Igor Sysoev02025fd2005-01-18 13:03:58 +0000754 r->header_name_start = p;
Igor Sysoev0c331d92002-08-15 17:20:26 +0000755
Igor Sysoev3338cfd2006-05-11 14:43:47 +0000756 c = lowcase[ch];
Igor Sysoev0c331d92002-08-15 17:20:26 +0000757
Igor Sysoev3338cfd2006-05-11 14:43:47 +0000758 if (c) {
759 hash = ngx_hash(0, c);
760 r->lowcase_header[0] = c;
761 i = 1;
Igor Sysoev0c331d92002-08-15 17:20:26 +0000762 break;
Igor Sysoev4e9393a2003-01-09 05:36:00 +0000763 }
Igor Sysoev0c331d92002-08-15 17:20:26 +0000764
Igor Sysoev3362b8d2005-05-14 18:42:03 +0000765 r->invalid_header = 1;
766
Igor Sysoev4d656dc2005-03-22 16:02:46 +0000767 break;
Igor Sysoev0c331d92002-08-15 17:20:26 +0000768
769 }
770 break;
771
772 /* header name */
Igor Sysoev016b8522002-08-29 16:59:54 +0000773 case sw_name:
Igor Sysoev3338cfd2006-05-11 14:43:47 +0000774 c = lowcase[ch];
775
776 if (c) {
777 hash = ngx_hash(hash, c);
778 r->lowcase_header[i++] = c;
Igor Sysoev8c8a6e52008-03-16 13:29:49 +0000779 i &= (NGX_HTTP_LC_HEADER_LEN - 1);
Igor Sysoev0c331d92002-08-15 17:20:26 +0000780 break;
Igor Sysoev4e9393a2003-01-09 05:36:00 +0000781 }
Igor Sysoev0c331d92002-08-15 17:20:26 +0000782
Igor Sysoev753792e2008-09-24 14:02:50 +0000783 if (ch == '_') {
784 if (allow_underscores) {
785 hash = ngx_hash(hash, ch);
786 r->lowcase_header[i++] = ch;
787 i &= (NGX_HTTP_LC_HEADER_LEN - 1);
788
789 } else {
790 r->invalid_header = 1;
791 }
792
793 break;
794 }
795
Igor Sysoev0c331d92002-08-15 17:20:26 +0000796 if (ch == ':') {
Igor Sysoev02025fd2005-01-18 13:03:58 +0000797 r->header_name_end = p;
Igor Sysoev016b8522002-08-29 16:59:54 +0000798 state = sw_space_before_value;
Igor Sysoev0c331d92002-08-15 17:20:26 +0000799 break;
800 }
801
Igor Sysoev899b44e2005-05-12 14:58:06 +0000802 if (ch == CR) {
803 r->header_name_end = p;
804 r->header_start = p;
805 r->header_end = p;
806 state = sw_almost_done;
807 break;
808 }
809
810 if (ch == LF) {
811 r->header_name_end = p;
812 r->header_start = p;
813 r->header_end = p;
814 goto done;
815 }
816
Igor Sysoev924bd792004-10-11 15:07:03 +0000817 /* IIS may send the duplicate "HTTP/1.1 ..." lines */
Igor Sysoev183f9a62003-04-09 15:42:08 +0000818 if (ch == '/'
Igor Sysoev899b44e2005-05-12 14:58:06 +0000819 && r->upstream
820 && p - r->header_name_start == 4
821 && ngx_strncmp(r->header_name_start, "HTTP", 4) == 0)
Igor Sysoev183f9a62003-04-09 15:42:08 +0000822 {
823 state = sw_ignore_line;
824 break;
Igor Sysoeve2a31542003-04-08 15:40:10 +0000825 }
826
Igor Sysoev3362b8d2005-05-14 18:42:03 +0000827 r->invalid_header = 1;
828
Igor Sysoev4d656dc2005-03-22 16:02:46 +0000829 break;
Igor Sysoev0c331d92002-08-15 17:20:26 +0000830
831 /* space* before header value */
Igor Sysoev016b8522002-08-29 16:59:54 +0000832 case sw_space_before_value:
Igor Sysoev0c331d92002-08-15 17:20:26 +0000833 switch (ch) {
834 case ' ':
835 break;
836 case CR:
Igor Sysoev899b44e2005-05-12 14:58:06 +0000837 r->header_start = p;
838 r->header_end = p;
Igor Sysoev016b8522002-08-29 16:59:54 +0000839 state = sw_almost_done;
Igor Sysoev0c331d92002-08-15 17:20:26 +0000840 break;
841 case LF:
Igor Sysoev899b44e2005-05-12 14:58:06 +0000842 r->header_start = p;
843 r->header_end = p;
Igor Sysoev02025fd2005-01-18 13:03:58 +0000844 goto done;
Igor Sysoev0c331d92002-08-15 17:20:26 +0000845 default:
Igor Sysoev02025fd2005-01-18 13:03:58 +0000846 r->header_start = p;
Igor Sysoev016b8522002-08-29 16:59:54 +0000847 state = sw_value;
Igor Sysoev0c331d92002-08-15 17:20:26 +0000848 break;
849 }
850 break;
851
852 /* header value */
Igor Sysoev016b8522002-08-29 16:59:54 +0000853 case sw_value:
Igor Sysoev0c331d92002-08-15 17:20:26 +0000854 switch (ch) {
855 case ' ':
Igor Sysoev02025fd2005-01-18 13:03:58 +0000856 r->header_end = p;
Igor Sysoev016b8522002-08-29 16:59:54 +0000857 state = sw_space_after_value;
Igor Sysoev0c331d92002-08-15 17:20:26 +0000858 break;
859 case CR:
Igor Sysoev02025fd2005-01-18 13:03:58 +0000860 r->header_end = p;
Igor Sysoev016b8522002-08-29 16:59:54 +0000861 state = sw_almost_done;
Igor Sysoev0c331d92002-08-15 17:20:26 +0000862 break;
863 case LF:
Igor Sysoev02025fd2005-01-18 13:03:58 +0000864 r->header_end = p;
865 goto done;
Igor Sysoev0c331d92002-08-15 17:20:26 +0000866 }
867 break;
868
869 /* space* before end of header line */
Igor Sysoev016b8522002-08-29 16:59:54 +0000870 case sw_space_after_value:
Igor Sysoev0c331d92002-08-15 17:20:26 +0000871 switch (ch) {
872 case ' ':
873 break;
874 case CR:
Igor Sysoev016b8522002-08-29 16:59:54 +0000875 state = sw_almost_done;
Igor Sysoev0c331d92002-08-15 17:20:26 +0000876 break;
877 case LF:
Igor Sysoev02025fd2005-01-18 13:03:58 +0000878 goto done;
Igor Sysoev0c331d92002-08-15 17:20:26 +0000879 default:
Igor Sysoev016b8522002-08-29 16:59:54 +0000880 state = sw_value;
Igor Sysoev0c331d92002-08-15 17:20:26 +0000881 break;
882 }
883 break;
884
Igor Sysoeve2a31542003-04-08 15:40:10 +0000885 /* ignore header line */
886 case sw_ignore_line:
887 switch (ch) {
888 case LF:
889 state = sw_start;
890 break;
891 default:
892 break;
893 }
894 break;
895
Igor Sysoev0c331d92002-08-15 17:20:26 +0000896 /* end of header line */
Igor Sysoev016b8522002-08-29 16:59:54 +0000897 case sw_almost_done:
Igor Sysoev0c331d92002-08-15 17:20:26 +0000898 switch (ch) {
899 case LF:
Igor Sysoev02025fd2005-01-18 13:03:58 +0000900 goto done;
Igor Sysoev70d09612008-03-16 16:47:16 +0000901 case CR:
902 break;
Igor Sysoev0c331d92002-08-15 17:20:26 +0000903 default:
Igor Sysoev1af7c822002-09-13 14:47:42 +0000904 return NGX_HTTP_PARSE_INVALID_HEADER;
Igor Sysoev0c331d92002-08-15 17:20:26 +0000905 }
Igor Sysoev455a7fc2006-03-21 08:20:41 +0000906 break;
Igor Sysoev0c331d92002-08-15 17:20:26 +0000907
908 /* end of header */
Igor Sysoev016b8522002-08-29 16:59:54 +0000909 case sw_header_almost_done:
Igor Sysoev0c331d92002-08-15 17:20:26 +0000910 switch (ch) {
911 case LF:
Igor Sysoev02025fd2005-01-18 13:03:58 +0000912 goto header_done;
Igor Sysoev0c331d92002-08-15 17:20:26 +0000913 default:
Igor Sysoev1af7c822002-09-13 14:47:42 +0000914 return NGX_HTTP_PARSE_INVALID_HEADER;
Igor Sysoev0c331d92002-08-15 17:20:26 +0000915 }
Igor Sysoev0c331d92002-08-15 17:20:26 +0000916 }
917 }
918
Igor Sysoev369145c2004-05-28 15:49:23 +0000919 b->pos = p;
Igor Sysoev02025fd2005-01-18 13:03:58 +0000920 r->state = state;
Igor Sysoev02f742b2005-04-08 15:18:55 +0000921 r->header_hash = hash;
Igor Sysoev3338cfd2006-05-11 14:43:47 +0000922 r->lowcase_index = i;
Igor Sysoev0c331d92002-08-15 17:20:26 +0000923
Igor Sysoev02025fd2005-01-18 13:03:58 +0000924 return NGX_AGAIN;
Igor Sysoev4e9393a2003-01-09 05:36:00 +0000925
Igor Sysoev02025fd2005-01-18 13:03:58 +0000926done:
Igor Sysoev4e9393a2003-01-09 05:36:00 +0000927
Igor Sysoev02025fd2005-01-18 13:03:58 +0000928 b->pos = p + 1;
929 r->state = sw_start;
Igor Sysoev02f742b2005-04-08 15:18:55 +0000930 r->header_hash = hash;
Igor Sysoev3338cfd2006-05-11 14:43:47 +0000931 r->lowcase_index = i;
Igor Sysoev02025fd2005-01-18 13:03:58 +0000932
933 return NGX_OK;
934
935header_done:
936
937 b->pos = p + 1;
938 r->state = sw_start;
939
940 return NGX_HTTP_PARSE_HEADER_DONE;
Igor Sysoev0c331d92002-08-15 17:20:26 +0000941}
Igor Sysoevc2bba092003-11-28 17:41:47 +0000942
943
Igor Sysoev899b44e2005-05-12 14:58:06 +0000944ngx_int_t
Igor Sysoev8decab32007-10-18 11:36:58 +0000945ngx_http_parse_complex_uri(ngx_http_request_t *r, ngx_uint_t merge_slashes)
Igor Sysoevc2bba092003-11-28 17:41:47 +0000946{
Igor Sysoev10a543a2004-03-16 07:10:12 +0000947 u_char c, ch, decoded, *p, *u;
Igor Sysoevc2bba092003-11-28 17:41:47 +0000948 enum {
949 sw_usual = 0,
950 sw_slash,
951 sw_dot,
952 sw_dot_dot,
Igor Sysoev1b735832004-11-11 14:07:14 +0000953#if (NGX_WIN32)
Igor Sysoevc2bba092003-11-28 17:41:47 +0000954 sw_dot_dot_dot,
955#endif
956 sw_quoted,
957 sw_quoted_second
958 } state, quoted_state;
959
Igor Sysoev02025fd2005-01-18 13:03:58 +0000960#if (NGX_SUPPRESS_WARN)
Igor Sysoevc2bba092003-11-28 17:41:47 +0000961 decoded = '\0';
962 quoted_state = sw_usual;
Igor Sysoev02025fd2005-01-18 13:03:58 +0000963#endif
Igor Sysoevc2bba092003-11-28 17:41:47 +0000964
965 state = sw_usual;
966 p = r->uri_start;
967 u = r->uri.data;
Igor Sysoev865c1502003-11-30 20:03:18 +0000968 r->uri_ext = NULL;
Igor Sysoev1b735832004-11-11 14:07:14 +0000969 r->args_start = NULL;
Igor Sysoevc2bba092003-11-28 17:41:47 +0000970
971 ch = *p++;
972
Igor Sysoev02025fd2005-01-18 13:03:58 +0000973 while (p <= r->uri_end) {
Igor Sysoev1b735832004-11-11 14:07:14 +0000974
975 /*
Igor Sysoev02025fd2005-01-18 13:03:58 +0000976 * we use "ch = *p++" inside the cycle, but this operation is safe,
Igor Sysoev1b735832004-11-11 14:07:14 +0000977 * because after the URI there is always at least one charcter:
978 * the line feed
979 */
Igor Sysoevc2bba092003-11-28 17:41:47 +0000980
Igor Sysoev54498db2004-02-11 17:08:49 +0000981 ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
Igor Sysoev1b735832004-11-11 14:07:14 +0000982 "s:%d in:'%Xd:%c', out:'%c'", state, ch, ch, *u);
Igor Sysoevc2bba092003-11-28 17:41:47 +0000983
984 switch (state) {
Igor Sysoev09c684b2005-11-09 17:25:55 +0000985
Igor Sysoevc2bba092003-11-28 17:41:47 +0000986 case sw_usual:
Igor Sysoev0359ba82006-10-28 12:04:43 +0000987
988 if (usual[ch >> 5] & (1 << (ch & 0x1f))) {
989 *u++ = ch;
990 ch = *p++;
991 break;
992 }
993
Igor Sysoevc2bba092003-11-28 17:41:47 +0000994 switch(ch) {
Igor Sysoev1b735832004-11-11 14:07:14 +0000995#if (NGX_WIN32)
996 case '\\':
997 r->uri_ext = NULL;
998
999 if (p == r->uri_start + r->uri.len) {
1000
1001 /*
1002 * we omit the last "\" to cause redirect because
1003 * the browsers do not treat "\" as "/" in relative URL path
1004 */
1005
1006 break;
1007 }
1008
1009 state = sw_slash;
1010 *u++ = '/';
1011 break;
1012#endif
Igor Sysoevc2bba092003-11-28 17:41:47 +00001013 case '/':
Igor Sysoev865c1502003-11-30 20:03:18 +00001014 r->uri_ext = NULL;
Igor Sysoevc2bba092003-11-28 17:41:47 +00001015 state = sw_slash;
1016 *u++ = ch;
1017 break;
1018 case '%':
1019 quoted_state = state;
1020 state = sw_quoted;
1021 break;
Igor Sysoev1b735832004-11-11 14:07:14 +00001022 case '?':
1023 r->args_start = p;
Igor Sysoevb80a7f42006-10-28 10:15:31 +00001024 goto args;
1025 case '#':
Igor Sysoev02025fd2005-01-18 13:03:58 +00001026 goto done;
Igor Sysoev865c1502003-11-30 20:03:18 +00001027 case '.':
1028 r->uri_ext = u + 1;
Igor Sysoev42b12b32004-12-02 18:40:46 +00001029 *u++ = ch;
1030 break;
Igor Sysoevef809b82006-06-28 16:00:26 +00001031 case '+':
1032 r->plus_in_uri = 1;
Igor Sysoevc2bba092003-11-28 17:41:47 +00001033 default:
1034 *u++ = ch;
1035 break;
1036 }
Igor Sysoev0359ba82006-10-28 12:04:43 +00001037
Igor Sysoevc2bba092003-11-28 17:41:47 +00001038 ch = *p++;
1039 break;
1040
1041 case sw_slash:
Igor Sysoev0359ba82006-10-28 12:04:43 +00001042
1043 if (usual[ch >> 5] & (1 << (ch & 0x1f))) {
1044 state = sw_usual;
1045 *u++ = ch;
1046 ch = *p++;
1047 break;
1048 }
1049
Igor Sysoevc2bba092003-11-28 17:41:47 +00001050 switch(ch) {
Igor Sysoev1b735832004-11-11 14:07:14 +00001051#if (NGX_WIN32)
1052 case '\\':
Igor Sysoev8decab32007-10-18 11:36:58 +00001053 break;
Igor Sysoev1b735832004-11-11 14:07:14 +00001054#endif
Igor Sysoevc2bba092003-11-28 17:41:47 +00001055 case '/':
Igor Sysoevb862cf42007-12-14 14:33:00 +00001056 if (!merge_slashes) {
Igor Sysoev8decab32007-10-18 11:36:58 +00001057 *u++ = ch;
1058 }
Igor Sysoevc2bba092003-11-28 17:41:47 +00001059 break;
1060 case '.':
1061 state = sw_dot;
1062 *u++ = ch;
1063 break;
1064 case '%':
1065 quoted_state = state;
1066 state = sw_quoted;
1067 break;
Igor Sysoev02025fd2005-01-18 13:03:58 +00001068 case '?':
1069 r->args_start = p;
Igor Sysoevb80a7f42006-10-28 10:15:31 +00001070 goto args;
1071 case '#':
Igor Sysoev02025fd2005-01-18 13:03:58 +00001072 goto done;
Igor Sysoevef809b82006-06-28 16:00:26 +00001073 case '+':
1074 r->plus_in_uri = 1;
Igor Sysoevc2bba092003-11-28 17:41:47 +00001075 default:
1076 state = sw_usual;
1077 *u++ = ch;
1078 break;
1079 }
Igor Sysoev0359ba82006-10-28 12:04:43 +00001080
Igor Sysoevc2bba092003-11-28 17:41:47 +00001081 ch = *p++;
1082 break;
1083
1084 case sw_dot:
Igor Sysoev0359ba82006-10-28 12:04:43 +00001085
1086 if (usual[ch >> 5] & (1 << (ch & 0x1f))) {
1087 state = sw_usual;
1088 *u++ = ch;
1089 ch = *p++;
1090 break;
1091 }
1092
Igor Sysoevc2bba092003-11-28 17:41:47 +00001093 switch(ch) {
Igor Sysoev1b735832004-11-11 14:07:14 +00001094#if (NGX_WIN32)
1095 case '\\':
Igor Sysoev1b735832004-11-11 14:07:14 +00001096#endif
Igor Sysoevc2bba092003-11-28 17:41:47 +00001097 case '/':
1098 state = sw_slash;
1099 u--;
1100 break;
1101 case '.':
1102 state = sw_dot_dot;
1103 *u++ = ch;
1104 break;
1105 case '%':
1106 quoted_state = state;
1107 state = sw_quoted;
1108 break;
Igor Sysoev02025fd2005-01-18 13:03:58 +00001109 case '?':
1110 r->args_start = p;
Igor Sysoevb80a7f42006-10-28 10:15:31 +00001111 goto args;
1112 case '#':
Igor Sysoev02025fd2005-01-18 13:03:58 +00001113 goto done;
Igor Sysoevef809b82006-06-28 16:00:26 +00001114 case '+':
1115 r->plus_in_uri = 1;
Igor Sysoevc2bba092003-11-28 17:41:47 +00001116 default:
1117 state = sw_usual;
1118 *u++ = ch;
1119 break;
1120 }
Igor Sysoev0359ba82006-10-28 12:04:43 +00001121
Igor Sysoevc2bba092003-11-28 17:41:47 +00001122 ch = *p++;
1123 break;
1124
1125 case sw_dot_dot:
Igor Sysoev0359ba82006-10-28 12:04:43 +00001126
1127 if (usual[ch >> 5] & (1 << (ch & 0x1f))) {
1128 state = sw_usual;
1129 *u++ = ch;
1130 ch = *p++;
1131 break;
1132 }
1133
Igor Sysoevc2bba092003-11-28 17:41:47 +00001134 switch(ch) {
Igor Sysoev1b735832004-11-11 14:07:14 +00001135#if (NGX_WIN32)
1136 case '\\':
Igor Sysoev1b735832004-11-11 14:07:14 +00001137#endif
Igor Sysoevc2bba092003-11-28 17:41:47 +00001138 case '/':
1139 state = sw_slash;
1140 u -= 4;
1141 if (u < r->uri.data) {
1142 return NGX_HTTP_PARSE_INVALID_REQUEST;
1143 }
1144 while (*(u - 1) != '/') {
1145 u--;
1146 }
1147 break;
1148 case '%':
1149 quoted_state = state;
1150 state = sw_quoted;
1151 break;
Igor Sysoev02025fd2005-01-18 13:03:58 +00001152 case '?':
1153 r->args_start = p;
Igor Sysoevb80a7f42006-10-28 10:15:31 +00001154 goto args;
1155 case '#':
Igor Sysoev02025fd2005-01-18 13:03:58 +00001156 goto done;
Igor Sysoev1b735832004-11-11 14:07:14 +00001157#if (NGX_WIN32)
Igor Sysoevc2bba092003-11-28 17:41:47 +00001158 case '.':
1159 state = sw_dot_dot_dot;
1160 *u++ = ch;
1161 break;
1162#endif
Igor Sysoevef809b82006-06-28 16:00:26 +00001163 case '+':
1164 r->plus_in_uri = 1;
Igor Sysoevc2bba092003-11-28 17:41:47 +00001165 default:
1166 state = sw_usual;
1167 *u++ = ch;
1168 break;
1169 }
Igor Sysoev0359ba82006-10-28 12:04:43 +00001170
Igor Sysoevc2bba092003-11-28 17:41:47 +00001171 ch = *p++;
1172 break;
1173
Igor Sysoev1b735832004-11-11 14:07:14 +00001174#if (NGX_WIN32)
Igor Sysoevc2bba092003-11-28 17:41:47 +00001175 case sw_dot_dot_dot:
Igor Sysoev0359ba82006-10-28 12:04:43 +00001176
1177 if (usual[ch >> 5] & (1 << (ch & 0x1f))) {
1178 state = sw_usual;
1179 *u++ = ch;
1180 ch = *p++;
1181 break;
1182 }
1183
Igor Sysoevc2bba092003-11-28 17:41:47 +00001184 switch(ch) {
Igor Sysoev1b735832004-11-11 14:07:14 +00001185 case '\\':
Igor Sysoevc2bba092003-11-28 17:41:47 +00001186 case '/':
1187 state = sw_slash;
1188 u -= 5;
1189 if (u < r->uri.data) {
1190 return NGX_HTTP_PARSE_INVALID_REQUEST;
1191 }
1192 while (*u != '/') {
1193 u--;
1194 }
1195 if (u < r->uri.data) {
1196 return NGX_HTTP_PARSE_INVALID_REQUEST;
1197 }
1198 while (*(u - 1) != '/') {
1199 u--;
1200 }
1201 break;
1202 case '%':
1203 quoted_state = state;
1204 state = sw_quoted;
1205 break;
Igor Sysoev09c684b2005-11-09 17:25:55 +00001206 case '?':
1207 r->args_start = p;
Igor Sysoevb80a7f42006-10-28 10:15:31 +00001208 goto args;
1209 case '#':
Igor Sysoev09c684b2005-11-09 17:25:55 +00001210 goto done;
Igor Sysoevef809b82006-06-28 16:00:26 +00001211 case '+':
1212 r->plus_in_uri = 1;
Igor Sysoevc2bba092003-11-28 17:41:47 +00001213 default:
1214 state = sw_usual;
1215 *u++ = ch;
1216 break;
1217 }
Igor Sysoev0359ba82006-10-28 12:04:43 +00001218
Igor Sysoevc2bba092003-11-28 17:41:47 +00001219 ch = *p++;
1220 break;
1221#endif
1222
1223 case sw_quoted:
Igor Sysoev8f125582006-07-28 15:16:17 +00001224 r->quoted_uri = 1;
1225
Igor Sysoevc2bba092003-11-28 17:41:47 +00001226 if (ch >= '0' && ch <= '9') {
Igor Sysoev9c610952004-03-16 13:35:20 +00001227 decoded = (u_char) (ch - '0');
Igor Sysoevc2bba092003-11-28 17:41:47 +00001228 state = sw_quoted_second;
1229 ch = *p++;
1230 break;
1231 }
1232
Igor Sysoev9c610952004-03-16 13:35:20 +00001233 c = (u_char) (ch | 0x20);
Igor Sysoevc2bba092003-11-28 17:41:47 +00001234 if (c >= 'a' && c <= 'f') {
Igor Sysoev9c610952004-03-16 13:35:20 +00001235 decoded = (u_char) (c - 'a' + 10);
Igor Sysoevc2bba092003-11-28 17:41:47 +00001236 state = sw_quoted_second;
1237 ch = *p++;
1238 break;
1239 }
1240
1241 return NGX_HTTP_PARSE_INVALID_REQUEST;
1242
1243 case sw_quoted_second:
1244 if (ch >= '0' && ch <= '9') {
Igor Sysoev9c610952004-03-16 13:35:20 +00001245 ch = (u_char) ((decoded << 4) + ch - '0');
Igor Sysoev1ebfead2005-02-16 13:40:36 +00001246
Igor Sysoev7adb8c02003-12-02 16:57:05 +00001247 if (ch == '%') {
1248 state = sw_usual;
1249 *u++ = ch;
1250 ch = *p++;
1251 break;
1252 }
Igor Sysoev1ebfead2005-02-16 13:40:36 +00001253
Igor Sysoevb80a7f42006-10-28 10:15:31 +00001254 if (ch == '#') {
1255 *u++ = ch;
1256 ch = *p++;
1257
1258 } else if (ch == '\0') {
Igor Sysoev1ebfead2005-02-16 13:40:36 +00001259 r->zero_in_uri = 1;
Igor Sysoev1ebfead2005-02-16 13:40:36 +00001260 }
1261
Igor Sysoevc2bba092003-11-28 17:41:47 +00001262 state = quoted_state;
1263 break;
1264 }
1265
Igor Sysoev9c610952004-03-16 13:35:20 +00001266 c = (u_char) (ch | 0x20);
Igor Sysoevc2bba092003-11-28 17:41:47 +00001267 if (c >= 'a' && c <= 'f') {
Igor Sysoev9c610952004-03-16 13:35:20 +00001268 ch = (u_char) ((decoded << 4) + c - 'a' + 10);
Igor Sysoevef809b82006-06-28 16:00:26 +00001269
Igor Sysoev02025fd2005-01-18 13:03:58 +00001270 if (ch == '?') {
Igor Sysoev7adb8c02003-12-02 16:57:05 +00001271 *u++ = ch;
1272 ch = *p++;
Igor Sysoevef809b82006-06-28 16:00:26 +00001273
1274 } else if (ch == '+') {
1275 r->plus_in_uri = 1;
Igor Sysoev7adb8c02003-12-02 16:57:05 +00001276 }
Igor Sysoevef809b82006-06-28 16:00:26 +00001277
Igor Sysoevc2bba092003-11-28 17:41:47 +00001278 state = quoted_state;
1279 break;
1280 }
1281
1282 return NGX_HTTP_PARSE_INVALID_REQUEST;
1283 }
1284 }
1285
Igor Sysoev02025fd2005-01-18 13:03:58 +00001286done:
1287
Igor Sysoevc2bba092003-11-28 17:41:47 +00001288 r->uri.len = u - r->uri.data;
Igor Sysoevc2bba092003-11-28 17:41:47 +00001289
Igor Sysoev865c1502003-11-30 20:03:18 +00001290 if (r->uri_ext) {
1291 r->exten.len = u - r->uri_ext;
Igor Sysoev1b735832004-11-11 14:07:14 +00001292 r->exten.data = r->uri_ext;
Igor Sysoev865c1502003-11-30 20:03:18 +00001293 }
1294
1295 r->uri_ext = NULL;
1296
Igor Sysoevc2bba092003-11-28 17:41:47 +00001297 return NGX_OK;
Igor Sysoevb80a7f42006-10-28 10:15:31 +00001298
1299args:
1300
1301 while (p < r->uri_end) {
1302 if (*p++ != '#') {
1303 continue;
1304 }
1305
1306 r->args.len = p - 1 - r->args_start;
1307 r->args.data = r->args_start;
1308 r->args_start = NULL;
1309
1310 break;
1311 }
1312
1313 r->uri.len = u - r->uri.data;
1314
1315 if (r->uri_ext) {
1316 r->exten.len = u - r->uri_ext;
1317 r->exten.data = r->uri_ext;
1318 }
1319
1320 r->uri_ext = NULL;
1321
1322 return NGX_OK;
Igor Sysoevc2bba092003-11-28 17:41:47 +00001323}
Igor Sysoev899b44e2005-05-12 14:58:06 +00001324
1325
1326ngx_int_t
Igor Sysoev09c684b2005-11-09 17:25:55 +00001327ngx_http_parse_unsafe_uri(ngx_http_request_t *r, ngx_str_t *uri,
1328 ngx_str_t *args, ngx_uint_t *flags)
1329{
1330 u_char ch, *p;
1331 size_t len;
1332
1333 len = uri->len;
1334 p = uri->data;
1335
1336 if (len == 0 || p[0] == '?') {
1337 goto unsafe;
1338 }
1339
1340 if (p[0] == '.' && len == 3 && p[1] == '.' && (p[2] == '/'
1341#if (NGX_WIN32)
1342 || p[2] == '\\'
1343#endif
1344 ))
1345 {
1346 goto unsafe;
1347 }
1348
1349 for ( /* void */ ; len; len--) {
1350
1351 ch = *p++;
1352
Igor Sysoev0359ba82006-10-28 12:04:43 +00001353 if (usual[ch >> 5] & (1 << (ch & 0x1f))) {
1354 continue;
1355 }
1356
Igor Sysoev09c684b2005-11-09 17:25:55 +00001357 if (ch == '?') {
1358 args->len = len - 1;
1359 args->data = p;
1360 uri->len -= len;
1361
1362 return NGX_OK;
1363 }
1364
1365 if (ch == '\0') {
1366 *flags |= NGX_HTTP_ZERO_IN_URI;
1367 continue;
1368 }
1369
Igor Sysoeva994bd02006-10-28 13:59:56 +00001370 if ((ch == '/'
Igor Sysoev09c684b2005-11-09 17:25:55 +00001371#if (NGX_WIN32)
Igor Sysoeva994bd02006-10-28 13:59:56 +00001372 || ch == '\\'
Igor Sysoev09c684b2005-11-09 17:25:55 +00001373#endif
Igor Sysoeva994bd02006-10-28 13:59:56 +00001374 ) && len > 2)
Igor Sysoev09c684b2005-11-09 17:25:55 +00001375 {
Igor Sysoev09c684b2005-11-09 17:25:55 +00001376 /* detect "/../" */
1377
Igor Sysoev3fc6f642005-11-10 07:44:53 +00001378 if (p[0] == '.' && p[1] == '.' && p[2] == '/') {
Igor Sysoev09c684b2005-11-09 17:25:55 +00001379 goto unsafe;
1380 }
1381
1382#if (NGX_WIN32)
1383
1384 if (p[2] == '\\') {
1385 goto unsafe;
1386 }
1387
1388 if (len > 3) {
1389
1390 /* detect "/.../" */
1391
Igor Sysoev3fc6f642005-11-10 07:44:53 +00001392 if (p[0] == '.' && p[1] == '.' && p[2] == '.'
1393 && (p[3] == '/' || p[3] == '\\'))
1394 {
Igor Sysoev09c684b2005-11-09 17:25:55 +00001395 goto unsafe;
1396 }
1397 }
1398#endif
1399 }
1400 }
1401
1402 return NGX_OK;
1403
1404unsafe:
1405
1406 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
1407 "unsafe URI \"%V\" was detected", uri);
1408
1409 return NGX_ERROR;
1410}
1411
1412
1413ngx_int_t
Igor Sysoev899b44e2005-05-12 14:58:06 +00001414ngx_http_parse_multi_header_lines(ngx_array_t *headers, ngx_str_t *name,
1415 ngx_str_t *value)
1416{
1417 ngx_uint_t i;
1418 u_char *start, *last, *end, ch;
1419 ngx_table_elt_t **h;
1420
1421 h = headers->elts;
1422
1423 for (i = 0; i < headers->nelts; i++) {
1424
1425 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, headers->pool->log, 0,
1426 "parse header: \"%V: %V\"", &h[i]->key, &h[i]->value);
1427
1428 if (name->len > h[i]->value.len) {
1429 continue;
1430 }
Igor Sysoev0e5dc5c2005-11-15 13:30:52 +00001431
Igor Sysoev899b44e2005-05-12 14:58:06 +00001432 start = h[i]->value.data;
1433 end = h[i]->value.data + h[i]->value.len;
1434
1435 while (start < end) {
1436
1437 if (ngx_strncasecmp(start, name->data, name->len) != 0) {
1438 goto skip;
1439 }
1440
1441 for (start += name->len; start < end && *start == ' '; start++) {
1442 /* void */
1443 }
1444
1445 if (value == NULL) {
1446 if (start == end || *start == ',') {
1447 return i;
1448 }
1449
1450 goto skip;
1451 }
1452
1453 if (start == end || *start++ != '=') {
1454 /* the invalid header value */
1455 goto skip;
1456 }
1457
1458 while (start < end && *start == ' ') { start++; }
1459
1460 for (last = start; last < end && *last != ';'; last++) {
1461 /* void */
1462 }
1463
1464 value->len = last - start;
1465 value->data = start;
1466
1467 return i;
1468
1469 skip:
Igor Sysoev09c684b2005-11-09 17:25:55 +00001470
Igor Sysoev899b44e2005-05-12 14:58:06 +00001471 while (start < end) {
1472 ch = *start++;
1473 if (ch == ';' || ch == ',') {
1474 break;
1475 }
1476 }
1477
1478 while (start < end && *start == ' ') { start++; }
1479 }
1480 }
1481
1482 return NGX_DECLINED;
1483}
Igor Sysoev84d17bb2008-12-22 12:02:05 +00001484
1485
1486ngx_int_t
1487ngx_http_arg(ngx_http_request_t *r, u_char *name, size_t len, ngx_str_t *value)
1488{
1489 u_char *p;
1490
1491 if (r->args.len == 0) {
1492 return NGX_DECLINED;
1493 }
1494
1495 for (p = r->args.data; *p && *p != ' '; p++) {
1496
1497 /*
1498 * although r->args.data is not null-terminated by itself,
1499 * however, there is null in the end of request line
1500 */
1501
1502 p = ngx_strcasestrn(p, (char *) name, len - 1);
1503
1504 if (p == NULL) {
1505 return NGX_DECLINED;
1506 }
1507
1508 if ((p == r->args.data || *(p - 1) == '&') && *(p + len) == '=') {
1509
1510 value->data = p + len + 1;
1511
1512 p = (u_char *) ngx_strchr(p, '&');
1513
1514 if (p == NULL) {
1515 p = r->args.data + r->args.len;
1516 }
1517
1518 value->len = p - value->data;
1519
1520 return NGX_OK;
1521 }
1522 }
1523
1524 return NGX_DECLINED;
1525}