[MEDIUM] http: properly handle "option forceclose"

The "forceclose" option used to close the output channel to the
server once it started to respond. While this happened to work with
most servers, some of them considered this as a connection abort and
immediately stopped responding.

Now that we're aware of the end of a request and response, we're able
to trivially handle this option and properly close both sides when the
server's response is complete.

During this change it appeared that forwarding could be allowed when
the BF_SHUTW_NOW flag was set on a buffer, which obviously is not
acceptable and was causing some trouble. This has been fixed too and
is the reason for the MEDIUM status on this patch.
This commit is contained in:
Willy Tarreau 2009-12-29 12:09:05 +01:00
parent 5523b32cc6
commit 82eeaf2fae
3 changed files with 16 additions and 12 deletions

View File

@ -2393,10 +2393,8 @@ no option forceclose
global session times in the logs. global session times in the logs.
When this happens, it is possible to use "option forceclose". It will When this happens, it is possible to use "option forceclose". It will
actively close the outgoing server channel as soon as the server begins to actively close the outgoing server channel as soon as the server has finished
reply and only if the request buffer is empty. Note that this should NOT be to respond. This option implicitly enables the "httpclose" option.
used if CONNECT requests are expected between the client and the server. This
option implicitly enables the "httpclose" option.
If this option has been enabled in a "defaults" section, it can be disabled If this option has been enabled in a "defaults" section, it can be disabled
in a specific instance by prepending the "no" keyword before it. in a specific instance by prepending the "no" keyword before it.

View File

@ -3317,6 +3317,11 @@ int http_request_forward_body(struct session *s, struct buffer *req, int an_bit)
* to reset the transaction here. * to reset the transaction here.
*/ */
if ((s->fe->options | s->be->options) & PR_O_FORCE_CLO) {
/* option forceclose is set, let's enforce it now that the transfer is complete. */
buffer_abort(req);
}
if (req->flags & (BF_SHUTW|BF_SHUTW_NOW)) { if (req->flags & (BF_SHUTW|BF_SHUTW_NOW)) {
if (req->flags & BF_OUT_EMPTY) if (req->flags & BF_OUT_EMPTY)
msg->msg_state = HTTP_MSG_CLOSED; msg->msg_state = HTTP_MSG_CLOSED;
@ -4256,6 +4261,11 @@ int http_response_forward_body(struct session *s, struct buffer *res, int an_bit
* to reset the transaction here. * to reset the transaction here.
*/ */
if ((s->fe->options | s->be->options) & PR_O_FORCE_CLO) {
/* option forceclose is set, let's enforce it now that the transfer is complete. */
buffer_abort(res);
}
if (res->flags & (BF_SHUTW|BF_SHUTW_NOW)) { if (res->flags & (BF_SHUTW|BF_SHUTW_NOW)) {
if (res->flags & BF_OUT_EMPTY) if (res->flags & BF_OUT_EMPTY)
msg->msg_state = HTTP_MSG_CLOSED; msg->msg_state = HTTP_MSG_CLOSED;

View File

@ -1000,7 +1000,7 @@ resync_stream_interface:
* everything. We configure the buffer to forward indefinitely. * everything. We configure the buffer to forward indefinitely.
*/ */
if (!s->req->analysers && if (!s->req->analysers &&
!(s->req->flags & (BF_HIJACK|BF_SHUTW)) && !(s->req->flags & (BF_HIJACK|BF_SHUTW|BF_SHUTW_NOW)) &&
(s->req->prod->state >= SI_ST_EST) && (s->req->prod->state >= SI_ST_EST) &&
(s->req->to_forward != BUF_INFINITE_FORWARD)) { (s->req->to_forward != BUF_INFINITE_FORWARD)) {
/* This buffer is freewheeling, there's no analyser nor hijacker /* This buffer is freewheeling, there's no analyser nor hijacker
@ -1042,13 +1042,9 @@ resync_stream_interface:
* happen either because the input is closed or because we want to force a close * happen either because the input is closed or because we want to force a close
* once the server has begun to respond. * once the server has begun to respond.
*/ */
if ((s->req->flags & (BF_SHUTW|BF_SHUTW_NOW|BF_HIJACK|BF_AUTO_CLOSE)) == BF_AUTO_CLOSE) { if (unlikely((s->req->flags & (BF_SHUTW|BF_SHUTW_NOW|BF_HIJACK|BF_AUTO_CLOSE|BF_SHUTR)) ==
if (unlikely((s->req->flags & BF_SHUTR) || (BF_AUTO_CLOSE|BF_SHUTR)))
((s->req->cons->state == SI_ST_EST) &&
(s->be->options & PR_O_FORCE_CLO) &&
(s->rep->flags & BF_READ_ACTIVITY))))
buffer_shutw_now(s->req); buffer_shutw_now(s->req);
}
/* shutdown(write) pending */ /* shutdown(write) pending */
if (unlikely((s->req->flags & (BF_SHUTW|BF_SHUTW_NOW|BF_OUT_EMPTY)) == (BF_SHUTW_NOW|BF_OUT_EMPTY))) if (unlikely((s->req->flags & (BF_SHUTW|BF_SHUTW_NOW|BF_OUT_EMPTY)) == (BF_SHUTW_NOW|BF_OUT_EMPTY)))
@ -1121,7 +1117,7 @@ resync_stream_interface:
* everything. We configure the buffer to forward indefinitely. * everything. We configure the buffer to forward indefinitely.
*/ */
if (!s->rep->analysers && if (!s->rep->analysers &&
!(s->rep->flags & (BF_HIJACK|BF_SHUTW)) && !(s->rep->flags & (BF_HIJACK|BF_SHUTW|BF_SHUTW_NOW)) &&
(s->rep->prod->state >= SI_ST_EST) && (s->rep->prod->state >= SI_ST_EST) &&
(s->rep->to_forward != BUF_INFINITE_FORWARD)) { (s->rep->to_forward != BUF_INFINITE_FORWARD)) {
/* This buffer is freewheeling, there's no analyser nor hijacker /* This buffer is freewheeling, there's no analyser nor hijacker