Skip to content

Commit

Permalink
Merge pull request #2737 from cesanta/strip
Browse files Browse the repository at this point in the history
cleanup 'str' API
  • Loading branch information
scaprile committed May 9, 2024
2 parents 6c7672f + 4c6c27d commit b46bee0
Show file tree
Hide file tree
Showing 22 changed files with 339 additions and 396 deletions.
4 changes: 0 additions & 4 deletions examples/rp2040/pico-rndis-device/main.c
Expand Up @@ -61,10 +61,6 @@ static void fn(struct mg_connection *c, int ev, void *ev_data, void *fn_dta) {
if (ev == MG_EV_HTTP_MSG) return mg_http_reply(c, 200, "", "ok\n");
}

uint64_t mg_now(void) {
return mg_millis();
}

int main(void) {
gpio_init(PICO_DEFAULT_LED_PIN);
gpio_set_dir(PICO_DEFAULT_LED_PIN, GPIO_OUT);
Expand Down
3 changes: 0 additions & 3 deletions examples/stm32/nucleo-h723zg-make-baremetal-builtin/main.c
Expand Up @@ -37,9 +37,6 @@ int hal_led_pin(void) {
return (int) LED1;
}

uint64_t mg_now(void) {
return mg_millis();
}
#endif

static void timer_fn(void *arg) {
Expand Down
201 changes: 81 additions & 120 deletions mongoose.c
Expand Up @@ -2227,6 +2227,17 @@ struct mg_fs mg_fs_posix = {p_stat, p_list, p_open, p_close, p_read,



static int mg_ncasecmp(const char *s1, const char *s2, size_t len) {
int diff = 0;
if (len > 0) do {
char c = *s1++, d = *s2++;
if (c >= 'A' && c <= 'Z') c += 'a' - 'A';
if (d >= 'A' && d <= 'Z') d += 'a' - 'A';
diff = c - d;
} while (diff == 0 && s1[-1] != '\0' && --len > 0);
return diff;
}

bool mg_to_size_t(struct mg_str str, size_t *val);
bool mg_to_size_t(struct mg_str str, size_t *val) {
size_t i = 0, max = (size_t) -1, max2 = max / 10, result = 0, ndigits = 0;
Expand Down Expand Up @@ -2517,15 +2528,15 @@ int mg_http_parse(const char *s, size_t len, struct mg_http_message *hm) {
// and method is not (PUT or POST) then reset body length to zero.
is_response = mg_ncasecmp(hm->method.buf, "HTTP/", 5) == 0;
if (hm->body.len == (size_t) ~0 && !is_response &&
mg_vcasecmp(&hm->method, "PUT") != 0 &&
mg_vcasecmp(&hm->method, "POST") != 0) {
mg_strcasecmp(hm->method, mg_str("PUT")) != 0 &&
mg_strcasecmp(hm->method, mg_str("POST")) != 0) {
hm->body.len = 0;
hm->message.len = (size_t) req_len;
}

// The 204 (No content) responses also have 0 body length
if (hm->body.len == (size_t) ~0 && is_response &&
mg_vcasecmp(&hm->uri, "204") == 0) {
mg_strcasecmp(hm->uri, mg_str("204")) == 0) {
hm->body.len = 0;
hm->message.len = (size_t) req_len;
}
Expand Down Expand Up @@ -2776,10 +2787,14 @@ void mg_http_serve_file(struct mg_connection *c, struct mg_http_message *hm,
if (path != NULL) {
// If a browser sends us "Accept-Encoding: gzip", try to open .gz first
struct mg_str *ae = mg_http_get_header(hm, "Accept-Encoding");
if (ae != NULL && mg_strstr(*ae, mg_str("gzip")) != NULL) {
mg_snprintf(tmp, sizeof(tmp), "%s.gz", path);
fd = mg_fs_open(fs, tmp, MG_FS_READ);
if (fd != NULL) gzip = true, path = tmp;
if (ae != NULL) {
char *ae_ = mg_mprintf("%.*s", ae->len, ae->buf);
if (strstr(ae_, "gzip") != NULL) {
mg_snprintf(tmp, sizeof(tmp), "%s.gz", path);
fd = mg_fs_open(fs, tmp, MG_FS_READ);
if (fd != NULL) gzip = true, path = tmp;
}
free(ae_);
}
// No luck opening .gz? Open what we've told to open
if (fd == NULL) fd = mg_fs_open(fs, path, MG_FS_READ);
Expand All @@ -2798,7 +2813,7 @@ void mg_http_serve_file(struct mg_connection *c, struct mg_http_message *hm,
// NOTE: mg_http_etag() call should go first!
} else if (mg_http_etag(etag, sizeof(etag), size, mtime) != NULL &&
(inm = mg_http_get_header(hm, "If-None-Match")) != NULL &&
mg_vcasecmp(inm, etag) == 0) {
mg_strcasecmp(*inm, mg_str(etag)) == 0) {
mg_fs_close(fd);
mg_http_reply(c, 304, opts->extra_headers, "");
} else {
Expand Down Expand Up @@ -2835,7 +2850,7 @@ void mg_http_serve_file(struct mg_connection *c, struct mg_http_message *hm,
status, mg_http_status_code_str(status), (int) mime.len, mime.buf,
etag, (uint64_t) cl, gzip ? "Content-Encoding: gzip\r\n" : "",
range, opts->extra_headers ? opts->extra_headers : "");
if (mg_vcasecmp(&hm->method, "HEAD") == 0) {
if (mg_strcasecmp(hm->method, mg_str("HEAD")) == 0) {
c->is_draining = 1;
c->is_resp = 0;
mg_fs_close(fd);
Expand Down Expand Up @@ -2991,7 +3006,8 @@ static int uri_to_path2(struct mg_connection *c, struct mg_http_message *hm,
}
n = strlen(path);
while (n > 1 && path[n - 1] == '/') path[--n] = 0; // Trim trailing slashes
flags = mg_vcmp(&hm->uri, "/") == 0 ? MG_FS_DIR : fs->st(path, NULL, NULL);
flags = mg_strcmp(hm->uri, mg_str("/")) == 0 ? MG_FS_DIR
: fs->st(path, NULL, NULL);
MG_VERBOSE(("%lu %.*s -> %s %d", c->id, (int) hm->uri.len, hm->uri.buf, path,
flags));
if (flags == 0) {
Expand Down Expand Up @@ -3054,8 +3070,7 @@ void mg_http_serve_dir(struct mg_connection *c, struct mg_http_message *hm,
#else
mg_http_reply(c, 403, "", "Forbidden\n");
#endif
} else if (flags && sp != NULL &&
mg_globmatch(sp, strlen(sp), path, strlen(path))) {
} else if (flags && sp != NULL && mg_match(mg_str(path), mg_str(sp), NULL)) {
mg_http_serve_ssi(c, opts->root_dir, path);
} else {
mg_http_serve_file(c, hm, path, opts);
Expand All @@ -3075,9 +3090,8 @@ size_t mg_url_encode(const char *s, size_t sl, char *buf, size_t len) {
if (mg_is_url_safe(c)) {
buf[n++] = s[i];
} else {
buf[n++] = '%';
mg_hex(&s[i], 1, &buf[n]);
n += 2;
mg_snprintf(&buf[n], 4, "%%%M", mg_print_hex, 1, &s[i]);
n += 3;
}
}
if (len > 0 && n < len - 1) buf[n] = '\0'; // Null-terminate the destination
Expand Down Expand Up @@ -3223,7 +3237,7 @@ static void http_cb(struct mg_connection *c, int ev, void *ev_data) {
hm.body.len = hm.message.len - (size_t) (hm.body.buf - hm.message.buf);
}
if ((te = mg_http_get_header(&hm, "Transfer-Encoding")) != NULL) {
if (mg_vcasecmp(te, "chunked") == 0) {
if (mg_strcasecmp(*te, mg_str("chunked")) == 0) {
is_chunked = true;
} else {
mg_error(c, "Invalid Transfer-Encoding"); // See #2460
Expand All @@ -3234,8 +3248,8 @@ static void http_cb(struct mg_connection *c, int ev, void *ev_data) {
// Content-length
bool is_response = mg_ncasecmp(hm.method.buf, "HTTP/", 5) == 0;
bool require_content_len = false;
if (!is_response && (mg_vcasecmp(&hm.method, "POST") == 0 ||
mg_vcasecmp(&hm.method, "PUT") == 0)) {
if (!is_response && (mg_strcasecmp(hm.method, mg_str("POST")) == 0 ||
mg_strcasecmp(hm.method, mg_str("PUT")) == 0)) {
// POST and PUT should include an entity body. Therefore, they should
// contain a Content-length header. Other requests can also contain a
// body, but their content has no defined semantics (RFC 7231)
Expand Down Expand Up @@ -4307,14 +4321,13 @@ size_t mg_mqtt_next_prop(struct mg_mqtt_message *msg, struct mg_mqtt_prop *prop,
}

void mg_mqtt_login(struct mg_connection *c, const struct mg_mqtt_opts *opts) {
char rnd[10], client_id[21];
char client_id[21];
struct mg_str cid = opts->client_id;
size_t total_len = 7 + 1 + 2 + 2;
uint8_t hdr[8] = {0, 4, 'M', 'Q', 'T', 'T', opts->version, 0};

if (cid.len == 0) {
mg_random(rnd, sizeof(rnd));
mg_hex(rnd, sizeof(rnd), client_id);
mg_random_str(client_id, sizeof(client_id) - 1);
client_id[sizeof(client_id) - 1] = '\0';
cid = mg_str(client_id);
}
Expand Down Expand Up @@ -4626,7 +4639,7 @@ size_t mg_printf(struct mg_connection *c, const char *fmt, ...) {

static bool mg_atonl(struct mg_str str, struct mg_addr *addr) {
uint32_t localhost = mg_htonl(0x7f000001);
if (mg_vcasecmp(&str, "localhost") != 0) return false;
if (mg_strcasecmp(str, mg_str("localhost")) != 0) return false;
memcpy(addr->ip, &localhost, sizeof(uint32_t));
addr->is_ip6 = false;
return true;
Expand Down Expand Up @@ -6618,7 +6631,10 @@ void mg_rpc_add(struct mg_rpc **head, struct mg_str method,
void (*fn)(struct mg_rpc_req *), void *fn_data) {
struct mg_rpc *rpc = (struct mg_rpc *) calloc(1, sizeof(*rpc));
if (rpc != NULL) {
rpc->method = mg_strdup(method), rpc->fn = fn, rpc->fn_data = fn_data;
rpc->method.buf = mg_mprintf("%.*s", method.len, method.buf);
rpc->method.len = method.len;
rpc->fn = fn;
rpc->fn_data = fn_data;
rpc->next = *head, *head = rpc;
}
}
Expand Down Expand Up @@ -8018,57 +8034,24 @@ struct mg_str mg_str_n(const char *s, size_t n) {
return str;
}

int mg_lower(const char *s) {
int c = *s;
if (c >= 'A' && c <= 'Z') c += 'a' - 'A';
return c;
static char tolc(char c) {
return (c >= 'A' && c <= 'Z') ? c + 'a' - 'A' : c;
}

int mg_ncasecmp(const char *s1, const char *s2, size_t len) {
int mg_casecmp(const char *s1, const char *s2) {
int diff = 0;
if (len > 0) do {
diff = mg_lower(s1++) - mg_lower(s2++);
} while (diff == 0 && s1[-1] != '\0' && --len > 0);
do {
char c = tolc(*s1++), d = tolc(*s2++);
diff = c - d;
} while (diff == 0 && s1[-1] != '\0');
return diff;
}

int mg_casecmp(const char *s1, const char *s2) {
return mg_ncasecmp(s1, s2, (size_t) ~0);
}

int mg_vcmp(const struct mg_str *s1, const char *s2) {
size_t n2 = strlen(s2), n1 = s1->len;
int r = strncmp(s1->buf, s2, (n1 < n2) ? n1 : n2);
if (r == 0) return (int) (n1 - n2);
return r;
}

int mg_vcasecmp(const struct mg_str *str1, const char *str2) {
size_t n2 = strlen(str2), n1 = str1->len;
int r = mg_ncasecmp(str1->buf, str2, (n1 < n2) ? n1 : n2);
if (r == 0) return (int) (n1 - n2);
return r;
}

struct mg_str mg_strdup(const struct mg_str s) {
struct mg_str r = {NULL, 0};
if (s.len > 0 && s.buf != NULL) {
char *sc = (char *) calloc(1, s.len + 1);
if (sc != NULL) {
memcpy(sc, s.buf, s.len);
sc[s.len] = '\0';
r.buf = sc;
r.len = s.len;
}
}
return r;
}

int mg_strcmp(const struct mg_str str1, const struct mg_str str2) {
size_t i = 0;
while (i < str1.len && i < str2.len) {
int c1 = str1.buf[i];
int c2 = str2.buf[i];
char c1 = str1.buf[i];
char c2 = str2.buf[i];
if (c1 < c2) return -1;
if (c1 > c2) return 1;
i++;
Expand All @@ -8078,27 +8061,18 @@ int mg_strcmp(const struct mg_str str1, const struct mg_str str2) {
return 0;
}

const char *mg_strstr(const struct mg_str haystack,
const struct mg_str needle) {
size_t i;
if (needle.len > haystack.len) return NULL;
if (needle.len == 0) return haystack.buf;
for (i = 0; i <= haystack.len - needle.len; i++) {
if (memcmp(haystack.buf + i, needle.buf, needle.len) == 0) {
return haystack.buf + i;
}
int mg_strcasecmp(const struct mg_str str1, const struct mg_str str2) {
size_t i = 0;
while (i < str1.len && i < str2.len) {
char c1 = tolc(str1.buf[i]);
char c2 = tolc(str2.buf[i]);
if (c1 < c2) return -1;
if (c1 > c2) return 1;
i++;
}
return NULL;
}

static bool is_space(int c) {
return c == ' ' || c == '\r' || c == '\n' || c == '\t';
}

struct mg_str mg_strstrip(struct mg_str s) {
while (s.len > 0 && is_space((int) *s.buf)) s.buf++, s.len--;
while (s.len > 0 && is_space((int) *(s.buf + s.len - 1))) s.len--;
return s;
if (i < str1.len) return 1;
if (i < str2.len) return -1;
return 0;
}

bool mg_match(struct mg_str s, struct mg_str p, struct mg_str *caps) {
Expand Down Expand Up @@ -8133,10 +8107,6 @@ bool mg_match(struct mg_str s, struct mg_str p, struct mg_str *caps) {
return true;
}

bool mg_globmatch(const char *s1, size_t n1, const char *s2, size_t n2) {
return mg_match(mg_str_n(s2, n2), mg_str_n(s1, n1), NULL);
}

bool mg_span(struct mg_str s, struct mg_str *a, struct mg_str *b, char sep) {
if (s.len == 0 || s.buf == NULL) {
return false; // Empty string, nothing to span - fail
Expand All @@ -8150,27 +8120,17 @@ bool mg_span(struct mg_str s, struct mg_str *a, struct mg_str *b, char sep) {
}
}

char *mg_hex(const void *buf, size_t len, char *to) {
const unsigned char *p = (const unsigned char *) buf;
const char *hex = "0123456789abcdef";
size_t i = 0;
for (; len--; p++) {
to[i++] = hex[p[0] >> 4];
to[i++] = hex[p[0] & 0x0f];
}
to[i] = '\0';
return to;
}

static unsigned char mg_unhex_nimble(unsigned char c) {
return (c >= '0' && c <= '9') ? (unsigned char) (c - '0')
: (c >= 'A' && c <= 'F') ? (unsigned char) (c - '7')
: (unsigned char) (c - 'W');
uint8_t mg_toi(char c, int base) {
return (c >= '0' && c <= '9') ? (uint8_t) (c - '0')
: base == 16 ? (c >= 'A' && c <= 'F') ? (uint8_t) (c - '7')
: (c >= 'a' && c <= 'f') ? (uint8_t) (c - 'W')
: (uint8_t) ~0
: (uint8_t) ~0;
}

unsigned long mg_unhexn(const char *s, size_t len) {
unsigned long i = 0, v = 0;
for (i = 0; i < len; i++) v <<= 4, v |= mg_unhex_nimble(((uint8_t *) s)[i]);
for (i = 0; i < len; i++) v <<= 4, v |= mg_toi(((char *) s)[i], 16);
return v;
}

Expand All @@ -8181,18 +8141,6 @@ void mg_unhex(const char *buf, size_t len, unsigned char *to) {
}
}

bool mg_path_is_sane(const struct mg_str path) {
const char *s = path.buf;
size_t n = path.len;
if (path.buf[0] == '.' && path.buf[1] == '.') return false; // Starts with ..
for (; s[0] != '\0' && n > 0; s++, n--) {
if ((s[0] == '/' || s[0] == '\\') && n >= 2) { // Subdir?
if (s[1] == '.' && s[2] == '.') return false; // Starts with ..
}
}
return true;
}

#ifdef MG_ENABLE_LINES
#line 1 "src/timer.c"
#endif
Expand Down Expand Up @@ -10607,7 +10555,8 @@ static int mg_parse_pem(const struct mg_str pem, const struct mg_str label,
const char *c;
struct mg_str caps[5];
if (!mg_match(pem, mg_str("#-----BEGIN #-----#-----END #-----#"), caps)) {
*der = mg_strdup(pem);
der->buf = mg_mprintf("%.*s", pem.len, pem.buf);
der->len = pem.len;
return 0;
}
if (mg_strcmp(caps[1], label) != 0 || mg_strcmp(caps[3], label) != 0) {
Expand Down Expand Up @@ -10923,7 +10872,7 @@ void mg_tls_init(struct mg_connection *c, const struct mg_tls_opts *opts) {
}
mbedtls_ssl_conf_rng(&tls->conf, mg_mbed_rng, c);

if (opts->ca.len == 0 || mg_vcmp(&opts->ca, "*") == 0) {
if (opts->ca.len == 0 || mg_strcmp(opts->ca, mg_str("*")) == 0) {
mbedtls_ssl_conf_authmode(&tls->conf, MBEDTLS_SSL_VERIFY_NONE);
} else {
if (mg_load_cert(opts->ca, &tls->ca) == false) goto fail;
Expand Down Expand Up @@ -14948,6 +14897,18 @@ int mg_check_ip_acl(struct mg_str acl, struct mg_addr *remote_ip) {
return allowed == '+';
}

bool mg_path_is_sane(const struct mg_str path) {
const char *s = path.buf;
size_t n = path.len;
if (path.buf[0] == '.' && path.buf[1] == '.') return false; // Starts with ..
for (; s[0] != '\0' && n > 0; s++, n--) {
if ((s[0] == '/' || s[0] == '\\') && n >= 2) { // Subdir?
if (s[1] == '.' && s[2] == '.') return false; // Starts with ..
}
}
return true;
}

#if MG_ENABLE_CUSTOM_MILLIS
#else
uint64_t mg_millis(void) {
Expand Down

0 comments on commit b46bee0

Please sign in to comment.