From 10e5794882547d0a604b5a8dcc0aed1a220fd40e Mon Sep 17 00:00:00 2001 From: Artyom Belov Date: Thu, 21 Apr 2022 13:48:05 +0300 Subject: [PATCH 1/3] Custom HTTP redirects --- fw/http.c | 287 +++++++++++++++++++++++++++++++++++++++++++- fw/http_match.h | 2 + fw/http_tbl.c | 57 +++++++-- fw/http_tbl.h | 21 +++- fw/t/unit/helpers.c | 2 +- 5 files changed, 352 insertions(+), 17 deletions(-) diff --git a/fw/http.c b/fw/http.c index 0865c1151c..0295cc1984 100644 --- a/fw/http.c +++ b/fw/http.c @@ -132,8 +132,12 @@ static struct { #define S_HTTPS "https://" #define S_200 "HTTP/1.1 200 OK" +#define S_301 "HTTP/1.1 301 Moved Permanently" #define S_302 "HTTP/1.1 302 Found" +#define S_303 "HTTP/1.1 303 See Also" #define S_304 "HTTP/1.1 304 Not Modified" +#define S_307 "HTTP/1.1 307 Temporary Redirect" +#define S_308 "HTTP/1.1 308 Permanent Redirect" #define S_400 "HTTP/1.1 400 Bad Request" #define S_403 "HTTP/1.1 403 Forbidden" #define S_404 "HTTP/1.1 404 Not Found" @@ -824,6 +828,43 @@ tfw_http_enum_resp_code(int status) } } +static inline char * +tfw_http_resp_status_line(int status) +{ + switch(status) { + case 200: + return S_200; + case 301: + return S_301; + case 302: + return S_302; + case 303: + return S_303; + case 307: + return S_307; + case 308: + return S_308; + case 400: + return S_400; + case 403: + return S_403; + case 404: + return S_404; + case 412: + return S_412; + case 500: + return S_500; + case 502: + return S_502; + case 503: + return S_503; + case 504: + return S_504; + default: + return NULL; + } +} + /** * Write HTTP/2 ':status' pseudo-header. The ':status' is only defined * pseudo-header for the response and all HTTP/2 responses must contain it. @@ -1076,6 +1117,123 @@ tfw_h1_send_resp(TfwHttpReq *req, int status) tfw_http_resp_build_error(req); } +static void +tfw_h2_send_resp2(TfwHttpReq *req, TfwStr *msg, int status, + unsigned int stream_id) +{ + TfwHttpResp *resp; + struct sk_buff **skb_head; + TfwHttpTransIter *mit; + TfwH2Ctx *ctx = tfw_h2_context(req->conn); + TfwStr hdr = { + .chunks = (TfwStr []){ {}, {} }, + .nchunks = 2 + }; + int i; + + if (!stream_id) { + stream_id = tfw_h2_stream_id_close(req, HTTP2_HEADERS, + HTTP2_F_END_STREAM); + if (unlikely(!stream_id)) { + tfw_http_conn_msg_free((TfwHttpMsg *)req); + return; + } + } + + resp = tfw_http_msg_alloc_resp_light(req); + if (unlikely(!resp)) + goto err; + + mit = &resp->mit; + skb_head = &resp->msg.skb_head; + + /* Set HTTP/2 ':status' pseudo-header. */ + mit->start_off = FRAME_HEADER_SIZE; + if (tfw_h2_resp_status_write(resp, status, TFW_H2_TRANS_EXPAND, false)) + goto err_setup; + + /* + * Form and write HTTP/2 response headers excluding "\r\n", ':' + * separators and OWS. + */ + for (i = 1; i < msg->nchunks - 1; i += 2) { + __TFW_STR_CH(&hdr, 0)->data = __TFW_STR_CH(msg, i)->data + SLEN(S_CRLF); + __TFW_STR_CH(&hdr, 0)->len = __TFW_STR_CH(msg, i)->len - SLEN(S_CRLF) - 2; + __TFW_STR_CH(&hdr, 1)->data = __TFW_STR_CH(msg, i + 1)->data; + __TFW_STR_CH(&hdr, 1)->len = __TFW_STR_CH(msg, i + 1)->len; + hdr.len = __TFW_STR_CH(&hdr, 0)->len + __TFW_STR_CH(&hdr, 1)->len; + hdr.hpack_idx = __TFW_STR_CH(msg, i)->hpack_idx; + + if (tfw_hpack_encode(resp, &hdr, TFW_H2_TRANS_EXPAND, true)) + goto err_setup; + } + + if (WARN_ON_ONCE(!mit->acc_len)) + goto err_setup; + + if (tfw_h2_frame_local_resp(resp, stream_id, mit->acc_len, NULL)) + goto err_setup; + + /* Send resulting HTTP/2 response and release HPACK encoder index. */ + tfw_h2_resp_fwd(resp); + + return; + +err_setup: + T_DBG("%s: HTTP/2 response message transformation error: conn=[%p]\n", + __func__, req->conn); + + tfw_hpack_enc_release(&ctx->hpack, resp->flags); + + tfw_http_msg_free((TfwHttpMsg *)resp); +err: + tfw_http_resp_build_error(req); +} + +static void +tfw_h1_send_resp2(TfwHttpReq *req, TfwStr *msg, int status) +{ + TfwMsgIter it; + TfwHttpResp *resp; + TfwStr *crlf; + + crlf = __TFW_STR_CH(msg, msg->nchunks - 1); + if (test_bit(TFW_HTTP_B_CONN_KA, req->flags) + || test_bit(TFW_HTTP_B_CONN_CLOSE, req->flags)) + { + unsigned long crlf_len = crlf->len; + if (test_bit(TFW_HTTP_B_CONN_CLOSE, req->flags)) { + crlf->data = S_CRLF S_H_CONN_CLOSE; + crlf->len = SLEN(S_CRLF S_H_CONN_CLOSE); + } else { + crlf->data = S_CRLF S_H_CONN_KA; + crlf->len = SLEN(S_CRLF S_H_CONN_KA); + } + msg->len += crlf->len - crlf_len; + } + + if (!(resp = tfw_http_msg_alloc_resp_light(req))) + goto err; + if (tfw_http_msg_setup((TfwHttpMsg *)resp, &it, msg->len, 0)) + goto err_setup; + + resp->status = status; + resp->content_length = 0; + + if (tfw_msg_write(&it, msg)) + goto err_setup; + + tfw_http_resp_fwd(resp); + + return; +err_setup: + T_DBG2("%s: Response message allocation error: conn=[%p]\n", + __func__, req->conn); + tfw_http_msg_free((TfwHttpMsg *)resp); +err: + tfw_http_resp_build_error(req); +} + /* * SKB data is needed for calculation of a cache key from fields of * a request. It's also needed when a request may need to be re-sent. @@ -1320,6 +1478,112 @@ tfw_http_send_resp(TfwHttpReq *req, int status, const char *reason) tfw_h1_send_resp(req, status); } +static void +tfw_http_send_resp2(TfwHttpReq *req, TfwStr *msg, int status) +{ + if (TFW_MSG_H2(req)) { + tfw_h2_send_resp2(req, msg, status, 0); + } else { + TfwCliConn *cli_conn = (TfwCliConn *)req->conn; + + WARN_ONCE(!list_empty_careful(&req->msg.seq_list), + "Request is already in seq_queue\n"); + tfw_stream_unlink_msg(req->stream); + spin_lock(&cli_conn->seq_qlock); + list_add_tail(&req->msg.seq_list, &cli_conn->seq_queue); + spin_unlock(&cli_conn->seq_qlock); + + tfw_h1_send_resp2(req, msg, status); + } +} + +static void +tfw_http_req_redir(TfwHttpReq *req, int status, const char *pattern) +{ + size_t url_len = strlen(pattern) + 1; + char *url = kmalloc(url_len, GFP_KERNEL); + char *date_val = *this_cpu_ptr(&g_buf); + char *url_p = url; + const char *pattern_end = pattern + strlen(pattern); + TfwStr *c, *end; + char *status_line; + + tfw_http_prep_date(date_val); + +#define TFW_STRCPY(from) \ +do { \ + size_t dif = url_p - url; \ + url = krealloc(url, url_len + (from)->len, GFP_KERNEL); \ + if (!url) { \ + T_WARN("HTTP: unable to allocate memory for redirection url\n"); \ + return; \ + } \ + url_p = url + dif; \ + TFW_STR_FOR_EACH_CHUNK(c, (from), end) { \ + memcpy_fast(url_p, c->data, c->len); \ + url_p += c->len; \ + } \ +} while (0) + + for (; *pattern; ++pattern) { + if (*pattern == '$') { + size_t len = pattern_end - pattern - 1; + + if (pattern_end - pattern > SLEN("request_uri") && + !strncmp(pattern + 1, "request_uri", min(SLEN("request_uri"), len))) + { + TFW_STRCPY(&req->uri_path); + pattern += SLEN("request_uri"); + } else if (pattern_end - pattern > SLEN("host") && + !strncmp(pattern + 1, "host", min(SLEN("host"), len))) + { + TFW_STRCPY(&req->host); + pattern += SLEN("host"); + } + } else { + *url_p++ = *pattern; + } + } + *url_p = '\0'; + +#undef TFW_STRCPY + + status_line = tfw_http_resp_status_line(status); + if (!status_line) { + T_WARN("Unexpected response error code: [%d]\n", status); + status_line = S_500; + } + + { + TfwStr msg = { + .chunks = (TfwStr []){ + { .data = status_line, .len = strlen(status_line) }, + { .data = S_CRLF S_F_DATE, .len = SLEN(S_CRLF S_F_DATE), + .hpack_idx = 33 }, + { .data = date_val, .len = SLEN(S_V_DATE) }, + { .data = S_CRLF S_F_CONTENT_LENGTH, + .len = SLEN(S_CRLF S_F_CONTENT_LENGTH), .hpack_idx = 28 }, + { .data = "0", .len = SLEN("0") }, + { .data = S_CRLF S_F_LOCATION, .len = SLEN(S_CRLF S_F_LOCATION), + .hpack_idx = 46 }, + { .data = (char *)url, .len = url_p - url }, + { .data = S_CRLF S_F_SERVER, .len = SLEN(S_CRLF S_F_SERVER), + .hpack_idx = 54 }, + { .data = TFW_NAME "/" TFW_VERSION, + .len = SLEN(TFW_NAME "/" TFW_VERSION) }, + { .data = S_CRLF S_CRLF, .len = SLEN(S_CRLF S_CRLF) }, + }, + .len = SLEN(S_301 S_CRLF S_F_DATE S_V_DATE S_CRLF S_F_CONTENT_LENGTH + "0" S_CRLF S_F_LOCATION S_CRLF S_F_SERVER TFW_NAME "/" + TFW_VERSION S_CRLF S_CRLF) + (url_p - url), + .nchunks = 10 + }; + tfw_http_send_resp2(req, &msg, status); + } + + kfree(url); +} + static bool tfw_http_hm_suspend(TfwHttpResp *resp, TfwServer *srv) { @@ -5327,6 +5591,7 @@ tfw_http_req_process(TfwConn *conn, TfwStream *stream, struct sk_buff *skb) TfwHttpMsg *hmsib; TfwFsmData data_up; int r = TFW_BLOCK; + TfwHttpActionResult res; BUG_ON(!stream->msg); @@ -5477,13 +5742,21 @@ tfw_http_req_process(TfwConn *conn, TfwStream *stream, struct sk_buff *skb) * rules, such as `mark` rule. Even if http_chains is the * slowest method we have, we can't simply skip it. */ - req->vhost = tfw_http_tbl_vhost((TfwMsg *)req, &block); + res = tfw_http_tbl_action((TfwMsg *)req, &block); if (unlikely(block)) { TFW_INC_STAT_BH(clnt.msgs_filtout); tfw_http_req_parse_block(req, 403, "request has been filtered out via http table"); return TFW_BLOCK; } + if (res.type == TFW_HTTP_RES_REDIR) { + tfw_http_req_redir(req, res.redir.resp_code, res.redir.url); + return TFW_PASS; + } else if (res.type == TFW_HTTP_RES_VHOST) { + req->vhost = res.vhost; + } else { + BUG(); + } if (req->vhost) req->location = tfw_location_match(req->vhost, &req->uri_path); /* @@ -6234,6 +6507,7 @@ tfw_http_hm_srv_send(TfwServer *srv, char *data, unsigned long len) }; LIST_HEAD(equeue); bool block = false; + TfwHttpActionResult res; if (!(req = tfw_http_msg_alloc_req_light())) return; @@ -6259,13 +6533,20 @@ tfw_http_hm_srv_send(TfwServer *srv, char *data, unsigned long len) * but in vhost: instead of table lookups target vhost could be chosen * directly. */ - req->vhost = tfw_http_tbl_vhost((TfwMsg *)req, &block); - if (unlikely(!req->vhost || block)) { + res = tfw_http_tbl_action((TfwMsg *)req, &block); + if (unlikely(block)) { T_WARN_ADDR("Unable to assign vhost for health monitoring " "request of backend server", &srv->addr, TFW_WITH_PORT); goto cleanup; } + if (res.type == TFW_HTTP_RES_REDIR) { + goto cleanup; + } else if (res.type == TFW_HTTP_RES_VHOST) { + req->vhost = res.vhost; + } else { + BUG(); + } req->location = req->vhost->loc_dflt; srv_conn = srv->sg->sched->sched_srv_conn((TfwMsg *)req, srv); diff --git a/fw/http_match.h b/fw/http_match.h index 67396db0c7..6c93331caa 100644 --- a/fw/http_match.h +++ b/fw/http_match.h @@ -72,6 +72,7 @@ typedef enum { TFW_HTTP_MATCH_ACT_CHAIN, TFW_HTTP_MATCH_ACT_VHOST, TFW_HTTP_MATCH_ACT_MARK, + TFW_HTTP_MATCH_ACT_REDIR, TFW_HTTP_MATCH_ACT_BLOCK, TFW_HTTP_MATCH_ACT_FLAG, _TFW_HTTP_MATCH_ACT_COUNT @@ -105,6 +106,7 @@ typedef struct { union { TfwHttpChain *chain; TfwVhost *vhost; + TfwHttpRedir redir; unsigned int mark; struct { unsigned int fid; diff --git a/fw/http_tbl.c b/fw/http_tbl.c index d930d5031c..3ac6630adc 100644 --- a/fw/http_tbl.c +++ b/fw/http_tbl.c @@ -120,7 +120,7 @@ static TfwHttpChain *tfw_chain_entry; * chain is processed primarily (must be first in the table list); if rule * of some chain points to other chain - move to that chain and scan it. */ -static TfwVhost * +static TfwHttpActionResult tfw_http_tbl_scan(TfwMsg *msg, TfwHttpTable *table, bool *block) { TfwHttpChain *chain; @@ -136,7 +136,7 @@ tfw_http_tbl_scan(TfwMsg *msg, TfwHttpTable *table, bool *block) if (unlikely(!rule)) { T_DBG("http_tbl: No rule found in HTTP chain '%s'\n", chain->name); - return NULL; + return (TfwHttpActionResult){ .type = TFW_HTTP_RES_VHOST, .vhost = NULL }; } chain = (rule->act.type == TFW_HTTP_MATCH_ACT_CHAIN) ? rule->act.chain @@ -145,13 +145,20 @@ tfw_http_tbl_scan(TfwMsg *msg, TfwHttpTable *table, bool *block) /* If rule points to virtual host, return the pointer. */ if (rule->act.type == TFW_HTTP_MATCH_ACT_VHOST) - return rule->act.vhost; + { + return (TfwHttpActionResult){ .type = TFW_HTTP_RES_VHOST, .vhost = rule->act.vhost }; + } + + if (rule->act.type == TFW_HTTP_MATCH_ACT_REDIR) + { + return (TfwHttpActionResult){ .type = TFW_HTTP_RES_REDIR, .redir = rule->act.redir}; + } /* If rule has 'block' action, request must be blocked. */ if (rule->act.type == TFW_HTTP_MATCH_ACT_BLOCK) *block = true; - return NULL; + return (TfwHttpActionResult){ .type = TFW_HTTP_RES_VHOST, .vhost = NULL }; } /* @@ -161,10 +168,10 @@ tfw_http_tbl_scan(TfwMsg *msg, TfwHttpTable *table, bool *block) * match http chain rules that specify which virtual host * or other http chain the request should be forwarded to. */ -TfwVhost * -tfw_http_tbl_vhost(TfwMsg *msg, bool *block) +TfwHttpActionResult +tfw_http_tbl_action(TfwMsg *msg, bool *block) { - TfwVhost *vhost = NULL; + TfwHttpActionResult action = { .type = TFW_HTTP_RES_VHOST, .vhost = NULL }; TfwHttpTable *active_table; rcu_read_lock_bh(); @@ -174,11 +181,14 @@ tfw_http_tbl_vhost(TfwMsg *msg, bool *block) goto done; BUG_ON(list_empty(&active_table->head)); - if ((vhost = tfw_http_tbl_scan(msg, active_table, block))) - tfw_vhost_get(vhost); + action = tfw_http_tbl_scan(msg, active_table, block); + + if (action.type == TFW_HTTP_RES_VHOST && action.vhost) + tfw_vhost_get(action.vhost); + done: - rcu_read_unlock_bh(); - return vhost; + rcu_read_unlock_bh(); + return action; } /* @@ -494,8 +504,29 @@ tfw_cfgop_http_rule(TfwCfgSpec *cs, TfwCfgEntry *e) return -EINVAL; } } + else if (action && action_val && + !tfw_cfg_parse_uint(action, &rule->act.redir.resp_code)) + { + size_t len; + + if (rule->act.redir.resp_code != 301 && + rule->act.redir.resp_code != 302 && + rule->act.redir.resp_code != 303 && + rule->act.redir.resp_code != 307 && + rule->act.redir.resp_code != 308) + { + T_ERR_NL("http_tbl: incorect redirection status code: '%s'\n", action_val); + return -EINVAL; + } + + len = strlen(action_val); + rule->act.redir.url = kmalloc(len + 1, GFP_KERNEL); + rule->act.type = TFW_HTTP_MATCH_ACT_REDIR; + + memcpy_fast(rule->act.redir.url, action_val, len + 1); + } else if (action_val) { - T_ERR_NL("http_tbl: only 'mark' or '$..' actions " + T_ERR_NL("http_tbl: only 'mark', '$..' or redirection actions " "may have any value: '%s'\n", action_val); return -EINVAL; @@ -539,6 +570,8 @@ tfw_cfgop_release_rule(TfwHttpMatchRule *rule) tfw_vhost_put(rule->act.vhost); if (rule->val.type == TFW_HTTP_MATCH_V_COOKIE) kfree(rule->val.ptn.str); + if (rule->act.type == TFW_HTTP_MATCH_ACT_REDIR) + kfree(rule->act.redir.url); return 0; } diff --git a/fw/http_tbl.h b/fw/http_tbl.h index c047e853a3..cccdec3500 100644 --- a/fw/http_tbl.h +++ b/fw/http_tbl.h @@ -23,6 +23,25 @@ #include "http.h" +typedef enum { + TFW_HTTP_RES_VHOST, + TFW_HTTP_RES_REDIR, + _TFW_HTTP_RES_COUNT +} tfw_http_res_act_t; + +typedef struct { + char *url; + unsigned int resp_code; +} TfwHttpRedir; + +typedef struct { + tfw_http_res_act_t type; + union { + TfwVhost *vhost; + TfwHttpRedir redir; + }; +} TfwHttpActionResult; + /** * HTTP chain. Contains list of rules for matching. * @@ -54,7 +73,7 @@ typedef struct { TfwPool *pool; } TfwHttpTable; -TfwVhost *tfw_http_tbl_vhost(TfwMsg *msg, bool *block); +TfwHttpActionResult tfw_http_tbl_action(TfwMsg *msg, bool *block); int tfw_http_tbl_method(const char *arg, tfw_http_meth_t *method); #endif /* __HTTP_TBL__ */ diff --git a/fw/t/unit/helpers.c b/fw/t/unit/helpers.c index a54cb543e7..e1aee297f1 100644 --- a/fw/t/unit/helpers.c +++ b/fw/t/unit/helpers.c @@ -313,7 +313,7 @@ tfw_vhost_get_hdr_mods(TfwLocation *loc, TfwVhost *vhost, int mod_type) } TfwVhost * -tfw_http_tbl_vhost(TfwMsg *msg, bool *block) +tfw_http_tbl_action(TfwMsg *msg, bool *block) { return NULL; } From 870191ad82e64351488c8ef8ee5deae9debbf3c2 Mon Sep 17 00:00:00 2001 From: Artyom Belov Date: Fri, 6 May 2022 16:35:46 +0300 Subject: [PATCH 2/3] fix review comments --- fw/http.c | 146 ++++++++++++++++++++++++++----------------- fw/http_tbl.c | 170 ++++++++++++++++++++++++++++++++++++++------------ fw/http_tbl.h | 31 +++++---- 3 files changed, 239 insertions(+), 108 deletions(-) diff --git a/fw/http.c b/fw/http.c index 0295cc1984..5785aa7f72 100644 --- a/fw/http.c +++ b/fw/http.c @@ -115,8 +115,10 @@ #define S_H2_STAT ":status" #define RESP_BUF_LEN 128 +#define URL_BUF_LEN 1024 static DEFINE_PER_CPU(char[RESP_BUF_LEN], g_buf); +static DEFINE_PER_CPU(char[URL_BUF_LEN], g_url_buf); #define TFW_CFG_BLK_DEF (TFW_BLK_ERR_REPLY) unsigned short tfw_blk_flags = TFW_CFG_BLK_DEF; @@ -1117,6 +1119,17 @@ tfw_h1_send_resp(TfwHttpReq *req, int status) tfw_http_resp_build_error(req); } +/* + * Perform operations to sending an custom HTTP2 response to a client. + * Set current date in the header of an HTTP response. + * If memory allocation error or message setup errors occurred, then + * client connection should be closed, because response-request + * pairing for pipelined requests is violated. + * + * NOTE: The first chunk is a status line, and then every odd chunk is a header + * field name starting with CRLF and ending with ': ', and every even chunk is + * a value. + */ static void tfw_h2_send_resp2(TfwHttpReq *req, TfwStr *msg, int status, unsigned int stream_id) @@ -1190,6 +1203,17 @@ tfw_h2_send_resp2(TfwHttpReq *req, TfwStr *msg, int status, tfw_http_resp_build_error(req); } +/* + * Perform operations to sending an custom HTTP1 response to a client. + * Set current date in the header of an HTTP response. + * If memory allocation error or message setup errors occurred, then client + * connection should be closed, because response-request pairing for pipelined + * requests is violated. + * + * NOTE: The first chunk is a status line, and then every odd chunk is a header + * field name starting with CRLF and ending with ': ', and every even chunk is + * a value. + */ static void tfw_h1_send_resp2(TfwHttpReq *req, TfwStr *msg, int status) { @@ -1498,54 +1522,59 @@ tfw_http_send_resp2(TfwHttpReq *req, TfwStr *msg, int status) } static void -tfw_http_req_redir(TfwHttpReq *req, int status, const char *pattern) +tfw_http_req_redir(TfwHttpReq *req, int status, TfwHttpRedir *redir) { - size_t url_len = strlen(pattern) + 1; - char *url = kmalloc(url_len, GFP_KERNEL); char *date_val = *this_cpu_ptr(&g_buf); + char *url = *this_cpu_ptr(&g_url_buf); char *url_p = url; - const char *pattern_end = pattern + strlen(pattern); - TfwStr *c, *end; + TfwStr *c, *end, *c2, *end2; char *status_line; + size_t i = 0; + TfwStr *hdr; + TfwStr hdr_val; tfw_http_prep_date(date_val); -#define TFW_STRCPY(from) \ -do { \ - size_t dif = url_p - url; \ - url = krealloc(url, url_len + (from)->len, GFP_KERNEL); \ - if (!url) { \ - T_WARN("HTTP: unable to allocate memory for redirection url\n"); \ - return; \ - } \ - url_p = url + dif; \ - TFW_STR_FOR_EACH_CHUNK(c, (from), end) { \ - memcpy_fast(url_p, c->data, c->len); \ - url_p += c->len; \ - } \ +#define TFW_STRCPY(from) \ +do { \ + if (url_p + (from)->len + 1 > url + URL_BUF_LEN) { \ + T_WARN("HTTP: unable to allocate memory for redirection " \ + "url\n"); \ + return; \ + } \ + TFW_STR_FOR_EACH_CHUNK(c2, (from), end2) { \ + memcpy_fast(url_p, c2->data, c2->len); \ + url_p += c2->len; \ + } \ } while (0) - for (; *pattern; ++pattern) { - if (*pattern == '$') { - size_t len = pattern_end - pattern - 1; + TFW_STR_FOR_EACH_CHUNK(c, &redir->url, end) { + if (url_p + c->len + 1 > url + URL_BUF_LEN) { + T_WARN("HTTP: unable to allocate memory for " + "redirection url\n"); + return; + } - if (pattern_end - pattern > SLEN("request_uri") && - !strncmp(pattern + 1, "request_uri", min(SLEN("request_uri"), len))) - { + memcpy_fast(url_p, c->data, c->len); + url_p += c->len; + + switch (redir->var[i]) { + case TFW_HTTP_REDIR_URI: TFW_STRCPY(&req->uri_path); - pattern += SLEN("request_uri"); - } else if (pattern_end - pattern > SLEN("host") && - !strncmp(pattern + 1, "host", min(SLEN("host"), len))) - { - TFW_STRCPY(&req->host); - pattern += SLEN("host"); - } - } else { - *url_p++ = *pattern; + break; + case TFW_HTTP_REDIR_HOST: + hdr = &req->h_tbl->tbl[TFW_HTTP_HDR_HOST]; + tfw_http_msg_clnthdr_val(req, hdr, + TFW_HTTP_HDR_HOST, + &hdr_val); + TFW_STRCPY(&hdr_val); + break; + default: + BUG(); } + i++; } *url_p = '\0'; - #undef TFW_STRCPY status_line = tfw_http_resp_status_line(status); @@ -1557,31 +1586,36 @@ do { \ { TfwStr msg = { .chunks = (TfwStr []){ - { .data = status_line, .len = strlen(status_line) }, - { .data = S_CRLF S_F_DATE, .len = SLEN(S_CRLF S_F_DATE), + { .data = status_line, + .len = strlen(status_line) }, + { .data = S_CRLF S_F_DATE, + .len = SLEN(S_CRLF S_F_DATE), .hpack_idx = 33 }, { .data = date_val, .len = SLEN(S_V_DATE) }, { .data = S_CRLF S_F_CONTENT_LENGTH, - .len = SLEN(S_CRLF S_F_CONTENT_LENGTH), .hpack_idx = 28 }, + .len = SLEN(S_CRLF S_F_CONTENT_LENGTH), + .hpack_idx = 28 }, { .data = "0", .len = SLEN("0") }, - { .data = S_CRLF S_F_LOCATION, .len = SLEN(S_CRLF S_F_LOCATION), + { .data = S_CRLF S_F_LOCATION, + .len = SLEN(S_CRLF S_F_LOCATION), .hpack_idx = 46 }, { .data = (char *)url, .len = url_p - url }, - { .data = S_CRLF S_F_SERVER, .len = SLEN(S_CRLF S_F_SERVER), + { .data = S_CRLF S_F_SERVER, + .len = SLEN(S_CRLF S_F_SERVER), .hpack_idx = 54 }, { .data = TFW_NAME "/" TFW_VERSION, .len = SLEN(TFW_NAME "/" TFW_VERSION) }, - { .data = S_CRLF S_CRLF, .len = SLEN(S_CRLF S_CRLF) }, + { .data = S_CRLF S_CRLF, + .len = SLEN(S_CRLF S_CRLF) }, }, - .len = SLEN(S_301 S_CRLF S_F_DATE S_V_DATE S_CRLF S_F_CONTENT_LENGTH - "0" S_CRLF S_F_LOCATION S_CRLF S_F_SERVER TFW_NAME "/" - TFW_VERSION S_CRLF S_CRLF) + (url_p - url), + .len = SLEN(S_301 S_CRLF S_F_DATE S_V_DATE S_CRLF + S_F_CONTENT_LENGTH "0" S_CRLF S_F_LOCATION + S_CRLF S_F_SERVER TFW_NAME "/" TFW_VERSION + S_CRLF S_CRLF) + (url_p - url), .nchunks = 10 }; tfw_http_send_resp2(req, &msg, status); } - - kfree(url); } static bool @@ -5584,7 +5618,6 @@ tfw_h1_req_process(TfwStream *stream, struct sk_buff *skb) static int tfw_http_req_process(TfwConn *conn, TfwStream *stream, struct sk_buff *skb) { - bool block; ss_skb_actor_t *actor; unsigned int parsed; TfwHttpReq *req; @@ -5603,7 +5636,6 @@ tfw_http_req_process(TfwConn *conn, TfwStream *stream, struct sk_buff *skb) * until all data in the SKB is processed. */ next_msg: - block = false; parsed = 0; hmsib = NULL; req = (TfwHttpReq *)stream->msg; @@ -5742,20 +5774,14 @@ tfw_http_req_process(TfwConn *conn, TfwStream *stream, struct sk_buff *skb) * rules, such as `mark` rule. Even if http_chains is the * slowest method we have, we can't simply skip it. */ - res = tfw_http_tbl_action((TfwMsg *)req, &block); - if (unlikely(block)) { + if (unlikely(r = tfw_http_tbl_action((TfwMsg *)req, &res))) { TFW_INC_STAT_BH(clnt.msgs_filtout); tfw_http_req_parse_block(req, 403, "request has been filtered out via http table"); return TFW_BLOCK; } - if (res.type == TFW_HTTP_RES_REDIR) { - tfw_http_req_redir(req, res.redir.resp_code, res.redir.url); - return TFW_PASS; - } else if (res.type == TFW_HTTP_RES_VHOST) { + if (res.type == TFW_HTTP_RES_VHOST) { req->vhost = res.vhost; - } else { - BUG(); } if (req->vhost) req->location = tfw_location_match(req->vhost, &req->uri_path); @@ -5806,6 +5832,11 @@ tfw_http_req_process(TfwConn *conn, TfwStream *stream, struct sk_buff *skb) return TFW_BLOCK; } + if (res.type == TFW_HTTP_RES_REDIR) { + tfw_http_req_redir(req, res.redir.resp_code, &res.redir); + return TFW_PASS; + } + /* * Sticky cookie module must be used before request can reach cache. * Unauthorised clients mustn't be able to get any resource on @@ -6506,8 +6537,8 @@ tfw_http_hm_srv_send(TfwServer *srv, char *data, unsigned long len) .len = len, }; LIST_HEAD(equeue); - bool block = false; TfwHttpActionResult res; + int r; if (!(req = tfw_http_msg_alloc_req_light())) return; @@ -6533,8 +6564,7 @@ tfw_http_hm_srv_send(TfwServer *srv, char *data, unsigned long len) * but in vhost: instead of table lookups target vhost could be chosen * directly. */ - res = tfw_http_tbl_action((TfwMsg *)req, &block); - if (unlikely(block)) { + if (unlikely(r = tfw_http_tbl_action((TfwMsg *)req, &res))) { T_WARN_ADDR("Unable to assign vhost for health monitoring " "request of backend server", &srv->addr, TFW_WITH_PORT); diff --git a/fw/http_tbl.c b/fw/http_tbl.c index 3ac6630adc..b02f3665b0 100644 --- a/fw/http_tbl.c +++ b/fw/http_tbl.c @@ -120,8 +120,8 @@ static TfwHttpChain *tfw_chain_entry; * chain is processed primarily (must be first in the table list); if rule * of some chain points to other chain - move to that chain and scan it. */ -static TfwHttpActionResult -tfw_http_tbl_scan(TfwMsg *msg, TfwHttpTable *table, bool *block) +static int +tfw_http_tbl_scan(TfwMsg *msg, TfwHttpTable *table, TfwHttpActionResult *action) { TfwHttpChain *chain; TfwHttpMatchRule *rule; @@ -136,29 +136,40 @@ tfw_http_tbl_scan(TfwMsg *msg, TfwHttpTable *table, bool *block) if (unlikely(!rule)) { T_DBG("http_tbl: No rule found in HTTP chain '%s'\n", chain->name); - return (TfwHttpActionResult){ .type = TFW_HTTP_RES_VHOST, .vhost = NULL }; + *action = (TfwHttpActionResult){ + .type = TFW_HTTP_RES_VHOST, + .vhost = NULL + }; + return 0; } chain = (rule->act.type == TFW_HTTP_MATCH_ACT_CHAIN) ? rule->act.chain : NULL; } - /* If rule points to virtual host, return the pointer. */ - if (rule->act.type == TFW_HTTP_MATCH_ACT_VHOST) - { - return (TfwHttpActionResult){ .type = TFW_HTTP_RES_VHOST, .vhost = rule->act.vhost }; + switch (rule->act.type) { + case TFW_HTTP_MATCH_ACT_VHOST: + *action = (TfwHttpActionResult){ + .type = TFW_HTTP_RES_VHOST, + .vhost = rule->act.vhost + }; + return 0; + case TFW_HTTP_MATCH_ACT_REDIR: + *action = (TfwHttpActionResult){ + .type = TFW_HTTP_RES_REDIR, + .redir = rule->act.redir + }; + return 0; + case TFW_HTTP_MATCH_ACT_BLOCK: + return -1; + + default: + *action = (TfwHttpActionResult){ + .type = TFW_HTTP_RES_VHOST, + .vhost = NULL + }; + return 0; } - - if (rule->act.type == TFW_HTTP_MATCH_ACT_REDIR) - { - return (TfwHttpActionResult){ .type = TFW_HTTP_RES_REDIR, .redir = rule->act.redir}; - } - - /* If rule has 'block' action, request must be blocked. */ - if (rule->act.type == TFW_HTTP_MATCH_ACT_BLOCK) - *block = true; - - return (TfwHttpActionResult){ .type = TFW_HTTP_RES_VHOST, .vhost = NULL }; } /* @@ -168,27 +179,30 @@ tfw_http_tbl_scan(TfwMsg *msg, TfwHttpTable *table, bool *block) * match http chain rules that specify which virtual host * or other http chain the request should be forwarded to. */ -TfwHttpActionResult -tfw_http_tbl_action(TfwMsg *msg, bool *block) +int +tfw_http_tbl_action(TfwMsg *msg, TfwHttpActionResult *action) { - TfwHttpActionResult action = { .type = TFW_HTTP_RES_VHOST, .vhost = NULL }; TfwHttpTable *active_table; + int r = 0; rcu_read_lock_bh(); active_table = rcu_dereference_bh(tfw_table); - if(!active_table) + if(!active_table) { + *action = (TfwHttpActionResult){ .type = TFW_HTTP_RES_VHOST, + .vhost = NULL }; goto done; + } BUG_ON(list_empty(&active_table->head)); - action = tfw_http_tbl_scan(msg, active_table, block); + r = tfw_http_tbl_scan(msg, active_table, action); - if (action.type == TFW_HTTP_RES_VHOST && action.vhost) - tfw_vhost_get(action.vhost); + if (action->type == TFW_HTTP_RES_VHOST && action->vhost) + tfw_vhost_get(action->vhost); done: rcu_read_unlock_bh(); - return action; + return r; } /* @@ -505,25 +519,97 @@ tfw_cfgop_http_rule(TfwCfgSpec *cs, TfwCfgEntry *e) } } else if (action && action_val && - !tfw_cfg_parse_uint(action, &rule->act.redir.resp_code)) + !tfw_cfg_parse_uint(action, &rule->act.redir.resp_code)) { - size_t len; + TfwStr *url = &rule->act.redir.url; + const char *begin, *pos; + const char *val_end = action_val + strlen(action_val); + size_t i; if (rule->act.redir.resp_code != 301 && - rule->act.redir.resp_code != 302 && - rule->act.redir.resp_code != 303 && - rule->act.redir.resp_code != 307 && - rule->act.redir.resp_code != 308) + rule->act.redir.resp_code != 302 && + rule->act.redir.resp_code != 303 && + rule->act.redir.resp_code != 307 && + rule->act.redir.resp_code != 308) { - T_ERR_NL("http_tbl: incorect redirection status code: '%s'\n", action_val); + T_ERR_NL("http_tbl: incorect redirection status code: " + "'%s'\n", action_val); return -EINVAL; } - len = strlen(action_val); - rule->act.redir.url = kmalloc(len + 1, GFP_KERNEL); - rule->act.type = TFW_HTTP_MATCH_ACT_REDIR; + url->chunks = kmalloc((TFW_HTTP_MAX_REDIR_VARS + 1) * + sizeof(TfwStr), GFP_KERNEL); + if (!url->chunks) { + T_ERR_NL("http_tbl: can't allocate memory for " + "redirections\n"); + return -EINVAL; + } + + url->nchunks = 0; + url->len = 0; + +#define CREATE_CHUNK() \ +do { \ + url->chunks[i].data = kmalloc(pos - begin + 1, GFP_KERNEL); \ + if (!url->chunks[i].data) { \ + kfree(url->chunks); \ + T_ERR_NL("http_tbl: can't allocate memory for " \ + "redirections\n"); \ + return -EINVAL; \ + } \ + url->chunks[i].len = pos - begin; \ + url->chunks[i].nchunks = 0; \ + memcpy(url->chunks[i].data, begin, pos - begin); \ + url->chunks[i].data[pos - begin] = '\0'; \ + url->nchunks++; \ + url->len += pos - begin; \ +} while (0) + + for (begin = pos = action_val, i = 0; + *pos && i < TFW_HTTP_MAX_REDIR_VARS;) + { + if (*pos == '$') { + tfw_http_redir_var_t var; + + if (val_end - pos > SLEN("request_uri") && + !strncmp(pos + 1, "request_uri", + SLEN("request_uri"))) + { + CREATE_CHUNK(); + + begin = pos += SLEN("$request_uri"); + + var= TFW_HTTP_REDIR_URI; + } else if (val_end - pos > SLEN("host") && + !strncmp(pos + 1, "host", + SLEN("host"))) + { + CREATE_CHUNK(); + + begin = pos += SLEN("$host"); + + var = TFW_HTTP_REDIR_HOST; + } else { + ++pos; + continue; + } + + rule->act.redir.var[i] = var; + i++; + } else { + ++pos; + } + } +#undef CREATE_CHUNK + + if (i >= TFW_HTTP_MAX_REDIR_VARS) { + T_ERR_NL("http_tbl: too many vars (more %d) in redirection url: " + "'%s'\n", + TFW_HTTP_MAX_REDIR_VARS, action_val); + return -EINVAL; + } - memcpy_fast(rule->act.redir.url, action_val, len + 1); + rule->act.type = TFW_HTTP_MATCH_ACT_REDIR; } else if (action_val) { T_ERR_NL("http_tbl: only 'mark', '$..' or redirection actions " @@ -570,8 +656,14 @@ tfw_cfgop_release_rule(TfwHttpMatchRule *rule) tfw_vhost_put(rule->act.vhost); if (rule->val.type == TFW_HTTP_MATCH_V_COOKIE) kfree(rule->val.ptn.str); - if (rule->act.type == TFW_HTTP_MATCH_ACT_REDIR) - kfree(rule->act.redir.url); + if (rule->act.type == TFW_HTTP_MATCH_ACT_REDIR) { + int i; + + for (i = 0; i < rule->act.redir.url.nchunks; ++i) { + kfree(rule->act.redir.url.chunks[i].data); + } + kfree(rule->act.redir.url.chunks); + } return 0; } diff --git a/fw/http_tbl.h b/fw/http_tbl.h index cccdec3500..6e07f82a95 100644 --- a/fw/http_tbl.h +++ b/fw/http_tbl.h @@ -23,23 +23,32 @@ #include "http.h" +#define TFW_HTTP_MAX_REDIR_VARS 8 + +typedef enum { + TFW_HTTP_REDIR_URI, + TFW_HTTP_REDIR_HOST, + _TFW_HTTP_REDIR_VAR_COUNT +} tfw_http_redir_var_t; + typedef enum { - TFW_HTTP_RES_VHOST, - TFW_HTTP_RES_REDIR, - _TFW_HTTP_RES_COUNT + TFW_HTTP_RES_VHOST, + TFW_HTTP_RES_REDIR, + _TFW_HTTP_RES_COUNT } tfw_http_res_act_t; typedef struct { - char *url; - unsigned int resp_code; + TfwStr url; + tfw_http_redir_var_t var[TFW_HTTP_MAX_REDIR_VARS]; + unsigned int resp_code; } TfwHttpRedir; typedef struct { - tfw_http_res_act_t type; - union { - TfwVhost *vhost; - TfwHttpRedir redir; - }; + tfw_http_res_act_t type; + union { + TfwVhost *vhost; + TfwHttpRedir redir; + }; } TfwHttpActionResult; /** @@ -73,7 +82,7 @@ typedef struct { TfwPool *pool; } TfwHttpTable; -TfwHttpActionResult tfw_http_tbl_action(TfwMsg *msg, bool *block); +int tfw_http_tbl_action(TfwMsg *msg, TfwHttpActionResult *action); int tfw_http_tbl_method(const char *arg, tfw_http_meth_t *method); #endif /* __HTTP_TBL__ */ From 6c779de88e31f292fd1fa0675d8a23d2e8229031 Mon Sep 17 00:00:00 2001 From: Artyom Belov Date: Fri, 6 May 2022 16:43:52 +0300 Subject: [PATCH 3/3] fix review comments renaming of functions --- fw/cache.c | 14 +++++++------- fw/http.c | 44 ++++++++++++++++++++++---------------------- fw/http.h | 2 +- 3 files changed, 30 insertions(+), 30 deletions(-) diff --git a/fw/cache.c b/fw/cache.c index da25d3af6f..93618cdfaa 100644 --- a/fw/cache.c +++ b/fw/cache.c @@ -863,7 +863,7 @@ tfw_handle_validation_req(TfwHttpReq *req, TfwCacheEntry *ce) || (req->method == TFW_HTTP_METH_HEAD)) tfw_cache_send_304(req, ce); else - tfw_http_send_resp(req, 412, + tfw_http_send_err_resp(req, 412, "request validation: " "precondition failed"); @@ -1965,14 +1965,14 @@ tfw_cache_purge_method(TfwHttpReq *req) /* Deny PURGE requests by default. */ if (!(cache_cfg.cache && g_vhost->cache_purge && g_vhost->cache_purge_acl)) { - tfw_http_send_resp(req, 403, "purge: not configured"); + tfw_http_send_err_resp(req, 403, "purge: not configured"); return -EINVAL; } /* Accept requests from configured hosts only. */ ss_getpeername(req->conn->sk, &saddr); if (!tfw_capuacl_match(&saddr)) { - tfw_http_send_resp(req, 403, "purge: ACL violation"); + tfw_http_send_err_resp(req, 403, "purge: ACL violation"); return -EINVAL; } @@ -1982,14 +1982,14 @@ tfw_cache_purge_method(TfwHttpReq *req) ret = tfw_cache_purge_invalidate(req); break; default: - tfw_http_send_resp(req, 403, "purge: invalid option"); + tfw_http_send_err_resp(req, 403, "purge: invalid option"); return -EINVAL; } if (ret) - tfw_http_send_resp(req, 404, "purge: processing error"); + tfw_http_send_err_resp(req, 404, "purge: processing error"); else if (!test_bit(TFW_HTTP_B_PURGE_GET, req->flags)) - tfw_http_send_resp(req, 200, "purge: success"); + tfw_http_send_err_resp(req, 200, "purge: success"); return ret; } @@ -2382,7 +2382,7 @@ cache_req_process_node(TfwHttpReq *req, tfw_http_cache_cb_t action) } out: if (!resp && (req->cache_ctl.flags & TFW_HTTP_CC_OIFCACHED)) - tfw_http_send_resp(req, 504, "resource not cached"); + tfw_http_send_err_resp(req, 504, "resource not cached"); else /* * TODO: RFC 7234 4.3.2: Extend preconditional request headers diff --git a/fw/http.c b/fw/http.c index 5785aa7f72..ed13fc500d 100644 --- a/fw/http.c +++ b/fw/http.c @@ -937,7 +937,7 @@ tfw_h2_resp_fwd(TfwHttpResp *resp) } static void -tfw_h2_send_resp(TfwHttpReq *req, int status, unsigned int stream_id) +tfw_h2_send_err_resp(TfwHttpReq *req, int status, unsigned int stream_id) { TfwStr *msg; resp_code_t code; @@ -1055,7 +1055,7 @@ tfw_h2_send_resp(TfwHttpReq *req, int status, unsigned int stream_id) * the fourth chunk must be CRLF. */ static void -tfw_h1_send_resp(TfwHttpReq *req, int status) +tfw_h1_send_err_resp(TfwHttpReq *req, int status) { TfwMsgIter it; resp_code_t code; @@ -1131,7 +1131,7 @@ tfw_h1_send_resp(TfwHttpReq *req, int status) * a value. */ static void -tfw_h2_send_resp2(TfwHttpReq *req, TfwStr *msg, int status, +tfw_h2_send_resp(TfwHttpReq *req, TfwStr *msg, int status, unsigned int stream_id) { TfwHttpResp *resp; @@ -1215,7 +1215,7 @@ tfw_h2_send_resp2(TfwHttpReq *req, TfwStr *msg, int status, * a value. */ static void -tfw_h1_send_resp2(TfwHttpReq *req, TfwStr *msg, int status) +tfw_h1_send_resp(TfwHttpReq *req, TfwStr *msg, int status) { TfwMsgIter it; TfwHttpResp *resp; @@ -1489,7 +1489,7 @@ tfw_http_nip_req_resched_err(TfwSrvConn *srv_conn, TfwHttpReq *req, /* Common interface for sending error responses. */ void -tfw_http_send_resp(TfwHttpReq *req, int status, const char *reason) +tfw_http_send_err_resp(TfwHttpReq *req, int status, const char *reason) { if (!(tfw_blk_flags & TFW_BLK_ERR_NOLOG)) { T_WARN_ADDR_STATUS(reason, &req->conn->peer->addr, @@ -1497,16 +1497,16 @@ tfw_http_send_resp(TfwHttpReq *req, int status, const char *reason) } if (TFW_MSG_H2(req)) - tfw_h2_send_resp(req, status, 0); + tfw_h2_send_err_resp(req, status, 0); else - tfw_h1_send_resp(req, status); + tfw_h1_send_err_resp(req, status); } static void -tfw_http_send_resp2(TfwHttpReq *req, TfwStr *msg, int status) +tfw_http_send_resp(TfwHttpReq *req, TfwStr *msg, int status) { if (TFW_MSG_H2(req)) { - tfw_h2_send_resp2(req, msg, status, 0); + tfw_h2_send_resp(req, msg, status, 0); } else { TfwCliConn *cli_conn = (TfwCliConn *)req->conn; @@ -1517,7 +1517,7 @@ tfw_http_send_resp2(TfwHttpReq *req, TfwStr *msg, int status) list_add_tail(&req->msg.seq_list, &cli_conn->seq_queue); spin_unlock(&cli_conn->seq_qlock); - tfw_h1_send_resp2(req, msg, status); + tfw_h1_send_resp(req, msg, status); } } @@ -1614,7 +1614,7 @@ do { \ S_CRLF S_CRLF) + (url_p - url), .nchunks = 10 }; - tfw_http_send_resp2(req, &msg, status); + tfw_http_send_resp(req, &msg, status); } } @@ -1717,7 +1717,7 @@ tfw_http_req_zap_error(struct list_head *eq) || (!TFW_MSG_H2(req) && !test_bit(TFW_HTTP_B_REQ_DROP, req->flags))) { - tfw_http_send_resp(req, req->httperr.status, + tfw_http_send_err_resp(req, req->httperr.status, req->httperr.reason); } else @@ -2237,7 +2237,7 @@ tfw_http_req_resched(TfwHttpReq *req, TfwServer *srv, struct list_head *eq) } } else if (!(sch_conn = tfw_http_get_srv_conn((TfwMsg *)req))) { T_DBG("Unable to find a backend server\n"); - tfw_http_send_resp(req, 502, "request dropped: unable to" + tfw_http_send_err_resp(req, 502, "request dropped: unable to" " find an available back end server"); TFW_INC_STAT_BH(clnt.msgs_otherr); return 0; @@ -4893,7 +4893,7 @@ tfw_h1_resp_adjust_fwd(TfwHttpResp *resp) */ if (tfw_http_adjust_resp(resp)) { tfw_http_conn_msg_free((TfwHttpMsg *)resp); - tfw_http_send_resp(req, 500, + tfw_http_send_err_resp(req, 500, "response dropped: processing error"); TFW_INC_STAT_BH(serv.msgs_otherr); return; @@ -4966,7 +4966,7 @@ tfw_h2_error_resp(TfwHttpReq *req, int status, bool reply, bool attack, * is already in locally closed state (switched in * @tfw_h2_stream_id_close() during failed proxy/internal response * creation) or will be switched into locally closed state in - * @tfw_h2_send_resp() (or in @tfw_h2_stream_id_close() if no error + * @tfw_h2_send_err_resp() (or in @tfw_h2_stream_id_close() if no error * response is needed) below; remotely (i.e. on client side) stream * will be closed - due to END_STREAM flag set in the last frame of * error response; in case of attack we must close entire connection, @@ -4974,7 +4974,7 @@ tfw_h2_error_resp(TfwHttpReq *req, int status, bool reply, bool attack, * error response. */ if (reply) { - tfw_h2_send_resp(req, status, 0); + tfw_h2_send_err_resp(req, status, 0); if (attack) tfw_h2_conn_terminate_close(ctx, HTTP2_ECODE_PROTO, !on_req_recv_event); @@ -5039,7 +5039,7 @@ tfw_h1_error_resp(TfwHttpReq *req, int status, bool reply, bool attack, */ if (on_req_recv_event || attack) tfw_http_req_set_conn_close(req); - tfw_h1_send_resp(req, status); + tfw_h1_send_err_resp(req, status); } /* * Serve all pending requests if not under attack, close immediately @@ -5263,7 +5263,7 @@ tfw_h2_resp_adjust_fwd(TfwHttpResp *resp) T_WARN_ADDR_STATUS("response dropped: processing error", &req->conn->peer->addr, TFW_NO_PORT, 500); - tfw_h2_send_resp(req, 500, stream_id); + tfw_h2_send_err_resp(req, 500, stream_id); tfw_hpack_enc_release(&ctx->hpack, resp->flags); TFW_INC_STAT_BH(serv.msgs_otherr); @@ -5343,11 +5343,11 @@ tfw_http_req_cache_cb(TfwHttpMsg *msg) goto conn_put; send_502: - tfw_http_send_resp(req, 502, "request dropped: processing error"); + tfw_http_send_err_resp(req, 502, "request dropped: processing error"); TFW_INC_STAT_BH(clnt.msgs_otherr); return; send_500: - tfw_http_send_resp(req, 500, "request dropped: processing error"); + tfw_http_send_err_resp(req, 500, "request dropped: processing error"); TFW_INC_STAT_BH(clnt.msgs_otherr); conn_put: /* @@ -5942,7 +5942,7 @@ tfw_http_req_process(TfwConn *conn, TfwStream *stream, struct sk_buff *skb) * The request should either be stored or released. * Otherwise we lose the reference to it and get a leak. */ - tfw_http_send_resp(req, 500, "request dropped:" + tfw_http_send_err_resp(req, 500, "request dropped:" " processing error"); TFW_INC_STAT_BH(clnt.msgs_otherr); } @@ -6178,7 +6178,7 @@ tfw_http_resp_cache(TfwHttpMsg *hmresp) if (tfw_cache_process(hmresp, tfw_http_resp_cache_cb)) { tfw_http_conn_msg_free(hmresp); - tfw_http_send_resp(req, 500, "response dropped:" + tfw_http_send_err_resp(req, 500, "response dropped:" " processing error"); TFW_INC_STAT_BH(serv.msgs_otherr); /* Proceed with processing of the next response. */ diff --git a/fw/http.h b/fw/http.h index b0f6e37b5e..9e2087db41 100644 --- a/fw/http.h +++ b/fw/http.h @@ -710,7 +710,7 @@ int tfw_h1_prep_redirect(TfwHttpResp *resp, unsigned short status, int tfw_http_prep_304(TfwHttpReq *req, struct sk_buff **skb_head, TfwMsgIter *it); void tfw_http_conn_msg_free(TfwHttpMsg *hm); -void tfw_http_send_resp(TfwHttpReq *req, int status, const char *reason); +void tfw_http_send_err_resp(TfwHttpReq *req, int status, const char *reason); /* Helper functions */ char *tfw_http_msg_body_dup(const char *filename, size_t *len);