/rsync/mongoose.c
https://github.com/AnupBansod/SS-Rsync · C · 5457 lines · 4233 code · 730 blank · 494 comment · 1272 complexity · 75b437de0ac5dd9b6bfe890035dd3fff MD5 · raw file
Large files are truncated click here to view the full file
- // Copyright (c) 2004-2013 Sergey Lyubka
- //
- // Permission is hereby granted, free of charge, to any person obtaining a copy
- // of this software and associated documentation files (the "Software"), to deal
- // in the Software without restriction, including without limitation the rights
- // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- // copies of the Software, and to permit persons to whom the Software is
- // furnished to do so, subject to the following conditions:
- //
- // The above copyright notice and this permission notice shall be included in
- // all copies or substantial portions of the Software.
- //
- // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- // THE SOFTWARE.
-
- #if defined(_WIN32)
- #define _CRT_SECURE_NO_WARNINGS // Disable deprecation warning in VS2005
- #else
- #ifdef __linux__
- #define _XOPEN_SOURCE 600 // For flockfile() on Linux
- #endif
- #define _LARGEFILE_SOURCE // Enable 64-bit file offsets
- #define __STDC_FORMAT_MACROS // <inttypes.h> 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 <sys/types.h>
- #include <sys/stat.h>
- #include <errno.h>
- #include <signal.h>
- #include <fcntl.h>
- #endif // !_WIN32_WCE
-
- #include <time.h>
- #include <stdlib.h>
- #include <stdarg.h>
- #include <assert.h>
- #include <string.h>
- #include <ctype.h>
- #include <limits.h>
- #include <stddef.h>
- #include <stdio.h>
- #include <sys/ioctl.h>
- int mg_in;
- int mg_out;
-
-
- #if defined(_WIN32) && !defined(__SYMBIAN32__) // Windows specific
- #define _WIN32_WINNT 0x0400 // To make it link in VS2005
- #include <windows.h>
-
- #ifndef PATH_MAX
- #define PATH_MAX MAX_PATH
- #endif
-
- #ifndef _WIN32_WCE
- #include <process.h>
- #include <direct.h>
- #include <io.h>
- #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) strtoul(x, y, z)
- #define strtoll(x, y, z) strtol(x, y, z)
- #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)
- #define popen(x, y) _popen(x, y)
- #define pclose(x) _pclose(x)
- #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) EnterCriticalSection(&global_log_file_lock)
- #define funlockfile(x) LeaveCriticalSection(&global_log_file_lock)
- #define sleep(x) Sleep((x) * 1000)
- #define va_copy(x, y) x = y
-
- #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);
- struct file;
- static char *mg_fgets(char *buf, size_t size, struct file *filep, char **p);
-
- #if defined(HAVE_STDINT)
- #include <stdint.h>
- #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;
-
- #ifndef HAS_POLL
- struct pollfd {
- int fd;
- short events;
- short revents;
- };
- #define POLLIN 1
- #endif
-
-
- // Mark required libraries
- #pragma comment(lib, "Ws2_32.lib")
-
- #else // UNIX specific
- #include <sys/wait.h>
- #include <sys/socket.h>
- #include <sys/poll.h>
- #include <netinet/in.h>
- #include <arpa/inet.h>
- #include <sys/time.h>
- #include <stdint.h>
- #include <inttypes.h>
- #include <netdb.h>
-
- #include <pwd.h>
- #include <unistd.h>
- #include <dirent.h>
- #if !defined(NO_SSL_DL) && !defined(NO_SSL)
- #include <dlfcn.h>
- #endif
- #include <pthread.h>
- #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_rename(x, y) rename(x, y)
- #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"
-
- #ifdef USE_LUA
- #include <lua.h>
- #include <lauxlib.h>
- #endif
-
- #define MONGOOSE_VERSION "3.8"
- #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 _WIN32
- static CRITICAL_SECTION global_log_file_lock;
- static pthread_t pthread_self(void) {
- return GetCurrentThreadId();
- }
- #endif // _WIN32
-
- #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
-
- #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
-
- static const char *http_500_error = "Internal Server Error";
-
- #if defined(NO_SSL_DL)
- #include <openssl/ssl.h>
- #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_callback_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 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)
-
- // set_ssl_option() function updates this array.
- // It loads SSL library dynamically and changes NULLs to the actual addresses
- // of respective functions. The macros above (like SSL_connect()) are really
- // just calling these functions indirectly via the pointer.
- static struct ssl_func ssl_sw[] = {
- {"SSL_free", NULL},
- {"SSL_accept", NULL},
- {"SSL_connect", NULL},
- {"SSL_read", NULL},
- {"SSL_write", NULL},
- {"SSL_get_error", NULL},
- {"SSL_set_fd", NULL},
- {"SSL_new", NULL},
- {"SSL_CTX_new", NULL},
- {"SSLv23_server_method", NULL},
- {"SSL_library_init", NULL},
- {"SSL_CTX_use_PrivateKey_file", NULL},
- {"SSL_CTX_use_certificate_file",NULL},
- {"SSL_CTX_set_default_passwd_cb",NULL},
- {"SSL_CTX_free", NULL},
- {"SSL_load_error_strings", NULL},
- {"SSL_CTX_use_certificate_chain_file", NULL},
- {"SSLv23_client_method", NULL},
- {"SSL_pending", NULL},
- {"SSL_CTX_set_verify", NULL},
- {NULL, NULL}
- };
-
- // Similar array as ssl_sw. These functions could be located in different lib.
- #if !defined(NO_SSL)
- static struct ssl_func crypto_sw[] = {
- {"CRYPTO_num_locks", NULL},
- {"CRYPTO_set_locking_callback", NULL},
- {"CRYPTO_set_id_callback", NULL},
- {"ERR_get_error", NULL},
- {"ERR_error_string", NULL},
- {NULL, NULL}
- };
- #endif // NO_SSL
- #endif // NO_SSL_DL
-
- static const char *month_names[] = {
- "Jan", "Feb", "Mar", "Apr", "May", "Jun",
- "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
- };
-
- // 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;
- FILE *fp;
- const char *membuf; // Non-NULL if file data is in memory
- };
- #define STRUCT_FILE_INITIALIZER {0, 0, 0, NULL, NULL}
-
- // 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 below.
- enum {
- CGI_EXTENSIONS, CGI_ENVIRONMENT, PUT_DELETE_PASSWORDS_FILE, CGI_INTERPRETER,
- PROTECT_URI, AUTHENTICATION_DOMAIN, SSI_EXTENSIONS, THROTTLE,
- 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
- };
-
- static const char *config_options[] = {
- "C", "cgi_pattern", "**.cgi$|**.pl$|**.php$",
- "E", "cgi_environment", NULL,
- "G", "put_delete_auth_file", NULL,
- "I", "cgi_interpreter", NULL,
- "P", "protect_uri", NULL,
- "R", "authentication_domain", "mydomain.com",
- "S", "ssi_pattern", "**.shtml$|**.shtm$",
- "T", "throttle", NULL,
- "a", "access_log_file", NULL,
- "d", "enable_directory_listing", "yes",
- "e", "error_log_file", NULL,
- "g", "global_auth_file", NULL,
- "i", "index_files",
- "index.html,index.htm,index.cgi,index.shtml,index.php,index.lp",
- "k", "enable_keep_alive", "no",
- "l", "access_control_list", NULL,
- "m", "extra_mime_types", NULL,
- "p", "listening_ports", "8080",
- "r", "document_root", ".",
- "s", "ssl_certificate", NULL,
- "t", "num_threads", "50",
- "u", "run_as_user", NULL,
- "w", "url_rewrite_patterns", NULL,
- "x", "hide_files_patterns", NULL,
- "z", "request_timeout_ms", "30000",
- NULL
- };
- #define ENTRIES_PER_CONFIG_OPTION 3
-
- 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
- struct mg_callbacks callbacks; // 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[20]; // 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_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 consumed_content; // How many bytes of content have been read
- 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
- int throttle; // Throttling, bytes/sec. <= 0 means no throttle
- time_t last_throttle_time; // Last time throttled data was sent
- int64_t last_throttle_bytes;// Bytes sent this second
- };
-
- const char **mg_get_valid_option_names(void) {
- return config_options;
- }
-
- static int is_file_in_memory(struct mg_connection *conn, const char *path,
- struct file *filep) {
- size_t size = 0;
- if ((filep->membuf = conn->ctx->callbacks.open_file == NULL ? NULL :
- conn->ctx->callbacks.open_file(conn, path, &size)) != NULL) {
- // NOTE: override filep->size only on success. Otherwise, it might break
- // constructs like if (!mg_stat() || !mg_fopen()) ...
- filep->size = size;
- }
- return filep->membuf != NULL;
- }
-
- static int is_file_opened(const struct file *filep) {
- return filep->membuf != NULL || filep->fp != NULL;
- }
-
- static int mg_fopen(struct mg_connection *conn, const char *path,
- const char *mode, struct file *filep) {
- if (!is_file_in_memory(conn, path, filep)) {
- #ifdef _WIN32
- wchar_t wbuf[PATH_MAX], wmode[20];
- to_unicode(path, wbuf, ARRAY_SIZE(wbuf));
- MultiByteToWideChar(CP_UTF8, 0, mode, -1, wmode, ARRAY_SIZE(wmode));
- filep->fp = _wfopen(wbuf, wmode);
- #else
- filep->fp = fopen(path, mode);
- #endif
- }
-
- return is_file_opened(filep);
- }
-
- static void mg_fclose(struct file *filep) {
- if (filep != NULL && filep->fp != NULL) {
- fclose(filep->fp);
- }
- }
-
- static int get_option_index(const char *name) {
- int i;
-
- for (i = 0; config_options[i] != NULL; i += ENTRIES_PER_CONFIG_OPTION) {
- if (strcmp(config_options[i], name) == 0 ||
- strcmp(config_options[i + 1], name) == 0) {
- return i / ENTRIES_PER_CONFIG_OPTION;
- }
- }
- return -1;
- }
-
- const char *mg_get_option(const struct mg_context *ctx, const char *name) {
- int i;
- if ((i = get_option_index(name)) == -1) {
- return NULL;
- } else if (ctx->config[i] == NULL) {
- return "";
- } else {
- return ctx->config[i];
- }
- }
-
- static void sockaddr_to_string(char *buf, size_t len,
- const union usa *usa) {
- buf[0] = '\0';
- #if defined(USE_IPV6)
- inet_ntop(usa->sa.sa_family, usa->sa.sa_family == AF_INET ?
- (void *) &usa->sin.sin_addr :
- (void *) &usa->sin6.sin6_addr, buf, len);
- #elif defined(_WIN32)
- // Only Windoze Vista (and newer) have inet_ntop()
- strncpy(buf, inet_ntoa(usa->sin.sin_addr), len);
- #else
- inet_ntop(usa->sa.sa_family, (void *) &usa->sin.sin_addr, buf, len);
- #endif
- }
-
- static void cry(struct mg_connection *conn,
- PRINTF_FORMAT_STRING(const char *fmt), ...) PRINTF_ARGS(2, 3);
-
- // Print error message to the opened error log stream.
- static void cry(struct mg_connection *conn, const char *fmt, ...) {
- char buf[MG_BUF_LEN], src_addr[20];
- va_list ap;
- FILE *fp;
- time_t timestamp;
-
- va_start(ap, fmt);
- (void) vsnprintf(buf, sizeof(buf), fmt, ap);
- va_end(ap);
-
- // Do not lock when getting the callback value, here and below.
- // I suppose this is fine, since function cannot disappear in the
- // same way string option can.
- if (conn->ctx->callbacks.log_message == NULL ||
- conn->ctx->callbacks.log_message(conn, buf) == 0) {
- fp = conn->ctx == NULL || conn->ctx->config[ERROR_LOG_FILE] == NULL ? NULL :
- fopen(conn->ctx->config[ERROR_LOG_FILE], "a+");
-
- if (fp != NULL) {
- flockfile(fp);
- timestamp = time(NULL);
-
- sockaddr_to_string(src_addr, sizeof(src_addr), &conn->client.rsa);
- fprintf(fp, "[%010lu] [error] [client %s] ", (unsigned long) timestamp,
- src_addr);
-
- if (conn->request_info.request_method != NULL) {
- fprintf(fp, "%s %s: ", conn->request_info.request_method,
- conn->request_info.uri);
- }
-
- fprintf(fp, "%s", buf);
- fputc('\n', fp);
- funlockfile(fp);
- fclose(fp);
- }
- }
- }
-
- // Return fake connection structure. Used for logging, if connection
- // is not applicable at the moment of logging.
- static struct mg_connection *fc(struct mg_context *ctx) {
- static struct mg_connection fake_connection;
- fake_connection.ctx = ctx;
- return &fake_connection;
- }
-
- const char *mg_version(void) {
- return MONGOOSE_VERSION;
- }
-
- struct mg_request_info *mg_get_request_info(struct mg_connection *conn) {
- return &conn->request_info;
- }
-
- static void mg_strlcpy(register char *dst, register const char *src, size_t n) {
- for (; *src != '\0' && n > 1; n--) {
- *dst++ = *src++;
- }
- *dst = '\0';
- }
-
- static int lowercase(const char *s) {
- return tolower(* (const unsigned char *) s);
- }
-
- static int mg_strncasecmp(const char *s1, const char *s2, size_t len) {
- int diff = 0;
-
- if (len > 0)
- do {
- diff = lowercase(s1++) - lowercase(s2++);
- } while (diff == 0 && s1[-1] != '\0' && --len > 0);
-
- return diff;
- }
-
- static int mg_strcasecmp(const char *s1, const char *s2) {
- int diff;
-
- do {
- diff = lowercase(s1++) - lowercase(s2++);
- } while (diff == 0 && s1[-1] != '\0');
-
- return diff;
- }
-
- static char * mg_strndup(const char *ptr, size_t len) {
- char *p;
-
- if ((p = (char *) malloc(len + 1)) != NULL) {
- mg_strlcpy(p, ptr, len + 1);
- }
-
- return p;
- }
-
- static char * mg_strdup(const char *str) {
- return mg_strndup(str, strlen(str));
- }
-
- // Like snprintf(), but never returns negative value, or a value
- // that is larger than a supplied buffer.
- // Thanks to Adam Zeldis to pointing snprintf()-caused vulnerability
- // in his audit report.
- static int mg_vsnprintf(struct mg_connection *conn, char *buf, size_t buflen,
- const char *fmt, va_list ap) {
- int n;
-
- if (buflen == 0)
- return 0;
-
- n = vsnprintf(buf, buflen, fmt, ap);
-
- if (n < 0) {
- cry(conn, "vsnprintf error");
- n = 0;
- } else if (n >= (int) buflen) {
- cry(conn, "truncating vsnprintf buffer: [%.*s]",
- n > 200 ? 200 : n, buf);
- n = (int) buflen - 1;
- }
- buf[n] = '\0';
-
- return n;
- }
-
- static int mg_snprintf(struct mg_connection *conn, char *buf, size_t buflen,
- PRINTF_FORMAT_STRING(const char *fmt), ...)
- PRINTF_ARGS(4, 5);
-
- static int mg_snprintf(struct mg_connection *conn, char *buf, size_t buflen,
- const char *fmt, ...) {
- va_list ap;
- int n;
-
- va_start(ap, fmt);
- n = mg_vsnprintf(conn, buf, buflen, fmt, ap);
- va_end(ap);
-
- return n;
- }
-
- // Skip the characters until one of the delimiters characters found.
- // 0-terminate resulting word. Skip the delimiter and following whitespaces.
- // Advance pointer to buffer to the next word. Return found 0-terminated word.
- // Delimiters can be quoted with quotechar.
- static char *skip_quoted(char **buf, const char *delimiters,
- const char *whitespace, char quotechar) {
- char *p, *begin_word, *end_word, *end_whitespace;
-
- begin_word = *buf;
- end_word = begin_word + strcspn(begin_word, delimiters);
-
- // Check for quotechar
- if (end_word > begin_word) {
- p = end_word - 1;
- while (*p == quotechar) {
- // If there is anything beyond end_word, copy it
- if (*end_word == '\0') {
- *p = '\0';
- break;
- } else {
- size_t end_off = strcspn(end_word + 1, delimiters);
- memmove (p, end_word, end_off + 1);
- p += end_off; // p must correspond to end_word - 1
- end_word += end_off + 1;
- }
- }
- for (p++; p < end_word; p++) {
- *p = '\0';
- }
- }
-
- if (*end_word == '\0') {
- *buf = end_word;
- } else {
- end_whitespace = end_word + 1 + strspn(end_word + 1, whitespace);
-
- for (p = end_word; p < end_whitespace; p++) {
- *p = '\0';
- }
-
- *buf = end_whitespace;
- }
-
- return begin_word;
- }
-
- // Simplified version of skip_quoted without quote char
- // and whitespace == delimiters
- static char *skip(char **buf, const char *delimiters) {
- return skip_quoted(buf, delimiters, delimiters, 0);
- }
-
-
- // Return HTTP header value, or NULL if not found.
- static const char *get_header(const struct mg_request_info *ri,
- const char *name) {
- int i;
-
- for (i = 0; i < ri->num_headers; i++)
- if (!mg_strcasecmp(name, ri->http_headers[i].name))
- return ri->http_headers[i].value;
-
- return NULL;
- }
-
- const char *mg_get_header(const struct mg_connection *conn, const char *name) {
- return get_header(&conn->request_info, name);
- }
-
- // A helper function for traversing a comma separated list of values.
- // It returns a list pointer shifted to the next value, or NULL if the end
- // of the list found.
- // Value is stored in val vector. If value has form "x=y", then eq_val
- // vector is initialized to point to the "y" part, and val vector length
- // is adjusted to point only to "x".
- static const char *next_option(const char *list, struct vec *val,
- struct vec *eq_val) {
- if (list == NULL || *list == '\0') {
- // End of the list
- list = NULL;
- } else {
- val->ptr = list;
- if ((list = strchr(val->ptr, ',')) != NULL) {
- // Comma found. Store length and shift the list ptr
- val->len = list - val->ptr;
- list++;
- } else {
- // This value is the last one
- list = val->ptr + strlen(val->ptr);
- val->len = list - val->ptr;
- }
-
- if (eq_val != NULL) {
- // Value has form "x=y", adjust pointers and lengths
- // so that val points to "x", and eq_val points to "y".
- eq_val->len = 0;
- eq_val->ptr = (const char *) memchr(val->ptr, '=', val->len);
- if (eq_val->ptr != NULL) {
- eq_val->ptr++; // Skip over '=' character
- eq_val->len = val->ptr + val->len - eq_val->ptr;
- val->len = (eq_val->ptr - val->ptr) - 1;
- }
- }
- }
-
- return list;
- }
-
- static int match_prefix(const char *pattern, int pattern_len, const char *str) {
- const char *or_str;
- int i, j, len, res;
-
- if ((or_str = (const char *) memchr(pattern, '|', pattern_len)) != NULL) {
- res = match_prefix(pattern, or_str - pattern, str);
- return res > 0 ? res :
- match_prefix(or_str + 1, (pattern + pattern_len) - (or_str + 1), str);
- }
-
- i = j = 0;
- res = -1;
- for (; i < pattern_len; i++, j++) {
- if (pattern[i] == '?' && str[j] != '\0') {
- continue;
- } else if (pattern[i] == '$') {
- return str[j] == '\0' ? j : -1;
- } else if (pattern[i] == '*') {
- i++;
- if (pattern[i] == '*') {
- i++;
- len = (int) strlen(str + j);
- } else {
- len = (int) strcspn(str + j, "/");
- }
- if (i == pattern_len) {
- return j + len;
- }
- do {
- res = match_prefix(pattern + i, pattern_len - i, str + j + len);
- } while (res == -1 && len-- > 0);
- return res == -1 ? -1 : j + res + len;
- } else if (pattern[i] != str[j]) {
- return -1;
- }
- }
- return j;
- }
-
- // HTTP 1.1 assumes keep alive if "Connection:" header is not set
- // This function must tolerate situations when connection info is not
- // set up, for example if request parsing failed.
- static int should_keep_alive(const struct mg_connection *conn) {
- const char *http_version = conn->request_info.http_version;
- const char *header = mg_get_header(conn, "Connection");
- if (conn->must_close ||
- conn->status_code == 401 ||
- mg_strcasecmp(conn->ctx->config[ENABLE_KEEP_ALIVE], "yes") != 0 ||
- (header != NULL && mg_strcasecmp(header, "keep-alive") != 0) ||
- (header == NULL && http_version && strcmp(http_version, "1.1"))) {
- return 0;
- }
- return 1;
- }
-
- static const char *suggest_connection_header(const struct mg_connection *conn) {
- return should_keep_alive(conn) ? "keep-alive" : "close";
- }
-
- static void send_http_error(struct mg_connection *, int, const char *,
- PRINTF_FORMAT_STRING(const char *fmt), ...)
- PRINTF_ARGS(4, 5);
-
-
- static void send_http_error(struct mg_connection *conn, int status,
- const char *reason, const char *fmt, ...) {
- char buf[MG_BUF_LEN];
- va_list ap;
- int len = 0;
-
- conn->status_code = status;
- if (conn->ctx->callbacks.http_error == NULL ||
- conn->ctx->callbacks.http_error(conn, status)) {
- buf[0] = '\0';
-
- // Errors 1xx, 204 and 304 MUST NOT send a body
- if (status > 199 && status != 204 && status != 304) {
- len = mg_snprintf(conn, buf, sizeof(buf), "Error %d: %s", status, reason);
- buf[len++] = '\n';
-
- va_start(ap, fmt);
- len += mg_vsnprintf(conn, buf + len, sizeof(buf) - len, fmt, ap);
- va_end(ap);
- }
- DEBUG_TRACE(("[%s]", buf));
-
- mg_printf(conn, "HTTP/1.1 %d %s\r\n"
- "Content-Length: %d\r\n"
- "Connection: %s\r\n\r\n", status, reason, len,
- suggest_connection_header(conn));
- conn->num_bytes_sent += mg_printf(conn, "%s", buf);
- }
- }
-
- #if defined(_WIN32) && !defined(__SYMBIAN32__)
- static int pthread_mutex_init(pthread_mutex_t *mutex, void *unused) {
- unused = NULL;
- *mutex = CreateMutex(NULL, FALSE, NULL);
- return *mutex == NULL ? -1 : 0;
- }
-
- static int pthread_mutex_destroy(pthread_mutex_t *mutex) {
- return CloseHandle(*mutex) == 0 ? -1 : 0;
- }
-
- static int pthread_mutex_lock(pthread_mutex_t *mutex) {
- return WaitForSingleObject(*mutex, INFINITE) == WAIT_OBJECT_0? 0 : -1;
- }
-
- static int pthread_mutex_unlock(pthread_mutex_t *mutex) {
- return ReleaseMutex(*mutex) == 0 ? -1 : 0;
- }
-
- static int pthread_cond_init(pthread_cond_t *cv, const void *unused) {
- unused = NULL;
- cv->signal = CreateEvent(NULL, FALSE, FALSE, NULL);
- cv->broadcast = CreateEvent(NULL, TRUE, FALSE, NULL);
- return cv->signal != NULL && cv->broadcast != NULL ? 0 : -1;
- }
-
- static int pthread_cond_wait(pthread_cond_t *cv, pthread_mutex_t *mutex) {
- HANDLE handles[] = {cv->signal, cv->broadcast};
- ReleaseMutex(*mutex);
- WaitForMultipleObjects(2, handles, FALSE, INFINITE);
- return WaitForSingleObject(*mutex, INFINITE) == WAIT_OBJECT_0? 0 : -1;
- }
-
- static int pthread_cond_signal(pthread_cond_t *cv) {
- return SetEvent(cv->signal) == 0 ? -1 : 0;
- }
-
- static int pthread_cond_broadcast(pthread_cond_t *cv) {
- // Implementation with PulseEvent() has race condition, see
- // http://www.cs.wustl.edu/~schmidt/win32-cv-1.html
- return PulseEvent(cv->broadcast) == 0 ? -1 : 0;
- }
-
- static int pthread_cond_destroy(pthread_cond_t *cv) {
- return CloseHandle(cv->signal) && CloseHandle(cv->broadcast) ? 0 : -1;
- }
-
- // For Windows, change all slashes to backslashes in path names.
- static void change_slashes_to_backslashes(char *path) {
- int i;
-
- for (i = 0; path[i] != '\0'; i++) {
- if (path[i] == '/')
- path[i] = '\\';
- // i > 0 check is to preserve UNC paths, like \\server\file.txt
- if (path[i] == '\\' && i > 0)
- while (path[i + 1] == '\\' || path[i + 1] == '/')
- (void) memmove(path + i + 1,
- path + i + 2, strlen(path + i + 1));
- }
- }
-
- // Encode 'path' which is assumed UTF-8 string, into UNICODE string.
- // wbuf and wbuf_len is a target buffer and its length.
- static void to_unicode(const char *path, wchar_t *wbuf, size_t wbuf_len) {
- char buf[PATH_MAX], buf2[PATH_MAX], *p;
-
- mg_strlcpy(buf, path, sizeof(buf));
- change_slashes_to_backslashes(buf);
-
- // Point p to the end of the file name
- p = buf + strlen(buf) - 1;
-
- // Convert to Unicode and back. If doubly-converted string does not
- // match the original, something is fishy, reject.
- memset(wbuf, 0, wbuf_len * sizeof(wchar_t));
- MultiByteToWideChar(CP_UTF8, 0, buf, -1, wbuf, (int) wbuf_len);
- WideCharToMultiByte(CP_UTF8, 0, wbuf, (int) wbuf_len, buf2, sizeof(buf2),
- NULL, NULL);
- if (strcmp(buf, buf2) != 0) {
- wbuf[0] = L'\0';
- }
- }
-
- #if defined(_WIN32_WCE)
- static time_t time(time_t *ptime) {
- time_t t;
- SYSTEMTIME st;
- FILETIME ft;
-
- GetSystemTime(&st);
- SystemTimeToFileTime(&st, &ft);
- t = SYS2UNIX_TIME(ft.dwLowDateTime, ft.dwHighDateTime);
-
- if (ptime != NULL) {
- *ptime = t;
- }
-
- return t;
- }
-
- static struct tm *localtime(const time_t *ptime, struct tm *ptm) {
- int64_t t = ((int64_t) *ptime) * RATE_DIFF + EPOCH_DIFF;
- FILETIME ft, lft;
- SYSTEMTIME st;
- TIME_ZONE_INFORMATION tzinfo;
-
- if (ptm == NULL) {
- return NULL;
- }
-
- * (int64_t *) &ft = t;
- FileTimeToLocalFileTime(&ft, &lft);
- FileTimeToSystemTime(&lft, &st);
- ptm->tm_year = st.wYear - 1900;
- ptm->tm_mon = st.wMonth - 1;
- ptm->tm_wday = st.wDayOfWeek;
- ptm->tm_mday = st.wDay;
- ptm->tm_hour = st.wHour;
- ptm->tm_min = st.wMinute;
- ptm->tm_sec = st.wSecond;
- ptm->tm_yday = 0; // hope nobody uses this
- ptm->tm_isdst =
- GetTimeZoneInformation(&tzinfo) == TIME_ZONE_ID_DAYLIGHT ? 1 : 0;
-
- return ptm;
- }
-
- static struct tm *gmtime(const time_t *ptime, struct tm *ptm) {
- // FIXME(lsm): fix this.
- return localtime(ptime, ptm);
- }
-
- static size_t strftime(char *dst, size_t dst_size, const char *fmt,
- const struct tm *tm) {
- (void) snprintf(dst, dst_size, "implement strftime() for WinCE");
- return 0;
- }
- #endif
-
- static int mg_rename(const char* oldname, const char* newname) {
- wchar_t woldbuf[PATH_MAX];
- wchar_t wnewbuf[PATH_MAX];
-
- to_unicode(oldname, woldbuf, ARRAY_SIZE(woldbuf));
- to_unicode(newname, wnewbuf, ARRAY_SIZE(wnewbuf));
-
- return MoveFileW(woldbuf, wnewbuf) ? 0 : -1;
- }
-
- // Windows happily opens files with some garbage at the end of file name.
- // For example, fopen("a.cgi ", "r") on Windows successfully opens
- // "a.cgi", despite one would expect an error back.
- // This function returns non-0 if path ends with some garbage.
- static int path_cannot_disclose_cgi(const char *path) {
- static const char *allowed_last_characters = "_-";
- int last = path[strlen(path) - 1];
- return isalnum(last) || strchr(allowed_last_characters, last) != NULL;
- }
-
- static int mg_stat(struct mg_connection *conn, const char *path,
- struct file *filep) {
- wchar_t wbuf[PATH_MAX];
- WIN32_FILE_ATTRIBUTE_DATA info;
-
- if (!is_file_in_memory(conn, path, filep)) {
- to_unicode(path, wbuf, ARRAY_SIZE(wbuf));
- if (GetFileAttributesExW(wbuf, GetFileExInfoStandard, &info) != 0) {
- filep->size = MAKEUQUAD(info.nFileSizeLow, info.nFileSizeHigh);
- filep->modification_time = SYS2UNIX_TIME(
- info.ftLastWriteTime.dwLowDateTime,
- info.ftLastWriteTime.dwHighDateTime);
- filep->is_directory = info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY;
- // If file name is fishy, reset the file structure and return error.
- // Note it is important to reset, not just return the error, cause
- // functions like is_file_opened() check the struct.
- if (!filep->is_directory && !path_cannot_disclose_cgi(path)) {
- memset(filep, 0, sizeof(*filep));
- }
- }
- }
-
- return filep->membuf != NULL || filep->modification_time != 0;
- }
-
- static int mg_remove(const char *path) {
- wchar_t wbuf[PATH_MAX];
- to_unicode(path, wbuf, ARRAY_SIZE(wbuf));
- return DeleteFileW(wbuf) ? 0 : -1;
- }
-
- static int mg_mkdir(const char *path, int mode) {
- char buf[PATH_MAX];
- wchar_t wbuf[PATH_MAX];
-
- mode = 0; // Unused
- mg_strlcpy(buf, path, sizeof(buf));
- change_slashes_to_backslashes(buf);
-
- (void) MultiByteToWideChar(CP_UTF8, 0, buf, -1, wbuf, ARRAY_SIZE(wbuf));
-
- return CreateDirectoryW(wbuf, NULL) ? 0 : -1;
- }
-
- // Implementation of POSIX opendir/closedir/readdir for Windows.
- static DIR * opendir(const char *name) {
- DIR *dir = NULL;
- wchar_t wpath[PATH_MAX];
- DWORD attrs;
-
- if (name == NULL) {
- SetLastError(ERROR_BAD_ARGUMENTS);
- } else if ((dir = (DIR *) malloc(sizeof(*dir))) == NULL) {
- SetLastError(ERROR_NOT_ENOUGH_MEMORY);
- } else {
- to_unicode(name, wpath, ARRAY_SIZE(wpath));
- attrs = GetFileAttributesW(wpath);
- if (attrs != 0xFFFFFFFF &&
- ((attrs & FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY)) {
- (void) wcscat(wpath, L"\\*");
- dir->handle = FindFirstFileW(wpath, &dir->info);
- dir->result.d_name[0] = '\0';
- } else {
- free(dir);
- dir = NULL;
- }
- }
-
- return dir;
- }
-
- static int closedir(DIR *dir) {
- int result = 0;
-
- if (dir != NULL) {
- if (dir->handle != INVALID_HANDLE_VALUE)
- result = FindClose(dir->handle) ? 0 : -1;
-
- free(dir);
- } else {
- result = -1;
- SetLastError(ERROR_BAD_ARGUMENTS);
- }
-
- return result;
- }
-
- static struct dirent *readdir(DIR *dir) {
- struct dirent *result = 0;
-
- if (dir) {
- if (dir->handle != INVALID_HANDLE_VALUE) {
- result = &dir->result;
- (void) WideCharToMultiByte(CP_UTF8, 0,
- dir->info.cFileName, -1, result->d_name,
- sizeof(result->d_name), NULL, NULL);
-
- if (!FindNextFileW(dir->handle, &dir->info)) {
- (void) FindClose(dir->handle);
- dir->handle = INVALID_HANDLE_VALUE;
- }
-
- } else {
- SetLastError(ERROR_FILE_NOT_FOUND);
- }
- } else {
- SetLastError(ERROR_BAD_ARGUMENTS);
- }
-
- return result;
- }
-
- #ifndef HAVE_POLL
- static int poll(struct pollfd *pfd, int n, int milliseconds) {
- struct timeval tv;
- fd_set set;
- int i, result;
-
- tv.tv_sec = milliseconds / 1000;
- tv.tv_usec = (milliseconds % 1000) * 1000;
- FD_ZERO(&set);
-
- for (i = 0; i < n; i++) {
- FD_SET((SOCKET) pfd[i].fd, &set);
- pfd[i].revents = 0;
- }
-
- if ((result = select(0, &set, NULL, NULL, &tv)) > 0) {
- for (i = 0; i < n; i++) {
- if (FD_ISSET(pfd[i].fd, &set)) {
- pfd[i].revents = POLLIN;
- }
- }
- }
-
- return result;
- }
- #endif // HAVE_POLL
-
- #define set_close_on_exec(x) // No FD_CLOEXEC on Windows
-
- int mg_start_thread(mg_thread_func_t f, void *p) {
- return _beginthread((void (__cdecl *)(void *)) f, 0, p) == -1L ? -1 : 0;
- }
-
- static HANDLE dlopen(const char *dll_name, int flags) {
- wchar_t wbuf[PATH_MAX];
- flags = 0; // Unused
- to_unicode(dll_name, wbuf, ARRAY_SIZE(wbuf));
- return LoadLibraryW(wbuf);
- }
-
- #if !defined(NO_CGI)
- #define SIGKILL 0
- static int kill(pid_t pid, int sig_num) {
- (void) TerminateProcess(pid, sig_num);
- (void) CloseHandle(pid);
- return 0;
- }
-
- static void trim_trailing_whitespaces(char *s) {
- char *e = s + strlen(s) - 1;
- while (e > s && isspace(* (unsigned char *) e)) {
- *e-- = '\0';
- }
- }
-
- static pid_t spawn_process(struct mg_connection *conn, const char *prog,
- char *envblk, char *envp[], int fd_stdin,
- int fd_stdout, const char *dir) {
- HANDLE me;
- char *p, *interp, full_interp[PATH_MAX], full_dir[PATH_MAX],
- cmdline[PATH_MAX], buf[PATH_MAX];
- struct file file = STRUCT_FILE_INITIALIZER;
- STARTUPINFOA si = { sizeof(si) };
- PROCESS_INFORMATION pi = { 0 };
-
- envp = NULL; // Unused
-
- // TODO(lsm): redirect CGI errors to the error log file
- si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
- si.wShowWindow = SW_HIDE;
-
- me = GetCurrentProcess();
- DuplicateHandle(me, (HANDLE) _get_osfhandle(fd_stdin), me,
- &si.hStdInput, 0, TRUE, DUPLICATE_SAME_ACCESS);
- DuplicateHandle(me, (HANDLE) _get_osfhandle(fd_stdout), me,
- &si.hStdOutput, 0, TRUE, DUPLICATE_SAME_ACCESS);
-
- // If CGI file is a script, try to read the interpreter line
- interp = conn->ctx->config[CGI_INTERPRETER];
- if (interp == NULL) {
- buf[0] = buf[1] = '\0';
-
- // Read the first line of the script into the buffer
- snprintf(cmdline, sizeof(cmdline), "%s%c%s", dir, '/', prog);
- if (mg_fopen(conn, cmdline, "r", &file)) {
- p = (char *) file.membuf;
- mg_fgets(buf, sizeof(buf), &file, &p);
- mg_fclose(&file);
- buf[sizeof(buf) - 1] = '\0';
- }
-
- if (buf[0] == '#' && buf[1] == '!') {
- trim_trailing_whitespaces(buf + 2);
- } else {
- buf[2] = '\0';
- }
- interp = buf + 2;
- }
-
- if (interp[0] != '\0') {
- GetFullPathNameA(interp, sizeof(full_interp), full_interp, NULL);
- interp = full_interp;
- }
- GetFullPathNameA(dir, sizeof(full_dir), full_dir, NULL);
-
- mg_snprintf(conn, cmdline, sizeof(cmdline), "%s%s%s\\%s",
- interp, interp[0] == '\0' ? "" : " ", full_dir, prog);
-
- DEBUG_TRACE(("Running [%s]", cmdline));
- if (CreateProcessA(NULL, cmdline, NULL, NULL, TRUE,
- CREATE_NEW_PROCESS_GROUP, envblk, NULL, &si, &pi) == 0) {
- cry(conn, "%s: CreateProcess(%s): %d",
- __func__, cmdline, ERRNO);
- pi.hProcess = (pid_t) -1;
- }
-
- // Always close these to prevent handle leakage.
- (void) close(fd_stdin);
- (void) close(fd_stdout);
-
- (void) CloseHandle(si.hStdOutput);
- (void) CloseHandle(si.hStdInput);
- (void) CloseHandle(pi.hThread);
-
- return (pid_t) pi.hProcess;
- }
- #endif // !NO_CGI
-
- static int set_non_blocking_mode(SOCKET sock) {
- unsigned long on = 1;
- return ioctlsocket(sock, FIONBIO, &on);
- }
-
- #else
- static int mg_stat(struct mg_connection *conn, const char *path,
- struct file *filep) {
- struct stat st;
-
- if (!is_file_in_memory(conn, path, filep) && !stat(path, &st)) {
- filep->size = st.st_size;
- filep->modification_time = st.st_mtime;
- filep->is_directory = S_ISDIR(st.st_mode);
- } else {
- filep->modification_time = (time_t) 0;
- }
-
- return filep->membuf != NULL || filep->modification_time != (time_t) 0;
- }
-
- static void set_close_on_exec(int fd) {
- fcntl(fd, F_SETFD, FD_CLOEXEC);
- }
-
- int mg_start_thread(mg_thread_func_t func, void *param) {
- pthread_t thread_id;
- pthread_attr_t attr;
-
- (void) pthread_attr_init(&attr);
- (void) pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
- // TODO(lsm): figure out why mongoose dies on Linux if next line is enabled
- // (void) pthread_attr_setstacksize(&attr, sizeof(struct mg_connection) * 5);
-
- return pthread_create(&thread_id, &attr, func, param);
- }
-
- #ifndef NO_CGI
- static pid_t spawn_process(struct mg_connection *conn, const char *prog,
- char *envblk, char *envp[], int fd_stdin,
- int fd_stdout, const char *dir) {
- pid_t pid;
- const char *interp;
-
- (void) envblk;
-
- if ((pid = fork()) == -1) {
- // Parent
- send_http_error(conn, 500, http_500_error, "fork(): %s", strerror(ERRNO));
- } else if (pid == 0) {
- // Child
- if (chdir(dir) != 0) {
- cry(conn, "%s: chdir(%s): %s", __func__, dir, strerror(ERRNO));
- } else if (dup2(fd_stdin, 0) == -1) {
- cry(conn, "%s: dup2(%d, 0): %s", __func__, fd_stdin, strerror(ERRNO));
- } else if (dup2(fd_stdout, 1) == -1) {
- cry(conn, "%s: dup2(%d, 1): %s", __func__, fd_stdout, strerror(ERRNO));
- } else {
- (void) dup2(fd_stdout, 2);
- (void) close(fd_stdin);
- (void) close(fd_stdout);
-
- // After exec, all signal handlers are restored to their default values,
- // with one exception of SIGCHLD. According to POSIX.1-2001 and Linux's
- // implementation, SIGCHLD's handler will leave unchanged after exec
- // if it was set to be ignored. Restore it to default action.
- signal(SIGCHLD, SIG_DFL);
-
- interp = conn->ctx->config[CGI_INTERPRETER];
- if (interp == NULL) {
- (void) execle(prog, prog, NULL, envp);
- cry(conn, "%s: execle(%s): %s", __func__, prog, strerror(ERRNO));
- } else {
- (void) execle(interp, interp, prog, NULL, envp);
- cry(conn, "%s: execle(%s %s): %s", __func__, interp, prog,
- strerror(ERRNO));
- }
- }
- exit(EXIT_FAILURE);
- }
-
- // Parent. Close stdio descriptors
- (void) close(fd_stdin);
- (void) close(fd_stdout);
-
- return pid;
- }
- #endif // !NO_CGI
-
- static int set_non_blocking_mode(SOCKET sock) {
- int flags;
-
- flags = fcntl(sock, F_GETFL, 0);
- (void) fcntl(sock, F_SETFL, flags | O_NONBLOCK);
-
- return 0;
- }
- #endif // _WIN32
-
- // Write data to the IO channel - opened file descriptor, socket or SSL
- // descriptor. Return number of bytes written.
- static int64_t push(FILE *fp, SOCKET sock, SSL *ssl, const char *buf,
- int64_t len) {
- int64_t sent;
- int n, k;
- sent = 0;
- while (sent < len) {
-
- // How many bytes we send in this iteration
- k = len - sent > INT_MAX ? INT_MAX : (int) (len - sent);
-
- #ifndef NO_SSL
- if (ssl != NULL) {
- n = SSL_write(ssl, buf + sent, k);
- } else
- #endif
- if (fp != NULL) {
- n = (int) fwrite(buf + sent, 1, (size_t) k, fp);
- if (ferror(fp))
- n = -1;
- } else {
- n = send(sock, buf + sent, (size_t) k, MSG_NOSIGNAL);
- }
-
- if (n <= 0)
- break;
-
- sent += n;
- }
- return sent;
- }
-
- /*
- char* read_post_data(char *buf)
- {
- int i =0 , count =0 ;
- char *data ; // char data[65536] ; alternate declaration to have more size
-
-
-
- FILE *fp ; fp = fopen("testpd.txt","a");fprintf(fp,"\nbuf->%s\npd-%s",buf,data);
- fclose(fp);
- while (i < strlen (buf))
- {
- if (buf[i] =='\r' && buf[i+1] =='\n' && buf[i+2] =='\r' && buf[i+3] == '\n' )
- {
- i= i+4 ;
- while ( buf[i] != '\r' && buf[i+1]!='\n' )
- {
- data[count] = buf[i] ;
- count++;
- i++;
- }
- data[i] = '\0';
- break ;
- }
- else{i++;}
- }//end while
- // fprintf(fp,"\nbuf->%s\npd-%s",buf,data);fclose(fp);
- return data;
- }*/
-
- char* read_post_data(char* buf, int len)
- {
- FILE * fp4;
- char *temp;
- temp = malloc(20);
- fp4 = fopen("testpost.txt","w");
- fprintf(fp4,"In the read_post_data %s", buf);
- //fclose(fp4);
- int i=0, j=0;
- /*while(buf[i] != '\r' && buf[i+1]!= '\n' && buf[i+2]!= '\r' && buf[i+3]!= '\n')
- i++;
- i=i+4;
- while(buf[i] != '\r' && buf[i+1]!= '\n')
- {
- temp[j++] = buf[i++];
- }
- temp[j] = '\0';*/
-
- while (i < strlen (buf))
- {
- if (buf[i] =='\r' && buf[i+1] =='\n' && buf[i+2] =='\r' && buf[i+3] == '\n' )
- {
- i= i+4 ;
- while ( buf[i] != '\r' && buf[i+1]!='\n' )
- {
- temp[j] = buf[i] ;
- j++;
- i++;
- }
- //temp[i] = '\0';
- break ;
- }
- else{i++;}
- }
-
- fprintf(fp4,"temp: %s", temp);
- fclose(fp4);
- return temp;
- }
-
- // Read from IO channel - opened file descriptor, socket, or SSL descriptor.
- // Return negative value on error, or number of bytes read on success.
- static int pull(FILE *fp, struct mg_connection *conn, char *buf, int len) {
- int nread;
-
- const struct mg_request_info *request_info = mg_get_request_info(conn);
- if (fp != NULL) {
- // Use read() instead of fread(), because if we're reading from the CGI
- // pipe, fread() may block until IO buffer is filled up. We cannot afford
- // to block and must pass all read bytes immediately to the client.
- nread = read(fileno(fp), buf, (size_t) len);
- #ifndef NO_SSL
- } else if (conn->ssl != NULL) {
- nread = SSL_read(conn->ssl, buf, len);
- #endif
- } else {
- nread = recv(conn->client.sock, buf, (size_t) len, 0);
- }
- return conn->ctx->stop_flag ? -1 : nread;
- }
-
- int mg_read(struct mg_connection *conn, void *buf, size_t len) {
- int n, buffered_len, nread;
- const char *body;
- FILE *fp8;
- fp8 = fopen("postdata.txt","a");
- nread = 0;
- if (conn->consumed_content < conn->content_len) {
- // Adjust number of bytes to read.
- int64_t to_read = conn->content_len - conn->consumed_content;
- if (to_read < (int64_t) len) {
- len = (size_t) to_read;
- }
-
- // Return buffered data
- body = conn->buf + conn->request_len + conn->consumed_content;
- buffered_len = &conn->buf[conn->data_len] - body;
- if (buffered_len > 0) {
- if (len < (size_t) buffered_len) {
- buffered_len = (int) len;
- }
- memcpy(buf, body, (size_t) buffered_len);
- len -= buffered_len;
- conn->consumed_content += buffered_len;
- nread += buffered_len;
- buf = (char *) buf + buffered_len;
- }
-
- // We have returned all buffered data. Read new data from the remote socket.
- while (len > 0) {
- n = pull(NULL, conn, (char *) buf, (int) len);
- if (n < 0) {
- nread = n; // Propagate the error
- break;
- } else if (n == 0) {
- break; // No more data to read
- } else {
- buf = (char *) buf + n;
- conn->consumed_content += n;
- nread += n;
- len -= n;
- }
- }
- }
- fprintf(fp8, "%s", body);
- fprintf(fp8, "buf: %s", buf);
- fclose(fp8);
- return nread;
- }
-
- int mg_write(struct mg_connection *conn, const void *buf, size_t len) {
- time_t now;
- int64_t n, total, allowed;
- FILE *fp11;
- fp11 = fopen("mgwrite.txt","a");
- fprintf(fp11," buf: %s",conn->buf );
- fclose(fp11);
- if (conn->throttle > 0) {
- if ((now = time(NULL)) != conn->last_throttle_time) {
- conn->last_throttle_time = now;
- conn->last_throttle_bytes = 0;
- }
- allowed = conn->throttle - conn->last_throttle_bytes;
- if (allowed > (int64_t) len) {
- allowed = len;
- }
- if ((total = push(NULL, conn->client.sock, conn->ssl, (const char *) buf,
- (int64_t) allowed)) == allowed) {
- buf = (char *) buf + total;
- conn->last_throttle_bytes += total;
- while (total < (int64_t) len && conn->ctx->stop_flag == 0) {
- allowed = conn->throttle > (int64_t) len - total ?
- (int64_t) len - total : conn->throttle;
- if ((n = push(NULL, conn->client.sock, conn->ssl, (const char *) buf,
- (int64_t) allowed)) != allowed) {
- break;
- }
- sleep(1);
- conn->last_throttle_bytes = allowed;
- conn->last_throttle_time = time(NULL);
- buf = (char *) buf + n;
- total += n;
- }
- }
- } else {
- total = push(NULL, conn->client.sock, conn->ssl, (const char *) buf,
- (int64_t) len);
- }
-
- return (int) total;
- }
-
- // Print message to buffer. If buffer is large enough to hold the message,
- // return buffer. If buffer is to small, allocate large enough buffer on heap,
- // and return allocated buffer.
- static int alloc_vprintf(char **buf, size_t size, const char *fmt, va_list ap) {
- va_list ap_copy;
- int len;
-
- // Windows is not standard-compliant, and vsnprintf() returns -1 if
- // buffer is too small. Also, older versions of msvcrt.dll do not have
- // _vscprintf(). However, if size is 0, vsnprintf() behaves correctly.
- // Therefore, we make two passes: on first pass, get required message length.
- // On second pass, actually print the message.
- va_copy(ap_copy, ap);
- len = vsnprintf(NULL, 0, fmt, ap_copy);
-
- if (len > (int) size &&
- (size = len + 1) > 0 &&
- (*buf = (char *) malloc(size)) == NULL) {
- len = -1; // Allocation failed, mark failure
- } else {
- va_copy(ap_copy, ap);
- vsnprintf(*buf, size, fmt, ap_copy);
- }
-
- return len;
- }
-
- int mg_vprintf(struct mg_connection *conn, const char *fmt, va_list ap) {
- char mem[MG_BUF_LEN], *buf = mem;
- int len;
- int i = 0;
- FILE *f9;
- f9 = fopen("mgv.txt","a");
- fprintf(f9,"%s", fmt);
- if ((len = alloc_vprintf(&buf, sizeof(mem), fmt, ap)) > 0) {
- while(i < len)
- {…