commit 3ff82c514becd08922fcf9bc9f4870941650932a
Author:     Laslo Hunhold <[email protected]>
AuthorDate: Tue Apr 3 00:55:52 2018 +0200
Commit:     Laslo Hunhold <[email protected]>
CommitDate: Tue Apr 3 01:03:03 2018 +0200

    Clean up request host properly
    
    We all agree that the IPv6 address format is a big clusterfuck and only
    an insane person would've come up with it given the double colons
    interfere with the way one actually appends a port to a normal IPv4 address.
    
    To counteract in this issue, the RFC specifies that one should enclose
    IPv6-addresses in square brackets to make the disctinction possible,
    i.e.
    
            host: ::1
            port: 80
    
            --> [::1]:80
    
    The host field can contain both a port suffix and, of course by the RFC,
    have the address enclosed in square brackets. Given I personally see
    this as a "transport enclosure" I'd rather like to see it gone as soon
    as possible and thus implement this cleanup in the http-header-parser so
    the output is nice and clean and we don't have to deal with this garbage
    later on.
    
    Thanks to Josuah Demangeon <[email protected]> for his wonderful input and
    his dedication to read the RFCs 3986 and 2732 in such great detail.

diff --git a/http.c b/http.c
index 12ebde8..9296f83 100644
--- a/http.c
+++ b/http.c
@@ -95,6 +95,7 @@ decode(char src[PATH_MAX], char dest[PATH_MAX])
 int
 http_get_request(int fd, struct request *r)
 {
+       struct in6_addr res;
        size_t hlen, i, mlen;
        ssize_t off;
        char h[HEADER_MAX], *p, *q;
@@ -232,6 +233,43 @@ http_get_request(int fd, struct request *r)
                p = q + (sizeof("\r\n") - 1);
        }
 
+       /*
+        * clean up host
+        */
+
+       p = strrchr(r->field[REQ_HOST], ':');
+       q = strrchr(r->field[REQ_HOST], ']');
+
+       /* strip port suffix but don't interfere with IPv6 bracket notation
+        * as per RFC 2732 */
+       if (p && (!q || p > q)) {
+               /* port suffix must not be empty */
+               if (*(p + 1) == '\0') {
+                       return http_send_status(fd, S_BAD_REQUEST);
+               }
+               *p = '\0';
+       }
+
+       /* strip the brackets from the IPv6 notation and validate the address */
+       if (q) {
+               /* brackets must be on the outside */
+               if (r->field[REQ_HOST][0] != '[' || *(q + 1) != '\0') {
+                       return http_send_status(fd, S_BAD_REQUEST);
+               }
+
+               /* remove the right bracket */
+               *q = '\0';
+               p = r->field[REQ_HOST] + 1;
+
+               /* validate the contained IPv6 address */
+               if (inet_pton(AF_INET6, p, &res) != 1) {
+                       return http_send_status(fd, S_BAD_REQUEST);
+               }
+
+               /* copy it into the host field */
+               memmove(r->field[REQ_HOST], p, q - p + 1);
+       }
+
        return 0;
 }
 

Reply via email to