Переглянути джерело

export base64 encoding/decoding to public API (#1038)

bel2125 3 роки тому
батько
коміт
65a80ce100
7 змінених файлів з 169 додано та 89 видалено
  1. 36 0
      docs/api/mg_base64_X.md
  2. 16 0
      include/civetweb.h
  3. 14 7
      src/civetweb.c
  4. 8 11
      src/mod_lua.inl
  5. 1 0
      unittest/CMakeLists.txt
  6. 0 71
      unittest/private.c
  7. 94 0
      unittest/public_func.c

+ 36 - 0
docs/api/mg_base64_X.md

@@ -0,0 +1,36 @@
+# Civetweb API Reference
+
+### `mg_base64_encode( src, src_len, dst, dst_len );`
+### `mg_base64_decode( src, src_len, dst, dst_len );`
+
+### Parameters `base64_encode`
+
+| Parameter | Type | Description |
+| :--- | :--- | :--- |
+|**`src`**|`const unsigned char *`|Source buffer containing bytes to be encoded into BASE-64 code.|
+|**`src_len`**|`size_t`|Number of bytes in source buffer to be encoded.|
+|**`dst`**|`char *`|Destination string buffer.|
+|**`dst_len`**|`size_t *`|Pointer to a variable containing the available size of the destination buffer in bytes.|
+
+### Parameters `base64_decode`
+
+| Parameter | Type | Description |
+| :--- | :--- | :--- |
+|**`src`**|`const char *`|Source string containing BASE-64 encoded data.|
+|**`src_len`**|`size_t`|Number of bytes in the source buffer to be decoded.|
+|**`dst`**|`unsigned char *`|Destination byte buffer.|
+|**`dst_len`**|`size_t *`|Pointer to a variable containing the available size of the destination buffer in bytes.|
+
+### Return Value
+
+| Type | Description |
+| :--- | :--- |
+|`int`|Error information. -1 indicates success.|
+
+### Description
+
+The function `mg_base64_encode()` encodes the source buffer into the destination buffer using BASE-64 encoding.
+The function `mg_base64_decode()` reads a BASE-64 encoded source buffer and decodes it into the destination buffer.
+Both functions return -1 on success.
+If the destination buffer is not big enough, the functions return 0.
+If the source buffer supplied to `mg_base64_decode()` contains invalid characters, the return value is the position of this character. 

+ 16 - 0
include/civetweb.h

@@ -1341,6 +1341,22 @@ CIVETWEB_API int mg_url_decode(const char *src,
 CIVETWEB_API int mg_url_encode(const char *src, char *dst, size_t dst_len);
 
 
+/* BASE64-encode input buffer into destination buffer.
+   returns -1 on OK. */
+CIVETWEB_API int mg_base64_encode(const unsigned char *src,
+                                  size_t src_len,
+                                  char *dst,
+                                  size_t *dst_len);
+
+
+/* BASE64-decode input buffer into destination buffer.
+   returns -1 on OK. */
+CIVETWEB_API int mg_base64_decode(const char *src,
+                                  size_t src_len,
+                                  unsigned char *dst,
+                                  size_t *dst_len);
+
+
 /* MD5 hash given strings.
    Buffer 'buf' must be 33 bytes long. Varargs is a NULL terminated list of
    ASCIIz strings. When function returns, buf will contain human-readable

+ 14 - 7
src/civetweb.c

@@ -7216,12 +7216,16 @@ mg_get_cookie(const char *cookie_header,
 }
 
 
-static int
-base64_encode(const unsigned char *src, int src_len, char *dst, size_t *dst_len)
+int
+mg_base64_encode(const unsigned char *src,
+                 size_t src_len,
+                 char *dst,
+                 size_t *dst_len)
 {
 	static const char *b64 =
 	    "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
-	int i, j, a, b, c;
+	size_t i, j;
+	int a, b, c;
 
 	if (dst_len != NULL) {
 		/* Expected length including 0 termination: */
@@ -7290,10 +7294,13 @@ b64reverse(char letter)
 }
 
 
-static int
-base64_decode(const unsigned char *src, int src_len, char *dst, size_t *dst_len)
+int
+mg_base64_decode(const char *src,
+                 size_t src_len,
+                 unsigned char *dst,
+                 size_t *dst_len)
 {
-	int i;
+	size_t i;
 	unsigned char a, b, c, d;
 	size_t dst_len_limit = (size_t)-1;
 	size_t dst_len_used = 0;
@@ -12446,7 +12453,7 @@ send_websocket_handshake(struct mg_connection *conn, const char *websock_key)
 	SHA1_Init(&sha_ctx);
 	SHA1_Update(&sha_ctx, (unsigned char *)buf, (uint32_t)strlen(buf));
 	SHA1_Final((unsigned char *)sha, &sha_ctx);
-	base64_encode((unsigned char *)sha, sizeof(sha), b64_sha, &dst_len);
+	mg_base64_encode((unsigned char *)sha, sizeof(sha), b64_sha, &dst_len);
 	mg_printf(conn,
 	          "HTTP/1.1 101 Switching Protocols\r\n"
 	          "Upgrade: websocket\r\n"

+ 8 - 11
src/mod_lua.inl

@@ -1519,10 +1519,10 @@ lsp_base64_encode(lua_State *L)
 			size_t dst_len = text_len * 8 / 6 + 4;
 			char *dst = (char *)mg_malloc_ctx(dst_len, ctx);
 			if (dst) {
-				base64_encode((const unsigned char *)text,
-				              (int)text_len,
-				              dst,
-				              &dst_len);
+				mg_base64_encode((const unsigned char *)text,
+				                 (int)text_len,
+				                 dst,
+				                 &dst_len);
 				lua_pushlstring(L, dst, dst_len);
 				mg_free(dst);
 			} else {
@@ -1547,7 +1547,7 @@ lsp_base64_decode(lua_State *L)
 	const char *text;
 	size_t text_len, dst_len;
 	int ret;
-	char *dst;
+	unsigned char *dst;
 	struct mg_context *ctx;
 
 	lua_pushlightuserdata(L, (void *)&lua_regkey_ctx);
@@ -1557,18 +1557,15 @@ lsp_base64_decode(lua_State *L)
 	if (num_args == 1) {
 		text = lua_tolstring(L, 1, &text_len);
 		if (text) {
-			dst = (char *)mg_malloc_ctx(text_len, ctx);
+			dst = (unsigned char *)mg_malloc_ctx(text_len, ctx);
 			if (dst) {
-				ret = base64_decode((const unsigned char *)text,
-				                    (int)text_len,
-				                    dst,
-				                    &dst_len);
+				ret = mg_base64_decode(text, (int)text_len, dst, &dst_len);
 				if (ret != -1) {
 					mg_free(dst);
 					return luaL_error(
 					    L, "illegal character in lsp_base64_decode() call");
 				} else {
-					lua_pushlstring(L, dst, dst_len);
+					lua_pushlstring(L, (char *)dst, dst_len);
 					mg_free(dst);
 				}
 			} else {

+ 1 - 0
unittest/CMakeLists.txt

@@ -168,6 +168,7 @@ civetweb_add_test(PublicFunc "Options")
 civetweb_add_test(PublicFunc "MIME types")
 civetweb_add_test(PublicFunc "strcasecmp")
 civetweb_add_test(PublicFunc "URL encoding decoding")
+civetweb_add_test(PublicFunc "BASE64 encoding decoding")
 civetweb_add_test(PublicFunc "Cookies and variables")
 civetweb_add_test(PublicFunc "MD5")
 civetweb_add_test(PublicFunc "Aux functions")

+ 0 - 71
unittest/private.c

@@ -964,80 +964,9 @@ START_TEST(test_encode_decode)
 	int ret;
 	size_t len;
 
-	const char *alpha_b64_enc = "YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXo=";
-	const char *nonalpha_b64_enc =
-	    "ICEiIyQlJicoKSorLC0uLzAxMjM0NTY3ODk6Ozw9Pj9A";
-
 	mark_point();
 
 	memset(buf, 77, sizeof(buf));
-	base64_encode((unsigned char *)"a", 1, buf, NULL);
-	ck_assert_str_eq(buf, "YQ==");
-
-	memset(buf, 77, sizeof(buf));
-	len = 9999;
-	base64_encode((unsigned char *)"ab", 1, buf, &len);
-	ck_assert_str_eq(buf, "YQ==");
-	ck_assert_int_eq((int)len, 5);
-
-	memset(buf, 77, sizeof(buf));
-	len = 9999;
-	base64_encode((unsigned char *)"ab", 2, buf, &len);
-	ck_assert_str_eq(buf, "YWI=");
-	ck_assert_int_eq((int)len, 5);
-
-	memset(buf, 77, sizeof(buf));
-	len = 9999;
-	base64_encode((unsigned char *)alpha, 3, buf, &len);
-	ck_assert_str_eq(buf, "YWJj");
-	ck_assert_int_eq((int)len, 5);
-
-	memset(buf, 77, sizeof(buf));
-	len = 9999;
-	base64_encode((unsigned char *)alpha, 4, buf, &len);
-	ck_assert_str_eq(buf, "YWJjZA==");
-	ck_assert_int_eq((int)len, 9);
-
-	memset(buf, 77, sizeof(buf));
-	len = 9999;
-	base64_encode((unsigned char *)alpha, 5, buf, &len);
-	ck_assert_str_eq(buf, "YWJjZGU=");
-	ck_assert_int_eq((int)len, 9);
-
-	memset(buf, 77, sizeof(buf));
-	len = 9999;
-	base64_encode((unsigned char *)alpha, 6, buf, &len);
-	ck_assert_str_eq(buf, "YWJjZGVm");
-	ck_assert_int_eq((int)len, 9);
-
-	memset(buf, 77, sizeof(buf));
-	len = 9999;
-	base64_encode((unsigned char *)alpha, (int)strlen(alpha), buf, &len);
-	ck_assert_str_eq(buf, alpha_b64_enc);
-	ck_assert_int_eq((int)len, (int)strlen(alpha_b64_enc) + 1);
-
-	memset(buf, 77, sizeof(buf));
-	len = 9999;
-	base64_encode((unsigned char *)nonalpha, (int)strlen(nonalpha), buf, &len);
-	ck_assert_str_eq(buf, nonalpha_b64_enc);
-	ck_assert_int_eq((int)len, (int)strlen(nonalpha_b64_enc) + 1);
-
-	memset(buf, 77, sizeof(buf));
-	len = 9999;
-	ret = base64_decode((unsigned char *)alpha_b64_enc,
-	                    (int)strlen(alpha_b64_enc),
-	                    buf,
-	                    &len);
-	ck_assert_int_eq(ret, -1);
-	ck_assert_int_eq((int)len, (int)strlen(alpha) + 1);
-	ck_assert_str_eq(buf, alpha);
-
-	memset(buf, 77, sizeof(buf));
-	len = 9999;
-	ret = base64_decode((unsigned char *)"AAA*AAA", 7, buf, &len);
-	ck_assert_int_eq(ret, 3);
-
-	memset(buf, 77, sizeof(buf));
 	ret = mg_url_encode(alpha, buf, sizeof(buf));
 	ck_assert_int_eq(ret, (int)strlen(buf));
 	ck_assert_int_eq(ret, (int)strlen(alpha));

+ 94 - 0
unittest/public_func.c

@@ -533,6 +533,93 @@ START_TEST(test_mg_url_decode)
 END_TEST
 
 
+START_TEST(test_mg_base64)
+{
+	char buf[128];
+	const char *alpha = "abcdefghijklmnopqrstuvwxyz";
+	const char *nonalpha = " !\"#$%&'()*+,-./0123456789:;<=>?@";
+	int ret;
+	size_t len;
+
+	const char *alpha_b64_enc = "YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXo=";
+	const char *nonalpha_b64_enc =
+	    "ICEiIyQlJicoKSorLC0uLzAxMjM0NTY3ODk6Ozw9Pj9A";
+
+	mark_point();
+
+	memset(buf, 77, sizeof(buf));
+	mg_base64_encode((unsigned char *)"a", 1, buf, NULL);
+	ck_assert_str_eq(buf, "YQ==");
+
+	memset(buf, 77, sizeof(buf));
+	len = 9999;
+	mg_base64_encode((unsigned char *)"ab", 1, buf, &len);
+	ck_assert_str_eq(buf, "YQ==");
+	ck_assert_int_eq((int)len, 5);
+
+	memset(buf, 77, sizeof(buf));
+	len = 9999;
+	mg_base64_encode((unsigned char *)"ab", 2, buf, &len);
+	ck_assert_str_eq(buf, "YWI=");
+	ck_assert_int_eq((int)len, 5);
+
+	memset(buf, 77, sizeof(buf));
+	len = 9999;
+	mg_base64_encode((unsigned char *)alpha, 3, buf, &len);
+	ck_assert_str_eq(buf, "YWJj");
+	ck_assert_int_eq((int)len, 5);
+
+	memset(buf, 77, sizeof(buf));
+	len = 9999;
+	mg_base64_encode((unsigned char *)alpha, 4, buf, &len);
+	ck_assert_str_eq(buf, "YWJjZA==");
+	ck_assert_int_eq((int)len, 9);
+
+	memset(buf, 77, sizeof(buf));
+	len = 9999;
+	mg_base64_encode((unsigned char *)alpha, 5, buf, &len);
+	ck_assert_str_eq(buf, "YWJjZGU=");
+	ck_assert_int_eq((int)len, 9);
+
+	memset(buf, 77, sizeof(buf));
+	len = 9999;
+	mg_base64_encode((unsigned char *)alpha, 6, buf, &len);
+	ck_assert_str_eq(buf, "YWJjZGVm");
+	ck_assert_int_eq((int)len, 9);
+
+	memset(buf, 77, sizeof(buf));
+	len = 9999;
+	mg_base64_encode((unsigned char *)alpha, (int)strlen(alpha), buf, &len);
+	ck_assert_str_eq(buf, alpha_b64_enc);
+	ck_assert_int_eq((int)len, (int)strlen(alpha_b64_enc) + 1);
+
+	memset(buf, 77, sizeof(buf));
+	len = 9999;
+	mg_base64_encode((unsigned char *)nonalpha,
+	                 (int)strlen(nonalpha),
+	                 buf,
+	                 &len);
+	ck_assert_str_eq(buf, nonalpha_b64_enc);
+	ck_assert_int_eq((int)len, (int)strlen(nonalpha_b64_enc) + 1);
+
+	memset(buf, 77, sizeof(buf));
+	len = 9999;
+	ret = mg_base64_decode((unsigned char *)alpha_b64_enc,
+	                       (int)strlen(alpha_b64_enc),
+	                       buf,
+	                       &len);
+	ck_assert_int_eq(ret, -1);
+	ck_assert_int_eq((int)len, (int)strlen(alpha) + 1);
+	ck_assert_str_eq(buf, alpha);
+
+	memset(buf, 77, sizeof(buf));
+	len = 9999;
+	ret = mg_base64_decode((unsigned char *)"AAA*AAA", 7, buf, &len);
+	ck_assert_int_eq(ret, 3);
+}
+END_TEST
+
+
 #define MG_MAX_FORM_FIELDS (64)
 
 START_TEST(test_mg_split_form_urlencoded)
@@ -638,6 +725,8 @@ make_public_func_suite(void)
 	TCase *const tcase_strncasecmp = tcase_create("strcasecmp");
 	TCase *const tcase_urlencodingdecoding =
 	    tcase_create("URL encoding decoding");
+	TCase *const tcase_base64encodingdecoding =
+	    tcase_create("BASE64 encoding decoding");
 	TCase *const tcase_cookies = tcase_create("Cookies and variables");
 	TCase *const tcase_md5 = tcase_create("MD5");
 	TCase *const tcase_aux = tcase_create("Aux functions");
@@ -664,6 +753,11 @@ make_public_func_suite(void)
 	tcase_set_timeout(tcase_urlencodingdecoding, civetweb_min_test_timeout);
 	suite_add_tcase(suite, tcase_urlencodingdecoding);
 
+	tcase_add_test(tcase_base64encodingdecoding, test_mg_base64);
+	tcase_set_timeout(tcase_base64encodingdecoding, civetweb_min_test_timeout);
+	suite_add_tcase(suite, tcase_base64encodingdecoding);
+	suite_add_tcase(suite, tcase_base64encodingdecoding);
+
 	tcase_add_test(tcase_cookies, test_mg_get_cookie);
 	tcase_add_test(tcase_cookies, test_mg_get_var);
 	tcase_set_timeout(tcase_cookies, civetweb_min_test_timeout);