Changeset ad6c1f1 in rtems


Ignore:
Timestamp:
Jun 28, 2012, 8:43:08 AM (7 years ago)
Author:
Christian Mauderer <christian.mauderer@…>
Branches:
4.11, master
Children:
4248b28
Parents:
c65afce4
git-author:
Christian Mauderer <christian.mauderer@…> (06/28/12 08:43:08)
git-committer:
Sebastian Huber <sebastian.huber@…> (07/12/12 07:51:44)
Message:

mghttpd: Update Mongoose

Update to Mongoose Mercurial revision 268:38a02c8a6744 available at:

https://code.google.com/p/mongoose/

Location:
cpukit/mghttpd
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • cpukit/mghttpd/Makefile.am

    rc65afce4 rad6c1f1  
    77libmghttpd_a_CPPFLAGS = $(AM_CPPFLAGS)
    88# libmghttpd_a_CPPFLAGS += -DHAVE_MD5
    9 libmghttpd_a_CPPFLAGS += -DNO_SSI -DNO_SSL -DNO_CGI
     9libmghttpd_a_CPPFLAGS += -DNO_SSL -DNO_POPEN -DNO_CGI
    1010
    1111libmghttpd_a_SOURCES = mongoose.c mongoose.h
  • cpukit/mghttpd/mongoose.1

    rc65afce4 rad6c1f1  
    11.\" Process this file with
    22.\" groff -man -Tascii mongoose.1
    3 .Dd Dec 1, 2008
     3.\" $Id: mongoose.1,v 1.12 2008/11/29 15:32:42 drozd Exp $
     4.Dd Aug 31, 2010
    45.Dt mongoose 1
    56.Sh NAME
     
    89.Sh SYNOPSIS
    910.Nm
    10 .Op Ar options
    1111.Op Ar config_file
     12.Op Ar OPTIONS
    1213.Nm
    1314.Fl A Ar htpasswd_file domain_name user_name password
    1415.Sh DESCRIPTION
    1516.Nm
    16 is small, fast and easy to use web server with CGI, SSL, Digest Authorization
    17 support.
     17is small, fast and easy to use web server with CGI, SSL, MD5 authorization,
     18and basic SSI support.
    1819.Pp
    1920.Nm
    2021does not detach from terminal, and uses current working directory
    2122as the web root, unless
    22 .Fl root
     23.Fl r
    2324option is specified.
    24 .Pp
    25 It is possible to specify multiple ports to listen on. For example, to
    26 make
     25It is possible to specify multiple ports to listen on. For example, to make
     26mongoose listen on HTTP port 80 and HTTPS port 443, one should start it as:
    2727.Nm
    28 listen on HTTP port 80 and HTTPS port 443, one should start it as
    29 .Dq mongoose -ssl_cert cert.pem -ports 80,443s .
    30 .Pp
    31 Options may be specified in any order, with one exception: if SSL listening
    32 port is specified in the -ports option, then -ssl_cert option must be set
    33 before -ports option.
     28.Fl s Ar cert.pem Fl p Ar 80,443s
    3429.Pp
    3530Unlike other web servers,
    3631.Nm
    37 does not expect CGI scripts to be put in a special directory. CGI scripts may
    38 be anywhere. CGI files are recognized by the file extension.
     32does not require CGI scripts be put in a special directory. CGI scripts can
     33be anywhere. CGI (and SSI) files are recognized by the file name pattern.
     34.Nm
     35uses shell-like glob patterns with the following syntax:
     36.Bl -tag -compact -width indent
     37.It **
     38Matches everything
     39.It *
     40Matches everything but slash character, '/'
     41.It ?
     42Matches any character
     43.It $
     44Matches the end of the string
     45.It |
     46Matches if pattern on the left side or the right side matches. Pattern on the
     47left side is matched first
     48.El
     49All other characters in the pattern match themselves.
    3950.Pp
    40 SSI files are also recognized by extension. Unknown SSI directives are silently
    41 ignored. Currently, two SSI directives supported, "include" and "exec". For the
    42 "include" directive, included file name can be specified in three different
    43 ways. Below is the summary of supported SSI directives:
    44 .Bl -bullet
    45 .It
    46 <!--#exec "shell command"--> Execute shell command.
    47 .It
    48 <!--#include "path"--> File path must be relative to the current document.
    49 .It
    50 <!--#include virtual="path"--> File path must be relative to the document root.
    51 .It
    52 <!--#include file="path"--> File path must be the absolute path.
    53 .El
    54 .Pp
     51If no arguments are given,
    5552.Nm
    56 can use the configuration file. By default, it is "mongoose.conf", and if it
    57 is present in the same directory where
    58 .Nm
    59 lives, the command line options are read from it. Alternatively, the
    60 configuration file may be specified as a last argument. The format of the
    61 configuration file is exactly the same as for the command line options, the
    62 only difference is that the command line options must be specified on
    63 separate lines, and leading dashes for option names must be omitted.
    64 Lines beginning with '#' are regarded as comments and ignored.
     53searches for a configuration file called "mongoose.conf" in the same directory
     54where mongoose binary is located. Alternatively, a file name could be
     55specified in the command line. Format of the configuration file is the same
     56as for the command line options except that each option must be specified
     57on a separate line, leading dashes for option names must be omitted.
     58Lines beginning with '#' and empty lines are ignored.
    6559.Pp
    6660.Sh OPTIONS
     
    6862.It Fl A Ar htpasswd_file domain_name user_name password
    6963Add/edit user's password in the passwords file. Deleting users can be done
    70 with any text editor. Functionality similar to Apache's
     64with any text editor. Functionality is similar to Apache's
    7165.Ic htdigest
    7266utility.
    73 .It Fl access_log Ar file
    74 Access log file. Default: not set, no logging is done.
    75 .It Fl acl Ar (+|-)x.x.x.x[/x],...
     67.It Fl C Ar cgi_pattern
     68All files that fully match cgi_pattern are treated as CGI.
     69Default pattern allows CGI files be
     70anywhere. To restrict CGIs to certain directory, use e.g. "-C /cgi-bin/**.cgi".
     71Default: "**.cgi$|**.pl$|**.php$"
     72.It Fl E Ar cgi_environment
     73Extra environment variables to be passed to the CGI script in addition to
     74standard ones. The list must be comma-separated list of X=Y pairs, like this:
     75"VARIABLE1=VALUE1,VARIABLE2=VALUE2". Default: ""
     76.It Fl G Ar put_delete_passwords_file
     77PUT and DELETE passwords file. This must be specified if PUT or
     78DELETE methods are used. Default: ""
     79.It Fl I Ar cgi_interpreter
     80Use
     81.Ar cgi_interpreter
     82as a CGI interpreter for all CGI scripts regardless script extension.
     83Mongoose decides which interpreter to use by looking at
     84the first line of a CGI script.  Default: "".
     85.It Fl M Ar max_request_size
     86Maximum HTTP request size in bytes. Default: "16384"
     87.It Fl P Ar protect_uri
     88Comma separated list of URI=PATH pairs, specifying that given URIs
     89must be protected with respected password files. Default: ""
     90.It Fl R Ar authentication_domain
     91Authorization realm. Default: "mydomain.com"
     92.It Fl S Ar ssi_pattern
     93All files that fully match ssi_pattern are treated as SSI.
     94Unknown SSI directives are silently ignored. Currently, two SSI directives
     95are supported, "include" and "exec".  Default: "**.shtml$|**.shtm$"
     96.It Fl a Ar access_log_file
     97Access log file. Default: "", no logging is done.
     98.It Fl d Ar enable_directory_listing
     99Enable/disable directory listing. Default: "yes"
     100.It Fl e Ar error_log_file
     101Error log file. Default: "", no errors are logged.
     102.It Fl g Ar global_passwords_file
     103Location of a global passwords file. If set, per-directory .htpasswd files are
     104ignored, and all requests must be authorised against that file.  Default: ""
     105.It Fl i Ar index_files
     106Comma-separated list of files to be treated as directory index files.
     107Default: "index.html,index.htm,index.cgi"
     108.It Fl l Ar access_control_list
    76109Specify access control list (ACL). ACL is a comma separated list
    77110of IP subnets, each subnet is prepended by '-' or '+' sign. Plus means allow,
     
    79112omitted, like "-1.2.3.4", then it means single IP address. Mask may vary
    80113from 0 to 32 inclusive. On each request, full list is traversed, and
    81 last match wins. Default: not set, allow all.
    82 .It Fl admin_uri Ar uri
    83 If set,
    84 .Nm
    85 creates special administrative URI where options may be changed at runtime.
    86 This URI probably wants to be password-protected, look at
    87 .Fl protect
    88 option, and in the EXAMPLES section on how to do it. Default: not set.
    89 .It Fl aliases Ar list
    90 This options gives an ability to serve the directories outside web root
    91 by sort of symbolic linking to certain URI. The
    92 .Ar list
    93 must be comma-separated list of URI=PATH pairs, like this:
    94 "/etc/=/my_etc,/tmp=/my_tmp". Default: not set.
    95 .It Fl auth_PUT Ar file
    96 PUT and DELETE passwords file. This must be specified if PUT or
    97 DELETE methods are used. Default: not set.
    98 .It Fl auth_gpass Ar file
    99 Location of global passwords file. When set, per-directory .htpasswd files are
    100 ignored, and all accessed must be authorised against global passwords file.
    101 Default: not set.
    102 .It Fl auth_realm Ar domain_name
    103 Authorization realm. Default: "mydomain.com".
    104 .It Fl cgi_env Ar list
    105 Pass environment variables to the CGI script in addition to standard ones.
    106 The list must be comma-separated list of X=Y pairs, like this:
    107 "VARIABLE1=VALUE1,VARIABLE2=VALUE2".  Default: not set.
    108 .It Fl cgi_ext Ar list
    109 Comma-separated list of CGI extensions.  All files having these extensions
    110 are treated as CGI scripts. Default: "cgi,pl,php"
    111 .It Fl cgi_interp Ar file
    112 Force
    113 .Ar file
    114 to be a CGI interpreter for all CGI scripts. By default this option is not
    115 set, and
    116 .Nm
    117 decides which interpreter to use by looking at the first line of CGI script.
    118 .It Fl dir_list Ar yes|no
    119 Enable/disable directory listing. Default: "1" (enabled).
    120 .It Fl error_log Ar file
    121 Error log file. Default: not set, no errors are logged.
    122 .It Fl idle_time Ar num_seconds
    123 Number of seconds worker thread waits for some work before exit. Default: 10
    124 .It Fl max_threads Ar number
    125 Maximum number of worker threads to start. Default: 100
    126 .It Fl mime_types Ar list
    127 Additional to builtin mime types, in form
     114last match wins. Default setting is to allow all. For example, to allow only
     115192.168/16 subnet to connect, run "mongoose -0.0.0.0/0,+192.168/16".
     116Default: ""
     117.It Fl m Ar extra_mime_types
     118Extra mime types to recognize, in form
    128119"extension1=type1,extension2=type2,...". Extension must include dot.
    129 .It Fl ports Ar port_list
     120Example: "mongoose -m .cpp=plain/text,.java=plain/text". Default: ""
     121.It Fl p Ar listening_ports
    130122Comma-separated list of ports to listen on. If the port is SSL, a letter 's'
    131 must be appeneded, for example, "-ports 80,443s" will open port 80 and port 443,
     123must be appeneded, for example, "-p 80,443s" will open port 80 and port 443,
    132124and connections on port 443 will be SSL-ed. It is possible to specify an
    133125IP address to bind to. In this case, an IP address and a colon must be
    134 prepended to the port number, for example, "-ports 127.0.0.1:8080". Note that
    135 if SSL listening port is requested, then
    136 .Fl ssl_cert
    137 option must specified BEFORE
    138 .Fl ports
    139 option. Default: 8080
    140 .It Fl protect Ar list
    141 Comma separated list of URI=PATH pairs, specifying that given URIs
    142 must the protected with respected password files. Default: not set.
    143 .It Fl root Ar directory
    144 Location of the WWW root directory. Default: working directory from which
    145 .Nm
    146 has been started.
    147 .It Fl ssi_ext Ar list
    148 Comma separated list of SSI extensions. Default: "shtml,shtm".
    149 .It Fl ssl_cert Ar pem_file
    150 Location of SSL certificate file. Default: not set.
    151 .It Fl uid Ar login
    152 Switch to given user after startup. Default: not set.
     126prepended to the port number. For example, to bind to a loopback interface
     127on port 80 and to all interfaces on HTTPS port 443, use
     128"mongoose -p 127.0.0.1:80,443s". Default: "8080"
     129.It Fl r Ar document_root
     130Location of the WWW root directory. Default: "."
     131.It Fl s Ar ssl_certificate
     132Location of SSL certificate file. Default: ""
     133.It Fl t Ar num_threads
     134Number of worker threads to start. Default: "10"
     135.It Fl u Ar run_as_user
     136Switch to given user's credentials after startup. Default: ""
     137.It Fl w Ar url_rewrite_patterns
     138Comma-separated list of URL rewrites in the form of
     139"pattern=substitution,..." If the "pattern" matches some prefix
     140of the requested URL, then matched prefix gets substituted with "substitution".
     141For example, "-w /config=/etc,**.doc|**.rtf=/path/to/cgi-bin/handle_doc.cgi"
     142will serve all URLs that start with "/config" from the "/etc" directory, and
     143call handle_doc.cgi script for .doc and .rtf file requests. If some pattern
     144matches, no further matching/substitution is performed
     145(first matching pattern wins). Use full paths in substitutions. Default: ""
    153146.El
    154147.Pp
     
    156149.Nm
    157150was designed to be embeddable into C/C++ applications. Since the
    158 source code is contained in single C file, it is fairly easy to embed it,
    159 and to follow the updates. Please refer to http://code.google.com/p/mongoose
     151source code is contained in single C file, it is fairly easy to embed it
     152and follow the updates. Please refer to http://code.google.com/p/mongoose
    160153for details.
    161154.Pp
    162155.Sh EXAMPLES
    163156.Bl -tag -width indent
    164 .It Nm Fl root Ar /var/www Fl ssl_cert Ar /etc/cert.pem Fl ports Ar 8080,8043s Fl aliases Ar /aa=/tmp,/bb=/etc
    165 Start listening on port 8080 for HTTP, and 8043 for HTTPS connections.
    166 Use /etc/cert.pem as SSL certificate file. Web root is /var/www. In addition,
    167 map directory /tmp to URI /aa, directory /etc to URI /bb.
    168 .It Nm Fl acl Ar -0.0.0.0/0,+10.0.0.0/8,+1.2.3.4
     157.It Nm Fl r Ar /var/www Fl s Ar /etc/cert.pem Fl p Ar 8080,8043s
     158Start serving files from /var/www. Listen on port 8080 for HTTP, and 8043
     159for HTTPS connections.  Use /etc/cert.pem as SSL certificate file.
     160.It Nm Fl l Ar -0.0.0.0/0,+10.0.0.0/8,+1.2.3.4
    169161Deny connections from everywhere, allow only IP address 1.2.3.4 and
    170162all IP addresses from 10.0.0.0/8 subnet to connect.
    171 .It Nm Fl admin_uri Ar /ctl Fl protect Ar /ctl=/tmp/passwords.txt
    172 Create an administrative URI "/ctl" where
    173 options may be changed at runtime, and protect that URI with authorization.
     163.It Nm Fl w Ar **=/usr/bin/script.cgi
     164Invoke /usr/bin/script.cgi for every incoming request, regardless of the URL.
    174165.El
    175166.Pp
  • cpukit/mghttpd/mongoose.c

    rc65afce4 rad6c1f1  
    1 /*
    2  * Copyright (c) 2004-2009 Sergey Lyubka
    3  * Portions Copyright (c) 2009 Gilbert Wellisch
    4  *
    5  * Permission is hereby granted, free of charge, to any person obtaining a copy
    6  * of this software and associated documentation files (the "Software"), to deal
    7  * in the Software without restriction, including without limitation the rights
    8  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
    9  * copies of the Software, and to permit persons to whom the Software is
    10  * furnished to do so, subject to the following conditions:
    11  *
    12  * The above copyright notice and this permission notice shall be included in
    13  * all copies or substantial portions of the Software.
    14  *
    15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    18  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    20  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
    21  * THE SOFTWARE.
    22  */
    23 
    24 #if HAVE_CONFIG_H
    25 #include "config.h"
     1// Copyright (c) 2004-2011 Sergey Lyubka
     2//
     3// Permission is hereby granted, free of charge, to any person obtaining a copy
     4// of this software and associated documentation files (the "Software"), to deal
     5// in the Software without restriction, including without limitation the rights
     6// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     7// copies of the Software, and to permit persons to whom the Software is
     8// furnished to do so, subject to the following conditions:
     9//
     10// The above copyright notice and this permission notice shall be included in
     11// all copies or substantial portions of the Software.
     12//
     13// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     14// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     15// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
     16// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     17// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
     18// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
     19// THE SOFTWARE.
     20
     21#if defined(_WIN32)
     22#define _CRT_SECURE_NO_WARNINGS // Disable deprecation warning in VS2005
     23#else
     24#define _XOPEN_SOURCE 600     // For flockfile() on Linux
     25#define _LARGEFILE_SOURCE     // Enable 64-bit file offsets
     26#define __STDC_FORMAT_MACROS  // <inttypes.h> wants this for C++
     27#define __STDC_LIMIT_MACROS   // C++ wants that for INT64_MAX
    2628#endif
    2729
    28 #if defined(_WIN32)
    29 #define _CRT_SECURE_NO_WARNINGS /* Disable deprecation warning in VS2005 */
    30 #endif /* _WIN32 */
    31 
    32 #ifndef _WIN32_WCE /* Some ANSI #includes are not available on Windows CE */
     30#if defined(__SYMBIAN32__)
     31#define NO_SSL // SSL is not supported
     32#define NO_CGI // CGI is not supported
     33#define PATH_MAX FILENAME_MAX
     34#endif // __SYMBIAN32__
     35
     36#ifndef _WIN32_WCE // Some ANSI #includes are not available on Windows CE
    3337#include <sys/types.h>
    3438#include <sys/stat.h>
     
    3640#include <signal.h>
    3741#include <fcntl.h>
    38 #endif /* !_WIN32_WCE */
     42#endif // !_WIN32_WCE
    3943
    4044#include <time.h>
     
    4852#include <stdio.h>
    4953
    50 #if defined(_WIN32)             /* Windows specific #includes and #defines */
    51 #define _WIN32_WINNT    0x0400  /* To make it link in VS2005 */
     54#if defined(_WIN32) && !defined(__SYMBIAN32__) // Windows specific
     55#define _WIN32_WINNT 0x0400 // To make it link in VS2005
    5256#include <windows.h>
     57
     58#ifndef PATH_MAX
     59#define PATH_MAX MAX_PATH
     60#endif
    5361
    5462#ifndef _WIN32_WCE
     
    5664#include <direct.h>
    5765#include <io.h>
    58 #else /* _WIN32_WCE */
    59 /* Windows CE-specific definitions */
     66#else // _WIN32_WCE
    6067#include <winsock2.h>
    61 #define NO_CGI  /* WinCE has no pipes */
    62 #define NO_SSI  /* WinCE has no pipes */
    63 
    64 #define FILENAME_MAX    MAX_PATH
    65 #define BUFSIZ          4096
     68#include <ws2tcpip.h>
     69#define NO_CGI // WinCE has no pipes
     70
    6671typedef long off_t;
    67 
    68 #define errno                   GetLastError()
    69 #define strerror(x)             _ultoa(x, (char *) _alloca(sizeof(x) *3 ), 10)
    70 #endif /* _WIN32_WCE */
    71 
    72 #define EPOCH_DIFF      0x019DB1DED53E8000 /* 116444736000000000 nsecs */
    73 #define RATE_DIFF       10000000 /* 100 nsecs */
    74 #define MAKEUQUAD(lo, hi)       ((uint64_t)(((uint32_t)(lo)) | \
    75                                 ((uint64_t)((uint32_t)(hi))) << 32))
    76 #define SYS2UNIX_TIME(lo, hi) \
    77         (time_t) ((MAKEUQUAD((lo), (hi)) - EPOCH_DIFF) / RATE_DIFF)
    78 
    79 /*
    80  * Visual Studio 6 does not know __func__ or __FUNCTION__
    81  * The rest of MS compilers use __FUNCTION__, not C99 __func__
    82  * Also use _strtoui64 on modern M$ compilers
    83  */
     72#define BUFSIZ  4096
     73
     74#define errno   GetLastError()
     75#define strerror(x)  _ultoa(x, (char *) _alloca(sizeof(x) *3 ), 10)
     76#endif // _WIN32_WCE
     77
     78#define MAKEUQUAD(lo, hi) ((uint64_t)(((uint32_t)(lo)) | \
     79      ((uint64_t)((uint32_t)(hi))) << 32))
     80#define RATE_DIFF 10000000 // 100 nsecs
     81#define EPOCH_DIFF MAKEUQUAD(0xd53e8000, 0x019db1de)
     82#define SYS2UNIX_TIME(lo, hi) \
     83  (time_t) ((MAKEUQUAD((lo), (hi)) - EPOCH_DIFF) / RATE_DIFF)
     84
     85// Visual Studio 6 does not know __func__ or __FUNCTION__
     86// The rest of MS compilers use __FUNCTION__, not C99 __func__
     87// Also use _strtoui64 on modern M$ compilers
    8488#if defined(_MSC_VER) && _MSC_VER < 1300
    85 #define STRX(x)                 #x
    86 #define STR(x)                  STRX(x)
    87 #define __func__                "line " STR(__LINE__)
    88 #define strtoull(x, y, z)       strtoul(x, y, z)
     89#define STRX(x) #x
     90#define STR(x) STRX(x)
     91#define __func__ "line " STR(__LINE__)
     92#define strtoull(x, y, z) strtoul(x, y, z)
     93#define strtoll(x, y, z) strtol(x, y, z)
    8994#else
    90 #define __func__                __FUNCTION__
    91 #define strtoull(x, y, z)       _strtoui64(x, y, z)
    92 #endif /* _MSC_VER */
    93 
    94 #define ERRNO                   GetLastError()
    95 #define NO_SOCKLEN_T
    96 #define SSL_LIB                 "ssleay32.dll"
    97 #define CRYPTO_LIB              "libeay32.dll"
    98 #define DIRSEP                  '\\'
    99 #define IS_DIRSEP_CHAR(c)       ((c) == '/' || (c) == '\\')
    100 #define O_NONBLOCK              0
    101 #define EWOULDBLOCK             WSAEWOULDBLOCK
    102 #define _POSIX_
    103 #define INT64_FMT               "I64"
    104 
    105 #define SHUT_WR                 1
    106 #define snprintf                _snprintf
    107 #define vsnprintf               _vsnprintf
    108 #define sleep(x)                Sleep((x) * 1000)
    109 
    110 #define popen(x, y)             _popen(x, y)
    111 #define pclose(x)               _pclose(x)
    112 #define close(x)                _close(x)
    113 #define dlsym(x,y)              GetProcAddress((HINSTANCE) (x), (y))
    114 #define RTLD_LAZY               0
    115 #define fseeko(x, y, z)         fseek((x), (y), (z))
    116 #define fdopen(x, y)            _fdopen((x), (y))
    117 #define write(x, y, z)          _write((x), (y), (unsigned) z)
    118 #define read(x, y, z)           _read((x), (y), (unsigned) z)
    119 #define flockfile(x)            (void) 0
    120 #define funlockfile(x)          (void) 0
     95#define __func__  __FUNCTION__
     96#define strtoull(x, y, z) _strtoui64(x, y, z)
     97#define strtoll(x, y, z) _strtoi64(x, y, z)
     98#endif // _MSC_VER
     99
     100#define ERRNO   GetLastError()
     101#define NO_SOCKLEN_T
     102#define SSL_LIB   "ssleay32.dll"
     103#define CRYPTO_LIB  "libeay32.dll"
     104#define DIRSEP '\\'
     105#define IS_DIRSEP_CHAR(c) ((c) == '/' || (c) == '\\')
     106#define O_NONBLOCK  0
     107#if !defined(EWOULDBLOCK)
     108#define EWOULDBLOCK  WSAEWOULDBLOCK
     109#endif // !EWOULDBLOCK
     110#define _POSIX_
     111#define INT64_FMT  "I64d"
     112
     113#define WINCDECL __cdecl
     114#define SHUT_WR 1
     115#define snprintf _snprintf
     116#define vsnprintf _vsnprintf
     117#define mg_sleep(x) Sleep(x)
     118
     119#define pipe(x) _pipe(x, BUFSIZ, _O_BINARY)
     120#define popen(x, y) _popen(x, y)
     121#define pclose(x) _pclose(x)
     122#define close(x) _close(x)
     123#define dlsym(x,y) GetProcAddress((HINSTANCE) (x), (y))
     124#define RTLD_LAZY  0
     125#define fseeko(x, y, z) fseek((x), (y), (z))
     126#define fdopen(x, y) _fdopen((x), (y))
     127#define write(x, y, z) _write((x), (y), (unsigned) z)
     128#define read(x, y, z) _read((x), (y), (unsigned) z)
     129#define flockfile(x) EnterCriticalSection(&global_log_file_lock)
     130#define funlockfile(x) LeaveCriticalSection(&global_log_file_lock)
    121131
    122132#if !defined(fileno)
    123 #define fileno(x)               _fileno(x)
    124 #endif /* !fileno MINGW #defines fileno */
     133#define fileno(x) _fileno(x)
     134#endif // !fileno MINGW #defines fileno
    125135
    126136typedef HANDLE pthread_mutex_t;
    127 typedef HANDLE pthread_cond_t;
     137typedef struct {HANDLE signal, broadcast;} pthread_cond_t;
    128138typedef DWORD pthread_t;
    129 #define pid_t HANDLE    /* MINGW typedefs pid_t to int. Using #define here. */
     139#define pid_t HANDLE // MINGW typedefs pid_t to int. Using #define here.
    130140
    131141struct timespec {
    132         long tv_nsec;
    133         long tv_sec;
     142  long tv_nsec;
     143  long tv_sec;
    134144};
    135145
    136146static int pthread_mutex_lock(pthread_mutex_t *);
    137147static int pthread_mutex_unlock(pthread_mutex_t *);
     148static FILE *mg_fopen(const char *path, const char *mode);
    138149
    139150#if defined(HAVE_STDINT)
    140151#include <stdint.h>
    141152#else
    142 typedef unsigned int            uint32_t;
    143 typedef unsigned short          uint16_t;
    144 typedef unsigned __int64        uint64_t;
    145 typedef __int64                 int64_t;
    146 #define INT64_MAX               9223372036854775807
    147 #endif /* HAVE_STDINT */
    148 
    149 /*
    150  * POSIX dirent interface
    151  */
     153typedef unsigned int  uint32_t;
     154typedef unsigned short  uint16_t;
     155typedef unsigned __int64 uint64_t;
     156typedef __int64   int64_t;
     157#define INT64_MAX  9223372036854775807
     158#endif // HAVE_STDINT
     159
     160// POSIX dirent interface
    152161struct dirent {
    153         char    d_name[FILENAME_MAX];
     162  char d_name[PATH_MAX];
    154163};
    155164
    156165typedef struct DIR {
    157         HANDLE                  handle;
    158         WIN32_FIND_DATAW        info;
    159         struct dirent           result;
     166  HANDLE   handle;
     167  WIN32_FIND_DATAW info;
     168  struct dirent  result;
    160169} DIR;
    161170
    162 #else                           /* UNIX  specific       */
     171#else    // UNIX  specific
    163172#include <sys/wait.h>
    164173#include <sys/socket.h>
    165174#include <sys/select.h>
    166 #if HAVE_SYS_MMAN_H
    167 #include <sys/mman.h>
    168 #endif
    169 #if defined(__rtems__)
    170 #define flockfile(x)            (void) 0
    171 #define funlockfile(x)          (void) 0
    172 #endif
    173175#include <netinet/in.h>
    174176#include <arpa/inet.h>
     
    176178#include <stdint.h>
    177179#include <inttypes.h>
     180#include <netdb.h>
    178181
    179182#include <pwd.h>
    180183#include <unistd.h>
    181184#include <dirent.h>
    182 #if HAVE_DLFCN_H
     185#if !defined(NO_SSL_DL) && !defined(NO_SSL)
    183186#include <dlfcn.h>
    184187#endif
    185188#include <pthread.h>
    186 #define SSL_LIB                 "libssl.so"
    187 #define CRYPTO_LIB              "libcrypto.so"
    188 #define DIRSEP                  '/'
    189 #define IS_DIRSEP_CHAR(c)       ((c) == '/')
    190 #define O_BINARY                0
    191 #define closesocket(a)          close(a)
    192 #define mg_fopen(x, y)          fopen(x, y)
    193 #define mg_mkdir(x, y)          mkdir(x, y)
    194 #define mg_remove(x)            remove(x)
    195 #define mg_rename(x, y)         rename(x, y)
    196 #define ERRNO                   errno
    197 #define INVALID_SOCKET          (-1)
    198 #define INT64_FMT               PRId64
     189#if defined(__MACH__)
     190#define SSL_LIB   "libssl.dylib"
     191#define CRYPTO_LIB  "libcrypto.dylib"
     192#else
     193#if !defined(SSL_LIB)
     194#define SSL_LIB   "libssl.so"
     195#endif
     196#if !defined(CRYPTO_LIB)
     197#define CRYPTO_LIB  "libcrypto.so"
     198#endif
     199#endif
     200#define DIRSEP   '/'
     201#define IS_DIRSEP_CHAR(c) ((c) == '/')
     202#ifndef O_BINARY
     203#define O_BINARY  0
     204#endif // O_BINARY
     205#define closesocket(a) close(a)
     206#define mg_fopen(x, y) fopen(x, y)
     207#define mg_mkdir(x, y) mkdir(x, y)
     208#define mg_remove(x) remove(x)
     209#define mg_rename(x, y) rename(x, y)
     210#define mg_sleep(x) usleep((x) * 1000)
     211#define ERRNO errno
     212#define INVALID_SOCKET (-1)
     213#define INT64_FMT PRId64
    199214typedef int SOCKET;
    200 
    201 #endif /* End of Windows and UNIX specific includes */
     215#define WINCDECL
     216
     217#endif // End of Windows and UNIX specific includes
    202218
    203219#include "mongoose.h"
    204220
    205 #define MONGOOSE_VERSION        "2.9"
    206 #define PASSWORDS_FILE_NAME     ".htpasswd"
    207 #define CGI_ENVIRONMENT_SIZE    4096
    208 #define MAX_CGI_ENVIR_VARS      64
    209 #define MAX_REQUEST_SIZE        8192
    210 #define MAX_LISTENING_SOCKETS   10
    211 #define MAX_CALLBACKS           20
    212 #define ARRAY_SIZE(array)       (sizeof(array) / sizeof(array[0]))
    213 #define DEBUG_MGS_PREFIX        "*** Mongoose debug *** "
     221#define MONGOOSE_VERSION "3.2"
     222#define PASSWORDS_FILE_NAME ".htpasswd"
     223#define CGI_ENVIRONMENT_SIZE 4096
     224#define MAX_CGI_ENVIR_VARS 64
     225#define ARRAY_SIZE(array) (sizeof(array) / sizeof(array[0]))
     226
     227#ifdef _WIN32
     228static CRITICAL_SECTION global_log_file_lock;
     229static pthread_t pthread_self(void) {
     230  return GetCurrentThreadId();
     231}
     232#endif // _WIN32
    214233
    215234#if defined(DEBUG)
    216 #define DEBUG_TRACE(x) do {printf x; putchar('\n'); fflush(stdout);} while (0)
     235#define DEBUG_TRACE(x) do { \
     236  flockfile(stdout); \
     237  printf("*** %lu.%p.%s.%d: ", \
     238         (unsigned long) time(NULL), (void *) pthread_self(), \
     239         __func__, __LINE__); \
     240  printf x; \
     241  putchar('\n'); \
     242  fflush(stdout); \
     243  funlockfile(stdout); \
     244} while (0)
    217245#else
    218246#define DEBUG_TRACE(x)
    219 #endif /* DEBUG */
    220 
    221 /*
    222  * Darwin prior to 7.0 and Win32 do not have socklen_t
    223  */
     247#endif // DEBUG
     248
     249// Darwin prior to 7.0 and Win32 do not have socklen_t
    224250#ifdef NO_SOCKLEN_T
    225251typedef int socklen_t;
    226 #endif /* NO_SOCKLEN_T */
    227 
    228 #if !defined(FALSE)
    229 enum {FALSE, TRUE};
    230 #endif /* !FALSE */
    231 
    232 typedef int bool_t;
     252#endif // NO_SOCKLEN_T
     253
     254#if !defined(MSG_NOSIGNAL)
     255#define MSG_NOSIGNAL 0
     256#endif
     257
    233258typedef void * (*mg_thread_func_t)(void *);
    234259
    235260static const char *http_500_error = "Internal Server Error";
    236261
    237 /*
    238  * Snatched from OpenSSL includes. I put the prototypes here to be independent
    239  * from the OpenSSL source installation. Having this, mongoose + SSL can be
    240  * built on any system with binary SSL libraries installed.
    241  */
     262// Snatched from OpenSSL includes. I put the prototypes here to be independent
     263// from the OpenSSL source installation. Having this, mongoose + SSL can be
     264// built on any system with binary SSL libraries installed.
    242265typedef struct ssl_st SSL;
    243266typedef struct ssl_method_st SSL_METHOD;
    244267typedef struct ssl_ctx_st SSL_CTX;
    245268
    246 #define SSL_ERROR_WANT_READ     2
    247 #define SSL_ERROR_WANT_WRITE    3
    248 #define SSL_FILETYPE_PEM        1
    249 #define CRYPTO_LOCK             1
    250 
    251 /*
    252  * Dynamically loaded SSL functionality
    253  */
     269#define SSL_ERROR_WANT_READ 2
     270#define SSL_ERROR_WANT_WRITE 3
     271#define SSL_FILETYPE_PEM 1
     272#define CRYPTO_LOCK  1
     273
     274#if defined(NO_SSL_DL)
     275extern void SSL_free(SSL *);
     276extern int SSL_accept(SSL *);
     277extern int SSL_connect(SSL *);
     278extern int SSL_read(SSL *, void *, int);
     279extern int SSL_write(SSL *, const void *, int);
     280extern int SSL_get_error(const SSL *, int);
     281extern int SSL_set_fd(SSL *, int);
     282extern SSL *SSL_new(SSL_CTX *);
     283extern SSL_CTX *SSL_CTX_new(SSL_METHOD *);
     284extern SSL_METHOD *SSLv23_server_method(void);
     285extern int SSL_library_init(void);
     286extern void SSL_load_error_strings(void);
     287extern int SSL_CTX_use_PrivateKey_file(SSL_CTX *, const char *, int);
     288extern int SSL_CTX_use_certificate_file(SSL_CTX *, const char *, int);
     289extern int SSL_CTX_use_certificate_chain_file(SSL_CTX *, const char *);
     290extern void SSL_CTX_set_default_passwd_cb(SSL_CTX *, mg_callback_t);
     291extern void SSL_CTX_free(SSL_CTX *);
     292extern unsigned long ERR_get_error(void);
     293extern char *ERR_error_string(unsigned long, char *);
     294extern int CRYPTO_num_locks(void);
     295extern void CRYPTO_set_locking_callback(void (*)(int, int, const char *, int));
     296extern void CRYPTO_set_id_callback(unsigned long (*)(void));
     297#else
     298// Dynamically loaded SSL functionality
    254299struct ssl_func {
    255         const char      *name;          /* SSL function name    */
    256         void            (*ptr)(void);   /* Function pointer     */
     300  const char *name;   // SSL function name
     301  void  (*ptr)(void); // Function pointer
    257302};
    258303
    259 #define SSL_free(x)     (* (void (*)(SSL *)) ssl_sw[0].ptr)(x)
    260 #define SSL_accept(x)   (* (int (*)(SSL *)) ssl_sw[1].ptr)(x)
    261 #define SSL_connect(x)  (* (int (*)(SSL *)) ssl_sw[2].ptr)(x)
    262 #define SSL_read(x,y,z) (* (int (*)(SSL *, void *, int))                \
    263                                 ssl_sw[3].ptr)((x),(y),(z))
    264 #define SSL_write(x,y,z) (* (int (*)(SSL *, const void *,int))          \
    265                                 ssl_sw[4].ptr)((x), (y), (z))
    266 #define SSL_get_error(x,y)(* (int (*)(SSL *, int)) ssl_sw[5])((x), (y))
    267 #define SSL_set_fd(x,y) (* (int (*)(SSL *, SOCKET)) ssl_sw[6].ptr)((x), (y))
    268 #define SSL_new(x)      (* (SSL * (*)(SSL_CTX *)) ssl_sw[7].ptr)(x)
    269 #define SSL_CTX_new(x)  (* (SSL_CTX * (*)(SSL_METHOD *)) ssl_sw[8].ptr)(x)
    270 #define SSLv23_server_method()  (* (SSL_METHOD * (*)(void)) ssl_sw[9].ptr)()
    271 #define SSL_library_init() (* (int (*)(void)) ssl_sw[10].ptr)()
    272 #define SSL_CTX_use_PrivateKey_file(x,y,z)      (* (int (*)(SSL_CTX *, \
    273                 const char *, int)) ssl_sw[11].ptr)((x), (y), (z))
    274 #define SSL_CTX_use_certificate_file(x,y,z)     (* (int (*)(SSL_CTX *, \
    275                 const char *, int)) ssl_sw[12].ptr)((x), (y), (z))
    276 #define SSL_CTX_set_default_passwd_cb(x,y) \
    277         (* (void (*)(SSL_CTX *, mg_spcb_t)) ssl_sw[13].ptr)((x),(y))
    278 #define SSL_CTX_free(x) (* (void (*)(SSL_CTX *)) ssl_sw[14].ptr)(x)
    279 
    280 #define CRYPTO_num_locks() (* (int (*)(void)) crypto_sw[0].ptr)()
    281 #define CRYPTO_set_locking_callback(x)                                  \
    282                 (* (void (*)(void (*)(int, int, const char *, int)))    \
    283                 crypto_sw[1].ptr)(x)
    284 #define CRYPTO_set_id_callback(x)                                       \
    285         (* (void (*)(unsigned long (*)(void))) crypto_sw[2].ptr)(x)
    286 
    287 /*
    288  * set_ssl_option() function when called, updates this array.
    289  * It loads SSL library dynamically and changes NULLs to the actual addresses
    290  * of respective functions. The macros above (like SSL_connect()) are really
    291  * just calling these functions indirectly via the pointer.
    292  */
    293 static struct ssl_func  ssl_sw[] = {
    294         {"SSL_free",                    NULL},
    295         {"SSL_accept",                  NULL},
    296         {"SSL_connect",                 NULL},
    297         {"SSL_read",                    NULL},
    298         {"SSL_write",                   NULL},
    299         {"SSL_get_error",               NULL},
    300         {"SSL_set_fd",                  NULL},
    301         {"SSL_new",                     NULL},
    302         {"SSL_CTX_new",                 NULL},
    303         {"SSLv23_server_method",        NULL},
    304         {"SSL_library_init",            NULL},
    305         {"SSL_CTX_use_PrivateKey_file", NULL},
    306         {"SSL_CTX_use_certificate_file",NULL},
    307         {"SSL_CTX_set_default_passwd_cb",NULL},
    308         {"SSL_CTX_free",                NULL},
    309         {NULL,                          NULL}
     304#define SSL_free (* (void (*)(SSL *)) ssl_sw[0].ptr)
     305#define SSL_accept (* (int (*)(SSL *)) ssl_sw[1].ptr)
     306#define SSL_connect (* (int (*)(SSL *)) ssl_sw[2].ptr)
     307#define SSL_read (* (int (*)(SSL *, void *, int)) ssl_sw[3].ptr)
     308#define SSL_write (* (int (*)(SSL *, const void *,int)) ssl_sw[4].ptr)
     309#define SSL_get_error (* (int (*)(SSL *, int)) ssl_sw[5].ptr)
     310#define SSL_set_fd (* (int (*)(SSL *, SOCKET)) ssl_sw[6].ptr)
     311#define SSL_new (* (SSL * (*)(SSL_CTX *)) ssl_sw[7].ptr)
     312#define SSL_CTX_new (* (SSL_CTX * (*)(SSL_METHOD *)) ssl_sw[8].ptr)
     313#define SSLv23_server_method (* (SSL_METHOD * (*)(void)) ssl_sw[9].ptr)
     314#define SSL_library_init (* (int (*)(void)) ssl_sw[10].ptr)
     315#define SSL_CTX_use_PrivateKey_file (* (int (*)(SSL_CTX *, \
     316        const char *, int)) ssl_sw[11].ptr)
     317#define SSL_CTX_use_certificate_file (* (int (*)(SSL_CTX *, \
     318        const char *, int)) ssl_sw[12].ptr)
     319#define SSL_CTX_set_default_passwd_cb \
     320  (* (void (*)(SSL_CTX *, mg_callback_t)) ssl_sw[13].ptr)
     321#define SSL_CTX_free (* (void (*)(SSL_CTX *)) ssl_sw[14].ptr)
     322#define SSL_load_error_strings (* (void (*)(void)) ssl_sw[15].ptr)
     323#define SSL_CTX_use_certificate_chain_file \
     324  (* (int (*)(SSL_CTX *, const char *)) ssl_sw[16].ptr)
     325
     326#define CRYPTO_num_locks (* (int (*)(void)) crypto_sw[0].ptr)
     327#define CRYPTO_set_locking_callback \
     328  (* (void (*)(void (*)(int, int, const char *, int))) crypto_sw[1].ptr)
     329#define CRYPTO_set_id_callback \
     330  (* (void (*)(unsigned long (*)(void))) crypto_sw[2].ptr)
     331#define ERR_get_error (* (unsigned long (*)(void)) crypto_sw[3].ptr)
     332#define ERR_error_string (* (char * (*)(unsigned long,char *)) crypto_sw[4].ptr)
     333
     334// set_ssl_option() function updates this array.
     335// It loads SSL library dynamically and changes NULLs to the actual addresses
     336// of respective functions. The macros above (like SSL_connect()) are really
     337// just calling these functions indirectly via the pointer.
     338static struct ssl_func ssl_sw[] = {
     339  {"SSL_free",   NULL},
     340  {"SSL_accept",   NULL},
     341  {"SSL_connect",   NULL},
     342  {"SSL_read",   NULL},
     343  {"SSL_write",   NULL},
     344  {"SSL_get_error",  NULL},
     345  {"SSL_set_fd",   NULL},
     346  {"SSL_new",   NULL},
     347  {"SSL_CTX_new",   NULL},
     348  {"SSLv23_server_method", NULL},
     349  {"SSL_library_init",  NULL},
     350  {"SSL_CTX_use_PrivateKey_file", NULL},
     351  {"SSL_CTX_use_certificate_file",NULL},
     352  {"SSL_CTX_set_default_passwd_cb",NULL},
     353  {"SSL_CTX_free",  NULL},
     354  {"SSL_load_error_strings", NULL},
     355  {"SSL_CTX_use_certificate_chain_file", NULL},
     356  {NULL,    NULL}
    310357};
    311358
     359// Similar array as ssl_sw. These functions could be located in different lib.
    312360#if !defined(NO_SSL)
    313 /*
    314  * Similar array as ssl_sw. These functions are located in different lib.
    315  */
    316 static struct ssl_func  crypto_sw[] = {
    317         {"CRYPTO_num_locks",            NULL},
    318         {"CRYPTO_set_locking_callback", NULL},
    319         {"CRYPTO_set_id_callback",      NULL},
    320         {NULL,                          NULL}
     361static struct ssl_func crypto_sw[] = {
     362  {"CRYPTO_num_locks",  NULL},
     363  {"CRYPTO_set_locking_callback", NULL},
     364  {"CRYPTO_set_id_callback", NULL},
     365  {"ERR_get_error",  NULL},
     366  {"ERR_error_string", NULL},
     367  {NULL,    NULL}
    321368};
     369#endif // NO_SSL
     370#endif // NO_SSL_DL
     371
     372static const char *month_names[] = {
     373  "Jan", "Feb", "Mar", "Apr", "May", "Jun",
     374  "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
     375};
     376
     377// Unified socket address. For IPv6 support, add IPv6 address structure
     378// in the union u.
     379union usa {
     380  struct sockaddr sa;
     381  struct sockaddr_in sin;
     382#if defined(USE_IPV6)
     383  struct sockaddr_in6 sin6;
    322384#endif
    323 
    324 /*
    325  * Month names
    326  */
    327 static const char *month_names[] = {
    328         "Jan", "Feb", "Mar", "Apr", "May", "Jun",
    329         "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
    330385};
    331386
    332 /*
    333  * Unified socket address. For IPv6 support, add IPv6 address structure
    334  * in the union u.
    335  */
    336 struct usa {
    337         socklen_t len;
    338         union {
    339                 struct sockaddr sa;
    340                 struct sockaddr_in sin;
    341         } u;
     387// Describes a string (chunk of memory).
     388struct vec {
     389  const char *ptr;
     390  size_t len;
    342391};
    343392
    344 /*
    345  * Specifies a string (chunk of memory).
    346  * Used to traverse comma separated lists of options.
    347  */
    348 struct vec {
    349         const char      *ptr;
    350         size_t          len;
     393// Structure used by mg_stat() function. Uses 64 bit file length.
     394struct mgstat {
     395  int is_directory;  // Directory marker
     396  int64_t size;      // File size
     397  time_t mtime;      // Modification time
    351398};
    352399
    353 /*
    354  * Structure used by mg_stat() function. Uses 64 bit file length.
    355  */
    356 struct mgstat {
    357         bool_t          is_directory;   /* Directory marker             */
    358         int64_t         size;           /* File size                    */
    359         time_t          mtime;          /* Modification time            */
     400// Describes listening socket, or socket which was accept()-ed by the master
     401// thread and queued for future handling by the worker thread.
     402struct socket {
     403  struct socket *next;  // Linkage
     404  SOCKET sock;          // Listening socket
     405  union usa lsa;        // Local socket address
     406  union usa rsa;        // Remote socket address
     407  int is_ssl;           // Is socket SSL-ed
    360408};
    361409
    362 struct mg_option {
    363         const char      *name;
    364         const char      *description;
    365         const char      *default_value;
    366         int             index;
    367         bool_t (*setter)(struct mg_context *, const char *);
     410enum {
     411  CGI_EXTENSIONS, CGI_ENVIRONMENT, PUT_DELETE_PASSWORDS_FILE, CGI_INTERPRETER,
     412  PROTECT_URI, AUTHENTICATION_DOMAIN, SSI_EXTENSIONS, ACCESS_LOG_FILE,
     413  SSL_CHAIN_FILE, ENABLE_DIRECTORY_LISTING, ERROR_LOG_FILE,
     414  GLOBAL_PASSWORDS_FILE, INDEX_FILES,
     415  ENABLE_KEEP_ALIVE, ACCESS_CONTROL_LIST, MAX_REQUEST_SIZE,
     416  EXTRA_MIME_TYPES, LISTENING_PORTS,
     417  DOCUMENT_ROOT, SSL_CERTIFICATE, NUM_THREADS, RUN_AS_USER, REWRITE,
     418  NUM_OPTIONS
    368419};
    369420
    370 /*
    371  * Numeric indexes for the option values in context, ctx->options
    372  */
    373 enum mg_option_index {
    374         OPT_ROOT, OPT_INDEX_FILES, OPT_PORTS, OPT_DIR_LIST, OPT_CGI_EXTENSIONS,
    375         OPT_CGI_INTERPRETER, OPT_CGI_ENV, OPT_SSI_EXTENSIONS, OPT_AUTH_DOMAIN,
    376         OPT_AUTH_GPASSWD, OPT_AUTH_PUT, OPT_ACCESS_LOG, OPT_ERROR_LOG,
    377         OPT_SSL_CERTIFICATE, OPT_ALIASES, OPT_ACL, OPT_UID, OPT_PROTECT,
    378         OPT_SERVICE, OPT_HIDE, OPT_ADMIN_URI, OPT_MAX_THREADS, OPT_IDLE_TIME,
    379         OPT_MIME_TYPES,
    380         NUM_OPTIONS
     421static const char *config_options[] = {
     422  "C", "cgi_pattern", "**.cgi$|**.pl$|**.php$",
     423  "E", "cgi_environment", NULL,
     424  "G", "put_delete_passwords_file", NULL,
     425  "I", "cgi_interpreter", NULL,
     426  "P", "protect_uri", NULL,
     427  "R", "authentication_domain", "mydomain.com",
     428  "S", "ssi_pattern", "**.shtml$|**.shtm$",
     429  "a", "access_log_file", NULL,
     430  "c", "ssl_chain_file", NULL,
     431  "d", "enable_directory_listing", "yes",
     432  "e", "error_log_file", NULL,
     433  "g", "global_passwords_file", NULL,
     434  "i", "index_files", "index.html,index.htm,index.cgi,index.shtml,index.php",
     435  "k", "enable_keep_alive", "no",
     436  "l", "access_control_list", NULL,
     437  "M", "max_request_size", "16384",
     438  "m", "extra_mime_types", NULL,
     439  "p", "listening_ports", "8080",
     440  "r", "document_root",  ".",
     441  "s", "ssl_certificate", NULL,
     442  "t", "num_threads", "10",
     443  "u", "run_as_user", NULL,
     444  "w", "url_rewrite_patterns", NULL,
     445  NULL
    381446};
    382 
    383 /*
    384  * Structure used to describe listening socket, or socket which was
    385  * accept()-ed by the master thread and queued for future handling
    386  * by the worker thread.
    387  */
    388 struct socket {
    389         SOCKET          sock;           /* Listening socket             */
    390         struct usa      lsa;            /* Local socket address         */
    391         struct usa      rsa;            /* Remote socket address        */
    392         bool_t          is_ssl;         /* Is socket SSL-ed             */
     447#define ENTRIES_PER_CONFIG_OPTION 3
     448
     449struct mg_context {
     450  volatile int stop_flag;       // Should we stop event loop
     451  SSL_CTX *ssl_ctx;             // SSL context
     452  char *config[NUM_OPTIONS];    // Mongoose configuration parameters
     453  mg_callback_t user_callback;  // User-defined callback function
     454  void *user_data;              // User-defined data
     455
     456  struct socket *listening_sockets;
     457
     458  volatile int num_threads;  // Number of threads
     459  pthread_mutex_t mutex;     // Protects (max|num)_threads
     460  pthread_cond_t  cond;      // Condvar for tracking workers terminations
     461
     462  struct socket queue[20];   // Accepted sockets
     463  volatile int sq_head;      // Head of the socket queue
     464  volatile int sq_tail;      // Tail of the socket queue
     465  pthread_cond_t sq_full;    // Singaled when socket is produced
     466  pthread_cond_t sq_empty;   // Signaled when socket is consumed
    393467};
    394468
    395 /*
    396  * Callback function, and where it is bound to
    397  */
    398 struct callback {
    399         char            *uri_regex;     /* URI regex to handle          */
    400         mg_callback_t   func;           /* user callback                */
    401         bool_t          is_auth;        /* func is auth checker         */
    402         int             status_code;    /* error code to handle         */
    403         void            *user_data;     /* opaque user data             */
     469struct mg_connection {
     470  struct mg_request_info request_info;
     471  struct mg_context *ctx;
     472  SSL *ssl;                   // SSL descriptor
     473  struct socket client;       // Connected client
     474  time_t birth_time;          // Time connection was accepted
     475  int64_t num_bytes_sent;     // Total bytes sent to client
     476  int64_t content_len;        // Content-Length header value
     477  int64_t consumed_content;   // How many bytes of content is already read
     478  char *buf;                  // Buffer for received data
     479  char *path_info;            // PATH_INFO part of the URL
     480  int must_close;             // 1 if connection must be closed
     481  int buf_size;               // Buffer size
     482  int request_len;            // Size of the request + headers in a buffer
     483  int data_len;               // Total size of data in a buffer
    404484};
    405485
    406 /*
    407  * Mongoose context
    408  */
    409 struct mg_context {
    410         int             stop_flag;      /* Should we stop event loop    */
    411         SSL_CTX         *ssl_ctx;       /* SSL context                  */
    412 
    413         FILE            *access_log;    /* Opened access log            */
    414         FILE            *error_log;     /* Opened error log             */
    415 
    416         struct socket   listeners[MAX_LISTENING_SOCKETS];
    417         int             num_listeners;
    418 
    419         struct callback callbacks[MAX_CALLBACKS];
    420         int             num_callbacks;
    421 
    422         char            *options[NUM_OPTIONS];  /* Configured opions    */
    423         pthread_mutex_t opt_mutex[NUM_OPTIONS]; /* Option protector     */
    424 
    425         int             max_threads;    /* Maximum number of threads    */
    426         int             num_threads;    /* Number of threads            */
    427         int             num_idle;       /* Number of idle threads       */
    428         pthread_mutex_t thr_mutex;      /* Protects (max|num)_threads   */
    429         pthread_cond_t  thr_cond;
    430         pthread_mutex_t bind_mutex;     /* Protects bind operations     */
    431 
    432         struct socket   queue[20];      /* Accepted sockets             */
    433         int             sq_head;        /* Head of the socket queue     */
    434         int             sq_tail;        /* Tail of the socket queue     */
    435         pthread_cond_t  empty_cond;     /* Socket queue empty condvar   */
    436         pthread_cond_t  full_cond;      /* Socket queue full condvar    */
    437 
    438         mg_spcb_t       ssl_password_callback;
    439         mg_callback_t   log_callback;
     486const char **mg_get_valid_option_names(void) {
     487  return config_options;
     488}
     489
     490static void *call_user(struct mg_connection *conn, enum mg_event event) {
     491  conn->request_info.user_data = conn->ctx->user_data;
     492  return conn->ctx->user_callback == NULL ? NULL :
     493    conn->ctx->user_callback(event, conn, &conn->request_info);
     494}
     495
     496static int get_option_index(const char *name) {
     497  int i;
     498
     499  for (i = 0; config_options[i] != NULL; i += ENTRIES_PER_CONFIG_OPTION) {
     500    if (strcmp(config_options[i], name) == 0 ||
     501        strcmp(config_options[i + 1], name) == 0) {
     502      return i / ENTRIES_PER_CONFIG_OPTION;
     503    }
     504  }
     505  return -1;
     506}
     507
     508const char *mg_get_option(const struct mg_context *ctx, const char *name) {
     509  int i;
     510  if ((i = get_option_index(name)) == -1) {
     511    return NULL;
     512  } else if (ctx->config[i] == NULL) {
     513    return "";
     514  } else {
     515    return ctx->config[i];
     516  }
     517}
     518
     519static void sockaddr_to_string(char *buf, size_t len,
     520                                     const union usa *usa) {
     521  buf[0] = '\0';
     522#if defined(USE_IPV6)
     523  inet_ntop(usa->sa.sa_family, usa->sa.sa_family == AF_INET ?
     524            (void *) &usa->sin.sin_addr :
     525            (void *) &usa->sin6.sin6_addr, buf, len);
     526#elif defined(_WIN32)
     527  // Only Windoze Vista (and newer) have inet_ntop()
     528  strncpy(buf, inet_ntoa(usa->sin.sin_addr), len);
     529#else
     530  inet_ntop(usa->sa.sa_family, (void *) &usa->sin.sin_addr, buf, len);
     531#endif
     532}
     533
     534// Print error message to the opened error log stream.
     535static void cry(struct mg_connection *conn, const char *fmt, ...) {
     536  char buf[BUFSIZ], src_addr[20];
     537  va_list ap;
     538  FILE *fp;
     539  time_t timestamp;
     540
     541  va_start(ap, fmt);
     542  (void) vsnprintf(buf, sizeof(buf), fmt, ap);
     543  va_end(ap);
     544
     545  // Do not lock when getting the callback value, here and below.
     546  // I suppose this is fine, since function cannot disappear in the
     547  // same way string option can.
     548  conn->request_info.log_message = buf;
     549  if (call_user(conn, MG_EVENT_LOG) == NULL) {
     550    fp = conn->ctx->config[ERROR_LOG_FILE] == NULL ? NULL :
     551      mg_fopen(conn->ctx->config[ERROR_LOG_FILE], "a+");
     552
     553    if (fp != NULL) {
     554      flockfile(fp);
     555      timestamp = time(NULL);
     556
     557      sockaddr_to_string(src_addr, sizeof(src_addr), &conn->client.rsa);
     558      fprintf(fp, "[%010lu] [error] [client %s] ", (unsigned long) timestamp,
     559              src_addr);
     560
     561      if (conn->request_info.request_method != NULL) {
     562        fprintf(fp, "%s %s: ", conn->request_info.request_method,
     563                conn->request_info.uri);
     564      }
     565
     566      (void) fprintf(fp, "%s", buf);
     567      fputc('\n', fp);
     568      funlockfile(fp);
     569      if (fp != stderr) {
     570        fclose(fp);
     571      }
     572    }
     573  }
     574  conn->request_info.log_message = NULL;
     575}
     576
     577// Return fake connection structure. Used for logging, if connection
     578// is not applicable at the moment of logging.
     579static struct mg_connection *fc(struct mg_context *ctx) {
     580  static struct mg_connection fake_connection;
     581  fake_connection.ctx = ctx;
     582  return &fake_connection;
     583}
     584
     585const char *mg_version(void) {
     586  return MONGOOSE_VERSION;
     587}
     588
     589static void mg_strlcpy(register char *dst, register const char *src, size_t n) {
     590  for (; *src != '\0' && n > 1; n--) {
     591    *dst++ = *src++;
     592  }
     593  *dst = '\0';
     594}
     595
     596static int lowercase(const char *s) {
     597  return tolower(* (const unsigned char *) s);
     598}
     599
     600static int mg_strncasecmp(const char *s1, const char *s2, size_t len) {
     601  int diff = 0;
     602
     603  if (len > 0)
     604    do {
     605      diff = lowercase(s1++) - lowercase(s2++);
     606    } while (diff == 0 && s1[-1] != '\0' && --len > 0);
     607
     608  return diff;
     609}
     610
     611static int mg_strcasecmp(const char *s1, const char *s2) {
     612  int diff;
     613
     614  do {
     615    diff = lowercase(s1++) - lowercase(s2++);
     616  } while (diff == 0 && s1[-1] != '\0');
     617
     618  return diff;
     619}
     620
     621static char * mg_strndup(const char *ptr, size_t len) {
     622  char *p;
     623
     624  if ((p = (char *) malloc(len + 1)) != NULL) {
     625    mg_strlcpy(p, ptr, len + 1);
     626  }
     627
     628  return p;
     629}
     630
     631static char * mg_strdup(const char *str) {
     632  return mg_strndup(str, strlen(str));
     633}
     634
     635// Like snprintf(), but never returns negative value, or the value
     636// that is larger than a supplied buffer.
     637// Thanks to Adam Zeldis to pointing snprintf()-caused vulnerability
     638// in his audit report.
     639static int mg_vsnprintf(struct mg_connection *conn, char *buf, size_t buflen,
     640                        const char *fmt, va_list ap) {
     641  int n;
     642
     643  if (buflen == 0)
     644    return 0;
     645
     646  n = vsnprintf(buf, buflen, fmt, ap);
     647
     648  if (n < 0) {
     649    cry(conn, "vsnprintf error");
     650    n = 0;
     651  } else if (n >= (int) buflen) {
     652    cry(conn, "truncating vsnprintf buffer: [%.*s]",
     653        n > 200 ? 200 : n, buf);
     654    n = (int) buflen - 1;
     655  }
     656  buf[n] = '\0';
     657
     658  return n;
     659}
     660
     661static int mg_snprintf(struct mg_connection *conn, char *buf, size_t buflen,
     662                       const char *fmt, ...) {
     663  va_list ap;
     664  int n;
     665
     666  va_start(ap, fmt);
     667  n = mg_vsnprintf(conn, buf, buflen, fmt, ap);
     668  va_end(ap);
     669
     670  return n;
     671}
     672
     673// Skip the characters until one of the delimiters characters found.
     674// 0-terminate resulting word. Skip the delimiter and following whitespaces if any.
     675// Advance pointer to buffer to the next word. Return found 0-terminated word.
     676// Delimiters can be quoted with quotechar.
     677static char *skip_quoted(char **buf, const char *delimiters, const char *whitespace, char quotechar) {
     678  char *p, *begin_word, *end_word, *end_whitespace;
     679
     680  begin_word = *buf;
     681  end_word = begin_word + strcspn(begin_word, delimiters);
     682
     683  // Check for quotechar
     684  if (end_word > begin_word) {
     685    p = end_word - 1;
     686    while (*p == quotechar) {
     687      // If there is anything beyond end_word, copy it
     688      if (*end_word == '\0') {
     689        *p = '\0';
     690        break;
     691      } else {
     692        size_t end_off = strcspn(end_word + 1, delimiters);
     693        memmove (p, end_word, end_off + 1);
     694        p += end_off; // p must correspond to end_word - 1
     695        end_word += end_off + 1;
     696      }
     697    }
     698    for (p++; p < end_word; p++) {
     699      *p = '\0';
     700    }
     701  }
     702
     703  if (*end_word == '\0') {
     704    *buf = end_word;
     705  } else {
     706    end_whitespace = end_word + 1 + strspn(end_word + 1, whitespace);
     707
     708    for (p = end_word; p < end_whitespace; p++) {
     709      *p = '\0';
     710    }
     711
     712    *buf = end_whitespace;
     713  }
     714
     715  return begin_word;
     716}
     717
     718// Simplified version of skip_quoted without quote char
     719// and whitespace == delimiters
     720static char *skip(char **buf, const char *delimiters) {
     721  return skip_quoted(buf, delimiters, delimiters, 0);
     722}
     723
     724
     725// Return HTTP header value, or NULL if not found.
     726static const char *get_header(const struct mg_request_info *ri,
     727                              const char *name) {
     728  int i;
     729
     730  for (i = 0; i < ri->num_headers; i++)
     731    if (!mg_strcasecmp(name, ri->http_headers[i].name))
     732      return ri->http_headers[i].value;
     733
     734  return NULL;
     735}
     736
     737const char *mg_get_header(const struct mg_connection *conn, const char *name) {
     738  return get_header(&conn->request_info, name);
     739}
     740
     741// A helper function for traversing comma separated list of values.
     742// It returns a list pointer shifted to the next value, of NULL if the end
     743// of the list found.
     744// Value is stored in val vector. If value has form "x=y", then eq_val
     745// vector is initialized to point to the "y" part, and val vector length
     746// is adjusted to point only to "x".
     747static const char *next_option(const char *list, struct vec *val,
     748                               struct vec *eq_val) {
     749  if (list == NULL || *list == '\0') {
     750    // End of the list
     751    list = NULL;
     752  } else {
     753    val->ptr = list;
     754    if ((list = strchr(val->ptr, ',')) != NULL) {
     755      // Comma found. Store length and shift the list ptr
     756      val->len = list - val->ptr;
     757      list++;
     758    } else {
     759      // This value is the last one
     760      list = val->ptr + strlen(val->ptr);
     761      val->len = list - val->ptr;
     762    }
     763
     764    if (eq_val != NULL) {
     765      // Value has form "x=y", adjust pointers and lengths
     766      // so that val points to "x", and eq_val points to "y".
     767      eq_val->len = 0;
     768      eq_val->ptr = (const char *) memchr(val->ptr, '=', val->len);
     769      if (eq_val->ptr != NULL) {
     770        eq_val->ptr++;  // Skip over '=' character
     771        eq_val->len = val->ptr + val->len - eq_val->ptr;
     772        val->len = (eq_val->ptr - val->ptr) - 1;
     773      }
     774    }
     775  }
     776
     777  return list;
     778}
     779
     780static int match_prefix(const char *pattern, int pattern_len, const char *str) {
     781  const char *or_str;
     782  int i, j, len, res;
     783
     784  if ((or_str = (const char *) memchr(pattern, '|', pattern_len)) != NULL) {
     785    res = match_prefix(pattern, or_str - pattern, str);
     786    return res > 0 ? res :
     787        match_prefix(or_str + 1, (pattern + pattern_len) - (or_str + 1), str);
     788  }
     789
     790  i = j = 0;
     791  res = -1;
     792  for (; i < pattern_len; i++, j++) {
     793    if (pattern[i] == '?' && str[j] != '\0') {
     794      continue;
     795    } else if (pattern[i] == '$') {
     796      return str[j] == '\0' ? j : -1;
     797    } else if (pattern[i] == '*') {
     798      i++;
     799      if (pattern[i] == '*') {
     800        i++;
     801        len = strlen(str + j);
     802      } else {
     803        len = strcspn(str + j, "/");
     804      }
     805      if (i == pattern_len) {
     806        return j + len;
     807      }
     808      do {
     809        res = match_prefix(pattern + i, pattern_len - i, str + j + len);
     810      } while (res == -1 && len-- > 0);
     811      return res == -1 ? -1 : j + res + len;
     812    } else if (pattern[i] != str[j]) {
     813      return -1;
     814    }
     815  }
     816  return j;
     817}
     818
     819// HTTP 1.1 assumes keep alive if "Connection:" header is not set
     820// This function must tolerate situations when connection info is not
     821// set up, for example if request parsing failed.
     822static int should_keep_alive(const struct mg_connection *conn) {
     823  const char *http_version = conn->request_info.http_version;
     824  const char *header = mg_get_header(conn, "Connection");
     825  if (conn->must_close ||
     826      conn->request_info.status_code == 401 ||
     827      mg_strcasecmp(conn->ctx->config[ENABLE_KEEP_ALIVE], "yes") != 0 ||
     828      (header != NULL && mg_strcasecmp(header, "keep-alive") != 0) ||
     829      (header == NULL && http_version && strcmp(http_version, "1.1"))) {
     830    return 0;
     831  }
     832  return 1;
     833}
     834
     835static const char *suggest_connection_header(const struct mg_connection *conn) {
     836  return should_keep_alive(conn) ? "keep-alive" : "close";
     837}
     838
     839static void send_http_error(struct mg_connection *conn, int status,
     840                            const char *reason, const char *fmt, ...) {
     841  char buf[BUFSIZ];
     842  va_list ap;
     843  int len;
     844
     845  conn->request_info.status_code = status;
     846
     847  if (call_user(conn, MG_HTTP_ERROR) == NULL) {
     848    buf[0] = '\0';
     849    len = 0;
     850
     851    // Errors 1xx, 204 and 304 MUST NOT send a body
     852    if (status > 199 && status != 204 && status != 304) {
     853      len = mg_snprintf(conn, buf, sizeof(buf), "Error %d: %s", status, reason);
     854      cry(conn, "%s", buf);
     855      buf[len++] = '\n';
     856
     857      va_start(ap, fmt);
     858      len += mg_vsnprintf(conn, buf + len, sizeof(buf) - len, fmt, ap);
     859      va_end(ap);
     860    }
     861    DEBUG_TRACE(("[%s]", buf));
     862
     863    mg_printf(conn, "HTTP/1.1 %d %s\r\n"
     864              "Content-Type: text/plain\r\n"
     865              "Content-Length: %d\r\n"
     866              "Connection: %s\r\n\r\n", status, reason, len,
     867              suggest_connection_header(conn));
     868    conn->num_bytes_sent += mg_printf(conn, "%s", buf);
     869  }
     870}
     871
     872#if defined(_WIN32) && !defined(__SYMBIAN32__)
     873static int pthread_mutex_init(pthread_mutex_t *mutex, void *unused) {
     874  unused = NULL;
     875  *mutex = CreateMutex(NULL, FALSE, NULL);
     876  return *mutex == NULL ? -1 : 0;
     877}
     878
     879static int pthread_mutex_destroy(pthread_mutex_t *mutex) {
     880  return CloseHandle(*mutex) == 0 ? -1 : 0;
     881}
     882
     883static int pthread_mutex_lock(pthread_mutex_t *mutex) {
     884  return WaitForSingleObject(*mutex, INFINITE) == WAIT_OBJECT_0? 0 : -1;
     885}
     886
     887static int pthread_mutex_unlock(pthread_mutex_t *mutex) {
     888  return ReleaseMutex(*mutex) == 0 ? -1 : 0;
     889}
     890
     891static int pthread_cond_init(pthread_cond_t *cv, const void *unused) {
     892  unused = NULL;
     893  cv->signal = CreateEvent(NULL, FALSE, FALSE, NULL);
     894  cv->broadcast = CreateEvent(NULL, TRUE, FALSE, NULL);
     895  return cv->signal != NULL && cv->broadcast != NULL ? 0 : -1;
     896}
     897
     898static int pthread_cond_wait(pthread_cond_t *cv, pthread_mutex_t *mutex) {
     899  HANDLE handles[] = {cv->signal, cv->broadcast};
     900  ReleaseMutex(*mutex);
     901  WaitForMultipleObjects(2, handles, FALSE, INFINITE);
     902  return WaitForSingleObject(*mutex, INFINITE) == WAIT_OBJECT_0? 0 : -1;
     903}
     904
     905static int pthread_cond_signal(pthread_cond_t *cv) {
     906  return SetEvent(cv->signal) == 0 ? -1 : 0;
     907}
     908
     909static int pthread_cond_broadcast(pthread_cond_t *cv) {
     910  // Implementation with PulseEvent() has race condition, see
     911  // http://www.cs.wustl.edu/~schmidt/win32-cv-1.html
     912  return PulseEvent(cv->broadcast) == 0 ? -1 : 0;
     913}
     914
     915static int pthread_cond_destroy(pthread_cond_t *cv) {
     916  return CloseHandle(cv->signal) && CloseHandle(cv->broadcast) ? 0 : -1;
     917}
     918
     919// For Windows, change all slashes to backslashes in path names.
     920static void change_slashes_to_backslashes(char *path) {
     921  int i;
     922
     923  for (i = 0; path[i] != '\0'; i++) {
     924    if (path[i] == '/')
     925      path[i] = '\\';
     926    // i > 0 check is to preserve UNC paths, like \\server\file.txt
     927    if (path[i] == '\\' && i > 0)
     928      while (path[i + 1] == '\\' || path[i + 1] == '/')
     929        (void) memmove(path + i + 1,
     930            path + i + 2, strlen(path + i + 1));
     931  }
     932}
     933
     934// Encode 'path' which is assumed UTF-8 string, into UNICODE string.
     935// wbuf and wbuf_len is a target buffer and its length.
     936static void to_unicode(const char *path, wchar_t *wbuf, size_t wbuf_len) {
     937  char buf[PATH_MAX], buf2[PATH_MAX], *p;
     938
     939  mg_strlcpy(buf, path, sizeof(buf));
     940  change_slashes_to_backslashes(buf);
     941
     942  // Point p to the end of the file name
     943  p = buf + strlen(buf) - 1;
     944
     945  // Trim trailing backslash character
     946  while (p > buf && *p == '\\' && p[-1] != ':') {
     947    *p-- = '\0';
     948  }
     949
     950   // Protect from CGI code disclosure.
     951   // This is very nasty hole. Windows happily opens files with
     952   // some garbage in the end of file name. So fopen("a.cgi    ", "r")
     953   // actually opens "a.cgi", and does not return an error!
     954  if (*p == 0x20 ||               // No space at the end
     955      (*p == 0x2e && p > buf) ||  // No '.' but allow '.' as full path
     956      *p == 0x2b ||               // No '+'
     957      (*p & ~0x7f)) {             // And generally no non-ascii chars
     958    (void) fprintf(stderr, "Rejecting suspicious path: [%s]", buf);
     959    wbuf[0] = L'\0';
     960  } else {
     961    // Convert to Unicode and back. If doubly-converted string does not
     962    // match the original, something is fishy, reject.
     963    memset(wbuf, 0, wbuf_len * sizeof(wchar_t));
     964    MultiByteToWideChar(CP_UTF8, 0, buf, -1, wbuf, (int) wbuf_len);
     965    WideCharToMultiByte(CP_UTF8, 0, wbuf, (int) wbuf_len, buf2, sizeof(buf2),
     966                        NULL, NULL);
     967    if (strcmp(buf, buf2) != 0) {
     968      wbuf[0] = L'\0';
     969    }
     970  }
     971}
     972
     973#if defined(_WIN32_WCE)
     974static time_t time(time_t *ptime) {
     975  time_t t;
     976  SYSTEMTIME st;
     977  FILETIME ft;
     978
     979  GetSystemTime(&st);
     980  SystemTimeToFileTime(&st, &ft);
     981  t = SYS2UNIX_TIME(ft.dwLowDateTime, ft.dwHighDateTime);
     982
     983  if (ptime != NULL) {
     984    *ptime = t;
     985  }
     986
     987  return t;
     988}
     989
     990static struct tm *localtime(const time_t *ptime, struct tm *ptm) {
     991  int64_t t = ((int64_t) *ptime) * RATE_DIFF + EPOCH_DIFF;
     992  FILETIME ft, lft;
     993  SYSTEMTIME st;
     994  TIME_ZONE_INFORMATION tzinfo;
     995
     996  if (ptm == NULL) {
     997    return NULL;
     998  }
     999
     1000  * (int64_t *) &ft = t;
     1001  FileTimeToLocalFileTime(&ft, &lft);
     1002  FileTimeToSystemTime(&lft, &st);
     1003  ptm->tm_year = st.wYear - 1900;
     1004  ptm->tm_mon = st.wMonth - 1;
     1005  ptm->tm_wday = st.wDayOfWeek;
     1006  ptm->tm_mday = st.wDay;
     1007  ptm->tm_hour = st.wHour;
     1008  ptm->tm_min = st.wMinute;
     1009  ptm->tm_sec = st.wSecond;
     1010  ptm->tm_yday = 0; // hope nobody uses this
     1011  ptm->tm_isdst =
     1012    GetTimeZoneInformation(&tzinfo) == TIME_ZONE_ID_DAYLIGHT ? 1 : 0;
     1013
     1014  return ptm;
     1015}
     1016
     1017static struct tm *gmtime(const time_t *ptime, struct tm *ptm) {
     1018  // FIXME(lsm): fix this.
     1019  return localtime(ptime, ptm);
     1020}
     1021
     1022static size_t strftime(char *dst, size_t dst_size, const char *fmt,
     1023                       const struct tm *tm) {
     1024  (void) snprintf(dst, dst_size, "implement strftime() for WinCE");
     1025  return 0;
     1026}
     1027#endif
     1028
     1029static int mg_rename(const char* oldname, const char* newname) {
     1030  wchar_t woldbuf[PATH_MAX];
     1031  wchar_t wnewbuf[PATH_MAX];
     1032
     1033  to_unicode(oldname, woldbuf, ARRAY_SIZE(woldbuf));
     1034  to_unicode(newname, wnewbuf, ARRAY_SIZE(wnewbuf));
     1035
     1036  return MoveFileW(woldbuf, wnewbuf) ? 0 : -1;
     1037}
     1038
     1039
     1040static FILE *mg_fopen(const char *path, const char *mode) {
     1041  wchar_t wbuf[PATH_MAX], wmode[20];
     1042
     1043  to_unicode(path, wbuf, ARRAY_SIZE(wbuf));
     1044  MultiByteToWideChar(CP_UTF8, 0, mode, -1, wmode, ARRAY_SIZE(wmode));
     1045
     1046  return _wfopen(wbuf, wmode);
     1047}
     1048
     1049static int mg_stat(const char *path, struct mgstat *stp) {
     1050  int ok = -1; // Error
     1051  wchar_t wbuf[PATH_MAX];
     1052  WIN32_FILE_ATTRIBUTE_DATA info;
     1053
     1054  to_unicode(path, wbuf, ARRAY_SIZE(wbuf));
     1055
     1056  if (GetFileAttributesExW(wbuf, GetFileExInfoStandard, &info) != 0) {
     1057    stp->size = MAKEUQUAD(info.nFileSizeLow, info.nFileSizeHigh);
     1058    stp->mtime = SYS2UNIX_TIME(info.ftLastWriteTime.dwLowDateTime,
     1059                               info.ftLastWriteTime.dwHighDateTime);
     1060    stp->is_directory =
     1061      info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY;
     1062    ok = 0;  // Success
     1063  }
     1064
     1065  return ok;
     1066}
     1067
     1068static int mg_remove(const char *path) {
     1069  wchar_t wbuf[PATH_MAX];
     1070  to_unicode(path, wbuf, ARRAY_SIZE(wbuf));
     1071  return DeleteFileW(wbuf) ? 0 : -1;
     1072}
     1073
     1074static int mg_mkdir(const char *path, int mode) {
     1075  char buf[PATH_MAX];
     1076  wchar_t wbuf[PATH_MAX];
     1077
     1078  mode = 0; // Unused
     1079  mg_strlcpy(buf, path, sizeof(buf));
     1080  change_slashes_to_backslashes(buf);
     1081
     1082  (void) MultiByteToWideChar(CP_UTF8, 0, buf, -1, wbuf, sizeof(wbuf));
     1083
     1084  return CreateDirectoryW(wbuf, NULL) ? 0 : -1;
     1085}
     1086
     1087// Implementation of POSIX opendir/closedir/readdir for Windows.
     1088static DIR * opendir(const char *name) {
     1089  DIR *dir = NULL;
     1090  wchar_t wpath[PATH_MAX];
     1091  DWORD attrs;
     1092
     1093  if (name == NULL) {
     1094    SetLastError(ERROR_BAD_ARGUMENTS);
     1095  } else if ((dir = (DIR *) malloc(sizeof(*dir))) == NULL) {
     1096    SetLastError(ERROR_NOT_ENOUGH_MEMORY);
     1097  } else {
     1098    to_unicode(name, wpath, ARRAY_SIZE(wpath));
     1099    attrs = GetFileAttributesW(wpath);
     1100    if (attrs != 0xFFFFFFFF &&
     1101        ((attrs & FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY)) {
     1102      (void) wcscat(wpath, L"\\*");
     1103      dir->handle = FindFirstFileW(wpath, &dir->info);
     1104      dir->result.d_name[0] = '\0';
     1105    } else {
     1106      free(dir);
     1107      dir = NULL;
     1108    }
     1109  }
     1110
     1111  return dir;
     1112}
     1113
     1114static int closedir(DIR *dir) {
     1115  int result = 0;
     1116
     1117  if (dir != NULL) {
     1118    if (dir->handle != INVALID_HANDLE_VALUE)
     1119      result = FindClose(dir->handle) ? 0 : -1;
     1120
     1121    free(dir);
     1122  } else {
     1123    result = -1;
     1124    SetLastError(ERROR_BAD_ARGUMENTS);
     1125  }
     1126
     1127  return result;
     1128}
     1129
     1130static struct dirent *readdir(DIR *dir) {
     1131  struct dirent *result = 0;
     1132
     1133  if (dir) {
     1134    if (dir->handle != INVALID_HANDLE_VALUE) {
     1135      result = &dir->result;
     1136      (void) WideCharToMultiByte(CP_UTF8, 0,
     1137          dir->info.cFileName, -1, result->d_name,
     1138          sizeof(result->d_name), NULL, NULL);
     1139
     1140      if (!FindNextFileW(dir->handle, &dir->info)) {
     1141        (void) FindClose(dir->handle);
     1142        dir->handle = INVALID_HANDLE_VALUE;
     1143      }
     1144
     1145    } else {
     1146      SetLastError(ERROR_FILE_NOT_FOUND);
     1147    }
     1148  } else {
     1149    SetLastError(ERROR_BAD_ARGUMENTS);
     1150  }
     1151
     1152  return result;
     1153}
     1154
     1155#define set_close_on_exec(fd) // No FD_CLOEXEC on Windows
     1156
     1157static int start_thread(struct mg_context *ctx, mg_thread_func_t f, void *p) {
     1158  return _beginthread((void (__cdecl *)(void *)) f, 0, p) == -1L ? -1 : 0;
     1159}
     1160
     1161static HANDLE dlopen(const char *dll_name, int flags) {
     1162  wchar_t wbuf[PATH_MAX];
     1163  flags = 0; // Unused
     1164  to_unicode(dll_name, wbuf, ARRAY_SIZE(wbuf));
     1165  return LoadLibraryW(wbuf);
     1166}
     1167
     1168#if !defined(NO_CGI)
     1169#define SIGKILL 0
     1170static int kill(pid_t pid, int sig_num) {
     1171  (void) TerminateProcess(pid, sig_num);
     1172  (void) CloseHandle(pid);
     1173  return 0;
     1174}
     1175
     1176static pid_t spawn_process(struct mg_connection *conn, const char *prog,
     1177                           char *envblk, char *envp[], int fd_stdin,
     1178                           int fd_stdout, const char *dir) {
     1179  HANDLE me;
     1180  char *p, *interp, cmdline[PATH_MAX], buf[PATH_MAX];
     1181  FILE *fp;
     1182  STARTUPINFOA si = { sizeof(si) };
     1183  PROCESS_INFORMATION pi = { 0 };
     1184
     1185  envp = NULL; // Unused
     1186
     1187  // TODO(lsm): redirect CGI errors to the error log file
     1188  si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
     1189  si.wShowWindow = SW_HIDE;
     1190
     1191  me = GetCurrentProcess();
     1192  (void) DuplicateHandle(me, (HANDLE) _get_osfhandle(fd_stdin), me,
     1193      &si.hStdInput, 0, TRUE, DUPLICATE_SAME_ACCESS);
     1194  (void) DuplicateHandle(me, (HANDLE) _get_osfhandle(fd_stdout), me,
     1195      &si.hStdOutput, 0, TRUE, DUPLICATE_SAME_ACCESS);
     1196
     1197  // If CGI file is a script, try to read the interpreter line
     1198  interp = conn->ctx->config[CGI_INTERPRETER];
     1199  if (interp == NULL) {
     1200    buf[2] = '\0';
     1201    mg_snprintf(conn, cmdline, sizeof(cmdline), "%s%c%s", dir, DIRSEP, prog);
     1202    if ((fp = fopen(cmdline, "r")) != NULL) {
     1203      (void) fgets(buf, sizeof(buf), fp);
     1204      if (buf[0] != '#' || buf[1] != '!') {
     1205        // First line does not start with "#!". Do not set interpreter.
     1206        buf[2] = '\0';
     1207      } else {
     1208        // Trim whitespaces in interpreter name
     1209        for (p = &buf[strlen(buf) - 1]; p > buf && isspace(*p); p--) {
     1210          *p = '\0';
     1211        }
     1212      }
     1213      (void) fclose(fp);
     1214    }
     1215    interp = buf + 2;
     1216  }
     1217
     1218  (void) mg_snprintf(conn, cmdline, sizeof(cmdline), "%s%s%s%c%s",
     1219                     interp, interp[0] == '\0' ? "" : " ", dir, DIRSEP, prog);
     1220
     1221  DEBUG_TRACE(("Running [%s]", cmdline));
     1222  if (CreateProcessA(NULL, cmdline, NULL, NULL, TRUE,
     1223        CREATE_NEW_PROCESS_GROUP, envblk, dir, &si, &pi) == 0) {
     1224    cry(conn, "%s: CreateProcess(%s): %d",
     1225        __func__, cmdline, ERRNO);
     1226    pi.hProcess = (pid_t) -1;
     1227  } else {
     1228    (void) close(fd_stdin);
     1229    (void) close(fd_stdout);
     1230  }
     1231
     1232  (void) CloseHandle(si.hStdOutput);
     1233  (void) CloseHandle(si.hStdInput);
     1234  (void) CloseHandle(pi.hThread);
     1235
     1236  return (pid_t) pi.hProcess;
     1237}
     1238#endif // !NO_CGI
     1239
     1240static int set_non_blocking_mode(SOCKET sock) {
     1241  unsigned long on = 1;
     1242  return ioctlsocket(sock, FIONBIO, &on);
     1243}
     1244
     1245#else
     1246static int mg_stat(const char *path, struct mgstat *stp) {
     1247  struct stat st;
     1248  int ok;
     1249
     1250  if (stat(path, &st) == 0) {
     1251    ok = 0;
     1252    stp->size = st.st_size;
     1253    stp->mtime = st.st_mtime;
     1254    stp->is_directory = S_ISDIR(st.st_mode);
     1255  } else {
     1256    ok = -1;
     1257  }
     1258
     1259  return ok;
     1260}
     1261
     1262static void set_close_on_exec(int fd) {
     1263  (void) fcntl(fd, F_SETFD, FD_CLOEXEC);
     1264}
     1265
     1266static int start_thread(struct mg_context *ctx, mg_thread_func_t func,
     1267                        void *param) {
     1268  pthread_t thread_id;
     1269  pthread_attr_t attr;
     1270  int retval;
     1271
     1272  (void) pthread_attr_init(&attr);
     1273  (void) pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
     1274  // TODO(lsm): figure out why mongoose dies on Linux if next line is enabled
     1275  // (void) pthread_attr_setstacksize(&attr, sizeof(struct mg_connection) * 5);
     1276
     1277  if ((retval = pthread_create(&thread_id, &attr, func, param)) != 0) {
     1278    cry(fc(ctx), "%s: %s", __func__, strerror(retval));
     1279  }
     1280
     1281  return retval;
     1282}
     1283
     1284#ifndef NO_CGI
     1285static pid_t spawn_process(struct mg_connection *conn, const char *prog,
     1286                           char *envblk, char *envp[], int fd_stdin,
     1287                           int fd_stdout, const char *dir) {
     1288  pid_t pid;
     1289  const char *interp;
     1290
     1291  envblk = NULL; // Unused
     1292
     1293  if ((pid = fork()) == -1) {
     1294    // Parent
     1295    send_http_error(conn, 500, http_500_error, "fork(): %s", strerror(ERRNO));
     1296  } else if (pid == 0) {
     1297    // Child
     1298    if (chdir(dir) != 0) {
     1299      cry(conn, "%s: chdir(%s): %s", __func__, dir, strerror(ERRNO));
     1300    } else if (dup2(fd_stdin, 0) == -1) {
     1301      cry(conn, "%s: dup2(%d, 0): %s", __func__, fd_stdin, strerror(ERRNO));
     1302    } else if (dup2(fd_stdout, 1) == -1) {
     1303      cry(conn, "%s: dup2(%d, 1): %s", __func__, fd_stdout, strerror(ERRNO));
     1304    } else {
     1305      (void) dup2(fd_stdout, 2);
     1306      (void) close(fd_stdin);
     1307      (void) close(fd_stdout);
     1308
     1309      // Execute CGI program. No need to lock: new process
     1310      interp = conn->ctx->config[CGI_INTERPRETER];
     1311      if (interp == NULL) {
     1312        (void) execle(prog, prog, NULL, envp);
     1313        cry(conn, "%s: execle(%s): %s", __func__, prog, strerror(ERRNO));
     1314      } else {
     1315        (void) execle(interp, interp, prog, NULL, envp);
     1316        cry(conn, "%s: execle(%s %s): %s", __func__, interp, prog,
     1317            strerror(ERRNO));
     1318      }
     1319    }
     1320    exit(EXIT_FAILURE);
     1321  } else {
     1322    // Parent. Close stdio descriptors
     1323    (void) close(fd_stdin);
     1324    (void) close(fd_stdout);
     1325  }
     1326
     1327  return pid;
     1328}
     1329#endif // !NO_CGI
     1330
     1331static int set_non_blocking_mode(SOCKET sock) {
     1332  int flags;
     1333
     1334  flags = fcntl(sock, F_GETFL, 0);
     1335  (void) fcntl(sock, F_SETFL, flags | O_NONBLOCK);
     1336
     1337  return 0;
     1338}
     1339#endif // _WIN32
     1340
     1341// Write data to the IO channel - opened file descriptor, socket or SSL
     1342// descriptor. Return number of bytes written.
     1343static int64_t push(FILE *fp, SOCKET sock, SSL *ssl, const char *buf,
     1344                    int64_t len) {
     1345  int64_t sent;
     1346  int n, k;
     1347
     1348  sent = 0;
     1349  while (sent < len) {
     1350
     1351    // How many bytes we send in this iteration
     1352    k = len - sent > INT_MAX ? INT_MAX : (int) (len - sent);
     1353
     1354    if (ssl != NULL) {
     1355      n = SSL_write(ssl, buf + sent, k);
     1356    } else if (fp != NULL) {
     1357      n = fwrite(buf + sent, 1, (size_t) k, fp);
     1358      if (ferror(fp))
     1359        n = -1;
     1360    } else {
     1361      n = send(sock, buf + sent, (size_t) k, MSG_NOSIGNAL);
     1362    }
     1363
     1364    if (n < 0)
     1365      break;
     1366
     1367    sent += n;
     1368  }
     1369
     1370  return sent;
     1371}
     1372
     1373// Read from IO channel - opened file descriptor, socket, or SSL descriptor.
     1374// Return number of bytes read.
     1375static int pull(FILE *fp, SOCKET sock, SSL *ssl, char *buf, int len) {
     1376  int nread;
     1377
     1378  if (ssl != NULL) {
     1379    nread = SSL_read(ssl, buf, len);
     1380  } else if (fp != NULL) {
     1381    // Use read() instead of fread(), because if we're reading from the CGI
     1382    // pipe, fread() may block until IO buffer is filled up. We cannot afford
     1383    // to block and must pass all read bytes immediately to the client.
     1384    nread = read(fileno(fp), buf, (size_t) len);
     1385    if (ferror(fp))
     1386      nread = -1;
     1387  } else {
     1388    nread = recv(sock, buf, (size_t) len, 0);
     1389  }
     1390
     1391  return nread;
     1392}
     1393
     1394int mg_read(struct mg_connection *conn, void *buf, size_t len) {
     1395  int n, buffered_len, nread;
     1396  const char *buffered;
     1397
     1398  assert((conn->content_len == -1 && conn->consumed_content == 0) ||
     1399         conn->consumed_content <= conn->content_len);
     1400  DEBUG_TRACE(("%p %zu %lld %lld", buf, len,
     1401               conn->content_len, conn->consumed_content));
     1402  nread = 0;
     1403  if (conn->consumed_content < conn->content_len) {
     1404
     1405    // Adjust number of bytes to read.
     1406    int64_t to_read = conn->content_len - conn->consumed_content;
     1407    if (to_read < (int64_t) len) {
     1408      len = (int) to_read;
     1409    }
     1410
     1411    // How many bytes of data we have buffered in the request buffer?
     1412    buffered = conn->buf + conn->request_len + conn->consumed_content;
     1413    buffered_len = conn->data_len - conn->request_len;
     1414    assert(buffered_len >= 0);
     1415
     1416    // Return buffered data back if we haven't done that yet.
     1417    if (conn->consumed_content < (int64_t) buffered_len) {
     1418      buffered_len -= (int) conn->consumed_content;
     1419      if (len < (size_t) buffered_len) {
     1420        buffered_len = len;
     1421      }
     1422      memcpy(buf, buffered, (size_t)buffered_len);
     1423      len -= buffered_len;
     1424      buf = (char *) buf + buffered_len;
     1425      conn->consumed_content += buffered_len;
     1426      nread = buffered_len;
     1427    }
     1428
     1429    // We have returned all buffered data. Read new data from the remote socket.
     1430    while (len > 0) {
     1431      n = pull(NULL, conn->client.sock, conn->ssl, (char *) buf, (int) len);
     1432      if (n <= 0) {
     1433        break;
     1434      }
     1435      buf = (char *) buf + n;
     1436      conn->consumed_content += n;
     1437      nread += n;
     1438      len -= n;
     1439    }
     1440  }
     1441  return nread;
     1442}
     1443
     1444int mg_write(struct mg_connection *conn, const void *buf, size_t len) {
     1445  return (int) push(NULL, conn->client.sock, conn->ssl, (const char *) buf,
     1446                    (int64_t) len);
     1447}
     1448
     1449int mg_printf(struct mg_connection *conn, const char *fmt, ...) {
     1450  char buf[BUFSIZ];
     1451  int len;
     1452  va_list ap;
     1453
     1454  va_start(ap, fmt);
     1455  len = mg_vsnprintf(conn, buf, sizeof(buf), fmt, ap);
     1456  va_end(ap);
     1457
     1458  return mg_write(conn, buf, (size_t)len);
     1459}
     1460
     1461// URL-decode input buffer into destination buffer.
     1462// 0-terminate the destination buffer. Return the length of decoded data.
     1463// form-url-encoded data differs from URI encoding in a way that it
     1464// uses '+' as character for space, see RFC 1866 section 8.2.1
     1465// http://ftp.ics.uci.edu/pub/ietf/html/rfc1866.txt
     1466static size_t url_decode(const char *src, size_t src_len, char *dst,
     1467                         size_t dst_len, int is_form_url_encoded) {
     1468  size_t i, j;
     1469  int a, b;
     1470#define HEXTOI(x) (isdigit(x) ? x - '0' : x - 'W')
     1471
     1472  for (i = j = 0; i < src_len && j < dst_len - 1; i++, j++) {
     1473    if (src[i] == '%' &&
     1474        isxdigit(* (const unsigned char *) (src + i + 1)) &&
     1475        isxdigit(* (const unsigned char *) (src + i + 2))) {
     1476      a = tolower(* (const unsigned char *) (src + i + 1));
     1477      b = tolower(* (const unsigned char *) (src + i + 2));
     1478      dst[j] = (char) ((HEXTOI(a) << 4) | HEXTOI(b));
     1479      i += 2;
     1480    } else if (is_form_url_encoded && src[i] == '+') {
     1481      dst[j] = ' ';
     1482    } else {
     1483      dst[j] = src[i];
     1484    }
     1485  }
     1486
     1487  dst[j] = '\0'; // Null-terminate the destination
     1488
     1489  return j;
     1490}
     1491
     1492// Scan given buffer and fetch the value of the given variable.
     1493// It can be specified in query string, or in the POST data.
     1494// Return NULL if the variable not found, or allocated 0-terminated value.
     1495// It is caller's responsibility to free the returned value.
     1496int mg_get_var(const char *buf, size_t buf_len, const char *name,
     1497               char *dst, size_t dst_len) {
     1498  const char *p, *e, *s;
     1499  size_t name_len, len;
     1500
     1501  name_len = strlen(name);
     1502  e = buf + buf_len;
     1503  len = -1;
     1504  dst[0] = '\0';
     1505
     1506  // buf is "var1=val1&var2=val2...". Find variable first
     1507  for (p = buf; p != NULL && p + name_len < e; p++) {
     1508    if ((p == buf || p[-1] == '&') && p[name_len] == '=' &&
     1509        !mg_strncasecmp(name, p, name_len)) {
     1510
     1511      // Point p to variable value
     1512      p += name_len + 1;
     1513
     1514      // Point s to the end of the value
     1515      s = (const char *) memchr(p, '&', (size_t)(e - p));
     1516      if (s == NULL) {
     1517        s = e;
     1518      }
     1519      assert(s >= p);
     1520
     1521      // Decode variable into destination buffer
     1522      if ((size_t) (s - p) < dst_len) {
     1523        len = url_decode(p, (size_t)(s - p), dst, dst_len, 1);
     1524      }
     1525      break;
     1526    }
     1527  }
     1528
     1529  return len;
     1530}
     1531
     1532int mg_get_cookie(const struct mg_connection *conn, const char *cookie_name,
     1533                  char *dst, size_t dst_size) {
     1534  const char *s, *p, *end;
     1535  int name_len, len = -1;
     1536
     1537  dst[0] = '\0';
     1538  if ((s = mg_get_header(conn, "Cookie")) == NULL) {
     1539    return 0;
     1540  }
     1541
     1542  name_len = strlen(cookie_name);
     1543  end = s + strlen(s);
     1544
     1545  for (; (s = strstr(s, cookie_name)) != NULL; s += name_len)
     1546    if (s[name_len] == '=') {
     1547      s += name_len + 1;
     1548      if ((p = strchr(s, ' ')) == NULL)
     1549        p = end;
     1550      if (p[-1] == ';')
     1551        p--;
     1552      if (*s == '"' && p[-1] == '"' && p > s + 1) {
     1553        s++;
     1554        p--;
     1555      }
     1556      if ((size_t) (p - s) < dst_size) {
     1557        len = (p - s) + 1;
     1558        mg_strlcpy(dst, s, (size_t)len);
     1559      }
     1560      break;
     1561    }
     1562
     1563  return len;
     1564}
     1565
     1566static int convert_uri_to_file_name(struct mg_connection *conn, char *buf,
     1567                                    size_t buf_len, struct mgstat *st) {
     1568  struct vec a, b;
     1569  const char *rewrite, *uri = conn->request_info.uri;
     1570  char *p;
     1571  int match_len, stat_result;
     1572
     1573  buf_len--;  // This is because memmove() for PATH_INFO may shift part
     1574              // of the path one byte on the right.
     1575  mg_snprintf(conn, buf, buf_len, "%s%s", conn->ctx->config[DOCUMENT_ROOT],
     1576              uri);
     1577
     1578  rewrite = conn->ctx->config[REWRITE];
     1579  while ((rewrite = next_option(rewrite, &a, &b)) != NULL) {
     1580    if ((match_len = match_prefix(a.ptr, a.len, uri)) > 0) {
     1581      mg_snprintf(conn, buf, buf_len, "%.*s%s", b.len, b.ptr, uri + match_len);
     1582      break;
     1583    }
     1584  }
     1585
     1586#if defined(_WIN32) && !defined(__SYMBIAN32__)
     1587  //change_slashes_to_backslashes(buf);
     1588#endif // _WIN32
     1589
     1590  if ((stat_result = mg_stat(buf, st)) != 0) {
     1591    // Support PATH_INFO for CGI scripts.
     1592    for (p = buf + strlen(buf); p > buf + 1; p--) {
     1593      if (*p == '/') {
     1594        *p = '\0';
     1595        if (match_prefix(conn->ctx->config[CGI_EXTENSIONS],
     1596                         strlen(conn->ctx->config[CGI_EXTENSIONS]), buf) > 0 &&
     1597            (stat_result = mg_stat(buf, st)) == 0) {
     1598          // Shift PATH_INFO block one character right, e.g.
     1599          //  "/x.cgi/foo/bar\x00" => "/x.cgi\x00/foo/bar\x00"
     1600          // conn->path_info is pointing to the local variable "path" declared
     1601          // in handle_request(), so PATH_INFO not valid after
     1602          // handle_request returns.
     1603          conn->path_info = p + 1;
     1604          memmove(p + 2, p + 1, strlen(p + 1) + 1);  // +1 is for trailing \0
     1605          p[1] = '/';
     1606          break;
     1607        } else {
     1608          *p = '/';
     1609          stat_result = -1;
     1610        }
     1611      }
     1612    }
     1613  }
     1614
     1615  return stat_result;
     1616}
     1617
     1618static int sslize(struct mg_connection *conn, int (*func)(SSL *)) {
     1619  return (conn->ssl = SSL_new(conn->ctx->ssl_ctx)) != NULL &&
     1620    SSL_set_fd(conn->ssl, conn->client.sock) == 1 &&
     1621    func(conn->ssl) == 1;
     1622}
     1623
     1624// Check whether full request is buffered. Return:
     1625//   -1  if request is malformed
     1626//    0  if request is not yet fully buffered
     1627//   >0  actual request length, including last \r\n\r\n
     1628static int get_request_len(const char *buf, int buflen) {
     1629  const char *s, *e;
     1630  int len = 0;
     1631
     1632  DEBUG_TRACE(("buf: %p, len: %d", buf, buflen));
     1633  for (s = buf, e = s + buflen - 1; len <= 0 && s < e; s++)
     1634    // Control characters are not allowed but >=128 is.
     1635    if (!isprint(* (const unsigned char *) s) && *s != '\r' &&
     1636        *s != '\n' && * (const unsigned char *) s < 128) {
     1637      len = -1;
     1638    } else if (s[0] == '\n' && s[1] == '\n') {
     1639      len = (int) (s - buf) + 2;
     1640    } else if (s[0] == '\n' && &s[1] < e &&
     1641        s[1] == '\r' && s[2] == '\n') {
     1642      len = (int) (s - buf) + 3;
     1643    }
     1644
     1645  return len;
     1646}
     1647
     1648// Convert month to the month number. Return -1 on error, or month number
     1649static int get_month_index(const char *s) {
     1650  size_t i;
     1651
     1652  for (i = 0; i < ARRAY_SIZE(month_names); i++)
     1653    if (!strcmp(s, month_names[i]))
     1654      return (int) i;
     1655
     1656  return -1;
     1657}
     1658
     1659// Parse UTC date-time string, and return the corresponding time_t value.
     1660static time_t parse_date_string(const char *datetime) {
     1661  static const unsigned short days_before_month[] = {
     1662    0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334
     1663  };
     1664  char month_str[32];
     1665  int second, minute, hour, day, month, year, leap_days, days;
     1666  time_t result = (time_t) 0;
     1667
     1668  if (((sscanf(datetime, "%d/%3s/%d %d:%d:%d",
     1669               &day, month_str, &year, &hour, &minute, &second) == 6) ||
     1670       (sscanf(datetime, "%d %3s %d %d:%d:%d",
     1671               &day, month_str, &year, &hour, &minute, &second) == 6) ||
     1672       (sscanf(datetime, "%*3s, %d %3s %d %d:%d:%d",
     1673               &day, month_str, &year, &hour, &minute, &second) == 6) ||
     1674       (sscanf(datetime, "%d-%3s-%d %d:%d:%d",
     1675               &day, month_str, &year, &hour, &minute, &second) == 6)) &&
     1676      year > 1970 &&
     1677      (month = get_month_index(month_str)) != -1) {
     1678    year -= 1970;
     1679    leap_days = year / 4 - year / 100 + year / 400;
     1680    days = year * 365 + days_before_month[month] + (day - 1) + leap_days;
     1681    result = days * 24 * 3600 + hour * 3600 + minute * 60 + second;
     1682  }
     1683
     1684  return result;
     1685}
     1686
     1687// Protect against directory disclosure attack by removing '..',
     1688// excessive '/' and '\' characters
     1689static void remove_double_dots_and_double_slashes(char *s) {
     1690  char *p = s;
     1691
     1692  while (*s != '\0') {
     1693    *p++ = *s++;
     1694    if (IS_DIRSEP_CHAR(s[-1])) {
     1695      // Skip all following slashes and backslashes
     1696      while (IS_DIRSEP_CHAR(s[0])) {
     1697        s++;
     1698      }
     1699
     1700      // Skip all double-dots
     1701      while (*s == '.' && s[1] == '.') {
     1702        s += 2;
     1703      }
     1704    }
     1705  }
     1706  *p = '\0';
     1707}
     1708
     1709static const struct {
     1710  const char *extension;
     1711  size_t ext_len;
     1712  const char *mime_type;
     1713  size_t mime_type_len;
     1714} builtin_mime_types[] = {
     1715  {".html", 5, "text/html",   9},
     1716  {".htm", 4, "text/html",   9},
     1717  {".shtm", 5, "text/html",   9},
     1718  {".shtml", 6, "text/html",   9},
     1719  {".css", 4, "text/css",   8},
     1720  {".js",  3, "application/x-javascript", 24},
     1721  {".ico", 4, "image/x-icon",   12},
     1722  {".gif", 4, "image/gif",   9},
     1723  {".jpg", 4, "image/jpeg",   10},
     1724  {".jpeg", 5, "image/jpeg",   10},
     1725  {".png", 4, "image/png",   9},
     1726  {".svg", 4, "image/svg+xml",  13},
     1727  {".torrent", 8, "application/x-bittorrent", 24},
     1728  {".wav", 4, "audio/x-wav",   11},
     1729  {".mp3", 4, "audio/x-mp3",   11},
     1730  {".mid", 4, "audio/mid",   9},
     1731  {".m3u", 4, "audio/x-mpegurl",  15},
     1732  {".ram", 4, "audio/x-pn-realaudio",  20},
     1733  {".xml", 4, "text/xml",   8},
     1734  {".xslt", 5, "application/xml",  15},
     1735  {".ra",  3, "audio/x-pn-realaudio",  20},
     1736  {".doc", 4, "application/msword",  19},
     1737  {".exe", 4, "application/octet-stream", 24},
     1738  {".zip", 4, "application/x-zip-compressed", 28},
     1739  {".xls", 4, "application/excel",  17},
     1740  {".tgz", 4, "application/x-tar-gz",  20},
     1741  {".tar", 4, "application/x-tar",  17},
     1742  {".gz",  3, "application/x-gunzip",  20},
     1743  {".arj", 4, "application/x-arj-compressed", 28},
     1744  {".rar", 4, "application/x-arj-compressed", 28},
     1745  {".rtf", 4, "application/rtf",  15},
     1746  {".pdf", 4, "application/pdf",  15},
     1747  {".swf", 4, "application/x-shockwave-flash",29},
     1748  {".mpg", 4, "video/mpeg",   10},
     1749  {".mpeg", 5, "video/mpeg",   10},
     1750  {".mp4", 4, "video/mp4", 9},
     1751  {".m4v", 4, "video/x-m4v", 11},
     1752  {".asf", 4, "video/x-ms-asf",  14},
     1753  {".avi", 4, "video/x-msvideo",  15},
     1754  {".bmp", 4, "image/bmp",   9},
     1755  {NULL,  0, NULL,    0}
    4401756};
    4411757
    442 /*
    443  * Client connection.
    444  */
    445 struct mg_connection {
    446         struct mg_request_info  request_info;
    447         struct mg_context *ctx;         /* Mongoose context we belong to*/
    448         SSL             *ssl;           /* SSL descriptor               */
    449         struct socket   client;         /* Connected client             */
    450         time_t          birth_time;     /* Time connection was accepted */
    451         bool_t          free_post_data; /* post_data was malloc-ed      */
    452         bool_t          embedded_auth;  /* Used for authorization       */
    453         int64_t         num_bytes_sent; /* Total bytes sent to client   */
    454 };
    455 
    456 /*
    457  * Print error message to the opened error log stream.
    458  */
    459 static void
    460 cry(struct mg_connection *conn, const char *fmt, ...)
    461 {
    462         char    buf[BUFSIZ];
    463         va_list ap;
    464 
    465         va_start(ap, fmt);
    466         (void) vsnprintf(buf, sizeof(buf), fmt, ap);
    467         conn->ctx->log_callback(conn, &conn->request_info, buf);
    468         va_end(ap);
    469 }
    470 
    471 /*
    472  * Return fake connection structure. Used for logging, if connection
    473  * is not applicable at the moment of logging.
    474  */
    475 static struct mg_connection *
    476 fc(struct mg_context *ctx)
    477 {
    478         static struct mg_connection fake_connection;
    479         fake_connection.ctx = ctx;
    480         return (&fake_connection);
    481 }
    482 
    483 /*
    484  * If an embedded code does not intercept logging by calling
    485  * mg_set_log_callback(), this function is used for logging. It prints
    486  * stuff to the conn->error_log, which is stderr unless "error_log"
    487  * option was set.
    488  */
    489 static void
    490 builtin_error_log(struct mg_connection *conn,
    491                 const struct mg_request_info *request_info, void *message)
    492 {
    493         FILE    *fp;
    494         time_t  timestamp;
    495 
    496         fp = conn->ctx->error_log;
    497         flockfile(fp);
    498 
    499         timestamp = time(NULL);
    500 
    501         (void) fprintf(fp,
    502             "[%010lu] [error] [client %s] ",
    503             (unsigned long) timestamp,
    504             inet_ntoa(conn->client.rsa.u.sin.sin_addr));
    505 
    506         if (request_info->request_method != NULL)
    507                 (void) fprintf(fp, "%s %s: ",
    508                     request_info->request_method,
    509                     request_info->uri);
    510 
    511         (void) fprintf(fp, "%s", (char *) message);
    512 
    513         fputc('\n', fp);
    514 
    515         funlockfile(fp);
    516 }
    517 
    518 const char *
    519 mg_version(void)
    520 {
    521         return (MONGOOSE_VERSION);
    522 }
    523 
    524 static void
    525 mg_strlcpy(register char *dst, register const char *src, size_t n)
    526 {
    527         for (; *src != '\0' && n > 1; n--)
    528                 *dst++ = *src++;
    529         *dst = '\0';
    530 }
    531 
    532 static int
    533 lowercase(const char *s)
    534 {
    535         return (tolower(* (unsigned char *) s));
    536 }
    537 
    538 static int
    539 mg_strncasecmp(const char *s1, const char *s2, size_t len)
    540 {
    541         int     diff = 0;
    542 
    543         if (len > 0)
    544                 do {
    545                         diff = lowercase(s1++) - lowercase(s2++);
    546                 } while (diff == 0 && s1[-1] != '\0' && --len > 0);
    547 
    548         return (diff);
    549 }
    550 
    551 static int
    552 mg_strcasecmp(const char *s1, const char *s2)
    553 {
    554         int     diff;
    555 
    556         do {
    557                 diff = lowercase(s1++) - lowercase(s2++);
    558         } while (diff == 0 && s1[-1] != '\0');
    559 
    560         return (diff);
    561 }
    562 
    563 static char *
    564 mg_strndup(const char *ptr, size_t len)
    565 {
    566         char    *p;
    567 
    568         if ((p = (char *) malloc(len + 1)) != NULL)
    569                 mg_strlcpy(p, ptr, len + 1);
    570 
    571         return (p);
    572 
    573 }
    574 
    575 static char *
    576 mg_strdup(const char *str)
    577 {
    578         return (mg_strndup(str, strlen(str)));
    579 }
    580 
    581 /*
    582  * Like snprintf(), but never returns negative value, or the value
    583  * that is larger than a supplied buffer.
    584  * Thanks to Adam Zeldis to pointing snprintf()-caused vulnerability
    585  * in his audit report.
    586  */
    587 static int
    588 mg_vsnprintf(struct mg_connection *conn,
    589                 char *buf, size_t buflen, const char *fmt, va_list ap)
    590 {
    591         int     n;
    592 
    593         if (buflen == 0)
    594                 return (0);
    595 
    596         n = vsnprintf(buf, buflen, fmt, ap);
    597 
    598         if (n < 0) {
    599                 cry(conn, "vsnprintf error");
    600                 n = 0;
    601         } else if (n >= (int) buflen) {
    602                 cry(conn, "truncating vsnprintf buffer: [%.*s]",
    603                     n > 200 ? 200 : n, buf);
    604                 n = (int) buflen - 1;
    605         }
    606         buf[n] = '\0';
    607 
    608         return (n);
    609 }
    610 
    611 static int
    612 mg_snprintf(struct mg_connection *conn,
    613                 char *buf, size_t buflen, const char *fmt, ...)
    614 {
    615         va_list ap;
    616         int     n;
    617 
    618         va_start(ap, fmt);
    619         n = mg_vsnprintf(conn, buf, buflen, fmt, ap);
    620         va_end(ap);
    621 
    622         return (n);
    623 }
    624 
    625 /*
    626  * Convert string representing a boolean value to a boolean value
    627  */
    628 static bool_t
    629 is_true(const char *str)
    630 {
    631         static const char       *trues[] = {"1", "yes", "true", "ja", NULL};
    632         int                     i;
    633 
    634         for (i = 0; trues[i] != NULL; i++)
    635                 if (str != NULL && mg_strcasecmp(str, trues[i]) == 0)
    636                         return (TRUE);
    637 
    638         return (FALSE);
    639 }
    640 
    641 /*
    642  * Skip the characters until one of the delimiters characters found.
    643  * 0-terminate resulting word. Skip the rest of the delimiters if any.
    644  * Advance pointer to buffer to the next word. Return found 0-terminated word.
    645  */
    646 static char *
    647 skip(char **buf, const char *delimiters)
    648 {
    649         char    *p, *begin_word, *end_word, *end_delimiters;
    650 
    651         begin_word = *buf;
    652         end_word = begin_word + strcspn(begin_word, delimiters);
    653         end_delimiters = end_word + strspn(end_word, delimiters);
    654 
    655         for (p = end_word; p < end_delimiters; p++)
    656                 *p = '\0';
    657 
    658         *buf = end_delimiters;
    659 
    660         return (begin_word);
    661 }
    662 
    663 /*
    664  * Return HTTP header value, or NULL if not found.
    665  */
    666 static const char *
    667 get_header(const struct mg_request_info *ri, const char *name)
    668 {
    669         int     i;
    670 
    671         for (i = 0; i < ri->num_headers; i++)
    672                 if (!mg_strcasecmp(name, ri->http_headers[i].name))
    673                         return (ri->http_headers[i].value);
    674 
    675         return (NULL);
    676 }
    677 
    678 const char *
    679 mg_get_header(const struct mg_connection *conn, const char *name)
    680 {
    681         return (get_header(&conn->request_info, name));
    682 }
    683 
    684 /*
    685  * A helper function for traversing comma separated list of values.
    686  * It returns a list pointer shifted to the next value, of NULL if the end
    687  * of the list found.
    688  * Value is stored in val vector. If value has form "x=y", then eq_val
    689  * vector is initialized to point to the "y" part, and val vector length
    690  * is adjusted to point only to "x".
    691  */
    692 static const char *
    693 next_option(const char *list, struct vec *val, struct vec *eq_val)
    694 {
    695         if (list == NULL || *list == '\0') {
    696                 /* End of the list */
    697                 list = NULL;
    698         } else {
    699                 val->ptr = list;
    700                 if ((list = strchr(val->ptr, ',')) != NULL) {
    701                         /* Comma found. Store length and shift the list ptr */
    702                         val->len = list - val->ptr;
    703                         list++;
    704                 } else {
    705                         /* This value is the last one */
    706                         list = val->ptr + strlen(val->ptr);
    707                         val->len = list - val->ptr;
    708                 }
    709 
    710                 if (eq_val != NULL) {
    711                         /*
    712                          * Value has form "x=y", adjust pointers and lengths
    713                          * so that val points to "x", and eq_val points to "y".
    714                          */
    715                         eq_val->len = 0;
    716                         eq_val->ptr = memchr(val->ptr, '=', val->len);
    717                         if (eq_val->ptr != NULL) {
    718                                 eq_val->ptr++;  /* Skip over '=' character */
    719                                 eq_val->len = val->ptr + val->len - eq_val->ptr;
    720                                 val->len = (eq_val->ptr - val->ptr) - 1;
    721                         }
    722                 }
    723         }
    724 
    725         return (list);
    726 }
    727 
    728 #if !(defined(NO_CGI) && defined(NO_SSI))
    729 /*
    730  * Verify that given file has certain extension
    731  */
    732 static bool_t
    733 match_extension(const char *path, const char *ext_list)
    734 {
    735         struct vec      ext_vec;
    736         size_t          path_len;
    737 
    738         path_len = strlen(path);
    739 
    740         while ((ext_list = next_option(ext_list, &ext_vec, NULL)) != NULL)
    741                 if (ext_vec.len < path_len &&
    742                     mg_strncasecmp(path + path_len - ext_vec.len,
    743                             ext_vec.ptr, ext_vec.len) == 0)
    744                         return (TRUE);
    745 
    746         return (FALSE);
    747 }
    748 #endif /* !(NO_CGI && NO_SSI) */
    749 
    750 /*
    751  * Return TRUE if "uri" matches "regexp".
    752  * '*' in the regexp means zero or more characters.
    753  */
    754 static bool_t
    755 match_regex(const char *uri, const char *regexp)
    756 {
    757         if (*regexp == '\0')
    758                 return (*uri == '\0');
    759 
    760         if (*regexp == '*')
    761                 do {
    762                         if (match_regex(uri, regexp + 1))
    763                                 return (TRUE);
    764                 } while (*uri++ != '\0');
    765 
    766         if (*uri != '\0' && *regexp == *uri)
    767                 return (match_regex(uri + 1, regexp + 1));
    768 
    769         return (FALSE);
    770 }
    771 
    772 static const struct callback *
    773 find_callback(struct mg_context *ctx, bool_t is_auth,
    774                 const char *uri, int status_code)
    775 {
    776         const struct callback   *cb, *found;
    777         int                     i;
    778 
    779         found = NULL;
    780         pthread_mutex_lock(&ctx->bind_mutex);
    781         for (i = 0; i < ctx->num_callbacks; i++) {
    782                 cb = ctx->callbacks + i;
    783                 if ((uri != NULL && cb->uri_regex != NULL &&
    784                     ((is_auth && cb->is_auth) || (!is_auth && !cb->is_auth)) &&
    785                     match_regex(uri, cb->uri_regex)) || (uri == NULL &&
    786                      (cb->status_code == 0 ||
    787                       cb->status_code == status_code))) {
    788                         found = cb;
    789                         break;
    790                 }
    791         }
    792         pthread_mutex_unlock(&ctx->bind_mutex);
    793 
    794         return (found);
    795 }
    796 
    797 /*
    798  * For use by external application. This sets custom logging function.
    799  */
    800 void
    801 mg_set_log_callback(struct mg_context *ctx, mg_callback_t log_callback)
    802 {
    803         /* If NULL is specified as a callback, revert back to the default */
    804         if (log_callback == NULL)
    805                 ctx->log_callback = &builtin_error_log;
    806         else
    807                 ctx->log_callback = log_callback;
    808 }
    809 
    810 /*
    811  * Send error message back to the client.
    812  */
    813 static void
    814 send_error(struct mg_connection *conn, int status, const char *reason,
    815                 const char *fmt, ...)
    816 {
    817         const struct callback   *cb;
    818         char            buf[BUFSIZ];
    819         va_list         ap;
    820         int             len;
    821 
    822         conn->request_info.status_code = status;
    823 
    824         /* If error handler is set, call it. Otherwise, send error message */
    825         if ((cb = find_callback(conn->ctx, FALSE, NULL, status)) != NULL) {
    826                 cb->func(conn, &conn->request_info, cb->user_data);
    827         } else {
    828                 buf[0] = '\0';
    829                 len = 0;
    830 
    831                 /* Errors 1xx, 204 and 304 MUST NOT send a body */
    832                 if (status > 199 && status != 204 && status != 304) {
    833                         len = mg_snprintf(conn, buf, sizeof(buf),
    834                             "Error %d: %s\n", status, reason);
    835                         cry(conn, "%s", buf);
    836 
    837                         va_start(ap, fmt);
    838                         len += mg_vsnprintf(conn, buf + len, sizeof(buf) - len,
    839                             fmt, ap);
    840                         va_end(ap);
    841                         conn->num_bytes_sent = len;
    842                 }
    843 
    844                 (void) mg_printf(conn,
    845                     "HTTP/1.1 %d %s\r\n"
    846                     "Content-Type: text/plain\r\n"
    847                     "Content-Length: %d\r\n"
    848                     "Connection: close\r\n"
    849                     "\r\n%s", status, reason, len, buf);
    850         }
    851 }
    852 
    853 #ifdef _WIN32
    854 static int
    855 pthread_mutex_init(pthread_mutex_t *mutex, void *unused)
    856 {
    857         unused = NULL;
    858         *mutex = CreateMutex(NULL, FALSE, NULL);
    859         return (*mutex == NULL ? -1 : 0);
    860 }
    861 
    862 static int
    863 pthread_mutex_destroy(pthread_mutex_t *mutex)
    864 {
    865         return (CloseHandle(*mutex) == 0 ? -1 : 0);
    866 }
    867 
    868 static int
    869 pthread_mutex_lock(pthread_mutex_t *mutex)
    870 {
    871         return (WaitForSingleObject(*mutex, INFINITE) == WAIT_OBJECT_0? 0 : -1);
    872 }
    873 
    874 static int
    875 pthread_mutex_unlock(pthread_mutex_t *mutex)
    876 {
    877         return (ReleaseMutex(*mutex) == 0 ? -1 : 0);
    878 }
    879 
    880 static int
    881 pthread_cond_init(pthread_cond_t *cv, const void *unused)
    882 {
    883         unused = NULL;
    884         *cv = CreateEvent(NULL, FALSE, FALSE, NULL);
    885         return (*cv == NULL ? -1 : 0);
    886 }
    887 
    888 static int
    889 pthread_cond_timedwait(pthread_cond_t *cv, pthread_mutex_t *mutex,
    890         const struct timespec *ts)
    891 {
    892         DWORD   status;
    893         DWORD   msec = INFINITE;
    894         time_t  now;
    895        
    896         if (ts != NULL) {
    897                 now = time(NULL);
    898                 msec = 1000 * (now > ts->tv_sec ? 0 : ts->tv_sec - now);
    899         }
    900 
    901         (void) ReleaseMutex(*mutex);
    902         status = WaitForSingleObject(*cv, msec);
    903         (void) WaitForSingleObject(*mutex, INFINITE);
    904        
    905         return (status == WAIT_OBJECT_0 ? 0 : -1);
    906 }
    907 
    908 static int
    909 pthread_cond_wait(pthread_cond_t *cv, pthread_mutex_t *mutex)
    910 {
    911         return (pthread_cond_timedwait(cv, mutex, NULL));
    912 }
    913 
    914 static int
    915 pthread_cond_signal(pthread_cond_t *cv)
    916 {
    917         return (SetEvent(*cv) == 0 ? -1 : 0);
    918 }
    919 
    920 static int
    921 pthread_cond_destroy(pthread_cond_t *cv)
    922 {
    923         return (CloseHandle(*cv) == 0 ? -1 : 0);
    924 }
    925 
    926 static pthread_t
    927 pthread_self(void)
    928 {
    929         return (GetCurrentThreadId());
    930 }
    931 
    932 /*
    933  * Change all slashes to backslashes. It is Windows.
    934  */
    935 static void
    936 fix_directory_separators(char *path)
    937 {
    938         int     i;
    939 
    940         for (i = 0; path[i] != '\0'; i++) {
    941                 if (path[i] == '/')
    942                         path[i] = '\\';
    943                 /* i > 0 check is to preserve UNC paths, \\server\file.txt */
    944                 if (path[i] == '\\' && i > 0)
    945                         while (path[i + 1] == '\\' || path[i + 1] == '/')
    946                                 (void) memmove(path + i + 1,
    947                                     path + i + 2, strlen(path + i + 1));
    948         }
    949 }
    950 
    951 /*
    952  * Encode 'path' which is assumed UTF-8 string, into UNICODE string.
    953  * wbuf and wbuf_len is a target buffer and its length.
    954  */
    955 static void
    956 to_unicode(const char *path, wchar_t *wbuf, size_t wbuf_len)
    957 {
    958         char    buf[FILENAME_MAX], *p;
    959 
    960         mg_strlcpy(buf, path, sizeof(buf));
    961         fix_directory_separators(buf);
    962 
    963         /* Point p to the end of the file name */
    964         p = buf + strlen(buf) - 1;
    965 
    966         /* Trim trailing backslash character */
    967         while (p > buf && *p == '\\' && p[-1] != ':')
    968                 *p-- = '\0';
    969 
    970         /*
    971          * Protect from CGI code disclosure.
    972          * This is very nasty hole. Windows happily opens files with
    973          * some garbage in the end of file name. So fopen("a.cgi    ", "r")
    974          * actually opens "a.cgi", and does not return an error!
    975          */
    976         if (*p == 0x20 ||               /* No space at the end */
    977             (*p == 0x2e && p > buf) ||  /* No '.' but allow '.' as full path */
    978             *p == 0x2b ||               /* No '+' */
    979             (*p & ~0x7f)) {             /* And generally no non-ascii chars */
    980                 (void) fprintf(stderr, "Rejecting suspicious path: [%s]", buf);
    981                 buf[0] = '\0';
    982         }
    983 
    984         (void) MultiByteToWideChar(CP_UTF8, 0, buf, -1, wbuf, (int) wbuf_len);
    985 }
    986 
    987 #if defined(_WIN32_WCE)
    988 
    989 static time_t
    990 time(time_t *ptime)
    991 {
    992         time_t          t;
    993         SYSTEMTIME      st;
    994         FILETIME        ft;
    995 
    996         GetSystemTime(&st);
    997         SystemTimeToFileTime(&st, &ft);
    998         t = SYS2UNIX_TIME(ft.dwLowDateTime, ft.dwHighDateTime);
    999 
    1000         if (ptime != NULL)
    1001                 *ptime = t;
    1002 
    1003         return (t);
    1004 }
    1005 
    1006 static time_t
    1007 mktime(struct tm *ptm)
    1008 {
    1009         SYSTEMTIME      st;
    1010         FILETIME        ft, lft;
    1011 
    1012         st.wYear = ptm->tm_year + 1900;
    1013         st.wMonth = ptm->tm_mon + 1;
    1014         st.wDay = ptm->tm_mday;
    1015         st.wHour = ptm->tm_hour;
    1016         st.wMinute = ptm->tm_min;
    1017         st.wSecond = ptm->tm_sec;
    1018         st.wMilliseconds = 0;
    1019 
    1020         SystemTimeToFileTime(&st, &ft);
    1021         LocalFileTimeToFileTime(&ft, &lft);
    1022         return (time_t)((MAKEUQUAD(lft.dwLowDateTime, lft.dwHighDateTime) -
    1023             EPOCH_DIFF) / RATE_DIFF);
    1024 }
    1025 
    1026 static struct tm *
    1027 localtime(const time_t *ptime, struct tm *ptm)
    1028 {
    1029         int64_t t = ((int64_t)*ptime) * RATE_DIFF + EPOCH_DIFF;
    1030         FILETIME        ft, lft;
    1031         SYSTEMTIME      st;
    1032         TIME_ZONE_INFORMATION   tzinfo;
    1033 
    1034         if (ptm == NULL)
    1035                 return NULL;
    1036 
    1037         * (int64_t *) &ft = t;
    1038         FileTimeToLocalFileTime(&ft, &lft);
    1039         FileTimeToSystemTime(&lft, &st);
    1040         ptm->tm_year = st.wYear - 1900;
    1041         ptm->tm_mon = st.wMonth - 1;
    1042         ptm->tm_wday = st.wDayOfWeek;
    1043         ptm->tm_mday = st.wDay;
    1044         ptm->tm_hour = st.wHour;
    1045         ptm->tm_min = st.wMinute;
    1046         ptm->tm_sec = st.wSecond;
    1047         ptm->tm_yday = 0; // hope nobody uses this
    1048         ptm->tm_isdst = ((GetTimeZoneInformation(&tzinfo) ==
    1049             TIME_ZONE_ID_DAYLIGHT) ? 1 : 0);
    1050 
    1051         return ptm;
    1052 }
    1053 
    1054 static size_t
    1055 strftime(char *dst, size_t dst_size, const char *fmt, const struct tm *tm)
    1056 {
    1057         (void) snprintf(dst, dst_size, "implement strftime() for WinCE");
    1058         return (0);
    1059 }       
    1060 #endif
    1061 
    1062 static int
    1063 mg_rename(const char* oldname, const char* newname)
    1064 {
    1065         wchar_t woldbuf[FILENAME_MAX];
    1066         wchar_t wnewbuf[FILENAME_MAX];
    1067 
    1068         to_unicode(oldname, woldbuf, ARRAY_SIZE(woldbuf));
    1069         to_unicode(newname, wnewbuf, ARRAY_SIZE(wnewbuf));
    1070 
    1071         return (MoveFileW(woldbuf, wnewbuf) ? 0 : -1);
    1072 }
    1073 
    1074 
    1075 static FILE *
    1076 mg_fopen(const char *path, const char *mode)
    1077 {
    1078         wchar_t wbuf[FILENAME_MAX], wmode[20];
    1079 
    1080         to_unicode(path, wbuf, ARRAY_SIZE(wbuf));
    1081         MultiByteToWideChar(CP_UTF8, 0, mode, -1, wmode, ARRAY_SIZE(wmode));
    1082 
    1083         return (_wfopen(wbuf, wmode));
    1084 }
    1085 
    1086 static int
    1087 mg_stat(const char *path, struct mgstat *stp)
    1088 {
    1089         int                             ok = -1; /* Error */
    1090         wchar_t                         wbuf[FILENAME_MAX];
    1091         WIN32_FILE_ATTRIBUTE_DATA       info;
    1092 
    1093         to_unicode(path, wbuf, ARRAY_SIZE(wbuf));
    1094 
    1095         if (GetFileAttributesExW(wbuf, GetFileExInfoStandard, &info) != 0) {
    1096                 stp->size = MAKEUQUAD(info.nFileSizeLow, info.nFileSizeHigh);
    1097                 stp->mtime = SYS2UNIX_TIME(info.ftLastWriteTime.dwLowDateTime,
    1098                     info.ftLastWriteTime.dwHighDateTime);
    1099                 stp->is_directory =
    1100                     info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY;
    1101                 ok = 0;  /* Success */
    1102         }
    1103 
    1104         return (ok);
    1105 }
    1106 
    1107 static int
    1108 mg_remove(const char *path)
    1109 {
    1110         wchar_t wbuf[FILENAME_MAX];
    1111 
    1112         to_unicode(path, wbuf, ARRAY_SIZE(wbuf));
    1113 
    1114         return (DeleteFileW(wbuf) ? 0 : -1);
    1115 }
    1116 
    1117 static int
    1118 mg_mkdir(const char *path, int mode)
    1119 {
    1120         char    buf[FILENAME_MAX];
    1121         wchar_t wbuf[FILENAME_MAX];
    1122 
    1123         mode = 0; /* Unused */
    1124         mg_strlcpy(buf, path, sizeof(buf));
    1125         fix_directory_separators(buf);
    1126 
    1127         (void) MultiByteToWideChar(CP_UTF8, 0, buf, -1, wbuf, sizeof(wbuf));
    1128 
    1129         return (CreateDirectoryW(wbuf, NULL) ? 0 : -1);
    1130 }
    1131 
    1132 /*
    1133  * Implementation of POSIX opendir/closedir/readdir for Windows.
    1134  */
    1135 static DIR *
    1136 opendir(const char *name)
    1137 {
    1138         DIR     *dir = NULL;
    1139         wchar_t wpath[FILENAME_MAX];
    1140         DWORD attrs;
    1141 
    1142         if (name == NULL) {
    1143                 SetLastError(ERROR_BAD_ARGUMENTS);
    1144         } else if ((dir = (DIR *) malloc(sizeof(*dir))) == NULL) {
    1145                 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
    1146         } else {
    1147                 to_unicode(name, wpath, ARRAY_SIZE(wpath));
    1148                 attrs = GetFileAttributesW(wpath);
    1149                 if (attrs != 0xFFFFFFFF &&
    1150                     ((attrs & FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY)) {
    1151                         (void) wcscat(wpath, L"\\*");
    1152                         dir->handle = FindFirstFileW(wpath, &dir->info);
    1153                         dir->result.d_name[0] = '\0';
    1154                 } else {
    1155                         free(dir);
    1156                         dir = NULL;
    1157                 }
    1158         }
    1159 
    1160         return (dir);
    1161 }
    1162 
    1163 static int
    1164 closedir(DIR *dir)
    1165 {
    1166         int result = 0;
    1167 
    1168         if (dir != NULL) {
    1169                 if (dir->handle != INVALID_HANDLE_VALUE)
    1170                         result = FindClose(dir->handle) ? 0 : -1;
    1171 
    1172                 free(dir);
    1173         } else {
    1174                 result = -1;
    1175                 SetLastError(ERROR_BAD_ARGUMENTS);
    1176         }
    1177 
    1178         return (result);
    1179 }
    1180 
    1181 struct dirent *
    1182 readdir(DIR *dir)
    1183 {
    1184         struct dirent *result = 0;
    1185 
    1186         if (dir) {
    1187                 if (dir->handle != INVALID_HANDLE_VALUE) {
    1188                         result = &dir->result;
    1189                         (void) WideCharToMultiByte(CP_UTF8, 0,
    1190                             dir->info.cFileName, -1, result->d_name,
    1191                             sizeof(result->d_name), NULL, NULL);
    1192 
    1193                         if (!FindNextFileW(dir->handle, &dir->info)) {
    1194                                 (void) FindClose(dir->handle);
    1195                                 dir->handle = INVALID_HANDLE_VALUE;
    1196                         }
    1197 
    1198                 } else {
    1199                         SetLastError(ERROR_FILE_NOT_FOUND);
    1200                 }
    1201         } else {
    1202                 SetLastError(ERROR_BAD_ARGUMENTS);
    1203         }
    1204 
    1205         return (result);
    1206 }
    1207 
    1208 #define set_close_on_exec(fd)   /* No FD_CLOEXEC on Windows */
    1209 
    1210 static int
    1211 start_thread(struct mg_context *ctx, mg_thread_func_t func, void *param)
    1212 {
    1213         HANDLE  hThread;
    1214 
    1215         ctx = NULL;     /* Unused */
    1216        
    1217         hThread = CreateThread(NULL, 0,
    1218             (LPTHREAD_START_ROUTINE) func, param, 0, NULL);
    1219 
    1220         if (hThread != NULL)
    1221                 (void) CloseHandle(hThread);
    1222 
    1223         return (hThread == NULL ? -1 : 0);
    1224 }
    1225 
    1226 static HANDLE
    1227 dlopen(const char *dll_name, int flags)
    1228 {
    1229         wchar_t wbuf[FILENAME_MAX];
    1230 
    1231         flags = 0; /* Unused */
    1232         to_unicode(dll_name, wbuf, ARRAY_SIZE(wbuf));
    1233 
    1234         return (LoadLibraryW(wbuf));
    1235 }
    1236 
    1237 #if !defined(NO_CGI)
    1238 static int
    1239 kill(pid_t pid, int sig_num)
    1240 {
    1241         (void) TerminateProcess(pid, sig_num);
    1242         (void) CloseHandle(pid);
    1243         return (0);
    1244 }
    1245 
    1246 static pid_t
    1247 spawn_process(struct mg_connection *conn, const char *prog, char *envblk,
    1248                 char *envp[], int fd_stdin, int fd_stdout, const char *dir)
    1249 {
    1250         HANDLE  me;
    1251         char    *p, *interp, cmdline[FILENAME_MAX], line[FILENAME_MAX];
    1252         FILE    *fp;
    1253         STARTUPINFOA            si;
    1254         PROCESS_INFORMATION     pi;
    1255 
    1256         envp = NULL; /* Unused */
    1257 
    1258         (void) memset(&si, 0, sizeof(si));
    1259         (void) memset(&pi, 0, sizeof(pi));
    1260 
    1261         /* XXX redirect CGI errors to the error log file */
    1262         si.cb           = sizeof(si);
    1263         si.dwFlags      = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
    1264         si.wShowWindow  = SW_HIDE;
    1265 
    1266         me = GetCurrentProcess();
    1267         (void) DuplicateHandle(me, (HANDLE) _get_osfhandle(fd_stdin), me,
    1268             &si.hStdInput, 0, TRUE, DUPLICATE_SAME_ACCESS);
    1269         (void) DuplicateHandle(me, (HANDLE) _get_osfhandle(fd_stdout), me,
    1270             &si.hStdOutput, 0, TRUE, DUPLICATE_SAME_ACCESS);
    1271 
    1272         /* If CGI file is a script, try to read the interpreter line */
    1273         interp = conn->ctx->options[OPT_CGI_INTERPRETER];
    1274         if (interp == NULL) {
    1275                 line[2] = '\0';
    1276                 (void) mg_snprintf(conn, cmdline, sizeof(cmdline), "%s%c%s",
    1277                     dir, DIRSEP, prog);
    1278                 if ((fp = fopen(cmdline, "r")) != NULL) {
    1279                         (void) fgets(line, sizeof(line), fp);
    1280                         if (memcmp(line, "#!", 2) != 0)
    1281                                 line[2] = '\0';
    1282                         /* Trim whitespaces from interpreter name */
    1283                         for (p = &line[strlen(line) - 1]; p > line &&
    1284                             isspace(*p); p--)
    1285                                 *p = '\0';
    1286                         (void) fclose(fp);
    1287                 }
    1288                 interp = line + 2;
    1289         }
    1290 
    1291         if ((p = (char *) strrchr(prog, '/')) != NULL)
    1292                 prog = p + 1;
    1293 
    1294         (void) mg_snprintf(conn, cmdline, sizeof(cmdline), "%s%s%s",
    1295             interp, interp[0] == '\0' ? "" : " ", prog);
    1296 
    1297         (void) mg_snprintf(conn, line, sizeof(line), "%s", dir);
    1298         fix_directory_separators(line);
    1299 
    1300         DEBUG_TRACE((DEBUG_MGS_PREFIX "%s: Running [%s]", __func__, cmdline));
    1301         if (CreateProcessA(NULL, cmdline, NULL, NULL, TRUE,
    1302             CREATE_NEW_PROCESS_GROUP, envblk, line, &si, &pi) == 0) {
    1303                 cry(conn, "%s: CreateProcess(%s): %d",
    1304                     __func__, cmdline, ERRNO);
    1305                 pi.hProcess = (pid_t) -1;
    1306         } else {
    1307                 (void) close(fd_stdin);
    1308                 (void) close(fd_stdout);
    1309         }
    1310 
    1311         (void) CloseHandle(si.hStdOutput);
    1312         (void) CloseHandle(si.hStdInput);
    1313         (void) CloseHandle(pi.hThread);
    1314 
    1315         return ((pid_t) pi.hProcess);
    1316 }
    1317 
    1318 static int
    1319 pipe(int *fds)
    1320 {
    1321         return (_pipe(fds, BUFSIZ, _O_BINARY));
    1322 }
    1323 #endif /* !NO_CGI */
    1324 
    1325 static int
    1326 set_non_blocking_mode(struct mg_connection *conn, SOCKET sock)
    1327 {
    1328         unsigned long   on = 1;
    1329 
    1330         conn = NULL; /* unused */
    1331         return (ioctlsocket(sock, FIONBIO, &on));
    1332 }
    1333 
    1334 #else
    1335 
    1336 static int
    1337 mg_stat(const char *path, struct mgstat *stp)
    1338 {
    1339         struct stat     st;
    1340         int             ok;
    1341 
    1342         if (stat(path, &st) == 0) {
    1343                 ok = 0;
    1344                 stp->size = st.st_size;
    1345                 stp->mtime = st.st_mtime;
    1346                 stp->is_directory = S_ISDIR(st.st_mode);
    1347         } else {
    1348                 ok = -1;
    1349         }
    1350 
    1351         return (ok);
    1352 }
    1353 
    1354 static void
    1355 set_close_on_exec(int fd)
    1356 {
    1357         (void) fcntl(fd, F_SETFD, FD_CLOEXEC);
    1358 }
    1359 
    1360 static int
    1361 start_thread(struct mg_context *ctx, mg_thread_func_t func, void *param)
    1362 {
    1363         pthread_t       thread_id;
    1364         pthread_attr_t  attr;
    1365         int             retval;
    1366 
    1367         (void) pthread_attr_init(&attr);
    1368         (void) pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
    1369 
    1370         if ((retval = pthread_create(&thread_id, &attr, func, param)) != 0)
    1371                 cry(fc(ctx), "%s: %s", __func__, strerror(retval));
    1372 
    1373         return (retval);
    1374 }
    1375 
    1376 #ifndef NO_CGI
    1377 static pid_t
    1378 spawn_process(struct mg_connection *conn, const char *prog, char *envblk,
    1379                 char *envp[], int fd_stdin, int fd_stdout, const char *dir)
    1380 {
    1381         pid_t           pid;
    1382         const char      *interp;
    1383 
    1384         envblk = NULL;  /* unused */
    1385 
    1386         if ((pid = fork()) == -1) {
    1387                 /* Parent */
    1388                 send_error(conn, 500, http_500_error,
    1389                     "fork(): %s", strerror(ERRNO));
    1390         } else if (pid == 0) {
    1391                 /* Child */
    1392                 if (chdir(dir) != 0) {
    1393                         cry(conn, "%s: chdir(%s): %s",
    1394                             __func__, dir, strerror(ERRNO));
    1395                 } else if (dup2(fd_stdin, 0) == -1) {
    1396                         cry(conn, "%s: dup2(stdin, %d): %s",
    1397                             __func__, fd_stdin, strerror(ERRNO));
    1398                 } else if (dup2(fd_stdout, 1) == -1) {
    1399                         cry(conn, "%s: dup2(stdout, %d): %s",
    1400                             __func__, fd_stdout, strerror(ERRNO));
    1401                 } else {
    1402                         /* If error file is specified, send errors there */
    1403                         if (conn->ctx->error_log != NULL)
    1404                                 (void) dup2(fileno(conn->ctx->error_log), 2);
    1405 
    1406                         (void) close(fd_stdin);
    1407                         (void) close(fd_stdout);
    1408 
    1409                         /* Execute CGI program */
    1410                         interp = conn->ctx->options[OPT_CGI_INTERPRETER];
    1411                         if (interp == NULL) {
    1412                                 (void) execle(prog, prog, NULL, envp);
    1413                                 cry(conn, "%s: execle(%s): %s",
    1414                                     __func__, prog, strerror(ERRNO));
    1415                         } else {
    1416                                 (void) execle(interp, interp, prog, NULL, envp);
    1417                                 cry(conn, "%s: execle(%s %s): %s",
    1418                                     __func__, interp, prog, strerror(ERRNO));
    1419                         }
    1420                 }
    1421                 exit(EXIT_FAILURE);
    1422         } else {
    1423                 /* Parent. Close stdio descriptors */
    1424                 (void) close(fd_stdin);
    1425                 (void) close(fd_stdout);
    1426         }
    1427 
    1428         return (pid);
    1429 }
    1430 #endif /* !NO_CGI */
    1431 
    1432 static int
    1433 set_non_blocking_mode(struct mg_connection *conn, SOCKET sock)
    1434 {
    1435         int     flags, ok = -1;
    1436 
    1437         if ((flags = fcntl(sock, F_GETFL, 0)) == -1) {
    1438                 cry(conn, "%s: fcntl(F_GETFL): %d", __func__, ERRNO);
    1439         } else if (fcntl(sock, F_SETFL, flags | O_NONBLOCK) != 0) {
    1440                 cry(conn, "%s: fcntl(F_SETFL): %d", __func__, ERRNO);
    1441         } else {
    1442                 ok = 0; /* Success */
    1443         }
    1444 
    1445         return (ok);
    1446 }
    1447 #endif /* _WIN32 */
    1448 
    1449 static void
    1450 lock_option(struct mg_context *ctx, int opt_index)
    1451 {
    1452         if (pthread_mutex_lock(&ctx->opt_mutex[opt_index]) != 0)
    1453                 cry(fc(ctx), "pthread_mutex_lock: %s", strerror(ERRNO));
    1454 }
    1455 
    1456 static void
    1457 unlock_option(struct mg_context *ctx, int opt_index)
    1458 {
    1459         if (pthread_mutex_unlock(&ctx->opt_mutex[opt_index]) != 0)
    1460                 cry(fc(ctx), "pthread_mutex_unlock: %s", strerror(ERRNO));
    1461 }
    1462 
    1463 /*
    1464  * Write data to the IO channel - opened file descriptor, socket or SSL
    1465  * descriptor. Return number of bytes written.
    1466  */
    1467 static int64_t
    1468 push(FILE *fp, SOCKET sock, SSL *ssl, const char *buf, int64_t len)
    1469 {
    1470         int64_t sent;
    1471         int     n, k;
    1472 
    1473         sent = 0;
    1474         while (sent < len) {
    1475 
    1476                 /* How many bytes we send in this iteration */
    1477                 k = len - sent > INT_MAX ? INT_MAX : (int) (len - sent);
    1478 
    1479                 if (ssl != NULL) {
    1480                         n = SSL_write(ssl, buf + sent, k);
    1481                 } else if (fp != NULL) {
    1482                         n = fwrite(buf + sent, 1, k, fp);
    1483                         if (ferror(fp))
    1484                                 n = -1;
    1485                 } else {
    1486                         n = send(sock, buf + sent, k, 0);
    1487                 }
    1488 
    1489                 if (n < 0)
    1490                         break;
    1491 
    1492                 sent += n;
    1493         }
    1494 
    1495         return (sent);
    1496 }
    1497 
    1498 /*
    1499  * Read from IO channel - opened file descriptor, socket, or SSL descriptor.
    1500  * Return number of bytes read.
    1501  */
    1502 static int
    1503 pull(FILE *fp, SOCKET sock, SSL *ssl, char *buf, int len)
    1504 {
    1505         int     nread;
    1506 
    1507         if (ssl != NULL) {
    1508                 nread = SSL_read(ssl, buf, len);
    1509         } else if (fp != NULL) {
    1510                 nread = fread(buf, 1, (size_t) len, fp);
    1511                 if (ferror(fp))
    1512                         nread = -1;
    1513         } else {
    1514                 nread = recv(sock, buf, (size_t) len, 0);
    1515         }
    1516 
    1517         return (nread);
    1518 }
    1519 
    1520 int
    1521 mg_write(struct mg_connection *conn, const void *buf, int len)
    1522 {
    1523         assert(len >= 0);
    1524         return ((int) push(NULL, conn->client.sock, conn->ssl,
    1525                                 (const char *) buf, (int64_t) len));
    1526 }
    1527 
    1528 int
    1529 mg_printf(struct mg_connection *conn, const char *fmt, ...)
    1530 {
    1531         char    buf[MAX_REQUEST_SIZE];
    1532         int     len;
    1533         va_list ap;
    1534 
    1535         va_start(ap, fmt);
    1536         len = mg_vsnprintf(conn, buf, sizeof(buf), fmt, ap);
    1537         va_end(ap);
    1538 
    1539         return (mg_write(conn, buf, len));
    1540 }
    1541 
    1542 /*
    1543  * Return content length of the request, or -1 constant if
    1544  * Content-Length header is not set.
    1545  */
    1546 static int64_t
    1547 get_content_length(const struct mg_connection *conn)
    1548 {
    1549         const char *cl = mg_get_header(conn, "Content-Length");
    1550         return (cl == NULL ? -1 : strtoll(cl, NULL, 10));
    1551 }
    1552 
    1553 /*
    1554  * URL-decode input buffer into destination buffer.
    1555  * 0-terminate the destination buffer. Return the length of decoded data.
    1556  * form-url-encoded data differs from URI encoding in a way that it
    1557  * uses '+' as character for space, see RFC 1866 section 8.2.1
    1558  * http://ftp.ics.uci.edu/pub/ietf/html/rfc1866.txt
    1559  */
    1560 static size_t
    1561 url_decode(const char *src, size_t src_len, char *dst, size_t dst_len,
    1562                 bool_t is_form_url_encoded)
    1563 {
    1564         size_t  i, j;
    1565         int     a, b;
    1566 #define HEXTOI(x)       (isdigit(x) ? x - '0' : x - 'W')
    1567 
    1568         for (i = j = 0; i < src_len && j < dst_len - 1; i++, j++) {
    1569                 if (src[i] == '%' &&
    1570                     isxdigit(* (unsigned char *) (src + i + 1)) &&
    1571                     isxdigit(* (unsigned char *) (src + i + 2))) {
    1572                         a = tolower(* (unsigned char *) (src + i + 1));
    1573                         b = tolower(* (unsigned char *) (src + i + 2));
    1574                         dst[j] = ((HEXTOI(a) << 4) | HEXTOI(b)) & 0xff;
    1575                         i += 2;
    1576                 } else if (is_form_url_encoded && src[i] == '+') {
    1577                         dst[j] = ' ';
    1578                 } else {
    1579                         dst[j] = src[i];
    1580                 }
    1581         }
    1582 
    1583         dst[j] = '\0';  /* Null-terminate the destination */
    1584 
    1585         return (j);
    1586 }
    1587 
    1588 /*
    1589  * Search for a form variable in a given buffer.
    1590  * Semantic is the same as for mg_get_var().
    1591  */
    1592 static char *
    1593 get_var(const char *name, const char *buf, size_t buf_len)
    1594 {
    1595         const char      *p, *e, *s;
    1596         char            *val;
    1597         size_t          var_len, len;
    1598 
    1599         var_len = strlen(name);
    1600         e = buf + buf_len;
    1601         val = NULL;
    1602 
    1603         /* buf is "var1=val1&var2=val2...". Find variable first */
    1604         for (p = buf; p + var_len < e; p++)
    1605                 if ((p == buf || p[-1] == '&') && p[var_len] == '=' &&
    1606                     !mg_strncasecmp(name, p, var_len)) {
    1607 
    1608                         /* Point p to variable value */
    1609                         p += var_len + 1;
    1610 
    1611                         /* Point s to the end of the value */
    1612                         s = (const char *) memchr(p, '&', e - p);
    1613                         if (s == NULL)
    1614                                 s = e;
    1615 
    1616                         /* Try to allocate the buffer */
    1617                         len = s - p;
    1618                         if ((val = (char *) malloc(len + 1)) != NULL)
    1619                                 (void) url_decode(p, len, val, len + 1, TRUE);
    1620                         break;
    1621                 }
    1622 
    1623         return (val);
    1624 }
    1625 
    1626 /*
    1627  * Free the pointer returned by mg_get_var(). This is needed for languages
    1628  * like python, to have an ability to free allocated data without
    1629  * loading C runtime library and calling free().
    1630  */
    1631 void
    1632 mg_free(char *data)
    1633 {
    1634         free(data);
    1635 }
    1636 
    1637 /*
    1638  * Return form data variable.
    1639  * It can be specified in query string, or in the POST data.
    1640  * Return NULL if the variable not found, or allocated 0-terminated value.
    1641  * It is caller's responsibility to free the returned value.
    1642  */
    1643 char *
    1644 mg_get_var(const struct mg_connection *conn, const char *name)
    1645 {
    1646         const struct mg_request_info    *ri = &conn->request_info;
    1647         char                            *v1, *v2;
    1648 
    1649         v1 = v2 = NULL;
    1650 
    1651         /* Look in both query_string and POST data */
    1652         if (ri->query_string != NULL)
    1653                 v1 = get_var(name, ri->query_string, strlen(ri->query_string));
    1654         if (ri->post_data_len > 0)
    1655                 v2 = get_var(name, ri->post_data, ri->post_data_len);
    1656 
    1657         /* If they both have queried variable, POST data wins */
    1658         if (v1 != NULL && v2 != NULL)
    1659                 free(v1);
    1660 
    1661         return (v2 == NULL ? v1 : v2);
    1662 }
    1663 
    1664 /*
    1665  * Transform URI to the file name.
    1666  */
    1667 static void
    1668 convert_uri_to_file_name(struct mg_connection *conn, const char *uri,
    1669                 char *buf, size_t buf_len)
    1670 {
    1671         struct mg_context       *ctx = conn->ctx;
    1672         struct vec              uri_vec, path_vec;
    1673         const char              *list;
    1674 
    1675         lock_option(ctx, OPT_ROOT);
    1676         mg_snprintf(conn, buf, buf_len, "%s%s", ctx->options[OPT_ROOT], uri);
    1677         unlock_option(ctx, OPT_ROOT);
    1678 
    1679         /* If requested URI has aliased prefix, use alternate root */
    1680         lock_option(ctx, OPT_ALIASES);
    1681         list = ctx->options[OPT_ALIASES];
    1682 
    1683         while ((list = next_option(list, &uri_vec, &path_vec)) != NULL) {
    1684                 if (memcmp(uri, uri_vec.ptr, uri_vec.len) == 0) {
    1685                         (void) mg_snprintf(conn, buf, buf_len, "%.*s%s",
    1686                             path_vec.len, path_vec.ptr, uri + uri_vec.len);
    1687                         break;
    1688                 }
    1689         }
    1690         unlock_option(ctx, OPT_ALIASES);
    1691 
    1692 #ifdef _WIN32
    1693         fix_directory_separators(buf);
    1694 #endif /* _WIN32 */
    1695 
    1696         DEBUG_TRACE((DEBUG_MGS_PREFIX "%s: [%s] -> [%s]", __func__, uri, buf));
    1697 }
    1698 
    1699 /*
    1700  * Setup listening socket on given address, return socket.
    1701  * Address format: [local_ip_address:]port_number
    1702  */
    1703 static SOCKET
    1704 mg_open_listening_port(struct mg_context *ctx, const char *str, struct usa *usa)
    1705 {
    1706         SOCKET          sock;
    1707         int             on = 1, a, b, c, d, port;
    1708 
    1709         /* MacOS needs that. If we do not zero it, bind() will fail. */
    1710         (void) memset(usa, 0, sizeof(*usa));
    1711 
    1712         if (sscanf(str, "%d.%d.%d.%d:%d", &a, &b, &c, &d, &port) == 5) {
    1713                 /* IP address to bind to is specified */
    1714                 usa->u.sin.sin_addr.s_addr =
    1715                     htonl(((uint32_t)a << 24) | ((uint32_t)b << 16) | ((uint32_t)c << 8) | (uint32_t)d);
    1716         } else if (sscanf(str, "%d", &port) == 1) {
    1717                 /* Only port number is specified. Bind to all addresses */
    1718                 usa->u.sin.sin_addr.s_addr = htonl(INADDR_ANY);
    1719         } else {
    1720                 return (INVALID_SOCKET);
    1721         }
    1722 
    1723         usa->len                        = sizeof(usa->u.sin);
    1724         usa->u.sin.sin_family           = AF_INET;
    1725         usa->u.sin.sin_port             = htons((uint16_t) port);
    1726 
    1727         if ((sock = socket(PF_INET, SOCK_STREAM, 6)) != INVALID_SOCKET &&
    1728             setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
    1729             (char *) &on, sizeof(on)) == 0 &&
    1730             bind(sock, &usa->u.sa, usa->len) == 0 &&
    1731             listen(sock, 20) == 0) {
    1732                 /* Success */
    1733                 set_close_on_exec(sock);
    1734         } else {
    1735                 /* Error */
    1736                 cry(fc(ctx), "%s(%d): %s", __func__, port, strerror(ERRNO));
    1737                 if (sock != INVALID_SOCKET)
    1738                         (void) closesocket(sock);
    1739                 sock = INVALID_SOCKET;
    1740         }
    1741 
    1742         return (sock);
    1743 }
    1744 
    1745 /*
    1746  * Check whether full request is buffered. Return:
    1747  *   -1         if request is malformed
    1748  *    0         if request is not yet fully buffered
    1749  *   >0         actual request length, including last \r\n\r\n
    1750  */
    1751 static int
    1752 get_request_len(const char *buf, size_t buflen)
    1753 {
    1754         const char      *s, *e;
    1755         int             len = 0;
    1756 
    1757         for (s = buf, e = s + buflen - 1; len <= 0 && s < e; s++)
    1758                 /* Control characters are not allowed but >=128 is. */
    1759                 if (!isprint(* (unsigned char *) s) && *s != '\r' &&
    1760                     *s != '\n' && * (unsigned char *) s < 128)
    1761                         len = -1;
    1762                 else if (s[0] == '\n' && s[1] == '\n')
    1763                         len = (int) (s - buf) + 2;
    1764                 else if (s[0] == '\n' && &s[1] < e &&
    1765                     s[1] == '\r' && s[2] == '\n')
    1766                         len = (int) (s - buf) + 3;
    1767 
    1768         return (len);
    1769 }
    1770 
    1771 /*
    1772  * Convert month to the month number. Return -1 on error, or month number
    1773  */
    1774 static int
    1775 montoi(const char *s)
    1776 {
    1777         size_t  i;
    1778 
    1779         for (i = 0; i < sizeof(month_names) / sizeof(month_names[0]); i++)
    1780                 if (!strcmp(s, month_names[i]))
    1781                         return ((int) i);
    1782 
    1783         return (-1);
    1784 }
    1785 
    1786 /*
    1787  * Parse date-time string, and return the corresponding time_t value
    1788  */
    1789 static time_t
    1790 date_to_epoch(const char *s)
    1791 {
    1792         time_t          current_time;
    1793         struct tm       tm, *tmp;
    1794         char            mon[32];
    1795         int             sec, min, hour, mday, month, year;
    1796 
    1797         (void) memset(&tm, 0, sizeof(tm));
    1798         sec = min = hour = mday = month = year = 0;
    1799 
    1800         if (((sscanf(s, "%d/%3s/%d %d:%d:%d",
    1801             &mday, mon, &year, &hour, &min, &sec) == 6) ||
    1802             (sscanf(s, "%d %3s %d %d:%d:%d",
    1803             &mday, mon, &year, &hour, &min, &sec) == 6) ||
    1804             (sscanf(s, "%*3s, %d %3s %d %d:%d:%d",
    1805             &mday, mon, &year, &hour, &min, &sec) == 6) ||
    1806             (sscanf(s, "%d-%3s-%d %d:%d:%d",
    1807             &mday, mon, &year, &hour, &min, &sec) == 6)) &&
    1808             (month = montoi(mon)) != -1) {
    1809                 tm.tm_mday      = mday;
    1810                 tm.tm_mon       = month;
    1811                 tm.tm_year      = year;
    1812                 tm.tm_hour      = hour;
    1813                 tm.tm_min       = min;
    1814                 tm.tm_sec       = sec;
    1815         }
    1816 
    1817         if (tm.tm_year > 1900)
    1818                 tm.tm_year -= 1900;
    1819         else if (tm.tm_year < 70)
    1820                 tm.tm_year += 100;
    1821 
    1822         /* Set Daylight Saving Time field */
    1823         current_time = time(NULL);
    1824         tmp = localtime(&current_time);
    1825         tm.tm_isdst = tmp->tm_isdst;
    1826 
    1827         return (mktime(&tm));
    1828 }
    1829 
    1830 /*
    1831  * Protect against directory disclosure attack by removing '..',
    1832  * excessive '/' and '\' characters
    1833  */
    1834 static void
    1835 remove_double_dots_and_double_slashes(char *s)
    1836 {
    1837         char    *p = s;
    1838 
    1839         while (*s != '\0') {
    1840                 *p++ = *s++;
    1841                 if (s[-1] == '/' || s[-1] == '\\') {
    1842                         /* Skip all following slashes and backslashes */
    1843                         while (*s == '/' || *s == '\\')
    1844                                 s++;
    1845 
    1846                         /* Skip all double-dots */
    1847                         while (*s == '.' && s[1] == '.')
    1848                                 s += 2;
    1849                 }
    1850         }
    1851         *p = '\0';
    1852 }
    1853 
    1854 /*
    1855  * Built-in mime types
    1856  */
    1857 static const struct {
    1858         const char      *extension;
    1859         size_t          ext_len;
    1860         const char      *mime_type;
    1861         size_t          mime_type_len;
    1862 } mime_types[] = {
    1863         {".html",       5,      "text/html",                    9},
    1864         {".htm",        4,      "text/html",                    9},
    1865         {".shtm",       5,      "text/html",                    9},
    1866         {".shtml",      6,      "text/html",                    9},
    1867         {".css",        4,      "text/css",                     8},
    1868         {".js",         3,      "application/x-javascript",     24},
    1869         {".ico",        4,      "image/x-icon",                 12},
    1870         {".gif",        4,      "image/gif",                    9},
    1871         {".jpg",        4,      "image/jpeg",                   10},
    1872         {".jpeg",       5,      "image/jpeg",                   10},
    1873         {".png",        4,      "image/png",                    9},
    1874         {".svg",        4,      "image/svg+xml",                13},
    1875         {".torrent",    8,      "application/x-bittorrent",     24},
    1876         {".wav",        4,      "audio/x-wav",                  11},
    1877         {".mp3",        4,      "audio/x-mp3",                  11},
    1878         {".mid",        4,      "audio/mid",                    9},
    1879         {".m3u",        4,      "audio/x-mpegurl",              15},
    1880         {".ram",        4,      "audio/x-pn-realaudio",         20},
    1881         {".xml",        4,      "text/xml",                     8},
    1882         {".xslt",       5,      "application/xml",              15},
    1883         {".ra",         3,      "audio/x-pn-realaudio",         20},
    1884         {".doc",        4,      "application/msword",           19},
    1885         {".exe",        4,      "application/octet-stream",     24},
    1886         {".zip",        4,      "application/x-zip-compressed", 28},
    1887         {".xls",        4,      "application/excel",            17},
    1888         {".tgz",        4,      "application/x-tar-gz",         20},
    1889         {".tar",        4,      "application/x-tar",            17},
    1890         {".gz",         3,      "application/x-gunzip",         20},
    1891         {".arj",        4,      "application/x-arj-compressed", 28},
    1892         {".rar",        4,      "application/x-arj-compressed", 28},
    1893         {".rtf",        4,      "application/rtf",              15},
    1894         {".pdf",        4,      "application/pdf",              15},
    1895         {".swf",        4,      "application/x-shockwave-flash",29},
    1896         {".mpg",        4,      "video/mpeg",                   10},
    1897         {".mpeg",       5,      "video/mpeg",                   10},
    1898         {".asf",        4,      "video/x-ms-asf",               14},
    1899         {".avi",        4,      "video/x-msvideo",              15},
    1900         {".bmp",        4,      "image/bmp",                    9},
    1901         {NULL,          0,      NULL,                           0}
    1902 };
    1903 
    1904 /*
    1905  * Look at the "path" extension and figure what mime type it has.
    1906  * Store mime type in the vector.
    1907  */
    1908 static void
    1909 get_mime_type(struct mg_context *ctx, const char *path, struct vec *vec)
    1910 {
    1911         struct vec      ext_vec, mime_vec;
    1912         const char      *list, *ext;
    1913         size_t          i, path_len;
    1914 
    1915         path_len = strlen(path);
    1916 
    1917         /*
    1918          * Scan user-defined mime types first, in case user wants to
    1919          * override default mime types.
    1920          */
    1921         lock_option(ctx, OPT_MIME_TYPES);
    1922         list = ctx->options[OPT_MIME_TYPES];
    1923         while ((list = next_option(list, &ext_vec, &mime_vec)) != NULL) {
    1924                 /* ext now points to the path suffix */
    1925                 ext = path + path_len - ext_vec.len;
    1926                 if (mg_strncasecmp(ext, ext_vec.ptr, ext_vec.len) == 0) {
    1927                         *vec = mime_vec;
    1928                         unlock_option(ctx, OPT_MIME_TYPES);
    1929                         return;
    1930                 }
    1931         }
    1932         unlock_option(ctx, OPT_MIME_TYPES);
    1933 
    1934         /* Now scan built-in mime types */
    1935         for (i = 0; mime_types[i].extension != NULL; i++) {
    1936                 ext = path + (path_len - mime_types[i].ext_len);
    1937                 if (path_len > mime_types[i].ext_len &&
    1938                     mg_strcasecmp(ext, mime_types[i].extension) == 0) {
    1939                         vec->ptr = mime_types[i].mime_type;
    1940                         vec->len = mime_types[i].mime_type_len;
    1941                         return;
    1942                 }
    1943         }
    1944 
    1945         /* Nothing found. Fall back to text/plain */
    1946         vec->ptr = "text/plain";
    1947         vec->len = 10;
     1758// Look at the "path" extension and figure what mime type it has.
     1759// Store mime type in the vector.
     1760static void get_mime_type(struct mg_context *ctx, const char *path,
     1761                          struct vec *vec) {
     1762  struct vec ext_vec, mime_vec;
     1763  const char *list, *ext;
     1764  size_t i, path_len;
     1765
     1766  path_len = strlen(path);
     1767
     1768  // Scan user-defined mime types first, in case user wants to
     1769  // override default mime types.
     1770  list = ctx->config[EXTRA_MIME_TYPES];
     1771  while ((list = next_option(list, &ext_vec, &mime_vec)) != NULL) {
     1772    // ext now points to the path suffix
     1773    ext = path + path_len - ext_vec.len;
     1774    if (mg_strncasecmp(ext, ext_vec.ptr, ext_vec.len) == 0) {
     1775      *vec = mime_vec;
     1776      return;
     1777    }
     1778  }
     1779
     1780  // Now scan built-in mime types
     1781  for (i = 0; builtin_mime_types[i].extension != NULL; i++) {
     1782    ext = path + (path_len - builtin_mime_types[i].ext_len);
     1783    if (path_len > builtin_mime_types[i].ext_len &&
     1784        mg_strcasecmp(ext, builtin_mime_types[i].extension) == 0) {
     1785      vec->ptr = builtin_mime_types[i].mime_type;
     1786      vec->len = builtin_mime_types[i].mime_type_len;
     1787      return;
     1788    }
     1789  }
     1790
     1791  // Nothing found. Fall back to "text/plain"
     1792  vec->ptr = "text/plain";
     1793  vec->len = 10;
    19481794}
    19491795
    19501796#ifndef HAVE_MD5
    19511797typedef struct MD5Context {
    1952         uint32_t        buf[4];
    1953         uint32_t        bits[2];
    1954         unsigned char   in[64];
     1798  uint32_t buf[4];
     1799  uint32_t bits[2];
     1800  unsigned char in[64];
    19551801} MD5_CTX;
    19561802
    1957 #if __BYTE_ORDER == 1234
    1958 #define byteReverse(buf, len)   /* Nothing */
     1803#if defined(__BYTE_ORDER) && (__BYTE_ORDER == 1234)
     1804#define byteReverse(buf, len) // Do nothing
    19591805#else
    1960 /*
    1961  * Note: this code is harmless on little-endian machines.
    1962  */
    1963 static void
    1964 byteReverse(unsigned char *buf, unsigned longs)
    1965 {
    1966         uint32_t t;
    1967         do {
    1968                 t = (uint32_t) ((unsigned) buf[3] << 8 | buf[2]) << 16 |
    1969                         ((unsigned) buf[1] << 8 | buf[0]);
    1970                 *(uint32_t *) buf = t;
    1971                 buf += 4;
    1972         } while (--longs);
    1973 }
    1974 #endif /* __BYTE_ORDER */
    1975 
    1976 /* The four core functions - F1 is optimized somewhat */
    1977 
    1978 /* #define F1(x, y, z) (x & y | ~x & z) */
     1806static void byteReverse(unsigned char *buf, unsigned longs) {
     1807  uint32_t t;
     1808  do {
     1809    t = (uint32_t) ((unsigned) buf[3] << 8 | buf[2]) << 16 |
     1810      ((unsigned) buf[1] << 8 | buf[0]);
     1811    *(uint32_t *) buf = t;
     1812    buf += 4;
     1813  } while (--longs);
     1814}
     1815#endif
     1816
    19791817#define F1(x, y, z) (z ^ (x & (y ^ z)))
    19801818#define F2(x, y, z) F1(z, x, y)
     
    19821820#define F4(x, y, z) (y ^ (x | ~z))
    19831821
    1984 /* This is the central step in the MD5 algorithm. */
    19851822#define MD5STEP(f, w, x, y, z, data, s) \
    1986 ( w += f(x, y, z) + data,  w = w<<s | w>>(32-s),  w += x )
    1987 
    1988 /*
    1989  * Start MD5 accumulation.  Set bit count to 0 and buffer to mysterious
    1990  * initialization constants.
    1991  */
    1992 static void
    1993 MD5Init(MD5_CTX *ctx)
    1994 {
    1995         ctx->buf[0] = 0x67452301;
    1996         ctx->buf[1] = 0xefcdab89;
    1997         ctx->buf[2] = 0x98badcfe;
    1998         ctx->buf[3] = 0x10325476;
    1999 
    2000         ctx->bits[0] = 0;
    2001         ctx->bits[1] = 0;
    2002 }
    2003 
    2004 /*
    2005  * The core of the MD5 algorithm, this alters an existing MD5 hash to
    2006  * reflect the addition of 16 longwords of new data.  MD5Update blocks
    2007  * the data and converts bytes into longwords for this routine.
    2008  */
    2009 static void
    2010 MD5Transform(uint32_t buf[4], uint32_t const in[16])
    2011 {
    2012         register uint32_t a, b, c, d;
    2013 
    2014         a = buf[0];
    2015         b = buf[1];
    2016         c = buf[2];
    2017         d = buf[3];
    2018 
    2019         MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7);
    2020         MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12);
    2021         MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17);
    2022         MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22);
    2023         MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7);
    2024         MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12);
    2025         MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17);
    2026         MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22);
    2027         MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7);
    2028         MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12);
    2029         MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17);
    2030         MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22);
    2031         MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7);
    2032         MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12);
    2033         MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17);
    2034         MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22);
    2035 
    2036         MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5);
    2037         MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9);
    2038         MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14);
    2039         MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20);
    2040         MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5);
    2041         MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9);
    2042         MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14);
    2043         MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20);
    2044         MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5);
    2045         MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9);
    2046         MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14);
    2047         MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20);
    2048         MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5);
    2049         MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9);
    2050         MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14);
    2051         MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20);
    2052 
    2053         MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4);
    2054         MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11);
    2055         MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16);
    2056         MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23);
    2057         MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4);
    2058         MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11);
    2059         MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16);
    2060         MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23);
    2061         MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4);
    2062         MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11);
    2063         MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16);
    2064         MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23);
    2065         MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4);
    2066         MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11);
    2067         MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16);
    2068         MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23);
    2069 
    2070         MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6);
    2071         MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10);
    2072         MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15);
    2073         MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21);
    2074         MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6);
    2075         MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10);
    2076         MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15);
    2077         MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21);
    2078         MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6);
    2079         MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10);
    2080         MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15);
    2081         MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21);
    2082         MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6);
    2083         MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10);
    2084         MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15);
    2085         MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21);
    2086 
    2087         buf[0] += a;
    2088         buf[1] += b;
    2089         buf[2] += c;
    2090         buf[3] += d;
    2091 }
    2092 
    2093 /*
    2094  * Update context to reflect the concatenation of another buffer full
    2095  * of bytes.
    2096  */
    2097 static void
    2098 MD5Update(MD5_CTX *ctx, unsigned char const *buf, uint32_t len)
    2099 {
    2100         uint32_t t;
    2101 
    2102         /* Update bitcount */
    2103 
    2104         t = ctx->bits[0];
    2105         if ((ctx->bits[0] = t + (len << 3)) < t)
    2106                 ctx->bits[1]++;         /* Carry from low to high */
    2107         ctx->bits[1] += len >> 29;
    2108 
    2109         t = (t >> 3) & 0x3f;    /* Bytes already in shsInfo->data */
    2110 
    2111         /* Handle any leading odd-sized chunks */
    2112 
    2113         if (t) {
    2114                 unsigned char *p = (unsigned char *) ctx->in + t;
    2115 
    2116                 t = 64 - t;
    2117                 if (len < t) {
    2118                         memcpy(p, buf, len);
    2119                         return;
    2120                 }
    2121                 memcpy(p, buf, t);
    2122                 byteReverse(ctx->in, 16);
    2123                 MD5Transform(ctx->buf, (uint32_t *) ctx->in);
    2124                 buf += t;
    2125                 len -= t;
    2126         }
    2127         /* Process data in 64-byte chunks */
    2128 
    2129         while (len >= 64) {
    2130                 memcpy(ctx->in, buf, 64);
    2131                 byteReverse(ctx->in, 16);
    2132                 MD5Transform(ctx->buf, (uint32_t *) ctx->in);
    2133                 buf += 64;
    2134                 len -= 64;
    2135         }
    2136 
    2137         /* Handle any remaining bytes of data. */
    2138 
    2139         memcpy(ctx->in, buf, len);
    2140 }
    2141 
    2142 /*
    2143  * Final wrapup - pad to 64-byte boundary with the bit pattern
    2144  * 1 0* (64-bit count of bits processed, MSB-first)
    2145  */
    2146 static void
    2147 MD5Final(unsigned char digest[16], MD5_CTX *ctx)
    2148 {
    2149         unsigned count;
    2150         unsigned char *p;
    2151 
    2152         /* Compute number of bytes mod 64 */
    2153         count = (ctx->bits[0] >> 3) & 0x3F;
    2154 
    2155         /* Set the first char of padding to 0x80.  This is safe since there is
    2156            always at least one byte free */
    2157         p = ctx->in + count;
    2158         *p++ = 0x80;
    2159 
    2160         /* Bytes of padding needed to make 64 bytes */
    2161         count = 64 - 1 - count;
    2162 
    2163         /* Pad out to 56 mod 64 */
    2164         if (count < 8) {
    2165                 /* Two lots of padding:  Pad the first block to 64 bytes */
    2166                 memset(p, 0, count);
    2167                 byteReverse(ctx->in, 16);
    2168                 MD5Transform(ctx->buf, (uint32_t *) ctx->in);
    2169 
    2170                 /* Now fill the next block with 56 bytes */
    2171                 memset(ctx->in, 0, 56);
    2172         } else {
    2173                 /* Pad block to 56 bytes */
    2174                 memset(p, 0, count - 8);
    2175         }
    2176         byteReverse(ctx->in, 14);
    2177 
    2178         /* Append length in bits and transform */
    2179         ((uint32_t *) ctx->in)[14] = ctx->bits[0];
    2180         ((uint32_t *) ctx->in)[15] = ctx->bits[1];
    2181 
    2182         MD5Transform(ctx->buf, (uint32_t *) ctx->in);
    2183         byteReverse((unsigned char *) ctx->buf, 4);
    2184         memcpy(digest, ctx->buf, 16);
    2185         memset((char *) ctx, 0, sizeof(ctx));   /* In case it's sensitive */
    2186 }
    2187 #endif /* !HAVE_MD5 */
    2188 
    2189 /*
    2190  * Stringify binary data. Output buffer must be twice as big as input,
    2191  * because each byte takes 2 bytes in string representation
    2192  */
    2193 static void
    2194 bin2str(char *to, const unsigned char *p, size_t len)
    2195 {
    2196         static const char *hex = "0123456789abcdef";
    2197 
    2198         for (; len--; p++) {
    2199                 *to++ = hex[p[0] >> 4];
    2200                 *to++ = hex[p[0] & 0x0f];
    2201         }
    2202         *to = '\0';
    2203 }
    2204 
    2205 /*
    2206  * Return stringified MD5 hash for list of vectors.
    2207  * buf must point to 33-bytes long buffer
    2208  */
    2209 static void
    2210 mg_md5(char *buf, ...)
    2211 {
    2212         unsigned char   hash[16];
    2213         const char      *p;
    2214         va_list         ap;
    2215         MD5_CTX         ctx;
    2216 
    2217         MD5Init(&ctx);
    2218 
    2219         va_start(ap, buf);
    2220         while ((p = va_arg(ap, const char *)) != NULL)
    2221                 MD5Update(&ctx, (unsigned char *) p, strlen(p));
    2222         va_end(ap);
    2223 
    2224         MD5Final(hash, &ctx);
    2225         bin2str(buf, hash, sizeof(hash));
    2226 }
    2227 
    2228 /*
    2229  * Check the user's password, return 1 if OK
    2230  */
    2231 static bool_t
    2232 check_password(const char *method, const char *ha1, const char *uri,
    2233                 const char *nonce, const char *nc, const char *cnonce,
    2234                 const char *qop, const char *response)
    2235 {
    2236         char    ha2[32 + 1], expected_response[32 + 1];
    2237 
    2238         /* XXX  Due to a bug in MSIE, we do not compare the URI  */
    2239         /* Also, we do not check for authentication timeout */
    2240         if (/*strcmp(dig->uri, c->ouri) != 0 || */
    2241             strlen(response) != 32 /*||
    2242             now - strtoul(dig->nonce, NULL, 10) > 3600 */)
    2243                 return (FALSE);
    2244 
    2245         mg_md5(ha2, method, ":", uri, NULL);
    2246         mg_md5(expected_response, ha1, ":", nonce, ":", nc,
    2247             ":", cnonce, ":", qop, ":", ha2, NULL);
    2248 
    2249         return (!mg_strcasecmp(response, expected_response));
    2250 }
    2251 
    2252 /*
    2253  * Use the global passwords file, if specified by auth_gpass option,
    2254  * or search for .htpasswd in the requested directory.
    2255  */
    2256 static FILE *
    2257 open_auth_file(struct mg_connection *conn, const char *path)
    2258 {
    2259         struct mg_context       *ctx = conn->ctx;
    2260         char                    name[FILENAME_MAX];
    2261         const char              *p, *e;
    2262         struct mgstat           st;
    2263         FILE                    *fp;
    2264 
    2265         if (ctx->options[OPT_AUTH_GPASSWD] != NULL) {
    2266                 /* Use global passwords file */
    2267                 fp =  mg_fopen(ctx->options[OPT_AUTH_GPASSWD], "r");
    2268                 if (fp == NULL)
    2269                         cry(fc(ctx), "fopen(%s): %s",
    2270                             ctx->options[OPT_AUTH_GPASSWD], strerror(ERRNO));
    2271         } else if (!mg_stat(path, &st) && st.is_directory) {
    2272                 (void) mg_snprintf(conn, name, sizeof(name), "%s%c%s",
    2273                     path, DIRSEP, PASSWORDS_FILE_NAME);
    2274                 fp = mg_fopen(name, "r");
    2275         } else {
    2276                 /*
    2277                  * Try to find .htpasswd in requested directory.
    2278                  * Given the path, create the path to .htpasswd file
    2279                  * in the same directory. Find the right-most
    2280                  * directory separator character first. That would be the
    2281                  * directory name. If directory separator character is not
    2282                  * found, 'e' will point to 'p'.
    2283                  */
    2284                 for (p = path, e = p + strlen(p) - 1; e > p; e--)
    2285                         if (IS_DIRSEP_CHAR(*e))
    2286                                 break;
    2287 
    2288                 /*
    2289                  * Make up the path by concatenating directory name and
    2290                  * .htpasswd file name.
    2291                  */
    2292                 (void) mg_snprintf(conn, name, sizeof(name), "%.*s%c%s",
    2293                     (int) (e - p), p, DIRSEP, PASSWORDS_FILE_NAME);
    2294                 fp = mg_fopen(name, "r");
    2295         }
    2296 
    2297         return (fp);
    2298 }
    2299 
    2300 /*
    2301  * Parsed Authorization: header
    2302  */
     1823  ( w += f(x, y, z) + data,  w = w<<s | w>>(32-s),  w += x )
     1824
     1825// Start MD5 accumulation.  Set bit count to 0 and buffer to mysterious
     1826// initialization constants.
     1827static void MD5Init(MD5_CTX *ctx) {
     1828  ctx->buf[0] = 0x67452301;
     1829  ctx->buf[1] = 0xefcdab89;
     1830  ctx->buf[2] = 0x98badcfe;
     1831  ctx->buf[3] = 0x10325476;
     1832
     1833  ctx->bits[0] = 0;
     1834  ctx->bits[1] = 0;
     1835}
     1836
     1837static void MD5Transform(uint32_t buf[4], uint32_t const in[16]) {
     1838  register uint32_t a, b, c, d;
     1839
     1840  a = buf[0];
     1841  b = buf[1];
     1842  c = buf[2];
     1843  d = buf[3];
     1844
     1845  MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7);
     1846  MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12);
     1847  MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17);
     1848  MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22);
     1849  MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7);
     1850  MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12);
     1851  MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17);
     1852  MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22);
     1853  MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7);
     1854  MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12);
     1855  MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17);
     1856  MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22);
     1857  MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7);
     1858  MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12);
     1859  MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17);
     1860  MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22);
     1861
     1862  MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5);
     1863  MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9);
     1864  MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14);
     1865  MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20);
     1866  MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5);
     1867  MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9);
     1868  MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14);
     1869  MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20);
     1870  MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5);
     1871  MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9);
     1872  MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14);
     1873  MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20);
     1874  MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5);
     1875  MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9);
     1876  MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14);
     1877  MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20);
     1878
     1879  MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4);
     1880  MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11);
     1881  MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16);
     1882  MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23);
     1883  MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4);
     1884  MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11);
     1885  MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16);
     1886  MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23);
     1887  MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4);
     1888  MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11);
     1889  MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16);
     1890  MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23);
     1891  MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4);
     1892  MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11);
     1893  MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16);
     1894  MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23);
     1895
     1896  MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6);
     1897  MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10);
     1898  MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15);
     1899  MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21);
     1900  MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6);
     1901  MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10);
     1902  MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15);
     1903  MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21);
     1904  MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6);
     1905  MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10);
     1906  MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15);
     1907  MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21);
     1908  MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6);
     1909  MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10);
     1910  MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15);
     1911  MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21);
     1912
     1913  buf[0] += a;
     1914  buf[1] += b;
     1915  buf[2] += c;
     1916  buf[3] += d;
     1917}
     1918
     1919static void MD5Update(MD5_CTX *ctx, unsigned char const *buf, unsigned len) {
     1920  uint32_t t;
     1921
     1922  t = ctx->bits[0];
     1923  if ((ctx->bits[0] = t + ((uint32_t) len << 3)) < t)
     1924    ctx->bits[1]++;
     1925  ctx->bits[1] += len >> 29;
     1926
     1927  t = (t >> 3) & 0x3f;
     1928
     1929  if (t) {
     1930    unsigned char *p = (unsigned char *) ctx->in + t;
     1931
     1932    t = 64 - t;
     1933    if (len < t) {
     1934      memcpy(p, buf, len);
     1935      return;
     1936    }
     1937    memcpy(p, buf, t);
     1938    byteReverse(ctx->in, 16);
     1939    MD5Transform(ctx->buf, (uint32_t *) ctx->in);
     1940    buf += t;
     1941    len -= t;
     1942  }
     1943
     1944  while (len >= 64) {
     1945    memcpy(ctx->in, buf, 64);
     1946    byteReverse(ctx->in, 16);
     1947    MD5Transform(ctx->buf, (uint32_t *) ctx->in);
     1948    buf += 64;
     1949    len -= 64;
     1950  }
     1951
     1952  memcpy(ctx->in, buf, len);
     1953}
     1954
     1955static void MD5Final(unsigned char digest[16], MD5_CTX *ctx) {
     1956  unsigned count;
     1957  unsigned char *p;
     1958
     1959  count = (ctx->bits[0] >> 3) & 0x3F;
     1960
     1961  p = ctx->in + count;
     1962  *p++ = 0x80;
     1963  count = 64 - 1 - count;
     1964  if (count < 8) {
     1965    memset(p, 0, count);
     1966    byteReverse(ctx->in, 16);
     1967    MD5Transform(ctx->buf, (uint32_t *) ctx->in);
     1968    memset(ctx->in, 0, 56);
     1969  } else {
     1970    memset(p, 0, count - 8);
     1971  }
     1972  byteReverse(ctx->in, 14);
     1973
     1974  ((uint32_t *) ctx->in)[14] = ctx->bits[0];
     1975  ((uint32_t *) ctx->in)[15] = ctx->bits[1];
     1976
     1977  MD5Transform(ctx->buf, (uint32_t *) ctx->in);
     1978  byteReverse((unsigned char *) ctx->buf, 4);
     1979  memcpy(digest, ctx->buf, 16);
     1980  memset((char *) ctx, 0, sizeof(*ctx));
     1981}
     1982#endif // !HAVE_MD5
     1983
     1984// Stringify binary data. Output buffer must be twice as big as input,
     1985// because each byte takes 2 bytes in string representation
     1986static void bin2str(char *to, const unsigned char *p, size_t len) {
     1987  static const char *hex = "0123456789abcdef";
     1988
     1989  for (; len--; p++) {
     1990    *to++ = hex[p[0] >> 4];
     1991    *to++ = hex[p[0] & 0x0f];
     1992  }
     1993  *to = '\0';
     1994}
     1995
     1996// Return stringified MD5 hash for list of vectors. Buffer must be 33 bytes.
     1997void mg_md5(char *buf, ...) {
     1998  unsigned char hash[16];
     1999  const char *p;
     2000  va_list ap;
     2001  MD5_CTX ctx;
     2002
     2003  MD5Init(&ctx);
     2004
     2005  va_start(ap, buf);
     2006  while ((p = va_arg(ap, const char *)) != NULL) {
     2007    MD5Update(&ctx, (const unsigned char *) p, (unsigned) strlen(p));
     2008  }
     2009  va_end(ap);
     2010
     2011  MD5Final(hash, &ctx);
     2012  bin2str(buf, hash, sizeof(hash));
     2013}
     2014
     2015// Check the user's password, return 1 if OK
     2016static int check_password(const char *method, const char *ha1, const char *uri,
     2017                          const char *nonce, const char *nc, const char *cnonce,
     2018                          const char *qop, const char *response) {
     2019  char ha2[32 + 1], expected_response[32 + 1];
     2020
     2021  // Some of the parameters may be NULL
     2022  if (method == NULL || nonce == NULL || nc == NULL || cnonce == NULL ||
     2023      qop == NULL || response == NULL) {
     2024    return 0;
     2025  }
     2026
     2027  // NOTE(lsm): due to a bug in MSIE, we do not compare the URI
     2028  // TODO(lsm): check for authentication timeout
     2029  if (// strcmp(dig->uri, c->ouri) != 0 ||
     2030      strlen(response) != 32
     2031      // || now - strtoul(dig->nonce, NULL, 10) > 3600
     2032      ) {
     2033    return 0;
     2034  }
     2035
     2036  mg_md5(ha2, method, ":", uri, NULL);
     2037  mg_md5(expected_response, ha1, ":", nonce, ":", nc,
     2038      ":", cnonce, ":", qop, ":", ha2, NULL);
     2039
     2040  return mg_strcasecmp(response, expected_response) == 0;
     2041}
     2042
     2043// Use the global passwords file, if specified by auth_gpass option,
     2044// or search for .htpasswd in the requested directory.
     2045static FILE *open_auth_file(struct mg_connection *conn, const char *path) {
     2046  struct mg_context *ctx = conn->ctx;
     2047  char name[PATH_MAX];
     2048  const char *p, *e;
     2049  struct mgstat st;
     2050  FILE *fp;
     2051
     2052  if (ctx->config[GLOBAL_PASSWORDS_FILE] != NULL) {
     2053    // Use global passwords file
     2054    fp =  mg_fopen(ctx->config[GLOBAL_PASSWORDS_FILE], "r");
     2055    if (fp == NULL)
     2056      cry(fc(ctx), "fopen(%s): %s",
     2057          ctx->config[GLOBAL_PASSWORDS_FILE], strerror(ERRNO));
     2058  } else if (!mg_stat(path, &st) && st.is_directory) {
     2059    (void) mg_snprintf(conn, name, sizeof(name), "%s%c%s",
     2060        path, DIRSEP, PASSWORDS_FILE_NAME);
     2061    fp = mg_fopen(name, "r");
     2062  } else {
     2063     // Try to find .htpasswd in requested directory.
     2064    for (p = path, e = p + strlen(p) - 1; e > p; e--)
     2065      if (IS_DIRSEP_CHAR(*e))
     2066        break;
     2067    (void) mg_snprintf(conn, name, sizeof(name), "%.*s%c%s",
     2068        (int) (e - p), p, DIRSEP, PASSWORDS_FILE_NAME);
     2069    fp = mg_fopen(name, "r");
     2070  }
     2071
     2072  return fp;
     2073}
     2074
     2075// Parsed Authorization header
    23032076struct ah {
    2304         char    *user, *uri, *cnonce, *response, *qop, *nc, *nonce;
     2077  char *user, *uri, *cnonce, *response, *qop, *nc, *nonce;
    23052078};
    23062079
    2307 static bool_t
    2308 parse_auth_header(struct mg_connection *conn, char *buf, size_t buf_size,
    2309                 struct ah *ah)
    2310 {
    2311         char            *name, *value, *s;
    2312         const char      *auth_header;
    2313 
    2314         if ((auth_header = mg_get_header(conn, "Authorization")) == NULL ||
    2315             mg_strncasecmp(auth_header, "Digest ", 7) != 0)
    2316                 return (FALSE);
    2317 
    2318         /* Make modifiable copy of the auth header */
    2319         (void) mg_strlcpy(buf, auth_header + 7, buf_size);
    2320 
    2321         s = buf;
    2322         (void) memset(ah, 0, sizeof(*ah));
    2323 
    2324         /* Gobble initial spaces */
    2325         while (isspace(* (unsigned char *) s))
    2326                 s++;
    2327 
    2328         /* Parse authorization header */
    2329         for (;;) {
    2330                 name = skip(&s, "=");
    2331                 value = skip(&s, ", ");
    2332 
    2333                 if (*value == '"') {
    2334                         value++;
    2335                         value[strlen(value) - 1] = '\0';
    2336                 } else if (*value == '\0') {
    2337                         break;
    2338                 }
    2339 
    2340                 if (!strcmp(name, "username")) {
    2341                         ah->user = value;
    2342                 } else if (!strcmp(name, "cnonce")) {
    2343                         ah->cnonce = value;
    2344                 } else if (!strcmp(name, "response")) {
    2345                         ah->response = value;
    2346                 } else if (!strcmp(name, "uri")) {
    2347                         ah->uri = value;
    2348                 } else if (!strcmp(name, "qop")) {
    2349                         ah->qop = value;
    2350                 } else if (!strcmp(name, "nc")) {
    2351                         ah->nc = value;
    2352                 } else if (!strcmp(name, "nonce")) {
    2353                         ah->nonce = value;
    2354                 }
    2355         }
    2356 
    2357         /* CGI needs it as REMOTE_USER */
    2358         if (ah->user != NULL)
    2359                 conn->request_info.remote_user = mg_strdup(ah->user);
    2360 
    2361         return (TRUE);
    2362 }
    2363 
    2364 /*
    2365  * Authorize against the opened passwords file. Return 1 if authorized.
    2366  */
    2367 static bool_t
    2368 authorize(struct mg_connection *conn, FILE *fp)
    2369 {
    2370         struct ah       ah;
    2371         char            line[256], f_user[256], domain[256], ha1[256],
    2372                         buf[MAX_REQUEST_SIZE];
    2373 
    2374         if (!parse_auth_header(conn, buf, sizeof(buf), &ah))
    2375                 return (FALSE);
    2376 
    2377         /* Loop over passwords file */
    2378         while (fgets(line, sizeof(line), fp) != NULL) {
    2379 
    2380                 if (sscanf(line, "%[^:]:%[^:]:%s", f_user, domain, ha1) != 3)
    2381                         continue;
    2382 
    2383                 if (!strcmp(ah.user, f_user) &&
    2384                     !strcmp(domain, conn->ctx->options[OPT_AUTH_DOMAIN]))
    2385                         return (check_password(
    2386                             conn->request_info.request_method, ha1,
    2387                             ah.uri, ah.nonce, ah.nc, ah.cnonce,
    2388                             ah.qop, ah.response));
    2389         }
    2390 
    2391         return (FALSE);
    2392 }
    2393 
    2394 /*
    2395  * Return TRUE if request is authorised, FALSE otherwise.
    2396  */
    2397 static bool_t
    2398 check_authorization(struct mg_connection *conn, const char *path)
    2399 {
    2400         FILE            *fp;
    2401         char            fname[FILENAME_MAX];
    2402         struct vec      uri_vec, filename_vec;
    2403         const char      *list;
    2404         bool_t          authorized;
    2405 
    2406         fp = NULL;
    2407         authorized = TRUE;
    2408 
    2409         lock_option(conn->ctx, OPT_PROTECT);
    2410         list = conn->ctx->options[OPT_PROTECT];
    2411         while ((list = next_option(list, &uri_vec, &filename_vec)) != NULL) {
    2412                 if (!memcmp(conn->request_info.uri, uri_vec.ptr, uri_vec.len)) {
    2413                         (void) mg_snprintf(conn, fname, sizeof(fname), "%.*s",
    2414                             filename_vec.len, filename_vec.ptr);
    2415                         if ((fp = mg_fopen(fname, "r")) == NULL)
    2416                                 cry(conn, "%s: cannot open %s: %s",
    2417                                     __func__, fname, strerror(errno));
    2418                         break;
    2419                 }
    2420         }
    2421         unlock_option(conn->ctx, OPT_PROTECT);
    2422 
    2423         if (fp == NULL)
    2424                 fp = open_auth_file(conn, path);
    2425 
    2426         if (fp != NULL) {
    2427                 authorized = authorize(conn, fp);
    2428                 (void) fclose(fp);
    2429         }
    2430 
    2431         return (authorized);
    2432 }
    2433 
    2434 static void
    2435 send_authorization_request(struct mg_connection *conn)
    2436 {
    2437         conn->request_info.status_code = 401;
    2438         (void) mg_printf(conn,
    2439             "HTTP/1.1 401 Unauthorized\r\n"
    2440             "WWW-Authenticate: Digest qop=\"auth\", "
    2441             "realm=\"%s\", nonce=\"%lu\"\r\n\r\n",
    2442             conn->ctx->options[OPT_AUTH_DOMAIN], (unsigned long) time(NULL));
    2443 }
    2444 
    2445 static bool_t
    2446 is_authorized_for_put(struct mg_connection *conn)
    2447 {
    2448         FILE    *fp;
    2449         int     ret = FALSE;
    2450 
    2451         if ((fp = mg_fopen(conn->ctx->options[OPT_AUTH_PUT], "r")) != NULL) {
    2452                 set_close_on_exec(fileno(fp));
    2453                 ret = authorize(conn, fp);
    2454                 (void) fclose(fp);
    2455         }
    2456 
    2457         return (ret);
    2458 }
    2459 
    2460 int
    2461 mg_modify_passwords_file(struct mg_context *ctx, const char *fname,
    2462                 const char *user, const char *pass)
    2463 {
    2464         int             found;
    2465         char            line[512], u[512], d[512], ha1[33], tmp[FILENAME_MAX];
    2466         const char      *domain;
    2467         FILE            *fp, *fp2;
    2468 
    2469         found = 0;
    2470         fp = fp2 = NULL;
    2471         domain = ctx->options[OPT_AUTH_DOMAIN];
    2472 
    2473         /* Regard empty password as no password - remove user record. */
    2474         if (pass[0] == '\0')
    2475                 pass = NULL;
    2476 
    2477         (void) snprintf(tmp, sizeof(tmp), "%s.tmp", fname);
    2478 
    2479         /* Create the file if does not exist */
    2480         if ((fp = mg_fopen(fname, "a+")) != NULL)
    2481                 (void) fclose(fp);
    2482 
    2483         /* Open the given file and temporary file */
    2484         if ((fp = mg_fopen(fname, "r")) == NULL) {
    2485                 cry(fc(ctx), "Cannot open %s: %s", fname, strerror(errno));
    2486                 return (0);
    2487         } else if ((fp2 = mg_fopen(tmp, "w+")) == NULL) {
    2488                 cry(fc(ctx), "Cannot open %s: %s", tmp, strerror(errno));
    2489                 return (0);
    2490         }
    2491 
    2492         /* Copy the stuff to temporary file */
    2493         while (fgets(line, sizeof(line), fp) != NULL) {
    2494 
    2495                 if (sscanf(line, "%[^:]:%[^:]:%*s", u, d) != 2)
    2496                         continue;
    2497 
    2498                 if (!strcmp(u, user) && !strcmp(d, domain)) {
    2499                         found++;
    2500                         if (pass != NULL) {
    2501                                 mg_md5(ha1, user, ":", domain, ":", pass, NULL);
    2502                                 fprintf(fp2, "%s:%s:%s\n", user, domain, ha1);
    2503                         }
    2504                 } else {
    2505                         (void) fprintf(fp2, "%s", line);
    2506                 }
    2507         }
    2508 
    2509         /* If new user, just add it */
    2510         if (!found && pass != NULL) {
    2511                 mg_md5(ha1, user, ":", domain, ":", pass, NULL);
    2512                 (void) fprintf(fp2, "%s:%s:%s\n", user, domain, ha1);
    2513         }
    2514 
    2515         /* Close files */
    2516         (void) fclose(fp);
    2517         (void) fclose(fp2);
    2518 
    2519         /* Put the temp file in place of real file */
    2520         (void) mg_remove(fname);
    2521         (void) mg_rename(tmp, fname);
    2522 
    2523         return (0);
     2080static int parse_auth_header(struct mg_connection *conn, char *buf,
     2081                             size_t buf_size, struct ah *ah) {
     2082  char *name, *value, *s;
     2083  const char *auth_header;
     2084
     2085  if ((auth_header = mg_get_header(conn, "Authorization")) == NULL ||
     2086      mg_strncasecmp(auth_header, "Digest ", 7) != 0) {
     2087    return 0;
     2088  }
     2089
     2090  // Make modifiable copy of the auth header
     2091  (void) mg_strlcpy(buf, auth_header + 7, buf_size);
     2092
     2093  s = buf;
     2094  (void) memset(ah, 0, sizeof(*ah));
     2095
     2096  // Parse authorization header
     2097  for (;;) {
     2098    // Gobble initial spaces
     2099    while (isspace(* (unsigned char *) s)) {
     2100      s++;
     2101    }
     2102    name = skip_quoted(&s, "=", " ", 0);
     2103    // Value is either quote-delimited, or ends at first comma or space.
     2104    if (s[0] == '\"') {
     2105      s++;
     2106      value = skip_quoted(&s, "\"", " ", '\\');
     2107      if (s[0] == ',') {
     2108        s++;
     2109      }
     2110    } else {
     2111      value = skip_quoted(&s, ", ", " ", 0);  // IE uses commas, FF uses spaces
     2112    }
     2113    if (*name == '\0') {
     2114      break;
     2115    }
     2116
     2117    if (!strcmp(name, "username")) {
     2118      ah->user = value;
     2119    } else if (!strcmp(name, "cnonce")) {
     2120      ah->cnonce = value;
     2121    } else if (!strcmp(name, "response")) {
     2122      ah->response = value;
     2123    } else if (!strcmp(name, "uri")) {
     2124      ah->uri = value;
     2125    } else if (!strcmp(name, "qop")) {
     2126      ah->qop = value;
     2127    } else if (!strcmp(name, "nc")) {
     2128      ah->nc = value;
     2129    } else if (!strcmp(name, "nonce")) {
     2130      ah->nonce = value;
     2131    }
     2132  }
     2133
     2134  // CGI needs it as REMOTE_USER
     2135  if (ah->user != NULL) {
     2136    conn->request_info.remote_user = mg_strdup(ah->user);
     2137  } else {
     2138    return 0;
     2139  }
     2140
     2141  return 1;
     2142}
     2143
     2144// Authorize against the opened passwords file. Return 1 if authorized.
     2145static int authorize(struct mg_connection *conn, FILE *fp) {
     2146  struct ah ah;
     2147  char line[256], f_user[256], ha1[256], f_domain[256], buf[BUFSIZ];
     2148
     2149  if (!parse_auth_header(conn, buf, sizeof(buf), &ah)) {
     2150    return 0;
     2151  }
     2152
     2153  // Loop over passwords file
     2154  while (fgets(line, sizeof(line), fp) != NULL) {
     2155    if (sscanf(line, "%[^:]:%[^:]:%s", f_user, f_domain, ha1) != 3) {
     2156      continue;
     2157    }
     2158
     2159    if (!strcmp(ah.user, f_user) &&
     2160        !strcmp(conn->ctx->config[AUTHENTICATION_DOMAIN], f_domain))
     2161      return check_password(
     2162            conn->request_info.request_method,
     2163            ha1, ah.uri, ah.nonce, ah.nc, ah.cnonce, ah.qop,
     2164            ah.response);
     2165  }
     2166
     2167  return 0;
     2168}
     2169
     2170// Return 1 if request is authorised, 0 otherwise.
     2171static int check_authorization(struct mg_connection *conn, const char *path) {
     2172  FILE *fp;
     2173  char fname[PATH_MAX];
     2174  struct vec uri_vec, filename_vec;
     2175  const char *list;
     2176  int authorized;
     2177
     2178  fp = NULL;
     2179  authorized = 1;
     2180
     2181  list = conn->ctx->config[PROTECT_URI];
     2182  while ((list = next_option(list, &uri_vec, &filename_vec)) != NULL) {
     2183    if (!memcmp(conn->request_info.uri, uri_vec.ptr, uri_vec.len)) {
     2184      (void) mg_snprintf(conn, fname, sizeof(fname), "%.*s",
     2185          filename_vec.len, filename_vec.ptr);
     2186      if ((fp = mg_fopen(fname, "r")) == NULL) {
     2187        cry(conn, "%s: cannot open %s: %s", __func__, fname, strerror(errno));
     2188      }
     2189      break;
     2190    }
     2191  }
     2192
     2193  if (fp == NULL) {
     2194    fp = open_auth_file(conn, path);
     2195  }
     2196
     2197  if (fp != NULL) {
     2198    authorized = authorize(conn, fp);
     2199    (void) fclose(fp);
     2200  }
     2201
     2202  return authorized;
     2203}
     2204
     2205static void send_authorization_request(struct mg_connection *conn) {
     2206  conn->request_info.status_code = 401;
     2207  (void) mg_printf(conn,
     2208      "HTTP/1.1 401 Unauthorized\r\n"
     2209      "Content-Length: 0\r\n"
     2210      "WWW-Authenticate: Digest qop=\"auth\", "
     2211      "realm=\"%s\", nonce=\"%lu\"\r\n\r\n",
     2212      conn->ctx->config[AUTHENTICATION_DOMAIN],
     2213      (unsigned long) time(NULL));
     2214}
     2215
     2216static int is_authorized_for_put(struct mg_connection *conn) {
     2217  FILE *fp;
     2218  int ret = 0;
     2219
     2220  fp = conn->ctx->config[PUT_DELETE_PASSWORDS_FILE] == NULL ? NULL :
     2221    mg_fopen(conn->ctx->config[PUT_DELETE_PASSWORDS_FILE], "r");
     2222
     2223  if (fp != NULL) {
     2224    ret = authorize(conn, fp);
     2225    (void) fclose(fp);
     2226  }
     2227
     2228  return ret;
     2229}
     2230
     2231int mg_modify_passwords_file(const char *fname, const char *domain,
     2232                             const char *user, const char *pass) {
     2233  int found;
     2234  char line[512], u[512], d[512], ha1[33], tmp[PATH_MAX];
     2235  FILE *fp, *fp2;
     2236
     2237  found = 0;
     2238  fp = fp2 = NULL;
     2239
     2240  // Regard empty password as no password - remove user record.
     2241  if (pass != NULL && pass[0] == '\0') {
     2242    pass = NULL;
     2243  }
     2244
     2245  (void) snprintf(tmp, sizeof(tmp), "%s.tmp", fname);
     2246
     2247  // Create the file if does not exist
     2248  if ((fp = mg_fopen(fname, "a+")) != NULL) {
     2249    (void) fclose(fp);
     2250  }
     2251
     2252  // Open the given file and temporary file
     2253  if ((fp = mg_fopen(fname, "r")) == NULL) {
     2254    return 0;
     2255  } else if ((fp2 = mg_fopen(tmp, "w+")) == NULL) {
     2256    fclose(fp);
     2257    return 0;
     2258  }
     2259
     2260  // Copy the stuff to temporary file
     2261  while (fgets(line, sizeof(line), fp) != NULL) {
     2262    if (sscanf(line, "%[^:]:%[^:]:%*s", u, d) != 2) {
     2263      continue;
     2264    }
     2265
     2266    if (!strcmp(u, user) && !strcmp(d, domain)) {
     2267      found++;
     2268      if (pass != NULL) {
     2269        mg_md5(ha1, user, ":", domain, ":", pass, NULL);
     2270        fprintf(fp2, "%s:%s:%s\n", user, domain, ha1);
     2271      }
     2272    } else {
     2273      (void) fprintf(fp2, "%s", line);
     2274    }
     2275  }
     2276
     2277  // If new user, just add it
     2278  if (!found && pass != NULL) {
     2279    mg_md5(ha1, user, ":", domain, ":", pass, NULL);
     2280    (void) fprintf(fp2, "%s:%s:%s\n", user, domain, ha1);
     2281  }
     2282
     2283  // Close files
     2284  (void) fclose(fp);
     2285  (void) fclose(fp2);
     2286
     2287  // Put the temp file in place of real file
     2288  (void) mg_remove(fname);
     2289  (void) mg_rename(tmp, fname);
     2290
     2291  return 1;
    25242292}
    25252293
    25262294struct de {
    2527         struct mg_connection    *conn;
    2528         char                    *file_name;
    2529         struct mgstat           st;
     2295  struct mg_connection *conn;
     2296  char *file_name;
     2297  struct mgstat st;
    25302298};
    25312299
    2532 static void
    2533 url_encode(const char *src, char *dst, size_t dst_len)
    2534 {
    2535         const char      *dont_escape = "._-$,;~()";
    2536         const char      *hex = "0123456789abcdef";
    2537         const char      *end = dst + dst_len - 1;
    2538        
    2539         for (; *src != '\0' && dst < end; src++, dst++) {
    2540                 if (isalnum(*(unsigned char *) src) ||
    2541                     strchr(dont_escape, * (unsigned char *) src) != NULL) {
    2542                         *dst = *src;
    2543                 } else if (dst + 2 < end) {
    2544                         dst[0] = '%';
    2545                         dst[1] = hex[(* (unsigned char *) src) >> 4];
    2546                         dst[2] = hex[(* (unsigned char *) src) & 0xf];
    2547                         dst += 2;
    2548                 }
    2549         }
    2550 
    2551         *dst = '\0';
    2552 }
    2553 
    2554 /*
    2555  * This function is called from send_directory() and prints out
    2556  * single directory entry.
    2557  */
    2558 static void
    2559 print_dir_entry(struct de *de)
    2560 {
    2561         char            size[64], mod[64], href[FILENAME_MAX];
    2562 
    2563         if (de->st.is_directory) {
    2564                 (void) mg_snprintf(de->conn,
    2565                     size, sizeof(size), "%s", "[DIRECTORY]");
    2566         } else {
    2567                 /*
    2568                  * We use (signed) cast below because MSVC 6 compiler cannot
    2569                  * convert unsigned __int64 to double. Sigh.
    2570                  */
    2571                 if (de->st.size < 1024)
    2572                         (void) mg_snprintf(de->conn, size, sizeof(size),
    2573                             "%lu", (unsigned long) de->st.size);
    2574                 else if (de->st.size < 0x100000 /* 1024 * 1024 */)
    2575                         (void) mg_snprintf(de->conn, size, sizeof(size),
    2576                             "%.1fk", (double) de->st.size / 1024.0);
    2577                 else if (de->st.size < 0x40000000 /* 1024 * 1024 * 1024 */)
    2578                         (void) mg_snprintf(de->conn, size, sizeof(size),
    2579                             "%.1fM", (double) de->st.size / 1048576);
    2580                 else
    2581                         (void) mg_snprintf(de->conn, size, sizeof(size),
    2582                           "%.1fG", (double) de->st.size / 1073741824);
    2583         }
    2584         (void) strftime(mod, sizeof(mod), "%d-%b-%Y %H:%M",
    2585                 localtime(&de->st.mtime));
    2586 
    2587         url_encode(de->file_name, href, sizeof(href));
    2588 
    2589         de->conn->num_bytes_sent += mg_printf(de->conn,
    2590             "<tr><td><a href=\"%s%s%s\">%s%s</a></td>"
    2591             "<td>&nbsp;%s</td><td>&nbsp;&nbsp;%s</td></tr>\n",
    2592             de->conn->request_info.uri, href, de->st.is_directory ? "/" : "",
    2593             de->file_name, de->st.is_directory ? "/" : "", mod, size);
    2594 }
    2595 
    2596 /*
    2597  * This function is called from send_directory() and used for
    2598  * sorting direcotory entries by size, or name, or modification time.
    2599  */
    2600 static int
    2601 compare_dir_entries(const void *p1, const void *p2)
    2602 {
    2603         const struct de *a = (struct de *) p1, *b = (struct de *) p2;
    2604         const char      *query_string = a->conn->request_info.query_string;
    2605         int             cmp_result = 0;
    2606 
    2607         if (query_string == NULL)
    2608                 query_string = "na";
    2609 
    2610         if (a->st.is_directory && !b->st.is_directory) {
    2611                 return (-1);  /* Always put directories on top */
    2612         } else if (!a->st.is_directory && b->st.is_directory) {
    2613                 return (1);   /* Always put directories on top */
    2614         } else if (*query_string == 'n') {
    2615                 cmp_result = strcmp(a->file_name, b->file_name);
    2616         } else if (*query_string == 's') {
    2617                 cmp_result = a->st.size == b->st.size ? 0 :
    2618                         a->st.size > b->st.size ? 1 : -1;
    2619         } else if (*query_string == 'd') {
    2620                 cmp_result = a->st.mtime == b->st.mtime ? 0 :
    2621                         a->st.mtime > b->st.mtime ? 1 : -1;
    2622         }
    2623 
    2624         return (query_string[1] == 'd' ? -cmp_result : cmp_result);
    2625 }
    2626 
    2627 /*
    2628  * Send directory contents.
    2629  */
    2630 static void
    2631 send_directory(struct mg_connection *conn, const char *dir)
    2632 {
    2633         struct dirent   *dp;
    2634         DIR             *dirp;
    2635         struct de       *entries = NULL;
    2636         char            path[FILENAME_MAX];
    2637         int             i, sort_direction, num_entries = 0, arr_size = 128;
    2638 
    2639         if ((dirp = opendir(dir)) == NULL) {
    2640                 send_error(conn, 500, "Cannot open directory",
    2641                     "Error: opendir(%s): %s", path, strerror(ERRNO));
    2642                 return;
    2643         }
    2644 
    2645         (void) mg_printf(conn, "%s",
    2646             "HTTP/1.1 200 OK\r\n"
    2647             "Connection: close\r\n"
    2648             "Content-Type: text/html; charset=utf-8\r\n\r\n");
    2649 
    2650         sort_direction = conn->request_info.query_string != NULL &&
    2651             conn->request_info.query_string[1] == 'd' ? 'a' : 'd';
    2652 
    2653         while ((dp = readdir(dirp)) != NULL) {
    2654 
    2655                 /* Do not show current dir and passwords file */
    2656                 if (!strcmp(dp->d_name, ".") ||
    2657                     !strcmp(dp->d_name, "..") ||
    2658                     !strcmp(dp->d_name, PASSWORDS_FILE_NAME))
    2659                         continue;
    2660 
    2661                 if (entries == NULL || num_entries >= arr_size) {
    2662                         arr_size *= 2;
    2663                         entries = (struct de *) realloc(entries,
    2664                             arr_size * sizeof(entries[0]));
    2665                 }
    2666 
    2667                 if (entries == NULL) {
    2668                         send_error(conn, 500, "Cannot open directory",
    2669                             "%s", "Error: cannot allocate memory");
    2670                         return;
    2671                 }
    2672 
    2673                 (void) mg_snprintf(conn, path, sizeof(path), "%s%c%s",
    2674                     dir, DIRSEP, dp->d_name);
    2675 
    2676                 /*
    2677                  * If we don't memset stat structure to zero, mtime will have
    2678                  * garbage and strftime() will segfault later on in
    2679                  * print_dir_entry(). memset is required only if mg_stat()
    2680                  * fails. For more details, see
    2681                  * http://code.google.com/p/mongoose/issues/detail?id=79
    2682                  */
    2683                 if (mg_stat(path, &entries[num_entries].st) != 0)
    2684                         (void) memset(&entries[num_entries].st, 0,
    2685                             sizeof(entries[num_entries].st));
    2686 
    2687                 entries[num_entries].conn = conn;
    2688                 entries[num_entries].file_name = mg_strdup(dp->d_name);
    2689                 num_entries++;
    2690         }
    2691         (void) closedir(dirp);
    2692 
    2693         conn->num_bytes_sent += mg_printf(conn,
    2694             "<html><head><title>Index of %s</title>"
    2695             "<style>th {text-align: left;}</style></head>"
    2696             "<body><h1>Index of %s</h1><pre><table cellpadding=\"0\">"
    2697             "<tr><th><a href=\"?n%c\">Name</a></th>"
    2698             "<th><a href=\"?d%c\">Modified</a></th>"
    2699             "<th><a href=\"?s%c\">Size</a></th></tr>"
    2700             "<tr><td colspan=\"3\"><hr></td></tr>",
    2701             conn->request_info.uri, conn->request_info.uri,
    2702             sort_direction, sort_direction, sort_direction);
    2703 
    2704         /* Print first entry - link to a parent directory */
    2705         conn->num_bytes_sent += mg_printf(conn,
    2706             "<tr><td><a href=\"%s%s\">%s</a></td>"
    2707             "<td>&nbsp;%s</td><td>&nbsp;&nbsp;%s</td></tr>\n",
    2708             conn->request_info.uri, "..", "Parent directory", "-", "-");
    2709 
    2710         /* Sort and print directory entries */
    2711         qsort(entries, num_entries, sizeof(entries[0]), compare_dir_entries);
    2712         for (i = 0; i < num_entries; i++) {
    2713                 print_dir_entry(&entries[i]);
    2714                 free(entries[i].file_name);
    2715         }
    2716         free(entries);
    2717 
    2718         conn->num_bytes_sent += mg_printf(conn, "%s", "</table></body></html>");
    2719         conn->request_info.status_code = 200;
    2720 }
    2721 
    2722 /*
    2723  * Send len bytes from the opened file to the client.
    2724  */
    2725 static void
    2726 send_opened_file_stream(struct mg_connection *conn, FILE *fp, int64_t len)
    2727 {
    2728         char    buf[BUFSIZ];
    2729         int     to_read, num_read, num_written;
    2730 
    2731         while (len > 0) {
    2732                 /* Calculate how much to read from the file in the buffer */
    2733                 to_read = sizeof(buf);
    2734                 if ((int64_t) to_read > len)
    2735                         to_read = (int) len;
    2736 
    2737                 /* Read from file, exit the loop on error */
    2738                 if ((num_read = fread(buf, 1, to_read, fp)) == 0)
    2739                         break;
    2740 
    2741                 /* Send read bytes to the client, exit the loop on error */
    2742                 if ((num_written = mg_write(conn, buf, num_read)) != num_read)
    2743                         break;
    2744 
    2745                 /* Both read and were successful, adjust counters */
    2746                 conn->num_bytes_sent += num_written;
    2747                 len -= num_written;
    2748         }
    2749 }
    2750 
    2751 /*
    2752  * Send regular file contents.
    2753  */
    2754 static void
    2755 send_file(struct mg_connection *conn, const char *path, struct mgstat *stp)
    2756 {
    2757         char            date[64], lm[64], etag[64], range[64];
    2758         const char      *fmt = "%a, %d %b %Y %H:%M:%S %Z", *msg = "OK", *hdr;
    2759         time_t          curtime = time(NULL);
    2760         int64_t         cl, r1, r2;
    2761         struct vec      mime_vec;
    2762         FILE            *fp;
    2763         int             n;
    2764 
    2765         get_mime_type(conn->ctx, path, &mime_vec);
    2766         cl = stp->size;
    2767         conn->request_info.status_code = 200;
    2768         range[0] = '\0';
    2769 
    2770         if ((fp = mg_fopen(path, "rb")) == NULL) {
    2771                 send_error(conn, 500, http_500_error,
    2772                     "fopen(%s): %s", path, strerror(ERRNO));
    2773                 return;
    2774         }
    2775         set_close_on_exec(fileno(fp));
    2776 
    2777         /* If Range: header specified, act accordingly */
    2778         r1 = r2 = 0;
    2779         hdr = mg_get_header(conn, "Range");
    2780         if (hdr != NULL && (n = sscanf(hdr,
    2781             "bytes=%" INT64_FMT "-%" INT64_FMT, &r1, &r2)) > 0) {
    2782                 conn->request_info.status_code = 206;
    2783                 (void) fseeko(fp, (off_t) r1, SEEK_SET);
    2784                 cl = n == 2 ? r2 - r1 + 1: cl - r1;
    2785                 (void) mg_snprintf(conn, range, sizeof(range),
    2786                     "Content-Range: bytes "
    2787                     "%" INT64_FMT "-%"
    2788                     INT64_FMT "/%" INT64_FMT "\r\n",
    2789                     r1, r1 + cl - 1, stp->size);
    2790                 msg = "Partial Content";
    2791         }
    2792 
    2793         /* Prepare Etag, Date, Last-Modified headers */
    2794         (void) strftime(date, sizeof(date), fmt, localtime(&curtime));
    2795         (void) strftime(lm, sizeof(lm), fmt, localtime(&stp->mtime));
    2796         (void) mg_snprintf(conn, etag, sizeof(etag), "%lx.%lx",
    2797             (unsigned long) stp->mtime, (unsigned long) stp->size);
    2798 
    2799         (void) mg_printf(conn,
    2800             "HTTP/1.1 %d %s\r\n"
    2801             "Date: %s\r\n"
    2802             "Last-Modified: %s\r\n"
    2803             "Etag: \"%s\"\r\n"
    2804             "Content-Type: %.*s\r\n"
    2805             "Content-Length: %" INT64_FMT "\r\n"
    2806             "Connection: close\r\n"
    2807             "Accept-Ranges: bytes\r\n"
    2808             "%s\r\n",
    2809             conn->request_info.status_code, msg, date, lm, etag,
    2810             mime_vec.len, mime_vec.ptr, cl, range);
    2811 
    2812         if (strcmp(conn->request_info.request_method, "HEAD") != 0)
    2813                 send_opened_file_stream(conn, fp, cl);
    2814         (void) fclose(fp);
    2815 }
    2816 
    2817 /*
    2818  * Parse HTTP headers from the given buffer, advance buffer to the point
    2819  * where parsing stopped.
    2820  */
    2821 static void
    2822 parse_http_headers(char **buf, struct mg_request_info *ri)
    2823 {
    2824         int     i;
    2825 
    2826         for (i = 0; i < (int) ARRAY_SIZE(ri->http_headers); i++) {
    2827                 ri->http_headers[i].name = skip(buf, ": ");
    2828                 ri->http_headers[i].value = skip(buf, "\r\n");
    2829                 if (ri->http_headers[i].name[0] == '\0')
    2830                         break;
    2831                 ri->num_headers = i + 1;
    2832         }
    2833 }
    2834 
    2835 static bool_t
    2836 is_valid_http_method(const char *method)
    2837 {
    2838         return (!strcmp(method, "GET") ||
    2839             !strcmp(method, "POST") ||
    2840             !strcmp(method, "HEAD") ||
    2841             !strcmp(method, "PUT") ||
    2842             !strcmp(method, "DELETE"));
    2843 }
    2844 
    2845 /*
    2846  * Parse HTTP request, fill in mg_request_info structure.
    2847  */
    2848 static bool_t
    2849 parse_http_request(char *buf, struct mg_request_info *ri, const struct usa *usa)
    2850 {
    2851         int     success_code = FALSE;
    2852 
    2853         ri->request_method = skip(&buf, " ");
    2854         ri->uri = skip(&buf, " ");
    2855         ri->http_version = skip(&buf, "\r\n");
    2856 
    2857         if (is_valid_http_method(ri->request_method) &&
    2858             ri->uri[0] == '/' &&
    2859             strncmp(ri->http_version, "HTTP/", 5) == 0) {
    2860                 ri->http_version += 5;   /* Skip "HTTP/" */
    2861                 parse_http_headers(&buf, ri);
    2862                 ri->remote_port = ntohs(usa->u.sin.sin_port);
    2863                 (void) memcpy(&ri->remote_ip, &usa->u.sin.sin_addr.s_addr, 4);
    2864                 ri->remote_ip = ntohl(ri->remote_ip);
    2865                 success_code = TRUE;
    2866         }
    2867 
    2868         return (success_code);
    2869 }
    2870 
    2871 /*
    2872  * Keep reading the input (either opened file descriptor fd, or socket sock,
    2873  * or SSL descriptor ssl) into buffer buf, until \r\n\r\n appears in the
    2874  * buffer (which marks the end of HTTP request). Buffer buf may already
    2875  * have some data. The length of the data is stored in nread.
    2876  * Upon every read operation, increase nread by the number of bytes read.
    2877  */
    2878 static int
    2879 read_request(FILE *fp, SOCKET sock, SSL *ssl, char *buf, int bufsiz, int *nread)
    2880 {
    2881         int     n, request_len;
    2882 
    2883         request_len = 0;
    2884         while (*nread < bufsiz && request_len == 0) {
    2885                 n = pull(fp, sock, ssl, buf + *nread, bufsiz - *nread);
    2886                 if (n <= 0) {
    2887                         break;
    2888                 } else {
    2889                         *nread += n;
    2890                         request_len = get_request_len(buf, (size_t) *nread);
    2891                 }
    2892         }
    2893 
    2894         return (request_len);
    2895 }
    2896 
    2897 /*
    2898  * For given directory path, substitute it to valid index file.
    2899  * Return 0 if index file has been found, -1 if not found.
    2900  * If the file is found, it's stats is returned in stp.
    2901  */
    2902 static bool_t
    2903 substitute_index_file(struct mg_connection *conn,
    2904                 char *path, size_t path_len, struct mgstat *stp)
    2905 {
    2906         const char      *list;
    2907         struct mgstat   st;
    2908         struct vec      filename_vec;
    2909         size_t          n;
    2910         bool_t          found;
    2911 
    2912         n = strlen(path);
    2913 
    2914         /*
    2915          * The 'path' given to us points to the directory. Remove all trailing
    2916          * directory separator characters from the end of the path, and
    2917          * then append single directory separator character.
    2918          */
    2919         while (n > 0 && IS_DIRSEP_CHAR(path[n - 1]))
    2920                 n--;
    2921         path[n] = DIRSEP;
    2922 
    2923         /*
    2924          * Traverse index files list. For each entry, append it to the given
    2925          * path and see if the file exists. If it exists, break the loop
    2926          */
    2927         lock_option(conn->ctx, OPT_INDEX_FILES);
    2928         list = conn->ctx->options[OPT_INDEX_FILES];
    2929         found = FALSE;
    2930 
    2931         while ((list = next_option(list, &filename_vec, NULL)) != NULL) {
    2932 
    2933                 /* Ignore too long entries that may overflow path buffer */
    2934                 if (filename_vec.len > path_len - n)
    2935                         continue;
    2936 
    2937                 /* Prepare full path to the index file  */
    2938                 (void) mg_strlcpy(path + n + 1,
    2939                     filename_vec.ptr, filename_vec.len + 1);
    2940 
    2941                 /* Does it exist ? */
    2942                 if (mg_stat(path, &st) == 0) {
    2943                         /* Yes it does, break the loop */
    2944                         *stp = st;
    2945                         found = TRUE;
    2946                         break;
    2947                 }
    2948         }
    2949         unlock_option(conn->ctx, OPT_INDEX_FILES);
    2950 
    2951         /* If no index file exists, restore directory path */
    2952         if (found == FALSE)
    2953                 path[n] = '\0';
    2954 
    2955         return (found);
    2956 }
    2957 
    2958 static void
    2959 remove_callback(struct mg_context *ctx,
    2960                 const char *uri_regex, int status_code, bool_t is_auth)
    2961 {
    2962         struct callback *cb;
    2963         int             i;
    2964 
    2965         for (i = 0; i < ctx->num_callbacks; i++) {
    2966                 cb = ctx->callbacks + i;
    2967                 if ((uri_regex != NULL && cb->uri_regex != NULL &&
    2968                     ((is_auth && cb->is_auth) || (!is_auth && !cb->is_auth)) &&
    2969                     !strcmp(uri_regex, cb->uri_regex)) || (uri_regex == NULL &&
    2970                      (cb->status_code == 0 ||
    2971                       cb->status_code == status_code))) {
    2972                         (void) memmove(cb, cb + 1,
    2973                             (char *) (ctx->callbacks + ctx->num_callbacks) -
    2974                             (char *) (cb + 1));
    2975                         break;
    2976                 }
    2977         }
    2978 }
    2979 
    2980 static void
    2981 add_callback(struct mg_context *ctx, const char *uri_regex, int status_code,
    2982                 mg_callback_t func, bool_t is_auth, void *user_data)
    2983 {
    2984         struct callback *cb;
    2985 
    2986         pthread_mutex_lock(&ctx->bind_mutex);
    2987         if (func == NULL) {
    2988                 remove_callback(ctx, uri_regex, status_code, is_auth);
    2989         } else if (ctx->num_callbacks >= (int) ARRAY_SIZE(ctx->callbacks) - 1) {
    2990                 cry(fc(ctx), "Too many callbacks! Increase MAX_CALLBACKS.");
    2991         } else {
    2992                 cb = &ctx->callbacks[ctx->num_callbacks];
    2993                 cb->uri_regex = uri_regex ? mg_strdup(uri_regex) : NULL;
    2994                 cb->func = func;
    2995                 cb->is_auth = is_auth;
    2996                 cb->status_code = status_code;
    2997                 cb->user_data = user_data;
    2998                 ctx->num_callbacks++;
    2999                 DEBUG_TRACE((DEBUG_MGS_PREFIX "%s: uri %s code %d",
    3000                     __func__, uri_regex ? uri_regex : "NULL", status_code));
    3001         }
    3002         pthread_mutex_unlock(&ctx->bind_mutex);
    3003 }
    3004 
    3005 void
    3006 mg_set_uri_callback(struct mg_context *ctx, const char *uri_regex,
    3007                 mg_callback_t func, void *user_data)
    3008 {
    3009         assert(uri_regex != NULL);
    3010         add_callback(ctx, uri_regex, -1, func, FALSE, user_data);
    3011 }
    3012 
    3013 void
    3014 mg_set_error_callback(struct mg_context *ctx, int error_code,
    3015                 mg_callback_t func, void *user_data)
    3016 {
    3017         assert(error_code >= 0 && error_code < 1000);
    3018         add_callback(ctx, NULL, error_code, func, FALSE, user_data);
    3019 }
    3020 
    3021 void
    3022 mg_set_auth_callback(struct mg_context *ctx, const char *uri_regex,
    3023                 mg_callback_t func, void *user_data)
    3024 {
    3025         assert(uri_regex != NULL);
    3026         add_callback(ctx, uri_regex, -1, func, TRUE, user_data);
    3027 }
    3028 
    3029 /*
    3030  * Return True if we should reply 304 Not Modified.
    3031  */
    3032 static bool_t
    3033 is_not_modified(const struct mg_connection *conn, const struct mgstat *stp)
    3034 {
    3035         const char *ims = mg_get_header(conn, "If-Modified-Since");
    3036         return (ims != NULL && stp->mtime < date_to_epoch(ims));
    3037 }
    3038 
    3039 static bool_t
    3040 append_chunk(struct mg_request_info *ri, FILE *fp, const char *buf, int len)
    3041 {
    3042         bool_t  ret_code = TRUE;
    3043 
    3044         if (fp == NULL) {
    3045                 /* TODO: check for NULL here */
    3046                 ri->post_data = (char *) realloc(ri->post_data,
    3047                     ri->post_data_len + len);
    3048                 (void) memcpy(ri->post_data + ri->post_data_len, buf, len);
    3049                 ri->post_data_len += len;
    3050         } else if (push(fp, INVALID_SOCKET,
    3051             NULL, buf, (int64_t) len) != (int64_t) len) {
    3052                 ret_code = FALSE;
    3053         }
    3054 
    3055         return (ret_code);
    3056 }
    3057 
    3058 static bool_t
    3059 handle_request_body(struct mg_connection *conn, FILE *fp)
    3060 {
    3061         struct mg_request_info  *ri = &conn->request_info;
    3062         const char      *expect, *tmp;
    3063         int64_t         content_len;
    3064         char            buf[BUFSIZ];
    3065         int             to_read, nread, already_read;
    3066         bool_t          success_code = FALSE;
    3067 
    3068         content_len = get_content_length(conn);
    3069         expect = mg_get_header(conn, "Expect");
    3070 
    3071         if (content_len == -1) {
    3072                 send_error(conn, 411, "Length Required", "");
    3073         } else if (expect != NULL && mg_strcasecmp(expect, "100-continue")) {
    3074                 send_error(conn, 417, "Expectation Failed", "");
    3075         } else {
    3076                 if (expect != NULL)
    3077                         (void) mg_printf(conn, "HTTP/1.1 100 Continue\r\n\r\n");
    3078 
    3079                 already_read = ri->post_data_len;
    3080                 assert(already_read >= 0);
    3081 
    3082                 if (content_len <= (int64_t) already_read) {
    3083                         ri->post_data_len = (int) content_len;
    3084                         /*
    3085                          * If fp is NULL, this is embedded mode, and we do not
    3086                          * have to do anything: POST data is already there,
    3087                          * no need to allocate a buffer and copy it in.
    3088                          * If fp != NULL, we need to write the data.
    3089                          */
    3090                         success_code = fp == NULL || (push(fp, INVALID_SOCKET,
    3091                             NULL, ri->post_data, content_len) == content_len) ?
    3092                             TRUE : FALSE;
    3093                 } else {
    3094 
    3095                         if (fp == NULL) {
    3096                                 conn->free_post_data = TRUE;
    3097                                 tmp = ri->post_data;
    3098                                 /* +1 in case if already_read == 0 */
    3099                                 ri->post_data = (char*)malloc(already_read + 1);
    3100                                 (void) memcpy(ri->post_data, tmp, already_read);
    3101                         } else {
    3102                                 (void) push(fp, INVALID_SOCKET, NULL,
    3103                                     ri->post_data, (int64_t) already_read);
    3104                         }
    3105 
    3106                         content_len -= already_read;
    3107 
    3108                         while (content_len > 0) {
    3109                                 to_read = sizeof(buf);
    3110                                 if ((int64_t) to_read > content_len)
    3111                                         to_read = (int) content_len;
    3112                                 nread = pull(NULL, conn->client.sock,
    3113                                     conn->ssl, buf, to_read);
    3114                                 if (nread <= 0)
    3115                                         break;
    3116                                 if (!append_chunk(ri, fp, buf, nread))
    3117                                         break;
    3118                                 content_len -= nread;
    3119                         }
    3120                         success_code = content_len == 0 ? TRUE : FALSE;
    3121                 }
    3122 
    3123                 /* Each error code path in this function must send an error */
    3124                 if (success_code != TRUE)
    3125                         send_error(conn, 577, http_500_error,
    3126                             "%s", "Error handling body data");
    3127         }
    3128 
    3129         return (success_code);
     2300static void url_encode(const char *src, char *dst, size_t dst_len) {
     2301  static const char *dont_escape = "._-$,;~()";
     2302  static const char *hex = "0123456789abcdef";
     2303  const char *end = dst + dst_len - 1;
     2304
     2305  for (; *src != '\0' && dst < end; src++, dst++) {
     2306    if (isalnum(*(const unsigned char *) src) ||
     2307        strchr(dont_escape, * (const unsigned char *) src) != NULL) {
     2308      *dst = *src;
     2309    } else if (dst + 2 < end) {
     2310      dst[0] = '%';
     2311      dst[1] = hex[(* (const unsigned char *) src) >> 4];
     2312      dst[2] = hex[(* (const unsigned char *) src) & 0xf];
     2313      dst += 2;
     2314    }
     2315  }
     2316
     2317  *dst = '\0';
     2318}
     2319
     2320static void print_dir_entry(struct de *de) {
     2321  char size[64], mod[64], href[PATH_MAX];
     2322
     2323  if (de->st.is_directory) {
     2324    (void) mg_snprintf(de->conn, size, sizeof(size), "%s", "[DIRECTORY]");
     2325  } else {
     2326     // We use (signed) cast below because MSVC 6 compiler cannot
     2327     // convert unsigned __int64 to double. Sigh.
     2328    if (de->st.size < 1024) {
     2329      (void) mg_snprintf(de->conn, size, sizeof(size),
     2330          "%lu", (unsigned long) de->st.size);
     2331    } else if (de->st.size < 1024 * 1024) {
     2332      (void) mg_snprintf(de->conn, size, sizeof(size),
     2333          "%.1fk", (double) de->st.size / 1024.0);
     2334    } else if (de->st.size < 1024 * 1024 * 1024) {
     2335      (void) mg_snprintf(de->conn, size, sizeof(size),
     2336          "%.1fM", (double) de->st.size / 1048576);
     2337    } else {
     2338      (void) mg_snprintf(de->conn, size, sizeof(size),
     2339          "%.1fG", (double) de->st.size / 1073741824);
     2340    }
     2341  }
     2342  (void) strftime(mod, sizeof(mod), "%d-%b-%Y %H:%M", localtime(&de->st.mtime));
     2343  url_encode(de->file_name, href, sizeof(href));
     2344  de->conn->num_bytes_sent += mg_printf(de->conn,
     2345      "<tr><td><a href=\"%s%s%s\">%s%s</a></td>"
     2346      "<td>&nbsp;%s</td><td>&nbsp;&nbsp;%s</td></tr>\n",
     2347      de->conn->request_info.uri, href, de->st.is_directory ? "/" : "",
     2348      de->file_name, de->st.is_directory ? "/" : "", mod, size);
     2349}
     2350
     2351// This function is called from send_directory() and used for
     2352// sorting directory entries by size, or name, or modification time.
     2353// On windows, __cdecl specification is needed in case if project is built
     2354// with __stdcall convention. qsort always requires __cdels callback.
     2355static int WINCDECL compare_dir_entries(const void *p1, const void *p2) {
     2356  const struct de *a = (const struct de *) p1, *b = (const struct de *) p2;
     2357  const char *query_string = a->conn->request_info.query_string;
     2358  int cmp_result = 0;
     2359
     2360  if (query_string == NULL) {
     2361    query_string = "na";
     2362  }
     2363
     2364  if (a->st.is_directory && !b->st.is_directory) {
     2365    return -1;  // Always put directories on top
     2366  } else if (!a->st.is_directory && b->st.is_directory) {
     2367    return 1;   // Always put directories on top
     2368  } else if (*query_string == 'n') {
     2369    cmp_result = strcmp(a->file_name, b->file_name);
     2370  } else if (*query_string == 's') {
     2371    cmp_result = a->st.size == b->st.size ? 0 :
     2372      a->st.size > b->st.size ? 1 : -1;
     2373  } else if (*query_string == 'd') {
     2374    cmp_result = a->st.mtime == b->st.mtime ? 0 :
     2375      a->st.mtime > b->st.mtime ? 1 : -1;
     2376  }
     2377
     2378  return query_string[1] == 'd' ? -cmp_result : cmp_result;
     2379}
     2380
     2381static int scan_directory(struct mg_connection *conn, const char *dir,
     2382                          void *data, void (*cb)(struct de *, void *)) {
     2383  char path[PATH_MAX];
     2384  struct dirent *dp;
     2385  DIR *dirp;
     2386  struct de de;
     2387
     2388  if ((dirp = opendir(dir)) == NULL) {
     2389    return 0;
     2390  } else {
     2391    de.conn = conn;
     2392
     2393    while ((dp = readdir(dirp)) != NULL) {
     2394      // Do not show current dir and passwords file
     2395      if (!strcmp(dp->d_name, ".") ||
     2396          !strcmp(dp->d_name, "..") ||
     2397          !strcmp(dp->d_name, PASSWORDS_FILE_NAME))
     2398        continue;
     2399
     2400      mg_snprintf(conn, path, sizeof(path), "%s%c%s", dir, DIRSEP, dp->d_name);
     2401
     2402      // If we don't memset stat structure to zero, mtime will have
     2403      // garbage and strftime() will segfault later on in
     2404      // print_dir_entry(). memset is required only if mg_stat()
     2405      // fails. For more details, see
     2406      // http://code.google.com/p/mongoose/issues/detail?id=79
     2407      if (mg_stat(path, &de.st) != 0) {
     2408        memset(&de.st, 0, sizeof(de.st));
     2409      }
     2410      de.file_name = dp->d_name;
     2411
     2412      cb(&de, data);
     2413    }
     2414    (void) closedir(dirp);
     2415  }
     2416  return 1;
     2417}
     2418
     2419struct dir_scan_data {
     2420  struct de *entries;
     2421  int num_entries;
     2422  int arr_size;
     2423};
     2424
     2425static void dir_scan_callback(struct de *de, void *data) {
     2426  struct dir_scan_data *dsd = (struct dir_scan_data *) data;
     2427
     2428  if (dsd->entries == NULL || dsd->num_entries >= dsd->arr_size) {
     2429    dsd->arr_size *= 2;
     2430    dsd->entries = (struct de *) realloc(dsd->entries, dsd->arr_size *
     2431                                         sizeof(dsd->entries[0]));
     2432  }
     2433  if (dsd->entries == NULL) {
     2434    // TODO(lsm): propagate an error to the caller
     2435    dsd->num_entries = 0;
     2436  } else {
     2437    dsd->entries[dsd->num_entries].file_name = mg_strdup(de->file_name);
     2438    dsd->entries[dsd->num_entries].st = de->st;
     2439    dsd->entries[dsd->num_entries].conn = de->conn;
     2440    dsd->num_entries++;
     2441  }
     2442}
     2443
     2444static void handle_directory_request(struct mg_connection *conn,
     2445                                     const char *dir) {
     2446  int i, sort_direction;
     2447  struct dir_scan_data data = { NULL, 0, 128 };
     2448
     2449  if (!scan_directory(conn, dir, &data, dir_scan_callback)) {
     2450    send_http_error(conn, 500, "Cannot open directory",
     2451                    "Error: opendir(%s): %s", dir, strerror(ERRNO));
     2452    return;
     2453  }
     2454
     2455  sort_direction = conn->request_info.query_string != NULL &&
     2456    conn->request_info.query_string[1] == 'd' ? 'a' : 'd';
     2457
     2458  conn->must_close = 1;
     2459  mg_printf(conn, "%s",
     2460            "HTTP/1.1 200 OK\r\n"
     2461            "Connection: close\r\n"
     2462            "Content-Type: text/html; charset=utf-8\r\n\r\n");
     2463
     2464  conn->num_bytes_sent += mg_printf(conn,
     2465      "<html><head><title>Index of %s</title>"
     2466      "<style>th {text-align: left;}</style></head>"
     2467      "<body><h1>Index of %s</h1><pre><table cellpadding=\"0\">"
     2468      "<tr><th><a href=\"?n%c\">Name</a></th>"
     2469      "<th><a href=\"?d%c\">Modified</a></th>"
     2470      "<th><a href=\"?s%c\">Size</a></th></tr>"
     2471      "<tr><td colspan=\"3\"><hr></td></tr>",
     2472      conn->request_info.uri, conn->request_info.uri,
     2473      sort_direction, sort_direction, sort_direction);
     2474
     2475  // Print first entry - link to a parent directory
     2476  conn->num_bytes_sent += mg_printf(conn,
     2477      "<tr><td><a href=\"%s%s\">%s</a></td>"
     2478      "<td>&nbsp;%s</td><td>&nbsp;&nbsp;%s</td></tr>\n",
     2479      conn->request_info.uri, "..", "Parent directory", "-", "-");
     2480
     2481  // Sort and print directory entries
     2482  qsort(data.entries, (size_t) data.num_entries, sizeof(data.entries[0]),
     2483        compare_dir_entries);
     2484  for (i = 0; i < data.num_entries; i++) {
     2485    print_dir_entry(&data.entries[i]);
     2486    free(data.entries[i].file_name);
     2487  }
     2488  free(data.entries);
     2489
     2490  conn->num_bytes_sent += mg_printf(conn, "%s", "</table></body></html>");
     2491  conn->request_info.status_code = 200;
     2492}
     2493
     2494// Send len bytes from the opened file to the client.
     2495static void send_file_data(struct mg_connection *conn, FILE *fp, int64_t len) {
     2496  char buf[BUFSIZ];
     2497  int to_read, num_read, num_written;
     2498
     2499  while (len > 0) {
     2500    // Calculate how much to read from the file in the buffer
     2501    to_read = sizeof(buf);
     2502    if ((int64_t) to_read > len)
     2503      to_read = (int) len;
     2504
     2505    // Read from file, exit the loop on error
     2506    if ((num_read = fread(buf, 1, (size_t)to_read, fp)) == 0)
     2507      break;
     2508
     2509    // Send read bytes to the client, exit the loop on error
     2510    if ((num_written = mg_write(conn, buf, (size_t)num_read)) != num_read)
     2511      break;
     2512
     2513    // Both read and were successful, adjust counters
     2514    conn->num_bytes_sent += num_written;
     2515    len -= num_written;
     2516  }
     2517}
     2518
     2519static int parse_range_header(const char *header, int64_t *a, int64_t *b) {
     2520  return sscanf(header, "bytes=%" INT64_FMT "-%" INT64_FMT, a, b);
     2521}
     2522
     2523static void gmt_time_string(char *buf, size_t buf_len, time_t *t) {
     2524  strftime(buf, buf_len, "%a, %d %b %Y %H:%M:%S GMT", gmtime(t));
     2525}
     2526
     2527static void handle_file_request(struct mg_connection *conn, const char *path,
     2528                                struct mgstat *stp) {
     2529  char date[64], lm[64], etag[64], range[64];
     2530  const char *msg = "OK", *hdr;
     2531  time_t curtime = time(NULL);
     2532  int64_t cl, r1, r2;
     2533  struct vec mime_vec;
     2534  FILE *fp;
     2535  int n;
     2536
     2537  get_mime_type(conn->ctx, path, &mime_vec);
     2538  cl = stp->size;
     2539  conn->request_info.status_code = 200;
     2540  range[0] = '\0';
     2541
     2542  if ((fp = mg_fopen(path, "rb")) == NULL) {
     2543    send_http_error(conn, 500, http_500_error,
     2544        "fopen(%s): %s", path, strerror(ERRNO));
     2545    return;
     2546  }
     2547  set_close_on_exec(fileno(fp));
     2548
     2549  // If Range: header specified, act accordingly
     2550  r1 = r2 = 0;
     2551  hdr = mg_get_header(conn, "Range");
     2552  if (hdr != NULL && (n = parse_range_header(hdr, &r1, &r2)) > 0) {
     2553    conn->request_info.status_code = 206;
     2554    (void) fseeko(fp, (off_t) r1, SEEK_SET);
     2555    cl = n == 2 ? r2 - r1 + 1: cl - r1;
     2556    (void) mg_snprintf(conn, range, sizeof(range),
     2557        "Content-Range: bytes "
     2558        "%" INT64_FMT "-%"
     2559        INT64_FMT "/%" INT64_FMT "\r\n",
     2560        r1, r1 + cl - 1, stp->size);
     2561    msg = "Partial Content";
     2562  }
     2563
     2564  // Prepare Etag, Date, Last-Modified headers. Must be in UTC, according to
     2565  // http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.3
     2566  gmt_time_string(date, sizeof(date), &curtime);
     2567  gmt_time_string(lm, sizeof(lm), &stp->mtime);
     2568  (void) mg_snprintf(conn, etag, sizeof(etag), "%lx.%lx",
     2569      (unsigned long) stp->mtime, (unsigned long) stp->size);
     2570
     2571  (void) mg_printf(conn,
     2572      "HTTP/1.1 %d %s\r\n"
     2573      "Date: %s\r\n"
     2574      "Last-Modified: %s\r\n"
     2575      "Etag: \"%s\"\r\n"
     2576      "Content-Type: %.*s\r\n"
     2577      "Content-Length: %" INT64_FMT "\r\n"
     2578      "Connection: %s\r\n"
     2579      "Accept-Ranges: bytes\r\n"
     2580      "%s\r\n",
     2581      conn->request_info.status_code, msg, date, lm, etag, (int) mime_vec.len,
     2582      mime_vec.ptr, cl, suggest_connection_header(conn), range);
     2583
     2584  if (strcmp(conn->request_info.request_method, "HEAD") != 0) {
     2585    send_file_data(conn, fp, cl);
     2586  }
     2587  (void) fclose(fp);
     2588}
     2589
     2590void mg_send_file(struct mg_connection *conn, const char *path) {
     2591  struct mgstat st;
     2592  if (mg_stat(path, &st) == 0) {
     2593    handle_file_request(conn, path, &st);
     2594  } else {
     2595    send_http_error(conn, 404, "Not Found", "%s", "File not found");
     2596  }
     2597}
     2598
     2599
     2600// Parse HTTP headers from the given buffer, advance buffer to the point
     2601// where parsing stopped.
     2602static void parse_http_headers(char **buf, struct mg_request_info *ri) {
     2603  int i;
     2604
     2605  for (i = 0; i < (int) ARRAY_SIZE(ri->http_headers); i++) {
     2606    ri->http_headers[i].name = skip_quoted(buf, ":", " ", 0);
     2607    ri->http_headers[i].value = skip(buf, "\r\n");
     2608    if (ri->http_headers[i].name[0] == '\0')
     2609      break;
     2610    ri->num_headers = i + 1;
     2611  }
     2612}
     2613
     2614static int is_valid_http_method(const char *method) {
     2615  return !strcmp(method, "GET") || !strcmp(method, "POST") ||
     2616    !strcmp(method, "HEAD") || !strcmp(method, "CONNECT") ||
     2617    !strcmp(method, "PUT") || !strcmp(method, "DELETE") ||
     2618    !strcmp(method, "OPTIONS") || !strcmp(method, "PROPFIND");
     2619}
     2620
     2621// Parse HTTP request, fill in mg_request_info structure.
     2622static int parse_http_request(char *buf, struct mg_request_info *ri) {
     2623  int status = 0;
     2624
     2625  // RFC says that all initial whitespaces should be ingored
     2626  while (*buf != '\0' && isspace(* (unsigned char *) buf)) {
     2627    buf++;
     2628  }
     2629
     2630  ri->request_method = skip(&buf, " ");
     2631  ri->uri = skip(&buf, " ");
     2632  ri->http_version = skip(&buf, "\r\n");
     2633
     2634  if (is_valid_http_method(ri->request_method) &&
     2635      strncmp(ri->http_version, "HTTP/", 5) == 0) {
     2636    ri->http_version += 5;   // Skip "HTTP/"
     2637    parse_http_headers(&buf, ri);
     2638    status = 1;
     2639  }
     2640
     2641  return status;
     2642}
     2643
     2644// Keep reading the input (either opened file descriptor fd, or socket sock,
     2645// or SSL descriptor ssl) into buffer buf, until \r\n\r\n appears in the
     2646// buffer (which marks the end of HTTP request). Buffer buf may already
     2647// have some data. The length of the data is stored in nread.
     2648// Upon every read operation, increase nread by the number of bytes read.
     2649static int read_request(FILE *fp, SOCKET sock, SSL *ssl, char *buf, int bufsiz,
     2650                        int *nread) {
     2651  int request_len, n = 0;
     2652
     2653  do {
     2654    request_len = get_request_len(buf, *nread);
     2655    if (request_len == 0 &&
     2656        (n = pull(fp, sock, ssl, buf + *nread, bufsiz - *nread)) > 0) {
     2657      *nread += n;
     2658    }
     2659  } while (*nread < bufsiz && request_len == 0 && n > 0);
     2660
     2661  return request_len;
     2662}
     2663
     2664// For given directory path, substitute it to valid index file.
     2665// Return 0 if index file has been found, -1 if not found.
     2666// If the file is found, it's stats is returned in stp.
     2667static int substitute_index_file(struct mg_connection *conn, char *path,
     2668                                 size_t path_len, struct mgstat *stp) {
     2669  const char *list = conn->ctx->config[INDEX_FILES];
     2670  struct mgstat st;
     2671  struct vec filename_vec;
     2672  size_t n = strlen(path);
     2673  int found = 0;
     2674
     2675  // The 'path' given to us points to the directory. Remove all trailing
     2676  // directory separator characters from the end of the path, and
     2677  // then append single directory separator character.
     2678  while (n > 0 && IS_DIRSEP_CHAR(path[n - 1])) {
     2679    n--;
     2680  }
     2681  path[n] = DIRSEP;
     2682
     2683  // Traverse index files list. For each entry, append it to the given
     2684  // path and see if the file exists. If it exists, break the loop
     2685  while ((list = next_option(list, &filename_vec, NULL)) != NULL) {
     2686
     2687    // Ignore too long entries that may overflow path buffer
     2688    if (filename_vec.len > path_len - (n + 2))
     2689      continue;
     2690
     2691    // Prepare full path to the index file
     2692    (void) mg_strlcpy(path + n + 1, filename_vec.ptr, filename_vec.len + 1);
     2693
     2694    // Does it exist?
     2695    if (mg_stat(path, &st) == 0) {
     2696      // Yes it does, break the loop
     2697      *stp = st;
     2698      found = 1;
     2699      break;
     2700    }
     2701  }
     2702
     2703  // If no index file exists, restore directory path
     2704  if (!found) {
     2705    path[n] = '\0';
     2706  }
     2707
     2708  return found;
     2709}
     2710
     2711// Return True if we should reply 304 Not Modified.
     2712static int is_not_modified(const struct mg_connection *conn,
     2713                           const struct mgstat *stp) {
     2714  const char *ims = mg_get_header(conn, "If-Modified-Since");
     2715  return ims != NULL && stp->mtime <= parse_date_string(ims);
     2716}
     2717
     2718static int forward_body_data(struct mg_connection *conn, FILE *fp,
     2719                             SOCKET sock, SSL *ssl) {
     2720  const char *expect, *buffered;
     2721  char buf[BUFSIZ];
     2722  int to_read, nread, buffered_len, success = 0;
     2723
     2724  expect = mg_get_header(conn, "Expect");
     2725  assert(fp != NULL);
     2726
     2727  if (conn->content_len == -1) {
     2728    send_http_error(conn, 411, "Length Required", "");
     2729  } else if (expect != NULL && mg_strcasecmp(expect, "100-continue")) {
     2730    send_http_error(conn, 417, "Expectation Failed", "");
     2731  } else {
     2732    if (expect != NULL) {
     2733      (void) mg_printf(conn, "%s", "HTTP/1.1 100 Continue\r\n\r\n");
     2734    }
     2735
     2736    buffered = conn->buf + conn->request_len;
     2737    buffered_len = conn->data_len - conn->request_len;
     2738    assert(buffered_len >= 0);
     2739    assert(conn->consumed_content == 0);
     2740
     2741    if (buffered_len > 0) {
     2742      if ((int64_t) buffered_len > conn->content_len) {
     2743        buffered_len = (int) conn->content_len;
     2744      }
     2745      push(fp, sock, ssl, buffered, (int64_t) buffered_len);
     2746      conn->consumed_content += buffered_len;
     2747    }
     2748
     2749    while (conn->consumed_content < conn->content_len) {
     2750      to_read = sizeof(buf);
     2751      if ((int64_t) to_read > conn->content_len - conn->consumed_content) {
     2752        to_read = (int) (conn->content_len - conn->consumed_content);
     2753      }
     2754      nread = pull(NULL, conn->client.sock, conn->ssl, buf, to_read);
     2755      if (nread <= 0 || push(fp, sock, ssl, buf, nread) != nread) {
     2756        break;
     2757      }
     2758      conn->consumed_content += nread;
     2759    }
     2760
     2761    if (conn->consumed_content == conn->content_len) {
     2762      success = 1;
     2763    }
     2764
     2765    // Each error code path in this function must send an error
     2766    if (!success) {
     2767      send_http_error(conn, 577, http_500_error, "");
     2768    }
     2769  }
     2770
     2771  return success;
    31302772}
    31312773
    31322774#if !defined(NO_CGI)
    3133 
    3134 /*
    3135  * This structure helps to create an environment for the spawned CGI program.
    3136  * Environment is an array of "VARIABLE=VALUE\0" ASCIIZ strings,
    3137  * last element must be NULL.
    3138  * However, on Windows there is a requirement that all these VARIABLE=VALUE\0
    3139  * strings must reside in a contiguous buffer. The end of the buffer is
    3140  * marked by two '\0' characters.
    3141  * We satisfy both worlds: we create an envp array (which is vars), all
    3142  * entries are actually pointers inside buf.
    3143  */
     2775// This structure helps to create an environment for the spawned CGI program.
     2776// Environment is an array of "VARIABLE=VALUE\0" ASCIIZ strings,
     2777// last element must be NULL.
     2778// However, on Windows there is a requirement that all these VARIABLE=VALUE\0
     2779// strings must reside in a contiguous buffer. The end of the buffer is
     2780// marked by two '\0' characters.
     2781// We satisfy both worlds: we create an envp array (which is vars), all
     2782// entries are actually pointers inside buf.
    31442783struct cgi_env_block {
    3145         struct mg_connection *conn;
    3146         char    buf[CGI_ENVIRONMENT_SIZE];      /* Environment buffer   */
    3147         int     len;                            /* Space taken          */
    3148         char    *vars[MAX_CGI_ENVIR_VARS];      /* char **envp          */
    3149         int     nvars;                          /* Number of variables  */
     2784  struct mg_connection *conn;
     2785  char buf[CGI_ENVIRONMENT_SIZE]; // Environment buffer
     2786  int len; // Space taken
     2787  char *vars[MAX_CGI_ENVIR_VARS]; // char **envp
     2788  int nvars; // Number of variables
    31502789};
    31512790
    3152 /*
    3153  * Append VARIABLE=VALUE\0 string to the buffer, and add a respective
    3154  * pointer into the vars array.
    3155  */
    3156 static char *
    3157 addenv(struct cgi_env_block *block, const char *fmt, ...)
    3158 {
    3159         int     n, space;
    3160         char    *added;
    3161         va_list ap;
    3162 
    3163         /* Calculate how much space is left in the buffer */
    3164         space = sizeof(block->buf) - block->len - 2;
    3165         assert(space >= 0);
    3166 
    3167         /* Make a pointer to the free space int the buffer */
    3168         added = block->buf + block->len;
    3169 
    3170         /* Copy VARIABLE=VALUE\0 string into the free space */
    3171         va_start(ap, fmt);
    3172         n = mg_vsnprintf(block->conn, added, (size_t) space, fmt, ap);
    3173         va_end(ap);
    3174 
    3175         /* Make sure we do not overflow buffer and the envp array */
    3176         if (n > 0 && n < space &&
    3177             block->nvars < (int) ARRAY_SIZE(block->vars) - 2) {
    3178                 /* Append a pointer to the added string into the envp array */
    3179                 block->vars[block->nvars++] = block->buf + block->len;
    3180                 /* Bump up used length counter. Include \0 terminator */
    3181                 block->len += n + 1;
    3182         }
    3183 
    3184         return (added);
    3185 }
    3186 
    3187 static void
    3188 prepare_cgi_environment(struct mg_connection *conn, const char *prog,
    3189                 struct cgi_env_block *blk)
    3190 {
    3191         const char      *s, *script_filename, *root, *slash;
    3192         struct vec      var_vec;
    3193         char            *p;
    3194         int             i;
    3195 
    3196         blk->len = blk->nvars = 0;
    3197         blk->conn = conn;
    3198 
    3199         /* SCRIPT_FILENAME */
    3200         script_filename = prog;
    3201         if ((s = strrchr(prog, '/')) != NULL)
    3202                 script_filename = s + 1;
    3203 
    3204         lock_option(conn->ctx, OPT_ROOT);
    3205         root = conn->ctx->options[OPT_ROOT];
    3206         addenv(blk, "SERVER_NAME=%s", conn->ctx->options[OPT_AUTH_DOMAIN]);
    3207         unlock_option(conn->ctx, OPT_ROOT);
    3208 
    3209         /* Prepare the environment block */
    3210         addenv(blk, "%s", "GATEWAY_INTERFACE=CGI/1.1");
    3211         addenv(blk, "%s", "SERVER_PROTOCOL=HTTP/1.1");
    3212         addenv(blk, "%s", "REDIRECT_STATUS=200");       /* PHP */
    3213         addenv(blk, "SERVER_PORT=%d", ntohs(conn->client.lsa.u.sin.sin_port));
    3214         addenv(blk, "SERVER_ROOT=%s", root);
    3215         addenv(blk, "DOCUMENT_ROOT=%s", root);
    3216         addenv(blk, "REQUEST_METHOD=%s", conn->request_info.request_method);
    3217         addenv(blk, "REMOTE_ADDR=%s",
    3218             inet_ntoa(conn->client.rsa.u.sin.sin_addr));
    3219         addenv(blk, "REMOTE_PORT=%d", conn->request_info.remote_port);
    3220         addenv(blk, "REQUEST_URI=%s", conn->request_info.uri);
    3221 
    3222         slash = strrchr(conn->request_info.uri, '/');
    3223         addenv(blk, "SCRIPT_NAME=%.*s%s",
    3224             (slash - conn->request_info.uri) + 1, conn->request_info.uri,
    3225             script_filename);
    3226 
    3227         addenv(blk, "SCRIPT_FILENAME=%s", script_filename);     /* PHP */
    3228         addenv(blk, "PATH_TRANSLATED=%s", prog);
    3229         addenv(blk, "HTTPS=%s", conn->ssl == NULL ? "off" : "on");
    3230 
    3231         if ((s = mg_get_header(conn, "Content-Type")) != NULL)
    3232                 addenv(blk, "CONTENT_TYPE=%s", s);
    3233 
    3234         if (conn->request_info.query_string != NULL)
    3235                 addenv(blk, "QUERY_STRING=%s", conn->request_info.query_string);
    3236 
    3237         if ((s = mg_get_header(conn, "Content-Length")) != NULL)
    3238                 addenv(blk, "CONTENT_LENGTH=%s", s);
    3239 
    3240         if ((s = getenv("PATH")) != NULL)
    3241                 addenv(blk, "PATH=%s", s);
     2791// Append VARIABLE=VALUE\0 string to the buffer, and add a respective
     2792// pointer into the vars array.
     2793static char *addenv(struct cgi_env_block *block, const char *fmt, ...) {
     2794  int n, space;
     2795  char *added;
     2796  va_list ap;
     2797
     2798  // Calculate how much space is left in the buffer
     2799  space = sizeof(block->buf) - block->len - 2;
     2800  assert(space >= 0);
     2801
     2802  // Make a pointer to the free space int the buffer
     2803  added = block->buf + block->len;
     2804
     2805  // Copy VARIABLE=VALUE\0 string into the free space
     2806  va_start(ap, fmt);
     2807  n = mg_vsnprintf(block->conn, added, (size_t) space, fmt, ap);
     2808  va_end(ap);
     2809
     2810  // Make sure we do not overflow buffer and the envp array
     2811  if (n > 0 && n < space &&
     2812      block->nvars < (int) ARRAY_SIZE(block->vars) - 2) {
     2813    // Append a pointer to the added string into the envp array
     2814    block->vars[block->nvars++] = block->buf + block->len;
     2815    // Bump up used length counter. Include \0 terminator
     2816    block->len += n + 1;
     2817  }
     2818
     2819  return added;
     2820}
     2821
     2822static void prepare_cgi_environment(struct mg_connection *conn,
     2823                                    const char *prog,
     2824                                    struct cgi_env_block *blk) {
     2825  const char *s, *slash;
     2826  struct vec var_vec;
     2827  char *p, src_addr[20];
     2828  int  i;
     2829
     2830  blk->len = blk->nvars = 0;
     2831  blk->conn = conn;
     2832  sockaddr_to_string(src_addr, sizeof(src_addr), &conn->client.rsa);
     2833
     2834  addenv(blk, "SERVER_NAME=%s", conn->ctx->config[AUTHENTICATION_DOMAIN]);
     2835  addenv(blk, "SERVER_ROOT=%s", conn->ctx->config[DOCUMENT_ROOT]);
     2836  addenv(blk, "DOCUMENT_ROOT=%s", conn->ctx->config[DOCUMENT_ROOT]);
     2837
     2838  // Prepare the environment block
     2839  addenv(blk, "%s", "GATEWAY_INTERFACE=CGI/1.1");
     2840  addenv(blk, "%s", "SERVER_PROTOCOL=HTTP/1.1");
     2841  addenv(blk, "%s", "REDIRECT_STATUS=200"); // For PHP
     2842
     2843  // TODO(lsm): fix this for IPv6 case
     2844  addenv(blk, "SERVER_PORT=%d", ntohs(conn->client.lsa.sin.sin_port));
     2845
     2846  addenv(blk, "REQUEST_METHOD=%s", conn->request_info.request_method);
     2847  addenv(blk, "REMOTE_ADDR=%s", src_addr);
     2848  addenv(blk, "REMOTE_PORT=%d", conn->request_info.remote_port);
     2849  addenv(blk, "REQUEST_URI=%s", conn->request_info.uri);
     2850
     2851  // SCRIPT_NAME
     2852  assert(conn->request_info.uri[0] == '/');
     2853  slash = strrchr(conn->request_info.uri, '/');
     2854  if ((s = strrchr(prog, '/')) == NULL)
     2855    s = prog;
     2856  addenv(blk, "SCRIPT_NAME=%.*s%s", slash - conn->request_info.uri,
     2857         conn->request_info.uri, s);
     2858
     2859  addenv(blk, "SCRIPT_FILENAME=%s", prog);
     2860  addenv(blk, "PATH_TRANSLATED=%s", prog);
     2861  addenv(blk, "HTTPS=%s", conn->ssl == NULL ? "off" : "on");
     2862
     2863  if ((s = mg_get_header(conn, "Content-Type")) != NULL)
     2864    addenv(blk, "CONTENT_TYPE=%s", s);
     2865
     2866  if (conn->request_info.query_string != NULL)
     2867    addenv(blk, "QUERY_STRING=%s", conn->request_info.query_string);
     2868
     2869  if ((s = mg_get_header(conn, "Content-Length")) != NULL)
     2870    addenv(blk, "CONTENT_LENGTH=%s", s);
     2871
     2872  if ((s = getenv("PATH")) != NULL)
     2873    addenv(blk, "PATH=%s", s);
     2874
     2875  if (conn->path_info != NULL) {
     2876    addenv(blk, "PATH_INFO=%s", conn->path_info);
     2877  }
    32422878
    32432879#if defined(_WIN32)
    3244         if ((s = getenv("COMSPEC")) != NULL)
    3245                 addenv(blk, "COMSPEC=%s", s);
    3246         if ((s = getenv("SYSTEMROOT")) != NULL)
    3247                 addenv(blk, "SYSTEMROOT=%s", s);
     2880  if ((s = getenv("COMSPEC")) != NULL) {
     2881    addenv(blk, "COMSPEC=%s", s);
     2882  }
     2883  if ((s = getenv("SYSTEMROOT")) != NULL) {
     2884    addenv(blk, "SYSTEMROOT=%s", s);
     2885  }
     2886  if ((s = getenv("SystemDrive")) != NULL) {
     2887    addenv(blk, "SystemDrive=%s", s);
     2888  }
    32482889#else
    3249         if ((s = getenv("LD_LIBRARY_PATH")) != NULL)
    3250                 addenv(blk, "LD_LIBRARY_PATH=%s", s);
    3251 #endif /* _WIN32 */
    3252 
    3253         if ((s = getenv("PERLLIB")) != NULL)
    3254                 addenv(blk, "PERLLIB=%s", s);
    3255 
    3256         if (conn->request_info.remote_user != NULL) {
    3257                 addenv(blk, "REMOTE_USER=%s", conn->request_info.remote_user);
    3258                 addenv(blk, "%s", "AUTH_TYPE=Digest");
    3259         }
    3260 
    3261         /* Add all headers as HTTP_* variables */
    3262         for (i = 0; i < conn->request_info.num_headers; i++) {
    3263                 p = addenv(blk, "HTTP_%s=%s",
    3264                     conn->request_info.http_headers[i].name,
    3265                     conn->request_info.http_headers[i].value);
    3266 
    3267                 /* Convert variable name into uppercase, and change - to _ */
    3268                 for (; *p != '=' && *p != '\0'; p++) {
    3269                         if (*p == '-')
    3270                                 *p = '_';
    3271                         *p = (char) toupper(* (unsigned char *) p);
    3272                 }
    3273         }
    3274 
    3275         /* Add user-specified variables */
    3276         lock_option(conn->ctx, OPT_CGI_ENV);
    3277         s = conn->ctx->options[OPT_CGI_ENV];
    3278         while ((s = next_option(s, &var_vec, NULL)) != NULL)
    3279                 addenv(blk, "%.*s", var_vec.len, var_vec.ptr);
    3280         unlock_option(conn->ctx, OPT_CGI_ENV);
    3281 
    3282         blk->vars[blk->nvars++] = NULL;
    3283         blk->buf[blk->len++] = '\0';
    3284 
    3285         assert(blk->nvars < (int) ARRAY_SIZE(blk->vars));
    3286         assert(blk->len > 0);
    3287         assert(blk->len < (int) sizeof(blk->buf));
    3288 }
    3289 
    3290 static void
    3291 send_cgi(struct mg_connection *conn, const char *prog)
    3292 {
    3293         int                     headers_len, data_len, i;
    3294         const char              *status;
    3295         char                    buf[MAX_REQUEST_SIZE], *pbuf;
    3296         struct mg_request_info  ri;
    3297         struct cgi_env_block    blk;
    3298         char                    dir[FILENAME_MAX], *p;
    3299         int                     fd_stdin[2], fd_stdout[2];
    3300         FILE                    *in, *out;
    3301         pid_t                   pid;
    3302 
    3303         prepare_cgi_environment(conn, prog, &blk);