mirror of
https://github.com/apache/httpd.git
synced 2025-08-08 15:02:10 +03:00
mod_proxy_http: follow up to r1836588/r1836648: handle unread 100-continue.
When the backend responds with a non-interim response to a 100-continue, mod_proxy_http won't read the client's body, so make sure "Connection: close" ends up being added to the response if nobody reads that body later. The right thing to do at mod_proxy level, rather then forcing AP_CONN_CLOSE, is to restore r->expecting_100 so that further processing (like error_override or trying on the next balancer member) can still work. git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1836716 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
@@ -246,16 +246,17 @@ typedef struct {
|
|||||||
proxy_conn_rec *backend;
|
proxy_conn_rec *backend;
|
||||||
conn_rec *origin;
|
conn_rec *origin;
|
||||||
|
|
||||||
rb_methods rb_method;
|
|
||||||
apr_bucket_alloc_t *bucket_alloc;
|
apr_bucket_alloc_t *bucket_alloc;
|
||||||
apr_bucket_brigade *header_brigade;
|
apr_bucket_brigade *header_brigade;
|
||||||
apr_bucket_brigade *input_brigade;
|
apr_bucket_brigade *input_brigade;
|
||||||
char *old_cl_val, *old_te_val;
|
char *old_cl_val, *old_te_val;
|
||||||
apr_off_t cl_val, bytes_spooled;
|
apr_off_t cl_val, bytes_spooled;
|
||||||
|
|
||||||
int do_100_continue;
|
rb_methods rb_method;
|
||||||
|
|
||||||
int expecting_100;
|
int expecting_100;
|
||||||
int flushall;
|
unsigned int do_100_continue:1,
|
||||||
|
flushall:1;
|
||||||
} proxy_http_req_t;
|
} proxy_http_req_t;
|
||||||
|
|
||||||
static int stream_reqbody_chunked(proxy_http_req_t *req)
|
static int stream_reqbody_chunked(proxy_http_req_t *req)
|
||||||
@@ -1643,14 +1644,6 @@ int ap_proxy_http_process_response(proxy_http_req_t *req)
|
|||||||
*/
|
*/
|
||||||
if (do_100_continue && (!interim_response
|
if (do_100_continue && (!interim_response
|
||||||
|| proxy_status == HTTP_CONTINUE)) {
|
|| proxy_status == HTTP_CONTINUE)) {
|
||||||
int do_send_body = (proxy_status == HTTP_CONTINUE
|
|
||||||
|| (!toclose && major > 0 && minor > 0));
|
|
||||||
|
|
||||||
/* Reset to old timeout iff we've adjusted it. */
|
|
||||||
if (worker->s->ping_timeout_set) {
|
|
||||||
apr_socket_timeout_set(backend->sock, old_timeout);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* RFC 7231 - Section 5.1.1 - Expect - Requirement for servers
|
/* RFC 7231 - Section 5.1.1 - Expect - Requirement for servers
|
||||||
* A server that responds with a final status code before
|
* A server that responds with a final status code before
|
||||||
* reading the entire message body SHOULD indicate in that
|
* reading the entire message body SHOULD indicate in that
|
||||||
@@ -1663,16 +1656,23 @@ int ap_proxy_http_process_response(proxy_http_req_t *req)
|
|||||||
* discard it or the caller try another balancer member with the
|
* discard it or the caller try another balancer member with the
|
||||||
* same body (given status 503, though not implemented yet).
|
* same body (given status 503, though not implemented yet).
|
||||||
*/
|
*/
|
||||||
if (proxy_status != HTTP_CONTINUE) {
|
int do_send_body = (proxy_status == HTTP_CONTINUE
|
||||||
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(10153)
|
|| (!toclose && major > 0 && minor > 0));
|
||||||
"HTTP: no 100-Continue sent by %pI (%s): "
|
|
||||||
"%ssending body%s (response: %s)",
|
/* Reset to old timeout iff we've adjusted it. */
|
||||||
backend->addr,
|
if (worker->s->ping_timeout_set) {
|
||||||
backend->hostname ? backend->hostname : "",
|
apr_socket_timeout_set(backend->sock, old_timeout);
|
||||||
do_send_body ? "" : "not ",
|
|
||||||
do_send_body ? " anyway" : "",
|
|
||||||
proxy_status_line);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(10153)
|
||||||
|
"HTTP: %s100 continue sent by %pI (%s): "
|
||||||
|
"%ssending body (response: HTTP/%i.%i %s)",
|
||||||
|
proxy_status != HTTP_CONTINUE ? "no " : "",
|
||||||
|
backend->addr,
|
||||||
|
backend->hostname ? backend->hostname : "",
|
||||||
|
do_send_body ? "" : "not ",
|
||||||
|
major, minor, proxy_status_line);
|
||||||
|
|
||||||
if (do_send_body) {
|
if (do_send_body) {
|
||||||
int status;
|
int status;
|
||||||
|
|
||||||
@@ -1709,11 +1709,30 @@ int ap_proxy_http_process_response(proxy_http_req_t *req)
|
|||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
/* If we don't read the client connection any further, since
|
||||||
|
* there are pending data it should be "Connection: close"d to
|
||||||
|
* prevent reuse. We don't exactly c->keepalive = AP_CONN_CLOSE
|
||||||
|
* here though, because error_override or a potential retry on
|
||||||
|
* another backend could finally read that data and finalize
|
||||||
|
* the request processing, making keep-alive possible. So what
|
||||||
|
* we do is restoring r->expecting_100 for ap_set_keepalive()
|
||||||
|
* to do the right thing according to the final response and
|
||||||
|
* any later update of r->expecting_100.
|
||||||
|
*/
|
||||||
|
r->expecting_100 = req->expecting_100;
|
||||||
|
req->expecting_100 = 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* Once only! */
|
/* Once only! */
|
||||||
do_100_continue = 0;
|
do_100_continue = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (interim_response) {
|
||||||
|
/* Already forwarded above, read next response */
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
/* Moved the fixups of Date headers and those affected by
|
/* Moved the fixups of Date headers and those affected by
|
||||||
* ProxyPassReverse/etc from here to ap_proxy_read_headers
|
* ProxyPassReverse/etc from here to ap_proxy_read_headers
|
||||||
*/
|
*/
|
||||||
@@ -1789,7 +1808,6 @@ int ap_proxy_http_process_response(proxy_http_req_t *req)
|
|||||||
|
|
||||||
/* send body - but only if a body is expected */
|
/* send body - but only if a body is expected */
|
||||||
if ((!r->header_only) && /* not HEAD request */
|
if ((!r->header_only) && /* not HEAD request */
|
||||||
!interim_response && /* not any 1xx response */
|
|
||||||
(proxy_status != HTTP_NO_CONTENT) && /* not 204 */
|
(proxy_status != HTTP_NO_CONTENT) && /* not 204 */
|
||||||
(proxy_status != HTTP_NOT_MODIFIED)) { /* not 304 */
|
(proxy_status != HTTP_NOT_MODIFIED)) { /* not 304 */
|
||||||
|
|
||||||
@@ -1976,7 +1994,7 @@ int ap_proxy_http_process_response(proxy_http_req_t *req)
|
|||||||
}
|
}
|
||||||
ap_log_rerror(APLOG_MARK, APLOG_TRACE2, 0, r, "end body send");
|
ap_log_rerror(APLOG_MARK, APLOG_TRACE2, 0, r, "end body send");
|
||||||
}
|
}
|
||||||
else if (!interim_response) {
|
else {
|
||||||
ap_log_rerror(APLOG_MARK, APLOG_TRACE2, 0, r, "header only");
|
ap_log_rerror(APLOG_MARK, APLOG_TRACE2, 0, r, "header only");
|
||||||
|
|
||||||
/* make sure we release the backend connection as soon
|
/* make sure we release the backend connection as soon
|
||||||
@@ -2249,12 +2267,15 @@ static int proxy_http_handler(request_rec *r, proxy_worker *worker,
|
|||||||
|
|
||||||
/* Step Six: Clean Up */
|
/* Step Six: Clean Up */
|
||||||
cleanup:
|
cleanup:
|
||||||
r->expecting_100 = req->expecting_100;
|
|
||||||
if (req->backend) {
|
if (req->backend) {
|
||||||
if (status != OK)
|
if (status != OK)
|
||||||
req->backend->close = 1;
|
req->backend->close = 1;
|
||||||
ap_proxy_http_cleanup(proxy_function, r, req->backend);
|
ap_proxy_http_cleanup(proxy_function, r, req->backend);
|
||||||
}
|
}
|
||||||
|
if (req->expecting_100) {
|
||||||
|
/* Restore r->expecting_100 if we didn't touch it */
|
||||||
|
r->expecting_100 = req->expecting_100;
|
||||||
|
}
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user