]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
[MEDIUM] allow a TCP frontend to switch to an HTTP backend
authorWilly Tarreau <w@1wt.eu>
Sun, 12 Jul 2009 07:47:04 +0000 (09:47 +0200)
committerWilly Tarreau <w@1wt.eu>
Sun, 12 Jul 2009 07:47:04 +0000 (09:47 +0200)
This patch allows a TCP frontend to switch to an HTTP backend.
During the switch, missing structures are automatically allocated.
The HTTP parser is enabled so that the backend first waits for a
full HTTP request.

doc/configuration.txt
src/proto_http.c
src/proxy.c

index 6f267be58d13931dbbbeb3d352d5653ad168dd4b..eafb8cfeb64f9bda76ccbe810510bbe9a1f36933 100644 (file)
@@ -4276,6 +4276,12 @@ use_backend <backend> unless <condition>
   used (in case of a "listen" section) or, in case of a frontend, no server is
   used and a 503 service unavailable response is returned.
 
+  Note that it is possible to switch from a TCP frontend to an HTTP backend. In
+  this case, etiher the frontend has already checked that the protocol is HTTP,
+  and backend processing will immediately follow, or the backend will wait for
+  a complete HTTP request to get in. This feature is useful when a frontend
+  must decode several protocols on a unique port, one of them being HTTP.
+
   See also: "default_backend", "tcp-request", and section 7 about ACLs.
   
 
index be31c488017f849daaf36450c8f027c62b34b9e5..229d71f48feaa0158c8e4d7b03bf79914b24b0b7 100644 (file)
@@ -1832,6 +1832,12 @@ int http_process_req_common(struct session *s, struct buffer *req, int an_bit, s
        struct redirect_rule *rule;
        int cur_idx;
 
+       if (unlikely(msg->msg_state != HTTP_MSG_BODY)) {
+               /* we need more data */
+               buffer_write_dis(req);
+               return 0;
+       }
+
        req->analysers &= ~an_bit;
        req->analyse_exp = TICK_ETERNITY;
 
@@ -2092,6 +2098,12 @@ int http_process_request(struct session *s, struct buffer *req, int an_bit)
        struct http_txn *txn = &s->txn;
        struct http_msg *msg = &txn->req;
 
+       if (unlikely(msg->msg_state != HTTP_MSG_BODY)) {
+               /* we need more data */
+               buffer_write_dis(req);
+               return 0;
+       }
+
        req->analysers &= ~an_bit;
        req->analyse_exp = TICK_ETERNITY;
 
@@ -2450,6 +2462,12 @@ int http_process_request_body(struct session *s, struct buffer *req, int an_bit)
        long long limit = s->be->url_param_post_limit;
        struct hdr_ctx ctx;
 
+       if (unlikely(msg->msg_state != HTTP_MSG_BODY)) {
+               /* we need more data */
+               buffer_write_dis(req);
+               return 0;
+       }
+
        /* We have to parse the HTTP request body to find any required data.
         * "balance url_param check_post" should have been the only way to get
         * into this. We were brought here after HTTP header analysis, so all
index 2dfc93b3b17d6c72ff929372fff25a2b9915a08d..7f11a19b35b3bd25b8501cca33a9e5a35e9b9f46 100644 (file)
@@ -30,6 +30,7 @@
 #include <proto/client.h>
 #include <proto/backend.h>
 #include <proto/fd.h>
+#include <proto/hdr_idx.h>
 #include <proto/log.h>
 #include <proto/protocols.h>
 #include <proto/proto_tcp.h>
@@ -245,7 +246,8 @@ struct proxy *findproxy(const char *name, int mode, int cap) {
                if ((curproxy->cap & cap)!=cap || strcmp(curproxy->id, name))
                        continue;
 
-               if (curproxy->mode != mode) {
+               if (curproxy->mode != mode &&
+                   !(curproxy->mode == PR_MODE_HTTP && mode == PR_MODE_TCP)) {
                        Alert("Unable to use proxy '%s' with wrong mode, required: %s, has: %s.\n", 
                                name, proxy_mode_str(mode), proxy_mode_str(curproxy->mode));
                        Alert("You may want to use 'mode %s'.\n", proxy_mode_str(mode));
@@ -654,6 +656,27 @@ int session_set_backend(struct session *s, struct proxy *be)
        if (be->options2 & PR_O2_RSPBUG_OK)
                s->txn.rsp.err_pos = -1; /* let buggy responses pass */
        s->flags |= SN_BE_ASSIGNED;
+
+       /* If the target backend requires HTTP processing, we have to allocate
+        * a struct hdr_idx for it if we did not have one.
+        */
+       if (unlikely(!s->txn.hdr_idx.v && (be->acl_requires & ACL_USE_L7_ANY))) {
+               if ((s->txn.hdr_idx.v = pool_alloc2(s->fe->hdr_idx_pool)) == NULL)
+                       return 0; /* not enough memory */
+               s->txn.hdr_idx.size = MAX_HTTP_HDR;
+               hdr_idx_init(&s->txn.hdr_idx);
+       }
+
+       /* If we're switching from TCP mode to HTTP mode, we need to
+        * enable several analysers on the backend.
+        */
+       if (unlikely(s->fe->mode != PR_MODE_HTTP && s->be->mode == PR_MODE_HTTP)) {
+               /* We want to wait for a complete HTTP request and process the
+                * backend parts.
+                */
+               s->req->analysers |= AN_REQ_WAIT_HTTP | AN_REQ_HTTP_PROCESS_BE | AN_REQ_HTTP_INNER;
+       }
+
        return 1;
 }