Mercurial > njs
changeset 160:d63ecb57f164
encodeURI() and encodeURIComponent() functions.
| author | Igor Sysoev <igor@sysoev.ru> |
|---|---|
| date | Tue, 30 Aug 2016 12:02:31 +0300 |
| parents | 7cce82b6b40b |
| children | 323f00dc9879 |
| files | 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 |
| diffstat | 9 files changed, 178 insertions(+), 15 deletions(-) [+] |
line wrap: on
line diff
--- a/njs/njs_builtin.c Tue Aug 16 19:13:41 2016 +0300 +++ b/njs/njs_builtin.c Tue Aug 30 12:02:31 2016 +0300 @@ -82,12 +82,14 @@ }; 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_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 = {
--- a/njs/njs_generator.c Tue Aug 16 19:13:41 2016 +0300 +++ b/njs/njs_generator.c Tue Aug 30 12:02:31 2016 +0300 @@ -300,6 +300,8 @@ 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:
--- a/njs/njs_lexer_keyword.c Tue Aug 16 19:13:41 2016 +0300 +++ b/njs/njs_lexer_keyword.c Tue Aug 30 12:02:31 2016 +0300 @@ -93,6 +93,8 @@ { 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. */
--- a/njs/njs_parser.c Tue Aug 16 19:13:41 2016 +0300 +++ b/njs/njs_parser.c Tue Aug 30 12:02:31 2016 +0300 @@ -1671,6 +1671,8 @@ 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:
--- a/njs/njs_parser.h Tue Aug 16 19:13:41 2016 +0300 +++ b/njs/njs_parser.h Tue Aug 30 12:02:31 2016 +0300 @@ -181,6 +181,8 @@ 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;
--- a/njs/njs_string.c Tue Aug 16 19:13:41 2016 +0300 +++ b/njs/njs_string.c Tue Aug 30 12:02:31 2016 +0300 @@ -45,6 +45,8 @@ 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 @@ }; +/* + * 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) {
--- a/njs/njs_string.h Tue Aug 16 19:13:41 2016 +0300 +++ b/njs/njs_string.h Tue Aug 30 12:02:31 2016 +0300 @@ -104,6 +104,10 @@ 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);
--- a/njs/njs_vm.h Tue Aug 16 19:13:41 2016 +0300 +++ b/njs/njs_vm.h Tue Aug 30 12:02:31 2016 +0300 @@ -668,7 +668,7 @@ 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_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) };
--- a/njs/test/njs_unit_test.c Tue Aug 16 19:13:41 2016 +0300 +++ b/njs/test/njs_unit_test.c Tue Aug 30 12:02:31 2016 +0300 @@ -3297,6 +3297,18 @@ { 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"),
