]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
BUG/MEDIUM: http/applet: Finish request processing when a service is registered
authorChristopher Faulet <cfaulet@haproxy.com>
Thu, 4 Jul 2019 09:27:15 +0000 (11:27 +0200)
committerChristopher Faulet <cfaulet@haproxy.com>
Fri, 5 Jul 2019 12:26:14 +0000 (14:26 +0200)
In the analyzers AN_REQ_HTTP_PROCESS_FE/BE, when a service is registered, it is
important to not interrupt remaining processing but just the http-request rules
processing. Otherwise, the part that handles the applets installation is
skipped.

Among the several effects, if the service is registered on a frontend (not a
listen), the forwarding of the request is skipped because all analyzers are not
set on the request channel. If the service does not depends on it, the response
is still produced and forwarded to the client. But the stream is infinitly
blocked because the request is not fully consumed. This issue was reported on
Github, see #151.

So this bug is fixed thanks to the new action return ACT_RET_DONE. Once a
service is registered, the action process_use_service() still returns
ACT_RET_STOP. But now, only rules processing is stopped. As a side effet, the
action http_action_reject() must now return ACT_RET_DONE to really stop all
processing.

This patch must be backported to 2.0. It depends on the commit introducing the
return code ACT_RET_DONE.

src/hlua.c
src/http_act.c
src/proto_http.c
src/proto_htx.c

index af2400400bd0ff17177e9dad194354f45a81298c..a2669be5278dbf4ea54ffa4c47dc726fc0e0e2f2 100644 (file)
@@ -6794,7 +6794,7 @@ static enum act_return hlua_action(struct act_rule *rule, struct proxy *px,
                        return ACT_RET_ERR;
                }
                if (s->hlua->flags & HLUA_STOP)
-                       return ACT_RET_STOP;
+                       return ACT_RET_DONE;
                return ACT_RET_CONT;
 
        /* yield. */
index 65d9595c0196da8cae0c55c2a1594ca5f5f26274..0653dd59e83d0f308fa2254fcc82bb67080e6c74 100644 (file)
@@ -269,7 +269,7 @@ static enum act_parse_ret parse_http_set_status(const char **args, int *orig_arg
  * alternative to the silent-drop action to defend against DoS attacks, and may
  * also be used with HTTP/2 to close a connection instead of just a stream.
  * The txn status is unchanged, indicating no response was sent. The termination
- * flags will indicate "PR". It always returns ACT_RET_STOP.
+ * flags will indicate "PR". It always returns ACT_RET_DONE.
  */
 static enum act_return http_action_reject(struct act_rule *rule, struct proxy *px,
                                           struct session *sess, struct stream *s, int flags)
@@ -290,7 +290,7 @@ static enum act_return http_action_reject(struct act_rule *rule, struct proxy *p
        if (!(s->flags & SF_FINST_MASK))
                s->flags |= SF_FINST_R;
 
-       return ACT_RET_STOP;
+       return ACT_RET_DONE;
 }
 
 /* parse the "reject" action:
index bfdb199159e4935903331f98b061ebf4584cec3e..35f86ef1dd20c2c75367cbed56a944c2c9199170 100644 (file)
@@ -1788,6 +1788,9 @@ resume_execution:
                        case ACT_RET_CONT:
                                break;
                        case ACT_RET_STOP:
+                               rule_ret = HTTP_RULE_RES_STOP;
+                               goto end;
+                       case ACT_RET_DONE:
                                rule_ret = HTTP_RULE_RES_DONE;
                                goto end;
                        case ACT_RET_YIELD:
@@ -2198,6 +2201,9 @@ resume_execution:
                        case ACT_RET_STOP:
                                rule_ret = HTTP_RULE_RES_STOP;
                                goto end;
+                       case ACT_RET_DONE:
+                               rule_ret = HTTP_RULE_RES_DONE;
+                               goto end;
                        case ACT_RET_YIELD:
                                s->current_rule = rule;
                                rule_ret = HTTP_RULE_RES_YIELD;
@@ -2588,7 +2594,7 @@ int http_process_req_common(struct stream *s, struct channel *req, int an_bit, s
         * by a possible reqrep, while they are processed *after* so that a
         * reqdeny can still block them. This clearly needs to change in 1.6!
         */
-       if (stats_check_uri(&s->si[1], txn, px)) {
+       if (!s->target && stats_check_uri(&s->si[1], txn, px)) {
                s->target = &http_stats_applet.obj_type;
                if (unlikely(!si_register_handler(&s->si[1], objt_applet(s->target)))) {
                        txn->status = 500;
index 6cbd33b9b36294e4b6355ae50e8bfeeae463caf3..d5119c1000cbc6431bdf020885fcb679f49fb14e 100644 (file)
@@ -540,7 +540,7 @@ int htx_process_req_common(struct stream *s, struct channel *req, int an_bit, st
         * by a possible reqrep, while they are processed *after* so that a
         * reqdeny can still block them. This clearly needs to change in 1.6!
         */
-       if (htx_stats_check_uri(s, txn, px)) {
+       if (!s->target && htx_stats_check_uri(s, txn, px)) {
                s->target = &http_stats_applet.obj_type;
                if (unlikely(!si_register_handler(&s->si[1], objt_applet(s->target)))) {
                        txn->status = 500;
@@ -3086,6 +3086,9 @@ static enum rule_result htx_req_get_intercept_rule(struct proxy *px, struct list
                                        case ACT_RET_CONT:
                                                break;
                                        case ACT_RET_STOP:
+                                               rule_ret = HTTP_RULE_RES_STOP;
+                                               goto end;
+                                       case ACT_RET_DONE:
                                                rule_ret = HTTP_RULE_RES_DONE;
                                                goto end;
                                        case ACT_RET_YIELD:
@@ -3478,6 +3481,9 @@ resume_execution:
                                        case ACT_RET_STOP:
                                                rule_ret = HTTP_RULE_RES_STOP;
                                                goto end;
+                                       case ACT_RET_DONE:
+                                               rule_ret = HTTP_RULE_RES_DONE;
+                                               goto end;
                                        case ACT_RET_YIELD:
                                                s->current_rule = rule;
                                                rule_ret = HTTP_RULE_RES_YIELD;