Previous 199869 Revisions Next

r30717 Friday 30th May, 2014 at 10:18:47 UTC by Miodrag Milanović
Updated to latest mongoose code in agreement with author (nw)
[src/emu]webengine.c webengine.h
[src/lib/web]mongoose.c mongoose.h

trunk/src/emu/webengine.c
r30716r30717
2020//  WEB ENGINE
2121//**************************************************************************
2222
23void web_engine::websocket_ready_handler(struct mg_connection *conn) {
24   static const char *message = "update_machine";
25   mg_websocket_write(conn, WEBSOCKET_OPCODE_TEXT, message, strlen(message));
26   m_websockets.append(*global_alloc(simple_list_wrapper<mg_connection>(conn)));
27}
28
29// Arguments:
30//   flags: first byte of websocket frame, see websocket RFC,
31//          http://tools.ietf.org/html/rfc6455, section 5.2
32//   data, data_len: payload data. Mask, if any, is already applied.
33int web_engine::websocket_data_handler(struct mg_connection *conn, int flags,
34                           char *data, size_t data_len)
35{
36   // just Echo example for now
37   if ((flags & 0x0f) == WEBSOCKET_OPCODE_TEXT)
38      mg_websocket_write(conn, WEBSOCKET_OPCODE_TEXT, data, data_len);
39
40   // Returning zero means stoping websocket conversation.
41   // Close the conversation if client has sent us "exit" string.
42   return memcmp(data, "exit", 4);
43}
44
45static void get_qsvar(const struct mg_request_info *request_info,
46                  const char *name, char *dst, size_t dst_len) {
47   const char *qs = request_info->query_string;
48   mg_get_var(qs, strlen(qs == NULL ? "" : qs), name, dst, dst_len);
49}
50
5123char* websanitize_statefilename ( char* unsanitized )
5224{
5325   // It's important that we remove any dangerous characters from any filename
r30716r30717
10779
10880   // Returning non-zero tells mongoose that our function has replied to
10981   // the client, and mongoose should not send client any more data.
110   return 1;
82
83   return MG_TRUE;
11184}
11285
11386int web_engine::json_slider_handler(struct mg_connection *conn)
r30716r30717
11689   astring tempstring;
11790   Json::Value array(Json::arrayValue);
11891
119   /* add all sliders */
92   // add all sliders
12093   for (curslider = machine().ui().get_slider_list(); curslider != NULL; curslider = curslider->next)
12194   {
12295      INT32 curval = (*curslider->update)(machine(), curslider->arg, &tempstring, SLIDER_NOCHANGE);
r30716r30717
130103      array.append(data);
131104   }
132105
133   /* add all sliders */
106   // add all sliders
134107   for (curslider = (slider_state*)machine().osd().get_slider_list(); curslider != NULL; curslider = curslider->next)
135108   {
136109      INT32 curval = (*curslider->update)(machine(), curslider->arg, &tempstring, SLIDER_NOCHANGE);
r30716r30717
154127         "%s",
155128         (int)strlen(json), json);
156129
157   return 1;
130   return MG_TRUE;
158131}
159132
160133// This function will be called by mongoose on every new request.
161134int web_engine::begin_request_handler(struct mg_connection *conn)
162135{
163   const struct mg_request_info *request_info = mg_get_request_info(conn);
164   if (!strncmp(request_info->uri, "/json/",6))
136   if (!strncmp(conn->uri, "/json/",6))
165137   {
166      if (!strcmp(request_info->uri, "/json/game"))
138      if (!strcmp(conn->uri, "/json/game"))
167139      {
168140         return json_game_handler(conn);
169141      }
170      if (!strcmp(request_info->uri, "/json/slider"))
142      if (!strcmp(conn->uri, "/json/slider"))
171143      {
172144         return json_slider_handler(conn);
173145      }
174146   }
175   else if (!strncmp(request_info->uri, "/cmd",4))
147   else if (!strncmp(conn->uri, "/cmd",4))
176148   {
177149      char cmd_name[64];
178      get_qsvar(request_info, "name", cmd_name, sizeof(cmd_name));
150      mg_get_var(conn, "name", cmd_name, sizeof(cmd_name));
179151
180152      if(!strcmp(cmd_name,"softreset"))
181153      {
r30716r30717
199171      else if(!strcmp(cmd_name,"savestate"))
200172      {
201173         char cmd_val[64];
202         get_qsvar(request_info, "val", cmd_val, sizeof(cmd_val));
174         mg_get_var(conn, "val", cmd_val, sizeof(cmd_val));
203175         char *filename = websanitize_statefilename(cmd_val);
204176         m_machine->schedule_save(filename);
205177      }
206178      else if(!strcmp(cmd_name,"loadstate"))
207179      {
208180         char cmd_val[64];
209         get_qsvar(request_info, "val", cmd_val, sizeof(cmd_val));
181         mg_get_var(conn, "val", cmd_val, sizeof(cmd_val));
210182         char *filename = cmd_val;
211183         m_machine->schedule_load(filename);
212184      }
r30716r30717
226198
227199      // Returning non-zero tells mongoose that our function has replied to
228200      // the client, and mongoose should not send client any more data.
229      return 1;
201      return MG_TRUE;
230202   }
231   else if (!strncmp(request_info->uri, "/slider",7))
203   else if (!strncmp(conn->uri, "/slider",7))
232204   {
233205      char cmd_id[64];
234206      char cmd_val[64];
235      get_qsvar(request_info, "id", cmd_id, sizeof(cmd_id));
236      get_qsvar(request_info, "val", cmd_val, sizeof(cmd_val));
207      mg_get_var(conn, "id", cmd_id, sizeof(cmd_id));
208      mg_get_var(conn, "val", cmd_val, sizeof(cmd_val));
237209      int cnt = 0;
238210      int id = atoi(cmd_id);
239211      const slider_state *curslider;
r30716r30717
260232
261233      // Returning non-zero tells mongoose that our function has replied to
262234      // the client, and mongoose should not send client any more data.
263      return 1;
235      return MG_TRUE;
264236   }
265   else if (!strncmp(request_info->uri, "/screenshot.png",15))
237   else if (!strncmp(conn->uri, "/screenshot.png",15))
266238   {
267      screen_device_iterator iter(m_machine->root_device());
268      screen_device *screen = iter.first();
269
270      if (screen == NULL)
239      FILE *fp = (FILE *) conn->connection_param;
240      char buf[200];
241      size_t n = 0;
242      if (fp == NULL)
271243      {
272         return 0;
273      }
244         screen_device_iterator iter(m_machine->root_device());
245         screen_device *screen = iter.first();
274246
275      astring fname("screenshot.png");
276      emu_file file(m_machine->options().snapshot_directory(), OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS);
277      file_error filerr = file.open(fname);
247         if (screen == NULL)
248         {
249            return 0;
250         }
278251
279      if (filerr != FILERR_NONE)
280      {
281         return 0;
282      }
252         astring fname("screenshot.png");
253         {
254            emu_file file(m_machine->options().snapshot_directory(), OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS);
255            file_error filerr = file.open(fname);
283256
284      m_machine->video().save_snapshot(screen, file);
285      astring fullpath(file.fullpath());
286      file.close();
257            if (filerr != FILERR_NONE)
258            {
259               return 0;
260            }
287261
288      mg_send_file(conn,fullpath);
289      return 1;
290   }
291   return 0;
292}
293
294void *web_engine::websocket_keepalive()
295{
296   while(!m_exiting_core)
297   {
298      osd_ticks_t curtime = osd_ticks();
299      if ((curtime - m_lastupdatetime) > osd_ticks_per_second() * 5)
300      {
301         m_lastupdatetime = curtime;
302         for (simple_list_wrapper<mg_connection> *curitem = m_websockets.first(); curitem != NULL; curitem = curitem->next())
262            m_machine->video().save_snapshot(screen, file);
263            astring fullpath(file.fullpath());
264            file.close();
265         }
266         
303267         {
304            int status = mg_websocket_write(curitem->object(), WEBSOCKET_OPCODE_PING, NULL, 0);
305            if (status==0) m_websockets.detach(*curitem); // remove inactive clients
268            emu_file file(m_machine->options().snapshot_directory(), OPEN_FLAG_READ);
269            file_error filerr = file.open(fname);
270
271            if (filerr != FILERR_NONE)
272            {
273               return 0;
274            }
275                     
276            file.seek(0, SEEK_SET);
277            mg_send_header(conn, "Content-Type", "image/png");
278            mg_send_header(conn, "Cache-Control", "no-cache, no-store, must-revalidate");
279            mg_send_header(conn, "Pragma", "no-cache");
280            mg_send_header(conn, "Expires", "0");         
281            do
282            {
283               n = file.read(buf, sizeof(buf));                             
284               mg_send_data(conn, buf, n);
285            }
286            while (n==sizeof(buf));
287            file.close();           
306288         }
307289      }
308      osd_sleep(osd_ticks_per_second()/5);
290      return MG_TRUE;
309291   }
310   return NULL;
292   return 0;
311293}
312294
313//-------------------------------------------------
314//  static callbacks
315//-------------------------------------------------
316static void websocket_ready_handler_static(struct mg_connection *conn)
317{
318   const struct mg_request_info *request_info = mg_get_request_info(conn);
319   web_engine *engine = static_cast<web_engine *>(request_info->user_data);
320   engine->websocket_ready_handler(conn);
295static int ev_handler(struct mg_connection *conn, enum mg_event ev) {
296  if (ev == MG_REQUEST) {
297   if (conn->is_websocket) {
298      // This handler is called for each incoming websocket frame, one or more
299      // times for connection lifetime.
300      // Echo websocket data back to the client.
301      //const char *msg = "update_machine";
302      //mg_websocket_write(conn, 1, msg, strlen(msg));
303      return conn->content_len == 4 && !memcmp(conn->content, "exit", 4) ? MG_FALSE : MG_TRUE;
304    } else {
305      web_engine *engine = static_cast<web_engine *>(conn->server_param);   
306      return engine->begin_request_handler(conn);   
307   }
308  } else if (ev == MG_AUTH) {
309    return MG_TRUE;
310  } else {
311    return MG_FALSE;
312  }
321313}
322314
323static int websocket_data_handler_static(struct mg_connection *conn, int flags,
324                           char *data, size_t data_len)
325{
326   const struct mg_request_info *request_info = mg_get_request_info(conn);
327   web_engine *engine = static_cast<web_engine *>(request_info->user_data);
328   return engine->websocket_data_handler(conn, flags, data, data_len);
315static int iterate_callback(struct mg_connection *c, enum mg_event ev) {
316  if (ev == MG_POLL && c->is_websocket) {
317    char buf[20];
318    int len = snprintf(buf, sizeof(buf), "%lu",
319     (unsigned long) * (time_t *) c->callback_param);
320    mg_websocket_write(c, 1, buf, len);
321  }
322  return MG_TRUE;
329323}
330324
331static int begin_request_handler_static(struct mg_connection *conn)
332{
333   const struct mg_request_info *request_info = mg_get_request_info(conn);
334   web_engine *engine = static_cast<web_engine *>(request_info->user_data);
335   return engine->begin_request_handler(conn);
325static void *serve(void *server) {
326   time_t current_timer = 0, last_timer = time(NULL);
327   for (;;) mg_poll_server((struct mg_server *) server, 1000);
328   current_timer = time(NULL);
329   if (current_timer - last_timer > 0) {
330      last_timer = current_timer;
331      mg_iterate_over_connections((struct mg_server *)server, iterate_callback, &current_timer);
332   } 
333   return NULL;
336334}
337335
338static int begin_http_error_handler_static(struct mg_connection *conn, int status)
339{
340   //const struct mg_request_info *request_info = mg_get_request_info(conn);
341   if (status == 404) // 404 -- File Not Found
342   {
343      {
344            mg_printf(conn,
345               "HTTP/1.1 404 Not Found\r\n"
346               "Content-Type: text/plain\r\n"
347               "Content-Length: 14\r\n"        // Always set Content-Length
348               "\r\n"
349               "Nothing to do.");
350      }
351   }
352   // Returning non-zero tells mongoose that our function has replied to
353   // the client, and mongoose should not send client any more data.
354   return 1;
355}
356
357static void *websocket_keepalive_static(void *thread_func_param)
358{
359   web_engine *engine = static_cast<web_engine *>(thread_func_param);
360   return engine->websocket_keepalive();
361}
362
363336//-------------------------------------------------
364337//  web_engine - constructor
365338//-------------------------------------------------
r30716r30717
367340web_engine::web_engine(emu_options &options)
368341   : m_options(options),
369342      m_machine(NULL),
370      m_ctx(NULL),
343      m_server(NULL),
371344      m_lastupdatetime(0),
372345      m_exiting_core(false)
373346
374347{
375   struct mg_callbacks callbacks;
376
377   // List of options. Last element must be NULL.
378   const char *web_options[] = {
379      "listening_ports", options.http_port(),
380      "document_root", options.http_path(),
381      NULL
382   };
383
384   // Prepare callbacks structure.
385   memset(&callbacks, 0, sizeof(callbacks));
386   callbacks.begin_request = begin_request_handler_static;
387   callbacks.websocket_ready = websocket_ready_handler_static;
388   callbacks.websocket_data = websocket_data_handler_static;
389   callbacks.http_error = begin_http_error_handler_static;
390
391   // Start the web server.
392348   if (m_options.http()) {
393      m_ctx = mg_start(&callbacks, this, web_options);
394
395      mg_start_thread(websocket_keepalive_static, this);
349      m_server = mg_create_server(this, ev_handler);
350     
351      mg_set_option(m_server, "listening_port", options.http_port());
352      mg_set_option(m_server, "document_root",  options.http_path());
353     
354      mg_start_thread(serve, m_server);
396355   }
397356
398357}
r30716r30717
414373void web_engine::close()
415374{
416375   m_exiting_core = 1;
417   osd_sleep(osd_ticks_per_second()/5);
418   for (simple_list_wrapper<mg_connection> *curitem = m_websockets.first(); curitem != NULL; curitem = curitem->next())
419   {
420      mg_websocket_write(curitem->object(), WEBSOCKET_OPCODE_CONNECTION_CLOSE, NULL, 0);
421   }
422   // Stop the server.
423   mg_stop(m_ctx);
376   // Cleanup, and free server instance
377   mg_destroy_server(&m_server);   
424378}
425379
380static int websocket_callback(struct mg_connection *c, enum mg_event ev) {
381  if (c->is_websocket) {
382    const char *message = (const char *)c->callback_param;
383    mg_websocket_write(c, 1, message, strlen(message));
384  }
385  return MG_TRUE;
386}
426387
427388void web_engine::push_message(const char *message)
428389{
429   for (simple_list_wrapper<mg_connection> *curitem = m_websockets.first(); curitem != NULL; curitem = curitem->next())
430   {
431      int status = mg_websocket_write(curitem->object(), WEBSOCKET_OPCODE_TEXT, message, strlen(message));
432      if (status==0) m_websockets.remove(*curitem); // remove inactive clients
433   }
390   if (m_server!=NULL)
391      mg_iterate_over_connections(m_server, websocket_callback, (void*)message);
434392}
trunk/src/emu/webengine.h
r30716r30717
1313#ifndef __WEB_ENGINE_H__
1414#define __WEB_ENGINE_H__
1515
16struct mg_context;     // Handle for the HTTP service itself
16struct mg_server;      // Handle for the HTTP server itself
1717struct mg_connection;  // Handle for the individual connection
1818
1919class web_engine
r30716r30717
2727   void close();
2828
2929   void set_machine(running_machine &machine) { m_machine = &machine; }
30
31   void websocket_ready_handler(struct mg_connection *conn);
32   int websocket_data_handler(struct mg_connection *conn, int flags, char *data, size_t data_len);
3330   int begin_request_handler(struct mg_connection *conn);
34   int begin_http_error_handler(struct mg_connection *conn, int status);
35   void *websocket_keepalive();
3631protected:
3732   // getters
3833   running_machine &machine() const { return *m_machine; }
r30716r30717
4338   // internal state
4439   emu_options &       m_options;
4540   running_machine *   m_machine;
46   struct mg_context * m_ctx;
41   struct mg_server * m_server;
4742   osd_ticks_t         m_lastupdatetime;
4843   bool                m_exiting_core;
49   simple_list<simple_list_wrapper<mg_connection> > m_websockets;
5044};
5145
5246#endif  /* __web_engine_H__ */
trunk/src/lib/web/mongoose.h
r30716r30717
1// Copyright (c) 2004-2012 Sergey Lyubka
1// Copyright (c) 2004-2013 Sergey Lyubka <valenok@gmail.com>
2// Copyright (c) 2013-2014 Cesanta Software Limited
3// All rights reserved
24//
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:
5// This library is dual-licensed: you can redistribute it and/or modify
6// it under the terms of the GNU General Public License version 2 as
7// published by the Free Software Foundation. For the terms of this
8// license, see <http://www.gnu.org/licenses/>.
99//
10// The above copyright notice and this permission notice shall be included in
11// all copies or substantial portions of the Software.
10// You are free to use this library under the terms of the GNU General
11// Public License, but WITHOUT ANY WARRANTY; without even the implied
12// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13// See the GNU General Public License for more details.
1214//
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.
15// Alternatively, you can license this library under a commercial
16// license, as set out in <http://cesanta.com/>.
17//
18// NOTE: Detailed API documentation is at http://cesanta.com/#docs
2019
2120#ifndef MONGOOSE_HEADER_INCLUDED
2221#define  MONGOOSE_HEADER_INCLUDED
2322
24#include <stdio.h>
25#include <stddef.h>
23#define MONGOOSE_VERSION "5.4"
2624
25#include <stdio.h>      // required for FILE
26#include <stddef.h>     // required for size_t
27
2728#ifdef __cplusplus
2829extern "C" {
2930#endif // __cplusplus
3031
31struct mg_context;     // Handle for the HTTP service itself
32struct mg_connection;  // Handle for the individual connection
32// This structure contains information about HTTP request.
33struct mg_connection {
34  const char *request_method; // "GET", "POST", etc
35  const char *uri;            // URL-decoded URI
36  const char *http_version;   // E.g. "1.0", "1.1"
37  const char *query_string;   // URL part after '?', not including '?', or NULL
3338
39  char remote_ip[48];         // Max IPv6 string length is 45 characters
40  char local_ip[48];          // Local IP address
41  unsigned short remote_port; // Client's port
42  unsigned short local_port;  // Local port number
3443
35// This structure contains information about the HTTP request.
36struct mg_request_info {
37   const char *request_method; // "GET", "POST", etc
38   const char *uri;            // URL-decoded URI
39   const char *http_version;   // E.g. "1.0", "1.1"
40   const char *query_string;   // URL part after '?', not including '?', or NULL
41   const char *remote_user;    // Authenticated user, or NULL if no auth used
42   long remote_ip;             // Client's IP address
43   int remote_port;            // Client's port
44   int is_ssl;                 // 1 if SSL-ed, 0 if not
45   void *user_data;            // User data pointer passed to mg_start()
44  int num_headers;            // Number of HTTP headers
45  struct mg_header {
46    const char *name;         // HTTP header name
47    const char *value;        // HTTP header value
48  } http_headers[30];
4649
47   int num_headers;            // Number of HTTP headers
48   struct mg_header {
49   const char *name;         // HTTP header name
50   const char *value;        // HTTP header value
51   } http_headers[64];         // Maximum 64 headers
50  char *content;              // POST (or websocket message) data, or NULL
51  size_t content_len;         // Data length
52
53  int is_websocket;           // Connection is a websocket connection
54  int status_code;            // HTTP status code for HTTP error handler
55  int wsbits;                 // First byte of the websocket frame
56  void *server_param;         // Parameter passed to mg_add_uri_handler()
57  void *connection_param;     // Placeholder for connection-specific data
58  void *callback_param;       // Needed by mg_iterate_over_connections()
5259};
5360
54
55// This structure needs to be passed to mg_start(), to let mongoose know
56// which callbacks to invoke. For detailed description, see
57// https://github.com/valenok/mongoose/blob/master/UserManual.md
58struct mg_callbacks {
59   // Called when mongoose has received new HTTP request.
60   // If callback returns non-zero,
61   // callback must process the request by sending valid HTTP headers and body,
62   // and mongoose will not do any further processing.
63   // If callback returns 0, mongoose processes the request itself. In this case,
64   // callback must not send any data to the client.
65   int  (*begin_request)(struct mg_connection *);
66
67   // Called when mongoose has finished processing request.
68   void (*end_request)(const struct mg_connection *, int reply_status_code);
69
70   // Called when mongoose is about to log a message. If callback returns
71   // non-zero, mongoose does not log anything.
72   int  (*log_message)(const struct mg_connection *, const char *message);
73
74   // Called when mongoose initializes SSL library.
75   int  (*init_ssl)(void *ssl_context, void *user_data);
76
77   // Called when websocket request is received, before websocket handshake.
78   // If callback returns 0, mongoose proceeds with handshake, otherwise
79   // cinnection is closed immediately.
80   int (*websocket_connect)(const struct mg_connection *);
81
82   // Called when websocket handshake is successfully completed, and
83   // connection is ready for data exchange.
84   void (*websocket_ready)(struct mg_connection *);
85
86   // Called when data frame has been received from the client.
87   // Parameters:
88   //    bits: first byte of the websocket frame, see websocket RFC at
89   //          http://tools.ietf.org/html/rfc6455, section 5.2
90   //    data, data_len: payload, with mask (if any) already applied.
91   // Return value:
92   //    non-0: keep this websocket connection opened.
93   //    0:     close this websocket connection.
94   int  (*websocket_data)(struct mg_connection *, int bits,
95                     char *data, size_t data_len);
96
97   // Called when mongoose tries to open a file. Used to intercept file open
98   // calls, and serve file data from memory instead.
99   // Parameters:
100   //    path:     Full path to the file to open.
101   //    data_len: Placeholder for the file size, if file is served from memory.
102   // Return value:
103   //    NULL: do not serve file from memory, proceed with normal file open.
104   //    non-NULL: pointer to the file contents in memory. data_len must be
105   //              initilized with the size of the memory block.
106   const char * (*open_file)(const struct mg_connection *,
107                        const char *path, size_t *data_len);
108
109   // Called when mongoose is about to serve Lua server page (.lp file), if
110   // Lua support is enabled.
111   // Parameters:
112   //   lua_context: "lua_State *" pointer.
113   void (*init_lua)(struct mg_connection *, void *lua_context);
114
115   // Called when mongoose has uploaded a file to a temporary directory as a
116   // result of mg_upload() call.
117   // Parameters:
118   //    file_file: full path name to the uploaded file.
119   void (*upload)(struct mg_connection *, const char *file_name);
120
121   // Called when mongoose is about to send HTTP error to the client.
122   // Implementing this callback allows to create custom error pages.
123   // Parameters:
124   //   status: HTTP error status code.
125   int  (*http_error)(struct mg_connection *, int status);
61struct mg_server; // Opaque structure describing server instance
62enum mg_result { MG_FALSE, MG_TRUE, MG_MORE };
63enum mg_event {
64  MG_POLL = 100,  // Callback return value is ignored
65  MG_CONNECT,     // If callback returns MG_FALSE, connect fails
66  MG_AUTH,        // If callback returns MG_FALSE, authentication fails
67  MG_REQUEST,     // If callback returns MG_FALSE, Mongoose continues with req
68  MG_REPLY,       // If callback returns MG_FALSE, Mongoose closes connection
69  MG_CLOSE,       // Connection is closed, callback return value is ignored
70  MG_WS_HANDSHAKE,  // New websocket connection, handshake request
71  MG_HTTP_ERROR   // If callback returns MG_FALSE, Mongoose continues with err
12672};
73typedef int (*mg_handler_t)(struct mg_connection *, enum mg_event);
12774
128// Start web server.
129//
130// Parameters:
131//   callbacks: mg_callbacks structure with user-defined callbacks.
132//   options: NULL terminated list of option_name, option_value pairs that
133//            specify Mongoose configuration parameters.
134//
135// Side-effects: on UNIX, ignores SIGCHLD and SIGPIPE signals. If custom
136//    processing is required for these, signal handlers must be set up
137//    after calling mg_start().
138//
139//
140// Example:
141//   const char *options[] = {
142//     "document_root", "/var/www",
143//     "listening_ports", "80,443s",
144//     NULL
145//   };
146//   struct mg_context *ctx = mg_start(&my_func, NULL, options);
147//
148// Refer to https://github.com/valenok/mongoose/blob/master/UserManual.md
149// for the list of valid option and their possible values.
150//
151// Return:
152//   web server context, or NULL on error.
153struct mg_context *mg_start(const struct mg_callbacks *callbacks,
154                     void *user_data,
155                     const char **configuration_options);
156
157
158// Stop the web server.
159//
160// Must be called last, when an application wants to stop the web server and
161// release all associated resources. This function blocks until all Mongoose
162// threads are stopped. Context pointer becomes invalid.
163void mg_stop(struct mg_context *);
164
165
166// Get the value of particular configuration parameter.
167// The value returned is read-only. Mongoose does not allow changing
168// configuration at run time.
169// If given parameter name is not valid, NULL is returned. For valid
170// names, return value is guaranteed to be non-NULL. If parameter is not
171// set, zero-length string is returned.
172const char *mg_get_option(const struct mg_context *ctx, const char *name);
173
174
175// Return array of strings that represent valid configuration options.
176// For each option, a short name, long name, and default value is returned.
177// Array is NULL terminated.
178const char **mg_get_valid_option_names(void);
179
180
181// Add, edit or delete the entry in the passwords file.
182//
183// This function allows an application to manipulate .htpasswd files on the
184// fly by adding, deleting and changing user records. This is one of the
185// several ways of implementing authentication on the server side. For another,
186// cookie-based way please refer to the examples/chat.c in the source tree.
187//
188// If password is not NULL, entry is added (or modified if already exists).
189// If password is NULL, entry is deleted.
190//
191// Return:
192//   1 on success, 0 on error.
193int mg_modify_passwords_file(const char *passwords_file_name,
194                        const char *domain,
195                        const char *user,
196                        const char *password);
197
198
199// Return information associated with the request.
200struct mg_request_info *mg_get_request_info(struct mg_connection *);
201
202
203// Send data to the client.
204// Return:
205//  0   when the connection has been closed
206//  -1  on error
207//  >0  number of bytes written on success
208int mg_write(struct mg_connection *, const void *buf, size_t len);
209
210
211// Send data to a websocket client wrapped in a websocket frame.
212// It is unsafe to read/write to this connection from another thread.
213// This function is available when mongoose is compiled with -DUSE_WEBSOCKET
214//
215// Return:
216//  0   when the connection has been closed
217//  -1  on error
218//  >0  number of bytes written on success
219int mg_websocket_write(struct mg_connection* conn, int opcode,
220                  const char *data, size_t data_len);
221
222// Opcodes, from http://tools.ietf.org/html/rfc6455
75// Websocket opcodes, from http://tools.ietf.org/html/rfc6455
22376enum {
224   WEBSOCKET_OPCODE_CONTINUATION = 0x0,
225   WEBSOCKET_OPCODE_TEXT = 0x1,
226   WEBSOCKET_OPCODE_BINARY = 0x2,
227   WEBSOCKET_OPCODE_CONNECTION_CLOSE = 0x8,
228   WEBSOCKET_OPCODE_PING = 0x9,
229   WEBSOCKET_OPCODE_PONG = 0xa
77  WEBSOCKET_OPCODE_CONTINUATION = 0x0,
78  WEBSOCKET_OPCODE_TEXT = 0x1,
79  WEBSOCKET_OPCODE_BINARY = 0x2,
80  WEBSOCKET_OPCODE_CONNECTION_CLOSE = 0x8,
81  WEBSOCKET_OPCODE_PING = 0x9,
82  WEBSOCKET_OPCODE_PONG = 0xa
23083};
23184
85// Server management functions
86struct mg_server *mg_create_server(void *server_param, mg_handler_t handler);
87void mg_destroy_server(struct mg_server **);
88const char *mg_set_option(struct mg_server *, const char *opt, const char *val);
89int mg_poll_server(struct mg_server *, int milliseconds);
90const char **mg_get_valid_option_names(void);
91const char *mg_get_option(const struct mg_server *server, const char *name);
92void mg_set_listening_socket(struct mg_server *, int sock);
93int mg_get_listening_socket(struct mg_server *);
94void mg_iterate_over_connections(struct mg_server *, mg_handler_t, void *);
95void mg_wakeup_server(struct mg_server *);
96void mg_wakeup_server_ex(struct mg_server *, mg_handler_t, const char *, ...);
97struct mg_connection *mg_connect(struct mg_server *, const char *, int, int);
23298
233// Macros for enabling compiler-specific checks for printf-like arguments.
234#undef PRINTF_FORMAT_STRING
235#if defined(_MSC_VER) && (_MSC_VER >= 1400)
236#include <sal.h>
237#if defined(_MSC_VER) && (_MSC_VER > 1400)
238#define PRINTF_FORMAT_STRING(s) _Printf_format_string_ s
239#else
240#define PRINTF_FORMAT_STRING(s) __format_string s
241#endif
242#else
243#define PRINTF_FORMAT_STRING(s) s
244#endif
99// Connection management functions
100void mg_send_status(struct mg_connection *, int status_code);
101void mg_send_header(struct mg_connection *, const char *name, const char *val);
102void mg_send_data(struct mg_connection *, const void *data, int data_len);
103void mg_printf_data(struct mg_connection *, const char *format, ...);
245104
246#ifdef __GNUC__
247#define PRINTF_ARGS(x, y) __attribute__((format(printf, x, y)))
248#else
249#define PRINTF_ARGS(x, y)
250#endif
105int mg_websocket_write(struct mg_connection *, int opcode,
106                       const char *data, size_t data_len);
107int mg_websocket_printf(struct mg_connection* conn, int opcode,
108                        const char *fmt, ...);
251109
252// Send data to the client using printf() semantics.
253//
254// Works exactly like mg_write(), but allows to do message formatting.
255int mg_printf(struct mg_connection *,
256            PRINTF_FORMAT_STRING(const char *fmt), ...) PRINTF_ARGS(2, 3);
110// Deprecated in favor of mg_send_* interface
111int mg_write(struct mg_connection *, const void *buf, int len);
112int mg_printf(struct mg_connection *conn, const char *fmt, ...);
257113
258
259// Send contents of the entire file together with HTTP headers.
260void mg_send_file(struct mg_connection *conn, const char *path);
261
262
263// Read data from the remote end, return number of bytes read.
264// Return:
265//   0     connection has been closed by peer. No more data could be read.
266//   < 0   read error. No more data could be read from the connection.
267//   > 0   number of bytes read into the buffer.
268int mg_read(struct mg_connection *, void *buf, size_t len);
269
270
271// Get the value of particular HTTP header.
272//
273// This is a helper function. It traverses request_info->http_headers array,
274// and if the header is present in the array, returns its value. If it is
275// not present, NULL is returned.
276114const char *mg_get_header(const struct mg_connection *, const char *name);
115const char *mg_get_mime_type(const char *name, const char *default_mime_type);
116int mg_get_var(const struct mg_connection *conn, const char *var_name,
117               char *buf, size_t buf_len);
118int mg_parse_header(const char *hdr, const char *var_name, char *buf, size_t);
119int mg_parse_multipart(const char *buf, int buf_len,
120                       char *var_name, int var_name_len,
121                       char *file_name, int file_name_len,
122                       const char **data, int *data_len);
277123
278
279// Get a value of particular form variable.
280//
281// Parameters:
282//   data: pointer to form-uri-encoded buffer. This could be either POST data,
283//         or request_info.query_string.
284//   data_len: length of the encoded data.
285//   var_name: variable name to decode from the buffer
286//   dst: destination buffer for the decoded variable
287//   dst_len: length of the destination buffer
288//
289// Return:
290//   On success, length of the decoded variable.
291//   On error:
292//      -1 (variable not found).
293//      -2 (destination buffer is NULL, zero length or too small to hold the
294//          decoded variable).
295//
296// Destination buffer is guaranteed to be '\0' - terminated if it is not
297// NULL or zero length.
298int mg_get_var(const char *data, size_t data_len,
299            const char *var_name, char *dst, size_t dst_len);
300
301// Fetch value of certain cookie variable into the destination buffer.
302//
303// Destination buffer is guaranteed to be '\0' - terminated. In case of
304// failure, dst[0] == '\0'. Note that RFC allows many occurrences of the same
305// parameter. This function returns only first occurrence.
306//
307// Return:
308//   On success, value length.
309//   On error:
310//      -1 (either "Cookie:" header is not present at all or the requested
311//          parameter is not found).
312//      -2 (destination buffer is NULL, zero length or too small to hold the
313//          value).
314int mg_get_cookie(const char *cookie, const char *var_name,
315               char *buf, size_t buf_len);
316
317
318// Download data from the remote web server.
319//   host: host name to connect to, e.g. "foo.com", or "10.12.40.1".
320//   port: port number, e.g. 80.
321//   use_ssl: wether to use SSL connection.
322//   error_buffer, error_buffer_size: error message placeholder.
323//   request_fmt,...: HTTP request.
324// Return:
325//   On success, valid pointer to the new connection, suitable for mg_read().
326//   On error, NULL. error_buffer contains error message.
327// Example:
328//   char ebuf[100];
329//   struct mg_connection *conn;
330//   conn = mg_download("google.com", 80, 0, ebuf, sizeof(ebuf),
331//                      "%s", "GET / HTTP/1.0\r\nHost: google.com\r\n\r\n");
332struct mg_connection *mg_download(const char *host, int port, int use_ssl,
333                           char *error_buffer, size_t error_buffer_size,
334                           PRINTF_FORMAT_STRING(const char *request_fmt),
335                           ...) PRINTF_ARGS(6, 7);
336
337
338// Close the connection opened by mg_download().
339void mg_close_connection(struct mg_connection *conn);
340
341
342// File upload functionality. Each uploaded file gets saved into a temporary
343// file and MG_UPLOAD event is sent.
344// Return number of uploaded files.
345int mg_upload(struct mg_connection *conn, const char *destination_dir);
346
347
348// Convenience function -- create detached thread.
349// Return: 0 on success, non-0 on error.
350typedef void * (*mg_thread_func_t)(void *);
351int mg_start_thread(mg_thread_func_t f, void *p);
352
353
354// Return builtin mime type for the given file name.
355// For unrecognized extensions, "text/plain" is returned.
356const char *mg_get_builtin_mime_type(const char *file_name);
357
358
359// Return Mongoose version.
360const char *mg_version(void);
361
362// URL-decode input buffer into destination buffer.
363// 0-terminate the destination buffer.
364// form-url-encoded data differs from URI encoding in a way that it
365// uses '+' as character for space, see RFC 1866 section 8.2.1
366// http://ftp.ics.uci.edu/pub/ietf/html/rfc1866.txt
367// Return: length of the decoded data, or -1 if dst buffer is too small.
368int mg_url_decode(const char *src, int src_len, char *dst,
369               int dst_len, int is_form_url_encoded);
370
371// MD5 hash given strings.
372// Buffer 'buf' must be 33 bytes long. Varargs is a NULL terminated list of
373// ASCIIz strings. When function returns, buf will contain human-readable
374// MD5 hash. Example:
375//   char buf[33];
376//   mg_md5(buf, "aa", "bb", NULL);
124// Utility functions
125void *mg_start_thread(void *(*func)(void *), void *param);
377126char *mg_md5(char buf[33], ...);
127int mg_authorize_digest(struct mg_connection *c, FILE *fp);
128int mg_url_encode(const char *src, size_t s_len, char *dst, size_t dst_len);
129int mg_url_decode(const char *src, int src_len, char *dst, int dst_len, int);
378130
131// Templates support
132struct mg_expansion {
133  const char *keyword;
134  void (*handler)(struct mg_connection *);
135};
136void mg_template(struct mg_connection *, const char *text,
137                 struct mg_expansion *expansions);
379138
139
380140#ifdef __cplusplus
381141}
382142#endif // __cplusplus
trunk/src/lib/web/mongoose.c
r30716r30717
1// Copyright (c) 2004-2013 Sergey Lyubka
1// Copyright (c) 2004-2013 Sergey Lyubka <valenok@gmail.com>
2// Copyright (c) 2013-2014 Cesanta Software Limited
3// All rights reserved
24//
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:
5// This library is dual-licensed: you can redistribute it and/or modify
6// it under the terms of the GNU General Public License version 2 as
7// published by the Free Software Foundation. For the terms of this
8// license, see <http://www.gnu.org/licenses/>.
99//
10// The above copyright notice and this permission notice shall be included in
11// all copies or substantial portions of the Software.
10// You are free to use this library under the terms of the GNU General
11// Public License, but WITHOUT ANY WARRANTY; without even the implied
12// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13// See the GNU General Public License for more details.
1214//
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.
15// Alternatively, you can license this library under a commercial
16// license, as set out in <http://cesanta.com/>.
2017
21#define NO_SSL
22#define USE_WEBSOCKET
23
24#if defined(_WIN32)
25#define SETSOCKOPT_CAST const char *
18#ifdef NOEMBED_NET_SKELETON
19#include "net_skeleton.h"
2620#else
27#define SETSOCKOPT_CAST void *
28#endif
21// net_skeleton start
22// Copyright (c) 2014 Cesanta Software Limited
23// All rights reserved
24//
25// This software is dual-licensed: you can redistribute it and/or modify
26// it under the terms of the GNU General Public License version 2 as
27// published by the Free Software Foundation. For the terms of this
28// license, see <http://www.gnu.org/licenses/>.
29//
30// You are free to use this software under the terms of the GNU General
31// Public License, but WITHOUT ANY WARRANTY; without even the implied
32// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
33// See the GNU General Public License for more details.
34//
35// Alternatively, you can license this software under a commercial
36// license, as set out in <http://cesanta.com/>.
2937
30#if defined(_WIN32)
31#if !defined(_CRT_SECURE_NO_WARNINGS)
32#define _CRT_SECURE_NO_WARNINGS // Disable deprecation warning in VS2005
33#endif
34#else
35#ifdef __linux__
36#define _XOPEN_SOURCE 600     // For flockfile() on Linux
37#endif
38#define _LARGEFILE_SOURCE     // Enable 64-bit file offsets
39#define __STDC_FORMAT_MACROS  // <inttypes.h> wants this for C++
40#define __STDC_LIMIT_MACROS   // C++ wants that for INT64_MAX
41#endif
38#ifndef NS_SKELETON_HEADER_INCLUDED
39#define NS_SKELETON_HEADER_INCLUDED
4240
43#if defined (_MSC_VER)
44// conditional expression is constant: introduced by FD_SET(..)
45#pragma warning (disable : 4127)
46// non-constant aggregate initializer: issued due to missing C99 support
47#pragma warning (disable : 4204)
48#endif
41#define NS_SKELETON_VERSION "1.1"
4942
50// Disable WIN32_LEAN_AND_MEAN.
51// This makes windows.h always include winsock2.h
52#ifdef WIN32_LEAN_AND_MEAN
53#undef WIN32_LEAN_AND_MEAN
43#undef UNICODE                  // Use ANSI WinAPI functions
44#undef _UNICODE                 // Use multibyte encoding on Windows
45#define _MBCS                   // Use multibyte encoding on Windows
46#define _INTEGRAL_MAX_BITS 64   // Enable _stati64() on Windows
47#define _CRT_SECURE_NO_WARNINGS // Disable deprecation warning in VS2005+
48#undef WIN32_LEAN_AND_MEAN      // Let windows.h always include winsock2.h
49#define _XOPEN_SOURCE 600       // For flockfile() on Linux
50#define __STDC_FORMAT_MACROS    // <inttypes.h> wants this for C++
51#define __STDC_LIMIT_MACROS     // C++ wants that for INT64_MAX
52#define _LARGEFILE_SOURCE       // Enable fseeko() and ftello() functions
53#define _FILE_OFFSET_BITS 64    // Enable 64-bit file offsets
54
55#ifdef _MSC_VER
56#pragma warning (disable : 4127)  // FD_SET() emits warning, disable it
57#pragma warning (disable : 4204)  // missing c99 support
5458#endif
5559
56#if defined(__SYMBIAN32__)
57#define NO_SSL // SSL is not supported
58#define NO_CGI // CGI is not supported
59#define PATH_MAX FILENAME_MAX
60#endif // __SYMBIAN32__
61
62#ifndef _WIN32_WCE // Some ANSI #includes are not available on Windows CE
6360#include <sys/types.h>
6461#include <sys/stat.h>
62#include <assert.h>
6563#include <errno.h>
66#include <signal.h>
6764#include <fcntl.h>
68#endif // !_WIN32_WCE
69
70#include <time.h>
71#include <stdlib.h>
7265#include <stdarg.h>
73#include <assert.h>
74#include <string.h>
75#include <ctype.h>
76#include <limits.h>
7766#include <stddef.h>
7867#include <stdio.h>
68#include <stdlib.h>
69#include <string.h>
70#include <time.h>
71#include <signal.h>
7972
80#if defined(_WIN32) && !defined(__SYMBIAN32__) // Windows specific
81#undef _WIN32_WINNT
82#define _WIN32_WINNT 0x0400 // To make it link in VS2005
83#include <windows.h>
84
85#ifndef PATH_MAX
86#define PATH_MAX MAX_PATH
73#ifdef _WIN32
74#ifdef _MSC_VER
75#pragma comment(lib, "ws2_32.lib")    // Linking with winsock library
8776#endif
88
89#ifndef _WIN32_WCE
77#include <windows.h>
9078#include <process.h>
91#include <direct.h>
92#include <io.h>
93#else // _WIN32_WCE
94#define NO_CGI // WinCE has no pipes
95
96typedef long off_t;
97
98#define errno   GetLastError()
99#define strerror(x)  _ultoa(x, (char *) _alloca(sizeof(x) *3 ), 10)
100#endif // _WIN32_WCE
101
102#define MAKEUQUAD(lo, hi) ((uint64_t)(((uint32_t)(lo)) | \
103      ((uint64_t)((uint32_t)(hi))) << 32))
104#define RATE_DIFF 10000000 // 100 nsecs
105#define EPOCH_DIFF MAKEUQUAD(0xd53e8000, 0x019db1de)
106#define SYS2UNIX_TIME(lo, hi) \
107   (time_t) ((MAKEUQUAD((lo), (hi)) - EPOCH_DIFF) / RATE_DIFF)
108
109// Visual Studio 6 does not know __func__ or __FUNCTION__
110// The rest of MS compilers use __FUNCTION__, not C99 __func__
111// Also use _strtoui64 on modern M$ compilers
112#if defined(_MSC_VER) && _MSC_VER < 1300
79#ifndef EINPROGRESS
80#define EINPROGRESS WSAEINPROGRESS
81#endif
82#ifndef EWOULDBLOCK
83#define EWOULDBLOCK WSAEWOULDBLOCK
84#endif
85#ifndef __func__
11386#define STRX(x) #x
11487#define STR(x) STRX(x)
11588#define __func__ __FILE__ ":" STR(__LINE__)
116#define strtoull(x, y, z) (unsigned __int64) _atoi64(x)
117#define strtoll(x, y, z) _atoi64(x)
118#else
119#define __func__  __FUNCTION__
120#define strtoull(x, y, z) _strtoui64(x, y, z)
121#define strtoll(x, y, z) _strtoi64(x, y, z)
122#endif // _MSC_VER
123
124#define ERRNO   GetLastError()
125#define NO_SOCKLEN_T
126#define SSL_LIB   "ssleay32.dll"
127#define CRYPTO_LIB  "libeay32.dll"
128#define O_NONBLOCK  0
129#if !defined(EWOULDBLOCK)
130#define EWOULDBLOCK  WSAEWOULDBLOCK
131#endif // !EWOULDBLOCK
132#define _POSIX_
133#define INT64_FMT  "I64d"
134
135#define WINCDECL __cdecl
136#define SHUT_WR 1
89#endif
90#ifndef va_copy
91#define va_copy(x,y) x = y
92#endif // MINGW #defines va_copy
13793#define snprintf _snprintf
13894#define vsnprintf _vsnprintf
139#define mg_sleep(x) Sleep(x)
140
141#define pipe(x) _pipe(x, MG_BUF_LEN, _O_BINARY)
142#ifndef popen
143#define popen(x, y) _popen(x, y)
144#endif
145#ifndef pclose
146#define pclose(x) _pclose(x)
147#endif
148#define close(x) _close(x)
149#define dlsym(x,y) GetProcAddress((HINSTANCE) (x), (y))
150#define RTLD_LAZY  0
151#define fseeko(x, y, z) _lseeki64(_fileno(x), (y), (z))
152#define fdopen(x, y) _fdopen((x), (y))
153#define write(x, y, z) _write((x), (y), (unsigned) z)
154#define read(x, y, z) _read((x), (y), (unsigned) z)
155#define flockfile(x) EnterCriticalSection(&global_log_file_lock)
156#define funlockfile(x) LeaveCriticalSection(&global_log_file_lock)
15795#define sleep(x) Sleep((x) * 1000)
158
159#if !defined(va_copy)
160#define va_copy(x, y) x = y
161#endif // !va_copy MINGW #defines va_copy
162
163#if !defined(fileno)
164#define fileno(x) _fileno(x)
165#endif // !fileno MINGW #defines fileno
166
167typedef HANDLE pthread_mutex_t;
168typedef struct {HANDLE signal, broadcast;} pthread_cond_t;
169typedef DWORD pthread_t;
170#define pid_t HANDLE // MINGW typedefs pid_t to int. Using #define here.
171
172static int pthread_mutex_lock(pthread_mutex_t *);
173static int pthread_mutex_unlock(pthread_mutex_t *);
174static void to_unicode(const char *path, wchar_t *wbuf, size_t wbuf_len);
175struct file;
176static char *mg_fgets(char *buf, size_t size, struct file *filep, char **p);
177
178#if defined(HAVE_STDINT)
179#include <stdint.h>
180#else
181typedef unsigned int  uint32_t;
182typedef unsigned short  uint16_t;
96#define to64(x) _atoi64(x)
97typedef int socklen_t;
98typedef unsigned char uint8_t;
99typedef unsigned int uint32_t;
100typedef unsigned short uint16_t;
183101typedef unsigned __int64 uint64_t;
184102typedef __int64   int64_t;
185#if defined(__GNUC__) || defined(_MSC_VER)
186#define U64(val) val##ULL
103typedef SOCKET sock_t;
187104#else
188#define U64(val) val
189#endif
190#define INT64_MAX  U64(9223372036854775807)
191#endif // HAVE_STDINT
192
193// POSIX dirent interface
194struct dirent {
195   char d_name[PATH_MAX];
196};
197
198typedef struct DIR {
199   HANDLE   handle;
200   WIN32_FIND_DATAW info;
201   struct dirent  result;
202} DIR;
203
204
205// Mark required libraries
206#ifdef _MSC_VER
207#pragma comment(lib, "Ws2_32.lib")
208#endif
209
210#else    // UNIX  specific
211#include <sys/wait.h>
212#include <sys/socket.h>
213#ifdef HAVE_POLL
214#include <sys/poll.h>
215#endif
216#include <netinet/in.h>
217#include <arpa/inet.h>
218#include <sys/time.h>
219#include <stdint.h>
220#include <inttypes.h>
105#include <errno.h>
106#include <fcntl.h>
221107#include <netdb.h>
222
223#include <pwd.h>
224#include <unistd.h>
225#include <dirent.h>
226#if !defined(NO_SSL_DL) && !defined(NO_SSL)
227#include <dlfcn.h>
228#endif
229108#include <pthread.h>
230#if defined(__MACH__)
231#define SSL_LIB   "libssl.dylib"
232#define CRYPTO_LIB  "libcrypto.dylib"
233#else
234#if !defined(SSL_LIB)
235#define SSL_LIB   "libssl.so"
236#endif
237#if !defined(CRYPTO_LIB)
238#define CRYPTO_LIB  "libcrypto.so"
239#endif
240#endif
241#ifndef O_BINARY
242#define O_BINARY  0
243#endif // O_BINARY
244#define closesocket(a) close(a)
245#define mg_mkdir(x, y) mkdir(x, y)
246#define mg_remove(x) remove(x)
247#define mg_sleep(x) usleep((x) * 1000)
248#define ERRNO errno
109#include <stdarg.h>
110#include <unistd.h>
111#include <arpa/inet.h>  // For inet_pton() when NS_ENABLE_IPV6 is defined
112#include <netinet/in.h>
113#include <sys/socket.h>
114#include <sys/select.h>
115#define closesocket(x) close(x)
116#define __cdecl
249117#define INVALID_SOCKET (-1)
250#define INT64_FMT PRId64
251typedef int SOCKET;
252#define WINCDECL
253
254#endif // End of Windows and UNIX specific includes
255
256#ifdef __OS2__
257#define NO_SOCKLEN_T
258#define SHUT_WR 1
118#define to64(x) strtoll(x, NULL, 10)
119typedef int sock_t;
259120#endif
260121
261#ifndef HAVE_POLL
262struct pollfd {
263   int fd;
264   short events;
265   short revents;
266};
267#define POLLIN 1
122#ifdef NS_ENABLE_DEBUG
123#define DBG(x) do { printf("%-20s ", __func__); printf x; putchar('\n'); \
124  fflush(stdout); } while(0)
125#else
126#define DBG(x)
268127#endif
269128
270#include "mongoose.h"
271
272#define MONGOOSE_VERSION "3.8"
273#define PASSWORDS_FILE_NAME ".htpasswd"
274#define CGI_ENVIRONMENT_SIZE 4096
275#define MAX_CGI_ENVIR_VARS 64
276#define MG_BUF_LEN 8192
277#define MAX_REQUEST_SIZE 16384
278129#define ARRAY_SIZE(array) (sizeof(array) / sizeof(array[0]))
279130
280#ifdef _WIN32
281static CRITICAL_SECTION global_log_file_lock;
282#if !defined(NO_SSL)
283static pthread_t pthread_self(void) {
284   return GetCurrentThreadId();
285}
131#ifdef NS_ENABLE_SSL
132#ifdef __APPLE__
133#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
286134#endif
287#endif // _WIN32
288
289#ifdef DEBUG_TRACE
290#undef DEBUG_TRACE
291#define DEBUG_TRACE(x)
135#include <openssl/ssl.h>
292136#else
293#if defined(DEBUG)
294#define DEBUG_TRACE(x) do { \
295   flockfile(stdout); \
296   printf("*** %lu.%p.%s.%d: ", \
297         (unsigned long) time(NULL), (void *) pthread_self(), \
298         __func__, __LINE__); \
299   printf x; \
300   putchar('\n'); \
301   fflush(stdout); \
302   funlockfile(stdout); \
303} while (0)
304#else
305#define DEBUG_TRACE(x)
306#endif // DEBUG
307#endif // DEBUG_TRACE
308
309// Darwin prior to 7.0 and Win32 do not have socklen_t
310#ifdef NO_SOCKLEN_T
311typedef int socklen_t;
312#endif // NO_SOCKLEN_T
313#define _DARWIN_UNLIMITED_SELECT
314
315#define IP_ADDR_STR_LEN 50  // IPv6 hex string is 46 chars
316
317#if !defined(MSG_NOSIGNAL)
318#define MSG_NOSIGNAL 0
137typedef void *SSL;
138typedef void *SSL_CTX;
319139#endif
320140
321#if !defined(SOMAXCONN)
322#define SOMAXCONN 100
323#endif
141#ifdef __cplusplus
142extern "C" {
143#endif // __cplusplus
324144
325#if !defined(PATH_MAX)
326#define PATH_MAX 4096
145union socket_address {
146  struct sockaddr sa;
147  struct sockaddr_in sin;
148#ifdef NS_ENABLE_IPV6
149  struct sockaddr_in6 sin6;
327150#endif
151};
328152
329static const char *http_500_error = "Internal Server Error";
153// IO buffers interface
154struct iobuf {
155  char *buf;
156  size_t len;
157  size_t size;
158};
330159
331#if defined(NO_SSL_DL)
332#include <openssl/ssl.h>
333#else
334// SSL loaded dynamically from DLL.
335// I put the prototypes here to be independent from OpenSSL source installation.
336typedef struct ssl_st SSL;
337typedef struct ssl_method_st SSL_METHOD;
338typedef struct ssl_ctx_st SSL_CTX;
160void iobuf_init(struct iobuf *, size_t initial_size);
161void iobuf_free(struct iobuf *);
162size_t iobuf_append(struct iobuf *, const void *data, size_t data_size);
163void iobuf_remove(struct iobuf *, size_t data_size);
339164
340struct ssl_func {
341   const char *name;   // SSL function name
342   void  (*ptr)(void); // Function pointer
165// Net skeleton interface
166// Events. Meaning of event parameter (evp) is given in the comment.
167enum ns_event {
168  NS_POLL,     // Sent to each connection on each call to ns_server_poll()
169  NS_ACCEPT,   // New connection accept()-ed. union socket_address *remote_addr
170  NS_CONNECT,  // connect() succeeded or failed. int *success_status
171  NS_RECV,     // Data has benn received. int *num_bytes
172  NS_SEND,     // Data has been written to a socket. int *num_bytes
173  NS_CLOSE     // Connection is closed. NULL
343174};
344175
345#define SSL_free (* (void (*)(SSL *)) ssl_sw[0].ptr)
346#define SSL_accept (* (int (*)(SSL *)) ssl_sw[1].ptr)
347#define SSL_connect (* (int (*)(SSL *)) ssl_sw[2].ptr)
348#define SSL_read (* (int (*)(SSL *, void *, int)) ssl_sw[3].ptr)
349#define SSL_write (* (int (*)(SSL *, const void *,int)) ssl_sw[4].ptr)
350#define SSL_get_error (* (int (*)(SSL *, int)) ssl_sw[5].ptr)
351#define SSL_set_fd (* (int (*)(SSL *, SOCKET)) ssl_sw[6].ptr)
352#define SSL_new (* (SSL * (*)(SSL_CTX *)) ssl_sw[7].ptr)
353#define SSL_CTX_new (* (SSL_CTX * (*)(SSL_METHOD *)) ssl_sw[8].ptr)
354#define SSLv23_server_method (* (SSL_METHOD * (*)(void)) ssl_sw[9].ptr)
355#define SSL_library_init (* (int (*)(void)) ssl_sw[10].ptr)
356#define SSL_CTX_use_PrivateKey_file (* (int (*)(SSL_CTX *, \
357      const char *, int)) ssl_sw[11].ptr)
358#define SSL_CTX_use_certificate_file (* (int (*)(SSL_CTX *, \
359      const char *, int)) ssl_sw[12].ptr)
360#define SSL_CTX_set_default_passwd_cb \
361   (* (void (*)(SSL_CTX *, mg_callback_t)) ssl_sw[13].ptr)
362#define SSL_CTX_free (* (void (*)(SSL_CTX *)) ssl_sw[14].ptr)
363#define SSL_load_error_strings (* (void (*)(void)) ssl_sw[15].ptr)
364#define SSL_CTX_use_certificate_chain_file \
365   (* (int (*)(SSL_CTX *, const char *)) ssl_sw[16].ptr)
366#define SSLv23_client_method (* (SSL_METHOD * (*)(void)) ssl_sw[17].ptr)
367#define SSL_pending (* (int (*)(SSL *)) ssl_sw[18].ptr)
368#define SSL_CTX_set_verify (* (void (*)(SSL_CTX *, int, int)) ssl_sw[19].ptr)
369#define SSL_shutdown (* (int (*)(SSL *)) ssl_sw[20].ptr)
176// Callback function (event handler) prototype, must be defined by user.
177// Net skeleton will call event handler, passing events defined above.
178struct ns_connection;
179typedef void (*ns_callback_t)(struct ns_connection *, enum ns_event, void *evp);
370180
371#define CRYPTO_num_locks (* (int (*)(void)) crypto_sw[0].ptr)
372#define CRYPTO_set_locking_callback \
373   (* (void (*)(void (*)(int, int, const char *, int))) crypto_sw[1].ptr)
374#define CRYPTO_set_id_callback \
375   (* (void (*)(unsigned long (*)(void))) crypto_sw[2].ptr)
376#define ERR_get_error (* (unsigned long (*)(void)) crypto_sw[3].ptr)
377#define ERR_error_string (* (char * (*)(unsigned long,char *)) crypto_sw[4].ptr)
378
379// set_ssl_option() function updates this array.
380// It loads SSL library dynamically and changes NULLs to the actual addresses
381// of respective functions. The macros above (like SSL_connect()) are really
382// just calling these functions indirectly via the pointer.
383static struct ssl_func ssl_sw[] = {
384   {"SSL_free",   NULL},
385   {"SSL_accept",   NULL},
386   {"SSL_connect",   NULL},
387   {"SSL_read",   NULL},
388   {"SSL_write",   NULL},
389   {"SSL_get_error",  NULL},
390   {"SSL_set_fd",   NULL},
391   {"SSL_new",   NULL},
392   {"SSL_CTX_new",   NULL},
393   {"SSLv23_server_method", NULL},
394   {"SSL_library_init",  NULL},
395   {"SSL_CTX_use_PrivateKey_file", NULL},
396   {"SSL_CTX_use_certificate_file",NULL},
397   {"SSL_CTX_set_default_passwd_cb",NULL},
398   {"SSL_CTX_free",  NULL},
399   {"SSL_load_error_strings", NULL},
400   {"SSL_CTX_use_certificate_chain_file", NULL},
401   {"SSLv23_client_method", NULL},
402   {"SSL_pending", NULL},
403   {"SSL_CTX_set_verify", NULL},
404   {"SSL_shutdown",   NULL},
405   {NULL,    NULL}
181struct ns_server {
182  void *server_data;
183  sock_t listening_sock;
184  struct ns_connection *active_connections;
185  ns_callback_t callback;
186  SSL_CTX *ssl_ctx;
187  SSL_CTX *client_ssl_ctx;
188  sock_t ctl[2];
406189};
407190
408// Similar array as ssl_sw. These functions could be located in different lib.
409#if !defined(NO_SSL)
410static struct ssl_func crypto_sw[] = {
411   {"CRYPTO_num_locks",  NULL},
412   {"CRYPTO_set_locking_callback", NULL},
413   {"CRYPTO_set_id_callback", NULL},
414   {"ERR_get_error",  NULL},
415   {"ERR_error_string", NULL},
416   {NULL,    NULL}
417};
418#endif // NO_SSL
419#endif // NO_SSL_DL
191struct ns_connection {
192  struct ns_connection *prev, *next;
193  struct ns_server *server;
194  sock_t sock;
195  union socket_address sa;
196  struct iobuf recv_iobuf;
197  struct iobuf send_iobuf;
198  SSL *ssl;
199  void *connection_data;
200  time_t last_io_time;
201  unsigned int flags;
202#define NSF_FINISHED_SENDING_DATA   (1 << 0)
203#define NSF_BUFFER_BUT_DONT_SEND    (1 << 1)
204#define NSF_SSL_HANDSHAKE_DONE      (1 << 2)
205#define NSF_CONNECTING              (1 << 3)
206#define NSF_CLOSE_IMMEDIATELY       (1 << 4)
207#define NSF_ACCEPTED                (1 << 5)
208#define NSF_WANT_READ               (1 << 6)
209#define NSF_WANT_WRITE              (1 << 7)
420210
421static const char *month_names[] = {
422   "Jan", "Feb", "Mar", "Apr", "May", "Jun",
423   "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
211#define NSF_USER_1                  (1 << 26)
212#define NSF_USER_2                  (1 << 27)
213#define NSF_USER_3                  (1 << 28)
214#define NSF_USER_4                  (1 << 29)
215#define NSF_USER_5                  (1 << 30)
216#define NSF_USER_6                  (1 << 31)
424217};
425218
426// Unified socket address. For IPv6 support, add IPv6 address structure
427// in the union u.
428union usa {
429   struct sockaddr sa;
430   struct sockaddr_in sin;
431#if defined(USE_IPV6)
432   struct sockaddr_in6 sin6;
433#endif
434};
219void ns_server_init(struct ns_server *, void *server_data, ns_callback_t);
220void ns_server_free(struct ns_server *);
221int ns_server_poll(struct ns_server *, int milli);
222void ns_server_wakeup(struct ns_server *);
223void ns_server_wakeup_ex(struct ns_server *, ns_callback_t, void *, size_t);
224void ns_iterate(struct ns_server *, ns_callback_t cb, void *param);
225struct ns_connection *ns_add_sock(struct ns_server *, sock_t sock, void *p);
435226
436// Describes a string (chunk of memory).
437struct vec {
438   const char *ptr;
439   size_t len;
440};
227int ns_bind(struct ns_server *, const char *addr);
228int ns_set_ssl_cert(struct ns_server *, const char *ssl_cert);
229int ns_set_ssl_ca_cert(struct ns_server *, const char *ssl_ca_cert);
230struct ns_connection *ns_connect(struct ns_server *, const char *host,
231                                 int port, int ssl, void *connection_param);
441232
442struct file {
443   int is_directory;
444   time_t modification_time;
445   int64_t size;
446   FILE *fp;
447   const char *membuf;   // Non-NULL if file data is in memory
448   // set to 1 if the content is gzipped
449   // in which case we need a content-encoding: gzip header
450   int gzipped;
451};
452#define STRUCT_FILE_INITIALIZER {0, 0, 0, NULL, NULL, 0}
233int ns_send(struct ns_connection *, const void *buf, int len);
234int ns_printf(struct ns_connection *, const char *fmt, ...);
235int ns_vprintf(struct ns_connection *, const char *fmt, va_list ap);
453236
454// Describes listening socket, or socket which was accept()-ed by the master
455// thread and queued for future handling by the worker thread.
456struct socket {
457   SOCKET sock;          // Listening socket
458   union usa lsa;        // Local socket address
459   union usa rsa;        // Remote socket address
460   unsigned is_ssl:1;    // Is port SSL-ed
461   unsigned ssl_redir:1; // Is port supposed to redirect everything to SSL port
462};
237// Utility functions
238void *ns_start_thread(void *(*f)(void *), void *p);
239int ns_socketpair(sock_t [2]);
240int ns_socketpair2(sock_t [2], int sock_type);  // SOCK_STREAM or SOCK_DGRAM
241void ns_set_close_on_exec(sock_t);
242void ns_sock_to_str(sock_t sock, char *buf, size_t len, int flags);
243int ns_hexdump(const void *buf, int len, char *dst, int dst_len);
463244
464// NOTE(lsm): this enum shoulds be in sync with the config_options below.
465enum {
466   CGI_EXTENSIONS, CGI_ENVIRONMENT, PUT_DELETE_PASSWORDS_FILE, CGI_INTERPRETER,
467   PROTECT_URI, AUTHENTICATION_DOMAIN, SSI_EXTENSIONS, THROTTLE,
468   ACCESS_LOG_FILE, ENABLE_DIRECTORY_LISTING, ERROR_LOG_FILE,
469   GLOBAL_PASSWORDS_FILE, INDEX_FILES, ENABLE_KEEP_ALIVE, ACCESS_CONTROL_LIST,
470   EXTRA_MIME_TYPES, LISTENING_PORTS, DOCUMENT_ROOT, SSL_CERTIFICATE,
471   NUM_THREADS, RUN_AS_USER, REWRITE, HIDE_FILES, REQUEST_TIMEOUT,
472   NUM_OPTIONS
473};
245#ifdef __cplusplus
246}
247#endif // __cplusplus
474248
475static const char *config_options[] = {
476   "cgi_pattern", "**.cgi$|**.pl$|**.php$",
477   "cgi_environment", NULL,
478   "put_delete_auth_file", NULL,
479   "cgi_interpreter", NULL,
480   "protect_uri", NULL,
481   "authentication_domain", "mydomain.com",
482   "ssi_pattern", "**.shtml$|**.shtm$",
483   "throttle", NULL,
484   "access_log_file", NULL,
485   "enable_directory_listing", "yes",
486   "error_log_file", NULL,
487   "global_auth_file", NULL,
488   "index_files",
489   "index.html,index.htm,index.cgi,index.shtml,index.php,index.lp",
490   "enable_keep_alive", "no",
491   "access_control_list", NULL,
492   "extra_mime_types", NULL,
493   "listening_ports", "8080",
494   "document_root",  ".",
495   "ssl_certificate", NULL,
496   "num_threads", "50",
497   "run_as_user", NULL,
498   "url_rewrite_patterns", NULL,
499   "hide_files_patterns", NULL,
500   "request_timeout_ms", "30000",
501   NULL
502};
249#endif // NS_SKELETON_HEADER_INCLUDED
250// Copyright (c) 2014 Cesanta Software Limited
251// All rights reserved
252//
253// This software is dual-licensed: you can redistribute it and/or modify
254// it under the terms of the GNU General Public License version 2 as
255// published by the Free Software Foundation. For the terms of this
256// license, see <http://www.gnu.org/licenses/>.
257//
258// You are free to use this software under the terms of the GNU General
259// Public License, but WITHOUT ANY WARRANTY; without even the implied
260// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
261// See the GNU General Public License for more details.
262//
263// Alternatively, you can license this software under a commercial
264// license, as set out in <http://cesanta.com/>.
503265
504struct mg_context {
505   volatile int stop_flag;         // Should we stop event loop
506   SSL_CTX *ssl_ctx;               // SSL context
507   char *config[NUM_OPTIONS];      // Mongoose configuration parameters
508   struct mg_callbacks callbacks;  // User-defined callback function
509   void *user_data;                // User-defined data
510266
511   struct socket *listening_sockets;
512   int num_listening_sockets;
267#ifndef NS_MALLOC
268#define NS_MALLOC malloc
269#endif
513270
514   volatile int num_threads;  // Number of threads
515   pthread_mutex_t mutex;     // Protects (max|num)_threads
516   pthread_cond_t  cond;      // Condvar for tracking workers terminations
271#ifndef NS_REALLOC
272#define NS_REALLOC realloc
273#endif
517274
518   struct socket queue[20];   // Accepted sockets
519   volatile int sq_head;      // Head of the socket queue
520   volatile int sq_tail;      // Tail of the socket queue
521   pthread_cond_t sq_full;    // Signaled when socket is produced
522   pthread_cond_t sq_empty;   // Signaled when socket is consumed
523};
275#ifndef NS_FREE
276#define NS_FREE free
277#endif
524278
525struct mg_connection {
526   struct mg_request_info request_info;
527   struct mg_context *ctx;
528   SSL *ssl;                   // SSL descriptor
529   SSL_CTX *client_ssl_ctx;    // SSL context for client connections
530   struct socket client;       // Connected client
531   time_t birth_time;          // Time when request was received
532   int64_t num_bytes_sent;     // Total bytes sent to client
533   int64_t content_len;        // Content-Length header value
534   int64_t consumed_content;   // How many bytes of content have been read
535   char *buf;                  // Buffer for received data
536   char *path_info;            // PATH_INFO part of the URL
537   int must_close;             // 1 if connection must be closed
538   int buf_size;               // Buffer size
539   int request_len;            // Size of the request + headers in a buffer
540   int data_len;               // Total size of data in a buffer
541   int status_code;            // HTTP reply status code, e.g. 200
542   int throttle;               // Throttling, bytes/sec. <= 0 means no throttle
543   time_t last_throttle_time;  // Last time throttled data was sent
544   int64_t last_throttle_bytes;// Bytes sent this second
279struct ctl_msg {
280  ns_callback_t callback;
281  char message[1024 * 8];
545282};
546283
547// Directory entry
548struct de {
549   struct mg_connection *conn;
550   char *file_name;
551   struct file file;
552};
284void iobuf_init(struct iobuf *iobuf, size_t size) {
285  iobuf->len = iobuf->size = 0;
286  iobuf->buf = NULL;
553287
554const char **mg_get_valid_option_names(void) {
555   return config_options;
288  if (size > 0 && (iobuf->buf = (char *) NS_MALLOC(size)) != NULL) {
289    iobuf->size = size;
290  }
556291}
557292
558static int is_file_in_memory(struct mg_connection *conn, const char *path,
559                        struct file *filep) {
560   size_t size = 0;
561   if ((filep->membuf = conn->ctx->callbacks.open_file == NULL ? NULL :
562      conn->ctx->callbacks.open_file(conn, path, &size)) != NULL) {
563   // NOTE: override filep->size only on success. Otherwise, it might break
564   // constructs like if (!mg_stat() || !mg_fopen()) ...
565   filep->size = size;
566   }
567   return filep->membuf != NULL;
293void iobuf_free(struct iobuf *iobuf) {
294  if (iobuf != NULL) {
295    if (iobuf->buf != NULL) NS_FREE(iobuf->buf);
296    iobuf_init(iobuf, 0);
297  }
568298}
569299
570static int is_file_opened(const struct file *filep) {
571   return filep->membuf != NULL || filep->fp != NULL;
300size_t iobuf_append(struct iobuf *io, const void *buf, size_t len) {
301  char *p = NULL;
302
303  assert(io != NULL);
304  assert(io->len <= io->size);
305
306  if (len <= 0) {
307  } else if (io->len + len <= io->size) {
308    memcpy(io->buf + io->len, buf, len);
309    io->len += len;
310  } else if ((p = (char *) NS_REALLOC(io->buf, io->len + len)) != NULL) {
311    io->buf = p;
312    memcpy(io->buf + io->len, buf, len);
313    io->len += len;
314    io->size = io->len;
315  } else {
316    len = 0;
317  }
318
319  return len;
572320}
573321
574static int mg_fopen(struct mg_connection *conn, const char *path,
575               const char *mode, struct file *filep) {
576   if (!is_file_in_memory(conn, path, filep)) {
322void iobuf_remove(struct iobuf *io, size_t n) {
323  if (n > 0 && n <= io->len) {
324    memmove(io->buf, io->buf + n, io->len - n);
325    io->len -= n;
326  }
327}
328
329#ifndef NS_DISABLE_THREADS
330void *ns_start_thread(void *(*f)(void *), void *p) {
577331#ifdef _WIN32
578   wchar_t wbuf[PATH_MAX], wmode[20];
579   to_unicode(path, wbuf, ARRAY_SIZE(wbuf));
580   MultiByteToWideChar(CP_UTF8, 0, mode, -1, wmode, ARRAY_SIZE(wmode));
581   filep->fp = _wfopen(wbuf, wmode);
332  return (void *) _beginthread((void (__cdecl *)(void *)) f, 0, p);
582333#else
583   filep->fp = fopen(path, mode);
584#endif
585   }
334  pthread_t thread_id = (pthread_t) 0;
335  pthread_attr_t attr;
586336
587   return is_file_opened(filep);
588}
337  (void) pthread_attr_init(&attr);
338  (void) pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
589339
590static void mg_fclose(struct file *filep) {
591   if (filep != NULL && filep->fp != NULL) {
592   fclose(filep->fp);
593   }
594}
340#if NS_STACK_SIZE > 1
341  (void) pthread_attr_setstacksize(&attr, NS_STACK_SIZE);
342#endif
595343
596static int get_option_index(const char *name) {
597   int i;
344  pthread_create(&thread_id, &attr, f, p);
345  pthread_attr_destroy(&attr);
598346
599   for (i = 0; config_options[i * 2] != NULL; i++) {
600   if (strcmp(config_options[i * 2], name) == 0) {
601      return i;
602   }
603   }
604   return -1;
347  return (void *) thread_id;
348#endif
605349}
350#endif  // NS_DISABLE_THREADS
606351
607const char *mg_get_option(const struct mg_context *ctx, const char *name) {
608   int i;
609   if ((i = get_option_index(name)) == -1) {
610   return NULL;
611   } else if (ctx->config[i] == NULL) {
612   return "";
613   } else {
614   return ctx->config[i];
615   }
352static void ns_add_conn(struct ns_server *server, struct ns_connection *c) {
353  c->next = server->active_connections;
354  server->active_connections = c;
355  c->prev = NULL;
356  if (c->next != NULL) c->next->prev = c;
616357}
617358
618static void sockaddr_to_string(char *buf, size_t len,
619                              const union usa *usa) {
620   buf[0] = '\0';
621#if defined(USE_IPV6)
622   inet_ntop(usa->sa.sa_family, usa->sa.sa_family == AF_INET ?
623         (void *) &usa->sin.sin_addr :
624         (void *) &usa->sin6.sin6_addr, buf, len);
625#elif defined(_WIN32)
626   // Only Windoze Vista (and newer) have inet_ntop()
627   strncpy(buf, inet_ntoa(usa->sin.sin_addr), len);
628#else
629   inet_ntop(usa->sa.sa_family, (void *) &usa->sin.sin_addr, buf, len);
630#endif
359static void ns_remove_conn(struct ns_connection *conn) {
360  if (conn->prev == NULL) conn->server->active_connections = conn->next;
361  if (conn->prev) conn->prev->next = conn->next;
362  if (conn->next) conn->next->prev = conn->prev;
631363}
632364
633static void cry(struct mg_connection *conn,
634            PRINTF_FORMAT_STRING(const char *fmt), ...) PRINTF_ARGS(2, 3);
365// Print message to buffer. If buffer is large enough to hold the message,
366// return buffer. If buffer is to small, allocate large enough buffer on heap,
367// and return allocated buffer.
368static int ns_avprintf(char **buf, size_t size, const char *fmt, va_list ap) {
369  va_list ap_copy;
370  int len;
635371
636// Print error message to the opened error log stream.
637static void cry(struct mg_connection *conn, const char *fmt, ...) {
638   char buf[MG_BUF_LEN], src_addr[IP_ADDR_STR_LEN];
639   va_list ap;
640   FILE *fp;
641   time_t timestamp;
372  va_copy(ap_copy, ap);
373  len = vsnprintf(*buf, size, fmt, ap_copy);
374  va_end(ap_copy);
642375
643   va_start(ap, fmt);
644   (void) vsnprintf(buf, sizeof(buf), fmt, ap);
645   va_end(ap);
376  if (len < 0) {
377    // eCos and Windows are not standard-compliant and return -1 when
378    // the buffer is too small. Keep allocating larger buffers until we
379    // succeed or out of memory.
380    *buf = NULL;
381    while (len < 0) {
382      if (*buf) free(*buf);
383      size *= 2;
384      if ((*buf = (char *) NS_MALLOC(size)) == NULL) break;
385      va_copy(ap_copy, ap);
386      len = vsnprintf(*buf, size, fmt, ap_copy);
387      va_end(ap_copy);
388    }
389  } else if (len > (int) size) {
390    // Standard-compliant code path. Allocate a buffer that is large enough.
391    if ((*buf = (char *) NS_MALLOC(len + 1)) == NULL) {
392      len = -1;
393    } else {
394      va_copy(ap_copy, ap);
395      len = vsnprintf(*buf, len + 1, fmt, ap_copy);
396      va_end(ap_copy);
397    }
398  }
646399
647   // Do not lock when getting the callback value, here and below.
648   // I suppose this is fine, since function cannot disappear in the
649   // same way string option can.
650   if (conn->ctx->callbacks.log_message == NULL ||
651      conn->ctx->callbacks.log_message(conn, buf) == 0) {
652   fp = conn->ctx == NULL || conn->ctx->config[ERROR_LOG_FILE] == NULL ? NULL :
653      fopen(conn->ctx->config[ERROR_LOG_FILE], "a+");
400  return len;
401}
654402
655   if (fp != NULL) {
656      flockfile(fp);
657      timestamp = time(NULL);
403int ns_vprintf(struct ns_connection *conn, const char *fmt, va_list ap) {
404  char mem[2000], *buf = mem;
405  int len;
658406
659      sockaddr_to_string(src_addr, sizeof(src_addr), &conn->client.rsa);
660      fprintf(fp, "[%010lu] [error] [client %s] ", (unsigned long) timestamp,
661            src_addr);
407  if ((len = ns_avprintf(&buf, sizeof(mem), fmt, ap)) > 0) {
408    iobuf_append(&conn->send_iobuf, buf, len);
409  }
410  if (buf != mem && buf != NULL) {
411    free(buf);
412  }
662413
663      if (conn->request_info.request_method != NULL) {
664      fprintf(fp, "%s %s: ", conn->request_info.request_method,
665            conn->request_info.uri);
666      }
667
668      fprintf(fp, "%s", buf);
669      fputc('\n', fp);
670      funlockfile(fp);
671      fclose(fp);
672   }
673   }
414  return len;
674415}
675416
676// Return fake connection structure. Used for logging, if connection
677// is not applicable at the moment of logging.
678static struct mg_connection *fc(struct mg_context *ctx) {
679   static struct mg_connection fake_connection;
680   fake_connection.ctx = ctx;
681   return &fake_connection;
417int ns_printf(struct ns_connection *conn, const char *fmt, ...) {
418  int len;
419  va_list ap;
420  va_start(ap, fmt);
421  len = ns_vprintf(conn, fmt, ap);
422  va_end(ap);
423  return len;
682424}
683425
684const char *mg_version(void) {
685   return MONGOOSE_VERSION;
426static void ns_call(struct ns_connection *conn, enum ns_event ev, void *p) {
427  if (conn->server->callback) conn->server->callback(conn, ev, p);
686428}
687429
688struct mg_request_info *mg_get_request_info(struct mg_connection *conn) {
689   return &conn->request_info;
430static void ns_close_conn(struct ns_connection *conn) {
431  DBG(("%p %d", conn, conn->flags));
432  ns_call(conn, NS_CLOSE, NULL);
433  ns_remove_conn(conn);
434  closesocket(conn->sock);
435  iobuf_free(&conn->recv_iobuf);
436  iobuf_free(&conn->send_iobuf);
437#ifdef NS_ENABLE_SSL
438  if (conn->ssl != NULL) {
439    SSL_free(conn->ssl);
440  }
441#endif
442  NS_FREE(conn);
690443}
691444
692static void mg_strlcpy(register char *dst, register const char *src, size_t n) {
693   for (; *src != '\0' && n > 1; n--) {
694   *dst++ = *src++;
695   }
696   *dst = '\0';
445void ns_set_close_on_exec(sock_t sock) {
446#ifdef _WIN32
447  (void) SetHandleInformation((HANDLE) sock, HANDLE_FLAG_INHERIT, 0);
448#else
449  fcntl(sock, F_SETFD, FD_CLOEXEC);
450#endif
697451}
698452
699static int lowercase(const char *s) {
700   return tolower(* (const unsigned char *) s);
453static void ns_set_non_blocking_mode(sock_t sock) {
454#ifdef _WIN32
455  unsigned long on = 1;
456  ioctlsocket(sock, FIONBIO, &on);
457#else
458  int flags = fcntl(sock, F_GETFL, 0);
459  fcntl(sock, F_SETFL, flags | O_NONBLOCK);
460#endif
701461}
702462
703static int mg_strncasecmp(const char *s1, const char *s2, size_t len) {
704   int diff = 0;
463#ifndef NS_DISABLE_SOCKETPAIR
464int ns_socketpair2(sock_t sp[2], int sock_type) {
465  union socket_address sa;
466  sock_t sock;
467  socklen_t len = sizeof(sa.sin);
468  int ret = 0;
705469
706   if (len > 0)
707   do {
708      diff = lowercase(s1++) - lowercase(s2++);
709   } while (diff == 0 && s1[-1] != '\0' && --len > 0);
470  sp[0] = sp[1] = INVALID_SOCKET;
710471
711   return diff;
712}
472  (void) memset(&sa, 0, sizeof(sa));
473  sa.sin.sin_family = AF_INET;
474  sa.sin.sin_port = htons(0);
475  sa.sin.sin_addr.s_addr = htonl(0x7f000001);
713476
714static int mg_strcasecmp(const char *s1, const char *s2) {
715   int diff;
477  if ((sock = socket(AF_INET, sock_type, 0)) != INVALID_SOCKET &&
478      !bind(sock, &sa.sa, len) &&
479      (sock_type == SOCK_DGRAM || !listen(sock, 1)) &&
480      !getsockname(sock, &sa.sa, &len) &&
481      (sp[0] = socket(AF_INET, sock_type, 0)) != INVALID_SOCKET &&
482      !connect(sp[0], &sa.sa, len) &&
483      (sock_type == SOCK_STREAM ||
484       (!getsockname(sp[0], &sa.sa, &len) && !connect(sock, &sa.sa, len))) &&
485      (sp[1] = (sock_type == SOCK_DGRAM ? sock :
486                accept(sock, &sa.sa, &len))) != INVALID_SOCKET) {
487    ns_set_close_on_exec(sp[0]);
488    ns_set_close_on_exec(sp[1]);
489    ret = 1;
490  } else {
491    if (sp[0] != INVALID_SOCKET) closesocket(sp[0]);
492    if (sp[1] != INVALID_SOCKET) closesocket(sp[1]);
493    sp[0] = sp[1] = INVALID_SOCKET;
494  }
495  if (sock_type != SOCK_DGRAM) closesocket(sock);
716496
717   do {
718   diff = lowercase(s1++) - lowercase(s2++);
719   } while (diff == 0 && s1[-1] != '\0');
497  return ret;
498}
720499
721   return diff;
500int ns_socketpair(sock_t sp[2]) {
501  return ns_socketpair2(sp, SOCK_STREAM);
722502}
503#endif  // NS_DISABLE_SOCKETPAIR
723504
724static char * mg_strndup(const char *ptr, size_t len) {
725   char *p;
505// Valid listening port spec is: [ip_address:]port, e.g. "80", "127.0.0.1:3128"
506static int ns_parse_port_string(const char *str, union socket_address *sa) {
507  unsigned int a, b, c, d, port;
508  int len = 0;
509#ifdef NS_ENABLE_IPV6
510  char buf[100];
511#endif
726512
727   if ((p = (char *) malloc(len + 1)) != NULL) {
728   mg_strlcpy(p, ptr, len + 1);
729   }
513  // MacOS needs that. If we do not zero it, subsequent bind() will fail.
514  // Also, all-zeroes in the socket address means binding to all addresses
515  // for both IPv4 and IPv6 (INADDR_ANY and IN6ADDR_ANY_INIT).
516  memset(sa, 0, sizeof(*sa));
517  sa->sin.sin_family = AF_INET;
730518
731   return p;
732}
519  if (sscanf(str, "%u.%u.%u.%u:%u%n", &a, &b, &c, &d, &port, &len) == 5) {
520    // Bind to a specific IPv4 address, e.g. 192.168.1.5:8080
521    sa->sin.sin_addr.s_addr = htonl((a << 24) | (b << 16) | (c << 8) | d);
522    sa->sin.sin_port = htons((uint16_t) port);
523#ifdef NS_ENABLE_IPV6
524  } else if (sscanf(str, "[%49[^]]]:%u%n", buf, &port, &len) == 2 &&
525             inet_pton(AF_INET6, buf, &sa->sin6.sin6_addr)) {
526    // IPv6 address, e.g. [3ffe:2a00:100:7031::1]:8080
527    sa->sin6.sin6_family = AF_INET6;
528    sa->sin6.sin6_port = htons((uint16_t) port);
529#endif
530  } else if (sscanf(str, "%u%n", &port, &len) == 1) {
531    // If only port is specified, bind to IPv4, INADDR_ANY
532    sa->sin.sin_port = htons((uint16_t) port);
533  } else {
534    port = 0;   // Parsing failure. Make port invalid.
535  }
733536
734static char * mg_strdup(const char *str) {
735   return mg_strndup(str, strlen(str));
537  return port <= 0xffff && str[len] == '\0';
736538}
737539
738static const char *mg_strcasestr(const char *big_str, const char *small_str) {
739   int i, big_len = strlen(big_str), small_len = strlen(small_str);
540// 'sa' must be an initialized address to bind to
541static sock_t ns_open_listening_socket(union socket_address *sa) {
542  socklen_t len = sizeof(*sa);
543  sock_t sock = INVALID_SOCKET;
544#ifndef _WIN32
545  int on = 1;
546#endif
740547
741   for (i = 0; i <= big_len - small_len; i++) {
742   if (mg_strncasecmp(big_str + i, small_str, small_len) == 0) {
743      return big_str + i;
744   }
745   }
548  if ((sock = socket(sa->sa.sa_family, SOCK_STREAM, 6)) != INVALID_SOCKET &&
549#ifndef _WIN32
550      !setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void *) &on, sizeof(on)) &&
551#endif
552      !bind(sock, &sa->sa, sa->sa.sa_family == AF_INET ?
553            sizeof(sa->sin) : sizeof(sa->sa)) &&
554      !listen(sock, SOMAXCONN)) {
555    ns_set_non_blocking_mode(sock);
556    // In case port was set to 0, get the real port number
557    (void) getsockname(sock, &sa->sa, &len);
558  } else if (sock != INVALID_SOCKET) {
559    closesocket(sock);
560    sock = INVALID_SOCKET;
561  }
746562
747   return NULL;
563  return sock;
748564}
749565
750// Like snprintf(), but never returns negative value, or a value
751// that is larger than a supplied buffer.
752// Thanks to Adam Zeldis to pointing snprintf()-caused vulnerability
753// in his audit report.
754static int mg_vsnprintf(struct mg_connection *conn, char *buf, size_t buflen,
755                  const char *fmt, va_list ap) {
756   int n;
566// Certificate generation script is at
567// https://github.com/cesanta/net_skeleton/blob/master/examples/gen_certs.sh
568int ns_set_ssl_ca_cert(struct ns_server *server, const char *cert) {
569#ifdef NS_ENABLE_SSL
570  STACK_OF(X509_NAME) *list = SSL_load_client_CA_file(cert);
571  if (cert != NULL && server->ssl_ctx != NULL && list != NULL) {
572    SSL_CTX_set_client_CA_list(server->ssl_ctx, list);
573    SSL_CTX_set_verify(server->ssl_ctx, SSL_VERIFY_PEER |
574                       SSL_VERIFY_FAIL_IF_NO_PEER_CERT, NULL);
575    return 0;
576  }
577#endif
578  return server != NULL && cert == NULL ? 0 : -1;
579}
757580
758   if (buflen == 0)
759   return 0;
581int ns_set_ssl_cert(struct ns_server *server, const char *cert) {
582#ifdef NS_ENABLE_SSL
583  if (cert != NULL &&
584      (server->ssl_ctx = SSL_CTX_new(SSLv23_server_method())) == NULL) {
585    return -1;
586  } else if (SSL_CTX_use_certificate_file(server->ssl_ctx, cert, 1) == 0 ||
587             SSL_CTX_use_PrivateKey_file(server->ssl_ctx, cert, 1) == 0) {
588    return -2;
589  } else {
590    SSL_CTX_use_certificate_chain_file(server->ssl_ctx, cert);
591    return 0;
592  }
593#endif
594  return server != NULL && cert == NULL ? 0 : -3;
595}
760596
761   n = vsnprintf(buf, buflen, fmt, ap);
597int ns_bind(struct ns_server *server, const char *str) {
598  union socket_address sa;
599  ns_parse_port_string(str, &sa);
600  if (server->listening_sock != INVALID_SOCKET) {
601    closesocket(server->listening_sock);
602  }
603  server->listening_sock = ns_open_listening_socket(&sa);
604  return server->listening_sock == INVALID_SOCKET ? -1 :
605  (int) ntohs(sa.sin.sin_port);
606}
762607
763   if (n < 0) {
764   cry(conn, "vsnprintf error");
765   n = 0;
766   } else if (n >= (int) buflen) {
767   cry(conn, "truncating vsnprintf buffer: [%.*s]",
768      n > 200 ? 200 : n, buf);
769   n = (int) buflen - 1;
770   }
771   buf[n] = '\0';
772608
773   return n;
774}
609static struct ns_connection *accept_conn(struct ns_server *server) {
610  struct ns_connection *c = NULL;
611  union socket_address sa;
612  socklen_t len = sizeof(sa);
613  sock_t sock = INVALID_SOCKET;
775614
776static int mg_snprintf(struct mg_connection *conn, char *buf, size_t buflen,
777                  PRINTF_FORMAT_STRING(const char *fmt), ...)
778   PRINTF_ARGS(4, 5);
615  // NOTE(lsm): on Windows, sock is always > FD_SETSIZE
616  if ((sock = accept(server->listening_sock, &sa.sa, &len)) == INVALID_SOCKET) {
617  } else if ((c = (struct ns_connection *) NS_MALLOC(sizeof(*c))) == NULL ||
618             memset(c, 0, sizeof(*c)) == NULL) {
619    closesocket(sock);
620#ifdef NS_ENABLE_SSL
621  } else if (server->ssl_ctx != NULL &&
622             ((c->ssl = SSL_new(server->ssl_ctx)) == NULL ||
623              SSL_set_fd(c->ssl, sock) != 1)) {
624    DBG(("SSL error"));
625    closesocket(sock);
626    free(c);
627    c = NULL;
628#endif
629  } else {
630    ns_set_close_on_exec(sock);
631    ns_set_non_blocking_mode(sock);
632    c->server = server;
633    c->sock = sock;
634    c->flags |= NSF_ACCEPTED;
779635
780static int mg_snprintf(struct mg_connection *conn, char *buf, size_t buflen,
781                  const char *fmt, ...) {
782   va_list ap;
783   int n;
636    ns_add_conn(server, c);
637    ns_call(c, NS_ACCEPT, &sa);
638    DBG(("%p %d %p %p", c, c->sock, c->ssl, server->ssl_ctx));
639  }
784640
785   va_start(ap, fmt);
786   n = mg_vsnprintf(conn, buf, buflen, fmt, ap);
787   va_end(ap);
641  return c;
642}
788643
789   return n;
644static int ns_is_error(int n) {
645  return n == 0 ||
646    (n < 0 && errno != EINTR && errno != EINPROGRESS &&
647     errno != EAGAIN && errno != EWOULDBLOCK
648#ifdef _WIN32
649     && WSAGetLastError() != WSAEINTR && WSAGetLastError() != WSAEWOULDBLOCK
650#endif
651    );
790652}
791653
792// Skip the characters until one of the delimiters characters found.
793// 0-terminate resulting word. Skip the delimiter and following whitespaces.
794// Advance pointer to buffer to the next word. Return found 0-terminated word.
795// Delimiters can be quoted with quotechar.
796static char *skip_quoted(char **buf, const char *delimiters,
797                     const char *whitespace, char quotechar) {
798   char *p, *begin_word, *end_word, *end_whitespace;
654void ns_sock_to_str(sock_t sock, char *buf, size_t len, int flags) {
655  union socket_address sa;
656  socklen_t slen = sizeof(sa);
799657
800   begin_word = *buf;
801   end_word = begin_word + strcspn(begin_word, delimiters);
658  if (buf != NULL && len > 0) {
659    buf[0] = '\0';
660    memset(&sa, 0, sizeof(sa));
661    if (flags & 4) {
662      getpeername(sock, &sa.sa, &slen);
663    } else {
664      getsockname(sock, &sa.sa, &slen);
665    }
666    if (flags & 1) {
667#if defined(NS_ENABLE_IPV6)
668      inet_ntop(sa.sa.sa_family, sa.sa.sa_family == AF_INET ?
669                (void *) &sa.sin.sin_addr :
670                (void *) &sa.sin6.sin6_addr, buf, len);
671#elif defined(_WIN32)
672      // Only Windoze Vista (and newer) have inet_ntop()
673      strncpy(buf, inet_ntoa(sa.sin.sin_addr), len);
674#else
675      inet_ntop(sa.sa.sa_family, (void *) &sa.sin.sin_addr, buf, len);
676#endif
677    }
678    if (flags & 2) {
679      snprintf(buf + strlen(buf), len - (strlen(buf) + 1), ":%d",
680      (int) ntohs(sa.sin.sin_port));
681    }
682  }
683}
802684
803   // Check for quotechar
804   if (end_word > begin_word) {
805   p = end_word - 1;
806   while (*p == quotechar) {
807      // If there is anything beyond end_word, copy it
808      if (*end_word == '\0') {
809      *p = '\0';
810      break;
811      } else {
812      size_t end_off = strcspn(end_word + 1, delimiters);
813      memmove (p, end_word, end_off + 1);
814      p += end_off; // p must correspond to end_word - 1
815      end_word += end_off + 1;
816      }
817   }
818   for (p++; p < end_word; p++) {
819      *p = '\0';
820   }
821   }
685int ns_hexdump(const void *buf, int len, char *dst, int dst_len) {
686  const unsigned char *p = (const unsigned char *) buf;
687  char ascii[17] = "";
688  int i, idx, n = 0;
822689
823   if (*end_word == '\0') {
824   *buf = end_word;
825   } else {
826   end_whitespace = end_word + 1 + strspn(end_word + 1, whitespace);
690  for (i = 0; i < len; i++) {
691    idx = i % 16;
692    if (idx == 0) {
693      if (i > 0) n += snprintf(dst + n, dst_len - n, "  %s\n", ascii);
694      n += snprintf(dst + n, dst_len - n, "%04x ", i);
695    }
696    n += snprintf(dst + n, dst_len - n, " %02x", p[i]);
697    ascii[idx] = p[i] < 0x20 || p[i] > 0x7e ? '.' : p[i];
698    ascii[idx + 1] = '\0';
699  }
827700
828   for (p = end_word; p < end_whitespace; p++) {
829      *p = '\0';
830   }
701  while (i++ % 16) n += snprintf(dst + n, dst_len - n, "%s", "   ");
702  n += snprintf(dst + n, dst_len - n, "  %s\n\n", ascii);
831703
832   *buf = end_whitespace;
833   }
834
835   return begin_word;
704  return n;
836705}
837706
838// Simplified version of skip_quoted without quote char
839// and whitespace == delimiters
840static char *skip(char **buf, const char *delimiters) {
841   return skip_quoted(buf, delimiters, delimiters, 0);
842}
707static void ns_read_from_socket(struct ns_connection *conn) {
708  char buf[2048];
709  int n = 0;
843710
711  if (conn->flags & NSF_CONNECTING) {
712    int ok = 1, ret;
713    socklen_t len = sizeof(ok);
844714
845// Return HTTP header value, or NULL if not found.
846static const char *get_header(const struct mg_request_info *ri,
847                        const char *name) {
848   int i;
715    ret = getsockopt(conn->sock, SOL_SOCKET, SO_ERROR, (char *) &ok, &len);
716    (void) ret;
717#ifdef NS_ENABLE_SSL
718    if (ret == 0 && ok == 0 && conn->ssl != NULL) {
719      int res = SSL_connect(conn->ssl);
720      int ssl_err = SSL_get_error(conn->ssl, res);
721      DBG(("%p %d wres %d %d", conn, conn->flags, res, ssl_err));
722      if (ssl_err == SSL_ERROR_WANT_READ) conn->flags |= NSF_WANT_READ;
723      if (ssl_err == SSL_ERROR_WANT_WRITE) conn->flags |= NSF_WANT_WRITE;
724      if (res == 1) {
725        conn->flags |= NSF_SSL_HANDSHAKE_DONE;
726      } else if (ssl_err == SSL_ERROR_WANT_READ ||
727                 ssl_err == SSL_ERROR_WANT_WRITE) {
728        return; // Call us again
729      } else {
730        ok = 1;
731      }
732    }
733#endif
734    conn->flags &= ~NSF_CONNECTING;
735    DBG(("%p ok=%d", conn, ok));
736    if (ok != 0) {
737      conn->flags |= NSF_CLOSE_IMMEDIATELY;
738    }
739    ns_call(conn, NS_CONNECT, &ok);
740    return;
741  }
849742
850   for (i = 0; i < ri->num_headers; i++)
851   if (!mg_strcasecmp(name, ri->http_headers[i].name))
852      return ri->http_headers[i].value;
743#ifdef NS_ENABLE_SSL
744  if (conn->ssl != NULL) {
745    if (conn->flags & NSF_SSL_HANDSHAKE_DONE) {
746      n = SSL_read(conn->ssl, buf, sizeof(buf));
747    } else {
748      int res = SSL_accept(conn->ssl);
749      int ssl_err = SSL_get_error(conn->ssl, res);
750      DBG(("%p %d rres %d %d", conn, conn->flags, res, ssl_err));
751      if (ssl_err == SSL_ERROR_WANT_READ) conn->flags |= NSF_WANT_READ;
752      if (ssl_err == SSL_ERROR_WANT_WRITE) conn->flags |= NSF_WANT_WRITE;
753      if (res == 1) {
754        conn->flags |= NSF_SSL_HANDSHAKE_DONE;
755      } else if (ssl_err == SSL_ERROR_WANT_READ ||
756                 ssl_err == SSL_ERROR_WANT_WRITE) {
757        return; // Call us again
758      } else {
759        conn->flags |= NSF_CLOSE_IMMEDIATELY;
760      }
761      return;
762    }
763  } else
764#endif
765  {
766    n = recv(conn->sock, buf, sizeof(buf), 0);
767  }
853768
854   return NULL;
855}
769  DBG(("%p %d <- %d bytes", conn, conn->flags, n));
856770
857const char *mg_get_header(const struct mg_connection *conn, const char *name) {
858   return get_header(&conn->request_info, name);
771  if (ns_is_error(n)) {
772    conn->flags |= NSF_CLOSE_IMMEDIATELY;
773  } else if (n > 0) {
774    iobuf_append(&conn->recv_iobuf, buf, n);
775    ns_call(conn, NS_RECV, &n);
776  }
859777}
860778
861// A helper function for traversing a comma separated list of values.
862// It returns a list pointer shifted to the next value, or NULL if the end
863// of the list found.
864// Value is stored in val vector. If value has form "x=y", then eq_val
865// vector is initialized to point to the "y" part, and val vector length
866// is adjusted to point only to "x".
867static const char *next_option(const char *list, struct vec *val,
868                        struct vec *eq_val) {
869   if (list == NULL || *list == '\0') {
870   // End of the list
871   list = NULL;
872   } else {
873   val->ptr = list;
874   if ((list = strchr(val->ptr, ',')) != NULL) {
875      // Comma found. Store length and shift the list ptr
876      val->len = list - val->ptr;
877      list++;
878   } else {
879      // This value is the last one
880      list = val->ptr + strlen(val->ptr);
881      val->len = list - val->ptr;
882   }
779static void ns_write_to_socket(struct ns_connection *conn) {
780  struct iobuf *io = &conn->send_iobuf;
781  int n = 0;
883782
884   if (eq_val != NULL) {
885      // Value has form "x=y", adjust pointers and lengths
886      // so that val points to "x", and eq_val points to "y".
887      eq_val->len = 0;
888      eq_val->ptr = (const char *) memchr(val->ptr, '=', val->len);
889      if (eq_val->ptr != NULL) {
890      eq_val->ptr++;  // Skip over '=' character
891      eq_val->len = val->ptr + val->len - eq_val->ptr;
892      val->len = (eq_val->ptr - val->ptr) - 1;
893      }
894   }
895   }
783#ifdef NS_ENABLE_SSL
784  if (conn->ssl != NULL) {
785    n = SSL_write(conn->ssl, io->buf, io->len);
786    if (n < 0) {
787      int ssl_err = SSL_get_error(conn->ssl, n);
788      DBG(("%p %d %d", conn, n, ssl_err));
789      if (ssl_err == 2 || ssl_err == 3) {
790        return; // Call us again
791      } else {
792        conn->flags |= NSF_CLOSE_IMMEDIATELY;
793      }
794    }
795  } else
796#endif
797  { n = send(conn->sock, io->buf, io->len, 0); }
896798
897   return list;
898}
799  DBG(("%p %d -> %d bytes", conn, conn->flags, n));
899800
900static int match_prefix(const char *pattern, int pattern_len, const char *str) {
901   const char *or_str;
902   int i, j, len, res;
801  ns_call(conn, NS_SEND, &n);
802  if (ns_is_error(n)) {
803    conn->flags |= NSF_CLOSE_IMMEDIATELY;
804  } else if (n > 0) {
805    iobuf_remove(io, n);
806  }
903807
904   if ((or_str = (const char *) memchr(pattern, '|', pattern_len)) != NULL) {
905   res = match_prefix(pattern, or_str - pattern, str);
906   return res > 0 ? res :
907      match_prefix(or_str + 1, (pattern + pattern_len) - (or_str + 1), str);
908   }
909
910   i = j = 0;
911   res = -1;
912   for (; i < pattern_len; i++, j++) {
913   if (pattern[i] == '?' && str[j] != '\0') {
914      continue;
915   } else if (pattern[i] == '$') {
916      return str[j] == '\0' ? j : -1;
917   } else if (pattern[i] == '*') {
918      i++;
919      if (pattern[i] == '*') {
920      i++;
921      len = (int) strlen(str + j);
922      } else {
923      len = (int) strcspn(str + j, "/");
924      }
925      if (i == pattern_len) {
926      return j + len;
927      }
928      do {
929      res = match_prefix(pattern + i, pattern_len - i, str + j + len);
930      } while (res == -1 && len-- > 0);
931      return res == -1 ? -1 : j + res + len;
932   } else if (pattern[i] != str[j]) {
933      return -1;
934   }
935   }
936   return j;
808  if (io->len == 0 && conn->flags & NSF_FINISHED_SENDING_DATA) {
809    conn->flags |= NSF_CLOSE_IMMEDIATELY;
810  }
937811}
938812
939// HTTP 1.1 assumes keep alive if "Connection:" header is not set
940// This function must tolerate situations when connection info is not
941// set up, for example if request parsing failed.
942static int should_keep_alive(const struct mg_connection *conn) {
943   const char *http_version = conn->request_info.http_version;
944   const char *header = mg_get_header(conn, "Connection");
945   if (conn->must_close ||
946      conn->status_code == 401 ||
947      mg_strcasecmp(conn->ctx->config[ENABLE_KEEP_ALIVE], "yes") != 0 ||
948      (header != NULL && mg_strcasecmp(header, "keep-alive") != 0) ||
949      (header == NULL && http_version && strcmp(http_version, "1.1"))) {
950   return 0;
951   }
952   return 1;
813int ns_send(struct ns_connection *conn, const void *buf, int len) {
814  return iobuf_append(&conn->send_iobuf, buf, len);
953815}
954816
955static const char *suggest_connection_header(const struct mg_connection *conn) {
956   return should_keep_alive(conn) ? "keep-alive" : "close";
817static void ns_add_to_set(sock_t sock, fd_set *set, sock_t *max_fd) {
818  if (sock != INVALID_SOCKET) {
819    FD_SET(sock, set);
820    if (*max_fd == INVALID_SOCKET || sock > *max_fd) {
821      *max_fd = sock;
822    }
823  }
957824}
958825
959static void send_http_error(struct mg_connection *, int, const char *,
960                     PRINTF_FORMAT_STRING(const char *fmt), ...)
961   PRINTF_ARGS(4, 5);
826int ns_server_poll(struct ns_server *server, int milli) {
827  struct ns_connection *conn, *tmp_conn;
828  struct timeval tv;
829  fd_set read_set, write_set;
830  int num_active_connections = 0;
831  sock_t max_fd = INVALID_SOCKET;
832  time_t current_time = time(NULL);
962833
834  if (server->listening_sock == INVALID_SOCKET &&
835      server->active_connections == NULL) return 0;
963836
964static void send_http_error(struct mg_connection *conn, int status,
965                     const char *reason, const char *fmt, ...) {
966   char buf[MG_BUF_LEN];
967   va_list ap;
968   int len = 0;
837  FD_ZERO(&read_set);
838  FD_ZERO(&write_set);
839  ns_add_to_set(server->listening_sock, &read_set, &max_fd);
840  ns_add_to_set(server->ctl[1], &read_set, &max_fd);
969841
970   conn->status_code = status;
971   if (conn->ctx->callbacks.http_error == NULL ||
972      conn->ctx->callbacks.http_error(conn, status)) {
973   buf[0] = '\0';
842  for (conn = server->active_connections; conn != NULL; conn = tmp_conn) {
843    tmp_conn = conn->next;
844    ns_call(conn, NS_POLL, &current_time);
845    if (!(conn->flags & NSF_WANT_WRITE)) {
846      //DBG(("%p read_set", conn));
847      ns_add_to_set(conn->sock, &read_set, &max_fd);
848    }
849    if (((conn->flags & NSF_CONNECTING) && !(conn->flags & NSF_WANT_READ)) ||
850        (conn->send_iobuf.len > 0 && !(conn->flags & NSF_CONNECTING) &&
851         !(conn->flags & NSF_BUFFER_BUT_DONT_SEND))) {
852      //DBG(("%p write_set", conn));
853      ns_add_to_set(conn->sock, &write_set, &max_fd);
854    }
855    if (conn->flags & NSF_CLOSE_IMMEDIATELY) {
856      ns_close_conn(conn);
857    }
858  }
974859
975   // Errors 1xx, 204 and 304 MUST NOT send a body
976   if (status > 199 && status != 204 && status != 304) {
977      len = mg_snprintf(conn, buf, sizeof(buf), "Error %d: %s", status, reason);
978      buf[len++] = '\n';
860  tv.tv_sec = milli / 1000;
861  tv.tv_usec = (milli % 1000) * 1000;
979862
980      va_start(ap, fmt);
981      len += mg_vsnprintf(conn, buf + len, sizeof(buf) - len, fmt, ap);
982      va_end(ap);
983   }
984   DEBUG_TRACE(("[%s]", buf));
863  if (select((int) max_fd + 1, &read_set, &write_set, NULL, &tv) > 0) {
864    // Accept new connections
865    if (server->listening_sock != INVALID_SOCKET &&
866        FD_ISSET(server->listening_sock, &read_set)) {
867      // We're not looping here, and accepting just one connection at
868      // a time. The reason is that eCos does not respect non-blocking
869      // flag on a listening socket and hangs in a loop.
870      if ((conn = accept_conn(server)) != NULL) {
871        conn->last_io_time = current_time;
872      }
873    }
985874
986   mg_printf(conn, "HTTP/1.1 %d %s\r\n"
987            "Content-Length: %d\r\n"
988            "Connection: %s\r\n\r\n", status, reason, len,
989            suggest_connection_header(conn));
990   conn->num_bytes_sent += mg_printf(conn, "%s", buf);
991   }
992}
875    // Read wakeup messages
876    if (server->ctl[1] != INVALID_SOCKET &&
877        FD_ISSET(server->ctl[1], &read_set)) {
878      struct ctl_msg ctl_msg;
879      int len = recv(server->ctl[1], (char *) &ctl_msg, sizeof(ctl_msg), 0);
880      send(server->ctl[1], ctl_msg.message, 1, 0);
881      if (len >= (int) sizeof(ctl_msg.callback) && ctl_msg.callback != NULL) {
882        ns_iterate(server, ctl_msg.callback, ctl_msg.message);
883      }
884    }
993885
994#if defined(_WIN32) && !defined(__SYMBIAN32__)
995static int pthread_mutex_init(pthread_mutex_t *mutex, void *unused) {
996   (void) unused;
997   *mutex = CreateMutex(NULL, FALSE, NULL);
998   return *mutex == NULL ? -1 : 0;
999}
886    for (conn = server->active_connections; conn != NULL; conn = tmp_conn) {
887      tmp_conn = conn->next;
888      //DBG(("%p LOOP %p", conn, conn->ssl));
889      if (FD_ISSET(conn->sock, &read_set)) {
890        conn->last_io_time = current_time;
891        ns_read_from_socket(conn);
892      }
893      if (FD_ISSET(conn->sock, &write_set)) {
894        if (conn->flags & NSF_CONNECTING) {
895          ns_read_from_socket(conn);
896        } else if (!(conn->flags & NSF_BUFFER_BUT_DONT_SEND)) {
897          conn->last_io_time = current_time;
898          ns_write_to_socket(conn);
899        }
900      }
901    }
902  }
1000903
1001static int pthread_mutex_destroy(pthread_mutex_t *mutex) {
1002   return CloseHandle(*mutex) == 0 ? -1 : 0;
1003}
904  for (conn = server->active_connections; conn != NULL; conn = tmp_conn) {
905    tmp_conn = conn->next;
906    num_active_connections++;
907    if (conn->flags & NSF_CLOSE_IMMEDIATELY) {
908      ns_close_conn(conn);
909    }
910  }
911  //DBG(("%d active connections", num_active_connections));
1004912
1005static int pthread_mutex_lock(pthread_mutex_t *mutex) {
1006   return WaitForSingleObject(*mutex, INFINITE) == WAIT_OBJECT_0? 0 : -1;
913  return num_active_connections;
1007914}
1008915
1009static int pthread_mutex_unlock(pthread_mutex_t *mutex) {
1010   return ReleaseMutex(*mutex) == 0 ? -1 : 0;
1011}
916struct ns_connection *ns_connect(struct ns_server *server, const char *host,
917                                 int port, int use_ssl, void *param) {
918  sock_t sock = INVALID_SOCKET;
919  struct sockaddr_in sin;
920  struct hostent *he = NULL;
921  struct ns_connection *conn = NULL;
922  int connect_ret_val;
1012923
1013static int pthread_cond_init(pthread_cond_t *cv, const void *unused) {
1014   (void) unused;
1015   cv->signal = CreateEvent(NULL, FALSE, FALSE, NULL);
1016   cv->broadcast = CreateEvent(NULL, TRUE, FALSE, NULL);
1017   return cv->signal != NULL && cv->broadcast != NULL ? 0 : -1;
1018}
924  (void) use_ssl;
1019925
1020static int pthread_cond_wait(pthread_cond_t *cv, pthread_mutex_t *mutex) {
1021   HANDLE handles[] = {cv->signal, cv->broadcast};
1022   ReleaseMutex(*mutex);
1023   WaitForMultipleObjects(2, handles, FALSE, INFINITE);
1024   return WaitForSingleObject(*mutex, INFINITE) == WAIT_OBJECT_0? 0 : -1;
1025}
926  if (host == NULL || (he = gethostbyname(host)) == NULL ||
927      (sock = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
928    DBG(("gethostbyname(%s) failed: %s", host, strerror(errno)));
929    return NULL;
930  }
1026931
1027static int pthread_cond_signal(pthread_cond_t *cv) {
1028   return SetEvent(cv->signal) == 0 ? -1 : 0;
1029}
932  sin.sin_family = AF_INET;
933  sin.sin_port = htons((uint16_t) port);
934  sin.sin_addr = * (struct in_addr *) he->h_addr_list[0];
935  ns_set_non_blocking_mode(sock);
1030936
1031static int pthread_cond_broadcast(pthread_cond_t *cv) {
1032   // Implementation with PulseEvent() has race condition, see
1033   // http://www.cs.wustl.edu/~schmidt/win32-cv-1.html
1034   return PulseEvent(cv->broadcast) == 0 ? -1 : 0;
1035}
937  connect_ret_val = connect(sock, (struct sockaddr *) &sin, sizeof(sin));
938  if (ns_is_error(connect_ret_val)) {
939    closesocket(sock);
940    return NULL;
941  } else if ((conn = (struct ns_connection *)
942              NS_MALLOC(sizeof(*conn))) == NULL) {
943    closesocket(sock);
944    return NULL;
945  }
1036946
1037static int pthread_cond_destroy(pthread_cond_t *cv) {
1038   return CloseHandle(cv->signal) && CloseHandle(cv->broadcast) ? 0 : -1;
1039}
947  memset(conn, 0, sizeof(*conn));
948  conn->server = server;
949  conn->sock = sock;
950  conn->connection_data = param;
951  conn->flags = NSF_CONNECTING;
952  conn->last_io_time = time(NULL);
1040953
1041// For Windows, change all slashes to backslashes in path names.
1042static void change_slashes_to_backslashes(char *path) {
1043   int i;
954#ifdef NS_ENABLE_SSL
955  if (use_ssl &&
956      (conn->ssl = SSL_new(server->client_ssl_ctx)) != NULL) {
957    SSL_set_fd(conn->ssl, sock);
958  }
959#endif
1044960
1045   for (i = 0; path[i] != '\0'; i++) {
1046   if (path[i] == '/')
1047      path[i] = '\\';
1048   // i > 0 check is to preserve UNC paths, like \\server\file.txt
1049   if (path[i] == '\\' && i > 0)
1050      while (path[i + 1] == '\\' || path[i + 1] == '/')
1051      (void) memmove(path + i + 1,
1052         path + i + 2, strlen(path + i + 1));
1053   }
1054}
961  ns_add_conn(server, conn);
962  DBG(("%p %s:%d %d %p", conn, host, port, conn->sock, conn->ssl));
1055963
1056// Encode 'path' which is assumed UTF-8 string, into UNICODE string.
1057// wbuf and wbuf_len is a target buffer and its length.
1058static void to_unicode(const char *path, wchar_t *wbuf, size_t wbuf_len) {
1059   char buf[PATH_MAX], buf2[PATH_MAX];
1060
1061   mg_strlcpy(buf, path, sizeof(buf));
1062   change_slashes_to_backslashes(buf);
1063
1064   // Convert to Unicode and back. If doubly-converted string does not
1065   // match the original, something is fishy, reject.
1066   memset(wbuf, 0, wbuf_len * sizeof(wchar_t));
1067   MultiByteToWideChar(CP_UTF8, 0, buf, -1, wbuf, (int) wbuf_len);
1068   WideCharToMultiByte(CP_UTF8, 0, wbuf, (int) wbuf_len, buf2, sizeof(buf2),
1069                  NULL, NULL);
1070   if (strcmp(buf, buf2) != 0) {
1071   wbuf[0] = L'\0';
1072   }
964  return conn;
1073965}
1074966
1075#if defined(_WIN32_WCE)
1076static time_t time(time_t *ptime) {
1077   time_t t;
1078   SYSTEMTIME st;
1079   FILETIME ft;
1080
1081   GetSystemTime(&st);
1082   SystemTimeToFileTime(&st, &ft);
1083   t = SYS2UNIX_TIME(ft.dwLowDateTime, ft.dwHighDateTime);
1084
1085   if (ptime != NULL) {
1086   *ptime = t;
1087   }
1088
1089   return t;
967struct ns_connection *ns_add_sock(struct ns_server *s, sock_t sock, void *p) {
968  struct ns_connection *conn;
969  if ((conn = (struct ns_connection *) NS_MALLOC(sizeof(*conn))) != NULL) {
970    memset(conn, 0, sizeof(*conn));
971    ns_set_non_blocking_mode(sock);
972    conn->sock = sock;
973    conn->connection_data = p;
974    conn->server = s;
975    conn->last_io_time = time(NULL);
976    ns_add_conn(s, conn);
977    DBG(("%p %d", conn, sock));
978  }
979  return conn;
1090980}
1091981
1092static struct tm *localtime(const time_t *ptime, struct tm *ptm) {
1093   int64_t t = ((int64_t) *ptime) * RATE_DIFF + EPOCH_DIFF;
1094   FILETIME ft, lft;
1095   SYSTEMTIME st;
1096   TIME_ZONE_INFORMATION tzinfo;
982void ns_iterate(struct ns_server *server, ns_callback_t cb, void *param) {
983  struct ns_connection *conn, *tmp_conn;
1097984
1098   if (ptm == NULL) {
1099   return NULL;
1100   }
1101
1102   * (int64_t *) &ft = t;
1103   FileTimeToLocalFileTime(&ft, &lft);
1104   FileTimeToSystemTime(&lft, &st);
1105   ptm->tm_year = st.wYear - 1900;
1106   ptm->tm_mon = st.wMonth - 1;
1107   ptm->tm_wday = st.wDayOfWeek;
1108   ptm->tm_mday = st.wDay;
1109   ptm->tm_hour = st.wHour;
1110   ptm->tm_min = st.wMinute;
1111   ptm->tm_sec = st.wSecond;
1112   ptm->tm_yday = 0; // hope nobody uses this
1113   ptm->tm_isdst =
1114   GetTimeZoneInformation(&tzinfo) == TIME_ZONE_ID_DAYLIGHT ? 1 : 0;
1115
1116   return ptm;
985  for (conn = server->active_connections; conn != NULL; conn = tmp_conn) {
986    tmp_conn = conn->next;
987    cb(conn, NS_POLL, param);
988  }
1117989}
1118990
1119static struct tm *gmtime(const time_t *ptime, struct tm *ptm) {
1120   // FIXME(lsm): fix this.
1121   return localtime(ptime, ptm);
991void ns_server_wakeup_ex(struct ns_server *server, ns_callback_t cb,
992                         void *data, size_t len) {
993  struct ctl_msg ctl_msg;
994  if (server->ctl[0] != INVALID_SOCKET && data != NULL &&
995      len < sizeof(ctl_msg.message)) {
996    ctl_msg.callback = cb;
997    memcpy(ctl_msg.message, data, len);
998    send(server->ctl[0], (char *) &ctl_msg,
999         offsetof(struct ctl_msg, message) + len, 0);
1000    recv(server->ctl[0], (char *) &len, 1, 0);
1001  }
11221002}
11231003
1124static size_t strftime(char *dst, size_t dst_size, const char *fmt,
1125                  const struct tm *tm) {
1126   (void) snprintf(dst, dst_size, "implement strftime() for WinCE");
1127   return 0;
1004void ns_server_wakeup(struct ns_server *server) {
1005  ns_server_wakeup_ex(server, NULL, (void *) "", 0);
11281006}
1129#endif
11301007
1131// Windows happily opens files with some garbage at the end of file name.
1132// For example, fopen("a.cgi    ", "r") on Windows successfully opens
1133// "a.cgi", despite one would expect an error back.
1134// This function returns non-0 if path ends with some garbage.
1135static int path_cannot_disclose_cgi(const char *path) {
1136   static const char *allowed_last_characters = "_-";
1137   int last = path[strlen(path) - 1];
1138   return isalnum(last) || strchr(allowed_last_characters, last) != NULL;
1139}
1008void ns_server_init(struct ns_server *s, void *server_data, ns_callback_t cb) {
1009  memset(s, 0, sizeof(*s));
1010  s->listening_sock = s->ctl[0] = s->ctl[1] = INVALID_SOCKET;
1011  s->server_data = server_data;
1012  s->callback = cb;
11401013
1141static int mg_stat(struct mg_connection *conn, const char *path,
1142               struct file *filep) {
1143   wchar_t wbuf[PATH_MAX];
1144   WIN32_FILE_ATTRIBUTE_DATA info;
1014#ifdef _WIN32
1015  { WSADATA data; WSAStartup(MAKEWORD(2, 2), &data); }
1016#else
1017  // Ignore SIGPIPE signal, so if client cancels the request, it
1018  // won't kill the whole process.
1019  signal(SIGPIPE, SIG_IGN);
1020#endif
11451021
1146   if (!is_file_in_memory(conn, path, filep)) {
1147   to_unicode(path, wbuf, ARRAY_SIZE(wbuf));
1148   if (GetFileAttributesExW(wbuf, GetFileExInfoStandard, &info) != 0) {
1149      filep->size = MAKEUQUAD(info.nFileSizeLow, info.nFileSizeHigh);
1150      filep->modification_time = SYS2UNIX_TIME(
1151         info.ftLastWriteTime.dwLowDateTime,
1152         info.ftLastWriteTime.dwHighDateTime);
1153      filep->is_directory = info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY;
1154      // If file name is fishy, reset the file structure and return error.
1155      // Note it is important to reset, not just return the error, cause
1156      // functions like is_file_opened() check the struct.
1157      if (!filep->is_directory && !path_cannot_disclose_cgi(path)) {
1158      memset(filep, 0, sizeof(*filep));
1159      }
1160   }
1161   }
1022#ifndef NS_DISABLE_SOCKETPAIR
1023  do {
1024    ns_socketpair2(s->ctl, SOCK_DGRAM);
1025  } while (s->ctl[0] == INVALID_SOCKET);
1026#endif
11621027
1163   return filep->membuf != NULL || filep->modification_time != 0;
1028#ifdef NS_ENABLE_SSL
1029  SSL_library_init();
1030  s->client_ssl_ctx = SSL_CTX_new(SSLv23_client_method());
1031#endif
11641032}
11651033
1166static int mg_remove(const char *path) {
1167   wchar_t wbuf[PATH_MAX];
1168   to_unicode(path, wbuf, ARRAY_SIZE(wbuf));
1169   return DeleteFileW(wbuf) ? 0 : -1;
1170}
1034void ns_server_free(struct ns_server *s) {
1035  struct ns_connection *conn, *tmp_conn;
11711036
1172static int mg_mkdir(const char *path, int mode) {
1173   char buf[PATH_MAX];
1174   wchar_t wbuf[PATH_MAX];
1037  DBG(("%p", s));
1038  if (s == NULL) return;
1039  // Do one last poll, see https://github.com/cesanta/mongoose/issues/286
1040  ns_server_poll(s, 0);
11751041
1176   (void) mode;
1177   mg_strlcpy(buf, path, sizeof(buf));
1178   change_slashes_to_backslashes(buf);
1042  if (s->listening_sock != INVALID_SOCKET) closesocket(s->listening_sock);
1043  if (s->ctl[0] != INVALID_SOCKET) closesocket(s->ctl[0]);
1044  if (s->ctl[1] != INVALID_SOCKET) closesocket(s->ctl[1]);
1045  s->listening_sock = s->ctl[0] = s->ctl[1] = INVALID_SOCKET;
11791046
1180   (void) MultiByteToWideChar(CP_UTF8, 0, buf, -1, wbuf, ARRAY_SIZE(wbuf));
1047  for (conn = s->active_connections; conn != NULL; conn = tmp_conn) {
1048    tmp_conn = conn->next;
1049    ns_close_conn(conn);
1050  }
11811051
1182   return CreateDirectoryW(wbuf, NULL) ? 0 : -1;
1052#ifdef NS_ENABLE_SSL
1053  if (s->ssl_ctx != NULL) SSL_CTX_free(s->ssl_ctx);
1054  if (s->client_ssl_ctx != NULL) SSL_CTX_free(s->client_ssl_ctx);
1055  s->ssl_ctx = s->client_ssl_ctx = NULL;
1056#endif
11831057}
1058// net_skeleton end
1059#endif  // NOEMBED_NET_SKELETON
11841060
1185// Implementation of POSIX opendir/closedir/readdir for Windows.
1186static DIR * opendir(const char *name) {
1187   DIR *dir = NULL;
1188   wchar_t wpath[PATH_MAX];
1189   DWORD attrs;
1061#include <ctype.h>
11901062
1191   if (name == NULL) {
1192   SetLastError(ERROR_BAD_ARGUMENTS);
1193   } else if ((dir = (DIR *) malloc(sizeof(*dir))) == NULL) {
1194   SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1195   } else {
1196   to_unicode(name, wpath, ARRAY_SIZE(wpath));
1197   attrs = GetFileAttributesW(wpath);
1198   if (attrs != 0xFFFFFFFF &&
1199      ((attrs & FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY)) {
1200      (void) wcscat(wpath, L"\\*");
1201      dir->handle = FindFirstFileW(wpath, &dir->info);
1202      dir->result.d_name[0] = '\0';
1203   } else {
1204      free(dir);
1205      dir = NULL;
1206   }
1207   }
1063#ifdef _WIN32         //////////////// Windows specific defines and includes
1064#include <io.h>       // For _lseeki64
1065#include <direct.h>   // For _mkdir
1066#ifndef S_ISDIR
1067#define S_ISDIR(x) ((x) & _S_IFDIR)
1068#endif
1069#ifdef stat
1070#undef stat
1071#endif
1072#ifdef lseek
1073#undef lseek
1074#endif
1075#ifdef popen
1076#undef popen
1077#endif
1078#ifdef pclose
1079#undef pclose
1080#endif
1081#define stat(x, y) mg_stat((x), (y))
1082#define fopen(x, y) mg_fopen((x), (y))
1083#define open(x, y) mg_open((x), (y))
1084#define lseek(x, y, z) _lseeki64((x), (y), (z))
1085#define popen(x, y) _popen((x), (y))
1086#define pclose(x) _pclose(x)
1087#define mkdir(x, y) _mkdir(x)
1088#ifndef __func__
1089#define STRX(x) #x
1090#define STR(x) STRX(x)
1091#define __func__ __FILE__ ":" STR(__LINE__)
1092#endif
1093#define INT64_FMT  "I64d"
1094#define stat(x, y) mg_stat((x), (y))
1095#define fopen(x, y) mg_fopen((x), (y))
1096#define open(x, y) mg_open((x), (y))
1097#define flockfile(x)      ((void) (x))
1098#define funlockfile(x)    ((void) (x))
1099typedef struct _stati64 file_stat_t;
1100typedef HANDLE process_id_t;
1101#else                    ////////////// UNIX specific defines and includes
1102#include <dirent.h>
1103#include <dlfcn.h>
1104#include <inttypes.h>
1105#include <pwd.h>
1106#define O_BINARY 0
1107#define INT64_FMT PRId64
1108typedef struct stat file_stat_t;
1109typedef pid_t process_id_t;
1110#endif                  //////// End of platform-specific defines and includes
12081111
1209   return dir;
1210}
1112#include "mongoose.h"
12111113
1212static int closedir(DIR *dir) {
1213   int result = 0;
1114#define MAX_REQUEST_SIZE 16384
1115#define IOBUF_SIZE 8192
1116#define MAX_PATH_SIZE 8192
1117#define DEFAULT_CGI_PATTERN "**.cgi$|**.pl$|**.php$"
1118#define CGI_ENVIRONMENT_SIZE 8192
1119#define MAX_CGI_ENVIR_VARS 64
1120#define ENV_EXPORT_TO_CGI "MONGOOSE_CGI"
1121#define PASSWORDS_FILE_NAME ".htpasswd"
12141122
1215   if (dir != NULL) {
1216   if (dir->handle != INVALID_HANDLE_VALUE)
1217      result = FindClose(dir->handle) ? 0 : -1;
1123#ifndef MONGOOSE_USE_WEBSOCKET_PING_INTERVAL
1124#define MONGOOSE_USE_WEBSOCKET_PING_INTERVAL 5
1125#endif
12181126
1219   free(dir);
1220   } else {
1221   result = -1;
1222   SetLastError(ERROR_BAD_ARGUMENTS);
1223   }
1127// Extra HTTP headers to send in every static file reply
1128#if !defined(MONGOOSE_USE_EXTRA_HTTP_HEADERS)
1129#define MONGOOSE_USE_EXTRA_HTTP_HEADERS ""
1130#endif
12241131
1225   return result;
1226}
1132#ifndef MONGOOSE_POST_SIZE_LIMIT
1133#define MONGOOSE_POST_SIZE_LIMIT 0
1134#endif
12271135
1228static struct dirent *readdir(DIR *dir) {
1229   struct dirent *result = 0;
1136#ifndef MONGOOSE_IDLE_TIMEOUT_SECONDS
1137#define MONGOOSE_IDLE_TIMEOUT_SECONDS 30
1138#endif
12301139
1231   if (dir) {
1232   if (dir->handle != INVALID_HANDLE_VALUE) {
1233      result = &dir->result;
1234      (void) WideCharToMultiByte(CP_UTF8, 0,
1235         dir->info.cFileName, -1, result->d_name,
1236         sizeof(result->d_name), NULL, NULL);
1140#ifdef MONGOOSE_NO_SOCKETPAIR
1141#define MONGOOSE_NO_CGI
1142#endif
12371143
1238      if (!FindNextFileW(dir->handle, &dir->info)) {
1239      (void) FindClose(dir->handle);
1240      dir->handle = INVALID_HANDLE_VALUE;
1241      }
1144#ifdef MONGOOSE_NO_FILESYSTEM
1145#define MONGOOSE_NO_AUTH
1146#define MONGOOSE_NO_CGI
1147#define MONGOOSE_NO_DAV
1148#define MONGOOSE_NO_DIRECTORY_LISTING
1149#define MONGOOSE_NO_LOGGING
1150#define MONGOOSE_NO_SSI
1151#define MONGOOSE_NO_DL
1152#endif
12421153
1243   } else {
1244      SetLastError(ERROR_FILE_NOT_FOUND);
1245   }
1246   } else {
1247   SetLastError(ERROR_BAD_ARGUMENTS);
1248   }
1154struct vec {
1155  const char *ptr;
1156  int len;
1157};
12491158
1250   return result;
1251}
1159// For directory listing and WevDAV support
1160struct dir_entry {
1161  struct connection *conn;
1162  char *file_name;
1163  file_stat_t st;
1164};
12521165
1253#define set_close_on_exec(x) // No FD_CLOEXEC on Windows
1166// NOTE(lsm): this enum shoulds be in sync with the config_options.
1167enum {
1168  ACCESS_CONTROL_LIST,
1169#ifndef MONGOOSE_NO_FILESYSTEM
1170  ACCESS_LOG_FILE,
1171#ifndef MONGOOSE_NO_AUTH
1172  AUTH_DOMAIN,
1173#endif
1174#ifndef MONGOOSE_NO_CGI
1175  CGI_INTERPRETER,
1176  CGI_PATTERN,
1177#endif
1178  DAV_AUTH_FILE,
1179  DOCUMENT_ROOT,
1180#ifndef MONGOOSE_NO_DIRECTORY_LISTING
1181  ENABLE_DIRECTORY_LISTING,
1182#endif
1183#endif
1184  EXTRA_MIME_TYPES,
1185#if !defined(MONGOOSE_NO_FILESYSTEM) && !defined(MONGOOSE_NO_AUTH)
1186  GLOBAL_AUTH_FILE,
1187#endif
1188#ifndef MONGOOSE_NO_FILESYSTEM
1189  HIDE_FILES_PATTERN,
1190  HEXDUMP_FILE,
1191  INDEX_FILES,
1192#endif
1193  LISTENING_PORT,
1194#ifndef _WIN32
1195  RUN_AS_USER,
1196#endif
1197#ifndef MONGOOSE_NO_SSI
1198  SSI_PATTERN,
1199#endif
1200#ifdef NS_ENABLE_SSL
1201  SSL_CERTIFICATE,
1202  SSL_CA_CERTIFICATE,
1203  SSL_MITM_CERTS,
1204#endif
1205  URL_REWRITES,
1206  NUM_OPTIONS
1207};
12541208
1255int mg_start_thread(mg_thread_func_t f, void *p) {
1256   return (long)_beginthread((void (__cdecl *)(void *)) f, 0, p) == -1L ? -1 : 0;
1257}
1258
1259#if !defined(NO_SSL)
1260static HANDLE dlopen(const char *dll_name, int flags) {
1261   wchar_t wbuf[PATH_MAX];
1262   (void) flags;
1263   to_unicode(dll_name, wbuf, ARRAY_SIZE(wbuf));
1264   return LoadLibraryW(wbuf);
1265}
1209static const char *static_config_options[] = {
1210  "access_control_list", NULL,
1211#ifndef MONGOOSE_NO_FILESYSTEM
1212  "access_log_file", NULL,
1213#ifndef MONGOOSE_NO_AUTH
1214  "auth_domain", "mydomain.com",
12661215#endif
1267#if !defined(NO_CGI)
1268#define SIGKILL 0
1269static int kill(pid_t pid, int sig_num) {
1270   (void) TerminateProcess(pid, sig_num);
1271   (void) CloseHandle(pid);
1272   return 0;
1273}
1216#ifndef MONGOOSE_NO_CGI
1217  "cgi_interpreter", NULL,
1218  "cgi_pattern", DEFAULT_CGI_PATTERN,
1219#endif
1220  "dav_auth_file", NULL,
1221  "document_root",  NULL,
1222#ifndef MONGOOSE_NO_DIRECTORY_LISTING
1223  "enable_directory_listing", "yes",
1224#endif
1225#endif
1226  "extra_mime_types", NULL,
1227#if !defined(MONGOOSE_NO_FILESYSTEM) && !defined(MONGOOSE_NO_AUTH)
1228  "global_auth_file", NULL,
1229#endif
1230#ifndef MONGOOSE_NO_FILESYSTEM
1231  "hide_files_patterns", NULL,
1232  "hexdump_file", NULL,
1233  "index_files","index.html,index.htm,index.shtml,index.cgi,index.php,index.lp",
1234#endif
1235  "listening_port", NULL,
1236#ifndef _WIN32
1237  "run_as_user", NULL,
1238#endif
1239#ifndef MONGOOSE_NO_SSI
1240  "ssi_pattern", "**.shtml$|**.shtm$",
1241#endif
1242#ifdef NS_ENABLE_SSL
1243  "ssl_certificate", NULL,
1244  "ssl_ca_certificate", NULL,
1245  "ssl_mitm_certs", NULL,
1246#endif
1247  "url_rewrites", NULL,
1248  NULL
1249};
12741250
1275static void trim_trailing_whitespaces(char *s) {
1276   char *e = s + strlen(s) - 1;
1277   while (e > s && isspace(* (unsigned char *) e)) {
1278   *e-- = '\0';
1279   }
1280}
1251struct mg_server {
1252  struct ns_server ns_server;
1253  union socket_address lsa;   // Listening socket address
1254  mg_handler_t event_handler;
1255  char *config_options[NUM_OPTIONS];
1256};
12811257
1282static pid_t spawn_process(struct mg_connection *conn, const char *prog,
1283                     char *envblk, char *envp[], int fd_stdin,
1284                     int fd_stdout, const char *dir) {
1285   HANDLE me;
1286   char *p, *interp, full_interp[PATH_MAX], full_dir[PATH_MAX],
1287      cmdline[PATH_MAX], buf[PATH_MAX];
1288   struct file file = STRUCT_FILE_INITIALIZER;
1289   STARTUPINFOA si;
1290   PROCESS_INFORMATION pi = { 0 };
1258// Local endpoint representation
1259union endpoint {
1260  int fd;                     // Opened regular local file
1261  struct ns_connection *nc;   // CGI or proxy->target connection
1262};
12911263
1292   (void) envp;
1264enum endpoint_type {
1265 EP_NONE, EP_FILE, EP_CGI, EP_USER, EP_PUT, EP_CLIENT, EP_PROXY
1266};
12931267
1294   memset(&si, 0, sizeof(si));
1295   si.cb = sizeof(si);
1268#define MG_HEADERS_SENT NSF_USER_1
1269#define MG_LONG_RUNNING NSF_USER_2
1270#define MG_CGI_CONN NSF_USER_3
1271#define MG_PROXY_CONN NSF_USER_4
12961272
1297   // TODO(lsm): redirect CGI errors to the error log file
1298   si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
1299   si.wShowWindow = SW_HIDE;
1273struct connection {
1274  struct ns_connection *ns_conn;  // NOTE(lsm): main.c depends on this order
1275  struct mg_connection mg_conn;
1276  struct mg_server *server;
1277  union endpoint endpoint;
1278  enum endpoint_type endpoint_type;
1279  char *path_info;
1280  char *request;
1281  int64_t num_bytes_sent; // Total number of bytes sent
1282  int64_t cl;             // Reply content length, for Range support
1283  int request_len;  // Request length, including last \r\n after last header
1284};
13001285
1301   me = GetCurrentProcess();
1302   DuplicateHandle(me, (HANDLE) _get_osfhandle(fd_stdin), me,
1303               &si.hStdInput, 0, TRUE, DUPLICATE_SAME_ACCESS);
1304   DuplicateHandle(me, (HANDLE) _get_osfhandle(fd_stdout), me,
1305               &si.hStdOutput, 0, TRUE, DUPLICATE_SAME_ACCESS);
1286#define MG_CONN_2_CONN(c) ((struct connection *) ((char *) (c) - \
1287  offsetof(struct connection, mg_conn)))
13061288
1307   // If CGI file is a script, try to read the interpreter line
1308   interp = conn->ctx->config[CGI_INTERPRETER];
1309   if (interp == NULL) {
1310   buf[0] = buf[1] = '\0';
1289static void open_local_endpoint(struct connection *conn, int skip_user);
1290static void close_local_endpoint(struct connection *conn);
13111291
1312   // Read the first line of the script into the buffer
1313   snprintf(cmdline, sizeof(cmdline), "%s%c%s", dir, '/', prog);
1314   if (mg_fopen(conn, cmdline, "r", &file)) {
1315      p = (char *) file.membuf;
1316      mg_fgets(buf, sizeof(buf), &file, &p);
1317      mg_fclose(&file);
1318      buf[sizeof(buf) - 1] = '\0';
1319   }
1292static const struct {
1293  const char *extension;
1294  size_t ext_len;
1295  const char *mime_type;
1296} static_builtin_mime_types[] = {
1297  {".html", 5, "text/html"},
1298  {".htm", 4, "text/html"},
1299  {".shtm", 5, "text/html"},
1300  {".shtml", 6, "text/html"},
1301  {".css", 4, "text/css"},
1302  {".js",  3, "application/x-javascript"},
1303  {".ico", 4, "image/x-icon"},
1304  {".gif", 4, "image/gif"},
1305  {".jpg", 4, "image/jpeg"},
1306  {".jpeg", 5, "image/jpeg"},
1307  {".png", 4, "image/png"},
1308  {".svg", 4, "image/svg+xml"},
1309  {".txt", 4, "text/plain"},
1310  {".torrent", 8, "application/x-bittorrent"},
1311  {".wav", 4, "audio/x-wav"},
1312  {".mp3", 4, "audio/x-mp3"},
1313  {".mid", 4, "audio/mid"},
1314  {".m3u", 4, "audio/x-mpegurl"},
1315  {".ogg", 4, "application/ogg"},
1316  {".ram", 4, "audio/x-pn-realaudio"},
1317  {".xml", 4, "text/xml"},
1318  {".json",  5, "text/json"},
1319  {".xslt", 5, "application/xml"},
1320  {".xsl", 4, "application/xml"},
1321  {".ra",  3, "audio/x-pn-realaudio"},
1322  {".doc", 4, "application/msword"},
1323  {".exe", 4, "application/octet-stream"},
1324  {".zip", 4, "application/x-zip-compressed"},
1325  {".xls", 4, "application/excel"},
1326  {".tgz", 4, "application/x-tar-gz"},
1327  {".tar", 4, "application/x-tar"},
1328  {".gz",  3, "application/x-gunzip"},
1329  {".arj", 4, "application/x-arj-compressed"},
1330  {".rar", 4, "application/x-rar-compressed"},
1331  {".rtf", 4, "application/rtf"},
1332  {".pdf", 4, "application/pdf"},
1333  {".swf", 4, "application/x-shockwave-flash"},
1334  {".mpg", 4, "video/mpeg"},
1335  {".webm", 5, "video/webm"},
1336  {".mpeg", 5, "video/mpeg"},
1337  {".mov", 4, "video/quicktime"},
1338  {".mp4", 4, "video/mp4"},
1339  {".m4v", 4, "video/x-m4v"},
1340  {".asf", 4, "video/x-ms-asf"},
1341  {".avi", 4, "video/x-msvideo"},
1342  {".bmp", 4, "image/bmp"},
1343  {".ttf", 4, "application/x-font-ttf"},
1344  {NULL,  0, NULL}
1345};
13201346
1321   if (buf[0] == '#' && buf[1] == '!') {
1322      trim_trailing_whitespaces(buf + 2);
1323   } else {
1324      buf[2] = '\0';
1325   }
1326   interp = buf + 2;
1327   }
1347#ifndef MONGOOSE_NO_THREADS
1348void *mg_start_thread(void *(*f)(void *), void *p) {
1349  return ns_start_thread(f, p);
1350}
1351#endif  // MONGOOSE_NO_THREADS
13281352
1329   if (interp[0] != '\0') {
1330   GetFullPathNameA(interp, sizeof(full_interp), full_interp, NULL);
1331   interp = full_interp;
1332   }
1333   GetFullPathNameA(dir, sizeof(full_dir), full_dir, NULL);
1353#if defined(_WIN32) && !defined(MONGOOSE_NO_FILESYSTEM)
1354// Encode 'path' which is assumed UTF-8 string, into UNICODE string.
1355// wbuf and wbuf_len is a target buffer and its length.
1356static void to_wchar(const char *path, wchar_t *wbuf, size_t wbuf_len) {
1357  char buf[MAX_PATH_SIZE * 2], buf2[MAX_PATH_SIZE * 2], *p;
13341358
1335   mg_snprintf(conn, cmdline, sizeof(cmdline), "%s%s%s\\%s",
1336            interp, interp[0] == '\0' ? "" : " ", full_dir, prog);
1359  strncpy(buf, path, sizeof(buf));
1360  buf[sizeof(buf) - 1] = '\0';
13371361
1338   DEBUG_TRACE(("Running [%s]", cmdline));
1339   if (CreateProcessA(NULL, cmdline, NULL, NULL, TRUE,
1340      CREATE_NEW_PROCESS_GROUP, envblk, NULL, &si, &pi) == 0) {
1341   cry(conn, "%s: CreateProcess(%s): %ld",
1342      __func__, cmdline, ERRNO);
1343   pi.hProcess = (pid_t) -1;
1344   }
1362  // Trim trailing slashes. Leave backslash for paths like "X:\"
1363  p = buf + strlen(buf) - 1;
1364  while (p > buf && p[-1] != ':' && (p[0] == '\\' || p[0] == '/')) *p-- = '\0';
13451365
1346   // Always close these to prevent handle leakage.
1347   (void) close(fd_stdin);
1348   (void) close(fd_stdout);
1366  // Convert to Unicode and back. If doubly-converted string does not
1367  // match the original, something is fishy, reject.
1368  memset(wbuf, 0, wbuf_len * sizeof(wchar_t));
1369  MultiByteToWideChar(CP_UTF8, 0, buf, -1, wbuf, (int) wbuf_len);
1370  WideCharToMultiByte(CP_UTF8, 0, wbuf, (int) wbuf_len, buf2, sizeof(buf2),
1371                      NULL, NULL);
1372  if (strcmp(buf, buf2) != 0) {
1373    wbuf[0] = L'\0';
1374  }
1375}
13491376
1350   (void) CloseHandle(si.hStdOutput);
1351   (void) CloseHandle(si.hStdInput);
1352   (void) CloseHandle(pi.hThread);
1377static int mg_stat(const char *path, file_stat_t *st) {
1378  wchar_t wpath[MAX_PATH_SIZE];
1379  to_wchar(path, wpath, ARRAY_SIZE(wpath));
1380  DBG(("[%ls] -> %d", wpath, _wstati64(wpath, st)));
1381  return _wstati64(wpath, st);
1382}
13531383
1354   return (pid_t) pi.hProcess;
1384static FILE *mg_fopen(const char *path, const char *mode) {
1385  wchar_t wpath[MAX_PATH_SIZE], wmode[10];
1386  to_wchar(path, wpath, ARRAY_SIZE(wpath));
1387  to_wchar(mode, wmode, ARRAY_SIZE(wmode));
1388  return _wfopen(wpath, wmode);
13551389}
1356#endif // !NO_CGI
13571390
1358static int set_non_blocking_mode(SOCKET sock) {
1359   unsigned long on = 1;
1360   return ioctlsocket(sock, FIONBIO, &on);
1391static int mg_open(const char *path, int flag) {
1392  wchar_t wpath[MAX_PATH_SIZE];
1393  to_wchar(path, wpath, ARRAY_SIZE(wpath));
1394  return _wopen(wpath, flag);
13611395}
1396#endif // _WIN32 && !MONGOOSE_NO_FILESYSTEM
13621397
1363#else
1364static int mg_stat(struct mg_connection *conn, const char *path,
1365               struct file *filep) {
1366   struct stat st;
1398// A helper function for traversing a comma separated list of values.
1399// It returns a list pointer shifted to the next value, or NULL if the end
1400// of the list found.
1401// Value is stored in val vector. If value has form "x=y", then eq_val
1402// vector is initialized to point to the "y" part, and val vector length
1403// is adjusted to point only to "x".
1404static const char *next_option(const char *list, struct vec *val,
1405                               struct vec *eq_val) {
1406  if (list == NULL || *list == '\0') {
1407    // End of the list
1408    list = NULL;
1409  } else {
1410    val->ptr = list;
1411    if ((list = strchr(val->ptr, ',')) != NULL) {
1412      // Comma found. Store length and shift the list ptr
1413      val->len = list - val->ptr;
1414      list++;
1415    } else {
1416      // This value is the last one
1417      list = val->ptr + strlen(val->ptr);
1418      val->len = list - val->ptr;
1419    }
13671420
1368   if (!is_file_in_memory(conn, path, filep) && !stat(path, &st)) {
1369   filep->size = st.st_size;
1370   filep->modification_time = st.st_mtime;
1371   filep->is_directory = S_ISDIR(st.st_mode);
1372   } else {
1373   filep->modification_time = (time_t) 0;
1374   }
1421    if (eq_val != NULL) {
1422      // Value has form "x=y", adjust pointers and lengths
1423      // so that val points to "x", and eq_val points to "y".
1424      eq_val->len = 0;
1425      eq_val->ptr = (const char *) memchr(val->ptr, '=', val->len);
1426      if (eq_val->ptr != NULL) {
1427        eq_val->ptr++;  // Skip over '=' character
1428        eq_val->len = val->ptr + val->len - eq_val->ptr;
1429        val->len = (eq_val->ptr - val->ptr) - 1;
1430      }
1431    }
1432  }
13751433
1376   return filep->membuf != NULL || filep->modification_time != (time_t) 0;
1434  return list;
13771435}
13781436
1379static void set_close_on_exec(int fd) {
1380   fcntl(fd, F_SETFD, FD_CLOEXEC);
1437// Like snprintf(), but never returns negative value, or a value
1438// that is larger than a supplied buffer.
1439static int mg_vsnprintf(char *buf, size_t buflen, const char *fmt, va_list ap) {
1440  int n;
1441  if (buflen < 1) return 0;
1442  n = vsnprintf(buf, buflen, fmt, ap);
1443  if (n < 0) {
1444    n = 0;
1445  } else if (n >= (int) buflen) {
1446    n = (int) buflen - 1;
1447  }
1448  buf[n] = '\0';
1449  return n;
13811450}
13821451
1383int mg_start_thread(mg_thread_func_t func, void *param) {
1384   pthread_t thread_id;
1385   pthread_attr_t attr;
1386   int result;
1452static int mg_snprintf(char *buf, size_t buflen, const char *fmt, ...) {
1453  va_list ap;
1454  int n;
1455  va_start(ap, fmt);
1456  n = mg_vsnprintf(buf, buflen, fmt, ap);
1457  va_end(ap);
1458  return n;
1459}
13871460
1388   (void) pthread_attr_init(&attr);
1389   (void) pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
1390   // TODO(lsm): figure out why mongoose dies on Linux if next line is enabled
1391   // (void) pthread_attr_setstacksize(&attr, sizeof(struct mg_connection) * 5);
1461// Check whether full request is buffered. Return:
1462//   -1  if request is malformed
1463//    0  if request is not yet fully buffered
1464//   >0  actual request length, including last \r\n\r\n
1465static int get_request_len(const char *s, int buf_len) {
1466  const unsigned char *buf = (unsigned char *) s;
1467  int i;
13921468
1393   result = pthread_create(&thread_id, &attr, func, param);
1394   pthread_attr_destroy(&attr);
1469  for (i = 0; i < buf_len; i++) {
1470    // Control characters are not allowed but >=128 are.
1471    // Abort scan as soon as one malformed character is found.
1472    if (!isprint(buf[i]) && buf[i] != '\r' && buf[i] != '\n' && buf[i] < 128) {
1473      return -1;
1474    } else if (buf[i] == '\n' && i + 1 < buf_len && buf[i + 1] == '\n') {
1475      return i + 2;
1476    } else if (buf[i] == '\n' && i + 2 < buf_len && buf[i + 1] == '\r' &&
1477               buf[i + 2] == '\n') {
1478      return i + 3;
1479    }
1480  }
13951481
1396   return result;
1482  return 0;
13971483}
13981484
1399#ifndef NO_CGI
1400static pid_t spawn_process(struct mg_connection *conn, const char *prog,
1401                     char *envblk, char *envp[], int fd_stdin,
1402                     int fd_stdout, const char *dir) {
1403   pid_t pid;
1404   const char *interp;
1485// Skip the characters until one of the delimiters characters found.
1486// 0-terminate resulting word. Skip the rest of the delimiters if any.
1487// Advance pointer to buffer to the next word. Return found 0-terminated word.
1488static char *skip(char **buf, const char *delimiters) {
1489  char *p, *begin_word, *end_word, *end_delimiters;
14051490
1406   (void) envblk;
1491  begin_word = *buf;
1492  end_word = begin_word + strcspn(begin_word, delimiters);
1493  end_delimiters = end_word + strspn(end_word, delimiters);
14071494
1408   if ((pid = fork()) == -1) {
1409   // Parent
1410   send_http_error(conn, 500, http_500_error, "fork(): %s", strerror(ERRNO));
1411   } else if (pid == 0) {
1412   // Child
1413   if (chdir(dir) != 0) {
1414      cry(conn, "%s: chdir(%s): %s", __func__, dir, strerror(ERRNO));
1415   } else if (dup2(fd_stdin, 0) == -1) {
1416      cry(conn, "%s: dup2(%d, 0): %s", __func__, fd_stdin, strerror(ERRNO));
1417   } else if (dup2(fd_stdout, 1) == -1) {
1418      cry(conn, "%s: dup2(%d, 1): %s", __func__, fd_stdout, strerror(ERRNO));
1419   } else {
1420      // Not redirecting stderr to stdout, to avoid output being littered
1421      // with the error messages.
1422      (void) close(fd_stdin);
1423      (void) close(fd_stdout);
1495  for (p = end_word; p < end_delimiters; p++) {
1496    *p = '\0';
1497  }
14241498
1425      // After exec, all signal handlers are restored to their default values,
1426      // with one exception of SIGCHLD. According to POSIX.1-2001 and Linux's
1427      // implementation, SIGCHLD's handler will leave unchanged after exec
1428      // if it was set to be ignored. Restore it to default action.
1429      signal(SIGCHLD, SIG_DFL);
1499  *buf = end_delimiters;
14301500
1431      interp = conn->ctx->config[CGI_INTERPRETER];
1432      if (interp == NULL) {
1433      (void) execle(prog, prog, NULL, envp);
1434      cry(conn, "%s: execle(%s): %s", __func__, prog, strerror(ERRNO));
1435      } else {
1436      (void) execle(interp, interp, prog, NULL, envp);
1437      cry(conn, "%s: execle(%s %s): %s", __func__, interp, prog,
1438         strerror(ERRNO));
1439      }
1440   }
1441   exit(EXIT_FAILURE);
1442   }
1501  return begin_word;
1502}
14431503
1444   // Parent. Close stdio descriptors
1445   (void) close(fd_stdin);
1446   (void) close(fd_stdout);
1504// Parse HTTP headers from the given buffer, advance buffer to the point
1505// where parsing stopped.
1506static void parse_http_headers(char **buf, struct mg_connection *ri) {
1507  size_t i;
14471508
1448   return pid;
1509  for (i = 0; i < ARRAY_SIZE(ri->http_headers); i++) {
1510    ri->http_headers[i].name = skip(buf, ": ");
1511    ri->http_headers[i].value = skip(buf, "\r\n");
1512    if (ri->http_headers[i].name[0] == '\0')
1513      break;
1514    ri->num_headers = i + 1;
1515  }
14491516}
1450#endif // !NO_CGI
14511517
1452static int set_non_blocking_mode(SOCKET sock) {
1453   int flags;
1454
1455   flags = fcntl(sock, F_GETFL, 0);
1456   (void) fcntl(sock, F_SETFL, flags | O_NONBLOCK);
1457
1458   return 0;
1518static const char *status_code_to_str(int status_code) {
1519  switch (status_code) {
1520    case 200: return "OK";
1521    case 201: return "Created";
1522    case 204: return "No Content";
1523    case 301: return "Moved Permanently";
1524    case 302: return "Found";
1525    case 304: return "Not Modified";
1526    case 400: return "Bad Request";
1527    case 403: return "Forbidden";
1528    case 404: return "Not Found";
1529    case 405: return "Method Not Allowed";
1530    case 409: return "Conflict";
1531    case 411: return "Length Required";
1532    case 413: return "Request Entity Too Large";
1533    case 415: return "Unsupported Media Type";
1534    case 423: return "Locked";
1535    case 500: return "Server Error";
1536    case 501: return "Not Implemented";
1537    default:  return "Server Error";
1538  }
14591539}
1460#endif // _WIN32
14611540
1462#ifndef HAVE_POLL
1463static int poll(struct pollfd *pfd, int n, int milliseconds) {
1464   struct timeval tv;
1465   fd_set set;
1466   int i, result, maxfd = 0;
1467
1468   tv.tv_sec = milliseconds / 1000;
1469   tv.tv_usec = (milliseconds % 1000) * 1000;
1470   FD_ZERO(&set);
1471
1472   for (i = 0; i < n; i++) {
1473   FD_SET((SOCKET) pfd[i].fd, &set);
1474   pfd[i].revents = 0;
1475
1476   if (pfd[i].fd > maxfd) {
1477      maxfd = pfd[i].fd;
1478   }
1479   }
1480
1481   if ((result = select(maxfd + 1, &set, NULL, NULL, &tv)) > 0) {
1482   for (i = 0; i < n; i++) {
1483      if (FD_ISSET(pfd[i].fd, &set)) {
1484      pfd[i].revents = POLLIN;
1485      }
1486   }
1487   }
1488
1489   return result;
1541static int call_user(struct connection *conn, enum mg_event ev) {
1542  return conn != NULL && conn->server != NULL &&
1543    conn->server->event_handler != NULL ?
1544    conn->server->event_handler(&conn->mg_conn, ev) : MG_FALSE;
14901545}
1491#endif // HAVE_POLL
14921546
1493// Write data to the IO channel - opened file descriptor, socket or SSL
1494// descriptor. Return number of bytes written.
1495static int64_t push(FILE *fp, SOCKET sock, SSL *ssl, const char *buf,
1496               int64_t len) {
1497   int64_t sent;
1498   int n, k;
1547static void send_http_error(struct connection *conn, int code,
1548                            const char *fmt, ...) {
1549  const char *message = status_code_to_str(code);
1550  const char *rewrites = conn->server->config_options[URL_REWRITES];
1551  char headers[200], body[200];
1552  struct vec a, b;
1553  va_list ap;
1554  int body_len, headers_len, match_code;
14991555
1500   (void) ssl;  // Get rid of warning
1501   sent = 0;
1502   while (sent < len) {
1503   // How many bytes we send in this iteration
1504   k = len - sent > INT_MAX ? INT_MAX : (int) (len - sent);
1556  conn->mg_conn.status_code = code;
15051557
1506#ifndef NO_SSL
1507   if (ssl != NULL) {
1508      n = SSL_write(ssl, buf + sent, k);
1509   } else
1510#endif
1511      if (fp != NULL) {
1512      n = (int) fwrite(buf + sent, 1, (size_t) k, fp);
1513      if (ferror(fp))
1514      n = -1;
1515   } else {
1516      n = send(sock, buf + sent, (size_t) k, MSG_NOSIGNAL);
1517   }
1558  // Invoke error handler if it is set
1559  if (call_user(conn, MG_HTTP_ERROR) == MG_TRUE) {
1560    close_local_endpoint(conn);
1561    return;
1562  }
15181563
1519   if (n <= 0)
1520      break;
1564  // Handle error code rewrites
1565  while ((rewrites = next_option(rewrites, &a, &b)) != NULL) {
1566    if ((match_code = atoi(a.ptr)) > 0 && match_code == code) {
1567      struct mg_connection *c = &conn->mg_conn;
1568      c->status_code = 302;
1569      mg_printf(c, "HTTP/1.1 %d Moved\r\n"
1570                "Location: %.*s?code=%d&orig_uri=%s&query_string=%s\r\n\r\n",
1571                c->status_code, b.len, b.ptr, code, c->uri,
1572                c->query_string == NULL ? "" : c->query_string);
1573      close_local_endpoint(conn);
1574      return;
1575    }
1576  }
15211577
1522   sent += n;
1523   }
1524
1525   return sent;
1578  body_len = mg_snprintf(body, sizeof(body), "%d %s\n", code, message);
1579  if (fmt != NULL) {
1580    va_start(ap, fmt);
1581    body_len += mg_vsnprintf(body + body_len, sizeof(body) - body_len, fmt, ap);
1582    va_end(ap);
1583  }
1584  if ((code >= 300 && code <= 399) || code == 204) {
1585    // 3xx errors do not have body
1586    body_len = 0;
1587  }
1588  headers_len = mg_snprintf(headers, sizeof(headers),
1589                            "HTTP/1.1 %d %s\r\nContent-Length: %d\r\n"
1590                            "Content-Type: text/plain\r\n\r\n",
1591                            code, message, body_len);
1592  ns_send(conn->ns_conn, headers, headers_len);
1593  ns_send(conn->ns_conn, body, body_len);
1594  close_local_endpoint(conn);  // This will write to the log file
15261595}
15271596
1528// Read from IO channel - opened file descriptor, socket, or SSL descriptor.
1529// Return negative value on error, or number of bytes read on success.
1530static int pull(FILE *fp, struct mg_connection *conn, char *buf, int len) {
1531   int nread;
1532
1533   if (fp != NULL) {
1534   // Use read() instead of fread(), because if we're reading from the CGI
1535   // pipe, fread() may block until IO buffer is filled up. We cannot afford
1536   // to block and must pass all read bytes immediately to the client.
1537   nread = read(fileno(fp), buf, (size_t) len);
1538#ifndef NO_SSL
1539   } else if (conn->ssl != NULL) {
1540   nread = SSL_read(conn->ssl, buf, len);
1541#endif
1542   } else {
1543   nread = recv(conn->client.sock, buf, (size_t) len, 0);
1544   }
1545
1546   return conn->ctx->stop_flag ? -1 : nread;
1597static void write_chunk(struct connection *conn, const char *buf, int len) {
1598  char chunk_size[50];
1599  int n = mg_snprintf(chunk_size, sizeof(chunk_size), "%X\r\n", len);
1600  ns_send(conn->ns_conn, chunk_size, n);
1601  ns_send(conn->ns_conn, buf, len);
1602  ns_send(conn->ns_conn, "\r\n", 2);
15471603}
15481604
1549static int pull_all(FILE *fp, struct mg_connection *conn, char *buf, int len) {
1550   int n, nread = 0;
1605int mg_printf(struct mg_connection *conn, const char *fmt, ...) {
1606  struct connection *c = MG_CONN_2_CONN(conn);
1607  int len;
1608  va_list ap;
15511609
1552   while (len > 0) {
1553   n = pull(fp, conn, buf + nread, len);
1554   if (n < 0) {
1555      nread = n;  // Propagate the error
1556      break;
1557   } else if (n == 0) {
1558      break;  // No more data to read
1559   } else {
1560      conn->consumed_content += n;
1561      nread += n;
1562      len -= n;
1563   }
1564   }
1610  va_start(ap, fmt);
1611  len = ns_vprintf(c->ns_conn, fmt, ap);
1612  va_end(ap);
15651613
1566   return nread;
1614  return len;
15671615}
15681616
1569int mg_read(struct mg_connection *conn, void *buf, size_t len) {
1570   int n, buffered_len, nread;
1571   const char *body;
1572
1573   // If Content-Length is not set, read until socket is closed
1574   if (conn->consumed_content == 0 && conn->content_len == 0) {
1575   conn->content_len = INT64_MAX;
1576   conn->must_close = 1;
1577   }
1578
1579   nread = 0;
1580   if (conn->consumed_content < conn->content_len) {
1581   // Adjust number of bytes to read.
1582   int64_t to_read = conn->content_len - conn->consumed_content;
1583   if (to_read < (int64_t) len) {
1584      len = (size_t) to_read;
1585   }
1586
1587   // Return buffered data
1588   body = conn->buf + conn->request_len + conn->consumed_content;
1589   buffered_len = &conn->buf[conn->data_len] - body;
1590   if (buffered_len > 0) {
1591      if (len < (size_t) buffered_len) {
1592      buffered_len = (int) len;
1593      }
1594      memcpy(buf, body, (size_t) buffered_len);
1595      len -= buffered_len;
1596      conn->consumed_content += buffered_len;
1597      nread += buffered_len;
1598      buf = (char *) buf + buffered_len;
1599   }
1600
1601   // We have returned all buffered data. Read new data from the remote socket.
1602   n = pull_all(NULL, conn, (char *) buf, (int) len);
1603   nread = n >= 0 ? nread + n : n;
1604   }
1605   return nread;
1617static void ns_forward(struct ns_connection *from, struct ns_connection *to) {
1618  DBG(("%p -> %p %zu bytes", from, to, from->recv_iobuf.len));
1619  ns_send(to, from->recv_iobuf.buf, from->recv_iobuf.len);
1620  iobuf_remove(&from->recv_iobuf, from->recv_iobuf.len);
16061621}
16071622
1608int mg_write(struct mg_connection *conn, const void *buf, size_t len) {
1609   time_t now;
1610   int64_t n, total, allowed;
1623#ifndef MONGOOSE_NO_CGI
1624#ifdef _WIN32
1625struct threadparam {
1626  sock_t s;
1627  HANDLE hPipe;
1628};
16111629
1612   if (conn->throttle > 0) {
1613   if ((now = time(NULL)) != conn->last_throttle_time) {
1614      conn->last_throttle_time = now;
1615      conn->last_throttle_bytes = 0;
1616   }
1617   allowed = conn->throttle - conn->last_throttle_bytes;
1618   if (allowed > (int64_t) len) {
1619      allowed = len;
1620   }
1621   if ((total = push(NULL, conn->client.sock, conn->ssl, (const char *) buf,
1622                  (int64_t) allowed)) == allowed) {
1623      buf = (char *) buf + total;
1624      conn->last_throttle_bytes += total;
1625      while (total < (int64_t) len && conn->ctx->stop_flag == 0) {
1626      allowed = conn->throttle > (int64_t) len - total ?
1627         (int64_t) len - total : conn->throttle;
1628      if ((n = push(NULL, conn->client.sock, conn->ssl, (const char *) buf,
1629                  (int64_t) allowed)) != allowed) {
1630         break;
1631      }
1632      sleep(1);
1633      conn->last_throttle_bytes = allowed;
1634      conn->last_throttle_time = time(NULL);
1635      buf = (char *) buf + n;
1636      total += n;
1637      }
1638   }
1639   } else {
1640   total = push(NULL, conn->client.sock, conn->ssl, (const char *) buf,
1641               (int64_t) len);
1642   }
1643   return (int) total;
1630static int wait_until_ready(sock_t sock, int for_read) {
1631  fd_set set;
1632  FD_ZERO(&set);
1633  FD_SET(sock, &set);
1634  select(sock + 1, for_read ? &set : 0, for_read ? 0 : &set, 0, 0);
1635  return 1;
16441636}
16451637
1646// Print message to buffer. If buffer is large enough to hold the message,
1647// return buffer. If buffer is to small, allocate large enough buffer on heap,
1648// and return allocated buffer.
1649static int alloc_vprintf(char **buf, size_t size, const char *fmt, va_list ap) {
1650   va_list ap_copy;
1651   int len;
1638static void *push_to_stdin(void *arg) {
1639  struct threadparam *tp = (struct threadparam *)arg;
1640  int n, sent, stop = 0;
1641  DWORD k;
1642  char buf[IOBUF_SIZE];
16521643
1653   // Windows is not standard-compliant, and vsnprintf() returns -1 if
1654   // buffer is too small. Also, older versions of msvcrt.dll do not have
1655   // _vscprintf().  However, if size is 0, vsnprintf() behaves correctly.
1656   // Therefore, we make two passes: on first pass, get required message length.
1657   // On second pass, actually print the message.
1658   va_copy(ap_copy, ap);
1659   len = vsnprintf(NULL, 0, fmt, ap_copy);
1660
1661   if (len > (int) size &&
1662      (size = len + 1) > 0 &&
1663      (*buf = (char *) malloc(size)) == NULL) {
1664   len = -1;  // Allocation failed, mark failure
1665   } else {
1666   va_copy(ap_copy, ap);
1667   vsnprintf(*buf, size, fmt, ap_copy);
1668   }
1669
1670   return len;
1644  while (!stop && wait_until_ready(tp->s, 1) &&
1645         (n = recv(tp->s, buf, sizeof(buf), 0)) > 0) {
1646    if (n == -1 && GetLastError() == WSAEWOULDBLOCK) continue;
1647    for (sent = 0; !stop && sent < n; sent += k) {
1648      if (!WriteFile(tp->hPipe, buf + sent, n - sent, &k, 0)) stop = 1;
1649    }
1650  }
1651  DBG(("%s", "FORWARED EVERYTHING TO CGI"));
1652  CloseHandle(tp->hPipe);
1653  free(tp);
1654  _endthread();
1655  return NULL;
16711656}
16721657
1673int mg_vprintf(struct mg_connection *conn, const char *fmt, va_list ap) {
1674   char mem[MG_BUF_LEN], *buf = mem;
1675   int len;
1658static void *pull_from_stdout(void *arg) {
1659  struct threadparam *tp = (struct threadparam *)arg;
1660  int k, stop = 0;
1661  DWORD n, sent;
1662  char buf[IOBUF_SIZE];
16761663
1677   if ((len = alloc_vprintf(&buf, sizeof(mem), fmt, ap)) > 0) {
1678   len = mg_write(conn, buf, (size_t) len);
1679   }
1680   if (buf != mem && buf != NULL) {
1681   free(buf);
1682   }
1683
1684   return len;
1664  while (!stop && ReadFile(tp->hPipe, buf, sizeof(buf), &n, NULL)) {
1665    for (sent = 0; !stop && sent < n; sent += k) {
1666      if (wait_until_ready(tp->s, 0) &&
1667          (k = send(tp->s, buf + sent, n - sent, 0)) <= 0) stop = 1;
1668    }
1669  }
1670  DBG(("%s", "EOF FROM CGI"));
1671  CloseHandle(tp->hPipe);
1672  shutdown(tp->s, 2);  // Without this, IO thread may get truncated data
1673  closesocket(tp->s);
1674  free(tp);
1675  _endthread();
1676  return NULL;
16851677}
16861678
1687int mg_printf(struct mg_connection *conn, const char *fmt, ...) {
1688   va_list ap;
1689   va_start(ap, fmt);
1690   return mg_vprintf(conn, fmt, ap);
1679static void spawn_stdio_thread(sock_t sock, HANDLE hPipe,
1680                               void *(*func)(void *)) {
1681  struct threadparam *tp = (struct threadparam *)malloc(sizeof(*tp));
1682  if (tp != NULL) {
1683    tp->s = sock;
1684    tp->hPipe = hPipe;
1685    mg_start_thread(func, tp);
1686  }
16911687}
16921688
1693int mg_url_decode(const char *src, int src_len, char *dst,
1694               int dst_len, int is_form_url_encoded) {
1695   int i, j, a, b;
1696#define HEXTOI(x) (isdigit(x) ? x - '0' : x - 'W')
1697
1698   for (i = j = 0; i < src_len && j < dst_len - 1; i++, j++) {
1699   if (src[i] == '%' && i < src_len - 2 &&
1700      isxdigit(* (const unsigned char *) (src + i + 1)) &&
1701      isxdigit(* (const unsigned char *) (src + i + 2))) {
1702      a = tolower(* (const unsigned char *) (src + i + 1));
1703      b = tolower(* (const unsigned char *) (src + i + 2));
1704      dst[j] = (char) ((HEXTOI(a) << 4) | HEXTOI(b));
1705      i += 2;
1706   } else if (is_form_url_encoded && src[i] == '+') {
1707      dst[j] = ' ';
1708   } else {
1709      dst[j] = src[i];
1710   }
1711   }
1712
1713   dst[j] = '\0'; // Null-terminate the destination
1714
1715   return i >= src_len ? j : -1;
1689static void abs_path(const char *utf8_path, char *abs_path, size_t len) {
1690  wchar_t buf[MAX_PATH_SIZE], buf2[MAX_PATH_SIZE];
1691  to_wchar(utf8_path, buf, ARRAY_SIZE(buf));
1692  GetFullPathNameW(buf, ARRAY_SIZE(buf2), buf2, NULL);
1693  WideCharToMultiByte(CP_UTF8, 0, buf2, wcslen(buf2) + 1, abs_path, len, 0, 0);
17161694}
17171695
1718int mg_get_var(const char *data, size_t data_len, const char *name,
1719            char *dst, size_t dst_len) {
1720   const char *p, *e, *s;
1721   size_t name_len;
1722   int len;
1696static process_id_t start_process(char *interp, const char *cmd,
1697                                  const char *env, const char *envp[],
1698                                  const char *dir, sock_t sock) {
1699  STARTUPINFOW si = {0};
1700  PROCESS_INFORMATION pi = {0};
1701  HANDLE a[2], b[2], me = GetCurrentProcess();
1702  wchar_t wcmd[MAX_PATH_SIZE], full_dir[MAX_PATH_SIZE];
1703  char buf[MAX_PATH_SIZE], buf4[MAX_PATH_SIZE], buf5[MAX_PATH_SIZE],
1704       cmdline[MAX_PATH_SIZE], *p;
1705  DWORD flags = DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS;
1706  FILE *fp;
17231707
1724   if (dst == NULL || dst_len == 0) {
1725   len = -2;
1726   } else if (data == NULL || name == NULL || data_len == 0) {
1727   len = -1;
1728   dst[0] = '\0';
1729   } else {
1730   name_len = strlen(name);
1731   e = data + data_len;
1732   len = -1;
1733   dst[0] = '\0';
1708  si.cb = sizeof(si);
1709  si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
1710  si.wShowWindow = SW_HIDE;
1711  si.hStdError = GetStdHandle(STD_ERROR_HANDLE);
17341712
1735   // data is "var1=val1&var2=val2...". Find variable first
1736   for (p = data; p + name_len < e; p++) {
1737      if ((p == data || p[-1] == '&') && p[name_len] == '=' &&
1738         !mg_strncasecmp(name, p, name_len)) {
1739      // Point p to variable value
1740      p += name_len + 1;
1713  CreatePipe(&a[0], &a[1], NULL, 0);
1714  CreatePipe(&b[0], &b[1], NULL, 0);
1715  DuplicateHandle(me, a[0], me, &si.hStdInput, 0, TRUE, flags);
1716  DuplicateHandle(me, b[1], me, &si.hStdOutput, 0, TRUE, flags);
17411717
1742      // Point s to the end of the value
1743      s = (const char *) memchr(p, '&', (size_t)(e - p));
1744      if (s == NULL) {
1745         s = e;
1746      }
1747      assert(s >= p);
1718  if (interp == NULL && (fp = fopen(cmd, "r")) != NULL) {
1719    buf[0] = buf[1] = '\0';
1720    fgets(buf, sizeof(buf), fp);
1721    buf[sizeof(buf) - 1] = '\0';
1722    if (buf[0] == '#' && buf[1] == '!') {
1723      interp = buf + 2;
1724      for (p = interp + strlen(interp);
1725           isspace(* (uint8_t *) p) && p > interp; p--) *p = '\0';
1726    }
1727    fclose(fp);
1728  }
17481729
1749      // Decode variable into destination buffer
1750      len = mg_url_decode(p, (size_t)(s - p), dst, dst_len, 1);
1730  if (interp != NULL) {
1731    abs_path(interp, buf4, ARRAY_SIZE(buf4));
1732    interp = buf4;
1733  }
1734  abs_path(dir, buf5, ARRAY_SIZE(buf5));
1735  to_wchar(dir, full_dir, ARRAY_SIZE(full_dir));
1736  mg_snprintf(cmdline, sizeof(cmdline), "%s%s\"%s\"",
1737              interp ? interp : "", interp ? " " : "", cmd);
1738  to_wchar(cmdline, wcmd, ARRAY_SIZE(wcmd));
17511739
1752      // Redirect error code from -1 to -2 (destination buffer too small).
1753      if (len == -1) {
1754         len = -2;
1755      }
1756      break;
1757      }
1758   }
1759   }
1740  if (CreateProcessW(NULL, wcmd, NULL, NULL, TRUE, CREATE_NEW_PROCESS_GROUP,
1741                     (void *) env, full_dir, &si, &pi) != 0) {
1742    spawn_stdio_thread(sock, a[1], push_to_stdin);
1743    spawn_stdio_thread(sock, b[0], pull_from_stdout);
1744  } else {
1745    CloseHandle(a[1]);
1746    CloseHandle(b[0]);
1747    closesocket(sock);
1748  }
1749  DBG(("CGI command: [%ls] -> %p", wcmd, pi.hProcess));
17601750
1761   return len;
1762}
1751  CloseHandle(si.hStdOutput);
1752  CloseHandle(si.hStdInput);
1753  CloseHandle(a[0]);
1754  CloseHandle(b[1]);
1755  CloseHandle(pi.hThread);
1756  CloseHandle(pi.hProcess);
17631757
1764int mg_get_cookie(const char *cookie_header, const char *var_name,
1765               char *dst, size_t dst_size) {
1766   const char *s, *p, *end;
1767   int name_len, len = -1;
1768
1769   if (dst == NULL || dst_size == 0) {
1770   len = -2;
1771   } else if (var_name == NULL || (s = cookie_header) == NULL) {
1772   len = -1;
1773   dst[0] = '\0';
1774   } else {
1775   name_len = (int) strlen(var_name);
1776   end = s + strlen(s);
1777   dst[0] = '\0';
1778
1779   for (; (s = mg_strcasestr(s, var_name)) != NULL; s += name_len) {
1780      if (s[name_len] == '=') {
1781      s += name_len + 1;
1782      if ((p = strchr(s, ' ')) == NULL)
1783         p = end;
1784      if (p[-1] == ';')
1785         p--;
1786      if (*s == '"' && p[-1] == '"' && p > s + 1) {
1787         s++;
1788         p--;
1789      }
1790      if ((size_t) (p - s) < dst_size) {
1791         len = p - s;
1792         mg_strlcpy(dst, s, (size_t) len + 1);
1793      } else {
1794         len = -3;
1795      }
1796      break;
1797      }
1798   }
1799   }
1800   return len;
1758  return pi.hProcess;
18011759}
1760#else
1761static process_id_t start_process(const char *interp, const char *cmd,
1762                                  const char *env, const char *envp[],
1763                                  const char *dir, sock_t sock) {
1764  char buf[500];
1765  process_id_t pid = fork();
1766  (void) env;
18021767
1803static void convert_uri_to_file_name(struct mg_connection *conn, char *buf,
1804                              size_t buf_len, struct file *filep) {
1805   struct vec a, b;
1806   const char *rewrite, *uri = conn->request_info.uri;
1807   char *p;
1808   int match_len;
1809   char gz_path[PATH_MAX];
1810   char const* accept_encoding;
1768  if (pid == 0) {
1769    (void) chdir(dir);
1770    (void) dup2(sock, 0);
1771    (void) dup2(sock, 1);
1772    closesocket(sock);
18111773
1812   // Using buf_len - 1 because memmove() for PATH_INFO may shift part
1813   // of the path one byte on the right.
1814   mg_snprintf(conn, buf, buf_len - 1, "%s%s", conn->ctx->config[DOCUMENT_ROOT],
1815            uri);
1774    // After exec, all signal handlers are restored to their default values,
1775    // with one exception of SIGCHLD. According to POSIX.1-2001 and Linux's
1776    // implementation, SIGCHLD's handler will leave unchanged after exec
1777    // if it was set to be ignored. Restore it to default action.
1778    signal(SIGCHLD, SIG_DFL);
18161779
1817   rewrite = conn->ctx->config[REWRITE];
1818   while ((rewrite = next_option(rewrite, &a, &b)) != NULL) {
1819   if ((match_len = match_prefix(a.ptr, a.len, uri)) > 0) {
1820      mg_snprintf(conn, buf, buf_len - 1, "%.*s%s", (int) b.len, b.ptr,
1821               uri + match_len);
1822      break;
1823   }
1824   }
1780    if (interp == NULL) {
1781      execle(cmd, cmd, NULL, envp);
1782    } else {
1783      execle(interp, interp, cmd, NULL, envp);
1784    }
1785    snprintf(buf, sizeof(buf), "Status: 500\r\n\r\n"
1786             "500 Server Error: %s%s%s: %s", interp == NULL ? "" : interp,
1787             interp == NULL ? "" : " ", cmd, strerror(errno));
1788    send(1, buf, strlen(buf), 0);
1789    exit(EXIT_FAILURE);  // exec call failed
1790  }
18251791
1826   if (mg_stat(conn, buf, filep)) return;
1827
1828   // if we can't find the actual file, look for the file
1829   // with the same name but a .gz extension. If we find it,
1830   // use that and set the gzipped flag in the file struct
1831   // to indicate that the response need to have the content-
1832   // encoding: gzip header
1833   // we can only do this if the browser declares support
1834   if ((accept_encoding = mg_get_header(conn, "Accept-Encoding")) != NULL) {
1835   if (strstr(accept_encoding,"gzip") != NULL) {
1836      snprintf(gz_path, sizeof(gz_path), "%s.gz", buf);
1837      if (mg_stat(conn, gz_path, filep)) {
1838      filep->gzipped = 1;
1839      return;
1840      }
1841   }
1842   }
1843
1844   // Support PATH_INFO for CGI scripts.
1845   for (p = buf + strlen(buf); p > buf + 1; p--) {
1846   if (*p == '/') {
1847      *p = '\0';
1848      if (match_prefix(conn->ctx->config[CGI_EXTENSIONS],
1849                  strlen(conn->ctx->config[CGI_EXTENSIONS]), buf) > 0 &&
1850         mg_stat(conn, buf, filep)) {
1851      // Shift PATH_INFO block one character right, e.g.
1852      //  "/x.cgi/foo/bar\x00" => "/x.cgi\x00/foo/bar\x00"
1853      // conn->path_info is pointing to the local variable "path" declared
1854      // in handle_request(), so PATH_INFO is not valid after
1855      // handle_request returns.
1856      conn->path_info = p + 1;
1857      memmove(p + 2, p + 1, strlen(p + 1) + 1);  // +1 is for trailing \0
1858      p[1] = '/';
1859      break;
1860      } else {
1861      *p = '/';
1862      }
1863   }
1864   }
1792  return pid;
18651793}
1794#endif  // _WIN32
18661795
1867// Check whether full request is buffered. Return:
1868//   -1  if request is malformed
1869//    0  if request is not yet fully buffered
1870//   >0  actual request length, including last \r\n\r\n
1871static int get_request_len(const char *buf, int buflen) {
1872   const char *s, *e;
1873   int len = 0;
1796// This structure helps to create an environment for the spawned CGI program.
1797// Environment is an array of "VARIABLE=VALUE\0" ASCIIZ strings,
1798// last element must be NULL.
1799// However, on Windows there is a requirement that all these VARIABLE=VALUE\0
1800// strings must reside in a contiguous buffer. The end of the buffer is
1801// marked by two '\0' characters.
1802// We satisfy both worlds: we create an envp array (which is vars), all
1803// entries are actually pointers inside buf.
1804struct cgi_env_block {
1805  struct mg_connection *conn;
1806  char buf[CGI_ENVIRONMENT_SIZE];       // Environment buffer
1807  const char *vars[MAX_CGI_ENVIR_VARS]; // char *envp[]
1808  int len;                              // Space taken
1809  int nvars;                            // Number of variables in envp[]
1810};
18741811
1875   for (s = buf, e = s + buflen - 1; len <= 0 && s < e; s++)
1876   // Control characters are not allowed but >=128 is.
1877   if (!isprint(* (const unsigned char *) s) && *s != '\r' &&
1878      *s != '\n' && * (const unsigned char *) s < 128) {
1879      len = -1;
1880      break;  // [i_a] abort scan as soon as one malformed character is found;
1881            // don't let subsequent \r\n\r\n win us over anyhow
1882   } else if (s[0] == '\n' && s[1] == '\n') {
1883      len = (int) (s - buf) + 2;
1884   } else if (s[0] == '\n' && &s[1] < e &&
1885      s[1] == '\r' && s[2] == '\n') {
1886      len = (int) (s - buf) + 3;
1887   }
1812// Append VARIABLE=VALUE\0 string to the buffer, and add a respective
1813// pointer into the vars array.
1814static char *addenv(struct cgi_env_block *block, const char *fmt, ...) {
1815  int n, space;
1816  char *added;
1817  va_list ap;
18881818
1889   return len;
1890}
1819  // Calculate how much space is left in the buffer
1820  space = sizeof(block->buf) - block->len - 2;
1821  assert(space >= 0);
18911822
1892// Convert month to the month number. Return -1 on error, or month number
1893static int get_month_index(const char *s) {
1894   size_t i;
1823  // Make a pointer to the free space int the buffer
1824  added = block->buf + block->len;
18951825
1896   for (i = 0; i < ARRAY_SIZE(month_names); i++)
1897   if (!strcmp(s, month_names[i]))
1898      return (int) i;
1826  // Copy VARIABLE=VALUE\0 string into the free space
1827  va_start(ap, fmt);
1828  n = mg_vsnprintf(added, (size_t) space, fmt, ap);
1829  va_end(ap);
18991830
1900   return -1;
1901}
1831  // Make sure we do not overflow buffer and the envp array
1832  if (n > 0 && n + 1 < space &&
1833      block->nvars < (int) ARRAY_SIZE(block->vars) - 2) {
1834    // Append a pointer to the added string into the envp array
1835    block->vars[block->nvars++] = added;
1836    // Bump up used length counter. Include \0 terminator
1837    block->len += n + 1;
1838  }
19021839
1903static int num_leap_years(int year) {
1904   return year / 4 - year / 100 + year / 400;
1840  return added;
19051841}
19061842
1907// Parse UTC date-time string, and return the corresponding time_t value.
1908static time_t parse_date_string(const char *datetime) {
1909   static const unsigned short days_before_month[] = {
1910   0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334
1911   };
1912   char month_str[32];
1913   int second, minute, hour, day, month, year, leap_days, days;
1914   time_t result = (time_t) 0;
1915
1916   if (((sscanf(datetime, "%d/%3s/%d %d:%d:%d",
1917            &day, month_str, &year, &hour, &minute, &second) == 6) ||
1918      (sscanf(datetime, "%d %3s %d %d:%d:%d",
1919            &day, month_str, &year, &hour, &minute, &second) == 6) ||
1920      (sscanf(datetime, "%*3s, %d %3s %d %d:%d:%d",
1921            &day, month_str, &year, &hour, &minute, &second) == 6) ||
1922      (sscanf(datetime, "%d-%3s-%d %d:%d:%d",
1923            &day, month_str, &year, &hour, &minute, &second) == 6)) &&
1924      year > 1970 &&
1925      (month = get_month_index(month_str)) != -1) {
1926   leap_days = num_leap_years(year) - num_leap_years(1970);
1927   year -= 1970;
1928   days = year * 365 + days_before_month[month] + (day - 1) + leap_days;
1929   result = days * 24 * 3600 + hour * 3600 + minute * 60 + second;
1930   }
1931
1932   return result;
1843static void addenv2(struct cgi_env_block *blk, const char *name) {
1844  const char *s;
1845  if ((s = getenv(name)) != NULL) addenv(blk, "%s=%s", name, s);
19331846}
19341847
1935// Protect against directory disclosure attack by removing '..',
1936// excessive '/' and '\' characters
1937static void remove_double_dots_and_double_slashes(char *s) {
1938   char *p = s;
1848static void prepare_cgi_environment(struct connection *conn,
1849                                    const char *prog,
1850                                    struct cgi_env_block *blk) {
1851  struct mg_connection *ri = &conn->mg_conn;
1852  const char *s, *slash;
1853  char *p, **opts = conn->server->config_options;
1854  int  i;
19391855
1940   while (*s != '\0') {
1941   *p++ = *s++;
1942   if (s[-1] == '/' || s[-1] == '\\') {
1943      // Skip all following slashes, backslashes and double-dots
1944      while (s[0] != '\0') {
1945      if (s[0] == '/' || s[0] == '\\') {
1946         s++;
1947      } else if (s[0] == '.' && s[1] == '.') {
1948         s += 2;
1949      } else {
1950         break;
1951      }
1952      }
1953   }
1954   }
1955   *p = '\0';
1956}
1856  blk->len = blk->nvars = 0;
1857  blk->conn = ri;
19571858
1958static const struct {
1959   const char *extension;
1960   size_t ext_len;
1961   const char *mime_type;
1962} builtin_mime_types[] = {
1963   {".html", 5, "text/html"},
1964   {".htm", 4, "text/html"},
1965   {".shtm", 5, "text/html"},
1966   {".shtml", 6, "text/html"},
1967   {".css", 4, "text/css"},
1968   {".js",  3, "application/x-javascript"},
1969   {".ico", 4, "image/x-icon"},
1970   {".gif", 4, "image/gif"},
1971   {".jpg", 4, "image/jpeg"},
1972   {".jpeg", 5, "image/jpeg"},
1973   {".png", 4, "image/png"},
1974   {".svg", 4, "image/svg+xml"},
1975   {".txt", 4, "text/plain"},
1976   {".torrent", 8, "application/x-bittorrent"},
1977   {".wav", 4, "audio/x-wav"},
1978   {".mp3", 4, "audio/x-mp3"},
1979   {".mid", 4, "audio/mid"},
1980   {".m3u", 4, "audio/x-mpegurl"},
1981   {".ogg", 4, "audio/ogg"},
1982   {".ram", 4, "audio/x-pn-realaudio"},
1983   {".xml", 4, "text/xml"},
1984   {".json",  5, "text/json"},
1985   {".xslt", 5, "application/xml"},
1986   {".xsl", 4, "application/xml"},
1987   {".ra",  3, "audio/x-pn-realaudio"},
1988   {".doc", 4, "application/msword"},
1989   {".exe", 4, "application/octet-stream"},
1990   {".zip", 4, "application/x-zip-compressed"},
1991   {".xls", 4, "application/excel"},
1992   {".tgz", 4, "application/x-tar-gz"},
1993   {".tar", 4, "application/x-tar"},
1994   {".gz",  3, "application/x-gunzip"},
1995   {".arj", 4, "application/x-arj-compressed"},
1996   {".rar", 4, "application/x-arj-compressed"},
1997   {".rtf", 4, "application/rtf"},
1998   {".pdf", 4, "application/pdf"},
1999   {".swf", 4, "application/x-shockwave-flash"},
2000   {".mpg", 4, "video/mpeg"},
2001   {".webm", 5, "video/webm"},
2002   {".mpeg", 5, "video/mpeg"},
2003   {".mov", 4, "video/quicktime"},
2004   {".mp4", 4, "video/mp4"},
2005   {".m4v", 4, "video/x-m4v"},
2006   {".asf", 4, "video/x-ms-asf"},
2007   {".avi", 4, "video/x-msvideo"},
2008   {".bmp", 4, "image/bmp"},
2009   {".ttf", 4, "application/x-font-ttf"},
2010   {NULL,  0, NULL}
2011};
1859  if ((s = getenv("SERVER_NAME")) != NULL) {
1860    addenv(blk, "SERVER_NAME=%s", s);
1861  } else {
1862    addenv(blk, "SERVER_NAME=%s", ri->local_ip);
1863  }
1864  addenv(blk, "SERVER_ROOT=%s", opts[DOCUMENT_ROOT]);
1865  addenv(blk, "DOCUMENT_ROOT=%s", opts[DOCUMENT_ROOT]);
1866  addenv(blk, "SERVER_SOFTWARE=%s/%s", "Mongoose", MONGOOSE_VERSION);
20121867
2013const char *mg_get_builtin_mime_type(const char *path) {
2014   const char *ext;
2015   size_t i, path_len;
1868  // Prepare the environment block
1869  addenv(blk, "%s", "GATEWAY_INTERFACE=CGI/1.1");
1870  addenv(blk, "%s", "SERVER_PROTOCOL=HTTP/1.1");
1871  addenv(blk, "%s", "REDIRECT_STATUS=200"); // For PHP
20161872
2017   path_len = strlen(path);
1873  // TODO(lsm): fix this for IPv6 case
1874  //addenv(blk, "SERVER_PORT=%d", ri->remote_port);
20181875
2019   for (i = 0; builtin_mime_types[i].extension != NULL; i++) {
2020   ext = path + (path_len - builtin_mime_types[i].ext_len);
2021   if (path_len > builtin_mime_types[i].ext_len &&
2022      mg_strcasecmp(ext, builtin_mime_types[i].extension) == 0) {
2023      return builtin_mime_types[i].mime_type;
2024   }
2025   }
1876  addenv(blk, "REQUEST_METHOD=%s", ri->request_method);
1877  addenv(blk, "REMOTE_ADDR=%s", ri->remote_ip);
1878  addenv(blk, "REMOTE_PORT=%d", ri->remote_port);
1879  addenv(blk, "REQUEST_URI=%s%s%s", ri->uri,
1880         ri->query_string == NULL ? "" : "?",
1881         ri->query_string == NULL ? "" : ri->query_string);
20261882
2027   return "text/plain";
2028}
1883  // SCRIPT_NAME
1884  if (conn->path_info != NULL) {
1885    addenv(blk, "SCRIPT_NAME=%.*s",
1886           (int) (strlen(ri->uri) - strlen(conn->path_info)), ri->uri);
1887    addenv(blk, "PATH_INFO=%s", conn->path_info);
1888  } else {
1889    s = strrchr(prog, '/');
1890    slash = strrchr(ri->uri, '/');
1891    addenv(blk, "SCRIPT_NAME=%.*s%s",
1892           slash == NULL ? 0 : (int) (slash - ri->uri), ri->uri,
1893           s == NULL ? prog : s);
1894  }
20291895
2030// Look at the "path" extension and figure what mime type it has.
2031// Store mime type in the vector.
2032static void get_mime_type(struct mg_context *ctx, const char *path,
2033                     struct vec *vec) {
2034   struct vec ext_vec, mime_vec;
2035   const char *list, *ext;
2036   size_t path_len;
1896  addenv(blk, "SCRIPT_FILENAME=%s", prog);
1897  addenv(blk, "PATH_TRANSLATED=%s", prog);
1898  addenv(blk, "HTTPS=%s", conn->ns_conn->ssl != NULL ? "on" : "off");
20371899
2038   path_len = strlen(path);
1900  if ((s = mg_get_header(ri, "Content-Type")) != NULL)
1901    addenv(blk, "CONTENT_TYPE=%s", s);
20391902
2040   // Scan user-defined mime types first, in case user wants to
2041   // override default mime types.
2042   list = ctx->config[EXTRA_MIME_TYPES];
2043   while ((list = next_option(list, &ext_vec, &mime_vec)) != NULL) {
2044   // ext now points to the path suffix
2045   ext = path + path_len - ext_vec.len;
2046   if (mg_strncasecmp(ext, ext_vec.ptr, ext_vec.len) == 0) {
2047      *vec = mime_vec;
2048      return;
2049   }
2050   }
1903  if (ri->query_string != NULL)
1904    addenv(blk, "QUERY_STRING=%s", ri->query_string);
20511905
2052   vec->ptr = mg_get_builtin_mime_type(path);
2053   vec->len = strlen(vec->ptr);
2054}
1906  if ((s = mg_get_header(ri, "Content-Length")) != NULL)
1907    addenv(blk, "CONTENT_LENGTH=%s", s);
20551908
2056static int is_big_endian(void) {
2057   static const int n = 1;
2058   return ((char *) &n)[0] == 0;
2059}
1909  addenv2(blk, "PATH");
1910  addenv2(blk, "TMP");
1911  addenv2(blk, "TEMP");
1912  addenv2(blk, "TMPDIR");
1913  addenv2(blk, "PERLLIB");
1914  addenv2(blk, ENV_EXPORT_TO_CGI);
20601915
2061#ifndef HAVE_MD5
2062typedef struct MD5Context {
2063   uint32_t buf[4];
2064   uint32_t bits[2];
2065   unsigned char in[64];
2066} MD5_CTX;
1916#if defined(_WIN32)
1917  addenv2(blk, "COMSPEC");
1918  addenv2(blk, "SYSTEMROOT");
1919  addenv2(blk, "SystemDrive");
1920  addenv2(blk, "ProgramFiles");
1921  addenv2(blk, "ProgramFiles(x86)");
1922  addenv2(blk, "CommonProgramFiles(x86)");
1923#else
1924  addenv2(blk, "LD_LIBRARY_PATH");
1925#endif // _WIN32
20671926
2068static void byteReverse(unsigned char *buf, unsigned longs) {
2069   uint32_t t;
1927  // Add all headers as HTTP_* variables
1928  for (i = 0; i < ri->num_headers; i++) {
1929    p = addenv(blk, "HTTP_%s=%s",
1930        ri->http_headers[i].name, ri->http_headers[i].value);
20701931
2071   // Forrest: MD5 expect LITTLE_ENDIAN, swap if BIG_ENDIAN
2072   if (is_big_endian()) {
2073   do {
2074      t = (uint32_t) ((unsigned) buf[3] << 8 | buf[2]) << 16 |
2075      ((unsigned) buf[1] << 8 | buf[0]);
2076      * (uint32_t *) buf = t;
2077      buf += 4;
2078   } while (--longs);
2079   }
2080}
1932    // Convert variable name into uppercase, and change - to _
1933    for (; *p != '=' && *p != '\0'; p++) {
1934      if (*p == '-')
1935        *p = '_';
1936      *p = (char) toupper(* (unsigned char *) p);
1937    }
1938  }
20811939
2082#define F1(x, y, z) (z ^ (x & (y ^ z)))
2083#define F2(x, y, z) F1(z, x, y)
2084#define F3(x, y, z) (x ^ y ^ z)
2085#define F4(x, y, z) (y ^ (x | ~z))
1940  blk->vars[blk->nvars++] = NULL;
1941  blk->buf[blk->len++] = '\0';
20861942
2087#define MD5STEP(f, w, x, y, z, data, s) \
2088   ( w += f(x, y, z) + data,  w = w<<s | w>>(32-s),  w += x )
2089
2090// Start MD5 accumulation.  Set bit count to 0 and buffer to mysterious
2091// initialization constants.
2092static void MD5Init(MD5_CTX *ctx) {
2093   ctx->buf[0] = 0x67452301;
2094   ctx->buf[1] = 0xefcdab89;
2095   ctx->buf[2] = 0x98badcfe;
2096   ctx->buf[3] = 0x10325476;
2097
2098   ctx->bits[0] = 0;
2099   ctx->bits[1] = 0;
1943  assert(blk->nvars < (int) ARRAY_SIZE(blk->vars));
1944  assert(blk->len > 0);
1945  assert(blk->len < (int) sizeof(blk->buf));
21001946}
21011947
2102static void MD5Transform(uint32_t buf[4], uint32_t const in[16]) {
2103   register uint32_t a, b, c, d;
1948static const char cgi_status[] = "HTTP/1.1 200 OK\r\n";
21041949
2105   a = buf[0];
2106   b = buf[1];
2107   c = buf[2];
2108   d = buf[3];
1950static void open_cgi_endpoint(struct connection *conn, const char *prog) {
1951  struct cgi_env_block blk;
1952  char dir[MAX_PATH_SIZE];
1953  const char *p;
1954  sock_t fds[2];
21091955
2110   MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7);
2111   MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12);
2112   MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17);
2113   MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22);
2114   MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7);
2115   MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12);
2116   MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17);
2117   MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22);
2118   MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7);
2119   MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12);
2120   MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17);
2121   MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22);
2122   MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7);
2123   MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12);
2124   MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17);
2125   MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22);
1956  prepare_cgi_environment(conn, prog, &blk);
1957  // CGI must be executed in its own directory. 'dir' must point to the
1958  // directory containing executable program, 'p' must point to the
1959  // executable program name relative to 'dir'.
1960  if ((p = strrchr(prog, '/')) == NULL) {
1961    mg_snprintf(dir, sizeof(dir), "%s", ".");
1962  } else {
1963    mg_snprintf(dir, sizeof(dir), "%.*s", (int) (p - prog), prog);
1964  }
21261965
2127   MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5);
2128   MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9);
2129   MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14);
2130   MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20);
2131   MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5);
2132   MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9);
2133   MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14);
2134   MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20);
2135   MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5);
2136   MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9);
2137   MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14);
2138   MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20);
2139   MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5);
2140   MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9);
2141   MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14);
2142   MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20);
1966  // Try to create socketpair in a loop until success. ns_socketpair()
1967  // can be interrupted by a signal and fail.
1968  // TODO(lsm): use sigaction to restart interrupted syscall
1969  do {
1970    ns_socketpair(fds);
1971  } while (fds[0] == INVALID_SOCKET);
21431972
2144   MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4);
2145   MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11);
2146   MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16);
2147   MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23);
2148   MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4);
2149   MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11);
2150   MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16);
2151   MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23);
2152   MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4);
2153   MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11);
2154   MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16);
2155   MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23);
2156   MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4);
2157   MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11);
2158   MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16);
2159   MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23);
1973  if (start_process(conn->server->config_options[CGI_INTERPRETER],
1974                    prog, blk.buf, blk.vars, dir, fds[1]) > 0) {
1975    conn->endpoint_type = EP_CGI;
1976    conn->endpoint.nc = ns_add_sock(&conn->server->ns_server,
1977                                          fds[0], conn);
1978    conn->endpoint.nc->flags |= MG_CGI_CONN;
1979    ns_send(conn->ns_conn, cgi_status, sizeof(cgi_status) - 1);
1980    conn->mg_conn.status_code = 200;
1981    conn->ns_conn->flags |= NSF_BUFFER_BUT_DONT_SEND;
1982    // Pass POST data to the CGI process
1983    conn->endpoint.nc->send_iobuf = conn->ns_conn->recv_iobuf;
1984    iobuf_init(&conn->ns_conn->recv_iobuf, 0);
1985  } else {
1986    closesocket(fds[0]);
1987    send_http_error(conn, 500, "start_process(%s) failed", prog);
1988  }
21601989
2161   MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6);
2162   MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10);
2163   MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15);
2164   MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21);
2165   MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6);
2166   MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10);
2167   MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15);
2168   MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21);
2169   MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6);
2170   MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10);
2171   MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15);
2172   MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21);
2173   MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6);
2174   MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10);
2175   MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15);
2176   MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21);
2177
2178   buf[0] += a;
2179   buf[1] += b;
2180   buf[2] += c;
2181   buf[3] += d;
1990#ifndef _WIN32
1991  closesocket(fds[1]);  // On Windows, CGI stdio thread closes that socket
1992#endif
21821993}
21831994
2184static void MD5Update(MD5_CTX *ctx, unsigned char const *buf, unsigned len) {
2185   uint32_t t;
1995static void on_cgi_data(struct ns_connection *nc) {
1996  struct connection *conn = (struct connection *) nc->connection_data;
1997  const char *status = "500";
1998  struct mg_connection c;
21861999
2187   t = ctx->bits[0];
2188   if ((ctx->bits[0] = t + ((uint32_t) len << 3)) < t)
2189   ctx->bits[1]++;
2190   ctx->bits[1] += len >> 29;
2000  if (!conn) return;
21912001
2192   t = (t >> 3) & 0x3f;
2002  // Copy CGI data from CGI socket to the client send buffer
2003  ns_forward(nc, conn->ns_conn);
21932004
2194   if (t) {
2195   unsigned char *p = (unsigned char *) ctx->in + t;
2005  // If reply has not been parsed yet, parse it
2006  if (conn->ns_conn->flags & NSF_BUFFER_BUT_DONT_SEND) {
2007    struct iobuf *io = &conn->ns_conn->send_iobuf;
2008    int s_len = sizeof(cgi_status) - 1;
2009    int len = get_request_len(io->buf + s_len, io->len - s_len);
2010    char buf[MAX_REQUEST_SIZE], *s = buf;
21962011
2197   t = 64 - t;
2198   if (len < t) {
2199      memcpy(p, buf, len);
2200      return;
2201   }
2202   memcpy(p, buf, t);
2203   byteReverse(ctx->in, 16);
2204   MD5Transform(ctx->buf, (uint32_t *) ctx->in);
2205   buf += t;
2206   len -= t;
2207   }
2012    if (len == 0) return;
22082013
2209   while (len >= 64) {
2210   memcpy(ctx->in, buf, 64);
2211   byteReverse(ctx->in, 16);
2212   MD5Transform(ctx->buf, (uint32_t *) ctx->in);
2213   buf += 64;
2214   len -= 64;
2215   }
2014    if (len < 0 || len > (int) sizeof(buf)) {
2015      len = io->len;
2016      iobuf_remove(io, io->len);
2017      send_http_error(conn, 500, "CGI program sent malformed headers: [%.*s]",
2018        len, io->buf);
2019    } else {
2020      memset(&c, 0, sizeof(c));
2021      memcpy(buf, io->buf + s_len, len);
2022      buf[len - 1] = '\0';
2023      parse_http_headers(&s, &c);
2024      if (mg_get_header(&c, "Location") != NULL) {
2025        status = "302";
2026      } else if ((status = (char *) mg_get_header(&c, "Status")) == NULL) {
2027        status = "200";
2028      }
2029      memcpy(io->buf + 9, status, 3);
2030      conn->mg_conn.status_code = atoi(status);
2031    }
2032    conn->ns_conn->flags &= ~NSF_BUFFER_BUT_DONT_SEND;
2033  }
2034}
2035#endif  // !MONGOOSE_NO_CGI
22162036
2217   memcpy(ctx->in, buf, len);
2037static char *mg_strdup(const char *str) {
2038  char *copy = (char *) malloc(strlen(str) + 1);
2039  if (copy != NULL) {
2040    strcpy(copy, str);
2041  }
2042  return copy;
22182043}
22192044
2220static void MD5Final(unsigned char digest[16], MD5_CTX *ctx) {
2221   unsigned count;
2222   unsigned char *p;
2223   uint32_t *a;
2045static int isbyte(int n) {
2046  return n >= 0 && n <= 255;
2047}
22242048
2225   count = (ctx->bits[0] >> 3) & 0x3F;
2049static int parse_net(const char *spec, uint32_t *net, uint32_t *mask) {
2050  int n, a, b, c, d, slash = 32, len = 0;
22262051
2227   p = ctx->in + count;
2228   *p++ = 0x80;
2229   count = 64 - 1 - count;
2230   if (count < 8) {
2231   memset(p, 0, count);
2232   byteReverse(ctx->in, 16);
2233   MD5Transform(ctx->buf, (uint32_t *) ctx->in);
2234   memset(ctx->in, 0, 56);
2235   } else {
2236   memset(p, 0, count - 8);
2237   }
2238   byteReverse(ctx->in, 14);
2052  if ((sscanf(spec, "%d.%d.%d.%d/%d%n", &a, &b, &c, &d, &slash, &n) == 5 ||
2053      sscanf(spec, "%d.%d.%d.%d%n", &a, &b, &c, &d, &n) == 4) &&
2054      isbyte(a) && isbyte(b) && isbyte(c) && isbyte(d) &&
2055      slash >= 0 && slash < 33) {
2056    len = n;
2057    *net = ((uint32_t)a << 24) | ((uint32_t)b << 16) | ((uint32_t)c << 8) | d;
2058    *mask = slash ? 0xffffffffU << (32 - slash) : 0;
2059  }
22392060
2240   a = (uint32_t *)ctx->in;
2241   a[14] = ctx->bits[0];
2242   a[15] = ctx->bits[1];
2243
2244   MD5Transform(ctx->buf, (uint32_t *) ctx->in);
2245   byteReverse((unsigned char *) ctx->buf, 4);
2246   memcpy(digest, ctx->buf, 16);
2247   memset((char *) ctx, 0, sizeof(*ctx));
2061  return len;
22482062}
2249#endif // !HAVE_MD5
22502063
2251// Stringify binary data. Output buffer must be twice as big as input,
2252// because each byte takes 2 bytes in string representation
2253static void bin2str(char *to, const unsigned char *p, size_t len) {
2254   static const char *hex = "0123456789abcdef";
2064// Verify given socket address against the ACL.
2065// Return -1 if ACL is malformed, 0 if address is disallowed, 1 if allowed.
2066static int check_acl(const char *acl, uint32_t remote_ip) {
2067  int allowed, flag;
2068  uint32_t net, mask;
2069  struct vec vec;
22552070
2256   for (; len--; p++) {
2257   *to++ = hex[p[0] >> 4];
2258   *to++ = hex[p[0] & 0x0f];
2259   }
2260   *to = '\0';
2261}
2071  // If any ACL is set, deny by default
2072  allowed = acl == NULL ? '+' : '-';
22622073
2263// Return stringified MD5 hash for list of strings. Buffer must be 33 bytes.
2264char *mg_md5(char buf[33], ...) {
2265   unsigned char hash[16];
2266   const char *p;
2267   va_list ap;
2268   MD5_CTX ctx;
2074  while ((acl = next_option(acl, &vec, NULL)) != NULL) {
2075    flag = vec.ptr[0];
2076    if ((flag != '+' && flag != '-') ||
2077        parse_net(&vec.ptr[1], &net, &mask) == 0) {
2078      return -1;
2079    }
22692080
2270   MD5Init(&ctx);
2081    if (net == (remote_ip & mask)) {
2082      allowed = flag;
2083    }
2084  }
22712085
2272   va_start(ap, buf);
2273   while ((p = va_arg(ap, const char *)) != NULL) {
2274   MD5Update(&ctx, (const unsigned char *) p, (unsigned) strlen(p));
2275   }
2276   va_end(ap);
2277
2278   MD5Final(hash, &ctx);
2279   bin2str(buf, hash, sizeof(hash));
2280   return buf;
2086  return allowed == '+';
22812087}
22822088
2283// Check the user's password, return 1 if OK
2284static int check_password(const char *method, const char *ha1, const char *uri,
2285                     const char *nonce, const char *nc, const char *cnonce,
2286                     const char *qop, const char *response) {
2287   char ha2[32 + 1], expected_response[32 + 1];
2089// Protect against directory disclosure attack by removing '..',
2090// excessive '/' and '\' characters
2091static void remove_double_dots_and_double_slashes(char *s) {
2092  char *p = s;
22882093
2289   // Some of the parameters may be NULL
2290   if (method == NULL || nonce == NULL || nc == NULL || cnonce == NULL ||
2291      qop == NULL || response == NULL) {
2292   return 0;
2293   }
2094  while (*s != '\0') {
2095    *p++ = *s++;
2096    if (s[-1] == '/' || s[-1] == '\\') {
2097      // Skip all following slashes, backslashes and double-dots
2098      while (s[0] != '\0') {
2099        if (s[0] == '/' || s[0] == '\\') { s++; }
2100        else if (s[0] == '.' && s[1] == '.') { s += 2; }
2101        else { break; }
2102      }
2103    }
2104  }
2105  *p = '\0';
2106}
22942107
2295   // NOTE(lsm): due to a bug in MSIE, we do not compare the URI
2296   // TODO(lsm): check for authentication timeout
2297   if (// strcmp(dig->uri, c->ouri) != 0 ||
2298      strlen(response) != 32
2299      // || now - strtoul(dig->nonce, NULL, 10) > 3600
2300      ) {
2301   return 0;
2302   }
2108int mg_url_decode(const char *src, int src_len, char *dst,
2109                  int dst_len, int is_form_url_encoded) {
2110  int i, j, a, b;
2111#define HEXTOI(x) (isdigit(x) ? x - '0' : x - 'W')
23032112
2304   mg_md5(ha2, method, ":", uri, NULL);
2305   mg_md5(expected_response, ha1, ":", nonce, ":", nc,
2306      ":", cnonce, ":", qop, ":", ha2, NULL);
2113  for (i = j = 0; i < src_len && j < dst_len - 1; i++, j++) {
2114    if (src[i] == '%' && i < src_len - 2 &&
2115        isxdigit(* (const unsigned char *) (src + i + 1)) &&
2116        isxdigit(* (const unsigned char *) (src + i + 2))) {
2117      a = tolower(* (const unsigned char *) (src + i + 1));
2118      b = tolower(* (const unsigned char *) (src + i + 2));
2119      dst[j] = (char) ((HEXTOI(a) << 4) | HEXTOI(b));
2120      i += 2;
2121    } else if (is_form_url_encoded && src[i] == '+') {
2122      dst[j] = ' ';
2123    } else {
2124      dst[j] = src[i];
2125    }
2126  }
23072127
2308   return mg_strcasecmp(response, expected_response) == 0;
2128  dst[j] = '\0'; // Null-terminate the destination
2129
2130  return i >= src_len ? j : -1;
23092131}
23102132
2311// Use the global passwords file, if specified by auth_gpass option,
2312// or search for .htpasswd in the requested directory.
2313static void open_auth_file(struct mg_connection *conn, const char *path,
2314                     struct file *filep) {
2315   char name[PATH_MAX];
2316   const char *p, *e, *gpass = conn->ctx->config[GLOBAL_PASSWORDS_FILE];
2317   struct file file = STRUCT_FILE_INITIALIZER;
2318
2319   if (gpass != NULL) {
2320   // Use global passwords file
2321   if (!mg_fopen(conn, gpass, "r", filep)) {
2322      cry(conn, "fopen(%s): %s", gpass, strerror(ERRNO));
2323   }
2324   // Important: using local struct file to test path for is_directory flag.
2325   // If filep is used, mg_stat() makes it appear as if auth file was opened.
2326   } else if (mg_stat(conn, path, &file) && file.is_directory) {
2327   mg_snprintf(conn, name, sizeof(name), "%s%c%s",
2328            path, '/', PASSWORDS_FILE_NAME);
2329   mg_fopen(conn, name, "r", filep);
2330   } else {
2331      // Try to find .htpasswd in requested directory.
2332   for (p = path, e = p + strlen(p) - 1; e > p; e--)
2333      if (e[0] == '/')
2334      break;
2335   mg_snprintf(conn, name, sizeof(name), "%.*s%c%s",
2336            (int) (e - p), p, '/', PASSWORDS_FILE_NAME);
2337   mg_fopen(conn, name, "r", filep);
2338   }
2133static int is_valid_http_method(const char *s) {
2134  return !strcmp(s, "GET") || !strcmp(s, "POST") || !strcmp(s, "HEAD") ||
2135    !strcmp(s, "CONNECT") || !strcmp(s, "PUT") || !strcmp(s, "DELETE") ||
2136    !strcmp(s, "OPTIONS") || !strcmp(s, "PROPFIND") || !strcmp(s, "MKCOL");
23392137}
23402138
2341// Parsed Authorization header
2342struct ah {
2343   char *user, *uri, *cnonce, *response, *qop, *nc, *nonce;
2344};
2139// Parse HTTP request, fill in mg_request structure.
2140// This function modifies the buffer by NUL-terminating
2141// HTTP request components, header names and header values.
2142// Note that len must point to the last \n of HTTP headers.
2143static int parse_http_message(char *buf, int len, struct mg_connection *ri) {
2144  int is_request, n;
23452145
2346// Return 1 on success. Always initializes the ah structure.
2347static int parse_auth_header(struct mg_connection *conn, char *buf,
2348                        size_t buf_size, struct ah *ah) {
2349   char *name, *value, *s;
2350   const char *auth_header;
2146  // Reset the connection. Make sure that we don't touch fields that are
2147  // set elsewhere: remote_ip, remote_port, server_param
2148  ri->request_method = ri->uri = ri->http_version = ri->query_string = NULL;
2149  ri->num_headers = ri->status_code = ri->is_websocket = ri->content_len = 0;
23512150
2352   (void) memset(ah, 0, sizeof(*ah));
2353   if ((auth_header = mg_get_header(conn, "Authorization")) == NULL ||
2354      mg_strncasecmp(auth_header, "Digest ", 7) != 0) {
2355   return 0;
2356   }
2151  buf[len - 1] = '\0';
23572152
2358   // Make modifiable copy of the auth header
2359   (void) mg_strlcpy(buf, auth_header + 7, buf_size);
2360   s = buf;
2153  // RFC says that all initial whitespaces should be ingored
2154  while (*buf != '\0' && isspace(* (unsigned char *) buf)) {
2155    buf++;
2156  }
2157  ri->request_method = skip(&buf, " ");
2158  ri->uri = skip(&buf, " ");
2159  ri->http_version = skip(&buf, "\r\n");
23612160
2362   // Parse authorization header
2363   for (;;) {
2364   // Gobble initial spaces
2365   while (isspace(* (unsigned char *) s)) {
2366      s++;
2367   }
2368   name = skip_quoted(&s, "=", " ", 0);
2369   // Value is either quote-delimited, or ends at first comma or space.
2370   if (s[0] == '\"') {
2371      s++;
2372      value = skip_quoted(&s, "\"", " ", '\\');
2373      if (s[0] == ',') {
2374      s++;
2375      }
2376   } else {
2377      value = skip_quoted(&s, ", ", " ", 0);  // IE uses commas, FF uses spaces
2378   }
2379   if (*name == '\0') {
2380      break;
2381   }
2161  // HTTP message could be either HTTP request or HTTP response, e.g.
2162  // "GET / HTTP/1.0 ...." or  "HTTP/1.0 200 OK ..."
2163  is_request = is_valid_http_method(ri->request_method);
2164  if ((is_request && memcmp(ri->http_version, "HTTP/", 5) != 0) ||
2165      (!is_request && memcmp(ri->request_method, "HTTP/", 5) != 0)) {
2166    len = -1;
2167  } else {
2168    if (is_request) {
2169      ri->http_version += 5;
2170    }
2171    parse_http_headers(&buf, ri);
23822172
2383   if (!strcmp(name, "username")) {
2384      ah->user = value;
2385   } else if (!strcmp(name, "cnonce")) {
2386      ah->cnonce = value;
2387   } else if (!strcmp(name, "response")) {
2388      ah->response = value;
2389   } else if (!strcmp(name, "uri")) {
2390      ah->uri = value;
2391   } else if (!strcmp(name, "qop")) {
2392      ah->qop = value;
2393   } else if (!strcmp(name, "nc")) {
2394      ah->nc = value;
2395   } else if (!strcmp(name, "nonce")) {
2396      ah->nonce = value;
2397   }
2398   }
2173    if ((ri->query_string = strchr(ri->uri, '?')) != NULL) {
2174      *(char *) ri->query_string++ = '\0';
2175    }
2176    n = (int) strlen(ri->uri);
2177    mg_url_decode(ri->uri, n, (char *) ri->uri, n + 1, 0);
2178    if (*ri->uri == '/' || *ri->uri == '.') {
2179      remove_double_dots_and_double_slashes((char *) ri->uri);     
2180    }
2181  }
23992182
2400   // CGI needs it as REMOTE_USER
2401   if (ah->user != NULL) {
2402   conn->request_info.remote_user = mg_strdup(ah->user);
2403   } else {
2404   return 0;
2405   }
2406
2407   return 1;
2183  return len;
24082184}
24092185
2410static char *mg_fgets(char *buf, size_t size, struct file *filep, char **p) {
2411   char *eof;
2412   size_t len;
2413
2414   if (filep->membuf != NULL && *p != NULL) {
2415   eof = (char*)memchr(*p, '\n', &filep->membuf[filep->size] - *p);
2416   len = (size_t) (eof - *p) > size - 1 ? size - 1 : (size_t) (eof - *p);
2417   memcpy(buf, *p, len);
2418   buf[len] = '\0';
2419   *p = eof;
2420   return eof;
2421   } else if (filep->fp != NULL) {
2422   return fgets(buf, size, filep->fp);
2423   } else {
2424   return NULL;
2425   }
2186static int lowercase(const char *s) {
2187  return tolower(* (const unsigned char *) s);
24262188}
24272189
2428// Authorize against the opened passwords file. Return 1 if authorized.
2429static int authorize(struct mg_connection *conn, struct file *filep) {
2430   struct ah ah;
2431   char line[256], f_user[256], ha1[256], f_domain[256], buf[MG_BUF_LEN], *p;
2190static int mg_strcasecmp(const char *s1, const char *s2) {
2191  int diff;
24322192
2433   if (!parse_auth_header(conn, buf, sizeof(buf), &ah)) {
2434   return 0;
2435   }
2193  do {
2194    diff = lowercase(s1++) - lowercase(s2++);
2195  } while (diff == 0 && s1[-1] != '\0');
24362196
2437   // Loop over passwords file
2438   p = (char *) filep->membuf;
2439   while (mg_fgets(line, sizeof(line), filep, &p) != NULL) {
2440   if (sscanf(line, "%[^:]:%[^:]:%s", f_user, f_domain, ha1) != 3) {
2441      continue;
2442   }
2197  return diff;
2198}
24432199
2444   if (!strcmp(ah.user, f_user) &&
2445      !strcmp(conn->ctx->config[AUTHENTICATION_DOMAIN], f_domain))
2446      return check_password(conn->request_info.request_method, ha1, ah.uri,
2447                     ah.nonce, ah.nc, ah.cnonce, ah.qop, ah.response);
2448   }
2200static int mg_strncasecmp(const char *s1, const char *s2, size_t len) {
2201  int diff = 0;
24492202
2450   return 0;
2203  if (len > 0)
2204    do {
2205      diff = lowercase(s1++) - lowercase(s2++);
2206    } while (diff == 0 && s1[-1] != '\0' && --len > 0);
2207
2208  return diff;
24512209}
24522210
2453// Return 1 if request is authorised, 0 otherwise.
2454static int check_authorization(struct mg_connection *conn, const char *path) {
2455   char fname[PATH_MAX];
2456   struct vec uri_vec, filename_vec;
2457   const char *list;
2458   struct file file = STRUCT_FILE_INITIALIZER;
2459   int authorized = 1;
2211// Return HTTP header value, or NULL if not found.
2212const char *mg_get_header(const struct mg_connection *ri, const char *s) {
2213  int i;
24602214
2461   list = conn->ctx->config[PROTECT_URI];
2462   while ((list = next_option(list, &uri_vec, &filename_vec)) != NULL) {
2463   if (!memcmp(conn->request_info.uri, uri_vec.ptr, uri_vec.len)) {
2464      mg_snprintf(conn, fname, sizeof(fname), "%.*s",
2465               (int) filename_vec.len, filename_vec.ptr);
2466      if (!mg_fopen(conn, fname, "r", &file)) {
2467      cry(conn, "%s: cannot open %s: %s", __func__, fname, strerror(errno));
2468      }
2469      break;
2470   }
2471   }
2215  for (i = 0; i < ri->num_headers; i++)
2216    if (!mg_strcasecmp(s, ri->http_headers[i].name))
2217      return ri->http_headers[i].value;
24722218
2473   if (!is_file_opened(&file)) {
2474   open_auth_file(conn, path, &file);
2475   }
2219  return NULL;
2220}
24762221
2477   if (is_file_opened(&file)) {
2478   authorized = authorize(conn, &file);
2479   mg_fclose(&file);
2480   }
2222// Perform case-insensitive match of string against pattern
2223int mg_match_prefix(const char *pattern, int pattern_len, const char *str) {
2224  const char *or_str;
2225  int len, res, i = 0, j = 0;
24812226
2482   return authorized;
2483}
2227  if ((or_str = (const char *) memchr(pattern, '|', pattern_len)) != NULL) {
2228    res = mg_match_prefix(pattern, or_str - pattern, str);
2229    return res > 0 ? res : mg_match_prefix(or_str + 1,
2230      (pattern + pattern_len) - (or_str + 1), str);
2231  }
24842232
2485static void send_authorization_request(struct mg_connection *conn) {
2486   conn->status_code = 401;
2487   mg_printf(conn,
2488         "HTTP/1.1 401 Unauthorized\r\n"
2489         "Content-Length: 0\r\n"
2490         "WWW-Authenticate: Digest qop=\"auth\", "
2491         "realm=\"%s\", nonce=\"%lu\"\r\n\r\n",
2492         conn->ctx->config[AUTHENTICATION_DOMAIN],
2493         (unsigned long) time(NULL));
2233  for (; i < pattern_len; i++, j++) {
2234    if (pattern[i] == '?' && str[j] != '\0') {
2235      continue;
2236    } else if (pattern[i] == '$') {
2237      return str[j] == '\0' ? j : -1;
2238    } else if (pattern[i] == '*') {
2239      i++;
2240      if (pattern[i] == '*') {
2241        i++;
2242        len = (int) strlen(str + j);
2243      } else {
2244        len = (int) strcspn(str + j, "/");
2245      }
2246      if (i == pattern_len) {
2247        return j + len;
2248      }
2249      do {
2250        res = mg_match_prefix(pattern + i, pattern_len - i, str + j + len);
2251      } while (res == -1 && len-- > 0);
2252      return res == -1 ? -1 : j + res + len;
2253    } else if (lowercase(&pattern[i]) != lowercase(&str[j])) {
2254      return -1;
2255    }
2256  }
2257  return j;
24942258}
24952259
2496static int is_authorized_for_put(struct mg_connection *conn) {
2497   struct file file = STRUCT_FILE_INITIALIZER;
2498   const char *passfile = conn->ctx->config[PUT_DELETE_PASSWORDS_FILE];
2499   int ret = 0;
2260// This function prints HTML pages, and expands "{{something}}" blocks
2261// inside HTML by calling appropriate callback functions.
2262// Note that {{@path/to/file}} construct outputs embedded file's contents,
2263// which provides SSI-like functionality.
2264void mg_template(struct mg_connection *conn, const char *s,
2265                 struct mg_expansion *expansions) {
2266  int i, j, pos = 0, inside_marker = 0;
25002267
2501   if (passfile != NULL && mg_fopen(conn, passfile, "r", &file)) {
2502   ret = authorize(conn, &file);
2503   mg_fclose(&file);
2504   }
2268  for (i = 0; s[i] != '\0'; i++) {
2269    if (inside_marker == 0 && !memcmp(&s[i], "{{", 2)) {
2270      if (i > pos) {
2271        mg_send_data(conn, &s[pos], i - pos);
2272      }
2273      pos = i;
2274      inside_marker = 1;
2275    }
2276    if (inside_marker == 1 && !memcmp(&s[i], "}}", 2)) {
2277      for (j = 0; expansions[j].keyword != NULL; j++) {
2278        const char *kw = expansions[j].keyword;
2279        if ((int) strlen(kw) == i - (pos + 2) &&
2280            memcmp(kw, &s[pos + 2], i - (pos + 2)) == 0) {
2281          expansions[j].handler(conn);
2282          pos = i + 2;
2283          break;
2284        }
2285      }
2286      inside_marker = 0;
2287    }
2288  }
2289  if (i > pos) {
2290    mg_send_data(conn, &s[pos], i - pos);
2291  }
2292}
25052293
2506   return ret;
2294#ifndef MONGOOSE_NO_FILESYSTEM
2295static int must_hide_file(struct connection *conn, const char *path) {
2296  const char *pw_pattern = "**" PASSWORDS_FILE_NAME "$";
2297  const char *pattern = conn->server->config_options[HIDE_FILES_PATTERN];
2298  return mg_match_prefix(pw_pattern, strlen(pw_pattern), path) > 0 ||
2299    (pattern != NULL && mg_match_prefix(pattern, strlen(pattern), path) > 0);
25072300}
25082301
2509int mg_modify_passwords_file(const char *fname, const char *domain,
2510                        const char *user, const char *pass) {
2511   int found;
2512   char line[512], u[512], d[512], ha1[33], tmp[PATH_MAX];
2513   FILE *fp, *fp2;
2302// Return 1 if real file has been found, 0 otherwise
2303static int convert_uri_to_file_name(struct connection *conn, char *buf,
2304                                    size_t buf_len, file_stat_t *st) {
2305  struct vec a, b;
2306  const char *rewrites = conn->server->config_options[URL_REWRITES];
2307  const char *root = conn->server->config_options[DOCUMENT_ROOT];
2308#ifndef MONGOOSE_NO_CGI
2309  const char *cgi_pat = conn->server->config_options[CGI_PATTERN];
2310  char *p;
2311#endif
2312  const char *uri = conn->mg_conn.uri;
2313  const char *domain = mg_get_header(&conn->mg_conn, "Host");
2314  int match_len, root_len = root == NULL ? 0 : strlen(root);
25142315
2515   found = 0;
2516   fp = fp2 = NULL;
2316  // Perform virtual hosting rewrites
2317  if (rewrites != NULL && domain != NULL) {
2318    const char *colon = strchr(domain, ':');
2319    int domain_len = colon == NULL ? (int) strlen(domain) : colon - domain;
25172320
2518   // Regard empty password as no password - remove user record.
2519   if (pass != NULL && pass[0] == '\0') {
2520   pass = NULL;
2521   }
2321    while ((rewrites = next_option(rewrites, &a, &b)) != NULL) {
2322      if (a.len > 1 && a.ptr[0] == '@' && a.len == domain_len + 1 &&
2323          mg_strncasecmp(a.ptr + 1, domain, domain_len) == 0) {
2324        root = b.ptr;
2325        root_len = b.len;
2326        break;
2327      }
2328    }
2329  }
25222330
2523   (void) snprintf(tmp, sizeof(tmp), "%s.tmp", fname);
2331  // No filesystem access
2332  if (root == NULL || root_len == 0) return 0;
25242333
2525   // Create the file if does not exist
2526   if ((fp = fopen(fname, "a+")) != NULL) {
2527   (void) fclose(fp);
2528   }
2334  // Handle URL rewrites
2335  mg_snprintf(buf, buf_len, "%.*s%s", root_len, root, uri);
2336  rewrites = conn->server->config_options[URL_REWRITES];  // Re-initialize!
2337  while ((rewrites = next_option(rewrites, &a, &b)) != NULL) {
2338    if ((match_len = mg_match_prefix(a.ptr, a.len, uri)) > 0) {
2339      mg_snprintf(buf, buf_len, "%.*s%s", (int) b.len, b.ptr, uri + match_len);
2340      break;
2341    }
2342  }
25292343
2530   // Open the given file and temporary file
2531   if ((fp = fopen(fname, "r")) == NULL) {
2532   return 0;
2533   } else if ((fp2 = fopen(tmp, "w+")) == NULL) {
2534   fclose(fp);
2535   return 0;
2536   }
2344  if (stat(buf, st) == 0) return 1;
25372345
2538   // Copy the stuff to temporary file
2539   while (fgets(line, sizeof(line), fp) != NULL) {
2540   if (sscanf(line, "%[^:]:%[^:]:%*s", u, d) != 2) {
2541      continue;
2542   }
2346#ifndef MONGOOSE_NO_CGI
2347  // Support PATH_INFO for CGI scripts.
2348  for (p = buf + strlen(root) + 2; *p != '\0'; p++) {
2349    if (*p == '/') {
2350      *p = '\0';
2351      if (mg_match_prefix(cgi_pat, strlen(cgi_pat), buf) > 0 &&
2352          !stat(buf, st)) {
2353      DBG(("!!!! [%s]", buf));
2354        *p = '/';
2355        conn->path_info = mg_strdup(p);
2356        *p = '\0';
2357        return 1;
2358      }
2359      *p = '/';
2360    }
2361  }
2362#endif
25432363
2544   if (!strcmp(u, user) && !strcmp(d, domain)) {
2545      found++;
2546      if (pass != NULL) {
2547      mg_md5(ha1, user, ":", domain, ":", pass, NULL);
2548      fprintf(fp2, "%s:%s:%s\n", user, domain, ha1);
2549      }
2550   } else {
2551      fprintf(fp2, "%s", line);
2552   }
2553   }
2364  return 0;
2365}
2366#endif  // MONGOOSE_NO_FILESYSTEM
25542367
2555   // If new user, just add it
2556   if (!found && pass != NULL) {
2557   mg_md5(ha1, user, ":", domain, ":", pass, NULL);
2558   fprintf(fp2, "%s:%s:%s\n", user, domain, ha1);
2559   }
2368static int should_keep_alive(const struct mg_connection *conn) {
2369  struct connection *c = MG_CONN_2_CONN(conn);
2370  const char *method = conn->request_method;
2371  const char *http_version = conn->http_version;
2372  const char *header = mg_get_header(conn, "Connection");
2373  return method != NULL &&
2374    (!strcmp(method, "GET") || c->endpoint_type == EP_USER) &&
2375    ((header != NULL && !mg_strcasecmp(header, "keep-alive")) ||
2376     (header == NULL && http_version && !strcmp(http_version, "1.1")));
2377}
25602378
2561   // Close files
2562   fclose(fp);
2563   fclose(fp2);
2379int mg_write(struct mg_connection *c, const void *buf, int len) {
2380  struct connection *conn = MG_CONN_2_CONN(c);
2381  return ns_send(conn->ns_conn, buf, len);
2382}
25642383
2565   // Put the temp file in place of real file
2566   remove(fname);
2567   rename(tmp, fname);
2384void mg_send_status(struct mg_connection *c, int status) {
2385  if (c->status_code == 0) {
2386    c->status_code = status;
2387    mg_printf(c, "HTTP/1.1 %d %s\r\n", status, status_code_to_str(status));
2388  }
2389}
25682390
2569   return 1;
2391void mg_send_header(struct mg_connection *c, const char *name, const char *v) {
2392  if (c->status_code == 0) {
2393    c->status_code = 200;
2394    mg_printf(c, "HTTP/1.1 %d %s\r\n", 200, status_code_to_str(200));
2395  }
2396  mg_printf(c, "%s: %s\r\n", name, v);
25702397}
25712398
2572static int conn2(const char *host, int port, int use_ssl,
2573               char *ebuf, size_t ebuf_len) {
2574   struct sockaddr_in sin;
2575   struct hostent *he;
2576   SOCKET sock = INVALID_SOCKET;
2399static void terminate_headers(struct mg_connection *c) {
2400  struct connection *conn = MG_CONN_2_CONN(c);
2401  if (!(conn->ns_conn->flags & MG_HEADERS_SENT)) {
2402    mg_send_header(c, "Transfer-Encoding", "chunked");
2403    mg_write(c, "\r\n", 2);
2404    conn->ns_conn->flags |= MG_HEADERS_SENT;
2405  }
2406}
25772407
2578   if (host == NULL) {
2579   snprintf(ebuf, ebuf_len, "%s", "NULL host");
2580   } else if (use_ssl && SSLv23_client_method == NULL) {
2581   snprintf(ebuf, ebuf_len, "%s", "SSL is not initialized");
2582   // TODO(lsm): use something threadsafe instead of gethostbyname()
2583   } else if ((he = gethostbyname(host)) == NULL) {
2584   snprintf(ebuf, ebuf_len, "gethostbyname(%s): %s", host, strerror(ERRNO));
2585   } else if ((sock = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
2586   snprintf(ebuf, ebuf_len, "socket(): %s", strerror(ERRNO));
2587   } else {
2588   sin.sin_family = AF_INET;
2589   sin.sin_port = htons((uint16_t) port);
2590   sin.sin_addr = * (struct in_addr *) he->h_addr_list[0];
2591   if (connect(sock, (struct sockaddr *) &sin, sizeof(sin)) != 0) {
2592      snprintf(ebuf, ebuf_len, "connect(%s:%d): %s",
2593            host, port, strerror(ERRNO));
2594      closesocket(sock);
2595      sock = INVALID_SOCKET;
2596   }
2597   }
2598   return sock;
2408void mg_send_data(struct mg_connection *c, const void *data, int data_len) {
2409  terminate_headers(c);
2410  write_chunk(MG_CONN_2_CONN(c), (const char *) data, data_len);
25992411}
26002412
2413void mg_printf_data(struct mg_connection *c, const char *fmt, ...) {
2414  struct connection *conn = MG_CONN_2_CONN(c);
2415  va_list ap;
2416  int len;
2417  char mem[IOBUF_SIZE], *buf = mem;
26012418
2419  terminate_headers(c);
26022420
2603void mg_url_encode(const char *src, char *dst, size_t dst_len) {
2604   static const char *dont_escape = "._-$,;~()";
2605   static const char *hex = "0123456789abcdef";
2606   const char *end = dst + dst_len - 1;
2421  va_start(ap, fmt);
2422  len = ns_avprintf(&buf, sizeof(mem), fmt, ap);
2423  va_end(ap);
26072424
2608   for (; *src != '\0' && dst < end; src++, dst++) {
2609   if (isalnum(*(const unsigned char *) src) ||
2610      strchr(dont_escape, * (const unsigned char *) src) != NULL) {
2611      *dst = *src;
2612   } else if (dst + 2 < end) {
2613      dst[0] = '%';
2614      dst[1] = hex[(* (const unsigned char *) src) >> 4];
2615      dst[2] = hex[(* (const unsigned char *) src) & 0xf];
2616      dst += 2;
2617   }
2618   }
2619
2620   *dst = '\0';
2425  if (len >= 0) {
2426    write_chunk((struct connection *) conn, buf, len);
2427  }
2428  if (buf != mem && buf != NULL) {
2429    free(buf);
2430  }
26212431}
26222432
2623static void print_dir_entry(struct de *de) {
2624   char size[64], mod[64], href[PATH_MAX];
2625
2626   if (de->file.is_directory) {
2627   mg_snprintf(de->conn, size, sizeof(size), "%s", "[DIRECTORY]");
2628   } else {
2629      // We use (signed) cast below because MSVC 6 compiler cannot
2630      // convert unsigned __int64 to double. Sigh.
2631   if (de->file.size < 1024) {
2632      mg_snprintf(de->conn, size, sizeof(size), "%d", (int) de->file.size);
2633   } else if (de->file.size < 0x100000) {
2634      mg_snprintf(de->conn, size, sizeof(size),
2635               "%.1fk", (double) de->file.size / 1024.0);
2636   } else if (de->file.size < 0x40000000) {
2637      mg_snprintf(de->conn, size, sizeof(size),
2638               "%.1fM", (double) de->file.size / 1048576);
2639   } else {
2640      mg_snprintf(de->conn, size, sizeof(size),
2641               "%.1fG", (double) de->file.size / 1073741824);
2642   }
2643   }
2644   strftime(mod, sizeof(mod), "%d-%b-%Y %H:%M",
2645         localtime(&de->file.modification_time));
2646   mg_url_encode(de->file_name, href, sizeof(href));
2647   de->conn->num_bytes_sent += mg_printf(de->conn,
2648      "<tr><td><a href=\"%s%s%s\">%s%s</a></td>"
2649      "<td>&nbsp;%s</td><td>&nbsp;&nbsp;%s</td></tr>\n",
2650      de->conn->request_info.uri, href, de->file.is_directory ? "/" : "",
2651      de->file_name, de->file.is_directory ? "/" : "", mod, size);
2433#if !defined(MONGOOSE_NO_WEBSOCKET) || !defined(MONGOOSE_NO_AUTH)
2434static int is_big_endian(void) {
2435  static const int n = 1;
2436  return ((char *) &n)[0] == 0;
26522437}
2438#endif
26532439
2654// This function is called from send_directory() and used for
2655// sorting directory entries by size, or name, or modification time.
2656// On windows, __cdecl specification is needed in case if project is built
2657// with __stdcall convention. qsort always requires __cdels callback.
2658static int WINCDECL compare_dir_entries(const void *p1, const void *p2) {
2659   const struct de *a = (const struct de *) p1, *b = (const struct de *) p2;
2660   const char *query_string = a->conn->request_info.query_string;
2661   int cmp_result = 0;
2440#ifndef MONGOOSE_NO_WEBSOCKET
2441// START OF SHA-1 code
2442// Copyright(c) By Steve Reid <steve@edmweb.com>
2443#define SHA1HANDSOFF
2444#if defined(__sun)
2445#include "solarisfixes.h"
2446#endif
26622447
2663   if (query_string == NULL) {
2664   query_string = "na";
2665   }
2448union char64long16 { unsigned char c[64]; uint32_t l[16]; };
26662449
2667   if (a->file.is_directory && !b->file.is_directory) {
2668   return -1;  // Always put directories on top
2669   } else if (!a->file.is_directory && b->file.is_directory) {
2670   return 1;   // Always put directories on top
2671   } else if (*query_string == 'n') {
2672   cmp_result = strcmp(a->file_name, b->file_name);
2673   } else if (*query_string == 's') {
2674   cmp_result = a->file.size == b->file.size ? 0 :
2675      a->file.size > b->file.size ? 1 : -1;
2676   } else if (*query_string == 'd') {
2677   cmp_result = a->file.modification_time == b->file.modification_time ? 0 :
2678      a->file.modification_time > b->file.modification_time ? 1 : -1;
2679   }
2450#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits))))
26802451
2681   return query_string[1] == 'd' ? -cmp_result : cmp_result;
2452static uint32_t blk0(union char64long16 *block, int i) {
2453  // Forrest: SHA expect BIG_ENDIAN, swap if LITTLE_ENDIAN
2454  if (!is_big_endian()) {
2455    block->l[i] = (rol(block->l[i], 24) & 0xFF00FF00) |
2456      (rol(block->l[i], 8) & 0x00FF00FF);
2457  }
2458  return block->l[i];
26822459}
26832460
2684static int must_hide_file(struct mg_connection *conn, const char *path) {
2685   const char *pw_pattern = "**" PASSWORDS_FILE_NAME "$";
2686   const char *pattern = conn->ctx->config[HIDE_FILES];
2687   return match_prefix(pw_pattern, strlen(pw_pattern), path) > 0 ||
2688   (pattern != NULL && match_prefix(pattern, strlen(pattern), path) > 0);
2689}
2461#define blk(i) (block->l[i&15] = rol(block->l[(i+13)&15]^block->l[(i+8)&15] \
2462    ^block->l[(i+2)&15]^block->l[i&15],1))
2463#define R0(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk0(block, i)+0x5A827999+rol(v,5);w=rol(w,30);
2464#define R1(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5);w=rol(w,30);
2465#define R2(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=rol(w,30);
2466#define R3(v,w,x,y,z,i) z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=rol(w,30);
2467#define R4(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=rol(w,30);
26902468
2691static int scan_directory(struct mg_connection *conn, const char *dir,
2692                     void *data, void (*cb)(struct de *, void *)) {
2693   char path[PATH_MAX];
2694   struct dirent *dp;
2695   DIR *dirp;
2696   struct de de;
2469typedef struct {
2470    uint32_t state[5];
2471    uint32_t count[2];
2472    unsigned char buffer[64];
2473} SHA1_CTX;
26972474
2698   if ((dirp = opendir(dir)) == NULL) {
2699   return 0;
2700   } else {
2701   de.conn = conn;
2475static void SHA1Transform(uint32_t state[5], const unsigned char buffer[64]) {
2476  uint32_t a, b, c, d, e;
2477  union char64long16 block[1];
27022478
2703   while ((dp = readdir(dirp)) != NULL) {
2704      // Do not show current dir and hidden files
2705      if (!strcmp(dp->d_name, ".") ||
2706         !strcmp(dp->d_name, "..") ||
2707         must_hide_file(conn, dp->d_name)) {
2708      continue;
2709      }
2479  memcpy(block, buffer, 64);
2480  a = state[0];
2481  b = state[1];
2482  c = state[2];
2483  d = state[3];
2484  e = state[4];
2485  R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3);
2486  R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7);
2487  R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11);
2488  R0(d,e,a,b,c,12); R0(c,d,e,a,b,13); R0(b,c,d,e,a,14); R0(a,b,c,d,e,15);
2489  R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19);
2490  R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23);
2491  R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27);
2492  R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31);
2493  R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35);
2494  R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39);
2495  R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43);
2496  R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47);
2497  R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51);
2498  R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55);
2499  R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59);
2500  R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63);
2501  R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67);
2502  R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71);
2503  R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75);
2504  R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79);
2505  state[0] += a;
2506  state[1] += b;
2507  state[2] += c;
2508  state[3] += d;
2509  state[4] += e;
2510  // Erase working structures. The order of operations is important,
2511  // used to ensure that compiler doesn't optimize those out.
2512  memset(block, 0, sizeof(block));
2513  a = b = c = d = e = 0;
2514  (void) a; (void) b; (void) c; (void) d; (void) e;
2515}
27102516
2711      mg_snprintf(conn, path, sizeof(path), "%s%c%s", dir, '/', dp->d_name);
2517static void SHA1Init(SHA1_CTX* context) {
2518  context->state[0] = 0x67452301;
2519  context->state[1] = 0xEFCDAB89;
2520  context->state[2] = 0x98BADCFE;
2521  context->state[3] = 0x10325476;
2522  context->state[4] = 0xC3D2E1F0;
2523  context->count[0] = context->count[1] = 0;
2524}
27122525
2713      // If we don't memset stat structure to zero, mtime will have
2714      // garbage and strftime() will segfault later on in
2715      // print_dir_entry(). memset is required only if mg_stat()
2716      // fails. For more details, see
2717      // http://code.google.com/p/mongoose/issues/detail?id=79
2718      memset(&de.file, 0, sizeof(de.file));
2719      mg_stat(conn, path, &de.file);
2526static void SHA1Update(SHA1_CTX* context, const unsigned char* data,
2527                       uint32_t len) {
2528  uint32_t i, j;
27202529
2721      de.file_name = dp->d_name;
2722      cb(&de, data);
2723   }
2724   (void) closedir(dirp);
2725   }
2726   return 1;
2530  j = context->count[0];
2531  if ((context->count[0] += len << 3) < j)
2532    context->count[1]++;
2533  context->count[1] += (len>>29);
2534  j = (j >> 3) & 63;
2535  if ((j + len) > 63) {
2536    memcpy(&context->buffer[j], data, (i = 64-j));
2537    SHA1Transform(context->state, context->buffer);
2538    for ( ; i + 63 < len; i += 64) {
2539      SHA1Transform(context->state, &data[i]);
2540    }
2541    j = 0;
2542  }
2543  else i = 0;
2544  memcpy(&context->buffer[j], &data[i], len - i);
27272545}
27282546
2729static int remove_directory(struct mg_connection *conn, const char *dir) {
2730   char path[PATH_MAX];
2731   struct dirent *dp;
2732   DIR *dirp;
2733   struct de de;
2547static void SHA1Final(unsigned char digest[20], SHA1_CTX* context) {
2548  unsigned i;
2549  unsigned char finalcount[8], c;
27342550
2735   if ((dirp = opendir(dir)) == NULL) {
2736   return 0;
2737   } else {
2738   de.conn = conn;
2551  for (i = 0; i < 8; i++) {
2552    finalcount[i] = (unsigned char)((context->count[(i >= 4 ? 0 : 1)]
2553                                     >> ((3-(i & 3)) * 8) ) & 255);
2554  }
2555  c = 0200;
2556  SHA1Update(context, &c, 1);
2557  while ((context->count[0] & 504) != 448) {
2558    c = 0000;
2559    SHA1Update(context, &c, 1);
2560  }
2561  SHA1Update(context, finalcount, 8);
2562  for (i = 0; i < 20; i++) {
2563    digest[i] = (unsigned char)
2564      ((context->state[i>>2] >> ((3-(i & 3)) * 8) ) & 255);
2565  }
2566  memset(context, '\0', sizeof(*context));
2567  memset(&finalcount, '\0', sizeof(finalcount));
2568}
2569// END OF SHA1 CODE
27392570
2740   while ((dp = readdir(dirp)) != NULL) {
2741      // Do not show current dir (but show hidden files as they will also be removed)
2742      if (!strcmp(dp->d_name, ".") ||
2743         !strcmp(dp->d_name, "..")) {
2744      continue;
2745      }
2571static void base64_encode(const unsigned char *src, int src_len, char *dst) {
2572  static const char *b64 =
2573    "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
2574  int i, j, a, b, c;
27462575
2747      mg_snprintf(conn, path, sizeof(path), "%s%c%s", dir, '/', dp->d_name);
2576  for (i = j = 0; i < src_len; i += 3) {
2577    a = src[i];
2578    b = i + 1 >= src_len ? 0 : src[i + 1];
2579    c = i + 2 >= src_len ? 0 : src[i + 2];
27482580
2749      // If we don't memset stat structure to zero, mtime will have
2750      // garbage and strftime() will segfault later on in
2751      // print_dir_entry(). memset is required only if mg_stat()
2752      // fails. For more details, see
2753      // http://code.google.com/p/mongoose/issues/detail?id=79
2754      memset(&de.file, 0, sizeof(de.file));
2755      mg_stat(conn, path, &de.file);
2756      if(de.file.modification_time) {
2757         if(de.file.is_directory) {
2758            remove_directory(conn, path);
2759         } else {
2760            mg_remove(path);
2761         }
2762      }
2581    dst[j++] = b64[a >> 2];
2582    dst[j++] = b64[((a & 3) << 4) | (b >> 4)];
2583    if (i + 1 < src_len) {
2584      dst[j++] = b64[(b & 15) << 2 | (c >> 6)];
2585    }
2586    if (i + 2 < src_len) {
2587      dst[j++] = b64[c & 63];
2588    }
2589  }
2590  while (j % 4 != 0) {
2591    dst[j++] = '=';
2592  }
2593  dst[j++] = '\0';
2594}
27632595
2764   }
2765   (void) closedir(dirp);
2596static void send_websocket_handshake(struct mg_connection *conn,
2597                                     const char *key) {
2598  static const char *magic = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
2599  char buf[500], sha[20], b64_sha[sizeof(sha) * 2];
2600  SHA1_CTX sha_ctx;
27662601
2767   rmdir(dir);
2768   }
2602  mg_snprintf(buf, sizeof(buf), "%s%s", key, magic);
2603  SHA1Init(&sha_ctx);
2604  SHA1Update(&sha_ctx, (unsigned char *) buf, strlen(buf));
2605  SHA1Final((unsigned char *) sha, &sha_ctx);
2606  base64_encode((unsigned char *) sha, sizeof(sha), b64_sha);
2607  mg_snprintf(buf, sizeof(buf), "%s%s%s",
2608              "HTTP/1.1 101 Switching Protocols\r\n"
2609              "Upgrade: websocket\r\n"
2610              "Connection: Upgrade\r\n"
2611              "Sec-WebSocket-Accept: ", b64_sha, "\r\n\r\n");
27692612
2770   return 1;
2613  mg_write(conn, buf, strlen(buf));
27712614}
27722615
2773struct dir_scan_data {
2774   struct de *entries;
2775   int num_entries;
2776   int arr_size;
2777};
2616static int deliver_websocket_frame(struct connection *conn) {
2617  // Having buf unsigned char * is important, as it is used below in arithmetic
2618  unsigned char *buf = (unsigned char *) conn->ns_conn->recv_iobuf.buf;
2619  int i, len, buf_len = conn->ns_conn->recv_iobuf.len, frame_len = 0,
2620      mask_len = 0, header_len = 0, data_len = 0, buffered = 0;
27782621
2779// Behaves like realloc(), but frees original pointer on failure
2780static void *realloc2(void *ptr, size_t size) {
2781   void *new_ptr = realloc(ptr, size);
2782   if (new_ptr == NULL) {
2783   free(ptr);
2784   }
2785   return new_ptr;
2786}
2622  if (buf_len >= 2) {
2623    len = buf[1] & 127;
2624    mask_len = buf[1] & 128 ? 4 : 0;
2625    if (len < 126 && buf_len >= mask_len) {
2626      data_len = len;
2627      header_len = 2 + mask_len;
2628    } else if (len == 126 && buf_len >= 4 + mask_len) {
2629      header_len = 4 + mask_len;
2630      data_len = ((((int) buf[2]) << 8) + buf[3]);
2631    } else if (buf_len >= 10 + mask_len) {
2632      header_len = 10 + mask_len;
2633      data_len = (int) (((uint64_t) htonl(* (uint32_t *) &buf[2])) << 32) +
2634        htonl(* (uint32_t *) &buf[6]);
2635    }
2636  }
27872637
2788static void dir_scan_callback(struct de *de, void *data) {
2789   struct dir_scan_data *dsd = (struct dir_scan_data *) data;
2638  frame_len = header_len + data_len;
2639  buffered = frame_len > 0 && frame_len <= buf_len;
27902640
2791   if (dsd->entries == NULL || dsd->num_entries >= dsd->arr_size) {
2792   dsd->arr_size *= 2;
2793   dsd->entries = (struct de *) realloc2(dsd->entries, dsd->arr_size *
2794                                 sizeof(dsd->entries[0]));
2795   }
2796   if (dsd->entries == NULL) {
2797   // TODO(lsm): propagate an error to the caller
2798   dsd->num_entries = 0;
2799   } else {
2800   dsd->entries[dsd->num_entries].file_name = mg_strdup(de->file_name);
2801   dsd->entries[dsd->num_entries].file = de->file;
2802   dsd->entries[dsd->num_entries].conn = de->conn;
2803   dsd->num_entries++;
2804   }
2805}
2641  if (buffered) {
2642    conn->mg_conn.content_len = data_len;
2643    conn->mg_conn.content = (char *) buf + header_len;
2644    conn->mg_conn.wsbits = buf[0];
28062645
2807static void handle_directory_request(struct mg_connection *conn,
2808                              const char *dir) {
2809   int i, sort_direction;
2810   struct dir_scan_data data = { NULL, 0, 128 };
2646    // Apply mask if necessary
2647    if (mask_len > 0) {
2648      for (i = 0; i < data_len; i++) {
2649        buf[i + header_len] ^= (buf + header_len - mask_len)[i % 4];
2650      }
2651    }
28112652
2812   if (!scan_directory(conn, dir, &data, dir_scan_callback)) {
2813   send_http_error(conn, 500, "Cannot open directory",
2814               "Error: opendir(%s): %s", dir, strerror(ERRNO));
2815   return;
2816   }
2653    // Call the handler and remove frame from the iobuf
2654    if (call_user(conn, MG_REQUEST) == MG_FALSE) {
2655      conn->ns_conn->flags |= NSF_FINISHED_SENDING_DATA;
2656    }
2657    iobuf_remove(&conn->ns_conn->recv_iobuf, frame_len);
2658  }
28172659
2818   sort_direction = conn->request_info.query_string != NULL &&
2819   conn->request_info.query_string[1] == 'd' ? 'a' : 'd';
2660  return buffered;
2661}
28202662
2821   conn->must_close = 1;
2822   mg_printf(conn, "%s",
2823         "HTTP/1.1 200 OK\r\n"
2824         "Connection: close\r\n"
2825         "Content-Type: text/html; charset=utf-8\r\n\r\n");
2663int mg_websocket_write(struct mg_connection* conn, int opcode,
2664                       const char *data, size_t data_len) {
2665    unsigned char mem[4192], *copy = mem;
2666    size_t copy_len = 0;
2667    int retval = -1;
28262668
2827   conn->num_bytes_sent += mg_printf(conn,
2828      "<html><head><title>Index of %s</title>"
2829      "<style>th {text-align: left;}</style></head>"
2830      "<body><h1>Index of %s</h1><pre><table cellpadding=\"0\">"
2831      "<tr><th><a href=\"?n%c\">Name</a></th>"
2832      "<th><a href=\"?d%c\">Modified</a></th>"
2833      "<th><a href=\"?s%c\">Size</a></th></tr>"
2834      "<tr><td colspan=\"3\"><hr></td></tr>",
2835      conn->request_info.uri, conn->request_info.uri,
2836      sort_direction, sort_direction, sort_direction);
2669    if (data_len + 10 > sizeof(mem) &&
2670        (copy = (unsigned char *) malloc(data_len + 10)) == NULL) {
2671      return -1;
2672    }
28372673
2838   // Print first entry - link to a parent directory
2839   conn->num_bytes_sent += mg_printf(conn,
2840      "<tr><td><a href=\"%s%s\">%s</a></td>"
2841      "<td>&nbsp;%s</td><td>&nbsp;&nbsp;%s</td></tr>\n",
2842      conn->request_info.uri, "..", "Parent directory", "-", "-");
2674    copy[0] = 0x80 + (opcode & 0x0f);
28432675
2844   // Sort and print directory entries
2845   qsort(data.entries, (size_t) data.num_entries, sizeof(data.entries[0]),
2846      compare_dir_entries);
2847   for (i = 0; i < data.num_entries; i++) {
2848   print_dir_entry(&data.entries[i]);
2849   free(data.entries[i].file_name);
2850   }
2851   free(data.entries);
2676    // Frame format: http://tools.ietf.org/html/rfc6455#section-5.2
2677    if (data_len < 126) {
2678      // Inline 7-bit length field
2679      copy[1] = data_len;
2680      memcpy(copy + 2, data, data_len);
2681      copy_len = 2 + data_len;
2682    } else if (data_len <= 0xFFFF) {
2683      // 16-bit length field
2684      copy[1] = 126;
2685      * (uint16_t *) (copy + 2) = (uint16_t) htons((uint16_t) data_len);
2686      memcpy(copy + 4, data, data_len);
2687      copy_len = 4 + data_len;
2688    } else {
2689      // 64-bit length field
2690      copy[1] = 127;
2691      * (uint32_t *) (copy + 2) = (uint32_t)
2692        htonl((uint32_t) ((uint64_t) data_len >> 32));
2693      * (uint32_t *) (copy + 6) = (uint32_t) htonl(data_len & 0xffffffff);
2694      memcpy(copy + 10, data, data_len);
2695      copy_len = 10 + data_len;
2696    }
28522697
2853   conn->num_bytes_sent += mg_printf(conn, "%s", "</table></body></html>");
2854   conn->status_code = 200;
2698    if (copy_len > 0) {
2699      retval = mg_write(conn, copy, copy_len);
2700    }
2701    if (copy != mem) {
2702      free(copy);
2703    }
2704
2705    return retval;
28552706}
28562707
2857// Send len bytes from the opened file to the client.
2858static void send_file_data(struct mg_connection *conn, struct file *filep,
2859                     int64_t offset, int64_t len) {
2860   char buf[MG_BUF_LEN];
2861   int to_read, num_read, num_written;
2708int mg_websocket_printf(struct mg_connection* conn, int opcode,
2709                        const char *fmt, ...) {
2710  char mem[4192], *buf = mem;
2711  va_list ap;
2712  int len;
28622713
2863   // Sanity check the offset
2864   offset = offset < 0 ? 0 : offset > filep->size ? filep->size : offset;
2714  va_start(ap, fmt);
2715  if ((len = ns_avprintf(&buf, sizeof(mem), fmt, ap)) > 0) {
2716    mg_websocket_write(conn, opcode, buf, len);
2717  }
2718  va_end(ap);
28652719
2866   if (len > 0 && filep->membuf != NULL && filep->size > 0) {
2867   if (len > filep->size - offset) {
2868      len = filep->size - offset;
2869   }
2870   mg_write(conn, filep->membuf + offset, (size_t) len);
2871   } else if (len > 0 && filep->fp != NULL) {
2872   fseeko(filep->fp, offset, SEEK_SET);
2873   while (len > 0) {
2874      // Calculate how much to read from the file in the buffer
2875      to_read = sizeof(buf);
2876      if ((int64_t) to_read > len) {
2877      to_read = (int) len;
2878      }
2720  if (buf != mem && buf != NULL) {
2721    free(buf);
2722  }
28792723
2880      // Read from file, exit the loop on error
2881      if ((num_read = fread(buf, 1, (size_t) to_read, filep->fp)) <= 0) {
2882      break;
2883      }
2884
2885      // Send read bytes to the client, exit the loop on error
2886      if ((num_written = mg_write(conn, buf, (size_t) num_read)) != num_read) {
2887      break;
2888      }
2889
2890      // Both read and were successful, adjust counters
2891      conn->num_bytes_sent += num_written;
2892      len -= num_written;
2893   }
2894   }
2724  return len;
28952725}
28962726
2897static int parse_range_header(const char *header, int64_t *a, int64_t *b) {
2898   return sscanf(header, "bytes=%" INT64_FMT "-%" INT64_FMT, a, b);
2727static void send_websocket_handshake_if_requested(struct mg_connection *conn) {
2728  const char *ver = mg_get_header(conn, "Sec-WebSocket-Version"),
2729        *key = mg_get_header(conn, "Sec-WebSocket-Key");
2730  if (ver != NULL && key != NULL) {
2731    conn->is_websocket = 1;
2732    if (call_user(MG_CONN_2_CONN(conn), MG_WS_HANDSHAKE) == MG_FALSE) {
2733      send_websocket_handshake(conn, key);
2734    }
2735  }
28992736}
29002737
2901static void gmt_time_string(char *buf, size_t buf_len, time_t *t) {
2902   strftime(buf, buf_len, "%a, %d %b %Y %H:%M:%S GMT", gmtime(t));
2738static void ping_idle_websocket_connection(struct connection *conn, time_t t) {
2739  if (t - conn->ns_conn->last_io_time > MONGOOSE_USE_WEBSOCKET_PING_INTERVAL) {
2740    mg_websocket_write(&conn->mg_conn, WEBSOCKET_OPCODE_PING, "", 0);
2741  }
29032742}
2743#else
2744#define ping_idle_websocket_connection(conn, t)
2745#endif // !MONGOOSE_NO_WEBSOCKET
29042746
2905static void construct_etag(char *buf, size_t buf_len,
2906                     const struct file *filep) {
2907   snprintf(buf, buf_len, "\"%lx.%" INT64_FMT "\"",
2908         (unsigned long) filep->modification_time, filep->size);
2747static void write_terminating_chunk(struct connection *conn) {
2748  mg_write(&conn->mg_conn, "0\r\n\r\n", 5);
29092749}
29102750
2911static void fclose_on_exec(struct file *filep) {
2912   if (filep != NULL && filep->fp != NULL) {
2913#ifndef _WIN32
2914   fcntl(fileno(filep->fp), F_SETFD, FD_CLOEXEC);
2915#endif
2916   }
2751static int call_request_handler(struct connection *conn) {
2752  int result;
2753  conn->mg_conn.content = conn->ns_conn->recv_iobuf.buf;
2754  if ((result = call_user(conn, MG_REQUEST)) == MG_TRUE) {
2755    if (conn->ns_conn->flags & MG_HEADERS_SENT) {
2756      write_terminating_chunk(conn);
2757    }
2758    close_local_endpoint(conn);
2759  }
2760  return result;
29172761}
29182762
2919static void handle_file_request(struct mg_connection *conn, const char *path,
2920                        struct file *filep) {
2921   char date[64], lm[64], etag[64], range[64];
2922   const char *msg = "OK", *hdr;
2923   time_t curtime = time(NULL);
2924   int64_t cl, r1, r2;
2925   struct vec mime_vec;
2926   int n;
2927   char gz_path[PATH_MAX];
2928   char const* encoding = "";
2763const char *mg_get_mime_type(const char *path, const char *default_mime_type) {
2764  const char *ext;
2765  size_t i, path_len;
29292766
2930   get_mime_type(conn->ctx, path, &mime_vec);
2931   cl = filep->size;
2932   conn->status_code = 200;
2933   range[0] = '\0';
2767  path_len = strlen(path);
29342768
2935   // if this file is in fact a pre-gzipped file, rewrite its filename
2936   // it's important to rewrite the filename after resolving
2937   // the mime type from it, to preserve the actual file's type
2938   if (filep->gzipped) {
2939   snprintf(gz_path, sizeof(gz_path), "%s.gz", path);
2940   path = gz_path;
2941   encoding = "Content-Encoding: gzip\r\n";
2942   }
2769  for (i = 0; static_builtin_mime_types[i].extension != NULL; i++) {
2770    ext = path + (path_len - static_builtin_mime_types[i].ext_len);
2771    if (path_len > static_builtin_mime_types[i].ext_len &&
2772        mg_strcasecmp(ext, static_builtin_mime_types[i].extension) == 0) {
2773      return static_builtin_mime_types[i].mime_type;
2774    }
2775  }
29432776
2944   if (!mg_fopen(conn, path, "rb", filep)) {
2945   send_http_error(conn, 500, http_500_error,
2946               "fopen(%s): %s", path, strerror(ERRNO));
2947   return;
2948   }
2777  return default_mime_type;
2778}
29492779
2950   fclose_on_exec(filep);
2780#ifndef MONGOOSE_NO_FILESYSTEM
2781// Convert month to the month number. Return -1 on error, or month number
2782static int get_month_index(const char *s) {
2783  static const char *month_names[] = {
2784    "Jan", "Feb", "Mar", "Apr", "May", "Jun",
2785    "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
2786  };
2787  int i;
29512788
2952   // If Range: header specified, act accordingly
2953   r1 = r2 = 0;
2954   hdr = mg_get_header(conn, "Range");
2955   if (hdr != NULL && (n = parse_range_header(hdr, &r1, &r2)) > 0 &&
2956      r1 >= 0 && r2 >= 0) {
2957   // actually, range requests don't play well with a pre-gzipped
2958   // file (since the range is specified in the uncmpressed space)
2959   if (filep->gzipped) {
2960      send_http_error(conn, 501, "Not Implemented", "range requests in gzipped files are not supported");
2961      return;
2962   }
2963   conn->status_code = 206;
2964   cl = n == 2 ? (r2 > cl ? cl : r2) - r1 + 1: cl - r1;
2965   mg_snprintf(conn, range, sizeof(range),
2966            "Content-Range: bytes "
2967            "%" INT64_FMT "-%"
2968            INT64_FMT "/%" INT64_FMT "\r\n",
2969            r1, r1 + cl - 1, filep->size);
2970   msg = "Partial Content";
2971   }
2789  for (i = 0; i < (int) ARRAY_SIZE(month_names); i++)
2790    if (!strcmp(s, month_names[i]))
2791      return i;
29722792
2973   // Prepare Etag, Date, Last-Modified headers. Must be in UTC, according to
2974   // http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.3
2975   gmt_time_string(date, sizeof(date), &curtime);
2976   gmt_time_string(lm, sizeof(lm), &filep->modification_time);
2977   construct_etag(etag, sizeof(etag), filep);
2978
2979   (void) mg_printf(conn,
2980      "HTTP/1.1 %d %s\r\n"
2981      "Date: %s\r\n"
2982      "Last-Modified: %s\r\n"
2983      "Etag: %s\r\n"
2984      "Content-Type: %.*s\r\n"
2985      "Content-Length: %" INT64_FMT "\r\n"
2986      "Connection: %s\r\n"
2987      "Accept-Ranges: bytes\r\n"
2988      "%s%s\r\n",
2989      conn->status_code, msg, date, lm, etag, (int) mime_vec.len,
2990      mime_vec.ptr, cl, suggest_connection_header(conn), range, encoding);
2991
2992   if (strcmp(conn->request_info.request_method, "HEAD") != 0) {
2993   send_file_data(conn, filep, r1, cl);
2994   }
2995   mg_fclose(filep);
2793  return -1;
29962794}
29972795
2998void mg_send_file(struct mg_connection *conn, const char *path) {
2999   struct file file = STRUCT_FILE_INITIALIZER;
3000   if (mg_stat(conn, path, &file)) {
3001   handle_file_request(conn, path, &file);
3002   } else {
3003   send_http_error(conn, 404, "Not Found", "%s", "File not found");
3004   }
2796static int num_leap_years(int year) {
2797  return year / 4 - year / 100 + year / 400;
30052798}
30062799
2800// Parse UTC date-time string, and return the corresponding time_t value.
2801static time_t parse_date_string(const char *datetime) {
2802  static const unsigned short days_before_month[] = {
2803    0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334
2804  };
2805  char month_str[32];
2806  int second, minute, hour, day, month, year, leap_days, days;
2807  time_t result = (time_t) 0;
30072808
3008// Parse HTTP headers from the given buffer, advance buffer to the point
3009// where parsing stopped.
3010static void parse_http_headers(char **buf, struct mg_request_info *ri) {
3011   int i;
2809  if (((sscanf(datetime, "%d/%3s/%d %d:%d:%d",
2810               &day, month_str, &year, &hour, &minute, &second) == 6) ||
2811       (sscanf(datetime, "%d %3s %d %d:%d:%d",
2812               &day, month_str, &year, &hour, &minute, &second) == 6) ||
2813       (sscanf(datetime, "%*3s, %d %3s %d %d:%d:%d",
2814               &day, month_str, &year, &hour, &minute, &second) == 6) ||
2815       (sscanf(datetime, "%d-%3s-%d %d:%d:%d",
2816               &day, month_str, &year, &hour, &minute, &second) == 6)) &&
2817      year > 1970 &&
2818      (month = get_month_index(month_str)) != -1) {
2819    leap_days = num_leap_years(year) - num_leap_years(1970);
2820    year -= 1970;
2821    days = year * 365 + days_before_month[month] + (day - 1) + leap_days;
2822    result = days * 24 * 3600 + hour * 3600 + minute * 60 + second;
2823  }
30122824
3013   for (i = 0; i < (int) ARRAY_SIZE(ri->http_headers); i++) {
3014   ri->http_headers[i].name = skip_quoted(buf, ":", " ", 0);
3015   ri->http_headers[i].value = skip(buf, "\r\n");
3016   if (ri->http_headers[i].name[0] == '\0')
3017      break;
3018   ri->num_headers = i + 1;
3019   }
2825  return result;
30202826}
30212827
3022static int is_valid_http_method(const char *method) {
3023   return !strcmp(method, "GET") || !strcmp(method, "POST") ||
3024   !strcmp(method, "HEAD") || !strcmp(method, "CONNECT") ||
3025   !strcmp(method, "PUT") || !strcmp(method, "DELETE") ||
3026   !strcmp(method, "OPTIONS") || !strcmp(method, "PROPFIND")
3027   || !strcmp(method, "MKCOL")
3028         ;
3029}
2828// Look at the "path" extension and figure what mime type it has.
2829// Store mime type in the vector.
2830static void get_mime_type(const struct mg_server *server, const char *path,
2831                          struct vec *vec) {
2832  struct vec ext_vec, mime_vec;
2833  const char *list, *ext;
2834  size_t path_len;
30302835
3031// Parse HTTP request, fill in mg_request_info structure.
3032// This function modifies the buffer by NUL-terminating
3033// HTTP request components, header names and header values.
3034static int parse_http_message(char *buf, int len, struct mg_request_info *ri) {
3035   int is_request, request_length = get_request_len(buf, len);
3036   if (request_length > 0) {
3037   // Reset attributes. DO NOT TOUCH is_ssl, remote_ip, remote_port
3038   ri->remote_user = ri->request_method = ri->uri = ri->http_version = NULL;
3039   ri->num_headers = 0;
2836  path_len = strlen(path);
30402837
3041   buf[request_length - 1] = '\0';
2838  // Scan user-defined mime types first, in case user wants to
2839  // override default mime types.
2840  list = server->config_options[EXTRA_MIME_TYPES];
2841  while ((list = next_option(list, &ext_vec, &mime_vec)) != NULL) {
2842    // ext now points to the path suffix
2843    ext = path + path_len - ext_vec.len;
2844    if (mg_strncasecmp(ext, ext_vec.ptr, ext_vec.len) == 0) {
2845      *vec = mime_vec;
2846      return;
2847    }
2848  }
30422849
3043   // RFC says that all initial whitespaces should be ingored
3044   while (*buf != '\0' && isspace(* (unsigned char *) buf)) {
3045      buf++;
3046   }
3047   ri->request_method = skip(&buf, " ");
3048   ri->uri = skip(&buf, " ");
3049   ri->http_version = skip(&buf, "\r\n");
3050   if (((is_request = is_valid_http_method(ri->request_method)) &&
3051         memcmp(ri->http_version, "HTTP/", 5) != 0) ||
3052      (!is_request && memcmp(ri->request_method, "HTTP/", 5)) != 0) {
3053      request_length = -1;
3054   } else {
3055      if (is_request) {
3056      ri->http_version += 5;
3057      }
3058      parse_http_headers(&buf, ri);
3059   }
3060   }
3061   return request_length;
2850  vec->ptr = mg_get_mime_type(path, "text/plain");
2851  vec->len = strlen(vec->ptr);
30622852}
30632853
3064// Keep reading the input (either opened file descriptor fd, or socket sock,
3065// or SSL descriptor ssl) into buffer buf, until \r\n\r\n appears in the
3066// buffer (which marks the end of HTTP request). Buffer buf may already
3067// have some data. The length of the data is stored in nread.
3068// Upon every read operation, increase nread by the number of bytes read.
3069static int read_request(FILE *fp, struct mg_connection *conn,
3070                  char *buf, int bufsiz, int *nread) {
3071   int request_len, n = 0;
2854static const char *suggest_connection_header(const struct mg_connection *conn) {
2855  return should_keep_alive(conn) ? "keep-alive" : "close";
2856}
30722857
3073   request_len = get_request_len(buf, *nread);
3074   while (*nread < bufsiz && request_len == 0 &&
3075         (n = pull(fp, conn, buf + *nread, bufsiz - *nread)) > 0) {
3076   *nread += n;
3077   assert(*nread <= bufsiz);
3078   request_len = get_request_len(buf, *nread);
3079   }
2858static void construct_etag(char *buf, size_t buf_len, const file_stat_t *st) {
2859  mg_snprintf(buf, buf_len, "\"%lx.%" INT64_FMT "\"",
2860              (unsigned long) st->st_mtime, (int64_t) st->st_size);
2861}
30802862
3081   return request_len <= 0 && n <= 0 ? -1 : request_len;
2863// Return True if we should reply 304 Not Modified.
2864static int is_not_modified(const struct connection *conn,
2865                           const file_stat_t *stp) {
2866  char etag[64];
2867  const char *ims = mg_get_header(&conn->mg_conn, "If-Modified-Since");
2868  const char *inm = mg_get_header(&conn->mg_conn, "If-None-Match");
2869  construct_etag(etag, sizeof(etag), stp);
2870  return (inm != NULL && !mg_strcasecmp(etag, inm)) ||
2871    (ims != NULL && stp->st_mtime <= parse_date_string(ims));
30822872}
30832873
30842874// For given directory path, substitute it to valid index file.
30852875// Return 0 if index file has been found, -1 if not found.
30862876// If the file is found, it's stats is returned in stp.
3087static int substitute_index_file(struct mg_connection *conn, char *path,
3088                           size_t path_len, struct file *filep) {
3089   const char *list = conn->ctx->config[INDEX_FILES];
3090   struct file file = STRUCT_FILE_INITIALIZER;
3091   struct vec filename_vec;
3092   size_t n = strlen(path);
3093   int found = 0;
2877static int find_index_file(struct connection *conn, char *path,
2878                           size_t path_len, file_stat_t *stp) {
2879  const char *list = conn->server->config_options[INDEX_FILES];
2880  file_stat_t st;
2881  struct vec filename_vec;
2882  size_t n = strlen(path), found = 0;
30942883
3095   // The 'path' given to us points to the directory. Remove all trailing
3096   // directory separator characters from the end of the path, and
3097   // then append single directory separator character.
3098   while (n > 0 && path[n - 1] == '/') {
3099   n--;
3100   }
3101   path[n] = '/';
2884  // The 'path' given to us points to the directory. Remove all trailing
2885  // directory separator characters from the end of the path, and
2886  // then append single directory separator character.
2887  while (n > 0 && path[n - 1] == '/') {
2888    n--;
2889  }
2890  path[n] = '/';
31022891
3103   // Traverse index files list. For each entry, append it to the given
3104   // path and see if the file exists. If it exists, break the loop
3105   while ((list = next_option(list, &filename_vec, NULL)) != NULL) {
3106   // Ignore too long entries that may overflow path buffer
3107   if (filename_vec.len > path_len - (n + 2))
3108      continue;
2892  // Traverse index files list. For each entry, append it to the given
2893  // path and see if the file exists. If it exists, break the loop
2894  while ((list = next_option(list, &filename_vec, NULL)) != NULL) {
31092895
3110   // Prepare full path to the index file
3111   mg_strlcpy(path + n + 1, filename_vec.ptr, filename_vec.len + 1);
2896    // Ignore too long entries that may overflow path buffer
2897    if (filename_vec.len > (int) (path_len - (n + 2)))
2898      continue;
31122899
3113   // Does it exist?
3114   if (mg_stat(conn, path, &file)) {
3115      // Yes it does, break the loop
3116      *filep = file;
3117      found = 1;
3118      break;
3119   }
3120   }
2900    // Prepare full path to the index file
2901    strncpy(path + n + 1, filename_vec.ptr, filename_vec.len);
2902    path[n + 1 + filename_vec.len] = '\0';
31212903
3122   // If no index file exists, restore directory path
3123   if (!found) {
3124   path[n] = '\0';
3125   }
2904    //DBG(("[%s]", path));
31262905
3127   return found;
2906    // Does it exist?
2907    if (!stat(path, &st)) {
2908      // Yes it does, break the loop
2909      *stp = st;
2910      found = 1;
2911      break;
2912    }
2913  }
2914
2915  // If no index file exists, restore directory path
2916  if (!found) {
2917    path[n] = '\0';
2918  }
2919
2920  return found;
31282921}
31292922
3130// Return True if we should reply 304 Not Modified.
3131static int is_not_modified(const struct mg_connection *conn,
3132                     const struct file *filep) {
3133   char etag[64];
3134   const char *ims = mg_get_header(conn, "If-Modified-Since");
3135   const char *inm = mg_get_header(conn, "If-None-Match");
3136   construct_etag(etag, sizeof(etag), filep);
3137   return (inm != NULL && !mg_strcasecmp(etag, inm)) ||
3138   (ims != NULL && filep->modification_time <= parse_date_string(ims));
2923static int parse_range_header(const char *header, int64_t *a, int64_t *b) {
2924  return sscanf(header, "bytes=%" INT64_FMT "-%" INT64_FMT, a, b);
31392925}
31402926
3141static int forward_body_data(struct mg_connection *conn, FILE *fp,
3142                        SOCKET sock, SSL *ssl) {
3143   const char *expect, *body;
3144   char buf[MG_BUF_LEN];
3145   int to_read, nread, buffered_len, success = 0;
2927static void gmt_time_string(char *buf, size_t buf_len, time_t *t) {
2928  strftime(buf, buf_len, "%a, %d %b %Y %H:%M:%S GMT", gmtime(t));
2929}
31462930
3147   expect = mg_get_header(conn, "Expect");
3148   assert(fp != NULL);
2931static void open_file_endpoint(struct connection *conn, const char *path,
2932                               file_stat_t *st) {
2933  char date[64], lm[64], etag[64], range[64], headers[500];
2934  const char *msg = "OK", *hdr;
2935  time_t curtime = time(NULL);
2936  int64_t r1, r2;
2937  struct vec mime_vec;
2938  int n;
31492939
3150   if (conn->content_len == -1) {
3151   send_http_error(conn, 411, "Length Required", "%s", "");
3152   } else if (expect != NULL && mg_strcasecmp(expect, "100-continue")) {
3153   send_http_error(conn, 417, "Expectation Failed", "%s", "");
3154   } else {
3155   if (expect != NULL) {
3156      (void) mg_printf(conn, "%s", "HTTP/1.1 100 Continue\r\n\r\n");
3157   }
2940  conn->endpoint_type = EP_FILE;
2941  ns_set_close_on_exec(conn->endpoint.fd);
2942  conn->mg_conn.status_code = 200;
31582943
3159   body = conn->buf + conn->request_len + conn->consumed_content;
3160   buffered_len = &conn->buf[conn->data_len] - body;
3161   assert(buffered_len >= 0);
3162   assert(conn->consumed_content == 0);
2944  get_mime_type(conn->server, path, &mime_vec);
2945  conn->cl = st->st_size;
2946  range[0] = '\0';
31632947
3164   if (buffered_len > 0) {
3165      if ((int64_t) buffered_len > conn->content_len) {
3166      buffered_len = (int) conn->content_len;
3167      }
3168      push(fp, sock, ssl, body, (int64_t) buffered_len);
3169      conn->consumed_content += buffered_len;
3170   }
2948  // If Range: header specified, act accordingly
2949  r1 = r2 = 0;
2950  hdr = mg_get_header(&conn->mg_conn, "Range");
2951  if (hdr != NULL && (n = parse_range_header(hdr, &r1, &r2)) > 0 &&
2952      r1 >= 0 && r2 >= 0) {
2953    conn->mg_conn.status_code = 206;
2954    conn->cl = n == 2 ? (r2 > conn->cl ? conn->cl : r2) - r1 + 1: conn->cl - r1;
2955    mg_snprintf(range, sizeof(range), "Content-Range: bytes "
2956                "%" INT64_FMT "-%" INT64_FMT "/%" INT64_FMT "\r\n",
2957                r1, r1 + conn->cl - 1, (int64_t) st->st_size);
2958    msg = "Partial Content";
2959    lseek(conn->endpoint.fd, r1, SEEK_SET);
2960  }
31712961
3172   nread = 0;
3173   while (conn->consumed_content < conn->content_len) {
3174      to_read = sizeof(buf);
3175      if ((int64_t) to_read > conn->content_len - conn->consumed_content) {
3176      to_read = (int) (conn->content_len - conn->consumed_content);
3177      }
3178      nread = pull(NULL, conn, buf, to_read);
3179      if (nread <= 0 || push(fp, sock, ssl, buf, nread) != nread) {
3180      break;
3181      }
3182      conn->consumed_content += nread;
3183   }
2962  // Prepare Etag, Date, Last-Modified headers. Must be in UTC, according to
2963  // http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.3
2964  gmt_time_string(date, sizeof(date), &curtime);
2965  gmt_time_string(lm, sizeof(lm), &st->st_mtime);
2966  construct_etag(etag, sizeof(etag), st);
31842967
3185   if (conn->consumed_content == conn->content_len) {
3186      success = nread >= 0;
3187   }
2968  n = mg_snprintf(headers, sizeof(headers),
2969                  "HTTP/1.1 %d %s\r\n"
2970                  "Date: %s\r\n"
2971                  "Last-Modified: %s\r\n"
2972                  "Etag: %s\r\n"
2973                  "Content-Type: %.*s\r\n"
2974                  "Content-Length: %" INT64_FMT "\r\n"
2975                  "Connection: %s\r\n"
2976                  "Accept-Ranges: bytes\r\n"
2977                  "%s%s\r\n",
2978                  conn->mg_conn.status_code, msg, date, lm, etag,
2979                  (int) mime_vec.len, mime_vec.ptr, conn->cl,
2980                  suggest_connection_header(&conn->mg_conn),
2981                  range, MONGOOSE_USE_EXTRA_HTTP_HEADERS);
2982  ns_send(conn->ns_conn, headers, n);
31882983
3189   // Each error code path in this function must send an error
3190   if (!success) {
3191      send_http_error(conn, 577, http_500_error, "%s", "");
3192   }
3193   }
2984  if (!strcmp(conn->mg_conn.request_method, "HEAD")) {
2985    conn->ns_conn->flags |= NSF_FINISHED_SENDING_DATA;
2986    close(conn->endpoint.fd);
2987    conn->endpoint_type = EP_NONE;
2988  }
2989}
2990#endif  // MONGOOSE_NO_FILESYSTEM
31942991
3195   return success;
2992static void call_request_handler_if_data_is_buffered(struct connection *conn) {
2993  struct iobuf *loc = &conn->ns_conn->recv_iobuf;
2994  struct mg_connection *c = &conn->mg_conn;
2995
2996#ifndef MONGOOSE_NO_WEBSOCKET
2997  if (conn->mg_conn.is_websocket) {
2998    do { } while (deliver_websocket_frame(conn));
2999  } else
3000#endif
3001  if ((size_t) loc->len >= c->content_len &&
3002      call_request_handler(conn) == MG_FALSE) {
3003    open_local_endpoint(conn, 1);
3004  }
31963005}
31973006
3198#if !defined(NO_CGI)
3199// This structure helps to create an environment for the spawned CGI program.
3200// Environment is an array of "VARIABLE=VALUE\0" ASCIIZ strings,
3201// last element must be NULL.
3202// However, on Windows there is a requirement that all these VARIABLE=VALUE\0
3203// strings must reside in a contiguous buffer. The end of the buffer is
3204// marked by two '\0' characters.
3205// We satisfy both worlds: we create an envp array (which is vars), all
3206// entries are actually pointers inside buf.
3207struct cgi_env_block {
3208   struct mg_connection *conn;
3209   char buf[CGI_ENVIRONMENT_SIZE]; // Environment buffer
3210   int len; // Space taken
3211   char *vars[MAX_CGI_ENVIR_VARS]; // char **envp
3212   int nvars; // Number of variables
3007#if !defined(MONGOOSE_NO_DIRECTORY_LISTING) || !defined(MONGOOSE_NO_DAV)
3008
3009#ifdef _WIN32
3010struct dirent {
3011  char d_name[MAX_PATH_SIZE];
32133012};
32143013
3215static char *addenv(struct cgi_env_block *block,
3216               PRINTF_FORMAT_STRING(const char *fmt), ...)
3217   PRINTF_ARGS(2, 3);
3014typedef struct DIR {
3015  HANDLE   handle;
3016  WIN32_FIND_DATAW info;
3017  struct dirent result;
3018} DIR;
32183019
3219// Append VARIABLE=VALUE\0 string to the buffer, and add a respective
3220// pointer into the vars array.
3221static char *addenv(struct cgi_env_block *block, const char *fmt, ...) {
3222   int n, space;
3223   char *added;
3224   va_list ap;
3020// Implementation of POSIX opendir/closedir/readdir for Windows.
3021static DIR *opendir(const char *name) {
3022  DIR *dir = NULL;
3023  wchar_t wpath[MAX_PATH_SIZE];
3024  DWORD attrs;
32253025
3226   // Calculate how much space is left in the buffer
3227   space = sizeof(block->buf) - block->len - 2;
3228   assert(space >= 0);
3026  if (name == NULL) {
3027    SetLastError(ERROR_BAD_ARGUMENTS);
3028  } else if ((dir = (DIR *) malloc(sizeof(*dir))) == NULL) {
3029    SetLastError(ERROR_NOT_ENOUGH_MEMORY);
3030  } else {
3031    to_wchar(name, wpath, ARRAY_SIZE(wpath));
3032    attrs = GetFileAttributesW(wpath);
3033    if (attrs != 0xFFFFFFFF &&
3034        ((attrs & FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY)) {
3035      (void) wcscat(wpath, L"\\*");
3036      dir->handle = FindFirstFileW(wpath, &dir->info);
3037      dir->result.d_name[0] = '\0';
3038    } else {
3039      free(dir);
3040      dir = NULL;
3041    }
3042  }
32293043
3230   // Make a pointer to the free space int the buffer
3231   added = block->buf + block->len;
3044  return dir;
3045}
32323046
3233   // Copy VARIABLE=VALUE\0 string into the free space
3234   va_start(ap, fmt);
3235   n = mg_vsnprintf(block->conn, added, (size_t) space, fmt, ap);
3236   va_end(ap);
3047static int closedir(DIR *dir) {
3048  int result = 0;
32373049
3238   // Make sure we do not overflow buffer and the envp array
3239   if (n > 0 && n + 1 < space &&
3240      block->nvars < (int) ARRAY_SIZE(block->vars) - 2) {
3241   // Append a pointer to the added string into the envp array
3242   block->vars[block->nvars++] = added;
3243   // Bump up used length counter. Include \0 terminator
3244   block->len += n + 1;
3245   } else {
3246   cry(block->conn, "%s: CGI env buffer truncated for [%s]", __func__, fmt);
3247   }
3050  if (dir != NULL) {
3051    if (dir->handle != INVALID_HANDLE_VALUE)
3052      result = FindClose(dir->handle) ? 0 : -1;
32483053
3249   return added;
3054    free(dir);
3055  } else {
3056    result = -1;
3057    SetLastError(ERROR_BAD_ARGUMENTS);
3058  }
3059
3060  return result;
32503061}
32513062
3252static void prepare_cgi_environment(struct mg_connection *conn,
3253                           const char *prog,
3254                           struct cgi_env_block *blk) {
3255   const char *s, *slash;
3256   struct vec var_vec;
3257   char *p, src_addr[IP_ADDR_STR_LEN];
3258   int  i;
3063static struct dirent *readdir(DIR *dir) {
3064  struct dirent *result = 0;
32593065
3260   blk->len = blk->nvars = 0;
3261   blk->conn = conn;
3262   sockaddr_to_string(src_addr, sizeof(src_addr), &conn->client.rsa);
3066  if (dir) {
3067    if (dir->handle != INVALID_HANDLE_VALUE) {
3068      result = &dir->result;
3069      (void) WideCharToMultiByte(CP_UTF8, 0,
3070          dir->info.cFileName, -1, result->d_name,
3071          sizeof(result->d_name), NULL, NULL);
32633072
3264   addenv(blk, "SERVER_NAME=%s", conn->ctx->config[AUTHENTICATION_DOMAIN]);
3265   addenv(blk, "SERVER_ROOT=%s", conn->ctx->config[DOCUMENT_ROOT]);
3266   addenv(blk, "DOCUMENT_ROOT=%s", conn->ctx->config[DOCUMENT_ROOT]);
3073      if (!FindNextFileW(dir->handle, &dir->info)) {
3074        (void) FindClose(dir->handle);
3075        dir->handle = INVALID_HANDLE_VALUE;
3076      }
32673077
3268   // Prepare the environment block
3269   addenv(blk, "%s", "GATEWAY_INTERFACE=CGI/1.1");
3270   addenv(blk, "%s", "SERVER_PROTOCOL=HTTP/1.1");
3271   addenv(blk, "%s", "REDIRECT_STATUS=200"); // For PHP
3078    } else {
3079      SetLastError(ERROR_FILE_NOT_FOUND);
3080    }
3081  } else {
3082    SetLastError(ERROR_BAD_ARGUMENTS);
3083  }
32723084
3273   // TODO(lsm): fix this for IPv6 case
3274   addenv(blk, "SERVER_PORT=%d", ntohs(conn->client.lsa.sin.sin_port));
3085  return result;
3086}
3087#endif // _WIN32  POSIX opendir/closedir/readdir implementation
32753088
3276   addenv(blk, "REQUEST_METHOD=%s", conn->request_info.request_method);
3277   addenv(blk, "REMOTE_ADDR=%s", src_addr);
3278   addenv(blk, "REMOTE_PORT=%d", conn->request_info.remote_port);
3279   addenv(blk, "REQUEST_URI=%s", conn->request_info.uri);
3089static int scan_directory(struct connection *conn, const char *dir,
3090                          struct dir_entry **arr) {
3091  char path[MAX_PATH_SIZE];
3092  struct dir_entry *p;
3093  struct dirent *dp;
3094  int arr_size = 0, arr_ind = 0, inc = 100;
3095  DIR *dirp;
32803096
3281   // SCRIPT_NAME
3282   assert(conn->request_info.uri[0] == '/');
3283   slash = strrchr(conn->request_info.uri, '/');
3284   if ((s = strrchr(prog, '/')) == NULL)
3285   s = prog;
3286   addenv(blk, "SCRIPT_NAME=%.*s%s", (int) (slash - conn->request_info.uri),
3287         conn->request_info.uri, s);
3097  *arr = NULL;
3098  if ((dirp = (opendir(dir))) == NULL) return 0;
32883099
3289   addenv(blk, "SCRIPT_FILENAME=%s", prog);
3290   addenv(blk, "PATH_TRANSLATED=%s", prog);
3291   addenv(blk, "HTTPS=%s", conn->ssl == NULL ? "off" : "on");
3100  while ((dp = readdir(dirp)) != NULL) {
3101    // Do not show current dir and hidden files
3102    if (!strcmp(dp->d_name, ".") ||
3103        !strcmp(dp->d_name, "..") ||
3104        must_hide_file(conn, dp->d_name)) {
3105      continue;
3106    }
3107    mg_snprintf(path, sizeof(path), "%s%c%s", dir, '/', dp->d_name);
32923108
3293   if ((s = mg_get_header(conn, "Content-Type")) != NULL)
3294   addenv(blk, "CONTENT_TYPE=%s", s);
3109    // Resize the array if nesessary
3110    if (arr_ind >= arr_size) {
3111      if ((p = (struct dir_entry *)
3112           realloc(*arr, (inc + arr_size) * sizeof(**arr))) != NULL) {
3113        // Memset new chunk to zero, otherwize st_mtime will have garbage which
3114        // can make strftime() segfault, see
3115        // http://code.google.com/p/mongoose/issues/detail?id=79
3116        memset(p + arr_size, 0, sizeof(**arr) * inc);
32953117
3296   if (conn->request_info.query_string != NULL)
3297   addenv(blk, "QUERY_STRING=%s", conn->request_info.query_string);
3118        *arr = p;
3119        arr_size += inc;
3120      }
3121    }
32983122
3299   if ((s = mg_get_header(conn, "Content-Length")) != NULL)
3300   addenv(blk, "CONTENT_LENGTH=%s", s);
3123    if (arr_ind < arr_size) {
3124      (*arr)[arr_ind].conn = conn;
3125      (*arr)[arr_ind].file_name = strdup(dp->d_name);
3126      stat(path, &(*arr)[arr_ind].st);
3127      arr_ind++;
3128    }
3129  }
3130  closedir(dirp);
33013131
3302   if ((s = getenv("PATH")) != NULL)
3303   addenv(blk, "PATH=%s", s);
3132  return arr_ind;
3133}
33043134
3305   if (conn->path_info != NULL) {
3306   addenv(blk, "PATH_INFO=%s", conn->path_info);
3307   }
3135int mg_url_encode(const char *src, size_t s_len, char *dst, size_t dst_len) {
3136  static const char *dont_escape = "._-$,;~()";
3137  static const char *hex = "0123456789abcdef";
3138  size_t i = 0, j = 0;
33083139
3309#if defined(_WIN32)
3310   if ((s = getenv("COMSPEC")) != NULL) {
3311   addenv(blk, "COMSPEC=%s", s);
3312   }
3313   if ((s = getenv("SYSTEMROOT")) != NULL) {
3314   addenv(blk, "SYSTEMROOT=%s", s);
3315   }
3316   if ((s = getenv("SystemDrive")) != NULL) {
3317   addenv(blk, "SystemDrive=%s", s);
3318   }
3319   if ((s = getenv("ProgramFiles")) != NULL) {
3320   addenv(blk, "ProgramFiles=%s", s);
3321   }
3322   if ((s = getenv("ProgramFiles(x86)")) != NULL) {
3323   addenv(blk, "ProgramFiles(x86)=%s", s);
3324   }
3325#else
3326   if ((s = getenv("LD_LIBRARY_PATH")) != NULL)
3327   addenv(blk, "LD_LIBRARY_PATH=%s", s);
3328#endif // _WIN32
3140  for (i = j = 0; dst_len > 0 && i < s_len && j < dst_len - 1; i++, j++) {
3141    if (isalnum(* (const unsigned char *) (src + i)) ||
3142        strchr(dont_escape, * (const unsigned char *) (src + i)) != NULL) {
3143      dst[j] = src[i];
3144    } else if (j + 3 < dst_len) {
3145      dst[j] = '%';
3146      dst[j + 1] = hex[(* (const unsigned char *) (src + i)) >> 4];
3147      dst[j + 2] = hex[(* (const unsigned char *) (src + i)) & 0xf];
3148      j += 2;
3149    }
3150  }
33293151
3330   if ((s = getenv("PERLLIB")) != NULL)
3331   addenv(blk, "PERLLIB=%s", s);
3152  dst[j] = '\0';
3153  return j;
3154}
3155#endif  // !NO_DIRECTORY_LISTING || !MONGOOSE_NO_DAV
33323156
3333   if (conn->request_info.remote_user != NULL) {
3334   addenv(blk, "REMOTE_USER=%s", conn->request_info.remote_user);
3335   addenv(blk, "%s", "AUTH_TYPE=Digest");
3336   }
3157#ifndef MONGOOSE_NO_DIRECTORY_LISTING
33373158
3338   // Add all headers as HTTP_* variables
3339   for (i = 0; i < conn->request_info.num_headers; i++) {
3340   p = addenv(blk, "HTTP_%s=%s",
3341      conn->request_info.http_headers[i].name,
3342      conn->request_info.http_headers[i].value);
3159static void print_dir_entry(const struct dir_entry *de) {
3160  char size[64], mod[64], href[MAX_PATH_SIZE * 3];
3161  int64_t fsize = de->st.st_size;
3162  int is_dir = S_ISDIR(de->st.st_mode);
3163  const char *slash = is_dir ? "/" : "";
33433164
3344   // Convert variable name into uppercase, and change - to _
3345   for (; *p != '=' && *p != '\0'; p++) {
3346      if (*p == '-')
3347      *p = '_';
3348      *p = (char) toupper(* (unsigned char *) p);
3349   }
3350   }
3165  if (is_dir) {
3166    mg_snprintf(size, sizeof(size), "%s", "[DIRECTORY]");
3167  } else {
3168     // We use (signed) cast below because MSVC 6 compiler cannot
3169     // convert unsigned __int64 to double.
3170    if (fsize < 1024) {
3171      mg_snprintf(size, sizeof(size), "%d", (int) fsize);
3172    } else if (fsize < 0x100000) {
3173      mg_snprintf(size, sizeof(size), "%.1fk", (double) fsize / 1024.0);
3174    } else if (fsize < 0x40000000) {
3175      mg_snprintf(size, sizeof(size), "%.1fM", (double) fsize / 1048576);
3176    } else {
3177      mg_snprintf(size, sizeof(size), "%.1fG", (double) fsize / 1073741824);
3178    }
3179  }
3180  strftime(mod, sizeof(mod), "%d-%b-%Y %H:%M", localtime(&de->st.st_mtime));
3181  mg_url_encode(de->file_name, strlen(de->file_name), href, sizeof(href));
3182  mg_printf_data(&de->conn->mg_conn,
3183                  "<tr><td><a href=\"%s%s\">%s%s</a></td>"
3184                  "<td>&nbsp;%s</td><td>&nbsp;&nbsp;%s</td></tr>\n",
3185                  href, slash, de->file_name, slash, mod, size);
3186}
33513187
3352   // Add user-specified variables
3353   s = conn->ctx->config[CGI_ENVIRONMENT];
3354   while ((s = next_option(s, &var_vec, NULL)) != NULL) {
3355   addenv(blk, "%.*s", (int) var_vec.len, var_vec.ptr);
3356   }
3188// Sort directory entries by size, or name, or modification time.
3189// On windows, __cdecl specification is needed in case if project is built
3190// with __stdcall convention. qsort always requires __cdels callback.
3191static int __cdecl compare_dir_entries(const void *p1, const void *p2) {
3192  const struct dir_entry *a = (const struct dir_entry *) p1,
3193        *b = (const struct dir_entry *) p2;
3194  const char *qs = a->conn->mg_conn.query_string ?
3195    a->conn->mg_conn.query_string : "na";
3196  int cmp_result = 0;
33573197
3358   blk->vars[blk->nvars++] = NULL;
3359   blk->buf[blk->len++] = '\0';
3198  if (S_ISDIR(a->st.st_mode) && !S_ISDIR(b->st.st_mode)) {
3199    return -1;  // Always put directories on top
3200  } else if (!S_ISDIR(a->st.st_mode) && S_ISDIR(b->st.st_mode)) {
3201    return 1;   // Always put directories on top
3202  } else if (*qs == 'n') {
3203    cmp_result = strcmp(a->file_name, b->file_name);
3204  } else if (*qs == 's') {
3205    cmp_result = a->st.st_size == b->st.st_size ? 0 :
3206      a->st.st_size > b->st.st_size ? 1 : -1;
3207  } else if (*qs == 'd') {
3208    cmp_result = a->st.st_mtime == b->st.st_mtime ? 0 :
3209      a->st.st_mtime > b->st.st_mtime ? 1 : -1;
3210  }
33603211
3361   assert(blk->nvars < (int) ARRAY_SIZE(blk->vars));
3362   assert(blk->len > 0);
3363   assert(blk->len < (int) sizeof(blk->buf));
3212  return qs[1] == 'd' ? -cmp_result : cmp_result;
33643213}
33653214
3366static void handle_cgi_request(struct mg_connection *conn, const char *prog) {
3367   int headers_len, data_len, i, fd_stdin[2], fd_stdout[2];
3368   const char *status, *status_text;
3369   char buf[16384], *pbuf, dir[PATH_MAX], *p;
3370   struct mg_request_info ri;
3371   struct cgi_env_block blk;
3372   FILE *in, *out;
3373   struct file fout = STRUCT_FILE_INITIALIZER;
3374   pid_t pid;
3375   ri.mg_request_info::num_headers = 0;
3215static void send_directory_listing(struct connection *conn, const char *dir) {
3216  struct dir_entry *arr = NULL;
3217  int i, num_entries, sort_direction = conn->mg_conn.query_string != NULL &&
3218    conn->mg_conn.query_string[1] == 'd' ? 'a' : 'd';
33763219
3377   prepare_cgi_environment(conn, prog, &blk);
3220  mg_send_header(&conn->mg_conn, "Transfer-Encoding", "chunked");
3221  mg_send_header(&conn->mg_conn, "Content-Type", "text/html; charset=utf-8");
33783222
3379   // CGI must be executed in its own directory. 'dir' must point to the
3380   // directory containing executable program, 'p' must point to the
3381   // executable program name relative to 'dir'.
3382   (void) mg_snprintf(conn, dir, sizeof(dir), "%s", prog);
3383   if ((p = strrchr(dir, '/')) != NULL) {
3384   *p++ = '\0';
3385   } else {
3386   dir[0] = '.', dir[1] = '\0';
3387   p = (char *) prog;
3388   }
3223  mg_printf_data(&conn->mg_conn,
3224              "<html><head><title>Index of %s</title>"
3225              "<style>th {text-align: left;}</style></head>"
3226              "<body><h1>Index of %s</h1><pre><table cellpadding=\"0\">"
3227              "<tr><th><a href=\"?n%c\">Name</a></th>"
3228              "<th><a href=\"?d%c\">Modified</a></th>"
3229              "<th><a href=\"?s%c\">Size</a></th></tr>"
3230              "<tr><td colspan=\"3\"><hr></td></tr>",
3231              conn->mg_conn.uri, conn->mg_conn.uri,
3232              sort_direction, sort_direction, sort_direction);
33893233
3390   pid = (pid_t) -1;
3391   fd_stdin[0] = fd_stdin[1] = fd_stdout[0] = fd_stdout[1] = -1;
3392   in = out = NULL;
3234  num_entries = scan_directory(conn, dir, &arr);
3235  qsort(arr, num_entries, sizeof(arr[0]), compare_dir_entries);
3236  for (i = 0; i < num_entries; i++) {
3237    print_dir_entry(&arr[i]);
3238    free(arr[i].file_name);
3239  }
3240  free(arr);
33933241
3394   if (pipe(fd_stdin) != 0 || pipe(fd_stdout) != 0) {
3395   send_http_error(conn, 500, http_500_error,
3396      "Cannot create CGI pipe: %s", strerror(ERRNO));
3397   goto done;
3398   }
3242  write_terminating_chunk(conn);
3243  close_local_endpoint(conn);
3244}
3245#endif  // MONGOOSE_NO_DIRECTORY_LISTING
33993246
3400   pid = spawn_process(conn, p, blk.buf, blk.vars, fd_stdin[0], fd_stdout[1],
3401                  dir);
3402   // spawn_process() must close those!
3403   // If we don't mark them as closed, close() attempt before
3404   // return from this function throws an exception on Windows.
3405   // Windows does not like when closed descriptor is closed again.
3406   fd_stdin[0] = fd_stdout[1] = -1;
3247#ifndef MONGOOSE_NO_DAV
3248static void print_props(struct connection *conn, const char *uri,
3249                        file_stat_t *stp) {
3250  char mtime[64];
34073251
3408   if (pid == (pid_t) -1) {
3409   send_http_error(conn, 500, http_500_error,
3410      "Cannot spawn CGI process [%s]: %s", prog, strerror(ERRNO));
3411   goto done;
3412   }
3252  gmt_time_string(mtime, sizeof(mtime), &stp->st_mtime);
3253  mg_printf(&conn->mg_conn,
3254      "<d:response>"
3255       "<d:href>%s</d:href>"
3256       "<d:propstat>"
3257        "<d:prop>"
3258         "<d:resourcetype>%s</d:resourcetype>"
3259         "<d:getcontentlength>%" INT64_FMT "</d:getcontentlength>"
3260         "<d:getlastmodified>%s</d:getlastmodified>"
3261        "</d:prop>"
3262        "<d:status>HTTP/1.1 200 OK</d:status>"
3263       "</d:propstat>"
3264      "</d:response>\n",
3265      uri, S_ISDIR(stp->st_mode) ? "<d:collection/>" : "",
3266      (int64_t) stp->st_size, mtime);
3267}
34133268
3414   if ((in = fdopen(fd_stdin[1], "wb")) == NULL ||
3415      (out = fdopen(fd_stdout[0], "rb")) == NULL) {
3416   send_http_error(conn, 500, http_500_error,
3417      "fopen: %s", strerror(ERRNO));
3418   goto done;
3419   }
3269static void handle_propfind(struct connection *conn, const char *path,
3270                            file_stat_t *stp, int exists) {
3271  static const char header[] = "HTTP/1.1 207 Multi-Status\r\n"
3272    "Connection: close\r\n"
3273    "Content-Type: text/xml; charset=utf-8\r\n\r\n"
3274    "<?xml version=\"1.0\" encoding=\"utf-8\"?>"
3275    "<d:multistatus xmlns:d='DAV:'>\n";
3276  static const char footer[] = "</d:multistatus>";
3277  const char *depth = mg_get_header(&conn->mg_conn, "Depth"),
3278        *list_dir = conn->server->config_options[ENABLE_DIRECTORY_LISTING];
34203279
3421   setbuf(in, NULL);
3422   setbuf(out, NULL);
3423   fout.fp = out;
3280  conn->mg_conn.status_code = 207;
34243281
3425   // Send POST data to the CGI process if needed
3426   if (!strcmp(conn->request_info.request_method, "POST") &&
3427      !forward_body_data(conn, in, INVALID_SOCKET, NULL)) {
3428   goto done;
3429   }
3282  // Print properties for the requested resource itself
3283  if (!exists) {
3284    conn->mg_conn.status_code = 404;
3285    mg_printf(&conn->mg_conn, "%s", "HTTP/1.1 404 Not Found\r\n\r\n");
3286  } else if (S_ISDIR(stp->st_mode) && mg_strcasecmp(list_dir, "yes") != 0) {
3287    conn->mg_conn.status_code = 403;
3288    mg_printf(&conn->mg_conn, "%s",
3289              "HTTP/1.1 403 Directory Listing Denied\r\n\r\n");
3290  } else {
3291    ns_send(conn->ns_conn, header, sizeof(header) - 1);
3292    print_props(conn, conn->mg_conn.uri, stp);
34303293
3431   // Close so child gets an EOF.
3432   fclose(in);
3433   in = NULL;
3434   fd_stdin[1] = -1;
3294    if (S_ISDIR(stp->st_mode) &&
3295             (depth == NULL || strcmp(depth, "0") != 0)) {
3296      struct dir_entry *arr = NULL;
3297      int i, num_entries = scan_directory(conn, path, &arr);
34353298
3436   // Now read CGI reply into a buffer. We need to set correct
3437   // status code, thus we need to see all HTTP headers first.
3438   // Do not send anything back to client, until we buffer in all
3439   // HTTP headers.
3440   data_len = 0;
3441   headers_len = read_request(out, conn, buf, sizeof(buf), &data_len);
3442   if (headers_len <= 0) {
3443   send_http_error(conn, 500, http_500_error,
3444               "CGI program sent malformed or too big (>%u bytes) "
3445               "HTTP headers: [%.*s]",
3446               (unsigned) sizeof(buf), data_len, buf);
3447   goto done;
3448   }
3449   pbuf = buf;
3450   buf[headers_len - 1] = '\0';
3451   parse_http_headers(&pbuf, &ri);
3299      for (i = 0; i < num_entries; i++) {
3300        char buf[MAX_PATH_SIZE * 3];
3301        struct dir_entry *de = &arr[i];
3302        mg_url_encode(de->file_name, strlen(de->file_name), buf, sizeof(buf));
3303        print_props(conn, buf, &de->st);
3304      }
3305    }
3306    ns_send(conn->ns_conn, footer, sizeof(footer) - 1);
3307  }
34523308
3453   // Make up and send the status line
3454   status_text = "OK";
3455   if ((status = get_header(&ri, "Status")) != NULL) {
3456   conn->status_code = atoi(status);
3457   status_text = status;
3458   while (isdigit(* (unsigned char *) status_text) || *status_text == ' ') {
3459      status_text++;
3460   }
3461   } else if (get_header(&ri, "Location") != NULL) {
3462   conn->status_code = 302;
3463   } else {
3464   conn->status_code = 200;
3465   }
3466   if (get_header(&ri, "Connection") != NULL &&
3467      !mg_strcasecmp(get_header(&ri, "Connection"), "keep-alive")) {
3468   conn->must_close = 1;
3469   }
3470   (void) mg_printf(conn, "HTTP/1.1 %d %s\r\n", conn->status_code,
3471               status_text);
3309  close_local_endpoint(conn);
3310}
34723311
3473   // Send headers
3474   for (i = 0; i < ri.num_headers; i++) {
3475   mg_printf(conn, "%s: %s\r\n",
3476            ri.http_headers[i].name, ri.http_headers[i].value);
3477   }
3478   mg_write(conn, "\r\n", 2);
3312static void handle_mkcol(struct connection *conn, const char *path) {
3313  int status_code = 500;
34793314
3480   // Send chunk of data that may have been read after the headers
3481   conn->num_bytes_sent += mg_write(conn, buf + headers_len,
3482                           (size_t)(data_len - headers_len));
3315  if (conn->mg_conn.content_len > 0) {
3316    status_code = 415;
3317  } else if (!mkdir(path, 0755)) {
3318    status_code = 201;
3319  } else if (errno == EEXIST) {
3320    status_code = 405;
3321  } else if (errno == EACCES) {
3322    status_code = 403;
3323  } else if (errno == ENOENT) {
3324    status_code = 409;
3325  }
3326  send_http_error(conn, status_code, NULL);
3327}
34833328
3484   // Read the rest of CGI output and send to the client
3485   send_file_data(conn, &fout, 0, INT64_MAX);
3329static int remove_directory(const char *dir) {
3330  char path[MAX_PATH_SIZE];
3331  struct dirent *dp;
3332  file_stat_t st;
3333  DIR *dirp;
34863334
3487done:
3488   if (pid != (pid_t) -1) {
3489   kill(pid, SIGKILL);
3490   }
3491   if (fd_stdin[0] != -1) {
3492   close(fd_stdin[0]);
3493   }
3494   if (fd_stdout[1] != -1) {
3495   close(fd_stdout[1]);
3496   }
3335  if ((dirp = opendir(dir)) == NULL) return 0;
34973336
3498   if (in != NULL) {
3499   fclose(in);
3500   } else if (fd_stdin[1] != -1) {
3501   close(fd_stdin[1]);
3502   }
3337  while ((dp = readdir(dirp)) != NULL) {
3338    if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, "..")) continue;
3339    mg_snprintf(path, sizeof(path), "%s%c%s", dir, '/', dp->d_name);
3340    stat(path, &st);
3341    if (S_ISDIR(st.st_mode)) {
3342      remove_directory(path);
3343    } else {
3344      remove(path);
3345    }
3346  }
3347  closedir(dirp);
3348  rmdir(dir);
35033349
3504   if (out != NULL) {
3505   fclose(out);
3506   } else if (fd_stdout[0] != -1) {
3507   close(fd_stdout[0]);
3508   }
3350  return 1;
35093351}
3510#endif // !NO_CGI
35113352
3353static void handle_delete(struct connection *conn, const char *path) {
3354  file_stat_t st;
3355
3356  if (stat(path, &st) != 0) {
3357    send_http_error(conn, 404, NULL);
3358  } else if (S_ISDIR(st.st_mode)) {
3359    remove_directory(path);
3360    send_http_error(conn, 204, NULL);
3361  } else if (remove(path) == 0) {
3362    send_http_error(conn, 204, NULL);
3363  } else {
3364    send_http_error(conn, 423, NULL);
3365  }
3366}
3367
35123368// For a given PUT path, create all intermediate subdirectories
35133369// for given path. Return 0 if the path itself is a directory,
35143370// or -1 on error, 1 if OK.
3515static int put_dir(struct mg_connection *conn, const char *path) {
3516   char buf[PATH_MAX];
3517   const char *s, *p;
3518   struct file file = STRUCT_FILE_INITIALIZER;
3519   int len, res = 1;
3371static int put_dir(const char *path) {
3372  char buf[MAX_PATH_SIZE];
3373  const char *s, *p;
3374  file_stat_t st;
35203375
3521   for (s = p = path + 2; (p = strchr(s, '/')) != NULL; s = ++p) {
3522   len = p - path;
3523   if (len >= (int) sizeof(buf)) {
3524      res = -1;
3525      break;
3526   }
3527   memcpy(buf, path, len);
3528   buf[len] = '\0';
3376  // Create intermediate directories if they do not exist
3377  for (s = p = path + 1; (p = strchr(s, '/')) != NULL; s = ++p) {
3378    if (p - path >= (int) sizeof(buf)) return -1; // Buffer overflow
3379    memcpy(buf, path, p - path);
3380    buf[p - path] = '\0';
3381    if (stat(buf, &st) != 0 && mkdir(buf, 0755) != 0) return -1;
3382    if (p[1] == '\0') return 0;  // Path is a directory itself
3383  }
35293384
3530   // Try to create intermediate directory
3531   DEBUG_TRACE(("mkdir(%s)", buf));
3532   if (!mg_stat(conn, buf, &file) && mg_mkdir(buf, 0755) != 0) {
3533      res = -1;
3534      break;
3535   }
3385  return 1;
3386}
35363387
3537   // Is path itself a directory?
3538   if (p[1] == '\0') {
3539      res = 0;
3540   }
3541   }
3388static void handle_put(struct connection *conn, const char *path) {
3389  file_stat_t st;
3390  const char *range, *cl_hdr = mg_get_header(&conn->mg_conn, "Content-Length");
3391  int64_t r1, r2;
3392  int rc;
35423393
3543   return res;
3394  conn->mg_conn.status_code = !stat(path, &st) ? 200 : 201;
3395  if ((rc = put_dir(path)) == 0) {
3396    mg_printf(&conn->mg_conn, "HTTP/1.1 %d OK\r\n\r\n",
3397              conn->mg_conn.status_code);
3398    close_local_endpoint(conn);
3399  } else if (rc == -1) {
3400    send_http_error(conn, 500, "put_dir: %s", strerror(errno));
3401  } else if (cl_hdr == NULL) {
3402    send_http_error(conn, 411, NULL);
3403#ifdef _WIN32
3404    //On Windows, open() is a macro with 2 params
3405  } else if ((conn->endpoint.fd =
3406              open(path, O_RDWR | O_CREAT | O_TRUNC)) < 0) {
3407#else
3408  } else if ((conn->endpoint.fd =
3409              open(path, O_RDWR | O_CREAT | O_TRUNC, 0644)) < 0) {
3410#endif
3411    send_http_error(conn, 500, "open(%s): %s", path, strerror(errno));
3412  } else {
3413    DBG(("PUT [%s] %zu", path, conn->ns_conn->recv_iobuf.len));
3414    conn->endpoint_type = EP_PUT;
3415    ns_set_close_on_exec(conn->endpoint.fd);
3416    range = mg_get_header(&conn->mg_conn, "Content-Range");
3417    conn->cl = to64(cl_hdr);
3418    r1 = r2 = 0;
3419    if (range != NULL && parse_range_header(range, &r1, &r2) > 0) {
3420      conn->mg_conn.status_code = 206;
3421      lseek(conn->endpoint.fd, r1, SEEK_SET);
3422      conn->cl = r2 > r1 ? r2 - r1 + 1: conn->cl - r1;
3423    }
3424    mg_printf(&conn->mg_conn, "HTTP/1.1 %d OK\r\nContent-Length: 0\r\n\r\n",
3425              conn->mg_conn.status_code);
3426  }
35443427}
35453428
3546static void mkcol(struct mg_connection *conn, const char *path) {
3547   int rc, body_len;
3548   struct de de;
3549   memset(&de.file, 0, sizeof(de.file));
3550   mg_stat(conn, path, &de.file);
3429static void forward_put_data(struct connection *conn) {
3430  struct iobuf *io = &conn->ns_conn->recv_iobuf;
3431  size_t k = conn->cl < (int64_t) io->len ? conn->cl : io->len;   // To write
3432  int n = write(conn->endpoint.fd, io->buf, k);   // Write them!
3433  if (n > 0) {
3434    iobuf_remove(io, n);
3435    conn->cl -= n;
3436  }
3437  if (conn->cl <= 0) {
3438    close_local_endpoint(conn);
3439  }
3440}
3441#endif //  MONGOOSE_NO_DAV
35513442
3552   if(de.file.modification_time) {
3553      send_http_error(conn, 405, "Method Not Allowed",
3554                  "mkcol(%s): %s", path, strerror(ERRNO));
3555      return;
3556   }
3443static void send_options(struct connection *conn) {
3444  conn->mg_conn.status_code = 200;
3445  mg_printf(&conn->mg_conn, "%s",
3446            "HTTP/1.1 200 OK\r\nAllow: GET, POST, HEAD, CONNECT, PUT, "
3447            "DELETE, OPTIONS, PROPFIND, MKCOL\r\nDAV: 1\r\n\r\n");
3448  close_local_endpoint(conn);
3449}
35573450
3558   body_len = conn->data_len - conn->request_len;
3559   if(body_len > 0) {
3560      send_http_error(conn, 415, "Unsupported media type",
3561                  "mkcol(%s): %s", path, strerror(ERRNO));
3562      return;
3563   }
3451#ifndef MONGOOSE_NO_AUTH
3452void mg_send_digest_auth_request(struct mg_connection *c) {
3453  struct connection *conn = MG_CONN_2_CONN(c);
3454  c->status_code = 401;
3455  mg_printf(c,
3456            "HTTP/1.1 401 Unauthorized\r\n"
3457            "WWW-Authenticate: Digest qop=\"auth\", "
3458            "realm=\"%s\", nonce=\"%lu\"\r\n\r\n",
3459            conn->server->config_options[AUTH_DOMAIN],
3460            (unsigned long) time(NULL));
3461  close_local_endpoint(conn);
3462}
35643463
3565   rc = mg_mkdir(path, 0755);
3464// Use the global passwords file, if specified by auth_gpass option,
3465// or search for .htpasswd in the requested directory.
3466static FILE *open_auth_file(struct connection *conn, const char *path) {
3467  char name[MAX_PATH_SIZE];
3468  const char *p, *gpass = conn->server->config_options[GLOBAL_AUTH_FILE];
3469  file_stat_t st;
3470  FILE *fp = NULL;
35663471
3567   if (rc == 0) {
3568   conn->status_code = 201;
3569   mg_printf(conn, "HTTP/1.1 %d Created\r\n\r\n", conn->status_code);
3570   } else if (rc == -1) {
3571      if(errno == EEXIST)
3572      send_http_error(conn, 405, "Method Not Allowed",
3573                  "mkcol(%s): %s", path, strerror(ERRNO));
3574      else if(errno == EACCES)
3575         send_http_error(conn, 403, "Forbidden",
3576                  "mkcol(%s): %s", path, strerror(ERRNO));
3577      else if(errno == ENOENT)
3578         send_http_error(conn, 409, "Conflict",
3579                  "mkcol(%s): %s", path, strerror(ERRNO));
3580      else
3581         send_http_error(conn, 500, http_500_error,
3582                     "fopen(%s): %s", path, strerror(ERRNO));
3583   }
3472  if (gpass != NULL) {
3473    // Use global passwords file
3474    fp = fopen(gpass, "r");
3475  } else if (!stat(path, &st) && S_ISDIR(st.st_mode)) {
3476    mg_snprintf(name, sizeof(name), "%s%c%s", path, '/', PASSWORDS_FILE_NAME);
3477    fp = fopen(name, "r");
3478  } else {
3479    // Try to find .htpasswd in requested directory.
3480    if ((p = strrchr(path, '/')) == NULL) p = path;
3481    mg_snprintf(name, sizeof(name), "%.*s%c%s",
3482                (int) (p - path), path, '/', PASSWORDS_FILE_NAME);
3483    fp = fopen(name, "r");
3484  }
3485
3486  return fp;
35843487}
35853488
3586static void put_file(struct mg_connection *conn, const char *path) {
3587   struct file file = STRUCT_FILE_INITIALIZER;
3588   const char *range;
3589   int64_t r1, r2;
3590   int rc;
3489#if !defined(HAVE_MD5) && !defined(MONGOOSE_NO_AUTH)
3490typedef struct MD5Context {
3491  uint32_t buf[4];
3492  uint32_t bits[2];
3493  unsigned char in[64];
3494} MD5_CTX;
35913495
3592   conn->status_code = mg_stat(conn, path, &file) ? 200 : 201;
3496static void byteReverse(unsigned char *buf, unsigned longs) {
3497  uint32_t t;
35933498
3594   if ((rc = put_dir(conn, path)) == 0) {
3595   mg_printf(conn, "HTTP/1.1 %d OK\r\n\r\n", conn->status_code);
3596   } else if (rc == -1) {
3597   send_http_error(conn, 500, http_500_error,
3598               "put_dir(%s): %s", path, strerror(ERRNO));
3599   } else if (!mg_fopen(conn, path, "wb+", &file) || file.fp == NULL) {
3600   mg_fclose(&file);
3601   send_http_error(conn, 500, http_500_error,
3602               "fopen(%s): %s", path, strerror(ERRNO));
3603   } else {
3604   fclose_on_exec(&file);
3605   range = mg_get_header(conn, "Content-Range");
3606   r1 = r2 = 0;
3607   if (range != NULL && parse_range_header(range, &r1, &r2) > 0) {
3608      conn->status_code = 206;
3609      fseeko(file.fp, r1, SEEK_SET);
3610   }
3611   if (forward_body_data(conn, file.fp, INVALID_SOCKET, NULL)) {
3612      mg_printf(conn, "HTTP/1.1 %d OK\r\n\r\n", conn->status_code);
3613   }
3614   mg_fclose(&file);
3615   }
3499  // Forrest: MD5 expect LITTLE_ENDIAN, swap if BIG_ENDIAN
3500  if (is_big_endian()) {
3501    do {
3502      t = (uint32_t) ((unsigned) buf[3] << 8 | buf[2]) << 16 |
3503        ((unsigned) buf[1] << 8 | buf[0]);
3504      * (uint32_t *) buf = t;
3505      buf += 4;
3506    } while (--longs);
3507  }
36163508}
36173509
3618static void send_ssi_file(struct mg_connection *, const char *,
3619                     struct file *, int);
3510#define F1(x, y, z) (z ^ (x & (y ^ z)))
3511#define F2(x, y, z) F1(z, x, y)
3512#define F3(x, y, z) (x ^ y ^ z)
3513#define F4(x, y, z) (y ^ (x | ~z))
36203514
3621static void do_ssi_include(struct mg_connection *conn, const char *ssi,
3622                     char *tag, int include_level) {
3623   char file_name[MG_BUF_LEN], path[PATH_MAX], *p;
3624   struct file file = STRUCT_FILE_INITIALIZER;
3515#define MD5STEP(f, w, x, y, z, data, s) \
3516  ( w += f(x, y, z) + data,  w = w<<s | w>>(32-s),  w += x )
36253517
3626   // sscanf() is safe here, since send_ssi_file() also uses buffer
3627   // of size MG_BUF_LEN to get the tag. So strlen(tag) is always < MG_BUF_LEN.
3628   if (sscanf(tag, " virtual=\"%[^\"]\"", file_name) == 1) {
3629   // File name is relative to the webserver root
3630   (void) mg_snprintf(conn, path, sizeof(path), "%s%c%s",
3631      conn->ctx->config[DOCUMENT_ROOT], '/', file_name);
3632   } else if (sscanf(tag, " file=\"%[^\"]\"", file_name) == 1) {
3633   // File name is relative to the webserver working directory
3634   // or it is absolute system path
3635   (void) mg_snprintf(conn, path, sizeof(path), "%s", file_name);
3636   } else if (sscanf(tag, " \"%[^\"]\"", file_name) == 1) {
3637   // File name is relative to the currect document
3638   (void) mg_snprintf(conn, path, sizeof(path), "%s", ssi);
3639   if ((p = strrchr(path, '/')) != NULL) {
3640      p[1] = '\0';
3641   }
3642   (void) mg_snprintf(conn, path + strlen(path),
3643      sizeof(path) - strlen(path), "%s", file_name);
3644   } else {
3645   cry(conn, "Bad SSI #include: [%s]", tag);
3646   return;
3647   }
3518// Start MD5 accumulation.  Set bit count to 0 and buffer to mysterious
3519// initialization constants.
3520static void MD5Init(MD5_CTX *ctx) {
3521  ctx->buf[0] = 0x67452301;
3522  ctx->buf[1] = 0xefcdab89;
3523  ctx->buf[2] = 0x98badcfe;
3524  ctx->buf[3] = 0x10325476;
36483525
3649   if (!mg_fopen(conn, path, "rb", &file)) {
3650   cry(conn, "Cannot open SSI #include: [%s]: fopen(%s): %s",
3651      tag, path, strerror(ERRNO));
3652   } else {
3653   fclose_on_exec(&file);
3654   if (match_prefix(conn->ctx->config[SSI_EXTENSIONS],
3655                  strlen(conn->ctx->config[SSI_EXTENSIONS]), path) > 0) {
3656      send_ssi_file(conn, path, &file, include_level + 1);
3657   } else {
3658      send_file_data(conn, &file, 0, INT64_MAX);
3659   }
3660   mg_fclose(&file);
3661   }
3526  ctx->bits[0] = 0;
3527  ctx->bits[1] = 0;
36623528}
36633529
3664#if !defined(NO_POPEN)
3665static void do_ssi_exec(struct mg_connection *conn, char *tag) {
3666   char cmd[MG_BUF_LEN];
3667   struct file file = STRUCT_FILE_INITIALIZER;
3530static void MD5Transform(uint32_t buf[4], uint32_t const in[16]) {
3531  register uint32_t a, b, c, d;
36683532
3669   if (sscanf(tag, " \"%[^\"]\"", cmd) != 1) {
3670   cry(conn, "Bad SSI #exec: [%s]", tag);
3671   } else if ((file.fp = popen(cmd, "r")) == NULL) {
3672   cry(conn, "Cannot SSI #exec: [%s]: %s", cmd, strerror(ERRNO));
3673   } else {
3674   send_file_data(conn, &file, 0, INT64_MAX);
3675   pclose(file.fp);
3676   }
3677}
3678#endif // !NO_POPEN
3533  a = buf[0];
3534  b = buf[1];
3535  c = buf[2];
3536  d = buf[3];
36793537
3680static int mg_fgetc(struct file *filep, int offset) {
3681   if (filep->membuf != NULL && offset >=0 && offset < filep->size) {
3682   return ((unsigned char *) filep->membuf)[offset];
3683   } else if (filep->fp != NULL) {
3684   return fgetc(filep->fp);
3685   } else {
3686   return EOF;
3687   }
3688}
3538  MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7);
3539  MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12);
3540  MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17);
3541  MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22);
3542  MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7);
3543  MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12);
3544  MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17);
3545  MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22);
3546  MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7);
3547  MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12);
3548  MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17);
3549  MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22);
3550  MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7);
3551  MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12);
3552  MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17);
3553  MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22);
36893554
3690static void send_ssi_file(struct mg_connection *conn, const char *path,
3691                     struct file *filep, int include_level) {
3692   char buf[MG_BUF_LEN];
3693   int ch, offset, len, in_ssi_tag;
3555  MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5);
3556  MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9);
3557  MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14);
3558  MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20);
3559  MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5);
3560  MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9);
3561  MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14);
3562  MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20);
3563  MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5);
3564  MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9);
3565  MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14);
3566  MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20);
3567  MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5);
3568  MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9);
3569  MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14);
3570  MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20);
36943571
3695   if (include_level > 10) {
3696   cry(conn, "SSI #include level is too deep (%s)", path);
3697   return;
3698   }
3572  MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4);
3573  MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11);
3574  MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16);
3575  MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23);
3576  MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4);
3577  MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11);
3578  MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16);
3579  MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23);
3580  MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4);
3581  MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11);
3582  MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16);
3583  MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23);
3584  MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4);
3585  MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11);
3586  MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16);
3587  MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23);
36993588
3700   in_ssi_tag = len = offset = 0;
3701   while ((ch = mg_fgetc(filep, offset)) != EOF) {
3702   if (in_ssi_tag && ch == '>') {
3703      in_ssi_tag = 0;
3704      buf[len++] = (char) ch;
3705      buf[len] = '\0';
3706      assert(len <= (int) sizeof(buf));
3707      if (len < 6 || memcmp(buf, "<!--#", 5) != 0) {
3708      // Not an SSI tag, pass it
3709      (void) mg_write(conn, buf, (size_t) len);
3710      } else {
3711      if (!memcmp(buf + 5, "include", 7)) {
3712         do_ssi_include(conn, path, buf + 12, include_level);
3713#if !defined(NO_POPEN)
3714      } else if (!memcmp(buf + 5, "exec", 4)) {
3715         do_ssi_exec(conn, buf + 9);
3716#endif // !NO_POPEN
3717      } else {
3718         cry(conn, "%s: unknown SSI " "command: \"%s\"", path, buf);
3719      }
3720      }
3721      len = 0;
3722   } else if (in_ssi_tag) {
3723      if (len == 5 && memcmp(buf, "<!--#", 5) != 0) {
3724      // Not an SSI tag
3725      in_ssi_tag = 0;
3726      } else if (len == (int) sizeof(buf) - 2) {
3727      cry(conn, "%s: SSI tag is too large", path);
3728      len = 0;
3729      }
3730      buf[len++] = ch & 0xff;
3731   } else if (ch == '<') {
3732      in_ssi_tag = 1;
3733      if (len > 0) {
3734      mg_write(conn, buf, (size_t) len);
3735      }
3736      len = 0;
3737      buf[len++] = ch & 0xff;
3738   } else {
3739      buf[len++] = ch & 0xff;
3740      if (len == (int) sizeof(buf)) {
3741      mg_write(conn, buf, (size_t) len);
3742      len = 0;
3743      }
3744   }
3745   }
3589  MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6);
3590  MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10);
3591  MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15);
3592  MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21);
3593  MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6);
3594  MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10);
3595  MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15);
3596  MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21);
3597  MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6);
3598  MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10);
3599  MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15);
3600  MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21);
3601  MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6);
3602  MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10);
3603  MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15);
3604  MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21);
37463605
3747   // Send the rest of buffered data
3748   if (len > 0) {
3749   mg_write(conn, buf, (size_t) len);
3750   }
3606  buf[0] += a;
3607  buf[1] += b;
3608  buf[2] += c;
3609  buf[3] += d;
37513610}
37523611
3753static void handle_ssi_file_request(struct mg_connection *conn,
3754                           const char *path) {
3755   struct file file = STRUCT_FILE_INITIALIZER;
3612static void MD5Update(MD5_CTX *ctx, unsigned char const *buf, unsigned len) {
3613  uint32_t t;
37563614
3757   if (!mg_fopen(conn, path, "rb", &file)) {
3758   send_http_error(conn, 500, http_500_error, "fopen(%s): %s", path,
3759               strerror(ERRNO));
3760   } else {
3761   conn->must_close = 1;
3762   fclose_on_exec(&file);
3763   mg_printf(conn, "HTTP/1.1 200 OK\r\n"
3764            "Content-Type: text/html\r\nConnection: %s\r\n\r\n",
3765            suggest_connection_header(conn));
3766   send_ssi_file(conn, path, &file, 0);
3767   mg_fclose(&file);
3768   }
3769}
3615  t = ctx->bits[0];
3616  if ((ctx->bits[0] = t + ((uint32_t) len << 3)) < t)
3617    ctx->bits[1]++;
3618  ctx->bits[1] += len >> 29;
37703619
3771static void send_options(struct mg_connection *conn) {
3772   conn->status_code = 200;
3620  t = (t >> 3) & 0x3f;
37733621
3774   mg_printf(conn, "%s", "HTTP/1.1 200 OK\r\n"
3775         "Allow: GET, POST, HEAD, CONNECT, PUT, DELETE, OPTIONS, PROPFIND, MKCOL\r\n"
3776         "DAV: 1\r\n\r\n");
3777}
3622  if (t) {
3623    unsigned char *p = (unsigned char *) ctx->in + t;
37783624
3779// Writes PROPFIND properties for a collection element
3780static void print_props(struct mg_connection *conn, const char* uri,
3781                  struct file *filep) {
3782   char mtime[64];
3783   gmt_time_string(mtime, sizeof(mtime), &filep->modification_time);
3784   conn->num_bytes_sent += mg_printf(conn,
3785      "<d:response>"
3786      "<d:href>%s</d:href>"
3787      "<d:propstat>"
3788      "<d:prop>"
3789         "<d:resourcetype>%s</d:resourcetype>"
3790         "<d:getcontentlength>%" INT64_FMT "</d:getcontentlength>"
3791         "<d:getlastmodified>%s</d:getlastmodified>"
3792      "</d:prop>"
3793      "<d:status>HTTP/1.1 200 OK</d:status>"
3794      "</d:propstat>"
3795      "</d:response>\n",
3796      uri,
3797      filep->is_directory ? "<d:collection/>" : "",
3798      filep->size,
3799      mtime);
3800}
3625    t = 64 - t;
3626    if (len < t) {
3627      memcpy(p, buf, len);
3628      return;
3629    }
3630    memcpy(p, buf, t);
3631    byteReverse(ctx->in, 16);
3632    MD5Transform(ctx->buf, (uint32_t *) ctx->in);
3633    buf += t;
3634    len -= t;
3635  }
38013636
3802static void print_dav_dir_entry(struct de *de, void *data) {
3803   char href[PATH_MAX];
3804   char href_encoded[PATH_MAX];
3805   struct mg_connection *conn = (struct mg_connection *) data;
3806   mg_snprintf(conn, href, sizeof(href), "%s%s",
3807            conn->request_info.uri, de->file_name);
3808   mg_url_encode(href, href_encoded, PATH_MAX-1);
3809   print_props(conn, href_encoded, &de->file);
3637  while (len >= 64) {
3638    memcpy(ctx->in, buf, 64);
3639    byteReverse(ctx->in, 16);
3640    MD5Transform(ctx->buf, (uint32_t *) ctx->in);
3641    buf += 64;
3642    len -= 64;
3643  }
3644
3645  memcpy(ctx->in, buf, len);
38103646}
38113647
3812static void handle_propfind(struct mg_connection *conn, const char *path,
3813                     struct file *filep) {
3814   const char *depth = mg_get_header(conn, "Depth");
3648static void MD5Final(unsigned char digest[16], MD5_CTX *ctx) {
3649  unsigned count;
3650  unsigned char *p;
3651  uint32_t *a;
38153652
3816   conn->must_close = 1;
3817   conn->status_code = 207;
3818   mg_printf(conn, "HTTP/1.1 207 Multi-Status\r\n"
3819         "Connection: close\r\n"
3820         "Content-Type: text/xml; charset=utf-8\r\n\r\n");
3653  count = (ctx->bits[0] >> 3) & 0x3F;
38213654
3822   conn->num_bytes_sent += mg_printf(conn,
3823      "<?xml version=\"1.0\" encoding=\"utf-8\"?>"
3824      "<d:multistatus xmlns:d='DAV:'>\n");
3655  p = ctx->in + count;
3656  *p++ = 0x80;
3657  count = 64 - 1 - count;
3658  if (count < 8) {
3659    memset(p, 0, count);
3660    byteReverse(ctx->in, 16);
3661    MD5Transform(ctx->buf, (uint32_t *) ctx->in);
3662    memset(ctx->in, 0, 56);
3663  } else {
3664    memset(p, 0, count - 8);
3665  }
3666  byteReverse(ctx->in, 14);
38253667
3826   // Print properties for the requested resource itself
3827   print_props(conn, conn->request_info.uri, filep);
3668  a = (uint32_t *)ctx->in;
3669  a[14] = ctx->bits[0];
3670  a[15] = ctx->bits[1];
38283671
3829   // If it is a directory, print directory entries too if Depth is not 0
3830   if (filep->is_directory &&
3831      !mg_strcasecmp(conn->ctx->config[ENABLE_DIRECTORY_LISTING], "yes") &&
3832      (depth == NULL || strcmp(depth, "0") != 0)) {
3833   scan_directory(conn, path, conn, &print_dav_dir_entry);
3834   }
3835
3836   conn->num_bytes_sent += mg_printf(conn, "%s\n", "</d:multistatus>");
3672  MD5Transform(ctx->buf, (uint32_t *) ctx->in);
3673  byteReverse((unsigned char *) ctx->buf, 4);
3674  memcpy(digest, ctx->buf, 16);
3675  memset((char *) ctx, 0, sizeof(*ctx));
38373676}
3677#endif // !HAVE_MD5
38383678
3839#if defined(USE_WEBSOCKET)
38403679
3841// START OF SHA-1 code
3842// Copyright(c) By Steve Reid <steve@edmweb.com>
3843#define SHA1HANDSOFF
3844#if defined(__sun)
3845#include "solarisfixes.h"
3846#endif
38473680
3848union char64long16 { unsigned char c[64]; uint32_t l[16]; };
3681// Stringify binary data. Output buffer must be twice as big as input,
3682// because each byte takes 2 bytes in string representation
3683static void bin2str(char *to, const unsigned char *p, size_t len) {
3684  static const char *hex = "0123456789abcdef";
38493685
3850#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits))))
3851
3852static uint32_t blk0(union char64long16 *block, int i) {
3853   // Forrest: SHA expect BIG_ENDIAN, swap if LITTLE_ENDIAN
3854   if (!is_big_endian()) {
3855   block->l[i] = (rol(block->l[i], 24) & 0xFF00FF00) |
3856      (rol(block->l[i], 8) & 0x00FF00FF);
3857   }
3858   return block->l[i];
3686  for (; len--; p++) {
3687    *to++ = hex[p[0] >> 4];
3688    *to++ = hex[p[0] & 0x0f];
3689  }
3690  *to = '\0';
38593691}
38603692
3861#define blk(i) (block->l[i&15] = rol(block->l[(i+13)&15]^block->l[(i+8)&15] \
3862   ^block->l[(i+2)&15]^block->l[i&15],1))
3863#define R0(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk0(block, i)+0x5A827999+rol(v,5);w=rol(w,30);
3864#define R1(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5);w=rol(w,30);
3865#define R2(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=rol(w,30);
3866#define R3(v,w,x,y,z,i) z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=rol(w,30);
3867#define R4(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=rol(w,30);
3693// Return stringified MD5 hash for list of strings. Buffer must be 33 bytes.
3694char *mg_md5(char buf[33], ...) {
3695  unsigned char hash[16];
3696  const char *p;
3697  va_list ap;
3698  MD5_CTX ctx;
38683699
3869typedef struct {
3870   uint32_t state[5];
3871   uint32_t count[2];
3872   unsigned char buffer[64];
3873} SHA1_CTX;
3700  MD5Init(&ctx);
38743701
3875static void SHA1Transform(uint32_t state[5], const unsigned char buffer[64]) {
3876   uint32_t a, b, c, d, e;
3877   union char64long16 block[1];
3702  va_start(ap, buf);
3703  while ((p = va_arg(ap, const char *)) != NULL) {
3704    MD5Update(&ctx, (const unsigned char *) p, (unsigned) strlen(p));
3705  }
3706  va_end(ap);
38783707
3879   memcpy(block, buffer, 64);
3880   a = state[0];
3881   b = state[1];
3882   c = state[2];
3883   d = state[3];
3884   e = state[4];
3885   R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3);
3886   R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7);
3887   R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11);
3888   R0(d,e,a,b,c,12); R0(c,d,e,a,b,13); R0(b,c,d,e,a,14); R0(a,b,c,d,e,15);
3889   R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19);
3890   R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23);
3891   R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27);
3892   R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31);
3893   R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35);
3894   R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39);
3895   R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43);
3896   R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47);
3897   R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51);
3898   R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55);
3899   R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59);
3900   R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63);
3901   R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67);
3902   R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71);
3903   R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75);
3904   R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79);
3905   state[0] += a;
3906   state[1] += b;
3907   state[2] += c;
3908   state[3] += d;
3909   state[4] += e;
3910   a = b = c = d = e = 0;
3911   memset(block, '\0', sizeof(block));
3708  MD5Final(hash, &ctx);
3709  bin2str(buf, hash, sizeof(hash));
3710  return buf;
39123711}
39133712
3914static void SHA1Init(SHA1_CTX* context) {
3915   context->state[0] = 0x67452301;
3916   context->state[1] = 0xEFCDAB89;
3917   context->state[2] = 0x98BADCFE;
3918   context->state[3] = 0x10325476;
3919   context->state[4] = 0xC3D2E1F0;
3920   context->count[0] = context->count[1] = 0;
3921}
3713// Check the user's password, return 1 if OK
3714static int check_password(const char *method, const char *ha1, const char *uri,
3715                          const char *nonce, const char *nc, const char *cnonce,
3716                          const char *qop, const char *response) {
3717  char ha2[32 + 1], expected_response[32 + 1];
39223718
3923static void SHA1Update(SHA1_CTX* context, const unsigned char* data,
3924                  uint32_t len) {
3925   uint32_t i, j;
3719#if 0
3720  // Check for authentication timeout
3721  if ((unsigned long) time(NULL) - (unsigned long) to64(nonce) > 3600 * 2) {
3722    return 0;
3723  }
3724#endif
39263725
3927   j = context->count[0];
3928   if ((context->count[0] += len << 3) < j)
3929   context->count[1]++;
3930   context->count[1] += (len>>29);
3931   j = (j >> 3) & 63;
3932   if ((j + len) > 63) {
3933   memcpy(&context->buffer[j], data, (i = 64-j));
3934   SHA1Transform(context->state, context->buffer);
3935   for ( ; i + 63 < len; i += 64) {
3936      SHA1Transform(context->state, &data[i]);
3937   }
3938   j = 0;
3939   }
3940   else i = 0;
3941   memcpy(&context->buffer[j], &data[i], len - i);
3942}
3726  mg_md5(ha2, method, ":", uri, NULL);
3727  mg_md5(expected_response, ha1, ":", nonce, ":", nc,
3728      ":", cnonce, ":", qop, ":", ha2, NULL);
39433729
3944static void SHA1Final(unsigned char digest[20], SHA1_CTX* context) {
3945   unsigned i;
3946   unsigned char finalcount[8], c;
3947
3948   for (i = 0; i < 8; i++) {
3949   finalcount[i] = (unsigned char)((context->count[(i >= 4 ? 0 : 1)]
3950                              >> ((3-(i & 3)) * 8) ) & 255);
3951   }
3952   c = 0200;
3953   SHA1Update(context, &c, 1);
3954   while ((context->count[0] & 504) != 448) {
3955   c = 0000;
3956   SHA1Update(context, &c, 1);
3957   }
3958   SHA1Update(context, finalcount, 8);
3959   for (i = 0; i < 20; i++) {
3960   digest[i] = (unsigned char)
3961      ((context->state[i>>2] >> ((3-(i & 3)) * 8) ) & 255);
3962   }
3963   memset(context, '\0', sizeof(*context));
3964   memset(&finalcount, '\0', sizeof(finalcount));
3730  return mg_strcasecmp(response, expected_response) == 0 ? MG_TRUE : MG_FALSE;
39653731}
3966// END OF SHA1 CODE
39673732
3968static void base64_encode(const unsigned char *src, int src_len, char *dst) {
3969   static const char *b64 =
3970   "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
3971   int i, j, a, b, c;
39723733
3973   for (i = j = 0; i < src_len; i += 3) {
3974   a = src[i];
3975   b = i + 1 >= src_len ? 0 : src[i + 1];
3976   c = i + 2 >= src_len ? 0 : src[i + 2];
3734// Authorize against the opened passwords file. Return 1 if authorized.
3735int mg_authorize_digest(struct mg_connection *c, FILE *fp) {
3736  struct connection *conn = MG_CONN_2_CONN(c);
3737  const char *hdr;
3738  char line[256], f_user[256], ha1[256], f_domain[256], user[100], nonce[100],
3739       uri[MAX_REQUEST_SIZE], cnonce[100], resp[100], qop[100], nc[100];
39773740
3978   dst[j++] = b64[a >> 2];
3979   dst[j++] = b64[((a & 3) << 4) | (b >> 4)];
3980   if (i + 1 < src_len) {
3981      dst[j++] = b64[(b & 15) << 2 | (c >> 6)];
3982   }
3983   if (i + 2 < src_len) {
3984      dst[j++] = b64[c & 63];
3985   }
3986   }
3987   while (j % 4 != 0) {
3988   dst[j++] = '=';
3989   }
3990   dst[j++] = '\0';
3991}
3741  if (c == NULL || fp == NULL) return 0;
3742  if ((hdr = mg_get_header(c, "Authorization")) == NULL ||
3743      mg_strncasecmp(hdr, "Digest ", 7) != 0) return 0;
3744  if (!mg_parse_header(hdr, "username", user, sizeof(user))) return 0;
3745  if (!mg_parse_header(hdr, "cnonce", cnonce, sizeof(cnonce))) return 0;
3746  if (!mg_parse_header(hdr, "response", resp, sizeof(resp))) return 0;
3747  if (!mg_parse_header(hdr, "uri", uri, sizeof(uri))) return 0;
3748  if (!mg_parse_header(hdr, "qop", qop, sizeof(qop))) return 0;
3749  if (!mg_parse_header(hdr, "nc", nc, sizeof(nc))) return 0;
3750  if (!mg_parse_header(hdr, "nonce", nonce, sizeof(nonce))) return 0;
39923751
3993static void send_websocket_handshake(struct mg_connection *conn) {
3994   static const char *magic = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
3995   char buf[100], sha[20], b64_sha[sizeof(sha) * 2];
3996   SHA1_CTX sha_ctx;
3997
3998   mg_snprintf(conn, buf, sizeof(buf), "%s%s",
3999            mg_get_header(conn, "Sec-WebSocket-Key"), magic);
4000   SHA1Init(&sha_ctx);
4001   SHA1Update(&sha_ctx, (unsigned char *) buf, strlen(buf));
4002   SHA1Final((unsigned char *) sha, &sha_ctx);
4003   base64_encode((unsigned char *) sha, sizeof(sha), b64_sha);
4004   mg_printf(conn, "%s%s%s",
4005         "HTTP/1.1 101 Switching Protocols\r\n"
4006         "Upgrade: websocket\r\n"
4007         "Connection: Upgrade\r\n"
4008         "Sec-WebSocket-Accept: ", b64_sha, "\r\n\r\n");
3752  while (fgets(line, sizeof(line), fp) != NULL) {
3753    if (sscanf(line, "%[^:]:%[^:]:%s", f_user, f_domain, ha1) == 3 &&
3754        !strcmp(user, f_user) &&
3755        // NOTE(lsm): due to a bug in MSIE, we do not compare URIs
3756        !strcmp(conn->server->config_options[AUTH_DOMAIN], f_domain))
3757      return check_password(c->request_method, ha1, uri,
3758                            nonce, nc, cnonce, qop, resp);
3759  }
3760  return MG_FALSE;
40093761}
40103762
4011static void read_websocket(struct mg_connection *conn) {
4012   // Pointer to the beginning of the portion of the incoming websocket message
4013   // queue. The original websocket upgrade request is never removed,
4014   // so the queue begins after it.
4015   unsigned char *buf = (unsigned char *) conn->buf + conn->request_len;
4016   int bits, n, stop = 0;
4017   size_t i, len, mask_len = 0, data_len = 0, header_len, body_len;
4018   // data points to the place where the message is stored when passed to the
4019   // websocket_data callback. This is either mem on the stack,
4020   // or a dynamically allocated buffer if it is too large.
4021   char mem[4 * 1024], mask[4], *data;
40223763
4023   assert(conn->content_len == 0);
3764// Return 1 if request is authorised, 0 otherwise.
3765static int is_authorized(struct connection *conn, const char *path) {
3766  FILE *fp;
3767  int authorized = MG_TRUE;
40243768
4025   // Loop continuously, reading messages from the socket, invoking the callback,
4026   // and waiting repeatedly until an error occurs.
4027   while (!stop) {
4028   header_len = 0;
4029   // body_len is the length of the entire queue in bytes
4030   // len is the length of the current message
4031   // data_len is the length of the current message's data payload
4032   // header_len is the length of the current message's header
4033   if ((body_len = conn->data_len - conn->request_len) >= 2) {
4034      len = buf[1] & 127;
4035      mask_len = buf[1] & 128 ? 4 : 0;
4036      if (len < 126 && body_len >= mask_len) {
4037      data_len = len;
4038      header_len = 2 + mask_len;
4039      } else if (len == 126 && body_len >= 4 + mask_len) {
4040      header_len = 4 + mask_len;
4041      data_len = ((((int) buf[2]) << 8) + buf[3]);
4042      } else if (body_len >= 10 + mask_len) {
4043      header_len = 10 + mask_len;
4044      data_len = (((uint64_t) htonl(* (uint32_t *) &buf[2])) << 32) +
4045         htonl(* (uint32_t *) &buf[6]);
4046      }
4047   }
3769  if ((fp = open_auth_file(conn, path)) != NULL) {
3770    authorized = mg_authorize_digest(&conn->mg_conn, fp);
3771    fclose(fp);
3772  }
40483773
4049   // Data layout is as follows:
4050   //  conn->buf               buf
4051   //     v                     v              frame1           | frame2
4052   //     |---------------------|----------------|--------------|-------
4053   //     |                     |<--header_len-->|<--data_len-->|
4054   //     |<-conn->request_len->|<-----body_len----------->|
4055   //     |<-------------------conn->data_len------------->|
3774  return authorized;
3775}
40563776
4057   if (header_len > 0) {
4058      // Allocate space to hold websocket payload
4059      data = mem;
4060      if (data_len > sizeof(mem) && (data = (char*)malloc(data_len)) == NULL) {
4061      // Allocation failed, exit the loop and then close the connection
4062      // TODO: notify user about the failure
4063      break;
4064      }
3777static int is_authorized_for_dav(struct connection *conn) {
3778  const char *auth_file = conn->server->config_options[DAV_AUTH_FILE];
3779  const char *method = conn->mg_conn.request_method;
3780  FILE *fp;
3781  int authorized = MG_FALSE;
40653782
4066      // Save mask and bits, otherwise it may be clobbered by memmove below
4067      bits = buf[0];
4068      memcpy(mask, buf + header_len - mask_len, mask_len);
3783  // If dav_auth_file is not set, allow non-authorized PROPFIND
3784  if (method != NULL && !strcmp(method, "PROPFIND") && auth_file == NULL) {
3785    authorized = MG_TRUE;
3786  } else if (auth_file != NULL && (fp = fopen(auth_file, "r")) != NULL) {
3787    authorized = mg_authorize_digest(&conn->mg_conn, fp);
3788    fclose(fp);
3789  }
40693790
4070      // Read frame payload into the allocated buffer.
4071      assert(body_len >= header_len);
4072      if (data_len + header_len > body_len) {
4073      len = body_len - header_len;
4074      memcpy(data, buf + header_len, len);
4075      // TODO: handle pull error
4076      pull_all(NULL, conn, data + len, data_len - len);
4077      conn->data_len = conn->request_len;
4078      } else {
4079      len = data_len + header_len;
4080      memcpy(data, buf + header_len, data_len);
4081      memmove(buf, buf + len, body_len - len);
4082      conn->data_len -= len;
4083      }
3791  return authorized;
3792}
40843793
4085      // Apply mask if necessary
4086      if (mask_len > 0) {
4087      for (i = 0; i < data_len; i++) {
4088         data[i] ^= mask[i % 4];
4089      }
4090      }
4091
4092      // Exit the loop if callback signalled to exit,
4093      // or "connection close" opcode received.
4094      if ((conn->ctx->callbacks.websocket_data != NULL &&
4095         !conn->ctx->callbacks.websocket_data(conn, bits, data, data_len)) ||
4096         (bits & 0xf) == 8) {  // Opcode == 8, connection close
4097      stop = 1;
4098      }
4099
4100      if (data != mem) {
4101      free(data);
4102      }
4103      // Not breaking the loop, process next websocket frame.
4104   } else {
4105      // Buffering websocket request
4106      if ((n = pull(NULL, conn, conn->buf + conn->data_len,
4107               conn->buf_size - conn->data_len)) <= 0) {
4108      break;
4109      }
4110      conn->data_len += n;
4111   }
4112   }
3794static int is_dav_request(const struct connection *conn) {
3795  const char *s = conn->mg_conn.request_method;
3796  return !strcmp(s, "PUT") || !strcmp(s, "DELETE") ||
3797    !strcmp(s, "MKCOL") || !strcmp(s, "PROPFIND");
41133798}
3799#endif // MONGOOSE_NO_AUTH
41143800
4115int mg_websocket_write(struct mg_connection* conn, int opcode,
4116                  const char *data, size_t data_len) {
4117   unsigned char *copy;
4118   size_t copy_len = 0;
4119   int retval = -1;
3801static int parse_header(const char *str, int str_len, const char *var_name,
3802                        char *buf, size_t buf_size) {
3803  int ch = ' ', len = 0, n = strlen(var_name);
3804  const char *p, *end = str + str_len, *s = NULL;
41203805
4121   if ((copy = (unsigned char *) malloc(data_len + 10)) == NULL) {
4122      return -1;
4123   }
3806  if (buf != NULL && buf_size > 0) buf[0] = '\0';
41243807
4125   copy[0] = 0x80 + (opcode & 0x0f);
3808  // Find where variable starts
3809  for (s = str; s != NULL && s + n < end; s++) {
3810    if ((s == str || s[-1] == ' ' || s[-1] == ',') && s[n] == '=' &&
3811        !memcmp(s, var_name, n)) break;
3812  }
41263813
4127   // Frame format: http://tools.ietf.org/html/rfc6455#section-5.2
4128   if (data_len < 126) {
4129      // Inline 7-bit length field
4130      copy[1] = data_len;
4131      memcpy(copy + 2, data, data_len);
4132      copy_len = 2 + data_len;
4133   } else if (data_len <= 0xFFFF) {
4134      // 16-bit length field
4135      copy[1] = 126;
4136      * (uint16_t *) (copy + 2) = htons(data_len);
4137      memcpy(copy + 4, data, data_len);
4138      copy_len = 4 + data_len;
4139   } else {
4140      // 64-bit length field
4141      copy[1] = 127;
4142      * (uint32_t *) (copy + 2) = htonl((uint64_t) data_len >> 32);
4143      * (uint32_t *) (copy + 6) = htonl(data_len & 0xffffffff);
4144      memcpy(copy + 10, data, data_len);
4145      copy_len = 10 + data_len;
4146   }
3814  if (s != NULL && &s[n + 1] < end) {
3815    s += n + 1;
3816    if (*s == '"' || *s == '\'') ch = *s++;
3817    p = s;
3818    while (p < end && p[0] != ch && p[0] != ',' && len < (int) buf_size) {
3819      if (p[0] == '\\' && p[1] == ch) p++;
3820      buf[len++] = *p++;
3821    }
3822    if (len >= (int) buf_size || (ch != ' ' && *p != ch)) {
3823      len = 0;
3824    } else {
3825      if (len > 0 && s[len - 1] == ',') len--;
3826      if (len > 0 && s[len - 1] == ';') len--;
3827      buf[len] = '\0';
3828    }
3829  }
41473830
4148   // Not thread safe
4149   if (copy_len > 0) {
4150      retval = mg_write(conn, copy, copy_len);
4151   }
4152   free(copy);
3831  return len;
3832}
41533833
4154   return retval;
3834int mg_parse_header(const char *s, const char *var_name, char *buf,
3835                    size_t buf_size) {
3836  return parse_header(s, s == NULL ? 0 : strlen(s), var_name, buf, buf_size);
41553837}
41563838
4157static void handle_websocket_request(struct mg_connection *conn) {
4158   const char *version = mg_get_header(conn, "Sec-WebSocket-Version");
4159   if (version == NULL || strcmp(version, "13") != 0) {
4160   send_http_error(conn, 426, "Upgrade Required", "%s", "Upgrade Required");
4161   } else if (conn->ctx->callbacks.websocket_connect != NULL &&
4162            conn->ctx->callbacks.websocket_connect(conn) != 0) {
4163   // Callback has returned non-zero, do not proceed with handshake
4164   } else {
4165   send_websocket_handshake(conn);
4166   if (conn->ctx->callbacks.websocket_ready != NULL) {
4167      conn->ctx->callbacks.websocket_ready(conn);
4168   }
4169   read_websocket(conn);
4170   }
3839#ifndef MONGOOSE_NO_SSI
3840static void send_ssi_file(struct mg_connection *, const char *, FILE *, int);
3841
3842static void send_file_data(struct mg_connection *conn, FILE *fp) {
3843  char buf[IOBUF_SIZE];
3844  int n;
3845  while ((n = fread(buf, 1, sizeof(buf), fp)) > 0) {
3846    mg_write(conn, buf, n);
3847  }
41713848}
41723849
4173static int is_websocket_request(const struct mg_connection *conn) {
4174   const char *host, *upgrade, *connection, *version, *key;
3850static void do_ssi_include(struct mg_connection *conn, const char *ssi,
3851                           char *tag, int include_level) {
3852  char file_name[IOBUF_SIZE], path[MAX_PATH_SIZE], *p;
3853  char **opts = (MG_CONN_2_CONN(conn))->server->config_options;
3854  FILE *fp;
41753855
4176   host = mg_get_header(conn, "Host");
4177   upgrade = mg_get_header(conn, "Upgrade");
4178   connection = mg_get_header(conn, "Connection");
4179   key = mg_get_header(conn, "Sec-WebSocket-Key");
4180   version = mg_get_header(conn, "Sec-WebSocket-Version");
3856  // sscanf() is safe here, since send_ssi_file() also uses buffer
3857  // of size MG_BUF_LEN to get the tag. So strlen(tag) is always < MG_BUF_LEN.
3858  if (sscanf(tag, " virtual=\"%[^\"]\"", file_name) == 1) {
3859    // File name is relative to the webserver root
3860    mg_snprintf(path, sizeof(path), "%s%c%s",
3861                opts[DOCUMENT_ROOT], '/', file_name);
3862  } else if (sscanf(tag, " abspath=\"%[^\"]\"", file_name) == 1) {
3863    // File name is relative to the webserver working directory
3864    // or it is absolute system path
3865    mg_snprintf(path, sizeof(path), "%s", file_name);
3866  } else if (sscanf(tag, " file=\"%[^\"]\"", file_name) == 1 ||
3867             sscanf(tag, " \"%[^\"]\"", file_name) == 1) {
3868    // File name is relative to the currect document
3869    mg_snprintf(path, sizeof(path), "%s", ssi);
3870    if ((p = strrchr(path, '/')) != NULL) {
3871      p[1] = '\0';
3872    }
3873    mg_snprintf(path + strlen(path), sizeof(path) - strlen(path), "%s",
3874                file_name);
3875  } else {
3876    mg_printf(conn, "Bad SSI #include: [%s]", tag);
3877    return;
3878  }
41813879
4182   return host != NULL && upgrade != NULL && connection != NULL &&
4183   key != NULL && version != NULL &&
4184   mg_strcasestr(upgrade, "websocket") != NULL &&
4185   mg_strcasestr(connection, "Upgrade") != NULL;
3880  if ((fp = fopen(path, "rb")) == NULL) {
3881    mg_printf(conn, "Cannot open SSI #include: [%s]: fopen(%s): %s",
3882              tag, path, strerror(errno));
3883  } else {
3884    ns_set_close_on_exec(fileno(fp));
3885    if (mg_match_prefix(opts[SSI_PATTERN], strlen(opts[SSI_PATTERN]),
3886        path) > 0) {
3887      send_ssi_file(conn, path, fp, include_level + 1);
3888    } else {
3889      send_file_data(conn, fp);
3890    }
3891    fclose(fp);
3892  }
41863893}
4187#endif // !USE_WEBSOCKET
41883894
4189static int isbyte(int n) {
4190   return n >= 0 && n <= 255;
3895#ifndef MONGOOSE_NO_POPEN
3896static void do_ssi_exec(struct mg_connection *conn, char *tag) {
3897  char cmd[IOBUF_SIZE];
3898  FILE *fp;
3899
3900  if (sscanf(tag, " \"%[^\"]\"", cmd) != 1) {
3901    mg_printf(conn, "Bad SSI #exec: [%s]", tag);
3902  } else if ((fp = popen(cmd, "r")) == NULL) {
3903    mg_printf(conn, "Cannot SSI #exec: [%s]: %s", cmd, strerror(errno));
3904  } else {
3905    send_file_data(conn, fp);
3906    pclose(fp);
3907  }
41913908}
3909#endif // !MONGOOSE_NO_POPEN
41923910
4193static int parse_net(const char *spec, uint32_t *net, uint32_t *mask) {
4194   int n, a, b, c, d, slash = 32, len = 0;
3911static void send_ssi_file(struct mg_connection *conn, const char *path,
3912                          FILE *fp, int include_level) {
3913  char buf[IOBUF_SIZE];
3914  int ch, offset, len, in_ssi_tag;
41953915
4196   if ((sscanf(spec, "%d.%d.%d.%d/%d%n", &a, &b, &c, &d, &slash, &n) == 5 ||
4197      sscanf(spec, "%d.%d.%d.%d%n", &a, &b, &c, &d, &n) == 4) &&
4198      isbyte(a) && isbyte(b) && isbyte(c) && isbyte(d) &&
4199      slash >= 0 && slash < 33) {
4200   len = n;
4201   *net = ((uint32_t)a << 24) | ((uint32_t)b << 16) | ((uint32_t)c << 8) | d;
4202   *mask = slash ? 0xffffffffU << (32 - slash) : 0;
4203   }
3916  if (include_level > 10) {
3917    mg_printf(conn, "SSI #include level is too deep (%s)", path);
3918    return;
3919  }
42043920
4205   return len;
3921  in_ssi_tag = len = offset = 0;
3922  while ((ch = fgetc(fp)) != EOF) {
3923    if (in_ssi_tag && ch == '>') {
3924      in_ssi_tag = 0;
3925      buf[len++] = (char) ch;
3926      buf[len] = '\0';
3927      assert(len <= (int) sizeof(buf));
3928      if (len < 6 || memcmp(buf, "<!--#", 5) != 0) {
3929        // Not an SSI tag, pass it
3930        (void) mg_write(conn, buf, (size_t) len);
3931      } else {
3932        if (!memcmp(buf + 5, "include", 7)) {
3933          do_ssi_include(conn, path, buf + 12, include_level);
3934#if !defined(MONGOOSE_NO_POPEN)
3935        } else if (!memcmp(buf + 5, "exec", 4)) {
3936          do_ssi_exec(conn, buf + 9);
3937#endif // !NO_POPEN
3938        } else {
3939          mg_printf(conn, "%s: unknown SSI " "command: \"%s\"", path, buf);
3940        }
3941      }
3942      len = 0;
3943    } else if (in_ssi_tag) {
3944      if (len == 5 && memcmp(buf, "<!--#", 5) != 0) {
3945        // Not an SSI tag
3946        in_ssi_tag = 0;
3947      } else if (len == (int) sizeof(buf) - 2) {
3948        mg_printf(conn, "%s: SSI tag is too large", path);
3949        len = 0;
3950      }
3951      buf[len++] = ch & 0xff;
3952    } else if (ch == '<') {
3953      in_ssi_tag = 1;
3954      if (len > 0) {
3955        mg_write(conn, buf, (size_t) len);
3956      }
3957      len = 0;
3958      buf[len++] = ch & 0xff;
3959    } else {
3960      buf[len++] = ch & 0xff;
3961      if (len == (int) sizeof(buf)) {
3962        mg_write(conn, buf, (size_t) len);
3963        len = 0;
3964      }
3965    }
3966  }
3967
3968  // Send the rest of buffered data
3969  if (len > 0) {
3970    mg_write(conn, buf, (size_t) len);
3971  }
42063972}
42073973
4208static int set_throttle(const char *spec, uint32_t remote_ip, const char *uri) {
4209   int throttle = 0;
4210   struct vec vec, val;
4211   uint32_t net, mask;
4212   char mult;
4213   double v;
3974static void handle_ssi_request(struct connection *conn, const char *path) {
3975  FILE *fp;
3976  struct vec mime_vec;
42143977
4215   while ((spec = next_option(spec, &vec, &val)) != NULL) {
4216   mult = ',';
4217   if (sscanf(val.ptr, "%lf%c", &v, &mult) < 1 || v < 0 ||
4218      (lowercase(&mult) != 'k' && lowercase(&mult) != 'm' && mult != ',')) {
4219      continue;
4220   }
4221   v *= lowercase(&mult) == 'k' ? 1024 : lowercase(&mult) == 'm' ? 1048576 : 1;
4222   if (vec.len == 1 && vec.ptr[0] == '*') {
4223      throttle = (int) v;
4224   } else if (parse_net(vec.ptr, &net, &mask) > 0) {
4225      if ((remote_ip & mask) == net) {
4226      throttle = (int) v;
4227      }
4228   } else if (match_prefix(vec.ptr, vec.len, uri) > 0) {
4229      throttle = (int) v;
4230   }
4231   }
4232
4233   return throttle;
3978  if ((fp = fopen(path, "rb")) == NULL) {
3979    send_http_error(conn, 500, "fopen(%s): %s", path, strerror(errno));
3980  } else {
3981    ns_set_close_on_exec(fileno(fp));
3982    get_mime_type(conn->server, path, &mime_vec);
3983    conn->mg_conn.status_code = 200;
3984    mg_printf(&conn->mg_conn,
3985              "HTTP/1.1 %d OK\r\n"
3986              "Content-Type: %.*s\r\n"
3987              "Connection: close\r\n\r\n",
3988              conn->mg_conn.status_code, (int) mime_vec.len, mime_vec.ptr);
3989    send_ssi_file(&conn->mg_conn, path, fp, 0);
3990    fclose(fp);
3991    close_local_endpoint(conn);
3992  }
42343993}
3994#endif
42353995
4236static uint32_t get_remote_ip(const struct mg_connection *conn) {
4237   return ntohl(* (uint32_t *) &conn->client.rsa.sin.sin_addr);
4238}
3996static int parse_url(const char *url, char *proto, size_t plen,
3997                     char *host, size_t hlen, unsigned short *port) {
3998  int n;
3999  char fmt1[100], fmt2[100], fmt3[100];
42394000
4240#ifdef USE_LUA
4241#include "mod_lua.c"
4242#endif // USE_LUA
4001  *port = 80;
4002  proto[0] = host[0] = '\0';
42434003
4244int mg_upload(struct mg_connection *conn, const char *destination_dir) {
4245   const char *content_type_header, *boundary_start;
4246   char buf[MG_BUF_LEN], path[PATH_MAX], fname[1024], boundary[100], *s;
4247   FILE *fp;
4248   int bl, n, i, j, headers_len, boundary_len, eof,
4249      len = 0, num_uploaded_files = 0;
4004  snprintf(fmt1, sizeof(fmt1), "%%%zu[a-z]://%%%zu[^: ]:%%hu%%n", plen, hlen);
4005  snprintf(fmt2, sizeof(fmt2), "%%%zu[a-z]://%%%zu[^/ ]%%n", plen, hlen);
4006  snprintf(fmt3, sizeof(fmt3), "%%%zu[^: ]:%%hu%%n", hlen);
42504007
4251   // Request looks like this:
4252   //
4253   // POST /upload HTTP/1.1
4254   // Host: 127.0.0.1:8080
4255   // Content-Length: 244894
4256   // Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryRVr
4257   //
4258   // ------WebKitFormBoundaryRVr
4259   // Content-Disposition: form-data; name="file"; filename="accum.png"
4260   // Content-Type: image/png
4261   //
4262   //  <89>PNG
4263   //  <PNG DATA>
4264   // ------WebKitFormBoundaryRVr
4008  if (sscanf(url, fmt1, proto, host, port, &n) == 3 ||
4009      sscanf(url, fmt2, proto, host, &n) == 2) {
4010    return n;
4011  } else if (sscanf(url, fmt3, host, port, &n) == 2) {
4012    proto[0] = '\0';
4013    return n;
4014  }
42654015
4266   // Extract boundary string from the Content-Type header
4267   if ((content_type_header = mg_get_header(conn, "Content-Type")) == NULL ||
4268      (boundary_start = mg_strcasestr(content_type_header,
4269                              "boundary=")) == NULL ||
4270      (sscanf(boundary_start, "boundary=\"%99[^\"]\"", boundary) == 0 &&
4271      sscanf(boundary_start, "boundary=%99s", boundary) == 0) ||
4272      boundary[0] == '\0') {
4273   return num_uploaded_files;
4274   }
4016  return 0;
4017}
42754018
4276   boundary_len = strlen(boundary);
4277   bl = boundary_len + 4;  // \r\n--<boundary>
4278   for (;;) {
4279   // Pull in headers
4280   assert(len >= 0 && len <= (int) sizeof(buf));
4281   while ((n = mg_read(conn, buf + len, sizeof(buf) - len)) > 0) {
4282      len += n;
4283   }
4284   if ((headers_len = get_request_len(buf, len)) <= 0) {
4285      break;
4286   }
4019static void proxy_request(struct ns_connection *pc, struct mg_connection *c) {
4020  int i, sent_close_header = 0;
42874021
4288   // Fetch file name.
4289   fname[0] = '\0';
4290   for (i = j = 0; i < headers_len; i++) {
4291      if (buf[i] == '\r' && buf[i + 1] == '\n') {
4292      buf[i] = buf[i + 1] = '\0';
4293      // TODO(lsm): don't expect filename to be the 3rd field,
4294      // parse the header properly instead.
4295      sscanf(&buf[j], "Content-Disposition: %*s %*s filename=\"%1023[^\"]",
4296            fname);
4297      j = i + 2;
4298      }
4299   }
4022  ns_printf(pc, "%s %s HTTP/%s\r\n", c->request_method, c->uri,
4023            c->http_version);
4024  for (i = 0; i < c->num_headers; i++) {
4025    if (mg_strcasecmp(c->http_headers[i].name, "Connection") == 0) {
4026      // Force connection close, cause we don't parse proxy replies
4027      // therefore we don't know message boundaries
4028      //ns_printf(pc, "%s: %s\r\n", "Connection", "close");
4029      sent_close_header = 1;
4030    //} else {
4031    }
4032      ns_printf(pc, "%s: %s\r\n", c->http_headers[i].name,
4033                c->http_headers[i].value);
4034  }
4035  if (!sent_close_header) {
4036    ns_printf(pc, "%s: %s\r\n", "Connection", "close");
4037  }
4038  ns_printf(pc, "%s", "\r\n");
4039  ns_send(pc, c->content, c->content_len);
43004040
4301   // Give up if the headers are not what we expect
4302   if (fname[0] == '\0') {
4303      break;
4304   }
4041}
43054042
4306   // Move data to the beginning of the buffer
4307   assert(len >= headers_len);
4308   memmove(buf, &buf[headers_len], len - headers_len);
4309   len -= headers_len;
4043static void proxify_connection(struct connection *conn) {
4044  char proto[10], host[500], cert[500];
4045  unsigned short port = 80;
4046  struct mg_connection *c = &conn->mg_conn;
4047  struct ns_server *server = &conn->server->ns_server;
4048  struct ns_connection *pc;
4049  int n, use_ssl;
43104050
4311   // We open the file with exclusive lock held. This guarantee us
4312   // there is no other thread can save into the same file simultaneously.
4313   fp = NULL;
4314   // Construct destination file name. Do not allow paths to have slashes.
4315   if ((s = strrchr(fname, '/')) == NULL &&
4316      (s = strrchr(fname, '\\')) == NULL) {
4317         s = fname;
4318   }
4051  proto[0] = host[0] = cert[0] = '\0';
4052  n = parse_url(c->uri, proto, sizeof(proto), host, sizeof(host), &port);
43194053
4320   // Open file in binary mode. TODO: set an exclusive lock.
4321   snprintf(path, sizeof(path), "%s/%s", destination_dir, s);
4322   if ((fp = fopen(path, "wb")) == NULL) {
4323      break;
4324   }
4054#ifdef NS_ENABLE_SSL
4055  // Find out whether we should be in the MITM mode
4056  {
4057    const char *certs = conn->server->config_options[SSL_MITM_CERTS];
4058    int host_len = strlen(host);
4059    struct vec a, b;
43254060
4326   // Read POST data, write into file until boundary is found.
4327   eof = n = 0;
4328   do {
4329      len += n;
4330      for (i = 0; i < len - bl; i++) {
4331      if (!memcmp(&buf[i], "\r\n--", 4) &&
4332         !memcmp(&buf[i + 4], boundary, boundary_len)) {
4333         // Found boundary, that's the end of file data.
4334         fwrite(buf, 1, i, fp);
4335         eof = 1;
4336         memmove(buf, &buf[i + bl], len - (i + bl));
4337         len -= i + bl;
4338         break;
4339      }
4340      }
4341      if (!eof && len > bl) {
4342      fwrite(buf, 1, len - bl, fp);
4343      memmove(buf, &buf[len - bl], bl);
4344      len = bl;
4345      }
4346   } while (!eof && (n = mg_read(conn, buf + len, sizeof(buf) - len)) > 0);
4347   fclose(fp);
4348   if (eof) {
4349      num_uploaded_files++;
4350      if (conn->ctx->callbacks.upload != NULL) {
4351      conn->ctx->callbacks.upload(conn, path);
4352      }
4353   }
4354   }
4061    while ((certs = next_option(certs, &a, &b)) != NULL) {
4062      if (a.len == host_len && mg_strncasecmp(a.ptr, host, a.len) == 0) {
4063        snprintf(cert, sizeof(cert), "%.*s", b.len, b.ptr);
4064        break;
4065      }
4066    }
4067  }
4068#endif
43554069
4356   return num_uploaded_files;
4357}
4070  use_ssl = port != 80 && cert[0] != '\0';
43584071
4359static int is_put_or_delete_request(const struct mg_connection *conn) {
4360   const char *s = conn->request_info.request_method;
4361   return s != NULL && (!strcmp(s, "PUT") || !strcmp(s, "DELETE") || !strcmp(s, "MKCOL"));
4362}
4072  if (n > 0 &&
4073      (pc = ns_connect(server, host, port, use_ssl, conn)) != NULL) {
4074    // Interlink two connections
4075    pc->flags |= MG_PROXY_CONN;
4076    conn->endpoint_type = EP_PROXY;
4077    conn->endpoint.nc = pc;
4078    DBG(("%p [%s] -> %p %d", conn, c->uri, pc, use_ssl));
43634079
4364static int get_first_ssl_listener_index(const struct mg_context *ctx) {
4365   int i, index = -1;
4366   for (i = 0; index == -1 && i < ctx->num_listening_sockets; i++) {
4367   index = ctx->listening_sockets[i].is_ssl ? i : -1;
4368   }
4369   return index;
4370}
4080    if (strcmp(c->request_method, "CONNECT") == 0) {
4081      // For CONNECT request, reply with 200 OK. Tunnel is established.
4082      mg_printf(c, "%s", "HTTP/1.1 200 OK\r\n\r\n");
4083      conn->request_len = 0;
4084      free(conn->request);
4085      conn->request = NULL;
4086#ifdef NS_ENABLE_SSL
4087      if (use_ssl) {
4088        SSL_CTX *ctx;
43714089
4372static void redirect_to_https_port(struct mg_connection *conn, int ssl_index) {
4373   char host[1025];
4374   const char *host_header;
4090        DBG(("%s", "Triggering MITM mode: terminating SSL connection"));
4091        SSL_library_init();
4092        ctx = SSL_CTX_new(SSLv23_server_method());
43754093
4376   if ((host_header = mg_get_header(conn, "Host")) == NULL ||
4377      sscanf(host_header, "%1024[^:]", host) == 0) {
4378   // Cannot get host from the Host: header. Fallback to our IP address.
4379   sockaddr_to_string(host, sizeof(host), &conn->client.lsa);
4380   }
4094        if (ctx == NULL) {
4095          pc->flags |= NSF_CLOSE_IMMEDIATELY;
4096        } else {
4097          SSL_CTX_use_certificate_file(ctx, cert, 1);
4098          SSL_CTX_use_PrivateKey_file(ctx, cert, 1);
4099          SSL_CTX_use_certificate_chain_file(ctx, cert);
43814100
4382   mg_printf(conn, "HTTP/1.1 302 Found\r\nLocation: https://%s:%d%s\r\n\r\n",
4383         host, (int) ntohs(conn->ctx->listening_sockets[ssl_index].
4384                        lsa.sin.sin_port), conn->request_info.uri);
4101          // When clear-text reply is pushed to client, switch to SSL mode.
4102          n = send(conn->ns_conn->sock, conn->ns_conn->send_iobuf.buf,
4103                   conn->ns_conn->send_iobuf.len, 0);
4104          DBG(("%p %lu %d SEND", c, conn->ns_conn->send_iobuf.len, n));
4105          conn->ns_conn->send_iobuf.len = 0;
4106          if ((conn->ns_conn->ssl = SSL_new(ctx)) != NULL) {
4107            //SSL_set_fd((SSL *) c->connection_param, conn->ns_conn->sock);
4108            SSL_set_fd(conn->ns_conn->ssl, conn->ns_conn->sock);
4109          }
4110          SSL_CTX_free(ctx);
4111        }
4112      }
4113#endif
4114    } else {
4115      // For other methods, forward the request to the target host.
4116      c->uri += n;
4117      proxy_request(pc, c);
4118    }
4119  } else {
4120    conn->ns_conn->flags |= NSF_CLOSE_IMMEDIATELY;
4121  }
43854122}
43864123
4387// This is the heart of the Mongoose's logic.
4388// This function is called when the request is read, parsed and validated,
4389// and Mongoose must decide what action to take: serve a file, or
4390// a directory, or call embedded function, etcetera.
4391static void handle_request(struct mg_connection *conn) {
4392   struct mg_request_info *ri = &conn->request_info;
4393   char path[PATH_MAX];
4394   int uri_len, ssl_index;
4395   struct file file = STRUCT_FILE_INITIALIZER;
4396
4397   if ((conn->request_info.query_string = strchr(ri->uri, '?')) != NULL) {
4398   * ((char *) conn->request_info.query_string++) = '\0';
4399   }
4400   uri_len = (int) strlen(ri->uri);
4401   mg_url_decode(ri->uri, uri_len, (char *) ri->uri, uri_len + 1, 0);
4402   remove_double_dots_and_double_slashes((char *) ri->uri);
4403   convert_uri_to_file_name(conn, path, sizeof(path), &file);
4404   conn->throttle = set_throttle(conn->ctx->config[THROTTLE],
4405                        get_remote_ip(conn), ri->uri);
4406
4407   DEBUG_TRACE(("%s", ri->uri));
4408   // Perform redirect and auth checks before calling begin_request() handler.
4409   // Otherwise, begin_request() would need to perform auth checks and redirects.
4410   if (!conn->client.is_ssl && conn->client.ssl_redir &&
4411      (ssl_index = get_first_ssl_listener_index(conn->ctx)) > -1) {
4412   redirect_to_https_port(conn, ssl_index);
4413   } else if (!is_put_or_delete_request(conn) &&
4414            !check_authorization(conn, path)) {
4415   send_authorization_request(conn);
4416   } else if (conn->ctx->callbacks.begin_request != NULL &&
4417      conn->ctx->callbacks.begin_request(conn)) {
4418   // Do nothing, callback has served the request
4419#if defined(USE_WEBSOCKET)
4420   } else if (is_websocket_request(conn)) {
4421   handle_websocket_request(conn);
4124static void open_local_endpoint(struct connection *conn, int skip_user) {
4125#ifndef MONGOOSE_NO_FILESYSTEM
4126  file_stat_t st;
4127  char path[MAX_PATH_SIZE];
4128  int exists = 0, is_directory = 0;
4129#ifndef MONGOOSE_NO_CGI
4130  const char *cgi_pat = conn->server->config_options[CGI_PATTERN];
4131#else
4132  const char *cgi_pat = DEFAULT_CGI_PATTERN;
44224133#endif
4423   } else if (!strcmp(ri->request_method, "OPTIONS")) {
4424   send_options(conn);
4425   } else if (conn->ctx->config[DOCUMENT_ROOT] == NULL) {
4426   send_http_error(conn, 404, "Not Found", "Not Found");
4427   } else if (is_put_or_delete_request(conn) &&
4428            (is_authorized_for_put(conn) != 1)) {
4429   send_authorization_request(conn);
4430   } else if (!strcmp(ri->request_method, "PUT")) {
4431   put_file(conn, path);
4432   } else if (!strcmp(ri->request_method, "MKCOL")) {
4433   mkcol(conn, path);
4434   } else if (!strcmp(ri->request_method, "DELETE")) {
4435      struct de de;
4436      memset(&de.file, 0, sizeof(de.file));
4437      if(!mg_stat(conn, path, &de.file)) {
4438         send_http_error(conn, 404, "Not Found", "%s", "File not found");
4439      } else {
4440         if(de.file.modification_time) {
4441            if(de.file.is_directory) {
4442               remove_directory(conn, path);
4443               send_http_error(conn, 204, "No Content", "%s", "");
4444            } else if (mg_remove(path) == 0) {
4445               send_http_error(conn, 204, "No Content", "%s", "");
4446            } else {
4447               send_http_error(conn, 423, "Locked", "remove(%s): %s", path,
4448                     strerror(ERRNO));
4449            }
4450         }
4451         else {
4452            send_http_error(conn, 500, http_500_error, "remove(%s): %s", path,
4453               strerror(ERRNO));
4454         }
4455      }
4456   } else if ((file.membuf == NULL && file.modification_time == (time_t) 0) ||
4457            must_hide_file(conn, path)) {
4458   send_http_error(conn, 404, "Not Found", "%s", "File not found");
4459   } else if (file.is_directory && ri->uri[uri_len - 1] != '/') {
4460   mg_printf(conn, "HTTP/1.1 301 Moved Permanently\r\n"
4461            "Location: %s/\r\n\r\n", ri->uri);
4462   } else if (!strcmp(ri->request_method, "PROPFIND")) {
4463   handle_propfind(conn, path, &file);
4464   } else if (file.is_directory &&
4465            !substitute_index_file(conn, path, sizeof(path), &file)) {
4466   if (!mg_strcasecmp(conn->ctx->config[ENABLE_DIRECTORY_LISTING], "yes")) {
4467      handle_directory_request(conn, path);
4468   } else {
4469      send_http_error(conn, 403, "Directory Listing Denied",
4470         "Directory listing denied");
4471   }
4472#ifdef USE_LUA
4473   } else if (match_prefix("**.lp$", 6, path) > 0) {
4474   handle_lsp_request(conn, path, &file, NULL);
4134#ifndef MONGOOSE_NO_DIRECTORY_LISTING
4135  const char *dir_lst = conn->server->config_options[ENABLE_DIRECTORY_LISTING];
4136#else
4137  const char *dir_lst = "yes";
44754138#endif
4476#if !defined(NO_CGI)
4477   } else if (match_prefix(conn->ctx->config[CGI_EXTENSIONS],
4478                     strlen(conn->ctx->config[CGI_EXTENSIONS]),
4479                     path) > 0) {
4480   if (strcmp(ri->request_method, "POST") &&
4481      strcmp(ri->request_method, "HEAD") &&
4482      strcmp(ri->request_method, "GET")) {
4483      send_http_error(conn, 501, "Not Implemented",
4484                  "Method %s is not implemented", ri->request_method);
4485   } else {
4486      handle_cgi_request(conn, path);
4487   }
4488#endif // !NO_CGI
4489   } else if (match_prefix(conn->ctx->config[SSI_EXTENSIONS],
4490                     strlen(conn->ctx->config[SSI_EXTENSIONS]),
4491                     path) > 0) {
4492   handle_ssi_file_request(conn, path);
4493   } else if (is_not_modified(conn, &file)) {
4494   send_http_error(conn, 304, "Not Modified", "%s", "");
4495   } else {
4496   handle_file_request(conn, path, &file);
4497   }
4498}
4139#endif
44994140
4500static void close_all_listening_sockets(struct mg_context *ctx) {
4501   int i;
4502   for (i = 0; i < ctx->num_listening_sockets; i++) {
4503   closesocket(ctx->listening_sockets[i].sock);
4504   }
4505   free(ctx->listening_sockets);
4506}
4141  // If EP_USER was set in a prev call, reset it
4142  conn->endpoint_type = EP_NONE;
45074143
4508// Valid listening port specification is: [ip_address:]port[s]
4509// Examples: 80, 443s, 127.0.0.1:3128, 1.2.3.4:8080s
4510// TODO(lsm): add parsing of the IPv6 address
4511static int parse_port_string(const struct vec *vec, struct socket *so) {
4512   int a, b, c, d, port, len;
4144#ifndef MONGOOSE_NO_AUTH
4145  if (conn->server->event_handler && call_user(conn, MG_AUTH) == MG_FALSE) {
4146    mg_send_digest_auth_request(&conn->mg_conn);
4147    return;
4148  }
4149#endif
45134150
4514   // MacOS needs that. If we do not zero it, subsequent bind() will fail.
4515   // Also, all-zeroes in the socket address means binding to all addresses
4516   // for both IPv4 and IPv6 (INADDR_ANY and IN6ADDR_ANY_INIT).
4517   memset(so, 0, sizeof(*so));
4151  // Call URI handler if one is registered for this URI
4152  if (skip_user == 0 && conn->server->event_handler != NULL) {
4153    conn->endpoint_type = EP_USER;
4154#if MONGOOSE_POST_SIZE_LIMIT > 1
4155    {
4156      const char *cl = mg_get_header(&conn->mg_conn, "Content-Length");
4157      if ((strcmp(conn->mg_conn.request_method, "POST") == 0 ||
4158           strcmp(conn->mg_conn.request_method, "PUT") == 0) &&
4159          (cl == NULL || to64(cl) > MONGOOSE_POST_SIZE_LIMIT)) {
4160        send_http_error(conn, 500, "POST size > %zu",
4161                        (size_t) MONGOOSE_POST_SIZE_LIMIT);
4162      }
4163    }
4164#endif
4165    return;
4166  }
45184167
4519   if (sscanf(vec->ptr, "%d.%d.%d.%d:%d%n", &a, &b, &c, &d, &port, &len) == 5) {
4520   // Bind to a specific IPv4 address
4521   so->lsa.sin.sin_addr.s_addr = htonl((a << 24) | (b << 16) | (c << 8) | d);
4522   } else if (sscanf(vec->ptr, "%d%n", &port, &len) != 1 ||
4523            len <= 0 ||
4524            len > (int) vec->len ||
4525            port < 1 ||
4526            port > 65535 ||
4527            (vec->ptr[len] && vec->ptr[len] != 's' &&
4528            vec->ptr[len] != 'r' && vec->ptr[len] != ',')) {
4529   return 0;
4530   }
4168  if (strcmp(conn->mg_conn.request_method, "CONNECT") == 0 ||
4169      memcmp(conn->mg_conn.uri, "http", 4) == 0) {
4170    proxify_connection(conn);
4171    return;
4172  }
45314173
4532   so->is_ssl = vec->ptr[len] == 's';
4533   so->ssl_redir = vec->ptr[len] == 'r';
4534#if defined(USE_IPV6)
4535   so->lsa.sin6.sin6_family = AF_INET6;
4536   so->lsa.sin6.sin6_port = htons((uint16_t) port);
4174#ifdef MONGOOSE_NO_FILESYSTEM
4175  if (!strcmp(conn->mg_conn.request_method, "OPTIONS")) {
4176    send_options(conn);
4177  } else {
4178    send_http_error(conn, 404, NULL);
4179  }
45374180#else
4538   so->lsa.sin.sin_family = AF_INET;
4539   so->lsa.sin.sin_port = htons((uint16_t) port);
4540#endif
4181  exists = convert_uri_to_file_name(conn, path, sizeof(path), &st);
4182  is_directory = S_ISDIR(st.st_mode);
45414183
4542   return 1;
4543}
4544
4545static int set_ports_option(struct mg_context *ctx) {
4546   const char *list = ctx->config[LISTENING_PORTS];
4547   int on = 1, success = 1;
4548#if defined(USE_IPV6)
4549   int off = 0;
4184  if (!strcmp(conn->mg_conn.request_method, "OPTIONS")) {
4185    send_options(conn);
4186  } else if (conn->server->config_options[DOCUMENT_ROOT] == NULL) {
4187    send_http_error(conn, 404, NULL);
4188#ifndef MONGOOSE_NO_AUTH
4189  } else if ((!is_dav_request(conn) && !is_authorized(conn, path)) ||
4190             (is_dav_request(conn) && !is_authorized_for_dav(conn))) {
4191    mg_send_digest_auth_request(&conn->mg_conn);
4192    close_local_endpoint(conn);
45504193#endif
4551   struct vec vec;
4552   struct socket so, *ptr;
4553
4554   while (success && (list = next_option(list, &vec, NULL)) != NULL) {
4555   if (!parse_port_string(&vec, &so)) {
4556      cry(fc(ctx), "%s: %.*s: invalid port spec. Expecting list of: %s",
4557         __func__, (int) vec.len, vec.ptr, "[IP_ADDRESS:]PORT[s|p]");
4558      success = 0;
4559   } else if (so.is_ssl && ctx->ssl_ctx == NULL) {
4560      cry(fc(ctx), "Cannot add SSL socket, is -ssl_certificate option set?");
4561      success = 0;
4562   } else if ((so.sock = socket(so.lsa.sa.sa_family, SOCK_STREAM, 6)) ==
4563            INVALID_SOCKET ||
4564            // On Windows, SO_REUSEADDR is recommended only for
4565            // broadcast UDP sockets
4566            setsockopt(so.sock, SOL_SOCKET, SO_REUSEADDR,
4567                     (SETSOCKOPT_CAST) &on, sizeof(on)) != 0 ||
4568#if defined(USE_IPV6)
4569            setsockopt(so.sock, IPPROTO_IPV6, IPV6_V6ONLY, (SETSOCKOPT_CAST) &off,
4570                     sizeof(off)) != 0 ||
4194#ifndef MONGOOSE_NO_DAV
4195  } else if (!strcmp(conn->mg_conn.request_method, "PROPFIND")) {
4196    handle_propfind(conn, path, &st, exists);
4197  } else if (!strcmp(conn->mg_conn.request_method, "MKCOL")) {
4198    handle_mkcol(conn, path);
4199  } else if (!strcmp(conn->mg_conn.request_method, "DELETE")) {
4200    handle_delete(conn, path);
4201  } else if (!strcmp(conn->mg_conn.request_method, "PUT")) {
4202    handle_put(conn, path);
45714203#endif
4572            bind(so.sock, &so.lsa.sa, sizeof(so.lsa)) != 0 ||
4573            listen(so.sock, SOMAXCONN) != 0) {
4574      cry(fc(ctx), "%s: cannot bind to %.*s: %s", __func__,
4575         (int) vec.len, vec.ptr, strerror(ERRNO));
4576      closesocket(so.sock);
4577      success = 0;
4578   } else if ((ptr = (struct socket*)realloc(ctx->listening_sockets,
4579                        (ctx->num_listening_sockets + 1) *
4580                        sizeof(ctx->listening_sockets[0]))) == NULL) {
4581      closesocket(so.sock);
4582      success = 0;
4583   } else {
4584      set_close_on_exec(so.sock);
4585      ctx->listening_sockets = ptr;
4586      ctx->listening_sockets[ctx->num_listening_sockets] = so;
4587      ctx->num_listening_sockets++;
4588   }
4589   }
4204  } else if (!exists || must_hide_file(conn, path)) {
4205    send_http_error(conn, 404, NULL);
4206  } else if (is_directory &&
4207             conn->mg_conn.uri[strlen(conn->mg_conn.uri) - 1] != '/') {
4208    conn->mg_conn.status_code = 301;
4209    mg_printf(&conn->mg_conn, "HTTP/1.1 301 Moved Permanently\r\n"
4210              "Location: %s/\r\n\r\n", conn->mg_conn.uri);
4211    close_local_endpoint(conn);
4212  } else if (is_directory && !find_index_file(conn, path, sizeof(path), &st)) {
4213    if (!mg_strcasecmp(dir_lst, "yes")) {
4214#ifndef MONGOOSE_NO_DIRECTORY_LISTING
4215      send_directory_listing(conn, path);
4216#else
4217      send_http_error(conn, 501, NULL);
4218#endif
4219    } else {
4220      send_http_error(conn, 403, NULL);
4221    }
4222  } else if (mg_match_prefix(cgi_pat, strlen(cgi_pat), path) > 0) {
4223#if !defined(MONGOOSE_NO_CGI)
4224    open_cgi_endpoint(conn, path);
4225#else
4226    send_http_error(conn, 501, NULL);
4227#endif // !MONGOOSE_NO_CGI
4228#ifndef MONGOOSE_NO_SSI
4229  } else if (mg_match_prefix(conn->server->config_options[SSI_PATTERN],
4230                             strlen(conn->server->config_options[SSI_PATTERN]),
4231                             path) > 0) {
4232    handle_ssi_request(conn, path);
4233#endif
4234  } else if (is_not_modified(conn, &st)) {
4235    send_http_error(conn, 304, NULL);
4236  } else if ((conn->endpoint.fd = open(path, O_RDONLY | O_BINARY)) != -1) {
4237    // O_BINARY is required for Windows, otherwise in default text mode
4238    // two bytes \r\n will be read as one.
4239    open_file_endpoint(conn, path, &st);
4240  } else {
4241    send_http_error(conn, 404, NULL);
4242  }
4243#endif  // MONGOOSE_NO_FILESYSTEM
4244}
45904245
4591   if (!success) {
4592   close_all_listening_sockets(ctx);
4593   }
4246static void send_continue_if_expected(struct connection *conn) {
4247  static const char expect_response[] = "HTTP/1.1 100 Continue\r\n\r\n";
4248  const char *expect_hdr = mg_get_header(&conn->mg_conn, "Expect");
45944249
4595   return success;
4250  if (expect_hdr != NULL && !mg_strcasecmp(expect_hdr, "100-continue")) {
4251    ns_send(conn->ns_conn, expect_response, sizeof(expect_response) - 1);
4252  }
45964253}
45974254
4598static void log_header(const struct mg_connection *conn, const char *header,
4599                  FILE *fp) {
4600   const char *header_value;
4601
4602   if ((header_value = mg_get_header(conn, header)) == NULL) {
4603   (void) fprintf(fp, "%s", " -");
4604   } else {
4605   (void) fprintf(fp, " \"%s\"", header_value);
4606   }
4255// Conform to http://www.w3.org/Protocols/rfc2616/rfc2616-sec5.html#sec5.1.2
4256static int is_valid_uri(const char *uri) {
4257  unsigned short n;
4258  return uri[0] == '/' ||
4259    strcmp(uri, "*") == 0 ||            // OPTIONS method can use asterisk URI
4260    memcmp(uri, "http", 4) == 0 ||      // Naive check for the absolute URI
4261    sscanf(uri, "%*[^ :]:%hu", &n) > 0; // CONNECT method can use host:port
46074262}
46084263
4609static void log_access(const struct mg_connection *conn) {
4610   const struct mg_request_info *ri;
4611   FILE *fp;
4612   char date[64], src_addr[IP_ADDR_STR_LEN];
4264static void try_parse(struct connection *conn) {
4265  struct iobuf *io = &conn->ns_conn->recv_iobuf;
46134266
4614   fp = conn->ctx->config[ACCESS_LOG_FILE] == NULL ?  NULL :
4615   fopen(conn->ctx->config[ACCESS_LOG_FILE], "a+");
4267  if (conn->request_len == 0 &&
4268      (conn->request_len = get_request_len(io->buf, io->len)) > 0) {
4269    // If request is buffered in, remove it from the iobuf. This is because
4270    // iobuf could be reallocated, and pointers in parsed request could
4271    // become invalid.
4272    conn->request = (char *) malloc(conn->request_len);
4273    memcpy(conn->request, io->buf, conn->request_len);
4274    //DBG(("%p [%.*s]", conn, conn->request_len, conn->request));
4275    iobuf_remove(io, conn->request_len);
4276    conn->request_len = parse_http_message(conn->request, conn->request_len,
4277                                           &conn->mg_conn);
4278    if (conn->request_len > 0) {
4279      const char *cl_hdr = mg_get_header(&conn->mg_conn, "Content-Length");
4280      conn->cl = cl_hdr == NULL ? 0 : to64(cl_hdr);
4281      conn->mg_conn.content_len = (size_t) conn->cl;
4282    }
4283  }
4284}
46164285
4617   if (fp == NULL)
4618   return;
4286static void do_proxy(struct connection *conn) {
4287  if (conn->request_len == 0) {
4288    DBG(("%p parsing", conn));
4289    try_parse(conn);
4290    if (conn->request_len > 0 &&
4291        call_user(conn, MG_REQUEST) == MG_FALSE) {
4292      proxy_request(conn->endpoint.nc, &conn->mg_conn);
4293    } else if (conn->request_len < 0) {
4294      ns_forward(conn->ns_conn, conn->endpoint.nc);
4295    }
4296  } else {
4297    DBG(("%p forwarding", conn));
4298    ns_forward(conn->ns_conn, conn->endpoint.nc);
4299  }
4300}
46194301
4620   strftime(date, sizeof(date), "%d/%b/%Y:%H:%M:%S %z",
4621         localtime(&conn->birth_time));
4302static void on_recv_data(struct connection *conn) {
4303  struct iobuf *io = &conn->ns_conn->recv_iobuf;
46224304
4623   ri = &conn->request_info;
4624   flockfile(fp);
4305  if (conn->endpoint_type == EP_PROXY && conn->endpoint.nc != NULL) {
4306    do_proxy(conn);
4307    return;
4308  }
46254309
4626   sockaddr_to_string(src_addr, sizeof(src_addr), &conn->client.rsa);
4627   fprintf(fp, "%s - %s [%s] \"%s %s HTTP/%s\" %d %" INT64_FMT,
4628         src_addr, ri->remote_user == NULL ? "-" : ri->remote_user, date,
4629         ri->request_method ? ri->request_method : "-",
4630         ri->uri ? ri->uri : "-", ri->http_version,
4631         conn->status_code, conn->num_bytes_sent);
4632   log_header(conn, "Referer", fp);
4633   log_header(conn, "User-Agent", fp);
4634   fputc('\n', fp);
4635   fflush(fp);
4310  try_parse(conn);
4311  DBG(("%p %d %zu %d", conn, conn->request_len, io->len, conn->ns_conn->flags));
4312  if (conn->request_len < 0 ||
4313      (conn->request_len > 0 && !is_valid_uri(conn->mg_conn.uri))) {
4314    send_http_error(conn, 400, NULL);
4315  } else if (conn->request_len == 0 && io->len > MAX_REQUEST_SIZE) {
4316    send_http_error(conn, 413, NULL);
4317  } else if (conn->request_len > 0 &&
4318             strcmp(conn->mg_conn.http_version, "1.0") != 0 &&
4319             strcmp(conn->mg_conn.http_version, "1.1") != 0) {
4320    send_http_error(conn, 505, NULL);
4321  } else if (conn->request_len > 0 && conn->endpoint_type == EP_NONE) {
4322#ifndef MONGOOSE_NO_WEBSOCKET
4323    send_websocket_handshake_if_requested(&conn->mg_conn);
4324#endif
4325    send_continue_if_expected(conn);
4326    open_local_endpoint(conn, 0);
4327  }
46364328
4637   funlockfile(fp);
4638   fclose(fp);
4329#ifndef MONGOOSE_NO_CGI
4330  if (conn->endpoint_type == EP_CGI && conn->endpoint.nc != NULL) {
4331    ns_forward(conn->ns_conn, conn->endpoint.nc);
4332  }
4333#endif
4334  if (conn->endpoint_type == EP_USER) {
4335    call_request_handler_if_data_is_buffered(conn);
4336  }
4337#ifndef MONGOOSE_NO_DAV
4338  if (conn->endpoint_type == EP_PUT && io->len > 0) {
4339    forward_put_data(conn);
4340  }
4341#endif
46394342}
46404343
4641// Verify given socket address against the ACL.
4642// Return -1 if ACL is malformed, 0 if address is disallowed, 1 if allowed.
4643static int check_acl(struct mg_context *ctx, uint32_t remote_ip) {
4644   int allowed, flag;
4645   uint32_t net, mask;
4646   struct vec vec;
4647   const char *list = ctx->config[ACCESS_CONTROL_LIST];
4344static void call_http_client_handler(struct connection *conn) {
4345  //conn->mg_conn.status_code = code;
4346  // For responses without Content-Lengh, use the whole buffer
4347  if (conn->cl == 0) {
4348    conn->mg_conn.content_len = conn->ns_conn->recv_iobuf.len;
4349  }
4350  conn->mg_conn.content = conn->ns_conn->recv_iobuf.buf;
4351  if (call_user(conn, MG_REPLY) == MG_FALSE) {
4352    conn->ns_conn->flags |= NSF_CLOSE_IMMEDIATELY;
4353  }
4354  iobuf_remove(&conn->ns_conn->recv_iobuf, conn->mg_conn.content_len);
4355  conn->mg_conn.status_code = 0;
4356  conn->cl = conn->num_bytes_sent = conn->request_len = 0;
4357  free(conn->request);
4358  conn->request = NULL;
4359}
46484360
4649   // If any ACL is set, deny by default
4650   allowed = list == NULL ? '+' : '-';
4361static void process_response(struct connection *conn) {
4362  struct iobuf *io = &conn->ns_conn->recv_iobuf;
46514363
4652   while ((list = next_option(list, &vec, NULL)) != NULL) {
4653   flag = vec.ptr[0];
4654   if ((flag != '+' && flag != '-') ||
4655      parse_net(&vec.ptr[1], &net, &mask) == 0) {
4656      cry(fc(ctx), "%s: subnet must be [+|-]x.x.x.x[/x]", __func__);
4657      return -1;
4658   }
4659
4660   if (net == (remote_ip & mask)) {
4661      allowed = flag;
4662   }
4663   }
4664
4665   return allowed == '+';
4364  try_parse(conn);
4365  DBG(("%p %d %zu", conn, conn->request_len, io->len));
4366  if (conn->request_len < 0 ||
4367      (conn->request_len == 0 && io->len > MAX_REQUEST_SIZE)) {
4368    call_http_client_handler(conn);
4369  } else if ((int64_t) io->len >= conn->cl) {
4370    call_http_client_handler(conn);
4371  }
46664372}
46674373
4668#if !defined(_WIN32)
4669static int set_uid_option(struct mg_context *ctx) {
4670   struct passwd *pw;
4671   const char *uid = ctx->config[RUN_AS_USER];
4672   int success = 0;
4374struct mg_connection *mg_connect(struct mg_server *server, const char *host,
4375                                 int port, int use_ssl) {
4376  struct ns_connection *nsconn;
4377  struct connection *conn;
46734378
4674   if (uid == NULL) {
4675   success = 1;
4676   } else {
4677   if ((pw = getpwnam(uid)) == NULL) {
4678      cry(fc(ctx), "%s: unknown user [%s]", __func__, uid);
4679   } else if (setgid(pw->pw_gid) == -1) {
4680      cry(fc(ctx), "%s: setgid(%s): %s", __func__, uid, strerror(errno));
4681   } else if (setuid(pw->pw_uid) == -1) {
4682      cry(fc(ctx), "%s: setuid(%s): %s", __func__, uid, strerror(errno));
4683   } else {
4684      success = 1;
4685   }
4686   }
4379  nsconn = ns_connect(&server->ns_server, host, port, use_ssl, NULL);
4380  if (nsconn == NULL) return 0;
46874381
4688   return success;
4689}
4690#endif // !_WIN32
4382  if ((conn = (struct connection *) calloc(1, sizeof(*conn))) == NULL) {
4383    nsconn->flags |= NSF_CLOSE_IMMEDIATELY;
4384    return 0;
4385  }
46914386
4692#if !defined(NO_SSL)
4693static pthread_mutex_t *ssl_mutexes;
4387  // Interlink two structs
4388  conn->ns_conn = nsconn;
4389  nsconn->connection_data = conn;
46944390
4695static int sslize(struct mg_connection *conn, SSL_CTX *s, int (*func)(SSL *)) {
4696   return (conn->ssl = SSL_new(s)) != NULL &&
4697   SSL_set_fd(conn->ssl, conn->client.sock) == 1 &&
4698   func(conn->ssl) == 1;
4699}
4391  conn->server = server;
4392  conn->endpoint_type = EP_CLIENT;
4393  //conn->handler = handler;
4394  conn->mg_conn.server_param = server->ns_server.server_data;
4395  conn->ns_conn->flags = NSF_CONNECTING;
47004396
4701// Return OpenSSL error message
4702static const char *ssl_error(void) {
4703   unsigned long err;
4704   err = ERR_get_error();
4705   return err == 0 ? "" : ERR_error_string(err, NULL);
4397  return &conn->mg_conn;
47064398}
47074399
4708static void ssl_locking_callback(int mode, int mutex_num, const char *file,
4709                           int line) {
4710   (void) line;
4711   (void) file;
4400#ifndef MONGOOSE_NO_LOGGING
4401static void log_header(const struct mg_connection *conn, const char *header,
4402                       FILE *fp) {
4403  const char *header_value;
47124404
4713   if (mode & 1) {  // 1 is CRYPTO_LOCK
4714   (void) pthread_mutex_lock(&ssl_mutexes[mutex_num]);
4715   } else {
4716   (void) pthread_mutex_unlock(&ssl_mutexes[mutex_num]);
4717   }
4405  if ((header_value = mg_get_header(conn, header)) == NULL) {
4406    (void) fprintf(fp, "%s", " -");
4407  } else {
4408    (void) fprintf(fp, " \"%s\"", header_value);
4409  }
47184410}
47194411
4720static unsigned long ssl_id_callback(void) {
4721   return (unsigned long) pthread_self();
4722}
4412static void log_access(const struct connection *conn, const char *path) {
4413  const struct mg_connection *c = &conn->mg_conn;
4414  FILE *fp = (path == NULL) ?  NULL : fopen(path, "a+");
4415  char date[64], user[100];
4416  time_t now;
47234417
4724#if !defined(NO_SSL_DL)
4725static int load_dll(struct mg_context *ctx, const char *dll_name,
4726               struct ssl_func *sw) {
4727   union {void *p; void (*fp)(void);} u;
4728   void  *dll_handle;
4729   struct ssl_func *fp;
4418  if (fp == NULL) return;
4419  now = time(NULL);
4420  strftime(date, sizeof(date), "%d/%b/%Y:%H:%M:%S %z", localtime(&now));
47304421
4731   if ((dll_handle = dlopen(dll_name, RTLD_LAZY)) == NULL) {
4732   cry(fc(ctx), "%s: cannot load %s", __func__, dll_name);
4733   return 0;
4734   }
4422  flockfile(fp);
4423  mg_parse_header(mg_get_header(&conn->mg_conn, "Authorization"), "username",
4424                  user, sizeof(user));
4425  fprintf(fp, "%s - %s [%s] \"%s %s%s%s HTTP/%s\" %d %" INT64_FMT,
4426          c->remote_ip, user[0] == '\0' ? "-" : user, date,
4427          c->request_method ? c->request_method : "-",
4428          c->uri ? c->uri : "-", c->query_string ? "?" : "",
4429          c->query_string ? c->query_string : "",
4430          c->http_version, c->status_code, conn->num_bytes_sent);
4431  log_header(c, "Referer", fp);
4432  log_header(c, "User-Agent", fp);
4433  fputc('\n', fp);
4434  fflush(fp);
47354435
4736   for (fp = sw; fp->name != NULL; fp++) {
4737#ifdef _WIN32
4738   // GetProcAddress() returns pointer to function
4739   u.fp = (void (*)(void)) dlsym(dll_handle, fp->name);
4740#else
4741   // dlsym() on UNIX returns void *. ISO C forbids casts of data pointers to
4742   // function pointers. We need to use a union to make a cast.
4743   u.p = dlsym(dll_handle, fp->name);
4744#endif // _WIN32
4745   if (u.fp == NULL) {
4746      cry(fc(ctx), "%s: %s: cannot find %s", __func__, dll_name, fp->name);
4747      return 0;
4748   } else {
4749      fp->ptr = u.fp;
4750   }
4751   }
4752
4753   return 1;
4436  funlockfile(fp);
4437  fclose(fp);
47544438}
4755#endif // NO_SSL_DL
4439#endif
47564440
4757// Dynamically load SSL library. Set up ctx->ssl_ctx pointer.
4758static int set_ssl_option(struct mg_context *ctx) {
4759   int i, size;
4760   const char *pem;
4441static void close_local_endpoint(struct connection *conn) {
4442  struct mg_connection *c = &conn->mg_conn;
4443  // Must be done before free()
4444  int keep_alive = should_keep_alive(&conn->mg_conn) &&
4445    (conn->endpoint_type == EP_FILE || conn->endpoint_type == EP_USER);
4446  DBG(("%p %d %d %d", conn, conn->endpoint_type, keep_alive,
4447       conn->ns_conn->flags));
47614448
4762   // If PEM file is not specified, skip SSL initialization.
4763   if ((pem = ctx->config[SSL_CERTIFICATE]) == NULL) {
4764   return 1;
4765   }
4449  switch (conn->endpoint_type) {
4450    case EP_PUT:
4451    case EP_FILE:
4452      close(conn->endpoint.fd);
4453      break;
4454    case EP_CGI:
4455    case EP_PROXY:
4456      if (conn->endpoint.nc != NULL) {
4457        DBG(("%p %p %p :-)", conn, conn->ns_conn, conn->endpoint.nc));
4458        conn->endpoint.nc->flags |= NSF_CLOSE_IMMEDIATELY;
4459        conn->endpoint.nc->connection_data = NULL;
4460      }
4461      break;
4462    default: break;
4463  }
47664464
4767#if !defined(NO_SSL_DL)
4768   if (!load_dll(ctx, SSL_LIB, ssl_sw) ||
4769      !load_dll(ctx, CRYPTO_LIB, crypto_sw)) {
4770   return 0;
4771   }
4772#endif // NO_SSL_DL
4465#ifndef MONGOOSE_NO_LOGGING
4466  if (c->status_code > 0 && conn->endpoint_type != EP_CLIENT &&
4467      c->status_code != 400) {
4468    log_access(conn, conn->server->config_options[ACCESS_LOG_FILE]);
4469  }
4470#endif
47734471
4774   // Initialize SSL library
4775   SSL_library_init();
4776   SSL_load_error_strings();
4472  // Gobble possible POST data sent to the URI handler
4473  iobuf_free(&conn->ns_conn->recv_iobuf);
4474  free(conn->request);
4475  free(conn->path_info);
47774476
4778   if ((ctx->ssl_ctx = SSL_CTX_new(SSLv23_server_method())) == NULL) {
4779   cry(fc(ctx), "SSL_CTX_new (server) error: %s", ssl_error());
4780   return 0;
4781   }
4477  conn->endpoint_type = EP_NONE;
4478  conn->cl = conn->num_bytes_sent = conn->request_len = 0;
4479  conn->ns_conn->flags &= ~(NSF_FINISHED_SENDING_DATA |
4480                            NSF_BUFFER_BUT_DONT_SEND | NSF_CLOSE_IMMEDIATELY |
4481                            MG_HEADERS_SENT | MG_LONG_RUNNING);
4482  c->num_headers = c->status_code = c->is_websocket = c->content_len = 0;
4483  conn->endpoint.nc = NULL;
4484  c->request_method = c->uri = c->http_version = c->query_string = NULL;
4485  conn->request = conn->path_info = NULL;
47824486
4783   // If user callback returned non-NULL, that means that user callback has
4784   // set up certificate itself. In this case, skip sertificate setting.
4785   if ((ctx->callbacks.init_ssl == NULL ||
4786      !ctx->callbacks.init_ssl(ctx->ssl_ctx, ctx->user_data)) &&
4787      (SSL_CTX_use_certificate_file(ctx->ssl_ctx, pem, 1) == 0 ||
4788      SSL_CTX_use_PrivateKey_file(ctx->ssl_ctx, pem, 1) == 0)) {
4789   cry(fc(ctx), "%s: cannot open %s: %s", __func__, pem, ssl_error());
4790   return 0;
4791   }
4487  if (keep_alive) {
4488    on_recv_data(conn);  // Can call us recursively if pipelining is used
4489  } else {
4490    conn->ns_conn->flags |= conn->ns_conn->send_iobuf.len == 0 ?
4491      NSF_CLOSE_IMMEDIATELY : NSF_FINISHED_SENDING_DATA;
4492  }
4493}
47924494
4793   if (pem != NULL) {
4794   (void) SSL_CTX_use_certificate_chain_file(ctx->ssl_ctx, pem);
4795   }
4495static void transfer_file_data(struct connection *conn) {
4496  char buf[IOBUF_SIZE];
4497  int n = read(conn->endpoint.fd, buf, conn->cl < (int64_t) sizeof(buf) ?
4498               (int) conn->cl : (int) sizeof(buf));
47964499
4797   // Initialize locking callbacks, needed for thread safety.
4798   // http://www.openssl.org/support/faq.html#PROG1
4799   size = sizeof(pthread_mutex_t) * CRYPTO_num_locks();
4800   if ((ssl_mutexes = (pthread_mutex_t *) malloc((size_t)size)) == NULL) {
4801   cry(fc(ctx), "%s: cannot allocate mutexes: %s", __func__, ssl_error());
4802   return 0;
4803   }
4500  if (n <= 0) {
4501    close_local_endpoint(conn);
4502  } else if (n > 0) {
4503    conn->cl -= n;
4504    ns_send(conn->ns_conn, buf, n);
4505    if (conn->cl <= 0) {
4506      close_local_endpoint(conn);
4507    }
4508  }
4509}
48044510
4805   for (i = 0; i < CRYPTO_num_locks(); i++) {
4806   pthread_mutex_init(&ssl_mutexes[i], NULL);
4807   }
4511int mg_poll_server(struct mg_server *server, int milliseconds) {
4512  return ns_server_poll(&server->ns_server, milliseconds);
4513}
48084514
4809   CRYPTO_set_locking_callback(&ssl_locking_callback);
4810   CRYPTO_set_id_callback(&ssl_id_callback);
4515void mg_destroy_server(struct mg_server **server) {
4516  if (server != NULL && *server != NULL) {
4517    struct mg_server *s = *server;
4518    int i;
48114519
4812   return 1;
4520    ns_server_free(&s->ns_server);
4521    for (i = 0; i < (int) ARRAY_SIZE(s->config_options); i++) {
4522      free(s->config_options[i]);  // It is OK to free(NULL)
4523    }
4524    free(s);
4525    *server = NULL;
4526  }
48134527}
48144528
4815static void uninitialize_ssl(struct mg_context *ctx) {
4816   int i;
4817   if (ctx->ssl_ctx != NULL) {
4818   CRYPTO_set_locking_callback(NULL);
4819   for (i = 0; i < CRYPTO_num_locks(); i++) {
4820      pthread_mutex_destroy(&ssl_mutexes[i]);
4821   }
4822   CRYPTO_set_locking_callback(NULL);
4823   CRYPTO_set_id_callback(NULL);
4824   }
4825}
4826#endif // !NO_SSL
4529struct mg_iterator {
4530  mg_handler_t cb;
4531  void *param;
4532};
48274533
4828static int set_gpass_option(struct mg_context *ctx) {
4829   struct file file = STRUCT_FILE_INITIALIZER;
4830   const char *path = ctx->config[GLOBAL_PASSWORDS_FILE];
4831   if (path != NULL && !mg_stat(fc(ctx), path, &file)) {
4832   cry(fc(ctx), "Cannot open %s: %s", path, strerror(ERRNO));
4833   return 0;
4834   }
4835   return 1;
4534static void iter(struct ns_connection *nsconn, enum ns_event ev, void *param) {
4535  if (ev == NS_POLL) {
4536    struct mg_iterator *it = (struct mg_iterator *) param;
4537    struct connection *c = (struct connection *) nsconn->connection_data;
4538    if (c != NULL) c->mg_conn.callback_param = it->param;
4539    it->cb(&c->mg_conn, MG_POLL);
4540  }
48364541}
48374542
4838static int set_acl_option(struct mg_context *ctx) {
4839   return check_acl(ctx, (uint32_t) 0x7f000001UL) != -1;
4543// Apply function to all active connections.
4544void mg_iterate_over_connections(struct mg_server *server, mg_handler_t cb,
4545  void *param) {
4546  struct mg_iterator it = { cb, param };
4547  ns_iterate(&server->ns_server, iter, &it);
48404548}
48414549
4842static void reset_per_request_attributes(struct mg_connection *conn) {
4843   conn->path_info = NULL;
4844   conn->num_bytes_sent = conn->consumed_content = 0;
4845   conn->status_code = -1;
4846   conn->must_close = conn->request_len = conn->throttle = 0;
4847}
4550static int get_var(const char *data, size_t data_len, const char *name,
4551                   char *dst, size_t dst_len) {
4552  const char *p, *e, *s;
4553  size_t name_len;
4554  int len;
48484555
4849static void close_socket_gracefully(struct mg_connection *conn) {
4850#if defined(_WIN32)
4851   char buf[MG_BUF_LEN];
4852   int n;
4853#endif
4854   struct linger linger;
4556  if (dst == NULL || dst_len == 0) {
4557    len = -2;
4558  } else if (data == NULL || name == NULL || data_len == 0) {
4559    len = -1;
4560    dst[0] = '\0';
4561  } else {
4562    name_len = strlen(name);
4563    e = data + data_len;
4564    len = -1;
4565    dst[0] = '\0';
48554566
4856   // Set linger option to avoid socket hanging out after close. This prevent
4857   // ephemeral port exhaust problem under high QPS.
4858   linger.l_onoff = 1;
4859   linger.l_linger = 1;
4860   setsockopt(conn->client.sock, SOL_SOCKET, SO_LINGER,
4861            (char *) &linger, sizeof(linger));
4567    // data is "var1=val1&var2=val2...". Find variable first
4568    for (p = data; p + name_len < e; p++) {
4569      if ((p == data || p[-1] == '&') && p[name_len] == '=' &&
4570          !mg_strncasecmp(name, p, name_len)) {
48624571
4863   // Send FIN to the client
4864   shutdown(conn->client.sock, SHUT_WR);
4865   set_non_blocking_mode(conn->client.sock);
4572        // Point p to variable value
4573        p += name_len + 1;
48664574
4867#if defined(_WIN32)
4868   // Read and discard pending incoming data. If we do not do that and close the
4869   // socket, the data in the send buffer may be discarded. This
4870   // behaviour is seen on Windows, when client keeps sending data
4871   // when server decides to close the connection; then when client
4872   // does recv() it gets no data back.
4873   do {
4874   n = pull(NULL, conn, buf, sizeof(buf));
4875   } while (n > 0);
4876#endif
4575        // Point s to the end of the value
4576        s = (const char *) memchr(p, '&', (size_t)(e - p));
4577        if (s == NULL) {
4578          s = e;
4579        }
4580        assert(s >= p);
48774581
4878   // Now we know that our FIN is ACK-ed, safe to close
4879   closesocket(conn->client.sock);
4880}
4582        // Decode variable into destination buffer
4583        len = mg_url_decode(p, (size_t)(s - p), dst, dst_len, 1);
48814584
4882static void close_connection(struct mg_connection *conn) {
4883   conn->must_close = 1;
4585        // Redirect error code from -1 to -2 (destination buffer too small).
4586        if (len == -1) {
4587          len = -2;
4588        }
4589        break;
4590      }
4591    }
4592  }
48844593
4885#ifndef NO_SSL
4886   if (conn->ssl != NULL) {
4887   // Run SSL_shutdown twice to ensure completly close SSL connection
4888   SSL_shutdown(conn->ssl);
4889   SSL_free(conn->ssl);
4890   conn->ssl = NULL;
4891   }
4892#endif
4893   if (conn->client.sock != INVALID_SOCKET) {
4894   close_socket_gracefully(conn);
4895   conn->client.sock = INVALID_SOCKET;
4896   }
4594  return len;
48974595}
48984596
4899void mg_close_connection(struct mg_connection *conn) {
4900#ifndef NO_SSL
4901   if (conn->client_ssl_ctx != NULL) {
4902   SSL_CTX_free((SSL_CTX *) conn->client_ssl_ctx);
4903   }
4904#endif
4905   close_connection(conn);
4906   free(conn);
4597int mg_get_var(const struct mg_connection *conn, const char *name,
4598               char *dst, size_t dst_len) {
4599  int len = get_var(conn->query_string, conn->query_string == NULL ? 0 :
4600                    strlen(conn->query_string), name, dst, dst_len);
4601  if (len < 0) {
4602    len = get_var(conn->content, conn->content_len, name, dst, dst_len);
4603  }
4604  return len;
49074605}
49084606
4909struct mg_connection *mg_connect(const char *host, int port, int use_ssl,
4910                           char *ebuf, size_t ebuf_len) {
4911   static struct mg_context fake_ctx;
4912   struct mg_connection *conn = NULL;
4913   SOCKET sock;
4607static int get_line_len(const char *buf, int buf_len) {
4608  int len = 0;
4609  while (len < buf_len && buf[len] != '\n') len++;
4610  return buf[len] == '\n' ? len + 1: -1;
4611}
49144612
4915   if ((sock = conn2(host, port, use_ssl, ebuf, ebuf_len)) == INVALID_SOCKET) {
4916   } else if ((conn = (struct mg_connection *)
4917            calloc(1, sizeof(*conn) + MAX_REQUEST_SIZE)) == NULL) {
4918   snprintf(ebuf, ebuf_len, "calloc(): %s", strerror(ERRNO));
4919   closesocket(sock);
4920#ifndef NO_SSL
4921   } else if (use_ssl && (conn->client_ssl_ctx =
4922                     SSL_CTX_new(SSLv23_client_method())) == NULL) {
4923   snprintf(ebuf, ebuf_len, "SSL_CTX_new error");
4924   closesocket(sock);
4925   free(conn);
4926   conn = NULL;
4927#endif // NO_SSL
4928   } else {
4929   socklen_t len;
4930   conn->buf_size = MAX_REQUEST_SIZE;
4931   conn->buf = (char *) (conn + 1);
4932   conn->ctx = &fake_ctx;
4933   conn->client.sock = sock;
4934   getsockname(sock, &conn->client.rsa.sa, &len);
4935   conn->client.is_ssl = use_ssl;
4936#ifndef NO_SSL
4937   if (use_ssl) {
4938      // SSL_CTX_set_verify call is needed to switch off server certificate
4939      // checking, which is off by default in OpenSSL and on in yaSSL.
4940      SSL_CTX_set_verify(conn->client_ssl_ctx, 0, 0);
4941      sslize(conn, conn->client_ssl_ctx, SSL_connect);
4942   }
4943#endif
4944   }
4613int mg_parse_multipart(const char *buf, int buf_len,
4614                       char *var_name, int var_name_len,
4615                       char *file_name, int file_name_len,
4616                       const char **data, int *data_len) {
4617  static const char cd[] = "Content-Disposition: ";
4618  //struct mg_connection c;
4619  int hl, bl, n, ll, pos, cdl = sizeof(cd) - 1;
4620  //char *p;
49454621
4946   return conn;
4947}
4622  if (buf == NULL || buf_len <= 0) return 0;
4623  if ((hl = get_request_len(buf, buf_len)) <= 0) return 0;
4624  if (buf[0] != '-' || buf[1] != '-' || buf[2] == '\n') return 0;
49484625
4949static int is_valid_uri(const char *uri) {
4950   // Conform to http://www.w3.org/Protocols/rfc2616/rfc2616-sec5.html#sec5.1.2
4951   // URI can be an asterisk (*) or should start with slash.
4952   return uri[0] == '/' || (uri[0] == '*' && uri[1] == '\0');
4953}
4626  // Get boundary length
4627  bl = get_line_len(buf, buf_len);
49544628
4955static int getreq(struct mg_connection *conn, char *ebuf, size_t ebuf_len) {
4956   const char *cl;
4629  // Loop through headers, fetch variable name and file name
4630  var_name[0] = file_name[0] = '\0';
4631  for (n = bl; (ll = get_line_len(buf + n, hl - n)) > 0; n += ll) {
4632    if (mg_strncasecmp(cd, buf + n, cdl) == 0) {
4633      parse_header(buf + n + cdl, ll - (cdl + 2), "name",
4634                   var_name, var_name_len);
4635      parse_header(buf + n + cdl, ll - (cdl + 2), "filename",
4636                   file_name, file_name_len);
4637    }
4638  }
49574639
4958   ebuf[0] = '\0';
4959   reset_per_request_attributes(conn);
4960   conn->request_len = read_request(NULL, conn, conn->buf, conn->buf_size,
4961                           &conn->data_len);
4962   assert(conn->request_len < 0 || conn->data_len >= conn->request_len);
4640  // Scan body, search for terminating boundary
4641  for (pos = hl; pos + (bl - 2) < buf_len; pos++) {
4642    if (buf[pos] == '-' && !memcmp(buf, &buf[pos], bl - 2)) {
4643      if (data_len != NULL) *data_len = (pos - 2) - hl;
4644      if (data != NULL) *data = buf + hl;
4645      return pos;
4646    }
4647  }
49634648
4964   if (conn->request_len == 0 && conn->data_len == conn->buf_size) {
4965   snprintf(ebuf, ebuf_len, "%s", "Request Too Large");
4966   } else if (conn->request_len <= 0) {
4967   snprintf(ebuf, ebuf_len, "%s", "Client closed connection");
4968   } else if (parse_http_message(conn->buf, conn->buf_size,
4969                        &conn->request_info) <= 0) {
4970   snprintf(ebuf, ebuf_len, "Bad request: [%.*s]", conn->data_len, conn->buf);
4971   } else {
4972   // Request is valid
4973   if ((cl = get_header(&conn->request_info, "Content-Length")) != NULL) {
4974      conn->content_len = strtoll(cl, NULL, 10);
4975   } else if (!mg_strcasecmp(conn->request_info.request_method, "POST") ||
4976            !mg_strcasecmp(conn->request_info.request_method, "PUT")) {
4977      conn->content_len = -1;
4978   } else {
4979      conn->content_len = 0;
4980   }
4981   conn->birth_time = time(NULL);
4982   }
4983   return ebuf[0] == '\0';
4649  return 0;
49844650}
49854651
4986struct mg_connection *mg_download(const char *host, int port, int use_ssl,
4987                           char *ebuf, size_t ebuf_len,
4988                           const char *fmt, ...) {
4989   struct mg_connection *conn;
4990   va_list ap;
4652const char **mg_get_valid_option_names(void) {
4653  return static_config_options;
4654}
49914655
4992   va_start(ap, fmt);
4993   ebuf[0] = '\0';
4994   if ((conn = mg_connect(host, port, use_ssl, ebuf, ebuf_len)) == NULL) {
4995   } else if (mg_vprintf(conn, fmt, ap) <= 0) {
4996   snprintf(ebuf, ebuf_len, "%s", "Error sending request");
4997   } else {
4998   getreq(conn, ebuf, ebuf_len);
4999   }
5000   if (ebuf[0] != '\0' && conn != NULL) {
5001   mg_close_connection(conn);
5002   conn = NULL;
5003   }
4656static int get_option_index(const char *name) {
4657  int i;
50044658
5005   return conn;
4659  for (i = 0; static_config_options[i * 2] != NULL; i++) {
4660    if (strcmp(static_config_options[i * 2], name) == 0) {
4661      return i;
4662    }
4663  }
4664  return -1;
50064665}
50074666
5008static void process_new_connection(struct mg_connection *conn) {
5009   struct mg_request_info *ri = &conn->request_info;
5010   int keep_alive_enabled, keep_alive, discard_len;
5011   char ebuf[100];
4667static void set_default_option_values(char **opts) {
4668  const char *value, **all_opts = mg_get_valid_option_names();
4669  int i;
50124670
5013   keep_alive_enabled = !strcmp(conn->ctx->config[ENABLE_KEEP_ALIVE], "yes");
5014   keep_alive = 0;
5015
5016   // Important: on new connection, reset the receiving buffer. Credit goes
5017   // to crule42.
5018   conn->data_len = 0;
5019   do {
5020   if (!getreq(conn, ebuf, sizeof(ebuf))) {
5021      send_http_error(conn, 500, "Server Error", "%s", ebuf);
5022      conn->must_close = 1;
5023   } else if (!is_valid_uri(conn->request_info.uri)) {
5024      snprintf(ebuf, sizeof(ebuf), "Invalid URI: [%s]", ri->uri);
5025      send_http_error(conn, 400, "Bad Request", "%s", ebuf);
5026   } else if (strcmp(ri->http_version, "1.0") &&
5027            strcmp(ri->http_version, "1.1")) {
5028      snprintf(ebuf, sizeof(ebuf), "Bad HTTP version: [%s]", ri->http_version);
5029      send_http_error(conn, 505, "Bad HTTP version", "%s", ebuf);
5030   }
5031
5032   if (ebuf[0] == '\0') {
5033      handle_request(conn);
5034      if (conn->ctx->callbacks.end_request != NULL) {
5035      conn->ctx->callbacks.end_request(conn, conn->status_code);
5036      }
5037      log_access(conn);
5038   }
5039   if (ri->remote_user != NULL) {
5040      free((void *) ri->remote_user);
5041      // Important! When having connections with and without auth
5042      // would cause double free and then crash
5043      ri->remote_user = NULL;
5044   }
5045
5046   // NOTE(lsm): order is important here. should_keep_alive() call
5047   // is using parsed request, which will be invalid after memmove's below.
5048   // Therefore, memorize should_keep_alive() result now for later use
5049   // in loop exit condition.
5050   keep_alive = conn->ctx->stop_flag == 0 && keep_alive_enabled &&
5051      conn->content_len >= 0 && should_keep_alive(conn);
5052
5053   // Discard all buffered data for this request
5054   discard_len = conn->content_len >= 0 && conn->request_len > 0 &&
5055      conn->request_len + conn->content_len < (int64_t) conn->data_len ?
5056      (int) (conn->request_len + conn->content_len) : conn->data_len;
5057   assert(discard_len >= 0);
5058   memmove(conn->buf, conn->buf + discard_len, conn->data_len - discard_len);
5059   conn->data_len -= discard_len;
5060   assert(conn->data_len >= 0);
5061   assert(conn->data_len <= conn->buf_size);
5062   } while (keep_alive);
4671  for (i = 0; all_opts[i * 2] != NULL; i++) {
4672    value = all_opts[i * 2 + 1];
4673    if (opts[i] == NULL && value != NULL) {
4674      opts[i] = mg_strdup(value);
4675    }
4676  }
50634677}
50644678
5065// Worker threads take accepted socket from the queue
5066static int consume_socket(struct mg_context *ctx, struct socket *sp) {
5067   (void) pthread_mutex_lock(&ctx->mutex);
5068   DEBUG_TRACE(("going idle"));
4679const char *mg_set_option(struct mg_server *server, const char *name,
4680                          const char *value) {
4681  int ind = get_option_index(name);
4682  const char *error_msg = NULL;
4683  char **v = NULL;
50694684
5070   // If the queue is empty, wait. We're idle at this point.
5071   while (ctx->sq_head == ctx->sq_tail && ctx->stop_flag == 0) {
5072   pthread_cond_wait(&ctx->sq_full, &ctx->mutex);
5073   }
4685  if (ind < 0) return  "No such option";
4686  v = &server->config_options[ind];
50744687
5075   // If we're stopping, sq_head may be equal to sq_tail.
5076   if (ctx->sq_head > ctx->sq_tail) {
5077   // Copy socket from the queue and increment tail
5078   *sp = ctx->queue[ctx->sq_tail % ARRAY_SIZE(ctx->queue)];
5079   ctx->sq_tail++;
5080   DEBUG_TRACE(("grabbed socket %d, going busy", sp->sock));
4688  // Return success immediately if setting to the same value
4689  if ((*v == NULL && value == NULL) ||
4690      (value != NULL && *v != NULL && !strcmp(value, *v))) {
4691    return NULL;
4692  }
50814693
5082   // Wrap pointers if needed
5083   while (ctx->sq_tail > (int) ARRAY_SIZE(ctx->queue)) {
5084      ctx->sq_tail -= ARRAY_SIZE(ctx->queue);
5085      ctx->sq_head -= ARRAY_SIZE(ctx->queue);
5086   }
5087   }
4694  if (*v != NULL) {
4695    free(*v);
4696    *v = NULL;
4697  }
50884698
5089   (void) pthread_cond_signal(&ctx->sq_empty);
5090   (void) pthread_mutex_unlock(&ctx->mutex);
4699  if (value == NULL || value[0] == '\0') return NULL;
50914700
5092   return !ctx->stop_flag;
5093}
4701  *v = mg_strdup(value);
4702  DBG(("%s [%s]", name, *v));
50944703
5095static void *worker_thread(void *thread_func_param) {
5096   struct mg_context *ctx = (struct mg_context *)thread_func_param;
5097   struct mg_connection *conn;
5098
5099   conn = (struct mg_connection *) calloc(1, sizeof(*conn) + MAX_REQUEST_SIZE);
5100   if (conn == NULL) {
5101   cry(fc(ctx), "%s", "Cannot create new connection struct, OOM");
5102   } else {
5103   conn->buf_size = MAX_REQUEST_SIZE;
5104   conn->buf = (char *) (conn + 1);
5105   conn->ctx = ctx;
5106   conn->request_info.user_data = ctx->user_data;
5107
5108   // Call consume_socket() even when ctx->stop_flag > 0, to let it signal
5109   // sq_empty condvar to wake up the master waiting in produce_socket()
5110   while (consume_socket(ctx, &conn->client)) {
5111      conn->birth_time = time(NULL);
5112
5113      // Fill in IP, port info early so even if SSL setup below fails,
5114      // error handler would have the corresponding info.
5115      // Thanks to Johannes Winkelmann for the patch.
5116      // TODO(lsm): Fix IPv6 case
5117      conn->request_info.remote_port = ntohs(conn->client.rsa.sin.sin_port);
5118      memcpy(&conn->request_info.remote_ip,
5119            &conn->client.rsa.sin.sin_addr.s_addr, 4);
5120      conn->request_info.remote_ip = ntohl(conn->request_info.remote_ip);
5121      conn->request_info.is_ssl = conn->client.is_ssl;
5122
5123      if (!conn->client.is_ssl
5124#ifndef NO_SSL
5125         || sslize(conn, conn->ctx->ssl_ctx, SSL_accept)
4704  if (ind == LISTENING_PORT) {
4705    int port = ns_bind(&server->ns_server, value);
4706    if (port < 0) {
4707      error_msg = "Cannot bind to port";
4708    } else {
4709      if (!strcmp(value, "0")) {
4710        char buf[10];
4711        mg_snprintf(buf, sizeof(buf), "%d", port);
4712        free(*v);
4713        *v = mg_strdup(buf);
4714      }
4715    }
4716#ifndef _WIN32
4717  } else if (ind == RUN_AS_USER) {
4718    struct passwd *pw;
4719    if ((pw = getpwnam(value)) == NULL) {
4720      error_msg = "Unknown user";
4721    } else if (setgid(pw->pw_gid) != 0) {
4722      error_msg = "setgid() failed";
4723    } else if (setuid(pw->pw_uid) != 0) {
4724      error_msg = "setuid() failed";
4725    }
51264726#endif
5127         ) {
5128      process_new_connection(conn);
5129      }
4727#ifdef NS_ENABLE_SSL
4728  } else if (ind == SSL_CERTIFICATE) {
4729    int res = ns_set_ssl_cert(&server->ns_server, value);
4730    if (res == -2) {
4731      error_msg = "Cannot load PEM";
4732    } else if (res == -3) {
4733      error_msg = "SSL not enabled";
4734    } else if (res == -1) {
4735      error_msg = "SSL_CTX_new() failed";
4736    }
4737  } else if (ind == SSL_CA_CERTIFICATE) {
4738    if (ns_set_ssl_ca_cert(&server->ns_server, value) != 0) {
4739       error_msg = "Error setting CA cert";
4740     }
4741#endif
4742  }
51304743
5131      close_connection(conn);
5132   }
5133   free(conn);
5134   }
4744  return error_msg;
4745}
51354746
5136   // Signal master that we're done with connection and exiting
5137   (void) pthread_mutex_lock(&ctx->mutex);
5138   ctx->num_threads--;
5139   (void) pthread_cond_signal(&ctx->cond);
5140   assert(ctx->num_threads >= 0);
5141   (void) pthread_mutex_unlock(&ctx->mutex);
4747static void set_ips(struct ns_connection *nc, int is_rem) {
4748  struct connection *conn = (struct connection *) nc->connection_data;
4749  struct mg_connection *c = &conn->mg_conn;
4750  char buf[100];
51424751
5143   DEBUG_TRACE(("exiting"));
5144   return NULL;
4752  ns_sock_to_str(nc->sock, buf, sizeof(buf), is_rem ? 7 : 3);
4753  sscanf(buf, "%47[^:]:%hu",
4754         is_rem ? c->remote_ip : c->local_ip,
4755         is_rem ? &c->remote_port : &c->local_port);
4756  //DBG(("%p %s %s", conn, is_rem ? "rem" : "loc", buf));
51454757}
51464758
5147// Master thread adds accepted socket to a queue
5148static void produce_socket(struct mg_context *ctx, const struct socket *sp) {
5149   (void) pthread_mutex_lock(&ctx->mutex);
4759static void on_accept(struct ns_connection *nc, union socket_address *sa) {
4760  struct mg_server *server = (struct mg_server *) nc->server;
4761  struct connection *conn;
51504762
5151   // If the queue is full, wait
5152   while (ctx->stop_flag == 0 &&
5153         ctx->sq_head - ctx->sq_tail >= (int) ARRAY_SIZE(ctx->queue)) {
5154   (void) pthread_cond_wait(&ctx->sq_empty, &ctx->mutex);
5155   }
4763  if (!check_acl(server->config_options[ACCESS_CONTROL_LIST],
4764                 ntohl(* (uint32_t *) &sa->sin.sin_addr)) ||
4765      (conn = (struct connection *) calloc(1, sizeof(*conn))) == NULL) {
4766    nc->flags |= NSF_CLOSE_IMMEDIATELY;
4767  } else {
4768    // Circularly link two connection structures
4769    nc->connection_data = conn;
4770    conn->ns_conn = nc;
51564771
5157   if (ctx->sq_head - ctx->sq_tail < (int) ARRAY_SIZE(ctx->queue)) {
5158   // Copy socket to the queue and increment head
5159   ctx->queue[ctx->sq_head % ARRAY_SIZE(ctx->queue)] = *sp;
5160   ctx->sq_head++;
5161   DEBUG_TRACE(("queued socket %d", sp->sock));
5162   }
5163
5164   (void) pthread_cond_signal(&ctx->sq_full);
5165   (void) pthread_mutex_unlock(&ctx->mutex);
4772    // Initialize the rest of connection attributes
4773    conn->server = server;
4774    conn->mg_conn.server_param = nc->server->server_data;
4775    set_ips(nc, 1);
4776    set_ips(nc, 0);
4777  }
51664778}
51674779
5168static int set_sock_timeout(SOCKET sock, int milliseconds) {
5169#ifdef _WIN32
5170   DWORD t = milliseconds;
5171#else
5172   struct timeval t;
5173   t.tv_sec = milliseconds / 1000;
5174   t.tv_usec = (milliseconds * 1000) % 1000000;
5175#endif
5176   return setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (SETSOCKOPT_CAST) &t, sizeof(t)) ||
5177   setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, (SETSOCKOPT_CAST) &t, sizeof(t));
5178}
4780#ifndef MONGOOSE_NO_FILESYSTEM
4781static void hexdump(struct ns_connection *nc, const char *path,
4782                    int num_bytes, int is_sent) {
4783  const struct iobuf *io = is_sent ? &nc->send_iobuf : &nc->recv_iobuf;
4784  FILE *fp;
4785  char *buf, src[60], dst[60];
4786  int buf_size = num_bytes * 5 + 100;
51794787
5180static void accept_new_connection(const struct socket *listener,
5181                           struct mg_context *ctx) {
5182   struct socket so;
5183   char src_addr[IP_ADDR_STR_LEN];
5184   socklen_t len = sizeof(so.rsa);
5185   int on = 1;
5186
5187   if ((so.sock = accept(listener->sock, &so.rsa.sa, &len)) == INVALID_SOCKET) {
5188   } else if (!check_acl(ctx, ntohl(* (uint32_t *) &so.rsa.sin.sin_addr))) {
5189   sockaddr_to_string(src_addr, sizeof(src_addr), &so.rsa);
5190   cry(fc(ctx), "%s: %s is not allowed to connect", __func__, src_addr);
5191   closesocket(so.sock);
5192   } else {
5193   // Put so socket structure into the queue
5194   DEBUG_TRACE(("Accepted socket %d", (int) so.sock));
5195   so.is_ssl = listener->is_ssl;
5196   so.ssl_redir = listener->ssl_redir;
5197   getsockname(so.sock, &so.lsa.sa, &len);
5198   // Set TCP keep-alive. This is needed because if HTTP-level keep-alive
5199   // is enabled, and client resets the connection, server won't get
5200   // TCP FIN or RST and will keep the connection open forever. With TCP
5201   // keep-alive, next keep-alive handshake will figure out that the client
5202   // is down and will close the server end.
5203   // Thanks to Igor Klopov who suggested the patch.
5204   setsockopt(so.sock, SOL_SOCKET, SO_KEEPALIVE, (SETSOCKOPT_CAST) &on, sizeof(on));
5205   set_sock_timeout(so.sock, atoi(ctx->config[REQUEST_TIMEOUT]));
5206   produce_socket(ctx, &so);
5207   }
4788  if (path != NULL && (fp = fopen(path, "a")) != NULL) {
4789    ns_sock_to_str(nc->sock, src, sizeof(src), 3);
4790    ns_sock_to_str(nc->sock, dst, sizeof(dst), 7);
4791    fprintf(fp, "%lu %p %s %s %s %d\n", (unsigned long) time(NULL),
4792            nc->connection_data, src,
4793            is_sent == 0 ? "<-" : is_sent == 1 ? "->" :
4794            is_sent == 2 ? "<A" : "C>", dst, num_bytes);
4795    if (num_bytes > 0 && (buf = (char *) malloc(buf_size)) != NULL) {
4796      ns_hexdump(io->buf + (is_sent ? 0 : io->len) - (is_sent ? 0 : num_bytes),
4797                 num_bytes, buf, buf_size);
4798      fprintf(fp, "%s", buf);
4799      free(buf);
4800    }
4801    fclose(fp);
4802  }
52084803}
4804#endif
52094805
5210static void *master_thread(void *thread_func_param) {
5211   struct mg_context *ctx = (struct mg_context *)thread_func_param;
5212   struct pollfd *pfd;
5213   int i;
4806static void mg_ev_handler(struct ns_connection *nc, enum ns_event ev, void *p) {
4807  struct connection *conn = (struct connection *) nc->connection_data;
4808  struct mg_server *server = (struct mg_server *) nc->server;
52144809
5215   // Increase priority of the master thread
5216#if defined(_WIN32)
5217   SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_ABOVE_NORMAL);
4810  // Send NS event to the handler. Note that call_user won't send an event
4811  // if conn == NULL. Therefore, repeat this for NS_ACCEPT event as well.
4812#ifdef MONGOOSE_SEND_NS_EVENTS
4813  {
4814    struct connection *conn = (struct connection *) nc->connection_data;
4815    if (conn != NULL) conn->mg_conn.callback_param = p;
4816    call_user(conn, (enum mg_event) ev);
4817  }
52184818#endif
52194819
5220#if defined(ISSUE_317)
5221   struct sched_param sched_param;
5222   sched_param.sched_priority = sched_get_priority_max(SCHED_RR);
5223   pthread_setschedparam(pthread_self(), SCHED_RR, &sched_param);
4820  switch (ev) {
4821    case NS_ACCEPT:
4822      on_accept(nc, (union socket_address *) p);
4823#ifndef MONGOOSE_NO_FILESYSTEM
4824      hexdump(nc, server->config_options[HEXDUMP_FILE], 0, 2);
52244825#endif
4826#ifdef MONGOOSE_SEND_NS_EVENTS
4827      {
4828        struct connection *conn = (struct connection *) nc->connection_data;
4829        if (conn != NULL) conn->mg_conn.callback_param = p;
4830        call_user(conn, (enum mg_event) ev);
4831      }
4832#endif
4833      break;
52254834
5226   pfd = (struct pollfd *)calloc(ctx->num_listening_sockets, sizeof(pfd[0]));
5227   while (pfd != NULL && ctx->stop_flag == 0) {
5228   for (i = 0; i < ctx->num_listening_sockets; i++) {
5229      pfd[i].fd = ctx->listening_sockets[i].sock;
5230      pfd[i].events = POLLIN;
5231   }
4835    case NS_CONNECT:
4836      if (nc->connection_data != NULL) {
4837        set_ips(nc, 1);
4838        set_ips(nc, 0);
4839      }
4840#ifndef MONGOOSE_NO_FILESYSTEM
4841      hexdump(nc, server->config_options[HEXDUMP_FILE], 0, 3);
4842#endif
4843      conn->mg_conn.status_code = * (int *) p;
4844      if (conn->mg_conn.status_code != 0 ||
4845          (!(nc->flags & MG_PROXY_CONN) &&
4846           call_user(conn, MG_CONNECT) == MG_FALSE)) {
4847        nc->flags |= NSF_CLOSE_IMMEDIATELY;
4848      }
4849      break;
52324850
5233   if (poll(pfd, ctx->num_listening_sockets, 200) > 0) {
5234      for (i = 0; i < ctx->num_listening_sockets; i++) {
5235      // NOTE(lsm): on QNX, poll() returns POLLRDNORM after the
5236      // successfull poll, and POLLIN is defined as (POLLRDNORM | POLLRDBAND)
5237      // Therefore, we're checking pfd[i].revents & POLLIN, not
5238      // pfd[i].revents == POLLIN.
5239      if (ctx->stop_flag == 0 && (pfd[i].revents & POLLIN)) {
5240         accept_new_connection(&ctx->listening_sockets[i], ctx);
5241      }
5242      }
5243   }
5244   }
5245   free(pfd);
5246   DEBUG_TRACE(("stopping workers"));
4851    case NS_RECV:
4852#ifndef MONGOOSE_NO_FILESYSTEM
4853      hexdump(nc, server->config_options[HEXDUMP_FILE], * (int *) p, 0);
4854#endif
4855      if (nc->flags & NSF_ACCEPTED) {
4856        on_recv_data(conn);
4857#ifndef MONGOOSE_NO_CGI
4858      } else if (nc->flags & MG_CGI_CONN) {
4859        on_cgi_data(nc);
4860#endif
4861      } else if (nc->flags & MG_PROXY_CONN) {
4862        if (conn != NULL) {
4863          ns_forward(nc, conn->ns_conn);
4864        }
4865      } else {
4866        process_response(conn);
4867      }
4868      break;
52474869
5248   // Stop signal received: somebody called mg_stop. Quit.
5249   close_all_listening_sockets(ctx);
4870    case NS_SEND:
4871#ifndef MONGOOSE_NO_FILESYSTEM
4872      hexdump(nc, server->config_options[HEXDUMP_FILE], * (int *) p, 1);
4873#endif
4874      break;
52504875
5251   // Wakeup workers that are waiting for connections to handle.
5252   pthread_cond_broadcast(&ctx->sq_full);
4876    case NS_CLOSE:
4877      nc->connection_data = NULL;
4878      if (nc->flags & (MG_CGI_CONN | MG_PROXY_CONN)) {
4879        DBG(("%p %p closing cgi/proxy conn", conn, nc));
4880        if (conn && conn->ns_conn) {
4881          conn->ns_conn->flags &= ~NSF_BUFFER_BUT_DONT_SEND;
4882          conn->ns_conn->flags |= conn->ns_conn->send_iobuf.len > 0 ?
4883            NSF_FINISHED_SENDING_DATA : NSF_CLOSE_IMMEDIATELY;
4884          conn->endpoint.nc = NULL;
4885        }
4886      } else if (conn != NULL) {
4887        DBG(("%p %p %d closing", conn, nc, conn->endpoint_type));
52534888
5254   // Wait until all threads finish
5255   (void) pthread_mutex_lock(&ctx->mutex);
5256   while (ctx->num_threads > 0) {
5257   (void) pthread_cond_wait(&ctx->cond, &ctx->mutex);
5258   }
5259   (void) pthread_mutex_unlock(&ctx->mutex);
4889        if (conn->endpoint_type == EP_CLIENT && nc->recv_iobuf.len > 0) {
4890          call_http_client_handler(conn);
4891        }
52604892
5261   // All threads exited, no sync is needed. Destroy mutex and condvars
5262   (void) pthread_mutex_destroy(&ctx->mutex);
5263   (void) pthread_cond_destroy(&ctx->cond);
5264   (void) pthread_cond_destroy(&ctx->sq_empty);
5265   (void) pthread_cond_destroy(&ctx->sq_full);
4893        call_user(conn, MG_CLOSE);
4894        close_local_endpoint(conn);
4895        conn->ns_conn = NULL;
4896        free(conn);
4897      }
4898      break;
52664899
5267#if !defined(NO_SSL)
5268   uninitialize_ssl(ctx);
5269#endif
5270   DEBUG_TRACE(("exiting"));
4900    case NS_POLL:
4901      if (call_user(conn, MG_POLL) == MG_TRUE) {
4902        nc->flags |= NSF_FINISHED_SENDING_DATA;
4903      }
52714904
5272   // Signal mg_stop() that we're done.
5273   // WARNING: This must be the very last thing this
5274   // thread does, as ctx becomes invalid after this line.
5275   ctx->stop_flag = 2;
5276   return NULL;
5277}
4905      if (conn != NULL && conn->endpoint_type == EP_FILE) {
4906        transfer_file_data(conn);
4907      }
52784908
5279static void free_context(struct mg_context *ctx) {
5280   int i;
4909      // Expire idle connections
4910      {
4911        time_t current_time = * (time_t *) p;
52814912
5282   // Deallocate config parameters
5283   for (i = 0; i < NUM_OPTIONS; i++) {
5284   if (ctx->config[i] != NULL)
5285      free(ctx->config[i]);
5286   }
4913        if (conn != NULL && conn->mg_conn.is_websocket) {
4914          ping_idle_websocket_connection(conn, current_time);
4915        }
52874916
5288#ifndef NO_SSL
5289   // Deallocate SSL context
5290   if (ctx->ssl_ctx != NULL) {
5291   SSL_CTX_free(ctx->ssl_ctx);
5292   }
5293   if (ssl_mutexes != NULL) {
5294   free(ssl_mutexes);
5295   ssl_mutexes = NULL;
5296   }
5297#endif // !NO_SSL
4917        if (nc->last_io_time + MONGOOSE_IDLE_TIMEOUT_SECONDS < current_time) {
4918          mg_ev_handler(nc, NS_CLOSE, NULL);
4919          nc->flags |= NSF_CLOSE_IMMEDIATELY;
4920        }
4921      }
4922      break;
52984923
5299   // Deallocate context itself
5300   free(ctx);
4924    default:
4925      break;
4926  }
53014927}
53024928
5303void mg_stop(struct mg_context *ctx) {
5304   if (!ctx) return;
5305   ctx->stop_flag = 1;
4929static void iter2(struct ns_connection *nc, enum ns_event ev, void *param) {
4930  mg_handler_t func = NULL;
4931  struct connection *conn = (struct connection *) nc->connection_data;
4932  const char *msg = (const char *) param;
4933  int n;
4934  (void) ev;
53064935
5307   // Wait until mg_fini() stops
5308   while (ctx->stop_flag != 2) {
5309   (void) mg_sleep(10);
5310   }
5311   free_context(ctx);
5312
5313#if defined(_WIN32) && !defined(__SYMBIAN32__)
5314   (void) WSACleanup();
5315#endif // _WIN32
4936  //DBG(("%p [%s]", conn, msg));
4937  if (sscanf(msg, "%p %n", &func, &n) && func != NULL) {
4938    conn->mg_conn.callback_param = (void *) (msg + n);
4939    func(&conn->mg_conn, MG_POLL);
4940  }
53164941}
53174942
5318struct mg_context *mg_start(const struct mg_callbacks *callbacks,
5319                     void *user_data,
5320                     const char **options) {
5321   struct mg_context *ctx;
5322   const char *name, *value, *default_value;
5323   int i;
4943void mg_wakeup_server_ex(struct mg_server *server, mg_handler_t cb,
4944                         const char *fmt, ...) {
4945  va_list ap;
4946  char buf[8 * 1024];
4947  int len;
53244948
5325#if defined(_WIN32) && !defined(__SYMBIAN32__)
5326   WSADATA data;
5327   WSAStartup(MAKEWORD(2,2), &data);
5328   InitializeCriticalSection(&global_log_file_lock);
5329#endif // _WIN32
4949  // Encode callback (cb) into a buffer
4950  len = snprintf(buf, sizeof(buf), "%p ", cb);
4951  va_start(ap, fmt);
4952  len += vsnprintf(buf + len, sizeof(buf) - len, fmt, ap);
4953  va_end(ap);
53304954
5331   // Allocate context and initialize reasonable general case defaults.
5332   // TODO(lsm): do proper error handling here.
5333   if ((ctx = (struct mg_context *) calloc(1, sizeof(*ctx))) == NULL) {
5334   return NULL;
5335   }
5336   ctx->callbacks = *callbacks;
5337   ctx->user_data = user_data;
4955  // "len + 1" is to include terminating \0 in the message
4956  ns_server_wakeup_ex(&server->ns_server, iter2, buf, len + 1);
4957}
53384958
5339   while (options && (name = *options++) != NULL) {
5340   if ((i = get_option_index(name)) == -1) {
5341      cry(fc(ctx), "Invalid option: %s", name);
5342      free_context(ctx);
5343      return NULL;
5344   } else if ((value = *options++) == NULL) {
5345      cry(fc(ctx), "%s: option value cannot be NULL", name);
5346      free_context(ctx);
5347      return NULL;
5348   }
5349   if (ctx->config[i] != NULL) {
5350      cry(fc(ctx), "warning: %s: duplicate option", name);
5351      free(ctx->config[i]);
5352   }
5353   ctx->config[i] = mg_strdup(value);
5354   DEBUG_TRACE(("[%s] -> [%s]", name, value));
5355   }
4959void mg_wakeup_server(struct mg_server *server) {
4960  ns_server_wakeup_ex(&server->ns_server, NULL, (void *) "", 0);
4961}
53564962
5357   // Set default value if needed
5358   for (i = 0; config_options[i * 2] != NULL; i++) {
5359   default_value = config_options[i * 2 + 1];
5360   if (ctx->config[i] == NULL && default_value != NULL) {
5361      ctx->config[i] = mg_strdup(default_value);
5362   }
5363   }
4963void mg_set_listening_socket(struct mg_server *server, int sock) {
4964  if (server->ns_server.listening_sock != INVALID_SOCKET) {
4965    closesocket(server->ns_server.listening_sock);
4966  }
4967  server->ns_server.listening_sock = (sock_t) sock;
4968}
53644969
5365   // NOTE(lsm): order is important here. SSL certificates must
5366   // be initialized before listening ports. UID must be set last.
5367   if (!set_gpass_option(ctx) ||
5368#if !defined(NO_SSL)
5369      !set_ssl_option(ctx) ||
5370#endif
5371      !set_ports_option(ctx) ||
5372#if !defined(_WIN32)
5373      !set_uid_option(ctx) ||
5374#endif
5375      !set_acl_option(ctx)) {
5376   free_context(ctx);
5377   return NULL;
5378   }
4970int mg_get_listening_socket(struct mg_server *server) {
4971  return server->ns_server.listening_sock;
4972}
53794973
5380#if !defined(_WIN32) && !defined(__SYMBIAN32__)
5381   // Ignore SIGPIPE signal, so if browser cancels the request, it
5382   // won't kill the whole process.
5383   (void) signal(SIGPIPE, SIG_IGN);
5384   // Also ignoring SIGCHLD to let the OS to reap zombies properly.
5385   (void) signal(SIGCHLD, SIG_IGN);
5386#endif // !_WIN32
4974const char *mg_get_option(const struct mg_server *server, const char *name) {
4975  const char **opts = (const char **) server->config_options;
4976  int i = get_option_index(name);
4977  return i == -1 ? NULL : opts[i] == NULL ? "" : opts[i];
4978}
53874979
5388   (void) pthread_mutex_init(&ctx->mutex, NULL);
5389   (void) pthread_cond_init(&ctx->cond, NULL);
5390   (void) pthread_cond_init(&ctx->sq_empty, NULL);
5391   (void) pthread_cond_init(&ctx->sq_full, NULL);
5392
5393   // Start master (listening) thread
5394   mg_start_thread(master_thread, ctx);
5395
5396   // Start worker threads
5397   for (i = 0; i < atoi(ctx->config[NUM_THREADS]); i++) {
5398   if (mg_start_thread(worker_thread, ctx) != 0) {
5399      cry(fc(ctx), "Cannot start worker thread: %ld", (long) ERRNO);
5400   } else {
5401      ctx->num_threads++;
5402   }
5403   }
5404
5405   return ctx;
4980struct mg_server *mg_create_server(void *server_data, mg_handler_t handler) {
4981  struct mg_server *server = (struct mg_server *) calloc(1, sizeof(*server));
4982  ns_server_init(&server->ns_server, server_data, mg_ev_handler);
4983  set_default_option_values(server->config_options);
4984  server->event_handler = handler;
4985  return server;
54064986}

Previous 199869 Revisions Next


© 1997-2024 The MAME Team