diff --git a/src/mod_extforward.c b/src/mod_extforward.c index dc0f01ac..74612f5a 100644 --- a/src/mod_extforward.c +++ b/src/mod_extforward.c @@ -958,6 +958,7 @@ static handler_t mod_extforward_Forwarded (request_st * const r, plugin_data * c else { buffer_copy_string_len(r->http_host, s+v, vlen-v); } + buffer_to_lower(r->http_host); if (0 != http_request_host_policy(r->http_host, r->conf.http_parseopts, diff --git a/src/request.c b/src/request.c index 520f2070..523a7f89 100644 --- a/src/request.c +++ b/src/request.c @@ -227,6 +227,9 @@ int http_request_host_normalize(buffer * const b, const int scheme_port) { } int http_request_host_policy (buffer * const b, const unsigned int http_parseopts, const int scheme_port) { + /* caller should lowercase, as is done in http_request_header_set_Host(), + * for consistency in case the value is used prior to calling policy func */ + /*buffer_to_lower(b);*/ return (((http_parseopts & HTTP_PARSEOPT_HOST_STRICT) && 0 != request_check_hostname(b)) || ((http_parseopts & HTTP_PARSEOPT_HOST_NORMALIZE) @@ -262,6 +265,16 @@ static int http_request_header_char_invalid(request_st * const restrict r, const } +__attribute_noinline__ +static void http_request_header_set_Host(request_st * const restrict r, const char * const h, size_t hlen) +{ + r->http_host = http_header_request_set_ptr(r, HTTP_HEADER_HOST, + CONST_STR_LEN("Host")); + buffer_copy_string_len(r->http_host, h, hlen); + buffer_to_lower(r->http_host); +} + + int64_t li_restricted_strtoint64 (const char *v, const uint32_t vlen, const char ** const err) { @@ -291,8 +304,6 @@ li_restricted_strtoint64 (const char *v, const uint32_t vlen, const char ** cons * returns 0 on success, HTTP status on error */ static int http_request_parse_single_header(request_st * const restrict r, const enum http_header_e id, const char * const restrict k, const size_t klen, const char * const restrict v, const size_t vlen) { - buffer **saveb = NULL; - /* * Note: k might not be '\0'-terminated * Note: v is not '\0'-terminated @@ -309,14 +320,18 @@ static int http_request_parse_single_header(request_st * const restrict r, const break; case HTTP_HEADER_HOST: if (!light_btst(r->rqst_htags, HTTP_HEADER_HOST)) { - saveb = &r->http_host; if (vlen >= 1024) { /*(expecting < 256)*/ return http_request_header_line_invalid(r, 400, "uri-authority too long -> 400"); } + /*(http_request_header_append() plus sets r->http_host)*/ + http_request_header_set_Host(r, v, vlen); + return 0; } else if (NULL != r->http_host - && buffer_is_equal_string(r->http_host, v, vlen)) { + && (__builtin_expect( buffer_eq_slen(r->http_host, v, vlen), 1) + || buffer_eq_icase_slen(r->http_host, v, vlen))) { /* ignore all Host: headers if match authority in request line */ + /* (expect Host to match case in :authority of HTTP/2 request) */ return 0; /* ignore header */ } else { @@ -407,11 +422,6 @@ static int http_request_parse_single_header(request_st * const restrict r, const } http_header_request_append(r, id, k, klen, v, vlen); - - if (saveb) { - *saveb = http_header_request_get(r, id, k, klen); - } - return 0; } @@ -459,10 +469,8 @@ static const char * http_request_parse_reqline_uri(request_st * const restrict r http_request_header_line_invalid(r, 400, "uri-authority empty or too long -> 400"); return NULL; } - /* Insert as host header */ - r->http_host = http_header_request_set_ptr(r, HTTP_HEADER_HOST, - CONST_STR_LEN("Host")); - buffer_copy_string_len(r->http_host, host, hostlen); + /* Insert as "Host" header */ + http_request_header_set_Host(r, host, hostlen); return nuri; } else if (!(http_parseopts & HTTP_PARSEOPT_HEADER_STRICT) /*(!http_header_strict)*/ || (HTTP_METHOD_CONNECT == r->http_method && (uri[0] == ':' || light_isdigit(uri[0]))) @@ -492,7 +500,7 @@ http_request_validate_pseudohdrs (request_st * const restrict r, const int schem return http_request_header_line_invalid(r, 400, "missing pseudo-header method -> 400"); - if (HTTP_METHOD_CONNECT != r->http_method) { + if (__builtin_expect( (HTTP_METHOD_CONNECT != r->http_method), 1)) { if (!scheme) return http_request_header_line_invalid(r, 400, "missing pseudo-header scheme -> 400"); @@ -516,7 +524,9 @@ http_request_validate_pseudohdrs (request_st * const restrict r, const int schem if (!buffer_is_blank(&r->target) || scheme) return http_request_header_line_invalid(r, 400, "invalid pseudo-header with CONNECT -> 400"); - /*(reuse uri and ulen to assign to r->target)*/ + /* note: this copy occurs prior to http_request_host_policy() + * so any consumer handling CONNECT should normalize r->target + * as appropriate */ buffer_copy_buffer(&r->target, r->http_host); } buffer_copy_buffer(&r->target_orig, &r->target); @@ -623,11 +633,8 @@ http_request_parse_header (request_st * const restrict r, http_header_parse_ctx if (vlen >= 1024) /*(expecting < 256)*/ return http_request_header_line_invalid(r, 400, "invalid pseudo-header authority too long -> 400"); - /* insert as host header */ - r->http_host = - http_header_request_set_ptr(r, HTTP_HEADER_HOST, - CONST_STR_LEN("Host")); - buffer_copy_string_len(r->http_host, v, vlen); + /* insert as "Host" header */ + http_request_header_set_Host(r, v, vlen); return 0; case HTTP_HEADER_H2_METHOD_GET: /*(any method, not only "GET")*/ case HTTP_HEADER_H2_METHOD_POST: @@ -1132,11 +1139,10 @@ http_request_parse (request_st * const restrict r, const int scheme_port) /* check hostname field if it is set */ /*(r->http_host might not be set until after parsing request headers)*/ if (__builtin_expect( (r->http_host != NULL), 1)) { - buffer_copy_buffer(&r->uri.authority, r->http_host); - buffer_to_lower(&r->uri.authority); if (0 != http_request_host_policy(r->http_host, http_parseopts, scheme_port)) return http_request_header_line_invalid(r, 400, "Invalid Hostname -> 400"); + buffer_copy_buffer(&r->uri.authority, r->http_host); } else { buffer_copy_string_len(&r->uri.authority, CONST_STR_LEN(""));