mirror of
http://git.haproxy.org/git/haproxy.git/
synced 2025-01-19 12:10:46 +00:00
MEDIUM: h1-htx: Add HTX EOM block when the message is in H1_MSG_DONE state
During H1 parsing, the HTX EOM block is added before switching the message state to H1_MSG_DONE. It is an exception in the way to convert an H1 message to HTX. Except for this block, the message is first switched to the right state before starting to add the corresponding HTX blocks. For instance, the message is switched in H1_MSG_DATA state and then the HTX DATA blocks are added. With this patch, the message is switched to the H1_MSG_DONE state when all data blocks or trailers were processed. It is the caller responsibility to call h1_parse_msg_eom() when the H1_MSG_DONE state is reached. This way, it is far easier to catch failures when the HTX buffer is full. The H1 and FCGI muxes have been updated accordingly. This patch may eventually be backported to 2.1 if it helps other backports.
This commit is contained in:
parent
719e07c989
commit
76014fd118
@ -34,6 +34,7 @@ int h1_parse_msg_data(struct h1m *h1m, struct htx **dsthtx,
|
||||
struct buffer *htxbuf);
|
||||
int h1_parse_msg_tlrs(struct h1m *h1m, struct htx *dsthtx,
|
||||
struct buffer *srcbuf, size_t ofs, size_t max);
|
||||
int h1_parse_msg_eom(struct h1m *h1m, struct htx *dsthtx, size_t max);
|
||||
|
||||
int h1_format_htx_reqline(const struct htx_sl *sl, struct buffer *chk);
|
||||
int h1_format_htx_stline(const struct htx_sl *sl, struct buffer *chk);
|
||||
|
31
src/h1_htx.c
31
src/h1_htx.c
@ -381,6 +381,11 @@ int h1_parse_msg_hdrs(struct h1m *h1m, union h1_sl *h1sl, struct htx *dsthtx,
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
/* Switch messages without any payload to DONE state */
|
||||
if (((h1m->flags & H1_MF_CLEN) && h1m->body_len == 0) ||
|
||||
((h1m->flags & (H1_MF_XFER_LEN|H1_MF_CLEN|H1_MF_CHNK)) == H1_MF_XFER_LEN))
|
||||
h1m->state = H1_MSG_DONE;
|
||||
|
||||
end:
|
||||
return ret;
|
||||
error:
|
||||
@ -465,11 +470,8 @@ int h1_parse_msg_data(struct h1m *h1m, struct htx **dsthtx,
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (!h1m->curr_len) {
|
||||
if (max < sizeof(struct htx_blk) + 1 || !htx_add_endof(*dsthtx, HTX_BLK_EOM))
|
||||
goto end;
|
||||
if (!h1m->curr_len)
|
||||
h1m->state = H1_MSG_DONE;
|
||||
}
|
||||
}
|
||||
else if (h1m->flags & H1_MF_CHNK) {
|
||||
/* te:chunked : parse chunks */
|
||||
@ -524,8 +526,6 @@ int h1_parse_msg_data(struct h1m *h1m, struct htx **dsthtx,
|
||||
/* XFER_LEN is set but not CLEN nor CHNK, it means there is no
|
||||
* body. Switch the message in DONE state
|
||||
*/
|
||||
if (max < sizeof(struct htx_blk) + 1 || !htx_add_endof(*dsthtx, HTX_BLK_EOM))
|
||||
goto end;
|
||||
h1m->state = H1_MSG_DONE;
|
||||
}
|
||||
else {
|
||||
@ -594,6 +594,8 @@ int h1_parse_msg_tlrs(struct h1m *h1m, struct htx *dsthtx,
|
||||
if (!htx_add_all_trailers(dsthtx, hdrs))
|
||||
goto error;
|
||||
|
||||
h1m->state = H1_MSG_DONE;
|
||||
|
||||
end:
|
||||
return ret;
|
||||
error:
|
||||
@ -603,6 +605,23 @@ int h1_parse_msg_tlrs(struct h1m *h1m, struct htx *dsthtx,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Finish HTTP/1 parsing by adding the HTX EOM block. It returns 1 on success or
|
||||
* 0 if it couldn't proceed. There is no parsing at this stage, but a parsing
|
||||
* error is reported if the message state is not H1_MSG_DONE. */
|
||||
int h1_parse_msg_eom(struct h1m *h1m, struct htx *dsthtx, size_t max)
|
||||
{
|
||||
if (h1m->state != H1_MSG_DONE) {
|
||||
h1m->err_state = h1m->state;
|
||||
h1m->err_pos = h1m->next;
|
||||
dsthtx->flags |= HTX_FL_PARSING_ERROR;
|
||||
return 0;
|
||||
}
|
||||
if (max < sizeof(struct htx_blk) + 1 || !htx_add_endof(dsthtx, HTX_BLK_EOM))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/* Appends the H1 representation of the request line <sl> to the chunk <chk>. It
|
||||
* returns 1 if data are successfully appended, otherwise it returns 0.
|
||||
|
@ -145,8 +145,7 @@ enum fcgi_strm_st {
|
||||
#define FCGI_SF_KILL_CONN 0x00004000 /* kill the whole connection with this stream */
|
||||
|
||||
/* Other flags */
|
||||
#define FCGI_SF_HAVE_I_TLR 0x00010000 /* Set during input process to know the trailers were processed */
|
||||
#define FCGI_SF_APPEND_EOM 0x00020000 /* Send EOM to the HTX buffer */
|
||||
#define FCGI_SF_H1_PARSING_DONE 0x00010000
|
||||
|
||||
/* FCGI stream descriptor */
|
||||
struct fcgi_strm {
|
||||
@ -2736,7 +2735,7 @@ static int fcgi_recv(struct fcgi_conn *fconn)
|
||||
conn->xprt->subscribe(conn, conn->xprt_ctx, SUB_RETRY_RECV, &fconn->wait_event);
|
||||
}
|
||||
else
|
||||
TRACE_DATA("send data", FCGI_EV_FCONN_RECV, conn,,, (size_t[]){ret});
|
||||
TRACE_DATA("recv data", FCGI_EV_FCONN_RECV, conn,,, (size_t[]){ret});
|
||||
|
||||
if (!b_data(buf)) {
|
||||
fcgi_release_buf(fconn, &fconn->dbuf);
|
||||
@ -3168,7 +3167,7 @@ static size_t fcgi_strm_parse_data(struct fcgi_strm *fstrm, struct h1m *h1m, str
|
||||
|
||||
TRACE_ENTER(FCGI_EV_RSP_DATA|FCGI_EV_RSP_BODY, fstrm->fconn->conn, fstrm,, (size_t[]){max});
|
||||
ret = h1_parse_msg_data(h1m, htx, buf, *ofs, max, htxbuf);
|
||||
if (ret <= 0) {
|
||||
if (!ret) {
|
||||
TRACE_DEVEL("leaving on missing data or error", FCGI_EV_RSP_DATA|FCGI_EV_RSP_BODY, fstrm->fconn->conn, fstrm);
|
||||
if ((*htx)->flags & HTX_FL_PARSING_ERROR) {
|
||||
TRACE_USER("rejected H1 response", FCGI_EV_RSP_DATA|FCGI_EV_RSP_BODY|FCGI_EV_FSTRM_ERR, fstrm->fconn->conn, fstrm);
|
||||
@ -3179,14 +3178,6 @@ static size_t fcgi_strm_parse_data(struct fcgi_strm *fstrm, struct h1m *h1m, str
|
||||
}
|
||||
*ofs += ret;
|
||||
end:
|
||||
if (h1m->state == H1_MSG_DONE) {
|
||||
fstrm->flags &= ~FCGI_SF_APPEND_EOM;
|
||||
TRACE_STATE("end of message", FCGI_EV_RSP_DATA|FCGI_EV_RSP_EOM, fstrm->fconn->conn);
|
||||
}
|
||||
else if (h1m->state == H1_MSG_DATA && (h1m->flags & H1_MF_XFER_LEN) && h1m->curr_len == 0) {
|
||||
fstrm->flags |= FCGI_SF_APPEND_EOM;
|
||||
TRACE_STATE("add append_eom", FCGI_EV_RSP_DATA, fstrm->fconn->conn);
|
||||
}
|
||||
TRACE_LEAVE(FCGI_EV_RSP_DATA|FCGI_EV_RSP_BODY, fstrm->fconn->conn, fstrm,, (size_t[]){ret});
|
||||
return ret;
|
||||
}
|
||||
@ -3198,7 +3189,7 @@ static size_t fcgi_strm_parse_trailers(struct fcgi_strm *fstrm, struct h1m *h1m,
|
||||
|
||||
TRACE_ENTER(FCGI_EV_RSP_DATA|FCGI_EV_RSP_TLRS, fstrm->fconn->conn, fstrm,, (size_t[]){max});
|
||||
ret = h1_parse_msg_tlrs(h1m, htx, buf, *ofs, max);
|
||||
if (ret <= 0) {
|
||||
if (!ret) {
|
||||
TRACE_DEVEL("leaving on missing data or error", FCGI_EV_RSP_DATA|FCGI_EV_RSP_TLRS, fstrm->fconn->conn, fstrm);
|
||||
if (htx->flags & HTX_FL_PARSING_ERROR) {
|
||||
TRACE_USER("rejected H1 response", FCGI_EV_RSP_DATA|FCGI_EV_RSP_TLRS|FCGI_EV_FSTRM_ERR, fstrm->fconn->conn, fstrm);
|
||||
@ -3208,27 +3199,31 @@ static size_t fcgi_strm_parse_trailers(struct fcgi_strm *fstrm, struct h1m *h1m,
|
||||
goto end;
|
||||
}
|
||||
*ofs += ret;
|
||||
fstrm->flags |= FCGI_SF_HAVE_I_TLR;
|
||||
end:
|
||||
TRACE_LEAVE(FCGI_EV_RSP_DATA|FCGI_EV_RSP_TLRS, fstrm->fconn->conn, fstrm,, (size_t[]){ret});
|
||||
return ret;
|
||||
}
|
||||
|
||||
static size_t fcgi_strm_add_eom(struct fcgi_strm *fstrm, struct h1m *h1m, struct htx *htx,
|
||||
size_t max)
|
||||
struct buffer *buf, size_t *ofs, size_t max)
|
||||
{
|
||||
TRACE_ENTER(FCGI_EV_RSP_DATA, fstrm->fconn->conn, fstrm,, (size_t[]){max});
|
||||
if (max < sizeof(struct htx_blk) + 1 || !htx_add_endof(htx, HTX_BLK_EOM)) {
|
||||
fstrm->flags |= FCGI_SF_APPEND_EOM;
|
||||
TRACE_STATE("leaving on append_eom", FCGI_EV_RSP_DATA, fstrm->fconn->conn);
|
||||
return 0;
|
||||
}
|
||||
int ret;
|
||||
|
||||
h1m->state = H1_MSG_DONE;
|
||||
fstrm->flags &= ~FCGI_SF_APPEND_EOM;
|
||||
TRACE_STATE("end of response", FCGI_EV_RSP_DATA|FCGI_EV_RSP_EOM, fstrm->fconn->conn, fstrm);
|
||||
TRACE_LEAVE(FCGI_EV_RSP_DATA, fstrm->fconn->conn, fstrm);
|
||||
return (sizeof(struct htx_blk) + 1);
|
||||
TRACE_ENTER(FCGI_EV_RSP_DATA||FCGI_EV_RSP_EOM, fstrm->fconn->conn, fstrm,, (size_t[]){max});
|
||||
ret = h1_parse_msg_eom(h1m, htx, max);
|
||||
if (!ret) {
|
||||
TRACE_DEVEL("leaving on missing data or error", FCGI_EV_RSP_DATA|FCGI_EV_RSP_EOM, fstrm->fconn->conn, fstrm);
|
||||
if (htx->flags & HTX_FL_PARSING_ERROR) {
|
||||
TRACE_USER("rejected H1 response", FCGI_EV_RSP_DATA|FCGI_EV_RSP_EOM|FCGI_EV_FSTRM_ERR, fstrm->fconn->conn, fstrm);
|
||||
fcgi_strm_error(fstrm);
|
||||
fcgi_strm_capture_bad_message(fstrm->fconn, fstrm, h1m, buf);
|
||||
}
|
||||
goto end;
|
||||
}
|
||||
fstrm->flags |= FCGI_SF_H1_PARSING_DONE;
|
||||
end:
|
||||
TRACE_LEAVE(FCGI_EV_RSP_DATA|FCGI_EV_RSP_EOM, fstrm->fconn->conn, fstrm,, (size_t[]){ret});
|
||||
return ret;
|
||||
}
|
||||
|
||||
static size_t fcgi_strm_parse_response(struct fcgi_strm *fstrm, struct buffer *buf, size_t count)
|
||||
@ -3270,30 +3265,27 @@ static size_t fcgi_strm_parse_response(struct fcgi_strm *fstrm, struct buffer *b
|
||||
else if (h1m->state < H1_MSG_TRAILERS) {
|
||||
TRACE_PROTO("parsing response payload", FCGI_EV_RSP_DATA|FCGI_EV_RSP_BODY, fconn->conn, fstrm);
|
||||
ret = fcgi_strm_parse_data(fstrm, h1m, &htx, &fstrm->rxbuf, &total, count, buf);
|
||||
if (!ret)
|
||||
if (!ret && h1m->state != H1_MSG_DONE)
|
||||
break;
|
||||
|
||||
TRACE_PROTO("rcvd response payload data", FCGI_EV_RSP_DATA|FCGI_EV_RSP_BODY, fconn->conn, fstrm, htx);
|
||||
|
||||
if (h1m->state == H1_MSG_DONE)
|
||||
TRACE_USER("H1 response fully rcvd", FCGI_EV_RSP_DATA|FCGI_EV_RSP_EOM, fconn->conn, fstrm, htx);
|
||||
}
|
||||
else if (h1m->state == H1_MSG_TRAILERS) {
|
||||
if (!(fstrm->flags & FCGI_SF_HAVE_I_TLR)) {
|
||||
TRACE_PROTO("parsing response trailers", FCGI_EV_RSP_DATA|FCGI_EV_RSP_TLRS, fconn->conn, fstrm);
|
||||
ret = fcgi_strm_parse_trailers(fstrm, h1m, htx, &fstrm->rxbuf, &total, count);
|
||||
if (!ret)
|
||||
break;
|
||||
|
||||
TRACE_PROTO("rcvd H1 response trailers", FCGI_EV_RSP_DATA|FCGI_EV_RSP_TLRS, fconn->conn, fstrm, htx);
|
||||
}
|
||||
else if (!fcgi_strm_add_eom(fstrm, h1m, htx, count))
|
||||
TRACE_PROTO("parsing response trailers", FCGI_EV_RSP_DATA|FCGI_EV_RSP_TLRS, fconn->conn, fstrm);
|
||||
ret = fcgi_strm_parse_trailers(fstrm, h1m, htx, &fstrm->rxbuf, &total, count);
|
||||
if (!ret && h1m->state != H1_MSG_DONE)
|
||||
break;
|
||||
|
||||
if (h1m->state == H1_MSG_DONE)
|
||||
TRACE_USER("H1 response fully rcvd", FCGI_EV_RSP_DATA|FCGI_EV_RSP_EOM, fconn->conn, fstrm, htx);
|
||||
TRACE_PROTO("rcvd H1 response trailers", FCGI_EV_RSP_DATA|FCGI_EV_RSP_TLRS, fconn->conn, fstrm, htx);
|
||||
}
|
||||
else if (h1m->state == H1_MSG_DONE) {
|
||||
if (!(fstrm->flags & FCGI_SF_H1_PARSING_DONE)) {
|
||||
if (!fcgi_strm_add_eom(fstrm, h1m, htx, &fstrm->rxbuf, &total, count))
|
||||
break;
|
||||
|
||||
TRACE_USER("H1 response fully rcvd", FCGI_EV_RSP_DATA|FCGI_EV_RSP_EOM, fconn->conn, fstrm, htx);
|
||||
}
|
||||
|
||||
if (b_data(&fstrm->rxbuf) > total) {
|
||||
htx->flags |= HTX_FL_PARSING_ERROR;
|
||||
TRACE_PROTO("too much data, parsing error", FCGI_EV_RSP_DATA, fconn->conn, fstrm);
|
||||
@ -3304,21 +3296,16 @@ static size_t fcgi_strm_parse_response(struct fcgi_strm *fstrm, struct buffer *b
|
||||
else if (h1m->state == H1_MSG_TUNNEL) {
|
||||
TRACE_PROTO("parsing response tunneled data", FCGI_EV_RSP_DATA, fconn->conn, fstrm);
|
||||
ret = fcgi_strm_parse_data(fstrm, h1m, &htx, &fstrm->rxbuf, &total, count, buf);
|
||||
|
||||
if (fstrm->state != FCGI_SS_ERROR &&
|
||||
(fstrm->flags & FCGI_SF_ES_RCVD) && b_data(&fstrm->rxbuf) == total) {
|
||||
TRACE_DEVEL("end of tunneled data", FCGI_EV_RSP_DATA, fconn->conn, fstrm);
|
||||
if ((h1m->flags & (H1_MF_VER_11|H1_MF_XFER_LEN)) == H1_MF_VER_11) {
|
||||
if (!fcgi_strm_add_eom(fstrm, h1m, htx, count))
|
||||
break;
|
||||
TRACE_USER("H1 response fully rcvd", FCGI_EV_RSP_DATA|FCGI_EV_RSP_EOM, fconn->conn, fstrm, htx);
|
||||
}
|
||||
else {
|
||||
h1m->state = H1_MSG_DONE;
|
||||
TRACE_USER("H1 response fully rcvd", FCGI_EV_RSP_DATA|FCGI_EV_RSP_EOM, fconn->conn, fstrm, htx);
|
||||
break;
|
||||
}
|
||||
if ((h1m->flags & (H1_MF_VER_11|H1_MF_XFER_LEN)) != H1_MF_VER_11)
|
||||
fstrm->flags |= FCGI_SF_H1_PARSING_DONE;
|
||||
h1m->state = H1_MSG_DONE;
|
||||
TRACE_USER("H1 response fully rcvd", FCGI_EV_RSP_DATA|FCGI_EV_RSP_EOM, fconn->conn, fstrm, htx);
|
||||
}
|
||||
if (!ret)
|
||||
if (!ret && h1m->state != H1_MSG_DONE)
|
||||
break;
|
||||
|
||||
TRACE_PROTO("rcvd H1 response tunneled data", FCGI_EV_RSP_DATA, fconn->conn, fstrm, htx);
|
||||
@ -3793,11 +3780,11 @@ static size_t fcgi_rcv_buf(struct conn_stream *cs, struct buffer *buf, size_t co
|
||||
else
|
||||
TRACE_STATE("fstrm rxbuf not allocated", FCGI_EV_STRM_RECV|FCGI_EV_FSTRM_BLK, fconn->conn, fstrm);
|
||||
|
||||
if (b_data(&fstrm->rxbuf) || (fstrm->flags & FCGI_SF_APPEND_EOM))
|
||||
if (b_data(&fstrm->rxbuf) || (fstrm->h1m.state == H1_MSG_DONE && !(fstrm->flags & FCGI_SF_H1_PARSING_DONE)))
|
||||
cs->flags |= (CS_FL_RCV_MORE | CS_FL_WANT_ROOM);
|
||||
else {
|
||||
cs->flags &= ~(CS_FL_RCV_MORE | CS_FL_WANT_ROOM);
|
||||
if (fstrm->state == FCGI_SS_ERROR || fstrm->h1m.state == H1_MSG_DONE) {
|
||||
if (fstrm->state == FCGI_SS_ERROR || (fstrm->flags & FCGI_SF_H1_PARSING_DONE)) {
|
||||
cs->flags |= CS_FL_EOI;
|
||||
if (!(fstrm->h1m.flags & (H1_MF_VER_11|H1_MF_XFER_LEN)))
|
||||
cs->flags |= CS_FL_EOS;
|
||||
|
138
src/mux_h1.c
138
src/mux_h1.c
@ -72,9 +72,8 @@
|
||||
#define H1S_F_NOT_FIRST 0x00000080 /* The H1 stream is not the first one */
|
||||
#define H1S_F_BUF_FLUSH 0x00000100 /* Flush input buffer and don't read more data */
|
||||
#define H1S_F_SPLICED_DATA 0x00000200 /* Set when the kernel splicing is in used */
|
||||
#define H1S_F_HAVE_I_TLR 0x00000800 /* Set during input process to know the trailers were processed */
|
||||
#define H1S_F_APPEND_EOM 0x00001000 /* Send EOM to the HTX buffer */
|
||||
/* 0x00002000 .. 0x00001000 unused */
|
||||
#define H1S_F_PARSING_DONE 0x00000400 /* Set when incoming message parsing is finished (EOM added) */
|
||||
/* 0x00000800 .. 0x00001000 unused */
|
||||
#define H1S_F_HAVE_SRV_NAME 0x00002000 /* Set during output process if the server name header was added to the request */
|
||||
#define H1S_F_HAVE_O_CONN 0x00004000 /* Set during output process to know connection mode was processed */
|
||||
|
||||
@ -468,7 +467,7 @@ static inline size_t h1s_data_pending(const struct h1s *h1s)
|
||||
|
||||
h1m = conn_is_back(h1s->h1c->conn) ? &h1s->res : &h1s->req;
|
||||
if (h1m->state == H1_MSG_DONE)
|
||||
return 0; // data not for this stream (e.g. pipelining)
|
||||
return !(h1s->flags & H1S_F_PARSING_DONE);
|
||||
|
||||
return b_data(&h1s->h1c->ibuf);
|
||||
}
|
||||
@ -612,7 +611,7 @@ static void h1s_destroy(struct h1s *h1s)
|
||||
|
||||
if (!(h1c->flags & (H1C_F_CS_ERROR|H1C_F_CS_SHUTW_NOW|H1C_F_CS_SHUTDOWN)) && /* No error/shutdown on h1c */
|
||||
!(h1c->conn->flags & (CO_FL_ERROR|CO_FL_SOCK_RD_SH|CO_FL_SOCK_WR_SH)) && /* No error/shutdown on conn */
|
||||
(h1s->flags & H1S_F_WANT_KAL) && /* K/A possible */
|
||||
(h1s->flags & (H1S_F_WANT_KAL|H1S_F_PARSING_DONE)) == (H1S_F_WANT_KAL|H1S_F_PARSING_DONE) && /* K/A possible */
|
||||
h1s->req.state == H1_MSG_DONE && h1s->res.state == H1_MSG_DONE) { /* req/res in DONE state */
|
||||
h1c->flags |= (H1C_F_CS_IDLE|H1C_F_WAIT_NEXT_REQ);
|
||||
TRACE_STATE("set idle mode on h1c, waiting for the next request", H1_EV_H1C_ERR, h1c->conn, h1s);
|
||||
@ -1119,9 +1118,12 @@ static void h1_set_req_tunnel_mode(struct h1s *h1s)
|
||||
h1s->req.state = H1_MSG_TUNNEL;
|
||||
TRACE_STATE("switch H1 request in tunnel mode", H1_EV_TX_DATA|H1_EV_TX_HDRS, h1s->h1c->conn, h1s);
|
||||
|
||||
if (!conn_is_back(h1s->h1c->conn) && h1s->res.state < H1_MSG_DONE) {
|
||||
h1s->h1c->flags |= H1C_F_IN_BUSY;
|
||||
TRACE_STATE("switch h1c in busy mode", H1_EV_RX_DATA|H1_EV_H1C_BLK, h1s->h1c->conn, h1s);
|
||||
if (!conn_is_back(h1s->h1c->conn)) {
|
||||
h1s->flags &= ~H1S_F_PARSING_DONE;
|
||||
if (h1s->res.state < H1_MSG_DONE) {
|
||||
h1s->h1c->flags |= H1C_F_IN_BUSY;
|
||||
TRACE_STATE("switch h1c in busy mode", H1_EV_RX_DATA|H1_EV_H1C_BLK, h1s->h1c->conn, h1s);
|
||||
}
|
||||
}
|
||||
else if (h1s->h1c->flags & H1C_F_IN_BUSY) {
|
||||
h1s->h1c->flags &= ~H1C_F_IN_BUSY;
|
||||
@ -1139,23 +1141,26 @@ static void h1_set_req_tunnel_mode(struct h1s *h1s)
|
||||
*/
|
||||
static void h1_set_res_tunnel_mode(struct h1s *h1s)
|
||||
{
|
||||
/* On protocol switching, switch the request to tunnel mode if it is in
|
||||
* DONE state. Otherwise we will wait the end of the request to switch
|
||||
* it in tunnel mode.
|
||||
*/
|
||||
if (h1s->status == 101 && h1s->req.state == H1_MSG_DONE) {
|
||||
h1s->req.flags &= ~(H1_MF_XFER_LEN|H1_MF_CLEN|H1_MF_CHNK);
|
||||
h1s->req.state = H1_MSG_TUNNEL;
|
||||
TRACE_STATE("switch H1 request in tunnel mode", H1_EV_TX_DATA|H1_EV_TX_HDRS, h1s->h1c->conn, h1s);
|
||||
}
|
||||
|
||||
h1s->res.flags &= ~(H1_MF_XFER_LEN|H1_MF_CLEN|H1_MF_CHNK);
|
||||
h1s->res.state = H1_MSG_TUNNEL;
|
||||
TRACE_STATE("switch H1 response in tunnel mode", H1_EV_TX_DATA|H1_EV_TX_HDRS, h1s->h1c->conn, h1s);
|
||||
|
||||
if (conn_is_back(h1s->h1c->conn) && h1s->req.state < H1_MSG_DONE) {
|
||||
h1s->h1c->flags |= H1C_F_IN_BUSY;
|
||||
TRACE_STATE("switch h1c in busy mode", H1_EV_RX_DATA|H1_EV_H1C_BLK, h1s->h1c->conn, h1s);
|
||||
if (conn_is_back(h1s->h1c->conn)) {
|
||||
h1s->flags &= ~H1S_F_PARSING_DONE;
|
||||
/* On protocol switching, switch the request to tunnel mode if it is in
|
||||
* DONE state. Otherwise we will wait the end of the request to switch
|
||||
* it in tunnel mode.
|
||||
*/
|
||||
if (h1s->req.state < H1_MSG_DONE) {
|
||||
h1s->h1c->flags |= H1C_F_IN_BUSY;
|
||||
TRACE_STATE("switch h1c in busy mode", H1_EV_RX_DATA|H1_EV_H1C_BLK, h1s->h1c->conn, h1s);
|
||||
}
|
||||
else if (h1s->status == 101 && h1s->req.state == H1_MSG_DONE) {
|
||||
h1s->req.flags &= ~(H1_MF_XFER_LEN|H1_MF_CLEN|H1_MF_CHNK);
|
||||
h1s->req.state = H1_MSG_TUNNEL;
|
||||
TRACE_STATE("switch H1 request in tunnel mode", H1_EV_TX_DATA|H1_EV_TX_HDRS, h1s->h1c->conn, h1s);
|
||||
}
|
||||
}
|
||||
else if (h1s->h1c->flags & H1C_F_IN_BUSY) {
|
||||
h1s->h1c->flags &= ~H1C_F_IN_BUSY;
|
||||
@ -1278,16 +1283,6 @@ static size_t h1_process_data(struct h1s *h1s, struct h1m *h1m, struct htx **htx
|
||||
*ofs += ret;
|
||||
|
||||
end:
|
||||
if (h1m->state == H1_MSG_DONE) {
|
||||
h1s->flags &= ~H1S_F_APPEND_EOM;
|
||||
h1s->cs->flags |= CS_FL_EOI;
|
||||
TRACE_STATE("end of message", H1_EV_RX_DATA|H1_EV_RX_BODY|H1_EV_RX_EOI, h1s->h1c->conn);
|
||||
}
|
||||
else if (h1m->state == H1_MSG_DATA && (h1m->flags & H1_MF_XFER_LEN) && h1m->curr_len == 0) {
|
||||
h1s->flags |= H1S_F_APPEND_EOM;
|
||||
TRACE_STATE("add append_eom", H1_EV_RX_DATA, h1s->h1c->conn);
|
||||
}
|
||||
|
||||
TRACE_LEAVE(H1_EV_RX_DATA|H1_EV_RX_BODY, h1s->h1c->conn, h1s,, (size_t[]){ret});
|
||||
return ret;
|
||||
}
|
||||
@ -1324,7 +1319,6 @@ static size_t h1_process_trailers(struct h1s *h1s, struct h1m *h1m, struct htx *
|
||||
}
|
||||
|
||||
*ofs += ret;
|
||||
h1s->flags |= H1S_F_HAVE_I_TLR;
|
||||
|
||||
end:
|
||||
TRACE_LEAVE(H1_EV_RX_DATA|H1_EV_RX_TLRS, h1s->h1c->conn, h1s,, (size_t[]){ret});
|
||||
@ -1332,26 +1326,40 @@ static size_t h1_process_trailers(struct h1s *h1s, struct h1m *h1m, struct htx *
|
||||
}
|
||||
|
||||
/*
|
||||
* Add the EOM in the HTX message and switch the message to the DONE state. It
|
||||
* returns the number of bytes parsed if > 0, or 0 if iet couldn't proceed. This
|
||||
* functions is responsible to update the parser state <h1m>. It also add the
|
||||
* flag CS_FL_EOI on the CS.
|
||||
* Add the EOM in the HTX message. It returns 1 on success or 0 if it couldn't
|
||||
* proceed. This functions is responsible to update the parser state <h1m>. It
|
||||
* also add the flag CS_FL_EOI on the CS.
|
||||
*/
|
||||
static size_t h1_process_eom(struct h1s *h1s, struct h1m *h1m, struct htx *htx, size_t max)
|
||||
static size_t h1_process_eom(struct h1s *h1s, struct h1m *h1m, struct htx *htx,
|
||||
struct buffer *buf, size_t *ofs, size_t max)
|
||||
{
|
||||
TRACE_ENTER(H1_EV_RX_DATA, h1s->h1c->conn, h1s,, (size_t[]){max});
|
||||
if (max < sizeof(struct htx_blk) + 1 || !htx_add_endof(htx, HTX_BLK_EOM)) {
|
||||
h1s->flags |= H1S_F_APPEND_EOM;
|
||||
TRACE_STATE("leaving on append_eom", H1_EV_RX_DATA, h1s->h1c->conn);
|
||||
return 0;
|
||||
int ret;
|
||||
|
||||
TRACE_ENTER(H1_EV_RX_DATA|H1_EV_RX_EOI, h1s->h1c->conn, h1s,, (size_t[]){max});
|
||||
ret = h1_parse_msg_eom(h1m, htx, max);
|
||||
if (!ret) {
|
||||
TRACE_DEVEL("leaving on missing data or error", H1_EV_RX_DATA|H1_EV_RX_EOI, h1s->h1c->conn, h1s);
|
||||
if (htx->flags & HTX_FL_PARSING_ERROR) {
|
||||
if (!(h1m->flags & H1_MF_RESP)) {
|
||||
h1s->flags |= H1S_F_REQ_ERROR;
|
||||
TRACE_USER("rejected H1 request", H1_EV_RX_DATA|H1_EV_RX_EOI|H1_EV_H1S_ERR, h1s->h1c->conn, h1s);
|
||||
}
|
||||
else {
|
||||
h1s->flags |= H1S_F_RES_ERROR;
|
||||
TRACE_USER("rejected H1 response", H1_EV_RX_DATA|H1_EV_RX_EOI|H1_EV_H1S_ERR, h1s->h1c->conn, h1s);
|
||||
}
|
||||
h1s->cs->flags |= CS_FL_EOI;
|
||||
TRACE_STATE("parsing error", H1_EV_RX_DATA|H1_EV_RX_EOI|H1_EV_H1S_ERR, h1s->h1c->conn, h1s);
|
||||
h1_capture_bad_message(h1s->h1c, h1s, h1m, buf);
|
||||
}
|
||||
goto end;
|
||||
}
|
||||
|
||||
h1s->flags &= ~H1S_F_APPEND_EOM;
|
||||
h1m->state = H1_MSG_DONE;
|
||||
h1s->flags |= H1S_F_PARSING_DONE;
|
||||
h1s->cs->flags |= CS_FL_EOI;
|
||||
TRACE_STATE("end of message", H1_EV_RX_DATA|H1_EV_RX_EOI, h1s->h1c->conn, h1s);
|
||||
TRACE_LEAVE(H1_EV_RX_DATA, h1s->h1c->conn, h1s);
|
||||
return (sizeof(struct htx_blk) + 1);
|
||||
end:
|
||||
TRACE_LEAVE(H1_EV_RX_DATA|H1_EV_RX_EOI, h1s->h1c->conn, h1s,, (size_t[]){ret});
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1406,33 +1414,30 @@ static size_t h1_process_input(struct h1c *h1c, struct buffer *buf, size_t count
|
||||
else if (h1m->state < H1_MSG_TRAILERS) {
|
||||
TRACE_PROTO("parsing message payload", H1_EV_RX_DATA|H1_EV_RX_BODY, h1c->conn, h1s);
|
||||
ret = h1_process_data(h1s, h1m, &htx, &h1c->ibuf, &total, count, buf);
|
||||
if (!ret)
|
||||
if (!ret && h1m->state != H1_MSG_DONE)
|
||||
break;
|
||||
|
||||
TRACE_PROTO((!(h1m->flags & H1_MF_RESP) ? "rcvd H1 request payload data" : "rcvd H1 response payload data"),
|
||||
H1_EV_RX_DATA|H1_EV_RX_BODY, h1c->conn, h1s, htx, (size_t[]){ret});
|
||||
|
||||
if (h1m->state == H1_MSG_DONE)
|
||||
TRACE_USER((!(h1m->flags & H1_MF_RESP) ? "H1 request fully rcvd" : "H1 response fully rcvd"),
|
||||
H1_EV_RX_DATA, h1c->conn, h1s, htx);
|
||||
}
|
||||
else if (h1m->state == H1_MSG_TRAILERS) {
|
||||
if (!(h1s->flags & H1S_F_HAVE_I_TLR)) {
|
||||
TRACE_PROTO("parsing message trailers", H1_EV_RX_DATA|H1_EV_RX_TLRS, h1c->conn, h1s);
|
||||
ret = h1_process_trailers(h1s, h1m, htx, &h1c->ibuf, &total, count);
|
||||
if (!ret)
|
||||
break;
|
||||
|
||||
TRACE_PROTO((!(h1m->flags & H1_MF_RESP) ? "rcvd H1 request trailers" : "rcvd H1 response trailers"),
|
||||
H1_EV_RX_DATA|H1_EV_RX_TLRS, h1c->conn, h1s, htx, (size_t[]){ret});
|
||||
}
|
||||
else if (!h1_process_eom(h1s, h1m, htx, count))
|
||||
TRACE_PROTO("parsing message trailers", H1_EV_RX_DATA|H1_EV_RX_TLRS, h1c->conn, h1s);
|
||||
ret = h1_process_trailers(h1s, h1m, htx, &h1c->ibuf, &total, count);
|
||||
if (!ret && h1m->state != H1_MSG_DONE)
|
||||
break;
|
||||
|
||||
TRACE_USER((!(h1m->flags & H1_MF_RESP) ? "H1 request fully rcvd" : "H1 response fully rcvd"),
|
||||
H1_EV_RX_DATA|H1_EV_RX_EOI, h1c->conn, h1s, htx);
|
||||
TRACE_PROTO((!(h1m->flags & H1_MF_RESP) ? "rcvd H1 request trailers" : "rcvd H1 response trailers"),
|
||||
H1_EV_RX_DATA|H1_EV_RX_TLRS, h1c->conn, h1s, htx, (size_t[]){ret});
|
||||
}
|
||||
else if (h1m->state == H1_MSG_DONE) {
|
||||
if (!(h1s->flags & H1S_F_PARSING_DONE)) {
|
||||
if (!h1_process_eom(h1s, h1m, htx, &h1c->ibuf, &total, count))
|
||||
break;
|
||||
|
||||
TRACE_USER((!(h1m->flags & H1_MF_RESP) ? "H1 request fully rcvd" : "H1 response fully rcvd"),
|
||||
H1_EV_RX_DATA|H1_EV_RX_EOI, h1c->conn, h1s, htx);
|
||||
}
|
||||
|
||||
if (!(h1m->flags & H1_MF_RESP) && h1s->status == 101)
|
||||
h1_set_req_tunnel_mode(h1s);
|
||||
else if (h1s->req.state < H1_MSG_DONE || h1s->res.state < H1_MSG_DONE) {
|
||||
@ -1478,12 +1483,9 @@ static size_t h1_process_input(struct h1c *h1c, struct buffer *buf, size_t count
|
||||
|
||||
if (!b_data(&h1c->ibuf))
|
||||
h1_release_buf(h1c, &h1c->ibuf);
|
||||
|
||||
if ((h1s_data_pending(h1s) && !htx_is_empty(htx)) || (h1s->flags & H1S_F_APPEND_EOM))
|
||||
if (h1s_data_pending(h1s))
|
||||
h1s->cs->flags |= CS_FL_RCV_MORE | CS_FL_WANT_ROOM;
|
||||
|
||||
if (((h1s->flags & (H1S_F_REOS|H1S_F_APPEND_EOM)) == H1S_F_REOS) &&
|
||||
(!h1s_data_pending(h1s) || htx_is_empty(htx))) {
|
||||
else if (h1s->flags & H1S_F_REOS) {
|
||||
h1s->cs->flags |= CS_FL_EOS;
|
||||
if (h1m->state == H1_MSG_TUNNEL)
|
||||
h1s->cs->flags |= CS_FL_EOI;
|
||||
|
Loading…
Reference in New Issue
Block a user