Steps to reproduce ---------------------- telnet test.server.com 80 Trying 54.xxx.xxx.18... Connected to test.server.com. Escape character is '^]'. POST /errors/test HTTP/1.1 HOST: test.server.com User-Agent: deadbeef Connection: Keep-Alive Content-Type: application/x-www-form-urlencoded Content-Length: 7 a=hi Expected behavior ----------------- Request is dropped and a 408 status code is returned. Actual behavior --------------- Request is handled normally. Platform -------- $ httpd -V Server version: Apache/2.4.18 (centos) Server built: Jul 14 2016 22:36:59 Server's Module Magic Number: 20120211:52 Server loaded: APR 1.5.2, APR-UTIL 1.5.2 Compiled using: APR 1.5.2, APR-UTIL 1.5.2 Architecture: 64-bit Server MPM: prefork threaded: no forked: yes (variable process count) Server compiled with.... -D APR_HAS_SENDFILE -D APR_HAS_MMAP -D APR_HAVE_IPV6 (IPv4-mapped addresses enabled) -D APR_USE_SYSVSEM_SERIALIZE -D APR_USE_PTHREAD_SERIALIZE -D SINGLE_LISTEN_UNSERIALIZED_ACCEPT -D APR_HAS_OTHER_CHILD -D AP_HAVE_RELIABLE_PIPED_LOGS -D DYNAMIC_MODULE_LIMIT=256 -D HTTPD_ROOT="/etc/httpd" -D SUEXEC_BIN="/usr/sbin/suexec" -D DEFAULT_PIDLOG="/run/httpd/httpd.pid" -D DEFAULT_SCOREBOARD="logs/apache_runtime_status" -D DEFAULT_ERRORLOG="logs/error_log" -D AP_TYPES_CONFIG_FILE="conf/mime.types" -D SERVER_CONFIG_FILE="conf/httpd.conf" $ cat /etc/redhat-release CentOS Linux release 7.2.1511 (Core)
Actual behavior --------------- 1477576164 20161027 224924 - 300 20197465 20 200 - 127.0.0.1 test.server.com POST /errors/test HTTP/1.1 - - - - nc - - - -errors test - HTTP/1.1 200 OK Date: Thu, 27 Oct 2016 13:49:24 GMT Server: Apache Charset: x-user-defined Content-Length: 300 Connection: close Content-Type: application/x-msgpack
This has been fixed in trunk (r1739201), will propose a backport to 2.4 shortly.
--- modules/http/http_filters.c 2016-10-28 14:44:05.977805795 +0900 +++ modules/http/http_filters.c 2016-10-28 14:44:34.470100476 +0900 @@ -1401,9 +1401,9 @@ case APR_ENOTIMPL: { return HTTP_NOT_IMPLEMENTED; } - case APR_ETIMEDOUT: { + case APR_TIMEUP: + case APR_ETIMEDOUT: return HTTP_REQUEST_TIME_OUT; - } default: { return status; } I made a patch like this, and recompiled apache 2.24.18. It seems not fixed in this case. Did I missed something?
How does your application read the body, through mod_php, mod_[proxy_f]cgi[d], or? This patch makes the core http filter return a 408 (instead of 400 in 2.4.23) for the modules/application to known, but if it's ignored in the first place this won't change anything...
What if the body length of apache was received less than Content-Length, should this case return 408 or process the request normally? The test was used mod_php.
If the connection has issues (timeout, closed, reset...) before the announced body is fully received (per Content-Length), httpd tells so to the module asking for it (mod_php or whatever). If that module (as a request handler) wants httpd to respond with the relevant HTTP error, it simply returns the corresponding ap_map_http_request_error(). But if the caller ignores the error, there is nothing httpd can do. No builtin httpd module should ignore errors, but mod_php is not maintained by the Apache HTTP server community, and I don't know enough about its internals to tell whether the error is ignored by it or the final application.
This a mod_php issue, and I found bug report here https://bugs.php.net/bug.php?id=61471 Thank you.
(In reply to Yann Ylavic from comment #2) > This has been fixed in trunk (r1739201), will propose a backport to 2.4 > shortly. The reported issue is not httpd's but for completeness, this fix related to timeouts handled by builtin modules was backported to upcoming 2.4.24 (r1768079), should one reach this PR with such issue.
Hi, I'm working on fixing this bug for mod_php. May I ask a question? If we have some codes did not handle the result of `ap_get_brigade`. we_do_not_want_modify_this_func() { ... while (ap_get_brigade(r->input_filters, brigade, AP_MODE_READBYTES, APR_BLOCK_READ, len) == APR_SUCCESS) { apr_brigade_flatten(brigade, buf, &len); apr_brigade_cleanup(brigade); tlen += len; if (tlen == count_bytes || !len) { break; } buf += len; len = count_bytes - tlen; } return tlen; } Is it possible to detect the error like this? Or is there a better way to do this? detect_error() { ... error = OK; bb = apr_brigade_create(r->pool, r->connection->bucket_alloc); rv = ap_pass_brigade(r->output_filters, bb); if (rv != APR_SUCCESS) { if (APR_STATUS_IS_TIMEUP(rv)) { error = ap_map_http_request_error(rv, HTTP_REQUEST_TIME_OUT); } else { error = ap_map_http_request_error(rv, HTTP_BAD_REQUEST); } } return error; } Thank you.