]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MINOR: proto_htx: Send valid HTX message when redir mode is enabled on a server
authorChristopher Faulet <cfaulet@haproxy.com>
Wed, 28 Nov 2018 16:46:40 +0000 (17:46 +0100)
committerWilly Tarreau <w@1wt.eu>
Sat, 1 Dec 2018 16:37:27 +0000 (17:37 +0100)
The function htx_perform_server_redirect() has been rewritten to send a valid
HTX message.

src/proto_htx.c

index 04afa1f1fc898a13129bb7277d7ab5231c625e17..da28dbc340937772ecd85fa78ba5dd9706625472 100644 (file)
@@ -4899,17 +4899,21 @@ static int htx_handle_stats(struct stream *s, struct channel *req)
 
 void htx_perform_server_redirect(struct stream *s, struct stream_interface *si)
 {
-       struct http_txn *txn = s->txn;
+       struct channel *req = &s->req;
+       struct channel *res = &s->res;
+       struct server *srv;
        struct htx *htx;
        struct htx_sl *sl;
-       struct server *srv;
-       struct ist path;
+       struct ist path, location;
+       unsigned int flags;
+       size_t data;
 
-       /* 1: create the response header */
-       if (!chunk_memcat(&trash, HTTP_302, strlen(HTTP_302)))
-               return;
+       /*
+        * Create the location
+        */
+       chunk_reset(&trash);
 
-       /* 2: add the server's prefix */
+       /* 1: add the server's prefix */
        /* special prefix "/" means don't change URL */
        srv = __objt_server(s->target);
        if (srv->rdr_len != 1 || *srv->rdr_pfx != '/') {
@@ -4917,8 +4921,8 @@ void htx_perform_server_redirect(struct stream *s, struct stream_interface *si)
                        return;
        }
 
-       /* 3: add the request Path */
-       htx = htx_from_buf(&s->req.buf);
+       /* 2: add the request Path */
+       htx = htx_from_buf(&req->buf);
        sl = http_find_stline(htx);
        path = http_get_path(htx_sl_req_uri(sl));
        if (!path.ptr)
@@ -4926,29 +4930,64 @@ void htx_perform_server_redirect(struct stream *s, struct stream_interface *si)
 
        if (!chunk_memcat(&trash, path.ptr, path.len))
                return;
+       location = ist2(trash.area, trash.data);
 
-       if (unlikely(txn->flags & TX_USE_PX_CONN)) {
-               if (!chunk_memcat(&trash, "\r\nProxy-Connection: close\r\n\r\n", 29))
-                       return;
-       }
-       else {
-               if (!chunk_memcat(&trash, "\r\nConnection: close\r\n\r\n", 23))
-                       return;
-       }
+       /*
+        * Create the 302 respone
+        */
+       htx = htx_from_buf(&res->buf);
+       flags = (HTX_SL_F_IS_RESP|HTX_SL_F_VER_11|HTX_SL_F_XFER_LEN|HTX_SL_F_BODYLESS);
+       sl = htx_add_stline(htx, HTX_BLK_RES_SL, flags,
+                           ist("HTTP/1.1"), ist("302"), ist("Found"));
+       if (!sl)
+               goto fail;
+       sl->info.res.status = 302;
+       s->txn->status = 302;
 
-       /* prepare to return without error. */
+        if (!htx_add_header(htx, ist("Cache-Control"), ist("no-cache")) ||
+           !htx_add_header(htx, ist("Connection"), ist("close")) ||
+           !htx_add_header(htx, ist("Content-length"), ist("0")) ||
+           !htx_add_header(htx, ist("Location"), location))
+               goto fail;
+
+       if (!htx_add_endof(htx, HTX_BLK_EOH) || !htx_add_endof(htx, HTX_BLK_EOM))
+               goto fail;
+
+       /*
+        * Send the message
+        */
+       data = htx->data - co_data(res);
+       b_set_data(&res->buf, b_size(&res->buf));
+       c_adv(res, data);
+       res->total += data;
+
+       /* return without error. */
        si_shutr(si);
        si_shutw(si);
        si->err_type = SI_ET_NONE;
        si->state    = SI_ST_CLO;
 
-       /* send the message */
-       txn->status = 302;
-       htx_server_error(s, si, SF_ERR_LOCAL, SF_FINST_C, &trash);
+       channel_auto_read(req);
+       channel_abort(req);
+       channel_auto_close(req);
+       channel_erase(req);
+       channel_auto_read(res);
+       channel_auto_close(res);
+
+       if (!(s->flags & SF_ERR_MASK))
+               s->flags |= SF_ERR_LOCAL;
+       if (!(s->flags & SF_FINST_MASK))
+               s->flags |= SF_FINST_C;
 
        /* FIXME: we should increase a counter of redirects per server and per backend. */
        srv_inc_sess_ctr(srv);
        srv_set_sess_last(srv);
+       return;
+
+  fail:
+       /* If an error occurred, remove the incomplete HTTP response from the
+        * buffer */
+       channel_truncate(res);
 }
 
 /* This function terminates the request because it was completly analyzed or