]> git.kaiwu.me - njs.git/commitdiff
encodeURI() and encodeURIComponent() functions.
authorIgor Sysoev <igor@sysoev.ru>
Tue, 30 Aug 2016 09:02:31 +0000 (12:02 +0300)
committerIgor Sysoev <igor@sysoev.ru>
Tue, 30 Aug 2016 09:02:31 +0000 (12:02 +0300)
njs/njs_builtin.c
njs/njs_generator.c
njs/njs_lexer_keyword.c
njs/njs_parser.c
njs/njs_parser.h
njs/njs_string.c
njs/njs_string.h
njs/njs_vm.h
njs/test/njs_unit_test.c

index e38379eba5b94015ebdd935b6ca6d75d0b1c1a20..16870f6358518ba2074af9ad832b9b7bb703ed18 100644 (file)
@@ -82,12 +82,14 @@ njs_builtin_objects_create(njs_vm_t *vm)
     };
 
     static const njs_object_init_t    *function_init[] = {
-        &njs_eval_function_init,
-        NULL,
-        NULL,
-        NULL,
-        NULL,
-        NULL,
+        &njs_eval_function_init,      /* eval               */
+        NULL,                         /* toString           */
+        NULL,                         /* isNaN              */
+        NULL,                         /* isFinite           */
+        NULL,                         /* parseInt           */
+        NULL,                         /* parseFloat         */
+        NULL,                         /* encodeURI          */
+        NULL,                         /* encodeURIComponent */
     };
 
     static const njs_function_init_t  native_functions[] = {
@@ -99,6 +101,8 @@ njs_builtin_objects_create(njs_vm_t *vm)
         { njs_number_parse_int,
           { NJS_SKIP_ARG, NJS_STRING_ARG, NJS_INTEGER_ARG } },
         { njs_number_parse_float,          { NJS_SKIP_ARG, NJS_STRING_ARG } },
+        { njs_string_encode_uri,           { NJS_SKIP_ARG, NJS_STRING_ARG } },
+        { njs_string_encode_uri_component, { NJS_SKIP_ARG, NJS_STRING_ARG } },
     };
 
     static const njs_object_prop_t    null_proto_property = {
index 5f8fa52c2884d0d05eced6431a48a7c6ce614713..5f210bc02196e103c96eee3f5d9c84c23f6a614b 100644 (file)
@@ -300,6 +300,8 @@ njs_generator(njs_vm_t *vm, njs_parser_t *parser, njs_parser_node_t *node)
     case NJS_TOKEN_IS_FINITE:
     case NJS_TOKEN_PARSE_INT:
     case NJS_TOKEN_PARSE_FLOAT:
+    case NJS_TOKEN_ENCODE_URI:
+    case NJS_TOKEN_ENCODE_URI_COMPONENT:
         return njs_generate_builtin_object(vm, parser, node);
 
     case NJS_TOKEN_FUNCTION:
index d6d39fd8e72e87125da3776e95aca7bd1134daea..f58d557e0bd75ab41f008fcdb19593fbfc720c5a 100644 (file)
@@ -93,6 +93,8 @@ static const njs_keyword_t  njs_keywords[] = {
     { nxt_string("isFinite"),      NJS_TOKEN_IS_FINITE, 0 },
     { nxt_string("parseInt"),      NJS_TOKEN_PARSE_INT, 0 },
     { nxt_string("parseFloat"),    NJS_TOKEN_PARSE_FLOAT, 0 },
+    { nxt_string("encodeURI"),     NJS_TOKEN_ENCODE_URI, 0 },
+    { nxt_string("encodeURIComponent"),  NJS_TOKEN_ENCODE_URI_COMPONENT, 0 },
 
     /* Reserved words. */
 
index c5635f66d7188dec09f982f2749207372ee567e8..96c5f0d6f802c9a973f79446563e5d9acc02bd77 100644 (file)
@@ -1671,6 +1671,8 @@ njs_parser_terminal(njs_vm_t *vm, njs_parser_t *parser, njs_token_t token)
     case NJS_TOKEN_IS_FINITE:
     case NJS_TOKEN_PARSE_INT:
     case NJS_TOKEN_PARSE_FLOAT:
+    case NJS_TOKEN_ENCODE_URI:
+    case NJS_TOKEN_ENCODE_URI_COMPONENT:
         return njs_parser_builtin_function(vm, parser, node);
 
     default:
index 312dfa64294c775fb7bd4bdffa507d40542becb8..2b93688f7b52b50829ead43ea564015d551a0a26 100644 (file)
@@ -181,6 +181,8 @@ typedef enum {
     NJS_TOKEN_IS_FINITE,
     NJS_TOKEN_PARSE_INT,
     NJS_TOKEN_PARSE_FLOAT,
+    NJS_TOKEN_ENCODE_URI,
+    NJS_TOKEN_ENCODE_URI_COMPONENT,
 
     NJS_TOKEN_RESERVED,
 } njs_token_t;
index 5efec84983311bfc04355ce6c3a2cafedd554165..82737bb782ce696f46ec03d10e50f148e9b8ed36 100644 (file)
@@ -45,6 +45,8 @@ static njs_ret_t njs_string_match_multiple(njs_vm_t *vm, njs_value_t *args,
     njs_regexp_pattern_t *pattern);
 static njs_ret_t njs_string_split_part_add(njs_vm_t *vm, njs_array_t *array,
     u_char *start, size_t size, nxt_uint_t utf8);
+static njs_ret_t njs_string_encode(njs_vm_t *vm, njs_value_t *value,
+    const uint32_t *escape);
 
 
 njs_ret_t
@@ -2105,6 +2107,137 @@ const njs_object_init_t  njs_string_prototype_init = {
 };
 
 
+/*
+ * encodeURI(string)
+ */
+
+njs_ret_t
+njs_string_encode_uri(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs,
+    njs_index_t unused)
+{
+    static const uint32_t  escape[] = {
+        0xffffffff,  /* 1111 1111 1111 1111  1111 1111 1111 1111 */
+
+                     /* ?>=< ;:98 7654 3210  /.-, +*)( '&%$ #"!  */
+        0x50000025,  /* 0101 0000 0000 0000  0000 0000 0010 0101 */
+
+                     /* _^]\ [ZYX WVUT SRQP  ONML KJIH GFED CBA@ */
+        0x78000000,  /* 0111 1000 0000 0000  0000 0000 0000 0000 */
+
+                     /*  ~}| {zyx wvut srqp  onml kjih gfed cba` */
+        0xb8000001,  /* 1011 1000 0000 0000  0000 0000 0000 0001 */
+
+        0xffffffff,  /* 1111 1111 1111 1111  1111 1111 1111 1111 */
+        0xffffffff,  /* 1111 1111 1111 1111  1111 1111 1111 1111 */
+        0xffffffff,  /* 1111 1111 1111 1111  1111 1111 1111 1111 */
+        0xffffffff,  /* 1111 1111 1111 1111  1111 1111 1111 1111 */
+    };
+
+    if (nargs > 1) {
+        return njs_string_encode(vm, &args[1], escape);
+    }
+
+    vm->retval = njs_string_void;
+
+    return NXT_OK;
+}
+
+
+/*
+ * encodeURIComponent(string)
+ */
+
+njs_ret_t
+njs_string_encode_uri_component(njs_vm_t *vm, njs_value_t *args,
+    nxt_uint_t nargs, njs_index_t unused)
+{
+    static const uint32_t  escape[] = {
+        0xffffffff,  /* 1111 1111 1111 1111  1111 1111 1111 1111 */
+
+                     /* ?>=< ;:98 7654 3210  /.-, +*)( '&%$ #"!  */
+        0xfc00987d,  /* 1111 1100 0000 0000  1001 1000 0111 1101 */
+
+                     /* _^]\ [ZYX WVUT SRQP  ONML KJIH GFED CBA@ */
+        0x78000001,  /* 0111 1000 0000 0000  0000 0000 0000 0001 */
+
+                     /*  ~}| {zyx wvut srqp  onml kjih gfed cba` */
+        0xb8000001,  /* 1011 1000 0000 0000  0000 0000 0000 0001 */
+
+        0xffffffff,  /* 1111 1111 1111 1111  1111 1111 1111 1111 */
+        0xffffffff,  /* 1111 1111 1111 1111  1111 1111 1111 1111 */
+        0xffffffff,  /* 1111 1111 1111 1111  1111 1111 1111 1111 */
+        0xffffffff,  /* 1111 1111 1111 1111  1111 1111 1111 1111 */
+    };
+
+    if (nargs > 1) {
+        return njs_string_encode(vm, &args[1], escape);
+    }
+
+    vm->retval = njs_string_void;
+
+    return NXT_OK;
+}
+
+
+static njs_ret_t
+njs_string_encode(njs_vm_t *vm, njs_value_t *value, const uint32_t *escape)
+{
+    u_char               byte, *src, *dst;
+    size_t               n, size;
+    njs_string_prop_t    string;
+    static const u_char  hex[16] = "0123456789ABCDEF";
+
+    nxt_prefetch(escape);
+
+    (void) njs_string_prop(&string, value);
+
+    src = string.start;
+    n = 0;
+
+    for (size = string.size; size != 0; size--) {
+        byte = *src++;
+
+        if ((escape[byte >> 5] & ((uint32_t) 1 << (byte & 0x1f))) != 0) {
+            n += 2;
+        }
+    }
+
+    if (n == 0) {
+        /* GC: retain src. */
+        vm->retval = *value;
+        return NXT_OK;
+    }
+
+    size = string.size + n;
+
+    dst = njs_string_alloc(vm, &vm->retval, size, size);
+    if (nxt_slow_path(dst == NULL)) {
+        return NXT_ERROR;
+    }
+
+    size = string.size;
+    src = string.start;
+
+    do {
+        byte = *src++;
+
+        if ((escape[byte >> 5] & ((uint32_t) 1 << (byte & 0x1f))) != 0) {
+            *dst++ = '%';
+            *dst++ = hex[byte >> 4];
+            *dst++ = hex[byte & 0xf];
+
+        } else {
+            *dst++ = byte;
+        }
+
+        size--;
+
+    } while (size != 0);
+
+    return NXT_OK;
+}
+
+
 static nxt_int_t
 njs_values_hash_test(nxt_lvlhsh_query_t *lhq, void *data)
 {
index e651c7056328a2c1fa493a207b8fe2b7817210bd..45e1d4416f477753be15356aa6aed98f813a1f0c 100644 (file)
@@ -104,6 +104,10 @@ nxt_noinline uint32_t njs_string_index(njs_string_prop_t *string,
 njs_ret_t njs_primitive_value_to_string(njs_vm_t *vm, njs_value_t *dst,
     const njs_value_t *src);
 double njs_string_to_number(njs_value_t *value, nxt_bool_t exact);
+njs_ret_t njs_string_encode_uri(njs_vm_t *vm, njs_value_t *args,
+    nxt_uint_t nargs, njs_index_t unused);
+njs_ret_t njs_string_encode_uri_component(njs_vm_t *vm, njs_value_t *args,
+    nxt_uint_t nargs, njs_index_t unused);
 
 njs_index_t njs_value_index(njs_vm_t *vm, njs_parser_t *parser,
     const njs_value_t *src);
index 79369145f41f55110dcf2db4097d8b8b736e497f..e2ff1143b83adcec9cb4c128a2de336fefc78344 100644 (file)
@@ -668,7 +668,7 @@ typedef enum {
 
 
 enum njs_prototypes_e {
-    NJS_PROTOTYPE_OBJECT =     0,
+    NJS_PROTOTYPE_OBJECT = 0,
     NJS_PROTOTYPE_ARRAY,
     NJS_PROTOTYPE_BOOLEAN,
     NJS_PROTOTYPE_NUMBER,
@@ -698,19 +698,21 @@ enum njs_constructor_e {
 
 
 enum njs_object_e {
-    NJS_OBJECT_MATH =          0,
+    NJS_OBJECT_MATH = 0,
 #define NJS_OBJECT_MAX         (NJS_OBJECT_MATH + 1)
 };
 
 
 enum njs_function_e {
-    NJS_FUNCTION_EVAL =        0,
-    NJS_FUNCTION_TO_STRING =   1,
-    NJS_FUNCTION_IS_NAN =      2,
-    NJS_FUNCTION_IS_FINITE =   3,
-    NJS_FUNCTION_PARSE_INT =   4,
-    NJS_FUNCTION_PARSE_FLOAT = 5,
-#define NJS_FUNCTION_MAX       (NJS_FUNCTION_PARSE_FLOAT + 1)
+    NJS_FUNCTION_EVAL = 0,
+    NJS_FUNCTION_TO_STRING,
+    NJS_FUNCTION_IS_NAN,
+    NJS_FUNCTION_IS_FINITE,
+    NJS_FUNCTION_PARSE_INT,
+    NJS_FUNCTION_PARSE_FLOAT,
+    NJS_FUNCTION_STRING_ENCODE_URI,
+    NJS_FUNCTION_STRING_ENCODE_URI_COMPONENT,
+#define NJS_FUNCTION_MAX       (NJS_FUNCTION_STRING_ENCODE_URI_COMPONENT + 1)
 };
 
 
index 2fbed344b7d6ee930ec57323878a55f354f660d5..2ca4250e3914e89c0d88e285f530acbccb1690cf 100644 (file)
@@ -3297,6 +3297,18 @@ static njs_unit_test_t  njs_test[] =
     { nxt_string("'0123456789'.split('').reverse().join('')"),
       nxt_string("9876543210") },
 
+    { nxt_string("encodeURI()"),
+      nxt_string("undefined")},
+
+    { nxt_string("encodeURI('012абв')"),
+      nxt_string("012%D0%B0%D0%B1%D0%B2")},
+
+    { nxt_string("encodeURI('~}|{`_^]\\\\[@?>=<;:/.-,+*)(\\\'&%$#\"! ')"),
+      nxt_string("~%7D%7C%7B%60_%5E%5D%5C%5B@?%3E=%3C;:/.-,+*)('&%25$#%22!%20")},
+
+    { nxt_string("encodeURIComponent('~}|{`_^]\\\\[@?>=<;:/.-,+*)(\\\'&%$#\"! ')"),
+      nxt_string("~%7D%7C%7B%60_%5E%5D%5C%5B%40%3F%3E%3D%3C%3B%3A%2F.-%2C%2B*)('%26%25%24%23%22!%20")},
+
     /* Functions. */
 
     { nxt_string("return"),