src/http/ngx_http_parse.c - nginx source code

Global variables defined

Data types defined

Functions defined

Macros defined

Source code


  1. /*
  2. * Copyright (C) Igor Sysoev
  3. * Copyright (C) Nginx, Inc.
  4. */


  5. #include <ngx_config.h>
  6. #include <ngx_core.h>
  7. #include <ngx_http.h>


  8. static uint32_t  usual[] = {
  9.     0x00000000, /* 0000 0000 0000 0000  0000 0000 0000 0000 */

  10.                 /* ?>=< ;:98 7654 3210  /.-, +*)( '&%$ #"!  */
  11.     0x7fff37d6, /* 0111 1111 1111 1111  0011 0111 1101 0110 */

  12.                 /* _^]\ [ZYX WVUT SRQP  ONML KJIH GFED CBA@ */
  13. #if (NGX_WIN32)
  14.     0xefffffff, /* 1110 1111 1111 1111  1111 1111 1111 1111 */
  15. #else
  16.     0xffffffff, /* 1111 1111 1111 1111  1111 1111 1111 1111 */
  17. #endif

  18.                 /*  ~}| {zyx wvut srqp  onml kjih gfed cba` */
  19.     0x7fffffff, /* 0111 1111 1111 1111  1111 1111 1111 1111 */

  20.     0xffffffff, /* 1111 1111 1111 1111  1111 1111 1111 1111 */
  21.     0xffffffff, /* 1111 1111 1111 1111  1111 1111 1111 1111 */
  22.     0xffffffff, /* 1111 1111 1111 1111  1111 1111 1111 1111 */
  23.     0xffffffff  /* 1111 1111 1111 1111  1111 1111 1111 1111 */
  24. };


  25. #if (NGX_HAVE_LITTLE_ENDIAN && NGX_HAVE_NONALIGNED)

  26. #define ngx_str3_cmp(m, c0, c1, c2, c3)                                       \
  27.     *(uint32_t *) m == ((c3 << 24) | (c2 << 16) | (c1 << 8) | c0)

  28. #define ngx_str3Ocmp(m, c0, c1, c2, c3)                                       \
  29.     *(uint32_t *) m == ((c3 << 24) | (c2 << 16) | (c1 << 8) | c0)

  30. #define ngx_str4cmp(m, c0, c1, c2, c3)                                        \
  31.     *(uint32_t *) m == ((c3 << 24) | (c2 << 16) | (c1 << 8) | c0)

  32. #define ngx_str5cmp(m, c0, c1, c2, c3, c4)                                    \
  33.     *(uint32_t *) m == ((c3 << 24) | (c2 << 16) | (c1 << 8) | c0)             \
  34.         && m[4] == c4

  35. #define ngx_str6cmp(m, c0, c1, c2, c3, c4, c5)                                \
  36.     *(uint32_t *) m == ((c3 << 24) | (c2 << 16) | (c1 << 8) | c0)             \
  37.         && (((uint32_t *) m)[1] & 0xffff) == ((c5 << 8) | c4)

  38. #define ngx_str7_cmp(m, c0, c1, c2, c3, c4, c5, c6, c7)                       \
  39.     *(uint32_t *) m == ((c3 << 24) | (c2 << 16) | (c1 << 8) | c0)             \
  40.         && ((uint32_t *) m)[1] == ((c7 << 24) | (c6 << 16) | (c5 << 8) | c4)

  41. #define ngx_str8cmp(m, c0, c1, c2, c3, c4, c5, c6, c7)                        \
  42.     *(uint32_t *) m == ((c3 << 24) | (c2 << 16) | (c1 << 8) | c0)             \
  43.         && ((uint32_t *) m)[1] == ((c7 << 24) | (c6 << 16) | (c5 << 8) | c4)

  44. #define ngx_str9cmp(m, c0, c1, c2, c3, c4, c5, c6, c7, c8)                    \
  45.     *(uint32_t *) m == ((c3 << 24) | (c2 << 16) | (c1 << 8) | c0)             \
  46.         && ((uint32_t *) m)[1] == ((c7 << 24) | (c6 << 16) | (c5 << 8) | c4)  \
  47.         && m[8] == c8

  48. #else /* !(NGX_HAVE_LITTLE_ENDIAN && NGX_HAVE_NONALIGNED) */

  49. #define ngx_str3_cmp(m, c0, c1, c2, c3)                                       \
  50.     m[0] == c0 && m[1] == c1 && m[2] == c2

  51. #define ngx_str3Ocmp(m, c0, c1, c2, c3)                                       \
  52.     m[0] == c0 && m[2] == c2 && m[3] == c3

  53. #define ngx_str4cmp(m, c0, c1, c2, c3)                                        \
  54.     m[0] == c0 && m[1] == c1 && m[2] == c2 && m[3] == c3

  55. #define ngx_str5cmp(m, c0, c1, c2, c3, c4)                                    \
  56.     m[0] == c0 && m[1] == c1 && m[2] == c2 && m[3] == c3 && m[4] == c4

  57. #define ngx_str6cmp(m, c0, c1, c2, c3, c4, c5)                                \
  58.     m[0] == c0 && m[1] == c1 && m[2] == c2 && m[3] == c3                      \
  59.         && m[4] == c4 && m[5] == c5

  60. #define ngx_str7_cmp(m, c0, c1, c2, c3, c4, c5, c6, c7)                       \
  61.     m[0] == c0 && m[1] == c1 && m[2] == c2 && m[3] == c3                      \
  62.         && m[4] == c4 && m[5] == c5 && m[6] == c6

  63. #define ngx_str8cmp(m, c0, c1, c2, c3, c4, c5, c6, c7)                        \
  64.     m[0] == c0 && m[1] == c1 && m[2] == c2 && m[3] == c3                      \
  65.         && m[4] == c4 && m[5] == c5 && m[6] == c6 && m[7] == c7

  66. #define ngx_str9cmp(m, c0, c1, c2, c3, c4, c5, c6, c7, c8)                    \
  67.     m[0] == c0 && m[1] == c1 && m[2] == c2 && m[3] == c3                      \
  68.         && m[4] == c4 && m[5] == c5 && m[6] == c6 && m[7] == c7 && m[8] == c8

  69. #endif


  70. /* gcc, icc, msvc and others compile these switches as an jump table */

  71. ngx_int_t
  72. ngx_http_parse_request_line(ngx_http_request_t *r, ngx_buf_t *b)
  73. {
  74.     u_char  c, ch, *p, *m;
  75.     enum {
  76.         sw_start = 0,
  77.         sw_method,
  78.         sw_spaces_before_uri,
  79.         sw_schema,
  80.         sw_schema_slash,
  81.         sw_schema_slash_slash,
  82.         sw_host_start,
  83.         sw_host,
  84.         sw_host_end,
  85.         sw_host_ip_literal,
  86.         sw_port,
  87.         sw_after_slash_in_uri,
  88.         sw_check_uri,
  89.         sw_uri,
  90.         sw_http_09,
  91.         sw_http_H,
  92.         sw_http_HT,
  93.         sw_http_HTT,
  94.         sw_http_HTTP,
  95.         sw_first_major_digit,
  96.         sw_major_digit,
  97.         sw_first_minor_digit,
  98.         sw_minor_digit,
  99.         sw_spaces_after_digit,
  100.         sw_almost_done
  101.     } state;

  102.     state = r->state;

  103.     for (p = b->pos; p < b->last; p++) {
  104.         ch = *p;

  105.         switch (state) {

  106.         /* HTTP methods: GET, HEAD, POST */
  107.         case sw_start:
  108.             r->request_start = p;

  109.             if (ch == CR || ch == LF) {
  110.                 break;
  111.             }

  112.             if ((ch < 'A' || ch > 'Z') && ch != '_' && ch != '-') {
  113.                 return NGX_HTTP_PARSE_INVALID_METHOD;
  114.             }

  115.             state = sw_method;
  116.             break;

  117.         case sw_method:
  118.             if (ch == ' ') {
  119.                 r->method_end = p - 1;
  120.                 m = r->request_start;

  121.                 switch (p - m) {

  122.                 case 3:
  123.                     if (ngx_str3_cmp(m, 'G', 'E', 'T', ' ')) {
  124.                         r->method = NGX_HTTP_GET;
  125.                         break;
  126.                     }

  127.                     if (ngx_str3_cmp(m, 'P', 'U', 'T', ' ')) {
  128.                         r->method = NGX_HTTP_PUT;
  129.                         break;
  130.                     }

  131.                     break;

  132.                 case 4:
  133.                     if (m[1] == 'O') {

  134.                         if (ngx_str3Ocmp(m, 'P', 'O', 'S', 'T')) {
  135.                             r->method = NGX_HTTP_POST;
  136.                             break;
  137.                         }

  138.                         if (ngx_str3Ocmp(m, 'C', 'O', 'P', 'Y')) {
  139.                             r->method = NGX_HTTP_COPY;
  140.                             break;
  141.                         }

  142.                         if (ngx_str3Ocmp(m, 'M', 'O', 'V', 'E')) {
  143.                             r->method = NGX_HTTP_MOVE;
  144.                             break;
  145.                         }

  146.                         if (ngx_str3Ocmp(m, 'L', 'O', 'C', 'K')) {
  147.                             r->method = NGX_HTTP_LOCK;
  148.                             break;
  149.                         }

  150.                     } else {

  151.                         if (ngx_str4cmp(m, 'H', 'E', 'A', 'D')) {
  152.                             r->method = NGX_HTTP_HEAD;
  153.                             break;
  154.                         }
  155.                     }

  156.                     break;

  157.                 case 5:
  158.                     if (ngx_str5cmp(m, 'M', 'K', 'C', 'O', 'L')) {
  159.                         r->method = NGX_HTTP_MKCOL;
  160.                         break;
  161.                     }

  162.                     if (ngx_str5cmp(m, 'P', 'A', 'T', 'C', 'H')) {
  163.                         r->method = NGX_HTTP_PATCH;
  164.                         break;
  165.                     }

  166.                     if (ngx_str5cmp(m, 'T', 'R', 'A', 'C', 'E')) {
  167.                         r->method = NGX_HTTP_TRACE;
  168.                         break;
  169.                     }

  170.                     break;

  171.                 case 6:
  172.                     if (ngx_str6cmp(m, 'D', 'E', 'L', 'E', 'T', 'E')) {
  173.                         r->method = NGX_HTTP_DELETE;
  174.                         break;
  175.                     }

  176.                     if (ngx_str6cmp(m, 'U', 'N', 'L', 'O', 'C', 'K')) {
  177.                         r->method = NGX_HTTP_UNLOCK;
  178.                         break;
  179.                     }

  180.                     break;

  181.                 case 7:
  182.                     if (ngx_str7_cmp(m, 'O', 'P', 'T', 'I', 'O', 'N', 'S', ' '))
  183.                     {
  184.                         r->method = NGX_HTTP_OPTIONS;
  185.                     }

  186.                     if (ngx_str7_cmp(m, 'C', 'O', 'N', 'N', 'E', 'C', 'T', ' '))
  187.                     {
  188.                         r->method = NGX_HTTP_CONNECT;
  189.                     }

  190.                     break;

  191.                 case 8:
  192.                     if (ngx_str8cmp(m, 'P', 'R', 'O', 'P', 'F', 'I', 'N', 'D'))
  193.                     {
  194.                         r->method = NGX_HTTP_PROPFIND;
  195.                     }

  196.                     break;

  197.                 case 9:
  198.                     if (ngx_str9cmp(m,
  199.                             'P', 'R', 'O', 'P', 'P', 'A', 'T', 'C', 'H'))
  200.                     {
  201.                         r->method = NGX_HTTP_PROPPATCH;
  202.                     }

  203.                     break;
  204.                 }

  205.                 state = sw_spaces_before_uri;
  206.                 break;
  207.             }

  208.             if ((ch < 'A' || ch > 'Z') && ch != '_' && ch != '-') {
  209.                 return NGX_HTTP_PARSE_INVALID_METHOD;
  210.             }

  211.             break;

  212.         /* space* before URI */
  213.         case sw_spaces_before_uri:

  214.             if (ch == '/') {
  215.                 r->uri_start = p;
  216.                 state = sw_after_slash_in_uri;
  217.                 break;
  218.             }

  219.             c = (u_char) (ch | 0x20);
  220.             if (c >= 'a' && c <= 'z') {
  221.                 r->schema_start = p;
  222.                 state = sw_schema;
  223.                 break;
  224.             }

  225.             switch (ch) {
  226.             case ' ':
  227.                 break;
  228.             default:
  229.                 return NGX_HTTP_PARSE_INVALID_REQUEST;
  230.             }
  231.             break;

  232.         case sw_schema:

  233.             c = (u_char) (ch | 0x20);
  234.             if (c >= 'a' && c <= 'z') {
  235.                 break;
  236.             }

  237.             if ((ch >= '0' && ch <= '9') || ch == '+' || ch == '-' || ch == '.')
  238.             {
  239.                 break;
  240.             }

  241.             switch (ch) {
  242.             case ':':
  243.                 r->schema_end = p;
  244.                 state = sw_schema_slash;
  245.                 break;
  246.             default:
  247.                 return NGX_HTTP_PARSE_INVALID_REQUEST;
  248.             }
  249.             break;

  250.         case sw_schema_slash:
  251.             switch (ch) {
  252.             case '/':
  253.                 state = sw_schema_slash_slash;
  254.                 break;
  255.             default:
  256.                 return NGX_HTTP_PARSE_INVALID_REQUEST;
  257.             }
  258.             break;

  259.         case sw_schema_slash_slash:
  260.             switch (ch) {
  261.             case '/':
  262.                 state = sw_host_start;
  263.                 break;
  264.             default:
  265.                 return NGX_HTTP_PARSE_INVALID_REQUEST;
  266.             }
  267.             break;

  268.         case sw_host_start:

  269.             r->host_start = p;

  270.             if (ch == '[') {
  271.                 state = sw_host_ip_literal;
  272.                 break;
  273.             }

  274.             state = sw_host;

  275.             /* fall through */

  276.         case sw_host:

  277.             c = (u_char) (ch | 0x20);
  278.             if (c >= 'a' && c <= 'z') {
  279.                 break;
  280.             }

  281.             if ((ch >= '0' && ch <= '9') || ch == '.' || ch == '-') {
  282.                 break;
  283.             }

  284.             /* fall through */

  285.         case sw_host_end:

  286.             r->host_end = p;

  287.             switch (ch) {
  288.             case ':':
  289.                 state = sw_port;
  290.                 break;
  291.             case '/':
  292.                 r->uri_start = p;
  293.                 state = sw_after_slash_in_uri;
  294.                 break;
  295.             case '?':
  296.                 r->uri_start = p;
  297.                 r->args_start = p + 1;
  298.                 r->empty_path_in_uri = 1;
  299.                 state = sw_uri;
  300.                 break;
  301.             case ' ':
  302.                 /*
  303.                  * use single "/" from request line to preserve pointers,
  304.                  * if request line will be copied to large client buffer
  305.                  */
  306.                 r->uri_start = r->schema_end + 1;
  307.                 r->uri_end = r->schema_end + 2;
  308.                 state = sw_http_09;
  309.                 break;
  310.             default:
  311.                 return NGX_HTTP_PARSE_INVALID_REQUEST;
  312.             }
  313.             break;

  314.         case sw_host_ip_literal:

  315.             if (ch >= '0' && ch <= '9') {
  316.                 break;
  317.             }

  318.             c = (u_char) (ch | 0x20);
  319.             if (c >= 'a' && c <= 'z') {
  320.                 break;
  321.             }

  322.             switch (ch) {
  323.             case ':':
  324.                 break;
  325.             case ']':
  326.                 state = sw_host_end;
  327.                 break;
  328.             case '-':
  329.             case '.':
  330.             case '_':
  331.             case '~':
  332.                 /* unreserved */
  333.                 break;
  334.             case '!':
  335.             case '$':
  336.             case '&':
  337.             case '\'':
  338.             case '(':
  339.             case ')':
  340.             case '*':
  341.             case '+':
  342.             case ',':
  343.             case ';':
  344.             case '=':
  345.                 /* sub-delims */
  346.                 break;
  347.             default:
  348.                 return NGX_HTTP_PARSE_INVALID_REQUEST;
  349.             }
  350.             break;

  351.         case sw_port:
  352.             if (ch >= '0' && ch <= '9') {
  353.                 break;
  354.             }

  355.             switch (ch) {
  356.             case '/':
  357.                 r->uri_start = p;
  358.                 state = sw_after_slash_in_uri;
  359.                 break;
  360.             case '?':
  361.                 r->uri_start = p;
  362.                 r->args_start = p + 1;
  363.                 r->empty_path_in_uri = 1;
  364.                 state = sw_uri;
  365.                 break;
  366.             case ' ':
  367.                 /*
  368.                  * use single "/" from request line to preserve pointers,
  369.                  * if request line will be copied to large client buffer
  370.                  */
  371.                 r->uri_start = r->schema_end + 1;
  372.                 r->uri_end = r->schema_end + 2;
  373.                 state = sw_http_09;
  374.                 break;
  375.             default:
  376.                 return NGX_HTTP_PARSE_INVALID_REQUEST;
  377.             }
  378.             break;

  379.         /* check "/.", "//", "%", and "\" (Win32) in URI */
  380.         case sw_after_slash_in_uri:

  381.             if (usual[ch >> 5] & (1U << (ch & 0x1f))) {
  382.                 state = sw_check_uri;
  383.                 break;
  384.             }

  385.             switch (ch) {
  386.             case ' ':
  387.                 r->uri_end = p;
  388.                 state = sw_http_09;
  389.                 break;
  390.             case CR:
  391.                 r->uri_end = p;
  392.                 r->http_minor = 9;
  393.                 state = sw_almost_done;
  394.                 break;
  395.             case LF:
  396.                 r->uri_end = p;
  397.                 r->http_minor = 9;
  398.                 goto done;
  399.             case '.':
  400.                 r->complex_uri = 1;
  401.                 state = sw_uri;
  402.                 break;
  403.             case '%':
  404.                 r->quoted_uri = 1;
  405.                 state = sw_uri;
  406.                 break;
  407.             case '/':
  408.                 r->complex_uri = 1;
  409.                 state = sw_uri;
  410.                 break;
  411. #if (NGX_WIN32)
  412.             case '\\':
  413.                 r->complex_uri = 1;
  414.                 state = sw_uri;
  415.                 break;
  416. #endif
  417.             case '?':
  418.                 r->args_start = p + 1;
  419.                 state = sw_uri;
  420.                 break;
  421.             case '#':
  422.                 r->complex_uri = 1;
  423.                 state = sw_uri;
  424.                 break;
  425.             case '+':
  426.                 r->plus_in_uri = 1;
  427.                 break;
  428.             default:
  429.                 if (ch < 0x20 || ch == 0x7f) {
  430.                     return NGX_HTTP_PARSE_INVALID_REQUEST;
  431.                 }
  432.                 state = sw_check_uri;
  433.                 break;
  434.             }
  435.             break;

  436.         /* check "/", "%" and "\" (Win32) in URI */
  437.         case sw_check_uri:

  438.             if (usual[ch >> 5] & (1U << (ch & 0x1f))) {
  439.                 break;
  440.             }

  441.             switch (ch) {
  442.             case '/':
  443. #if (NGX_WIN32)
  444.                 if (r->uri_ext == p) {
  445.                     r->complex_uri = 1;
  446.                     state = sw_uri;
  447.                     break;
  448.                 }
  449. #endif
  450.                 r->uri_ext = NULL;
  451.                 state = sw_after_slash_in_uri;
  452.                 break;
  453.             case '.':
  454.                 r->uri_ext = p + 1;
  455.                 break;
  456.             case ' ':
  457.                 r->uri_end = p;
  458.                 state = sw_http_09;
  459.                 break;
  460.             case CR:
  461.                 r->uri_end = p;
  462.                 r->http_minor = 9;
  463.                 state = sw_almost_done;
  464.                 break;
  465.             case LF:
  466.                 r->uri_end = p;
  467.                 r->http_minor = 9;
  468.                 goto done;
  469. #if (NGX_WIN32)
  470.             case '\\':
  471.                 r->complex_uri = 1;
  472.                 state = sw_after_slash_in_uri;
  473.                 break;
  474. #endif
  475.             case '%':
  476.                 r->quoted_uri = 1;
  477.                 state = sw_uri;
  478.                 break;
  479.             case '?':
  480.                 r->args_start = p + 1;
  481.                 state = sw_uri;
  482.                 break;
  483.             case '#':
  484.                 r->complex_uri = 1;
  485.                 state = sw_uri;
  486.                 break;
  487.             case '+':
  488.                 r->plus_in_uri = 1;
  489.                 break;
  490.             default:
  491.                 if (ch < 0x20 || ch == 0x7f) {
  492.                     return NGX_HTTP_PARSE_INVALID_REQUEST;
  493.                 }
  494.                 break;
  495.             }
  496.             break;

  497.         /* URI */
  498.         case sw_uri:

  499.             if (usual[ch >> 5] & (1U << (ch & 0x1f))) {
  500.                 break;
  501.             }

  502.             switch (ch) {
  503.             case ' ':
  504.                 r->uri_end = p;
  505.                 state = sw_http_09;
  506.                 break;
  507.             case CR:
  508.                 r->uri_end = p;
  509.                 r->http_minor = 9;
  510.                 state = sw_almost_done;
  511.                 break;
  512.             case LF:
  513.                 r->uri_end = p;
  514.                 r->http_minor = 9;
  515.                 goto done;
  516.             case '#':
  517.                 r->complex_uri = 1;
  518.                 break;
  519.             default:
  520.                 if (ch < 0x20 || ch == 0x7f) {
  521.                     return NGX_HTTP_PARSE_INVALID_REQUEST;
  522.                 }
  523.                 break;
  524.             }
  525.             break;

  526.         /* space+ after URI */
  527.         case sw_http_09:
  528.             switch (ch) {
  529.             case ' ':
  530.                 break;
  531.             case CR:
  532.                 r->http_minor = 9;
  533.                 state = sw_almost_done;
  534.                 break;
  535.             case LF:
  536.                 r->http_minor = 9;
  537.                 goto done;
  538.             case 'H':
  539.                 r->http_protocol.data = p;
  540.                 state = sw_http_H;
  541.                 break;
  542.             default:
  543.                 return NGX_HTTP_PARSE_INVALID_REQUEST;
  544.             }
  545.             break;

  546.         case sw_http_H:
  547.             switch (ch) {
  548.             case 'T':
  549.                 state = sw_http_HT;
  550.                 break;
  551.             default:
  552.                 return NGX_HTTP_PARSE_INVALID_REQUEST;
  553.             }
  554.             break;

  555.         case sw_http_HT:
  556.             switch (ch) {
  557.             case 'T':
  558.                 state = sw_http_HTT;
  559.                 break;
  560.             default:
  561.                 return NGX_HTTP_PARSE_INVALID_REQUEST;
  562.             }
  563.             break;

  564.         case sw_http_HTT:
  565.             switch (ch) {
  566.             case 'P':
  567.                 state = sw_http_HTTP;
  568.                 break;
  569.             default:
  570.                 return NGX_HTTP_PARSE_INVALID_REQUEST;
  571.             }
  572.             break;

  573.         case sw_http_HTTP:
  574.             switch (ch) {
  575.             case '/':
  576.                 state = sw_first_major_digit;
  577.                 break;
  578.             default:
  579.                 return NGX_HTTP_PARSE_INVALID_REQUEST;
  580.             }
  581.             break;

  582.         /* first digit of major HTTP version */
  583.         case sw_first_major_digit:
  584.             if (ch < '1' || ch > '9') {
  585.                 return NGX_HTTP_PARSE_INVALID_REQUEST;
  586.             }

  587.             r->http_major = ch - '0';

  588.             if (r->http_major > 1) {
  589.                 return NGX_HTTP_PARSE_INVALID_VERSION;
  590.             }

  591.             state = sw_major_digit;
  592.             break;

  593.         /* major HTTP version or dot */
  594.         case sw_major_digit:
  595.             if (ch == '.') {
  596.                 state = sw_first_minor_digit;
  597.                 break;
  598.             }

  599.             if (ch < '0' || ch > '9') {
  600.                 return NGX_HTTP_PARSE_INVALID_REQUEST;
  601.             }

  602.             r->http_major = r->http_major * 10 + (ch - '0');

  603.             if (r->http_major > 1) {
  604.                 return NGX_HTTP_PARSE_INVALID_VERSION;
  605.             }

  606.             break;

  607.         /* first digit of minor HTTP version */
  608.         case sw_first_minor_digit:
  609.             if (ch < '0' || ch > '9') {
  610.                 return NGX_HTTP_PARSE_INVALID_REQUEST;
  611.             }

  612.             r->http_minor = ch - '0';
  613.             state = sw_minor_digit;
  614.             break;

  615.         /* minor HTTP version or end of request line */
  616.         case sw_minor_digit:
  617.             if (ch == CR) {
  618.                 state = sw_almost_done;
  619.                 break;
  620.             }

  621.             if (ch == LF) {
  622.                 goto done;
  623.             }

  624.             if (ch == ' ') {
  625.                 state = sw_spaces_after_digit;
  626.                 break;
  627.             }

  628.             if (ch < '0' || ch > '9') {
  629.                 return NGX_HTTP_PARSE_INVALID_REQUEST;
  630.             }

  631.             if (r->http_minor > 99) {
  632.                 return NGX_HTTP_PARSE_INVALID_REQUEST;
  633.             }

  634.             r->http_minor = r->http_minor * 10 + (ch - '0');
  635.             break;

  636.         case sw_spaces_after_digit:
  637.             switch (ch) {
  638.             case ' ':
  639.                 break;
  640.             case CR:
  641.                 state = sw_almost_done;
  642.                 break;
  643.             case LF:
  644.                 goto done;
  645.             default:
  646.                 return NGX_HTTP_PARSE_INVALID_REQUEST;
  647.             }
  648.             break;

  649.         /* end of request line */
  650.         case sw_almost_done:
  651.             r->request_end = p - 1;
  652.             switch (ch) {
  653.             case LF:
  654.                 goto done;
  655.             default:
  656.                 return NGX_HTTP_PARSE_INVALID_REQUEST;
  657.             }
  658.         }
  659.     }

  660.     b->pos = p;
  661.     r->state = state;

  662.     return NGX_AGAIN;

  663. done:

  664.     b->pos = p + 1;

  665.     if (r->request_end == NULL) {
  666.         r->request_end = p;
  667.     }

  668.     r->http_version = r->http_major * 1000 + r->http_minor;
  669.     r->state = sw_start;

  670.     if (r->http_version == 9 && r->method != NGX_HTTP_GET) {
  671.         return NGX_HTTP_PARSE_INVALID_09_METHOD;
  672.     }

  673.     return NGX_OK;
  674. }


  675. ngx_int_t
  676. ngx_http_parse_header_line(ngx_http_request_t *r, ngx_buf_t *b,
  677.     ngx_uint_t allow_underscores)
  678. {
  679.     u_char      c, ch, *p;
  680.     ngx_uint_t  hash, i;
  681.     enum {
  682.         sw_start = 0,
  683.         sw_name,
  684.         sw_space_before_value,
  685.         sw_value,
  686.         sw_space_after_value,
  687.         sw_ignore_line,
  688.         sw_almost_done,
  689.         sw_header_almost_done
  690.     } state;

  691.     /* the last '\0' is not needed because string is zero terminated */

  692.     static u_char  lowcase[] =
  693.         "\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"
  694.         "\0\0\0\0\0\0\0\0\0\0\0\0\0-\0\0" "0123456789\0\0\0\0\0\0"
  695.         "\0abcdefghijklmnopqrstuvwxyz\0\0\0\0\0"
  696.         "\0abcdefghijklmnopqrstuvwxyz\0\0\0\0\0"
  697.         "\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"
  698.         "\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"
  699.         "\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"
  700.         "\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";

  701.     state = r->state;
  702.     hash = r->header_hash;
  703.     i = r->lowcase_index;

  704.     for (p = b->pos; p < b->last; p++) {
  705.         ch = *p;

  706.         switch (state) {

  707.         /* first char */
  708.         case sw_start:
  709.             r->header_name_start = p;
  710.             r->invalid_header = 0;

  711.             switch (ch) {
  712.             case CR:
  713.                 r->header_end = p;
  714.                 state = sw_header_almost_done;
  715.                 break;
  716.             case LF:
  717.                 r->header_end = p;
  718.                 goto header_done;
  719.             default:
  720.                 state = sw_name;

  721.                 c = lowcase[ch];

  722.                 if (c) {
  723.                     hash = ngx_hash(0, c);
  724.                     r->lowcase_header[0] = c;
  725.                     i = 1;
  726.                     break;
  727.                 }

  728.                 if (ch == '_') {
  729.                     if (allow_underscores) {
  730.                         hash = ngx_hash(0, ch);
  731.                         r->lowcase_header[0] = ch;
  732.                         i = 1;

  733.                     } else {
  734.                         hash = 0;
  735.                         i = 0;
  736.                         r->invalid_header = 1;
  737.                     }

  738.                     break;
  739.                 }

  740.                 if (ch <= 0x20 || ch == 0x7f || ch == ':') {
  741.                     r->header_end = p;
  742.                     return NGX_HTTP_PARSE_INVALID_HEADER;
  743.                 }

  744.                 hash = 0;
  745.                 i = 0;
  746.                 r->invalid_header = 1;

  747.                 break;

  748.             }
  749.             break;

  750.         /* header name */
  751.         case sw_name:
  752.             c = lowcase[ch];

  753.             if (c) {
  754.                 hash = ngx_hash(hash, c);
  755.                 r->lowcase_header[i++] = c;
  756.                 i &= (NGX_HTTP_LC_HEADER_LEN - 1);
  757.                 break;
  758.             }

  759.             if (ch == '_') {
  760.                 if (allow_underscores) {
  761.                     hash = ngx_hash(hash, ch);
  762.                     r->lowcase_header[i++] = ch;
  763.                     i &= (NGX_HTTP_LC_HEADER_LEN - 1);

  764.                 } else {
  765.                     r->invalid_header = 1;
  766.                 }

  767.                 break;
  768.             }

  769.             if (ch == ':') {
  770.                 r->header_name_end = p;
  771.                 state = sw_space_before_value;
  772.                 break;
  773.             }

  774.             if (ch == CR) {
  775.                 r->header_name_end = p;
  776.                 r->header_start = p;
  777.                 r->header_end = p;
  778.                 state = sw_almost_done;
  779.                 break;
  780.             }

  781.             if (ch == LF) {
  782.                 r->header_name_end = p;
  783.                 r->header_start = p;
  784.                 r->header_end = p;
  785.                 goto done;
  786.             }

  787.             /* IIS may send the duplicate "HTTP/1.1 ..." lines */
  788.             if (ch == '/'
  789.                 && r->upstream
  790.                 && p - r->header_name_start == 4
  791.                 && ngx_strncmp(r->header_name_start, "HTTP", 4) == 0)
  792.             {
  793.                 state = sw_ignore_line;
  794.                 break;
  795.             }

  796.             if (ch <= 0x20 || ch == 0x7f) {
  797.                 r->header_end = p;
  798.                 return NGX_HTTP_PARSE_INVALID_HEADER;
  799.             }

  800.             r->invalid_header = 1;

  801.             break;

  802.         /* space* before header value */
  803.         case sw_space_before_value:
  804.             switch (ch) {
  805.             case ' ':
  806.                 break;
  807.             case CR:
  808.                 r->header_start = p;
  809.                 r->header_end = p;
  810.                 state = sw_almost_done;
  811.                 break;
  812.             case LF:
  813.                 r->header_start = p;
  814.                 r->header_end = p;
  815.                 goto done;
  816.             case '\0':
  817.                 r->header_end = p;
  818.                 return NGX_HTTP_PARSE_INVALID_HEADER;
  819.             default:
  820.                 r->header_start = p;
  821.                 state = sw_value;
  822.                 break;
  823.             }
  824.             break;

  825.         /* header value */
  826.         case sw_value:
  827.             switch (ch) {
  828.             case ' ':
  829.                 r->header_end = p;
  830.                 state = sw_space_after_value;
  831.                 break;
  832.             case CR:
  833.                 r->header_end = p;
  834.                 state = sw_almost_done;
  835.                 break;
  836.             case LF:
  837.                 r->header_end = p;
  838.                 goto done;
  839.             case '\0':
  840.                 r->header_end = p;
  841.                 return NGX_HTTP_PARSE_INVALID_HEADER;
  842.             }
  843.             break;

  844.         /* space* before end of header line */
  845.         case sw_space_after_value:
  846.             switch (ch) {
  847.             case ' ':
  848.                 break;
  849.             case CR:
  850.                 state = sw_almost_done;
  851.                 break;
  852.             case LF:
  853.                 goto done;
  854.             case '\0':
  855.                 r->header_end = p;
  856.                 return NGX_HTTP_PARSE_INVALID_HEADER;
  857.             default:
  858.                 state = sw_value;
  859.                 break;
  860.             }
  861.             break;

  862.         /* ignore header line */
  863.         case sw_ignore_line:
  864.             switch (ch) {
  865.             case LF:
  866.                 state = sw_start;
  867.                 break;
  868.             default:
  869.                 break;
  870.             }
  871.             break;

  872.         /* end of header line */
  873.         case sw_almost_done:
  874.             switch (ch) {
  875.             case LF:
  876.                 goto done;
  877.             case CR:
  878.                 break;
  879.             default:
  880.                 return NGX_HTTP_PARSE_INVALID_HEADER;
  881.             }
  882.             break;

  883.         /* end of header */
  884.         case sw_header_almost_done:
  885.             switch (ch) {
  886.             case LF:
  887.                 goto header_done;
  888.             default:
  889.                 return NGX_HTTP_PARSE_INVALID_HEADER;
  890.             }
  891.         }
  892.     }

  893.     b->pos = p;
  894.     r->state = state;
  895.     r->header_hash = hash;
  896.     r->lowcase_index = i;

  897.     return NGX_AGAIN;

  898. done:

  899.     b->pos = p + 1;
  900.     r->state = sw_start;
  901.     r->header_hash = hash;
  902.     r->lowcase_index = i;

  903.     return NGX_OK;

  904. header_done:

  905.     b->pos = p + 1;
  906.     r->state = sw_start;

  907.     return NGX_HTTP_PARSE_HEADER_DONE;
  908. }


  909. ngx_int_t
  910. ngx_http_parse_uri(ngx_http_request_t *r)
  911. {
  912.     u_char  *p, ch;
  913.     enum {
  914.         sw_start = 0,
  915.         sw_after_slash_in_uri,
  916.         sw_check_uri,
  917.         sw_uri
  918.     } state;

  919.     state = sw_start;

  920.     for (p = r->uri_start; p != r->uri_end; p++) {

  921.         ch = *p;

  922.         switch (state) {

  923.         case sw_start:

  924.             if (ch != '/') {
  925.                 return NGX_ERROR;
  926.             }

  927.             state = sw_after_slash_in_uri;
  928.             break;

  929.         /* check "/.", "//", "%", and "\" (Win32) in URI */
  930.         case sw_after_slash_in_uri:

  931.             if (usual[ch >> 5] & (1U << (ch & 0x1f))) {
  932.                 state = sw_check_uri;
  933.                 break;
  934.             }

  935.             switch (ch) {
  936.             case '.':
  937.                 r->complex_uri = 1;
  938.                 state = sw_uri;
  939.                 break;
  940.             case '%':
  941.                 r->quoted_uri = 1;
  942.                 state = sw_uri;
  943.                 break;
  944.             case '/':
  945.                 r->complex_uri = 1;
  946.                 state = sw_uri;
  947.                 break;
  948. #if (NGX_WIN32)
  949.             case '\\':
  950.                 r->complex_uri = 1;
  951.                 state = sw_uri;
  952.                 break;
  953. #endif
  954.             case '?':
  955.                 r->args_start = p + 1;
  956.                 state = sw_uri;
  957.                 break;
  958.             case '#':
  959.                 r->complex_uri = 1;
  960.                 state = sw_uri;
  961.                 break;
  962.             case '+':
  963.                 r->plus_in_uri = 1;
  964.                 break;
  965.             default:
  966.                 if (ch <= 0x20 || ch == 0x7f) {
  967.                     return NGX_ERROR;
  968.                 }
  969.                 state = sw_check_uri;
  970.                 break;
  971.             }
  972.             break;

  973.         /* check "/", "%" and "\" (Win32) in URI */
  974.         case sw_check_uri:

  975.             if (usual[ch >> 5] & (1U << (ch & 0x1f))) {
  976.                 break;
  977.             }

  978.             switch (ch) {
  979.             case '/':
  980. #if (NGX_WIN32)
  981.                 if (r->uri_ext == p) {
  982.                     r->complex_uri = 1;
  983.                     state = sw_uri;
  984.                     break;
  985.                 }
  986. #endif
  987.                 r->uri_ext = NULL;
  988.                 state = sw_after_slash_in_uri;
  989.                 break;
  990.             case '.':
  991.                 r->uri_ext = p + 1;
  992.                 break;
  993. #if (NGX_WIN32)
  994.             case '\\':
  995.                 r->complex_uri = 1;
  996.                 state = sw_after_slash_in_uri;
  997.                 break;
  998. #endif
  999.             case '%':
  1000.                 r->quoted_uri = 1;
  1001.                 state = sw_uri;
  1002.                 break;
  1003.             case '?':
  1004.                 r->args_start = p + 1;
  1005.                 state = sw_uri;
  1006.                 break;
  1007.             case '#':
  1008.                 r->complex_uri = 1;
  1009.                 state = sw_uri;
  1010.                 break;
  1011.             case '+':
  1012.                 r->plus_in_uri = 1;
  1013.                 break;
  1014.             default:
  1015.                 if (ch <= 0x20 || ch == 0x7f) {
  1016.                     return NGX_ERROR;
  1017.                 }
  1018.                 break;
  1019.             }
  1020.             break;

  1021.         /* URI */
  1022.         case sw_uri:

  1023.             if (usual[ch >> 5] & (1U << (ch & 0x1f))) {
  1024.                 break;
  1025.             }

  1026.             switch (ch) {
  1027.             case '#':
  1028.                 r->complex_uri = 1;
  1029.                 break;
  1030.             default:
  1031.                 if (ch <= 0x20 || ch == 0x7f) {
  1032.                     return NGX_ERROR;
  1033.                 }
  1034.                 break;
  1035.             }
  1036.             break;
  1037.         }
  1038.     }

  1039.     return NGX_OK;
  1040. }


  1041. ngx_int_t
  1042. ngx_http_parse_complex_uri(ngx_http_request_t *r, ngx_uint_t merge_slashes)
  1043. {
  1044.     u_char  c, ch, decoded, *p, *u;
  1045.     enum {
  1046.         sw_usual = 0,
  1047.         sw_slash,
  1048.         sw_dot,
  1049.         sw_dot_dot,
  1050.         sw_quoted,
  1051.         sw_quoted_second
  1052.     } state, quoted_state;

  1053. #if (NGX_SUPPRESS_WARN)
  1054.     decoded = '\0';
  1055.     quoted_state = sw_usual;
  1056. #endif

  1057.     state = sw_usual;
  1058.     p = r->uri_start;
  1059.     u = r->uri.data;
  1060.     r->uri_ext = NULL;
  1061.     r->args_start = NULL;

  1062.     if (r->empty_path_in_uri) {
  1063.         *u++ = '/';
  1064.     }

  1065.     ch = *p++;

  1066.     while (p <= r->uri_end) {

  1067.         /*
  1068.          * we use "ch = *p++" inside the cycle, but this operation is safe,
  1069.          * because after the URI there is always at least one character:
  1070.          * the line feed
  1071.          */

  1072.         ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  1073.                        "s:%d in:'%Xd:%c'", state, ch, ch);

  1074.         switch (state) {

  1075.         case sw_usual:

  1076.             if (usual[ch >> 5] & (1U << (ch & 0x1f))) {
  1077.                 *u++ = ch;
  1078.                 ch = *p++;
  1079.                 break;
  1080.             }

  1081.             switch (ch) {
  1082. #if (NGX_WIN32)
  1083.             case '\\':
  1084.                 if (u - 2 >= r->uri.data
  1085.                     && *(u - 1) == '.' && *(u - 2) != '.')
  1086.                 {
  1087.                     u--;
  1088.                 }

  1089.                 r->uri_ext = NULL;

  1090.                 if (p == r->uri_start + r->uri.len) {

  1091.                     /*
  1092.                      * we omit the last "\" to cause redirect because
  1093.                      * the browsers do not treat "\" as "/" in relative URL path
  1094.                      */

  1095.                     break;
  1096.                 }

  1097.                 state = sw_slash;
  1098.                 *u++ = '/';
  1099.                 break;
  1100. #endif
  1101.             case '/':
  1102. #if (NGX_WIN32)
  1103.                 if (u - 2 >= r->uri.data
  1104.                     && *(u - 1) == '.' && *(u - 2) != '.')
  1105.                 {
  1106.                     u--;
  1107.                 }
  1108. #endif
  1109.                 r->uri_ext = NULL;
  1110.                 state = sw_slash;
  1111.                 *u++ = ch;
  1112.                 break;
  1113.             case '%':
  1114.                 quoted_state = state;
  1115.                 state = sw_quoted;
  1116.                 break;
  1117.             case '?':
  1118.                 r->args_start = p;
  1119.                 goto args;
  1120.             case '#':
  1121.                 goto done;
  1122.             case '.':
  1123.                 r->uri_ext = u + 1;
  1124.                 *u++ = ch;
  1125.                 break;
  1126.             case '+':
  1127.                 r->plus_in_uri = 1;
  1128.                 /* fall through */
  1129.             default:
  1130.                 *u++ = ch;
  1131.                 break;
  1132.             }

  1133.             ch = *p++;
  1134.             break;

  1135.         case sw_slash:

  1136.             if (usual[ch >> 5] & (1U << (ch & 0x1f))) {
  1137.                 state = sw_usual;
  1138.                 *u++ = ch;
  1139.                 ch = *p++;
  1140.                 break;
  1141.             }

  1142.             switch (ch) {
  1143. #if (NGX_WIN32)
  1144.             case '\\':
  1145.                 break;
  1146. #endif
  1147.             case '/':
  1148.                 if (!merge_slashes) {
  1149.                     *u++ = ch;
  1150.                 }
  1151.                 break;
  1152.             case '.':
  1153.                 state = sw_dot;
  1154.                 *u++ = ch;
  1155.                 break;
  1156.             case '%':
  1157.                 quoted_state = state;
  1158.                 state = sw_quoted;
  1159.                 break;
  1160.             case '?':
  1161.                 r->args_start = p;
  1162.                 goto args;
  1163.             case '#':
  1164.                 goto done;
  1165.             case '+':
  1166.                 r->plus_in_uri = 1;
  1167.                 /* fall through */
  1168.             default:
  1169.                 state = sw_usual;
  1170.                 *u++ = ch;
  1171.                 break;
  1172.             }

  1173.             ch = *p++;
  1174.             break;

  1175.         case sw_dot:

  1176.             if (usual[ch >> 5] & (1U << (ch & 0x1f))) {
  1177.                 state = sw_usual;
  1178.                 *u++ = ch;
  1179.                 ch = *p++;
  1180.                 break;
  1181.             }

  1182.             switch (ch) {
  1183. #if (NGX_WIN32)
  1184.             case '\\':
  1185. #endif
  1186.             case '/':
  1187.                 state = sw_slash;
  1188.                 u--;
  1189.                 break;
  1190.             case '.':
  1191.                 state = sw_dot_dot;
  1192.                 *u++ = ch;
  1193.                 break;
  1194.             case '%':
  1195.                 quoted_state = state;
  1196.                 state = sw_quoted;
  1197.                 break;
  1198.             case '?':
  1199.                 u--;
  1200.                 r->args_start = p;
  1201.                 goto args;
  1202.             case '#':
  1203.                 u--;
  1204.                 goto done;
  1205.             case '+':
  1206.                 r->plus_in_uri = 1;
  1207.                 /* fall through */
  1208.             default:
  1209.                 state = sw_usual;
  1210.                 *u++ = ch;
  1211.                 break;
  1212.             }

  1213.             ch = *p++;
  1214.             break;

  1215.         case sw_dot_dot:

  1216.             if (usual[ch >> 5] & (1U << (ch & 0x1f))) {
  1217.                 state = sw_usual;
  1218.                 *u++ = ch;
  1219.                 ch = *p++;
  1220.                 break;
  1221.             }

  1222.             switch (ch) {
  1223. #if (NGX_WIN32)
  1224.             case '\\':
  1225. #endif
  1226.             case '/':
  1227.             case '?':
  1228.             case '#':
  1229.                 u -= 4;
  1230.                 for ( ;; ) {
  1231.                     if (u < r->uri.data) {
  1232.                         return NGX_HTTP_PARSE_INVALID_REQUEST;
  1233.                     }
  1234.                     if (*u == '/') {
  1235.                         u++;
  1236.                         break;
  1237.                     }
  1238.                     u--;
  1239.                 }
  1240.                 if (ch == '?') {
  1241.                     r->args_start = p;
  1242.                     goto args;
  1243.                 }
  1244.                 if (ch == '#') {
  1245.                     goto done;
  1246.                 }
  1247.                 state = sw_slash;
  1248.                 break;
  1249.             case '%':
  1250.                 quoted_state = state;
  1251.                 state = sw_quoted;
  1252.                 break;
  1253.             case '+':
  1254.                 r->plus_in_uri = 1;
  1255.                 /* fall through */
  1256.             default:
  1257.                 state = sw_usual;
  1258.                 *u++ = ch;
  1259.                 break;
  1260.             }

  1261.             ch = *p++;
  1262.             break;

  1263.         case sw_quoted:
  1264.             r->quoted_uri = 1;

  1265.             if (ch >= '0' && ch <= '9') {
  1266.                 decoded = (u_char) (ch - '0');
  1267.                 state = sw_quoted_second;
  1268.                 ch = *p++;
  1269.                 break;
  1270.             }

  1271.             c = (u_char) (ch | 0x20);
  1272.             if (c >= 'a' && c <= 'f') {
  1273.                 decoded = (u_char) (c - 'a' + 10);
  1274.                 state = sw_quoted_second;
  1275.                 ch = *p++;
  1276.                 break;
  1277.             }

  1278.             return NGX_HTTP_PARSE_INVALID_REQUEST;

  1279.         case sw_quoted_second:
  1280.             if (ch >= '0' && ch <= '9') {
  1281.                 ch = (u_char) ((decoded << 4) + (ch - '0'));

  1282.                 if (ch == '%' || ch == '#') {
  1283.                     state = sw_usual;
  1284.                     *u++ = ch;
  1285.                     ch = *p++;
  1286.                     break;

  1287.                 } else if (ch == '\0') {
  1288.                     return NGX_HTTP_PARSE_INVALID_REQUEST;
  1289.                 }

  1290.                 state = quoted_state;
  1291.                 break;
  1292.             }

  1293.             c = (u_char) (ch | 0x20);
  1294.             if (c >= 'a' && c <= 'f') {
  1295.                 ch = (u_char) ((decoded << 4) + (c - 'a') + 10);

  1296.                 if (ch == '?') {
  1297.                     state = sw_usual;
  1298.                     *u++ = ch;
  1299.                     ch = *p++;
  1300.                     break;

  1301.                 } else if (ch == '+') {
  1302.                     r->plus_in_uri = 1;
  1303.                 }

  1304.                 state = quoted_state;
  1305.                 break;
  1306.             }

  1307.             return NGX_HTTP_PARSE_INVALID_REQUEST;
  1308.         }
  1309.     }

  1310.     if (state == sw_quoted || state == sw_quoted_second) {
  1311.         return NGX_HTTP_PARSE_INVALID_REQUEST;
  1312.     }

  1313.     if (state == sw_dot) {
  1314.         u--;

  1315.     } else if (state == sw_dot_dot) {
  1316.         u -= 4;

  1317.         for ( ;; ) {
  1318.             if (u < r->uri.data) {
  1319.                 return NGX_HTTP_PARSE_INVALID_REQUEST;
  1320.             }

  1321.             if (*u == '/') {
  1322.                 u++;
  1323.                 break;
  1324.             }

  1325.             u--;
  1326.         }
  1327.     }

  1328. done:

  1329.     r->uri.len = u - r->uri.data;

  1330.     if (r->uri_ext) {
  1331.         r->exten.len = u - r->uri_ext;
  1332.         r->exten.data = r->uri_ext;
  1333.     }

  1334.     r->uri_ext = NULL;

  1335.     return NGX_OK;

  1336. args:

  1337.     while (p < r->uri_end) {
  1338.         if (*p++ != '#') {
  1339.             continue;
  1340.         }

  1341.         r->args.len = p - 1 - r->args_start;
  1342.         r->args.data = r->args_start;
  1343.         r->args_start = NULL;

  1344.         break;
  1345.     }

  1346.     r->uri.len = u - r->uri.data;

  1347.     if (r->uri_ext) {
  1348.         r->exten.len = u - r->uri_ext;
  1349.         r->exten.data = r->uri_ext;
  1350.     }

  1351.     r->uri_ext = NULL;

  1352.     return NGX_OK;
  1353. }


  1354. ngx_int_t
  1355. ngx_http_parse_status_line(ngx_http_request_t *r, ngx_buf_t *b,
  1356.     ngx_http_status_t *status)
  1357. {
  1358.     u_char   ch;
  1359.     u_char  *p;
  1360.     enum {
  1361.         sw_start = 0,
  1362.         sw_H,
  1363.         sw_HT,
  1364.         sw_HTT,
  1365.         sw_HTTP,
  1366.         sw_first_major_digit,
  1367.         sw_major_digit,
  1368.         sw_first_minor_digit,
  1369.         sw_minor_digit,
  1370.         sw_status,
  1371.         sw_space_after_status,
  1372.         sw_status_text,
  1373.         sw_almost_done
  1374.     } state;

  1375.     state = r->state;

  1376.     for (p = b->pos; p < b->last; p++) {
  1377.         ch = *p;

  1378.         switch (state) {

  1379.         /* "HTTP/" */
  1380.         case sw_start:
  1381.             switch (ch) {
  1382.             case 'H':
  1383.                 state = sw_H;
  1384.                 break;
  1385.             default:
  1386.                 return NGX_ERROR;
  1387.             }
  1388.             break;

  1389.         case sw_H:
  1390.             switch (ch) {
  1391.             case 'T':
  1392.                 state = sw_HT;
  1393.                 break;
  1394.             default:
  1395.                 return NGX_ERROR;
  1396.             }
  1397.             break;

  1398.         case sw_HT:
  1399.             switch (ch) {
  1400.             case 'T':
  1401.                 state = sw_HTT;
  1402.                 break;
  1403.             default:
  1404.                 return NGX_ERROR;
  1405.             }
  1406.             break;

  1407.         case sw_HTT:
  1408.             switch (ch) {
  1409.             case 'P':
  1410.                 state = sw_HTTP;
  1411.                 break;
  1412.             default:
  1413.                 return NGX_ERROR;
  1414.             }
  1415.             break;

  1416.         case sw_HTTP:
  1417.             switch (ch) {
  1418.             case '/':
  1419.                 state = sw_first_major_digit;
  1420.                 break;
  1421.             default:
  1422.                 return NGX_ERROR;
  1423.             }
  1424.             break;

  1425.         /* the first digit of major HTTP version */
  1426.         case sw_first_major_digit:
  1427.             if (ch < '1' || ch > '9') {
  1428.                 return NGX_ERROR;
  1429.             }

  1430.             r->http_major = ch - '0';
  1431.             state = sw_major_digit;
  1432.             break;

  1433.         /* the major HTTP version or dot */
  1434.         case sw_major_digit:
  1435.             if (ch == '.') {
  1436.                 state = sw_first_minor_digit;
  1437.                 break;
  1438.             }

  1439.             if (ch < '0' || ch > '9') {
  1440.                 return NGX_ERROR;
  1441.             }

  1442.             if (r->http_major > 99) {
  1443.                 return NGX_ERROR;
  1444.             }

  1445.             r->http_major = r->http_major * 10 + (ch - '0');
  1446.             break;

  1447.         /* the first digit of minor HTTP version */
  1448.         case sw_first_minor_digit:
  1449.             if (ch < '0' || ch > '9') {
  1450.                 return NGX_ERROR;
  1451.             }

  1452.             r->http_minor = ch - '0';
  1453.             state = sw_minor_digit;
  1454.             break;

  1455.         /* the minor HTTP version or the end of the request line */
  1456.         case sw_minor_digit:
  1457.             if (ch == ' ') {
  1458.                 state = sw_status;
  1459.                 break;
  1460.             }

  1461.             if (ch < '0' || ch > '9') {
  1462.                 return NGX_ERROR;
  1463.             }

  1464.             if (r->http_minor > 99) {
  1465.                 return NGX_ERROR;
  1466.             }

  1467.             r->http_minor = r->http_minor * 10 + (ch - '0');
  1468.             break;

  1469.         /* HTTP status code */
  1470.         case sw_status:
  1471.             if (ch == ' ') {
  1472.                 break;
  1473.             }

  1474.             if (ch < '0' || ch > '9') {
  1475.                 return NGX_ERROR;
  1476.             }

  1477.             status->code = status->code * 10 + (ch - '0');

  1478.             if (++status->count == 3) {
  1479.                 state = sw_space_after_status;
  1480.                 status->start = p - 2;
  1481.             }

  1482.             break;

  1483.         /* space or end of line */
  1484.         case sw_space_after_status:
  1485.             switch (ch) {
  1486.             case ' ':
  1487.                 state = sw_status_text;
  1488.                 break;
  1489.             case '.':                    /* IIS may send 403.1, 403.2, etc */
  1490.                 state = sw_status_text;
  1491.                 break;
  1492.             case CR:
  1493.                 state = sw_almost_done;
  1494.                 break;
  1495.             case LF:
  1496.                 goto done;
  1497.             default:
  1498.                 return NGX_ERROR;
  1499.             }
  1500.             break;

  1501.         /* any text until end of line */
  1502.         case sw_status_text:
  1503.             switch (ch) {
  1504.             case CR:
  1505.                 state = sw_almost_done;

  1506.                 break;
  1507.             case LF:
  1508.                 goto done;
  1509.             }
  1510.             break;

  1511.         /* end of status line */
  1512.         case sw_almost_done:
  1513.             status->end = p - 1;
  1514.             switch (ch) {
  1515.             case LF:
  1516.                 goto done;
  1517.             default:
  1518.                 return NGX_ERROR;
  1519.             }
  1520.         }
  1521.     }

  1522.     b->pos = p;
  1523.     r->state = state;

  1524.     return NGX_AGAIN;

  1525. done:

  1526.     b->pos = p + 1;

  1527.     if (status->end == NULL) {
  1528.         status->end = p;
  1529.     }

  1530.     status->http_version = r->http_major * 1000 + r->http_minor;
  1531.     r->state = sw_start;

  1532.     return NGX_OK;
  1533. }


  1534. ngx_int_t
  1535. ngx_http_parse_unsafe_uri(ngx_http_request_t *r, ngx_str_t *uri,
  1536.     ngx_str_t *args, ngx_uint_t *flags)
  1537. {
  1538.     u_char      ch, *p, *src, *dst;
  1539.     size_t      len;
  1540.     ngx_uint_t  quoted;

  1541.     len = uri->len;
  1542.     p = uri->data;
  1543.     quoted = 0;

  1544.     if (len == 0 || p[0] == '?') {
  1545.         goto unsafe;
  1546.     }

  1547.     if (p[0] == '.' && len > 1 && p[1] == '.'
  1548.         && (len == 2 || ngx_path_separator(p[2])))
  1549.     {
  1550.         goto unsafe;
  1551.     }

  1552.     for ( /* void */ ; len; len--) {

  1553.         ch = *p++;

  1554.         if (ch == '%') {
  1555.             quoted = 1;
  1556.             continue;
  1557.         }

  1558.         if (usual[ch >> 5] & (1U << (ch & 0x1f))) {
  1559.             continue;
  1560.         }

  1561.         if (ch == '?') {
  1562.             args->len = len - 1;
  1563.             args->data = p;
  1564.             uri->len -= len;

  1565.             break;
  1566.         }

  1567.         if (ch == '\0') {
  1568.             goto unsafe;
  1569.         }

  1570.         if (ngx_path_separator(ch) && len > 2) {

  1571.             /* detect "/../" and "/.." */

  1572.             if (p[0] == '.' && p[1] == '.'
  1573.                 && (len == 3 || ngx_path_separator(p[2])))
  1574.             {
  1575.                 goto unsafe;
  1576.             }
  1577.         }
  1578.     }

  1579.     if (quoted) {
  1580.         ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  1581.                        "escaped URI: \"%V\"", uri);

  1582.         src = uri->data;

  1583.         dst = ngx_pnalloc(r->pool, uri->len);
  1584.         if (dst == NULL) {
  1585.             return NGX_ERROR;
  1586.         }

  1587.         uri->data = dst;

  1588.         ngx_unescape_uri(&dst, &src, uri->len, 0);

  1589.         uri->len = dst - uri->data;

  1590.         ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  1591.                        "unescaped URI: \"%V\"", uri);

  1592.         len = uri->len;
  1593.         p = uri->data;

  1594.         if (p[0] == '.' && len > 1 && p[1] == '.'
  1595.             && (len == 2 || ngx_path_separator(p[2])))
  1596.         {
  1597.             goto unsafe;
  1598.         }

  1599.         for ( /* void */ ; len; len--) {

  1600.             ch = *p++;

  1601.             if (ch == '\0') {
  1602.                 goto unsafe;
  1603.             }

  1604.             if (ngx_path_separator(ch) && len > 2) {

  1605.                 /* detect "/../" and "/.." */

  1606.                 if (p[0] == '.' && p[1] == '.'
  1607.                     && (len == 3 || ngx_path_separator(p[2])))
  1608.                 {
  1609.                     goto unsafe;
  1610.                 }
  1611.             }
  1612.         }
  1613.     }

  1614.     return NGX_OK;

  1615. unsafe:

  1616.     if (*flags & NGX_HTTP_LOG_UNSAFE) {
  1617.         ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  1618.                       "unsafe URI \"%V\" was detected", uri);
  1619.     }

  1620.     return NGX_ERROR;
  1621. }


  1622. ngx_table_elt_t *
  1623. ngx_http_parse_multi_header_lines(ngx_http_request_t *r,
  1624.     ngx_table_elt_t *headers, ngx_str_t *name, ngx_str_t *value)
  1625. {
  1626.     u_char           *start, *last, *end, ch;
  1627.     ngx_table_elt_t  *h;

  1628.     for (h = headers; h; h = h->next) {

  1629.         ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  1630.                        "parse header: \"%V: %V\"", &h->key, &h->value);

  1631.         if (name->len > h->value.len) {
  1632.             continue;
  1633.         }

  1634.         start = h->value.data;
  1635.         end = h->value.data + h->value.len;

  1636.         while (start < end) {

  1637.             if (ngx_strncasecmp(start, name->data, name->len) != 0) {
  1638.                 goto skip;
  1639.             }

  1640.             for (start += name->len; start < end && *start == ' '; start++) {
  1641.                 /* void */
  1642.             }

  1643.             if (value == NULL) {
  1644.                 if (start == end || *start == ',') {
  1645.                     return h;
  1646.                 }

  1647.                 goto skip;
  1648.             }

  1649.             if (start == end || *start++ != '=') {
  1650.                 /* the invalid header value */
  1651.                 goto skip;
  1652.             }

  1653.             while (start < end && *start == ' ') { start++; }

  1654.             for (last = start; last < end && *last != ';'; last++) {
  1655.                 /* void */
  1656.             }

  1657.             value->len = last - start;
  1658.             value->data = start;

  1659.             return h;

  1660.         skip:

  1661.             while (start < end) {
  1662.                 ch = *start++;
  1663.                 if (ch == ';' || ch == ',') {
  1664.                     break;
  1665.                 }
  1666.             }

  1667.             while (start < end && *start == ' ') { start++; }
  1668.         }
  1669.     }

  1670.     return NULL;
  1671. }


  1672. ngx_table_elt_t *
  1673. ngx_http_parse_set_cookie_lines(ngx_http_request_t *r,
  1674.     ngx_table_elt_t *headers, ngx_str_t *name, ngx_str_t *value)
  1675. {
  1676.     u_char           *start, *last, *end;
  1677.     ngx_table_elt_t  *h;

  1678.     for (h = headers; h; h = h->next) {

  1679.         ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  1680.                        "parse header: \"%V: %V\"", &h->key, &h->value);

  1681.         if (name->len >= h->value.len) {
  1682.             continue;
  1683.         }

  1684.         start = h->value.data;
  1685.         end = h->value.data + h->value.len;

  1686.         if (ngx_strncasecmp(start, name->data, name->len) != 0) {
  1687.             continue;
  1688.         }

  1689.         for (start += name->len; start < end && *start == ' '; start++) {
  1690.             /* void */
  1691.         }

  1692.         if (start == end || *start++ != '=') {
  1693.             /* the invalid header value */
  1694.             continue;
  1695.         }

  1696.         while (start < end && *start == ' ') { start++; }

  1697.         for (last = start; last < end && *last != ';'; last++) {
  1698.             /* void */
  1699.         }

  1700.         value->len = last - start;
  1701.         value->data = start;

  1702.         return h;
  1703.     }

  1704.     return NULL;
  1705. }


  1706. ngx_int_t
  1707. ngx_http_arg(ngx_http_request_t *r, u_char *name, size_t len, ngx_str_t *value)
  1708. {
  1709.     u_char  *p, *last;

  1710.     if (r->args.len == 0) {
  1711.         return NGX_DECLINED;
  1712.     }

  1713.     p = r->args.data;
  1714.     last = p + r->args.len;

  1715.     for ( /* void */ ; p < last; p++) {

  1716.         /* we need '=' after name, so drop one char from last */

  1717.         p = ngx_strlcasestrn(p, last - 1, name, len - 1);

  1718.         if (p == NULL) {
  1719.             return NGX_DECLINED;
  1720.         }

  1721.         if ((p == r->args.data || *(p - 1) == '&') && *(p + len) == '=') {

  1722.             value->data = p + len + 1;

  1723.             p = ngx_strlchr(p, last, '&');

  1724.             if (p == NULL) {
  1725.                 p = r->args.data + r->args.len;
  1726.             }

  1727.             value->len = p - value->data;

  1728.             return NGX_OK;
  1729.         }
  1730.     }

  1731.     return NGX_DECLINED;
  1732. }


  1733. void
  1734. ngx_http_split_args(ngx_http_request_t *r, ngx_str_t *uri, ngx_str_t *args)
  1735. {
  1736.     u_char  *p, *last;

  1737.     last = uri->data + uri->len;

  1738.     p = ngx_strlchr(uri->data, last, '?');

  1739.     if (p) {
  1740.         uri->len = p - uri->data;
  1741.         p++;
  1742.         args->len = last - p;
  1743.         args->data = p;

  1744.     } else {
  1745.         args->len = 0;
  1746.     }
  1747. }


  1748. ngx_int_t
  1749. ngx_http_parse_chunked(ngx_http_request_t *r, ngx_buf_t *b,
  1750.     ngx_http_chunked_t *ctx, ngx_uint_t keep_trailers)
  1751. {
  1752.     u_char     *pos, ch, c;
  1753.     ngx_int_t   rc;
  1754.     enum {
  1755.         sw_chunk_start = 0,
  1756.         sw_chunk_size,
  1757.         sw_chunk_extension,
  1758.         sw_chunk_extension_almost_done,
  1759.         sw_chunk_data,
  1760.         sw_after_data,
  1761.         sw_after_data_almost_done,
  1762.         sw_last_chunk_extension,
  1763.         sw_last_chunk_extension_almost_done,
  1764.         sw_trailer,
  1765.         sw_trailer_almost_done,
  1766.         sw_trailer_header,
  1767.         sw_trailer_header_almost_done
  1768.     } state;

  1769.     state = ctx->state;

  1770.     if (state == sw_chunk_data && ctx->size == 0) {
  1771.         state = sw_after_data;
  1772.     }

  1773.     rc = NGX_AGAIN;

  1774.     for (pos = b->pos; pos < b->last; pos++) {

  1775.         ch = *pos;

  1776.         ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  1777.                        "http chunked byte: %02Xd s:%d", ch, state);

  1778.         switch (state) {

  1779.         case sw_chunk_start:
  1780.             if (ch >= '0' && ch <= '9') {
  1781.                 state = sw_chunk_size;
  1782.                 ctx->size = ch - '0';
  1783.                 break;
  1784.             }

  1785.             c = (u_char) (ch | 0x20);

  1786.             if (c >= 'a' && c <= 'f') {
  1787.                 state = sw_chunk_size;
  1788.                 ctx->size = c - 'a' + 10;
  1789.                 break;
  1790.             }

  1791.             goto invalid;

  1792.         case sw_chunk_size:
  1793.             if (ctx->size > NGX_MAX_OFF_T_VALUE / 16) {
  1794.                 goto invalid;
  1795.             }

  1796.             if (ch >= '0' && ch <= '9') {
  1797.                 ctx->size = ctx->size * 16 + (ch - '0');
  1798.                 break;
  1799.             }

  1800.             c = (u_char) (ch | 0x20);

  1801.             if (c >= 'a' && c <= 'f') {
  1802.                 ctx->size = ctx->size * 16 + (c - 'a' + 10);
  1803.                 break;
  1804.             }

  1805.             if (ctx->size == 0) {

  1806.                 switch (ch) {
  1807.                 case CR:
  1808.                     state = sw_last_chunk_extension_almost_done;
  1809.                     break;
  1810.                 case LF:
  1811.                     if (keep_trailers) {
  1812.                         goto done;
  1813.                     }
  1814.                     state = sw_trailer;
  1815.                     break;
  1816.                 case ';':
  1817.                 case ' ':
  1818.                 case '\t':
  1819.                     state = sw_last_chunk_extension;
  1820.                     break;
  1821.                 default:
  1822.                     goto invalid;
  1823.                 }

  1824.                 break;
  1825.             }

  1826.             switch (ch) {
  1827.             case CR:
  1828.                 state = sw_chunk_extension_almost_done;
  1829.                 break;
  1830.             case LF:
  1831.                 state = sw_chunk_data;
  1832.                 break;
  1833.             case ';':
  1834.             case ' ':
  1835.             case '\t':
  1836.                 state = sw_chunk_extension;
  1837.                 break;
  1838.             default:
  1839.                 goto invalid;
  1840.             }

  1841.             break;

  1842.         case sw_chunk_extension:
  1843.             switch (ch) {
  1844.             case CR:
  1845.                 state = sw_chunk_extension_almost_done;
  1846.                 break;
  1847.             case LF:
  1848.                 state = sw_chunk_data;
  1849.             }
  1850.             break;

  1851.         case sw_chunk_extension_almost_done:
  1852.             if (ch == LF) {
  1853.                 state = sw_chunk_data;
  1854.                 break;
  1855.             }
  1856.             goto invalid;

  1857.         case sw_chunk_data:
  1858.             rc = NGX_OK;
  1859.             goto data;

  1860.         case sw_after_data:
  1861.             switch (ch) {
  1862.             case CR:
  1863.                 state = sw_after_data_almost_done;
  1864.                 break;
  1865.             case LF:
  1866.                 state = sw_chunk_start;
  1867.                 break;
  1868.             default:
  1869.                 goto invalid;
  1870.             }
  1871.             break;

  1872.         case sw_after_data_almost_done:
  1873.             if (ch == LF) {
  1874.                 state = sw_chunk_start;
  1875.                 break;
  1876.             }
  1877.             goto invalid;

  1878.         case sw_last_chunk_extension:
  1879.             switch (ch) {
  1880.             case CR:
  1881.                 state = sw_last_chunk_extension_almost_done;
  1882.                 break;
  1883.             case LF:
  1884.                 if (keep_trailers) {
  1885.                     goto done;
  1886.                 }
  1887.                 state = sw_trailer;
  1888.             }
  1889.             break;

  1890.         case sw_last_chunk_extension_almost_done:
  1891.             if (ch == LF) {
  1892.                 if (keep_trailers) {
  1893.                     goto done;
  1894.                 }
  1895.                 state = sw_trailer;
  1896.                 break;
  1897.             }
  1898.             goto invalid;

  1899.         case sw_trailer:
  1900.             switch (ch) {
  1901.             case CR:
  1902.                 state = sw_trailer_almost_done;
  1903.                 break;
  1904.             case LF:
  1905.                 goto done;
  1906.             default:
  1907.                 state = sw_trailer_header;
  1908.             }
  1909.             break;

  1910.         case sw_trailer_almost_done:
  1911.             if (ch == LF) {
  1912.                 goto done;
  1913.             }
  1914.             goto invalid;

  1915.         case sw_trailer_header:
  1916.             switch (ch) {
  1917.             case CR:
  1918.                 state = sw_trailer_header_almost_done;
  1919.                 break;
  1920.             case LF:
  1921.                 state = sw_trailer;
  1922.             }
  1923.             break;

  1924.         case sw_trailer_header_almost_done:
  1925.             if (ch == LF) {
  1926.                 state = sw_trailer;
  1927.                 break;
  1928.             }
  1929.             goto invalid;

  1930.         }
  1931.     }

  1932. data:

  1933.     ctx->state = state;
  1934.     b->pos = pos;

  1935.     if (ctx->size > NGX_MAX_OFF_T_VALUE - 5) {
  1936.         goto invalid;
  1937.     }

  1938.     switch (state) {

  1939.     case sw_chunk_start:
  1940.         ctx->length = 3 /* "0" LF LF */;
  1941.         break;
  1942.     case sw_chunk_size:
  1943.         ctx->length = 1 /* LF */
  1944.                       + (ctx->size ? ctx->size + 4 /* LF "0" LF LF */
  1945.                                    : 1 /* LF */);
  1946.         break;
  1947.     case sw_chunk_extension:
  1948.     case sw_chunk_extension_almost_done:
  1949.         ctx->length = 1 /* LF */ + ctx->size + 4 /* LF "0" LF LF */;
  1950.         break;
  1951.     case sw_chunk_data:
  1952.         ctx->length = ctx->size + 4 /* LF "0" LF LF */;
  1953.         break;
  1954.     case sw_after_data:
  1955.     case sw_after_data_almost_done:
  1956.         ctx->length = 4 /* LF "0" LF LF */;
  1957.         break;
  1958.     case sw_last_chunk_extension:
  1959.     case sw_last_chunk_extension_almost_done:
  1960.         ctx->length = 2 /* LF LF */;
  1961.         break;
  1962.     case sw_trailer:
  1963.     case sw_trailer_almost_done:
  1964.         ctx->length = 1 /* LF */;
  1965.         break;
  1966.     case sw_trailer_header:
  1967.     case sw_trailer_header_almost_done:
  1968.         ctx->length = 2 /* LF LF */;
  1969.         break;

  1970.     }

  1971.     return rc;

  1972. done:

  1973.     ctx->state = 0;
  1974.     b->pos = pos + 1;

  1975.     return NGX_DONE;

  1976. invalid:

  1977.     return NGX_ERROR;
  1978. }