Bug 60313 - body timeout will not cause 408 error
Summary: body timeout will not cause 408 error
Status: RESOLVED WORKSFORME
Alias: None
Product: Apache httpd-2
Classification: Unclassified
Component: Core (show other bugs)
Version: 2.4.18
Hardware: PC Linux
: P2 normal (vote)
Target Milestone: ---
Assignee: Apache HTTPD Bugs Mailing List
URL:
Keywords: FixedInTrunk
Depends on:
Blocks:
 
Reported: 2016-10-27 13:43 UTC by Zheng SHAO
Modified: 2016-12-11 13:42 UTC (History)
1 user (show)



Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Zheng SHAO 2016-10-27 13:43:22 UTC
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)
Comment 1 Zheng SHAO 2016-10-27 13:51:41 UTC
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
Comment 2 Yann Ylavic 2016-10-27 23:39:54 UTC
This has been fixed in trunk (r1739201), will propose a backport to 2.4 shortly.
Comment 3 Zheng SHAO 2016-10-28 06:39:22 UTC
--- 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?
Comment 4 Yann Ylavic 2016-10-28 10:24:24 UTC
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...
Comment 5 Zheng SHAO 2016-10-28 14:05:33 UTC
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.
Comment 6 Yann Ylavic 2016-10-28 22:57:17 UTC
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.
Comment 7 Zheng SHAO 2016-10-30 15:00:18 UTC
This a mod_php issue, and I found bug report here
https://bugs.php.net/bug.php?id=61471

Thank you.
Comment 8 Yann Ylavic 2016-11-04 22:39:05 UTC
(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.
Comment 9 Zheng SHAO 2016-12-11 13:42:16 UTC
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.