You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

153 lines
5.1 KiB

From 1430a0c0f62fcff4303706f5baf2b544e00fcda3 Mon Sep 17 00:00:00 2001
From: Christopher Faulet <cfaulet@haproxy.com>
Date: Tue, 18 Jul 2017 10:48:24 +0200
Subject: [PATCH 13/18] MINOR: http: Switch requests/responses in TUNNEL mode
only by checking txn flags
Today, the only way to have a request or a response in HTTP_MSG_TUNNEL state is
to have the flag TX_CON_WANT_TUN set on the transaction. So this is a symmetric
state. Both the request and the response are switch in same time in this
state. This can be done only by checking transaction flags instead of relying on
the other side state. This is the purpose of this patch.
This way, if for any reason we need to switch only one side in TUNNEL mode, it
will be possible. And to prepare asymmetric cases, we check channel flags in
DONE _AND_ TUNNEL states.
WARNING: This patch will be used to fix a bug. The fix will be commited in a
very next commit. So if the fix is backported, this one must be backported too.
(cherry picked from commit 4be9803914ae7156109c915659aad216e4a3c6c1)
Signed-off-by: William Lallemand <wlallemand@haproxy.org>
---
src/proto_http.c | 65 +++++++++++++++++++-------------------------------------
1 file changed, 22 insertions(+), 43 deletions(-)
diff --git a/src/proto_http.c b/src/proto_http.c
index aaf9f648..00a92cdb 100644
--- a/src/proto_http.c
+++ b/src/proto_http.c
@@ -5294,7 +5294,7 @@ int http_sync_req_state(struct stream *s)
unsigned int old_flags = chn->flags;
unsigned int old_state = txn->req.msg_state;
- if (unlikely(txn->req.msg_state < HTTP_MSG_BODY))
+ if (unlikely(txn->req.msg_state < HTTP_MSG_DONE))
return 0;
if (txn->req.msg_state == HTTP_MSG_DONE) {
@@ -5338,13 +5338,6 @@ int http_sync_req_state(struct stream *s)
goto wait_other_side;
}
- if (txn->rsp.msg_state == HTTP_MSG_TUNNEL) {
- /* if any side switches to tunnel mode, the other one does too */
- channel_auto_read(chn);
- txn->req.msg_state = HTTP_MSG_TUNNEL;
- goto wait_other_side;
- }
-
/* When we get here, it means that both the request and the
* response have finished receiving. Depending on the connection
* mode, we'll have to wait for the last bytes to leave in either
@@ -5377,20 +5370,7 @@ int http_sync_req_state(struct stream *s)
}
}
- if (chn->flags & (CF_SHUTW|CF_SHUTW_NOW)) {
- /* if we've just closed an output, let's switch */
- s->si[1].flags |= SI_FL_NOLINGER; /* we want to close ASAP */
-
- if (!channel_is_empty(chn)) {
- txn->req.msg_state = HTTP_MSG_CLOSING;
- goto http_msg_closing;
- }
- else {
- txn->req.msg_state = HTTP_MSG_CLOSED;
- goto http_msg_closed;
- }
- }
- goto wait_other_side;
+ goto check_channel_flags;
}
if (txn->req.msg_state == HTTP_MSG_CLOSING) {
@@ -5419,6 +5399,16 @@ int http_sync_req_state(struct stream *s)
goto wait_other_side;
}
+ check_channel_flags:
+ /* Here, we are in HTTP_MSG_DONE or HTTP_MSG_TUNNEL */
+ if (chn->flags & (CF_SHUTW|CF_SHUTW_NOW)) {
+ /* if we've just closed an output, let's switch */
+ s->si[1].flags |= SI_FL_NOLINGER; /* we want to close ASAP */
+ txn->req.msg_state = HTTP_MSG_CLOSING;
+ goto http_msg_closing;
+ }
+
+
wait_other_side:
return txn->req.msg_state != old_state || chn->flags != old_flags;
}
@@ -5438,7 +5428,7 @@ int http_sync_res_state(struct stream *s)
unsigned int old_flags = chn->flags;
unsigned int old_state = txn->rsp.msg_state;
- if (unlikely(txn->rsp.msg_state < HTTP_MSG_BODY))
+ if (unlikely(txn->rsp.msg_state < HTTP_MSG_DONE))
return 0;
if (txn->rsp.msg_state == HTTP_MSG_DONE) {
@@ -5461,14 +5451,6 @@ int http_sync_res_state(struct stream *s)
goto wait_other_side;
}
- if (txn->req.msg_state == HTTP_MSG_TUNNEL) {
- /* if any side switches to tunnel mode, the other one does too */
- channel_auto_read(chn);
- txn->rsp.msg_state = HTTP_MSG_TUNNEL;
- chn->flags |= CF_NEVER_WAIT;
- goto wait_other_side;
- }
-
/* When we get here, it means that both the request and the
* response have finished receiving. Depending on the connection
* mode, we'll have to wait for the last bytes to leave in either
@@ -5506,18 +5488,7 @@ int http_sync_res_state(struct stream *s)
txn->rsp.msg_state = HTTP_MSG_TUNNEL;
}
- if (chn->flags & (CF_SHUTW|CF_SHUTW_NOW)) {
- /* if we've just closed an output, let's switch */
- if (!channel_is_empty(chn)) {
- txn->rsp.msg_state = HTTP_MSG_CLOSING;
- goto http_msg_closing;
- }
- else {
- txn->rsp.msg_state = HTTP_MSG_CLOSED;
- goto http_msg_closed;
- }
- }
- goto wait_other_side;
+ goto check_channel_flags;
}
if (txn->rsp.msg_state == HTTP_MSG_CLOSING) {
@@ -5548,6 +5519,14 @@ int http_sync_res_state(struct stream *s)
goto wait_other_side;
}
+ check_channel_flags:
+ /* Here, we are in HTTP_MSG_DONE or HTTP_MSG_TUNNEL */
+ if (chn->flags & (CF_SHUTW|CF_SHUTW_NOW)) {
+ /* if we've just closed an output, let's switch */
+ txn->rsp.msg_state = HTTP_MSG_CLOSING;
+ goto http_msg_closing;
+ }
+
wait_other_side:
/* We force the response to leave immediately if we're waiting for the
* other side, since there is no pending shutdown to push it out.
--
2.13.0