]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MEDIUM: htx: 1xx messages are now part of the final reponses
authorChristopher Faulet <cfaulet@haproxy.com>
Fri, 17 May 2019 06:37:28 +0000 (08:37 +0200)
committerWilly Tarreau <w@1wt.eu>
Tue, 28 May 2019 05:42:30 +0000 (07:42 +0200)
1xx informational messages (all except 101) are now part of the HTTP reponse,
semantically speaking. These messages are not followed by an EOM anymore,
because a final reponse is always expected. All these parts can also be
transferred to the channel in same time, if possible. The HTX response analyzer
has been update to forward them in loop, as the legacy one.

src/http_fetch.c
src/mux_h1.c
src/mux_h2.c
src/proto_htx.c

index 395e665e9df607ce7785781adb757e64aac85291..05074d6eb4fc98266bb8bc5f0b9f57c675d6b141 100644 (file)
@@ -203,7 +203,7 @@ struct htx *smp_prefetch_htx(struct sample *smp, struct channel *chn, int vol)
 
                if (msg->msg_state < HTTP_MSG_BODY) {
                        /* Analyse not yet started */
-                       if (htx_is_empty(htx) || htx_get_tail_type(htx) < HTX_BLK_EOH) {
+                       if (htx_is_empty(htx) || htx->sl_pos == -1) {
                                /* Parsing is done by the mux, just wait */
                                smp->flags |= SMP_F_MAY_CHANGE;
                                return NULL;
index 947e1930c83035b57e2be801ddd5dc69ea738e9a..881501eb0cac330cc00c51fa8075d4727b37bd63 100644 (file)
@@ -932,21 +932,6 @@ static size_t h1_eval_htx_res_size(struct h1m *h1m, union h1_sl *h1sl, struct ht
        return sz;
 }
 
-/*
- * Handle 100-Continue responses or any other informational 1xx responses which
- * is non-final. In such case, this function reset the response parser. It is
- * the caller responsibility to call this function when appropriate.
- */
-static void h1_handle_1xx_response(struct h1s *h1s, struct h1m *h1m)
-{
-       if ((h1m->flags & H1_MF_RESP) && h1m->state == H1_MSG_DONE &&
-           h1s->status < 200 && (h1s->status == 100 || h1s->status >= 102)) {
-               h1m_init_res(&h1s->res);
-               h1m->flags |= (H1_MF_NO_PHDR|H1_MF_CLEAN_CONN_HDR);
-               h1s->h1c->flags &= ~H1C_F_IN_BUSY;
-       }
-}
-
 /*
  * Parse HTTP/1 headers. It returns the number of bytes parsed if > 0, or 0 if
  * it couldn't proceed. Parsing errors are reported by setting H1S_F_*_ERROR
@@ -1004,10 +989,6 @@ static size_t h1_process_headers(struct h1s *h1s, struct h1m *h1m, struct htx *h
                        /* Switch CONNECT requests to tunnel mode */
                        h1_set_req_tunnel_mode(h1s);
                }
-               else if (!(h1m->flags & H1_MF_CHNK) && !h1m->body_len) {
-                       /* Switch requests with no body to done. */
-                       h1m->state = H1_MSG_DONE;
-               }
 
                if (!h1_process_req_vsn(h1s, h1m, h1sl)) {
                        h1m->err_pos = h1sl.rq.v.ptr - b_head(buf);
@@ -1027,18 +1008,14 @@ static size_t h1_process_headers(struct h1s *h1s, struct h1m *h1m, struct htx *h
                else if ((h1s->meth == HTTP_METH_HEAD) ||
                         (h1s->status >= 100 && h1s->status < 200) ||
                         (h1s->status == 204) || (h1s->status == 304)) {
-                       /* Switch responses without body to done. */
+                       /* Responses known to have no body. */
                        h1m->flags &= ~(H1_MF_CLEN|H1_MF_CHNK);
                        h1m->flags |= H1_MF_XFER_LEN;
                        h1m->curr_len = h1m->body_len = 0;
-                       h1m->state = H1_MSG_DONE;
                }
                else if (h1m->flags & (H1_MF_CLEN|H1_MF_CHNK)) {
-                       /* Responses with a known body length. Switch requests
-                        * with no body to done. */
+                       /* Responses with a known body length. */
                        h1m->flags |= H1_MF_XFER_LEN;
-                       if ((h1m->flags & H1_MF_CLEN) && !h1m->body_len)
-                               h1m->state = H1_MSG_DONE;
                }
                else {
                        /* Responses with an unknown body length */
@@ -1061,16 +1038,25 @@ static size_t h1_process_headers(struct h1s *h1s, struct h1m *h1m, struct htx *h
                flags |= HTX_SL_F_XFER_LEN;
                if (h1m->flags & H1_MF_CHNK)
                        flags |= HTX_SL_F_CHNK;
-               else if (h1m->flags & H1_MF_CLEN)
+               else if (h1m->flags & H1_MF_CLEN) {
                        flags |= HTX_SL_F_CLEN;
-               if (h1m->state == H1_MSG_DONE)
+                       if (h1m->body_len == 0)
+                               flags |= HTX_SL_F_BODYLESS;
+               }
+               else
                        flags |= HTX_SL_F_BODYLESS;
        }
 
        used = htx_used_space(htx);
        if (!(h1m->flags & H1_MF_RESP)) {
-               if (h1_eval_htx_req_size(h1m, &h1sl, hdrs) > max)
-                       goto error;
+               if (h1_eval_htx_req_size(h1m, &h1sl, hdrs) > max) {
+                       if (htx_is_empty(htx))
+                               goto error;
+                       h1m_init_req(h1m);
+                       h1m->flags |= (H1_MF_NO_PHDR|H1_MF_CLEAN_CONN_HDR);
+                       ret = 0;
+                       goto end;
+               }
 
                sl = htx_add_stline(htx, HTX_BLK_REQ_SL, flags, h1sl.rq.m, h1sl.rq.u, h1sl.rq.v);
                if (!sl || !htx_add_all_headers(htx, hdrs))
@@ -1078,8 +1064,14 @@ static size_t h1_process_headers(struct h1s *h1s, struct h1m *h1m, struct htx *h
                sl->info.req.meth = h1s->meth;
        }
        else {
-               if (h1_eval_htx_res_size(h1m, &h1sl, hdrs) > max)
-                       goto error;
+               if (h1_eval_htx_res_size(h1m, &h1sl, hdrs) > max) {
+                       if (htx_is_empty(htx))
+                               goto error;
+                       h1m_init_res(h1m);
+                       h1m->flags |= (H1_MF_NO_PHDR|H1_MF_CLEAN_CONN_HDR);
+                       ret = 0;
+                       goto end;
+               }
 
                flags |= HTX_SL_F_IS_RESP;
                sl = htx_add_stline(htx, HTX_BLK_RES_SL, flags, h1sl.st.v, h1sl.st.c, h1sl.st.r);
@@ -1091,13 +1083,6 @@ static size_t h1_process_headers(struct h1s *h1s, struct h1m *h1m, struct htx *h
        /* Set bytes used in the HTX mesage for the headers now */
        sl->hdrs_bytes = htx_used_space(htx) - used;
 
-
-       if (h1m->state == H1_MSG_DONE) {
-               if (!htx_add_endof(htx, HTX_BLK_EOM))
-                       goto error;
-               h1s->cs->flags |= CS_FL_EOI;
-       }
-
        h1_process_input_conn_mode(h1s, h1m, htx);
 
        /* If body length cannot be determined, set htx->extra to
@@ -1113,6 +1098,8 @@ static size_t h1_process_headers(struct h1s *h1s, struct h1m *h1m, struct htx *h
        h1m->err_pos = h1m->next;
   vsn_error:
        h1s->flags |= (!(h1m->flags & H1_MF_RESP) ? H1S_F_REQ_ERROR : H1S_F_RES_ERROR);
+       h1s->cs->flags |= CS_FL_EOI;
+       htx->flags |= HTX_FL_PARSING_ERROR;
        h1_capture_bad_message(h1s->h1c, h1s, h1m, buf);
        ret = 0;
        goto end;
@@ -1315,6 +1302,8 @@ static size_t h1_process_data(struct h1s *h1s, struct h1m *h1m, struct htx *htx,
   end:
        if (ret < 0) {
                h1s->flags |= (!(h1m->flags & H1_MF_RESP) ? H1S_F_REQ_ERROR : H1S_F_RES_ERROR);
+               h1s->cs->flags |= CS_FL_EOI;
+               htx->flags |= HTX_FL_PARSING_ERROR;
                h1m->err_state = h1m->state;
                h1m->err_pos = *ofs + max + ret;
                h1_capture_bad_message(h1s->h1c, h1s, h1m, buf);
@@ -1359,6 +1348,11 @@ static size_t h1_process_input(struct h1c *h1c, struct buffer *buf, size_t count
                        ret = h1_process_headers(h1s, h1m, htx, &h1c->ibuf, &total, count);
                        if (!ret)
                                break;
+                       if ((h1m->flags & H1_MF_RESP) &&
+                           h1s->status < 200 && (h1s->status == 100 || h1s->status >= 102)) {
+                               h1m_init_res(&h1s->res);
+                               h1m->flags |= (H1_MF_NO_PHDR|H1_MF_CLEAN_CONN_HDR);
+                       }
                }
                else if (h1m->state <= H1_MSG_TRAILERS) {
                        ret = h1_process_data(h1s, h1m, htx, &h1c->ibuf, &total, count, buf);
@@ -1415,9 +1409,7 @@ static size_t h1_process_input(struct h1c *h1c, struct buffer *buf, size_t count
 
   parsing_err:
        b_reset(&h1c->ibuf);
-       htx->flags |= HTX_FL_PARSING_ERROR;
        htx_to_buf(htx, buf);
-       h1s->cs->flags |= CS_FL_EOI;
        return 0;
 }
 
@@ -1628,6 +1620,11 @@ static size_t h1_process_output(struct h1c *h1c, struct buffer *buf, size_t coun
                                         * to the client . Switch the response to tunnel mode. */
                                        h1_set_res_tunnel_mode(h1s);
                                }
+                               else if ((h1m->flags & H1_MF_RESP) &&
+                                        h1s->status < 200 && (h1s->status == 100 || h1s->status >= 102)) {
+                                       h1m_init_res(&h1s->res);
+                                       h1m->flags |= (H1_MF_NO_PHDR|H1_MF_CLEAN_CONN_HDR);
+                               }
                                else
                                        h1m->state = H1_MSG_DATA;
                                break;
@@ -1689,9 +1686,6 @@ static size_t h1_process_output(struct h1c *h1c, struct buffer *buf, size_t coun
                }
        }
 
-       if (htx_is_empty(chn_htx))
-               h1_handle_1xx_response(h1s, h1m);
-
   copy:
        /* when the output buffer is empty, tmp shares the same area so that we
         * only have to update pointers and lengths.
index 55c7619c51bff00551b9b3be0521a85ab7bb8c82..6bec578b6224180f502d433d71f364816d7557c4 100644 (file)
@@ -3670,7 +3670,7 @@ next_frame:
        if (!(msgf & H2_MSGF_RSP_1XX))
                *flags |= H2_SF_HEADERS_RCVD;
 
-       if ((h2c->dff & H2_F_HEADERS_END_STREAM) || (msgf & H2_MSGF_RSP_1XX)) {
+       if ((h2c->dff & H2_F_HEADERS_END_STREAM)) {
                /* Mark the end of message, either using EOM in HTX or with the
                 * trailing CRLF after the end of trailers. Note that DATA_CHNK
                 * is not set during headers with END_STREAM. For HTX trailers,
index dbbd937bdf14bafea0270cfa2b7034d3552e9e06..953b49f98d05a01d60e56d0c5c25c05867bddd32 100644 (file)
@@ -132,19 +132,7 @@ int htx_wait_for_request(struct stream *s, struct channel *req, int an_bit)
         * a timeout or connection reset is not counted as an error. However
         * a bad request is.
         */
-       if (unlikely(htx_is_empty(htx) || htx_get_tail_type(htx) < HTX_BLK_EOH)) {
-               /*
-                * First catch invalid request because only part of headers have
-                * been transfered. Multiplexers have the responsibility to emit
-                * all headers at once.
-                */
-               if (htx_is_not_empty(htx) || (s->si[0].flags & SI_FL_RXBLK_ROOM)) {
-                       stream_inc_http_req_ctr(s);
-                       stream_inc_http_err_ctr(s);
-                       proxy_inc_fe_req_ctr(sess->fe);
-                       goto return_bad_req;
-               }
-
+       if (unlikely(htx_is_empty(htx) || htx->sl_pos == -1)) {
                if (htx->flags & HTX_FL_UPGRADE)
                        goto failed_keep_alive;
 
@@ -1481,17 +1469,8 @@ int htx_wait_for_response(struct stream *s, struct channel *rep, int an_bit)
         * we should only check for HTTP status there, and check I/O
         * errors somewhere else.
         */
-       if (unlikely(co_data(rep) || htx_is_empty(htx) || htx_get_tail_type(htx) < HTX_BLK_EOH)) {
-               /*
-                * First catch invalid response because of a parsing error or
-                * because only part of headers have been transfered.
-                * Multiplexers have the responsibility to emit all headers at
-                * once. We must be sure to have forwarded all outgoing data
-                * first.
-                */
-               if (!co_data(rep) && (htx_is_not_empty(htx) || (s->si[1].flags & SI_FL_RXBLK_ROOM)))
-                       goto return_bad_res;
-
+  next_one:
+       if (unlikely(htx_is_empty(htx) || htx->sl_pos == -1)) {
                /* 1: have we encountered a read error ? */
                if (rep->flags & CF_READ_ERROR) {
                        struct connection *conn = NULL;
@@ -1719,18 +1698,20 @@ int htx_wait_for_response(struct stream *s, struct channel *rep, int an_bit)
                int32_t pos;
 
                FLT_STRM_CB(s, flt_http_reset(s, msg));
-               for (pos = htx_get_head(htx); pos != -1; pos = htx_get_next(htx, pos)) {
+               for (pos = htx_get_first(htx); pos != -1; pos = htx_get_next(htx, pos)) {
                        struct htx_blk *blk = htx_get_blk(htx, pos);
                        enum htx_blk_type type = htx_get_blk_type(blk);
 
                        c_adv(rep, htx_get_blksz(blk));
-                       if (type == HTX_BLK_EOM)
+                       if (type == HTX_BLK_EOH) {
+                               htx->sl_pos = htx_get_next(htx, pos);
                                break;
+                       }
                }
                msg->msg_state = HTTP_MSG_RPBEFORE;
                txn->status = 0;
                s->logs.t_data = -1; /* was not a response yet */
-               return 0;
+               goto next_one;
        }
 
        /*