1 // Copyright (c) 2004-2013 Sergey Lyubka
2 // Copyright (c) 2013-2021 Cesanta Software Limited
5 // This software is dual-licensed: you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License version 2 as
7 // published by the Free Software Foundation. For the terms of this
8 // license, see http://www.gnu.org/licenses/
10 // You are free to use this software under the terms of the GNU General
11 // Public License, but WITHOUT ANY WARRANTY; without even the implied
12 // warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13 // See the GNU General Public License for more details.
15 // Alternatively, you can license this software under a commercial
16 // license, as set out in https://www.mongoose.ws/licensing/
20 #ifdef MG_ENABLE_LINES
21 #line 1 "src/base64.c"
26 static int mg_b64idx(int c) {
34 return c == 62 ? '+' : '/';
38 static int mg_b64rev(int c) {
39 if (c >= 'A' && c <= 'Z') {
41 } else if (c >= 'a' && c <= 'z') {
43 } else if (c >= '0' && c <= '9') {
45 } else if (c == '+') {
47 } else if (c == '/') {
49 } else if (c == '=') {
56 int mg_base64_update(unsigned char ch, char *to, int n) {
57 int rem = (n & 3) % 3;
59 to[n] = (char) mg_b64idx(ch >> 2);
60 to[++n] = (char) ((ch & 3) << 4);
61 } else if (rem == 1) {
62 to[n] = (char) mg_b64idx(to[n] | (ch >> 4));
63 to[++n] = (char) ((ch & 15) << 2);
65 to[n] = (char) mg_b64idx(to[n] | (ch >> 6));
66 to[++n] = (char) mg_b64idx(ch & 63);
72 int mg_base64_final(char *to, int n) {
74 // printf("---[%.*s]\n", n, to);
75 if (n & 3) n = mg_base64_update(0, to, n);
76 if ((saved & 3) == 2) n--;
77 // printf(" %d[%.*s]\n", n, n, to);
78 while (n & 3) to[n++] = '=';
83 int mg_base64_encode(const unsigned char *p, int n, char *to) {
85 for (i = 0; i < n; i++) len = mg_base64_update(p[i], to, len);
86 len = mg_base64_final(to, len);
90 int mg_base64_decode(const char *src, int n, char *dst) {
91 const char *end = src + n;
93 while (src + 3 < end) {
94 int a = mg_b64rev(src[0]), b = mg_b64rev(src[1]), c = mg_b64rev(src[2]),
95 d = mg_b64rev(src[3]);
96 if (a == 64 || a < 0 || b == 64 || b < 0 || c < 0 || d < 0) return 0;
97 dst[len++] = (char) ((a << 2) | (b >> 4));
99 dst[len++] = (char) ((b << 4) | (c >> 2));
100 if (src[3] != '=') dst[len++] = (char) ((c << 6) | d);
108 #ifdef MG_ENABLE_LINES
118 struct dns_data *next;
119 struct mg_connection *c;
120 unsigned long expire;
124 static struct dns_data *s_reqs; // Active DNS requests
126 static void mg_sendnsreq(struct mg_connection *, struct mg_str *, int,
127 struct mg_dns *, bool);
129 static void mg_dns_free(struct dns_data *d) {
130 LIST_DELETE(struct dns_data, &s_reqs, d);
134 void mg_resolve_cancel(struct mg_connection *c) {
135 struct dns_data *tmp, *d;
136 for (d = s_reqs; d != NULL; d = tmp) {
138 if (d->c == c) mg_dns_free(d);
142 static size_t mg_dns_parse_name_depth(const uint8_t *s, size_t len, size_t ofs,
143 char *to, size_t tolen, int depth) {
145 if (tolen > 0) to[0] = '\0';
146 if (depth > 5) return 0;
147 while (ofs + i + 1 < len) {
148 size_t n = s[ofs + i];
154 size_t ptr = (((n & 0x3f) << 8) | s[ofs + i + 1]); // 12 is hdr len
155 if (ptr + 1 < len && (s[ptr] & 0xc0) == 0 &&
156 mg_dns_parse_name_depth(s, len, ptr, to, tolen, depth + 1) == 0)
161 if (ofs + i + n + 1 >= len) return 0;
163 if (j < tolen) to[j] = '.';
166 if (j + n < tolen) memcpy(&to[j], &s[ofs + i + 1], n);
169 if (j < tolen) to[j] = '\0'; // Zero-terminate this chunk
171 if (tolen > 0) to[tolen - 1] = '\0'; // Make sure make sure it is nul-term
175 static size_t mg_dns_parse_name(const uint8_t *s, size_t n, size_t ofs,
176 char *dst, size_t dstlen) {
177 return mg_dns_parse_name_depth(s, n, ofs, dst, dstlen, 0);
180 size_t mg_dns_parse_rr(const uint8_t *buf, size_t len, size_t ofs,
181 bool is_question, struct mg_dns_rr *rr) {
182 const uint8_t *s = buf + ofs, *e = &buf[len];
184 memset(rr, 0, sizeof(*rr));
185 if (len < sizeof(struct mg_dns_header)) return 0; // Too small
186 if (len > 512) return 0; // Too large, we don't expect that
187 if (s >= e) return 0; // Overflow
189 if ((rr->nlen = (uint16_t) mg_dns_parse_name(buf, len, ofs, NULL, 0)) == 0)
193 rr->atype = (uint16_t) (((uint16_t) s[-4] << 8) | s[-3]);
194 rr->aclass = (uint16_t) (((uint16_t) s[-2] << 8) | s[-1]);
195 if (is_question) return (size_t) (rr->nlen + 4);
199 rr->alen = (uint16_t) (((uint16_t) s[-2] << 8) | s[-1]);
200 if (s + rr->alen > e) return 0;
201 return (size_t) (rr->nlen + rr->alen + 10);
204 bool mg_dns_parse(const uint8_t *buf, size_t len, struct mg_dns_message *dm) {
205 const struct mg_dns_header *h = (struct mg_dns_header *) buf;
207 size_t i, n, ofs = sizeof(*h);
208 memset(dm, 0, sizeof(*dm));
210 if (len < sizeof(*h)) return 0; // Too small, headers dont fit
211 if (mg_ntohs(h->num_questions) > 1) return 0; // Sanity
212 if (mg_ntohs(h->num_answers) > 10) return 0; // Sanity
213 dm->txnid = mg_ntohs(h->txnid);
215 for (i = 0; i < mg_ntohs(h->num_questions); i++) {
216 if ((n = mg_dns_parse_rr(buf, len, ofs, true, &rr)) == 0) return false;
217 // LOG(LL_INFO, ("Q %zu %zu", ofs, n));
220 for (i = 0; i < mg_ntohs(h->num_answers); i++) {
221 // LOG(LL_INFO, ("A -- %zu %zu %s", ofs, n, dm->name));
222 if ((n = mg_dns_parse_rr(buf, len, ofs, false, &rr)) == 0) return false;
223 mg_dns_parse_name(buf, len, ofs, dm->name, sizeof(dm->name));
226 if (rr.alen == 4 && rr.atype == 1 && rr.aclass == 1) {
227 dm->addr.is_ip6 = false;
228 memcpy(&dm->addr.ip, &buf[ofs - 4], 4);
230 break; // Return success
231 } else if (rr.alen == 16 && rr.atype == 28 && rr.aclass == 1) {
232 dm->addr.is_ip6 = true;
233 memcpy(&dm->addr.ip6, &buf[ofs - 16], 16);
235 break; // Return success
241 static void dns_cb(struct mg_connection *c, int ev, void *ev_data,
243 struct dns_data *d, *tmp;
244 if (ev == MG_EV_POLL) {
245 unsigned long now = *(unsigned long *) ev_data;
246 for (d = s_reqs; d != NULL; d = tmp) {
248 // LOG(LL_DEBUG, ("%lu %lu dns poll", d->expire, now));
249 if (now > d->expire) mg_error(d->c, "DNS timeout");
251 } else if (ev == MG_EV_READ) {
252 struct mg_dns_message dm;
254 if (mg_dns_parse(c->recv.buf, c->recv.len, &dm) == false) {
255 char *s = mg_hexdump(c->recv.buf, c->recv.len);
256 LOG(LL_ERROR, ("Unexpected DNS response:\n%s\n", s));
259 LOG(LL_VERBOSE_DEBUG, ("%s %d", dm.name, dm.resolved));
260 for (d = s_reqs; d != NULL; d = tmp) {
262 // LOG(LL_INFO, ("d %p %hu %hu", d, d->txnid, dm.txnid));
263 if (dm.txnid != d->txnid) continue;
264 if (d->c->is_resolving) {
265 d->c->is_resolving = 0;
270 dm.addr.port = d->c->peer.port; // Save port
271 d->c->peer = dm.addr; // Copy resolved address
272 LOG(LL_DEBUG, ("%lu %s resolved to %s", d->c->id, dm.name,
273 mg_ntoa(&d->c->peer, buf, sizeof(buf))));
274 mg_connect_resolved(d->c);
276 } else if (dm.addr.is_ip6 == false && dm.name[0] != '\0') {
277 struct mg_str x = mg_str(dm.name);
278 mg_sendnsreq(d->c, &x, c->mgr->dnstimeout, &c->mgr->dns6, true);
281 mg_error(d->c, "%s DNS lookup failed", dm.name);
284 LOG(LL_ERROR, ("%lu already resolved", d->c->id));
290 if (!resolved) LOG(LL_ERROR, ("stray DNS reply"));
292 } else if (ev == MG_EV_CLOSE) {
293 for (d = s_reqs; d != NULL; d = tmp) {
301 static void mg_dns_send(struct mg_connection *c, const struct mg_str *name,
302 uint16_t txnid, bool ipv6) {
304 struct mg_dns_header header;
308 memset(&pkt, 0, sizeof(pkt));
309 pkt.header.txnid = mg_htons(txnid);
310 pkt.header.flags = mg_htons(0x100);
311 pkt.header.num_questions = mg_htons(1);
312 for (i = n = 0; i < sizeof(pkt.data) - 5; i++) {
313 if (name->ptr[i] == '.' || i >= name->len) {
314 pkt.data[n] = (uint8_t) (i - n);
315 memcpy(&pkt.data[n + 1], name->ptr + n, i - n);
318 if (i >= name->len) break;
320 memcpy(&pkt.data[n], "\x00\x00\x01\x00\x01", 5); // A query
322 if (ipv6) pkt.data[n - 3] = 0x1c; // AAAA query
323 // memcpy(&pkt.data[n], "\xc0\x0c\x00\x1c\x00\x01", 6); // AAAA query
325 mg_send(c, &pkt, sizeof(pkt.header) + n);
327 // Immediately after A query, send AAAA query. Whatever reply comes first,
328 // we'll use it. Note: we cannot send two queries in a single packet.
329 // https://stackoverflow.com/questions/4082081/requesting-a-and-aaaa-records-in-single-dns-query
330 pkt.data[n - 3] = 0x1c; // AAAA query
331 mg_send(c, &pkt, sizeof(pkt.header) + n);
335 static void mg_sendnsreq(struct mg_connection *c, struct mg_str *name, int ms,
336 struct mg_dns *dnsc, bool ipv6) {
337 struct dns_data *d = NULL;
338 if (dnsc->url == NULL) {
339 mg_error(c, "DNS server URL is NULL. Call mg_mgr_init()");
340 } else if (dnsc->c == NULL) {
341 dnsc->c = mg_connect(c->mgr, dnsc->url, NULL, NULL);
342 if (dnsc->c != NULL) {
343 dnsc->c->pfn = dns_cb;
344 snprintf(dnsc->c->label, sizeof(dnsc->c->label), "%s", "DNS");
345 // dnsc->c->is_hexdumping = 1;
348 if (dnsc->c == NULL) {
349 mg_error(c, "resolver");
350 } else if ((d = (struct dns_data *) calloc(1, sizeof(*d))) == NULL) {
351 mg_error(c, "resolve OOM");
356 d->txnid = s_reqs ? (uint16_t) (s_reqs->txnid + 1) : 1;
359 d->expire = mg_millis() + (unsigned long) ms;
362 LOG(LL_VERBOSE_DEBUG,
363 ("%lu resolving %.*s @ %s, txnid %hu", c->id, (int) name->len,
364 name->ptr, mg_ntoa(&dnsc->c->peer, buf, sizeof(buf)), d->txnid));
365 mg_dns_send(dnsc->c, name, d->txnid, ipv6);
369 void mg_resolve(struct mg_connection *c, struct mg_str *name, int ms) {
370 if (mg_aton(*name, &c->peer)) {
371 // name is an IP address, do not fire name resolution
372 mg_connect_resolved(c);
374 // name is not an IP, send DNS resolution request
375 mg_sendnsreq(c, name, ms, &c->mgr->dns4, false);
379 #ifdef MG_ENABLE_LINES
380 #line 1 "src/event.c"
387 void mg_call(struct mg_connection *c, int ev, void *ev_data) {
388 // Run user-defined handler first, in order to give it an ability
389 // to intercept processing (e.g. clean input buffer) before the
390 // protocol handler kicks in
391 if (c->fn != NULL) c->fn(c, ev, ev_data, c->fn_data);
392 if (c->pfn != NULL) c->pfn(c, ev, ev_data, c->pfn_data);
395 void mg_error(struct mg_connection *c, const char *fmt, ...) {
396 char mem[256], *buf = mem;
399 mg_vasprintf(&buf, sizeof(mem), fmt, ap);
401 LOG(LL_ERROR, ("%lu %s", c->id, buf));
402 c->is_closing = 1; // Set is_closing before sending MG_EV_CALL
403 mg_call(c, MG_EV_ERROR, buf); // Let user handler to override it
404 if (buf != mem) free(buf);
407 #ifdef MG_ENABLE_LINES
408 #line 1 "src/fs_packed.c"
418 const char *mg_unpack(const char *path, size_t *size, time_t *mtime);
419 const char *mg_unlist(size_t no);
420 #if MG_ENABLE_PACKED_FS
422 const char *mg_unpack(const char *path, size_t *size, time_t *mtime) {
423 (void) path, (void) size, (void) mtime;
426 const char *mg_unlist(size_t no) {
432 static int is_dir_prefix(const char *prefix, size_t n, const char *path) {
433 return n < strlen(path) && memcmp(prefix, path, n) == 0 && path[n] == '/';
434 //(n == 0 || path[n] == MG_DIRSEP);
437 static int packed_stat(const char *path, size_t *size, time_t *mtime) {
439 size_t i, n = strlen(path);
440 if (mg_unpack(path, size, mtime)) return MG_FS_READ; // Regular file
441 // Scan all files. If `path` is a dir prefix for any of them, it's a dir
442 for (i = 0; (p = mg_unlist(i)) != NULL; i++) {
443 if (is_dir_prefix(path, n, p)) return MG_FS_DIR;
448 static void packed_list(const char *dir, void (*fn)(const char *, void *),
450 char buf[256], tmp[sizeof(buf)];
451 const char *path, *begin, *end;
452 size_t i, n = strlen(dir);
453 tmp[0] = '\0'; // Previously listed entry
454 for (i = 0; (path = mg_unlist(i)) != NULL; i++) {
455 if (!is_dir_prefix(dir, n, path)) continue;
456 begin = &path[n + 1];
457 end = strchr(begin, '/');
458 if (end == NULL) end = begin + strlen(begin);
459 snprintf(buf, sizeof(buf), "%.*s", (int) (end - begin), begin);
460 buf[sizeof(buf) - 1] = '\0';
461 // If this entry has been already listed, skip
462 // NOTE: we're assuming that file list is sorted alphabetically
463 if (strcmp(buf, tmp) == 0) continue;
464 fn(buf, userdata); // Not yet listed, call user function
465 strcpy(tmp, buf); // And save this entry as listed
469 static struct mg_fd *packed_open(const char *path, int flags) {
471 const char *data = mg_unpack(path, &size, NULL);
472 struct packed_file *fp = NULL;
473 struct mg_fd *fd = NULL;
474 if (data == NULL) return NULL;
475 if (flags & MG_FS_WRITE) return NULL;
476 fp = (struct packed_file *) calloc(1, sizeof(*fp));
477 fd = (struct mg_fd *) calloc(1, sizeof(*fd));
481 fd->fs = &mg_fs_packed;
485 static void packed_close(struct mg_fd *fd) {
486 if (fd) free(fd->fd), free(fd);
489 static size_t packed_read(void *fd, void *buf, size_t len) {
490 struct packed_file *fp = (struct packed_file *) fd;
491 if (fp->pos + len > fp->size) len = fp->size - fp->pos;
492 memcpy(buf, &fp->data[fp->pos], len);
497 static size_t packed_write(void *fd, const void *buf, size_t len) {
498 (void) fd, (void) buf, (void) len;
502 static size_t packed_seek(void *fd, size_t offset) {
503 struct packed_file *fp = (struct packed_file *) fd;
505 if (fp->pos > fp->size) fp->pos = fp->size;
509 struct mg_fs mg_fs_packed = {packed_stat, packed_list, packed_open,
510 packed_close, packed_read, packed_write,
513 #ifdef MG_ENABLE_LINES
514 #line 1 "src/fs_posix.c"
518 #if defined(FOPEN_MAX)
519 static int p_stat(const char *path, size_t *size, time_t *mtime) {
522 wchar_t tmp[PATH_MAX];
523 MultiByteToWideChar(CP_UTF8, 0, path, -1, tmp, sizeof(tmp) / sizeof(tmp[0]));
524 if (_wstati64(tmp, &st) != 0) return 0;
527 if (stat(path, &st) != 0) return 0;
529 if (size) *size = (size_t) st.st_size;
530 if (mtime) *mtime = st.st_mtime;
531 return MG_FS_READ | MG_FS_WRITE | (S_ISDIR(st.st_mode) ? MG_FS_DIR : 0);
536 char d_name[MAX_PATH];
539 typedef struct win32_dir {
541 WIN32_FIND_DATAW info;
542 struct dirent result;
545 int gettimeofday(struct timeval *tv, void *tz) {
547 unsigned __int64 tmpres = 0;
550 GetSystemTimeAsFileTime(&ft);
551 tmpres |= ft.dwHighDateTime;
553 tmpres |= ft.dwLowDateTime;
554 tmpres /= 10; // convert into microseconds
555 tmpres -= (int64_t) 11644473600000000;
556 tv->tv_sec = (long) (tmpres / 1000000UL);
557 tv->tv_usec = (long) (tmpres % 1000000UL);
563 static int to_wchar(const char *path, wchar_t *wbuf, size_t wbuf_len) {
565 char buf[MAX_PATH * 2], buf2[MAX_PATH * 2], *p;
566 strncpy(buf, path, sizeof(buf));
567 buf[sizeof(buf) - 1] = '\0';
568 // Trim trailing slashes. Leave backslash for paths like "X:\"
569 p = buf + strlen(buf) - 1;
570 while (p > buf && p[-1] != ':' && (p[0] == '\\' || p[0] == '/')) *p-- = '\0';
571 memset(wbuf, 0, wbuf_len * sizeof(wchar_t));
572 ret = MultiByteToWideChar(CP_UTF8, 0, buf, -1, wbuf, (int) wbuf_len);
573 // Convert back to Unicode. If doubly-converted string does not match the
574 // original, something is fishy, reject.
575 WideCharToMultiByte(CP_UTF8, 0, wbuf, (int) wbuf_len, buf2, sizeof(buf2),
577 if (strcmp(buf, buf2) != 0) {
584 DIR *opendir(const char *name) {
586 wchar_t wpath[MAX_PATH];
590 SetLastError(ERROR_BAD_ARGUMENTS);
591 } else if ((d = (DIR *) calloc(1, sizeof(*d))) == NULL) {
592 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
594 to_wchar(name, wpath, sizeof(wpath) / sizeof(wpath[0]));
595 attrs = GetFileAttributesW(wpath);
596 if (attrs != 0Xffffffff && (attrs & FILE_ATTRIBUTE_DIRECTORY)) {
597 (void) wcscat(wpath, L"\\*");
598 d->handle = FindFirstFileW(wpath, &d->info);
599 d->result.d_name[0] = '\0';
608 int closedir(DIR *d) {
611 if (d->handle != INVALID_HANDLE_VALUE)
612 result = FindClose(d->handle) ? 0 : -1;
616 SetLastError(ERROR_BAD_ARGUMENTS);
621 struct dirent *readdir(DIR *d) {
622 struct dirent *result = NULL;
624 memset(&d->result, 0, sizeof(d->result));
625 if (d->handle != INVALID_HANDLE_VALUE) {
627 WideCharToMultiByte(CP_UTF8, 0, d->info.cFileName, -1, result->d_name,
628 sizeof(result->d_name), NULL, NULL);
629 if (!FindNextFileW(d->handle, &d->info)) {
630 FindClose(d->handle);
631 d->handle = INVALID_HANDLE_VALUE;
634 SetLastError(ERROR_FILE_NOT_FOUND);
637 SetLastError(ERROR_BAD_ARGUMENTS);
643 static void p_list(const char *dir, void (*fn)(const char *, void *),
645 #if MG_ENABLE_DIRLIST
648 if ((dirp = (opendir(dir))) == NULL) return;
649 while ((dp = readdir(dirp)) != NULL) {
650 if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, "..")) continue;
651 fn(dp->d_name, userdata);
655 (void) dir, (void) fn, (void) userdata;
659 static struct mg_fd *p_open(const char *path, int flags) {
660 const char *mode = flags == (MG_FS_READ | MG_FS_WRITE) ? "r+b"
661 : flags & MG_FS_READ ? "rb"
662 : flags & MG_FS_WRITE ? "wb"
665 struct mg_fd *fd = NULL;
667 wchar_t b1[PATH_MAX], b2[10];
668 MultiByteToWideChar(CP_UTF8, 0, path, -1, b1, sizeof(b1) / sizeof(b1[0]));
669 MultiByteToWideChar(CP_UTF8, 0, mode, -1, b2, sizeof(b2) / sizeof(b2[0]));
670 fp = (void *) _wfopen(b1, b2);
672 fp = (void *) fopen(path, mode);
674 if (fp == NULL) return NULL;
675 fd = (struct mg_fd *) calloc(1, sizeof(*fd));
677 fd->fs = &mg_fs_posix;
681 static void p_close(struct mg_fd *fd) {
682 if (fd != NULL) fclose((FILE *) fd->fd), free(fd);
685 static size_t p_read(void *fp, void *buf, size_t len) {
686 return fread(buf, 1, len, (FILE *) fp);
689 static size_t p_write(void *fp, const void *buf, size_t len) {
690 return fwrite(buf, 1, len, (FILE *) fp);
693 static size_t p_seek(void *fp, size_t offset) {
694 #if (defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS == 64) || \
695 (defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 200112L) || \
696 (defined(_XOPEN_SOURCE) && _XOPEN_SOURCE >= 600)
697 fseeko((FILE *) fp, (off_t) offset, SEEK_SET);
699 fseek((FILE *) fp, (long) offset, SEEK_SET);
701 return (size_t) ftell((FILE *) fp);
704 static char *p_realpath(const char *path, char *resolved_path) {
705 (void) path, (void) resolved_path;
709 static int p_stat(const char *path, size_t *size, time_t *mtime) {
710 (void) path, (void) size, (void) mtime;
714 static void p_list(const char *path, void (*fn)(const char *, void *),
716 (void) path, (void) fn, (void) userdata;
719 static struct mg_fd *p_open(const char *path, int flags) {
720 (void) path, (void) flags;
724 static void p_close(struct mg_fd *fd) {
728 static size_t p_read(void *fd, void *buf, size_t len) {
729 (void) fd, (void) buf, (void) len;
733 static size_t p_write(void *fd, const void *buf, size_t len) {
734 (void) fd, (void) buf, (void) len;
738 static size_t p_seek(void *fd, size_t offset) {
739 (void) fd, (void) offset;
744 struct mg_fs mg_fs_posix = {p_stat, p_list, p_open, p_close,
745 p_read, p_write, p_seek};
747 #ifdef MG_ENABLE_LINES
760 // Multipart POST example:
762 // Content-Disposition: form-data; name="val"
766 // Content-Disposition: form-data; name="foo"; filename="a.txt"
767 // Content-Type: text/plain
772 size_t mg_http_next_multipart(struct mg_str body, size_t ofs,
773 struct mg_http_part *part) {
774 struct mg_str cd = mg_str_n("Content-Disposition", 19);
775 const char *s = body.ptr;
776 size_t b = ofs, h1, h2, b1, b2, max = body.len;
779 if (part != NULL) part->name = part->filename = part->body = mg_str_n(0, 0);
782 while (b + 2 < max && s[b] != '\r' && s[b + 1] != '\n') b++;
783 if (b <= ofs || b + 2 >= max) return 0;
784 // LOG(LL_INFO, ("B: %zu %zu [%.*s]", ofs, b - ofs, (int) (b - ofs), s));
789 while (h2 + 2 < max && s[h2] != '\r' && s[h2 + 1] != '\n') h2++;
791 if (h2 + 2 >= max) return 0;
792 // LOG(LL_INFO, ("Header: [%.*s]", (int) (h2 - h1), &s[h1]));
793 if (part != NULL && h1 + cd.len + 2 < h2 && s[h1 + cd.len] == ':' &&
794 mg_ncasecmp(&s[h1], cd.ptr, cd.len) == 0) {
795 struct mg_str v = mg_str_n(&s[h1 + cd.len + 2], h2 - (h1 + cd.len + 2));
796 part->name = mg_http_get_header_var(v, mg_str_n("name", 4));
797 part->filename = mg_http_get_header_var(v, mg_str_n("filename", 8));
802 while (b2 + 2 + (b - ofs) + 2 < max && !(s[b2] == '\r' && s[b2 + 1] == '\n' &&
803 memcmp(&s[b2 + 2], s, b - ofs) == 0))
806 if (b2 + 2 >= max) return 0;
807 if (part != NULL) part->body = mg_str_n(&s[b1], b2 - b1);
808 // LOG(LL_INFO, ("Body: [%.*s]", (int) (b2 - b1), &s[b1]));
812 void mg_http_bauth(struct mg_connection *c, const char *user,
814 struct mg_str u = mg_str(user), p = mg_str(pass);
815 size_t need = c->send.len + 36 + (u.len + p.len) * 2;
816 if (c->send.size < need) mg_iobuf_resize(&c->send, need);
817 if (c->send.size >= need) {
819 char *buf = (char *) &c->send.buf[c->send.len + 21];
820 memcpy(&buf[-21], "Authorization: Basic ", 21); // DON'T use mg_send!
821 for (i = 0; i < (int) u.len; i++) {
822 n = mg_base64_update(((unsigned char *) u.ptr)[i], buf, n);
825 n = mg_base64_update(':', buf, n);
826 for (i = 0; i < (int) p.len; i++) {
827 n = mg_base64_update(((unsigned char *) p.ptr)[i], buf, n);
830 n = mg_base64_final(buf, n);
831 c->send.len += 21 + (size_t) n + 2;
832 memcpy(&c->send.buf[c->send.len - 2], "\r\n", 2);
834 LOG(LL_ERROR, ("%lu %s cannot resize iobuf %d->%d ", c->id, c->label,
835 (int) c->send.size, (int) need));
839 int mg_http_get_var(const struct mg_str *buf, const char *name, char *dst,
841 const char *p, *e, *s;
845 if (dst == NULL || dst_len == 0) {
846 len = -2; // Bad destination
847 } else if (buf->ptr == NULL || name == NULL || buf->len == 0) {
848 len = -1; // Bad source
851 name_len = strlen(name);
852 e = buf->ptr + buf->len;
853 len = -4; // Name does not exist
855 for (p = buf->ptr; p + name_len < e; p++) {
856 if ((p == buf->ptr || p[-1] == '&') && p[name_len] == '=' &&
857 !mg_ncasecmp(name, p, name_len)) {
859 s = (const char *) memchr(p, '&', (size_t) (e - p));
860 if (s == NULL) s = e;
861 len = mg_url_decode(p, (size_t) (s - p), dst, dst_len, 1);
862 if (len < 0) len = -3; // Failed to decode
870 int mg_url_decode(const char *src, size_t src_len, char *dst, size_t dst_len,
871 int is_form_url_encoded) {
873 for (i = j = 0; i < src_len && j + 1 < dst_len; i++, j++) {
875 // Use `i + 2 < src_len`, not `i < src_len - 2`, note small src_len
876 if (i + 2 < src_len && isxdigit(*(const unsigned char *) (src + i + 1)) &&
877 isxdigit(*(const unsigned char *) (src + i + 2))) {
878 mg_unhex(src + i + 1, 2, (uint8_t *) &dst[j]);
883 } else if (is_form_url_encoded && src[i] == '+') {
889 if (j < dst_len) dst[j] = '\0'; // Null-terminate the destination
890 return i >= src_len && j < dst_len ? (int) j : -1;
893 int mg_http_get_request_len(const unsigned char *buf, size_t buf_len) {
895 for (i = 0; i < buf_len; i++) {
896 if (!isprint(buf[i]) && buf[i] != '\r' && buf[i] != '\n' && buf[i] < 128)
898 if ((i > 0 && buf[i] == '\n' && buf[i - 1] == '\n') ||
899 (i > 3 && buf[i] == '\n' && buf[i - 1] == '\r' && buf[i - 2] == '\n'))
905 static const char *skip(const char *s, const char *e, const char *d,
908 while (s < e && *s != '\n' && strchr(d, *s) == NULL) s++;
909 v->len = (size_t) (s - v->ptr);
910 while (s < e && strchr(d, *s) != NULL) s++;
914 struct mg_str *mg_http_get_header(struct mg_http_message *h, const char *name) {
915 size_t i, n = strlen(name), max = sizeof(h->headers) / sizeof(h->headers[0]);
916 for (i = 0; i < max && h->headers[i].name.len > 0; i++) {
917 struct mg_str *k = &h->headers[i].name, *v = &h->headers[i].value;
918 if (n == k->len && mg_ncasecmp(k->ptr, name, n) == 0) return v;
923 static void mg_http_parse_headers(const char *s, const char *end,
924 struct mg_http_header *h, int max_headers) {
926 for (i = 0; i < max_headers; i++) {
927 struct mg_str k, v, tmp;
928 const char *he = skip(s, end, "\n", &tmp);
929 s = skip(s, he, ": \r\n", &k);
930 s = skip(s, he, "\r\n", &v);
931 if (k.len == tmp.len) continue;
932 while (v.len > 0 && v.ptr[v.len - 1] == ' ') v.len--; // Trim spaces
933 if (k.len == 0) break;
934 // LOG(LL_INFO, ("--HH [%.*s] [%.*s] [%.*s]", (int) tmp.len - 1, tmp.ptr,
935 //(int) k.len, k.ptr, (int) v.len, v.ptr));
941 int mg_http_parse(const char *s, size_t len, struct mg_http_message *hm) {
942 int is_response, req_len = mg_http_get_request_len((unsigned char *) s, len);
943 const char *end = s + req_len, *qs;
946 memset(hm, 0, sizeof(*hm));
947 if (req_len <= 0) return req_len;
949 hm->message.ptr = hm->head.ptr = s;
951 hm->head.len = (size_t) req_len;
953 hm->message.len = hm->body.len = (size_t) ~0; // Set body length to infinite
955 // Parse request line
956 s = skip(s, end, " ", &hm->method);
957 s = skip(s, end, " ", &hm->uri);
958 s = skip(s, end, "\r\n", &hm->proto);
960 // Sanity check. Allow protocol/reason to be empty
961 if (hm->method.len == 0 || hm->uri.len == 0) return -1;
963 // If URI contains '?' character, setup query string
964 if ((qs = (const char *) memchr(hm->uri.ptr, '?', hm->uri.len)) != NULL) {
965 hm->query.ptr = qs + 1;
966 hm->query.len = (size_t) (&hm->uri.ptr[hm->uri.len] - (qs + 1));
967 hm->uri.len = (size_t) (qs - hm->uri.ptr);
970 mg_http_parse_headers(s, end, hm->headers,
971 sizeof(hm->headers) / sizeof(hm->headers[0]));
972 if ((cl = mg_http_get_header(hm, "Content-Length")) != NULL) {
973 hm->body.len = (size_t) mg_to64(*cl);
974 hm->message.len = (size_t) req_len + hm->body.len;
977 // mg_http_parse() is used to parse both HTTP requests and HTTP
978 // responses. If HTTP response does not have Content-Length set, then
979 // body is read until socket is closed, i.e. body.len is infinite (~0).
981 // For HTTP requests though, according to
982 // http://tools.ietf.org/html/rfc7231#section-8.1.3,
983 // only POST and PUT methods have defined body semantics.
984 // Therefore, if Content-Length is not specified and methods are
985 // not one of PUT or POST, set body length to 0.
987 // So, if it is HTTP request, and Content-Length is not set,
988 // and method is not (PUT or POST) then reset body length to zero.
989 is_response = mg_ncasecmp(hm->method.ptr, "HTTP/", 5) == 0;
990 if (hm->body.len == (size_t) ~0 && !is_response &&
991 mg_vcasecmp(&hm->method, "PUT") != 0 &&
992 mg_vcasecmp(&hm->method, "POST") != 0) {
994 hm->message.len = (size_t) req_len;
997 // The 204 (No content) responses also have 0 body length
998 if (hm->body.len == (size_t) ~0 && is_response &&
999 mg_vcasecmp(&hm->uri, "204") == 0) {
1001 hm->message.len = (size_t) req_len;
1007 static void mg_http_vprintf_chunk(struct mg_connection *c, const char *fmt,
1009 char mem[256], *buf = mem;
1010 int len = mg_vasprintf(&buf, sizeof(mem), fmt, ap);
1011 mg_printf(c, "%X\r\n", len);
1012 mg_send(c, buf, len > 0 ? (size_t) len : 0);
1013 mg_send(c, "\r\n", 2);
1014 if (buf != mem) free(buf);
1017 void mg_http_printf_chunk(struct mg_connection *c, const char *fmt, ...) {
1020 mg_http_vprintf_chunk(c, fmt, ap);
1024 void mg_http_write_chunk(struct mg_connection *c, const char *buf, size_t len) {
1025 mg_printf(c, "%lX\r\n", (unsigned long) len);
1026 mg_send(c, buf, len);
1027 mg_send(c, "\r\n", 2);
1031 static const char *mg_http_status_code_str(int status_code) {
1032 switch (status_code) {
1033 case 100: return "Continue";
1034 case 101: return "Switching Protocols";
1035 case 102: return "Processing";
1036 case 200: return "OK";
1037 case 201: return "Created";
1038 case 202: return "Accepted";
1039 case 203: return "Non-authoritative Information";
1040 case 204: return "No Content";
1041 case 205: return "Reset Content";
1042 case 206: return "Partial Content";
1043 case 207: return "Multi-Status";
1044 case 208: return "Already Reported";
1045 case 226: return "IM Used";
1046 case 300: return "Multiple Choices";
1047 case 301: return "Moved Permanently";
1048 case 302: return "Found";
1049 case 303: return "See Other";
1050 case 304: return "Not Modified";
1051 case 305: return "Use Proxy";
1052 case 307: return "Temporary Redirect";
1053 case 308: return "Permanent Redirect";
1054 case 400: return "Bad Request";
1055 case 401: return "Unauthorized";
1056 case 402: return "Payment Required";
1057 case 403: return "Forbidden";
1058 case 404: return "Not Found";
1059 case 405: return "Method Not Allowed";
1060 case 406: return "Not Acceptable";
1061 case 407: return "Proxy Authentication Required";
1062 case 408: return "Request Timeout";
1063 case 409: return "Conflict";
1064 case 410: return "Gone";
1065 case 411: return "Length Required";
1066 case 412: return "Precondition Failed";
1067 case 413: return "Payload Too Large";
1068 case 414: return "Request-URI Too Long";
1069 case 415: return "Unsupported Media Type";
1070 case 416: return "Requested Range Not Satisfiable";
1071 case 417: return "Expectation Failed";
1072 case 418: return "I'm a teapot";
1073 case 421: return "Misdirected Request";
1074 case 422: return "Unprocessable Entity";
1075 case 423: return "Locked";
1076 case 424: return "Failed Dependency";
1077 case 426: return "Upgrade Required";
1078 case 428: return "Precondition Required";
1079 case 429: return "Too Many Requests";
1080 case 431: return "Request Header Fields Too Large";
1081 case 444: return "Connection Closed Without Response";
1082 case 451: return "Unavailable For Legal Reasons";
1083 case 499: return "Client Closed Request";
1084 case 500: return "Internal Server Error";
1085 case 501: return "Not Implemented";
1086 case 502: return "Bad Gateway";
1087 case 503: return "Service Unavailable";
1088 case 504: return "Gateway Timeout";
1089 case 505: return "HTTP Version Not Supported";
1090 case 506: return "Variant Also Negotiates";
1091 case 507: return "Insufficient Storage";
1092 case 508: return "Loop Detected";
1093 case 510: return "Not Extended";
1094 case 511: return "Network Authentication Required";
1095 case 599: return "Network Connect Timeout Error";
1096 default: return "OK";
1101 void mg_http_reply(struct mg_connection *c, int code, const char *headers,
1102 const char *fmt, ...) {
1103 char mem[256], *buf = mem;
1107 len = mg_vasprintf(&buf, sizeof(mem), fmt, ap);
1109 mg_printf(c, "HTTP/1.1 %d %s\r\n%sContent-Length: %d\r\n\r\n", code,
1110 mg_http_status_code_str(code), headers == NULL ? "" : headers, len);
1111 mg_send(c, buf, len > 0 ? (size_t) len : 0);
1112 if (buf != mem) free(buf);
1115 static void http_cb(struct mg_connection *, int, void *, void *);
1116 static void restore_http_cb(struct mg_connection *c) {
1117 struct mg_fd *fd = (struct mg_fd *) c->pfn_data;
1118 if (fd != NULL) fd->fs->close(fd);
1123 char *mg_http_etag(char *buf, size_t len, size_t size, time_t mtime);
1124 char *mg_http_etag(char *buf, size_t len, size_t size, time_t mtime) {
1125 snprintf(buf, len, "\"%lx." MG_INT64_FMT "\"", (unsigned long) mtime,
1130 int mg_http_upload(struct mg_connection *c, struct mg_http_message *hm,
1132 char offset[40] = "", name[200] = "", path[256];
1133 mg_http_get_var(&hm->query, "offset", offset, sizeof(offset));
1134 mg_http_get_var(&hm->query, "name", name, sizeof(name));
1135 if (name[0] == '\0') {
1136 mg_http_reply(c, 400, "", "%s", "name required");
1140 size_t oft = strtoul(offset, NULL, 0);
1141 snprintf(path, sizeof(path), "%s%c%s", dir, MG_DIRSEP, name);
1143 ("%p %d bytes @ %d [%s]", c->fd, (int) hm->body.len, (int) oft, name));
1144 if ((fp = fopen(path, oft == 0 ? "wb" : "ab")) == NULL) {
1145 mg_http_reply(c, 400, "", "fopen(%s): %d", name, errno);
1148 fwrite(hm->body.ptr, 1, hm->body.len, fp);
1150 mg_http_reply(c, 200, "", "");
1151 return (int) hm->body.len;
1156 static void static_cb(struct mg_connection *c, int ev, void *ev_data,
1158 if (ev == MG_EV_WRITE || ev == MG_EV_POLL) {
1159 struct mg_fd *fd = (struct mg_fd *) fn_data;
1160 // Read to send IO buffer directly, avoid extra on-stack buffer
1161 size_t n, max = 2 * MG_IO_SIZE;
1162 if (c->send.size < max) mg_iobuf_resize(&c->send, max);
1163 if (c->send.len >= c->send.size) return; // Rate limit
1164 n = fd->fs->read(fd->fd, c->send.buf + c->send.len,
1165 c->send.size - c->send.len);
1166 if (n > 0) c->send.len += n;
1167 if (c->send.len < c->send.size) restore_http_cb(c);
1168 } else if (ev == MG_EV_CLOSE) {
1174 static struct mg_str guess_content_type(struct mg_str path, const char *extra) {
1176 struct mimeentry { struct mg_str extension, value; };
1177 #define MIME_ENTRY(a, b) {{a, sizeof(a) - 1 }, { b, sizeof(b) - 1 }}
1179 const struct mimeentry tab[] = {
1180 MIME_ENTRY("html", "text/html; charset=utf-8"),
1181 MIME_ENTRY("htm", "text/html; charset=utf-8"),
1182 MIME_ENTRY("css", "text/css; charset=utf-8"),
1183 MIME_ENTRY("js", "text/javascript; charset=utf-8"),
1184 MIME_ENTRY("gif", "image/gif"),
1185 MIME_ENTRY("png", "image/png"),
1186 MIME_ENTRY("jpg", "image/jpeg"),
1187 MIME_ENTRY("jpeg", "image/jpeg"),
1188 MIME_ENTRY("woff", "font/woff"),
1189 MIME_ENTRY("ttf", "font/ttf"),
1190 MIME_ENTRY("svg", "image/svg+xml"),
1191 MIME_ENTRY("txt", "text/plain; charset=utf-8"),
1192 MIME_ENTRY("avi", "video/x-msvideo"),
1193 MIME_ENTRY("csv", "text/csv"),
1194 MIME_ENTRY("doc", "application/msword"),
1195 MIME_ENTRY("exe", "application/octet-stream"),
1196 MIME_ENTRY("gz", "application/gzip"),
1197 MIME_ENTRY("ico", "image/x-icon"),
1198 MIME_ENTRY("json", "application/json"),
1199 MIME_ENTRY("mov", "video/quicktime"),
1200 MIME_ENTRY("mp3", "audio/mpeg"),
1201 MIME_ENTRY("mp4", "video/mp4"),
1202 MIME_ENTRY("mpeg", "video/mpeg"),
1203 MIME_ENTRY("pdf", "application/pdf"),
1204 MIME_ENTRY("shtml", "text/html; charset=utf-8"),
1205 MIME_ENTRY("tgz", "application/tar-gz"),
1206 MIME_ENTRY("wav", "audio/wav"),
1207 MIME_ENTRY("webp", "image/webp"),
1208 MIME_ENTRY("zip", "application/zip"),
1209 MIME_ENTRY("3gp", "video/3gpp"),
1213 struct mg_str k, v, s = mg_str(extra);
1215 // Shrink path to its extension only
1216 while (i < path.len && path.ptr[path.len - i - 1] != '.') i++;
1217 path.ptr += path.len - i;
1220 // Process user-provided mime type overrides, if any
1221 while (mg_commalist(&s, &k, &v)) {
1222 if (mg_strcmp(path, k) == 0) return v;
1225 // Process built-in mime types
1226 for (i = 0; tab[i].extension.ptr != NULL; i++) {
1227 if (mg_strcmp(path, tab[i].extension) == 0) return tab[i].value;
1230 return mg_str("text/plain; charset=utf-8");
1233 static int getrange(struct mg_str *s, int64_t *a, int64_t *b) {
1234 size_t i, numparsed = 0;
1235 LOG(LL_INFO, ("%.*s", (int) s->len, s->ptr));
1236 for (i = 0; i + 6 < s->len; i++) {
1237 if (memcmp(&s->ptr[i], "bytes=", 6) == 0) {
1238 struct mg_str p = mg_str_n(s->ptr + i + 6, s->len - i - 6);
1239 if (p.len > 0 && p.ptr[0] >= '0' && p.ptr[0] <= '9') numparsed++;
1241 // LOG(LL_INFO, ("PPP [%.*s] %d", (int) p.len, p.ptr, numparsed));
1242 while (p.len && p.ptr[0] >= '0' && p.ptr[0] <= '9') p.ptr++, p.len--;
1243 if (p.len && p.ptr[0] == '-') p.ptr++, p.len--;
1245 if (p.len > 0 && p.ptr[0] >= '0' && p.ptr[0] <= '9') numparsed++;
1246 // LOG(LL_INFO, ("PPP [%.*s] %d", (int) p.len, p.ptr, numparsed));
1250 return (int) numparsed;
1253 void mg_http_serve_file(struct mg_connection *c, struct mg_http_message *hm,
1254 const char *path, struct mg_http_serve_opts *opts) {
1256 struct mg_fs *fs = opts->fs == NULL ? &mg_fs_posix : opts->fs;
1257 struct mg_fd *fd = fs->open(path, MG_FS_READ);
1260 struct mg_str *inm = NULL;
1262 if (fd == NULL || fs->stat(path, &size, &mtime) == 0) {
1263 LOG(LL_DEBUG, ("404 [%s] %p", path, (void *) fd));
1264 mg_http_reply(c, 404, "", "%s", "Not found\n");
1266 // NOTE: mg_http_etag() call should go first!
1267 } else if (mg_http_etag(etag, sizeof(etag), size, mtime) != NULL &&
1268 (inm = mg_http_get_header(hm, "If-None-Match")) != NULL &&
1269 mg_vcasecmp(inm, etag) == 0) {
1271 mg_printf(c, "HTTP/1.1 304 Not Modified\r\nContent-Length: 0\r\n\r\n");
1273 int n, status = 200;
1274 char range[100] = "";
1275 int64_t r1 = 0, r2 = 0, cl = (int64_t) size;
1276 struct mg_str mime = guess_content_type(mg_str(path), opts->mime_types);
1278 // Handle Range header
1279 struct mg_str *rh = mg_http_get_header(hm, "Range");
1280 if (rh != NULL && (n = getrange(rh, &r1, &r2)) > 0 && r1 >= 0 && r2 >= 0) {
1281 // If range is specified like "400-", set second limit to content len
1282 if (n == 1) r2 = cl - 1;
1283 if (r1 > r2 || r2 >= cl) {
1286 snprintf(range, sizeof(range),
1287 "Content-Range: bytes */" MG_INT64_FMT "\r\n", (int64_t) size);
1291 snprintf(range, sizeof(range),
1292 "Content-Range: bytes " MG_INT64_FMT "-" MG_INT64_FMT
1293 "/" MG_INT64_FMT "\r\n",
1294 r1, r1 + cl - 1, (int64_t) size);
1295 fs->seek(fd->fd, (size_t) r1);
1300 "HTTP/1.1 %d %s\r\nContent-Type: %.*s\r\n"
1301 "Etag: %s\r\nContent-Length: " MG_INT64_FMT "\r\n%s%s\r\n",
1302 status, mg_http_status_code_str(status), (int) mime.len, mime.ptr,
1303 etag, cl, range, opts->extra_headers ? opts->extra_headers : "");
1304 if (mg_vcasecmp(&hm->method, "HEAD") == 0) {
1314 struct printdirentrydata {
1315 struct mg_connection *c;
1316 struct mg_http_message *hm;
1317 struct mg_http_serve_opts *opts;
1321 static void printdirentry(const char *name, void *userdata) {
1322 struct printdirentrydata *d = (struct printdirentrydata *) userdata;
1323 struct mg_fs *fs = d->opts->fs == NULL ? &mg_fs_posix : d->opts->fs;
1326 char path[MG_PATH_MAX], sz[64], mod[64];
1329 // LOG(LL_DEBUG, ("[%s] [%s]", d->dir, name));
1330 if (snprintf(path, sizeof(path), "%s%c%s", d->dir, '/', name) < 0) {
1331 LOG(LL_ERROR, ("%s truncated", name));
1332 } else if ((flags = fs->stat(path, &size, &t)) == 0) {
1333 LOG(LL_ERROR, ("%lu stat(%s): %d", d->c->id, path, errno));
1335 const char *slash = flags & MG_FS_DIR ? "/" : "";
1337 if (flags & MG_FS_DIR) {
1338 snprintf(sz, sizeof(sz), "%s", "[DIR]");
1339 } else if (size < 1024) {
1340 snprintf(sz, sizeof(sz), "%d", (int) size);
1341 } else if (size < 0x100000) {
1342 snprintf(sz, sizeof(sz), "%.1fk", (double) size / 1024.0);
1343 } else if (size < 0x40000000) {
1344 snprintf(sz, sizeof(sz), "%.1fM", (double) size / 1048576);
1346 snprintf(sz, sizeof(sz), "%.1fG", (double) size / 1073741824);
1348 strftime(mod, sizeof(mod), "%d-%b-%Y %H:%M", localtime_r(&t, &tm));
1349 n = (int) mg_url_encode(name, strlen(name), path, sizeof(path));
1351 " <tr><td><a href=\"%.*s%s\">%s%s</a></td>"
1352 "<td name=%lu>%s</td><td name=" MG_INT64_FMT ">%s</td></tr>\n",
1353 n, path, slash, name, slash, (unsigned long) t, mod,
1354 flags & MG_FS_DIR ? (int64_t) -1 : (int64_t) size, sz);
1358 static void listdir(struct mg_connection *c, struct mg_http_message *hm,
1359 struct mg_http_serve_opts *opts, char *dir) {
1360 static const char *sort_js_code =
1361 "<script>function srt(tb, sc, so, d) {"
1362 "var tr = Array.prototype.slice.call(tb.rows, 0),"
1363 "tr = tr.sort(function (a, b) { var c1 = a.cells[sc], c2 = b.cells[sc],"
1364 "n1 = c1.getAttribute('name'), n2 = c2.getAttribute('name'), "
1365 "t1 = a.cells[2].getAttribute('name'), "
1366 "t2 = b.cells[2].getAttribute('name'); "
1367 "return so * (t1 < 0 && t2 >= 0 ? -1 : t2 < 0 && t1 >= 0 ? 1 : "
1368 "n1 ? parseInt(n2) - parseInt(n1) : "
1369 "c1.textContent.trim().localeCompare(c2.textContent.trim())); });";
1370 static const char *sort_js_code2 =
1371 "for (var i = 0; i < tr.length; i++) tb.appendChild(tr[i]); "
1372 "if (!d) window.location.hash = ('sc=' + sc + '&so=' + so); "
1374 "window.onload = function() {"
1375 "var tb = document.getElementById('tb');"
1376 "var m = /sc=([012]).so=(1|-1)/.exec(window.location.hash) || [0, 2, 1];"
1377 "var sc = m[1], so = m[2]; document.onclick = function(ev) { "
1378 "var c = ev.target.rel; if (c) {if (c == sc) so *= -1; srt(tb, c, so); "
1379 "sc = c; ev.preventDefault();}};"
1380 "srt(tb, sc, so, true);"
1383 struct mg_fs *fs = opts->fs == NULL ? &mg_fs_posix : opts->fs;
1384 struct printdirentrydata d = {c, hm, opts, dir};
1385 char tmp[10], buf[MG_PATH_MAX];
1387 int len = mg_url_decode(hm->uri.ptr, hm->uri.len, buf, sizeof(buf), 0);
1388 struct mg_str uri = len > 0 ? mg_str_n(buf, (size_t) len) : hm->uri;
1391 "HTTP/1.1 200 OK\r\n"
1392 "Content-Type: text/html; charset=utf-8\r\n"
1394 "Content-Length: \r\n\r\n",
1395 opts->extra_headers == NULL ? "" : opts->extra_headers);
1396 off = c->send.len; // Start of body
1398 "<!DOCTYPE html><html><head><title>Index of %.*s</title>%s%s"
1399 "<style>th,td {text-align: left; padding-right: 1em; "
1400 "font-family: monospace; }</style></head>"
1401 "<body><h1>Index of %.*s</h1><table cellpadding=\"0\"><thead>"
1402 "<tr><th><a href=\"#\" rel=\"0\">Name</a></th><th>"
1403 "<a href=\"#\" rel=\"1\">Modified</a></th>"
1404 "<th><a href=\"#\" rel=\"2\">Size</a></th></tr>"
1405 "<tr><td colspan=\"3\"><hr></td></tr>"
1407 "<tbody id=\"tb\">\n",
1408 (int) uri.len, uri.ptr, sort_js_code, sort_js_code2, (int) uri.len,
1411 fs->list(dir, printdirentry, &d);
1413 "</tbody><tfoot><tr><td colspan=\"3\"><hr></td></tr></tfoot>"
1414 "</table><address>Mongoose v.%s</address></body></html>\n",
1416 n = (size_t) snprintf(tmp, sizeof(tmp), "%lu",
1417 (unsigned long) (c->send.len - off));
1418 if (n > sizeof(tmp)) n = 0;
1419 memcpy(c->send.buf + off - 10, tmp, n); // Set content length
1422 static void remove_double_dots(char *s) {
1424 while (*s != '\0') {
1426 if (s[-1] == '/' || s[-1] == '\\') {
1427 while (s[0] != '\0') {
1428 if (s[0] == '/' || s[0] == '\\') {
1430 } else if (s[0] == '.' && s[1] == '.' &&
1431 (s[2] == '/' || s[2] == '\\')) {
1442 // Resolve requested file into `path` and return its fs->stat() result
1443 static int uri_to_path2(struct mg_connection *c, struct mg_http_message *hm,
1444 struct mg_fs *fs, struct mg_str url, struct mg_str dir,
1445 char *path, size_t path_size) {
1447 // Append URI to the root_dir, and sanitize it
1448 size_t n = (size_t) snprintf(path, path_size, "%.*s", (int) dir.len, dir.ptr);
1449 if (n > path_size) n = path_size;
1450 path[path_size - 1] = '\0';
1451 if ((fs->stat(path, NULL, NULL) & MG_FS_DIR) == 0) {
1452 mg_http_reply(c, 400, "", "Invalid web root [%.*s]\n", (int) dir.len,
1455 if (n + 2 < path_size) path[n++] = '/', path[n] = '\0';
1456 mg_url_decode(hm->uri.ptr + url.len, hm->uri.len - url.len, path + n,
1458 path[path_size - 1] = '\0'; // Double-check
1459 remove_double_dots(path);
1461 LOG(LL_VERBOSE_DEBUG,
1462 ("%lu %.*s -> %s", c->id, (int) hm->uri.len, hm->uri.ptr, path));
1463 while (n > 0 && path[n - 1] == '/') path[--n] = 0; // Trim trailing slashes
1464 flags = fs->stat(path, NULL, NULL); // Does it exist?
1466 mg_http_reply(c, 404, "", "Not found\n"); // Does not exist, doh
1467 } else if ((flags & MG_FS_DIR) && hm->uri.len > 0 &&
1468 hm->uri.ptr[hm->uri.len - 1] != '/') {
1470 "HTTP/1.1 301 Moved\r\n"
1471 "Location: %.*s/\r\n"
1472 "Content-Length: 0\r\n"
1474 (int) hm->uri.len, hm->uri.ptr);
1476 } else if (flags & MG_FS_DIR) {
1477 if (((snprintf(path + n, path_size - n, "/" MG_HTTP_INDEX) > 0 &&
1478 (tmp = fs->stat(path, NULL, NULL)) != 0) ||
1479 (snprintf(path + n, path_size - n, "/index.shtml") > 0 &&
1480 (tmp = fs->stat(path, NULL, NULL)) != 0))) {
1483 path[n] = '\0'; // Remove appended index file name
1490 static int uri_to_path(struct mg_connection *c, struct mg_http_message *hm,
1491 struct mg_http_serve_opts *opts, char *path,
1493 struct mg_fs *fs = opts->fs == NULL ? &mg_fs_posix : opts->fs;
1494 struct mg_str k, v, s = mg_str(opts->root_dir), u = {0, 0}, p = {0, 0};
1495 while (mg_commalist(&s, &k, &v)) {
1496 if (v.len == 0) v = k, k = mg_str("/");
1497 if (hm->uri.len < k.len) continue;
1498 if (mg_strcmp(k, mg_str_n(hm->uri.ptr, k.len)) != 0) continue;
1501 return uri_to_path2(c, hm, fs, u, p, path, path_size);
1504 void mg_http_serve_dir(struct mg_connection *c, struct mg_http_message *hm,
1505 struct mg_http_serve_opts *opts) {
1506 char path[MG_PATH_MAX] = "";
1507 const char *sp = opts->ssi_pattern;
1508 int flags = uri_to_path(c, hm, opts, path, sizeof(path));
1509 if (flags == 0) return;
1510 LOG(LL_VERBOSE_DEBUG,
1511 ("%.*s %s %d", (int) hm->uri.len, hm->uri.ptr, path, flags));
1512 if (flags & MG_FS_DIR) {
1513 listdir(c, hm, opts, path);
1514 } else if (sp != NULL && mg_globmatch(sp, strlen(sp), path, strlen(path))) {
1515 mg_http_serve_ssi(c, opts->root_dir, path);
1517 mg_http_serve_file(c, hm, path, opts);
1521 static bool mg_is_url_safe(int c) {
1522 return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'z') ||
1523 (c >= 'A' && c <= 'Z') || c == '.' || c == '_' || c == '-' || c == '~';
1526 size_t mg_url_encode(const char *s, size_t sl, char *buf, size_t len) {
1528 for (i = 0; i < sl; i++) {
1529 int c = *(unsigned char *) &s[i];
1530 if (n + 4 >= len) return 0;
1531 if (mg_is_url_safe(c)) {
1535 mg_hex(&s[i], 1, &buf[n]);
1542 void mg_http_creds(struct mg_http_message *hm, char *user, size_t userlen,
1543 char *pass, size_t passlen) {
1544 struct mg_str *v = mg_http_get_header(hm, "Authorization");
1545 user[0] = pass[0] = '\0';
1546 if (v != NULL && v->len > 6 && memcmp(v->ptr, "Basic ", 6) == 0) {
1548 int n = mg_base64_decode(v->ptr + 6, (int) v->len - 6, buf);
1549 const char *p = (const char *) memchr(buf, ':', n > 0 ? (size_t) n : 0);
1551 snprintf(user, userlen, "%.*s", (int) (p - buf), buf);
1552 snprintf(pass, passlen, "%.*s", n - (int) (p - buf) - 1, p + 1);
1554 } else if (v != NULL && v->len > 7 && memcmp(v->ptr, "Bearer ", 7) == 0) {
1555 snprintf(pass, passlen, "%.*s", (int) v->len - 7, v->ptr + 7);
1556 } else if ((v = mg_http_get_header(hm, "Cookie")) != NULL) {
1557 struct mg_str t = mg_http_get_header_var(*v, mg_str_n("access_token", 12));
1558 if (t.len > 0) snprintf(pass, passlen, "%.*s", (int) t.len, t.ptr);
1560 mg_http_get_var(&hm->query, "access_token", pass, passlen);
1564 static struct mg_str stripquotes(struct mg_str s) {
1565 return s.len > 1 && s.ptr[0] == '"' && s.ptr[s.len - 1] == '"'
1566 ? mg_str_n(s.ptr + 1, s.len - 2)
1570 struct mg_str mg_http_get_header_var(struct mg_str s, struct mg_str v) {
1572 for (i = 0; v.len > 0 && i + v.len + 2 < s.len; i++) {
1573 if (s.ptr[i + v.len] == '=' && memcmp(&s.ptr[i], v.ptr, v.len) == 0) {
1574 const char *p = &s.ptr[i + v.len + 1], *b = p, *x = &s.ptr[s.len];
1575 int q = p < x && *p == '"' ? 1 : 0;
1577 (q ? p == b || *p != '"' : *p != ';' && *p != ' ' && *p != ','))
1579 // LOG(LL_INFO, ("[%.*s] [%.*s] [%.*s]", (int) s.len, s.ptr, (int) v.len,
1580 // v.ptr, (int) (p - b), b));
1581 return stripquotes(mg_str_n(b, (size_t) (p - b + q)));
1584 return mg_str_n(NULL, 0);
1587 bool mg_http_match_uri(const struct mg_http_message *hm, const char *glob) {
1588 return mg_globmatch(glob, strlen(glob), hm->uri.ptr, hm->uri.len);
1591 static size_t get_chunk_length(const char *buf, size_t len, size_t *ll) {
1593 while (i < len && buf[i] != '\r' && i != '\n') i++;
1594 n = mg_unhexn((char *) buf, i);
1595 while (i < len && (buf[i] == '\r' || i == '\n')) i++;
1596 // LOG(LL_INFO, ("len %zu i %zu n %zu ", len, i, n));
1597 if (ll != NULL) *ll = i + 1;
1598 if (i < len && i + n + 2 < len) return i + n + 3;
1602 // Walk through all chunks in the chunked body. For each chunk, fire
1603 // an MG_EV_HTTP_CHUNK event.
1604 static void walkchunks(struct mg_connection *c, struct mg_http_message *hm,
1606 size_t off = 0, bl, ll;
1607 while (off + reqlen < c->recv.len) {
1608 char *buf = (char *) &c->recv.buf[reqlen];
1609 size_t memo = c->recv.len;
1610 size_t cl = get_chunk_length(&buf[off], memo - reqlen - off, &ll);
1611 // LOG(LL_INFO, ("len %zu off %zu cl %zu ll %zu", len, off, cl, ll));
1613 hm->chunk = mg_str_n(&buf[off + ll], cl < ll + 2 ? 0 : cl - ll - 2);
1614 mg_call(c, MG_EV_HTTP_CHUNK, hm);
1615 // Increase offset only if user has not deleted this chunk
1616 if (memo == c->recv.len) off += cl;
1618 // Zero chunk - last one. Prepare body - cut off chunk lengths
1620 while (off + reqlen < c->recv.len) {
1621 char *buf2 = (char *) &c->recv.buf[reqlen];
1622 size_t memo2 = c->recv.len;
1623 size_t cl2 = get_chunk_length(&buf2[off], memo2 - reqlen - off, &ll);
1624 size_t n = cl2 < ll + 2 ? 0 : cl2 - ll - 2;
1625 memmove(buf2 + bl, buf2 + off + ll, n);
1628 if (cl2 <= 5) break;
1630 // LOG(LL_INFO, ("BL->%d del %d off %d", (int) bl, (int) del, (int) off));
1631 c->recv.len -= off - bl;
1632 // Set message length to indicate we've received
1633 // everything, to fire MG_EV_HTTP_MSG
1634 hm->message.len = bl + reqlen;
1641 static bool mg_is_chunked(struct mg_http_message *hm) {
1642 struct mg_str needle = mg_str_n("chunked", 7);
1643 struct mg_str *te = mg_http_get_header(hm, "Transfer-Encoding");
1644 return te != NULL && mg_strstr(*te, needle) != NULL;
1647 void mg_http_delete_chunk(struct mg_connection *c, struct mg_http_message *hm) {
1648 struct mg_str ch = hm->chunk;
1649 if (mg_is_chunked(hm)) {
1650 ch.len += 4; // \r\n before and after the chunk
1652 while (ch.ptr > hm->body.ptr && *ch.ptr != '\n') ch.ptr--, ch.len++;
1655 const char *end = &ch.ptr[ch.len];
1656 size_t n = (size_t) (end - (char *) c->recv.buf);
1657 if (c->recv.len > n) {
1658 memmove((char *) ch.ptr, end, (size_t) (c->recv.len - n));
1660 // LOG(LL_INFO, ("DELETING CHUNK: %zu %zu %zu\n%.*s", c->recv.len, n,
1661 // ch.len, (int) ch.len, ch.ptr));
1663 c->recv.len -= ch.len;
1666 static void http_cb(struct mg_connection *c, int ev, void *evd, void *fnd) {
1667 if (ev == MG_EV_READ || ev == MG_EV_CLOSE) {
1668 struct mg_http_message hm;
1670 int n = mg_http_parse((char *) c->recv.buf, c->recv.len, &hm);
1671 bool is_chunked = n > 0 && mg_is_chunked(&hm);
1672 if (ev == MG_EV_CLOSE) {
1673 hm.message.len = c->recv.len;
1674 hm.body.len = hm.message.len - (size_t) (hm.body.ptr - hm.message.ptr);
1675 } else if (is_chunked && n > 0) {
1676 walkchunks(c, &hm, (size_t) n);
1679 //("---->%d %d\n%.*s", n, is_chunked, (int) c->recv.len, c->recv.buf));
1680 if (n < 0 && ev == MG_EV_READ) {
1681 mg_error(c, "HTTP parse:\n%.*s", (int) c->recv.len, c->recv.buf);
1683 } else if (n > 0 && (size_t) c->recv.len >= hm.message.len) {
1684 mg_call(c, MG_EV_HTTP_MSG, &hm);
1685 mg_iobuf_del(&c->recv, 0, hm.message.len);
1687 if (n > 0 && !is_chunked) {
1689 mg_str_n((char *) &c->recv.buf[n], c->recv.len - (size_t) n);
1690 mg_call(c, MG_EV_HTTP_CHUNK, &hm);
1700 struct mg_connection *mg_http_connect(struct mg_mgr *mgr, const char *url,
1701 mg_event_handler_t fn, void *fn_data) {
1702 struct mg_connection *c = mg_connect(mgr, url, fn, fn_data);
1703 if (c != NULL) c->pfn = http_cb;
1707 struct mg_connection *mg_http_listen(struct mg_mgr *mgr, const char *url,
1708 mg_event_handler_t fn, void *fn_data) {
1709 struct mg_connection *c = mg_listen(mgr, url, fn, fn_data);
1710 if (c != NULL) c->pfn = http_cb;
1714 #ifdef MG_ENABLE_LINES
1715 #line 1 "src/iobuf.c"
1722 // Not using memset for zeroing memory, cause it can be dropped by compiler
1723 // See https://github.com/cesanta/mongoose/pull/1265
1724 static void zeromem(volatile unsigned char *buf, size_t len) {
1726 while (len--) *buf++ = 0;
1730 int mg_iobuf_resize(struct mg_iobuf *io, size_t new_size) {
1732 if (new_size == 0) {
1733 zeromem(io->buf, io->size);
1736 io->len = io->size = 0;
1737 } else if (new_size != io->size) {
1738 // NOTE(lsm): do not use realloc here. Use calloc/free only, to ease the
1739 // porting to some obscure platforms like FreeRTOS
1740 void *p = calloc(1, new_size);
1742 size_t len = new_size < io->len ? new_size : io->len;
1743 if (len > 0) memcpy(p, io->buf, len);
1744 zeromem(io->buf, io->size);
1746 io->buf = (unsigned char *) p;
1747 io->size = new_size;
1751 ("%lu->%lu", (unsigned long) io->size, (unsigned long) new_size));
1757 int mg_iobuf_init(struct mg_iobuf *io, size_t size) {
1758 return mg_iobuf_resize(io, size);
1761 size_t mg_iobuf_add(struct mg_iobuf *io, size_t ofs, const void *buf,
1762 size_t len, size_t chunk_size) {
1763 size_t new_size = io->len + len;
1764 if (new_size > io->size) {
1765 new_size += chunk_size; // Make sure that io->size
1766 new_size -= new_size % chunk_size; // is aligned by chunk_size boundary
1767 mg_iobuf_resize(io, new_size); // Attempt to realloc
1768 if (new_size != io->size) len = 0; // Realloc failure, append nothing
1770 if (ofs < io->len) memmove(io->buf + ofs + len, io->buf + ofs, io->len - ofs);
1771 if (buf != NULL) memmove(io->buf + ofs, buf, len);
1772 if (ofs > io->len) io->len += ofs - io->len;
1777 size_t mg_iobuf_del(struct mg_iobuf *io, size_t ofs, size_t len) {
1778 if (ofs > io->len) ofs = io->len;
1779 if (ofs + len > io->len) len = io->len - ofs;
1780 memmove(io->buf + ofs, io->buf + ofs + len, io->len - ofs - len);
1781 zeromem(io->buf + io->len - len, len);
1786 void mg_iobuf_free(struct mg_iobuf *io) {
1787 mg_iobuf_resize(io, 0);
1790 #ifdef MG_ENABLE_LINES
1797 static void mg_log_stdout(const void *buf, size_t len, void *userdata) {
1799 fwrite(buf, 1, len, stdout);
1802 static const char *s_spec = "2";
1803 static void (*s_fn)(const void *, size_t, void *) = mg_log_stdout;
1804 static void *s_fn_param = NULL;
1806 void mg_log_set(const char *spec) {
1807 LOG(LL_DEBUG, ("Setting log level to %s", spec));
1811 bool mg_log_prefix(int level, const char *file, int line, const char *fname) {
1812 // static unsigned long seq;
1814 struct mg_str k, v, s = mg_str(s_spec);
1815 const char *p = strrchr(file, '/');
1817 if (s_fn == NULL) return false;
1819 if (p == NULL) p = strrchr(file, '\\');
1820 p = p == NULL ? file : p + 1;
1822 while (mg_commalist(&s, &k, &v)) {
1823 if (v.len == 0) max = atoi(k.ptr);
1824 if (v.len > 0 && strncmp(p, k.ptr, k.len) == 0) max = atoi(v.ptr);
1828 char timebuf[21], buf[50] = "";
1829 time_t t = time(NULL);
1830 struct tm tmp, *tm = gmtime_r(&t, &tmp);
1833 strftime(timebuf, sizeof(timebuf), "%Y-%m-%d %H:%M:%S", tm);
1834 n = snprintf(buf, sizeof(buf), "%s %d %s:%d:%s", timebuf, level, p, line,
1836 if (n < 0 || n > (int) sizeof(buf) - 2) n = sizeof(buf) - 2;
1837 while (n < (int) sizeof(buf) - 1) buf[n++] = ' ';
1838 s_fn(buf, sizeof(buf) - 1, s_fn_param);
1845 void mg_log(const char *fmt, ...) {
1846 char mem[256], *buf = mem;
1850 len = mg_vasprintf(&buf, sizeof(mem), fmt, ap);
1852 s_fn(buf, len > 0 ? (size_t) len : 0, s_fn_param);
1853 s_fn("\n", 1, s_fn_param);
1854 if (buf != mem) free(buf);
1857 void mg_log_set_callback(void (*fn)(const void *, size_t, void *), void *fnd) {
1863 #ifdef MG_ENABLE_LINES
1869 #if defined(MG_ENABLE_MD5) && MG_ENABLE_MD5
1870 #if !defined(BYTE_ORDER) && defined(__BYTE_ORDER)
1871 #define BYTE_ORDER __BYTE_ORDER
1872 #ifndef LITTLE_ENDIAN
1873 #define LITTLE_ENDIAN __LITTLE_ENDIAN
1874 #endif /* LITTLE_ENDIAN */
1876 #define BIG_ENDIAN __LITTLE_ENDIAN
1877 #endif /* BIG_ENDIAN */
1878 #endif /* BYTE_ORDER */
1880 static void mg_byte_reverse(unsigned char *buf, unsigned longs) {
1881 /* Forrest: MD5 expect LITTLE_ENDIAN, swap if BIG_ENDIAN */
1882 #if BYTE_ORDER == BIG_ENDIAN
1884 uint32_t t = (uint32_t)((unsigned) buf[3] << 8 | buf[2]) << 16 |
1885 ((unsigned) buf[1] << 8 | buf[0]);
1886 *(uint32_t *) buf = t;
1895 #define F1(x, y, z) (z ^ (x & (y ^ z)))
1896 #define F2(x, y, z) F1(z, x, y)
1897 #define F3(x, y, z) (x ^ y ^ z)
1898 #define F4(x, y, z) (y ^ (x | ~z))
1900 #define MD5STEP(f, w, x, y, z, data, s) \
1901 (w += f(x, y, z) + data, w = w << s | w >> (32 - s), w += x)
1904 * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious
1905 * initialization constants.
1907 void mg_md5_init(mg_md5_ctx *ctx) {
1908 ctx->buf[0] = 0x67452301;
1909 ctx->buf[1] = 0xefcdab89;
1910 ctx->buf[2] = 0x98badcfe;
1911 ctx->buf[3] = 0x10325476;
1917 static void mg_md5_transform(uint32_t buf[4], uint32_t const in[16]) {
1918 uint32_t a, b, c, d;
1925 MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7);
1926 MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12);
1927 MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17);
1928 MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22);
1929 MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7);
1930 MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12);
1931 MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17);
1932 MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22);
1933 MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7);
1934 MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12);
1935 MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17);
1936 MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22);
1937 MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7);
1938 MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12);
1939 MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17);
1940 MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22);
1942 MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5);
1943 MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9);
1944 MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14);
1945 MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20);
1946 MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5);
1947 MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9);
1948 MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14);
1949 MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20);
1950 MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5);
1951 MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9);
1952 MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14);
1953 MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20);
1954 MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5);
1955 MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9);
1956 MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14);
1957 MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20);
1959 MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4);
1960 MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11);
1961 MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16);
1962 MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23);
1963 MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4);
1964 MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11);
1965 MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16);
1966 MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23);
1967 MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4);
1968 MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11);
1969 MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16);
1970 MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23);
1971 MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4);
1972 MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11);
1973 MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16);
1974 MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23);
1976 MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6);
1977 MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10);
1978 MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15);
1979 MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21);
1980 MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6);
1981 MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10);
1982 MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15);
1983 MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21);
1984 MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6);
1985 MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10);
1986 MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15);
1987 MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21);
1988 MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6);
1989 MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10);
1990 MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15);
1991 MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21);
1999 void mg_md5_update(mg_md5_ctx *ctx, const unsigned char *buf, size_t len) {
2003 if ((ctx->bits[0] = t + ((uint32_t) len << 3)) < t) ctx->bits[1]++;
2004 ctx->bits[1] += (uint32_t) len >> 29;
2006 t = (t >> 3) & 0x3f;
2009 unsigned char *p = (unsigned char *) ctx->in + t;
2013 memcpy(p, buf, len);
2017 mg_byte_reverse(ctx->in, 16);
2018 mg_md5_transform(ctx->buf, (uint32_t *) ctx->in);
2024 memcpy(ctx->in, buf, 64);
2025 mg_byte_reverse(ctx->in, 16);
2026 mg_md5_transform(ctx->buf, (uint32_t *) ctx->in);
2031 memcpy(ctx->in, buf, len);
2034 void mg_md5_final(mg_md5_ctx *ctx, unsigned char digest[16]) {
2039 count = (ctx->bits[0] >> 3) & 0x3F;
2041 p = ctx->in + count;
2043 count = 64 - 1 - count;
2045 memset(p, 0, count);
2046 mg_byte_reverse(ctx->in, 16);
2047 mg_md5_transform(ctx->buf, (uint32_t *) ctx->in);
2048 memset(ctx->in, 0, 56);
2050 memset(p, 0, count - 8);
2052 mg_byte_reverse(ctx->in, 14);
2054 a = (uint32_t *) ctx->in;
2055 a[14] = ctx->bits[0];
2056 a[15] = ctx->bits[1];
2058 mg_md5_transform(ctx->buf, (uint32_t *) ctx->in);
2059 mg_byte_reverse((unsigned char *) ctx->buf, 4);
2060 memcpy(digest, ctx->buf, 16);
2061 memset((char *) ctx, 0, sizeof(*ctx));
2065 #ifdef MG_ENABLE_LINES
2066 #line 1 "src/mqtt.c"
2076 #define MQTT_CLEAN_SESSION 0x02
2077 #define MQTT_HAS_WILL 0x04
2078 #define MQTT_WILL_RETAIN 0x20
2079 #define MQTT_HAS_PASSWORD 0x40
2080 #define MQTT_HAS_USER_NAME 0x80
2082 enum { MQTT_OK, MQTT_INCOMPLETE, MQTT_MALFORMED };
2084 void mg_mqtt_send_header(struct mg_connection *c, uint8_t cmd, uint8_t flags,
2086 uint8_t buf[1 + sizeof(len)], *vlen = &buf[1];
2087 buf[0] = (uint8_t) ((cmd << 4) | flags);
2091 if (len > 0) *vlen |= 0x80;
2093 } while (len > 0 && vlen < &buf[sizeof(buf)]);
2094 mg_send(c, buf, (size_t) (vlen - buf));
2097 static void mg_send_u16(struct mg_connection *c, uint16_t value) {
2098 mg_send(c, &value, sizeof(value));
2101 void mg_mqtt_login(struct mg_connection *c, struct mg_mqtt_opts *opts) {
2102 char rnd[9], client_id[16];
2103 struct mg_str cid = opts->client_id;
2104 uint32_t total_len = 7 + 1 + 2 + 2;
2105 uint8_t connflag = (uint8_t) ((opts->qos & 3) << 1);
2108 mg_random(rnd, sizeof(rnd));
2109 mg_base64_encode((unsigned char *) rnd, sizeof(rnd), client_id);
2110 client_id[sizeof(client_id) - 1] = '\0';
2111 cid = mg_str(client_id);
2114 if (opts->user.len > 0) {
2115 total_len += 2 + (uint32_t) opts->user.len;
2116 connflag |= MQTT_HAS_USER_NAME;
2118 if (opts->pass.len > 0) {
2119 total_len += 2 + (uint32_t) opts->pass.len;
2120 connflag |= MQTT_HAS_PASSWORD;
2122 if (opts->will_topic.len > 0 && opts->will_message.len > 0) {
2124 4 + (uint32_t) opts->will_topic.len + (uint32_t) opts->will_message.len;
2125 connflag |= MQTT_HAS_WILL;
2127 if (opts->clean || cid.len == 0) connflag |= MQTT_CLEAN_SESSION;
2128 if (opts->will_retain) connflag |= MQTT_WILL_RETAIN;
2129 total_len += (uint32_t) cid.len;
2131 mg_mqtt_send_header(c, MQTT_CMD_CONNECT, 0, total_len);
2132 mg_send(c, "\00\04MQTT\04", 7);
2133 mg_send(c, &connflag, sizeof(connflag));
2134 // keepalive == 0 means "do not disconnect us!"
2135 mg_send_u16(c, mg_htons((uint16_t) opts->keepalive));
2136 mg_send_u16(c, mg_htons((uint16_t) cid.len));
2137 mg_send(c, cid.ptr, cid.len);
2138 if (connflag & MQTT_HAS_WILL) {
2139 mg_send_u16(c, mg_htons((uint16_t) opts->will_topic.len));
2140 mg_send(c, opts->will_topic.ptr, opts->will_topic.len);
2141 mg_send_u16(c, mg_htons((uint16_t) opts->will_message.len));
2142 mg_send(c, opts->will_message.ptr, opts->will_message.len);
2144 if (opts->user.len > 0) {
2145 mg_send_u16(c, mg_htons((uint16_t) opts->user.len));
2146 mg_send(c, opts->user.ptr, opts->user.len);
2148 if (opts->pass.len > 0) {
2149 mg_send_u16(c, mg_htons((uint16_t) opts->pass.len));
2150 mg_send(c, opts->pass.ptr, opts->pass.len);
2154 void mg_mqtt_pub(struct mg_connection *c, struct mg_str *topic,
2155 struct mg_str *data, int qos, bool retain) {
2156 uint8_t flags = (uint8_t) (((qos & 3) << 1) | (retain ? 1 : 0));
2157 uint32_t total_len = 2 + (uint32_t) topic->len + (uint32_t) data->len;
2158 LOG(LL_DEBUG, ("%lu [%.*s] -> [%.*s]", c->id, (int) topic->len,
2159 (char *) topic->ptr, (int) data->len, (char *) data->ptr));
2160 if (qos > 0) total_len += 2;
2161 mg_mqtt_send_header(c, MQTT_CMD_PUBLISH, flags, total_len);
2162 mg_send_u16(c, mg_htons((uint16_t) topic->len));
2163 mg_send(c, topic->ptr, topic->len);
2165 static uint16_t s_id;
2166 if (++s_id == 0) s_id++;
2167 mg_send_u16(c, mg_htons(s_id));
2169 mg_send(c, data->ptr, data->len);
2172 void mg_mqtt_sub(struct mg_connection *c, struct mg_str *topic, int qos) {
2173 static uint16_t s_id;
2174 uint8_t qos_ = qos & 3;
2175 uint32_t total_len = 2 + (uint32_t) topic->len + 2 + 1;
2176 mg_mqtt_send_header(c, MQTT_CMD_SUBSCRIBE, 2, total_len);
2177 if (++s_id == 0) ++s_id;
2178 mg_send_u16(c, mg_htons(s_id));
2179 mg_send_u16(c, mg_htons((uint16_t) topic->len));
2180 mg_send(c, topic->ptr, topic->len);
2181 mg_send(c, &qos_, sizeof(qos_));
2184 int mg_mqtt_parse(const uint8_t *buf, size_t len, struct mg_mqtt_message *m) {
2185 uint8_t lc = 0, *p, *end;
2186 uint32_t n = 0, len_len = 0;
2188 memset(m, 0, sizeof(*m));
2189 m->dgram.ptr = (char *) buf;
2190 if (len < 2) return MQTT_INCOMPLETE;
2191 m->cmd = (uint8_t) (buf[0] >> 4);
2192 m->qos = (buf[0] >> 1) & 3;
2195 p = (uint8_t *) buf + 1;
2196 while ((size_t) (p - buf) < len) {
2197 lc = *((uint8_t *) p++);
2198 n += (uint32_t) ((lc & 0x7f) << 7 * len_len);
2200 if (!(lc & 0x80)) break;
2201 if (len_len >= 4) return MQTT_MALFORMED;
2204 if (lc & 0x80 || end > buf + len) return MQTT_INCOMPLETE;
2205 m->dgram.len = (size_t) (end - buf);
2208 case MQTT_CMD_CONNACK:
2209 if (end - p < 2) return MQTT_MALFORMED;
2212 case MQTT_CMD_PUBACK:
2213 case MQTT_CMD_PUBREC:
2214 case MQTT_CMD_PUBREL:
2215 case MQTT_CMD_PUBCOMP:
2216 case MQTT_CMD_SUBACK:
2217 if (p + 2 > end) return MQTT_MALFORMED;
2218 m->id = (uint16_t) ((((uint16_t) p[0]) << 8) | p[1]);
2220 case MQTT_CMD_SUBSCRIBE: {
2221 if (p + 2 > end) return MQTT_MALFORMED;
2222 m->id = (uint16_t) ((((uint16_t) p[0]) << 8) | p[1]);
2226 case MQTT_CMD_PUBLISH: {
2227 if (p + 2 > end) return MQTT_MALFORMED;
2228 m->topic.len = (uint16_t) ((((uint16_t) p[0]) << 8) | p[1]);
2229 m->topic.ptr = (char *) p + 2;
2230 p += 2 + m->topic.len;
2231 if (p > end) return MQTT_MALFORMED;
2233 if (p + 2 > end) return MQTT_MALFORMED;
2234 m->id = (uint16_t) ((((uint16_t) p[0]) << 8) | p[1]);
2237 if (p > end) return MQTT_MALFORMED;
2238 m->data.ptr = (char *) p;
2239 m->data.len = (size_t) (end - p);
2248 static size_t mg_mqtt_next_topic(struct mg_mqtt_message *msg,
2249 struct mg_str *topic, uint8_t *qos,
2251 unsigned char *buf = (unsigned char *) msg->dgram.ptr + pos;
2253 if (pos >= msg->dgram.len) return 0;
2255 topic->len = (size_t) (((unsigned) buf[0]) << 8 | buf[1]);
2256 topic->ptr = (char *) buf + 2;
2257 new_pos = pos + 2 + topic->len + (qos == NULL ? 0 : 1);
2258 if ((size_t) new_pos > msg->dgram.len) return 0;
2259 if (qos != NULL) *qos = buf[2 + topic->len];
2263 size_t mg_mqtt_next_sub(struct mg_mqtt_message *msg, struct mg_str *topic,
2264 uint8_t *qos, size_t pos) {
2266 return mg_mqtt_next_topic(msg, topic, qos == NULL ? &tmp : qos, pos);
2269 size_t mg_mqtt_next_unsub(struct mg_mqtt_message *msg, struct mg_str *topic,
2271 return mg_mqtt_next_topic(msg, topic, NULL, pos);
2274 static void mqtt_cb(struct mg_connection *c, int ev, void *ev_data,
2276 if (ev == MG_EV_READ) {
2278 struct mg_mqtt_message mm;
2279 int rc = mg_mqtt_parse(c->recv.buf, c->recv.len, &mm);
2280 if (rc == MQTT_MALFORMED) {
2281 LOG(LL_ERROR, ("%lu MQTT malformed message", c->id));
2284 } else if (rc == MQTT_OK) {
2285 LOG(LL_VERBOSE_DEBUG,
2286 ("%p MQTT CMD %d len %d [%.*s]", c->fd, mm.cmd, (int) mm.dgram.len,
2287 (int) mm.data.len, mm.data.ptr));
2289 case MQTT_CMD_CONNACK:
2290 mg_call(c, MG_EV_MQTT_OPEN, &mm.ack);
2292 LOG(LL_INFO, ("%lu Connected", c->id));
2294 LOG(LL_ERROR, ("%lu MQTT auth failed, code %d", c->id, mm.ack));
2298 case MQTT_CMD_PUBLISH: {
2299 LOG(LL_DEBUG, ("%lu [%.*s] -> [%.*s]", c->id, (int) mm.topic.len,
2300 mm.topic.ptr, (int) mm.data.len, mm.data.ptr));
2301 mg_call(c, MG_EV_MQTT_MSG, &mm);
2305 mg_call(c, MG_EV_MQTT_CMD, &mm);
2306 mg_iobuf_del(&c->recv, 0, mm.dgram.len);
2316 void mg_mqtt_ping(struct mg_connection *nc) {
2317 mg_mqtt_send_header(nc, MQTT_CMD_PINGREQ, 0, 0);
2320 void mg_mqtt_pong(struct mg_connection *nc) {
2321 mg_mqtt_send_header(nc, MQTT_CMD_PINGRESP, 0, 0);
2324 void mg_mqtt_disconnect(struct mg_connection *nc) {
2325 mg_mqtt_send_header(nc, MQTT_CMD_DISCONNECT, 0, 0);
2328 struct mg_connection *mg_mqtt_connect(struct mg_mgr *mgr, const char *url,
2329 struct mg_mqtt_opts *opts,
2330 mg_event_handler_t fn, void *fn_data) {
2331 struct mg_connection *c = mg_connect(mgr, url, fn, fn_data);
2333 struct mg_mqtt_opts empty;
2334 memset(&empty, 0, sizeof(empty));
2335 mg_mqtt_login(c, opts == NULL ? &empty : opts);
2341 struct mg_connection *mg_mqtt_listen(struct mg_mgr *mgr, const char *url,
2342 mg_event_handler_t fn, void *fn_data) {
2343 struct mg_connection *c = mg_listen(mgr, url, fn, fn_data);
2344 if (c != NULL) c->pfn = mqtt_cb, c->pfn_data = mgr;
2348 #ifdef MG_ENABLE_LINES
2355 int mg_vprintf(struct mg_connection *c, const char *fmt, va_list ap) {
2356 char mem[256], *buf = mem;
2357 int len = mg_vasprintf(&buf, sizeof(mem), fmt, ap);
2358 len = mg_send(c, buf, len > 0 ? (size_t) len : 0);
2359 if (buf != mem) free(buf);
2363 int mg_printf(struct mg_connection *c, const char *fmt, ...) {
2367 len = mg_vprintf(c, fmt, ap);
2372 char *mg_straddr(struct mg_connection *c, char *buf, size_t len) {
2374 const char *fmt = c->peer.is_ip6 ? "[%s]:%d" : "%s:%d";
2375 mg_ntoa(&c->peer, tmp, sizeof(tmp));
2376 snprintf(buf, len, fmt, tmp, (int) mg_ntohs(c->peer.port));
2380 char *mg_ntoa(const struct mg_addr *addr, char *buf, size_t len) {
2382 uint16_t *p = (uint16_t *) addr->ip6;
2383 snprintf(buf, len, "%x:%x:%x:%x:%x:%x:%x:%x", mg_htons(p[0]),
2384 mg_htons(p[1]), mg_htons(p[2]), mg_htons(p[3]), mg_htons(p[4]),
2385 mg_htons(p[5]), mg_htons(p[6]), mg_htons(p[7]));
2388 memcpy(p, &addr->ip, sizeof(p));
2389 snprintf(buf, len, "%d.%d.%d.%d", (int) p[0], (int) p[1], (int) p[2],
2395 static bool mg_atonl(struct mg_str str, struct mg_addr *addr) {
2396 if (mg_vcasecmp(&str, "localhost") != 0) return false;
2397 addr->ip = mg_htonl(0x7f000001);
2398 addr->is_ip6 = false;
2402 static bool mg_atone(struct mg_str str, struct mg_addr *addr) {
2403 if (str.len > 0) return false;
2405 addr->is_ip6 = false;
2409 static bool mg_aton4(struct mg_str str, struct mg_addr *addr) {
2410 uint8_t data[4] = {0, 0, 0, 0};
2411 size_t i, num_dots = 0;
2412 for (i = 0; i < str.len; i++) {
2413 if (str.ptr[i] >= '0' && str.ptr[i] <= '9') {
2414 int octet = data[num_dots] * 10 + (str.ptr[i] - '0');
2415 if (octet > 255) return false;
2416 data[num_dots] = (uint8_t) octet;
2417 } else if (str.ptr[i] == '.') {
2418 if (num_dots >= 3 || i == 0 || str.ptr[i - 1] == '.') return false;
2424 if (num_dots != 3 || str.ptr[i - 1] == '.') return false;
2425 memcpy(&addr->ip, data, sizeof(data));
2426 addr->is_ip6 = false;
2430 static bool mg_v4mapped(struct mg_str str, struct mg_addr *addr) {
2432 if (str.len < 14) return false;
2433 if (str.ptr[0] != ':' || str.ptr[1] != ':' || str.ptr[6] != ':') return false;
2434 for (i = 2; i < 6; i++) {
2435 if (str.ptr[i] != 'f' && str.ptr[i] != 'F') return false;
2437 if (!mg_aton4(mg_str_n(&str.ptr[7], str.len - 7), addr)) return false;
2438 memset(addr->ip6, 0, sizeof(addr->ip6));
2439 addr->ip6[10] = addr->ip6[11] = 255;
2440 memcpy(&addr->ip6[12], &addr->ip, 4);
2441 addr->is_ip6 = true;
2445 static bool mg_aton6(struct mg_str str, struct mg_addr *addr) {
2446 size_t i, j = 0, n = 0, dc = 42;
2447 if (str.len > 2 && str.ptr[0] == '[') str.ptr++, str.len -= 2;
2448 if (mg_v4mapped(str, addr)) return true;
2449 for (i = 0; i < str.len; i++) {
2450 if ((str.ptr[i] >= '0' && str.ptr[i] <= '9') ||
2451 (str.ptr[i] >= 'a' && str.ptr[i] <= 'f') ||
2452 (str.ptr[i] >= 'A' && str.ptr[i] <= 'F')) {
2454 if (i > j + 3) return false;
2455 // LOG(LL_DEBUG, ("%zu %zu [%.*s]", i, j, (int) (i - j + 1),
2457 val = mg_unhexn(&str.ptr[j], i - j + 1);
2458 addr->ip6[n] = (uint8_t) ((val >> 8) & 255);
2459 addr->ip6[n + 1] = (uint8_t) (val & 255);
2460 } else if (str.ptr[i] == ':') {
2462 if (i > 0 && str.ptr[i - 1] == ':') {
2463 dc = n; // Double colon
2464 if (i > 1 && str.ptr[i - 2] == ':') return false;
2468 if (n > 14) return false;
2469 addr->ip6[n] = addr->ip6[n + 1] = 0; // For trailing ::
2474 if (n < 14 && dc == 42) return false;
2476 memmove(&addr->ip6[dc + (14 - n)], &addr->ip6[dc], n - dc + 2);
2477 memset(&addr->ip6[dc], 0, 14 - n);
2479 addr->is_ip6 = true;
2483 bool mg_aton(struct mg_str str, struct mg_addr *addr) {
2484 // LOG(LL_INFO, ("[%.*s]", (int) str.len, str.ptr));
2485 return mg_atone(str, addr) || mg_atonl(str, addr) || mg_aton4(str, addr) ||
2486 mg_aton6(str, addr);
2489 void mg_mgr_free(struct mg_mgr *mgr) {
2490 struct mg_connection *c;
2491 for (c = mgr->conns; c != NULL; c = c->next) c->is_closing = 1;
2492 mg_mgr_poll(mgr, 0);
2493 #if MG_ARCH == MG_ARCH_FREERTOS_TCP
2494 FreeRTOS_DeleteSocketSet(mgr->ss);
2496 LOG(LL_INFO, ("All connections closed"));
2499 void mg_mgr_init(struct mg_mgr *mgr) {
2500 memset(mgr, 0, sizeof(*mgr));
2501 #if defined(_WIN32) && MG_ENABLE_WINSOCK
2503 { WSADATA data; WSAStartup(MAKEWORD(2, 2), &data); }
2505 #elif MG_ARCH == MG_ARCH_FREERTOS_TCP
2506 mgr->ss = FreeRTOS_CreateSocketSet();
2507 #elif defined(__unix) || defined(__unix__) || defined(__APPLE__)
2508 // Ignore SIGPIPE signal, so if client cancels the request, it
2509 // won't kill the whole process.
2510 signal(SIGPIPE, SIG_IGN);
2512 mgr->dnstimeout = 3000;
2513 mgr->dns4.url = "udp://8.8.8.8:53";
2514 mgr->dns6.url = "udp://[2001:4860:4860::8888]:53";
2517 #ifdef MG_ENABLE_LINES
2518 #line 1 "src/sha1.c"
2520 /* Copyright(c) By Steve Reid <steve@edmweb.com> */
2521 /* 100% Public Domain */
2526 * clang with std=-c99 uses __LITTLE_ENDIAN, by default
2527 * while for ex, RTOS gcc - LITTLE_ENDIAN, by default
2528 * it depends on __USE_BSD, but let's have everything
2530 #if !defined(BYTE_ORDER) && defined(__BYTE_ORDER)
2531 #define BYTE_ORDER __BYTE_ORDER
2532 #ifndef LITTLE_ENDIAN
2533 #define LITTLE_ENDIAN __LITTLE_ENDIAN
2534 #endif /* LITTLE_ENDIAN */
2536 #define BIG_ENDIAN __LITTLE_ENDIAN
2537 #endif /* BIG_ENDIAN */
2538 #endif /* BYTE_ORDER */
2540 union char64long16 {
2541 unsigned char c[64];
2545 #define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits))))
2547 static uint32_t blk0(union char64long16 *block, int i) {
2548 /* Forrest: SHA expect BIG_ENDIAN, swap if LITTLE_ENDIAN */
2549 #if BYTE_ORDER == LITTLE_ENDIAN
2551 (rol(block->l[i], 24) & 0xFF00FF00) | (rol(block->l[i], 8) & 0x00FF00FF);
2556 /* Avoid redefine warning (ARM /usr/include/sys/ucontext.h define R0~R4) */
2565 (block->l[i & 15] = rol(block->l[(i + 13) & 15] ^ block->l[(i + 8) & 15] ^ \
2566 block->l[(i + 2) & 15] ^ block->l[i & 15], \
2568 #define R0(v, w, x, y, z, i) \
2569 z += ((w & (x ^ y)) ^ y) + blk0(block, i) + 0x5A827999 + rol(v, 5); \
2571 #define R1(v, w, x, y, z, i) \
2572 z += ((w & (x ^ y)) ^ y) + blk(i) + 0x5A827999 + rol(v, 5); \
2574 #define R2(v, w, x, y, z, i) \
2575 z += (w ^ x ^ y) + blk(i) + 0x6ED9EBA1 + rol(v, 5); \
2577 #define R3(v, w, x, y, z, i) \
2578 z += (((w | x) & y) | (w & x)) + blk(i) + 0x8F1BBCDC + rol(v, 5); \
2580 #define R4(v, w, x, y, z, i) \
2581 z += (w ^ x ^ y) + blk(i) + 0xCA62C1D6 + rol(v, 5); \
2584 static void mg_sha1_transform(uint32_t state[5], const unsigned char buffer[64]) {
2585 uint32_t a, b, c, d, e;
2586 union char64long16 block[1];
2588 memcpy(block, buffer, 64);
2594 R0(a, b, c, d, e, 0);
2595 R0(e, a, b, c, d, 1);
2596 R0(d, e, a, b, c, 2);
2597 R0(c, d, e, a, b, 3);
2598 R0(b, c, d, e, a, 4);
2599 R0(a, b, c, d, e, 5);
2600 R0(e, a, b, c, d, 6);
2601 R0(d, e, a, b, c, 7);
2602 R0(c, d, e, a, b, 8);
2603 R0(b, c, d, e, a, 9);
2604 R0(a, b, c, d, e, 10);
2605 R0(e, a, b, c, d, 11);
2606 R0(d, e, a, b, c, 12);
2607 R0(c, d, e, a, b, 13);
2608 R0(b, c, d, e, a, 14);
2609 R0(a, b, c, d, e, 15);
2610 R1(e, a, b, c, d, 16);
2611 R1(d, e, a, b, c, 17);
2612 R1(c, d, e, a, b, 18);
2613 R1(b, c, d, e, a, 19);
2614 R2(a, b, c, d, e, 20);
2615 R2(e, a, b, c, d, 21);
2616 R2(d, e, a, b, c, 22);
2617 R2(c, d, e, a, b, 23);
2618 R2(b, c, d, e, a, 24);
2619 R2(a, b, c, d, e, 25);
2620 R2(e, a, b, c, d, 26);
2621 R2(d, e, a, b, c, 27);
2622 R2(c, d, e, a, b, 28);
2623 R2(b, c, d, e, a, 29);
2624 R2(a, b, c, d, e, 30);
2625 R2(e, a, b, c, d, 31);
2626 R2(d, e, a, b, c, 32);
2627 R2(c, d, e, a, b, 33);
2628 R2(b, c, d, e, a, 34);
2629 R2(a, b, c, d, e, 35);
2630 R2(e, a, b, c, d, 36);
2631 R2(d, e, a, b, c, 37);
2632 R2(c, d, e, a, b, 38);
2633 R2(b, c, d, e, a, 39);
2634 R3(a, b, c, d, e, 40);
2635 R3(e, a, b, c, d, 41);
2636 R3(d, e, a, b, c, 42);
2637 R3(c, d, e, a, b, 43);
2638 R3(b, c, d, e, a, 44);
2639 R3(a, b, c, d, e, 45);
2640 R3(e, a, b, c, d, 46);
2641 R3(d, e, a, b, c, 47);
2642 R3(c, d, e, a, b, 48);
2643 R3(b, c, d, e, a, 49);
2644 R3(a, b, c, d, e, 50);
2645 R3(e, a, b, c, d, 51);
2646 R3(d, e, a, b, c, 52);
2647 R3(c, d, e, a, b, 53);
2648 R3(b, c, d, e, a, 54);
2649 R3(a, b, c, d, e, 55);
2650 R3(e, a, b, c, d, 56);
2651 R3(d, e, a, b, c, 57);
2652 R3(c, d, e, a, b, 58);
2653 R3(b, c, d, e, a, 59);
2654 R4(a, b, c, d, e, 60);
2655 R4(e, a, b, c, d, 61);
2656 R4(d, e, a, b, c, 62);
2657 R4(c, d, e, a, b, 63);
2658 R4(b, c, d, e, a, 64);
2659 R4(a, b, c, d, e, 65);
2660 R4(e, a, b, c, d, 66);
2661 R4(d, e, a, b, c, 67);
2662 R4(c, d, e, a, b, 68);
2663 R4(b, c, d, e, a, 69);
2664 R4(a, b, c, d, e, 70);
2665 R4(e, a, b, c, d, 71);
2666 R4(d, e, a, b, c, 72);
2667 R4(c, d, e, a, b, 73);
2668 R4(b, c, d, e, a, 74);
2669 R4(a, b, c, d, e, 75);
2670 R4(e, a, b, c, d, 76);
2671 R4(d, e, a, b, c, 77);
2672 R4(c, d, e, a, b, 78);
2673 R4(b, c, d, e, a, 79);
2679 /* Erase working structures. The order of operations is important,
2680 * used to ensure that compiler doesn't optimize those out. */
2681 memset(block, 0, sizeof(block));
2682 a = b = c = d = e = 0;
2690 void mg_sha1_init(mg_sha1_ctx *context) {
2691 context->state[0] = 0x67452301;
2692 context->state[1] = 0xEFCDAB89;
2693 context->state[2] = 0x98BADCFE;
2694 context->state[3] = 0x10325476;
2695 context->state[4] = 0xC3D2E1F0;
2696 context->count[0] = context->count[1] = 0;
2699 void mg_sha1_update(mg_sha1_ctx *context, const unsigned char *data,
2703 j = context->count[0];
2704 if ((context->count[0] += (uint32_t) len << 3) < j) context->count[1]++;
2705 context->count[1] += (uint32_t)(len >> 29);
2707 if ((j + len) > 63) {
2708 memcpy(&context->buffer[j], data, (i = 64 - j));
2709 mg_sha1_transform(context->state, context->buffer);
2710 for (; i + 63 < len; i += 64) {
2711 mg_sha1_transform(context->state, &data[i]);
2716 memcpy(&context->buffer[j], &data[i], len - i);
2719 void mg_sha1_final(unsigned char digest[20], mg_sha1_ctx *context) {
2721 unsigned char finalcount[8], c;
2723 for (i = 0; i < 8; i++) {
2724 finalcount[i] = (unsigned char) ((context->count[(i >= 4 ? 0 : 1)] >>
2725 ((3 - (i & 3)) * 8)) &
2729 mg_sha1_update(context, &c, 1);
2730 while ((context->count[0] & 504) != 448) {
2732 mg_sha1_update(context, &c, 1);
2734 mg_sha1_update(context, finalcount, 8);
2735 for (i = 0; i < 20; i++) {
2737 (unsigned char) ((context->state[i >> 2] >> ((3 - (i & 3)) * 8)) & 255);
2739 memset(context, '\0', sizeof(*context));
2740 memset(&finalcount, '\0', sizeof(finalcount));
2743 void mg_hmac_sha1(const unsigned char *key, size_t keylen,
2744 const unsigned char *data, size_t datalen,
2745 unsigned char out[20]) {
2747 unsigned char buf1[64], buf2[64], tmp_key[20], i;
2749 if (keylen > sizeof(buf1)) {
2751 mg_sha1_update(&ctx, key, keylen);
2752 mg_sha1_final(tmp_key, &ctx);
2754 keylen = sizeof(tmp_key);
2757 memset(buf1, 0, sizeof(buf1));
2758 memset(buf2, 0, sizeof(buf2));
2759 memcpy(buf1, key, keylen);
2760 memcpy(buf2, key, keylen);
2762 for (i = 0; i < sizeof(buf1); i++) {
2768 mg_sha1_update(&ctx, buf1, sizeof(buf1));
2769 mg_sha1_update(&ctx, data, datalen);
2770 mg_sha1_final(out, &ctx);
2773 mg_sha1_update(&ctx, buf2, sizeof(buf2));
2774 mg_sha1_update(&ctx, out, 20);
2775 mg_sha1_final(out, &ctx);
2778 #ifdef MG_ENABLE_LINES
2779 #line 1 "src/sntp.c"
2787 #define SNTP_INTERVAL_SEC (3600)
2788 #define SNTP_TIME_OFFSET 2208988800UL
2790 static unsigned long s_sntmp_next;
2792 int mg_sntp_parse(const unsigned char *buf, size_t len, struct timeval *tv) {
2793 int mode = len > 0 ? buf[0] & 7 : 0, res = -1;
2795 LOG(LL_ERROR, ("%s", "corrupt packet"));
2796 } else if ((buf[0] & 0x38) >> 3 != 4) {
2797 LOG(LL_ERROR, ("%s", "wrong version"));
2798 } else if (mode != 4 && mode != 5) {
2799 LOG(LL_ERROR, ("%s", "not a server reply"));
2800 } else if (buf[1] == 0) {
2801 LOG(LL_ERROR, ("%s", "server sent a kiss of death"));
2803 uint32_t *data = (uint32_t *) &buf[40];
2804 tv->tv_sec = (time_t) (mg_ntohl(data[0]) - SNTP_TIME_OFFSET);
2805 tv->tv_usec = (suseconds_t) mg_ntohl(data[1]);
2806 s_sntmp_next = (unsigned long) (tv->tv_sec + SNTP_INTERVAL_SEC);
2812 static void sntp_cb(struct mg_connection *c, int ev, void *evd, void *fnd) {
2813 if (ev == MG_EV_READ) {
2814 struct timeval tv = {0, 0};
2815 if (mg_sntp_parse(c->recv.buf, c->recv.len, &tv) == 0) {
2816 mg_call(c, MG_EV_SNTP_TIME, &tv);
2817 LOG(LL_DEBUG, ("%u.%u, next at %lu", (unsigned) tv.tv_sec,
2818 (unsigned) tv.tv_usec, s_sntmp_next));
2820 c->recv.len = 0; // Clear receive buffer
2821 } else if (ev == MG_EV_CONNECT) {
2822 mg_sntp_send(c, (unsigned long) time(NULL));
2823 } else if (ev == MG_EV_CLOSE) {
2829 void mg_sntp_send(struct mg_connection *c, unsigned long utc) {
2830 if (c->is_resolving) {
2831 LOG(LL_ERROR, ("%lu wait until resolved", c->id));
2832 } else if (utc > s_sntmp_next) {
2833 uint8_t buf[48] = {0};
2834 s_sntmp_next = utc + SNTP_INTERVAL_SEC;
2835 buf[0] = (0 << 6) | (4 << 3) | 3;
2836 mg_send(c, buf, sizeof(buf));
2837 LOG(LL_DEBUG, ("%lu ct %lu, next at %lu", c->id, utc, s_sntmp_next));
2841 struct mg_connection *mg_sntp_connect(struct mg_mgr *mgr, const char *url,
2842 mg_event_handler_t fn, void *fnd) {
2843 struct mg_connection *c = NULL;
2844 if (url == NULL) url = "udp://time.google.com:123";
2845 if ((c = mg_connect(mgr, url, fn, fnd)) != NULL) c->pfn = sntp_cb;
2849 #ifdef MG_ENABLE_LINES
2850 #line 1 "src/sock.c"
2862 #if MG_ENABLE_SOCKET
2863 #if defined(_WIN32) && MG_ENABLE_WINSOCK
2864 #define MG_SOCK_ERRNO WSAGetLastError()
2865 #ifndef SO_EXCLUSIVEADDRUSE
2866 #define SO_EXCLUSIVEADDRUSE ((int) (~SO_REUSEADDR))
2868 #elif MG_ARCH == MG_ARCH_FREERTOS_TCP
2869 #define MG_SOCK_ERRNO errno
2870 typedef Socket_t SOCKET;
2871 #define INVALID_SOCKET FREERTOS_INVALID_SOCKET
2873 #define MG_SOCK_ERRNO errno
2875 #define closesocket(x) close(x)
2877 #define INVALID_SOCKET (-1)
2881 #define FD(c_) ((SOCKET) (size_t) (c_)->fd)
2882 #define S2PTR(s_) ((void *) (size_t) (s_))
2884 #ifndef MSG_NONBLOCKING
2885 #define MSG_NONBLOCKING 0
2894 struct sockaddr_in sin;
2896 struct sockaddr_in6 sin6;
2900 static socklen_t tousa(struct mg_addr *a, union usa *usa) {
2901 socklen_t len = sizeof(usa->sin);
2902 memset(usa, 0, sizeof(*usa));
2903 usa->sin.sin_family = AF_INET;
2904 usa->sin.sin_port = a->port;
2905 *(uint32_t *) &usa->sin.sin_addr = a->ip;
2908 usa->sin.sin_family = AF_INET6;
2909 usa->sin6.sin6_port = a->port;
2910 memcpy(&usa->sin6.sin6_addr, a->ip6, sizeof(a->ip6));
2911 len = sizeof(usa->sin6);
2917 static void tomgaddr(union usa *usa, struct mg_addr *a, bool is_ip6) {
2919 a->port = usa->sin.sin_port;
2920 memcpy(&a->ip, &usa->sin.sin_addr, sizeof(a->ip));
2923 memcpy(a->ip6, &usa->sin6.sin6_addr, sizeof(a->ip6));
2924 a->port = usa->sin6.sin6_port;
2929 static bool mg_sock_would_block(void) {
2930 int err = MG_SOCK_ERRNO;
2931 return err == EINPROGRESS || err == EWOULDBLOCK
2933 || err == EAGAIN || err == EINTR
2935 #if defined(_WIN32) && MG_ENABLE_WINSOCK
2936 || err == WSAEINTR || err == WSAEWOULDBLOCK
2941 static struct mg_connection *alloc_conn(struct mg_mgr *mgr, bool is_client,
2943 struct mg_connection *c = (struct mg_connection *) calloc(1, sizeof(*c));
2945 c->is_client = is_client;
2948 c->id = ++mgr->nextid;
2953 static long mg_sock_send(struct mg_connection *c, const void *buf, size_t len) {
2955 #if !defined(__APPLE__)
2956 // See #1338, #1382. On Windows, UDP send() can fail despite connected.
2957 // Use sendto() instead. But not on Mac - we'll get EISCONN
2960 socklen_t slen = tousa(&c->peer, &usa);
2961 n = sendto(FD(c), (char *) buf, len, 0, &usa.sa, slen);
2965 n = send(FD(c), (char *) buf, len, MSG_NONBLOCKING);
2967 return n == 0 ? -1 : n < 0 && mg_sock_would_block() ? 0 : n;
2970 bool mg_send(struct mg_connection *c, const void *buf, size_t len) {
2971 return c->is_udp ? mg_sock_send(c, buf, len) > 0
2972 : mg_iobuf_add(&c->send, c->send.len, buf, len, MG_IO_SIZE);
2975 static void mg_set_non_blocking_mode(SOCKET fd) {
2976 #if defined(_WIN32) && MG_ENABLE_WINSOCK
2977 unsigned long on = 1;
2978 ioctlsocket(fd, FIONBIO, &on);
2979 #elif MG_ARCH == MG_ARCH_FREERTOS_TCP
2980 const BaseType_t off = 0;
2981 setsockopt(fd, 0, FREERTOS_SO_RCVTIMEO, &off, sizeof(off));
2982 setsockopt(fd, 0, FREERTOS_SO_SNDTIMEO, &off, sizeof(off));
2983 #elif MG_ARCH == MG_ARCH_FREERTOS_LWIP
2984 lwip_fcntl(fd, F_SETFL, O_NONBLOCK);
2985 #elif MG_ARCH == MG_ARCH_AZURERTOS
2986 fcntl(fd, F_SETFL, O_NONBLOCK);
2988 fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK); // Set non-blocking mode
2989 fcntl(fd, F_SETFD, FD_CLOEXEC); // Set close-on-exec
2993 static SOCKET mg_open_listener(const char *url, struct mg_addr *addr) {
2994 SOCKET fd = INVALID_SOCKET;
2995 int s_err = 0; // Memoized socket error, in case closesocket() overrides it
2996 memset(addr, 0, sizeof(*addr));
2997 addr->port = mg_htons(mg_url_port(url));
2998 if (!mg_aton(mg_url_host(url), addr)) {
2999 LOG(LL_ERROR, ("invalid listening URL: %s", url));
3002 socklen_t slen = tousa(addr, &usa);
3003 int on = 1, af = addr->is_ip6 ? AF_INET6 : AF_INET;
3004 int type = strncmp(url, "udp:", 4) == 0 ? SOCK_DGRAM : SOCK_STREAM;
3005 int proto = type == SOCK_DGRAM ? IPPROTO_UDP : IPPROTO_TCP;
3008 if ((fd = socket(af, type, proto)) != INVALID_SOCKET &&
3009 #if (!defined(_WIN32) || !defined(SO_EXCLUSIVEADDRUSE)) && \
3010 (!defined(LWIP_SOCKET) || (defined(LWIP_SOCKET) && SO_REUSE == 1))
3011 // 1. SO_RESUSEADDR is not enabled on Windows because the semantics of
3012 // SO_REUSEADDR on UNIX and Windows is different. On Windows,
3013 // SO_REUSEADDR allows to bind a socket to a port without error even
3014 // if the port is already open by another program. This is not the
3015 // behavior SO_REUSEADDR was designed for, and leads to hard-to-track
3016 // failure scenarios. Therefore, SO_REUSEADDR was disabled on Windows
3017 // unless SO_EXCLUSIVEADDRUSE is supported and set on a socket.
3018 // 2. In case of LWIP, SO_REUSEADDR should be explicitly enabled, by
3020 // SO_REUSE (in lwipopts.h), otherwise the code below will compile
3021 // but won't work! (setsockopt will return EINVAL)
3022 !setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &on, sizeof(on)) &&
3024 #if defined(_WIN32) && defined(SO_EXCLUSIVEADDRUSE) && !defined(WINCE)
3025 // "Using SO_REUSEADDR and SO_EXCLUSIVEADDRUSE"
3026 //! setsockopt(fd, SOL_SOCKET, SO_BROADCAST, (char *) &on, sizeof(on))
3028 !setsockopt(fd, SOL_SOCKET, SO_EXCLUSIVEADDRUSE, (char *) &on,
3031 bind(fd, &usa.sa, slen) == 0 &&
3032 // NOTE(lsm): FreeRTOS uses backlog value as a connection limit
3033 (type == SOCK_DGRAM || listen(fd, MG_SOCK_LISTEN_BACKLOG_SIZE) == 0)) {
3034 // In case port was set to 0, get the real port number
3035 if (getsockname(fd, &usa.sa, &slen) == 0) {
3036 addr->port = usa.sin.sin_port;
3038 if (addr->is_ip6) addr->port = usa.sin6.sin6_port;
3041 mg_set_non_blocking_mode(fd);
3042 } else if (fd != INVALID_SOCKET) {
3043 s_err = MG_SOCK_ERRNO;
3045 fd = INVALID_SOCKET;
3048 if (fd == INVALID_SOCKET) {
3049 if (s_err == 0) s_err = MG_SOCK_ERRNO;
3050 LOG(LL_ERROR, ("Failed to listen on %s, errno %d", url, s_err));
3056 static long mg_sock_recv(struct mg_connection *c, void *buf, size_t len) {
3060 socklen_t slen = tousa(&c->peer, &usa);
3061 n = recvfrom(FD(c), (char *) buf, len, 0, &usa.sa, &slen);
3062 if (n > 0) tomgaddr(&usa, &c->peer, slen != sizeof(usa.sin));
3064 n = recv(FD(c), (char *) buf, len, MSG_NONBLOCKING);
3066 return n == 0 ? -1 : n < 0 && mg_sock_would_block() ? 0 : n;
3069 // NOTE(lsm): do only one iteration of reads, cause some systems
3070 // (e.g. FreeRTOS stack) return 0 instead of -1/EWOULDBLOCK when no data
3071 static long read_conn(struct mg_connection *c) {
3073 if (c->recv.len >= MG_MAX_RECV_BUF_SIZE) {
3074 mg_error(c, "max_recv_buf_size reached");
3075 } else if (c->recv.size - c->recv.len < MG_IO_SIZE &&
3076 !mg_iobuf_resize(&c->recv, c->recv.size + MG_IO_SIZE)) {
3079 char *buf = (char *) &c->recv.buf[c->recv.len];
3080 size_t len = c->recv.size - c->recv.len;
3081 n = c->is_tls ? mg_tls_recv(c, buf, len) : mg_sock_recv(c, buf, len);
3082 LOG(n > 0 ? LL_VERBOSE_DEBUG : LL_DEBUG,
3083 ("%-3lu %d%d%d%d%d%d%d%d%d%d%d%d%d%d %7ld %ld/%ld err %d", c->id,
3084 c->is_listening, c->is_client, c->is_accepted, c->is_resolving,
3085 c->is_connecting, c->is_tls, c->is_tls_hs, c->is_udp, c->is_websocket,
3086 c->is_hexdumping, c->is_draining, c->is_closing, c->is_readable,
3087 c->is_writable, (long) c->recv.len, n, (long) len, MG_SOCK_ERRNO));
3091 c->is_closing = 1; // Error, or normal termination
3093 struct mg_str evd = mg_str_n(buf, (size_t) n);
3094 if (c->is_hexdumping) {
3095 char *s = mg_hexdump(buf, (size_t) n);
3096 LOG(LL_INFO, ("\n-- %lu %s %s %ld\n%s", c->id, c->label, "<-", n, s));
3099 c->recv.len += (size_t) n;
3100 mg_call(c, MG_EV_READ, &evd);
3106 static void write_conn(struct mg_connection *c) {
3107 char *buf = (char *) c->send.buf;
3108 size_t len = c->send.len;
3109 long n = c->is_tls ? mg_tls_send(c, buf, len) : mg_sock_send(c, buf, len);
3111 LOG(n > 0 ? LL_VERBOSE_DEBUG : LL_DEBUG,
3112 ("%-3lu %d%d%d%d%d%d%d%d%d%d%d%d%d%d %7ld %ld err %d", c->id,
3113 c->is_listening, c->is_client, c->is_accepted, c->is_resolving,
3114 c->is_connecting, c->is_tls, c->is_tls_hs, c->is_udp, c->is_websocket,
3115 c->is_hexdumping, c->is_draining, c->is_closing, c->is_readable,
3116 c->is_writable, (long) c->send.len, n, MG_SOCK_ERRNO));
3121 c->is_closing = 1; // Error, or normal termination
3123 // Hexdump before deleting
3124 if (c->is_hexdumping) {
3125 char *s = mg_hexdump(buf, (size_t) n);
3126 LOG(LL_INFO, ("\n-- %lu %s %s %ld\n%s", c->id, c->label, "<-", n, s));
3129 mg_iobuf_del(&c->send, 0, (size_t) n);
3130 if (c->send.len == 0) mg_iobuf_resize(&c->send, 0);
3131 mg_call(c, MG_EV_WRITE, &n);
3132 // if (c->send.len == 0) mg_iobuf_resize(&c->send, 0);
3136 static void close_conn(struct mg_connection *c) {
3137 mg_resolve_cancel(c); // Close any pending DNS query
3138 LIST_DELETE(struct mg_connection, &c->mgr->conns, c);
3139 if (c == c->mgr->dns4.c) c->mgr->dns4.c = NULL;
3140 if (c == c->mgr->dns6.c) c->mgr->dns6.c = NULL;
3141 // Order of operations is important. `MG_EV_CLOSE` event must be fired
3142 // before we deallocate received data, see #1331
3143 mg_call(c, MG_EV_CLOSE, NULL);
3144 LOG(LL_DEBUG, ("%lu closed", c->id));
3145 if (FD(c) != INVALID_SOCKET) {
3147 #if MG_ARCH == MG_ARCH_FREERTOS_TCP
3148 FreeRTOS_FD_CLR(c->fd, c->mgr->ss, eSELECT_ALL);
3150 c->fd = S2PTR(INVALID_SOCKET);
3153 mg_iobuf_free(&c->recv);
3154 mg_iobuf_free(&c->send);
3155 memset(c, 0, sizeof(*c));
3159 static void setsockopts(struct mg_connection *c) {
3160 #if MG_ARCH == MG_ARCH_FREERTOS_TCP || MG_ARCH == MG_ARCH_AZURERTOS
3164 #if !defined(SOL_TCP)
3165 #define SOL_TCP IPPROTO_TCP
3167 setsockopt(FD(c), SOL_TCP, TCP_NODELAY, (char *) &on, sizeof(on));
3168 #if defined(TCP_QUICKACK)
3169 setsockopt(FD(c), SOL_TCP, TCP_QUICKACK, (char *) &on, sizeof(on));
3171 setsockopt(FD(c), SOL_SOCKET, SO_KEEPALIVE, (char *) &on, sizeof(on));
3172 #if (defined(ESP32) && ESP32) || (defined(ESP8266) && ESP8266) || \
3175 setsockopt(FD(c), IPPROTO_TCP, TCP_KEEPIDLE, &idle, sizeof(idle));
3177 #if !defined(_WIN32) && !defined(__QNX__)
3179 int cnt = 3, intvl = 20;
3180 setsockopt(FD(c), IPPROTO_TCP, TCP_KEEPCNT, &cnt, sizeof(cnt));
3181 setsockopt(FD(c), IPPROTO_TCP, TCP_KEEPINTVL, &intvl, sizeof(intvl));
3187 void mg_connect_resolved(struct mg_connection *c) {
3189 int type = c->is_udp ? SOCK_DGRAM : SOCK_STREAM;
3190 int rc, af = c->peer.is_ip6 ? AF_INET6 : AF_INET;
3191 mg_straddr(c, buf, sizeof(buf));
3192 c->fd = S2PTR(socket(af, type, 0));
3193 if (FD(c) == INVALID_SOCKET) {
3194 mg_error(c, "socket(): %d", MG_SOCK_ERRNO);
3197 socklen_t slen = tousa(&c->peer, &usa);
3198 if (c->is_udp == 0) mg_set_non_blocking_mode(FD(c));
3199 if (c->is_udp == 0) setsockopts(c);
3200 mg_call(c, MG_EV_RESOLVE, NULL);
3201 if ((rc = connect(FD(c), &usa.sa, slen)) == 0) {
3202 mg_call(c, MG_EV_CONNECT, NULL);
3203 } else if (mg_sock_would_block()) {
3204 c->is_connecting = 1;
3206 mg_error(c, "connect: %d", MG_SOCK_ERRNO);
3211 struct mg_connection *mg_connect(struct mg_mgr *mgr, const char *url,
3212 mg_event_handler_t fn, void *fn_data) {
3213 struct mg_connection *c = NULL;
3214 if ((c = alloc_conn(mgr, 1, INVALID_SOCKET)) == NULL) {
3215 LOG(LL_ERROR, ("OOM"));
3217 struct mg_str host = mg_url_host(url);
3218 LIST_ADD_HEAD(struct mg_connection, &mgr->conns, c);
3219 c->is_udp = (strncmp(url, "udp:", 4) == 0);
3220 c->peer.port = mg_htons(mg_url_port(url));
3222 c->fn_data = fn_data;
3223 LOG(LL_DEBUG, ("%lu -> %s", c->id, url));
3224 mg_call(c, MG_EV_OPEN, NULL);
3225 mg_resolve(c, &host, mgr->dnstimeout);
3230 static void accept_conn(struct mg_mgr *mgr, struct mg_connection *lsn) {
3231 struct mg_connection *c = NULL;
3233 socklen_t sa_len = sizeof(usa);
3234 SOCKET fd = accept(FD(lsn), &usa.sa, &sa_len);
3235 if (fd == INVALID_SOCKET) {
3236 #if MG_ARCH == MG_ARCH_AZURERTOS
3237 // AzureRTOS, in non-block socket mode can mark listening socket readable
3238 // even it is not. See comment for 'select' func implementation in nx_bsd.c
3239 // That's not an error, just should try later
3240 if (MG_SOCK_ERRNO != EAGAIN)
3242 LOG(LL_ERROR, ("%lu accept failed, errno %d", lsn->id, MG_SOCK_ERRNO));
3243 #if (!defined(_WIN32) && (MG_ARCH != MG_ARCH_FREERTOS_TCP))
3244 } else if ((long) fd >= FD_SETSIZE) {
3245 LOG(LL_ERROR, ("%ld > %ld", (long) fd, (long) FD_SETSIZE));
3248 } else if ((c = alloc_conn(mgr, 0, fd)) == NULL) {
3249 LOG(LL_ERROR, ("%lu OOM", lsn->id));
3253 tomgaddr(&usa, &c->peer, sa_len != sizeof(usa.sin));
3254 mg_straddr(c, buf, sizeof(buf));
3255 LOG(LL_DEBUG, ("%lu accepted %s", c->id, buf));
3256 mg_set_non_blocking_mode(FD(c));
3258 LIST_ADD_HEAD(struct mg_connection, &mgr->conns, c);
3260 c->is_hexdumping = lsn->is_hexdumping;
3262 c->pfn_data = lsn->pfn_data;
3264 c->fn_data = lsn->fn_data;
3265 mg_call(c, MG_EV_OPEN, NULL);
3266 mg_call(c, MG_EV_ACCEPT, NULL);
3270 static bool mg_socketpair(SOCKET sp[2], union usa usa[2]) {
3271 socklen_t n = sizeof(usa[0].sin);
3272 bool result = false;
3274 (void) memset(&usa[0], 0, sizeof(usa[0]));
3275 usa[0].sin.sin_family = AF_INET;
3276 *(uint32_t *) &usa->sin.sin_addr = mg_htonl(0x7f000001); // 127.0.0.1
3279 if ((sp[0] = socket(AF_INET, SOCK_DGRAM, 0)) != INVALID_SOCKET &&
3280 (sp[1] = socket(AF_INET, SOCK_DGRAM, 0)) != INVALID_SOCKET &&
3281 bind(sp[0], &usa[0].sa, n) == 0 && bind(sp[1], &usa[1].sa, n) == 0 &&
3282 getsockname(sp[0], &usa[0].sa, &n) == 0 &&
3283 getsockname(sp[1], &usa[1].sa, &n) == 0 &&
3284 connect(sp[0], &usa[1].sa, n) == 0 &&
3285 connect(sp[1], &usa[0].sa, n) == 0) {
3286 mg_set_non_blocking_mode(sp[1]); // Set close-on-exec
3289 if (sp[0] != INVALID_SOCKET) closesocket(sp[0]);
3290 if (sp[1] != INVALID_SOCKET) closesocket(sp[1]);
3291 sp[0] = sp[1] = INVALID_SOCKET;
3297 void mg_mgr_wakeup(struct mg_connection *c) {
3298 LOG(LL_INFO, ("skt: %p", c->pfn_data));
3299 send((SOCKET) (size_t) c->pfn_data, "\x01", 1, MSG_NONBLOCKING);
3302 static void pf1(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
3303 if (ev == MG_EV_READ) mg_iobuf_free(&c->recv);
3304 (void) ev_data, (void) fn_data;
3307 struct mg_connection *mg_mkpipe(struct mg_mgr *mgr, mg_event_handler_t fn,
3310 SOCKET sp[2] = {INVALID_SOCKET, INVALID_SOCKET};
3311 struct mg_connection *c = NULL;
3312 if (!mg_socketpair(sp, usa)) {
3313 LOG(LL_ERROR, ("Cannot create socket pair"));
3314 } else if ((c = alloc_conn(mgr, false, sp[1])) == NULL) {
3317 LOG(LL_ERROR, ("OOM"));
3319 LOG(LL_INFO, ("pipe %lu", (unsigned long) sp[0]));
3320 tomgaddr(&usa[0], &c->peer, false);
3323 c->pfn_data = (void *) (size_t) sp[0];
3325 c->fn_data = fn_data;
3326 mg_call(c, MG_EV_OPEN, NULL);
3327 LIST_ADD_HEAD(struct mg_connection, &mgr->conns, c);
3332 struct mg_connection *mg_listen(struct mg_mgr *mgr, const char *url,
3333 mg_event_handler_t fn, void *fn_data) {
3334 struct mg_connection *c = NULL;
3335 bool is_udp = strncmp(url, "udp:", 4) == 0;
3336 struct mg_addr addr;
3337 SOCKET fd = mg_open_listener(url, &addr);
3338 if (fd == INVALID_SOCKET) {
3339 LOG(LL_ERROR, ("Failed: %s, errno %d", url, MG_SOCK_ERRNO));
3340 } else if ((c = alloc_conn(mgr, 0, fd)) == NULL) {
3341 LOG(LL_ERROR, ("OOM %s", url));
3344 memcpy(&c->peer, &addr, sizeof(struct mg_addr));
3346 c->is_listening = 1;
3348 LIST_ADD_HEAD(struct mg_connection, &mgr->conns, c);
3350 c->fn_data = fn_data;
3351 mg_call(c, MG_EV_OPEN, NULL);
3353 ("%lu accepting on %s (port %u)", c->id, url, mg_ntohs(c->peer.port)));
3358 static void mg_iotest(struct mg_mgr *mgr, int ms) {
3359 #if MG_ARCH == MG_ARCH_FREERTOS_TCP
3360 struct mg_connection *c;
3361 for (c = mgr->conns; c != NULL; c = c->next) {
3362 if (c->is_closing || c->is_resolving || FD(c) == INVALID_SOCKET) continue;
3363 FreeRTOS_FD_SET(c->fd, mgr->ss, eSELECT_READ | eSELECT_EXCEPT);
3364 if (c->is_connecting || (c->send.len > 0 && c->is_tls_hs == 0))
3365 FreeRTOS_FD_SET(c->fd, mgr->ss, eSELECT_WRITE);
3367 FreeRTOS_select(mgr->ss, pdMS_TO_TICKS(ms));
3368 for (c = mgr->conns; c != NULL; c = c->next) {
3369 EventBits_t bits = FreeRTOS_FD_ISSET(c->fd, mgr->ss);
3370 c->is_readable = bits & (eSELECT_READ | eSELECT_EXCEPT) ? 1 : 0;
3371 c->is_writable = bits & eSELECT_WRITE ? 1 : 0;
3372 FreeRTOS_FD_CLR(c->fd, mgr->ss,
3373 eSELECT_READ | eSELECT_EXCEPT | eSELECT_WRITE);
3376 struct timeval tv = {ms / 1000, (ms % 1000) * 1000};
3377 struct mg_connection *c;
3385 for (c = mgr->conns; c != NULL; c = c->next) {
3386 if (c->is_closing || c->is_resolving || FD(c) == INVALID_SOCKET) continue;
3387 FD_SET(FD(c), &rset);
3388 if (FD(c) > maxfd) maxfd = FD(c);
3389 if (c->is_connecting || (c->send.len > 0 && c->is_tls_hs == 0))
3390 FD_SET(FD(c), &wset);
3393 if ((rc = select((int) maxfd + 1, &rset, &wset, NULL, &tv)) < 0) {
3394 LOG(LL_DEBUG, ("select: %d %d", rc, MG_SOCK_ERRNO));
3399 for (c = mgr->conns; c != NULL; c = c->next) {
3400 // TLS might have stuff buffered, so dig everything
3401 c->is_readable = FD(c) != INVALID_SOCKET && FD_ISSET(FD(c), &rset);
3402 c->is_writable = FD(c) != INVALID_SOCKET && FD_ISSET(FD(c), &wset);
3407 static void connect_conn(struct mg_connection *c) {
3409 #if MG_ARCH != MG_ARCH_FREERTOS_TCP
3410 socklen_t len = sizeof(rc);
3411 if (getsockopt(FD(c), SOL_SOCKET, SO_ERROR, (char *) &rc, &len)) rc = 1;
3413 if (rc == EAGAIN || rc == EWOULDBLOCK) rc = 0;
3414 c->is_connecting = 0;
3417 mg_error(c, "error connecting to %s", mg_straddr(c, buf, sizeof(buf)));
3419 if (c->is_tls_hs) mg_tls_handshake(c);
3420 mg_call(c, MG_EV_CONNECT, NULL);
3424 void mg_mgr_poll(struct mg_mgr *mgr, int ms) {
3425 struct mg_connection *c, *tmp;
3432 for (c = mgr->conns; c != NULL; c = tmp) {
3434 mg_call(c, MG_EV_POLL, &now);
3435 LOG(LL_VERBOSE_DEBUG,
3436 ("%lu %c%c %c%c%c%c%c", c->id, c->is_readable ? 'r' : '-',
3437 c->is_writable ? 'w' : '-', c->is_tls ? 'T' : 't',
3438 c->is_connecting ? 'C' : 'c', c->is_tls_hs ? 'H' : 'h',
3439 c->is_resolving ? 'R' : 'r', c->is_closing ? 'C' : 'c'));
3440 if (c->is_resolving || c->is_closing) {
3442 } else if (c->is_listening && c->is_udp == 0) {
3443 if (c->is_readable) accept_conn(mgr, c);
3444 } else if (c->is_connecting) {
3445 if (c->is_readable || c->is_writable) connect_conn(c);
3446 } else if (c->is_tls_hs) {
3447 if ((c->is_readable || c->is_writable)) mg_tls_handshake(c);
3449 if (c->is_readable) read_conn(c);
3450 if (c->is_writable) write_conn(c);
3451 while (c->is_tls && read_conn(c) > 0) (void) 0; // Read buffered TLS data
3454 if (c->is_draining && c->send.len == 0) c->is_closing = 1;
3455 if (c->is_closing) close_conn(c);
3460 #ifdef MG_ENABLE_LINES
3467 #ifndef MG_MAX_SSI_DEPTH
3468 #define MG_MAX_SSI_DEPTH 5
3472 static char *mg_ssi(const char *path, const char *root, int depth) {
3473 struct mg_iobuf b = {NULL, 0, 0};
3474 FILE *fp = fopen(path, "rb");
3476 char buf[BUFSIZ], arg[sizeof(buf)];
3478 size_t len = 0, align = MG_IO_SIZE;
3479 while ((ch = fgetc(fp)) != EOF) {
3480 if (intag && ch == '>' && buf[len - 1] == '-' && buf[len - 2] == '-') {
3481 buf[len++] = (char) (ch & 0xff);
3482 if (sscanf(buf, "<!--#include file=\"%[^\"]", arg)) {
3483 char tmp[MG_PATH_MAX + BUFSIZ + 10],
3484 *p = (char *) path + strlen(path), *data;
3485 while (p > path && p[-1] != MG_DIRSEP && p[-1] != '/') p--;
3486 snprintf(tmp, sizeof(tmp), "%.*s%s", (int) (p - path), path, arg);
3487 if (depth < MG_MAX_SSI_DEPTH &&
3488 (data = mg_ssi(tmp, root, depth + 1)) != NULL) {
3489 mg_iobuf_add(&b, b.len, data, strlen(data), align);
3492 LOG(LL_ERROR, ("%s: file=%s error or too deep", path, arg));
3494 } else if (sscanf(buf, "<!--#include virtual=\"%[^\"]", arg)) {
3495 char tmp[MG_PATH_MAX + BUFSIZ + 10], *data;
3496 snprintf(tmp, sizeof(tmp), "%s%s", root, arg);
3497 if (depth < MG_MAX_SSI_DEPTH &&
3498 (data = mg_ssi(tmp, root, depth + 1)) != NULL) {
3499 mg_iobuf_add(&b, b.len, data, strlen(data), align);
3502 LOG(LL_ERROR, ("%s: virtual=%s error or too deep", path, arg));
3506 LOG(LL_INFO, ("Unknown SSI tag: %.*s", (int) len, buf));
3507 mg_iobuf_add(&b, b.len, buf, len, align);
3511 } else if (ch == '<') {
3513 if (len > 0) mg_iobuf_add(&b, b.len, buf, len, align);
3515 buf[len++] = (char) (ch & 0xff);
3517 if (len == 5 && strncmp(buf, "<!--#", 5) != 0) {
3519 } else if (len >= sizeof(buf) - 2) {
3520 LOG(LL_ERROR, ("%s: SSI tag is too large", path));
3523 buf[len++] = (char) (ch & 0xff);
3525 buf[len++] = (char) (ch & 0xff);
3526 if (len >= sizeof(buf)) {
3527 mg_iobuf_add(&b, b.len, buf, len, align);
3532 if (len > 0) mg_iobuf_add(&b, b.len, buf, len, align);
3533 if (b.len > 0) mg_iobuf_add(&b, b.len, "", 1, align); // nul-terminate
3538 return (char *) b.buf;
3541 void mg_http_serve_ssi(struct mg_connection *c, const char *root,
3542 const char *fullpath) {
3543 const char *headers = "Content-Type: text/html; charset=utf-8\r\n";
3544 char *data = mg_ssi(fullpath, root, 0);
3545 mg_http_reply(c, 200, headers, "%s", data == NULL ? "" : data);
3549 void mg_http_serve_ssi(struct mg_connection *c, const char *root,
3550 const char *fullpath) {
3551 mg_http_reply(c, 501, NULL, "SSI not enabled");
3552 (void) root, (void) fullpath;
3556 #ifdef MG_ENABLE_LINES
3562 struct mg_str mg_str_s(const char *s) {
3563 struct mg_str str = {s, s == NULL ? 0 : strlen(s)};
3567 struct mg_str mg_str_n(const char *s, size_t n) {
3568 struct mg_str str = {s, n};
3572 int mg_lower(const char *s) {
3573 return tolower(*(const unsigned char *) s);
3576 int mg_ncasecmp(const char *s1, const char *s2, size_t len) {
3579 diff = mg_lower(s1++) - mg_lower(s2++);
3580 } while (diff == 0 && s1[-1] != '\0' && --len > 0);
3584 int mg_casecmp(const char *s1, const char *s2) {
3585 return mg_ncasecmp(s1, s2, (size_t) ~0);
3588 int mg_vcmp(const struct mg_str *s1, const char *s2) {
3589 size_t n2 = strlen(s2), n1 = s1->len;
3590 int r = strncmp(s1->ptr, s2, (n1 < n2) ? n1 : n2);
3591 if (r == 0) return (int) (n1 - n2);
3595 int mg_vcasecmp(const struct mg_str *str1, const char *str2) {
3596 size_t n2 = strlen(str2), n1 = str1->len;
3597 int r = mg_ncasecmp(str1->ptr, str2, (n1 < n2) ? n1 : n2);
3598 if (r == 0) return (int) (n1 - n2);
3602 struct mg_str mg_strdup(const struct mg_str s) {
3603 struct mg_str r = {NULL, 0};
3604 if (s.len > 0 && s.ptr != NULL) {
3605 char *sc = (char *) calloc(1, s.len + 1);
3607 memcpy(sc, s.ptr, s.len);
3616 int mg_strcmp(const struct mg_str str1, const struct mg_str str2) {
3618 while (i < str1.len && i < str2.len) {
3619 int c1 = str1.ptr[i];
3620 int c2 = str2.ptr[i];
3621 if (c1 < c2) return -1;
3622 if (c1 > c2) return 1;
3625 if (i < str1.len) return 1;
3626 if (i < str2.len) return -1;
3630 const char *mg_strstr(const struct mg_str haystack,
3631 const struct mg_str needle) {
3633 if (needle.len > haystack.len) return NULL;
3634 for (i = 0; i <= haystack.len - needle.len; i++) {
3635 if (memcmp(haystack.ptr + i, needle.ptr, needle.len) == 0) {
3636 return haystack.ptr + i;
3642 struct mg_str mg_strstrip(struct mg_str s) {
3643 while (s.len > 0 && isspace((int) *s.ptr)) s.ptr++, s.len--;
3644 while (s.len > 0 && isspace((int) *(s.ptr + s.len - 1))) s.len--;
3648 #ifdef MG_ENABLE_LINES
3649 #line 1 "src/timer.c"
3651 // Copyright (c) Cesanta Software Limited
3652 // All rights reserved
3657 struct mg_timer *g_timers;
3659 void mg_timer_init(struct mg_timer *t, unsigned long ms, unsigned flags,
3660 void (*fn)(void *), void *arg) {
3661 struct mg_timer tmp = {ms, 0UL, flags, fn, arg, g_timers};
3664 if (flags & MG_TIMER_RUN_NOW) fn(arg);
3667 void mg_timer_free(struct mg_timer *t) {
3668 struct mg_timer **head = &g_timers;
3669 while (*head && *head != t) head = &(*head)->next;
3670 if (*head) *head = t->next;
3673 void mg_timer_poll(unsigned long now_ms) {
3674 // If time goes back (wrapped around), reset timers
3675 struct mg_timer *t, *tmp;
3676 static unsigned long oldnow; // Timestamp in a previous invocation
3677 if (oldnow > now_ms) { // If it is wrapped, reset timers
3678 for (t = g_timers; t != NULL; t = t->next) t->expire = 0;
3682 for (t = g_timers; t != NULL; t = tmp) {
3684 if (t->expire == 0) t->expire = now_ms + t->period_ms;
3685 if (t->expire > now_ms) continue;
3687 // Try to tick timers with the given period as accurate as possible,
3688 // even if this polling function is called with some random period.
3689 t->expire = now_ms - t->expire > (unsigned long) t->period_ms
3690 ? now_ms + t->period_ms
3691 : t->expire + t->period_ms;
3692 if (!(t->flags & MG_TIMER_REPEAT)) mg_timer_free(t);
3696 #ifdef MG_ENABLE_LINES
3697 #line 1 "src/tls_dummy.c"
3701 #if !MG_ENABLE_MBEDTLS && !MG_ENABLE_OPENSSL && !MG_ENABLE_CUSTOM_TLS
3702 void mg_tls_init(struct mg_connection *c, struct mg_tls_opts *opts) {
3704 mg_error(c, "TLS is not enabled");
3706 void mg_tls_handshake(struct mg_connection *c) {
3709 void mg_tls_free(struct mg_connection *c) {
3712 long mg_tls_recv(struct mg_connection *c, void *buf, size_t len) {
3713 return c == NULL || buf == NULL || len == 0 ? 0 : -1;
3715 long mg_tls_send(struct mg_connection *c, const void *buf, size_t len) {
3716 return c == NULL || buf == NULL || len == 0 ? 0 : -1;
3720 #ifdef MG_ENABLE_LINES
3721 #line 1 "src/tls_mbed.c"
3725 #if MG_ENABLE_MBEDTLS
3726 void mg_tls_handshake(struct mg_connection *c) {
3727 struct mg_tls *tls = (struct mg_tls *) c->tls;
3729 mbedtls_ssl_set_bio(&tls->ssl, &c->fd, mbedtls_net_send, mbedtls_net_recv, 0);
3730 rc = mbedtls_ssl_handshake(&tls->ssl);
3731 if (rc == 0) { // Success
3732 LOG(LL_DEBUG, ("%lu success", c->id));
3734 } else if (rc == MBEDTLS_ERR_SSL_WANT_READ ||
3735 rc == MBEDTLS_ERR_SSL_WANT_WRITE) { // Still pending
3736 LOG(LL_VERBOSE_DEBUG, ("%lu pending, %d%d %d (-%#x)", c->id,
3737 c->is_connecting, c->is_tls_hs, rc, -rc));
3739 mg_error(c, "TLS handshake: -%#x", -rc); // Error
3743 static int mbed_rng(void *ctx, unsigned char *buf, size_t len) {
3744 mg_random(buf, len);
3749 static void debug_cb(void *c, int lev, const char *s, int n, const char *s2) {
3750 n = (int) strlen(s2) - 1;
3751 LOG(LL_VERBOSE_DEBUG, ("%p %.*s", ((struct mg_connection *) c)->fd, n, s2));
3757 #if defined(MBEDTLS_VERSION_NUMBER) && MBEDTLS_VERSION_NUMBER >= 0x03000000
3758 static int rng_get(void *p_rng, unsigned char *buf, size_t len) {
3760 mg_random(buf, len);
3765 void mg_tls_init(struct mg_connection *c, struct mg_tls_opts *opts) {
3766 struct mg_tls *tls = (struct mg_tls *) calloc(1, sizeof(*tls));
3768 const char *ca = opts->ca == NULL ? "-"
3769 : opts->ca[0] == '-' ? "(emb)"
3771 const char *crl = opts->crl == NULL ? "-"
3772 : opts->crl[0] == '-' ? "(emb)"
3774 const char *cert = opts->cert == NULL ? "-"
3775 : opts->cert[0] == '-' ? "(emb)"
3777 const char *certkey = opts->certkey == NULL ? "-"
3778 : opts->certkey[0] == '-' ? "(emb)"
3781 mg_error(c, "TLS OOM");
3784 LOG(LL_DEBUG, ("%lu Setting TLS, CA: %s, CRL: %s, cert: %s, key: %s", c->id,
3785 ca, crl, cert, certkey));
3786 mbedtls_ssl_init(&tls->ssl);
3787 mbedtls_ssl_config_init(&tls->conf);
3788 mbedtls_x509_crt_init(&tls->ca);
3789 mbedtls_x509_crl_init(&tls->crl);
3790 mbedtls_x509_crt_init(&tls->cert);
3791 mbedtls_pk_init(&tls->pk);
3792 mbedtls_ssl_conf_dbg(&tls->conf, debug_cb, c);
3793 //#if !defined(ESP_PLATFORM)
3794 // mbedtls_debug_set_threshold(5);
3796 if ((rc = mbedtls_ssl_config_defaults(
3798 c->is_client ? MBEDTLS_SSL_IS_CLIENT : MBEDTLS_SSL_IS_SERVER,
3799 MBEDTLS_SSL_TRANSPORT_STREAM, MBEDTLS_SSL_PRESET_DEFAULT)) != 0) {
3800 mg_error(c, "tls defaults %#x", -rc);
3803 mbedtls_ssl_conf_rng(&tls->conf, mbed_rng, c);
3804 if (opts->ca == NULL || strcmp(opts->ca, "*") == 0) {
3805 mbedtls_ssl_conf_authmode(&tls->conf, MBEDTLS_SSL_VERIFY_NONE);
3807 if (opts->ca != NULL && opts->ca[0] != '\0') {
3808 if (opts->crl != NULL && opts->crl[0] != '\0') {
3809 rc = opts->crl[0] == '-'
3810 ? mbedtls_x509_crl_parse(&tls->crl, (uint8_t *) opts->crl,
3811 strlen(opts->crl) + 1)
3812 : mbedtls_x509_crl_parse_file(&tls->crl, opts->crl);
3814 mg_error(c, "parse(%s) err %#x", crl, -rc);
3818 #if defined(MBEDTLS_X509_CA_CHAIN_ON_DISK)
3819 tls->cafile = strdup(opts->ca);
3820 rc = mbedtls_ssl_conf_ca_chain_file(&tls->conf, tls->cafile, &tls->crl);
3822 mg_error(c, "parse on-disk chain(%s) err %#x", ca, -rc);
3826 rc = opts->ca[0] == '-'
3827 ? mbedtls_x509_crt_parse(&tls->ca, (uint8_t *) opts->ca,
3828 strlen(opts->ca) + 1)
3829 : mbedtls_x509_crt_parse_file(&tls->ca, opts->ca);
3831 mg_error(c, "parse(%s) err %#x", ca, -rc);
3834 mbedtls_ssl_conf_ca_chain(&tls->conf, &tls->ca, &tls->crl);
3836 if (opts->srvname.len > 0) {
3837 char mem[128], *buf = mem;
3838 mg_asprintf(&buf, sizeof(mem), "%.*s", (int) opts->srvname.len,
3840 mbedtls_ssl_set_hostname(&tls->ssl, buf);
3841 if (buf != mem) free(buf);
3843 mbedtls_ssl_conf_authmode(&tls->conf, MBEDTLS_SSL_VERIFY_REQUIRED);
3845 if (opts->cert != NULL && opts->cert[0] != '\0') {
3846 const char *key = opts->certkey;
3851 rc = opts->cert[0] == '-'
3852 ? mbedtls_x509_crt_parse(&tls->cert, (uint8_t *) opts->cert,
3853 strlen(opts->cert) + 1)
3854 : mbedtls_x509_crt_parse_file(&tls->cert, opts->cert);
3856 mg_error(c, "parse(%s) err %#x", cert, -rc);
3859 rc = key[0] == '-' ? mbedtls_pk_parse_key(&tls->pk, (uint8_t *) key,
3860 strlen(key) + 1, NULL, 0 RNG)
3861 : mbedtls_pk_parse_keyfile(&tls->pk, key, NULL RNG);
3863 mg_error(c, "tls key(%s) %#x", certkey, -rc);
3866 rc = mbedtls_ssl_conf_own_cert(&tls->conf, &tls->cert, &tls->pk);
3868 mg_error(c, "own cert %#x", -rc);
3872 if ((rc = mbedtls_ssl_setup(&tls->ssl, &tls->conf)) != 0) {
3873 mg_error(c, "setup err %#x", -rc);
3879 if (c->is_client && c->is_resolving == 0 && c->is_connecting == 0) {
3880 mg_tls_handshake(c);
3888 long mg_tls_recv(struct mg_connection *c, void *buf, size_t len) {
3889 struct mg_tls *tls = (struct mg_tls *) c->tls;
3890 long n = mbedtls_ssl_read(&tls->ssl, (unsigned char *) buf, len);
3891 return n == 0 ? -1 : n == MBEDTLS_ERR_SSL_WANT_READ ? 0 : n;
3894 long mg_tls_send(struct mg_connection *c, const void *buf, size_t len) {
3895 struct mg_tls *tls = (struct mg_tls *) c->tls;
3896 long n = mbedtls_ssl_write(&tls->ssl, (unsigned char *) buf, len);
3897 return n == 0 ? -1 : n == MBEDTLS_ERR_SSL_WANT_WRITE ? 0 : n;
3900 void mg_tls_free(struct mg_connection *c) {
3901 struct mg_tls *tls = (struct mg_tls *) c->tls;
3902 if (tls == NULL) return;
3904 mbedtls_ssl_free(&tls->ssl);
3905 mbedtls_pk_free(&tls->pk);
3906 mbedtls_x509_crt_free(&tls->ca);
3907 mbedtls_x509_crl_free(&tls->crl);
3908 mbedtls_x509_crt_free(&tls->cert);
3909 mbedtls_ssl_config_free(&tls->conf);
3915 #ifdef MG_ENABLE_LINES
3916 #line 1 "src/tls_openssl.c"
3920 #if MG_ENABLE_OPENSSL
3921 static int mg_tls_err(struct mg_tls *tls, int res) {
3922 int err = SSL_get_error(tls->ssl, res);
3923 // We've just fetched the last error from the queue.
3924 // Now we need to clear the error queue. If we do not, then the following
3925 // can happen (actually reported):
3926 // - A new connection is accept()-ed with cert error (e.g. self-signed cert)
3927 // - Since all accept()-ed connections share listener's context,
3928 // - *ALL* SSL accepted connection report read error on the next poll cycle.
3929 // Thus a single errored connection can close all the rest, unrelated ones.
3930 // Clearing the error keeps the shared SSL_CTX in an OK state.
3932 if (err != 0) ERR_print_errors_fp(stderr);
3934 if (err == SSL_ERROR_WANT_READ) return 0;
3935 if (err == SSL_ERROR_WANT_WRITE) return 0;
3939 void mg_tls_init(struct mg_connection *c, struct mg_tls_opts *opts) {
3940 struct mg_tls *tls = (struct mg_tls *) calloc(1, sizeof(*tls));
3941 const char *id = "mongoose";
3942 static unsigned char s_initialised = 0;
3946 mg_error(c, "TLS OOM");
3950 if (!s_initialised) {
3954 LOG(LL_DEBUG, ("%lu Setting TLS, CA: %s, cert: %s, key: %s", c->id,
3955 opts->ca == NULL ? "null" : opts->ca,
3956 opts->cert == NULL ? "null" : opts->cert,
3957 opts->certkey == NULL ? "null" : opts->certkey));
3958 tls->ctx = c->is_client ? SSL_CTX_new(SSLv23_client_method())
3959 : SSL_CTX_new(SSLv23_server_method());
3960 if ((tls->ssl = SSL_new(tls->ctx)) == NULL) {
3961 mg_error(c, "SSL_new");
3964 SSL_set_session_id_context(tls->ssl, (const uint8_t *) id,
3965 (unsigned) strlen(id));
3966 // Disable deprecated protocols
3967 SSL_set_options(tls->ssl, SSL_OP_NO_SSLv2);
3968 SSL_set_options(tls->ssl, SSL_OP_NO_SSLv3);
3969 SSL_set_options(tls->ssl, SSL_OP_NO_TLSv1);
3970 SSL_set_options(tls->ssl, SSL_OP_NO_TLSv1_1);
3971 #ifdef MG_ENABLE_OPENSSL_NO_COMPRESSION
3972 SSL_set_options(tls->ssl, SSL_OP_NO_COMPRESSION);
3974 #ifdef MG_ENABLE_OPENSSL_CIPHER_SERVER_PREFERENCE
3975 SSL_set_options(tls->ssl, SSL_OP_CIPHER_SERVER_PREFERENCE);
3978 if (opts->ca != NULL && opts->ca[0] != '\0') {
3979 SSL_set_verify(tls->ssl, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT,
3981 if ((rc = SSL_CTX_load_verify_locations(tls->ctx, opts->ca, NULL)) != 1) {
3982 mg_error(c, "parse(%s): err %d", opts->ca, mg_tls_err(tls, rc));
3986 if (opts->cert != NULL && opts->cert[0] != '\0') {
3987 const char *key = opts->certkey;
3988 if (key == NULL) key = opts->cert;
3989 if ((rc = SSL_use_certificate_file(tls->ssl, opts->cert, 1)) != 1) {
3990 mg_error(c, "Invalid SSL cert, err %d", mg_tls_err(tls, rc));
3992 } else if ((rc = SSL_use_PrivateKey_file(tls->ssl, key, 1)) != 1) {
3993 mg_error(c, "Invalid SSL key, err %d", mg_tls_err(tls, rc));
3995 #if OPENSSL_VERSION_NUMBER > 0x10100000L
3996 } else if ((rc = SSL_use_certificate_chain_file(tls->ssl, opts->cert)) !=
3998 mg_error(c, "Invalid CA, err %d", mg_tls_err(tls, rc));
4002 SSL_set_mode(tls->ssl, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
4003 #if OPENSSL_VERSION_NUMBER > 0x10002000L
4004 SSL_set_ecdh_auto(tls->ssl, 1);
4008 if (opts->ciphers != NULL) SSL_set_cipher_list(tls->ssl, opts->ciphers);
4009 if (opts->srvname.len > 0) {
4010 char mem[128], *buf = mem;
4011 mg_asprintf(&buf, sizeof(mem), "%.*s", (int) opts->srvname.len,
4013 SSL_set_tlsext_host_name(tls->ssl, buf);
4014 if (buf != mem) free(buf);
4019 if (c->is_client && c->is_resolving == 0 && c->is_connecting == 0) {
4020 mg_tls_handshake(c);
4022 c->is_hexdumping = 1;
4023 LOG(LL_DEBUG, ("%lu SSL %s OK", c->id, c->is_accepted ? "accept" : "client"));
4030 void mg_tls_handshake(struct mg_connection *c) {
4031 struct mg_tls *tls = (struct mg_tls *) c->tls;
4033 SSL_set_fd(tls->ssl, (int) (size_t) c->fd);
4034 rc = c->is_client ? SSL_connect(tls->ssl) : SSL_accept(tls->ssl);
4036 LOG(LL_DEBUG, ("%lu success", c->id));
4039 int code = mg_tls_err(tls, rc);
4040 if (code != 0) mg_error(c, "tls hs: rc %d, err %d", rc, code);
4044 void mg_tls_free(struct mg_connection *c) {
4045 struct mg_tls *tls = (struct mg_tls *) c->tls;
4046 if (tls == NULL) return;
4048 SSL_CTX_free(tls->ctx);
4053 long mg_tls_recv(struct mg_connection *c, void *buf, size_t len) {
4054 struct mg_tls *tls = (struct mg_tls *) c->tls;
4055 int n = SSL_read(tls->ssl, buf, (int) len);
4056 return n == 0 ? -1 : n < 0 && mg_tls_err(tls, n) == 0 ? 0 : n;
4059 long mg_tls_send(struct mg_connection *c, const void *buf, size_t len) {
4060 struct mg_tls *tls = (struct mg_tls *) c->tls;
4061 int n = SSL_write(tls->ssl, buf, (int) len);
4062 return n == 0 ? -1 : n < 0 && mg_tls_err(tls, n) == 0 ? 0 : n;
4066 #ifdef MG_ENABLE_LINES
4073 size_t key, user, pass, host, port, uri, end;
4076 int mg_url_is_ssl(const char *url) {
4077 return strncmp(url, "wss:", 4) == 0 || strncmp(url, "https:", 6) == 0 ||
4078 strncmp(url, "mqtts:", 6) == 0 || strncmp(url, "ssl:", 4) == 0 ||
4079 strncmp(url, "tls:", 4) == 0;
4082 static struct url urlparse(const char *url) {
4085 memset(&u, 0, sizeof(u));
4086 for (i = 0; url[i] != '\0'; i++) {
4087 if (i > 0 && u.host == 0 && url[i - 1] == '/' && url[i] == '/') {
4090 } else if (url[i] == ']') {
4091 u.port = 0; // IPv6 URLs, like http://[::1]/bar
4092 } else if (url[i] == ':' && u.port == 0 && u.uri == 0) {
4094 } else if (url[i] == '@' && u.user == 0 && u.pass == 0) {
4099 } else if (u.host && u.uri == 0 && url[i] == '/') {
4105 printf("[%s] %d %d %d %d %d\n", url, u.user, u.pass, u.host, u.port, u.uri);
4110 struct mg_str mg_url_host(const char *url) {
4111 struct url u = urlparse(url);
4112 size_t n = u.port ? u.port - u.host - 1
4113 : u.uri ? u.uri - u.host
4115 struct mg_str s = mg_str_n(url + u.host, n);
4119 const char *mg_url_uri(const char *url) {
4120 struct url u = urlparse(url);
4121 return u.uri ? url + u.uri : "/";
4124 unsigned short mg_url_port(const char *url) {
4125 struct url u = urlparse(url);
4126 unsigned short port = 0;
4127 if (memcmp(url, "http:", 5) == 0 || memcmp(url, "ws:", 3) == 0) port = 80;
4128 if (memcmp(url, "wss:", 4) == 0 || memcmp(url, "https:", 6) == 0) port = 443;
4129 if (memcmp(url, "mqtt:", 5) == 0) port = 1883;
4130 if (memcmp(url, "mqtts:", 6) == 0) port = 8883;
4131 if (u.port) port = (unsigned short) atoi(url + u.port);
4135 struct mg_str mg_url_user(const char *url) {
4136 struct url u = urlparse(url);
4137 struct mg_str s = mg_str("");
4138 if (u.user && (u.pass || u.host)) {
4139 size_t n = u.pass ? u.pass - u.user - 1 : u.host - u.user - 1;
4140 s = mg_str_n(url + u.user, n);
4145 struct mg_str mg_url_pass(const char *url) {
4146 struct url u = urlparse(url);
4147 struct mg_str s = mg_str_n("", 0UL);
4148 if (u.pass && u.host) {
4149 size_t n = u.host - u.pass - 1;
4150 s = mg_str_n(url + u.pass, n);
4155 #ifdef MG_ENABLE_LINES
4156 #line 1 "src/util.c"
4162 #if MG_ARCH == MG_ARCH_UNIX && defined(__APPLE__)
4163 #include <mach/mach_time.h>
4166 char *mg_file_read(const char *path, size_t *sizep) {
4170 if ((fp = fopen(path, "rb")) != NULL) {
4171 fseek(fp, 0, SEEK_END);
4172 size = (size_t) ftell(fp);
4174 data = (char *) calloc(1, size + 1);
4176 if (fread(data, 1, size, fp) != size) {
4181 if (sizep != NULL) *sizep = size;
4189 bool mg_file_write(const char *path, const void *buf, size_t len) {
4190 bool result = false;
4192 char tmp[MG_PATH_MAX];
4193 snprintf(tmp, sizeof(tmp), "%s.%d", path, rand());
4194 fp = fopen(tmp, "wb");
4196 result = fwrite(buf, 1, len, fp) == len;
4208 bool mg_file_printf(const char *path, const char *fmt, ...) {
4209 char tmp[256], *buf = tmp;
4214 len = mg_vasprintf(&buf, sizeof(tmp), fmt, ap);
4216 result = mg_file_write(path, buf, len > 0 ? (size_t) len : 0);
4217 if (buf != tmp) free(buf);
4221 #if MG_ENABLE_CUSTOM_RANDOM
4223 void mg_random(void *buf, size_t len) {
4225 unsigned char *p = (unsigned char *) buf;
4226 #if MG_ARCH == MG_ARCH_ESP32
4227 while (len--) *p++ = (unsigned char) (esp_random() & 255);
4229 #elif MG_ARCH == MG_ARCH_WIN32
4231 FILE *fp = fopen("/dev/urandom", "rb");
4233 if (fread(buf, 1, len, fp) == len) done = true;
4237 // If everything above did not work, fallback to a pseudo random generator
4238 while (!done && len--) *p++ = (unsigned char) (rand() & 255);
4242 bool mg_globmatch(const char *s1, size_t n1, const char *s2, size_t n2) {
4243 size_t i = 0, j = 0, ni = 0, nj = 0;
4244 while (i < n1 || j < n2) {
4245 if (i < n1 && j < n2 && (s1[i] == '?' || s2[j] == s1[i])) {
4247 } else if (i < n1 && (s1[i] == '*' || s1[i] == '#')) {
4248 ni = i, nj = j + 1, i++;
4249 } else if (nj > 0 && nj <= n2 && (s1[ni] == '#' || s2[j] != '/')) {
4252 // printf(">>: [%s] [%s] %d %d %d %d\n", s1, s2, i, j, ni, nj);
4259 static size_t mg_nce(const char *s, size_t n, size_t ofs, size_t *koff,
4260 size_t *klen, size_t *voff, size_t *vlen) {
4262 for (kvlen = 0; ofs + kvlen < n && s[ofs + kvlen] != ',';) kvlen++;
4263 for (kl = 0; kl < kvlen && s[ofs + kl] != '=';) kl++;
4264 if (koff != NULL) *koff = ofs;
4265 if (klen != NULL) *klen = kl;
4266 if (voff != NULL) *voff = kl < kvlen ? ofs + kl + 1 : 0;
4267 if (vlen != NULL) *vlen = kl < kvlen ? kvlen - kl - 1 : 0;
4269 return ofs > n ? n : ofs;
4272 bool mg_commalist(struct mg_str *s, struct mg_str *k, struct mg_str *v) {
4273 size_t koff = 0, klen = 0, voff = 0, vlen = 0;
4274 size_t off = mg_nce(s->ptr, s->len, 0, &koff, &klen, &voff, &vlen);
4275 if (k != NULL) *k = mg_str_n(s->ptr + koff, klen);
4276 if (v != NULL) *v = mg_str_n(s->ptr + voff, vlen);
4277 *s = mg_str_n(s->ptr + off, s->len - off);
4281 uint32_t mg_ntohl(uint32_t net) {
4282 uint8_t data[4] = {0, 0, 0, 0};
4283 memcpy(&data, &net, sizeof(data));
4284 return (((uint32_t) data[3]) << 0) | (((uint32_t) data[2]) << 8) |
4285 (((uint32_t) data[1]) << 16) | (((uint32_t) data[0]) << 24);
4288 uint16_t mg_ntohs(uint16_t net) {
4289 uint8_t data[2] = {0, 0};
4290 memcpy(&data, &net, sizeof(data));
4291 return (uint16_t) ((uint16_t) data[1] | (((uint16_t) data[0]) << 8));
4294 char *mg_hexdump(const void *buf, size_t len) {
4295 const unsigned char *p = (const unsigned char *) buf;
4296 size_t i, idx, n = 0, ofs = 0, dlen = len * 5 + 100;
4297 char ascii[17] = "", *dst = (char *) calloc(1, dlen);
4298 if (dst == NULL) return dst;
4299 for (i = 0; i < len; i++) {
4302 if (i > 0 && dlen > n)
4303 n += (size_t) snprintf(dst + n, dlen - n, " %s\n", ascii);
4305 n += (size_t) snprintf(dst + n, dlen - n, "%04x ", (int) (i + ofs));
4307 if (dlen < n) break;
4308 n += (size_t) snprintf(dst + n, dlen - n, " %02x", p[i]);
4309 ascii[idx] = (char) (p[i] < 0x20 || p[i] > 0x7e ? '.' : p[i]);
4310 ascii[idx + 1] = '\0';
4313 if (n < dlen) n += (size_t) snprintf(dst + n, dlen - n, "%s", " ");
4315 if (n < dlen) n += (size_t) snprintf(dst + n, dlen - n, " %s\n", ascii);
4316 if (n > dlen - 1) n = dlen - 1;
4321 char *mg_hex(const void *buf, size_t len, char *to) {
4322 const unsigned char *p = (const unsigned char *) buf;
4323 static const char *hex = "0123456789abcdef";
4325 for (; len--; p++) {
4326 to[i++] = hex[p[0] >> 4];
4327 to[i++] = hex[p[0] & 0x0f];
4333 static unsigned char mg_unhex_nimble(unsigned char c) {
4334 return (c >= '0' && c <= '9') ? (unsigned char) (c - '0')
4335 : (c >= 'A' && c <= 'F') ? (unsigned char) (c - '7')
4336 : (unsigned char) (c - 'W');
4339 unsigned long mg_unhexn(const char *s, size_t len) {
4340 unsigned long i = 0, v = 0;
4341 for (i = 0; i < len; i++) v <<= 4, v |= mg_unhex_nimble(((uint8_t *) s)[i]);
4345 void mg_unhex(const char *buf, size_t len, unsigned char *to) {
4347 for (i = 0; i < len; i += 2) {
4348 to[i >> 1] = (unsigned char) mg_unhexn(&buf[i], 2);
4352 int mg_vasprintf(char **buf, size_t size, const char *fmt, va_list ap) {
4356 va_copy(ap_copy, ap);
4357 len = vsnprintf(*buf, size, fmt, ap_copy);
4361 // eCos and Windows are not standard-compliant and return -1 when
4362 // the buffer is too small. Keep allocating larger buffers until we
4363 // succeed or out of memory.
4368 if (size == 0) size = 5;
4370 if ((*buf = (char *) calloc(1, size)) == NULL) {
4374 va_copy(ap_copy, ap);
4375 len = vsnprintf(*buf, size - 1, fmt, ap_copy);
4378 // Microsoft version of vsnprintf() is not always null-terminated, so put
4379 // the terminator manually
4380 if (*buf != NULL) (*buf)[len] = 0;
4382 } else if (len >= (int) size) {
4383 /// Standard-compliant code path. Allocate a buffer that is large enough
4384 if ((*buf = (char *) calloc(1, (size_t) len + 1)) == NULL) {
4385 len = -1; // LCOV_EXCL_LINE
4386 } else { // LCOV_EXCL_LINE
4387 va_copy(ap_copy, ap);
4388 len = vsnprintf(*buf, (size_t) len + 1, fmt, ap_copy);
4396 int mg_asprintf(char **buf, size_t size, const char *fmt, ...) {
4400 ret = mg_vasprintf(buf, size, fmt, ap);
4405 int64_t mg_to64(struct mg_str str) {
4406 int64_t result = 0, neg = 1, max = 922337203685477570 /* INT64_MAX/10-10 */;
4408 while (i < str.len && (str.ptr[i] == ' ' || str.ptr[i] == '\t')) i++;
4409 if (i < str.len && str.ptr[i] == '-') neg = -1, i++;
4410 while (i < str.len && str.ptr[i] >= '0' && str.ptr[i] <= '9') {
4411 if (result > max) return 0;
4413 result += (str.ptr[i] - '0');
4416 return result * neg;
4419 uint32_t mg_crc32(uint32_t crc, const char *buf, size_t len) {
4423 crc ^= *(unsigned char *) buf++;
4424 for (i = 0; i < 8; i++) crc = crc & 1 ? (crc >> 1) ^ 0xedb88320 : crc >> 1;
4429 static int isbyte(int n) {
4430 return n >= 0 && n <= 255;
4433 static int parse_net(const char *spec, uint32_t *net, uint32_t *mask) {
4434 int n, a, b, c, d, slash = 32, len = 0;
4435 if ((sscanf(spec, "%d.%d.%d.%d/%d%n", &a, &b, &c, &d, &slash, &n) == 5 ||
4436 sscanf(spec, "%d.%d.%d.%d%n", &a, &b, &c, &d, &n) == 4) &&
4437 isbyte(a) && isbyte(b) && isbyte(c) && isbyte(d) && slash >= 0 &&
4440 *net = ((uint32_t) a << 24) | ((uint32_t) b << 16) | ((uint32_t) c << 8) |
4442 *mask = slash ? (uint32_t) (0xffffffffU << (32 - slash)) : (uint32_t) 0;
4447 int mg_check_ip_acl(struct mg_str acl, uint32_t remote_ip) {
4449 int allowed = acl.len == 0 ? '+' : '-'; // If any ACL is set, deny by default
4450 while (mg_commalist(&acl, &k, &v)) {
4452 if (k.ptr[0] != '+' && k.ptr[0] != '-') return -1;
4453 if (parse_net(&k.ptr[1], &net, &mask) == 0) return -2;
4454 if ((remote_ip & mask) == net) allowed = k.ptr[0];
4456 return allowed == '+';
4459 double mg_time(void) {
4460 #if MG_ARCH == MG_ARCH_WIN32
4463 GetLocalTime(&sysnow);
4464 SystemTimeToFileTime(&sysnow, &ftime);
4466 * 1. VC 6.0 doesn't support conversion uint64 -> double, so, using int64
4467 * This should not cause a problems in this (21th) century
4468 * 2. Windows FILETIME is a number of 100-nanosecond intervals since January
4469 * 1, 1601 while time_t is a number of _seconds_ since January 1, 1970 UTC,
4470 * thus, we need to convert to seconds and adjust amount (subtract 11644473600
4473 return (double) (((int64_t) ftime.dwLowDateTime +
4474 ((int64_t) ftime.dwHighDateTime << 32)) /
4477 #elif MG_ARCH == MG_ARCH_FREERTOS_TCP || MG_ARCH == MG_ARCH_AZURERTOS
4478 return mg_millis() / 1000.0;
4481 if (gettimeofday(&tv, NULL /* tz */) != 0) return 0;
4482 return (double) tv.tv_sec + (((double) tv.tv_usec) / 1000000.0);
4486 void mg_usleep(unsigned long usecs) {
4487 #if MG_ARCH == MG_ARCH_WIN32
4488 Sleep(usecs / 1000);
4489 #elif MG_ARCH == MG_ARCH_ESP8266
4490 ets_delay_us(usecs);
4491 #elif MG_ARCH == MG_ARCH_FREERTOS_TCP || MG_ARCH == MG_ARCH_FREERTOS_LWIP
4492 vTaskDelay(pdMS_TO_TICKS(usecs / 1000));
4493 #elif MG_ARCH == MG_ARCH_AZURERTOS
4494 tx_thread_sleep((usecs / 1000) * TX_TIMER_TICKS_PER_SECOND);
4496 usleep((useconds_t) usecs);
4500 unsigned long mg_millis(void) {
4501 #if MG_ARCH == MG_ARCH_WIN32
4502 return GetTickCount();
4503 #elif MG_ARCH == MG_ARCH_ESP32
4504 return esp_timer_get_time() / 1000;
4505 #elif MG_ARCH == MG_ARCH_ESP8266
4506 return xTaskGetTickCount() * portTICK_PERIOD_MS;
4507 #elif MG_ARCH == MG_ARCH_FREERTOS_TCP || MG_ARCH == MG_ARCH_FREERTOS_LWIP
4508 return xTaskGetTickCount() * portTICK_PERIOD_MS;
4509 #elif MG_ARCH == MG_ARCH_AZURERTOS
4510 return tx_time_get() * (1000 /* MS per SEC */ / TX_TIMER_TICKS_PER_SECOND);
4511 #elif MG_ARCH == MG_ARCH_UNIX && defined(__APPLE__)
4512 uint64_t ticks = mach_absolute_time();
4513 static mach_timebase_info_data_t timebase;
4514 mach_timebase_info(&timebase);
4515 double ticks_to_nanos = (double)timebase.numer / timebase.denom;
4516 uint64_t uptime_nanos = (uint64_t)(ticks_to_nanos * ticks);
4517 return (unsigned long) (uptime_nanos / 1000000);
4520 #ifdef _POSIX_MONOTONIC_CLOCK
4521 #ifdef CLOCK_MONOTONIC_RAW
4522 clock_gettime(CLOCK_MONOTONIC_RAW, &ts);
4524 clock_gettime(CLOCK_MONOTONIC, &ts);
4527 clock_gettime(CLOCK_REALTIME, &ts);
4529 return (unsigned long) ((uint64_t) ts.tv_sec * 1000 +
4530 (uint64_t) ts.tv_nsec / 1000000);
4534 #ifdef MG_ENABLE_LINES
4552 static void ws_handshake(struct mg_connection *c, const struct mg_str *wskey,
4553 const struct mg_str *wsproto, const char *fmt,
4555 const char *magic = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
4556 unsigned char sha[20], b64_sha[30];
4557 char mem[128], *buf = mem;
4559 mg_sha1_ctx sha_ctx;
4560 mg_sha1_init(&sha_ctx);
4561 mg_sha1_update(&sha_ctx, (unsigned char *) wskey->ptr, wskey->len);
4562 mg_sha1_update(&sha_ctx, (unsigned char *) magic, 36);
4563 mg_sha1_final(sha, &sha_ctx);
4564 mg_base64_encode(sha, sizeof(sha), (char *) b64_sha);
4566 if (fmt != NULL) mg_vasprintf(&buf, sizeof(mem), fmt, ap);
4568 "HTTP/1.1 101 Switching Protocols\r\n"
4569 "Upgrade: websocket\r\n"
4570 "Connection: Upgrade\r\n"
4571 "Sec-WebSocket-Accept: %s\r\n"
4574 if (buf != mem) free(buf);
4575 if (wsproto != NULL) {
4576 mg_printf(c, "Sec-WebSocket-Protocol: %.*s\r\n", (int) wsproto->len,
4579 mg_send(c, "\r\n", 2);
4582 static size_t ws_process(uint8_t *buf, size_t len, struct ws_msg *msg) {
4583 size_t i, n = 0, mask_len = 0;
4584 memset(msg, 0, sizeof(*msg));
4586 n = buf[1] & 0x7f; // Frame length
4587 mask_len = buf[1] & 128 ? 4 : 0; // last bit is a mask bit
4588 msg->flags = buf[0];
4589 if (n < 126 && len >= mask_len) {
4591 msg->header_len = 2 + mask_len;
4592 } else if (n == 126 && len >= 4 + mask_len) {
4593 msg->header_len = 4 + mask_len;
4594 msg->data_len = mg_ntohs(*(uint16_t *) &buf[2]);
4595 } else if (len >= 10 + mask_len) {
4596 msg->header_len = 10 + mask_len;
4598 (size_t) (((uint64_t) mg_ntohl(*(uint32_t *) &buf[2])) << 32) +
4599 mg_ntohl(*(uint32_t *) &buf[6]);
4602 // Sanity check, and integer overflow protection for the boundary check below
4603 // data_len should not be larger than 1 Gb
4604 if (msg->data_len > 1024 * 1024 * 1024) return 0;
4605 if (msg->header_len + msg->data_len > len) return 0;
4607 uint8_t *p = buf + msg->header_len, *m = p - mask_len;
4608 for (i = 0; i < msg->data_len; i++) p[i] ^= m[i & 3];
4610 return msg->header_len + msg->data_len;
4613 static size_t mkhdr(size_t len, int op, bool is_client, uint8_t *buf) {
4615 buf[0] = (uint8_t) (op | 128);
4617 buf[1] = (unsigned char) len;
4619 } else if (len < 65536) {
4620 uint16_t tmp = mg_htons((uint16_t) len);
4622 memcpy(&buf[2], &tmp, sizeof(tmp));
4627 tmp = mg_htonl((uint32_t) ((uint64_t) len >> 32));
4628 memcpy(&buf[2], &tmp, sizeof(tmp));
4629 tmp = mg_htonl((uint32_t) (len & 0xffffffff));
4630 memcpy(&buf[6], &tmp, sizeof(tmp));
4634 buf[1] |= 1 << 7; // Set masking flag
4635 mg_random(&buf[n], 4);
4641 static void mg_ws_mask(struct mg_connection *c, size_t len) {
4642 if (c->is_client && c->send.buf != NULL) {
4644 uint8_t *p = c->send.buf + c->send.len - len, *mask = p - 4;
4645 for (i = 0; i < len; i++) p[i] ^= mask[i & 3];
4649 size_t mg_ws_send(struct mg_connection *c, const char *buf, size_t len,
4652 size_t header_len = mkhdr(len, op, c->is_client, header);
4653 mg_send(c, header, header_len);
4654 LOG(LL_VERBOSE_DEBUG, ("WS out: %d [%.*s]", (int) len, (int) len, buf));
4655 mg_send(c, buf, len);
4657 return header_len + len;
4660 static void mg_ws_cb(struct mg_connection *c, int ev, void *ev_data,
4663 size_t ofs = (size_t) c->pfn_data;
4665 // assert(ofs < c->recv.len);
4666 if (ev == MG_EV_READ) {
4667 if (!c->is_websocket && c->is_client) {
4668 int n = mg_http_get_request_len(c->recv.buf, c->recv.len);
4670 c->is_closing = 1; // Some just, not an HTTP request
4672 if (n < 15 || memcmp(c->recv.buf + 9, "101", 3) != 0) {
4674 ("%lu WS handshake error: %.*s", c->id, 15, c->recv.buf));
4677 struct mg_http_message hm;
4678 mg_http_parse((char *) c->recv.buf, c->recv.len, &hm);
4679 c->is_websocket = 1;
4680 mg_call(c, MG_EV_WS_OPEN, &hm);
4682 mg_iobuf_del(&c->recv, 0, (size_t) n);
4684 return; // A request is not yet received
4688 while (ws_process(c->recv.buf + ofs, c->recv.len - ofs, &msg) > 0) {
4689 char *s = (char *) c->recv.buf + ofs + msg.header_len;
4690 struct mg_ws_message m = {{s, msg.data_len}, msg.flags};
4691 size_t len = msg.header_len + msg.data_len;
4692 uint8_t final = msg.flags & 128, op = msg.flags & 15;
4693 // LOG(LL_VERBOSE_DEBUG, ("fin %d op %d len %d [%.*s]", final, op,
4694 // (int) m.data.len, (int) m.data.len, m.data.ptr));
4696 case WEBSOCKET_OP_CONTINUE:
4697 mg_call(c, MG_EV_WS_CTL, &m);
4699 case WEBSOCKET_OP_PING:
4700 LOG(LL_DEBUG, ("%s", "WS PONG"));
4701 mg_ws_send(c, s, msg.data_len, WEBSOCKET_OP_PONG);
4702 mg_call(c, MG_EV_WS_CTL, &m);
4704 case WEBSOCKET_OP_PONG:
4705 mg_call(c, MG_EV_WS_CTL, &m);
4707 case WEBSOCKET_OP_TEXT:
4708 case WEBSOCKET_OP_BINARY:
4709 if (final) mg_call(c, MG_EV_WS_MSG, &m);
4711 case WEBSOCKET_OP_CLOSE:
4712 LOG(LL_ERROR, ("%lu Got WS CLOSE", c->id));
4713 mg_call(c, MG_EV_WS_CTL, &m);
4717 // Per RFC6455, close conn when an unknown op is recvd
4718 mg_error(c, "unknown WS op %d", op);
4722 // Handle fragmented frames: strip header, keep in c->recv
4723 if (final == 0 || op == 0) {
4724 if (op) ofs++, len--, msg.header_len--; // First frame
4725 mg_iobuf_del(&c->recv, ofs, msg.header_len); // Strip header
4726 len -= msg.header_len;
4728 c->pfn_data = (void *) ofs;
4729 // LOG(LL_INFO, ("FRAG %d [%.*s]", (int) ofs, (int) ofs, c->recv.buf));
4731 // Remove non-fragmented frame
4732 if (final && op) mg_iobuf_del(&c->recv, ofs, len);
4733 // Last chunk of the fragmented frame
4735 m.flags = c->recv.buf[0];
4736 m.data = mg_str_n((char *) &c->recv.buf[1], (size_t) (ofs - 1));
4737 mg_call(c, MG_EV_WS_MSG, &m);
4738 mg_iobuf_del(&c->recv, 0, ofs);
4748 struct mg_connection *mg_ws_connect(struct mg_mgr *mgr, const char *url,
4749 mg_event_handler_t fn, void *fn_data,
4750 const char *fmt, ...) {
4751 struct mg_connection *c = mg_connect(mgr, url, fn, fn_data);
4753 char nonce[16], key[30], mem1[128], mem2[256], *buf1 = mem1, *buf2 = mem2;
4754 struct mg_str host = mg_url_host(url);
4759 n1 = mg_vasprintf(&buf1, sizeof(mem1), fmt, ap);
4762 // Send handshake request
4763 // mg_url_host(url, host, sizeof(host));
4764 mg_random(nonce, sizeof(nonce));
4765 mg_base64_encode((unsigned char *) nonce, sizeof(nonce), key);
4766 // LOG(LL_DEBUG, "%p [%s]", uri, uri == NULL ? "???" : uri);
4767 n2 = mg_asprintf(&buf2, sizeof(mem2),
4768 "GET %s HTTP/1.1\r\n"
4769 "Upgrade: websocket\r\n"
4771 "Connection: Upgrade\r\n"
4773 "Sec-WebSocket-Version: 13\r\n"
4774 "Sec-WebSocket-Key: %s\r\n"
4776 mg_url_uri(url), (int) host.len, host.ptr, n1, buf1, key);
4777 mg_send(c, buf2, n2 > 0 ? (size_t) n2 : 0);
4778 if (buf1 != mem1) free(buf1);
4779 if (buf2 != mem2) free(buf2);
4786 void mg_ws_upgrade(struct mg_connection *c, struct mg_http_message *hm,
4787 const char *fmt, ...) {
4788 struct mg_str *wskey = mg_http_get_header(hm, "Sec-WebSocket-Key");
4791 if (wskey == NULL) {
4792 mg_http_reply(c, 426, "", "WS upgrade expected\n");
4795 struct mg_str *wsproto = mg_http_get_header(hm, "Sec-WebSocket-Protocol");
4798 ws_handshake(c, wskey, wsproto, fmt, ap);
4800 c->is_websocket = 1;
4801 mg_call(c, MG_EV_WS_OPEN, hm);
4805 size_t mg_ws_wrap(struct mg_connection *c, size_t len, int op) {
4806 uint8_t header[14], *p;
4807 size_t header_len = mkhdr(len, op, c->is_client, header);
4809 // NOTE: order of operations is important!
4810 mg_iobuf_add(&c->send, c->send.len, NULL, header_len, MG_IO_SIZE);
4811 p = &c->send.buf[c->send.len - len]; // p points to data
4812 memmove(p, p - header_len, len); // Shift data
4813 memcpy(p - header_len, header, header_len); // Prepend header
4814 mg_ws_mask(c, len); // Mask data