File indexing completed on 2025-08-02 08:21:05
0001 #include "mongoose.h"
0002 #ifdef MG_MODULE_LINES
0003 #line 1 "./src/internal.h"
0004 #endif
0005
0006
0007
0008
0009
0010 #ifndef CS_MONGOOSE_SRC_INTERNAL_H_
0011 #define CS_MONGOOSE_SRC_INTERNAL_H_
0012
0013 #ifndef MG_MALLOC
0014 #define MG_MALLOC malloc
0015 #endif
0016
0017 #ifndef MG_CALLOC
0018 #define MG_CALLOC calloc
0019 #endif
0020
0021 #ifndef MG_REALLOC
0022 #define MG_REALLOC realloc
0023 #endif
0024
0025 #ifndef MG_FREE
0026 #define MG_FREE free
0027 #endif
0028
0029 #ifndef MBUF_REALLOC
0030 #define MBUF_REALLOC MG_REALLOC
0031 #endif
0032
0033 #ifndef MBUF_FREE
0034 #define MBUF_FREE MG_FREE
0035 #endif
0036
0037 #define MG_SET_PTRPTR(_ptr, _v) \
0038 do { \
0039 if (_ptr) *(_ptr) = _v; \
0040 } while (0)
0041
0042 #ifndef MG_INTERNAL
0043 #define MG_INTERNAL static
0044 #endif
0045
0046 #ifdef PICOTCP
0047 #define NO_LIBC
0048 #define MG_DISABLE_FILESYSTEM
0049 #define MG_DISABLE_POPEN
0050 #define MG_DISABLE_CGI
0051 #define MG_DISABLE_DIRECTORY_LISTING
0052 #define MG_DISABLE_SOCKETPAIR
0053 #define MG_DISABLE_PFS
0054 #endif
0055
0056
0057
0058
0059 #define MG_CTL_MSG_MESSAGE_SIZE 8192
0060
0061
0062 MG_INTERNAL struct mg_connection *mg_do_connect(struct mg_connection *nc,
0063 int proto,
0064 union socket_address *sa);
0065
0066 MG_INTERNAL int mg_parse_address(const char *str, union socket_address *sa,
0067 int *proto, char *host, size_t host_len);
0068 MG_INTERNAL void mg_call(struct mg_connection *nc,
0069 mg_event_handler_t ev_handler, int ev, void *ev_data);
0070 void mg_forward(struct mg_connection *from, struct mg_connection *to);
0071 MG_INTERNAL void mg_add_conn(struct mg_mgr *mgr, struct mg_connection *c);
0072 MG_INTERNAL void mg_remove_conn(struct mg_connection *c);
0073 MG_INTERNAL struct mg_connection *mg_create_connection(
0074 struct mg_mgr *mgr, mg_event_handler_t callback,
0075 struct mg_add_sock_opts opts);
0076 #ifndef MG_DISABLE_FILESYSTEM
0077 MG_INTERNAL int mg_uri_to_local_path(struct http_message *hm,
0078 const struct mg_serve_http_opts *opts,
0079 char **local_path,
0080 struct mg_str *remainder);
0081 #endif
0082 #ifdef _WIN32
0083
0084 int to_wchar(const char *path, wchar_t *wbuf, size_t wbuf_len);
0085 #endif
0086
0087
0088
0089
0090
0091
0092
0093
0094
0095
0096
0097
0098 MG_INTERNAL size_t mg_handle_chunked(struct mg_connection *nc,
0099 struct http_message *hm, char *buf,
0100 size_t blen);
0101
0102 #ifndef MG_DISABLE_FILESYSTEM
0103 MG_INTERNAL time_t mg_parse_date_string(const char *datetime);
0104 MG_INTERNAL int mg_is_not_modified(struct http_message *hm, cs_stat_t *st);
0105 #endif
0106
0107 struct ctl_msg {
0108 mg_event_handler_t callback;
0109 char message[MG_CTL_MSG_MESSAGE_SIZE];
0110 };
0111
0112 #ifndef MG_DISABLE_MQTT
0113 struct mg_mqtt_message;
0114 MG_INTERNAL int parse_mqtt(struct mbuf *io, struct mg_mqtt_message *mm);
0115 #endif
0116
0117
0118 extern void *(*test_malloc)(size_t size);
0119 extern void *(*test_calloc)(size_t count, size_t size);
0120
0121 #endif
0122 #ifdef MG_MODULE_LINES
0123 #line 1 "./src/../../common/base64.c"
0124 #endif
0125
0126
0127
0128
0129
0130 #ifndef EXCLUDE_COMMON
0131
0132
0133 #include <string.h>
0134
0135
0136
0137 #define NUM_UPPERCASES ('Z' - 'A' + 1)
0138 #define NUM_LETTERS (NUM_UPPERCASES * 2)
0139 #define NUM_DIGITS ('9' - '0' + 1)
0140
0141
0142
0143
0144
0145
0146 static void cs_base64_emit_code(struct cs_base64_ctx *ctx, int v) {
0147 if (v < NUM_UPPERCASES) {
0148 ctx->b64_putc(v + 'A', ctx->user_data);
0149 } else if (v < (NUM_LETTERS)) {
0150 ctx->b64_putc(v - NUM_UPPERCASES + 'a', ctx->user_data);
0151 } else if (v < (NUM_LETTERS + NUM_DIGITS)) {
0152 ctx->b64_putc(v - NUM_LETTERS + '0', ctx->user_data);
0153 } else {
0154 ctx->b64_putc(v - NUM_LETTERS - NUM_DIGITS == 0 ? '+' : '/',
0155 ctx->user_data);
0156 }
0157 }
0158
0159 static void cs_base64_emit_chunk(struct cs_base64_ctx *ctx) {
0160 int a, b, c;
0161
0162 a = ctx->chunk[0];
0163 b = ctx->chunk[1];
0164 c = ctx->chunk[2];
0165
0166 cs_base64_emit_code(ctx, a >> 2);
0167 cs_base64_emit_code(ctx, ((a & 3) << 4) | (b >> 4));
0168 if (ctx->chunk_size > 1) {
0169 cs_base64_emit_code(ctx, (b & 15) << 2 | (c >> 6));
0170 }
0171 if (ctx->chunk_size > 2) {
0172 cs_base64_emit_code(ctx, c & 63);
0173 }
0174 }
0175
0176 void cs_base64_init(struct cs_base64_ctx *ctx, cs_base64_putc_t b64_putc,
0177 void *user_data) {
0178 ctx->chunk_size = 0;
0179 ctx->b64_putc = b64_putc;
0180 ctx->user_data = user_data;
0181 }
0182
0183 void cs_base64_update(struct cs_base64_ctx *ctx, const char *str, size_t len) {
0184 const unsigned char *src = (const unsigned char *) str;
0185 size_t i;
0186 for (i = 0; i < len; i++) {
0187 ctx->chunk[ctx->chunk_size++] = src[i];
0188 if (ctx->chunk_size == 3) {
0189 cs_base64_emit_chunk(ctx);
0190 ctx->chunk_size = 0;
0191 }
0192 }
0193 }
0194
0195 void cs_base64_finish(struct cs_base64_ctx *ctx) {
0196 if (ctx->chunk_size > 0) {
0197 int i;
0198 memset(&ctx->chunk[ctx->chunk_size], 0, 3 - ctx->chunk_size);
0199 cs_base64_emit_chunk(ctx);
0200 for (i = 0; i < (3 - ctx->chunk_size); i++) {
0201 ctx->b64_putc('=', ctx->user_data);
0202 }
0203 }
0204 }
0205
0206 #define BASE64_ENCODE_BODY \
0207 static const char *b64 = \
0208 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; \
0209 int i, j, a, b, c; \
0210 \
0211 for (i = j = 0; i < src_len; i += 3) { \
0212 a = src[i]; \
0213 b = i + 1 >= src_len ? 0 : src[i + 1]; \
0214 c = i + 2 >= src_len ? 0 : src[i + 2]; \
0215 \
0216 BASE64_OUT(b64[a >> 2]); \
0217 BASE64_OUT(b64[((a & 3) << 4) | (b >> 4)]); \
0218 if (i + 1 < src_len) { \
0219 BASE64_OUT(b64[(b & 15) << 2 | (c >> 6)]); \
0220 } \
0221 if (i + 2 < src_len) { \
0222 BASE64_OUT(b64[c & 63]); \
0223 } \
0224 } \
0225 \
0226 while (j % 4 != 0) { \
0227 BASE64_OUT('='); \
0228 } \
0229 BASE64_FLUSH()
0230
0231 #define BASE64_OUT(ch) \
0232 do { \
0233 dst[j++] = (ch); \
0234 } while (0)
0235
0236 #define BASE64_FLUSH() \
0237 do { \
0238 dst[j++] = '\0'; \
0239 } while (0)
0240
0241 void cs_base64_encode(const unsigned char *src, int src_len, char *dst) {
0242 BASE64_ENCODE_BODY;
0243 }
0244
0245 #undef BASE64_OUT
0246 #undef BASE64_FLUSH
0247
0248 #ifndef CS_DISABLE_STDIO
0249 #define BASE64_OUT(ch) \
0250 do { \
0251 fprintf(f, "%c", (ch)); \
0252 j++; \
0253 } while (0)
0254
0255 #define BASE64_FLUSH()
0256
0257 void cs_fprint_base64(FILE *f, const unsigned char *src, int src_len) {
0258 BASE64_ENCODE_BODY;
0259 }
0260
0261 #undef BASE64_OUT
0262 #undef BASE64_FLUSH
0263 #endif
0264
0265
0266 static unsigned char from_b64(unsigned char ch) {
0267
0268 static const unsigned char tab[128] = {
0269 255, 255, 255, 255,
0270 255, 255, 255, 255,
0271 255, 255, 255, 255,
0272 255, 255, 255, 255,
0273 255, 255, 255, 255,
0274 255, 255, 255, 255,
0275 255, 255, 255, 255,
0276 255, 255, 255, 255,
0277 255, 255, 255, 255,
0278 255, 255, 255, 255,
0279 255, 255, 255, 62,
0280 255, 255, 255, 63,
0281 52, 53, 54, 55,
0282 56, 57, 58, 59,
0283 60, 61, 255, 255,
0284 255, 200, 255, 255,
0285 255, 0, 1, 2,
0286 3, 4, 5, 6,
0287 7, 8, 9, 10,
0288 11, 12, 13, 14,
0289 15, 16, 17, 18,
0290 19, 20, 21, 22,
0291 23, 24, 25, 255,
0292 255, 255, 255, 255,
0293 255, 26, 27, 28,
0294 29, 30, 31, 32,
0295 33, 34, 35, 36,
0296 37, 38, 39, 40,
0297 41, 42, 43, 44,
0298 45, 46, 47, 48,
0299 49, 50, 51, 255,
0300 255, 255, 255, 255,
0301 };
0302 return tab[ch & 127];
0303 }
0304
0305 int cs_base64_decode(const unsigned char *s, int len, char *dst) {
0306 unsigned char a, b, c, d;
0307 int orig_len = len;
0308 while (len >= 4 && (a = from_b64(s[0])) != 255 &&
0309 (b = from_b64(s[1])) != 255 && (c = from_b64(s[2])) != 255 &&
0310 (d = from_b64(s[3])) != 255) {
0311 s += 4;
0312 len -= 4;
0313 if (a == 200 || b == 200) break;
0314 *dst++ = a << 2 | b >> 4;
0315 if (c == 200) break;
0316 *dst++ = b << 4 | c >> 2;
0317 if (d == 200) break;
0318 *dst++ = c << 6 | d;
0319 }
0320 *dst = 0;
0321 return orig_len - len;
0322 }
0323
0324 #endif
0325 #ifdef MG_MODULE_LINES
0326 #line 1 "./src/../../common/cs_dbg.c"
0327 #endif
0328
0329
0330
0331
0332
0333
0334
0335 #include <stdarg.h>
0336 #include <stdio.h>
0337
0338
0339
0340 enum cs_log_level cs_log_level =
0341 #ifdef CS_ENABLE_DEBUG
0342 LL_VERBOSE_DEBUG;
0343 #else
0344 LL_ERROR;
0345 #endif
0346
0347 #ifndef CS_DISABLE_STDIO
0348
0349 FILE *cs_log_file = NULL;
0350
0351 #ifdef CS_LOG_TS_DIFF
0352 double cs_log_ts;
0353 #endif
0354
0355 void cs_log_print_prefix(const char *func) {
0356 if (cs_log_file == NULL) cs_log_file = stderr;
0357 fprintf(cs_log_file, "%-20s ", func);
0358 #ifdef CS_LOG_TS_DIFF
0359 {
0360 double now = cs_time();
0361 fprintf(cs_log_file, "%7u ", (unsigned int) ((now - cs_log_ts) * 1000000));
0362 cs_log_ts = now;
0363 }
0364 #endif
0365 }
0366
0367 void cs_log_printf(const char *fmt, ...) {
0368 va_list ap;
0369 va_start(ap, fmt);
0370 vfprintf(cs_log_file, fmt, ap);
0371 va_end(ap);
0372 fputc('\n', cs_log_file);
0373 fflush(cs_log_file);
0374 }
0375
0376 void cs_log_set_file(FILE *file) {
0377 cs_log_file = file;
0378 }
0379
0380 #endif
0381
0382 void cs_log_set_level(enum cs_log_level level) {
0383 cs_log_level = level;
0384 #if defined(CS_LOG_TS_DIFF) && !defined(CS_DISABLE_STDIO)
0385 cs_log_ts = cs_time();
0386 #endif
0387 }
0388 #ifdef MG_MODULE_LINES
0389 #line 1 "./src/../../common/cs_dirent.h"
0390 #endif
0391
0392
0393
0394
0395
0396 #ifndef CS_COMMON_CS_DIRENT_H_
0397 #define CS_COMMON_CS_DIRENT_H_
0398
0399 #ifdef __cplusplus
0400 extern "C" {
0401 #endif
0402
0403 #ifdef CS_ENABLE_SPIFFS
0404
0405 #include <spiffs.h>
0406
0407 typedef struct {
0408 spiffs_DIR dh;
0409 struct spiffs_dirent de;
0410 } DIR;
0411
0412 #define d_name name
0413 #define dirent spiffs_dirent
0414
0415 int rmdir(const char *path);
0416 int mkdir(const char *path, mode_t mode);
0417
0418 #endif
0419
0420 #if defined(_WIN32)
0421 struct dirent {
0422 char d_name[MAX_PATH];
0423 };
0424
0425 typedef struct DIR {
0426 HANDLE handle;
0427 WIN32_FIND_DATAW info;
0428 struct dirent result;
0429 } DIR;
0430 #endif
0431
0432 #if defined(_WIN32) || defined(CS_ENABLE_SPIFFS)
0433 DIR *opendir(const char *dir_name);
0434 int closedir(DIR *dir);
0435 struct dirent *readdir(DIR *dir);
0436 #endif
0437
0438 #ifdef __cplusplus
0439 }
0440 #endif
0441
0442 #endif
0443 #ifdef MG_MODULE_LINES
0444 #line 1 "./src/../../common/cs_dirent.c"
0445 #endif
0446
0447
0448
0449
0450
0451 #ifndef EXCLUDE_COMMON
0452
0453
0454
0455
0456
0457
0458
0459
0460 #ifndef MG_FREE
0461 #define MG_FREE free
0462 #endif
0463
0464 #ifndef MG_MALLOC
0465 #define MG_MALLOC malloc
0466 #endif
0467
0468 #ifdef _WIN32
0469 DIR *opendir(const char *name) {
0470 DIR *dir = NULL;
0471 wchar_t wpath[MAX_PATH];
0472 DWORD attrs;
0473
0474 if (name == NULL) {
0475 SetLastError(ERROR_BAD_ARGUMENTS);
0476 } else if ((dir = (DIR *) MG_MALLOC(sizeof(*dir))) == NULL) {
0477 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
0478 } else {
0479 to_wchar(name, wpath, ARRAY_SIZE(wpath));
0480 attrs = GetFileAttributesW(wpath);
0481 if (attrs != 0xFFFFFFFF && (attrs & FILE_ATTRIBUTE_DIRECTORY)) {
0482 (void) wcscat(wpath, L"\\*");
0483 dir->handle = FindFirstFileW(wpath, &dir->info);
0484 dir->result.d_name[0] = '\0';
0485 } else {
0486 MG_FREE(dir);
0487 dir = NULL;
0488 }
0489 }
0490
0491 return dir;
0492 }
0493
0494 int closedir(DIR *dir) {
0495 int result = 0;
0496
0497 if (dir != NULL) {
0498 if (dir->handle != INVALID_HANDLE_VALUE)
0499 result = FindClose(dir->handle) ? 0 : -1;
0500 MG_FREE(dir);
0501 } else {
0502 result = -1;
0503 SetLastError(ERROR_BAD_ARGUMENTS);
0504 }
0505
0506 return result;
0507 }
0508
0509 struct dirent *readdir(DIR *dir) {
0510 struct dirent *result = NULL;
0511
0512 if (dir) {
0513 if (dir->handle != INVALID_HANDLE_VALUE) {
0514 result = &dir->result;
0515 (void) WideCharToMultiByte(CP_UTF8, 0, dir->info.cFileName, -1,
0516 result->d_name, sizeof(result->d_name), NULL,
0517 NULL);
0518
0519 if (!FindNextFileW(dir->handle, &dir->info)) {
0520 (void) FindClose(dir->handle);
0521 dir->handle = INVALID_HANDLE_VALUE;
0522 }
0523
0524 } else {
0525 SetLastError(ERROR_FILE_NOT_FOUND);
0526 }
0527 } else {
0528 SetLastError(ERROR_BAD_ARGUMENTS);
0529 }
0530
0531 return result;
0532 }
0533 #endif
0534
0535 #ifdef CS_ENABLE_SPIFFS
0536
0537 DIR *opendir(const char *dir_name) {
0538 DIR *dir = NULL;
0539 extern spiffs fs;
0540
0541 if (dir_name != NULL && (dir = (DIR *) malloc(sizeof(*dir))) != NULL &&
0542 SPIFFS_opendir(&fs, (char *) dir_name, &dir->dh) == NULL) {
0543 free(dir);
0544 dir = NULL;
0545 }
0546
0547 return dir;
0548 }
0549
0550 int closedir(DIR *dir) {
0551 if (dir != NULL) {
0552 SPIFFS_closedir(&dir->dh);
0553 free(dir);
0554 }
0555 return 0;
0556 }
0557
0558 struct dirent *readdir(DIR *dir) {
0559 return SPIFFS_readdir(&dir->dh, &dir->de);
0560 }
0561
0562
0563 int rmdir(const char *path) {
0564 (void) path;
0565 return ENOTDIR;
0566 }
0567
0568 int mkdir(const char *path, mode_t mode) {
0569 (void) path;
0570 (void) mode;
0571
0572 return (strlen(path) == 1 && *path == '.') ? 0 : ENOTDIR;
0573 }
0574
0575 #endif
0576
0577 #endif
0578
0579
0580 typedef int cs_dirent_dummy;
0581 #ifdef MG_MODULE_LINES
0582 #line 1 "./src/../../common/cs_time.c"
0583 #endif
0584
0585
0586
0587
0588
0589
0590
0591 #ifndef _WIN32
0592 #include <stddef.h>
0593 #if !defined(CS_PLATFORM) || \
0594 (CS_PLATFORM != CS_P_CC3200 && CS_PLATFORM != CS_P_MSP432)
0595 #include <sys/time.h>
0596 #endif
0597 #else
0598 #include <windows.h>
0599 #endif
0600
0601 double cs_time() {
0602 double now;
0603 #ifndef _WIN32
0604 struct timeval tv;
0605 if (gettimeofday(&tv, NULL ) != 0) return 0;
0606 now = (double) tv.tv_sec + (((double) tv.tv_usec) / 1000000.0);
0607 #else
0608 now = GetTickCount() / 1000.0;
0609 #endif
0610 return now;
0611 }
0612 #ifdef MG_MODULE_LINES
0613 #line 1 "./src/../deps/frozen/frozen.c"
0614 #endif
0615
0616
0617
0618
0619
0620
0621
0622
0623
0624
0625
0626
0627
0628
0629
0630
0631
0632
0633
0634 #ifndef _CRT_SECURE_NO_WARNINGS
0635 #define _CRT_SECURE_NO_WARNINGS
0636 #endif
0637
0638 #include <stdio.h>
0639 #include <stdlib.h>
0640 #include <string.h>
0641 #include <stdarg.h>
0642
0643
0644 #ifdef _WIN32
0645 #define snprintf _snprintf
0646 #endif
0647
0648 #ifndef FROZEN_REALLOC
0649 #define FROZEN_REALLOC realloc
0650 #endif
0651
0652 #ifndef FROZEN_FREE
0653 #define FROZEN_FREE free
0654 #endif
0655
0656 struct frozen {
0657 const char *end;
0658 const char *cur;
0659 struct json_token *tokens;
0660 int max_tokens;
0661 int num_tokens;
0662 int do_realloc;
0663 };
0664
0665 static int parse_object(struct frozen *f);
0666 static int parse_value(struct frozen *f);
0667
0668 #define EXPECT(cond, err_code) \
0669 do { \
0670 if (!(cond)) return (err_code); \
0671 } while (0)
0672 #define TRY(expr) \
0673 do { \
0674 int _n = expr; \
0675 if (_n < 0) return _n; \
0676 } while (0)
0677 #define END_OF_STRING (-1)
0678
0679 static int left(const struct frozen *f) {
0680 return f->end - f->cur;
0681 }
0682
0683 static int is_space(int ch) {
0684 return ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n';
0685 }
0686
0687 static void skip_whitespaces(struct frozen *f) {
0688 while (f->cur < f->end && is_space(*f->cur)) f->cur++;
0689 }
0690
0691 static int cur(struct frozen *f) {
0692 skip_whitespaces(f);
0693 return f->cur >= f->end ? END_OF_STRING : *(unsigned char *) f->cur;
0694 }
0695
0696 static int test_and_skip(struct frozen *f, int expected) {
0697 int ch = cur(f);
0698 if (ch == expected) {
0699 f->cur++;
0700 return 0;
0701 }
0702 return ch == END_OF_STRING ? JSON_STRING_INCOMPLETE : JSON_STRING_INVALID;
0703 }
0704
0705 static int test_no_skip(struct frozen *f, int expected) {
0706 int ch = cur(f);
0707 if (ch == expected) {
0708 return 0;
0709 }
0710 return ch == END_OF_STRING ? JSON_STRING_INCOMPLETE : JSON_STRING_INVALID;
0711 }
0712
0713 static int is_alpha(int ch) {
0714 return (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z');
0715 }
0716
0717 static int is_digit(int ch) {
0718 return ch >= '0' && ch <= '9';
0719 }
0720
0721 static int is_hex_digit(int ch) {
0722 return is_digit(ch) || (ch >= 'a' && ch <= 'f') || (ch >= 'A' && ch <= 'F');
0723 }
0724
0725 static int get_escape_len(const char *s, int len) {
0726 switch (*s) {
0727 case 'u':
0728 return len < 6 ? JSON_STRING_INCOMPLETE
0729 : is_hex_digit(s[1]) && is_hex_digit(s[2]) &&
0730 is_hex_digit(s[3]) && is_hex_digit(s[4])
0731 ? 5
0732 : JSON_STRING_INVALID;
0733 case '"':
0734 case '\\':
0735 case '/':
0736 case 'b':
0737 case 'f':
0738 case 'n':
0739 case 'r':
0740 case 't':
0741 return len < 2 ? JSON_STRING_INCOMPLETE : 1;
0742 default:
0743 return JSON_STRING_INVALID;
0744 }
0745 }
0746
0747 static int capture_ptr(struct frozen *f, const char *ptr, enum json_type type) {
0748 if (f->do_realloc && f->num_tokens >= f->max_tokens) {
0749 int new_size = f->max_tokens == 0 ? 100 : f->max_tokens * 2;
0750 void *p = FROZEN_REALLOC(f->tokens, new_size * sizeof(f->tokens[0]));
0751 if (p == NULL) return JSON_TOKEN_ARRAY_TOO_SMALL;
0752 f->max_tokens = new_size;
0753 f->tokens = (struct json_token *) p;
0754 }
0755 if (f->tokens == NULL || f->max_tokens == 0) return 0;
0756 if (f->num_tokens >= f->max_tokens) return JSON_TOKEN_ARRAY_TOO_SMALL;
0757 f->tokens[f->num_tokens].ptr = ptr;
0758 f->tokens[f->num_tokens].type = type;
0759 f->num_tokens++;
0760 return 0;
0761 }
0762
0763 static int capture_len(struct frozen *f, int token_index, const char *ptr) {
0764 if (f->tokens == 0 || f->max_tokens == 0) return 0;
0765 EXPECT(token_index >= 0 && token_index < f->max_tokens, JSON_STRING_INVALID);
0766 f->tokens[token_index].len = ptr - f->tokens[token_index].ptr;
0767 f->tokens[token_index].num_desc = (f->num_tokens - 1) - token_index;
0768 return 0;
0769 }
0770
0771
0772 static int parse_identifier(struct frozen *f) {
0773 EXPECT(is_alpha(cur(f)), JSON_STRING_INVALID);
0774 TRY(capture_ptr(f, f->cur, JSON_TYPE_STRING));
0775 while (f->cur < f->end &&
0776 (*f->cur == '_' || is_alpha(*f->cur) || is_digit(*f->cur))) {
0777 f->cur++;
0778 }
0779 capture_len(f, f->num_tokens - 1, f->cur);
0780 return 0;
0781 }
0782
0783 static int get_utf8_char_len(unsigned char ch) {
0784 if ((ch & 0x80) == 0) return 1;
0785 switch (ch & 0xf0) {
0786 case 0xf0:
0787 return 4;
0788 case 0xe0:
0789 return 3;
0790 default:
0791 return 2;
0792 }
0793 }
0794
0795
0796 static int parse_string(struct frozen *f) {
0797 int n, ch = 0, len = 0;
0798 TRY(test_and_skip(f, '"'));
0799 TRY(capture_ptr(f, f->cur, JSON_TYPE_STRING));
0800 for (; f->cur < f->end; f->cur += len) {
0801 ch = *(unsigned char *) f->cur;
0802 len = get_utf8_char_len((unsigned char) ch);
0803 EXPECT(ch >= 32 && len > 0, JSON_STRING_INVALID);
0804 EXPECT(len < left(f), JSON_STRING_INCOMPLETE);
0805 if (ch == '\\') {
0806 EXPECT((n = get_escape_len(f->cur + 1, left(f))) > 0, n);
0807 len += n;
0808 } else if (ch == '"') {
0809 capture_len(f, f->num_tokens - 1, f->cur);
0810 f->cur++;
0811 break;
0812 };
0813 }
0814 return ch == '"' ? 0 : JSON_STRING_INCOMPLETE;
0815 }
0816
0817
0818 static int parse_number(struct frozen *f) {
0819 int ch = cur(f);
0820 TRY(capture_ptr(f, f->cur, JSON_TYPE_NUMBER));
0821 if (ch == '-') f->cur++;
0822 EXPECT(f->cur < f->end, JSON_STRING_INCOMPLETE);
0823 EXPECT(is_digit(f->cur[0]), JSON_STRING_INVALID);
0824 while (f->cur < f->end && is_digit(f->cur[0])) f->cur++;
0825 if (f->cur < f->end && f->cur[0] == '.') {
0826 f->cur++;
0827 EXPECT(f->cur < f->end, JSON_STRING_INCOMPLETE);
0828 EXPECT(is_digit(f->cur[0]), JSON_STRING_INVALID);
0829 while (f->cur < f->end && is_digit(f->cur[0])) f->cur++;
0830 }
0831 if (f->cur < f->end && (f->cur[0] == 'e' || f->cur[0] == 'E')) {
0832 f->cur++;
0833 EXPECT(f->cur < f->end, JSON_STRING_INCOMPLETE);
0834 if ((f->cur[0] == '+' || f->cur[0] == '-')) f->cur++;
0835 EXPECT(f->cur < f->end, JSON_STRING_INCOMPLETE);
0836 EXPECT(is_digit(f->cur[0]), JSON_STRING_INVALID);
0837 while (f->cur < f->end && is_digit(f->cur[0])) f->cur++;
0838 }
0839 capture_len(f, f->num_tokens - 1, f->cur);
0840 return 0;
0841 }
0842
0843
0844 static int parse_array(struct frozen *f) {
0845 int ind;
0846 TRY(test_and_skip(f, '['));
0847 TRY(capture_ptr(f, f->cur - 1, JSON_TYPE_ARRAY));
0848 ind = f->num_tokens - 1;
0849 while (cur(f) != ']') {
0850 TRY(parse_value(f));
0851 if (cur(f) == ',') f->cur++;
0852 }
0853 TRY(test_and_skip(f, ']'));
0854 capture_len(f, ind, f->cur);
0855 return 0;
0856 }
0857
0858 static int compare(const char *s, const char *str, int len) {
0859 int i = 0;
0860 while (i < len && s[i] == str[i]) i++;
0861 return i == len ? 1 : 0;
0862 }
0863
0864 static int expect(struct frozen *f, const char *s, int len, enum json_type t) {
0865 int i, n = left(f);
0866
0867 TRY(capture_ptr(f, f->cur, t));
0868 for (i = 0; i < len; i++) {
0869 if (i >= n) return JSON_STRING_INCOMPLETE;
0870 if (f->cur[i] != s[i]) return JSON_STRING_INVALID;
0871 }
0872 f->cur += len;
0873 TRY(capture_len(f, f->num_tokens - 1, f->cur));
0874
0875 return 0;
0876 }
0877
0878
0879 static int parse_value(struct frozen *f) {
0880 int ch = cur(f);
0881
0882 switch (ch) {
0883 case '"':
0884 TRY(parse_string(f));
0885 break;
0886 case '{':
0887 TRY(parse_object(f));
0888 break;
0889 case '[':
0890 TRY(parse_array(f));
0891 break;
0892 case 'n':
0893 TRY(expect(f, "null", 4, JSON_TYPE_NULL));
0894 break;
0895 case 't':
0896 TRY(expect(f, "true", 4, JSON_TYPE_TRUE));
0897 break;
0898 case 'f':
0899 TRY(expect(f, "false", 5, JSON_TYPE_FALSE));
0900 break;
0901 case '-':
0902 case '0':
0903 case '1':
0904 case '2':
0905 case '3':
0906 case '4':
0907 case '5':
0908 case '6':
0909 case '7':
0910 case '8':
0911 case '9':
0912 TRY(parse_number(f));
0913 break;
0914 default:
0915 return ch == END_OF_STRING ? JSON_STRING_INCOMPLETE : JSON_STRING_INVALID;
0916 }
0917
0918 return 0;
0919 }
0920
0921
0922 static int parse_key(struct frozen *f) {
0923 int ch = cur(f);
0924 #if 0
0925 printf("%s 1 [%.*s]\n", __func__, (int) (f->end - f->cur), f->cur);
0926 #endif
0927 if (is_alpha(ch)) {
0928 TRY(parse_identifier(f));
0929 } else if (ch == '"') {
0930 TRY(parse_string(f));
0931 } else {
0932 return ch == END_OF_STRING ? JSON_STRING_INCOMPLETE : JSON_STRING_INVALID;
0933 }
0934 return 0;
0935 }
0936
0937
0938 static int parse_pair(struct frozen *f) {
0939 TRY(parse_key(f));
0940 TRY(test_and_skip(f, ':'));
0941 TRY(parse_value(f));
0942 return 0;
0943 }
0944
0945
0946 static int parse_object(struct frozen *f) {
0947 int ind;
0948 TRY(test_and_skip(f, '{'));
0949 TRY(capture_ptr(f, f->cur - 1, JSON_TYPE_OBJECT));
0950 ind = f->num_tokens - 1;
0951 while (cur(f) != '}') {
0952 TRY(parse_pair(f));
0953 if (cur(f) == ',') f->cur++;
0954 }
0955 TRY(test_and_skip(f, '}'));
0956 capture_len(f, ind, f->cur);
0957 return 0;
0958 }
0959
0960 static int doit(struct frozen *f) {
0961 int ret = 0;
0962
0963 if (f->cur == 0 || f->end < f->cur) return JSON_STRING_INVALID;
0964 if (f->end == f->cur) return JSON_STRING_INCOMPLETE;
0965
0966 if (0 == (ret = test_no_skip(f, '{'))) {
0967 TRY(parse_object(f));
0968 } else if (0 == (ret = test_no_skip(f, '['))) {
0969 TRY(parse_array(f));
0970 } else {
0971 return ret;
0972 }
0973
0974 TRY(capture_ptr(f, f->cur, JSON_TYPE_EOF));
0975 capture_len(f, f->num_tokens, f->cur);
0976 return 0;
0977 }
0978
0979
0980 int parse_json(const char *s, int s_len, struct json_token *arr, int arr_len) {
0981 struct frozen frozen;
0982
0983 memset(&frozen, 0, sizeof(frozen));
0984 frozen.end = s + s_len;
0985 frozen.cur = s;
0986 frozen.tokens = arr;
0987 frozen.max_tokens = arr_len;
0988
0989 TRY(doit(&frozen));
0990
0991 return frozen.cur - s;
0992 }
0993
0994 struct json_token *parse_json2(const char *s, int s_len) {
0995 struct frozen frozen;
0996
0997 memset(&frozen, 0, sizeof(frozen));
0998 frozen.end = s + s_len;
0999 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;
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
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
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
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229 #if !defined(DISABLE_MD5) && !defined(EXCLUDE_COMMON)
1230
1231
1232
1233 #ifndef CS_ENABLE_NATIVE_MD5
1234 static void byteReverse(unsigned char *buf, unsigned longs) {
1235
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
1259
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
1418
1419
1420
1421
1422
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
1456 #ifdef MG_MODULE_LINES
1457 #line 1 "./src/../../common/mbuf.c"
1458 #endif
1459
1460
1461
1462
1463
1464 #ifndef EXCLUDE_COMMON
1465
1466 #include <assert.h>
1467 #include <string.h>
1468
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
1496
1497
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
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
1553 #ifdef MG_MODULE_LINES
1554 #line 1 "./src/../../common/sha1.c"
1555 #endif
1556
1557
1558
1559 #if !defined(DISABLE_SHA1) && !defined(EXCLUDE_COMMON)
1560
1561
1562
1563 #define SHA1HANDSOFF
1564 #if defined(__sun)
1565
1566 #endif
1567
1568 union char64long16 {
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
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
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
1708
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
1807 #ifdef MG_MODULE_LINES
1808 #line 1 "./src/../../common/str_util.c"
1809 #endif
1810
1811
1812
1813
1814
1815 #ifndef EXCLUDE_COMMON
1816
1817
1818
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
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
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
1869 if (neg) {
1870 tmp[k++] = '-';
1871 }
1872
1873
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 != '%') {
1886 C_SNPRINTF_APPEND_CHAR(ch);
1887 } else {
1888
1889
1890
1891
1892
1893
1894
1895
1896 flags = field_width = precision = len_mod = 0;
1897
1898
1899 if (*fmt == '0') {
1900 flags |= C_SNPRINTF_FLAG_ZERO;
1901 }
1902
1903
1904 while (*fmt >= '0' && *fmt <= '9') {
1905 field_width *= 10;
1906 field_width += *fmt++ - '0';
1907 }
1908
1909 if (*fmt == '*') {
1910 field_width = va_arg(ap, int);
1911 fmt++;
1912 }
1913
1914
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
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 *);
1953 int j;
1954 int pad = field_width - (precision >= 0 ? c_strnlen(s, precision) : 0);
1955 for (j = 0; j < pad; j++) {
1956 C_SNPRINTF_APPEND_CHAR(' ');
1957 }
1958
1959
1960 if (s != NULL) {
1961
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);
1968 C_SNPRINTF_APPEND_CHAR(ch);
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 *);
1994 C_SNPRINTF_APPEND_CHAR('0');
1995 C_SNPRINTF_APPEND_CHAR('x');
1996 i += c_itoa(buf + i, buf_size - i, num, 16, flags, 0);
1997 } else {
1998 #ifndef NO_LIBC
1999
2000
2001
2002
2003 abort();
2004 #endif
2005 }
2006 }
2007 }
2008
2009
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
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
2044
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
2056
2057
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
2076 #ifdef MG_MODULE_LINES
2077 #line 1 "./src/net.c"
2078 #endif
2079
2080
2081
2082
2083
2084
2085
2086
2087
2088
2089
2090
2091
2092
2093
2094
2095
2096
2097
2098
2099
2100
2101
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
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
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
2140 MG_INTERNAL void mg_remove_conn(struct mg_connection *conn) {
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
2147 MG_INTERNAL void mg_call(struct mg_connection *nc,
2148 mg_event_handler_t ev_handler, int ev, void *ev_data) {
2149 if (ev_handler == NULL) {
2150
2151
2152
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
2162 if (nc->mgr->hexdump_file != NULL && ev != MG_EV_POLL &&
2163 ev != MG_EV_SEND ) {
2164 if (ev == MG_EV_RECV) {
2165 mg_hexdump_connection(nc, nc->mgr->hexdump_file, nc->recv_mbuf.buf,
2166 *(int *) ev_data, ev);
2167 } else {
2168 mg_hexdump_connection(nc, nc->mgr->hexdump_file, NULL, 0, ev);
2169 }
2170 }
2171
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
2179 if (ev_handler == nc->handler && nc->flags != flags_before) {
2180 nc->flags = (flags_before & ~_MG_CALLBACK_MODIFIABLE_FLAGS_MASK) |
2181 (nc->flags & _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
2198
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
2249
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
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);
2325 }
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
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
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
2376
2377 MG_INTERNAL struct mg_connection *mg_create_connection_base(
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();
2387 conn->flags = opts.flags & _MG_ALLOWED_CONNECT_FLAGS_MASK;
2388 conn->user_data = opts.user_data;
2389
2390
2391
2392
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
2402 MG_INTERNAL struct mg_connection *mg_create_connection(
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
2418
2419
2420
2421
2422
2423
2424
2425
2426
2427
2428
2429 MG_INTERNAL int mg_parse_address(const char *str, union socket_address *sa,
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
2439
2440
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
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
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
2477 sa->sin.sin_port = htons((uint16_t) port);
2478 } else {
2479 return -1;
2480 }
2481
2482 ch = str[len];
2483 return port < 0xffffUL && (ch == '\0' || ch == ',' || isspace(ch)) ? len : -1;
2484 }
2485
2486 #ifdef MG_ENABLE_SSL
2487
2488
2489
2490
2491
2492 #ifndef MG_DISABLE_PFS
2493
2494
2495
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
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
2538
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
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
2583
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
2604
2605
2606
2607
2608
2609
2610
2611
2612
2613
2614
2615
2616
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
2652
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
2663
2664 struct mg_connection *mg_if_accept_new_conn(struct mg_connection *lc) {
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
2680 void mg_if_accept_tcp_cb(struct mg_connection *nc, union socket_address *sa,
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) {
2703 nc->flags |= MG_F_CLOSE_IMMEDIATELY;
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
2714
2715
2716 MG_FREE(buf);
2717 return;
2718 }
2719 nc->last_io_time = mg_time();
2720 if (nc->recv_mbuf.len == 0) {
2721
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
2744
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
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
2769 }
2770 }
2771 }
2772 if (nc != NULL) {
2773 mg_recv_common(nc, buf, len);
2774 } else {
2775
2776 MG_FREE(buf);
2777 mg_if_recved(nc, len);
2778 }
2779 }
2780
2781
2782
2783
2784
2785
2786
2787 MG_INTERNAL struct mg_connection *mg_do_connect(struct mg_connection *nc,
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) {
2807 nc->flags |= MG_F_CLOSE_IMMEDIATELY;
2808 }
2809 mg_call(nc, NULL, MG_EV_CONNECT, &err);
2810 }
2811
2812 #ifndef MG_DISABLE_RESOLVER
2813
2814
2815
2816
2817
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
2829
2830 for (i = 0; i < msg->num_answers; i++) {
2831 if (msg->answers[i].rtype == MG_DNS_A_RECORD) {
2832
2833
2834
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
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
2881 MG_SET_PTRPTR(opts.error_string, "cannot parse address");
2882 mg_destroy_conn(nc);
2883 return NULL;
2884 }
2885 nc->flags |= opts.flags & _MG_ALLOWED_CONNECT_FLAGS_MASK;
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
2904 MG_SET_PTRPTR(opts.error_string,
2905 "Server name verification requested but is not supported");
2906 mg_destroy_conn(nc);
2907 return NULL;
2908 #endif
2909 }
2910 }
2911 #endif
2912
2913 if (rc == 0) {
2914 #ifndef MG_DISABLE_RESOLVER
2915
2916
2917
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
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
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
3005 void mg_broadcast(struct mg_mgr *mgr, mg_event_handler_t cb, void *data,
3006 size_t len) {
3007 struct ctl_msg ctl_msg;
3008
3009
3010
3011
3012
3013
3014
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;
3026 }
3027 }
3028 #endif
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
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
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
3085
3086
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
3122
3123
3124
3125 #ifndef MG_DISABLE_SOCKET_IF
3126
3127
3128
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
3170 void mg_if_connect_tcp(struct mg_connection *nc,
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)
3179 mg_set_non_blocking_mode(nc->sock);
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
3186 void mg_if_connect_udp(struct mg_connection *nc) {
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
3224 int mg_if_create_conn(struct mg_connection *nc) {
3225 (void) nc;
3226 return 1;
3227 }
3228
3229 void mg_if_destroy_conn(struct mg_connection *nc) {
3230 if (nc->sock == INVALID_SOCKET) return;
3231 if (!(nc->flags & MG_F_UDP)) {
3232 closesocket(nc->sock);
3233 } else {
3234
3235 if (nc->listener == NULL) closesocket(nc->sock);
3236 }
3237
3238
3239
3240
3241
3242
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
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
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)
3292 #if defined(_WIN32) && defined(SO_EXCLUSIVEADDRUSE)
3293
3294 !setsockopt(sock, SOL_SOCKET, SO_EXCLUSIVEADDRUSE, (void *) &on,
3295 sizeof(on)) &&
3296 #endif
3297
3298 #if !defined(_WIN32) || !defined(SO_EXCLUSIVEADDRUSE)
3299
3300
3301
3302
3303
3304
3305
3306
3307
3308 !setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void *) &on, sizeof(on)) &&
3309 #endif
3310 #endif
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)
3316 mg_set_non_blocking_mode(sock);
3317
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
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;
3360 }
3361 } else {
3362
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
3403
3404
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
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,
3425 recv_avail_size(conn, MG_TCP_RECV_BUFFER_SIZE), 0);
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
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
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) {
3489 nc->flags |= MG_F_SSL_HANDSHAKE_DONE;
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 }
3506 nc->flags |= MG_F_CLOSE_IMMEDIATELY;
3507 }
3508 }
3509 }
3510 #endif
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
3532
3533
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
3558
3559
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;
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
3601 void mg_sock_set(struct mg_connection *nc, sock_t sock) {
3602 mg_set_non_blocking_mode(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
3622 void mg_ev_mgr_add_conn(struct mg_connection *nc) {
3623 (void) nc;
3624 }
3625
3626 void mg_ev_mgr_remove_conn(struct mg_connection *nc) {
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
3664
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
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
3710
3711
3712 if (num_timers > 0) {
3713 double timer_timeout_ms = (min_timer - mg_time()) * 1000 + 1 ;
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)) {
3731 mg_mgr_handle_ctl_sock(mgr);
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)
3741 ? _MG_F_FD_CAN_READ
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
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
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);
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
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
3842
3843
3844 if (remote) memcpy(sa, &nc->sa, sizeof(*sa));
3845 #endif
3846 }
3847
3848 #endif
3849 #ifdef MG_MODULE_LINES
3850 #line 1 "./src/multithreading.c"
3851 #endif
3852
3853
3854
3855
3856
3857
3858
3859
3860 #ifdef MG_ENABLE_THREADS
3861
3862 static void multithreaded_ev_handler(struct mg_connection *c, int ev, void *p);
3863
3864
3865
3866
3867
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
3913
3914
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
3922 link_conns(c[0], nc);
3923
3924
3925
3926
3927
3928 mg_add_conn(nc->mgr, c[0]);
3929
3930
3931
3932
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
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
3961
3962
3963
3964
3965
3966
3967
3968
3969
3970
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
4006
4007
4008
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;
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
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
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
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
4117 } else if (mg_vcmp(&component, "..") == 0) {
4118
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
4138
4139
4140
4141 #ifndef MG_DISABLE_HTTP
4142
4143
4144
4145
4146
4147
4148 #ifndef MG_DISABLE_HTTP_WEBSOCKET
4149 #define MG_WS_NO_HOST_HEADER_MAGIC ((char *) 0x1)
4150 #endif
4151
4152
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
4159 enum mg_http_proto_data_type { DATA_NONE, DATA_FILE, DATA_PUT };
4160
4161 struct mg_http_proto_data_file {
4162 FILE *fp;
4163 int64_t cl;
4164 int64_t sent;
4165 int keepalive;
4166 enum mg_http_proto_data_type type;
4167 };
4168
4169 struct mg_http_proto_data_cgi {
4170 struct mg_connection *cgi_nc;
4171 };
4172
4173 struct mg_http_proto_data_chuncked {
4174 int64_t body_len;
4175 };
4176
4177 struct mg_http_endpoint {
4178 struct mg_http_endpoint *next;
4179 const char *name;
4180 size_t name_len;
4181 mg_event_handler_t handler;
4182 };
4183
4184 enum mg_http_multipart_stream_state {
4185 MPS_BEGIN,
4186 MPS_WAITING_FOR_BOUNDARY,
4187 MPS_WAITING_FOR_CHUNK,
4188 MPS_GOT_CHUNK,
4189 MPS_GOT_BOUNDARY,
4190 MPS_FINALIZE,
4191 MPS_FINISHED
4192 };
4193
4194 struct mg_http_multipart_stream {
4195 const char *boundary;
4196 int boundary_len;
4197 const char *var_name;
4198 const char *file_name;
4199 void *user_data;
4200 int prev_io_len;
4201 enum mg_http_multipart_stream_state state;
4202 int processing_part;
4203 };
4204
4205 struct mg_http_proto_data {
4206 #ifndef MG_DISABLE_FILESYSTEM
4207 struct mg_http_proto_data_file file;
4208 #endif
4209 #ifndef MG_DISABLE_CGI
4210 struct mg_http_proto_data_cgi cgi;
4211 #endif
4212 #ifdef MG_ENABLE_HTTP_STREAMING_MULTIPART
4213 struct mg_http_multipart_stream mp_stream;
4214 #endif
4215 struct mg_http_proto_data_chuncked chunk;
4216 struct mg_http_endpoint *endpoints;
4217 mg_event_handler_t endpoint_handler;
4218 };
4219
4220 static void mg_http_conn_destructor(void *proto_data);
4221
4222 static struct mg_http_proto_data *mg_http_get_proto_data(
4223 struct mg_connection *c) {
4224 if (c->proto_data == NULL) {
4225 c->proto_data = MG_CALLOC(1, sizeof(struct mg_http_proto_data));
4226 c->proto_data_destructor = mg_http_conn_destructor;
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
4245 static void mg_http_free_proto_data_file(struct mg_http_proto_data_file *d) {
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
4256 static void mg_http_free_proto_data_cgi(struct mg_http_proto_data_cgi *d) {
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
4264 static void mg_http_free_proto_data_endpoints(struct mg_http_endpoint **ep) {
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
4280 mg_http_free_proto_data_file(&pd->file);
4281 #endif
4282 #ifndef MG_DISABLE_CGI
4283 mg_http_free_proto_data_cgi(&pd->cgi);
4284 #endif
4285 #ifdef MG_ENABLE_HTTP_STREAMING_MULTIPART
4286 mg_http_free_proto_data_mp_stream(&pd->mp_stream);
4287 #endif
4288 mg_http_free_proto_data_endpoints(&pd->endpoints);
4289 free(proto_data);
4290 }
4291
4292
4293
4294
4295
4296
4297
4298
4299
4300
4301
4302 struct mg_cgi_env_block {
4303 struct mg_connection *nc;
4304 char buf[MG_CGI_ENVIRONMENT_SIZE];
4305 const char *vars[MG_MAX_CGI_ENVIR_VARS];
4306 int len;
4307 int nvars;
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;
4318 } mg_static_builtin_mime_types[] = {
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] == '.' &&
4399 mg_casecmp(ext, mg_static_builtin_mime_types[i].extension) == 0) {
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
4414
4415
4416
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--;
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
4477 while (s < end && isspace(*(unsigned char *) s)) s++;
4478
4479 if (is_req) {
4480
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
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
4505
4506
4507
4508
4509
4510
4511
4512
4513
4514
4515
4516
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
4550 static void mg_handle_incoming_websocket_frame(struct mg_connection *nc,
4551 struct websocket_message *wsm) {
4552 if (wsm->flags & 0x8) {
4553 mg_call(nc, nc->handler, MG_EV_WEBSOCKET_CONTROL_FRAME, wsm);
4554 } else {
4555 mg_call(nc, nc->handler, MG_EV_WEBSOCKET_FRAME, wsm);
4556 }
4557 }
4558
4559 static int mg_deliver_websocket_data(struct mg_connection *nc) {
4560
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];
4566 int ok, reass = buf_len > 0 && mg_is_ws_fragment(p[0]) &&
4567 !(nc->flags & MG_F_WEBSOCKET_NO_DEFRAG);
4568
4569
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
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
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;
4614 buf = p + 1 + sizeof(*sizep);
4615 *sizep = 0;
4616 }
4617
4618
4619 memmove(buf, wsm.data, e - wsm.data);
4620 (*sizep) += wsm.size;
4621 nc->recv_mbuf.len -= wsm.data - buf;
4622
4623
4624 if (wsm.flags & 0x80) {
4625 wsm.data = p + 1 + sizeof(*sizep);
4626 wsm.size = *sizep;
4627 mg_handle_incoming_websocket_frame(nc, &wsm);
4628 mbuf_remove(&nc->recv_mbuf, 1 + sizeof(*sizep) + *sizep);
4629 }
4630 } else {
4631
4632 mg_handle_incoming_websocket_frame(nc, &wsm);
4633 mbuf_remove(&nc->recv_mbuf, (size_t) frame_len);
4634 }
4635
4636
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;
4647 uint32_t mask;
4648 };
4649
4650 static uint32_t mg_ws_random_mask(void) {
4651 uint32_t mask;
4652
4653
4654
4655
4656
4657
4658
4659
4660
4661
4662
4663
4664
4665
4666 #ifdef MG_DISABLE_WS_RANDOM_MASK
4667 mask = 0xefbeadde;
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
4703 if (nc->listener == NULL) {
4704 header[1] |= 1 << 7;
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
4759 void mg_printf_websocket_frame(struct mg_connection *nc, int op,
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
4787 {
4788 time_t now = *(time_t *) ev_data;
4789 if (nc->flags & MG_F_IS_WEBSOCKET &&
4790 now > nc->last_io_time + MG_WEBSOCKET_PING_INTERVAL_SECONDS) {
4791 mg_send_websocket_frame(nc, WEBSOCKET_OP_PING, "", 0);
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
4823
4824 #ifndef MG_DISABLE_FILESYSTEM
4825 static void mg_http_transfer_file_data(struct mg_connection *nc) {
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
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;
4849 mg_http_free_proto_data_file(&pd->file);
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;
4862 mg_http_free_proto_data_file(&pd->file);
4863 }
4864 }
4865 #ifndef MG_DISABLE_CGI
4866 else if (pd->cgi.cgi_nc != NULL) {
4867
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
4877
4878
4879
4880
4881
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;
4887 size_t i = 0;
4888
4889
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
4897 if (i == 0 || i + 2 > len || s[i] != '\r' || s[i + 1] != '\n') {
4898 return 0;
4899 }
4900 i += 2;
4901
4902
4903 *chunk_data = (char *) s + i;
4904 *chunk_len = n;
4905
4906
4907 i += n;
4908
4909
4910 if (i == 0 || i + 2 > len || s[i] != '\r' || s[i + 1] != '\n') {
4911 return 0;
4912 }
4913 return i + 2;
4914 }
4915
4916 MG_INTERNAL size_t mg_handle_chunked(struct mg_connection *nc,
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
4924 body_len = pd->chunk.body_len;
4925 assert(blen >= body_len);
4926
4927
4928 for (i = body_len;
4929 (n = mg_http_parse_chunk(buf + i, blen - i, &data, &data_len)) > 0;
4930 i += n) {
4931
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
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
4952 nc->flags &= ~MG_F_DELETE_CHUNK;
4953 mg_call(nc, nc->handler, MG_EV_HTTP_CHUNK, hm);
4954
4955
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
4971 static mg_event_handler_t mg_http_get_endpoint_handler(
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
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
5008 ? mg_http_get_endpoint_handler(nc->listener, &hm->uri)
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
5025
5026
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
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
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
5056
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
5071
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) {
5082 mg_http_transfer_file_data(nc);
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
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
5114
5115
5116 if ((req_len < 0 ||
5117 (req_len == 0 && io->len >= MG_MAX_HTTP_REQUEST_SIZE))) {
5118 DBG(("invalid request"));
5119 nc->flags |= MG_F_CLOSE_IMMEDIATELY;
5120 } else if (req_len == 0) {
5121
5122 }
5123 #ifndef MG_DISABLE_HTTP_WEBSOCKET
5124 else if (nc->listener == NULL &&
5125 mg_get_http_header(hm, "Sec-WebSocket-Accept")) {
5126
5127
5128 mbuf_remove(io, req_len);
5129 nc->proto_handler = mg_websocket_handler;
5130 nc->flags |= MG_F_IS_WEBSOCKET;
5131 mg_call(nc, nc->handler, MG_EV_WEBSOCKET_HANDSHAKE_DONE, NULL);
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
5136 mbuf_remove(io, req_len);
5137 nc->proto_handler = mg_websocket_handler;
5138 nc->flags |= MG_F_IS_WEBSOCKET;
5139
5140
5141 mg_call(nc, nc->handler, MG_EV_WEBSOCKET_HANDSHAKE_REQUEST, hm);
5142 if (!(nc->flags & MG_F_CLOSE_IMMEDIATELY)) {
5143 if (nc->send_mbuf.len == 0) {
5144 mg_ws_handshake(nc, vec);
5145 }
5146 mg_call(nc, nc->handler, MG_EV_WEBSOCKET_HANDSHAKE_DONE, NULL);
5147 mg_websocket_handler(nc, MG_EV_RECV, ev_data);
5148 }
5149 #endif
5150 } else if (hm->message.len <= io->len) {
5151 int trigger_ev = nc->listener ? MG_EV_HTTP_REQUEST : MG_EV_HTTP_REPLY;
5152
5153
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
5163 v1 = v7_get(v7, v7_get_global(v7), "Http", ~0);
5164 v2 = v7_get(v7, v1, ev_name, ~0);
5165
5166
5167 args = v7_mk_array(v7);
5168 req = v7_mk_object(v7);
5169 headers = v7_mk_object(v7);
5170
5171
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
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
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
5227 goto exit_mp;
5228 }
5229
5230 ct = mg_get_http_header(hm, "Content-Type");
5231 if (ct == NULL) {
5232
5233 goto exit_mp;
5234 }
5235
5236
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
5246
5247
5248 nc->flags = MG_F_CLOSE_IMMEDIATELY;
5249 DBG(("invalid request"));
5250 goto exit_mp;
5251 }
5252
5253
5254
5255 if (pd->mp_stream.boundary != NULL) {
5256
5257
5258
5259
5260 nc->flags |= MG_F_CLOSE_IMMEDIATELY;
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
5266 pd->endpoint_handler = mg_http_get_endpoint_handler(nc->listener, &hm->uri);
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;
5284 struct mg_http_proto_data *pd = mg_http_get_proto_data(c);
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) {
5297 struct mg_http_proto_data *pd = mg_http_get_proto_data(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) {
5310 struct mg_http_proto_data *pd = mg_http_get_proto_data(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;
5322 struct mg_http_proto_data *pd = mg_http_get_proto_data(c);
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;
5349 struct mg_http_proto_data *pd = mg_http_get_proto_data(c);
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) {
5400 struct mg_http_proto_data *pd = mg_http_get_proto_data(c);
5401 struct mbuf *io = &c->recv_mbuf;
5402
5403 const char *boundary;
5404 if ((int) io->len < pd->mp_stream.boundary_len + 6 ) {
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) {
5430 struct mg_http_proto_data *pd = mg_http_get_proto_data(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: {
5468 mbuf_remove(&c->recv_mbuf, c->recv_mbuf.len);
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
5518
5519
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
5556
5557
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
5584
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
5598
5599 void mg_set_protocol_http_websocket(struct mg_connection *nc) {
5600 nc->proto_handler = mg_http_handler;
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
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
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) {
5636 mg_send_websocket_handshake2(nc, path, MG_WS_NO_HOST_HEADER_MAGIC, NULL,
5637 extra_headers);
5638 }
5639
5640 #endif
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
5727
5728
5729 if (sscanf(tag, " virtual=\"%[^\"]\"", file_name) == 1) {
5730
5731 snprintf(path, sizeof(path), "%s/%s", opts->document_root, file_name);
5732 } else if (sscanf(tag, " abspath=\"%[^\"]\"", file_name) == 1) {
5733
5734
5735
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
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
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
5787
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;
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
5813 buf[i--] = '\0';
5814 while (i > 0 && buf[i] == ' ') {
5815 buf[i--] = '\0';
5816 }
5817
5818
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
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
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
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
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
5905
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));
5924 mg_http_free_proto_data_file(&pd->file);
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
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
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
5995
5996
5997
5998
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;
6016 mg_http_transfer_file_data(nc);
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';
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
6111 if (buf != mem && buf != NULL) {
6112 MG_FREE(buf);
6113 }
6114
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] == '<' ? "<" : ">", 4);
6131 j = i + 1;
6132 }
6133 }
6134 mg_send(nc, buf + j, i - j);
6135 }
6136
6137
6138 if (buf != mem && buf != NULL) {
6139 MG_FREE(buf);
6140 }
6141
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
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
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
6240
6241
6242
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
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
6273
6274
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
6280 strcmp(auth_domain, f_domain) == 0) {
6281
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
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", "<");
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
6391
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));
6406 mg_printf_http_chunk(nc,
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
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
6464 mg_printf_http_chunk(
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);
6479 mg_printf_http_chunk(nc,
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
6487 nc->flags |= MG_F_SEND_AND_CLOSE;
6488 }
6489 #endif
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;
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
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
6547
6548
6549
6550
6551
6552
6553
6554
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
6665 static int mg_create_itermediate_directories(const char *path) {
6666 const char *s;
6667
6668
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
6691 mg_http_free_proto_data_file(&pd->file);
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
6714 mbuf_remove(&nc->recv_mbuf, hm->message.len - hm->body.len);
6715 mg_http_transfer_file_data(nc);
6716 }
6717 }
6718 #endif
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
6740
6741
6742
6743
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
6753
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
6762 if (mg_stat(*index_file, &st) == 0 && S_ISREG(st.st_mode)) {
6763
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
6776 static int mg_http_send_port_based_redirect(
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,
6784 MG_SOCK_STRINGIFY_PORT);
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
6799 MG_INTERNAL int mg_uri_to_local_path(struct http_message *hm,
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 {
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
6816 while ((rewrites = mg_next_comma_list_entry(rewrites, &a, &b)) != NULL) {
6817 if (a.len > 1 && a.p[0] == '@') {
6818
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
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
6831 } else if (*(file_uri_start - 1) == '/') {
6832
6833 file_uri_start--;
6834 } else {
6835
6836 continue;
6837 }
6838 root = b;
6839 break;
6840 }
6841 }
6842 }
6843
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 {
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
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
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
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
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
6919 for (i = 0; i < component.len; i++, p++) {
6920 if (*p == '\0' || *p == DIRSEP
6921 #ifdef _WIN32
6922
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);
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
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
7088 CloseHandle(si.hStdOutput);
7089 CloseHandle(si.hStdInput);
7090
7091
7092
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
7107
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
7117
7118
7119
7120
7121 signal(SIGCHLD, SIG_DFL);
7122
7123 if (interp == NULL) {
7124 execle(cmd, cmd, (char *) 0, envp);
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);
7135 }
7136
7137 return pid;
7138 }
7139 #endif
7140
7141
7142
7143
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
7151 space = sizeof(block->buf) - (block->len + 2);
7152 if (space > 0) {
7153
7154 va_start(ap, fmt);
7155 n = vsnprintf(added, (size_t) space, fmt, ap);
7156 va_end(ap);
7157
7158
7159 if (n > 0 && n + 1 < space &&
7160 block->nvars < (int) ARRAY_SIZE(block->vars) - 2) {
7161
7162 block->vars[block->nvars++] = added;
7163
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
7176 static void mg_prepare_cgi_environment(struct mg_connection *nc,
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
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");
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),
7213 MG_SOCK_STRINGIFY_REMOTE | MG_SOCK_STRINGIFY_IP);
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
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");
7256 mg_addenv2(blk, MG_ENV_EXPORT_TO_CGI);
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
7268
7269
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
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
7297
7298
7299
7300
7301
7302
7303
7304
7305
7306
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:
7335 mg_http_free_proto_data_cgi(&mg_http_get_proto_data(cgi_nc)->cgi);
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
7354
7355
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
7366
7367
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
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]);
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
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
7452 static void mg_http_send_digest_auth_request(struct mg_connection *c,
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
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)) {
7521 mg_http_send_digest_auth_request(nc, opts->auth_domain);
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
7528 } else if ((!exists ||
7529 mg_is_file_hidden(path, opts, 0 )) &&
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)))) {
7541 mg_http_send_digest_auth_request(nc, opts->auth_domain);
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")) {
7557 mg_http_send_options(nc);
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
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
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
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
7636
7637
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;
7651 #endif
7652 }
7653
7654 while (*url != '\0') {
7655 *addr = (char *) MG_REALLOC(*addr, addr_len + 5 );
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
7689 struct mg_connection *mg_connect_http_base(
7690 struct mg_mgr *mgr, mg_event_handler_t ev_handler,
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
7715
7716
7717
7718 mg_set_ssl(nc, NULL, NULL);
7719 }
7720 #endif
7721 mg_set_protocol_http_websocket(nc);
7722
7723
7724 if (port_i >= 0) (*addr)[port_i] = '\0';
7725 }
7726
7727 return nc;
7728 }
7729
7730 struct mg_connection *mg_connect_http_opt(struct mg_mgr *mgr,
7731 mg_event_handler_t ev_handler,
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
7756 struct mg_connection *mg_connect_http(struct mg_mgr *mgr,
7757 mg_event_handler_t ev_handler,
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
7767 struct mg_connection *mg_connect_ws_opt(struct mg_mgr *mgr,
7768 mg_event_handler_t ev_handler,
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
7787 struct mg_connection *mg_connect_ws(struct mg_mgr *mgr,
7788 mg_event_handler_t ev_handler,
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
7808 bl = mg_get_line_len(buf, buf_len);
7809
7810
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
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,
7835 mg_event_handler_t handler) {
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
7847 #ifdef MG_MODULE_LINES
7848 #line 1 "./src/util.c"
7849 #endif
7850
7851
7852
7853
7854
7855
7856
7857
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) {
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);
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
7968
7969
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
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));
8030 mg_if_get_conn_addr(nc, flags & MG_SOCK_STRINGIFY_REMOTE, &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
8068
8069
8070 *buf = NULL;
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
8080 } else if (len >= (int) size) {
8081
8082 if ((*buf = (char *) MG_MALLOC(len + 1)) == NULL) {
8083 len = -1;
8084 } else {
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),
8114 MG_SOCK_STRINGIFY_IP | MG_SOCK_STRINGIFY_PORT);
8115 mg_conn_addr_to_str(nc, dst, sizeof(dst), MG_SOCK_STRINGIFY_IP |
8116 MG_SOCK_STRINGIFY_PORT |
8117 MG_SOCK_STRINGIFY_REMOTE);
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
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
8146 list = NULL;
8147 } else {
8148 val->p = list;
8149 if ((list = strchr(val->p, ',')) != NULL) {
8150
8151 val->len = list - val->p;
8152 list++;
8153 } else {
8154
8155 list = val->p + strlen(val->p);
8156 val->len = list - val->p;
8157 }
8158
8159 if (eq_val != NULL) {
8160
8161
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++;
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
8235
8236
8237 #ifndef MG_DISABLE_JSON_RPC
8238
8239
8240
8241
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;
8309 case JSON_RPC_INVALID_REQUEST_ERROR:
8310 message = "invalid request";
8311 break;
8312 case JSON_RPC_METHOD_NOT_FOUND_ERROR:
8313 message = "method not found";
8314 break;
8315 case JSON_RPC_INVALID_PARAMS_ERROR:
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
8339 : JSON_RPC_SERVER_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,
8350 JSON_RPC_INVALID_REQUEST_ERROR);
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,
8362 JSON_RPC_METHOD_NOT_FOUND_ERROR);
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
8392 #ifdef MG_MODULE_LINES
8393 #line 1 "./src/mqtt.c"
8394 #endif
8395
8396
8397
8398
8399
8400 #ifndef MG_DISABLE_MQTT
8401
8402 #include <string.h>
8403
8404
8405
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
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
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
8461
8462
8463 mm->message_id = ntohs(*(uint16_t *) io->buf);
8464 var_len = 2;
8465 break;
8466 default:
8467
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;
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
8500 void mg_set_protocol_mqtt(struct mg_connection *nc) {
8501 nc->proto_handler = mqtt_handler;
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
8518
8519
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
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
8597 mg_mqtt_prepend_header(nc, MG_MQTT_CMD_PUBLISH, flags,
8598 nc->send_mbuf.len - old_len);
8599 }
8600
8601 void mg_mqtt_subscribe(struct mg_connection *nc,
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
8617 mg_mqtt_prepend_header(nc, MG_MQTT_CMD_SUBSCRIBE, MG_MQTT_QOS(1),
8618 nc->send_mbuf.len - old_len);
8619 }
8620
8621 int mg_mqtt_next_subscribe_topic(struct mg_mqtt_message *msg,
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
8648 mg_mqtt_prepend_header(nc, MG_MQTT_CMD_UNSUBSCRIBE, MG_MQTT_QOS(1),
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);
8656 mg_mqtt_prepend_header(nc, MG_MQTT_CMD_CONNACK, 0, 2);
8657 }
8658
8659
8660
8661
8662
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) {
8672 mg_send_mqtt_short_command(nc, MG_MQTT_CMD_PUBACK, message_id);
8673 }
8674
8675 void mg_mqtt_pubrec(struct mg_connection *nc, uint16_t message_id) {
8676 mg_send_mqtt_short_command(nc, MG_MQTT_CMD_PUBREC, message_id);
8677 }
8678
8679 void mg_mqtt_pubrel(struct mg_connection *nc, uint16_t message_id) {
8680 mg_send_mqtt_short_command(nc, MG_MQTT_CMD_PUBREL, message_id);
8681 }
8682
8683 void mg_mqtt_pubcomp(struct mg_connection *nc, uint16_t message_id) {
8684 mg_send_mqtt_short_command(nc, MG_MQTT_CMD_PUBCOMP, 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) {
8699 mg_send_mqtt_short_command(nc, MG_MQTT_CMD_UNSUBACK, message_id);
8700 }
8701
8702 void mg_mqtt_ping(struct mg_connection *nc) {
8703 mg_mqtt_prepend_header(nc, MG_MQTT_CMD_PINGREQ, 0, 0);
8704 }
8705
8706 void mg_mqtt_pong(struct mg_connection *nc) {
8707 mg_mqtt_prepend_header(nc, MG_MQTT_CMD_PINGRESP, 0, 0);
8708 }
8709
8710 void mg_mqtt_disconnect(struct mg_connection *nc) {
8711 mg_mqtt_prepend_header(nc, MG_MQTT_CMD_DISCONNECT, 0, 0);
8712 }
8713
8714 #endif
8715 #ifdef MG_MODULE_LINES
8716 #line 1 "./src/mqtt-broker.c"
8717 #endif
8718
8719
8720
8721
8722
8723
8724
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
8774 mg_mqtt_connack(nc, MG_EV_MQTT_CONNACK_SERVER_UNAVAILABLE);
8775 return;
8776
8777 }
8778
8779
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
8786 mg_mqtt_connack(nc, MG_EV_MQTT_CONNACK_ACCEPTED);
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
8820
8821
8822
8823
8824
8825 static int mg_mqtt_match_topic_expression(const char *exp, const char *topic) {
8826
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:
8863 mg_set_protocol_mqtt(nc);
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
8888 #ifdef MG_MODULE_LINES
8889 #line 1 "./src/dns.c"
8890 #endif
8891
8892
8893
8894
8895
8896 #ifndef MG_DISABLE_DNS
8897
8898
8899
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;
8908 uint16_t num_authority_prs;
8909 uint16_t num_other_prs;
8910 };
8911
8912 struct mg_dns_resource_record *mg_dns_next_record(
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
8926 int mg_dns_parse_record_data(struct mg_dns_message *msg,
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;
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;
8990 }
8991 n = s - name;
8992 mbuf_append(io, &n, 1);
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);
9003
9004 return io->len - pos;
9005 }
9006
9007 int mg_dns_encode_record(struct mbuf *io, struct mg_dns_resource_record *rr,
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;
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
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 );
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;
9071 rr->kind = MG_DNS_QUESTION;
9072
9073 if (mg_dns_encode_record(&pkt, rr, name, strlen(name), NULL, 0) == -1) {
9074
9075 goto cleanup;
9076 }
9077
9078
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
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
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
9248 nc->handler(nc, MG_DNS_MESSAGE, &msg);
9249 }
9250 mbuf_remove(io, io->len);
9251 break;
9252 }
9253 }
9254
9255 void mg_set_protocol_dns(struct mg_connection *nc) {
9256 nc->proto_handler = dns_handler;
9257 }
9258
9259 #endif
9260 #ifdef MG_MODULE_LINES
9261 #line 1 "./src/dns-server.c"
9262 #endif
9263
9264
9265
9266
9267
9268 #ifdef MG_ENABLE_DNS_SERVER
9269
9270
9271
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
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;
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;
9327 };
9328
9329 msg->num_answers++;
9330 return 0;
9331 }
9332
9333 #endif
9334 #ifdef MG_MODULE_LINES
9335 #line 1 "./src/resolv.c"
9336 #endif
9337
9338
9339
9340
9341
9342 #ifndef MG_DISABLE_RESOLVER
9343
9344
9345
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
9353 MG_INTERNAL char mg_dns_server[256];
9354
9355 struct mg_resolve_async_request {
9356 char name[1024];
9357 int query;
9358 mg_resolve_callback_t callback;
9359 void *data;
9360 time_t timeout;
9361 int max_retries;
9362 enum mg_resolve_err err;
9363
9364
9365 time_t last_time;
9366 int retries;
9367 };
9368
9369
9370
9371
9372
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
9398
9399
9400
9401
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
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
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
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
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) {
9496 req->err = MG_RESOLVE_EXCEEDED_RETRY_COUNT;
9497 nc->flags |= MG_F_CLOSE_IMMEDIATELY;
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);
9517 nc->flags |= MG_F_CLOSE_IMMEDIATELY;
9518 break;
9519 case MG_EV_SEND:
9520
9521
9522
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;
9529 nc->flags |= MG_F_CLOSE_IMMEDIATELY;
9530 break;
9531 case MG_EV_CLOSE:
9532
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
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
9569 req->max_retries = opts.max_retries ? opts.max_retries : 2;
9570 req->timeout = opts.timeout ? opts.timeout : 5;
9571
9572
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
9597 #ifdef MG_MODULE_LINES
9598 #line 1 "./src/coap.c"
9599 #endif
9600
9601
9602
9603
9604
9605
9606
9607
9608
9609
9610
9611
9612
9613
9614
9615
9616
9617
9618
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
9645
9646
9647
9648 if (cm->optiomg_tail->number <= new_option->number) {
9649
9650 cm->optiomg_tail = cm->optiomg_tail->next = new_option;
9651 } else {
9652
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
9669 new_option->next = cm->options;
9670 cm->options = new_option;
9671 }
9672 }
9673 }
9674
9675 return new_option;
9676 }
9677
9678
9679
9680
9681
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
9692
9693
9694
9695
9696 if (((uint8_t) *ptr >> 6) != 1) {
9697 cm->flags |= MG_COAP_IGNORE;
9698 return NULL;
9699 }
9700
9701
9702
9703
9704
9705
9706 cm->msg_type = ((uint8_t) *ptr & 0x30) >> 4;
9707 cm->flags |= MG_COAP_MSG_TYPE_FIELD;
9708
9709
9710
9711
9712
9713
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
9725
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
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
9744
9745
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
9765
9766
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
9774
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;
9781 }
9782 } else if (*opt_info == 14) {
9783
9784
9785
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;
9792 }
9793 }
9794
9795 return ret;
9796 }
9797
9798
9799
9800
9801
9802
9803
9804
9805
9806
9807
9808
9809
9810
9811
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
9820 return NULL;
9821 }
9822
9823
9824 while (ptr < io->buf + io->len && (uint8_t) *ptr != 0xFF) {
9825 uint16_t option_delta, option_lenght;
9826 int optinfo_len;
9827
9828
9829 option_delta = ((uint8_t) *ptr & 0xF0) >> 4;
9830
9831 option_lenght = *ptr & 0x0F;
9832
9833 if (option_delta == 15 || option_lenght == 15) {
9834
9835
9836
9837
9838 cm->flags |= MG_COAP_FORMAT_ERROR;
9839 break;
9840 }
9841
9842 ptr++;
9843
9844
9845 optinfo_len = coap_get_ext_opt(ptr, io, &option_delta);
9846 if (optinfo_len == -1) {
9847 cm->flags |= MG_COAP_NOT_ENOUGH_DATA;
9848 break;
9849 }
9850
9851 ptr += optinfo_len;
9852
9853
9854 optinfo_len = coap_get_ext_opt(ptr, io, &option_lenght);
9855 if (optinfo_len == -1) {
9856 cm->flags |= MG_COAP_NOT_ENOUGH_DATA;
9857 break;
9858 }
9859
9860 ptr += optinfo_len;
9861
9862
9863
9864
9865
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;
9875 break;
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
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
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
9927
9928
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
9944
9945
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
9967
9968
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
9980
9981
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
9996
9997
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;
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;
10021 }
10022
10023 opt = cm->options;
10024 prev_opt_number = 0;
10025 while (opt != NULL) {
10026 *len += 1;
10027 *len += coap_get_ext_opt_size(opt->number);
10028 *len += coap_get_ext_opt_size((uint32_t) opt->value.len);
10029
10030
10031
10032
10033
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
10059 prev_io_len = io->len;
10060 mbuf_append(io, NULL, packet_size);
10061 ptr = io->buf + prev_io_len;
10062
10063
10064
10065
10066
10067
10068
10069 *ptr = (1 << 6) | (cm->msg_type << 4) | (cm->token.len);
10070 ptr++;
10071
10072
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;
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
10160
10161
10162 cm.flags |= MG_COAP_FORMAT_ERROR;
10163 }
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
10174
10175
10176
10177
10178
10179
10180
10181
10182 int mg_set_protocol_coap(struct mg_connection *nc) {
10183
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
10194 #ifdef MG_MODULE_LINES
10195 #line 1 "./src/../../common/platforms/cc3200/cc3200_libc.c"
10196 #endif
10197
10198
10199
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
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
10258 do {
10259 r2 = r1;
10260 r1 = PRCMSlowClkCtrFastGet();
10261 } while (r1 != r2);
10262
10263 tp->tv_sec = (r1 >> 15);
10264
10265
10266 tp->tv_usec = (r1 & 0x7FFF) * 30;
10267 return 0;
10268 }
10269
10270 long int random(void) {
10271 return 42;
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
10284 *(int *) 1 = status;
10285 while (1)
10286 ;
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
10309 return fd < 2;
10310 }
10311
10312 #endif
10313 #ifdef MG_MODULE_LINES
10314 #line 1 "./src/../../common/platforms/msp432/msp432_libc.c"
10315 #endif
10316
10317
10318
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;
10335 }
10336
10337 #endif
10338 #ifdef MG_MODULE_LINES
10339 #line 1 "./src/../../common/platforms/simplelink/sl_fs_slfs.h"
10340 #endif
10341
10342
10343
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
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
10373
10374 #endif
10375 #ifdef MG_MODULE_LINES
10376 #line 1 "./src/../../common/platforms/simplelink/sl_fs_slfs.c"
10377 #endif
10378
10379
10380
10381
10382
10383
10384
10385 #if defined(MG_FS_SLFS) || defined(CC3200_FS_SLFS)
10386
10387
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
10398
10399 extern int set_errno(int e);
10400
10401
10402
10403
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
10467
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
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
10596 #ifdef MG_MODULE_LINES
10597 #line 1 "./src/../../common/platforms/simplelink/sl_fs.c"
10598 #endif
10599
10600
10601
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
10624
10625
10626 #ifdef CC3200_FS_SPIFFS
10627
10628 #endif
10629
10630 #ifdef MG_FS_SLFS
10631
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
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
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
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
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
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
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
10967
10968 #ifdef MG_MODULE_LINES
10969 #line 1 "./src/../../common/platforms/simplelink/sl_socket.c"
10970 #endif
10971
10972
10973
10974
10975
10976 #ifdef MG_SOCKET_SIMPLELINK
10977
10978 #include <errno.h>
10979 #include <stdio.h>
10980
10981
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
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
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