]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MEDIUM: http: add support for sending the server's name in the outgoing request
authorMark Lamourine <markllama@redhat.com>
Wed, 4 Jan 2012 18:02:01 +0000 (13:02 -0500)
committerWilly Tarreau <w@1wt.eu>
Thu, 5 Jan 2012 14:17:31 +0000 (15:17 +0100)
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.

doc/configuration.txt
include/proto/proto_http.h
include/types/proxy.h
src/cfgparse.c
src/proto_http.c
src/session.c
tests/test-http-send-name-hdr.cfg [new file with mode: 0644]

index 066f935683f25f3a2555268070a4331c9cd2358e..3e777fad21955d05efa11e9447e2be07b6bf0581 100644 (file)
@@ -2523,6 +2523,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
@@ -4760,7 +4776,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 or IPv6 address of the server. Alternatively, a
               resolvable hostname is supported, but this name will be resolved
@@ -4787,7 +4804,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 } ]
index f5dcbce30cacae011bc53072e18cf2ff67221347..0eed363ea90b888ca70cacd92ee129a003b9a757 100644 (file)
@@ -71,6 +71,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);
index 593260e2fd214460872f5ddd093d7378eeb89c15..d0bc51cafd1004bdf8f10fb62012a71e647d145f 100644 (file)
@@ -272,6 +272,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 */
index bf2eb36c4f5e6111d3fbe4446ebf66be757f7ad3..b881cd94d6a80960e6862bc91747785ac538687d 100644 (file)
@@ -1431,6 +1431,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;
@@ -1560,6 +1565,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);
 
@@ -2460,6 +2467,23 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm)
                err_code |= warnif_cond_requires_resp(rule->cond, file, linenum);
                LIST_ADDQ(&curproxy->http_req_rules, &rule->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]);
index 1906916b309b540de1a7f8b1419f49d7d269a127..c6cfb358c0a3a8ce9e6d4caa4b60a51c5d4bb267 100644 (file)
@@ -3932,6 +3932,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.
  */
index c465990923613debe9d41304b8a9bc657013a88b..d87813e3710a78dacbcf6076796196e88b82b23d 100644 (file)
@@ -1885,6 +1885,19 @@ struct task *process_session(struct task *t)
                        if (s->si[1].state == SI_ST_ASS && srv && 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,
+                                             target_srv(&s->target)->id);
+               }
        }
 
        /* Benchmarks have shown that it's optimal to do a full resync now */
diff --git a/tests/test-http-send-name-hdr.cfg b/tests/test-http-send-name-hdr.cfg
new file mode 100644 (file)
index 0000000..65fc0d0
--- /dev/null
@@ -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
+