]> git.kaiwu.me - njs.git/commitdiff
Added support for Object.prototype.valueOf() in Buffer.from().
authorAlexander Borisov <alexander.borisov@nginx.com>
Tue, 20 Oct 2020 11:00:40 +0000 (14:00 +0300)
committerAlexander Borisov <alexander.borisov@nginx.com>
Tue, 20 Oct 2020 11:00:40 +0000 (14:00 +0300)
Missed in 27bb9caf186c.

src/njs_buffer.c
src/njs_value.c
src/njs_value.h
src/test/njs_unit_test.c

index 1142cf7ad37984d7576d7c47ecb51e8e630ea54e..f4d1f31d277c77218748a644cb0950f257c62529 100644 (file)
@@ -228,11 +228,13 @@ njs_buffer_from(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
     njs_index_t unused)
 {
     njs_int_t                    ret;
-    njs_value_t                  *value;
+    njs_value_t                  *value, retval;
     const njs_buffer_encoding_t  *encoding;
 
     value = njs_arg(args, nargs, 1);
 
+next:
+
     switch (value->type) {
     case NJS_TYPED_ARRAY:
         return njs_buffer_from_typed_array(vm, value);
@@ -251,6 +253,19 @@ njs_buffer_from(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
 
     default:
         if (njs_is_object(value)) {
+            ret = njs_value_of(vm, value, &retval);
+            if (njs_slow_path(ret == NJS_ERROR)) {
+                return ret;
+            }
+
+            if (ret == NJS_OK && !njs_is_null(&retval)
+                && !(njs_is_object(&retval)
+                     && njs_object(&retval) == njs_object(value)))
+            {
+                *value = retval;
+                goto next;
+            }
+
             ret = njs_buffer_from_object(vm, value);
             if (njs_slow_path(ret != NJS_DECLINED)) {
                 return ret;
index 5cd78d7f8bbe25cb04b9564cbc574d42c2d56609..365013fab7629becc5dac6649d2698b6285529d3 100644 (file)
@@ -261,6 +261,33 @@ njs_value_own_enumerate(njs_vm_t *vm, njs_value_t *value,
 }
 
 
+njs_int_t
+njs_value_of(njs_vm_t *vm, njs_value_t *value, njs_value_t *retval)
+{
+
+    njs_int_t  ret;
+
+    static const njs_value_t  value_of = njs_string("valueOf");
+
+    if (njs_slow_path(!njs_is_object(value))) {
+        return NJS_DECLINED;
+    }
+
+    ret = njs_value_property(vm, value, njs_value_arg(&value_of),
+                             retval);
+    if (njs_slow_path(ret != NJS_OK)) {
+        return ret;
+    }
+
+    if (!njs_is_function(retval)) {
+        njs_type_error(vm, "object.valueOf is not a function");
+        return NJS_ERROR;
+    }
+
+    return njs_function_apply(vm, njs_function(retval), value, 1, retval);
+}
+
+
 njs_int_t
 njs_value_length(njs_vm_t *vm, njs_value_t *value, int64_t *length)
 {
index 1cf808a1b1cdbe2987f35d00e962b3125f945776..b8aa77397579132f4aa0cfb4115c743a85a488cc 100644 (file)
@@ -1053,6 +1053,7 @@ njs_array_t *njs_value_enumerate(njs_vm_t *vm, njs_value_t *value,
     njs_object_enum_t kind, njs_object_enum_type_t type, njs_bool_t all);
 njs_array_t *njs_value_own_enumerate(njs_vm_t *vm, njs_value_t *value,
     njs_object_enum_t kind, njs_object_enum_type_t type, njs_bool_t all);
+njs_int_t njs_value_of(njs_vm_t *vm, njs_value_t *value, njs_value_t *retval);
 njs_int_t njs_value_length(njs_vm_t *vm, njs_value_t *value, int64_t *dst);
 const char *njs_type_string(njs_value_type_t type);
 
index ea0055749f4e7b45fe29006ec3d96e6410017854..76a4fa85befcbf4543df6775eae374328feb4f63 100644 (file)
@@ -18580,6 +18580,29 @@ static njs_unit_test_t  njs_test[] =
     { njs_str("var buf = Buffer.from('α'); njs.dump(buf)"),
       njs_str("Buffer [206,177]") },
 
+    { njs_str("var arr = new Array(1,2,3); arr.valueOf = () => arr;"
+              "njs.dump(Buffer.from(arr))"),
+      njs_str("Buffer [1,2,3]") },
+
+    { njs_str("var obj = new Object(); obj.valueOf = () => obj;"
+              "Buffer.from(obj)"),
+      njs_str("TypeError: first argument object is not a string or Buffer-like object") },
+
+    { njs_str("var obj = new Object(); obj.valueOf = () => undefined;"
+              "njs.dump(Buffer.from(obj))"),
+      njs_str("TypeError: first argument undefined is not a string or Buffer-like object") },
+
+    { njs_str("var arr = new Array(1,2,3); arr.valueOf = () => null;"
+              "njs.dump(Buffer.from(arr))"),
+      njs_str("Buffer [1,2,3]") },
+
+    { njs_str("var obj = new Object(); obj.valueOf = () => new Array(1,2,3);"
+              "njs.dump(Buffer.from(obj))"),
+      njs_str("Buffer [1,2,3]") },
+
+    { njs_str("njs.dump(Buffer.from(new String('test')))"),
+      njs_str("Buffer [116,101,115,116]") },
+
     { njs_str("["
              " ['6576696c', 'hex'],"
              " ['ZXZpbA==', 'base64'],"