blob: 027d9efe671d671b2f7a62a36ea87fe5f5e7c549 [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 Sysoev899b44e2005-05-12 14:58:06 +000012ngx_int_t
13ngx_http_parse_request_line(ngx_http_request_t *r, ngx_buf_t *b)
Igor Sysoev0c331d92002-08-15 17:20:26 +000014{
Igor Sysoev02f742b2005-04-08 15:18:55 +000015 u_char c, ch, *p, *m;
Igor Sysoev0c331d92002-08-15 17:20:26 +000016 enum {
Igor Sysoev016b8522002-08-29 16:59:54 +000017 sw_start = 0,
Igor Sysoeva3677242004-04-14 05:57:36 +000018 sw_method,
Igor Sysoev016b8522002-08-29 16:59:54 +000019 sw_space_after_method,
20 sw_spaces_before_uri,
Igor Sysoeva3677242004-04-14 05:57:36 +000021 sw_schema,
22 sw_schema_slash,
23 sw_schema_slash_slash,
24 sw_host,
25 sw_port,
Igor Sysoev016b8522002-08-29 16:59:54 +000026 sw_after_slash_in_uri,
27 sw_check_uri,
28 sw_uri,
29 sw_http_09,
Igor Sysoeva9830112003-05-19 16:39:14 +000030 sw_http_H,
31 sw_http_HT,
32 sw_http_HTT,
33 sw_http_HTTP,
Igor Sysoev016b8522002-08-29 16:59:54 +000034 sw_first_major_digit,
35 sw_major_digit,
36 sw_first_minor_digit,
37 sw_minor_digit,
Igor Sysoev02025fd2005-01-18 13:03:58 +000038 sw_almost_done
Igor Sysoev481b6432002-12-04 16:29:40 +000039 } state;
40
41 state = r->state;
Igor Sysoev0c331d92002-08-15 17:20:26 +000042
Igor Sysoev02025fd2005-01-18 13:03:58 +000043 for (p = b->pos; p < b->last; p++) {
44 ch = *p;
Igor Sysoev0c331d92002-08-15 17:20:26 +000045
Igor Sysoevd90282d2004-09-28 08:34:51 +000046 /* gcc 2.95.2 and msvc 6.0 compile this switch as an jump table */
Igor Sysoev0c331d92002-08-15 17:20:26 +000047
48 switch (state) {
49
50 /* HTTP methods: GET, HEAD, POST */
Igor Sysoev016b8522002-08-29 16:59:54 +000051 case sw_start:
Igor Sysoev02025fd2005-01-18 13:03:58 +000052 r->request_start = p;
Igor Sysoev3d062ad2003-03-05 06:37:42 +000053
Igor Sysoev732a2712004-04-21 18:54:33 +000054 if (ch == CR || ch == LF) {
55 break;
56 }
57
Igor Sysoeva3677242004-04-14 05:57:36 +000058 if (ch < 'A' || ch > 'Z') {
Igor Sysoev1af7c822002-09-13 14:47:42 +000059 return NGX_HTTP_PARSE_INVALID_METHOD;
Igor Sysoev0c331d92002-08-15 17:20:26 +000060 }
Igor Sysoeva3677242004-04-14 05:57:36 +000061
62 state = sw_method;
Igor Sysoeva9830112003-05-19 16:39:14 +000063 break;
Igor Sysoev0c331d92002-08-15 17:20:26 +000064
Igor Sysoeva3677242004-04-14 05:57:36 +000065 case sw_method:
66 if (ch == ' ') {
Igor Sysoev899b44e2005-05-12 14:58:06 +000067 r->method_end = p - 1;
Igor Sysoeva3677242004-04-14 05:57:36 +000068 m = r->request_start;
Igor Sysoeva9830112003-05-19 16:39:14 +000069
Igor Sysoev02025fd2005-01-18 13:03:58 +000070 if (p - m == 3) {
Igor Sysoeva9830112003-05-19 16:39:14 +000071
Igor Sysoev2e6ba932004-09-09 15:40:48 +000072 if (m[0] == 'G' && m[1] == 'E' && m[2] == 'T') {
Igor Sysoeva3677242004-04-14 05:57:36 +000073 r->method = NGX_HTTP_GET;
74 }
Igor Sysoeva9830112003-05-19 16:39:14 +000075
Igor Sysoev02025fd2005-01-18 13:03:58 +000076 } else if (p - m == 4) {
Igor Sysoeva9830112003-05-19 16:39:14 +000077
Igor Sysoev2e6ba932004-09-09 15:40:48 +000078 if (m[0] == 'P' && m[1] == 'O'
Igor Sysoev02025fd2005-01-18 13:03:58 +000079 && m[2] == 'S' && m[3] == 'T')
Igor Sysoeva3677242004-04-14 05:57:36 +000080 {
81 r->method = NGX_HTTP_POST;
Igor Sysoeva9830112003-05-19 16:39:14 +000082
Igor Sysoev2e6ba932004-09-09 15:40:48 +000083 } else if (m[0] == 'H' && m[1] == 'E'
84 && m[2] == 'A' && m[3] == 'D')
Igor Sysoeva3677242004-04-14 05:57:36 +000085 {
86 r->method = NGX_HTTP_HEAD;
87 }
88 }
Igor Sysoeva9830112003-05-19 16:39:14 +000089
Igor Sysoeva3677242004-04-14 05:57:36 +000090 state = sw_spaces_before_uri;
Igor Sysoeva9830112003-05-19 16:39:14 +000091 break;
Igor Sysoeva9830112003-05-19 16:39:14 +000092 }
Igor Sysoeva9830112003-05-19 16:39:14 +000093
Igor Sysoeva3677242004-04-14 05:57:36 +000094 if (ch < 'A' || ch > 'Z') {
Igor Sysoeva9830112003-05-19 16:39:14 +000095 return NGX_HTTP_PARSE_INVALID_METHOD;
96 }
Igor Sysoeva3677242004-04-14 05:57:36 +000097
Igor Sysoev0c331d92002-08-15 17:20:26 +000098 break;
99
100 /* single space after method */
Igor Sysoev016b8522002-08-29 16:59:54 +0000101 case sw_space_after_method:
Igor Sysoev0c331d92002-08-15 17:20:26 +0000102 switch (ch) {
103 case ' ':
Igor Sysoev016b8522002-08-29 16:59:54 +0000104 state = sw_spaces_before_uri;
Igor Sysoev0c331d92002-08-15 17:20:26 +0000105 break;
106 default:
Igor Sysoev1af7c822002-09-13 14:47:42 +0000107 return NGX_HTTP_PARSE_INVALID_METHOD;
Igor Sysoev0c331d92002-08-15 17:20:26 +0000108 }
109 break;
110
111 /* space* before URI */
Igor Sysoev016b8522002-08-29 16:59:54 +0000112 case sw_spaces_before_uri:
Igor Sysoev02f742b2005-04-08 15:18:55 +0000113
114 c = (u_char) (ch | 0x20);
115 if (c >= 'a' && c <= 'f') {
Igor Sysoev1ebfead2005-02-16 13:40:36 +0000116 r->schema_start = p;
117 state = sw_schema;
118 break;
119 }
120
Igor Sysoev0c331d92002-08-15 17:20:26 +0000121 switch (ch) {
122 case '/':
Igor Sysoev02025fd2005-01-18 13:03:58 +0000123 r->uri_start = p;
Igor Sysoev016b8522002-08-29 16:59:54 +0000124 state = sw_after_slash_in_uri;
Igor Sysoev0c331d92002-08-15 17:20:26 +0000125 break;
126 case ' ':
127 break;
128 default:
Igor Sysoeva3677242004-04-14 05:57:36 +0000129 return NGX_HTTP_PARSE_INVALID_REQUEST;
130 }
131 break;
132
133 case sw_schema:
Igor Sysoev02f742b2005-04-08 15:18:55 +0000134
135 c = (u_char) (ch | 0x20);
136 if (c >= 'a' && c <= 'f') {
Igor Sysoev1ebfead2005-02-16 13:40:36 +0000137 break;
138 }
139
Igor Sysoeva3677242004-04-14 05:57:36 +0000140 switch (ch) {
141 case ':':
Igor Sysoev02025fd2005-01-18 13:03:58 +0000142 r->schema_end = p;
Igor Sysoeva3677242004-04-14 05:57:36 +0000143 state = sw_schema_slash;
144 break;
145 default:
Igor Sysoeva3677242004-04-14 05:57:36 +0000146 return NGX_HTTP_PARSE_INVALID_REQUEST;
147 }
148 break;
149
150 case sw_schema_slash:
151 switch (ch) {
152 case '/':
153 state = sw_schema_slash_slash;
154 break;
155 default:
156 return NGX_HTTP_PARSE_INVALID_REQUEST;
157 }
158 break;
159
160 case sw_schema_slash_slash:
161 switch (ch) {
162 case '/':
Igor Sysoev02025fd2005-01-18 13:03:58 +0000163 r->host_start = p;
Igor Sysoeva3677242004-04-14 05:57:36 +0000164 state = sw_host;
165 break;
166 default:
167 return NGX_HTTP_PARSE_INVALID_REQUEST;
168 }
169 break;
170
171 case sw_host:
Igor Sysoev02f742b2005-04-08 15:18:55 +0000172
173 c = (u_char) (ch | 0x20);
174 if (c >= 'a' && c <= 'f') {
175 break;
176 }
177
178 if ((ch >= '0' && ch <= '9') || ch == '.' || ch == '-')
Igor Sysoev1ebfead2005-02-16 13:40:36 +0000179 {
180 break;
181 }
182
Igor Sysoeva3677242004-04-14 05:57:36 +0000183 switch (ch) {
184 case ':':
Igor Sysoev02025fd2005-01-18 13:03:58 +0000185 r->host_end = p;
Igor Sysoeva3677242004-04-14 05:57:36 +0000186 state = sw_port;
187 break;
188 case '/':
Igor Sysoev02025fd2005-01-18 13:03:58 +0000189 r->host_end = p;
190 r->uri_start = p;
Igor Sysoeva3677242004-04-14 05:57:36 +0000191 state = sw_after_slash_in_uri;
192 break;
193 default:
Igor Sysoeva3677242004-04-14 05:57:36 +0000194 return NGX_HTTP_PARSE_INVALID_REQUEST;
195 }
196 break;
197
198 case sw_port:
Igor Sysoev1ebfead2005-02-16 13:40:36 +0000199 if (ch >= '0' && ch <= '9') {
200 break;
201 }
202
Igor Sysoeva3677242004-04-14 05:57:36 +0000203 switch (ch) {
204 case '/':
Igor Sysoev02025fd2005-01-18 13:03:58 +0000205 r->port_end = p;
206 r->uri_start = p;
Igor Sysoeva3677242004-04-14 05:57:36 +0000207 state = sw_after_slash_in_uri;
208 break;
209 default:
Igor Sysoev1ebfead2005-02-16 13:40:36 +0000210 return NGX_HTTP_PARSE_INVALID_REQUEST;
Igor Sysoev0c331d92002-08-15 17:20:26 +0000211 }
212 break;
213
Igor Sysoev1b735832004-11-11 14:07:14 +0000214 /* check "/.", "//", "%", and "\" (Win32) in URI */
Igor Sysoev016b8522002-08-29 16:59:54 +0000215 case sw_after_slash_in_uri:
Igor Sysoev1ebfead2005-02-16 13:40:36 +0000216
Igor Sysoev02f742b2005-04-08 15:18:55 +0000217 c = (u_char) (ch | 0x20);
218 if (c >= 'a' && c <= 'f') {
219 state = sw_check_uri;
220 break;
221 }
222
223 if (ch >= '0' && ch <= '9') {
Igor Sysoev1ebfead2005-02-16 13:40:36 +0000224 state = sw_check_uri;
225 break;
226 }
227
Igor Sysoev0c331d92002-08-15 17:20:26 +0000228 switch (ch) {
Igor Sysoev1ebfead2005-02-16 13:40:36 +0000229 case ' ':
230 r->uri_end = p;
231 state = sw_http_09;
232 break;
Igor Sysoev0c331d92002-08-15 17:20:26 +0000233 case CR:
Igor Sysoev02025fd2005-01-18 13:03:58 +0000234 r->uri_end = p;
Igor Sysoev0c331d92002-08-15 17:20:26 +0000235 r->http_minor = 9;
Igor Sysoev016b8522002-08-29 16:59:54 +0000236 state = sw_almost_done;
Igor Sysoev0c331d92002-08-15 17:20:26 +0000237 break;
238 case LF:
Igor Sysoev02025fd2005-01-18 13:03:58 +0000239 r->uri_end = p;
Igor Sysoev0c331d92002-08-15 17:20:26 +0000240 r->http_minor = 9;
Igor Sysoev02025fd2005-01-18 13:03:58 +0000241 goto done;
Igor Sysoev0c331d92002-08-15 17:20:26 +0000242 case '.':
243 r->complex_uri = 1;
Igor Sysoev016b8522002-08-29 16:59:54 +0000244 state = sw_uri;
Igor Sysoev0c331d92002-08-15 17:20:26 +0000245 break;
Igor Sysoev924bd792004-10-11 15:07:03 +0000246 case '%':
247 r->quoted_uri = 1;
248 state = sw_uri;
249 break;
Igor Sysoev1ebfead2005-02-16 13:40:36 +0000250 case '/':
251 r->complex_uri = 1;
252 state = sw_uri;
253 break;
Igor Sysoev1b735832004-11-11 14:07:14 +0000254#if (NGX_WIN32)
255 case '\\':
256 r->complex_uri = 1;
Igor Sysoev1ebfead2005-02-16 13:40:36 +0000257 state = sw_uri;
Igor Sysoev1b735832004-11-11 14:07:14 +0000258 break;
259#endif
Igor Sysoev1ebfead2005-02-16 13:40:36 +0000260 case '?':
261 r->args_start = p + 1;
262 state = sw_uri;
Igor Sysoev0c331d92002-08-15 17:20:26 +0000263 break;
Igor Sysoev805d9db2005-02-03 19:33:37 +0000264 case '+':
265 r->plus_in_uri = 1;
266 break;
Igor Sysoev1ebfead2005-02-16 13:40:36 +0000267 case '\0':
268 r->zero_in_uri = 1;
Igor Sysoev0c331d92002-08-15 17:20:26 +0000269 break;
270 default:
Igor Sysoev016b8522002-08-29 16:59:54 +0000271 state = sw_check_uri;
Igor Sysoev0c331d92002-08-15 17:20:26 +0000272 break;
273 }
274 break;
275
Igor Sysoev1b735832004-11-11 14:07:14 +0000276 /* check "/", "%" and "\" (Win32) in URI */
Igor Sysoev016b8522002-08-29 16:59:54 +0000277 case sw_check_uri:
Igor Sysoev1ebfead2005-02-16 13:40:36 +0000278
Igor Sysoev02f742b2005-04-08 15:18:55 +0000279 c = (u_char) (ch | 0x20);
280 if (c >= 'a' && c <= 'f') {
281 break;
282 }
283
284 if (ch >= '0' && ch <= '9') {
Igor Sysoev1ebfead2005-02-16 13:40:36 +0000285 break;
286 }
287
Igor Sysoev0c331d92002-08-15 17:20:26 +0000288 switch (ch) {
Igor Sysoev1ebfead2005-02-16 13:40:36 +0000289 case '/':
290 r->uri_ext = NULL;
291 state = sw_after_slash_in_uri;
292 break;
293 case '.':
294 r->uri_ext = p + 1;
295 break;
296 case ' ':
297 r->uri_end = p;
298 state = sw_http_09;
299 break;
Igor Sysoev0c331d92002-08-15 17:20:26 +0000300 case CR:
Igor Sysoev02025fd2005-01-18 13:03:58 +0000301 r->uri_end = p;
Igor Sysoev0c331d92002-08-15 17:20:26 +0000302 r->http_minor = 9;
Igor Sysoev016b8522002-08-29 16:59:54 +0000303 state = sw_almost_done;
Igor Sysoev0c331d92002-08-15 17:20:26 +0000304 break;
305 case LF:
Igor Sysoev02025fd2005-01-18 13:03:58 +0000306 r->uri_end = p;
Igor Sysoev0c331d92002-08-15 17:20:26 +0000307 r->http_minor = 9;
Igor Sysoev02025fd2005-01-18 13:03:58 +0000308 goto done;
Igor Sysoev1b735832004-11-11 14:07:14 +0000309#if (NGX_WIN32)
310 case '\\':
311 r->complex_uri = 1;
312 state = sw_after_slash_in_uri;
313 break;
314#endif
Igor Sysoev7578ec92003-06-02 15:24:30 +0000315 case '%':
Igor Sysoev924bd792004-10-11 15:07:03 +0000316 r->quoted_uri = 1;
Igor Sysoev7578ec92003-06-02 15:24:30 +0000317 state = sw_uri;
318 break;
Igor Sysoev1ebfead2005-02-16 13:40:36 +0000319 case '+':
320 r->plus_in_uri = 1;
321 break;
Igor Sysoev0c331d92002-08-15 17:20:26 +0000322 case '?':
Igor Sysoev02025fd2005-01-18 13:03:58 +0000323 r->args_start = p + 1;
Igor Sysoev016b8522002-08-29 16:59:54 +0000324 state = sw_uri;
Igor Sysoev0c331d92002-08-15 17:20:26 +0000325 break;
Igor Sysoev1ebfead2005-02-16 13:40:36 +0000326 case '\0':
327 r->zero_in_uri = 1;
328 break;
Igor Sysoev0c331d92002-08-15 17:20:26 +0000329 }
330 break;
331
332 /* URI */
Igor Sysoev016b8522002-08-29 16:59:54 +0000333 case sw_uri:
Igor Sysoev0c331d92002-08-15 17:20:26 +0000334 switch (ch) {
Igor Sysoev1ebfead2005-02-16 13:40:36 +0000335 case ' ':
336 r->uri_end = p;
337 state = sw_http_09;
338 break;
Igor Sysoev0c331d92002-08-15 17:20:26 +0000339 case CR:
Igor Sysoev02025fd2005-01-18 13:03:58 +0000340 r->uri_end = p;
Igor Sysoev0c331d92002-08-15 17:20:26 +0000341 r->http_minor = 9;
Igor Sysoev016b8522002-08-29 16:59:54 +0000342 state = sw_almost_done;
Igor Sysoev0c331d92002-08-15 17:20:26 +0000343 break;
344 case LF:
Igor Sysoev02025fd2005-01-18 13:03:58 +0000345 r->uri_end = p;
Igor Sysoev0c331d92002-08-15 17:20:26 +0000346 r->http_minor = 9;
Igor Sysoev02025fd2005-01-18 13:03:58 +0000347 goto done;
Igor Sysoev805d9db2005-02-03 19:33:37 +0000348 case '+':
349 r->plus_in_uri = 1;
350 break;
Igor Sysoev1ebfead2005-02-16 13:40:36 +0000351 case '\0':
352 r->zero_in_uri = 1;
Igor Sysoev0c331d92002-08-15 17:20:26 +0000353 break;
354 }
355 break;
356
357 /* space+ after URI */
Igor Sysoev016b8522002-08-29 16:59:54 +0000358 case sw_http_09:
Igor Sysoev0c331d92002-08-15 17:20:26 +0000359 switch (ch) {
360 case ' ':
361 break;
362 case CR:
363 r->http_minor = 9;
Igor Sysoev016b8522002-08-29 16:59:54 +0000364 state = sw_almost_done;
Igor Sysoev0c331d92002-08-15 17:20:26 +0000365 break;
366 case LF:
367 r->http_minor = 9;
Igor Sysoev02025fd2005-01-18 13:03:58 +0000368 goto done;
Igor Sysoev0c331d92002-08-15 17:20:26 +0000369 case 'H':
Igor Sysoev02025fd2005-01-18 13:03:58 +0000370 r->http_protocol.data = p;
Igor Sysoeva9830112003-05-19 16:39:14 +0000371 state = sw_http_H;
Igor Sysoev0c331d92002-08-15 17:20:26 +0000372 break;
373 default:
Igor Sysoev1af7c822002-09-13 14:47:42 +0000374 return NGX_HTTP_PARSE_INVALID_REQUEST;
Igor Sysoev0c331d92002-08-15 17:20:26 +0000375 }
376 break;
377
Igor Sysoeva9830112003-05-19 16:39:14 +0000378 case sw_http_H:
379 switch (ch) {
380 case 'T':
381 state = sw_http_HT;
382 break;
383 default:
Igor Sysoev1af7c822002-09-13 14:47:42 +0000384 return NGX_HTTP_PARSE_INVALID_REQUEST;
Igor Sysoev4e9393a2003-01-09 05:36:00 +0000385 }
Igor Sysoeva9830112003-05-19 16:39:14 +0000386 break;
Igor Sysoev0c331d92002-08-15 17:20:26 +0000387
Igor Sysoeva9830112003-05-19 16:39:14 +0000388 case sw_http_HT:
389 switch (ch) {
390 case 'T':
391 state = sw_http_HTT;
392 break;
393 default:
394 return NGX_HTTP_PARSE_INVALID_REQUEST;
395 }
396 break;
397
398 case sw_http_HTT:
399 switch (ch) {
400 case 'P':
401 state = sw_http_HTTP;
402 break;
403 default:
404 return NGX_HTTP_PARSE_INVALID_REQUEST;
405 }
406 break;
407
408 case sw_http_HTTP:
409 switch (ch) {
410 case '/':
411 state = sw_first_major_digit;
412 break;
413 default:
414 return NGX_HTTP_PARSE_INVALID_REQUEST;
415 }
Igor Sysoev0c331d92002-08-15 17:20:26 +0000416 break;
417
418 /* first digit of major HTTP version */
Igor Sysoev016b8522002-08-29 16:59:54 +0000419 case sw_first_major_digit:
Igor Sysoev4e9393a2003-01-09 05:36:00 +0000420 if (ch < '1' || ch > '9') {
Igor Sysoev1af7c822002-09-13 14:47:42 +0000421 return NGX_HTTP_PARSE_INVALID_REQUEST;
Igor Sysoev4e9393a2003-01-09 05:36:00 +0000422 }
Igor Sysoev0c331d92002-08-15 17:20:26 +0000423
424 r->http_major = ch - '0';
Igor Sysoev016b8522002-08-29 16:59:54 +0000425 state = sw_major_digit;
Igor Sysoev0c331d92002-08-15 17:20:26 +0000426 break;
427
428 /* major HTTP version or dot */
Igor Sysoev016b8522002-08-29 16:59:54 +0000429 case sw_major_digit:
Igor Sysoev0c331d92002-08-15 17:20:26 +0000430 if (ch == '.') {
Igor Sysoev016b8522002-08-29 16:59:54 +0000431 state = sw_first_minor_digit;
Igor Sysoev0c331d92002-08-15 17:20:26 +0000432 break;
433 }
434
Igor Sysoev4e9393a2003-01-09 05:36:00 +0000435 if (ch < '0' || ch > '9') {
Igor Sysoev1af7c822002-09-13 14:47:42 +0000436 return NGX_HTTP_PARSE_INVALID_REQUEST;
Igor Sysoev4e9393a2003-01-09 05:36:00 +0000437 }
Igor Sysoev0c331d92002-08-15 17:20:26 +0000438
439 r->http_major = r->http_major * 10 + ch - '0';
440 break;
441
442 /* first digit of minor HTTP version */
Igor Sysoev016b8522002-08-29 16:59:54 +0000443 case sw_first_minor_digit:
Igor Sysoev4e9393a2003-01-09 05:36:00 +0000444 if (ch < '0' || ch > '9') {
Igor Sysoev1af7c822002-09-13 14:47:42 +0000445 return NGX_HTTP_PARSE_INVALID_REQUEST;
Igor Sysoev4e9393a2003-01-09 05:36:00 +0000446 }
Igor Sysoev0c331d92002-08-15 17:20:26 +0000447
448 r->http_minor = ch - '0';
Igor Sysoev016b8522002-08-29 16:59:54 +0000449 state = sw_minor_digit;
Igor Sysoev0c331d92002-08-15 17:20:26 +0000450 break;
451
452 /* minor HTTP version or end of request line */
Igor Sysoev016b8522002-08-29 16:59:54 +0000453 case sw_minor_digit:
Igor Sysoev0c331d92002-08-15 17:20:26 +0000454 if (ch == CR) {
Igor Sysoev016b8522002-08-29 16:59:54 +0000455 state = sw_almost_done;
Igor Sysoev0c331d92002-08-15 17:20:26 +0000456 break;
457 }
458
459 if (ch == LF) {
Igor Sysoev02025fd2005-01-18 13:03:58 +0000460 goto done;
Igor Sysoev0c331d92002-08-15 17:20:26 +0000461 }
462
Igor Sysoev4e9393a2003-01-09 05:36:00 +0000463 if (ch < '0' || ch > '9') {
Igor Sysoev1af7c822002-09-13 14:47:42 +0000464 return NGX_HTTP_PARSE_INVALID_REQUEST;
Igor Sysoev4e9393a2003-01-09 05:36:00 +0000465 }
Igor Sysoev0c331d92002-08-15 17:20:26 +0000466
467 r->http_minor = r->http_minor * 10 + ch - '0';
468 break;
469
470 /* end of request line */
Igor Sysoev016b8522002-08-29 16:59:54 +0000471 case sw_almost_done:
Igor Sysoev02025fd2005-01-18 13:03:58 +0000472 r->request_end = p - 1;
Igor Sysoev0c331d92002-08-15 17:20:26 +0000473 switch (ch) {
474 case LF:
Igor Sysoev02025fd2005-01-18 13:03:58 +0000475 goto done;
Igor Sysoev0c331d92002-08-15 17:20:26 +0000476 default:
Igor Sysoev1af7c822002-09-13 14:47:42 +0000477 return NGX_HTTP_PARSE_INVALID_REQUEST;
Igor Sysoev0c331d92002-08-15 17:20:26 +0000478 }
Igor Sysoev0c331d92002-08-15 17:20:26 +0000479 }
480 }
481
Igor Sysoevdd888c42004-09-21 05:38:28 +0000482 b->pos = p;
Igor Sysoev02025fd2005-01-18 13:03:58 +0000483 r->state = state;
Igor Sysoev0c331d92002-08-15 17:20:26 +0000484
Igor Sysoev02025fd2005-01-18 13:03:58 +0000485 return NGX_AGAIN;
Igor Sysoev4e9393a2003-01-09 05:36:00 +0000486
Igor Sysoev02025fd2005-01-18 13:03:58 +0000487done:
Igor Sysoev4e9393a2003-01-09 05:36:00 +0000488
Igor Sysoev02025fd2005-01-18 13:03:58 +0000489 b->pos = p + 1;
Igor Sysoev4e9393a2003-01-09 05:36:00 +0000490
Igor Sysoev02025fd2005-01-18 13:03:58 +0000491 if (r->request_end == NULL) {
492 r->request_end = p;
Igor Sysoev0c331d92002-08-15 17:20:26 +0000493 }
Igor Sysoev02025fd2005-01-18 13:03:58 +0000494
495 r->http_version = r->http_major * 1000 + r->http_minor;
496 r->state = sw_start;
497
498 if (r->http_version == 9 && r->method != NGX_HTTP_GET) {
499 return NGX_HTTP_PARSE_INVALID_09_METHOD;
500 }
501
502 return NGX_OK;
Igor Sysoev0c331d92002-08-15 17:20:26 +0000503}
504
Igor Sysoevc2bba092003-11-28 17:41:47 +0000505
Igor Sysoev899b44e2005-05-12 14:58:06 +0000506ngx_int_t
507ngx_http_parse_header_line(ngx_http_request_t *r, ngx_buf_t *b)
Igor Sysoev0c331d92002-08-15 17:20:26 +0000508{
Igor Sysoev02f742b2005-04-08 15:18:55 +0000509 u_char c, ch, *p;
510 ngx_uint_t hash;
Igor Sysoevc2bba092003-11-28 17:41:47 +0000511 enum {
Igor Sysoev016b8522002-08-29 16:59:54 +0000512 sw_start = 0,
513 sw_name,
514 sw_space_before_value,
515 sw_value,
516 sw_space_after_value,
Igor Sysoev4d656dc2005-03-22 16:02:46 +0000517 sw_ignore_line,
Igor Sysoev016b8522002-08-29 16:59:54 +0000518 sw_almost_done,
Igor Sysoev4d656dc2005-03-22 16:02:46 +0000519 sw_header_almost_done
Igor Sysoev481b6432002-12-04 16:29:40 +0000520 } state;
521
522 state = r->state;
Igor Sysoev02f742b2005-04-08 15:18:55 +0000523 hash = r->header_hash;
Igor Sysoev0c331d92002-08-15 17:20:26 +0000524
Igor Sysoev02025fd2005-01-18 13:03:58 +0000525 for (p = b->pos; p < b->last; p++) {
526 ch = *p;
Igor Sysoev0c331d92002-08-15 17:20:26 +0000527
Igor Sysoev0c331d92002-08-15 17:20:26 +0000528 switch (state) {
529
530 /* first char */
Igor Sysoev016b8522002-08-29 16:59:54 +0000531 case sw_start:
Igor Sysoev3362b8d2005-05-14 18:42:03 +0000532 r->invalid_header = 0;
533
Igor Sysoev0c331d92002-08-15 17:20:26 +0000534 switch (ch) {
535 case CR:
Igor Sysoev02025fd2005-01-18 13:03:58 +0000536 r->header_end = p;
Igor Sysoev016b8522002-08-29 16:59:54 +0000537 state = sw_header_almost_done;
Igor Sysoev0c331d92002-08-15 17:20:26 +0000538 break;
539 case LF:
Igor Sysoev02025fd2005-01-18 13:03:58 +0000540 r->header_end = p;
541 goto header_done;
Igor Sysoev0c331d92002-08-15 17:20:26 +0000542 default:
Igor Sysoev016b8522002-08-29 16:59:54 +0000543 state = sw_name;
Igor Sysoev02025fd2005-01-18 13:03:58 +0000544 r->header_name_start = p;
Igor Sysoev0c331d92002-08-15 17:20:26 +0000545
Igor Sysoev9c610952004-03-16 13:35:20 +0000546 c = (u_char) (ch | 0x20);
Igor Sysoev4e9393a2003-01-09 05:36:00 +0000547 if (c >= 'a' && c <= 'z') {
Igor Sysoev02f742b2005-04-08 15:18:55 +0000548 hash = c;
Igor Sysoev0c331d92002-08-15 17:20:26 +0000549 break;
Igor Sysoev4e9393a2003-01-09 05:36:00 +0000550 }
Igor Sysoev0c331d92002-08-15 17:20:26 +0000551
Igor Sysoev4e9393a2003-01-09 05:36:00 +0000552 if (ch >= '0' && ch <= '9') {
Igor Sysoev02f742b2005-04-08 15:18:55 +0000553 hash = ch;
Igor Sysoev0c331d92002-08-15 17:20:26 +0000554 break;
Igor Sysoev4e9393a2003-01-09 05:36:00 +0000555 }
Igor Sysoev0c331d92002-08-15 17:20:26 +0000556
Igor Sysoev3362b8d2005-05-14 18:42:03 +0000557 r->invalid_header = 1;
558
Igor Sysoev4d656dc2005-03-22 16:02:46 +0000559 break;
Igor Sysoev0c331d92002-08-15 17:20:26 +0000560
561 }
562 break;
563
564 /* header name */
Igor Sysoev016b8522002-08-29 16:59:54 +0000565 case sw_name:
Igor Sysoev10a543a2004-03-16 07:10:12 +0000566 c = (u_char) (ch | 0x20);
Igor Sysoev4e9393a2003-01-09 05:36:00 +0000567 if (c >= 'a' && c <= 'z') {
Igor Sysoev02f742b2005-04-08 15:18:55 +0000568 hash += c;
Igor Sysoev0c331d92002-08-15 17:20:26 +0000569 break;
Igor Sysoev4e9393a2003-01-09 05:36:00 +0000570 }
Igor Sysoev0c331d92002-08-15 17:20:26 +0000571
572 if (ch == ':') {
Igor Sysoev02025fd2005-01-18 13:03:58 +0000573 r->header_name_end = p;
Igor Sysoev016b8522002-08-29 16:59:54 +0000574 state = sw_space_before_value;
Igor Sysoev0c331d92002-08-15 17:20:26 +0000575 break;
576 }
577
Igor Sysoev4d656dc2005-03-22 16:02:46 +0000578 if (ch == '-') {
Igor Sysoev02f742b2005-04-08 15:18:55 +0000579 hash += ch;
Igor Sysoev0c331d92002-08-15 17:20:26 +0000580 break;
Igor Sysoev4e9393a2003-01-09 05:36:00 +0000581 }
Igor Sysoev0c331d92002-08-15 17:20:26 +0000582
Igor Sysoev4e9393a2003-01-09 05:36:00 +0000583 if (ch >= '0' && ch <= '9') {
Igor Sysoev02f742b2005-04-08 15:18:55 +0000584 hash += ch;
Igor Sysoev0c331d92002-08-15 17:20:26 +0000585 break;
Igor Sysoev4e9393a2003-01-09 05:36:00 +0000586 }
Igor Sysoev0c331d92002-08-15 17:20:26 +0000587
Igor Sysoev899b44e2005-05-12 14:58:06 +0000588 if (ch == CR) {
589 r->header_name_end = p;
590 r->header_start = p;
591 r->header_end = p;
592 state = sw_almost_done;
593 break;
594 }
595
596 if (ch == LF) {
597 r->header_name_end = p;
598 r->header_start = p;
599 r->header_end = p;
600 goto done;
601 }
602
Igor Sysoev924bd792004-10-11 15:07:03 +0000603 /* IIS may send the duplicate "HTTP/1.1 ..." lines */
Igor Sysoev183f9a62003-04-09 15:42:08 +0000604 if (ch == '/'
Igor Sysoev899b44e2005-05-12 14:58:06 +0000605 && r->upstream
606 && p - r->header_name_start == 4
607 && ngx_strncmp(r->header_name_start, "HTTP", 4) == 0)
Igor Sysoev183f9a62003-04-09 15:42:08 +0000608 {
609 state = sw_ignore_line;
610 break;
Igor Sysoeve2a31542003-04-08 15:40:10 +0000611 }
612
Igor Sysoev3362b8d2005-05-14 18:42:03 +0000613 r->invalid_header = 1;
614
Igor Sysoev4d656dc2005-03-22 16:02:46 +0000615 break;
Igor Sysoev0c331d92002-08-15 17:20:26 +0000616
617 /* space* before header value */
Igor Sysoev016b8522002-08-29 16:59:54 +0000618 case sw_space_before_value:
Igor Sysoev0c331d92002-08-15 17:20:26 +0000619 switch (ch) {
620 case ' ':
621 break;
622 case CR:
Igor Sysoev899b44e2005-05-12 14:58:06 +0000623 r->header_start = p;
624 r->header_end = p;
Igor Sysoev016b8522002-08-29 16:59:54 +0000625 state = sw_almost_done;
Igor Sysoev0c331d92002-08-15 17:20:26 +0000626 break;
627 case LF:
Igor Sysoev899b44e2005-05-12 14:58:06 +0000628 r->header_start = p;
629 r->header_end = p;
Igor Sysoev02025fd2005-01-18 13:03:58 +0000630 goto done;
Igor Sysoev0c331d92002-08-15 17:20:26 +0000631 default:
Igor Sysoev02025fd2005-01-18 13:03:58 +0000632 r->header_start = p;
Igor Sysoev016b8522002-08-29 16:59:54 +0000633 state = sw_value;
Igor Sysoev0c331d92002-08-15 17:20:26 +0000634 break;
635 }
636 break;
637
638 /* header value */
Igor Sysoev016b8522002-08-29 16:59:54 +0000639 case sw_value:
Igor Sysoev0c331d92002-08-15 17:20:26 +0000640 switch (ch) {
641 case ' ':
Igor Sysoev02025fd2005-01-18 13:03:58 +0000642 r->header_end = p;
Igor Sysoev016b8522002-08-29 16:59:54 +0000643 state = sw_space_after_value;
Igor Sysoev0c331d92002-08-15 17:20:26 +0000644 break;
645 case CR:
Igor Sysoev02025fd2005-01-18 13:03:58 +0000646 r->header_end = p;
Igor Sysoev016b8522002-08-29 16:59:54 +0000647 state = sw_almost_done;
Igor Sysoev0c331d92002-08-15 17:20:26 +0000648 break;
649 case LF:
Igor Sysoev02025fd2005-01-18 13:03:58 +0000650 r->header_end = p;
651 goto done;
Igor Sysoev0c331d92002-08-15 17:20:26 +0000652 }
653 break;
654
655 /* space* before end of header line */
Igor Sysoev016b8522002-08-29 16:59:54 +0000656 case sw_space_after_value:
Igor Sysoev0c331d92002-08-15 17:20:26 +0000657 switch (ch) {
658 case ' ':
659 break;
660 case CR:
Igor Sysoev016b8522002-08-29 16:59:54 +0000661 state = sw_almost_done;
Igor Sysoev0c331d92002-08-15 17:20:26 +0000662 break;
663 case LF:
Igor Sysoev02025fd2005-01-18 13:03:58 +0000664 goto done;
Igor Sysoev0c331d92002-08-15 17:20:26 +0000665 default:
Igor Sysoev016b8522002-08-29 16:59:54 +0000666 state = sw_value;
Igor Sysoev0c331d92002-08-15 17:20:26 +0000667 break;
668 }
669 break;
670
Igor Sysoeve2a31542003-04-08 15:40:10 +0000671 /* ignore header line */
672 case sw_ignore_line:
673 switch (ch) {
674 case LF:
675 state = sw_start;
676 break;
677 default:
678 break;
679 }
680 break;
681
Igor Sysoev0c331d92002-08-15 17:20:26 +0000682 /* end of header line */
Igor Sysoev016b8522002-08-29 16:59:54 +0000683 case sw_almost_done:
Igor Sysoev0c331d92002-08-15 17:20:26 +0000684 switch (ch) {
685 case LF:
Igor Sysoev02025fd2005-01-18 13:03:58 +0000686 goto done;
Igor Sysoev0c331d92002-08-15 17:20:26 +0000687 default:
Igor Sysoev1af7c822002-09-13 14:47:42 +0000688 return NGX_HTTP_PARSE_INVALID_HEADER;
Igor Sysoev0c331d92002-08-15 17:20:26 +0000689 }
Igor Sysoev0c331d92002-08-15 17:20:26 +0000690
691 /* end of header */
Igor Sysoev016b8522002-08-29 16:59:54 +0000692 case sw_header_almost_done:
Igor Sysoev0c331d92002-08-15 17:20:26 +0000693 switch (ch) {
694 case LF:
Igor Sysoev02025fd2005-01-18 13:03:58 +0000695 goto header_done;
Igor Sysoev0c331d92002-08-15 17:20:26 +0000696 default:
Igor Sysoev1af7c822002-09-13 14:47:42 +0000697 return NGX_HTTP_PARSE_INVALID_HEADER;
Igor Sysoev0c331d92002-08-15 17:20:26 +0000698 }
Igor Sysoev0c331d92002-08-15 17:20:26 +0000699 }
700 }
701
Igor Sysoev369145c2004-05-28 15:49:23 +0000702 b->pos = p;
Igor Sysoev02025fd2005-01-18 13:03:58 +0000703 r->state = state;
Igor Sysoev02f742b2005-04-08 15:18:55 +0000704 r->header_hash = hash;
Igor Sysoev0c331d92002-08-15 17:20:26 +0000705
Igor Sysoev02025fd2005-01-18 13:03:58 +0000706 return NGX_AGAIN;
Igor Sysoev4e9393a2003-01-09 05:36:00 +0000707
Igor Sysoev02025fd2005-01-18 13:03:58 +0000708done:
Igor Sysoev4e9393a2003-01-09 05:36:00 +0000709
Igor Sysoev02025fd2005-01-18 13:03:58 +0000710 b->pos = p + 1;
711 r->state = sw_start;
Igor Sysoev02f742b2005-04-08 15:18:55 +0000712 r->header_hash = hash;
Igor Sysoev02025fd2005-01-18 13:03:58 +0000713
714 return NGX_OK;
715
716header_done:
717
718 b->pos = p + 1;
719 r->state = sw_start;
720
721 return NGX_HTTP_PARSE_HEADER_DONE;
Igor Sysoev0c331d92002-08-15 17:20:26 +0000722}
Igor Sysoevc2bba092003-11-28 17:41:47 +0000723
724
Igor Sysoev899b44e2005-05-12 14:58:06 +0000725ngx_int_t
726ngx_http_parse_complex_uri(ngx_http_request_t *r)
Igor Sysoevc2bba092003-11-28 17:41:47 +0000727{
Igor Sysoev10a543a2004-03-16 07:10:12 +0000728 u_char c, ch, decoded, *p, *u;
Igor Sysoevc2bba092003-11-28 17:41:47 +0000729 enum {
730 sw_usual = 0,
731 sw_slash,
732 sw_dot,
733 sw_dot_dot,
Igor Sysoev1b735832004-11-11 14:07:14 +0000734#if (NGX_WIN32)
Igor Sysoevc2bba092003-11-28 17:41:47 +0000735 sw_dot_dot_dot,
736#endif
737 sw_quoted,
738 sw_quoted_second
739 } state, quoted_state;
740
Igor Sysoev02025fd2005-01-18 13:03:58 +0000741#if (NGX_SUPPRESS_WARN)
Igor Sysoevc2bba092003-11-28 17:41:47 +0000742 decoded = '\0';
743 quoted_state = sw_usual;
Igor Sysoev02025fd2005-01-18 13:03:58 +0000744#endif
Igor Sysoevc2bba092003-11-28 17:41:47 +0000745
746 state = sw_usual;
747 p = r->uri_start;
748 u = r->uri.data;
Igor Sysoev865c1502003-11-30 20:03:18 +0000749 r->uri_ext = NULL;
Igor Sysoev1b735832004-11-11 14:07:14 +0000750 r->args_start = NULL;
Igor Sysoevc2bba092003-11-28 17:41:47 +0000751
752 ch = *p++;
753
Igor Sysoev02025fd2005-01-18 13:03:58 +0000754 while (p <= r->uri_end) {
Igor Sysoev1b735832004-11-11 14:07:14 +0000755
756 /*
Igor Sysoev02025fd2005-01-18 13:03:58 +0000757 * we use "ch = *p++" inside the cycle, but this operation is safe,
Igor Sysoev1b735832004-11-11 14:07:14 +0000758 * because after the URI there is always at least one charcter:
759 * the line feed
760 */
Igor Sysoevc2bba092003-11-28 17:41:47 +0000761
Igor Sysoev54498db2004-02-11 17:08:49 +0000762 ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
Igor Sysoev1b735832004-11-11 14:07:14 +0000763 "s:%d in:'%Xd:%c', out:'%c'", state, ch, ch, *u);
Igor Sysoevc2bba092003-11-28 17:41:47 +0000764
765 switch (state) {
766 case sw_usual:
767 switch(ch) {
Igor Sysoev1b735832004-11-11 14:07:14 +0000768#if (NGX_WIN32)
769 case '\\':
770 r->uri_ext = NULL;
771
772 if (p == r->uri_start + r->uri.len) {
773
774 /*
775 * we omit the last "\" to cause redirect because
776 * the browsers do not treat "\" as "/" in relative URL path
777 */
778
779 break;
780 }
781
782 state = sw_slash;
783 *u++ = '/';
784 break;
785#endif
Igor Sysoevc2bba092003-11-28 17:41:47 +0000786 case '/':
Igor Sysoev865c1502003-11-30 20:03:18 +0000787 r->uri_ext = NULL;
Igor Sysoevc2bba092003-11-28 17:41:47 +0000788 state = sw_slash;
789 *u++ = ch;
790 break;
791 case '%':
792 quoted_state = state;
793 state = sw_quoted;
794 break;
Igor Sysoev1b735832004-11-11 14:07:14 +0000795 case '?':
796 r->args_start = p;
Igor Sysoev02025fd2005-01-18 13:03:58 +0000797 goto done;
Igor Sysoev865c1502003-11-30 20:03:18 +0000798 case '.':
799 r->uri_ext = u + 1;
Igor Sysoev42b12b32004-12-02 18:40:46 +0000800 *u++ = ch;
801 break;
Igor Sysoevc2bba092003-11-28 17:41:47 +0000802 default:
803 *u++ = ch;
804 break;
805 }
806 ch = *p++;
807 break;
808
809 case sw_slash:
810 switch(ch) {
Igor Sysoev1b735832004-11-11 14:07:14 +0000811#if (NGX_WIN32)
812 case '\\':
813 break;
814#endif
Igor Sysoevc2bba092003-11-28 17:41:47 +0000815 case '/':
816 break;
817 case '.':
818 state = sw_dot;
819 *u++ = ch;
820 break;
821 case '%':
822 quoted_state = state;
823 state = sw_quoted;
824 break;
Igor Sysoev02025fd2005-01-18 13:03:58 +0000825 case '?':
826 r->args_start = p;
827 goto done;
Igor Sysoevc2bba092003-11-28 17:41:47 +0000828 default:
829 state = sw_usual;
830 *u++ = ch;
831 break;
832 }
833 ch = *p++;
834 break;
835
836 case sw_dot:
837 switch(ch) {
Igor Sysoev1b735832004-11-11 14:07:14 +0000838#if (NGX_WIN32)
839 case '\\':
840 /* fall through */
841#endif
Igor Sysoevc2bba092003-11-28 17:41:47 +0000842 case '/':
843 state = sw_slash;
844 u--;
845 break;
846 case '.':
847 state = sw_dot_dot;
848 *u++ = ch;
849 break;
850 case '%':
851 quoted_state = state;
852 state = sw_quoted;
853 break;
Igor Sysoev02025fd2005-01-18 13:03:58 +0000854 case '?':
855 r->args_start = p;
856 goto done;
Igor Sysoevc2bba092003-11-28 17:41:47 +0000857 default:
858 state = sw_usual;
859 *u++ = ch;
860 break;
861 }
862 ch = *p++;
863 break;
864
865 case sw_dot_dot:
866 switch(ch) {
Igor Sysoev1b735832004-11-11 14:07:14 +0000867#if (NGX_WIN32)
868 case '\\':
869 /* fall through */
870#endif
Igor Sysoevc2bba092003-11-28 17:41:47 +0000871 case '/':
872 state = sw_slash;
873 u -= 4;
874 if (u < r->uri.data) {
875 return NGX_HTTP_PARSE_INVALID_REQUEST;
876 }
877 while (*(u - 1) != '/') {
878 u--;
879 }
880 break;
881 case '%':
882 quoted_state = state;
883 state = sw_quoted;
884 break;
Igor Sysoev02025fd2005-01-18 13:03:58 +0000885 case '?':
886 r->args_start = p;
887 goto done;
Igor Sysoev1b735832004-11-11 14:07:14 +0000888#if (NGX_WIN32)
Igor Sysoevc2bba092003-11-28 17:41:47 +0000889 case '.':
890 state = sw_dot_dot_dot;
891 *u++ = ch;
892 break;
893#endif
894 default:
895 state = sw_usual;
896 *u++ = ch;
897 break;
898 }
899 ch = *p++;
900 break;
901
Igor Sysoev1b735832004-11-11 14:07:14 +0000902#if (NGX_WIN32)
Igor Sysoevc2bba092003-11-28 17:41:47 +0000903 case sw_dot_dot_dot:
904 switch(ch) {
Igor Sysoev1b735832004-11-11 14:07:14 +0000905 case '\\':
Igor Sysoevc2bba092003-11-28 17:41:47 +0000906 case '/':
907 state = sw_slash;
908 u -= 5;
909 if (u < r->uri.data) {
910 return NGX_HTTP_PARSE_INVALID_REQUEST;
911 }
912 while (*u != '/') {
913 u--;
914 }
915 if (u < r->uri.data) {
916 return NGX_HTTP_PARSE_INVALID_REQUEST;
917 }
918 while (*(u - 1) != '/') {
919 u--;
920 }
921 break;
922 case '%':
923 quoted_state = state;
924 state = sw_quoted;
925 break;
926 default:
927 state = sw_usual;
928 *u++ = ch;
929 break;
930 }
931 ch = *p++;
932 break;
933#endif
934
935 case sw_quoted:
936 if (ch >= '0' && ch <= '9') {
Igor Sysoev9c610952004-03-16 13:35:20 +0000937 decoded = (u_char) (ch - '0');
Igor Sysoevc2bba092003-11-28 17:41:47 +0000938 state = sw_quoted_second;
939 ch = *p++;
940 break;
941 }
942
Igor Sysoev9c610952004-03-16 13:35:20 +0000943 c = (u_char) (ch | 0x20);
Igor Sysoevc2bba092003-11-28 17:41:47 +0000944 if (c >= 'a' && c <= 'f') {
Igor Sysoev9c610952004-03-16 13:35:20 +0000945 decoded = (u_char) (c - 'a' + 10);
Igor Sysoevc2bba092003-11-28 17:41:47 +0000946 state = sw_quoted_second;
947 ch = *p++;
948 break;
949 }
950
951 return NGX_HTTP_PARSE_INVALID_REQUEST;
952
953 case sw_quoted_second:
954 if (ch >= '0' && ch <= '9') {
Igor Sysoev9c610952004-03-16 13:35:20 +0000955 ch = (u_char) ((decoded << 4) + ch - '0');
Igor Sysoev1ebfead2005-02-16 13:40:36 +0000956
Igor Sysoev7adb8c02003-12-02 16:57:05 +0000957 if (ch == '%') {
958 state = sw_usual;
959 *u++ = ch;
960 ch = *p++;
961 break;
962 }
Igor Sysoev1ebfead2005-02-16 13:40:36 +0000963
964 if (ch == '\0') {
965 r->zero_in_uri = 1;
966 *u++ = ch;
967 ch = *p++;
968 }
969
Igor Sysoevc2bba092003-11-28 17:41:47 +0000970 state = quoted_state;
971 break;
972 }
973
Igor Sysoev9c610952004-03-16 13:35:20 +0000974 c = (u_char) (ch | 0x20);
Igor Sysoevc2bba092003-11-28 17:41:47 +0000975 if (c >= 'a' && c <= 'f') {
Igor Sysoev9c610952004-03-16 13:35:20 +0000976 ch = (u_char) ((decoded << 4) + c - 'a' + 10);
Igor Sysoev02025fd2005-01-18 13:03:58 +0000977 if (ch == '?') {
Igor Sysoev7adb8c02003-12-02 16:57:05 +0000978 *u++ = ch;
979 ch = *p++;
Igor Sysoev7adb8c02003-12-02 16:57:05 +0000980 }
Igor Sysoevc2bba092003-11-28 17:41:47 +0000981 state = quoted_state;
982 break;
983 }
984
985 return NGX_HTTP_PARSE_INVALID_REQUEST;
986 }
987 }
988
Igor Sysoev02025fd2005-01-18 13:03:58 +0000989done:
990
Igor Sysoevc2bba092003-11-28 17:41:47 +0000991 r->uri.len = u - r->uri.data;
992 r->uri.data[r->uri.len] = '\0';
993
Igor Sysoev865c1502003-11-30 20:03:18 +0000994 if (r->uri_ext) {
995 r->exten.len = u - r->uri_ext;
Igor Sysoev1b735832004-11-11 14:07:14 +0000996 r->exten.data = r->uri_ext;
Igor Sysoev865c1502003-11-30 20:03:18 +0000997 }
998
999 r->uri_ext = NULL;
1000
Igor Sysoevc2bba092003-11-28 17:41:47 +00001001 return NGX_OK;
1002}
Igor Sysoev899b44e2005-05-12 14:58:06 +00001003
1004
1005ngx_int_t
1006ngx_http_parse_multi_header_lines(ngx_array_t *headers, ngx_str_t *name,
1007 ngx_str_t *value)
1008{
1009 ngx_uint_t i;
1010 u_char *start, *last, *end, ch;
1011 ngx_table_elt_t **h;
1012
1013 h = headers->elts;
1014
1015 for (i = 0; i < headers->nelts; i++) {
1016
1017 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, headers->pool->log, 0,
1018 "parse header: \"%V: %V\"", &h[i]->key, &h[i]->value);
1019
1020 if (name->len > h[i]->value.len) {
1021 continue;
1022 }
1023
1024 start = h[i]->value.data;
1025 end = h[i]->value.data + h[i]->value.len;
1026
1027 while (start < end) {
1028
1029 if (ngx_strncasecmp(start, name->data, name->len) != 0) {
1030 goto skip;
1031 }
1032
1033 for (start += name->len; start < end && *start == ' '; start++) {
1034 /* void */
1035 }
1036
1037 if (value == NULL) {
1038 if (start == end || *start == ',') {
1039 return i;
1040 }
1041
1042 goto skip;
1043 }
1044
1045 if (start == end || *start++ != '=') {
1046 /* the invalid header value */
1047 goto skip;
1048 }
1049
1050 while (start < end && *start == ' ') { start++; }
1051
1052 for (last = start; last < end && *last != ';'; last++) {
1053 /* void */
1054 }
1055
1056 value->len = last - start;
1057 value->data = start;
1058
1059 return i;
1060
1061 skip:
1062 while (start < end) {
1063 ch = *start++;
1064 if (ch == ';' || ch == ',') {
1065 break;
1066 }
1067 }
1068
1069 while (start < end && *start == ' ') { start++; }
1070 }
1071 }
1072
1073 return NGX_DECLINED;
1074}