mirror of
https://git.haproxy.org/git/haproxy.git/
synced 2025-09-21 13:51:26 +02:00
[MAJOR] http: complete splitting of the remaining stages
The HTTP processing has been splitted into 7 steps, one of which is not anymore HTTP-specific (content-switching). That way, it becomes possible to use "use_backend" rules in TCP mode. A new "use_server" directive should follow soon.
This commit is contained in:
parent
3a816293e9
commit
1d0dfb155d
@ -1440,11 +1440,6 @@ default_backend <backend>
|
|||||||
used when no rule has matched. It generally is the dynamic backend which
|
used when no rule has matched. It generally is the dynamic backend which
|
||||||
will catch all undetermined requests.
|
will catch all undetermined requests.
|
||||||
|
|
||||||
The "default_backend" keyword is also supported in TCP mode frontends to
|
|
||||||
facilitate the ordering of configurations in frontends and backends,
|
|
||||||
eventhough it does not make much more sense in case of TCP due to the fact
|
|
||||||
that use_backend currently does not work in TCP mode.
|
|
||||||
|
|
||||||
Example :
|
Example :
|
||||||
|
|
||||||
use_backend dynamic if url_dyn
|
use_backend dynamic if url_dyn
|
||||||
@ -4254,7 +4249,7 @@ transparent (deprecated)
|
|||||||
|
|
||||||
use_backend <backend> if <condition>
|
use_backend <backend> if <condition>
|
||||||
use_backend <backend> unless <condition>
|
use_backend <backend> unless <condition>
|
||||||
Switch to a specific backend if/unless a Layer 7 condition is matched.
|
Switch to a specific backend if/unless an ACL-based condition is matched.
|
||||||
May be used in sections : defaults | frontend | listen | backend
|
May be used in sections : defaults | frontend | listen | backend
|
||||||
no | yes | yes | no
|
no | yes | yes | no
|
||||||
Arguments :
|
Arguments :
|
||||||
@ -4265,7 +4260,10 @@ use_backend <backend> unless <condition>
|
|||||||
When doing content-switching, connections arrive on a frontend and are then
|
When doing content-switching, connections arrive on a frontend and are then
|
||||||
dispatched to various backends depending on a number of conditions. The
|
dispatched to various backends depending on a number of conditions. The
|
||||||
relation between the conditions and the backends is described with the
|
relation between the conditions and the backends is described with the
|
||||||
"use_backend" keyword. This is supported only in HTTP mode.
|
"use_backend" keyword. While it is normally used with HTTP processing, it can
|
||||||
|
also be used in pure TCP, either without content using stateless ACLs (eg:
|
||||||
|
source address validation) or combined with a "tcp-request" rule to wait for
|
||||||
|
some payload.
|
||||||
|
|
||||||
There may be as many "use_backend" rules as desired. All of these rules are
|
There may be as many "use_backend" rules as desired. All of these rules are
|
||||||
evaluated in their declaration order, and the first one which matches will
|
evaluated in their declaration order, and the first one which matches will
|
||||||
@ -4278,7 +4276,7 @@ use_backend <backend> unless <condition>
|
|||||||
used (in case of a "listen" section) or, in case of a frontend, no server is
|
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.
|
used and a 503 service unavailable response is returned.
|
||||||
|
|
||||||
See also: "default_backend" and section 7 about ACLs.
|
See also: "default_backend", "tcp-request", and section 7 about ACLs.
|
||||||
|
|
||||||
|
|
||||||
5. Server options
|
5. Server options
|
||||||
|
@ -62,6 +62,7 @@ int process_cli(struct session *t);
|
|||||||
int process_srv_data(struct session *t);
|
int process_srv_data(struct session *t);
|
||||||
int process_srv_conn(struct session *t);
|
int process_srv_conn(struct session *t);
|
||||||
int http_wait_for_request(struct session *s, struct buffer *req, int an_bit);
|
int http_wait_for_request(struct session *s, struct buffer *req, int an_bit);
|
||||||
|
int http_process_req_common(struct session *s, struct buffer *req, int an_bit, struct proxy *px);
|
||||||
int http_process_request(struct session *t, struct buffer *req, int an_bit);
|
int http_process_request(struct session *t, struct buffer *req, int an_bit);
|
||||||
int http_process_tarpit(struct session *s, struct buffer *req, int an_bit);
|
int http_process_tarpit(struct session *s, struct buffer *req, int an_bit);
|
||||||
int http_process_request_body(struct session *s, struct buffer *req, int an_bit);
|
int http_process_request_body(struct session *s, struct buffer *req, int an_bit);
|
||||||
|
@ -35,6 +35,7 @@ void pause_proxy(struct proxy *p);
|
|||||||
void stop_proxy(struct proxy *p);
|
void stop_proxy(struct proxy *p);
|
||||||
void pause_proxies(void);
|
void pause_proxies(void);
|
||||||
void listen_proxies(void);
|
void listen_proxies(void);
|
||||||
|
void session_set_backend(struct session *s, struct proxy *be);
|
||||||
|
|
||||||
const char *proxy_cap_str(int cap);
|
const char *proxy_cap_str(int cap);
|
||||||
const char *proxy_mode_str(int mode);
|
const char *proxy_mode_str(int mode);
|
||||||
|
@ -106,12 +106,16 @@
|
|||||||
* afterwards.
|
* afterwards.
|
||||||
*/
|
*/
|
||||||
#define AN_REQ_INSPECT 0x00000001 /* inspect request contents */
|
#define AN_REQ_INSPECT 0x00000001 /* inspect request contents */
|
||||||
#define AN_REQ_HTTP_HDR 0x00000002 /* inspect HTTP request headers */
|
#define AN_REQ_WAIT_HTTP 0x00000002 /* wait for an HTTP request */
|
||||||
#define AN_REQ_HTTP_BODY 0x00000004 /* inspect HTTP request body */
|
#define AN_REQ_HTTP_PROCESS_FE 0x00000004 /* process the frontend's HTTP part */
|
||||||
#define AN_REQ_HTTP_TARPIT 0x00000008 /* wait for end of HTTP tarpit */
|
#define AN_REQ_SWITCHING_RULES 0x00000008 /* apply the switching rules */
|
||||||
#define AN_RTR_HTTP_HDR 0x00000010 /* inspect HTTP response headers */
|
#define AN_REQ_HTTP_PROCESS_BE 0x00000010 /* process the backend's HTTP part */
|
||||||
#define AN_REQ_UNIX_STATS 0x00000020 /* process unix stats socket request */
|
#define AN_REQ_HTTP_INNER 0x00000020 /* inner processing of HTTP request */
|
||||||
#define AN_REQ_WAIT_HTTP 0x00000040 /* wait for an HTTP request */
|
#define AN_REQ_HTTP_TARPIT 0x00000040 /* wait for end of HTTP tarpit */
|
||||||
|
#define AN_REQ_HTTP_BODY 0x00000080 /* inspect HTTP request body */
|
||||||
|
#define AN_REQ_UNIX_STATS 0x00000100 /* process unix stats socket request */
|
||||||
|
|
||||||
|
#define AN_RTR_HTTP_HDR 0x00000200 /* inspect HTTP response headers */
|
||||||
|
|
||||||
/* describes a chunk of string */
|
/* describes a chunk of string */
|
||||||
struct chunk {
|
struct chunk {
|
||||||
|
@ -3775,9 +3775,11 @@ int check_config_validity()
|
|||||||
listener->accept = event_accept;
|
listener->accept = event_accept;
|
||||||
listener->private = curproxy;
|
listener->private = curproxy;
|
||||||
listener->handler = process_session;
|
listener->handler = process_session;
|
||||||
|
/* both TCP and HTTP must check switching rules */
|
||||||
|
listener->analysers |= AN_REQ_SWITCHING_RULES;
|
||||||
|
|
||||||
if (curproxy->mode == PR_MODE_HTTP)
|
if (curproxy->mode == PR_MODE_HTTP)
|
||||||
listener->analysers |= AN_REQ_WAIT_HTTP | AN_REQ_HTTP_HDR;
|
listener->analysers |= AN_REQ_WAIT_HTTP | AN_REQ_HTTP_PROCESS_FE | AN_REQ_HTTP_INNER | AN_REQ_HTTP_PROCESS_BE;
|
||||||
|
|
||||||
/* smart accept mode is automatic in HTTP mode */
|
/* smart accept mode is automatic in HTTP mode */
|
||||||
if ((curproxy->options2 & PR_O2_SMARTACC) ||
|
if ((curproxy->options2 & PR_O2_SMARTACC) ||
|
||||||
@ -3789,6 +3791,7 @@ int check_config_validity()
|
|||||||
!LIST_ISEMPTY(&curproxy->tcp_req.inspect_rules))
|
!LIST_ISEMPTY(&curproxy->tcp_req.inspect_rules))
|
||||||
listener->analysers |= AN_REQ_INSPECT;
|
listener->analysers |= AN_REQ_INSPECT;
|
||||||
|
|
||||||
|
/* We want the use_backend and default_backend rules to apply */
|
||||||
listener = listener->next;
|
listener = listener->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
20
src/client.c
20
src/client.c
@ -165,18 +165,12 @@ int event_accept(int fd) {
|
|||||||
|
|
||||||
s->task = t;
|
s->task = t;
|
||||||
s->listener = l;
|
s->listener = l;
|
||||||
s->be = s->fe = p;
|
|
||||||
|
|
||||||
/* in HTTP mode, content switching requires that the backend
|
/* Note: initially, the session's backend points to the frontend.
|
||||||
* first points to the same proxy as the frontend. However, in
|
* This changes later when switching rules are executed or
|
||||||
* TCP mode there will be no header processing so any default
|
* when the default backend is assigned.
|
||||||
* backend must be assigned if set.
|
|
||||||
*/
|
*/
|
||||||
if (p->mode == PR_MODE_TCP) {
|
s->be = s->fe = p;
|
||||||
if (p->defbe.be)
|
|
||||||
s->be = p->defbe.be;
|
|
||||||
s->flags |= SN_BE_ASSIGNED;
|
|
||||||
}
|
|
||||||
|
|
||||||
s->ana_state = 0; /* analysers may change it but must reset it upon exit */
|
s->ana_state = 0; /* analysers may change it but must reset it upon exit */
|
||||||
s->req = s->rep = NULL; /* will be allocated later */
|
s->req = s->rep = NULL; /* will be allocated later */
|
||||||
@ -459,12 +453,6 @@ int event_accept(int fd) {
|
|||||||
if (p->feconn > p->feconn_max)
|
if (p->feconn > p->feconn_max)
|
||||||
p->feconn_max = p->feconn;
|
p->feconn_max = p->feconn;
|
||||||
|
|
||||||
if (s->flags & SN_BE_ASSIGNED) {
|
|
||||||
proxy_inc_be_ctr(s->be);
|
|
||||||
s->be->beconn++;
|
|
||||||
if (s->be->beconn > s->be->beconn_max)
|
|
||||||
s->be->beconn_max = s->be->beconn;
|
|
||||||
}
|
|
||||||
actconn++;
|
actconn++;
|
||||||
totalconn++;
|
totalconn++;
|
||||||
|
|
||||||
|
541
src/proto_http.c
541
src/proto_http.c
@ -354,10 +354,6 @@ const char http_is_ver_token[256] = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
#ifdef DEBUG_FULL
|
|
||||||
static char *cli_stnames[4] = { "DAT", "SHR", "SHW", "CLS" };
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Adds a header and its CRLF at the tail of buffer <b>, just before the last
|
* Adds a header and its CRLF at the tail of buffer <b>, just before the last
|
||||||
* CRLF. Text length is measured first, so it cannot be NULL.
|
* CRLF. Text length is measured first, so it cannot be NULL.
|
||||||
@ -1809,17 +1805,20 @@ int http_wait_for_request(struct session *s, struct buffer *req, int an_bit)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* This function performs all the processing enabled for the current request.
|
/* This stream analyser runs all HTTP request processing which is common to
|
||||||
|
* frontends and backends, which means blocking ACLs, filters, connection-close,
|
||||||
|
* reqadd, stats and redirects. This is performed for the designated proxy.
|
||||||
* It returns 1 if the processing can continue on next analysers, or zero if it
|
* It returns 1 if the processing can continue on next analysers, or zero if it
|
||||||
* needs more data, encounters an error, or wants to immediately abort the
|
* either needs more data or wants to immediately abort the request (eg: deny,
|
||||||
* request. It relies on buffers flags, and updates s->req->analysers.
|
* error, ...).
|
||||||
*/
|
*/
|
||||||
int http_process_request(struct session *s, struct buffer *req, int an_bit)
|
int http_process_req_common(struct session *s, struct buffer *req, int an_bit, struct proxy *px)
|
||||||
{
|
{
|
||||||
int cur_idx;
|
|
||||||
struct http_txn *txn = &s->txn;
|
struct http_txn *txn = &s->txn;
|
||||||
struct http_msg *msg = &txn->req;
|
struct http_msg *msg = &txn->req;
|
||||||
struct proxy *cur_proxy;
|
struct acl_cond *cond;
|
||||||
|
struct redirect_rule *rule;
|
||||||
|
int cur_idx;
|
||||||
|
|
||||||
req->analysers &= ~an_bit;
|
req->analysers &= ~an_bit;
|
||||||
req->analyse_exp = TICK_ETERNITY;
|
req->analyse_exp = TICK_ETERNITY;
|
||||||
@ -1833,70 +1832,27 @@ int http_process_request(struct session *s, struct buffer *req, int an_bit)
|
|||||||
req->l,
|
req->l,
|
||||||
req->analysers);
|
req->analysers);
|
||||||
|
|
||||||
/*
|
/* first check whether we have some ACLs set to block this request */
|
||||||
* 6: we will have to evaluate the filters.
|
list_for_each_entry(cond, &px->block_cond, list) {
|
||||||
* As opposed to version 1.2, now they will be evaluated in the
|
int ret = acl_exec_cond(cond, px, s, txn, ACL_DIR_REQ);
|
||||||
* filters order and not in the header order. This means that
|
|
||||||
* each filter has to be validated among all headers.
|
|
||||||
*
|
|
||||||
* We can now check whether we want to switch to another
|
|
||||||
* backend, in which case we will re-check the backend's
|
|
||||||
* filters and various options. In order to support 3-level
|
|
||||||
* switching, here's how we should proceed :
|
|
||||||
*
|
|
||||||
* a) run be.
|
|
||||||
* if (switch) then switch ->be to the new backend.
|
|
||||||
* b) run be if (be != fe).
|
|
||||||
* There cannot be any switch from there, so ->be cannot be
|
|
||||||
* changed anymore.
|
|
||||||
*
|
|
||||||
* => filters always apply to ->be, then ->be may change.
|
|
||||||
*
|
|
||||||
* The response path will be able to apply either ->be, or
|
|
||||||
* ->be then ->fe filters in order to match the reverse of
|
|
||||||
* the forward sequence.
|
|
||||||
*/
|
|
||||||
|
|
||||||
do {
|
ret = acl_pass(ret);
|
||||||
struct acl_cond *cond;
|
if (cond->pol == ACL_COND_UNLESS)
|
||||||
struct redirect_rule *rule;
|
ret = !ret;
|
||||||
struct proxy *rule_set = s->be;
|
|
||||||
cur_proxy = s->be;
|
|
||||||
|
|
||||||
/* first check whether we have some ACLs set to block this request */
|
if (ret) {
|
||||||
list_for_each_entry(cond, &cur_proxy->block_cond, list) {
|
txn->status = 403;
|
||||||
int ret = acl_exec_cond(cond, cur_proxy, s, txn, ACL_DIR_REQ);
|
/* let's log the request time */
|
||||||
|
s->logs.tv_request = now;
|
||||||
ret = acl_pass(ret);
|
stream_int_retnclose(req->prod, error_message(s, HTTP_ERR_403));
|
||||||
if (cond->pol == ACL_COND_UNLESS)
|
goto return_prx_cond;
|
||||||
ret = !ret;
|
|
||||||
|
|
||||||
if (ret) {
|
|
||||||
txn->status = 403;
|
|
||||||
/* let's log the request time */
|
|
||||||
s->logs.tv_request = now;
|
|
||||||
stream_int_retnclose(req->prod, error_message(s, HTTP_ERR_403));
|
|
||||||
goto return_prx_cond;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* try headers filters */
|
/* try headers filters */
|
||||||
if (rule_set->req_exp != NULL) {
|
if (px->req_exp != NULL) {
|
||||||
if (apply_filters_to_request(s, req, rule_set->req_exp) < 0)
|
if (apply_filters_to_request(s, req, px->req_exp) < 0)
|
||||||
goto return_bad_req;
|
goto return_bad_req;
|
||||||
}
|
|
||||||
|
|
||||||
if (!(s->flags & SN_BE_ASSIGNED) && (s->be != cur_proxy)) {
|
|
||||||
/* to ensure correct connection accounting on
|
|
||||||
* the backend, we count the connection for the
|
|
||||||
* one managing the queue.
|
|
||||||
*/
|
|
||||||
s->be->beconn++;
|
|
||||||
if (s->be->beconn > s->be->beconn_max)
|
|
||||||
s->be->beconn_max = s->be->beconn;
|
|
||||||
proxy_inc_be_ctr(s->be);
|
|
||||||
s->flags |= SN_BE_ASSIGNED;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* has the request been denied ? */
|
/* has the request been denied ? */
|
||||||
if (txn->flags & TX_CLDENY) {
|
if (txn->flags & TX_CLDENY) {
|
||||||
@ -1907,249 +1863,235 @@ int http_process_request(struct session *s, struct buffer *req, int an_bit)
|
|||||||
stream_int_retnclose(req->prod, error_message(s, HTTP_ERR_403));
|
stream_int_retnclose(req->prod, error_message(s, HTTP_ERR_403));
|
||||||
goto return_prx_cond;
|
goto return_prx_cond;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* We might have to check for "Connection:" */
|
/* We might have to check for "Connection:" */
|
||||||
if (((s->fe->options | s->be->options) & (PR_O_HTTP_CLOSE|PR_O_FORCE_CLO)) &&
|
if (((s->fe->options | s->be->options) & (PR_O_HTTP_CLOSE|PR_O_FORCE_CLO)) &&
|
||||||
!(s->flags & SN_CONN_CLOSED)) {
|
!(s->flags & SN_CONN_CLOSED)) {
|
||||||
char *cur_ptr, *cur_end, *cur_next;
|
char *cur_ptr, *cur_end, *cur_next;
|
||||||
int cur_idx, old_idx, delta, val;
|
int old_idx, delta, val;
|
||||||
struct hdr_idx_elem *cur_hdr;
|
struct hdr_idx_elem *cur_hdr;
|
||||||
|
|
||||||
cur_next = req->data + txn->req.som + hdr_idx_first_pos(&txn->hdr_idx);
|
cur_next = req->data + txn->req.som + hdr_idx_first_pos(&txn->hdr_idx);
|
||||||
old_idx = 0;
|
old_idx = 0;
|
||||||
|
|
||||||
while ((cur_idx = txn->hdr_idx.v[old_idx].next)) {
|
while ((cur_idx = txn->hdr_idx.v[old_idx].next)) {
|
||||||
cur_hdr = &txn->hdr_idx.v[cur_idx];
|
cur_hdr = &txn->hdr_idx.v[cur_idx];
|
||||||
cur_ptr = cur_next;
|
cur_ptr = cur_next;
|
||||||
cur_end = cur_ptr + cur_hdr->len;
|
cur_end = cur_ptr + cur_hdr->len;
|
||||||
cur_next = cur_end + cur_hdr->cr + 1;
|
cur_next = cur_end + cur_hdr->cr + 1;
|
||||||
|
|
||||||
val = http_header_match2(cur_ptr, cur_end, "Connection", 10);
|
val = http_header_match2(cur_ptr, cur_end, "Connection", 10);
|
||||||
if (val) {
|
if (val) {
|
||||||
/* 3 possibilities :
|
/* 3 possibilities :
|
||||||
* - we have already set Connection: close,
|
* - we have already set Connection: close,
|
||||||
* so we remove this line.
|
* so we remove this line.
|
||||||
* - we have not yet set Connection: close,
|
* - we have not yet set Connection: close,
|
||||||
* but this line indicates close. We leave
|
* but this line indicates close. We leave
|
||||||
* it untouched and set the flag.
|
* it untouched and set the flag.
|
||||||
* - we have not yet set Connection: close,
|
* - we have not yet set Connection: close,
|
||||||
* and this line indicates non-close. We
|
* and this line indicates non-close. We
|
||||||
* replace it.
|
* replace it.
|
||||||
*/
|
*/
|
||||||
if (s->flags & SN_CONN_CLOSED) {
|
if (s->flags & SN_CONN_CLOSED) {
|
||||||
delta = buffer_replace2(req, cur_ptr, cur_next, NULL, 0);
|
delta = buffer_replace2(req, cur_ptr, cur_next, NULL, 0);
|
||||||
txn->req.eoh += delta;
|
txn->req.eoh += delta;
|
||||||
|
cur_next += delta;
|
||||||
|
txn->hdr_idx.v[old_idx].next = cur_hdr->next;
|
||||||
|
txn->hdr_idx.used--;
|
||||||
|
cur_hdr->len = 0;
|
||||||
|
} else {
|
||||||
|
if (strncasecmp(cur_ptr + val, "close", 5) != 0) {
|
||||||
|
delta = buffer_replace2(req, cur_ptr + val, cur_end,
|
||||||
|
"close", 5);
|
||||||
cur_next += delta;
|
cur_next += delta;
|
||||||
txn->hdr_idx.v[old_idx].next = cur_hdr->next;
|
cur_hdr->len += delta;
|
||||||
txn->hdr_idx.used--;
|
txn->req.eoh += delta;
|
||||||
cur_hdr->len = 0;
|
|
||||||
} else {
|
|
||||||
if (strncasecmp(cur_ptr + val, "close", 5) != 0) {
|
|
||||||
delta = buffer_replace2(req, cur_ptr + val, cur_end,
|
|
||||||
"close", 5);
|
|
||||||
cur_next += delta;
|
|
||||||
cur_hdr->len += delta;
|
|
||||||
txn->req.eoh += delta;
|
|
||||||
}
|
|
||||||
s->flags |= SN_CONN_CLOSED;
|
|
||||||
}
|
}
|
||||||
|
s->flags |= SN_CONN_CLOSED;
|
||||||
}
|
}
|
||||||
old_idx = cur_idx;
|
|
||||||
}
|
}
|
||||||
|
old_idx = cur_idx;
|
||||||
}
|
}
|
||||||
/* add request headers from the rule sets in the same order */
|
}
|
||||||
for (cur_idx = 0; cur_idx < rule_set->nb_reqadd; cur_idx++) {
|
/* add request headers from the rule sets in the same order */
|
||||||
if (unlikely(http_header_add_tail(req,
|
for (cur_idx = 0; cur_idx < px->nb_reqadd; cur_idx++) {
|
||||||
&txn->req,
|
if (unlikely(http_header_add_tail(req,
|
||||||
&txn->hdr_idx,
|
&txn->req,
|
||||||
rule_set->req_add[cur_idx])) < 0)
|
&txn->hdr_idx,
|
||||||
|
px->req_add[cur_idx])) < 0)
|
||||||
|
goto return_bad_req;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* check if stats URI was requested, and if an auth is needed */
|
||||||
|
if (px->uri_auth != NULL &&
|
||||||
|
(txn->meth == HTTP_METH_GET || txn->meth == HTTP_METH_HEAD)) {
|
||||||
|
/* we have to check the URI and auth for this request.
|
||||||
|
* FIXME!!! that one is rather dangerous, we want to
|
||||||
|
* make it follow standard rules (eg: clear req->analysers).
|
||||||
|
*/
|
||||||
|
if (stats_check_uri_auth(s, px)) {
|
||||||
|
req->analysers = 0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* check whether we have some ACLs set to redirect this request */
|
||||||
|
list_for_each_entry(rule, &px->redirect_rules, list) {
|
||||||
|
int ret = acl_exec_cond(rule->cond, px, s, txn, ACL_DIR_REQ);
|
||||||
|
|
||||||
|
ret = acl_pass(ret);
|
||||||
|
if (rule->cond->pol == ACL_COND_UNLESS)
|
||||||
|
ret = !ret;
|
||||||
|
|
||||||
|
if (ret) {
|
||||||
|
struct chunk rdr = { trash, 0 };
|
||||||
|
const char *msg_fmt;
|
||||||
|
|
||||||
|
/* build redirect message */
|
||||||
|
switch(rule->code) {
|
||||||
|
case 303:
|
||||||
|
rdr.len = strlen(HTTP_303);
|
||||||
|
msg_fmt = HTTP_303;
|
||||||
|
break;
|
||||||
|
case 301:
|
||||||
|
rdr.len = strlen(HTTP_301);
|
||||||
|
msg_fmt = HTTP_301;
|
||||||
|
break;
|
||||||
|
case 302:
|
||||||
|
default:
|
||||||
|
rdr.len = strlen(HTTP_302);
|
||||||
|
msg_fmt = HTTP_302;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (unlikely(rdr.len > sizeof(trash)))
|
||||||
goto return_bad_req;
|
goto return_bad_req;
|
||||||
}
|
memcpy(rdr.str, msg_fmt, rdr.len);
|
||||||
|
|
||||||
/* check if stats URI was requested, and if an auth is needed */
|
switch(rule->type) {
|
||||||
if (rule_set->uri_auth != NULL &&
|
case REDIRECT_TYPE_PREFIX: {
|
||||||
(txn->meth == HTTP_METH_GET || txn->meth == HTTP_METH_HEAD)) {
|
const char *path;
|
||||||
/* we have to check the URI and auth for this request.
|
int pathlen;
|
||||||
* FIXME!!! that one is rather dangerous, we want to
|
|
||||||
* make it follow standard rules (eg: clear req->analysers).
|
|
||||||
*/
|
|
||||||
if (stats_check_uri_auth(s, rule_set)) {
|
|
||||||
req->analysers = 0;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* first check whether we have some ACLs set to redirect this request */
|
path = http_get_path(txn);
|
||||||
list_for_each_entry(rule, &cur_proxy->redirect_rules, list) {
|
/* build message using path */
|
||||||
int ret = acl_exec_cond(rule->cond, cur_proxy, s, txn, ACL_DIR_REQ);
|
if (path) {
|
||||||
|
pathlen = txn->req.sl.rq.u_l + (txn->req.sol+txn->req.sl.rq.u) - path;
|
||||||
ret = acl_pass(ret);
|
if (rule->flags & REDIRECT_FLAG_DROP_QS) {
|
||||||
if (rule->cond->pol == ACL_COND_UNLESS)
|
int qs = 0;
|
||||||
ret = !ret;
|
while (qs < pathlen) {
|
||||||
|
if (path[qs] == '?') {
|
||||||
if (ret) {
|
pathlen = qs;
|
||||||
struct chunk rdr = { trash, 0 };
|
break;
|
||||||
const char *msg_fmt;
|
|
||||||
|
|
||||||
/* build redirect message */
|
|
||||||
switch(rule->code) {
|
|
||||||
case 303:
|
|
||||||
rdr.len = strlen(HTTP_303);
|
|
||||||
msg_fmt = HTTP_303;
|
|
||||||
break;
|
|
||||||
case 301:
|
|
||||||
rdr.len = strlen(HTTP_301);
|
|
||||||
msg_fmt = HTTP_301;
|
|
||||||
break;
|
|
||||||
case 302:
|
|
||||||
default:
|
|
||||||
rdr.len = strlen(HTTP_302);
|
|
||||||
msg_fmt = HTTP_302;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (unlikely(rdr.len > sizeof(trash)))
|
|
||||||
goto return_bad_req;
|
|
||||||
memcpy(rdr.str, msg_fmt, rdr.len);
|
|
||||||
|
|
||||||
switch(rule->type) {
|
|
||||||
case REDIRECT_TYPE_PREFIX: {
|
|
||||||
const char *path;
|
|
||||||
int pathlen;
|
|
||||||
|
|
||||||
path = http_get_path(txn);
|
|
||||||
/* build message using path */
|
|
||||||
if (path) {
|
|
||||||
pathlen = txn->req.sl.rq.u_l + (txn->req.sol+txn->req.sl.rq.u) - path;
|
|
||||||
if (rule->flags & REDIRECT_FLAG_DROP_QS) {
|
|
||||||
int qs = 0;
|
|
||||||
while (qs < pathlen) {
|
|
||||||
if (path[qs] == '?') {
|
|
||||||
pathlen = qs;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
qs++;
|
|
||||||
}
|
}
|
||||||
|
qs++;
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
path = "/";
|
|
||||||
pathlen = 1;
|
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
if (rdr.len + rule->rdr_len + pathlen > sizeof(trash) - 4)
|
path = "/";
|
||||||
goto return_bad_req;
|
pathlen = 1;
|
||||||
|
|
||||||
/* add prefix. Note that if prefix == "/", we don't want to
|
|
||||||
* add anything, otherwise it makes it hard for the user to
|
|
||||||
* configure a self-redirection.
|
|
||||||
*/
|
|
||||||
if (rule->rdr_len != 1 || *rule->rdr_str != '/') {
|
|
||||||
memcpy(rdr.str + rdr.len, rule->rdr_str, rule->rdr_len);
|
|
||||||
rdr.len += rule->rdr_len;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* add path */
|
|
||||||
memcpy(rdr.str + rdr.len, path, pathlen);
|
|
||||||
rdr.len += pathlen;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
case REDIRECT_TYPE_LOCATION:
|
|
||||||
default:
|
|
||||||
if (rdr.len + rule->rdr_len > sizeof(trash) - 4)
|
|
||||||
goto return_bad_req;
|
|
||||||
|
|
||||||
/* add location */
|
if (rdr.len + rule->rdr_len + pathlen > sizeof(trash) - 4)
|
||||||
|
goto return_bad_req;
|
||||||
|
|
||||||
|
/* add prefix. Note that if prefix == "/", we don't want to
|
||||||
|
* add anything, otherwise it makes it hard for the user to
|
||||||
|
* configure a self-redirection.
|
||||||
|
*/
|
||||||
|
if (rule->rdr_len != 1 || *rule->rdr_str != '/') {
|
||||||
memcpy(rdr.str + rdr.len, rule->rdr_str, rule->rdr_len);
|
memcpy(rdr.str + rdr.len, rule->rdr_str, rule->rdr_len);
|
||||||
rdr.len += rule->rdr_len;
|
rdr.len += rule->rdr_len;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rule->cookie_len) {
|
/* add path */
|
||||||
memcpy(rdr.str + rdr.len, "\r\nSet-Cookie: ", 14);
|
memcpy(rdr.str + rdr.len, path, pathlen);
|
||||||
rdr.len += 14;
|
rdr.len += pathlen;
|
||||||
memcpy(rdr.str + rdr.len, rule->cookie_str, rule->cookie_len);
|
break;
|
||||||
rdr.len += rule->cookie_len;
|
|
||||||
memcpy(rdr.str + rdr.len, "\r\n", 2);
|
|
||||||
rdr.len += 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* add end of headers */
|
|
||||||
memcpy(rdr.str + rdr.len, "\r\n\r\n", 4);
|
|
||||||
rdr.len += 4;
|
|
||||||
|
|
||||||
txn->status = rule->code;
|
|
||||||
/* let's log the request time */
|
|
||||||
s->logs.tv_request = now;
|
|
||||||
stream_int_retnclose(req->prod, &rdr);
|
|
||||||
goto return_prx_cond;
|
|
||||||
}
|
}
|
||||||
}
|
case REDIRECT_TYPE_LOCATION:
|
||||||
|
default:
|
||||||
|
if (rdr.len + rule->rdr_len > sizeof(trash) - 4)
|
||||||
|
goto return_bad_req;
|
||||||
|
|
||||||
/* now check whether we have some switching rules for this request */
|
/* add location */
|
||||||
if (!(s->flags & SN_BE_ASSIGNED)) {
|
memcpy(rdr.str + rdr.len, rule->rdr_str, rule->rdr_len);
|
||||||
struct switching_rule *rule;
|
rdr.len += rule->rdr_len;
|
||||||
|
break;
|
||||||
list_for_each_entry(rule, &cur_proxy->switching_rules, list) {
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
ret = acl_exec_cond(rule->cond, cur_proxy, s, txn, ACL_DIR_REQ);
|
|
||||||
|
|
||||||
ret = acl_pass(ret);
|
|
||||||
if (rule->cond->pol == ACL_COND_UNLESS)
|
|
||||||
ret = !ret;
|
|
||||||
|
|
||||||
if (ret) {
|
|
||||||
s->be = rule->be.backend;
|
|
||||||
s->be->beconn++;
|
|
||||||
if (s->be->beconn > s->be->beconn_max)
|
|
||||||
s->be->beconn_max = s->be->beconn;
|
|
||||||
proxy_inc_be_ctr(s->be);
|
|
||||||
|
|
||||||
/* assign new parameters to the session from the new backend */
|
|
||||||
s->rep->rto = s->req->wto = s->be->timeout.server;
|
|
||||||
s->req->cto = s->be->timeout.connect;
|
|
||||||
s->conn_retries = s->be->conn_retries;
|
|
||||||
if (s->be->options2 & PR_O2_RSPBUG_OK)
|
|
||||||
s->txn.rsp.err_pos = -1; /* let buggy responses pass */
|
|
||||||
s->flags |= SN_BE_ASSIGNED;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (rule->cookie_len) {
|
||||||
|
memcpy(rdr.str + rdr.len, "\r\nSet-Cookie: ", 14);
|
||||||
|
rdr.len += 14;
|
||||||
|
memcpy(rdr.str + rdr.len, rule->cookie_str, rule->cookie_len);
|
||||||
|
rdr.len += rule->cookie_len;
|
||||||
|
memcpy(rdr.str + rdr.len, "\r\n", 2);
|
||||||
|
rdr.len += 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* add end of headers */
|
||||||
|
memcpy(rdr.str + rdr.len, "\r\n\r\n", 4);
|
||||||
|
rdr.len += 4;
|
||||||
|
|
||||||
|
txn->status = rule->code;
|
||||||
|
/* let's log the request time */
|
||||||
|
s->logs.tv_request = now;
|
||||||
|
stream_int_retnclose(req->prod, &rdr);
|
||||||
|
goto return_prx_cond;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(s->flags & SN_BE_ASSIGNED) && cur_proxy->defbe.be) {
|
|
||||||
/* No backend was set, but there was a default
|
|
||||||
* backend set in the frontend, so we use it and
|
|
||||||
* loop again.
|
|
||||||
*/
|
|
||||||
s->be = cur_proxy->defbe.be;
|
|
||||||
s->be->beconn++;
|
|
||||||
if (s->be->beconn > s->be->beconn_max)
|
|
||||||
s->be->beconn_max = s->be->beconn;
|
|
||||||
proxy_inc_be_ctr(s->be);
|
|
||||||
|
|
||||||
/* assign new parameters to the session from the new backend */
|
|
||||||
s->rep->rto = s->req->wto = s->be->timeout.server;
|
|
||||||
s->req->cto = s->be->timeout.connect;
|
|
||||||
s->conn_retries = s->be->conn_retries;
|
|
||||||
if (s->be->options2 & PR_O2_RSPBUG_OK)
|
|
||||||
s->txn.rsp.err_pos = -1; /* let buggy responses pass */
|
|
||||||
s->flags |= SN_BE_ASSIGNED;
|
|
||||||
}
|
|
||||||
} while (s->be != cur_proxy); /* we loop only if s->be has changed */
|
|
||||||
|
|
||||||
if (!(s->flags & SN_BE_ASSIGNED)) {
|
|
||||||
/* To ensure correct connection accounting on
|
|
||||||
* the backend, we count the connection for the
|
|
||||||
* one managing the queue.
|
|
||||||
*/
|
|
||||||
s->be->beconn++;
|
|
||||||
if (s->be->beconn > s->be->beconn_max)
|
|
||||||
s->be->beconn_max = s->be->beconn;
|
|
||||||
proxy_inc_be_ctr(s->be);
|
|
||||||
s->flags |= SN_BE_ASSIGNED;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* that's OK for us now, let's move on to next analysers */
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
return_bad_req:
|
||||||
|
/* We centralize bad requests processing here */
|
||||||
|
if (unlikely(msg->msg_state == HTTP_MSG_ERROR) || msg->err_pos >= 0) {
|
||||||
|
/* we detected a parsing error. We want to archive this request
|
||||||
|
* in the dedicated proxy area for later troubleshooting.
|
||||||
|
*/
|
||||||
|
http_capture_bad_message(&s->fe->invalid_req, s, req, msg, s->fe);
|
||||||
|
}
|
||||||
|
|
||||||
|
txn->req.msg_state = HTTP_MSG_ERROR;
|
||||||
|
txn->status = 400;
|
||||||
|
stream_int_retnclose(req->prod, error_message(s, HTTP_ERR_400));
|
||||||
|
s->fe->failed_req++;
|
||||||
|
|
||||||
|
return_prx_cond:
|
||||||
|
if (!(s->flags & SN_ERR_MASK))
|
||||||
|
s->flags |= SN_ERR_PRXCOND;
|
||||||
|
if (!(s->flags & SN_FINST_MASK))
|
||||||
|
s->flags |= SN_FINST_R;
|
||||||
|
|
||||||
|
req->analysers = 0;
|
||||||
|
req->analyse_exp = TICK_ETERNITY;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This function performs all the processing enabled for the current request.
|
||||||
|
* It returns 1 if the processing can continue on next analysers, or zero if it
|
||||||
|
* needs more data, encounters an error, or wants to immediately abort the
|
||||||
|
* request. It relies on buffers flags, and updates s->req->analysers.
|
||||||
|
*/
|
||||||
|
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;
|
||||||
|
|
||||||
|
req->analysers &= ~an_bit;
|
||||||
|
req->analyse_exp = TICK_ETERNITY;
|
||||||
|
|
||||||
|
DPRINTF(stderr,"[%u] %s: session=%p b=%p, exp(r,w)=%u,%u bf=%08x bl=%d analysers=%02x\n",
|
||||||
|
now_ms, __FUNCTION__,
|
||||||
|
s,
|
||||||
|
req,
|
||||||
|
req->rex, req->wex,
|
||||||
|
req->flags,
|
||||||
|
req->l,
|
||||||
|
req->analysers);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Right now, we know that we have processed the entire headers
|
* Right now, we know that we have processed the entire headers
|
||||||
* and that unwanted requests have been filtered out. We can do
|
* and that unwanted requests have been filtered out. We can do
|
||||||
@ -2436,7 +2378,6 @@ int http_process_request(struct session *s, struct buffer *req, int an_bit)
|
|||||||
stream_int_retnclose(req->prod, error_message(s, HTTP_ERR_400));
|
stream_int_retnclose(req->prod, error_message(s, HTTP_ERR_400));
|
||||||
s->fe->failed_req++;
|
s->fe->failed_req++;
|
||||||
|
|
||||||
return_prx_cond:
|
|
||||||
if (!(s->flags & SN_ERR_MASK))
|
if (!(s->flags & SN_ERR_MASK))
|
||||||
s->flags |= SN_ERR_PRXCOND;
|
s->flags |= SN_ERR_PRXCOND;
|
||||||
if (!(s->flags & SN_FINST_MASK))
|
if (!(s->flags & SN_FINST_MASK))
|
||||||
@ -3142,18 +3083,7 @@ int apply_filter_to_req_headers(struct session *t, struct buffer *req, struct hd
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
/* Swithing Proxy */
|
/* Swithing Proxy */
|
||||||
t->be = (struct proxy *) exp->replace;
|
session_set_backend(t, (struct proxy *)exp->replace);
|
||||||
|
|
||||||
/* right now, the backend switch is not overly complicated
|
|
||||||
* because we have associated req_cap and rsp_cap to the
|
|
||||||
* frontend, and the beconn will be updated later.
|
|
||||||
*/
|
|
||||||
|
|
||||||
t->rep->rto = t->req->wto = t->be->timeout.server;
|
|
||||||
t->req->cto = t->be->timeout.connect;
|
|
||||||
t->conn_retries = t->be->conn_retries;
|
|
||||||
if (t->be->options2 & PR_O2_RSPBUG_OK)
|
|
||||||
t->txn.rsp.err_pos = -1; /* let buggy responses pass */
|
|
||||||
last_hdr = 1;
|
last_hdr = 1;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -3265,18 +3195,7 @@ int apply_filter_to_req_line(struct session *t, struct buffer *req, struct hdr_e
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
/* Swithing Proxy */
|
/* Swithing Proxy */
|
||||||
t->be = (struct proxy *) exp->replace;
|
session_set_backend(t, (struct proxy *)exp->replace);
|
||||||
|
|
||||||
/* right now, the backend switch is not too much complicated
|
|
||||||
* because we have associated req_cap and rsp_cap to the
|
|
||||||
* frontend, and the beconn will be updated later.
|
|
||||||
*/
|
|
||||||
|
|
||||||
t->rep->rto = t->req->wto = t->be->timeout.server;
|
|
||||||
t->req->cto = t->be->timeout.connect;
|
|
||||||
t->conn_retries = t->be->conn_retries;
|
|
||||||
if (t->be->options2 & PR_O2_RSPBUG_OK)
|
|
||||||
t->txn.rsp.err_pos = -1; /* let buggy responses pass */
|
|
||||||
done = 1;
|
done = 1;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
24
src/proxy.c
24
src/proxy.c
@ -631,6 +631,30 @@ void listen_proxies(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Set current session's backend to <be>. Nothing is done if the
|
||||||
|
* session already had a backend assigned, which is indicated by
|
||||||
|
* s->flags & SN_BE_ASSIGNED.
|
||||||
|
* All flags, stats and counters which need be updated are updated.
|
||||||
|
*/
|
||||||
|
void session_set_backend(struct session *s, struct proxy *be)
|
||||||
|
{
|
||||||
|
if (s->flags & SN_BE_ASSIGNED)
|
||||||
|
return;
|
||||||
|
s->be = be;
|
||||||
|
be->beconn++;
|
||||||
|
if (be->beconn > be->beconn_max)
|
||||||
|
be->beconn_max = be->beconn;
|
||||||
|
proxy_inc_be_ctr(be);
|
||||||
|
|
||||||
|
/* assign new parameters to the session from the new backend */
|
||||||
|
s->rep->rto = s->req->wto = be->timeout.server;
|
||||||
|
s->req->cto = be->timeout.connect;
|
||||||
|
s->conn_retries = be->conn_retries;
|
||||||
|
if (be->options2 & PR_O2_RSPBUG_OK)
|
||||||
|
s->txn.rsp.err_pos = -1; /* let buggy responses pass */
|
||||||
|
s->flags |= SN_BE_ASSIGNED;
|
||||||
|
}
|
||||||
|
|
||||||
static struct cfg_kw_list cfg_kws = {{ },{
|
static struct cfg_kw_list cfg_kws = {{ },{
|
||||||
{ CFG_LISTEN, "timeout", proxy_parse_timeout },
|
{ CFG_LISTEN, "timeout", proxy_parse_timeout },
|
||||||
{ CFG_LISTEN, "clitimeout", proxy_parse_timeout },
|
{ CFG_LISTEN, "clitimeout", proxy_parse_timeout },
|
||||||
|
@ -19,6 +19,7 @@
|
|||||||
#include <types/capture.h>
|
#include <types/capture.h>
|
||||||
#include <types/global.h>
|
#include <types/global.h>
|
||||||
|
|
||||||
|
#include <proto/acl.h>
|
||||||
#include <proto/backend.h>
|
#include <proto/backend.h>
|
||||||
#include <proto/buffers.h>
|
#include <proto/buffers.h>
|
||||||
#include <proto/hdr_idx.h>
|
#include <proto/hdr_idx.h>
|
||||||
@ -27,6 +28,7 @@
|
|||||||
#include <proto/pipe.h>
|
#include <proto/pipe.h>
|
||||||
#include <proto/proto_http.h>
|
#include <proto/proto_http.h>
|
||||||
#include <proto/proto_tcp.h>
|
#include <proto/proto_tcp.h>
|
||||||
|
#include <proto/proxy.h>
|
||||||
#include <proto/queue.h>
|
#include <proto/queue.h>
|
||||||
#include <proto/server.h>
|
#include <proto/server.h>
|
||||||
#include <proto/stream_interface.h>
|
#include <proto/stream_interface.h>
|
||||||
@ -552,6 +554,59 @@ static void sess_prepare_conn_req(struct session *s, struct stream_interface *si
|
|||||||
si->state = SI_ST_ASS;
|
si->state = SI_ST_ASS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* This stream analyser checks the switching rules and changes the backend
|
||||||
|
* if appropriate. The default_backend rule is also considered.
|
||||||
|
* It returns 1 if the processing can continue on next analysers, or zero if it
|
||||||
|
* either needs more data or wants to immediately abort the request.
|
||||||
|
*/
|
||||||
|
int process_switching_rules(struct session *s, struct buffer *req, int an_bit)
|
||||||
|
{
|
||||||
|
req->analysers &= ~an_bit;
|
||||||
|
req->analyse_exp = TICK_ETERNITY;
|
||||||
|
|
||||||
|
DPRINTF(stderr,"[%u] %s: session=%p b=%p, exp(r,w)=%u,%u bf=%08x bl=%d analysers=%02x\n",
|
||||||
|
now_ms, __FUNCTION__,
|
||||||
|
s,
|
||||||
|
req,
|
||||||
|
req->rex, req->wex,
|
||||||
|
req->flags,
|
||||||
|
req->l,
|
||||||
|
req->analysers);
|
||||||
|
|
||||||
|
/* now check whether we have some switching rules for this request */
|
||||||
|
if (!(s->flags & SN_BE_ASSIGNED)) {
|
||||||
|
struct switching_rule *rule;
|
||||||
|
|
||||||
|
list_for_each_entry(rule, &s->fe->switching_rules, list) {
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = acl_exec_cond(rule->cond, s->fe, s, &s->txn, ACL_DIR_REQ);
|
||||||
|
ret = acl_pass(ret);
|
||||||
|
if (rule->cond->pol == ACL_COND_UNLESS)
|
||||||
|
ret = !ret;
|
||||||
|
|
||||||
|
if (ret) {
|
||||||
|
session_set_backend(s, rule->be.backend);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* To ensure correct connection accounting on the backend, we
|
||||||
|
* have to assign one if it was not set (eg: a listen). This
|
||||||
|
* measure also takes care of correctly setting the default
|
||||||
|
* backend if any.
|
||||||
|
*/
|
||||||
|
if (!(s->flags & SN_BE_ASSIGNED))
|
||||||
|
session_set_backend(s, s->fe->defbe.be ? s->fe->defbe.be : s->be);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* we don't want to run the HTTP filters again if the backend has not changed */
|
||||||
|
if (s->fe == s->be)
|
||||||
|
s->req->analysers &= ~AN_REQ_HTTP_PROCESS_BE;
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
/* Processes the client, server, request and response jobs of a session task,
|
/* Processes the client, server, request and response jobs of a session task,
|
||||||
* then puts it back to the wait queue in a clean state, or cleans up its
|
* then puts it back to the wait queue in a clean state, or cleans up its
|
||||||
* resources if it must be deleted. Returns in <next> the date the task wants
|
* resources if it must be deleted. Returns in <next> the date the task wants
|
||||||
@ -736,9 +791,27 @@ resync_stream_interface:
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (s->req->analysers & AN_REQ_HTTP_HDR) {
|
if (s->req->analysers & AN_REQ_HTTP_PROCESS_FE) {
|
||||||
last_ana |= AN_REQ_HTTP_HDR;
|
last_ana |= AN_REQ_HTTP_PROCESS_FE;
|
||||||
if (!http_process_request(s, s->req, AN_REQ_HTTP_HDR))
|
if (!http_process_req_common(s, s->req, AN_REQ_HTTP_PROCESS_FE, s->fe))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (s->req->analysers & AN_REQ_SWITCHING_RULES) {
|
||||||
|
last_ana |= AN_REQ_SWITCHING_RULES;
|
||||||
|
if (!process_switching_rules(s, s->req, AN_REQ_SWITCHING_RULES))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (s->req->analysers & AN_REQ_HTTP_PROCESS_BE) {
|
||||||
|
last_ana |= AN_REQ_HTTP_PROCESS_BE;
|
||||||
|
if (!http_process_req_common(s, s->req, AN_REQ_HTTP_PROCESS_BE, s->be))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (s->req->analysers & AN_REQ_HTTP_INNER) {
|
||||||
|
last_ana |= AN_REQ_HTTP_INNER;
|
||||||
|
if (!http_process_request(s, s->req, AN_REQ_HTTP_INNER))
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user