comparison src/http/ngx_http_request.c @ 376:d13234035cad NGINX_0_6_32

nginx 0.6.32 *) Change: the "none" parameter in the "ssl_session_cache" directive; now this is default parameter. Thanks to Rob Mueller. *) Change: now the 0x00-0x1F, '"' and '\' characters are escaped as \xXX in an access_log. Thanks to Maxim Dounin. *) Change: now nginx allows several "Host" request header line. *) Feature: the "modified" flag in the "expires" directive. *) Feature: the $uid_got and $uid_set variables may be used at any request processing stage. *) Feature: the $hostname variable. Thanks to Andrei Nigmatulin. *) Feature: DESTDIR support. Thanks to Todd A. Fisher and Andras Voroskoi. *) Bugfix: if sub_filter and SSI were used together, then responses might were transferred incorrectly. *) Bugfix: large SSI inclusions might be truncated. *) Bugfix: the "proxy_pass" directive did not work with the HTTPS protocol; the bug had appeared in 0.6.9. *) Bugfix: worker processes might not catch reconfiguration and log rotation signals. *) Bugfix: nginx could not be built on latest Fedora 9 Linux. Thanks to Roxis. *) Bugfix: a segmentation fault might occur in worker process on Linux, if keepalive was enabled.
author Igor Sysoev <http://sysoev.ru>
date Mon, 07 Jul 2008 00:00:00 +0400
parents 6639b93e81b2
children fc497c1dfb7c
comparison
equal deleted inserted replaced
375:52f3c9c7eff0 376:d13234035cad
19 19
20 static ngx_int_t ngx_http_process_header_line(ngx_http_request_t *r, 20 static ngx_int_t ngx_http_process_header_line(ngx_http_request_t *r,
21 ngx_table_elt_t *h, ngx_uint_t offset); 21 ngx_table_elt_t *h, ngx_uint_t offset);
22 static ngx_int_t ngx_http_process_unique_header_line(ngx_http_request_t *r, 22 static ngx_int_t ngx_http_process_unique_header_line(ngx_http_request_t *r,
23 ngx_table_elt_t *h, ngx_uint_t offset); 23 ngx_table_elt_t *h, ngx_uint_t offset);
24 static ngx_int_t ngx_http_process_host(ngx_http_request_t *r,
25 ngx_table_elt_t *h, ngx_uint_t offset);
24 static ngx_int_t ngx_http_process_connection(ngx_http_request_t *r, 26 static ngx_int_t ngx_http_process_connection(ngx_http_request_t *r,
27 ngx_table_elt_t *h, ngx_uint_t offset);
28 static ngx_int_t ngx_http_process_user_agent(ngx_http_request_t *r,
25 ngx_table_elt_t *h, ngx_uint_t offset); 29 ngx_table_elt_t *h, ngx_uint_t offset);
26 static ngx_int_t ngx_http_process_cookie(ngx_http_request_t *r, 30 static ngx_int_t ngx_http_process_cookie(ngx_http_request_t *r,
27 ngx_table_elt_t *h, ngx_uint_t offset); 31 ngx_table_elt_t *h, ngx_uint_t offset);
28 32
29 static ngx_int_t ngx_http_process_request_header(ngx_http_request_t *r); 33 static ngx_int_t ngx_http_process_request_header(ngx_http_request_t *r);
30 static void ngx_http_process_request(ngx_http_request_t *r); 34 static void ngx_http_process_request(ngx_http_request_t *r);
31 static void ngx_http_find_virtual_server(ngx_http_request_t *r, u_char *host, 35 static ssize_t ngx_http_validate_host(u_char *host, size_t len);
32 size_t len, ngx_uint_t hash); 36 static ngx_int_t ngx_http_find_virtual_server(ngx_http_request_t *r,
37 u_char *host, size_t len);
33 38
34 static void ngx_http_request_handler(ngx_event_t *ev); 39 static void ngx_http_request_handler(ngx_event_t *ev);
35 static ngx_int_t ngx_http_set_write_handler(ngx_http_request_t *r); 40 static ngx_int_t ngx_http_set_write_handler(ngx_http_request_t *r);
36 static void ngx_http_writer(ngx_http_request_t *r); 41 static void ngx_http_writer(ngx_http_request_t *r);
37 42
67 "client sent invalid method in HTTP/0.9 request" 72 "client sent invalid method in HTTP/0.9 request"
68 }; 73 };
69 74
70 75
71 ngx_http_header_t ngx_http_headers_in[] = { 76 ngx_http_header_t ngx_http_headers_in[] = {
72 { ngx_string("Host"), offsetof(ngx_http_headers_in_t, host), 77 { ngx_string("Host"), 0, ngx_http_process_host },
73 ngx_http_process_unique_header_line }, 78
74 79 { ngx_string("Connection"), 0, ngx_http_process_connection },
75 { ngx_string("Connection"), offsetof(ngx_http_headers_in_t, connection),
76 ngx_http_process_connection },
77 80
78 { ngx_string("If-Modified-Since"), 81 { ngx_string("If-Modified-Since"),
79 offsetof(ngx_http_headers_in_t, if_modified_since), 82 offsetof(ngx_http_headers_in_t, if_modified_since),
80 ngx_http_process_unique_header_line }, 83 ngx_http_process_unique_header_line },
81 84
82 { ngx_string("User-Agent"), offsetof(ngx_http_headers_in_t, user_agent), 85 { ngx_string("User-Agent"), 0, ngx_http_process_user_agent },
83 ngx_http_process_header_line },
84 86
85 { ngx_string("Referer"), offsetof(ngx_http_headers_in_t, referer), 87 { ngx_string("Referer"), offsetof(ngx_http_headers_in_t, referer),
86 ngx_http_process_header_line }, 88 ngx_http_process_header_line },
87 89
88 { ngx_string("Content-Length"), 90 { ngx_string("Content-Length"),
560 #ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME 562 #ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
561 563
562 int 564 int
563 ngx_http_ssl_servername(ngx_ssl_conn_t *ssl_conn, int *ad, void *arg) 565 ngx_http_ssl_servername(ngx_ssl_conn_t *ssl_conn, int *ad, void *arg)
564 { 566 {
565 u_char *p;
566 ngx_uint_t hash;
567 const char *servername; 567 const char *servername;
568 ngx_connection_t *c; 568 ngx_connection_t *c;
569 ngx_http_request_t *r; 569 ngx_http_request_t *r;
570 ngx_http_ssl_srv_conf_t *sscf; 570 ngx_http_ssl_srv_conf_t *sscf;
571 571
580 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, 580 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0,
581 "SSL server name: \"%s\"", servername); 581 "SSL server name: \"%s\"", servername);
582 582
583 r = c->data; 583 r = c->data;
584 584
585 if (r->virtual_names == NULL) { 585 if (ngx_http_find_virtual_server(r, (u_char *) servername,
586 ngx_strlen(servername))
587 != NGX_OK)
588 {
586 return SSL_TLSEXT_ERR_NOACK; 589 return SSL_TLSEXT_ERR_NOACK;
587 } 590 }
588
589 /* it seems browsers send low case server name */
590
591 hash = 0;
592
593 for (p = (u_char *) servername; *p; p++) {
594 hash = ngx_hash(hash, *p);
595 }
596
597 ngx_http_find_virtual_server(r, (u_char *) servername,
598 p - (u_char *) servername, hash);
599 591
600 sscf = ngx_http_get_module_srv_conf(r, ngx_http_ssl_module); 592 sscf = ngx_http_get_module_srv_conf(r, ngx_http_ssl_module);
601 593
602 SSL_set_SSL_CTX(ssl_conn, sscf->ssl.ctx); 594 SSL_set_SSL_CTX(ssl_conn, sscf->ssl.ctx);
603 595
724 "http args: \"%V\"", &r->args); 716 "http args: \"%V\"", &r->args);
725 717
726 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, 718 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0,
727 "http exten: \"%V\"", &r->exten); 719 "http exten: \"%V\"", &r->exten);
728 720
721 if (r->host_start && r->host_end) {
722 n = ngx_http_validate_host(r->host_start,
723 r->host_end - r->host_start);
724
725 if (n <= 0) {
726 ngx_log_error(NGX_LOG_INFO, c->log, 0,
727 "client sent invalid host in request line");
728 ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST);
729 return;
730 }
731
732 r->headers_in.server.len = n;
733 r->headers_in.server.data = r->host_start;
734 }
735
729 if (r->http_version < NGX_HTTP_VERSION_10) { 736 if (r->http_version < NGX_HTTP_VERSION_10) {
737
738 if (ngx_http_find_virtual_server(r, r->headers_in.server.data,
739 r->headers_in.server.len)
740 == NGX_ERROR)
741 {
742 ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
743 return;
744 }
745
730 ngx_http_process_request(r); 746 ngx_http_process_request(r);
731 return; 747 return;
732 } 748 }
733 749
734 750
1215 return NGX_ERROR; 1231 return NGX_ERROR;
1216 } 1232 }
1217 1233
1218 1234
1219 static ngx_int_t 1235 static ngx_int_t
1236 ngx_http_process_host(ngx_http_request_t *r, ngx_table_elt_t *h,
1237 ngx_uint_t offset)
1238 {
1239 ssize_t len;
1240
1241 if (r->headers_in.host == NULL) {
1242 r->headers_in.host = h;
1243 }
1244
1245 len = ngx_http_validate_host(h->value.data, h->value.len);
1246
1247 if (len <= 0) {
1248 ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
1249 "client sent invalid host header");
1250 ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST);
1251 return NGX_ERROR;
1252 }
1253
1254 if (r->headers_in.server.len) {
1255 return NGX_OK;
1256 }
1257
1258 r->headers_in.server.len = len;
1259 r->headers_in.server.data = h->value.data;
1260
1261 return NGX_OK;
1262 }
1263
1264
1265 static ngx_int_t
1220 ngx_http_process_connection(ngx_http_request_t *r, ngx_table_elt_t *h, 1266 ngx_http_process_connection(ngx_http_request_t *r, ngx_table_elt_t *h,
1221 ngx_uint_t offset) 1267 ngx_uint_t offset)
1222 { 1268 {
1223 if (ngx_strcasestrn(h->value.data, "close", 5 - 1)) { 1269 if (ngx_strcasestrn(h->value.data, "close", 5 - 1)) {
1224 r->headers_in.connection_type = NGX_HTTP_CONNECTION_CLOSE; 1270 r->headers_in.connection_type = NGX_HTTP_CONNECTION_CLOSE;
1225 1271
1226 } else if (ngx_strcasestrn(h->value.data, "keep-alive", 10 - 1)) { 1272 } else if (ngx_strcasestrn(h->value.data, "keep-alive", 10 - 1)) {
1227 r->headers_in.connection_type = NGX_HTTP_CONNECTION_KEEP_ALIVE; 1273 r->headers_in.connection_type = NGX_HTTP_CONNECTION_KEEP_ALIVE;
1274 }
1275
1276 return NGX_OK;
1277 }
1278
1279
1280 static ngx_int_t
1281 ngx_http_process_user_agent(ngx_http_request_t *r, ngx_table_elt_t *h,
1282 ngx_uint_t offset)
1283 {
1284 u_char *ua, *user_agent;
1285
1286 if (r->headers_in.user_agent) {
1287 return NGX_OK;
1288 }
1289
1290 r->headers_in.user_agent = h;
1291
1292 /* check some widespread browsers while the header is in CPU cache */
1293
1294 user_agent = h->value.data;
1295
1296 ua = ngx_strstrn(user_agent, "MSIE", 4 - 1);
1297
1298 if (ua && ua + 8 < user_agent + h->value.len) {
1299
1300 r->headers_in.msie = 1;
1301
1302 if (ua[4] == ' ' && ua[5] == '4' && ua[6] == '.') {
1303 r->headers_in.msie4 = 1;
1304 }
1305
1306 #if 0
1307 /* MSIE ignores the SSL "close notify" alert */
1308 if (c->ssl) {
1309 c->ssl->no_send_shutdown = 1;
1310 }
1311 #endif
1312 }
1313
1314 if (ngx_strstrn(user_agent, "Opera", 5 - 1)) {
1315 r->headers_in.opera = 1;
1316 r->headers_in.msie = 0;
1317 r->headers_in.msie4 = 0;
1318 }
1319
1320 if (!r->headers_in.msie && !r->headers_in.opera) {
1321
1322 if (ngx_strstrn(user_agent, "Gecko/", 6 - 1)) {
1323 r->headers_in.gecko = 1;
1324
1325 } else if (ngx_strstrn(user_agent, "Konqueror", 9 - 1)) {
1326 r->headers_in.konqueror = 1;
1327 }
1228 } 1328 }
1229 1329
1230 return NGX_OK; 1330 return NGX_OK;
1231 } 1331 }
1232 1332
1250 1350
1251 1351
1252 static ngx_int_t 1352 static ngx_int_t
1253 ngx_http_process_request_header(ngx_http_request_t *r) 1353 ngx_http_process_request_header(ngx_http_request_t *r)
1254 { 1354 {
1255 size_t len; 1355 if (ngx_http_find_virtual_server(r, r->headers_in.server.data,
1256 u_char *host, *ua, *user_agent, ch; 1356 r->headers_in.server.len)
1257 ngx_uint_t hash; 1357 == NGX_ERROR)
1258 1358 {
1259 if (r->headers_in.host) { 1359 ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
1260 1360 return NGX_ERROR;
1261 hash = 0; 1361 }
1262 1362
1263 for (len = 0; len < r->headers_in.host->value.len; len++) { 1363 if (r->headers_in.host == NULL && r->http_version > NGX_HTTP_VERSION_10) {
1264 ch = r->headers_in.host->value.data[len]; 1364 ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
1265 1365 "client sent HTTP/1.1 request without \"Host\" header");
1266 if (ch == ':') { 1366 ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST);
1267 break; 1367 return NGX_ERROR;
1268 }
1269
1270 ch = ngx_tolower(ch);
1271 r->headers_in.host->value.data[len] = ch;
1272 hash = ngx_hash(hash, ch);
1273 }
1274
1275 if (len && r->headers_in.host->value.data[len - 1] == '.') {
1276 len--;
1277 hash = ngx_hash_key(r->headers_in.host->value.data, len);
1278 }
1279
1280 r->headers_in.host_name_len = len;
1281
1282 if (r->virtual_names) {
1283
1284 host = r->host_start;
1285
1286 if (host == NULL) {
1287 host = r->headers_in.host->value.data;
1288 len = r->headers_in.host_name_len;
1289
1290 } else {
1291 len = r->host_end - host;
1292 }
1293
1294 ngx_http_find_virtual_server(r, host, len, hash);
1295 }
1296
1297 } else {
1298 if (r->http_version > NGX_HTTP_VERSION_10) {
1299 ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
1300 "client sent HTTP/1.1 request without \"Host\" header");
1301 ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST);
1302 return NGX_ERROR;
1303 }
1304
1305 r->headers_in.host_name_len = 0;
1306 } 1368 }
1307 1369
1308 if (r->headers_in.content_length) { 1370 if (r->headers_in.content_length) {
1309 r->headers_in.content_length_n = 1371 r->headers_in.content_length_n =
1310 ngx_atoof(r->headers_in.content_length->value.data, 1372 ngx_atoof(r->headers_in.content_length->value.data,
1351 ngx_atotm(r->headers_in.keep_alive->value.data, 1413 ngx_atotm(r->headers_in.keep_alive->value.data,
1352 r->headers_in.keep_alive->value.len); 1414 r->headers_in.keep_alive->value.len);
1353 } 1415 }
1354 } 1416 }
1355 1417
1356 if (r->headers_in.user_agent) {
1357
1358 /*
1359 * check some widespread browsers while the headers are still
1360 * in CPU cache
1361 */
1362
1363 user_agent = r->headers_in.user_agent->value.data;
1364
1365 ua = ngx_strstrn(user_agent, "MSIE", 4 - 1);
1366
1367 if (ua && ua + 8 < user_agent + r->headers_in.user_agent->value.len) {
1368
1369 r->headers_in.msie = 1;
1370
1371 if (ua[4] == ' ' && ua[5] == '4' && ua[6] == '.') {
1372 r->headers_in.msie4 = 1;
1373 }
1374
1375 #if 0
1376 /* MSIE ignores the SSL "close notify" alert */
1377 if (c->ssl) {
1378 c->ssl->no_send_shutdown = 1;
1379 }
1380 #endif
1381 }
1382
1383 if (ngx_strstrn(user_agent, "Opera", 5 - 1)) {
1384 r->headers_in.opera = 1;
1385 r->headers_in.msie = 0;
1386 r->headers_in.msie4 = 0;
1387 }
1388
1389 if (!r->headers_in.msie && !r->headers_in.opera) {
1390
1391 if (ngx_strstrn(user_agent, "Gecko/", 6 - 1)) {
1392 r->headers_in.gecko = 1;
1393
1394 } else if (ngx_strstrn(user_agent, "Konqueror", 9 - 1)) {
1395 r->headers_in.konqueror = 1;
1396 }
1397 }
1398 }
1399
1400 return NGX_OK; 1418 return NGX_OK;
1401 } 1419 }
1402 1420
1403 1421
1404 static void 1422 static void
1477 1495
1478 return; 1496 return;
1479 } 1497 }
1480 1498
1481 1499
1482 static void 1500 static ssize_t
1483 ngx_http_find_virtual_server(ngx_http_request_t *r, u_char *host, size_t len, 1501 ngx_http_validate_host(u_char *host, size_t len)
1484 ngx_uint_t hash) 1502 {
1485 { 1503 u_char ch;
1504 size_t i, last;
1505 ngx_uint_t dot;
1506
1507 last = len;
1508 dot = 0;
1509
1510 for (i = 0; i < len; i++) {
1511 ch = host[i];
1512
1513 if (ch == '.') {
1514 if (dot) {
1515 return -1;
1516 }
1517
1518 dot = 1;
1519 continue;
1520 }
1521
1522 dot = 0;
1523
1524 if (ch == ':') {
1525 last = i;
1526 continue;
1527 }
1528
1529 if (ch == '/' || ch == '\0') {
1530 return -1;
1531 }
1532
1533 #if (NGX_WIN32)
1534 if (ch == '\\') {
1535 return -1;
1536 }
1537 #endif
1538 }
1539
1540 if (dot) {
1541 last--;
1542 }
1543
1544 return last;
1545 }
1546
1547
1548 static ngx_int_t
1549 ngx_http_find_virtual_server(ngx_http_request_t *r, u_char *host, size_t len)
1550 {
1551 u_char *server, ch;
1552 ngx_uint_t i, hash;
1486 ngx_http_core_loc_conf_t *clcf; 1553 ngx_http_core_loc_conf_t *clcf;
1487 ngx_http_core_srv_conf_t *cscf; 1554 ngx_http_core_srv_conf_t *cscf;
1488 1555 u_char buf[32];
1489 cscf = ngx_hash_find_combined(&r->virtual_names->names, hash, host, len); 1556
1557 if (len == 0 || r->virtual_names == NULL) {
1558 return NGX_DECLINED;
1559 }
1560
1561 if (len <= 32) {
1562 server = buf;
1563
1564 } else {
1565 server = ngx_palloc(r->pool, len);
1566 if (server == NULL) {
1567 return NGX_ERROR;
1568 }
1569 }
1570
1571 hash = 0;
1572
1573 for (i = 0; i < len; i++) {
1574 ch = host[i];
1575
1576 ch = ngx_tolower(ch);
1577 server[i] = ch;
1578
1579 hash = ngx_hash(hash, ch);
1580 }
1581
1582 cscf = ngx_hash_find_combined(&r->virtual_names->names, hash, server, len);
1490 1583
1491 if (cscf) { 1584 if (cscf) {
1492 goto found; 1585 goto found;
1493 } 1586 }
1494 1587
1499 ngx_uint_t i; 1592 ngx_uint_t i;
1500 ngx_str_t name; 1593 ngx_str_t name;
1501 ngx_http_server_name_t *sn; 1594 ngx_http_server_name_t *sn;
1502 1595
1503 name.len = len; 1596 name.len = len;
1504 name.data = host; 1597 name.data = server;
1505 1598
1506 sn = r->virtual_names->regex; 1599 sn = r->virtual_names->regex;
1507 1600
1508 for (i = 0; i < r->virtual_names->nregex; i++) { 1601 for (i = 0; i < r->virtual_names->nregex; i++) {
1509 1602
1516 if (n < 0) { 1609 if (n < 0) {
1517 ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, 1610 ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
1518 ngx_regex_exec_n 1611 ngx_regex_exec_n
1519 " failed: %d on \"%V\" using \"%V\"", 1612 " failed: %d on \"%V\" using \"%V\"",
1520 n, &name, &sn[i].name); 1613 n, &name, &sn[i].name);
1521 return; 1614 return NGX_ERROR;
1522 } 1615 }
1523 1616
1524 /* match */ 1617 /* match */
1525 1618
1526 cscf = sn[i].core_srv_conf; 1619 cscf = sn[i].core_srv_conf;
1529 } 1622 }
1530 } 1623 }
1531 1624
1532 #endif 1625 #endif
1533 1626
1534 return; 1627 return NGX_OK;
1535 1628
1536 found: 1629 found:
1537 1630
1538 r->srv_conf = cscf->ctx->srv_conf; 1631 r->srv_conf = cscf->ctx->srv_conf;
1539 r->loc_conf = cscf->ctx->loc_conf; 1632 r->loc_conf = cscf->ctx->loc_conf;
1543 1636
1544 if (!(r->connection->log->log_level & NGX_LOG_DEBUG_CONNECTION)) { 1637 if (!(r->connection->log->log_level & NGX_LOG_DEBUG_CONNECTION)) {
1545 r->connection->log->log_level = clcf->err_log->log_level; 1638 r->connection->log->log_level = clcf->err_log->log_level;
1546 } 1639 }
1547 1640
1548 return; 1641 return NGX_OK;
1549 } 1642 }
1550 1643
1551 1644
1552 static void 1645 static void
1553 ngx_http_request_handler(ngx_event_t *ev) 1646 ngx_http_request_handler(ngx_event_t *ev)
2062 #endif 2155 #endif
2063 2156
2064 hc->pipeline = 1; 2157 hc->pipeline = 1;
2065 c->log->action = "reading client pipelined request line"; 2158 c->log->action = "reading client pipelined request line";
2066 2159
2067 ngx_http_init_request(rev); 2160 rev->handler = ngx_http_init_request;
2161 ngx_post_event(rev, &ngx_posted_events);
2068 return; 2162 return;
2069 } 2163 }
2070 2164
2071 hc->pipeline = 0; 2165 hc->pipeline = 0;
2072 2166
2178 #endif 2272 #endif
2179 2273
2180 c->idle = 1; 2274 c->idle = 1;
2181 2275
2182 if (rev->ready) { 2276 if (rev->ready) {
2183 ngx_http_keepalive_handler(rev); 2277 ngx_post_event(rev, &ngx_posted_events);
2184 } 2278 }
2185 } 2279 }
2186 2280
2187 2281
2188 static void 2282 static void