15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2004-2011 Sergey Lyubka 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Permission is hereby granted, free of charge, to any person obtaining a copy 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// of this software and associated documentation files (the "Software"), to deal 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// in the Software without restriction, including without limitation the rights 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// copies of the Software, and to permit persons to whom the Software is 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// furnished to do so, subject to the following conditions: 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The above copyright notice and this permission notice shall be included in 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// all copies or substantial portions of the Software. 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// THE SOFTWARE. 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(_WIN32) 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define _CRT_SECURE_NO_WARNINGS // Disable deprecation warning in VS2005 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#else 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define _XOPEN_SOURCE 600 // For flockfile() on Linux 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define _LARGEFILE_SOURCE // Enable 64-bit file offsets 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifndef __STDC_FORMAT_MACROS 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define __STDC_FORMAT_MACROS // <inttypes.h> wants this for C++ 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif // __STDC_FORMAT_MACROS 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(__SYMBIAN32__) 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define NO_SSL // SSL is not supported 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define NO_CGI // CGI is not supported 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define PATH_MAX FILENAME_MAX 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif // __SYMBIAN32__ 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifndef _WIN32_WCE // Some ANSI #includes are not available on Windows CE 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <sys/types.h> 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <sys/stat.h> 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <errno.h> 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <signal.h> 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <fcntl.h> 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif // !_WIN32_WCE 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <time.h> 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <stdlib.h> 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <stdarg.h> 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <assert.h> 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <string.h> 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <ctype.h> 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <limits.h> 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <stddef.h> 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <stdio.h> 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(_WIN32) && !defined(__SYMBIAN32__) // Windows specific 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) #ifdef _WIN32_WINNT 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) #undef _WIN32_WINNT 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) #endif 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define _WIN32_WINNT 0x0400 // To make it link in VS2005 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <windows.h> 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <winsock2.h> 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifndef PATH_MAX 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define PATH_MAX MAX_PATH 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifndef _WIN32_WCE 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <process.h> 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <direct.h> 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <io.h> 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#else // _WIN32_WCE 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define NO_CGI // WinCE has no pipes 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)typedef long off_t; 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define BUFSIZ 4096 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define errno GetLastError() 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define strerror(x) _ultoa(x, (char *) _alloca(sizeof(x) *3 ), 10) 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif // _WIN32_WCE 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define MAKEUQUAD(lo, hi) ((uint64_t)(((uint32_t)(lo)) | \ 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ((uint64_t)((uint32_t)(hi))) << 32)) 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define RATE_DIFF 10000000 // 100 nsecs 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define EPOCH_DIFF MAKEUQUAD(0xd53e8000, 0x019db1de) 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define SYS2UNIX_TIME(lo, hi) \ 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (time_t) ((MAKEUQUAD((lo), (hi)) - EPOCH_DIFF) / RATE_DIFF) 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Visual Studio 6 does not know __func__ or __FUNCTION__ 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The rest of MS compilers use __FUNCTION__, not C99 __func__ 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Also use _strtoui64 on modern M$ compilers 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(_MSC_VER) && _MSC_VER < 1300 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define STRX(x) #x 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define STR(x) STRX(x) 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define __func__ "line " STR(__LINE__) 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define strtoull(x, y, z) strtoul(x, y, z) 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define strtoll(x, y, z) strtol(x, y, z) 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#else 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define __func__ __FUNCTION__ 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define strtoull(x, y, z) _strtoui64(x, y, z) 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define strtoll(x, y, z) _strtoi64(x, y, z) 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif // _MSC_VER 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define ERRNO GetLastError() 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define NO_SOCKLEN_T 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define SSL_LIB "ssleay32.dll" 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define CRYPTO_LIB "libeay32.dll" 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define DIRSEP '\\' 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define IS_DIRSEP_CHAR(c) ((c) == '/' || (c) == '\\') 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define O_NONBLOCK 0 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if !defined(EWOULDBLOCK) 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define EWOULDBLOCK WSAEWOULDBLOCK 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif // !EWOULDBLOCK 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define _POSIX_ 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define INT64_FMT "I64d" 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define WINCDECL __cdecl 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define SHUT_WR 1 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define snprintf _snprintf 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define vsnprintf _vsnprintf 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define sleep(x) Sleep((x) * 1000) 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define pipe(x) _pipe(x, BUFSIZ, _O_BINARY) 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define popen(x, y) _popen(x, y) 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define pclose(x) _pclose(x) 1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define close(x) _close(x) 1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define dlsym(x,y) GetProcAddress((HINSTANCE) (x), (y)) 1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define RTLD_LAZY 0 1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define fseeko(x, y, z) fseek((x), (y), (z)) 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define fdopen(x, y) _fdopen((x), (y)) 1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define write(x, y, z) _write((x), (y), (unsigned) z) 1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define read(x, y, z) _read((x), (y), (unsigned) z) 1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define flockfile(x) (void) 0 1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define funlockfile(x) (void) 0 1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if !defined(fileno) 1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define fileno(x) _fileno(x) 1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif // !fileno MINGW #defines fileno 1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)typedef HANDLE pthread_mutex_t; 1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)typedef struct {HANDLE signal, broadcast;} pthread_cond_t; 1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)typedef DWORD pthread_t; 1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define pid_t HANDLE // MINGW typedefs pid_t to int. Using #define here. 1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)struct timespec { 1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) long tv_nsec; 1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) long tv_sec; 1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int pthread_mutex_lock(pthread_mutex_t *); 1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int pthread_mutex_unlock(pthread_mutex_t *); 1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static FILE *mg_fopen(const char *path, const char *mode); 1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(HAVE_STDINT) 1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <stdint.h> 1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#else 1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)typedef unsigned int uint32_t; 1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)typedef unsigned short uint16_t; 1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)typedef unsigned __int64 uint64_t; 1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)typedef __int64 int64_t; 1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define INT64_MAX 9223372036854775807 1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif // HAVE_STDINT 1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// POSIX dirent interface 1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)struct dirent { 1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) char d_name[PATH_MAX]; 1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)typedef struct DIR { 1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HANDLE handle; 1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) WIN32_FIND_DATAW info; 1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) struct dirent result; 1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} DIR; 1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#else // UNIX specific 1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <sys/wait.h> 1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <sys/socket.h> 1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <sys/select.h> 1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <netinet/in.h> 1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <arpa/inet.h> 1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <sys/time.h> 1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <stdint.h> 1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <inttypes.h> 1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <netdb.h> 1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <pwd.h> 1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <unistd.h> 1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <dirent.h> 1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if !defined(NO_SSL_DL) && !defined(NO_SSL) 1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <dlfcn.h> 1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <pthread.h> 1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(__MACH__) 1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define SSL_LIB "libssl.dylib" 1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define CRYPTO_LIB "libcrypto.dylib" 1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#else 1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if !defined(SSL_LIB) 1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define SSL_LIB "libssl.so" 1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if !defined(CRYPTO_LIB) 2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define CRYPTO_LIB "libcrypto.so" 2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define DIRSEP '/' 2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define IS_DIRSEP_CHAR(c) ((c) == '/') 2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifndef O_BINARY 2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define O_BINARY 0 2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif // O_BINARY 2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define closesocket(a) close(a) 2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define mg_fopen(x, y) fopen(x, y) 2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define mg_mkdir(x, y) mkdir(x, y) 2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define mg_remove(x) remove(x) 2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define mg_rename(x, y) rename(x, y) 2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define ERRNO errno 2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define INVALID_SOCKET (-1) 2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define INT64_FMT PRId64 2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)typedef int SOCKET; 2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define WINCDECL 2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif // End of Windows and UNIX specific includes 2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "mongoose.h" 2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define MONGOOSE_VERSION "3.1" 2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define PASSWORDS_FILE_NAME ".htpasswd" 2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define CGI_ENVIRONMENT_SIZE 4096 2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define MAX_CGI_ENVIR_VARS 64 2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define ARRAY_SIZE(array) (sizeof(array) / sizeof(array[0])) 2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifdef _WIN32 2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static pthread_t pthread_self(void) { 2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return GetCurrentThreadId(); 2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif // _WIN32 2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(DEBUG) 2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define DEBUG_TRACE(x) do { \ 2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) flockfile(stdout); \ 2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) printf("*** %lu.%p.%s.%d: ", \ 2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (unsigned long) time(NULL), (void *) pthread_self(), \ 2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) __func__, __LINE__); \ 2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) printf x; \ 2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) putchar('\n'); \ 2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fflush(stdout); \ 2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) funlockfile(stdout); \ 2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} while (0) 2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#else 2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define DEBUG_TRACE(x) 2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif // DEBUG 2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Darwin prior to 7.0 and Win32 do not have socklen_t 2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifdef NO_SOCKLEN_T 2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)typedef int socklen_t; 2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif // NO_SOCKLEN_T 2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)typedef void * (*mg_thread_func_t)(void *); 2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const char *http_500_error = "Internal Server Error"; 2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Snatched from OpenSSL includes. I put the prototypes here to be independent 2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// from the OpenSSL source installation. Having this, mongoose + SSL can be 2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// built on any system with binary SSL libraries installed. 2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)typedef struct ssl_st SSL; 2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)typedef struct ssl_method_st SSL_METHOD; 2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)typedef struct ssl_ctx_st SSL_CTX; 2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define SSL_ERROR_WANT_READ 2 2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define SSL_ERROR_WANT_WRITE 3 2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define SSL_FILETYPE_PEM 1 2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define CRYPTO_LOCK 1 2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(NO_SSL_DL) 2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)extern void SSL_free(SSL *); 2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)extern int SSL_accept(SSL *); 2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)extern int SSL_connect(SSL *); 2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)extern int SSL_read(SSL *, void *, int); 2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)extern int SSL_write(SSL *, const void *, int); 2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)extern int SSL_get_error(const SSL *, int); 2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)extern int SSL_set_fd(SSL *, int); 2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)extern SSL *SSL_new(SSL_CTX *); 2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)extern SSL_CTX *SSL_CTX_new(SSL_METHOD *); 2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)extern SSL_METHOD *SSLv23_server_method(void); 2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)extern int SSL_library_init(void); 2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)extern void SSL_load_error_strings(void); 2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)extern int SSL_CTX_use_PrivateKey_file(SSL_CTX *, const char *, int); 2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)extern int SSL_CTX_use_certificate_file(SSL_CTX *, const char *, int); 2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)extern int SSL_CTX_use_certificate_chain_file(SSL_CTX *, const char *); 2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)extern void SSL_CTX_set_default_passwd_cb(SSL_CTX *, mg_callback_t); 2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)extern void SSL_CTX_free(SSL_CTX *); 2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)extern unsigned long ERR_get_error(void); 2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)extern char *ERR_error_string(unsigned long, char *); 2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)extern int CRYPTO_num_locks(void); 2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)extern void CRYPTO_set_locking_callback(void (*)(int, int, const char *, int)); 2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)extern void CRYPTO_set_id_callback(unsigned long (*)(void)); 2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#else 2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Dynamically loaded SSL functionality 2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)struct ssl_func { 2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char *name; // SSL function name 2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void (*ptr)(void); // Function pointer 2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define SSL_free (* (void (*)(SSL *)) ssl_sw[0].ptr) 3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define SSL_accept (* (int (*)(SSL *)) ssl_sw[1].ptr) 3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define SSL_connect (* (int (*)(SSL *)) ssl_sw[2].ptr) 3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define SSL_read (* (int (*)(SSL *, void *, int)) ssl_sw[3].ptr) 3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define SSL_write (* (int (*)(SSL *, const void *,int)) ssl_sw[4].ptr) 3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define SSL_get_error (* (int (*)(SSL *, int)) ssl_sw[5].ptr) 3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define SSL_set_fd (* (int (*)(SSL *, SOCKET)) ssl_sw[6].ptr) 3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define SSL_new (* (SSL * (*)(SSL_CTX *)) ssl_sw[7].ptr) 3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define SSL_CTX_new (* (SSL_CTX * (*)(SSL_METHOD *)) ssl_sw[8].ptr) 3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define SSLv23_server_method (* (SSL_METHOD * (*)(void)) ssl_sw[9].ptr) 3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define SSL_library_init (* (int (*)(void)) ssl_sw[10].ptr) 3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define SSL_CTX_use_PrivateKey_file (* (int (*)(SSL_CTX *, \ 3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char *, int)) ssl_sw[11].ptr) 3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define SSL_CTX_use_certificate_file (* (int (*)(SSL_CTX *, \ 3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char *, int)) ssl_sw[12].ptr) 3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define SSL_CTX_set_default_passwd_cb \ 3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (* (void (*)(SSL_CTX *, mg_callback_t)) ssl_sw[13].ptr) 3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define SSL_CTX_free (* (void (*)(SSL_CTX *)) ssl_sw[14].ptr) 3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define SSL_load_error_strings (* (void (*)(void)) ssl_sw[15].ptr) 3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define SSL_CTX_use_certificate_chain_file \ 3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (* (int (*)(SSL_CTX *, const char *)) ssl_sw[16].ptr) 3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define CRYPTO_num_locks (* (int (*)(void)) crypto_sw[0].ptr) 3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define CRYPTO_set_locking_callback \ 3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (* (void (*)(void (*)(int, int, const char *, int))) crypto_sw[1].ptr) 3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define CRYPTO_set_id_callback \ 3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (* (void (*)(unsigned long (*)(void))) crypto_sw[2].ptr) 3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define ERR_get_error (* (unsigned long (*)(void)) crypto_sw[3].ptr) 3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define ERR_error_string (* (char * (*)(unsigned long,char *)) crypto_sw[4].ptr) 3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// set_ssl_option() function updates this array. 3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// It loads SSL library dynamically and changes NULLs to the actual addresses 3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// of respective functions. The macros above (like SSL_connect()) are really 3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// just calling these functions indirectly via the pointer. 3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static struct ssl_func ssl_sw[] = { 3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) {"SSL_free", NULL}, 3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) {"SSL_accept", NULL}, 3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) {"SSL_connect", NULL}, 3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) {"SSL_read", NULL}, 3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) {"SSL_write", NULL}, 3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) {"SSL_get_error", NULL}, 3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) {"SSL_set_fd", NULL}, 3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) {"SSL_new", NULL}, 3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) {"SSL_CTX_new", NULL}, 3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) {"SSLv23_server_method", NULL}, 3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) {"SSL_library_init", NULL}, 3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) {"SSL_CTX_use_PrivateKey_file", NULL}, 3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) {"SSL_CTX_use_certificate_file",NULL}, 3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) {"SSL_CTX_set_default_passwd_cb",NULL}, 3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) {"SSL_CTX_free", NULL}, 3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) {"SSL_load_error_strings", NULL}, 3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) {"SSL_CTX_use_certificate_chain_file", NULL}, 3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) {NULL, NULL} 3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Similar array as ssl_sw. These functions could be located in different lib. 3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static struct ssl_func crypto_sw[] = { 3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) {"CRYPTO_num_locks", NULL}, 3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) {"CRYPTO_set_locking_callback", NULL}, 3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) {"CRYPTO_set_id_callback", NULL}, 3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) {"ERR_get_error", NULL}, 3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) {"ERR_error_string", NULL}, 3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) {NULL, NULL} 3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif // NO_SSL_DL 3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const char *month_names[] = { 3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "Jan", "Feb", "Mar", "Apr", "May", "Jun", 3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" 3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Unified socket address. For IPv6 support, add IPv6 address structure 3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// in the union u. 3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)struct usa { 3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) socklen_t len; 3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) union { 3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) struct sockaddr sa; 3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) struct sockaddr_in sin; 3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } u; 3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Describes a string (chunk of memory). 3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)struct vec { 3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char *ptr; 3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size_t len; 3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Structure used by mg_stat() function. Uses 64 bit file length. 3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)struct mgstat { 3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int is_directory; // Directory marker 3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int64_t size; // File size 3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) time_t mtime; // Modification time 3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Describes listening socket, or socket which was accept()-ed by the master 3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// thread and queued for future handling by the worker thread. 3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)struct socket { 3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) struct socket *next; // Linkage 3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SOCKET sock; // Listening socket 4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) struct usa lsa; // Local socket address 4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) struct usa rsa; // Remote socket address 4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int is_ssl; // Is socket SSL-ed 4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int is_proxy; 4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)enum { 4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CGI_EXTENSIONS, CGI_ENVIRONMENT, PUT_DELETE_PASSWORDS_FILE, CGI_INTERPRETER, 4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PROTECT_URI, AUTHENTICATION_DOMAIN, SSI_EXTENSIONS, ACCESS_LOG_FILE, 4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SSL_CHAIN_FILE, ENABLE_DIRECTORY_LISTING, ERROR_LOG_FILE, 4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GLOBAL_PASSWORDS_FILE, INDEX_FILES, 4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ENABLE_KEEP_ALIVE, ACCESS_CONTROL_LIST, MAX_REQUEST_SIZE, 4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EXTRA_MIME_TYPES, LISTENING_PORTS, 4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DOCUMENT_ROOT, SSL_CERTIFICATE, NUM_THREADS, RUN_AS_USER, 4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NUM_OPTIONS 4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const char *config_options[] = { 4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "C", "cgi_extensions", ".cgi,.pl,.php", 4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "E", "cgi_environment", NULL, 4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "G", "put_delete_passwords_file", NULL, 4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "I", "cgi_interpreter", NULL, 4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "P", "protect_uri", NULL, 4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "R", "authentication_domain", "mydomain.com", 4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "S", "ssi_extensions", ".shtml,.shtm", 4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "a", "access_log_file", NULL, 4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "c", "ssl_chain_file", NULL, 4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "d", "enable_directory_listing", "yes", 4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "e", "error_log_file", NULL, 4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "g", "global_passwords_file", NULL, 4305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "i", "index_files", "index.html,index.htm,index.cgi", 4315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "k", "enable_keep_alive", "no", 4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "l", "access_control_list", NULL, 4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "M", "max_request_size", "16384", 4345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "m", "extra_mime_types", NULL, 4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "p", "listening_ports", "8080", 4365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "r", "document_root", ".", 4375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "s", "ssl_certificate", NULL, 4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "t", "num_threads", "10", 4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "u", "run_as_user", NULL, 4405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NULL 4415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 4425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define ENTRIES_PER_CONFIG_OPTION 3 4435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)struct mg_context { 4455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) volatile int stop_flag; // Should we stop event loop 4465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SSL_CTX *ssl_ctx; // SSL context 4475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) char *config[NUM_OPTIONS]; // Mongoose configuration parameters 4485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mg_callback_t user_callback; // User-defined callback function 4495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void *user_data; // User-defined data 4505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) struct socket *listening_sockets; 4525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) volatile int num_threads; // Number of threads 4545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pthread_mutex_t mutex; // Protects (max|num)_threads 4555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pthread_cond_t cond; // Condvar for tracking workers terminations 4565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) struct socket queue[20]; // Accepted sockets 4585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) volatile int sq_head; // Head of the socket queue 4595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) volatile int sq_tail; // Tail of the socket queue 4605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pthread_cond_t sq_full; // Singaled when socket is produced 4615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pthread_cond_t sq_empty; // Signaled when socket is consumed 4625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 4635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)struct mg_connection { 4655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) struct mg_connection *peer; // Remote target in proxy mode 4665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) struct mg_request_info request_info; 4675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) struct mg_context *ctx; 4685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SSL *ssl; // SSL descriptor 4695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) struct socket client; // Connected client 4705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) time_t birth_time; // Time connection was accepted 4715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int64_t num_bytes_sent; // Total bytes sent to client 4725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int64_t content_len; // Content-Length header value 4735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int64_t consumed_content; // How many bytes of content is already read 4745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) char *buf; // Buffer for received data 4755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int buf_size; // Buffer size 4765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int request_len; // Size of the request + headers in a buffer 4775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int data_len; // Total size of data in a buffer 4785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 4795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char **mg_get_valid_option_names(void) { 4815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return config_options; 4825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void *call_user(struct mg_connection *conn, enum mg_event event) { 4855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) conn->request_info.user_data = conn->ctx->user_data; 4865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return conn->ctx->user_callback == NULL ? NULL : 4875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) conn->ctx->user_callback(event, conn, &conn->request_info); 4885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int get_option_index(const char *name) { 4915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int i; 4925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (i = 0; config_options[i] != NULL; i += ENTRIES_PER_CONFIG_OPTION) { 4945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (strcmp(config_options[i], name) == 0 || 4955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) strcmp(config_options[i + 1], name) == 0) { 4965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return i / ENTRIES_PER_CONFIG_OPTION; 4975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return -1; 5005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char *mg_get_option(const struct mg_context *ctx, const char *name) { 5035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int i; 5045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if ((i = get_option_index(name)) == -1) { 5055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return NULL; 5065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (ctx->config[i] == NULL) { 5075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return ""; 5085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 5095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return ctx->config[i]; 5105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Print error message to the opened error log stream. 5145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void cry(struct mg_connection *conn, const char *fmt, ...) { 5155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) char buf[BUFSIZ]; 5165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) va_list ap; 5175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FILE *fp; 5185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) time_t timestamp; 5195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) va_start(ap, fmt); 5215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (void) vsnprintf(buf, sizeof(buf), fmt, ap); 5225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) va_end(ap); 5235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Do not lock when getting the callback value, here and below. 5255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // I suppose this is fine, since function cannot disappear in the 5265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // same way string option can. 5275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) conn->request_info.log_message = buf; 5285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (call_user(conn, MG_EVENT_LOG) == NULL) { 5295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fp = conn->ctx->config[ERROR_LOG_FILE] == NULL ? NULL : 5305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mg_fopen(conn->ctx->config[ERROR_LOG_FILE], "a+"); 5315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (fp != NULL) { 5335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) flockfile(fp); 5345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) timestamp = time(NULL); 5355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (void) fprintf(fp, 5375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "[%010lu] [error] [client %s] ", 5385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (unsigned long) timestamp, 5395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) inet_ntoa(conn->client.rsa.u.sin.sin_addr)); 5405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (conn->request_info.request_method != NULL) { 5425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (void) fprintf(fp, "%s %s: ", 5435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) conn->request_info.request_method, 5445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) conn->request_info.uri); 5455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (void) fprintf(fp, "%s", buf); 5485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fputc('\n', fp); 5495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) funlockfile(fp); 5505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (fp != stderr) { 5515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fclose(fp); 5525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) conn->request_info.log_message = NULL; 5565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Return OpenSSL error message 5595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const char *ssl_error(void) { 5605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unsigned long err; 5615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) err = ERR_get_error(); 5625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return err == 0 ? "" : ERR_error_string(err, NULL); 5635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Return fake connection structure. Used for logging, if connection 5665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// is not applicable at the moment of logging. 5675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static struct mg_connection *fc(struct mg_context *ctx) { 5685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static struct mg_connection fake_connection; 5695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fake_connection.ctx = ctx; 5705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return &fake_connection; 5715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char *mg_version(void) { 5745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return MONGOOSE_VERSION; 5755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void mg_strlcpy(register char *dst, register const char *src, size_t n) { 5785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (; *src != '\0' && n > 1; n--) { 5795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *dst++ = *src++; 5805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *dst = '\0'; 5825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int lowercase(const char *s) { 5855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return tolower(* (const unsigned char *) s); 5865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int mg_strncasecmp(const char *s1, const char *s2, size_t len) { 5895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int diff = 0; 5905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (len > 0) 5925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) do { 5935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) diff = lowercase(s1++) - lowercase(s2++); 5945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } while (diff == 0 && s1[-1] != '\0' && --len > 0); 5955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return diff; 5975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int mg_strcasecmp(const char *s1, const char *s2) { 6005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int diff; 6015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) do { 6035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) diff = lowercase(s1++) - lowercase(s2++); 6045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } while (diff == 0 && s1[-1] != '\0'); 6055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return diff; 6075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 6085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static char * mg_strndup(const char *ptr, size_t len) { 6105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) char *p; 6115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if ((p = (char *) malloc(len + 1)) != NULL) { 6135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mg_strlcpy(p, ptr, len + 1); 6145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 6155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return p; 6175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 6185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static char * mg_strdup(const char *str) { 6205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return mg_strndup(str, strlen(str)); 6215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 6225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Like snprintf(), but never returns negative value, or the value 6245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// that is larger than a supplied buffer. 6255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Thanks to Adam Zeldis to pointing snprintf()-caused vulnerability 6265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// in his audit report. 6275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int mg_vsnprintf(struct mg_connection *conn, char *buf, size_t buflen, 6285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char *fmt, va_list ap) { 6295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int n; 6305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (buflen == 0) 6325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 0; 6335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) n = vsnprintf(buf, buflen, fmt, ap); 6355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (n < 0) { 6375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cry(conn, "vsnprintf error"); 6385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) n = 0; 6395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (n >= (int) buflen) { 6405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cry(conn, "truncating vsnprintf buffer: [%.*s]", 6415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) n > 200 ? 200 : n, buf); 6425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) n = (int) buflen - 1; 6435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 6445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) buf[n] = '\0'; 6455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return n; 6475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 6485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int mg_snprintf(struct mg_connection *conn, char *buf, size_t buflen, 6505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char *fmt, ...) { 6515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) va_list ap; 6525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int n; 6535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) va_start(ap, fmt); 6555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) n = mg_vsnprintf(conn, buf, buflen, fmt, ap); 6565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) va_end(ap); 6575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return n; 6595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 6605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Skip the characters until one of the delimiters characters found. 6625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 0-terminate resulting word. Skip the delimiter and following whitespaces if any. 6635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Advance pointer to buffer to the next word. Return found 0-terminated word. 6645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Delimiters can be quoted with quotechar. 6655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static char *skip_quoted(char **buf, const char *delimiters, const char *whitespace, char quotechar) { 6665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) char *p, *begin_word, *end_word, *end_whitespace; 6675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) begin_word = *buf; 6695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) end_word = begin_word + strcspn(begin_word, delimiters); 6705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Check for quotechar 6725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (end_word > begin_word) { 6735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) p = end_word - 1; 6745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while (*p == quotechar) { 6755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If there is anything beyond end_word, copy it 6765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (*end_word == '\0') { 6775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *p = '\0'; 6785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 6795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 6805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size_t end_off = strcspn(end_word + 1, delimiters); 6815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) memmove (p, end_word, end_off + 1); 6825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) p += end_off; // p must correspond to end_word - 1 6835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) end_word += end_off + 1; 6845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 6855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 6865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (p++; p < end_word; p++) { 6875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *p = '\0'; 6885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 6895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 6905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (*end_word == '\0') { 6925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *buf = end_word; 6935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 6945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) end_whitespace = end_word + 1 + strspn(end_word + 1, whitespace); 6955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (p = end_word; p < end_whitespace; p++) { 6975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *p = '\0'; 6985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 6995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *buf = end_whitespace; 7015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 7025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return begin_word; 7045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 7055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Simplified version of skip_quoted without quote char 7075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// and whitespace == delimiters 7085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static char *skip(char **buf, const char *delimiters) { 7095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return skip_quoted(buf, delimiters, delimiters, 0); 7105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 7115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Return HTTP header value, or NULL if not found. 7145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const char *get_header(const struct mg_request_info *ri, 7155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char *name) { 7165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int i; 7175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (i = 0; i < ri->num_headers; i++) 7195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!mg_strcasecmp(name, ri->http_headers[i].name)) 7205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return ri->http_headers[i].value; 7215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return NULL; 7235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 7245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char *mg_get_header(const struct mg_connection *conn, const char *name) { 7265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return get_header(&conn->request_info, name); 7275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 7285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// A helper function for traversing comma separated list of values. 7305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// It returns a list pointer shifted to the next value, of NULL if the end 7315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// of the list found. 7325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Value is stored in val vector. If value has form "x=y", then eq_val 7335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// vector is initialized to point to the "y" part, and val vector length 7345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// is adjusted to point only to "x". 7355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const char *next_option(const char *list, struct vec *val, 7365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) struct vec *eq_val) { 7375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (list == NULL || *list == '\0') { 7385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // End of the list 7395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) list = NULL; 7405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 7415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) val->ptr = list; 7425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if ((list = strchr(val->ptr, ',')) != NULL) { 7435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Comma found. Store length and shift the list ptr 7445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) val->len = list - val->ptr; 7455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) list++; 7465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 7475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // This value is the last one 7485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) list = val->ptr + strlen(val->ptr); 7495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) val->len = list - val->ptr; 7505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 7515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (eq_val != NULL) { 7535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Value has form "x=y", adjust pointers and lengths 7545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // so that val points to "x", and eq_val points to "y". 7555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) eq_val->len = 0; 7565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) eq_val->ptr = (const char *) memchr(val->ptr, '=', val->len); 7575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (eq_val->ptr != NULL) { 7585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) eq_val->ptr++; // Skip over '=' character 7595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) eq_val->len = val->ptr + val->len - eq_val->ptr; 7605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) val->len = (eq_val->ptr - val->ptr) - 1; 7615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 7625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 7635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 7645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return list; 7665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 7675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int match_extension(const char *path, const char *ext_list) { 7695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) struct vec ext_vec; 7705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size_t path_len; 7715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) path_len = strlen(path); 7735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while ((ext_list = next_option(ext_list, &ext_vec, NULL)) != NULL) 7755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (ext_vec.len < path_len && 7765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mg_strncasecmp(path + path_len - ext_vec.len, 7775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ext_vec.ptr, ext_vec.len) == 0) 7785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 1; 7795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 0; 7815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 7825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// HTTP 1.1 assumes keep alive if "Connection:" header is not set 7845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// This function must tolerate situations when connection info is not 7855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// set up, for example if request parsing failed. 7865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int should_keep_alive(const struct mg_connection *conn) { 7875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char *http_version = conn->request_info.http_version; 7885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char *header = mg_get_header(conn, "Connection"); 7895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return (header == NULL && http_version && !strcmp(http_version, "1.1")) || 7905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (header != NULL && !mg_strcasecmp(header, "keep-alive")); 7915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 7925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const char *suggest_connection_header(const struct mg_connection *conn) { 7945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return should_keep_alive(conn) ? "keep-alive" : "close"; 7955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 7965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void send_http_error(struct mg_connection *conn, int status, 7985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char *reason, const char *fmt, ...) { 7995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) char buf[BUFSIZ]; 8005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) va_list ap; 8015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int len; 8025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) conn->request_info.status_code = status; 8045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (call_user(conn, MG_HTTP_ERROR) == NULL) { 8065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) buf[0] = '\0'; 8075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) len = 0; 8085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Errors 1xx, 204 and 304 MUST NOT send a body 8105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (status > 199 && status != 204 && status != 304) { 8115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) len = mg_snprintf(conn, buf, sizeof(buf), "Error %d: %s", status, reason); 8125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cry(conn, "%s", buf); 8135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) buf[len++] = '\n'; 8145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) va_start(ap, fmt); 8165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) len += mg_vsnprintf(conn, buf + len, sizeof(buf) - len, fmt, ap); 8175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) va_end(ap); 8185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 8195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DEBUG_TRACE(("[%s]", buf)); 8205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mg_printf(conn, "HTTP/1.1 %d %s\r\n" 8225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "Content-Type: text/plain\r\n" 8235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "Content-Length: %d\r\n" 8245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "Connection: %s\r\n\r\n", status, reason, len, 8255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) suggest_connection_header(conn)); 8265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) conn->num_bytes_sent += mg_printf(conn, "%s", buf); 8275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 8285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 8295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(_WIN32) && !defined(__SYMBIAN32__) 8315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int pthread_mutex_init(pthread_mutex_t *mutex, void *unused) { 8325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unused = NULL; 8335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *mutex = CreateMutex(NULL, FALSE, NULL); 8345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return *mutex == NULL ? -1 : 0; 8355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 8365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int pthread_mutex_destroy(pthread_mutex_t *mutex) { 8385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return CloseHandle(*mutex) == 0 ? -1 : 0; 8395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 8405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int pthread_mutex_lock(pthread_mutex_t *mutex) { 8425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return WaitForSingleObject(*mutex, INFINITE) == WAIT_OBJECT_0? 0 : -1; 8435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 8445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int pthread_mutex_unlock(pthread_mutex_t *mutex) { 8465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return ReleaseMutex(*mutex) == 0 ? -1 : 0; 8475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 8485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int pthread_cond_init(pthread_cond_t *cv, const void *unused) { 8505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unused = NULL; 8515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cv->signal = CreateEvent(NULL, FALSE, FALSE, NULL); 8525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cv->broadcast = CreateEvent(NULL, TRUE, FALSE, NULL); 8535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return cv->signal != NULL && cv->broadcast != NULL ? 0 : -1; 8545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 8555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int pthread_cond_wait(pthread_cond_t *cv, pthread_mutex_t *mutex) { 8575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HANDLE handles[2]; 8585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) handles[0] = cv->signal; 8595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) handles[1] = cv->broadcast; 8605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ReleaseMutex(*mutex); 8615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) WaitForMultipleObjects(2, handles, FALSE, INFINITE); 8625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return WaitForSingleObject(*mutex, INFINITE) == WAIT_OBJECT_0? 0 : -1; 8635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 8645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int pthread_cond_signal(pthread_cond_t *cv) { 8665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return SetEvent(cv->signal) == 0 ? -1 : 0; 8675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 8685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int pthread_cond_broadcast(pthread_cond_t *cv) { 8705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Implementation with PulseEvent() has race condition, see 8715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // http://www.cs.wustl.edu/~schmidt/win32-cv-1.html 8725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return PulseEvent(cv->broadcast) == 0 ? -1 : 0; 8735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 8745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int pthread_cond_destroy(pthread_cond_t *cv) { 8765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return CloseHandle(cv->signal) && CloseHandle(cv->broadcast) ? 0 : -1; 8775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 8785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// For Windows, change all slashes to backslashes in path names. 8805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void change_slashes_to_backslashes(char *path) { 8815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int i; 8825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (i = 0; path[i] != '\0'; i++) { 8845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (path[i] == '/') 8855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) path[i] = '\\'; 8865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // i > 0 check is to preserve UNC paths, like \\server\file.txt 8875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (path[i] == '\\' && i > 0) 8885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while (path[i + 1] == '\\' || path[i + 1] == '/') 8895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (void) memmove(path + i + 1, 8905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) path + i + 2, strlen(path + i + 1)); 8915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 8925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 8935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Encode 'path' which is assumed UTF-8 string, into UNICODE string. 8955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// wbuf and wbuf_len is a target buffer and its length. 8965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void to_unicode(const char *path, wchar_t *wbuf, size_t wbuf_len) { 8975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) char buf[PATH_MAX], buf2[PATH_MAX], *p; 8985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mg_strlcpy(buf, path, sizeof(buf)); 9005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) change_slashes_to_backslashes(buf); 9015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Point p to the end of the file name 9035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) p = buf + strlen(buf) - 1; 9045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Trim trailing backslash character 9065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while (p > buf && *p == '\\' && p[-1] != ':') { 9075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *p-- = '\0'; 9085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 9095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Protect from CGI code disclosure. 9115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // This is very nasty hole. Windows happily opens files with 9125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // some garbage in the end of file name. So fopen("a.cgi ", "r") 9135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // actually opens "a.cgi", and does not return an error! 9145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (*p == 0x20 || // No space at the end 9155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (*p == 0x2e && p > buf) || // No '.' but allow '.' as full path 9165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *p == 0x2b || // No '+' 9175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (*p & ~0x7f)) { // And generally no non-ascii chars 9185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (void) fprintf(stderr, "Rejecting suspicious path: [%s]", buf); 9195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) wbuf[0] = L'\0'; 9205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 9215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Convert to Unicode and back. If doubly-converted string does not 9225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // match the original, something is fishy, reject. 9235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MultiByteToWideChar(CP_UTF8, 0, buf, -1, wbuf, (int) wbuf_len); 9245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) WideCharToMultiByte(CP_UTF8, 0, wbuf, (int) wbuf_len, buf2, sizeof(buf2), 9255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NULL, NULL); 9265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (strcmp(buf, buf2) != 0) { 9275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) wbuf[0] = L'\0'; 9285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 9295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 9305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 9315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(_WIN32_WCE) 9335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static time_t time(time_t *ptime) { 9345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) time_t t; 9355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SYSTEMTIME st; 9365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FILETIME ft; 9375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GetSystemTime(&st); 9395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SystemTimeToFileTime(&st, &ft); 9405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) t = SYS2UNIX_TIME(ft.dwLowDateTime, ft.dwHighDateTime); 9415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (ptime != NULL) { 9435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *ptime = t; 9445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 9455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return t; 9475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 9485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static struct tm *localtime(const time_t *ptime, struct tm *ptm) { 9505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int64_t t = ((int64_t) *ptime) * RATE_DIFF + EPOCH_DIFF; 9515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FILETIME ft, lft; 9525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SYSTEMTIME st; 9535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TIME_ZONE_INFORMATION tzinfo; 9545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (ptm == NULL) { 9565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return NULL; 9575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 9585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * (int64_t *) &ft = t; 9605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FileTimeToLocalFileTime(&ft, &lft); 9615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FileTimeToSystemTime(&lft, &st); 9625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ptm->tm_year = st.wYear - 1900; 9635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ptm->tm_mon = st.wMonth - 1; 9645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ptm->tm_wday = st.wDayOfWeek; 9655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ptm->tm_mday = st.wDay; 9665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ptm->tm_hour = st.wHour; 9675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ptm->tm_min = st.wMinute; 9685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ptm->tm_sec = st.wSecond; 9695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ptm->tm_yday = 0; // hope nobody uses this 9705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ptm->tm_isdst = 9715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GetTimeZoneInformation(&tzinfo) == TIME_ZONE_ID_DAYLIGHT ? 1 : 0; 9725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return ptm; 9745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 9755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static struct tm *gmtime(const time_t *ptime, struct tm *ptm) { 9775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // FIXME(lsm): fix this. 9785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return localtime(ptime, ptm); 9795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 9805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static size_t strftime(char *dst, size_t dst_size, const char *fmt, 9825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const struct tm *tm) { 9835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (void) snprintf(dst, dst_size, "implement strftime() for WinCE"); 9845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 0; 9855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 9865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 9875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int mg_rename(const char* oldname, const char* newname) { 9895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) wchar_t woldbuf[PATH_MAX]; 9905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) wchar_t wnewbuf[PATH_MAX]; 9915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) to_unicode(oldname, woldbuf, ARRAY_SIZE(woldbuf)); 9935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) to_unicode(newname, wnewbuf, ARRAY_SIZE(wnewbuf)); 9945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return MoveFileW(woldbuf, wnewbuf) ? 0 : -1; 9965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 9975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static FILE *mg_fopen(const char *path, const char *mode) { 10005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) wchar_t wbuf[PATH_MAX], wmode[20]; 10015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) to_unicode(path, wbuf, ARRAY_SIZE(wbuf)); 10035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MultiByteToWideChar(CP_UTF8, 0, mode, -1, wmode, ARRAY_SIZE(wmode)); 10045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return _wfopen(wbuf, wmode); 10065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 10075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int mg_stat(const char *path, struct mgstat *stp) { 10095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int ok = -1; // Error 10105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) wchar_t wbuf[PATH_MAX]; 10115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) WIN32_FILE_ATTRIBUTE_DATA info; 10125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) to_unicode(path, wbuf, ARRAY_SIZE(wbuf)); 10145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (GetFileAttributesExW(wbuf, GetFileExInfoStandard, &info) != 0) { 10165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) stp->size = MAKEUQUAD(info.nFileSizeLow, info.nFileSizeHigh); 10175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) stp->mtime = SYS2UNIX_TIME(info.ftLastWriteTime.dwLowDateTime, 10185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) info.ftLastWriteTime.dwHighDateTime); 10195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) stp->is_directory = 10205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY; 10215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ok = 0; // Success 10225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 10235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return ok; 10255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 10265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int mg_remove(const char *path) { 10285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) wchar_t wbuf[PATH_MAX]; 10295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) to_unicode(path, wbuf, ARRAY_SIZE(wbuf)); 10305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return DeleteFileW(wbuf) ? 0 : -1; 10315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 10325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int mg_mkdir(const char *path, int mode) { 10345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) char buf[PATH_MAX]; 10355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) wchar_t wbuf[PATH_MAX]; 10365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mode = 0; // Unused 10385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mg_strlcpy(buf, path, sizeof(buf)); 10395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) change_slashes_to_backslashes(buf); 10405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (void) MultiByteToWideChar(CP_UTF8, 0, buf, -1, wbuf, sizeof(wbuf)); 10425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return CreateDirectoryW(wbuf, NULL) ? 0 : -1; 10445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 10455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Implementation of POSIX opendir/closedir/readdir for Windows. 10475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static DIR * opendir(const char *name) { 10485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DIR *dir = NULL; 10495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) wchar_t wpath[PATH_MAX]; 10505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DWORD attrs; 10515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (name == NULL) { 10535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SetLastError(ERROR_BAD_ARGUMENTS); 10545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if ((dir = (DIR *) malloc(sizeof(*dir))) == NULL) { 10555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SetLastError(ERROR_NOT_ENOUGH_MEMORY); 10565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 10575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) to_unicode(name, wpath, ARRAY_SIZE(wpath)); 10585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) attrs = GetFileAttributesW(wpath); 10595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (attrs != 0xFFFFFFFF && 10605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ((attrs & FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY)) { 10615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (void) wcscat(wpath, L"\\*"); 10625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dir->handle = FindFirstFileW(wpath, &dir->info); 10635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dir->result.d_name[0] = '\0'; 10645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 10655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) free(dir); 10665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dir = NULL; 10675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 10685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 10695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return dir; 10715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 10725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int closedir(DIR *dir) { 10745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int result = 0; 10755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (dir != NULL) { 10775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (dir->handle != INVALID_HANDLE_VALUE) 10785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) result = FindClose(dir->handle) ? 0 : -1; 10795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) free(dir); 10815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 10825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) result = -1; 10835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SetLastError(ERROR_BAD_ARGUMENTS); 10845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 10855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return result; 10875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 10885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)struct dirent * readdir(DIR *dir) { 10905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) struct dirent *result = 0; 10915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (dir) { 10935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (dir->handle != INVALID_HANDLE_VALUE) { 10945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) result = &dir->result; 10955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (void) WideCharToMultiByte(CP_UTF8, 0, 10965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dir->info.cFileName, -1, result->d_name, 10975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sizeof(result->d_name), NULL, NULL); 10985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!FindNextFileW(dir->handle, &dir->info)) { 11005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (void) FindClose(dir->handle); 11015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dir->handle = INVALID_HANDLE_VALUE; 11025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 11035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 11045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 11055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SetLastError(ERROR_FILE_NOT_FOUND); 11065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 11075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 11085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SetLastError(ERROR_BAD_ARGUMENTS); 11095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 11105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 11115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return result; 11125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 11135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 11145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define set_close_on_exec(fd) // No FD_CLOEXEC on Windows 11155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 11165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int start_thread(struct mg_context *ctx, mg_thread_func_t f, void *p) { 11175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return _beginthread((void (__cdecl *)(void *)) f, 0, p) == -1L ? -1 : 0; 11185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 11195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 11205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static HANDLE dlopen(const char *dll_name, int flags) { 11215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) wchar_t wbuf[PATH_MAX]; 11225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) flags = 0; // Unused 11235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) to_unicode(dll_name, wbuf, ARRAY_SIZE(wbuf)); 11245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return LoadLibraryW(wbuf); 11255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 11265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 11275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if !defined(NO_CGI) 11285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define SIGKILL 0 11295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int kill(pid_t pid, int sig_num) { 11305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (void) TerminateProcess(pid, sig_num); 11315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (void) CloseHandle(pid); 11325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 0; 11335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 11345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 11355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static pid_t spawn_process(struct mg_connection *conn, const char *prog, 11365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) char *envblk, char *envp[], int fd_stdin, 11375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int fd_stdout, const char *dir) { 11385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HANDLE me; 11395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) char *p, *interp, cmdline[PATH_MAX], buf[PATH_MAX]; 11405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FILE *fp; 11415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) STARTUPINFOA si; 11425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PROCESS_INFORMATION pi; 11435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 11445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) envp = NULL; // Unused 11455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 11465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (void) memset(&si, 0, sizeof(si)); 11475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (void) memset(&pi, 0, sizeof(pi)); 11485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 11495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // TODO(lsm): redirect CGI errors to the error log file 11505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) si.cb = sizeof(si); 11515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW; 11525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) si.wShowWindow = SW_HIDE; 11535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 11545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) me = GetCurrentProcess(); 11555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (void) DuplicateHandle(me, (HANDLE) _get_osfhandle(fd_stdin), me, 11565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) &si.hStdInput, 0, TRUE, DUPLICATE_SAME_ACCESS); 11575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (void) DuplicateHandle(me, (HANDLE) _get_osfhandle(fd_stdout), me, 11585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) &si.hStdOutput, 0, TRUE, DUPLICATE_SAME_ACCESS); 11595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 11605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If CGI file is a script, try to read the interpreter line 11615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) interp = conn->ctx->config[CGI_INTERPRETER]; 11625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (interp == NULL) { 11635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) buf[2] = '\0'; 11645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mg_snprintf(conn, cmdline, sizeof(cmdline), "%s%c%s", dir, DIRSEP, prog); 11655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if ((fp = fopen(cmdline, "r")) != NULL) { 11665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (void) fgets(buf, sizeof(buf), fp); 11675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (buf[0] != '#' || buf[1] != '!') { 11685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // First line does not start with "#!". Do not set interpreter. 11695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) buf[2] = '\0'; 11705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 11715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Trim whitespaces in interpreter name 11725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (p = &buf[strlen(buf) - 1]; p > buf && isspace(*p); p--) { 11735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *p = '\0'; 11745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 11755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 11765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (void) fclose(fp); 11775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 11785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) interp = buf + 2; 11795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 11805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 11815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (void) mg_snprintf(conn, cmdline, sizeof(cmdline), "%s%s%s%c%s", 11825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) interp, interp[0] == '\0' ? "" : " ", dir, DIRSEP, prog); 11835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 11845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DEBUG_TRACE(("Running [%s]", cmdline)); 11855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (CreateProcessA(NULL, cmdline, NULL, NULL, TRUE, 11865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CREATE_NEW_PROCESS_GROUP, envblk, dir, &si, &pi) == 0) { 11875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cry(conn, "%s: CreateProcess(%s): %d", 11885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) __func__, cmdline, ERRNO); 11895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pi.hProcess = (pid_t) -1; 11905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 11915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (void) close(fd_stdin); 11925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (void) close(fd_stdout); 11935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 11945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 11955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (void) CloseHandle(si.hStdOutput); 11965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (void) CloseHandle(si.hStdInput); 11975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (void) CloseHandle(pi.hThread); 11985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 11995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return (pid_t) pi.hProcess; 12005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 12015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif // !NO_CGI 12025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 12035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int set_non_blocking_mode(SOCKET sock) { 12045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unsigned long on = 1; 12055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return ioctlsocket(sock, FIONBIO, &on); 12065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 12075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 12085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#else 12095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int mg_stat(const char *path, struct mgstat *stp) { 12105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) struct stat st; 12115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int ok; 12125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 12135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (stat(path, &st) == 0) { 12145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ok = 0; 12155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) stp->size = st.st_size; 12165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) stp->mtime = st.st_mtime; 12175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) stp->is_directory = S_ISDIR(st.st_mode); 12185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 12195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ok = -1; 12205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 12215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 12225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return ok; 12235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 12245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 12255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void set_close_on_exec(int fd) { 12265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (void) fcntl(fd, F_SETFD, FD_CLOEXEC); 12275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 12285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 12295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int start_thread(struct mg_context *ctx, mg_thread_func_t func, 12305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void *param) { 12315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pthread_t thread_id; 12325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pthread_attr_t attr; 12335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int retval; 12345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 12355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (void) pthread_attr_init(&attr); 12365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (void) pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); 12375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // TODO(lsm): figure out why mongoose dies on Linux if next line is enabled 12385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // (void) pthread_attr_setstacksize(&attr, sizeof(struct mg_connection) * 5); 12395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 12405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if ((retval = pthread_create(&thread_id, &attr, func, param)) != 0) { 12415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cry(fc(ctx), "%s: %s", __func__, strerror(retval)); 12425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 12435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 12445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return retval; 12455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 12465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 12475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifndef NO_CGI 12485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static pid_t spawn_process(struct mg_connection *conn, const char *prog, 12495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) char *envblk, char *envp[], int fd_stdin, 12505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int fd_stdout, const char *dir) { 12515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pid_t pid; 12525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char *interp; 12535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 12545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) envblk = NULL; // Unused 12555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 12565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if ((pid = fork()) == -1) { 12575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Parent 12585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) send_http_error(conn, 500, http_500_error, "fork(): %s", strerror(ERRNO)); 12595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (pid == 0) { 12605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Child 12615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (chdir(dir) != 0) { 12625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cry(conn, "%s: chdir(%s): %s", __func__, dir, strerror(ERRNO)); 12635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (dup2(fd_stdin, 0) == -1) { 12645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cry(conn, "%s: dup2(%d, 0): %s", __func__, fd_stdin, strerror(ERRNO)); 12655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (dup2(fd_stdout, 1) == -1) { 12665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cry(conn, "%s: dup2(%d, 1): %s", __func__, fd_stdout, strerror(ERRNO)); 12675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 12685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (void) dup2(fd_stdout, 2); 12695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (void) close(fd_stdin); 12705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (void) close(fd_stdout); 12715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 12725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Execute CGI program. No need to lock: new process 12735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) interp = conn->ctx->config[CGI_INTERPRETER]; 12745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (interp == NULL) { 12755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (void) execle(prog, prog, NULL, envp); 12765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cry(conn, "%s: execle(%s): %s", __func__, prog, strerror(ERRNO)); 12775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 12785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (void) execle(interp, interp, prog, NULL, envp); 12795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cry(conn, "%s: execle(%s %s): %s", __func__, interp, prog, 12805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) strerror(ERRNO)); 12815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 12825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 12835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) exit(EXIT_FAILURE); 12845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 12855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Parent. Close stdio descriptors 12865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (void) close(fd_stdin); 12875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (void) close(fd_stdout); 12885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 12895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 12905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return pid; 12915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 12925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif // !NO_CGI 12935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 12945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int set_non_blocking_mode(SOCKET sock) { 12955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int flags; 12965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 12975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) flags = fcntl(sock, F_GETFL, 0); 12985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (void) fcntl(sock, F_SETFL, flags | O_NONBLOCK); 12995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 13005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 0; 13015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 13025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif // _WIN32 13035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 13045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Write data to the IO channel - opened file descriptor, socket or SSL 13055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// descriptor. Return number of bytes written. 13065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int64_t push(FILE *fp, SOCKET sock, SSL *ssl, const char *buf, 13075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int64_t len) { 13085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int64_t sent; 13095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int n, k; 13105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 13115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sent = 0; 13125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while (sent < len) { 13135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 13145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // How many bytes we send in this iteration 13155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) k = len - sent > INT_MAX ? INT_MAX : (int) (len - sent); 13165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 13175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (ssl != NULL) { 13185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) n = SSL_write(ssl, buf + sent, k); 13195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (fp != NULL) { 13205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) n = fwrite(buf + sent, 1, (size_t)k, fp); 13215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (ferror(fp)) 13225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) n = -1; 13235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 13245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) n = send(sock, buf + sent, (size_t)k, 0); 13255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 13265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 13275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (n < 0) 13285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 13295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 13305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sent += n; 13315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 13325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 13335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return sent; 13345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 13355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 13365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Read from IO channel - opened file descriptor, socket, or SSL descriptor. 13375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Return number of bytes read. 13385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int pull(FILE *fp, SOCKET sock, SSL *ssl, char *buf, int len) { 13395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int nread; 13405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 13415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (ssl != NULL) { 13425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) nread = SSL_read(ssl, buf, len); 13435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (fp != NULL) { 13445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Use read() instead of fread(), because if we're reading from the CGI 13455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // pipe, fread() may block until IO buffer is filled up. We cannot afford 13465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // to block and must pass all read bytes immediately to the client. 13475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) nread = read(fileno(fp), buf, (size_t) len); 13485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (ferror(fp)) 13495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) nread = -1; 13505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 13515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) nread = recv(sock, buf, (size_t) len, 0); 13525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 13535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 13545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return nread; 13555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 13565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 13575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int mg_read(struct mg_connection *conn, void *buf, size_t len) { 13585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int n, buffered_len, nread; 13595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char *buffered; 13605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 13615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) assert((conn->content_len == -1 && conn->consumed_content == 0) || 13625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) conn->consumed_content <= conn->content_len); 13635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DEBUG_TRACE(("%p %zu %lld %lld", buf, len, 13645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) conn->content_len, conn->consumed_content)); 13655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) nread = 0; 13665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (conn->consumed_content < conn->content_len) { 13675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 13685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Adjust number of bytes to read. 13695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int64_t to_read = conn->content_len - conn->consumed_content; 13705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (to_read < (int64_t) len) { 13715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) len = (int) to_read; 13725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 13735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 13745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // How many bytes of data we have buffered in the request buffer? 13755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) buffered = conn->buf + conn->request_len + conn->consumed_content; 13765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) buffered_len = conn->data_len - conn->request_len; 13775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) assert(buffered_len >= 0); 13785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 13795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Return buffered data back if we haven't done that yet. 13805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (conn->consumed_content < (int64_t) buffered_len) { 13815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) buffered_len -= (int) conn->consumed_content; 13825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (len < (size_t) buffered_len) { 13835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) buffered_len = len; 13845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 13855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) memcpy(buf, buffered, (size_t)buffered_len); 13865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) len -= buffered_len; 13875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) buf = (char *) buf + buffered_len; 13885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) conn->consumed_content += buffered_len; 13895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) nread = buffered_len; 13905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 13915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 13925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We have returned all buffered data. Read new data from the remote socket. 13935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while (len > 0) { 13945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) n = pull(NULL, conn->client.sock, conn->ssl, (char *) buf, (int) len); 13955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (n <= 0) { 13965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 13975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 13985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) buf = (char *) buf + n; 13995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) conn->consumed_content += n; 14005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) nread += n; 14015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) len -= n; 14025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 14035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 14045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return nread; 14055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 14065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 14075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int mg_write(struct mg_connection *conn, const void *buf, size_t len) { 14085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return (int) push(NULL, conn->client.sock, conn->ssl, 14095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (const char *) buf, (int64_t) len); 14105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 14115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 14125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int mg_printf(struct mg_connection *conn, const char *fmt, ...) { 14135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) char buf[BUFSIZ]; 14145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int len; 14155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) va_list ap; 14165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 14175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) va_start(ap, fmt); 14185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) len = mg_vsnprintf(conn, buf, sizeof(buf), fmt, ap); 14195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) va_end(ap); 14205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 14215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return mg_write(conn, buf, (size_t)len); 14225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 14235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 14245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// URL-decode input buffer into destination buffer. 14255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 0-terminate the destination buffer. Return the length of decoded data. 14265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// form-url-encoded data differs from URI encoding in a way that it 14275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// uses '+' as character for space, see RFC 1866 section 8.2.1 14285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// http://ftp.ics.uci.edu/pub/ietf/html/rfc1866.txt 14295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static size_t url_decode(const char *src, size_t src_len, char *dst, 14305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size_t dst_len, int is_form_url_encoded) { 14315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size_t i, j; 14325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int a, b; 14335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define HEXTOI(x) (isdigit(x) ? x - '0' : x - 'W') 14345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 14355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (i = j = 0; i < src_len && j < dst_len - 1; i++, j++) { 14365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (src[i] == '%' && 14375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) isxdigit(* (const unsigned char *) (src + i + 1)) && 14385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) isxdigit(* (const unsigned char *) (src + i + 2))) { 14395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) a = tolower(* (const unsigned char *) (src + i + 1)); 14405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) b = tolower(* (const unsigned char *) (src + i + 2)); 14415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dst[j] = (char) ((HEXTOI(a) << 4) | HEXTOI(b)); 14425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) i += 2; 14435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (is_form_url_encoded && src[i] == '+') { 14445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dst[j] = ' '; 14455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 14465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dst[j] = src[i]; 14475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 14485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 14495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 14505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dst[j] = '\0'; // Null-terminate the destination 14515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 14525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return j; 14535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 14545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 14555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Scan given buffer and fetch the value of the given variable. 14565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// It can be specified in query string, or in the POST data. 14575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Return NULL if the variable not found, or allocated 0-terminated value. 14585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// It is caller's responsibility to free the returned value. 14595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int mg_get_var(const char *buf, size_t buf_len, const char *name, 14605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) char *dst, size_t dst_len) { 14615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char *p, *e, *s; 14625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size_t name_len, len; 14635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 14645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) name_len = strlen(name); 14655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) e = buf + buf_len; 14665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) len = -1; 14675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dst[0] = '\0'; 14685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 14695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // buf is "var1=val1&var2=val2...". Find variable first 14705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (p = buf; p != NULL && p + name_len < e; p++) { 14715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if ((p == buf || p[-1] == '&') && p[name_len] == '=' && 14725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) !mg_strncasecmp(name, p, name_len)) { 14735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 14745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Point p to variable value 14755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) p += name_len + 1; 14765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 14775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Point s to the end of the value 14785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) s = (const char *) memchr(p, '&', (size_t)(e - p)); 14795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (s == NULL) { 14805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) s = e; 14815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 14825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) assert(s >= p); 14835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 14845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Decode variable into destination buffer 14855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if ((size_t) (s - p) < dst_len) { 14865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) len = url_decode(p, (size_t)(s - p), dst, dst_len, 1); 14875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 14885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 14895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 14905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 14915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 14925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return len; 14935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 14945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 14955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int mg_get_cookie(const struct mg_connection *conn, const char *cookie_name, 14965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) char *dst, size_t dst_size) { 14975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char *s, *p, *end; 14985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int name_len, len = -1; 14995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 15005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dst[0] = '\0'; 15015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if ((s = mg_get_header(conn, "Cookie")) == NULL) { 15025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 0; 15035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 15045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 15055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) name_len = strlen(cookie_name); 15065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) end = s + strlen(s); 15075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 15085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (; (s = strstr(s, cookie_name)) != NULL; s += name_len) 15095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (s[name_len] == '=') { 15105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) s += name_len + 1; 15115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if ((p = strchr(s, ' ')) == NULL) 15125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) p = end; 15135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (p[-1] == ';') 15145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) p--; 15155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (*s == '"' && p[-1] == '"' && p > s + 1) { 15165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) s++; 15175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) p--; 15185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 15195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if ((size_t) (p - s) < dst_size) { 15205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) len = (p - s) + 1; 15215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mg_strlcpy(dst, s, (size_t)len); 15225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 15235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 15245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 15255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 15265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return len; 15275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 15285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 15295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Mongoose allows to specify multiple directories to serve, 15305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// like /var/www,/~bob=/home/bob. That means that root directory depends on URI. 15315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// This function returns root dir for given URI. 15325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int get_document_root(const struct mg_connection *conn, 15335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) struct vec *document_root) { 15345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char *root, *uri; 15355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int len_of_matched_uri; 15365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) struct vec uri_vec, path_vec; 15375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 15385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) uri = conn->request_info.uri; 15395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) len_of_matched_uri = 0; 15405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) root = next_option(conn->ctx->config[DOCUMENT_ROOT], document_root, NULL); 15415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 15425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while ((root = next_option(root, &uri_vec, &path_vec)) != NULL) { 15435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (memcmp(uri, uri_vec.ptr, uri_vec.len) == 0) { 15445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *document_root = path_vec; 15455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) len_of_matched_uri = uri_vec.len; 15465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 15475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 15485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 15495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 15505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return len_of_matched_uri; 15515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 15525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 15535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void convert_uri_to_file_name(struct mg_connection *conn, 15545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char *uri, char *buf, 15555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size_t buf_len) { 15565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) struct vec vec; 15575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int match_len; 15585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 15595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) match_len = get_document_root(conn, &vec); 15605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mg_snprintf(conn, buf, buf_len, "%.*s%s", vec.len, vec.ptr, uri + match_len); 15615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 15625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(_WIN32) && !defined(__SYMBIAN32__) 15635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) change_slashes_to_backslashes(buf); 15645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif // _WIN32 15655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 15665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DEBUG_TRACE(("[%s] -> [%s], [%.*s]", uri, buf, (int) vec.len, vec.ptr)); 15675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 15685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 15695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int sslize(struct mg_connection *conn, int (*func)(SSL *)) { 15705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return (conn->ssl = SSL_new(conn->ctx->ssl_ctx)) != NULL && 15715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SSL_set_fd(conn->ssl, conn->client.sock) == 1 && 15725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) func(conn->ssl) == 1; 15735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 15745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 15755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static struct mg_connection *mg_connect(struct mg_connection *conn, 15765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char *host, int port, int use_ssl) { 15775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) struct mg_connection *newconn = NULL; 15785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) struct sockaddr_in sin; 15795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) struct hostent *he; 15805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int sock; 15815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 15825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (conn->ctx->ssl_ctx == NULL && use_ssl) { 15835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cry(conn, "%s: SSL is not initialized", __func__); 15845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if ((he = gethostbyname(host)) == NULL) { 15855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cry(conn, "%s: gethostbyname(%s): %s", __func__, host, strerror(ERRNO)); 15865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if ((sock = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) { 15875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cry(conn, "%s: socket: %s", __func__, strerror(ERRNO)); 15885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 15895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sin.sin_family = AF_INET; 15905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sin.sin_port = htons((uint16_t) port); 15915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sin.sin_addr = * (struct in_addr *) he->h_addr_list[0]; 15925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (connect(sock, (struct sockaddr *) &sin, sizeof(sin)) != 0) { 15935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cry(conn, "%s: connect(%s:%d): %s", __func__, host, port, 15945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) strerror(ERRNO)); 15955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) closesocket(sock); 15965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if ((newconn = (struct mg_connection *) 15975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) calloc(1, sizeof(*newconn))) == NULL) { 15985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cry(conn, "%s: calloc: %s", __func__, strerror(ERRNO)); 15995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) closesocket(sock); 16005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 16015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) newconn->client.sock = sock; 16025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) newconn->client.rsa.u.sin = sin; 16035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (use_ssl) { 16045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sslize(newconn, SSL_connect); 16055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 16065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 16075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 16085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 16095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return newconn; 16105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 16115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 16125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Check whether full request is buffered. Return: 16135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// -1 if request is malformed 16145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 0 if request is not yet fully buffered 16155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// >0 actual request length, including last \r\n\r\n 16165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int get_request_len(const char *buf, int buflen) { 16175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char *s, *e; 16185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int len = 0; 16195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 16205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DEBUG_TRACE(("buf: %p, len: %d", buf, buflen)); 16215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (s = buf, e = s + buflen - 1; len <= 0 && s < e; s++) 16225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Control characters are not allowed but >=128 is. 16235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!isprint(* (const unsigned char *) s) && *s != '\r' && 16245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *s != '\n' && * (const unsigned char *) s < 128) { 16255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) len = -1; 16265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (s[0] == '\n' && s[1] == '\n') { 16275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) len = (int) (s - buf) + 2; 16285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (s[0] == '\n' && &s[1] < e && 16295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) s[1] == '\r' && s[2] == '\n') { 16305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) len = (int) (s - buf) + 3; 16315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 16325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 16335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return len; 16345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 16355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 16365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Convert month to the month number. Return -1 on error, or month number 16375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int get_month_index(const char *s) { 16385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size_t i; 16395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 16405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (i = 0; i < ARRAY_SIZE(month_names); i++) 16415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!strcmp(s, month_names[i])) 16425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return (int) i; 16435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 16445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return -1; 16455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 16465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 16475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Parse UTC date-time string, and return the corresponding time_t value. 16485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static time_t parse_date_string(const char *datetime) { 16495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static const unsigned short days_before_month[] = { 16505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 16515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }; 16525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) char month_str[32]; 16535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int second, minute, hour, day, month, year, leap_days, days; 16545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) time_t result = (time_t) 0; 16555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 16565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (((sscanf(datetime, "%d/%3s/%d %d:%d:%d", 16575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) &day, month_str, &year, &hour, &minute, &second) == 6) || 16585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (sscanf(datetime, "%d %3s %d %d:%d:%d", 16595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) &day, month_str, &year, &hour, &minute, &second) == 6) || 16605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (sscanf(datetime, "%*3s, %d %3s %d %d:%d:%d", 16615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) &day, month_str, &year, &hour, &minute, &second) == 6) || 16625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (sscanf(datetime, "%d-%3s-%d %d:%d:%d", 16635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) &day, month_str, &year, &hour, &minute, &second) == 6)) && 16645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) year > 1970 && 16655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (month = get_month_index(month_str)) != -1) { 16665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) year -= 1970; 16675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) leap_days = year / 4 - year / 100 + year / 400; 16685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) days = year * 365 + days_before_month[month] + (day - 1) + leap_days; 16695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) result = days * 24 * 3600 + hour * 3600 + minute * 60 + second; 16705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 16715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 16725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return result; 16735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 16745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 16755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Protect against directory disclosure attack by removing '..', 16765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// excessive '/' and '\' characters 16775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void remove_double_dots_and_double_slashes(char *s) { 16785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) char *p = s; 16795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 16805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while (*s != '\0') { 16815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *p++ = *s++; 16825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (s[-1] == '/' || s[-1] == '\\') { 16835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Skip all following slashes and backslashes 16845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while (*s == '/' || *s == '\\') { 16855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) s++; 16865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 16875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 16885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Skip all double-dots 16895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while (*s == '.' && s[1] == '.') { 16905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) s += 2; 16915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 16925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 16935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 16945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *p = '\0'; 16955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 16965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 16975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const struct { 16985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char *extension; 16995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size_t ext_len; 17005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char *mime_type; 17015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size_t mime_type_len; 17025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} builtin_mime_types[] = { 17035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) {".html", 5, "text/html", 9}, 17045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) {".htm", 4, "text/html", 9}, 17055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) {".shtm", 5, "text/html", 9}, 17065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) {".shtml", 6, "text/html", 9}, 17075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) {".css", 4, "text/css", 8}, 17085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) {".js", 3, "application/x-javascript", 24}, 17095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) {".ico", 4, "image/x-icon", 12}, 17105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) {".gif", 4, "image/gif", 9}, 17115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) {".jpg", 4, "image/jpeg", 10}, 17125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) {".jpeg", 5, "image/jpeg", 10}, 17135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) {".png", 4, "image/png", 9}, 17145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) {".svg", 4, "image/svg+xml", 13}, 17155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) {".torrent", 8, "application/x-bittorrent", 24}, 17165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) {".wav", 4, "audio/x-wav", 11}, 17175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) {".mp3", 4, "audio/x-mp3", 11}, 17185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) {".mid", 4, "audio/mid", 9}, 17195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) {".m3u", 4, "audio/x-mpegurl", 15}, 17205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) {".ram", 4, "audio/x-pn-realaudio", 20}, 17215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) {".xml", 4, "text/xml", 8}, 17225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) {".xslt", 5, "application/xml", 15}, 17235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) {".ra", 3, "audio/x-pn-realaudio", 20}, 17245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) {".doc", 4, "application/msword", 19}, 17255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) {".exe", 4, "application/octet-stream", 24}, 17265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) {".zip", 4, "application/x-zip-compressed", 28}, 17275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) {".xls", 4, "application/excel", 17}, 17285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) {".tgz", 4, "application/x-tar-gz", 20}, 17295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) {".tar", 4, "application/x-tar", 17}, 17305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) {".gz", 3, "application/x-gunzip", 20}, 17315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) {".arj", 4, "application/x-arj-compressed", 28}, 17325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) {".rar", 4, "application/x-arj-compressed", 28}, 17335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) {".rtf", 4, "application/rtf", 15}, 17345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) {".pdf", 4, "application/pdf", 15}, 17355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) {".swf", 4, "application/x-shockwave-flash",29}, 17365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) {".mpg", 4, "video/mpeg", 10}, 17375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) {".mpeg", 5, "video/mpeg", 10}, 17385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) {".mp4", 4, "video/mp4", 9}, 17395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) {".m4v", 4, "video/x-m4v", 11}, 17405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) {".asf", 4, "video/x-ms-asf", 14}, 17415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) {".avi", 4, "video/x-msvideo", 15}, 17425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) {".bmp", 4, "image/bmp", 9}, 17435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) {NULL, 0, NULL, 0} 17445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 17455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 17465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Look at the "path" extension and figure what mime type it has. 17475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Store mime type in the vector. 17485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void get_mime_type(struct mg_context *ctx, const char *path, 17495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) struct vec *vec) { 17505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) struct vec ext_vec, mime_vec; 17515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char *list, *ext; 17525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size_t i, path_len; 17535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 17545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) path_len = strlen(path); 17555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 17565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Scan user-defined mime types first, in case user wants to 17575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // override default mime types. 17585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) list = ctx->config[EXTRA_MIME_TYPES]; 17595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while ((list = next_option(list, &ext_vec, &mime_vec)) != NULL) { 17605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // ext now points to the path suffix 17615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ext = path + path_len - ext_vec.len; 17625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (mg_strncasecmp(ext, ext_vec.ptr, ext_vec.len) == 0) { 17635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *vec = mime_vec; 17645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 17655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 17665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 17675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 17685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Now scan built-in mime types 17695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (i = 0; builtin_mime_types[i].extension != NULL; i++) { 17705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ext = path + (path_len - builtin_mime_types[i].ext_len); 17715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (path_len > builtin_mime_types[i].ext_len && 17725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mg_strcasecmp(ext, builtin_mime_types[i].extension) == 0) { 17735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) vec->ptr = builtin_mime_types[i].mime_type; 17745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) vec->len = builtin_mime_types[i].mime_type_len; 17755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 17765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 17775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 17785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 17795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Nothing found. Fall back to "text/plain" 17805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) vec->ptr = "text/plain"; 17815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) vec->len = 10; 17825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 17835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 17845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifndef HAVE_MD5 17855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)typedef struct MD5Context { 17865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) uint32_t buf[4]; 17875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) uint32_t bits[2]; 17885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unsigned char in[64]; 17895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} MD5_CTX; 17905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 17915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(__BYTE_ORDER) && (__BYTE_ORDER == 1234) 17925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define byteReverse(buf, len) // Do nothing 17935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#else 17945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void byteReverse(unsigned char *buf, unsigned longs) { 17955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) uint32_t t; 17965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) do { 17975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) t = (uint32_t) ((unsigned) buf[3] << 8 | buf[2]) << 16 | 17985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ((unsigned) buf[1] << 8 | buf[0]); 17995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *(uint32_t *) buf = t; 18005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) buf += 4; 18015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } while (--longs); 18025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 18035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 18045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 18055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define F1(x, y, z) (z ^ (x & (y ^ z))) 18065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define F2(x, y, z) F1(z, x, y) 18075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define F3(x, y, z) (x ^ y ^ z) 18085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define F4(x, y, z) (y ^ (x | ~z)) 18095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 18105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define MD5STEP(f, w, x, y, z, data, s) \ 18115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ( w += f(x, y, z) + data, w = w<<s | w>>(32-s), w += x ) 18125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 18135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Start MD5 accumulation. Set bit count to 0 and buffer to mysterious 18145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// initialization constants. 18155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void MD5Init(MD5_CTX *ctx) { 18165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ctx->buf[0] = 0x67452301; 18175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ctx->buf[1] = 0xefcdab89; 18185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ctx->buf[2] = 0x98badcfe; 18195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ctx->buf[3] = 0x10325476; 18205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 18215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ctx->bits[0] = 0; 18225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ctx->bits[1] = 0; 18235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 18245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 18255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void MD5Transform(uint32_t buf[4], uint32_t const in[16]) { 18265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) register uint32_t a, b, c, d; 18275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 18285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) a = buf[0]; 18295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) b = buf[1]; 18305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) c = buf[2]; 18315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) d = buf[3]; 18325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 18335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7); 18345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12); 18355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17); 18365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22); 18375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7); 18385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12); 18395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17); 18405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22); 18415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7); 18425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12); 18435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17); 18445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22); 18455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7); 18465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12); 18475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17); 18485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22); 18495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 18505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5); 18515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9); 18525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14); 18535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20); 18545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5); 18555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9); 18565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14); 18575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20); 18585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5); 18595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9); 18605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14); 18615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20); 18625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5); 18635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9); 18645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14); 18655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20); 18665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 18675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4); 18685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11); 18695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16); 18705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23); 18715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4); 18725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11); 18735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16); 18745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23); 18755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4); 18765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11); 18775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16); 18785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23); 18795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4); 18805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11); 18815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16); 18825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23); 18835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 18845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6); 18855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10); 18865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15); 18875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21); 18885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6); 18895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10); 18905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15); 18915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21); 18925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6); 18935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10); 18945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15); 18955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21); 18965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6); 18975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10); 18985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15); 18995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21); 19005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 19015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) buf[0] += a; 19025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) buf[1] += b; 19035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) buf[2] += c; 19045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) buf[3] += d; 19055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 19065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 19075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void MD5Update(MD5_CTX *ctx, unsigned char const *buf, unsigned len) { 19085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) uint32_t t; 19095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 19105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) t = ctx->bits[0]; 19115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if ((ctx->bits[0] = t + ((uint32_t) len << 3)) < t) 19125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ctx->bits[1]++; 19135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ctx->bits[1] += len >> 29; 19145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 19155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) t = (t >> 3) & 0x3f; 19165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 19175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (t) { 19185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unsigned char *p = (unsigned char *) ctx->in + t; 19195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 19205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) t = 64 - t; 19215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (len < t) { 19225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) memcpy(p, buf, len); 19235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 19245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 19255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) memcpy(p, buf, t); 19265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) byteReverse(ctx->in, 16); 19275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MD5Transform(ctx->buf, (uint32_t *) ctx->in); 19285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) buf += t; 19295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) len -= t; 19305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 19315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 19325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while (len >= 64) { 19335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) memcpy(ctx->in, buf, 64); 19345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) byteReverse(ctx->in, 16); 19355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MD5Transform(ctx->buf, (uint32_t *) ctx->in); 19365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) buf += 64; 19375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) len -= 64; 19385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 19395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 19405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) memcpy(ctx->in, buf, len); 19415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 19425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 19435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void MD5Final(unsigned char digest[16], MD5_CTX *ctx) { 19445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unsigned count; 19455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unsigned char *p; 19465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 19475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) count = (ctx->bits[0] >> 3) & 0x3F; 19485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 19495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) p = ctx->in + count; 19505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *p++ = 0x80; 19515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) count = 64 - 1 - count; 19525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (count < 8) { 19535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) memset(p, 0, count); 19545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) byteReverse(ctx->in, 16); 19555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MD5Transform(ctx->buf, (uint32_t *) ctx->in); 19565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) memset(ctx->in, 0, 56); 19575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 19585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) memset(p, 0, count - 8); 19595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 19605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) byteReverse(ctx->in, 14); 19615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 19625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ((uint32_t *) ctx->in)[14] = ctx->bits[0]; 19635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ((uint32_t *) ctx->in)[15] = ctx->bits[1]; 19645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 19655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MD5Transform(ctx->buf, (uint32_t *) ctx->in); 19665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) byteReverse((unsigned char *) ctx->buf, 4); 19675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) memcpy(digest, ctx->buf, 16); 19685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) memset((char *) ctx, 0, sizeof(*ctx)); 19695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 19705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif // !HAVE_MD5 19715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 19725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Stringify binary data. Output buffer must be twice as big as input, 19735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// because each byte takes 2 bytes in string representation 19745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void bin2str(char *to, const unsigned char *p, size_t len) { 19755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static const char *hex = "0123456789abcdef"; 19765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 19775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (; len--; p++) { 19785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *to++ = hex[p[0] >> 4]; 19795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *to++ = hex[p[0] & 0x0f]; 19805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 19815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *to = '\0'; 19825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 19835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 19845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Return stringified MD5 hash for list of vectors. Buffer must be 33 bytes. 19855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void mg_md5(char *buf, ...) { 19865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unsigned char hash[16]; 19875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char *p; 19885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) va_list ap; 19895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MD5_CTX ctx; 19905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 19915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MD5Init(&ctx); 19925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 19935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) va_start(ap, buf); 19945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while ((p = va_arg(ap, const char *)) != NULL) { 19955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MD5Update(&ctx, (const unsigned char *) p, (unsigned) strlen(p)); 19965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 19975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) va_end(ap); 19985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 19995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MD5Final(hash, &ctx); 20005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bin2str(buf, hash, sizeof(hash)); 20015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 20025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 20035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Check the user's password, return 1 if OK 20045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int check_password(const char *method, const char *ha1, const char *uri, 20055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char *nonce, const char *nc, const char *cnonce, 20065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char *qop, const char *response) { 20075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) char ha2[32 + 1], expected_response[32 + 1]; 20085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 20095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Some of the parameters may be NULL 20105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (method == NULL || nonce == NULL || nc == NULL || cnonce == NULL || 20115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) qop == NULL || response == NULL) { 20125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 0; 20135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 20145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 20155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // NOTE(lsm): due to a bug in MSIE, we do not compare the URI 20165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // TODO(lsm): check for authentication timeout 20175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (// strcmp(dig->uri, c->ouri) != 0 || 20185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) strlen(response) != 32 20195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // || now - strtoul(dig->nonce, NULL, 10) > 3600 20205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ) { 20215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 0; 20225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 20235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 20245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mg_md5(ha2, method, ":", uri, NULL); 20255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mg_md5(expected_response, ha1, ":", nonce, ":", nc, 20265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ":", cnonce, ":", qop, ":", ha2, NULL); 20275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 20285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return mg_strcasecmp(response, expected_response) == 0; 20295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 20305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 20315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use the global passwords file, if specified by auth_gpass option, 20325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// or search for .htpasswd in the requested directory. 20335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static FILE *open_auth_file(struct mg_connection *conn, const char *path) { 20345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) struct mg_context *ctx = conn->ctx; 20355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) char name[PATH_MAX]; 20365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char *p, *e; 20375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) struct mgstat st; 20385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FILE *fp; 20395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 20405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (ctx->config[GLOBAL_PASSWORDS_FILE] != NULL) { 20415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Use global passwords file 20425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fp = mg_fopen(ctx->config[GLOBAL_PASSWORDS_FILE], "r"); 20435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (fp == NULL) 20445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cry(fc(ctx), "fopen(%s): %s", 20455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ctx->config[GLOBAL_PASSWORDS_FILE], strerror(ERRNO)); 20465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (!mg_stat(path, &st) && st.is_directory) { 20475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (void) mg_snprintf(conn, name, sizeof(name), "%s%c%s", 20485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) path, DIRSEP, PASSWORDS_FILE_NAME); 20495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fp = mg_fopen(name, "r"); 20505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 20515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Try to find .htpasswd in requested directory. 20525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (p = path, e = p + strlen(p) - 1; e > p; e--) 20535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (IS_DIRSEP_CHAR(*e)) 20545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 20555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (void) mg_snprintf(conn, name, sizeof(name), "%.*s%c%s", 20565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (int) (e - p), p, DIRSEP, PASSWORDS_FILE_NAME); 20575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fp = mg_fopen(name, "r"); 20585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 20595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 20605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return fp; 20615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 20625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 20635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Parsed Authorization header 20645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)struct ah { 20655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) char *user, *uri, *cnonce, *response, *qop, *nc, *nonce; 20665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 20675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 20685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int parse_auth_header(struct mg_connection *conn, char *buf, 20695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size_t buf_size, struct ah *ah) { 20705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) char *name, *value, *s; 20715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char *auth_header; 20725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 20735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if ((auth_header = mg_get_header(conn, "Authorization")) == NULL || 20745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mg_strncasecmp(auth_header, "Digest ", 7) != 0) { 20755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 0; 20765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 20775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 20785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Make modifiable copy of the auth header 20795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (void) mg_strlcpy(buf, auth_header + 7, buf_size); 20805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 20815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) s = buf; 20825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (void) memset(ah, 0, sizeof(*ah)); 20835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 20845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Parse authorization header 20855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (;;) { 20865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Gobble initial spaces 20875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while (isspace(* (unsigned char *) s)) { 20885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) s++; 20895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 20905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) name = skip_quoted(&s, "=", " ", 0); 20915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Value is either quote-delimited, or ends at first comma or space. 20925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (s[0] == '\"') { 20935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) s++; 20945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) value = skip_quoted(&s, "\"", " ", '\\'); 20955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (s[0] == ',') { 20965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) s++; 20975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 20985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 20995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) value = skip_quoted(&s, ", ", " ", 0); // IE uses commas, FF uses spaces 21005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 21015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (*name == '\0') { 21025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 21035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 21045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 21055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!strcmp(name, "username")) { 21065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ah->user = value; 21075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (!strcmp(name, "cnonce")) { 21085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ah->cnonce = value; 21095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (!strcmp(name, "response")) { 21105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ah->response = value; 21115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (!strcmp(name, "uri")) { 21125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ah->uri = value; 21135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (!strcmp(name, "qop")) { 21145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ah->qop = value; 21155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (!strcmp(name, "nc")) { 21165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ah->nc = value; 21175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (!strcmp(name, "nonce")) { 21185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ah->nonce = value; 21195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 21205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 21215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 21225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // CGI needs it as REMOTE_USER 21235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (ah->user != NULL) { 21245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) conn->request_info.remote_user = mg_strdup(ah->user); 21255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 21265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 0; 21275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 21285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 21295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 1; 21305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 21315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 21325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Authorize against the opened passwords file. Return 1 if authorized. 21335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int authorize(struct mg_connection *conn, FILE *fp) { 21345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) struct ah ah; 21355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) char line[256], f_user[256], ha1[256], f_domain[256], buf[BUFSIZ]; 21365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 21375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!parse_auth_header(conn, buf, sizeof(buf), &ah)) { 21385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 0; 21395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 21405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 21415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Loop over passwords file 21425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while (fgets(line, sizeof(line), fp) != NULL) { 21435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (sscanf(line, "%[^:]:%[^:]:%s", f_user, f_domain, ha1) != 3) { 21445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) continue; 21455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 21465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 21475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!strcmp(ah.user, f_user) && 21485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) !strcmp(conn->ctx->config[AUTHENTICATION_DOMAIN], f_domain)) 21495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return check_password( 21505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) conn->request_info.request_method, 21515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ha1, ah.uri, ah.nonce, ah.nc, ah.cnonce, ah.qop, 21525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ah.response); 21535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 21545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 21555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 0; 21565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 21575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 21585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Return 1 if request is authorised, 0 otherwise. 21595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int check_authorization(struct mg_connection *conn, const char *path) { 21605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FILE *fp; 21615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) char fname[PATH_MAX]; 21625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) struct vec uri_vec, filename_vec; 21635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char *list; 21645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int authorized; 21655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 21665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fp = NULL; 21675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) authorized = 1; 21685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 21695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) list = conn->ctx->config[PROTECT_URI]; 21705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while ((list = next_option(list, &uri_vec, &filename_vec)) != NULL) { 21715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!memcmp(conn->request_info.uri, uri_vec.ptr, uri_vec.len)) { 21725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (void) mg_snprintf(conn, fname, sizeof(fname), "%.*s", 21735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) filename_vec.len, filename_vec.ptr); 21745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if ((fp = mg_fopen(fname, "r")) == NULL) { 21755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cry(conn, "%s: cannot open %s: %s", __func__, fname, strerror(errno)); 21765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 21775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 21785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 21795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 21805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 21815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (fp == NULL) { 21825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fp = open_auth_file(conn, path); 21835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 21845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 21855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (fp != NULL) { 21865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) authorized = authorize(conn, fp); 21875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (void) fclose(fp); 21885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 21895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 21905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return authorized; 21915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 21925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 21935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void send_authorization_request(struct mg_connection *conn) { 21945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) conn->request_info.status_code = 401; 21955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (void) mg_printf(conn, 21965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "HTTP/1.1 401 Unauthorized\r\n" 21975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "Content-Length: 0\r\n" 21985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "WWW-Authenticate: Digest qop=\"auth\", " 21995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "realm=\"%s\", nonce=\"%lu\"\r\n\r\n", 22005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) conn->ctx->config[AUTHENTICATION_DOMAIN], 22015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (unsigned long) time(NULL)); 22025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 22035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 22045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int is_authorized_for_put(struct mg_connection *conn) { 22055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FILE *fp; 22065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int ret = 0; 22075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 22085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fp = conn->ctx->config[PUT_DELETE_PASSWORDS_FILE] == NULL ? NULL : 22095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mg_fopen(conn->ctx->config[PUT_DELETE_PASSWORDS_FILE], "r"); 22105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 22115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (fp != NULL) { 22125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ret = authorize(conn, fp); 22135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (void) fclose(fp); 22145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 22155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 22165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return ret; 22175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 22185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 22195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int mg_modify_passwords_file(const char *fname, const char *domain, 22205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char *user, const char *pass) { 22215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int found; 22225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) char line[512], u[512], d[512], ha1[33], tmp[PATH_MAX]; 22235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FILE *fp, *fp2; 22245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 22255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) found = 0; 22265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fp = fp2 = NULL; 22275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 22285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Regard empty password as no password - remove user record. 22295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (pass != NULL && pass[0] == '\0') { 22305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pass = NULL; 22315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 22325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 22335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (void) snprintf(tmp, sizeof(tmp), "%s.tmp", fname); 22345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 22355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Create the file if does not exist 22365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if ((fp = mg_fopen(fname, "a+")) != NULL) { 22375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (void) fclose(fp); 22385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 22395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 22405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Open the given file and temporary file 22415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if ((fp = mg_fopen(fname, "r")) == NULL) { 22425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 0; 22435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if ((fp2 = mg_fopen(tmp, "w+")) == NULL) { 22445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fclose(fp); 22455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 0; 22465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 22475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 22485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Copy the stuff to temporary file 22495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while (fgets(line, sizeof(line), fp) != NULL) { 22505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (sscanf(line, "%[^:]:%[^:]:%*s", u, d) != 2) { 22515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) continue; 22525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 22535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 22545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!strcmp(u, user) && !strcmp(d, domain)) { 22555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) found++; 22565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (pass != NULL) { 22575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mg_md5(ha1, user, ":", domain, ":", pass, NULL); 22585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fprintf(fp2, "%s:%s:%s\n", user, domain, ha1); 22595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 22605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 22615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (void) fprintf(fp2, "%s", line); 22625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 22635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 22645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 22655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If new user, just add it 22665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!found && pass != NULL) { 22675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mg_md5(ha1, user, ":", domain, ":", pass, NULL); 22685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (void) fprintf(fp2, "%s:%s:%s\n", user, domain, ha1); 22695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 22705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 22715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Close files 22725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (void) fclose(fp); 22735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (void) fclose(fp2); 22745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 22755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Put the temp file in place of real file 22765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (void) mg_remove(fname); 22775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (void) mg_rename(tmp, fname); 22785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 22795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 1; 22805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 22815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 22825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)struct de { 22835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) struct mg_connection *conn; 22845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) char *file_name; 22855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) struct mgstat st; 22865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 22875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 22885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void url_encode(const char *src, char *dst, size_t dst_len) { 22895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static const char *dont_escape = "._-$,;~()"; 22905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static const char *hex = "0123456789abcdef"; 22915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char *end = dst + dst_len - 1; 22925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 22935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (; *src != '\0' && dst < end; src++, dst++) { 22945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (isalnum(*(const unsigned char *) src) || 22955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) strchr(dont_escape, * (const unsigned char *) src) != NULL) { 22965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *dst = *src; 22975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (dst + 2 < end) { 22985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dst[0] = '%'; 22995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dst[1] = hex[(* (const unsigned char *) src) >> 4]; 23005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dst[2] = hex[(* (const unsigned char *) src) & 0xf]; 23015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dst += 2; 23025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 23035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 23045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 23055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *dst = '\0'; 23065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 23075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 23085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void print_dir_entry(struct de *de) { 23095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) char size[64], mod[64], href[PATH_MAX]; 23105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 23115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (de->st.is_directory) { 23125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (void) mg_snprintf(de->conn, size, sizeof(size), "%s", "[DIRECTORY]"); 23135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 23145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We use (signed) cast below because MSVC 6 compiler cannot 23155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // convert unsigned __int64 to double. Sigh. 23165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (de->st.size < 1024) { 23175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (void) mg_snprintf(de->conn, size, sizeof(size), 23185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "%lu", (unsigned long) de->st.size); 23195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (de->st.size < 1024 * 1024) { 23205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (void) mg_snprintf(de->conn, size, sizeof(size), 23215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "%.1fk", (double) de->st.size / 1024.0); 23225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (de->st.size < 1024 * 1024 * 1024) { 23235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (void) mg_snprintf(de->conn, size, sizeof(size), 23245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "%.1fM", (double) de->st.size / 1048576); 23255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 23265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (void) mg_snprintf(de->conn, size, sizeof(size), 23275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "%.1fG", (double) de->st.size / 1073741824); 23285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 23295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 23305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (void) strftime(mod, sizeof(mod), "%d-%b-%Y %H:%M", localtime(&de->st.mtime)); 23315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) url_encode(de->file_name, href, sizeof(href)); 23325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) de->conn->num_bytes_sent += mg_printf(de->conn, 23335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "<tr><td><a href=\"%s%s%s\">%s%s</a></td>" 23345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "<td> %s</td><td> %s</td></tr>\n", 23355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) de->conn->request_info.uri, href, de->st.is_directory ? "/" : "", 23365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) de->file_name, de->st.is_directory ? "/" : "", mod, size); 23375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 23385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 23395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// This function is called from send_directory() and used for 23405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// sorting directory entries by size, or name, or modification time. 23415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// On windows, __cdecl specification is needed in case if project is built 23425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// with __stdcall convention. qsort always requires __cdels callback. 23435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int WINCDECL compare_dir_entries(const void *p1, const void *p2) { 23445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const struct de *a = (const struct de *) p1, *b = (const struct de *) p2; 23455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char *query_string = a->conn->request_info.query_string; 23465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int cmp_result = 0; 23475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 23485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (query_string == NULL) { 23495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) query_string = "na"; 23505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 23515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 23525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (a->st.is_directory && !b->st.is_directory) { 23535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return -1; // Always put directories on top 23545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (!a->st.is_directory && b->st.is_directory) { 23555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 1; // Always put directories on top 23565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (*query_string == 'n') { 23575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cmp_result = strcmp(a->file_name, b->file_name); 23585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (*query_string == 's') { 23595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cmp_result = a->st.size == b->st.size ? 0 : 23605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) a->st.size > b->st.size ? 1 : -1; 23615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (*query_string == 'd') { 23625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cmp_result = a->st.mtime == b->st.mtime ? 0 : 23635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) a->st.mtime > b->st.mtime ? 1 : -1; 23645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 23655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 23665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return query_string[1] == 'd' ? -cmp_result : cmp_result; 23675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 23685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 23695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int scan_directory(struct mg_connection *conn, const char *dir, 23705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void *data, void (*cb)(struct de *, void *)) { 23715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) char path[PATH_MAX]; 23725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) struct dirent *dp; 23735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DIR *dirp; 23745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) struct de de; 23755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 23765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if ((dirp = opendir(dir)) == NULL) { 23775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 0; 23785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 23795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) de.conn = conn; 23805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 23815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while ((dp = readdir(dirp)) != NULL) { 23825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Do not show current dir and passwords file 23835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!strcmp(dp->d_name, ".") || 23845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) !strcmp(dp->d_name, "..") || 23855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) !strcmp(dp->d_name, PASSWORDS_FILE_NAME)) 23865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) continue; 23875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 23885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mg_snprintf(conn, path, sizeof(path), "%s%c%s", dir, DIRSEP, dp->d_name); 23895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 23905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If we don't memset stat structure to zero, mtime will have 23915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // garbage and strftime() will segfault later on in 23925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // print_dir_entry(). memset is required only if mg_stat() 23935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // fails. For more details, see 23945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // http://code.google.com/p/mongoose/issues/detail?id=79 23955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (mg_stat(path, &de.st) != 0) { 23965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) memset(&de.st, 0, sizeof(de.st)); 23975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 23985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) de.file_name = dp->d_name; 23995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 24005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cb(&de, data); 24015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 24025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (void) closedir(dirp); 24035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 24045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 1; 24055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 24065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 24075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)struct dir_scan_data { 24085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) struct de *entries; 24095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int num_entries; 24105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int arr_size; 24115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 24125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 24135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void dir_scan_callback(struct de *de, void *data) { 24145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) struct dir_scan_data *dsd = (struct dir_scan_data *) data; 24155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 24165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (dsd->entries == NULL || dsd->num_entries >= dsd->arr_size) { 24175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dsd->arr_size *= 2; 24185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dsd->entries = (struct de *) realloc(dsd->entries, dsd->arr_size * 24195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sizeof(dsd->entries[0])); 24205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 24215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (dsd->entries == NULL) { 24225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // TODO(lsm): propagate an error to the caller 24235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dsd->num_entries = 0; 24245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 24255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dsd->entries[dsd->num_entries].file_name = mg_strdup(de->file_name); 24265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dsd->entries[dsd->num_entries].st = de->st; 24275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dsd->entries[dsd->num_entries].conn = de->conn; 24285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dsd->num_entries++; 24295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 24305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 24315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 24325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void handle_directory_request(struct mg_connection *conn, 24335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char *dir) { 24345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int i, sort_direction; 24355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) struct dir_scan_data data = { NULL, 0, 128 }; 24365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 24375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!scan_directory(conn, dir, &data, dir_scan_callback)) { 24385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) send_http_error(conn, 500, "Cannot open directory", 24395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "Error: opendir(%s): %s", dir, strerror(ERRNO)); 24405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 24415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 24425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 24435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sort_direction = conn->request_info.query_string != NULL && 24445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) conn->request_info.query_string[1] == 'd' ? 'a' : 'd'; 24455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 24465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mg_printf(conn, "%s", 24475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "HTTP/1.1 200 OK\r\n" 24485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "Connection: close\r\n" 24495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "Content-Type: text/html; charset=utf-8\r\n\r\n"); 24505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 24515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) conn->num_bytes_sent += mg_printf(conn, 24525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "<html><head><title>Index of %s</title>" 24535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "<style>th {text-align: left;}</style></head>" 24545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "<body><h1>Index of %s</h1><pre><table cellpadding=\"0\">" 24555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "<tr><th><a href=\"?n%c\">Name</a></th>" 24565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "<th><a href=\"?d%c\">Modified</a></th>" 24575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "<th><a href=\"?s%c\">Size</a></th></tr>" 24585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "<tr><td colspan=\"3\"><hr></td></tr>", 24595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) conn->request_info.uri, conn->request_info.uri, 24605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sort_direction, sort_direction, sort_direction); 24615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 24625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Print first entry - link to a parent directory 24635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) conn->num_bytes_sent += mg_printf(conn, 24645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "<tr><td><a href=\"%s%s\">%s</a></td>" 24655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "<td> %s</td><td> %s</td></tr>\n", 24665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) conn->request_info.uri, "..", "Parent directory", "-", "-"); 24675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 24685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Sort and print directory entries 24695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) qsort(data.entries, (size_t) data.num_entries, sizeof(data.entries[0]), 24705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) compare_dir_entries); 24715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (i = 0; i < data.num_entries; i++) { 24725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) print_dir_entry(&data.entries[i]); 24735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) free(data.entries[i].file_name); 24745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 24755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) free(data.entries); 24765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 24775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) conn->num_bytes_sent += mg_printf(conn, "%s", "</table></body></html>"); 24785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) conn->request_info.status_code = 200; 24795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 24805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 24815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Send len bytes from the opened file to the client. 24825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void send_file_data(struct mg_connection *conn, FILE *fp, int64_t len) { 24835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) char buf[BUFSIZ]; 24845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int to_read, num_read, num_written; 24855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 24865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while (len > 0) { 24875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Calculate how much to read from the file in the buffer 24885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) to_read = sizeof(buf); 24895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if ((int64_t) to_read > len) 24905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) to_read = (int) len; 24915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 24925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Read from file, exit the loop on error 24935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if ((num_read = fread(buf, 1, (size_t)to_read, fp)) == 0) 24945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 24955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 24965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Send read bytes to the client, exit the loop on error 24975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if ((num_written = mg_write(conn, buf, (size_t)num_read)) != num_read) 24985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 24995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 25005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Both read and were successful, adjust counters 25015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) conn->num_bytes_sent += num_written; 25025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) len -= num_written; 25035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 25045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 25055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 25065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int parse_range_header(const char *header, int64_t *a, int64_t *b) { 25075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return sscanf(header, "bytes=%" INT64_FMT "-%" INT64_FMT, a, b); 25085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 25095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 25105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void gmt_time_string(char *buf, size_t buf_len, time_t *t) { 25115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) strftime(buf, buf_len, "%a, %d %b %Y %H:%M:%S GMT", gmtime(t)); 25125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 25135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 25145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void handle_file_request(struct mg_connection *conn, const char *path, 25155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) struct mgstat *stp) { 25165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) char date[64], lm[64], etag[64], range[64]; 25175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char *msg = "OK", *hdr; 25185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) time_t curtime = time(NULL); 25195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int64_t cl, r1, r2; 25205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) struct vec mime_vec; 25215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FILE *fp; 25225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int n; 25235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 25245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) get_mime_type(conn->ctx, path, &mime_vec); 25255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cl = stp->size; 25265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) conn->request_info.status_code = 200; 25275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) range[0] = '\0'; 25285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 25295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if ((fp = mg_fopen(path, "rb")) == NULL) { 25305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) send_http_error(conn, 500, http_500_error, 25315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "fopen(%s): %s", path, strerror(ERRNO)); 25325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 25335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 25345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) set_close_on_exec(fileno(fp)); 25355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 25365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If Range: header specified, act accordingly 25375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) r1 = r2 = 0; 25385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) hdr = mg_get_header(conn, "Range"); 25395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (hdr != NULL && (n = parse_range_header(hdr, &r1, &r2)) > 0) { 25405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) conn->request_info.status_code = 206; 25415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (void) fseeko(fp, (off_t) r1, SEEK_SET); 25425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cl = n == 2 ? r2 - r1 + 1: cl - r1; 25435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (void) mg_snprintf(conn, range, sizeof(range), 25445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "Content-Range: bytes " 25455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "%" INT64_FMT "-%" 25465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) INT64_FMT "/%" INT64_FMT "\r\n", 25475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) r1, r1 + cl - 1, stp->size); 25485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) msg = "Partial Content"; 25495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 25505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 25515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Prepare Etag, Date, Last-Modified headers. Must be in UTC, according to 25525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.3 25535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gmt_time_string(date, sizeof(date), &curtime); 25545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gmt_time_string(lm, sizeof(lm), &stp->mtime); 25555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (void) mg_snprintf(conn, etag, sizeof(etag), "%lx.%lx", 25565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (unsigned long) stp->mtime, (unsigned long) stp->size); 25575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 25585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (void) mg_printf(conn, 25595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "HTTP/1.1 %d %s\r\n" 25605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "Date: %s\r\n" 25615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "Last-Modified: %s\r\n" 25625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "Etag: \"%s\"\r\n" 25635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "Content-Type: %.*s\r\n" 25645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "Content-Length: %" INT64_FMT "\r\n" 25655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "Connection: %s\r\n" 25665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "Accept-Ranges: bytes\r\n" 25675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "%s\r\n", 25685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) conn->request_info.status_code, msg, date, lm, etag, 25695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mime_vec.len, mime_vec.ptr, cl, suggest_connection_header(conn), range); 25705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 25715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (strcmp(conn->request_info.request_method, "HEAD") != 0) { 25725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) send_file_data(conn, fp, cl); 25735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 25745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (void) fclose(fp); 25755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 25765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 25775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void mg_send_file(struct mg_connection *conn, const char *path) { 25785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) struct mgstat st; 25795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (mg_stat(path, &st) == 0) { 25805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) handle_file_request(conn, path, &st); 25815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 25825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) send_http_error(conn, 404, "Not Found", "%s", "File not found"); 25835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 25845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 25855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 25865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 25875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Parse HTTP headers from the given buffer, advance buffer to the point 25885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// where parsing stopped. 25895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void parse_http_headers(char **buf, struct mg_request_info *ri) { 25905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int i; 25915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 25925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (i = 0; i < (int) ARRAY_SIZE(ri->http_headers); i++) { 25935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ri->http_headers[i].name = skip_quoted(buf, ":", " ", 0); 25945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ri->http_headers[i].value = skip(buf, "\r\n"); 25955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (ri->http_headers[i].name[0] == '\0') 25965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 25975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ri->num_headers = i + 1; 25985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 25995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 26005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 26015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int is_valid_http_method(const char *method) { 26025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return !strcmp(method, "GET") || !strcmp(method, "POST") || 26035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) !strcmp(method, "HEAD") || !strcmp(method, "CONNECT") || 26045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) !strcmp(method, "PUT") || !strcmp(method, "DELETE") || 26055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) !strcmp(method, "OPTIONS") || !strcmp(method, "PROPFIND"); 26065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 26075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 26085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Parse HTTP request, fill in mg_request_info structure. 26095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int parse_http_request(char *buf, struct mg_request_info *ri) { 26105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int status = 0; 26115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 26125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // RFC says that all initial whitespaces should be ingored 26135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while (*buf != '\0' && isspace(* (unsigned char *) buf)) { 26145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) buf++; 26155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 26165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 26175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ri->request_method = skip(&buf, " "); 26185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ri->uri = skip(&buf, " "); 26195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ri->http_version = skip(&buf, "\r\n"); 26205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 26215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (is_valid_http_method(ri->request_method) && 26225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) strncmp(ri->http_version, "HTTP/", 5) == 0) { 26235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ri->http_version += 5; // Skip "HTTP/" 26245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) parse_http_headers(&buf, ri); 26255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) status = 1; 26265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 26275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 26285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return status; 26295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 26305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 26315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Keep reading the input (either opened file descriptor fd, or socket sock, 26325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// or SSL descriptor ssl) into buffer buf, until \r\n\r\n appears in the 26335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// buffer (which marks the end of HTTP request). Buffer buf may already 26345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// have some data. The length of the data is stored in nread. 26355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Upon every read operation, increase nread by the number of bytes read. 26365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int read_request(FILE *fp, SOCKET sock, SSL *ssl, char *buf, int bufsiz, 26375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int *nread) { 26385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int n, request_len; 26395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 26405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) request_len = 0; 26415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while (*nread < bufsiz && request_len == 0) { 26425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) n = pull(fp, sock, ssl, buf + *nread, bufsiz - *nread); 26435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (n <= 0) { 26445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 26455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 26465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *nread += n; 26475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) request_len = get_request_len(buf, *nread); 26485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 26495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 26505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 26515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return request_len; 26525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 26535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 26545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// For given directory path, substitute it to valid index file. 26555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Return 0 if index file has been found, -1 if not found. 26565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// If the file is found, it's stats is returned in stp. 26575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int substitute_index_file(struct mg_connection *conn, char *path, 26585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size_t path_len, struct mgstat *stp) { 26595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char *list = conn->ctx->config[INDEX_FILES]; 26605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) struct mgstat st; 26615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) struct vec filename_vec; 26625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size_t n = strlen(path); 26635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int found = 0; 26645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 26655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The 'path' given to us points to the directory. Remove all trailing 26665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // directory separator characters from the end of the path, and 26675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // then append single directory separator character. 26685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while (n > 0 && IS_DIRSEP_CHAR(path[n - 1])) { 26695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) n--; 26705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 26715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) path[n] = DIRSEP; 26725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 26735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Traverse index files list. For each entry, append it to the given 26745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // path and see if the file exists. If it exists, break the loop 26755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while ((list = next_option(list, &filename_vec, NULL)) != NULL) { 26765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 26775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Ignore too long entries that may overflow path buffer 26785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (filename_vec.len > path_len - n) 26795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) continue; 26805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 26815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Prepare full path to the index file 26825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (void) mg_strlcpy(path + n + 1, filename_vec.ptr, filename_vec.len + 1); 26835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 26845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Does it exist? 26855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (mg_stat(path, &st) == 0) { 26865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Yes it does, break the loop 26875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *stp = st; 26885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) found = 1; 26895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 26905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 26915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 26925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 26935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If no index file exists, restore directory path 26945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!found) { 26955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) path[n] = '\0'; 26965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 26975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 26985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return found; 26995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 27005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 27015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Return True if we should reply 304 Not Modified. 27025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int is_not_modified(const struct mg_connection *conn, 27035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const struct mgstat *stp) { 27045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char *ims = mg_get_header(conn, "If-Modified-Since"); 27055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return ims != NULL && stp->mtime <= parse_date_string(ims); 27065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 27075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 27085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int forward_body_data(struct mg_connection *conn, FILE *fp, 27095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SOCKET sock, SSL *ssl) { 27105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char *expect, *buffered; 27115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) char buf[BUFSIZ]; 27125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int to_read, nread, buffered_len, success = 0; 27135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 27145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) expect = mg_get_header(conn, "Expect"); 27155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) assert(fp != NULL); 27165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 27175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (conn->content_len == -1) { 27185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) send_http_error(conn, 411, "Length Required", ""); 27195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (expect != NULL && mg_strcasecmp(expect, "100-continue")) { 27205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) send_http_error(conn, 417, "Expectation Failed", ""); 27215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 27225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (expect != NULL) { 27235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (void) mg_printf(conn, "%s", "HTTP/1.1 100 Continue\r\n\r\n"); 27245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 27255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 27265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) buffered = conn->buf + conn->request_len; 27275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) buffered_len = conn->data_len - conn->request_len; 27285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) assert(buffered_len >= 0); 27295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) assert(conn->consumed_content == 0); 27305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 27315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (buffered_len > 0) { 27325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if ((int64_t) buffered_len > conn->content_len) { 27335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) buffered_len = (int) conn->content_len; 27345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 27355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) push(fp, sock, ssl, buffered, (int64_t) buffered_len); 27365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) conn->consumed_content += buffered_len; 27375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 27385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 27395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while (conn->consumed_content < conn->content_len) { 27405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) to_read = sizeof(buf); 27415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if ((int64_t) to_read > conn->content_len - conn->consumed_content) { 27425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) to_read = (int) (conn->content_len - conn->consumed_content); 27435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 27445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) nread = pull(NULL, conn->client.sock, conn->ssl, buf, to_read); 27455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (nread <= 0 || push(fp, sock, ssl, buf, nread) != nread) { 27465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 27475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 27485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) conn->consumed_content += nread; 27495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 27505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 27515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (conn->consumed_content == conn->content_len) { 27525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) success = 1; 27535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 27545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 27555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Each error code path in this function must send an error 27565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!success) { 27575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) send_http_error(conn, 577, http_500_error, ""); 27585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 27595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 27605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 27615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return success; 27625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 27635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 27645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if !defined(NO_CGI) 27655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// This structure helps to create an environment for the spawned CGI program. 27665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Environment is an array of "VARIABLE=VALUE\0" ASCIIZ strings, 27675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// last element must be NULL. 27685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// However, on Windows there is a requirement that all these VARIABLE=VALUE\0 27695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// strings must reside in a contiguous buffer. The end of the buffer is 27705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// marked by two '\0' characters. 27715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// We satisfy both worlds: we create an envp array (which is vars), all 27725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// entries are actually pointers inside buf. 27735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)struct cgi_env_block { 27745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) struct mg_connection *conn; 27755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) char buf[CGI_ENVIRONMENT_SIZE]; // Environment buffer 27765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int len; // Space taken 27775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) char *vars[MAX_CGI_ENVIR_VARS]; // char **envp 27785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int nvars; // Number of variables 27795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 27805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 27815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Append VARIABLE=VALUE\0 string to the buffer, and add a respective 27825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// pointer into the vars array. 27835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static char *addenv(struct cgi_env_block *block, const char *fmt, ...) { 27845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int n, space; 27855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) char *added; 27865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) va_list ap; 27875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 27885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Calculate how much space is left in the buffer 27895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) space = sizeof(block->buf) - block->len - 2; 27905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) assert(space >= 0); 27915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 27925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Make a pointer to the free space int the buffer 27935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) added = block->buf + block->len; 27945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 27955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Copy VARIABLE=VALUE\0 string into the free space 27965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) va_start(ap, fmt); 27975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) n = mg_vsnprintf(block->conn, added, (size_t) space, fmt, ap); 27985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) va_end(ap); 27995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 28005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Make sure we do not overflow buffer and the envp array 28015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (n > 0 && n < space && 28025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) block->nvars < (int) ARRAY_SIZE(block->vars) - 2) { 28035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Append a pointer to the added string into the envp array 28045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) block->vars[block->nvars++] = block->buf + block->len; 28055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Bump up used length counter. Include \0 terminator 28065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) block->len += n + 1; 28075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 28085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 28095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return added; 28105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 28115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 28125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void prepare_cgi_environment(struct mg_connection *conn, 28135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char *prog, 28145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) struct cgi_env_block *blk) { 28155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char *s, *slash; 28165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) struct vec var_vec, root; 28175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) char *p; 28185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int i; 28195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 28205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) blk->len = blk->nvars = 0; 28215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) blk->conn = conn; 28225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 28235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) memset(&root, 0, sizeof(root)); 28245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 28255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) get_document_root(conn, &root); 28265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 28275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) addenv(blk, "SERVER_NAME=%s", conn->ctx->config[AUTHENTICATION_DOMAIN]); 28285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) addenv(blk, "SERVER_ROOT=%.*s", root.len, root.ptr); 28295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) addenv(blk, "DOCUMENT_ROOT=%.*s", root.len, root.ptr); 28305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 28315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Prepare the environment block 28325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) addenv(blk, "%s", "GATEWAY_INTERFACE=CGI/1.1"); 28335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) addenv(blk, "%s", "SERVER_PROTOCOL=HTTP/1.1"); 28345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) addenv(blk, "%s", "REDIRECT_STATUS=200"); // For PHP 28355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) addenv(blk, "SERVER_PORT=%d", ntohs(conn->client.lsa.u.sin.sin_port)); 28365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) addenv(blk, "REQUEST_METHOD=%s", conn->request_info.request_method); 28375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) addenv(blk, "REMOTE_ADDR=%s", 28385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) inet_ntoa(conn->client.rsa.u.sin.sin_addr)); 28395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) addenv(blk, "REMOTE_PORT=%d", conn->request_info.remote_port); 28405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) addenv(blk, "REQUEST_URI=%s", conn->request_info.uri); 28415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 28425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // SCRIPT_NAME 28435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) assert(conn->request_info.uri[0] == '/'); 28445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) slash = strrchr(conn->request_info.uri, '/'); 28455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if ((s = strrchr(prog, '/')) == NULL) 28465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) s = prog; 28475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) addenv(blk, "SCRIPT_NAME=%.*s%s", slash - conn->request_info.uri, 28485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) conn->request_info.uri, s); 28495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 28505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) addenv(blk, "SCRIPT_FILENAME=%s", prog); 28515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) addenv(blk, "PATH_TRANSLATED=%s", prog); 28525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) addenv(blk, "HTTPS=%s", conn->ssl == NULL ? "off" : "on"); 28535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 28545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if ((s = mg_get_header(conn, "Content-Type")) != NULL) 28555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) addenv(blk, "CONTENT_TYPE=%s", s); 28565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 28575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (conn->request_info.query_string != NULL) 28585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) addenv(blk, "QUERY_STRING=%s", conn->request_info.query_string); 28595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 28605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if ((s = mg_get_header(conn, "Content-Length")) != NULL) 28615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) addenv(blk, "CONTENT_LENGTH=%s", s); 28625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 28635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if ((s = getenv("PATH")) != NULL) 28645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) addenv(blk, "PATH=%s", s); 28655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 28665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(_WIN32) 28675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if ((s = getenv("COMSPEC")) != NULL) 28685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) addenv(blk, "COMSPEC=%s", s); 28695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if ((s = getenv("SYSTEMROOT")) != NULL) 28705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) addenv(blk, "SYSTEMROOT=%s", s); 28715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#else 28725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if ((s = getenv("LD_LIBRARY_PATH")) != NULL) 28735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) addenv(blk, "LD_LIBRARY_PATH=%s", s); 28745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif // _WIN32 28755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 28765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if ((s = getenv("PERLLIB")) != NULL) 28775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) addenv(blk, "PERLLIB=%s", s); 28785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 28795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (conn->request_info.remote_user != NULL) { 28805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) addenv(blk, "REMOTE_USER=%s", conn->request_info.remote_user); 28815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) addenv(blk, "%s", "AUTH_TYPE=Digest"); 28825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 28835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 28845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Add all headers as HTTP_* variables 28855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (i = 0; i < conn->request_info.num_headers; i++) { 28865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) p = addenv(blk, "HTTP_%s=%s", 28875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) conn->request_info.http_headers[i].name, 28885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) conn->request_info.http_headers[i].value); 28895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 28905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Convert variable name into uppercase, and change - to _ 28915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (; *p != '=' && *p != '\0'; p++) { 28925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (*p == '-') 28935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *p = '_'; 28945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *p = (char) toupper(* (unsigned char *) p); 28955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 28965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 28975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 28985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Add user-specified variables 28995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) s = conn->ctx->config[CGI_ENVIRONMENT]; 29005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while ((s = next_option(s, &var_vec, NULL)) != NULL) { 29015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) addenv(blk, "%.*s", var_vec.len, var_vec.ptr); 29025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 29035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 29045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) blk->vars[blk->nvars++] = NULL; 29055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) blk->buf[blk->len++] = '\0'; 29065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 29075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) assert(blk->nvars < (int) ARRAY_SIZE(blk->vars)); 29085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) assert(blk->len > 0); 29095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) assert(blk->len < (int) sizeof(blk->buf)); 29105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 29115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 29125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void handle_cgi_request(struct mg_connection *conn, const char *prog) { 29135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int headers_len, data_len, i, fd_stdin[2], fd_stdout[2]; 29145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char *status; 29155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) char buf[BUFSIZ], *pbuf, dir[PATH_MAX], *p; 29165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) struct mg_request_info ri; 29175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) struct cgi_env_block blk; 29185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FILE *in, *out; 29195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pid_t pid; 29205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 29215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) memset(&ri, 0, sizeof(ri)); 29225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 29235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) prepare_cgi_environment(conn, prog, &blk); 29245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 29255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // CGI must be executed in its own directory. 'dir' must point to the 29265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // directory containing executable program, 'p' must point to the 29275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // executable program name relative to 'dir'. 29285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (void) mg_snprintf(conn, dir, sizeof(dir), "%s", prog); 29295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if ((p = strrchr(dir, DIRSEP)) != NULL) { 29305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *p++ = '\0'; 29315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 29325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dir[0] = '.', dir[1] = '\0'; 29335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) p = (char *) prog; 29345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 29355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 29365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pid = (pid_t) -1; 29375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fd_stdin[0] = fd_stdin[1] = fd_stdout[0] = fd_stdout[1] = -1; 29385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) in = out = NULL; 29395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 29405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (pipe(fd_stdin) != 0 || pipe(fd_stdout) != 0) { 29415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) send_http_error(conn, 500, http_500_error, 29425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "Cannot create CGI pipe: %s", strerror(ERRNO)); 29435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) goto done; 29445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if ((pid = spawn_process(conn, p, blk.buf, blk.vars, 29455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fd_stdin[0], fd_stdout[1], dir)) == (pid_t) -1) { 29465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) goto done; 29475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if ((in = fdopen(fd_stdin[1], "wb")) == NULL || 29485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (out = fdopen(fd_stdout[0], "rb")) == NULL) { 29495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) send_http_error(conn, 500, http_500_error, 29505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "fopen: %s", strerror(ERRNO)); 29515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) goto done; 29525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 29535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 29545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) setbuf(in, NULL); 29555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) setbuf(out, NULL); 29565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 29575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // spawn_process() must close those! 29585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If we don't mark them as closed, close() attempt before 29595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // return from this function throws an exception on Windows. 29605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Windows does not like when closed descriptor is closed again. 29615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fd_stdin[0] = fd_stdout[1] = -1; 29625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 29635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Send POST data to the CGI process if needed 29645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!strcmp(conn->request_info.request_method, "POST") && 29655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) !forward_body_data(conn, in, INVALID_SOCKET, NULL)) { 29665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) goto done; 29675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 29685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 29695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Now read CGI reply into a buffer. We need to set correct 29705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // status code, thus we need to see all HTTP headers first. 29715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Do not send anything back to client, until we buffer in all 29725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // HTTP headers. 29735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) data_len = 0; 29745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) headers_len = read_request(out, INVALID_SOCKET, NULL, 29755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) buf, sizeof(buf), &data_len); 29765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (headers_len <= 0) { 29775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) send_http_error(conn, 500, http_500_error, 29785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "CGI program sent malformed HTTP headers: [%.*s]", 29795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) data_len, buf); 29805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) goto done; 29815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 29825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pbuf = buf; 29835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) buf[headers_len - 1] = '\0'; 29845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) parse_http_headers(&pbuf, &ri); 29855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 29865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Make up and send the status line 29875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) status = get_header(&ri, "Status"); 29885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) conn->request_info.status_code = status == NULL ? 200 : atoi(status); 29895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (void) mg_printf(conn, "HTTP/1.1 %d OK\r\n", conn->request_info.status_code); 29905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 29915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Send headers 29925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (i = 0; i < ri.num_headers; i++) { 29935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mg_printf(conn, "%s: %s\r\n", 29945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ri.http_headers[i].name, ri.http_headers[i].value); 29955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 29965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (void) mg_write(conn, "\r\n", 2); 29975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 29985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Send chunk of data that may be read after the headers 29995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) conn->num_bytes_sent += mg_write(conn, buf + headers_len, 30005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (size_t)(data_len - headers_len)); 30015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 30025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Read the rest of CGI output and send to the client 30035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) send_file_data(conn, out, INT64_MAX); 30045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 30055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)done: 30065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (pid != (pid_t) -1) { 30075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) kill(pid, SIGKILL); 30085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 30095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (fd_stdin[0] != -1) { 30105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (void) close(fd_stdin[0]); 30115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 30125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (fd_stdout[1] != -1) { 30135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (void) close(fd_stdout[1]); 30145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 30155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 30165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (in != NULL) { 30175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (void) fclose(in); 30185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (fd_stdin[1] != -1) { 30195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (void) close(fd_stdin[1]); 30205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 30215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 30225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (out != NULL) { 30235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (void) fclose(out); 30245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (fd_stdout[0] != -1) { 30255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (void) close(fd_stdout[0]); 30265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 30275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 30285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif // !NO_CGI 30295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 30305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// For a given PUT path, create all intermediate subdirectories 30315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// for given path. Return 0 if the path itself is a directory, 30325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// or -1 on error, 1 if OK. 30335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int put_dir(const char *path) { 30345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) char buf[PATH_MAX]; 30355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char *s, *p; 30365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) struct mgstat st; 30375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int len, res = 1; 30385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 30395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (s = p = path + 2; (p = strchr(s, DIRSEP)) != NULL; s = ++p) { 30405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) len = p - path; 30415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (len >= (int) sizeof(buf)) { 30425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) res = -1; 30435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 30445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 30455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) memcpy(buf, path, len); 30465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) buf[len] = '\0'; 30475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 30485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Try to create intermediate directory 30495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DEBUG_TRACE(("mkdir(%s)", buf)); 30505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (mg_stat(buf, &st) == -1 && mg_mkdir(buf, 0755) != 0) { 30515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) res = -1; 30525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 30535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 30545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 30555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Is path itself a directory? 30565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (p[1] == '\0') { 30575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) res = 0; 30585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 30595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 30605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 30615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return res; 30625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 30635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 30645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void put_file(struct mg_connection *conn, const char *path) { 30655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) struct mgstat st; 30665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char *range; 30675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int64_t r1, r2; 30685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FILE *fp; 30695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int rc; 30705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 30715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) conn->request_info.status_code = mg_stat(path, &st) == 0 ? 200 : 201; 30725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 30735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if ((rc = put_dir(path)) == 0) { 30745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mg_printf(conn, "HTTP/1.1 %d OK\r\n\r\n", conn->request_info.status_code); 30755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (rc == -1) { 30765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) send_http_error(conn, 500, http_500_error, 30775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "put_dir(%s): %s", path, strerror(ERRNO)); 30785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if ((fp = mg_fopen(path, "wb+")) == NULL) { 30795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) send_http_error(conn, 500, http_500_error, 30805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "fopen(%s): %s", path, strerror(ERRNO)); 30815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 30825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) set_close_on_exec(fileno(fp)); 30835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) range = mg_get_header(conn, "Content-Range"); 30845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) r1 = r2 = 0; 30855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (range != NULL && parse_range_header(range, &r1, &r2) > 0) { 30865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) conn->request_info.status_code = 206; 30875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // TODO(lsm): handle seek error 30885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (void) fseeko(fp, (off_t) r1, SEEK_SET); 30895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 30905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (forward_body_data(conn, fp, INVALID_SOCKET, NULL)) 30915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (void) mg_printf(conn, "HTTP/1.1 %d OK\r\n\r\n", 30925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) conn->request_info.status_code); 30935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (void) fclose(fp); 30945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 30955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 30965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 30975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void send_ssi_file(struct mg_connection *, const char *, FILE *, int); 30985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 30995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void do_ssi_include(struct mg_connection *conn, const char *ssi, 31005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) char *tag, int include_level) { 31015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) char file_name[BUFSIZ], path[PATH_MAX], *p; 31025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) struct vec root; 31035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int is_ssi; 31045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FILE *fp; 31055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 31065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) get_document_root(conn, &root); 31075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 31085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // sscanf() is safe here, since send_ssi_file() also uses buffer 31095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // of size BUFSIZ to get the tag. So strlen(tag) is always < BUFSIZ. 31105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (sscanf(tag, " virtual=\"%[^\"]\"", file_name) == 1) { 31115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // File name is relative to the webserver root 31125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (void) mg_snprintf(conn, path, sizeof(path), "%.*s%c%s", 31135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) root.len, root.ptr, DIRSEP, file_name); 31145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (sscanf(tag, " file=\"%[^\"]\"", file_name) == 1) { 31155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // File name is relative to the webserver working directory 31165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // or it is absolute system path 31175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (void) mg_snprintf(conn, path, sizeof(path), "%s", file_name); 31185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (sscanf(tag, " \"%[^\"]\"", file_name) == 1) { 31195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // File name is relative to the currect document 31205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (void) mg_snprintf(conn, path, sizeof(path), "%s", ssi); 31215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if ((p = strrchr(path, DIRSEP)) != NULL) { 31225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) p[1] = '\0'; 31235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 31245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (void) mg_snprintf(conn, path + strlen(path), 31255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sizeof(path) - strlen(path), "%s", file_name); 31265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 31275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cry(conn, "Bad SSI #include: [%s]", tag); 31285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 31295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 31305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 31315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if ((fp = mg_fopen(path, "rb")) == NULL) { 31325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cry(conn, "Cannot open SSI #include: [%s]: fopen(%s): %s", 31335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tag, path, strerror(ERRNO)); 31345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 31355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) set_close_on_exec(fileno(fp)); 31365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) is_ssi = match_extension(path, conn->ctx->config[SSI_EXTENSIONS]); 31375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (is_ssi) { 31385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) send_ssi_file(conn, path, fp, include_level + 1); 31395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 31405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) send_file_data(conn, fp, INT64_MAX); 31415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 31425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (void) fclose(fp); 31435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 31445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 31455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 31465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if !defined(NO_POPEN) 31475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void do_ssi_exec(struct mg_connection *conn, char *tag) { 31485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) char cmd[BUFSIZ]; 31495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FILE *fp; 31505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 31515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (sscanf(tag, " \"%[^\"]\"", cmd) != 1) { 31525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cry(conn, "Bad SSI #exec: [%s]", tag); 31535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if ((fp = popen(cmd, "r")) == NULL) { 31545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cry(conn, "Cannot SSI #exec: [%s]: %s", cmd, strerror(ERRNO)); 31555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 31565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) send_file_data(conn, fp, INT64_MAX); 31575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (void) pclose(fp); 31585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 31595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 31605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif // !NO_POPEN 31615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 31625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void send_ssi_file(struct mg_connection *conn, const char *path, 31635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FILE *fp, int include_level) { 31645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) char buf[BUFSIZ]; 31655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int ch, len, in_ssi_tag; 31665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 31675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (include_level > 10) { 31685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cry(conn, "SSI #include level is too deep (%s)", path); 31695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 31705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 31715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 31725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) in_ssi_tag = 0; 31735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) len = 0; 31745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 31755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while ((ch = fgetc(fp)) != EOF) { 31765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (in_ssi_tag && ch == '>') { 31775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) in_ssi_tag = 0; 31785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) buf[len++] = (char) ch; 31795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) buf[len] = '\0'; 31805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) assert(len <= (int) sizeof(buf)); 31815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (len < 6 || memcmp(buf, "<!--#", 5) != 0) { 31825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Not an SSI tag, pass it 31835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (void) mg_write(conn, buf, (size_t)len); 31845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 31855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!memcmp(buf + 5, "include", 7)) { 31865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) do_ssi_include(conn, path, buf + 12, include_level); 31875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if !defined(NO_POPEN) 31885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (!memcmp(buf + 5, "exec", 4)) { 31895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) do_ssi_exec(conn, buf + 9); 31905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif // !NO_POPEN 31915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 31925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cry(conn, "%s: unknown SSI " "command: \"%s\"", path, buf); 31935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 31945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 31955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) len = 0; 31965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (in_ssi_tag) { 31975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (len == 5 && memcmp(buf, "<!--#", 5) != 0) { 31985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Not an SSI tag 31995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) in_ssi_tag = 0; 32005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (len == (int) sizeof(buf) - 2) { 32015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cry(conn, "%s: SSI tag is too large", path); 32025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) len = 0; 32035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 32045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) buf[len++] = ch & 0xff; 32055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (ch == '<') { 32065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) in_ssi_tag = 1; 32075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (len > 0) { 32085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (void) mg_write(conn, buf, (size_t)len); 32095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 32105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) len = 0; 32115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) buf[len++] = ch & 0xff; 32125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 32135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) buf[len++] = ch & 0xff; 32145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (len == (int) sizeof(buf)) { 32155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (void) mg_write(conn, buf, (size_t)len); 32165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) len = 0; 32175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 32185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 32195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 32205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 32215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Send the rest of buffered data 32225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (len > 0) { 32235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (void) mg_write(conn, buf, (size_t)len); 32245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 32255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 32265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 32275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void handle_ssi_file_request(struct mg_connection *conn, 32285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char *path) { 32295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FILE *fp; 32305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 32315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if ((fp = mg_fopen(path, "rb")) == NULL) { 32325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) send_http_error(conn, 500, http_500_error, "fopen(%s): %s", path, 32335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) strerror(ERRNO)); 32345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 32355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) set_close_on_exec(fileno(fp)); 32365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mg_printf(conn, "HTTP/1.1 200 OK\r\n" 32375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "Content-Type: text/html\r\nConnection: %s\r\n\r\n", 32385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) suggest_connection_header(conn)); 32395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) send_ssi_file(conn, path, fp, 0); 32405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (void) fclose(fp); 32415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 32425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 32435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 32445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void send_options(struct mg_connection *conn) { 32455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) conn->request_info.status_code = 200; 32465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 32475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (void) mg_printf(conn, 32485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "HTTP/1.1 200 OK\r\n" 32495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "Allow: GET, POST, HEAD, CONNECT, PUT, DELETE, OPTIONS\r\n" 32505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "DAV: 1\r\n\r\n"); 32515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 32525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 32535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Writes PROPFIND properties for a collection element 32545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void print_props(struct mg_connection *conn, const char* uri, 32555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) struct mgstat* st) { 32565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) char mtime[64]; 32575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gmt_time_string(mtime, sizeof(mtime), &st->mtime); 32585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) conn->num_bytes_sent += mg_printf(conn, 32595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "<d:response>" 32605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "<d:href>%s</d:href>" 32615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "<d:propstat>" 32625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "<d:prop>" 32635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "<d:resourcetype>%s</d:resourcetype>" 32645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "<d:getcontentlength>%" INT64_FMT "</d:getcontentlength>" 32655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "<d:getlastmodified>%s</d:getlastmodified>" 32665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "</d:prop>" 32675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "<d:status>HTTP/1.1 200 OK</d:status>" 32685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "</d:propstat>" 32695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "</d:response>\n", 32705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) uri, 32715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) st->is_directory ? "<d:collection/>" : "", 32725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) st->size, 32735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mtime); 32745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 32755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 32765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void print_dav_dir_entry(struct de *de, void *data) { 32775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) char href[PATH_MAX]; 32785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) struct mg_connection *conn = (struct mg_connection *) data; 32795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mg_snprintf(conn, href, sizeof(href), "%s%s", 32805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) conn->request_info.uri, de->file_name); 32815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) print_props(conn, href, &de->st); 32825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 32835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 32845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void handle_propfind(struct mg_connection *conn, const char* path, 32855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) struct mgstat* st) { 32865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char *depth = mg_get_header(conn, "Depth"); 32875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 32885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) conn->request_info.status_code = 207; 32895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mg_printf(conn, "HTTP/1.1 207 Multi-Status\r\n" 32905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "Connection: close\r\n" 32915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "Content-Type: text/xml; charset=utf-8\r\n\r\n"); 32925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 32935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) conn->num_bytes_sent += mg_printf(conn, 32945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "<?xml version=\"1.0\" encoding=\"utf-8\"?>" 32955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "<d:multistatus xmlns:d='DAV:'>\n"); 32965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 32975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Print properties for the requested resource itself 32985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) print_props(conn, conn->request_info.uri, st); 32995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 33005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If it is a directory, print directory entries too if Depth is not 0 33015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (st->is_directory && 33025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) !mg_strcasecmp(conn->ctx->config[ENABLE_DIRECTORY_LISTING], "yes") && 33035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (depth == NULL || strcmp(depth, "0") != 0)) { 33045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scan_directory(conn, path, conn, &print_dav_dir_entry); 33055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 33065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 33075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) conn->num_bytes_sent += mg_printf(conn, "%s\n", "</d:multistatus>"); 33085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 33095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 33105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// This is the heart of the Mongoose's logic. 33115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// This function is called when the request is read, parsed and validated, 33125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// and Mongoose must decide what action to take: serve a file, or 33135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// a directory, or call embedded function, etcetera. 33145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void handle_request(struct mg_connection *conn) { 33155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) struct mg_request_info *ri = &conn->request_info; 33165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) char path[PATH_MAX]; 33175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int uri_len; 33185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) struct mgstat st; 33195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 33205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if ((conn->request_info.query_string = strchr(ri->uri, '?')) != NULL) { 33215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * conn->request_info.query_string++ = '\0'; 33225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 33235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) uri_len = strlen(ri->uri); 33245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) url_decode(ri->uri, (size_t)uri_len, ri->uri, (size_t)(uri_len + 1), 0); 33255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) remove_double_dots_and_double_slashes(ri->uri); 33265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) convert_uri_to_file_name(conn, ri->uri, path, sizeof(path)); 33275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 33285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DEBUG_TRACE(("%s", ri->uri)); 33295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!check_authorization(conn, path)) { 33305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) send_authorization_request(conn); 33315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (call_user(conn, MG_NEW_REQUEST) != NULL) { 33325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Do nothing, callback has served the request 33335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (!strcmp(ri->request_method, "OPTIONS")) { 33345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) send_options(conn); 33355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (strstr(path, PASSWORDS_FILE_NAME)) { 33365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Do not allow to view passwords files 33375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) send_http_error(conn, 403, "Forbidden", "Access Forbidden"); 33385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (conn->ctx->config[DOCUMENT_ROOT] == NULL) { 33395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) send_http_error(conn, 404, "Not Found", "Not Found"); 33405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if ((!strcmp(ri->request_method, "PUT") || 33415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) !strcmp(ri->request_method, "DELETE")) && 33425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (conn->ctx->config[PUT_DELETE_PASSWORDS_FILE] == NULL || 33435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) !is_authorized_for_put(conn))) { 33445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) send_authorization_request(conn); 33455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (!strcmp(ri->request_method, "PUT")) { 33465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) put_file(conn, path); 33475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (!strcmp(ri->request_method, "DELETE")) { 33485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (mg_remove(path) == 0) { 33495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) send_http_error(conn, 200, "OK", ""); 33505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 33515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) send_http_error(conn, 500, http_500_error, "remove(%s): %s", path, 33525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) strerror(ERRNO)); 33535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 33545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (mg_stat(path, &st) != 0) { 33555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) send_http_error(conn, 404, "Not Found", "%s", "File not found"); 33565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (st.is_directory && ri->uri[uri_len - 1] != '/') { 33575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (void) mg_printf(conn, 33585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "HTTP/1.1 301 Moved Permanently\r\n" 33595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "Location: %s/\r\n\r\n", ri->uri); 33605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (!strcmp(ri->request_method, "PROPFIND")) { 33615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) handle_propfind(conn, path, &st); 33625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (st.is_directory && 33635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) !substitute_index_file(conn, path, sizeof(path), &st)) { 33645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!mg_strcasecmp(conn->ctx->config[ENABLE_DIRECTORY_LISTING], "yes")) { 33655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) handle_directory_request(conn, path); 33665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 33675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) send_http_error(conn, 403, "Directory Listing Denied", 33685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "Directory listing denied"); 33695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 33705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if !defined(NO_CGI) 33715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (match_extension(path, conn->ctx->config[CGI_EXTENSIONS])) { 33725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (strcmp(ri->request_method, "POST") && 33735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) strcmp(ri->request_method, "GET")) { 33745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) send_http_error(conn, 501, "Not Implemented", 33755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "Method %s is not implemented", ri->request_method); 33765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 33775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) handle_cgi_request(conn, path); 33785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 33795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif // !NO_CGI 33805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (match_extension(path, conn->ctx->config[SSI_EXTENSIONS])) { 33815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) handle_ssi_file_request(conn, path); 33825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (is_not_modified(conn, &st)) { 33835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) send_http_error(conn, 304, "Not Modified", ""); 33845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 33855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) handle_file_request(conn, path, &st); 33865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 33875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 33885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 33895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void close_all_listening_sockets(struct mg_context *ctx) { 33905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) struct socket *sp, *tmp; 33915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (sp = ctx->listening_sockets; sp != NULL; sp = tmp) { 33925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tmp = sp->next; 33935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (void) closesocket(sp->sock); 33945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) free(sp); 33955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 33965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 33975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 33985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Valid listening port specification is: [ip_address:]port[s|p] 33995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Examples: 80, 443s, 127.0.0.1:3128p, 1.2.3.4:8080sp 34005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int parse_port_string(const struct vec *vec, struct socket *so) { 34015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) struct usa *usa = &so->lsa; 34025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int a, b, c, d, port, len; 34035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 34045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // MacOS needs that. If we do not zero it, subsequent bind() will fail. 34055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) memset(so, 0, sizeof(*so)); 34065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 34075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (sscanf(vec->ptr, "%d.%d.%d.%d:%d%n", &a, &b, &c, &d, &port, &len) == 5) { 34085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // IP address to bind to is specified 34095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) usa->u.sin.sin_addr.s_addr = htonl((a << 24) | (b << 16) | (c << 8) | d); 34105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (sscanf(vec->ptr, "%d%n", &port, &len) == 1) { 34115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Only port number is specified. Bind to all addresses 34125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) usa->u.sin.sin_addr.s_addr = htonl(INADDR_ANY); 34135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 34145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 0; 34155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 34165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) assert(len > 0 && len <= (int) vec->len); 34175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 34185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (strchr("sp,", vec->ptr[len]) == NULL) { 34195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 0; 34205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 34215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 34225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) so->is_ssl = vec->ptr[len] == 's'; 34235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) so->is_proxy = vec->ptr[len] == 'p'; 34245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) usa->len = sizeof(usa->u.sin); 34255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) usa->u.sin.sin_family = AF_INET; 34265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) usa->u.sin.sin_port = htons((uint16_t) port); 34275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 34285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 1; 34295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 34305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 34315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int set_ports_option(struct mg_context *ctx) { 34325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char *list = ctx->config[LISTENING_PORTS]; 34335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int on = 1, success = 1; 34345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SOCKET sock; 34355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) struct vec vec; 34365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) struct socket so, *listener; 34375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 34385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) struct linger linger; 34395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) linger.l_onoff = 1; 34405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) linger.l_linger = 1; 34415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 34425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while (success && (list = next_option(list, &vec, NULL)) != NULL) { 34435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!parse_port_string(&vec, &so)) { 34445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cry(fc(ctx), "%s: %.*s: invalid port spec. Expecting list of: %s", 34455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) __func__, vec.len, vec.ptr, "[IP_ADDRESS:]PORT[s|p]"); 34465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) success = 0; 34475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (so.is_ssl && ctx->ssl_ctx == NULL) { 34485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cry(fc(ctx), "Cannot add SSL socket, is -ssl_certificate option set?"); 34495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) success = 0; 34505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if ((sock = socket(PF_INET, SOCK_STREAM, 6)) == INVALID_SOCKET || 34515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if !defined(_WIN32) 34525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // On Windows, SO_REUSEADDR is recommended only for 34535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // broadcast UDP sockets 34545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &on, 34555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sizeof(on)) != 0 || 34565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif // !_WIN32 34575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Set TCP keep-alive. This is needed because if HTTP-level 34585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // keep-alive is enabled, and client resets the connection, 34595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // server won't get TCP FIN or RST and will keep the connection 34605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // open forever. With TCP keep-alive, next keep-alive 34615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // handshake will figure out that the client is down and 34625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // will close the server end. 34635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Thanks to Igor Klopov who suggested the patch. 34645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (void *) &on, 34655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sizeof(on)) != 0 || 34665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) setsockopt(sock, SOL_SOCKET, SO_LINGER, (void *) &linger, 34675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sizeof(linger)) || 34685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bind(sock, &so.lsa.u.sa, so.lsa.len) != 0 || 34695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) listen(sock, 100) != 0) { 34705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) closesocket(sock); 34715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cry(fc(ctx), "%s: cannot bind to %.*s: %s", __func__, 34725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) vec.len, vec.ptr, strerror(ERRNO)); 34735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) success = 0; 34745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if ((listener = (struct socket *) 34755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) calloc(1, sizeof(*listener))) == NULL) { 34765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) closesocket(sock); 34775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cry(fc(ctx), "%s: %s", __func__, strerror(ERRNO)); 34785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) success = 0; 34795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 34805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *listener = so; 34815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) listener->sock = sock; 34825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) set_close_on_exec(listener->sock); 34835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) listener->next = ctx->listening_sockets; 34845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ctx->listening_sockets = listener; 34855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 34865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 34875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 34885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!success) { 34895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) close_all_listening_sockets(ctx); 34905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 34915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 34925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return success; 34935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 34945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 34955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void log_header(const struct mg_connection *conn, const char *header, 34965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FILE *fp) { 34975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char *header_value; 34985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 34995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if ((header_value = mg_get_header(conn, header)) == NULL) { 35005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (void) fprintf(fp, "%s", " -"); 35015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 35025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (void) fprintf(fp, " \"%s\"", header_value); 35035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 35045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 35055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 35065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void log_access(const struct mg_connection *conn) { 35075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const struct mg_request_info *ri; 35085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FILE *fp; 35095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) char date[64]; 35105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 35115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fp = conn->ctx->config[ACCESS_LOG_FILE] == NULL ? NULL : 35125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mg_fopen(conn->ctx->config[ACCESS_LOG_FILE], "a+"); 35135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 35145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (fp == NULL) 35155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 35165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 35175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (void) strftime(date, sizeof(date), "%d/%b/%Y:%H:%M:%S %z", 35185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) localtime(&conn->birth_time)); 35195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 35205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ri = &conn->request_info; 35215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 35225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) flockfile(fp); 35235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 35245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (void) fprintf(fp, 35255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "%s - %s [%s] \"%s %s HTTP/%s\" %d %" INT64_FMT, 35265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) inet_ntoa(conn->client.rsa.u.sin.sin_addr), 35275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ri->remote_user == NULL ? "-" : ri->remote_user, 35285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) date, 35295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ri->request_method ? ri->request_method : "-", 35305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ri->uri ? ri->uri : "-", 35315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ri->http_version, 35325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) conn->request_info.status_code, conn->num_bytes_sent); 35335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) log_header(conn, "Referer", fp); 35345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) log_header(conn, "User-Agent", fp); 35355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (void) fputc('\n', fp); 35365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (void) fflush(fp); 35375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 35385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) funlockfile(fp); 35395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (void) fclose(fp); 35405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 35415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 35425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int isbyte(int n) { 35435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return n >= 0 && n <= 255; 35445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 35455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 35465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Verify given socket address against the ACL. 35475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Return -1 if ACL is malformed, 0 if address is disallowed, 1 if allowed. 35485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int check_acl(struct mg_context *ctx, const struct usa *usa) { 35495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int a, b, c, d, n, mask, allowed; 35505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) char flag; 35515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) uint32_t acl_subnet, acl_mask, remote_ip; 35525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) struct vec vec; 35535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char *list = ctx->config[ACCESS_CONTROL_LIST]; 35545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 35555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (list == NULL) { 35565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 1; 35575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 35585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 35595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (void) memcpy(&remote_ip, &usa->u.sin.sin_addr, sizeof(remote_ip)); 35605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 35615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If any ACL is set, deny by default 35625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) allowed = '-'; 35635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 35645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while ((list = next_option(list, &vec, NULL)) != NULL) { 35655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mask = 32; 35665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 35675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (sscanf(vec.ptr, "%c%d.%d.%d.%d%n", &flag, &a, &b, &c, &d, &n) != 5) { 35685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cry(fc(ctx), "%s: subnet must be [+|-]x.x.x.x[/x]", __func__); 35695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return -1; 35705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (flag != '+' && flag != '-') { 35715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cry(fc(ctx), "%s: flag must be + or -: [%s]", __func__, vec.ptr); 35725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return -1; 35735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (!isbyte(a)||!isbyte(b)||!isbyte(c)||!isbyte(d)) { 35745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cry(fc(ctx), "%s: bad ip address: [%s]", __func__, vec.ptr); 35755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return -1; 35765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (sscanf(vec.ptr + n, "/%d", &mask) == 0) { 35775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Do nothing, no mask specified 35785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (mask < 0 || mask > 32) { 35795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cry(fc(ctx), "%s: bad subnet mask: %d [%s]", __func__, n, vec.ptr); 35805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return -1; 35815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 35825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 35835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) acl_subnet = (a << 24) | (b << 16) | (c << 8) | d; 35845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) acl_mask = mask ? 0xffffffffU << (32 - mask) : 0; 35855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 35865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (acl_subnet == (ntohl(remote_ip) & acl_mask)) { 35875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) allowed = flag; 35885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 35895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 35905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 35915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return allowed == '+'; 35925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 35935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 35945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void add_to_set(SOCKET fd, fd_set *set, int *max_fd) { 35955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FD_SET(fd, set); 35965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (fd > (SOCKET) *max_fd) { 35975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *max_fd = (int) fd; 35985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 35995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 36005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 36015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if !defined(_WIN32) 36025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int set_uid_option(struct mg_context *ctx) { 36035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) struct passwd *pw; 36045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char *uid = ctx->config[RUN_AS_USER]; 36055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int success = 0; 36065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 36075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (uid == NULL) { 36085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) success = 1; 36095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 36105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if ((pw = getpwnam(uid)) == NULL) { 36115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cry(fc(ctx), "%s: unknown user [%s]", __func__, uid); 36125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (setgid(pw->pw_gid) == -1) { 36135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cry(fc(ctx), "%s: setgid(%s): %s", __func__, uid, strerror(errno)); 36145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (setuid(pw->pw_uid) == -1) { 36155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cry(fc(ctx), "%s: setuid(%s): %s", __func__, uid, strerror(errno)); 36165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 36175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) success = 1; 36185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 36195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 36205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 36215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return success; 36225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 36235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif // !_WIN32 36245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 36255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if !defined(NO_SSL) 36265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static pthread_mutex_t *ssl_mutexes; 36275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 36285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void ssl_locking_callback(int mode, int mutex_num, const char *file, 36295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int line) { 36305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) line = 0; // Unused 36315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) file = NULL; // Unused 36325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 36335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (mode & CRYPTO_LOCK) { 36345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (void) pthread_mutex_lock(&ssl_mutexes[mutex_num]); 36355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 36365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (void) pthread_mutex_unlock(&ssl_mutexes[mutex_num]); 36375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 36385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 36395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 36405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static unsigned long ssl_id_callback(void) { 36415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return (unsigned long) pthread_self(); 36425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 36435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 36445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if !defined(NO_SSL_DL) 36455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int load_dll(struct mg_context *ctx, const char *dll_name, 36465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) struct ssl_func *sw) { 36475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) union {void *p; void (*fp)(void);} u; 36485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void *dll_handle; 36495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) struct ssl_func *fp; 36505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 36515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if ((dll_handle = dlopen(dll_name, RTLD_LAZY)) == NULL) { 36525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cry(fc(ctx), "%s: cannot load %s", __func__, dll_name); 36535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 0; 36545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 36555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 36565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (fp = sw; fp->name != NULL; fp++) { 36575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifdef _WIN32 36585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // GetProcAddress() returns pointer to function 36595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) u.fp = (void (*)(void)) dlsym(dll_handle, fp->name); 36605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#else 36615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // dlsym() on UNIX returns void *. ISO C forbids casts of data pointers to 36625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // function pointers. We need to use a union to make a cast. 36635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) u.p = dlsym(dll_handle, fp->name); 36645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif // _WIN32 36655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (u.fp == NULL) { 36665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cry(fc(ctx), "%s: %s: cannot find %s", __func__, dll_name, fp->name); 36675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 0; 36685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 36695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fp->ptr = u.fp; 36705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 36715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 36725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 36735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 1; 36745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 36755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif // NO_SSL_DL 36765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 36775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Dynamically load SSL library. Set up ctx->ssl_ctx pointer. 36785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int set_ssl_option(struct mg_context *ctx) { 36795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) struct mg_request_info request_info; 36805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SSL_CTX *CTX; 36815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int i, size; 36825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char *pem = ctx->config[SSL_CERTIFICATE]; 36835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char *chain = ctx->config[SSL_CHAIN_FILE]; 36845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 36855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (pem == NULL) { 36865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 1; 36875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 36885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 36895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if !defined(NO_SSL_DL) 36905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!load_dll(ctx, SSL_LIB, ssl_sw) || 36915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) !load_dll(ctx, CRYPTO_LIB, crypto_sw)) { 36925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 0; 36935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 36945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif // NO_SSL_DL 36955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 36965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Initialize SSL crap 36975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SSL_library_init(); 36985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SSL_load_error_strings(); 36995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 37005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if ((CTX = SSL_CTX_new(SSLv23_server_method())) == NULL) { 37015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cry(fc(ctx), "SSL_CTX_new error: %s", ssl_error()); 37025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (ctx->user_callback != NULL) { 37035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) memset(&request_info, 0, sizeof(request_info)); 37045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) request_info.user_data = ctx->user_data; 37055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ctx->user_callback(MG_INIT_SSL, (struct mg_connection *) CTX, 37065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) &request_info); 37075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 37085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 37095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (CTX != NULL && SSL_CTX_use_certificate_file(CTX, pem, 37105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SSL_FILETYPE_PEM) == 0) { 37115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cry(fc(ctx), "%s: cannot open %s: %s", __func__, pem, ssl_error()); 37125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 0; 37135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (CTX != NULL && SSL_CTX_use_PrivateKey_file(CTX, pem, 37145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SSL_FILETYPE_PEM) == 0) { 37155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cry(fc(ctx), "%s: cannot open %s: %s", NULL, pem, ssl_error()); 37165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 0; 37175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 37185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 37195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (CTX != NULL && chain != NULL && 37205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SSL_CTX_use_certificate_chain_file(CTX, chain) == 0) { 37215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cry(fc(ctx), "%s: cannot open %s: %s", NULL, chain, ssl_error()); 37225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 0; 37235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 37245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 37255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Initialize locking callbacks, needed for thread safety. 37265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // http://www.openssl.org/support/faq.html#PROG1 37275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size = sizeof(pthread_mutex_t) * CRYPTO_num_locks(); 37285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if ((ssl_mutexes = (pthread_mutex_t *) malloc((size_t)size)) == NULL) { 37295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cry(fc(ctx), "%s: cannot allocate mutexes: %s", __func__, ssl_error()); 37305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 0; 37315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 37325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 37335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (i = 0; i < CRYPTO_num_locks(); i++) { 37345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pthread_mutex_init(&ssl_mutexes[i], NULL); 37355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 37365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 37375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CRYPTO_set_locking_callback(&ssl_locking_callback); 37385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CRYPTO_set_id_callback(&ssl_id_callback); 37395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 37405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Done with everything. Save the context. 37415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ctx->ssl_ctx = CTX; 37425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 37435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 1; 37445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 37455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 37465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void uninitialize_ssl(struct mg_context *ctx) { 37475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int i; 37485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (ctx->ssl_ctx != NULL) { 37495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CRYPTO_set_locking_callback(NULL); 37505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (i = 0; i < CRYPTO_num_locks(); i++) { 37515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pthread_mutex_destroy(&ssl_mutexes[i]); 37525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 37535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CRYPTO_set_locking_callback(NULL); 37545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CRYPTO_set_id_callback(NULL); 37555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 37565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 37575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif // !NO_SSL 37585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 37595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int set_gpass_option(struct mg_context *ctx) { 37605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) struct mgstat mgstat; 37615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char *path = ctx->config[GLOBAL_PASSWORDS_FILE]; 37625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return path == NULL || mg_stat(path, &mgstat) == 0; 37635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 37645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 37655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int set_acl_option(struct mg_context *ctx) { 37665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) struct usa fake; 37675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return check_acl(ctx, &fake) != -1; 37685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 37695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 37705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void reset_per_request_attributes(struct mg_connection *conn) { 37715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) struct mg_request_info *ri = &conn->request_info; 37725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 37735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Reset request info attributes. DO NOT TOUCH is_ssl, remote_ip, remote_port 37745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (ri->remote_user != NULL) { 37755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) free((void *) ri->remote_user); 37765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 37775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ri->remote_user = ri->request_method = ri->uri = ri->http_version = NULL; 37785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ri->num_headers = 0; 37795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ri->status_code = -1; 37805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 37815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) conn->num_bytes_sent = conn->consumed_content = 0; 37825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) conn->content_len = -1; 37835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) conn->request_len = conn->data_len = 0; 37845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 37855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 37865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void close_socket_gracefully(SOCKET sock) { 37875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) char buf[BUFSIZ]; 37885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int n; 37895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 37905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Send FIN to the client 37915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (void) shutdown(sock, SHUT_WR); 37925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) set_non_blocking_mode(sock); 37935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 37945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Read and discard pending data. If we do not do that and close the 37955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // socket, the data in the send buffer may be discarded. This 37965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // behaviour is seen on Windows, when client keeps sending data 37975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // when server decide to close the connection; then when client 37985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // does recv() it gets no data back. 37995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) do { 38005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) n = pull(NULL, sock, NULL, buf, sizeof(buf)); 38015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } while (n > 0); 38025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 38035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Now we know that our FIN is ACK-ed, safe to close 38045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (void) closesocket(sock); 38055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 38065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 38075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void close_connection(struct mg_connection *conn) { 38085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (conn->ssl) { 38095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SSL_free(conn->ssl); 38105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) conn->ssl = NULL; 38115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 38125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 38135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (conn->client.sock != INVALID_SOCKET) { 38145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) close_socket_gracefully(conn->client.sock); 38155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 38165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 38175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 38185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void discard_current_request_from_buffer(struct mg_connection *conn) { 38195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int buffered_len, body_len; 38205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 38215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) buffered_len = conn->data_len - conn->request_len; 38225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) assert(buffered_len >= 0); 38235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 38245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (conn->content_len == -1) { 38255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) body_len = 0; 38265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (conn->content_len < (int64_t) buffered_len) { 38275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) body_len = (int) conn->content_len; 38285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 38295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) body_len = buffered_len; 38305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 38315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 38325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) conn->data_len -= conn->request_len + body_len; 38335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) memmove(conn->buf, conn->buf + conn->request_len + body_len, 38345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (size_t) conn->data_len); 38355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 38365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 38375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int parse_url(const char *url, char *host, int *port) { 38385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int len; 38395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 38405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (sscanf(url, "%*[htps]://%1024[^:]:%d%n", host, port, &len) == 2 || 38415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sscanf(url, "%1024[^:]:%d%n", host, port, &len) == 2) { 38425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (sscanf(url, "%*[htps]://%1024[^/]%n", host, &len) == 1) { 38435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *port = 80; 38445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 38455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sscanf(url, "%1024[^/]%n", host, &len); 38465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *port = 80; 38475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 38485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DEBUG_TRACE(("Host:%s, port:%d", host, *port)); 38495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 38505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return len; 38515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 38525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 38535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void handle_proxy_request(struct mg_connection *conn) { 38545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) struct mg_request_info *ri = &conn->request_info; 38555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) char host[1025], buf[BUFSIZ]; 38565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int port, is_ssl, len, i, n; 38575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 38585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DEBUG_TRACE(("URL: %s", ri->uri)); 38595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (ri->uri == NULL || 38605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ri->uri[0] == '/' || 38615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (len = parse_url(ri->uri, host, &port)) == 0) { 38625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 38635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 38645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 38655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (conn->peer == NULL) { 38665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) is_ssl = !strcmp(ri->request_method, "CONNECT"); 38675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if ((conn->peer = mg_connect(conn, host, port, is_ssl)) == NULL) { 38685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 38695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 38705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) conn->peer->client.is_ssl = is_ssl; 38715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 38725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 38735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Forward client's request to the target 38745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mg_printf(conn->peer, "%s %s HTTP/%s\r\n", ri->request_method, ri->uri + len, 38755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ri->http_version); 38765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 38775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // And also all headers. TODO(lsm): anonymize! 38785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (i = 0; i < ri->num_headers; i++) { 38795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mg_printf(conn->peer, "%s: %s\r\n", ri->http_headers[i].name, 38805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ri->http_headers[i].value); 38815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 38825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // End of headers, final newline 38835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mg_write(conn->peer, "\r\n", 2); 38845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 38855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Read and forward body data if any 38865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!strcmp(ri->request_method, "POST")) { 38875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) forward_body_data(conn, NULL, conn->peer->client.sock, conn->peer->ssl); 38885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 38895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 38905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Read data from the target and forward it to the client 38915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while ((n = pull(NULL, conn->peer->client.sock, conn->peer->ssl, 38925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) buf, sizeof(buf))) > 0) { 38935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (mg_write(conn, buf, (size_t)n) != n) { 38945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 38955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 38965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 38975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 38985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!conn->peer->client.is_ssl) { 38995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) close_connection(conn->peer); 39005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) free(conn->peer); 39015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) conn->peer = NULL; 39025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 39035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 39045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 39055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int is_valid_uri(const char *uri) { 39065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Conform to http://www.w3.org/Protocols/rfc2616/rfc2616-sec5.html#sec5.1.2 39075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // URI can be an asterisk (*) or should start with slash. 39085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return (uri[0] == '/' || (uri[0] == '*' && uri[1] == '\0')); 39095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 39105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 39115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void process_new_connection(struct mg_connection *conn) { 39125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) struct mg_request_info *ri = &conn->request_info; 39135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int keep_alive_enabled; 39145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char *cl; 39155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 39165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) keep_alive_enabled = !strcmp(conn->ctx->config[ENABLE_KEEP_ALIVE], "yes"); 39175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 39185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) do { 39195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) reset_per_request_attributes(conn); 39205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 39215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If next request is not pipelined, read it in 39225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if ((conn->request_len = get_request_len(conn->buf, conn->data_len)) == 0) { 39235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) conn->request_len = read_request(NULL, conn->client.sock, conn->ssl, 39245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) conn->buf, conn->buf_size, &conn->data_len); 39255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 39265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) assert(conn->data_len >= conn->request_len); 39275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (conn->request_len == 0 && conn->data_len == conn->buf_size) { 39285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) send_http_error(conn, 413, "Request Too Large", ""); 39295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 39305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } if (conn->request_len <= 0) { 39315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; // Remote end closed the connection 39325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 39335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 39345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Nul-terminate the request cause parse_http_request() uses sscanf 39355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) conn->buf[conn->request_len - 1] = '\0'; 39365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!parse_http_request(conn->buf, ri) || 39375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (!conn->client.is_proxy && !is_valid_uri(ri->uri))) { 39385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Do not put garbage in the access log, just send it back to the client 39395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) send_http_error(conn, 400, "Bad Request", 39405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "Cannot parse HTTP request: [%.*s]", conn->data_len, conn->buf); 39415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (strcmp(ri->http_version, "1.0") && 39425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) strcmp(ri->http_version, "1.1")) { 39435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Request seems valid, but HTTP version is strange 39445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) send_http_error(conn, 505, "HTTP version not supported", ""); 39455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) log_access(conn); 39465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 39475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Request is valid, handle it 39485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cl = get_header(ri, "Content-Length"); 39495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) conn->content_len = cl == NULL ? -1 : strtoll(cl, NULL, 10); 39505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) conn->birth_time = time(NULL); 39515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (conn->client.is_proxy) { 39525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) handle_proxy_request(conn); 39535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 39545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) handle_request(conn); 39555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 39565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) log_access(conn); 39575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) discard_current_request_from_buffer(conn); 39585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 39595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // conn->peer is not NULL only for SSL-ed proxy connections 39605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } while (conn->ctx->stop_flag == 0 && 39615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (conn->peer || (keep_alive_enabled && should_keep_alive(conn)))); 39625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 39635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 39645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Worker threads take accepted socket from the queue 39655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int consume_socket(struct mg_context *ctx, struct socket *sp) { 39665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (void) pthread_mutex_lock(&ctx->mutex); 39675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DEBUG_TRACE(("going idle")); 39685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 39695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If the queue is empty, wait. We're idle at this point. 39705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while (ctx->sq_head == ctx->sq_tail && ctx->stop_flag == 0) { 39715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pthread_cond_wait(&ctx->sq_full, &ctx->mutex); 39725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 39735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 39745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If we're stopping, sq_head may be equal to sq_tail. 39755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (ctx->sq_head > ctx->sq_tail) { 39765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Copy socket from the queue and increment tail 39775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *sp = ctx->queue[ctx->sq_tail % ARRAY_SIZE(ctx->queue)]; 39785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ctx->sq_tail++; 39795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DEBUG_TRACE(("grabbed socket %d, going busy", sp->sock)); 39805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 39815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Wrap pointers if needed 39825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while (ctx->sq_tail > (int) ARRAY_SIZE(ctx->queue)) { 39835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ctx->sq_tail -= ARRAY_SIZE(ctx->queue); 39845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ctx->sq_head -= ARRAY_SIZE(ctx->queue); 39855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 39865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 39875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 39885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (void) pthread_cond_signal(&ctx->sq_empty); 39895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (void) pthread_mutex_unlock(&ctx->mutex); 39905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 39915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return !ctx->stop_flag; 39925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 39935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 39945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void worker_thread(struct mg_context *ctx) { 39955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) struct mg_connection *conn; 39965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int buf_size = atoi(ctx->config[MAX_REQUEST_SIZE]); 39975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 39985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) conn = (struct mg_connection *) calloc(1, sizeof(*conn) + buf_size); 39995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) conn->buf_size = buf_size; 40005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) conn->buf = (char *) (conn + 1); 40015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) assert(conn != NULL); 40025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 40035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Call consume_socket() even when ctx->stop_flag > 0, to let it signal 40045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // sq_empty condvar to wake up the master waiting in produce_socket() 40055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while (consume_socket(ctx, &conn->client)) { 40065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) conn->birth_time = time(NULL); 40075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) conn->ctx = ctx; 40085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 40095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Fill in IP, port info early so even if SSL setup below fails, 40105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // error handler would have the corresponding info. 40115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Thanks to Johannes Winkelmann for the patch. 40125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) conn->request_info.remote_port = ntohs(conn->client.rsa.u.sin.sin_port); 40135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) memcpy(&conn->request_info.remote_ip, 40145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) &conn->client.rsa.u.sin.sin_addr.s_addr, 4); 40155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) conn->request_info.remote_ip = ntohl(conn->request_info.remote_ip); 40165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) conn->request_info.is_ssl = conn->client.is_ssl; 40175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 40185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!conn->client.is_ssl || 40195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (conn->client.is_ssl && sslize(conn, SSL_accept))) { 40205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) process_new_connection(conn); 40215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 40225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 40235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) close_connection(conn); 40245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 40255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) free(conn); 40265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 40275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Signal master that we're done with connection and exiting 40285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (void) pthread_mutex_lock(&ctx->mutex); 40295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ctx->num_threads--; 40305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (void) pthread_cond_signal(&ctx->cond); 40315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) assert(ctx->num_threads >= 0); 40325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (void) pthread_mutex_unlock(&ctx->mutex); 40335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 40345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DEBUG_TRACE(("exiting")); 40355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 40365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 40375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Master thread adds accepted socket to a queue 40385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void produce_socket(struct mg_context *ctx, const struct socket *sp) { 40395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (void) pthread_mutex_lock(&ctx->mutex); 40405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 40415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If the queue is full, wait 40425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while (ctx->stop_flag == 0 && 40435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ctx->sq_head - ctx->sq_tail >= (int) ARRAY_SIZE(ctx->queue)) { 40445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (void) pthread_cond_wait(&ctx->sq_empty, &ctx->mutex); 40455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 40465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 40475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (ctx->sq_head - ctx->sq_tail < (int) ARRAY_SIZE(ctx->queue)) { 40485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Copy socket to the queue and increment head 40495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ctx->queue[ctx->sq_head % ARRAY_SIZE(ctx->queue)] = *sp; 40505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ctx->sq_head++; 40515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DEBUG_TRACE(("queued socket %d", sp->sock)); 40525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 40535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 40545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (void) pthread_cond_signal(&ctx->sq_full); 40555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (void) pthread_mutex_unlock(&ctx->mutex); 40565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 40575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 40585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void accept_new_connection(const struct socket *listener, 40595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) struct mg_context *ctx) { 40605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) struct socket accepted; 40615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int allowed; 40625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 40635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) accepted.rsa.len = sizeof(accepted.rsa.u.sin); 40645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) accepted.lsa = listener->lsa; 40655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) accepted.sock = accept(listener->sock, &accepted.rsa.u.sa, &accepted.rsa.len); 40665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (accepted.sock != INVALID_SOCKET) { 40675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) allowed = check_acl(ctx, &accepted.rsa); 40685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (allowed) { 40695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Put accepted socket structure into the queue 40705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DEBUG_TRACE(("accepted socket %d", accepted.sock)); 40715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) accepted.is_ssl = listener->is_ssl; 40725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) accepted.is_proxy = listener->is_proxy; 40735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) produce_socket(ctx, &accepted); 40745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 40755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cry(fc(ctx), "%s: %s is not allowed to connect", 40765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) __func__, inet_ntoa(accepted.rsa.u.sin.sin_addr)); 40775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (void) closesocket(accepted.sock); 40785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 40795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 40805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 40815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 40825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void master_thread(struct mg_context *ctx) { 40835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fd_set read_set; 40845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) struct timeval tv; 40855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) struct socket *sp; 40865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int max_fd; 40875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 40885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while (ctx->stop_flag == 0) { 40895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FD_ZERO(&read_set); 40905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) max_fd = -1; 40915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 40925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Add listening sockets to the read set 40935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (sp = ctx->listening_sockets; sp != NULL; sp = sp->next) { 40945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) add_to_set(sp->sock, &read_set, &max_fd); 40955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 40965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 40975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tv.tv_sec = 0; 40985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tv.tv_usec = 200 * 1000; 40995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 41005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (select(max_fd + 1, &read_set, NULL, NULL, &tv) < 0) { 41015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifdef _WIN32 41025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // On windows, if read_set and write_set are empty, 41035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // select() returns "Invalid parameter" error 41045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // (at least on my Windows XP Pro). So in this case, we sleep here. 41055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sleep(1); 41065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif // _WIN32 41075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 41085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (sp = ctx->listening_sockets; sp != NULL; sp = sp->next) { 41095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (ctx->stop_flag == 0 && FD_ISSET(sp->sock, &read_set)) { 41105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) accept_new_connection(sp, ctx); 41115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 41125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 41135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 41145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 41155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DEBUG_TRACE(("stopping workers")); 41165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 41175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Stop signal received: somebody called mg_stop. Quit. 41185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) close_all_listening_sockets(ctx); 41195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 41205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Wakeup workers that are waiting for connections to handle. 41215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pthread_cond_broadcast(&ctx->sq_full); 41225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 41235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Wait until all threads finish 41245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (void) pthread_mutex_lock(&ctx->mutex); 41255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while (ctx->num_threads > 0) { 41265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (void) pthread_cond_wait(&ctx->cond, &ctx->mutex); 41275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 41285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (void) pthread_mutex_unlock(&ctx->mutex); 41295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 41305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // All threads exited, no sync is needed. Destroy mutex and condvars 41315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (void) pthread_mutex_destroy(&ctx->mutex); 41325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (void) pthread_cond_destroy(&ctx->cond); 41335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (void) pthread_cond_destroy(&ctx->sq_empty); 41345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (void) pthread_cond_destroy(&ctx->sq_full); 41355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 41365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if !defined(NO_SSL) 41375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) uninitialize_ssl(ctx); 41385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 41395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 41405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Signal mg_stop() that we're done 41415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ctx->stop_flag = 2; 41425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 41435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DEBUG_TRACE(("exiting")); 41445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 41455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 41465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void free_context(struct mg_context *ctx) { 41475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int i; 41485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 41495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Deallocate config parameters 41505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (i = 0; i < NUM_OPTIONS; i++) { 41515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (ctx->config[i] != NULL) 41525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) free(ctx->config[i]); 41535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 41545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 41555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Deallocate SSL context 41565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (ctx->ssl_ctx != NULL) { 41575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SSL_CTX_free(ctx->ssl_ctx); 41585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 41595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifndef NO_SSL 41605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (ssl_mutexes != NULL) { 41615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) free(ssl_mutexes); 41625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 41635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif // !NO_SSL 41645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 41655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Deallocate context itself 41665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) free(ctx); 41675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 41685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 41695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void mg_stop(struct mg_context *ctx) { 41705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ctx->stop_flag = 1; 41715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 41725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Wait until mg_fini() stops 41735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while (ctx->stop_flag != 2) { 41745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (void) sleep(0); 41755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 41765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) free_context(ctx); 41775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 41785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(_WIN32) && !defined(__SYMBIAN32__) 41795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (void) WSACleanup(); 41805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif // _WIN32 41815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 41825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 41835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)struct mg_context *mg_start(mg_callback_t user_callback, void *user_data, 41845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char **options) { 41855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) struct mg_context *ctx; 41865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char *name, *value, *default_value; 41875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int i; 41885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 41895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(_WIN32) && !defined(__SYMBIAN32__) 41905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) WSADATA data; 41915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) WSAStartup(MAKEWORD(2,2), &data); 41925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif // _WIN32 41935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 41945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Allocate context and initialize reasonable general case defaults. 41955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // TODO(lsm): do proper error handling here. 41965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ctx = (struct mg_context *) calloc(1, sizeof(*ctx)); 41975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ctx->user_callback = user_callback; 41985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ctx->user_data = user_data; 41995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 42005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while (options && (name = *options++) != NULL) { 42015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if ((i = get_option_index(name)) == -1) { 42025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cry(fc(ctx), "Invalid option: %s", name); 42035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) free_context(ctx); 42045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return NULL; 42055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if ((value = *options++) == NULL) { 42065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cry(fc(ctx), "%s: option value cannot be NULL", name); 42075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) free_context(ctx); 42085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return NULL; 42095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 42105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ctx->config[i] = mg_strdup(value); 42115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DEBUG_TRACE(("[%s] -> [%s]", name, value)); 42125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 42135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 42145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Set default value if needed 42155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (i = 0; config_options[i * ENTRIES_PER_CONFIG_OPTION] != NULL; i++) { 42165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) default_value = config_options[i * ENTRIES_PER_CONFIG_OPTION + 2]; 42175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (ctx->config[i] == NULL && default_value != NULL) { 42185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ctx->config[i] = mg_strdup(default_value); 42195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DEBUG_TRACE(("Setting default: [%s] -> [%s]", 42205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) config_options[i * ENTRIES_PER_CONFIG_OPTION + 1], 42215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) default_value)); 42225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 42235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 42245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 42255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // NOTE(lsm): order is important here. SSL certificates must 42265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // be initialized before listening ports. UID must be set last. 42275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!set_gpass_option(ctx) || 42285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if !defined(NO_SSL) 42295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) !set_ssl_option(ctx) || 42305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 42315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) !set_ports_option(ctx) || 42325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if !defined(_WIN32) 42335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) !set_uid_option(ctx) || 42345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 42355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) !set_acl_option(ctx)) { 42365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) free_context(ctx); 42375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return NULL; 42385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 42395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 42405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if !defined(_WIN32) && !defined(__SYMBIAN32__) 42415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Ignore SIGPIPE signal, so if browser cancels the request, it 42425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // won't kill the whole process. 42435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (void) signal(SIGPIPE, SIG_IGN); 42445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif // !_WIN32 42455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 42465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (void) pthread_mutex_init(&ctx->mutex, NULL); 42475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (void) pthread_cond_init(&ctx->cond, NULL); 42485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (void) pthread_cond_init(&ctx->sq_empty, NULL); 42495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (void) pthread_cond_init(&ctx->sq_full, NULL); 42505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 42515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Start master (listening) thread 42525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) start_thread(ctx, (mg_thread_func_t) master_thread, ctx); 42535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 42545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Start worker threads 42555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (i = 0; i < atoi(ctx->config[NUM_THREADS]); i++) { 42565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (start_thread(ctx, (mg_thread_func_t) worker_thread, ctx) != 0) { 42575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cry(fc(ctx), "Cannot start worker thread: %d", ERRNO); 42585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 42595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ctx->num_threads++; 42605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 42615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 42625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 42635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return ctx; 42645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4265