~ubuntu-branches/ubuntu/trusty/nginx/trusty-proposed

« back to all changes in this revision

Viewing changes to src/http/ngx_http_parse.c

  • Committer: Package Import Robot
  • Author(s): Kartik Mistry
  • Date: 2013-04-25 12:51:45 UTC
  • mfrom: (1.3.28)
  • mto: (1.3.29) (15.1.2 experimental)
  • mto: This revision was merged to the branch mainline in revision 64.
  • Revision ID: package-import@ubuntu.com-20130425125145-ugl0wor6bq0u5eae
Tags: upstream-1.4.0
ImportĀ upstreamĀ versionĀ 1.4.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
 
2
2
/*
3
3
 * Copyright (C) Igor Sysoev
 
4
 * Copyright (C) Nginx, Inc.
4
5
 */
5
6
 
6
7
 
110
111
        sw_schema,
111
112
        sw_schema_slash,
112
113
        sw_schema_slash_slash,
 
114
        sw_host_start,
113
115
        sw_host,
 
116
        sw_host_end,
 
117
        sw_host_ip_literal,
114
118
        sw_port,
 
119
        sw_host_http_09,
115
120
        sw_after_slash_in_uri,
116
121
        sw_check_uri,
 
122
        sw_check_uri_http_09,
117
123
        sw_uri,
118
124
        sw_http_09,
119
125
        sw_http_H,
143
149
                break;
144
150
            }
145
151
 
146
 
            if (ch < 'A' || ch > 'Z') {
 
152
            if ((ch < 'A' || ch > 'Z') && ch != '_') {
147
153
                return NGX_HTTP_PARSE_INVALID_METHOD;
148
154
            }
149
155
 
208
214
                        r->method = NGX_HTTP_MKCOL;
209
215
                    }
210
216
 
 
217
                    if (ngx_str5cmp(m, 'P', 'A', 'T', 'C', 'H')) {
 
218
                        r->method = NGX_HTTP_PATCH;
 
219
                    }
 
220
 
211
221
                    if (ngx_str5cmp(m, 'T', 'R', 'A', 'C', 'E')) {
212
222
                        r->method = NGX_HTTP_TRACE;
213
223
                    }
257
267
                break;
258
268
            }
259
269
 
260
 
            if (ch < 'A' || ch > 'Z') {
 
270
            if ((ch < 'A' || ch > 'Z') && ch != '_') {
261
271
                return NGX_HTTP_PARSE_INVALID_METHOD;
262
272
            }
263
273
 
266
276
        /* space* before URI */
267
277
        case sw_spaces_before_uri:
268
278
 
269
 
            if (ch == '/' ){
 
279
            if (ch == '/') {
270
280
                r->uri_start = p;
271
281
                state = sw_after_slash_in_uri;
272
282
                break;
317
327
        case sw_schema_slash_slash:
318
328
            switch (ch) {
319
329
            case '/':
320
 
                r->host_start = p + 1;
321
 
                state = sw_host;
 
330
                state = sw_host_start;
322
331
                break;
323
332
            default:
324
333
                return NGX_HTTP_PARSE_INVALID_REQUEST;
325
334
            }
326
335
            break;
327
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
 
328
350
        case sw_host:
329
351
 
330
352
            c = (u_char) (ch | 0x20);
336
358
                break;
337
359
            }
338
360
 
 
361
            /* fall through */
 
362
 
 
363
        case sw_host_end:
 
364
 
339
365
            r->host_end = p;
340
366
 
341
367
            switch (ch) {
353
379
                 */
354
380
                r->uri_start = r->schema_end + 1;
355
381
                r->uri_end = r->schema_end + 2;
356
 
                state = sw_http_09;
 
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 */
357
424
                break;
358
425
            default:
359
426
                return NGX_HTTP_PARSE_INVALID_REQUEST;
379
446
                 */
380
447
                r->uri_start = r->schema_end + 1;
381
448
                r->uri_end = r->schema_end + 2;
382
 
                state = sw_http_09;
383
 
                break;
384
 
            default:
385
 
                return NGX_HTTP_PARSE_INVALID_REQUEST;
386
 
            }
387
 
            break;
 
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
 
388
477
 
389
478
        /* check "/.", "//", "%", and "\" (Win32) in URI */
390
479
        case sw_after_slash_in_uri:
397
486
            switch (ch) {
398
487
            case ' ':
399
488
                r->uri_end = p;
400
 
                state = sw_http_09;
 
489
                state = sw_check_uri_http_09;
401
490
                break;
402
491
            case CR:
403
492
                r->uri_end = p;
438
527
                r->plus_in_uri = 1;
439
528
                break;
440
529
            case '\0':
441
 
                r->zero_in_uri = 1;
442
 
                break;
 
530
                return NGX_HTTP_PARSE_INVALID_REQUEST;
443
531
            default:
444
532
                state = sw_check_uri;
445
533
                break;
455
543
 
456
544
            switch (ch) {
457
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
458
553
                r->uri_ext = NULL;
459
554
                state = sw_after_slash_in_uri;
460
555
                break;
463
558
                break;
464
559
            case ' ':
465
560
                r->uri_end = p;
466
 
                state = sw_http_09;
 
561
                state = sw_check_uri_http_09;
467
562
                break;
468
563
            case CR:
469
564
                r->uri_end = p;
496
591
                r->plus_in_uri = 1;
497
592
                break;
498
593
            case '\0':
499
 
                r->zero_in_uri = 1;
500
 
                break;
501
 
            }
502
 
            break;
 
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
 
503
621
 
504
622
        /* URI */
505
623
        case sw_uri:
526
644
                r->complex_uri = 1;
527
645
                break;
528
646
            case '\0':
529
 
                r->zero_in_uri = 1;
530
 
                break;
 
647
                return NGX_HTTP_PARSE_INVALID_REQUEST;
531
648
            }
532
649
            break;
533
650
 
548
665
                state = sw_http_H;
549
666
                break;
550
667
            default:
551
 
                return NGX_HTTP_PARSE_INVALID_REQUEST;
 
668
                r->space_in_uri = 1;
 
669
                state = sw_uri;
 
670
                break;
552
671
            }
553
672
            break;
554
673
 
700
819
 
701
820
 
702
821
ngx_int_t
703
 
ngx_http_parse_header_line(ngx_http_request_t *r, ngx_buf_t *b)
 
822
ngx_http_parse_header_line(ngx_http_request_t *r, ngx_buf_t *b,
 
823
    ngx_uint_t allow_underscores)
704
824
{
705
825
    u_char      c, ch, *p;
706
826
    ngx_uint_t  hash, i;
738
858
 
739
859
        /* first char */
740
860
        case sw_start:
 
861
            r->header_name_start = p;
741
862
            r->invalid_header = 0;
742
863
 
743
864
            switch (ch) {
750
871
                goto header_done;
751
872
            default:
752
873
                state = sw_name;
753
 
                r->header_name_start = p;
754
874
 
755
875
                c = lowcase[ch];
756
876
 
761
881
                    break;
762
882
                }
763
883
 
 
884
                if (ch == '\0') {
 
885
                    return NGX_HTTP_PARSE_INVALID_HEADER;
 
886
                }
 
887
 
764
888
                r->invalid_header = 1;
765
889
 
766
890
                break;
779
903
                break;
780
904
            }
781
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
 
782
919
            if (ch == ':') {
783
920
                r->header_name_end = p;
784
921
                state = sw_space_before_value;
810
947
                break;
811
948
            }
812
949
 
 
950
            if (ch == '\0') {
 
951
                return NGX_HTTP_PARSE_INVALID_HEADER;
 
952
            }
 
953
 
813
954
            r->invalid_header = 1;
814
955
 
815
956
            break;
828
969
                r->header_start = p;
829
970
                r->header_end = p;
830
971
                goto done;
 
972
            case '\0':
 
973
                return NGX_HTTP_PARSE_INVALID_HEADER;
831
974
            default:
832
975
                r->header_start = p;
833
976
                state = sw_value;
849
992
            case LF:
850
993
                r->header_end = p;
851
994
                goto done;
 
995
            case '\0':
 
996
                return NGX_HTTP_PARSE_INVALID_HEADER;
852
997
            }
853
998
            break;
854
999
 
862
1007
                break;
863
1008
            case LF:
864
1009
                goto done;
 
1010
            case '\0':
 
1011
                return NGX_HTTP_PARSE_INVALID_HEADER;
865
1012
            default:
866
1013
                state = sw_value;
867
1014
                break;
928
1075
 
929
1076
 
930
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
931
1226
ngx_http_parse_complex_uri(ngx_http_request_t *r, ngx_uint_t merge_slashes)
932
1227
{
933
1228
    u_char  c, ch, decoded, *p, *u;
936
1231
        sw_slash,
937
1232
        sw_dot,
938
1233
        sw_dot_dot,
939
 
#if (NGX_WIN32)
940
 
        sw_dot_dot_dot,
941
 
#endif
942
1234
        sw_quoted,
943
1235
        sw_quoted_second
944
1236
    } state, quoted_state;
960
1252
 
961
1253
        /*
962
1254
         * we use "ch = *p++" inside the cycle, but this operation is safe,
963
 
         * because after the URI there is always at least one charcter:
 
1255
         * because after the URI there is always at least one character:
964
1256
         * the line feed
965
1257
         */
966
1258
 
980
1272
            switch(ch) {
981
1273
#if (NGX_WIN32)
982
1274
            case '\\':
 
1275
                if (u - 2 >= r->uri.data
 
1276
                    && *(u - 1) == '.' && *(u - 2) != '.')
 
1277
                {
 
1278
                    u--;
 
1279
                }
 
1280
 
983
1281
                r->uri_ext = NULL;
984
1282
 
985
1283
                if (p == r->uri_start + r->uri.len) {
997
1295
                break;
998
1296
#endif
999
1297
            case '/':
 
1298
#if (NGX_WIN32)
 
1299
                if (u - 2 >= r->uri.data
 
1300
                    && *(u - 1) == '.' && *(u - 2) != '.')
 
1301
                {
 
1302
                    u--;
 
1303
                }
 
1304
#endif
1000
1305
                r->uri_ext = NULL;
1001
1306
                state = sw_slash;
1002
1307
                *u++ = ch;
1016
1321
                break;
1017
1322
            case '+':
1018
1323
                r->plus_in_uri = 1;
 
1324
                /* fall through */
1019
1325
            default:
1020
1326
                *u++ = ch;
1021
1327
                break;
1123
1429
#endif
1124
1430
            case '/':
1125
1431
                state = sw_slash;
1126
 
                u -= 4;
1127
 
                if (u < r->uri.data) {
1128
 
                    return NGX_HTTP_PARSE_INVALID_REQUEST;
1129
 
                }
1130
 
                while (*(u - 1) != '/') {
1131
 
                    u--;
1132
 
                }
1133
 
                break;
1134
 
            case '%':
1135
 
                quoted_state = state;
1136
 
                state = sw_quoted;
1137
 
                break;
1138
 
            case '?':
1139
 
                r->args_start = p;
1140
 
                goto args;
1141
 
            case '#':
1142
 
                goto done;
1143
 
#if (NGX_WIN32)
1144
 
            case '.':
1145
 
                state = sw_dot_dot_dot;
1146
 
                *u++ = ch;
1147
 
                break;
1148
 
#endif
1149
 
            case '+':
1150
 
                r->plus_in_uri = 1;
1151
 
            default:
1152
 
                state = sw_usual;
1153
 
                *u++ = ch;
1154
 
                break;
1155
 
            }
1156
 
 
1157
 
            ch = *p++;
1158
 
            break;
1159
 
 
1160
 
#if (NGX_WIN32)
1161
 
        case sw_dot_dot_dot:
1162
 
 
1163
 
            if (usual[ch >> 5] & (1 << (ch & 0x1f))) {
1164
 
                state = sw_usual;
1165
 
                *u++ = ch;
1166
 
                ch = *p++;
1167
 
                break;
1168
 
            }
1169
 
 
1170
 
            switch(ch) {
1171
 
            case '\\':
1172
 
            case '/':
1173
 
                state = sw_slash;
1174
1432
                u -= 5;
1175
 
                if (u < r->uri.data) {
1176
 
                    return NGX_HTTP_PARSE_INVALID_REQUEST;
1177
 
                }
1178
 
                while (*u != '/') {
1179
 
                    u--;
1180
 
                }
1181
 
                if (u < r->uri.data) {
1182
 
                    return NGX_HTTP_PARSE_INVALID_REQUEST;
1183
 
                }
1184
 
                while (*(u - 1) != '/') {
 
1433
                for ( ;; ) {
 
1434
                    if (u < r->uri.data) {
 
1435
                        return NGX_HTTP_PARSE_INVALID_REQUEST;
 
1436
                    }
 
1437
                    if (*u == '/') {
 
1438
                        u++;
 
1439
                        break;
 
1440
                    }
1185
1441
                    u--;
1186
1442
                }
1187
1443
                break;
1204
1460
 
1205
1461
            ch = *p++;
1206
1462
            break;
1207
 
#endif
1208
1463
 
1209
1464
        case sw_quoted:
1210
1465
            r->quoted_uri = 1;
1230
1485
            if (ch >= '0' && ch <= '9') {
1231
1486
                ch = (u_char) ((decoded << 4) + ch - '0');
1232
1487
 
1233
 
                if (ch == '%') {
 
1488
                if (ch == '%' || ch == '#') {
1234
1489
                    state = sw_usual;
1235
1490
                    *u++ = ch;
1236
1491
                    ch = *p++;
1237
1492
                    break;
1238
 
                }
1239
 
 
1240
 
                if (ch == '#') {
1241
 
                    *u++ = ch;
1242
 
                    ch = *p++;
1243
1493
 
1244
1494
                } else if (ch == '\0') {
1245
 
                    r->zero_in_uri = 1;
 
1495
                    return NGX_HTTP_PARSE_INVALID_REQUEST;
1246
1496
                }
1247
1497
 
1248
1498
                state = quoted_state;
1254
1504
                ch = (u_char) ((decoded << 4) + c - 'a' + 10);
1255
1505
 
1256
1506
                if (ch == '?') {
 
1507
                    state = sw_usual;
1257
1508
                    *u++ = ch;
1258
1509
                    ch = *p++;
 
1510
                    break;
1259
1511
 
1260
1512
                } else if (ch == '+') {
1261
1513
                    r->plus_in_uri = 1;
1310
1562
 
1311
1563
 
1312
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
1313
1775
ngx_http_parse_unsafe_uri(ngx_http_request_t *r, ngx_str_t *uri,
1314
1776
    ngx_str_t *args, ngx_uint_t *flags)
1315
1777
{
1323
1785
        goto unsafe;
1324
1786
    }
1325
1787
 
1326
 
    if (p[0] == '.' && len == 3 && p[1] == '.' && (p[2] == '/'
1327
 
#if (NGX_WIN32)
1328
 
                                                   || p[2] == '\\'
1329
 
#endif
1330
 
        ))
1331
 
    {
 
1788
    if (p[0] == '.' && len == 3 && p[1] == '.' && (ngx_path_separator(p[2]))) {
1332
1789
        goto unsafe;
1333
1790
    }
1334
1791
 
1349
1806
        }
1350
1807
 
1351
1808
        if (ch == '\0') {
1352
 
            *flags |= NGX_HTTP_ZERO_IN_URI;
1353
 
            continue;
 
1809
            goto unsafe;
1354
1810
        }
1355
1811
 
1356
 
        if ((ch == '/'
1357
 
#if (NGX_WIN32)
1358
 
             || ch == '\\'
1359
 
#endif
1360
 
            ) && len > 2)
1361
 
        {
 
1812
        if (ngx_path_separator(ch) && len > 2) {
 
1813
 
1362
1814
            /* detect "/../" */
1363
1815
 
1364
 
            if (p[0] == '.' && p[1] == '.' && p[2] == '/') {
1365
 
                goto unsafe;
1366
 
            }
1367
 
 
1368
 
#if (NGX_WIN32)
1369
 
 
1370
 
            if (p[2] == '\\') {
1371
 
                goto unsafe;
1372
 
            }
1373
 
 
1374
 
            if (len > 3) {
1375
 
 
1376
 
                /* detect "/.../" */
1377
 
 
1378
 
                if (p[0] == '.' && p[1] == '.' && p[2] == '.'
1379
 
                    && (p[3] == '/' || p[3] == '\\'))
1380
 
                {
1381
 
                    goto unsafe;
1382
 
                }
1383
 
            }
1384
 
#endif
 
1816
            if (p[0] == '.' && p[1] == '.' && ngx_path_separator(p[2])) {
 
1817
                goto unsafe;
 
1818
            }
1385
1819
        }
1386
1820
    }
1387
1821
 
1389
1823
 
1390
1824
unsafe:
1391
1825
 
1392
 
    ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
1393
 
                  "unsafe URI \"%V\" was detected", uri);
 
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
    }
1394
1830
 
1395
1831
    return NGX_ERROR;
1396
1832
}
1467
1903
 
1468
1904
    return NGX_DECLINED;
1469
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
    return rc;
 
2213
 
 
2214
done:
 
2215
 
 
2216
    ctx->state = 0;
 
2217
    b->pos = pos + 1;
 
2218
 
 
2219
    return NGX_DONE;
 
2220
 
 
2221
invalid:
 
2222
 
 
2223
    return NGX_ERROR;
 
2224
}