diff options
author | Igor Sysoev <igor@sysoev.ru> | 2008-05-15 18:44:47 +0400 |
---|---|---|
committer | Igor Sysoev <igor@sysoev.ru> | 2008-05-15 18:44:47 +0400 |
commit | 5fd0931a611c112265d7d11a448cf26ffb542aad (patch) | |
tree | 503d22585a5fe2a2a703deccbb19552c0eaceac5 /src | |
parent | 433608c18072cbaa99deddf4432ab2537397f025 (diff) |
*) host in request line has priority
*) allow several Host headers
*) validate host
Diffstat (limited to 'src')
-rw-r--r-- | src/http/modules/ngx_http_dav_module.c | 18 | ||||
-rw-r--r-- | src/http/ngx_http_core_module.c | 3 | ||||
-rw-r--r-- | src/http/ngx_http_header_filter_module.c | 5 | ||||
-rw-r--r-- | src/http/ngx_http_request.c | 255 | ||||
-rw-r--r-- | src/http/ngx_http_request.h | 2 | ||||
-rw-r--r-- | src/http/ngx_http_variables.c | 25 |
6 files changed, 188 insertions, 120 deletions
diff --git a/src/http/modules/ngx_http_dav_module.c b/src/http/modules/ngx_http_dav_module.c index b1e0831b1..3d54525e8 100644 --- a/src/http/modules/ngx_http_dav_module.c +++ b/src/http/modules/ngx_http_dav_module.c @@ -512,7 +512,7 @@ ngx_http_dav_mkcol_handler(ngx_http_request_t *r, ngx_http_dav_loc_conf_t *dlcf) static ngx_int_t ngx_http_dav_copy_move_handler(ngx_http_request_t *r) { - u_char *p, *desthost, *last, ch; + u_char *p, *host, *last, ch; size_t len, root; ngx_err_t err; ngx_int_t rc, depth; @@ -520,7 +520,7 @@ ngx_http_dav_copy_move_handler(ngx_http_request_t *r) ngx_str_t path, uri; ngx_tree_ctx_t tree; ngx_file_info_t fi; - ngx_table_elt_t *host, *dest, *over; + ngx_table_elt_t *dest, *over; ngx_http_dav_copy_ctx_t copy; ngx_http_dav_loc_conf_t *dlcf; @@ -536,9 +536,9 @@ ngx_http_dav_copy_move_handler(ngx_http_request_t *r) return NGX_HTTP_BAD_REQUEST; } - host = r->headers_in.host; + len = r->headers_in.server.len; - if (host == NULL) { + if (len == 0) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "client sent no \"Host\" header"); return NGX_HTTP_BAD_REQUEST; @@ -553,7 +553,7 @@ ngx_http_dav_copy_move_handler(ngx_http_request_t *r) goto invalid_destination; } - desthost = dest->value.data + sizeof("https://") - 1; + host = dest->value.data + sizeof("https://") - 1; } else #endif @@ -564,12 +564,10 @@ ngx_http_dav_copy_move_handler(ngx_http_request_t *r) goto invalid_destination; } - desthost = dest->value.data + sizeof("http://") - 1; + host = dest->value.data + sizeof("http://") - 1; } - len = r->headers_in.host_name_len; - - if (ngx_strncmp(desthost, host->value.data, len) != 0) { + if (ngx_strncmp(host, r->headers_in.server.data, len) != 0) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "\"Destination\" URI \"%V\" is handled by " "different repository than the source URI", @@ -579,7 +577,7 @@ ngx_http_dav_copy_move_handler(ngx_http_request_t *r) last = dest->value.data + dest->value.len; - for (p = desthost + len; p < last; p++) { + for (p = host + len; p < last; p++) { if (*p == '/') { goto destination_done; } diff --git a/src/http/ngx_http_core_module.c b/src/http/ngx_http_core_module.c index cb9eb14c7..a80947058 100644 --- a/src/http/ngx_http_core_module.c +++ b/src/http/ngx_http_core_module.c @@ -3216,8 +3216,7 @@ ngx_http_core_server_name(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) value[i].len--; value[i].data++; - sn->regex = ngx_regex_compile(&value[i], NGX_REGEX_CASELESS, cf->pool, - &err); + sn->regex = ngx_regex_compile(&value[i], 0, cf->pool, &err); if (sn->regex == NULL) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "%s", err.data); diff --git a/src/http/ngx_http_header_filter_module.c b/src/http/ngx_http_header_filter_module.c index 9cdac6126..2dd5b952b 100644 --- a/src/http/ngx_http_header_filter_module.c +++ b/src/http/ngx_http_header_filter_module.c @@ -286,9 +286,8 @@ ngx_http_header_filter(ngx_http_request_t *r) cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module); host = cscf->server_name; - } else if (r->headers_in.host) { - host.len = r->headers_in.host_name_len; - host.data = r->headers_in.host->value.data; + } else if (r->headers_in.server.len) { + host = r->headers_in.server; } else { host.data = addr; diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c index e124e5f99..0535fc0ef 100644 --- a/src/http/ngx_http_request.c +++ b/src/http/ngx_http_request.c @@ -21,6 +21,8 @@ static ngx_int_t ngx_http_process_header_line(ngx_http_request_t *r, ngx_table_elt_t *h, ngx_uint_t offset); static ngx_int_t ngx_http_process_unique_header_line(ngx_http_request_t *r, ngx_table_elt_t *h, ngx_uint_t offset); +static ngx_int_t ngx_http_process_host(ngx_http_request_t *r, + ngx_table_elt_t *h, ngx_uint_t offset); static ngx_int_t ngx_http_process_connection(ngx_http_request_t *r, ngx_table_elt_t *h, ngx_uint_t offset); static ngx_int_t ngx_http_process_user_agent(ngx_http_request_t *r, @@ -30,8 +32,9 @@ static ngx_int_t ngx_http_process_cookie(ngx_http_request_t *r, static ngx_int_t ngx_http_process_request_header(ngx_http_request_t *r); static void ngx_http_process_request(ngx_http_request_t *r); -static void ngx_http_find_virtual_server(ngx_http_request_t *r, u_char *host, - size_t len, ngx_uint_t hash); +static ssize_t ngx_http_validate_host(u_char *host, size_t len); +static ngx_int_t ngx_http_find_virtual_server(ngx_http_request_t *r, + u_char *host, size_t len); static void ngx_http_request_handler(ngx_event_t *ev); static ngx_int_t ngx_http_set_write_handler(ngx_http_request_t *r); @@ -71,8 +74,7 @@ static char *ngx_http_client_errors[] = { ngx_http_header_t ngx_http_headers_in[] = { - { ngx_string("Host"), offsetof(ngx_http_headers_in_t, host), - ngx_http_process_unique_header_line }, + { ngx_string("Host"), 0, ngx_http_process_host }, { ngx_string("Connection"), 0, ngx_http_process_connection }, @@ -562,8 +564,6 @@ ngx_http_ssl_handshake_handler(ngx_connection_t *c) int ngx_http_ssl_servername(ngx_ssl_conn_t *ssl_conn, int *ad, void *arg) { - u_char *p; - ngx_uint_t hash; const char *servername; ngx_connection_t *c; ngx_http_request_t *r; @@ -582,21 +582,13 @@ ngx_http_ssl_servername(ngx_ssl_conn_t *ssl_conn, int *ad, void *arg) r = c->data; - if (r->virtual_names == NULL) { + if (ngx_http_find_virtual_server(r, (u_char *) servername, + ngx_strlen(servername)) + != NGX_OK) + { return SSL_TLSEXT_ERR_NOACK; } - /* it seems browsers send low case server name */ - - hash = 0; - - for (p = (u_char *) servername; *p; p++) { - hash = ngx_hash(hash, *p); - } - - ngx_http_find_virtual_server(r, (u_char *) servername, - p - (u_char *) servername, hash); - sscf = ngx_http_get_module_srv_conf(r, ngx_http_ssl_module); SSL_set_SSL_CTX(ssl_conn, sscf->ssl.ctx); @@ -726,7 +718,31 @@ ngx_http_process_request_line(ngx_event_t *rev) ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, "http exten: \"%V\"", &r->exten); + if (r->host_start && r->host_end) { + n = ngx_http_validate_host(r->host_start, + r->host_end - r->host_start); + + if (n <= 0) { + ngx_log_error(NGX_LOG_INFO, c->log, 0, + "client sent invalid host in request line"); + ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST); + return; + } + + r->headers_in.server.len = n; + r->headers_in.server.data = r->host_start; + } + if (r->http_version < NGX_HTTP_VERSION_10) { + + if (ngx_http_find_virtual_server(r, r->headers_in.server.data, + r->headers_in.server.len) + == NGX_ERROR) + { + ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); + return; + } + ngx_http_process_request(r); return; } @@ -1217,35 +1233,47 @@ ngx_http_process_unique_header_line(ngx_http_request_t *r, ngx_table_elt_t *h, static ngx_int_t -ngx_http_process_connection(ngx_http_request_t *r, ngx_table_elt_t *h, +ngx_http_process_host(ngx_http_request_t *r, ngx_table_elt_t *h, ngx_uint_t offset) { - if (ngx_strcasestrn(h->value.data, "close", 5 - 1)) { - r->headers_in.connection_type = NGX_HTTP_CONNECTION_CLOSE; + ssize_t len; - } else if (ngx_strcasestrn(h->value.data, "keep-alive", 10 - 1)) { - r->headers_in.connection_type = NGX_HTTP_CONNECTION_KEEP_ALIVE; + if (r->headers_in.host == NULL) { + r->headers_in.host = h; + } + + len = ngx_http_validate_host(h->value.data, h->value.len); + + if (len <= 0) { + ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, + "client sent invalid host header"); + ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST); + return NGX_ERROR; + } + + if (r->headers_in.server.len) { + return NGX_OK; } + r->headers_in.server.len = len; + r->headers_in.server.data = h->value.data; + return NGX_OK; } static ngx_int_t -ngx_http_process_cookie(ngx_http_request_t *r, ngx_table_elt_t *h, +ngx_http_process_connection(ngx_http_request_t *r, ngx_table_elt_t *h, ngx_uint_t offset) { - ngx_table_elt_t **cookie; + if (ngx_strcasestrn(h->value.data, "close", 5 - 1)) { + r->headers_in.connection_type = NGX_HTTP_CONNECTION_CLOSE; - cookie = ngx_array_push(&r->headers_in.cookies); - if (cookie) { - *cookie = h; - return NGX_OK; + } else if (ngx_strcasestrn(h->value.data, "keep-alive", 10 - 1)) { + r->headers_in.connection_type = NGX_HTTP_CONNECTION_KEEP_ALIVE; } - ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); - - return NGX_ERROR; + return NGX_OK; } @@ -1304,59 +1332,39 @@ ngx_http_process_user_agent(ngx_http_request_t *r, ngx_table_elt_t *h, static ngx_int_t -ngx_http_process_request_header(ngx_http_request_t *r) +ngx_http_process_cookie(ngx_http_request_t *r, ngx_table_elt_t *h, + ngx_uint_t offset) { - size_t len; - u_char *host, ch; - ngx_uint_t hash; - - if (r->headers_in.host) { - - hash = 0; - - for (len = 0; len < r->headers_in.host->value.len; len++) { - ch = r->headers_in.host->value.data[len]; - - if (ch == ':') { - break; - } - - ch = ngx_tolower(ch); - r->headers_in.host->value.data[len] = ch; - hash = ngx_hash(hash, ch); - } - - if (len && r->headers_in.host->value.data[len - 1] == '.') { - len--; - hash = ngx_hash_key(r->headers_in.host->value.data, len); - } - - r->headers_in.host_name_len = len; - - if (r->virtual_names) { + ngx_table_elt_t **cookie; - host = r->host_start; + cookie = ngx_array_push(&r->headers_in.cookies); + if (cookie) { + *cookie = h; + return NGX_OK; + } - if (host == NULL) { - host = r->headers_in.host->value.data; - len = r->headers_in.host_name_len; + ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); - } else { - len = r->host_end - host; - } + return NGX_ERROR; +} - ngx_http_find_virtual_server(r, host, len, hash); - } - } else { - if (r->http_version > NGX_HTTP_VERSION_10) { - ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, - "client sent HTTP/1.1 request without \"Host\" header"); - ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST); - return NGX_ERROR; - } +static ngx_int_t +ngx_http_process_request_header(ngx_http_request_t *r) +{ + if (ngx_http_find_virtual_server(r, r->headers_in.server.data, + r->headers_in.server.len) + == NGX_ERROR) + { + ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); + return NGX_ERROR; + } - r->headers_in.host_name_len = 0; + if (r->headers_in.host == NULL && r->http_version > NGX_HTTP_VERSION_10) { + ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, + "client sent HTTP/1.1 request without \"Host\" header"); + ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST); + return NGX_ERROR; } if (r->headers_in.content_length) { @@ -1489,14 +1497,89 @@ ngx_http_process_request(ngx_http_request_t *r) } -static void -ngx_http_find_virtual_server(ngx_http_request_t *r, u_char *host, size_t len, - ngx_uint_t hash) +static ssize_t +ngx_http_validate_host(u_char *host, size_t len) +{ + u_char ch; + size_t i, last; + ngx_uint_t dot; + + last = len; + dot = 0; + + for (i = 0; i < len; i++) { + ch = host[i]; + + if (ch == '.') { + if (dot) { + return -1; + } + + dot = 1; + continue; + } + + dot = 0; + + if (ch == ':') { + last = i; + continue; + } + + if (ch == '/' || ch == '\0') { + return -1; + } + +#if (NGX_WIN32) + if (ch == '\\') { + return -1; + } +#endif + } + + if (dot) { + last--; + } + + return last; +} + + +static ngx_int_t +ngx_http_find_virtual_server(ngx_http_request_t *r, u_char *host, size_t len) { + u_char *server, ch; + ngx_uint_t i, hash; ngx_http_core_loc_conf_t *clcf; ngx_http_core_srv_conf_t *cscf; + u_char buf[32]; + + if (len == 0 || r->virtual_names == NULL) { + return NGX_DECLINED; + } - cscf = ngx_hash_find_combined(&r->virtual_names->names, hash, host, len); + if (len <= 32) { + server = buf; + + } else { + server = ngx_palloc(r->pool, len); + if (server == NULL) { + return NGX_ERROR; + } + } + + hash = 0; + + for (i = 0; i < len; i++) { + ch = host[i]; + + ch = ngx_tolower(ch); + server[i] = ch; + + hash = ngx_hash(hash, ch); + } + + cscf = ngx_hash_find_combined(&r->virtual_names->names, hash, server, len); if (cscf) { goto found; @@ -1511,7 +1594,7 @@ ngx_http_find_virtual_server(ngx_http_request_t *r, u_char *host, size_t len, ngx_http_server_name_t *sn; name.len = len; - name.data = host; + name.data = server; sn = r->virtual_names->regex; @@ -1528,7 +1611,7 @@ ngx_http_find_virtual_server(ngx_http_request_t *r, u_char *host, size_t len, ngx_regex_exec_n " failed: %d on \"%V\" using \"%V\"", n, &name, &sn[i].name); - return; + return NGX_ERROR; } /* match */ @@ -1541,7 +1624,7 @@ ngx_http_find_virtual_server(ngx_http_request_t *r, u_char *host, size_t len, #endif - return; + return NGX_OK; found: @@ -1555,7 +1638,7 @@ found: r->connection->log->log_level = clcf->err_log->log_level; } - return; + return NGX_OK; } diff --git a/src/http/ngx_http_request.h b/src/http/ngx_http_request.h index 9073be928..2e7ff54b6 100644 --- a/src/http/ngx_http_request.h +++ b/src/http/ngx_http_request.h @@ -206,7 +206,7 @@ typedef struct { ngx_array_t cookies; - size_t host_name_len; + ngx_str_t server; off_t content_length_n; time_t keep_alive_n; diff --git a/src/http/ngx_http_variables.c b/src/http/ngx_http_variables.c index df00675eb..c2a27a76a 100644 --- a/src/http/ngx_http_variables.c +++ b/src/http/ngx_http_variables.c @@ -712,26 +712,15 @@ ngx_http_variable_host(ngx_http_request_t *r, ngx_http_variable_value_t *v, { ngx_http_core_srv_conf_t *cscf; - if (r->host_start == NULL) { - - if (r->headers_in.host) { - v->len = r->headers_in.host_name_len; - v->data = r->headers_in.host->value.data; - - } else { - cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module); - - v->len = cscf->server_name.len; - v->data = cscf->server_name.data; - } - - } else if (r->host_end) { - v->len = r->host_end - r->host_start; - v->data = r->host_start; + if (r->headers_in.server.len) { + v->len = r->headers_in.server.len; + v->data = r->headers_in.server.data; } else { - v->not_found = 1; - return NGX_OK; + cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module); + + v->len = cscf->server_name.len; + v->data = cscf->server_name.data; } v->valid = 1; |