[njs] Refactoring iteration over external objects.

Dmitry Volyntsev xeioex at nginx.com
Wed Oct 23 11:47:15 UTC 2019


details:   https://hg.nginx.org/njs/rev/9e327cd3a33e
branches:  
changeset: 1197:9e327cd3a33e
user:      Dmitry Volyntsev <xeioex at nginx.com>
date:      Wed Oct 23 14:42:38 2019 +0300
description:
Refactoring iteration over external objects.

Previously, two callbacks were required to support
array-like iteration for external objects (foreach, next).

Instead using only one callback (keys) to simplify.

diffstat:

 nginx/ngx_http_js_module.c   |  242 ++++++++++++++++++------------------------
 nginx/ngx_stream_js_module.c |   13 --
 src/njs.h                    |    8 +-
 src/njs_extern.c             |    3 +-
 src/njs_extern.h             |    3 +-
 src/njs_json.c               |    8 +-
 src/njs_shell.c              |    6 -
 src/njs_value.c              |   42 +++++++
 src/njs_vmcode.c             |   94 +---------------
 src/test/njs_unit_test.c     |   61 ++++------
 10 files changed, 187 insertions(+), 293 deletions(-)

diffs (truncated from 1094 to 1000 lines):

diff -r 5e136f9a5954 -r 9e327cd3a33e nginx/ngx_http_js_module.c
--- a/nginx/ngx_http_js_module.c	Wed Oct 23 14:42:38 2019 +0300
+++ b/nginx/ngx_http_js_module.c	Wed Oct 23 14:42:38 2019 +0300
@@ -36,12 +36,6 @@ typedef struct {
 
 
 typedef struct {
-    ngx_list_part_t     *part;
-    ngx_uint_t           item;
-} ngx_http_js_table_entry_t;
-
-
-typedef struct {
     ngx_http_request_t  *request;
     njs_vm_event_t       vm_event;
     void                *unused;
@@ -62,10 +56,8 @@ static void ngx_http_js_cleanup_vm(void 
 
 static njs_int_t ngx_http_js_ext_get_string(njs_vm_t *vm, njs_value_t *value,
     void *obj, uintptr_t data);
-static njs_int_t ngx_http_js_ext_foreach_header(njs_vm_t *vm, void *obj,
-    void *next, uintptr_t data);
-static njs_int_t ngx_http_js_ext_next_header(njs_vm_t *vm, njs_value_t *value,
-    void *obj, void *next);
+static njs_int_t ngx_http_js_ext_keys_header(njs_vm_t *vm, void *obj,
+    njs_value_t *keys, uintptr_t data);
 static ngx_table_elt_t *ngx_http_js_get_header(ngx_list_part_t *part,
     u_char *data, size_t len);
 static njs_int_t ngx_http_js_ext_get_header_out(njs_vm_t *vm,
@@ -74,8 +66,8 @@ static njs_int_t ngx_http_js_ext_set_hea
     uintptr_t data, njs_str_t *value);
 static njs_int_t ngx_http_js_ext_delete_header_out(njs_vm_t *vm, void *obj,
     uintptr_t data, njs_bool_t delete);
-static njs_int_t ngx_http_js_ext_foreach_header_out(njs_vm_t *vm, void *obj,
-    void *next); /*FIXME*/
+static njs_int_t ngx_http_js_ext_keys_header_out(njs_vm_t *vm, void *obj,
+    njs_value_t *keys); /*FIXME*/
 static njs_int_t ngx_http_js_ext_get_status(njs_vm_t *vm, njs_value_t *value,
     void *obj, uintptr_t data);
 static njs_int_t ngx_http_js_ext_set_status(njs_vm_t *vm, void *obj,
@@ -108,14 +100,12 @@ static njs_int_t ngx_http_js_ext_get_req
     njs_value_t *value, void *obj, uintptr_t data);
 static njs_int_t ngx_http_js_ext_get_header_in(njs_vm_t *vm, njs_value_t *value,
     void *obj, uintptr_t data);
-static njs_int_t ngx_http_js_ext_foreach_header_in(njs_vm_t *vm, void *obj,
-    void *next); /*FIXME*/
+static njs_int_t ngx_http_js_ext_keys_header_in(njs_vm_t *vm, void *obj,
+    njs_value_t *keys); /*FIXME*/
 static njs_int_t ngx_http_js_ext_get_arg(njs_vm_t *vm, njs_value_t *value,
     void *obj, uintptr_t data);
-static njs_int_t ngx_http_js_ext_foreach_arg(njs_vm_t *vm, void *obj,
-    void *next);
-static njs_int_t ngx_http_js_ext_next_arg(njs_vm_t *vm, njs_value_t *value,
-    void *obj, void *next);
+static njs_int_t ngx_http_js_ext_keys_arg(njs_vm_t *vm, void *obj,
+    njs_value_t *keys);
 static njs_int_t ngx_http_js_ext_get_variable(njs_vm_t *vm, njs_value_t *value,
     void *obj, uintptr_t data);
 static njs_int_t ngx_http_js_ext_set_variable(njs_vm_t *vm, void *obj,
@@ -229,7 +219,6 @@ static njs_external_t  ngx_http_js_ext_r
       NULL,
       NULL,
       NULL,
-      NULL,
       offsetof(ngx_http_request_t, uri) },
 
     { njs_str("method"),
@@ -241,7 +230,6 @@ static njs_external_t  ngx_http_js_ext_r
       NULL,
       NULL,
       NULL,
-      NULL,
       offsetof(ngx_http_request_t, method_name) },
 
     { njs_str("httpVersion"),
@@ -253,7 +241,6 @@ static njs_external_t  ngx_http_js_ext_r
       NULL,
       NULL,
       NULL,
-      NULL,
       0 },
 
     { njs_str("remoteAddress"),
@@ -265,7 +252,6 @@ static njs_external_t  ngx_http_js_ext_r
       NULL,
       NULL,
       NULL,
-      NULL,
       0 },
 
     { njs_str("parent"),
@@ -277,7 +263,6 @@ static njs_external_t  ngx_http_js_ext_r
       NULL,
       NULL,
       NULL,
-      NULL,
       0 },
 
     { njs_str("requestBody"),
@@ -289,7 +274,6 @@ static njs_external_t  ngx_http_js_ext_r
       NULL,
       NULL,
       NULL,
-      NULL,
       0 },
 
     { njs_str("responseBody"),
@@ -301,7 +285,6 @@ static njs_external_t  ngx_http_js_ext_r
       NULL,
       NULL,
       NULL,
-      NULL,
       0 },
 
     { njs_str("headersIn"),
@@ -311,8 +294,7 @@ static njs_external_t  ngx_http_js_ext_r
       ngx_http_js_ext_get_header_in,
       NULL,
       NULL,
-      ngx_http_js_ext_foreach_header_in,
-      ngx_http_js_ext_next_header,
+      ngx_http_js_ext_keys_header_in,
       NULL,
       0 },
 
@@ -323,8 +305,7 @@ static njs_external_t  ngx_http_js_ext_r
       ngx_http_js_ext_get_arg,
       NULL,
       NULL,
-      ngx_http_js_ext_foreach_arg,
-      ngx_http_js_ext_next_arg,
+      ngx_http_js_ext_keys_arg,
       NULL,
       0 },
 
@@ -337,7 +318,6 @@ static njs_external_t  ngx_http_js_ext_r
       NULL,
       NULL,
       NULL,
-      NULL,
       0 },
 
     { njs_str("status"),
@@ -349,7 +329,6 @@ static njs_external_t  ngx_http_js_ext_r
       NULL,
       NULL,
       NULL,
-      NULL,
       offsetof(ngx_http_request_t, headers_out.status) },
 
     { njs_str("headersOut"),
@@ -359,8 +338,7 @@ static njs_external_t  ngx_http_js_ext_r
       ngx_http_js_ext_get_header_out,
       ngx_http_js_ext_set_header_out,
       ngx_http_js_ext_delete_header_out,
-      ngx_http_js_ext_foreach_header_out,
-      ngx_http_js_ext_next_header,
+      ngx_http_js_ext_keys_header_out,
       NULL,
       0 },
 
@@ -372,7 +350,6 @@ static njs_external_t  ngx_http_js_ext_r
       NULL,
       NULL,
       NULL,
-      NULL,
       ngx_http_js_ext_subrequest,
       0 },
 
@@ -384,7 +361,6 @@ static njs_external_t  ngx_http_js_ext_r
       NULL,
       NULL,
       NULL,
-      NULL,
       ngx_http_js_ext_log,
       0 },
 
@@ -396,7 +372,6 @@ static njs_external_t  ngx_http_js_ext_r
       NULL,
       NULL,
       NULL,
-      NULL,
       ngx_http_js_ext_warn,
       0 },
 
@@ -408,7 +383,6 @@ static njs_external_t  ngx_http_js_ext_r
       NULL,
       NULL,
       NULL,
-      NULL,
       ngx_http_js_ext_error,
       0 },
 
@@ -420,7 +394,6 @@ static njs_external_t  ngx_http_js_ext_r
       NULL,
       NULL,
       NULL,
-      NULL,
       ngx_http_js_ext_send_header,
       0 },
 
@@ -432,7 +405,6 @@ static njs_external_t  ngx_http_js_ext_r
       NULL,
       NULL,
       NULL,
-      NULL,
       ngx_http_js_ext_send,
       0 },
 
@@ -444,7 +416,6 @@ static njs_external_t  ngx_http_js_ext_r
       NULL,
       NULL,
       NULL,
-      NULL,
       ngx_http_js_ext_finish,
       0 },
 
@@ -456,7 +427,6 @@ static njs_external_t  ngx_http_js_ext_r
       NULL,
       NULL,
       NULL,
-      NULL,
       ngx_http_js_ext_return,
       0 },
 
@@ -468,7 +438,6 @@ static njs_external_t  ngx_http_js_ext_r
       NULL,
       NULL,
       NULL,
-      NULL,
       ngx_http_js_ext_internal_redirect,
       0 },
 };
@@ -485,7 +454,6 @@ static njs_external_t  ngx_http_js_exter
       NULL,
       NULL,
       NULL,
-      NULL,
       0 },
 };
 
@@ -822,64 +790,79 @@ ngx_http_js_ext_get_string(njs_vm_t *vm,
 
 
 static njs_int_t
-ngx_http_js_ext_foreach_header(njs_vm_t *vm, void *obj, void *next,
+ngx_http_js_ext_keys_header(njs_vm_t *vm, void *obj, njs_value_t *keys,
     uintptr_t data)
 {
     char *p = obj;
 
-    ngx_list_t                 *headers;
-    ngx_http_request_t         *r;
-    ngx_http_js_table_entry_t  *entry, **e;
-
-    r = (ngx_http_request_t *) obj;
-
-    entry = ngx_palloc(r->pool, sizeof(ngx_http_js_table_entry_t));
-    if (entry == NULL) {
+    njs_int_t         rc, cookie, x_for;
+    ngx_uint_t        item;
+    ngx_list_t       *headers;
+    njs_value_t      *value;
+    ngx_list_part_t  *part;
+    ngx_table_elt_t  *header, *h;
+
+    rc = njs_vm_array_alloc(vm, keys, 8);
+    if (rc != NJS_OK) {
         return NJS_ERROR;
     }
 
     headers = (ngx_list_t *) (p + data);
-
-    entry->part = &headers->part;
-    entry->item = 0;
-
-    e = (ngx_http_js_table_entry_t **) next;
-    *e = entry;
-
-    return NJS_OK;
-}
-
-
-static njs_int_t
-ngx_http_js_ext_next_header(njs_vm_t *vm, njs_value_t *value, void *obj,
-    void *next)
-{
-    ngx_http_js_table_entry_t **e = next;
-
-    ngx_table_elt_t            *header, *h;
-    ngx_http_js_table_entry_t  *entry;
-
-    entry = *e;
-
-    while (entry->part) {
-
-        if (entry->item >= entry->part->nelts) {
-            entry->part = entry->part->next;
-            entry->item = 0;
+    part = &headers->part;
+    item = 0;
+
+    cookie = 0;
+    x_for = 0;
+
+    while (part) {
+
+        if (item >= part->nelts) {
+            part = part->next;
+            item = 0;
             continue;
         }
 
-        header = entry->part->elts;
-        h = &header[entry->item++];
+        header = part->elts;
+        h = &header[item++];
 
         if (h->hash == 0) {
             continue;
         }
 
-        return njs_vm_value_string_set(vm, value, h->key.data, h->key.len);
+        if (h->key.len == njs_length("Cookie")
+            && ngx_strncasecmp(h->key.data, (u_char *) "Cookie",
+                               h->key.len) == 0)
+        {
+            if (cookie) {
+                continue;
+            }
+
+            cookie = 1;
+        }
+
+        if (h->key.len == njs_length("X-Forwarded-For")
+            && ngx_strncasecmp(h->key.data, (u_char *) "X-Forwarded-For",
+                               h->key.len) == 0)
+        {
+            if (x_for) {
+                continue;
+            }
+
+            x_for = 1;
+        }
+
+        value = njs_vm_array_push(vm, keys);
+        if (value == NULL) {
+            return NJS_ERROR;
+        }
+
+        rc = njs_vm_value_string_set(vm, value, h->key.data, h->key.len);
+        if (rc != NJS_OK) {
+            return NJS_ERROR;
+        }
     }
 
-    return NJS_DONE;
+    return NJS_OK;
 }
 
 
@@ -1078,9 +1061,9 @@ ngx_http_js_ext_delete_header_out(njs_vm
 
 
 static njs_int_t
-ngx_http_js_ext_foreach_header_out(njs_vm_t *vm, void *obj, void *next)
+ngx_http_js_ext_keys_header_out(njs_vm_t *vm, void *obj, njs_value_t *keys)
 {
-    return ngx_http_js_ext_foreach_header(vm, obj, next,
+    return ngx_http_js_ext_keys_header(vm, obj, keys,
                              offsetof(ngx_http_request_t, headers_out.headers));
 }
 
@@ -1604,9 +1587,9 @@ multi:
 
 
 static njs_int_t
-ngx_http_js_ext_foreach_header_in(njs_vm_t *vm, void *obj, void *next)
+ngx_http_js_ext_keys_header_in(njs_vm_t *vm, void *obj, njs_value_t *keys)
 {
-    return ngx_http_js_ext_foreach_header(vm, obj, next,
+    return ngx_http_js_ext_keys_header(vm, obj, keys,
                               offsetof(ngx_http_request_t, headers_in.headers));
 }
 
@@ -1632,71 +1615,54 @@ ngx_http_js_ext_get_arg(njs_vm_t *vm, nj
 
 
 static njs_int_t
-ngx_http_js_ext_foreach_arg(njs_vm_t *vm, void *obj, void *next)
+ngx_http_js_ext_keys_arg(njs_vm_t *vm, void *obj, njs_value_t *keys)
 {
-    ngx_str_t           *entry, **e;
+    u_char              *v, *p, *start, *end;
+    njs_int_t            rc;
+    njs_value_t         *value;
     ngx_http_request_t  *r;
 
     r = (ngx_http_request_t *) obj;
 
-    entry = ngx_palloc(r->pool, sizeof(ngx_str_t));
-    if (entry == NULL) {
+    rc = njs_vm_array_alloc(vm, keys, 8);
+    if (rc != NJS_OK) {
         return NJS_ERROR;
     }
 
-    *entry = r->args;
-
-    e = (ngx_str_t **) next;
-    *e = entry;
+    start = r->args.data;
+    end = start + r->args.len;
+
+    while (start < end) {
+        p = ngx_strlchr(start, end, '&');
+        if (p == NULL) {
+            p = end;
+        }
+
+        v = ngx_strlchr(start, p, '=');
+        if (v == NULL) {
+            v = p;
+        }
+
+        if (v != start) {
+            value = njs_vm_array_push(vm, keys);
+            if (value == NULL) {
+                return NJS_ERROR;
+            }
+
+            rc = njs_vm_value_string_set(vm, value, start, v - start);
+            if (rc != NJS_OK) {
+                return NJS_ERROR;
+            }
+        }
+
+        start = p + 1;
+    }
 
     return NJS_OK;
 }
 
 
 static njs_int_t
-ngx_http_js_ext_next_arg(njs_vm_t *vm, njs_value_t *value, void *obj,
-    void *next)
-{
-    ngx_str_t **e = next;
-
-    size_t      len;
-    u_char     *v, *p, *start, *end;
-    ngx_str_t  *entry;
-
-    entry = *e;
-
-    if (entry->len == 0) {
-        return NJS_DONE;
-    }
-
-    start = entry->data;
-    end = start + entry->len;
-
-    p = ngx_strlchr(start, end, '&');
-    if (p == NULL) {
-        p = end;
-    }
-
-    v = ngx_strlchr(start, p, '=');
-    if (v == NULL) {
-        v = p;
-    }
-
-    len = v - start;
-
-    if (p != end) {
-        entry->data = &p[1];
-        entry->len = end - entry->data;
-
-    } else {
-        entry->len = 0;
-    }
-
-    return njs_vm_value_string_set(vm, value, start, len);
-}
-
-
-static njs_int_t
 ngx_http_js_ext_get_variable(njs_vm_t *vm, njs_value_t *value, void *obj,
     uintptr_t data)
 {
diff -r 5e136f9a5954 -r 9e327cd3a33e nginx/ngx_stream_js_module.c
--- a/nginx/ngx_stream_js_module.c	Wed Oct 23 14:42:38 2019 +0300
+++ b/nginx/ngx_stream_js_module.c	Wed Oct 23 14:42:38 2019 +0300
@@ -211,7 +211,6 @@ static njs_external_t  ngx_stream_js_ext
       NULL,
       NULL,
       NULL,
-      NULL,
       0 },
 
     { njs_str("variables"),
@@ -223,7 +222,6 @@ static njs_external_t  ngx_stream_js_ext
       NULL,
       NULL,
       NULL,
-      NULL,
       0 },
 
     { njs_str("allow"),
@@ -234,7 +232,6 @@ static njs_external_t  ngx_stream_js_ext
       NULL,
       NULL,
       NULL,
-      NULL,
       ngx_stream_js_ext_done,
       0 },
 
@@ -246,7 +243,6 @@ static njs_external_t  ngx_stream_js_ext
       NULL,
       NULL,
       NULL,
-      NULL,
       ngx_stream_js_ext_deny,
       0 },
 
@@ -258,7 +254,6 @@ static njs_external_t  ngx_stream_js_ext
       NULL,
       NULL,
       NULL,
-      NULL,
       ngx_stream_js_ext_decline,
       0 },
 
@@ -270,7 +265,6 @@ static njs_external_t  ngx_stream_js_ext
       NULL,
       NULL,
       NULL,
-      NULL,
       ngx_stream_js_ext_done,
       0 },
 
@@ -282,7 +276,6 @@ static njs_external_t  ngx_stream_js_ext
       NULL,
       NULL,
       NULL,
-      NULL,
       ngx_stream_js_ext_log,
       0 },
 
@@ -294,7 +287,6 @@ static njs_external_t  ngx_stream_js_ext
       NULL,
       NULL,
       NULL,
-      NULL,
       ngx_stream_js_ext_warn,
       0 },
 
@@ -306,7 +298,6 @@ static njs_external_t  ngx_stream_js_ext
       NULL,
       NULL,
       NULL,
-      NULL,
       ngx_stream_js_ext_error,
       0 },
 
@@ -318,7 +309,6 @@ static njs_external_t  ngx_stream_js_ext
       NULL,
       NULL,
       NULL,
-      NULL,
       ngx_stream_js_ext_on,
       0 },
 
@@ -330,7 +320,6 @@ static njs_external_t  ngx_stream_js_ext
       NULL,
       NULL,
       NULL,
-      NULL,
       ngx_stream_js_ext_off,
       0 },
 
@@ -342,7 +331,6 @@ static njs_external_t  ngx_stream_js_ext
       NULL,
       NULL,
       NULL,
-      NULL,
       ngx_stream_js_ext_send,
       0 },
 
@@ -360,7 +348,6 @@ static njs_external_t  ngx_stream_js_ext
       NULL,
       NULL,
       NULL,
-      NULL,
       0 },
 };
 
diff -r 5e136f9a5954 -r 9e327cd3a33e src/njs.h
--- a/src/njs.h	Wed Oct 23 14:42:38 2019 +0300
+++ b/src/njs.h	Wed Oct 23 14:42:38 2019 +0300
@@ -66,9 +66,8 @@ typedef njs_int_t (*njs_extern_set_t)(nj
     njs_str_t *value);
 typedef njs_int_t (*njs_extern_find_t)(njs_vm_t *vm, void *obj, uintptr_t data,
     njs_bool_t delete);
-typedef njs_int_t (*njs_extern_foreach_t)(njs_vm_t *vm, void *obj, void *next);
-typedef njs_int_t (*njs_extern_next_t)(njs_vm_t *vm, njs_value_t *value,
-    void *obj, void *next);
+typedef njs_int_t (*njs_extern_keys_t)(njs_vm_t *vm, void *obj,
+    njs_value_t *keys);
 typedef njs_int_t (*njs_extern_method_t)(njs_vm_t *vm, njs_value_t *args,
     njs_uint_t nargs, njs_index_t unused);
 
@@ -92,8 +91,7 @@ struct njs_external_s {
     njs_extern_set_t                set;
     njs_extern_find_t               find;
 
-    njs_extern_foreach_t            foreach;
-    njs_extern_next_t               next;
+    njs_extern_keys_t               keys;
 
     njs_extern_method_t             method;
 
diff -r 5e136f9a5954 -r 9e327cd3a33e src/njs_extern.c
--- a/src/njs_extern.c	Wed Oct 23 14:42:38 2019 +0300
+++ b/src/njs_extern.c	Wed Oct 23 14:42:38 2019 +0300
@@ -89,8 +89,7 @@ njs_vm_external_add(njs_vm_t *vm, njs_lv
         ext->get = external->get;
         ext->set = external->set;
         ext->find = external->find;
-        ext->foreach = external->foreach;
-        ext->next = external->next;
+        ext->keys = external->keys;
         ext->data = external->data;
 
         if (external->method != NULL) {
diff -r 5e136f9a5954 -r 9e327cd3a33e src/njs_extern.h
--- a/src/njs_extern.h	Wed Oct 23 14:42:38 2019 +0300
+++ b/src/njs_extern.h	Wed Oct 23 14:42:38 2019 +0300
@@ -26,8 +26,7 @@ struct njs_extern_s {
     njs_extern_set_t             set;
     njs_extern_find_t            find;
 
-    njs_extern_foreach_t         foreach;
-    njs_extern_next_t            next;
+    njs_extern_keys_t            keys;
 
     njs_function_t               *function;
 
diff -r 5e136f9a5954 -r 9e327cd3a33e src/njs_json.c
--- a/src/njs_json.c	Wed Oct 23 14:42:38 2019 +0300
+++ b/src/njs_json.c	Wed Oct 23 14:42:38 2019 +0300
@@ -2295,12 +2295,8 @@ njs_dump_value(njs_json_stringify_t *str
             njs_dump_item("\"find\"");
         }
 
-        if (ext_proto->foreach != NULL) {
-            njs_dump_item("\"foreach\"");
-        }
-
-        if (ext_proto->next != NULL) {
-            njs_dump_item("\"next\"");
+        if (ext_proto->keys != NULL) {
+            njs_dump_item("\"keys\"");
         }
 
         return njs_json_buf_append(stringify, "]}", 2);
diff -r 5e136f9a5954 -r 9e327cd3a33e src/njs_shell.c
--- a/src/njs_shell.c	Wed Oct 23 14:42:38 2019 +0300
+++ b/src/njs_shell.c	Wed Oct 23 14:42:38 2019 +0300
@@ -112,7 +112,6 @@ static njs_external_t  njs_ext_console[]
       NULL,
       NULL,
       NULL,
-      NULL,
       njs_ext_console_log,
       0 },
 
@@ -124,7 +123,6 @@ static njs_external_t  njs_ext_console[]
       NULL,
       NULL,
       NULL,
-      NULL,
       njs_ext_console_dump,
       0 },
 
@@ -136,7 +134,6 @@ static njs_external_t  njs_ext_console[]
       NULL,
       NULL,
       NULL,
-      NULL,
       njs_ext_console_help,
       0 },
 
@@ -148,7 +145,6 @@ static njs_external_t  njs_ext_console[]
       NULL,
       NULL,
       NULL,
-      NULL,
       njs_ext_console_time,
       0 },
 
@@ -160,7 +156,6 @@ static njs_external_t  njs_ext_console[]
       NULL,
       NULL,
       NULL,
-      NULL,
       njs_ext_console_time_end,
       0 },
 };
@@ -176,7 +171,6 @@ static njs_external_t  njs_externals[] =
       NULL,
       NULL,
       NULL,
-      NULL,
       0 },
 };
 
diff -r 5e136f9a5954 -r 9e327cd3a33e src/njs_value.c
--- a/src/njs_value.c	Wed Oct 23 14:42:38 2019 +0300
+++ b/src/njs_value.c	Wed Oct 23 14:42:38 2019 +0300
@@ -191,13 +191,34 @@ njs_array_t *
 njs_value_enumerate(njs_vm_t *vm, const njs_value_t *value,
     njs_object_enum_t kind, njs_bool_t all)
 {
+    void                *obj;
+    njs_int_t           ret;
+    njs_value_t         keys;
     njs_object_value_t  obj_val;
+    const njs_extern_t  *ext_proto;
 
     if (njs_is_object(value)) {
         return njs_object_enumerate(vm, njs_object(value), kind, all);
     }
 
     if (value->type != NJS_STRING) {
+        if (kind == NJS_ENUM_KEYS && njs_is_external(value)) {
+            ext_proto = value->external.proto;
+
+            if (ext_proto->keys != NULL) {
+                obj = njs_extern_object(vm, value);
+
+                ret = ext_proto->keys(vm, obj, &keys);
+                if (njs_slow_path(ret != NJS_OK)) {
+                    return NULL;
+                }
+
+                return njs_array(&keys);
+            }
+
+            return njs_extern_keys_array(vm, ext_proto);
+        }
+
         return njs_array_alloc(vm, 0, NJS_ARRAY_SPARE);
     }
 
@@ -212,13 +233,34 @@ njs_array_t *
 njs_value_own_enumerate(njs_vm_t *vm, const njs_value_t *value,
     njs_object_enum_t kind, njs_bool_t all)
 {
+    void                *obj;
+    njs_int_t           ret;
+    njs_value_t         keys;
     njs_object_value_t  obj_val;
+    const njs_extern_t  *ext_proto;
 
     if (njs_is_object(value)) {
         return njs_object_own_enumerate(vm, njs_object(value), kind, all);
     }
 
     if (value->type != NJS_STRING) {
+        if (kind == NJS_ENUM_KEYS && njs_is_external(value)) {
+            ext_proto = value->external.proto;
+
+            if (ext_proto->keys != NULL) {
+                obj = njs_extern_object(vm, value);
+
+                ret = ext_proto->keys(vm, obj, &keys);
+                if (njs_slow_path(ret != NJS_OK)) {
+                    return NULL;
+                }
+
+                return njs_array(&keys);
+            }
+
+            return njs_extern_keys_array(vm, ext_proto);
+        }
+
         return njs_array_alloc(vm, 0, NJS_ARRAY_SPARE);
     }
 
diff -r 5e136f9a5954 -r 9e327cd3a33e src/njs_vmcode.c
--- a/src/njs_vmcode.c	Wed Oct 23 14:42:38 2019 +0300
+++ b/src/njs_vmcode.c	Wed Oct 23 14:42:38 2019 +0300
@@ -31,8 +31,6 @@ static njs_jump_off_t njs_vmcode_propert
     njs_value_t *value, njs_value_t *key);
 static njs_jump_off_t njs_vmcode_property_foreach(njs_vm_t *vm,
     njs_value_t *object, njs_value_t *invld, u_char *pc);
-static njs_jump_off_t njs_vmcode_property_next(njs_vm_t *vm,
-    njs_value_t *object, njs_value_t *value, u_char *pc);
 static njs_jump_off_t njs_vmcode_instance_of(njs_vm_t *vm, njs_value_t *object,
     njs_value_t *constructor);
 static njs_jump_off_t njs_vmcode_typeof(njs_vm_t *vm, njs_value_t *value,
@@ -771,25 +769,21 @@ next:
                 break;
 
             case NJS_VMCODE_PROPERTY_NEXT:
-                if (!njs_is_external(value1)) {
-                    pnext = (njs_vmcode_prop_next_t *) pc;
-                    retval = njs_vmcode_operand(vm, pnext->retval);
+                pnext = (njs_vmcode_prop_next_t *) pc;
+                retval = njs_vmcode_operand(vm, pnext->retval);
 
-                    next = value2->data.u.next;
+                next = value2->data.u.next;
 
-                    if (next->index < next->array->length) {
-                        *retval = next->array->data[next->index++];
+                if (next->index < next->array->length) {
+                    *retval = next->array->data[next->index++];
 
-                        ret = pnext->offset;
-                        break;
-                    }
+                    ret = pnext->offset;
+                    break;
                 }
 
-                ret = njs_vmcode_property_next(vm, value1, value2, pc);
-                if (njs_slow_path(ret == NJS_ERROR)) {
-                    goto error;
-                }
+                njs_mp_free(vm->mem_pool, next);
 
+                ret = sizeof(njs_vmcode_prop_next_t);
                 break;
 
             case NJS_VMCODE_THIS:
@@ -1306,27 +1300,9 @@ static njs_jump_off_t
 njs_vmcode_property_foreach(njs_vm_t *vm, njs_value_t *object,
     njs_value_t *invld, u_char *pc)
 {
-    void                       *obj;
-    njs_jump_off_t             ret;
-    const njs_extern_t         *ext_proto;
     njs_property_next_t        *next;
     njs_vmcode_prop_foreach_t  *code;
 
-    if (njs_is_external(object)) {
-        ext_proto = object->external.proto;
-
-        if (ext_proto->foreach != NULL) {
-            obj = njs_extern_object(vm, object);
-
-            ret = ext_proto->foreach(vm, obj, &vm->retval);
-            if (njs_slow_path(ret != NJS_OK)) {
-                return ret;
-            }
-        }
-
-        goto done;
-    }
-
     next = njs_mp_alloc(vm->mem_pool, sizeof(njs_property_next_t));
     if (njs_slow_path(next == NULL)) {
         njs_memory_error(vm);
@@ -1342,8 +1318,6 @@ njs_vmcode_property_foreach(njs_vm_t *vm
 
     vm->retval.data.u.next = next;
 
-done:
-
     code = (njs_vmcode_prop_foreach_t *) pc;
 
     return code->offset;
@@ -1351,56 +1325,6 @@ done:
 
 
 static njs_jump_off_t
-njs_vmcode_property_next(njs_vm_t *vm, njs_value_t *object, njs_value_t *value,
-    u_char *pc)
-{
-    void                    *obj;
-    njs_value_t             *retval;
-    njs_jump_off_t          ret;
-    njs_property_next_t     *next;
-    const njs_extern_t      *ext_proto;
-    njs_vmcode_prop_next_t  *code;
-
-    code = (njs_vmcode_prop_next_t *) pc;
-    retval = njs_vmcode_operand(vm, code->retval);
-
-    if (njs_is_external(object)) {
-        ext_proto = object->external.proto;
-
-        if (ext_proto->next != NULL) {
-            obj = njs_extern_object(vm, object);
-
-            ret = ext_proto->next(vm, retval, obj, value);
-
-            if (ret == NJS_OK) {
-                return code->offset;
-            }
-
-            if (njs_slow_path(ret == NJS_ERROR)) {
-                return ret;
-            }
-
-            /* ret == NJS_DONE. */
-        }
-
-        return sizeof(njs_vmcode_prop_next_t);
-    }
-
-    next = value->data.u.next;
-
-    if (next->index < next->array->length) {
-        *retval = next->array->data[next->index++];
-
-        return code->offset;
-    }
-
-    njs_mp_free(vm->mem_pool, next);
-
-    return sizeof(njs_vmcode_prop_next_t);
-}
-
-
-static njs_jump_off_t
 njs_vmcode_instance_of(njs_vm_t *vm, njs_value_t *object,
     njs_value_t *constructor)
 {
diff -r 5e136f9a5954 -r 9e327cd3a33e src/test/njs_unit_test.c
--- a/src/test/njs_unit_test.c	Wed Oct 23 14:42:38 2019 +0300
+++ b/src/test/njs_unit_test.c	Wed Oct 23 14:42:38 2019 +0300
@@ -14029,7 +14029,7 @@ static njs_unit_test_t  njs_test[] =
       njs_str("{a:{type:\"property\",props:[\"getter\"]},b:{type:\"property\",props:[\"getter\"]}}") },
 
     { njs_str("njs.dump($r.header)"),
-      njs_str("{type:\"object\",props:[\"getter\",\"foreach\",\"next\"]}") },
+      njs_str("{type:\"object\",props:[\"getter\",\"keys\"]}") },
 
     { njs_str("njs.dump(njs) == `{version:'${njs.version}'}`"),
       njs_str("true") },
@@ -14988,36 +14988,36 @@ njs_unit_test_header_external(njs_vm_t *
 
 
 static njs_int_t
-njs_unit_test_header_foreach_external(njs_vm_t *vm, void *obj, void *next)
+njs_unit_test_header_keys_external(njs_vm_t *vm, void *obj, njs_value_t *keys)
 {
-    u_char  *s;
-
-    s = next;
-    s[0] = '0';
-    s[1] = '0';
+    njs_int_t    rc, i;
+    njs_value_t  *value;
+    u_char       k[2];
+
+    rc = njs_vm_array_alloc(vm, keys, 4);
+    if (rc != NJS_OK) {
+        return NJS_ERROR;
+    }
+
+    k[0] = '0';
+    k[1] = '1';
+
+    for (i = 0; i < 3; i++) {
+        value = njs_vm_array_push(vm, keys);
+        if (value == NULL) {
+            return NJS_ERROR;
+        }
+
+        (void) njs_vm_value_string_set(vm, value, k, 2);
+
+        k[1]++;
+    }
 
     return NJS_OK;
 }
 
 
 static njs_int_t
-njs_unit_test_header_next_external(njs_vm_t *vm, njs_value_t *value, void *obj,
-    void *next)
-{
-    u_char  *s;
-
-    s = next;
-    s[1]++;
-
-    if (s[1] == '4') {
-        return NJS_DONE;
-    }
-
-    return njs_vm_value_string_set(vm, value, s, 2);
-}
-
-


More information about the nginx-devel mailing list