Var: supported HTTP response header variables.
This commit adds the variable $response_header_NAME.
This commit is contained in:
@@ -38,6 +38,12 @@ njs updated to 0.8.0.
|
|||||||
</para>
|
</para>
|
||||||
</change>
|
</change>
|
||||||
|
|
||||||
|
<change type="feature">
|
||||||
|
<para>
|
||||||
|
ability to get the HTTP response header variables.
|
||||||
|
</para>
|
||||||
|
</change>
|
||||||
|
|
||||||
<change type="bugfix">
|
<change type="bugfix">
|
||||||
<para>
|
<para>
|
||||||
ensure that $uri variable is not cached.
|
ensure that $uri variable is not cached.
|
||||||
|
|||||||
@@ -1284,7 +1284,7 @@ nxt_h1p_request_header_send(nxt_task_t *task, nxt_http_request_t *r,
|
|||||||
size += NXT_WEBSOCKET_ACCEPT_SIZE + 2;
|
size += NXT_WEBSOCKET_ACCEPT_SIZE + 2;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
http11 = (h1p->parser.version.s.minor != '0');
|
http11 = nxt_h1p_is_http11(h1p);
|
||||||
|
|
||||||
if (r->resp.content_length == NULL || r->resp.content_length->skip) {
|
if (r->resp.content_length == NULL || r->resp.content_length->skip) {
|
||||||
|
|
||||||
|
|||||||
@@ -51,4 +51,7 @@ struct nxt_h1proto_s {
|
|||||||
nxt_conn_t *conn;
|
nxt_conn_t *conn;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define nxt_h1p_is_http11(h1p) \
|
||||||
|
((h1p)->parser.version.s.minor != '0')
|
||||||
|
|
||||||
#endif /* _NXT_H1PROTO_H_INCLUDED_ */
|
#endif /* _NXT_H1PROTO_H_INCLUDED_ */
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
|
|
||||||
#include <nxt_router.h>
|
#include <nxt_router.h>
|
||||||
#include <nxt_http.h>
|
#include <nxt_http.h>
|
||||||
|
#include <nxt_h1proto.h>
|
||||||
|
|
||||||
|
|
||||||
static nxt_int_t nxt_http_var_dollar(nxt_task_t *task, nxt_str_t *str,
|
static nxt_int_t nxt_http_var_dollar(nxt_task_t *task, nxt_str_t *str,
|
||||||
@@ -35,12 +36,20 @@ static nxt_int_t nxt_http_var_referer(nxt_task_t *task, nxt_str_t *str,
|
|||||||
void *ctx, void *data);
|
void *ctx, void *data);
|
||||||
static nxt_int_t nxt_http_var_user_agent(nxt_task_t *task, nxt_str_t *str,
|
static nxt_int_t nxt_http_var_user_agent(nxt_task_t *task, nxt_str_t *str,
|
||||||
void *ctx, void *data);
|
void *ctx, void *data);
|
||||||
|
static nxt_int_t nxt_http_var_response_connection(nxt_task_t *task,
|
||||||
|
nxt_str_t *str, void *ctx, void *data);
|
||||||
|
static nxt_int_t nxt_http_var_response_content_length(nxt_task_t *task,
|
||||||
|
nxt_str_t *str, void *ctx, void *data);
|
||||||
|
static nxt_int_t nxt_http_var_response_transfer_encoding(nxt_task_t *task,
|
||||||
|
nxt_str_t *str, void *ctx, void *data);
|
||||||
static nxt_int_t nxt_http_var_arg(nxt_task_t *task, nxt_str_t *str, void *ctx,
|
static nxt_int_t nxt_http_var_arg(nxt_task_t *task, nxt_str_t *str, void *ctx,
|
||||||
void *data);
|
void *data);
|
||||||
static nxt_int_t nxt_http_var_header(nxt_task_t *task, nxt_str_t *str,
|
static nxt_int_t nxt_http_var_header(nxt_task_t *task, nxt_str_t *str,
|
||||||
void *ctx, void *data);
|
void *ctx, void *data);
|
||||||
static nxt_int_t nxt_http_var_cookie(nxt_task_t *task, nxt_str_t *str,
|
static nxt_int_t nxt_http_var_cookie(nxt_task_t *task, nxt_str_t *str,
|
||||||
void *ctx, void *data);
|
void *ctx, void *data);
|
||||||
|
static nxt_int_t nxt_http_var_response_header(nxt_task_t *task, nxt_str_t *str,
|
||||||
|
void *ctx, void *data);
|
||||||
|
|
||||||
|
|
||||||
static nxt_var_decl_t nxt_http_vars[] = {
|
static nxt_var_decl_t nxt_http_vars[] = {
|
||||||
@@ -92,6 +101,18 @@ static nxt_var_decl_t nxt_http_vars[] = {
|
|||||||
.name = nxt_string("header_referer"),
|
.name = nxt_string("header_referer"),
|
||||||
.handler = nxt_http_var_referer,
|
.handler = nxt_http_var_referer,
|
||||||
.cacheable = 1,
|
.cacheable = 1,
|
||||||
|
}, {
|
||||||
|
.name = nxt_string("response_header_connection"),
|
||||||
|
.handler = nxt_http_var_response_connection,
|
||||||
|
.cacheable = 1,
|
||||||
|
}, {
|
||||||
|
.name = nxt_string("response_header_content_length"),
|
||||||
|
.handler = nxt_http_var_response_content_length,
|
||||||
|
.cacheable = 1,
|
||||||
|
}, {
|
||||||
|
.name = nxt_string("response_header_transfer_encoding"),
|
||||||
|
.handler = nxt_http_var_response_transfer_encoding,
|
||||||
|
.cacheable = 1,
|
||||||
}, {
|
}, {
|
||||||
.name = nxt_string("header_user_agent"),
|
.name = nxt_string("header_user_agent"),
|
||||||
.handler = nxt_http_var_user_agent,
|
.handler = nxt_http_var_user_agent,
|
||||||
@@ -112,7 +133,30 @@ nxt_http_unknown_var_ref(nxt_tstr_state_t *state, nxt_var_ref_t *ref,
|
|||||||
nxt_str_t *name)
|
nxt_str_t *name)
|
||||||
{
|
{
|
||||||
int64_t hash;
|
int64_t hash;
|
||||||
nxt_str_t str;
|
nxt_str_t str, *lower;
|
||||||
|
|
||||||
|
if (nxt_str_start(name, "response_header_", 16)) {
|
||||||
|
ref->handler = nxt_http_var_response_header;
|
||||||
|
ref->cacheable = 1;
|
||||||
|
|
||||||
|
str.start = name->start + 16;
|
||||||
|
str.length = name->length - 16;
|
||||||
|
|
||||||
|
if (str.length == 0) {
|
||||||
|
return NXT_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
lower = nxt_str_alloc(state->pool, str.length);
|
||||||
|
if (nxt_slow_path(lower == NULL)) {
|
||||||
|
return NXT_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
nxt_memcpy_lowcase(lower->start, str.start, str.length);
|
||||||
|
|
||||||
|
ref->data = lower;
|
||||||
|
|
||||||
|
return NXT_OK;
|
||||||
|
}
|
||||||
|
|
||||||
if (nxt_str_start(name, "header_", 7)) {
|
if (nxt_str_start(name, "header_", 7)) {
|
||||||
ref->handler = nxt_http_var_header;
|
ref->handler = nxt_http_var_header;
|
||||||
@@ -355,6 +399,7 @@ static nxt_int_t
|
|||||||
nxt_http_var_body_bytes_sent(nxt_task_t *task, nxt_str_t *str, void *ctx,
|
nxt_http_var_body_bytes_sent(nxt_task_t *task, nxt_str_t *str, void *ctx,
|
||||||
void *data)
|
void *data)
|
||||||
{
|
{
|
||||||
|
u_char *p;
|
||||||
nxt_off_t bytes;
|
nxt_off_t bytes;
|
||||||
nxt_http_request_t *r;
|
nxt_http_request_t *r;
|
||||||
|
|
||||||
@@ -367,8 +412,9 @@ nxt_http_var_body_bytes_sent(nxt_task_t *task, nxt_str_t *str, void *ctx,
|
|||||||
|
|
||||||
bytes = nxt_http_proto[r->protocol].body_bytes_sent(task, r->proto);
|
bytes = nxt_http_proto[r->protocol].body_bytes_sent(task, r->proto);
|
||||||
|
|
||||||
str->length = nxt_sprintf(str->start, str->start + NXT_OFF_T_LEN, "%O",
|
p = nxt_sprintf(str->start, str->start + NXT_OFF_T_LEN, "%O", bytes);
|
||||||
bytes) - str->start;
|
|
||||||
|
str->length = p - str->start;
|
||||||
|
|
||||||
return NXT_OK;
|
return NXT_OK;
|
||||||
}
|
}
|
||||||
@@ -377,6 +423,7 @@ nxt_http_var_body_bytes_sent(nxt_task_t *task, nxt_str_t *str, void *ctx,
|
|||||||
static nxt_int_t
|
static nxt_int_t
|
||||||
nxt_http_var_status(nxt_task_t *task, nxt_str_t *str, void *ctx, void *data)
|
nxt_http_var_status(nxt_task_t *task, nxt_str_t *str, void *ctx, void *data)
|
||||||
{
|
{
|
||||||
|
u_char *p;
|
||||||
nxt_http_request_t *r;
|
nxt_http_request_t *r;
|
||||||
|
|
||||||
r = ctx;
|
r = ctx;
|
||||||
@@ -386,8 +433,9 @@ nxt_http_var_status(nxt_task_t *task, nxt_str_t *str, void *ctx, void *data)
|
|||||||
return NXT_ERROR;
|
return NXT_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
str->length = nxt_sprintf(str->start, str->start + 3, "%03d", r->status)
|
p = nxt_sprintf(str->start, str->start + 3, "%03d", r->status);
|
||||||
- str->start;
|
|
||||||
|
str->length = p - str->start;
|
||||||
|
|
||||||
return NXT_OK;
|
return NXT_OK;
|
||||||
}
|
}
|
||||||
@@ -431,6 +479,103 @@ nxt_http_var_user_agent(nxt_task_t *task, nxt_str_t *str, void *ctx, void *data)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static nxt_int_t
|
||||||
|
nxt_http_var_response_connection(nxt_task_t *task, nxt_str_t *str, void *ctx,
|
||||||
|
void *data)
|
||||||
|
{
|
||||||
|
nxt_int_t conn;
|
||||||
|
nxt_bool_t http11;
|
||||||
|
nxt_h1proto_t *h1p;
|
||||||
|
nxt_http_request_t *r;
|
||||||
|
|
||||||
|
static const nxt_str_t connection[3] = {
|
||||||
|
nxt_string("close"),
|
||||||
|
nxt_string("keep-alive"),
|
||||||
|
nxt_string("Upgrade"),
|
||||||
|
};
|
||||||
|
|
||||||
|
r = ctx;
|
||||||
|
h1p = r->proto.h1;
|
||||||
|
|
||||||
|
conn = -1;
|
||||||
|
|
||||||
|
if (r->websocket_handshake && r->status == NXT_HTTP_SWITCHING_PROTOCOLS) {
|
||||||
|
conn = 2;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
http11 = nxt_h1p_is_http11(h1p);
|
||||||
|
|
||||||
|
if (http11 ^ h1p->keepalive) {
|
||||||
|
conn = h1p->keepalive;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (conn >= 0) {
|
||||||
|
*str = connection[conn];
|
||||||
|
|
||||||
|
} else {
|
||||||
|
nxt_str_null(str);
|
||||||
|
}
|
||||||
|
|
||||||
|
return NXT_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static nxt_int_t
|
||||||
|
nxt_http_var_response_content_length(nxt_task_t *task, nxt_str_t *str,
|
||||||
|
void *ctx, void *data)
|
||||||
|
{
|
||||||
|
u_char *p;
|
||||||
|
nxt_http_request_t *r;
|
||||||
|
|
||||||
|
r = ctx;
|
||||||
|
|
||||||
|
if (r->resp.content_length != NULL) {
|
||||||
|
str->length = r->resp.content_length->value_length;
|
||||||
|
str->start = r->resp.content_length->value;
|
||||||
|
|
||||||
|
return NXT_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (r->resp.content_length_n >= 0) {
|
||||||
|
str->start = nxt_mp_nget(r->mem_pool, NXT_OFF_T_LEN);
|
||||||
|
if (str->start == NULL) {
|
||||||
|
return NXT_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
p = nxt_sprintf(str->start, str->start + NXT_OFF_T_LEN,
|
||||||
|
"%O", r->resp.content_length_n);
|
||||||
|
|
||||||
|
str->length = p - str->start;
|
||||||
|
|
||||||
|
return NXT_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
nxt_str_null(str);
|
||||||
|
|
||||||
|
return NXT_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static nxt_int_t
|
||||||
|
nxt_http_var_response_transfer_encoding(nxt_task_t *task, nxt_str_t *str,
|
||||||
|
void *ctx, void *data)
|
||||||
|
{
|
||||||
|
nxt_http_request_t *r;
|
||||||
|
|
||||||
|
r = ctx;
|
||||||
|
|
||||||
|
if (r->proto.h1->chunked) {
|
||||||
|
nxt_str_set(str, "chunked");
|
||||||
|
|
||||||
|
} else {
|
||||||
|
nxt_str_null(str);
|
||||||
|
}
|
||||||
|
|
||||||
|
return NXT_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static nxt_int_t
|
static nxt_int_t
|
||||||
nxt_http_var_arg(nxt_task_t *task, nxt_str_t *str, void *ctx, void *data)
|
nxt_http_var_arg(nxt_task_t *task, nxt_str_t *str, void *ctx, void *data)
|
||||||
{
|
{
|
||||||
@@ -539,3 +684,65 @@ nxt_http_var_cookie(nxt_task_t *task, nxt_str_t *str, void *ctx, void *data)
|
|||||||
|
|
||||||
return NXT_OK;
|
return NXT_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int
|
||||||
|
nxt_http_field_name_cmp(nxt_str_t *name, nxt_http_field_t *field)
|
||||||
|
{
|
||||||
|
size_t i;
|
||||||
|
u_char c1, c2;
|
||||||
|
|
||||||
|
if (name->length != field->name_length) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < name->length; i++) {
|
||||||
|
c1 = name->start[i];
|
||||||
|
c2 = field->name[i];
|
||||||
|
|
||||||
|
if (c2 >= 'A' && c2 <= 'Z') {
|
||||||
|
c2 |= 0x20;
|
||||||
|
|
||||||
|
} else if (c2 == '-') {
|
||||||
|
c2 = '_';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c1 != c2) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static nxt_int_t
|
||||||
|
nxt_http_var_response_header(nxt_task_t *task, nxt_str_t *str, void *ctx,
|
||||||
|
void *data)
|
||||||
|
{
|
||||||
|
nxt_str_t *name;
|
||||||
|
nxt_http_field_t *f;
|
||||||
|
nxt_http_request_t *r;
|
||||||
|
|
||||||
|
r = ctx;
|
||||||
|
name = data;
|
||||||
|
|
||||||
|
nxt_list_each(f, r->resp.fields) {
|
||||||
|
|
||||||
|
if (f->skip) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nxt_http_field_name_cmp(name, f) == 0) {
|
||||||
|
str->start = f->value;
|
||||||
|
str->length = f->value_length;
|
||||||
|
|
||||||
|
return NXT_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
} nxt_list_loop;
|
||||||
|
|
||||||
|
nxt_str_null(str);
|
||||||
|
|
||||||
|
return NXT_OK;
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user