From: Christopher Faulet Date: Mon, 22 Oct 2018 07:29:56 +0000 (+0200) Subject: MINOR: proto_htx: Add some functions to handle HTX messages X-Git-Tag: v1.9-dev7~67 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=0f226958b7046685af569a91dc01557a5a59c049;p=thirdparty%2Fhaproxy.git MINOR: proto_htx: Add some functions to handle HTX messages More functions will come, but it is the minimum to switch HTX analyzers on the HTX internal representation. --- diff --git a/include/proto/proto_http.h b/include/proto/proto_http.h index 6c84f35bc0..54169a1117 100644 --- a/include/proto/proto_http.h +++ b/include/proto/proto_http.h @@ -53,6 +53,8 @@ void http_txn_reset_req(struct http_txn *txn); void http_txn_reset_res(struct http_txn *txn); /* Export HTX analyzers and helpers */ +// FIXME: Rename all these functions http_* once legacy code will be removed + int htx_wait_for_request(struct stream *s, struct channel *req, int an_bit); int htx_process_req_common(struct stream *s, struct channel *req, int an_bit, struct proxy *px); int htx_process_request(struct stream *s, struct channel *req, int an_bit); @@ -63,8 +65,11 @@ int htx_wait_for_response(struct stream *s, struct channel *rep, int an_bit); int htx_process_res_common(struct stream *s, struct channel *rep, int an_bit, struct proxy *px); int htx_request_forward_body(struct stream *s, struct channel *req, int an_bit); int htx_response_forward_body(struct stream *s, struct channel *res, int an_bit); -void htx_adjust_conn_mode(struct stream *s, struct http_txn *txn, struct http_msg *msg); +void htx_adjust_conn_mode(struct stream *s, struct http_txn *txn); int htx_apply_redirect_rule(struct redirect_rule *rule, struct stream *s, struct http_txn *txn); +void htx_server_error(struct stream *s, struct stream_interface *si, int err, int finst, const struct buffer *msg); +void htx_reply_and_close(struct stream *s, short status, struct buffer *msg); + void debug_hdr(const char *dir, struct stream *s, const char *start, const char *end); int apply_filter_to_req_headers(struct stream *s, struct channel *req, struct hdr_exp *exp); diff --git a/src/proto_http.c b/src/proto_http.c index bd4221abe3..348116003d 100644 --- a/src/proto_http.c +++ b/src/proto_http.c @@ -791,7 +791,7 @@ void http_adjust_conn_mode(struct stream *s, struct http_txn *txn, struct http_m int tmp = TX_CON_WANT_KAL; if (IS_HTX_STRM(s)) - return htx_adjust_conn_mode(s, txn, msg); + return htx_adjust_conn_mode(s, txn); if ((fe->options & PR_O_HTTP_MODE) == PR_O_HTTP_TUN || (s->be->options & PR_O_HTTP_MODE) == PR_O_HTTP_TUN) diff --git a/src/proto_htx.c b/src/proto_htx.c index 4eb22bc74c..8af28e6069 100644 --- a/src/proto_htx.c +++ b/src/proto_htx.c @@ -16,6 +16,7 @@ #include #include +#include #include #include @@ -23,6 +24,8 @@ #include #include #include +#include +#include #include #include #include @@ -34,6 +37,11 @@ static void htx_end_request(struct stream *s); static void htx_end_response(struct stream *s); +static void htx_capture_headers(struct htx *htx, char **cap, struct cap_hdr *cap_hdr); +static size_t htx_fmt_req_line(const union h1_sl sl, char *str, size_t len); +static void htx_debug_stline(const char *dir, struct stream *s, const union h1_sl sl); +static void htx_debug_hdr(const char *dir, struct stream *s, const struct ist n, const struct ist v); + /* This stream analyser waits for a complete HTTP request. 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 (eg: timeout, error, ...). It @@ -612,7 +620,7 @@ int htx_wait_for_request(struct stream *s, struct channel *req, int an_bit) * time. */ if ((sess->fe->options & PR_O_HTTP_MODE) != (s->be->options & PR_O_HTTP_MODE)) - htx_adjust_conn_mode(s, txn, msg); + htx_adjust_conn_mode(s, txn); /* we may have to wait for the request's body */ if ((s->be->options & PR_O_WREQ_BODY) && @@ -2757,7 +2765,7 @@ int htx_response_forward_body(struct stream *s, struct channel *res, int an_bit) return 0; } -void htx_adjust_conn_mode(struct stream *s, struct http_txn *txn, struct http_msg *msg) +void htx_adjust_conn_mode(struct stream *s, struct http_txn *txn) { struct proxy *fe = strm_fe(s); int tmp = TX_CON_WANT_CLO; @@ -2766,7 +2774,7 @@ void htx_adjust_conn_mode(struct stream *s, struct http_txn *txn, struct http_ms tmp = TX_CON_WANT_TUN; if ((txn->flags & TX_CON_WANT_MSK) < tmp) - txn->flags = (txn->flags & ~TX_CON_WANT_MSK) | TX_CON_WANT_CLO; + txn->flags = (txn->flags & ~TX_CON_WANT_MSK) | tmp; } /* Perform an HTTP redirect based on the information in . The function @@ -3285,6 +3293,187 @@ static void htx_end_response(struct stream *s) channel_auto_read(chn); } +void htx_server_error(struct stream *s, struct stream_interface *si, int err, + int finst, const struct buffer *msg) +{ + channel_auto_read(si_oc(si)); + channel_abort(si_oc(si)); + channel_auto_close(si_oc(si)); + channel_erase(si_oc(si)); + channel_auto_close(si_ic(si)); + channel_auto_read(si_ic(si)); + if (msg) { + struct channel *chn = si_ic(si); + struct htx *htx; + + htx = htx_from_buf(&chn->buf); + htx_add_oob(htx, ist2(msg->area, msg->data)); + //FLT_STRM_CB(s, flt_htx_reply(s, s->txn->status, htx)); + b_set_data(&chn->buf, b_size(&chn->buf)); + c_adv(chn, htx->data); + chn->total += htx->data; + } + if (!(s->flags & SF_ERR_MASK)) + s->flags |= err; + if (!(s->flags & SF_FINST_MASK)) + s->flags |= finst; +} + +void htx_reply_and_close(struct stream *s, short status, struct buffer *msg) +{ + channel_auto_read(&s->req); + channel_abort(&s->req); + channel_auto_close(&s->req); + channel_erase(&s->req); + channel_truncate(&s->res); + + s->txn->flags &= ~TX_WAIT_NEXT_RQ; + if (msg) { + struct channel *chn = &s->res; + struct htx *htx; + + htx = htx_from_buf(&chn->buf); + htx_add_oob(htx, ist2(msg->area, msg->data)); + //FLT_STRM_CB(s, flt_htx_reply(s, s->txn->status, htx)); + b_set_data(&chn->buf, b_size(&chn->buf)); + c_adv(chn, htx->data); + chn->total += htx->data; + } + + s->res.wex = tick_add_ifset(now_ms, s->res.wto); + channel_auto_read(&s->res); + channel_auto_close(&s->res); + channel_shutr_now(&s->res); +} + +/* + * Capture headers from message according to header list , and + * fill the pointers appropriately. + */ +static void htx_capture_headers(struct htx *htx, char **cap, struct cap_hdr *cap_hdr) +{ + struct cap_hdr *h; + int32_t pos; + + for (pos = htx_get_head(htx); pos != -1; pos = htx_get_next(htx, pos)) { + struct htx_blk *blk = htx_get_blk(htx, pos); + enum htx_blk_type type = htx_get_blk_type(blk); + struct ist n, v; + + if (type == HTX_BLK_EOH) + break; + if (type != HTX_BLK_HDR) + continue; + + n = htx_get_blk_name(htx, blk); + + for (h = cap_hdr; h; h = h->next) { + if (h->namelen && (h->namelen == n.len) && + (strncasecmp(n.ptr, h->name, h->namelen) == 0)) { + if (cap[h->index] == NULL) + cap[h->index] = + pool_alloc(h->pool); + + if (cap[h->index] == NULL) { + ha_alert("HTTP capture : out of memory.\n"); + break; + } + + v = htx_get_blk_value(htx, blk); + if (v.len > h->len) + v.len = h->len; + + memcpy(cap[h->index], v.ptr, v.len); + cap[h->index][v.len]=0; + } + } + } +} + + +/* Formats the start line of the request (without CRLF) and puts it in and + * return the written lenght. The line can be truncated if it exceeds . + */ +static size_t htx_fmt_req_line(const union h1_sl sl, char *str, size_t len) +{ + struct ist dst = ist2(str, 0); + + if (istcat(&dst, sl.rq.m, len) == -1) + goto end; + if (dst.len + 1 > len) + goto end; + dst.ptr[dst.len++] = ' '; + + if (istcat(&dst, sl.rq.u, len) == -1) + goto end; + if (dst.len + 1 > len) + goto end; + dst.ptr[dst.len++] = ' '; + + istcat(&dst, sl.rq.v, len); + end: + return dst.len; +} + +/* + * Print a debug line with a start line. + */ +static void htx_debug_stline(const char *dir, struct stream *s, const union h1_sl sl) +{ + struct session *sess = strm_sess(s); + int max; + + chunk_printf(&trash, "%08x:%s.%s[%04x:%04x]: ", s->uniq_id, s->be->id, + dir, + objt_conn(sess->origin) ? (unsigned short)objt_conn(sess->origin)->handle.fd : -1, + objt_cs(s->si[1].end) ? (unsigned short)objt_cs(s->si[1].end)->conn->handle.fd : -1); + + max = sl.rq.m.len; + UBOUND(max, trash.size - trash.data - 3); + chunk_memcat(&trash, sl.rq.m.ptr, max); + trash.area[trash.data++] = ' '; + + max = sl.rq.u.len; + UBOUND(max, trash.size - trash.data - 2); + chunk_memcat(&trash, sl.rq.u.ptr, max); + trash.area[trash.data++] = ' '; + + max = sl.rq.v.len; + UBOUND(max, trash.size - trash.data - 1); + chunk_memcat(&trash, sl.rq.v.ptr, max); + trash.area[trash.data++] = '\n'; + + shut_your_big_mouth_gcc(write(1, trash.area, trash.data)); +} + +/* + * Print a debug line with a header. + */ +static void htx_debug_hdr(const char *dir, struct stream *s, const struct ist n, const struct ist v) +{ + struct session *sess = strm_sess(s); + int max; + + chunk_printf(&trash, "%08x:%s.%s[%04x:%04x]: ", s->uniq_id, s->be->id, + dir, + objt_conn(sess->origin) ? (unsigned short)objt_conn(sess->origin)->handle.fd : -1, + objt_cs(s->si[1].end) ? (unsigned short)objt_cs(s->si[1].end)->conn->handle.fd : -1); + + max = n.len; + UBOUND(max, trash.size - trash.data - 3); + chunk_memcat(&trash, n.ptr, max); + trash.area[trash.data++] = ':'; + trash.area[trash.data++] = ' '; + + max = v.len; + UBOUND(max, trash.size - trash.data - 1); + chunk_memcat(&trash, v.ptr, max); + trash.area[trash.data++] = '\n'; + + shut_your_big_mouth_gcc(write(1, trash.area, trash.data)); +} + + __attribute__((constructor)) static void __htx_protocol_init(void) {