55f9c172698c87c2b6b5297f54e341671ca8bdf0
[openwrt-packages.git] /
1 commit 8ece0801d813d6f821dabde13f7a74759dd95ee4
2 Author: Christopher Faulet <cfaulet@haproxy.com>
3 Date:   Fri Nov 15 16:31:46 2019 +0100
4
5     BUG/MINOR: http-ana/filters: Wait end of the http_end callback for all filters
6     
7     Filters may define the "http_end" callback, called at the end of the analysis of
8     any HTTP messages. It is called at the end of the payload forwarding and it can
9     interrupt the stream processing. So we must be sure to not remove the XFER_BODY
10     analyzers while there is still at least filter in progress on this callback.
11     
12     Unfortunatly, once the request and the response are borh in the DONE or the
13     TUNNEL mode, we consider the XFER_BODY analyzer has finished its processing on
14     both sides. So it is possible to prematurely interrupt the execution of the
15     filters "http_end" callback.
16     
17     To fix this bug, we switch a message in the ENDING state. It is then switched in
18     DONE/TUNNEL mode only after the execution of the filters "http_end" callback.
19     
20     This patch must be backported (and adapted) to 2.1, 2.0 and 1.9. The legacy HTTP
21     mode shoud probaly be fixed too.
22     
23     (cherry picked from commit 1a3e0279c6079174288e2e3fbbf09e530ff221c5)
24     Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
25
26 diff --git a/src/http_ana.c b/src/http_ana.c
27 index 268796d2e..047ed813a 100644
28 --- a/src/http_ana.c
29 +++ b/src/http_ana.c
30 @@ -1166,11 +1166,8 @@ int http_request_forward_body(struct stream *s, struct channel *req, int an_bit)
31  
32         if (req->to_forward) {
33                 if (req->to_forward == CHN_INFINITE_FORWARD) {
34 -                       if (req->flags & CF_EOI) {
35 -                               msg->msg_state = HTTP_MSG_DONE;
36 -                               req->to_forward = 0;
37 -                               goto done;
38 -                       }
39 +                       if (req->flags & CF_EOI)
40 +                               msg->msg_state = HTTP_MSG_ENDING;
41                 }
42                 else {
43                         /* We can't process the buffer's contents yet */
44 @@ -1179,8 +1176,14 @@ int http_request_forward_body(struct stream *s, struct channel *req, int an_bit)
45                 }
46         }
47  
48 -       if (msg->msg_state >= HTTP_MSG_DONE)
49 -               goto done;
50 +       if (msg->msg_state >= HTTP_MSG_ENDING)
51 +               goto ending;
52 +
53 +       if (txn->meth == HTTP_METH_CONNECT) {
54 +               msg->msg_state = HTTP_MSG_ENDING;
55 +               goto ending;
56 +       }
57 +
58         /* Forward input data. We get it by removing all outgoing data not
59          * forwarded yet from HTX data size. If there are some data filters, we
60          * let them decide the amount of data to forward.
61 @@ -1197,11 +1200,8 @@ int http_request_forward_body(struct stream *s, struct channel *req, int an_bit)
62                         channel_htx_forward_forever(req, htx);
63         }
64  
65 -       if (txn->meth == HTTP_METH_CONNECT) {
66 -               msg->msg_state = HTTP_MSG_TUNNEL;
67 -               goto done;
68 -       }
69 -
70 +       if (htx->data != co_data(req))
71 +               goto missing_data_or_waiting;
72  
73         /* Check if the end-of-message is reached and if so, switch the message
74          * in HTTP_MSG_ENDING state. Then if all data was marked to be
75 @@ -1211,16 +1211,11 @@ int http_request_forward_body(struct stream *s, struct channel *req, int an_bit)
76                 goto missing_data_or_waiting;
77  
78         msg->msg_state = HTTP_MSG_ENDING;
79 -       if (htx->data != co_data(req))
80 -               goto missing_data_or_waiting;
81 -       msg->msg_state = HTTP_MSG_DONE;
82 -       req->to_forward = 0;
83  
84 -  done:
85 -       /* other states, DONE...TUNNEL */
86 -       /* we don't want to forward closes on DONE except in tunnel mode. */
87 -       if (!(txn->flags & TX_CON_WANT_TUN))
88 -               channel_dont_close(req);
89 +  ending:
90 +       /* other states, ENDING...TUNNEL */
91 +       if (msg->msg_state >= HTTP_MSG_DONE)
92 +               goto done;
93  
94         if (HAS_REQ_DATA_FILTERS(s)) {
95                 ret = flt_http_end(s, msg);
96 @@ -1231,6 +1226,18 @@ int http_request_forward_body(struct stream *s, struct channel *req, int an_bit)
97                 }
98         }
99  
100 +       if (txn->meth == HTTP_METH_CONNECT)
101 +               msg->msg_state = HTTP_MSG_TUNNEL;
102 +       else {
103 +               msg->msg_state = HTTP_MSG_DONE;
104 +               req->to_forward = 0;
105 +       }
106 +
107 +  done:
108 +       /* we don't want to forward closes on DONE except in tunnel mode. */
109 +       if (!(txn->flags & TX_CON_WANT_TUN))
110 +               channel_dont_close(req);
111 +
112         http_end_request(s);
113         if (!(req->analysers & an_bit)) {
114                 http_end_response(s);
115 @@ -2179,11 +2186,8 @@ int http_response_forward_body(struct stream *s, struct channel *res, int an_bit
116  
117         if (res->to_forward) {
118                 if (res->to_forward == CHN_INFINITE_FORWARD) {
119 -                       if (res->flags & CF_EOI) {
120 -                               msg->msg_state = HTTP_MSG_DONE;
121 -                               res->to_forward = 0;
122 -                               goto done;
123 -                       }
124 +                       if (res->flags & CF_EOI)
125 +                               msg->msg_state = HTTP_MSG_ENDING;
126                 }
127                 else {
128                         /* We can't process the buffer's contents yet */
129 @@ -2192,8 +2196,14 @@ int http_response_forward_body(struct stream *s, struct channel *res, int an_bit
130                 }
131         }
132  
133 -       if (msg->msg_state >= HTTP_MSG_DONE)
134 -               goto done;
135 +       if (msg->msg_state >= HTTP_MSG_ENDING)
136 +               goto ending;
137 +
138 +       if ((txn->meth == HTTP_METH_CONNECT && txn->status == 200) || txn->status == 101 ||
139 +           (!(msg->flags & HTTP_MSGF_XFER_LEN) && !HAS_RSP_DATA_FILTERS(s))) {
140 +               msg->msg_state = HTTP_MSG_ENDING;
141 +               goto ending;
142 +       }
143  
144         /* Forward input data. We get it by removing all outgoing data not
145          * forwarded yet from HTX data size. If there are some data filters, we
146 @@ -2211,10 +2221,12 @@ int http_response_forward_body(struct stream *s, struct channel *res, int an_bit
147                         channel_htx_forward_forever(res, htx);
148         }
149  
150 -       if ((txn->meth == HTTP_METH_CONNECT && txn->status == 200) || txn->status == 101 ||
151 -           (!(msg->flags & HTTP_MSGF_XFER_LEN) && (res->flags & CF_SHUTR || !HAS_RSP_DATA_FILTERS(s)))) {
152 -               msg->msg_state = HTTP_MSG_TUNNEL;
153 -               goto done;
154 +       if (htx->data != co_data(res))
155 +               goto missing_data_or_waiting;
156 +
157 +       if (!(msg->flags & HTTP_MSGF_XFER_LEN) && res->flags & CF_SHUTR) {
158 +               msg->msg_state = HTTP_MSG_ENDING;
159 +               goto ending;
160         }
161  
162         /* Check if the end-of-message is reached and if so, switch the message
163 @@ -2225,14 +2237,11 @@ int http_response_forward_body(struct stream *s, struct channel *res, int an_bit
164                 goto missing_data_or_waiting;
165  
166         msg->msg_state = HTTP_MSG_ENDING;
167 -       if (htx->data != co_data(res))
168 -               goto missing_data_or_waiting;
169 -       msg->msg_state = HTTP_MSG_DONE;
170 -       res->to_forward = 0;
171  
172 -  done:
173 -       /* other states, DONE...TUNNEL */
174 -       channel_dont_close(res);
175 +  ending:
176 +       /* other states, ENDING...TUNNEL */
177 +       if (msg->msg_state >= HTTP_MSG_DONE)
178 +               goto done;
179  
180         if (HAS_RSP_DATA_FILTERS(s)) {
181                 ret = flt_http_end(s, msg);
182 @@ -2243,6 +2252,20 @@ int http_response_forward_body(struct stream *s, struct channel *res, int an_bit
183                 }
184         }
185  
186 +       if ((txn->meth == HTTP_METH_CONNECT && txn->status == 200) || txn->status == 101 ||
187 +           !(msg->flags & HTTP_MSGF_XFER_LEN)) {
188 +               msg->msg_state = HTTP_MSG_TUNNEL;
189 +               goto ending;
190 +       }
191 +       else {
192 +               msg->msg_state = HTTP_MSG_DONE;
193 +               res->to_forward = 0;
194 +       }
195 +
196 +  done:
197 +
198 +       channel_dont_close(res);
199 +
200         http_end_response(s);
201         if (!(res->analysers & an_bit)) {
202                 http_end_request(s);
git clone https://git.99rst.org/PROJECT