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);
extern const struct http_method_name http_known_methods[HTTP_METH_OTHER];
+extern struct pool_head *pool2_http_txn;
+
#endif /* _TYPES_PROTO_HTTP_H */
/*
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 */
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;
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;
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)) ||
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;
*/
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++;
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;
((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));
}
*/
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;
{
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;
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;
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) {
(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) {
/* 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;
" 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",
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,
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) {
* 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 */
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
/* 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;
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)
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
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)
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)
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)
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.
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))
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)
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
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;
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)
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)
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)
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. */
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;
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;
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) {
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;
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;
((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;
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;
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 */
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))
/* 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);
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,
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,
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,
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;
*/
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;
*/
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;
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;
{
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;
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;
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;
{
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();
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);
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;
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);
* 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;
*/
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
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
*/
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
/* 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]);
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;
/* 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]);
}
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
* 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)
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;
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;
*/
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;
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;
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
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;
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;
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;
{
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;
{
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)))
*/
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) {
* 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;
*/
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;
{
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;
{
char *cur_ptr, *cur_end;
int done;
- struct http_txn *txn = &s->txn;
+ struct http_txn *txn = s->txn;
int delta;
*/
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) {
*/
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;
*/
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;
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;
}
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;
shut_your_big_mouth_gcc(write(1, trash.str, trash.len));
}
+
+/* Allocate a new HTTP transaction for stream <s> 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 <s>. It is assumed that all
* the required fields are properly allocated and that we only need to (re)init
*/
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;
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;
/* 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 */
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 <s>,
+ * <txn>, and <hdr_idx.v> are properly set. An extra check protects
+ * against an eventual mistake in the fetch capability matrix.
*/
if (unlikely(!s || !txn))
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;
}
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;
}
* 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 */
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;
}
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;
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 */
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;
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)
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);
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 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 (s->txn) {
+ if (be->options2 & PR_O2_RSPBUG_OK)
+ s->txn->rsp.err_pos = -1; /* let buggy responses pass */
+ /* 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;
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;
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);
*/
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;
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)
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);
}
}
else {
- s->txn.rsp.msg_state = HTTP_MSG_RPBEFORE;
rep->flags |= CF_READ_DONTWAIT; /* a single read is enough to get response headers */
}
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;
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;
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;
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;
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;
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;
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;
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;
// 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);
(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);
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;