Skip to content

Commit ef5eae9

Browse files
committed
add base64 encoder, fix base64 decoder bug
1 parent c8592db commit ef5eae9

3 files changed

Lines changed: 79 additions & 6 deletions

File tree

deps/picotest/picotest.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@
44
#include <string.h>
55
#include "picotest.h"
66

7-
#define _STR(s) #s
8-
#define STR(s) _STR(s)
7+
#define _STR(...) #__VA_ARGS__
8+
#define STR(...) _STR(__VA_ARGS__)
99

1010
static int numtests_in_subtest, subtest_success;
1111
static int all_success = 1;

include/h2o.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -271,6 +271,7 @@ uv_buf_t h2o_strdup(h2o_mempool_t *pool, const char *s, size_t len);
271271
uv_buf_t h2o_sprintf(h2o_mempool_t *pool, const char *fmt, ...) __attribute__((format (printf, 2, 3)));
272272
size_t h2o_snprintf(char *buf, size_t bufsz, const char *fmt, ...) __attribute__((format (printf, 3, 4)));
273273
uv_buf_t h2o_decode_base64url(h2o_mempool_t *pool, const char *src, size_t len);
274+
void h2o_base64_encode(char *dst, const uint8_t *src, size_t len, int url_encoded);
274275
void h2o_time2str_rfc1123(char *buf, time_t time);
275276
void h2o_time2str_log(char *buf, time_t time);
276277
const char *h2o_get_filext(const char *path, size_t len);

src/util.c

Lines changed: 76 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -145,10 +145,10 @@ size_t h2o_snprintf(char *buf, size_t bufsz, const char *fmt, ...)
145145

146146
static uint32_t decode_base64url_quad(const char *src)
147147
{
148+
const char *src_end = src + 4;
148149
uint32_t decoded = 0;
149-
int i;
150150

151-
for (i = 0; i != 4; ++i, ++src, decoded <<= 6) {
151+
while (1) {
152152
if ('A' <= *src && *src <= 'Z') {
153153
decoded |= *src - 'A';
154154
} else if ('a' <= *src && *src <= 'z') {
@@ -168,6 +168,9 @@ static uint32_t decode_base64url_quad(const char *src)
168168
} else {
169169
return UINT32_MAX;
170170
}
171+
if (++src == src_end)
172+
break;
173+
decoded <<= 6;
171174
}
172175

173176
return decoded;
@@ -203,7 +206,7 @@ uv_buf_t h2o_decode_base64url(h2o_mempool_t *pool, const char *src, size_t len)
203206
remaining_input[1] = *src++;
204207
remaining_input[2] = 'A';
205208
remaining_input[3] = 'A';
206-
if ((t = decode_base64url_quad(src)) == UINT32_MAX)
209+
if ((t = decode_base64url_quad(remaining_input)) == UINT32_MAX)
207210
goto Error;
208211
*dst++ = t >> 16;
209212
break;
@@ -212,7 +215,7 @@ uv_buf_t h2o_decode_base64url(h2o_mempool_t *pool, const char *src, size_t len)
212215
remaining_input[1] = *src++;
213216
remaining_input[2] = *src++;
214217
remaining_input[3] = 'A';
215-
if ((t = decode_base64url_quad(src)) == UINT32_MAX)
218+
if ((t = decode_base64url_quad(remaining_input)) == UINT32_MAX)
216219
goto Error;
217220
*dst++ = t >> 16;
218221
*dst++ = t >> 8;
@@ -227,6 +230,50 @@ uv_buf_t h2o_decode_base64url(h2o_mempool_t *pool, const char *src, size_t len)
227230
return uv_buf_init(NULL, 0);
228231
}
229232

233+
void h2o_base64_encode(char *dst, const uint8_t *src, size_t len, int url_encoded)
234+
{
235+
static const char *MAP =
236+
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
237+
"abcdefghijklmnopqrstuvwxyz"
238+
"0123456789+/";
239+
static const char *MAP_URL_ENCODED =
240+
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
241+
"abcdefghijklmnopqrstuvwxyz"
242+
"0123456789-_";
243+
244+
const char *map = url_encoded ? MAP_URL_ENCODED : MAP;
245+
uint32_t quad;
246+
247+
for (; len >= 3; src += 3, len -= 3) {
248+
quad = ((uint32_t)src[0] << 16)
249+
| ((uint32_t)src[1] << 8)
250+
| src[2];
251+
*dst++ = map[quad >> 18];
252+
*dst++ = map[(quad >> 12) & 63];
253+
*dst++ = map[(quad >> 6) & 63];
254+
*dst++ = map[quad & 63];
255+
}
256+
if (len != 0) {
257+
quad = (uint32_t)src[0] << 16;
258+
*dst++ = map[quad >> 18];
259+
if (len == 2) {
260+
quad |= (uint32_t)src[1] << 8;
261+
*dst++ = map[(quad >> 12) & 63];
262+
*dst++ = map[(quad >> 6) & 63];
263+
if (! url_encoded)
264+
*dst++ = '=';
265+
} else {
266+
*dst++ = map[(quad >> 12) & 63];
267+
if (! url_encoded) {
268+
*dst++ = '=';
269+
*dst++ = '=';
270+
}
271+
}
272+
}
273+
274+
*dst = '\0';
275+
}
276+
230277
void h2o_time2str_rfc1123(char *buf, time_t time)
231278
{
232279
struct tm gmt;
@@ -438,3 +485,28 @@ void h2o_send_error(h2o_req_t *req, int status, const char *reason, const char *
438485

439486
h2o_send_inline(req, body, SIZE_MAX);
440487
}
488+
489+
#ifdef PICOTEST_FUNCS
490+
491+
#include "picotest.h"
492+
493+
void util_test(void)
494+
{
495+
h2o_mempool_t pool;
496+
497+
h2o_mempool_init(&pool);
498+
499+
note("base64");
500+
{
501+
char buf[256];
502+
uv_buf_t src = { H2O_STRLIT("The quick brown fox jumps over the lazy dog.") }, decoded;
503+
h2o_base64_encode(buf, (const uint8_t*)src.base, src.len, 1);
504+
ok(strcmp(buf, "VGhlIHF1aWNrIGJyb3duIGZveCBqdW1wcyBvdmVyIHRoZSBsYXp5IGRvZy4") == 0);
505+
decoded = h2o_decode_base64url(&pool, buf, strlen(buf));
506+
ok(src.len == decoded.len);
507+
ok(strcmp(decoded.base, src.base) == 0);
508+
}
509+
h2o_mempool_clear(&pool);
510+
}
511+
512+
#endif

0 commit comments

Comments
 (0)