mirror of
https://git.haproxy.org/git/haproxy.git/
synced 2025-09-22 22:31:28 +02:00
MINOR: proto_htx: Rewrite htx_apply_redirect_rule to handle HTX messages
This commit is contained in:
parent
7ff1ceaa5e
commit
80f14bffc7
193
src/proto_htx.c
193
src/proto_htx.c
@ -2354,8 +2354,8 @@ void htx_adjust_conn_mode(struct stream *s, struct http_txn *txn)
|
|||||||
*/
|
*/
|
||||||
int htx_apply_redirect_rule(struct redirect_rule *rule, struct stream *s, struct http_txn *txn)
|
int htx_apply_redirect_rule(struct redirect_rule *rule, struct stream *s, struct http_txn *txn)
|
||||||
{
|
{
|
||||||
struct http_msg *req = &txn->req;
|
struct htx *htx = htx_from_buf(&s->req.buf);
|
||||||
struct http_msg *res = &txn->rsp;
|
union h1_sl sl;
|
||||||
const char *msg_fmt;
|
const char *msg_fmt;
|
||||||
struct buffer *chunk;
|
struct buffer *chunk;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
@ -2389,178 +2389,129 @@ int htx_apply_redirect_rule(struct redirect_rule *rule, struct stream *s, struct
|
|||||||
|
|
||||||
switch(rule->type) {
|
switch(rule->type) {
|
||||||
case REDIRECT_TYPE_SCHEME: {
|
case REDIRECT_TYPE_SCHEME: {
|
||||||
const char *path;
|
struct http_hdr_ctx ctx;
|
||||||
const char *host;
|
struct ist path, host;
|
||||||
struct hdr_ctx ctx;
|
|
||||||
int pathlen;
|
|
||||||
int hostlen;
|
|
||||||
|
|
||||||
host = "";
|
host = ist("");
|
||||||
hostlen = 0;
|
ctx.blk = NULL;
|
||||||
ctx.idx = 0;
|
if (http_find_header(htx, ist("Host"), &ctx, 0))
|
||||||
if (http_find_header2("Host", 4, ci_head(req->chn), &txn->hdr_idx, &ctx)) {
|
host = ctx.value;
|
||||||
host = ctx.line + ctx.val;
|
|
||||||
hostlen = ctx.vlen;
|
|
||||||
}
|
|
||||||
|
|
||||||
path = http_txn_get_path(txn);
|
sl = http_find_stline(htx);
|
||||||
|
path = http_get_path(sl.rq.u);
|
||||||
/* build message using path */
|
/* build message using path */
|
||||||
if (path) {
|
if (path.ptr) {
|
||||||
pathlen = req->sl.rq.u_l + (ci_head(req->chn) + req->sl.rq.u) - path;
|
|
||||||
if (rule->flags & REDIRECT_FLAG_DROP_QS) {
|
if (rule->flags & REDIRECT_FLAG_DROP_QS) {
|
||||||
int qs = 0;
|
int qs = 0;
|
||||||
while (qs < pathlen) {
|
while (qs < path.len) {
|
||||||
if (path[qs] == '?') {
|
if (*(path.ptr + qs) == '?') {
|
||||||
pathlen = qs;
|
path.len = qs;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
qs++;
|
qs++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
path = "/";
|
|
||||||
pathlen = 1;
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
path = ist("/");
|
||||||
|
|
||||||
if (rule->rdr_str) { /* this is an old "redirect" rule */
|
if (rule->rdr_str) { /* this is an old "redirect" rule */
|
||||||
/* check if we can add scheme + "://" + host + path */
|
|
||||||
if (chunk->data + rule->rdr_len + 3 + hostlen + pathlen > chunk->size - 4)
|
|
||||||
goto leave;
|
|
||||||
|
|
||||||
/* add scheme */
|
/* add scheme */
|
||||||
memcpy(chunk->area + chunk->data, rule->rdr_str,
|
if (!chunk_memcat(chunk, rule->rdr_str, rule->rdr_len))
|
||||||
rule->rdr_len);
|
goto leave;
|
||||||
chunk->data += rule->rdr_len;
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
/* add scheme with executing log format */
|
/* add scheme with executing log format */
|
||||||
chunk->data += build_logline(s,
|
chunk->data += build_logline(s, chunk->area + chunk->data,
|
||||||
chunk->area + chunk->data,
|
|
||||||
chunk->size - chunk->data,
|
chunk->size - chunk->data,
|
||||||
&rule->rdr_fmt);
|
&rule->rdr_fmt);
|
||||||
|
|
||||||
/* check if we can add scheme + "://" + host + path */
|
|
||||||
if (chunk->data + 3 + hostlen + pathlen > chunk->size - 4)
|
|
||||||
goto leave;
|
|
||||||
}
|
}
|
||||||
/* add "://" */
|
/* add "://" + host + path */
|
||||||
memcpy(chunk->area + chunk->data, "://", 3);
|
if (!chunk_memcat(chunk, "://", 3) ||
|
||||||
chunk->data += 3;
|
!chunk_memcat(chunk, host.ptr, host.len) ||
|
||||||
|
!chunk_memcat(chunk, path.ptr, path.len))
|
||||||
/* add host */
|
goto leave;
|
||||||
memcpy(chunk->area + chunk->data, host, hostlen);
|
|
||||||
chunk->data += hostlen;
|
|
||||||
|
|
||||||
/* add path */
|
|
||||||
memcpy(chunk->area + chunk->data, path, pathlen);
|
|
||||||
chunk->data += pathlen;
|
|
||||||
|
|
||||||
/* append a slash at the end of the location if needed and missing */
|
/* append a slash at the end of the location if needed and missing */
|
||||||
if (chunk->data && chunk->area[chunk->data - 1] != '/' &&
|
if (chunk->data && chunk->area[chunk->data - 1] != '/' &&
|
||||||
(rule->flags & REDIRECT_FLAG_APPEND_SLASH)) {
|
(rule->flags & REDIRECT_FLAG_APPEND_SLASH)) {
|
||||||
if (chunk->data > chunk->size - 5)
|
if (chunk->data + 1 >= chunk->size)
|
||||||
goto leave;
|
goto leave;
|
||||||
chunk->area[chunk->data] = '/';
|
chunk->area[chunk->data++] = '/';
|
||||||
chunk->data++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case REDIRECT_TYPE_PREFIX: {
|
case REDIRECT_TYPE_PREFIX: {
|
||||||
const char *path;
|
struct ist path;
|
||||||
int pathlen;
|
|
||||||
|
|
||||||
path = http_txn_get_path(txn);
|
sl = http_find_stline(htx);
|
||||||
|
path = http_get_path(sl.rq.u);
|
||||||
/* build message using path */
|
/* build message using path */
|
||||||
if (path) {
|
if (path.ptr) {
|
||||||
pathlen = req->sl.rq.u_l + (ci_head(req->chn) + req->sl.rq.u) - path;
|
|
||||||
if (rule->flags & REDIRECT_FLAG_DROP_QS) {
|
if (rule->flags & REDIRECT_FLAG_DROP_QS) {
|
||||||
int qs = 0;
|
int qs = 0;
|
||||||
while (qs < pathlen) {
|
while (qs < path.len) {
|
||||||
if (path[qs] == '?') {
|
if (*(path.ptr + qs) == '?') {
|
||||||
pathlen = qs;
|
path.len = qs;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
qs++;
|
qs++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
path = "/";
|
|
||||||
pathlen = 1;
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
path = ist("/");
|
||||||
|
|
||||||
if (rule->rdr_str) { /* this is an old "redirect" rule */
|
if (rule->rdr_str) { /* this is an old "redirect" rule */
|
||||||
if (chunk->data + rule->rdr_len + pathlen > chunk->size - 4)
|
|
||||||
goto leave;
|
|
||||||
|
|
||||||
/* add prefix. Note that if prefix == "/", we don't want to
|
/* add prefix. Note that if prefix == "/", we don't want to
|
||||||
* add anything, otherwise it makes it hard for the user to
|
* add anything, otherwise it makes it hard for the user to
|
||||||
* configure a self-redirection.
|
* configure a self-redirection.
|
||||||
*/
|
*/
|
||||||
if (rule->rdr_len != 1 || *rule->rdr_str != '/') {
|
if (rule->rdr_len != 1 || *rule->rdr_str != '/') {
|
||||||
memcpy(chunk->area + chunk->data,
|
if (!chunk_memcat(chunk, rule->rdr_str, rule->rdr_len))
|
||||||
rule->rdr_str, rule->rdr_len);
|
goto leave;
|
||||||
chunk->data += rule->rdr_len;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
/* add prefix with executing log format */
|
/* add prefix with executing log format */
|
||||||
chunk->data += build_logline(s,
|
chunk->data += build_logline(s, chunk->area + chunk->data,
|
||||||
chunk->area + chunk->data,
|
|
||||||
chunk->size - chunk->data,
|
chunk->size - chunk->data,
|
||||||
&rule->rdr_fmt);
|
&rule->rdr_fmt);
|
||||||
|
|
||||||
/* Check length */
|
|
||||||
if (chunk->data + pathlen > chunk->size - 4)
|
|
||||||
goto leave;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* add path */
|
/* add path */
|
||||||
memcpy(chunk->area + chunk->data, path, pathlen);
|
if (!chunk_memcat(chunk, path.ptr, path.len))
|
||||||
chunk->data += pathlen;
|
goto leave;
|
||||||
|
|
||||||
/* append a slash at the end of the location if needed and missing */
|
/* append a slash at the end of the location if needed and missing */
|
||||||
if (chunk->data && chunk->area[chunk->data - 1] != '/' &&
|
if (chunk->data && chunk->area[chunk->data - 1] != '/' &&
|
||||||
(rule->flags & REDIRECT_FLAG_APPEND_SLASH)) {
|
(rule->flags & REDIRECT_FLAG_APPEND_SLASH)) {
|
||||||
if (chunk->data > chunk->size - 5)
|
if (chunk->data + 1 >= chunk->size)
|
||||||
goto leave;
|
goto leave;
|
||||||
chunk->area[chunk->data] = '/';
|
chunk->area[chunk->data++] = '/';
|
||||||
chunk->data++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case REDIRECT_TYPE_LOCATION:
|
case REDIRECT_TYPE_LOCATION:
|
||||||
default:
|
default:
|
||||||
if (rule->rdr_str) { /* this is an old "redirect" rule */
|
if (rule->rdr_str) { /* this is an old "redirect" rule */
|
||||||
if (chunk->data + rule->rdr_len > chunk->size - 4)
|
|
||||||
goto leave;
|
|
||||||
|
|
||||||
/* add location */
|
/* add location */
|
||||||
memcpy(chunk->area + chunk->data, rule->rdr_str,
|
if (!chunk_memcat(chunk, rule->rdr_str, rule->rdr_len))
|
||||||
rule->rdr_len);
|
goto leave;
|
||||||
chunk->data += rule->rdr_len;
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
/* add location with executing log format */
|
/* add location with executing log format */
|
||||||
chunk->data += build_logline(s,
|
chunk->data += build_logline(s, chunk->area + chunk->data,
|
||||||
chunk->area + chunk->data,
|
|
||||||
chunk->size - chunk->data,
|
chunk->size - chunk->data,
|
||||||
&rule->rdr_fmt);
|
&rule->rdr_fmt);
|
||||||
|
|
||||||
/* Check left length */
|
|
||||||
if (chunk->data > chunk->size - 4)
|
|
||||||
goto leave;
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rule->cookie_len) {
|
if (rule->cookie_len) {
|
||||||
memcpy(chunk->area + chunk->data, "\r\nSet-Cookie: ", 14);
|
if (!chunk_memcat(chunk, "\r\nSet-Cookie: ", 14) ||
|
||||||
chunk->data += 14;
|
!chunk_memcat(chunk, rule->cookie_str, rule->cookie_len))
|
||||||
memcpy(chunk->area + chunk->data, rule->cookie_str,
|
goto leave;
|
||||||
rule->cookie_len);
|
|
||||||
chunk->data += rule->cookie_len;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* add end of headers and the keep-alive/close status. */
|
/* add end of headers and the keep-alive/close status. */
|
||||||
@ -2568,50 +2519,16 @@ int htx_apply_redirect_rule(struct redirect_rule *rule, struct stream *s, struct
|
|||||||
/* let's log the request time */
|
/* let's log the request time */
|
||||||
s->logs.tv_request = now;
|
s->logs.tv_request = now;
|
||||||
|
|
||||||
if (((!(req->flags & HTTP_MSGF_TE_CHNK) && !req->body_len) || (req->msg_state == HTTP_MSG_DONE))) {
|
/* FIXME: close for now, but it could be cool to handle the keep-alive here */
|
||||||
/* keep-alive possible */
|
|
||||||
if (!(req->flags & HTTP_MSGF_VER_11)) {
|
|
||||||
if (unlikely(txn->flags & TX_USE_PX_CONN)) {
|
if (unlikely(txn->flags & TX_USE_PX_CONN)) {
|
||||||
memcpy(chunk->area + chunk->data,
|
if (!chunk_memcat(chunk, "\r\nProxy-Connection: close\r\n\r\n", 29))
|
||||||
"\r\nProxy-Connection: keep-alive", 30);
|
goto leave;
|
||||||
chunk->data += 30;
|
|
||||||
} else {
|
} else {
|
||||||
memcpy(chunk->area + chunk->data,
|
if (!chunk_memcat(chunk, "\r\nConnection: close\r\n\r\n", 23))
|
||||||
"\r\nConnection: keep-alive", 24);
|
goto leave;
|
||||||
chunk->data += 24;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
memcpy(chunk->area + chunk->data, "\r\n\r\n", 4);
|
|
||||||
chunk->data += 4;
|
|
||||||
FLT_STRM_CB(s, flt_http_reply(s, txn->status, chunk));
|
|
||||||
co_inject(res->chn, chunk->area, chunk->data);
|
|
||||||
/* "eat" the request */
|
|
||||||
b_del(&req->chn->buf, req->sov);
|
|
||||||
req->next -= req->sov;
|
|
||||||
req->sov = 0;
|
|
||||||
s->req.analysers = AN_REQ_HTTP_XFER_BODY | (s->req.analysers & AN_REQ_FLT_END);
|
|
||||||
s->res.analysers = AN_RES_HTTP_XFER_BODY | (s->res.analysers & AN_RES_FLT_END);
|
|
||||||
req->msg_state = HTTP_MSG_CLOSED;
|
|
||||||
res->msg_state = HTTP_MSG_DONE;
|
|
||||||
/* Trim any possible response */
|
|
||||||
b_set_data(&res->chn->buf, co_data(res->chn));
|
|
||||||
res->next = res->sov = 0;
|
|
||||||
/* let the server side turn to SI_ST_CLO */
|
|
||||||
channel_shutw_now(req->chn);
|
|
||||||
} else {
|
|
||||||
/* keep-alive not possible */
|
|
||||||
if (unlikely(txn->flags & TX_USE_PX_CONN)) {
|
|
||||||
memcpy(chunk->area + chunk->data,
|
|
||||||
"\r\nProxy-Connection: close\r\n\r\n", 29);
|
|
||||||
chunk->data += 29;
|
|
||||||
} else {
|
|
||||||
memcpy(chunk->area + chunk->data,
|
|
||||||
"\r\nConnection: close\r\n\r\n", 23);
|
|
||||||
chunk->data += 23;
|
|
||||||
}
|
|
||||||
http_reply_and_close(s, txn->status, chunk);
|
|
||||||
req->chn->analysers &= AN_REQ_FLT_END;
|
|
||||||
}
|
}
|
||||||
|
htx_reply_and_close(s, txn->status, chunk);
|
||||||
|
s->req.analysers &= AN_REQ_FLT_END;
|
||||||
|
|
||||||
if (!(s->flags & SF_ERR_MASK))
|
if (!(s->flags & SF_ERR_MASK))
|
||||||
s->flags |= SF_ERR_LOCAL;
|
s->flags |= SF_ERR_LOCAL;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user