// Copyright (c) 2004-2013 Sergey Lyubka // Copyright (c) 2013 Cesanta Software Limited // All rights reserved // // This library is dual-licensed: you can redistribute it and/or modify // it under the terms of the GNU General Public License version 2 as // published by the Free Software Foundation. For the terms of this // license, see . // // You are free to use this library under the terms of the GNU General // Public License, but WITHOUT ANY WARRANTY; without even the implied // warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. // See the GNU General Public License for more details. // // Alternatively, you can license this library under a commercial // license, as set out in . #if defined(_WIN32) #undef _UNICODE #define _MBCS #if !defined(_CRT_SECURE_NO_WARNINGS) #define _CRT_SECURE_NO_WARNINGS // Disable deprecation warning in VS2005 #endif #else #ifdef __linux__ #define _XOPEN_SOURCE 600 // For flockfile() on Linux #endif #if !defined(_LARGEFILE_SOURCE) #define _LARGEFILE_SOURCE // Enable 64-bit file offsets #endif #define __STDC_FORMAT_MACROS // wants this for C++ #define __STDC_LIMIT_MACROS // C++ wants that for INT64_MAX #endif #if defined (_MSC_VER) // conditional expression is constant: introduced by FD_SET(..) #pragma warning (disable : 4127) // non-constant aggregate initializer: issued due to missing C99 support #pragma warning (disable : 4204) #endif // Disable WIN32_LEAN_AND_MEAN. // This makes windows.h always include winsock2.h #ifdef WIN32_LEAN_AND_MEAN #undef WIN32_LEAN_AND_MEAN #endif #if defined(__SYMBIAN32__) #define NO_SSL // SSL is not supported #define NO_CGI // CGI is not supported #define PATH_MAX FILENAME_MAX #endif // __SYMBIAN32__ #ifndef _WIN32_WCE // Some ANSI #includes are not available on Windows CE #include #include #include #include #include #endif // !_WIN32_WCE #include #include #include #include #include #include #include #include #include #if defined(_WIN32) && !defined(__SYMBIAN32__) // Windows specific #undef _WIN32_WINNT #define _WIN32_WINNT 0x0400 // To make it link in VS2005 #include #ifndef PATH_MAX #define PATH_MAX MAX_PATH #endif #ifndef _WIN32_WCE #include #include #include #else // _WIN32_WCE #define NO_CGI // WinCE has no pipes typedef long off_t; #define errno GetLastError() #define strerror(x) _ultoa(x, (char *) _alloca(sizeof(x) *3 ), 10) #endif // _WIN32_WCE #define MAKEUQUAD(lo, hi) ((uint64_t)(((uint32_t)(lo)) | \ ((uint64_t)((uint32_t)(hi))) << 32)) #define RATE_DIFF 10000000 // 100 nsecs #define EPOCH_DIFF MAKEUQUAD(0xd53e8000, 0x019db1de) #define SYS2UNIX_TIME(lo, hi) \ (time_t) ((MAKEUQUAD((lo), (hi)) - EPOCH_DIFF) / RATE_DIFF) // Visual Studio 6 does not know __func__ or __FUNCTION__ // The rest of MS compilers use __FUNCTION__, not C99 __func__ // Also use _strtoui64 on modern M$ compilers #if defined(_MSC_VER) && _MSC_VER < 1300 #define STRX(x) #x #define STR(x) STRX(x) #define __func__ __FILE__ ":" STR(__LINE__) #define strtoull(x, y, z) (unsigned __int64) _atoi64(x) #define strtoll(x, y, z) _atoi64(x) #else #define __func__ __FUNCTION__ #define strtoull(x, y, z) _strtoui64(x, y, z) #define strtoll(x, y, z) _strtoi64(x, y, z) #endif // _MSC_VER #define ERRNO GetLastError() #define NO_SOCKLEN_T #define SSL_LIB "ssleay32.dll" #define CRYPTO_LIB "libeay32.dll" #define O_NONBLOCK 0 #if !defined(EWOULDBLOCK) #define EWOULDBLOCK WSAEWOULDBLOCK #endif // !EWOULDBLOCK #define _POSIX_ #define INT64_FMT "I64d" #define WINCDECL __cdecl #define SHUT_WR 1 #define snprintf _snprintf #define vsnprintf _vsnprintf #define mg_sleep(x) Sleep(x) #define pipe(x) _pipe(x, MG_BUF_LEN, _O_BINARY) #ifndef popen #define popen(x, y) _popen(x, y) #endif #ifndef pclose #define pclose(x) _pclose(x) #endif #define close(x) _close(x) #define dlsym(x,y) GetProcAddress((HINSTANCE) (x), (y)) #define RTLD_LAZY 0 #define fseeko(x, y, z) _lseeki64(_fileno(x), (y), (z)) #define fdopen(x, y) _fdopen((x), (y)) #define write(x, y, z) _write((x), (y), (unsigned) z) #define read(x, y, z) _read((x), (y), (unsigned) z) #define flockfile(x) #define funlockfile(x) #define sleep(x) Sleep((x) * 1000) #define rmdir(x) _rmdir(x) #if !defined(va_copy) #define va_copy(x, y) x = y #endif // !va_copy MINGW #defines va_copy #if !defined(fileno) #define fileno(x) _fileno(x) #endif // !fileno MINGW #defines fileno typedef HANDLE pthread_mutex_t; typedef struct {HANDLE signal, broadcast;} pthread_cond_t; typedef DWORD pthread_t; #define pid_t HANDLE // MINGW typedefs pid_t to int. Using #define here. static int pthread_mutex_lock(pthread_mutex_t *); static int pthread_mutex_unlock(pthread_mutex_t *); static void to_unicode(const char *path, wchar_t *wbuf, size_t wbuf_len); #if defined(HAVE_STDINT) #include #else typedef unsigned int uint32_t; typedef unsigned short uint16_t; typedef unsigned __int64 uint64_t; typedef __int64 int64_t; #define INT64_MAX 9223372036854775807 #endif // HAVE_STDINT // POSIX dirent interface struct dirent { char d_name[PATH_MAX]; }; typedef struct DIR { HANDLE handle; WIN32_FIND_DATAW info; struct dirent result; } DIR; struct pollfd { SOCKET fd; short events; short revents; }; #define POLLIN 1 #ifdef HAVE_POLL #define poll(x, y, z) WSAPoll((x), (y), (z)) #endif // Mark required libraries #ifdef _MSC_VER #pragma comment(lib, "Ws2_32.lib") #endif #else // UNIX specific #include #include #include #include #include #include #include #include #include #include #include #include #if !defined(NO_SSL_DL) && !defined(NO_SSL) #include #endif #include #if defined(__MACH__) #define SSL_LIB "libssl.dylib" #define CRYPTO_LIB "libcrypto.dylib" #else #if !defined(SSL_LIB) #define SSL_LIB "libssl.so" #endif #if !defined(CRYPTO_LIB) #define CRYPTO_LIB "libcrypto.so" #endif #endif #ifndef O_BINARY #define O_BINARY 0 #endif // O_BINARY #define closesocket(a) close(a) #define mg_mkdir(x, y) mkdir(x, y) #define mg_remove(x) remove(x) #define mg_sleep(x) usleep((x) * 1000) #define ERRNO errno #define INVALID_SOCKET (-1) #define INT64_FMT PRId64 typedef int SOCKET; #define WINCDECL #endif // End of Windows and UNIX specific includes #include "mongoose.h" #define MONGOOSE_VERSION "4.2" #define PASSWORDS_FILE_NAME ".htpasswd" #define CGI_ENVIRONMENT_SIZE 4096 #define MAX_CGI_ENVIR_VARS 64 #define MG_BUF_LEN 8192 #define MAX_REQUEST_SIZE 16384 #define ARRAY_SIZE(array) (sizeof(array) / sizeof(array[0])) #ifdef DEBUG_TRACE #undef DEBUG_TRACE #define DEBUG_TRACE(x) #else #if defined(DEBUG) #define DEBUG_TRACE(x) do { \ flockfile(stdout); \ printf("*** %lu.%p.%s.%d: ", \ (unsigned long) time(NULL), (void *) pthread_self(), \ __func__, __LINE__); \ printf x; \ putchar('\n'); \ fflush(stdout); \ funlockfile(stdout); \ } while (0) #else #define DEBUG_TRACE(x) #endif // DEBUG #endif // DEBUG_TRACE // Darwin prior to 7.0 and Win32 do not have socklen_t #ifdef NO_SOCKLEN_T typedef int socklen_t; #endif // NO_SOCKLEN_T #define _DARWIN_UNLIMITED_SELECT #define IP_ADDR_STR_LEN 50 // IPv6 hex string is 46 chars #if !defined(MSG_NOSIGNAL) #define MSG_NOSIGNAL 0 #endif #if !defined(SOMAXCONN) #define SOMAXCONN 100 #endif #if !defined(PATH_MAX) #define PATH_MAX 4096 #endif // Size of the accepted socket queue #if !defined(MGSQLEN) #define MGSQLEN 20 #endif // Extra HTTP headers to send in every static file reply #if !defined(EXTRA_HTTP_HEADERS) #define EXTRA_HTTP_HEADERS "" #endif static const char *http_500_error = "Internal Server Error"; #if defined(NO_SSL_DL) #include #include #else // SSL loaded dynamically from DLL. // I put the prototypes here to be independent from OpenSSL source installation. typedef struct ssl_st SSL; typedef struct ssl_method_st SSL_METHOD; typedef struct ssl_ctx_st SSL_CTX; struct ssl_func { const char *name; // SSL function name void (*ptr)(void); // Function pointer }; #define SSL_free (* (void (*)(SSL *)) ssl_sw[0].ptr) #define SSL_accept (* (int (*)(SSL *)) ssl_sw[1].ptr) #define SSL_connect (* (int (*)(SSL *)) ssl_sw[2].ptr) #define SSL_read (* (int (*)(SSL *, void *, int)) ssl_sw[3].ptr) #define SSL_write (* (int (*)(SSL *, const void *,int)) ssl_sw[4].ptr) #define SSL_get_error (* (int (*)(SSL *, int)) ssl_sw[5].ptr) #define SSL_set_fd (* (int (*)(SSL *, SOCKET)) ssl_sw[6].ptr) #define SSL_new (* (SSL * (*)(SSL_CTX *)) ssl_sw[7].ptr) #define SSL_CTX_new (* (SSL_CTX * (*)(SSL_METHOD *)) ssl_sw[8].ptr) #define SSLv23_server_method (* (SSL_METHOD * (*)(void)) ssl_sw[9].ptr) #define SSL_library_init (* (int (*)(void)) ssl_sw[10].ptr) #define SSL_CTX_use_PrivateKey_file (* (int (*)(SSL_CTX *, \ const char *, int)) ssl_sw[11].ptr) #define SSL_CTX_use_certificate_file (* (int (*)(SSL_CTX *, \ const char *, int)) ssl_sw[12].ptr) #define SSL_CTX_set_default_passwd_cb \ (* (void (*)(SSL_CTX *, mg_event_handler_t)) ssl_sw[13].ptr) #define SSL_CTX_free (* (void (*)(SSL_CTX *)) ssl_sw[14].ptr) #define SSL_load_error_strings (* (void (*)(void)) ssl_sw[15].ptr) #define SSL_CTX_use_certificate_chain_file \ (* (int (*)(SSL_CTX *, const char *)) ssl_sw[16].ptr) #define SSLv23_client_method (* (SSL_METHOD * (*)(void)) ssl_sw[17].ptr) #define SSL_pending (* (int (*)(SSL *)) ssl_sw[18].ptr) #define SSL_CTX_set_verify (* (void (*)(SSL_CTX *, int, int)) ssl_sw[19].ptr) #define SSL_shutdown (* (int (*)(SSL *)) ssl_sw[20].ptr) #define CRYPTO_num_locks (* (int (*)(void)) crypto_sw[0].ptr) #define CRYPTO_set_locking_callback \ (* (void (*)(void (*)(int, int, const char *, int))) crypto_sw[1].ptr) #define CRYPTO_set_id_callback \ (* (void (*)(unsigned long (*)(void))) crypto_sw[2].ptr) #define ERR_get_error (* (unsigned long (*)(void)) crypto_sw[3].ptr) #define ERR_error_string (* (char * (*)(unsigned long,char *)) crypto_sw[4].ptr) #endif // NO_SSL_DL // Unified socket address. For IPv6 support, add IPv6 address structure // in the union u. union usa { struct sockaddr sa; struct sockaddr_in sin; #if defined(USE_IPV6) struct sockaddr_in6 sin6; #endif }; // Describes a string (chunk of memory). struct vec { const char *ptr; size_t len; }; struct file { int is_directory; time_t modification_time; int64_t size; // set to 1 if the content is gzipped // in which case we need a content-encoding: gzip header int gzipped; }; #define STRUCT_FILE_INITIALIZER { 0, 0, 0, 0 } // Describes listening socket, or socket which was accept()-ed by the master // thread and queued for future handling by the worker thread. struct socket { SOCKET sock; // Listening socket union usa lsa; // Local socket address union usa rsa; // Remote socket address unsigned is_ssl:1; // Is port SSL-ed unsigned ssl_redir:1; // Is port supposed to redirect everything to SSL port }; // NOTE(lsm): this enum shoulds be in sync with the config_options. enum { CGI_EXTENSIONS, CGI_ENVIRONMENT, PUT_DELETE_PASSWORDS_FILE, CGI_INTERPRETER, PROTECT_URI, AUTHENTICATION_DOMAIN, SSI_EXTENSIONS, ACCESS_LOG_FILE, ENABLE_DIRECTORY_LISTING, ERROR_LOG_FILE, GLOBAL_PASSWORDS_FILE, INDEX_FILES, ENABLE_KEEP_ALIVE, ACCESS_CONTROL_LIST, EXTRA_MIME_TYPES, LISTENING_PORTS, DOCUMENT_ROOT, SSL_CERTIFICATE, NUM_THREADS, RUN_AS_USER, REWRITE, HIDE_FILES, REQUEST_TIMEOUT, NUM_OPTIONS }; struct mg_context { volatile int stop_flag; // Should we stop event loop SSL_CTX *ssl_ctx; // SSL context char *config[NUM_OPTIONS]; // Mongoose configuration parameters mg_event_handler_t event_handler; // User-defined callback function void *user_data; // User-defined data struct socket *listening_sockets; int num_listening_sockets; volatile int num_threads; // Number of threads pthread_mutex_t mutex; // Protects (max|num)_threads pthread_cond_t cond; // Condvar for tracking workers terminations struct socket queue[MGSQLEN]; // Accepted sockets volatile int sq_head; // Head of the socket queue volatile int sq_tail; // Tail of the socket queue pthread_cond_t sq_full; // Signaled when socket is produced pthread_cond_t sq_empty; // Signaled when socket is consumed }; struct mg_connection { struct mg_request_info request_info; struct mg_event event; struct mg_context *ctx; SSL *ssl; // SSL descriptor SSL_CTX *client_ssl_ctx; // SSL context for client connections struct socket client; // Connected client time_t birth_time; // Time when request was received int64_t num_bytes_sent; // Total bytes sent to client int64_t content_len; // Content-Length header value int64_t num_bytes_read; // Bytes read from a remote socket char *buf; // Buffer for received data char *path_info; // PATH_INFO part of the URL int must_close; // 1 if connection must be closed int buf_size; // Buffer size int request_len; // Size of the request + headers in a buffer int data_len; // Total size of data in a buffer int status_code; // HTTP reply status code, e.g. 200 }; // Directory entry struct de { struct mg_connection *conn; char *file_name; struct file file; }; static FILE *mg_fopen(const char *path, const char *mode); static int mg_stat(const char *path, struct file *filep); static void send_http_error(struct mg_connection *, int, const char *, PRINTF_FORMAT_STRING(const char *fmt), ...) PRINTF_ARGS(4, 5); static void cry(struct mg_connection *conn, PRINTF_FORMAT_STRING(const char *fmt), ...) PRINTF_ARGS(2, 3); static int getreq(struct mg_connection *conn, char *ebuf, size_t ebuf_len); #ifdef USE_LUA #include "lua_5.2.1.h" static int handle_lsp_request(struct mg_connection *, const char *, struct file *, struct lua_State *); #endif