[njs] HTTP: improved getting of multi-valued headers in r.headersIn.
Dmitry Volyntsev
xeioex at nginx.com
Thu Apr 30 09:43:05 UTC 2020
details: https://hg.nginx.org/njs/rev/f35440bf511f
branches:
changeset: 1383:f35440bf511f
user: Dmitry Volyntsev <xeioex at nginx.com>
date: Wed Apr 29 11:57:11 2020 +0000
description:
HTTP: improved getting of multi-valued headers in r.headersIn.
1) Duplicates of Content-Type, ETag, From, Max-Forwards, Referer,
Proxy-Authorization, User-Agent are ignored.
2) Duplicate Cookie headers are joined together with ';'.
3) All other duplicate header values are joined together with ','.
diffstat:
nginx/ngx_http_js_module.c | 284 ++++++++++++++++++++++++++++----------------
1 files changed, 180 insertions(+), 104 deletions(-)
diffs (363 lines):
diff -r 95fba9d4686f -r f35440bf511f nginx/ngx_http_js_module.c
--- a/nginx/ngx_http_js_module.c Wed Apr 29 11:57:10 2020 +0000
+++ b/nginx/ngx_http_js_module.c Wed Apr 29 11:57:11 2020 +0000
@@ -136,6 +136,22 @@ static njs_int_t ngx_http_js_ext_get_req
static njs_int_t ngx_http_js_ext_get_header_in(njs_vm_t *vm,
njs_object_prop_t *prop, njs_value_t *value, njs_value_t *setval,
njs_value_t *retval);
+static njs_int_t ngx_http_js_header_in_cookie(njs_vm_t *vm,
+ ngx_http_request_t *r, njs_str_t *name, njs_value_t *setval,
+ njs_value_t *retval);
+#if (NGX_HTTP_X_FORWARDED_FOR)
+static njs_int_t ngx_http_js_header_in_x_forwarded_for(njs_vm_t *vm,
+ ngx_http_request_t *r, njs_str_t *name, njs_value_t *setval,
+ njs_value_t *retval);
+#endif
+static njs_int_t ngx_http_js_header_in_array(njs_vm_t *vm,
+ ngx_http_request_t *r, ngx_array_t *array, u_char sep, njs_value_t *retval);
+static njs_int_t ngx_http_js_header_in_single(njs_vm_t *vm,
+ ngx_http_request_t *r, njs_str_t *name, njs_value_t *setval,
+ njs_value_t *retval);
+static njs_int_t ngx_http_js_header_in_generic(njs_vm_t *vm,
+ ngx_http_request_t *r, njs_str_t *name, njs_value_t *setval,
+ njs_value_t *retval);
static njs_int_t ngx_http_js_ext_keys_header_in(njs_vm_t *vm,
njs_value_t *value, njs_value_t *keys);
static njs_int_t ngx_http_js_ext_get_arg(njs_vm_t *vm,
@@ -922,6 +938,75 @@ ngx_http_js_get_header(ngx_list_part_t *
static njs_int_t
+ngx_http_js_return_header(njs_vm_t *vm, ngx_http_request_t *r,
+ ngx_list_part_t *part, njs_str_t *name, njs_value_t *retval)
+{
+ size_t len;
+ u_char *data, *p, *start, *end;
+ ngx_uint_t i;
+ ngx_table_elt_t *header, *h;
+
+ header = part->elts;
+
+ p = NULL;
+ start = NULL;
+ end = NULL;
+
+ for (i = 0; /* void */ ; i++) {
+
+ if (i >= part->nelts) {
+ if (part->next == NULL) {
+ break;
+ }
+
+ part = part->next;
+ header = part->elts;
+ i = 0;
+ }
+
+ h = &header[i];
+
+ if (h->hash == 0
+ || h->key.len != name->length
+ || ngx_strncasecmp(h->key.data, name->start, name->length) != 0)
+ {
+ continue;
+ }
+
+ if (p == NULL) {
+ start = h->value.data;
+ end = h->value.data + h->value.len;
+ p = end;
+ continue;
+ }
+
+ if (p + h->value.len + 1 > end) {
+ len = njs_max(p + h->value.len + 1 - start, 2 * (end - start));
+
+ data = ngx_pnalloc(r->pool, len);
+ if (data == NULL) {
+ return NJS_ERROR;
+ }
+
+ p = ngx_cpymem(data, start, p - start);
+ start = data;
+ end = data + len;
+ }
+
+ *p++ = ',';
+ p = ngx_cpymem(p, h->value.data, h->value.len);
+ }
+
+ if (p == NULL) {
+ njs_value_undefined_set(retval);
+ return NJS_DECLINED;
+ }
+
+ return njs_vm_value_string_set(vm, retval, start, p - start);
+}
+
+
+static njs_int_t
ngx_http_js_ext_header_out(njs_vm_t *vm, njs_object_prop_t *prop,
njs_value_t *value, njs_value_t *setval, njs_value_t *retval)
{
@@ -1147,8 +1232,7 @@ static njs_int_t
ngx_http_js_header_out_generic(njs_vm_t *vm, ngx_http_request_t *r,
njs_str_t *name, njs_value_t *setval, njs_value_t *retval)
{
- size_t len;
- u_char *data, *p, *start, *end;
+ u_char *p;
int64_t length;
njs_value_t *array;
njs_int_t rc;
@@ -1163,63 +1247,7 @@ ngx_http_js_header_out_generic(njs_vm_t
part = &headers->part;
if (retval != NULL && setval == NULL) {
- header = part->elts;
-
- p = NULL;
- start = NULL;
- end = NULL;
-
- for (i = 0; /* void */ ; i++) {
-
- if (i >= part->nelts) {
- if (part->next == NULL) {
- break;
- }
-
- part = part->next;
- header = part->elts;
- i = 0;
- }
-
- h = &header[i];
-
- if (h->hash == 0
- || h->key.len != name->length
- || ngx_strncasecmp(h->key.data, name->start, name->length) != 0)
- {
- continue;
- }
-
- if (p == NULL) {
- start = h->value.data;
- end = h->value.data + h->value.len;
- p = end;
- continue;
- }
-
- if (p + h->value.len + 1 > end) {
- len = njs_max(p + h->value.len + 1 - start, 2 * (end - start));
-
- data = ngx_pnalloc(r->pool, len);
- if (data == NULL) {
- return NJS_ERROR;
- }
-
- p = ngx_cpymem(data, start, p - start);
- start = data;
- end = data + len;
- }
-
- *p++ = ',';
- p = ngx_cpymem(p, h->value.data, h->value.len);
- }
-
- if (p == NULL) {
- njs_value_undefined_set(retval);
- return NJS_DECLINED;
- }
-
- return njs_vm_value_string_set(vm, retval, start, p - start);
+ return ngx_http_js_return_header(vm, r, part, name, retval);
}
header = part->elts;
@@ -1903,69 +1931,92 @@ static njs_int_t
ngx_http_js_ext_get_header_in(njs_vm_t *vm, njs_object_prop_t *prop,
njs_value_t *value, njs_value_t *setval, njs_value_t *retval)
{
- u_char *p, *end, sep;
- size_t len;
- njs_int_t rc;
- njs_str_t *v, name;
- ngx_uint_t i, n;
- ngx_array_t *a;
- ngx_table_elt_t *h, **hh;
- ngx_http_request_t *r;
+ njs_int_t rc;
+ njs_str_t name;
+ ngx_http_request_t *r;
+ ngx_http_js_header_t *h;
+
+ static ngx_http_js_header_t headers_in[] = {
+ { njs_str("Content-Type"), ngx_http_js_header_in_single },
+ { njs_str("Cookie"), ngx_http_js_header_in_cookie },
+ { njs_str("ETag"), ngx_http_js_header_in_single },
+ { njs_str("From"), ngx_http_js_header_in_single },
+ { njs_str("Max-Forwards"), ngx_http_js_header_in_single },
+ { njs_str("Referer"), ngx_http_js_header_in_single },
+ { njs_str("Proxy-Authorization"), ngx_http_js_header_in_single },
+ { njs_str("User-Agent"), ngx_http_js_header_in_single },
+#if (NGX_HTTP_X_FORWARDED_FOR)
+ { njs_str("X-Forwarded-For"), ngx_http_js_header_in_x_forwarded_for },
+#endif
+ { njs_str(""), ngx_http_js_header_in_generic },
+ };
r = njs_vm_external(vm, value);
if (r == NULL) {
- njs_value_undefined_set(retval);
+ if (retval != NULL) {
+ njs_value_undefined_set(retval);
+ }
+
return NJS_DECLINED;
}
rc = njs_vm_prop_name(vm, prop, &name);
if (rc != NJS_OK) {
- njs_value_undefined_set(retval);
+ if (retval != NULL) {
+ njs_value_undefined_set(retval);
+ }
+
return NJS_DECLINED;
}
- v = &name;
-
- if (v->length == njs_length("Cookie")
- && ngx_strncasecmp(v->start, (u_char *) "Cookie",
- v->length) == 0)
- {
- sep = ';';
- a = &r->headers_in.cookies;
- goto multi;
+ for (h = headers_in; h->name.length > 0; h++) {
+ if (h->name.length == name.length
+ && ngx_strncasecmp(h->name.start, name.start, name.length) == 0)
+ {
+ break;
+ }
}
+ return h->handler(vm, r, &name, setval, retval);
+}
+
+
+static njs_int_t
+ngx_http_js_header_in_cookie(njs_vm_t *vm, ngx_http_request_t *r,
+ njs_str_t *name, njs_value_t *setval, njs_value_t *retval)
+{
+ return ngx_http_js_header_in_array(vm, r, &r->headers_in.cookies,
+ ';', retval);
+}
+
+
#if (NGX_HTTP_X_FORWARDED_FOR)
- if (v->length == njs_length("X-Forwarded-For")
- && ngx_strncasecmp(v->start, (u_char *) "X-Forwarded-For",
- v->length) == 0)
- {
- sep = ',';
- a = &r->headers_in.x_forwarded_for;
- goto multi;
- }
+static njs_int_t
+ngx_http_js_header_in_x_forwarded_for(njs_vm_t *vm, ngx_http_request_t *r,
+ njs_str_t *name, njs_value_t *setval, njs_value_t *retval)
+{
+ return ngx_http_js_header_in_array(vm, r, &r->headers_in.x_forwarded_for,
+ ',', retval);
+}
#endif
- h = ngx_http_js_get_header(&r->headers_in.headers.part, v->start,
- v->length);
- if (h == NULL) {
- njs_value_undefined_set(retval);
- return NJS_DECLINED;
- }
-
- return njs_vm_value_string_set(vm, retval, h->value.data, h->value.len);
-
-multi:
-
- /* Cookie, X-Forwarded-For */
-
- n = a->nelts;
- hh = a->elts;
+
+static njs_int_t
+ngx_http_js_header_in_array(njs_vm_t *vm, ngx_http_request_t *r,
+ ngx_array_t *array, u_char sep, njs_value_t *retval)
+{
+ u_char *p, *end;
+ size_t len;
+ ngx_uint_t i, n;
+ ngx_table_elt_t **hh;
+
+ n = array->nelts;
+ hh = array->elts;
len = 0;
for (i = 0; i < n; i++) {
- len += hh[i]->value.len + 2;
+ len += hh[i]->value.len + 1;
}
if (len == 0) {
@@ -1973,7 +2024,7 @@ multi:
return NJS_DECLINED;
}
- len -= 2;
+ len -= 1;
if (n == 1) {
return njs_vm_value_string_set(vm, retval, (*hh)->value.data,
@@ -1997,7 +2048,6 @@ multi:
}
*p++ = sep;
- *p++ = ' ';
}
return NJS_OK;
@@ -2005,6 +2055,32 @@ multi:
static njs_int_t
+ngx_http_js_header_in_single(njs_vm_t *vm, ngx_http_request_t *r,
+ njs_str_t *name, njs_value_t *setval, njs_value_t *retval)
+{
+ ngx_table_elt_t *h;
+
+ h = ngx_http_js_get_header(&r->headers_in.headers.part, name->start,
+ name->length);
+ if (h == NULL) {
+ njs_value_undefined_set(retval);
+ return NJS_DECLINED;
+ }
+
+ return njs_vm_value_string_set(vm, retval, h->value.data, h->value.len);
+}
+
+
+static njs_int_t
+ngx_http_js_header_in_generic(njs_vm_t *vm, ngx_http_request_t *r,
+ njs_str_t *name, njs_value_t *setval, njs_value_t *retval)
+{
+ return ngx_http_js_return_header(vm, r, &r->headers_in.headers.part, name,
+ retval);
+}
+
+
+static njs_int_t
ngx_http_js_ext_keys_header_in(njs_vm_t *vm, njs_value_t *value,
njs_value_t *keys)
{
More information about the nginx-devel
mailing list