changeset 8489:5d2e285677a7 quic

HTTP/3: generate Location response header for absolute redirects.
author Roman Arutyunyan <arut@nginx.com>
date Thu, 23 Jul 2020 12:31:40 +0300
parents 79125ef2e39f
children e24f7b50ba1d
files src/http/v3/ngx_http_v3_request.c
diffstat 1 files changed, 81 insertions(+), 2 deletions(-) [+]
line wrap: on
line diff
--- a/src/http/v3/ngx_http_v3_request.c
+++ b/src/http/v3/ngx_http_v3_request.c
@@ -14,6 +14,7 @@
 #define NGX_HTTP_V3_HEADER_CONTENT_LENGTH_ZERO       4
 #define NGX_HTTP_V3_HEADER_DATE                      6
 #define NGX_HTTP_V3_HEADER_LAST_MODIFIED             10
+#define NGX_HTTP_V3_HEADER_LOCATION                  12
 #define NGX_HTTP_V3_HEADER_STATUS_200                25
 #define NGX_HTTP_V3_HEADER_CONTENT_TYPE_TEXT_PLAIN   53
 #define NGX_HTTP_V3_HEADER_VARY_ACCEPT_ENCODING      59
@@ -426,12 +427,15 @@ ngx_http_v3_create_header(ngx_http_reque
     u_char                    *p;
     size_t                     len, n;
     ngx_buf_t                 *b;
-    ngx_uint_t                 i;
+    ngx_str_t                  host;
+    ngx_uint_t                 i, port;
     ngx_chain_t               *hl, *cl, *bl;
     ngx_list_part_t           *part;
     ngx_table_elt_t           *header;
     ngx_connection_t          *c;
     ngx_http_core_loc_conf_t  *clcf;
+    ngx_http_core_srv_conf_t  *cscf;
+    u_char                     addr[NGX_SOCKADDR_STRLEN];
 
     c = r->connection;
 
@@ -506,7 +510,52 @@ ngx_http_v3_create_header(ngx_http_reque
                                   sizeof("Mon, 28 Sep 1970 06:00:00 GMT") - 1);
     }
 
-    /* XXX location */
+    if (r->headers_out.location
+        && r->headers_out.location->value.len
+        && r->headers_out.location->value.data[0] == '/'
+        && clcf->absolute_redirect)
+    {
+        r->headers_out.location->hash = 0;
+
+        if (clcf->server_name_in_redirect) {
+            cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module);
+            host = cscf->server_name;
+
+        } else if (r->headers_in.server.len) {
+            host = r->headers_in.server;
+
+        } else {
+            host.len = NGX_SOCKADDR_STRLEN;
+            host.data = addr;
+
+            if (ngx_connection_local_sockaddr(c, &host, 0) != NGX_OK) {
+                return NULL;
+            }
+        }
+
+        port = ngx_inet_get_port(c->local_sockaddr);
+
+        n = sizeof("https://") - 1 + host.len
+            + r->headers_out.location->value.len;
+
+        if (clcf->port_in_redirect) {
+            port = (port == 443) ? 0 : port;
+
+        } else {
+            port = 0;
+        }
+
+        if (port) {
+            n += sizeof(":65535") - 1;
+        }
+
+        len += ngx_http_v3_encode_header_lri(NULL, 0,
+                                         NGX_HTTP_V3_HEADER_LOCATION, NULL, n);
+
+    } else {
+        ngx_str_null(&host);
+        port = 0;
+    }
 
 #if (NGX_HTTP_GZIP)
     if (r->gzip_vary) {
@@ -650,6 +699,36 @@ ngx_http_v3_create_header(ngx_http_reque
         b->last = ngx_http_time(b->last, r->headers_out.last_modified_time);
     }
 
+    if (host.data) {
+        n = sizeof("https://") - 1 + host.len
+            + r->headers_out.location->value.len;
+
+        if (port) {
+            n += ngx_sprintf(b->last, ":%ui", port) - b->last;
+        }
+
+        b->last = (u_char *) ngx_http_v3_encode_header_lri(b->last, 0,
+                                                   NGX_HTTP_V3_HEADER_LOCATION,
+                                                   NULL, n);
+
+        p = b->last;
+        b->last = ngx_cpymem(b->last, "https://", sizeof("https://") - 1);
+        b->last = ngx_cpymem(b->last, host.data, host.len);
+
+        if (port) {
+            b->last = ngx_sprintf(b->last, ":%ui", port);
+        }
+
+        b->last = ngx_cpymem(b->last, r->headers_out.location->value.data,
+                             r->headers_out.location->value.len);
+
+        /* update r->headers_out.location->value for possible logging */
+
+        r->headers_out.location->value.len = b->last - p;
+        r->headers_out.location->value.data = p;
+        ngx_str_set(&r->headers_out.location->key, "Location");
+    }
+
 #if (NGX_HTTP_GZIP)
     if (r->gzip_vary) {
         b->last = (u_char *) ngx_http_v3_encode_header_ri(b->last, 0,