Index: server/protocol.c =================================================================== --- server/protocol.c (revision 1658974) +++ server/protocol.c (working copy) @@ -985,6 +985,42 @@ AP_DECLARE(void) ap_get_mime_headers(request_rec * apr_brigade_destroy(tmp_bb); } +static char *construct_host_header(request_rec *r) +{ + struct iovec iov[5]; + apr_size_t nvec = 0; + int is_v6literal = 0; + + /* + * We cannot use ap_get_server_name/port here, because we must + * ignore UseCanonicalName/Port. + */ + if (ap_strchr_c(r->hostname, ':')) { + is_v6literal = 1; + iov[nvec].iov_base = "["; + iov[nvec].iov_len = 1; + nvec++; + } + iov[nvec].iov_base = (void *)r->hostname; + iov[nvec].iov_len = strlen(r->hostname); + nvec++; + if (is_v6literal) { + iov[nvec].iov_base = "]"; + iov[nvec].iov_len = 1; + nvec++; + } + if (r->parsed_uri.port_str + && !ap_is_default_port(r->parsed_uri.port, r)) { + iov[nvec].iov_base = ":"; + iov[nvec].iov_len = 1; + nvec++; + iov[nvec].iov_base = r->parsed_uri.port_str; + iov[nvec].iov_len = strlen(r->parsed_uri.port_str); + nvec++; + } + return apr_pstrcatv(r->pool, iov, nvec, NULL); +} + request_rec *ap_read_request(conn_rec *conn) { request_rec *r; @@ -1139,6 +1175,25 @@ request_rec *ap_read_request(conn_rec *conn) */ apr_table_unset(r->headers_in, "Content-Length"); } + + /* + * If we have both hostname from an absoluteURI and a Host header, + * we must ignore the Host header (RFC 7230, Section 5.4). + * To enforce this, we reset the Host header to the value from the + * request line. + */ + if (r->hostname) { + const char *host = apr_table_get(r->headers_in, "Host"); + if (host && strcasecmp(host, r->hostname) != 0) { + char *newhost = construct_host_header(r); + if (strcasecmp(host, newhost) != 0) { + ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(02417) + "Replacing Host header '%s' with host from " + "request uri: '%s'", host, newhost); + apr_table_setn(r->headers_in, "Host", newhost); + } + } + } } else { if (r->header_only) { Index: server/vhost.c =================================================================== --- server/vhost.c (revision 1658974) +++ server/vhost.c (working copy) @@ -811,8 +811,7 @@ bad: * Instead we just check for filesystem metacharacters: directory * separators / and \ and sequences of more than one dot. */ -static int fix_hostname(request_rec *r, const char *host_header, - unsigned http_conformance) +static int fix_hostname(request_rec *r) { const char *src; char *host, *scope_id; @@ -819,15 +818,21 @@ bad: apr_port_t port; apr_status_t rv; const char *c; - int is_v6literal = 0; - int strict = http_conformance & AP_HTTP_CONFORMANCE_STRICT; - int strict_logonly = http_conformance & AP_HTTP_CONFORMANCE_LOGONLY; + int is_v6literal; + core_server_config *conf = + ap_get_core_module_config(r->server->module_config); + int strict = conf->http_conformance & AP_HTTP_CONFORMANCE_STRICT; + int strict_logonly = conf->http_conformance & AP_HTTP_CONFORMANCE_LOGONLY; - src = host_header ? host_header : r->hostname; + /* + * If there was a host part in the Request-URI, ignore the 'Host' + * header. + */ + src = r->hostname ? r->hostname : apr_table_get(r->headers_in, "Host"); /* According to RFC 2616, Host header field CAN be blank */ - if (!*src) { - return is_v6literal; + if (!src || !*src) { + return 0; } /* apr_parse_addr_port will interpret a bare integer as a port @@ -845,10 +850,18 @@ bad: goto bad_nolog; } r->hostname = src; - return is_v6literal; + return 0; } - if (host_header) { + if (r->hostname) { + /* + * Already parsed, surrounding [ ] (if IPv6 literal) and :port have + * already been removed. + */ + host = apr_pstrdup(r->pool, r->hostname); + is_v6literal = (ap_strchr(host, ':') != NULL); + } + else { rv = apr_parse_addr_port(&host, &scope_id, &port, src, r->pool); if (rv != APR_SUCCESS || scope_id) goto bad; @@ -861,18 +874,8 @@ bad: r->parsed_uri.port = port; r->parsed_uri.port_str = apr_itoa(r->pool, (int)port); } - if (host_header[0] == '[') - is_v6literal = 1; + is_v6literal = (src[0] == '['); } - else { - /* - * Already parsed, surrounding [ ] (if IPv6 literal) and :port have - * already been removed. - */ - host = apr_pstrdup(r->pool, r->hostname); - if (ap_strchr(host, ':') != NULL) - is_v6literal = 1; - } if (is_v6literal) { rv = fix_hostname_v6_literal(r, host); @@ -1106,80 +1109,12 @@ static void check_serverpath(request_rec *r) } } -static APR_INLINE const char *construct_host_header(request_rec *r, - int is_v6literal) -{ - struct iovec iov[5]; - apr_size_t nvec = 0; - /* - * We cannot use ap_get_server_name/port here, because we must - * ignore UseCanonicalName/Port. - */ - if (is_v6literal) { - iov[nvec].iov_base = "["; - iov[nvec].iov_len = 1; - nvec++; - } - iov[nvec].iov_base = (void *)r->hostname; - iov[nvec].iov_len = strlen(r->hostname); - nvec++; - if (is_v6literal) { - iov[nvec].iov_base = "]"; - iov[nvec].iov_len = 1; - nvec++; - } - if (r->parsed_uri.port_str) { - iov[nvec].iov_base = ":"; - iov[nvec].iov_len = 1; - nvec++; - iov[nvec].iov_base = r->parsed_uri.port_str; - iov[nvec].iov_len = strlen(r->parsed_uri.port_str); - nvec++; - } - return apr_pstrcatv(r->pool, iov, nvec, NULL); -} - AP_DECLARE(void) ap_update_vhost_from_headers(request_rec *r) { - core_server_config *conf = ap_get_core_module_config(r->server->module_config); - const char *host_header = apr_table_get(r->headers_in, "Host"); - int is_v6literal = 0; - int have_hostname_from_url = 0; - - if (r->hostname) { - /* - * If there was a host part in the Request-URI, ignore the 'Host' - * header. - */ - have_hostname_from_url = 1; - is_v6literal = fix_hostname(r, NULL, conf->http_conformance); - } - else if (host_header != NULL) { - is_v6literal = fix_hostname(r, host_header, conf->http_conformance); - } + fix_hostname(r); if (r->status != HTTP_OK) return; - if (conf->http_conformance & AP_HTTP_CONFORMANCE_STRICT) { - /* - * If we have both hostname from an absoluteURI and a Host header, - * we must ignore the Host header (RFC 2616 5.2). - * To enforce this, we reset the Host header to the value from the - * request line. - */ - if (have_hostname_from_url && host_header != NULL) { - const char *info = "Would replace"; - const char *new = construct_host_header(r, is_v6literal); - if (!(conf->http_conformance & AP_HTTP_CONFORMANCE_LOGONLY)) { - apr_table_set(r->headers_in, "Host", r->hostname); - info = "Replacing"; - } - ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(02417) - "%s Host header '%s' with host from request uri: " - "'%s'", info, host_header, new); - } - } - /* check if we tucked away a name_chain */ if (r->connection->vhost_lookup_data) { if (r->hostname)