diff --git a/include/proto/proto_http.h b/include/proto/proto_http.h index 40e82b2c3..0d3d7df05 100644 --- a/include/proto/proto_http.h +++ b/include/proto/proto_http.h @@ -75,6 +75,7 @@ void htx_res_set_status(unsigned int status, const char *reason, struct stream * void htx_check_request_for_cacheability(struct stream *s, struct channel *req); void htx_check_response_for_cacheability(struct stream *s, struct channel *res); int htx_send_name_header(struct stream *s, struct proxy *be, const char *srv_name); +void htx_perform_server_redirect(struct stream *s, struct stream_interface *si); void htx_server_error(struct stream *s, struct stream_interface *si, int err, int finst, const struct buffer *msg); void htx_reply_and_close(struct stream *s, short status, struct buffer *msg); diff --git a/src/proto_http.c b/src/proto_http.c index fc46826b5..90d1b859c 100644 --- a/src/proto_http.c +++ b/src/proto_http.c @@ -467,6 +467,9 @@ void http_perform_server_redirect(struct stream *s, struct stream_interface *si) char *path; int len, rewind; + if (IS_HTX_STRM(s)) + return htx_perform_server_redirect(s, si); + /* 1: create the response header */ trash.data = strlen(HTTP_302); memcpy(trash.area, HTTP_302, trash.data); diff --git a/src/proto_htx.c b/src/proto_htx.c index d7dbabac9..391470f00 100644 --- a/src/proto_htx.c +++ b/src/proto_htx.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include @@ -4765,6 +4766,60 @@ int htx_send_name_header(struct stream *s, struct proxy *be, const char *srv_nam return 0; } +void htx_perform_server_redirect(struct stream *s, struct stream_interface *si) +{ + struct http_txn *txn = s->txn; + struct htx *htx; + struct server *srv; + union h1_sl sl; + struct ist path; + + /* 1: create the response header */ + if (!chunk_memcat(&trash, HTTP_302, strlen(HTTP_302))) + return; + + /* 2: 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 != '/') { + if (!chunk_memcat(&trash, srv->rdr_pfx, srv->rdr_len)) + return; + } + + /* 3: add the request Path */ + htx = htx_from_buf(&s->req.buf); + sl = http_find_stline(htx); + path = http_get_path(sl.rq.u); + if (!path.ptr) + return; + + if (!chunk_memcat(&trash, path.ptr, path.len)) + return; + + 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; + } + + /* prepare to 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); + + /* FIXME: we should increase a counter of redirects per server and per backend. */ + srv_inc_sess_ctr(srv); + srv_set_sess_last(srv); +} + /* This function terminates the request because it was completly analyzed or * because an error was triggered during the body forwarding. */