# HG changeset patch # User Igor Sysoev # Date 1217849349 0 # Node ID fb3b084e7d42d19103b470b85ba51c3f65907ba2 # Parent 76d5af541412f6601cf7a184906e35070710b695 test Content-Type via hash: *) ngx_http_test_content_type() *) ngx_http_types_slot() *) ngx_http_merge_types() diff --git a/src/http/ngx_http.c b/src/http/ngx_http.c --- a/src/http/ngx_http.c +++ b/src/http/ngx_http.c @@ -1687,3 +1687,135 @@ ngx_http_init_listening(ngx_conf_t *cf, return NGX_OK; } + + +char * +ngx_http_types_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + char *p = conf; + + ngx_array_t **types; + ngx_str_t *value, *default_type; + ngx_uint_t i, n, hash; + ngx_hash_key_t *type; + + types = (ngx_array_t **) (p + cmd->offset); + + default_type = cmd->post; + + if (*types == NULL) { + *types = ngx_array_create(cf->temp_pool, 1, sizeof(ngx_hash_key_t)); + if (*types == NULL) { + return NGX_CONF_ERROR; + } + + if (default_type) { + type = ngx_array_push(*types); + if (type == NULL) { + return NGX_CONF_ERROR; + } + + type->key = *default_type; + type->key_hash = ngx_hash_key(default_type->data, + default_type->len); + type->value = (void *) 4; + } + } + + value = cf->args->elts; + + for (i = 1; i < cf->args->nelts; i++) { + + hash = ngx_hash_strlow(value[i].data, value[i].data, value[i].len); + value[i].data[value[i].len] = '\0'; + + type = (*types)->elts; + for (n = 0; n < (*types)->nelts; n++) { + + if (ngx_strcmp(value[i].data, type[n].key.data) == 0) { + ngx_conf_log_error(NGX_LOG_WARN, cf, 0, + "duplicate MIME type \"%V\"", &value[i]); + continue; + } + } + + type = ngx_array_push(*types); + if (type == NULL) { + return NGX_CONF_ERROR; + } + + type->key = value[i]; + type->key_hash = hash; + type->value = (void *) 4; + } + + return NGX_CONF_OK; +} + + +char * +ngx_http_merge_types(ngx_conf_t *cf, ngx_array_t *keys, ngx_hash_t *types_hash, + ngx_array_t *prev_keys, ngx_hash_t *prev_types_hash, + ngx_str_t *default_types) +{ + ngx_hash_init_t hash; + + if (keys == NULL) { + + if (prev_keys) { + *types_hash = *prev_types_hash; + return NGX_CONF_OK; + } + + if (ngx_http_set_default_types(cf, &keys, default_types) + != NGX_CONF_OK) + { + return NGX_CONF_ERROR; + } + } + + hash.hash = types_hash; + hash.key = NULL; + hash.max_size = 2048; + hash.bucket_size = 64; + hash.name = "test_types_hash"; + hash.pool = cf->pool; + hash.temp_pool = NULL; + + if (ngx_hash_init(&hash, keys->elts, keys->nelts) != NGX_OK) { + return NGX_CONF_ERROR; + } + + return NGX_CONF_OK; + +} + + +char * +ngx_http_set_default_types(ngx_conf_t *cf, ngx_array_t **types, + ngx_str_t *default_type) +{ + ngx_hash_key_t *type; + + *types = ngx_array_create(cf->temp_pool, 1, sizeof(ngx_hash_key_t)); + if (*types == NULL) { + return NGX_CONF_ERROR; + } + + while (default_type->len) { + + type = ngx_array_push(*types); + if (type == NULL) { + return NGX_CONF_ERROR; + } + + type->key = *default_type; + type->key_hash = ngx_hash_key(default_type->data, + default_type->len); + type->value = (void *) 4; + + default_type++; + } + + return NGX_CONF_OK; +} diff --git a/src/http/ngx_http.h b/src/http/ngx_http.h --- a/src/http/ngx_http.h +++ b/src/http/ngx_http.h @@ -107,6 +107,14 @@ ngx_int_t ngx_http_discard_request_body( void ngx_http_block_reading(ngx_http_request_t *r); +char *ngx_http_types_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); +char *ngx_http_merge_types(ngx_conf_t *cf, ngx_array_t *keys, + ngx_hash_t *types_hash, ngx_array_t *prev_keys, ngx_hash_t *prev_types_hash, + ngx_str_t *default_types); +char *ngx_http_set_default_types(ngx_conf_t *cf, ngx_array_t **types, + ngx_str_t *default_type); + + extern ngx_module_t ngx_http_module; diff --git a/src/http/ngx_http_core_module.c b/src/http/ngx_http_core_module.c --- a/src/http/ngx_http_core_module.c +++ b/src/http/ngx_http_core_module.c @@ -1302,6 +1302,44 @@ ngx_http_core_send_continue(ngx_http_req } +void * +ngx_http_test_content_type(ngx_http_request_t *r, ngx_hash_t *types_hash) +{ + u_char c, *p; + ngx_uint_t i, hash; + + if (r->headers_out.content_type.len == 0) { + return NULL; + } + + if (r->headers_out.content_type_lowcase == NULL) { + + p = ngx_pnalloc(r->pool, r->headers_out.content_type_len); + + if (p == NULL) { + return NULL; + } + + r->headers_out.content_type_lowcase = p; + + hash = 0; + + for (i = 0; i < r->headers_out.content_type_len; i++) { + c = ngx_tolower(r->headers_out.content_type.data[i]); + hash = ngx_hash(hash, c); + *p++ = c; + } + + r->headers_out.content_type_hash = hash; + } + + return ngx_hash_find(types_hash, + r->headers_out.content_type_hash, + r->headers_out.content_type_lowcase, + r->headers_out.content_type_len); +} + + ngx_int_t ngx_http_set_content_type(ngx_http_request_t *r) { diff --git a/src/http/ngx_http_core_module.h b/src/http/ngx_http_core_module.h --- a/src/http/ngx_http_core_module.h +++ b/src/http/ngx_http_core_module.h @@ -373,6 +373,8 @@ ngx_int_t ngx_http_core_post_access_phas ngx_int_t ngx_http_core_content_phase(ngx_http_request_t *r, ngx_http_phase_handler_t *ph); + +void *ngx_http_test_content_type(ngx_http_request_t *r, ngx_hash_t *types_hash); ngx_int_t ngx_http_set_content_type(ngx_http_request_t *r); ngx_int_t ngx_http_set_exten(ngx_http_request_t *r); u_char *ngx_http_map_uri_to_path(ngx_http_request_t *r, ngx_str_t *name, diff --git a/src/http/ngx_http_request.h b/src/http/ngx_http_request.h --- a/src/http/ngx_http_request.h +++ b/src/http/ngx_http_request.h @@ -244,6 +244,8 @@ typedef struct { size_t content_type_len; ngx_str_t content_type; ngx_str_t charset; + u_char *content_type_lowcase; + ngx_uint_t content_type_hash; ngx_array_t cache_control;