It is recommended to use a URL in the Location header of 3xx
authorreyk <reyk@openbsd.org>
Fri, 25 Jul 2014 23:23:39 +0000 (23:23 +0000)
committerreyk <reyk@openbsd.org>
Fri, 25 Jul 2014 23:23:39 +0000 (23:23 +0000)
responses.  To accomplish this, add some semantics to retrieve the
server host name of a connection: either IP, IP:PORT (if not 80) or
[IP6]:PORT, or Host value (if valid).

usr.sbin/httpd/http.h
usr.sbin/httpd/httpd.h
usr.sbin/httpd/server.c
usr.sbin/httpd/server_file.c
usr.sbin/httpd/server_http.c

index af2627f..994e98b 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: http.h,v 1.3 2014/07/13 15:11:23 reyk Exp $   */
+/*     $OpenBSD: http.h,v 1.4 2014/07/25 23:23:39 reyk Exp $   */
 
 /*
  * Copyright (c) 2012 - 2014 Reyk Floeter <reyk@openbsd.org>
@@ -19,6 +19,9 @@
 #ifndef _HTTP_H
 #define _HTTP_H
 
+#define HTTP_PORT      80
+#define HTTPS_PORT     443
+
 enum httpmethod {
        HTTP_METHOD_NONE        = 0,
 
@@ -148,13 +151,14 @@ struct http_descriptor {
 #define query_key               http_matchquery.kv_key
 #define query_val               http_matchquery.kv_value
 
-       char                    *http_version;
+       char                     http_host[MAXHOSTNAMELEN];
        enum httpmethod          http_method;
        int                      http_chunked;
+       char                    *http_version;
 
        /* A tree of headers and attached lists for repeated headers. */
-       struct kvtree            http_headers;
        struct kv               *http_lastheader;
+       struct kvtree            http_headers;
 };
 
 #endif /* _HTTP_H */
index f2e3dce..f88a46f 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: httpd.h,v 1.13 2014/07/25 21:29:58 reyk Exp $ */
+/*     $OpenBSD: httpd.h,v 1.14 2014/07/25 23:23:39 reyk Exp $ */
 
 /*
  * Copyright (c) 2006 - 2014 Reyk Floeter <reyk@openbsd.org>
@@ -256,6 +256,7 @@ struct client {
        void                    *clt_srv;
        void                    *clt_srv_conf;
        u_int32_t                clt_srv_id;
+       struct sockaddr_storage  clt_srv_ss;
 
        int                      clt_s;
        in_port_t                clt_port;
@@ -412,6 +413,8 @@ int  server_response_http(struct client *, u_int, struct media_type *,
 void    server_reset_http(struct client *);
 void    server_close_http(struct client *);
 int     server_response(struct httpd *, struct client *);
+const char *
+        server_http_host(struct sockaddr_storage *, char *, size_t);
 
 /* server_file.c */
 int     server_file(struct httpd *, struct client *);
index 21ccff2..18fe06c 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: server.c,v 1.11 2014/07/25 16:23:19 reyk Exp $        */
+/*     $OpenBSD: server.c,v 1.12 2014/07/25 23:23:39 reyk Exp $        */
 
 /*
  * Copyright (c) 2006 - 2014 Reyk Floeter <reyk@openbsd.org>
@@ -503,6 +503,19 @@ server_accept(int fd, short event, void *arg)
        clt->clt_srv_id = srv->srv_conf.id;
        clt->clt_pid = getpid();
        clt->clt_inflight = 1;
+
+       /* get local address */
+       slen = sizeof(clt->clt_srv_ss);
+       if (getsockname(s, (struct sockaddr *)&clt->clt_srv_ss,
+           &slen) == -1) {
+               server_close(clt, "listen address lookup failed");
+               return;
+       }
+
+       /* get client address */
+       memcpy(&clt->clt_ss, &ss, sizeof(clt->clt_ss));
+
+       /* get ports */
        switch (ss.ss_family) {
        case AF_INET:
                clt->clt_port = ((struct sockaddr_in *)&ss)->sin_port;
@@ -511,7 +524,6 @@ server_accept(int fd, short event, void *arg)
                clt->clt_port = ((struct sockaddr_in6 *)&ss)->sin6_port;
                break;
        }
-       memcpy(&clt->clt_ss, &ss, sizeof(clt->clt_ss));
 
        getmonotime(&clt->clt_tv_start);
        memcpy(&clt->clt_tv_last, &clt->clt_tv_start, sizeof(clt->clt_tv_last));
@@ -571,7 +583,8 @@ server_inflight_dec(struct client *clt, const char *why)
 void
 server_close(struct client *clt, const char *msg)
 {
-       char                     ibuf[128], obuf[128], *ptr = NULL;
+       char                     ibuf[MAXHOSTNAMELEN], obuf[MAXHOSTNAMELEN];
+       char                    *ptr = NULL;
        struct server           *srv = clt->clt_srv;
        struct server_config    *srv_conf = clt->clt_srv_conf;
 
@@ -590,14 +603,14 @@ server_close(struct client *clt, const char *msg)
                memset(&ibuf, 0, sizeof(ibuf));
                memset(&obuf, 0, sizeof(obuf));
                (void)print_host(&clt->clt_ss, ibuf, sizeof(ibuf));
-               (void)print_host(&srv_conf->ss, obuf, sizeof(obuf));
+               (void)server_http_host(&clt->clt_srv_ss, obuf, sizeof(obuf));
                if (EVBUFFER_LENGTH(clt->clt_log) &&
                    evbuffer_add_printf(clt->clt_log, "\r\n") != -1)
                        ptr = evbuffer_readline(clt->clt_log);
                log_info("server %s, "
-                   "client %d (%d active), %s -> %s:%d, "
+                   "client %d (%d active), %s:%u -> %s, "
                    "%s%s%s", srv_conf->name, clt->clt_id, server_clients,
-                   ibuf, obuf, ntohs(clt->clt_port), msg,
+                   ibuf, ntohs(clt->clt_port), obuf, msg,
                    ptr == NULL ? "" : ",", ptr == NULL ? "" : ptr);
                if (ptr != NULL)
                        free(ptr);
index 81346ce..8031a8f 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: server_file.c,v 1.15 2014/07/25 21:29:58 reyk Exp $   */
+/*     $OpenBSD: server_file.c,v 1.16 2014/07/25 23:23:39 reyk Exp $   */
 
 /*
  * Copyright (c) 2006 - 2014 Reyk Floeter <reyk@openbsd.org>
@@ -72,7 +72,8 @@ server_file_access(struct http_descriptor *desc, char *path, size_t len,
 
                /* Redirect to path with trailing "/" */
                if (path[strlen(path) - 1] != '/') {
-                       if (asprintf(&newpath, "%s/", desc->http_path) == -1)
+                       if (asprintf(&newpath, "http://%s%s/",
+                           desc->http_host, desc->http_path) == -1)
                                return (500);
                        free(desc->http_path);
                        desc->http_path = newpath;
index 2751ac3..a05f25c 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: server_http.c,v 1.17 2014/07/25 21:48:05 reyk Exp $   */
+/*     $OpenBSD: server_http.c,v 1.18 2014/07/25 23:23:39 reyk Exp $   */
 
 /*
  * Copyright (c) 2006 - 2014 Reyk Floeter <reyk@openbsd.org>
@@ -528,6 +528,38 @@ server_http_date(char *tmbuf, size_t len)
        strftime(tmbuf, len, "%a, %d %h %Y %T %Z", &tm);
 }
 
+const char *
+server_http_host(struct sockaddr_storage *ss, char *buf, size_t len)
+{
+       char            hbuf[MAXHOSTNAMELEN];
+       in_port_t       port;
+
+       if (print_host(ss, buf, len) == NULL)
+               return (NULL);
+
+       port = ntohs(server_socket_getport(ss));
+       if (port == HTTP_PORT)
+               return (buf);
+
+       switch (ss->ss_family) {
+       case AF_INET:
+               if ((size_t)snprintf(hbuf, sizeof(hbuf),
+                   "%s:%u", buf, port) >= sizeof(hbuf))
+                       return (NULL);
+               break;
+       case AF_INET6:
+               if ((size_t)snprintf(hbuf, sizeof(hbuf),
+                   "[%s]:%u", buf, port) >= sizeof(hbuf))
+                       return (NULL);
+               break;
+       }
+
+       if (strlcpy(buf, hbuf, len) >= len)
+               return (NULL);
+
+       return (buf);
+}
+
 void
 server_abort_http(struct client *clt, u_int code, const char *msg)
 {
@@ -636,8 +668,8 @@ server_response(struct httpd *httpd, struct client *clt)
        char                     path[MAXPATHLEN];
        struct http_descriptor  *desc   = clt->clt_desc;
        struct server           *srv = clt->clt_srv;
-       struct server_config    *srv_conf;
-       struct kv               *kv, key;
+       struct server_config    *srv_conf = &srv->srv_conf;
+       struct kv               *kv, key, *host;
        int                      ret;
 
        /* Canonicalize the request path */
@@ -648,10 +680,14 @@ server_response(struct httpd *httpd, struct client *clt)
        if ((desc->http_path = strdup(path)) == NULL)
                goto fail;
 
+       key.kv_key = "Host";
+       if ((host = kv_find(&desc->http_headers, &key)) != NULL &&
+           host->kv_value == NULL)
+               host = NULL;
+
        if (strcmp(desc->http_version, "HTTP/1.1") == 0) {
                /* Host header is mandatory */
-               key.kv_key = "Host";
-               if ((kv = kv_find(&desc->http_headers, &key)) == NULL)
+               if (host == NULL)
                        goto fail;
 
                /* Is the connection persistent? */
@@ -675,19 +711,31 @@ server_response(struct httpd *httpd, struct client *clt)
         * Do we have a Host header and matching configuration?
         * XXX the Host can also appear in the URL path.
         */
-       key.kv_key = "Host";
-       if ((kv = kv_find(&desc->http_headers, &key)) != NULL) {
+       if (host != NULL) {
                /* XXX maybe better to turn srv_hosts into a tree */
                TAILQ_FOREACH(srv_conf, &srv->srv_hosts, entry) {
-                       if (fnmatch(srv_conf->name, kv->kv_value,
+                       if (fnmatch(srv_conf->name, host->kv_value,
                            FNM_CASEFOLD) == 0) {
                                /* Replace host configuration */
                                clt->clt_srv_conf = srv_conf;
+                               srv_conf = NULL;
                                break;
                        }
                }
        }
 
+       if (srv_conf != NULL) {
+               /* Use the actual server IP address */
+               if (server_http_host(&clt->clt_srv_ss, desc->http_host,
+                   sizeof(desc->http_host)) == NULL)
+                       goto fail;
+       } else {
+               /* Host header was valid and found */
+               if (strlcpy(desc->http_host, host->kv_value,
+                   sizeof(desc->http_host)) >= sizeof(desc->http_host))
+                       goto fail;
+       }
+
        if ((ret = server_file(httpd, clt)) == -1)
                return (-1);