]> granicus.if.org Git - libevent/commitdiff
http: add EVHTTP_URI_HOST_STRIP_BRACKETS
authorAzat Khuzhin <azat@libevent.org>
Mon, 26 Oct 2020 22:40:34 +0000 (01:40 +0300)
committerAzat Khuzhin <azat@libevent.org>
Mon, 26 Oct 2020 23:13:21 +0000 (02:13 +0300)
Refs: #1115

http-internal.h
http.c
include/event2/http.h
test/regress_http.c

index 94059065c3d0f913482c4d589306c395f80ae9b3..2d0ae8fc69a5a09d7ee4c197ec476eab706b5c45 100644 (file)
@@ -215,6 +215,9 @@ void evhttp_start_write_(struct evhttp_connection *);
 void evhttp_response_code_(struct evhttp_request *, int, const char *);
 void evhttp_send_page_(struct evhttp_request *, struct evbuffer *);
 
+/* [] has been stripped */
+#define _EVHTTP_URI_HOST_HAS_BRACKETS 0x02
+
 EVENT2_EXPORT_SYMBOL
 int evhttp_decode_uri_internal(const char *uri, size_t length,
     char *ret, int decode_plus);
diff --git a/http.c b/http.c
index 8afb3600fa59d702f81c7e80d7a0ba84c9171fa9..45441f22b8f4cb0a824e76101d623e4bfe0bb93e 100644 (file)
--- a/http.c
+++ b/http.c
@@ -180,7 +180,7 @@ extern int debug;
 static evutil_socket_t create_bind_socket_nonblock(struct evutil_addrinfo *, int reuse);
 static evutil_socket_t bind_socket(const char *, ev_uint16_t, int reuse);
 static void name_from_addr(struct sockaddr *, ev_socklen_t, char **, char **);
-static struct evhttp_uri *evhttp_uri_parse_authority(char *source_uri);
+static struct evhttp_uri *evhttp_uri_parse_authority(char *source_uri, unsigned flags);
 static int evhttp_associate_new_request_with_connection(
        struct evhttp_connection *evcon);
 static void evhttp_connection_start_detectclose(
@@ -2055,7 +2055,7 @@ evhttp_parse_request_line(struct evhttp_request *req, char *line, size_t len)
        }
 
        if (type == EVHTTP_REQ_CONNECT) {
-               if ((req->uri_elems = evhttp_uri_parse_authority(req->uri)) == NULL) {
+               if ((req->uri_elems = evhttp_uri_parse_authority(req->uri, 0)) == NULL) {
                        return -1;
                }
        } else {
@@ -4910,9 +4910,11 @@ bracket_addr_ok(const char *s, const char *eos)
 }
 
 static int
-parse_authority(struct evhttp_uri *uri, char *s, char *eos)
+parse_authority(struct evhttp_uri *uri, char *s, char *eos, unsigned *flags)
 {
+       size_t len;
        char *cp, *port;
+
        EVUTIL_ASSERT(eos);
        if (eos == s) {
                uri->host = mm_strdup("");
@@ -4952,22 +4954,31 @@ parse_authority(struct evhttp_uri *uri, char *s, char *eos)
        /* Now, cp..eos holds the "host" port, which can be an IPv4Address,
         * an IP-Literal, or a reg-name */
        EVUTIL_ASSERT(eos >= cp);
+       len = eos-cp;
        if (*cp == '[' && eos >= cp+2 && *(eos-1) == ']') {
                /* IPv6address, IP-Literal, or junk. */
                if (! bracket_addr_ok(cp, eos))
                        return -1;
+               if (*flags & EVHTTP_URI_HOST_STRIP_BRACKETS)
+                       len = eos-cp-2;
        } else {
                /* Make sure the host part is ok. */
                if (! regname_ok(cp,eos)) /* Match IPv4Address or reg-name */
                        return -1;
        }
-       uri->host = mm_malloc(eos-cp+1);
+
+       uri->host = mm_malloc(len+1);
        if (uri->host == NULL) {
                event_warn("%s: malloc", __func__);
                return -1;
        }
-       memcpy(uri->host, cp, eos-cp);
-       uri->host[eos-cp] = '\0';
+       if (*cp == '[' && *flags & EVHTTP_URI_HOST_STRIP_BRACKETS) {
+               memcpy(uri->host, cp+1, len);
+               *flags |= _EVHTTP_URI_HOST_HAS_BRACKETS;
+       } else {
+               memcpy(uri->host, cp, len);
+       }
+       uri->host[len] = '\0';
        return 0;
 
 }
@@ -5103,7 +5114,7 @@ evhttp_uri_parse_with_flags(const char *source_uri, unsigned flags)
                readp += 2;
                authority = readp;
                path = end_of_authority(readp);
-               if (parse_authority(uri, authority, path) < 0)
+               if (parse_authority(uri, authority, path, &uri->flags) < 0)
                        goto err;
                readp = path;
                got_authority = 1;
@@ -5182,7 +5193,7 @@ err:
 }
 
 static struct evhttp_uri *
-evhttp_uri_parse_authority(char *source_uri)
+evhttp_uri_parse_authority(char *source_uri, unsigned flags)
 {
        struct evhttp_uri *uri = mm_calloc(1, sizeof(struct evhttp_uri));
        char *end;
@@ -5192,10 +5203,10 @@ evhttp_uri_parse_authority(char *source_uri)
                goto err;
        }
        uri->port = -1;
-       uri->flags = 0;
+       uri->flags = flags;
 
        end = end_of_authority(source_uri);
-       if (parse_authority(uri, source_uri, end) < 0)
+       if (parse_authority(uri, source_uri, end, &uri->flags) < 0)
                goto err;
 
        uri->path = mm_strdup("");
@@ -5254,7 +5265,13 @@ evhttp_uri_join(struct evhttp_uri *uri, char *buf, size_t limit)
                evbuffer_add(tmp, "//", 2);
                if (uri->userinfo)
                        evbuffer_add_printf(tmp,"%s@", uri->userinfo);
-               URI_ADD_(host);
+               if (uri->flags & _EVHTTP_URI_HOST_HAS_BRACKETS) {
+                       evbuffer_add(tmp, "[", 1);
+                       URI_ADD_(host);
+                       evbuffer_add(tmp, "]", 1);
+               } else {
+                       URI_ADD_(host);
+               }
                if (uri->port >= 0)
                        evbuffer_add_printf(tmp,":%d", uri->port);
 
@@ -5284,7 +5301,7 @@ evhttp_uri_join(struct evhttp_uri *uri, char *buf, size_t limit)
                evbuffer_free(tmp);
                return NULL;
        }
-               evbuffer_remove(tmp, buf, joined_size);
+       evbuffer_remove(tmp, buf, joined_size);
 
        output = buf;
 err:
@@ -5363,17 +5380,39 @@ evhttp_uri_set_userinfo(struct evhttp_uri *uri, const char *userinfo)
 int
 evhttp_uri_set_host(struct evhttp_uri *uri, const char *host)
 {
+       size_t len = 0;
+
        if (host) {
+               len = strlen(host);
+
                if (host[0] == '[') {
-                       if (! bracket_addr_ok(host, host+strlen(host)))
+                       if (! bracket_addr_ok(host, host+len))
                                return -1;
                } else {
-                       if (! regname_ok(host, host+strlen(host)))
+                       if (! regname_ok(host, host+len))
                                return -1;
                }
        }
 
-       URI_SET_STR_(host);
+       if (host && host[0] == '[' && uri->flags & EVHTTP_URI_HOST_STRIP_BRACKETS) {
+               char *new_host;
+
+               len -= 2;
+               new_host = mm_realloc(uri->host, len+1);
+               if (!new_host) {
+                       free(uri->host);
+                       uri->host = NULL;
+               } else {
+                       memcpy(new_host, host+1, len);
+                       new_host[len] = '\0';
+                       uri->host = new_host;
+               }
+               uri->flags |= _EVHTTP_URI_HOST_HAS_BRACKETS;
+       } else {
+               URI_SET_STR_(host);
+               uri->flags &= ~_EVHTTP_URI_HOST_HAS_BRACKETS;
+       }
+
        return 0;
 }
 int
index aef8a45b5e7861407f0ddc6e5a215748e839daff..d32bd0b35928b81fa9896c96bfd41c589dfb1d9d 100644 (file)
@@ -1378,6 +1378,15 @@ struct evhttp_uri *evhttp_uri_parse_with_flags(const char *source_uri,
  * </ul>
  */
 #define EVHTTP_URI_NONCONFORMANT 0x01
+/**
+ * Strip brackets from the IPv6 address and only for evhttp_uri_get_host(),
+ * evhttp_uri_join() returns the host with brackets.
+ *
+ * Thus you can use host part of the evhttp_uri for getaddrinfo().
+ *
+ * @see also _EVHTTP_URI_HOST_HAS_BRACKETS
+ */
+#define EVHTTP_URI_HOST_STRIP_BRACKETS 0x04
 
 /** Alias for evhttp_uri_parse_with_flags(source_uri, 0) */
 EVENT2_EXPORT_SYMBOL
index b952ff470dd272893c6513ebc5d7dad4927d2b34..959fcc28440d7f3b8e8af211b7460815e0ff0c1b 100644 (file)
@@ -2835,6 +2835,8 @@ http_parse_uri_test(void *ptr)
            nonconform ? EVHTTP_URI_NONCONFORMANT : 0;
        struct evhttp_uri *uri = NULL;
        char url_tmp[4096];
+#define URI_PARSE_FLAGS(uri, flags) \
+       evhttp_uri_parse_with_flags((uri), flags)
 #define URI_PARSE(uri) \
        evhttp_uri_parse_with_flags((uri), parse_flags)
 
@@ -3205,6 +3207,29 @@ http_parse_uri_test(void *ptr)
        tt_want(strcmp(evhttp_uri_get_fragment(uri), "fr?ed") == 0);
        TT_URI("#fr?ed");
        evhttp_uri_free(uri);
+
+       // EVHTTP_URI_HOST_STRIP_BRACKETS
+       uri = URI_PARSE_FLAGS("ftp://[ff00::127.0.0.1]/?q=test", EVHTTP_URI_HOST_STRIP_BRACKETS);
+       tt_want(strcmp(evhttp_uri_get_scheme(uri), "ftp") == 0);
+       tt_want(strcmp(evhttp_uri_get_host(uri), "ff00::127.0.0.1") == 0);
+       tt_want(strcmp(evhttp_uri_get_path(uri), "/") == 0);
+       tt_want(strcmp(evhttp_uri_get_query(uri), "q=test") == 0);
+       tt_want(evhttp_uri_get_userinfo(uri) == NULL);
+       tt_want(evhttp_uri_get_port(uri) == -1);
+       tt_want(evhttp_uri_get_fragment(uri) == NULL);
+       TT_URI("ftp://[ff00::127.0.0.1]/?q=test");
+
+       tt_want(0 == evhttp_uri_set_host(uri, "foo"));
+       tt_want(strcmp(evhttp_uri_get_host(uri), "foo") == 0);
+       TT_URI("ftp://foo/?q=test");
+
+       tt_want(0 == evhttp_uri_set_host(uri, "[ff00::127.0.0.1]"));
+       tt_want(strcmp(evhttp_uri_get_host(uri), "ff00::127.0.0.1") == 0);
+       TT_URI("ftp://[ff00::127.0.0.1]/?q=test");
+
+       evhttp_uri_free(uri);
+
+#undef URI_PARSE_FLAGS
 #undef URI_PARSE
 #undef TT_URI
 #undef BAD