Analysis Software
Documentation for sPHENIX simulation software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
mongoose.cc
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file mongoose.cc
1 #include "mongoose.h"
2 #ifdef MG_MODULE_LINES
3 #line 1 "./src/internal.h"
4 #endif
5 /*
6  * Copyright (c) 2014 Cesanta Software Limited
7  * All rights reserved
8  */
9 
10 #ifndef CS_MONGOOSE_SRC_INTERNAL_H_
11 #define CS_MONGOOSE_SRC_INTERNAL_H_
12 
13 #ifndef MG_MALLOC
14 #define MG_MALLOC malloc
15 #endif
16 
17 #ifndef MG_CALLOC
18 #define MG_CALLOC calloc
19 #endif
20 
21 #ifndef MG_REALLOC
22 #define MG_REALLOC realloc
23 #endif
24 
25 #ifndef MG_FREE
26 #define MG_FREE free
27 #endif
28 
29 #ifndef MBUF_REALLOC
30 #define MBUF_REALLOC MG_REALLOC
31 #endif
32 
33 #ifndef MBUF_FREE
34 #define MBUF_FREE MG_FREE
35 #endif
36 
37 #define MG_SET_PTRPTR(_ptr, _v) \
38 do { \
39 if (_ptr) *(_ptr) = _v; \
40 } while (0)
41 
42 #ifndef MG_INTERNAL
43 #define MG_INTERNAL static
44 #endif
45 
46 #ifdef PICOTCP
47 #define NO_LIBC
48 #define MG_DISABLE_FILESYSTEM
49 #define MG_DISABLE_POPEN
50 #define MG_DISABLE_CGI
51 #define MG_DISABLE_DIRECTORY_LISTING
52 #define MG_DISABLE_SOCKETPAIR
53 #define MG_DISABLE_PFS
54 #endif
55 
56 /* Amalgamated: #include "mongoose/src/net.h" */
57 /* Amalgamated: #include "mongoose/src/http.h" */
58 
59 #define MG_CTL_MSG_MESSAGE_SIZE 8192
60 
61 /* internals that need to be accessible in unit tests */
63  int proto,
64  union socket_address *sa);
65 
66 MG_INTERNAL int mg_parse_address(const char *str, union socket_address *sa,
67  int *proto, char *host, size_t host_len);
68 MG_INTERNAL void mg_call(struct mg_connection *nc,
69  mg_event_handler_t ev_handler, int ev, void *ev_data);
70 void mg_forward(struct mg_connection *from, struct mg_connection *to);
71 MG_INTERNAL void mg_add_conn(struct mg_mgr *mgr, struct mg_connection *c);
74  struct mg_mgr *mgr, mg_event_handler_t callback,
75  struct mg_add_sock_opts opts);
76 #ifndef MG_DISABLE_FILESYSTEM
78  const struct mg_serve_http_opts *opts,
79  char **local_path,
80  struct mg_str *remainder);
81 #endif
82 #ifdef _WIN32
83 /* Retur value is the same as for MultiByteToWideChar. */
84 int to_wchar(const char *path, wchar_t *wbuf, size_t wbuf_len);
85 #endif
86 
87 /*
88  * Reassemble the content of the buffer (buf, blen) which should be
89  * in the HTTP chunked encoding, by collapsing data chunks to the
90  * beginning of the buffer.
91  *
92  * If chunks get reassembled, modify hm->body to point to the reassembled
93  * body and fire MG_EV_HTTP_CHUNK event. If handler sets MG_F_DELETE_CHUNK
94  * in nc->flags, delete reassembled body from the mbuf.
95  *
96  * Return reassembled body size.
97  */
99  struct http_message *hm, char *buf,
100  size_t blen);
101 
102 #ifndef MG_DISABLE_FILESYSTEM
103 MG_INTERNAL time_t mg_parse_date_string(const char *datetime);
104 MG_INTERNAL int mg_is_not_modified(struct http_message *hm, cs_stat_t *st);
105 #endif
106 
107 struct ctl_msg {
110 };
111 
112 #ifndef MG_DISABLE_MQTT
113 struct mg_mqtt_message;
114 MG_INTERNAL int parse_mqtt(struct mbuf *io, struct mg_mqtt_message *mm);
115 #endif
116 
117 /* Forward declarations for testing. */
118 extern void *(*test_malloc)(size_t size);
119 extern void *(*test_calloc)(size_t count, size_t size);
120 
121 #endif /* CS_MONGOOSE_SRC_INTERNAL_H_ */
122 #ifdef MG_MODULE_LINES
123 #line 1 "./src/../../common/base64.c"
124 #endif
125 /*
126  * Copyright (c) 2014 Cesanta Software Limited
127  * All rights reserved
128  */
129 
130 #ifndef EXCLUDE_COMMON
131 
132 /* Amalgamated: #include "common/base64.h" */
133 #include <string.h>
134 
135 /* ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/ */
136 
137 #define NUM_UPPERCASES ('Z' - 'A' + 1)
138 #define NUM_LETTERS (NUM_UPPERCASES * 2)
139 #define NUM_DIGITS ('9' - '0' + 1)
140 
141 /*
142  * Emit a base64 code char.
143  *
144  * Doesn't use memory, thus it's safe to use to safely dump memory in crashdumps
145  */
146 static void cs_base64_emit_code(struct cs_base64_ctx *ctx, int v) {
147  if (v < NUM_UPPERCASES) {
148  ctx->b64_putc(v + 'A', ctx->user_data);
149  } else if (v < (NUM_LETTERS)) {
150  ctx->b64_putc(v - NUM_UPPERCASES + 'a', ctx->user_data);
151  } else if (v < (NUM_LETTERS + NUM_DIGITS)) {
152  ctx->b64_putc(v - NUM_LETTERS + '0', ctx->user_data);
153  } else {
154  ctx->b64_putc(v - NUM_LETTERS - NUM_DIGITS == 0 ? '+' : '/',
155  ctx->user_data);
156  }
157 }
158 
159 static void cs_base64_emit_chunk(struct cs_base64_ctx *ctx) {
160  int a, b, c;
161 
162  a = ctx->chunk[0];
163  b = ctx->chunk[1];
164  c = ctx->chunk[2];
165 
166  cs_base64_emit_code(ctx, a >> 2);
167  cs_base64_emit_code(ctx, ((a & 3) << 4) | (b >> 4));
168  if (ctx->chunk_size > 1) {
169  cs_base64_emit_code(ctx, (b & 15) << 2 | (c >> 6));
170  }
171  if (ctx->chunk_size > 2) {
172  cs_base64_emit_code(ctx, c & 63);
173  }
174 }
175 
176 void cs_base64_init(struct cs_base64_ctx *ctx, cs_base64_putc_t b64_putc,
177  void *user_data) {
178  ctx->chunk_size = 0;
179  ctx->b64_putc = b64_putc;
180  ctx->user_data = user_data;
181 }
182 
183 void cs_base64_update(struct cs_base64_ctx *ctx, const char *str, size_t len) {
184  const unsigned char *src = (const unsigned char *) str;
185  size_t i;
186  for (i = 0; i < len; i++) {
187  ctx->chunk[ctx->chunk_size++] = src[i];
188  if (ctx->chunk_size == 3) {
190  ctx->chunk_size = 0;
191  }
192  }
193 }
194 
195 void cs_base64_finish(struct cs_base64_ctx *ctx) {
196  if (ctx->chunk_size > 0) {
197  int i;
198  memset(&ctx->chunk[ctx->chunk_size], 0, 3 - ctx->chunk_size);
200  for (i = 0; i < (3 - ctx->chunk_size); i++) {
201  ctx->b64_putc('=', ctx->user_data);
202  }
203  }
204 }
205 
206 #define BASE64_ENCODE_BODY \
207 static const char *b64 = \
208 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; \
209 int i, j, a, b, c; \
210 \
211 for (i = j = 0; i < src_len; i += 3) { \
212 a = src[i]; \
213 b = i + 1 >= src_len ? 0 : src[i + 1]; \
214 c = i + 2 >= src_len ? 0 : src[i + 2]; \
215 \
216 BASE64_OUT(b64[a >> 2]); \
217 BASE64_OUT(b64[((a & 3) << 4) | (b >> 4)]); \
218 if (i + 1 < src_len) { \
219 BASE64_OUT(b64[(b & 15) << 2 | (c >> 6)]); \
220 } \
221 if (i + 2 < src_len) { \
222 BASE64_OUT(b64[c & 63]); \
223 } \
224 } \
225 \
226 while (j % 4 != 0) { \
227 BASE64_OUT('='); \
228 } \
229 BASE64_FLUSH()
230 
231 #define BASE64_OUT(ch) \
232 do { \
233 dst[j++] = (ch); \
234 } while (0)
235 
236 #define BASE64_FLUSH() \
237 do { \
238 dst[j++] = '\0'; \
239 } while (0)
240 
241 void cs_base64_encode(const unsigned char *src, int src_len, char *dst) {
243 }
244 
245 #undef BASE64_OUT
246 #undef BASE64_FLUSH
247 
248 #ifndef CS_DISABLE_STDIO
249 #define BASE64_OUT(ch) \
250 do { \
251 fprintf(f, "%c", (ch)); \
252 j++; \
253 } while (0)
254 
255 #define BASE64_FLUSH()
256 
257 void cs_fprint_base64(FILE *f, const unsigned char *src, int src_len) {
259 }
260 
261 #undef BASE64_OUT
262 #undef BASE64_FLUSH
263 #endif /* !CS_DISABLE_STDIO */
264 
265 /* Convert one byte of encoded base64 input stream to 6-bit chunk */
266 static unsigned char from_b64(unsigned char ch) {
267  /* Inverse lookup map */
268  static const unsigned char tab[128] = {
269  255, 255, 255, 255,
270  255, 255, 255, 255, /* 0 */
271  255, 255, 255, 255,
272  255, 255, 255, 255, /* 8 */
273  255, 255, 255, 255,
274  255, 255, 255, 255, /* 16 */
275  255, 255, 255, 255,
276  255, 255, 255, 255, /* 24 */
277  255, 255, 255, 255,
278  255, 255, 255, 255, /* 32 */
279  255, 255, 255, 62,
280  255, 255, 255, 63, /* 40 */
281  52, 53, 54, 55,
282  56, 57, 58, 59, /* 48 */
283  60, 61, 255, 255,
284  255, 200, 255, 255, /* 56 '=' is 200, on index 61 */
285  255, 0, 1, 2,
286  3, 4, 5, 6, /* 64 */
287  7, 8, 9, 10,
288  11, 12, 13, 14, /* 72 */
289  15, 16, 17, 18,
290  19, 20, 21, 22, /* 80 */
291  23, 24, 25, 255,
292  255, 255, 255, 255, /* 88 */
293  255, 26, 27, 28,
294  29, 30, 31, 32, /* 96 */
295  33, 34, 35, 36,
296  37, 38, 39, 40, /* 104 */
297  41, 42, 43, 44,
298  45, 46, 47, 48, /* 112 */
299  49, 50, 51, 255,
300  255, 255, 255, 255, /* 120 */
301  };
302  return tab[ch & 127];
303 }
304 
305 int cs_base64_decode(const unsigned char *s, int len, char *dst) {
306  unsigned char a, b, c, d;
307  int orig_len = len;
308  while (len >= 4 && (a = from_b64(s[0])) != 255 &&
309  (b = from_b64(s[1])) != 255 && (c = from_b64(s[2])) != 255 &&
310  (d = from_b64(s[3])) != 255) {
311  s += 4;
312  len -= 4;
313  if (a == 200 || b == 200) break; /* '=' can't be there */
314  *dst++ = a << 2 | b >> 4;
315  if (c == 200) break;
316  *dst++ = b << 4 | c >> 2;
317  if (d == 200) break;
318  *dst++ = c << 6 | d;
319  }
320  *dst = 0;
321  return orig_len - len;
322 }
323 
324 #endif /* EXCLUDE_COMMON */
325 #ifdef MG_MODULE_LINES
326 #line 1 "./src/../../common/cs_dbg.c"
327 #endif
328 /*
329  * Copyright (c) 2014-2016 Cesanta Software Limited
330  * All rights reserved
331  */
332 
333 /* Amalgamated: #include "common/cs_dbg.h" */
334 
335 #include <stdarg.h>
336 #include <stdio.h>
337 
338 /* Amalgamated: #include "common/cs_time.h" */
339 
341 #ifdef CS_ENABLE_DEBUG
343 #else
344 LL_ERROR;
345 #endif
346 
347 #ifndef CS_DISABLE_STDIO
348 
349 FILE *cs_log_file = NULL;
350 
351 #ifdef CS_LOG_TS_DIFF
352 double cs_log_ts;
353 #endif
354 
355 void cs_log_print_prefix(const char *func) {
356  if (cs_log_file == NULL) cs_log_file = stderr;
357  fprintf(cs_log_file, "%-20s ", func);
358 #ifdef CS_LOG_TS_DIFF
359  {
360  double now = cs_time();
361  fprintf(cs_log_file, "%7u ", (unsigned int) ((now - cs_log_ts) * 1000000));
362  cs_log_ts = now;
363  }
364 #endif
365 }
366 
367 void cs_log_printf(const char *fmt, ...) {
368  va_list ap;
369  va_start(ap, fmt);
370  vfprintf(cs_log_file, fmt, ap);
371  va_end(ap);
372  fputc('\n', cs_log_file);
373  fflush(cs_log_file);
374 }
375 
376 void cs_log_set_file(FILE *file) {
377  cs_log_file = file;
378 }
379 
380 #endif /* !CS_DISABLE_STDIO */
381 
384 #if defined(CS_LOG_TS_DIFF) && !defined(CS_DISABLE_STDIO)
385  cs_log_ts = cs_time();
386 #endif
387 }
388 #ifdef MG_MODULE_LINES
389 #line 1 "./src/../../common/cs_dirent.h"
390 #endif
391 /*
392  * Copyright (c) 2014-2016 Cesanta Software Limited
393  * All rights reserved
394  */
395 
396 #ifndef CS_COMMON_CS_DIRENT_H_
397 #define CS_COMMON_CS_DIRENT_H_
398 
399 #ifdef __cplusplus
400 extern "C" {
401 #endif /* __cplusplus */
402 
403 #ifdef CS_ENABLE_SPIFFS
404 
405 #include <spiffs.h>
406 
407  typedef struct {
408  spiffs_DIR dh;
409  struct spiffs_dirent de;
410  } DIR;
411 
412 #define d_name name
413 #define dirent spiffs_dirent
414 
415  int rmdir(const char *path);
416  int mkdir(const char *path, mode_t mode);
417 
418 #endif
419 
420 #if defined(_WIN32)
421  struct dirent {
422  char d_name[MAX_PATH];
423  };
424 
425  typedef struct DIR {
426  HANDLE handle;
427  WIN32_FIND_DATAW info;
428  struct dirent result;
429  } DIR;
430 #endif
431 
432 #if defined(_WIN32) || defined(CS_ENABLE_SPIFFS)
433  DIR *opendir(const char *dir_name);
434  int closedir(DIR *dir);
435  struct dirent *readdir(DIR *dir);
436 #endif
437 
438 #ifdef __cplusplus
439 }
440 #endif /* __cplusplus */
441 
442 #endif /* CS_COMMON_CS_DIRENT_H_ */
443 #ifdef MG_MODULE_LINES
444 #line 1 "./src/../../common/cs_dirent.c"
445 #endif
446 /*
447  * Copyright (c) 2015 Cesanta Software Limited
448  * All rights reserved
449  */
450 
451 #ifndef EXCLUDE_COMMON
452 
453 /* Amalgamated: #include "common/cs_dirent.h" */
454 
455 /*
456  * This file contains POSIX opendir/closedir/readdir API implementation
457  * for systems which do not natively support it (e.g. Windows).
458  */
459 
460 #ifndef MG_FREE
461 #define MG_FREE free
462 #endif
463 
464 #ifndef MG_MALLOC
465 #define MG_MALLOC malloc
466 #endif
467 
468 #ifdef _WIN32
469 DIR *opendir(const char *name) {
470  DIR *dir = NULL;
471  wchar_t wpath[MAX_PATH];
472  DWORD attrs;
473 
474  if (name == NULL) {
475  SetLastError(ERROR_BAD_ARGUMENTS);
476  } else if ((dir = (DIR *) MG_MALLOC(sizeof(*dir))) == NULL) {
477  SetLastError(ERROR_NOT_ENOUGH_MEMORY);
478  } else {
479  to_wchar(name, wpath, ARRAY_SIZE(wpath));
480  attrs = GetFileAttributesW(wpath);
481  if (attrs != 0xFFFFFFFF && (attrs & FILE_ATTRIBUTE_DIRECTORY)) {
482  (void) wcscat(wpath, L"\\*");
483  dir->handle = FindFirstFileW(wpath, &dir->info);
484  dir->result.d_name[0] = '\0';
485  } else {
486  MG_FREE(dir);
487  dir = NULL;
488  }
489  }
490 
491  return dir;
492 }
493 
494 int closedir(DIR *dir) {
495  int result = 0;
496 
497  if (dir != NULL) {
498  if (dir->handle != INVALID_HANDLE_VALUE)
499  result = FindClose(dir->handle) ? 0 : -1;
500  MG_FREE(dir);
501  } else {
502  result = -1;
503  SetLastError(ERROR_BAD_ARGUMENTS);
504  }
505 
506  return result;
507 }
508 
509 struct dirent *readdir(DIR *dir) {
510  struct dirent *result = NULL;
511 
512  if (dir) {
513  if (dir->handle != INVALID_HANDLE_VALUE) {
514  result = &dir->result;
515  (void) WideCharToMultiByte(CP_UTF8, 0, dir->info.cFileName, -1,
516  result->d_name, sizeof(result->d_name), NULL,
517  NULL);
518 
519  if (!FindNextFileW(dir->handle, &dir->info)) {
520  (void) FindClose(dir->handle);
521  dir->handle = INVALID_HANDLE_VALUE;
522  }
523 
524  } else {
525  SetLastError(ERROR_FILE_NOT_FOUND);
526  }
527  } else {
528  SetLastError(ERROR_BAD_ARGUMENTS);
529  }
530 
531  return result;
532 }
533 #endif
534 
535 #ifdef CS_ENABLE_SPIFFS
536 
537 DIR *opendir(const char *dir_name) {
538  DIR *dir = NULL;
539  extern spiffs fs;
540 
541  if (dir_name != NULL && (dir = (DIR *) malloc(sizeof(*dir))) != NULL &&
542  SPIFFS_opendir(&fs, (char *) dir_name, &dir->dh) == NULL) {
543  free(dir);
544  dir = NULL;
545  }
546 
547  return dir;
548 }
549 
550 int closedir(DIR *dir) {
551  if (dir != NULL) {
552  SPIFFS_closedir(&dir->dh);
553  free(dir);
554  }
555  return 0;
556 }
557 
558 struct dirent *readdir(DIR *dir) {
559  return SPIFFS_readdir(&dir->dh, &dir->de);
560 }
561 
562 /* SPIFFs doesn't support directory operations */
563 int rmdir(const char *path) {
564  (void) path;
565  return ENOTDIR;
566 }
567 
568 int mkdir(const char *path, mode_t mode) {
569  (void) path;
570  (void) mode;
571  /* for spiffs supports only root dir, which comes from mongoose as '.' */
572  return (strlen(path) == 1 && *path == '.') ? 0 : ENOTDIR;
573 }
574 
575 #endif /* CS_ENABLE_SPIFFS */
576 
577 #endif /* EXCLUDE_COMMON */
578 
579 /* ISO C requires a translation unit to contain at least one declaration */
580 typedef int cs_dirent_dummy;
581 #ifdef MG_MODULE_LINES
582 #line 1 "./src/../../common/cs_time.c"
583 #endif
584 /*
585  * Copyright (c) 2014-2016 Cesanta Software Limited
586  * All rights reserved
587  */
588 
589 /* Amalgamated: #include "common/cs_time.h" */
590 
591 #ifndef _WIN32
592 #include <stddef.h>
593 #if !defined(CS_PLATFORM) || \
594 (CS_PLATFORM != CS_P_CC3200 && CS_PLATFORM != CS_P_MSP432)
595 #include <sys/time.h>
596 #endif
597 #else
598 #include <windows.h>
599 #endif
600 
601 double cs_time() {
602  double now;
603 #ifndef _WIN32
604  struct timeval tv;
605  if (gettimeofday(&tv, NULL /* tz */) != 0) return 0;
606  now = (double) tv.tv_sec + (((double) tv.tv_usec) / 1000000.0);
607 #else
608  now = GetTickCount() / 1000.0;
609 #endif
610  return now;
611 }
612 #ifdef MG_MODULE_LINES
613 #line 1 "./src/../deps/frozen/frozen.c"
614 #endif
615 /*
616  * Copyright (c) 2004-2013 Sergey Lyubka <valenok@gmail.com>
617  * Copyright (c) 2013 Cesanta Software Limited
618  * All rights reserved
619  *
620  * This library is dual-licensed: you can redistribute it and/or modify
621  * it under the terms of the GNU General Public License version 2 as
622  * published by the Free Software Foundation. For the terms of this
623  * license, see <http: *www.gnu.org/licenses/>.
624  *
625  * You are free to use this library under the terms of the GNU General
626  * Public License, but WITHOUT ANY WARRANTY; without even the implied
627  * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
628  * See the GNU General Public License for more details.
629  *
630  * Alternatively, you can license this library under a commercial
631  * license, as set out in <http://cesanta.com/products.html>.
632  */
633 
634 #ifndef _CRT_SECURE_NO_WARNINGS
635 #define _CRT_SECURE_NO_WARNINGS /* Disable deprecation warning in VS2005+ */
636 #endif
637 
638 #include <stdio.h>
639 #include <stdlib.h>
640 #include <string.h>
641 #include <stdarg.h>
642 /* Amalgamated: #include "frozen.h" */
643 
644 #ifdef _WIN32
645 #define snprintf _snprintf
646 #endif
647 
648 #ifndef FROZEN_REALLOC
649 #define FROZEN_REALLOC realloc
650 #endif
651 
652 #ifndef FROZEN_FREE
653 #define FROZEN_FREE free
654 #endif
655 
656 struct frozen {
657  const char *end;
658  const char *cur;
663 };
664 
665 static int parse_object(struct frozen *f);
666 static int parse_value(struct frozen *f);
667 
668 #define EXPECT(cond, err_code) \
669 do { \
670 if (!(cond)) return (err_code); \
671 } while (0)
672 #define TRY(expr) \
673 do { \
674 int _n = expr; \
675 if (_n < 0) return _n; \
676 } while (0)
677 #define END_OF_STRING (-1)
678 
679 static int left(const struct frozen *f) {
680  return f->end - f->cur;
681 }
682 
683 static int is_space(int ch) {
684  return ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n';
685 }
686 
687 static void skip_whitespaces(struct frozen *f) {
688  while (f->cur < f->end && is_space(*f->cur)) f->cur++;
689 }
690 
691 static int cur(struct frozen *f) {
692  skip_whitespaces(f);
693  return f->cur >= f->end ? END_OF_STRING : *(unsigned char *) f->cur;
694 }
695 
696 static int test_and_skip(struct frozen *f, int expected) {
697  int ch = cur(f);
698  if (ch == expected) {
699  f->cur++;
700  return 0;
701  }
703 }
704 
705 static int test_no_skip(struct frozen *f, int expected) {
706  int ch = cur(f);
707  if (ch == expected) {
708  return 0;
709  }
711 }
712 
713 static int is_alpha(int ch) {
714  return (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z');
715 }
716 
717 static int is_digit(int ch) {
718  return ch >= '0' && ch <= '9';
719 }
720 
721 static int is_hex_digit(int ch) {
722  return is_digit(ch) || (ch >= 'a' && ch <= 'f') || (ch >= 'A' && ch <= 'F');
723 }
724 
725 static int get_escape_len(const char *s, int len) {
726  switch (*s) {
727  case 'u':
728  return len < 6 ? JSON_STRING_INCOMPLETE
729  : is_hex_digit(s[1]) && is_hex_digit(s[2]) &&
730  is_hex_digit(s[3]) && is_hex_digit(s[4])
731  ? 5
733  case '"':
734  case '\\':
735  case '/':
736  case 'b':
737  case 'f':
738  case 'n':
739  case 'r':
740  case 't':
741  return len < 2 ? JSON_STRING_INCOMPLETE : 1;
742  default:
743  return JSON_STRING_INVALID;
744  }
745 }
746 
747 static int capture_ptr(struct frozen *f, const char *ptr, enum json_type type) {
748  if (f->do_realloc && f->num_tokens >= f->max_tokens) {
749  int new_size = f->max_tokens == 0 ? 100 : f->max_tokens * 2;
750  void *p = FROZEN_REALLOC(f->tokens, new_size * sizeof(f->tokens[0]));
751  if (p == NULL) return JSON_TOKEN_ARRAY_TOO_SMALL;
752  f->max_tokens = new_size;
753  f->tokens = (struct json_token *) p;
754  }
755  if (f->tokens == NULL || f->max_tokens == 0) return 0;
756  if (f->num_tokens >= f->max_tokens) return JSON_TOKEN_ARRAY_TOO_SMALL;
757  f->tokens[f->num_tokens].ptr = ptr;
758  f->tokens[f->num_tokens].type = type;
759  f->num_tokens++;
760  return 0;
761 }
762 
763 static int capture_len(struct frozen *f, int token_index, const char *ptr) {
764  if (f->tokens == 0 || f->max_tokens == 0) return 0;
765  EXPECT(token_index >= 0 && token_index < f->max_tokens, JSON_STRING_INVALID);
766  f->tokens[token_index].len = ptr - f->tokens[token_index].ptr;
767  f->tokens[token_index].num_desc = (f->num_tokens - 1) - token_index;
768  return 0;
769 }
770 
771 /* identifier = letter { letter | digit | '_' } */
772 static int parse_identifier(struct frozen *f) {
775  while (f->cur < f->end &&
776  (*f->cur == '_' || is_alpha(*f->cur) || is_digit(*f->cur))) {
777  f->cur++;
778  }
779  capture_len(f, f->num_tokens - 1, f->cur);
780  return 0;
781 }
782 
783 static int get_utf8_char_len(unsigned char ch) {
784  if ((ch & 0x80) == 0) return 1;
785  switch (ch & 0xf0) {
786  case 0xf0:
787  return 4;
788  case 0xe0:
789  return 3;
790  default:
791  return 2;
792  }
793 }
794 
795 /* string = '"' { quoted_printable_chars } '"' */
796 static int parse_string(struct frozen *f) {
797  int n, ch = 0, len = 0;
798  TRY(test_and_skip(f, '"'));
800  for (; f->cur < f->end; f->cur += len) {
801  ch = *(unsigned char *) f->cur;
802  len = get_utf8_char_len((unsigned char) ch);
803  EXPECT(ch >= 32 && len > 0, JSON_STRING_INVALID); /* No control chars */
805  if (ch == '\\') {
806  EXPECT((n = get_escape_len(f->cur + 1, left(f))) > 0, n);
807  len += n;
808  } else if (ch == '"') {
809  capture_len(f, f->num_tokens - 1, f->cur);
810  f->cur++;
811  break;
812  };
813  }
814  return ch == '"' ? 0 : JSON_STRING_INCOMPLETE;
815 }
816 
817 /* number = [ '-' ] digit+ [ '.' digit+ ] [ ['e'|'E'] ['+'|'-'] digit+ ] */
818 static int parse_number(struct frozen *f) {
819  int ch = cur(f);
821  if (ch == '-') f->cur++;
824  while (f->cur < f->end && is_digit(f->cur[0])) f->cur++;
825  if (f->cur < f->end && f->cur[0] == '.') {
826  f->cur++;
829  while (f->cur < f->end && is_digit(f->cur[0])) f->cur++;
830  }
831  if (f->cur < f->end && (f->cur[0] == 'e' || f->cur[0] == 'E')) {
832  f->cur++;
834  if ((f->cur[0] == '+' || f->cur[0] == '-')) f->cur++;
837  while (f->cur < f->end && is_digit(f->cur[0])) f->cur++;
838  }
839  capture_len(f, f->num_tokens - 1, f->cur);
840  return 0;
841 }
842 
843 /* array = '[' [ value { ',' value } ] ']' */
844 static int parse_array(struct frozen *f) {
845  int ind;
846  TRY(test_and_skip(f, '['));
847  TRY(capture_ptr(f, f->cur - 1, JSON_TYPE_ARRAY));
848  ind = f->num_tokens - 1;
849  while (cur(f) != ']') {
850  TRY(parse_value(f));
851  if (cur(f) == ',') f->cur++;
852  }
853  TRY(test_and_skip(f, ']'));
854  capture_len(f, ind, f->cur);
855  return 0;
856 }
857 
858 static int compare(const char *s, const char *str, int len) {
859  int i = 0;
860  while (i < len && s[i] == str[i]) i++;
861  return i == len ? 1 : 0;
862 }
863 
864 static int expect(struct frozen *f, const char *s, int len, enum json_type t) {
865  int i, n = left(f);
866 
867  TRY(capture_ptr(f, f->cur, t));
868  for (i = 0; i < len; i++) {
869  if (i >= n) return JSON_STRING_INCOMPLETE;
870  if (f->cur[i] != s[i]) return JSON_STRING_INVALID;
871  }
872  f->cur += len;
873  TRY(capture_len(f, f->num_tokens - 1, f->cur));
874 
875  return 0;
876 }
877 
878 /* value = 'null' | 'true' | 'false' | number | string | array | object */
879 static int parse_value(struct frozen *f) {
880  int ch = cur(f);
881 
882  switch (ch) {
883  case '"':
884  TRY(parse_string(f));
885  break;
886  case '{':
887  TRY(parse_object(f));
888  break;
889  case '[':
890  TRY(parse_array(f));
891  break;
892  case 'n':
893  TRY(expect(f, "null", 4, JSON_TYPE_NULL));
894  break;
895  case 't':
896  TRY(expect(f, "true", 4, JSON_TYPE_TRUE));
897  break;
898  case 'f':
899  TRY(expect(f, "false", 5, JSON_TYPE_FALSE));
900  break;
901  case '-':
902  case '0':
903  case '1':
904  case '2':
905  case '3':
906  case '4':
907  case '5':
908  case '6':
909  case '7':
910  case '8':
911  case '9':
912  TRY(parse_number(f));
913  break;
914  default:
916  }
917 
918  return 0;
919 }
920 
921 /* key = identifier | string */
922 static int parse_key(struct frozen *f) {
923  int ch = cur(f);
924 #if 0
925  printf("%s 1 [%.*s]\n", __func__, (int) (f->end - f->cur), f->cur);
926 #endif
927  if (is_alpha(ch)) {
928  TRY(parse_identifier(f));
929  } else if (ch == '"') {
930  TRY(parse_string(f));
931  } else {
933  }
934  return 0;
935 }
936 
937 /* pair = key ':' value */
938 static int parse_pair(struct frozen *f) {
939  TRY(parse_key(f));
940  TRY(test_and_skip(f, ':'));
941  TRY(parse_value(f));
942  return 0;
943 }
944 
945 /* object = '{' pair { ',' pair } '}' */
946 static int parse_object(struct frozen *f) {
947  int ind;
948  TRY(test_and_skip(f, '{'));
949  TRY(capture_ptr(f, f->cur - 1, JSON_TYPE_OBJECT));
950  ind = f->num_tokens - 1;
951  while (cur(f) != '}') {
952  TRY(parse_pair(f));
953  if (cur(f) == ',') f->cur++;
954  }
955  TRY(test_and_skip(f, '}'));
956  capture_len(f, ind, f->cur);
957  return 0;
958 }
959 
960 static int doit(struct frozen *f) {
961  int ret = 0;
962 
963  if (f->cur == 0 || f->end < f->cur) return JSON_STRING_INVALID;
964  if (f->end == f->cur) return JSON_STRING_INCOMPLETE;
965 
966  if (0 == (ret = test_no_skip(f, '{'))) {
967  TRY(parse_object(f));
968  } else if (0 == (ret = test_no_skip(f, '['))) {
969  TRY(parse_array(f));
970  } else {
971  return ret;
972  }
973 
974  TRY(capture_ptr(f, f->cur, JSON_TYPE_EOF));
975  capture_len(f, f->num_tokens, f->cur);
976  return 0;
977 }
978 
979 /* json = object */
980 int parse_json(const char *s, int s_len, struct json_token *arr, int arr_len) {
981  struct frozen frozen;
982 
983  memset(&frozen, 0, sizeof(frozen));
984  frozen.end = s + s_len;
985  frozen.cur = s;
986  frozen.tokens = arr;
987  frozen.max_tokens = arr_len;
988 
989  TRY(doit(&frozen));
990 
991  return frozen.cur - s;
992 }
993 
994 struct json_token *parse_json2(const char *s, int s_len) {
995  struct frozen frozen;
996 
997  memset(&frozen, 0, sizeof(frozen));
998  frozen.end = s + s_len;
999  frozen.cur = s;
1000  frozen.do_realloc = 1;
1001 
1002  if (doit(&frozen) < 0) {
1003  FROZEN_FREE((void *) frozen.tokens);
1004  frozen.tokens = NULL;
1005  }
1006  return frozen.tokens;
1007 }
1008 
1009 static int path_part_len(const char *p) {
1010  int i = 0;
1011  while (p[i] != '\0' && p[i] != '[' && p[i] != '.') i++;
1012  return i;
1013 }
1014 
1015 struct json_token *find_json_token(struct json_token *toks, const char *path) {
1016  while (path != 0 && path[0] != '\0') {
1017  int i, ind2 = 0, ind = -1, skip = 2, n = path_part_len(path);
1018  if (path[0] == '[') {
1019  if (toks->type != JSON_TYPE_ARRAY || !is_digit(path[1])) return 0;
1020  for (ind = 0, n = 1; path[n] != ']' && path[n] != '\0'; n++) {
1021  if (!is_digit(path[n])) return 0;
1022  ind *= 10;
1023  ind += path[n] - '0';
1024  }
1025  if (path[n++] != ']') return 0;
1026  skip = 1; /* In objects, we skip 2 elems while iterating, in arrays 1. */
1027  } else if (toks->type != JSON_TYPE_OBJECT)
1028  return 0;
1029  toks++;
1030  for (i = 0; i < toks[-1].num_desc; i += skip, ind2++) {
1031  /* ind == -1 indicated that we're iterating an array, not object */
1032  if (ind == -1 && toks[i].type != JSON_TYPE_STRING) return 0;
1033  if (ind2 == ind ||
1034  (ind == -1 && toks[i].len == n && compare(path, toks[i].ptr, n))) {
1035  i += skip - 1;
1036  break;
1037  };
1038  if (toks[i - 1 + skip].type == JSON_TYPE_ARRAY ||
1039  toks[i - 1 + skip].type == JSON_TYPE_OBJECT) {
1040  i += toks[i - 1 + skip].num_desc;
1041  }
1042  }
1043  if (i == toks[-1].num_desc) return 0;
1044  path += n;
1045  if (path[0] == '.') path++;
1046  if (path[0] == '\0') return &toks[i];
1047  toks += i;
1048  }
1049  return 0;
1050 }
1051 
1052 int json_emit_long(char *buf, int buf_len, long int value) {
1053  char tmp[20];
1054  int n = snprintf(tmp, sizeof(tmp), "%ld", value);
1055  strncpy(buf, tmp, buf_len > 0 ? buf_len : 0);
1056  return n;
1057 }
1058 
1059 int json_emit_double(char *buf, int buf_len, double value) {
1060  char tmp[20];
1061  int n = snprintf(tmp, sizeof(tmp), "%g", value);
1062  strncpy(buf, tmp, buf_len > 0 ? buf_len : 0);
1063  return n;
1064 }
1065 
1066 int json_emit_quoted_str(char *s, int s_len, const char *str, int len) {
1067  const char *begin = s, *end = s + s_len, *str_end = str + len;
1068  char ch;
1069 
1070 #define EMIT(x) \
1071 do { \
1072 if (s < end) *s = x; \
1073 s++; \
1074 } while (0)
1075 
1076  EMIT('"');
1077  while (str < str_end) {
1078  ch = *str++;
1079  switch (ch) {
1080  case '"':
1081  EMIT('\\');
1082  EMIT('"');
1083  break;
1084  case '\\':
1085  EMIT('\\');
1086  EMIT('\\');
1087  break;
1088  case '\b':
1089  EMIT('\\');
1090  EMIT('b');
1091  break;
1092  case '\f':
1093  EMIT('\\');
1094  EMIT('f');
1095  break;
1096  case '\n':
1097  EMIT('\\');
1098  EMIT('n');
1099  break;
1100  case '\r':
1101  EMIT('\\');
1102  EMIT('r');
1103  break;
1104  case '\t':
1105  EMIT('\\');
1106  EMIT('t');
1107  break;
1108  default:
1109  EMIT(ch);
1110  }
1111  }
1112  EMIT('"');
1113  if (s < end) {
1114  *s = '\0';
1115  }
1116 
1117  return s - begin;
1118 }
1119 
1120 int json_emit_unquoted_str(char *buf, int buf_len, const char *str, int len) {
1121  if (buf_len > 0 && len > 0) {
1122  int n = len < buf_len ? len : buf_len;
1123  memcpy(buf, str, n);
1124  if (n < buf_len) {
1125  buf[n] = '\0';
1126  }
1127  }
1128  return len;
1129 }
1130 
1131 int json_emit_va(char *s, int s_len, const char *fmt, va_list ap) {
1132  const char *end = s + s_len, *str, *orig = s;
1133  size_t len;
1134 
1135  while (*fmt != '\0') {
1136  switch (*fmt) {
1137  case '[':
1138  case ']':
1139  case '{':
1140  case '}':
1141  case ',':
1142  case ':':
1143  case ' ':
1144  case '\r':
1145  case '\n':
1146  case '\t':
1147  if (s < end) {
1148  *s = *fmt;
1149  }
1150  s++;
1151  break;
1152  case 'i':
1153  s += json_emit_long(s, end - s, va_arg(ap, long) );
1154  break;
1155  case 'f':
1156  s += json_emit_double(s, end - s, va_arg(ap, double) );
1157  break;
1158  case 'v':
1159  str = va_arg(ap, char *);
1160  len = va_arg(ap, size_t);
1161  s += json_emit_quoted_str(s, end - s, str, len);
1162  break;
1163  case 'V':
1164  str = va_arg(ap, char *);
1165  len = va_arg(ap, size_t);
1166  s += json_emit_unquoted_str(s, end - s, str, len);
1167  break;
1168  case 's':
1169  str = va_arg(ap, char *);
1170  s += json_emit_quoted_str(s, end - s, str, strlen(str));
1171  break;
1172  case 'S':
1173  str = va_arg(ap, char *);
1174  s += json_emit_unquoted_str(s, end - s, str, strlen(str));
1175  break;
1176  case 'T':
1177  s += json_emit_unquoted_str(s, end - s, "true", 4);
1178  break;
1179  case 'F':
1180  s += json_emit_unquoted_str(s, end - s, "false", 5);
1181  break;
1182  case 'N':
1183  s += json_emit_unquoted_str(s, end - s, "null", 4);
1184  break;
1185  default:
1186  return 0;
1187  }
1188  fmt++;
1189  }
1190 
1191  /* Best-effort to 0-terminate generated string */
1192  if (s < end) {
1193  *s = '\0';
1194  }
1195 
1196  return s - orig;
1197 }
1198 
1199 int json_emit(char *buf, int buf_len, const char *fmt, ...) {
1200  int len;
1201  va_list ap;
1202 
1203  va_start(ap, fmt);
1204  len = json_emit_va(buf, buf_len, fmt, ap);
1205  va_end(ap);
1206 
1207  return len;
1208 }
1209 #ifdef MG_MODULE_LINES
1210 #line 1 "./src/../../common/md5.c"
1211 #endif
1212 /*
1213  * This code implements the MD5 message-digest algorithm.
1214  * The algorithm is due to Ron Rivest. This code was
1215  * written by Colin Plumb in 1993, no copyright is claimed.
1216  * This code is in the public domain; do with it what you wish.
1217  *
1218  * Equivalent code is available from RSA Data Security, Inc.
1219  * This code has been tested against that, and is equivalent,
1220  * except that you don't need to include two pages of legalese
1221  * with every copy.
1222  *
1223  * To compute the message digest of a chunk of bytes, declare an
1224  * MD5Context structure, pass it to MD5Init, call MD5Update as
1225  * needed on buffers full of bytes, and then call MD5Final, which
1226  * will fill a supplied 16-byte array with the digest.
1227  */
1228 
1229 #if !defined(DISABLE_MD5) && !defined(EXCLUDE_COMMON)
1230 
1231 /* Amalgamated: #include "common/md5.h" */
1232 
1233 #ifndef CS_ENABLE_NATIVE_MD5
1234 static void byteReverse(unsigned char *buf, unsigned longs) {
1235  /* Forrest: MD5 expect LITTLE_ENDIAN, swap if BIG_ENDIAN */
1236 #if BYTE_ORDER == BIG_ENDIAN
1237  do {
1238  uint32_t t = (uint32_t)((unsigned) buf[3] << 8 | buf[2]) << 16 |
1239  ((unsigned) buf[1] << 8 | buf[0]);
1240  *(uint32_t *) buf = t;
1241  buf += 4;
1242  } while (--longs);
1243 #else
1244  (void) buf;
1245  (void) longs;
1246 #endif
1247 }
1248 
1249 #define F1(x, y, z) (z ^ (x & (y ^ z)))
1250 #define F2(x, y, z) F1(z, x, y)
1251 #define F3(x, y, z) (x ^ y ^ z)
1252 #define F4(x, y, z) (y ^ (x | ~z))
1253 
1254 #define MD5STEP(f, w, x, y, z, data, s) \
1255 (w += f(x, y, z) + data, w = w << s | w >> (32 - s), w += x)
1256 
1257 /*
1258  * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious
1259  * initialization constants.
1260  */
1261 void MD5_Init(MD5_CTX *ctx) {
1262  ctx->buf[0] = 0x67452301;
1263  ctx->buf[1] = 0xefcdab89;
1264  ctx->buf[2] = 0x98badcfe;
1265  ctx->buf[3] = 0x10325476;
1266 
1267  ctx->bits[0] = 0;
1268  ctx->bits[1] = 0;
1269 }
1270 
1271 static void MD5Transform(uint32_t buf[4], uint32_t const in[16]) {
1272  uint32_t a, b, c, d;
1273 
1274  a = buf[0];
1275  b = buf[1];
1276  c = buf[2];
1277  d = buf[3];
1278 
1279  MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7);
1280  MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12);
1281  MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17);
1282  MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22);
1283  MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7);
1284  MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12);
1285  MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17);
1286  MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22);
1287  MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7);
1288  MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12);
1289  MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17);
1290  MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22);
1291  MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7);
1292  MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12);
1293  MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17);
1294  MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22);
1295 
1296  MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5);
1297  MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9);
1298  MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14);
1299  MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20);
1300  MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5);
1301  MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9);
1302  MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14);
1303  MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20);
1304  MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5);
1305  MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9);
1306  MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14);
1307  MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20);
1308  MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5);
1309  MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9);
1310  MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14);
1311  MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20);
1312 
1313  MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4);
1314  MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11);
1315  MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16);
1316  MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23);
1317  MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4);
1318  MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11);
1319  MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16);
1320  MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23);
1321  MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4);
1322  MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11);
1323  MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16);
1324  MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23);
1325  MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4);
1326  MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11);
1327  MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16);
1328  MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23);
1329 
1330  MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6);
1331  MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10);
1332  MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15);
1333  MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21);
1334  MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6);
1335  MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10);
1336  MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15);
1337  MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21);
1338  MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6);
1339  MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10);
1340  MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15);
1341  MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21);
1342  MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6);
1343  MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10);
1344  MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15);
1345  MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21);
1346 
1347  buf[0] += a;
1348  buf[1] += b;
1349  buf[2] += c;
1350  buf[3] += d;
1351 }
1352 
1353 void MD5_Update(MD5_CTX *ctx, const unsigned char *buf, size_t len) {
1354  uint32_t t;
1355 
1356  t = ctx->bits[0];
1357  if ((ctx->bits[0] = t + ((uint32_t) len << 3)) < t) ctx->bits[1]++;
1358  ctx->bits[1] += (uint32_t) len >> 29;
1359 
1360  t = (t >> 3) & 0x3f;
1361 
1362  if (t) {
1363  unsigned char *p = (unsigned char *) ctx->in + t;
1364 
1365  t = 64 - t;
1366  if (len < t) {
1367  memcpy(p, buf, len);
1368  return;
1369  }
1370  memcpy(p, buf, t);
1371  byteReverse(ctx->in, 16);
1372  MD5Transform(ctx->buf, (uint32_t *) ctx->in);
1373  buf += t;
1374  len -= t;
1375  }
1376 
1377  while (len >= 64) {
1378  memcpy(ctx->in, buf, 64);
1379  byteReverse(ctx->in, 16);
1380  MD5Transform(ctx->buf, (uint32_t *) ctx->in);
1381  buf += 64;
1382  len -= 64;
1383  }
1384 
1385  memcpy(ctx->in, buf, len);
1386 }
1387 
1388 void MD5_Final(unsigned char digest[16], MD5_CTX *ctx) {
1389  unsigned count;
1390  unsigned char *p;
1391  uint32_t *a;
1392 
1393  count = (ctx->bits[0] >> 3) & 0x3F;
1394 
1395  p = ctx->in + count;
1396  *p++ = 0x80;
1397  count = 64 - 1 - count;
1398  if (count < 8) {
1399  memset(p, 0, count);
1400  byteReverse(ctx->in, 16);
1401  MD5Transform(ctx->buf, (uint32_t *) ctx->in);
1402  memset(ctx->in, 0, 56);
1403  } else {
1404  memset(p, 0, count - 8);
1405  }
1406  byteReverse(ctx->in, 14);
1407 
1408  a = (uint32_t *) ctx->in;
1409  a[14] = ctx->bits[0];
1410  a[15] = ctx->bits[1];
1411 
1412  MD5Transform(ctx->buf, (uint32_t *) ctx->in);
1413  byteReverse((unsigned char *) ctx->buf, 4);
1414  memcpy(digest, ctx->buf, 16);
1415  memset((char *) ctx, 0, sizeof(*ctx));
1416 }
1417 #endif /* CS_ENABLE_NATIVE_MD5 */
1418 
1419 /*
1420  * Stringify binary data. Output buffer size must be 2 * size_of_input + 1
1421  * because each byte of input takes 2 bytes in string representation
1422  * plus 1 byte for the terminating \0 character.
1423  */
1424 void cs_to_hex(char *to, const unsigned char *p, size_t len) {
1425  static const char *hex = "0123456789abcdef";
1426 
1427  for (; len--; p++) {
1428  *to++ = hex[p[0] >> 4];
1429  *to++ = hex[p[0] & 0x0f];
1430  }
1431  *to = '\0';
1432 }
1433 
1434 char *cs_md5(char buf[33], ...) {
1435  unsigned char hash[16];
1436  const unsigned char *p;
1437  va_list ap;
1438  MD5_CTX ctx;
1439 
1440  MD5_Init(&ctx);
1441 
1442  va_start(ap, buf);
1443  while ((p = va_arg(ap, const unsigned char *) ) != NULL) {
1444  size_t len = va_arg(ap, size_t);
1445  MD5_Update(&ctx, p, len);
1446  }
1447  va_end(ap);
1448 
1449  MD5_Final(hash, &ctx);
1450  cs_to_hex(buf, hash, sizeof(hash));
1451 
1452  return buf;
1453 }
1454 
1455 #endif /* EXCLUDE_COMMON */
1456 #ifdef MG_MODULE_LINES
1457 #line 1 "./src/../../common/mbuf.c"
1458 #endif
1459 /*
1460  * Copyright (c) 2014 Cesanta Software Limited
1461  * All rights reserved
1462  */
1463 
1464 #ifndef EXCLUDE_COMMON
1465 
1466 #include <assert.h>
1467 #include <string.h>
1468 /* Amalgamated: #include "common/mbuf.h" */
1469 
1470 #ifndef MBUF_REALLOC
1471 #define MBUF_REALLOC realloc
1472 #endif
1473 
1474 #ifndef MBUF_FREE
1475 #define MBUF_FREE free
1476 #endif
1477 
1478 void mbuf_init(struct mbuf *mbuf, size_t initial_size) {
1479  mbuf->len = mbuf->size = 0;
1480  mbuf->buf = NULL;
1481  mbuf_resize(mbuf, initial_size);
1482 }
1483 
1484 void mbuf_free(struct mbuf *mbuf) {
1485  if (mbuf->buf != NULL) {
1486  MBUF_FREE(mbuf->buf);
1487  mbuf_init(mbuf, 0);
1488  }
1489 }
1490 
1491 void mbuf_resize(struct mbuf *a, size_t new_size) {
1492  if (new_size > a->size || (new_size < a->size && new_size >= a->len)) {
1493  char *buf = (char *) MBUF_REALLOC(a->buf, new_size);
1494  /*
1495  * In case realloc fails, there's not much we can do, except keep things as
1496  * they are. Note that NULL is a valid return value from realloc when
1497  * size == 0, but that is covered too.
1498  */
1499  if (buf == NULL && new_size != 0) return;
1500  a->buf = buf;
1501  a->size = new_size;
1502  }
1503 }
1504 
1505 void mbuf_trim(struct mbuf *mbuf) {
1506  mbuf_resize(mbuf, mbuf->len);
1507 }
1508 
1509 size_t mbuf_insert(struct mbuf *a, size_t off, const void *buf, size_t len) {
1510  char *p = NULL;
1511 
1512  assert(a != NULL);
1513  assert(a->len <= a->size);
1514  assert(off <= a->len);
1515 
1516  /* check overflow */
1517  if (~(size_t) 0 - (size_t) a->buf < len) return 0;
1518 
1519  if (a->len + len <= a->size) {
1520  memmove(a->buf + off + len, a->buf + off, a->len - off);
1521  if (buf != NULL) {
1522  memcpy(a->buf + off, buf, len);
1523  }
1524  a->len += len;
1525  } else {
1526  size_t new_size = (a->len + len) * MBUF_SIZE_MULTIPLIER;
1527  if ((p = (char *) MBUF_REALLOC(a->buf, new_size)) != NULL) {
1528  a->buf = p;
1529  memmove(a->buf + off + len, a->buf + off, a->len - off);
1530  if (buf != NULL) memcpy(a->buf + off, buf, len);
1531  a->len += len;
1532  a->size = new_size;
1533  } else {
1534  len = 0;
1535  }
1536  }
1537 
1538  return len;
1539 }
1540 
1541 size_t mbuf_append(struct mbuf *a, const void *buf, size_t len) {
1542  return mbuf_insert(a, a->len, buf, len);
1543 }
1544 
1545 void mbuf_remove(struct mbuf *mb, size_t n) {
1546  if (n > 0 && n <= mb->len) {
1547  memmove(mb->buf, mb->buf + n, mb->len - n);
1548  mb->len -= n;
1549  }
1550 }
1551 
1552 #endif /* EXCLUDE_COMMON */
1553 #ifdef MG_MODULE_LINES
1554 #line 1 "./src/../../common/sha1.c"
1555 #endif
1556 /* Copyright(c) By Steve Reid <steve@edmweb.com> */
1557 /* 100% Public Domain */
1558 
1559 #if !defined(DISABLE_SHA1) && !defined(EXCLUDE_COMMON)
1560 
1561 /* Amalgamated: #include "common/sha1.h" */
1562 
1563 #define SHA1HANDSOFF
1564 #if defined(__sun)
1565 /* Amalgamated: #include "common/solarisfixes.h" */
1566 #endif
1567 
1569  unsigned char c[64];
1570  uint32_t l[16];
1571 };
1572 
1573 #define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits))))
1574 
1575 static uint32_t blk0(union char64long16 *block, int i) {
1576  /* Forrest: SHA expect BIG_ENDIAN, swap if LITTLE_ENDIAN */
1577 #if BYTE_ORDER == LITTLE_ENDIAN
1578  block->l[i] =
1579  (rol(block->l[i], 24) & 0xFF00FF00) | (rol(block->l[i], 8) & 0x00FF00FF);
1580 #endif
1581  return block->l[i];
1582 }
1583 
1584 /* Avoid redefine warning (ARM /usr/include/sys/ucontext.h define R0~R4) */
1585 #undef blk
1586 #undef R0
1587 #undef R1
1588 #undef R2
1589 #undef R3
1590 #undef R4
1591 
1592 #define blk(i) \
1593 (block->l[i & 15] = rol(block->l[(i + 13) & 15] ^ block->l[(i + 8) & 15] ^ \
1594 block->l[(i + 2) & 15] ^ block->l[i & 15], \
1595 1))
1596 #define R0(v, w, x, y, z, i) \
1597 z += ((w & (x ^ y)) ^ y) + blk0(block, i) + 0x5A827999 + rol(v, 5); \
1598 w = rol(w, 30);
1599 #define R1(v, w, x, y, z, i) \
1600 z += ((w & (x ^ y)) ^ y) + blk(i) + 0x5A827999 + rol(v, 5); \
1601 w = rol(w, 30);
1602 #define R2(v, w, x, y, z, i) \
1603 z += (w ^ x ^ y) + blk(i) + 0x6ED9EBA1 + rol(v, 5); \
1604 w = rol(w, 30);
1605 #define R3(v, w, x, y, z, i) \
1606 z += (((w | x) & y) | (w & x)) + blk(i) + 0x8F1BBCDC + rol(v, 5); \
1607 w = rol(w, 30);
1608 #define R4(v, w, x, y, z, i) \
1609 z += (w ^ x ^ y) + blk(i) + 0xCA62C1D6 + rol(v, 5); \
1610 w = rol(w, 30);
1611 
1612 void cs_sha1_transform(uint32_t state[5], const unsigned char buffer[64]) {
1613  uint32_t a, b, c, d, e;
1614  union char64long16 block[1];
1615 
1616  memcpy(block, buffer, 64);
1617  a = state[0];
1618  b = state[1];
1619  c = state[2];
1620  d = state[3];
1621  e = state[4];
1622  R0(a, b, c, d, e, 0);
1623  R0(e, a, b, c, d, 1);
1624  R0(d, e, a, b, c, 2);
1625  R0(c, d, e, a, b, 3);
1626  R0(b, c, d, e, a, 4);
1627  R0(a, b, c, d, e, 5);
1628  R0(e, a, b, c, d, 6);
1629  R0(d, e, a, b, c, 7);
1630  R0(c, d, e, a, b, 8);
1631  R0(b, c, d, e, a, 9);
1632  R0(a, b, c, d, e, 10);
1633  R0(e, a, b, c, d, 11);
1634  R0(d, e, a, b, c, 12);
1635  R0(c, d, e, a, b, 13);
1636  R0(b, c, d, e, a, 14);
1637  R0(a, b, c, d, e, 15);
1638  R1(e, a, b, c, d, 16);
1639  R1(d, e, a, b, c, 17);
1640  R1(c, d, e, a, b, 18);
1641  R1(b, c, d, e, a, 19);
1642  R2(a, b, c, d, e, 20);
1643  R2(e, a, b, c, d, 21);
1644  R2(d, e, a, b, c, 22);
1645  R2(c, d, e, a, b, 23);
1646  R2(b, c, d, e, a, 24);
1647  R2(a, b, c, d, e, 25);
1648  R2(e, a, b, c, d, 26);
1649  R2(d, e, a, b, c, 27);
1650  R2(c, d, e, a, b, 28);
1651  R2(b, c, d, e, a, 29);
1652  R2(a, b, c, d, e, 30);
1653  R2(e, a, b, c, d, 31);
1654  R2(d, e, a, b, c, 32);
1655  R2(c, d, e, a, b, 33);
1656  R2(b, c, d, e, a, 34);
1657  R2(a, b, c, d, e, 35);
1658  R2(e, a, b, c, d, 36);
1659  R2(d, e, a, b, c, 37);
1660  R2(c, d, e, a, b, 38);
1661  R2(b, c, d, e, a, 39);
1662  R3(a, b, c, d, e, 40);
1663  R3(e, a, b, c, d, 41);
1664  R3(d, e, a, b, c, 42);
1665  R3(c, d, e, a, b, 43);
1666  R3(b, c, d, e, a, 44);
1667  R3(a, b, c, d, e, 45);
1668  R3(e, a, b, c, d, 46);
1669  R3(d, e, a, b, c, 47);
1670  R3(c, d, e, a, b, 48);
1671  R3(b, c, d, e, a, 49);
1672  R3(a, b, c, d, e, 50);
1673  R3(e, a, b, c, d, 51);
1674  R3(d, e, a, b, c, 52);
1675  R3(c, d, e, a, b, 53);
1676  R3(b, c, d, e, a, 54);
1677  R3(a, b, c, d, e, 55);
1678  R3(e, a, b, c, d, 56);
1679  R3(d, e, a, b, c, 57);
1680  R3(c, d, e, a, b, 58);
1681  R3(b, c, d, e, a, 59);
1682  R4(a, b, c, d, e, 60);
1683  R4(e, a, b, c, d, 61);
1684  R4(d, e, a, b, c, 62);
1685  R4(c, d, e, a, b, 63);
1686  R4(b, c, d, e, a, 64);
1687  R4(a, b, c, d, e, 65);
1688  R4(e, a, b, c, d, 66);
1689  R4(d, e, a, b, c, 67);
1690  R4(c, d, e, a, b, 68);
1691  R4(b, c, d, e, a, 69);
1692  R4(a, b, c, d, e, 70);
1693  R4(e, a, b, c, d, 71);
1694  R4(d, e, a, b, c, 72);
1695  R4(c, d, e, a, b, 73);
1696  R4(b, c, d, e, a, 74);
1697  R4(a, b, c, d, e, 75);
1698  R4(e, a, b, c, d, 76);
1699  R4(d, e, a, b, c, 77);
1700  R4(c, d, e, a, b, 78);
1701  R4(b, c, d, e, a, 79);
1702  state[0] += a;
1703  state[1] += b;
1704  state[2] += c;
1705  state[3] += d;
1706  state[4] += e;
1707  /* Erase working structures. The order of operations is important,
1708  * used to ensure that compiler doesn't optimize those out. */
1709  memset(block, 0, sizeof(block));
1710  a = b = c = d = e = 0;
1711  (void) a;
1712  (void) b;
1713  (void) c;
1714  (void) d;
1715  (void) e;
1716 }
1717 
1718 void cs_sha1_init(cs_sha1_ctx *context) {
1719  context->state[0] = 0x67452301;
1720  context->state[1] = 0xEFCDAB89;
1721  context->state[2] = 0x98BADCFE;
1722  context->state[3] = 0x10325476;
1723  context->state[4] = 0xC3D2E1F0;
1724  context->count[0] = context->count[1] = 0;
1725 }
1726 
1727 void cs_sha1_update(cs_sha1_ctx *context, const unsigned char *data,
1728  uint32_t len) {
1729  uint32_t i, j;
1730 
1731  j = context->count[0];
1732  if ((context->count[0] += len << 3) < j) context->count[1]++;
1733  context->count[1] += (len >> 29);
1734  j = (j >> 3) & 63;
1735  if ((j + len) > 63) {
1736  memcpy(&context->buffer[j], data, (i = 64 - j));
1737  cs_sha1_transform(context->state, context->buffer);
1738  for (; i + 63 < len; i += 64) {
1739  cs_sha1_transform(context->state, &data[i]);
1740  }
1741  j = 0;
1742  } else
1743  i = 0;
1744  memcpy(&context->buffer[j], &data[i], len - i);
1745 }
1746 
1747 void cs_sha1_final(unsigned char digest[20], cs_sha1_ctx *context) {
1748  unsigned i;
1749  unsigned char finalcount[8], c;
1750 
1751  for (i = 0; i < 8; i++) {
1752  finalcount[i] = (unsigned char) ((context->count[(i >= 4 ? 0 : 1)] >>
1753  ((3 - (i & 3)) * 8)) &
1754  255);
1755  }
1756  c = 0200;
1757  cs_sha1_update(context, &c, 1);
1758  while ((context->count[0] & 504) != 448) {
1759  c = 0000;
1760  cs_sha1_update(context, &c, 1);
1761  }
1762  cs_sha1_update(context, finalcount, 8);
1763  for (i = 0; i < 20; i++) {
1764  digest[i] =
1765  (unsigned char) ((context->state[i >> 2] >> ((3 - (i & 3)) * 8)) & 255);
1766  }
1767  memset(context, '\0', sizeof(*context));
1768  memset(&finalcount, '\0', sizeof(finalcount));
1769 }
1770 
1771 void cs_hmac_sha1(const unsigned char *key, size_t keylen,
1772  const unsigned char *data, size_t datalen,
1773  unsigned char out[20]) {
1774  cs_sha1_ctx ctx;
1775  unsigned char buf1[64], buf2[64], tmp_key[20], i;
1776 
1777  if (keylen > sizeof(buf1)) {
1778  cs_sha1_init(&ctx);
1779  cs_sha1_update(&ctx, key, keylen);
1780  cs_sha1_final(tmp_key, &ctx);
1781  key = tmp_key;
1782  keylen = sizeof(tmp_key);
1783  }
1784 
1785  memset(buf1, 0, sizeof(buf1));
1786  memset(buf2, 0, sizeof(buf2));
1787  memcpy(buf1, key, keylen);
1788  memcpy(buf2, key, keylen);
1789 
1790  for (i = 0; i < sizeof(buf1); i++) {
1791  buf1[i] ^= 0x36;
1792  buf2[i] ^= 0x5c;
1793  }
1794 
1795  cs_sha1_init(&ctx);
1796  cs_sha1_update(&ctx, buf1, sizeof(buf1));
1797  cs_sha1_update(&ctx, data, datalen);
1798  cs_sha1_final(out, &ctx);
1799 
1800  cs_sha1_init(&ctx);
1801  cs_sha1_update(&ctx, buf2, sizeof(buf2));
1802  cs_sha1_update(&ctx, out, 20);
1803  cs_sha1_final(out, &ctx);
1804 }
1805 
1806 #endif /* EXCLUDE_COMMON */
1807 #ifdef MG_MODULE_LINES
1808 #line 1 "./src/../../common/str_util.c"
1809 #endif
1810 /*
1811  * Copyright (c) 2015 Cesanta Software Limited
1812  * All rights reserved
1813  */
1814 
1815 #ifndef EXCLUDE_COMMON
1816 
1817 /* Amalgamated: #include "common/platform.h" */
1818 /* Amalgamated: #include "common/str_util.h" */
1819 
1820 size_t c_strnlen(const char *s, size_t maxlen) {
1821  size_t l = 0;
1822  for (; l < maxlen && s[l] != '\0'; l++) {
1823  }
1824  return l;
1825 }
1826 
1827 #define C_SNPRINTF_APPEND_CHAR(ch) \
1828 do { \
1829 if (i < (int) buf_size) buf[i] = ch; \
1830 i++; \
1831 } while (0)
1832 
1833 #define C_SNPRINTF_FLAG_ZERO 1
1834 
1835 #ifdef C_DISABLE_BUILTIN_SNPRINTF
1836 int c_vsnprintf(char *buf, size_t buf_size, const char *fmt, va_list ap) {
1837  return vsnprintf(buf, buf_size, fmt, ap);
1838 }
1839 #else
1840 static int c_itoa(char *buf, size_t buf_size, int64_t num, int base, int flags,
1841  int field_width) {
1842  char tmp[40];
1843  int i = 0, k = 0, neg = 0;
1844 
1845  if (num < 0) {
1846  neg++;
1847  num = -num;
1848  }
1849 
1850  /* Print into temporary buffer - in reverse order */
1851  do {
1852  int rem = num % base;
1853  if (rem < 10) {
1854  tmp[k++] = '0' + rem;
1855  } else {
1856  tmp[k++] = 'a' + (rem - 10);
1857  }
1858  num /= base;
1859  } while (num > 0);
1860 
1861  /* Zero padding */
1862  if (flags && C_SNPRINTF_FLAG_ZERO) {
1863  while (k < field_width && k < (int) sizeof(tmp) - 1) {
1864  tmp[k++] = '0';
1865  }
1866  }
1867 
1868  /* And sign */
1869  if (neg) {
1870  tmp[k++] = '-';
1871  }
1872 
1873  /* Now output */
1874  while (--k >= 0) {
1875  C_SNPRINTF_APPEND_CHAR(tmp[k]);
1876  }
1877 
1878  return i;
1879 }
1880 
1881 int c_vsnprintf(char *buf, size_t buf_size, const char *fmt, va_list ap) {
1882  int ch, i = 0, len_mod, flags, precision, field_width;
1883 
1884  while ((ch = *fmt++) != '\0') {
1885  if (ch != '%') {
1887  } else {
1888  /*
1889  * Conversion specification:
1890  * zero or more flags (one of: # 0 - <space> + ')
1891  * an optional minimum field width (digits)
1892  * an optional precision (. followed by digits, or *)
1893  * an optional length modifier (one of: hh h l ll L q j z t)
1894  * conversion specifier (one of: d i o u x X e E f F g G a A c s p n)
1895  */
1896  flags = field_width = precision = len_mod = 0;
1897 
1898  /* Flags. only zero-pad flag is supported. */
1899  if (*fmt == '0') {
1900  flags |= C_SNPRINTF_FLAG_ZERO;
1901  }
1902 
1903  /* Field width */
1904  while (*fmt >= '0' && *fmt <= '9') {
1905  field_width *= 10;
1906  field_width += *fmt++ - '0';
1907  }
1908  /* Dynamic field width */
1909  if (*fmt == '*') {
1910  field_width = va_arg(ap, int);
1911  fmt++;
1912  }
1913 
1914  /* Precision */
1915  if (*fmt == '.') {
1916  fmt++;
1917  if (*fmt == '*') {
1918  precision = va_arg(ap, int);
1919  fmt++;
1920  } else {
1921  while (*fmt >= '0' && *fmt <= '9') {
1922  precision *= 10;
1923  precision += *fmt++ - '0';
1924  }
1925  }
1926  }
1927 
1928  /* Length modifier */
1929  switch (*fmt) {
1930  case 'h':
1931  case 'l':
1932  case 'L':
1933  case 'I':
1934  case 'q':
1935  case 'j':
1936  case 'z':
1937  case 't':
1938  len_mod = *fmt++;
1939  if (*fmt == 'h') {
1940  len_mod = 'H';
1941  fmt++;
1942  }
1943  if (*fmt == 'l') {
1944  len_mod = 'q';
1945  fmt++;
1946  }
1947  break;
1948  }
1949 
1950  ch = *fmt++;
1951  if (ch == 's') {
1952  const char *s = va_arg(ap, const char *); /* Always fetch parameter */
1953  int j;
1954  int pad = field_width - (precision >= 0 ? c_strnlen(s, precision) : 0);
1955  for (j = 0; j < pad; j++) {
1957  }
1958 
1959  /* `s` may be NULL in case of %.*s */
1960  if (s != NULL) {
1961  /* Ignore negative and 0 precisions */
1962  for (j = 0; (precision <= 0 || j < precision) && s[j] != '\0'; j++) {
1963  C_SNPRINTF_APPEND_CHAR(s[j]);
1964  }
1965  }
1966  } else if (ch == 'c') {
1967  ch = va_arg(ap, int); /* Always fetch parameter */
1969  } else if (ch == 'd' && len_mod == 0) {
1970  i += c_itoa(buf + i, buf_size - i, va_arg(ap, int), 10, flags,
1971  field_width);
1972  } else if (ch == 'd' && len_mod == 'l') {
1973  i += c_itoa(buf + i, buf_size - i, va_arg(ap, long), 10, flags,
1974  field_width);
1975 #ifdef SSIZE_MAX
1976  } else if (ch == 'd' && len_mod == 'z') {
1977  i += c_itoa(buf + i, buf_size - i, va_arg(ap, ssize_t), 10, flags,
1978  field_width);
1979 #endif
1980  } else if (ch == 'd' && len_mod == 'q') {
1981  i += c_itoa(buf + i, buf_size - i, va_arg(ap, int64_t), 10, flags,
1982  field_width);
1983  } else if ((ch == 'x' || ch == 'u') && len_mod == 0) {
1984  i += c_itoa(buf + i, buf_size - i, va_arg(ap, unsigned),
1985  ch == 'x' ? 16 : 10, flags, field_width);
1986  } else if ((ch == 'x' || ch == 'u') && len_mod == 'l') {
1987  i += c_itoa(buf + i, buf_size - i, va_arg(ap, unsigned long),
1988  ch == 'x' ? 16 : 10, flags, field_width);
1989  } else if ((ch == 'x' || ch == 'u') && len_mod == 'z') {
1990  i += c_itoa(buf + i, buf_size - i, va_arg(ap, size_t),
1991  ch == 'x' ? 16 : 10, flags, field_width);
1992  } else if (ch == 'p') {
1993  unsigned long num = (unsigned long) va_arg(ap, void *);
1996  i += c_itoa(buf + i, buf_size - i, num, 16, flags, 0);
1997  } else {
1998 #ifndef NO_LIBC
1999  /*
2000  * TODO(lsm): abort is not nice in a library, remove it
2001  * Also, ESP8266 SDK doesn't have it
2002  */
2003  abort();
2004 #endif
2005  }
2006  }
2007  }
2008 
2009  /* Zero-terminate the result */
2010  if (buf_size > 0) {
2011  buf[i < (int) buf_size ? i : (int) buf_size - 1] = '\0';
2012  }
2013 
2014  return i;
2015 }
2016 #endif
2017 
2018 int c_snprintf(char *buf, size_t buf_size, const char *fmt, ...) {
2019  int result;
2020  va_list ap;
2021  va_start(ap, fmt);
2022  result = c_vsnprintf(buf, buf_size, fmt, ap);
2023  va_end(ap);
2024  return result;
2025 }
2026 
2027 #ifdef _WIN32
2028 int to_wchar(const char *path, wchar_t *wbuf, size_t wbuf_len) {
2029  int ret;
2030  char buf[MAX_PATH * 2], buf2[MAX_PATH * 2], *p;
2031 
2032  strncpy(buf, path, sizeof(buf));
2033  buf[sizeof(buf) - 1] = '\0';
2034 
2035  /* Trim trailing slashes. Leave backslash for paths like "X:\" */
2036  p = buf + strlen(buf) - 1;
2037  while (p > buf && p[-1] != ':' && (p[0] == '\\' || p[0] == '/')) *p-- = '\0';
2038 
2039  memset(wbuf, 0, wbuf_len * sizeof(wchar_t));
2040  ret = MultiByteToWideChar(CP_UTF8, 0, buf, -1, wbuf, (int) wbuf_len);
2041 
2042  /*
2043  * Convert back to Unicode. If doubly-converted string does not match the
2044  * original, something is fishy, reject.
2045  */
2046  WideCharToMultiByte(CP_UTF8, 0, wbuf, (int) wbuf_len, buf2, sizeof(buf2),
2047  NULL, NULL);
2048  if (strcmp(buf, buf2) != 0) {
2049  wbuf[0] = L'\0';
2050  ret = 0;
2051  }
2052 
2053  return ret;
2054 }
2055 #endif /* _WIN32 */
2056 
2057 /* The simplest O(mn) algorithm. Better implementation are GPLed */
2058 const char *c_strnstr(const char *s, const char *find, size_t slen) {
2059  size_t find_length = strlen(find);
2060  size_t i;
2061 
2062  for (i = 0; i < slen; i++) {
2063  if (i + find_length > slen) {
2064  return NULL;
2065  }
2066 
2067  if (strncmp(&s[i], find, find_length) == 0) {
2068  return &s[i];
2069  }
2070  }
2071 
2072  return NULL;
2073 }
2074 
2075 #endif /* EXCLUDE_COMMON */
2076 #ifdef MG_MODULE_LINES
2077 #line 1 "./src/net.c"
2078 #endif
2079 /*
2080  * Copyright (c) 2014 Cesanta Software Limited
2081  * All rights reserved
2082  *
2083  * This software is dual-licensed: you can redistribute it and/or modify
2084  * it under the terms of the GNU General Public License version 2 as
2085  * published by the Free Software Foundation. For the terms of this
2086  * license, see <http://www.gnu.org/licenses/>.
2087  *
2088  * You are free to use this software under the terms of the GNU General
2089  * Public License, but WITHOUT ANY WARRANTY; without even the implied
2090  * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
2091  * See the GNU General Public License for more details.
2092  *
2093  * Alternatively, you can license this software under a commercial
2094  * license, as set out in <https://www.cesanta.com/license>.
2095  */
2096 
2097 /* Amalgamated: #include "mongoose/src/internal.h" */
2098 /* Amalgamated: #include "mongoose/src/util.h" */
2099 /* Amalgamated: #include "mongoose/src/dns.h" */
2100 /* Amalgamated: #include "mongoose/src/resolv.h" */
2101 /* Amalgamated: #include "common/cs_time.h" */
2102 
2103 #define MG_MAX_HOST_LEN 200
2104 
2105 #define MG_COPY_COMMON_CONNECTION_OPTIONS(dst, src) \
2106 memcpy(dst, src, sizeof(*dst));
2107 
2108 /* Which flags can be pre-set by the user at connection creation time. */
2109 #define _MG_ALLOWED_CONNECT_FLAGS_MASK \
2110 (MG_F_USER_1 | MG_F_USER_2 | MG_F_USER_3 | MG_F_USER_4 | MG_F_USER_5 | \
2111 MG_F_USER_6 | MG_F_WEBSOCKET_NO_DEFRAG)
2112 /* Which flags should be modifiable by user's callbacks. */
2113 #define _MG_CALLBACK_MODIFIABLE_FLAGS_MASK \
2114 (MG_F_USER_1 | MG_F_USER_2 | MG_F_USER_3 | MG_F_USER_4 | MG_F_USER_5 | \
2115 MG_F_USER_6 | MG_F_WEBSOCKET_NO_DEFRAG | MG_F_SEND_AND_CLOSE | \
2116 MG_F_CLOSE_IMMEDIATELY | MG_F_IS_WEBSOCKET | MG_F_DELETE_CHUNK)
2117 
2118 #ifndef intptr_t
2119 #define intptr_t long
2120 #endif
2121 
2122 int mg_is_error(int n);
2123 void mg_set_non_blocking_mode(sock_t sock);
2124 
2125 extern void mg_ev_mgr_init(struct mg_mgr *mgr);
2126 extern void mg_ev_mgr_free(struct mg_mgr *mgr);
2127 extern void mg_ev_mgr_add_conn(struct mg_connection *nc);
2128 extern void mg_ev_mgr_remove_conn(struct mg_connection *nc);
2129 
2130 MG_INTERNAL void mg_add_conn(struct mg_mgr *mgr, struct mg_connection *c) {
2131  DBG(("%p %p", mgr, c));
2132  c->mgr = mgr;
2133  c->next = mgr->active_connections;
2134  mgr->active_connections = c;
2135  c->prev = NULL;
2136  if (c->next != NULL) c->next->prev = c;
2137  mg_ev_mgr_add_conn(c);
2138 }
2139 
2141  if (conn->prev == NULL) conn->mgr->active_connections = conn->next;
2142  if (conn->prev) conn->prev->next = conn->next;
2143  if (conn->next) conn->next->prev = conn->prev;
2144  mg_ev_mgr_remove_conn(conn);
2145 }
2146 
2148  mg_event_handler_t ev_handler, int ev, void *ev_data) {
2149  if (ev_handler == NULL) {
2150  /*
2151  * If protocol handler is specified, call it. Otherwise, call user-specified
2152  * event handler.
2153  */
2154  ev_handler = nc->proto_handler ? nc->proto_handler : nc->handler;
2155  }
2156  DBG(("%p %s ev=%d ev_data=%p flags=%lu rmbl=%d smbl=%d", nc,
2157  ev_handler == nc->handler ? "user" : "proto", ev, ev_data, nc->flags,
2158  (int) nc->recv_mbuf.len, (int) nc->send_mbuf.len));
2159 
2160 #if !defined(NO_LIBC) && !defined(MG_DISABLE_HEXDUMP)
2161  /* LCOV_EXCL_START */
2162  if (nc->mgr->hexdump_file != NULL && ev != MG_EV_POLL &&
2163  ev != MG_EV_SEND /* handled separately */) {
2164  if (ev == MG_EV_RECV) {
2166  *(int *) ev_data, ev);
2167  } else {
2168  mg_hexdump_connection(nc, nc->mgr->hexdump_file, NULL, 0, ev);
2169  }
2170  }
2171  /* LCOV_EXCL_STOP */
2172 #endif
2173  if (ev_handler != NULL) {
2174  unsigned long flags_before = nc->flags;
2175  size_t recv_mbuf_before = nc->recv_mbuf.len, recved;
2176  ev_handler(nc, ev, ev_data);
2177  recved = (recv_mbuf_before - nc->recv_mbuf.len);
2178  /* Prevent user handler from fiddling with system flags. */
2179  if (ev_handler == nc->handler && nc->flags != flags_before) {
2180  nc->flags = (flags_before & ~_MG_CALLBACK_MODIFIABLE_FLAGS_MASK) |
2182  }
2183  if (recved > 0 && !(nc->flags & MG_F_UDP)) {
2184  mg_if_recved(nc, recved);
2185  }
2186  }
2187  DBG(("%p after %s flags=%lu rmbl=%d smbl=%d", nc,
2188  ev_handler == nc->handler ? "user" : "proto", nc->flags,
2189  (int) nc->recv_mbuf.len, (int) nc->send_mbuf.len));
2190 }
2191 
2192 void mg_if_timer(struct mg_connection *c, double now) {
2193  if (c->ev_timer_time > 0 && now >= c->ev_timer_time) {
2194  double old_value = c->ev_timer_time;
2195  mg_call(c, NULL, MG_EV_TIMER, &now);
2196  /*
2197  * To prevent timer firing all the time, reset the timer after delivery.
2198  * However, in case user sets it to new value, do not reset.
2199  */
2200  if (c->ev_timer_time == old_value) {
2201  c->ev_timer_time = 0;
2202  }
2203  }
2204 }
2205 
2206 void mg_if_poll(struct mg_connection *nc, time_t now) {
2207  if (nc->ssl == NULL || (nc->flags & MG_F_SSL_HANDSHAKE_DONE)) {
2208  mg_call(nc, NULL, MG_EV_POLL, &now);
2209  }
2210 }
2211 
2212 static void mg_destroy_conn(struct mg_connection *conn) {
2213  if (conn->proto_data != NULL && conn->proto_data_destructor != NULL) {
2214  conn->proto_data_destructor(conn->proto_data);
2215  }
2216  mg_if_destroy_conn(conn);
2217 #ifdef MG_ENABLE_SSL
2218  if (conn->ssl != NULL) SSL_free(conn->ssl);
2219  if (conn->ssl_ctx != NULL) SSL_CTX_free(conn->ssl_ctx);
2220 #endif
2221  mbuf_free(&conn->recv_mbuf);
2222  mbuf_free(&conn->send_mbuf);
2223 
2224  memset(conn, 0, sizeof(*conn));
2225  MG_FREE(conn);
2226 }
2227 
2228 void mg_close_conn(struct mg_connection *conn) {
2229  DBG(("%p %lu", conn, conn->flags));
2230  mg_call(conn, NULL, MG_EV_CLOSE, NULL);
2231  mg_remove_conn(conn);
2232  mg_destroy_conn(conn);
2233 }
2234 
2235 void mg_mgr_init(struct mg_mgr *m, void *user_data) {
2236  memset(m, 0, sizeof(*m));
2237 #ifndef MG_DISABLE_SOCKETPAIR
2238  m->ctl[0] = m->ctl[1] = INVALID_SOCKET;
2239 #endif
2240  m->user_data = user_data;
2241 
2242 #ifdef _WIN32
2243  {
2244  WSADATA data;
2245  WSAStartup(MAKEWORD(2, 2), &data);
2246  }
2247 #elif defined(__unix__)
2248  /* Ignore SIGPIPE signal, so if client cancels the request, it
2249  * won't kill the whole process. */
2250  signal(SIGPIPE, SIG_IGN);
2251 #endif
2252 
2253 #ifdef MG_ENABLE_SSL
2254  {
2255  static int init_done;
2256  if (!init_done) {
2257  SSL_library_init();
2258  init_done++;
2259  }
2260  }
2261 #endif
2262 
2263  mg_ev_mgr_init(m);
2264  DBG(("=================================="));
2265  DBG(("init mgr=%p", m));
2266 }
2267 
2268 #ifdef MG_ENABLE_JAVASCRIPT
2269 static enum v7_err mg_send_js(struct v7 *v7, v7_val_t *res) {
2270  v7_val_t arg0 = v7_arg(v7, 0);
2271  v7_val_t arg1 = v7_arg(v7, 1);
2272  struct mg_connection *c = (struct mg_connection *) v7_get_ptr(arg0);
2273  size_t len = 0;
2274 
2275  if (v7_is_string(arg1)) {
2276  const char *data = v7_get_string(v7, &arg1, &len);
2277  mg_send(c, data, len);
2278  }
2279 
2280  *res = v7_mk_number(len);
2281 
2282  return V7_OK;
2283 }
2284 
2285 enum v7_err mg_enable_javascript(struct mg_mgr *m, struct v7 *v7,
2286  const char *init_file_name) {
2287  v7_val_t v;
2288  m->v7 = v7;
2289  v7_set_method(v7, v7_get_global(v7), "mg_send", mg_send_js);
2290  return v7_exec_file(v7, init_file_name, &v);
2291 }
2292 #endif
2293 
2294 void mg_mgr_free(struct mg_mgr *m) {
2295  struct mg_connection *conn, *tmp_conn;
2296 
2297  DBG(("%p", m));
2298  if (m == NULL) return;
2299  /* Do one last poll, see https://github.com/cesanta/mongoose/issues/286 */
2300  mg_mgr_poll(m, 0);
2301 
2302 #ifndef MG_DISABLE_SOCKETPAIR
2303  if (m->ctl[0] != INVALID_SOCKET) closesocket(m->ctl[0]);
2304  if (m->ctl[1] != INVALID_SOCKET) closesocket(m->ctl[1]);
2305  m->ctl[0] = m->ctl[1] = INVALID_SOCKET;
2306 #endif
2307 
2308  for (conn = m->active_connections; conn != NULL; conn = tmp_conn) {
2309  tmp_conn = conn->next;
2310  mg_close_conn(conn);
2311  }
2312 
2313  mg_ev_mgr_free(m);
2314 }
2315 
2316 int mg_vprintf(struct mg_connection *nc, const char *fmt, va_list ap) {
2317  char mem[MG_VPRINTF_BUFFER_SIZE], *buf = mem;
2318  int len;
2319 
2320  if ((len = mg_avprintf(&buf, sizeof(mem), fmt, ap)) > 0) {
2321  mg_send(nc, buf, len);
2322  }
2323  if (buf != mem && buf != NULL) {
2324  MG_FREE(buf); /* LCOV_EXCL_LINE */
2325  } /* LCOV_EXCL_LINE */
2326 
2327  return len;
2328 }
2329 
2330 int mg_printf(struct mg_connection *conn, const char *fmt, ...) {
2331  int len;
2332  va_list ap;
2333  va_start(ap, fmt);
2334  len = mg_vprintf(conn, fmt, ap);
2335  va_end(ap);
2336  return len;
2337 }
2338 
2339 #ifndef MG_DISABLE_SYNC_RESOLVER
2340 /* TODO(lsm): use non-blocking resolver */
2341 static int mg_resolve2(const char *host, struct in_addr *ina) {
2342 #ifdef MG_ENABLE_GETADDRINFO
2343  int rv = 0;
2344  struct addrinfo hints, *servinfo, *p;
2345  struct sockaddr_in *h = NULL;
2346  memset(&hints, 0, sizeof hints);
2347  hints.ai_family = AF_INET;
2348  hints.ai_socktype = SOCK_STREAM;
2349  if ((rv = getaddrinfo(host, NULL, NULL, &servinfo)) != 0) {
2350  DBG(("getaddrinfo(%s) failed: %s", host, strerror(errno)));
2351  return 0;
2352  }
2353  for (p = servinfo; p != NULL; p = p->ai_next) {
2354  memcpy(&h, &p->ai_addr, sizeof(struct sockaddr_in *));
2355  memcpy(ina, &h->sin_addr, sizeof(ina));
2356  }
2357  freeaddrinfo(servinfo);
2358  return 1;
2359 #else
2360  struct hostent *he;
2361  if ((he = gethostbyname(host)) == NULL) {
2362  DBG(("gethostbyname(%s) failed: %s", host, strerror(errno)));
2363  } else {
2364  memcpy(ina, he->h_addr_list[0], sizeof(*ina));
2365  return 1;
2366  }
2367  return 0;
2368 #endif /* MG_ENABLE_GETADDRINFO */
2369 }
2370 
2371 int mg_resolve(const char *host, char *buf, size_t n) {
2372  struct in_addr ad;
2373  return mg_resolve2(host, &ad) ? snprintf(buf, n, "%s", inet_ntoa(ad)) : 0;
2374 }
2375 #endif /* MG_DISABLE_SYNC_RESOLVER */
2376 
2378  struct mg_mgr *mgr, mg_event_handler_t callback,
2379  struct mg_add_sock_opts opts) {
2380  struct mg_connection *conn;
2381 
2382  if ((conn = (struct mg_connection *) MG_CALLOC(1, sizeof(*conn))) != NULL) {
2383  conn->sock = INVALID_SOCKET;
2384  conn->handler = callback;
2385  conn->mgr = mgr;
2386  conn->last_io_time = mg_time();
2388  conn->user_data = opts.user_data;
2389  /*
2390  * SIZE_MAX is defined as a long long constant in
2391  * system headers on some platforms and so it
2392  * doesn't compile with pedantic ansi flags.
2393  */
2394  conn->recv_mbuf_limit = ~0;
2395  } else {
2396  MG_SET_PTRPTR(opts.error_string, "failed to create connection");
2397  }
2398 
2399  return conn;
2400 }
2401 
2403  struct mg_mgr *mgr, mg_event_handler_t callback,
2404  struct mg_add_sock_opts opts) {
2405  struct mg_connection *conn = mg_create_connection_base(mgr, callback, opts);
2406 
2407  if (!mg_if_create_conn(conn)) {
2408  MG_FREE(conn);
2409  conn = NULL;
2410  MG_SET_PTRPTR(opts.error_string, "failed to init connection");
2411  }
2412 
2413  return conn;
2414 }
2415 
2416 /*
2417  * Address format: [PROTO://][HOST]:PORT
2418  *
2419  * HOST could be IPv4/IPv6 address or a host name.
2420  * `host` is a destination buffer to hold parsed HOST part. Shoud be at least
2421  * MG_MAX_HOST_LEN bytes long.
2422  * `proto` is a returned socket type, either SOCK_STREAM or SOCK_DGRAM
2423  *
2424  * Return:
2425  * -1 on parse error
2426  * 0 if HOST needs DNS lookup
2427  * >0 length of the address string
2428  */
2430  int *proto, char *host, size_t host_len) {
2431  unsigned int a, b, c, d, port = 0;
2432  int ch, len = 0;
2433 #ifdef MG_ENABLE_IPV6
2434  char buf[100];
2435 #endif
2436 
2437  /*
2438  * MacOS needs that. If we do not zero it, subsequent bind() will fail.
2439  * Also, all-zeroes in the socket address means binding to all addresses
2440  * for both IPv4 and IPv6 (INADDR_ANY and IN6ADDR_ANY_INIT).
2441  */
2442  memset(sa, 0, sizeof(*sa));
2443  sa->sin.sin_family = AF_INET;
2444 
2445  *proto = SOCK_STREAM;
2446 
2447  if (strncmp(str, "udp://", 6) == 0) {
2448  str += 6;
2449  *proto = SOCK_DGRAM;
2450  } else if (strncmp(str, "tcp://", 6) == 0) {
2451  str += 6;
2452  }
2453 
2454  if (sscanf(str, "%u.%u.%u.%u:%u%n", &a, &b, &c, &d, &port, &len) == 5) {
2455  /* Bind to a specific IPv4 address, e.g. 192.168.1.5:8080 */
2456  sa->sin.sin_addr.s_addr =
2457  htonl(((uint32_t) a << 24) | ((uint32_t) b << 16) | c << 8 | d);
2458  sa->sin.sin_port = htons((uint16_t) port);
2459 #ifdef MG_ENABLE_IPV6
2460  } else if (sscanf(str, "[%99[^]]]:%u%n", buf, &port, &len) == 2 &&
2461  inet_pton(AF_INET6, buf, &sa->sin6.sin6_addr)) {
2462  /* IPv6 address, e.g. [3ffe:2a00:100:7031::1]:8080 */
2463  sa->sin6.sin6_family = AF_INET6;
2464  sa->sin.sin_port = htons((uint16_t) port);
2465 #endif
2466 #ifndef MG_DISABLE_RESOLVER
2467  } else if (strlen(str) < host_len &&
2468  sscanf(str, "%[^ :]:%u%n", host, &port, &len) == 2) {
2469  sa->sin.sin_port = htons((uint16_t) port);
2470  if (mg_resolve_from_hosts_file(host, sa) != 0) {
2471  return 0;
2472  }
2473 #endif
2474  } else if (sscanf(str, ":%u%n", &port, &len) == 1 ||
2475  sscanf(str, "%u%n", &port, &len) == 1) {
2476  /* If only port is specified, bind to IPv4, INADDR_ANY */
2477  sa->sin.sin_port = htons((uint16_t) port);
2478  } else {
2479  return -1;
2480  }
2481 
2482  ch = str[len]; /* Character that follows the address */
2483  return port < 0xffffUL && (ch == '\0' || ch == ',' || isspace(ch)) ? len : -1;
2484 }
2485 
2486 #ifdef MG_ENABLE_SSL
2487 /*
2488  * Certificate generation script is at
2489  * https://github.com/cesanta/mongoose/blob/master/scripts/generate_ssl_certificates.sh
2490  */
2491 
2492 #ifndef MG_DISABLE_PFS
2493 /*
2494  * Cipher suite options used for TLS negotiation.
2495  * https://wiki.mozilla.org/Security/Server_Side_TLS#Recommended_configurations
2496  */
2497 static const char mg_s_cipher_list[] =
2498 #if defined(MG_SSL_CRYPTO_MODERN)
2499 "ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:"
2500 "ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:"
2501 "DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:"
2502 "ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:"
2503 "ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:"
2504 "ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:"
2505 "DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:"
2506 "DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:"
2507 "!aNULL:!eNULL:!EXPORT:!DES:!RC4:!3DES:!MD5:!PSK"
2508 #elif defined(MG_SSL_CRYPTO_OLD)
2509 "ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:"
2510 "ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:"
2511 "DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:"
2512 "ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:"
2513 "ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:"
2514 "ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:"
2515 "DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:"
2516 "DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:ECDHE-RSA-DES-CBC3-SHA:"
2517 "ECDHE-ECDSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:"
2518 "AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:DES-CBC3-SHA:"
2519 "HIGH:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:"
2520 "!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA"
2521 #else /* Default - intermediate. */
2522 "ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:"
2523 "ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:"
2524 "DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:"
2525 "ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:"
2526 "ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:"
2527 "ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:"
2528 "DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:"
2529 "DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:"
2530 "AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:CAMELLIA:"
2531 "DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:"
2532 "!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA"
2533 #endif
2534 ;
2535 
2536 /*
2537  * Default DH params for PFS cipher negotiation. This is a 2048-bit group.
2538  * Will be used if none are provided by the user in the certificate file.
2539  */
2540 static const char mg_s_default_dh_params[] =
2541 "\
2542 -----BEGIN DH PARAMETERS-----\n\
2543 MIIBCAKCAQEAlvbgD/qh9znWIlGFcV0zdltD7rq8FeShIqIhkQ0C7hYFThrBvF2E\n\
2544 Z9bmgaP+sfQwGpVlv9mtaWjvERbu6mEG7JTkgmVUJrUt/wiRzwTaCXBqZkdUO8Tq\n\
2545 +E6VOEQAilstG90ikN1Tfo+K6+X68XkRUIlgawBTKuvKVwBhuvlqTGerOtnXWnrt\n\
2546 ym//hd3cd5PBYGBix0i7oR4xdghvfR2WLVu0LgdThTBb6XP7gLd19cQ1JuBtAajZ\n\
2547 wMuPn7qlUkEFDIkAZy59/Hue/H2Q2vU/JsvVhHWCQBL4F1ofEAt50il6ZxR1QfFK\n\
2548 9VGKDC4oOgm9DlxwwBoC2FjqmvQlqVV3kwIBAg==\n\
2549 -----END DH PARAMETERS-----\n";
2550 #endif
2551 
2552 static int mg_use_ca_cert(SSL_CTX *ctx, const char *cert) {
2553  if (ctx == NULL) {
2554  return -1;
2555  } else if (cert == NULL || cert[0] == '\0') {
2556  return 0;
2557  }
2558  SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, 0);
2559  return SSL_CTX_load_verify_locations(ctx, cert, NULL) == 1 ? 0 : -2;
2560 }
2561 
2562 static int mg_use_cert(SSL_CTX *ctx, const char *pem_file) {
2563  if (ctx == NULL) {
2564  return -1;
2565  } else if (pem_file == NULL || pem_file[0] == '\0') {
2566  return 0;
2567  } else if (SSL_CTX_use_certificate_file(ctx, pem_file, 1) == 0 ||
2568  SSL_CTX_use_PrivateKey_file(ctx, pem_file, 1) == 0) {
2569  return -2;
2570  } else {
2571 #ifndef MG_DISABLE_PFS
2572  BIO *bio = NULL;
2573  DH *dh = NULL;
2574 
2575  /* Try to read DH parameters from the cert/key file. */
2576  bio = BIO_new_file(pem_file, "r");
2577  if (bio != NULL) {
2578  dh = PEM_read_bio_DHparams(bio, NULL, NULL, NULL);
2579  BIO_free(bio);
2580  }
2581  /*
2582  * If there are no DH params in the file, fall back to hard-coded ones.
2583  * Not ideal, but better than nothing.
2584  */
2585  if (dh == NULL) {
2586  bio = BIO_new_mem_buf((void *) mg_s_default_dh_params, -1);
2587  dh = PEM_read_bio_DHparams(bio, NULL, NULL, NULL);
2588  BIO_free(bio);
2589  }
2590  if (dh != NULL) {
2591  SSL_CTX_set_tmp_dh(ctx, dh);
2592  SSL_CTX_set_options(ctx, SSL_OP_SINGLE_DH_USE);
2593  DH_free(dh);
2594  }
2595 #endif
2596  SSL_CTX_set_mode(ctx, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
2597  SSL_CTX_use_certificate_chain_file(ctx, pem_file);
2598  return 0;
2599  }
2600 }
2601 
2602 /*
2603  * Turn the connection into SSL mode.
2604  * `cert` is the certificate file in PEM format. For listening connections,
2605  * certificate file must contain private key and server certificate,
2606  * concatenated. It may also contain DH params - these will be used for more
2607  * secure key exchange. `ca_cert` is a certificate authority (CA) PEM file, and
2608  * it is optional (can be set to NULL). If `ca_cert` is non-NULL, then
2609  * the connection is so-called two-way-SSL: other peer's certificate is
2610  * checked against the `ca_cert`.
2611  *
2612  * Handy OpenSSL command to generate test self-signed certificate:
2613  *
2614  * openssl req -x509 -newkey rsa:2048 -keyout key.pem -out cert.pem -days 999
2615  *
2616  * Return NULL on success, or error message on failure.
2617  */
2618 const char *mg_set_ssl(struct mg_connection *nc, const char *cert,
2619  const char *ca_cert) {
2620  const char *result = NULL;
2621  DBG(("%p %s %s", nc, (cert ? cert : ""), (ca_cert ? ca_cert : "")));
2622 
2623  if (nc->flags & MG_F_UDP) {
2624  return "SSL for UDP is not supported";
2625  }
2626 
2627  if (nc->ssl != NULL) {
2628  SSL_free(nc->ssl);
2629  nc->ssl = NULL;
2630  }
2631  if (nc->ssl_ctx != NULL) {
2632  SSL_CTX_free(nc->ssl_ctx);
2633  nc->ssl_ctx = NULL;
2634  }
2635 
2636  if ((nc->flags & MG_F_LISTENING) &&
2637  (nc->ssl_ctx = SSL_CTX_new(SSLv23_server_method())) == NULL) {
2638  result = "SSL_CTX_new() failed";
2639  } else if (!(nc->flags & MG_F_LISTENING) &&
2640  (nc->ssl_ctx = SSL_CTX_new(SSLv23_client_method())) == NULL) {
2641  result = "SSL_CTX_new() failed";
2642  } else if (mg_use_cert(nc->ssl_ctx, cert) != 0) {
2643  result = "Invalid ssl cert";
2644  } else if (mg_use_ca_cert(nc->ssl_ctx, ca_cert) != 0) {
2645  result = "Invalid CA cert";
2646  } else if (!(nc->flags & MG_F_LISTENING) &&
2647  (nc->ssl = SSL_new(nc->ssl_ctx)) == NULL) {
2648  result = "SSL_new() failed";
2649  } else if (!(nc->flags & MG_F_LISTENING) && nc->sock != INVALID_SOCKET) {
2650  /*
2651  * Socket is open here only if we are connecting to IP address
2652  * and does not open if we are connecting using async DNS resolver
2653  */
2654  SSL_set_fd(nc->ssl, nc->sock);
2655  }
2656 
2657 #ifndef MG_DISABLE_PFS
2658  SSL_CTX_set_cipher_list(nc->ssl_ctx, mg_s_cipher_list);
2659 #endif
2660  return result;
2661 }
2662 #endif /* MG_ENABLE_SSL */
2663 
2665  struct mg_add_sock_opts opts;
2666  struct mg_connection *nc;
2667  memset(&opts, 0, sizeof(opts));
2668  nc = mg_create_connection(lc->mgr, lc->handler, opts);
2669  if (nc == NULL) return NULL;
2670  nc->listener = lc;
2671  nc->proto_handler = lc->proto_handler;
2672  nc->user_data = lc->user_data;
2673  nc->recv_mbuf_limit = lc->recv_mbuf_limit;
2674  mg_add_conn(nc->mgr, nc);
2675  DBG(("%p %p %d %d, %p %p", lc, nc, nc->sock, (int) nc->flags, lc->ssl_ctx,
2676  nc->ssl));
2677  return nc;
2678 }
2679 
2681  size_t sa_len) {
2682  (void) sa_len;
2683  nc->sa = *sa;
2684  mg_call(nc, NULL, MG_EV_ACCEPT, &nc->sa);
2685 }
2686 
2687 void mg_send(struct mg_connection *nc, const void *buf, int len) {
2688  nc->last_io_time = mg_time();
2689  if (nc->flags & MG_F_UDP) {
2690  mg_if_udp_send(nc, buf, len);
2691  } else {
2692  mg_if_tcp_send(nc, buf, len);
2693  }
2694 #if !defined(NO_LIBC) && !defined(MG_DISABLE_HEXDUMP)
2695  if (nc->mgr && nc->mgr->hexdump_file != NULL) {
2696  mg_hexdump_connection(nc, nc->mgr->hexdump_file, buf, len, MG_EV_SEND);
2697  }
2698 #endif
2699 }
2700 
2701 void mg_if_sent_cb(struct mg_connection *nc, int num_sent) {
2702  if (num_sent < 0) {
2704  }
2705  mg_call(nc, NULL, MG_EV_SEND, &num_sent);
2706 }
2707 
2708 static void mg_recv_common(struct mg_connection *nc, void *buf, int len) {
2709  DBG(("%p %d %u", nc, len, (unsigned int) nc->recv_mbuf.len));
2710  if (nc->flags & MG_F_CLOSE_IMMEDIATELY) {
2711  DBG(("%p discarded %d bytes", nc, len));
2712  /*
2713  * This connection will not survive next poll. Do not deliver events,
2714  * send data to /dev/null without acking.
2715  */
2716  MG_FREE(buf);
2717  return;
2718  }
2719  nc->last_io_time = mg_time();
2720  if (nc->recv_mbuf.len == 0) {
2721  /* Adopt buf as recv_mbuf's backing store. */
2722  mbuf_free(&nc->recv_mbuf);
2723  nc->recv_mbuf.buf = (char *) buf;
2724  nc->recv_mbuf.size = nc->recv_mbuf.len = len;
2725  } else {
2726  mbuf_append(&nc->recv_mbuf, buf, len);
2727  MG_FREE(buf);
2728  }
2729  mg_call(nc, NULL, MG_EV_RECV, &len);
2730 }
2731 
2732 void mg_if_recv_tcp_cb(struct mg_connection *nc, void *buf, int len) {
2733  mg_recv_common(nc, buf, len);
2734 }
2735 
2736 void mg_if_recv_udp_cb(struct mg_connection *nc, void *buf, int len,
2737  union socket_address *sa, size_t sa_len) {
2738  assert(nc->flags & MG_F_UDP);
2739  DBG(("%p %u", nc, (unsigned int) len));
2740  if (nc->flags & MG_F_LISTENING) {
2741  struct mg_connection *lc = nc;
2742  /*
2743  * Do we have an existing connection for this source?
2744  * This is very inefficient for long connection lists.
2745  */
2746  for (nc = mg_next(lc->mgr, NULL); nc != NULL; nc = mg_next(lc->mgr, nc)) {
2747  if (memcmp(&nc->sa.sa, &sa->sa, sa_len) == 0 && nc->listener == lc) {
2748  break;
2749  }
2750  }
2751  if (nc == NULL) {
2752  struct mg_add_sock_opts opts;
2753  memset(&opts, 0, sizeof(opts));
2754  /* Create fake connection w/out sock initialization */
2755  nc = mg_create_connection_base(lc->mgr, lc->handler, opts);
2756  if (nc != NULL) {
2757  nc->sock = lc->sock;
2758  nc->listener = lc;
2759  nc->sa = *sa;
2760  nc->proto_handler = lc->proto_handler;
2761  nc->user_data = lc->user_data;
2762  nc->recv_mbuf_limit = lc->recv_mbuf_limit;
2763  nc->flags = MG_F_UDP;
2764  mg_add_conn(lc->mgr, nc);
2765  mg_call(nc, NULL, MG_EV_ACCEPT, &nc->sa);
2766  } else {
2767  DBG(("OOM"));
2768  /* No return here, we still need to drop on the floor */
2769  }
2770  }
2771  }
2772  if (nc != NULL) {
2773  mg_recv_common(nc, buf, len);
2774  } else {
2775  /* Drop on the floor. */
2776  MG_FREE(buf);
2777  mg_if_recved(nc, len);
2778  }
2779 }
2780 
2781 /*
2782  * Schedules an async connect for a resolved address and proto.
2783  * Called from two places: `mg_connect_opt()` and from async resolver.
2784  * When called from the async resolver, it must trigger `MG_EV_CONNECT` event
2785  * with a failure flag to indicate connection failure.
2786  */
2788  int proto,
2789  union socket_address *sa) {
2790  DBG(("%p %s://%s:%hu", nc, proto == SOCK_DGRAM ? "udp" : "tcp",
2791  inet_ntoa(sa->sin.sin_addr), ntohs(sa->sin.sin_port)));
2792 
2793  nc->flags |= MG_F_CONNECTING;
2794  if (proto == SOCK_DGRAM) {
2795  mg_if_connect_udp(nc);
2796  } else {
2797  mg_if_connect_tcp(nc, sa);
2798  }
2799  mg_add_conn(nc->mgr, nc);
2800  return nc;
2801 }
2802 
2803 void mg_if_connect_cb(struct mg_connection *nc, int err) {
2804  DBG(("%p connect, err=%d", nc, err));
2805  nc->flags &= ~MG_F_CONNECTING;
2806  if (err != 0) {
2808  }
2809  mg_call(nc, NULL, MG_EV_CONNECT, &err);
2810 }
2811 
2812 #ifndef MG_DISABLE_RESOLVER
2813 /*
2814  * Callback for the async resolver on mg_connect_opt() call.
2815  * Main task of this function is to trigger MG_EV_CONNECT event with
2816  * either failure (and dealloc the connection)
2817  * or success (and proceed with connect()
2818  */
2819 static void resolve_cb(struct mg_dns_message *msg, void *data,
2820  enum mg_resolve_err e) {
2821  struct mg_connection *nc = (struct mg_connection *) data;
2822  int i;
2823  int failure = -1;
2824 
2825  nc->flags &= ~MG_F_RESOLVING;
2826  if (msg != NULL) {
2827  /*
2828  * Take the first DNS A answer and run...
2829  */
2830  for (i = 0; i < msg->num_answers; i++) {
2831  if (msg->answers[i].rtype == MG_DNS_A_RECORD) {
2832  /*
2833  * Async resolver guarantees that there is at least one answer.
2834  * TODO(lsm): handle IPv6 answers too
2835  */
2836  mg_dns_parse_record_data(msg, &msg->answers[i], &nc->sa.sin.sin_addr,
2837  4);
2838  mg_do_connect(nc, nc->flags & MG_F_UDP ? SOCK_DGRAM : SOCK_STREAM,
2839  &nc->sa);
2840  return;
2841  }
2842  }
2843  }
2844 
2845  if (e == MG_RESOLVE_TIMEOUT) {
2846  double now = mg_time();
2847  mg_call(nc, NULL, MG_EV_TIMER, &now);
2848  }
2849 
2850  /*
2851  * If we get there was no MG_DNS_A_RECORD in the answer
2852  */
2853  mg_call(nc, NULL, MG_EV_CONNECT, &failure);
2854  mg_call(nc, NULL, MG_EV_CLOSE, NULL);
2855  mg_destroy_conn(nc);
2856 }
2857 #endif
2858 
2859 struct mg_connection *mg_connect(struct mg_mgr *mgr, const char *address,
2860  mg_event_handler_t callback) {
2861  struct mg_connect_opts opts;
2862  memset(&opts, 0, sizeof(opts));
2863  return mg_connect_opt(mgr, address, callback, opts);
2864 }
2865 
2866 struct mg_connection *mg_connect_opt(struct mg_mgr *mgr, const char *address,
2867  mg_event_handler_t callback,
2868  struct mg_connect_opts opts) {
2869  struct mg_connection *nc = NULL;
2870  int proto, rc;
2871  struct mg_add_sock_opts add_sock_opts;
2872  char host[MG_MAX_HOST_LEN];
2873 
2874  MG_COPY_COMMON_CONNECTION_OPTIONS(&add_sock_opts, &opts);
2875 
2876  if ((nc = mg_create_connection(mgr, callback, add_sock_opts)) == NULL) {
2877  return NULL;
2878  } else if ((rc = mg_parse_address(address, &nc->sa, &proto, host,
2879  sizeof(host))) < 0) {
2880  /* Address is malformed */
2881  MG_SET_PTRPTR(opts.error_string, "cannot parse address");
2882  mg_destroy_conn(nc);
2883  return NULL;
2884  }
2886  nc->flags |= (proto == SOCK_DGRAM) ? MG_F_UDP : 0;
2887  nc->user_data = opts.user_data;
2888 
2889 #ifdef MG_ENABLE_SSL
2890  if (opts.ssl_cert != NULL || opts.ssl_ca_cert != NULL) {
2891  const char *err = mg_set_ssl(nc, opts.ssl_cert, opts.ssl_ca_cert);
2892  if (err != NULL) {
2893  MG_SET_PTRPTR(opts.error_string, err);
2894  mg_destroy_conn(nc);
2895  return NULL;
2896  }
2897  if (opts.ssl_ca_cert != NULL && (opts.ssl_server_name == NULL ||
2898  strcmp(opts.ssl_server_name, "*") != 0)) {
2899  if (opts.ssl_server_name == NULL) opts.ssl_server_name = host;
2900 #ifdef SSL_KRYPTON
2901  SSL_CTX_kr_set_verify_name(nc->ssl_ctx, opts.ssl_server_name);
2902 #else
2903  /* TODO(rojer): Implement server name verification on OpenSSL. */
2905  "Server name verification requested but is not supported");
2906  mg_destroy_conn(nc);
2907  return NULL;
2908 #endif /* SSL_KRYPTON */
2909  }
2910  }
2911 #endif /* MG_ENABLE_SSL */
2912 
2913  if (rc == 0) {
2914 #ifndef MG_DISABLE_RESOLVER
2915  /*
2916  * DNS resolution is required for host.
2917  * mg_parse_address() fills port in nc->sa, which we pass to resolve_cb()
2918  */
2919  struct mg_connection *dns_conn = NULL;
2920  struct mg_resolve_async_opts o;
2921  memset(&o, 0, sizeof(o));
2922  o.dns_conn = &dns_conn;
2923  if (mg_resolve_async_opt(nc->mgr, host, MG_DNS_A_RECORD, resolve_cb, nc,
2924  o) != 0) {
2925  MG_SET_PTRPTR(opts.error_string, "cannot schedule DNS lookup");
2926  mg_destroy_conn(nc);
2927  return NULL;
2928  }
2929  nc->priv_2 = dns_conn;
2930  nc->flags |= MG_F_RESOLVING;
2931  return nc;
2932 #else
2933  MG_SET_PTRPTR(opts.error_string, "Resolver is disabled");
2934  mg_destroy_conn(nc);
2935  return NULL;
2936 #endif
2937  } else {
2938  /* Address is parsed and resolved to IP. proceed with connect() */
2939  return mg_do_connect(nc, proto, &nc->sa);
2940  }
2941 }
2942 
2943 struct mg_connection *mg_bind(struct mg_mgr *srv, const char *address,
2944  mg_event_handler_t event_handler) {
2945  struct mg_bind_opts opts;
2946  memset(&opts, 0, sizeof(opts));
2947  return mg_bind_opt(srv, address, event_handler, opts);
2948 }
2949 
2950 struct mg_connection *mg_bind_opt(struct mg_mgr *mgr, const char *address,
2951  mg_event_handler_t callback,
2952  struct mg_bind_opts opts) {
2953  union socket_address sa;
2954  struct mg_connection *nc = NULL;
2955  int proto, rc;
2956  struct mg_add_sock_opts add_sock_opts;
2957  char host[MG_MAX_HOST_LEN];
2958 
2959  MG_COPY_COMMON_CONNECTION_OPTIONS(&add_sock_opts, &opts);
2960 
2961  if (mg_parse_address(address, &sa, &proto, host, sizeof(host)) <= 0) {
2962  MG_SET_PTRPTR(opts.error_string, "cannot parse address");
2963  return NULL;
2964  }
2965 
2966  nc = mg_create_connection(mgr, callback, add_sock_opts);
2967  if (nc == NULL) {
2968  return NULL;
2969  }
2970 
2971  nc->sa = sa;
2972  nc->flags |= MG_F_LISTENING;
2973  if (proto == SOCK_DGRAM) {
2974  nc->flags |= MG_F_UDP;
2975  rc = mg_if_listen_udp(nc, &nc->sa);
2976  } else {
2977  rc = mg_if_listen_tcp(nc, &nc->sa);
2978  }
2979  if (rc != 0) {
2980  DBG(("Failed to open listener: %d", rc));
2981  MG_SET_PTRPTR(opts.error_string, "failed to open listener");
2982  mg_destroy_conn(nc);
2983  return NULL;
2984  }
2985 #ifdef MG_ENABLE_SSL
2986  if (opts.ssl_cert != NULL || opts.ssl_ca_cert != NULL) {
2987  const char *err = mg_set_ssl(nc, opts.ssl_cert, opts.ssl_ca_cert);
2988  if (err != NULL) {
2989  MG_SET_PTRPTR(opts.error_string, err);
2990  mg_destroy_conn(nc);
2991  return NULL;
2992  }
2993  }
2994 #endif /* MG_ENABLE_SSL */
2995  mg_add_conn(nc->mgr, nc);
2996 
2997  return nc;
2998 }
2999 
3000 struct mg_connection *mg_next(struct mg_mgr *s, struct mg_connection *conn) {
3001  return conn == NULL ? s->active_connections : conn->next;
3002 }
3003 
3004 #ifndef MG_DISABLE_SOCKETPAIR
3006  size_t len) {
3007  struct ctl_msg ctl_msg;
3008 
3009  /*
3010  * Mongoose manager has a socketpair, `struct mg_mgr::ctl`,
3011  * where `mg_broadcast()` pushes the message.
3012  * `mg_mgr_poll()` wakes up, reads a message from the socket pair, and calls
3013  * specified callback for each connection. Thus the callback function executes
3014  * in event manager thread.
3015  */
3016  if (mgr->ctl[0] != INVALID_SOCKET && data != NULL &&
3017  len < sizeof(ctl_msg.message)) {
3018  size_t dummy;
3019 
3020  ctl_msg.callback = cb;
3021  memcpy(ctl_msg.message, data, len);
3022  dummy = MG_SEND_FUNC(mgr->ctl[0], (char *) &ctl_msg,
3023  offsetof(struct ctl_msg, message) + len, 0);
3024  dummy = MG_RECV_FUNC(mgr->ctl[0], (char *) &len, 1, 0);
3025  (void) dummy; /* https://gcc.gnu.org/bugzilla/show_bug.cgi?id=25509 */
3026  }
3027 }
3028 #endif /* MG_DISABLE_SOCKETPAIR */
3029 
3030 static int isbyte(int n) {
3031  return n >= 0 && n <= 255;
3032 }
3033 
3034 static int parse_net(const char *spec, uint32_t *net, uint32_t *mask) {
3035  int n, a, b, c, d, slash = 32, len = 0;
3036 
3037  if ((sscanf(spec, "%d.%d.%d.%d/%d%n", &a, &b, &c, &d, &slash, &n) == 5 ||
3038  sscanf(spec, "%d.%d.%d.%d%n", &a, &b, &c, &d, &n) == 4) &&
3039  isbyte(a) && isbyte(b) && isbyte(c) && isbyte(d) && slash >= 0 &&
3040  slash < 33) {
3041  len = n;
3042  *net =
3043  ((uint32_t) a << 24) | ((uint32_t) b << 16) | ((uint32_t) c << 8) | d;
3044  *mask = slash ? 0xffffffffU << (32 - slash) : 0;
3045  }
3046 
3047  return len;
3048 }
3049 
3050 int mg_check_ip_acl(const char *acl, uint32_t remote_ip) {
3051  int allowed, flag;
3052  uint32_t net, mask;
3053  struct mg_str vec;
3054 
3055  /* If any ACL is set, deny by default */
3056  allowed = (acl == NULL || *acl == '\0') ? '+' : '-';
3057 
3058  while ((acl = mg_next_comma_list_entry(acl, &vec, NULL)) != NULL) {
3059  flag = vec.p[0];
3060  if ((flag != '+' && flag != '-') ||
3061  parse_net(&vec.p[1], &net, &mask) == 0) {
3062  return -1;
3063  }
3064 
3065  if (net == (remote_ip & mask)) {
3066  allowed = flag;
3067  }
3068  }
3069 
3070  DBG(("%08x %c", remote_ip, allowed));
3071  return allowed == '+';
3072 }
3073 
3074 /* Move data from one connection to another */
3075 void mg_forward(struct mg_connection *from, struct mg_connection *to) {
3076  mg_send(to, from->recv_mbuf.buf, from->recv_mbuf.len);
3077  mbuf_remove(&from->recv_mbuf, from->recv_mbuf.len);
3078 }
3079 
3080 double mg_set_timer(struct mg_connection *c, double timestamp) {
3081  double result = c->ev_timer_time;
3082  c->ev_timer_time = timestamp;
3083  /*
3084  * If this connection is resolving, it's not in the list of active
3085  * connections, so not processed yet. It has a DNS resolver connection
3086  * linked to it. Set up a timer for the DNS connection.
3087  */
3088  DBG(("%p %p %d -> %lu", c, c->priv_2, c->flags & MG_F_RESOLVING,
3089  (unsigned long) timestamp));
3090  if ((c->flags & MG_F_RESOLVING) && c->priv_2 != NULL) {
3091  ((struct mg_connection *) c->priv_2)->ev_timer_time = timestamp;
3092  }
3093  return result;
3094 }
3095 
3096 struct mg_connection *mg_add_sock_opt(struct mg_mgr *s, sock_t sock,
3097  mg_event_handler_t callback,
3098  struct mg_add_sock_opts opts) {
3099  struct mg_connection *nc = mg_create_connection_base(s, callback, opts);
3100  if (nc != NULL) {
3101  mg_sock_set(nc, sock);
3102  mg_add_conn(nc->mgr, nc);
3103  }
3104  return nc;
3105 }
3106 
3107 struct mg_connection *mg_add_sock(struct mg_mgr *s, sock_t sock,
3108  mg_event_handler_t callback) {
3109  struct mg_add_sock_opts opts;
3110  memset(&opts, 0, sizeof(opts));
3111  return mg_add_sock_opt(s, sock, callback, opts);
3112 }
3113 
3114 double mg_time() {
3115  return cs_time();
3116 }
3117 #ifdef MG_MODULE_LINES
3118 #line 1 "./src/net_if_socket.c"
3119 #endif
3120 /*
3121  * Copyright (c) 2014-2016 Cesanta Software Limited
3122  * All rights reserved
3123  */
3124 
3125 #ifndef MG_DISABLE_SOCKET_IF
3126 
3127 /* Amalgamated: #include "mongoose/src/internal.h" */
3128 /* Amalgamated: #include "mongoose/src/util.h" */
3129 
3130 #define MG_TCP_RECV_BUFFER_SIZE 1024
3131 #define MG_UDP_RECV_BUFFER_SIZE 1500
3132 
3133 static sock_t mg_open_listening_socket(union socket_address *sa, int proto);
3134 #ifdef MG_ENABLE_SSL
3135 static void mg_ssl_begin(struct mg_connection *nc);
3136 static int mg_ssl_err(struct mg_connection *conn, int res);
3137 #endif
3138 
3139 void mg_set_non_blocking_mode(sock_t sock) {
3140 #ifdef _WIN32
3141  unsigned long on = 1;
3142  ioctlsocket(sock, FIONBIO, &on);
3143 #elif defined(MG_SOCKET_SIMPLELINK)
3144  SlSockNonblocking_t opt;
3145  opt.NonblockingEnabled = 1;
3146  sl_SetSockOpt(sock, SL_SOL_SOCKET, SL_SO_NONBLOCKING, &opt, sizeof(opt));
3147 #else
3148  int flags = fcntl(sock, F_GETFL, 0);
3149  fcntl(sock, F_SETFL, flags | O_NONBLOCK);
3150 #endif
3151 }
3152 
3153 int mg_is_error(int n) {
3154 #ifdef MG_SOCKET_SIMPLELINK
3155  DBG(("n = %d, errno = %d", n, errno));
3156  if (n < 0) errno = n;
3157 #endif
3158  return n == 0 || (n < 0 && errno != EINTR && errno != EINPROGRESS &&
3159  errno != EAGAIN && errno != EWOULDBLOCK
3160 #ifdef MG_SOCKET_SIMPLELINK
3161  && errno != SL_EALREADY
3162 #endif
3163 #ifdef _WIN32
3164  && WSAGetLastError() != WSAEINTR &&
3165  WSAGetLastError() != WSAEWOULDBLOCK
3166 #endif
3167  );
3168 }
3169 
3171  const union socket_address *sa) {
3172  int rc;
3173  nc->sock = socket(AF_INET, SOCK_STREAM, 0);
3174  if (nc->sock == INVALID_SOCKET) {
3175  nc->err = errno ? errno : 1;
3176  return;
3177  }
3178 #if !defined(MG_SOCKET_SIMPLELINK) && !defined(MG_ESP8266)
3180 #endif
3181  rc = connect(nc->sock, &sa->sa, sizeof(sa->sin));
3182  nc->err = mg_is_error(rc) ? errno : 0;
3183  DBG(("%p sock %d err %d", nc, nc->sock, nc->err));
3184 }
3185 
3187  nc->sock = socket(AF_INET, SOCK_DGRAM, 0);
3188  if (nc->sock == INVALID_SOCKET) {
3189  nc->err = errno ? errno : 1;
3190  return;
3191  }
3192  nc->err = 0;
3193 }
3194 
3195 int mg_if_listen_tcp(struct mg_connection *nc, union socket_address *sa) {
3196  sock_t sock = mg_open_listening_socket(sa, SOCK_STREAM);
3197  if (sock == INVALID_SOCKET) {
3198  return (errno ? errno : 1);
3199  }
3200  mg_sock_set(nc, sock);
3201  return 0;
3202 }
3203 
3204 int mg_if_listen_udp(struct mg_connection *nc, union socket_address *sa) {
3205  sock_t sock = mg_open_listening_socket(sa, SOCK_DGRAM);
3206  if (sock == INVALID_SOCKET) return (errno ? errno : 1);
3207  mg_sock_set(nc, sock);
3208  return 0;
3209 }
3210 
3211 void mg_if_tcp_send(struct mg_connection *nc, const void *buf, size_t len) {
3212  mbuf_append(&nc->send_mbuf, buf, len);
3213 }
3214 
3215 void mg_if_udp_send(struct mg_connection *nc, const void *buf, size_t len) {
3216  mbuf_append(&nc->send_mbuf, buf, len);
3217 }
3218 
3219 void mg_if_recved(struct mg_connection *nc, size_t len) {
3220  (void) nc;
3221  (void) len;
3222 }
3223 
3225  (void) nc;
3226  return 1;
3227 }
3228 
3230  if (nc->sock == INVALID_SOCKET) return;
3231  if (!(nc->flags & MG_F_UDP)) {
3232  closesocket(nc->sock);
3233  } else {
3234  /* Only close outgoing UDP sockets or listeners. */
3235  if (nc->listener == NULL) closesocket(nc->sock);
3236  }
3237  /*
3238  * avoid users accidentally double close a socket
3239  * because it can lead to difficult to debug situations.
3240  * It would happen only if reusing a destroyed mg_connection
3241  * but it's not always possible to run the code through an
3242  * address sanitizer.
3243  */
3244  nc->sock = INVALID_SOCKET;
3245 }
3246 
3247 static int mg_accept_conn(struct mg_connection *lc) {
3248  struct mg_connection *nc;
3249  union socket_address sa;
3250  socklen_t sa_len = sizeof(sa);
3251  /* NOTE(lsm): on Windows, sock is always > FD_SETSIZE */
3252  sock_t sock = accept(lc->sock, &sa.sa, &sa_len);
3253  if (sock == INVALID_SOCKET) {
3254  if (mg_is_error(-1)) DBG(("%p: failed to accept: %d", lc, errno));
3255  return 0;
3256  }
3257  nc = mg_if_accept_new_conn(lc);
3258  if (nc == NULL) {
3259  closesocket(sock);
3260  return 0;
3261  }
3262  DBG(("%p conn from %s:%d", nc, inet_ntoa(sa.sin.sin_addr),
3263  ntohs(sa.sin.sin_port)));
3264  mg_sock_set(nc, sock);
3265 #ifdef MG_ENABLE_SSL
3266  if (lc->ssl_ctx != NULL) {
3267  nc->ssl = SSL_new(lc->ssl_ctx);
3268  if (nc->ssl == NULL || SSL_set_fd(nc->ssl, sock) != 1) {
3269  DBG(("SSL error"));
3270  mg_close_conn(nc);
3271  }
3272  } else
3273 #endif
3274  {
3275  mg_if_accept_tcp_cb(nc, &sa, sa_len);
3276  }
3277  return 1;
3278 }
3279 
3280 /* 'sa' must be an initialized address to bind to */
3281 static sock_t mg_open_listening_socket(union socket_address *sa, int proto) {
3282  socklen_t sa_len =
3283  (sa->sa.sa_family == AF_INET) ? sizeof(sa->sin) : sizeof(sa->sin6);
3284  sock_t sock = INVALID_SOCKET;
3285 #if !defined(MG_SOCKET_SIMPLELINK) && !defined(MG_LWIP)
3286  int on = 1;
3287 #endif
3288 
3289  if ((sock = socket(sa->sa.sa_family, proto, 0)) != INVALID_SOCKET &&
3290 #if !defined(MG_SOCKET_SIMPLELINK) && \
3291 !defined(MG_LWIP) /* SimpleLink and LWIP don't support either */
3292 #if defined(_WIN32) && defined(SO_EXCLUSIVEADDRUSE)
3293  /* "Using SO_REUSEADDR and SO_EXCLUSIVEADDRUSE" http://goo.gl/RmrFTm */
3294  !setsockopt(sock, SOL_SOCKET, SO_EXCLUSIVEADDRUSE, (void *) &on,
3295  sizeof(on)) &&
3296 #endif
3297 
3298 #if !defined(_WIN32) || !defined(SO_EXCLUSIVEADDRUSE)
3299  /*
3300  * SO_RESUSEADDR is not enabled on Windows because the semantics of
3301  * SO_REUSEADDR on UNIX and Windows is different. On Windows,
3302  * SO_REUSEADDR allows to bind a socket to a port without error even if
3303  * the port is already open by another program. This is not the behavior
3304  * SO_REUSEADDR was designed for, and leads to hard-to-track failure
3305  * scenarios. Therefore, SO_REUSEADDR was disabled on Windows unless
3306  * SO_EXCLUSIVEADDRUSE is supported and set on a socket.
3307  */
3308  !setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void *) &on, sizeof(on)) &&
3309 #endif
3310 #endif /* !MG_SOCKET_SIMPLELINK && !MG_LWIP */
3311 
3312  !bind(sock, &sa->sa, sa_len) &&
3313  (proto == SOCK_DGRAM || listen(sock, SOMAXCONN) == 0)) {
3314 #if !defined(MG_SOCKET_SIMPLELINK) && \
3315 !defined(MG_LWIP) /* TODO(rojer): Fix this. */
3317  /* In case port was set to 0, get the real port number */
3318  (void) getsockname(sock, &sa->sa, &sa_len);
3319 #endif
3320  } else if (sock != INVALID_SOCKET) {
3321  closesocket(sock);
3322  sock = INVALID_SOCKET;
3323  }
3324 
3325  return sock;
3326 }
3327 
3328 static void mg_write_to_socket(struct mg_connection *nc) {
3329  struct mbuf *io = &nc->send_mbuf;
3330  int n = 0;
3331 
3332 #ifdef MG_LWIP
3333  /* With LWIP we don't know if the socket is ready */
3334  if (io->len == 0) return;
3335 #endif
3336 
3337  assert(io->len > 0);
3338 
3339  if (nc->flags & MG_F_UDP) {
3340  int n =
3341  sendto(nc->sock, io->buf, io->len, 0, &nc->sa.sa, sizeof(nc->sa.sin));
3342  DBG(("%p %d %d %d %s:%hu", nc, nc->sock, n, errno,
3343  inet_ntoa(nc->sa.sin.sin_addr), ntohs(nc->sa.sin.sin_port)));
3344  if (n > 0) {
3345  mbuf_remove(io, n);
3346  }
3347  mg_if_sent_cb(nc, n);
3348  return;
3349  }
3350 
3351 #ifdef MG_ENABLE_SSL
3352  if (nc->ssl != NULL) {
3353  if (nc->flags & MG_F_SSL_HANDSHAKE_DONE) {
3354  n = SSL_write(nc->ssl, io->buf, io->len);
3355  DBG(("%p %d bytes -> %d (SSL)", nc, n, nc->sock));
3356  if (n <= 0) {
3357  int ssl_err = mg_ssl_err(nc, n);
3358  if (ssl_err == SSL_ERROR_WANT_READ || ssl_err == SSL_ERROR_WANT_WRITE) {
3359  return; /* Call us again */
3360  }
3361  } else {
3362  /* Successful SSL operation, clear off SSL wait flags */
3363  nc->flags &= ~(MG_F_WANT_READ | MG_F_WANT_WRITE);
3364  }
3365  } else {
3366  mg_ssl_begin(nc);
3367  return;
3368  }
3369  } else
3370 #endif
3371  {
3372  n = (int) MG_SEND_FUNC(nc->sock, io->buf, io->len, 0);
3373  DBG(("%p %d bytes -> %d", nc, n, nc->sock));
3374  if (n < 0 && !mg_is_error(n)) return;
3375  }
3376 
3377  if (n > 0) {
3378  mbuf_remove(io, n);
3379  }
3380  mg_if_sent_cb(nc, n);
3381 }
3382 
3383 MG_INTERNAL size_t recv_avail_size(struct mg_connection *conn, size_t max) {
3384  size_t avail;
3385  if (conn->recv_mbuf_limit < conn->recv_mbuf.len) return 0;
3386  avail = conn->recv_mbuf_limit - conn->recv_mbuf.len;
3387  return avail > max ? max : avail;
3388 }
3389 
3390 static void mg_read_from_socket(struct mg_connection *conn) {
3391  int n = 0;
3392  char *buf = (char *) MG_MALLOC(MG_TCP_RECV_BUFFER_SIZE);
3393 
3394  if (buf == NULL) {
3395  DBG(("OOM"));
3396  return;
3397  }
3398 
3399 #ifdef MG_ENABLE_SSL
3400  if (conn->ssl != NULL) {
3401  if (conn->flags & MG_F_SSL_HANDSHAKE_DONE) {
3402  /* SSL library may have more bytes ready to read then we ask to read.
3403  * Therefore, read in a loop until we read everything. Without the loop,
3404  * we skip to the next select() cycle which can just timeout. */
3405  while ((n = SSL_read(conn->ssl, buf, MG_TCP_RECV_BUFFER_SIZE)) > 0) {
3406  DBG(("%p %d bytes <- %d (SSL)", conn, n, conn->sock));
3407  mg_if_recv_tcp_cb(conn, buf, n);
3408  buf = NULL;
3409  if (conn->flags & MG_F_CLOSE_IMMEDIATELY) break;
3410  /* buf has been freed, we need a new one. */
3411  buf = (char *) MG_MALLOC(MG_TCP_RECV_BUFFER_SIZE);
3412  if (buf == NULL) break;
3413  }
3414  MG_FREE(buf);
3415  mg_ssl_err(conn, n);
3416  } else {
3417  MG_FREE(buf);
3418  mg_ssl_begin(conn);
3419  return;
3420  }
3421  } else
3422 #endif
3423  {
3424  n = (int) MG_RECV_FUNC(conn->sock, buf,
3426  DBG(("%p %d bytes (PLAIN) <- %d", conn, n, conn->sock));
3427  if (n > 0) {
3428  mg_if_recv_tcp_cb(conn, buf, n);
3429  } else {
3430  MG_FREE(buf);
3431  }
3432  if (n == 0) {
3433  /* Orderly shutdown of the socket, try flushing output. */
3434  conn->flags |= MG_F_SEND_AND_CLOSE;
3435  } else if (mg_is_error(n)) {
3436  conn->flags |= MG_F_CLOSE_IMMEDIATELY;
3437  }
3438  }
3439 }
3440 
3441 static int mg_recvfrom(struct mg_connection *nc, union socket_address *sa,
3442  socklen_t *sa_len, char **buf) {
3443  int n;
3444  *buf = (char *) MG_MALLOC(MG_UDP_RECV_BUFFER_SIZE);
3445  if (*buf == NULL) {
3446  DBG(("Out of memory"));
3447  return -ENOMEM;
3448  }
3449  n = recvfrom(nc->sock, *buf, MG_UDP_RECV_BUFFER_SIZE, 0, &sa->sa, sa_len);
3450  if (n <= 0) {
3451  DBG(("%p recvfrom: %s", nc, strerror(errno)));
3452  MG_FREE(*buf);
3453  }
3454  return n;
3455 }
3456 
3457 static void mg_handle_udp_read(struct mg_connection *nc) {
3458  char *buf = NULL;
3459  union socket_address sa;
3460  socklen_t sa_len = sizeof(sa);
3461  int n = mg_recvfrom(nc, &sa, &sa_len, &buf);
3462  DBG(("%p %d bytes from %s:%d", nc, n, inet_ntoa(nc->sa.sin.sin_addr),
3463  ntohs(nc->sa.sin.sin_port)));
3464  mg_if_recv_udp_cb(nc, buf, n, &sa, sa_len);
3465 }
3466 
3467 #ifdef MG_ENABLE_SSL
3468 static int mg_ssl_err(struct mg_connection *conn, int res) {
3469  int ssl_err = SSL_get_error(conn->ssl, res);
3470  DBG(("%p %d -> %d", conn, res, ssl_err));
3471  if (ssl_err == SSL_ERROR_WANT_READ) {
3472  conn->flags |= MG_F_WANT_READ;
3473  } else if (ssl_err == SSL_ERROR_WANT_WRITE) {
3474  conn->flags |= MG_F_WANT_WRITE;
3475  } else {
3476  /* There could be an alert to deliver. Try our best. */
3477  SSL_write(conn->ssl, "", 0);
3478  conn->flags |= MG_F_CLOSE_IMMEDIATELY;
3479  }
3480  return ssl_err;
3481 }
3482 
3483 static void mg_ssl_begin(struct mg_connection *nc) {
3484  int server_side = (nc->listener != NULL);
3485  int res = server_side ? SSL_accept(nc->ssl) : SSL_connect(nc->ssl);
3486  DBG(("%p %d res %d %d", nc, server_side, res, errno));
3487 
3488  if (res == 1) {
3490  nc->flags &= ~(MG_F_WANT_READ | MG_F_WANT_WRITE);
3491 
3492  if (server_side) {
3493  union socket_address sa;
3494  socklen_t sa_len = sizeof(sa);
3495  (void) getpeername(nc->sock, &sa.sa, &sa_len);
3496  mg_if_accept_tcp_cb(nc, &sa, sa_len);
3497  } else {
3498  mg_if_connect_cb(nc, 0);
3499  }
3500  } else {
3501  int ssl_err = mg_ssl_err(nc, res);
3502  if (ssl_err != SSL_ERROR_WANT_READ && ssl_err != SSL_ERROR_WANT_WRITE) {
3503  if (!server_side) {
3504  mg_if_connect_cb(nc, ssl_err);
3505  }
3507  }
3508  }
3509 }
3510 #endif /* MG_ENABLE_SSL */
3511 
3512 #define _MG_F_FD_CAN_READ 1
3513 #define _MG_F_FD_CAN_WRITE 1 << 1
3514 #define _MG_F_FD_ERROR 1 << 2
3515 
3516 void mg_mgr_handle_conn(struct mg_connection *nc, int fd_flags, double now) {
3517  DBG(("%p fd=%d fd_flags=%d nc_flags=%lu rmbl=%d smbl=%d", nc, nc->sock,
3518  fd_flags, nc->flags, (int) nc->recv_mbuf.len, (int) nc->send_mbuf.len));
3519 
3520  if (nc->flags & MG_F_CONNECTING) {
3521  if (fd_flags != 0) {
3522  int err = 0;
3523 #if !defined(MG_SOCKET_SIMPLELINK) && !defined(MG_ESP8266)
3524  if (!(nc->flags & MG_F_UDP)) {
3525  socklen_t len = sizeof(err);
3526  int ret =
3527  getsockopt(nc->sock, SOL_SOCKET, SO_ERROR, (char *) &err, &len);
3528  if (ret != 0) err = 1;
3529  }
3530 #else
3531  /* On SimpleLink and ESP8266 we use blocking connect. If we got as far as
3532  * this, it means connect() was successful.
3533  * TODO(rojer): Figure out why it fails where blocking succeeds.
3534  */
3535 #endif
3536 #ifdef MG_ENABLE_SSL
3537  if (nc->ssl != NULL && err == 0) {
3538  SSL_set_fd(nc->ssl, nc->sock);
3539  mg_ssl_begin(nc);
3540  } else {
3541  mg_if_connect_cb(nc, err);
3542  }
3543 #else
3544  mg_if_connect_cb(nc, err);
3545 #endif
3546  } else if (nc->err != 0) {
3547  mg_if_connect_cb(nc, nc->err);
3548  }
3549  }
3550 
3551  if (fd_flags & _MG_F_FD_CAN_READ) {
3552  if (nc->flags & MG_F_UDP) {
3553  mg_handle_udp_read(nc);
3554  } else {
3555  if (nc->flags & MG_F_LISTENING) {
3556  /*
3557  * We're not looping here, and accepting just one connection at
3558  * a time. The reason is that eCos does not respect non-blocking
3559  * flag on a listening socket and hangs in a loop.
3560  */
3561  if (fd_flags & _MG_F_FD_CAN_READ) mg_accept_conn(nc);
3562  } else {
3563  mg_read_from_socket(nc);
3564  }
3565  }
3566  }
3567 
3568  if (!(nc->flags & MG_F_CLOSE_IMMEDIATELY)) {
3569  if ((fd_flags & _MG_F_FD_CAN_WRITE) && nc->send_mbuf.len > 0) {
3570  mg_write_to_socket(nc);
3571  }
3572 
3573  if (!(fd_flags & (_MG_F_FD_CAN_READ | _MG_F_FD_CAN_WRITE))) {
3574  mg_if_poll(nc, now);
3575  }
3576  mg_if_timer(nc, now);
3577  }
3578 
3579  DBG(("%p after fd=%d nc_flags=%lu rmbl=%d smbl=%d", nc, nc->sock, nc->flags,
3580  (int) nc->recv_mbuf.len, (int) nc->send_mbuf.len));
3581 }
3582 
3583 #ifndef MG_DISABLE_SOCKETPAIR
3584 static void mg_mgr_handle_ctl_sock(struct mg_mgr *mgr) {
3585  struct ctl_msg ctl_msg;
3586  int len =
3587  (int) MG_RECV_FUNC(mgr->ctl[1], (char *) &ctl_msg, sizeof(ctl_msg), 0);
3588  size_t dummy = MG_SEND_FUNC(mgr->ctl[1], ctl_msg.message, 1, 0);
3589  DBG(("read %d from ctl socket", len));
3590  (void) dummy; /* https://gcc.gnu.org/bugzilla/show_bug.cgi?id=25509 */
3591  if (len >= (int) sizeof(ctl_msg.callback) && ctl_msg.callback != NULL) {
3592  struct mg_connection *nc;
3593  for (nc = mg_next(mgr, NULL); nc != NULL; nc = mg_next(mgr, nc)) {
3594  ctl_msg.callback(nc, MG_EV_POLL, ctl_msg.message);
3595  }
3596  }
3597 }
3598 #endif
3599 
3600 /* Associate a socket to a connection. */
3601 void mg_sock_set(struct mg_connection *nc, sock_t sock) {
3603  mg_set_close_on_exec(sock);
3604  nc->sock = sock;
3605  DBG(("%p %d", nc, sock));
3606 }
3607 
3608 void mg_ev_mgr_init(struct mg_mgr *mgr) {
3609  (void) mgr;
3610  DBG(("%p using select()", mgr));
3611 #ifndef MG_DISABLE_SOCKETPAIR
3612  do {
3613  mg_socketpair(mgr->ctl, SOCK_DGRAM);
3614  } while (mgr->ctl[0] == INVALID_SOCKET);
3615 #endif
3616 }
3617 
3618 void mg_ev_mgr_free(struct mg_mgr *mgr) {
3619  (void) mgr;
3620 }
3621 
3623  (void) nc;
3624 }
3625 
3627  (void) nc;
3628 }
3629 
3630 void mg_add_to_set(sock_t sock, fd_set *set, sock_t *max_fd) {
3631  if (sock != INVALID_SOCKET
3632 #ifdef __unix__
3633  && sock < FD_SETSIZE
3634 #endif
3635  ) {
3636  FD_SET(sock, set);
3637  if (*max_fd == INVALID_SOCKET || sock > *max_fd) {
3638  *max_fd = sock;
3639  }
3640  }
3641 }
3642 
3643 time_t mg_mgr_poll(struct mg_mgr *mgr, int timeout_ms) {
3644  double now = mg_time();
3645  double min_timer;
3646  struct mg_connection *nc, *tmp;
3647  struct timeval tv;
3648  fd_set read_set, write_set, err_set;
3649  sock_t max_fd = INVALID_SOCKET;
3650  int num_fds, num_ev, num_timers = 0;
3651 #ifdef __unix__
3652  int try_dup = 1;
3653 #endif
3654 
3655  FD_ZERO(&read_set);
3656  FD_ZERO(&write_set);
3657  FD_ZERO(&err_set);
3658 #ifndef MG_DISABLE_SOCKETPAIR
3659  mg_add_to_set(mgr->ctl[1], &read_set, &max_fd);
3660 #endif
3661 
3662  /*
3663  * Note: it is ok to have connections with sock == INVALID_SOCKET in the list,
3664  * e.g. timer-only "connections".
3665  */
3666  min_timer = 0;
3667  for (nc = mgr->active_connections, num_fds = 0; nc != NULL; nc = tmp) {
3668  tmp = nc->next;
3669 
3670  if (nc->sock != INVALID_SOCKET) {
3671  num_fds++;
3672 
3673 #ifdef __unix__
3674  /* A hack to make sure all our file descriptos fit into FD_SETSIZE. */
3675  if (nc->sock >= FD_SETSIZE && try_dup) {
3676  int new_sock = dup(nc->sock);
3677  if (new_sock >= 0 && new_sock < FD_SETSIZE) {
3678  closesocket(nc->sock);
3679  DBG(("new sock %d -> %d", nc->sock, new_sock));
3680  nc->sock = new_sock;
3681  } else {
3682  try_dup = 0;
3683  }
3684  }
3685 #endif
3686 
3687  if (!(nc->flags & MG_F_WANT_WRITE) &&
3688  nc->recv_mbuf.len < nc->recv_mbuf_limit &&
3689  (!(nc->flags & MG_F_UDP) || nc->listener == NULL)) {
3690  mg_add_to_set(nc->sock, &read_set, &max_fd);
3691  }
3692 
3693  if (((nc->flags & MG_F_CONNECTING) && !(nc->flags & MG_F_WANT_READ)) ||
3694  (nc->send_mbuf.len > 0 && !(nc->flags & MG_F_CONNECTING))) {
3695  mg_add_to_set(nc->sock, &write_set, &max_fd);
3696  mg_add_to_set(nc->sock, &err_set, &max_fd);
3697  }
3698  }
3699 
3700  if (nc->ev_timer_time > 0) {
3701  if (num_timers == 0 || nc->ev_timer_time < min_timer) {
3702  min_timer = nc->ev_timer_time;
3703  }
3704  num_timers++;
3705  }
3706  }
3707 
3708  /*
3709  * If there is a timer to be fired earlier than the requested timeout,
3710  * adjust the timeout.
3711  */
3712  if (num_timers > 0) {
3713  double timer_timeout_ms = (min_timer - mg_time()) * 1000 + 1 /* rounding */;
3714  if (timer_timeout_ms < timeout_ms) {
3715  timeout_ms = timer_timeout_ms;
3716  }
3717  }
3718  if (timeout_ms < 0) timeout_ms = 0;
3719 
3720  tv.tv_sec = timeout_ms / 1000;
3721  tv.tv_usec = (timeout_ms % 1000) * 1000;
3722 
3723  num_ev = select((int) max_fd + 1, &read_set, &write_set, &err_set, &tv);
3724  now = mg_time();
3725  DBG(("select @ %ld num_ev=%d of %d, timeout=%d", (long) now, num_ev, num_fds,
3726  timeout_ms));
3727 
3728 #ifndef MG_DISABLE_SOCKETPAIR
3729  if (num_ev > 0 && mgr->ctl[1] != INVALID_SOCKET &&
3730  FD_ISSET(mgr->ctl[1], &read_set)) {
3732  }
3733 #endif
3734 
3735  for (nc = mgr->active_connections; nc != NULL; nc = tmp) {
3736  int fd_flags = 0;
3737  if (nc->sock != INVALID_SOCKET) {
3738  if (num_ev > 0) {
3739  fd_flags = (FD_ISSET(nc->sock, &read_set) &&
3740  (!(nc->flags & MG_F_UDP) || nc->listener == NULL)
3742  : 0) |
3743  (FD_ISSET(nc->sock, &write_set) ? _MG_F_FD_CAN_WRITE : 0) |
3744  (FD_ISSET(nc->sock, &err_set) ? _MG_F_FD_ERROR : 0);
3745  }
3746 #ifdef MG_SOCKET_SIMPLELINK
3747  /* SimpleLink does not report UDP sockets as writeable. */
3748  if (nc->flags & MG_F_UDP &&
3749  (nc->send_mbuf.len > 0 || nc->flags & MG_F_CONNECTING)) {
3750  fd_flags |= _MG_F_FD_CAN_WRITE;
3751  }
3752 #endif
3753 #ifdef MG_LWIP
3754  /* With LWIP socket emulation layer, we don't get write events */
3755  fd_flags |= _MG_F_FD_CAN_WRITE;
3756 #endif
3757  }
3758  tmp = nc->next;
3759  mg_mgr_handle_conn(nc, fd_flags, now);
3760  }
3761 
3762  for (nc = mgr->active_connections; nc != NULL; nc = tmp) {
3763  tmp = nc->next;
3764  if ((nc->flags & MG_F_CLOSE_IMMEDIATELY) ||
3765  (nc->send_mbuf.len == 0 && (nc->flags & MG_F_SEND_AND_CLOSE))) {
3766  mg_close_conn(nc);
3767  }
3768  }
3769 
3770  return now;
3771 }
3772 
3773 #ifndef MG_DISABLE_SOCKETPAIR
3774 int mg_socketpair(sock_t sp[2], int sock_type) {
3775  union socket_address sa;
3776  sock_t sock;
3777  socklen_t len = sizeof(sa.sin);
3778  int ret = 0;
3779 
3780  sock = sp[0] = sp[1] = INVALID_SOCKET;
3781 
3782  (void) memset(&sa, 0, sizeof(sa));
3783  sa.sin.sin_family = AF_INET;
3784  sa.sin.sin_port = htons(0);
3785  sa.sin.sin_addr.s_addr = htonl(0x7f000001); /* 127.0.0.1 */
3786 
3787  if ((sock = socket(AF_INET, sock_type, 0)) == INVALID_SOCKET) {
3788  } else if (bind(sock, &sa.sa, len) != 0) {
3789  } else if (sock_type == SOCK_STREAM && listen(sock, 1) != 0) {
3790  } else if (getsockname(sock, &sa.sa, &len) != 0) {
3791  } else if ((sp[0] = socket(AF_INET, sock_type, 0)) == INVALID_SOCKET) {
3792  } else if (connect(sp[0], &sa.sa, len) != 0) {
3793  } else if (sock_type == SOCK_DGRAM &&
3794  (getsockname(sp[0], &sa.sa, &len) != 0 ||
3795  connect(sock, &sa.sa, len) != 0)) {
3796  } else if ((sp[1] = (sock_type == SOCK_DGRAM ? sock
3797  : accept(sock, &sa.sa, &len))) ==
3798  INVALID_SOCKET) {
3799  } else {
3800  mg_set_close_on_exec(sp[0]);
3801  mg_set_close_on_exec(sp[1]);
3802  if (sock_type == SOCK_STREAM) closesocket(sock);
3803  ret = 1;
3804  }
3805 
3806  if (!ret) {
3807  if (sp[0] != INVALID_SOCKET) closesocket(sp[0]);
3808  if (sp[1] != INVALID_SOCKET) closesocket(sp[1]);
3809  if (sock != INVALID_SOCKET) closesocket(sock);
3810  sock = sp[0] = sp[1] = INVALID_SOCKET;
3811  }
3812 
3813  return ret;
3814 }
3815 #endif /* MG_DISABLE_SOCKETPAIR */
3816 
3817 #ifndef MG_SOCKET_SIMPLELINK
3818 static void mg_sock_get_addr(sock_t sock, int remote,
3819  union socket_address *sa) {
3820  socklen_t slen = sizeof(*sa);
3821  memset(sa, 0, slen);
3822  if (remote) {
3823  getpeername(sock, &sa->sa, &slen);
3824  } else {
3825  getsockname(sock, &sa->sa, &slen);
3826  }
3827 }
3828 
3829 void mg_sock_to_str(sock_t sock, char *buf, size_t len, int flags) {
3830  union socket_address sa;
3831  mg_sock_get_addr(sock, flags & MG_SOCK_STRINGIFY_REMOTE, &sa);
3832  mg_sock_addr_to_str(&sa, buf, len, flags);
3833 }
3834 #endif
3835 
3836 void mg_if_get_conn_addr(struct mg_connection *nc, int remote,
3837  union socket_address *sa) {
3838 #ifndef MG_SOCKET_SIMPLELINK
3839  mg_sock_get_addr(nc->sock, remote, sa);
3840 #else
3841  /* SimpleLink does not provide a way to get socket's peer address after
3842  * accept or connect. Address hould have been preserved in the connection,
3843  * so we do our best here by using it. */
3844  if (remote) memcpy(sa, &nc->sa, sizeof(*sa));
3845 #endif
3846 }
3847 
3848 #endif /* !MG_DISABLE_SOCKET_IF */
3849 #ifdef MG_MODULE_LINES
3850 #line 1 "./src/multithreading.c"
3851 #endif
3852 /*
3853  * Copyright (c) 2014 Cesanta Software Limited
3854  * All rights reserved
3855  */
3856 
3857 /* Amalgamated: #include "mongoose/src/internal.h" */
3858 /* Amalgamated: #include "mongoose/src/util.h" */
3859 
3860 #ifdef MG_ENABLE_THREADS
3861 
3862 static void multithreaded_ev_handler(struct mg_connection *c, int ev, void *p);
3863 
3864 /*
3865  * This thread function executes user event handler.
3866  * It runs an event manager that has only one connection, until that
3867  * connection is alive.
3868  */
3869 static void *per_connection_thread_function(void *param) {
3870  struct mg_connection *c = (struct mg_connection *) param;
3871  struct mg_mgr m;
3872 
3873  mg_mgr_init(&m, NULL);
3874  mg_add_conn(&m, c);
3875  while (m.active_connections != NULL) {
3876  mg_mgr_poll(&m, 1000);
3877  }
3878  mg_mgr_free(&m);
3879 
3880  return param;
3881 }
3882 
3883 static void link_conns(struct mg_connection *c1, struct mg_connection *c2) {
3884  c1->priv_2 = c2;
3885  c2->priv_2 = c1;
3886 }
3887 
3888 static void unlink_conns(struct mg_connection *c) {
3889  struct mg_connection *peer = (struct mg_connection *) c->priv_2;
3890  if (peer != NULL) {
3891  peer->flags |= MG_F_SEND_AND_CLOSE;
3892  peer->priv_2 = NULL;
3893  }
3894  c->priv_2 = NULL;
3895 }
3896 
3897 static void forwarder_ev_handler(struct mg_connection *c, int ev, void *p) {
3898  (void) p;
3899  if (ev == MG_EV_RECV && c->priv_2) {
3900  mg_forward(c, (struct mg_connection *) c->priv_2);
3901  } else if (ev == MG_EV_CLOSE) {
3902  unlink_conns(c);
3903  }
3904 }
3905 
3906 static void spawn_handling_thread(struct mg_connection *nc) {
3907  struct mg_mgr dummy;
3908  sock_t sp[2];
3909  struct mg_connection *c[2];
3910 
3911  /*
3912  * Create a socket pair, and wrap each socket into the connection with
3913  * dummy event manager.
3914  * c[0] stays in this thread, c[1] goes to another thread.
3915  */
3916  mg_socketpair(sp, SOCK_STREAM);
3917  memset(&dummy, 0, sizeof(dummy));
3918  c[0] = mg_add_sock(&dummy, sp[0], forwarder_ev_handler);
3919  c[1] = mg_add_sock(&dummy, sp[1], nc->listener->priv_1.f);
3920 
3921  /* Interlink client connection with c[0] */
3922  link_conns(c[0], nc);
3923 
3924  /*
3925  * Switch c[0] manager from the dummy one to the real one. c[1] manager
3926  * will be set in another thread, allocated on stack of that thread.
3927  */
3928  mg_add_conn(nc->mgr, c[0]);
3929 
3930  /*
3931  * Dress c[1] as nc.
3932  * TODO(lsm): code in accept_conn() looks similar. Refactor.
3933  */
3934  c[1]->listener = nc->listener;
3935  c[1]->proto_handler = nc->proto_handler;
3936  c[1]->proto_data = nc->proto_data;
3937  c[1]->user_data = nc->user_data;
3938 
3939  mg_start_thread(per_connection_thread_function, c[1]);
3940 }
3941 
3942 static void multithreaded_ev_handler(struct mg_connection *c, int ev, void *p) {
3943  (void) p;
3944  if (ev == MG_EV_ACCEPT) {
3945  spawn_handling_thread(c);
3946  c->handler = forwarder_ev_handler;
3947  }
3948 }
3949 
3950 void mg_enable_multithreading(struct mg_connection *nc) {
3951  /* Wrap user event handler into our multithreaded_ev_handler */
3952  nc->priv_1.f = nc->handler;
3953  nc->handler = multithreaded_ev_handler;
3954 }
3955 #endif
3956 #ifdef MG_MODULE_LINES
3957 #line 1 "./src/uri.c"
3958 #endif
3959 /*
3960  * Copyright (c) 2014 Cesanta Software Limited
3961  * All rights reserved
3962  */
3963 
3964 /* Amalgamated: #include "mongoose/src/internal.h" */
3965 /* Amalgamated: #include "mongoose/src/uri.h" */
3966 
3967 /*
3968  * scan string until `sep`, keeping track of component boundaries in `res`.
3969  *
3970  * `p` will point to the char after the separator or it will be `end`.
3971  */
3972 static void parse_uri_component(const char **p, const char *end, char sep,
3973  struct mg_str *res) {
3974  res->p = *p;
3975  for (; *p < end; (*p)++) {
3976  if (**p == sep) {
3977  break;
3978  }
3979  }
3980  res->len = (*p) - res->p;
3981  if (*p < end) (*p)++;
3982 }
3983 
3984 int mg_parse_uri(struct mg_str uri, struct mg_str *scheme,
3985  struct mg_str *user_info, struct mg_str *host,
3986  unsigned int *port, struct mg_str *path, struct mg_str *query,
3987  struct mg_str *fragment) {
3988  struct mg_str rscheme = {0, 0}, ruser_info = {0, 0}, rhost = {0, 0},
3989  rpath = {0, 0}, rquery = {0, 0}, rfragment = {0, 0};
3990  unsigned int rport = 0;
3991  enum {
3992  P_START,
3993  P_SCHEME_OR_PORT,
3994  P_USER_INFO,
3995  P_HOST,
3996  P_PORT,
3997  P_REST
3998  } state = P_START;
3999 
4000  const char *p = uri.p, *end = p + uri.len;
4001  while (p < end) {
4002  switch (state) {
4003  case P_START:
4004  /*
4005  * expecting on of:
4006  * - `scheme://xxxx`
4007  * - `xxxx:port`
4008  * - `xxxx/path`
4009  */
4010  for (; p < end; p++) {
4011  if (*p == ':') {
4012  state = P_SCHEME_OR_PORT;
4013  break;
4014  } else if (*p == '/') {
4015  state = P_REST;
4016  break;
4017  }
4018  }
4019  if (state == P_START || state == P_REST) {
4020  rhost.p = uri.p;
4021  rhost.len = p - uri.p;
4022  }
4023  break;
4024  case P_SCHEME_OR_PORT:
4025  if (end - p >= 3 && memcmp(p, "://", 3) == 0) {
4026  rscheme.p = uri.p;
4027  rscheme.len = p - uri.p;
4028  state = P_USER_INFO;
4029  p += 2; /* point to last separator char */
4030  } else {
4031  rhost.p = uri.p;
4032  rhost.len = p - uri.p;
4033  state = P_PORT;
4034  }
4035  break;
4036  case P_USER_INFO:
4037  p++;
4038  ruser_info.p = p;
4039  for (; p < end; p++) {
4040  if (*p == '@') {
4041  state = P_HOST;
4042  break;
4043  } else if (*p == '/') {
4044  break;
4045  }
4046  }
4047  if (p == end || *p == '/') {
4048  /* backtrack and parse as host */
4049  state = P_HOST;
4050  p = ruser_info.p;
4051  }
4052  ruser_info.len = p - ruser_info.p;
4053  break;
4054  case P_HOST:
4055  if (*p == '@') p++;
4056  rhost.p = p;
4057  for (; p < end; p++) {
4058  if (*p == ':') {
4059  state = P_PORT;
4060  break;
4061  } else if (*p == '/') {
4062  state = P_REST;
4063  break;
4064  }
4065  }
4066  rhost.len = p - rhost.p;
4067  break;
4068  case P_PORT:
4069  p++;
4070  for (; p < end; p++) {
4071  if (*p == '/') {
4072  state = P_REST;
4073  break;
4074  }
4075  rport *= 10;
4076  rport += *p - '0';
4077  }
4078  break;
4079  case P_REST:
4080  /* `p` points to separator. `path` includes the separator */
4081  parse_uri_component(&p, end, '?', &rpath);
4082  parse_uri_component(&p, end, '#', &rquery);
4083  parse_uri_component(&p, end, '\0', &rfragment);
4084  break;
4085  }
4086  }
4087 
4088  if (scheme != 0) *scheme = rscheme;
4089  if (user_info != 0) *user_info = ruser_info;
4090  if (host != 0) *host = rhost;
4091  if (port != 0) *port = rport;
4092  if (path != 0) *path = rpath;
4093  if (query != 0) *query = rquery;
4094  if (fragment != 0) *fragment = rfragment;
4095 
4096  return 0;
4097 }
4098 
4099 /* Normalize the URI path. Remove/resolve "." and "..". */
4100 int mg_normalize_uri_path(const struct mg_str *in, struct mg_str *out) {
4101  const char *s = in->p, *se = s + in->len;
4102  char *cp = (char *) out->p, *d;
4103 
4104  if (in->len == 0 || *s != '/') {
4105  out->len = 0;
4106  return 0;
4107  }
4108 
4109  d = cp;
4110 
4111  while (s < se) {
4112  const char *next = s;
4113  struct mg_str component;
4114  parse_uri_component(&next, se, '/', &component);
4115  if (mg_vcmp(&component, ".") == 0) {
4116  /* Yum. */
4117  } else if (mg_vcmp(&component, "..") == 0) {
4118  /* Backtrack to previous slash. */
4119  if (d > cp + 1 && *(d - 1) == '/') d--;
4120  while (d > cp && *(d - 1) != '/') d--;
4121  } else {
4122  memmove(d, s, next - s);
4123  d += next - s;
4124  }
4125  s = next;
4126  }
4127  if (d == cp) *d++ = '/';
4128 
4129  out->p = cp;
4130  out->len = d - cp;
4131  return 1;
4132 }
4133 #ifdef MG_MODULE_LINES
4134 #line 1 "./src/http.c"
4135 #endif
4136 /*
4137  * Copyright (c) 2014 Cesanta Software Limited
4138  * All rights reserved
4139  */
4140 
4141 #ifndef MG_DISABLE_HTTP
4142 
4143 /* Amalgamated: #include "mongoose/src/internal.h" */
4144 /* Amalgamated: #include "mongoose/src/util.h" */
4145 /* Amalgamated: #include "common/sha1.h" */
4146 /* Amalgamated: #include "common/md5.h" */
4147 
4148 #ifndef MG_DISABLE_HTTP_WEBSOCKET
4149 #define MG_WS_NO_HOST_HEADER_MAGIC ((char *) 0x1)
4150 #endif
4151 
4152 /* CGI requires socketpair. */
4153 #if defined(MG_DISABLE_SOCKETPAIR) && !defined(MG_DISABLE_CGI)
4154 #define MG_DISABLE_CGI 1
4155 #endif
4156 
4157 static const char *mg_version_header = "Mongoose/" MG_VERSION;
4158 
4160 
4162  FILE *fp; /* Opened file. */
4163  int64_t cl; /* Content-Length. How many bytes to send. */
4164  int64_t sent; /* How many bytes have been already sent. */
4165  int keepalive; /* Keep connection open after sending. */
4167 };
4168 
4171 };
4172 
4174  int64_t body_len; /* How many bytes of chunked body was reassembled. */
4175 };
4176 
4179  const char *name;
4180  size_t name_len;
4182 };
4183 
4192 };
4193 
4195  const char *boundary;
4197  const char *var_name;
4198  const char *file_name;
4199  void *user_data;
4203 };
4204 
4206 #ifndef MG_DISABLE_FILESYSTEM
4208 #endif
4209 #ifndef MG_DISABLE_CGI
4211 #endif
4212 #ifdef MG_ENABLE_HTTP_STREAMING_MULTIPART
4213  struct mg_http_multipart_stream mp_stream;
4214 #endif
4218 };
4219 
4220 static void mg_http_conn_destructor(void *proto_data);
4221 
4223  struct mg_connection *c) {
4224  if (c->proto_data == NULL) {
4225  c->proto_data = MG_CALLOC(1, sizeof(struct mg_http_proto_data));
4227  }
4228 
4229  return (struct mg_http_proto_data *) c->proto_data;
4230 }
4231 
4232 #ifdef MG_ENABLE_HTTP_STREAMING_MULTIPART
4233 static void mg_http_free_proto_data_mp_stream(
4234  struct mg_http_multipart_stream *mp) {
4235  free((void *) mp->boundary);
4236  mp->boundary = NULL;
4237  free((void *) mp->var_name);
4238  mp->var_name = NULL;
4239  free((void *) mp->file_name);
4240  mp->file_name = NULL;
4241 }
4242 #endif
4243 
4244 #ifndef MG_DISABLE_FILESYSTEM
4246  if (d != NULL) {
4247  if (d->fp != NULL) {
4248  fclose(d->fp);
4249  }
4250  memset(d, 0, sizeof(struct mg_http_proto_data_file));
4251  }
4252 }
4253 #endif
4254 
4255 #ifndef MG_DISABLE_CGI
4257  if (d != NULL) {
4258  if (d->cgi_nc != NULL) d->cgi_nc->flags |= MG_F_CLOSE_IMMEDIATELY;
4259  memset(d, 0, sizeof(struct mg_http_proto_data_cgi));
4260  }
4261 }
4262 #endif
4263 
4265  struct mg_http_endpoint *current = *ep;
4266 
4267  while (current != NULL) {
4268  struct mg_http_endpoint *tmp = current->next;
4269  free((void *) current->name);
4270  free(current);
4271  current = tmp;
4272  }
4273 
4274  ep = NULL;
4275 }
4276 
4277 static void mg_http_conn_destructor(void *proto_data) {
4278  struct mg_http_proto_data *pd = (struct mg_http_proto_data *) proto_data;
4279 #ifndef MG_DISABLE_FILESYSTEM
4281 #endif
4282 #ifndef MG_DISABLE_CGI
4284 #endif
4285 #ifdef MG_ENABLE_HTTP_STREAMING_MULTIPART
4286  mg_http_free_proto_data_mp_stream(&pd->mp_stream);
4287 #endif
4289  free(proto_data);
4290 }
4291 
4292 /*
4293  * This structure helps to create an environment for the spawned CGI program.
4294  * Environment is an array of "VARIABLE=VALUE\0" ASCIIZ strings,
4295  * last element must be NULL.
4296  * However, on Windows there is a requirement that all these VARIABLE=VALUE\0
4297  * strings must reside in a contiguous buffer. The end of the buffer is
4298  * marked by two '\0' characters.
4299  * We satisfy both worlds: we create an envp array (which is vars), all
4300  * entries are actually pointers inside buf.
4301  */
4304  char buf[MG_CGI_ENVIRONMENT_SIZE]; /* Environment buffer */
4305  const char *vars[MG_MAX_CGI_ENVIR_VARS]; /* char *envp[] */
4306  int len; /* Space taken */
4307  int nvars; /* Number of variables in envp[] */
4308 };
4309 
4310 #ifndef MG_DISABLE_FILESYSTEM
4311 
4312 #define MIME_ENTRY(_ext, _type) \
4313 { _ext, sizeof(_ext) - 1, _type }
4314 static const struct {
4315  const char *extension;
4316  size_t ext_len;
4317  const char *mime_type;
4319  MIME_ENTRY("html", "text/html"),
4320  MIME_ENTRY("html", "text/html"),
4321  MIME_ENTRY("htm", "text/html"),
4322  MIME_ENTRY("shtm", "text/html"),
4323  MIME_ENTRY("shtml", "text/html"),
4324  MIME_ENTRY("css", "text/css"),
4325  MIME_ENTRY("js", "application/x-javascript"),
4326  MIME_ENTRY("ico", "image/x-icon"),
4327  MIME_ENTRY("gif", "image/gif"),
4328  MIME_ENTRY("jpg", "image/jpeg"),
4329  MIME_ENTRY("jpeg", "image/jpeg"),
4330  MIME_ENTRY("png", "image/png"),
4331  MIME_ENTRY("svg", "image/svg+xml"),
4332  MIME_ENTRY("txt", "text/plain"),
4333  MIME_ENTRY("torrent", "application/x-bittorrent"),
4334  MIME_ENTRY("wav", "audio/x-wav"),
4335  MIME_ENTRY("mp3", "audio/x-mp3"),
4336  MIME_ENTRY("mid", "audio/mid"),
4337  MIME_ENTRY("m3u", "audio/x-mpegurl"),
4338  MIME_ENTRY("ogg", "application/ogg"),
4339  MIME_ENTRY("ram", "audio/x-pn-realaudio"),
4340  MIME_ENTRY("xml", "text/xml"),
4341  MIME_ENTRY("ttf", "application/x-font-ttf"),
4342  MIME_ENTRY("json", "application/json"),
4343  MIME_ENTRY("xslt", "application/xml"),
4344  MIME_ENTRY("xsl", "application/xml"),
4345  MIME_ENTRY("ra", "audio/x-pn-realaudio"),
4346  MIME_ENTRY("doc", "application/msword"),
4347  MIME_ENTRY("exe", "application/octet-stream"),
4348  MIME_ENTRY("zip", "application/x-zip-compressed"),
4349  MIME_ENTRY("xls", "application/excel"),
4350  MIME_ENTRY("tgz", "application/x-tar-gz"),
4351  MIME_ENTRY("tar", "application/x-tar"),
4352  MIME_ENTRY("gz", "application/x-gunzip"),
4353  MIME_ENTRY("arj", "application/x-arj-compressed"),
4354  MIME_ENTRY("rar", "application/x-rar-compressed"),
4355  MIME_ENTRY("rtf", "application/rtf"),
4356  MIME_ENTRY("pdf", "application/pdf"),
4357  MIME_ENTRY("swf", "application/x-shockwave-flash"),
4358  MIME_ENTRY("mpg", "video/mpeg"),
4359  MIME_ENTRY("webm", "video/webm"),
4360  MIME_ENTRY("mpeg", "video/mpeg"),
4361  MIME_ENTRY("mov", "video/quicktime"),
4362  MIME_ENTRY("mp4", "video/mp4"),
4363  MIME_ENTRY("m4v", "video/x-m4v"),
4364  MIME_ENTRY("asf", "video/x-ms-asf"),
4365  MIME_ENTRY("avi", "video/x-msvideo"),
4366  MIME_ENTRY("bmp", "image/bmp"),
4367  {NULL, 0, NULL}};
4368 
4369 #ifndef MG_DISABLE_DAV
4370 static int mg_mkdir(const char *path, uint32_t mode) {
4371 #ifndef _WIN32
4372  return mkdir(path, mode);
4373 #else
4374  (void) mode;
4375  return _mkdir(path);
4376 #endif
4377 }
4378 #endif
4379 
4380 static struct mg_str mg_get_mime_type(const char *path, const char *dflt,
4381  const struct mg_serve_http_opts *opts) {
4382  const char *ext, *overrides;
4383  size_t i, path_len;
4384  struct mg_str r, k, v;
4385 
4386  path_len = strlen(path);
4387 
4388  overrides = opts->custom_mime_types;
4389  while ((overrides = mg_next_comma_list_entry(overrides, &k, &v)) != NULL) {
4390  ext = path + (path_len - k.len);
4391  if (path_len > k.len && mg_vcasecmp(&k, ext) == 0) {
4392  return v;
4393  }
4394  }
4395 
4396  for (i = 0; mg_static_builtin_mime_types[i].extension != NULL; i++) {
4397  ext = path + (path_len - mg_static_builtin_mime_types[i].ext_len);
4398  if (path_len > mg_static_builtin_mime_types[i].ext_len && ext[-1] == '.' &&
4400  r.p = mg_static_builtin_mime_types[i].mime_type;
4401  r.len = strlen(r.p);
4402  return r;
4403  }
4404  }
4405 
4406  r.p = dflt;
4407  r.len = strlen(r.p);
4408  return r;
4409 }
4410 #endif
4411 
4412 /*
4413  * Check whether full request is buffered. Return:
4414  * -1 if request is malformed
4415  * 0 if request is not yet fully buffered
4416  * >0 actual request length, including last \r\n\r\n
4417  */
4418 static int mg_http_get_request_len(const char *s, int buf_len) {
4419  const unsigned char *buf = (unsigned char *) s;
4420  int i;
4421 
4422  for (i = 0; i < buf_len; i++) {
4423  if (!isprint(buf[i]) && buf[i] != '\r' && buf[i] != '\n' && buf[i] < 128) {
4424  return -1;
4425  } else if (buf[i] == '\n' && i + 1 < buf_len && buf[i + 1] == '\n') {
4426  return i + 2;
4427  } else if (buf[i] == '\n' && i + 2 < buf_len && buf[i + 1] == '\r' &&
4428  buf[i + 2] == '\n') {
4429  return i + 3;
4430  }
4431  }
4432 
4433  return 0;
4434 }
4435 
4436 static const char *mg_http_parse_headers(const char *s, const char *end,
4437  int len, struct http_message *req) {
4438  int i;
4439  for (i = 0; i < (int) ARRAY_SIZE(req->header_names) - 1; i++) {
4440  struct mg_str *k = &req->header_names[i], *v = &req->header_values[i];
4441 
4442  s = mg_skip(s, end, ": ", k);
4443  s = mg_skip(s, end, "\r\n", v);
4444 
4445  while (v->len > 0 && v->p[v->len - 1] == ' ') {
4446  v->len--; /* Trim trailing spaces in header value */
4447  }
4448 
4449  if (k->len == 0 || v->len == 0) {
4450  k->p = v->p = NULL;
4451  k->len = v->len = 0;
4452  break;
4453  }
4454 
4455  if (!mg_ncasecmp(k->p, "Content-Length", 14)) {
4456  req->body.len = to64(v->p);
4457  req->message.len = len + req->body.len;
4458  }
4459  }
4460 
4461  return s;
4462 }
4463 
4464 int mg_parse_http(const char *s, int n, struct http_message *hm, int is_req) {
4465  const char *end, *qs;
4466  int len = mg_http_get_request_len(s, n);
4467 
4468  if (len <= 0) return len;
4469 
4470  memset(hm, 0, sizeof(*hm));
4471  hm->message.p = s;
4472  hm->body.p = s + len;
4473  hm->message.len = hm->body.len = (size_t) ~0;
4474  end = s + len;
4475 
4476  /* Request is fully buffered. Skip leading whitespaces. */
4477  while (s < end && isspace(*(unsigned char *) s)) s++;
4478 
4479  if (is_req) {
4480  /* Parse request line: method, URI, proto */
4481  s = mg_skip(s, end, " ", &hm->method);
4482  s = mg_skip(s, end, " ", &hm->uri);
4483  s = mg_skip(s, end, "\r\n", &hm->proto);
4484  if (hm->uri.p <= hm->method.p || hm->proto.p <= hm->uri.p) return -1;
4485 
4486  /* If URI contains '?' character, initialize query_string */
4487  if ((qs = (char *) memchr(hm->uri.p, '?', hm->uri.len)) != NULL) {
4488  hm->query_string.p = qs + 1;
4489  hm->query_string.len = &hm->uri.p[hm->uri.len] - (qs + 1);
4490  hm->uri.len = qs - hm->uri.p;
4491  }
4492  } else {
4493  s = mg_skip(s, end, " ", &hm->proto);
4494  if (end - s < 4 || s[3] != ' ') return -1;
4495  hm->resp_code = atoi(s);
4496  if (hm->resp_code < 100 || hm->resp_code >= 600) return -1;
4497  s += 4;
4498  s = mg_skip(s, end, "\r\n", &hm->resp_status_msg);
4499  }
4500 
4501  s = mg_http_parse_headers(s, end, len, hm);
4502 
4503  /*
4504  * mg_parse_http() is used to parse both HTTP requests and HTTP
4505  * responses. If HTTP response does not have Content-Length set, then
4506  * body is read until socket is closed, i.e. body.len is infinite (~0).
4507  *
4508  * For HTTP requests though, according to
4509  * http://tools.ietf.org/html/rfc7231#section-8.1.3,
4510  * only POST and PUT methods have defined body semantics.
4511  * Therefore, if Content-Length is not specified and methods are
4512  * not one of PUT or POST, set body length to 0.
4513  *
4514  * So,
4515  * if it is HTTP request, and Content-Length is not set,
4516  * and method is not (PUT or POST) then reset body length to zero.
4517  */
4518  if (hm->body.len == (size_t) ~0 && is_req &&
4519  mg_vcasecmp(&hm->method, "PUT") != 0 &&
4520  mg_vcasecmp(&hm->method, "POST") != 0) {
4521  hm->body.len = 0;
4522  hm->message.len = len;
4523  }
4524 
4525  return len;
4526 }
4527 
4528 struct mg_str *mg_get_http_header(struct http_message *hm, const char *name) {
4529  size_t i, len = strlen(name);
4530 
4531  for (i = 0; hm->header_names[i].len > 0; i++) {
4532  struct mg_str *h = &hm->header_names[i], *v = &hm->header_values[i];
4533  if (h->p != NULL && h->len == len && !mg_ncasecmp(h->p, name, len))
4534  return v;
4535  }
4536 
4537  return NULL;
4538 }
4539 
4540 #ifndef MG_DISABLE_HTTP_WEBSOCKET
4541 
4542 static int mg_is_ws_fragment(unsigned char flags) {
4543  return (flags & 0x80) == 0 || (flags & 0x0f) == 0;
4544 }
4545 
4546 static int mg_is_ws_first_fragment(unsigned char flags) {
4547  return (flags & 0x80) == 0 && (flags & 0x0f) != 0;
4548 }
4549 
4551  struct websocket_message *wsm) {
4552  if (wsm->flags & 0x8) {
4554  } else {
4555  mg_call(nc, nc->handler, MG_EV_WEBSOCKET_FRAME, wsm);
4556  }
4557 }
4558 
4560  /* Using unsigned char *, cause of integer arithmetic below */
4561  uint64_t i, data_len = 0, frame_len = 0, buf_len = nc->recv_mbuf.len, len,
4562  mask_len = 0, header_len = 0;
4563  unsigned char *p = (unsigned char *) nc->recv_mbuf.buf, *buf = p,
4564  *e = p + buf_len;
4565  unsigned *sizep = (unsigned *) &p[1]; /* Size ptr for defragmented frames */
4566  int ok, reass = buf_len > 0 && mg_is_ws_fragment(p[0]) &&
4568 
4569  /* If that's a continuation frame that must be reassembled, handle it */
4570  if (reass && !mg_is_ws_first_fragment(p[0]) &&
4571  buf_len >= 1 + sizeof(*sizep) && buf_len >= 1 + sizeof(*sizep) + *sizep) {
4572  buf += 1 + sizeof(*sizep) + *sizep;
4573  buf_len -= 1 + sizeof(*sizep) + *sizep;
4574  }
4575 
4576  if (buf_len >= 2) {
4577  len = buf[1] & 127;
4578  mask_len = buf[1] & 128 ? 4 : 0;
4579  if (len < 126 && buf_len >= mask_len) {
4580  data_len = len;
4581  header_len = 2 + mask_len;
4582  } else if (len == 126 && buf_len >= 4 + mask_len) {
4583  header_len = 4 + mask_len;
4584  data_len = ntohs(*(uint16_t *) &buf[2]);
4585  } else if (buf_len >= 10 + mask_len) {
4586  header_len = 10 + mask_len;
4587  data_len = (((uint64_t) ntohl(*(uint32_t *) &buf[2])) << 32) +
4588  ntohl(*(uint32_t *) &buf[6]);
4589  }
4590  }
4591 
4592  frame_len = header_len + data_len;
4593  ok = frame_len > 0 && frame_len <= buf_len;
4594 
4595  if (ok) {
4596  struct websocket_message wsm;
4597 
4598  wsm.size = (size_t) data_len;
4599  wsm.data = buf + header_len;
4600  wsm.flags = buf[0];
4601 
4602  /* Apply mask if necessary */
4603  if (mask_len > 0) {
4604  for (i = 0; i < data_len; i++) {
4605  buf[i + header_len] ^= (buf + header_len - mask_len)[i % 4];
4606  }
4607  }
4608 
4609  if (reass) {
4610  /* On first fragmented frame, nullify size */
4611  if (mg_is_ws_first_fragment(wsm.flags)) {
4612  mbuf_resize(&nc->recv_mbuf, nc->recv_mbuf.size + sizeof(*sizep));
4613  p[0] &= ~0x0f; /* Next frames will be treated as continuation */
4614  buf = p + 1 + sizeof(*sizep);
4615  *sizep = 0; /* TODO(lsm): fix. this can stomp over frame data */
4616  }
4617 
4618  /* Append this frame to the reassembled buffer */
4619  memmove(buf, wsm.data, e - wsm.data);
4620  (*sizep) += wsm.size;
4621  nc->recv_mbuf.len -= wsm.data - buf;
4622 
4623  /* On last fragmented frame - call user handler and remove data */
4624  if (wsm.flags & 0x80) {
4625  wsm.data = p + 1 + sizeof(*sizep);
4626  wsm.size = *sizep;
4628  mbuf_remove(&nc->recv_mbuf, 1 + sizeof(*sizep) + *sizep);
4629  }
4630  } else {
4631  /* TODO(lsm): properly handle OOB control frames during defragmentation */
4633  mbuf_remove(&nc->recv_mbuf, (size_t) frame_len); /* Cleanup frame */
4634  }
4635 
4636  /* If client closes, close too */
4637  if ((buf[0] & 0x0f) == WEBSOCKET_OP_CLOSE) {
4638  nc->flags |= MG_F_SEND_AND_CLOSE;
4639  }
4640  }
4641 
4642  return ok;
4643 }
4644 
4645 struct ws_mask_ctx {
4646  size_t pos; /* zero means unmasked */
4647  uint32_t mask;
4648 };
4649 
4650 static uint32_t mg_ws_random_mask(void) {
4651  uint32_t mask;
4652  /*
4653  * The spec requires WS client to generate hard to
4654  * guess mask keys. From RFC6455, Section 5.3:
4655  *
4656  * The unpredictability of the masking key is essential to prevent
4657  * authors of malicious applications from selecting the bytes that appear on
4658  * the wire.
4659  *
4660  * Hence this feature is essential when the actual end user of this API
4661  * is untrusted code that wouldn't have access to a lower level net API
4662  * anyway (e.g. web browsers). Hence this feature is low prio for most
4663  * mongoose use cases and thus can be disabled, e.g. when porting to a platform
4664  * that lacks random().
4665  */
4666 #ifdef MG_DISABLE_WS_RANDOM_MASK
4667  mask = 0xefbeadde; /* generated with a random number generator, I swear */
4668 #else
4669  if (sizeof(long) >= 4) {
4670  mask = (uint32_t) random();
4671  } else if (sizeof(long) == 2) {
4672  mask = (uint32_t) random() << 16 | (uint32_t) random();
4673  }
4674 #endif
4675  return mask;
4676 }
4677 
4678 static void mg_send_ws_header(struct mg_connection *nc, int op, size_t len,
4679  struct ws_mask_ctx *ctx) {
4680  int header_len;
4681  unsigned char header[10];
4682 
4683  header[0] = (op & WEBSOCKET_DONT_FIN ? 0x0 : 0x80) + (op & 0x0f);
4684  if (len < 126) {
4685  header[1] = len;
4686  header_len = 2;
4687  } else if (len < 65535) {
4688  uint16_t tmp = htons((uint16_t) len);
4689  header[1] = 126;
4690  memcpy(&header[2], &tmp, sizeof(tmp));
4691  header_len = 4;
4692  } else {
4693  uint32_t tmp;
4694  header[1] = 127;
4695  tmp = htonl((uint32_t)((uint64_t) len >> 32));
4696  memcpy(&header[2], &tmp, sizeof(tmp));
4697  tmp = htonl((uint32_t)(len & 0xffffffff));
4698  memcpy(&header[6], &tmp, sizeof(tmp));
4699  header_len = 10;
4700  }
4701 
4702  /* client connections enable masking */
4703  if (nc->listener == NULL) {
4704  header[1] |= 1 << 7; /* set masking flag */
4705  mg_send(nc, header, header_len);
4706  ctx->mask = mg_ws_random_mask();
4707  mg_send(nc, &ctx->mask, sizeof(ctx->mask));
4708  ctx->pos = nc->send_mbuf.len;
4709  } else {
4710  mg_send(nc, header, header_len);
4711  ctx->pos = 0;
4712  }
4713 }
4714 
4715 static void mg_ws_mask_frame(struct mbuf *mbuf, struct ws_mask_ctx *ctx) {
4716  size_t i;
4717  if (ctx->pos == 0) return;
4718  for (i = 0; i < (mbuf->len - ctx->pos); i++) {
4719  mbuf->buf[ctx->pos + i] ^= ((char *) &ctx->mask)[i % 4];
4720  }
4721 }
4722 
4723 void mg_send_websocket_frame(struct mg_connection *nc, int op, const void *data,
4724  size_t len) {
4725  struct ws_mask_ctx ctx;
4726  DBG(("%p %d %d", nc, op, (int) len));
4727  mg_send_ws_header(nc, op, len, &ctx);
4728  mg_send(nc, data, len);
4729 
4730  mg_ws_mask_frame(&nc->send_mbuf, &ctx);
4731 
4732  if (op == WEBSOCKET_OP_CLOSE) {
4733  nc->flags |= MG_F_SEND_AND_CLOSE;
4734  }
4735 }
4736 
4737 void mg_send_websocket_framev(struct mg_connection *nc, int op,
4738  const struct mg_str *strv, int strvcnt) {
4739  struct ws_mask_ctx ctx;
4740  int i;
4741  int len = 0;
4742  for (i = 0; i < strvcnt; i++) {
4743  len += strv[i].len;
4744  }
4745 
4746  mg_send_ws_header(nc, op, len, &ctx);
4747 
4748  for (i = 0; i < strvcnt; i++) {
4749  mg_send(nc, strv[i].p, strv[i].len);
4750  }
4751 
4752  mg_ws_mask_frame(&nc->send_mbuf, &ctx);
4753 
4754  if (op == WEBSOCKET_OP_CLOSE) {
4755  nc->flags |= MG_F_SEND_AND_CLOSE;
4756  }
4757 }
4758 
4760  const char *fmt, ...) {
4761  char mem[MG_VPRINTF_BUFFER_SIZE], *buf = mem;
4762  va_list ap;
4763  int len;
4764 
4765  va_start(ap, fmt);
4766  if ((len = mg_avprintf(&buf, sizeof(mem), fmt, ap)) > 0) {
4767  mg_send_websocket_frame(nc, op, buf, len);
4768  }
4769  va_end(ap);
4770 
4771  if (buf != mem && buf != NULL) {
4772  MG_FREE(buf);
4773  }
4774 }
4775 
4776 static void mg_websocket_handler(struct mg_connection *nc, int ev,
4777  void *ev_data) {
4778  mg_call(nc, nc->handler, ev, ev_data);
4779 
4780  switch (ev) {
4781  case MG_EV_RECV:
4782  do {
4783  } while (mg_deliver_websocket_data(nc));
4784  break;
4785  case MG_EV_POLL:
4786  /* Ping idle websocket connections */
4787  {
4788  time_t now = *(time_t *) ev_data;
4789  if (nc->flags & MG_F_IS_WEBSOCKET &&
4792  }
4793  }
4794  break;
4795  default:
4796  break;
4797  }
4798 }
4799 
4800 static void mg_ws_handshake(struct mg_connection *nc,
4801  const struct mg_str *key) {
4802  static const char *magic = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
4803  char buf[MG_VPRINTF_BUFFER_SIZE], sha[20], b64_sha[sizeof(sha) * 2];
4804  cs_sha1_ctx sha_ctx;
4805 
4806  snprintf(buf, sizeof(buf), "%.*s%s", (int) key->len, key->p, magic);
4807 
4808  cs_sha1_init(&sha_ctx);
4809  cs_sha1_update(&sha_ctx, (unsigned char *) buf, strlen(buf));
4810  cs_sha1_final((unsigned char *) sha, &sha_ctx);
4811 
4812  mg_base64_encode((unsigned char *) sha, sizeof(sha), b64_sha);
4813  mg_printf(nc, "%s%s%s",
4814  "HTTP/1.1 101 Switching Protocols\r\n"
4815  "Upgrade: websocket\r\n"
4816  "Connection: Upgrade\r\n"
4817  "Sec-WebSocket-Accept: ",
4818  b64_sha, "\r\n\r\n");
4819  DBG(("%p %.*s %s", nc, (int) key->len, key->p, b64_sha));
4820 }
4821 
4822 #endif /* MG_DISABLE_HTTP_WEBSOCKET */
4823 
4824 #ifndef MG_DISABLE_FILESYSTEM
4826  struct mg_http_proto_data *pd = mg_http_get_proto_data(nc);
4827  char buf[MG_MAX_HTTP_SEND_MBUF];
4828  int64_t left = pd->file.cl - pd->file.sent;
4829  size_t n = 0, to_read = 0;
4830 
4831  if (pd->file.type == DATA_FILE) {
4832  struct mbuf *io = &nc->send_mbuf;
4833  if (io->len < sizeof(buf)) {
4834  to_read = sizeof(buf) - io->len;
4835  }
4836 
4837  if (left > 0 && to_read > (size_t) left) {
4838  to_read = left;
4839  }
4840 
4841  if (to_read == 0) {
4842  /* Rate limiting. send_mbuf is too full, wait until it's drained. */
4843  } else if (pd->file.sent < pd->file.cl &&
4844  (n = fread(buf, 1, to_read, pd->file.fp)) > 0) {
4845  mg_send(nc, buf, n);
4846  pd->file.sent += n;
4847  } else {
4848  if (!pd->file.keepalive) nc->flags |= MG_F_SEND_AND_CLOSE;
4850  }
4851  } else if (pd->file.type == DATA_PUT) {
4852  struct mbuf *io = &nc->recv_mbuf;
4853  size_t to_write =
4854  left <= 0 ? 0 : left < (int64_t) io->len ? (size_t) left : io->len;
4855  size_t n = fwrite(io->buf, 1, to_write, pd->file.fp);
4856  if (n > 0) {
4857  mbuf_remove(io, n);
4858  pd->file.sent += n;
4859  }
4860  if (n == 0 || pd->file.sent >= pd->file.cl) {
4861  if (!pd->file.keepalive) nc->flags |= MG_F_SEND_AND_CLOSE;
4863  }
4864  }
4865 #ifndef MG_DISABLE_CGI
4866  else if (pd->cgi.cgi_nc != NULL) {
4867  /* This is POST data that needs to be forwarded to the CGI process */
4868  if (pd->cgi.cgi_nc != NULL) {
4869  mg_forward(nc, pd->cgi.cgi_nc);
4870  } else {
4871  nc->flags |= MG_F_SEND_AND_CLOSE;
4872  }
4873  }
4874 #endif
4875 }
4876 #endif /* MG_DISABLE_FILESYSTEM */
4877 
4878 /*
4879  * Parse chunked-encoded buffer. Return 0 if the buffer is not encoded, or
4880  * if it's incomplete. If the chunk is fully buffered, return total number of
4881  * bytes in a chunk, and store data in `data`, `data_len`.
4882  */
4883 static size_t mg_http_parse_chunk(char *buf, size_t len, char **chunk_data,
4884  size_t *chunk_len) {
4885  unsigned char *s = (unsigned char *) buf;
4886  size_t n = 0; /* scanned chunk length */
4887  size_t i = 0; /* index in s */
4888 
4889  /* Scan chunk length. That should be a hexadecimal number. */
4890  while (i < len && isxdigit(s[i])) {
4891  n *= 16;
4892  n += (s[i] >= '0' && s[i] <= '9') ? s[i] - '0' : tolower(s[i]) - 'a' + 10;
4893  i++;
4894  }
4895 
4896  /* Skip new line */
4897  if (i == 0 || i + 2 > len || s[i] != '\r' || s[i + 1] != '\n') {
4898  return 0;
4899  }
4900  i += 2;
4901 
4902  /* Record where the data is */
4903  *chunk_data = (char *) s + i;
4904  *chunk_len = n;
4905 
4906  /* Skip data */
4907  i += n;
4908 
4909  /* Skip new line */
4910  if (i == 0 || i + 2 > len || s[i] != '\r' || s[i + 1] != '\n') {
4911  return 0;
4912  }
4913  return i + 2;
4914 }
4915 
4917  struct http_message *hm, char *buf,
4918  size_t blen) {
4919  struct mg_http_proto_data *pd = mg_http_get_proto_data(nc);
4920  char *data;
4921  size_t i, n, data_len, body_len, zero_chunk_received = 0;
4922 
4923  /* Find out piece of received data that is not yet reassembled */
4924  body_len = pd->chunk.body_len;
4925  assert(blen >= body_len);
4926 
4927  /* Traverse all fully buffered chunks */
4928  for (i = body_len;
4929  (n = mg_http_parse_chunk(buf + i, blen - i, &data, &data_len)) > 0;
4930  i += n) {
4931  /* Collapse chunk data to the rest of HTTP body */
4932  memmove(buf + body_len, data, data_len);
4933  body_len += data_len;
4934  hm->body.len = body_len;
4935 
4936  if (data_len == 0) {
4937  zero_chunk_received = 1;
4938  i += n;
4939  break;
4940  }
4941  }
4942 
4943  if (i > body_len) {
4944  /* Shift unparsed content to the parsed body */
4945  assert(i <= blen);
4946  memmove(buf + body_len, buf + i, blen - i);
4947  memset(buf + body_len + blen - i, 0, i - body_len);
4948  nc->recv_mbuf.len -= i - body_len;
4949  pd->chunk.body_len = body_len;
4950 
4951  /* Send MG_EV_HTTP_CHUNK event */
4952  nc->flags &= ~MG_F_DELETE_CHUNK;
4953  mg_call(nc, nc->handler, MG_EV_HTTP_CHUNK, hm);
4954 
4955  /* Delete processed data if user set MG_F_DELETE_CHUNK flag */
4956  if (nc->flags & MG_F_DELETE_CHUNK) {
4957  memset(buf, 0, body_len);
4958  memmove(buf, buf + body_len, blen - i);
4959  nc->recv_mbuf.len -= body_len;
4960  hm->body.len = pd->chunk.body_len = 0;
4961  }
4962 
4963  if (zero_chunk_received) {
4964  hm->message.len = pd->chunk.body_len + blen - i;
4965  }
4966  }
4967 
4968  return body_len;
4969 }
4970 
4972  struct mg_connection *nc, struct mg_str *uri_path) {
4973  struct mg_http_proto_data *pd;
4974  mg_event_handler_t ret = NULL;
4975  int matched, matched_max = 0;
4976  struct mg_http_endpoint *ep;
4977 
4978  if (nc == NULL) {
4979  return NULL;
4980  }
4981 
4982  pd = mg_http_get_proto_data(nc);
4983 
4984  ep = pd->endpoints;
4985  while (ep != NULL) {
4986  const struct mg_str name_s = {ep->name, ep->name_len};
4987  if ((matched = mg_match_prefix_n(name_s, *uri_path)) != -1) {
4988  if (matched > matched_max) {
4989  /* Looking for the longest suitable handler */
4990  ret = ep->handler;
4991  matched_max = matched;
4992  }
4993  }
4994 
4995  ep = ep->next;
4996  }
4997 
4998  return ret;
4999 }
5000 
5001 static void mg_http_call_endpoint_handler(struct mg_connection *nc, int ev,
5002  struct http_message *hm) {
5003  struct mg_http_proto_data *pd = mg_http_get_proto_data(nc);
5004 
5005  if (pd->endpoint_handler == NULL || ev == MG_EV_HTTP_REQUEST) {
5006  pd->endpoint_handler =
5007  ev == MG_EV_HTTP_REQUEST
5009  : NULL;
5010  }
5011  mg_call(nc, pd->endpoint_handler ? pd->endpoint_handler : nc->handler, ev,
5012  hm);
5013 }
5014 
5015 #ifdef MG_ENABLE_HTTP_STREAMING_MULTIPART
5016 static void mg_http_multipart_continue(struct mg_connection *nc);
5017 
5018 static void mg_http_multipart_begin(struct mg_connection *nc,
5019  struct http_message *hm, int req_len);
5020 
5021 #endif
5022 
5023 /*
5024  * lx106 compiler has a bug (TODO(mkm) report and insert tracking bug here)
5025  * If a big structure is declared in a big function, lx106 gcc will make it
5026  * even bigger (round up to 4k, from 700 bytes of actual size).
5027  */
5028 #ifdef __xtensa__
5029 static void mg_http_handler2(struct mg_connection *nc, int ev, void *ev_data,
5030  struct http_message *hm) __attribute__((noinline));
5031 
5032 void mg_http_handler(struct mg_connection *nc, int ev, void *ev_data) {
5033  struct http_message hm;
5034  mg_http_handler2(nc, ev, ev_data, &hm);
5035 }
5036 
5037 static void mg_http_handler2(struct mg_connection *nc, int ev, void *ev_data,
5038  struct http_message *hm) {
5039 #else /* !__XTENSA__ */
5040  void mg_http_handler(struct mg_connection *nc, int ev, void *ev_data) {
5041  struct http_message shm;
5042  struct http_message *hm = &shm;
5043 #endif /* __XTENSA__ */
5044  struct mg_http_proto_data *pd = mg_http_get_proto_data(nc);
5045  struct mbuf *io = &nc->recv_mbuf;
5046  int req_len;
5047  const int is_req = (nc->listener != NULL);
5048 #ifndef MG_DISABLE_HTTP_WEBSOCKET
5049  struct mg_str *vec;
5050 #endif
5051  if (ev == MG_EV_CLOSE) {
5052 #ifdef MG_ENABLE_HTTP_STREAMING_MULTIPART
5053  if (pd->mp_stream.boundary != NULL) {
5054  /*
5055  * Multipart message is in progress, but we get close
5056  * MG_EV_HTTP_PART_END with error flag
5057  */
5058  struct mg_http_multipart_part mp;
5059  memset(&mp, 0, sizeof(mp));
5060 
5061  mp.status = -1;
5062  mp.var_name = pd->mp_stream.var_name;
5063  mp.file_name = pd->mp_stream.file_name;
5064  mg_call(nc, (pd->endpoint_handler ? pd->endpoint_handler : nc->handler),
5065  MG_EV_HTTP_PART_END, &mp);
5066  } else
5067 #endif
5068  if (io->len > 0 && mg_parse_http(io->buf, io->len, hm, is_req) > 0) {
5069  /*
5070  * For HTTP messages without Content-Length, always send HTTP message
5071  * before MG_EV_CLOSE message.
5072  */
5073  int ev2 = is_req ? MG_EV_HTTP_REQUEST : MG_EV_HTTP_REPLY;
5074  hm->message.len = io->len;
5075  hm->body.len = io->buf + io->len - hm->body.p;
5076  mg_http_call_endpoint_handler(nc, ev2, hm);
5077  }
5078  }
5079 
5080 #ifndef MG_DISABLE_FILESYSTEM
5081  if (pd->file.fp != NULL) {
5083  }
5084 #endif
5085 
5086  mg_call(nc, nc->handler, ev, ev_data);
5087 
5088  if (ev == MG_EV_RECV) {
5089  struct mg_str *s;
5090 
5091 #ifdef MG_ENABLE_HTTP_STREAMING_MULTIPART
5092  if (pd->mp_stream.boundary != NULL) {
5093  mg_http_multipart_continue(nc);
5094  return;
5095  }
5096 #endif /* MG_ENABLE_HTTP_STREAMING_MULTIPART */
5097 
5098  req_len = mg_parse_http(io->buf, io->len, hm, is_req);
5099 
5100  if (req_len > 0 &&
5101  (s = mg_get_http_header(hm, "Transfer-Encoding")) != NULL &&
5102  mg_vcasecmp(s, "chunked") == 0) {
5103  mg_handle_chunked(nc, hm, io->buf + req_len, io->len - req_len);
5104  }
5105 
5106 #ifdef MG_ENABLE_HTTP_STREAMING_MULTIPART
5107  if (req_len > 0 && (s = mg_get_http_header(hm, "Content-Type")) != NULL &&
5108  s->len >= 9 && strncmp(s->p, "multipart", 9) == 0) {
5109  mg_http_multipart_begin(nc, hm, req_len);
5110  mg_http_multipart_continue(nc);
5111  return;
5112  }
5113 #endif /* MG_ENABLE_HTTP_STREAMING_MULTIPART */
5114 
5115  /* TODO(alashkin): refactor this ifelseifelseifelseifelse */
5116  if ((req_len < 0 ||
5117  (req_len == 0 && io->len >= MG_MAX_HTTP_REQUEST_SIZE))) {
5118  DBG(("invalid request"));
5120  } else if (req_len == 0) {
5121  /* Do nothing, request is not yet fully buffered */
5122  }
5123 #ifndef MG_DISABLE_HTTP_WEBSOCKET
5124  else if (nc->listener == NULL &&
5125  mg_get_http_header(hm, "Sec-WebSocket-Accept")) {
5126  /* We're websocket client, got handshake response from server. */
5127  /* TODO(lsm): check the validity of accept Sec-WebSocket-Accept */
5128  mbuf_remove(io, req_len);
5130  nc->flags |= MG_F_IS_WEBSOCKET;
5132  mg_websocket_handler(nc, MG_EV_RECV, ev_data);
5133  } else if (nc->listener != NULL &&
5134  (vec = mg_get_http_header(hm, "Sec-WebSocket-Key")) != NULL) {
5135  /* This is a websocket request. Switch protocol handlers. */
5136  mbuf_remove(io, req_len);
5138  nc->flags |= MG_F_IS_WEBSOCKET;
5139 
5140  /* Send handshake */
5142  if (!(nc->flags & MG_F_CLOSE_IMMEDIATELY)) {
5143  if (nc->send_mbuf.len == 0) {
5144  mg_ws_handshake(nc, vec);
5145  }
5147  mg_websocket_handler(nc, MG_EV_RECV, ev_data);
5148  }
5149 #endif /* MG_DISABLE_HTTP_WEBSOCKET */
5150  } else if (hm->message.len <= io->len) {
5151  int trigger_ev = nc->listener ? MG_EV_HTTP_REQUEST : MG_EV_HTTP_REPLY;
5152 
5153  /* Whole HTTP message is fully buffered, call event handler */
5154 
5155 #ifdef MG_ENABLE_JAVASCRIPT
5156  v7_val_t v1, v2, headers, req, args, res;
5157  struct v7 *v7 = nc->mgr->v7;
5158  const char *ev_name = trigger_ev == MG_EV_HTTP_REPLY ? "onsnd" : "onrcv";
5159  int i, js_callback_handled_request = 0;
5160 
5161  if (v7 != NULL) {
5162  /* Lookup JS callback */
5163  v1 = v7_get(v7, v7_get_global(v7), "Http", ~0);
5164  v2 = v7_get(v7, v1, ev_name, ~0);
5165 
5166  /* Create callback params. TODO(lsm): own/disown those */
5167  args = v7_mk_array(v7);
5168  req = v7_mk_object(v7);
5169  headers = v7_mk_object(v7);
5170 
5171  /* Populate request object */
5172  v7_set(v7, req, "method", ~0,
5173  v7_mk_string(v7, hm->method.p, hm->method.len, 1));
5174  v7_set(v7, req, "uri", ~0, v7_mk_string(v7, hm->uri.p, hm->uri.len, 1));
5175  v7_set(v7, req, "body", ~0,
5176  v7_mk_string(v7, hm->body.p, hm->body.len, 1));
5177  v7_set(v7, req, "headers", ~0, headers);
5178  for (i = 0; hm->header_names[i].len > 0; i++) {
5179  const struct mg_str *name = &hm->header_names[i];
5180  const struct mg_str *value = &hm->header_values[i];
5181  v7_set(v7, headers, name->p, name->len,
5182  v7_mk_string(v7, value->p, value->len, 1));
5183  }
5184 
5185  /* Invoke callback. TODO(lsm): report errors */
5186  v7_array_push(v7, args, v7_mk_foreign(nc));
5187  v7_array_push(v7, args, req);
5188  if (v7_apply(v7, v2, v7_mk_undefined(), args, &res) == V7_OK &&
5189  v7_is_truthy(v7, res)) {
5190  js_callback_handled_request++;
5191  }
5192  }
5193 
5194  /* If JS callback returns true, stop request processing */
5195  if (js_callback_handled_request) {
5196  nc->flags |= MG_F_SEND_AND_CLOSE;
5197  } else {
5198  mg_http_call_endpoint_handler(nc, trigger_ev, hm);
5199  }
5200 #else
5201  mg_http_call_endpoint_handler(nc, trigger_ev, hm);
5202 #endif
5203  mbuf_remove(io, hm->message.len);
5204  }
5205  }
5206  (void) pd;
5207  }
5208 
5209  static size_t mg_get_line_len(const char *buf, size_t buf_len) {
5210  size_t len = 0;
5211  while (len < buf_len && buf[len] != '\n') len++;
5212  return len == buf_len ? 0 : len + 1;
5213  }
5214 
5215 #ifdef MG_ENABLE_HTTP_STREAMING_MULTIPART
5216  static void mg_http_multipart_begin(struct mg_connection *nc,
5217  struct http_message *hm, int req_len) {
5218  struct mg_http_proto_data *pd = mg_http_get_proto_data(nc);
5219  struct mg_str *ct;
5220  struct mbuf *io = &nc->recv_mbuf;
5221 
5222  char boundary[100];
5223  int boundary_len;
5224 
5225  if (nc->listener == NULL) {
5226  /* No streaming for replies now */
5227  goto exit_mp;
5228  }
5229 
5230  ct = mg_get_http_header(hm, "Content-Type");
5231  if (ct == NULL) {
5232  /* We need more data - or it isn't multipart mesage */
5233  goto exit_mp;
5234  }
5235 
5236  /* Content-type should start with "multipart" */
5237  if (ct->len < 9 || strncmp(ct->p, "multipart", 9) != 0) {
5238  goto exit_mp;
5239  }
5240 
5241  boundary_len =
5242  mg_http_parse_header(ct, "boundary", boundary, sizeof(boundary));
5243  if (boundary_len == 0) {
5244  /*
5245  * Content type is multipart, but there is no boundary,
5246  * probably malformed request
5247  */
5249  DBG(("invalid request"));
5250  goto exit_mp;
5251  }
5252 
5253  /* If we reach this place - that is multipart request */
5254 
5255  if (pd->mp_stream.boundary != NULL) {
5256  /*
5257  * Another streaming request was in progress,
5258  * looks like protocol error
5259  */
5261  } else {
5262  pd->mp_stream.boundary = strdup(boundary);
5263  pd->mp_stream.boundary_len = strlen(boundary);
5264  pd->mp_stream.var_name = pd->mp_stream.file_name = NULL;
5265 
5267  if (pd->endpoint_handler == NULL) {
5268  pd->endpoint_handler = nc->handler;
5269  }
5270 
5271  mg_call(nc, pd->endpoint_handler, MG_EV_HTTP_MULTIPART_REQUEST, hm);
5272 
5273  mbuf_remove(io, req_len);
5274  }
5275  exit_mp:
5276  ;
5277  }
5278 
5279 #define CONTENT_DISPOSITION "Content-Disposition: "
5280 
5281  static void mg_http_multipart_call_handler(struct mg_connection *c, int ev,
5282  const char *data, size_t data_len) {
5283  struct mg_http_multipart_part mp;
5285  memset(&mp, 0, sizeof(mp));
5286 
5287  mp.var_name = pd->mp_stream.var_name;
5288  mp.file_name = pd->mp_stream.file_name;
5289  mp.user_data = pd->mp_stream.user_data;
5290  mp.data.p = data;
5291  mp.data.len = data_len;
5292  mg_call(c, pd->endpoint_handler, ev, &mp);
5293  pd->mp_stream.user_data = mp.user_data;
5294  }
5295 
5296  static int mg_http_multipart_got_chunk(struct mg_connection *c) {
5298  struct mbuf *io = &c->recv_mbuf;
5299 
5300  mg_http_multipart_call_handler(c, MG_EV_HTTP_PART_DATA, io->buf,
5301  pd->mp_stream.prev_io_len);
5302  mbuf_remove(io, pd->mp_stream.prev_io_len);
5303  pd->mp_stream.prev_io_len = 0;
5304  pd->mp_stream.state = MPS_WAITING_FOR_CHUNK;
5305 
5306  return 0;
5307  }
5308 
5309  static int mg_http_multipart_finalize(struct mg_connection *c) {
5311 
5312  mg_http_multipart_call_handler(c, MG_EV_HTTP_PART_END, NULL, 0);
5313  mg_http_free_proto_data_mp_stream(&pd->mp_stream);
5314  pd->mp_stream.state = MPS_FINISHED;
5315 
5316  return 1;
5317  }
5318 
5319  static int mg_http_multipart_wait_for_boundary(struct mg_connection *c) {
5320  const char *boundary;
5321  struct mbuf *io = &c->recv_mbuf;
5323 
5324  if ((int) io->len < pd->mp_stream.boundary_len + 2) {
5325  return 0;
5326  }
5327 
5328  boundary = c_strnstr(io->buf, pd->mp_stream.boundary, io->len);
5329  if (boundary != NULL) {
5330  if (io->len - (boundary - io->buf) < 4) {
5331  return 0;
5332  }
5333  if (memcmp(boundary + pd->mp_stream.boundary_len, "--", 2) == 0) {
5334  pd->mp_stream.state = MPS_FINALIZE;
5335  } else {
5336  pd->mp_stream.state = MPS_GOT_BOUNDARY;
5337  }
5338  } else {
5339  return 0;
5340  }
5341 
5342  return 1;
5343  }
5344 
5345  static int mg_http_multipart_process_boundary(struct mg_connection *c) {
5346  int data_size;
5347  const char *boundary, *block_begin;
5348  struct mbuf *io = &c->recv_mbuf;
5350  char file_name[100], var_name[100];
5351  int line_len;
5352  boundary = c_strnstr(io->buf, pd->mp_stream.boundary, io->len);
5353  block_begin = boundary + pd->mp_stream.boundary_len + 2;
5354  data_size = io->len - (block_begin - io->buf);
5355 
5356  while (data_size > 0 &&
5357  (line_len = mg_get_line_len(block_begin, data_size)) != 0) {
5358  if (line_len > (int) sizeof(CONTENT_DISPOSITION) &&
5359  mg_ncasecmp(block_begin, CONTENT_DISPOSITION,
5360  sizeof(CONTENT_DISPOSITION) - 1) == 0) {
5361  struct mg_str header;
5362 
5363  header.p = block_begin + sizeof(CONTENT_DISPOSITION) - 1;
5364  header.len = line_len - sizeof(CONTENT_DISPOSITION) - 1;
5365  mg_http_parse_header(&header, "name", var_name, sizeof(var_name) - 2);
5366  mg_http_parse_header(&header, "filename", file_name,
5367  sizeof(file_name) - 2);
5368  block_begin += line_len;
5369  data_size -= line_len;
5370  continue;
5371  }
5372 
5373  if (line_len == 2 && mg_ncasecmp(block_begin, "\r\n", 2) == 0) {
5374  mbuf_remove(io, block_begin - io->buf + 2);
5375 
5376  if (pd->mp_stream.processing_part != 0) {
5377  mg_http_multipart_call_handler(c, MG_EV_HTTP_PART_END, NULL, 0);
5378  }
5379 
5380  free((void *) pd->mp_stream.file_name);
5381  pd->mp_stream.file_name = strdup(file_name);
5382  free((void *) pd->mp_stream.var_name);
5383  pd->mp_stream.var_name = strdup(var_name);
5384 
5385  mg_http_multipart_call_handler(c, MG_EV_HTTP_PART_BEGIN, NULL, 0);
5386  pd->mp_stream.state = MPS_WAITING_FOR_CHUNK;
5387  pd->mp_stream.processing_part++;
5388  return 1;
5389  }
5390 
5391  block_begin += line_len;
5392  }
5393 
5394  pd->mp_stream.state = MPS_WAITING_FOR_BOUNDARY;
5395 
5396  return 0;
5397  }
5398 
5399  static int mg_http_multipart_continue_wait_for_chunk(struct mg_connection *c) {
5401  struct mbuf *io = &c->recv_mbuf;
5402 
5403  const char *boundary;
5404  if ((int) io->len < pd->mp_stream.boundary_len + 6 /* \r\n, --, -- */) {
5405  return 0;
5406  }
5407 
5408  boundary = c_strnstr(io->buf, pd->mp_stream.boundary, io->len);
5409  if (boundary == NULL && pd->mp_stream.prev_io_len == 0) {
5410  pd->mp_stream.prev_io_len = io->len;
5411  return 0;
5412  } else if (boundary == NULL &&
5413  (int) io->len >
5414  pd->mp_stream.prev_io_len + pd->mp_stream.boundary_len + 4) {
5415  pd->mp_stream.state = MPS_GOT_CHUNK;
5416  return 1;
5417  } else if (boundary != NULL) {
5418  int data_size = (boundary - io->buf - 4);
5419  mg_http_multipart_call_handler(c, MG_EV_HTTP_PART_DATA, io->buf, data_size);
5420  mbuf_remove(io, (boundary - io->buf));
5421  pd->mp_stream.prev_io_len = 0;
5422  pd->mp_stream.state = MPS_WAITING_FOR_BOUNDARY;
5423  return 1;
5424  } else {
5425  return 0;
5426  }
5427  }
5428 
5429  static void mg_http_multipart_continue(struct mg_connection *c) {
5431  while (1) {
5432  switch (pd->mp_stream.state) {
5433  case MPS_BEGIN: {
5434  pd->mp_stream.state = MPS_WAITING_FOR_BOUNDARY;
5435  break;
5436  }
5437  case MPS_WAITING_FOR_BOUNDARY: {
5438  if (mg_http_multipart_wait_for_boundary(c) == 0) {
5439  return;
5440  }
5441  break;
5442  }
5443  case MPS_GOT_BOUNDARY: {
5444  if (mg_http_multipart_process_boundary(c) == 0) {
5445  return;
5446  }
5447  break;
5448  }
5449  case MPS_WAITING_FOR_CHUNK: {
5450  if (mg_http_multipart_continue_wait_for_chunk(c) == 0) {
5451  return;
5452  }
5453  break;
5454  }
5455  case MPS_GOT_CHUNK: {
5456  if (mg_http_multipart_got_chunk(c) == 0) {
5457  return;
5458  }
5459  break;
5460  }
5461  case MPS_FINALIZE: {
5462  if (mg_http_multipart_finalize(c) == 0) {
5463  return;
5464  }
5465  break;
5466  }
5467  case MPS_FINISHED: {
5469  return;
5470  }
5471  }
5472  }
5473  }
5474 
5475  struct file_upload_state {
5476  char *lfn;
5477  size_t num_recd;
5478  FILE *fp;
5479  };
5480 
5481  void mg_file_upload_handler(struct mg_connection *nc, int ev, void *ev_data,
5482  mg_fu_fname_fn local_name_fn) {
5483  switch (ev) {
5484  case MG_EV_HTTP_PART_BEGIN: {
5485  struct mg_http_multipart_part *mp =
5486  (struct mg_http_multipart_part *) ev_data;
5487  struct file_upload_state *fus =
5488  (struct file_upload_state *) calloc(1, sizeof(*fus));
5489  mp->user_data = NULL;
5490 
5491  struct mg_str lfn = local_name_fn(nc, mg_mk_str(mp->file_name));
5492  if (lfn.p == NULL || lfn.len == 0) {
5493  LOG(LL_ERROR, ("%p Not allowed to upload %s", nc, mp->file_name));
5494  mg_printf(nc,
5495  "HTTP/1.1 403 Not Allowed\r\n"
5496  "Content-Type: text/plain\r\n"
5497  "Connection: close\r\n\r\n"
5498  "Not allowed to upload %s\r\n",
5499  mp->file_name);
5500  nc->flags |= MG_F_SEND_AND_CLOSE;
5501  return;
5502  }
5503  fus->lfn = (char *) malloc(lfn.len + 1);
5504  memcpy(fus->lfn, lfn.p, lfn.len);
5505  fus->lfn[lfn.len] = '\0';
5506  if (lfn.p != mp->file_name) free((char *) lfn.p);
5507  LOG(LL_DEBUG,
5508  ("%p Receiving file %s -> %s", nc, mp->file_name, fus->lfn));
5509  fus->fp = fopen(fus->lfn, "w");
5510  if (fus->fp == NULL) {
5511  mg_printf(nc,
5512  "HTTP/1.1 500 Internal Server Error\r\n"
5513  "Content-Type: text/plain\r\n"
5514  "Connection: close\r\n\r\n");
5515  LOG(LL_ERROR, ("Failed to open %s: %d\n", fus->lfn, errno));
5516  mg_printf(nc, "Failed to open %s: %d\n", fus->lfn, errno);
5517  /* Do not close the connection just yet, discard remainder of the data.
5518  * This is because at the time of writing some browsers (Chrome) fail to
5519  * render response before all the data is sent. */
5520  }
5521  mp->user_data = (void *) fus;
5522  break;
5523  }
5524  case MG_EV_HTTP_PART_DATA: {
5525  struct mg_http_multipart_part *mp =
5526  (struct mg_http_multipart_part *) ev_data;
5527  struct file_upload_state *fus =
5528  (struct file_upload_state *) mp->user_data;
5529  if (fus == NULL || fus->fp == NULL) break;
5530  if (fwrite(mp->data.p, 1, mp->data.len, fus->fp) != mp->data.len) {
5531  LOG(LL_ERROR, ("Failed to write to %s: %d, wrote %d", fus->lfn, errno,
5532  (int) fus->num_recd));
5533  if (errno == ENOSPC
5534 #ifdef SPIFFS_ERR_FULL
5535  || errno == SPIFFS_ERR_FULL
5536 #endif
5537  ) {
5538  mg_printf(nc,
5539  "HTTP/1.1 413 Payload Too Large\r\n"
5540  "Content-Type: text/plain\r\n"
5541  "Connection: close\r\n\r\n");
5542  mg_printf(nc, "Failed to write to %s: no space left; wrote %d\r\n",
5543  fus->lfn, (int) fus->num_recd);
5544  } else {
5545  mg_printf(nc,
5546  "HTTP/1.1 500 Internal Server Error\r\n"
5547  "Content-Type: text/plain\r\n"
5548  "Connection: close\r\n\r\n");
5549  mg_printf(nc, "Failed to write to %s: %d, wrote %d", mp->file_name,
5550  errno, (int) fus->num_recd);
5551  }
5552  fclose(fus->fp);
5553  remove(fus->lfn);
5554  fus->fp = NULL;
5555  /* Do not close the connection just yet, discard remainder of the data.
5556  * This is because at the time of writing some browsers (Chrome) fail to
5557  * render response before all the data is sent. */
5558  return;
5559  }
5560  fus->num_recd += mp->data.len;
5561  LOG(LL_DEBUG, ("%p rec'd %d bytes, %d total", nc, (int) mp->data.len,
5562  (int) fus->num_recd));
5563  break;
5564  }
5565  case MG_EV_HTTP_PART_END: {
5566  struct mg_http_multipart_part *mp =
5567  (struct mg_http_multipart_part *) ev_data;
5568  struct file_upload_state *fus =
5569  (struct file_upload_state *) mp->user_data;
5570  if (fus == NULL) break;
5571  if (mp->status >= 0 && fus->fp != NULL) {
5572  LOG(LL_DEBUG, ("%p Uploaded %s (%s), %d bytes", nc, mp->file_name,
5573  fus->lfn, (int) fus->num_recd));
5574  mg_printf(nc,
5575  "HTTP/1.1 200 OK\r\n"
5576  "Content-Type: text/plain\r\n"
5577  "Connection: close\r\n\r\n"
5578  "Ok, %s - %d bytes.\r\n",
5579  mp->file_name, (int) fus->num_recd);
5580  } else {
5581  LOG(LL_ERROR, ("Failed to store %s (%s)", mp->file_name, fus->lfn));
5582  /*
5583  * mp->status < 0 means connection was terminated, so no reason to send
5584  * HTTP reply
5585  */
5586  }
5587  if (fus->fp != NULL) fclose(fus->fp);
5588  free(fus->lfn);
5589  free(fus);
5590  mp->user_data = NULL;
5591  nc->flags |= MG_F_SEND_AND_CLOSE;
5592  break;
5593  }
5594  }
5595  }
5596 
5597 #endif /* MG_ENABLE_HTTP_STREAMING_MULTIPART */
5598 
5601  }
5602 
5603 #ifndef MG_DISABLE_HTTP_WEBSOCKET
5604 
5605  void mg_send_websocket_handshake2(struct mg_connection *nc, const char *path,
5606  const char *host, const char *protocol,
5607  const char *extra_headers) {
5608  /* pretty poor source of randomness, TODO fix */
5609  unsigned long random = (unsigned long) path;
5610  char key[sizeof(random) * 3];
5611 
5612  mg_base64_encode((unsigned char *) &random, sizeof(random), key);
5613  mg_printf(nc,
5614  "GET %s HTTP/1.1\r\n"
5615  "Upgrade: websocket\r\n"
5616  "Connection: Upgrade\r\n"
5617  "Sec-WebSocket-Version: 13\r\n"
5618  "Sec-WebSocket-Key: %s\r\n",
5619  path, key);
5620 
5621  /* TODO(mkm): take default hostname from http proto data if host == NULL */
5622  if (host != MG_WS_NO_HOST_HEADER_MAGIC) {
5623  mg_printf(nc, "Host: %s\r\n", host);
5624  }
5625  if (protocol != NULL) {
5626  mg_printf(nc, "Sec-WebSocket-Protocol: %s\r\n", protocol);
5627  }
5628  if (extra_headers != NULL) {
5629  mg_printf(nc, "%s", extra_headers);
5630  }
5631  mg_printf(nc, "\r\n");
5632  }
5633 
5634  void mg_send_websocket_handshake(struct mg_connection *nc, const char *path,
5635  const char *extra_headers) {
5637  extra_headers);
5638  }
5639 
5640 #endif /* MG_DISABLE_HTTP_WEBSOCKET */
5641 
5642  void mg_send_response_line(struct mg_connection *nc, int status_code,
5643  const char *extra_headers) {
5644  const char *status_message = "OK";
5645  switch (status_code) {
5646  case 206:
5647  status_message = "Partial Content";
5648  break;
5649  case 301:
5650  status_message = "Moved";
5651  break;
5652  case 302:
5653  status_message = "Found";
5654  break;
5655  case 401:
5656  status_message = "Unauthorized";
5657  break;
5658  case 403:
5659  status_message = "Forbidden";
5660  break;
5661  case 404:
5662  status_message = "Not Found";
5663  break;
5664  case 416:
5665  status_message = "Requested range not satisfiable";
5666  break;
5667  case 418:
5668  status_message = "I'm a teapot";
5669  break;
5670  case 500:
5671  status_message = "Internal Server Error";
5672  break;
5673  }
5674  mg_printf(nc, "HTTP/1.1 %d %s\r\nServer: %s\r\n", status_code, status_message,
5675  mg_version_header);
5676  if (extra_headers != NULL) {
5677  mg_printf(nc, "%s\r\n", extra_headers);
5678  }
5679  }
5680 
5681  void mg_send_head(struct mg_connection *c, int status_code,
5682  int64_t content_length, const char *extra_headers) {
5683  mg_send_response_line(c, status_code, extra_headers);
5684  if (content_length < 0) {
5685  mg_printf(c, "%s", "Transfer-Encoding: chunked\r\n");
5686  } else {
5687  mg_printf(c, "Content-Length: %" INT64_FMT "\r\n", content_length);
5688  }
5689  mg_send(c, "\r\n", 2);
5690  }
5691 
5692 #ifdef MG_DISABLE_FILESYSTEM
5693  void mg_serve_http(struct mg_connection *nc, struct http_message *hm,
5694  struct mg_serve_http_opts opts) {
5695  mg_send_head(nc, 501, 0, NULL);
5696  }
5697 #else
5698  static void mg_http_send_error(struct mg_connection *nc, int code,
5699  const char *reason) {
5700  if (!reason) reason = "";
5701  DBG(("%p %d %s", nc, code, reason));
5702  mg_send_head(nc, code, strlen(reason),
5703  "Content-Type: text/plain\r\nConnection: close");
5704  mg_send(nc, reason, strlen(reason));
5705  nc->flags |= MG_F_SEND_AND_CLOSE;
5706  }
5707 #ifndef MG_DISABLE_SSI
5708  static void mg_send_ssi_file(struct mg_connection *, const char *, FILE *, int,
5709  const struct mg_serve_http_opts *);
5710 
5711  static void mg_send_file_data(struct mg_connection *nc, FILE *fp) {
5712  char buf[BUFSIZ];
5713  size_t n;
5714  while ((n = fread(buf, 1, sizeof(buf), fp)) > 0) {
5715  mg_send(nc, buf, n);
5716  }
5717  }
5718 
5719  static void mg_do_ssi_include(struct mg_connection *nc, const char *ssi,
5720  char *tag, int include_level,
5721  const struct mg_serve_http_opts *opts) {
5722  char file_name[BUFSIZ], path[MAX_PATH_SIZE], *p;
5723  FILE *fp;
5724 
5725  /*
5726  * sscanf() is safe here, since send_ssi_file() also uses buffer
5727  * of size MG_BUF_LEN to get the tag. So strlen(tag) is always < MG_BUF_LEN.
5728  */
5729  if (sscanf(tag, " virtual=\"%[^\"]\"", file_name) == 1) {
5730  /* File name is relative to the webserver root */
5731  snprintf(path, sizeof(path), "%s/%s", opts->document_root, file_name);
5732  } else if (sscanf(tag, " abspath=\"%[^\"]\"", file_name) == 1) {
5733  /*
5734  * File name is relative to the webserver working directory
5735  * or it is absolute system path
5736  */
5737  snprintf(path, sizeof(path), "%s", file_name);
5738  } else if (sscanf(tag, " file=\"%[^\"]\"", file_name) == 1 ||
5739  sscanf(tag, " \"%[^\"]\"", file_name) == 1) {
5740  /* File name is relative to the currect document */
5741  snprintf(path, sizeof(path), "%s", ssi);
5742  if ((p = strrchr(path, DIRSEP)) != NULL) {
5743  p[1] = '\0';
5744  }
5745  snprintf(path + strlen(path), sizeof(path) - strlen(path), "%s", file_name);
5746  } else {
5747  mg_printf(nc, "Bad SSI #include: [%s]", tag);
5748  return;
5749  }
5750 
5751  if ((fp = fopen(path, "rb")) == NULL) {
5752  mg_printf(nc, "SSI include error: fopen(%s): %s", path, strerror(errno));
5753  } else {
5754  mg_set_close_on_exec(fileno(fp));
5755  if (mg_match_prefix(opts->ssi_pattern, strlen(opts->ssi_pattern), path) >
5756  0) {
5757  mg_send_ssi_file(nc, path, fp, include_level + 1, opts);
5758  } else {
5759  mg_send_file_data(nc, fp);
5760  }
5761  fclose(fp);
5762  }
5763  }
5764 
5765 #ifndef MG_DISABLE_POPEN
5766  static void do_ssi_exec(struct mg_connection *nc, char *tag) {
5767  char cmd[BUFSIZ];
5768  FILE *fp;
5769 
5770  if (sscanf(tag, " \"%[^\"]\"", cmd) != 1) {
5771  mg_printf(nc, "Bad SSI #exec: [%s]", tag);
5772  } else if ((fp = popen(cmd, "r")) == NULL) {
5773  mg_printf(nc, "Cannot SSI #exec: [%s]: %s", cmd, strerror(errno));
5774  } else {
5775  mg_send_file_data(nc, fp);
5776  pclose(fp);
5777  }
5778  }
5779 #endif /* !MG_DISABLE_POPEN */
5780 
5781  static void mg_do_ssi_call(struct mg_connection *nc, char *tag) {
5782  mg_call(nc, NULL, MG_EV_SSI_CALL, tag);
5783  }
5784 
5785  /*
5786  * SSI directive has the following format:
5787  * <!--#directive parameter=value parameter=value -->
5788  */
5789  static void mg_send_ssi_file(struct mg_connection *nc, const char *path,
5790  FILE *fp, int include_level,
5791  const struct mg_serve_http_opts *opts) {
5792  static const struct mg_str btag = MG_MK_STR("<!--#");
5793  static const struct mg_str d_include = MG_MK_STR("include");
5794  static const struct mg_str d_call = MG_MK_STR("call");
5795 #ifndef MG_DISABLE_POPEN
5796  static const struct mg_str d_exec = MG_MK_STR("exec");
5797 #endif
5798  char buf[BUFSIZ], *p = buf + btag.len; /* p points to SSI directive */
5799  int ch, len, in_ssi_tag;
5800 
5801  if (include_level > 10) {
5802  mg_printf(nc, "SSI #include level is too deep (%s)", path);
5803  return;
5804  }
5805 
5806  in_ssi_tag = len = 0;
5807  while ((ch = fgetc(fp)) != EOF) {
5808  if (in_ssi_tag && ch == '>' && buf[len - 1] == '-' && buf[len - 2] == '-') {
5809  size_t i = len - 2;
5810  in_ssi_tag = 0;
5811 
5812  /* Trim closing --> */
5813  buf[i--] = '\0';
5814  while (i > 0 && buf[i] == ' ') {
5815  buf[i--] = '\0';
5816  }
5817 
5818  /* Handle known SSI directives */
5819  if (memcmp(p, d_include.p, d_include.len) == 0) {
5820  mg_do_ssi_include(nc, path, p + d_include.len + 1, include_level, opts);
5821  } else if (memcmp(p, d_call.p, d_call.len) == 0) {
5822  mg_do_ssi_call(nc, p + d_call.len + 1);
5823 #ifndef MG_DISABLE_POPEN
5824  } else if (memcmp(p, d_exec.p, d_exec.len) == 0) {
5825  do_ssi_exec(nc, p + d_exec.len + 1);
5826 #endif
5827  } else {
5828  /* Silently ignore unknown SSI directive. */
5829  }
5830  len = 0;
5831  } else if (ch == '<') {
5832  in_ssi_tag = 1;
5833  if (len > 0) {
5834  mg_send(nc, buf, (size_t) len);
5835  }
5836  len = 0;
5837  buf[len++] = ch & 0xff;
5838  } else if (in_ssi_tag) {
5839  if (len == (int) btag.len && memcmp(buf, btag.p, btag.len) != 0) {
5840  /* Not an SSI tag */
5841  in_ssi_tag = 0;
5842  } else if (len == (int) sizeof(buf) - 2) {
5843  mg_printf(nc, "%s: SSI tag is too large", path);
5844  len = 0;
5845  }
5846  buf[len++] = ch & 0xff;
5847  } else {
5848  buf[len++] = ch & 0xff;
5849  if (len == (int) sizeof(buf)) {
5850  mg_send(nc, buf, (size_t) len);
5851  len = 0;
5852  }
5853  }
5854  }
5855 
5856  /* Send the rest of buffered data */
5857  if (len > 0) {
5858  mg_send(nc, buf, (size_t) len);
5859  }
5860  }
5861 
5862  static void mg_handle_ssi_request(struct mg_connection *nc, const char *path,
5863  const struct mg_serve_http_opts *opts) {
5864  FILE *fp;
5865  struct mg_str mime_type;
5866 
5867  if ((fp = fopen(path, "rb")) == NULL) {
5868  mg_http_send_error(nc, 404, NULL);
5869  } else {
5870  mg_set_close_on_exec(fileno(fp));
5871 
5872  mime_type = mg_get_mime_type(path, "text/plain", opts);
5873  mg_send_response_line(nc, 200, opts->extra_headers);
5874  mg_printf(nc,
5875  "Content-Type: %.*s\r\n"
5876  "Connection: close\r\n\r\n",
5877  (int) mime_type.len, mime_type.p);
5878  mg_send_ssi_file(nc, path, fp, 0, opts);
5879  fclose(fp);
5880  nc->flags |= MG_F_SEND_AND_CLOSE;
5881  }
5882  }
5883 #else
5884  static void mg_handle_ssi_request(struct mg_connection *nc, const char *path,
5885  const struct mg_serve_http_opts *opts) {
5886  (void) path;
5887  (void) opts;
5888  mg_http_send_error(nc, 500, "SSI disabled");
5889  }
5890 #endif /* MG_DISABLE_SSI */
5891 
5892  static void mg_http_construct_etag(char *buf, size_t buf_len,
5893  const cs_stat_t *st) {
5894  snprintf(buf, buf_len, "\"%lx.%" INT64_FMT "\"", (unsigned long) st->st_mtime,
5895  (int64_t) st->st_size);
5896  }
5897  static void mg_gmt_time_string(char *buf, size_t buf_len, time_t *t) {
5898  strftime(buf, buf_len, "%a, %d %b %Y %H:%M:%S GMT", gmtime(t));
5899  }
5900 
5901  static int mg_http_parse_range_header(const struct mg_str *header, int64_t *a,
5902  int64_t *b) {
5903  /*
5904  * There is no snscanf. Headers are not guaranteed to be NUL-terminated,
5905  * so we have this. Ugh.
5906  */
5907  int result;
5908  char *p = (char *) MG_MALLOC(header->len + 1);
5909  if (p == NULL) return 0;
5910  memcpy(p, header->p, header->len);
5911  p[header->len] = '\0';
5912  result = sscanf(p, "bytes=%" INT64_FMT "-%" INT64_FMT, a, b);
5913  MG_FREE(p);
5914  return result;
5915  }
5916 
5917  static void mg_http_send_file2(struct mg_connection *nc, const char *path,
5918  cs_stat_t *st, struct http_message *hm,
5919  struct mg_serve_http_opts *opts) {
5920  struct mg_http_proto_data *pd = mg_http_get_proto_data(nc);
5921  struct mg_str mime_type;
5922 
5923  DBG(("%p [%s]", nc, path));
5925  if ((pd->file.fp = fopen(path, "rb")) == NULL) {
5926  int code;
5927  switch (errno) {
5928  case EACCES:
5929  code = 403;
5930  break;
5931  case ENOENT:
5932  code = 404;
5933  break;
5934  default:
5935  code = 500;
5936  };
5937  mg_http_send_error(nc, code, "Open failed");
5938  } else if (mg_match_prefix(opts->ssi_pattern, strlen(opts->ssi_pattern),
5939  path) > 0) {
5940  mg_handle_ssi_request(nc, path, opts);
5941  } else {
5942  char etag[50], current_time[50], last_modified[50], range[70];
5943  time_t t = time(NULL);
5944  int64_t r1 = 0, r2 = 0, cl = st->st_size;
5945  struct mg_str *range_hdr = mg_get_http_header(hm, "Range");
5946  int n, status_code = 200;
5947 
5948  /* Handle Range header */
5949  range[0] = '\0';
5950  if (range_hdr != NULL &&
5951  (n = mg_http_parse_range_header(range_hdr, &r1, &r2)) > 0 && r1 >= 0 &&
5952  r2 >= 0) {
5953  /* If range is specified like "400-", set second limit to content len */
5954  if (n == 1) {
5955  r2 = cl - 1;
5956  }
5957  if (r1 > r2 || r2 >= cl) {
5958  status_code = 416;
5959  cl = 0;
5960  snprintf(range, sizeof(range),
5961  "Content-Range: bytes */%" INT64_FMT "\r\n",
5962  (int64_t) st->st_size);
5963  } else {
5964  status_code = 206;
5965  cl = r2 - r1 + 1;
5966  snprintf(range, sizeof(range), "Content-Range: bytes %" INT64_FMT
5967  "-%" INT64_FMT "/%" INT64_FMT "\r\n",
5968  r1, r1 + cl - 1, (int64_t) st->st_size);
5969 #if _FILE_OFFSET_BITS == 64 || _POSIX_C_SOURCE >= 200112L || \
5970 _XOPEN_SOURCE >= 600
5971  fseeko(pd->file.fp, r1, SEEK_SET);
5972 #else
5973  fseek(pd->file.fp, r1, SEEK_SET);
5974 #endif
5975  }
5976  }
5977 
5978 #ifndef MG_DISABLE_HTTP_KEEP_ALIVE
5979  {
5980  struct mg_str *conn_hdr = mg_get_http_header(hm, "Connection");
5981  if (conn_hdr != NULL) {
5982  pd->file.keepalive = (mg_vcasecmp(conn_hdr, "keep-alive") == 0);
5983  } else {
5984  pd->file.keepalive = (mg_vcmp(&hm->proto, "HTTP/1.1") == 0);
5985  }
5986  }
5987 #endif
5988 
5989  mg_http_construct_etag(etag, sizeof(etag), st);
5990  mg_gmt_time_string(current_time, sizeof(current_time), &t);
5991  mg_gmt_time_string(last_modified, sizeof(last_modified), &st->st_mtime);
5992  mime_type = mg_get_mime_type(path, "text/plain", opts);
5993  /*
5994  * Content length casted to size_t because:
5995  * 1) that's the maximum buffer size anyway
5996  * 2) ESP8266 RTOS SDK newlib vprintf cannot contain a 64bit arg at non-last
5997  * position
5998  * TODO(mkm): fix ESP8266 RTOS SDK
5999  */
6000  mg_send_response_line(nc, status_code, opts->extra_headers);
6001  mg_printf(nc,
6002  "Date: %s\r\n"
6003  "Last-Modified: %s\r\n"
6004  "Accept-Ranges: bytes\r\n"
6005  "Content-Type: %.*s\r\n"
6006  "Connection: %s\r\n"
6007  "Content-Length: %" SIZE_T_FMT
6008  "\r\n"
6009  "%sEtag: %s\r\n\r\n",
6010  current_time, last_modified, (int) mime_type.len, mime_type.p,
6011  (pd->file.keepalive ? "keep-alive" : "close"), (size_t) cl, range,
6012  etag);
6013 
6014  pd->file.cl = cl;
6015  pd->file.type = DATA_FILE;
6017  }
6018  }
6019 
6020 #endif
6021 
6022  int mg_url_decode(const char *src, int src_len, char *dst, int dst_len,
6023  int is_form_url_encoded) {
6024  int i, j, a, b;
6025 #define HEXTOI(x) (isdigit(x) ? x - '0' : x - 'W')
6026 
6027  for (i = j = 0; i < src_len && j < dst_len - 1; i++, j++) {
6028  if (src[i] == '%') {
6029  if (i < src_len - 2 && isxdigit(*(const unsigned char *) (src + i + 1)) &&
6030  isxdigit(*(const unsigned char *) (src + i + 2))) {
6031  a = tolower(*(const unsigned char *) (src + i + 1));
6032  b = tolower(*(const unsigned char *) (src + i + 2));
6033  dst[j] = (char) ((HEXTOI(a) << 4) | HEXTOI(b));
6034  i += 2;
6035  } else {
6036  return -1;
6037  }
6038  } else if (is_form_url_encoded && src[i] == '+') {
6039  dst[j] = ' ';
6040  } else {
6041  dst[j] = src[i];
6042  }
6043  }
6044 
6045  dst[j] = '\0'; /* Null-terminate the destination */
6046 
6047  return i >= src_len ? j : -1;
6048  }
6049 
6050  int mg_get_http_var(const struct mg_str *buf, const char *name, char *dst,
6051  size_t dst_len) {
6052  const char *p, *e, *s;
6053  size_t name_len;
6054  int len;
6055 
6056  if (dst == NULL || dst_len == 0) {
6057  len = -2;
6058  } else if (buf->p == NULL || name == NULL || buf->len == 0) {
6059  len = -1;
6060  dst[0] = '\0';
6061  } else {
6062  name_len = strlen(name);
6063  e = buf->p + buf->len;
6064  len = -1;
6065  dst[0] = '\0';
6066 
6067  for (p = buf->p; p + name_len < e; p++) {
6068  if ((p == buf->p || p[-1] == '&') && p[name_len] == '=' &&
6069  !mg_ncasecmp(name, p, name_len)) {
6070  p += name_len + 1;
6071  s = (const char *) memchr(p, '&', (size_t)(e - p));
6072  if (s == NULL) {
6073  s = e;
6074  }
6075  len = mg_url_decode(p, (size_t)(s - p), dst, dst_len, 1);
6076  if (len == -1) {
6077  len = -2;
6078  }
6079  break;
6080  }
6081  }
6082  }
6083 
6084  return len;
6085  }
6086 
6087  void mg_send_http_chunk(struct mg_connection *nc, const char *buf, size_t len) {
6088  char chunk_size[50];
6089  int n;
6090 
6091  n = snprintf(chunk_size, sizeof(chunk_size), "%lX\r\n", (unsigned long) len);
6092  mg_send(nc, chunk_size, n);
6093  mg_send(nc, buf, len);
6094  mg_send(nc, "\r\n", 2);
6095  }
6096 
6097  void mg_printf_http_chunk(struct mg_connection *nc, const char *fmt, ...) {
6098  char mem[MG_VPRINTF_BUFFER_SIZE], *buf = mem;
6099  int len;
6100  va_list ap;
6101 
6102  va_start(ap, fmt);
6103  len = mg_avprintf(&buf, sizeof(mem), fmt, ap);
6104  va_end(ap);
6105 
6106  if (len >= 0) {
6107  mg_send_http_chunk(nc, buf, len);
6108  }
6109 
6110  /* LCOV_EXCL_START */
6111  if (buf != mem && buf != NULL) {
6112  MG_FREE(buf);
6113  }
6114  /* LCOV_EXCL_STOP */
6115  }
6116 
6117  void mg_printf_html_escape(struct mg_connection *nc, const char *fmt, ...) {
6118  char mem[MG_VPRINTF_BUFFER_SIZE], *buf = mem;
6119  int i, j, len;
6120  va_list ap;
6121 
6122  va_start(ap, fmt);
6123  len = mg_avprintf(&buf, sizeof(mem), fmt, ap);
6124  va_end(ap);
6125 
6126  if (len >= 0) {
6127  for (i = j = 0; i < len; i++) {
6128  if (buf[i] == '<' || buf[i] == '>') {
6129  mg_send(nc, buf + j, i - j);
6130  mg_send(nc, buf[i] == '<' ? "&lt;" : "&gt;", 4);
6131  j = i + 1;
6132  }
6133  }
6134  mg_send(nc, buf + j, i - j);
6135  }
6136 
6137  /* LCOV_EXCL_START */
6138  if (buf != mem && buf != NULL) {
6139  MG_FREE(buf);
6140  }
6141  /* LCOV_EXCL_STOP */
6142  }
6143 
6144  int mg_http_parse_header(struct mg_str *hdr, const char *var_name, char *buf,
6145  size_t buf_size) {
6146  int ch = ' ', ch1 = ',', len = 0, n = strlen(var_name);
6147  const char *p, *end = hdr ? hdr->p + hdr->len : NULL, *s = NULL;
6148 
6149  if (buf != NULL && buf_size > 0) buf[0] = '\0';
6150  if (hdr == NULL) return 0;
6151 
6152  /* Find where variable starts */
6153  for (s = hdr->p; s != NULL && s + n < end; s++) {
6154  if ((s == hdr->p || s[-1] == ch || s[-1] == ch1) && s[n] == '=' &&
6155  !memcmp(s, var_name, n))
6156  break;
6157  }
6158 
6159  if (s != NULL && &s[n + 1] < end) {
6160  s += n + 1;
6161  if (*s == '"' || *s == '\'') {
6162  ch = ch1 = *s++;
6163  }
6164  p = s;
6165  while (p < end && p[0] != ch && p[0] != ch1 && len < (int) buf_size) {
6166  if (ch != ' ' && p[0] == '\\' && p[1] == ch) p++;
6167  buf[len++] = *p++;
6168  }
6169  if (len >= (int) buf_size || (ch != ' ' && *p != ch)) {
6170  len = 0;
6171  } else {
6172  if (len > 0 && s[len - 1] == ',') len--;
6173  if (len > 0 && s[len - 1] == ';') len--;
6174  buf[len] = '\0';
6175  }
6176  }
6177 
6178  return len;
6179  }
6180 
6181 #ifndef MG_DISABLE_FILESYSTEM
6182  static int mg_is_file_hidden(const char *path,
6183  const struct mg_serve_http_opts *opts,
6184  int exclude_specials) {
6185  const char *p1 = opts->per_directory_auth_file;
6186  const char *p2 = opts->hidden_file_pattern;
6187 
6188  /* Strip directory path from the file name */
6189  const char *pdir = strrchr(path, DIRSEP);
6190  if (pdir != NULL) {
6191  path = pdir + 1;
6192  }
6193 
6194  return (exclude_specials && (!strcmp(path, ".") || !strcmp(path, ".."))) ||
6195  (p1 != NULL &&
6196  mg_match_prefix(p1, strlen(p1), path) == (int) strlen(p1)) ||
6197  (p2 != NULL && mg_match_prefix(p2, strlen(p2), path) > 0);
6198  }
6199 
6200 #ifndef MG_DISABLE_HTTP_DIGEST_AUTH
6201  static void mg_mkmd5resp(const char *method, size_t method_len, const char *uri,
6202  size_t uri_len, const char *ha1, size_t ha1_len,
6203  const char *nonce, size_t nonce_len, const char *nc,
6204  size_t nc_len, const char *cnonce, size_t cnonce_len,
6205  const char *qop, size_t qop_len, char *resp) {
6206  static const char colon[] = ":";
6207  static const size_t one = 1;
6208  char ha2[33];
6209 
6210  cs_md5(ha2, method, method_len, colon, one, uri, uri_len, NULL);
6211  cs_md5(resp, ha1, ha1_len, colon, one, nonce, nonce_len, colon, one, nc,
6212  nc_len, colon, one, cnonce, cnonce_len, colon, one, qop, qop_len,
6213  colon, one, ha2, sizeof(ha2) - 1, NULL);
6214  }
6215 
6216  int mg_http_create_digest_auth_header(char *buf, size_t buf_len,
6217  const char *method, const char *uri,
6218  const char *auth_domain, const char *user,
6219  const char *passwd) {
6220  static const char colon[] = ":", qop[] = "auth";
6221  static const size_t one = 1;
6222  char ha1[33], resp[33], cnonce[40];
6223 
6224  snprintf(cnonce, sizeof(cnonce), "%x", (unsigned int) time(NULL));
6225  cs_md5(ha1, user, (size_t) strlen(user), colon, one, auth_domain,
6226  (size_t) strlen(auth_domain), colon, one, passwd,
6227  (size_t) strlen(passwd), NULL);
6228  mg_mkmd5resp(method, strlen(method), uri, strlen(uri), ha1, sizeof(ha1) - 1,
6229  cnonce, strlen(cnonce), "1", one, cnonce, strlen(cnonce), qop,
6230  sizeof(qop) - 1, resp);
6231  return snprintf(buf, buf_len,
6232  "Authorization: Digest username=\"%s\","
6233  "realm=\"%s\",uri=\"%s\",qop=%s,nc=1,cnonce=%s,"
6234  "nonce=%s,response=%s\r\n",
6235  user, auth_domain, uri, qop, cnonce, cnonce, resp);
6236  }
6237 
6238  /*
6239  * Check for authentication timeout.
6240  * Clients send time stamp encoded in nonce. Make sure it is not too old,
6241  * to prevent replay attacks.
6242  * Assumption: nonce is a hexadecimal number of seconds since 1970.
6243  */
6244  static int mg_check_nonce(const char *nonce) {
6245  unsigned long now = (unsigned long) time(NULL);
6246  unsigned long val = (unsigned long) strtoul(nonce, NULL, 16);
6247  return now < val || now - val < 3600;
6248  }
6249 
6250  int mg_http_check_digest_auth(struct http_message *hm, const char *auth_domain,
6251  FILE *fp) {
6252  struct mg_str *hdr;
6253  char buf[128], f_user[sizeof(buf)], f_ha1[sizeof(buf)], f_domain[sizeof(buf)];
6254  char user[50], cnonce[33], response[40], uri[200], qop[20], nc[20], nonce[30];
6255  char expected_response[33];
6256 
6257  /* Parse "Authorization:" header, fail fast on parse error */
6258  if (hm == NULL || fp == NULL ||
6259  (hdr = mg_get_http_header(hm, "Authorization")) == NULL ||
6260  mg_http_parse_header(hdr, "username", user, sizeof(user)) == 0 ||
6261  mg_http_parse_header(hdr, "cnonce", cnonce, sizeof(cnonce)) == 0 ||
6262  mg_http_parse_header(hdr, "response", response, sizeof(response)) == 0 ||
6263  mg_http_parse_header(hdr, "uri", uri, sizeof(uri)) == 0 ||
6264  mg_http_parse_header(hdr, "qop", qop, sizeof(qop)) == 0 ||
6265  mg_http_parse_header(hdr, "nc", nc, sizeof(nc)) == 0 ||
6266  mg_http_parse_header(hdr, "nonce", nonce, sizeof(nonce)) == 0 ||
6267  mg_check_nonce(nonce) == 0) {
6268  return 0;
6269  }
6270 
6271  /*
6272  * Read passwords file line by line. If should have htdigest format,
6273  * i.e. each line should be a colon-separated sequence:
6274  * USER_NAME:DOMAIN_NAME:HA1_HASH_OF_USER_DOMAIN_AND_PASSWORD
6275  */
6276  while (fgets(buf, sizeof(buf), fp) != NULL) {
6277  if (sscanf(buf, "%[^:]:%[^:]:%s", f_user, f_domain, f_ha1) == 3 &&
6278  strcmp(user, f_user) == 0 &&
6279  /* NOTE(lsm): due to a bug in MSIE, we do not compare URIs */
6280  strcmp(auth_domain, f_domain) == 0) {
6281  /* User and domain matched, check the password */
6282  mg_mkmd5resp(
6283  hm->method.p, hm->method.len, hm->uri.p,
6284  hm->uri.len + (hm->query_string.len ? hm->query_string.len + 1 : 0),
6285  f_ha1, strlen(f_ha1), nonce, strlen(nonce), nc, strlen(nc), cnonce,
6286  strlen(cnonce), qop, strlen(qop), expected_response);
6287  return mg_casecmp(response, expected_response) == 0;
6288  }
6289  }
6290 
6291  /* None of the entries in the passwords file matched - return failure */
6292  return 0;
6293  }
6294 
6295  static int mg_is_authorized(struct http_message *hm, const char *path,
6296  int is_directory, const char *domain,
6297  const char *passwords_file,
6298  int is_global_pass_file) {
6299  char buf[MG_MAX_PATH];
6300  const char *p;
6301  FILE *fp;
6302  int authorized = 1;
6303 
6304  if (domain != NULL && passwords_file != NULL) {
6305  if (is_global_pass_file) {
6306  fp = fopen(passwords_file, "r");
6307  } else if (is_directory) {
6308  snprintf(buf, sizeof(buf), "%s%c%s", path, DIRSEP, passwords_file);
6309  fp = fopen(buf, "r");
6310  } else {
6311  p = strrchr(path, DIRSEP);
6312  if (p == NULL) p = path;
6313  snprintf(buf, sizeof(buf), "%.*s%c%s", (int) (p - path), path, DIRSEP,
6314  passwords_file);
6315  fp = fopen(buf, "r");
6316  }
6317 
6318  if (fp != NULL) {
6319  authorized = mg_http_check_digest_auth(hm, domain, fp);
6320  fclose(fp);
6321  }
6322  }
6323 
6324  DBG(("%s %s %d %d", path, passwords_file ? passwords_file : "",
6325  is_global_pass_file, authorized));
6326  return authorized;
6327  }
6328 #else
6329  static int mg_is_authorized(struct http_message *hm, const char *path,
6330  int is_directory, const char *domain,
6331  const char *passwords_file,
6332  int is_global_pass_file) {
6333  (void) hm;
6334  (void) path;
6335  (void) is_directory;
6336  (void) domain;
6337  (void) passwords_file;
6338  (void) is_global_pass_file;
6339  return 1;
6340  }
6341 #endif
6342 
6343 #ifndef MG_DISABLE_DIRECTORY_LISTING
6344  static size_t mg_url_encode(const char *src, size_t s_len, char *dst,
6345  size_t dst_len) {
6346  static const char *dont_escape = "._-$,;~()/";
6347  static const char *hex = "0123456789abcdef";
6348  size_t i = 0, j = 0;
6349 
6350  for (i = j = 0; dst_len > 0 && i < s_len && j + 2 < dst_len - 1; i++, j++) {
6351  if (isalnum(*(const unsigned char *) (src + i)) ||
6352  strchr(dont_escape, *(const unsigned char *) (src + i)) != NULL) {
6353  dst[j] = src[i];
6354  } else if (j + 3 < dst_len) {
6355  dst[j] = '%';
6356  dst[j + 1] = hex[(*(const unsigned char *) (src + i)) >> 4];
6357  dst[j + 2] = hex[(*(const unsigned char *) (src + i)) & 0xf];
6358  j += 2;
6359  }
6360  }
6361 
6362  dst[j] = '\0';
6363  return j;
6364  }
6365 
6366  static void mg_escape(const char *src, char *dst, size_t dst_len) {
6367  size_t n = 0;
6368  while (*src != '\0' && n + 5 < dst_len) {
6369  unsigned char ch = *(unsigned char *) src++;
6370  if (ch == '<') {
6371  n += snprintf(dst + n, dst_len - n, "%s", "&lt;");
6372  } else {
6373  dst[n++] = ch;
6374  }
6375  }
6376  dst[n] = '\0';
6377  }
6378 
6379  static void mg_print_dir_entry(struct mg_connection *nc, const char *file_name,
6380  cs_stat_t *stp) {
6381  char size[64], mod[64], href[MAX_PATH_SIZE * 3], path[MAX_PATH_SIZE];
6382  int64_t fsize = stp->st_size;
6383  int is_dir = S_ISDIR(stp->st_mode);
6384  const char *slash = is_dir ? "/" : "";
6385 
6386  if (is_dir) {
6387  snprintf(size, sizeof(size), "%s", "[DIRECTORY]");
6388  } else {
6389  /*
6390  * We use (double) cast below because MSVC 6 compiler cannot
6391  * convert unsigned __int64 to double.
6392  */
6393  if (fsize < 1024) {
6394  snprintf(size, sizeof(size), "%d", (int) fsize);
6395  } else if (fsize < 0x100000) {
6396  snprintf(size, sizeof(size), "%.1fk", (double) fsize / 1024.0);
6397  } else if (fsize < 0x40000000) {
6398  snprintf(size, sizeof(size), "%.1fM", (double) fsize / 1048576);
6399  } else {
6400  snprintf(size, sizeof(size), "%.1fG", (double) fsize / 1073741824);
6401  }
6402  }
6403  strftime(mod, sizeof(mod), "%d-%b-%Y %H:%M", localtime(&stp->st_mtime));
6404  mg_escape(file_name, path, sizeof(path));
6405  mg_url_encode(file_name, strlen(file_name), href, sizeof(href));
6407  "<tr><td><a href=\"%s%s\">%s%s</a></td>"
6408  "<td>%s</td><td name=%" INT64_FMT ">%s</td></tr>\n",
6409  href, slash, path, slash, mod, is_dir ? -1 : fsize,
6410  size);
6411  }
6412 
6413  static void mg_scan_directory(struct mg_connection *nc, const char *dir,
6414  const struct mg_serve_http_opts *opts,
6415  void (*func)(struct mg_connection *, const char *,
6416  cs_stat_t *)) {
6417  char path[MAX_PATH_SIZE];
6418  cs_stat_t st;
6419  struct dirent *dp;
6420  DIR *dirp;
6421 
6422  DBG(("%p [%s]", nc, dir));
6423  if ((dirp = (opendir(dir))) != NULL) {
6424  while ((dp = readdir(dirp)) != NULL) {
6425  /* Do not show current dir and hidden files */
6426  if (mg_is_file_hidden((const char *) dp->d_name, opts, 1)) {
6427  continue;
6428  }
6429  snprintf(path, sizeof(path), "%s/%s", dir, dp->d_name);
6430  if (mg_stat(path, &st) == 0) {
6431  func(nc, (const char *) dp->d_name, &st);
6432  }
6433  }
6434  closedir(dirp);
6435  } else {
6436  DBG(("%p opendir(%s) -> %d", nc, dir, errno));
6437  }
6438  }
6439 
6440  static void mg_send_directory_listing(struct mg_connection *nc, const char *dir,
6441  struct http_message *hm,
6442  struct mg_serve_http_opts *opts) {
6443  static const char *sort_js_code =
6444  "<script>function srt(tb, col) {"
6445  "var tr = Array.prototype.slice.call(tb.rows, 0),"
6446  "tr = tr.sort(function (a, b) { var c1 = a.cells[col], c2 = b.cells[col],"
6447  "n1 = c1.getAttribute('name'), n2 = c2.getAttribute('name'), "
6448  "t1 = a.cells[2].getAttribute('name'), "
6449  "t2 = b.cells[2].getAttribute('name'); "
6450  "return t1 < 0 && t2 >= 0 ? -1 : t2 < 0 && t1 >= 0 ? 1 : "
6451  "n1 ? parseInt(n2) - parseInt(n1) : "
6452  "c1.textContent.trim().localeCompare(c2.textContent.trim()); });";
6453  static const char *sort_js_code2 =
6454  "for (var i = 0; i < tr.length; i++) tb.appendChild(tr[i]);}"
6455  "window.onload = function() { "
6456  "var tb = document.getElementById('tb');"
6457  "document.onclick = function(ev){ "
6458  "var c = ev.target.rel; if (c) srt(tb, c)}; srt(tb, 2); };</script>";
6459 
6460  mg_send_response_line(nc, 200, opts->extra_headers);
6461  mg_printf(nc, "%s: %s\r\n%s: %s\r\n\r\n", "Transfer-Encoding", "chunked",
6462  "Content-Type", "text/html; charset=utf-8");
6463 
6465  nc,
6466  "<html><head><title>Index of %.*s</title>%s%s"
6467  "<style>th,td {text-align: left; padding-right: 1em; "
6468  "font-family: monospace; }</style></head>\n"
6469  "<body><h1>Index of %.*s</h1>\n<table cellpadding=0><thead>"
6470  "<tr><th><a href=# rel=0>Name</a></th><th>"
6471  "<a href=# rel=1>Modified</a</th>"
6472  "<th><a href=# rel=2>Size</a></th></tr>"
6473  "<tr><td colspan=3><hr></td></tr>\n"
6474  "</thead>\n"
6475  "<tbody id=tb>",
6476  (int) hm->uri.len, hm->uri.p, sort_js_code, sort_js_code2,
6477  (int) hm->uri.len, hm->uri.p);
6478  mg_scan_directory(nc, dir, opts, mg_print_dir_entry);
6480  "<tr><td colspan=3><hr></td></tr>\n"
6481  "</tbody></table>\n"
6482  "<address>%s</address>\n"
6483  "</body></html>",
6484  mg_version_header);
6485  mg_send_http_chunk(nc, "", 0);
6486  /* TODO(rojer): Remove when cesanta/dev/issues/197 is fixed. */
6487  nc->flags |= MG_F_SEND_AND_CLOSE;
6488  }
6489 #endif /* MG_DISABLE_DIRECTORY_LISTING */
6490 
6491 #ifndef MG_DISABLE_DAV
6492  static void mg_print_props(struct mg_connection *nc, const char *name,
6493  cs_stat_t *stp) {
6494  char mtime[64], buf[MAX_PATH_SIZE * 3];
6495  time_t t = stp->st_mtime; /* store in local variable for NDK compile */
6496  mg_gmt_time_string(mtime, sizeof(mtime), &t);
6497  mg_url_encode(name, strlen(name), buf, sizeof(buf));
6498  mg_printf(nc,
6499  "<d:response>"
6500  "<d:href>%s</d:href>"
6501  "<d:propstat>"
6502  "<d:prop>"
6503  "<d:resourcetype>%s</d:resourcetype>"
6504  "<d:getcontentlength>%" INT64_FMT
6505  "</d:getcontentlength>"
6506  "<d:getlastmodified>%s</d:getlastmodified>"
6507  "</d:prop>"
6508  "<d:status>HTTP/1.1 200 OK</d:status>"
6509  "</d:propstat>"
6510  "</d:response>\n",
6511  buf, S_ISDIR(stp->st_mode) ? "<d:collection/>" : "",
6512  (int64_t) stp->st_size, mtime);
6513  }
6514 
6515  static void mg_handle_propfind(struct mg_connection *nc, const char *path,
6516  cs_stat_t *stp, struct http_message *hm,
6517  struct mg_serve_http_opts *opts) {
6518  static const char header[] =
6519  "HTTP/1.1 207 Multi-Status\r\n"
6520  "Connection: close\r\n"
6521  "Content-Type: text/xml; charset=utf-8\r\n\r\n"
6522  "<?xml version=\"1.0\" encoding=\"utf-8\"?>"
6523  "<d:multistatus xmlns:d='DAV:'>\n";
6524  static const char footer[] = "</d:multistatus>\n";
6525  const struct mg_str *depth = mg_get_http_header(hm, "Depth");
6526 
6527  /* Print properties for the requested resource itself */
6528  if (S_ISDIR(stp->st_mode) &&
6529  strcmp(opts->enable_directory_listing, "yes") != 0) {
6530  mg_printf(nc, "%s", "HTTP/1.1 403 Directory Listing Denied\r\n\r\n");
6531  } else {
6532  char uri[MAX_PATH_SIZE];
6533  mg_send(nc, header, sizeof(header) - 1);
6534  snprintf(uri, sizeof(uri), "%.*s", (int) hm->uri.len, hm->uri.p);
6535  mg_print_props(nc, uri, stp);
6536  if (S_ISDIR(stp->st_mode) && (depth == NULL || mg_vcmp(depth, "0") != 0)) {
6537  mg_scan_directory(nc, path, opts, mg_print_props);
6538  }
6539  mg_send(nc, footer, sizeof(footer) - 1);
6540  nc->flags |= MG_F_SEND_AND_CLOSE;
6541  }
6542  }
6543 
6544 #ifdef MG_ENABLE_FAKE_DAVLOCK
6545  /*
6546  * Windows explorer (probably there are another WebDav clients like it)
6547  * requires LOCK support in webdav. W/out this, it still works, but fails
6548  * to save file: shows error message and offers "Save As".
6549  * "Save as" works, but this message is very annoying.
6550  * This is fake lock, which doesn't lock something, just returns LOCK token,
6551  * UNLOCK always answers "OK".
6552  * With this fake LOCK Windows Explorer looks happy and saves file.
6553  * NOTE: that is not DAV LOCK imlementation, it is just a way to shut up
6554  * Windows native DAV client. This is why FAKE LOCK is not enabed by default
6555  */
6556  static void mg_handle_lock(struct mg_connection *nc, const char *path) {
6557  static const char *reply =
6558  "HTTP/1.1 207 Multi-Status\r\n"
6559  "Connection: close\r\n"
6560  "Content-Type: text/xml; charset=utf-8\r\n\r\n"
6561  "<?xml version=\"1.0\" encoding=\"utf-8\"?>"
6562  "<d:multistatus xmlns:d='DAV:'>\n"
6563  "<D:lockdiscovery>\n"
6564  "<D:activelock>\n"
6565  "<D:locktoken>\n"
6566  "<D:href>\n"
6567  "opaquelocktoken:%s%u"
6568  "</D:href>"
6569  "</D:locktoken>"
6570  "</D:activelock>\n"
6571  "</D:lockdiscovery>"
6572  "</d:multistatus>\n";
6573  mg_printf(nc, reply, path, (unsigned int) time(NULL));
6574  nc->flags |= MG_F_SEND_AND_CLOSE;
6575  }
6576 #endif
6577 
6578  static void mg_handle_mkcol(struct mg_connection *nc, const char *path,
6579  struct http_message *hm) {
6580  int status_code = 500;
6581  if (hm->body.len != (size_t) ~0 && hm->body.len > 0) {
6582  status_code = 415;
6583  } else if (!mg_mkdir(path, 0755)) {
6584  status_code = 201;
6585  } else if (errno == EEXIST) {
6586  status_code = 405;
6587  } else if (errno == EACCES) {
6588  status_code = 403;
6589  } else if (errno == ENOENT) {
6590  status_code = 409;
6591  } else {
6592  status_code = 500;
6593  }
6594  mg_http_send_error(nc, status_code, NULL);
6595  }
6596 
6597  static int mg_remove_directory(const struct mg_serve_http_opts *opts,
6598  const char *dir) {
6599  char path[MAX_PATH_SIZE];
6600  struct dirent *dp;
6601  cs_stat_t st;
6602  DIR *dirp;
6603 
6604  if ((dirp = opendir(dir)) == NULL) return 0;
6605 
6606  while ((dp = readdir(dirp)) != NULL) {
6607  if (mg_is_file_hidden((const char *) dp->d_name, opts, 1)) {
6608  continue;
6609  }
6610  snprintf(path, sizeof(path), "%s%c%s", dir, '/', dp->d_name);
6611  mg_stat(path, &st);
6612  if (S_ISDIR(st.st_mode)) {
6613  mg_remove_directory(opts, path);
6614  } else {
6615  remove(path);
6616  }
6617  }
6618  closedir(dirp);
6619  rmdir(dir);
6620 
6621  return 1;
6622  }
6623 
6624  static void mg_handle_move(struct mg_connection *c,
6625  const struct mg_serve_http_opts *opts,
6626  const char *path, struct http_message *hm) {
6627  const struct mg_str *dest = mg_get_http_header(hm, "Destination");
6628  if (dest == NULL) {
6629  mg_http_send_error(c, 411, NULL);
6630  } else {
6631  const char *p = (char *) memchr(dest->p, '/', dest->len);
6632  if (p != NULL && p[1] == '/' &&
6633  (p = (char *) memchr(p + 2, '/', dest->p + dest->len - p)) != NULL) {
6634  char buf[MAX_PATH_SIZE];
6635  snprintf(buf, sizeof(buf), "%s%.*s", opts->dav_document_root,
6636  (int) (dest->p + dest->len - p), p);
6637  if (rename(path, buf) == 0) {
6638  mg_http_send_error(c, 200, NULL);
6639  } else {
6640  mg_http_send_error(c, 418, NULL);
6641  }
6642  } else {
6643  mg_http_send_error(c, 500, NULL);
6644  }
6645  }
6646  }
6647 
6648  static void mg_handle_delete(struct mg_connection *nc,
6649  const struct mg_serve_http_opts *opts,
6650  const char *path) {
6651  cs_stat_t st;
6652  if (mg_stat(path, &st) != 0) {
6653  mg_http_send_error(nc, 404, NULL);
6654  } else if (S_ISDIR(st.st_mode)) {
6655  mg_remove_directory(opts, path);
6656  mg_http_send_error(nc, 204, NULL);
6657  } else if (remove(path) == 0) {
6658  mg_http_send_error(nc, 204, NULL);
6659  } else {
6660  mg_http_send_error(nc, 423, NULL);
6661  }
6662  }
6663 
6664  /* Return -1 on error, 1 on success. */
6665  static int mg_create_itermediate_directories(const char *path) {
6666  const char *s;
6667 
6668  /* Create intermediate directories if they do not exist */
6669  for (s = path + 1; *s != '\0'; s++) {
6670  if (*s == '/') {
6671  char buf[MAX_PATH_SIZE];
6672  cs_stat_t st;
6673  snprintf(buf, sizeof(buf), "%.*s", (int) (s - path), path);
6674  buf[sizeof(buf) - 1] = '\0';
6675  if (mg_stat(buf, &st) != 0 && mg_mkdir(buf, 0755) != 0) {
6676  return -1;
6677  }
6678  }
6679  }
6680 
6681  return 1;
6682  }
6683 
6684  static void mg_handle_put(struct mg_connection *nc, const char *path,
6685  struct http_message *hm) {
6686  struct mg_http_proto_data *pd = mg_http_get_proto_data(nc);
6687  cs_stat_t st;
6688  const struct mg_str *cl_hdr = mg_get_http_header(hm, "Content-Length");
6689  int rc, status_code = mg_stat(path, &st) == 0 ? 200 : 201;
6690 
6692  if ((rc = mg_create_itermediate_directories(path)) == 0) {
6693  mg_printf(nc, "HTTP/1.1 %d OK\r\nContent-Length: 0\r\n\r\n", status_code);
6694  } else if (rc == -1) {
6695  mg_http_send_error(nc, 500, NULL);
6696  } else if (cl_hdr == NULL) {
6697  mg_http_send_error(nc, 411, NULL);
6698  } else if ((pd->file.fp = fopen(path, "w+b")) == NULL) {
6699  mg_http_send_error(nc, 500, NULL);
6700  } else {
6701  const struct mg_str *range_hdr = mg_get_http_header(hm, "Content-Range");
6702  int64_t r1 = 0, r2 = 0;
6703  pd->file.type = DATA_PUT;
6704  mg_set_close_on_exec(fileno(pd->file.fp));
6705  pd->file.cl = to64(cl_hdr->p);
6706  if (range_hdr != NULL &&
6707  mg_http_parse_range_header(range_hdr, &r1, &r2) > 0) {
6708  status_code = 206;
6709  fseeko(pd->file.fp, r1, SEEK_SET);
6710  pd->file.cl = r2 > r1 ? r2 - r1 + 1 : pd->file.cl - r1;
6711  }
6712  mg_printf(nc, "HTTP/1.1 %d OK\r\nContent-Length: 0\r\n\r\n", status_code);
6713  /* Remove HTTP request from the mbuf, leave only payload */
6714  mbuf_remove(&nc->recv_mbuf, hm->message.len - hm->body.len);
6716  }
6717  }
6718 #endif /* MG_DISABLE_DAV */
6719 
6720  static int mg_is_dav_request(const struct mg_str *s) {
6721  static const char *methods[] = {"PUT", "DELETE", "MKCOL", "PROPFIND", "MOVE"
6722 #ifdef MG_ENABLE_FAKE_DAVLOCK
6723  ,
6724  "LOCK", "UNLOCK"
6725 #endif
6726  };
6727  size_t i;
6728 
6729  for (i = 0; i < ARRAY_SIZE(methods); i++) {
6730  if (mg_vcmp(s, methods[i]) == 0) {
6731  return 1;
6732  }
6733  }
6734 
6735  return 0;
6736  }
6737 
6738  /*
6739  * Given a directory path, find one of the files specified in the
6740  * comma-separated list of index files `list`.
6741  * First found index file wins. If an index file is found, then gets
6742  * appended to the `path`, stat-ed, and result of `stat()` passed to `stp`.
6743  * If index file is not found, then `path` and `stp` remain unchanged.
6744  */
6745  MG_INTERNAL void mg_find_index_file(const char *path, const char *list,
6746  char **index_file, cs_stat_t *stp) {
6747  struct mg_str vec;
6748  size_t path_len = strlen(path);
6749  int found = 0;
6750  *index_file = NULL;
6751 
6752  /* Traverse index files list. For each entry, append it to the given */
6753  /* path and see if the file exists. If it exists, break the loop */
6754  while ((list = mg_next_comma_list_entry(list, &vec, NULL)) != NULL) {
6755  cs_stat_t st;
6756  size_t len = path_len + 1 + vec.len + 1;
6757  *index_file = (char *) MG_REALLOC(*index_file, len);
6758  if (*index_file == NULL) break;
6759  snprintf(*index_file, len, "%s%c%.*s", path, DIRSEP, (int) vec.len, vec.p);
6760 
6761  /* Does it exist? Is it a file? */
6762  if (mg_stat(*index_file, &st) == 0 && S_ISREG(st.st_mode)) {
6763  /* Yes it does, break the loop */
6764  *stp = st;
6765  found = 1;
6766  break;
6767  }
6768  }
6769  if (!found) {
6770  MG_FREE(*index_file);
6771  *index_file = NULL;
6772  }
6773  DBG(("[%s] [%s]", path, (*index_file ? *index_file : "")));
6774  }
6775 
6777  struct mg_connection *c, struct http_message *hm,
6778  const struct mg_serve_http_opts *opts) {
6779  const char *rewrites = opts->url_rewrites;
6780  struct mg_str a, b;
6781  char local_port[20] = {'%'};
6782 
6783  mg_conn_addr_to_str(c, local_port + 1, sizeof(local_port) - 1,
6785 
6786  while ((rewrites = mg_next_comma_list_entry(rewrites, &a, &b)) != NULL) {
6787  if (mg_vcmp(&a, local_port) == 0) {
6788  mg_send_response_line(c, 301, NULL);
6789  mg_printf(c, "Content-Length: 0\r\nLocation: %.*s%.*s\r\n\r\n",
6790  (int) b.len, b.p, (int) (hm->proto.p - hm->uri.p - 1),
6791  hm->uri.p);
6792  return 1;
6793  }
6794  }
6795 
6796  return 0;
6797  }
6798 
6800  const struct mg_serve_http_opts *opts,
6801  char **local_path,
6802  struct mg_str *remainder) {
6803  int ok = 1;
6804  const char *cp = hm->uri.p, *cp_end = hm->uri.p + hm->uri.len;
6805  struct mg_str root = {NULL, 0};
6806  const char *file_uri_start = cp;
6807  *local_path = NULL;
6808  remainder->p = NULL;
6809  remainder->len = 0;
6810 
6811  { /* 1. Determine which root to use. */
6812  const char *rewrites = opts->url_rewrites;
6813  struct mg_str *hh = mg_get_http_header(hm, "Host");
6814  struct mg_str a, b;
6815  /* Check rewrites first. */
6816  while ((rewrites = mg_next_comma_list_entry(rewrites, &a, &b)) != NULL) {
6817  if (a.len > 1 && a.p[0] == '@') {
6818  /* Host rewrite. */
6819  if (hh != NULL && hh->len == a.len - 1 &&
6820  mg_ncasecmp(a.p + 1, hh->p, a.len - 1) == 0) {
6821  root = b;
6822  break;
6823  }
6824  } else {
6825  /* Regular rewrite, URI=directory */
6826  int match_len = mg_match_prefix_n(a, hm->uri);
6827  if (match_len > 0) {
6828  file_uri_start = hm->uri.p + match_len;
6829  if (*file_uri_start == '/' || file_uri_start == cp_end) {
6830  /* Match ended at component boundary, ok. */
6831  } else if (*(file_uri_start - 1) == '/') {
6832  /* Pattern ends with '/', backtrack. */
6833  file_uri_start--;
6834  } else {
6835  /* No match: must fall on the component boundary. */
6836  continue;
6837  }
6838  root = b;
6839  break;
6840  }
6841  }
6842  }
6843  /* If no rewrite rules matched, use DAV or regular document root. */
6844  if (root.p == NULL) {
6845 #ifndef MG_DISABLE_DAV
6846  if (opts->dav_document_root != NULL && mg_is_dav_request(&hm->method)) {
6847  root.p = opts->dav_document_root;
6848  root.len = strlen(opts->dav_document_root);
6849  } else
6850 #endif
6851  {
6852  root.p = opts->document_root;
6853  root.len = strlen(opts->document_root);
6854  }
6855  }
6856  assert(root.p != NULL && root.len > 0);
6857  }
6858 
6859  { /* 2. Find where in the canonical URI path the local path ends. */
6860  const char *u = file_uri_start + 1;
6861  char *lp = (char *) MG_MALLOC(root.len + hm->uri.len + 1);
6862  char *lp_end = lp + root.len + hm->uri.len + 1;
6863  char *p = lp, *ps;
6864  int exists = 1;
6865  if (lp == NULL) {
6866  ok = 0;
6867  goto out;
6868  }
6869  memcpy(p, root.p, root.len);
6870  p += root.len;
6871  if (*(p - 1) == DIRSEP) p--;
6872  *p = '\0';
6873  ps = p;
6874 
6875  /* Chop off URI path components one by one and build local path. */
6876  while (u <= cp_end) {
6877  const char *next = u;
6878  struct mg_str component;
6879  if (exists) {
6880  cs_stat_t st;
6881  exists = (mg_stat(lp, &st) == 0);
6882  if (exists && S_ISREG(st.st_mode)) {
6883  /* We found the terminal, the rest of the URI (if any) is path_info.
6884  */
6885  if (*(u - 1) == '/') u--;
6886  break;
6887  }
6888  }
6889  if (u >= cp_end) break;
6890  parse_uri_component((const char **) &next, cp_end, '/', &component);
6891  if (component.len > 0) {
6892  int len;
6893  memmove(p + 1, component.p, component.len);
6894  len = mg_url_decode(p + 1, component.len, p + 1, lp_end - p - 1, 0);
6895  if (len <= 0) {
6896  ok = 0;
6897  break;
6898  }
6899  component.p = p + 1;
6900  component.len = len;
6901  if (mg_vcmp(&component, ".") == 0) {
6902  /* Yum. */
6903  } else if (mg_vcmp(&component, "..") == 0) {
6904  while (p > ps && *p != DIRSEP) p--;
6905  *p = '\0';
6906  } else {
6907  size_t i;
6908 #ifdef _WIN32
6909  /* On Windows, make sure it's valid Unicode (no funny stuff). */
6910  wchar_t buf[MG_MAX_PATH * 2];
6911  if (to_wchar(component.p, buf, MG_MAX_PATH) == 0) {
6912  DBG(("[%.*s] smells funny", (int) component.len, component.p));
6913  ok = 0;
6914  break;
6915  }
6916 #endif
6917  *p++ = DIRSEP;
6918  /* No NULs and DIRSEPs in the component (percent-encoded). */
6919  for (i = 0; i < component.len; i++, p++) {
6920  if (*p == '\0' || *p == DIRSEP
6921 #ifdef _WIN32
6922  /* On Windows, "/" is also accepted, so check for that too. */
6923  ||
6924  *p == '/'
6925 #endif
6926  ) {
6927  ok = 0;
6928  break;
6929  }
6930  }
6931  }
6932  }
6933  u = next;
6934  }
6935  if (ok) {
6936  *local_path = lp;
6937  remainder->p = u;
6938  remainder->len = cp_end - u;
6939  } else {
6940  MG_FREE(lp);
6941  }
6942  }
6943 
6944  out:
6945  DBG(("'%.*s' -> '%s' + '%.*s'", (int) hm->uri.len, hm->uri.p,
6946  *local_path ? *local_path : "", (int) remainder->len, remainder->p));
6947  return ok;
6948  }
6949 
6950 #ifndef MG_DISABLE_CGI
6951 #ifdef _WIN32
6952  struct mg_threadparam {
6953  sock_t s;
6954  HANDLE hPipe;
6955  };
6956 
6957  static int mg_wait_until_ready(sock_t sock, int for_read) {
6958  fd_set set;
6959  FD_ZERO(&set);
6960  FD_SET(sock, &set);
6961  return select(sock + 1, for_read ? &set : 0, for_read ? 0 : &set, 0, 0) == 1;
6962  }
6963 
6964  static void *mg_push_to_stdin(void *arg) {
6965  struct mg_threadparam *tp = (struct mg_threadparam *) arg;
6966  int n, sent, stop = 0;
6967  DWORD k;
6968  char buf[BUFSIZ];
6969 
6970  while (!stop && mg_wait_until_ready(tp->s, 1) &&
6971  (n = recv(tp->s, buf, sizeof(buf), 0)) > 0) {
6972  if (n == -1 && GetLastError() == WSAEWOULDBLOCK) continue;
6973  for (sent = 0; !stop && sent < n; sent += k) {
6974  if (!WriteFile(tp->hPipe, buf + sent, n - sent, &k, 0)) stop = 1;
6975  }
6976  }
6977  DBG(("%s", "FORWARED EVERYTHING TO CGI"));
6978  CloseHandle(tp->hPipe);
6979  MG_FREE(tp);
6980  _endthread();
6981  return NULL;
6982  }
6983 
6984  static void *mg_pull_from_stdout(void *arg) {
6985  struct mg_threadparam *tp = (struct mg_threadparam *) arg;
6986  int k = 0, stop = 0;
6987  DWORD n, sent;
6988  char buf[BUFSIZ];
6989 
6990  while (!stop && ReadFile(tp->hPipe, buf, sizeof(buf), &n, NULL)) {
6991  for (sent = 0; !stop && sent < n; sent += k) {
6992  if (mg_wait_until_ready(tp->s, 0) &&
6993  (k = send(tp->s, buf + sent, n - sent, 0)) <= 0)
6994  stop = 1;
6995  }
6996  }
6997  DBG(("%s", "EOF FROM CGI"));
6998  CloseHandle(tp->hPipe);
6999  shutdown(tp->s, 2); // Without this, IO thread may get truncated data
7000  closesocket(tp->s);
7001  MG_FREE(tp);
7002  _endthread();
7003  return NULL;
7004  }
7005 
7006  static void mg_spawn_stdio_thread(sock_t sock, HANDLE hPipe,
7007  void *(*func)(void *)) {
7008  struct mg_threadparam *tp = (struct mg_threadparam *) MG_MALLOC(sizeof(*tp));
7009  if (tp != NULL) {
7010  tp->s = sock;
7011  tp->hPipe = hPipe;
7012  mg_start_thread(func, tp);
7013  }
7014  }
7015 
7016  static void mg_abs_path(const char *utf8_path, char *abs_path, size_t len) {
7017  wchar_t buf[MAX_PATH_SIZE], buf2[MAX_PATH_SIZE];
7018  to_wchar(utf8_path, buf, ARRAY_SIZE(buf));
7019  GetFullPathNameW(buf, ARRAY_SIZE(buf2), buf2, NULL);
7020  WideCharToMultiByte(CP_UTF8, 0, buf2, wcslen(buf2) + 1, abs_path, len, 0, 0);
7021  }
7022 
7023  static pid_t mg_start_process(const char *interp, const char *cmd,
7024  const char *env, const char *envp[],
7025  const char *dir, sock_t sock) {
7026  STARTUPINFOW si;
7027  PROCESS_INFORMATION pi;
7028  HANDLE a[2], b[2], me = GetCurrentProcess();
7029  wchar_t wcmd[MAX_PATH_SIZE], full_dir[MAX_PATH_SIZE];
7030  char buf[MAX_PATH_SIZE], buf2[MAX_PATH_SIZE], buf5[MAX_PATH_SIZE],
7031  buf4[MAX_PATH_SIZE], cmdline[MAX_PATH_SIZE];
7032  DWORD flags = DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS;
7033  FILE *fp;
7034 
7035  memset(&si, 0, sizeof(si));
7036  memset(&pi, 0, sizeof(pi));
7037 
7038  si.cb = sizeof(si);
7039  si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
7040  si.wShowWindow = SW_HIDE;
7041  si.hStdError = GetStdHandle(STD_ERROR_HANDLE);
7042 
7043  CreatePipe(&a[0], &a[1], NULL, 0);
7044  CreatePipe(&b[0], &b[1], NULL, 0);
7045  DuplicateHandle(me, a[0], me, &si.hStdInput, 0, TRUE, flags);
7046  DuplicateHandle(me, b[1], me, &si.hStdOutput, 0, TRUE, flags);
7047 
7048  if (interp == NULL && (fp = fopen(cmd, "r")) != NULL) {
7049  buf[0] = buf[1] = '\0';
7050  fgets(buf, sizeof(buf), fp);
7051  buf[sizeof(buf) - 1] = '\0';
7052  if (buf[0] == '#' && buf[1] == '!') {
7053  interp = buf + 2;
7054  /* Trim leading spaces: https://github.com/cesanta/mongoose/issues/489 */
7055  while (*interp != '\0' && isspace(*(unsigned char *) interp)) {
7056  interp++;
7057  }
7058  }
7059  fclose(fp);
7060  }
7061 
7062  snprintf(buf, sizeof(buf), "%s/%s", dir, cmd);
7063  mg_abs_path(buf, buf2, ARRAY_SIZE(buf2));
7064 
7065  mg_abs_path(dir, buf5, ARRAY_SIZE(buf5));
7066  to_wchar(dir, full_dir, ARRAY_SIZE(full_dir));
7067 
7068  if (interp != NULL) {
7069  mg_abs_path(interp, buf4, ARRAY_SIZE(buf4));
7070  snprintf(cmdline, sizeof(cmdline), "%s \"%s\"", buf4, buf2);
7071  } else {
7072  snprintf(cmdline, sizeof(cmdline), "\"%s\"", buf2);
7073  }
7074  to_wchar(cmdline, wcmd, ARRAY_SIZE(wcmd));
7075 
7076  if (CreateProcessW(NULL, wcmd, NULL, NULL, TRUE, CREATE_NEW_PROCESS_GROUP,
7077  (void *) env, full_dir, &si, &pi) != 0) {
7078  mg_spawn_stdio_thread(sock, a[1], mg_push_to_stdin);
7079  mg_spawn_stdio_thread(sock, b[0], mg_pull_from_stdout);
7080  } else {
7081  CloseHandle(a[1]);
7082  CloseHandle(b[0]);
7083  closesocket(sock);
7084  }
7085  DBG(("CGI command: [%ls] -> %p", wcmd, pi.hProcess));
7086 
7087  /* Not closing a[0] and b[1] because we've used DUPLICATE_CLOSE_SOURCE */
7088  CloseHandle(si.hStdOutput);
7089  CloseHandle(si.hStdInput);
7090  /* TODO(lsm): check if we need close process and thread handles too */
7091  /* CloseHandle(pi.hThread); */
7092  /* CloseHandle(pi.hProcess); */
7093 
7094  return pi.hProcess;
7095  }
7096 #else
7097  static pid_t mg_start_process(const char *interp, const char *cmd,
7098  const char *env, const char *envp[],
7099  const char *dir, sock_t sock) {
7100  char buf[500];
7101  pid_t pid = fork();
7102  (void) env;
7103 
7104  if (pid == 0) {
7105  /*
7106  * In Linux `chdir` declared with `warn_unused_result` attribute
7107  * To shutup compiler we have yo use result in some way
7108  */
7109  int tmp = chdir(dir);
7110  (void) tmp;
7111  (void) dup2(sock, 0);
7112  (void) dup2(sock, 1);
7113  closesocket(sock);
7114 
7115  /*
7116  * After exec, all signal handlers are restored to their default values,
7117  * with one exception of SIGCHLD. According to POSIX.1-2001 and Linux's
7118  * implementation, SIGCHLD's handler will leave unchanged after exec
7119  * if it was set to be ignored. Restore it to default action.
7120  */
7121  signal(SIGCHLD, SIG_DFL);
7122 
7123  if (interp == NULL) {
7124  execle(cmd, cmd, (char *) 0, envp); /* (char *) 0 to squash warning */
7125  } else {
7126  execle(interp, interp, cmd, (char *) 0, envp);
7127  }
7128  snprintf(buf, sizeof(buf),
7129  "Status: 500\r\n\r\n"
7130  "500 Server Error: %s%s%s: %s",
7131  interp == NULL ? "" : interp, interp == NULL ? "" : " ", cmd,
7132  strerror(errno));
7133  send(1, buf, strlen(buf), 0);
7134  exit(EXIT_FAILURE); /* exec call failed */
7135  }
7136 
7137  return pid;
7138  }
7139 #endif /* _WIN32 */
7140 
7141  /*
7142  * Append VARIABLE=VALUE\0 string to the buffer, and add a respective
7143  * pointer into the vars array.
7144  */
7145  static char *mg_addenv(struct mg_cgi_env_block *block, const char *fmt, ...) {
7146  int n, space;
7147  char *added = block->buf + block->len;
7148  va_list ap;
7149 
7150  /* Calculate how much space is left in the buffer */
7151  space = sizeof(block->buf) - (block->len + 2);
7152  if (space > 0) {
7153  /* Copy VARIABLE=VALUE\0 string into the free space */
7154  va_start(ap, fmt);
7155  n = vsnprintf(added, (size_t) space, fmt, ap);
7156  va_end(ap);
7157 
7158  /* Make sure we do not overflow buffer and the envp array */
7159  if (n > 0 && n + 1 < space &&
7160  block->nvars < (int) ARRAY_SIZE(block->vars) - 2) {
7161  /* Append a pointer to the added string into the envp array */
7162  block->vars[block->nvars++] = added;
7163  /* Bump up used length counter. Include \0 terminator */
7164  block->len += n + 1;
7165  }
7166  }
7167 
7168  return added;
7169  }
7170 
7171  static void mg_addenv2(struct mg_cgi_env_block *blk, const char *name) {
7172  const char *s;
7173  if ((s = getenv(name)) != NULL) mg_addenv(blk, "%s=%s", name, s);
7174  }
7175 
7177  const char *prog,
7178  const struct mg_str *path_info,
7179  const struct http_message *hm,
7180  const struct mg_serve_http_opts *opts,
7181  struct mg_cgi_env_block *blk) {
7182  const char *s;
7183  struct mg_str *h;
7184  char *p;
7185  size_t i;
7186  char buf[100];
7187 
7188  blk->len = blk->nvars = 0;
7189  blk->nc = nc;
7190 
7191  if ((s = getenv("SERVER_NAME")) != NULL) {
7192  mg_addenv(blk, "SERVER_NAME=%s", s);
7193  } else {
7194  mg_sock_to_str(nc->sock, buf, sizeof(buf), 3);
7195  mg_addenv(blk, "SERVER_NAME=%s", buf);
7196  }
7197  mg_addenv(blk, "SERVER_ROOT=%s", opts->document_root);
7198  mg_addenv(blk, "DOCUMENT_ROOT=%s", opts->document_root);
7199  mg_addenv(blk, "SERVER_SOFTWARE=%s/%s", "Mongoose", MG_VERSION);
7200 
7201  /* Prepare the environment block */
7202  mg_addenv(blk, "%s", "GATEWAY_INTERFACE=CGI/1.1");
7203  mg_addenv(blk, "%s", "SERVER_PROTOCOL=HTTP/1.1");
7204  mg_addenv(blk, "%s", "REDIRECT_STATUS=200"); /* For PHP */
7205 
7206  mg_addenv(blk, "REQUEST_METHOD=%.*s", (int) hm->method.len, hm->method.p);
7207 
7208  mg_addenv(blk, "REQUEST_URI=%.*s%s%.*s", (int) hm->uri.len, hm->uri.p,
7209  hm->query_string.len == 0 ? "" : "?", (int) hm->query_string.len,
7210  hm->query_string.p);
7211 
7212  mg_conn_addr_to_str(nc, buf, sizeof(buf),
7214  mg_addenv(blk, "REMOTE_ADDR=%s", buf);
7215  mg_conn_addr_to_str(nc, buf, sizeof(buf), MG_SOCK_STRINGIFY_PORT);
7216  mg_addenv(blk, "SERVER_PORT=%s", buf);
7217 
7218  s = hm->uri.p + hm->uri.len - path_info->len - 1;
7219  if (*s == '/') {
7220  const char *base_name = strrchr(prog, DIRSEP);
7221  mg_addenv(blk, "SCRIPT_NAME=%.*s/%s", (int) (s - hm->uri.p), hm->uri.p,
7222  (base_name != NULL ? base_name + 1 : prog));
7223  } else {
7224  mg_addenv(blk, "SCRIPT_NAME=%.*s", (int) (s - hm->uri.p + 1), hm->uri.p);
7225  }
7226  mg_addenv(blk, "SCRIPT_FILENAME=%s", prog);
7227 
7228  if (path_info != NULL && path_info->len > 0) {
7229  mg_addenv(blk, "PATH_INFO=%.*s", (int) path_info->len, path_info->p);
7230  /* Not really translated... */
7231  mg_addenv(blk, "PATH_TRANSLATED=%.*s", (int) path_info->len, path_info->p);
7232  }
7233 
7234  mg_addenv(blk, "HTTPS=%s", nc->ssl != NULL ? "on" : "off");
7235 
7236  if ((h = mg_get_http_header((struct http_message *) hm, "Content-Type")) !=
7237  NULL) {
7238  mg_addenv(blk, "CONTENT_TYPE=%.*s", (int) h->len, h->p);
7239  }
7240 
7241  if (hm->query_string.len > 0) {
7242  mg_addenv(blk, "QUERY_STRING=%.*s", (int) hm->query_string.len,
7243  hm->query_string.p);
7244  }
7245 
7246  if ((h = mg_get_http_header((struct http_message *) hm, "Content-Length")) !=
7247  NULL) {
7248  mg_addenv(blk, "CONTENT_LENGTH=%.*s", (int) h->len, h->p);
7249  }
7250 
7251  mg_addenv2(blk, "PATH");
7252  mg_addenv2(blk, "TMP");
7253  mg_addenv2(blk, "TEMP");
7254  mg_addenv2(blk, "TMPDIR");
7255  mg_addenv2(blk, "PERLLIB");
7257 
7258 #if defined(_WIN32)
7259  mg_addenv2(blk, "COMSPEC");
7260  mg_addenv2(blk, "SYSTEMROOT");
7261  mg_addenv2(blk, "SystemDrive");
7262  mg_addenv2(blk, "ProgramFiles");
7263  mg_addenv2(blk, "ProgramFiles(x86)");
7264  mg_addenv2(blk, "CommonProgramFiles(x86)");
7265 #else
7266  mg_addenv2(blk, "LD_LIBRARY_PATH");
7267 #endif /* _WIN32 */
7268 
7269  /* Add all headers as HTTP_* variables */
7270  for (i = 0; hm->header_names[i].len > 0; i++) {
7271  p = mg_addenv(blk, "HTTP_%.*s=%.*s", (int) hm->header_names[i].len,
7272  hm->header_names[i].p, (int) hm->header_values[i].len,
7273  hm->header_values[i].p);
7274 
7275  /* Convert variable name into uppercase, and change - to _ */
7276  for (; *p != '=' && *p != '\0'; p++) {
7277  if (*p == '-') *p = '_';
7278  *p = (char) toupper(*(unsigned char *) p);
7279  }
7280  }
7281 
7282  blk->vars[blk->nvars++] = NULL;
7283  blk->buf[blk->len++] = '\0';
7284  }
7285 
7286  static void mg_cgi_ev_handler(struct mg_connection *cgi_nc, int ev,
7287  void *ev_data) {
7288  struct mg_connection *nc = (struct mg_connection *) cgi_nc->user_data;
7289  (void) ev_data;
7290 
7291  if (nc == NULL) return;
7292 
7293  switch (ev) {
7294  case MG_EV_RECV:
7295  /*
7296  * CGI script does not output reply line, like "HTTP/1.1 CODE XXXXX\n"
7297  * It outputs headers, then body. Headers might include "Status"
7298  * header, which changes CODE, and it might include "Location" header
7299  * which changes CODE to 302.
7300  *
7301  * Therefore we do not send the output from the CGI script to the user
7302  * until all CGI headers are received.
7303  *
7304  * Here we parse the output from the CGI script, and if all headers has
7305  * been received, send appropriate reply line, and forward all
7306  * received headers to the client.
7307  */
7308  if (nc->flags & MG_F_USER_1) {
7309  struct mbuf *io = &cgi_nc->recv_mbuf;
7310  int len = mg_http_get_request_len(io->buf, io->len);
7311 
7312  if (len == 0) break;
7313  if (len < 0 || io->len > MG_MAX_HTTP_REQUEST_SIZE) {
7314  cgi_nc->flags |= MG_F_CLOSE_IMMEDIATELY;
7315  mg_http_send_error(nc, 500, "Bad headers");
7316  } else {
7317  struct http_message hm;
7318  struct mg_str *h;
7319  mg_http_parse_headers(io->buf, io->buf + io->len, io->len, &hm);
7320  if (mg_get_http_header(&hm, "Location") != NULL) {
7321  mg_printf(nc, "%s", "HTTP/1.1 302 Moved\r\n");
7322  } else if ((h = mg_get_http_header(&hm, "Status")) != NULL) {
7323  mg_printf(nc, "HTTP/1.1 %.*s\r\n", (int) h->len, h->p);
7324  } else {
7325  mg_printf(nc, "%s", "HTTP/1.1 200 OK\r\n");
7326  }
7327  }
7328  nc->flags &= ~MG_F_USER_1;
7329  }
7330  if (!(nc->flags & MG_F_USER_1)) {
7331  mg_forward(cgi_nc, nc);
7332  }
7333  break;
7334  case MG_EV_CLOSE:
7336  nc->flags |= MG_F_SEND_AND_CLOSE;
7337  break;
7338  }
7339  }
7340 
7341  static void mg_handle_cgi(struct mg_connection *nc, const char *prog,
7342  const struct mg_str *path_info,
7343  const struct http_message *hm,
7344  const struct mg_serve_http_opts *opts) {
7345  struct mg_cgi_env_block blk;
7346  char dir[MAX_PATH_SIZE];
7347  const char *p;
7348  sock_t fds[2];
7349 
7350  DBG(("%p [%s]", nc, prog));
7351  mg_prepare_cgi_environment(nc, prog, path_info, hm, opts, &blk);
7352  /*
7353  * CGI must be executed in its own directory. 'dir' must point to the
7354  * directory containing executable program, 'p' must point to the
7355  * executable program name relative to 'dir'.
7356  */
7357  if ((p = strrchr(prog, DIRSEP)) == NULL) {
7358  snprintf(dir, sizeof(dir), "%s", ".");
7359  } else {
7360  snprintf(dir, sizeof(dir), "%.*s", (int) (p - prog), prog);
7361  prog = p + 1;
7362  }
7363 
7364  /*
7365  * Try to create socketpair in a loop until success. mg_socketpair()
7366  * can be interrupted by a signal and fail.
7367  * TODO(lsm): use sigaction to restart interrupted syscall
7368  */
7369  do {
7370  mg_socketpair(fds, SOCK_STREAM);
7371  } while (fds[0] == INVALID_SOCKET);
7372 
7373  if (mg_start_process(opts->cgi_interpreter, prog, blk.buf, blk.vars, dir,
7374  fds[1]) != 0) {
7375  size_t n = nc->recv_mbuf.len - (hm->message.len - hm->body.len);
7376  struct mg_connection *cgi_nc =
7377  mg_add_sock(nc->mgr, fds[0], mg_cgi_ev_handler);
7378  struct mg_http_proto_data *cgi_pd = mg_http_get_proto_data(cgi_nc);
7379  cgi_pd->cgi.cgi_nc = cgi_nc;
7380  cgi_pd->cgi.cgi_nc->user_data = nc;
7381  nc->flags |= MG_F_USER_1;
7382  /* Push POST data to the CGI */
7383  if (n > 0 && n < nc->recv_mbuf.len) {
7384  mg_send(cgi_pd->cgi.cgi_nc, hm->body.p, n);
7385  }
7386  mbuf_remove(&nc->recv_mbuf, nc->recv_mbuf.len);
7387  } else {
7388  closesocket(fds[0]);
7389  mg_http_send_error(nc, 500, "CGI failure");
7390  }
7391 
7392 #ifndef _WIN32
7393  closesocket(fds[1]); /* On Windows, CGI stdio thread closes that socket */
7394 #endif
7395  }
7396 #endif
7397 
7398  static int mg_get_month_index(const char *s) {
7399  static const char *month_names[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
7400  "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
7401  size_t i;
7402 
7403  for (i = 0; i < ARRAY_SIZE(month_names); i++)
7404  if (!strcmp(s, month_names[i])) return (int) i;
7405 
7406  return -1;
7407  }
7408 
7409  static int mg_num_leap_years(int year) {
7410  return year / 4 - year / 100 + year / 400;
7411  }
7412 
7413  /* Parse UTC date-time string, and return the corresponding time_t value. */
7414  MG_INTERNAL time_t mg_parse_date_string(const char *datetime) {
7415  static const unsigned short days_before_month[] = {
7416  0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334};
7417  char month_str[32];
7418  int second, minute, hour, day, month, year, leap_days, days;
7419  time_t result = (time_t) 0;
7420 
7421  if (((sscanf(datetime, "%d/%3s/%d %d:%d:%d", &day, month_str, &year, &hour,
7422  &minute, &second) == 6) ||
7423  (sscanf(datetime, "%d %3s %d %d:%d:%d", &day, month_str, &year, &hour,
7424  &minute, &second) == 6) ||
7425  (sscanf(datetime, "%*3s, %d %3s %d %d:%d:%d", &day, month_str, &year,
7426  &hour, &minute, &second) == 6) ||
7427  (sscanf(datetime, "%d-%3s-%d %d:%d:%d", &day, month_str, &year, &hour,
7428  &minute, &second) == 6)) &&
7429  year > 1970 && (month = mg_get_month_index(month_str)) != -1) {
7430  leap_days = mg_num_leap_years(year) - mg_num_leap_years(1970);
7431  year -= 1970;
7432  days = year * 365 + days_before_month[month] + (day - 1) + leap_days;
7433  result = days * 24 * 3600 + hour * 3600 + minute * 60 + second;
7434  }
7435 
7436  return result;
7437  }
7438 
7439  MG_INTERNAL int mg_is_not_modified(struct http_message *hm, cs_stat_t *st) {
7440  struct mg_str *hdr;
7441  if ((hdr = mg_get_http_header(hm, "If-None-Match")) != NULL) {
7442  char etag[64];
7443  mg_http_construct_etag(etag, sizeof(etag), st);
7444  return mg_vcasecmp(hdr, etag) == 0;
7445  } else if ((hdr = mg_get_http_header(hm, "If-Modified-Since")) != NULL) {
7446  return st->st_mtime <= mg_parse_date_string(hdr->p);
7447  } else {
7448  return 0;
7449  }
7450  }
7451 
7453  const char *domain) {
7454  mg_printf(c,
7455  "HTTP/1.1 401 Unauthorized\r\n"
7456  "WWW-Authenticate: Digest qop=\"auth\", "
7457  "realm=\"%s\", nonce=\"%lu\"\r\n"
7458  "Content-Length: 0\r\n\r\n",
7459  domain, (unsigned long) time(NULL));
7460  }
7461 
7462  static void mg_http_send_options(struct mg_connection *nc) {
7463  mg_printf(nc, "%s",
7464  "HTTP/1.1 200 OK\r\nAllow: GET, POST, HEAD, CONNECT, OPTIONS"
7465 #ifndef MG_DISABLE_DAV
7466  ", MKCOL, PUT, DELETE, PROPFIND, MOVE\r\nDAV: 1,2"
7467 #endif
7468  "\r\n\r\n");
7469  nc->flags |= MG_F_SEND_AND_CLOSE;
7470  }
7471 
7472  static int mg_is_creation_request(const struct http_message *hm) {
7473  return mg_vcmp(&hm->method, "MKCOL") == 0 || mg_vcmp(&hm->method, "PUT") == 0;
7474  }
7475 
7476  MG_INTERNAL void mg_send_http_file(struct mg_connection *nc, char *path,
7477  const struct mg_str *path_info,
7478  struct http_message *hm,
7479  struct mg_serve_http_opts *opts) {
7480  int exists, is_directory, is_dav = mg_is_dav_request(&hm->method);
7481  int is_cgi;
7482  char *index_file = NULL;
7483  cs_stat_t st;
7484 
7485  exists = (mg_stat(path, &st) == 0);
7486  is_directory = exists && S_ISDIR(st.st_mode);
7487 
7488  if (is_directory)
7489  mg_find_index_file(path, opts->index_files, &index_file, &st);
7490 
7491  is_cgi =
7492  (mg_match_prefix(opts->cgi_file_pattern, strlen(opts->cgi_file_pattern),
7493  index_file ? index_file : path) > 0);
7494 
7495  DBG(("%p %.*s [%s] exists=%d is_dir=%d is_dav=%d is_cgi=%d index=%s", nc,
7496  (int) hm->method.len, hm->method.p, path, exists, is_directory, is_dav,
7497  is_cgi, index_file ? index_file : ""));
7498 
7499  if (is_directory && hm->uri.p[hm->uri.len - 1] != '/' && !is_dav) {
7500  mg_printf(nc,
7501  "HTTP/1.1 301 Moved\r\nLocation: %.*s/\r\n"
7502  "Content-Length: 0\r\n\r\n",
7503  (int) hm->uri.len, hm->uri.p);
7504  MG_FREE(index_file);
7505  return;
7506  }
7507 
7508  /* If we have path_info, the only way to handle it is CGI. */
7509  if (path_info->len > 0 && !is_cgi) {
7510  mg_http_send_error(nc, 501, NULL);
7511  MG_FREE(index_file);
7512  return;
7513  }
7514 
7515  if (is_dav && opts->dav_document_root == NULL) {
7516  mg_http_send_error(nc, 501, NULL);
7517  } else if (!mg_is_authorized(hm, path, is_directory, opts->auth_domain,
7518  opts->global_auth_file, 1) ||
7519  !mg_is_authorized(hm, path, is_directory, opts->auth_domain,
7520  opts->per_directory_auth_file, 0)) {
7522  } else if (is_cgi) {
7523 #if !defined(MG_DISABLE_CGI)
7524  mg_handle_cgi(nc, index_file ? index_file : path, path_info, hm, opts);
7525 #else
7526  mg_http_send_error(nc, 501, NULL);
7527 #endif /* MG_DISABLE_CGI */
7528  } else if ((!exists ||
7529  mg_is_file_hidden(path, opts, 0 /* specials are ok */)) &&
7530  !mg_is_creation_request(hm)) {
7531  mg_http_send_error(nc, 404, NULL);
7532 #ifndef MG_DISABLE_DAV
7533  } else if (!mg_vcmp(&hm->method, "PROPFIND")) {
7534  mg_handle_propfind(nc, path, &st, hm, opts);
7535 #ifndef MG_DISABLE_DAV_AUTH
7536  } else if (is_dav &&
7537  (opts->dav_auth_file == NULL ||
7538  (strcmp(opts->dav_auth_file, "-") != 0 &&
7539  !mg_is_authorized(hm, path, is_directory, opts->auth_domain,
7540  opts->dav_auth_file, 1)))) {
7542 #endif
7543  } else if (!mg_vcmp(&hm->method, "MKCOL")) {
7544  mg_handle_mkcol(nc, path, hm);
7545  } else if (!mg_vcmp(&hm->method, "DELETE")) {
7546  mg_handle_delete(nc, opts, path);
7547  } else if (!mg_vcmp(&hm->method, "PUT")) {
7548  mg_handle_put(nc, path, hm);
7549  } else if (!mg_vcmp(&hm->method, "MOVE")) {
7550  mg_handle_move(nc, opts, path, hm);
7551 #ifdef MG_ENABLE_FAKE_DAVLOCK
7552  } else if (!mg_vcmp(&hm->method, "LOCK")) {
7553  mg_handle_lock(nc, path);
7554 #endif
7555 #endif
7556  } else if (!mg_vcmp(&hm->method, "OPTIONS")) {
7558  } else if (is_directory && index_file == NULL) {
7559 #ifndef MG_DISABLE_DIRECTORY_LISTING
7560  if (strcmp(opts->enable_directory_listing, "yes") == 0) {
7561  mg_send_directory_listing(nc, path, hm, opts);
7562  } else {
7563  mg_http_send_error(nc, 403, NULL);
7564  }
7565 #else
7566  mg_http_send_error(nc, 501, NULL);
7567 #endif
7568  } else if (mg_is_not_modified(hm, &st)) {
7569  mg_http_send_error(nc, 304, "Not Modified");
7570  } else {
7571  mg_http_send_file2(nc, index_file ? index_file : path, &st, hm, opts);
7572  }
7573  MG_FREE(index_file);
7574  }
7575 
7576  void mg_serve_http(struct mg_connection *nc, struct http_message *hm,
7577  struct mg_serve_http_opts opts) {
7578  char *path = NULL;
7579  struct mg_str *hdr, path_info;
7580  uint32_t remote_ip = ntohl(*(uint32_t *) &nc->sa.sin.sin_addr);
7581 
7582  if (mg_check_ip_acl(opts.ip_acl, remote_ip) != 1) {
7583  /* Not allowed to connect */
7584  mg_http_send_error(nc, 403, NULL);
7585  nc->flags |= MG_F_SEND_AND_CLOSE;
7586  return;
7587  }
7588 
7589  if (mg_http_send_port_based_redirect(nc, hm, &opts)) {
7590  return;
7591  }
7592 
7593  if (opts.document_root == NULL) {
7594  opts.document_root = ".";
7595  }
7596  if (opts.per_directory_auth_file == NULL) {
7597  opts.per_directory_auth_file = ".htpasswd";
7598  }
7599  if (opts.enable_directory_listing == NULL) {
7600  opts.enable_directory_listing = "yes";
7601  }
7602  if (opts.cgi_file_pattern == NULL) {
7603  opts.cgi_file_pattern = "**.cgi$|**.php$";
7604  }
7605  if (opts.ssi_pattern == NULL) {
7606  opts.ssi_pattern = "**.shtml$|**.shtm$";
7607  }
7608  if (opts.index_files == NULL) {
7609  opts.index_files = "index.html,index.htm,index.shtml,index.cgi,index.php";
7610  }
7611  /* Normalize path - resolve "." and ".." (in-place). */
7612  if (!mg_normalize_uri_path(&hm->uri, &hm->uri)) {
7613  mg_http_send_error(nc, 400, NULL);
7614  return;
7615  }
7616  if (mg_uri_to_local_path(hm, &opts, &path, &path_info) == 0) {
7617  mg_http_send_error(nc, 404, NULL);
7618  return;
7619  }
7620  mg_send_http_file(nc, path, &path_info, hm, &opts);
7621 
7622  MG_FREE(path);
7623  path = NULL;
7624 
7625  /* Close connection for non-keep-alive requests */
7626  if (mg_vcmp(&hm->proto, "HTTP/1.1") != 0 ||
7627  ((hdr = mg_get_http_header(hm, "Connection")) != NULL &&
7628  mg_vcmp(hdr, "keep-alive") != 0)) {
7629 #if 0
7630  nc->flags |= MG_F_SEND_AND_CLOSE;
7631 #endif
7632  }
7633  }
7634 
7635 #endif /* MG_DISABLE_FILESYSTEM */
7636 
7637  /* returns 0 on success, -1 on error */
7638  static int mg_http_common_url_parse(const char *url, const char *schema,
7639  const char *schema_tls, int *use_ssl,
7640  char **addr, int *port_i,
7641  const char **path) {
7642  int addr_len = 0;
7643 
7644  if (memcmp(url, schema, strlen(schema)) == 0) {
7645  url += strlen(schema);
7646  } else if (memcmp(url, schema_tls, strlen(schema_tls)) == 0) {
7647  url += strlen(schema_tls);
7648  *use_ssl = 1;
7649 #ifndef MG_ENABLE_SSL
7650  return -1; /* SSL is not enabled, cannot do HTTPS URLs */
7651 #endif
7652  }
7653 
7654  while (*url != '\0') {
7655  *addr = (char *) MG_REALLOC(*addr, addr_len + 5 /* space for port too. */);
7656  if (*addr == NULL) {
7657  DBG(("OOM"));
7658  return -1;
7659  }
7660  if (*url == '/') {
7661  break;
7662  }
7663  if (*url == ':') *port_i = addr_len;
7664  (*addr)[addr_len++] = *url;
7665  (*addr)[addr_len] = '\0';
7666  url++;
7667  }
7668  if (addr_len == 0) goto cleanup;
7669  if (*port_i < 0) {
7670  *port_i = addr_len;
7671  strcpy(*addr + *port_i, *use_ssl ? ":443" : ":80");
7672  } else {
7673  *port_i = -1;
7674  }
7675 
7676  if (*path == NULL) *path = url;
7677 
7678  if (**path == '\0') *path = "/";
7679 
7680  DBG(("%s %s", *addr, *path));
7681 
7682  return 0;
7683 
7684  cleanup:
7685  MG_FREE(*addr);
7686  return -1;
7687  }
7688 
7691  struct mg_connect_opts opts, const char *schema, const char *schema_ssl,
7692  const char *url, const char **path, char **addr) {
7693  struct mg_connection *nc = NULL;
7694  int port_i = -1;
7695  int use_ssl = 0;
7696 
7697  if (mg_http_common_url_parse(url, schema, schema_ssl, &use_ssl, addr, &port_i,
7698  path) < 0) {
7699  return NULL;
7700  }
7701 
7702 #ifndef MG_ENABLE_SSL
7703  if (use_ssl) {
7704  MG_SET_PTRPTR(opts.error_string, "ssl is disabled");
7705  MG_FREE(addr);
7706  return NULL;
7707  }
7708 #endif
7709 
7710  if ((nc = mg_connect_opt(mgr, *addr, ev_handler, opts)) != NULL) {
7711 #ifdef MG_ENABLE_SSL
7712  if (use_ssl && nc->ssl_ctx == NULL) {
7713  /*
7714  * Schema requires SSL, but no SSL parameters were provided in
7715  * opts. In order to maintain backward compatibility, use
7716  * NULL, NULL
7717  */
7718  mg_set_ssl(nc, NULL, NULL);
7719  }
7720 #endif
7722 
7723  /* If the port was addred by us, restore the original host. */
7724  if (port_i >= 0) (*addr)[port_i] = '\0';
7725  }
7726 
7727  return nc;
7728  }
7729 
7732  struct mg_connect_opts opts,
7733  const char *url,
7734  const char *extra_headers,
7735  const char *post_data) {
7736  char *addr = NULL;
7737  const char *path = NULL;
7738  struct mg_connection *nc = mg_connect_http_base(
7739  mgr, ev_handler, opts, "http://", "https://", url, &path, &addr);
7740 
7741  if (nc == NULL) {
7742  return NULL;
7743  }
7744 
7745  mg_printf(nc, "%s %s HTTP/1.1\r\nHost: %s\r\nContent-Length: %" SIZE_T_FMT
7746  "\r\n%s\r\n%s",
7747  post_data == NULL ? "GET" : "POST", path, addr,
7748  post_data == NULL ? 0 : strlen(post_data),
7749  extra_headers == NULL ? "" : extra_headers,
7750  post_data == NULL ? "" : post_data);
7751 
7752  MG_FREE(addr);
7753  return nc;
7754  }
7755 
7758  const char *url,
7759  const char *extra_headers,
7760  const char *post_data) {
7761  struct mg_connect_opts opts;
7762  memset(&opts, 0, sizeof(opts));
7763  return mg_connect_http_opt(mgr, ev_handler, opts, url, extra_headers,
7764  post_data);
7765  }
7766 
7769  struct mg_connect_opts opts,
7770  const char *url, const char *protocol,
7771  const char *extra_headers) {
7772  char *addr = NULL;
7773  const char *path = NULL;
7774  struct mg_connection *nc = mg_connect_http_base(
7775  mgr, ev_handler, opts, "ws://", "wss://", url, &path, &addr);
7776 
7777  if (nc == NULL) {
7778  return NULL;
7779  }
7780 
7781  mg_send_websocket_handshake2(nc, path, addr, protocol, extra_headers);
7782 
7783  MG_FREE(addr);
7784  return nc;
7785  }
7786 
7789  const char *url, const char *protocol,
7790  const char *extra_headers) {
7791  struct mg_connect_opts opts;
7792  memset(&opts, 0, sizeof(opts));
7793  return mg_connect_ws_opt(mgr, ev_handler, opts, url, protocol, extra_headers);
7794  }
7795 
7796  size_t mg_parse_multipart(const char *buf, size_t buf_len, char *var_name,
7797  size_t var_name_len, char *file_name,
7798  size_t file_name_len, const char **data,
7799  size_t *data_len) {
7800  static const char cd[] = "Content-Disposition: ";
7801  size_t hl, bl, n, ll, pos, cdl = sizeof(cd) - 1;
7802 
7803  if (buf == NULL || buf_len <= 0) return 0;
7804  if ((hl = mg_http_get_request_len(buf, buf_len)) <= 0) return 0;
7805  if (buf[0] != '-' || buf[1] != '-' || buf[2] == '\n') return 0;
7806 
7807  /* Get boundary length */
7808  bl = mg_get_line_len(buf, buf_len);
7809 
7810  /* Loop through headers, fetch variable name and file name */
7811  var_name[0] = file_name[0] = '\0';
7812  for (n = bl; (ll = mg_get_line_len(buf + n, hl - n)) > 0; n += ll) {
7813  if (mg_ncasecmp(cd, buf + n, cdl) == 0) {
7814  struct mg_str header;
7815  header.p = buf + n + cdl;
7816  header.len = ll - (cdl + 2);
7817  mg_http_parse_header(&header, "name", var_name, var_name_len);
7818  mg_http_parse_header(&header, "filename", file_name, file_name_len);
7819  }
7820  }
7821 
7822  /* Scan through the body, search for terminating boundary */
7823  for (pos = hl; pos + (bl - 2) < buf_len; pos++) {
7824  if (buf[pos] == '-' && !memcmp(buf, &buf[pos], bl - 2)) {
7825  if (data_len != NULL) *data_len = (pos - 2) - hl;
7826  if (data != NULL) *data = buf + hl;
7827  return pos;
7828  }
7829  }
7830 
7831  return 0;
7832  }
7833 
7834  void mg_register_http_endpoint(struct mg_connection *nc, const char *uri_path,
7836  struct mg_http_proto_data *pd = mg_http_get_proto_data(nc);
7837  struct mg_http_endpoint *new_ep =
7838  (struct mg_http_endpoint *) calloc(1, sizeof(*new_ep));
7839  new_ep->name = strdup(uri_path);
7840  new_ep->name_len = strlen(new_ep->name);
7841  new_ep->handler = handler;
7842  new_ep->next = pd->endpoints;
7843  pd->endpoints = new_ep;
7844  }
7845 
7846 #endif /* MG_DISABLE_HTTP */
7847 #ifdef MG_MODULE_LINES
7848 #line 1 "./src/util.c"
7849 #endif
7850  /*
7851  * Copyright (c) 2014 Cesanta Software Limited
7852  * All rights reserved
7853  */
7854 
7855  /* Amalgamated: #include "common/base64.h" */
7856  /* Amalgamated: #include "mongoose/src/internal.h" */
7857  /* Amalgamated: #include "mongoose/src/util.h" */
7858 
7859  const char *mg_skip(const char *s, const char *end, const char *delims,
7860  struct mg_str *v) {
7861  v->p = s;
7862  while (s < end && strchr(delims, *(unsigned char *) s) == NULL) s++;
7863  v->len = s - v->p;
7864  while (s < end && strchr(delims, *(unsigned char *) s) != NULL) s++;
7865  return s;
7866  }
7867 
7868  static int lowercase(const char *s) {
7869  return tolower(*(const unsigned char *) s);
7870  }
7871 
7872  int mg_ncasecmp(const char *s1, const char *s2, size_t len) {
7873  int diff = 0;
7874 
7875  if (len > 0) do {
7876  diff = lowercase(s1++) - lowercase(s2++);
7877  } while (diff == 0 && s1[-1] != '\0' && --len > 0);
7878 
7879  return diff;
7880  }
7881 
7882  int mg_casecmp(const char *s1, const char *s2) {
7883  return mg_ncasecmp(s1, s2, (size_t) ~0);
7884  }
7885 
7886  int mg_vcasecmp(const struct mg_str *str1, const char *str2) {
7887  size_t n2 = strlen(str2), n1 = str1->len;
7888  int r = mg_ncasecmp(str1->p, str2, (n1 < n2) ? n1 : n2);
7889  if (r == 0) {
7890  return n1 - n2;
7891  }
7892  return r;
7893  }
7894 
7895  int mg_vcmp(const struct mg_str *str1, const char *str2) {
7896  size_t n2 = strlen(str2), n1 = str1->len;
7897  int r = memcmp(str1->p, str2, (n1 < n2) ? n1 : n2);
7898  if (r == 0) {
7899  return n1 - n2;
7900  }
7901  return r;
7902  }
7903 
7904 #ifndef MG_DISABLE_FILESYSTEM
7905  int mg_stat(const char *path, cs_stat_t *st) {
7906 #ifdef _WIN32
7907  wchar_t wpath[MAX_PATH_SIZE];
7908  to_wchar(path, wpath, ARRAY_SIZE(wpath));
7909  DBG(("[%ls] -> %d", wpath, _wstati64(wpath, st)));
7910  return _wstati64(wpath, (struct _stati64 *) st);
7911 #else
7912  return stat(path, st);
7913 #endif
7914  }
7915 
7916  FILE *mg_fopen(const char *path, const char *mode) {
7917 #ifdef _WIN32
7918  wchar_t wpath[MAX_PATH_SIZE], wmode[10];
7919  to_wchar(path, wpath, ARRAY_SIZE(wpath));
7920  to_wchar(mode, wmode, ARRAY_SIZE(wmode));
7921  return _wfopen(wpath, wmode);
7922 #else
7923  return fopen(path, mode);
7924 #endif
7925  }
7926 
7927  int mg_open(const char *path, int flag, int mode) { /* LCOV_EXCL_LINE */
7928 #ifdef _WIN32
7929  wchar_t wpath[MAX_PATH_SIZE];
7930  to_wchar(path, wpath, ARRAY_SIZE(wpath));
7931  return _wopen(wpath, flag, mode);
7932 #else
7933  return open(path, flag, mode); /* LCOV_EXCL_LINE */
7934 #endif
7935  }
7936 #endif
7937 
7938  void mg_base64_encode(const unsigned char *src, int src_len, char *dst) {
7939  cs_base64_encode(src, src_len, dst);
7940  }
7941 
7942  int mg_base64_decode(const unsigned char *s, int len, char *dst) {
7943  return cs_base64_decode(s, len, dst);
7944  }
7945 
7946 #ifdef MG_ENABLE_THREADS
7947  void *mg_start_thread(void *(*f)(void *), void *p) {
7948 #ifdef _WIN32
7949  return (void *) _beginthread((void(__cdecl *) (void *) ) f, 0, p);
7950 #else
7951  pthread_t thread_id = (pthread_t) 0;
7952  pthread_attr_t attr;
7953 
7954  (void) pthread_attr_init(&attr);
7955  (void) pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
7956 
7957 #if defined(MG_STACK_SIZE) && MG_STACK_SIZE > 1
7958  (void) pthread_attr_setstacksize(&attr, MG_STACK_SIZE);
7959 #endif
7960 
7961  pthread_create(&thread_id, &attr, f, p);
7962  pthread_attr_destroy(&attr);
7963 
7964  return (void *) thread_id;
7965 #endif
7966  }
7967 #endif /* MG_ENABLE_THREADS */
7968 
7969  /* Set close-on-exec bit for a given socket. */
7970  void mg_set_close_on_exec(sock_t sock) {
7971 #ifdef _WIN32
7972  (void) SetHandleInformation((HANDLE) sock, HANDLE_FLAG_INHERIT, 0);
7973 #elif defined(__unix__)
7974  fcntl(sock, F_SETFD, FD_CLOEXEC);
7975 #else
7976  (void) sock;
7977 #endif
7978  }
7979 
7980  void mg_sock_addr_to_str(const union socket_address *sa, char *buf, size_t len,
7981  int flags) {
7982  int is_v6;
7983  if (buf == NULL || len <= 0) return;
7984  buf[0] = '\0';
7985 #if defined(MG_ENABLE_IPV6)
7986  is_v6 = sa->sa.sa_family == AF_INET6;
7987 #else
7988  is_v6 = 0;
7989 #endif
7990  if (flags & MG_SOCK_STRINGIFY_IP) {
7991 #if defined(MG_ENABLE_IPV6)
7992  const void *addr = NULL;
7993  char *start = buf;
7994  socklen_t capacity = len;
7995  if (!is_v6) {
7996  addr = &sa->sin.sin_addr;
7997  } else {
7998  addr = (void *) &sa->sin6.sin6_addr;
7999  if (flags & MG_SOCK_STRINGIFY_PORT) {
8000  *buf = '[';
8001  start++;
8002  capacity--;
8003  }
8004  }
8005  if (inet_ntop(sa->sa.sa_family, addr, start, capacity) == NULL) {
8006  *buf = '\0';
8007  }
8008 #elif defined(_WIN32) || defined(MG_LWIP)
8009  /* Only Windoze Vista (and newer) have inet_ntop() */
8010  strncpy(buf, inet_ntoa(sa->sin.sin_addr), len);
8011 #else
8012  inet_ntop(AF_INET, (void *) &sa->sin.sin_addr, buf, len);
8013 #endif
8014  }
8015  if (flags & MG_SOCK_STRINGIFY_PORT) {
8016  int port = ntohs(sa->sin.sin_port);
8017  if (flags & MG_SOCK_STRINGIFY_IP) {
8018  snprintf(buf + strlen(buf), len - (strlen(buf) + 1), "%s:%d",
8019  (is_v6 ? "]" : ""), port);
8020  } else {
8021  snprintf(buf, len, "%d", port);
8022  }
8023  }
8024  }
8025 
8026  void mg_conn_addr_to_str(struct mg_connection *nc, char *buf, size_t len,
8027  int flags) {
8028  union socket_address sa;
8029  memset(&sa, 0, sizeof(sa));
8031  mg_sock_addr_to_str(&sa, buf, len, flags);
8032  }
8033 
8034 #ifndef MG_DISABLE_HEXDUMP
8035  int mg_hexdump(const void *buf, int len, char *dst, int dst_len) {
8036  const unsigned char *p = (const unsigned char *) buf;
8037  char ascii[17] = "";
8038  int i, idx, n = 0;
8039 
8040  for (i = 0; i < len; i++) {
8041  idx = i % 16;
8042  if (idx == 0) {
8043  if (i > 0) n += snprintf(dst + n, dst_len - n, " %s\n", ascii);
8044  n += snprintf(dst + n, dst_len - n, "%04x ", i);
8045  }
8046  n += snprintf(dst + n, dst_len - n, " %02x", p[i]);
8047  ascii[idx] = p[i] < 0x20 || p[i] > 0x7e ? '.' : p[i];
8048  ascii[idx + 1] = '\0';
8049  }
8050 
8051  while (i++ % 16) n += snprintf(dst + n, dst_len - n, "%s", " ");
8052  n += snprintf(dst + n, dst_len - n, " %s\n\n", ascii);
8053 
8054  return n;
8055  }
8056 #endif
8057 
8058  int mg_avprintf(char **buf, size_t size, const char *fmt, va_list ap) {
8059  va_list ap_copy;
8060  int len;
8061 
8062  va_copy(ap_copy, ap);
8063  len = vsnprintf(*buf, size, fmt, ap_copy);
8064  va_end(ap_copy);
8065 
8066  if (len < 0) {
8067  /* eCos and Windows are not standard-compliant and return -1 when
8068  * the buffer is too small. Keep allocating larger buffers until we
8069  * succeed or out of memory. */
8070  *buf = NULL; /* LCOV_EXCL_START */
8071  while (len < 0) {
8072  MG_FREE(*buf);
8073  size *= 2;
8074  if ((*buf = (char *) MG_MALLOC(size)) == NULL) break;
8075  va_copy(ap_copy, ap);
8076  len = vsnprintf(*buf, size, fmt, ap_copy);
8077  va_end(ap_copy);
8078  }
8079  /* LCOV_EXCL_STOP */
8080  } else if (len >= (int) size) {
8081  /* Standard-compliant code path. Allocate a buffer that is large enough. */
8082  if ((*buf = (char *) MG_MALLOC(len + 1)) == NULL) {
8083  len = -1; /* LCOV_EXCL_LINE */
8084  } else { /* LCOV_EXCL_LINE */
8085  va_copy(ap_copy, ap);
8086  len = vsnprintf(*buf, len + 1, fmt, ap_copy);
8087  va_end(ap_copy);
8088  }
8089  }
8090 
8091  return len;
8092  }
8093 
8094 #if !defined(MG_DISABLE_HEXDUMP)
8095  void mg_hexdump_connection(struct mg_connection *nc, const char *path,
8096  const void *buf, int num_bytes, int ev) {
8097 #if !defined(NO_LIBC) && !defined(MG_DISABLE_STDIO)
8098  FILE *fp = NULL;
8099  char *hexbuf, src[60], dst[60];
8100  int buf_size = num_bytes * 5 + 100;
8101 
8102  if (strcmp(path, "-") == 0) {
8103  fp = stdout;
8104  } else if (strcmp(path, "--") == 0) {
8105  fp = stderr;
8106 #ifndef MG_DISABLE_FILESYSTEM
8107  } else {
8108  fp = fopen(path, "a");
8109 #endif
8110  }
8111  if (fp == NULL) return;
8112 
8113  mg_conn_addr_to_str(nc, src, sizeof(src),
8115  mg_conn_addr_to_str(nc, dst, sizeof(dst), MG_SOCK_STRINGIFY_IP |
8118  fprintf(
8119  fp, "%lu %p %s %s %s %d\n", (unsigned long) time(NULL), (void *) nc, src,
8120  ev == MG_EV_RECV ? "<-" : ev == MG_EV_SEND
8121  ? "->"
8122  : ev == MG_EV_ACCEPT
8123  ? "<A"
8124  : ev == MG_EV_CONNECT ? "C>" : "XX",
8125  dst, num_bytes);
8126  if (num_bytes > 0 && (hexbuf = (char *) MG_MALLOC(buf_size)) != NULL) {
8127  mg_hexdump(buf, num_bytes, hexbuf, buf_size);
8128  fprintf(fp, "%s", hexbuf);
8129  MG_FREE(hexbuf);
8130  }
8131  if (fp != stdin && fp != stdout) fclose(fp);
8132 #endif
8133  }
8134 #endif
8135 
8136  int mg_is_big_endian(void) {
8137  static const int n = 1;
8138  /* TODO(mkm) use compiletime check with 4-byte char literal */
8139  return ((char *) &n)[0] == 0;
8140  }
8141 
8142  const char *mg_next_comma_list_entry(const char *list, struct mg_str *val,
8143  struct mg_str *eq_val) {
8144  if (list == NULL || *list == '\0') {
8145  /* End of the list */
8146  list = NULL;
8147  } else {
8148  val->p = list;
8149  if ((list = strchr(val->p, ',')) != NULL) {
8150  /* Comma found. Store length and shift the list ptr */
8151  val->len = list - val->p;
8152  list++;
8153  } else {
8154  /* This value is the last one */
8155  list = val->p + strlen(val->p);
8156  val->len = list - val->p;
8157  }
8158 
8159  if (eq_val != NULL) {
8160  /* Value has form "x=y", adjust pointers and lengths */
8161  /* so that val points to "x", and eq_val points to "y". */
8162  eq_val->len = 0;
8163  eq_val->p = (const char *) memchr(val->p, '=', val->len);
8164  if (eq_val->p != NULL) {
8165  eq_val->p++; /* Skip over '=' character */
8166  eq_val->len = val->p + val->len - eq_val->p;
8167  val->len = (eq_val->p - val->p) - 1;
8168  }
8169  }
8170  }
8171 
8172  return list;
8173  }
8174 
8175  int mg_match_prefix_n(const struct mg_str pattern, const struct mg_str str) {
8176  const char *or_str;
8177  size_t len, i = 0, j = 0;
8178  int res;
8179 
8180  if ((or_str = (const char *) memchr(pattern.p, '|', pattern.len)) != NULL) {
8181  struct mg_str pstr = {pattern.p, (size_t)(or_str - pattern.p)};
8182  res = mg_match_prefix_n(pstr, str);
8183  if (res > 0) return res;
8184  pstr.p = or_str + 1;
8185  pstr.len = (pattern.p + pattern.len) - (or_str + 1);
8186  return mg_match_prefix_n(pstr, str);
8187  }
8188 
8189  for (; i < pattern.len; i++, j++) {
8190  if (pattern.p[i] == '?' && j != str.len) {
8191  continue;
8192  } else if (pattern.p[i] == '$') {
8193  return j == str.len ? (int) j : -1;
8194  } else if (pattern.p[i] == '*') {
8195  i++;
8196  if (pattern.p[i] == '*') {
8197  i++;
8198  len = str.len - j;
8199  } else {
8200  len = 0;
8201  while (j + len != str.len && str.p[len] != '/') {
8202  len++;
8203  }
8204  }
8205  if (i == pattern.len) {
8206  return j + len;
8207  }
8208  do {
8209  const struct mg_str pstr = {pattern.p + i, pattern.len - i};
8210  const struct mg_str sstr = {str.p + j + len, str.len - j - len};
8211  res = mg_match_prefix_n(pstr, sstr);
8212  } while (res == -1 && len-- > 0);
8213  return res == -1 ? -1 : (int) (j + res + len);
8214  } else if (lowercase(&pattern.p[i]) != lowercase(&str.p[j])) {
8215  return -1;
8216  }
8217  }
8218  return j;
8219  }
8220 
8221  int mg_match_prefix(const char *pattern, int pattern_len, const char *str) {
8222  const struct mg_str pstr = {pattern, (size_t) pattern_len};
8223  return mg_match_prefix_n(pstr, mg_mk_str(str));
8224  }
8225 
8226  struct mg_str mg_mk_str(const char *s) {
8227  struct mg_str ret = {s, 0};
8228  if (s != NULL) ret.len = strlen(s);
8229  return ret;
8230  }
8231 #ifdef MG_MODULE_LINES
8232 #line 1 "./src/json-rpc.c"
8233 #endif
8234  /* Copyright (c) 2014 Cesanta Software Limited */
8235  /* All rights reserved */
8236 
8237 #ifndef MG_DISABLE_JSON_RPC
8238 
8239  /* Amalgamated: #include "mongoose/src/internal.h" */
8240  /* Amalgamated: #include "mongoose/src/json-rpc.h" */
8241  /* Amalgamated: #include "mongoose/deps/frozen/frozen.h" */
8242 
8243  int mg_rpc_create_reply(char *buf, int len, const struct mg_rpc_request *req,
8244  const char *result_fmt, ...) {
8245  static const struct json_token null_tok = {"null", 4, 0, JSON_TYPE_NULL};
8246  const struct json_token *id = req->id == NULL ? &null_tok : req->id;
8247  va_list ap;
8248  int n = 0;
8249 
8250  n += json_emit(buf + n, len - n, "{s:s,s:", "jsonrpc", "2.0", "id");
8251  if (id->type == JSON_TYPE_STRING) {
8252  n += json_emit_quoted_str(buf + n, len - n, id->ptr, id->len);
8253  } else {
8254  n += json_emit_unquoted_str(buf + n, len - n, id->ptr, id->len);
8255  }
8256  n += json_emit(buf + n, len - n, ",s:", "result");
8257 
8258  va_start(ap, result_fmt);
8259  n += json_emit_va(buf + n, len - n, result_fmt, ap);
8260  va_end(ap);
8261 
8262  n += json_emit(buf + n, len - n, "}");
8263 
8264  return n;
8265  }
8266 
8267  int mg_rpc_create_request(char *buf, int len, const char *method,
8268  const char *id, const char *params_fmt, ...) {
8269  va_list ap;
8270  int n = 0;
8271 
8272  n += json_emit(buf + n, len - n, "{s:s,s:s,s:s,s:", "jsonrpc", "2.0", "id",
8273  id, "method", method, "params");
8274  va_start(ap, params_fmt);
8275  n += json_emit_va(buf + n, len - n, params_fmt, ap);
8276  va_end(ap);
8277 
8278  n += json_emit(buf + n, len - n, "}");
8279 
8280  return n;
8281  }
8282 
8283  int mg_rpc_create_error(char *buf, int len, struct mg_rpc_request *req,
8284  int code, const char *message, const char *fmt, ...) {
8285  va_list ap;
8286  int n = 0;
8287 
8288  n += json_emit(buf + n, len - n, "{s:s,s:V,s:{s:i,s:s,s:", "jsonrpc", "2.0",
8289  "id", req->id == NULL ? "null" : req->id->ptr,
8290  req->id == NULL ? 4 : req->id->len, "error", "code",
8291  (long) code, "message", message, "data");
8292  va_start(ap, fmt);
8293  n += json_emit_va(buf + n, len - n, fmt, ap);
8294  va_end(ap);
8295 
8296  n += json_emit(buf + n, len - n, "}}");
8297 
8298  return n;
8299  }
8300 
8301  int mg_rpc_create_std_error(char *buf, int len, struct mg_rpc_request *req,
8302  int code) {
8303  const char *message = NULL;
8304 
8305  switch (code) {
8306  case JSON_RPC_PARSE_ERROR:
8307  message = "parse error";
8308  break;
8310  message = "invalid request";
8311  break;
8313  message = "method not found";
8314  break;
8316  message = "invalid parameters";
8317  break;
8318  case JSON_RPC_SERVER_ERROR:
8319  message = "server error";
8320  break;
8321  default:
8322  message = "unspecified error";
8323  break;
8324  }
8325 
8326  return mg_rpc_create_error(buf, len, req, code, message, "N");
8327  }
8328 
8329  int mg_rpc_dispatch(const char *buf, int len, char *dst, int dst_len,
8330  const char **methods, mg_rpc_handler_t *handlers) {
8331  struct json_token tokens[200];
8332  struct mg_rpc_request req;
8333  int i, n;
8334 
8335  memset(&req, 0, sizeof(req));
8336  n = parse_json(buf, len, tokens, sizeof(tokens) / sizeof(tokens[0]));
8337  if (n <= 0) {
8338  int err_code = (n == JSON_STRING_INVALID) ? JSON_RPC_PARSE_ERROR
8340  return mg_rpc_create_std_error(dst, dst_len, &req, err_code);
8341  }
8342 
8343  req.message = tokens;
8344  req.id = find_json_token(tokens, "id");
8345  req.method = find_json_token(tokens, "method");
8346  req.params = find_json_token(tokens, "params");
8347 
8348  if (req.id == NULL || req.method == NULL) {
8349  return mg_rpc_create_std_error(dst, dst_len, &req,
8351  }
8352 
8353  for (i = 0; methods[i] != NULL; i++) {
8354  int mlen = strlen(methods[i]);
8355  if (mlen == req.method->len &&
8356  memcmp(methods[i], req.method->ptr, mlen) == 0)
8357  break;
8358  }
8359 
8360  if (methods[i] == NULL) {
8361  return mg_rpc_create_std_error(dst, dst_len, &req,
8363  }
8364 
8365  return handlers[i](dst, dst_len, &req);
8366  }
8367 
8368  int mg_rpc_parse_reply(const char *buf, int len, struct json_token *toks,
8369  int max_toks, struct mg_rpc_reply *rep,
8370  struct mg_rpc_error *er) {
8371  int n = parse_json(buf, len, toks, max_toks);
8372 
8373  memset(rep, 0, sizeof(*rep));
8374  memset(er, 0, sizeof(*er));
8375 
8376  if (n > 0) {
8377  if ((rep->result = find_json_token(toks, "result")) != NULL) {
8378  rep->message = toks;
8379  rep->id = find_json_token(toks, "id");
8380  } else {
8381  er->message = toks;
8382  er->id = find_json_token(toks, "id");
8383  er->error_code = find_json_token(toks, "error.code");
8384  er->error_message = find_json_token(toks, "error.message");
8385  er->error_data = find_json_token(toks, "error.data");
8386  }
8387  }
8388  return n;
8389  }
8390 
8391 #endif /* MG_DISABLE_JSON_RPC */
8392 #ifdef MG_MODULE_LINES
8393 #line 1 "./src/mqtt.c"
8394 #endif
8395  /*
8396  * Copyright (c) 2014 Cesanta Software Limited
8397  * All rights reserved
8398  */
8399 
8400 #ifndef MG_DISABLE_MQTT
8401 
8402 #include <string.h>
8403 
8404  /* Amalgamated: #include "mongoose/src/internal.h" */
8405  /* Amalgamated: #include "mongoose/src/mqtt.h" */
8406 
8407  MG_INTERNAL int parse_mqtt(struct mbuf *io, struct mg_mqtt_message *mm) {
8408  uint8_t header;
8409  int cmd;
8410  size_t len = 0;
8411  int var_len = 0;
8412  char *vlen = &io->buf[1];
8413 
8414  if (io->len < 2) return -1;
8415 
8416  header = io->buf[0];
8417  cmd = header >> 4;
8418 
8419  /* decode mqtt variable length */
8420  do {
8421  len += (*vlen & 127) << 7 * (vlen - &io->buf[1]);
8422  } while ((*vlen++ & 128) != 0 && ((size_t)(vlen - io->buf) <= io->len));
8423 
8424  if (len != 0 && io->len < (size_t)(len - 1)) return -1;
8425 
8426  mbuf_remove(io, 1 + (vlen - &io->buf[1]));
8427  mm->cmd = cmd;
8428  mm->qos = MG_MQTT_GET_QOS(header);
8429 
8430  switch (cmd) {
8431  case MG_MQTT_CMD_CONNECT:
8432  /* TODO(mkm): parse keepalive and will */
8433  break;
8434  case MG_MQTT_CMD_CONNACK:
8435  mm->connack_ret_code = io->buf[1];
8436  var_len = 2;
8437  break;
8438  case MG_MQTT_CMD_PUBACK:
8439  case MG_MQTT_CMD_PUBREC:
8440  case MG_MQTT_CMD_PUBREL:
8441  case MG_MQTT_CMD_PUBCOMP:
8442  case MG_MQTT_CMD_SUBACK:
8443  mm->message_id = ntohs(*(uint16_t *) io->buf);
8444  var_len = 2;
8445  break;
8446  case MG_MQTT_CMD_PUBLISH: {
8447  uint16_t topic_len = ntohs(*(uint16_t *) io->buf);
8448  mm->topic = (char *) MG_MALLOC(topic_len + 1);
8449  mm->topic[topic_len] = 0;
8450  strncpy(mm->topic, io->buf + 2, topic_len);
8451  var_len = topic_len + 2;
8452 
8453  if (MG_MQTT_GET_QOS(header) > 0) {
8454  mm->message_id = ntohs(*(uint16_t *) io->buf);
8455  var_len += 2;
8456  }
8457  } break;
8458  case MG_MQTT_CMD_SUBSCRIBE:
8459  /*
8460  * topic expressions are left in the payload and can be parsed with
8461  * `mg_mqtt_next_subscribe_topic`
8462  */
8463  mm->message_id = ntohs(*(uint16_t *) io->buf);
8464  var_len = 2;
8465  break;
8466  default:
8467  /* Unhandled command */
8468  break;
8469  }
8470 
8471  mbuf_remove(io, var_len);
8472  return len - var_len;
8473  }
8474 
8475  static void mqtt_handler(struct mg_connection *nc, int ev, void *ev_data) {
8476  int len;
8477  struct mbuf *io = &nc->recv_mbuf;
8478  struct mg_mqtt_message mm;
8479  memset(&mm, 0, sizeof(mm));
8480 
8481  nc->handler(nc, ev, ev_data);
8482 
8483  switch (ev) {
8484  case MG_EV_RECV:
8485  len = parse_mqtt(io, &mm);
8486  if (len == -1) break; /* not fully buffered */
8487  mm.payload.p = io->buf;
8488  mm.payload.len = len;
8489 
8490  nc->handler(nc, MG_MQTT_EVENT_BASE + mm.cmd, &mm);
8491 
8492  if (mm.topic) {
8493  MG_FREE(mm.topic);
8494  }
8495  mbuf_remove(io, mm.payload.len);
8496  break;
8497  }
8498  }
8499 
8502  }
8503 
8504  void mg_send_mqtt_handshake(struct mg_connection *nc, const char *client_id) {
8505  static struct mg_send_mqtt_handshake_opts opts;
8506  mg_send_mqtt_handshake_opt(nc, client_id, opts);
8507  }
8508 
8509  void mg_send_mqtt_handshake_opt(struct mg_connection *nc, const char *client_id,
8510  struct mg_send_mqtt_handshake_opts opts) {
8511  uint8_t header = MG_MQTT_CMD_CONNECT << 4;
8512  uint8_t rem_len;
8513  uint16_t keep_alive;
8514  uint16_t len;
8515 
8516  /*
8517  * 9: version_header(len, magic_string, version_number), 1: flags, 2:
8518  * keep-alive timer,
8519  * 2: client_identifier_len, n: client_id
8520  */
8521  rem_len = 9 + 1 + 2 + 2 + strlen(client_id);
8522 
8523  if (opts.user_name != NULL) {
8524  opts.flags |= MG_MQTT_HAS_USER_NAME;
8525  rem_len += strlen(opts.user_name) + 2;
8526  }
8527  if (opts.password != NULL) {
8528  opts.flags |= MG_MQTT_HAS_PASSWORD;
8529  rem_len += strlen(opts.password) + 2;
8530  }
8531 
8532  mg_send(nc, &header, 1);
8533  mg_send(nc, &rem_len, 1);
8534  mg_send(nc, "\00\06MQIsdp\03", 9);
8535  mg_send(nc, &opts.flags, 1);
8536 
8537  if (opts.keep_alive == 0) {
8538  opts.keep_alive = 60;
8539  }
8540  keep_alive = htons(opts.keep_alive);
8541  mg_send(nc, &keep_alive, 2);
8542 
8543  len = htons(strlen(client_id));
8544  mg_send(nc, &len, 2);
8545  mg_send(nc, client_id, strlen(client_id));
8546 
8547  if (opts.flags & MG_MQTT_HAS_USER_NAME) {
8548  len = htons(strlen(opts.user_name));
8549  mg_send(nc, &len, 2);
8550  mg_send(nc, opts.user_name, strlen(opts.user_name));
8551  }
8552  if (opts.flags & MG_MQTT_HAS_PASSWORD) {
8553  len = htons(strlen(opts.password));
8554  mg_send(nc, &len, 2);
8555  mg_send(nc, opts.password, strlen(opts.password));
8556  }
8557  }
8558 
8559  static void mg_mqtt_prepend_header(struct mg_connection *nc, uint8_t cmd,
8560  uint8_t flags, size_t len) {
8561  size_t off = nc->send_mbuf.len - len;
8562  uint8_t header = cmd << 4 | (uint8_t) flags;
8563 
8564  uint8_t buf[1 + sizeof(size_t)];
8565  uint8_t *vlen = &buf[1];
8566 
8567  assert(nc->send_mbuf.len >= len);
8568 
8569  buf[0] = header;
8570 
8571  /* mqtt variable length encoding */
8572  do {
8573  *vlen = len % 0x80;
8574  len /= 0x80;
8575  if (len > 0) *vlen |= 0x80;
8576  vlen++;
8577  } while (len > 0);
8578 
8579  mbuf_insert(&nc->send_mbuf, off, buf, vlen - buf);
8580  }
8581 
8582  void mg_mqtt_publish(struct mg_connection *nc, const char *topic,
8583  uint16_t message_id, int flags, const void *data,
8584  size_t len) {
8585  size_t old_len = nc->send_mbuf.len;
8586 
8587  uint16_t topic_len = htons(strlen(topic));
8588  uint16_t message_id_net = htons(message_id);
8589 
8590  mg_send(nc, &topic_len, 2);
8591  mg_send(nc, topic, strlen(topic));
8592  if (MG_MQTT_GET_QOS(flags) > 0) {
8593  mg_send(nc, &message_id_net, 2);
8594  }
8595  mg_send(nc, data, len);
8596 
8598  nc->send_mbuf.len - old_len);
8599  }
8600 
8602  const struct mg_mqtt_topic_expression *topics,
8603  size_t topics_len, uint16_t message_id) {
8604  size_t old_len = nc->send_mbuf.len;
8605 
8606  uint16_t message_id_n = htons(message_id);
8607  size_t i;
8608 
8609  mg_send(nc, (char *) &message_id_n, 2);
8610  for (i = 0; i < topics_len; i++) {
8611  uint16_t topic_len_n = htons(strlen(topics[i].topic));
8612  mg_send(nc, &topic_len_n, 2);
8613  mg_send(nc, topics[i].topic, strlen(topics[i].topic));
8614  mg_send(nc, &topics[i].qos, 1);
8615  }
8616 
8618  nc->send_mbuf.len - old_len);
8619  }
8620 
8622  struct mg_str *topic, uint8_t *qos, int pos) {
8623  unsigned char *buf = (unsigned char *) msg->payload.p + pos;
8624  if ((size_t) pos >= msg->payload.len) {
8625  return -1;
8626  }
8627 
8628  topic->len = buf[0] << 8 | buf[1];
8629  topic->p = (char *) buf + 2;
8630  *qos = buf[2 + topic->len];
8631  return pos + 2 + topic->len + 1;
8632  }
8633 
8634  void mg_mqtt_unsubscribe(struct mg_connection *nc, char **topics,
8635  size_t topics_len, uint16_t message_id) {
8636  size_t old_len = nc->send_mbuf.len;
8637 
8638  uint16_t message_id_n = htons(message_id);
8639  size_t i;
8640 
8641  mg_send(nc, (char *) &message_id_n, 2);
8642  for (i = 0; i < topics_len; i++) {
8643  uint16_t topic_len_n = htons(strlen(topics[i]));
8644  mg_send(nc, &topic_len_n, 2);
8645  mg_send(nc, topics[i], strlen(topics[i]));
8646  }
8647 
8649  nc->send_mbuf.len - old_len);
8650  }
8651 
8652  void mg_mqtt_connack(struct mg_connection *nc, uint8_t return_code) {
8653  uint8_t unused = 0;
8654  mg_send(nc, &unused, 1);
8655  mg_send(nc, &return_code, 1);
8657  }
8658 
8659  /*
8660  * Sends a command which contains only a `message_id` and a QoS level of 1.
8661  *
8662  * Helper function.
8663  */
8664  static void mg_send_mqtt_short_command(struct mg_connection *nc, uint8_t cmd,
8665  uint16_t message_id) {
8666  uint16_t message_id_net = htons(message_id);
8667  mg_send(nc, &message_id_net, 2);
8668  mg_mqtt_prepend_header(nc, cmd, MG_MQTT_QOS(1), 2);
8669  }
8670 
8671  void mg_mqtt_puback(struct mg_connection *nc, uint16_t message_id) {
8673  }
8674 
8675  void mg_mqtt_pubrec(struct mg_connection *nc, uint16_t message_id) {
8677  }
8678 
8679  void mg_mqtt_pubrel(struct mg_connection *nc, uint16_t message_id) {
8681  }
8682 
8683  void mg_mqtt_pubcomp(struct mg_connection *nc, uint16_t message_id) {
8685  }
8686 
8687  void mg_mqtt_suback(struct mg_connection *nc, uint8_t *qoss, size_t qoss_len,
8688  uint16_t message_id) {
8689  size_t i;
8690  uint16_t message_id_net = htons(message_id);
8691  mg_send(nc, &message_id_net, 2);
8692  for (i = 0; i < qoss_len; i++) {
8693  mg_send(nc, &qoss[i], 1);
8694  }
8695  mg_mqtt_prepend_header(nc, MG_MQTT_CMD_SUBACK, MG_MQTT_QOS(1), 2 + qoss_len);
8696  }
8697 
8698  void mg_mqtt_unsuback(struct mg_connection *nc, uint16_t message_id) {
8700  }
8701 
8702  void mg_mqtt_ping(struct mg_connection *nc) {
8704  }
8705 
8706  void mg_mqtt_pong(struct mg_connection *nc) {
8708  }
8709 
8712  }
8713 
8714 #endif /* MG_DISABLE_MQTT */
8715 #ifdef MG_MODULE_LINES
8716 #line 1 "./src/mqtt-broker.c"
8717 #endif
8718  /*
8719  * Copyright (c) 2014 Cesanta Software Limited
8720  * All rights reserved
8721  */
8722 
8723  /* Amalgamated: #include "mongoose/src/internal.h" */
8724  /* Amalgamated: #include "mongoose/src/mqtt-broker.h" */
8725 
8726 #ifdef MG_ENABLE_MQTT_BROKER
8727 
8728  static void mg_mqtt_session_init(struct mg_mqtt_broker *brk,
8729  struct mg_mqtt_session *s,
8730  struct mg_connection *nc) {
8731  s->brk = brk;
8732  s->subscriptions = NULL;
8733  s->num_subscriptions = 0;
8734  s->nc = nc;
8735  }
8736 
8737  static void mg_mqtt_add_session(struct mg_mqtt_session *s) {
8738  s->next = s->brk->sessions;
8739  s->brk->sessions = s;
8740  s->prev = NULL;
8741  if (s->next != NULL) s->next->prev = s;
8742  }
8743 
8744  static void mg_mqtt_remove_session(struct mg_mqtt_session *s) {
8745  if (s->prev == NULL) s->brk->sessions = s->next;
8746  if (s->prev) s->prev->next = s->next;
8747  if (s->next) s->next->prev = s->prev;
8748  }
8749 
8750  static void mg_mqtt_destroy_session(struct mg_mqtt_session *s) {
8751  size_t i;
8752  for (i = 0; i < s->num_subscriptions; i++) {
8753  MG_FREE((void *) s->subscriptions[i].topic);
8754  }
8755  MG_FREE(s->subscriptions);
8756  MG_FREE(s);
8757  }
8758 
8759  static void mg_mqtt_close_session(struct mg_mqtt_session *s) {
8760  mg_mqtt_remove_session(s);
8761  mg_mqtt_destroy_session(s);
8762  }
8763 
8764  void mg_mqtt_broker_init(struct mg_mqtt_broker *brk, void *user_data) {
8765  brk->sessions = NULL;
8766  brk->user_data = user_data;
8767  }
8768 
8769  static void mg_mqtt_broker_handle_connect(struct mg_mqtt_broker *brk,
8770  struct mg_connection *nc) {
8771  struct mg_mqtt_session *s = (struct mg_mqtt_session *) malloc(sizeof *s);
8772  if (s == NULL) {
8773  /* LCOV_EXCL_START */
8775  return;
8776  /* LCOV_EXCL_STOP */
8777  }
8778 
8779  /* TODO(mkm): check header (magic and version) */
8780 
8781  mg_mqtt_session_init(brk, s, nc);
8782  s->user_data = nc->user_data;
8783  nc->user_data = s;
8784  mg_mqtt_add_session(s);
8785 
8787  }
8788 
8789  static void mg_mqtt_broker_handle_subscribe(struct mg_connection *nc,
8790  struct mg_mqtt_message *msg) {
8791  struct mg_mqtt_session *ss = (struct mg_mqtt_session *) nc->user_data;
8792  uint8_t qoss[512];
8793  size_t qoss_len = 0;
8794  struct mg_str topic;
8795  uint8_t qos;
8796  int pos;
8797  struct mg_mqtt_topic_expression *te;
8798 
8799  for (pos = 0;
8800  (pos = mg_mqtt_next_subscribe_topic(msg, &topic, &qos, pos)) != -1;) {
8801  qoss[qoss_len++] = qos;
8802  }
8803 
8804  ss->subscriptions = (struct mg_mqtt_topic_expression *) realloc(
8805  ss->subscriptions, sizeof(*ss->subscriptions) * qoss_len);
8806  for (pos = 0;
8807  (pos = mg_mqtt_next_subscribe_topic(msg, &topic, &qos, pos)) != -1;
8808  ss->num_subscriptions++) {
8809  te = &ss->subscriptions[ss->num_subscriptions];
8810  te->topic = (char *) malloc(topic.len + 1);
8811  te->qos = qos;
8812  strncpy((char *) te->topic, topic.p, topic.len + 1);
8813  }
8814 
8815  mg_mqtt_suback(nc, qoss, qoss_len, msg->message_id);
8816  }
8817 
8818  /*
8819  * Matches a topic against a topic expression
8820  *
8821  * See http://goo.gl/iWk21X
8822  *
8823  * Returns 1 if it matches; 0 otherwise.
8824  */
8825  static int mg_mqtt_match_topic_expression(const char *exp, const char *topic) {
8826  /* TODO(mkm): implement real matching */
8827  int len = strlen(exp);
8828  if (strchr(exp, '#')) {
8829  len -= 2;
8830  }
8831  return strncmp(exp, topic, len) == 0;
8832  }
8833 
8834  static void mg_mqtt_broker_handle_publish(struct mg_mqtt_broker *brk,
8835  struct mg_mqtt_message *msg) {
8836  struct mg_mqtt_session *s;
8837  size_t i;
8838 
8839  for (s = mg_mqtt_next(brk, NULL); s != NULL; s = mg_mqtt_next(brk, s)) {
8840  for (i = 0; i < s->num_subscriptions; i++) {
8841  if (mg_mqtt_match_topic_expression(s->subscriptions[i].topic,
8842  msg->topic)) {
8843  mg_mqtt_publish(s->nc, msg->topic, 0, 0, msg->payload.p,
8844  msg->payload.len);
8845  break;
8846  }
8847  }
8848  }
8849  }
8850 
8851  void mg_mqtt_broker(struct mg_connection *nc, int ev, void *data) {
8852  struct mg_mqtt_message *msg = (struct mg_mqtt_message *) data;
8853  struct mg_mqtt_broker *brk;
8854 
8855  if (nc->listener) {
8856  brk = (struct mg_mqtt_broker *) nc->listener->user_data;
8857  } else {
8858  brk = (struct mg_mqtt_broker *) nc->user_data;
8859  }
8860 
8861  switch (ev) {
8862  case MG_EV_ACCEPT:
8864  break;
8865  case MG_EV_MQTT_CONNECT:
8866  mg_mqtt_broker_handle_connect(brk, nc);
8867  break;
8868  case MG_EV_MQTT_SUBSCRIBE:
8869  mg_mqtt_broker_handle_subscribe(nc, msg);
8870  break;
8871  case MG_EV_MQTT_PUBLISH:
8872  mg_mqtt_broker_handle_publish(brk, msg);
8873  break;
8874  case MG_EV_CLOSE:
8875  if (nc->listener) {
8876  mg_mqtt_close_session((struct mg_mqtt_session *) nc->user_data);
8877  }
8878  break;
8879  }
8880  }
8881 
8882  struct mg_mqtt_session *mg_mqtt_next(struct mg_mqtt_broker *brk,
8883  struct mg_mqtt_session *s) {
8884  return s == NULL ? brk->sessions : s->next;
8885  }
8886 
8887 #endif /* MG_ENABLE_MQTT_BROKER */
8888 #ifdef MG_MODULE_LINES
8889 #line 1 "./src/dns.c"
8890 #endif
8891  /*
8892  * Copyright (c) 2014 Cesanta Software Limited
8893  * All rights reserved
8894  */
8895 
8896 #ifndef MG_DISABLE_DNS
8897 
8898  /* Amalgamated: #include "mongoose/src/internal.h" */
8899  /* Amalgamated: #include "mongoose/src/dns.h" */
8900 
8901  static int mg_dns_tid = 0xa0;
8902 
8903  struct mg_dns_header {
8904  uint16_t transaction_id;
8905  uint16_t flags;
8906  uint16_t num_questions;
8907  uint16_t num_answers;
8909  uint16_t num_other_prs;
8910  };
8911 
8913  struct mg_dns_message *msg, int query,
8914  struct mg_dns_resource_record *prev) {
8915  struct mg_dns_resource_record *rr;
8916 
8917  for (rr = (prev == NULL ? msg->answers : prev + 1);
8918  rr - msg->answers < msg->num_answers; rr++) {
8919  if (rr->rtype == query) {
8920  return rr;
8921  }
8922  }
8923  return NULL;
8924  }
8925 
8927  struct mg_dns_resource_record *rr, void *data,
8928  size_t data_len) {
8929  switch (rr->rtype) {
8930  case MG_DNS_A_RECORD:
8931  if (data_len < sizeof(struct in_addr)) {
8932  return -1;
8933  }
8934  if (rr->rdata.p + data_len > msg->pkt.p + msg->pkt.len) {
8935  return -1;
8936  }
8937  memcpy(data, rr->rdata.p, data_len);
8938  return 0;
8939 #ifdef MG_ENABLE_IPV6
8940  case MG_DNS_AAAA_RECORD:
8941  if (data_len < sizeof(struct in6_addr)) {
8942  return -1; /* LCOV_EXCL_LINE */
8943  }
8944  memcpy(data, rr->rdata.p, data_len);
8945  return 0;
8946 #endif
8947  case MG_DNS_CNAME_RECORD:
8948  mg_dns_uncompress_name(msg, &rr->rdata, (char *) data, data_len);
8949  return 0;
8950  }
8951 
8952  return -1;
8953  }
8954 
8955  int mg_dns_insert_header(struct mbuf *io, size_t pos,
8956  struct mg_dns_message *msg) {
8957  struct mg_dns_header header;
8958 
8959  memset(&header, 0, sizeof(header));
8960  header.transaction_id = msg->transaction_id;
8961  header.flags = htons(msg->flags);
8962  header.num_questions = htons(msg->num_questions);
8963  header.num_answers = htons(msg->num_answers);
8964 
8965  return mbuf_insert(io, pos, &header, sizeof(header));
8966  }
8967 
8968  int mg_dns_copy_questions(struct mbuf *io, struct mg_dns_message *msg) {
8969  unsigned char *begin, *end;
8970  struct mg_dns_resource_record *last_q;
8971  if (msg->num_questions <= 0) return 0;
8972  begin = (unsigned char *) msg->pkt.p + sizeof(struct mg_dns_header);
8973  last_q = &msg->questions[msg->num_questions - 1];
8974  end = (unsigned char *) last_q->name.p + last_q->name.len + 4;
8975  return mbuf_append(io, begin, end - begin);
8976  }
8977 
8978  static int mg_dns_encode_name(struct mbuf *io, const char *name, size_t len) {
8979  const char *s;
8980  unsigned char n;
8981  size_t pos = io->len;
8982 
8983  do {
8984  if ((s = strchr(name, '.')) == NULL) {
8985  s = name + len;
8986  }
8987 
8988  if (s - name > 127) {
8989  return -1; /* TODO(mkm) cover */
8990  }
8991  n = s - name; /* chunk length */
8992  mbuf_append(io, &n, 1); /* send length */
8993  mbuf_append(io, name, n);
8994 
8995  if (*s == '.') {
8996  n++;
8997  }
8998 
8999  name += n;
9000  len -= n;
9001  } while (*s != '\0');
9002  mbuf_append(io, "\0", 1); /* Mark end of host name */
9003 
9004  return io->len - pos;
9005  }
9006 
9008  const char *name, size_t nlen, const void *rdata,
9009  size_t rlen) {
9010  size_t pos = io->len;
9011  uint16_t u16;
9012  uint32_t u32;
9013 
9014  if (rr->kind == MG_DNS_INVALID_RECORD) {
9015  return -1; /* LCOV_EXCL_LINE */
9016  }
9017 
9018  if (mg_dns_encode_name(io, name, nlen) == -1) {
9019  return -1;
9020  }
9021 
9022  u16 = htons(rr->rtype);
9023  mbuf_append(io, &u16, 2);
9024  u16 = htons(rr->rclass);
9025  mbuf_append(io, &u16, 2);
9026 
9027  if (rr->kind == MG_DNS_ANSWER) {
9028  u32 = htonl(rr->ttl);
9029  mbuf_append(io, &u32, 4);
9030 
9031  if (rr->rtype == MG_DNS_CNAME_RECORD) {
9032  int clen;
9033  /* fill size after encoding */
9034  size_t off = io->len;
9035  mbuf_append(io, &u16, 2);
9036  if ((clen = mg_dns_encode_name(io, (const char *) rdata, rlen)) == -1) {
9037  return -1;
9038  }
9039  u16 = clen;
9040  io->buf[off] = u16 >> 8;
9041  io->buf[off + 1] = u16 & 0xff;
9042  } else {
9043  u16 = htons(rlen);
9044  mbuf_append(io, &u16, 2);
9045  mbuf_append(io, rdata, rlen);
9046  }
9047  }
9048 
9049  return io->len - pos;
9050  }
9051 
9052  void mg_send_dns_query(struct mg_connection *nc, const char *name,
9053  int query_type) {
9054  struct mg_dns_message *msg =
9055  (struct mg_dns_message *) MG_CALLOC(1, sizeof(*msg));
9056  struct mbuf pkt;
9057  struct mg_dns_resource_record *rr = &msg->questions[0];
9058 
9059  DBG(("%s %d", name, query_type));
9060 
9061  mbuf_init(&pkt, 64 /* Start small, it'll grow as needed. */);
9062 
9063  msg->transaction_id = ++mg_dns_tid;
9064  msg->flags = 0x100;
9065  msg->num_questions = 1;
9066 
9067  mg_dns_insert_header(&pkt, 0, msg);
9068 
9069  rr->rtype = query_type;
9070  rr->rclass = 1; /* Class: inet */
9071  rr->kind = MG_DNS_QUESTION;
9072 
9073  if (mg_dns_encode_record(&pkt, rr, name, strlen(name), NULL, 0) == -1) {
9074  /* TODO(mkm): return an error code */
9075  goto cleanup; /* LCOV_EXCL_LINE */
9076  }
9077 
9078  /* TCP DNS requires messages to be prefixed with len */
9079  if (!(nc->flags & MG_F_UDP)) {
9080  uint16_t len = htons(pkt.len);
9081  mbuf_insert(&pkt, 0, &len, 2);
9082  }
9083 
9084  mg_send(nc, pkt.buf, pkt.len);
9085  mbuf_free(&pkt);
9086 
9087  cleanup:
9088  MG_FREE(msg);
9089  }
9090 
9091  static unsigned char *mg_parse_dns_resource_record(
9092  unsigned char *data, unsigned char *end, struct mg_dns_resource_record *rr,
9093  int reply) {
9094  unsigned char *name = data;
9095  int chunk_len, data_len;
9096 
9097  while (data < end && (chunk_len = *data)) {
9098  if (((unsigned char *) data)[0] & 0xc0) {
9099  data += 1;
9100  break;
9101  }
9102  data += chunk_len + 1;
9103  }
9104 
9105  if (data > end - 5) {
9106  return NULL;
9107  }
9108 
9109  rr->name.p = (char *) name;
9110  rr->name.len = data - name + 1;
9111  data++;
9112 
9113  rr->rtype = data[0] << 8 | data[1];
9114  data += 2;
9115 
9116  rr->rclass = data[0] << 8 | data[1];
9117  data += 2;
9118 
9119  rr->kind = reply ? MG_DNS_ANSWER : MG_DNS_QUESTION;
9120  if (reply) {
9121  if (data >= end - 6) {
9122  return NULL;
9123  }
9124 
9125  rr->ttl = (uint32_t) data[0] << 24 | (uint32_t) data[1] << 16 |
9126  data[2] << 8 | data[3];
9127  data += 4;
9128 
9129  data_len = *data << 8 | *(data + 1);
9130  data += 2;
9131 
9132  rr->rdata.p = (char *) data;
9133  rr->rdata.len = data_len;
9134  data += data_len;
9135  }
9136  return data;
9137  }
9138 
9139  int mg_parse_dns(const char *buf, int len, struct mg_dns_message *msg) {
9140  struct mg_dns_header *header = (struct mg_dns_header *) buf;
9141  unsigned char *data = (unsigned char *) buf + sizeof(*header);
9142  unsigned char *end = (unsigned char *) buf + len;
9143  int i;
9144 
9145  memset(msg, 0, sizeof(*msg));
9146  msg->pkt.p = buf;
9147  msg->pkt.len = len;
9148 
9149  if (len < (int) sizeof(*header)) return -1;
9150 
9151  msg->transaction_id = header->transaction_id;
9152  msg->flags = ntohs(header->flags);
9153  msg->num_questions = ntohs(header->num_questions);
9154  if (msg->num_questions > (int) ARRAY_SIZE(msg->questions)) {
9155  msg->num_questions = (int) ARRAY_SIZE(msg->questions);
9156  }
9157  msg->num_answers = ntohs(header->num_answers);
9158  if (msg->num_answers > (int) ARRAY_SIZE(msg->answers)) {
9159  msg->num_answers = (int) ARRAY_SIZE(msg->answers);
9160  }
9161 
9162  for (i = 0; i < msg->num_questions; i++) {
9163  data = mg_parse_dns_resource_record(data, end, &msg->questions[i], 0);
9164  if (data == NULL) return -1;
9165  }
9166 
9167  for (i = 0; i < msg->num_answers; i++) {
9168  data = mg_parse_dns_resource_record(data, end, &msg->answers[i], 1);
9169  if (data == NULL) return -1;
9170  }
9171 
9172  return 0;
9173  }
9174 
9175  size_t mg_dns_uncompress_name(struct mg_dns_message *msg, struct mg_str *name,
9176  char *dst, int dst_len) {
9177  int chunk_len;
9178  char *old_dst = dst;
9179  const unsigned char *data = (unsigned char *) name->p;
9180  const unsigned char *end = (unsigned char *) msg->pkt.p + msg->pkt.len;
9181 
9182  if (data >= end) {
9183  return 0;
9184  }
9185 
9186  while ((chunk_len = *data++)) {
9187  int leeway = dst_len - (dst - old_dst);
9188  if (data >= end) {
9189  return 0;
9190  }
9191 
9192  if (chunk_len & 0xc0) {
9193  uint16_t off = (data[-1] & (~0xc0)) << 8 | data[0];
9194  if (off >= msg->pkt.len) {
9195  return 0;
9196  }
9197  data = (unsigned char *) msg->pkt.p + off;
9198  continue;
9199  }
9200  if (chunk_len > leeway) {
9201  chunk_len = leeway;
9202  }
9203 
9204  if (data + chunk_len >= end) {
9205  return 0;
9206  }
9207 
9208  memcpy(dst, data, chunk_len);
9209  data += chunk_len;
9210  dst += chunk_len;
9211  leeway -= chunk_len;
9212  if (leeway == 0) {
9213  return dst - old_dst;
9214  }
9215  *dst++ = '.';
9216  }
9217 
9218  if (dst != old_dst) {
9219  *--dst = 0;
9220  }
9221  return dst - old_dst;
9222  }
9223 
9224  static void dns_handler(struct mg_connection *nc, int ev, void *ev_data) {
9225  struct mbuf *io = &nc->recv_mbuf;
9226  struct mg_dns_message msg;
9227 
9228  /* Pass low-level events to the user handler */
9229  nc->handler(nc, ev, ev_data);
9230 
9231  switch (ev) {
9232  case MG_EV_RECV:
9233  if (!(nc->flags & MG_F_UDP)) {
9234  mbuf_remove(&nc->recv_mbuf, 2);
9235  }
9236  if (mg_parse_dns(nc->recv_mbuf.buf, nc->recv_mbuf.len, &msg) == -1) {
9237  /* reply + recursion allowed + format error */
9238  memset(&msg, 0, sizeof(msg));
9239  msg.flags = 0x8081;
9240  mg_dns_insert_header(io, 0, &msg);
9241  if (!(nc->flags & MG_F_UDP)) {
9242  uint16_t len = htons(io->len);
9243  mbuf_insert(io, 0, &len, 2);
9244  }
9245  mg_send(nc, io->buf, io->len);
9246  } else {
9247  /* Call user handler with parsed message */
9248  nc->handler(nc, MG_DNS_MESSAGE, &msg);
9249  }
9250  mbuf_remove(io, io->len);
9251  break;
9252  }
9253  }
9254 
9256  nc->proto_handler = dns_handler;
9257  }
9258 
9259 #endif /* MG_DISABLE_DNS */
9260 #ifdef MG_MODULE_LINES
9261 #line 1 "./src/dns-server.c"
9262 #endif
9263  /*
9264  * Copyright (c) 2014 Cesanta Software Limited
9265  * All rights reserved
9266  */
9267 
9268 #ifdef MG_ENABLE_DNS_SERVER
9269 
9270  /* Amalgamated: #include "mongoose/src/internal.h" */
9271  /* Amalgamated: #include "mongoose/src/dns-server.h" */
9272 
9273  struct mg_dns_reply mg_dns_create_reply(struct mbuf *io,
9274  struct mg_dns_message *msg) {
9275  struct mg_dns_reply rep;
9276  rep.msg = msg;
9277  rep.io = io;
9278  rep.start = io->len;
9279 
9280  /* reply + recursion allowed */
9281  msg->flags |= 0x8080;
9282  mg_dns_copy_questions(io, msg);
9283 
9284  msg->num_answers = 0;
9285  return rep;
9286  }
9287 
9288  void mg_dns_send_reply(struct mg_connection *nc, struct mg_dns_reply *r) {
9289  size_t sent = r->io->len - r->start;
9290  mg_dns_insert_header(r->io, r->start, r->msg);
9291  if (!(nc->flags & MG_F_UDP)) {
9292  uint16_t len = htons(sent);
9293  mbuf_insert(r->io, r->start, &len, 2);
9294  }
9295 
9296  if (&nc->send_mbuf != r->io) {
9297  mg_send(nc, r->io->buf + r->start, r->io->len - r->start);
9298  r->io->len = r->start;
9299  }
9300  }
9301 
9302  int mg_dns_reply_record(struct mg_dns_reply *reply,
9303  struct mg_dns_resource_record *question,
9304  const char *name, int rtype, int ttl, const void *rdata,
9305  size_t rdata_len) {
9306  struct mg_dns_message *msg = (struct mg_dns_message *) reply->msg;
9307  char rname[512];
9308  struct mg_dns_resource_record *ans = &msg->answers[msg->num_answers];
9309  if (msg->num_answers >= MG_MAX_DNS_ANSWERS) {
9310  return -1; /* LCOV_EXCL_LINE */
9311  }
9312 
9313  if (name == NULL) {
9314  name = rname;
9315  rname[511] = 0;
9316  mg_dns_uncompress_name(msg, &question->name, rname, sizeof(rname) - 1);
9317  }
9318 
9319  *ans = *question;
9320  ans->kind = MG_DNS_ANSWER;
9321  ans->rtype = rtype;
9322  ans->ttl = ttl;
9323 
9324  if (mg_dns_encode_record(reply->io, ans, name, strlen(name), rdata,
9325  rdata_len) == -1) {
9326  return -1; /* LCOV_EXCL_LINE */
9327  };
9328 
9329  msg->num_answers++;
9330  return 0;
9331  }
9332 
9333 #endif /* MG_ENABLE_DNS_SERVER */
9334 #ifdef MG_MODULE_LINES
9335 #line 1 "./src/resolv.c"
9336 #endif
9337  /*
9338  * Copyright (c) 2014 Cesanta Software Limited
9339  * All rights reserved
9340  */
9341 
9342 #ifndef MG_DISABLE_RESOLVER
9343 
9344  /* Amalgamated: #include "mongoose/src/internal.h" */
9345  /* Amalgamated: #include "mongoose/src/resolv.h" */
9346 
9347 #ifndef MG_DEFAULT_NAMESERVER
9348 #define MG_DEFAULT_NAMESERVER "8.8.8.8"
9349 #endif
9350 
9351  static const char *mg_default_dns_server = "udp://" MG_DEFAULT_NAMESERVER ":53";
9352 
9354 
9356  char name[1024];
9357  int query;
9359  void *data;
9360  time_t timeout;
9363 
9364  /* state */
9365  time_t last_time;
9366  int retries;
9367  };
9368 
9369  /*
9370  * Find what nameserver to use.
9371  *
9372  * Return 0 if OK, -1 if error
9373  */
9374  static int mg_get_ip_address_of_nameserver(char *name, size_t name_len) {
9375  int ret = -1;
9376 
9377 #ifdef _WIN32
9378  int i;
9379  LONG err;
9380  HKEY hKey, hSub;
9381  char subkey[512], value[128],
9382  *key = "SYSTEM\\ControlSet001\\Services\\Tcpip\\Parameters\\Interfaces";
9383 
9384  if ((err = RegOpenKeyA(HKEY_LOCAL_MACHINE, key, &hKey)) != ERROR_SUCCESS) {
9385  fprintf(stderr, "cannot open reg key %s: %d\n", key, err);
9386  ret = -1;
9387  } else {
9388  for (ret = -1, i = 0;
9389  RegEnumKeyA(hKey, i, subkey, sizeof(subkey)) == ERROR_SUCCESS; i++) {
9390  DWORD type, len = sizeof(value);
9391  if (RegOpenKeyA(hKey, subkey, &hSub) == ERROR_SUCCESS &&
9392  (RegQueryValueExA(hSub, "NameServer", 0, &type, (void *) value,
9393  &len) == ERROR_SUCCESS ||
9394  RegQueryValueExA(hSub, "DhcpNameServer", 0, &type, (void *) value,
9395  &len) == ERROR_SUCCESS)) {
9396  /*
9397  * See https://github.com/cesanta/mongoose/issues/176
9398  * The value taken from the registry can be empty, a single
9399  * IP address, or multiple IP addresses separated by comma.
9400  * If it's empty, check the next interface.
9401  * If it's multiple IP addresses, take the first one.
9402  */
9403  char *comma = strchr(value, ',');
9404  if (value[0] == '\0') {
9405  continue;
9406  }
9407  if (comma != NULL) {
9408  *comma = '\0';
9409  }
9410  snprintf(name, name_len, "udp://%s:53", value);
9411  ret = 0;
9412  RegCloseKey(hSub);
9413  break;
9414  }
9415  }
9416  RegCloseKey(hKey);
9417  }
9418 #elif !defined(MG_DISABLE_FILESYSTEM)
9419  FILE *fp;
9420  char line[512];
9421 
9422  if ((fp = fopen("/etc/resolv.conf", "r")) == NULL) {
9423  ret = -1;
9424  } else {
9425  /* Try to figure out what nameserver to use */
9426  for (ret = -1; fgets(line, sizeof(line), fp) != NULL;) {
9427  char buf[256];
9428  if (sscanf(line, "nameserver %255[^\n\t #]s", buf) == 1) {
9429  snprintf(name, name_len, "udp://%s:53", buf);
9430  ret = 0;
9431  break;
9432  }
9433  }
9434  (void) fclose(fp);
9435  }
9436 #else
9437  snprintf(name, name_len, "%s", mg_default_dns_server);
9438 #endif /* _WIN32 */
9439 
9440  return ret;
9441  }
9442 
9443  int mg_resolve_from_hosts_file(const char *name, union socket_address *usa) {
9444 #ifndef MG_DISABLE_FILESYSTEM
9445  /* TODO(mkm) cache /etc/hosts */
9446  FILE *fp;
9447  char line[1024];
9448  char *p;
9449  char alias[256];
9450  unsigned int a, b, c, d;
9451  int len = 0;
9452 
9453  if ((fp = fopen("/etc/hosts", "r")) == NULL) {
9454  return -1;
9455  }
9456 
9457  for (; fgets(line, sizeof(line), fp) != NULL;) {
9458  if (line[0] == '#') continue;
9459 
9460  if (sscanf(line, "%u.%u.%u.%u%n", &a, &b, &c, &d, &len) == 0) {
9461  /* TODO(mkm): handle ipv6 */
9462  continue;
9463  }
9464  for (p = line + len; sscanf(p, "%s%n", alias, &len) == 1; p += len) {
9465  if (strcmp(alias, name) == 0) {
9466  usa->sin.sin_addr.s_addr = htonl(a << 24 | b << 16 | c << 8 | d);
9467  fclose(fp);
9468  return 0;
9469  }
9470  }
9471  }
9472 
9473  fclose(fp);
9474 #endif
9475 
9476  return -1;
9477  }
9478 
9479  static void mg_resolve_async_eh(struct mg_connection *nc, int ev, void *data) {
9480  time_t now = time(NULL);
9481  struct mg_resolve_async_request *req;
9482  struct mg_dns_message *msg;
9483 
9484  DBG(("ev=%d user_data=%p", ev, nc->user_data));
9485 
9486  req = (struct mg_resolve_async_request *) nc->user_data;
9487 
9488  if (req == NULL) {
9489  return;
9490  }
9491 
9492  switch (ev) {
9493  case MG_EV_CONNECT:
9494  case MG_EV_POLL:
9495  if (req->retries > req->max_retries) {
9498  break;
9499  }
9500  if (now - req->last_time >= req->timeout) {
9501  mg_send_dns_query(nc, req->name, req->query);
9502  req->last_time = now;
9503  req->retries++;
9504  }
9505  break;
9506  case MG_EV_RECV:
9507  msg = (struct mg_dns_message *) MG_MALLOC(sizeof(*msg));
9508  if (mg_parse_dns(nc->recv_mbuf.buf, *(int *) data, msg) == 0 &&
9509  msg->num_answers > 0) {
9510  req->callback(msg, req->data, MG_RESOLVE_OK);
9511  nc->user_data = NULL;
9512  MG_FREE(req);
9513  } else {
9514  req->err = MG_RESOLVE_NO_ANSWERS;
9515  }
9516  MG_FREE(msg);
9518  break;
9519  case MG_EV_SEND:
9520  /*
9521  * If a send error occurs, prevent closing of the connection by the core.
9522  * We will retry after timeout.
9523  */
9524  nc->flags &= ~MG_F_CLOSE_IMMEDIATELY;
9525  mbuf_remove(&nc->send_mbuf, nc->send_mbuf.len);
9526  break;
9527  case MG_EV_TIMER:
9528  req->err = MG_RESOLVE_TIMEOUT;
9530  break;
9531  case MG_EV_CLOSE:
9532  /* If we got here with request still not done, fire an error callback. */
9533  if (req != NULL) {
9534  req->callback(NULL, req->data, req->err);
9535  nc->user_data = NULL;
9536  MG_FREE(req);
9537  }
9538  break;
9539  }
9540  }
9541 
9542  int mg_resolve_async(struct mg_mgr *mgr, const char *name, int query,
9543  mg_resolve_callback_t cb, void *data) {
9544  struct mg_resolve_async_opts opts;
9545  memset(&opts, 0, sizeof(opts));
9546  return mg_resolve_async_opt(mgr, name, query, cb, data, opts);
9547  }
9548 
9549  int mg_resolve_async_opt(struct mg_mgr *mgr, const char *name, int query,
9550  mg_resolve_callback_t cb, void *data,
9551  struct mg_resolve_async_opts opts) {
9552  struct mg_resolve_async_request *req;
9553  struct mg_connection *dns_nc;
9554  const char *nameserver = opts.nameserver_url;
9555 
9556  DBG(("%s %d %p", name, query, opts.dns_conn));
9557 
9558  /* resolve with DNS */
9559  req = (struct mg_resolve_async_request *) MG_CALLOC(1, sizeof(*req));
9560  if (req == NULL) {
9561  return -1;
9562  }
9563 
9564  strncpy(req->name, name, sizeof(req->name));
9565  req->query = query;
9566  req->callback = cb;
9567  req->data = data;
9568  /* TODO(mkm): parse defaults out of resolve.conf */
9569  req->max_retries = opts.max_retries ? opts.max_retries : 2;
9570  req->timeout = opts.timeout ? opts.timeout : 5;
9571 
9572  /* Lazily initialize dns server */
9573  if (nameserver == NULL && mg_dns_server[0] == '\0' &&
9574  mg_get_ip_address_of_nameserver(mg_dns_server, sizeof(mg_dns_server)-10) ==
9575  -1) {
9576  strncpy(mg_dns_server, mg_default_dns_server, sizeof(mg_dns_server));
9577  }
9578 
9579  if (nameserver == NULL) {
9580  nameserver = mg_dns_server;
9581  }
9582 
9583  dns_nc = mg_connect(mgr, nameserver, mg_resolve_async_eh);
9584  if (dns_nc == NULL) {
9585  free(req);
9586  return -1;
9587  }
9588  dns_nc->user_data = req;
9589  if (opts.dns_conn != NULL) {
9590  *opts.dns_conn = dns_nc;
9591  }
9592 
9593  return 0;
9594  }
9595 
9596 #endif /* MG_DISABLE_RESOLVE */
9597 #ifdef MG_MODULE_LINES
9598 #line 1 "./src/coap.c"
9599 #endif
9600  /*
9601  * Copyright (c) 2015 Cesanta Software Limited
9602  * All rights reserved
9603  * This software is dual-licensed: you can redistribute it and/or modify
9604  * it under the terms of the GNU General Public License version 2 as
9605  * published by the Free Software Foundation. For the terms of this
9606  * license, see <http://www.gnu.org/licenses/>.
9607  *
9608  * You are free to use this software under the terms of the GNU General
9609  * Public License, but WITHOUT ANY WARRANTY; without even the implied
9610  * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
9611  * See the GNU General Public License for more details.
9612  *
9613  * Alternatively, you can license this software under a commercial
9614  * license, as set out in <https://www.cesanta.com/license>.
9615  */
9616 
9617  /* Amalgamated: #include "mongoose/src/internal.h" */
9618  /* Amalgamated: #include "mongoose/src/coap.h" */
9619 
9620 #ifdef MG_ENABLE_COAP
9621 
9622  void mg_coap_free_options(struct mg_coap_message *cm) {
9623  while (cm->options != NULL) {
9624  struct mg_coap_option *next = cm->options->next;
9625  MG_FREE(cm->options);
9626  cm->options = next;
9627  }
9628  }
9629 
9630  struct mg_coap_option *mg_coap_add_option(struct mg_coap_message *cm,
9631  uint32_t number, char *value,
9632  size_t len) {
9633  struct mg_coap_option *new_option =
9634  (struct mg_coap_option *) MG_CALLOC(1, sizeof(*new_option));
9635 
9636  new_option->number = number;
9637  new_option->value.p = value;
9638  new_option->value.len = len;
9639 
9640  if (cm->options == NULL) {
9641  cm->options = cm->optiomg_tail = new_option;
9642  } else {
9643  /*
9644  * A very simple attention to help clients to compose options:
9645  * CoAP wants to see options ASC ordered.
9646  * Could be change by using sort in coap_compose
9647  */
9648  if (cm->optiomg_tail->number <= new_option->number) {
9649  /* if option is already ordered just add it */
9650  cm->optiomg_tail = cm->optiomg_tail->next = new_option;
9651  } else {
9652  /* looking for appropriate position */
9653  struct mg_coap_option *current_opt = cm->options;
9654  struct mg_coap_option *prev_opt = 0;
9655 
9656  while (current_opt != NULL) {
9657  if (current_opt->number > new_option->number) {
9658  break;
9659  }
9660  prev_opt = current_opt;
9661  current_opt = current_opt->next;
9662  }
9663 
9664  if (prev_opt != NULL) {
9665  prev_opt->next = new_option;
9666  new_option->next = current_opt;
9667  } else {
9668  /* insert new_option to the beginning */
9669  new_option->next = cm->options;
9670  cm->options = new_option;
9671  }
9672  }
9673  }
9674 
9675  return new_option;
9676  }
9677 
9678  /*
9679  * Fills CoAP header in mg_coap_message.
9680  *
9681  * Helper function.
9682  */
9683  static char *coap_parse_header(char *ptr, struct mbuf *io,
9684  struct mg_coap_message *cm) {
9685  if (io->len < sizeof(uint32_t)) {
9686  cm->flags |= MG_COAP_NOT_ENOUGH_DATA;
9687  return NULL;
9688  }
9689 
9690  /*
9691  * Version (Ver): 2-bit unsigned integer. Indicates the CoAP version
9692  * number. Implementations of this specification MUST set this field
9693  * to 1 (01 binary). Other values are reserved for future versions.
9694  * Messages with unknown version numbers MUST be silently ignored.
9695  */
9696  if (((uint8_t) *ptr >> 6) != 1) {
9697  cm->flags |= MG_COAP_IGNORE;
9698  return NULL;
9699  }
9700 
9701  /*
9702  * Type (T): 2-bit unsigned integer. Indicates if this message is of
9703  * type Confirmable (0), Non-confirmable (1), Acknowledgement (2), or
9704  * Reset (3).
9705  */
9706  cm->msg_type = ((uint8_t) *ptr & 0x30) >> 4;
9707  cm->flags |= MG_COAP_MSG_TYPE_FIELD;
9708 
9709  /*
9710  * Token Length (TKL): 4-bit unsigned integer. Indicates the length of
9711  * the variable-length Token field (0-8 bytes). Lengths 9-15 are
9712  * reserved, MUST NOT be sent, and MUST be processed as a message
9713  * format error.
9714  */
9715  cm->token.len = *ptr & 0x0F;
9716  if (cm->token.len > 8) {
9717  cm->flags |= MG_COAP_FORMAT_ERROR;
9718  return NULL;
9719  }
9720 
9721  ptr++;
9722 
9723  /*
9724  * Code: 8-bit unsigned integer, split into a 3-bit class (most
9725  * significant bits) and a 5-bit detail (least significant bits)
9726  */
9727  cm->code_class = (uint8_t) *ptr >> 5;
9728  cm->code_detail = *ptr & 0x1F;
9729  cm->flags |= (MG_COAP_CODE_CLASS_FIELD | MG_COAP_CODE_DETAIL_FIELD);
9730 
9731  ptr++;
9732 
9733  /* Message ID: 16-bit unsigned integer in network byte order. */
9734  cm->msg_id = (uint8_t) *ptr << 8 | (uint8_t) * (ptr + 1);
9735  cm->flags |= MG_COAP_MSG_ID_FIELD;
9736 
9737  ptr += 2;
9738 
9739  return ptr;
9740  }
9741 
9742  /*
9743  * Fills token information in mg_coap_message.
9744  *
9745  * Helper function.
9746  */
9747  static char *coap_get_token(char *ptr, struct mbuf *io,
9748  struct mg_coap_message *cm) {
9749  if (cm->token.len != 0) {
9750  if (ptr + cm->token.len > io->buf + io->len) {
9751  cm->flags |= MG_COAP_NOT_ENOUGH_DATA;
9752  return NULL;
9753  } else {
9754  cm->token.p = ptr;
9755  ptr += cm->token.len;
9756  cm->flags |= MG_COAP_TOKEN_FIELD;
9757  }
9758  }
9759 
9760  return ptr;
9761  }
9762 
9763  /*
9764  * Returns Option Delta or Length.
9765  *
9766  * Helper function.
9767  */
9768  static int coap_get_ext_opt(char *ptr, struct mbuf *io, uint16_t *opt_info) {
9769  int ret = 0;
9770 
9771  if (*opt_info == 13) {
9772  /*
9773  * 13: An 8-bit unsigned integer follows the initial byte and
9774  * indicates the Option Delta/Length minus 13.
9775  */
9776  if (ptr < io->buf + io->len) {
9777  *opt_info = (uint8_t) *ptr + 13;
9778  ret = sizeof(uint8_t);
9779  } else {
9780  ret = -1; /* LCOV_EXCL_LINE */
9781  }
9782  } else if (*opt_info == 14) {
9783  /*
9784  * 14: A 16-bit unsigned integer in network byte order follows the
9785  * initial byte and indicates the Option Delta/Length minus 269.
9786  */
9787  if (ptr + sizeof(uint8_t) < io->buf + io->len) {
9788  *opt_info = ((uint8_t) *ptr << 8 | (uint8_t) * (ptr + 1)) + 269;
9789  ret = sizeof(uint16_t);
9790  } else {
9791  ret = -1; /* LCOV_EXCL_LINE */
9792  }
9793  }
9794 
9795  return ret;
9796  }
9797 
9798  /*
9799  * Fills options in mg_coap_message.
9800  *
9801  * Helper function.
9802  *
9803  * General options format:
9804  * +---------------+---------------+
9805  * | Option Delta | Option Length | 1 byte
9806  * +---------------+---------------+
9807  * \ Option Delta (extended) \ 0-2 bytes
9808  * +-------------------------------+
9809  * / Option Length (extended) \ 0-2 bytes
9810  * +-------------------------------+
9811  * \ Option Value \ 0 or more bytes
9812  * +-------------------------------+
9813  */
9814  static char *coap_get_options(char *ptr, struct mbuf *io,
9815  struct mg_coap_message *cm) {
9816  uint16_t prev_opt = 0;
9817 
9818  if (ptr == io->buf + io->len) {
9819  /* end of packet, ok */
9820  return NULL;
9821  }
9822 
9823  /* 0xFF is payload marker */
9824  while (ptr < io->buf + io->len && (uint8_t) *ptr != 0xFF) {
9825  uint16_t option_delta, option_lenght;
9826  int optinfo_len;
9827 
9828  /* Option Delta: 4-bit unsigned integer */
9829  option_delta = ((uint8_t) *ptr & 0xF0) >> 4;
9830  /* Option Length: 4-bit unsigned integer */
9831  option_lenght = *ptr & 0x0F;
9832 
9833  if (option_delta == 15 || option_lenght == 15) {
9834  /*
9835  * 15: Reserved for future use. If the field is set to this value,
9836  * it MUST be processed as a message format error
9837  */
9838  cm->flags |= MG_COAP_FORMAT_ERROR;
9839  break;
9840  }
9841 
9842  ptr++;
9843 
9844  /* check for extended option delta */
9845  optinfo_len = coap_get_ext_opt(ptr, io, &option_delta);
9846  if (optinfo_len == -1) {
9847  cm->flags |= MG_COAP_NOT_ENOUGH_DATA; /* LCOV_EXCL_LINE */
9848  break; /* LCOV_EXCL_LINE */
9849  }
9850 
9851  ptr += optinfo_len;
9852 
9853  /* check or extended option lenght */
9854  optinfo_len = coap_get_ext_opt(ptr, io, &option_lenght);
9855  if (optinfo_len == -1) {
9856  cm->flags |= MG_COAP_NOT_ENOUGH_DATA; /* LCOV_EXCL_LINE */
9857  break; /* LCOV_EXCL_LINE */
9858  }
9859 
9860  ptr += optinfo_len;
9861 
9862  /*
9863  * Instead of specifying the Option Number directly, the instances MUST
9864  * appear in order of their Option Numbers and a delta encoding is used
9865  * between them.
9866  */
9867  option_delta += prev_opt;
9868 
9869  mg_coap_add_option(cm, option_delta, ptr, option_lenght);
9870 
9871  prev_opt = option_delta;
9872 
9873  if (ptr + option_lenght > io->buf + io->len) {
9874  cm->flags |= MG_COAP_NOT_ENOUGH_DATA; /* LCOV_EXCL_LINE */
9875  break; /* LCOV_EXCL_LINE */
9876  }
9877 
9878  ptr += option_lenght;
9879  }
9880 
9881  if ((cm->flags & MG_COAP_ERROR) != 0) {
9882  mg_coap_free_options(cm);
9883  return NULL;
9884  }
9885 
9886  cm->flags |= MG_COAP_OPTIOMG_FIELD;
9887 
9888  if (ptr == io->buf + io->len) {
9889  /* end of packet, ok */
9890  return NULL;
9891  }
9892 
9893  ptr++;
9894 
9895  return ptr;
9896  }
9897 
9898  uint32_t mg_coap_parse(struct mbuf *io, struct mg_coap_message *cm) {
9899  char *ptr;
9900 
9901  memset(cm, 0, sizeof(*cm));
9902 
9903  if ((ptr = coap_parse_header(io->buf, io, cm)) == NULL) {
9904  return cm->flags;
9905  }
9906 
9907  if ((ptr = coap_get_token(ptr, io, cm)) == NULL) {
9908  return cm->flags;
9909  }
9910 
9911  if ((ptr = coap_get_options(ptr, io, cm)) == NULL) {
9912  return cm->flags;
9913  }
9914 
9915  /* the rest is payload */
9916  cm->payload.len = io->len - (ptr - io->buf);
9917  if (cm->payload.len != 0) {
9918  cm->payload.p = ptr;
9919  cm->flags |= MG_COAP_PAYLOAD_FIELD;
9920  }
9921 
9922  return cm->flags;
9923  }
9924 
9925  /*
9926  * Calculates extended size of given Opt Number/Length in coap message.
9927  *
9928  * Helper function.
9929  */
9930  static size_t coap_get_ext_opt_size(uint32_t value) {
9931  int ret = 0;
9932 
9933  if (value >= 13 && value <= 0xFF + 13) {
9934  ret = sizeof(uint8_t);
9935  } else if (value > 0xFF + 13 && value <= 0xFFFF + 269) {
9936  ret = sizeof(uint16_t);
9937  }
9938 
9939  return ret;
9940  }
9941 
9942  /*
9943  * Splits given Opt Number/Length into base and ext values.
9944  *
9945  * Helper function.
9946  */
9947  static int coap_split_opt(uint32_t value, uint8_t *base, uint16_t *ext) {
9948  int ret = 0;
9949 
9950  if (value < 13) {
9951  *base = value;
9952  } else if (value >= 13 && value <= 0xFF + 13) {
9953  *base = 13;
9954  *ext = value - 13;
9955  ret = sizeof(uint8_t);
9956  } else if (value > 0xFF + 13 && value <= 0xFFFF + 269) {
9957  *base = 14;
9958  *ext = value - 269;
9959  ret = sizeof(uint16_t);
9960  }
9961 
9962  return ret;
9963  }
9964 
9965  /*
9966  * Puts uint16_t (in network order) into given char stream.
9967  *
9968  * Helper function.
9969  */
9970  static char *coap_add_uint16(char *ptr, uint16_t val) {
9971  *ptr = val >> 8;
9972  ptr++;
9973  *ptr = val & 0x00FF;
9974  ptr++;
9975  return ptr;
9976  }
9977 
9978  /*
9979  * Puts extended value of Opt Number/Length into given char stream.
9980  *
9981  * Helper function.
9982  */
9983  static char *coap_add_opt_info(char *ptr, uint16_t val, size_t len) {
9984  if (len == sizeof(uint8_t)) {
9985  *ptr = val;
9986  ptr++;
9987  } else if (len == sizeof(uint16_t)) {
9988  ptr = coap_add_uint16(ptr, val);
9989  }
9990 
9991  return ptr;
9992  }
9993 
9994  /*
9995  * Verifies given mg_coap_message and calculates message size for it.
9996  *
9997  * Helper function.
9998  */
9999  static uint32_t coap_calculate_packet_size(struct mg_coap_message *cm,
10000  size_t *len) {
10001  struct mg_coap_option *opt;
10002  uint32_t prev_opt_number;
10003 
10004  *len = 4; /* header */
10005  if (cm->msg_type > MG_COAP_MSG_MAX) {
10006  return MG_COAP_ERROR | MG_COAP_MSG_TYPE_FIELD;
10007  }
10008  if (cm->token.len > 8) {
10009  return MG_COAP_ERROR | MG_COAP_TOKEN_FIELD;
10010  }
10011  if (cm->code_class > 7) {
10012  return MG_COAP_ERROR | MG_COAP_CODE_CLASS_FIELD;
10013  }
10014  if (cm->code_detail > 31) {
10015  return MG_COAP_ERROR | MG_COAP_CODE_DETAIL_FIELD;
10016  }
10017 
10018  *len += cm->token.len;
10019  if (cm->payload.len != 0) {
10020  *len += cm->payload.len + 1; /* ... + 1; add payload marker */
10021  }
10022 
10023  opt = cm->options;
10024  prev_opt_number = 0;
10025  while (opt != NULL) {
10026  *len += 1; /* basic delta/length */
10027  *len += coap_get_ext_opt_size(opt->number);
10028  *len += coap_get_ext_opt_size((uint32_t) opt->value.len);
10029  /*
10030  * Current implementation performs check if
10031  * option_number > previous option_number and produces an error
10032  * TODO(alashkin): write design doc with limitations
10033  * May be resorting is more suitable solution.
10034  */
10035  if ((opt->next != NULL && opt->number > opt->next->number) ||
10036  opt->value.len > 0xFFFF + 269 ||
10037  opt->number - prev_opt_number > 0xFFFF + 269) {
10038  return MG_COAP_ERROR | MG_COAP_OPTIOMG_FIELD;
10039  }
10040  *len += opt->value.len;
10041  opt = opt->next;
10042  }
10043 
10044  return 0;
10045  }
10046 
10047  uint32_t mg_coap_compose(struct mg_coap_message *cm, struct mbuf *io) {
10048  struct mg_coap_option *opt;
10049  uint32_t res, prev_opt_number;
10050  size_t prev_io_len, packet_size;
10051  char *ptr;
10052 
10053  res = coap_calculate_packet_size(cm, &packet_size);
10054  if (res != 0) {
10055  return res;
10056  }
10057 
10058  /* saving previous lenght to handle non-empty mbuf */
10059  prev_io_len = io->len;
10060  mbuf_append(io, NULL, packet_size);
10061  ptr = io->buf + prev_io_len;
10062 
10063  /*
10064  * since cm is verified, it is possible to use bits shift operator
10065  * without additional zeroing of unused bits
10066  */
10067 
10068  /* ver: 2 bits, msg_type: 2 bits, toklen: 4 bits */
10069  *ptr = (1 << 6) | (cm->msg_type << 4) | (cm->token.len);
10070  ptr++;
10071 
10072  /* code class: 3 bits, code detail: 5 bits */
10073  *ptr = (cm->code_class << 5) | (cm->code_detail);
10074  ptr++;
10075 
10076  ptr = coap_add_uint16(ptr, cm->msg_id);
10077 
10078  if (cm->token.len != 0) {
10079  memcpy(ptr, cm->token.p, cm->token.len);
10080  ptr += cm->token.len;
10081  }
10082 
10083  opt = cm->options;
10084  prev_opt_number = 0;
10085  while (opt != NULL) {
10086  uint8_t delta_base = 0, length_base = 0;
10087  uint16_t delta_ext, length_ext;
10088 
10089  size_t opt_delta_len =
10090  coap_split_opt(opt->number - prev_opt_number, &delta_base, &delta_ext);
10091  size_t opt_lenght_len =
10092  coap_split_opt((uint32_t) opt->value.len, &length_base, &length_ext);
10093 
10094  *ptr = (delta_base << 4) | length_base;
10095  ptr++;
10096 
10097  ptr = coap_add_opt_info(ptr, delta_ext, opt_delta_len);
10098  ptr = coap_add_opt_info(ptr, length_ext, opt_lenght_len);
10099 
10100  if (opt->value.len != 0) {
10101  memcpy(ptr, opt->value.p, opt->value.len);
10102  ptr += opt->value.len;
10103  }
10104 
10105  prev_opt_number = opt->number;
10106  opt = opt->next;
10107  }
10108 
10109  if (cm->payload.len != 0) {
10110  *ptr = -1;
10111  ptr++;
10112  memcpy(ptr, cm->payload.p, cm->payload.len);
10113  }
10114 
10115  return 0;
10116  }
10117 
10118  uint32_t mg_coap_send_message(struct mg_connection *nc,
10119  struct mg_coap_message *cm) {
10120  struct mbuf packet_out;
10121  uint32_t compose_res;
10122 
10123  mbuf_init(&packet_out, 0);
10124  compose_res = mg_coap_compose(cm, &packet_out);
10125  if (compose_res != 0) {
10126  return compose_res; /* LCOV_EXCL_LINE */
10127  }
10128 
10129  mg_send(nc, packet_out.buf, (int) packet_out.len);
10130  mbuf_free(&packet_out);
10131 
10132  return 0;
10133  }
10134 
10135  uint32_t mg_coap_send_ack(struct mg_connection *nc, uint16_t msg_id) {
10136  struct mg_coap_message cm;
10137  memset(&cm, 0, sizeof(cm));
10138  cm.msg_type = MG_COAP_MSG_ACK;
10139  cm.msg_id = msg_id;
10140 
10141  return mg_coap_send_message(nc, &cm);
10142  }
10143 
10144  static void coap_handler(struct mg_connection *nc, int ev, void *ev_data) {
10145  struct mbuf *io = &nc->recv_mbuf;
10146  struct mg_coap_message cm;
10147  uint32_t parse_res;
10148 
10149  memset(&cm, 0, sizeof(cm));
10150 
10151  nc->handler(nc, ev, ev_data);
10152 
10153  switch (ev) {
10154  case MG_EV_RECV:
10155  parse_res = mg_coap_parse(io, &cm);
10156  if ((parse_res & MG_COAP_IGNORE) == 0) {
10157  if ((cm.flags & MG_COAP_NOT_ENOUGH_DATA) != 0) {
10158  /*
10159  * Since we support UDP only
10160  * MG_COAP_NOT_ENOUGH_DATA == MG_COAP_FORMAT_ERROR
10161  */
10162  cm.flags |= MG_COAP_FORMAT_ERROR; /* LCOV_EXCL_LINE */
10163  } /* LCOV_EXCL_LINE */
10164  nc->handler(nc, MG_COAP_EVENT_BASE + cm.msg_type, &cm);
10165  }
10166 
10167  mg_coap_free_options(&cm);
10168  mbuf_remove(io, io->len);
10169  break;
10170  }
10171  }
10172  /*
10173  * Attach built-in CoAP event handler to the given connection.
10174  *
10175  * The user-defined event handler will receive following extra events:
10176  *
10177  * - MG_EV_COAP_CON
10178  * - MG_EV_COAP_NOC
10179  * - MG_EV_COAP_ACK
10180  * - MG_EV_COAP_RST
10181  */
10182  int mg_set_protocol_coap(struct mg_connection *nc) {
10183  /* supports UDP only */
10184  if ((nc->flags & MG_F_UDP) == 0) {
10185  return -1;
10186  }
10187 
10188  nc->proto_handler = coap_handler;
10189 
10190  return 0;
10191  }
10192 
10193 #endif /* MG_DISABLE_COAP */
10194 #ifdef MG_MODULE_LINES
10195 #line 1 "./src/../../common/platforms/cc3200/cc3200_libc.c"
10196 #endif
10197  /*
10198  * Copyright (c) 2014-2016 Cesanta Software Limited
10199  * All rights reserved
10200  */
10201 
10202 #if CS_PLATFORM == CS_P_CC3200
10203 
10204 #include <stdio.h>
10205 #include <string.h>
10206 
10207 #ifndef __TI_COMPILER_VERSION__
10208 #include <reent.h>
10209 #include <sys/stat.h>
10210 #include <sys/time.h>
10211 #include <unistd.h>
10212 #endif
10213 
10214 #include <inc/hw_types.h>
10215 #include <inc/hw_memmap.h>
10216 #include <driverlib/prcm.h>
10217 #include <driverlib/rom.h>
10218 #include <driverlib/rom_map.h>
10219 #include <driverlib/uart.h>
10220 #include <driverlib/utils.h>
10221 
10222 #define CONSOLE_UART UARTA0_BASE
10223 
10224 #ifdef __TI_COMPILER_VERSION__
10225  int asprintf(char **strp, const char *fmt, ...) {
10226  va_list ap;
10227  int len;
10228 
10229  *strp = malloc(BUFSIZ);
10230  if (*strp == NULL) return -1;
10231 
10232  va_start(ap, fmt);
10233  len = vsnprintf(*strp, BUFSIZ, fmt, ap);
10234  va_end(ap);
10235 
10236  if (len > 0) {
10237  *strp = realloc(*strp, len);
10238  if (*strp == NULL) return -1;
10239  }
10240 
10241  if (len >= BUFSIZ) {
10242  va_start(ap, fmt);
10243  len = vsnprintf(*strp, len, fmt, ap);
10244  va_end(ap);
10245  }
10246 
10247  return len;
10248  }
10249 #endif /* __TI_COMPILER_VERSION__ */
10250 
10251 #ifndef __TI_COMPILER_VERSION__
10252  int _gettimeofday_r(struct _reent *r, struct timeval *tp, void *tzp) {
10253 #else
10254  int gettimeofday(struct timeval *tp, void *tzp) {
10255 #endif
10256  unsigned long long r1 = 0, r2;
10257  /* Achieve two consecutive reads of the same value. */
10258  do {
10259  r2 = r1;
10260  r1 = PRCMSlowClkCtrFastGet();
10261  } while (r1 != r2);
10262  /* This is a 32768 Hz counter. */
10263  tp->tv_sec = (r1 >> 15);
10264  /* 1/32768-th of a second is 30.517578125 microseconds, approx. 31,
10265  * but we round down so it doesn't overflow at 32767 */
10266  tp->tv_usec = (r1 & 0x7FFF) * 30;
10267  return 0;
10268  }
10269 
10270  long int random(void) {
10271  return 42; /* FIXME */
10272  }
10273 
10274  void fprint_str(FILE *fp, const char *str) {
10275  while (*str != '\0') {
10276  if (*str == '\n') MAP_UARTCharPut(CONSOLE_UART, '\r');
10277  MAP_UARTCharPut(CONSOLE_UART, *str++);
10278  }
10279  }
10280 
10281  void _exit(int status) {
10282  fprint_str(stderr, "_exit\n");
10283  /* cause an unaligned access exception, that will drop you into gdb */
10284  *(int *) 1 = status;
10285  while (1)
10286  ; /* avoid gcc warning because stdlib abort() has noreturn attribute */
10287  }
10288 
10289  void _not_implemented(const char *what) {
10290  fprint_str(stderr, what);
10291  fprint_str(stderr, " is not implemented\n");
10292  _exit(42);
10293  }
10294 
10295  int _kill(int pid, int sig) {
10296  (void) pid;
10297  (void) sig;
10298  _not_implemented("_kill");
10299  return -1;
10300  }
10301 
10302  int _getpid() {
10303  fprint_str(stderr, "_getpid is not implemented\n");
10304  return 42;
10305  }
10306 
10307  int _isatty(int fd) {
10308  /* 0, 1 and 2 are TTYs. */
10309  return fd < 2;
10310  }
10311 
10312 #endif /* CS_PLATFORM == CS_P_CC3200 */
10313 #ifdef MG_MODULE_LINES
10314 #line 1 "./src/../../common/platforms/msp432/msp432_libc.c"
10315 #endif
10316  /*
10317  * Copyright (c) 2014-2016 Cesanta Software Limited
10318  * All rights reserved
10319  */
10320 
10321 #if CS_PLATFORM == CS_P_MSP432
10322 
10323 #include <ti/sysbios/BIOS.h>
10324 #include <ti/sysbios/knl/Clock.h>
10325 
10326  int gettimeofday(struct timeval *tp, void *tzp) {
10327  uint32_t ticks = Clock_getTicks();
10328  tp->tv_sec = ticks / 1000;
10329  tp->tv_usec = (ticks % 1000) * 1000;
10330  return 0;
10331  }
10332 
10333  long int random(void) {
10334  return 42; /* FIXME */
10335  }
10336 
10337 #endif /* CS_PLATFORM == CS_P_MSP432 */
10338 #ifdef MG_MODULE_LINES
10339 #line 1 "./src/../../common/platforms/simplelink/sl_fs_slfs.h"
10340 #endif
10341  /*
10342  * Copyright (c) 2014-2016 Cesanta Software Limited
10343  * All rights reserved
10344  */
10345 
10346 #ifndef CS_COMMON_PLATFORMS_SIMPLELINK_SL_FS_SLFS_H_
10347 #define CS_COMMON_PLATFORMS_SIMPLELINK_SL_FS_SLFS_H_
10348 
10349 #if defined(MG_FS_SLFS)
10350 
10351 #include <stdio.h>
10352 #ifndef __TI_COMPILER_VERSION__
10353 #include <unistd.h>
10354 #include <sys/stat.h>
10355 #endif
10356 
10357 #define MAX_OPEN_SLFS_FILES 8
10358 
10359  /* Indirect libc interface - same functions, different names. */
10360  int fs_slfs_open(const char *pathname, int flags, mode_t mode);
10361  int fs_slfs_close(int fd);
10362  ssize_t fs_slfs_read(int fd, void *buf, size_t count);
10363  ssize_t fs_slfs_write(int fd, const void *buf, size_t count);
10364  int fs_slfs_stat(const char *pathname, struct stat *s);
10365  int fs_slfs_fstat(int fd, struct stat *s);
10366  off_t fs_slfs_lseek(int fd, off_t offset, int whence);
10367  int fs_slfs_unlink(const char *filename);
10368  int fs_slfs_rename(const char *from, const char *to);
10369 
10370  void fs_slfs_set_new_file_size(const char *name, size_t size);
10371 
10372 #endif /* defined(MG_FS_SLFS) */
10373 
10374 #endif /* CS_COMMON_PLATFORMS_SIMPLELINK_SL_FS_SLFS_H_ */
10375 #ifdef MG_MODULE_LINES
10376 #line 1 "./src/../../common/platforms/simplelink/sl_fs_slfs.c"
10377 #endif
10378  /*
10379  * Copyright (c) 2014-2016 Cesanta Software Limited
10380  * All rights reserved
10381  */
10382 
10383  /* Standard libc interface to TI SimpleLink FS. */
10384 
10385 #if defined(MG_FS_SLFS) || defined(CC3200_FS_SLFS)
10386 
10387  /* Amalgamated: #include "common/platforms/simplelink/sl_fs_slfs.h" */
10388 
10389 #include <errno.h>
10390 
10391 #if CS_PLATFORM == CS_P_CC3200
10392 #include <inc/hw_types.h>
10393 #endif
10394 #include <simplelink/include/simplelink.h>
10395 #include <simplelink/include/fs.h>
10396 
10397  /* Amalgamated: #include "common/cs_dbg.h" */
10398 
10399  extern int set_errno(int e); /* From sl_fs.c */
10400 
10401  /*
10402  * With SLFS, you have to pre-declare max file size. Yes. Really.
10403  * 64K should be enough for everyone. Right?
10404  */
10405 #ifndef FS_SLFS_MAX_FILE_SIZE
10406 #define FS_SLFS_MAX_FILE_SIZE (64 * 1024)
10407 #endif
10408 
10409  struct sl_file_size_hint {
10410  char *name;
10411  size_t size;
10412  };
10413 
10414  struct sl_fd_info {
10415  _i32 fh;
10416  _off_t pos;
10417  size_t size;
10418  };
10419 
10420  static struct sl_fd_info s_sl_fds[MAX_OPEN_SLFS_FILES];
10421  static struct sl_file_size_hint s_sl_file_size_hints[MAX_OPEN_SLFS_FILES];
10422 
10423  static int sl_fs_to_errno(_i32 r) {
10424  DBG(("SL error: %d", (int) r));
10425  switch (r) {
10426  case SL_FS_OK:
10427  return 0;
10428  case SL_FS_FILE_NAME_EXIST:
10429  return EEXIST;
10430  case SL_FS_WRONG_FILE_NAME:
10431  return EINVAL;
10432  case SL_FS_ERR_NO_AVAILABLE_NV_INDEX:
10433  case SL_FS_ERR_NO_AVAILABLE_BLOCKS:
10434  return ENOSPC;
10435  case SL_FS_ERR_FAILED_TO_ALLOCATE_MEM:
10436  return ENOMEM;
10437  case SL_FS_ERR_FILE_NOT_EXISTS:
10438  return ENOENT;
10439  case SL_FS_ERR_NOT_SUPPORTED:
10440  return ENOTSUP;
10441  }
10442  return ENXIO;
10443  }
10444 
10445  int fs_slfs_open(const char *pathname, int flags, mode_t mode) {
10446  int fd;
10447  for (fd = 0; fd < MAX_OPEN_SLFS_FILES; fd++) {
10448  if (s_sl_fds[fd].fh <= 0) break;
10449  }
10450  if (fd >= MAX_OPEN_SLFS_FILES) return set_errno(ENOMEM);
10451  struct sl_fd_info *fi = &s_sl_fds[fd];
10452 
10453  _u32 am = 0;
10454  fi->size = (size_t) -1;
10455  if (pathname[0] == '/') pathname++;
10456  int rw = (flags & 3);
10457  if (rw == O_RDONLY) {
10458  SlFsFileInfo_t sl_fi;
10459  _i32 r = sl_FsGetInfo((const _u8 *) pathname, 0, &sl_fi);
10460  if (r == SL_FS_OK) {
10461  fi->size = sl_fi.FileLen;
10462  }
10463  am = FS_MODE_OPEN_READ;
10464  } else {
10465  if (!(flags & O_TRUNC) || (flags & O_APPEND)) {
10466  // FailFS files cannot be opened for append and will be truncated
10467  // when opened for write.
10468  return set_errno(ENOTSUP);
10469  }
10470  if (flags & O_CREAT) {
10471  size_t i, size = FS_SLFS_MAX_FILE_SIZE;
10472  for (i = 0; i < MAX_OPEN_SLFS_FILES; i++) {
10473  if (s_sl_file_size_hints[i].name != NULL &&
10474  strcmp(s_sl_file_size_hints[i].name, pathname) == 0) {
10475  size = s_sl_file_size_hints[i].size;
10476  free(s_sl_file_size_hints[i].name);
10477  s_sl_file_size_hints[i].name = NULL;
10478  break;
10479  }
10480  }
10481  DBG(("creating %s with max size %d", pathname, (int) size));
10482  am = FS_MODE_OPEN_CREATE(size, 0);
10483  } else {
10484  am = FS_MODE_OPEN_WRITE;
10485  }
10486  }
10487  _i32 r = sl_FsOpen((_u8 *) pathname, am, NULL, &fi->fh);
10488  DBG(("sl_FsOpen(%s, 0x%x) = %d, %d", pathname, (int) am, (int) r,
10489  (int) fi->fh));
10490  if (r == SL_FS_OK) {
10491  fi->pos = 0;
10492  r = fd;
10493  } else {
10494  fi->fh = -1;
10495  r = set_errno(sl_fs_to_errno(r));
10496  }
10497  return r;
10498  }
10499 
10500  int fs_slfs_close(int fd) {
10501  struct sl_fd_info *fi = &s_sl_fds[fd];
10502  if (fi->fh <= 0) return set_errno(EBADF);
10503  _i32 r = sl_FsClose(fi->fh, NULL, NULL, 0);
10504  DBG(("sl_FsClose(%d) = %d", (int) fi->fh, (int) r));
10505  s_sl_fds[fd].fh = -1;
10506  return set_errno(sl_fs_to_errno(r));
10507  }
10508 
10509  ssize_t fs_slfs_read(int fd, void *buf, size_t count) {
10510  struct sl_fd_info *fi = &s_sl_fds[fd];
10511  if (fi->fh <= 0) return set_errno(EBADF);
10512  /* Simulate EOF. sl_FsRead @ file_size return SL_FS_ERR_OFFSET_OUT_OF_RANGE.
10513  */
10514  if (fi->pos == fi->size) return 0;
10515  _i32 r = sl_FsRead(fi->fh, fi->pos, buf, count);
10516  DBG(("sl_FsRead(%d, %d, %d) = %d", (int) fi->fh, (int) fi->pos, (int) count,
10517  (int) r));
10518  if (r >= 0) {
10519  fi->pos += r;
10520  return r;
10521  }
10522  return set_errno(sl_fs_to_errno(r));
10523  }
10524 
10525  ssize_t fs_slfs_write(int fd, const void *buf, size_t count) {
10526  struct sl_fd_info *fi = &s_sl_fds[fd];
10527  if (fi->fh <= 0) return set_errno(EBADF);
10528  _i32 r = sl_FsWrite(fi->fh, fi->pos, (_u8 *) buf, count);
10529  DBG(("sl_FsWrite(%d, %d, %d) = %d", (int) fi->fh, (int) fi->pos, (int) count,
10530  (int) r));
10531  if (r >= 0) {
10532  fi->pos += r;
10533  return r;
10534  }
10535  return set_errno(sl_fs_to_errno(r));
10536  }
10537 
10538  int fs_slfs_stat(const char *pathname, struct stat *s) {
10539  SlFsFileInfo_t sl_fi;
10540  _i32 r = sl_FsGetInfo((const _u8 *) pathname, 0, &sl_fi);
10541  if (r == SL_FS_OK) {
10542  s->st_mode = S_IFREG | 0666;
10543  s->st_nlink = 1;
10544  s->st_size = sl_fi.FileLen;
10545  return 0;
10546  }
10547  return set_errno(sl_fs_to_errno(r));
10548  }
10549 
10550  int fs_slfs_fstat(int fd, struct stat *s) {
10551  struct sl_fd_info *fi = &s_sl_fds[fd];
10552  if (fi->fh <= 0) return set_errno(EBADF);
10553  s->st_mode = 0666;
10554  s->st_mode = S_IFREG | 0666;
10555  s->st_nlink = 1;
10556  s->st_size = fi->size;
10557  return 0;
10558  }
10559 
10560  off_t fs_slfs_lseek(int fd, off_t offset, int whence) {
10561  if (s_sl_fds[fd].fh <= 0) return set_errno(EBADF);
10562  switch (whence) {
10563  case SEEK_SET:
10564  s_sl_fds[fd].pos = offset;
10565  break;
10566  case SEEK_CUR:
10567  s_sl_fds[fd].pos += offset;
10568  break;
10569  case SEEK_END:
10570  return set_errno(ENOTSUP);
10571  }
10572  return 0;
10573  }
10574 
10575  int fs_slfs_unlink(const char *filename) {
10576  return set_errno(sl_fs_to_errno(sl_FsDel((const _u8 *) filename, 0)));
10577  }
10578 
10579  int fs_slfs_rename(const char *from, const char *to) {
10580  return set_errno(ENOTSUP);
10581  }
10582 
10583  void fs_slfs_set_new_file_size(const char *name, size_t size) {
10584  int i;
10585  for (i = 0; i < MAX_OPEN_SLFS_FILES; i++) {
10586  if (s_sl_file_size_hints[i].name == NULL) {
10587  DBG(("File size hint: %s %d", name, (int) size));
10588  s_sl_file_size_hints[i].name = strdup(name);
10589  s_sl_file_size_hints[i].size = size;
10590  break;
10591  }
10592  }
10593  }
10594 
10595 #endif /* defined(MG_FS_SLFS) || defined(CC3200_FS_SLFS) */
10596 #ifdef MG_MODULE_LINES
10597 #line 1 "./src/../../common/platforms/simplelink/sl_fs.c"
10598 #endif
10599  /*
10600  * Copyright (c) 2014-2016 Cesanta Software Limited
10601  * All rights reserved
10602  */
10603 
10604 #if defined(MG_SOCKET_SIMPLELINK) && \
10605 (defined(MG_FS_SLFS) || defined(MG_FS_SPIFFS))
10606 
10607 #include <errno.h>
10608 #include <stdio.h>
10609 #include <stdlib.h>
10610 #include <string.h>
10611 #ifdef __TI_COMPILER_VERSION__
10612 #include <file.h>
10613 #endif
10614 
10615 #if CS_PLATFORM == CS_P_CC3200
10616 #include <inc/hw_types.h>
10617 #include <inc/hw_memmap.h>
10618 #include <driverlib/rom.h>
10619 #include <driverlib/rom_map.h>
10620 #include <driverlib/uart.h>
10621 #endif
10622 
10623  /* Amalgamated: #include "common/cs_dbg.h" */
10624  /* Amalgamated: #include "common/platform.h" */
10625 
10626 #ifdef CC3200_FS_SPIFFS
10627  /* Amalgamated: #include "cc3200_fs_spiffs.h" */
10628 #endif
10629 
10630 #ifdef MG_FS_SLFS
10631  /* Amalgamated: #include "sl_fs_slfs.h" */
10632 #endif
10633 
10634 #define NUM_SYS_FDS 3
10635 #define SPIFFS_FD_BASE 10
10636 #define SLFS_FD_BASE 100
10637 
10638 #define CONSOLE_UART UARTA0_BASE
10639 
10640  int set_errno(int e) {
10641  errno = e;
10642  return -e;
10643  }
10644 
10645  static int is_sl_fname(const char *fname) {
10646  return strncmp(fname, "SL:", 3) == 0;
10647  }
10648 
10649  static const char *sl_fname(const char *fname) {
10650  return fname + 3;
10651  }
10652 
10653  static const char *drop_dir(const char *fname) {
10654  if (*fname == '.') fname++;
10655  if (*fname == '/') fname++;
10656  return fname;
10657  }
10658 
10659  enum fd_type {
10660  FD_INVALID,
10661  FD_SYS,
10662 #ifdef CC3200_FS_SPIFFS
10663  FD_SPIFFS,
10664 #endif
10665 #ifdef MG_FS_SLFS
10666  FD_SLFS
10667 #endif
10668  };
10669  static int fd_type(int fd) {
10670  if (fd >= 0 && fd < NUM_SYS_FDS) return FD_SYS;
10671 #ifdef CC3200_FS_SPIFFS
10672  if (fd >= SPIFFS_FD_BASE && fd < SPIFFS_FD_BASE + MAX_OPEN_SPIFFS_FILES) {
10673  return FD_SPIFFS;
10674  }
10675 #endif
10676 #ifdef MG_FS_SLFS
10677  if (fd >= SLFS_FD_BASE && fd < SLFS_FD_BASE + MAX_OPEN_SLFS_FILES) {
10678  return FD_SLFS;
10679  }
10680 #endif
10681  return FD_INVALID;
10682  }
10683 
10684  int _open(const char *pathname, int flags, mode_t mode) {
10685  int fd = -1;
10686  pathname = drop_dir(pathname);
10687  if (is_sl_fname(pathname)) {
10688 #ifdef MG_FS_SLFS
10689  fd = fs_slfs_open(sl_fname(pathname), flags, mode);
10690  if (fd >= 0) fd += SLFS_FD_BASE;
10691 #endif
10692  } else {
10693 #ifdef CC3200_FS_SPIFFS
10694  fd = fs_spiffs_open(pathname, flags, mode);
10695  if (fd >= 0) fd += SPIFFS_FD_BASE;
10696 #endif
10697  }
10698  DBG(("open(%s, 0x%x) = %d", pathname, flags, fd));
10699  return fd;
10700  }
10701 
10702  int _stat(const char *pathname, struct stat *st) {
10703  int res = -1;
10704  const char *fname = pathname;
10705  int is_sl = is_sl_fname(pathname);
10706  if (is_sl) fname = sl_fname(pathname);
10707  fname = drop_dir(fname);
10708  memset(st, 0, sizeof(*st));
10709  /* Simulate statting the root directory. */
10710  if (strcmp(fname, "") == 0) {
10711  st->st_ino = 0;
10712  st->st_mode = S_IFDIR | 0777;
10713  st->st_nlink = 1;
10714  st->st_size = 0;
10715  return 0;
10716  }
10717  if (is_sl) {
10718 #ifdef MG_FS_SLFS
10719  res = fs_slfs_stat(fname, st);
10720 #endif
10721  } else {
10722 #ifdef CC3200_FS_SPIFFS
10723  res = fs_spiffs_stat(fname, st);
10724 #endif
10725  }
10726  DBG(("stat(%s) = %d; fname = %s", pathname, res, fname));
10727  return res;
10728  }
10729 
10730  int _close(int fd) {
10731  int r = -1;
10732  switch (fd_type(fd)) {
10733  case FD_INVALID:
10734  r = set_errno(EBADF);
10735  break;
10736  case FD_SYS:
10737  r = set_errno(EACCES);
10738  break;
10739 #ifdef CC3200_FS_SPIFFS
10740  case FD_SPIFFS:
10741  r = fs_spiffs_close(fd - SPIFFS_FD_BASE);
10742  break;
10743 #endif
10744 #ifdef MG_FS_SLFS
10745  case FD_SLFS:
10746  r = fs_slfs_close(fd - SLFS_FD_BASE);
10747  break;
10748 #endif
10749  }
10750  DBG(("close(%d) = %d", fd, r));
10751  return r;
10752  }
10753 
10754  off_t _lseek(int fd, off_t offset, int whence) {
10755  int r = -1;
10756  switch (fd_type(fd)) {
10757  case FD_INVALID:
10758  r = set_errno(EBADF);
10759  break;
10760  case FD_SYS:
10761  r = set_errno(ESPIPE);
10762  break;
10763 #ifdef CC3200_FS_SPIFFS
10764  case FD_SPIFFS:
10765  r = fs_spiffs_lseek(fd - SPIFFS_FD_BASE, offset, whence);
10766  break;
10767 #endif
10768 #ifdef MG_FS_SLFS
10769  case FD_SLFS:
10770  r = fs_slfs_lseek(fd - SLFS_FD_BASE, offset, whence);
10771  break;
10772 #endif
10773  }
10774  DBG(("lseek(%d, %d, %d) = %d", fd, (int) offset, whence, r));
10775  return r;
10776  }
10777 
10778  int _fstat(int fd, struct stat *s) {
10779  int r = -1;
10780  memset(s, 0, sizeof(*s));
10781  switch (fd_type(fd)) {
10782  case FD_INVALID:
10783  r = set_errno(EBADF);
10784  break;
10785  case FD_SYS: {
10786  /* Create barely passable stats for STD{IN,OUT,ERR}. */
10787  memset(s, 0, sizeof(*s));
10788  s->st_ino = fd;
10789  s->st_mode = S_IFCHR | 0666;
10790  r = 0;
10791  break;
10792  }
10793 #ifdef CC3200_FS_SPIFFS
10794  case FD_SPIFFS:
10795  r = fs_spiffs_fstat(fd - SPIFFS_FD_BASE, s);
10796  break;
10797 #endif
10798 #ifdef MG_FS_SLFS
10799  case FD_SLFS:
10800  r = fs_slfs_fstat(fd - SLFS_FD_BASE, s);
10801  break;
10802 #endif
10803  }
10804  DBG(("fstat(%d) = %d", fd, r));
10805  return r;
10806  }
10807 
10808  ssize_t _read(int fd, void *buf, size_t count) {
10809  int r = -1;
10810  switch (fd_type(fd)) {
10811  case FD_INVALID:
10812  r = set_errno(EBADF);
10813  break;
10814  case FD_SYS: {
10815  if (fd != 0) {
10816  r = set_errno(EACCES);
10817  break;
10818  }
10819  /* Should we allow reading from stdin = uart? */
10820  r = set_errno(ENOTSUP);
10821  break;
10822  }
10823 #ifdef CC3200_FS_SPIFFS
10824  case FD_SPIFFS:
10825  r = fs_spiffs_read(fd - SPIFFS_FD_BASE, buf, count);
10826  break;
10827 #endif
10828 #ifdef MG_FS_SLFS
10829  case FD_SLFS:
10830  r = fs_slfs_read(fd - SLFS_FD_BASE, buf, count);
10831  break;
10832 #endif
10833  }
10834  DBG(("read(%d, %u) = %d", fd, count, r));
10835  return r;
10836  }
10837 
10838  ssize_t _write(int fd, const void *buf, size_t count) {
10839  int r = -1;
10840  size_t i = 0;
10841  switch (fd_type(fd)) {
10842  case FD_INVALID:
10843  r = set_errno(EBADF);
10844  break;
10845  case FD_SYS: {
10846  if (fd == 0) {
10847  r = set_errno(EACCES);
10848  break;
10849  }
10850 #if CS_PLATFORM == CS_P_CC3200
10851  for (i = 0; i < count; i++) {
10852  const char c = ((const char *) buf)[i];
10853  if (c == '\n') MAP_UARTCharPut(CONSOLE_UART, '\r');
10854  MAP_UARTCharPut(CONSOLE_UART, c);
10855  }
10856 #else
10857  (void) i;
10858 #endif
10859  r = count;
10860  break;
10861  }
10862 #ifdef CC3200_FS_SPIFFS
10863  case FD_SPIFFS:
10864  r = fs_spiffs_write(fd - SPIFFS_FD_BASE, buf, count);
10865  break;
10866 #endif
10867 #ifdef MG_FS_SLFS
10868  case FD_SLFS:
10869  r = fs_slfs_write(fd - SLFS_FD_BASE, buf, count);
10870  break;
10871 #endif
10872  }
10873  return r;
10874  }
10875 
10876  int _rename(const char *from, const char *to) {
10877  int r = -1;
10878  from = drop_dir(from);
10879  to = drop_dir(to);
10880  if (is_sl_fname(from) || is_sl_fname(to)) {
10881 #ifdef MG_FS_SLFS
10882  r = fs_slfs_rename(sl_fname(from), sl_fname(to));
10883 #endif
10884  } else {
10885 #ifdef CC3200_FS_SPIFFS
10886  r = fs_spiffs_rename(from, to);
10887 #endif
10888  }
10889  DBG(("rename(%s, %s) = %d", from, to, r));
10890  return r;
10891  }
10892 
10893  int _link(const char *from, const char *to) {
10894  DBG(("link(%s, %s)", from, to));
10895  return set_errno(ENOTSUP);
10896  }
10897 
10898  int _unlink(const char *filename) {
10899  int r = -1;
10900  filename = drop_dir(filename);
10901  if (is_sl_fname(filename)) {
10902 #ifdef MG_FS_SLFS
10903  r = fs_slfs_unlink(sl_fname(filename));
10904 #endif
10905  } else {
10906 #ifdef CC3200_FS_SPIFFS
10907  r = fs_spiffs_unlink(filename);
10908 #endif
10909  }
10910  DBG(("unlink(%s) = %d", filename, r));
10911  return r;
10912  }
10913 
10914 #ifdef CC3200_FS_SPIFFS /* FailFS does not support listing files. */
10915  DIR *opendir(const char *dir_name) {
10916  DIR *r = NULL;
10917  if (is_sl_fname(dir_name)) {
10918  r = NULL;
10919  set_errno(ENOTSUP);
10920  } else {
10921  r = fs_spiffs_opendir(dir_name);
10922  }
10923  DBG(("opendir(%s) = %p", dir_name, r));
10924  return r;
10925  }
10926 
10927  struct dirent *readdir(DIR *dir) {
10928  struct dirent *res = fs_spiffs_readdir(dir);
10929  DBG(("readdir(%p) = %p", dir, res));
10930  return res;
10931  }
10932 
10933  int closedir(DIR *dir) {
10934  int res = fs_spiffs_closedir(dir);
10935  DBG(("closedir(%p) = %d", dir, res));
10936  return res;
10937  }
10938 
10939  int rmdir(const char *path) {
10940  return fs_spiffs_rmdir(path);
10941  }
10942 
10943  int mkdir(const char *path, mode_t mode) {
10944  (void) path;
10945  (void) mode;
10946  /* for spiffs supports only root dir, which comes from mongoose as '.' */
10947  return (strlen(path) == 1 && *path == '.') ? 0 : ENOTDIR;
10948  }
10949 #endif
10950 
10951  int sl_fs_init() {
10952  int ret = 1;
10953 #ifdef __TI_COMPILER_VERSION__
10954 #ifdef MG_FS_SLFS
10955 #pragma diag_push
10956 #pragma diag_suppress 169 /* Nothing we can do about the prototype mismatch. */
10957  ret = (add_device("SL", _MSA, fs_slfs_open, fs_slfs_close, fs_slfs_read,
10958  fs_slfs_write, fs_slfs_lseek, fs_slfs_unlink,
10959  fs_slfs_rename) == 0);
10960 #pragma diag_pop
10961 #endif
10962 #endif
10963  return ret;
10964  }
10965 
10966 #endif /* defined(MG_SOCKET_SIMPLELINK) && (defined(MG_FS_SLFS) || \
10967 defined(MG_FS_SPIFFS)) */
10968 #ifdef MG_MODULE_LINES
10969 #line 1 "./src/../../common/platforms/simplelink/sl_socket.c"
10970 #endif
10971  /*
10972  * Copyright (c) 2014-2016 Cesanta Software Limited
10973  * All rights reserved
10974  */
10975 
10976 #ifdef MG_SOCKET_SIMPLELINK
10977 
10978 #include <errno.h>
10979 #include <stdio.h>
10980 
10981  /* Amalgamated: #include "common/platform.h" */
10982 
10983 #include <simplelink/include/netapp.h>
10984 
10985  const char *inet_ntop(int af, const void *src, char *dst, socklen_t size) {
10986  int res;
10987  struct in_addr *in = (struct in_addr *) src;
10988  if (af != AF_INET) {
10989  errno = EAFNOSUPPORT;
10990  return NULL;
10991  }
10992  res = snprintf(dst, size, "%lu.%lu.%lu.%lu", SL_IPV4_BYTE(in->s_addr, 0),
10993  SL_IPV4_BYTE(in->s_addr, 1), SL_IPV4_BYTE(in->s_addr, 2),
10994  SL_IPV4_BYTE(in->s_addr, 3));
10995  return res > 0 ? dst : NULL;
10996  }
10997 
10998  char *inet_ntoa(struct in_addr n) {
10999  static char a[16];
11000  return (char *) inet_ntop(AF_INET, &n, a, sizeof(n));
11001  }
11002 
11003  int inet_pton(int af, const char *src, void *dst) {
11004  uint32_t a0, a1, a2, a3;
11005  uint8_t *db = (uint8_t *) dst;
11006  if (af != AF_INET) {
11007  errno = EAFNOSUPPORT;
11008  return 0;
11009  }
11010  if (sscanf(src, "%lu.%lu.%lu.%lu", &a0, &a1, &a2, &a3) != 4) {
11011  return 0;
11012  }
11013  *db = a3;
11014  *(db + 1) = a2;
11015  *(db + 2) = a1;
11016  *(db + 3) = a0;
11017  return 1;
11018  }
11019 
11020 #endif /* CS_COMMON_PLATFORMS_SIMPLELINK_SL_SOCKET_C_ */
11021 #ifdef MG_MODULE_LINES
11022 #line 1 "./src/../../common/platforms/simplelink/sl_mg_task.c"
11023 #endif
11024 #if defined(MG_SOCKET_SIMPLELINK)
11025 
11026  /* Amalgamated: #include "mg_task.h" */
11027 
11028 #include <oslib/osi.h>
11029 
11030  enum mg_q_msg_type {
11031  MG_Q_MSG_CB,
11032  };
11033  struct mg_q_msg {
11034  enum mg_q_msg_type type;
11035  void (*cb)(struct mg_mgr *mgr, void *arg);
11036  void *arg;
11037  };
11038  static OsiMsgQ_t s_mg_q;
11039  static void mg_task(void *arg);
11040 
11041  bool mg_start_task(int priority, int stack_size, mg_init_cb mg_init) {
11042  if (osi_MsgQCreate(&s_mg_q, "MG", sizeof(struct mg_q_msg), 16) != OSI_OK) {
11043  return false;
11044  }
11045  if (osi_TaskCreate(mg_task, (const signed char *) "MG", stack_size,
11046  (void *) mg_init, priority, NULL) != OSI_OK) {
11047  return false;
11048  }
11049  return true;
11050  }
11051 
11052  static void mg_task(void *arg) {
11053  struct mg_mgr mgr;
11054  mg_init_cb mg_init = (mg_init_cb) arg;
11055  mg_mgr_init(&mgr, NULL);
11056  mg_init(&mgr);
11057  while (1) {
11058  struct mg_q_msg msg;
11059  mg_mgr_poll(&mgr, 1);
11060  if (osi_MsgQRead(&s_mg_q, &msg, 1) != OSI_OK) continue;
11061  switch (msg.type) {
11062  case MG_Q_MSG_CB: {
11063  msg.cb(&mgr, msg.arg);
11064  }
11065  }
11066  }
11067  }
11068 
11069  void mg_run_in_task(void (*cb)(struct mg_mgr *mgr, void *arg), void *cb_arg) {
11070  struct mg_q_msg msg = {MG_Q_MSG_CB, cb, cb_arg};
11071  osi_MsgQWrite(&s_mg_q, &msg, OSI_NO_WAIT);
11072  }
11073 
11074 #endif /* defined(MG_SOCKET_SIMPLELINK) */