summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorZhidao HONG <z.hong@f5.com>2023-07-01 12:18:22 +0800
committerZhidao HONG <z.hong@f5.com>2023-07-01 12:18:22 +0800
commit458722df55bb9727680b7734e7fff8fb5639db28 (patch)
tree6f1d628a50e94fd784eaebeefd3f049e3b475dcf
parentc61ccec7b4926476b2188092e25990e433332688 (diff)
downloadunit-458722df55bb9727680b7734e7fff8fb5639db28.tar.gz
unit-458722df55bb9727680b7734e7fff8fb5639db28.tar.bz2
Var: supported HTTP response header variables.
This commit adds the variable $response_header_NAME.
-rw-r--r--docs/changes.xml6
-rw-r--r--src/nxt_h1proto.c2
-rw-r--r--src/nxt_h1proto.h3
-rw-r--r--src/nxt_http_variables.c217
4 files changed, 222 insertions, 6 deletions
diff --git a/docs/changes.xml b/docs/changes.xml
index 2522b823..b2c70376 100644
--- a/docs/changes.xml
+++ b/docs/changes.xml
@@ -38,6 +38,12 @@ njs updated to 0.8.0.
</para>
</change>
+<change type="feature">
+<para>
+ability to get the HTTP response header variables.
+</para>
+</change>
+
<change type="bugfix">
<para>
ensure that $uri variable is not cached.
diff --git a/src/nxt_h1proto.c b/src/nxt_h1proto.c
index df1f82f9..1dfe4b6e 100644
--- a/src/nxt_h1proto.c
+++ b/src/nxt_h1proto.c
@@ -1284,7 +1284,7 @@ nxt_h1p_request_header_send(nxt_task_t *task, nxt_http_request_t *r,
size += NXT_WEBSOCKET_ACCEPT_SIZE + 2;
} 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) {
diff --git a/src/nxt_h1proto.h b/src/nxt_h1proto.h
index f8500963..b324db8d 100644
--- a/src/nxt_h1proto.h
+++ b/src/nxt_h1proto.h
@@ -51,4 +51,7 @@ struct nxt_h1proto_s {
nxt_conn_t *conn;
};
+#define nxt_h1p_is_http11(h1p) \
+ ((h1p)->parser.version.s.minor != '0')
+
#endif /* _NXT_H1PROTO_H_INCLUDED_ */
diff --git a/src/nxt_http_variables.c b/src/nxt_http_variables.c
index 04e21e67..04e24a4b 100644
--- a/src/nxt_http_variables.c
+++ b/src/nxt_http_variables.c
@@ -5,6 +5,7 @@
#include <nxt_router.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,
@@ -35,12 +36,20 @@ static nxt_int_t nxt_http_var_referer(nxt_task_t *task, nxt_str_t *str,
void *ctx, void *data);
static nxt_int_t 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);
+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,
void *data);
static nxt_int_t nxt_http_var_header(nxt_task_t *task, nxt_str_t *str,
void *ctx, void *data);
static nxt_int_t nxt_http_var_cookie(nxt_task_t *task, nxt_str_t *str,
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[] = {
@@ -93,6 +102,18 @@ static nxt_var_decl_t nxt_http_vars[] = {
.handler = nxt_http_var_referer,
.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"),
.handler = nxt_http_var_user_agent,
.cacheable = 1,
@@ -112,7 +133,30 @@ nxt_http_unknown_var_ref(nxt_tstr_state_t *state, nxt_var_ref_t *ref,
nxt_str_t *name)
{
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)) {
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,
void *data)
{
+ u_char *p;
nxt_off_t bytes;
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);
- str->length = nxt_sprintf(str->start, str->start + NXT_OFF_T_LEN, "%O",
- bytes) - str->start;
+ p = nxt_sprintf(str->start, str->start + NXT_OFF_T_LEN, "%O", bytes);
+
+ str->length = p - str->start;
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
nxt_http_var_status(nxt_task_t *task, nxt_str_t *str, void *ctx, void *data)
{
+ u_char *p;
nxt_http_request_t *r;
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;
}
- str->length = nxt_sprintf(str->start, str->start + 3, "%03d", r->status)
- - str->start;
+ p = nxt_sprintf(str->start, str->start + 3, "%03d", r->status);
+
+ str->length = p - str->start;
return NXT_OK;
}
@@ -432,6 +480,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
nxt_http_var_arg(nxt_task_t *task, nxt_str_t *str, void *ctx, void *data)
{
nxt_array_t *args;
@@ -539,3 +684,65 @@ nxt_http_var_cookie(nxt_task_t *task, nxt_str_t *str, void *ctx, void *data)
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;
+}