diff --git a/include/proto/proto_http.h b/include/proto/proto_http.h index 477b9b056..a8056af88 100644 --- a/include/proto/proto_http.h +++ b/include/proto/proto_http.h @@ -114,6 +114,7 @@ unsigned int http_get_hdr(const struct http_msg *msg, const char *hname, int hle struct hdr_idx *idx, int occ, struct hdr_ctx *ctx, char **vptr, int *vlen); +struct http_txn *http_alloc_txn(struct stream *s); void http_init_txn(struct stream *s); void http_end_txn(struct stream *s); void http_reset_txn(struct stream *s); diff --git a/include/types/proto_http.h b/include/types/proto_http.h index b7dc4b53f..d1fdf7585 100644 --- a/include/types/proto_http.h +++ b/include/types/proto_http.h @@ -545,6 +545,8 @@ extern struct http_res_action_kw_list http_res_keywords; extern const struct http_method_name http_known_methods[HTTP_METH_OTHER]; +extern struct pool_head *pool2_http_txn; + #endif /* _TYPES_PROTO_HTTP_H */ /* diff --git a/include/types/stream.h b/include/types/stream.h index 80d84ac10..3a0a60f5f 100644 --- a/include/types/stream.h +++ b/include/types/stream.h @@ -124,7 +124,7 @@ struct stream { struct server *srv_conn; /* stream already has a slot on a server and is not in queue */ struct pendconn *pend_pos; /* if not NULL, points to the position in the pending queue */ - struct http_txn txn; /* current HTTP transaction being processed. Should become a list. */ + struct http_txn *txn; /* current HTTP transaction being processed. Should become a list. */ struct task *task; /* the task associated with this stream */ struct list list; /* position in global streams list */ diff --git a/src/backend.c b/src/backend.c index 2c2a61e7a..a8cf644c0 100644 --- a/src/backend.c +++ b/src/backend.c @@ -300,7 +300,7 @@ struct server *get_server_ph(struct proxy *px, const char *uri, int uri_len) struct server *get_server_ph_post(struct stream *s) { unsigned int hash = 0; - struct http_txn *txn = &s->txn; + struct http_txn *txn = s->txn; struct channel *req = &s->req; struct http_msg *msg = &txn->req; struct proxy *px = s->be; @@ -378,7 +378,7 @@ struct server *get_server_ph_post(struct stream *s) struct server *get_server_hh(struct stream *s) { unsigned int hash = 0; - struct http_txn *txn = &s->txn; + struct http_txn *txn = s->txn; struct proxy *px = s->be; unsigned int plen = px->hh_len; unsigned long len; @@ -553,7 +553,7 @@ int assign_server(struct stream *s) if (conn && (conn->flags & CO_FL_CONNECTED) && objt_server(conn->target) && __objt_server(conn->target)->proxy == s->be && - ((s->txn.flags & TX_PREFER_LAST) || + ((s->txn && s->txn->flags & TX_PREFER_LAST) || ((s->be->options & PR_O_PREF_LAST) && (!s->be->max_ka_queue || server_has_room(__objt_server(conn->target)) || @@ -627,29 +627,29 @@ int assign_server(struct stream *s) case BE_LB_HASH_URI: /* URI hashing */ - if (s->txn.req.msg_state < HTTP_MSG_BODY) + if (!s->txn || s->txn->req.msg_state < HTTP_MSG_BODY) break; srv = get_server_uh(s->be, - b_ptr(s->req.buf, -http_uri_rewind(&s->txn.req)), - s->txn.req.sl.rq.u_l); + b_ptr(s->req.buf, -http_uri_rewind(&s->txn->req)), + s->txn->req.sl.rq.u_l); break; case BE_LB_HASH_PRM: /* URL Parameter hashing */ - if (s->txn.req.msg_state < HTTP_MSG_BODY) + if (!s->txn || s->txn->req.msg_state < HTTP_MSG_BODY) break; srv = get_server_ph(s->be, - b_ptr(s->req.buf, -http_uri_rewind(&s->txn.req)), - s->txn.req.sl.rq.u_l); + b_ptr(s->req.buf, -http_uri_rewind(&s->txn->req)), + s->txn->req.sl.rq.u_l); - if (!srv && s->txn.meth == HTTP_METH_POST) + if (!srv && s->txn->meth == HTTP_METH_POST) srv = get_server_ph_post(s); break; case BE_LB_HASH_HDR: /* Header Parameter hashing */ - if (s->txn.req.msg_state < HTTP_MSG_BODY) + if (!s->txn || s->txn->req.msg_state < HTTP_MSG_BODY) break; srv = get_server_hh(s); break; @@ -861,9 +861,9 @@ int assign_server_and_queue(struct stream *s) */ if (prev_srv != objt_server(s->target)) { - if ((s->txn.flags & TX_CK_MASK) == TX_CK_VALID) { - s->txn.flags &= ~TX_CK_MASK; - s->txn.flags |= TX_CK_DOWN; + if (s->txn && (s->txn->flags & TX_CK_MASK) == TX_CK_VALID) { + s->txn->flags &= ~TX_CK_MASK; + s->txn->flags |= TX_CK_DOWN; } s->flags |= SF_REDISP; prev_srv->counters.redispatches++; @@ -973,7 +973,7 @@ static void assign_tproxy_address(struct stream *s) memset(&srv_conn->addr.from, 0, sizeof(srv_conn->addr.from)); break; case CO_SRC_TPROXY_DYN: - if (src->bind_hdr_occ) { + if (src->bind_hdr_occ && s->txn) { char *vptr; int vlen; int rewind; @@ -983,9 +983,9 @@ static void assign_tproxy_address(struct stream *s) ((struct sockaddr_in *)&srv_conn->addr.from)->sin_port = 0; ((struct sockaddr_in *)&srv_conn->addr.from)->sin_addr.s_addr = 0; - b_rew(s->req.buf, rewind = http_hdr_rewind(&s->txn.req)); - if (http_get_hdr(&s->txn.req, src->bind_hdr_name, src->bind_hdr_len, - &s->txn.hdr_idx, src->bind_hdr_occ, NULL, &vptr, &vlen)) { + b_rew(s->req.buf, rewind = http_hdr_rewind(&s->txn->req)); + if (http_get_hdr(&s->txn->req, src->bind_hdr_name, src->bind_hdr_len, + &s->txn->hdr_idx, src->bind_hdr_occ, NULL, &vptr, &vlen)) { ((struct sockaddr_in *)&srv_conn->addr.from)->sin_addr.s_addr = htonl(inetaddr_host_lim(vptr, vptr + vlen)); } diff --git a/src/compression.c b/src/compression.c index 0ae634f2e..50d41c119 100644 --- a/src/compression.c +++ b/src/compression.c @@ -184,7 +184,7 @@ int http_compression_buffer_init(struct stream *s, struct buffer *in, struct buf */ int http_compression_buffer_add_data(struct stream *s, struct buffer *in, struct buffer *out) { - struct http_msg *msg = &s->txn.rsp; + struct http_msg *msg = &s->txn->rsp; int consumed_data = 0; int data_process_len; int block1, block2; @@ -234,7 +234,7 @@ int http_compression_buffer_end(struct stream *s, struct buffer **in, struct buf { int to_forward; int left; - struct http_msg *msg = &s->txn.rsp; + struct http_msg *msg = &s->txn->rsp; struct buffer *ib = *in, *ob = *out; char *tail; diff --git a/src/dumpstats.c b/src/dumpstats.c index 2aed81a71..c24f81551 100644 --- a/src/dumpstats.c +++ b/src/dumpstats.c @@ -4422,13 +4422,13 @@ static int stats_process_http_post(struct stream_interface *si) int reql; temp = get_trash_chunk(); - if (temp->size < s->txn.req.body_len) { + if (temp->size < s->txn->req.body_len) { /* too large request */ appctx->ctx.stats.st_code = STAT_STATUS_EXCD; goto out; } - reql = bo_getblk(si_oc(si), temp->str, s->txn.req.body_len, s->txn.req.eoh + 2); + reql = bo_getblk(si_oc(si), temp->str, s->txn->req.body_len, s->txn->req.eoh + 2); if (reql <= 0) { /* we need more data */ appctx->ctx.stats.st_code = STAT_STATUS_NONE; @@ -4742,7 +4742,7 @@ static int stats_send_http_headers(struct stream_interface *si) else chunk_appendf(&trash, "\r\n"); - s->txn.status = 200; + s->txn->status = 200; s->logs.tv_request = now; if (bi_putchk(si_ic(si), &trash) == -1) { @@ -4789,7 +4789,7 @@ static int stats_send_http_redirect(struct stream_interface *si) (appctx->ctx.stats.flags & STAT_NO_REFRESH) ? ";norefresh" : "", scope_txt); - s->txn.status = 303; + s->txn->status = 303; s->logs.tv_request = now; if (bi_putchk(si_ic(si), &trash) == -1) { @@ -4822,7 +4822,7 @@ static void http_stats_io_handler(struct stream_interface *si) /* all states are processed in sequence */ if (appctx->st0 == STAT_HTTP_HEAD) { if (stats_send_http_headers(si)) { - if (s->txn.meth == HTTP_METH_HEAD) + if (s->txn->meth == HTTP_METH_HEAD) appctx->st0 = STAT_HTTP_DONE; else appctx->st0 = STAT_HTTP_DUMP; @@ -5134,10 +5134,11 @@ static int stats_dump_full_sess_to_buffer(struct stream_interface *si, struct st " age=%s)\n", human_time(now.tv_sec - sess->logs.accept_date.tv_sec, 1)); - chunk_appendf(&trash, + if (sess->txn) + chunk_appendf(&trash, " txn=%p flags=0x%x meth=%d status=%d req.st=%s rsp.st=%s waiting=%d\n", - &sess->txn, sess->txn.flags, sess->txn.meth, sess->txn.status, - http_msg_state_str(sess->txn.req.msg_state), http_msg_state_str(sess->txn.rsp.msg_state), !LIST_ISEMPTY(&sess->buffer_wait)); + sess->txn, sess->txn->flags, sess->txn->meth, sess->txn->status, + http_msg_state_str(sess->txn->req.msg_state), http_msg_state_str(sess->txn->rsp.msg_state), !LIST_ISEMPTY(&sess->buffer_wait)); chunk_appendf(&trash, " si[0]=%p (state=%s flags=0x%02x endp0=%s:%p exp=%s, et=0x%03x)\n", @@ -5247,7 +5248,7 @@ static int stats_dump_full_sess_to_buffer(struct stream_interface *si, struct st sess->req.buf, sess->req.buf->data, sess->req.buf->o, (int)(sess->req.buf->p - sess->req.buf->data), - sess->txn.req.next, sess->req.buf->i, + sess->txn ? sess->txn->req.next : 0, sess->req.buf->i, sess->req.buf->size); chunk_appendf(&trash, @@ -5276,7 +5277,7 @@ static int stats_dump_full_sess_to_buffer(struct stream_interface *si, struct st sess->res.buf, sess->res.buf->data, sess->res.buf->o, (int)(sess->res.buf->p - sess->res.buf->data), - sess->txn.rsp.next, sess->res.buf->i, + sess->txn ? sess->txn->rsp.next : 0, sess->res.buf->i, sess->res.buf->size); if (bi_putchk(si_ic(si), &trash) == -1) { diff --git a/src/frontend.c b/src/frontend.c index 3a71bc4ee..3a28d6fd4 100644 --- a/src/frontend.c +++ b/src/frontend.c @@ -127,9 +127,7 @@ int frontend_accept(struct stream *s) * that we may make use of them. This of course includes * (mode == PR_MODE_HTTP). */ - s->txn.hdr_idx.size = global.tune.max_http_hdr; - - if (unlikely((s->txn.hdr_idx.v = pool_alloc2(pool2_hdr_idx)) == NULL)) + if (unlikely(!http_alloc_txn(s))) goto out_free_rspcap; /* no memory */ /* and now initialize the HTTP transaction state */ diff --git a/src/hlua.c b/src/hlua.c index e54c02914..43d9c1b36 100644 --- a/src/hlua.c +++ b/src/hlua.c @@ -2169,13 +2169,7 @@ __LJMP static int hlua_socket_new(lua_State *L) socket->s->res_cap = NULL; /* XXX: See later. */ - socket->s->txn.sessid = NULL; - socket->s->txn.srv_cookie = NULL; - socket->s->txn.cli_cookie = NULL; - socket->s->txn.uri = NULL; - socket->s->txn.hdr_idx.v = NULL; - socket->s->txn.hdr_idx.size = 0; - socket->s->txn.hdr_idx.used = 0; + socket->s->txn = NULL; /* Configure "left" stream interface as applet. This "si" produce * and use the data received from the server. The applet is initialized @@ -2971,17 +2965,20 @@ __LJMP static int hlua_http_get_headers(lua_State *L, struct hlua_txn *htxn, str /* Create the table. */ lua_newtable(L); + if (!htxn->s->txn) + return 1; + /* Build array of headers. */ old_idx = 0; - cur_next = msg->chn->buf->p + hdr_idx_first_pos(&htxn->s->txn.hdr_idx); + cur_next = msg->chn->buf->p + hdr_idx_first_pos(&htxn->s->txn->hdr_idx); while (1) { - cur_idx = htxn->s->txn.hdr_idx.v[old_idx].next; + cur_idx = htxn->s->txn->hdr_idx.v[old_idx].next; if (!cur_idx) break; old_idx = cur_idx; - cur_hdr = &htxn->s->txn.hdr_idx.v[cur_idx]; + cur_hdr = &htxn->s->txn->hdr_idx.v[cur_idx]; cur_ptr = cur_next; cur_next = cur_ptr + cur_hdr->len + cur_hdr->cr + 1; @@ -3021,7 +3018,7 @@ __LJMP static int hlua_http_req_get_headers(lua_State *L) MAY_LJMP(check_args(L, 1, "req_get_headers")); htxn = MAY_LJMP(hlua_checkhttp(L, 1)); - return hlua_http_get_headers(L, htxn, &htxn->s->txn.req); + return hlua_http_get_headers(L, htxn, &htxn->s->txn->req); } __LJMP static int hlua_http_res_get_headers(lua_State *L) @@ -3031,7 +3028,7 @@ __LJMP static int hlua_http_res_get_headers(lua_State *L) MAY_LJMP(check_args(L, 1, "res_get_headers")); htxn = MAY_LJMP(hlua_checkhttp(L, 1)); - return hlua_http_get_headers(L, htxn, &htxn->s->txn.rsp); + return hlua_http_get_headers(L, htxn, &htxn->s->txn->rsp); } /* This function replace full header, or just a value in @@ -3062,7 +3059,7 @@ __LJMP static int hlua_http_req_rep_hdr(lua_State *L) MAY_LJMP(check_args(L, 4, "req_rep_hdr")); htxn = MAY_LJMP(hlua_checkhttp(L, 1)); - return MAY_LJMP(hlua_http_rep_hdr(L, htxn, &htxn->s->txn.req, HTTP_REQ_ACT_REPLACE_HDR)); + return MAY_LJMP(hlua_http_rep_hdr(L, htxn, &htxn->s->txn->req, HTTP_REQ_ACT_REPLACE_HDR)); } __LJMP static int hlua_http_res_rep_hdr(lua_State *L) @@ -3072,7 +3069,7 @@ __LJMP static int hlua_http_res_rep_hdr(lua_State *L) MAY_LJMP(check_args(L, 4, "res_rep_hdr")); htxn = MAY_LJMP(hlua_checkhttp(L, 1)); - return MAY_LJMP(hlua_http_rep_hdr(L, htxn, &htxn->s->txn.rsp, HTTP_RES_ACT_REPLACE_HDR)); + return MAY_LJMP(hlua_http_rep_hdr(L, htxn, &htxn->s->txn->rsp, HTTP_RES_ACT_REPLACE_HDR)); } __LJMP static int hlua_http_req_rep_val(lua_State *L) @@ -3082,7 +3079,7 @@ __LJMP static int hlua_http_req_rep_val(lua_State *L) MAY_LJMP(check_args(L, 4, "req_rep_hdr")); htxn = MAY_LJMP(hlua_checkhttp(L, 1)); - return MAY_LJMP(hlua_http_rep_hdr(L, htxn, &htxn->s->txn.req, HTTP_REQ_ACT_REPLACE_VAL)); + return MAY_LJMP(hlua_http_rep_hdr(L, htxn, &htxn->s->txn->req, HTTP_REQ_ACT_REPLACE_VAL)); } __LJMP static int hlua_http_res_rep_val(lua_State *L) @@ -3092,7 +3089,7 @@ __LJMP static int hlua_http_res_rep_val(lua_State *L) MAY_LJMP(check_args(L, 4, "res_rep_val")); htxn = MAY_LJMP(hlua_checkhttp(L, 1)); - return MAY_LJMP(hlua_http_rep_hdr(L, htxn, &htxn->s->txn.rsp, HTTP_RES_ACT_REPLACE_VAL)); + return MAY_LJMP(hlua_http_rep_hdr(L, htxn, &htxn->s->txn->rsp, HTTP_RES_ACT_REPLACE_VAL)); } /* This function deletes all the occurences of an header. @@ -3103,7 +3100,7 @@ __LJMP static inline int hlua_http_del_hdr(lua_State *L, struct hlua_txn *htxn, size_t len; const char *name = MAY_LJMP(luaL_checklstring(L, 2, &len)); struct hdr_ctx ctx; - struct http_txn *txn = &htxn->s->txn; + struct http_txn *txn = htxn->s->txn; ctx.idx = 0; while (http_find_header2(name, len, msg->chn->buf->p, &txn->hdr_idx, &ctx)) @@ -3118,7 +3115,7 @@ __LJMP static int hlua_http_req_del_hdr(lua_State *L) MAY_LJMP(check_args(L, 2, "req_del_hdr")); htxn = MAY_LJMP(hlua_checkhttp(L, 1)); - return hlua_http_del_hdr(L, htxn, &htxn->s->txn.req); + return hlua_http_del_hdr(L, htxn, &htxn->s->txn->req); } __LJMP static int hlua_http_res_del_hdr(lua_State *L) @@ -3128,7 +3125,7 @@ __LJMP static int hlua_http_res_del_hdr(lua_State *L) MAY_LJMP(check_args(L, 2, "req_del_hdr")); htxn = MAY_LJMP(hlua_checkhttp(L, 1)); - return hlua_http_del_hdr(L, htxn, &htxn->s->txn.rsp); + return hlua_http_del_hdr(L, htxn, &htxn->s->txn->rsp); } /* This function adds an header. It is a wrapper used by @@ -3157,7 +3154,7 @@ __LJMP static inline int hlua_http_add_hdr(lua_State *L, struct hlua_txn *htxn, p++; memcpy(p, value, value_len); - lua_pushboolean(L, http_header_add_tail2(msg, &htxn->s->txn.hdr_idx, + lua_pushboolean(L, http_header_add_tail2(msg, &htxn->s->txn->hdr_idx, trash.str, trash.len) != 0); return 0; @@ -3170,7 +3167,7 @@ __LJMP static int hlua_http_req_add_hdr(lua_State *L) MAY_LJMP(check_args(L, 3, "req_add_hdr")); htxn = MAY_LJMP(hlua_checkhttp(L, 1)); - return hlua_http_add_hdr(L, htxn, &htxn->s->txn.req); + return hlua_http_add_hdr(L, htxn, &htxn->s->txn->req); } __LJMP static int hlua_http_res_add_hdr(lua_State *L) @@ -3180,7 +3177,7 @@ __LJMP static int hlua_http_res_add_hdr(lua_State *L) MAY_LJMP(check_args(L, 3, "res_add_hdr")); htxn = MAY_LJMP(hlua_checkhttp(L, 1)); - return hlua_http_add_hdr(L, htxn, &htxn->s->txn.rsp); + return hlua_http_add_hdr(L, htxn, &htxn->s->txn->rsp); } static int hlua_http_req_set_hdr(lua_State *L) @@ -3190,8 +3187,8 @@ static int hlua_http_req_set_hdr(lua_State *L) MAY_LJMP(check_args(L, 3, "req_set_hdr")); htxn = MAY_LJMP(hlua_checkhttp(L, 1)); - hlua_http_del_hdr(L, htxn, &htxn->s->txn.req); - return hlua_http_add_hdr(L, htxn, &htxn->s->txn.req); + hlua_http_del_hdr(L, htxn, &htxn->s->txn->req); + return hlua_http_add_hdr(L, htxn, &htxn->s->txn->req); } static int hlua_http_res_set_hdr(lua_State *L) @@ -3201,8 +3198,8 @@ static int hlua_http_res_set_hdr(lua_State *L) MAY_LJMP(check_args(L, 3, "res_set_hdr")); htxn = MAY_LJMP(hlua_checkhttp(L, 1)); - hlua_http_del_hdr(L, htxn, &htxn->s->txn.rsp); - return hlua_http_add_hdr(L, htxn, &htxn->s->txn.rsp); + hlua_http_del_hdr(L, htxn, &htxn->s->txn->rsp); + return hlua_http_add_hdr(L, htxn, &htxn->s->txn->rsp); } /* This function set the method. */ @@ -3211,7 +3208,7 @@ static int hlua_http_req_set_meth(lua_State *L) struct hlua_txn *htxn = MAY_LJMP(hlua_checkhttp(L, 1)); size_t name_len; const char *name = MAY_LJMP(luaL_checklstring(L, 2, &name_len)); - struct http_txn *txn = &htxn->s->txn; + struct http_txn *txn = htxn->s->txn; lua_pushboolean(L, http_replace_req_line(0, name, name_len, htxn->p, htxn->s, txn) != -1); return 1; @@ -3223,7 +3220,7 @@ static int hlua_http_req_set_path(lua_State *L) struct hlua_txn *htxn = MAY_LJMP(hlua_checkhttp(L, 1)); size_t name_len; const char *name = MAY_LJMP(luaL_checklstring(L, 2, &name_len)); - struct http_txn *txn = &htxn->s->txn; + struct http_txn *txn = htxn->s->txn; lua_pushboolean(L, http_replace_req_line(1, name, name_len, htxn->p, htxn->s, txn) != -1); return 1; @@ -3235,7 +3232,7 @@ static int hlua_http_req_set_query(lua_State *L) struct hlua_txn *htxn = MAY_LJMP(hlua_checkhttp(L, 1)); size_t name_len; const char *name = MAY_LJMP(luaL_checklstring(L, 2, &name_len)); - struct http_txn *txn = &htxn->s->txn; + struct http_txn *txn = htxn->s->txn; /* Check length. */ if (name_len > trash.size - 1) { @@ -3259,7 +3256,7 @@ static int hlua_http_req_set_uri(lua_State *L) struct hlua_txn *htxn = MAY_LJMP(hlua_checkhttp(L, 1)); size_t name_len; const char *name = MAY_LJMP(luaL_checklstring(L, 2, &name_len)); - struct http_txn *txn = &htxn->s->txn; + struct http_txn *txn = htxn->s->txn; lua_pushboolean(L, http_replace_req_line(3, name, name_len, htxn->p, htxn->s, txn) != -1); return 1; diff --git a/src/log.c b/src/log.c index 949dc29fc..97a20807f 100644 --- a/src/log.c +++ b/src/log.c @@ -922,7 +922,7 @@ int build_logline(struct stream *s, char *dst, size_t maxsize, struct list *list struct session *sess = strm_sess(s); struct proxy *fe = sess->fe; struct proxy *be = s->be; - struct http_txn *txn = &s->txn; + struct http_txn *txn = s->txn; char *uri; struct tm tm; int t_request; @@ -1615,7 +1615,7 @@ void strm_log(struct stream *s) ((s->flags & SF_ERR_MASK) > SF_ERR_LOCAL) || (((s->flags & SF_ERR_MASK) == SF_ERR_NONE) && (s->si[1].conn_retries != s->be->conn_retries)) || - ((sess->fe->mode == PR_MODE_HTTP) && s->txn.status >= 500); + ((sess->fe->mode == PR_MODE_HTTP) && s->txn && s->txn->status >= 500); if (!err && (sess->fe->options2 & PR_O2_NOLOGNORM)) return; diff --git a/src/peers.c b/src/peers.c index 08ccfa9bb..b5d1d8e0b 100644 --- a/src/peers.c +++ b/src/peers.c @@ -1113,7 +1113,6 @@ static struct stream *peer_session_create(struct peer *peer, struct peer_session struct proxy *p = (struct proxy *)l->frontend; /* attached frontend */ struct appctx *appctx; struct stream *s; - struct http_txn *txn; struct task *t; struct connection *conn; @@ -1218,17 +1217,7 @@ static struct stream *peer_session_create(struct peer *peer, struct peer_session s->uniq_id = 0; s->unique_id = NULL; - txn = &s->txn; - /* Those variables will be checked and freed if non-NULL in - * stream.c:stream_free(). It is important that they are - * properly initialized. - */ - txn->sessid = NULL; - txn->srv_cookie = NULL; - txn->cli_cookie = NULL; - txn->uri = NULL; - txn->hdr_idx.v = NULL; - txn->hdr_idx.size = txn->hdr_idx.used = 0; + s->txn = NULL; channel_init(&s->req); s->req.flags |= CF_READ_ATTACHED; /* the producer is already connected */ diff --git a/src/proto_http.c b/src/proto_http.c index 8bd6b5ef5..9b682702f 100644 --- a/src/proto_http.c +++ b/src/proto_http.c @@ -834,7 +834,7 @@ static void http_server_error(struct stream *s, struct stream_interface *si, channel_auto_close(si_ic(si)); channel_auto_read(si_ic(si)); if (status > 0 && msg) { - s->txn.status = status; + s->txn->status = status; bo_inject(si_ic(si), msg->str, msg->len); } if (!(s->flags & SF_ERR_MASK)) @@ -1001,7 +1001,7 @@ void http_perform_server_redirect(struct stream *s, struct stream_interface *si) /* 3: add the request URI. Since it was already forwarded, we need * to temporarily rewind the buffer. */ - txn = &s->txn; + txn = s->txn; b_rew(s->req.buf, rewind = http_hdr_rewind(&txn->req)); path = http_get_path(txn); @@ -1060,7 +1060,7 @@ void http_return_srv_error(struct stream *s, struct stream_interface *si) 503, http_error_message(s, HTTP_ERR_503)); else if (err_type & SI_ET_CONN_ABRT) http_server_error(s, si, SF_ERR_CLICL, SF_FINST_C, - 503, (s->txn.flags & TX_NOT_FIRST) ? NULL : + 503, (s->txn->flags & TX_NOT_FIRST) ? NULL : http_error_message(s, HTTP_ERR_503)); else if (err_type & SI_ET_QUEUE_TO) http_server_error(s, si, SF_ERR_SRVTO, SF_FINST_Q, @@ -1070,7 +1070,7 @@ void http_return_srv_error(struct stream *s, struct stream_interface *si) 503, http_error_message(s, HTTP_ERR_503)); else if (err_type & SI_ET_CONN_TO) http_server_error(s, si, SF_ERR_SRVTO, SF_FINST_C, - 503, (s->txn.flags & TX_NOT_FIRST) ? NULL : + 503, (s->txn->flags & TX_NOT_FIRST) ? NULL : http_error_message(s, HTTP_ERR_503)); else if (err_type & SI_ET_CONN_ERR) http_server_error(s, si, SF_ERR_SRVCL, SF_FINST_C, @@ -1078,7 +1078,7 @@ void http_return_srv_error(struct stream *s, struct stream_interface *si) http_error_message(s, HTTP_ERR_503)); else if (err_type & SI_ET_CONN_RES) http_server_error(s, si, SF_ERR_RESOURCE, SF_FINST_C, - 503, (s->txn.flags & TX_NOT_FIRST) ? NULL : + 503, (s->txn->flags & TX_NOT_FIRST) ? NULL : http_error_message(s, HTTP_ERR_503)); else /* SI_ET_CONN_OTHER and others */ http_server_error(s, si, SF_ERR_INTERNAL, SF_FINST_C, @@ -1437,7 +1437,7 @@ int get_http_auth(struct stream *s) { - struct http_txn *txn = &s->txn; + struct http_txn *txn = s->txn; struct chunk auth_method; struct hdr_ctx ctx; char *h, *p; @@ -2240,7 +2240,7 @@ int parse_qvalue(const char *qvalue, const char **end) */ int select_compression_request_header(struct stream *s, struct buffer *req) { - struct http_txn *txn = &s->txn; + struct http_txn *txn = s->txn; struct http_msg *msg = &txn->req; struct hdr_ctx ctx; struct comp_algo *comp_algo = NULL; @@ -2351,7 +2351,7 @@ int select_compression_request_header(struct stream *s, struct buffer *req) */ int select_compression_response_header(struct stream *s, struct buffer *res) { - struct http_txn *txn = &s->txn; + struct http_txn *txn = s->txn; struct http_msg *msg = &txn->rsp; struct hdr_ctx ctx; struct comp_type *comp_type; @@ -2550,7 +2550,7 @@ int http_wait_for_request(struct stream *s, struct channel *req, int an_bit) int cur_idx; int use_close_only; struct session *sess = s->sess; - struct http_txn *txn = &s->txn; + struct http_txn *txn = s->txn; struct http_msg *msg = &txn->req; struct hdr_ctx ctx; @@ -3103,7 +3103,7 @@ int http_handle_stats(struct stream *s, struct channel *req) { struct stats_admin_rule *stats_admin_rule; struct stream_interface *si = &s->si[1]; - struct http_txn *txn = &s->txn; + struct http_txn *txn = s->txn; struct http_msg *msg = &txn->req; struct uri_auth *uri_auth = s->be->uri_auth; const char *uri, *h, *lookup; @@ -3114,7 +3114,7 @@ int http_handle_stats(struct stream *s, struct channel *req) appctx->st1 = appctx->st2 = 0; appctx->ctx.stats.st_code = STAT_STATUS_INIT; appctx->ctx.stats.flags |= STAT_FMT_HTML; /* assume HTML mode by default */ - if ((msg->flags & HTTP_MSGF_VER_11) && (s->txn.meth != HTTP_METH_HEAD)) + if ((msg->flags & HTTP_MSGF_VER_11) && (s->txn->meth != HTTP_METH_HEAD)) appctx->ctx.stats.flags |= STAT_CHUNKED; uri = msg->chn->buf->p + msg->sl.rq.u; @@ -3197,7 +3197,7 @@ int http_handle_stats(struct stream *s, struct channel *req) int ret = 1; if (stats_admin_rule->cond) { - ret = acl_exec_cond(stats_admin_rule->cond, s->be, s, &s->txn, SMP_OPT_DIR_REQ|SMP_OPT_FINAL); + ret = acl_exec_cond(stats_admin_rule->cond, s->be, s, s->txn, SMP_OPT_DIR_REQ|SMP_OPT_FINAL); ret = acl_pass(ret); if (stats_admin_rule->cond->pol == ACL_COND_UNLESS) ret = !ret; @@ -3258,7 +3258,7 @@ int http_transform_header_str(struct stream* s, struct http_msg *msg, { struct hdr_ctx ctx; char *buf = msg->chn->buf->p; - struct hdr_idx *idx = &s->txn.hdr_idx; + struct hdr_idx *idx = &s->txn->hdr_idx; int (*http_find_hdr_func)(const char *name, int len, char *sol, struct hdr_idx *idx, struct hdr_ctx *ctx); struct chunk *output = get_trash_chunk(); @@ -3565,7 +3565,7 @@ http_req_get_intercept_rule(struct proxy *px, struct list *rules, struct stream void *ptr; t = rule->act_prm.trk_ctr.table.t; - key = stktable_fetch_key(t, s->be, s, &s->txn, SMP_OPT_DIR_REQ | SMP_OPT_FINAL, rule->act_prm.trk_ctr.expr, NULL); + key = stktable_fetch_key(t, s->be, s, s->txn, SMP_OPT_DIR_REQ | SMP_OPT_FINAL, rule->act_prm.trk_ctr.expr, NULL); if (key && (ts = stktable_get_entry(t, key))) { stream_track_stkctr(&s->stkctr[http_req_trk_idx(rule->action)], t, ts); @@ -4073,7 +4073,7 @@ static int http_apply_redirect_rule(struct redirect_rule *rule, struct stream *s int http_process_req_common(struct stream *s, struct channel *req, int an_bit, struct proxy *px) { struct session *sess = s->sess; - struct http_txn *txn = &s->txn; + struct http_txn *txn = s->txn; struct http_msg *msg = &txn->req; struct redirect_rule *rule; struct cond_wordlist *wl; @@ -4314,7 +4314,7 @@ int http_process_req_common(struct stream *s, struct channel *req, int an_bit, s int http_process_request(struct stream *s, struct channel *req, int an_bit) { struct session *sess = s->sess; - struct http_txn *txn = &s->txn; + struct http_txn *txn = s->txn; struct http_msg *msg = &txn->req; struct connection *cli_conn = objt_conn(s->si[1].end); @@ -4592,7 +4592,7 @@ int http_process_request(struct stream *s, struct channel *req, int an_bit) * that parameter. This will be done in another analyser. */ if (!(s->flags & (SF_ASSIGNED|SF_DIRECT)) && - s->txn.meth == HTTP_METH_POST && s->be->url_param_name != NULL && + s->txn->meth == HTTP_METH_POST && s->be->url_param_name != NULL && (msg->flags & (HTTP_MSGF_CNT_LEN|HTTP_MSGF_TE_CHNK))) { channel_dont_connect(req); req->analysers |= AN_REQ_HTTP_BODY; @@ -4661,7 +4661,7 @@ int http_process_request(struct stream *s, struct channel *req, int an_bit) */ int http_process_tarpit(struct stream *s, struct channel *req, int an_bit) { - struct http_txn *txn = &s->txn; + struct http_txn *txn = s->txn; /* This connection is being tarpitted. The CLIENT side has * already set the connect expiration date to the right @@ -4707,8 +4707,8 @@ int http_process_tarpit(struct stream *s, struct channel *req, int an_bit) int http_wait_for_request_body(struct stream *s, struct channel *req, int an_bit) { struct session *sess = s->sess; - struct http_txn *txn = &s->txn; - struct http_msg *msg = &s->txn.req; + struct http_txn *txn = s->txn; + struct http_msg *msg = &s->txn->req; /* We have to parse the HTTP request body to find any required data. * "balance url_param check_post" should have been the only way to get @@ -4903,7 +4903,7 @@ int http_send_name_header(struct http_txn *txn, struct proxy* be, const char* sr */ void http_end_txn_clean_session(struct stream *s) { - int prev_status = s->txn.status; + int prev_status = s->txn->status; struct proxy *fe = strm_sess(s)->fe; /* FIXME: We need a more portable way of releasing a backend's and a @@ -4915,7 +4915,7 @@ void http_end_txn_clean_session(struct stream *s) /* unless we're doing keep-alive, we want to quickly close the connection * to the server. */ - if (((s->txn.flags & TX_CON_WANT_MSK) != TX_CON_WANT_KAL) || + if (((s->txn->flags & TX_CON_WANT_MSK) != TX_CON_WANT_KAL) || !si_conn_ready(&s->si[1])) { s->si[1].flags |= SI_FL_NOLINGER | SI_FL_NOHALF; si_shutr(&s->si[1]); @@ -4931,10 +4931,10 @@ void http_end_txn_clean_session(struct stream *s) s->logs.t_close = tv_ms_elapsed(&s->logs.tv_accept, &now); stream_process_counters(s); - if (s->txn.status) { + if (s->txn->status) { int n; - n = s->txn.status / 100; + n = s->txn->status / 100; if (n < 1 || n > 5) n = 0; @@ -4997,7 +4997,7 @@ void http_end_txn_clean_session(struct stream *s) /* only release our endpoint if we don't intend to reuse the * connection. */ - if (((s->txn.flags & TX_CON_WANT_MSK) != TX_CON_WANT_KAL) || + if (((s->txn->flags & TX_CON_WANT_MSK) != TX_CON_WANT_KAL) || !si_conn_ready(&s->si[1])) { si_release_endpoint(&s->si[1]); } @@ -5013,9 +5013,9 @@ void http_end_txn_clean_session(struct stream *s) s->flags &= ~(SF_CURR_SESS|SF_REDIRECTABLE|SF_SRV_REUSED); s->flags &= ~(SF_ERR_MASK|SF_FINST_MASK|SF_REDISP); - s->txn.meth = 0; + s->txn->meth = 0; http_reset_txn(s); - s->txn.flags |= TX_NOT_FIRST | TX_WAIT_NEXT_RQ; + s->txn->flags |= TX_NOT_FIRST | TX_WAIT_NEXT_RQ; if (prev_status == 401 || prev_status == 407) { /* In HTTP keep-alive mode, if we receive a 401, we still have @@ -5025,7 +5025,7 @@ void http_end_txn_clean_session(struct stream *s) * an opportunity for sending the challenge to the proper place, * it's better to do it (at least it helps with debugging). */ - s->txn.flags |= TX_PREFER_LAST; + s->txn->flags |= TX_PREFER_LAST; } if (fe->options2 & PR_O2_INDEPSTR) @@ -5074,7 +5074,7 @@ void http_end_txn_clean_session(struct stream *s) int http_sync_req_state(struct stream *s) { struct channel *chn = &s->req; - struct http_txn *txn = &s->txn; + struct http_txn *txn = s->txn; unsigned int old_flags = chn->flags; unsigned int old_state = txn->req.msg_state; @@ -5212,7 +5212,7 @@ int http_sync_req_state(struct stream *s) int http_sync_res_state(struct stream *s) { struct channel *chn = &s->res; - struct http_txn *txn = &s->txn; + struct http_txn *txn = s->txn; unsigned int old_flags = chn->flags; unsigned int old_state = txn->rsp.msg_state; @@ -5340,7 +5340,7 @@ int http_sync_res_state(struct stream *s) */ int http_resync_states(struct stream *s) { - struct http_txn *txn = &s->txn; + struct http_txn *txn = s->txn; int old_req_state = txn->req.msg_state; int old_res_state = txn->rsp.msg_state; @@ -5417,8 +5417,8 @@ int http_resync_states(struct stream *s) int http_request_forward_body(struct stream *s, struct channel *req, int an_bit) { struct session *sess = s->sess; - struct http_txn *txn = &s->txn; - struct http_msg *msg = &s->txn.req; + struct http_txn *txn = s->txn; + struct http_msg *msg = &s->txn->req; if (unlikely(msg->msg_state < HTTP_MSG_BODY)) return 0; @@ -5589,7 +5589,7 @@ int http_request_forward_body(struct stream *s, struct channel *req, int an_bit) channel_auto_read(req); channel_auto_close(req); } - else if (s->txn.meth == HTTP_METH_POST) { + else if (s->txn->meth == HTTP_METH_POST) { /* POST requests may require to read extra CRLF * sent by broken browsers and which could cause * an RST to be sent upon close on some systems @@ -5722,7 +5722,7 @@ int http_request_forward_body(struct stream *s, struct channel *req, int an_bit) int http_wait_for_response(struct stream *s, struct channel *rep, int an_bit) { struct session *sess = s->sess; - struct http_txn *txn = &s->txn; + struct http_txn *txn = s->txn; struct http_msg *msg = &txn->rsp; struct hdr_ctx ctx; int use_close_only; @@ -6290,7 +6290,7 @@ int http_wait_for_response(struct stream *s, struct channel *rep, int an_bit) int http_process_res_common(struct stream *s, struct channel *rep, int an_bit, struct proxy *px) { struct session *sess = s->sess; - struct http_txn *txn = &s->txn; + struct http_txn *txn = s->txn; struct http_msg *msg = &txn->rsp; struct proxy *cur_proxy; struct cond_wordlist *wl; @@ -6630,8 +6630,8 @@ int http_process_res_common(struct stream *s, struct channel *rep, int an_bit, s int http_response_forward_body(struct stream *s, struct channel *res, int an_bit) { struct session *sess = s->sess; - struct http_txn *txn = &s->txn; - struct http_msg *msg = &s->txn.rsp; + struct http_txn *txn = s->txn; + struct http_msg *msg = &s->txn->rsp; static struct buffer *tmpbuf = &buf_empty; int compressing = 0; int ret; @@ -6947,7 +6947,7 @@ int apply_filter_to_req_headers(struct stream *s, struct channel *req, struct hd { char *cur_ptr, *cur_end, *cur_next; int cur_idx, old_idx, last_hdr; - struct http_txn *txn = &s->txn; + struct http_txn *txn = s->txn; struct hdr_idx_elem *cur_hdr; int delta; @@ -7059,7 +7059,7 @@ int apply_filter_to_req_line(struct stream *s, struct channel *req, struct hdr_e { char *cur_ptr, *cur_end; int done; - struct http_txn *txn = &s->txn; + struct http_txn *txn = s->txn; int delta; if (unlikely(txn->flags & (TX_CLDENY | TX_CLTARPIT))) @@ -7151,7 +7151,7 @@ int apply_filter_to_req_line(struct stream *s, struct channel *req, struct hdr_e */ int apply_filters_to_request(struct stream *s, struct channel *req, struct proxy *px) { - struct http_txn *txn = &s->txn; + struct http_txn *txn = s->txn; struct hdr_exp *exp; for (exp = px->req_exp; exp; exp = exp->next) { @@ -7207,7 +7207,7 @@ int apply_filters_to_request(struct stream *s, struct channel *req, struct proxy * If the server is found, it's assigned to the stream. */ void manage_client_side_appsession(struct stream *s, const char *buf, int len) { - struct http_txn *txn = &s->txn; + struct http_txn *txn = s->txn; appsess *asession = NULL; char *sessid_temp = NULL; @@ -7359,7 +7359,7 @@ int del_hdr_value(struct buffer *buf, char **from, char *next) */ void manage_client_side_cookies(struct stream *s, struct channel *req) { - struct http_txn *txn = &s->txn; + struct http_txn *txn = s->txn; struct session *sess = s->sess; int preserve_hdr; int cur_idx, old_idx; @@ -7811,7 +7811,7 @@ int apply_filter_to_resp_headers(struct stream *s, struct channel *rtr, struct h { char *cur_ptr, *cur_end, *cur_next; int cur_idx, old_idx, last_hdr; - struct http_txn *txn = &s->txn; + struct http_txn *txn = s->txn; struct hdr_idx_elem *cur_hdr; int delta; @@ -7902,7 +7902,7 @@ int apply_filter_to_sts_line(struct stream *s, struct channel *rtr, struct hdr_e { char *cur_ptr, *cur_end; int done; - struct http_txn *txn = &s->txn; + struct http_txn *txn = s->txn; int delta; @@ -7975,7 +7975,7 @@ int apply_filter_to_sts_line(struct stream *s, struct channel *rtr, struct hdr_e */ int apply_filters_to_response(struct stream *s, struct channel *rtr, struct proxy *px) { - struct http_txn *txn = &s->txn; + struct http_txn *txn = s->txn; struct hdr_exp *exp; for (exp = px->rsp_exp; exp; exp = exp->next) { @@ -8033,7 +8033,7 @@ int apply_filters_to_response(struct stream *s, struct channel *rtr, struct prox */ void manage_server_side_cookies(struct stream *s, struct channel *res) { - struct http_txn *txn = &s->txn; + struct http_txn *txn = s->txn; struct session *sess = s->sess; struct server *srv; int is_cookie2; @@ -8397,7 +8397,7 @@ void manage_server_side_cookies(struct stream *s, struct channel *res) */ void check_response_for_cacheability(struct stream *s, struct channel *rtr) { - struct http_txn *txn = &s->txn; + struct http_txn *txn = s->txn; char *p1, *p2; char *cur_ptr, *cur_end, *cur_next; @@ -8493,7 +8493,7 @@ void get_srv_from_appsession(struct stream *s, const char *begin, int len) int mode = s->be->options2 & PR_O2_AS_M_ANY; if (s->be->appsession_name == NULL || - (s->txn.meth != HTTP_METH_GET && s->txn.meth != HTTP_METH_POST && s->txn.meth != HTTP_METH_HEAD)) { + (s->txn->meth != HTTP_METH_GET && s->txn->meth != HTTP_METH_POST && s->txn->meth != HTTP_METH_HEAD)) { return; } @@ -8625,7 +8625,7 @@ void http_capture_bad_message(struct error_snapshot *es, struct stream *s, es->ev_id = error_snapshot_id++; es->b_flags = chn->flags; es->s_flags = s->flags; - es->t_flags = s->txn.flags; + es->t_flags = s->txn->flags; es->m_flags = msg->flags; es->b_out = chn->buf->o; es->b_wrap = chn->buf->data + chn->buf->size - chn->buf->p; @@ -8789,6 +8789,34 @@ void debug_hdr(const char *dir, struct stream *s, const char *start, const char shut_your_big_mouth_gcc(write(1, trash.str, trash.len)); } + +/* Allocate a new HTTP transaction for stream unless there is one already. + * The hdr_idx is allocated as well. In case of allocation failure, everything + * allocated is freed and NULL is returned. Otherwise the new transaction is + * assigned to the stream and returned. + */ +struct http_txn *http_alloc_txn(struct stream *s) +{ + struct http_txn *txn = s->txn; + + if (txn) + return txn; + + txn = pool_alloc2(pool2_http_txn); + if (!txn) + return txn; + + txn->hdr_idx.size = global.tune.max_http_hdr; + txn->hdr_idx.v = pool_alloc2(pool2_hdr_idx); + if (!txn->hdr_idx.v) { + pool_free2(pool2_http_txn, txn); + return NULL; + } + + s->txn = txn; + return txn; +} + /* * Initialize a new HTTP transaction for stream . It is assumed that all * the required fields are properly allocated and that we only need to (re)init @@ -8796,7 +8824,7 @@ void debug_hdr(const char *dir, struct stream *s, const char *start, const char */ void http_init_txn(struct stream *s) { - struct http_txn *txn = &s->txn; + struct http_txn *txn = s->txn; struct proxy *fe = strm_sess(s)->fe; txn->flags = 0; @@ -8805,6 +8833,11 @@ void http_init_txn(struct stream *s) txn->cookie_first_date = 0; txn->cookie_last_date = 0; + txn->sessid = NULL; + txn->srv_cookie = NULL; + txn->cli_cookie = NULL; + txn->uri = NULL; + txn->req.flags = 0; txn->req.sol = txn->req.eol = txn->req.eoh = 0; /* relative to the buffer */ txn->req.next = 0; @@ -8833,7 +8866,7 @@ void http_init_txn(struct stream *s) /* to be used at the end of a transaction */ void http_end_txn(struct stream *s) { - struct http_txn *txn = &s->txn; + struct http_txn *txn = s->txn; struct proxy *fe = strm_sess(s)->fe; /* release any possible compression context */ @@ -9876,8 +9909,10 @@ smp_prefetch_http(struct proxy *px, struct stream *s, void *l7, unsigned int opt struct http_txn *txn = l7; struct http_msg *msg = &txn->req; - /* Note: hdr_idx.v cannot be NULL in this ACL because the ACL is tagged - * as a layer7 ACL, which involves automatic allocation of hdr_idx. + /* Note: this function may only be used from places where + * http_init_txn() has already been done, and implies that , + * , and are properly set. An extra check protects + * against an eventual mistake in the fetch capability matrix. */ if (unlikely(!s || !txn)) @@ -10668,7 +10703,7 @@ smp_fetch_http_first_req(struct proxy *px, struct stream *s, void *l7, unsigned const struct arg *args, struct sample *smp, const char *kw, void *private) { smp->type = SMP_T_BOOL; - smp->data.uint = !(s->txn.flags & TX_NOT_FIRST); + smp->data.uint = !(s->txn->flags & TX_NOT_FIRST); return 1; } @@ -10687,7 +10722,7 @@ smp_fetch_http_auth(struct proxy *px, struct stream *l4, void *l7, unsigned int return 0; smp->type = SMP_T_BOOL; - smp->data.uint = check_user(args->data.usr, l4->txn.auth.user, l4->txn.auth.pass); + smp->data.uint = check_user(args->data.usr, l4->txn->auth.user, l4->txn->auth.pass); return 1; } @@ -10709,7 +10744,7 @@ smp_fetch_http_auth_grp(struct proxy *px, struct stream *l4, void *l7, unsigned * report that it unconditionally does not match. Otherwise we return * a string containing the username. */ - if (!check_user(args->data.usr, l4->txn.auth.user, l4->txn.auth.pass)) + if (!check_user(args->data.usr, l4->txn->auth.user, l4->txn->auth.pass)) return 0; /* pat_match_auth() will need the user list */ @@ -10717,8 +10752,8 @@ smp_fetch_http_auth_grp(struct proxy *px, struct stream *l4, void *l7, unsigned smp->type = SMP_T_STR; smp->flags = SMP_F_CONST; - smp->data.str.str = l4->txn.auth.user; - smp->data.str.len = strlen(l4->txn.auth.user); + smp->data.str.str = l4->txn->auth.user; + smp->data.str.len = strlen(l4->txn->auth.user); return 1; } diff --git a/src/proto_tcp.c b/src/proto_tcp.c index e77edc43b..af61c54dc 100644 --- a/src/proto_tcp.c +++ b/src/proto_tcp.c @@ -1134,7 +1134,7 @@ int tcp_inspect_request(struct stream *s, struct channel *req, int an_bit) enum acl_test_res ret = ACL_TEST_PASS; if (rule->cond) { - ret = acl_exec_cond(rule->cond, s->be, s, &s->txn, SMP_OPT_DIR_REQ | partial); + ret = acl_exec_cond(rule->cond, s->be, s, s->txn, SMP_OPT_DIR_REQ | partial); if (ret == ACL_TEST_MISS) goto missing_data; @@ -1175,7 +1175,7 @@ int tcp_inspect_request(struct stream *s, struct channel *req, int an_bit) continue; t = rule->act_prm.trk_ctr.table.t; - key = stktable_fetch_key(t, s->be, s, &s->txn, SMP_OPT_DIR_REQ | partial, rule->act_prm.trk_ctr.expr, &smp); + key = stktable_fetch_key(t, s->be, s, s->txn, SMP_OPT_DIR_REQ | partial, rule->act_prm.trk_ctr.expr, &smp); if ((smp.flags & SMP_F_MAY_CHANGE) && !(partial & SMP_OPT_FINAL)) goto missing_data; /* key might appear later */ @@ -1193,7 +1193,7 @@ int tcp_inspect_request(struct stream *s, struct channel *req, int an_bit) char **cap = s->req_cap; int len; - key = sample_fetch_string(s->be, s, &s->txn, SMP_OPT_DIR_REQ | partial, rule->act_prm.cap.expr); + key = sample_fetch_string(s->be, s, s->txn, SMP_OPT_DIR_REQ | partial, rule->act_prm.cap.expr); if (!key) continue; @@ -1292,7 +1292,7 @@ int tcp_inspect_response(struct stream *s, struct channel *rep, int an_bit) enum acl_test_res ret = ACL_TEST_PASS; if (rule->cond) { - ret = acl_exec_cond(rule->cond, s->be, s, &s->txn, SMP_OPT_DIR_RES | partial); + ret = acl_exec_cond(rule->cond, s->be, s, s->txn, SMP_OPT_DIR_RES | partial); if (ret == ACL_TEST_MISS) { /* just set the analyser timeout once at the beginning of the response */ if (!tick_isset(rep->analyse_exp) && s->be->tcp_rep.inspect_delay) @@ -1407,7 +1407,7 @@ int tcp_exec_req_rules(struct stream *s) continue; t = rule->act_prm.trk_ctr.table.t; - key = stktable_fetch_key(t, s->be, s, &s->txn, SMP_OPT_DIR_REQ|SMP_OPT_FINAL, rule->act_prm.trk_ctr.expr, NULL); + key = stktable_fetch_key(t, s->be, s, s->txn, SMP_OPT_DIR_REQ|SMP_OPT_FINAL, rule->act_prm.trk_ctr.expr, NULL); if (key && (ts = stktable_get_entry(t, key))) stream_track_stkctr(&s->stkctr[tcp_trk_idx(rule->action)], t, ts); diff --git a/src/proxy.c b/src/proxy.c index 9b23db025..f55aaa48a 100644 --- a/src/proxy.c +++ b/src/proxy.c @@ -940,39 +940,40 @@ int stream_set_backend(struct stream *s, struct proxy *be) if (be->options2 & PR_O2_INDEPSTR) s->si[1].flags |= SI_FL_INDEP_STR; - if (be->options2 & PR_O2_RSPBUG_OK) - s->txn.rsp.err_pos = -1; /* let buggy responses pass */ - s->flags |= SF_BE_ASSIGNED; - /* If the target backend requires HTTP processing, we have to allocate - * a struct hdr_idx for it if we did not have one. + * the HTTP transaction and hdr_idx if we did not have one. */ - if (unlikely(!s->txn.hdr_idx.v && be->http_needed)) { - s->txn.hdr_idx.size = global.tune.max_http_hdr; - if ((s->txn.hdr_idx.v = pool_alloc2(pool2_hdr_idx)) == NULL) + if (unlikely(!s->txn && be->http_needed)) { + if (unlikely(!http_alloc_txn(s))) return 0; /* not enough memory */ /* and now initialize the HTTP transaction state */ http_init_txn(s); } - /* If we chain to an HTTP backend running a different HTTP mode, we - * have to re-adjust the desired keep-alive/close mode to accommodate - * both the frontend's and the backend's modes. - */ - if (strm_sess(s)->fe->mode == PR_MODE_HTTP && be->mode == PR_MODE_HTTP && - ((strm_sess(s)->fe->options & PR_O_HTTP_MODE) != (be->options & PR_O_HTTP_MODE))) - http_adjust_conn_mode(s, &s->txn, &s->txn.req); + if (s->txn) { + if (be->options2 & PR_O2_RSPBUG_OK) + s->txn->rsp.err_pos = -1; /* let buggy responses pass */ - /* If an LB algorithm needs to access some pre-parsed body contents, - * we must not start to forward anything until the connection is - * confirmed otherwise we'll lose the pointer to these data and - * prevent the hash from being doable again after a redispatch. - */ - if (be->mode == PR_MODE_HTTP && - (be->lbprm.algo & (BE_LB_KIND | BE_LB_PARM)) == (BE_LB_KIND_HI | BE_LB_HASH_PRM)) - s->txn.req.flags |= HTTP_MSGF_WAIT_CONN; + /* If we chain to an HTTP backend running a different HTTP mode, we + * have to re-adjust the desired keep-alive/close mode to accommodate + * both the frontend's and the backend's modes. + */ + if (strm_sess(s)->fe->mode == PR_MODE_HTTP && be->mode == PR_MODE_HTTP && + ((strm_sess(s)->fe->options & PR_O_HTTP_MODE) != (be->options & PR_O_HTTP_MODE))) + http_adjust_conn_mode(s, s->txn, &s->txn->req); + /* If an LB algorithm needs to access some pre-parsed body contents, + * we must not start to forward anything until the connection is + * confirmed otherwise we'll lose the pointer to these data and + * prevent the hash from being doable again after a redispatch. + */ + if (be->mode == PR_MODE_HTTP && + (be->lbprm.algo & (BE_LB_KIND | BE_LB_PARM)) == (BE_LB_KIND_HI | BE_LB_HASH_PRM)) + s->txn->req.flags |= HTTP_MSGF_WAIT_CONN; + } + + s->flags |= SF_BE_ASSIGNED; if (be->options2 & PR_O2_NODELAY) { s->req.flags |= CF_NEVER_WAIT; s->res.flags |= CF_NEVER_WAIT; diff --git a/src/stream.c b/src/stream.c index cd0f8bd9e..f12b2c36a 100644 --- a/src/stream.c +++ b/src/stream.c @@ -425,7 +425,6 @@ int stream_complete(struct stream *s) struct session *sess = s->sess; struct listener *l = sess->listener; struct proxy *p = sess->fe; - struct http_txn *txn; struct task *t = s->task; struct connection *conn = __objt_conn(s->target); int ret; @@ -531,23 +530,7 @@ int stream_complete(struct stream *s) s->res.wex = TICK_ETERNITY; s->res.analyse_exp = TICK_ETERNITY; - txn = &s->txn; - /* Those variables will be checked and freed if non-NULL in - * stream.c:stream_free(). It is important that they are - * properly initialized. - */ - txn->sessid = NULL; - txn->srv_cookie = NULL; - txn->cli_cookie = NULL; - txn->uri = NULL; - txn->hdr_idx.v = NULL; - txn->hdr_idx.size = txn->hdr_idx.used = 0; - txn->flags = 0; - txn->req.flags = 0; - txn->rsp.flags = 0; - /* the HTTP messages need to know what buffer they're associated with */ - txn->req.chn = &s->req; - txn->rsp.chn = &s->res; + s->txn = NULL; HLUA_INIT(&s->hlua); @@ -591,7 +574,6 @@ int stream_complete(struct stream *s) */ static void stream_free(struct stream *s) { - struct http_txn *txn = &s->txn; struct session *sess = strm_sess(s); struct proxy *fe = sess->fe; struct bref *bref, *back; @@ -636,7 +618,8 @@ static void stream_free(struct stream *s) stream_offer_buffers(); hlua_ctx_destroy(&s->hlua); - http_end_txn(s); + if (s->txn) + http_end_txn(s); /* ensure the client-side transport layer is destroyed */ if (cli_conn) @@ -649,7 +632,12 @@ static void stream_free(struct stream *s) s->store[i].ts = NULL; } - pool_free2(pool2_hdr_idx, txn->hdr_idx.v); + if (s->txn) { + pool_free2(pool2_hdr_idx, s->txn->hdr_idx.v); + pool_free2(pool2_http_txn, s->txn); + s->txn = NULL; + } + if (fe) { pool_free2(fe->rsp_cap_pool, s->res_cap); pool_free2(fe->req_cap_pool, s->req_cap); @@ -1080,7 +1068,6 @@ static void sess_establish(struct stream *s) } } else { - s->txn.rsp.msg_state = HTTP_MSG_RPBEFORE; rep->flags |= CF_READ_DONTWAIT; /* a single read is enough to get response headers */ } @@ -1404,7 +1391,7 @@ static int process_switching_rules(struct stream *s, struct channel *req, int an int ret = 1; if (rule->cond) { - ret = acl_exec_cond(rule->cond, fe, s, &s->txn, SMP_OPT_DIR_REQ|SMP_OPT_FINAL); + ret = acl_exec_cond(rule->cond, fe, s, s->txn, SMP_OPT_DIR_REQ|SMP_OPT_FINAL); ret = acl_pass(ret); if (rule->cond->pol == ACL_COND_UNLESS) ret = !ret; @@ -1457,7 +1444,7 @@ static int process_switching_rules(struct stream *s, struct channel *req, int an int ret = 1; if (prst_rule->cond) { - ret = acl_exec_cond(prst_rule->cond, s->be, s, &s->txn, SMP_OPT_DIR_REQ|SMP_OPT_FINAL); + ret = acl_exec_cond(prst_rule->cond, s->be, s, s->txn, SMP_OPT_DIR_REQ|SMP_OPT_FINAL); ret = acl_pass(ret); if (prst_rule->cond->pol == ACL_COND_UNLESS) ret = !ret; @@ -1486,7 +1473,8 @@ static int process_switching_rules(struct stream *s, struct channel *req, int an if (!(s->flags & SF_FINST_MASK)) s->flags |= SF_FINST_R; - s->txn.status = 500; + if (s->txn) + s->txn->status = 500; s->req.analysers = 0; s->req.analyse_exp = TICK_ETERNITY; return 0; @@ -1514,7 +1502,7 @@ static int process_server_rules(struct stream *s, struct channel *req, int an_bi list_for_each_entry(rule, &px->server_rules, list) { int ret; - ret = acl_exec_cond(rule->cond, s->be, s, &s->txn, SMP_OPT_DIR_REQ|SMP_OPT_FINAL); + ret = acl_exec_cond(rule->cond, s->be, s, s->txn, SMP_OPT_DIR_REQ|SMP_OPT_FINAL); ret = acl_pass(ret); if (rule->cond->pol == ACL_COND_UNLESS) ret = !ret; @@ -1579,7 +1567,7 @@ static int process_sticking_rules(struct stream *s, struct channel *req, int an_ continue; if (rule->cond) { - ret = acl_exec_cond(rule->cond, px, s, &s->txn, SMP_OPT_DIR_REQ|SMP_OPT_FINAL); + ret = acl_exec_cond(rule->cond, px, s, s->txn, SMP_OPT_DIR_REQ|SMP_OPT_FINAL); ret = acl_pass(ret); if (rule->cond->pol == ACL_COND_UNLESS) ret = !ret; @@ -1588,7 +1576,7 @@ static int process_sticking_rules(struct stream *s, struct channel *req, int an_ if (ret) { struct stktable_key *key; - key = stktable_fetch_key(rule->table.t, px, s, &s->txn, SMP_OPT_DIR_REQ|SMP_OPT_FINAL, rule->expr, NULL); + key = stktable_fetch_key(rule->table.t, px, s, s->txn, SMP_OPT_DIR_REQ|SMP_OPT_FINAL, rule->expr, NULL); if (!key) continue; @@ -1682,7 +1670,7 @@ static int process_store_rules(struct stream *s, struct channel *rep, int an_bit continue; if (rule->cond) { - ret = acl_exec_cond(rule->cond, px, s, &s->txn, SMP_OPT_DIR_RES|SMP_OPT_FINAL); + ret = acl_exec_cond(rule->cond, px, s, s->txn, SMP_OPT_DIR_RES|SMP_OPT_FINAL); ret = acl_pass(ret); if (rule->cond->pol == ACL_COND_UNLESS) ret = !ret; @@ -1691,7 +1679,7 @@ static int process_store_rules(struct stream *s, struct channel *rep, int an_bit if (ret) { struct stktable_key *key; - key = stktable_fetch_key(rule->table.t, px, s, &s->txn, SMP_OPT_DIR_RES|SMP_OPT_FINAL, rule->expr, NULL); + key = stktable_fetch_key(rule->table.t, px, s, s->txn, SMP_OPT_DIR_RES|SMP_OPT_FINAL, rule->expr, NULL); if (!key) continue; @@ -1780,7 +1768,8 @@ struct task *process_stream(struct task *t) // si_f->state, si_b->state, si_b->err_type, req->flags, res->flags); /* this data may be no longer valid, clear it */ - memset(&s->txn.auth, 0, sizeof(s->txn.auth)); + if (s->txn) + memset(&s->txn->auth, 0, sizeof(s->txn->auth)); /* This flag must explicitly be set every time */ req->flags &= ~(CF_READ_NOEXP|CF_WAKE_WRITE); @@ -2445,7 +2434,7 @@ struct task *process_stream(struct task *t) (s->be->server_id_hdr_name != NULL) && (s->be->mode == PR_MODE_HTTP) && objt_server(s->target)) { - http_send_name_header(&s->txn, s->be, objt_server(s->target)->id); + http_send_name_header(s->txn, s->be, objt_server(s->target)->id); } srv = objt_server(s->target); @@ -2722,10 +2711,10 @@ struct task *process_stream(struct task *t) s->logs.t_close = tv_ms_elapsed(&s->logs.tv_accept, &now); stream_process_counters(s); - if (s->txn.status) { + if (s->txn && s->txn->status) { int n; - n = s->txn.status / 100; + n = s->txn->status / 100; if (n < 1 || n > 5) n = 0;