Annotation of embedaddon/nginx/src/http/ngx_http_parse.c, revision 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>