Added base64 encoding for byte strings.
diff --git a/njs/njs_string.c b/njs/njs_string.c
index 972cfab..7842b4b 100644
--- a/njs/njs_string.c
+++ b/njs/njs_string.c
@@ -79,6 +79,8 @@
 } 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 @@
     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 @@
 }
 
 
+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 --git a/njs/njs_string.h b/njs/njs_string.h
index 0735d33..6e9c82c 100644
--- a/njs/njs_string.h
+++ b/njs/njs_string.h
@@ -124,6 +124,10 @@
     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);