comparison src/http/ngx_http_parse.c @ 635:e67b227c8dbb default tip

Merge with current.
author Maxim Dounin <mdounin@mdounin.ru>
date Mon, 25 Apr 2011 04:07:55 +0400
parents c456a023113c
children
comparison
equal deleted inserted replaced
578:f3a9e57d2e17 635:e67b227c8dbb
110 sw_schema, 110 sw_schema,
111 sw_schema_slash, 111 sw_schema_slash,
112 sw_schema_slash_slash, 112 sw_schema_slash_slash,
113 sw_host, 113 sw_host,
114 sw_port, 114 sw_port,
115 sw_host_http_09,
115 sw_after_slash_in_uri, 116 sw_after_slash_in_uri,
116 sw_check_uri, 117 sw_check_uri,
118 sw_check_uri_http_09,
117 sw_uri, 119 sw_uri,
118 sw_http_09, 120 sw_http_09,
119 sw_http_H, 121 sw_http_H,
120 sw_http_HT, 122 sw_http_HT,
121 sw_http_HTT, 123 sw_http_HTT,
206 case 5: 208 case 5:
207 if (ngx_str5cmp(m, 'M', 'K', 'C', 'O', 'L')) { 209 if (ngx_str5cmp(m, 'M', 'K', 'C', 'O', 'L')) {
208 r->method = NGX_HTTP_MKCOL; 210 r->method = NGX_HTTP_MKCOL;
209 } 211 }
210 212
213 if (ngx_str5cmp(m, 'P', 'A', 'T', 'C', 'H')) {
214 r->method = NGX_HTTP_PATCH;
215 }
216
211 if (ngx_str5cmp(m, 'T', 'R', 'A', 'C', 'E')) { 217 if (ngx_str5cmp(m, 'T', 'R', 'A', 'C', 'E')) {
212 r->method = NGX_HTTP_TRACE; 218 r->method = NGX_HTTP_TRACE;
213 } 219 }
214 220
215 break; 221 break;
264 break; 270 break;
265 271
266 /* space* before URI */ 272 /* space* before URI */
267 case sw_spaces_before_uri: 273 case sw_spaces_before_uri:
268 274
269 if (ch == '/' ){ 275 if (ch == '/') {
270 r->uri_start = p; 276 r->uri_start = p;
271 state = sw_after_slash_in_uri; 277 state = sw_after_slash_in_uri;
272 break; 278 break;
273 } 279 }
274 280
351 * use single "/" from request line to preserve pointers, 357 * use single "/" from request line to preserve pointers,
352 * if request line will be copied to large client buffer 358 * if request line will be copied to large client buffer
353 */ 359 */
354 r->uri_start = r->schema_end + 1; 360 r->uri_start = r->schema_end + 1;
355 r->uri_end = r->schema_end + 2; 361 r->uri_end = r->schema_end + 2;
356 state = sw_http_09; 362 state = sw_host_http_09;
357 break; 363 break;
358 default: 364 default:
359 return NGX_HTTP_PARSE_INVALID_REQUEST; 365 return NGX_HTTP_PARSE_INVALID_REQUEST;
360 } 366 }
361 break; 367 break;
377 * use single "/" from request line to preserve pointers, 383 * use single "/" from request line to preserve pointers,
378 * if request line will be copied to large client buffer 384 * if request line will be copied to large client buffer
379 */ 385 */
380 r->uri_start = r->schema_end + 1; 386 r->uri_start = r->schema_end + 1;
381 r->uri_end = r->schema_end + 2; 387 r->uri_end = r->schema_end + 2;
382 state = sw_http_09; 388 state = sw_host_http_09;
383 break; 389 break;
384 default: 390 default:
385 return NGX_HTTP_PARSE_INVALID_REQUEST; 391 return NGX_HTTP_PARSE_INVALID_REQUEST;
386 } 392 }
387 break; 393 break;
394
395 /* space+ after "http://host[:port] " */
396 case sw_host_http_09:
397 switch (ch) {
398 case ' ':
399 break;
400 case CR:
401 r->http_minor = 9;
402 state = sw_almost_done;
403 break;
404 case LF:
405 r->http_minor = 9;
406 goto done;
407 case 'H':
408 r->http_protocol.data = p;
409 state = sw_http_H;
410 break;
411 default:
412 return NGX_HTTP_PARSE_INVALID_REQUEST;
413 }
414 break;
415
388 416
389 /* check "/.", "//", "%", and "\" (Win32) in URI */ 417 /* check "/.", "//", "%", and "\" (Win32) in URI */
390 case sw_after_slash_in_uri: 418 case sw_after_slash_in_uri:
391 419
392 if (usual[ch >> 5] & (1 << (ch & 0x1f))) { 420 if (usual[ch >> 5] & (1 << (ch & 0x1f))) {
395 } 423 }
396 424
397 switch (ch) { 425 switch (ch) {
398 case ' ': 426 case ' ':
399 r->uri_end = p; 427 r->uri_end = p;
400 state = sw_http_09; 428 state = sw_check_uri_http_09;
401 break; 429 break;
402 case CR: 430 case CR:
403 r->uri_end = p; 431 r->uri_end = p;
404 r->http_minor = 9; 432 r->http_minor = 9;
405 state = sw_almost_done; 433 state = sw_almost_done;
436 break; 464 break;
437 case '+': 465 case '+':
438 r->plus_in_uri = 1; 466 r->plus_in_uri = 1;
439 break; 467 break;
440 case '\0': 468 case '\0':
441 r->zero_in_uri = 1; 469 return NGX_HTTP_PARSE_INVALID_REQUEST;
442 break;
443 default: 470 default:
444 state = sw_check_uri; 471 state = sw_check_uri;
445 break; 472 break;
446 } 473 }
447 break; 474 break;
461 case '.': 488 case '.':
462 r->uri_ext = p + 1; 489 r->uri_ext = p + 1;
463 break; 490 break;
464 case ' ': 491 case ' ':
465 r->uri_end = p; 492 r->uri_end = p;
466 state = sw_http_09; 493 state = sw_check_uri_http_09;
467 break; 494 break;
468 case CR: 495 case CR:
469 r->uri_end = p; 496 r->uri_end = p;
470 r->http_minor = 9; 497 r->http_minor = 9;
471 state = sw_almost_done; 498 state = sw_almost_done;
494 break; 521 break;
495 case '+': 522 case '+':
496 r->plus_in_uri = 1; 523 r->plus_in_uri = 1;
497 break; 524 break;
498 case '\0': 525 case '\0':
499 r->zero_in_uri = 1; 526 return NGX_HTTP_PARSE_INVALID_REQUEST;
500 break; 527 }
501 } 528 break;
502 break; 529
530 /* space+ after URI */
531 case sw_check_uri_http_09:
532 switch (ch) {
533 case ' ':
534 break;
535 case CR:
536 r->http_minor = 9;
537 state = sw_almost_done;
538 break;
539 case LF:
540 r->http_minor = 9;
541 goto done;
542 case 'H':
543 r->http_protocol.data = p;
544 state = sw_http_H;
545 break;
546 default:
547 r->space_in_uri = 1;
548 state = sw_check_uri;
549 break;
550 }
551 break;
552
503 553
504 /* URI */ 554 /* URI */
505 case sw_uri: 555 case sw_uri:
506 556
507 if (usual[ch >> 5] & (1 << (ch & 0x1f))) { 557 if (usual[ch >> 5] & (1 << (ch & 0x1f))) {
524 goto done; 574 goto done;
525 case '#': 575 case '#':
526 r->complex_uri = 1; 576 r->complex_uri = 1;
527 break; 577 break;
528 case '\0': 578 case '\0':
529 r->zero_in_uri = 1; 579 return NGX_HTTP_PARSE_INVALID_REQUEST;
530 break;
531 } 580 }
532 break; 581 break;
533 582
534 /* space+ after URI */ 583 /* space+ after URI */
535 case sw_http_09: 584 case sw_http_09:
546 case 'H': 595 case 'H':
547 r->http_protocol.data = p; 596 r->http_protocol.data = p;
548 state = sw_http_H; 597 state = sw_http_H;
549 break; 598 break;
550 default: 599 default:
551 return NGX_HTTP_PARSE_INVALID_REQUEST; 600 r->space_in_uri = 1;
601 state = sw_uri;
602 break;
552 } 603 }
553 break; 604 break;
554 605
555 case sw_http_H: 606 case sw_http_H:
556 switch (ch) { 607 switch (ch) {
1188 1239
1189 case sw_quoted_second: 1240 case sw_quoted_second:
1190 if (ch >= '0' && ch <= '9') { 1241 if (ch >= '0' && ch <= '9') {
1191 ch = (u_char) ((decoded << 4) + ch - '0'); 1242 ch = (u_char) ((decoded << 4) + ch - '0');
1192 1243
1193 if (ch == '%') { 1244 if (ch == '%' || ch == '#') {
1194 state = sw_usual; 1245 state = sw_usual;
1195 *u++ = ch; 1246 *u++ = ch;
1196 ch = *p++; 1247 ch = *p++;
1197 break; 1248 break;
1198 }
1199
1200 if (ch == '#') {
1201 *u++ = ch;
1202 ch = *p++;
1203 1249
1204 } else if (ch == '\0') { 1250 } else if (ch == '\0') {
1205 r->zero_in_uri = 1; 1251 return NGX_HTTP_PARSE_INVALID_REQUEST;
1206 } 1252 }
1207 1253
1208 state = quoted_state; 1254 state = quoted_state;
1209 break; 1255 break;
1210 } 1256 }
1212 c = (u_char) (ch | 0x20); 1258 c = (u_char) (ch | 0x20);
1213 if (c >= 'a' && c <= 'f') { 1259 if (c >= 'a' && c <= 'f') {
1214 ch = (u_char) ((decoded << 4) + c - 'a' + 10); 1260 ch = (u_char) ((decoded << 4) + c - 'a' + 10);
1215 1261
1216 if (ch == '?') { 1262 if (ch == '?') {
1263 state = sw_usual;
1217 *u++ = ch; 1264 *u++ = ch;
1218 ch = *p++; 1265 ch = *p++;
1266 break;
1219 1267
1220 } else if (ch == '+') { 1268 } else if (ch == '+') {
1221 r->plus_in_uri = 1; 1269 r->plus_in_uri = 1;
1222 } 1270 }
1223 1271
1262 r->exten.len = u - r->uri_ext; 1310 r->exten.len = u - r->uri_ext;
1263 r->exten.data = r->uri_ext; 1311 r->exten.data = r->uri_ext;
1264 } 1312 }
1265 1313
1266 r->uri_ext = NULL; 1314 r->uri_ext = NULL;
1315
1316 return NGX_OK;
1317 }
1318
1319
1320 ngx_int_t
1321 ngx_http_parse_status_line(ngx_http_request_t *r, ngx_buf_t *b,
1322 ngx_http_status_t *status)
1323 {
1324 u_char ch;
1325 u_char *p;
1326 enum {
1327 sw_start = 0,
1328 sw_H,
1329 sw_HT,
1330 sw_HTT,
1331 sw_HTTP,
1332 sw_first_major_digit,
1333 sw_major_digit,
1334 sw_first_minor_digit,
1335 sw_minor_digit,
1336 sw_status,
1337 sw_space_after_status,
1338 sw_status_text,
1339 sw_almost_done
1340 } state;
1341
1342 state = r->state;
1343
1344 for (p = b->pos; p < b->last; p++) {
1345 ch = *p;
1346
1347 switch (state) {
1348
1349 /* "HTTP/" */
1350 case sw_start:
1351 switch (ch) {
1352 case 'H':
1353 state = sw_H;
1354 break;
1355 default:
1356 return NGX_ERROR;
1357 }
1358 break;
1359
1360 case sw_H:
1361 switch (ch) {
1362 case 'T':
1363 state = sw_HT;
1364 break;
1365 default:
1366 return NGX_ERROR;
1367 }
1368 break;
1369
1370 case sw_HT:
1371 switch (ch) {
1372 case 'T':
1373 state = sw_HTT;
1374 break;
1375 default:
1376 return NGX_ERROR;
1377 }
1378 break;
1379
1380 case sw_HTT:
1381 switch (ch) {
1382 case 'P':
1383 state = sw_HTTP;
1384 break;
1385 default:
1386 return NGX_ERROR;
1387 }
1388 break;
1389
1390 case sw_HTTP:
1391 switch (ch) {
1392 case '/':
1393 state = sw_first_major_digit;
1394 break;
1395 default:
1396 return NGX_ERROR;
1397 }
1398 break;
1399
1400 /* the first digit of major HTTP version */
1401 case sw_first_major_digit:
1402 if (ch < '1' || ch > '9') {
1403 return NGX_ERROR;
1404 }
1405
1406 state = sw_major_digit;
1407 break;
1408
1409 /* the major HTTP version or dot */
1410 case sw_major_digit:
1411 if (ch == '.') {
1412 state = sw_first_minor_digit;
1413 break;
1414 }
1415
1416 if (ch < '0' || ch > '9') {
1417 return NGX_ERROR;
1418 }
1419
1420 break;
1421
1422 /* the first digit of minor HTTP version */
1423 case sw_first_minor_digit:
1424 if (ch < '0' || ch > '9') {
1425 return NGX_ERROR;
1426 }
1427
1428 state = sw_minor_digit;
1429 break;
1430
1431 /* the minor HTTP version or the end of the request line */
1432 case sw_minor_digit:
1433 if (ch == ' ') {
1434 state = sw_status;
1435 break;
1436 }
1437
1438 if (ch < '0' || ch > '9') {
1439 return NGX_ERROR;
1440 }
1441
1442 break;
1443
1444 /* HTTP status code */
1445 case sw_status:
1446 if (ch == ' ') {
1447 break;
1448 }
1449
1450 if (ch < '0' || ch > '9') {
1451 return NGX_ERROR;
1452 }
1453
1454 status->code = status->code * 10 + ch - '0';
1455
1456 if (++status->count == 3) {
1457 state = sw_space_after_status;
1458 status->start = p - 2;
1459 }
1460
1461 break;
1462
1463 /* space or end of line */
1464 case sw_space_after_status:
1465 switch (ch) {
1466 case ' ':
1467 state = sw_status_text;
1468 break;
1469 case '.': /* IIS may send 403.1, 403.2, etc */
1470 state = sw_status_text;
1471 break;
1472 case CR:
1473 state = sw_almost_done;
1474 break;
1475 case LF:
1476 goto done;
1477 default:
1478 return NGX_ERROR;
1479 }
1480 break;
1481
1482 /* any text until end of line */
1483 case sw_status_text:
1484 switch (ch) {
1485 case CR:
1486 state = sw_almost_done;
1487
1488 break;
1489 case LF:
1490 goto done;
1491 }
1492 break;
1493
1494 /* end of status line */
1495 case sw_almost_done:
1496 status->end = p - 1;
1497 switch (ch) {
1498 case LF:
1499 goto done;
1500 default:
1501 return NGX_ERROR;
1502 }
1503 }
1504 }
1505
1506 b->pos = p;
1507 r->state = state;
1508
1509 return NGX_AGAIN;
1510
1511 done:
1512
1513 b->pos = p + 1;
1514
1515 if (status->end == NULL) {
1516 status->end = p;
1517 }
1518
1519 r->state = sw_start;
1267 1520
1268 return NGX_OK; 1521 return NGX_OK;
1269 } 1522 }
1270 1523
1271 1524
1302 1555
1303 return NGX_OK; 1556 return NGX_OK;
1304 } 1557 }
1305 1558
1306 if (ch == '\0') { 1559 if (ch == '\0') {
1307 *flags |= NGX_HTTP_ZERO_IN_URI; 1560 goto unsafe;
1308 continue;
1309 } 1561 }
1310 1562
1311 if (ngx_path_separator(ch) && len > 2) { 1563 if (ngx_path_separator(ch) && len > 2) {
1312 1564
1313 /* detect "/../" */ 1565 /* detect "/../" */
1447 1699
1448 1700
1449 void 1701 void
1450 ngx_http_split_args(ngx_http_request_t *r, ngx_str_t *uri, ngx_str_t *args) 1702 ngx_http_split_args(ngx_http_request_t *r, ngx_str_t *uri, ngx_str_t *args)
1451 { 1703 {
1452 u_char ch, *p, *last; 1704 u_char *p, *last;
1453 1705
1454 p = uri->data; 1706 last = uri->data + uri->len;
1455 1707
1456 last = p + uri->len; 1708 p = ngx_strlchr(uri->data, last, '?');
1457 1709
1458 args->len = 0; 1710 if (p) {
1459 1711 uri->len = p - uri->data;
1460 while (p < last) { 1712 p++;
1461 1713 args->len = last - p;
1462 ch = *p++; 1714 args->data = p;
1463 1715
1464 if (ch == '?') { 1716 } else {
1465 args->len = last - p; 1717 args->len = 0;
1466 args->data = p;
1467
1468 uri->len = p - 1 - uri->data;
1469
1470 if (ngx_strlchr(p, last, '\0') != NULL) {
1471 r->zero_in_uri = 1;
1472 }
1473
1474 return;
1475 }
1476
1477 if (ch == '\0') {
1478 r->zero_in_uri = 1;
1479 continue;
1480 }
1481 } 1718 }
1482 } 1719 }