]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MEDIUM: httpclient: allow to use another proxy
authorWilliam Lallemand <wlallemand@haproxy.org>
Mon, 12 Sep 2022 15:39:04 +0000 (17:39 +0200)
committerWilliam Lallemand <wlallemand@haproxy.org>
Tue, 13 Sep 2022 15:12:38 +0000 (17:12 +0200)
httpclient_new_from_proxy() is a variant of httpclient_new() which
allows to create the requests from a different proxy.

The proxy and its 2 servers are now stored in the httpclient structure.

The proxy must have been created with httpclient_create_proxy() to be
used.

The httpclient_postcheck() callback will finish the initialization of
all proxies created with PR_CAP_HTTPCLIENT.

include/haproxy/http_client-t.h
include/haproxy/http_client.h
src/http_client.c

index 6efb671a92265f3b8951a4e2eaf0e20570b27ea9..3d05c0451c4950c622ad45890738e31e7167730f 100644 (file)
@@ -32,6 +32,11 @@ struct httpclient {
        int timeout_server;                   /* server timeout in ms */
        void *caller;                         /* ptr of the caller */
        unsigned int flags;                   /* other flags */
+       struct proxy *px;                     /* proxy for special cases */
+       struct server *srv_raw;               /* server for clear connections */
+#ifdef USE_OPENSSL
+       struct server *srv_ssl;               /* server for SSL connections */
+#endif
 };
 
 /* Action (FA) to do */
index cc4c9fe6259cfb52936bd2605ea1edadbac6d78f..e91d1adb9ede4dbbae7eeb2062118cf1e4052eea 100644 (file)
@@ -6,6 +6,8 @@
 void httpclient_destroy(struct httpclient *hc);
 void httpclient_stop_and_destroy(struct httpclient *hc);
 struct httpclient *httpclient_new(void *caller, enum http_meth_t meth, struct ist url);
+struct httpclient *httpclient_new_from_proxy(struct proxy *px, void *caller, enum http_meth_t meth, struct ist url);
+int httpclient_set_proxy(struct httpclient *hc, struct proxy *px);
 
 struct appctx *httpclient_start(struct httpclient *hc);
 int httpclient_set_dst(struct httpclient *hc, const char *dst);
index 7d04cd4fca3d0d12920c74145d6254ef793c3e97..155045d43ff974c3968d3036cadfe878584ed29d 100644 (file)
@@ -610,6 +610,8 @@ void httpclient_destroy(struct httpclient *hc)
 }
 
 /* Allocate an httpclient and its buffers
+ * Use the default httpclient_proxy
+ *
  * Return NULL on failure */
 struct httpclient *httpclient_new(void *caller, enum http_meth_t meth, struct ist url)
 {
@@ -624,6 +626,7 @@ struct httpclient *httpclient_new(void *caller, enum http_meth_t meth, struct is
        hc->caller = caller;
        hc->req.url = istdup(url);
        hc->req.meth = meth;
+       httpclient_set_proxy(hc, httpclient_proxy);
 
        return hc;
 
@@ -632,6 +635,49 @@ err:
        return NULL;
 }
 
+/* Allocate an httpclient and its buffers,
+ * Use the proxy <px>
+ *
+ * Return and httpclient or NULL.
+ */
+struct httpclient *httpclient_new_from_proxy(struct proxy *px, void *caller, enum http_meth_t meth, struct ist url)
+{
+       struct httpclient *hc;
+
+       hc = httpclient_new(caller, meth, url);
+       if (!hc)
+               return NULL;
+
+       httpclient_set_proxy(hc, px);
+
+       return hc;
+}
+
+/*
+ * Configure an httpclient with a specific proxy <px>
+ *
+ * The proxy <px> must contains 2 srv, one configured for clear connections, the other for SSL.
+ *
+ */
+int httpclient_set_proxy(struct httpclient *hc, struct proxy *px)
+{
+       struct server *srv;
+
+       hc->px = px;
+
+       for (srv = px->srv; srv != NULL; srv = srv->next) {
+               if (srv->xprt == xprt_get(XPRT_RAW)) {
+                       hc->srv_raw = srv;
+#ifdef USE_OPENSSL
+               } else if (srv->xprt == xprt_get(XPRT_SSL)) {
+                       hc->srv_ssl = srv;
+#endif
+               }
+       }
+
+       return 0;
+}
+
 static void httpclient_applet_io_handler(struct appctx *appctx)
 {
        struct httpclient *hc = appctx->svcctx;
@@ -974,12 +1020,12 @@ static int httpclient_applet_init(struct appctx *appctx)
        /* choose the SSL server or not */
        switch (scheme) {
                case SCH_HTTP:
-                       target = &httpclient_srv_raw->obj_type;
+                       target = &hc->srv_raw->obj_type;
                        break;
                case SCH_HTTPS:
 #ifdef USE_OPENSSL
-                       if (httpclient_srv_ssl) {
-                               target = &httpclient_srv_ssl->obj_type;
+                       if (hc->srv_ssl) {
+                               target = &hc->srv_ssl->obj_type;
                        } else {
                                ha_alert("httpclient: SSL was disabled (wrong verify/ca-file)!\n");
                                goto out_free_addr;
@@ -991,7 +1037,7 @@ static int httpclient_applet_init(struct appctx *appctx)
                        break;
        }
 
-       if (appctx_finalize_startup(appctx, httpclient_proxy, &hc->req.buf) == -1) {
+       if (appctx_finalize_startup(appctx, hc->px, &hc->req.buf) == -1) {
                ha_alert("httpclient: Failed to initialize appctx %s:%d.\n", __FUNCTION__, __LINE__);
                goto out_free_addr;
        }
@@ -1301,53 +1347,71 @@ static int httpclient_postcheck()
 {
        int err_code = ERR_NONE;
        struct logsrv *logsrv;
-       struct proxy *curproxy = httpclient_proxy;
+       struct proxy *curproxy = NULL;
        char *errmsg = NULL;
+#ifdef USE_OPENSSL
+       struct server *srv = NULL;
+       struct server *srv_ssl = NULL;
+#endif
 
        if (global.mode & MODE_MWORKER_WAIT)
                return ERR_NONE;
 
-       /* copy logs from "global" log list */
-       list_for_each_entry(logsrv, &global.logsrvs, list) {
-               struct logsrv *node = malloc(sizeof(*node));
+       /* Initialize the logs for every proxy dedicated to the httpclient */
+       for (curproxy = proxies_list; curproxy; curproxy = curproxy->next) {
 
-               if (!node) {
-                       memprintf(&errmsg, "out of memory.");
-                       err_code |= ERR_ALERT | ERR_FATAL;
-                       goto err;
-               }
+               if (!(curproxy->cap & PR_CAP_HTTPCLIENT))
+                       continue;
 
-               memcpy(node, logsrv, sizeof(*node));
-               LIST_INIT(&node->list);
-               LIST_APPEND(&curproxy->logsrvs, &node->list);
-               node->ring_name = logsrv->ring_name ? strdup(logsrv->ring_name) : NULL;
-               node->conf.file = logsrv->conf.file ? strdup(logsrv->conf.file) : NULL;
-       }
-       if (curproxy->conf.logformat_string) {
-               curproxy->conf.args.ctx = ARGC_LOG;
-               if (!parse_logformat_string(curproxy->conf.logformat_string, curproxy, &curproxy->logformat,
-                                           LOG_OPT_MANDATORY|LOG_OPT_MERGE_SPACES,
-                                           SMP_VAL_FE_LOG_END, &errmsg)) {
-                       memprintf(&errmsg, "failed to parse log-format : %s.", errmsg);
-                       err_code |= ERR_ALERT | ERR_FATAL;
-                       goto err;
+               /* copy logs from "global" log list */
+               list_for_each_entry(logsrv, &global.logsrvs, list) {
+                       struct logsrv *node = malloc(sizeof(*node));
+
+                       if (!node) {
+                               memprintf(&errmsg, "out of memory.");
+                               err_code |= ERR_ALERT | ERR_FATAL;
+                               goto err;
+                       }
+
+                       memcpy(node, logsrv, sizeof(*node));
+                       LIST_INIT(&node->list);
+                       LIST_APPEND(&curproxy->logsrvs, &node->list);
+                       node->ring_name = logsrv->ring_name ? strdup(logsrv->ring_name) : NULL;
+                       node->conf.file = logsrv->conf.file ? strdup(logsrv->conf.file) : NULL;
+               }
+               if (curproxy->conf.logformat_string) {
+                       curproxy->conf.args.ctx = ARGC_LOG;
+                       if (!parse_logformat_string(curproxy->conf.logformat_string, curproxy, &curproxy->logformat,
+                                                   LOG_OPT_MANDATORY|LOG_OPT_MERGE_SPACES,
+                                                   SMP_VAL_FE_LOG_END, &errmsg)) {
+                               memprintf(&errmsg, "failed to parse log-format : %s.", errmsg);
+                               err_code |= ERR_ALERT | ERR_FATAL;
+                               goto err;
+                       }
+                       curproxy->conf.args.file = NULL;
+                       curproxy->conf.args.line = 0;
                }
-               curproxy->conf.args.file = NULL;
-               curproxy->conf.args.line = 0;
-       }
 
 #ifdef USE_OPENSSL
-       if (httpclient_srv_ssl) {
-               /* init the SNI expression */
-               /* always use the host header as SNI, without the port */
-               httpclient_srv_ssl->sni_expr = strdup("req.hdr(host),field(1,:)");
-               err_code |= server_parse_sni_expr(httpclient_srv_ssl, httpclient_proxy, &errmsg);
-               if (err_code & ERR_CODE) {
-                       memprintf(&errmsg, "failed to configure sni: %s.", errmsg);
-                       goto err;
+               /* initialize the SNI for the SSL servers */
+
+               for (srv = curproxy->srv; srv != NULL; srv = srv->next) {
+                       if (srv->xprt == xprt_get(XPRT_SSL)) {
+                               srv_ssl = srv;
+                       }
+               }
+               if (srv_ssl) {
+                       /* init the SNI expression */
+                       /* always use the host header as SNI, without the port */
+                       srv_ssl->sni_expr = strdup("req.hdr(host),field(1,:)");
+                       err_code |= server_parse_sni_expr(srv_ssl, curproxy, &errmsg);
+                       if (err_code & ERR_CODE) {
+                               memprintf(&errmsg, "failed to configure sni: %s.", errmsg);
+                               goto err;
+                       }
                }
-       }
 #endif
+       }
 
 err:
        if (err_code & ERR_CODE) {