mirror of
https://github.com/cesanta/mongoose.git
synced 2024-11-27 12:49:01 +08:00
Add mg_next_query_string_entry_n() and mg_url_decode_n()
Move to mg_util.h so encode and decode are next ot each other. Pull out mg_next_list_entry_n() for advanced use cases. Add unit tests.
This commit is contained in:
parent
9fe1c93c9b
commit
be64f81eee
155
mongoose.c
155
mongoose.c
@ -2116,6 +2116,43 @@ int mg_avprintf(char **buf, size_t size, const char *fmt, va_list ap) {
|
||||
return len;
|
||||
}
|
||||
|
||||
static struct mg_str mg_next_list_entry_n(struct mg_str list, char sep1,
|
||||
struct mg_str *val1, char sep2,
|
||||
struct mg_str *val2) {
|
||||
if (list.len == 0) {
|
||||
/* End of the list */
|
||||
list = mg_mk_str(NULL);
|
||||
} else {
|
||||
const char *chr = NULL;
|
||||
*val1 = list;
|
||||
|
||||
if ((chr = mg_strchr(*val1, sep1)) != NULL) {
|
||||
/* Comma found. Store length and shift the list ptr */
|
||||
val1->len = chr - val1->p;
|
||||
chr++;
|
||||
list.len -= (chr - list.p);
|
||||
list.p = chr;
|
||||
} else {
|
||||
/* This value is the last one */
|
||||
list = mg_mk_str_n(list.p + list.len, 0);
|
||||
}
|
||||
|
||||
if (val2 != NULL) {
|
||||
/* Value has form "x=y", adjust pointers and lengths */
|
||||
/* so that val points to "x", and eq_val points to "y". */
|
||||
val2->len = 0;
|
||||
val2->p = (const char *) memchr(val1->p, sep2, val1->len);
|
||||
if (val2->p != NULL) {
|
||||
val2->p++; /* Skip over sep2 character */
|
||||
val2->len = val1->p + val1->len - val2->p;
|
||||
val1->len = (val2->p - val1->p) - 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
const char *mg_next_comma_list_entry(const char *, struct mg_str *,
|
||||
struct mg_str *) WEAK;
|
||||
const char *mg_next_comma_list_entry(const char *list, struct mg_str *val,
|
||||
@ -2128,38 +2165,16 @@ struct mg_str mg_next_comma_list_entry_n(struct mg_str list, struct mg_str *val,
|
||||
struct mg_str *eq_val) WEAK;
|
||||
struct mg_str mg_next_comma_list_entry_n(struct mg_str list, struct mg_str *val,
|
||||
struct mg_str *eq_val) {
|
||||
if (list.len == 0) {
|
||||
/* End of the list */
|
||||
list = mg_mk_str(NULL);
|
||||
} else {
|
||||
const char *chr = NULL;
|
||||
*val = list;
|
||||
return mg_next_list_entry_n(list, ',', val, '=', eq_val);
|
||||
}
|
||||
|
||||
if ((chr = mg_strchr(*val, ',')) != NULL) {
|
||||
/* Comma found. Store length and shift the list ptr */
|
||||
val->len = chr - val->p;
|
||||
chr++;
|
||||
list.len -= (chr - list.p);
|
||||
list.p = chr;
|
||||
} else {
|
||||
/* This value is the last one */
|
||||
list = mg_mk_str_n(list.p + list.len, 0);
|
||||
}
|
||||
|
||||
if (eq_val != NULL) {
|
||||
/* Value has form "x=y", adjust pointers and lengths */
|
||||
/* so that val points to "x", and eq_val points to "y". */
|
||||
eq_val->len = 0;
|
||||
eq_val->p = (const char *) memchr(val->p, '=', val->len);
|
||||
if (eq_val->p != NULL) {
|
||||
eq_val->p++; /* Skip over '=' character */
|
||||
eq_val->len = val->p + val->len - eq_val->p;
|
||||
val->len = (eq_val->p - val->p) - 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return list;
|
||||
struct mg_str mg_next_query_string_entry_n(struct mg_str list,
|
||||
struct mg_str *val,
|
||||
struct mg_str *eq_val) WEAK;
|
||||
struct mg_str mg_next_query_string_entry_n(struct mg_str list,
|
||||
struct mg_str *val,
|
||||
struct mg_str *eq_val) {
|
||||
return mg_next_list_entry_n(list, '&', val, '=', eq_val);
|
||||
}
|
||||
|
||||
size_t mg_match_prefix_n(const struct mg_str, const struct mg_str) WEAK;
|
||||
@ -7264,34 +7279,6 @@ static void mg_http_serve_file2(struct mg_connection *nc, const char *path,
|
||||
|
||||
#endif
|
||||
|
||||
int mg_url_decode(const char *src, int src_len, char *dst, int dst_len,
|
||||
int is_form_url_encoded) {
|
||||
int i, j, a, b;
|
||||
#define HEXTOI(x) (isdigit(x) ? x - '0' : x - 'W')
|
||||
|
||||
for (i = j = 0; i < src_len && j < dst_len - 1; i++, j++) {
|
||||
if (src[i] == '%') {
|
||||
if (i < src_len - 2 && isxdigit(*(const unsigned char *) (src + i + 1)) &&
|
||||
isxdigit(*(const unsigned char *) (src + i + 2))) {
|
||||
a = tolower(*(const unsigned char *) (src + i + 1));
|
||||
b = tolower(*(const unsigned char *) (src + i + 2));
|
||||
dst[j] = (char) ((HEXTOI(a) << 4) | HEXTOI(b));
|
||||
i += 2;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
} else if (is_form_url_encoded && src[i] == '+') {
|
||||
dst[j] = ' ';
|
||||
} else {
|
||||
dst[j] = src[i];
|
||||
}
|
||||
}
|
||||
|
||||
dst[j] = '\0'; /* Null-terminate the destination */
|
||||
|
||||
return i >= src_len ? j : -1;
|
||||
}
|
||||
|
||||
int mg_get_http_var(const struct mg_str *buf, const char *name, char *dst,
|
||||
size_t dst_len) {
|
||||
const char *p, *e, *s;
|
||||
@ -10662,6 +10649,56 @@ struct mg_str mg_url_encode_opt(const struct mg_str src,
|
||||
struct mg_str mg_url_encode(const struct mg_str src) {
|
||||
return mg_url_encode_opt(src, mg_mk_str("._-$,;~()/"), 0);
|
||||
}
|
||||
|
||||
int mg_url_decode(const char *src, int src_len, char *dst, int dst_len,
|
||||
int is_form_url_encoded) {
|
||||
struct mg_str srcs = MG_MK_STR_N(src, (size_t) src_len);
|
||||
struct mg_str dsts = MG_MK_STR_N(dst, (size_t) dst_len);
|
||||
int res = mg_url_decode_n(srcs, &dsts, is_form_url_encoded);
|
||||
if (res >= 0) {
|
||||
if (res < dst_len) {
|
||||
dst[res] = '\0';
|
||||
} else {
|
||||
res = -1; /* Not enough space for NUL-temrination. */
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
#define HEXTOI(x) (isdigit(x) ? x - '0' : x - 'W')
|
||||
int mg_url_decode_n(struct mg_str srcs, struct mg_str *dsts,
|
||||
int is_form_url_encoded) {
|
||||
int i, j, a, b, src_len, dst_len;
|
||||
const char *src = srcs.p;
|
||||
char *dst;
|
||||
if (dsts == NULL) return -1;
|
||||
dst = (char *) dsts->p;
|
||||
src_len = (int) srcs.len;
|
||||
dst_len = (int) dsts->len;
|
||||
|
||||
for (i = j = 0; i < src_len && j < dst_len; i++, j++) {
|
||||
if (src[i] == '%') {
|
||||
if (i < src_len - 2 && isxdigit(*(const unsigned char *) (src + i + 1)) &&
|
||||
isxdigit(*(const unsigned char *) (src + i + 2))) {
|
||||
a = tolower(*(const unsigned char *) (src + i + 1));
|
||||
b = tolower(*(const unsigned char *) (src + i + 2));
|
||||
dst[j] = (char) ((HEXTOI(a) << 4) | HEXTOI(b));
|
||||
i += 2;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
} else if (is_form_url_encoded && src[i] == '+') {
|
||||
dst[j] = ' ';
|
||||
} else {
|
||||
dst[j] = src[i];
|
||||
}
|
||||
}
|
||||
dsts->len = (size_t) j;
|
||||
|
||||
return i == src_len ? j : -1;
|
||||
}
|
||||
#undef HEXTOI
|
||||
|
||||
#ifdef MG_MODULE_LINES
|
||||
#line 1 "src/mg_mqtt.c"
|
||||
#endif
|
||||
|
43
mongoose.h
43
mongoose.h
@ -2323,6 +2323,14 @@ const char *mg_next_comma_list_entry(const char *list, struct mg_str *val,
|
||||
struct mg_str mg_next_comma_list_entry_n(struct mg_str list, struct mg_str *val,
|
||||
struct mg_str *eq_val);
|
||||
|
||||
/*
|
||||
* Helper for parsing query strings.
|
||||
* Parses '&' and '=' entries. Does not perform unescaping.
|
||||
*/
|
||||
struct mg_str mg_next_query_string_entry_n(struct mg_str list,
|
||||
struct mg_str *val,
|
||||
struct mg_str *eq_val);
|
||||
|
||||
/*
|
||||
* Matches 0-terminated string (mg_match_prefix) or string with given length
|
||||
* mg_match_prefix_n against a glob pattern. Glob syntax:
|
||||
@ -4325,6 +4333,27 @@ struct mg_str mg_url_encode_opt(const struct mg_str src,
|
||||
/* Same as `mg_url_encode_opt(src, "._-$,;~()/", 0)`. */
|
||||
struct mg_str mg_url_encode(const struct mg_str src);
|
||||
|
||||
/*
|
||||
* Decodes a URL-encoded string.
|
||||
*
|
||||
* Source string is specified by (`src`, `src_len`), and destination is
|
||||
* (`dst`, `dst_len`). If `is_form_url_encoded` is non-zero, then
|
||||
* `+` character is decoded as a blank space character. This function
|
||||
* guarantees to NUL-terminate the destination. If destination is too small,
|
||||
* then the source string is partially decoded and `-1` is returned.
|
||||
* Otherwise, the length of the decoded string is returned,
|
||||
* not counting final NUL.
|
||||
*/
|
||||
int mg_url_decode(const char *src, int src_len, char *dst, int dst_len,
|
||||
int is_form_url_encoded);
|
||||
|
||||
/*
|
||||
* mg_str variant of mg_url_decode. Does not NUL-terminate dst.
|
||||
* It is ok for src and dst to be the same.
|
||||
*/
|
||||
int mg_url_decode_n(struct mg_str src, struct mg_str *dst,
|
||||
int is_form_url_encoded);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
@ -4662,20 +4691,6 @@ void mg_printf_websocket_frame(struct mg_connection *nc, int op_and_flags,
|
||||
|
||||
#endif /* MG_ENABLE_HTTP_WEBSOCKET */
|
||||
|
||||
/*
|
||||
* Decodes a URL-encoded string.
|
||||
*
|
||||
* Source string is specified by (`src`, `src_len`), and destination is
|
||||
* (`dst`, `dst_len`). If `is_form_url_encoded` is non-zero, then
|
||||
* `+` character is decoded as a blank space character. This function
|
||||
* guarantees to NUL-terminate the destination. If destination is too small,
|
||||
* then the source string is partially decoded and `-1` is returned.
|
||||
*Otherwise,
|
||||
* a length of the decoded string is returned, not counting final NUL.
|
||||
*/
|
||||
int mg_url_decode(const char *src, int src_len, char *dst, int dst_len,
|
||||
int is_form_url_encoded);
|
||||
|
||||
extern void mg_hash_md5_v(size_t num_msgs, const uint8_t *msgs[],
|
||||
const size_t *msg_lens, uint8_t *digest);
|
||||
extern void mg_hash_sha1_v(size_t num_msgs, const uint8_t *msgs[],
|
||||
|
6
src/.clang-format
Normal file
6
src/.clang-format
Normal file
@ -0,0 +1,6 @@
|
||||
BasedOnStyle: Google
|
||||
AllowShortFunctionsOnASingleLine: false
|
||||
SpaceAfterCStyleCast: true
|
||||
PointerBindsToType: false
|
||||
DerivePointerBinding: false
|
||||
IncludeBlocks: Preserve
|
@ -413,6 +413,43 @@ int mg_avprintf(char **buf, size_t size, const char *fmt, va_list ap) {
|
||||
return len;
|
||||
}
|
||||
|
||||
static struct mg_str mg_next_list_entry_n(struct mg_str list, char sep1,
|
||||
struct mg_str *val1, char sep2,
|
||||
struct mg_str *val2) {
|
||||
if (list.len == 0) {
|
||||
/* End of the list */
|
||||
list = mg_mk_str(NULL);
|
||||
} else {
|
||||
const char *chr = NULL;
|
||||
*val1 = list;
|
||||
|
||||
if ((chr = mg_strchr(*val1, sep1)) != NULL) {
|
||||
/* Comma found. Store length and shift the list ptr */
|
||||
val1->len = chr - val1->p;
|
||||
chr++;
|
||||
list.len -= (chr - list.p);
|
||||
list.p = chr;
|
||||
} else {
|
||||
/* This value is the last one */
|
||||
list = mg_mk_str_n(list.p + list.len, 0);
|
||||
}
|
||||
|
||||
if (val2 != NULL) {
|
||||
/* Value has form "x=y", adjust pointers and lengths */
|
||||
/* so that val points to "x", and eq_val points to "y". */
|
||||
val2->len = 0;
|
||||
val2->p = (const char *) memchr(val1->p, sep2, val1->len);
|
||||
if (val2->p != NULL) {
|
||||
val2->p++; /* Skip over sep2 character */
|
||||
val2->len = val1->p + val1->len - val2->p;
|
||||
val1->len = (val2->p - val1->p) - 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
const char *mg_next_comma_list_entry(const char *, struct mg_str *,
|
||||
struct mg_str *) WEAK;
|
||||
const char *mg_next_comma_list_entry(const char *list, struct mg_str *val,
|
||||
@ -425,38 +462,16 @@ struct mg_str mg_next_comma_list_entry_n(struct mg_str list, struct mg_str *val,
|
||||
struct mg_str *eq_val) WEAK;
|
||||
struct mg_str mg_next_comma_list_entry_n(struct mg_str list, struct mg_str *val,
|
||||
struct mg_str *eq_val) {
|
||||
if (list.len == 0) {
|
||||
/* End of the list */
|
||||
list = mg_mk_str(NULL);
|
||||
} else {
|
||||
const char *chr = NULL;
|
||||
*val = list;
|
||||
return mg_next_list_entry_n(list, ',', val, '=', eq_val);
|
||||
}
|
||||
|
||||
if ((chr = mg_strchr(*val, ',')) != NULL) {
|
||||
/* Comma found. Store length and shift the list ptr */
|
||||
val->len = chr - val->p;
|
||||
chr++;
|
||||
list.len -= (chr - list.p);
|
||||
list.p = chr;
|
||||
} else {
|
||||
/* This value is the last one */
|
||||
list = mg_mk_str_n(list.p + list.len, 0);
|
||||
}
|
||||
|
||||
if (eq_val != NULL) {
|
||||
/* Value has form "x=y", adjust pointers and lengths */
|
||||
/* so that val points to "x", and eq_val points to "y". */
|
||||
eq_val->len = 0;
|
||||
eq_val->p = (const char *) memchr(val->p, '=', val->len);
|
||||
if (eq_val->p != NULL) {
|
||||
eq_val->p++; /* Skip over '=' character */
|
||||
eq_val->len = val->p + val->len - eq_val->p;
|
||||
val->len = (eq_val->p - val->p) - 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return list;
|
||||
struct mg_str mg_next_query_string_entry_n(struct mg_str list,
|
||||
struct mg_str *val,
|
||||
struct mg_str *eq_val) WEAK;
|
||||
struct mg_str mg_next_query_string_entry_n(struct mg_str list,
|
||||
struct mg_str *val,
|
||||
struct mg_str *eq_val) {
|
||||
return mg_next_list_entry_n(list, '&', val, '=', eq_val);
|
||||
}
|
||||
|
||||
size_t mg_match_prefix_n(const struct mg_str, const struct mg_str) WEAK;
|
||||
|
@ -148,6 +148,14 @@ const char *mg_next_comma_list_entry(const char *list, struct mg_str *val,
|
||||
struct mg_str mg_next_comma_list_entry_n(struct mg_str list, struct mg_str *val,
|
||||
struct mg_str *eq_val);
|
||||
|
||||
/*
|
||||
* Helper for parsing query strings.
|
||||
* Parses '&' and '=' entries. Does not perform unescaping.
|
||||
*/
|
||||
struct mg_str mg_next_query_string_entry_n(struct mg_str list,
|
||||
struct mg_str *val,
|
||||
struct mg_str *eq_val);
|
||||
|
||||
/*
|
||||
* Matches 0-terminated string (mg_match_prefix) or string with given length
|
||||
* mg_match_prefix_n against a glob pattern. Glob syntax:
|
||||
|
@ -1624,34 +1624,6 @@ static void mg_http_serve_file2(struct mg_connection *nc, const char *path,
|
||||
|
||||
#endif
|
||||
|
||||
int mg_url_decode(const char *src, int src_len, char *dst, int dst_len,
|
||||
int is_form_url_encoded) {
|
||||
int i, j, a, b;
|
||||
#define HEXTOI(x) (isdigit(x) ? x - '0' : x - 'W')
|
||||
|
||||
for (i = j = 0; i < src_len && j < dst_len - 1; i++, j++) {
|
||||
if (src[i] == '%') {
|
||||
if (i < src_len - 2 && isxdigit(*(const unsigned char *) (src + i + 1)) &&
|
||||
isxdigit(*(const unsigned char *) (src + i + 2))) {
|
||||
a = tolower(*(const unsigned char *) (src + i + 1));
|
||||
b = tolower(*(const unsigned char *) (src + i + 2));
|
||||
dst[j] = (char) ((HEXTOI(a) << 4) | HEXTOI(b));
|
||||
i += 2;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
} else if (is_form_url_encoded && src[i] == '+') {
|
||||
dst[j] = ' ';
|
||||
} else {
|
||||
dst[j] = src[i];
|
||||
}
|
||||
}
|
||||
|
||||
dst[j] = '\0'; /* Null-terminate the destination */
|
||||
|
||||
return i >= src_len ? j : -1;
|
||||
}
|
||||
|
||||
int mg_get_http_var(const struct mg_str *buf, const char *name, char *dst,
|
||||
size_t dst_len) {
|
||||
const char *p, *e, *s;
|
||||
|
@ -329,20 +329,6 @@ void mg_printf_websocket_frame(struct mg_connection *nc, int op_and_flags,
|
||||
|
||||
#endif /* MG_ENABLE_HTTP_WEBSOCKET */
|
||||
|
||||
/*
|
||||
* Decodes a URL-encoded string.
|
||||
*
|
||||
* Source string is specified by (`src`, `src_len`), and destination is
|
||||
* (`dst`, `dst_len`). If `is_form_url_encoded` is non-zero, then
|
||||
* `+` character is decoded as a blank space character. This function
|
||||
* guarantees to NUL-terminate the destination. If destination is too small,
|
||||
* then the source string is partially decoded and `-1` is returned.
|
||||
*Otherwise,
|
||||
* a length of the decoded string is returned, not counting final NUL.
|
||||
*/
|
||||
int mg_url_decode(const char *src, int src_len, char *dst, int dst_len,
|
||||
int is_form_url_encoded);
|
||||
|
||||
extern void mg_hash_md5_v(size_t num_msgs, const uint8_t *msgs[],
|
||||
const size_t *msg_lens, uint8_t *digest);
|
||||
extern void mg_hash_sha1_v(size_t num_msgs, const uint8_t *msgs[],
|
||||
|
@ -338,3 +338,53 @@ struct mg_str mg_url_encode_opt(const struct mg_str src,
|
||||
struct mg_str mg_url_encode(const struct mg_str src) {
|
||||
return mg_url_encode_opt(src, mg_mk_str("._-$,;~()/"), 0);
|
||||
}
|
||||
|
||||
int mg_url_decode(const char *src, int src_len, char *dst, int dst_len,
|
||||
int is_form_url_encoded) {
|
||||
struct mg_str srcs = MG_MK_STR_N(src, (size_t) src_len);
|
||||
struct mg_str dsts = MG_MK_STR_N(dst, (size_t) dst_len);
|
||||
int res = mg_url_decode_n(srcs, &dsts, is_form_url_encoded);
|
||||
if (res >= 0) {
|
||||
if (res < dst_len) {
|
||||
dst[res] = '\0';
|
||||
} else {
|
||||
res = -1; /* Not enough space for NUL-temrination. */
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
#define HEXTOI(x) (isdigit(x) ? x - '0' : x - 'W')
|
||||
int mg_url_decode_n(struct mg_str srcs, struct mg_str *dsts,
|
||||
int is_form_url_encoded) {
|
||||
int i, j, a, b, src_len, dst_len;
|
||||
const char *src = srcs.p;
|
||||
char *dst;
|
||||
if (dsts == NULL) return -1;
|
||||
dst = (char *) dsts->p;
|
||||
src_len = (int) srcs.len;
|
||||
dst_len = (int) dsts->len;
|
||||
|
||||
for (i = j = 0; i < src_len && j < dst_len; i++, j++) {
|
||||
if (src[i] == '%') {
|
||||
if (i < src_len - 2 && isxdigit(*(const unsigned char *) (src + i + 1)) &&
|
||||
isxdigit(*(const unsigned char *) (src + i + 2))) {
|
||||
a = tolower(*(const unsigned char *) (src + i + 1));
|
||||
b = tolower(*(const unsigned char *) (src + i + 2));
|
||||
dst[j] = (char) ((HEXTOI(a) << 4) | HEXTOI(b));
|
||||
i += 2;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
} else if (is_form_url_encoded && src[i] == '+') {
|
||||
dst[j] = ' ';
|
||||
} else {
|
||||
dst[j] = src[i];
|
||||
}
|
||||
}
|
||||
dsts->len = (size_t) j;
|
||||
|
||||
return i == src_len ? j : -1;
|
||||
}
|
||||
#undef HEXTOI
|
||||
|
||||
|
@ -205,6 +205,27 @@ struct mg_str mg_url_encode_opt(const struct mg_str src,
|
||||
/* Same as `mg_url_encode_opt(src, "._-$,;~()/", 0)`. */
|
||||
struct mg_str mg_url_encode(const struct mg_str src);
|
||||
|
||||
/*
|
||||
* Decodes a URL-encoded string.
|
||||
*
|
||||
* Source string is specified by (`src`, `src_len`), and destination is
|
||||
* (`dst`, `dst_len`). If `is_form_url_encoded` is non-zero, then
|
||||
* `+` character is decoded as a blank space character. This function
|
||||
* guarantees to NUL-terminate the destination. If destination is too small,
|
||||
* then the source string is partially decoded and `-1` is returned.
|
||||
* Otherwise, the length of the decoded string is returned,
|
||||
* not counting final NUL.
|
||||
*/
|
||||
int mg_url_decode(const char *src, int src_len, char *dst, int dst_len,
|
||||
int is_form_url_encoded);
|
||||
|
||||
/*
|
||||
* mg_str variant of mg_url_decode. Does not NUL-terminate dst.
|
||||
* It is ok for src and dst to be the same.
|
||||
*/
|
||||
int mg_url_decode_n(struct mg_str src, struct mg_str *dst,
|
||||
int is_form_url_encoded);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
6
test/.clang-format
Normal file
6
test/.clang-format
Normal file
@ -0,0 +1,6 @@
|
||||
BasedOnStyle: Google
|
||||
AllowShortFunctionsOnASingleLine: false
|
||||
SpaceAfterCStyleCast: true
|
||||
PointerBindsToType: false
|
||||
DerivePointerBinding: false
|
||||
IncludeBlocks: Preserve
|
@ -112,3 +112,7 @@ fuzz:
|
||||
# docker run -v $(CURDIR)/../..:/cesanta -t -i --entrypoint=/bin/bash cesanta/mongoose_test
|
||||
docker:
|
||||
docker run --rm -v $(CURDIR)/../..:/cesanta cesanta/mongoose_test
|
||||
|
||||
amalgam:
|
||||
cd .. && tools/amalgam.py --prefix=MG --public-header=mongoose.h --license=LICENSE `cat src/mongoose.c.manifest` > mongoose.c
|
||||
cd .. && tools/amalgam.py --prefix=MG --license=LICENSE `cat src/mongoose.h.manifest` > mongoose.h
|
||||
|
166
test/unit_test.c
166
test/unit_test.c
@ -19,8 +19,8 @@
|
||||
|
||||
#include "mongoose.h"
|
||||
|
||||
#include "common/cs_md5.h"
|
||||
#include "../src/mg_internal.h"
|
||||
#include "common/cs_md5.h"
|
||||
#include "test_main.h"
|
||||
#include "test_util.h"
|
||||
|
||||
@ -856,6 +856,106 @@ static const char *test_mg_normalize_uri_path(void) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static const char *test_mg_next_list_entry(void) {
|
||||
struct mg_str val1, val2;
|
||||
{
|
||||
struct mg_str l = MG_NULL_STR;
|
||||
l = mg_next_comma_list_entry_n(l, &val1, &val2);
|
||||
ASSERT_TRUE(l.p == NULL);
|
||||
ASSERT_EQ(l.len, 0);
|
||||
}
|
||||
{
|
||||
struct mg_str l = MG_MK_STR("a");
|
||||
l = mg_next_comma_list_entry_n(l, &val1, &val2);
|
||||
ASSERT_TRUE(l.p != NULL);
|
||||
ASSERT_EQ(l.len, 0);
|
||||
ASSERT_MG_STREQ(val1, "a");
|
||||
ASSERT_MG_STREQ(val2, "");
|
||||
l = mg_next_comma_list_entry_n(l, &val1, &val2);
|
||||
ASSERT_TRUE(l.p == NULL);
|
||||
ASSERT_EQ(l.len, 0);
|
||||
}
|
||||
{
|
||||
struct mg_str l = MG_MK_STR("a=1");
|
||||
l = mg_next_comma_list_entry_n(l, &val1, &val2);
|
||||
ASSERT_TRUE(l.p != NULL);
|
||||
ASSERT_EQ(l.len, 0);
|
||||
ASSERT_MG_STREQ(val1, "a");
|
||||
ASSERT_MG_STREQ(val2, "1");
|
||||
l = mg_next_comma_list_entry_n(l, &val1, &val2);
|
||||
ASSERT_TRUE(l.p == NULL);
|
||||
ASSERT_EQ(l.len, 0);
|
||||
}
|
||||
{
|
||||
struct mg_str l = MG_MK_STR("a=");
|
||||
l = mg_next_comma_list_entry_n(l, &val1, &val2);
|
||||
ASSERT_TRUE(l.p != NULL);
|
||||
ASSERT_EQ(l.len, 0);
|
||||
ASSERT_MG_STREQ(val1, "a");
|
||||
ASSERT_MG_STREQ(val2, "");
|
||||
l = mg_next_comma_list_entry_n(l, &val1, &val2);
|
||||
ASSERT_TRUE(l.p == NULL);
|
||||
ASSERT_EQ(l.len, 0);
|
||||
}
|
||||
{
|
||||
struct mg_str l = MG_MK_STR("a=,");
|
||||
l = mg_next_comma_list_entry_n(l, &val1, &val2);
|
||||
ASSERT_TRUE(l.p != NULL);
|
||||
ASSERT_EQ(l.len, 0);
|
||||
ASSERT_MG_STREQ(val1, "a");
|
||||
ASSERT_MG_STREQ(val2, "");
|
||||
l = mg_next_comma_list_entry_n(l, &val1, &val2);
|
||||
ASSERT_TRUE(l.p == NULL);
|
||||
ASSERT_EQ(l.len, 0);
|
||||
}
|
||||
{
|
||||
struct mg_str l = MG_MK_STR("a=123,b=456");
|
||||
l = mg_next_comma_list_entry_n(l, &val1, &val2);
|
||||
ASSERT_MG_STREQ(l, "b=456");
|
||||
ASSERT_MG_STREQ(val1, "a");
|
||||
ASSERT_MG_STREQ(val2, "123");
|
||||
l = mg_next_comma_list_entry_n(l, &val1, &val2);
|
||||
ASSERT_TRUE(l.p != NULL);
|
||||
ASSERT_EQ(l.len, 0);
|
||||
ASSERT_MG_STREQ(val1, "b");
|
||||
ASSERT_MG_STREQ(val2, "456");
|
||||
l = mg_next_comma_list_entry_n(l, &val1, &val2);
|
||||
ASSERT_TRUE(l.p == NULL);
|
||||
ASSERT_EQ(l.len, 0);
|
||||
}
|
||||
{
|
||||
struct mg_str l = MG_MK_STR("a,b=456");
|
||||
l = mg_next_comma_list_entry_n(l, &val1, &val2);
|
||||
ASSERT_MG_STREQ(l, "b=456");
|
||||
ASSERT_MG_STREQ(val1, "a");
|
||||
ASSERT_MG_STREQ(val2, "");
|
||||
l = mg_next_comma_list_entry_n(l, &val1, &val2);
|
||||
ASSERT_TRUE(l.p != NULL);
|
||||
ASSERT_EQ(l.len, 0);
|
||||
ASSERT_MG_STREQ(val1, "b");
|
||||
ASSERT_MG_STREQ(val2, "456");
|
||||
l = mg_next_comma_list_entry_n(l, &val1, &val2);
|
||||
ASSERT_TRUE(l.p == NULL);
|
||||
ASSERT_EQ(l.len, 0);
|
||||
}
|
||||
{
|
||||
struct mg_str l = MG_MK_STR("a,b&c=4+5%206");
|
||||
l = mg_next_query_string_entry_n(l, &val1, &val2);
|
||||
ASSERT_MG_STREQ(l, "c=4+5%206");
|
||||
ASSERT_MG_STREQ(val1, "a,b");
|
||||
ASSERT_MG_STREQ(val2, "");
|
||||
l = mg_next_query_string_entry_n(l, &val1, &val2);
|
||||
ASSERT_TRUE(l.p != NULL);
|
||||
ASSERT_EQ(l.len, 0);
|
||||
ASSERT_MG_STREQ(val1, "c");
|
||||
ASSERT_MG_STREQ(val2, "4+5%206");
|
||||
l = mg_next_query_string_entry_n(l, &val1, &val2);
|
||||
ASSERT_TRUE(l.p == NULL);
|
||||
ASSERT_EQ(l.len, 0);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#define CHECK_U2LP(u, exp_rv, exp_lp, exp_rem) \
|
||||
do { \
|
||||
int rv; \
|
||||
@ -931,21 +1031,25 @@ static const char *test_mg_uri_to_local_path(void) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static const char *test_mg_url_encode(void) {
|
||||
const struct mg_str encode_me =
|
||||
MG_MK_STR("I'm a.little_tea-pot,here's$my;spout~oink(oink)oink/!");
|
||||
static const char *test_mg_url_encode_decode(void) {
|
||||
#define ENCODE_ME "I'm a.little_tea-po+,here's$my;spout~oink(oink)oink/!"
|
||||
struct mg_str encode_me = MG_MK_STR(ENCODE_ME "XXX");
|
||||
encode_me.len -= 3; /* Not nul-terminated on purpose */
|
||||
{
|
||||
struct mg_str encoded = mg_url_encode(encode_me);
|
||||
ASSERT_MG_STREQ(
|
||||
encoded,
|
||||
"I%27m%20a.little_tea-pot,here%27s$my;spout~oink(oink)oink/%21");
|
||||
"I%27m%20a.little_tea-po%2b,here%27s$my;spout~oink(oink)oink/%21");
|
||||
ASSERT_EQ(mg_url_decode_n(encoded, &encoded, 1), encode_me.len);
|
||||
ASSERT_MG_STREQ(encoded, ENCODE_ME);
|
||||
free((void *) encoded.p);
|
||||
}
|
||||
{
|
||||
struct mg_str encoded = mg_url_encode_opt(encode_me, mg_mk_str(NULL), 0);
|
||||
ASSERT_MG_STREQ(encoded,
|
||||
"I%27m%20a%2elittle%5ftea%2dpot%2chere%27s%24my%3bspout%"
|
||||
"I%27m%20a%2elittle%5ftea%2dpo%2b%2chere%27s%24my%3bspout%"
|
||||
"7eoink%28oink%29oink%2f%21");
|
||||
ASSERT_EQ(mg_url_decode_n(encoded, &encoded, 0), encode_me.len);
|
||||
free((void *) encoded.p);
|
||||
}
|
||||
{
|
||||
@ -953,8 +1057,10 @@ static const char *test_mg_url_encode(void) {
|
||||
MG_URL_ENCODE_F_UPPERCASE_HEX);
|
||||
ASSERT_MG_STREQ(encoded,
|
||||
"I%27m "
|
||||
"a%2Elittle%5Ftea%2Dpot%2Chere%27s%24my%3Bspout%7Eoink%"
|
||||
"a%2Elittle%5Ftea%2Dpo%2B%2Chere%27s%24my%3Bspout%7Eoink%"
|
||||
"28oink%29oink/!");
|
||||
ASSERT_EQ(mg_url_decode_n(encoded, &encoded, 0), encode_me.len);
|
||||
ASSERT_MG_STREQ(encoded, ENCODE_ME);
|
||||
free((void *) encoded.p);
|
||||
}
|
||||
{
|
||||
@ -962,10 +1068,51 @@ static const char *test_mg_url_encode(void) {
|
||||
encode_me, mg_mk_str("/!"),
|
||||
MG_URL_ENCODE_F_SPACE_AS_PLUS | MG_URL_ENCODE_F_UPPERCASE_HEX);
|
||||
ASSERT_MG_STREQ(encoded,
|
||||
"I%27m+a%2Elittle%5Ftea%2Dpot%2Chere%27s%24my%3Bspout%"
|
||||
"I%27m+a%2Elittle%5Ftea%2Dpo%2B%2Chere%27s%24my%3Bspout%"
|
||||
"7Eoink%28oink%29oink/!");
|
||||
ASSERT_EQ(mg_url_decode_n(encoded, &encoded, 1), encode_me.len);
|
||||
ASSERT_MG_STREQ(encoded, ENCODE_ME);
|
||||
free((void *) encoded.p);
|
||||
}
|
||||
{
|
||||
struct mg_str in = MG_MK_STR("a%20b%20c");
|
||||
char outbuf[6] = {'X', 'X', 'X', 'X', 'X', 'X'};
|
||||
struct mg_str out = MG_MK_STR_N(outbuf, sizeof(outbuf)), out1 = out;
|
||||
ASSERT_EQ(mg_url_decode_n(in, &out, 0), 5);
|
||||
ASSERT_MG_STREQ(out, "a b c");
|
||||
ASSERT_MG_STREQ(out1, "a b cX");
|
||||
}
|
||||
{
|
||||
struct mg_str in = MG_MK_STR("a%20b%20c");
|
||||
char outbuf[6] = {'X', 'X', 'X', 'X', 'X', 'X'};
|
||||
ASSERT_EQ(mg_url_decode(in.p, (int) in.len, outbuf, sizeof(outbuf), 0), 5);
|
||||
/* NUL-terminated for her pleasure. */
|
||||
ASSERT_MG_STREQ(mg_mk_str(outbuf), "a b c");
|
||||
}
|
||||
{
|
||||
struct mg_str in = MG_MK_STR("a%20b%20c");
|
||||
char outbuf[6] = {'X', 'X', 'X', 'X', 'X', 'X'};
|
||||
struct mg_str out = MG_MK_STR_N(outbuf, 4);
|
||||
ASSERT_EQ(mg_url_decode_n(in, &out, 0), -1);
|
||||
ASSERT_MG_STREQ(out, "a b ");
|
||||
ASSERT_MG_STREQ(mg_mk_str_n(outbuf, sizeof(outbuf)), "a b XX");
|
||||
}
|
||||
{
|
||||
struct mg_str in = MG_MK_STR("a%20b%20c");
|
||||
char outbuf[6] = {'X', 'X', 'X', 'X', 'X', 'X'};
|
||||
ASSERT_EQ(mg_url_decode(in.p, (int) in.len, outbuf, 5, 0), -1);
|
||||
/* Not enough space to NUL-terminate. */
|
||||
struct mg_str out1 = MG_MK_STR_N(outbuf, sizeof(outbuf));
|
||||
ASSERT_MG_STREQ(out1, "a b cX");
|
||||
}
|
||||
{
|
||||
struct mg_str in = MG_MK_STR("a%20b%YYc");
|
||||
char outbuf[6] = {'X', 'X', 'X', 'X', 'X', 'X'};
|
||||
struct mg_str out = MG_MK_STR_N(outbuf, sizeof(outbuf)), out1 = out;
|
||||
ASSERT_EQ(mg_url_decode_n(in, &out, 0), -1);
|
||||
ASSERT_MG_STREQ(out, "a b");
|
||||
ASSERT_MG_STREQ(out1, "a bXXX");
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -5788,8 +5935,9 @@ const char *tests_run(const char *filter) {
|
||||
RUN_TEST(test_assemble_uri);
|
||||
RUN_TEST(test_parse_address);
|
||||
RUN_TEST(test_mg_normalize_uri_path);
|
||||
RUN_TEST(test_mg_next_list_entry);
|
||||
RUN_TEST(test_mg_uri_to_local_path);
|
||||
RUN_TEST(test_mg_url_encode);
|
||||
RUN_TEST(test_mg_url_encode_decode);
|
||||
RUN_TEST(test_check_ip_acl);
|
||||
RUN_TEST(test_connect_opts);
|
||||
RUN_TEST(test_connect_opts_error_string);
|
||||
|
@ -21,4 +21,4 @@ $ tools/amalgam.py --prefix=MG --public-header=mongoose.h $(cat mongoose.c.manif
|
||||
|
||||
The same applies to `mongoose.h`, except `--public-header` should be omitted during amalgamation.
|
||||
|
||||
`tools/amalgam.sh` can be used to assemble `mongoose.c` and `mongoose.h`.
|
||||
`tools/amalgam.py` can be used to assemble `mongoose.c` and `mongoose.h`.
|
||||
|
Loading…
Reference in New Issue
Block a user