[MEDIUM] allow a TCP frontend to switch to an HTTP backend

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.
This commit is contained in:
Willy Tarreau 2009-07-12 09:47:04 +02:00
parent a55b7dc528
commit 51aecc76f8
3 changed files with 48 additions and 1 deletions

View 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.

View 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

View 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;
}