diff --git a/mongoose.c b/mongoose.c index e67d70fd..adfe4a19 100644 --- a/mongoose.c +++ b/mongoose.c @@ -1243,6 +1243,22 @@ struct mg_fs mg_fs_posix = {p_stat, p_list, p_open, p_close, p_read, +bool mg_to_size_t(struct mg_str str, size_t *val); +bool mg_to_size_t(struct mg_str str, size_t *val) { + uint64_t result = 0, max = 1844674407370955160 /* (UINT64_MAX-9)/10 */; + size_t i = 0; + while (i < str.len && (str.ptr[i] == ' ' || str.ptr[i] == '\t')) i++; + if (i < str.len && str.ptr[i] == '-') return false; + while (i < str.len && str.ptr[i] >= '0' && str.ptr[i] <= '9') { + if (result > max) return false; + result *= 10; + result += (unsigned) (str.ptr[i] - '0'); + i++; + } + *val = (size_t) result; + return true; +} + // Chunk deletion marker is the MSB in the "processed" counter #define MG_DMARK ((size_t) 1 << (sizeof(size_t) * 8 - 1)) @@ -1382,7 +1398,9 @@ int mg_url_decode(const char *src, size_t src_len, char *dst, size_t dst_len, return i >= src_len && j < dst_len ? (int) j : -1; } -static bool isok(uint8_t c) { return c == '\n' || c == '\r' || c >= ' '; } +static bool isok(uint8_t c) { + return c == '\n' || c == '\r' || c >= ' '; +} int mg_http_get_request_len(const unsigned char *buf, size_t buf_len) { size_t i; @@ -1463,9 +1481,7 @@ int mg_http_parse(const char *s, size_t len, struct mg_http_message *hm) { mg_http_parse_headers(s, end, hm->headers, sizeof(hm->headers) / sizeof(hm->headers[0])); if ((cl = mg_http_get_header(hm, "Content-Length")) != NULL) { - int64_t content_len = mg_to64(*cl); - if(content_len < 0) return -1; - hm->body.len = (size_t) content_len; + if (mg_to_size_t(*cl, &hm->body.len) == false) return -1; hm->message.len = (size_t) req_len + hm->body.len; } @@ -1662,18 +1678,18 @@ static struct mg_str guess_content_type(struct mg_str path, const char *extra) { return mg_str("text/plain; charset=utf-8"); } -static int getrange(struct mg_str *s, int64_t *a, int64_t *b) { +static int getrange(struct mg_str *s, size_t *a, size_t *b) { size_t i, numparsed = 0; // MG_INFO(("%.*s", (int) s->len, s->ptr)); for (i = 0; i + 6 < s->len; i++) { if (memcmp(&s->ptr[i], "bytes=", 6) == 0) { struct mg_str p = mg_str_n(s->ptr + i + 6, s->len - i - 6); if (p.len > 0 && p.ptr[0] >= '0' && p.ptr[0] <= '9') numparsed++; - *a = mg_to64(p); + if (!mg_to_size_t(p, a)) return 0; // MG_INFO(("PPP [%.*s] %d", (int) p.len, p.ptr, numparsed)); while (p.len && p.ptr[0] >= '0' && p.ptr[0] <= '9') p.ptr++, p.len--; if (p.len && p.ptr[0] == '-') p.ptr++, p.len--; - *b = mg_to64(p); + if (!mg_to_size_t(p, b)) return 0; if (p.len > 0 && p.ptr[0] >= '0' && p.ptr[0] <= '9') numparsed++; // MG_INFO(("PPP [%.*s] %d", (int) p.len, p.ptr, numparsed)); break; @@ -1725,12 +1741,12 @@ void mg_http_serve_file(struct mg_connection *c, struct mg_http_message *hm, } else { int n, status = 200; char range[100]; - int64_t r1 = 0, r2 = 0, cl = (int64_t) size; - + size_t r1 = 0, r2 = 0, cl = size; + // Handle Range header struct mg_str *rh = mg_http_get_header(hm, "Range"); range[0] = '\0'; - if (rh != NULL && (n = getrange(rh, &r1, &r2)) > 0 && r1 >= 0 && r2 >= 0) { + if (rh != NULL && (n = getrange(rh, &r1, &r2)) > 0) { // If range is specified like "400-", set second limit to content len if (n == 1) r2 = cl - 1; if (r1 > r2 || r2 >= cl) { @@ -1742,9 +1758,9 @@ void mg_http_serve_file(struct mg_connection *c, struct mg_http_message *hm, status = 206; cl = r2 - r1 + 1; mg_snprintf(range, sizeof(range), - "Content-Range: bytes %lld-%lld/%lld\r\n", r1, r1 + cl - 1, - (int64_t) size); - fs->sk(fd->fd, (size_t) r1); + "Content-Range: bytes %llu-%llu/%llu\r\n", (uint64_t) r1, + (uint64_t) (r1 + cl - 1), (uint64_t) size); + fs->sk(fd->fd, r1); } } mg_printf(c, @@ -1754,8 +1770,8 @@ void mg_http_serve_file(struct mg_connection *c, struct mg_http_message *hm, "Content-Length: %llu\r\n" "%s%s%s\r\n", status, mg_http_status_code_str(status), (int) mime.len, mime.ptr, - etag, cl, gzip ? "Content-Encoding: gzip\r\n" : "", range, - opts->extra_headers ? opts->extra_headers : ""); + etag, (uint64_t) cl, gzip ? "Content-Encoding: gzip\r\n" : "", + range, opts->extra_headers ? opts->extra_headers : ""); if (mg_vcasecmp(&hm->method, "HEAD") == 0) { c->is_draining = 1; c->is_resp = 0; @@ -1766,7 +1782,7 @@ void mg_http_serve_file(struct mg_connection *c, struct mg_http_message *hm, sizeof(size_t) * sizeof(size_t)]; c->pfn = static_cb; c->pfn_data = fd; - *clp = (size_t) cl; + *clp = cl; } } } @@ -5306,32 +5322,6 @@ void mg_unhex(const char *buf, size_t len, unsigned char *to) { } } -uint64_t mg_tou64(struct mg_str str) { - uint64_t result = 0; - size_t i = 0; - while (i < str.len && (str.ptr[i] == ' ' || str.ptr[i] == '\t')) i++; - while (i < str.len && str.ptr[i] >= '0' && str.ptr[i] <= '9') { - result *= 10; - result += (unsigned) (str.ptr[i] - '0'); - i++; - } - return result; -} - -int64_t mg_to64(struct mg_str str) { - int64_t result = 0, neg = 1, max = 922337203685477570 /* INT64_MAX/10-10 */; - size_t i = 0; - while (i < str.len && (str.ptr[i] == ' ' || str.ptr[i] == '\t')) i++; - if (i < str.len && str.ptr[i] == '-') neg = -1, i++; - while (i < str.len && str.ptr[i] >= '0' && str.ptr[i] <= '9') { - if (result > max) return 0; - result *= 10; - result += (str.ptr[i] - '0'); - i++; - } - return result * neg; -} - char *mg_remove_double_dots(char *s) { char *saved = s, *p = s; while (*s != '\0') { diff --git a/mongoose.h b/mongoose.h index db184f97..318033e5 100644 --- a/mongoose.h +++ b/mongoose.h @@ -829,8 +829,6 @@ char *mg_hex(const void *buf, size_t len, char *dst); void mg_unhex(const char *buf, size_t len, unsigned char *to); unsigned long mg_unhexn(const char *s, size_t len); int mg_check_ip_acl(struct mg_str acl, uint32_t remote_ip); -int64_t mg_to64(struct mg_str str); -uint64_t mg_tou64(struct mg_str str); char *mg_remove_double_dots(char *s); diff --git a/src/http.c b/src/http.c index c2418196..cfdcef56 100644 --- a/src/http.c +++ b/src/http.c @@ -1,7 +1,7 @@ +#include "http.h" #include "arch.h" #include "base64.h" #include "fmt.h" -#include "http.h" #include "json.h" #include "log.h" #include "net.h" @@ -11,6 +11,22 @@ #include "version.h" #include "ws.h" +bool mg_to_size_t(struct mg_str str, size_t *val); +bool mg_to_size_t(struct mg_str str, size_t *val) { + uint64_t result = 0, max = 1844674407370955160 /* (UINT64_MAX-9)/10 */; + size_t i = 0; + while (i < str.len && (str.ptr[i] == ' ' || str.ptr[i] == '\t')) i++; + if (i < str.len && str.ptr[i] == '-') return false; + while (i < str.len && str.ptr[i] >= '0' && str.ptr[i] <= '9') { + if (result > max) return false; + result *= 10; + result += (unsigned) (str.ptr[i] - '0'); + i++; + } + *val = (size_t) result; + return true; +} + // Chunk deletion marker is the MSB in the "processed" counter #define MG_DMARK ((size_t) 1 << (sizeof(size_t) * 8 - 1)) @@ -150,7 +166,9 @@ int mg_url_decode(const char *src, size_t src_len, char *dst, size_t dst_len, return i >= src_len && j < dst_len ? (int) j : -1; } -static bool isok(uint8_t c) { return c == '\n' || c == '\r' || c >= ' '; } +static bool isok(uint8_t c) { + return c == '\n' || c == '\r' || c >= ' '; +} int mg_http_get_request_len(const unsigned char *buf, size_t buf_len) { size_t i; @@ -231,9 +249,7 @@ int mg_http_parse(const char *s, size_t len, struct mg_http_message *hm) { mg_http_parse_headers(s, end, hm->headers, sizeof(hm->headers) / sizeof(hm->headers[0])); if ((cl = mg_http_get_header(hm, "Content-Length")) != NULL) { - int64_t content_len = mg_to64(*cl); - if(content_len < 0) return -1; - hm->body.len = (size_t) content_len; + if (mg_to_size_t(*cl, &hm->body.len) == false) return -1; hm->message.len = (size_t) req_len + hm->body.len; } @@ -430,18 +446,18 @@ static struct mg_str guess_content_type(struct mg_str path, const char *extra) { return mg_str("text/plain; charset=utf-8"); } -static int getrange(struct mg_str *s, int64_t *a, int64_t *b) { +static int getrange(struct mg_str *s, size_t *a, size_t *b) { size_t i, numparsed = 0; // MG_INFO(("%.*s", (int) s->len, s->ptr)); for (i = 0; i + 6 < s->len; i++) { if (memcmp(&s->ptr[i], "bytes=", 6) == 0) { struct mg_str p = mg_str_n(s->ptr + i + 6, s->len - i - 6); if (p.len > 0 && p.ptr[0] >= '0' && p.ptr[0] <= '9') numparsed++; - *a = mg_to64(p); + if (!mg_to_size_t(p, a)) return 0; // MG_INFO(("PPP [%.*s] %d", (int) p.len, p.ptr, numparsed)); while (p.len && p.ptr[0] >= '0' && p.ptr[0] <= '9') p.ptr++, p.len--; if (p.len && p.ptr[0] == '-') p.ptr++, p.len--; - *b = mg_to64(p); + if (!mg_to_size_t(p, b)) return 0; if (p.len > 0 && p.ptr[0] >= '0' && p.ptr[0] <= '9') numparsed++; // MG_INFO(("PPP [%.*s] %d", (int) p.len, p.ptr, numparsed)); break; @@ -493,12 +509,12 @@ void mg_http_serve_file(struct mg_connection *c, struct mg_http_message *hm, } else { int n, status = 200; char range[100]; - int64_t r1 = 0, r2 = 0, cl = (int64_t) size; - + size_t r1 = 0, r2 = 0, cl = size; + // Handle Range header struct mg_str *rh = mg_http_get_header(hm, "Range"); range[0] = '\0'; - if (rh != NULL && (n = getrange(rh, &r1, &r2)) > 0 && r1 >= 0 && r2 >= 0) { + if (rh != NULL && (n = getrange(rh, &r1, &r2)) > 0) { // If range is specified like "400-", set second limit to content len if (n == 1) r2 = cl - 1; if (r1 > r2 || r2 >= cl) { @@ -510,9 +526,9 @@ void mg_http_serve_file(struct mg_connection *c, struct mg_http_message *hm, status = 206; cl = r2 - r1 + 1; mg_snprintf(range, sizeof(range), - "Content-Range: bytes %lld-%lld/%lld\r\n", r1, r1 + cl - 1, - (int64_t) size); - fs->sk(fd->fd, (size_t) r1); + "Content-Range: bytes %llu-%llu/%llu\r\n", (uint64_t) r1, + (uint64_t) (r1 + cl - 1), (uint64_t) size); + fs->sk(fd->fd, r1); } } mg_printf(c, @@ -522,8 +538,8 @@ void mg_http_serve_file(struct mg_connection *c, struct mg_http_message *hm, "Content-Length: %llu\r\n" "%s%s%s\r\n", status, mg_http_status_code_str(status), (int) mime.len, mime.ptr, - etag, cl, gzip ? "Content-Encoding: gzip\r\n" : "", range, - opts->extra_headers ? opts->extra_headers : ""); + etag, (uint64_t) cl, gzip ? "Content-Encoding: gzip\r\n" : "", + range, opts->extra_headers ? opts->extra_headers : ""); if (mg_vcasecmp(&hm->method, "HEAD") == 0) { c->is_draining = 1; c->is_resp = 0; @@ -534,7 +550,7 @@ void mg_http_serve_file(struct mg_connection *c, struct mg_http_message *hm, sizeof(size_t) * sizeof(size_t)]; c->pfn = static_cb; c->pfn_data = fd; - *clp = (size_t) cl; + *clp = cl; } } } diff --git a/src/str.c b/src/str.c index 20af52e7..f7f00e70 100644 --- a/src/str.c +++ b/src/str.c @@ -187,32 +187,6 @@ void mg_unhex(const char *buf, size_t len, unsigned char *to) { } } -uint64_t mg_tou64(struct mg_str str) { - uint64_t result = 0; - size_t i = 0; - while (i < str.len && (str.ptr[i] == ' ' || str.ptr[i] == '\t')) i++; - while (i < str.len && str.ptr[i] >= '0' && str.ptr[i] <= '9') { - result *= 10; - result += (unsigned) (str.ptr[i] - '0'); - i++; - } - return result; -} - -int64_t mg_to64(struct mg_str str) { - int64_t result = 0, neg = 1, max = 922337203685477570 /* INT64_MAX/10-10 */; - size_t i = 0; - while (i < str.len && (str.ptr[i] == ' ' || str.ptr[i] == '\t')) i++; - if (i < str.len && str.ptr[i] == '-') neg = -1, i++; - while (i < str.len && str.ptr[i] >= '0' && str.ptr[i] <= '9') { - if (result > max) return 0; - result *= 10; - result += (str.ptr[i] - '0'); - i++; - } - return result * neg; -} - char *mg_remove_double_dots(char *s) { char *saved = s, *p = s; while (*s != '\0') { diff --git a/src/str.h b/src/str.h index 597d2ad7..00554781 100644 --- a/src/str.h +++ b/src/str.h @@ -35,6 +35,4 @@ char *mg_hex(const void *buf, size_t len, char *dst); void mg_unhex(const char *buf, size_t len, unsigned char *to); unsigned long mg_unhexn(const char *s, size_t len); int mg_check_ip_acl(struct mg_str acl, uint32_t remote_ip); -int64_t mg_to64(struct mg_str str); -uint64_t mg_tou64(struct mg_str str); char *mg_remove_double_dots(char *s); diff --git a/test/unit_test.c b/test/unit_test.c index c5f90974..c8161214 100644 --- a/test/unit_test.c +++ b/test/unit_test.c @@ -790,10 +790,18 @@ static void test_http_server(void) { ASSERT(fetch(&mgr, buf, url, "GET /..ddot HTTP/1.0\n\n") == 301); ASSERT(fetch(&mgr, buf, url, "GET /..ddot/ HTTP/1.0\n\n") == 200); ASSERT(cmpbody(buf, "hi\n") == 0); - ASSERT(fetch(&mgr, buf, url, "GET /a.txt HTTP/1.0\n" - "Content-Length: -123\n\n") == 0); - ASSERT(fetch(&mgr, buf, url, "POST /a.txt HTTP/1.0\n" + ASSERT(fetch(&mgr, buf, url, + "GET /a.txt HTTP/1.0\n" "Content-Length: -123\n\n") == 0); + ASSERT(fetch(&mgr, buf, url, + "POST /a.txt HTTP/1.0\n" + "Content-Length: -123\n\n") == 0); + ASSERT(fetch(&mgr, buf, url, + "GET /a.txt HTTP/1.0\n" + "Content-Length: 19000000000000000000\n\n") == 0); + ASSERT(fetch(&mgr, buf, url, + "POST /a.txt HTTP/1.0\n" + "Content-Length: 19000000000000000000\n\n") == 0); { extern char *mg_http_etag(char *, size_t, size_t, time_t); @@ -1405,7 +1413,9 @@ static void test_http_range(void) { ASSERT(mgr.conns == NULL); } -static void f1(void *arg) { (*(int *) arg)++; } +static void f1(void *arg) { + (*(int *) arg)++; +} static void test_timer(void) { int v1 = 0, v2 = 0, v3 = 0; @@ -1964,14 +1974,19 @@ static void test_util(void) { free(s); } - ASSERT(mg_to64(mg_str("-9223372036854775809")) == 0); - ASSERT(mg_to64(mg_str("9223372036854775800")) == 0); - ASSERT(mg_to64(mg_str("9223372036854775700")) > 0); - ASSERT(mg_tou64(mg_str("0")) == 0); - ASSERT(mg_tou64(mg_str("123")) == 123); - ASSERT(mg_tou64(mg_str("")) == 0); - ASSERT(mg_tou64(mg_str("-")) == 0); - ASSERT(mg_tou64(mg_str("18446744073709551615")) == 18446744073709551615U); + { + extern bool mg_to_size_t(struct mg_str, size_t *); + size_t val = 1; + ASSERT(mg_to_size_t(mg_str("0"), &val) && val == 0); + ASSERT(mg_to_size_t(mg_str("123"), &val) && val == 123); + ASSERT(mg_to_size_t(mg_str(""), &val) && val == 0); + ASSERT(mg_to_size_t(mg_str("-"), &val) == false); + ASSERT(mg_to_size_t(mg_str("18446744073709551616"), &val) == + false); // range +1 + ASSERT(mg_to_size_t(mg_str("18446744073709551610"), &val) == false); + // TODO(): ASSERT(mg_to_size_t(mg_str("18446744073709551609"), &val) && + // val == 18446744073709551609U); // our max or SIZE_MAX + } { size_t i; @@ -2865,7 +2880,9 @@ static void start_thread(void (*f)(void *), void *p) { pthread_attr_destroy(&attr); } #else -static void start_thread(void (*f)(void *), void *p) { (void) f, (void) p; } +static void start_thread(void (*f)(void *), void *p) { + (void) f, (void) p; +} #endif static void test_queue(void) {