HTTP: controlling response headers support.
This commit is contained in:
@@ -93,6 +93,7 @@ NXT_LIB_SRCS=" \
|
|||||||
src/nxt_http_route.c \
|
src/nxt_http_route.c \
|
||||||
src/nxt_http_route_addr.c \
|
src/nxt_http_route_addr.c \
|
||||||
src/nxt_http_rewrite.c \
|
src/nxt_http_rewrite.c \
|
||||||
|
src/nxt_http_set_headers.c \
|
||||||
src/nxt_http_return.c \
|
src/nxt_http_return.c \
|
||||||
src/nxt_http_static.c \
|
src/nxt_http_static.c \
|
||||||
src/nxt_http_proxy.c \
|
src/nxt_http_proxy.c \
|
||||||
|
|||||||
@@ -38,6 +38,12 @@ njs updated to 0.8.0.
|
|||||||
</para>
|
</para>
|
||||||
</change>
|
</change>
|
||||||
|
|
||||||
|
<change type="feature">
|
||||||
|
<para>
|
||||||
|
ability to control HTTP response headers.
|
||||||
|
</para>
|
||||||
|
</change>
|
||||||
|
|
||||||
<change type="feature">
|
<change type="feature">
|
||||||
<para>
|
<para>
|
||||||
ability to get the HTTP response header variables.
|
ability to get the HTTP response header variables.
|
||||||
|
|||||||
@@ -167,6 +167,8 @@ static nxt_int_t nxt_conf_vldt_match_addrs(nxt_conf_validation_t *vldt,
|
|||||||
nxt_conf_value_t *value, void *data);
|
nxt_conf_value_t *value, void *data);
|
||||||
static nxt_int_t nxt_conf_vldt_match_addr(nxt_conf_validation_t *vldt,
|
static nxt_int_t nxt_conf_vldt_match_addr(nxt_conf_validation_t *vldt,
|
||||||
nxt_conf_value_t *value);
|
nxt_conf_value_t *value);
|
||||||
|
static nxt_int_t nxt_conf_vldt_response_header(nxt_conf_validation_t *vldt,
|
||||||
|
nxt_str_t *name, nxt_conf_value_t *value);
|
||||||
static nxt_int_t nxt_conf_vldt_app_name(nxt_conf_validation_t *vldt,
|
static nxt_int_t nxt_conf_vldt_app_name(nxt_conf_validation_t *vldt,
|
||||||
nxt_conf_value_t *value, void *data);
|
nxt_conf_value_t *value, void *data);
|
||||||
static nxt_int_t nxt_conf_vldt_forwarded(nxt_conf_validation_t *vldt,
|
static nxt_int_t nxt_conf_vldt_forwarded(nxt_conf_validation_t *vldt,
|
||||||
@@ -688,6 +690,12 @@ static nxt_conf_vldt_object_t nxt_conf_vldt_action_common_members[] = {
|
|||||||
.name = nxt_string("rewrite"),
|
.name = nxt_string("rewrite"),
|
||||||
.type = NXT_CONF_VLDT_STRING,
|
.type = NXT_CONF_VLDT_STRING,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
.name = nxt_string("response_headers"),
|
||||||
|
.type = NXT_CONF_VLDT_OBJECT,
|
||||||
|
.validator = nxt_conf_vldt_object_iterator,
|
||||||
|
.u.object = nxt_conf_vldt_response_header,
|
||||||
|
},
|
||||||
|
|
||||||
NXT_CONF_VLDT_END
|
NXT_CONF_VLDT_END
|
||||||
};
|
};
|
||||||
@@ -2447,6 +2455,35 @@ nxt_conf_vldt_object_conf_commands(nxt_conf_validation_t *vldt,
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
static nxt_int_t
|
||||||
|
nxt_conf_vldt_response_header(nxt_conf_validation_t *vldt, nxt_str_t *name,
|
||||||
|
nxt_conf_value_t *value)
|
||||||
|
{
|
||||||
|
nxt_uint_t type;
|
||||||
|
|
||||||
|
static nxt_str_t content_length = nxt_string("Content-Length");
|
||||||
|
|
||||||
|
if (name->length == 0) {
|
||||||
|
return nxt_conf_vldt_error(vldt, "The response header name "
|
||||||
|
"must not be empty.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nxt_strstr_eq(name, &content_length)) {
|
||||||
|
return nxt_conf_vldt_error(vldt, "The \"Content-Length\" response "
|
||||||
|
"header value is not supported");
|
||||||
|
}
|
||||||
|
|
||||||
|
type = nxt_conf_type(value);
|
||||||
|
|
||||||
|
if (type == NXT_CONF_STRING || type == NXT_CONF_NULL) {
|
||||||
|
return NXT_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
return nxt_conf_vldt_error(vldt, "The \"%V\" response header value "
|
||||||
|
"must either be a string or a null", name);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static nxt_int_t
|
static nxt_int_t
|
||||||
nxt_conf_vldt_app_name(nxt_conf_validation_t *vldt, nxt_conf_value_t *value,
|
nxt_conf_vldt_app_name(nxt_conf_validation_t *vldt, nxt_conf_value_t *value,
|
||||||
void *data)
|
void *data)
|
||||||
|
|||||||
@@ -228,6 +228,7 @@ typedef struct nxt_http_route_addr_rule_s nxt_http_route_addr_rule_t;
|
|||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
nxt_conf_value_t *rewrite;
|
nxt_conf_value_t *rewrite;
|
||||||
|
nxt_conf_value_t *set_headers;
|
||||||
nxt_conf_value_t *pass;
|
nxt_conf_value_t *pass;
|
||||||
nxt_conf_value_t *ret;
|
nxt_conf_value_t *ret;
|
||||||
nxt_conf_value_t *location;
|
nxt_conf_value_t *location;
|
||||||
@@ -256,6 +257,7 @@ struct nxt_http_action_s {
|
|||||||
} u;
|
} u;
|
||||||
|
|
||||||
nxt_tstr_t *rewrite;
|
nxt_tstr_t *rewrite;
|
||||||
|
nxt_array_t *set_headers; /* of nxt_http_field_t */
|
||||||
nxt_http_action_t *fallback;
|
nxt_http_action_t *fallback;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -385,6 +387,10 @@ nxt_int_t nxt_http_rewrite_init(nxt_router_conf_t *rtcf,
|
|||||||
nxt_http_action_t *action, nxt_http_action_conf_t *acf);
|
nxt_http_action_t *action, nxt_http_action_conf_t *acf);
|
||||||
nxt_int_t nxt_http_rewrite(nxt_task_t *task, nxt_http_request_t *r);
|
nxt_int_t nxt_http_rewrite(nxt_task_t *task, nxt_http_request_t *r);
|
||||||
|
|
||||||
|
nxt_int_t nxt_http_set_headers_init(nxt_router_conf_t *rtcf,
|
||||||
|
nxt_http_action_t *action, nxt_http_action_conf_t *acf);
|
||||||
|
nxt_int_t nxt_http_set_headers(nxt_http_request_t *r);
|
||||||
|
|
||||||
nxt_int_t nxt_http_return_init(nxt_router_conf_t *rtcf,
|
nxt_int_t nxt_http_return_init(nxt_router_conf_t *rtcf,
|
||||||
nxt_http_action_t *action, nxt_http_action_conf_t *acf);
|
nxt_http_action_t *action, nxt_http_action_conf_t *acf);
|
||||||
|
|
||||||
|
|||||||
@@ -630,9 +630,15 @@ nxt_http_request_header_send(nxt_task_t *task, nxt_http_request_t *r,
|
|||||||
nxt_work_handler_t body_handler, void *data)
|
nxt_work_handler_t body_handler, void *data)
|
||||||
{
|
{
|
||||||
u_char *p, *end, *server_string;
|
u_char *p, *end, *server_string;
|
||||||
|
nxt_int_t ret;
|
||||||
nxt_http_field_t *server, *date, *content_length;
|
nxt_http_field_t *server, *date, *content_length;
|
||||||
nxt_socket_conf_t *skcf;
|
nxt_socket_conf_t *skcf;
|
||||||
|
|
||||||
|
ret = nxt_http_set_headers(r);
|
||||||
|
if (nxt_slow_path(ret != NXT_OK)) {
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* TODO: "Server", "Date", and "Content-Length" processing should be moved
|
* TODO: "Server", "Date", and "Content-Length" processing should be moved
|
||||||
* to the last header filter.
|
* to the last header filter.
|
||||||
|
|||||||
@@ -583,6 +583,11 @@ static nxt_conf_map_t nxt_http_route_action_conf[] = {
|
|||||||
NXT_CONF_MAP_PTR,
|
NXT_CONF_MAP_PTR,
|
||||||
offsetof(nxt_http_action_conf_t, rewrite)
|
offsetof(nxt_http_action_conf_t, rewrite)
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
nxt_string("response_headers"),
|
||||||
|
NXT_CONF_MAP_PTR,
|
||||||
|
offsetof(nxt_http_action_conf_t, set_headers)
|
||||||
|
},
|
||||||
{
|
{
|
||||||
nxt_string("pass"),
|
nxt_string("pass"),
|
||||||
NXT_CONF_MAP_PTR,
|
NXT_CONF_MAP_PTR,
|
||||||
@@ -671,6 +676,13 @@ nxt_http_action_init(nxt_task_t *task, nxt_router_temp_conf_t *tmcf,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (acf.set_headers != NULL) {
|
||||||
|
ret = nxt_http_set_headers_init(rtcf, action, &acf);
|
||||||
|
if (nxt_slow_path(ret != NXT_OK)) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (acf.ret != NULL) {
|
if (acf.ret != NULL) {
|
||||||
return nxt_http_return_init(rtcf, action, &acf);
|
return nxt_http_return_init(rtcf, action, &acf);
|
||||||
}
|
}
|
||||||
|
|||||||
176
src/nxt_http_set_headers.c
Normal file
176
src/nxt_http_set_headers.c
Normal file
@@ -0,0 +1,176 @@
|
|||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (C) Zhidao HONG
|
||||||
|
* Copyright (C) NGINX, Inc.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <nxt_router.h>
|
||||||
|
#include <nxt_http.h>
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
nxt_str_t name;
|
||||||
|
nxt_tstr_t *value;
|
||||||
|
} nxt_http_header_val_t;
|
||||||
|
|
||||||
|
|
||||||
|
nxt_int_t
|
||||||
|
nxt_http_set_headers_init(nxt_router_conf_t *rtcf, nxt_http_action_t *action,
|
||||||
|
nxt_http_action_conf_t *acf)
|
||||||
|
{
|
||||||
|
uint32_t next;
|
||||||
|
nxt_str_t str, name;
|
||||||
|
nxt_array_t *headers;
|
||||||
|
nxt_conf_value_t *value;
|
||||||
|
nxt_http_header_val_t *hv;
|
||||||
|
|
||||||
|
headers = nxt_array_create(rtcf->mem_pool, 4,
|
||||||
|
sizeof(nxt_http_header_val_t));
|
||||||
|
if (nxt_slow_path(headers == NULL)) {
|
||||||
|
return NXT_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
action->set_headers = headers;
|
||||||
|
|
||||||
|
next = 0;
|
||||||
|
|
||||||
|
for ( ;; ) {
|
||||||
|
value = nxt_conf_next_object_member(acf->set_headers, &name, &next);
|
||||||
|
if (value == NULL) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
hv = nxt_array_zero_add(headers);
|
||||||
|
if (nxt_slow_path(hv == NULL)) {
|
||||||
|
return NXT_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
hv->name.length = name.length;
|
||||||
|
|
||||||
|
hv->name.start = nxt_mp_nget(rtcf->mem_pool, name.length);
|
||||||
|
if (nxt_slow_path(hv->name.start == NULL)) {
|
||||||
|
return NXT_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
nxt_memcpy(hv->name.start, name.start, name.length);
|
||||||
|
|
||||||
|
if (nxt_conf_type(value) == NXT_CONF_STRING) {
|
||||||
|
nxt_conf_get_string(value, &str);
|
||||||
|
|
||||||
|
hv->value = nxt_tstr_compile(rtcf->tstr_state, &str, 0);
|
||||||
|
if (nxt_slow_path(hv->value == NULL)) {
|
||||||
|
return NXT_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return NXT_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static nxt_http_field_t *
|
||||||
|
nxt_http_resp_header_find(nxt_http_request_t *r, u_char *name, size_t length)
|
||||||
|
{
|
||||||
|
nxt_http_field_t *f;
|
||||||
|
|
||||||
|
nxt_list_each(f, r->resp.fields) {
|
||||||
|
|
||||||
|
if (f->skip) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (length == f->name_length
|
||||||
|
&& nxt_memcasecmp(name, f->name, f->name_length) == 0)
|
||||||
|
{
|
||||||
|
return f;
|
||||||
|
}
|
||||||
|
|
||||||
|
} nxt_list_loop;
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
nxt_int_t
|
||||||
|
nxt_http_set_headers(nxt_http_request_t *r)
|
||||||
|
{
|
||||||
|
nxt_int_t ret;
|
||||||
|
nxt_uint_t i, n;
|
||||||
|
nxt_str_t *value;
|
||||||
|
nxt_http_field_t *f;
|
||||||
|
nxt_router_conf_t *rtcf;
|
||||||
|
nxt_http_action_t *action;
|
||||||
|
nxt_http_header_val_t *hv, *header;
|
||||||
|
|
||||||
|
action = r->action;
|
||||||
|
|
||||||
|
if (action == NULL || action->set_headers == NULL) {
|
||||||
|
return NXT_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((r->status < NXT_HTTP_OK || r->status >= NXT_HTTP_BAD_REQUEST)) {
|
||||||
|
return NXT_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
rtcf = r->conf->socket_conf->router_conf;
|
||||||
|
|
||||||
|
header = action->set_headers->elts;
|
||||||
|
n = action->set_headers->nelts;
|
||||||
|
|
||||||
|
value = nxt_mp_zalloc(r->mem_pool, sizeof(nxt_str_t) * n);
|
||||||
|
if (nxt_slow_path(value == NULL)) {
|
||||||
|
return NXT_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < n; i++) {
|
||||||
|
hv = &header[i];
|
||||||
|
|
||||||
|
if (hv->value == NULL) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nxt_tstr_is_const(hv->value)) {
|
||||||
|
nxt_tstr_str(hv->value, &value[i]);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
ret = nxt_tstr_query_init(&r->tstr_query, rtcf->tstr_state,
|
||||||
|
&r->tstr_cache, r, r->mem_pool);
|
||||||
|
if (nxt_slow_path(ret != NXT_OK)) {
|
||||||
|
return NXT_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
nxt_tstr_query(&r->task, r->tstr_query, hv->value, &value[i]);
|
||||||
|
|
||||||
|
if (nxt_slow_path(nxt_tstr_query_failed(r->tstr_query))) {
|
||||||
|
return NXT_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < n; i++) {
|
||||||
|
hv = &header[i];
|
||||||
|
|
||||||
|
f = nxt_http_resp_header_find(r, hv->name.start, hv->name.length);
|
||||||
|
|
||||||
|
if (value[i].start != NULL) {
|
||||||
|
|
||||||
|
if (f == NULL) {
|
||||||
|
f = nxt_list_zero_add(r->resp.fields);
|
||||||
|
if (nxt_slow_path(f == NULL)) {
|
||||||
|
return NXT_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
f->name = hv->name.start;
|
||||||
|
f->name_length = hv->name.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
f->value = value[i].start;
|
||||||
|
f->value_length = value[i].length;
|
||||||
|
|
||||||
|
} else if (f != NULL) {
|
||||||
|
f->skip = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return NXT_OK;
|
||||||
|
}
|
||||||
@@ -137,7 +137,7 @@ nxt_http_unknown_var_ref(nxt_tstr_state_t *state, nxt_var_ref_t *ref,
|
|||||||
|
|
||||||
if (nxt_str_start(name, "response_header_", 16)) {
|
if (nxt_str_start(name, "response_header_", 16)) {
|
||||||
ref->handler = nxt_http_var_response_header;
|
ref->handler = nxt_http_var_response_header;
|
||||||
ref->cacheable = 1;
|
ref->cacheable = 0;
|
||||||
|
|
||||||
str.start = name->start + 16;
|
str.start = name->start + 16;
|
||||||
str.length = name->length - 16;
|
str.length = name->length - 16;
|
||||||
|
|||||||
Reference in New Issue
Block a user