@@ -145,10 +145,10 @@ size_t h2o_snprintf(char *buf, size_t bufsz, const char *fmt, ...)
145145
146146static 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+
230277void 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