]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MEDIUM: httpclient: remove url2sa to use a more flexible parser
authorWilliam Lallemand <wlallemand@haproxy.org>
Thu, 14 Apr 2022 15:50:20 +0000 (17:50 +0200)
committerWilliam Lallemand <wlallemand@haproxy.org>
Wed, 4 May 2022 09:21:01 +0000 (11:21 +0200)
The httpclient DNS resolver will need a more efficient URL parser which
splits the URL into parts and does not try to resolve.

httpclient_spliturl uses the http_uri_parser in order to split the URL
into several ist.

The result of the function host part is then processed into str2ip2(),
and fails if it it not an IP, allowing us to resolve the domain later.

src/http_client.c

index 0d34ca8c6dc6f3aa368c5ea43fecb8b5e36929e1..282963592ca56fd59daf7274c5dedfcb3bccc9a4 100644 (file)
@@ -32,6 +32,7 @@
 #include <haproxy/proxy.h>
 #include <haproxy/server.h>
 #include <haproxy/ssl_sock-t.h>
+#include <haproxy/sock_inet.h>
 #include <haproxy/tools.h>
 
 #include <string.h>
@@ -444,6 +445,54 @@ int httpclient_set_dst(struct httpclient *hc, const char *dst)
        return 0;
 }
 
+/*
+ * Return a splitted URL in <scheme>, <host>, <port>
+ */
+static void httpclient_spliturl(struct ist url, enum http_scheme *scheme,
+                                struct ist *host, int *port)
+{
+       enum http_scheme scheme_tmp = SCH_HTTP;
+       int port_tmp = 0;
+       struct ist scheme_ist, authority_ist, host_ist, port_ist;
+       char *p, *end;
+       struct http_uri_parser parser;
+
+       parser = http_uri_parser_init(url);
+       scheme_ist = http_parse_scheme(&parser);
+
+       if (isteqi(scheme_ist, ist("http://"))){
+               scheme_tmp = SCH_HTTP;
+               port_tmp = 80;
+       } else if (isteqi(scheme_ist, ist("https://"))) {
+               scheme_tmp = SCH_HTTPS;
+               port_tmp = 443;
+       }
+
+       authority_ist = http_parse_authority(&parser, 1);
+       p = end = istend(authority_ist);
+
+       /* look for a port at the end of the authority */
+       while (p > istptr(authority_ist) && isdigit((unsigned char)*--p))
+               ;
+
+       if (*p == ':') {
+               host_ist = ist2(istptr(authority_ist), p - istptr(authority_ist));
+               port_ist = istnext(ist2(p, end - p));
+               ist2str(trash.area, port_ist);
+               port_tmp = atoi(trash.area);
+       } else {
+               host_ist = authority_ist;
+       }
+
+       if (scheme)
+               *scheme = scheme_tmp;
+       if (host)
+               *host = host_ist;
+       if (port)
+               *port = port_tmp;
+
+}
+
 /*
  * Start the HTTP client
  * Create the appctx, session, stream and wakeup the applet
@@ -461,11 +510,12 @@ struct appctx *httpclient_start(struct httpclient *hc)
        struct conn_stream *cs;
        struct stream *s;
        struct sockaddr_storage *addr = NULL;
-       int len;
-       struct sockaddr_storage ss_url;
-       struct sockaddr_storage* ss_dst;
-       struct split_url out;
+       struct sockaddr_storage ss_url = {};
+       struct sockaddr_storage *ss_dst;
        enum obj_type *target = NULL;
+       struct ist host = IST_NULL;
+       enum http_scheme scheme;
+       int port;
 
        /* if the client was started and not ended, an applet is already
         * running, we shouldn't try anything */
@@ -474,12 +524,12 @@ struct appctx *httpclient_start(struct httpclient *hc)
 
        hc->flags = 0;
 
-       /* parse URI and fill sockaddr_storage */
-       len = url2sa(istptr(hc->req.url), istlen(hc->req.url), &ss_url, &out);
-       if (len == -1) {
-               ha_alert("httpclient: cannot parse uri '%s'.\n", istptr(hc->req.url));
-               goto out;
-       }
+       /* parse the URL and  */
+       httpclient_spliturl(hc->req.url, &scheme, &host, &port);
+
+       ist2str(trash.area, host);
+       ss_dst = str2ip2(trash.area, &ss_url, 0);
+       sock_inet_set_port(&ss_url, port);
 
        /* The HTTP client will be created in the same thread as the caller,
         * avoiding threading issues */
@@ -494,7 +544,7 @@ struct appctx *httpclient_start(struct httpclient *hc)
        }
 
        /* choose the SSL server or not */
-       switch (out.scheme) {
+       switch (scheme) {
                case SCH_HTTP:
                        target = &httpclient_srv_raw->obj_type;
                        break;
@@ -516,8 +566,9 @@ struct appctx *httpclient_start(struct httpclient *hc)
        /* if httpclient_set_dst() was used, sets the alternative address */
        if (hc->dst)
                ss_dst = hc->dst;
-       else
-               ss_dst = &ss_url;
+
+       /* TODO: if ss_dst == NULL, must resolve the domain */
+
 
        if (!sockaddr_alloc(&addr, ss_dst, sizeof(*hc->dst)))
                goto out_free_sess;