~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Linux Cross Reference
Nginx/http/ngx_http_parse.c

Version: ~ [ nginx-0.8.20 ] ~ [ nginx-0.7.62 ] ~ [ nginx-0.6.39 ] ~

  1 
  2 /*
  3  * Copyright (C) Igor Sysoev
  4  */
  5 
  6 
  7 #include <ngx_config.h>
  8 #include <ngx_core.h>
  9 #include <ngx_http.h>
 10 
 11 
 12 static uint32_t  usual[] = {
 13     0xffffdbfe, /* 1111 1111 1111 1111  1101 1011 1111 1110 */
 14 
 15                 /* ?>=< ;:98 7654 3210  /.-, +*)( '&%$ #"!  */
 16     0x7fff37d6, /* 0111 1111 1111 1111  0011 0111 1101 0110 */
 17 
 18                 /* _^]\ [ZYX WVUT SRQP  ONML KJIH GFED CBA@ */
 19 #if (NGX_WIN32)
 20     0xefffffff, /* 1110 1111 1111 1111  1111 1111 1111 1111 */
 21 #else
 22     0xffffffff, /* 1111 1111 1111 1111  1111 1111 1111 1111 */
 23 #endif
 24 
 25                 /*  ~}| {zyx wvut srqp  onml kjih gfed cba` */
 26     0xffffffff, /* 1111 1111 1111 1111  1111 1111 1111 1111 */
 27 
 28     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 };
 33 
 34 
 35 #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 
100 /* gcc, icc, msvc and others compile these switches as an jump table */
101 
102 ngx_int_t
103 ngx_http_parse_request_line(ngx_http_request_t *r, ngx_buf_t *b)
104 {
105     u_char  c, ch, *p, *m;
106     enum {
107         sw_start = 0,
108         sw_method,
109         sw_spaces_before_uri,
110         sw_schema,
111         sw_schema_slash,
112         sw_schema_slash_slash,
113         sw_host,
114         sw_port,
115         sw_after_slash_in_uri,
116         sw_check_uri,
117         sw_uri,
118         sw_http_09,
119         sw_http_H,
120         sw_http_HT,
121         sw_http_HTT,
122         sw_http_HTTP,
123         sw_first_major_digit,
124         sw_major_digit,
125         sw_first_minor_digit,
126         sw_minor_digit,
127         sw_spaces_after_digit,
128         sw_almost_done
129     } state;
130 
131     state = r->state;
132 
133     for (p = b->pos; p < b->last; p++) {
134         ch = *p;
135 
136         switch (state) {
137 
138         /* HTTP methods: GET, HEAD, POST */
139         case sw_start:
140             r->request_start = p;
141 
142             if (ch == CR || ch == LF) {
143                 break;
144             }
145 
146             if ((ch < 'A' || ch > 'Z') && ch != '_') {
147                 return NGX_HTTP_PARSE_INVALID_METHOD;
148             }
149 
150             state = sw_method;
151             break;
152 
153         case sw_method:
154             if (ch == ' ') {
155                 r->method_end = p - 1;
156                 m = r->request_start;
157 
158                 switch (p - m) {
159 
160                 case 3:
161                     if (ngx_str3_cmp(m, 'G', 'E', 'T', ' ')) {
162                         r->method = NGX_HTTP_GET;
163                         break;
164                     }
165 
166                     if (ngx_str3_cmp(m, 'P', 'U', 'T', ' ')) {
167                         r->method = NGX_HTTP_PUT;
168                         break;
169                     }
170 
171                     break;
172 
173                 case 4:
174                     if (m[1] == 'O') {
175 
176                         if (ngx_str3Ocmp(m, 'P', 'O', 'S', 'T')) {
177                             r->method = NGX_HTTP_POST;
178                             break;
179                         }
180 
181                         if (ngx_str3Ocmp(m, 'C', 'O', 'P', 'Y')) {
182                             r->method = NGX_HTTP_COPY;
183                             break;
184                         }
185 
186                         if (ngx_str3Ocmp(m, 'M', 'O', 'V', 'E')) {
187                             r->method = NGX_HTTP_MOVE;
188                             break;
189                         }
190 
191                         if (ngx_str3Ocmp(m, 'L', 'O', 'C', 'K')) {
192                             r->method = NGX_HTTP_LOCK;
193                             break;
194                         }
195 
196                     } else {
197 
198                         if (ngx_str4cmp(m, 'H', 'E', 'A', 'D')) {
199                             r->method = NGX_HTTP_HEAD;
200                             break;
201                         }
202                     }
203 
204                     break;
205 
206                 case 5:
207                     if (ngx_str5cmp(m, 'M', 'K', 'C', 'O', 'L')) {
208                         r->method = NGX_HTTP_MKCOL;
209                     }
210 
211                     if (ngx_str5cmp(m, 'T', 'R', 'A', 'C', 'E')) {
212                         r->method = NGX_HTTP_TRACE;
213                     }
214 
215                     break;
216 
217                 case 6:
218                     if (ngx_str6cmp(m, 'D', 'E', 'L', 'E', 'T', 'E')) {
219                         r->method = NGX_HTTP_DELETE;
220                         break;
221                     }
222 
223                     if (ngx_str6cmp(m, 'U', 'N', 'L', 'O', 'C', 'K')) {
224                         r->method = NGX_HTTP_UNLOCK;
225                         break;
226                     }
227 
228                     break;
229 
230                 case 7:
231                     if (ngx_str7_cmp(m, 'O', 'P', 'T', 'I', 'O', 'N', 'S', ' '))
232                     {
233                         r->method = NGX_HTTP_OPTIONS;
234                     }
235 
236                     break;
237 
238                 case 8:
239                     if (ngx_str8cmp(m, 'P', 'R', 'O', 'P', 'F', 'I', 'N', 'D'))
240                     {
241                         r->method = NGX_HTTP_PROPFIND;
242                     }
243 
244                     break;
245 
246                 case 9:
247                     if (ngx_str9cmp(m,
248                             'P', 'R', 'O', 'P', 'P', 'A', 'T', 'C', 'H'))
249                     {
250                         r->method = NGX_HTTP_PROPPATCH;
251                     }
252 
253                     break;
254                 }
255 
256                 state = sw_spaces_before_uri;
257                 break;
258             }
259 
260             if ((ch < 'A' || ch > 'Z') && ch != '_') {
261                 return NGX_HTTP_PARSE_INVALID_METHOD;
262             }
263 
264             break;
265 
266         /* space* before URI */
267         case sw_spaces_before_uri:
268 
269             if (ch == '/' ){
270                 r->uri_start = p;
271                 state = sw_after_slash_in_uri;
272                 break;
273             }
274 
275             c = (u_char) (ch | 0x20);
276             if (c >= 'a' && c <= 'z') {
277                 r->schema_start = p;
278                 state = sw_schema;
279                 break;
280             }
281 
282             switch (ch) {
283             case ' ':
284                 break;
285             default:
286                 return NGX_HTTP_PARSE_INVALID_REQUEST;
287             }
288             break;
289 
290         case sw_schema:
291 
292             c = (u_char) (ch | 0x20);
293             if (c >= 'a' && c <= 'z') {
294                 break;
295             }
296 
297             switch (ch) {
298             case ':':
299                 r->schema_end = p;
300                 state = sw_schema_slash;
301                 break;
302             default:
303                 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 '/':
320                 r->host_start = p + 1;
321                 state = sw_host;
322                 break;
323             default:
324                 return NGX_HTTP_PARSE_INVALID_REQUEST;
325             }
326             break;
327 
328         case sw_host:
329 
330             c = (u_char) (ch | 0x20);
331             if (c >= 'a' && c <= 'z') {
332                 break;
333             }
334 
335             if ((ch >= '' && ch <= '9') || ch == '.' || ch == '-') {
336                 break;
337             }
338 
339             r->host_end = p;
340 
341             switch (ch) {
342             case ':':
343                 state = sw_port;
344                 break;
345             case '/':
346                 r->uri_start = p;
347                 state = sw_after_slash_in_uri;
348                 break;
349             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;
358             default:
359                 return NGX_HTTP_PARSE_INVALID_REQUEST;
360             }
361             break;
362 
363         case sw_port:
364             if (ch >= '' && ch <= '9') {
365                 break;
366             }
367 
368             switch (ch) {
369             case '/':
370                 r->port_end = p;
371                 r->uri_start = p;
372                 state = sw_after_slash_in_uri;
373                 break;
374             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;
384             default:
385                 return NGX_HTTP_PARSE_INVALID_REQUEST;
386             }
387             break;
388 
389         /* check "/.", "//", "%", and "\" (Win32) in URI */
390         case sw_after_slash_in_uri:
391 
392             if (usual[ch >> 5] & (1 << (ch & 0x1f))) {
393                 state = sw_check_uri;
394                 break;
395             }
396 
397             switch (ch) {
398             case ' ':
399                 r->uri_end = p;
400                 state = sw_http_09;
401                 break;
402             case CR:
403                 r->uri_end = p;
404                 r->http_minor = 9;
405                 state = sw_almost_done;
406                 break;
407             case LF:
408                 r->uri_end = p;
409                 r->http_minor = 9;
410                 goto done;
411             case '.':
412                 r->complex_uri = 1;
413                 state = sw_uri;
414                 break;
415             case '%':
416                 r->quoted_uri = 1;
417                 state = sw_uri;
418                 break;
419             case '/':
420                 r->complex_uri = 1;
421                 state = sw_uri;
422                 break;
423 #if (NGX_WIN32)
424             case '\\':
425                 r->complex_uri = 1;
426                 state = sw_uri;
427                 break;
428 #endif
429             case '?':
430                 r->args_start = p + 1;
431                 state = sw_uri;
432                 break;
433             case '#':
434                 r->complex_uri = 1;
435                 state = sw_uri;
436                 break;
437             case '+':
438                 r->plus_in_uri = 1;
439                 break;
440             case '\0':
441                 r->zero_in_uri = 1;
442                 break;
443             default:
444                 state = sw_check_uri;
445                 break;
446             }
447             break;
448 
449         /* check "/", "%" and "\" (Win32) in URI */
450         case sw_check_uri:
451 
452             if (usual[ch >> 5] & (1 << (ch & 0x1f))) {
453                 break;
454             }
455 
456             switch (ch) {
457             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;
468             case CR:
469                 r->uri_end = p;
470                 r->http_minor = 9;
471                 state = sw_almost_done;
472                 break;
473             case LF:
474                 r->uri_end = p;
475                 r->http_minor = 9;
476                 goto done;
477 #if (NGX_WIN32)
478             case '\\':
479                 r->complex_uri = 1;
480                 state = sw_after_slash_in_uri;
481                 break;
482 #endif
483             case '%':
484                 r->quoted_uri = 1;
485                 state = sw_uri;
486                 break;
487             case '?':
488                 r->args_start = p + 1;
489                 state = sw_uri;
490                 break;
491             case '#':
492                 r->complex_uri = 1;
493                 state = sw_uri;
494                 break;
495             case '+':
496                 r->plus_in_uri = 1;
497                 break;
498             case '\0':
499                 r->zero_in_uri = 1;
500                 break;
501             }
502             break;
503 
504         /* URI */
505         case sw_uri:
506 
507             if (usual[ch >> 5] & (1 << (ch & 0x1f))) {
508                 break;
509             }
510 
511             switch (ch) {
512             case ' ':
513                 r->uri_end = p;
514                 state = sw_http_09;
515                 break;
516             case CR:
517                 r->uri_end = p;
518                 r->http_minor = 9;
519                 state = sw_almost_done;
520                 break;
521             case LF:
522                 r->uri_end = p;
523                 r->http_minor = 9;
524                 goto done;
525             case '#':
526                 r->complex_uri = 1;
527                 break;
528             case '\0':
529                 r->zero_in_uri = 1;
530                 break;
531             }
532             break;
533 
534         /* space+ after URI */
535         case sw_http_09:
536             switch (ch) {
537             case ' ':
538                 break;
539             case CR:
540                 r->http_minor = 9;
541                 state = sw_almost_done;
542                 break;
543             case LF:
544                 r->http_minor = 9;
545                 goto done;
546             case 'H':
547                 r->http_protocol.data = p;
548                 state = sw_http_H;
549                 break;
550             default:
551                 return NGX_HTTP_PARSE_INVALID_REQUEST;
552             }
553             break;
554 
555         case sw_http_H:
556             switch (ch) {
557             case 'T':
558                 state = sw_http_HT;
559                 break;
560             default:
561                 return NGX_HTTP_PARSE_INVALID_REQUEST;
562             }
563             break;
564 
565         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             }
593             break;
594 
595         /* first digit of major HTTP version */
596         case sw_first_major_digit:
597             if (ch < '1' || ch > '9') {
598                 return NGX_HTTP_PARSE_INVALID_REQUEST;
599             }
600 
601             r->http_major = ch - '';
602             state = sw_major_digit;
603             break;
604 
605         /* major HTTP version or dot */
606         case sw_major_digit:
607             if (ch == '.') {
608                 state = sw_first_minor_digit;
609                 break;
610             }
611 
612             if (ch < '' || ch > '9') {
613                 return NGX_HTTP_PARSE_INVALID_REQUEST;
614             }
615 
616             r->http_major = r->http_major * 10 + ch - '';
617             break;
618 
619         /* first digit of minor HTTP version */
620         case sw_first_minor_digit:
621             if (ch < '' || ch > '9') {
622                 return NGX_HTTP_PARSE_INVALID_REQUEST;
623             }
624 
625             r->http_minor = ch - '';
626             state = sw_minor_digit;
627             break;
628 
629         /* minor HTTP version or end of request line */
630         case sw_minor_digit:
631             if (ch == CR) {
632                 state = sw_almost_done;
633                 break;
634             }
635 
636             if (ch == LF) {
637                 goto done;
638             }
639 
640             if (ch == ' ') {
641                 state = sw_spaces_after_digit;
642                 break;
643             }
644 
645             if (ch < '' || ch > '9') {
646                 return NGX_HTTP_PARSE_INVALID_REQUEST;
647             }
648 
649             r->http_minor = r->http_minor * 10 + ch - '';
650             break;
651 
652         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 
666         /* end of request line */
667         case sw_almost_done:
668             r->request_end = p - 1;
669             switch (ch) {
670             case LF:
671                 goto done;
672             default:
673                 return NGX_HTTP_PARSE_INVALID_REQUEST;
674             }
675         }
676     }
677 
678     b->pos = p;
679     r->state = state;
680 
681     return NGX_AGAIN;
682 
683 done:
684 
685     b->pos = p + 1;
686 
687     if (r->request_end == NULL) {
688         r->request_end = p;
689     }
690 
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;
699 }
700 
701 
702 ngx_int_t
703 ngx_http_parse_header_line(ngx_http_request_t *r, ngx_buf_t *b,
704     ngx_uint_t allow_underscores)
705 {
706     u_char      c, ch, *p;
707     ngx_uint_t  hash, i;
708     enum {
709         sw_start = 0,
710         sw_name,
711         sw_space_before_value,
712         sw_value,
713         sw_space_after_value,
714         sw_ignore_line,
715         sw_almost_done,
716         sw_header_almost_done
717     } state;
718 
719     /* the last '\0' is not needed because string is zero terminated */
720 
721     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"
724         "\0abcdefghijklmnopqrstuvwxyz\0\0\0\0\0"
725         "\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"
729         "\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";
730 
731     state = r->state;
732     hash = r->header_hash;
733     i = r->lowcase_index;
734 
735     for (p = b->pos; p < b->last; p++) {
736         ch = *p;
737 
738         switch (state) {
739 
740         /* first char */
741         case sw_start:
742             r->header_name_start = p;
743             r->invalid_header = 0;
744 
745             switch (ch) {
746             case CR:
747                 r->header_end = p;
748                 state = sw_header_almost_done;
749                 break;
750             case LF:
751                 r->header_end = p;
752                 goto header_done;
753             default:
754                 state = sw_name;
755 
756                 c = lowcase[ch];
757 
758                 if (c) {
759                     hash = ngx_hash(0, c);
760                     r->lowcase_header[0] = c;
761                     i = 1;
762                     break;
763                 }
764 
765                 r->invalid_header = 1;
766 
767                 break;
768 
769             }
770             break;
771 
772         /* header name */
773         case sw_name:
774             c = lowcase[ch];
775 
776             if (c) {
777                 hash = ngx_hash(hash, c);
778                 r->lowcase_header[i++] = c;
779                 i &= (NGX_HTTP_LC_HEADER_LEN - 1);
780                 break;
781             }
782 
783             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 
796             if (ch == ':') {
797                 r->header_name_end = p;
798                 state = sw_space_before_value;
799                 break;
800             }
801 
802             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 
817             /* IIS may send the duplicate "HTTP/1.1 ..." lines */
818             if (ch == '/'
819                 && r->upstream
820                 && p - r->header_name_start == 4
821                 && ngx_strncmp(r->header_name_start, "HTTP", 4) == 0)
822             {
823                 state = sw_ignore_line;
824                 break;
825             }
826 
827             r->invalid_header = 1;
828 
829             break;
830 
831         /* space* before header value */
832         case sw_space_before_value:
833             switch (ch) {
834             case ' ':
835                 break;
836             case CR:
837                 r->header_start = p;
838                 r->header_end = p;
839                 state = sw_almost_done;
840                 break;
841             case LF:
842                 r->header_start = p;
843                 r->header_end = p;
844                 goto done;
845             default:
846                 r->header_start = p;
847                 state = sw_value;
848                 break;
849             }
850             break;
851 
852         /* header value */
853         case sw_value:
854             switch (ch) {
855             case ' ':
856                 r->header_end = p;
857                 state = sw_space_after_value;
858                 break;
859             case CR:
860                 r->header_end = p;
861                 state = sw_almost_done;
862                 break;
863             case LF:
864                 r->header_end = p;
865                 goto done;
866             }
867             break;
868 
869         /* space* before end of header line */
870         case sw_space_after_value:
871             switch (ch) {
872             case ' ':
873                 break;
874             case CR:
875                 state = sw_almost_done;
876                 break;
877             case LF:
878                 goto done;
879             default:
880                 state = sw_value;
881                 break;
882             }
883             break;
884 
885         /* 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 
896         /* end of header line */
897         case sw_almost_done:
898             switch (ch) {
899             case LF:
900                 goto done;
901             case CR:
902                 break;
903             default:
904                 return NGX_HTTP_PARSE_INVALID_HEADER;
905             }
906             break;
907 
908         /* end of header */
909         case sw_header_almost_done:
910             switch (ch) {
911             case LF:
912                 goto header_done;
913             default:
914                 return NGX_HTTP_PARSE_INVALID_HEADER;
915             }
916         }
917     }
918 
919     b->pos = p;
920     r->state = state;
921     r->header_hash = hash;
922     r->lowcase_index = i;
923 
924     return NGX_AGAIN;
925 
926 done:
927 
928     b->pos = p + 1;
929     r->state = sw_start;
930     r->header_hash = hash;
931     r->lowcase_index = i;
932 
933     return NGX_OK;
934 
935 header_done:
936 
937     b->pos = p + 1;
938     r->state = sw_start;
939 
940     return NGX_HTTP_PARSE_HEADER_DONE;
941 }
942 
943 
944 ngx_int_t
945 ngx_http_parse_complex_uri(ngx_http_request_t *r, ngx_uint_t merge_slashes)
946 {
947     u_char  c, ch, decoded, *p, *u;
948     enum {
949         sw_usual = 0,
950         sw_slash,
951         sw_dot,
952         sw_dot_dot,
953         sw_quoted,
954         sw_quoted_second
955     } state, quoted_state;
956 
957 #if (NGX_SUPPRESS_WARN)
958     decoded = '\0';
959     quoted_state = sw_usual;
960 #endif
961 
962     state = sw_usual;
963     p = r->uri_start;
964     u = r->uri.data;
965     r->uri_ext = NULL;
966     r->args_start = NULL;
967 
968     ch = *p++;
969 
970     while (p <= r->uri_end) {
971 
972         /*
973          * we use "ch = *p++" inside the cycle, but this operation is safe,
974          * because after the URI there is always at least one charcter:
975          * the line feed
976          */
977 
978         ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
979                        "s:%d in:'%Xd:%c', out:'%c'", state, ch, ch, *u);
980 
981         switch (state) {
982 
983         case sw_usual:
984 
985             if (usual[ch >> 5] & (1 << (ch & 0x1f))) {
986                 *u++ = ch;
987                 ch = *p++;
988                 break;
989             }
990 
991             switch(ch) {
992 #if (NGX_WIN32)
993             case '\\':
994                 r->uri_ext = NULL;
995 
996                 if (p == r->uri_start + r->uri.len) {
997 
998                     /*
999                      * we omit the last "\" to cause redirect because
1000                      * the browsers do not treat "\" as "/" in relative URL path
1001                      */
1002 
1003                     break;
1004                 }
1005 
1006                 state = sw_slash;
1007                 *u++ = '/';
1008                 break;
1009 #endif
1010             case '/':
1011                 r->uri_ext = NULL;
1012                 state = sw_slash;
1013                 *u++ = ch;
1014                 break;
1015             case '%':
1016                 quoted_state = state;
1017                 state = sw_quoted;
1018                 break;
1019             case '?':
1020                 r->args_start = p;
1021                 goto args;
1022             case '#':
1023                 goto done;
1024             case '.':
1025                 r->uri_ext = u + 1;
1026                 *u++ = ch;
1027                 break;
1028             case '+':
1029                 r->plus_in_uri = 1;
1030             default:
1031                 *u++ = ch;
1032                 break;
1033             }
1034 
1035             ch = *p++;
1036             break;
1037 
1038         case sw_slash:
1039 
1040             if (usual[ch >> 5] & (1 << (ch & 0x1f))) {
1041                 state = sw_usual;
1042                 *u++ = ch;
1043                 ch = *p++;
1044                 break;
1045             }
1046 
1047             switch(ch) {
1048 #if (NGX_WIN32)
1049             case '\\':
1050                 break;
1051 #endif
1052             case '/':
1053                 if (!merge_slashes) {
1054                     *u++ = ch;
1055                 }
1056                 break;
1057             case '.':
1058                 state = sw_dot;
1059                 *u++ = ch;
1060                 break;
1061             case '%':
1062                 quoted_state = state;
1063                 state = sw_quoted;
1064                 break;
1065             case '?':
1066                 r->args_start = p;
1067                 goto args;
1068             case '#':
1069                 goto done;
1070             case '+':
1071                 r->plus_in_uri = 1;
1072             default:
1073                 state = sw_usual;
1074                 *u++ = ch;
1075                 break;
1076             }
1077 
1078             ch = *p++;
1079             break;
1080 
1081         case sw_dot:
1082 
1083             if (usual[ch >> 5] & (1 << (ch & 0x1f))) {
1084                 state = sw_usual;
1085                 *u++ = ch;
1086                 ch = *p++;
1087                 break;
1088             }
1089 
1090             switch(ch) {
1091 #if (NGX_WIN32)
1092             case '\\':
1093 #endif
1094             case '/':
1095                 state = sw_slash;
1096                 u--;
1097                 break;
1098             case '.':
1099                 state = sw_dot_dot;
1100                 *u++ = ch;
1101                 break;
1102             case '%':
1103                 quoted_state = state;
1104                 state = sw_quoted;
1105                 break;
1106             case '?':
1107                 r->args_start = p;
1108                 goto args;
1109             case '#':
1110                 goto done;
1111             case '+':
1112                 r->plus_in_uri = 1;
1113             default:
1114                 state = sw_usual;
1115                 *u++ = ch;
1116                 break;
1117             }
1118 
1119             ch = *p++;
1120             break;
1121 
1122         case sw_dot_dot:
1123 
1124             if (usual[ch >> 5] & (1 << (ch & 0x1f))) {
1125                 state = sw_usual;
1126                 *u++ = ch;
1127                 ch = *p++;
1128                 break;
1129             }
1130 
1131             switch(ch) {
1132 #if (NGX_WIN32)
1133             case '\\':
1134 #endif
1135             case '/':
1136                 state = sw_slash;
1137                 u -= 5;
1138                 for ( ;; ) {
1139                     if (u < r->uri.data) {
1140                         return NGX_HTTP_PARSE_INVALID_REQUEST;
1141                     }
1142                     if (*u == '/') {
1143                         u++;
1144                         break;
1145                     }
1146                     u--;
1147                 }
1148                 break;
1149             case '%':
1150                 quoted_state = state;
1151                 state = sw_quoted;
1152                 break;
1153             case '?':
1154                 r->args_start = p;
1155                 goto args;
1156             case '#':
1157                 goto done;
1158             case '+':
1159                 r->plus_in_uri = 1;
1160             default:
1161                 state = sw_usual;
1162                 *u++ = ch;
1163                 break;
1164             }
1165 
1166             ch = *p++;
1167             break;
1168 
1169         case sw_quoted:
1170             r->quoted_uri = 1;
1171 
1172             if (ch >= '' && ch <= '9') {
1173                 decoded = (u_char) (ch - '');
1174                 state = sw_quoted_second;
1175                 ch = *p++;
1176                 break;
1177             }
1178 
1179             c = (u_char) (ch | 0x20);
1180             if (c >= 'a' && c <= 'f') {
1181                 decoded = (u_char) (c - 'a' + 10);
1182                 state = sw_quoted_second;
1183                 ch = *p++;
1184                 break;
1185             }
1186 
1187             return NGX_HTTP_PARSE_INVALID_REQUEST;
1188 
1189         case sw_quoted_second:
1190             if (ch >= '' && ch <= '9') {
1191                 ch = (u_char) ((decoded << 4) + ch - '');
1192 
1193                 if (ch == '%') {
1194                     state = sw_usual;
1195                     *u++ = ch;
1196                     ch = *p++;
1197                     break;
1198                 }
1199 
1200                 if (ch == '#') {
1201                     *u++ = ch;
1202                     ch = *p++;
1203 
1204                 } else if (ch == '\0') {
1205                     r->zero_in_uri = 1;
1206                 }
1207 
1208                 state = quoted_state;
1209                 break;
1210             }
1211 
1212             c = (u_char) (ch | 0x20);
1213             if (c >= 'a' && c <= 'f') {
1214                 ch = (u_char) ((decoded << 4) + c - 'a' + 10);
1215 
1216                 if (ch == '?') {
1217                     *u++ = ch;
1218                     ch = *p++;
1219 
1220                 } else if (ch == '+') {
1221                     r->plus_in_uri = 1;
1222                 }
1223 
1224                 state = quoted_state;
1225                 break;
1226             }
1227 
1228             return NGX_HTTP_PARSE_INVALID_REQUEST;
1229         }
1230     }
1231 
1232 done:
1233 
1234     r->uri.len = u - r->uri.data;
1235 
1236     if (r->uri_ext) {
1237         r->exten.len = u - r->uri_ext;
1238         r->exten.data = r->uri_ext;
1239     }
1240 
1241     r->uri_ext = NULL;
1242 
1243     return NGX_OK;
1244 
1245 args:
1246 
1247     while (p < r->uri_end) {
1248         if (*p++ != '#') {
1249             continue;
1250         }
1251 
1252         r->args.len = p - 1 - r->args_start;
1253         r->args.data = r->args_start;
1254         r->args_start = NULL;
1255 
1256         break;
1257     }
1258 
1259     r->uri.len = u - r->uri.data;
1260 
1261     if (r->uri_ext) {
1262         r->exten.len = u - r->uri_ext;
1263         r->exten.data = r->uri_ext;
1264     }
1265 
1266     r->uri_ext = NULL;
1267 
1268     return NGX_OK;
1269 }
1270 
1271 
1272 ngx_int_t
1273 ngx_http_parse_unsafe_uri(ngx_http_request_t *r, ngx_str_t *uri,
1274     ngx_str_t *args, ngx_uint_t *flags)
1275 {
1276     u_char  ch, *p;
1277     size_t  len;
1278 
1279     len = uri->len;
1280     p = uri->data;
1281 
1282     if (len == 0 || p[0] == '?') {
1283         goto unsafe;
1284     }
1285 
1286     if (p[0] == '.' && len == 3 && p[1] == '.' && (ngx_path_separator(p[2]))) {
1287         goto unsafe;
1288     }
1289 
1290     for ( /* void */ ; len; len--) {
1291 
1292         ch = *p++;
1293 
1294         if (usual[ch >> 5] & (1 << (ch & 0x1f))) {
1295             continue;
1296         }
1297 
1298         if (ch == '?') {
1299             args->len = len - 1;
1300             args->data = p;
1301             uri->len -= len;
1302 
1303             return NGX_OK;
1304         }
1305 
1306         if (ch == '\0') {
1307             *flags |= NGX_HTTP_ZERO_IN_URI;
1308             continue;
1309         }
1310 
1311         if (ngx_path_separator(ch) && len > 2) {
1312 
1313             /* detect "/../" */
1314 
1315             if (p[0] == '.' && p[1] == '.' && ngx_path_separator(p[2])) {
1316                 goto unsafe;
1317             }
1318         }
1319     }
1320 
1321     return NGX_OK;
1322 
1323 unsafe:
1324 
1325     if (*flags & NGX_HTTP_LOG_UNSAFE) {
1326         ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
1327                       "unsafe URI \"%V\" was detected", uri);
1328     }
1329 
1330     return NGX_ERROR;
1331 }
1332 
1333 
1334 ngx_int_t
1335 ngx_http_parse_multi_header_lines(ngx_array_t *headers, ngx_str_t *name,
1336     ngx_str_t *value)
1337 {
1338     ngx_uint_t         i;
1339     u_char            *start, *last, *end, ch;
1340     ngx_table_elt_t  **h;
1341 
1342     h = headers->elts;
1343 
1344     for (i = 0; i < headers->nelts; i++) {
1345 
1346         ngx_log_debug2(NGX_LOG_DEBUG_HTTP, headers->pool->log, 0,
1347                        "parse header: \"%V: %V\"", &h[i]->key, &h[i]->value);
1348 
1349         if (name->len > h[i]->value.len) {
1350             continue;
1351         }
1352 
1353         start = h[i]->value.data;
1354         end = h[i]->value.data + h[i]->value.len;
1355 
1356         while (start < end) {
1357 
1358             if (ngx_strncasecmp(start, name->data, name->len) != 0) {
1359                 goto skip;
1360             }
1361 
1362             for (start += name->len; start < end && *start == ' '; start++) {
1363                 /* void */
1364             }
1365 
1366             if (value == NULL) {
1367                 if (start == end || *start == ',') {
1368                     return i;
1369                 }
1370 
1371                 goto skip;
1372             }
1373 
1374             if (start == end || *start++ != '=') {
1375                 /* the invalid header value */
1376                 goto skip;
1377             }
1378 
1379             while (start < end && *start == ' ') { start++; }
1380 
1381             for (last = start; last < end && *last != ';'; last++) {
1382                 /* void */
1383             }
1384 
1385             value->len = last - start;
1386             value->data = start;
1387 
1388             return i;
1389 
1390         skip:
1391 
1392             while (start < end) {
1393                 ch = *start++;
1394                 if (ch == ';' || ch == ',') {
1395                     break;
1396                 }
1397             }
1398 
1399             while (start < end && *start == ' ') { start++; }
1400         }
1401     }
1402 
1403     return NGX_DECLINED;
1404 }
1405 
1406 
1407 ngx_int_t
1408 ngx_http_arg(ngx_http_request_t *r, u_char *name, size_t len, ngx_str_t *value)
1409 {
1410     u_char  *p, *last;
1411 
1412     if (r->args.len == 0) {
1413         return NGX_DECLINED;
1414     }
1415 
1416     p = r->args.data;
1417     last = p + r->args.len;
1418 
1419     for ( /* void */ ; p < last; p++) {
1420 
1421         /* we need '=' after name, so drop one char from last */
1422 
1423         p = ngx_strlcasestrn(p, last - 1, name, len - 1);
1424 
1425         if (p == NULL) {
1426             return NGX_DECLINED;
1427         }
1428 
1429         if ((p == r->args.data || *(p - 1) == '&') && *(p + len) == '=') {
1430 
1431             value->data = p + len + 1;
1432 
1433             p = ngx_strlchr(p, last, '&');
1434 
1435             if (p == NULL) {
1436                 p = r->args.data + r->args.len;
1437             }
1438 
1439             value->len = p - value->data;
1440 
1441             return NGX_OK;
1442         }
1443     }
1444 
1445     return NGX_DECLINED;
1446 }
1447 
1448 
1449 void
1450 ngx_http_split_args(ngx_http_request_t *r, ngx_str_t *uri, ngx_str_t *args)
1451 {
1452     u_char  ch, *p, *last;
1453 
1454     p = uri->data;
1455 
1456     last = p + uri->len;
1457 
1458     args->len = 0;
1459 
1460     while (p < last) {
1461 
1462         ch = *p++;
1463 
1464         if (ch == '?') {
1465             args->len = last - p;
1466             args->data = p;
1467 
1468             uri->len = p - 1 - uri->data;
1469 
1470             if (ngx_strlchr(p, last, '\0') != NULL) {
1471                 r->zero_in_uri = 1;
1472             }
1473 
1474             return;
1475         }
1476 
1477         if (ch == '\0') {
1478             r->zero_in_uri = 1;
1479             continue;
1480         }
1481     }
1482 }
1483 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

This page was automatically generated by the LXR engine.
Visit the LXR main site for more information.