Skip to content

Commit

Permalink
MEDIUM: http: add support for sending the server's name in the outgoi…
Browse files Browse the repository at this point in the history
…ng request

New option "http-send-name-header" specifies the name of a header which
will hold the server name in outgoing requests. This is the name of the
server the connection is really sent to, which means that upon redispatches,
the header's value is updated so that it always matches the server's name.
(cherry picked from commit c2247f0b8d37cc31d34e586fcc60ae67b398feb8)
  • Loading branch information
Mark Lamourine authored and wtarreau committed Jan 5, 2012
1 parent f50e75b commit 0742b31
Show file tree
Hide file tree
Showing 7 changed files with 121 additions and 2 deletions.
22 changes: 20 additions & 2 deletions doc/configuration.txt
Expand Up @@ -2330,6 +2330,22 @@ http-request { allow | deny | auth [realm <realm>] }
See also : "stats http-request", section 3.4 about userlists and section 7
about ACL usage.

http-send-name-header [<header>]
Add the server name to a request. Use the header string given by <header>

May be used in sections: defaults | frontend | listen | backend
yes | no | yes | yes

Arguments :

<header> The header string to use to send the server name

The "http-send-name-header" statement causes the name of the target
server to be added to the headers of an HTTP request. The name
is added with the header string proved.

See also : "server"

id <value>
Set a persistent ID to a proxy.
May be used in sections : defaults | frontend | listen | backend
Expand Down Expand Up @@ -4527,7 +4543,8 @@ server <name> <address>[:port] [param*]
no | no | yes | yes
Arguments :
<name> is the internal name assigned to this server. This name will
appear in logs and alerts.
appear in logs and alerts. If "http-send-server-name" is
set, it will be added to the request header sent to the server.

<address> is the IPv4 address of the server. Alternatively, a resolvable
hostname is supported, but this name will be resolved during
Expand All @@ -4551,7 +4568,8 @@ server <name> <address>[:port] [param*]
server first 10.1.1.1:1080 cookie first check inter 1000
server second 10.1.1.2:1080 cookie second check inter 1000

See also: "default-server" and section 5 about server options
See also: "default-server", "http-send-name-header" and section 5 about
server options


source <addr>[:<port>] [usesrc { <addr2>[:<port2>] | client | clientip } ]
Expand Down
1 change: 1 addition & 0 deletions include/proto/proto_http.h
Expand Up @@ -66,6 +66,7 @@ int http_process_req_common(struct session *s, struct buffer *req, int an_bit, s
int http_process_request(struct session *t, struct buffer *req, int an_bit);
int http_process_tarpit(struct session *s, struct buffer *req, int an_bit);
int http_process_request_body(struct session *s, struct buffer *req, int an_bit);
int http_send_name_header(struct http_txn *txn, struct http_msg *msg, struct buffer *buf, struct proxy* be, const char* svr_name);
int http_wait_for_response(struct session *s, struct buffer *rep, int an_bit);
int http_process_res_common(struct session *t, struct buffer *rep, int an_bit, struct proxy *px);
int http_request_forward_body(struct session *s, struct buffer *req, int an_bit);
Expand Down
2 changes: 2 additions & 0 deletions include/types/proxy.h
Expand Up @@ -258,6 +258,8 @@ struct proxy {
int fwdfor_hdr_len; /* length of "x-forwarded-for" header */
char *orgto_hdr_name; /* header to use - default: "x-original-to" */
int orgto_hdr_len; /* length of "x-original-to" header */
char *server_id_hdr_name; /* the header to use to send the server id (name) */
int server_id_hdr_len; /* the length of the id (name) header... name */

unsigned down_trans; /* up-down transitions */
unsigned down_time; /* total time the proxy was down */
Expand Down
24 changes: 24 additions & 0 deletions src/cfgparse.c
Expand Up @@ -1182,6 +1182,11 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm)
curproxy->orgto_hdr_name = strdup(defproxy.orgto_hdr_name);
}

if (defproxy.server_id_hdr_len) {
curproxy->server_id_hdr_len = defproxy.server_id_hdr_len;
curproxy->server_id_hdr_name = strdup(defproxy.server_id_hdr_name);
}

if (curproxy->cap & PR_CAP_FE) {
curproxy->maxconn = defproxy.maxconn;
curproxy->backlog = defproxy.backlog;
Expand Down Expand Up @@ -1310,6 +1315,8 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm)
defproxy.fwdfor_hdr_len = 0;
free(defproxy.orgto_hdr_name);
defproxy.orgto_hdr_len = 0;
free(defproxy.server_id_hdr_name);
defproxy.server_id_hdr_len = 0;
free(defproxy.expect_str);
if (defproxy.expect_regex) regfree(defproxy.expect_regex);

Expand Down Expand Up @@ -2084,6 +2091,23 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm)
err_code |= warnif_cond_requires_resp(req_acl->cond, file, linenum);
LIST_ADDQ(&curproxy->req_acl, &req_acl->list);
}
else if (!strcmp(args[0], "http-send-name-header")) { /* send server name in request header */
/* set the header name and length into the proxy structure */
if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[0], NULL))
err_code |= ERR_WARN;

if (!*args[1]) {
Alert("parsing [%s:%d] : '%s' requires a header string.\n",
file, linenum, args[0]);
err_code |= ERR_ALERT | ERR_FATAL;
goto out;
}

/* set the desired header name */
free(curproxy->server_id_hdr_name);
curproxy->server_id_hdr_name = strdup(args[1]);
curproxy->server_id_hdr_len = strlen(curproxy->server_id_hdr_name);
}
else if (!strcmp(args[0], "block")) { /* early blocking based on ACLs */
if (curproxy == &defproxy) {
Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
Expand Down
28 changes: 28 additions & 0 deletions src/proto_http.c
Expand Up @@ -3859,6 +3859,34 @@ int http_process_request_body(struct session *s, struct buffer *req, int an_bit)
return 0;
}

int http_send_name_header(struct http_txn *txn, struct http_msg *msg, struct buffer *buf, struct proxy* be, const char* srv_name) {

struct hdr_ctx ctx;

ctx.idx = 0;

char *hdr_name = be->server_id_hdr_name;
int hdr_name_len = be->server_id_hdr_len;

char *hdr_val;

while (http_find_header2(hdr_name, hdr_name_len, msg->sol, &txn->hdr_idx, &ctx)) {
/* remove any existing values from the header */
http_remove_header2(msg, buf, &txn->hdr_idx, &ctx);
}

/* Add the new header requested with the server value */
hdr_val = trash;
memcpy(hdr_val, hdr_name, hdr_name_len);
hdr_val += hdr_name_len;
*hdr_val++ = ':';
*hdr_val++ = ' ';
hdr_val += strlcpy2(hdr_val, srv_name, trash + sizeof(trash) - hdr_val);
http_header_add_tail2(buf, msg, &txn->hdr_idx, trash, hdr_val - trash);

return 0;
}

/* Terminate current transaction and prepare a new one. This is very tricky
* right now but it works.
*/
Expand Down
13 changes: 13 additions & 0 deletions src/session.c
Expand Up @@ -1408,6 +1408,19 @@ struct task *process_session(struct task *t)
s->srv->rdr_len && (s->flags & SN_REDIRECTABLE))
perform_http_redirect(s, &s->si[1]);
} while (s->si[1].state == SI_ST_ASS);

/* Now we can add the server name to a header (if requested) */
/* check for HTTP mode and proxy server_name_hdr_name != NULL */
if ((s->flags && SN_BE_ASSIGNED) &&
(s->be->mode == PR_MODE_HTTP) &&
(s->be->server_id_hdr_name != NULL)) {

http_send_name_header(&s->txn,
&s->txn.req,
s->req,
s->be,
s->srv->id);
}
}

/* Benchmarks have shown that it's optimal to do a full resync now */
Expand Down
33 changes: 33 additions & 0 deletions tests/test-http-send-name-hdr.cfg
@@ -0,0 +1,33 @@
# Test Rewriting Host header
global
maxconn 100

defaults
mode http
timeout client 10000
timeout server 10000
timeout connect 10000
balance roundrobin

listen send-name-silo-id
bind :8001

# Set the test conditions: Add a new header
http-send-name-header X-Silo-Id
server srv-silo1 127.0.0.1:8080

# Add headers containing the correct values for test verification
reqadd X-test-server-name-header:\ X-Silo-Id
reqadd X-test-server-name-value:\ srv-silo1

listen send-name-host
bind :8002

# Set the test conditions: Replace an existing header
http-send-name-header host
server srv-host 127.0.0.1:8080

# Add headers containing the correct values for test verification
reqadd X-test-server-name-header:\ Host
reqadd X-test-server-name-value:\ srv-host

0 comments on commit 0742b31

Please sign in to comment.