[njs] HTTP: adapting to changes in nginx header structures.
Dmitry Volyntsev
xeioex at nginx.com
Tue May 31 16:33:00 UTC 2022
details: https://hg.nginx.org/njs/rev/5b7676ec600d
branches:
changeset: 1868:5b7676ec600d
user: Dmitry Volyntsev <xeioex at nginx.com>
date: Tue May 31 09:26:47 2022 -0700
description:
HTTP: adapting to changes in nginx header structures.
diffstat:
nginx/ngx_http_js_module.c | 617 +++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 617 insertions(+), 0 deletions(-)
diffs (748 lines):
diff -r 6ccb060f328b -r 5b7676ec600d nginx/ngx_http_js_module.c
--- a/nginx/ngx_http_js_module.c Thu May 26 15:28:06 2022 +0400
+++ b/nginx/ngx_http_js_module.c Tue May 31 09:26:47 2022 -0700
@@ -12,6 +12,11 @@
#include "ngx_js.h"
+#define NJS_HEADER_SEMICOLON 0x1
+#define NJS_HEADER_SINGLE 0x2
+#define NJS_HEADER_ARRAY 0x4
+
+
typedef struct {
njs_vm_t *vm;
ngx_array_t *imports;
@@ -84,10 +89,17 @@ typedef struct {
typedef struct {
njs_str_t name;
+#if defined(nginx_version) && (nginx_version >= 1023000)
+ unsigned flags;
+ njs_int_t (*handler)(njs_vm_t *vm, ngx_http_request_t *r,
+ unsigned flags, njs_str_t *name,
+ njs_value_t *setval, njs_value_t *retval);
+#else
njs_int_t (*handler)(njs_vm_t *vm, ngx_http_request_t *r,
ngx_list_t *headers, njs_str_t *name,
njs_value_t *setval, njs_value_t *retval);
+#endif
} ngx_http_js_header_t;
@@ -107,14 +119,17 @@ static void ngx_http_js_cleanup_vm(void
static njs_int_t ngx_http_js_ext_keys_header(njs_vm_t *vm, njs_value_t *value,
njs_value_t *keys, ngx_list_t *headers);
+#if defined(nginx_version) && (nginx_version < 1023000)
static ngx_table_elt_t *ngx_http_js_get_header(ngx_list_part_t *part,
u_char *data, size_t len);
+#endif
static njs_int_t ngx_http_js_ext_raw_header(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_ext_header_out(njs_vm_t *vm,
njs_object_prop_t *prop, njs_value_t *value, njs_value_t *setval,
njs_value_t *retval);
+#if defined(nginx_version) && (nginx_version < 1023000)
static njs_int_t ngx_http_js_header_single(njs_vm_t *vm,
ngx_http_request_t *r, ngx_list_t *headers, njs_str_t *name,
njs_value_t *setval, njs_value_t *retval);
@@ -136,6 +151,7 @@ static njs_int_t ngx_http_js_content_enc
static njs_int_t ngx_http_js_content_type(njs_vm_t *vm, ngx_http_request_t *r,
ngx_list_t *headers, njs_str_t *name, njs_value_t *setval,
njs_value_t *retval);
+#endif
static njs_int_t ngx_http_js_ext_keys_header_out(njs_vm_t *vm,
njs_value_t *value, njs_value_t *keys);
static njs_int_t ngx_http_js_ext_status(njs_vm_t *vm, njs_object_prop_t *prop,
@@ -169,6 +185,7 @@ static njs_int_t ngx_http_js_ext_get_req
static njs_int_t ngx_http_js_ext_header_in(njs_vm_t *vm,
njs_object_prop_t *prop, njs_value_t *value, njs_value_t *setval,
njs_value_t *retval);
+#if defined(nginx_version) && (nginx_version < 1023000)
static njs_int_t ngx_http_js_header_cookie(njs_vm_t *vm,
ngx_http_request_t *r, ngx_list_t *headers, njs_str_t *name,
njs_value_t *setval, njs_value_t *retval);
@@ -179,6 +196,7 @@ static njs_int_t ngx_http_js_header_x_fo
#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);
+#endif
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,
@@ -203,6 +221,28 @@ static njs_int_t ngx_http_js_ext_get_res
njs_object_prop_t *prop, njs_value_t *value, njs_value_t *setval,
njs_value_t *retval);
+#if defined(nginx_version) && (nginx_version >= 1023000)
+static njs_int_t ngx_http_js_header_in(njs_vm_t *vm, ngx_http_request_t *r,
+ unsigned flags, njs_str_t *name, njs_value_t *retval);
+static njs_int_t ngx_http_js_header_out(njs_vm_t *vm, ngx_http_request_t *r,
+ unsigned flags, njs_str_t *name, njs_value_t *setval, njs_value_t *retval);
+static njs_int_t ngx_http_js_content_encoding(njs_vm_t *vm,
+ ngx_http_request_t *r, unsigned flags, njs_str_t *name,
+ njs_value_t *setval, njs_value_t *retval);
+static njs_int_t ngx_http_js_content_length(njs_vm_t *vm, ngx_http_request_t *r,
+ unsigned flags, njs_str_t *name, njs_value_t *setval,
+ njs_value_t *retval);
+static njs_int_t ngx_http_js_content_type(njs_vm_t *vm, ngx_http_request_t *r,
+ unsigned flags, njs_str_t *name, njs_value_t *setval,
+ njs_value_t *retval);
+static njs_int_t ngx_http_js_header_out_special(njs_vm_t *vm,
+ ngx_http_request_t *r, njs_str_t *v, njs_value_t *setval,
+ njs_value_t *retval, ngx_table_elt_t **hh);
+static njs_int_t ngx_http_js_header_generic(njs_vm_t *vm,
+ ngx_http_request_t *r, ngx_list_t *headers, ngx_table_elt_t **ph,
+ unsigned flags, njs_str_t *name, njs_value_t *retval);
+#endif
+
static njs_host_event_t ngx_http_js_set_timer(njs_external_ptr_t external,
uint64_t delay, njs_vm_event_t vm_event);
static void ngx_http_js_clear_timer(njs_external_ptr_t external,
@@ -1319,6 +1359,7 @@ ngx_http_js_ext_keys_header(njs_vm_t *vm
}
+#if defined(nginx_version) && (nginx_version < 1023000)
static ngx_table_elt_t *
ngx_http_js_get_header(ngx_list_part_t *part, u_char *data, size_t len)
{
@@ -1352,6 +1393,7 @@ ngx_http_js_get_header(ngx_list_part_t *
return NULL;
}
+#endif
static njs_int_t
@@ -1446,6 +1488,7 @@ ngx_http_js_ext_header_out(njs_vm_t *vm,
ngx_http_js_header_t *h;
static ngx_http_js_header_t headers_out[] = {
+#if defined(nginx_version) && (nginx_version < 1023000)
{ njs_str("Age"), ngx_http_js_header_single },
{ njs_str("Content-Type"), ngx_http_js_content_type },
{ njs_str("Content-Length"), ngx_http_js_content_length },
@@ -1457,6 +1500,19 @@ ngx_http_js_ext_header_out(njs_vm_t *vm,
{ njs_str("Set-Cookie"), ngx_http_js_header_array },
{ njs_str("Retry-After"), ngx_http_js_header_single },
{ njs_str(""), ngx_http_js_header_generic },
+#else
+ { njs_str("Age"), NJS_HEADER_SINGLE, ngx_http_js_header_out },
+ { njs_str("Content-Encoding"), 0, ngx_http_js_content_encoding },
+ { njs_str("Content-Length"), 0, ngx_http_js_content_length },
+ { njs_str("Content-Type"), 0, ngx_http_js_content_type },
+ { njs_str("Etag"), NJS_HEADER_SINGLE, ngx_http_js_header_out },
+ { njs_str("Expires"), NJS_HEADER_SINGLE, ngx_http_js_header_out },
+ { njs_str("Last-Modified"), NJS_HEADER_SINGLE, ngx_http_js_header_out },
+ { njs_str("Location"), NJS_HEADER_SINGLE, ngx_http_js_header_out },
+ { njs_str("Set-Cookie"), NJS_HEADER_ARRAY, ngx_http_js_header_out },
+ { njs_str("Retry-After"), NJS_HEADER_SINGLE, ngx_http_js_header_out },
+ { njs_str(""), 0, ngx_http_js_header_out },
+#endif
};
r = njs_vm_external(vm, ngx_http_js_request_proto_id, value);
@@ -1485,10 +1541,15 @@ ngx_http_js_ext_header_out(njs_vm_t *vm,
}
}
+#if defined(nginx_version) && (nginx_version < 1023000)
return h->handler(vm, r, &r->headers_out.headers, &name, setval, retval);
+#else
+ return h->handler(vm, r, h->flags, &name, setval, retval);
+#endif
}
+#if defined(nginx_version) && (nginx_version < 1023000)
static njs_int_t
ngx_http_js_header_single(njs_vm_t *vm, ngx_http_request_t *r,
ngx_list_t *headers, njs_str_t *name, njs_value_t *setval,
@@ -1940,6 +2001,7 @@ ngx_http_js_content_type(njs_vm_t *vm, n
return NJS_OK;
}
+#endif
static njs_int_t
@@ -2545,6 +2607,7 @@ done:
}
+#if defined(nginx_version) && (nginx_version < 1023000)
static njs_int_t
ngx_http_js_ext_header_in(njs_vm_t *vm, njs_object_prop_t *prop,
njs_value_t *value, njs_value_t *setval, njs_value_t *retval)
@@ -2672,6 +2735,59 @@ ngx_http_js_header_in_array(njs_vm_t *vm
return NJS_OK;
}
+#else
+static njs_int_t
+ngx_http_js_ext_header_in(njs_vm_t *vm, njs_object_prop_t *prop,
+ njs_value_t *value, njs_value_t *unused, njs_value_t *retval)
+{
+ unsigned flags;
+ njs_int_t rc;
+ njs_str_t name, *h;
+ ngx_http_request_t *r;
+
+ static njs_str_t single_headers_in[] = {
+ njs_str("Content-Type"),
+ njs_str("ETag"),
+ njs_str("From"),
+ njs_str("Max-Forwards"),
+ njs_str("Referer"),
+ njs_str("Proxy-Authorization"),
+ njs_str("User-Agent"),
+ njs_str(""),
+ };
+
+ r = njs_vm_external(vm, ngx_http_js_request_proto_id, value);
+ if (r == NULL) {
+ if (retval != NULL) {
+ njs_value_undefined_set(retval);
+ }
+
+ return NJS_DECLINED;
+ }
+
+ rc = njs_vm_prop_name(vm, prop, &name);
+ if (rc != NJS_OK) {
+ if (retval != NULL) {
+ njs_value_undefined_set(retval);
+ }
+
+ return NJS_DECLINED;
+ }
+
+ flags = 0;
+
+ for (h = single_headers_in; h->length > 0; h++) {
+ if (h->length == name.length
+ && ngx_strncasecmp(h->start, name.start, name.length) == 0)
+ {
+ flags |= NJS_HEADER_SINGLE;
+ break;
+ }
+ }
+
+ return ngx_http_js_header_in(vm, r, flags, &name, retval);
+}
+#endif
static njs_int_t
@@ -3392,6 +3508,507 @@ ngx_http_js_ext_get_response_body(njs_vm
}
+#if defined(nginx_version) && (nginx_version >= 1023000)
+static njs_int_t
+ngx_http_js_header_in(njs_vm_t *vm, ngx_http_request_t *r, unsigned flags,
+ njs_str_t *name, njs_value_t *retval)
+{
+ u_char *lowcase_key;
+ ngx_uint_t hash;
+ ngx_table_elt_t **ph;
+ ngx_http_header_t *hh;
+ ngx_http_core_main_conf_t *cmcf;
+
+ if (retval == NULL) {
+ return NJS_OK;
+ }
+
+ /* look up hashed headers */
+
+ lowcase_key = ngx_pnalloc(r->pool, name->length);
+ if (lowcase_key == NULL) {
+ njs_vm_memory_error(vm);
+ return NJS_ERROR;
+ }
+
+ hash = ngx_hash_strlow(lowcase_key, name->start, name->length);
+
+ cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module);
+
+ hh = ngx_hash_find(&cmcf->headers_in_hash, hash, lowcase_key,
+ name->length);
+
+ ph = NULL;
+
+ if (hh) {
+ if (hh->offset == offsetof(ngx_http_headers_in_t, cookie)) {
+ flags |= NJS_HEADER_SEMICOLON;
+ }
+
+ ph = (ngx_table_elt_t **) ((char *) &r->headers_in + hh->offset);
+ }
+
+ return ngx_http_js_header_generic(vm, r, &r->headers_in.headers, ph, flags,
+ name, retval);
+}
+
+
+static njs_int_t
+ngx_http_js_header_out(njs_vm_t *vm, ngx_http_request_t *r, unsigned flags,
+ njs_str_t *name, njs_value_t *setval, njs_value_t *retval)
+{
+ u_char *p;
+ int64_t length;
+ njs_value_t *array;
+ njs_int_t rc;
+ njs_str_t s;
+ ngx_uint_t i;
+ ngx_list_part_t *part;
+ ngx_table_elt_t *header, *h, **ph;
+ njs_opaque_value_t lvalue;
+
+ if (retval != NULL && setval == NULL) {
+ return ngx_http_js_header_generic(vm, r, &r->headers_out.headers, NULL,
+ flags, name, retval);
+
+ }
+
+ part = &r->headers_out.headers.part;
+ header = part->elts;
+
+ 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;
+ }
+
+ h->hash = 0;
+ h->next = NULL;
+ }
+
+ if (retval == NULL) {
+ return NJS_OK;
+ }
+
+ if (njs_value_is_array(setval)) {
+ array = setval;
+
+ rc = njs_vm_array_length(vm, array, &length);
+ if (rc != NJS_OK) {
+ return NJS_ERROR;
+ }
+
+ if (length == 0) {
+ return NJS_OK;
+ }
+
+ } else {
+ array = NULL;
+ length = 1;
+ }
+
+ ph = &header;
+
+ for (i = 0; i < (ngx_uint_t) length; i++) {
+ if (array != NULL) {
+ setval = njs_vm_array_prop(vm, array, i, &lvalue);
+ }
+
+ if (ngx_js_string(vm, setval, &s) != NGX_OK) {
+ return NJS_ERROR;
+ }
+
+ if (s.length == 0) {
+ continue;
+ }
+
+ h = ngx_list_push(&r->headers_out.headers);
+ if (h == NULL) {
+ njs_vm_memory_error(vm);
+ return NJS_ERROR;
+ }
+
+ p = ngx_pnalloc(r->pool, name->length);
+ if (p == NULL) {
+ h->hash = 0;
+ njs_vm_memory_error(vm);
+ return NJS_ERROR;
+ }
+
+ ngx_memcpy(p, name->start, name->length);
+
+ h->key.data = p;
+ h->key.len = name->length;
+
+ p = ngx_pnalloc(r->pool, s.length);
+ if (p == NULL) {
+ h->hash = 0;
+ njs_vm_memory_error(vm);
+ return NJS_ERROR;
+ }
+
+ ngx_memcpy(p, s.start, s.length);
+
+ h->value.data = p;
+ h->value.len = s.length;
+ h->hash = 1;
+
+ *ph = h;
+ ph = &h->next;
+ }
+
+ *ph = NULL;
+
+ return NJS_OK;
+}
+
+
+static njs_int_t
+ngx_http_js_content_encoding(njs_vm_t *vm, ngx_http_request_t *r,
+ unsigned flags, njs_str_t *v, njs_value_t *setval, njs_value_t *retval)
+{
+ njs_int_t rc;
+ ngx_table_elt_t *h;
+
+ rc = ngx_http_js_header_out_special(vm, r, v, setval, retval, &h);
+ if (rc != NJS_OK) {
+ return NJS_ERROR;
+ }
+
+ if (setval != NULL || retval == NULL) {
+ r->headers_out.content_encoding = h;
+ }
+
+ return NJS_OK;
+}
+
+
+static njs_int_t
+ngx_http_js_content_length(njs_vm_t *vm, ngx_http_request_t *r,
+ unsigned flags, njs_str_t *v, njs_value_t *setval, njs_value_t *retval)
+{
+ u_char *p, *start;
+ njs_int_t rc;
+ ngx_int_t n;
+ ngx_table_elt_t *h;
+ u_char content_len[NGX_OFF_T_LEN];
+
+ if (retval != NULL && setval == NULL) {
+ if (r->headers_out.content_length == NULL
+ && r->headers_out.content_length_n >= 0)
+ {
+ p = ngx_sprintf(content_len, "%O", r->headers_out.content_length_n);
+
+ start = njs_vm_value_string_alloc(vm, retval, p - content_len);
+ if (start == NULL) {
+ return NJS_ERROR;
+ }
+
+ ngx_memcpy(start, content_len, p - content_len);
+
+ return NJS_OK;
+ }
+ }
+
+ rc = ngx_http_js_header_out_special(vm, r, v, setval, retval, &h);
+ if (rc != NJS_OK) {
+ return NJS_ERROR;
+ }
+
+ if (setval != NULL || retval == NULL) {
+ if (h != NULL) {
+ n = ngx_atoi(h->value.data, h->value.len);
+ if (n == NGX_ERROR) {
+ h->hash = 0;
+ njs_vm_error(vm, "failed converting argument "
+ "to positive integer");
+ return NJS_ERROR;
+ }
+
+ r->headers_out.content_length = h;
+ r->headers_out.content_length_n = n;
+
+ } else {
+ ngx_http_clear_content_length(r);
+ }
+ }
+
+ return NJS_OK;
+}
+
+
+static njs_int_t
+ngx_http_js_content_type(njs_vm_t *vm, ngx_http_request_t *r,
+ unsigned flags, njs_str_t *v, njs_value_t *setval, njs_value_t *retval)
+{
+ int64_t length;
+ njs_int_t rc;
+ njs_str_t s;
+ ngx_str_t *hdr;
+ njs_opaque_value_t lvalue;
+
+ if (retval != NULL && setval == NULL) {
+ hdr = &r->headers_out.content_type;
+ return njs_vm_value_string_set(vm, retval, hdr->data, hdr->len);
+ }
+
+ if (setval != NULL && njs_value_is_array(setval)) {
+ rc = njs_vm_array_length(vm, setval, &length);
+ if (rc != NJS_OK) {
+ return NJS_ERROR;
+ }
+
+ setval = njs_vm_array_prop(vm, setval, length - 1, &lvalue);
+ }
+
+ if (ngx_js_string(vm, setval, &s) != NGX_OK) {
+ return NJS_ERROR;
+ }
+
+ r->headers_out.content_type.len = s.length;
+ r->headers_out.content_type_len = r->headers_out.content_type.len;
+ r->headers_out.content_type.data = s.start;
+ r->headers_out.content_type_lowcase = NULL;
+
+ return NJS_OK;
+}
+
+
+static njs_int_t
+ngx_http_js_header_out_special(njs_vm_t *vm, ngx_http_request_t *r,
+ njs_str_t *v, njs_value_t *setval, njs_value_t *retval,
+ ngx_table_elt_t **hh)
+{
+ u_char *p;
+ int64_t length;
+ njs_int_t rc;
+ njs_str_t s;
+ ngx_uint_t i;
+ ngx_list_t *headers;
+ ngx_list_part_t *part;
+ ngx_table_elt_t *header, *h;
+ njs_opaque_value_t lvalue;
+
+ headers = &r->headers_out.headers;
+
+ if (retval != NULL && setval == NULL) {
+ return ngx_http_js_header_out(vm, r, NJS_HEADER_SINGLE, v, setval,
+ retval);
+ }
+
+ if (setval != NULL && njs_value_is_array(setval)) {
+ rc = njs_vm_array_length(vm, setval, &length);
+ if (rc != NJS_OK) {
+ return NJS_ERROR;
+ }
+
+ setval = njs_vm_array_prop(vm, setval, length - 1, &lvalue);
+ }
+
+ if (ngx_js_string(vm, setval, &s) != NGX_OK) {
+ return NJS_ERROR;
+ }
+
+ h = NULL;
+ part = &headers->part;
+ header = part->elts;
+
+ 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) {
+ continue;
+ }
+
+ if (h->key.len == v->length
+ && ngx_strncasecmp(h->key.data, v->start, v->length) == 0)
+ {
+ break;
+ }
+ }
+
+ if (h != NULL && s.length == 0) {
+ h->hash = 0;
+ h = NULL;
+ }
+
+ if (h == NULL && s.length != 0) {
+ h = ngx_list_push(headers);
+ if (h == NULL) {
+ njs_vm_memory_error(vm);
+ return NJS_ERROR;
+ }
+
+ p = ngx_pnalloc(r->pool, v->length);
+ if (p == NULL) {
+ h->hash = 0;
+ njs_vm_memory_error(vm);
+ return NJS_ERROR;
+ }
+
+ ngx_memcpy(p, v->start, v->length);
+
+ h->key.data = p;
+ h->key.len = v->length;
+ }
+
+ if (h != NULL) {
+ p = ngx_pnalloc(r->pool, s.length);
+ if (p == NULL) {
+ h->hash = 0;
+ njs_vm_memory_error(vm);
+ return NJS_ERROR;
+ }
+
+ ngx_memcpy(p, s.start, s.length);
+
+ h->value.data = p;
+ h->value.len = s.length;
+ h->hash = 1;
+ }
+
+ if (hh != NULL) {
+ *hh = h;
+ }
+
+ return NJS_OK;
+}
+
+
+static njs_int_t
+ngx_http_js_header_generic(njs_vm_t *vm, ngx_http_request_t *r,
+ ngx_list_t *headers, ngx_table_elt_t **ph, unsigned flags, njs_str_t *name,
+ njs_value_t *retval)
+{
+ u_char *p, sep;
+ ssize_t size;
+ njs_int_t rc;
+ ngx_uint_t i;
+ njs_value_t *value;
+ ngx_list_part_t *part;
+ ngx_table_elt_t *header, *h;
+
+ if (ph == NULL) {
+ /* iterate over all headers */
+
+ ph = &header;
+ part = &headers->part;
+ h = part->elts;
+
+ for (i = 0; /* void */ ; i++) {
+
+ if (i >= part->nelts) {
+ if (part->next == NULL) {
+ break;
+ }
+
+ part = part->next;
+ h = part->elts;
+ i = 0;
+ }
+
+ if (h[i].hash == 0
+ || name->length != h[i].key.len
+ || ngx_strncasecmp(name->start, h[i].key.data, name->length)
+ != 0)
+ {
+ continue;
+ }
+
+ *ph = &h[i];
+ ph = &h[i].next;
+ }
+
+ *ph = NULL;
+ ph = &header;
+ }
+
+ if (*ph == NULL) {
+ njs_value_undefined_set(retval);
+ return NJS_DECLINED;
+ }
+
+ if (flags & NJS_HEADER_ARRAY) {
+ rc = njs_vm_array_alloc(vm, retval, 4);
+ if (rc != NJS_OK) {
+ return NJS_ERROR;
+ }
+
+ for (h = *ph; h; h = h->next) {
+ value = njs_vm_array_push(vm, retval);
+ if (value == NULL) {
+ return NJS_ERROR;
+ }
+
+ rc = njs_vm_value_string_set(vm, value, h->value.data,
+ h->value.len);
+ if (rc != NJS_OK) {
+ return NJS_ERROR;
+ }
+ }
+
+ return NJS_OK;
+ }
+
+ if ((*ph)->next == NULL || flags & NJS_HEADER_SINGLE) {
+ return njs_vm_value_string_set(vm, retval, (*ph)->value.data,
+ (*ph)->value.len);
+ }
+
+ size = - (ssize_t) njs_length("; ");
+
+ for (h = *ph; h; h = h->next) {
+ size += h->value.len + njs_length("; ");
+ }
+
+ p = njs_vm_value_string_alloc(vm, retval, size);
+ if (p == NULL) {
+ return NJS_ERROR;
+ }
+
+ sep = flags & NJS_HEADER_SEMICOLON ? ';' : ',';
+
+ for (h = *ph; h; h = h->next) {
+ p = ngx_copy(p, h->value.data, h->value.len);
+
+ if (h->next == NULL) {
+ break;
+ }
+
+ *p++ = sep; *p++ = ' ';
+ }
+
+ return NJS_OK;
+}
+#endif
+
+
static njs_host_event_t
ngx_http_js_set_timer(njs_external_ptr_t external, uint64_t delay,
njs_vm_event_t vm_event)
More information about the nginx-devel
mailing list