diff --git a/src/proto_htx.c b/src/proto_htx.c index 04afa1f1f..da28dbc34 100644 --- a/src/proto_htx.c +++ b/src/proto_htx.c @@ -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