MEDIUM: h1: remove the useless H1_MSG_BODY state

This state was only a delimiter between headers and body but it now
causes more harm than good because it requires someone to change it.
Since the H1 parser knows if we're in DATA or CHUNK_SIZE, simply let
it set the right next state so that h1m->state constantly matches
what is expected afterwards.
This commit is contained in:
Willy Tarreau 2018-09-12 17:25:32 +02:00
parent 4c34c0e74a
commit 001823c304
4 changed files with 29 additions and 25 deletions

View File

@ -150,7 +150,6 @@ static inline const char *h1m_state_str(enum h1_state msg_state)
case H1_MSG_HDR_L2_LF: return "MSG_HDR_L2_LF"; case H1_MSG_HDR_L2_LF: return "MSG_HDR_L2_LF";
case H1_MSG_HDR_L2_LWS: return "MSG_HDR_L2_LWS"; case H1_MSG_HDR_L2_LWS: return "MSG_HDR_L2_LWS";
case H1_MSG_LAST_LF: return "MSG_LAST_LF"; case H1_MSG_LAST_LF: return "MSG_LAST_LF";
case H1_MSG_BODY: return "MSG_BODY";
case H1_MSG_CHUNK_SIZE: return "MSG_CHUNK_SIZE"; case H1_MSG_CHUNK_SIZE: return "MSG_CHUNK_SIZE";
case H1_MSG_DATA: return "MSG_DATA"; case H1_MSG_DATA: return "MSG_DATA";
case H1_MSG_CHUNK_CRLF: return "MSG_CHUNK_CRLF"; case H1_MSG_CHUNK_CRLF: return "MSG_CHUNK_CRLF";

View File

@ -120,21 +120,17 @@ enum h1m_state {
H1_MSG_HDR_L2_LF = 23, // parsing header LWS (LF) inside/after value H1_MSG_HDR_L2_LF = 23, // parsing header LWS (LF) inside/after value
H1_MSG_HDR_L2_LWS = 24, // checking whether it's a new header or an LWS H1_MSG_HDR_L2_LWS = 24, // checking whether it's a new header or an LWS
H1_MSG_LAST_LF = 25, // parsing last LF H1_MSG_LAST_LF = 25, // parsing last LF, last state for headers
/* Body processing. /* Body processing. */
* The state H1_MSG_BODY is a delimiter to know if we're waiting for headers
* or body. All the sub-states below also indicate we're processing the body, H1_MSG_CHUNK_SIZE = 26, // parsing the chunk size (RFC7230 #4.1)
* with some additional information. H1_MSG_DATA = 27, // skipping data chunk / content-length data
*/ H1_MSG_CHUNK_CRLF = 28, // skipping CRLF after data chunk
H1_MSG_BODY = 26, // parsing body at end of headers H1_MSG_TRAILERS = 29, // trailers (post-data entity headers)
H1_MSG_CHUNK_SIZE = 27, // parsing the chunk size (RFC7230 #4.1)
H1_MSG_DATA = 28, // skipping data chunk / content-length data
H1_MSG_CHUNK_CRLF = 29, // skipping CRLF after data chunk
H1_MSG_TRAILERS = 30, // trailers (post-data entity headers)
/* we enter this state when we've received the end of the current message */ /* we enter this state when we've received the end of the current message */
H1_MSG_DONE = 31, // message end received, waiting for resync or close H1_MSG_DONE = 30, // message end received, waiting for resync or close
H1_MSG_TUNNEL = 32, // tunneled data after DONE H1_MSG_TUNNEL = 31, // tunneled data after DONE
} __attribute__((packed)); } __attribute__((packed));

View File

@ -1073,7 +1073,21 @@ int h1_headers_to_hdr_list(char *start, const char *stop,
} }
http_set_hdr(&hdr[hdr_count++], ist(""), ist("")); http_set_hdr(&hdr[hdr_count++], ist(""), ist(""));
} }
state = H1_MSG_BODY;
/* reaching here we've parsed the whole message. We may detect
* that we were already continuing an interrupted parsing pass
* so we were silently looking for the end of message not
* updating anything before deciding to parse it fully at once.
* It's guaranteed that we won't match this test twice in a row
* since restarting will turn zero.
*/
if (restarting)
goto restart;
if (h1m->flags & H1_MF_CHNK)
state = H1_MSG_CHUNK_SIZE;
else
state = H1_MSG_DATA;
break; break;
default: default:
@ -1081,14 +1095,9 @@ int h1_headers_to_hdr_list(char *start, const char *stop,
goto http_msg_invalid; goto http_msg_invalid;
} }
/* reaching here, we've parsed the whole message and the state is /* Now we've left the headers state and are either in H1_MSG_DATA or
* H1_MSG_BODY. We may discover that we were already continuing an * H1_MSG_CHUNK_SIZE.
* interrupted parsing session, thus we were silently looking for
* the end of message before deciding to parse it fully at once.
* We won't come there again since restarting will turn zero.
*/ */
if (restarting)
goto restart;
if (slp && !skip_update) if (slp && !skip_update)
*slp = sl; *slp = sl;

View File

@ -3237,8 +3237,8 @@ static size_t h2s_frt_make_resp_headers(struct h2s *h2s, const struct buffer *bu
h1m->err_pos = -1; // don't care about errors on the response path h1m->err_pos = -1; // don't care about errors on the response path
goto end; goto end;
} }
else
h1m->state = (h1m->flags & H1_MF_CHNK) ? H1_MSG_CHUNK_SIZE : H1_MSG_BODY; /* now the h1m state is either H1_MSG_CHUNK_SIZE or H1_MSG_DATA */
end: end:
//fprintf(stderr, "[%d] sent simple H2 response (sid=%d) = %d bytes (%d in, ep=%u, es=%s)\n", h2c->st0, h2s->id, outbuf.len, ret, h1m->err_pos, h1_msg_state_str(h1m->err_state)); //fprintf(stderr, "[%d] sent simple H2 response (sid=%d) = %d bytes (%d in, ep=%u, es=%s)\n", h2c->st0, h2s->id, outbuf.len, ret, h1m->err_pos, h1_msg_state_str(h1m->err_state));
@ -3568,7 +3568,7 @@ static size_t h2_snd_buf(struct conn_stream *cs, struct buffer *buf, size_t coun
h2s->flags |= H2_SF_OUTGOING_DATA; h2s->flags |= H2_SF_OUTGOING_DATA;
while (h2s->h1m.state < H1_MSG_DONE && count) { while (h2s->h1m.state < H1_MSG_DONE && count) {
if (h2s->h1m.state < H1_MSG_BODY) { if (h2s->h1m.state <= H1_MSG_LAST_LF) {
ret = h2s_frt_make_resp_headers(h2s, buf, total, count); ret = h2s_frt_make_resp_headers(h2s, buf, total, count);
} }
else if (h2s->h1m.state < H1_MSG_TRAILERS) { else if (h2s->h1m.state < H1_MSG_TRAILERS) {