Annotation of embedaddon/nginx/src/http/ngx_http_parse.c, revision 1.1.1.1

1.1       misho       1: 
                      2: /*
                      3:  * Copyright (C) Igor Sysoev
                      4:  * Copyright (C) Nginx, Inc.
                      5:  */
                      6: 
                      7: 
                      8: #include <ngx_config.h>
                      9: #include <ngx_core.h>
                     10: #include <ngx_http.h>
                     11: 
                     12: 
                     13: static uint32_t  usual[] = {
                     14:     0xffffdbfe, /* 1111 1111 1111 1111  1101 1011 1111 1110 */
                     15: 
                     16:                 /* ?>=< ;:98 7654 3210  /.-, +*)( '&%$ #"!  */
                     17:     0x7fff37d6, /* 0111 1111 1111 1111  0011 0111 1101 0110 */
                     18: 
                     19:                 /* _^]\ [ZYX WVUT SRQP  ONML KJIH GFED CBA@ */
                     20: #if (NGX_WIN32)
                     21:     0xefffffff, /* 1110 1111 1111 1111  1111 1111 1111 1111 */
                     22: #else
                     23:     0xffffffff, /* 1111 1111 1111 1111  1111 1111 1111 1111 */
                     24: #endif
                     25: 
                     26:                 /*  ~}| {zyx wvut srqp  onml kjih gfed cba` */
                     27:     0xffffffff, /* 1111 1111 1111 1111  1111 1111 1111 1111 */
                     28: 
                     29:     0xffffffff, /* 1111 1111 1111 1111  1111 1111 1111 1111 */
                     30:     0xffffffff, /* 1111 1111 1111 1111  1111 1111 1111 1111 */
                     31:     0xffffffff, /* 1111 1111 1111 1111  1111 1111 1111 1111 */
                     32:     0xffffffff  /* 1111 1111 1111 1111  1111 1111 1111 1111 */
                     33: };
                     34: 
                     35: 
                     36: #if (NGX_HAVE_LITTLE_ENDIAN && NGX_HAVE_NONALIGNED)
                     37: 
                     38: #define ngx_str3_cmp(m, c0, c1, c2, c3)                                       \
                     39:     *(uint32_t *) m == ((c3 << 24) | (c2 << 16) | (c1 << 8) | c0)
                     40: 
                     41: #define ngx_str3Ocmp(m, c0, c1, c2, c3)                                       \
                     42:     *(uint32_t *) m == ((c3 << 24) | (c2 << 16) | (c1 << 8) | c0)
                     43: 
                     44: #define ngx_str4cmp(m, c0, c1, c2, c3)                                        \
                     45:     *(uint32_t *) m == ((c3 << 24) | (c2 << 16) | (c1 << 8) | c0)
                     46: 
                     47: #define ngx_str5cmp(m, c0, c1, c2, c3, c4)                                    \
                     48:     *(uint32_t *) m == ((c3 << 24) | (c2 << 16) | (c1 << 8) | c0)             \
                     49:         && m[4] == c4
                     50: 
                     51: #define ngx_str6cmp(m, c0, c1, c2, c3, c4, c5)                                \
                     52:     *(uint32_t *) m == ((c3 << 24) | (c2 << 16) | (c1 << 8) | c0)             \
                     53:         && (((uint32_t *) m)[1] & 0xffff) == ((c5 << 8) | c4)
                     54: 
                     55: #define ngx_str7_cmp(m, c0, c1, c2, c3, c4, c5, c6, c7)                       \
                     56:     *(uint32_t *) m == ((c3 << 24) | (c2 << 16) | (c1 << 8) | c0)             \
                     57:         && ((uint32_t *) m)[1] == ((c7 << 24) | (c6 << 16) | (c5 << 8) | c4)
                     58: 
                     59: #define ngx_str8cmp(m, c0, c1, c2, c3, c4, c5, c6, c7)                        \
                     60:     *(uint32_t *) m == ((c3 << 24) | (c2 << 16) | (c1 << 8) | c0)             \
                     61:         && ((uint32_t *) m)[1] == ((c7 << 24) | (c6 << 16) | (c5 << 8) | c4)
                     62: 
                     63: #define ngx_str9cmp(m, c0, c1, c2, c3, c4, c5, c6, c7, c8)                    \
                     64:     *(uint32_t *) m == ((c3 << 24) | (c2 << 16) | (c1 << 8) | c0)             \
                     65:         && ((uint32_t *) m)[1] == ((c7 << 24) | (c6 << 16) | (c5 << 8) | c4)  \
                     66:         && m[8] == c8
                     67: 
                     68: #else /* !(NGX_HAVE_LITTLE_ENDIAN && NGX_HAVE_NONALIGNED) */
                     69: 
                     70: #define ngx_str3_cmp(m, c0, c1, c2, c3)                                       \
                     71:     m[0] == c0 && m[1] == c1 && m[2] == c2
                     72: 
                     73: #define ngx_str3Ocmp(m, c0, c1, c2, c3)                                       \
                     74:     m[0] == c0 && m[2] == c2 && m[3] == c3
                     75: 
                     76: #define ngx_str4cmp(m, c0, c1, c2, c3)                                        \
                     77:     m[0] == c0 && m[1] == c1 && m[2] == c2 && m[3] == c3
                     78: 
                     79: #define ngx_str5cmp(m, c0, c1, c2, c3, c4)                                    \
                     80:     m[0] == c0 && m[1] == c1 && m[2] == c2 && m[3] == c3 && m[4] == c4
                     81: 
                     82: #define ngx_str6cmp(m, c0, c1, c2, c3, c4, c5)                                \
                     83:     m[0] == c0 && m[1] == c1 && m[2] == c2 && m[3] == c3                      \
                     84:         && m[4] == c4 && m[5] == c5
                     85: 
                     86: #define ngx_str7_cmp(m, c0, c1, c2, c3, c4, c5, c6, c7)                       \
                     87:     m[0] == c0 && m[1] == c1 && m[2] == c2 && m[3] == c3                      \
                     88:         && m[4] == c4 && m[5] == c5 && m[6] == c6
                     89: 
                     90: #define ngx_str8cmp(m, c0, c1, c2, c3, c4, c5, c6, c7)                        \
                     91:     m[0] == c0 && m[1] == c1 && m[2] == c2 && m[3] == c3                      \
                     92:         && m[4] == c4 && m[5] == c5 && m[6] == c6 && m[7] == c7
                     93: 
                     94: #define ngx_str9cmp(m, c0, c1, c2, c3, c4, c5, c6, c7, c8)                    \
                     95:     m[0] == c0 && m[1] == c1 && m[2] == c2 && m[3] == c3                      \
                     96:         && m[4] == c4 && m[5] == c5 && m[6] == c6 && m[7] == c7 && m[8] == c8
                     97: 
                     98: #endif
                     99: 
                    100: 
                    101: /* gcc, icc, msvc and others compile these switches as an jump table */
                    102: 
                    103: ngx_int_t
                    104: ngx_http_parse_request_line(ngx_http_request_t *r, ngx_buf_t *b)
                    105: {
                    106:     u_char  c, ch, *p, *m;
                    107:     enum {
                    108:         sw_start = 0,
                    109:         sw_method,
                    110:         sw_spaces_before_uri,
                    111:         sw_schema,
                    112:         sw_schema_slash,
                    113:         sw_schema_slash_slash,
                    114:         sw_host_start,
                    115:         sw_host,
                    116:         sw_host_end,
                    117:         sw_host_ip_literal,
                    118:         sw_port,
                    119:         sw_host_http_09,
                    120:         sw_after_slash_in_uri,
                    121:         sw_check_uri,
                    122:         sw_check_uri_http_09,
                    123:         sw_uri,
                    124:         sw_http_09,
                    125:         sw_http_H,
                    126:         sw_http_HT,
                    127:         sw_http_HTT,
                    128:         sw_http_HTTP,
                    129:         sw_first_major_digit,
                    130:         sw_major_digit,
                    131:         sw_first_minor_digit,
                    132:         sw_minor_digit,
                    133:         sw_spaces_after_digit,
                    134:         sw_almost_done
                    135:     } state;
                    136: 
                    137:     state = r->state;
                    138: 
                    139:     for (p = b->pos; p < b->last; p++) {
                    140:         ch = *p;
                    141: 
                    142:         switch (state) {
                    143: 
                    144:         /* HTTP methods: GET, HEAD, POST */
                    145:         case sw_start:
                    146:             r->request_start = p;
                    147: 
                    148:             if (ch == CR || ch == LF) {
                    149:                 break;
                    150:             }
                    151: 
                    152:             if ((ch < 'A' || ch > 'Z') && ch != '_') {
                    153:                 return NGX_HTTP_PARSE_INVALID_METHOD;
                    154:             }
                    155: 
                    156:             state = sw_method;
                    157:             break;
                    158: 
                    159:         case sw_method:
                    160:             if (ch == ' ') {
                    161:                 r->method_end = p - 1;
                    162:                 m = r->request_start;
                    163: 
                    164:                 switch (p - m) {
                    165: 
                    166:                 case 3:
                    167:                     if (ngx_str3_cmp(m, 'G', 'E', 'T', ' ')) {
                    168:                         r->method = NGX_HTTP_GET;
                    169:                         break;
                    170:                     }
                    171: 
                    172:                     if (ngx_str3_cmp(m, 'P', 'U', 'T', ' ')) {
                    173:                         r->method = NGX_HTTP_PUT;
                    174:                         break;
                    175:                     }
                    176: 
                    177:                     break;
                    178: 
                    179:                 case 4:
                    180:                     if (m[1] == 'O') {
                    181: 
                    182:                         if (ngx_str3Ocmp(m, 'P', 'O', 'S', 'T')) {
                    183:                             r->method = NGX_HTTP_POST;
                    184:                             break;
                    185:                         }
                    186: 
                    187:                         if (ngx_str3Ocmp(m, 'C', 'O', 'P', 'Y')) {
                    188:                             r->method = NGX_HTTP_COPY;
                    189:                             break;
                    190:                         }
                    191: 
                    192:                         if (ngx_str3Ocmp(m, 'M', 'O', 'V', 'E')) {
                    193:                             r->method = NGX_HTTP_MOVE;
                    194:                             break;
                    195:                         }
                    196: 
                    197:                         if (ngx_str3Ocmp(m, 'L', 'O', 'C', 'K')) {
                    198:                             r->method = NGX_HTTP_LOCK;
                    199:                             break;
                    200:                         }
                    201: 
                    202:                     } else {
                    203: 
                    204:                         if (ngx_str4cmp(m, 'H', 'E', 'A', 'D')) {
                    205:                             r->method = NGX_HTTP_HEAD;
                    206:                             break;
                    207:                         }
                    208:                     }
                    209: 
                    210:                     break;
                    211: 
                    212:                 case 5:
                    213:                     if (ngx_str5cmp(m, 'M', 'K', 'C', 'O', 'L')) {
                    214:                         r->method = NGX_HTTP_MKCOL;
                    215:                     }
                    216: 
                    217:                     if (ngx_str5cmp(m, 'P', 'A', 'T', 'C', 'H')) {
                    218:                         r->method = NGX_HTTP_PATCH;
                    219:                     }
                    220: 
                    221:                     if (ngx_str5cmp(m, 'T', 'R', 'A', 'C', 'E')) {
                    222:                         r->method = NGX_HTTP_TRACE;
                    223:                     }
                    224: 
                    225:                     break;
                    226: 
                    227:                 case 6:
                    228:                     if (ngx_str6cmp(m, 'D', 'E', 'L', 'E', 'T', 'E')) {
                    229:                         r->method = NGX_HTTP_DELETE;
                    230:                         break;
                    231:                     }
                    232: 
                    233:                     if (ngx_str6cmp(m, 'U', 'N', 'L', 'O', 'C', 'K')) {
                    234:                         r->method = NGX_HTTP_UNLOCK;
                    235:                         break;
                    236:                     }
                    237: 
                    238:                     break;
                    239: 
                    240:                 case 7:
                    241:                     if (ngx_str7_cmp(m, 'O', 'P', 'T', 'I', 'O', 'N', 'S', ' '))
                    242:                     {
                    243:                         r->method = NGX_HTTP_OPTIONS;
                    244:                     }
                    245: 
                    246:                     break;
                    247: 
                    248:                 case 8:
                    249:                     if (ngx_str8cmp(m, 'P', 'R', 'O', 'P', 'F', 'I', 'N', 'D'))
                    250:                     {
                    251:                         r->method = NGX_HTTP_PROPFIND;
                    252:                     }
                    253: 
                    254:                     break;
                    255: 
                    256:                 case 9:
                    257:                     if (ngx_str9cmp(m,
                    258:                             'P', 'R', 'O', 'P', 'P', 'A', 'T', 'C', 'H'))
                    259:                     {
                    260:                         r->method = NGX_HTTP_PROPPATCH;
                    261:                     }
                    262: 
                    263:                     break;
                    264:                 }
                    265: 
                    266:                 state = sw_spaces_before_uri;
                    267:                 break;
                    268:             }
                    269: 
                    270:             if ((ch < 'A' || ch > 'Z') && ch != '_') {
                    271:                 return NGX_HTTP_PARSE_INVALID_METHOD;
                    272:             }
                    273: 
                    274:             break;
                    275: 
                    276:         /* space* before URI */
                    277:         case sw_spaces_before_uri:
                    278: 
                    279:             if (ch == '/') {
                    280:                 r->uri_start = p;
                    281:                 state = sw_after_slash_in_uri;
                    282:                 break;
                    283:             }
                    284: 
                    285:             c = (u_char) (ch | 0x20);
                    286:             if (c >= 'a' && c <= 'z') {
                    287:                 r->schema_start = p;
                    288:                 state = sw_schema;
                    289:                 break;
                    290:             }
                    291: 
                    292:             switch (ch) {
                    293:             case ' ':
                    294:                 break;
                    295:             default:
                    296:                 return NGX_HTTP_PARSE_INVALID_REQUEST;
                    297:             }
                    298:             break;
                    299: 
                    300:         case sw_schema:
                    301: 
                    302:             c = (u_char) (ch | 0x20);
                    303:             if (c >= 'a' && c <= 'z') {
                    304:                 break;
                    305:             }
                    306: 
                    307:             switch (ch) {
                    308:             case ':':
                    309:                 r->schema_end = p;
                    310:                 state = sw_schema_slash;
                    311:                 break;
                    312:             default:
                    313:                 return NGX_HTTP_PARSE_INVALID_REQUEST;
                    314:             }
                    315:             break;
                    316: 
                    317:         case sw_schema_slash:
                    318:             switch (ch) {
                    319:             case '/':
                    320:                 state = sw_schema_slash_slash;
                    321:                 break;
                    322:             default:
                    323:                 return NGX_HTTP_PARSE_INVALID_REQUEST;
                    324:             }
                    325:             break;
                    326: 
                    327:         case sw_schema_slash_slash:
                    328:             switch (ch) {
                    329:             case '/':
                    330:                 state = sw_host_start;
                    331:                 break;
                    332:             default:
                    333:                 return NGX_HTTP_PARSE_INVALID_REQUEST;
                    334:             }
                    335:             break;
                    336: 
                    337:         case sw_host_start:
                    338: 
                    339:             r->host_start = p;
                    340: 
                    341:             if (ch == '[') {
                    342:                 state = sw_host_ip_literal;
                    343:                 break;
                    344:             }
                    345: 
                    346:             state = sw_host;
                    347: 
                    348:             /* fall through */
                    349: 
                    350:         case sw_host:
                    351: 
                    352:             c = (u_char) (ch | 0x20);
                    353:             if (c >= 'a' && c <= 'z') {
                    354:                 break;
                    355:             }
                    356: 
                    357:             if ((ch >= '0' && ch <= '9') || ch == '.' || ch == '-') {
                    358:                 break;
                    359:             }
                    360: 
                    361:             /* fall through */
                    362: 
                    363:         case sw_host_end:
                    364: 
                    365:             r->host_end = p;
                    366: 
                    367:             switch (ch) {
                    368:             case ':':
                    369:                 state = sw_port;
                    370:                 break;
                    371:             case '/':
                    372:                 r->uri_start = p;
                    373:                 state = sw_after_slash_in_uri;
                    374:                 break;
                    375:             case ' ':
                    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_host_http_09;
                    383:                 break;
                    384:             default:
                    385:                 return NGX_HTTP_PARSE_INVALID_REQUEST;
                    386:             }
                    387:             break;
                    388: 
                    389:         case sw_host_ip_literal:
                    390: 
                    391:             if (ch >= '0' && ch <= '9') {
                    392:                 break;
                    393:             }
                    394: 
                    395:             c = (u_char) (ch | 0x20);
                    396:             if (c >= 'a' && c <= 'z') {
                    397:                 break;
                    398:             }
                    399: 
                    400:             switch (ch) {
                    401:             case ':':
                    402:                 break;
                    403:             case ']':
                    404:                 state = sw_host_end;
                    405:                 break;
                    406:             case '-':
                    407:             case '.':
                    408:             case '_':
                    409:             case '~':
                    410:                 /* unreserved */
                    411:                 break;
                    412:             case '!':
                    413:             case '$':
                    414:             case '&':
                    415:             case '\'':
                    416:             case '(':
                    417:             case ')':
                    418:             case '*':
                    419:             case '+':
                    420:             case ',':
                    421:             case ';':
                    422:             case '=':
                    423:                 /* sub-delims */
                    424:                 break;
                    425:             default:
                    426:                 return NGX_HTTP_PARSE_INVALID_REQUEST;
                    427:             }
                    428:             break;
                    429: 
                    430:         case sw_port:
                    431:             if (ch >= '0' && ch <= '9') {
                    432:                 break;
                    433:             }
                    434: 
                    435:             switch (ch) {
                    436:             case '/':
                    437:                 r->port_end = p;
                    438:                 r->uri_start = p;
                    439:                 state = sw_after_slash_in_uri;
                    440:                 break;
                    441:             case ' ':
                    442:                 r->port_end = p;
                    443:                 /*
                    444:                  * use single "/" from request line to preserve pointers,
                    445:                  * if request line will be copied to large client buffer
                    446:                  */
                    447:                 r->uri_start = r->schema_end + 1;
                    448:                 r->uri_end = r->schema_end + 2;
                    449:                 state = sw_host_http_09;
                    450:                 break;
                    451:             default:
                    452:                 return NGX_HTTP_PARSE_INVALID_REQUEST;
                    453:             }
                    454:             break;
                    455: 
                    456:         /* space+ after "http://host[:port] " */
                    457:         case sw_host_http_09:
                    458:             switch (ch) {
                    459:             case ' ':
                    460:                 break;
                    461:             case CR:
                    462:                 r->http_minor = 9;
                    463:                 state = sw_almost_done;
                    464:                 break;
                    465:             case LF:
                    466:                 r->http_minor = 9;
                    467:                 goto done;
                    468:             case 'H':
                    469:                 r->http_protocol.data = p;
                    470:                 state = sw_http_H;
                    471:                 break;
                    472:             default:
                    473:                 return NGX_HTTP_PARSE_INVALID_REQUEST;
                    474:             }
                    475:             break;
                    476: 
                    477: 
                    478:         /* check "/.", "//", "%", and "\" (Win32) in URI */
                    479:         case sw_after_slash_in_uri:
                    480: 
                    481:             if (usual[ch >> 5] & (1 << (ch & 0x1f))) {
                    482:                 state = sw_check_uri;
                    483:                 break;
                    484:             }
                    485: 
                    486:             switch (ch) {
                    487:             case ' ':
                    488:                 r->uri_end = p;
                    489:                 state = sw_check_uri_http_09;
                    490:                 break;
                    491:             case CR:
                    492:                 r->uri_end = p;
                    493:                 r->http_minor = 9;
                    494:                 state = sw_almost_done;
                    495:                 break;
                    496:             case LF:
                    497:                 r->uri_end = p;
                    498:                 r->http_minor = 9;
                    499:                 goto done;
                    500:             case '.':
                    501:                 r->complex_uri = 1;
                    502:                 state = sw_uri;
                    503:                 break;
                    504:             case '%':
                    505:                 r->quoted_uri = 1;
                    506:                 state = sw_uri;
                    507:                 break;
                    508:             case '/':
                    509:                 r->complex_uri = 1;
                    510:                 state = sw_uri;
                    511:                 break;
                    512: #if (NGX_WIN32)
                    513:             case '\\':
                    514:                 r->complex_uri = 1;
                    515:                 state = sw_uri;
                    516:                 break;
                    517: #endif
                    518:             case '?':
                    519:                 r->args_start = p + 1;
                    520:                 state = sw_uri;
                    521:                 break;
                    522:             case '#':
                    523:                 r->complex_uri = 1;
                    524:                 state = sw_uri;
                    525:                 break;
                    526:             case '+':
                    527:                 r->plus_in_uri = 1;
                    528:                 break;
                    529:             case '\0':
                    530:                 return NGX_HTTP_PARSE_INVALID_REQUEST;
                    531:             default:
                    532:                 state = sw_check_uri;
                    533:                 break;
                    534:             }
                    535:             break;
                    536: 
                    537:         /* check "/", "%" and "\" (Win32) in URI */
                    538:         case sw_check_uri:
                    539: 
                    540:             if (usual[ch >> 5] & (1 << (ch & 0x1f))) {
                    541:                 break;
                    542:             }
                    543: 
                    544:             switch (ch) {
                    545:             case '/':
                    546: #if (NGX_WIN32)
                    547:                 if (r->uri_ext == p) {
                    548:                     r->complex_uri = 1;
                    549:                     state = sw_uri;
                    550:                     break;
                    551:                 }
                    552: #endif
                    553:                 r->uri_ext = NULL;
                    554:                 state = sw_after_slash_in_uri;
                    555:                 break;
                    556:             case '.':
                    557:                 r->uri_ext = p + 1;
                    558:                 break;
                    559:             case ' ':
                    560:                 r->uri_end = p;
                    561:                 state = sw_check_uri_http_09;
                    562:                 break;
                    563:             case CR:
                    564:                 r->uri_end = p;
                    565:                 r->http_minor = 9;
                    566:                 state = sw_almost_done;
                    567:                 break;
                    568:             case LF:
                    569:                 r->uri_end = p;
                    570:                 r->http_minor = 9;
                    571:                 goto done;
                    572: #if (NGX_WIN32)
                    573:             case '\\':
                    574:                 r->complex_uri = 1;
                    575:                 state = sw_after_slash_in_uri;
                    576:                 break;
                    577: #endif
                    578:             case '%':
                    579:                 r->quoted_uri = 1;
                    580:                 state = sw_uri;
                    581:                 break;
                    582:             case '?':
                    583:                 r->args_start = p + 1;
                    584:                 state = sw_uri;
                    585:                 break;
                    586:             case '#':
                    587:                 r->complex_uri = 1;
                    588:                 state = sw_uri;
                    589:                 break;
                    590:             case '+':
                    591:                 r->plus_in_uri = 1;
                    592:                 break;
                    593:             case '\0':
                    594:                 return NGX_HTTP_PARSE_INVALID_REQUEST;
                    595:             }
                    596:             break;
                    597: 
                    598:         /* space+ after URI */
                    599:         case sw_check_uri_http_09:
                    600:             switch (ch) {
                    601:             case ' ':
                    602:                 break;
                    603:             case CR:
                    604:                 r->http_minor = 9;
                    605:                 state = sw_almost_done;
                    606:                 break;
                    607:             case LF:
                    608:                 r->http_minor = 9;
                    609:                 goto done;
                    610:             case 'H':
                    611:                 r->http_protocol.data = p;
                    612:                 state = sw_http_H;
                    613:                 break;
                    614:             default:
                    615:                 r->space_in_uri = 1;
                    616:                 state = sw_check_uri;
                    617:                 break;
                    618:             }
                    619:             break;
                    620: 
                    621: 
                    622:         /* URI */
                    623:         case sw_uri:
                    624: 
                    625:             if (usual[ch >> 5] & (1 << (ch & 0x1f))) {
                    626:                 break;
                    627:             }
                    628: 
                    629:             switch (ch) {
                    630:             case ' ':
                    631:                 r->uri_end = p;
                    632:                 state = sw_http_09;
                    633:                 break;
                    634:             case CR:
                    635:                 r->uri_end = p;
                    636:                 r->http_minor = 9;
                    637:                 state = sw_almost_done;
                    638:                 break;
                    639:             case LF:
                    640:                 r->uri_end = p;
                    641:                 r->http_minor = 9;
                    642:                 goto done;
                    643:             case '#':
                    644:                 r->complex_uri = 1;
                    645:                 break;
                    646:             case '\0':
                    647:                 return NGX_HTTP_PARSE_INVALID_REQUEST;
                    648:             }
                    649:             break;
                    650: 
                    651:         /* space+ after URI */
                    652:         case sw_http_09:
                    653:             switch (ch) {
                    654:             case ' ':
                    655:                 break;
                    656:             case CR:
                    657:                 r->http_minor = 9;
                    658:                 state = sw_almost_done;
                    659:                 break;
                    660:             case LF:
                    661:                 r->http_minor = 9;
                    662:                 goto done;
                    663:             case 'H':
                    664:                 r->http_protocol.data = p;
                    665:                 state = sw_http_H;
                    666:                 break;
                    667:             default:
                    668:                 r->space_in_uri = 1;
                    669:                 state = sw_uri;
                    670:                 break;
                    671:             }
                    672:             break;
                    673: 
                    674:         case sw_http_H:
                    675:             switch (ch) {
                    676:             case 'T':
                    677:                 state = sw_http_HT;
                    678:                 break;
                    679:             default:
                    680:                 return NGX_HTTP_PARSE_INVALID_REQUEST;
                    681:             }
                    682:             break;
                    683: 
                    684:         case sw_http_HT:
                    685:             switch (ch) {
                    686:             case 'T':
                    687:                 state = sw_http_HTT;
                    688:                 break;
                    689:             default:
                    690:                 return NGX_HTTP_PARSE_INVALID_REQUEST;
                    691:             }
                    692:             break;
                    693: 
                    694:         case sw_http_HTT:
                    695:             switch (ch) {
                    696:             case 'P':
                    697:                 state = sw_http_HTTP;
                    698:                 break;
                    699:             default:
                    700:                 return NGX_HTTP_PARSE_INVALID_REQUEST;
                    701:             }
                    702:             break;
                    703: 
                    704:         case sw_http_HTTP:
                    705:             switch (ch) {
                    706:             case '/':
                    707:                 state = sw_first_major_digit;
                    708:                 break;
                    709:             default:
                    710:                 return NGX_HTTP_PARSE_INVALID_REQUEST;
                    711:             }
                    712:             break;
                    713: 
                    714:         /* first digit of major HTTP version */
                    715:         case sw_first_major_digit:
                    716:             if (ch < '1' || ch > '9') {
                    717:                 return NGX_HTTP_PARSE_INVALID_REQUEST;
                    718:             }
                    719: 
                    720:             r->http_major = ch - '0';
                    721:             state = sw_major_digit;
                    722:             break;
                    723: 
                    724:         /* major HTTP version or dot */
                    725:         case sw_major_digit:
                    726:             if (ch == '.') {
                    727:                 state = sw_first_minor_digit;
                    728:                 break;
                    729:             }
                    730: 
                    731:             if (ch < '0' || ch > '9') {
                    732:                 return NGX_HTTP_PARSE_INVALID_REQUEST;
                    733:             }
                    734: 
                    735:             r->http_major = r->http_major * 10 + ch - '0';
                    736:             break;
                    737: 
                    738:         /* first digit of minor HTTP version */
                    739:         case sw_first_minor_digit:
                    740:             if (ch < '0' || ch > '9') {
                    741:                 return NGX_HTTP_PARSE_INVALID_REQUEST;
                    742:             }
                    743: 
                    744:             r->http_minor = ch - '0';
                    745:             state = sw_minor_digit;
                    746:             break;
                    747: 
                    748:         /* minor HTTP version or end of request line */
                    749:         case sw_minor_digit:
                    750:             if (ch == CR) {
                    751:                 state = sw_almost_done;
                    752:                 break;
                    753:             }
                    754: 
                    755:             if (ch == LF) {
                    756:                 goto done;
                    757:             }
                    758: 
                    759:             if (ch == ' ') {
                    760:                 state = sw_spaces_after_digit;
                    761:                 break;
                    762:             }
                    763: 
                    764:             if (ch < '0' || ch > '9') {
                    765:                 return NGX_HTTP_PARSE_INVALID_REQUEST;
                    766:             }
                    767: 
                    768:             r->http_minor = r->http_minor * 10 + ch - '0';
                    769:             break;
                    770: 
                    771:         case sw_spaces_after_digit:
                    772:             switch (ch) {
                    773:             case ' ':
                    774:                 break;
                    775:             case CR:
                    776:                 state = sw_almost_done;
                    777:                 break;
                    778:             case LF:
                    779:                 goto done;
                    780:             default:
                    781:                 return NGX_HTTP_PARSE_INVALID_REQUEST;
                    782:             }
                    783:             break;
                    784: 
                    785:         /* end of request line */
                    786:         case sw_almost_done:
                    787:             r->request_end = p - 1;
                    788:             switch (ch) {
                    789:             case LF:
                    790:                 goto done;
                    791:             default:
                    792:                 return NGX_HTTP_PARSE_INVALID_REQUEST;
                    793:             }
                    794:         }
                    795:     }
                    796: 
                    797:     b->pos = p;
                    798:     r->state = state;
                    799: 
                    800:     return NGX_AGAIN;
                    801: 
                    802: done:
                    803: 
                    804:     b->pos = p + 1;
                    805: 
                    806:     if (r->request_end == NULL) {
                    807:         r->request_end = p;
                    808:     }
                    809: 
                    810:     r->http_version = r->http_major * 1000 + r->http_minor;
                    811:     r->state = sw_start;
                    812: 
                    813:     if (r->http_version == 9 && r->method != NGX_HTTP_GET) {
                    814:         return NGX_HTTP_PARSE_INVALID_09_METHOD;
                    815:     }
                    816: 
                    817:     return NGX_OK;
                    818: }
                    819: 
                    820: 
                    821: ngx_int_t
                    822: ngx_http_parse_header_line(ngx_http_request_t *r, ngx_buf_t *b,
                    823:     ngx_uint_t allow_underscores)
                    824: {
                    825:     u_char      c, ch, *p;
                    826:     ngx_uint_t  hash, i;
                    827:     enum {
                    828:         sw_start = 0,
                    829:         sw_name,
                    830:         sw_space_before_value,
                    831:         sw_value,
                    832:         sw_space_after_value,
                    833:         sw_ignore_line,
                    834:         sw_almost_done,
                    835:         sw_header_almost_done
                    836:     } state;
                    837: 
                    838:     /* the last '\0' is not needed because string is zero terminated */
                    839: 
                    840:     static u_char  lowcase[] =
                    841:         "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
                    842:         "\0\0\0\0\0\0\0\0\0\0\0\0\0-\0\0" "0123456789\0\0\0\0\0\0"
                    843:         "\0abcdefghijklmnopqrstuvwxyz\0\0\0\0\0"
                    844:         "\0abcdefghijklmnopqrstuvwxyz\0\0\0\0\0"
                    845:         "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
                    846:         "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
                    847:         "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
                    848:         "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
                    849: 
                    850:     state = r->state;
                    851:     hash = r->header_hash;
                    852:     i = r->lowcase_index;
                    853: 
                    854:     for (p = b->pos; p < b->last; p++) {
                    855:         ch = *p;
                    856: 
                    857:         switch (state) {
                    858: 
                    859:         /* first char */
                    860:         case sw_start:
                    861:             r->header_name_start = p;
                    862:             r->invalid_header = 0;
                    863: 
                    864:             switch (ch) {
                    865:             case CR:
                    866:                 r->header_end = p;
                    867:                 state = sw_header_almost_done;
                    868:                 break;
                    869:             case LF:
                    870:                 r->header_end = p;
                    871:                 goto header_done;
                    872:             default:
                    873:                 state = sw_name;
                    874: 
                    875:                 c = lowcase[ch];
                    876: 
                    877:                 if (c) {
                    878:                     hash = ngx_hash(0, c);
                    879:                     r->lowcase_header[0] = c;
                    880:                     i = 1;
                    881:                     break;
                    882:                 }
                    883: 
                    884:                 if (ch == '\0') {
                    885:                     return NGX_HTTP_PARSE_INVALID_HEADER;
                    886:                 }
                    887: 
                    888:                 r->invalid_header = 1;
                    889: 
                    890:                 break;
                    891: 
                    892:             }
                    893:             break;
                    894: 
                    895:         /* header name */
                    896:         case sw_name:
                    897:             c = lowcase[ch];
                    898: 
                    899:             if (c) {
                    900:                 hash = ngx_hash(hash, c);
                    901:                 r->lowcase_header[i++] = c;
                    902:                 i &= (NGX_HTTP_LC_HEADER_LEN - 1);
                    903:                 break;
                    904:             }
                    905: 
                    906:             if (ch == '_') {
                    907:                 if (allow_underscores) {
                    908:                     hash = ngx_hash(hash, ch);
                    909:                     r->lowcase_header[i++] = ch;
                    910:                     i &= (NGX_HTTP_LC_HEADER_LEN - 1);
                    911: 
                    912:                 } else {
                    913:                     r->invalid_header = 1;
                    914:                 }
                    915: 
                    916:                 break;
                    917:             }
                    918: 
                    919:             if (ch == ':') {
                    920:                 r->header_name_end = p;
                    921:                 state = sw_space_before_value;
                    922:                 break;
                    923:             }
                    924: 
                    925:             if (ch == CR) {
                    926:                 r->header_name_end = p;
                    927:                 r->header_start = p;
                    928:                 r->header_end = p;
                    929:                 state = sw_almost_done;
                    930:                 break;
                    931:             }
                    932: 
                    933:             if (ch == LF) {
                    934:                 r->header_name_end = p;
                    935:                 r->header_start = p;
                    936:                 r->header_end = p;
                    937:                 goto done;
                    938:             }
                    939: 
                    940:             /* IIS may send the duplicate "HTTP/1.1 ..." lines */
                    941:             if (ch == '/'
                    942:                 && r->upstream
                    943:                 && p - r->header_name_start == 4
                    944:                 && ngx_strncmp(r->header_name_start, "HTTP", 4) == 0)
                    945:             {
                    946:                 state = sw_ignore_line;
                    947:                 break;
                    948:             }
                    949: 
                    950:             if (ch == '\0') {
                    951:                 return NGX_HTTP_PARSE_INVALID_HEADER;
                    952:             }
                    953: 
                    954:             r->invalid_header = 1;
                    955: 
                    956:             break;
                    957: 
                    958:         /* space* before header value */
                    959:         case sw_space_before_value:
                    960:             switch (ch) {
                    961:             case ' ':
                    962:                 break;
                    963:             case CR:
                    964:                 r->header_start = p;
                    965:                 r->header_end = p;
                    966:                 state = sw_almost_done;
                    967:                 break;
                    968:             case LF:
                    969:                 r->header_start = p;
                    970:                 r->header_end = p;
                    971:                 goto done;
                    972:             case '\0':
                    973:                 return NGX_HTTP_PARSE_INVALID_HEADER;
                    974:             default:
                    975:                 r->header_start = p;
                    976:                 state = sw_value;
                    977:                 break;
                    978:             }
                    979:             break;
                    980: 
                    981:         /* header value */
                    982:         case sw_value:
                    983:             switch (ch) {
                    984:             case ' ':
                    985:                 r->header_end = p;
                    986:                 state = sw_space_after_value;
                    987:                 break;
                    988:             case CR:
                    989:                 r->header_end = p;
                    990:                 state = sw_almost_done;
                    991:                 break;
                    992:             case LF:
                    993:                 r->header_end = p;
                    994:                 goto done;
                    995:             case '\0':
                    996:                 return NGX_HTTP_PARSE_INVALID_HEADER;
                    997:             }
                    998:             break;
                    999: 
                   1000:         /* space* before end of header line */
                   1001:         case sw_space_after_value:
                   1002:             switch (ch) {
                   1003:             case ' ':
                   1004:                 break;
                   1005:             case CR:
                   1006:                 state = sw_almost_done;
                   1007:                 break;
                   1008:             case LF:
                   1009:                 goto done;
                   1010:             case '\0':
                   1011:                 return NGX_HTTP_PARSE_INVALID_HEADER;
                   1012:             default:
                   1013:                 state = sw_value;
                   1014:                 break;
                   1015:             }
                   1016:             break;
                   1017: 
                   1018:         /* ignore header line */
                   1019:         case sw_ignore_line:
                   1020:             switch (ch) {
                   1021:             case LF:
                   1022:                 state = sw_start;
                   1023:                 break;
                   1024:             default:
                   1025:                 break;
                   1026:             }
                   1027:             break;
                   1028: 
                   1029:         /* end of header line */
                   1030:         case sw_almost_done:
                   1031:             switch (ch) {
                   1032:             case LF:
                   1033:                 goto done;
                   1034:             case CR:
                   1035:                 break;
                   1036:             default:
                   1037:                 return NGX_HTTP_PARSE_INVALID_HEADER;
                   1038:             }
                   1039:             break;
                   1040: 
                   1041:         /* end of header */
                   1042:         case sw_header_almost_done:
                   1043:             switch (ch) {
                   1044:             case LF:
                   1045:                 goto header_done;
                   1046:             default:
                   1047:                 return NGX_HTTP_PARSE_INVALID_HEADER;
                   1048:             }
                   1049:         }
                   1050:     }
                   1051: 
                   1052:     b->pos = p;
                   1053:     r->state = state;
                   1054:     r->header_hash = hash;
                   1055:     r->lowcase_index = i;
                   1056: 
                   1057:     return NGX_AGAIN;
                   1058: 
                   1059: done:
                   1060: 
                   1061:     b->pos = p + 1;
                   1062:     r->state = sw_start;
                   1063:     r->header_hash = hash;
                   1064:     r->lowcase_index = i;
                   1065: 
                   1066:     return NGX_OK;
                   1067: 
                   1068: header_done:
                   1069: 
                   1070:     b->pos = p + 1;
                   1071:     r->state = sw_start;
                   1072: 
                   1073:     return NGX_HTTP_PARSE_HEADER_DONE;
                   1074: }
                   1075: 
                   1076: 
                   1077: ngx_int_t
                   1078: ngx_http_parse_uri(ngx_http_request_t *r)
                   1079: {
                   1080:     u_char  *p, ch;
                   1081:     enum {
                   1082:         sw_start = 0,
                   1083:         sw_after_slash_in_uri,
                   1084:         sw_check_uri,
                   1085:         sw_uri
                   1086:     } state;
                   1087: 
                   1088:     state = sw_start;
                   1089: 
                   1090:     for (p = r->uri_start; p != r->uri_end; p++) {
                   1091: 
                   1092:         ch = *p;
                   1093: 
                   1094:         switch (state) {
                   1095: 
                   1096:         case sw_start:
                   1097: 
                   1098:             if (ch != '/') {
                   1099:                 return NGX_ERROR;
                   1100:             }
                   1101: 
                   1102:             state = sw_after_slash_in_uri;
                   1103:             break;
                   1104: 
                   1105:         /* check "/.", "//", "%", and "\" (Win32) in URI */
                   1106:         case sw_after_slash_in_uri:
                   1107: 
                   1108:             if (usual[ch >> 5] & (1 << (ch & 0x1f))) {
                   1109:                 state = sw_check_uri;
                   1110:                 break;
                   1111:             }
                   1112: 
                   1113:             switch (ch) {
                   1114:             case ' ':
                   1115:                 r->space_in_uri = 1;
                   1116:                 state = sw_check_uri;
                   1117:                 break;
                   1118:             case '.':
                   1119:                 r->complex_uri = 1;
                   1120:                 state = sw_uri;
                   1121:                 break;
                   1122:             case '%':
                   1123:                 r->quoted_uri = 1;
                   1124:                 state = sw_uri;
                   1125:                 break;
                   1126:             case '/':
                   1127:                 r->complex_uri = 1;
                   1128:                 state = sw_uri;
                   1129:                 break;
                   1130: #if (NGX_WIN32)
                   1131:             case '\\':
                   1132:                 r->complex_uri = 1;
                   1133:                 state = sw_uri;
                   1134:                 break;
                   1135: #endif
                   1136:             case '?':
                   1137:                 r->args_start = p + 1;
                   1138:                 state = sw_uri;
                   1139:                 break;
                   1140:             case '#':
                   1141:                 r->complex_uri = 1;
                   1142:                 state = sw_uri;
                   1143:                 break;
                   1144:             case '+':
                   1145:                 r->plus_in_uri = 1;
                   1146:                 break;
                   1147:             default:
                   1148:                 state = sw_check_uri;
                   1149:                 break;
                   1150:             }
                   1151:             break;
                   1152: 
                   1153:         /* check "/", "%" and "\" (Win32) in URI */
                   1154:         case sw_check_uri:
                   1155: 
                   1156:             if (usual[ch >> 5] & (1 << (ch & 0x1f))) {
                   1157:                 break;
                   1158:             }
                   1159: 
                   1160:             switch (ch) {
                   1161:             case '/':
                   1162: #if (NGX_WIN32)
                   1163:                 if (r->uri_ext == p) {
                   1164:                     r->complex_uri = 1;
                   1165:                     state = sw_uri;
                   1166:                     break;
                   1167:                 }
                   1168: #endif
                   1169:                 r->uri_ext = NULL;
                   1170:                 state = sw_after_slash_in_uri;
                   1171:                 break;
                   1172:             case '.':
                   1173:                 r->uri_ext = p + 1;
                   1174:                 break;
                   1175:             case ' ':
                   1176:                 r->space_in_uri = 1;
                   1177:                 break;
                   1178: #if (NGX_WIN32)
                   1179:             case '\\':
                   1180:                 r->complex_uri = 1;
                   1181:                 state = sw_after_slash_in_uri;
                   1182:                 break;
                   1183: #endif
                   1184:             case '%':
                   1185:                 r->quoted_uri = 1;
                   1186:                 state = sw_uri;
                   1187:                 break;
                   1188:             case '?':
                   1189:                 r->args_start = p + 1;
                   1190:                 state = sw_uri;
                   1191:                 break;
                   1192:             case '#':
                   1193:                 r->complex_uri = 1;
                   1194:                 state = sw_uri;
                   1195:                 break;
                   1196:             case '+':
                   1197:                 r->plus_in_uri = 1;
                   1198:                 break;
                   1199:             }
                   1200:             break;
                   1201: 
                   1202:         /* URI */
                   1203:         case sw_uri:
                   1204: 
                   1205:             if (usual[ch >> 5] & (1 << (ch & 0x1f))) {
                   1206:                 break;
                   1207:             }
                   1208: 
                   1209:             switch (ch) {
                   1210:             case ' ':
                   1211:                 r->space_in_uri = 1;
                   1212:                 break;
                   1213:             case '#':
                   1214:                 r->complex_uri = 1;
                   1215:                 break;
                   1216:             }
                   1217:             break;
                   1218:         }
                   1219:     }
                   1220: 
                   1221:     return NGX_OK;
                   1222: }
                   1223: 
                   1224: 
                   1225: ngx_int_t
                   1226: ngx_http_parse_complex_uri(ngx_http_request_t *r, ngx_uint_t merge_slashes)
                   1227: {
                   1228:     u_char  c, ch, decoded, *p, *u;
                   1229:     enum {
                   1230:         sw_usual = 0,
                   1231:         sw_slash,
                   1232:         sw_dot,
                   1233:         sw_dot_dot,
                   1234:         sw_quoted,
                   1235:         sw_quoted_second
                   1236:     } state, quoted_state;
                   1237: 
                   1238: #if (NGX_SUPPRESS_WARN)
                   1239:     decoded = '\0';
                   1240:     quoted_state = sw_usual;
                   1241: #endif
                   1242: 
                   1243:     state = sw_usual;
                   1244:     p = r->uri_start;
                   1245:     u = r->uri.data;
                   1246:     r->uri_ext = NULL;
                   1247:     r->args_start = NULL;
                   1248: 
                   1249:     ch = *p++;
                   1250: 
                   1251:     while (p <= r->uri_end) {
                   1252: 
                   1253:         /*
                   1254:          * we use "ch = *p++" inside the cycle, but this operation is safe,
                   1255:          * because after the URI there is always at least one character:
                   1256:          * the line feed
                   1257:          */
                   1258: 
                   1259:         ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                   1260:                        "s:%d in:'%Xd:%c', out:'%c'", state, ch, ch, *u);
                   1261: 
                   1262:         switch (state) {
                   1263: 
                   1264:         case sw_usual:
                   1265: 
                   1266:             if (usual[ch >> 5] & (1 << (ch & 0x1f))) {
                   1267:                 *u++ = ch;
                   1268:                 ch = *p++;
                   1269:                 break;
                   1270:             }
                   1271: 
                   1272:             switch(ch) {
                   1273: #if (NGX_WIN32)
                   1274:             case '\\':
                   1275:                 if (u - 2 >= r->uri.data
                   1276:                     && *(u - 1) == '.' && *(u - 2) != '.')
                   1277:                 {
                   1278:                     u--;
                   1279:                 }
                   1280: 
                   1281:                 r->uri_ext = NULL;
                   1282: 
                   1283:                 if (p == r->uri_start + r->uri.len) {
                   1284: 
                   1285:                     /*
                   1286:                      * we omit the last "\" to cause redirect because
                   1287:                      * the browsers do not treat "\" as "/" in relative URL path
                   1288:                      */
                   1289: 
                   1290:                     break;
                   1291:                 }
                   1292: 
                   1293:                 state = sw_slash;
                   1294:                 *u++ = '/';
                   1295:                 break;
                   1296: #endif
                   1297:             case '/':
                   1298: #if (NGX_WIN32)
                   1299:                 if (u - 2 >= r->uri.data
                   1300:                     && *(u - 1) == '.' && *(u - 2) != '.')
                   1301:                 {
                   1302:                     u--;
                   1303:                 }
                   1304: #endif
                   1305:                 r->uri_ext = NULL;
                   1306:                 state = sw_slash;
                   1307:                 *u++ = ch;
                   1308:                 break;
                   1309:             case '%':
                   1310:                 quoted_state = state;
                   1311:                 state = sw_quoted;
                   1312:                 break;
                   1313:             case '?':
                   1314:                 r->args_start = p;
                   1315:                 goto args;
                   1316:             case '#':
                   1317:                 goto done;
                   1318:             case '.':
                   1319:                 r->uri_ext = u + 1;
                   1320:                 *u++ = ch;
                   1321:                 break;
                   1322:             case '+':
                   1323:                 r->plus_in_uri = 1;
                   1324:                 /* fall through */
                   1325:             default:
                   1326:                 *u++ = ch;
                   1327:                 break;
                   1328:             }
                   1329: 
                   1330:             ch = *p++;
                   1331:             break;
                   1332: 
                   1333:         case sw_slash:
                   1334: 
                   1335:             if (usual[ch >> 5] & (1 << (ch & 0x1f))) {
                   1336:                 state = sw_usual;
                   1337:                 *u++ = ch;
                   1338:                 ch = *p++;
                   1339:                 break;
                   1340:             }
                   1341: 
                   1342:             switch(ch) {
                   1343: #if (NGX_WIN32)
                   1344:             case '\\':
                   1345:                 break;
                   1346: #endif
                   1347:             case '/':
                   1348:                 if (!merge_slashes) {
                   1349:                     *u++ = ch;
                   1350:                 }
                   1351:                 break;
                   1352:             case '.':
                   1353:                 state = sw_dot;
                   1354:                 *u++ = ch;
                   1355:                 break;
                   1356:             case '%':
                   1357:                 quoted_state = state;
                   1358:                 state = sw_quoted;
                   1359:                 break;
                   1360:             case '?':
                   1361:                 r->args_start = p;
                   1362:                 goto args;
                   1363:             case '#':
                   1364:                 goto done;
                   1365:             case '+':
                   1366:                 r->plus_in_uri = 1;
                   1367:             default:
                   1368:                 state = sw_usual;
                   1369:                 *u++ = ch;
                   1370:                 break;
                   1371:             }
                   1372: 
                   1373:             ch = *p++;
                   1374:             break;
                   1375: 
                   1376:         case sw_dot:
                   1377: 
                   1378:             if (usual[ch >> 5] & (1 << (ch & 0x1f))) {
                   1379:                 state = sw_usual;
                   1380:                 *u++ = ch;
                   1381:                 ch = *p++;
                   1382:                 break;
                   1383:             }
                   1384: 
                   1385:             switch(ch) {
                   1386: #if (NGX_WIN32)
                   1387:             case '\\':
                   1388: #endif
                   1389:             case '/':
                   1390:                 state = sw_slash;
                   1391:                 u--;
                   1392:                 break;
                   1393:             case '.':
                   1394:                 state = sw_dot_dot;
                   1395:                 *u++ = ch;
                   1396:                 break;
                   1397:             case '%':
                   1398:                 quoted_state = state;
                   1399:                 state = sw_quoted;
                   1400:                 break;
                   1401:             case '?':
                   1402:                 r->args_start = p;
                   1403:                 goto args;
                   1404:             case '#':
                   1405:                 goto done;
                   1406:             case '+':
                   1407:                 r->plus_in_uri = 1;
                   1408:             default:
                   1409:                 state = sw_usual;
                   1410:                 *u++ = ch;
                   1411:                 break;
                   1412:             }
                   1413: 
                   1414:             ch = *p++;
                   1415:             break;
                   1416: 
                   1417:         case sw_dot_dot:
                   1418: 
                   1419:             if (usual[ch >> 5] & (1 << (ch & 0x1f))) {
                   1420:                 state = sw_usual;
                   1421:                 *u++ = ch;
                   1422:                 ch = *p++;
                   1423:                 break;
                   1424:             }
                   1425: 
                   1426:             switch(ch) {
                   1427: #if (NGX_WIN32)
                   1428:             case '\\':
                   1429: #endif
                   1430:             case '/':
                   1431:                 state = sw_slash;
                   1432:                 u -= 5;
                   1433:                 for ( ;; ) {
                   1434:                     if (u < r->uri.data) {
                   1435:                         return NGX_HTTP_PARSE_INVALID_REQUEST;
                   1436:                     }
                   1437:                     if (*u == '/') {
                   1438:                         u++;
                   1439:                         break;
                   1440:                     }
                   1441:                     u--;
                   1442:                 }
                   1443:                 break;
                   1444:             case '%':
                   1445:                 quoted_state = state;
                   1446:                 state = sw_quoted;
                   1447:                 break;
                   1448:             case '?':
                   1449:                 r->args_start = p;
                   1450:                 goto args;
                   1451:             case '#':
                   1452:                 goto done;
                   1453:             case '+':
                   1454:                 r->plus_in_uri = 1;
                   1455:             default:
                   1456:                 state = sw_usual;
                   1457:                 *u++ = ch;
                   1458:                 break;
                   1459:             }
                   1460: 
                   1461:             ch = *p++;
                   1462:             break;
                   1463: 
                   1464:         case sw_quoted:
                   1465:             r->quoted_uri = 1;
                   1466: 
                   1467:             if (ch >= '0' && ch <= '9') {
                   1468:                 decoded = (u_char) (ch - '0');
                   1469:                 state = sw_quoted_second;
                   1470:                 ch = *p++;
                   1471:                 break;
                   1472:             }
                   1473: 
                   1474:             c = (u_char) (ch | 0x20);
                   1475:             if (c >= 'a' && c <= 'f') {
                   1476:                 decoded = (u_char) (c - 'a' + 10);
                   1477:                 state = sw_quoted_second;
                   1478:                 ch = *p++;
                   1479:                 break;
                   1480:             }
                   1481: 
                   1482:             return NGX_HTTP_PARSE_INVALID_REQUEST;
                   1483: 
                   1484:         case sw_quoted_second:
                   1485:             if (ch >= '0' && ch <= '9') {
                   1486:                 ch = (u_char) ((decoded << 4) + ch - '0');
                   1487: 
                   1488:                 if (ch == '%' || ch == '#') {
                   1489:                     state = sw_usual;
                   1490:                     *u++ = ch;
                   1491:                     ch = *p++;
                   1492:                     break;
                   1493: 
                   1494:                 } else if (ch == '\0') {
                   1495:                     return NGX_HTTP_PARSE_INVALID_REQUEST;
                   1496:                 }
                   1497: 
                   1498:                 state = quoted_state;
                   1499:                 break;
                   1500:             }
                   1501: 
                   1502:             c = (u_char) (ch | 0x20);
                   1503:             if (c >= 'a' && c <= 'f') {
                   1504:                 ch = (u_char) ((decoded << 4) + c - 'a' + 10);
                   1505: 
                   1506:                 if (ch == '?') {
                   1507:                     state = sw_usual;
                   1508:                     *u++ = ch;
                   1509:                     ch = *p++;
                   1510:                     break;
                   1511: 
                   1512:                 } else if (ch == '+') {
                   1513:                     r->plus_in_uri = 1;
                   1514:                 }
                   1515: 
                   1516:                 state = quoted_state;
                   1517:                 break;
                   1518:             }
                   1519: 
                   1520:             return NGX_HTTP_PARSE_INVALID_REQUEST;
                   1521:         }
                   1522:     }
                   1523: 
                   1524: done:
                   1525: 
                   1526:     r->uri.len = u - r->uri.data;
                   1527: 
                   1528:     if (r->uri_ext) {
                   1529:         r->exten.len = u - r->uri_ext;
                   1530:         r->exten.data = r->uri_ext;
                   1531:     }
                   1532: 
                   1533:     r->uri_ext = NULL;
                   1534: 
                   1535:     return NGX_OK;
                   1536: 
                   1537: args:
                   1538: 
                   1539:     while (p < r->uri_end) {
                   1540:         if (*p++ != '#') {
                   1541:             continue;
                   1542:         }
                   1543: 
                   1544:         r->args.len = p - 1 - r->args_start;
                   1545:         r->args.data = r->args_start;
                   1546:         r->args_start = NULL;
                   1547: 
                   1548:         break;
                   1549:     }
                   1550: 
                   1551:     r->uri.len = u - r->uri.data;
                   1552: 
                   1553:     if (r->uri_ext) {
                   1554:         r->exten.len = u - r->uri_ext;
                   1555:         r->exten.data = r->uri_ext;
                   1556:     }
                   1557: 
                   1558:     r->uri_ext = NULL;
                   1559: 
                   1560:     return NGX_OK;
                   1561: }
                   1562: 
                   1563: 
                   1564: ngx_int_t
                   1565: ngx_http_parse_status_line(ngx_http_request_t *r, ngx_buf_t *b,
                   1566:     ngx_http_status_t *status)
                   1567: {
                   1568:     u_char   ch;
                   1569:     u_char  *p;
                   1570:     enum {
                   1571:         sw_start = 0,
                   1572:         sw_H,
                   1573:         sw_HT,
                   1574:         sw_HTT,
                   1575:         sw_HTTP,
                   1576:         sw_first_major_digit,
                   1577:         sw_major_digit,
                   1578:         sw_first_minor_digit,
                   1579:         sw_minor_digit,
                   1580:         sw_status,
                   1581:         sw_space_after_status,
                   1582:         sw_status_text,
                   1583:         sw_almost_done
                   1584:     } state;
                   1585: 
                   1586:     state = r->state;
                   1587: 
                   1588:     for (p = b->pos; p < b->last; p++) {
                   1589:         ch = *p;
                   1590: 
                   1591:         switch (state) {
                   1592: 
                   1593:         /* "HTTP/" */
                   1594:         case sw_start:
                   1595:             switch (ch) {
                   1596:             case 'H':
                   1597:                 state = sw_H;
                   1598:                 break;
                   1599:             default:
                   1600:                 return NGX_ERROR;
                   1601:             }
                   1602:             break;
                   1603: 
                   1604:         case sw_H:
                   1605:             switch (ch) {
                   1606:             case 'T':
                   1607:                 state = sw_HT;
                   1608:                 break;
                   1609:             default:
                   1610:                 return NGX_ERROR;
                   1611:             }
                   1612:             break;
                   1613: 
                   1614:         case sw_HT:
                   1615:             switch (ch) {
                   1616:             case 'T':
                   1617:                 state = sw_HTT;
                   1618:                 break;
                   1619:             default:
                   1620:                 return NGX_ERROR;
                   1621:             }
                   1622:             break;
                   1623: 
                   1624:         case sw_HTT:
                   1625:             switch (ch) {
                   1626:             case 'P':
                   1627:                 state = sw_HTTP;
                   1628:                 break;
                   1629:             default:
                   1630:                 return NGX_ERROR;
                   1631:             }
                   1632:             break;
                   1633: 
                   1634:         case sw_HTTP:
                   1635:             switch (ch) {
                   1636:             case '/':
                   1637:                 state = sw_first_major_digit;
                   1638:                 break;
                   1639:             default:
                   1640:                 return NGX_ERROR;
                   1641:             }
                   1642:             break;
                   1643: 
                   1644:         /* the first digit of major HTTP version */
                   1645:         case sw_first_major_digit:
                   1646:             if (ch < '1' || ch > '9') {
                   1647:                 return NGX_ERROR;
                   1648:             }
                   1649: 
                   1650:             r->http_major = ch - '0';
                   1651:             state = sw_major_digit;
                   1652:             break;
                   1653: 
                   1654:         /* the major HTTP version or dot */
                   1655:         case sw_major_digit:
                   1656:             if (ch == '.') {
                   1657:                 state = sw_first_minor_digit;
                   1658:                 break;
                   1659:             }
                   1660: 
                   1661:             if (ch < '0' || ch > '9') {
                   1662:                 return NGX_ERROR;
                   1663:             }
                   1664: 
                   1665:             r->http_major = r->http_major * 10 + ch - '0';
                   1666:             break;
                   1667: 
                   1668:         /* the first digit of minor HTTP version */
                   1669:         case sw_first_minor_digit:
                   1670:             if (ch < '0' || ch > '9') {
                   1671:                 return NGX_ERROR;
                   1672:             }
                   1673: 
                   1674:             r->http_minor = ch - '0';
                   1675:             state = sw_minor_digit;
                   1676:             break;
                   1677: 
                   1678:         /* the minor HTTP version or the end of the request line */
                   1679:         case sw_minor_digit:
                   1680:             if (ch == ' ') {
                   1681:                 state = sw_status;
                   1682:                 break;
                   1683:             }
                   1684: 
                   1685:             if (ch < '0' || ch > '9') {
                   1686:                 return NGX_ERROR;
                   1687:             }
                   1688: 
                   1689:             r->http_minor = r->http_minor * 10 + ch - '0';
                   1690:             break;
                   1691: 
                   1692:         /* HTTP status code */
                   1693:         case sw_status:
                   1694:             if (ch == ' ') {
                   1695:                 break;
                   1696:             }
                   1697: 
                   1698:             if (ch < '0' || ch > '9') {
                   1699:                 return NGX_ERROR;
                   1700:             }
                   1701: 
                   1702:             status->code = status->code * 10 + ch - '0';
                   1703: 
                   1704:             if (++status->count == 3) {
                   1705:                 state = sw_space_after_status;
                   1706:                 status->start = p - 2;
                   1707:             }
                   1708: 
                   1709:             break;
                   1710: 
                   1711:         /* space or end of line */
                   1712:         case sw_space_after_status:
                   1713:             switch (ch) {
                   1714:             case ' ':
                   1715:                 state = sw_status_text;
                   1716:                 break;
                   1717:             case '.':                    /* IIS may send 403.1, 403.2, etc */
                   1718:                 state = sw_status_text;
                   1719:                 break;
                   1720:             case CR:
                   1721:                 state = sw_almost_done;
                   1722:                 break;
                   1723:             case LF:
                   1724:                 goto done;
                   1725:             default:
                   1726:                 return NGX_ERROR;
                   1727:             }
                   1728:             break;
                   1729: 
                   1730:         /* any text until end of line */
                   1731:         case sw_status_text:
                   1732:             switch (ch) {
                   1733:             case CR:
                   1734:                 state = sw_almost_done;
                   1735: 
                   1736:                 break;
                   1737:             case LF:
                   1738:                 goto done;
                   1739:             }
                   1740:             break;
                   1741: 
                   1742:         /* end of status line */
                   1743:         case sw_almost_done:
                   1744:             status->end = p - 1;
                   1745:             switch (ch) {
                   1746:             case LF:
                   1747:                 goto done;
                   1748:             default:
                   1749:                 return NGX_ERROR;
                   1750:             }
                   1751:         }
                   1752:     }
                   1753: 
                   1754:     b->pos = p;
                   1755:     r->state = state;
                   1756: 
                   1757:     return NGX_AGAIN;
                   1758: 
                   1759: done:
                   1760: 
                   1761:     b->pos = p + 1;
                   1762: 
                   1763:     if (status->end == NULL) {
                   1764:         status->end = p;
                   1765:     }
                   1766: 
                   1767:     status->http_version = r->http_major * 1000 + r->http_minor;
                   1768:     r->state = sw_start;
                   1769: 
                   1770:     return NGX_OK;
                   1771: }
                   1772: 
                   1773: 
                   1774: ngx_int_t
                   1775: ngx_http_parse_unsafe_uri(ngx_http_request_t *r, ngx_str_t *uri,
                   1776:     ngx_str_t *args, ngx_uint_t *flags)
                   1777: {
                   1778:     u_char  ch, *p;
                   1779:     size_t  len;
                   1780: 
                   1781:     len = uri->len;
                   1782:     p = uri->data;
                   1783: 
                   1784:     if (len == 0 || p[0] == '?') {
                   1785:         goto unsafe;
                   1786:     }
                   1787: 
                   1788:     if (p[0] == '.' && len == 3 && p[1] == '.' && (ngx_path_separator(p[2]))) {
                   1789:         goto unsafe;
                   1790:     }
                   1791: 
                   1792:     for ( /* void */ ; len; len--) {
                   1793: 
                   1794:         ch = *p++;
                   1795: 
                   1796:         if (usual[ch >> 5] & (1 << (ch & 0x1f))) {
                   1797:             continue;
                   1798:         }
                   1799: 
                   1800:         if (ch == '?') {
                   1801:             args->len = len - 1;
                   1802:             args->data = p;
                   1803:             uri->len -= len;
                   1804: 
                   1805:             return NGX_OK;
                   1806:         }
                   1807: 
                   1808:         if (ch == '\0') {
                   1809:             goto unsafe;
                   1810:         }
                   1811: 
                   1812:         if (ngx_path_separator(ch) && len > 2) {
                   1813: 
                   1814:             /* detect "/../" */
                   1815: 
                   1816:             if (p[0] == '.' && p[1] == '.' && ngx_path_separator(p[2])) {
                   1817:                 goto unsafe;
                   1818:             }
                   1819:         }
                   1820:     }
                   1821: 
                   1822:     return NGX_OK;
                   1823: 
                   1824: unsafe:
                   1825: 
                   1826:     if (*flags & NGX_HTTP_LOG_UNSAFE) {
                   1827:         ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                   1828:                       "unsafe URI \"%V\" was detected", uri);
                   1829:     }
                   1830: 
                   1831:     return NGX_ERROR;
                   1832: }
                   1833: 
                   1834: 
                   1835: ngx_int_t
                   1836: ngx_http_parse_multi_header_lines(ngx_array_t *headers, ngx_str_t *name,
                   1837:     ngx_str_t *value)
                   1838: {
                   1839:     ngx_uint_t         i;
                   1840:     u_char            *start, *last, *end, ch;
                   1841:     ngx_table_elt_t  **h;
                   1842: 
                   1843:     h = headers->elts;
                   1844: 
                   1845:     for (i = 0; i < headers->nelts; i++) {
                   1846: 
                   1847:         ngx_log_debug2(NGX_LOG_DEBUG_HTTP, headers->pool->log, 0,
                   1848:                        "parse header: \"%V: %V\"", &h[i]->key, &h[i]->value);
                   1849: 
                   1850:         if (name->len > h[i]->value.len) {
                   1851:             continue;
                   1852:         }
                   1853: 
                   1854:         start = h[i]->value.data;
                   1855:         end = h[i]->value.data + h[i]->value.len;
                   1856: 
                   1857:         while (start < end) {
                   1858: 
                   1859:             if (ngx_strncasecmp(start, name->data, name->len) != 0) {
                   1860:                 goto skip;
                   1861:             }
                   1862: 
                   1863:             for (start += name->len; start < end && *start == ' '; start++) {
                   1864:                 /* void */
                   1865:             }
                   1866: 
                   1867:             if (value == NULL) {
                   1868:                 if (start == end || *start == ',') {
                   1869:                     return i;
                   1870:                 }
                   1871: 
                   1872:                 goto skip;
                   1873:             }
                   1874: 
                   1875:             if (start == end || *start++ != '=') {
                   1876:                 /* the invalid header value */
                   1877:                 goto skip;
                   1878:             }
                   1879: 
                   1880:             while (start < end && *start == ' ') { start++; }
                   1881: 
                   1882:             for (last = start; last < end && *last != ';'; last++) {
                   1883:                 /* void */
                   1884:             }
                   1885: 
                   1886:             value->len = last - start;
                   1887:             value->data = start;
                   1888: 
                   1889:             return i;
                   1890: 
                   1891:         skip:
                   1892: 
                   1893:             while (start < end) {
                   1894:                 ch = *start++;
                   1895:                 if (ch == ';' || ch == ',') {
                   1896:                     break;
                   1897:                 }
                   1898:             }
                   1899: 
                   1900:             while (start < end && *start == ' ') { start++; }
                   1901:         }
                   1902:     }
                   1903: 
                   1904:     return NGX_DECLINED;
                   1905: }
                   1906: 
                   1907: 
                   1908: ngx_int_t
                   1909: ngx_http_arg(ngx_http_request_t *r, u_char *name, size_t len, ngx_str_t *value)
                   1910: {
                   1911:     u_char  *p, *last;
                   1912: 
                   1913:     if (r->args.len == 0) {
                   1914:         return NGX_DECLINED;
                   1915:     }
                   1916: 
                   1917:     p = r->args.data;
                   1918:     last = p + r->args.len;
                   1919: 
                   1920:     for ( /* void */ ; p < last; p++) {
                   1921: 
                   1922:         /* we need '=' after name, so drop one char from last */
                   1923: 
                   1924:         p = ngx_strlcasestrn(p, last - 1, name, len - 1);
                   1925: 
                   1926:         if (p == NULL) {
                   1927:             return NGX_DECLINED;
                   1928:         }
                   1929: 
                   1930:         if ((p == r->args.data || *(p - 1) == '&') && *(p + len) == '=') {
                   1931: 
                   1932:             value->data = p + len + 1;
                   1933: 
                   1934:             p = ngx_strlchr(p, last, '&');
                   1935: 
                   1936:             if (p == NULL) {
                   1937:                 p = r->args.data + r->args.len;
                   1938:             }
                   1939: 
                   1940:             value->len = p - value->data;
                   1941: 
                   1942:             return NGX_OK;
                   1943:         }
                   1944:     }
                   1945: 
                   1946:     return NGX_DECLINED;
                   1947: }
                   1948: 
                   1949: 
                   1950: void
                   1951: ngx_http_split_args(ngx_http_request_t *r, ngx_str_t *uri, ngx_str_t *args)
                   1952: {
                   1953:     u_char  *p, *last;
                   1954: 
                   1955:     last = uri->data + uri->len;
                   1956: 
                   1957:     p = ngx_strlchr(uri->data, last, '?');
                   1958: 
                   1959:     if (p) {
                   1960:         uri->len = p - uri->data;
                   1961:         p++;
                   1962:         args->len = last - p;
                   1963:         args->data = p;
                   1964: 
                   1965:     } else {
                   1966:         args->len = 0;
                   1967:     }
                   1968: }
                   1969: 
                   1970: 
                   1971: ngx_int_t
                   1972: ngx_http_parse_chunked(ngx_http_request_t *r, ngx_buf_t *b,
                   1973:     ngx_http_chunked_t *ctx)
                   1974: {
                   1975:     u_char     *pos, ch, c;
                   1976:     ngx_int_t   rc;
                   1977:     enum {
                   1978:         sw_chunk_start = 0,
                   1979:         sw_chunk_size,
                   1980:         sw_chunk_extension,
                   1981:         sw_chunk_extension_almost_done,
                   1982:         sw_chunk_data,
                   1983:         sw_after_data,
                   1984:         sw_after_data_almost_done,
                   1985:         sw_last_chunk_extension,
                   1986:         sw_last_chunk_extension_almost_done,
                   1987:         sw_trailer,
                   1988:         sw_trailer_almost_done,
                   1989:         sw_trailer_header,
                   1990:         sw_trailer_header_almost_done
                   1991:     } state;
                   1992: 
                   1993:     state = ctx->state;
                   1994: 
                   1995:     if (state == sw_chunk_data && ctx->size == 0) {
                   1996:         state = sw_after_data;
                   1997:     }
                   1998: 
                   1999:     rc = NGX_AGAIN;
                   2000: 
                   2001:     for (pos = b->pos; pos < b->last; pos++) {
                   2002: 
                   2003:         ch = *pos;
                   2004: 
                   2005:         ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                   2006:                        "http chunked byte: %02Xd s:%d", ch, state);
                   2007: 
                   2008:         switch (state) {
                   2009: 
                   2010:         case sw_chunk_start:
                   2011:             if (ch >= '0' && ch <= '9') {
                   2012:                 state = sw_chunk_size;
                   2013:                 ctx->size = ch - '0';
                   2014:                 break;
                   2015:             }
                   2016: 
                   2017:             c = (u_char) (ch | 0x20);
                   2018: 
                   2019:             if (c >= 'a' && c <= 'f') {
                   2020:                 state = sw_chunk_size;
                   2021:                 ctx->size = c - 'a' + 10;
                   2022:                 break;
                   2023:             }
                   2024: 
                   2025:             goto invalid;
                   2026: 
                   2027:         case sw_chunk_size:
                   2028:             if (ch >= '0' && ch <= '9') {
                   2029:                 ctx->size = ctx->size * 16 + (ch - '0');
                   2030:                 break;
                   2031:             }
                   2032: 
                   2033:             c = (u_char) (ch | 0x20);
                   2034: 
                   2035:             if (c >= 'a' && c <= 'f') {
                   2036:                 ctx->size = ctx->size * 16 + (c - 'a' + 10);
                   2037:                 break;
                   2038:             }
                   2039: 
                   2040:             if (ctx->size == 0) {
                   2041: 
                   2042:                 switch (ch) {
                   2043:                 case CR:
                   2044:                     state = sw_last_chunk_extension_almost_done;
                   2045:                     break;
                   2046:                 case LF:
                   2047:                     state = sw_trailer;
                   2048:                     break;
                   2049:                 case ';':
                   2050:                 case ' ':
                   2051:                 case '\t':
                   2052:                     state = sw_last_chunk_extension;
                   2053:                     break;
                   2054:                 default:
                   2055:                     goto invalid;
                   2056:                 }
                   2057: 
                   2058:                 break;
                   2059:             }
                   2060: 
                   2061:             switch (ch) {
                   2062:             case CR:
                   2063:                 state = sw_chunk_extension_almost_done;
                   2064:                 break;
                   2065:             case LF:
                   2066:                 state = sw_chunk_data;
                   2067:                 break;
                   2068:             case ';':
                   2069:             case ' ':
                   2070:             case '\t':
                   2071:                 state = sw_chunk_extension;
                   2072:                 break;
                   2073:             default:
                   2074:                 goto invalid;
                   2075:             }
                   2076: 
                   2077:             break;
                   2078: 
                   2079:         case sw_chunk_extension:
                   2080:             switch (ch) {
                   2081:             case CR:
                   2082:                 state = sw_chunk_extension_almost_done;
                   2083:                 break;
                   2084:             case LF:
                   2085:                 state = sw_chunk_data;
                   2086:             }
                   2087:             break;
                   2088: 
                   2089:         case sw_chunk_extension_almost_done:
                   2090:             if (ch == LF) {
                   2091:                 state = sw_chunk_data;
                   2092:                 break;
                   2093:             }
                   2094:             goto invalid;
                   2095: 
                   2096:         case sw_chunk_data:
                   2097:             rc = NGX_OK;
                   2098:             goto data;
                   2099: 
                   2100:         case sw_after_data:
                   2101:             switch (ch) {
                   2102:             case CR:
                   2103:                 state = sw_after_data_almost_done;
                   2104:                 break;
                   2105:             case LF:
                   2106:                 state = sw_chunk_start;
                   2107:             }
                   2108:             break;
                   2109: 
                   2110:         case sw_after_data_almost_done:
                   2111:             if (ch == LF) {
                   2112:                 state = sw_chunk_start;
                   2113:                 break;
                   2114:             }
                   2115:             goto invalid;
                   2116: 
                   2117:         case sw_last_chunk_extension:
                   2118:             switch (ch) {
                   2119:             case CR:
                   2120:                 state = sw_last_chunk_extension_almost_done;
                   2121:                 break;
                   2122:             case LF:
                   2123:                 state = sw_trailer;
                   2124:             }
                   2125:             break;
                   2126: 
                   2127:         case sw_last_chunk_extension_almost_done:
                   2128:             if (ch == LF) {
                   2129:                 state = sw_trailer;
                   2130:                 break;
                   2131:             }
                   2132:             goto invalid;
                   2133: 
                   2134:         case sw_trailer:
                   2135:             switch (ch) {
                   2136:             case CR:
                   2137:                 state = sw_trailer_almost_done;
                   2138:                 break;
                   2139:             case LF:
                   2140:                 goto done;
                   2141:             default:
                   2142:                 state = sw_trailer_header;
                   2143:             }
                   2144:             break;
                   2145: 
                   2146:         case sw_trailer_almost_done:
                   2147:             if (ch == LF) {
                   2148:                 goto done;
                   2149:             }
                   2150:             goto invalid;
                   2151: 
                   2152:         case sw_trailer_header:
                   2153:             switch (ch) {
                   2154:             case CR:
                   2155:                 state = sw_trailer_header_almost_done;
                   2156:                 break;
                   2157:             case LF:
                   2158:                 state = sw_trailer;
                   2159:             }
                   2160:             break;
                   2161: 
                   2162:         case sw_trailer_header_almost_done:
                   2163:             if (ch == LF) {
                   2164:                 state = sw_trailer;
                   2165:                 break;
                   2166:             }
                   2167:             goto invalid;
                   2168: 
                   2169:         }
                   2170:     }
                   2171: 
                   2172: data:
                   2173: 
                   2174:     ctx->state = state;
                   2175:     b->pos = pos;
                   2176: 
                   2177:     switch (state) {
                   2178: 
                   2179:     case sw_chunk_start:
                   2180:         ctx->length = 3 /* "0" LF LF */;
                   2181:         break;
                   2182:     case sw_chunk_size:
                   2183:         ctx->length = 2 /* LF LF */
                   2184:                       + (ctx->size ? ctx->size + 4 /* LF "0" LF LF */ : 0);
                   2185:         break;
                   2186:     case sw_chunk_extension:
                   2187:     case sw_chunk_extension_almost_done:
                   2188:         ctx->length = 1 /* LF */ + ctx->size + 4 /* LF "0" LF LF */;
                   2189:         break;
                   2190:     case sw_chunk_data:
                   2191:         ctx->length = ctx->size + 4 /* LF "0" LF LF */;
                   2192:         break;
                   2193:     case sw_after_data:
                   2194:     case sw_after_data_almost_done:
                   2195:         ctx->length = 4 /* LF "0" LF LF */;
                   2196:         break;
                   2197:     case sw_last_chunk_extension:
                   2198:     case sw_last_chunk_extension_almost_done:
                   2199:         ctx->length = 2 /* LF LF */;
                   2200:         break;
                   2201:     case sw_trailer:
                   2202:     case sw_trailer_almost_done:
                   2203:         ctx->length = 1 /* LF */;
                   2204:         break;
                   2205:     case sw_trailer_header:
                   2206:     case sw_trailer_header_almost_done:
                   2207:         ctx->length = 2 /* LF LF */;
                   2208:         break;
                   2209: 
                   2210:     }
                   2211: 
                   2212:     if (ctx->size < 0 || ctx->length < 0) {
                   2213:         goto invalid;
                   2214:     }
                   2215: 
                   2216:     return rc;
                   2217: 
                   2218: done:
                   2219: 
                   2220:     ctx->state = 0;
                   2221:     b->pos = pos + 1;
                   2222: 
                   2223:     return NGX_DONE;
                   2224: 
                   2225: invalid:
                   2226: 
                   2227:     return NGX_ERROR;
                   2228: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>