MINOR: http_fetch: Add smp_prefetch_htx
It does the same than smp_prefetch_http but for HTX messages. It can be called from an HTTP proxy or a TCP proxy. For HTTP proxies, the parsing is handled by the mux, so it does nothing but wait. For TCP proxies, it tries to parse an HTTP message and to convert it in a temporary HTX message. Sample fetches will use this temporary variable to do their job.
This commit is contained in:
parent
fec7bd16de
commit
ef453ed9b0
|
@ -39,6 +39,9 @@
|
|||
int smp_prefetch_http(struct proxy *px, struct stream *s, unsigned int opt,
|
||||
const struct arg *args, struct sample *smp, int req_vol);
|
||||
|
||||
struct htx;
|
||||
struct htx *smp_prefetch_htx(struct sample *smp, const struct arg *args);
|
||||
|
||||
int val_hdr(struct arg *arg, char **err_msg);
|
||||
|
||||
|
||||
|
|
127
src/http_fetch.c
127
src/http_fetch.c
|
@ -31,6 +31,8 @@
|
|||
#include <proto/arg.h>
|
||||
#include <proto/auth.h>
|
||||
#include <proto/http_fetch.h>
|
||||
#include <proto/http_htx.h>
|
||||
#include <proto/htx.h>
|
||||
#include <proto/log.h>
|
||||
#include <proto/obj_type.h>
|
||||
#include <proto/proto_http.h>
|
||||
|
@ -40,6 +42,8 @@
|
|||
|
||||
/* this struct is used between calls to smp_fetch_hdr() or smp_fetch_cookie() */
|
||||
static THREAD_LOCAL struct hdr_ctx static_hdr_ctx;
|
||||
static THREAD_LOCAL struct http_hdr_ctx static_http_hdr_ctx;
|
||||
|
||||
|
||||
/*
|
||||
* Returns the data from Authorization header. Function may be called more
|
||||
|
@ -122,6 +126,129 @@ static int get_http_auth(struct stream *s)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* This function ensures that the prerequisites for an L7 fetch are ready,
|
||||
* which means that a request or response is ready. If some data is missing,
|
||||
* a parsing attempt is made. This is useful in TCP-based ACLs which are able
|
||||
* to extract data from L7.
|
||||
*
|
||||
* The function returns :
|
||||
* NULL with SMP_F_MAY_CHANGE in the sample flags if some data is missing to
|
||||
* decide whether or not an HTTP message is present ;
|
||||
* NULL if the requested data cannot be fetched or if it is certain that
|
||||
* we'll never have any HTTP message there ;
|
||||
* The HTX message if ready
|
||||
*/
|
||||
struct htx *smp_prefetch_htx(struct sample *smp, const struct arg *args)
|
||||
{
|
||||
struct proxy *px = smp->px;
|
||||
struct stream *s = smp->strm;
|
||||
unsigned int opt = smp->opt;
|
||||
struct http_txn *txn = NULL;
|
||||
struct htx *htx = NULL;
|
||||
|
||||
/* Note: it is possible that <s> is NULL when called before stream
|
||||
* initialization (eg: tcp-request connection), so this function is the
|
||||
* one responsible for guarding against this case for all HTTP users.
|
||||
*/
|
||||
if (!s)
|
||||
return NULL;
|
||||
|
||||
if (!s->txn) {
|
||||
if (unlikely(!http_alloc_txn(s)))
|
||||
return NULL; /* not enough memory */
|
||||
http_init_txn(s);
|
||||
txn = s->txn;
|
||||
}
|
||||
|
||||
if (px->mode == PR_MODE_HTTP) {
|
||||
if ((opt & SMP_OPT_DIR) == SMP_OPT_DIR_REQ) {
|
||||
union h1_sl sl;
|
||||
|
||||
htx = htx_from_buf(&s->req.buf);
|
||||
if (htx_is_empty(htx) || htx_get_tail_type(htx) < HTX_BLK_EOH) {
|
||||
/* Parsing is done by the mux, just wait */
|
||||
smp->flags |= SMP_F_MAY_CHANGE;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* OK we just got a valid HTTP request. We have some
|
||||
* minor preparation to perform so that further checks
|
||||
* can rely on HTTP tests.
|
||||
*/
|
||||
if (txn) {
|
||||
sl = http_find_stline(htx);
|
||||
txn->meth = sl.rq.meth;
|
||||
if (txn->meth == HTTP_METH_GET || txn->meth == HTTP_METH_HEAD)
|
||||
s->flags |= SF_REDIRECTABLE;
|
||||
}
|
||||
|
||||
/* otherwise everything's ready for the request */
|
||||
}
|
||||
else {
|
||||
htx = htx_from_buf(&s->res.buf);
|
||||
if (htx_is_empty(htx) || htx_get_tail_type(htx) < HTX_BLK_EOH) {
|
||||
/* Parsing is done by the mux, just wait */
|
||||
smp->flags |= SMP_F_MAY_CHANGE;
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
else { /* PR_MODE_TCP */
|
||||
if ((opt & SMP_OPT_DIR) == SMP_OPT_DIR_REQ) {
|
||||
struct buffer *buf;
|
||||
struct h1m h1m;
|
||||
struct http_hdr hdrs[MAX_HTTP_HDR];
|
||||
union h1_sl sl;
|
||||
int ret;
|
||||
|
||||
buf = &s->req.buf;
|
||||
if (b_head(buf) + b_data(buf) > b_wrap(buf))
|
||||
b_slow_realign(buf, trash.area, 0);
|
||||
|
||||
h1m_init_req(&h1m);
|
||||
ret = h1_headers_to_hdr_list(b_head(buf), b_stop(buf),
|
||||
hdrs, sizeof(hdrs)/sizeof(hdrs[0]), &h1m, &sl);
|
||||
if (ret <= 0) {
|
||||
/* Invalid or too big*/
|
||||
if (ret < 0 || channel_full(&s->req, global.tune.maxrewrite))
|
||||
return NULL;
|
||||
|
||||
/* wait for a full request */
|
||||
smp->flags |= SMP_F_MAY_CHANGE;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* OK we just got a valid HTTP request. We have to
|
||||
* convert it into an HTX message.
|
||||
*/
|
||||
if (unlikely(sl.rq.v.len == 0)) {
|
||||
/* try to convert HTTP/0.9 requests to HTTP/1.0 */
|
||||
if (sl.rq.meth != HTTP_METH_GET || !sl.rq.u.len)
|
||||
return NULL;
|
||||
sl.rq.v = ist("HTTP/1.0");
|
||||
}
|
||||
htx = htx_from_buf(get_trash_chunk());
|
||||
if (!htx_add_reqline(htx, sl) || !htx_add_all_headers(htx, hdrs))
|
||||
return NULL;
|
||||
|
||||
if (txn) {
|
||||
txn->meth = sl.rq.meth;
|
||||
if (txn->meth == HTTP_METH_GET || txn->meth == HTTP_METH_HEAD)
|
||||
s->flags |= SF_REDIRECTABLE;
|
||||
}
|
||||
/* Ok, now everything's ready for the request */
|
||||
}
|
||||
else {
|
||||
/* Impossible, no HTTP fetch on tcp-response */
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* everything's OK */
|
||||
smp->data.u.sint = 1;
|
||||
return htx;
|
||||
}
|
||||
|
||||
/* This function ensures that the prerequisites for an L7 fetch are ready,
|
||||
* which means that a request or response is ready. If some data is missing,
|
||||
* a parsing attempt is made. This is useful in TCP-based ACLs which are able
|
||||
|
|
Loading…
Reference in New Issue