MEDIUM: proxy/http_ext: implement dynamic http_ext
proxy http-only options implemented in http_ext were statically stored
within proxy struct.
We're making some changes so that http_ext are now stored in a dynamically
allocated structs.
http_ext related structs are only allocated when needed to save some space
whenever possible, and they are automatically freed upon proxy deletion.
Related PX_O_HTTP{7239,XFF,XOT) option flags were removed because we're now
considering an http_ext option as 'active' if it is allocated (ptr is not NULL)
A few checks (and BUG_ON) were added to make these changes safe because
it adds some (acceptable) complexity to the previous design.
Also, proxy.http was renamed to proxy.http_ext to make things more explicit.
diff --git a/include/haproxy/http_ext-t.h b/include/haproxy/http_ext-t.h
index ab83b35..68eb047 100644
--- a/include/haproxy/http_ext-t.h
+++ b/include/haproxy/http_ext-t.h
@@ -132,4 +132,18 @@
struct net_addr except_net; /* don't forward x-original-to for this address. */
};
+/* http_ext options */
+struct http_ext {
+ /* forwarded header (RFC 7239) */
+ struct http_ext_7239 *fwd;
+ /* x-forward-for:
+ * conditionally insert x-forwarded-for with client address
+ */
+ struct http_ext_xff *xff;
+ /* x-original-to:
+ * insert x-original-to with destination address
+ */
+ struct http_ext_xot *xot;
+};
+
#endif /* !_HAPROXY_HTTPEXT_T_H */
diff --git a/include/haproxy/http_ext.h b/include/haproxy/http_ext.h
index 63ecafb..53764a2 100644
--- a/include/haproxy/http_ext.h
+++ b/include/haproxy/http_ext.h
@@ -33,17 +33,26 @@
int http_handle_xff_header(struct stream *s, struct channel *req);
int http_handle_xot_header(struct stream *s, struct channel *req);
-void http_ext_7239_clean(struct http_ext_7239 *);
-void http_ext_xff_clean(struct http_ext_xff *);
-void http_ext_xot_clean(struct http_ext_xot *);
-
-void http_ext_7239_copy(struct http_ext_7239 *dest, const struct http_ext_7239 *orig);
-void http_ext_xff_copy(struct http_ext_xff *dest, const struct http_ext_xff *orig);
-void http_ext_xot_copy(struct http_ext_xot *dest, const struct http_ext_xot *orig);
-
int proxy_http_parse_7239(char **args, int cur_arg, struct proxy *curproxy, const struct proxy *defpx, const char *file, int linenum);
int proxy_http_compile_7239(struct proxy *curproxy);
int proxy_http_parse_xff(char **args, int cur_arg, struct proxy *curproxy, const struct proxy *defpx, const char *file, int linenum);
int proxy_http_parse_xot(char **args, int cur_arg, struct proxy *curproxy, const struct proxy *defpx, const char *file, int linenum);
+int http_ext_7239_prepare(struct proxy *cur);
+int http_ext_xff_prepare(struct proxy *cur);
+int http_ext_xot_prepare(struct proxy *cur);
+
+void http_ext_7239_dup(const struct proxy *def, struct proxy *cpy);
+void http_ext_xff_dup(const struct proxy *def, struct proxy *cpy);
+void http_ext_xot_dup(const struct proxy *def, struct proxy *cpy);
+
+void http_ext_7239_clean(struct proxy *cur);
+void http_ext_xff_clean(struct proxy *cur);
+void http_ext_xot_clean(struct proxy *cur);
+
+int http_ext_prepare(struct proxy *cur);
+void http_ext_dup(const struct proxy *def, struct proxy *cpy);
+void http_ext_clean(struct proxy *cur);
+void http_ext_softclean(struct proxy *cur);
+
#endif /* !_HAPROXY_HTTPEXT_H */
diff --git a/include/haproxy/proxy-t.h b/include/haproxy/proxy-t.h
index 8391f9f..3db2d3e 100644
--- a/include/haproxy/proxy-t.h
+++ b/include/haproxy/proxy-t.h
@@ -88,7 +88,7 @@
#define PR_O_PREF_LAST 0x00000020 /* prefer last server */
#define PR_O_DISPATCH 0x00000040 /* use dispatch mode */
#define PR_O_FORCED_ID 0x00000080 /* proxy's ID was forced in the configuration */
-#define PR_O_HTTP_XFF 0x00000100 /* conditionally insert x-forwarded-for with client address */
+/* unused: 0x00000100 */
#define PR_O_IGNORE_PRB 0x00000200 /* ignore empty requests (aborts and timeouts) */
#define PR_O_NULLNOLOG 0x00000400 /* a connect without request will not be logged */
#define PR_O_WREQ_BODY 0x00000800 /* always wait for the HTTP request body */
@@ -101,7 +101,7 @@
#define PR_O_TCP_CLI_KA 0x00040000 /* enable TCP keep-alive on client-side streams */
#define PR_O_TCP_SRV_KA 0x00080000 /* enable TCP keep-alive on server-side streams */
#define PR_O_USE_ALL_BK 0x00100000 /* load-balance between backup servers */
-#define PR_O_HTTP_7239 0x00200000 /* insert 7239 forwarded header */
+/* unused: 0x00200000 */
#define PR_O_TCP_NOLING 0x00400000 /* disable lingering on client and server connections */
#define PR_O_ABRT_CLOSE 0x00800000 /* immediately abort request when client closes */
@@ -115,7 +115,7 @@
#define PR_O_CONTSTATS 0x10000000 /* continuous counters */
/* unused: 0x20000000 */
#define PR_O_DISABLE404 0x40000000 /* Disable a server on a 404 response to a health-check */
-#define PR_O_HTTP_XOT 0x80000000 /* insert x-original-to with destination address */
+/* unused: 0x80000000 */
/* bits for proxy->options2 */
#define PR_O2_SPLIC_REQ 0x00000001 /* transfer requests using linux kernel's splice() */
@@ -267,16 +267,6 @@
char buf[VAR_ARRAY]; /* copy of the beginning of the message for bufsize bytes */
};
-/* http options */
-struct proxy_http {
- /* forwarded header (RFC 7239) */
- struct http_ext_7239 fwd;
- /* x-forward-for */
- struct http_ext_xff xff;
- /* x-original-to */
- struct http_ext_xot xot;
-};
-
struct proxy {
enum obj_type obj_type; /* object type == OBJ_TYPE_PROXY */
char flags; /* bit field PR_FL_* */
@@ -448,7 +438,7 @@
char *elfs_file;
int elfs_line;
} conf; /* config information */
- struct proxy_http http; /* http only options */
+ struct http_ext *http_ext; /* http ext options */
struct eb_root used_server_addr; /* list of server addresses in use */
void *parent; /* parent of the proxy when applicable */
struct comp *comp; /* http compression */
diff --git a/src/cfgparse-listen.c b/src/cfgparse-listen.c
index 20965c8..485b0b3 100644
--- a/src/cfgparse-listen.c
+++ b/src/cfgparse-listen.c
@@ -2038,7 +2038,8 @@
goto out;
}
else if (kwm == KWM_NO) {
- curproxy->options &= ~PR_O_HTTP_7239;
+ if (curproxy->http_ext)
+ http_ext_7239_clean(curproxy);
goto out;
}
}
diff --git a/src/cfgparse.c b/src/cfgparse.c
index ecb75a7..c207c6e 100644
--- a/src/cfgparse.c
+++ b/src/cfgparse.c
@@ -3670,8 +3670,9 @@
else
curproxy->http_needed |= !!(curproxy->lbprm.expr->fetch->use & SMP_USE_HTTP_ANY);
}
+
/* option "forwarded" may need to compile its expressions */
- if ((curproxy->mode == PR_MODE_HTTP) && curproxy->options & PR_O_HTTP_7239)
+ if ((curproxy->mode == PR_MODE_HTTP) && curproxy->http_ext && curproxy->http_ext->fwd)
cfgerr += proxy_http_compile_7239(curproxy);
/* only now we can check if some args remain unresolved.
@@ -3968,25 +3969,26 @@
err_code |= ERR_WARN;
}
- if (curproxy->options & PR_O_HTTP_7239) {
- ha_warning("'option %s' ignored for %s '%s' as it requires HTTP mode.\n",
- "forwarded", proxy_type_str(curproxy), curproxy->id);
- err_code |= ERR_WARN;
- curproxy->options &= ~PR_O_HTTP_7239;
- }
-
- if (curproxy->options & PR_O_HTTP_XFF) {
- ha_warning("'option %s' ignored for %s '%s' as it requires HTTP mode.\n",
- "forwardfor", proxy_type_str(curproxy), curproxy->id);
- err_code |= ERR_WARN;
- curproxy->options &= ~PR_O_HTTP_XFF;
- }
-
- if (curproxy->options & PR_O_HTTP_XOT) {
- ha_warning("'option %s' ignored for %s '%s' as it requires HTTP mode.\n",
- "originalto", proxy_type_str(curproxy), curproxy->id);
- err_code |= ERR_WARN;
- curproxy->options &= ~PR_O_HTTP_XOT;
+ if (curproxy->http_ext) {
+ /* consistency checks for http_ext */
+ if (curproxy->http_ext->fwd) {
+ ha_warning("'option %s' ignored for %s '%s' as it requires HTTP mode.\n",
+ "forwarded", proxy_type_str(curproxy), curproxy->id);
+ err_code |= ERR_WARN;
+ http_ext_7239_clean(curproxy);
+ }
+ if (curproxy->http_ext->xff) {
+ ha_warning("'option %s' ignored for %s '%s' as it requires HTTP mode.\n",
+ "forwardfor", proxy_type_str(curproxy), curproxy->id);
+ err_code |= ERR_WARN;
+ http_ext_xff_clean(curproxy);
+ }
+ if (curproxy->http_ext->xot) {
+ ha_warning("'option %s' ignored for %s '%s' as it requires HTTP mode.\n",
+ "originalto", proxy_type_str(curproxy), curproxy->id);
+ err_code |= ERR_WARN;
+ http_ext_xot_clean(curproxy);
+ }
}
for (optnum = 0; cfg_opts[optnum].name; optnum++) {
@@ -4221,6 +4223,8 @@
rules->flags = 0;
}
}
+ /* http_ext post init early cleanup */
+ http_ext_softclean(curproxy);
}
/*
diff --git a/src/http_ana.c b/src/http_ana.c
index fe5044e..4f1decd 100644
--- a/src/http_ana.c
+++ b/src/http_ana.c
@@ -662,29 +662,13 @@
goto return_fail_rewrite;
}
- /* add forwarded header (RFC 7239) (ignored for frontends) */
- if (s->be->options & PR_O_HTTP_7239) {
- if (unlikely(!http_handle_7239_header(s, req)))
- goto return_fail_rewrite;
- }
-
- /*
- * add X-Forwarded-For if either the frontend or the backend
- * asks for it.
- */
- if ((sess->fe->options | s->be->options) & PR_O_HTTP_XFF) {
- if (unlikely(!http_handle_xff_header(s, req)))
- goto return_fail_rewrite;
- }
-
- /*
- * add X-Original-To if either the frontend or the backend
- * asks for it.
- */
- if ((sess->fe->options | s->be->options) & PR_O_HTTP_XOT) {
- if (unlikely(!http_handle_xot_header(s, req)))
- goto return_fail_rewrite;
- }
+ /* handle http extensions (if configured) */
+ if (unlikely(!http_handle_7239_header(s, req)))
+ goto return_fail_rewrite;
+ if (unlikely(!http_handle_xff_header(s, req)))
+ goto return_fail_rewrite;
+ if (unlikely(!http_handle_xot_header(s, req)))
+ goto return_fail_rewrite;
/* Filter the request headers if there are filters attached to the
* stream.
diff --git a/src/http_ext.c b/src/http_ext.c
index f2e3781..0dcafc5 100644
--- a/src/http_ext.c
+++ b/src/http_ext.c
@@ -611,7 +611,7 @@
if (forby->np_mode)
chunk_appendf(out, "\"");
offset_save = out->data;
- http_build_7239_header_node(out, s, curproxy, addr, &curproxy->http.fwd.p_by);
+ http_build_7239_header_nodename(out, s, curproxy, addr, forby);
if (offset_save == out->data) {
/* could not build nodename, either because some
* data is not available or user is providing bad input
@@ -621,7 +621,7 @@
if (forby->np_mode) {
chunk_appendf(out, ":");
offset_save = out->data;
- http_build_7239_header_nodeport(out, s, curproxy, addr, &curproxy->http.fwd.p_by);
+ http_build_7239_header_nodeport(out, s, curproxy, addr, forby);
if (offset_save == out->data) {
/* could not build nodeport, either because some data is
* not available or user is providing bad input
@@ -682,31 +682,30 @@
{
struct connection *cli_conn = objt_conn(strm_sess(s)->origin);
- if (curproxy->http.fwd.p_proto) {
+ if (curproxy->http_ext->fwd->p_proto) {
chunk_appendf(out, "%sproto=%s", ((out->data) ? ";" : ""),
((conn_is_ssl(cli_conn)) ? "https" : "http"));
}
- if (curproxy->http.fwd.p_host.mode) {
+ if (curproxy->http_ext->fwd->p_host.mode) {
/* always add quotes for host parameter to make output compliancy checks simpler */
chunk_appendf(out, "%shost=\"", ((out->data) ? ";" : ""));
/* ignore return value for now, but could be useful some day */
- http_build_7239_header_host(out, s, curproxy, htx,
- &curproxy->http.fwd.p_host);
+ http_build_7239_header_host(out, s, curproxy, htx, &curproxy->http_ext->fwd->p_host);
chunk_appendf(out, "\"");
}
- if (curproxy->http.fwd.p_by.nn_mode) {
+ if (curproxy->http_ext->fwd->p_by.nn_mode) {
const struct sockaddr_storage *dst = sc_dst(s->scf);
chunk_appendf(out, "%sby=", ((out->data) ? ";" : ""));
- http_build_7239_header_node(out, s, curproxy, dst, &curproxy->http.fwd.p_by);
+ http_build_7239_header_node(out, s, curproxy, dst, &curproxy->http_ext->fwd->p_by);
}
- if (curproxy->http.fwd.p_for.nn_mode) {
+ if (curproxy->http_ext->fwd->p_for.nn_mode) {
const struct sockaddr_storage *src = sc_src(s->scf);
chunk_appendf(out, "%sfor=", ((out->data) ? ";" : ""));
- http_build_7239_header_node(out, s, curproxy, src, &curproxy->http.fwd.p_for);
+ http_build_7239_header_node(out, s, curproxy, src, &curproxy->http_ext->fwd->p_for);
}
if (unlikely(out->data == out->size)) {
/* not enough space in buffer, error */
@@ -715,177 +714,196 @@
return 1;
}
-/* This function will try to inject 7239 forwarded header
+/* This function will try to inject RFC 7239 forwarded header if
+ * configured on the backend (ignored for frontends).
+ * Will do nothing if the option is not enabled on the proxy.
* Returns 1 for success and 0 for failure
*/
int http_handle_7239_header(struct stream *s, struct channel *req)
{
- struct htx *htx = htxbuf(&req->buf);
struct proxy *curproxy = s->be; /* ignore frontend */
- int validate = 1;
- struct http_hdr_ctx find = { .blk = NULL };
- struct http_hdr_ctx last = { .blk = NULL};
- struct ist hdr = ist("forwarded");
- BUG_ON(!(curproxy->options & PR_O_HTTP_7239)); /* should not happen */
+ if (curproxy->http_ext && curproxy->http_ext->fwd) {
+ struct htx *htx = htxbuf(&req->buf);
+ int validate = 1;
+ struct http_hdr_ctx find = { .blk = NULL };
+ struct http_hdr_ctx last = { .blk = NULL};
+ struct ist hdr = ist("forwarded");
- /* ok, let's build forwarded header */
- chunk_reset(&trash);
- if (unlikely(!http_build_7239_header(&trash, s, curproxy, htx)))
- return 0; /* error when building header (bad user conf or memory error) */
+ /* ok, let's build forwarded header */
+ chunk_reset(&trash);
+ if (unlikely(!http_build_7239_header(&trash, s, curproxy, htx)))
+ return 0; /* error when building header (bad user conf or memory error) */
- /* validate existing forwarded header (including multiple values),
- * hard stop if error is encountered
- */
- while (http_find_header(htx, hdr, &find, 0)) {
- /* validate current header chunk */
- if (!http_validate_7239_header(find.value, FORWARDED_HEADER_ALL, NULL)) {
- /* at least one error, existing forwarded header not OK, add our own
- * forwarded header, so that it can be trusted
- */
- validate = 0;
- break;
+ /* validate existing forwarded header (including multiple values),
+ * hard stop if error is encountered
+ */
+ while (http_find_header(htx, hdr, &find, 0)) {
+ /* validate current header chunk */
+ if (!http_validate_7239_header(find.value, FORWARDED_HEADER_ALL, NULL)) {
+ /* at least one error, existing forwarded header not OK, add our own
+ * forwarded header, so that it can be trusted
+ */
+ validate = 0;
+ break;
+ }
+ last = find;
}
- last = find;
- }
- /* no errors, append our data at the end of existing header */
- if (last.blk && validate) {
- if (unlikely(!http_append_header_value(htx, &last, ist2(trash.area, trash.data))))
- return 0; /* htx error */
- }
- else {
- if (unlikely(!http_add_header(htx, hdr, ist2(trash.area, trash.data))))
- return 0; /* htx error */
+ /* no errors, append our data at the end of existing header */
+ if (last.blk && validate) {
+ if (unlikely(!http_append_header_value(htx, &last, ist2(trash.area, trash.data))))
+ return 0; /* htx error */
+ }
+ else {
+ if (unlikely(!http_add_header(htx, hdr, ist2(trash.area, trash.data))))
+ return 0; /* htx error */
+ }
}
return 1;
}
-/* This function will try to inject x-forwarded-for header if
- * configured on the frontend or the backend (or both)
+/*
+ * add X-Forwarded-For if either the frontend or the backend
+ * asks for it.
* Returns 1 for success and 0 for failure
*/
int http_handle_xff_header(struct stream *s, struct channel *req)
{
struct session *sess = s->sess;
- struct htx *htx = htxbuf(&req->buf);
- const struct sockaddr_storage *src = sc_src(s->scf);
- struct http_hdr_ctx ctx = { .blk = NULL };
- struct http_ext_xff *f_xff = ((sess->fe->options & PR_O_HTTP_XFF) ? &sess->fe->http.xff : NULL);
- struct http_ext_xff *b_xff = ((s->be->options & PR_O_HTTP_XFF) ? &s->be->http.xff : NULL);
- struct ist hdr;
-
- /* xff is expected to be enabled on be, or fe, or both */
- BUG_ON(!f_xff && !b_xff);
+ struct http_ext_xff *f_xff = NULL;
+ struct http_ext_xff *b_xff = NULL;
- hdr = ((b_xff) ? b_xff->hdr_name : f_xff->hdr_name);
-
- if (f_xff && f_xff->mode == HTTP_XFF_IFNONE &&
- b_xff && b_xff->mode == HTTP_XFF_IFNONE &&
- http_find_header(htx, hdr, &ctx, 0)) {
- /* The header is set to be added only if none is present
- * and we found it, so don't do anything.
- */
+ if (sess->fe->http_ext && sess->fe->http_ext->xff) {
+ /* frontend */
+ f_xff = sess->fe->http_ext->xff;
}
- else if (src && src->ss_family == AF_INET) {
- /* Add an X-Forwarded-For header unless the source IP is
- * in the 'except' network range.
- */
- if ((!f_xff || ipcmp2net(src, &f_xff->except_net)) &&
- (!b_xff || ipcmp2net(src, &b_xff->except_net))) {
- unsigned char *pn = (unsigned char *)&((struct sockaddr_in *)src)->sin_addr;
+ if (s->be->http_ext && s->be->http_ext->xff) {
+ /* backend */
+ b_xff = s->be->http_ext->xff;
+ }
+
+ if (f_xff || b_xff) {
+ struct htx *htx = htxbuf(&req->buf);
+ const struct sockaddr_storage *src = sc_src(s->scf);
+ struct http_hdr_ctx ctx = { .blk = NULL };
+ struct ist hdr = ((b_xff) ? b_xff->hdr_name : f_xff->hdr_name);
- /* Note: we rely on the backend to get the header name to be used for
- * x-forwarded-for, because the header is really meant for the backends.
- * However, if the backend did not specify any option, we have to rely
- * on the frontend's header name.
+ if (f_xff && f_xff->mode == HTTP_XFF_IFNONE &&
+ b_xff && b_xff->mode == HTTP_XFF_IFNONE &&
+ http_find_header(htx, hdr, &ctx, 0)) {
+ /* The header is set to be added only if none is present
+ * and we found it, so don't do anything.
*/
- chunk_printf(&trash, "%d.%d.%d.%d", pn[0], pn[1], pn[2], pn[3]);
- if (unlikely(!http_add_header(htx, hdr, ist2(trash.area, trash.data))))
- return 0;
}
- }
- else if (src && src->ss_family == AF_INET6) {
- /* Add an X-Forwarded-For header unless the source IP is
- * in the 'except' network range.
- */
- if ((!f_xff || ipcmp2net(src, &f_xff->except_net)) &&
- (!b_xff || ipcmp2net(src, &b_xff->except_net))) {
- char pn[INET6_ADDRSTRLEN];
-
- inet_ntop(AF_INET6,
- (const void *)&((struct sockaddr_in6 *)(src))->sin6_addr,
- pn, sizeof(pn));
+ else if (src && src->ss_family == AF_INET) {
+ /* Add an X-Forwarded-For header unless the source IP is
+ * in the 'except' network range.
+ */
+ if ((!f_xff || ipcmp2net(src, &f_xff->except_net)) &&
+ (!b_xff || ipcmp2net(src, &b_xff->except_net))) {
+ unsigned char *pn = (unsigned char *)&((struct sockaddr_in *)src)->sin_addr;
- /* Note: we rely on the backend to get the header name to be used for
- * x-forwarded-for, because the header is really meant for the backends.
- * However, if the backend did not specify any option, we have to rely
- * on the frontend's header name.
+ /* Note: we rely on the backend to get the header name to be used for
+ * x-forwarded-for, because the header is really meant for the backends.
+ * However, if the backend did not specify any option, we have to rely
+ * on the frontend's header name.
+ */
+ chunk_printf(&trash, "%d.%d.%d.%d", pn[0], pn[1], pn[2], pn[3]);
+ if (unlikely(!http_add_header(htx, hdr, ist2(trash.area, trash.data))))
+ return 0;
+ }
+ }
+ else if (src && src->ss_family == AF_INET6) {
+ /* Add an X-Forwarded-For header unless the source IP is
+ * in the 'except' network range.
*/
- chunk_printf(&trash, "%s", pn);
- if (unlikely(!http_add_header(htx, hdr, ist2(trash.area, trash.data))))
- return 0;
+ if ((!f_xff || ipcmp2net(src, &f_xff->except_net)) &&
+ (!b_xff || ipcmp2net(src, &b_xff->except_net))) {
+ char pn[INET6_ADDRSTRLEN];
+
+ inet_ntop(AF_INET6,
+ (const void *)&((struct sockaddr_in6 *)(src))->sin6_addr,
+ pn, sizeof(pn));
+
+ /* Note: we rely on the backend to get the header name to be used for
+ * x-forwarded-for, because the header is really meant for the backends.
+ * However, if the backend did not specify any option, we have to rely
+ * on the frontend's header name.
+ */
+ chunk_printf(&trash, "%s", pn);
+ if (unlikely(!http_add_header(htx, hdr, ist2(trash.area, trash.data))))
+ return 0;
+ }
}
}
-
return 1;
}
-/* This function will try to inject x-original-to header if
- * configured on the frontend or the backend (or both)
+/*
+ * add X-Original-To if either the frontend or the backend
+ * asks for it.
* Returns 1 for success and 0 for failure
*/
int http_handle_xot_header(struct stream *s, struct channel *req)
{
struct session *sess = s->sess;
- struct htx *htx = htxbuf(&req->buf);
- const struct sockaddr_storage *dst = sc_dst(s->scf);
- struct http_ext_xot *f_xot = ((sess->fe->options & PR_O_HTTP_XOT) ? &sess->fe->http.xot : NULL);
- struct http_ext_xot *b_xot = ((s->be->options & PR_O_HTTP_XOT) ? &s->be->http.xot : NULL);
- struct ist hdr;
-
- /* xot is expected to be enabled on be, or fe, or both */
- BUG_ON(!f_xot && !b_xot);
+ struct http_ext_xot *f_xot = NULL;
+ struct http_ext_xot *b_xot = NULL;
- hdr = ((b_xot) ? b_xot->hdr_name : f_xot->hdr_name);
+ if (sess->fe->http_ext && sess->fe->http_ext->xot) {
+ /* frontend */
+ f_xot = sess->fe->http_ext->xot;
+ }
+ if (s->be->http_ext && s->be->http_ext->xot) {
+ /* backend */
+ BUG_ON(!s->be->http_ext);
+ b_xot = s->be->http_ext->xot;
+ }
- if (dst && dst->ss_family == AF_INET) {
- /* Add an X-Original-To header unless the destination IP is
- * in the 'except' network range.
- */
- if ((!f_xot || ipcmp2net(dst, &f_xot->except_net)) &&
- (!b_xot || ipcmp2net(dst, &b_xot->except_net))) {
- unsigned char *pn = (unsigned char *)&((struct sockaddr_in *)dst)->sin_addr;
+ if (f_xot || b_xot) {
+ struct htx *htx = htxbuf(&req->buf);
+ const struct sockaddr_storage *dst = sc_dst(s->scf);
+ struct ist hdr = ((b_xot) ? b_xot->hdr_name : f_xot->hdr_name);
- /* Note: we rely on the backend to get the header name to be used for
- * x-original-to, because the header is really meant for the backends.
- * However, if the backend did not specify any option, we have to rely
- * on the frontend's header name.
+ if (dst && dst->ss_family == AF_INET) {
+ /* Add an X-Original-To header unless the destination IP is
+ * in the 'except' network range.
*/
- chunk_printf(&trash, "%d.%d.%d.%d", pn[0], pn[1], pn[2], pn[3]);
- if (unlikely(!http_add_header(htx, hdr, ist2(trash.area, trash.data))))
- return 0;
+ if ((!f_xot || ipcmp2net(dst, &f_xot->except_net)) &&
+ (!b_xot || ipcmp2net(dst, &b_xot->except_net))) {
+ unsigned char *pn = (unsigned char *)&((struct sockaddr_in *)dst)->sin_addr;
+
+ /* Note: we rely on the backend to get the header name to be used for
+ * x-original-to, because the header is really meant for the backends.
+ * However, if the backend did not specify any option, we have to rely
+ * on the frontend's header name.
+ */
+ chunk_printf(&trash, "%d.%d.%d.%d", pn[0], pn[1], pn[2], pn[3]);
+ if (unlikely(!http_add_header(htx, hdr, ist2(trash.area, trash.data))))
+ return 0;
+ }
}
- }
- else if (dst && dst->ss_family == AF_INET6) {
- /* Add an X-Original-To header unless the source IP is
- * in the 'except' network range.
- */
- if ((!f_xot || ipcmp2net(dst, &f_xot->except_net)) &&
- (!b_xot || ipcmp2net(dst, &b_xot->except_net))) {
- char pn[INET6_ADDRSTRLEN];
+ else if (dst && dst->ss_family == AF_INET6) {
+ /* Add an X-Original-To header unless the source IP is
+ * in the 'except' network range.
+ */
+ if ((!f_xot || ipcmp2net(dst, &f_xot->except_net)) &&
+ (!b_xot || ipcmp2net(dst, &b_xot->except_net))) {
+ char pn[INET6_ADDRSTRLEN];
- inet_ntop(AF_INET6,
- (const void *)&((struct sockaddr_in6 *)dst)->sin6_addr,
- pn, sizeof(pn));
+ inet_ntop(AF_INET6,
+ (const void *)&((struct sockaddr_in6 *)dst)->sin6_addr,
+ pn, sizeof(pn));
- /* Note: we rely on the backend to get the header name to be used for
- * x-forwarded-for, because the header is really meant for the backends.
- * However, if the backend did not specify any option, we have to rely
- * on the frontend's header name.
- */
- chunk_printf(&trash, "%s", pn);
- if (unlikely(!http_add_header(htx, hdr, ist2(trash.area, trash.data))))
- return 0;
+ /* Note: we rely on the backend to get the header name to be used for
+ * x-forwarded-for, because the header is really meant for the backends.
+ * However, if the backend did not specify any option, we have to rely
+ * on the frontend's header name.
+ */
+ chunk_printf(&trash, "%s", pn);
+ if (unlikely(!http_add_header(htx, hdr, ist2(trash.area, trash.data))))
+ return 0;
+ }
}
}
return 1;
@@ -930,6 +948,7 @@
struct proxy *curproxy, const struct proxy *defpx,
const char *file, int linenum)
{
+ struct http_ext_7239 *fwd;
int err_code = 0;
if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, "option forwarded", NULL)) {
@@ -938,73 +957,77 @@
goto out;
}
+ if (!http_ext_7239_prepare(curproxy))
+ return proxy_http_parse_oom(file, linenum);
+
+ fwd = curproxy->http_ext->fwd;
+
- curproxy->options |= PR_O_HTTP_7239;
- curproxy->http.fwd.p_proto = 0;
- curproxy->http.fwd.p_host.mode = 0;
- curproxy->http.fwd.p_for.nn_mode = 0;
- curproxy->http.fwd.p_for.np_mode = 0;
- curproxy->http.fwd.p_by.nn_mode = 0;
- curproxy->http.fwd.p_by.np_mode = 0;
- ha_free(&curproxy->http.fwd.c_file);
- curproxy->http.fwd.c_file = strdup(file);
- curproxy->http.fwd.c_line = linenum;
+ fwd->p_proto = 0;
+ fwd->p_host.mode = 0;
+ fwd->p_for.nn_mode = 0;
+ fwd->p_for.np_mode = 0;
+ fwd->p_by.nn_mode = 0;
+ fwd->p_by.np_mode = 0;
+ ha_free(&fwd->c_file);
+ fwd->c_file = strdup(file);
+ fwd->c_line = linenum;
/* start at 2, since 0+1 = "option" "forwarded" */
cur_arg = 2;
if (!*(args[cur_arg])) {
/* no optional argument provided, use default settings */
- curproxy->http.fwd.p_for.nn_mode = HTTP_7239_FORBY_ORIG; /* enable for and mimic xff */
- curproxy->http.fwd.p_proto = 1; /* enable proto */
+ fwd->p_for.nn_mode = HTTP_7239_FORBY_ORIG; /* enable for and mimic xff */
+ fwd->p_proto = 1; /* enable proto */
goto out;
}
/* loop to go through optional arguments */
while (*(args[cur_arg])) {
if (strcmp(args[cur_arg], "proto") == 0) {
- curproxy->http.fwd.p_proto = 1;
+ fwd->p_proto = 1;
cur_arg += 1;
} else if (strcmp(args[cur_arg], "host") == 0) {
- curproxy->http.fwd.p_host.mode = HTTP_7239_HOST_ORIG;
+ fwd->p_host.mode = HTTP_7239_HOST_ORIG;
cur_arg += 1;
} else if (strcmp(args[cur_arg], "host-expr") == 0) {
- curproxy->http.fwd.p_host.mode = HTTP_7239_HOST_SMP;
+ fwd->p_host.mode = HTTP_7239_HOST_SMP;
err_code |= _proxy_http_parse_7239_expr(args, &cur_arg, file, linenum,
- &curproxy->http.fwd.p_host.expr_s);
+ &fwd->p_host.expr_s);
if (err_code & ERR_FATAL)
goto out;
} else if (strcmp(args[cur_arg], "by") == 0) {
- curproxy->http.fwd.p_by.nn_mode = HTTP_7239_FORBY_ORIG;
+ fwd->p_by.nn_mode = HTTP_7239_FORBY_ORIG;
cur_arg += 1;
} else if (strcmp(args[cur_arg], "by-expr") == 0) {
- curproxy->http.fwd.p_by.nn_mode = HTTP_7239_FORBY_SMP;
+ fwd->p_by.nn_mode = HTTP_7239_FORBY_SMP;
err_code |= _proxy_http_parse_7239_expr(args, &cur_arg, file, linenum,
- &curproxy->http.fwd.p_by.nn_expr_s);
+ &fwd->p_by.nn_expr_s);
if (err_code & ERR_FATAL)
goto out;
} else if (strcmp(args[cur_arg], "for") == 0) {
- curproxy->http.fwd.p_for.nn_mode = HTTP_7239_FORBY_ORIG;
+ fwd->p_for.nn_mode = HTTP_7239_FORBY_ORIG;
cur_arg += 1;
} else if (strcmp(args[cur_arg], "for-expr") == 0) {
- curproxy->http.fwd.p_for.nn_mode = HTTP_7239_FORBY_SMP;
+ fwd->p_for.nn_mode = HTTP_7239_FORBY_SMP;
err_code |= _proxy_http_parse_7239_expr(args, &cur_arg, file, linenum,
- &curproxy->http.fwd.p_for.nn_expr_s);
+ &fwd->p_for.nn_expr_s);
if (err_code & ERR_FATAL)
goto out;
} else if (strcmp(args[cur_arg], "by_port") == 0) {
- curproxy->http.fwd.p_by.np_mode = HTTP_7239_FORBY_ORIG;
+ fwd->p_by.np_mode = HTTP_7239_FORBY_ORIG;
cur_arg += 1;
} else if (strcmp(args[cur_arg], "by_port-expr") == 0) {
- curproxy->http.fwd.p_by.np_mode = HTTP_7239_FORBY_SMP;
+ fwd->p_by.np_mode = HTTP_7239_FORBY_SMP;
err_code |= _proxy_http_parse_7239_expr(args, &cur_arg, file, linenum,
- &curproxy->http.fwd.p_by.np_expr_s);
+ &fwd->p_by.np_expr_s);
if (err_code & ERR_FATAL)
goto out;
} else if (strcmp(args[cur_arg], "for_port") == 0) {
- curproxy->http.fwd.p_for.np_mode = HTTP_7239_FORBY_ORIG;
+ fwd->p_for.np_mode = HTTP_7239_FORBY_ORIG;
cur_arg += 1;
} else if (strcmp(args[cur_arg], "for_port-expr") == 0) {
- curproxy->http.fwd.p_for.np_mode = HTTP_7239_FORBY_SMP;
+ fwd->p_for.np_mode = HTTP_7239_FORBY_SMP;
err_code |= _proxy_http_parse_7239_expr(args, &cur_arg, file, linenum,
- &curproxy->http.fwd.p_for.np_expr_s);
+ &fwd->p_for.np_expr_s);
if (err_code & ERR_FATAL)
goto out;
} else {
@@ -1019,24 +1042,24 @@
} /* end while loop */
/* consistency check */
- if (curproxy->http.fwd.p_by.np_mode &&
- !curproxy->http.fwd.p_by.nn_mode) {
- curproxy->http.fwd.p_by.np_mode = 0;
- ha_free(&curproxy->http.fwd.p_by.np_expr_s);
+ if (fwd->p_by.np_mode &&
+ !fwd->p_by.nn_mode) {
+ fwd->p_by.np_mode = 0;
+ ha_free(&fwd->p_by.np_expr_s);
ha_warning("parsing [%s:%d] : '%s %s' : '%s' will be ignored because both 'by' "
"and 'by-expr' are unset\n",
file, linenum, args[0], args[1],
- ((curproxy->http.fwd.p_by.np_mode == HTTP_7239_FORBY_ORIG) ? "by_port" : "by_port-expr"));
+ ((fwd->p_by.np_mode == HTTP_7239_FORBY_ORIG) ? "by_port" : "by_port-expr"));
err_code |= ERR_WARN;
}
- if (curproxy->http.fwd.p_for.np_mode &&
- !curproxy->http.fwd.p_for.nn_mode) {
- curproxy->http.fwd.p_for.np_mode = 0;
- ha_free(&curproxy->http.fwd.p_for.np_expr_s);
+ if (fwd->p_for.np_mode &&
+ !fwd->p_for.nn_mode) {
+ fwd->p_for.np_mode = 0;
+ ha_free(&fwd->p_for.np_expr_s);
ha_warning("parsing [%s:%d] : '%s %s' : '%s' will be ignored because both 'for' "
"and 'for-expr' are unset\n",
file, linenum, args[0], args[1],
- ((curproxy->http.fwd.p_for.np_mode == HTTP_7239_FORBY_ORIG) ? "for_port" : "for_port-expr"));
+ ((fwd->p_for.np_mode == HTTP_7239_FORBY_ORIG) ? "for_port" : "for_port-expr"));
err_code |= ERR_WARN;
}
@@ -1049,21 +1072,22 @@
*/
int proxy_http_compile_7239(struct proxy *curproxy)
{
+ struct http_ext_7239 *fwd;
int cfgerr = 0;
int loop;
- BUG_ON(!(curproxy->options & PR_O_HTTP_7239)); /* should not happen */
if (!(curproxy->cap & PR_CAP_BE)) {
- /* no backend cap: not supported (ie: frontend)
- * Moreover, 7239 settings are only inherited from default
- * if proxy is backend capable.. going further would result in
- * undefined behavior */
+ /* no backend cap: not supported (ie: frontend) */
goto out;
}
+ /* should not happen (test should be performed after BE cap test) */
+ BUG_ON(!curproxy->http_ext || !curproxy->http_ext->fwd);
+
curproxy->conf.args.ctx = ARGC_OPT; /* option */
- curproxy->conf.args.file = curproxy->http.fwd.c_file;
- curproxy->conf.args.line = curproxy->http.fwd.c_line;
+ curproxy->conf.args.file = curproxy->http_ext->fwd->c_file;
+ curproxy->conf.args.line = curproxy->http_ext->fwd->c_line;
+ fwd = curproxy->http_ext->fwd;
/* it is important that we keep iterating on error to make sure
* all fwd config fields are in the same state (post-parsing state)
@@ -1079,38 +1103,33 @@
switch (loop) {
case 0:
/* host */
- expr_str = &curproxy->http.fwd.p_host.expr_s;
- expr = &curproxy->http.fwd.p_host.expr;
- smp = (curproxy->http.fwd.p_host.mode ==
- HTTP_7239_HOST_SMP);
+ expr_str = &fwd->p_host.expr_s;
+ expr = &fwd->p_host.expr;
+ smp = (fwd->p_host.mode == HTTP_7239_HOST_SMP);
break;
case 1:
/* by->node */
- expr_str = &curproxy->http.fwd.p_by.nn_expr_s;
- expr = &curproxy->http.fwd.p_by.nn_expr;
- smp = (curproxy->http.fwd.p_by.nn_mode ==
- HTTP_7239_FORBY_SMP);
+ expr_str = &fwd->p_by.nn_expr_s;
+ expr = &fwd->p_by.nn_expr;
+ smp = (fwd->p_by.nn_mode == HTTP_7239_FORBY_SMP);
break;
case 2:
/* by->nodeport */
- expr_str = &curproxy->http.fwd.p_by.np_expr_s;
- expr = &curproxy->http.fwd.p_by.np_expr;
- smp = (curproxy->http.fwd.p_by.np_mode ==
- HTTP_7239_FORBY_SMP);
+ expr_str = &fwd->p_by.np_expr_s;
+ expr = &fwd->p_by.np_expr;
+ smp = (fwd->p_by.np_mode == HTTP_7239_FORBY_SMP);
break;
case 3:
/* for->node */
- expr_str = &curproxy->http.fwd.p_for.nn_expr_s;
- expr = &curproxy->http.fwd.p_for.nn_expr;
- smp = (curproxy->http.fwd.p_for.nn_mode ==
- HTTP_7239_FORBY_SMP);
+ expr_str = &fwd->p_for.nn_expr_s;
+ expr = &fwd->p_for.nn_expr;
+ smp = (fwd->p_for.nn_mode == HTTP_7239_FORBY_SMP);
break;
case 4:
/* for->nodeport */
- expr_str = &curproxy->http.fwd.p_for.np_expr_s;
- expr = &curproxy->http.fwd.p_for.np_expr;
- smp = (curproxy->http.fwd.p_for.np_mode ==
- HTTP_7239_FORBY_SMP);
+ expr_str = &fwd->p_for.np_expr_s;
+ expr = &fwd->p_for.np_expr;
+ smp = (fwd->p_for.np_mode == HTTP_7239_FORBY_SMP);
break;
}
if (!smp)
@@ -1123,7 +1142,7 @@
/* should not happen unless system memory exhaustion */
ha_alert("%s '%s' [%s:%d]: failed to parse 'option forwarded' expression : %s.\n",
proxy_type_str(curproxy), curproxy->id,
- curproxy->http.fwd.c_file, curproxy->http.fwd.c_line,
+ fwd->c_file, fwd->c_line,
"memory error");
cfgerr++;
continue;
@@ -1131,14 +1150,14 @@
cur_expr =
sample_parse_expr((char*[]){*expr_str, NULL}, &idx,
- curproxy->http.fwd.c_file,
- curproxy->http.fwd.c_line,
+ fwd->c_file,
+ fwd->c_line,
&err, &curproxy->conf.args, NULL);
if (!cur_expr) {
ha_alert("%s '%s' [%s:%d]: failed to parse 'option forwarded' expression '%s' in : %s.\n",
proxy_type_str(curproxy), curproxy->id,
- curproxy->http.fwd.c_file, curproxy->http.fwd.c_line,
+ fwd->c_file, fwd->c_line,
*expr_str, err);
ha_free(&err);
cfgerr++;
@@ -1153,7 +1172,7 @@
"some args extract information from '%s', "
"none of which is available here.\n",
proxy_type_str(curproxy), curproxy->id,
- curproxy->http.fwd.c_file, curproxy->http.fwd.c_line,
+ fwd->c_file, fwd->c_line,
*expr_str, sample_ckp_names(cur_expr->fetch->use));
}
/* post parsing individual expr cleanup */
@@ -1166,10 +1185,10 @@
curproxy->conf.args.line = 0;
/* post parsing general cleanup */
- ha_free(&curproxy->http.fwd.c_file);
- curproxy->http.fwd.c_line = 0;
+ ha_free(&fwd->c_file);
+ fwd->c_line = 0;
- curproxy->http.fwd.c_mode = 1; /* parsing completed */
+ fwd->c_mode = 1; /* parsing completed */
out:
return cfgerr;
@@ -1180,21 +1199,25 @@
struct proxy *curproxy, const struct proxy *defpx,
const char *file, int linenum)
{
+ struct http_ext_xff *xff;
int err_code = 0;
+ if (!http_ext_xff_prepare(curproxy))
+ return proxy_http_parse_oom(file, linenum);
+
+ xff = curproxy->http_ext->xff;
+
/* insert x-forwarded-for field, but not for the IP address listed as an except.
* set default options (ie: bitfield, header name, etc)
*/
- curproxy->options |= PR_O_HTTP_XFF;
+ xff->mode = HTTP_XFF_ALWAYS;
- curproxy->http.xff.mode = HTTP_XFF_ALWAYS;
-
- istfree(&curproxy->http.xff.hdr_name);
- curproxy->http.xff.hdr_name = istdup(ist(DEF_XFORWARDFOR_HDR));
- if (!isttest(curproxy->http.xff.hdr_name))
+ istfree(&xff->hdr_name);
+ xff->hdr_name = istdup(ist(DEF_XFORWARDFOR_HDR));
+ if (!isttest(xff->hdr_name))
return proxy_http_parse_oom(file, linenum);
- curproxy->http.xff.except_net.family = AF_UNSPEC;
+ xff->except_net.family = AF_UNSPEC;
/* loop to go through arguments - start at 2, since 0+1 = "option" "forwardfor" */
cur_arg = 2;
@@ -1205,16 +1228,16 @@
/* suboption except - needs additional argument for it */
if (*(args[cur_arg+1]) &&
- str2net(args[cur_arg+1], 1, &curproxy->http.xff.except_net.addr.v4.ip, &curproxy->http.xff.except_net.addr.v4.mask)) {
- curproxy->http.xff.except_net.family = AF_INET;
- curproxy->http.xff.except_net.addr.v4.ip.s_addr &= curproxy->http.xff.except_net.addr.v4.mask.s_addr;
+ str2net(args[cur_arg+1], 1, &xff->except_net.addr.v4.ip, &xff->except_net.addr.v4.mask)) {
+ xff->except_net.family = AF_INET;
+ xff->except_net.addr.v4.ip.s_addr &= xff->except_net.addr.v4.mask.s_addr;
}
else if (*(args[cur_arg+1]) &&
- str62net(args[cur_arg+1], &curproxy->http.xff.except_net.addr.v6.ip, &mask)) {
- curproxy->http.xff.except_net.family = AF_INET6;
- len2mask6(mask, &curproxy->http.xff.except_net.addr.v6.mask);
+ str62net(args[cur_arg+1], &xff->except_net.addr.v6.ip, &mask)) {
+ xff->except_net.family = AF_INET6;
+ len2mask6(mask, &xff->except_net.addr.v6.mask);
for (i = 0; i < 16; i++)
- curproxy->http.xff.except_net.addr.v6.ip.s6_addr[i] &= curproxy->http.xff.except_net.addr.v6.mask.s6_addr[i];
+ xff->except_net.addr.v6.ip.s6_addr[i] &= xff->except_net.addr.v6.mask.s6_addr[i];
}
else {
ha_alert("parsing [%s:%d] : '%s %s %s' expects <address>[/mask] as argument.\n",
@@ -1232,13 +1255,13 @@
err_code |= ERR_ALERT | ERR_FATAL;
goto out;
}
- istfree(&curproxy->http.xff.hdr_name);
- curproxy->http.xff.hdr_name = istdup(ist(args[cur_arg+1]));
- if (!isttest(curproxy->http.xff.hdr_name))
+ istfree(&xff->hdr_name);
+ xff->hdr_name = istdup(ist(args[cur_arg+1]));
+ if (!isttest(xff->hdr_name))
return proxy_http_parse_oom(file, linenum);
cur_arg += 2;
} else if (strcmp(args[cur_arg], "if-none") == 0) {
- curproxy->http.xff.mode = HTTP_XFF_IFNONE;
+ xff->mode = HTTP_XFF_IFNONE;
cur_arg += 1;
} else {
/* unknown suboption - catchall */
@@ -1257,19 +1280,23 @@
struct proxy *curproxy, const struct proxy *defpx,
const char *file, int linenum)
{
+ struct http_ext_xot *xot;
int err_code = 0;
+ if (!http_ext_xot_prepare(curproxy))
+ return proxy_http_parse_oom(file, linenum);
+
+ xot = curproxy->http_ext->xot;
+
/* insert x-original-to field, but not for the IP address listed as an except.
* set default options (ie: bitfield, header name, etc)
*/
- curproxy->options |= PR_O_HTTP_XOT;
-
- istfree(&curproxy->http.xot.hdr_name);
- curproxy->http.xot.hdr_name = istdup(ist(DEF_XORIGINALTO_HDR));
- if (!isttest(curproxy->http.xot.hdr_name))
+ istfree(&xot->hdr_name);
+ xot->hdr_name = istdup(ist(DEF_XORIGINALTO_HDR));
+ if (!isttest(xot->hdr_name))
return proxy_http_parse_oom(file, linenum);
- curproxy->http.xot.except_net.family = AF_UNSPEC;
+ xot->except_net.family = AF_UNSPEC;
/* loop to go through arguments - start at 2, since 0+1 = "option" "originalto" */
cur_arg = 2;
@@ -1280,16 +1307,16 @@
/* suboption except - needs additional argument for it */
if (*(args[cur_arg+1]) &&
- str2net(args[cur_arg+1], 1, &curproxy->http.xot.except_net.addr.v4.ip, &curproxy->http.xot.except_net.addr.v4.mask)) {
- curproxy->http.xot.except_net.family = AF_INET;
- curproxy->http.xot.except_net.addr.v4.ip.s_addr &= curproxy->http.xot.except_net.addr.v4.mask.s_addr;
+ str2net(args[cur_arg+1], 1, &xot->except_net.addr.v4.ip, &xot->except_net.addr.v4.mask)) {
+ xot->except_net.family = AF_INET;
+ xot->except_net.addr.v4.ip.s_addr &= xot->except_net.addr.v4.mask.s_addr;
}
else if (*(args[cur_arg+1]) &&
- str62net(args[cur_arg+1], &curproxy->http.xot.except_net.addr.v6.ip, &mask)) {
- curproxy->http.xot.except_net.family = AF_INET6;
- len2mask6(mask, &curproxy->http.xot.except_net.addr.v6.mask);
+ str62net(args[cur_arg+1], &xot->except_net.addr.v6.ip, &mask)) {
+ xot->except_net.family = AF_INET6;
+ len2mask6(mask, &xot->except_net.addr.v6.mask);
for (i = 0; i < 16; i++)
- curproxy->http.xot.except_net.addr.v6.ip.s6_addr[i] &= curproxy->http.xot.except_net.addr.v6.mask.s6_addr[i];
+ xot->except_net.addr.v6.ip.s6_addr[i] &= xot->except_net.addr.v6.mask.s6_addr[i];
}
else {
ha_alert("parsing [%s:%d] : '%s %s %s' expects <address>[/mask] as argument.\n",
@@ -1306,9 +1333,9 @@
err_code |= ERR_ALERT | ERR_FATAL;
goto out;
}
- istfree(&curproxy->http.xot.hdr_name);
- curproxy->http.xot.hdr_name = istdup(ist(args[cur_arg+1]));
- if (!isttest(curproxy->http.xot.hdr_name))
+ istfree(&xot->hdr_name);
+ xot->hdr_name = istdup(ist(args[cur_arg+1]));
+ if (!isttest(xot->hdr_name))
return proxy_http_parse_oom(file, linenum);
cur_arg += 2;
} else {
@@ -1328,9 +1355,106 @@
* =========== MGMT ===========
* below are helpers to manage http ext options
*/
+
+/* Ensure http_ext->fwd is properly allocated and
+ * initialized for <curproxy>.
+ * The function will leverage http_ext_prepare() to make
+ * sure http_ext is properly allocated and initialized as well.
+ * Returns 1 for success and 0 for failure (memory error)
+ */
+int http_ext_7239_prepare(struct proxy *curproxy)
+{
+ struct http_ext_7239 *fwd;
+
+ if (!http_ext_prepare(curproxy))
+ return 0;
+ if (curproxy->http_ext->fwd)
+ return 1; /* nothing to do */
+
+ fwd = malloc(sizeof(*fwd));
+ if (!fwd)
+ return 0;
+ /* initialize fwd mandatory fields */
+ fwd->c_mode = 0; /* pre-compile (parse) time */
+ fwd->c_file = NULL;
+ fwd->p_host.expr_s = NULL;
+ fwd->p_by.nn_expr_s = NULL;
+ fwd->p_by.np_expr_s = NULL;
+ fwd->p_for.nn_expr_s = NULL;
+ fwd->p_for.np_expr_s = NULL;
+ /* assign */
+ curproxy->http_ext->fwd = fwd;
+ return 1;
+}
+
+/* Ensure http_ext->xff is properly allocated and
+ * initialized for <curproxy>.
+ * The function will leverage http_ext_prepare() to make
+ * sure http_ext is properly allocated and initialized as well.
+ * Returns 1 for success and 0 for failure (memory error)
+ */
+int http_ext_xff_prepare(struct proxy *curproxy)
+{
+ struct http_ext_xff *xff;
+
+ if (!http_ext_prepare(curproxy))
+ return 0;
+ if (curproxy->http_ext->xff)
+ return 1; /* nothing to do */
+
+ xff = malloc(sizeof(*xff));
+ if (!xff)
+ return 0;
+ /* initialize xff mandatory fields */
+ xff->hdr_name = IST_NULL;
+ /* assign */
+ curproxy->http_ext->xff = xff;
+ return 1;
+}
+
+/* Ensure http_ext->xot is properly allocated and
+ * initialized for <curproxy>.
+ * The function will leverage http_ext_prepare() to make
+ * sure http_ext is properly allocated and initialized as well.
+ * Returns 1 for success and 0 for failure (memory error)
+ */
+int http_ext_xot_prepare(struct proxy *curproxy)
+{
+ struct http_ext_xot *xot;
-void http_ext_7239_clean(struct http_ext_7239 *clean)
+ if (!http_ext_prepare(curproxy))
+ return 0;
+ if (curproxy->http_ext->xot)
+ return 1; /* nothing to do */
+
+ xot = malloc(sizeof(*xot));
+ if (!xot)
+ return 0;
+ /* initialize xot mandatory fields */
+ xot->hdr_name = IST_NULL;
+ /* assign */
+ curproxy->http_ext->xot = xot;
+ return 1;
+}
+
+/* deep clean http_ext->fwd parameter for <curproxy>
+ * http_ext->fwd will be freed
+ * clean behavior will differ depending on http_ext->fwd
+ * state. If fwd is in 'parsed' state, parsing hints will be
+ * cleaned. Else, it means fwd is in 'compiled' state, in this
+ * case we're cleaning compiled results.
+ * This is because parse and compile memory areas are shared in
+ * a single union to optimize struct http_ext_7239 size.
+ */
+void http_ext_7239_clean(struct proxy *curproxy)
{
+ struct http_ext_7239 *clean;
+
+ if (!curproxy->http_ext)
+ return;
+ clean = curproxy->http_ext->fwd;
+ if (!clean)
+ return; /* nothing to do */
if (!clean->c_mode) {
/* parsed */
ha_free(&clean->c_file);
@@ -1353,22 +1477,69 @@
release_sample_expr(clean->p_for.np_expr);
clean->p_for.np_expr = NULL;
}
+ /* free fwd */
+ ha_free(&curproxy->http_ext->fwd);
}
-void http_ext_xff_clean(struct http_ext_xff *clean)
+/* deep clean http_ext->xff parameter for <curproxy>
+ * http_ext->xff will be freed
+ */
+void http_ext_xff_clean(struct proxy *curproxy)
{
+ struct http_ext_xff *clean;
+
+ if (!curproxy->http_ext)
+ return;
+ clean = curproxy->http_ext->xff;
+ if (!clean)
+ return; /* nothing to do */
istfree(&clean->hdr_name);
+ /* free xff */
+ ha_free(&curproxy->http_ext->xff);
}
-void http_ext_xot_clean(struct http_ext_xot *clean)
+/* deep clean http_ext->xot parameter for <curproxy>
+ * http_ext->xot will be freed
+ */
+void http_ext_xot_clean(struct proxy *curproxy)
{
+ struct http_ext_xot *clean;
+
+ if (!curproxy->http_ext)
+ return;
+ clean = curproxy->http_ext->xot;
+ if (!clean)
+ return; /* nothing to do */
istfree(&clean->hdr_name);
+ /* free xot */
+ ha_free(&curproxy->http_ext->xot);
}
-void http_ext_7239_copy(struct http_ext_7239 *dest, const struct http_ext_7239 *orig)
+/* duplicate http_ext->fwd parameters from <def> to <cpy>
+ * performs the required memory allocation and initialization
+ */
+void http_ext_7239_dup(const struct proxy *def, struct proxy *cpy)
{
+ struct http_ext_7239 *dest = NULL;
+ struct http_ext_7239 *orig = NULL;
+
+ /* feature requires backend cap */
+ if (!(cpy->cap & PR_CAP_BE))
+ return;
+
+ if (def->http_ext == NULL || def->http_ext->fwd == NULL)
+ return;
+
+ orig = def->http_ext->fwd;
+
if (orig->c_mode)
return; /* copy not supported once compiled */
+
+ if (!http_ext_7239_prepare(cpy))
+ return;
+
+ dest = cpy->http_ext->fwd;
+
if (orig->c_file)
dest->c_file = strdup(orig->c_file);
dest->c_line = orig->c_line;
@@ -1396,21 +1567,104 @@
dest->p_for.np_expr_s = strdup(orig->p_for.np_expr_s);
}
-void http_ext_xff_copy(struct http_ext_xff *dest, const struct http_ext_xff *orig)
+/* duplicate http_ext->xff parameters from <def> to <cpy>
+ * performs the required memory allocation and initialization
+ */
+void http_ext_xff_dup(const struct proxy *def, struct proxy *cpy)
{
+ struct http_ext_xff *dest = NULL;
+ struct http_ext_xff *orig = NULL;
+
+ if (def->http_ext == NULL || def->http_ext->xff == NULL ||
+ !http_ext_xff_prepare(cpy))
+ return;
+
+ orig = def->http_ext->xff;
+ dest = cpy->http_ext->xff;
+
if (isttest(orig->hdr_name))
dest->hdr_name = istdup(orig->hdr_name);
dest->mode = orig->mode;
dest->except_net = orig->except_net;
}
-void http_ext_xot_copy(struct http_ext_xot *dest, const struct http_ext_xot *orig)
+/* duplicate http_ext->xot parameters from <def> to <cpy>
+ * performs the required memory allocation and initialization
+ */
+void http_ext_xot_dup(const struct proxy *def, struct proxy *cpy)
{
+ struct http_ext_xot *dest = NULL;
+ struct http_ext_xot *orig = NULL;
+
+ if (def->http_ext == NULL || def->http_ext->xot == NULL ||
+ !http_ext_xot_prepare(cpy))
+ return;
+
+ orig = def->http_ext->xot;
+ dest = cpy->http_ext->xot;
+
if (isttest(orig->hdr_name))
dest->hdr_name = istdup(orig->hdr_name);
dest->except_net = orig->except_net;
}
+/* Allocate new http_ext and initialize it
+ * if needed
+ * Returns 1 for success and 0 for failure
+ */
+int http_ext_prepare(struct proxy *curproxy)
+{
+ if (curproxy->http_ext)
+ return 1; /* nothing to do */
+
+ curproxy->http_ext = malloc(sizeof(*curproxy->http_ext));
+ if (!curproxy->http_ext)
+ return 0; /* failure */
+ /* first init, set supported ext to NULL */
+ curproxy->http_ext->fwd = NULL;
+ curproxy->http_ext->xff = NULL;
+ curproxy->http_ext->xot = NULL;
+ return 1;
+}
+
+/* duplicate existing http_ext from <defproxy> to <curproxy>
+ */
+void http_ext_dup(const struct proxy *defproxy, struct proxy *curproxy)
+{
+ /* copy defproxy.http_ext members */
+ http_ext_7239_dup(defproxy, curproxy);
+ http_ext_xff_dup(defproxy, curproxy);
+ http_ext_xot_dup(defproxy, curproxy);
+}
+
+/* deep clean http_ext for <curproxy> (if previously allocated)
+ */
+void http_ext_clean(struct proxy *curproxy)
+{
+ if (!curproxy->http_ext)
+ return; /* nothing to do */
+ /* first, free supported ext */
+ http_ext_7239_clean(curproxy);
+ http_ext_xff_clean(curproxy);
+ http_ext_xot_clean(curproxy);
+
+ /* then, free http_ext */
+ ha_free(&curproxy->http_ext);
+}
+
+/* soft clean (only clean http_ext if no more options are used) */
+void http_ext_softclean(struct proxy *curproxy)
+{
+ if (!curproxy->http_ext)
+ return; /* nothing to do */
+ if (!curproxy->http_ext->fwd &&
+ !curproxy->http_ext->xff &&
+ !curproxy->http_ext->xot) {
+ /* no more use for http_ext, all options are disabled */
+ http_ext_clean(curproxy);
+ }
+}
+
/*
* =========== CONV ===========
* related converters
diff --git a/src/proxy.c b/src/proxy.c
index efb8ddb..43a35f5 100644
--- a/src/proxy.c
+++ b/src/proxy.c
@@ -352,9 +352,8 @@
pxdf->fct(p);
free(p->desc);
- http_ext_7239_clean(&p->http.fwd);
- http_ext_xff_clean(&p->http.xff);
- http_ext_xot_clean(&p->http.xot);
+
+ http_ext_clean(p);
task_destroy(p->task);
@@ -1467,9 +1466,7 @@
ha_free(&defproxy->conn_src.iface_name);
istfree(&defproxy->server_id_hdr_name);
- http_ext_7239_clean(&defproxy->http.fwd);
- http_ext_xff_clean(&defproxy->http.xff);
- http_ext_xot_clean(&defproxy->http.xot);
+ http_ext_clean(defproxy);
list_for_each_entry_safe(acl, aclb, &defproxy->acl, list) {
LIST_DELETE(&acl->list);
@@ -1650,10 +1647,8 @@
curproxy->tcp_req.inspect_delay = defproxy->tcp_req.inspect_delay;
curproxy->tcp_rep.inspect_delay = defproxy->tcp_rep.inspect_delay;
- if (defproxy->options & PR_O_HTTP_XFF)
- http_ext_xff_copy(&curproxy->http.xff, &defproxy->http.xff);
- if (defproxy->options & PR_O_HTTP_XOT)
- http_ext_xot_copy(&curproxy->http.xot, &defproxy->http.xot);
+ http_ext_clean(curproxy);
+ http_ext_dup(defproxy, curproxy);
if (isttest(defproxy->server_id_hdr_name))
curproxy->server_id_hdr_name = istdup(defproxy->server_id_hdr_name);
@@ -1697,8 +1692,6 @@
}
curproxy->ck_opts = defproxy->ck_opts;
- if (defproxy->options & PR_O_HTTP_7239)
- http_ext_7239_copy(&curproxy->http.fwd, &defproxy->http.fwd);
if (defproxy->cookie_name)
curproxy->cookie_name = strdup(defproxy->cookie_name);