[njs] Added base64 encoding for byte strings.

Dmitry Volyntsev xeioex at nginx.com
Fri Mar 30 12:47:10 UTC 2018


details:   http://hg.nginx.org/njs/rev/d35406201c78
branches:  
changeset: 474:d35406201c78
user:      Dmitry Volyntsev <xeioex at nginx.com>
date:      Fri Mar 30 15:46:38 2018 +0300
description:
Added base64 encoding for byte strings.

diffstat:

 njs/njs_string.c |  134 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 njs/njs_string.h |    4 +
 2 files changed, 138 insertions(+), 0 deletions(-)

diffs (172 lines):

diff -r c685137c4e57 -r d35406201c78 njs/njs_string.c
--- a/njs/njs_string.c	Fri Mar 30 15:46:38 2018 +0300
+++ b/njs/njs_string.c	Fri Mar 30 15:46:38 2018 +0300
@@ -79,6 +79,8 @@ typedef struct {
 } njs_string_replace_t;
 
 
+static void njs_encode_base64_core(nxt_str_t *dst, const nxt_str_t *src,
+    const u_char *basis, nxt_uint_t padding);
 static nxt_noinline void njs_string_slice_prop(njs_string_prop_t *string,
     njs_slice_prop_t *slice, njs_value_t *args, nxt_uint_t nargs);
 static nxt_noinline void njs_string_slice_args(njs_slice_prop_t *slice,
@@ -119,6 +121,9 @@ static njs_ret_t njs_string_decode(njs_v
     const uint32_t *reserve);
 
 
+#define njs_base64_encoded_length(len)  (((len + 2) / 3) * 4)
+
+
 njs_ret_t
 njs_string_create(njs_vm_t *vm, njs_value_t *value, u_char *start,
     uint32_t size, uint32_t length)
@@ -275,6 +280,135 @@ njs_string_hex(njs_vm_t *vm, njs_value_t
 }
 
 
+static void
+njs_encode_base64(nxt_str_t *dst, const nxt_str_t *src)
+{
+    static u_char   basis64[] =
+        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+    njs_encode_base64_core(dst, src, basis64, 1);
+}
+
+
+static void
+njs_encode_base64url(nxt_str_t *dst, const nxt_str_t *src)
+{
+    static u_char   basis64[] =
+        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
+
+    njs_encode_base64_core(dst, src, basis64, 0);
+}
+
+
+static void
+njs_encode_base64_core(nxt_str_t *dst, const nxt_str_t *src,
+    const u_char *basis, nxt_bool_t padding)
+{
+   u_char  *d, *s, c0, c1, c2;
+   size_t  len;
+
+    len = src->length;
+    s = src->start;
+    d = dst->start;
+
+    while (len > 2) {
+        c0 = s[0];
+        c1 = s[1];
+        c2 = s[2];
+
+        *d++ = basis[c0 >> 2];
+        *d++ = basis[((c0 & 0x03) << 4) | (c1 >> 4)];
+        *d++ = basis[((c1 & 0x0f) << 2) | (c2 >> 6)];
+        *d++ = basis[c2 & 0x3f];
+
+        s += 3;
+        len -= 3;
+    }
+
+    if (len > 0) {
+        c0 = s[0];
+        *d++ = basis[c0 >> 2];
+
+        if (len == 1) {
+            *d++ = basis[(c0 & 0x03) << 4];
+            if (padding) {
+                *d++ = '=';
+                *d++ = '=';
+            }
+
+        } else {
+            c1 = s[1];
+
+            *d++ = basis[((c0 & 0x03) << 4) | (c1 >> 4)];
+            *d++ = basis[(c1 & 0x0f) << 2];
+
+            if (padding) {
+                *d++ = '=';
+            }
+        }
+
+    }
+
+    dst->length = d - dst->start;
+}
+
+
+nxt_noinline njs_ret_t
+njs_string_base64(njs_vm_t *vm, njs_value_t *value, const nxt_str_t *src)
+{
+    nxt_str_t  dst;
+
+    if (nxt_slow_path(src->length == 0)) {
+        vm->retval = njs_string_empty;
+        return NXT_OK;
+    }
+
+    dst.length = njs_base64_encoded_length(src->length);
+
+    dst.start = njs_string_alloc(vm, &vm->retval, dst.length, dst.length);
+    if (nxt_slow_path(dst.start == NULL)) {
+        njs_memory_error(vm);
+        return NXT_ERROR;
+    }
+
+    njs_encode_base64(&dst, src);
+
+    return NXT_OK;
+}
+
+
+nxt_noinline njs_ret_t
+njs_string_base64url(njs_vm_t *vm, njs_value_t *value, const nxt_str_t *src)
+{
+    size_t     padding;
+    nxt_str_t  dst;
+
+    if (nxt_slow_path(src->length == 0)) {
+        vm->retval = njs_string_empty;
+        return NXT_OK;
+    }
+
+    padding = src->length % 3;
+
+    /*
+     * Calculating the padding length: 0 -> 0, 1 -> 2, 2 -> 1.
+     */
+    padding = (4 >> padding) & 0x03;
+
+    dst.length = njs_base64_encoded_length(src->length) - padding;
+
+    dst.start = njs_string_alloc(vm, &vm->retval, dst.length, dst.length);
+    if (nxt_slow_path(dst.start == NULL)) {
+        njs_memory_error(vm);
+        return NXT_ERROR;
+    }
+
+    njs_encode_base64url(&dst, src);
+
+    return NXT_OK;
+}
+
+
 void
 njs_string_copy(njs_value_t *dst, njs_value_t *src)
 {
diff -r c685137c4e57 -r d35406201c78 njs/njs_string.h
--- a/njs/njs_string.h	Fri Mar 30 15:46:38 2018 +0300
+++ b/njs/njs_string.h	Fri Mar 30 15:46:38 2018 +0300
@@ -124,6 +124,10 @@ njs_ret_t njs_string_new(njs_vm_t *vm, n
     uint32_t size, uint32_t length);
 njs_ret_t njs_string_hex(njs_vm_t *vm, njs_value_t *value,
     const nxt_str_t *src);
+njs_ret_t njs_string_base64(njs_vm_t *vm, njs_value_t *value,
+	const nxt_str_t *src);
+njs_ret_t njs_string_base64url(njs_vm_t *vm, njs_value_t *value,
+	const nxt_str_t *src);
 void njs_string_copy(njs_value_t *dst, njs_value_t *src);
 njs_ret_t njs_string_validate(njs_vm_t *vm, njs_string_prop_t *string,
     njs_value_t *value);


More information about the nginx-devel mailing list