File indexing completed on 2025-05-11 08:24:21
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021 #ifdef HAVE_CONFIG_H
0022 #include "config.h"
0023 #endif
0024
0025 #if defined(__rtems__)
0026 #include <md5.h>
0027 #define HAVE_MD5
0028 #define NO_CGI
0029 #define NO_POPEN
0030 #define NO_SSL
0031 #define USE_WEBSOCKET
0032 #endif
0033
0034 #if defined(_WIN32)
0035 #if !defined(_CRT_SECURE_NO_WARNINGS)
0036 #define _CRT_SECURE_NO_WARNINGS
0037 #endif
0038 #else
0039 #ifdef __linux__
0040 #define _XOPEN_SOURCE 600
0041 #endif
0042 #define _LARGEFILE_SOURCE
0043 #define __STDC_FORMAT_MACROS
0044 #define __STDC_LIMIT_MACROS
0045 #endif
0046
0047 #if defined (_MSC_VER)
0048
0049 #pragma warning (disable : 4127)
0050
0051 #pragma warning (disable : 4204)
0052 #endif
0053
0054
0055
0056 #ifdef WIN32_LEAN_AND_MEAN
0057 #undef WIN32_LEAN_AND_MEAN
0058 #endif
0059
0060 #if defined(__SYMBIAN32__)
0061 #define NO_SSL
0062 #define NO_CGI
0063 #define PATH_MAX FILENAME_MAX
0064 #endif
0065
0066 #ifndef _WIN32_WCE
0067 #include <sys/types.h>
0068 #include <sys/stat.h>
0069 #include <errno.h>
0070 #include <signal.h>
0071 #include <fcntl.h>
0072 #endif
0073
0074 #include <time.h>
0075 #include <stdlib.h>
0076 #include <stdarg.h>
0077 #include <assert.h>
0078 #include <string.h>
0079 #include <ctype.h>
0080 #include <limits.h>
0081 #include <stddef.h>
0082 #include <stdio.h>
0083
0084 #if __rtems__
0085 #include <time.h>
0086 #include <sys/param.h>
0087 #include <rtems/libio_.h>
0088 #endif
0089
0090 #if defined(_WIN32) && !defined(__SYMBIAN32__)
0091 #undef _WIN32_WINNT
0092 #define _WIN32_WINNT 0x0400
0093 #include <windows.h>
0094
0095 #ifndef PATH_MAX
0096 #define PATH_MAX MAX_PATH
0097 #endif
0098
0099 #ifndef _WIN32_WCE
0100 #include <process.h>
0101 #include <direct.h>
0102 #include <io.h>
0103 #else
0104 #define NO_CGI
0105
0106 typedef long off_t;
0107
0108 #define errno GetLastError()
0109 #define strerror(x) _ultoa(x, (char *) _alloca(sizeof(x) *3 ), 10)
0110 #endif
0111
0112 #define MAKEUQUAD(lo, hi) ((uint64_t)(((uint32_t)(lo)) | \
0113 ((uint64_t)((uint32_t)(hi))) << 32))
0114 #define RATE_DIFF 10000000
0115 #define EPOCH_DIFF MAKEUQUAD(0xd53e8000, 0x019db1de)
0116 #define SYS2UNIX_TIME(lo, hi) \
0117 (time_t) ((MAKEUQUAD((lo), (hi)) - EPOCH_DIFF) / RATE_DIFF)
0118
0119
0120
0121
0122 #if defined(_MSC_VER) && _MSC_VER < 1300
0123 #define STRX(x) #x
0124 #define STR(x) STRX(x)
0125 #define __func__ __FILE__ ":" STR(__LINE__)
0126 #define strtoull(x, y, z) (unsigned __int64) _atoi64(x)
0127 #define strtoll(x, y, z) _atoi64(x)
0128 #else
0129 #define __func__ __FUNCTION__
0130 #define strtoull(x, y, z) _strtoui64(x, y, z)
0131 #define strtoll(x, y, z) _strtoi64(x, y, z)
0132 #endif
0133
0134 #define ERRNO GetLastError()
0135 #define NO_SOCKLEN_T
0136 #define SSL_LIB "ssleay32.dll"
0137 #define CRYPTO_LIB "libeay32.dll"
0138 #define O_NONBLOCK 0
0139 #if !defined(EWOULDBLOCK)
0140 #define EWOULDBLOCK WSAEWOULDBLOCK
0141 #endif
0142 #define _POSIX_
0143 #define INT64_FMT "I64d"
0144
0145 #define WINCDECL __cdecl
0146 #define SHUT_WR 1
0147 #define snprintf _snprintf
0148 #define vsnprintf _vsnprintf
0149 #define mg_sleep(x) Sleep(x)
0150
0151 #define pipe(x) _pipe(x, MG_BUF_LEN, _O_BINARY)
0152 #ifndef popen
0153 #define popen(x, y) _popen(x, y)
0154 #endif
0155 #ifndef pclose
0156 #define pclose(x) _pclose(x)
0157 #endif
0158 #define close(x) _close(x)
0159 #define dlsym(x,y) GetProcAddress((HINSTANCE) (x), (y))
0160 #define RTLD_LAZY 0
0161 #define fseeko(x, y, z) _lseeki64(_fileno(x), (y), (z))
0162 #define fdopen(x, y) _fdopen((x), (y))
0163 #define write(x, y, z) _write((x), (y), (unsigned) z)
0164 #define read(x, y, z) _read((x), (y), (unsigned) z)
0165 #define flockfile(x) EnterCriticalSection(&global_log_file_lock)
0166 #define funlockfile(x) LeaveCriticalSection(&global_log_file_lock)
0167 #define sleep(x) Sleep((x) * 1000)
0168 #define rmdir(x) _rmdir(x)
0169
0170 #if !defined(va_copy)
0171 #define va_copy(x, y) x = y
0172 #endif
0173
0174 #if !defined(fileno)
0175 #define fileno(x) _fileno(x)
0176 #endif
0177
0178 typedef HANDLE pthread_mutex_t;
0179 typedef struct {HANDLE signal, broadcast;} pthread_cond_t;
0180 typedef DWORD pthread_t;
0181 #define pid_t HANDLE
0182
0183 static int pthread_mutex_lock(pthread_mutex_t *);
0184 static int pthread_mutex_unlock(pthread_mutex_t *);
0185 static void to_unicode(const char *path, wchar_t *wbuf, size_t wbuf_len);
0186 struct file;
0187 static char *mg_fgets(char *buf, size_t size, struct file *filep, char **p);
0188
0189 #if defined(HAVE_STDINT)
0190 #include <stdint.h>
0191 #else
0192 typedef unsigned int uint32_t;
0193 typedef unsigned short uint16_t;
0194 typedef unsigned __int64 uint64_t;
0195 typedef __int64 int64_t;
0196 #define INT64_MAX 9223372036854775807
0197 #endif
0198
0199
0200 struct dirent {
0201 char d_name[PATH_MAX];
0202 };
0203
0204 typedef struct DIR {
0205 HANDLE handle;
0206 WIN32_FIND_DATAW info;
0207 struct dirent result;
0208 } DIR;
0209
0210
0211
0212 #ifdef _MSC_VER
0213 #pragma comment(lib, "Ws2_32.lib")
0214 #endif
0215
0216 #else
0217 #include <sys/wait.h>
0218 #include <sys/socket.h>
0219 #include <sys/select.h>
0220 #ifdef HAVE_POLL
0221 #include <sys/poll.h>
0222 #endif
0223 #include <netinet/in.h>
0224 #include <arpa/inet.h>
0225 #include <sys/time.h>
0226 #include <stdint.h>
0227 #include <inttypes.h>
0228 #include <netdb.h>
0229
0230 #include <pwd.h>
0231 #include <unistd.h>
0232 #include <dirent.h>
0233 #if !defined(NO_SSL_DL) && !defined(NO_SSL)
0234 #include <dlfcn.h>
0235 #endif
0236 #include <pthread.h>
0237 #if defined(__MACH__)
0238 #define SSL_LIB "libssl.dylib"
0239 #define CRYPTO_LIB "libcrypto.dylib"
0240 #else
0241 #if !defined(SSL_LIB)
0242 #define SSL_LIB "libssl.so"
0243 #endif
0244 #if !defined(CRYPTO_LIB)
0245 #define CRYPTO_LIB "libcrypto.so"
0246 #endif
0247 #endif
0248 #ifndef O_BINARY
0249 #define O_BINARY 0
0250 #endif
0251 #define closesocket(a) close(a)
0252 #define mg_mkdir(x, y) mkdir(x, y)
0253 #define mg_remove(x) remove(x)
0254 #define mg_sleep(x) usleep((x) * 1000)
0255 #define ERRNO errno
0256 #define INVALID_SOCKET (-1)
0257 #define INT64_FMT PRId64
0258 typedef int SOCKET;
0259 #define WINCDECL
0260
0261 #endif
0262
0263 #ifndef HAVE_POLL
0264 struct pollfd {
0265 SOCKET fd;
0266 short events;
0267 short revents;
0268 };
0269 #define POLLIN 1
0270 #endif
0271
0272 #include <mghttpd/mongoose.h>
0273
0274 #define MONGOOSE_VERSION "3.9"
0275 #define PASSWORDS_FILE_NAME ".htpasswd"
0276 #define CGI_ENVIRONMENT_SIZE 4096
0277 #define MAX_CGI_ENVIR_VARS 64
0278 #define MG_BUF_LEN 8192
0279 #define MAX_REQUEST_SIZE 16384
0280 #define ARRAY_SIZE(array) (sizeof(array) / sizeof(array[0]))
0281
0282 #ifdef _WIN32
0283 static CRITICAL_SECTION global_log_file_lock;
0284 static pthread_t pthread_self(void) {
0285 return GetCurrentThreadId();
0286 }
0287 #endif
0288
0289 #ifdef DEBUG_TRACE
0290 #undef DEBUG_TRACE
0291 #define DEBUG_TRACE(x)
0292 #else
0293 #if defined(DEBUG)
0294 #define DEBUG_TRACE(x) do { \
0295 flockfile(stdout); \
0296 printf("*** %lu.%p.%s.%d: ", \
0297 (unsigned long) time(NULL), (void *) pthread_self(), \
0298 __func__, __LINE__); \
0299 printf x; \
0300 putchar('\n'); \
0301 fflush(stdout); \
0302 funlockfile(stdout); \
0303 } while (0)
0304 #else
0305 #define DEBUG_TRACE(x)
0306 #endif
0307 #endif
0308
0309
0310 #ifdef NO_SOCKLEN_T
0311 typedef int socklen_t;
0312 #endif
0313 #define _DARWIN_UNLIMITED_SELECT
0314
0315 #define IP_ADDR_STR_LEN 50
0316
0317 #if !defined(MSG_NOSIGNAL)
0318 #define MSG_NOSIGNAL 0
0319 #endif
0320
0321 #if !defined(SOMAXCONN)
0322 #define SOMAXCONN 100
0323 #endif
0324
0325 #if !defined(PATH_MAX)
0326 #define PATH_MAX 4096
0327 #endif
0328
0329
0330 #if !defined(MGSQLEN)
0331 #define MGSQLEN 20
0332 #endif
0333
0334 static const char *http_500_error = "Internal Server Error";
0335
0336 #if defined(NO_SSL_DL)
0337 #include <openssl/ssl.h>
0338 #include <openssl/err.h>
0339 #else
0340
0341
0342 typedef struct ssl_st SSL;
0343 typedef struct ssl_method_st SSL_METHOD;
0344 typedef struct ssl_ctx_st SSL_CTX;
0345
0346 struct ssl_func {
0347 const char *name;
0348 void (*ptr)(void);
0349 };
0350
0351 #define SSL_free (* (void (*)(SSL *)) ssl_sw[0].ptr)
0352 #define SSL_accept (* (int (*)(SSL *)) ssl_sw[1].ptr)
0353 #define SSL_connect (* (int (*)(SSL *)) ssl_sw[2].ptr)
0354 #define SSL_read (* (int (*)(SSL *, void *, int)) ssl_sw[3].ptr)
0355 #define SSL_write (* (int (*)(SSL *, const void *,int)) ssl_sw[4].ptr)
0356 #define SSL_get_error (* (int (*)(SSL *, int)) ssl_sw[5].ptr)
0357 #define SSL_set_fd (* (int (*)(SSL *, SOCKET)) ssl_sw[6].ptr)
0358 #define SSL_new (* (SSL * (*)(SSL_CTX *)) ssl_sw[7].ptr)
0359 #define SSL_CTX_new (* (SSL_CTX * (*)(SSL_METHOD *)) ssl_sw[8].ptr)
0360 #define SSLv23_server_method (* (SSL_METHOD * (*)(void)) ssl_sw[9].ptr)
0361 #define SSL_library_init (* (int (*)(void)) ssl_sw[10].ptr)
0362 #define SSL_CTX_use_PrivateKey_file (* (int (*)(SSL_CTX *, \
0363 const char *, int)) ssl_sw[11].ptr)
0364 #define SSL_CTX_use_certificate_file (* (int (*)(SSL_CTX *, \
0365 const char *, int)) ssl_sw[12].ptr)
0366 #define SSL_CTX_set_default_passwd_cb \
0367 (* (void (*)(SSL_CTX *, mg_callback_t)) ssl_sw[13].ptr)
0368 #define SSL_CTX_free (* (void (*)(SSL_CTX *)) ssl_sw[14].ptr)
0369 #define SSL_load_error_strings (* (void (*)(void)) ssl_sw[15].ptr)
0370 #define SSL_CTX_use_certificate_chain_file \
0371 (* (int (*)(SSL_CTX *, const char *)) ssl_sw[16].ptr)
0372 #define SSLv23_client_method (* (SSL_METHOD * (*)(void)) ssl_sw[17].ptr)
0373 #define SSL_pending (* (int (*)(SSL *)) ssl_sw[18].ptr)
0374 #define SSL_CTX_set_verify (* (void (*)(SSL_CTX *, int, int)) ssl_sw[19].ptr)
0375 #define SSL_shutdown (* (int (*)(SSL *)) ssl_sw[20].ptr)
0376
0377 #define CRYPTO_num_locks (* (int (*)(void)) crypto_sw[0].ptr)
0378 #define CRYPTO_set_locking_callback \
0379 (* (void (*)(void (*)(int, int, const char *, int))) crypto_sw[1].ptr)
0380 #define CRYPTO_set_id_callback \
0381 (* (void (*)(unsigned long (*)(void))) crypto_sw[2].ptr)
0382 #define ERR_get_error (* (unsigned long (*)(void)) crypto_sw[3].ptr)
0383 #define ERR_error_string (* (char * (*)(unsigned long,char *)) crypto_sw[4].ptr)
0384
0385
0386
0387
0388
0389 static struct ssl_func ssl_sw[] = {
0390 {"SSL_free", NULL},
0391 {"SSL_accept", NULL},
0392 {"SSL_connect", NULL},
0393 {"SSL_read", NULL},
0394 {"SSL_write", NULL},
0395 {"SSL_get_error", NULL},
0396 {"SSL_set_fd", NULL},
0397 {"SSL_new", NULL},
0398 {"SSL_CTX_new", NULL},
0399 {"SSLv23_server_method", NULL},
0400 {"SSL_library_init", NULL},
0401 {"SSL_CTX_use_PrivateKey_file", NULL},
0402 {"SSL_CTX_use_certificate_file",NULL},
0403 {"SSL_CTX_set_default_passwd_cb",NULL},
0404 {"SSL_CTX_free", NULL},
0405 {"SSL_load_error_strings", NULL},
0406 {"SSL_CTX_use_certificate_chain_file", NULL},
0407 {"SSLv23_client_method", NULL},
0408 {"SSL_pending", NULL},
0409 {"SSL_CTX_set_verify", NULL},
0410 {"SSL_shutdown", NULL},
0411 {NULL, NULL}
0412 };
0413
0414
0415 #if !defined(NO_SSL)
0416 static struct ssl_func crypto_sw[] = {
0417 {"CRYPTO_num_locks", NULL},
0418 {"CRYPTO_set_locking_callback", NULL},
0419 {"CRYPTO_set_id_callback", NULL},
0420 {"ERR_get_error", NULL},
0421 {"ERR_error_string", NULL},
0422 {NULL, NULL}
0423 };
0424 #endif
0425 #endif
0426
0427 static const char *month_names[] = {
0428 "Jan", "Feb", "Mar", "Apr", "May", "Jun",
0429 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
0430 };
0431
0432
0433
0434 union usa {
0435 struct sockaddr sa;
0436 struct sockaddr_in sin;
0437 #if defined(USE_IPV6)
0438 struct sockaddr_in6 sin6;
0439 #endif
0440 };
0441
0442
0443 struct vec {
0444 const char *ptr;
0445 size_t len;
0446 };
0447
0448 struct file {
0449 int is_directory;
0450 time_t modification_time;
0451 int64_t size;
0452 FILE *fp;
0453 const char *membuf;
0454
0455
0456 int gzipped;
0457 };
0458 #define STRUCT_FILE_INITIALIZER {0, 0, 0, NULL, NULL, 0}
0459
0460
0461
0462 struct socket {
0463 SOCKET sock;
0464 union usa lsa;
0465 union usa rsa;
0466 unsigned is_ssl:1;
0467 unsigned ssl_redir:1;
0468 };
0469
0470
0471 enum {
0472 CGI_EXTENSIONS, CGI_ENVIRONMENT, PUT_DELETE_PASSWORDS_FILE, CGI_INTERPRETER,
0473 PROTECT_URI, AUTHENTICATION_DOMAIN, SSI_EXTENSIONS, THROTTLE,
0474 ACCESS_LOG_FILE, ENABLE_DIRECTORY_LISTING, ERROR_LOG_FILE,
0475 GLOBAL_PASSWORDS_FILE, INDEX_FILES, ENABLE_KEEP_ALIVE, ACCESS_CONTROL_LIST,
0476 EXTRA_MIME_TYPES, LISTENING_PORTS, DOCUMENT_ROOT, SSL_CERTIFICATE,
0477 NUM_THREADS, RUN_AS_USER, REWRITE, HIDE_FILES, REQUEST_TIMEOUT,
0478 THREAD_STACK_SIZE, THREAD_PRIORITY, THREAD_POLICY,
0479 NUM_OPTIONS
0480 };
0481
0482 static const char *config_options[] = {
0483 "cgi_pattern", "**.cgi$|**.pl$|**.php$",
0484 "cgi_environment", NULL,
0485 "put_delete_auth_file", NULL,
0486 "cgi_interpreter", NULL,
0487 "protect_uri", NULL,
0488 "authentication_domain", "mydomain.com",
0489 "ssi_pattern", "**.shtml$|**.shtm$",
0490 "throttle", NULL,
0491 "access_log_file", NULL,
0492 "enable_directory_listing", "yes",
0493 "error_log_file", NULL,
0494 "global_auth_file", NULL,
0495 "index_files",
0496 "index.html,index.htm,index.cgi,index.shtml,index.php,index.lp",
0497 "enable_keep_alive", "no",
0498 "access_control_list", NULL,
0499 "extra_mime_types", NULL,
0500 "listening_ports", "8080",
0501 "document_root", NULL,
0502 "ssl_certificate", NULL,
0503 "num_threads", "50",
0504 "run_as_user", NULL,
0505 "url_rewrite_patterns", NULL,
0506 "hide_files_patterns", NULL,
0507 "request_timeout_ms", "30000",
0508 "thread_stack_size", NULL,
0509 "thread_priority", NULL,
0510 "thread_policy", NULL,
0511 NULL
0512 };
0513
0514 struct mg_context {
0515 volatile int stop_flag;
0516 SSL_CTX *ssl_ctx;
0517 char *config[NUM_OPTIONS];
0518 struct mg_callbacks callbacks;
0519 void *user_data;
0520
0521 struct socket *listening_sockets;
0522 int num_listening_sockets;
0523
0524 volatile int num_threads;
0525 pthread_mutex_t mutex;
0526 pthread_cond_t cond;
0527
0528 struct socket queue[MGSQLEN];
0529 volatile int sq_head;
0530 volatile int sq_tail;
0531 pthread_cond_t sq_full;
0532 pthread_cond_t sq_empty;
0533 };
0534
0535 struct mg_connection {
0536 struct mg_request_info request_info;
0537 struct mg_context *ctx;
0538 SSL *ssl;
0539 SSL_CTX *client_ssl_ctx;
0540 struct socket client;
0541 time_t birth_time;
0542 int64_t num_bytes_sent;
0543 int64_t content_len;
0544 int64_t consumed_content;
0545 char *buf;
0546 char *path_info;
0547 int must_close;
0548 int buf_size;
0549 int request_len;
0550 int data_len;
0551 int status_code;
0552 int throttle;
0553 time_t last_throttle_time;
0554 int64_t last_throttle_bytes;
0555 };
0556
0557
0558 struct de {
0559 struct mg_connection *conn;
0560 char *file_name;
0561 struct file file;
0562 };
0563
0564 const char **mg_get_valid_option_names(void) {
0565 return config_options;
0566 }
0567
0568 static int is_file_in_memory(struct mg_connection *conn, const char *path,
0569 struct file *filep) {
0570 size_t size = 0;
0571 if ((filep->membuf = conn->ctx->callbacks.open_file == NULL ? NULL :
0572 conn->ctx->callbacks.open_file(conn, path, &size)) != NULL) {
0573
0574
0575 filep->size = size;
0576 }
0577 return filep->membuf != NULL;
0578 }
0579
0580 static int is_file_opened(const struct file *filep) {
0581 return filep->membuf != NULL || filep->fp != NULL;
0582 }
0583
0584 static int mg_fopen(struct mg_connection *conn, const char *path,
0585 const char *mode, struct file *filep) {
0586 if (!is_file_in_memory(conn, path, filep)) {
0587 #ifdef _WIN32
0588 wchar_t wbuf[PATH_MAX], wmode[20];
0589 to_unicode(path, wbuf, ARRAY_SIZE(wbuf));
0590 MultiByteToWideChar(CP_UTF8, 0, mode, -1, wmode, ARRAY_SIZE(wmode));
0591 filep->fp = _wfopen(wbuf, wmode);
0592 #else
0593 filep->fp = fopen(path, mode);
0594 #endif
0595 }
0596
0597 return is_file_opened(filep);
0598 }
0599
0600 static void mg_fclose(struct file *filep) {
0601 if (filep != NULL && filep->fp != NULL) {
0602 fclose(filep->fp);
0603 }
0604 }
0605
0606 static int get_option_index(const char *name) {
0607 int i;
0608
0609 for (i = 0; config_options[i * 2] != NULL; i++) {
0610 if (strcmp(config_options[i * 2], name) == 0) {
0611 return i;
0612 }
0613 }
0614 return -1;
0615 }
0616
0617 const char *mg_get_option(const struct mg_context *ctx, const char *name) {
0618 int i;
0619 if ((i = get_option_index(name)) == -1) {
0620 return NULL;
0621 } else if (ctx->config[i] == NULL) {
0622 return "";
0623 } else {
0624 return ctx->config[i];
0625 }
0626 }
0627
0628 static void sockaddr_to_string(char *buf, size_t len,
0629 const union usa *usa) {
0630 buf[0] = '\0';
0631 #if defined(USE_IPV6)
0632 inet_ntop(usa->sa.sa_family, usa->sa.sa_family == AF_INET ?
0633 (void *) &usa->sin.sin_addr :
0634 (void *) &usa->sin6.sin6_addr, buf, len);
0635 #elif defined(_WIN32)
0636
0637 strncpy(buf, inet_ntoa(usa->sin.sin_addr), len);
0638 #else
0639 inet_ntop(usa->sa.sa_family, (void *) &usa->sin.sin_addr, buf, len);
0640 #endif
0641 }
0642
0643 static void cry(struct mg_connection *conn,
0644 PRINTF_FORMAT_STRING(const char *fmt), ...) PRINTF_ARGS(2, 3);
0645
0646
0647 static void cry(struct mg_connection *conn, const char *fmt, ...) {
0648 char buf[MG_BUF_LEN], src_addr[IP_ADDR_STR_LEN];
0649 va_list ap;
0650 FILE *fp;
0651 time_t timestamp;
0652
0653 va_start(ap, fmt);
0654 (void) vsnprintf(buf, sizeof(buf), fmt, ap);
0655 va_end(ap);
0656
0657
0658
0659
0660 if (conn->ctx->callbacks.log_message == NULL ||
0661 conn->ctx->callbacks.log_message(conn, buf) == 0) {
0662 fp = conn->ctx == NULL || conn->ctx->config[ERROR_LOG_FILE] == NULL ? NULL :
0663 fopen(conn->ctx->config[ERROR_LOG_FILE], "a+");
0664
0665 if (fp != NULL) {
0666 flockfile(fp);
0667 timestamp = time(NULL);
0668
0669 sockaddr_to_string(src_addr, sizeof(src_addr), &conn->client.rsa);
0670 fprintf(fp, "[%010lu] [error] [client %s] ", (unsigned long) timestamp,
0671 src_addr);
0672
0673 if (conn->request_info.request_method != NULL) {
0674 fprintf(fp, "%s %s: ", conn->request_info.request_method,
0675 conn->request_info.uri);
0676 }
0677
0678 fprintf(fp, "%s", buf);
0679 fputc('\n', fp);
0680 funlockfile(fp);
0681 fclose(fp);
0682 }
0683 }
0684 }
0685
0686
0687
0688 static struct mg_connection *fc(struct mg_context *ctx) {
0689 static struct mg_connection fake_connection;
0690 fake_connection.ctx = ctx;
0691 return &fake_connection;
0692 }
0693
0694 const char *mg_version(void) {
0695 return MONGOOSE_VERSION;
0696 }
0697
0698 struct mg_request_info *mg_get_request_info(struct mg_connection *conn) {
0699 return &conn->request_info;
0700 }
0701
0702 static void mg_strlcpy(register char *dst, register const char *src, size_t n) {
0703 for (; *src != '\0' && n > 1; n--) {
0704 *dst++ = *src++;
0705 }
0706 *dst = '\0';
0707 }
0708
0709 static int lowercase(const char *s) {
0710 return tolower(* (const unsigned char *) s);
0711 }
0712
0713 static int mg_strncasecmp(const char *s1, const char *s2, size_t len) {
0714 int diff = 0;
0715
0716 if (len > 0)
0717 do {
0718 diff = lowercase(s1++) - lowercase(s2++);
0719 } while (diff == 0 && s1[-1] != '\0' && --len > 0);
0720
0721 return diff;
0722 }
0723
0724 static int mg_strcasecmp(const char *s1, const char *s2) {
0725 int diff;
0726
0727 do {
0728 diff = lowercase(s1++) - lowercase(s2++);
0729 } while (diff == 0 && s1[-1] != '\0');
0730
0731 return diff;
0732 }
0733
0734 static char * mg_strndup(const char *ptr, size_t len) {
0735 char *p;
0736
0737 if ((p = (char *) malloc(len + 1)) != NULL) {
0738 mg_strlcpy(p, ptr, len + 1);
0739 }
0740
0741 return p;
0742 }
0743
0744 static char * mg_strdup(const char *str) {
0745 return mg_strndup(str, strlen(str));
0746 }
0747
0748 static const char *mg_strcasestr(const char *big_str, const char *small_str) {
0749 int i, big_len = strlen(big_str), small_len = strlen(small_str);
0750
0751 for (i = 0; i <= big_len - small_len; i++) {
0752 if (mg_strncasecmp(big_str + i, small_str, small_len) == 0) {
0753 return big_str + i;
0754 }
0755 }
0756
0757 return NULL;
0758 }
0759
0760
0761
0762
0763
0764 static int mg_vsnprintf(struct mg_connection *conn, char *buf, size_t buflen,
0765 const char *fmt, va_list ap) {
0766 int n;
0767
0768 if (buflen == 0)
0769 return 0;
0770
0771 n = vsnprintf(buf, buflen, fmt, ap);
0772
0773 if (n < 0) {
0774 cry(conn, "vsnprintf error");
0775 n = 0;
0776 } else if (n >= (int) buflen) {
0777 cry(conn, "truncating vsnprintf buffer: [%.*s]",
0778 n > 200 ? 200 : n, buf);
0779 n = (int) buflen - 1;
0780 }
0781 buf[n] = '\0';
0782
0783 return n;
0784 }
0785
0786 static int mg_snprintf(struct mg_connection *conn, char *buf, size_t buflen,
0787 PRINTF_FORMAT_STRING(const char *fmt), ...)
0788 PRINTF_ARGS(4, 5);
0789
0790 static int mg_snprintf(struct mg_connection *conn, char *buf, size_t buflen,
0791 const char *fmt, ...) {
0792 va_list ap;
0793 int n;
0794
0795 va_start(ap, fmt);
0796 n = mg_vsnprintf(conn, buf, buflen, fmt, ap);
0797 va_end(ap);
0798
0799 return n;
0800 }
0801
0802
0803
0804
0805
0806 static char *skip_quoted(char **buf, const char *delimiters,
0807 const char *whitespace, char quotechar) {
0808 char *p, *begin_word, *end_word, *end_whitespace;
0809
0810 begin_word = *buf;
0811 end_word = begin_word + strcspn(begin_word, delimiters);
0812
0813
0814 if (end_word > begin_word) {
0815 p = end_word - 1;
0816 while (*p == quotechar) {
0817
0818 if (*end_word == '\0') {
0819
0820 *p = '\0';
0821 break;
0822 } else {
0823 size_t end_off = strcspn(end_word + 1, delimiters);
0824 memmove (p, end_word, end_off + 1);
0825 p += end_off;
0826 end_word += end_off + 1;
0827 }
0828 }
0829 for (p++; p < end_word; p++) {
0830 *p = '\0';
0831 }
0832 }
0833
0834 if (*end_word == '\0') {
0835 *buf = end_word;
0836 } else {
0837 end_whitespace = end_word + 1 + strspn(end_word + 1, whitespace);
0838
0839 for (p = end_word; p < end_whitespace; p++) {
0840 *p = '\0';
0841 }
0842
0843 *buf = end_whitespace;
0844 }
0845
0846 return begin_word;
0847 }
0848
0849
0850
0851 static char *skip(char **buf, const char *delimiters) {
0852 return skip_quoted(buf, delimiters, delimiters, 0);
0853 }
0854
0855
0856
0857 static const char *get_header(const struct mg_request_info *ri,
0858 const char *name) {
0859 int i;
0860
0861 for (i = 0; i < ri->num_headers; i++)
0862 if (!mg_strcasecmp(name, ri->http_headers[i].name))
0863 return ri->http_headers[i].value;
0864
0865 return NULL;
0866 }
0867
0868 const char *mg_get_header(const struct mg_connection *conn, const char *name) {
0869 return get_header(&conn->request_info, name);
0870 }
0871
0872
0873
0874
0875
0876
0877
0878 static const char *next_option(const char *list, struct vec *val,
0879 struct vec *eq_val) {
0880 if (list == NULL || *list == '\0') {
0881
0882 list = NULL;
0883 } else {
0884 val->ptr = list;
0885 if ((list = strchr(val->ptr, ',')) != NULL) {
0886
0887 val->len = list - val->ptr;
0888 list++;
0889 } else {
0890
0891 list = val->ptr + strlen(val->ptr);
0892 val->len = list - val->ptr;
0893 }
0894
0895 if (eq_val != NULL) {
0896
0897
0898 eq_val->len = 0;
0899 eq_val->ptr = (const char *) memchr(val->ptr, '=', val->len);
0900 if (eq_val->ptr != NULL) {
0901 eq_val->ptr++;
0902 eq_val->len = val->ptr + val->len - eq_val->ptr;
0903 val->len = (eq_val->ptr - val->ptr) - 1;
0904 }
0905 }
0906 }
0907
0908 return list;
0909 }
0910
0911
0912 static int match_prefix(const char *pattern, int pattern_len, const char *str) {
0913 const char *or_str;
0914 int i, j, len, res;
0915
0916 if ((or_str = (const char *) memchr(pattern, '|', pattern_len)) != NULL) {
0917 res = match_prefix(pattern, or_str - pattern, str);
0918 return res > 0 ? res :
0919 match_prefix(or_str + 1, (pattern + pattern_len) - (or_str + 1), str);
0920 }
0921
0922 i = j = 0;
0923 res = -1;
0924 for (; i < pattern_len; i++, j++) {
0925 if (pattern[i] == '?' && str[j] != '\0') {
0926 continue;
0927 } else if (pattern[i] == '$') {
0928 return str[j] == '\0' ? j : -1;
0929 } else if (pattern[i] == '*') {
0930 i++;
0931 if (pattern[i] == '*') {
0932 i++;
0933 len = (int) strlen(str + j);
0934 } else {
0935 len = (int) strcspn(str + j, "/");
0936 }
0937 if (i == pattern_len) {
0938 return j + len;
0939 }
0940 do {
0941 res = match_prefix(pattern + i, pattern_len - i, str + j + len);
0942 } while (res == -1 && len-- > 0);
0943 return res == -1 ? -1 : j + res + len;
0944 } else if (lowercase(&pattern[i]) != lowercase(&str[j])) {
0945 return -1;
0946 }
0947 }
0948 return j;
0949 }
0950
0951
0952
0953
0954 static int should_keep_alive(const struct mg_connection *conn) {
0955 const char *http_version = conn->request_info.http_version;
0956 const char *header = mg_get_header(conn, "Connection");
0957 if (conn->must_close ||
0958 conn->status_code == 401 ||
0959 mg_strcasecmp(conn->ctx->config[ENABLE_KEEP_ALIVE], "yes") != 0 ||
0960 (header != NULL && mg_strcasecmp(header, "keep-alive") != 0) ||
0961 (header == NULL && http_version && strcmp(http_version, "1.1"))) {
0962 return 0;
0963 }
0964 return 1;
0965 }
0966
0967 static const char *suggest_connection_header(const struct mg_connection *conn) {
0968 return should_keep_alive(conn) ? "keep-alive" : "close";
0969 }
0970
0971 static void send_http_error(struct mg_connection *, int, const char *,
0972 PRINTF_FORMAT_STRING(const char *fmt), ...)
0973 PRINTF_ARGS(4, 5);
0974
0975
0976 static void send_http_error(struct mg_connection *conn, int status,
0977 const char *reason, const char *fmt, ...) {
0978 char buf[MG_BUF_LEN];
0979 va_list ap;
0980 int len = 0;
0981
0982 conn->status_code = status;
0983 if (conn->ctx->callbacks.http_error == NULL ||
0984 conn->ctx->callbacks.http_error(conn, status)) {
0985 buf[0] = '\0';
0986
0987
0988 if (status > 199 && status != 204 && status != 304) {
0989 len = mg_snprintf(conn, buf, sizeof(buf), "Error %d: %s", status, reason);
0990 buf[len++] = '\n';
0991
0992 va_start(ap, fmt);
0993 len += mg_vsnprintf(conn, buf + len, sizeof(buf) - len, fmt, ap);
0994 va_end(ap);
0995 }
0996 DEBUG_TRACE(("[%s]", buf));
0997
0998 mg_printf(conn, "HTTP/1.1 %d %s\r\n"
0999 "Content-Length: %d\r\n"
1000 "Connection: %s\r\n\r\n", status, reason, len,
1001 suggest_connection_header(conn));
1002 conn->num_bytes_sent += mg_printf(conn, "%s", buf);
1003 }
1004 }
1005
1006 #if defined(_WIN32) && !defined(__SYMBIAN32__)
1007 static int pthread_mutex_init(pthread_mutex_t *mutex, void *unused) {
1008 (void) unused;
1009 *mutex = CreateMutex(NULL, FALSE, NULL);
1010 return *mutex == NULL ? -1 : 0;
1011 }
1012
1013 static int pthread_mutex_destroy(pthread_mutex_t *mutex) {
1014 return CloseHandle(*mutex) == 0 ? -1 : 0;
1015 }
1016
1017 static int pthread_mutex_lock(pthread_mutex_t *mutex) {
1018 return WaitForSingleObject(*mutex, INFINITE) == WAIT_OBJECT_0? 0 : -1;
1019 }
1020
1021 static int pthread_mutex_unlock(pthread_mutex_t *mutex) {
1022 return ReleaseMutex(*mutex) == 0 ? -1 : 0;
1023 }
1024
1025 static int pthread_cond_init(pthread_cond_t *cv, const void *unused) {
1026 (void) unused;
1027 cv->signal = CreateEvent(NULL, FALSE, FALSE, NULL);
1028 cv->broadcast = CreateEvent(NULL, TRUE, FALSE, NULL);
1029 return cv->signal != NULL && cv->broadcast != NULL ? 0 : -1;
1030 }
1031
1032 static int pthread_cond_wait(pthread_cond_t *cv, pthread_mutex_t *mutex) {
1033 HANDLE handles[] = {cv->signal, cv->broadcast};
1034 ReleaseMutex(*mutex);
1035 WaitForMultipleObjects(2, handles, FALSE, INFINITE);
1036 return WaitForSingleObject(*mutex, INFINITE) == WAIT_OBJECT_0? 0 : -1;
1037 }
1038
1039 static int pthread_cond_signal(pthread_cond_t *cv) {
1040 return SetEvent(cv->signal) == 0 ? -1 : 0;
1041 }
1042
1043 static int pthread_cond_broadcast(pthread_cond_t *cv) {
1044
1045
1046 return PulseEvent(cv->broadcast) == 0 ? -1 : 0;
1047 }
1048
1049 static int pthread_cond_destroy(pthread_cond_t *cv) {
1050 return CloseHandle(cv->signal) && CloseHandle(cv->broadcast) ? 0 : -1;
1051 }
1052
1053
1054 static void change_slashes_to_backslashes(char *path) {
1055 int i;
1056
1057 for (i = 0; path[i] != '\0'; i++) {
1058 if (path[i] == '/')
1059 path[i] = '\\';
1060
1061 if (path[i] == '\\' && i > 0)
1062 while (path[i + 1] == '\\' || path[i + 1] == '/')
1063 (void) memmove(path + i + 1,
1064 path + i + 2, strlen(path + i + 1));
1065 }
1066 }
1067
1068
1069
1070 static void to_unicode(const char *path, wchar_t *wbuf, size_t wbuf_len) {
1071 char buf[PATH_MAX], buf2[PATH_MAX];
1072
1073 mg_strlcpy(buf, path, sizeof(buf));
1074 change_slashes_to_backslashes(buf);
1075
1076
1077
1078 memset(wbuf, 0, wbuf_len * sizeof(wchar_t));
1079 MultiByteToWideChar(CP_UTF8, 0, buf, -1, wbuf, (int) wbuf_len);
1080 WideCharToMultiByte(CP_UTF8, 0, wbuf, (int) wbuf_len, buf2, sizeof(buf2),
1081 NULL, NULL);
1082 if (strcmp(buf, buf2) != 0) {
1083 wbuf[0] = L'\0';
1084 }
1085 }
1086
1087 #if defined(_WIN32_WCE)
1088 static time_t time(time_t *ptime) {
1089 time_t t;
1090 SYSTEMTIME st;
1091 FILETIME ft;
1092
1093 GetSystemTime(&st);
1094 SystemTimeToFileTime(&st, &ft);
1095 t = SYS2UNIX_TIME(ft.dwLowDateTime, ft.dwHighDateTime);
1096
1097 if (ptime != NULL) {
1098 *ptime = t;
1099 }
1100
1101 return t;
1102 }
1103
1104 static struct tm *localtime(const time_t *ptime, struct tm *ptm) {
1105 int64_t t = ((int64_t) *ptime) * RATE_DIFF + EPOCH_DIFF;
1106 FILETIME ft, lft;
1107 SYSTEMTIME st;
1108 TIME_ZONE_INFORMATION tzinfo;
1109
1110 if (ptm == NULL) {
1111 return NULL;
1112 }
1113
1114 * (int64_t *) &ft = t;
1115 FileTimeToLocalFileTime(&ft, &lft);
1116 FileTimeToSystemTime(&lft, &st);
1117 ptm->tm_year = st.wYear - 1900;
1118 ptm->tm_mon = st.wMonth - 1;
1119 ptm->tm_wday = st.wDayOfWeek;
1120 ptm->tm_mday = st.wDay;
1121 ptm->tm_hour = st.wHour;
1122 ptm->tm_min = st.wMinute;
1123 ptm->tm_sec = st.wSecond;
1124 ptm->tm_yday = 0;
1125 ptm->tm_isdst =
1126 GetTimeZoneInformation(&tzinfo) == TIME_ZONE_ID_DAYLIGHT ? 1 : 0;
1127
1128 return ptm;
1129 }
1130
1131 static struct tm *gmtime(const time_t *ptime, struct tm *ptm) {
1132
1133 return localtime(ptime, ptm);
1134 }
1135
1136 static size_t strftime(char *dst, size_t dst_size, const char *fmt,
1137 const struct tm *tm) {
1138 (void) snprintf(dst, dst_size, "implement strftime() for WinCE");
1139 return 0;
1140 }
1141 #endif
1142
1143
1144
1145
1146
1147 static int path_cannot_disclose_cgi(const char *path) {
1148 static const char *allowed_last_characters = "_-";
1149 int last = path[strlen(path) - 1];
1150 return isalnum(last) || strchr(allowed_last_characters, last) != NULL;
1151 }
1152
1153 static int mg_stat(struct mg_connection *conn, const char *path,
1154 struct file *filep) {
1155 wchar_t wbuf[PATH_MAX];
1156 WIN32_FILE_ATTRIBUTE_DATA info;
1157
1158 if (!is_file_in_memory(conn, path, filep)) {
1159 to_unicode(path, wbuf, ARRAY_SIZE(wbuf));
1160 if (GetFileAttributesExW(wbuf, GetFileExInfoStandard, &info) != 0) {
1161 filep->size = MAKEUQUAD(info.nFileSizeLow, info.nFileSizeHigh);
1162 filep->modification_time = SYS2UNIX_TIME(
1163 info.ftLastWriteTime.dwLowDateTime,
1164 info.ftLastWriteTime.dwHighDateTime);
1165 filep->is_directory = info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY;
1166
1167
1168
1169 if (!filep->is_directory && !path_cannot_disclose_cgi(path)) {
1170 memset(filep, 0, sizeof(*filep));
1171 }
1172 }
1173 }
1174
1175 return filep->membuf != NULL || filep->modification_time != 0;
1176 }
1177
1178 static int mg_remove(const char *path) {
1179 wchar_t wbuf[PATH_MAX];
1180 to_unicode(path, wbuf, ARRAY_SIZE(wbuf));
1181 return DeleteFileW(wbuf) ? 0 : -1;
1182 }
1183
1184 static int mg_mkdir(const char *path, int mode) {
1185 char buf[PATH_MAX];
1186 wchar_t wbuf[PATH_MAX];
1187
1188 (void) mode;
1189 mg_strlcpy(buf, path, sizeof(buf));
1190 change_slashes_to_backslashes(buf);
1191
1192 (void) MultiByteToWideChar(CP_UTF8, 0, buf, -1, wbuf, ARRAY_SIZE(wbuf));
1193
1194 return CreateDirectoryW(wbuf, NULL) ? 0 : -1;
1195 }
1196
1197
1198 static DIR * opendir(const char *name) {
1199 DIR *dir = NULL;
1200 wchar_t wpath[PATH_MAX];
1201 DWORD attrs;
1202
1203 if (name == NULL) {
1204 SetLastError(ERROR_BAD_ARGUMENTS);
1205 } else if ((dir = (DIR *) malloc(sizeof(*dir))) == NULL) {
1206 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1207 } else {
1208 to_unicode(name, wpath, ARRAY_SIZE(wpath));
1209 attrs = GetFileAttributesW(wpath);
1210 if (attrs != 0xFFFFFFFF &&
1211 ((attrs & FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY)) {
1212 (void) wcscat(wpath, L"\\*");
1213 dir->handle = FindFirstFileW(wpath, &dir->info);
1214 dir->result.d_name[0] = '\0';
1215 } else {
1216 free(dir);
1217 dir = NULL;
1218 }
1219 }
1220
1221 return dir;
1222 }
1223
1224 static int closedir(DIR *dir) {
1225 int result = 0;
1226
1227 if (dir != NULL) {
1228 if (dir->handle != INVALID_HANDLE_VALUE)
1229 result = FindClose(dir->handle) ? 0 : -1;
1230
1231 free(dir);
1232 } else {
1233 result = -1;
1234 SetLastError(ERROR_BAD_ARGUMENTS);
1235 }
1236
1237 return result;
1238 }
1239
1240 static struct dirent *readdir(DIR *dir) {
1241 struct dirent *result = 0;
1242
1243 if (dir) {
1244 if (dir->handle != INVALID_HANDLE_VALUE) {
1245 result = &dir->result;
1246 (void) WideCharToMultiByte(CP_UTF8, 0,
1247 dir->info.cFileName, -1, result->d_name,
1248 sizeof(result->d_name), NULL, NULL);
1249
1250 if (!FindNextFileW(dir->handle, &dir->info)) {
1251 (void) FindClose(dir->handle);
1252 dir->handle = INVALID_HANDLE_VALUE;
1253 }
1254
1255 } else {
1256 SetLastError(ERROR_FILE_NOT_FOUND);
1257 }
1258 } else {
1259 SetLastError(ERROR_BAD_ARGUMENTS);
1260 }
1261
1262 return result;
1263 }
1264
1265 static void set_close_on_exec(SOCKET sock) {
1266 (void) SetHandleInformation((HANDLE) sock, HANDLE_FLAG_INHERIT, 0);
1267 }
1268
1269 int mg_start_thread(mg_thread_func_t f, void *p) {
1270 return (long)_beginthread((void (__cdecl *)(void *)) f, 0, p) == -1L ? -1 : 0;
1271 }
1272
1273 static HANDLE dlopen(const char *dll_name, int flags) {
1274 wchar_t wbuf[PATH_MAX];
1275 (void) flags;
1276 to_unicode(dll_name, wbuf, ARRAY_SIZE(wbuf));
1277 return LoadLibraryW(wbuf);
1278 }
1279
1280 #if !defined(NO_CGI)
1281 #define SIGKILL 0
1282 static int kill(pid_t pid, int sig_num) {
1283 (void) TerminateProcess(pid, sig_num);
1284 (void) CloseHandle(pid);
1285 return 0;
1286 }
1287
1288 static void trim_trailing_whitespaces(char *s) {
1289 char *e = s + strlen(s) - 1;
1290 while (e > s && isspace(* (unsigned char *) e)) {
1291 *e-- = '\0';
1292 }
1293 }
1294
1295 static pid_t spawn_process(struct mg_connection *conn, const char *prog,
1296 char *envblk, char *envp[], int fdin,
1297 int fdout, const char *dir) {
1298 HANDLE me;
1299 char *p, *interp, full_interp[PATH_MAX], full_dir[PATH_MAX],
1300 cmdline[PATH_MAX], buf[PATH_MAX];
1301 struct file file = STRUCT_FILE_INITIALIZER;
1302 STARTUPINFOA si;
1303 PROCESS_INFORMATION pi = { 0 };
1304
1305 (void) envp;
1306
1307 memset(&si, 0, sizeof(si));
1308 si.cb = sizeof(si);
1309
1310
1311 si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
1312 si.wShowWindow = SW_HIDE;
1313
1314 me = GetCurrentProcess();
1315 DuplicateHandle(me, (HANDLE) _get_osfhandle(fdin), me,
1316 &si.hStdInput, 0, TRUE, DUPLICATE_SAME_ACCESS);
1317 DuplicateHandle(me, (HANDLE) _get_osfhandle(fdout), me,
1318 &si.hStdOutput, 0, TRUE, DUPLICATE_SAME_ACCESS);
1319
1320
1321 interp = conn->ctx->config[CGI_INTERPRETER];
1322 if (interp == NULL) {
1323 buf[0] = buf[1] = '\0';
1324
1325
1326 snprintf(cmdline, sizeof(cmdline), "%s%c%s", dir, '/', prog);
1327 if (mg_fopen(conn, cmdline, "r", &file)) {
1328 p = (char *) file.membuf;
1329 mg_fgets(buf, sizeof(buf), &file, &p);
1330 mg_fclose(&file);
1331 buf[sizeof(buf) - 1] = '\0';
1332 }
1333
1334 if (buf[0] == '#' && buf[1] == '!') {
1335 trim_trailing_whitespaces(buf + 2);
1336 } else {
1337 buf[2] = '\0';
1338 }
1339 interp = buf + 2;
1340 }
1341
1342 if (interp[0] != '\0') {
1343 GetFullPathNameA(interp, sizeof(full_interp), full_interp, NULL);
1344 interp = full_interp;
1345 }
1346 GetFullPathNameA(dir, sizeof(full_dir), full_dir, NULL);
1347
1348 mg_snprintf(conn, cmdline, sizeof(cmdline), "%s%s\"%s\\%s\"",
1349 interp, interp[0] == '\0' ? "" : " ", full_dir, prog);
1350
1351 DEBUG_TRACE(("Running [%s]", cmdline));
1352 if (CreateProcessA(NULL, cmdline, NULL, NULL, TRUE,
1353 CREATE_NEW_PROCESS_GROUP, envblk, NULL, &si, &pi) == 0) {
1354 cry(conn, "%s: CreateProcess(%s): %ld",
1355 __func__, cmdline, ERRNO);
1356 pi.hProcess = (pid_t) -1;
1357 }
1358
1359 (void) CloseHandle(si.hStdOutput);
1360 (void) CloseHandle(si.hStdInput);
1361 (void) CloseHandle(pi.hThread);
1362
1363 return (pid_t) pi.hProcess;
1364 }
1365 #endif
1366
1367 static int set_non_blocking_mode(SOCKET sock) {
1368 unsigned long on = 1;
1369 return ioctlsocket(sock, FIONBIO, &on);
1370 }
1371
1372 #else
1373 static int mg_stat(struct mg_connection *conn, const char *path,
1374 struct file *filep) {
1375 struct stat st;
1376
1377 if (!is_file_in_memory(conn, path, filep) && !stat(path, &st)) {
1378 filep->size = st.st_size;
1379 filep->modification_time = st.st_mtime;
1380 filep->is_directory = S_ISDIR(st.st_mode);
1381 } else {
1382 filep->modification_time = (time_t) 0;
1383 }
1384
1385 return filep->membuf != NULL || filep->modification_time != (time_t) 0;
1386 }
1387
1388 static void set_close_on_exec(int fd) {
1389 fcntl(fd, F_SETFD, FD_CLOEXEC);
1390 }
1391
1392 int mg_start_thread(mg_thread_func_t func, void *param) {
1393 pthread_t thread_id;
1394 pthread_attr_t attr;
1395 int result;
1396 struct mg_context* ctx = param;
1397 char* stacksize = ctx->config[THREAD_STACK_SIZE];
1398 char* priority = ctx->config[THREAD_PRIORITY];
1399 char* policy = ctx->config[THREAD_POLICY];
1400 int noinheritsched = 0;
1401
1402 (void) pthread_attr_init(&attr);
1403 (void) pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
1404
1405 #if USE_STACK_SIZE > 1
1406
1407 if (stacksize == NULL)
1408 (void) pthread_attr_setstacksize(&attr, USE_STACK_SIZE);
1409 #endif
1410
1411 if (stacksize != NULL) {
1412 size_t size = atoi(stacksize);
1413 (void) pthread_attr_setstacksize(&attr, size);
1414 }
1415
1416 if (priority != NULL) {
1417 struct sched_param sched_param;
1418 memset(&sched_param, 0, sizeof(sched_param));
1419 sched_param.sched_priority = atoi(priority);
1420 (void) pthread_attr_setschedparam(&attr, &sched_param);
1421 noinheritsched = 1;
1422 }
1423
1424 if (policy != NULL) {
1425 int p_policy;
1426 (void) pthread_attr_getschedpolicy(&attr, &p_policy);
1427
1428 switch (policy[0]) {
1429 case 'o':
1430 p_policy = SCHED_OTHER;
1431 break;
1432 case 'f':
1433 p_policy = SCHED_FIFO;
1434 break;
1435 case 'r':
1436 p_policy = SCHED_RR;
1437 break;
1438 #if defined(_POSIX_SPORADIC_SERVER) || defined(_POSIX_THREAD_SPORADIC_SERVER)
1439 case 's':
1440 p_policy = SCHED_SPORADIC;
1441 break;
1442 #endif
1443 default:
1444 cry(fc(ctx), "%s: Unknown scheduler: %s", __func__, policy);
1445 break;
1446 }
1447
1448 (void) pthread_attr_setschedpolicy(&attr, p_policy);
1449
1450 noinheritsched = 1;
1451 }
1452
1453 if (noinheritsched != 0) {
1454 (void) pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED);
1455 }
1456
1457 result = pthread_create(&thread_id, &attr, func, param);
1458 pthread_attr_destroy(&attr);
1459
1460 return result;
1461 }
1462
1463 #ifndef NO_CGI
1464 static pid_t spawn_process(struct mg_connection *conn, const char *prog,
1465 char *envblk, char *envp[], int fdin,
1466 int fdout, const char *dir) {
1467 pid_t pid;
1468 const char *interp;
1469
1470 (void) envblk;
1471
1472 if ((pid = fork()) == -1) {
1473
1474 send_http_error(conn, 500, http_500_error, "fork(): %s", strerror(ERRNO));
1475 } else if (pid == 0) {
1476
1477 if (chdir(dir) != 0) {
1478 cry(conn, "%s: chdir(%s): %s", __func__, dir, strerror(ERRNO));
1479 } else if (dup2(fdin, 0) == -1) {
1480 cry(conn, "%s: dup2(%d, 0): %s", __func__, fdin, strerror(ERRNO));
1481 } else if (dup2(fdout, 1) == -1) {
1482 cry(conn, "%s: dup2(%d, 1): %s", __func__, fdout, strerror(ERRNO));
1483 } else {
1484
1485
1486 (void) close(fdin);
1487 (void) close(fdout);
1488
1489
1490
1491
1492
1493 signal(SIGCHLD, SIG_DFL);
1494
1495 interp = conn->ctx->config[CGI_INTERPRETER];
1496 if (interp == NULL) {
1497 (void) execle(prog, prog, NULL, envp);
1498 cry(conn, "%s: execle(%s): %s", __func__, prog, strerror(ERRNO));
1499 } else {
1500 (void) execle(interp, interp, prog, NULL, envp);
1501 cry(conn, "%s: execle(%s %s): %s", __func__, interp, prog,
1502 strerror(ERRNO));
1503 }
1504 }
1505 exit(EXIT_FAILURE);
1506 }
1507
1508 return pid;
1509 }
1510 #endif
1511
1512 static int set_non_blocking_mode(SOCKET sock) {
1513 int flags;
1514
1515 flags = fcntl(sock, F_GETFL, 0);
1516 (void) fcntl(sock, F_SETFL, flags | O_NONBLOCK);
1517
1518 return 0;
1519 }
1520 #endif
1521
1522 #ifndef HAVE_POLL
1523 static int poll(struct pollfd *pfd, int n, int milliseconds) {
1524 struct timeval tv;
1525 #if __rtems__
1526 #define set (*set_prealloc)
1527 static fd_set *set_prealloc;
1528 static size_t set_size;
1529 #else
1530 fd_set set;
1531 #endif
1532 int i, result;
1533 SOCKET maxfd = 0;
1534
1535 tv.tv_sec = milliseconds / 1000;
1536 tv.tv_usec = (milliseconds % 1000) * 1000;
1537 #if __rtems__
1538 if (set_prealloc == NULL) {
1539 set_size =
1540 sizeof(fd_set) * (howmany(rtems_libio_number_iops, sizeof(fd_set) * 8));
1541 set_prealloc = malloc(set_size);
1542 if (set_prealloc == NULL) {
1543 errno = ENOMEM;
1544 return -1;
1545 }
1546 }
1547 memset(set_prealloc, 0, set_size);
1548 #else
1549 FD_ZERO(&set);
1550 #endif
1551
1552 for (i = 0; i < n; i++) {
1553 FD_SET((SOCKET) pfd[i].fd, &set);
1554 pfd[i].revents = 0;
1555
1556 if (pfd[i].fd > maxfd) {
1557 maxfd = pfd[i].fd;
1558 }
1559 }
1560
1561 if ((result = select(maxfd + 1, &set, NULL, NULL, &tv)) > 0) {
1562 for (i = 0; i < n; i++) {
1563 if (FD_ISSET(pfd[i].fd, &set)) {
1564 pfd[i].revents = POLLIN;
1565 }
1566 }
1567 }
1568
1569 return result;
1570 }
1571 #endif
1572
1573
1574
1575 static int64_t push(FILE *fp, SOCKET sock, SSL *ssl, const char *buf,
1576 int64_t len) {
1577 int64_t sent;
1578 int n, k;
1579
1580 (void) ssl;
1581 sent = 0;
1582 while (sent < len) {
1583
1584
1585 k = len - sent > INT_MAX ? INT_MAX : (int) (len - sent);
1586
1587 #ifndef NO_SSL
1588 if (ssl != NULL) {
1589 n = SSL_write(ssl, buf + sent, k);
1590 } else
1591 #endif
1592 if (fp != NULL) {
1593 n = (int) fwrite(buf + sent, 1, (size_t) k, fp);
1594 if (ferror(fp))
1595 n = -1;
1596 } else {
1597 n = send(sock, buf + sent, (size_t) k, MSG_NOSIGNAL);
1598 }
1599
1600 if (n <= 0)
1601 break;
1602
1603 sent += n;
1604 }
1605
1606 return sent;
1607 }
1608
1609
1610
1611 static int pull(FILE *fp, struct mg_connection *conn, char *buf, int len) {
1612 int nread;
1613
1614 if (fp != NULL) {
1615
1616
1617
1618 nread = read(fileno(fp), buf, (size_t) len);
1619 #ifndef NO_SSL
1620 } else if (conn->ssl != NULL) {
1621 nread = SSL_read(conn->ssl, buf, len);
1622 #endif
1623 } else {
1624 nread = recv(conn->client.sock, buf, (size_t) len, 0);
1625 }
1626
1627 return conn->ctx->stop_flag ? -1 : nread;
1628 }
1629
1630 static int pull_all(FILE *fp, struct mg_connection *conn, char *buf, int len) {
1631 int n, nread = 0;
1632
1633 while (len > 0 && conn->ctx->stop_flag == 0) {
1634 n = pull(fp, conn, buf + nread, len);
1635 if (n < 0) {
1636 nread = n;
1637 break;
1638 } else if (n == 0) {
1639 break;
1640 } else {
1641 conn->consumed_content += n;
1642 nread += n;
1643 len -= n;
1644 }
1645 }
1646
1647 return nread;
1648 }
1649
1650 int mg_read(struct mg_connection *conn, void *buf, size_t len) {
1651 int n, buffered_len, nread;
1652 const char *body;
1653
1654
1655 if (conn->consumed_content == 0 && conn->content_len == 0) {
1656 conn->content_len = INT64_MAX;
1657 conn->must_close = 1;
1658 }
1659
1660 nread = 0;
1661 if (conn->consumed_content < conn->content_len) {
1662
1663 int64_t to_read = conn->content_len - conn->consumed_content;
1664 if (to_read < (int64_t) len) {
1665 len = (size_t) to_read;
1666 }
1667
1668
1669 body = conn->buf + conn->request_len + conn->consumed_content;
1670 buffered_len = &conn->buf[conn->data_len] - body;
1671 if (buffered_len > 0) {
1672 if (len < (size_t) buffered_len) {
1673 buffered_len = (int) len;
1674 }
1675 memcpy(buf, body, (size_t) buffered_len);
1676 len -= buffered_len;
1677 conn->consumed_content += buffered_len;
1678 nread += buffered_len;
1679 buf = (char *) buf + buffered_len;
1680 }
1681
1682
1683 n = pull_all(NULL, conn, (char *) buf, (int) len);
1684 nread = n >= 0 ? nread + n : n;
1685 }
1686 return nread;
1687 }
1688
1689 int mg_write(struct mg_connection *conn, const void *buf, size_t len) {
1690 time_t now;
1691 int64_t n, total, allowed;
1692
1693 if (conn->throttle > 0) {
1694 if ((now = time(NULL)) != conn->last_throttle_time) {
1695 conn->last_throttle_time = now;
1696 conn->last_throttle_bytes = 0;
1697 }
1698 allowed = conn->throttle - conn->last_throttle_bytes;
1699 if (allowed > (int64_t) len) {
1700 allowed = len;
1701 }
1702 if ((total = push(NULL, conn->client.sock, conn->ssl, (const char *) buf,
1703 (int64_t) allowed)) == allowed) {
1704 buf = (char *) buf + total;
1705 conn->last_throttle_bytes += total;
1706 while (total < (int64_t) len && conn->ctx->stop_flag == 0) {
1707 allowed = conn->throttle > (int64_t) len - total ?
1708 (int64_t) len - total : conn->throttle;
1709 if ((n = push(NULL, conn->client.sock, conn->ssl, (const char *) buf,
1710 (int64_t) allowed)) != allowed) {
1711 break;
1712 }
1713 sleep(1);
1714 conn->last_throttle_bytes = allowed;
1715 conn->last_throttle_time = time(NULL);
1716 buf = (char *) buf + n;
1717 total += n;
1718 }
1719 }
1720 } else {
1721 total = push(NULL, conn->client.sock, conn->ssl, (const char *) buf,
1722 (int64_t) len);
1723 }
1724 return (int) total;
1725 }
1726
1727
1728 static int alloc_vprintf2(char **buf, const char *fmt, va_list ap) {
1729 va_list ap_copy;
1730 int size = MG_BUF_LEN;
1731 int len = -1;
1732
1733 *buf = NULL;
1734 while (len == -1) {
1735 if (*buf) free(*buf);
1736 *buf = malloc(size *= 4);
1737 if (!*buf) break;
1738 va_copy(ap_copy, ap);
1739 len = vsnprintf(*buf, size, fmt, ap_copy);
1740 }
1741
1742 return len;
1743 }
1744
1745
1746
1747
1748 static int alloc_vprintf(char **buf, size_t size, const char *fmt, va_list ap) {
1749 va_list ap_copy;
1750 int len;
1751
1752
1753
1754
1755
1756
1757 va_copy(ap_copy, ap);
1758 len = vsnprintf(NULL, 0, fmt, ap_copy);
1759
1760 if (len < 0) {
1761
1762
1763 va_copy(ap_copy, ap);
1764 len = alloc_vprintf2(buf, fmt, ap);
1765 } else if (len > (int) size &&
1766 (size = len + 1) > 0 &&
1767 (*buf = (char *) malloc(size)) == NULL) {
1768 len = -1;
1769 } else {
1770 va_copy(ap_copy, ap);
1771 vsnprintf(*buf, size, fmt, ap_copy);
1772 }
1773
1774 return len;
1775 }
1776
1777 static int mg_vprintf(struct mg_connection *conn, const char *fmt, va_list ap) {
1778 char mem[MG_BUF_LEN], *buf = mem;
1779 int len;
1780
1781 if ((len = alloc_vprintf(&buf, sizeof(mem), fmt, ap)) > 0) {
1782 len = mg_write(conn, buf, (size_t) len);
1783 }
1784 if (buf != mem && buf != NULL) {
1785 free(buf);
1786 }
1787
1788 return len;
1789 }
1790
1791 int mg_printf(struct mg_connection *conn, const char *fmt, ...) {
1792 va_list ap;
1793 va_start(ap, fmt);
1794 return mg_vprintf(conn, fmt, ap);
1795 }
1796
1797 int mg_url_decode(const char *src, int src_len, char *dst,
1798 int dst_len, int is_form_url_encoded) {
1799 int i, j, a, b;
1800 #define HEXTOI(x) (isdigit(x) ? x - '0' : x - 'W')
1801
1802 for (i = j = 0; i < src_len && j < dst_len - 1; i++, j++) {
1803 if (src[i] == '%' && i < src_len - 2 &&
1804 isxdigit(* (const unsigned char *) (src + i + 1)) &&
1805 isxdigit(* (const unsigned char *) (src + i + 2))) {
1806 a = tolower(* (const unsigned char *) (src + i + 1));
1807 b = tolower(* (const unsigned char *) (src + i + 2));
1808 dst[j] = (char) ((HEXTOI(a) << 4) | HEXTOI(b));
1809 i += 2;
1810 } else if (is_form_url_encoded && src[i] == '+') {
1811 dst[j] = ' ';
1812 } else {
1813 dst[j] = src[i];
1814 }
1815 }
1816
1817 dst[j] = '\0';
1818
1819 return i >= src_len ? j : -1;
1820 }
1821
1822 int mg_get_var(const char *data, size_t data_len, const char *name,
1823 char *dst, size_t dst_len) {
1824 const char *p, *e, *s;
1825 size_t name_len;
1826 int len;
1827
1828 if (dst == NULL || dst_len == 0) {
1829 len = -2;
1830 } else if (data == NULL || name == NULL || data_len == 0) {
1831 len = -1;
1832 dst[0] = '\0';
1833 } else {
1834 name_len = strlen(name);
1835 e = data + data_len;
1836 len = -1;
1837 dst[0] = '\0';
1838
1839
1840 for (p = data; p + name_len < e; p++) {
1841 if ((p == data || p[-1] == '&') && p[name_len] == '=' &&
1842 !mg_strncasecmp(name, p, name_len)) {
1843
1844
1845 p += name_len + 1;
1846
1847
1848 s = (const char *) memchr(p, '&', (size_t)(e - p));
1849 if (s == NULL) {
1850 s = e;
1851 }
1852 assert(s >= p);
1853
1854
1855 len = mg_url_decode(p, (size_t)(s - p), dst, dst_len, 1);
1856
1857
1858 if (len == -1) {
1859 len = -2;
1860 }
1861 break;
1862 }
1863 }
1864 }
1865
1866 return len;
1867 }
1868
1869 int mg_get_cookie(const char *cookie_header, const char *var_name,
1870 char *dst, size_t dst_size) {
1871 const char *s, *p, *end;
1872 int name_len, len = -1;
1873
1874 if (dst == NULL || dst_size == 0) {
1875 len = -2;
1876 } else if (var_name == NULL || (s = cookie_header) == NULL) {
1877 len = -1;
1878 dst[0] = '\0';
1879 } else {
1880 name_len = (int) strlen(var_name);
1881 end = s + strlen(s);
1882 dst[0] = '\0';
1883
1884 for (; (s = mg_strcasestr(s, var_name)) != NULL; s += name_len) {
1885 if (s[name_len] == '=') {
1886 s += name_len + 1;
1887 if ((p = strchr(s, ' ')) == NULL)
1888 p = end;
1889 if (p[-1] == ';')
1890 p--;
1891 if (*s == '"' && p[-1] == '"' && p > s + 1) {
1892 s++;
1893 p--;
1894 }
1895 if ((size_t) (p - s) < dst_size) {
1896 len = p - s;
1897 mg_strlcpy(dst, s, (size_t) len + 1);
1898 } else {
1899 len = -3;
1900 }
1901 break;
1902 }
1903 }
1904 }
1905 return len;
1906 }
1907
1908 static void convert_uri_to_file_name(struct mg_connection *conn, char *buf,
1909 size_t buf_len, struct file *filep) {
1910 struct vec a, b;
1911 const char *rewrite, *uri = conn->request_info.uri,
1912 *root = conn->ctx->config[DOCUMENT_ROOT];
1913 char *p;
1914 int match_len;
1915 char gz_path[PATH_MAX + 3];
1916 char const* accept_encoding;
1917
1918
1919
1920
1921 mg_snprintf(conn, buf, buf_len - 1, "%s%s",
1922 root == NULL ? "" : root,
1923 root == NULL ? "" : uri);
1924
1925 rewrite = conn->ctx->config[REWRITE];
1926 while ((rewrite = next_option(rewrite, &a, &b)) != NULL) {
1927 if ((match_len = match_prefix(a.ptr, a.len, uri)) > 0) {
1928 mg_snprintf(conn, buf, buf_len - 1, "%.*s%s", (int) b.len, b.ptr,
1929 uri + match_len);
1930 break;
1931 }
1932 }
1933
1934 if (mg_stat(conn, buf, filep)) return;
1935
1936
1937
1938
1939
1940
1941
1942 if ((accept_encoding = mg_get_header(conn, "Accept-Encoding")) != NULL) {
1943 if (strstr(accept_encoding,"gzip") != NULL) {
1944 snprintf(gz_path, sizeof(gz_path), "%s.gz", buf);
1945 if (mg_stat(conn, gz_path, filep)) {
1946 filep->gzipped = 1;
1947 return;
1948 }
1949 }
1950 }
1951
1952
1953 for (p = buf + strlen(buf); p > buf + 1; p--) {
1954 if (*p == '/') {
1955 *p = '\0';
1956 if (match_prefix(conn->ctx->config[CGI_EXTENSIONS],
1957 strlen(conn->ctx->config[CGI_EXTENSIONS]), buf) > 0 &&
1958 mg_stat(conn, buf, filep)) {
1959
1960
1961
1962
1963
1964 conn->path_info = p + 1;
1965 memmove(p + 2, p + 1, strlen(p + 1) + 1);
1966 p[1] = '/';
1967 break;
1968 } else {
1969 *p = '/';
1970 }
1971 }
1972 }
1973 }
1974
1975
1976
1977
1978
1979 static int get_request_len(const char *buf, int buflen) {
1980 const char *s, *e;
1981 int len = 0;
1982
1983 for (s = buf, e = s + buflen - 1; len <= 0 && s < e; s++)
1984
1985 if (!isprint(* (const unsigned char *) s) && *s != '\r' &&
1986 *s != '\n' && * (const unsigned char *) s < 128) {
1987 len = -1;
1988 break;
1989
1990 } else if (s[0] == '\n' && s[1] == '\n') {
1991 len = (int) (s - buf) + 2;
1992 } else if (s[0] == '\n' && &s[1] < e &&
1993 s[1] == '\r' && s[2] == '\n') {
1994 len = (int) (s - buf) + 3;
1995 }
1996
1997 return len;
1998 }
1999
2000
2001 static int get_month_index(const char *s) {
2002 size_t i;
2003
2004 for (i = 0; i < ARRAY_SIZE(month_names); i++)
2005 if (!strcmp(s, month_names[i]))
2006 return (int) i;
2007
2008 return -1;
2009 }
2010
2011 static int num_leap_years(int year) {
2012 return year / 4 - year / 100 + year / 400;
2013 }
2014
2015
2016 static time_t parse_date_string(const char *datetime) {
2017 static const unsigned short days_before_month[] = {
2018 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334
2019 };
2020 char month_str[32];
2021 int second, minute, hour, day, month, year, leap_days, days;
2022 time_t result = (time_t) 0;
2023
2024 if (((sscanf(datetime, "%d/%3s/%d %d:%d:%d",
2025 &day, month_str, &year, &hour, &minute, &second) == 6) ||
2026 (sscanf(datetime, "%d %3s %d %d:%d:%d",
2027 &day, month_str, &year, &hour, &minute, &second) == 6) ||
2028 (sscanf(datetime, "%*3s, %d %3s %d %d:%d:%d",
2029 &day, month_str, &year, &hour, &minute, &second) == 6) ||
2030 (sscanf(datetime, "%d-%3s-%d %d:%d:%d",
2031 &day, month_str, &year, &hour, &minute, &second) == 6)) &&
2032 year > 1970 &&
2033 (month = get_month_index(month_str)) != -1) {
2034 leap_days = num_leap_years(year) - num_leap_years(1970);
2035 year -= 1970;
2036 days = year * 365 + days_before_month[month] + (day - 1) + leap_days;
2037 result = days * 24 * 3600 + hour * 3600 + minute * 60 + second;
2038 }
2039
2040 return result;
2041 }
2042
2043
2044
2045 static void remove_double_dots_and_double_slashes(char *s) {
2046 char *p = s;
2047
2048 while (*s != '\0') {
2049 *p++ = *s++;
2050 if (s[-1] == '/' || s[-1] == '\\') {
2051
2052 while (s[0] != '\0') {
2053 if (s[0] == '/' || s[0] == '\\') {
2054 s++;
2055 } else if (s[0] == '.' && s[1] == '.') {
2056 s += 2;
2057 } else {
2058 break;
2059 }
2060 }
2061 }
2062 }
2063 *p = '\0';
2064 }
2065
2066 static const struct {
2067 const char *extension;
2068 size_t ext_len;
2069 const char *mime_type;
2070 } builtin_mime_types[] = {
2071 {".html", 5, "text/html"},
2072 {".htm", 4, "text/html"},
2073 {".shtm", 5, "text/html"},
2074 {".shtml", 6, "text/html"},
2075 {".css", 4, "text/css"},
2076 {".js", 3, "application/x-javascript"},
2077 {".ico", 4, "image/x-icon"},
2078 {".gif", 4, "image/gif"},
2079 {".jpg", 4, "image/jpeg"},
2080 {".jpeg", 5, "image/jpeg"},
2081 {".png", 4, "image/png"},
2082 {".svg", 4, "image/svg+xml"},
2083 {".txt", 4, "text/plain"},
2084 {".torrent", 8, "application/x-bittorrent"},
2085 {".wav", 4, "audio/x-wav"},
2086 {".mp3", 4, "audio/x-mp3"},
2087 {".mid", 4, "audio/mid"},
2088 {".m3u", 4, "audio/x-mpegurl"},
2089 {".ogg", 4, "audio/ogg"},
2090 {".ram", 4, "audio/x-pn-realaudio"},
2091 {".xml", 4, "text/xml"},
2092 {".json", 5, "text/json"},
2093 {".xslt", 5, "application/xml"},
2094 {".xsl", 4, "application/xml"},
2095 {".ra", 3, "audio/x-pn-realaudio"},
2096 {".doc", 4, "application/msword"},
2097 {".exe", 4, "application/octet-stream"},
2098 {".zip", 4, "application/x-zip-compressed"},
2099 {".xls", 4, "application/excel"},
2100 {".tgz", 4, "application/x-tar-gz"},
2101 {".tar", 4, "application/x-tar"},
2102 {".gz", 3, "application/x-gunzip"},
2103 {".arj", 4, "application/x-arj-compressed"},
2104 {".rar", 4, "application/x-arj-compressed"},
2105 {".rtf", 4, "application/rtf"},
2106 {".pdf", 4, "application/pdf"},
2107 {".swf", 4, "application/x-shockwave-flash"},
2108 {".mpg", 4, "video/mpeg"},
2109 {".webm", 5, "video/webm"},
2110 {".mpeg", 5, "video/mpeg"},
2111 {".mov", 4, "video/quicktime"},
2112 {".mp4", 4, "video/mp4"},
2113 {".m4v", 4, "video/x-m4v"},
2114 {".asf", 4, "video/x-ms-asf"},
2115 {".avi", 4, "video/x-msvideo"},
2116 {".bmp", 4, "image/bmp"},
2117 {".ttf", 4, "application/x-font-ttf"},
2118 {NULL, 0, NULL}
2119 };
2120
2121 const char *mg_get_builtin_mime_type(const char *path) {
2122 const char *ext;
2123 size_t i, path_len;
2124
2125 path_len = strlen(path);
2126
2127 for (i = 0; builtin_mime_types[i].extension != NULL; i++) {
2128 ext = path + (path_len - builtin_mime_types[i].ext_len);
2129 if (path_len > builtin_mime_types[i].ext_len &&
2130 mg_strcasecmp(ext, builtin_mime_types[i].extension) == 0) {
2131 return builtin_mime_types[i].mime_type;
2132 }
2133 }
2134
2135 return "text/plain";
2136 }
2137
2138
2139
2140 static void get_mime_type(struct mg_context *ctx, const char *path,
2141 struct vec *vec) {
2142 struct vec ext_vec, mime_vec;
2143 const char *list, *ext;
2144 size_t path_len;
2145
2146 path_len = strlen(path);
2147
2148
2149
2150 list = ctx->config[EXTRA_MIME_TYPES];
2151 while ((list = next_option(list, &ext_vec, &mime_vec)) != NULL) {
2152
2153 ext = path + path_len - ext_vec.len;
2154 if (mg_strncasecmp(ext, ext_vec.ptr, ext_vec.len) == 0) {
2155 *vec = mime_vec;
2156 return;
2157 }
2158 }
2159
2160 vec->ptr = mg_get_builtin_mime_type(path);
2161 vec->len = strlen(vec->ptr);
2162 }
2163
2164 static int is_big_endian(void) {
2165 static const int n = 1;
2166 return ((char *) &n)[0] == 0;
2167 }
2168
2169 #ifndef HAVE_MD5
2170 typedef struct MD5Context {
2171 uint32_t buf[4];
2172 uint32_t bits[2];
2173 unsigned char in[64];
2174 } MD5_CTX;
2175
2176 static void byteReverse(unsigned char *buf, unsigned longs) {
2177 uint32_t t;
2178
2179
2180 if (is_big_endian()) {
2181 do {
2182 t = (uint32_t) ((unsigned) buf[3] << 8 | buf[2]) << 16 |
2183 ((unsigned) buf[1] << 8 | buf[0]);
2184 * (uint32_t *) buf = t;
2185 buf += 4;
2186 } while (--longs);
2187 }
2188 }
2189
2190 #define F1(x, y, z) (z ^ (x & (y ^ z)))
2191 #define F2(x, y, z) F1(z, x, y)
2192 #define F3(x, y, z) (x ^ y ^ z)
2193 #define F4(x, y, z) (y ^ (x | ~z))
2194
2195 #define MD5STEP(f, w, x, y, z, data, s) \
2196 ( w += f(x, y, z) + data, w = w<<s | w>>(32-s), w += x )
2197
2198
2199
2200 static void MD5Init(MD5_CTX *ctx) {
2201 ctx->buf[0] = 0x67452301;
2202 ctx->buf[1] = 0xefcdab89;
2203 ctx->buf[2] = 0x98badcfe;
2204 ctx->buf[3] = 0x10325476;
2205
2206 ctx->bits[0] = 0;
2207 ctx->bits[1] = 0;
2208 }
2209
2210 static void MD5Transform(uint32_t buf[4], uint32_t const in[16]) {
2211 register uint32_t a, b, c, d;
2212
2213 a = buf[0];
2214 b = buf[1];
2215 c = buf[2];
2216 d = buf[3];
2217
2218 MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7);
2219 MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12);
2220 MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17);
2221 MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22);
2222 MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7);
2223 MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12);
2224 MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17);
2225 MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22);
2226 MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7);
2227 MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12);
2228 MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17);
2229 MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22);
2230 MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7);
2231 MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12);
2232 MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17);
2233 MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22);
2234
2235 MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5);
2236 MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9);
2237 MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14);
2238 MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20);
2239 MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5);
2240 MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9);
2241 MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14);
2242 MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20);
2243 MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5);
2244 MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9);
2245 MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14);
2246 MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20);
2247 MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5);
2248 MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9);
2249 MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14);
2250 MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20);
2251
2252 MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4);
2253 MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11);
2254 MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16);
2255 MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23);
2256 MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4);
2257 MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11);
2258 MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16);
2259 MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23);
2260 MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4);
2261 MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11);
2262 MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16);
2263 MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23);
2264 MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4);
2265 MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11);
2266 MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16);
2267 MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23);
2268
2269 MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6);
2270 MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10);
2271 MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15);
2272 MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21);
2273 MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6);
2274 MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10);
2275 MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15);
2276 MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21);
2277 MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6);
2278 MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10);
2279 MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15);
2280 MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21);
2281 MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6);
2282 MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10);
2283 MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15);
2284 MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21);
2285
2286 buf[0] += a;
2287 buf[1] += b;
2288 buf[2] += c;
2289 buf[3] += d;
2290 }
2291
2292 static void MD5Update(MD5_CTX *ctx, unsigned char const *buf, unsigned len) {
2293 uint32_t t;
2294
2295 t = ctx->bits[0];
2296 if ((ctx->bits[0] = t + ((uint32_t) len << 3)) < t)
2297 ctx->bits[1]++;
2298 ctx->bits[1] += len >> 29;
2299
2300 t = (t >> 3) & 0x3f;
2301
2302 if (t) {
2303 unsigned char *p = (unsigned char *) ctx->in + t;
2304
2305 t = 64 - t;
2306 if (len < t) {
2307 memcpy(p, buf, len);
2308 return;
2309 }
2310 memcpy(p, buf, t);
2311 byteReverse(ctx->in, 16);
2312 MD5Transform(ctx->buf, (uint32_t *) ctx->in);
2313 buf += t;
2314 len -= t;
2315 }
2316
2317 while (len >= 64) {
2318 memcpy(ctx->in, buf, 64);
2319 byteReverse(ctx->in, 16);
2320 MD5Transform(ctx->buf, (uint32_t *) ctx->in);
2321 buf += 64;
2322 len -= 64;
2323 }
2324
2325 memcpy(ctx->in, buf, len);
2326 }
2327
2328 static void MD5Final(unsigned char digest[16], MD5_CTX *ctx) {
2329 unsigned count;
2330 unsigned char *p;
2331 uint32_t *a;
2332
2333 count = (ctx->bits[0] >> 3) & 0x3F;
2334
2335 p = ctx->in + count;
2336 *p++ = 0x80;
2337 count = 64 - 1 - count;
2338 if (count < 8) {
2339 memset(p, 0, count);
2340 byteReverse(ctx->in, 16);
2341 MD5Transform(ctx->buf, (uint32_t *) ctx->in);
2342 memset(ctx->in, 0, 56);
2343 } else {
2344 memset(p, 0, count - 8);
2345 }
2346 byteReverse(ctx->in, 14);
2347
2348 a = (uint32_t *)ctx->in;
2349 a[14] = ctx->bits[0];
2350 a[15] = ctx->bits[1];
2351
2352 MD5Transform(ctx->buf, (uint32_t *) ctx->in);
2353 byteReverse((unsigned char *) ctx->buf, 4);
2354 memcpy(digest, ctx->buf, 16);
2355 memset((char *) ctx, 0, sizeof(*ctx));
2356 }
2357 #endif
2358
2359
2360
2361 static void bin2str(char *to, const unsigned char *p, size_t len) {
2362 static const char *hex = "0123456789abcdef";
2363
2364 for (; len--; p++) {
2365 *to++ = hex[p[0] >> 4];
2366 *to++ = hex[p[0] & 0x0f];
2367 }
2368 *to = '\0';
2369 }
2370
2371
2372 char *mg_md5(char buf[33], ...) {
2373 unsigned char hash[16];
2374 const char *p;
2375 va_list ap;
2376 MD5_CTX ctx;
2377
2378 MD5Init(&ctx);
2379
2380 va_start(ap, buf);
2381 while ((p = va_arg(ap, const char *)) != NULL) {
2382 MD5Update(&ctx, (const unsigned char *) p, (unsigned) strlen(p));
2383 }
2384 va_end(ap);
2385
2386 MD5Final(hash, &ctx);
2387 bin2str(buf, hash, sizeof(hash));
2388 return buf;
2389 }
2390
2391
2392 static int check_password(const char *method, const char *ha1, const char *uri,
2393 const char *nonce, const char *nc, const char *cnonce,
2394 const char *qop, const char *response) {
2395 char ha2[32 + 1], expected_response[32 + 1];
2396
2397
2398 if (method == NULL || nonce == NULL || nc == NULL || cnonce == NULL ||
2399 qop == NULL || response == NULL) {
2400 return 0;
2401 }
2402
2403
2404
2405 if (
2406 strlen(response) != 32
2407
2408 ) {
2409 return 0;
2410 }
2411
2412 mg_md5(ha2, method, ":", uri, NULL);
2413 mg_md5(expected_response, ha1, ":", nonce, ":", nc,
2414 ":", cnonce, ":", qop, ":", ha2, NULL);
2415
2416 return mg_strcasecmp(response, expected_response) == 0;
2417 }
2418
2419
2420
2421 static void open_auth_file(struct mg_connection *conn, const char *path,
2422 struct file *filep) {
2423 char name[PATH_MAX];
2424 const char *p, *e, *gpass = conn->ctx->config[GLOBAL_PASSWORDS_FILE];
2425 struct file file = STRUCT_FILE_INITIALIZER;
2426
2427 if (gpass != NULL) {
2428
2429 if (!mg_fopen(conn, gpass, "r", filep)) {
2430 cry(conn, "fopen(%s): %s", gpass, strerror(ERRNO));
2431 }
2432
2433
2434 } else if (mg_stat(conn, path, &file) && file.is_directory) {
2435 mg_snprintf(conn, name, sizeof(name), "%s%c%s",
2436 path, '/', PASSWORDS_FILE_NAME);
2437 mg_fopen(conn, name, "r", filep);
2438 } else {
2439
2440 for (p = path, e = p + strlen(p) - 1; e > p; e--)
2441 if (e[0] == '/')
2442 break;
2443 mg_snprintf(conn, name, sizeof(name), "%.*s%c%s",
2444 (int) (e - p), p, '/', PASSWORDS_FILE_NAME);
2445 mg_fopen(conn, name, "r", filep);
2446 }
2447 }
2448
2449
2450 struct ah {
2451 char *user, *uri, *cnonce, *response, *qop, *nc, *nonce;
2452 };
2453
2454
2455 static int parse_auth_header(struct mg_connection *conn, char *buf,
2456 size_t buf_size, struct ah *ah) {
2457 char *name, *value, *s;
2458 const char *auth_header;
2459
2460 (void) memset(ah, 0, sizeof(*ah));
2461 if ((auth_header = mg_get_header(conn, "Authorization")) == NULL ||
2462 mg_strncasecmp(auth_header, "Digest ", 7) != 0) {
2463 return 0;
2464 }
2465
2466
2467 (void) mg_strlcpy(buf, auth_header + 7, buf_size);
2468 s = buf;
2469
2470
2471 for (;;) {
2472
2473 while (isspace(* (unsigned char *) s)) {
2474 s++;
2475 }
2476 name = skip_quoted(&s, "=", " ", 0);
2477
2478 if (s[0] == '\"') {
2479 s++;
2480 value = skip_quoted(&s, "\"", " ", '\\');
2481 if (s[0] == ',') {
2482 s++;
2483 }
2484 } else {
2485 value = skip_quoted(&s, ", ", " ", 0);
2486 }
2487 if (*name == '\0') {
2488 break;
2489 }
2490
2491 if (!strcmp(name, "username")) {
2492 ah->user = value;
2493 } else if (!strcmp(name, "cnonce")) {
2494 ah->cnonce = value;
2495 } else if (!strcmp(name, "response")) {
2496 ah->response = value;
2497 } else if (!strcmp(name, "uri")) {
2498 ah->uri = value;
2499 } else if (!strcmp(name, "qop")) {
2500 ah->qop = value;
2501 } else if (!strcmp(name, "nc")) {
2502 ah->nc = value;
2503 } else if (!strcmp(name, "nonce")) {
2504 ah->nonce = value;
2505 }
2506 }
2507
2508
2509 if (ah->user != NULL) {
2510 conn->request_info.remote_user = mg_strdup(ah->user);
2511 } else {
2512 return 0;
2513 }
2514
2515 return 1;
2516 }
2517
2518 static char *mg_fgets(char *buf, size_t size, struct file *filep, char **p) {
2519 char *eof;
2520 size_t len;
2521 char *memend;
2522
2523 if (filep->membuf != NULL && *p != NULL) {
2524 memend = (char *) &filep->membuf[filep->size];
2525 eof = (char *) memchr(*p, '\n', memend - *p);
2526 if (eof != NULL) {
2527 eof += 1;
2528 } else {
2529 eof = memend;
2530 }
2531 len = (size_t) (eof - *p) > size - 1 ? size - 1 : (size_t) (eof - *p);
2532 memcpy(buf, *p, len);
2533 buf[len] = '\0';
2534 *p += len;
2535 return len ? eof : NULL;
2536 } else if (filep->fp != NULL) {
2537 return fgets(buf, size, filep->fp);
2538 } else {
2539 return NULL;
2540 }
2541 }
2542
2543
2544 static int authorize(struct mg_connection *conn, struct file *filep) {
2545 struct ah ah;
2546 char line[256], f_user[256], ha1[256], f_domain[256], buf[MG_BUF_LEN], *p;
2547
2548 if (!parse_auth_header(conn, buf, sizeof(buf), &ah)) {
2549 return 0;
2550 }
2551
2552
2553 p = (char *) filep->membuf;
2554 while (mg_fgets(line, sizeof(line), filep, &p) != NULL) {
2555 if (sscanf(line, "%[^:]:%[^:]:%s", f_user, f_domain, ha1) != 3) {
2556 continue;
2557 }
2558
2559 if (!strcmp(ah.user, f_user) &&
2560 !strcmp(conn->ctx->config[AUTHENTICATION_DOMAIN], f_domain))
2561 return check_password(conn->request_info.request_method, ha1, ah.uri,
2562 ah.nonce, ah.nc, ah.cnonce, ah.qop, ah.response);
2563 }
2564
2565 return 0;
2566 }
2567
2568
2569 static int check_authorization(struct mg_connection *conn, const char *path) {
2570 char fname[PATH_MAX];
2571 struct vec uri_vec, filename_vec;
2572 const char *list;
2573 struct file file = STRUCT_FILE_INITIALIZER;
2574 int authorized = 1;
2575
2576 list = conn->ctx->config[PROTECT_URI];
2577 while ((list = next_option(list, &uri_vec, &filename_vec)) != NULL) {
2578 if (!memcmp(conn->request_info.uri, uri_vec.ptr, uri_vec.len)) {
2579 mg_snprintf(conn, fname, sizeof(fname), "%.*s",
2580 (int) filename_vec.len, filename_vec.ptr);
2581 if (!mg_fopen(conn, fname, "r", &file)) {
2582 cry(conn, "%s: cannot open %s: %s", __func__, fname, strerror(errno));
2583 }
2584 break;
2585 }
2586 }
2587
2588 if (!is_file_opened(&file)) {
2589 open_auth_file(conn, path, &file);
2590 }
2591
2592 if (is_file_opened(&file)) {
2593 authorized = authorize(conn, &file);
2594 mg_fclose(&file);
2595 }
2596
2597 return authorized;
2598 }
2599
2600 static void send_authorization_request(struct mg_connection *conn) {
2601 conn->status_code = 401;
2602 mg_printf(conn,
2603 "HTTP/1.1 401 Unauthorized\r\n"
2604 "Content-Length: 0\r\n"
2605 "WWW-Authenticate: Digest qop=\"auth\", "
2606 "realm=\"%s\", nonce=\"%lu\"\r\n\r\n",
2607 conn->ctx->config[AUTHENTICATION_DOMAIN],
2608 (unsigned long) time(NULL));
2609 }
2610
2611 static int is_authorized_for_put(struct mg_connection *conn) {
2612 struct file file = STRUCT_FILE_INITIALIZER;
2613 const char *passfile = conn->ctx->config[PUT_DELETE_PASSWORDS_FILE];
2614 int ret = 0;
2615
2616 if (passfile != NULL && mg_fopen(conn, passfile, "r", &file)) {
2617 ret = authorize(conn, &file);
2618 mg_fclose(&file);
2619 }
2620
2621 return ret;
2622 }
2623
2624 int mg_modify_passwords_file(const char *fname, const char *domain,
2625 const char *user, const char *pass) {
2626 int found;
2627 char line[512], u[512], d[512], ha1[33], tmp[PATH_MAX];
2628 FILE *fp, *fp2;
2629
2630 found = 0;
2631 fp = fp2 = NULL;
2632
2633
2634 if (pass != NULL && pass[0] == '\0') {
2635 pass = NULL;
2636 }
2637
2638 (void) snprintf(tmp, sizeof(tmp), "%s.tmp", fname);
2639
2640
2641 if ((fp = fopen(fname, "a+")) != NULL) {
2642 (void) fclose(fp);
2643 }
2644
2645
2646 if ((fp = fopen(fname, "r")) == NULL) {
2647 return 0;
2648 } else if ((fp2 = fopen(tmp, "w+")) == NULL) {
2649 fclose(fp);
2650 return 0;
2651 }
2652
2653
2654 while (fgets(line, sizeof(line), fp) != NULL) {
2655 if (sscanf(line, "%[^:]:%[^:]:%*s", u, d) != 2) {
2656 continue;
2657 }
2658
2659 if (!strcmp(u, user) && !strcmp(d, domain)) {
2660 found++;
2661 if (pass != NULL) {
2662 mg_md5(ha1, user, ":", domain, ":", pass, NULL);
2663 fprintf(fp2, "%s:%s:%s\n", user, domain, ha1);
2664 }
2665 } else {
2666 fprintf(fp2, "%s", line);
2667 }
2668 }
2669
2670
2671 if (!found && pass != NULL) {
2672 mg_md5(ha1, user, ":", domain, ":", pass, NULL);
2673 fprintf(fp2, "%s:%s:%s\n", user, domain, ha1);
2674 }
2675
2676
2677 fclose(fp);
2678 fclose(fp2);
2679
2680
2681 remove(fname);
2682 rename(tmp, fname);
2683
2684 return 1;
2685 }
2686
2687 static SOCKET conn2(const char *host, int port, int use_ssl,
2688 char *ebuf, size_t ebuf_len) {
2689 struct sockaddr_in sin;
2690 struct hostent *he;
2691 SOCKET sock = INVALID_SOCKET;
2692
2693 if (host == NULL) {
2694 snprintf(ebuf, ebuf_len, "%s", "NULL host");
2695 } else if (use_ssl && SSLv23_client_method == NULL) {
2696 snprintf(ebuf, ebuf_len, "%s", "SSL is not initialized");
2697
2698 } else if ((he = gethostbyname(host)) == NULL) {
2699 snprintf(ebuf, ebuf_len, "gethostbyname(%s): %s", host, strerror(ERRNO));
2700 } else if ((sock = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
2701 snprintf(ebuf, ebuf_len, "socket(): %s", strerror(ERRNO));
2702 } else {
2703 set_close_on_exec(sock);
2704 sin.sin_family = AF_INET;
2705 sin.sin_port = htons((uint16_t) port);
2706 sin.sin_addr = * (struct in_addr *) he->h_addr_list[0];
2707 if (connect(sock, (struct sockaddr *) &sin, sizeof(sin)) != 0) {
2708 snprintf(ebuf, ebuf_len, "connect(%s:%d): %s",
2709 host, port, strerror(ERRNO));
2710 closesocket(sock);
2711 sock = INVALID_SOCKET;
2712 }
2713 }
2714 return sock;
2715 }
2716
2717
2718
2719 static void mg_url_encode(const char *src, char *dst, size_t dst_len) {
2720 static const char *dont_escape = "._-$,;~()";
2721 static const char *hex = "0123456789abcdef";
2722 const char *end = dst + dst_len - 1;
2723
2724 for (; *src != '\0' && dst < end; src++, dst++) {
2725 if (isalnum(*(const unsigned char *) src) ||
2726 strchr(dont_escape, * (const unsigned char *) src) != NULL) {
2727 *dst = *src;
2728 } else if (dst + 2 < end) {
2729 dst[0] = '%';
2730 dst[1] = hex[(* (const unsigned char *) src) >> 4];
2731 dst[2] = hex[(* (const unsigned char *) src) & 0xf];
2732 dst += 2;
2733 }
2734 }
2735
2736 *dst = '\0';
2737 }
2738
2739 static void print_dir_entry(struct de *de) {
2740 char size[64], mod[64], href[PATH_MAX];
2741
2742 if (de->file.is_directory) {
2743 mg_snprintf(de->conn, size, sizeof(size), "%s", "[DIRECTORY]");
2744 } else {
2745
2746
2747 if (de->file.size < 1024) {
2748 mg_snprintf(de->conn, size, sizeof(size), "%d", (int) de->file.size);
2749 } else if (de->file.size < 0x100000) {
2750 mg_snprintf(de->conn, size, sizeof(size),
2751 "%.1fk", (double) de->file.size / 1024.0);
2752 } else if (de->file.size < 0x40000000) {
2753 mg_snprintf(de->conn, size, sizeof(size),
2754 "%.1fM", (double) de->file.size / 1048576);
2755 } else {
2756 mg_snprintf(de->conn, size, sizeof(size),
2757 "%.1fG", (double) de->file.size / 1073741824);
2758 }
2759 }
2760 strftime(mod, sizeof(mod), "%d-%b-%Y %H:%M",
2761 localtime(&de->file.modification_time));
2762 mg_url_encode(de->file_name, href, sizeof(href));
2763 de->conn->num_bytes_sent += mg_printf(de->conn,
2764 "<tr><td><a href=\"%s%s%s\">%s%s</a></td>"
2765 "<td> %s</td><td> %s</td></tr>\n",
2766 de->conn->request_info.uri, href, de->file.is_directory ? "/" : "",
2767 de->file_name, de->file.is_directory ? "/" : "", mod, size);
2768 }
2769
2770
2771
2772
2773
2774 static int WINCDECL compare_dir_entries(const void *p1, const void *p2) {
2775 const struct de *a = (const struct de *) p1, *b = (const struct de *) p2;
2776 const char *query_string = a->conn->request_info.query_string;
2777 int cmp_result = 0;
2778
2779 if (query_string == NULL) {
2780 query_string = "na";
2781 }
2782
2783 if (a->file.is_directory && !b->file.is_directory) {
2784 return -1;
2785 } else if (!a->file.is_directory && b->file.is_directory) {
2786 return 1;
2787 } else if (*query_string == 'n') {
2788 cmp_result = strcmp(a->file_name, b->file_name);
2789 } else if (*query_string == 's') {
2790 cmp_result = a->file.size == b->file.size ? 0 :
2791 a->file.size > b->file.size ? 1 : -1;
2792 } else if (*query_string == 'd') {
2793 cmp_result = a->file.modification_time == b->file.modification_time ? 0 :
2794 a->file.modification_time > b->file.modification_time ? 1 : -1;
2795 }
2796
2797 return query_string[1] == 'd' ? -cmp_result : cmp_result;
2798 }
2799
2800 static int must_hide_file(struct mg_connection *conn, const char *path) {
2801 const char *pw_pattern = "**" PASSWORDS_FILE_NAME "$";
2802 const char *pattern = conn->ctx->config[HIDE_FILES];
2803 return match_prefix(pw_pattern, strlen(pw_pattern), path) > 0 ||
2804 (pattern != NULL && match_prefix(pattern, strlen(pattern), path) > 0);
2805 }
2806
2807 static int scan_directory(struct mg_connection *conn, const char *dir,
2808 void *data, void (*cb)(struct de *, void *)) {
2809 char path[PATH_MAX];
2810 struct dirent *dp;
2811 DIR *dirp;
2812 struct de de;
2813
2814 if ((dirp = opendir(dir)) == NULL) {
2815 return 0;
2816 } else {
2817 de.conn = conn;
2818
2819 while ((dp = readdir(dirp)) != NULL) {
2820
2821 if (!strcmp(dp->d_name, ".") ||
2822 !strcmp(dp->d_name, "..") ||
2823 must_hide_file(conn, dp->d_name)) {
2824 continue;
2825 }
2826
2827 mg_snprintf(conn, path, sizeof(path), "%s%c%s", dir, '/', dp->d_name);
2828
2829
2830
2831
2832
2833
2834 memset(&de.file, 0, sizeof(de.file));
2835 mg_stat(conn, path, &de.file);
2836
2837 de.file_name = dp->d_name;
2838 cb(&de, data);
2839 }
2840 (void) closedir(dirp);
2841 }
2842 return 1;
2843 }
2844
2845 static int remove_directory(struct mg_connection *conn, const char *dir) {
2846 char path[PATH_MAX];
2847 struct dirent *dp;
2848 DIR *dirp;
2849 struct de de;
2850
2851 if ((dirp = opendir(dir)) == NULL) {
2852 return 0;
2853 } else {
2854 de.conn = conn;
2855
2856 while ((dp = readdir(dirp)) != NULL) {
2857
2858 if (!strcmp(dp->d_name, ".") ||
2859 !strcmp(dp->d_name, "..")) {
2860 continue;
2861 }
2862
2863 mg_snprintf(conn, path, sizeof(path), "%s%c%s", dir, '/', dp->d_name);
2864
2865
2866
2867
2868
2869
2870 memset(&de.file, 0, sizeof(de.file));
2871 mg_stat(conn, path, &de.file);
2872 if(de.file.modification_time) {
2873 if(de.file.is_directory) {
2874 remove_directory(conn, path);
2875 } else {
2876 mg_remove(path);
2877 }
2878 }
2879
2880 }
2881 (void) closedir(dirp);
2882
2883 rmdir(dir);
2884 }
2885
2886 return 1;
2887 }
2888
2889 struct dir_scan_data {
2890 struct de *entries;
2891 int num_entries;
2892 int arr_size;
2893 };
2894
2895
2896 static void *realloc2(void *ptr, size_t size) {
2897 void *new_ptr = realloc(ptr, size);
2898 if (new_ptr == NULL) {
2899 free(ptr);
2900 }
2901 return new_ptr;
2902 }
2903
2904 static void dir_scan_callback(struct de *de, void *data) {
2905 struct dir_scan_data *dsd = (struct dir_scan_data *) data;
2906
2907 if (dsd->entries == NULL || dsd->num_entries >= dsd->arr_size) {
2908 dsd->arr_size *= 2;
2909 dsd->entries = (struct de *) realloc2(dsd->entries, dsd->arr_size *
2910 sizeof(dsd->entries[0]));
2911 }
2912 if (dsd->entries == NULL) {
2913
2914 dsd->num_entries = 0;
2915 } else {
2916 dsd->entries[dsd->num_entries].file_name = mg_strdup(de->file_name);
2917 dsd->entries[dsd->num_entries].file = de->file;
2918 dsd->entries[dsd->num_entries].conn = de->conn;
2919 dsd->num_entries++;
2920 }
2921 }
2922
2923 static void handle_directory_request(struct mg_connection *conn,
2924 const char *dir) {
2925 int i, sort_direction;
2926 struct dir_scan_data data = { NULL, 0, 128 };
2927
2928 if (!scan_directory(conn, dir, &data, dir_scan_callback)) {
2929 send_http_error(conn, 500, "Cannot open directory",
2930 "Error: opendir(%s): %s", dir, strerror(ERRNO));
2931 return;
2932 }
2933
2934 sort_direction = conn->request_info.query_string != NULL &&
2935 conn->request_info.query_string[1] == 'd' ? 'a' : 'd';
2936
2937 conn->must_close = 1;
2938 mg_printf(conn, "%s",
2939 "HTTP/1.1 200 OK\r\n"
2940 "Connection: close\r\n"
2941 "Content-Type: text/html; charset=utf-8\r\n\r\n");
2942
2943 conn->num_bytes_sent += mg_printf(conn,
2944 "<html><head><title>Index of %s</title>"
2945 "<style>th {text-align: left;}</style></head>"
2946 "<body><h1>Index of %s</h1><pre><table cellpadding=\"0\">"
2947 "<tr><th><a href=\"?n%c\">Name</a></th>"
2948 "<th><a href=\"?d%c\">Modified</a></th>"
2949 "<th><a href=\"?s%c\">Size</a></th></tr>"
2950 "<tr><td colspan=\"3\"><hr></td></tr>",
2951 conn->request_info.uri, conn->request_info.uri,
2952 sort_direction, sort_direction, sort_direction);
2953
2954
2955 conn->num_bytes_sent += mg_printf(conn,
2956 "<tr><td><a href=\"%s%s\">%s</a></td>"
2957 "<td> %s</td><td> %s</td></tr>\n",
2958 conn->request_info.uri, "..", "Parent directory", "-", "-");
2959
2960
2961 qsort(data.entries, (size_t) data.num_entries, sizeof(data.entries[0]),
2962 compare_dir_entries);
2963 for (i = 0; i < data.num_entries; i++) {
2964 print_dir_entry(&data.entries[i]);
2965 free(data.entries[i].file_name);
2966 }
2967 free(data.entries);
2968
2969 conn->num_bytes_sent += mg_printf(conn, "%s", "</table></body></html>");
2970 conn->status_code = 200;
2971 }
2972
2973
2974 static void send_file_data(struct mg_connection *conn, struct file *filep,
2975 int64_t offset, int64_t len) {
2976 char buf[MG_BUF_LEN];
2977 int to_read, num_read, num_written;
2978
2979
2980 offset = offset < 0 ? 0 : offset > filep->size ? filep->size : offset;
2981
2982 if (len > 0 && filep->membuf != NULL && filep->size > 0) {
2983 if (len > filep->size - offset) {
2984 len = filep->size - offset;
2985 }
2986 mg_write(conn, filep->membuf + offset, (size_t) len);
2987 } else if (len > 0 && filep->fp != NULL) {
2988 fseeko(filep->fp, offset, SEEK_SET);
2989 while (len > 0) {
2990
2991 to_read = sizeof(buf);
2992 if ((int64_t) to_read > len) {
2993 to_read = (int) len;
2994 }
2995
2996
2997 if ((num_read = fread(buf, 1, (size_t) to_read, filep->fp)) <= 0) {
2998 break;
2999 }
3000
3001
3002 if ((num_written = mg_write(conn, buf, (size_t) num_read)) != num_read) {
3003 break;
3004 }
3005
3006
3007 conn->num_bytes_sent += num_written;
3008 len -= num_written;
3009 }
3010 }
3011 }
3012
3013 static int parse_range_header(const char *header, int64_t *a, int64_t *b) {
3014 return sscanf(header, "bytes=%" INT64_FMT "-%" INT64_FMT, a, b);
3015 }
3016
3017 static void gmt_time_string(char *buf, size_t buf_len, time_t *t) {
3018 strftime(buf, buf_len, "%a, %d %b %Y %H:%M:%S GMT", gmtime(t));
3019 }
3020
3021 static void construct_etag(const struct mg_connection *conn, const char *path,
3022 char *buf, size_t buf_len,
3023 const struct file *filep) {
3024 if (conn->ctx->callbacks.http_etag != NULL &&
3025 conn->ctx->callbacks.http_etag(conn, path, buf, buf_len)) {
3026 }
3027 else {
3028 snprintf(buf, buf_len, "\"%lx.%" INT64_FMT "\"",
3029 (unsigned long) filep->modification_time, filep->size);
3030 }
3031 }
3032
3033 static void fclose_on_exec(struct file *filep) {
3034 if (filep != NULL && filep->fp != NULL) {
3035 #ifndef _WIN32
3036 fcntl(fileno(filep->fp), F_SETFD, FD_CLOEXEC);
3037 #endif
3038 }
3039 }
3040
3041 static void handle_file_request(struct mg_connection *conn, const char *path,
3042 struct file *filep) {
3043 char date[64], lm[64], etag[64], range[64];
3044 const char *msg = "OK", *hdr;
3045 time_t curtime = time(NULL);
3046 int64_t cl, r1, r2;
3047 struct vec mime_vec;
3048 int n;
3049 char gz_path[PATH_MAX + 3];
3050 char const* encoding = "";
3051
3052 get_mime_type(conn->ctx, path, &mime_vec);
3053 cl = filep->size;
3054 conn->status_code = 200;
3055 range[0] = '\0';
3056
3057
3058
3059
3060 if (filep->gzipped) {
3061 snprintf(gz_path, sizeof(gz_path), "%s.gz", path);
3062 path = gz_path;
3063 encoding = "Content-Encoding: gzip\r\n";
3064 }
3065
3066 if (!mg_fopen(conn, path, "rb", filep)) {
3067 send_http_error(conn, 500, http_500_error,
3068 "fopen(%s): %s", path, strerror(ERRNO));
3069 return;
3070 }
3071
3072 fclose_on_exec(filep);
3073
3074
3075 r1 = r2 = 0;
3076 hdr = mg_get_header(conn, "Range");
3077 if (hdr != NULL && (n = parse_range_header(hdr, &r1, &r2)) > 0 &&
3078 r1 >= 0 && r2 >= 0) {
3079
3080
3081 if (filep->gzipped) {
3082 send_http_error(conn, 501, "Not Implemented", "range requests in gzipped files are not supported");
3083 return;
3084 }
3085 conn->status_code = 206;
3086 cl = n == 2 ? (r2 > cl ? cl : r2) - r1 + 1: cl - r1;
3087 mg_snprintf(conn, range, sizeof(range),
3088 "Content-Range: bytes "
3089 "%" INT64_FMT "-%"
3090 INT64_FMT "/%" INT64_FMT "\r\n",
3091 r1, r1 + cl - 1, filep->size);
3092 msg = "Partial Content";
3093 }
3094
3095
3096
3097 gmt_time_string(date, sizeof(date), &curtime);
3098 gmt_time_string(lm, sizeof(lm), &filep->modification_time);
3099 construct_etag(conn, path, etag, sizeof(etag), filep);
3100
3101 (void) mg_printf(conn,
3102 "HTTP/1.1 %d %s\r\n"
3103 "Date: %s\r\n"
3104 "Last-Modified: %s\r\n"
3105 "Etag: %s\r\n"
3106 "Content-Type: %.*s\r\n"
3107 "Content-Length: %" INT64_FMT "\r\n"
3108 "Connection: %s\r\n"
3109 "Accept-Ranges: bytes\r\n"
3110 "%s%s\r\n",
3111 conn->status_code, msg, date, lm, etag, (int) mime_vec.len,
3112 mime_vec.ptr, cl, suggest_connection_header(conn), range, encoding);
3113
3114 if (strcmp(conn->request_info.request_method, "HEAD") != 0) {
3115 send_file_data(conn, filep, r1, cl);
3116 }
3117 mg_fclose(filep);
3118 }
3119
3120 void mg_send_file(struct mg_connection *conn, const char *path) {
3121 struct file file = STRUCT_FILE_INITIALIZER;
3122 if (mg_stat(conn, path, &file)) {
3123 handle_file_request(conn, path, &file);
3124 } else {
3125 send_http_error(conn, 404, "Not Found", "%s", "File not found");
3126 }
3127 }
3128
3129
3130
3131
3132 static void parse_http_headers(char **buf, struct mg_request_info *ri) {
3133 int i;
3134
3135 for (i = 0; i < (int) ARRAY_SIZE(ri->http_headers); i++) {
3136 ri->http_headers[i].name = skip_quoted(buf, ":", " ", 0);
3137 ri->http_headers[i].value = skip(buf, "\r\n");
3138 if (ri->http_headers[i].name[0] == '\0')
3139 break;
3140 ri->num_headers = i + 1;
3141 }
3142 }
3143
3144 static int is_valid_http_method(const char *method) {
3145 return !strcmp(method, "GET") || !strcmp(method, "POST") ||
3146 !strcmp(method, "HEAD") || !strcmp(method, "CONNECT") ||
3147 !strcmp(method, "PUT") || !strcmp(method, "DELETE") ||
3148 !strcmp(method, "OPTIONS") || !strcmp(method, "PROPFIND")
3149 || !strcmp(method, "MKCOL")
3150 ;
3151 }
3152
3153
3154
3155
3156 static int parse_http_message(char *buf, int len, struct mg_request_info *ri) {
3157 int is_request, request_length = get_request_len(buf, len);
3158 if (request_length > 0) {
3159
3160 ri->remote_user = ri->request_method = ri->uri = ri->http_version = NULL;
3161 ri->num_headers = 0;
3162
3163 buf[request_length - 1] = '\0';
3164
3165
3166 while (*buf != '\0' && isspace(* (unsigned char *) buf)) {
3167 buf++;
3168 }
3169 ri->request_method = skip(&buf, " ");
3170 ri->uri = skip(&buf, " ");
3171 ri->http_version = skip(&buf, "\r\n");
3172
3173
3174
3175 is_request = is_valid_http_method(ri->request_method);
3176 if ((is_request && memcmp(ri->http_version, "HTTP/", 5) != 0) ||
3177 (!is_request && memcmp(ri->request_method, "HTTP/", 5) != 0)) {
3178 request_length = -1;
3179 } else {
3180 if (is_request) {
3181 ri->http_version += 5;
3182 }
3183 parse_http_headers(&buf, ri);
3184 }
3185 }
3186 return request_length;
3187 }
3188
3189
3190
3191
3192
3193
3194 static int read_request(FILE *fp, struct mg_connection *conn,
3195 char *buf, int bufsiz, int *nread) {
3196 int request_len, n = 0;
3197
3198 request_len = get_request_len(buf, *nread);
3199 while (conn->ctx->stop_flag == 0 &&
3200 *nread < bufsiz && request_len == 0 &&
3201 (n = pull(fp, conn, buf + *nread, bufsiz - *nread)) > 0) {
3202 *nread += n;
3203 assert(*nread <= bufsiz);
3204 request_len = get_request_len(buf, *nread);
3205 }
3206
3207 return request_len <= 0 && n <= 0 ? -1 : request_len;
3208 }
3209
3210
3211
3212
3213 static int substitute_index_file(struct mg_connection *conn, char *path,
3214 size_t path_len, struct file *filep) {
3215 const char *list = conn->ctx->config[INDEX_FILES];
3216 struct file file = STRUCT_FILE_INITIALIZER;
3217 struct vec filename_vec;
3218 size_t n = strlen(path);
3219 int found = 0;
3220
3221
3222
3223
3224 while (n > 0 && path[n - 1] == '/') {
3225 n--;
3226 }
3227 path[n] = '/';
3228
3229
3230
3231 while ((list = next_option(list, &filename_vec, NULL)) != NULL) {
3232
3233
3234 if (filename_vec.len > path_len - (n + 2))
3235 continue;
3236
3237
3238 mg_strlcpy(path + n + 1, filename_vec.ptr, filename_vec.len + 1);
3239
3240
3241 if (mg_stat(conn, path, &file)) {
3242
3243 *filep = file;
3244 found = 1;
3245 break;
3246 }
3247 }
3248
3249
3250 if (!found) {
3251 path[n] = '\0';
3252 }
3253
3254 return found;
3255 }
3256
3257
3258 static int is_not_modified(const struct mg_connection *conn,
3259 const char *path,
3260 const struct file *filep) {
3261 char etag[64];
3262 const char *ims = mg_get_header(conn, "If-Modified-Since");
3263 const char *inm = mg_get_header(conn, "If-None-Match");
3264 construct_etag(conn, path, etag, sizeof(etag), filep);
3265 return (inm != NULL && !mg_strcasecmp(etag, inm)) ||
3266 (ims != NULL && filep->modification_time <= parse_date_string(ims));
3267 }
3268
3269 static int forward_body_data(struct mg_connection *conn, FILE *fp,
3270 SOCKET sock, SSL *ssl) {
3271 const char *expect, *body;
3272 char buf[MG_BUF_LEN];
3273 int to_read, nread, buffered_len, success = 0;
3274
3275 expect = mg_get_header(conn, "Expect");
3276 assert(fp != NULL);
3277
3278 if (conn->content_len == -1) {
3279 send_http_error(conn, 411, "Length Required", "%s", "");
3280 } else if (expect != NULL && mg_strcasecmp(expect, "100-continue")) {
3281 send_http_error(conn, 417, "Expectation Failed", "%s", "");
3282 } else {
3283 if (expect != NULL) {
3284 (void) mg_printf(conn, "%s", "HTTP/1.1 100 Continue\r\n\r\n");
3285 }
3286
3287 body = conn->buf + conn->request_len + conn->consumed_content;
3288 buffered_len = &conn->buf[conn->data_len] - body;
3289 assert(buffered_len >= 0);
3290 assert(conn->consumed_content == 0);
3291
3292 if (buffered_len > 0) {
3293 if ((int64_t) buffered_len > conn->content_len) {
3294 buffered_len = (int) conn->content_len;
3295 }
3296 push(fp, sock, ssl, body, (int64_t) buffered_len);
3297 conn->consumed_content += buffered_len;
3298 }
3299
3300 nread = 0;
3301 while (conn->consumed_content < conn->content_len) {
3302 to_read = sizeof(buf);
3303 if ((int64_t) to_read > conn->content_len - conn->consumed_content) {
3304 to_read = (int) (conn->content_len - conn->consumed_content);
3305 }
3306 nread = pull(NULL, conn, buf, to_read);
3307 if (nread <= 0 || push(fp, sock, ssl, buf, nread) != nread) {
3308 break;
3309 }
3310 conn->consumed_content += nread;
3311 }
3312
3313 if (conn->consumed_content == conn->content_len) {
3314 success = nread >= 0;
3315 }
3316
3317
3318 if (!success) {
3319 send_http_error(conn, 577, http_500_error, "%s", "");
3320 }
3321 }
3322
3323 return success;
3324 }
3325
3326 #if !defined(NO_CGI)
3327
3328
3329
3330
3331
3332
3333
3334
3335 struct cgi_env_block {
3336 struct mg_connection *conn;
3337 char buf[CGI_ENVIRONMENT_SIZE];
3338 int len;
3339 char *vars[MAX_CGI_ENVIR_VARS];
3340 int nvars;
3341 };
3342
3343 static char *addenv(struct cgi_env_block *block,
3344 PRINTF_FORMAT_STRING(const char *fmt), ...)
3345 PRINTF_ARGS(2, 3);
3346
3347
3348
3349 static char *addenv(struct cgi_env_block *block, const char *fmt, ...) {
3350 int n, space;
3351 char *added;
3352 va_list ap;
3353
3354
3355 space = sizeof(block->buf) - block->len - 2;
3356 assert(space >= 0);
3357
3358
3359 added = block->buf + block->len;
3360
3361
3362 va_start(ap, fmt);
3363 n = mg_vsnprintf(block->conn, added, (size_t) space, fmt, ap);
3364 va_end(ap);
3365
3366
3367 if (n > 0 && n + 1 < space &&
3368 block->nvars < (int) ARRAY_SIZE(block->vars) - 2) {
3369
3370 block->vars[block->nvars++] = added;
3371
3372 block->len += n + 1;
3373 } else {
3374 cry(block->conn, "%s: CGI env buffer truncated for [%s]", __func__, fmt);
3375 }
3376
3377 return added;
3378 }
3379
3380 static void prepare_cgi_environment(struct mg_connection *conn,
3381 const char *prog,
3382 struct cgi_env_block *blk) {
3383 const char *s, *slash;
3384 struct vec var_vec;
3385 char *p, src_addr[IP_ADDR_STR_LEN];
3386 int i;
3387
3388 blk->len = blk->nvars = 0;
3389 blk->conn = conn;
3390 sockaddr_to_string(src_addr, sizeof(src_addr), &conn->client.rsa);
3391
3392 addenv(blk, "SERVER_NAME=%s", conn->ctx->config[AUTHENTICATION_DOMAIN]);
3393 addenv(blk, "SERVER_ROOT=%s", conn->ctx->config[DOCUMENT_ROOT]);
3394 addenv(blk, "DOCUMENT_ROOT=%s", conn->ctx->config[DOCUMENT_ROOT]);
3395 addenv(blk, "SERVER_SOFTWARE=%s/%s", "Mongoose", mg_version());
3396
3397
3398 addenv(blk, "%s", "GATEWAY_INTERFACE=CGI/1.1");
3399 addenv(blk, "%s", "SERVER_PROTOCOL=HTTP/1.1");
3400 addenv(blk, "%s", "REDIRECT_STATUS=200");
3401
3402
3403 addenv(blk, "SERVER_PORT=%d", ntohs(conn->client.lsa.sin.sin_port));
3404
3405 addenv(blk, "REQUEST_METHOD=%s", conn->request_info.request_method);
3406 addenv(blk, "REMOTE_ADDR=%s", src_addr);
3407 addenv(blk, "REMOTE_PORT=%d", conn->request_info.remote_port);
3408 addenv(blk, "REQUEST_URI=%s", conn->request_info.uri);
3409
3410
3411 assert(conn->request_info.uri[0] == '/');
3412 slash = strrchr(conn->request_info.uri, '/');
3413 if ((s = strrchr(prog, '/')) == NULL)
3414 s = prog;
3415 addenv(blk, "SCRIPT_NAME=%.*s%s", (int) (slash - conn->request_info.uri),
3416 conn->request_info.uri, s);
3417
3418 addenv(blk, "SCRIPT_FILENAME=%s", prog);
3419 addenv(blk, "PATH_TRANSLATED=%s", prog);
3420 addenv(blk, "HTTPS=%s", conn->ssl == NULL ? "off" : "on");
3421
3422 if ((s = mg_get_header(conn, "Content-Type")) != NULL)
3423 addenv(blk, "CONTENT_TYPE=%s", s);
3424
3425 if (conn->request_info.query_string != NULL)
3426 addenv(blk, "QUERY_STRING=%s", conn->request_info.query_string);
3427
3428 if ((s = mg_get_header(conn, "Content-Length")) != NULL)
3429 addenv(blk, "CONTENT_LENGTH=%s", s);
3430
3431 if ((s = getenv("PATH")) != NULL)
3432 addenv(blk, "PATH=%s", s);
3433
3434 if (conn->path_info != NULL) {
3435 addenv(blk, "PATH_INFO=%s", conn->path_info);
3436 }
3437
3438 #if defined(_WIN32)
3439 if ((s = getenv("COMSPEC")) != NULL) {
3440 addenv(blk, "COMSPEC=%s", s);
3441 }
3442 if ((s = getenv("SYSTEMROOT")) != NULL) {
3443 addenv(blk, "SYSTEMROOT=%s", s);
3444 }
3445 if ((s = getenv("SystemDrive")) != NULL) {
3446 addenv(blk, "SystemDrive=%s", s);
3447 }
3448 if ((s = getenv("ProgramFiles")) != NULL) {
3449 addenv(blk, "ProgramFiles=%s", s);
3450 }
3451 if ((s = getenv("ProgramFiles(x86)")) != NULL) {
3452 addenv(blk, "ProgramFiles(x86)=%s", s);
3453 }
3454 #else
3455 if ((s = getenv("LD_LIBRARY_PATH")) != NULL)
3456 addenv(blk, "LD_LIBRARY_PATH=%s", s);
3457 #endif
3458
3459 if ((s = getenv("PERLLIB")) != NULL)
3460 addenv(blk, "PERLLIB=%s", s);
3461
3462 if (conn->request_info.remote_user != NULL) {
3463 addenv(blk, "REMOTE_USER=%s", conn->request_info.remote_user);
3464 addenv(blk, "%s", "AUTH_TYPE=Digest");
3465 }
3466
3467
3468 for (i = 0; i < conn->request_info.num_headers; i++) {
3469 p = addenv(blk, "HTTP_%s=%s",
3470 conn->request_info.http_headers[i].name,
3471 conn->request_info.http_headers[i].value);
3472
3473
3474 for (; *p != '=' && *p != '\0'; p++) {
3475 if (*p == '-')
3476 *p = '_';
3477 *p = (char) toupper(* (unsigned char *) p);
3478 }
3479 }
3480
3481
3482 s = conn->ctx->config[CGI_ENVIRONMENT];
3483 while ((s = next_option(s, &var_vec, NULL)) != NULL) {
3484 addenv(blk, "%.*s", (int) var_vec.len, var_vec.ptr);
3485 }
3486
3487 blk->vars[blk->nvars++] = NULL;
3488 blk->buf[blk->len++] = '\0';
3489
3490 assert(blk->nvars < (int) ARRAY_SIZE(blk->vars));
3491 assert(blk->len > 0);
3492 assert(blk->len < (int) sizeof(blk->buf));
3493 }
3494
3495 static void handle_cgi_request(struct mg_connection *conn, const char *prog) {
3496 int headers_len, data_len, i, fdin[2], fdout[2];
3497 const char *status, *status_text;
3498 char buf[16384], *pbuf, dir[PATH_MAX], *p;
3499 struct mg_request_info ri;
3500 struct cgi_env_block blk;
3501 FILE *in = NULL, *out = NULL;
3502 struct file fout = STRUCT_FILE_INITIALIZER;
3503 pid_t pid = (pid_t) -1;
3504
3505 prepare_cgi_environment(conn, prog, &blk);
3506
3507
3508
3509
3510 (void) mg_snprintf(conn, dir, sizeof(dir), "%s", prog);
3511 if ((p = strrchr(dir, '/')) != NULL) {
3512 *p++ = '\0';
3513 } else {
3514 dir[0] = '.', dir[1] = '\0';
3515 p = (char *) prog;
3516 }
3517
3518 if (pipe(fdin) != 0 || pipe(fdout) != 0) {
3519 send_http_error(conn, 500, http_500_error,
3520 "Cannot create CGI pipe: %s", strerror(ERRNO));
3521 goto done;
3522 }
3523
3524 pid = spawn_process(conn, p, blk.buf, blk.vars, fdin[0], fdout[1], dir);
3525 if (pid == (pid_t) -1) {
3526 send_http_error(conn, 500, http_500_error,
3527 "Cannot spawn CGI process [%s]: %s", prog, strerror(ERRNO));
3528 goto done;
3529 }
3530
3531
3532 set_close_on_exec(fdin[0]);
3533 set_close_on_exec(fdin[1]);
3534 set_close_on_exec(fdout[0]);
3535 set_close_on_exec(fdout[1]);
3536
3537
3538
3539
3540
3541 (void) close(fdin[0]);
3542 (void) close(fdout[1]);
3543 fdin[0] = fdout[1] = -1;
3544
3545
3546 if ((in = fdopen(fdin[1], "wb")) == NULL ||
3547 (out = fdopen(fdout[0], "rb")) == NULL) {
3548 send_http_error(conn, 500, http_500_error,
3549 "fopen: %s", strerror(ERRNO));
3550 goto done;
3551 }
3552
3553 setbuf(in, NULL);
3554 setbuf(out, NULL);
3555 fout.fp = out;
3556
3557
3558 if (!strcmp(conn->request_info.request_method, "POST") &&
3559 !forward_body_data(conn, in, INVALID_SOCKET, NULL)) {
3560 goto done;
3561 }
3562
3563
3564 fclose(in);
3565 in = NULL;
3566 fdin[1] = -1;
3567
3568
3569
3570
3571
3572 data_len = 0;
3573 headers_len = read_request(out, conn, buf, sizeof(buf), &data_len);
3574 if (headers_len <= 0) {
3575 send_http_error(conn, 500, http_500_error,
3576 "CGI program sent malformed or too big (>%u bytes) "
3577 "HTTP headers: [%.*s]",
3578 (unsigned) sizeof(buf), data_len, buf);
3579 goto done;
3580 }
3581 pbuf = buf;
3582 buf[headers_len - 1] = '\0';
3583 parse_http_headers(&pbuf, &ri);
3584
3585
3586 status_text = "OK";
3587 if ((status = get_header(&ri, "Status")) != NULL) {
3588 conn->status_code = atoi(status);
3589 status_text = status;
3590 while (isdigit(* (unsigned char *) status_text) || *status_text == ' ') {
3591 status_text++;
3592 }
3593 } else if (get_header(&ri, "Location") != NULL) {
3594 conn->status_code = 302;
3595 } else {
3596 conn->status_code = 200;
3597 }
3598 if (get_header(&ri, "Connection") != NULL &&
3599 !mg_strcasecmp(get_header(&ri, "Connection"), "keep-alive")) {
3600 conn->must_close = 1;
3601 }
3602 (void) mg_printf(conn, "HTTP/1.1 %d %s\r\n", conn->status_code,
3603 status_text);
3604
3605
3606 for (i = 0; i < ri.num_headers; i++) {
3607 mg_printf(conn, "%s: %s\r\n",
3608 ri.http_headers[i].name, ri.http_headers[i].value);
3609 }
3610 mg_write(conn, "\r\n", 2);
3611
3612
3613 conn->num_bytes_sent += mg_write(conn, buf + headers_len,
3614 (size_t)(data_len - headers_len));
3615
3616
3617 send_file_data(conn, &fout, 0, INT64_MAX);
3618
3619 done:
3620 if (pid != (pid_t) -1) {
3621 kill(pid, SIGKILL);
3622 }
3623 if (fdin[0] != -1) {
3624 close(fdin[0]);
3625 }
3626 if (fdout[1] != -1) {
3627 close(fdout[1]);
3628 }
3629
3630 if (in != NULL) {
3631 fclose(in);
3632 } else if (fdin[1] != -1) {
3633 close(fdin[1]);
3634 }
3635
3636 if (out != NULL) {
3637 fclose(out);
3638 } else if (fdout[0] != -1) {
3639 close(fdout[0]);
3640 }
3641 }
3642 #endif
3643
3644
3645
3646
3647 static int put_dir(struct mg_connection *conn, const char *path) {
3648 char buf[PATH_MAX];
3649 const char *s, *p;
3650 struct file file = STRUCT_FILE_INITIALIZER;
3651 int len, res = 1;
3652
3653 for (s = p = path + 2; (p = strchr(s, '/')) != NULL; s = ++p) {
3654 len = p - path;
3655 if (len >= (int) sizeof(buf)) {
3656 res = -1;
3657 break;
3658 }
3659 memcpy(buf, path, len);
3660 buf[len] = '\0';
3661
3662
3663 DEBUG_TRACE(("mkdir(%s)", buf));
3664 if (!mg_stat(conn, buf, &file) && mg_mkdir(buf, 0755) != 0) {
3665 res = -1;
3666 break;
3667 }
3668
3669
3670 if (p[1] == '\0') {
3671 res = 0;
3672 }
3673 }
3674
3675 return res;
3676 }
3677
3678 static void mkcol(struct mg_connection *conn, const char *path) {
3679 int rc, body_len;
3680 struct de de;
3681 memset(&de.file, 0, sizeof(de.file));
3682 mg_stat(conn, path, &de.file);
3683
3684 if(de.file.modification_time) {
3685 send_http_error(conn, 405, "Method Not Allowed",
3686 "mkcol(%s): %s", path, strerror(ERRNO));
3687 return;
3688 }
3689
3690 body_len = conn->data_len - conn->request_len;
3691 if(body_len > 0) {
3692 send_http_error(conn, 415, "Unsupported media type",
3693 "mkcol(%s): %s", path, strerror(ERRNO));
3694 return;
3695 }
3696
3697 rc = mg_mkdir(path, 0755);
3698
3699 if (rc == 0) {
3700 conn->status_code = 201;
3701 mg_printf(conn, "HTTP/1.1 %d Created\r\n\r\n", conn->status_code);
3702 } else if (rc == -1) {
3703 if(errno == EEXIST)
3704 send_http_error(conn, 405, "Method Not Allowed",
3705 "mkcol(%s): %s", path, strerror(ERRNO));
3706 else if(errno == EACCES)
3707 send_http_error(conn, 403, "Forbidden",
3708 "mkcol(%s): %s", path, strerror(ERRNO));
3709 else if(errno == ENOENT)
3710 send_http_error(conn, 409, "Conflict",
3711 "mkcol(%s): %s", path, strerror(ERRNO));
3712 else
3713 send_http_error(conn, 500, http_500_error,
3714 "fopen(%s): %s", path, strerror(ERRNO));
3715 }
3716 }
3717
3718 static void put_file(struct mg_connection *conn, const char *path) {
3719 struct file file = STRUCT_FILE_INITIALIZER;
3720 const char *range;
3721 int64_t r1, r2;
3722 int rc;
3723
3724 conn->status_code = mg_stat(conn, path, &file) ? 200 : 201;
3725
3726 if ((rc = put_dir(conn, path)) == 0) {
3727 mg_printf(conn, "HTTP/1.1 %d OK\r\n\r\n", conn->status_code);
3728 } else if (rc == -1) {
3729 send_http_error(conn, 500, http_500_error,
3730 "put_dir(%s): %s", path, strerror(ERRNO));
3731 } else if (!mg_fopen(conn, path, "wb+", &file) || file.fp == NULL) {
3732 mg_fclose(&file);
3733 send_http_error(conn, 500, http_500_error,
3734 "fopen(%s): %s", path, strerror(ERRNO));
3735 } else {
3736 fclose_on_exec(&file);
3737 range = mg_get_header(conn, "Content-Range");
3738 r1 = r2 = 0;
3739 if (range != NULL && parse_range_header(range, &r1, &r2) > 0) {
3740 conn->status_code = 206;
3741 fseeko(file.fp, r1, SEEK_SET);
3742 }
3743 if (!forward_body_data(conn, file.fp, INVALID_SOCKET, NULL)) {
3744 conn->status_code = 500;
3745 }
3746 mg_printf(conn, "HTTP/1.1 %d OK\r\nContent-Length: 0\r\n\r\n",
3747 conn->status_code);
3748 mg_fclose(&file);
3749 }
3750 }
3751
3752 static void send_ssi_file(struct mg_connection *, const char *,
3753 struct file *, int);
3754
3755 static void do_ssi_include(struct mg_connection *conn, const char *ssi,
3756 char *tag, int include_level) {
3757 char file_name[MG_BUF_LEN], path[PATH_MAX], *p;
3758 struct file file = STRUCT_FILE_INITIALIZER;
3759
3760
3761
3762 if (sscanf(tag, " virtual=\"%[^\"]\"", file_name) == 1) {
3763
3764 (void) mg_snprintf(conn, path, sizeof(path), "%s%c%s",
3765 conn->ctx->config[DOCUMENT_ROOT], '/', file_name);
3766 } else if (sscanf(tag, " abspath=\"%[^\"]\"", file_name) == 1) {
3767
3768
3769 (void) mg_snprintf(conn, path, sizeof(path), "%s", file_name);
3770 } else if (sscanf(tag, " file=\"%[^\"]\"", file_name) == 1 ||
3771 sscanf(tag, " \"%[^\"]\"", file_name) == 1) {
3772
3773 (void) mg_snprintf(conn, path, sizeof(path), "%s", ssi);
3774 if ((p = strrchr(path, '/')) != NULL) {
3775 p[1] = '\0';
3776 }
3777 (void) mg_snprintf(conn, path + strlen(path),
3778 sizeof(path) - strlen(path), "%s", file_name);
3779 } else {
3780 cry(conn, "Bad SSI #include: [%s]", tag);
3781 return;
3782 }
3783
3784 if (!mg_fopen(conn, path, "rb", &file)) {
3785 cry(conn, "Cannot open SSI #include: [%s]: fopen(%s): %s",
3786 tag, path, strerror(ERRNO));
3787 } else {
3788 fclose_on_exec(&file);
3789 if (match_prefix(conn->ctx->config[SSI_EXTENSIONS],
3790 strlen(conn->ctx->config[SSI_EXTENSIONS]), path) > 0) {
3791 send_ssi_file(conn, path, &file, include_level + 1);
3792 } else {
3793 send_file_data(conn, &file, 0, INT64_MAX);
3794 }
3795 mg_fclose(&file);
3796 }
3797 }
3798
3799 #if !defined(NO_POPEN)
3800 static void do_ssi_exec(struct mg_connection *conn, char *tag) {
3801 char cmd[MG_BUF_LEN];
3802 struct file file = STRUCT_FILE_INITIALIZER;
3803
3804 if (sscanf(tag, " \"%[^\"]\"", cmd) != 1) {
3805 cry(conn, "Bad SSI #exec: [%s]", tag);
3806 } else if ((file.fp = popen(cmd, "r")) == NULL) {
3807 cry(conn, "Cannot SSI #exec: [%s]: %s", cmd, strerror(ERRNO));
3808 } else {
3809 send_file_data(conn, &file, 0, INT64_MAX);
3810 pclose(file.fp);
3811 }
3812 }
3813 #endif
3814
3815 static int mg_fgetc(struct file *filep, int offset) {
3816 if (filep->membuf != NULL && offset >=0 && offset < filep->size) {
3817 return ((unsigned char *) filep->membuf)[offset];
3818 } else if (filep->fp != NULL) {
3819 return fgetc(filep->fp);
3820 } else {
3821 return EOF;
3822 }
3823 }
3824
3825 static void send_ssi_file(struct mg_connection *conn, const char *path,
3826 struct file *filep, int include_level) {
3827 char buf[MG_BUF_LEN];
3828 int ch, offset, len, in_ssi_tag;
3829
3830 if (include_level > 10) {
3831 cry(conn, "SSI #include level is too deep (%s)", path);
3832 return;
3833 }
3834
3835 in_ssi_tag = len = offset = 0;
3836 while ((ch = mg_fgetc(filep, offset)) != EOF) {
3837 if (in_ssi_tag && ch == '>') {
3838 in_ssi_tag = 0;
3839 buf[len++] = (char) ch;
3840 buf[len] = '\0';
3841 assert(len <= (int) sizeof(buf));
3842 if (len < 6 || memcmp(buf, "<!--#", 5) != 0) {
3843
3844 (void) mg_write(conn, buf, (size_t) len);
3845 } else {
3846 if (!memcmp(buf + 5, "include", 7)) {
3847 do_ssi_include(conn, path, buf + 12, include_level);
3848 #if !defined(NO_POPEN)
3849 } else if (!memcmp(buf + 5, "exec", 4)) {
3850 do_ssi_exec(conn, buf + 9);
3851 #endif
3852 } else {
3853 cry(conn, "%s: unknown SSI " "command: \"%s\"", path, buf);
3854 }
3855 }
3856 len = 0;
3857 } else if (in_ssi_tag) {
3858 if (len == 5 && memcmp(buf, "<!--#", 5) != 0) {
3859
3860 in_ssi_tag = 0;
3861 } else if (len == (int) sizeof(buf) - 2) {
3862 cry(conn, "%s: SSI tag is too large", path);
3863 len = 0;
3864 }
3865 buf[len++] = ch & 0xff;
3866 } else if (ch == '<') {
3867 in_ssi_tag = 1;
3868 if (len > 0) {
3869 mg_write(conn, buf, (size_t) len);
3870 }
3871 len = 0;
3872 buf[len++] = ch & 0xff;
3873 } else {
3874 buf[len++] = ch & 0xff;
3875 if (len == (int) sizeof(buf)) {
3876 mg_write(conn, buf, (size_t) len);
3877 len = 0;
3878 }
3879 }
3880 }
3881
3882
3883 if (len > 0) {
3884 mg_write(conn, buf, (size_t) len);
3885 }
3886 }
3887
3888 static void handle_ssi_file_request(struct mg_connection *conn,
3889 const char *path) {
3890 struct file file = STRUCT_FILE_INITIALIZER;
3891
3892 if (!mg_fopen(conn, path, "rb", &file)) {
3893 send_http_error(conn, 500, http_500_error, "fopen(%s): %s", path,
3894 strerror(ERRNO));
3895 } else {
3896 conn->must_close = 1;
3897 fclose_on_exec(&file);
3898 mg_printf(conn, "HTTP/1.1 200 OK\r\n"
3899 "Content-Type: text/html\r\nConnection: %s\r\n\r\n",
3900 suggest_connection_header(conn));
3901 send_ssi_file(conn, path, &file, 0);
3902 mg_fclose(&file);
3903 }
3904 }
3905
3906 static void send_options(struct mg_connection *conn) {
3907 conn->status_code = 200;
3908
3909 mg_printf(conn, "%s", "HTTP/1.1 200 OK\r\n"
3910 "Allow: GET, POST, HEAD, CONNECT, PUT, DELETE, OPTIONS, PROPFIND, MKCOL\r\n"
3911 "DAV: 1\r\n\r\n");
3912 }
3913
3914
3915 static void print_props(struct mg_connection *conn, const char* uri,
3916 struct file *filep) {
3917 char mtime[64];
3918 gmt_time_string(mtime, sizeof(mtime), &filep->modification_time);
3919 conn->num_bytes_sent += mg_printf(conn,
3920 "<d:response>"
3921 "<d:href>%s</d:href>"
3922 "<d:propstat>"
3923 "<d:prop>"
3924 "<d:resourcetype>%s</d:resourcetype>"
3925 "<d:getcontentlength>%" INT64_FMT "</d:getcontentlength>"
3926 "<d:getlastmodified>%s</d:getlastmodified>"
3927 "</d:prop>"
3928 "<d:status>HTTP/1.1 200 OK</d:status>"
3929 "</d:propstat>"
3930 "</d:response>\n",
3931 uri,
3932 filep->is_directory ? "<d:collection/>" : "",
3933 filep->size,
3934 mtime);
3935 }
3936
3937 static void print_dav_dir_entry(struct de *de, void *data) {
3938 char href[PATH_MAX];
3939 char href_encoded[PATH_MAX];
3940 struct mg_connection *conn = (struct mg_connection *) data;
3941 mg_snprintf(conn, href, sizeof(href), "%s%s",
3942 conn->request_info.uri, de->file_name);
3943 mg_url_encode(href, href_encoded, PATH_MAX-1);
3944 print_props(conn, href_encoded, &de->file);
3945 }
3946
3947 static void handle_propfind(struct mg_connection *conn, const char *path,
3948 struct file *filep) {
3949 const char *depth = mg_get_header(conn, "Depth");
3950
3951 conn->must_close = 1;
3952 conn->status_code = 207;
3953 mg_printf(conn, "HTTP/1.1 207 Multi-Status\r\n"
3954 "Connection: close\r\n"
3955 "Content-Type: text/xml; charset=utf-8\r\n\r\n");
3956
3957 conn->num_bytes_sent += mg_printf(conn,
3958 "<?xml version=\"1.0\" encoding=\"utf-8\"?>"
3959 "<d:multistatus xmlns:d='DAV:'>\n");
3960
3961
3962 print_props(conn, conn->request_info.uri, filep);
3963
3964
3965 if (filep->is_directory &&
3966 !mg_strcasecmp(conn->ctx->config[ENABLE_DIRECTORY_LISTING], "yes") &&
3967 (depth == NULL || strcmp(depth, "0") != 0)) {
3968 scan_directory(conn, path, conn, &print_dav_dir_entry);
3969 }
3970
3971 conn->num_bytes_sent += mg_printf(conn, "%s\n", "</d:multistatus>");
3972 }
3973
3974 #if defined(USE_WEBSOCKET)
3975
3976
3977
3978 #define SHA1HANDSOFF
3979 #if defined(__sun)
3980 #include "solarisfixes.h"
3981 #endif
3982
3983 union char64long16 { unsigned char c[64]; uint32_t l[16]; };
3984
3985 #define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits))))
3986
3987 static uint32_t blk0(union char64long16 *block, int i) {
3988
3989 if (!is_big_endian()) {
3990 block->l[i] = (rol(block->l[i], 24) & 0xFF00FF00) |
3991 (rol(block->l[i], 8) & 0x00FF00FF);
3992 }
3993 return block->l[i];
3994 }
3995
3996 #define blk(i) (block->l[i&15] = rol(block->l[(i+13)&15]^block->l[(i+8)&15] \
3997 ^block->l[(i+2)&15]^block->l[i&15],1))
3998 #define R0(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk0(block, i)+0x5A827999+rol(v,5);w=rol(w,30);
3999 #define R1(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5);w=rol(w,30);
4000 #define R2(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=rol(w,30);
4001 #define R3(v,w,x,y,z,i) z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=rol(w,30);
4002 #define R4(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=rol(w,30);
4003
4004 typedef struct {
4005 uint32_t state[5];
4006 uint32_t count[2];
4007 unsigned char buffer[64];
4008 } SHA1_CTX;
4009
4010 static void SHA1Transform(uint32_t state[5], const unsigned char buffer[64]) {
4011 uint32_t a, b, c, d, e;
4012 union char64long16 block[1];
4013
4014 memcpy(block, buffer, 64);
4015 a = state[0];
4016 b = state[1];
4017 c = state[2];
4018 d = state[3];
4019 e = state[4];
4020 R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3);
4021 R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7);
4022 R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11);
4023 R0(d,e,a,b,c,12); R0(c,d,e,a,b,13); R0(b,c,d,e,a,14); R0(a,b,c,d,e,15);
4024 R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19);
4025 R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23);
4026 R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27);
4027 R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31);
4028 R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35);
4029 R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39);
4030 R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43);
4031 R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47);
4032 R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51);
4033 R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55);
4034 R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59);
4035 R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63);
4036 R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67);
4037 R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71);
4038 R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75);
4039 R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79);
4040 state[0] += a;
4041 state[1] += b;
4042 state[2] += c;
4043 state[3] += d;
4044 state[4] += e;
4045 a = b = c = d = e = 0;
4046 memset(block, '\0', sizeof(block));
4047 }
4048
4049 static void SHA1Init(SHA1_CTX* context) {
4050 context->state[0] = 0x67452301;
4051 context->state[1] = 0xEFCDAB89;
4052 context->state[2] = 0x98BADCFE;
4053 context->state[3] = 0x10325476;
4054 context->state[4] = 0xC3D2E1F0;
4055 context->count[0] = context->count[1] = 0;
4056 }
4057
4058 static void SHA1Update(SHA1_CTX* context, const unsigned char* data,
4059 uint32_t len) {
4060 uint32_t i, j;
4061
4062 j = context->count[0];
4063 if ((context->count[0] += len << 3) < j)
4064 context->count[1]++;
4065 context->count[1] += (len>>29);
4066 j = (j >> 3) & 63;
4067 if ((j + len) > 63) {
4068 memcpy(&context->buffer[j], data, (i = 64-j));
4069 SHA1Transform(context->state, context->buffer);
4070 for ( ; i + 63 < len; i += 64) {
4071 SHA1Transform(context->state, &data[i]);
4072 }
4073 j = 0;
4074 }
4075 else i = 0;
4076 memcpy(&context->buffer[j], &data[i], len - i);
4077 }
4078
4079 static void SHA1Final(unsigned char digest[20], SHA1_CTX* context) {
4080 unsigned i;
4081 unsigned char finalcount[8], c;
4082
4083 for (i = 0; i < 8; i++) {
4084 finalcount[i] = (unsigned char)((context->count[(i >= 4 ? 0 : 1)]
4085 >> ((3-(i & 3)) * 8) ) & 255);
4086 }
4087 c = 0200;
4088 SHA1Update(context, &c, 1);
4089 while ((context->count[0] & 504) != 448) {
4090 c = 0000;
4091 SHA1Update(context, &c, 1);
4092 }
4093 SHA1Update(context, finalcount, 8);
4094 for (i = 0; i < 20; i++) {
4095 digest[i] = (unsigned char)
4096 ((context->state[i>>2] >> ((3-(i & 3)) * 8) ) & 255);
4097 }
4098 memset(context, '\0', sizeof(*context));
4099 memset(&finalcount, '\0', sizeof(finalcount));
4100 }
4101
4102
4103 static void base64_encode(const unsigned char *src, int src_len, char *dst) {
4104 static const char *b64 =
4105 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
4106 int i, j, a, b, c;
4107
4108 for (i = j = 0; i < src_len; i += 3) {
4109 a = src[i];
4110 b = i + 1 >= src_len ? 0 : src[i + 1];
4111 c = i + 2 >= src_len ? 0 : src[i + 2];
4112
4113 dst[j++] = b64[a >> 2];
4114 dst[j++] = b64[((a & 3) << 4) | (b >> 4)];
4115 if (i + 1 < src_len) {
4116 dst[j++] = b64[(b & 15) << 2 | (c >> 6)];
4117 }
4118 if (i + 2 < src_len) {
4119 dst[j++] = b64[c & 63];
4120 }
4121 }
4122 while (j % 4 != 0) {
4123 dst[j++] = '=';
4124 }
4125 dst[j++] = '\0';
4126 }
4127
4128 static void send_websocket_handshake(struct mg_connection *conn) {
4129 static const char *magic = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
4130 char buf[100], sha[20], b64_sha[sizeof(sha) * 2];
4131 SHA1_CTX sha_ctx;
4132
4133 mg_snprintf(conn, buf, sizeof(buf), "%s%s",
4134 mg_get_header(conn, "Sec-WebSocket-Key"), magic);
4135 SHA1Init(&sha_ctx);
4136 SHA1Update(&sha_ctx, (unsigned char *) buf, strlen(buf));
4137 SHA1Final((unsigned char *) sha, &sha_ctx);
4138 base64_encode((unsigned char *) sha, sizeof(sha), b64_sha);
4139 mg_printf(conn, "%s%s%s",
4140 "HTTP/1.1 101 Switching Protocols\r\n"
4141 "Upgrade: websocket\r\n"
4142 "Connection: Upgrade\r\n"
4143 "Sec-WebSocket-Accept: ", b64_sha, "\r\n\r\n");
4144 }
4145
4146 static void read_websocket(struct mg_connection *conn) {
4147
4148
4149
4150 unsigned char *buf = (unsigned char *) conn->buf + conn->request_len;
4151 int bits, n, stop = 0;
4152 size_t i, len, mask_len, data_len, header_len, body_len;
4153
4154
4155
4156 char mem[4 * 1024], mask[4], *data;
4157
4158 assert(conn->content_len == 0);
4159
4160
4161
4162 while (!stop) {
4163 header_len = 0;
4164
4165
4166
4167
4168 if ((body_len = conn->data_len - conn->request_len) >= 2) {
4169 len = buf[1] & 127;
4170 mask_len = buf[1] & 128 ? 4 : 0;
4171 if (len < 126 && body_len >= mask_len) {
4172 data_len = len;
4173 header_len = 2 + mask_len;
4174 } else if (len == 126 && body_len >= 4 + mask_len) {
4175 header_len = 4 + mask_len;
4176 data_len = ((((int) buf[2]) << 8) + buf[3]);
4177 } else if (body_len >= 10 + mask_len) {
4178 header_len = 10 + mask_len;
4179 data_len = (((uint64_t) htonl(* (uint32_t *) &buf[2])) << 32) +
4180 htonl(* (uint32_t *) &buf[6]);
4181 }
4182 }
4183
4184
4185
4186
4187
4188
4189
4190
4191
4192 if (header_len > 0) {
4193
4194 data = mem;
4195 if (data_len > sizeof(mem) && (data = malloc(data_len)) == NULL) {
4196
4197
4198 break;
4199 }
4200
4201
4202 bits = buf[0];
4203 memcpy(mask, buf + header_len - mask_len, mask_len);
4204
4205
4206 assert(body_len >= header_len);
4207 if (data_len + header_len > body_len) {
4208 len = body_len - header_len;
4209 memcpy(data, buf + header_len, len);
4210
4211 pull_all(NULL, conn, data + len, data_len - len);
4212 conn->data_len = conn->request_len;
4213 } else {
4214 len = data_len + header_len;
4215 memcpy(data, buf + header_len, data_len);
4216 memmove(buf, buf + len, body_len - len);
4217 conn->data_len -= len;
4218 }
4219
4220
4221 if (mask_len > 0) {
4222 for (i = 0; i < data_len; i++) {
4223 data[i] ^= mask[i % 4];
4224 }
4225 }
4226
4227
4228
4229 if ((bits & WEBSOCKET_OPCODE_CONNECTION_CLOSE) ||
4230 (conn->ctx->callbacks.websocket_data != NULL &&
4231 !conn->ctx->callbacks.websocket_data(conn, bits, data, data_len))) {
4232 stop = 1;
4233 }
4234
4235 if (data != mem) {
4236 free(data);
4237 }
4238
4239 } else {
4240
4241 if ((n = pull(NULL, conn, conn->buf + conn->data_len,
4242 conn->buf_size - conn->data_len)) <= 0) {
4243 break;
4244 }
4245 conn->data_len += n;
4246 }
4247 }
4248 }
4249
4250 int mg_websocket_write(struct mg_connection* conn, int opcode,
4251 const char *data, size_t data_len) {
4252 unsigned char *copy;
4253 size_t copy_len = 0;
4254 int retval = -1;
4255
4256 if ((copy = (unsigned char *) malloc(data_len + 10)) == NULL) {
4257 return -1;
4258 }
4259
4260 copy[0] = 0x80 + (opcode & 0x0f);
4261
4262
4263 if (data_len < 126) {
4264
4265 copy[1] = data_len;
4266 memcpy(copy + 2, data, data_len);
4267 copy_len = 2 + data_len;
4268 } else if (data_len <= 0xFFFF) {
4269
4270 copy[1] = 126;
4271 * (uint16_t *) (copy + 2) = htons(data_len);
4272 memcpy(copy + 4, data, data_len);
4273 copy_len = 4 + data_len;
4274 } else {
4275
4276 copy[1] = 127;
4277 * (uint32_t *) (copy + 2) = htonl((uint64_t) data_len >> 32);
4278 * (uint32_t *) (copy + 6) = htonl(data_len & 0xffffffff);
4279 memcpy(copy + 10, data, data_len);
4280 copy_len = 10 + data_len;
4281 }
4282
4283
4284 if (copy_len > 0) {
4285 retval = mg_write(conn, copy, copy_len);
4286 }
4287 free(copy);
4288
4289 return retval;
4290 }
4291
4292 static void handle_websocket_request(struct mg_connection *conn) {
4293 const char *version = mg_get_header(conn, "Sec-WebSocket-Version");
4294 if (version == NULL || strcmp(version, "13") != 0) {
4295 send_http_error(conn, 426, "Upgrade Required", "%s", "Upgrade Required");
4296 } else if (conn->ctx->callbacks.websocket_connect != NULL &&
4297 conn->ctx->callbacks.websocket_connect(conn) != 0) {
4298
4299 } else {
4300 send_websocket_handshake(conn);
4301 if (conn->ctx->callbacks.websocket_ready != NULL) {
4302 conn->ctx->callbacks.websocket_ready(conn);
4303 }
4304 read_websocket(conn);
4305 }
4306 }
4307
4308 static int is_websocket_request(const struct mg_connection *conn) {
4309 const char *host, *upgrade, *connection, *version, *key;
4310
4311 host = mg_get_header(conn, "Host");
4312 upgrade = mg_get_header(conn, "Upgrade");
4313 connection = mg_get_header(conn, "Connection");
4314 key = mg_get_header(conn, "Sec-WebSocket-Key");
4315 version = mg_get_header(conn, "Sec-WebSocket-Version");
4316
4317 return host != NULL && upgrade != NULL && connection != NULL &&
4318 key != NULL && version != NULL &&
4319 mg_strcasestr(upgrade, "websocket") != NULL &&
4320 mg_strcasestr(connection, "Upgrade") != NULL;
4321 }
4322 #endif
4323
4324 static int isbyte(int n) {
4325 return n >= 0 && n <= 255;
4326 }
4327
4328 static int parse_net(const char *spec, uint32_t *net, uint32_t *mask) {
4329 int n, a, b, c, d, slash = 32, len = 0;
4330
4331 if ((sscanf(spec, "%d.%d.%d.%d/%d%n", &a, &b, &c, &d, &slash, &n) == 5 ||
4332 sscanf(spec, "%d.%d.%d.%d%n", &a, &b, &c, &d, &n) == 4) &&
4333 isbyte(a) && isbyte(b) && isbyte(c) && isbyte(d) &&
4334 slash >= 0 && slash < 33) {
4335 len = n;
4336 *net = ((uint32_t)a << 24) | ((uint32_t)b << 16) | ((uint32_t)c << 8) | d;
4337 *mask = slash ? 0xffffffffU << (32 - slash) : 0;
4338 }
4339
4340 return len;
4341 }
4342
4343 static int set_throttle(const char *spec, uint32_t remote_ip, const char *uri) {
4344 int throttle = 0;
4345 struct vec vec, val;
4346 uint32_t net, mask;
4347 char mult;
4348 double v;
4349
4350 while ((spec = next_option(spec, &vec, &val)) != NULL) {
4351 mult = ',';
4352 if (sscanf(val.ptr, "%lf%c", &v, &mult) < 1 || v < 0 ||
4353 (lowercase(&mult) != 'k' && lowercase(&mult) != 'm' && mult != ',')) {
4354 continue;
4355 }
4356 v *= lowercase(&mult) == 'k' ? 1024 : lowercase(&mult) == 'm' ? 1048576 : 1;
4357 if (vec.len == 1 && vec.ptr[0] == '*') {
4358 throttle = (int) v;
4359 } else if (parse_net(vec.ptr, &net, &mask) > 0) {
4360 if ((remote_ip & mask) == net) {
4361 throttle = (int) v;
4362 }
4363 } else if (match_prefix(vec.ptr, vec.len, uri) > 0) {
4364 throttle = (int) v;
4365 }
4366 }
4367
4368 return throttle;
4369 }
4370
4371 static uint32_t get_remote_ip(const struct mg_connection *conn) {
4372 return ntohl(* (uint32_t *) &conn->client.rsa.sin.sin_addr);
4373 }
4374
4375 #ifdef USE_LUA
4376 #include "mod_lua.c"
4377 #endif
4378
4379 int mg_upload(struct mg_connection *conn, const char *destination_dir) {
4380 const char *content_type_header, *boundary_start;
4381 char buf[MG_BUF_LEN], path[PATH_MAX], fname[1024], boundary[100], *s;
4382 FILE *fp;
4383 int bl, n, i, j, headers_len, boundary_len, eof,
4384 len = 0, num_uploaded_files = 0;
4385
4386
4387
4388
4389
4390
4391
4392
4393
4394
4395
4396
4397
4398
4399
4400
4401
4402 if ((content_type_header = mg_get_header(conn, "Content-Type")) == NULL ||
4403 (boundary_start = mg_strcasestr(content_type_header,
4404 "boundary=")) == NULL ||
4405 (sscanf(boundary_start, "boundary=\"%99[^\"]\"", boundary) == 0 &&
4406 sscanf(boundary_start, "boundary=%99s", boundary) == 0) ||
4407 boundary[0] == '\0') {
4408 return num_uploaded_files;
4409 }
4410
4411 boundary_len = strlen(boundary);
4412 bl = boundary_len + 4;
4413 for (;;) {
4414
4415 assert(len >= 0 && len <= (int) sizeof(buf));
4416 while ((n = mg_read(conn, buf + len, sizeof(buf) - len)) > 0) {
4417 len += n;
4418 }
4419 if ((headers_len = get_request_len(buf, len)) <= 0) {
4420 break;
4421 }
4422
4423
4424 fname[0] = '\0';
4425 for (i = j = 0; i < headers_len; i++) {
4426 if (buf[i] == '\r' && buf[i + 1] == '\n') {
4427 buf[i] = buf[i + 1] = '\0';
4428
4429
4430 sscanf(&buf[j], "Content-Disposition: %*s %*s filename=\"%1023[^\"]",
4431 fname);
4432 j = i + 2;
4433 }
4434 }
4435
4436
4437 if (fname[0] == '\0') {
4438 break;
4439 }
4440
4441
4442 assert(len >= headers_len);
4443 memmove(buf, &buf[headers_len], len - headers_len);
4444 len -= headers_len;
4445
4446
4447
4448 fp = NULL;
4449
4450 if ((s = strrchr(fname, '/')) == NULL &&
4451 (s = strrchr(fname, '\\')) == NULL) {
4452 s = fname;
4453 }
4454
4455
4456 snprintf(path, sizeof(path), "%s/%s", destination_dir, s);
4457 if ((fp = fopen(path, "wb")) == NULL) {
4458 break;
4459 }
4460
4461
4462 eof = n = 0;
4463 do {
4464 len += n;
4465 for (i = 0; i < len - bl; i++) {
4466 if (!memcmp(&buf[i], "\r\n--", 4) &&
4467 !memcmp(&buf[i + 4], boundary, boundary_len)) {
4468
4469 fwrite(buf, 1, i, fp);
4470 eof = 1;
4471 memmove(buf, &buf[i + bl], len - (i + bl));
4472 len -= i + bl;
4473 break;
4474 }
4475 }
4476 if (!eof && len > bl) {
4477 fwrite(buf, 1, len - bl, fp);
4478 memmove(buf, &buf[len - bl], bl);
4479 len = bl;
4480 }
4481 } while (!eof && (n = mg_read(conn, buf + len, sizeof(buf) - len)) > 0);
4482 fclose(fp);
4483 if (eof) {
4484 num_uploaded_files++;
4485 if (conn->ctx->callbacks.upload != NULL) {
4486 conn->ctx->callbacks.upload(conn, path);
4487 }
4488 }
4489 }
4490
4491 return num_uploaded_files;
4492 }
4493
4494 static int is_put_or_delete_request(const struct mg_connection *conn) {
4495 const char *s = conn->request_info.request_method;
4496 return s != NULL && (!strcmp(s, "PUT") ||
4497 !strcmp(s, "DELETE") ||
4498 !strcmp(s, "MKCOL"));
4499 }
4500
4501 static int get_first_ssl_listener_index(const struct mg_context *ctx) {
4502 int i, index = -1;
4503 for (i = 0; index == -1 && i < ctx->num_listening_sockets; i++) {
4504 index = ctx->listening_sockets[i].is_ssl ? i : -1;
4505 }
4506 return index;
4507 }
4508
4509 static void redirect_to_https_port(struct mg_connection *conn, int ssl_index) {
4510 char host[1025];
4511 const char *host_header;
4512
4513 if ((host_header = mg_get_header(conn, "Host")) == NULL ||
4514 sscanf(host_header, "%1024[^:]", host) == 0) {
4515
4516 sockaddr_to_string(host, sizeof(host), &conn->client.lsa);
4517 }
4518
4519 mg_printf(conn, "HTTP/1.1 302 Found\r\nLocation: https://%s:%d%s\r\n\r\n",
4520 host, (int) ntohs(conn->ctx->listening_sockets[ssl_index].
4521 lsa.sin.sin_port), conn->request_info.uri);
4522 }
4523
4524
4525
4526
4527
4528 static void handle_request(struct mg_connection *conn) {
4529 struct mg_request_info *ri = &conn->request_info;
4530 char path[PATH_MAX];
4531 int uri_len, ssl_index;
4532 struct file file = STRUCT_FILE_INITIALIZER;
4533
4534 if ((conn->request_info.query_string = strchr(ri->uri, '?')) != NULL) {
4535 * ((char *) conn->request_info.query_string++) = '\0';
4536 }
4537 uri_len = (int) strlen(ri->uri);
4538 mg_url_decode(ri->uri, uri_len, (char *) ri->uri, uri_len + 1, 0);
4539 remove_double_dots_and_double_slashes((char *) ri->uri);
4540 convert_uri_to_file_name(conn, path, sizeof(path), &file);
4541 conn->throttle = set_throttle(conn->ctx->config[THROTTLE],
4542 get_remote_ip(conn), ri->uri);
4543
4544 DEBUG_TRACE(("%s", ri->uri));
4545
4546
4547 if (!conn->client.is_ssl && conn->client.ssl_redir &&
4548 (ssl_index = get_first_ssl_listener_index(conn->ctx)) > -1) {
4549 redirect_to_https_port(conn, ssl_index);
4550 } else if (!is_put_or_delete_request(conn) &&
4551 !check_authorization(conn, path)) {
4552 send_authorization_request(conn);
4553 } else if (conn->ctx->callbacks.begin_request != NULL &&
4554 conn->ctx->callbacks.begin_request(conn)) {
4555
4556 #if defined(USE_WEBSOCKET)
4557 } else if (is_websocket_request(conn)) {
4558 handle_websocket_request(conn);
4559 #endif
4560 } else if (!strcmp(ri->request_method, "OPTIONS")) {
4561 send_options(conn);
4562 } else if (conn->ctx->config[DOCUMENT_ROOT] == NULL) {
4563 send_http_error(conn, 404, "Not Found", "Not Found");
4564 } else if (is_put_or_delete_request(conn) &&
4565 (is_authorized_for_put(conn) != 1)) {
4566 send_authorization_request(conn);
4567 } else if (!strcmp(ri->request_method, "PUT")) {
4568 put_file(conn, path);
4569 } else if (!strcmp(ri->request_method, "MKCOL")) {
4570 mkcol(conn, path);
4571 } else if (!strcmp(ri->request_method, "DELETE")) {
4572 struct de de;
4573 memset(&de.file, 0, sizeof(de.file));
4574 if(!mg_stat(conn, path, &de.file)) {
4575 send_http_error(conn, 404, "Not Found", "%s", "File not found");
4576 } else {
4577 if(de.file.modification_time) {
4578 if(de.file.is_directory) {
4579 remove_directory(conn, path);
4580 send_http_error(conn, 204, "No Content", "%s", "");
4581 } else if (mg_remove(path) == 0) {
4582 send_http_error(conn, 204, "No Content", "%s", "");
4583 } else {
4584 send_http_error(conn, 423, "Locked", "remove(%s): %s", path,
4585 strerror(ERRNO));
4586 }
4587 }
4588 else {
4589 send_http_error(conn, 500, http_500_error, "remove(%s): %s", path,
4590 strerror(ERRNO));
4591 }
4592 }
4593 } else if ((file.membuf == NULL && file.modification_time == (time_t) 0) ||
4594 must_hide_file(conn, path)) {
4595 send_http_error(conn, 404, "Not Found", "%s", "File not found");
4596 } else if (file.is_directory && ri->uri[uri_len - 1] != '/') {
4597 mg_printf(conn, "HTTP/1.1 301 Moved Permanently\r\n"
4598 "Location: %s/\r\n\r\n", ri->uri);
4599 } else if (!strcmp(ri->request_method, "PROPFIND")) {
4600 handle_propfind(conn, path, &file);
4601 } else if (file.is_directory &&
4602 !substitute_index_file(conn, path, sizeof(path), &file)) {
4603 if (!mg_strcasecmp(conn->ctx->config[ENABLE_DIRECTORY_LISTING], "yes")) {
4604 handle_directory_request(conn, path);
4605 } else {
4606 send_http_error(conn, 403, "Directory Listing Denied",
4607 "Directory listing denied");
4608 }
4609 #ifdef USE_LUA
4610 } else if (match_prefix("**.lp$", 6, path) > 0) {
4611 handle_lsp_request(conn, path, &file, NULL);
4612 #endif
4613 #if !defined(NO_CGI)
4614 } else if (match_prefix(conn->ctx->config[CGI_EXTENSIONS],
4615 strlen(conn->ctx->config[CGI_EXTENSIONS]),
4616 path) > 0) {
4617 if (strcmp(ri->request_method, "POST") &&
4618 strcmp(ri->request_method, "HEAD") &&
4619 strcmp(ri->request_method, "GET")) {
4620 send_http_error(conn, 501, "Not Implemented",
4621 "Method %s is not implemented", ri->request_method);
4622 } else {
4623 handle_cgi_request(conn, path);
4624 }
4625 #endif
4626 } else if (match_prefix(conn->ctx->config[SSI_EXTENSIONS],
4627 strlen(conn->ctx->config[SSI_EXTENSIONS]),
4628 path) > 0) {
4629 handle_ssi_file_request(conn, path);
4630 } else if (is_not_modified(conn, path, &file)) {
4631 send_http_error(conn, 304, "Not Modified", "%s", "");
4632 } else {
4633 handle_file_request(conn, path, &file);
4634 }
4635 }
4636
4637 static void close_all_listening_sockets(struct mg_context *ctx) {
4638 int i;
4639 for (i = 0; i < ctx->num_listening_sockets; i++) {
4640 closesocket(ctx->listening_sockets[i].sock);
4641 }
4642 free(ctx->listening_sockets);
4643 }
4644
4645 static int is_valid_port(unsigned int port) {
4646 return port > 0 && port < 0xffff;
4647 }
4648
4649
4650
4651
4652 static int parse_port_string(const struct vec *vec, struct socket *so) {
4653 unsigned int a, b, c, d, ch, len, port;
4654 #if defined(USE_IPV6)
4655 char buf[100];
4656 #endif
4657
4658
4659
4660
4661 memset(so, 0, sizeof(*so));
4662 so->lsa.sin.sin_family = AF_INET;
4663
4664 if (sscanf(vec->ptr, "%u.%u.%u.%u:%u%n", &a, &b, &c, &d, &port, &len) == 5) {
4665
4666 so->lsa.sin.sin_addr.s_addr = htonl((a << 24) | (b << 16) | (c << 8) | d);
4667 so->lsa.sin.sin_port = htons((uint16_t) port);
4668 #if defined(USE_IPV6)
4669
4670 } else if (sscanf(vec->ptr, "[%49[^]]]:%d%n", buf, &port, &len) == 2 &&
4671 inet_pton(AF_INET6, buf, &so->lsa.sin6.sin6_addr)) {
4672
4673 so->lsa.sin6.sin6_family = AF_INET6;
4674 so->lsa.sin6.sin6_port = htons((uint16_t) port);
4675 #endif
4676 } else if (sscanf(vec->ptr, "%u%n", &port, &len) == 1) {
4677
4678 so->lsa.sin.sin_port = htons((uint16_t) port);
4679 } else {
4680 port = len = 0;
4681 }
4682
4683 ch = vec->ptr[len];
4684 so->is_ssl = ch == 's';
4685 so->ssl_redir = ch == 'r';
4686
4687
4688 return is_valid_port(port) &&
4689 (ch == '\0' || ch == 's' || ch == 'r' || ch == ',');
4690 }
4691
4692 static int set_ports_option(struct mg_context *ctx) {
4693 const char *list = ctx->config[LISTENING_PORTS];
4694 int on = 1, success = 1;
4695 #if defined(USE_IPV6)
4696 int off = 0;
4697 #endif
4698 struct vec vec;
4699 struct socket so, *ptr;
4700
4701 while (success && (list = next_option(list, &vec, NULL)) != NULL) {
4702 if (!parse_port_string(&vec, &so)) {
4703 cry(fc(ctx), "%s: %.*s: invalid port spec. Expecting list of: %s",
4704 __func__, (int) vec.len, vec.ptr, "[IP_ADDRESS:]PORT[s|r]");
4705 success = 0;
4706 } else if (so.is_ssl && ctx->ssl_ctx == NULL) {
4707 cry(fc(ctx), "Cannot add SSL socket, is -ssl_certificate option set?");
4708 success = 0;
4709 } else if ((so.sock = socket(so.lsa.sa.sa_family, SOCK_STREAM, 6)) ==
4710 INVALID_SOCKET ||
4711
4712
4713 setsockopt(so.sock, SOL_SOCKET, SO_REUSEADDR,
4714 (void *) &on, sizeof(on)) != 0 ||
4715 #if defined(USE_IPV6)
4716 (so.lsa.sa.sa_family == AF_INET6 &&
4717 setsockopt(so.sock, IPPROTO_IPV6, IPV6_V6ONLY, (void *) &off,
4718 sizeof(off)) != 0) ||
4719 #endif
4720 bind(so.sock, &so.lsa.sa, so.lsa.sa.sa_family == AF_INET ?
4721 sizeof(so.lsa.sin) : sizeof(so.lsa)) != 0 ||
4722 listen(so.sock, SOMAXCONN) != 0) {
4723 cry(fc(ctx), "%s: cannot bind to %.*s: %d (%s)", __func__,
4724 (int) vec.len, vec.ptr, ERRNO, strerror(errno));
4725 closesocket(so.sock);
4726 success = 0;
4727 } else if ((ptr = (struct socket *) realloc(ctx->listening_sockets,
4728 (ctx->num_listening_sockets + 1) *
4729 sizeof(ctx->listening_sockets[0]))) == NULL) {
4730 closesocket(so.sock);
4731 success = 0;
4732 } else {
4733 set_close_on_exec(so.sock);
4734 ctx->listening_sockets = ptr;
4735 ctx->listening_sockets[ctx->num_listening_sockets] = so;
4736 ctx->num_listening_sockets++;
4737 }
4738 }
4739
4740 if (!success) {
4741 close_all_listening_sockets(ctx);
4742 }
4743
4744 return success;
4745 }
4746
4747 static void log_header(const struct mg_connection *conn, const char *header,
4748 FILE *fp) {
4749 const char *header_value;
4750
4751 if ((header_value = mg_get_header(conn, header)) == NULL) {
4752 (void) fprintf(fp, "%s", " -");
4753 } else {
4754 (void) fprintf(fp, " \"%s\"", header_value);
4755 }
4756 }
4757
4758 static void log_access(const struct mg_connection *conn) {
4759 const struct mg_request_info *ri;
4760 FILE *fp;
4761 char date[64], src_addr[IP_ADDR_STR_LEN];
4762
4763 fp = conn->ctx->config[ACCESS_LOG_FILE] == NULL ? NULL :
4764 fopen(conn->ctx->config[ACCESS_LOG_FILE], "a+");
4765
4766 if (fp == NULL)
4767 return;
4768
4769 strftime(date, sizeof(date), "%d/%b/%Y:%H:%M:%S %z",
4770 localtime(&conn->birth_time));
4771
4772 ri = &conn->request_info;
4773 flockfile(fp);
4774
4775 sockaddr_to_string(src_addr, sizeof(src_addr), &conn->client.rsa);
4776 fprintf(fp, "%s - %s [%s] \"%s %s HTTP/%s\" %d %" INT64_FMT,
4777 src_addr, ri->remote_user == NULL ? "-" : ri->remote_user, date,
4778 ri->request_method ? ri->request_method : "-",
4779 ri->uri ? ri->uri : "-", ri->http_version,
4780 conn->status_code, conn->num_bytes_sent);
4781 log_header(conn, "Referer", fp);
4782 log_header(conn, "User-Agent", fp);
4783 fputc('\n', fp);
4784 fflush(fp);
4785
4786 funlockfile(fp);
4787 fclose(fp);
4788 }
4789
4790
4791
4792 static int check_acl(struct mg_context *ctx, uint32_t remote_ip) {
4793 int allowed, flag;
4794 uint32_t net, mask;
4795 struct vec vec;
4796 const char *list = ctx->config[ACCESS_CONTROL_LIST];
4797
4798
4799 allowed = list == NULL ? '+' : '-';
4800
4801 while ((list = next_option(list, &vec, NULL)) != NULL) {
4802 flag = vec.ptr[0];
4803 if ((flag != '+' && flag != '-') ||
4804 parse_net(&vec.ptr[1], &net, &mask) == 0) {
4805 cry(fc(ctx), "%s: subnet must be [+|-]x.x.x.x[/x]", __func__);
4806 return -1;
4807 }
4808
4809 if (net == (remote_ip & mask)) {
4810 allowed = flag;
4811 }
4812 }
4813
4814 return allowed == '+';
4815 }
4816
4817 #if !defined(_WIN32)
4818 static int set_uid_option(struct mg_context *ctx) {
4819 struct passwd *pw;
4820 const char *uid = ctx->config[RUN_AS_USER];
4821 int success = 0;
4822
4823 if (uid == NULL) {
4824 success = 1;
4825 } else {
4826 if ((pw = getpwnam(uid)) == NULL) {
4827 cry(fc(ctx), "%s: unknown user [%s]", __func__, uid);
4828 } else if (setgid(pw->pw_gid) == -1) {
4829 cry(fc(ctx), "%s: setgid(%s): %s", __func__, uid, strerror(errno));
4830 } else if (setuid(pw->pw_uid) == -1) {
4831 cry(fc(ctx), "%s: setuid(%s): %s", __func__, uid, strerror(errno));
4832 } else {
4833 success = 1;
4834 }
4835 }
4836
4837 return success;
4838 }
4839 #endif
4840
4841 #if !defined(NO_SSL)
4842 static pthread_mutex_t *ssl_mutexes;
4843
4844 static int sslize(struct mg_connection *conn, SSL_CTX *s, int (*func)(SSL *)) {
4845 return (conn->ssl = SSL_new(s)) != NULL &&
4846 SSL_set_fd(conn->ssl, conn->client.sock) == 1 &&
4847 func(conn->ssl) == 1;
4848 }
4849
4850
4851 static const char *ssl_error(void) {
4852 unsigned long err;
4853 err = ERR_get_error();
4854 return err == 0 ? "" : ERR_error_string(err, NULL);
4855 }
4856
4857 static void ssl_locking_callback(int mode, int mutex_num, const char *file,
4858 int line) {
4859 (void) line;
4860 (void) file;
4861
4862 if (mode & 1) {
4863 (void) pthread_mutex_lock(&ssl_mutexes[mutex_num]);
4864 } else {
4865 (void) pthread_mutex_unlock(&ssl_mutexes[mutex_num]);
4866 }
4867 }
4868
4869 static unsigned long ssl_id_callback(void) {
4870 return (unsigned long) pthread_self();
4871 }
4872
4873 #if !defined(NO_SSL_DL)
4874 static int load_dll(struct mg_context *ctx, const char *dll_name,
4875 struct ssl_func *sw) {
4876 union {void *p; void (*fp)(void);} u;
4877 void *dll_handle;
4878 struct ssl_func *fp;
4879
4880 if ((dll_handle = dlopen(dll_name, RTLD_LAZY)) == NULL) {
4881 cry(fc(ctx), "%s: cannot load %s", __func__, dll_name);
4882 return 0;
4883 }
4884
4885 for (fp = sw; fp->name != NULL; fp++) {
4886 #ifdef _WIN32
4887
4888 u.fp = (void (*)(void)) dlsym(dll_handle, fp->name);
4889 #else
4890
4891
4892 u.p = dlsym(dll_handle, fp->name);
4893 #endif
4894 if (u.fp == NULL) {
4895 cry(fc(ctx), "%s: %s: cannot find %s", __func__, dll_name, fp->name);
4896 return 0;
4897 } else {
4898 fp->ptr = u.fp;
4899 }
4900 }
4901
4902 return 1;
4903 }
4904 #endif
4905
4906
4907 static int set_ssl_option(struct mg_context *ctx) {
4908 int i, size;
4909 const char *pem;
4910
4911
4912
4913 if ((pem = ctx->config[SSL_CERTIFICATE]) == NULL &&
4914 ctx->callbacks.init_ssl == NULL) {
4915 return 1;
4916 }
4917
4918 #if !defined(NO_SSL_DL)
4919 if (!load_dll(ctx, SSL_LIB, ssl_sw) ||
4920 !load_dll(ctx, CRYPTO_LIB, crypto_sw)) {
4921 return 0;
4922 }
4923 #endif
4924
4925
4926 SSL_library_init();
4927 SSL_load_error_strings();
4928
4929 if ((ctx->ssl_ctx = SSL_CTX_new(SSLv23_server_method())) == NULL) {
4930 cry(fc(ctx), "SSL_CTX_new (server) error: %s", ssl_error());
4931 return 0;
4932 }
4933
4934
4935
4936 if ((ctx->callbacks.init_ssl == NULL ||
4937 !ctx->callbacks.init_ssl(ctx->ssl_ctx, ctx->user_data)) &&
4938 (SSL_CTX_use_certificate_file(ctx->ssl_ctx, pem, 1) == 0 ||
4939 SSL_CTX_use_PrivateKey_file(ctx->ssl_ctx, pem, 1) == 0)) {
4940 cry(fc(ctx), "%s: cannot open %s: %s", __func__, pem, ssl_error());
4941 return 0;
4942 }
4943
4944 if (pem != NULL) {
4945 (void) SSL_CTX_use_certificate_chain_file(ctx->ssl_ctx, pem);
4946 }
4947
4948
4949
4950 size = sizeof(pthread_mutex_t) * CRYPTO_num_locks();
4951 if ((ssl_mutexes = (pthread_mutex_t *) malloc((size_t)size)) == NULL) {
4952 cry(fc(ctx), "%s: cannot allocate mutexes: %s", __func__, ssl_error());
4953 return 0;
4954 }
4955
4956 for (i = 0; i < CRYPTO_num_locks(); i++) {
4957 pthread_mutex_init(&ssl_mutexes[i], NULL);
4958 }
4959
4960 CRYPTO_set_locking_callback(&ssl_locking_callback);
4961 CRYPTO_set_id_callback(&ssl_id_callback);
4962
4963 return 1;
4964 }
4965
4966 static void uninitialize_ssl(struct mg_context *ctx) {
4967 int i;
4968 if (ctx->ssl_ctx != NULL) {
4969 CRYPTO_set_locking_callback(NULL);
4970 for (i = 0; i < CRYPTO_num_locks(); i++) {
4971 pthread_mutex_destroy(&ssl_mutexes[i]);
4972 }
4973 CRYPTO_set_locking_callback(NULL);
4974 CRYPTO_set_id_callback(NULL);
4975 }
4976 }
4977 #endif
4978
4979 static int set_gpass_option(struct mg_context *ctx) {
4980 struct file file = STRUCT_FILE_INITIALIZER;
4981 const char *path = ctx->config[GLOBAL_PASSWORDS_FILE];
4982 if (path != NULL && !mg_stat(fc(ctx), path, &file)) {
4983 cry(fc(ctx), "Cannot open %s: %s", path, strerror(ERRNO));
4984 return 0;
4985 }
4986 return 1;
4987 }
4988
4989 static int set_acl_option(struct mg_context *ctx) {
4990 return check_acl(ctx, (uint32_t) 0x7f000001UL) != -1;
4991 }
4992
4993 static void reset_per_request_attributes(struct mg_connection *conn) {
4994 conn->path_info = NULL;
4995 conn->num_bytes_sent = conn->consumed_content = 0;
4996 conn->status_code = -1;
4997 conn->must_close = conn->request_len = conn->throttle = 0;
4998 }
4999
5000 static void close_socket_gracefully(struct mg_connection *conn) {
5001 #if defined(_WIN32)
5002 char buf[MG_BUF_LEN];
5003 int n;
5004 #endif
5005 struct linger linger;
5006
5007
5008
5009 linger.l_onoff = 1;
5010 linger.l_linger = 1;
5011 setsockopt(conn->client.sock, SOL_SOCKET, SO_LINGER,
5012 (char *) &linger, sizeof(linger));
5013
5014
5015 shutdown(conn->client.sock, SHUT_WR);
5016 set_non_blocking_mode(conn->client.sock);
5017
5018 #if defined(_WIN32)
5019
5020
5021
5022
5023
5024 do {
5025 n = pull(NULL, conn, buf, sizeof(buf));
5026 } while (n > 0);
5027 #endif
5028
5029
5030 closesocket(conn->client.sock);
5031 }
5032
5033 static void close_connection(struct mg_connection *conn) {
5034 conn->must_close = 1;
5035
5036 #ifndef NO_SSL
5037 if (conn->ssl != NULL) {
5038
5039 SSL_shutdown(conn->ssl);
5040 SSL_free(conn->ssl);
5041 conn->ssl = NULL;
5042 }
5043 #endif
5044 if (conn->client.sock != INVALID_SOCKET) {
5045 close_socket_gracefully(conn);
5046 conn->client.sock = INVALID_SOCKET;
5047 }
5048 }
5049
5050 void mg_close_connection(struct mg_connection *conn) {
5051 #ifndef NO_SSL
5052 if (conn->client_ssl_ctx != NULL) {
5053 SSL_CTX_free((SSL_CTX *) conn->client_ssl_ctx);
5054 }
5055 #endif
5056 close_connection(conn);
5057 free(conn);
5058 }
5059
5060 static struct mg_connection *mg_connect(const char *host, int port, int use_ssl,
5061 char *ebuf, size_t ebuf_len) {
5062 static struct mg_context fake_ctx;
5063 struct mg_connection *conn = NULL;
5064 SOCKET sock;
5065
5066 if ((sock = conn2(host, port, use_ssl, ebuf, ebuf_len)) == INVALID_SOCKET) {
5067 } else if ((conn = (struct mg_connection *)
5068 calloc(1, sizeof(*conn) + MAX_REQUEST_SIZE)) == NULL) {
5069 snprintf(ebuf, ebuf_len, "calloc(): %s", strerror(ERRNO));
5070 closesocket(sock);
5071 #ifndef NO_SSL
5072 } else if (use_ssl && (conn->client_ssl_ctx =
5073 SSL_CTX_new(SSLv23_client_method())) == NULL) {
5074 snprintf(ebuf, ebuf_len, "SSL_CTX_new error");
5075 closesocket(sock);
5076 free(conn);
5077 conn = NULL;
5078 #endif
5079 } else {
5080 socklen_t len = sizeof(struct sockaddr);
5081 conn->buf_size = MAX_REQUEST_SIZE;
5082 conn->buf = (char *) (conn + 1);
5083 conn->ctx = &fake_ctx;
5084 conn->client.sock = sock;
5085 getsockname(sock, &conn->client.rsa.sa, &len);
5086 conn->client.is_ssl = use_ssl;
5087 #ifndef NO_SSL
5088 if (use_ssl) {
5089
5090
5091 SSL_CTX_set_verify(conn->client_ssl_ctx, 0, 0);
5092 sslize(conn, conn->client_ssl_ctx, SSL_connect);
5093 }
5094 #endif
5095 }
5096
5097 return conn;
5098 }
5099
5100 static int is_valid_uri(const char *uri) {
5101
5102
5103 return uri[0] == '/' || (uri[0] == '*' && uri[1] == '\0');
5104 }
5105
5106 static int getreq(struct mg_connection *conn, char *ebuf, size_t ebuf_len) {
5107 const char *cl;
5108
5109 ebuf[0] = '\0';
5110 reset_per_request_attributes(conn);
5111 conn->request_len = read_request(NULL, conn, conn->buf, conn->buf_size,
5112 &conn->data_len);
5113 assert(conn->request_len < 0 || conn->data_len >= conn->request_len);
5114
5115 if (conn->request_len == 0 && conn->data_len == conn->buf_size) {
5116 snprintf(ebuf, ebuf_len, "%s", "Request Too Large");
5117 } else if (conn->request_len <= 0) {
5118 snprintf(ebuf, ebuf_len, "%s", "Client closed connection");
5119 } else if (parse_http_message(conn->buf, conn->buf_size,
5120 &conn->request_info) <= 0) {
5121 snprintf(ebuf, ebuf_len, "Bad request: [%.*s]", conn->data_len, conn->buf);
5122 } else {
5123
5124 if ((cl = get_header(&conn->request_info, "Content-Length")) != NULL) {
5125 conn->content_len = strtoll(cl, NULL, 10);
5126 } else if (!mg_strcasecmp(conn->request_info.request_method, "POST") ||
5127 !mg_strcasecmp(conn->request_info.request_method, "PUT")) {
5128 conn->content_len = -1;
5129 } else {
5130 conn->content_len = 0;
5131 }
5132 conn->birth_time = time(NULL);
5133 }
5134 return ebuf[0] == '\0';
5135 }
5136
5137 struct mg_connection *mg_download(const char *host, int port, int use_ssl,
5138 char *ebuf, size_t ebuf_len,
5139 const char *fmt, ...) {
5140 struct mg_connection *conn;
5141 va_list ap;
5142
5143 va_start(ap, fmt);
5144 ebuf[0] = '\0';
5145 if ((conn = mg_connect(host, port, use_ssl, ebuf, ebuf_len)) == NULL) {
5146 } else if (mg_vprintf(conn, fmt, ap) <= 0) {
5147 snprintf(ebuf, ebuf_len, "%s", "Error sending request");
5148 } else {
5149 getreq(conn, ebuf, ebuf_len);
5150 }
5151 if (ebuf[0] != '\0' && conn != NULL) {
5152 mg_close_connection(conn);
5153 conn = NULL;
5154 }
5155
5156 return conn;
5157 }
5158
5159 static void process_new_connection(struct mg_connection *conn) {
5160 struct mg_request_info *ri = &conn->request_info;
5161 int keep_alive_enabled, keep_alive, discard_len;
5162 char ebuf[100];
5163
5164 keep_alive_enabled = !strcmp(conn->ctx->config[ENABLE_KEEP_ALIVE], "yes");
5165 keep_alive = 0;
5166
5167
5168
5169 conn->data_len = 0;
5170 do {
5171 if (!getreq(conn, ebuf, sizeof(ebuf))) {
5172 send_http_error(conn, 500, "Server Error", "%s", ebuf);
5173 conn->must_close = 1;
5174 } else if (!is_valid_uri(conn->request_info.uri)) {
5175 snprintf(ebuf, sizeof(ebuf), "Invalid URI: [%s]", ri->uri);
5176 send_http_error(conn, 400, "Bad Request", "%s", ebuf);
5177 } else if (strcmp(ri->http_version, "1.0") &&
5178 strcmp(ri->http_version, "1.1")) {
5179 snprintf(ebuf, sizeof(ebuf), "Bad HTTP version: [%s]", ri->http_version);
5180 send_http_error(conn, 505, "Bad HTTP version", "%s", ebuf);
5181 }
5182
5183 if (ebuf[0] == '\0') {
5184 handle_request(conn);
5185 if (conn->ctx->callbacks.end_request != NULL) {
5186 conn->ctx->callbacks.end_request(conn, conn->status_code);
5187 }
5188 log_access(conn);
5189 }
5190 if (ri->remote_user != NULL) {
5191 free((void *) ri->remote_user);
5192
5193
5194 ri->remote_user = NULL;
5195 }
5196
5197
5198
5199
5200
5201 keep_alive = conn->ctx->stop_flag == 0 && keep_alive_enabled &&
5202 conn->content_len >= 0 && should_keep_alive(conn);
5203
5204
5205 discard_len = conn->content_len >= 0 && conn->request_len > 0 &&
5206 conn->request_len + conn->content_len < (int64_t) conn->data_len ?
5207 (int) (conn->request_len + conn->content_len) : conn->data_len;
5208 assert(discard_len >= 0);
5209 memmove(conn->buf, conn->buf + discard_len, conn->data_len - discard_len);
5210 conn->data_len -= discard_len;
5211 assert(conn->data_len >= 0);
5212 assert(conn->data_len <= conn->buf_size);
5213 } while (keep_alive);
5214 }
5215
5216
5217 static int consume_socket(struct mg_context *ctx, struct socket *sp) {
5218 (void) pthread_mutex_lock(&ctx->mutex);
5219 DEBUG_TRACE(("going idle"));
5220
5221
5222 while (ctx->sq_head == ctx->sq_tail && ctx->stop_flag == 0) {
5223 pthread_cond_wait(&ctx->sq_full, &ctx->mutex);
5224 }
5225
5226
5227 if (ctx->sq_head > ctx->sq_tail) {
5228
5229 *sp = ctx->queue[ctx->sq_tail % ARRAY_SIZE(ctx->queue)];
5230 ctx->sq_tail++;
5231 DEBUG_TRACE(("grabbed socket %d, going busy", sp->sock));
5232
5233
5234 while (ctx->sq_tail > (int) ARRAY_SIZE(ctx->queue)) {
5235 ctx->sq_tail -= ARRAY_SIZE(ctx->queue);
5236 ctx->sq_head -= ARRAY_SIZE(ctx->queue);
5237 }
5238 }
5239
5240 (void) pthread_cond_signal(&ctx->sq_empty);
5241 (void) pthread_mutex_unlock(&ctx->mutex);
5242
5243 return !ctx->stop_flag;
5244 }
5245
5246 static void *worker_thread(void *thread_func_param) {
5247 struct mg_context *ctx = (struct mg_context *) thread_func_param;
5248 struct mg_connection *conn;
5249
5250 conn = (struct mg_connection *) calloc(1, sizeof(*conn) + MAX_REQUEST_SIZE);
5251 if (conn == NULL) {
5252 cry(fc(ctx), "%s", "Cannot create new connection struct, OOM");
5253 } else {
5254 conn->buf_size = MAX_REQUEST_SIZE;
5255 conn->buf = (char *) (conn + 1);
5256 conn->ctx = ctx;
5257 conn->request_info.user_data = ctx->user_data;
5258
5259
5260
5261 while (consume_socket(ctx, &conn->client)) {
5262 conn->birth_time = time(NULL);
5263
5264
5265
5266
5267
5268 conn->request_info.remote_port = ntohs(conn->client.rsa.sin.sin_port);
5269 memcpy(&conn->request_info.remote_ip,
5270 &conn->client.rsa.sin.sin_addr.s_addr, 4);
5271 conn->request_info.remote_ip = ntohl(conn->request_info.remote_ip);
5272 conn->request_info.is_ssl = conn->client.is_ssl;
5273
5274 if (!conn->client.is_ssl
5275 #ifndef NO_SSL
5276 || sslize(conn, conn->ctx->ssl_ctx, SSL_accept)
5277 #endif
5278 ) {
5279 process_new_connection(conn);
5280 }
5281
5282 close_connection(conn);
5283 }
5284 free(conn);
5285 }
5286
5287
5288 (void) pthread_mutex_lock(&ctx->mutex);
5289 ctx->num_threads--;
5290 (void) pthread_cond_signal(&ctx->cond);
5291 assert(ctx->num_threads >= 0);
5292 (void) pthread_mutex_unlock(&ctx->mutex);
5293
5294 DEBUG_TRACE(("exiting"));
5295 return NULL;
5296 }
5297
5298
5299 static void produce_socket(struct mg_context *ctx, const struct socket *sp) {
5300 (void) pthread_mutex_lock(&ctx->mutex);
5301
5302
5303 while (ctx->stop_flag == 0 &&
5304 ctx->sq_head - ctx->sq_tail >= (int) ARRAY_SIZE(ctx->queue)) {
5305 (void) pthread_cond_wait(&ctx->sq_empty, &ctx->mutex);
5306 }
5307
5308 if (ctx->sq_head - ctx->sq_tail < (int) ARRAY_SIZE(ctx->queue)) {
5309
5310 ctx->queue[ctx->sq_head % ARRAY_SIZE(ctx->queue)] = *sp;
5311 ctx->sq_head++;
5312 DEBUG_TRACE(("queued socket %d", sp->sock));
5313 }
5314
5315 (void) pthread_cond_signal(&ctx->sq_full);
5316 (void) pthread_mutex_unlock(&ctx->mutex);
5317 }
5318
5319 static int set_sock_timeout(SOCKET sock, int milliseconds) {
5320 #ifdef _WIN32
5321 DWORD t = milliseconds;
5322 #else
5323 struct timeval t;
5324 t.tv_sec = milliseconds / 1000;
5325 t.tv_usec = (milliseconds * 1000) % 1000000;
5326 #endif
5327 return setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (void *) &t, sizeof(t)) ||
5328 setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, (void *) &t, sizeof(t));
5329 }
5330
5331 static void accept_new_connection(const struct socket *listener,
5332 struct mg_context *ctx) {
5333 struct socket so;
5334 char src_addr[IP_ADDR_STR_LEN];
5335 socklen_t len = sizeof(so.rsa);
5336 int on = 1;
5337
5338 if ((so.sock = accept(listener->sock, &so.rsa.sa, &len)) == INVALID_SOCKET) {
5339 } else if (!check_acl(ctx, ntohl(* (uint32_t *) &so.rsa.sin.sin_addr))) {
5340 sockaddr_to_string(src_addr, sizeof(src_addr), &so.rsa);
5341 cry(fc(ctx), "%s: %s is not allowed to connect", __func__, src_addr);
5342 closesocket(so.sock);
5343 } else {
5344
5345 DEBUG_TRACE(("Accepted socket %d", (int) so.sock));
5346 set_close_on_exec(so.sock);
5347 so.is_ssl = listener->is_ssl;
5348 so.ssl_redir = listener->ssl_redir;
5349 getsockname(so.sock, &so.lsa.sa, &len);
5350
5351
5352
5353
5354
5355
5356 setsockopt(so.sock, SOL_SOCKET, SO_KEEPALIVE, (void *) &on, sizeof(on));
5357 set_sock_timeout(so.sock, atoi(ctx->config[REQUEST_TIMEOUT]));
5358 produce_socket(ctx, &so);
5359 }
5360 }
5361
5362 static void *master_thread(void *thread_func_param) {
5363 struct mg_context *ctx = (struct mg_context *) thread_func_param;
5364 struct pollfd *pfd;
5365 int i;
5366
5367
5368 #if defined(_WIN32)
5369 SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_ABOVE_NORMAL);
5370 #endif
5371
5372 #if defined(ISSUE_317)
5373 struct sched_param sched_param;
5374 sched_param.sched_priority = sched_get_priority_max(SCHED_RR);
5375 pthread_setschedparam(pthread_self(), SCHED_RR, &sched_param);
5376 #endif
5377
5378 pfd = (struct pollfd *) calloc(ctx->num_listening_sockets, sizeof(pfd[0]));
5379 while (pfd != NULL && ctx->stop_flag == 0) {
5380 for (i = 0; i < ctx->num_listening_sockets; i++) {
5381 pfd[i].fd = ctx->listening_sockets[i].sock;
5382 pfd[i].events = POLLIN;
5383 }
5384
5385 if (poll(pfd, ctx->num_listening_sockets, 200) > 0) {
5386 for (i = 0; i < ctx->num_listening_sockets; i++) {
5387
5388
5389
5390
5391 if (ctx->stop_flag == 0 && (pfd[i].revents & POLLIN)) {
5392 accept_new_connection(&ctx->listening_sockets[i], ctx);
5393 }
5394 }
5395 }
5396 #if __rtems__
5397 else {
5398 struct timespec t = { .tv_sec = 0, .tv_nsec = 500000000L };
5399 nanosleep(&t, &t);
5400 }
5401 #endif
5402 }
5403 free(pfd);
5404 DEBUG_TRACE(("stopping workers"));
5405
5406
5407 close_all_listening_sockets(ctx);
5408
5409
5410 pthread_cond_broadcast(&ctx->sq_full);
5411
5412
5413 (void) pthread_mutex_lock(&ctx->mutex);
5414 while (ctx->num_threads > 0) {
5415 (void) pthread_cond_wait(&ctx->cond, &ctx->mutex);
5416 }
5417 (void) pthread_mutex_unlock(&ctx->mutex);
5418
5419
5420 (void) pthread_mutex_destroy(&ctx->mutex);
5421 (void) pthread_cond_destroy(&ctx->cond);
5422 (void) pthread_cond_destroy(&ctx->sq_empty);
5423 (void) pthread_cond_destroy(&ctx->sq_full);
5424
5425 #if !defined(NO_SSL)
5426 uninitialize_ssl(ctx);
5427 #endif
5428 DEBUG_TRACE(("exiting"));
5429
5430
5431
5432
5433 ctx->stop_flag = 2;
5434 return NULL;
5435 }
5436
5437 static void free_context(struct mg_context *ctx) {
5438 int i;
5439
5440
5441 for (i = 0; i < NUM_OPTIONS; i++) {
5442 if (ctx->config[i] != NULL)
5443 free(ctx->config[i]);
5444 }
5445
5446 #ifndef NO_SSL
5447
5448 if (ctx->ssl_ctx != NULL) {
5449 SSL_CTX_free(ctx->ssl_ctx);
5450 }
5451 if (ssl_mutexes != NULL) {
5452 free(ssl_mutexes);
5453 ssl_mutexes = NULL;
5454 }
5455 #endif
5456
5457
5458 free(ctx);
5459 }
5460
5461 void mg_stop(struct mg_context *ctx) {
5462 ctx->stop_flag = 1;
5463
5464
5465 while (ctx->stop_flag != 2) {
5466 (void) mg_sleep(10);
5467 }
5468 free_context(ctx);
5469
5470 #if defined(_WIN32) && !defined(__SYMBIAN32__)
5471 (void) WSACleanup();
5472 #endif
5473 }
5474
5475 struct mg_context *mg_start(const struct mg_callbacks *callbacks,
5476 void *user_data,
5477 const char **options) {
5478 struct mg_context *ctx;
5479 const char *name, *value, *default_value;
5480 int i;
5481
5482 #if defined(_WIN32) && !defined(__SYMBIAN32__)
5483 WSADATA data;
5484 WSAStartup(MAKEWORD(2,2), &data);
5485 InitializeCriticalSection(&global_log_file_lock);
5486 #endif
5487
5488
5489
5490 if ((ctx = (struct mg_context *) calloc(1, sizeof(*ctx))) == NULL) {
5491 return NULL;
5492 }
5493 ctx->callbacks = *callbacks;
5494 ctx->user_data = user_data;
5495
5496 while (options && (name = *options++) != NULL) {
5497 if ((i = get_option_index(name)) == -1) {
5498 cry(fc(ctx), "Invalid option: %s", name);
5499 free_context(ctx);
5500 return NULL;
5501 } else if ((value = *options++) == NULL) {
5502 cry(fc(ctx), "%s: option value cannot be NULL", name);
5503 free_context(ctx);
5504 return NULL;
5505 }
5506 if (ctx->config[i] != NULL) {
5507 cry(fc(ctx), "warning: %s: duplicate option", name);
5508 free(ctx->config[i]);
5509 }
5510 ctx->config[i] = mg_strdup(value);
5511 DEBUG_TRACE(("[%s] -> [%s]", name, value));
5512 }
5513
5514
5515 for (i = 0; config_options[i * 2] != NULL; i++) {
5516 default_value = config_options[i * 2 + 1];
5517 if (ctx->config[i] == NULL && default_value != NULL) {
5518 ctx->config[i] = mg_strdup(default_value);
5519 }
5520 }
5521
5522
5523
5524 if (!set_gpass_option(ctx) ||
5525 #if !defined(NO_SSL)
5526 !set_ssl_option(ctx) ||
5527 #endif
5528 !set_ports_option(ctx) ||
5529 #if !defined(_WIN32)
5530 !set_uid_option(ctx) ||
5531 #endif
5532 !set_acl_option(ctx)) {
5533 free_context(ctx);
5534 return NULL;
5535 }
5536
5537 #if !defined(_WIN32) && !defined(__SYMBIAN32__)
5538
5539
5540 (void) signal(SIGPIPE, SIG_IGN);
5541
5542 (void) signal(SIGCHLD, SIG_IGN);
5543 #endif
5544
5545 (void) pthread_mutex_init(&ctx->mutex, NULL);
5546 (void) pthread_cond_init(&ctx->cond, NULL);
5547 (void) pthread_cond_init(&ctx->sq_empty, NULL);
5548 (void) pthread_cond_init(&ctx->sq_full, NULL);
5549
5550
5551 mg_start_thread(master_thread, ctx);
5552
5553
5554 for (i = 0; i < atoi(ctx->config[NUM_THREADS]); i++) {
5555 if (mg_start_thread(worker_thread, ctx) != 0) {
5556 cry(fc(ctx), "Cannot start worker thread: %ld", (long) ERRNO);
5557 } else {
5558 ctx->num_threads++;
5559 }
5560 }
5561
5562 return ctx;
5563 }
5564 #ifdef __rtems__
5565 #include <rtems/printer.h>
5566
5567 static int mg_printer_plugin(void *context, const char *fmt, va_list ap) {
5568 return mg_vprintf(context, fmt, ap);
5569 }
5570
5571 void rtems_print_printer_mg_printf(rtems_printer *printer, struct mg_connection *conn) {
5572 printer->context = conn;
5573 printer->printer = mg_printer_plugin;
5574 }
5575 #endif