Mercurial > hg > nginx-mail
comparison src/http/ngx_http_parse.c @ 665:0b460e61bdcd default tip
Merge with nginx 1.0.0.
author | Maxim Dounin <mdounin@mdounin.ru> |
---|---|
date | Mon, 25 Apr 2011 04:22:17 +0400 |
parents | c456a023113c |
children |
comparison
equal
deleted
inserted
replaced
572:06419a2298a9 | 665:0b460e61bdcd |
---|---|
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 "/../" */ |
1320 | 1572 |
1321 return NGX_OK; | 1573 return NGX_OK; |
1322 | 1574 |
1323 unsafe: | 1575 unsafe: |
1324 | 1576 |
1325 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, | 1577 if (*flags & NGX_HTTP_LOG_UNSAFE) { |
1326 "unsafe URI \"%V\" was detected", uri); | 1578 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, |
1579 "unsafe URI \"%V\" was detected", uri); | |
1580 } | |
1327 | 1581 |
1328 return NGX_ERROR; | 1582 return NGX_ERROR; |
1329 } | 1583 } |
1330 | 1584 |
1331 | 1585 |
1445 | 1699 |
1446 | 1700 |
1447 void | 1701 void |
1448 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) |
1449 { | 1703 { |
1450 u_char ch, *p, *last; | 1704 u_char *p, *last; |
1451 | 1705 |
1452 p = uri->data; | 1706 last = uri->data + uri->len; |
1453 | 1707 |
1454 last = p + uri->len; | 1708 p = ngx_strlchr(uri->data, last, '?'); |
1455 | 1709 |
1456 args->len = 0; | 1710 if (p) { |
1457 | 1711 uri->len = p - uri->data; |
1458 while (p < last) { | 1712 p++; |
1459 | 1713 args->len = last - p; |
1460 ch = *p++; | 1714 args->data = p; |
1461 | 1715 |
1462 if (ch == '?') { | 1716 } else { |
1463 args->len = last - p; | 1717 args->len = 0; |
1464 args->data = p; | |
1465 | |
1466 uri->len = p - 1 - uri->data; | |
1467 | |
1468 if (ngx_strlchr(p, last, '\0') != NULL) { | |
1469 r->zero_in_uri = 1; | |
1470 } | |
1471 | |
1472 return; | |
1473 } | |
1474 | |
1475 if (ch == '\0') { | |
1476 r->zero_in_uri = 1; | |
1477 continue; | |
1478 } | |
1479 } | 1718 } |
1480 } | 1719 } |