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 6c84f35..54169a1 100644
--- a/include/proto/proto_http.h
+++ b/include/proto/proto_http.h
@@ -53,6 +53,8 @@
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_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 bd4221a..3481160 100644
--- a/src/proto_http.c
+++ b/src/proto_http.c
@@ -791,7 +791,7 @@
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 4eb22bc..8af28e6 100644
--- a/src/proto_htx.c
+++ b/src/proto_htx.c
@@ -16,6 +16,7 @@
#include <common/uri_auth.h>
#include <types/cache.h>
+#include <types/capture.h>
#include <proto/acl.h>
#include <proto/channel.h>
@@ -23,6 +24,8 @@
#include <proto/connection.h>
#include <proto/filters.h>
#include <proto/hdr_idx.h>
+#include <proto/http_htx.h>
+#include <proto/htx.h>
#include <proto/log.h>
#include <proto/proto_http.h>
#include <proto/proxy.h>
@@ -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 @@
* 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 @@
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 @@
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 <rule>. The function
@@ -3285,6 +3293,187 @@
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 <htx> according to header list <cap_hdr>, and
+ * fill the <cap> 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 <str> and
+ * return the written lenght. The line can be truncated if it exceeds <len>.
+ */
+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)
{