comparison src/http/ngx_http_request.c @ 7354:1812f1d79d84

Fixed socket leak with "return 444" in error_page (ticket #274). Socket leak was observed in the following configuration: error_page 400 = /close; location = /close { return 444; } The problem is that "return 444" triggers termination of the request, and due to error_page termination thinks that it needs to use a posted request to clear stack. But at the early request processing where 400 errors are generated there are no ngx_http_run_posted_requests() calls, so the request is only terminated after an external event. Variants of the problem include "error_page 497" instead (ticket #695) and various other errors generated during early request processing (405, 414, 421, 494, 495, 496, 501, 505). The same problem can be also triggered with "return 499" and "return 408" as both codes trigger ngx_http_terminate_request(), much like "return 444". To fix this, the patch adds ngx_http_run_posted_requests() calls to ngx_http_process_request_line() and ngx_http_process_request_headers() functions, and to ngx_http_v2_run_request() and ngx_http_v2_push_stream() functions in HTTP/2. Since the ngx_http_process_request() function is now only called via other functions which call ngx_http_run_posted_requests(), the call there is no longer needed and was removed.
author Maxim Dounin <mdounin@mdounin.ru>
date Fri, 21 Sep 2018 15:59:30 +0300
parents 2b5528023f6b
children bf1ac3dc1e68
comparison
equal deleted inserted replaced
7353:87d2ea860f38 7354:1812f1d79d84
957 957
958 if (rc == NGX_AGAIN) { 958 if (rc == NGX_AGAIN) {
959 n = ngx_http_read_request_header(r); 959 n = ngx_http_read_request_header(r);
960 960
961 if (n == NGX_AGAIN || n == NGX_ERROR) { 961 if (n == NGX_AGAIN || n == NGX_ERROR) {
962 return; 962 break;
963 } 963 }
964 } 964 }
965 965
966 rc = ngx_http_parse_request_line(r, r->header_in); 966 rc = ngx_http_parse_request_line(r, r->header_in);
967 967
982 if (r->http_protocol.data) { 982 if (r->http_protocol.data) {
983 r->http_protocol.len = r->request_end - r->http_protocol.data; 983 r->http_protocol.len = r->request_end - r->http_protocol.data;
984 } 984 }
985 985
986 if (ngx_http_process_request_uri(r) != NGX_OK) { 986 if (ngx_http_process_request_uri(r) != NGX_OK) {
987 return; 987 break;
988 } 988 }
989 989
990 if (r->schema_end) { 990 if (r->schema_end) {
991 r->schema.len = r->schema_end - r->schema_start; 991 r->schema.len = r->schema_end - r->schema_start;
992 r->schema.data = r->schema_start; 992 r->schema.data = r->schema_start;
1001 1001
1002 if (rc == NGX_DECLINED) { 1002 if (rc == NGX_DECLINED) {
1003 ngx_log_error(NGX_LOG_INFO, c->log, 0, 1003 ngx_log_error(NGX_LOG_INFO, c->log, 0,
1004 "client sent invalid host in request line"); 1004 "client sent invalid host in request line");
1005 ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST); 1005 ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST);
1006 return; 1006 break;
1007 } 1007 }
1008 1008
1009 if (rc == NGX_ERROR) { 1009 if (rc == NGX_ERROR) {
1010 ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); 1010 ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
1011 return; 1011 break;
1012 } 1012 }
1013 1013
1014 if (ngx_http_set_virtual_server(r, &host) == NGX_ERROR) { 1014 if (ngx_http_set_virtual_server(r, &host) == NGX_ERROR) {
1015 return; 1015 break;
1016 } 1016 }
1017 1017
1018 r->headers_in.server = host; 1018 r->headers_in.server = host;
1019 } 1019 }
1020 1020
1022 1022
1023 if (r->headers_in.server.len == 0 1023 if (r->headers_in.server.len == 0
1024 && ngx_http_set_virtual_server(r, &r->headers_in.server) 1024 && ngx_http_set_virtual_server(r, &r->headers_in.server)
1025 == NGX_ERROR) 1025 == NGX_ERROR)
1026 { 1026 {
1027 return; 1027 break;
1028 } 1028 }
1029 1029
1030 ngx_http_process_request(r); 1030 ngx_http_process_request(r);
1031 return; 1031 break;
1032 } 1032 }
1033 1033
1034 1034
1035 if (ngx_list_init(&r->headers_in.headers, r->pool, 20, 1035 if (ngx_list_init(&r->headers_in.headers, r->pool, 20,
1036 sizeof(ngx_table_elt_t)) 1036 sizeof(ngx_table_elt_t))
1037 != NGX_OK) 1037 != NGX_OK)
1038 { 1038 {
1039 ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); 1039 ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
1040 return; 1040 break;
1041 } 1041 }
1042 1042
1043 c->log->action = "reading client request headers"; 1043 c->log->action = "reading client request headers";
1044 1044
1045 rev->handler = ngx_http_process_request_headers; 1045 rev->handler = ngx_http_process_request_headers;
1046 ngx_http_process_request_headers(rev); 1046 ngx_http_process_request_headers(rev);
1047 1047
1048 return; 1048 break;
1049 } 1049 }
1050 1050
1051 if (rc != NGX_AGAIN) { 1051 if (rc != NGX_AGAIN) {
1052 1052
1053 /* there was error while a request line parsing */ 1053 /* there was error while a request line parsing */
1060 1060
1061 } else { 1061 } else {
1062 ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST); 1062 ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST);
1063 } 1063 }
1064 1064
1065 return; 1065 break;
1066 } 1066 }
1067 1067
1068 /* NGX_AGAIN: a request line parsing is still incomplete */ 1068 /* NGX_AGAIN: a request line parsing is still incomplete */
1069 1069
1070 if (r->header_in->pos == r->header_in->end) { 1070 if (r->header_in->pos == r->header_in->end) {
1071 1071
1072 rv = ngx_http_alloc_large_header_buffer(r, 1); 1072 rv = ngx_http_alloc_large_header_buffer(r, 1);
1073 1073
1074 if (rv == NGX_ERROR) { 1074 if (rv == NGX_ERROR) {
1075 ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); 1075 ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
1076 return; 1076 break;
1077 } 1077 }
1078 1078
1079 if (rv == NGX_DECLINED) { 1079 if (rv == NGX_DECLINED) {
1080 r->request_line.len = r->header_in->end - r->request_start; 1080 r->request_line.len = r->header_in->end - r->request_start;
1081 r->request_line.data = r->request_start; 1081 r->request_line.data = r->request_start;
1082 1082
1083 ngx_log_error(NGX_LOG_INFO, c->log, 0, 1083 ngx_log_error(NGX_LOG_INFO, c->log, 0,
1084 "client sent too long URI"); 1084 "client sent too long URI");
1085 ngx_http_finalize_request(r, NGX_HTTP_REQUEST_URI_TOO_LARGE); 1085 ngx_http_finalize_request(r, NGX_HTTP_REQUEST_URI_TOO_LARGE);
1086 return; 1086 break;
1087 } 1087 }
1088 } 1088 }
1089 } 1089 }
1090
1091 ngx_http_run_posted_requests(c);
1090 } 1092 }
1091 1093
1092 1094
1093 ngx_int_t 1095 ngx_int_t
1094 ngx_http_process_request_uri(ngx_http_request_t *r) 1096 ngx_http_process_request_uri(ngx_http_request_t *r)
1246 1248
1247 rv = ngx_http_alloc_large_header_buffer(r, 0); 1249 rv = ngx_http_alloc_large_header_buffer(r, 0);
1248 1250
1249 if (rv == NGX_ERROR) { 1251 if (rv == NGX_ERROR) {
1250 ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); 1252 ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
1251 return; 1253 break;
1252 } 1254 }
1253 1255
1254 if (rv == NGX_DECLINED) { 1256 if (rv == NGX_DECLINED) {
1255 p = r->header_name_start; 1257 p = r->header_name_start;
1256 1258
1259 if (p == NULL) { 1261 if (p == NULL) {
1260 ngx_log_error(NGX_LOG_INFO, c->log, 0, 1262 ngx_log_error(NGX_LOG_INFO, c->log, 0,
1261 "client sent too large request"); 1263 "client sent too large request");
1262 ngx_http_finalize_request(r, 1264 ngx_http_finalize_request(r,
1263 NGX_HTTP_REQUEST_HEADER_TOO_LARGE); 1265 NGX_HTTP_REQUEST_HEADER_TOO_LARGE);
1264 return; 1266 break;
1265 } 1267 }
1266 1268
1267 len = r->header_in->end - p; 1269 len = r->header_in->end - p;
1268 1270
1269 if (len > NGX_MAX_ERROR_STR - 300) { 1271 if (len > NGX_MAX_ERROR_STR - 300) {
1274 "client sent too long header line: \"%*s...\"", 1276 "client sent too long header line: \"%*s...\"",
1275 len, r->header_name_start); 1277 len, r->header_name_start);
1276 1278
1277 ngx_http_finalize_request(r, 1279 ngx_http_finalize_request(r,
1278 NGX_HTTP_REQUEST_HEADER_TOO_LARGE); 1280 NGX_HTTP_REQUEST_HEADER_TOO_LARGE);
1279 return; 1281 break;
1280 } 1282 }
1281 } 1283 }
1282 1284
1283 n = ngx_http_read_request_header(r); 1285 n = ngx_http_read_request_header(r);
1284 1286
1285 if (n == NGX_AGAIN || n == NGX_ERROR) { 1287 if (n == NGX_AGAIN || n == NGX_ERROR) {
1286 return; 1288 break;
1287 } 1289 }
1288 } 1290 }
1289 1291
1290 /* the host header could change the server configuration context */ 1292 /* the host header could change the server configuration context */
1291 cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module); 1293 cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module);
1311 /* a header line has been parsed successfully */ 1313 /* a header line has been parsed successfully */
1312 1314
1313 h = ngx_list_push(&r->headers_in.headers); 1315 h = ngx_list_push(&r->headers_in.headers);
1314 if (h == NULL) { 1316 if (h == NULL) {
1315 ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); 1317 ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
1316 return; 1318 break;
1317 } 1319 }
1318 1320
1319 h->hash = r->header_hash; 1321 h->hash = r->header_hash;
1320 1322
1321 h->key.len = r->header_name_end - r->header_name_start; 1323 h->key.len = r->header_name_end - r->header_name_start;
1327 h->value.data[h->value.len] = '\0'; 1329 h->value.data[h->value.len] = '\0';
1328 1330
1329 h->lowcase_key = ngx_pnalloc(r->pool, h->key.len); 1331 h->lowcase_key = ngx_pnalloc(r->pool, h->key.len);
1330 if (h->lowcase_key == NULL) { 1332 if (h->lowcase_key == NULL) {
1331 ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); 1333 ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
1332 return; 1334 break;
1333 } 1335 }
1334 1336
1335 if (h->key.len == r->lowcase_index) { 1337 if (h->key.len == r->lowcase_index) {
1336 ngx_memcpy(h->lowcase_key, r->lowcase_header, h->key.len); 1338 ngx_memcpy(h->lowcase_key, r->lowcase_header, h->key.len);
1337 1339
1341 1343
1342 hh = ngx_hash_find(&cmcf->headers_in_hash, h->hash, 1344 hh = ngx_hash_find(&cmcf->headers_in_hash, h->hash,
1343 h->lowcase_key, h->key.len); 1345 h->lowcase_key, h->key.len);
1344 1346
1345 if (hh && hh->handler(r, h, hh->offset) != NGX_OK) { 1347 if (hh && hh->handler(r, h, hh->offset) != NGX_OK) {
1346 return; 1348 break;
1347 } 1349 }
1348 1350
1349 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, 1351 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1350 "http header: \"%V: %V\"", 1352 "http header: \"%V: %V\"",
1351 &h->key, &h->value); 1353 &h->key, &h->value);
1365 r->http_state = NGX_HTTP_PROCESS_REQUEST_STATE; 1367 r->http_state = NGX_HTTP_PROCESS_REQUEST_STATE;
1366 1368
1367 rc = ngx_http_process_request_header(r); 1369 rc = ngx_http_process_request_header(r);
1368 1370
1369 if (rc != NGX_OK) { 1371 if (rc != NGX_OK) {
1370 return; 1372 break;
1371 } 1373 }
1372 1374
1373 ngx_http_process_request(r); 1375 ngx_http_process_request(r);
1374 1376
1375 return; 1377 break;
1376 } 1378 }
1377 1379
1378 if (rc == NGX_AGAIN) { 1380 if (rc == NGX_AGAIN) {
1379 1381
1380 /* a header line parsing is still not complete */ 1382 /* a header line parsing is still not complete */
1386 1388
1387 ngx_log_error(NGX_LOG_INFO, c->log, 0, 1389 ngx_log_error(NGX_LOG_INFO, c->log, 0,
1388 "client sent invalid header line"); 1390 "client sent invalid header line");
1389 1391
1390 ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST); 1392 ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST);
1391 return; 1393 break;
1392 } 1394 }
1395
1396 ngx_http_run_posted_requests(c);
1393 } 1397 }
1394 1398
1395 1399
1396 static ssize_t 1400 static ssize_t
1397 ngx_http_read_request_header(ngx_http_request_t *r) 1401 ngx_http_read_request_header(ngx_http_request_t *r)
1942 c->read->handler = ngx_http_request_handler; 1946 c->read->handler = ngx_http_request_handler;
1943 c->write->handler = ngx_http_request_handler; 1947 c->write->handler = ngx_http_request_handler;
1944 r->read_event_handler = ngx_http_block_reading; 1948 r->read_event_handler = ngx_http_block_reading;
1945 1949
1946 ngx_http_handler(r); 1950 ngx_http_handler(r);
1947
1948 ngx_http_run_posted_requests(c);
1949 } 1951 }
1950 1952
1951 1953
1952 static ngx_int_t 1954 static ngx_int_t
1953 ngx_http_validate_host(ngx_str_t *host, ngx_pool_t *pool, ngx_uint_t alloc) 1955 ngx_http_validate_host(ngx_str_t *host, ngx_pool_t *pool, ngx_uint_t alloc)