1 // Copyright (c) 2004-2013 Sergey Lyubka <valenok@gmail.com>
2 // Copyright (c) 2013-2014 Cesanta Software Limited
3 // All rights reserved
4 //
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/>.
9 //
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.
14 //
15 // Alternatively, you can license this library under a commercial
16 // license, as set out in <http://cesanta.com/>.
17 
18 #ifdef NOEMBED_NET_SKELETON
19 #include "net_skeleton.h"
20 #else
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/>.
37 
38 #ifndef NS_SKELETON_HEADER_INCLUDED
39 #define NS_SKELETON_HEADER_INCLUDED
40 
41 #define NS_SKELETON_VERSION "2.1.0"
42 
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 #ifdef __Linux__
50 #define _XOPEN_SOURCE 600       // For flockfile() on Linux
51 #endif
52 #define __STDC_FORMAT_MACROS    // <inttypes.h> wants this for C++
53 #define __STDC_LIMIT_MACROS     // C++ wants that for INT64_MAX
54 #ifndef _LARGEFILE_SOURCE
55 #define _LARGEFILE_SOURCE       // Enable fseeko() and ftello() functions
56 #endif
57 #define _FILE_OFFSET_BITS 64    // Enable 64-bit file offsets
58 
59 #ifdef _MSC_VER
60 #pragma warning (disable : 4127)  // FD_SET() emits warning, disable it
61 #pragma warning (disable : 4204)  // missing c99 support
62 #endif
63 
64 #include <sys/types.h>
65 #include <sys/stat.h>
66 #include <assert.h>
67 #include <ctype.h>
68 #include <errno.h>
69 #include <fcntl.h>
70 #include <stdarg.h>
71 #include <stddef.h>
72 #include <stdio.h>
73 #include <stdlib.h>
74 #include <string.h>
75 #include <time.h>
76 #include <signal.h>
77 
78 #ifdef _WIN32
79 #ifdef _MSC_VER
80 #pragma comment(lib, "ws2_32.lib")    // Linking with winsock library
81 #include <BaseTsd.h>
82 typedef SSIZE_T ssize_t;
83 #endif
84 #include <winsock2.h>
85 #include <ws2tcpip.h>
86 #include <windows.h>
87 #include <process.h>
88 #ifndef EINPROGRESS
89 #define EINPROGRESS WSAEINPROGRESS
90 #endif
91 #ifndef EWOULDBLOCK
92 #define EWOULDBLOCK WSAEWOULDBLOCK
93 #endif
94 #ifndef __func__
95 #define STRX(x) #x
96 #define STR(x) STRX(x)
97 #define __func__ __FILE__ ":" STR(__LINE__)
98 #endif
99 #ifndef va_copy
100 #define va_copy(x,y) x = y
101 #endif // MINGW #defines va_copy
102 #define snprintf _snprintf
103 #define vsnprintf _vsnprintf
104 #define sleep(x) Sleep((x) * 1000)
105 #define to64(x) _atoi64(x)
106 typedef int socklen_t;
107 typedef unsigned char uint8_t;
108 typedef unsigned int uint32_t;
109 typedef unsigned short uint16_t;
110 typedef unsigned __int64 uint64_t;
111 typedef __int64   int64_t;
112 typedef SOCKET sock_t;
113 typedef struct _stati64 ns_stat_t;
114 #ifndef S_ISDIR
115 #define S_ISDIR(x) ((x) & _S_IFDIR)
116 #endif
117 #else
118 #include <errno.h>
119 #include <fcntl.h>
120 #include <netdb.h>
121 #include <pthread.h>
122 #include <stdarg.h>
123 #include <unistd.h>
124 #include <arpa/inet.h>  // For inet_pton() when NS_ENABLE_IPV6 is defined
125 #include <netinet/in.h>
126 #include <sys/socket.h>
127 #include <sys/select.h>
128 #define closesocket(x) close(x)
129 #ifndef __OS2__
130 #define __cdecl
131 #else
132 #include <sys/time.h>
133 typedef int socklen_t;
134 #endif
135 #define INVALID_SOCKET (-1)
136 #define to64(x) strtoll(x, NULL, 10)
137 typedef int sock_t;
138 typedef struct stat ns_stat_t;
139 #endif
140 
141 #ifdef NS_ENABLE_DEBUG
142 #define DBG(x) do { printf("%-20s ", __func__); printf x; putchar('\n'); \
143   fflush(stdout); } while(0)
144 #else
145 #define DBG(x)
146 #endif
147 
148 #ifndef ARRAY_SIZE
149 #define ARRAY_SIZE(array) (sizeof(array) / sizeof(array[0]))
150 #endif
151 
152 #ifdef NS_ENABLE_SSL
153 #ifdef __APPLE__
154 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
155 #endif
156 #include <openssl/ssl.h>
157 #else
158 typedef void *SSL;
159 typedef void *SSL_CTX;
160 #endif
161 
162 #ifdef __cplusplus
163 extern "C" {
164 #endif // __cplusplus
165 
166 union socket_address {
167   struct sockaddr sa;
168   struct sockaddr_in sin;
169 #ifdef NS_ENABLE_IPV6
170   struct sockaddr_in6 sin6;
171 #else
172   struct sockaddr sin6;
173 #endif
174 };
175 
176 // Describes chunk of memory
177 struct ns_str {
178   const char *p;
179   size_t len;
180 };
181 
182 // IO buffers interface
183 struct iobuf {
184   char *buf;
185   size_t len;
186   size_t size;
187 };
188 
189 void iobuf_init(struct iobuf *, size_t initial_size);
190 void iobuf_free(struct iobuf *);
191 size_t iobuf_append(struct iobuf *, const void *data, size_t data_size);
192 void iobuf_remove(struct iobuf *, size_t data_size);
193 void iobuf_resize(struct iobuf *, size_t new_size);
194 
195 // Callback function (event handler) prototype, must be defined by user.
196 // Net skeleton will call event handler, passing events defined above.
197 struct ns_connection;
198 typedef void (*ns_callback_t)(struct ns_connection *, int event_num, void *evp);
199 
200 // Events. Meaning of event parameter (evp) is given in the comment.
201 #define NS_POLL    0  // Sent to each connection on each call to ns_mgr_poll()
202 #define NS_ACCEPT  1  // New connection accept()-ed. union socket_address *addr
203 #define NS_CONNECT 2  // connect() succeeded or failed. int *success_status
204 #define NS_RECV    3  // Data has benn received. int *num_bytes
205 #define NS_SEND    4  // Data has been written to a socket. int *num_bytes
206 #define NS_CLOSE   5  // Connection is closed. NULL
207 
208 
209 struct ns_mgr {
210   struct ns_connection *active_connections;
211   const char *hexdump_file;         // Debug hexdump file path
212   sock_t ctl[2];                    // Socketpair for mg_wakeup()
213   void *user_data;                  // User data
214 };
215 
216 
217 struct ns_connection {
218   struct ns_connection *next, *prev;  // ns_mgr::active_connections linkage
219   struct ns_connection *listener;     // Set only for accept()-ed connections
220   struct ns_mgr *mgr;
221 
222   sock_t sock;                // Socket
223   union socket_address sa;    // Peer address
224   struct iobuf recv_iobuf;    // Received data
225   struct iobuf send_iobuf;    // Data scheduled for sending
226   SSL *ssl;
227   SSL_CTX *ssl_ctx;
228   void *user_data;            // User-specific data
229   void *proto_data;           // Application protocol-specific data
230   time_t last_io_time;        // Timestamp of the last socket IO
231   ns_callback_t callback;     // Event handler function
232 
233   unsigned int flags;
234 #define NSF_FINISHED_SENDING_DATA   (1 << 0)
235 #define NSF_BUFFER_BUT_DONT_SEND    (1 << 1)
236 #define NSF_SSL_HANDSHAKE_DONE      (1 << 2)
237 #define NSF_CONNECTING              (1 << 3)
238 #define NSF_CLOSE_IMMEDIATELY       (1 << 4)
239 #define NSF_WANT_READ               (1 << 5)
240 #define NSF_WANT_WRITE              (1 << 6)
241 #define NSF_LISTENING               (1 << 7)
242 #define NSF_UDP                     (1 << 8)
243 
244 #define NSF_USER_1                  (1 << 20)
245 #define NSF_USER_2                  (1 << 21)
246 #define NSF_USER_3                  (1 << 22)
247 #define NSF_USER_4                  (1 << 23)
248 #define NSF_USER_5                  (1 << 24)
249 #define NSF_USER_6                  (1 << 25)
250 };
251 
252 void ns_mgr_init(struct ns_mgr *, void *user_data);
253 void ns_mgr_free(struct ns_mgr *);
254 time_t ns_mgr_poll(struct ns_mgr *, int milli);
255 void ns_broadcast(struct ns_mgr *, ns_callback_t, void *, size_t);
256 
257 struct ns_connection *ns_next(struct ns_mgr *, struct ns_connection *);
258 struct ns_connection *ns_add_sock(struct ns_mgr *, sock_t,
259                                   ns_callback_t, void *);
260 struct ns_connection *ns_bind(struct ns_mgr *, const char *,
261                               ns_callback_t, void *);
262 struct ns_connection *ns_connect(struct ns_mgr *, const char *,
263                                  ns_callback_t, void *);
264 
265 int ns_send(struct ns_connection *, const void *buf, size_t len);
266 int ns_printf(struct ns_connection *, const char *fmt, ...);
267 int ns_vprintf(struct ns_connection *, const char *fmt, va_list ap);
268 
269 // Utility functions
270 void *ns_start_thread(void *(*f)(void *), void *p);
271 int ns_socketpair(sock_t [2]);
272 int ns_socketpair2(sock_t [2], int sock_type);  // SOCK_STREAM or SOCK_DGRAM
273 void ns_set_close_on_exec(sock_t);
274 void ns_sock_to_str(sock_t sock, char *buf, size_t len, int flags);
275 int ns_hexdump(const void *buf, int len, char *dst, int dst_len);
276 int ns_avprintf(char **buf, size_t size, const char *fmt, va_list ap);
277 int ns_resolve(const char *domain_name, char *ip_addr_buf, size_t buf_len);
278 
279 #ifdef __cplusplus
280 }
281 #endif // __cplusplus
282 
283 #endif // NS_SKELETON_HEADER_INCLUDED
284 // Copyright (c) 2014 Cesanta Software Limited
285 // All rights reserved
286 //
287 // This software is dual-licensed: you can redistribute it and/or modify
288 // it under the terms of the GNU General Public License version 2 as
289 // published by the Free Software Foundation. For the terms of this
290 // license, see <http://www.gnu.org/licenses/>.
291 //
292 // You are free to use this software under the terms of the GNU General
293 // Public License, but WITHOUT ANY WARRANTY; without even the implied
294 // warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
295 // See the GNU General Public License for more details.
296 //
297 // Alternatively, you can license this software under a commercial
298 // license, as set out in <http://cesanta.com/>.
299 //
300 // $Date: 2014-09-28 05:04:41 UTC $
301 
302 
303 #ifndef NS_MALLOC
304 #define NS_MALLOC malloc
305 #endif
306 
307 #ifndef NS_REALLOC
308 #define NS_REALLOC realloc
309 #endif
310 
311 #ifndef NS_FREE
312 #define NS_FREE free
313 #endif
314 
315 #ifndef NS_CALLOC
316 #define NS_CALLOC calloc
317 #endif
318 
319 #define NS_CTL_MSG_MESSAGE_SIZE     (8 * 1024)
320 #define NS_READ_BUFFER_SIZE         2048
321 #define NS_UDP_RECEIVE_BUFFER_SIZE  2000
322 #define NS_VPRINTF_BUFFER_SIZE      500
323 
324 struct ctl_msg {
325   ns_callback_t callback;
326   char message[NS_CTL_MSG_MESSAGE_SIZE];
327 };
328 
329 void iobuf_resize(struct iobuf *io, size_t new_size) {
330   char *p;
331   if ((new_size > io->size || (new_size < io->size && new_size >= io->len)) &&
332       (p = (char *) NS_REALLOC(io->buf, new_size)) != NULL) {
333     io->size = new_size;
334     io->buf = p;
335   }
336 }
337 
338 void iobuf_init(struct iobuf *iobuf, size_t initial_size) {
339   iobuf->len = iobuf->size = 0;
340   iobuf->buf = NULL;
341   iobuf_resize(iobuf, initial_size);
342 }
343 
344 void iobuf_free(struct iobuf *iobuf) {
345   if (iobuf != NULL) {
346     if (iobuf->buf != NULL) NS_FREE(iobuf->buf);
347     iobuf_init(iobuf, 0);
348   }
349 }
350 
351 size_t iobuf_append(struct iobuf *io, const void *buf, size_t len) {
352   char *p = NULL;
353 
354   assert(io != NULL);
355   assert(io->len <= io->size);
356 
357   /* check overflow */
358   if (len > ~(size_t)0 - (size_t)(io->buf + io->len)) {
359     return 0;
360   }
361 
362   if (len <= 0) {
363   } else if (io->len + len <= io->size) {
364     memcpy(io->buf + io->len, buf, len);
365     io->len += len;
366   } else if ((p = (char *) NS_REALLOC(io->buf, io->len + len)) != NULL) {
367     io->buf = p;
368     memcpy(io->buf + io->len, buf, len);
369     io->len += len;
370     io->size = io->len;
371   } else {
372     len = 0;
373   }
374 
375   return len;
376 }
377 
378 void iobuf_remove(struct iobuf *io, size_t n) {
379   if (n > 0 && n <= io->len) {
380     memmove(io->buf, io->buf + n, io->len - n);
381     io->len -= n;
382   }
383 }
384 
385 static size_t ns_out(struct ns_connection *nc, const void *buf, size_t len) {
386   if (nc->flags & NSF_UDP) {
387     long n = sendto(nc->sock, (const char *) buf, len, 0, &nc->sa.sa,
388                     sizeof(nc->sa.sin));
389     DBG(("%p %d send %ld (%d %s)", nc, nc->sock, n, errno, strerror(errno)));
390     return n < 0 ? 0 : n;
391   } else {
392     return iobuf_append(&nc->send_iobuf, buf, len);
393   }
394 }
395 
396 #ifndef NS_DISABLE_THREADS
397 void *ns_start_thread(void *(*f)(void *), void *p) {
398 #ifdef _WIN32
399   return (void *) _beginthread((void (__cdecl *)(void *)) f, 0, p);
400 #else
401   pthread_t thread_id = (pthread_t) 0;
402   pthread_attr_t attr;
403 
404   (void) pthread_attr_init(&attr);
405   (void) pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
406 
407 #if defined(NS_STACK_SIZE) && NS_STACK_SIZE > 1
408   (void) pthread_attr_setstacksize(&attr, NS_STACK_SIZE);
409 #endif
410 
411   pthread_create(&thread_id, &attr, f, p);
412   pthread_attr_destroy(&attr);
413 
414   return (void *) thread_id;
415 #endif
416 }
417 #endif  // NS_DISABLE_THREADS
418 
419 static void ns_add_conn(struct ns_mgr *mgr, struct ns_connection *c) {
420   c->next = mgr->active_connections;
421   mgr->active_connections = c;
422   c->prev = NULL;
423   if (c->next != NULL) c->next->prev = c;
424 }
425 
426 static void ns_remove_conn(struct ns_connection *conn) {
427   if (conn->prev == NULL) conn->mgr->active_connections = conn->next;
428   if (conn->prev) conn->prev->next = conn->next;
429   if (conn->next) conn->next->prev = conn->prev;
430 }
431 
432 // Print message to buffer. If buffer is large enough to hold the message,
433 // return buffer. If buffer is to small, allocate large enough buffer on heap,
434 // and return allocated buffer.
435 int ns_avprintf(char **buf, size_t size, const char *fmt, va_list ap) {
436   va_list ap_copy;
437   int len;
438 
439   va_copy(ap_copy, ap);
440   len = vsnprintf(*buf, size, fmt, ap_copy);
441   va_end(ap_copy);
442 
443   if (len < 0) {
444     // eCos and Windows are not standard-compliant and return -1 when
445     // the buffer is too small. Keep allocating larger buffers until we
446     // succeed or out of memory.
447     *buf = NULL;
448     while (len < 0) {
449       if (*buf) NS_FREE(*buf);
450       size *= 2;
451       if ((*buf = (char *) NS_MALLOC(size)) == NULL) break;
452       va_copy(ap_copy, ap);
453       len = vsnprintf(*buf, size, fmt, ap_copy);
454       va_end(ap_copy);
455     }
456   } else if (len > (int) size) {
457     // Standard-compliant code path. Allocate a buffer that is large enough.
458     if ((*buf = (char *) NS_MALLOC(len + 1)) == NULL) {
459       len = -1;
460     } else {
461       va_copy(ap_copy, ap);
462       len = vsnprintf(*buf, len + 1, fmt, ap_copy);
463       va_end(ap_copy);
464     }
465   }
466 
467   return len;
468 }
469 
470 int ns_vprintf(struct ns_connection *nc, const char *fmt, va_list ap) {
471   char mem[NS_VPRINTF_BUFFER_SIZE], *buf = mem;
472   int len;
473 
474   if ((len = ns_avprintf(&buf, sizeof(mem), fmt, ap)) > 0) {
475     ns_out(nc, buf, len);
476   }
477   if (buf != mem && buf != NULL) {
478     NS_FREE(buf);
479   }
480 
481   return len;
482 }
483 
484 int ns_printf(struct ns_connection *conn, const char *fmt, ...) {
485   int len;
486   va_list ap;
487   va_start(ap, fmt);
488   len = ns_vprintf(conn, fmt, ap);
489   va_end(ap);
490   return len;
491 }
492 
493 static void hexdump(struct ns_connection *nc, const char *path,
494                     int num_bytes, int ev) {
495   const struct iobuf *io = ev == NS_SEND ? &nc->send_iobuf : &nc->recv_iobuf;
496   FILE *fp;
497   char *buf, src[60], dst[60];
498   int buf_size = num_bytes * 5 + 100;
499 
500   if ((fp = fopen(path, "a")) != NULL) {
501     ns_sock_to_str(nc->sock, src, sizeof(src), 3);
502     ns_sock_to_str(nc->sock, dst, sizeof(dst), 7);
503     fprintf(fp, "%lu %p %s %s %s %d\n", (unsigned long) time(NULL),
504             nc->user_data, src,
505             ev == NS_RECV ? "<-" : ev == NS_SEND ? "->" :
506             ev == NS_ACCEPT ? "<A" : ev == NS_CONNECT ? "C>" : "XX",
507             dst, num_bytes);
508     if (num_bytes > 0 && (buf = (char *) NS_MALLOC(buf_size)) != NULL) {
509       ns_hexdump(io->buf + (ev == NS_SEND ? 0 : io->len) -
510         (ev == NS_SEND ? 0 : num_bytes), num_bytes, buf, buf_size);
511       fprintf(fp, "%s", buf);
512       NS_FREE(buf);
513     }
514     fclose(fp);
515   }
516 }
517 
518 static void ns_call(struct ns_connection *nc, int ev, void *p) {
519   if (nc->mgr->hexdump_file != NULL && ev != NS_POLL) {
520     int len = (ev == NS_RECV || ev == NS_SEND) ? * (int *) p : 0;
521     hexdump(nc, nc->mgr->hexdump_file, len, ev);
522   }
523 
524   nc->callback(nc, ev, p);
525 }
526 
527 static void ns_destroy_conn(struct ns_connection *conn) {
528   closesocket(conn->sock);
529   iobuf_free(&conn->recv_iobuf);
530   iobuf_free(&conn->send_iobuf);
531 #ifdef NS_ENABLE_SSL
532   if (conn->ssl != NULL) {
533     SSL_free(conn->ssl);
534   }
535   if (conn->ssl_ctx != NULL) {
536     SSL_CTX_free(conn->ssl_ctx);
537   }
538 #endif
539   NS_FREE(conn);
540 }
541 
542 static void ns_close_conn(struct ns_connection *conn) {
543   DBG(("%p %d", conn, conn->flags));
544   ns_call(conn, NS_CLOSE, NULL);
545   ns_remove_conn(conn);
546   ns_destroy_conn(conn);
547 }
548 
549 void ns_set_close_on_exec(sock_t sock) {
550 #ifdef _WIN32
551   (void) SetHandleInformation((HANDLE) sock, HANDLE_FLAG_INHERIT, 0);
552 #else
553   fcntl(sock, F_SETFD, FD_CLOEXEC);
554 #endif
555 }
556 
557 static void ns_set_non_blocking_mode(sock_t sock) {
558 #ifdef _WIN32
559   unsigned long on = 1;
560   ioctlsocket(sock, FIONBIO, &on);
561 #else
562   int flags = fcntl(sock, F_GETFL, 0);
563   fcntl(sock, F_SETFL, flags | O_NONBLOCK);
564 #endif
565 }
566 
567 #ifndef NS_DISABLE_SOCKETPAIR
568 int ns_socketpair2(sock_t sp[2], int sock_type) {
569   union socket_address sa;
570   sock_t sock;
571   socklen_t len = sizeof(sa.sin);
572   int ret = 0;
573 
574   sp[0] = sp[1] = INVALID_SOCKET;
575 
576   (void) memset(&sa, 0, sizeof(sa));
577   sa.sin.sin_family = AF_INET;
578   sa.sin.sin_port = htons(0);
579   sa.sin.sin_addr.s_addr = htonl(0x7f000001);
580 
581   if ((sock = socket(AF_INET, sock_type, 0)) != INVALID_SOCKET &&
582       !bind(sock, &sa.sa, len) &&
583       (sock_type == SOCK_DGRAM || !listen(sock, 1)) &&
584       !getsockname(sock, &sa.sa, &len) &&
585       (sp[0] = socket(AF_INET, sock_type, 0)) != INVALID_SOCKET &&
586       !connect(sp[0], &sa.sa, len) &&
587       (sock_type == SOCK_STREAM ||
588        (!getsockname(sp[0], &sa.sa, &len) && !connect(sock, &sa.sa, len))) &&
589       (sp[1] = (sock_type == SOCK_DGRAM ? sock :
590                 accept(sock, &sa.sa, &len))) != INVALID_SOCKET) {
591     ns_set_close_on_exec(sp[0]);
592     ns_set_close_on_exec(sp[1]);
593     ret = 1;
594   } else {
595     if (sp[0] != INVALID_SOCKET) closesocket(sp[0]);
596     if (sp[1] != INVALID_SOCKET) closesocket(sp[1]);
597     sp[0] = sp[1] = INVALID_SOCKET;
598   }
599   if (sock_type != SOCK_DGRAM) closesocket(sock);
600 
601   return ret;
602 }
603 
604 int ns_socketpair(sock_t sp[2]) {
605   return ns_socketpair2(sp, SOCK_STREAM);
606 }
607 #endif  // NS_DISABLE_SOCKETPAIR
608 
609 // TODO(lsm): use non-blocking resolver
610 static int ns_resolve2(const char *host, struct in_addr *ina) {
611 #ifdef NS_ENABLE_GETADDRINFO
612   int rv = 0;
613   struct addrinfo hints, *servinfo, *p;
614   struct sockaddr_in *h = NULL;
615   char *ip = NS_MALLOC(17);
616   memset(ip, '\0', 17);
617 
618   memset(&hints, 0, sizeof hints);
619   hints.ai_family = AF_INET;
620   hints.ai_socktype = SOCK_STREAM;
621 
622   if((rv = getaddrinfo(host, NULL , NULL, &servinfo)) != 0) {
623     DBG(("getaddrinfo(%s) failed: %s", host, strerror(errno)));
624     return 0;
625   }
626 
627   for(p = servinfo; p != NULL; p = p->ai_next) {
628     memcpy(&h, &p->ai_addr, sizeof(struct sockaddr_in *));
629     memcpy(ina, &h->sin_addr, sizeof(ina));
630   }
631 
632   freeaddrinfo(servinfo);
633   return 1;
634 #else
635   struct hostent *he;
636   if ((he = gethostbyname(host)) == NULL) {
637     DBG(("gethostbyname(%s) failed: %s", host, strerror(errno)));
638   } else {
639     memcpy(ina, he->h_addr_list[0], sizeof(*ina));
640     return 1;
641   }
642   return 0;
643 #endif
644 }
645 
646 // Resolve FDQN "host", store IP address in the "ip".
647 // Return > 0 (IP address length) on success.
648 int ns_resolve(const char *host, char *buf, size_t n) {
649   struct in_addr ad;
650   return ns_resolve2(host, &ad) ? snprintf(buf, n, "%s", inet_ntoa(ad)) : 0;
651 }
652 
653 // Address format: [PROTO://][IP_ADDRESS:]PORT[:CERT][:CA_CERT]
654 static int ns_parse_address(const char *str, union socket_address *sa,
655                             int *proto, int *use_ssl, char *cert, char *ca) {
656   unsigned int a, b, c, d, port;
657   int n = 0, len = 0;
658   char host[200];
659 #ifdef NS_ENABLE_IPV6
660   char buf[100];
661 #endif
662 
663   // MacOS needs that. If we do not zero it, subsequent bind() will fail.
664   // Also, all-zeroes in the socket address means binding to all addresses
665   // for both IPv4 and IPv6 (INADDR_ANY and IN6ADDR_ANY_INIT).
666   memset(sa, 0, sizeof(*sa));
667   sa->sin.sin_family = AF_INET;
668 
669   *proto = SOCK_STREAM;
670   *use_ssl = 0;
671   cert[0] = ca[0] = '\0';
672 
673   if (memcmp(str, "ssl://", 6) == 0) {
674     str += 6;
675     *use_ssl = 1;
676   } else if (memcmp(str, "udp://", 6) == 0) {
677     str += 6;
678     *proto = SOCK_DGRAM;
679   } else if (memcmp(str, "tcp://", 6) == 0) {
680     str += 6;
681   }
682 
683   if (sscanf(str, "%u.%u.%u.%u:%u%n", &a, &b, &c, &d, &port, &len) == 5) {
684     // Bind to a specific IPv4 address, e.g. 192.168.1.5:8080
685     sa->sin.sin_addr.s_addr = htonl((a << 24) | (b << 16) | (c << 8) | d);
686     sa->sin.sin_port = htons((uint16_t) port);
687 #ifdef NS_ENABLE_IPV6
688   } else if (sscanf(str, "[%99[^]]]:%u%n", buf, &port, &len) == 2 &&
689              inet_pton(AF_INET6, buf, &sa->sin6.sin6_addr)) {
690     // IPv6 address, e.g. [3ffe:2a00:100:7031::1]:8080
691     sa->sin6.sin6_family = AF_INET6;
692     sa->sin6.sin6_port = htons((uint16_t) port);
693 #endif
694   } else if (sscanf(str, "%199[^ :]:%u%n", host, &port, &len) == 2) {
695     sa->sin.sin_port = htons((uint16_t) port);
696     ns_resolve2(host, &sa->sin.sin_addr);
697   } else if (sscanf(str, "%u%n", &port, &len) == 1) {
698     // If only port is specified, bind to IPv4, INADDR_ANY
699     sa->sin.sin_port = htons((uint16_t) port);
700   }
701 
702   if (*use_ssl && (sscanf(str + len, ":%99[^:,]:%99[^:,]%n", cert, ca, &n) == 2 ||
703                    sscanf(str + len, ":%99[^:,]%n", cert, &n) == 1)) {
704     len += n;
705   }
706 
707   return port < 0xffff && str[len] == '\0' ? len : 0;
708 }
709 
710 // 'sa' must be an initialized address to bind to
711 static sock_t ns_open_listening_socket(union socket_address *sa, int proto) {
712   socklen_t sa_len = (sa->sa.sa_family == AF_INET) ?
713     sizeof(sa->sin) : sizeof(sa->sin6);
714   sock_t sock = INVALID_SOCKET;
715 #ifndef _WIN32
716   int on = 1;
717 #endif
718 
719   if ((sock = socket(sa->sa.sa_family, proto, 0)) != INVALID_SOCKET &&
720 #ifndef _WIN32
721       // SO_RESUSEADDR is not enabled on Windows because the semantics of
722       // SO_REUSEADDR on UNIX and Windows is different. On Windows,
723       // SO_REUSEADDR allows to bind a socket to a port without error even if
724       // the port is already open by another program. This is not the behavior
725       // SO_REUSEADDR was designed for, and leads to hard-to-track failure
726       // scenarios. Therefore, SO_REUSEADDR was disabled on Windows.
727       !setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void *) &on, sizeof(on)) &&
728 #endif
729       !bind(sock, &sa->sa, sa_len) &&
730       (proto == SOCK_DGRAM || listen(sock, SOMAXCONN) == 0)) {
731     ns_set_non_blocking_mode(sock);
732     // In case port was set to 0, get the real port number
733     (void) getsockname(sock, &sa->sa, &sa_len);
734   } else if (sock != INVALID_SOCKET) {
735     closesocket(sock);
736     sock = INVALID_SOCKET;
737   }
738 
739   return sock;
740 }
741 
742 #ifdef NS_ENABLE_SSL
743 // Certificate generation script is at
744 // https://github.com/cesanta/net_skeleton/blob/master/scripts/gen_certs.sh
745 
746 static int ns_use_ca_cert(SSL_CTX *ctx, const char *cert) {
747   if (ctx == NULL) {
748     return -1;
749   } else if (cert == NULL || cert[0] == '\0') {
750     return 0;
751   }
752   SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, 0);
753   return SSL_CTX_load_verify_locations(ctx, cert, NULL) == 1 ? 0 : -2;
754 }
755 
756 static int ns_use_cert(SSL_CTX *ctx, const char *pem_file) {
757   if (ctx == NULL) {
758     return -1;
759   } else if (pem_file == NULL || pem_file[0] == '\0') {
760     return 0;
761   } else if (SSL_CTX_use_certificate_file(ctx, pem_file, 1) == 0 ||
762              SSL_CTX_use_PrivateKey_file(ctx, pem_file, 1) == 0) {
763     return -2;
764   } else {
765     SSL_CTX_set_mode(ctx, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
766     SSL_CTX_use_certificate_chain_file(ctx, pem_file);
767     return 0;
768   }
769 }
770 #endif  // NS_ENABLE_SSL
771 
772 struct ns_connection *ns_bind(struct ns_mgr *srv, const char *str,
773                               ns_callback_t callback, void *user_data) {
774   union socket_address sa;
775   struct ns_connection *nc = NULL;
776   int use_ssl, proto;
777   char cert[100], ca_cert[100];
778   sock_t sock;
779 
780   ns_parse_address(str, &sa, &proto, &use_ssl, cert, ca_cert);
781   if (use_ssl && cert[0] == '\0') return NULL;
782 
783   if ((sock = ns_open_listening_socket(&sa, proto)) == INVALID_SOCKET) {
784   } else if ((nc = ns_add_sock(srv, sock, callback, NULL)) == NULL) {
785     closesocket(sock);
786   } else {
787     nc->sa = sa;
788     nc->flags |= NSF_LISTENING;
789     nc->user_data = user_data;
790     nc->callback = callback;
791 
792     if (proto == SOCK_DGRAM) {
793       nc->flags |= NSF_UDP;
794     }
795 
796 #ifdef NS_ENABLE_SSL
797     if (use_ssl) {
798       nc->ssl_ctx = SSL_CTX_new(SSLv23_server_method());
799       if (ns_use_cert(nc->ssl_ctx, cert) != 0 ||
800           ns_use_ca_cert(nc->ssl_ctx, ca_cert) != 0) {
801         ns_close_conn(nc);
802         nc = NULL;
803       }
804     }
805 #endif
806 
807     DBG(("%p sock %d/%d ssl %p %p", nc, sock, proto, nc->ssl_ctx, nc->ssl));
808   }
809 
810   return nc;
811 }
812 
813 static struct ns_connection *accept_conn(struct ns_connection *ls) {
814   struct ns_connection *c = NULL;
815   union socket_address sa;
816   socklen_t len = sizeof(sa);
817   sock_t sock = INVALID_SOCKET;
818 
819   // NOTE(lsm): on Windows, sock is always > FD_SETSIZE
820   if ((sock = accept(ls->sock, &sa.sa, &len)) == INVALID_SOCKET) {
821   } else if ((c = ns_add_sock(ls->mgr, sock, ls->callback,
822               ls->user_data)) == NULL) {
823     closesocket(sock);
824 #ifdef NS_ENABLE_SSL
825   } else if (ls->ssl_ctx != NULL &&
826              ((c->ssl = SSL_new(ls->ssl_ctx)) == NULL ||
827               SSL_set_fd(c->ssl, sock) != 1)) {
828     DBG(("SSL error"));
829     ns_close_conn(c);
830     c = NULL;
831 #endif
832   } else {
833     c->listener = ls;
834     c->proto_data = ls->proto_data;
835     ns_call(c, NS_ACCEPT, &sa);
836     DBG(("%p %d %p %p", c, c->sock, c->ssl_ctx, c->ssl));
837   }
838 
839   return c;
840 }
841 
842 static int ns_is_error(int n) {
843   return n == 0 ||
844     (n < 0 && errno != EINTR && errno != EINPROGRESS &&
845      errno != EAGAIN && errno != EWOULDBLOCK
846 #ifdef _WIN32
847      && WSAGetLastError() != WSAEINTR && WSAGetLastError() != WSAEWOULDBLOCK
848 #endif
849     );
850 }
851 
852 void ns_sock_to_str(sock_t sock, char *buf, size_t len, int flags) {
853   union socket_address sa;
854   socklen_t slen = sizeof(sa);
855 
856   if (buf != NULL && len > 0) {
857     buf[0] = '\0';
858     memset(&sa, 0, sizeof(sa));
859     if (flags & 4) {
860       getpeername(sock, &sa.sa, &slen);
861     } else {
862       getsockname(sock, &sa.sa, &slen);
863     }
864     if (flags & 1) {
865 #if defined(NS_ENABLE_IPV6)
866       inet_ntop(sa.sa.sa_family, sa.sa.sa_family == AF_INET ?
867                 (void *) &sa.sin.sin_addr :
868                 (void *) &sa.sin6.sin6_addr, buf, len);
869 #elif defined(_WIN32)
870       // Only Windoze Vista (and newer) have inet_ntop()
871       strncpy(buf, inet_ntoa(sa.sin.sin_addr), len);
872 #else
873       inet_ntop(sa.sa.sa_family, (void *) &sa.sin.sin_addr, buf,(socklen_t)len);
874 #endif
875     }
876     if (flags & 2) {
877       snprintf(buf + strlen(buf), len - (strlen(buf) + 1), "%s%d",
878                flags & 1 ? ":" : "", (int) ntohs(sa.sin.sin_port));
879     }
880   }
881 }
882 
883 int ns_hexdump(const void *buf, int len, char *dst, int dst_len) {
884   const unsigned char *p = (const unsigned char *) buf;
885   char ascii[17] = "";
886   int i, idx, n = 0;
887 
888   for (i = 0; i < len; i++) {
889     idx = i % 16;
890     if (idx == 0) {
891       if (i > 0) n += snprintf(dst + n, dst_len - n, "  %s\n", ascii);
892       n += snprintf(dst + n, dst_len - n, "%04x ", i);
893     }
894     n += snprintf(dst + n, dst_len - n, " %02x", p[i]);
895     ascii[idx] = p[i] < 0x20 || p[i] > 0x7e ? '.' : p[i];
896     ascii[idx + 1] = '\0';
897   }
898 
899   while (i++ % 16) n += snprintf(dst + n, dst_len - n, "%s", "   ");
900   n += snprintf(dst + n, dst_len - n, "  %s\n\n", ascii);
901 
902   return n;
903 }
904 
905 #ifdef NS_ENABLE_SSL
906 static int ns_ssl_err(struct ns_connection *conn, int res) {
907   int ssl_err = SSL_get_error(conn->ssl, res);
908   if (ssl_err == SSL_ERROR_WANT_READ) conn->flags |= NSF_WANT_READ;
909   if (ssl_err == SSL_ERROR_WANT_WRITE) conn->flags |= NSF_WANT_WRITE;
910   return ssl_err;
911 }
912 #endif
913 
914 static void ns_read_from_socket(struct ns_connection *conn) {
915   char buf[NS_READ_BUFFER_SIZE];
916   int n = 0;
917 
918   if (conn->flags & NSF_CONNECTING) {
919     int ok = 1, ret;
920     socklen_t len = sizeof(ok);
921 
922     ret = getsockopt(conn->sock, SOL_SOCKET, SO_ERROR, (char *) &ok, &len);
923     (void) ret;
924 #ifdef NS_ENABLE_SSL
925     if (ret == 0 && ok == 0 && conn->ssl != NULL) {
926       int res = SSL_connect(conn->ssl);
927       int ssl_err = ns_ssl_err(conn, res);
928       if (res == 1) {
929         conn->flags |= NSF_SSL_HANDSHAKE_DONE;
930       } else if (ssl_err == SSL_ERROR_WANT_READ ||
931                  ssl_err == SSL_ERROR_WANT_WRITE) {
932         return; // Call us again
933       } else {
934         ok = 1;
935       }
936       conn->flags &= ~(NSF_WANT_READ | NSF_WANT_WRITE);
937     }
938 #endif
939     conn->flags &= ~NSF_CONNECTING;
940     DBG(("%p ok=%d", conn, ok));
941     if (ok != 0) {
942       conn->flags |= NSF_CLOSE_IMMEDIATELY;
943     }
944     ns_call(conn, NS_CONNECT, &ok);
945     return;
946   }
947 
948 #ifdef NS_ENABLE_SSL
949   if (conn->ssl != NULL) {
950     if (conn->flags & NSF_SSL_HANDSHAKE_DONE) {
951       // SSL library may have more bytes ready to read then we ask to read.
952       // Therefore, read in a loop until we read everything. Without the loop,
953       // we skip to the next select() cycle which can just timeout.
954       while ((n = SSL_read(conn->ssl, buf, sizeof(buf))) > 0) {
955         DBG(("%p %d <- %d bytes (SSL)", conn, conn->flags, n));
956         iobuf_append(&conn->recv_iobuf, buf, n);
957         ns_call(conn, NS_RECV, &n);
958       }
959       ns_ssl_err(conn, n);
960     } else {
961       int res = SSL_accept(conn->ssl);
962       int ssl_err = ns_ssl_err(conn, res);
963       if (res == 1) {
964         conn->flags |= NSF_SSL_HANDSHAKE_DONE;
965         conn->flags &= ~(NSF_WANT_READ | NSF_WANT_WRITE);
966       } else if (ssl_err == SSL_ERROR_WANT_READ ||
967                  ssl_err == SSL_ERROR_WANT_WRITE) {
968         return; // Call us again
969       } else {
970         conn->flags |= NSF_CLOSE_IMMEDIATELY;
971       }
972       return;
973     }
974   } else
975 #endif
976   {
977     while ((n = (int) recv(conn->sock, buf, sizeof(buf), 0)) > 0) {
978       DBG(("%p %d <- %d bytes (PLAIN)", conn, conn->flags, n));
979       iobuf_append(&conn->recv_iobuf, buf, n);
980       ns_call(conn, NS_RECV, &n);
981     }
982   }
983 
984   if (ns_is_error(n)) {
985     conn->flags |= NSF_CLOSE_IMMEDIATELY;
986   }
987 }
988 
989 static void ns_write_to_socket(struct ns_connection *conn) {
990   struct iobuf *io = &conn->send_iobuf;
991   int n = 0;
992 
993 #ifdef NS_ENABLE_SSL
994   if (conn->ssl != NULL) {
995     n = SSL_write(conn->ssl, io->buf, io->len);
996     if (n <= 0) {
997       int ssl_err = ns_ssl_err(conn, n);
998       if (ssl_err == SSL_ERROR_WANT_READ || ssl_err == SSL_ERROR_WANT_WRITE) {
999         return; // Call us again
1000       } else {
1001         conn->flags |= NSF_CLOSE_IMMEDIATELY;
1002       }
1003     } else {
1004       conn->flags &= ~(NSF_WANT_READ | NSF_WANT_WRITE);
1005     }
1006   } else
1007 #endif
1008   { n = (int) send(conn->sock, io->buf, io->len, 0); }
1009 
1010   DBG(("%p %d -> %d bytes", conn, conn->flags, n));
1011 
1012   ns_call(conn, NS_SEND, &n);
1013   if (ns_is_error(n)) {
1014     conn->flags |= NSF_CLOSE_IMMEDIATELY;
1015   } else if (n > 0) {
1016     iobuf_remove(io, n);
1017   }
1018 }
1019 
1020 int ns_send(struct ns_connection *conn, const void *buf, size_t len) {
1021   return (int) ns_out(conn, buf, len);
1022 }
1023 
1024 static void ns_handle_udp(struct ns_connection *ls) {
1025   struct ns_connection nc;
1026   char buf[NS_UDP_RECEIVE_BUFFER_SIZE];
1027   ssize_t n;
1028   socklen_t s_len = sizeof(nc.sa);
1029 
1030   memset(&nc, 0, sizeof(nc));
1031   n = recvfrom(ls->sock, buf, sizeof(buf), 0, &nc.sa.sa, &s_len);
1032   if (n <= 0) {
1033     DBG(("%p recvfrom: %s", ls, strerror(errno)));
1034   } else {
1035     nc.mgr = ls->mgr;
1036     nc.recv_iobuf.buf = buf;
1037     nc.recv_iobuf.len = nc.recv_iobuf.size = n;
1038     nc.sock = ls->sock;
1039     nc.callback = ls->callback;
1040     nc.user_data = ls->user_data;
1041     nc.proto_data = ls->proto_data;
1042     nc.mgr = ls->mgr;
1043     nc.listener = ls;
1044     nc.flags = NSF_UDP;
1045     DBG(("%p %d bytes received", ls, n));
1046     ns_call(&nc, NS_RECV, &n);
1047   }
1048 }
1049 
1050 static void ns_add_to_set(sock_t sock, fd_set *set, sock_t *max_fd) {
1051   if (sock != INVALID_SOCKET) {
1052     FD_SET(sock, set);
1053     if (*max_fd == INVALID_SOCKET || sock > *max_fd) {
1054       *max_fd = sock;
1055     }
1056   }
1057 }
1058 
1059 time_t ns_mgr_poll(struct ns_mgr *mgr, int milli) {
1060   struct ns_connection *conn, *tmp_conn;
1061   struct timeval tv;
1062   fd_set read_set, write_set;
1063   sock_t max_fd = INVALID_SOCKET;
1064   time_t current_time = time(NULL);
1065 
1066   FD_ZERO(&read_set);
1067   FD_ZERO(&write_set);
1068   ns_add_to_set(mgr->ctl[1], &read_set, &max_fd);
1069 
1070   for (conn = mgr->active_connections; conn != NULL; conn = tmp_conn) {
1071     tmp_conn = conn->next;
1072     if (!(conn->flags & (NSF_LISTENING | NSF_CONNECTING))) {
1073       ns_call(conn, NS_POLL, &current_time);
1074     }
1075     if (conn->flags & NSF_CLOSE_IMMEDIATELY) {
1076       ns_close_conn(conn);
1077     } else {
1078       if (!(conn->flags & NSF_WANT_WRITE)) {
1079         //DBG(("%p read_set", conn));
1080         ns_add_to_set(conn->sock, &read_set, &max_fd);
1081       }
1082       if (((conn->flags & NSF_CONNECTING) && !(conn->flags & NSF_WANT_READ)) ||
1083           (conn->send_iobuf.len > 0 && !(conn->flags & NSF_CONNECTING) &&
1084            !(conn->flags & NSF_BUFFER_BUT_DONT_SEND))) {
1085         //DBG(("%p write_set", conn));
1086         ns_add_to_set(conn->sock, &write_set, &max_fd);
1087       }
1088     }
1089   }
1090 
1091   tv.tv_sec = milli / 1000;
1092   tv.tv_usec = (milli % 1000) * 1000;
1093 
1094   if (select((int) max_fd + 1, &read_set, &write_set, NULL, &tv) > 0) {
1095     // select() might have been waiting for a long time, reset current_time
1096     // now to prevent last_io_time being set to the past.
1097     current_time = time(NULL);
1098 
1099     // Read wakeup messages
1100     if (mgr->ctl[1] != INVALID_SOCKET &&
1101         FD_ISSET(mgr->ctl[1], &read_set)) {
1102       struct ctl_msg ctl_msg;
1103       int len = (int) recv(mgr->ctl[1], (char *) &ctl_msg, sizeof(ctl_msg), 0);
1104       send(mgr->ctl[1], ctl_msg.message, 1, 0);
1105       if (len >= (int) sizeof(ctl_msg.callback) && ctl_msg.callback != NULL) {
1106         struct ns_connection *c;
1107         for (c = ns_next(mgr, NULL); c != NULL; c = ns_next(mgr, c)) {
1108           ctl_msg.callback(c, NS_POLL, ctl_msg.message);
1109         }
1110       }
1111     }
1112 
1113     for (conn = mgr->active_connections; conn != NULL; conn = tmp_conn) {
1114       tmp_conn = conn->next;
1115       if (FD_ISSET(conn->sock, &read_set)) {
1116         if (conn->flags & NSF_LISTENING) {
1117           if (conn->flags & NSF_UDP) {
1118             ns_handle_udp(conn);
1119           } else {
1120             // We're not looping here, and accepting just one connection at
1121             // a time. The reason is that eCos does not respect non-blocking
1122             // flag on a listening socket and hangs in a loop.
1123             accept_conn(conn);
1124           }
1125         } else {
1126           conn->last_io_time = current_time;
1127           ns_read_from_socket(conn);
1128         }
1129       }
1130 
1131       if (FD_ISSET(conn->sock, &write_set)) {
1132         if (conn->flags & NSF_CONNECTING) {
1133           ns_read_from_socket(conn);
1134         } else if (!(conn->flags & NSF_BUFFER_BUT_DONT_SEND)) {
1135           conn->last_io_time = current_time;
1136           ns_write_to_socket(conn);
1137         }
1138       }
1139     }
1140   }
1141 
1142   for (conn = mgr->active_connections; conn != NULL; conn = tmp_conn) {
1143     tmp_conn = conn->next;
1144     if ((conn->flags & NSF_CLOSE_IMMEDIATELY) ||
1145         (conn->send_iobuf.len == 0 &&
1146           (conn->flags & NSF_FINISHED_SENDING_DATA))) {
1147       ns_close_conn(conn);
1148     }
1149   }
1150 
1151   return current_time;
1152 }
1153 
1154 struct ns_connection *ns_connect(struct ns_mgr *mgr, const char *address,
1155                                  ns_callback_t callback, void *user_data) {
1156   sock_t sock = INVALID_SOCKET;
1157   struct ns_connection *nc = NULL;
1158   union socket_address sa;
1159   char cert[100], ca_cert[100];
1160   int rc, use_ssl, proto;
1161 
1162   ns_parse_address(address, &sa, &proto, &use_ssl, cert, ca_cert);
1163   if ((sock = socket(AF_INET, proto, 0)) == INVALID_SOCKET) {
1164     return NULL;
1165   }
1166   ns_set_non_blocking_mode(sock);
1167   rc = (proto == SOCK_DGRAM) ? 0 : connect(sock, &sa.sa, sizeof(sa.sin));
1168 
1169   if (rc != 0 && ns_is_error(rc)) {
1170     closesocket(sock);
1171     return NULL;
1172   } else if ((nc = ns_add_sock(mgr, sock, callback, user_data)) == NULL) {
1173     closesocket(sock);
1174     return NULL;
1175   }
1176 
1177   nc->sa = sa;   // Important, cause UDP conns will use sendto()
1178   nc->flags = (proto == SOCK_DGRAM) ? NSF_UDP : NSF_CONNECTING;
1179 
1180 #ifdef NS_ENABLE_SSL
1181   if (use_ssl) {
1182     if ((nc->ssl_ctx = SSL_CTX_new(SSLv23_client_method())) == NULL ||
1183         ns_use_cert(nc->ssl_ctx, cert) != 0 ||
1184         ns_use_ca_cert(nc->ssl_ctx, ca_cert) != 0 ||
1185         (nc->ssl = SSL_new(nc->ssl_ctx)) == NULL) {
1186       ns_close_conn(nc);
1187       return NULL;
1188     } else {
1189       SSL_set_fd(nc->ssl, sock);
1190     }
1191   }
1192 #endif
1193 
1194   return nc;
1195 }
1196 
1197 struct ns_connection *ns_add_sock(struct ns_mgr *s, sock_t sock,
1198                                   ns_callback_t callback, void *user_data) {
1199   struct ns_connection *conn;
1200   if ((conn = (struct ns_connection *) NS_MALLOC(sizeof(*conn))) != NULL) {
1201     memset(conn, 0, sizeof(*conn));
1202     ns_set_non_blocking_mode(sock);
1203     ns_set_close_on_exec(sock);
1204     conn->sock = sock;
1205     conn->user_data = user_data;
1206     conn->callback = callback;
1207     conn->mgr = s;
1208     conn->last_io_time = time(NULL);
1209     ns_add_conn(s, conn);
1210     DBG(("%p %d", conn, sock));
1211   }
1212   return conn;
1213 }
1214 
1215 struct ns_connection *ns_next(struct ns_mgr *s, struct ns_connection *conn) {
1216   return conn == NULL ? s->active_connections : conn->next;
1217 }
1218 
1219 void ns_broadcast(struct ns_mgr *mgr, ns_callback_t cb,void *data, size_t len) {
1220   struct ctl_msg ctl_msg;
1221   if (mgr->ctl[0] != INVALID_SOCKET && data != NULL &&
1222       len < sizeof(ctl_msg.message)) {
1223     ctl_msg.callback = cb;
1224     memcpy(ctl_msg.message, data, len);
1225     send(mgr->ctl[0], (char *) &ctl_msg,
1226          offsetof(struct ctl_msg, message) + len, 0);
1227     recv(mgr->ctl[0], (char *) &len, 1, 0);
1228   }
1229 }
1230 
1231 void ns_mgr_init(struct ns_mgr *s, void *user_data) {
1232   memset(s, 0, sizeof(*s));
1233   s->ctl[0] = s->ctl[1] = INVALID_SOCKET;
1234   s->user_data = user_data;
1235 
1236 #ifdef _WIN32
1237   { WSADATA data; WSAStartup(MAKEWORD(2, 2), &data); }
1238 #else
1239   // Ignore SIGPIPE signal, so if client cancels the request, it
1240   // won't kill the whole process.
1241   signal(SIGPIPE, SIG_IGN);
1242 #endif
1243 
1244 #ifndef NS_DISABLE_SOCKETPAIR
1245   do {
1246     ns_socketpair2(s->ctl, SOCK_DGRAM);
1247   } while (s->ctl[0] == INVALID_SOCKET);
1248 #endif
1249 
1250 #ifdef NS_ENABLE_SSL
1251   {static int init_done; if (!init_done) { SSL_library_init(); init_done++; }}
1252 #endif
1253 }
1254 
1255 void ns_mgr_free(struct ns_mgr *s) {
1256   struct ns_connection *conn, *tmp_conn;
1257 
1258   DBG(("%p", s));
1259   if (s == NULL) return;
1260   // Do one last poll, see https://github.com/cesanta/mongoose/issues/286
1261   ns_mgr_poll(s, 0);
1262 
1263   if (s->ctl[0] != INVALID_SOCKET) closesocket(s->ctl[0]);
1264   if (s->ctl[1] != INVALID_SOCKET) closesocket(s->ctl[1]);
1265   s->ctl[0] = s->ctl[1] = INVALID_SOCKET;
1266 
1267   for (conn = s->active_connections; conn != NULL; conn = tmp_conn) {
1268     tmp_conn = conn->next;
1269     ns_close_conn(conn);
1270   }
1271 }
1272 // net_skeleton end
1273 #endif  // NOEMBED_NET_SKELETON
1274 
1275 #include <ctype.h>
1276 
1277 #ifdef _WIN32         //////////////// Windows specific defines and includes
1278 #include <io.h>       // For _lseeki64
1279 #include <direct.h>   // For _mkdir
1280 #ifndef S_ISDIR
1281 #define S_ISDIR(x) ((x) & _S_IFDIR)
1282 #endif
1283 #ifdef stat
1284 #undef stat
1285 #endif
1286 #ifdef lseek
1287 #undef lseek
1288 #endif
1289 #ifdef popen
1290 #undef popen
1291 #endif
1292 #ifdef pclose
1293 #undef pclose
1294 #endif
1295 #define stat(x, y) mg_stat((x), (y))
1296 #define fopen(x, y) mg_fopen((x), (y))
1297 #define open(x, y, z) mg_open((x), (y), (z))
1298 #define close(x) _close(x)
1299 #define fileno(x) _fileno(x)
1300 #define lseek(x, y, z) _lseeki64((x), (y), (z))
1301 #define read(x, y, z) _read((x), (y), (z))
1302 #define write(x, y, z) _write((x), (y), (z))
1303 #define popen(x, y) _popen((x), (y))
1304 #define pclose(x) _pclose(x)
1305 #define mkdir(x, y) _mkdir(x)
1306 #define rmdir(x) _rmdir(x)
1307 #define strdup(x) _strdup(x)
1308 #ifndef __func__
1309 #define STRX(x) #x
1310 #define STR(x) STRX(x)
1311 #define __func__ __FILE__ ":" STR(__LINE__)
1312 #endif
1313 #define INT64_FMT   "I64d"
1314 #define flockfile(x)      ((void) (x))
1315 #define funlockfile(x)    ((void) (x))
1316 typedef struct _stati64 file_stat_t;
1317 typedef HANDLE process_id_t;
1318 
1319 #else                    ////////////// UNIX specific defines and includes
1320 
1321 #if !defined(MONGOOSE_NO_FILESYSTEM) &&\
1322     (!defined(MONGOOSE_NO_DAV) || !defined(MONGOOSE_NO_DIRECTORY_LISTING))
1323 #include <dirent.h>
1324 #endif
1325 #if !defined(MONGOOSE_NO_FILESYSTEM) && !defined(MONGOOSE_NO_DL)
1326 #include <dlfcn.h>
1327 #endif
1328 #include <inttypes.h>
1329 #include <pwd.h>
1330 #if !defined(O_BINARY)
1331 #define O_BINARY 0
1332 #endif
1333 #define INT64_FMT PRId64
1334 typedef struct stat file_stat_t;
1335 typedef pid_t process_id_t;
1336 #endif                  //////// End of platform-specific defines and includes
1337 
1338 #include "mongoose.h"
1339 
1340 #define MAX_REQUEST_SIZE 16384
1341 #define IOBUF_SIZE 8192
1342 #define MAX_PATH_SIZE 8192
1343 #define DEFAULT_CGI_PATTERN "**.cgi$|**.pl$|**.php$"
1344 #define CGI_ENVIRONMENT_SIZE 8192
1345 #define MAX_CGI_ENVIR_VARS 64
1346 #define ENV_EXPORT_TO_CGI "MONGOOSE_CGI"
1347 #define PASSWORDS_FILE_NAME ".htpasswd"
1348 
1349 #ifndef MONGOOSE_USE_WEBSOCKET_PING_INTERVAL
1350 #define MONGOOSE_USE_WEBSOCKET_PING_INTERVAL 5
1351 #endif
1352 
1353 // Extra HTTP headers to send in every static file reply
1354 #if !defined(MONGOOSE_USE_EXTRA_HTTP_HEADERS)
1355 #define MONGOOSE_USE_EXTRA_HTTP_HEADERS ""
1356 #endif
1357 
1358 #ifndef MONGOOSE_POST_SIZE_LIMIT
1359 #define MONGOOSE_POST_SIZE_LIMIT 0
1360 #endif
1361 
1362 #ifndef MONGOOSE_IDLE_TIMEOUT_SECONDS
1363 #define MONGOOSE_IDLE_TIMEOUT_SECONDS 300
1364 #endif
1365 
1366 #if defined(NS_DISABLE_SOCKETPAIR) && !defined(MONGOOSE_NO_CGI)
1367 #define MONGOOSE_NO_CGI
1368 #endif
1369 
1370 #ifdef MONGOOSE_NO_FILESYSTEM
1371 #define MONGOOSE_NO_AUTH
1372 #if !defined(MONGOOSE_NO_CGI)
1373 #define MONGOOSE_NO_CGI
1374 #endif
1375 #define MONGOOSE_NO_DAV
1376 #define MONGOOSE_NO_DIRECTORY_LISTING
1377 #define MONGOOSE_NO_LOGGING
1378 #define MONGOOSE_NO_SSI
1379 #define MONGOOSE_NO_DL
1380 #endif
1381 
1382 struct vec {
1383   const char *ptr;
1384   size_t len;
1385 };
1386 
1387 // For directory listing and WevDAV support
1388 struct dir_entry {
1389   struct connection *conn;
1390   char *file_name;
1391   file_stat_t st;
1392 };
1393 
1394 // NOTE(lsm): this enum shoulds be in sync with the config_options.
1395 enum {
1396   ACCESS_CONTROL_LIST,
1397 #ifndef MONGOOSE_NO_FILESYSTEM
1398   ACCESS_LOG_FILE,
1399 #ifndef MONGOOSE_NO_AUTH
1400   AUTH_DOMAIN,
1401 #endif
1402 #ifndef MONGOOSE_NO_CGI
1403   CGI_INTERPRETER,
1404   CGI_PATTERN,
1405 #endif
1406   DAV_AUTH_FILE,
1407   DAV_ROOT,
1408   DOCUMENT_ROOT,
1409 #ifndef MONGOOSE_NO_DIRECTORY_LISTING
1410   ENABLE_DIRECTORY_LISTING,
1411 #endif
1412 #endif
1413   ENABLE_PROXY,
1414   EXTRA_MIME_TYPES,
1415 #if !defined(MONGOOSE_NO_FILESYSTEM) && !defined(MONGOOSE_NO_AUTH)
1416   GLOBAL_AUTH_FILE,
1417 #endif
1418 #ifndef MONGOOSE_NO_FILESYSTEM
1419   HIDE_FILES_PATTERN,
1420   HEXDUMP_FILE,
1421   INDEX_FILES,
1422 #endif
1423   LISTENING_PORT,
1424 #ifndef _WIN32
1425   RUN_AS_USER,
1426 #endif
1427 #ifndef MONGOOSE_NO_SSI
1428   SSI_PATTERN,
1429 #endif
1430   URL_REWRITES,
1431   NUM_OPTIONS
1432 };
1433 
1434 static const char *static_config_options[] = {
1435   "access_control_list", NULL,
1436 #ifndef MONGOOSE_NO_FILESYSTEM
1437   "access_log_file", NULL,
1438 #ifndef MONGOOSE_NO_AUTH
1439   "auth_domain", "mydomain.com",
1440 #endif
1441 #ifndef MONGOOSE_NO_CGI
1442   "cgi_interpreter", NULL,
1443   "cgi_pattern", DEFAULT_CGI_PATTERN,
1444 #endif
1445   "dav_auth_file", NULL,
1446   "dav_root", NULL,
1447   "document_root",  NULL,
1448 #ifndef MONGOOSE_NO_DIRECTORY_LISTING
1449   "enable_directory_listing", "yes",
1450 #endif
1451 #endif
1452   "enable_proxy", NULL,
1453   "extra_mime_types", NULL,
1454 #if !defined(MONGOOSE_NO_FILESYSTEM) && !defined(MONGOOSE_NO_AUTH)
1455   "global_auth_file", NULL,
1456 #endif
1457 #ifndef MONGOOSE_NO_FILESYSTEM
1458   "hide_files_patterns", NULL,
1459   "hexdump_file", NULL,
1460   "index_files","index.html,index.htm,index.shtml,index.cgi,index.php",
1461 #endif
1462   "listening_port", NULL,
1463 #ifndef _WIN32
1464   "run_as_user", NULL,
1465 #endif
1466 #ifndef MONGOOSE_NO_SSI
1467   "ssi_pattern", "**.shtml$|**.shtm$",
1468 #endif
1469   "url_rewrites", NULL,
1470   NULL
1471 };
1472 
1473 struct mg_server {
1474   struct ns_mgr ns_mgr;
1475   union socket_address lsa;   // Listening socket address
1476   mg_handler_t event_handler;
1477   char *config_options[NUM_OPTIONS];
1478 };
1479 
1480 // Local endpoint representation
1481 union endpoint {
1482   int fd;                     // Opened regular local file
1483   struct ns_connection *nc;   // CGI or proxy->target connection
1484 };
1485 
1486 enum endpoint_type {
1487  EP_NONE, EP_FILE, EP_CGI, EP_USER, EP_PUT, EP_CLIENT, EP_PROXY
1488 };
1489 
1490 #define MG_HEADERS_SENT NSF_USER_1
1491 #define MG_USING_CHUNKED_API NSF_USER_2
1492 #define MG_CGI_CONN NSF_USER_3
1493 #define MG_PROXY_CONN NSF_USER_4
1494 #define MG_PROXY_DONT_PARSE NSF_USER_5
1495 
1496 struct connection {
1497   struct ns_connection *ns_conn;  // NOTE(lsm): main.c depends on this order
1498   struct mg_connection mg_conn;
1499   struct mg_server *server;
1500   union endpoint endpoint;
1501   enum endpoint_type endpoint_type;
1502   char *path_info;
1503   char *request;
1504   int64_t num_bytes_recv; // Total number of bytes received
1505   int64_t cl;             // Reply content length, for Range support
1506   ssize_t request_len;  // Request length, including last \r\n after last header
1507 };
1508 
1509 #define MG_CONN_2_CONN(c) ((struct connection *) ((char *) (c) - \
1510   offsetof(struct connection, mg_conn)))
1511 
1512 static void open_local_endpoint(struct connection *conn, int skip_user);
1513 static void close_local_endpoint(struct connection *conn);
1514 static void mg_ev_handler(struct ns_connection *nc, int ev, void *p);
1515 
1516 static const struct {
1517   const char *extension;
1518   size_t ext_len;
1519   const char *mime_type;
1520 } static_builtin_mime_types[] = {
1521   {".html", 5, "text/html"},
1522   {".htm", 4, "text/html"},
1523   {".shtm", 5, "text/html"},
1524   {".shtml", 6, "text/html"},
1525   {".css", 4, "text/css"},
1526   {".js",  3, "application/javascript"},
1527   {".ico", 4, "image/x-icon"},
1528   {".gif", 4, "image/gif"},
1529   {".jpg", 4, "image/jpeg"},
1530   {".jpeg", 5, "image/jpeg"},
1531   {".png", 4, "image/png"},
1532   {".svg", 4, "image/svg+xml"},
1533   {".txt", 4, "text/plain"},
1534   {".torrent", 8, "application/x-bittorrent"},
1535   {".wav", 4, "audio/x-wav"},
1536   {".mp3", 4, "audio/x-mp3"},
1537   {".mid", 4, "audio/mid"},
1538   {".m3u", 4, "audio/x-mpegurl"},
1539   {".ogg", 4, "application/ogg"},
1540   {".ram", 4, "audio/x-pn-realaudio"},
1541   {".xml", 4, "text/xml"},
1542   {".json",  5, "application/json"},
1543   {".xslt", 5, "application/xml"},
1544   {".xsl", 4, "application/xml"},
1545   {".ra",  3, "audio/x-pn-realaudio"},
1546   {".doc", 4, "application/msword"},
1547   {".exe", 4, "application/octet-stream"},
1548   {".zip", 4, "application/x-zip-compressed"},
1549   {".xls", 4, "application/excel"},
1550   {".tgz", 4, "application/x-tar-gz"},
1551   {".tar", 4, "application/x-tar"},
1552   {".gz",  3, "application/x-gunzip"},
1553   {".arj", 4, "application/x-arj-compressed"},
1554   {".rar", 4, "application/x-rar-compressed"},
1555   {".rtf", 4, "application/rtf"},
1556   {".pdf", 4, "application/pdf"},
1557   {".swf", 4, "application/x-shockwave-flash"},
1558   {".mpg", 4, "video/mpeg"},
1559   {".webm", 5, "video/webm"},
1560   {".mpeg", 5, "video/mpeg"},
1561   {".mov", 4, "video/quicktime"},
1562   {".mp4", 4, "video/mp4"},
1563   {".m4v", 4, "video/x-m4v"},
1564   {".asf", 4, "video/x-ms-asf"},
1565   {".avi", 4, "video/x-msvideo"},
1566   {".bmp", 4, "image/bmp"},
1567   {".ttf", 4, "application/x-font-ttf"},
1568   {NULL,  0, NULL}
1569 };
1570 
1571 #ifdef MONGOOSE_ENABLE_THREADS
1572 void *mg_start_thread(void *(*f)(void *), void *p) {
1573   return ns_start_thread(f, p);
1574 }
1575 #endif  // MONGOOSE_ENABLE_THREADS
1576 
1577 #ifndef MONGOOSE_NO_MMAP
1578 #ifdef _WIN32
1579 static void *mmap(void *addr, int64_t len, int prot, int flags, int fd,
1580                   int offset) {
1581   HANDLE fh = (HANDLE) _get_osfhandle(fd);
1582   HANDLE mh = CreateFileMapping(fh, 0, PAGE_READONLY, 0, 0, 0);
1583   void *p = MapViewOfFile(mh, FILE_MAP_READ, 0, 0, (size_t) len);
1584   CloseHandle(mh);
1585   return p;
1586 }
1587 #define munmap(x, y)  UnmapViewOfFile(x)
1588 #define MAP_FAILED NULL
1589 #define MAP_PRIVATE 0
1590 #define PROT_READ 0
1591 #elif defined(__OS2__)
1592 static void *mmap(void *addr, int64_t len, int prot, int flags, int fd,
1593                   int offset) {
1594   void *p;
1595 
1596   int pos = lseek( fd, 0, SEEK_CUR ); /* Get a current position */
1597 
1598   if (pos == -1)
1599     return NULL;
1600 
1601   /* Seek to offset offset */
1602   if (lseek( fd, offset, SEEK_SET) == -1)
1603     return NULL;
1604 
1605   p = malloc(len);
1606 
1607   /* Read in a file */
1608   if (!p || read(fd, p, len) == -1) {
1609     free(p);
1610     p = NULL;
1611   }
1612 
1613   /* Restore the position */
1614   lseek(fd, pos, SEEK_SET);
1615 
1616   return p;
1617 }
1618 #define munmap(x, y)  free(x)
1619 #define MAP_FAILED NULL
1620 #define MAP_PRIVATE 0
1621 #define PROT_READ 0
1622 #else
1623 #include <sys/mman.h>
1624 #endif
1625 
1626 void *mg_mmap(FILE *fp, size_t size) {
1627   void *p = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fileno(fp), 0);
1628   return p == MAP_FAILED ? NULL : p;
1629 }
1630 
1631 void mg_munmap(void *p, size_t size) {
1632   munmap(p, size);
1633 }
1634 #endif  // MONGOOSE_NO_MMAP
1635 
1636 #if defined(_WIN32) && !defined(MONGOOSE_NO_FILESYSTEM)
1637 // Encode 'path' which is assumed UTF-8 string, into UNICODE string.
1638 // wbuf and wbuf_len is a target buffer and its length.
1639 static void to_wchar(const char *path, wchar_t *wbuf, size_t wbuf_len) {
1640   char buf[MAX_PATH_SIZE * 2], buf2[MAX_PATH_SIZE * 2], *p;
1641 
1642   strncpy(buf, path, sizeof(buf));
1643   buf[sizeof(buf) - 1] = '\0';
1644 
1645   // Trim trailing slashes. Leave backslash for paths like "X:\"
1646   p = buf + strlen(buf) - 1;
1647   while (p > buf && p[-1] != ':' && (p[0] == '\\' || p[0] == '/')) *p-- = '\0';
1648 
1649   // Convert to Unicode and back. If doubly-converted string does not
1650   // match the original, something is fishy, reject.
1651   memset(wbuf, 0, wbuf_len * sizeof(wchar_t));
1652   MultiByteToWideChar(CP_UTF8, 0, buf, -1, wbuf, (int) wbuf_len);
1653   WideCharToMultiByte(CP_UTF8, 0, wbuf, (int) wbuf_len, buf2, sizeof(buf2),
1654                       NULL, NULL);
1655   if (strcmp(buf, buf2) != 0) {
1656     wbuf[0] = L'\0';
1657   }
1658 }
1659 
1660 static int mg_stat(const char *path, file_stat_t *st) {
1661   wchar_t wpath[MAX_PATH_SIZE];
1662   to_wchar(path, wpath, ARRAY_SIZE(wpath));
1663   DBG(("[%ls] -> %d", wpath, _wstati64(wpath, st)));
1664   return _wstati64(wpath, st);
1665 }
1666 
1667 static FILE *mg_fopen(const char *path, const char *mode) {
1668   wchar_t wpath[MAX_PATH_SIZE], wmode[10];
1669   to_wchar(path, wpath, ARRAY_SIZE(wpath));
1670   to_wchar(mode, wmode, ARRAY_SIZE(wmode));
1671   return _wfopen(wpath, wmode);
1672 }
1673 
1674 static int mg_open(const char *path, int flag, int mode) {
1675   wchar_t wpath[MAX_PATH_SIZE];
1676   to_wchar(path, wpath, ARRAY_SIZE(wpath));
1677   return _wopen(wpath, flag, mode);
1678 }
1679 #endif // _WIN32 && !MONGOOSE_NO_FILESYSTEM
1680 
1681 // A helper function for traversing a comma separated list of values.
1682 // It returns a list pointer shifted to the next value, or NULL if the end
1683 // of the list found.
1684 // Value is stored in val vector. If value has form "x=y", then eq_val
1685 // vector is initialized to point to the "y" part, and val vector length
1686 // is adjusted to point only to "x".
1687 static const char *next_option(const char *list, struct vec *val,
1688                                struct vec *eq_val) {
1689   if (list == NULL || *list == '\0') {
1690     // End of the list
1691     list = NULL;
1692   } else {
1693     val->ptr = list;
1694     if ((list = strchr(val->ptr, ',')) != NULL) {
1695       // Comma found. Store length and shift the list ptr
1696       val->len = list - val->ptr;
1697       list++;
1698     } else {
1699       // This value is the last one
1700       list = val->ptr + strlen(val->ptr);
1701       val->len = list - val->ptr;
1702     }
1703 
1704     if (eq_val != NULL) {
1705       // Value has form "x=y", adjust pointers and lengths
1706       // so that val points to "x", and eq_val points to "y".
1707       eq_val->len = 0;
1708       eq_val->ptr = (const char *) memchr(val->ptr, '=', val->len);
1709       if (eq_val->ptr != NULL) {
1710         eq_val->ptr++;  // Skip over '=' character
1711         eq_val->len = val->ptr + val->len - eq_val->ptr;
1712         val->len = (eq_val->ptr - val->ptr) - 1;
1713       }
1714     }
1715   }
1716 
1717   return list;
1718 }
1719 
1720 // Like snprintf(), but never returns negative value, or a value
1721 // that is larger than a supplied buffer.
1722 static int mg_vsnprintf(char *buf, size_t buflen, const char *fmt, va_list ap) {
1723   int n;
1724   if (buflen < 1) return 0;
1725   n = vsnprintf(buf, buflen, fmt, ap);
1726   if (n < 0) {
1727     n = 0;
1728   } else if (n >= (int) buflen) {
1729     n = (int) buflen - 1;
1730   }
1731   buf[n] = '\0';
1732   return n;
1733 }
1734 
1735 static int mg_snprintf(char *buf, size_t buflen, const char *fmt, ...) {
1736   va_list ap;
1737   int n;
1738   va_start(ap, fmt);
1739   n = mg_vsnprintf(buf, buflen, fmt, ap);
1740   va_end(ap);
1741   return n;
1742 }
1743 
1744 // Check whether full request is buffered. Return:
1745 //   -1  if request is malformed
1746 //    0  if request is not yet fully buffered
1747 //   >0  actual request length, including last \r\n\r\n
1748 static int get_request_len(const char *s, size_t buf_len) {
1749   const unsigned char *buf = (unsigned char *) s;
1750   size_t i;
1751 
1752   for (i = 0; i < buf_len; i++) {
1753     // Control characters are not allowed but >=128 are.
1754     // Abort scan as soon as one malformed character is found.
1755     if (!isprint(buf[i]) && buf[i] != '\r' && buf[i] != '\n' && buf[i] < 128) {
1756       return -1;
1757     } else if (buf[i] == '\n' && i + 1 < buf_len && buf[i + 1] == '\n') {
1758       return i + 2;
1759     } else if (buf[i] == '\n' && i + 2 < buf_len && buf[i + 1] == '\r' &&
1760                buf[i + 2] == '\n') {
1761       return i + 3;
1762     }
1763   }
1764 
1765   return 0;
1766 }
1767 
1768 // Skip the characters until one of the delimiters characters found.
1769 // 0-terminate resulting word. Skip the rest of the delimiters if any.
1770 // Advance pointer to buffer to the next word. Return found 0-terminated word.
1771 static char *skip(char **buf, const char *delimiters) {
1772   char *p, *begin_word, *end_word, *end_delimiters;
1773 
1774   begin_word = *buf;
1775   end_word = begin_word + strcspn(begin_word, delimiters);
1776   end_delimiters = end_word + strspn(end_word, delimiters);
1777 
1778   for (p = end_word; p < end_delimiters; p++) {
1779     *p = '\0';
1780   }
1781 
1782   *buf = end_delimiters;
1783 
1784   return begin_word;
1785 }
1786 
1787 // Parse HTTP headers from the given buffer, advance buffer to the point
1788 // where parsing stopped.
1789 static void parse_http_headers(char **buf, struct mg_connection *ri) {
1790   size_t i;
1791 
1792   for (i = 0; i < ARRAY_SIZE(ri->http_headers); i++) {
1793     ri->http_headers[i].name = skip(buf, ": ");
1794     ri->http_headers[i].value = skip(buf, "\r\n");
1795     if (ri->http_headers[i].name[0] == '\0')
1796       break;
1797     ri->num_headers = i + 1;
1798   }
1799 }
1800 
1801 static const char *status_code_to_str(int status_code) {
1802   switch (status_code) {
1803 
1804     case 100: return "Continue";
1805     case 101: return "Switching Protocols";
1806     case 102: return "Processing";
1807 
1808     case 200: return "OK";
1809     case 201: return "Created";
1810     case 202: return "Accepted";
1811     case 203: return "Non-Authoritative Information";
1812     case 204: return "No Content";
1813     case 205: return "Reset Content";
1814     case 206: return "Partial Content";
1815     case 207: return "Multi-Status";
1816     case 208: return "Already Reported";
1817     case 226: return "IM Used";
1818 
1819     case 300: return "Multiple Choices";
1820     case 301: return "Moved Permanently";
1821     case 302: return "Found";
1822     case 303: return "See Other";
1823     case 304: return "Not Modified";
1824     case 305: return "Use Proxy";
1825     case 306: return "Switch Proxy";
1826     case 307: return "Temporary Redirect";
1827     case 308: return "Permanent Redirect";
1828 
1829     case 400: return "Bad Request";
1830     case 401: return "Unauthorized";
1831     case 402: return "Payment Required";
1832     case 403: return "Forbidden";
1833     case 404: return "Not Found";
1834     case 405: return "Method Not Allowed";
1835     case 406: return "Not Acceptable";
1836     case 407: return "Proxy Authentication Required";
1837     case 408: return "Request Timeout";
1838     case 409: return "Conflict";
1839     case 410: return "Gone";
1840     case 411: return "Length Required";
1841     case 412: return "Precondition Failed";
1842     case 413: return "Payload Too Large";
1843     case 414: return "URI Too Long";
1844     case 415: return "Unsupported Media Type";
1845     case 416: return "Requested Range Not Satisfiable";
1846     case 417: return "Expectation Failed";
1847     case 418: return "I\'m a teapot";
1848     case 422: return "Unprocessable Entity";
1849     case 423: return "Locked";
1850     case 424: return "Failed Dependency";
1851     case 426: return "Upgrade Required";
1852     case 428: return "Precondition Required";
1853     case 429: return "Too Many Requests";
1854     case 431: return "Request Header Fields Too Large";
1855     case 451: return "Unavailable For Legal Reasons";
1856 
1857     case 500: return "Internal Server Error";
1858     case 501: return "Not Implemented";
1859     case 502: return "Bad Gateway";
1860     case 503: return "Service Unavailable";
1861     case 504: return "Gateway Timeout";
1862     case 505: return "HTTP Version Not Supported";
1863     case 506: return "Variant Also Negotiates";
1864     case 507: return "Insufficient Storage";
1865     case 508: return "Loop Detected";
1866     case 510: return "Not Extended";
1867     case 511: return "Network Authentication Required";
1868 
1869     default:  return "Server Error";
1870   }
1871 }
1872 
1873 static int call_user(struct connection *conn, enum mg_event ev) {
1874   return conn != NULL && conn->server != NULL &&
1875     conn->server->event_handler != NULL ?
1876     conn->server->event_handler(&conn->mg_conn, ev) : MG_FALSE;
1877 }
1878 
1879 static void send_http_error(struct connection *conn, int code,
1880                             const char *fmt, ...) {
1881   const char *message = status_code_to_str(code);
1882   const char *rewrites = conn->server->config_options[URL_REWRITES];
1883   char headers[200], body[200];
1884   struct vec a, b;
1885   va_list ap;
1886   int body_len, headers_len, match_code;
1887 
1888   conn->mg_conn.status_code = code;
1889 
1890   // Invoke error handler if it is set
1891   if (call_user(conn, MG_HTTP_ERROR) == MG_TRUE) {
1892     close_local_endpoint(conn);
1893     return;
1894   }
1895 
1896   // Handle error code rewrites
1897   while ((rewrites = next_option(rewrites, &a, &b)) != NULL) {
1898     if ((match_code = atoi(a.ptr)) > 0 && match_code == code) {
1899       struct mg_connection *c = &conn->mg_conn;
1900       c->status_code = 302;
1901       mg_printf(c, "HTTP/1.1 %d Moved\r\n"
1902                 "Location: %.*s?code=%d&orig_uri=%s&query_string=%s\r\n\r\n",
1903                 c->status_code, b.len, b.ptr, code, c->uri,
1904                 c->query_string == NULL ? "" : c->query_string);
1905       close_local_endpoint(conn);
1906       return;
1907     }
1908   }
1909 
1910   body_len = mg_snprintf(body, sizeof(body), "%d %s\n", code, message);
1911   if (fmt != NULL) {
1912     va_start(ap, fmt);
1913     body_len += mg_vsnprintf(body + body_len, sizeof(body) - body_len, fmt, ap);
1914     va_end(ap);
1915   }
1916   if ((code >= 300 && code <= 399) || code == 204) {
1917     // 3xx errors do not have body
1918     body_len = 0;
1919   }
1920   headers_len = mg_snprintf(headers, sizeof(headers),
1921                             "HTTP/1.1 %d %s\r\nContent-Length: %d\r\n"
1922                             "Content-Type: text/plain\r\n\r\n",
1923                             code, message, body_len);
1924   ns_send(conn->ns_conn, headers, headers_len);
1925   ns_send(conn->ns_conn, body, body_len);
1926   close_local_endpoint(conn);  // This will write to the log file
1927 }
1928 
1929 static void write_chunk(struct connection *conn, const char *buf, int len) {
1930   char chunk_size[50];
1931   int n = mg_snprintf(chunk_size, sizeof(chunk_size), "%X\r\n", len);
1932   ns_send(conn->ns_conn, chunk_size, n);
1933   ns_send(conn->ns_conn, buf, len);
1934   ns_send(conn->ns_conn, "\r\n", 2);
1935 }
1936 
1937 size_t mg_printf(struct mg_connection *conn, const char *fmt, ...) {
1938   struct connection *c = MG_CONN_2_CONN(conn);
1939   va_list ap;
1940 
1941   va_start(ap, fmt);
1942   ns_vprintf(c->ns_conn, fmt, ap);
1943   va_end(ap);
1944 
1945   return c->ns_conn->send_iobuf.len;
1946 }
1947 
1948 static void ns_forward(struct ns_connection *from, struct ns_connection *to) {
1949   DBG(("%p -> %p %lu bytes", from, to, (unsigned long)from->recv_iobuf.len));
1950   ns_send(to, from->recv_iobuf.buf, from->recv_iobuf.len);
1951   iobuf_remove(&from->recv_iobuf, from->recv_iobuf.len);
1952 }
1953 
1954 #ifndef MONGOOSE_NO_CGI
1955 #ifdef _WIN32
1956 struct threadparam {
1957   sock_t s;
1958   HANDLE hPipe;
1959 };
1960 
1961 static int wait_until_ready(sock_t sock, int for_read) {
1962   fd_set set;
1963   FD_ZERO(&set);
1964   FD_SET(sock, &set);
1965   select(sock + 1, for_read ? &set : 0, for_read ? 0 : &set, 0, 0);
1966   return 1;
1967 }
1968 
1969 static void *push_to_stdin(void *arg) {
1970   struct threadparam *tp = (struct threadparam *)arg;
1971   int n, sent, stop = 0;
1972   DWORD k;
1973   char buf[IOBUF_SIZE];
1974 
1975   while (!stop && wait_until_ready(tp->s, 1) &&
1976          (n = recv(tp->s, buf, sizeof(buf), 0)) > 0) {
1977     if (n == -1 && GetLastError() == WSAEWOULDBLOCK) continue;
1978     for (sent = 0; !stop && sent < n; sent += k) {
1979       if (!WriteFile(tp->hPipe, buf + sent, n - sent, &k, 0)) stop = 1;
1980     }
1981   }
1982   DBG(("%s", "FORWARED EVERYTHING TO CGI"));
1983   CloseHandle(tp->hPipe);
1984   NS_FREE(tp);
1985   _endthread();
1986   return NULL;
1987 }
1988 
1989 static void *pull_from_stdout(void *arg) {
1990   struct threadparam *tp = (struct threadparam *)arg;
1991   int k = 0, stop = 0;
1992   DWORD n, sent;
1993   char buf[IOBUF_SIZE];
1994 
1995   while (!stop && ReadFile(tp->hPipe, buf, sizeof(buf), &n, NULL)) {
1996     for (sent = 0; !stop && sent < n; sent += k) {
1997       if (wait_until_ready(tp->s, 0) &&
1998           (k = send(tp->s, buf + sent, n - sent, 0)) <= 0) stop = 1;
1999     }
2000   }
2001   DBG(("%s", "EOF FROM CGI"));
2002   CloseHandle(tp->hPipe);
2003   shutdown(tp->s, 2);  // Without this, IO thread may get truncated data
2004   closesocket(tp->s);
2005   NS_FREE(tp);
2006   _endthread();
2007   return NULL;
2008 }
2009 
2010 static void spawn_stdio_thread(sock_t sock, HANDLE hPipe,
2011                                void *(*func)(void *)) {
2012   struct threadparam *tp = (struct threadparam *)NS_MALLOC(sizeof(*tp));
2013   if (tp != NULL) {
2014     tp->s = sock;
2015     tp->hPipe = hPipe;
2016     mg_start_thread(func, tp);
2017   }
2018 }
2019 
2020 static void abs_path(const char *utf8_path, char *abs_path, size_t len) {
2021   wchar_t buf[MAX_PATH_SIZE], buf2[MAX_PATH_SIZE];
2022   to_wchar(utf8_path, buf, ARRAY_SIZE(buf));
2023   GetFullPathNameW(buf, ARRAY_SIZE(buf2), buf2, NULL);
2024   WideCharToMultiByte(CP_UTF8, 0, buf2, wcslen(buf2) + 1, abs_path, len, 0, 0);
2025 }
2026 
2027 static process_id_t start_process(char *interp, const char *cmd,
2028                                   const char *env, const char *envp[],
2029                                   const char *dir, sock_t sock) {
2030   STARTUPINFOW si;
2031   PROCESS_INFORMATION pi;
2032   HANDLE a[2], b[2], me = GetCurrentProcess();
2033   wchar_t wcmd[MAX_PATH_SIZE], full_dir[MAX_PATH_SIZE];
2034   char buf[MAX_PATH_SIZE], buf4[MAX_PATH_SIZE], buf5[MAX_PATH_SIZE],
2035        cmdline[MAX_PATH_SIZE], *p;
2036   DWORD flags = DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS;
2037   FILE *fp;
2038 
2039   memset(&si, 0, sizeof(si));
2040   memset(&pi, 0, sizeof(pi));
2041 
2042   si.cb = sizeof(si);
2043   si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
2044   si.wShowWindow = SW_HIDE;
2045   si.hStdError = GetStdHandle(STD_ERROR_HANDLE);
2046 
2047   CreatePipe(&a[0], &a[1], NULL, 0);
2048   CreatePipe(&b[0], &b[1], NULL, 0);
2049   DuplicateHandle(me, a[0], me, &si.hStdInput, 0, TRUE, flags);
2050   DuplicateHandle(me, b[1], me, &si.hStdOutput, 0, TRUE, flags);
2051 
2052   if (interp == NULL && (fp = fopen(cmd, "r")) != NULL) {
2053     buf[0] = buf[1] = '\0';
2054     fgets(buf, sizeof(buf), fp);
2055     buf[sizeof(buf) - 1] = '\0';
2056     if (buf[0] == '#' && buf[1] == '!') {
2057       interp = buf + 2;
2058       for (p = interp + strlen(interp) - 1;
2059            isspace(* (uint8_t *) p) && p > interp; p--) *p = '\0';
2060     }
2061     fclose(fp);
2062   }
2063 
2064   if (interp != NULL) {
2065     abs_path(interp, buf4, ARRAY_SIZE(buf4));
2066     interp = buf4;
2067   }
2068   abs_path(dir, buf5, ARRAY_SIZE(buf5));
2069   to_wchar(dir, full_dir, ARRAY_SIZE(full_dir));
2070   mg_snprintf(cmdline, sizeof(cmdline), "%s%s\"%s\"",
2071               interp ? interp : "", interp ? " " : "", cmd);
2072   to_wchar(cmdline, wcmd, ARRAY_SIZE(wcmd));
2073 
2074   if (CreateProcessW(NULL, wcmd, NULL, NULL, TRUE, CREATE_NEW_PROCESS_GROUP,
2075                      (void *) env, full_dir, &si, &pi) != 0) {
2076     spawn_stdio_thread(sock, a[1], push_to_stdin);
2077     spawn_stdio_thread(sock, b[0], pull_from_stdout);
2078   } else {
2079     CloseHandle(a[1]);
2080     CloseHandle(b[0]);
2081     closesocket(sock);
2082   }
2083   DBG(("CGI command: [%ls] -> %p", wcmd, pi.hProcess));
2084 
2085   // Not closing a[0] and b[1] because we've used DUPLICATE_CLOSE_SOURCE
2086   CloseHandle(si.hStdOutput);
2087   CloseHandle(si.hStdInput);
2088   //CloseHandle(pi.hThread);
2089   //CloseHandle(pi.hProcess);
2090 
2091   return pi.hProcess;
2092 }
2093 #else
2094 static process_id_t start_process(const char *interp, const char *cmd,
2095                                   const char *env, const char *envp[],
2096                                   const char *dir, sock_t sock) {
2097   char buf[500];
2098   process_id_t pid = fork();
2099   (void) env;
2100 
2101   if (pid == 0) {
2102     (void) chdir(dir);
2103     (void) dup2(sock, 0);
2104     (void) dup2(sock, 1);
2105     closesocket(sock);
2106 
2107     // After exec, all signal handlers are restored to their default values,
2108     // with one exception of SIGCHLD. According to POSIX.1-2001 and Linux's
2109     // implementation, SIGCHLD's handler will leave unchanged after exec
2110     // if it was set to be ignored. Restore it to default action.
2111     signal(SIGCHLD, SIG_DFL);
2112 
2113     if (interp == NULL) {
2114       execle(cmd, cmd, (char *) 0, envp); // Using (char *) 0 to avoid warning
2115     } else {
2116       execle(interp, interp, cmd, (char *) 0, envp);
2117     }
2118     snprintf(buf, sizeof(buf), "Status: 500\r\n\r\n"
2119              "500 Server Error: %s%s%s: %s", interp == NULL ? "" : interp,
2120              interp == NULL ? "" : " ", cmd, strerror(errno));
2121     send(1, buf, strlen(buf), 0);
2122     exit(EXIT_FAILURE);  // exec call failed
2123   }
2124 
2125   return pid;
2126 }
2127 #endif  // _WIN32
2128 
2129 // This structure helps to create an environment for the spawned CGI program.
2130 // Environment is an array of "VARIABLE=VALUE\0" ASCIIZ strings,
2131 // last element must be NULL.
2132 // However, on Windows there is a requirement that all these VARIABLE=VALUE\0
2133 // strings must reside in a contiguous buffer. The end of the buffer is
2134 // marked by two '\0' characters.
2135 // We satisfy both worlds: we create an envp array (which is vars), all
2136 // entries are actually pointers inside buf.
2137 struct cgi_env_block {
2138   struct mg_connection *conn;
2139   char buf[CGI_ENVIRONMENT_SIZE];       // Environment buffer
2140   const char *vars[MAX_CGI_ENVIR_VARS]; // char *envp[]
2141   int len;                              // Space taken
2142   int nvars;                            // Number of variables in envp[]
2143 };
2144 
2145 // Append VARIABLE=VALUE\0 string to the buffer, and add a respective
2146 // pointer into the vars array.
2147 static char *addenv(struct cgi_env_block *block, const char *fmt, ...) {
2148   int n, space;
2149   char *added;
2150   va_list ap;
2151 
2152   // Calculate how much space is left in the buffer
2153   space = sizeof(block->buf) - block->len - 2;
2154   assert(space >= 0);
2155 
2156   // Make a pointer to the free space int the buffer
2157   added = block->buf + block->len;
2158 
2159   // Copy VARIABLE=VALUE\0 string into the free space
2160   va_start(ap, fmt);
2161   n = mg_vsnprintf(added, (size_t) space, fmt, ap);
2162   va_end(ap);
2163 
2164   // Make sure we do not overflow buffer and the envp array
2165   if (n > 0 && n + 1 < space &&
2166       block->nvars < (int) ARRAY_SIZE(block->vars) - 2) {
2167     // Append a pointer to the added string into the envp array
2168     block->vars[block->nvars++] = added;
2169     // Bump up used length counter. Include \0 terminator
2170     block->len += n + 1;
2171   }
2172 
2173   return added;
2174 }
2175 
2176 static void addenv2(struct cgi_env_block *blk, const char *name) {
2177   const char *s;
2178   if ((s = getenv(name)) != NULL) addenv(blk, "%s=%s", name, s);
2179 }
2180 
2181 static void prepare_cgi_environment(struct connection *conn,
2182                                     const char *prog,
2183                                     struct cgi_env_block *blk) {
2184   struct mg_connection *ri = &conn->mg_conn;
2185   const char *s, *slash;
2186   char *p, **opts = conn->server->config_options;
2187   int  i;
2188 
2189   blk->len = blk->nvars = 0;
2190   blk->conn = ri;
2191 
2192   if ((s = getenv("SERVER_NAME")) != NULL) {
2193     addenv(blk, "SERVER_NAME=%s", s);
2194   } else {
2195     addenv(blk, "SERVER_NAME=%s", ri->local_ip);
2196   }
2197   addenv(blk, "SERVER_ROOT=%s", opts[DOCUMENT_ROOT]);
2198   addenv(blk, "DOCUMENT_ROOT=%s", opts[DOCUMENT_ROOT]);
2199   addenv(blk, "SERVER_SOFTWARE=%s/%s", "Mongoose", MONGOOSE_VERSION);
2200 
2201   // Prepare the environment block
2202   addenv(blk, "%s", "GATEWAY_INTERFACE=CGI/1.1");
2203   addenv(blk, "%s", "SERVER_PROTOCOL=HTTP/1.1");
2204   addenv(blk, "%s", "REDIRECT_STATUS=200"); // For PHP
2205 
2206   // TODO(lsm): fix this for IPv6 case
2207   //addenv(blk, "SERVER_PORT=%d", ri->remote_port);
2208 
2209   addenv(blk, "REQUEST_METHOD=%s", ri->request_method);
2210   addenv(blk, "REMOTE_ADDR=%s", ri->remote_ip);
2211   addenv(blk, "REMOTE_PORT=%d", ri->remote_port);
2212   addenv(blk, "REQUEST_URI=%s%s%s", ri->uri,
2213          ri->query_string == NULL ? "" : "?",
2214          ri->query_string == NULL ? "" : ri->query_string);
2215 
2216   // SCRIPT_NAME
2217   if (conn->path_info != NULL) {
2218     addenv(blk, "SCRIPT_NAME=%.*s",
2219            (int) (strlen(ri->uri) - strlen(conn->path_info)), ri->uri);
2220     addenv(blk, "PATH_INFO=%s", conn->path_info);
2221   } else {
2222     s = strrchr(prog, '/');
2223     slash = strrchr(ri->uri, '/');
2224     addenv(blk, "SCRIPT_NAME=%.*s%s",
2225            slash == NULL ? 0 : (int) (slash - ri->uri), ri->uri,
2226            s == NULL ? prog : s);
2227   }
2228 
2229   addenv(blk, "SCRIPT_FILENAME=%s", prog);
2230   addenv(blk, "PATH_TRANSLATED=%s", prog);
2231   addenv(blk, "HTTPS=%s", conn->ns_conn->ssl != NULL ? "on" : "off");
2232 
2233   if ((s = mg_get_header(ri, "Content-Type")) != NULL)
2234     addenv(blk, "CONTENT_TYPE=%s", s);
2235 
2236   if (ri->query_string != NULL)
2237     addenv(blk, "QUERY_STRING=%s", ri->query_string);
2238 
2239   if ((s = mg_get_header(ri, "Content-Length")) != NULL)
2240     addenv(blk, "CONTENT_LENGTH=%s", s);
2241 
2242   addenv2(blk, "PATH");
2243   addenv2(blk, "TMP");
2244   addenv2(blk, "TEMP");
2245   addenv2(blk, "TMPDIR");
2246   addenv2(blk, "PERLLIB");
2247   addenv2(blk, ENV_EXPORT_TO_CGI);
2248 
2249 #if defined(_WIN32)
2250   addenv2(blk, "COMSPEC");
2251   addenv2(blk, "SYSTEMROOT");
2252   addenv2(blk, "SystemDrive");
2253   addenv2(blk, "ProgramFiles");
2254   addenv2(blk, "ProgramFiles(x86)");
2255   addenv2(blk, "CommonProgramFiles(x86)");
2256 #else
2257   addenv2(blk, "LD_LIBRARY_PATH");
2258 #endif // _WIN32
2259 
2260   // Add all headers as HTTP_* variables
2261   for (i = 0; i < ri->num_headers; i++) {
2262     p = addenv(blk, "HTTP_%s=%s",
2263         ri->http_headers[i].name, ri->http_headers[i].value);
2264 
2265     // Convert variable name into uppercase, and change - to _
2266     for (; *p != '=' && *p != '\0'; p++) {
2267       if (*p == '-')
2268         *p = '_';
2269       *p = (char) toupper(* (unsigned char *) p);
2270     }
2271   }
2272 
2273   blk->vars[blk->nvars++] = NULL;
2274   blk->buf[blk->len++] = '\0';
2275 
2276   assert(blk->nvars < (int) ARRAY_SIZE(blk->vars));
2277   assert(blk->len > 0);
2278   assert(blk->len < (int) sizeof(blk->buf));
2279 }
2280 
2281 static const char cgi_status[] = "HTTP/1.1 200 OK\r\n";
2282 
2283 static void open_cgi_endpoint(struct connection *conn, const char *prog) {
2284   struct cgi_env_block blk;
2285   char dir[MAX_PATH_SIZE];
2286   const char *p;
2287   sock_t fds[2];
2288 
2289   prepare_cgi_environment(conn, prog, &blk);
2290   // CGI must be executed in its own directory. 'dir' must point to the
2291   // directory containing executable program, 'p' must point to the
2292   // executable program name relative to 'dir'.
2293   if ((p = strrchr(prog, '/')) == NULL) {
2294     mg_snprintf(dir, sizeof(dir), "%s", ".");
2295   } else {
2296     mg_snprintf(dir, sizeof(dir), "%.*s", (int) (p - prog), prog);
2297   }
2298 
2299   // Try to create socketpair in a loop until success. ns_socketpair()
2300   // can be interrupted by a signal and fail.
2301   // TODO(lsm): use sigaction to restart interrupted syscall
2302   do {
2303     ns_socketpair(fds);
2304   } while (fds[0] == INVALID_SOCKET);
2305 
2306   if (start_process(conn->server->config_options[CGI_INTERPRETER],
2307                     prog, blk.buf, blk.vars, dir, fds[1]) != 0) {
2308     conn->endpoint_type = EP_CGI;
2309     conn->endpoint.nc = ns_add_sock(&conn->server->ns_mgr, fds[0],
2310                                     mg_ev_handler, conn);
2311     conn->endpoint.nc->flags |= MG_CGI_CONN;
2312     ns_send(conn->ns_conn, cgi_status, sizeof(cgi_status) - 1);
2313     conn->mg_conn.status_code = 200;
2314     conn->ns_conn->flags |= NSF_BUFFER_BUT_DONT_SEND;
2315     // Pass POST data to the CGI process
2316     conn->endpoint.nc->send_iobuf = conn->ns_conn->recv_iobuf;
2317     iobuf_init(&conn->ns_conn->recv_iobuf, 0);
2318   } else {
2319     closesocket(fds[0]);
2320     send_http_error(conn, 500, "start_process(%s) failed", prog);
2321   }
2322 
2323 #ifndef _WIN32
2324   closesocket(fds[1]);  // On Windows, CGI stdio thread closes that socket
2325 #endif
2326 }
2327 
2328 static void on_cgi_data(struct ns_connection *nc) {
2329   struct connection *conn = (struct connection *) nc->user_data;
2330   const char *status = "500";
2331   struct mg_connection c;
2332 
2333   if (!conn) return;
2334 
2335   // Copy CGI data from CGI socket to the client send buffer
2336   ns_forward(nc, conn->ns_conn);
2337 
2338   // If reply has not been parsed yet, parse it
2339   if (conn->ns_conn->flags & NSF_BUFFER_BUT_DONT_SEND) {
2340     struct iobuf *io = &conn->ns_conn->send_iobuf;
2341     size_t s_len = sizeof(cgi_status) - 1;
2342     int len = get_request_len(io->buf + s_len, io->len - s_len);
2343     char buf[MAX_REQUEST_SIZE], *s = buf;
2344 
2345     if (len == 0) return;
2346 
2347     if (len < 0 || len > (int) sizeof(buf)) {
2348       len = io->len;
2349       iobuf_remove(io, io->len);
2350       send_http_error(conn, 500, "CGI program sent malformed headers: [%.*s]",
2351         len, io->buf);
2352     } else {
2353       memset(&c, 0, sizeof(c));
2354       memcpy(buf, io->buf + s_len, len);
2355       buf[len - 1] = '\0';
2356       parse_http_headers(&s, &c);
2357       if (mg_get_header(&c, "Location") != NULL) {
2358         status = "302";
2359       } else if ((status = (char *) mg_get_header(&c, "Status")) == NULL) {
2360         status = "200";
2361       }
2362       memcpy(io->buf + 9, status, 3);
2363       conn->mg_conn.status_code = atoi(status);
2364     }
2365     conn->ns_conn->flags &= ~NSF_BUFFER_BUT_DONT_SEND;
2366   }
2367 }
2368 #endif  // !MONGOOSE_NO_CGI
2369 
2370 static char *mg_strdup(const char *str) {
2371   char *copy = (char *) NS_MALLOC(strlen(str) + 1);
2372   if (copy != NULL) {
2373     strcpy(copy, str);
2374   }
2375   return copy;
2376 }
2377 
2378 static int isbyte(int n) {
2379   return n >= 0 && n <= 255;
2380 }
2381 
2382 static int parse_net(const char *spec, uint32_t *net, uint32_t *mask) {
2383   int n, a, b, c, d, slash = 32, len = 0;
2384 
2385   if ((sscanf(spec, "%d.%d.%d.%d/%d%n", &a, &b, &c, &d, &slash, &n) == 5 ||
2386       sscanf(spec, "%d.%d.%d.%d%n", &a, &b, &c, &d, &n) == 4) &&
2387       isbyte(a) && isbyte(b) && isbyte(c) && isbyte(d) &&
2388       slash >= 0 && slash < 33) {
2389     len = n;
2390     *net = ((uint32_t)a << 24) | ((uint32_t)b << 16) | ((uint32_t)c << 8) | d;
2391     *mask = slash ? 0xffffffffU << (32 - slash) : 0;
2392   }
2393 
2394   return len;
2395 }
2396 
2397 // Verify given socket address against the ACL.
2398 // Return -1 if ACL is malformed, 0 if address is disallowed, 1 if allowed.
2399 static int check_acl(const char *acl, uint32_t remote_ip) {
2400   int allowed, flag;
2401   uint32_t net, mask;
2402   struct vec vec;
2403 
2404   // If any ACL is set, deny by default
2405   allowed = acl == NULL ? '+' : '-';
2406 
2407   while ((acl = next_option(acl, &vec, NULL)) != NULL) {
2408     flag = vec.ptr[0];
2409     if ((flag != '+' && flag != '-') ||
2410         parse_net(&vec.ptr[1], &net, &mask) == 0) {
2411       return -1;
2412     }
2413 
2414     if (net == (remote_ip & mask)) {
2415       allowed = flag;
2416     }
2417   }
2418 
2419   return allowed == '+';
2420 }
2421 
2422 // Protect against directory disclosure attack by removing '..',
2423 // excessive '/' and '\' characters
2424 static void remove_double_dots_and_double_slashes(char *s) {
2425   char *p = s;
2426 
2427   while (*s != '\0') {
2428     *p++ = *s++;
2429     if (s[-1] == '/' || s[-1] == '\\') {
2430       // Skip all following slashes, backslashes and double-dots
2431       while (s[0] != '\0') {
2432         if (s[0] == '/' || s[0] == '\\') { s++; }
2433         else if (s[0] == '.' && (s[1] == '/' || s[1] == '\\')) { s += 2; }
2434         else if (s[0] == '.' && s[1] == '.' && s[2] == '\0') { s += 2; }
2435         else if (s[0] == '.' && s[1] == '.' && (s[2] == '/' || s[2] == '\\')) { s += 3; }
2436         else { break; }
2437       }
2438     }
2439   }
2440   *p = '\0';
2441 }
2442 
2443 int mg_url_decode(const char *src, size_t src_len, char *dst,
2444                   size_t dst_len, int is_form_url_encoded) {
2445   size_t i, j = 0;
2446   int a, b;
2447 #define HEXTOI(x) (isdigit(x) ? (x) - '0' : (x) - 'W')
2448 
2449   for (i = j = 0; i < src_len && j < dst_len - 1; i++, j++) {
2450     if (src[i] == '%' && i + 2 < src_len &&
2451         isxdigit(* (const unsigned char *) (src + i + 1)) &&
2452         isxdigit(* (const unsigned char *) (src + i + 2))) {
2453       a = tolower(* (const unsigned char *) (src + i + 1));
2454       b = tolower(* (const unsigned char *) (src + i + 2));
2455       dst[j] = (char) ((HEXTOI(a) << 4) | HEXTOI(b));
2456       i += 2;
2457     } else if (is_form_url_encoded && src[i] == '+') {
2458       dst[j] = ' ';
2459     } else {
2460       dst[j] = src[i];
2461     }
2462   }
2463 
2464   dst[j] = '\0'; // Null-terminate the destination
2465 
2466   return i >= src_len ? j : -1;
2467 }
2468 
2469 static int is_valid_http_method(const char *s) {
2470   return !strcmp(s, "GET") || !strcmp(s, "POST") || !strcmp(s, "HEAD") ||
2471     !strcmp(s, "CONNECT") || !strcmp(s, "PUT") || !strcmp(s, "DELETE") ||
2472     !strcmp(s, "OPTIONS") || !strcmp(s, "PROPFIND") || !strcmp(s, "MKCOL");
2473 }
2474 
2475 // Parse HTTP request, fill in mg_request structure.
2476 // This function modifies the buffer by NUL-terminating
2477 // HTTP request components, header names and header values.
2478 // Note that len must point to the last \n of HTTP headers.
2479 static size_t parse_http_message(char *buf, size_t len,
2480                                  struct mg_connection *ri) {
2481   int is_request, n;
2482 
2483   // Reset the connection. Make sure that we don't touch fields that are
2484   // set elsewhere: remote_ip, remote_port, server_param
2485   ri->request_method = ri->uri = ri->http_version = ri->query_string = NULL;
2486   ri->num_headers = ri->status_code = ri->is_websocket = ri->content_len = 0;
2487 
2488   if (len < 1) return ~0;
2489 
2490   buf[len - 1] = '\0';
2491 
2492   // RFC says that all initial whitespaces should be ingored
2493   while (*buf != '\0' && isspace(* (unsigned char *) buf)) {
2494     buf++;
2495   }
2496   ri->request_method = skip(&buf, " ");
2497   ri->uri = skip(&buf, " ");
2498   ri->http_version = skip(&buf, "\r\n");
2499 
2500   // HTTP message could be either HTTP request or HTTP response, e.g.
2501   // "GET / HTTP/1.0 ...." or  "HTTP/1.0 200 OK ..."
2502   is_request = is_valid_http_method(ri->request_method);
2503   if ((is_request && memcmp(ri->http_version, "HTTP/", 5) != 0) ||
2504       (!is_request && memcmp(ri->request_method, "HTTP/", 5) != 0)) {
2505     len = ~0;
2506   } else {
2507     if (is_request) {
2508       ri->http_version += 5;
2509     } else {
2510       ri->status_code = atoi(ri->uri);
2511     }
2512     parse_http_headers(&buf, ri);
2513 
2514     if ((ri->query_string = strchr(ri->uri, '?')) != NULL) {
2515       *(char *) ri->query_string++ = '\0';
2516     }
2517     n = (int) strlen(ri->uri);
2518     mg_url_decode(ri->uri, n, (char *) ri->uri, n + 1, 0);
2519     if (*ri->uri == '/' || *ri->uri == '.') {
2520       remove_double_dots_and_double_slashes((char *) ri->uri);
2521     }
2522   }
2523 
2524   return len;
2525 }
2526 
2527 static int lowercase(const char *s) {
2528   return tolower(* (const unsigned char *) s);
2529 }
2530 
2531 static int mg_strcasecmp(const char *s1, const char *s2) {
2532   int diff;
2533 
2534   do {
2535     diff = lowercase(s1++) - lowercase(s2++);
2536   } while (diff == 0 && s1[-1] != '\0');
2537 
2538   return diff;
2539 }
2540 
2541 static int mg_strncasecmp(const char *s1, const char *s2, size_t len) {
2542   int diff = 0;
2543 
2544   if (len > 0)
2545     do {
2546       diff = lowercase(s1++) - lowercase(s2++);
2547     } while (diff == 0 && s1[-1] != '\0' && --len > 0);
2548 
2549   return diff;
2550 }
2551 
2552 // Return HTTP header value, or NULL if not found.
2553 const char *mg_get_header(const struct mg_connection *ri, const char *s) {
2554   int i;
2555 
2556   for (i = 0; i < ri->num_headers; i++)
2557     if (!mg_strcasecmp(s, ri->http_headers[i].name))
2558       return ri->http_headers[i].value;
2559 
2560   return NULL;
2561 }
2562 
2563 // Perform case-insensitive match of string against pattern
2564 int mg_match_prefix(const char *pattern, ssize_t pattern_len, const char *str) {
2565   const char *or_str;
2566   int len, res, i = 0, j = 0;
2567 
2568   if ((or_str = (const char *) memchr(pattern, '|', pattern_len)) != NULL) {
2569     res = mg_match_prefix(pattern, or_str - pattern, str);
2570     return res > 0 ? res : mg_match_prefix(or_str + 1,
2571       (pattern + pattern_len) - (or_str + 1), str);
2572   }
2573 
2574   for (; i < pattern_len; i++, j++) {
2575     if (pattern[i] == '?' && str[j] != '\0') {
2576       continue;
2577     } else if (pattern[i] == '$') {
2578       return str[j] == '\0' ? j : -1;
2579     } else if (pattern[i] == '*') {
2580       i++;
2581       if (pattern[i] == '*') {
2582         i++;
2583         len = (int) strlen(str + j);
2584       } else {
2585         len = (int) strcspn(str + j, "/");
2586       }
2587       if (i == pattern_len) {
2588         return j + len;
2589       }
2590       do {
2591         res = mg_match_prefix(pattern + i, pattern_len - i, str + j + len);
2592       } while (res == -1 && len-- > 0);
2593       return res == -1 ? -1 : j + res + len;
2594     } else if (lowercase(&pattern[i]) != lowercase(&str[j])) {
2595       return -1;
2596     }
2597   }
2598   return j;
2599 }
2600 
2601 // This function prints HTML pages, and expands "{{something}}" blocks
2602 // inside HTML by calling appropriate callback functions.
2603 // Note that {{@path/to/file}} construct outputs embedded file's contents,
2604 // which provides SSI-like functionality.
2605 void mg_template(struct mg_connection *conn, const char *s,
2606                  struct mg_expansion *expansions) {
2607   int i, j, pos = 0, inside_marker = 0;
2608 
2609   for (i = 0; s[i] != '\0'; i++) {
2610     if (inside_marker == 0 && !memcmp(&s[i], "{{", 2)) {
2611       if (i > pos) {
2612         mg_send_data(conn, &s[pos], i - pos);
2613       }
2614       pos = i;
2615       inside_marker = 1;
2616     }
2617     if (inside_marker == 1 && !memcmp(&s[i], "}}", 2)) {
2618       for (j = 0; expansions[j].keyword != NULL; j++) {
2619         const char *kw = expansions[j].keyword;
2620         if ((int) strlen(kw) == i - (pos + 2) &&
2621             memcmp(kw, &s[pos + 2], i - (pos + 2)) == 0) {
2622           expansions[j].handler(conn);
2623           pos = i + 2;
2624           break;
2625         }
2626       }
2627       inside_marker = 0;
2628     }
2629   }
2630   if (i > pos) {
2631     mg_send_data(conn, &s[pos], i - pos);
2632   }
2633 }
2634 
2635 #ifndef MONGOOSE_NO_FILESYSTEM
2636 static int is_dav_request(const struct connection *conn) {
2637   const char *s = conn->mg_conn.request_method;
2638   return !strcmp(s, "PUT") || !strcmp(s, "DELETE") ||
2639     !strcmp(s, "MKCOL") || !strcmp(s, "PROPFIND");
2640 }
2641 
2642 static int must_hide_file(struct connection *conn, const char *path) {
2643   const char *pw_pattern = "**" PASSWORDS_FILE_NAME "$";
2644   const char *pattern = conn->server->config_options[HIDE_FILES_PATTERN];
2645   return mg_match_prefix(pw_pattern, strlen(pw_pattern), path) > 0 ||
2646     (pattern != NULL && mg_match_prefix(pattern, strlen(pattern), path) > 0);
2647 }
2648 
2649 // Return 1 if real file has been found, 0 otherwise
2650 static int convert_uri_to_file_name(struct connection *conn, char *buf,
2651                                     size_t buf_len, file_stat_t *st) {
2652   struct vec a, b;
2653   const char *rewrites = conn->server->config_options[URL_REWRITES];
2654   const char *root =
2655 #ifndef MONGOOSE_NO_DAV
2656     is_dav_request(conn) && conn->server->config_options[DAV_ROOT] != NULL ?
2657     conn->server->config_options[DAV_ROOT] :
2658 #endif
2659     conn->server->config_options[DOCUMENT_ROOT];
2660 #ifndef MONGOOSE_NO_CGI
2661   const char *cgi_pat = conn->server->config_options[CGI_PATTERN];
2662   char *p;
2663 #endif
2664   const char *uri = conn->mg_conn.uri;
2665   const char *domain = mg_get_header(&conn->mg_conn, "Host");
2666   size_t match_len, root_len = root == NULL ? 0 : strlen(root);
2667 
2668   // Perform virtual hosting rewrites
2669   if (rewrites != NULL && domain != NULL) {
2670     const char *colon = strchr(domain, ':');
2671     size_t domain_len = colon == NULL ? strlen(domain) : colon - domain;
2672 
2673     while ((rewrites = next_option(rewrites, &a, &b)) != NULL) {
2674       if (a.len > 1 && a.ptr[0] == '@' && a.len == domain_len + 1 &&
2675           mg_strncasecmp(a.ptr + 1, domain, domain_len) == 0) {
2676         root = b.ptr;
2677         root_len = b.len;
2678         break;
2679       }
2680     }
2681   }
2682 
2683   // No filesystem access
2684   if (root == NULL || root_len == 0) return 0;
2685 
2686   // Handle URL rewrites
2687   mg_snprintf(buf, buf_len, "%.*s%s", root_len, root, uri);
2688   rewrites = conn->server->config_options[URL_REWRITES];  // Re-initialize!
2689   while ((rewrites = next_option(rewrites, &a, &b)) != NULL) {
2690     if ((match_len = mg_match_prefix(a.ptr, a.len, uri)) > 0) {
2691       mg_snprintf(buf, buf_len, "%.*s%s", (int) b.len, b.ptr, uri + match_len);
2692       break;
2693     }
2694   }
2695 
2696   if (stat(buf, st) == 0) return 1;
2697 
2698 #ifndef MONGOOSE_NO_CGI
2699   // Support PATH_INFO for CGI scripts.
2700   for (p = buf + strlen(root) + 2; *p != '\0'; p++) {
2701     if (*p == '/') {
2702       *p = '\0';
2703       if (mg_match_prefix(cgi_pat, strlen(cgi_pat), buf) > 0 &&
2704           !stat(buf, st)) {
2705       DBG(("!!!! [%s]", buf));
2706         *p = '/';
2707         conn->path_info = mg_strdup(p);
2708         *p = '\0';
2709         return 1;
2710       }
2711       *p = '/';
2712     }
2713   }
2714 #endif
2715 
2716   return 0;
2717 }
2718 #endif  // MONGOOSE_NO_FILESYSTEM
2719 
2720 static int should_keep_alive(const struct mg_connection *conn) {
2721   struct connection *c = MG_CONN_2_CONN(conn);
2722   const char *method = conn->request_method;
2723   const char *http_version = conn->http_version;
2724   const char *header = mg_get_header(conn, "Connection");
2725   return method != NULL &&
2726     (!strcmp(method, "GET") || c->endpoint_type == EP_USER) &&
2727     ((header != NULL && !mg_strcasecmp(header, "keep-alive")) ||
2728      (header == NULL && http_version && !strcmp(http_version, "1.1")));
2729 }
2730 
2731 size_t mg_write(struct mg_connection *c, const void *buf, size_t len) {
2732   struct connection *conn = MG_CONN_2_CONN(c);
2733   ns_send(conn->ns_conn, buf, len);
2734   return conn->ns_conn->send_iobuf.len;
2735 }
2736 
2737 void mg_send_status(struct mg_connection *c, int status) {
2738   struct connection *conn = MG_CONN_2_CONN(c);
2739   if (c->status_code == 0) {
2740     c->status_code = status;
2741     mg_printf(c, "HTTP/1.1 %d %s\r\n", status, status_code_to_str(status));
2742   }
2743   conn->ns_conn->flags |= MG_USING_CHUNKED_API;
2744 }
2745 
2746 void mg_send_header(struct mg_connection *c, const char *name, const char *v) {
2747   struct connection *conn = MG_CONN_2_CONN(c);
2748   if (c->status_code == 0) {
2749     c->status_code = 200;
2750     mg_printf(c, "HTTP/1.1 %d %s\r\n", 200, status_code_to_str(200));
2751   }
2752   mg_printf(c, "%s: %s\r\n", name, v);
2753   conn->ns_conn->flags |= MG_USING_CHUNKED_API;
2754 }
2755 
2756 static void terminate_headers(struct mg_connection *c) {
2757   struct connection *conn = MG_CONN_2_CONN(c);
2758   if (!(conn->ns_conn->flags & MG_HEADERS_SENT)) {
2759     mg_send_header(c, "Transfer-Encoding", "chunked");
2760     mg_write(c, "\r\n", 2);
2761     conn->ns_conn->flags |= MG_HEADERS_SENT;
2762   }
2763 }
2764 
2765 size_t mg_send_data(struct mg_connection *c, const void *data, int data_len) {
2766   struct connection *conn = MG_CONN_2_CONN(c);
2767   terminate_headers(c);
2768   write_chunk(MG_CONN_2_CONN(c), (const char *) data, data_len);
2769   return conn->ns_conn->send_iobuf.len;
2770 }
2771 
2772 size_t mg_printf_data(struct mg_connection *c, const char *fmt, ...) {
2773   struct connection *conn = MG_CONN_2_CONN(c);
2774   va_list ap;
2775   int len;
2776   char mem[IOBUF_SIZE], *buf = mem;
2777 
2778   terminate_headers(c);
2779 
2780   va_start(ap, fmt);
2781   len = ns_avprintf(&buf, sizeof(mem), fmt, ap);
2782   va_end(ap);
2783 
2784   if (len >= 0) {
2785     write_chunk((struct connection *) conn, buf, len);
2786   }
2787   if (buf != mem && buf != NULL) {
2788     NS_FREE(buf);
2789   }
2790   return conn->ns_conn->send_iobuf.len;
2791 }
2792 
2793 #if !defined(MONGOOSE_NO_WEBSOCKET) || !defined(MONGOOSE_NO_AUTH)
2794 static int is_big_endian(void) {
2795   static const int n = 1;
2796   return ((char *) &n)[0] == 0;
2797 }
2798 #endif
2799 
2800 #ifndef MONGOOSE_NO_WEBSOCKET
2801 // START OF SHA-1 code
2802 // Copyright(c) By Steve Reid <steve@edmweb.com>
2803 #define SHA1HANDSOFF
2804 #if defined(__sun)
2805 #include "solarisfixes.h"
2806 #endif
2807 
2808 union char64long16 { unsigned char c[64]; uint32_t l[16]; };
2809 
2810 #define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits))))
2811 
2812 static uint32_t blk0(union char64long16 *block, int i) {
2813   // Forrest: SHA expect BIG_ENDIAN, swap if LITTLE_ENDIAN
2814   if (!is_big_endian()) {
2815     block->l[i] = (rol(block->l[i], 24) & 0xFF00FF00) |
2816       (rol(block->l[i], 8) & 0x00FF00FF);
2817   }
2818   return block->l[i];
2819 }
2820 
2821 /* Avoid redefine warning (ARM /usr/include/sys/ucontext.h define R0~R4) */
2822 #undef blk
2823 #undef R0
2824 #undef R1
2825 #undef R2
2826 #undef R3
2827 #undef R4
2828 
2829 #define blk(i) (block->l[i&15] = rol(block->l[(i+13)&15]^block->l[(i+8)&15] \
2830     ^block->l[(i+2)&15]^block->l[i&15],1))
2831 #define R0(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk0(block, i)+0x5A827999+rol(v,5);w=rol(w,30);
2832 #define R1(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5);w=rol(w,30);
2833 #define R2(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=rol(w,30);
2834 #define R3(v,w,x,y,z,i) z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=rol(w,30);
2835 #define R4(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=rol(w,30);
2836 
2837 typedef struct {
2838     uint32_t state[5];
2839     uint32_t count[2];
2840     unsigned char buffer[64];
2841 } SHA1_CTX;
2842 
2843 static void SHA1Transform(uint32_t state[5], const unsigned char buffer[64]) {
2844   uint32_t a, b, c, d, e;
2845   union char64long16 block[1];
2846 
2847   memcpy(block, buffer, 64);
2848   a = state[0];
2849   b = state[1];
2850   c = state[2];
2851   d = state[3];
2852   e = state[4];
2853   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);
2854   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);
2855   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);
2856   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);
2857   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);
2858   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);
2859   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);
2860   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);
2861   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);
2862   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);
2863   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);
2864   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);
2865   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);
2866   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);
2867   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);
2868   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);
2869   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);
2870   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);
2871   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);
2872   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);
2873   state[0] += a;
2874   state[1] += b;
2875   state[2] += c;
2876   state[3] += d;
2877   state[4] += e;
2878   // Erase working structures. The order of operations is important,
2879   // used to ensure that compiler doesn't optimize those out.
2880   memset(block, 0, sizeof(block));
2881   a = b = c = d = e = 0;
2882   (void) a; (void) b; (void) c; (void) d; (void) e;
2883 }
2884 
2885 static void SHA1Init(SHA1_CTX *context) {
2886   context->state[0] = 0x67452301;
2887   context->state[1] = 0xEFCDAB89;
2888   context->state[2] = 0x98BADCFE;
2889   context->state[3] = 0x10325476;
2890   context->state[4] = 0xC3D2E1F0;
2891   context->count[0] = context->count[1] = 0;
2892 }
2893 
2894 static void SHA1Update(SHA1_CTX *context, const unsigned char *data,
2895                        size_t len) {
2896   size_t i, j;
2897 
2898   j = context->count[0];
2899   if ((context->count[0] += len << 3) < j)
2900     context->count[1]++;
2901   context->count[1] += (len>>29);
2902   j = (j >> 3) & 63;
2903   if ((j + len) > 63) {
2904     memcpy(&context->buffer[j], data, (i = 64-j));
2905     SHA1Transform(context->state, context->buffer);
2906     for ( ; i + 63 < len; i += 64) {
2907       SHA1Transform(context->state, &data[i]);
2908     }
2909     j = 0;
2910   }
2911   else i = 0;
2912   memcpy(&context->buffer[j], &data[i], len - i);
2913 }
2914 
2915 static void SHA1Final(unsigned char digest[20], SHA1_CTX *context) {
2916   unsigned i;
2917   unsigned char finalcount[8], c;
2918 
2919   for (i = 0; i < 8; i++) {
2920     finalcount[i] = (unsigned char)((context->count[(i >= 4 ? 0 : 1)]
2921                                      >> ((3-(i & 3)) * 8) ) & 255);
2922   }
2923   c = 0200;
2924   SHA1Update(context, &c, 1);
2925   while ((context->count[0] & 504) != 448) {
2926     c = 0000;
2927     SHA1Update(context, &c, 1);
2928   }
2929   SHA1Update(context, finalcount, 8);
2930   for (i = 0; i < 20; i++) {
2931     digest[i] = (unsigned char)
2932       ((context->state[i>>2] >> ((3-(i & 3)) * 8) ) & 255);
2933   }
2934   memset(context, '\0', sizeof(*context));
2935   memset(&finalcount, '\0', sizeof(finalcount));
2936 }
2937 // END OF SHA1 CODE
2938 
2939 static void base64_encode(const unsigned char *src, int src_len, char *dst) {
2940   static const char *b64 =
2941     "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
2942   int i, j, a, b, c;
2943 
2944   for (i = j = 0; i < src_len; i += 3) {
2945     a = src[i];
2946     b = i + 1 >= src_len ? 0 : src[i + 1];
2947     c = i + 2 >= src_len ? 0 : src[i + 2];
2948 
2949     dst[j++] = b64[a >> 2];
2950     dst[j++] = b64[((a & 3) << 4) | (b >> 4)];
2951     if (i + 1 < src_len) {
2952       dst[j++] = b64[(b & 15) << 2 | (c >> 6)];
2953     }
2954     if (i + 2 < src_len) {
2955       dst[j++] = b64[c & 63];
2956     }
2957   }
2958   while (j % 4 != 0) {
2959     dst[j++] = '=';
2960   }
2961   dst[j++] = '\0';
2962 }
2963 
2964 static void send_websocket_handshake(struct mg_connection *conn,
2965                                      const char *key) {
2966   static const char *magic = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
2967   char buf[500], sha[20], b64_sha[sizeof(sha) * 2];
2968   SHA1_CTX sha_ctx;
2969 
2970   mg_snprintf(buf, sizeof(buf), "%s%s", key, magic);
2971   SHA1Init(&sha_ctx);
2972   SHA1Update(&sha_ctx, (unsigned char *) buf, strlen(buf));
2973   SHA1Final((unsigned char *) sha, &sha_ctx);
2974   base64_encode((unsigned char *) sha, sizeof(sha), b64_sha);
2975   mg_snprintf(buf, sizeof(buf), "%s%s%s",
2976               "HTTP/1.1 101 Switching Protocols\r\n"
2977               "Upgrade: websocket\r\n"
2978               "Connection: Upgrade\r\n"
2979               "Sec-WebSocket-Accept: ", b64_sha, "\r\n\r\n");
2980 
2981   mg_write(conn, buf, strlen(buf));
2982 }
2983 
2984 static size_t deliver_websocket_frame(struct connection *conn) {
2985   // Having buf unsigned char * is important, as it is used below in arithmetic
2986   unsigned char *buf = (unsigned char *) conn->ns_conn->recv_iobuf.buf;
2987   size_t i, len, buf_len = conn->ns_conn->recv_iobuf.len, frame_len = 0,
2988       mask_len = 0, header_len = 0, data_len = 0, buffered = 0;
2989 
2990   if (buf_len >= 2) {
2991     len = buf[1] & 127;
2992     mask_len = buf[1] & 128 ? 4 : 0;
2993     if (len < 126 && buf_len >= mask_len) {
2994       data_len = len;
2995       header_len = 2 + mask_len;
2996     } else if (len == 126 && buf_len >= 4 + mask_len) {
2997       header_len = 4 + mask_len;
2998       data_len = ((((size_t) buf[2]) << 8) + buf[3]);
2999     } else if (buf_len >= 10 + mask_len) {
3000       header_len = 10 + mask_len;
3001       data_len = (size_t) (((uint64_t) htonl(* (uint32_t *) &buf[2])) << 32) +
3002         htonl(* (uint32_t *) &buf[6]);
3003     }
3004   }
3005 
3006   frame_len = header_len + data_len;
3007   buffered = frame_len > 0 && frame_len <= buf_len;
3008 
3009   if (buffered) {
3010     conn->mg_conn.content_len = data_len;
3011     conn->mg_conn.content = (char *) buf + header_len;
3012     conn->mg_conn.wsbits = buf[0];
3013 
3014     // Apply mask if necessary
3015     if (mask_len > 0) {
3016       for (i = 0; i < data_len; i++) {
3017         buf[i + header_len] ^= (buf + header_len - mask_len)[i % 4];
3018       }
3019     }
3020 
3021     // Call the handler and remove frame from the iobuf
3022     if (call_user(conn, MG_REQUEST) == MG_FALSE) {
3023       conn->ns_conn->flags |= NSF_FINISHED_SENDING_DATA;
3024     }
3025     iobuf_remove(&conn->ns_conn->recv_iobuf, frame_len);
3026   }
3027 
3028   return buffered;
3029 }
3030 
3031 size_t mg_websocket_write(struct mg_connection *conn, int opcode,
3032                           const char *data, size_t data_len) {
3033     unsigned char mem[4192], *copy = mem;
3034     size_t copy_len = 0;
3035 
3036     /* Check overflow */
3037     if (data_len > ~(size_t)0 - (size_t)10) {
3038       return 0;
3039     }
3040 
3041     if (data_len + 10 > sizeof(mem) &&
3042         (copy = (unsigned char *) NS_MALLOC(data_len + 10)) == NULL) {
3043       return 0;
3044     }
3045 
3046     copy[0] = 0x80 + (opcode & 0x0f);
3047 
3048     // Frame format: http://tools.ietf.org/html/rfc6455#section-5.2
3049     if (data_len < 126) {
3050       // Inline 7-bit length field
3051       copy[1] = data_len;
3052       memcpy(copy + 2, data, data_len);
3053       copy_len = 2 + data_len;
3054     } else if (data_len <= 0xFFFF) {
3055       // 16-bit length field
3056       copy[1] = 126;
3057       * (uint16_t *) (copy + 2) = (uint16_t) htons((uint16_t) data_len);
3058       memcpy(copy + 4, data, data_len);
3059       copy_len = 4 + data_len;
3060     } else {
3061       // 64-bit length field
3062       const uint32_t hi = htonl((uint32_t) ((uint64_t) data_len >> 32));
3063       const uint32_t lo = htonl(data_len & 0xffffffff);
3064       copy[1] = 127;
3065       memcpy(copy+2,&hi,sizeof(hi));
3066       memcpy(copy+6,&lo,sizeof(lo));
3067       memcpy(copy + 10, data, data_len);
3068       copy_len = 10 + data_len;
3069     }
3070 
3071     if (copy_len > 0) {
3072       mg_write(conn, copy, copy_len);
3073     }
3074     if (copy != mem) {
3075       NS_FREE(copy);
3076     }
3077 
3078     // If we send closing frame, schedule a connection to be closed after
3079     // data is drained to the client.
3080     if (opcode == WEBSOCKET_OPCODE_CONNECTION_CLOSE) {
3081       MG_CONN_2_CONN(conn)->ns_conn->flags |= NSF_FINISHED_SENDING_DATA;
3082     }
3083 
3084     return MG_CONN_2_CONN(conn)->ns_conn->send_iobuf.len;
3085 }
3086 
3087 size_t mg_websocket_printf(struct mg_connection *conn, int opcode,
3088                            const char *fmt, ...) {
3089   char mem[4192], *buf = mem;
3090   va_list ap;
3091   int len;
3092 
3093   va_start(ap, fmt);
3094   if ((len = ns_avprintf(&buf, sizeof(mem), fmt, ap)) > 0) {
3095     mg_websocket_write(conn, opcode, buf, len);
3096   }
3097   va_end(ap);
3098 
3099   if (buf != mem && buf != NULL) {
3100     NS_FREE(buf);
3101   }
3102 
3103   return MG_CONN_2_CONN(conn)->ns_conn->send_iobuf.len;
3104 }
3105 
3106 static void send_websocket_handshake_if_requested(struct mg_connection *conn) {
3107   const char *ver = mg_get_header(conn, "Sec-WebSocket-Version"),
3108         *key = mg_get_header(conn, "Sec-WebSocket-Key");
3109   if (ver != NULL && key != NULL) {
3110     conn->is_websocket = 1;
3111     if (call_user(MG_CONN_2_CONN(conn), MG_WS_HANDSHAKE) == MG_FALSE) {
3112       send_websocket_handshake(conn, key);
3113     }
3114     call_user(MG_CONN_2_CONN(conn), MG_WS_CONNECT);
3115   }
3116 }
3117 
3118 static void ping_idle_websocket_connection(struct connection *conn, time_t t) {
3119   if (t - conn->ns_conn->last_io_time > MONGOOSE_USE_WEBSOCKET_PING_INTERVAL) {
3120     mg_websocket_write(&conn->mg_conn, WEBSOCKET_OPCODE_PING, "", 0);
3121   }
3122 }
3123 #else
3124 #define ping_idle_websocket_connection(conn, t)
3125 #endif // !MONGOOSE_NO_WEBSOCKET
3126 
3127 static void write_terminating_chunk(struct connection *conn) {
3128   mg_write(&conn->mg_conn, "0\r\n\r\n", 5);
3129 }
3130 
3131 static int call_request_handler(struct connection *conn) {
3132   int result;
3133   conn->mg_conn.content = conn->ns_conn->recv_iobuf.buf;
3134   if ((result = call_user(conn, MG_REQUEST)) == MG_TRUE) {
3135     if (conn->ns_conn->flags & MG_USING_CHUNKED_API) {
3136       terminate_headers(&conn->mg_conn);
3137       write_terminating_chunk(conn);
3138     }
3139     close_local_endpoint(conn);
3140   }
3141   return result;
3142 }
3143 
3144 const char *mg_get_mime_type(const char *path, const char *default_mime_type) {
3145   const char *ext;
3146   size_t i, path_len;
3147 
3148   path_len = strlen(path);
3149 
3150   for (i = 0; static_builtin_mime_types[i].extension != NULL; i++) {
3151     ext = path + (path_len - static_builtin_mime_types[i].ext_len);
3152     if (path_len > static_builtin_mime_types[i].ext_len &&
3153         mg_strcasecmp(ext, static_builtin_mime_types[i].extension) == 0) {
3154       return static_builtin_mime_types[i].mime_type;
3155     }
3156   }
3157 
3158   return default_mime_type;
3159 }
3160 
3161 #ifndef MONGOOSE_NO_FILESYSTEM
3162 // Convert month to the month number. Return -1 on error, or month number
3163 static int get_month_index(const char *s) {
3164   static const char *month_names[] = {
3165     "Jan", "Feb", "Mar", "Apr", "May", "Jun",
3166     "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
3167   };
3168   int i;
3169 
3170   for (i = 0; i < (int) ARRAY_SIZE(month_names); i++)
3171     if (!strcmp(s, month_names[i]))
3172       return i;
3173 
3174   return -1;
3175 }
3176 
3177 static int num_leap_years(int year) {
3178   return year / 4 - year / 100 + year / 400;
3179 }
3180 
3181 // Parse UTC date-time string, and return the corresponding time_t value.
3182 static time_t parse_date_string(const char *datetime) {
3183   static const unsigned short days_before_month[] = {
3184     0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334
3185   };
3186   char month_str[32];
3187   int second, minute, hour, day, month, year, leap_days, days;
3188   time_t result = (time_t) 0;
3189 
3190   if (((sscanf(datetime, "%d/%3s/%d %d:%d:%d",
3191                &day, month_str, &year, &hour, &minute, &second) == 6) ||
3192        (sscanf(datetime, "%d %3s %d %d:%d:%d",
3193                &day, month_str, &year, &hour, &minute, &second) == 6) ||
3194        (sscanf(datetime, "%*3s, %d %3s %d %d:%d:%d",
3195                &day, month_str, &year, &hour, &minute, &second) == 6) ||
3196        (sscanf(datetime, "%d-%3s-%d %d:%d:%d",
3197                &day, month_str, &year, &hour, &minute, &second) == 6)) &&
3198       year > 1970 &&
3199       (month = get_month_index(month_str)) != -1) {
3200     leap_days = num_leap_years(year) - num_leap_years(1970);
3201     year -= 1970;
3202     days = year * 365 + days_before_month[month] + (day - 1) + leap_days;
3203     result = days * 24 * 3600 + hour * 3600 + minute * 60 + second;
3204   }
3205 
3206   return result;
3207 }
3208 
3209 // Look at the "path" extension and figure what mime type it has.
3210 // Store mime type in the vector.
3211 static void get_mime_type(const struct mg_server *server, const char *path,
3212                           struct vec *vec) {
3213   struct vec ext_vec, mime_vec;
3214   const char *list, *ext;
3215   size_t path_len;
3216 
3217   path_len = strlen(path);
3218 
3219   // Scan user-defined mime types first, in case user wants to
3220   // override default mime types.
3221   list = server->config_options[EXTRA_MIME_TYPES];
3222   while ((list = next_option(list, &ext_vec, &mime_vec)) != NULL) {
3223     // ext now points to the path suffix
3224     ext = path + path_len - ext_vec.len;
3225     if (mg_strncasecmp(ext, ext_vec.ptr, ext_vec.len) == 0) {
3226       *vec = mime_vec;
3227       return;
3228     }
3229   }
3230 
3231   vec->ptr = mg_get_mime_type(path, "text/plain");
3232   vec->len = strlen(vec->ptr);
3233 }
3234 
3235 static const char *suggest_connection_header(const struct mg_connection *conn) {
3236   return should_keep_alive(conn) ? "keep-alive" : "close";
3237 }
3238 
3239 static void construct_etag(char *buf, size_t buf_len, const file_stat_t *st) {
3240   mg_snprintf(buf, buf_len, "\"%lx.%" INT64_FMT "\"",
3241               (unsigned long) st->st_mtime, (int64_t) st->st_size);
3242 }
3243 
3244 // Return True if we should reply 304 Not Modified.
3245 static int is_not_modified(const struct connection *conn,
3246                            const file_stat_t *stp) {
3247   char etag[64];
3248   const char *ims = mg_get_header(&conn->mg_conn, "If-Modified-Since");
3249   const char *inm = mg_get_header(&conn->mg_conn, "If-None-Match");
3250   construct_etag(etag, sizeof(etag), stp);
3251   return (inm != NULL && !mg_strcasecmp(etag, inm)) ||
3252     (ims != NULL && stp->st_mtime <= parse_date_string(ims));
3253 }
3254 
3255 // For given directory path, substitute it to valid index file.
3256 // Return 0 if index file has been found, -1 if not found.
3257 // If the file is found, it's stats is returned in stp.
3258 static int find_index_file(struct connection *conn, char *path,
3259                            size_t path_len, file_stat_t *stp) {
3260   const char *list = conn->server->config_options[INDEX_FILES];
3261   file_stat_t st;
3262   struct vec filename_vec;
3263   size_t n = strlen(path);
3264   int found = 0;
3265 
3266   // The 'path' given to us points to the directory. Remove all trailing
3267   // directory separator characters from the end of the path, and
3268   // then append single directory separator character.
3269   while (n > 0 && path[n - 1] == '/') {
3270     n--;
3271   }
3272   path[n] = '/';
3273 
3274   // Traverse index files list. For each entry, append it to the given
3275   // path and see if the file exists. If it exists, break the loop
3276   while ((list = next_option(list, &filename_vec, NULL)) != NULL) {
3277 
3278     if (path_len <= n + 2) {
3279       continue;
3280     }
3281 
3282     // Ignore too long entries that may overflow path buffer
3283     if (filename_vec.len > (path_len - (n + 2)))
3284       continue;
3285 
3286     // Prepare full path to the index file
3287     strncpy(path + n + 1, filename_vec.ptr, filename_vec.len);
3288     path[n + 1 + filename_vec.len] = '\0';
3289 
3290     //DBG(("[%s]", path));
3291 
3292     // Does it exist?
3293     if (!stat(path, &st)) {
3294       // Yes it does, break the loop
3295       *stp = st;
3296       found = 1;
3297       break;
3298     }
3299   }
3300 
3301   // If no index file exists, restore directory path
3302   if (!found) {
3303     path[n] = '\0';
3304   }
3305 
3306   return found;
3307 }
3308 
3309 static int parse_range_header(const char *header, int64_t *a, int64_t *b) {
3310   return sscanf(header, "bytes=%" INT64_FMT "-%" INT64_FMT, a, b);
3311 }
3312 
3313 static void gmt_time_string(char *buf, size_t buf_len, time_t *t) {
3314   strftime(buf, buf_len, "%a, %d %b %Y %H:%M:%S GMT", gmtime(t));
3315 }
3316 
3317 static void open_file_endpoint(struct connection *conn, const char *path,
3318                                file_stat_t *st, const char *extra_headers) {
3319   char date[64], lm[64], etag[64], range[64], headers[1000];
3320   const char *msg = "OK", *hdr;
3321   time_t curtime = time(NULL);
3322   int64_t r1, r2;
3323   struct vec mime_vec;
3324   int n;
3325 
3326   conn->endpoint_type = EP_FILE;
3327   ns_set_close_on_exec(conn->endpoint.fd);
3328   conn->mg_conn.status_code = 200;
3329 
3330   get_mime_type(conn->server, path, &mime_vec);
3331   conn->cl = st->st_size;
3332   range[0] = '\0';
3333 
3334   // If Range: header specified, act accordingly
3335   r1 = r2 = 0;
3336   hdr = mg_get_header(&conn->mg_conn, "Range");
3337   if (hdr != NULL && (n = parse_range_header(hdr, &r1, &r2)) > 0 &&
3338       r1 >= 0 && r2 >= 0) {
3339     conn->mg_conn.status_code = 206;
3340     conn->cl = n == 2 ? (r2 > conn->cl ? conn->cl : r2) - r1 + 1: conn->cl - r1;
3341     mg_snprintf(range, sizeof(range), "Content-Range: bytes "
3342                 "%" INT64_FMT "-%" INT64_FMT "/%" INT64_FMT "\r\n",
3343                 r1, r1 + conn->cl - 1, (int64_t) st->st_size);
3344     msg = "Partial Content";
3345     lseek(conn->endpoint.fd, r1, SEEK_SET);
3346   }
3347 
3348   // Prepare Etag, Date, Last-Modified headers. Must be in UTC, according to
3349   // http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.3
3350   gmt_time_string(date, sizeof(date), &curtime);
3351   gmt_time_string(lm, sizeof(lm), &st->st_mtime);
3352   construct_etag(etag, sizeof(etag), st);
3353 
3354   n = mg_snprintf(headers, sizeof(headers),
3355                   "HTTP/1.1 %d %s\r\n"
3356                   "Date: %s\r\n"
3357                   "Last-Modified: %s\r\n"
3358                   "Etag: %s\r\n"
3359                   "Content-Type: %.*s\r\n"
3360                   "Content-Length: %" INT64_FMT "\r\n"
3361                   "Connection: %s\r\n"
3362                   "Accept-Ranges: bytes\r\n"
3363                   "%s%s%s\r\n",
3364                   conn->mg_conn.status_code, msg, date, lm, etag,
3365                   (int) mime_vec.len, mime_vec.ptr, conn->cl,
3366                   suggest_connection_header(&conn->mg_conn),
3367                   range, extra_headers == NULL ? "" : extra_headers,
3368                   MONGOOSE_USE_EXTRA_HTTP_HEADERS);
3369   ns_send(conn->ns_conn, headers, n);
3370 
3371   if (!strcmp(conn->mg_conn.request_method, "HEAD")) {
3372     conn->ns_conn->flags |= NSF_FINISHED_SENDING_DATA;
3373     close(conn->endpoint.fd);
3374     conn->endpoint_type = EP_NONE;
3375   }
3376 }
3377 
3378 void mg_send_file_data(struct mg_connection *c, int fd) {
3379   struct connection *conn = MG_CONN_2_CONN(c);
3380   conn->endpoint_type = EP_FILE;
3381   conn->endpoint.fd = fd;
3382   ns_set_close_on_exec(conn->endpoint.fd);
3383 }
3384 #endif  // MONGOOSE_NO_FILESYSTEM
3385 
3386 static void call_request_handler_if_data_is_buffered(struct connection *conn) {
3387 #ifndef MONGOOSE_NO_WEBSOCKET
3388   if (conn->mg_conn.is_websocket) {
3389     do { } while (deliver_websocket_frame(conn));
3390   } else
3391 #endif
3392   if (conn->num_bytes_recv >= (conn->cl + conn->request_len) &&
3393       call_request_handler(conn) == MG_FALSE) {
3394     open_local_endpoint(conn, 1);
3395   }
3396 }
3397 
3398 #if !defined(MONGOOSE_NO_DIRECTORY_LISTING) || !defined(MONGOOSE_NO_DAV)
3399 
3400 #ifdef _WIN32
3401 struct dirent {
3402   char d_name[MAX_PATH_SIZE];
3403 };
3404 
3405 typedef struct DIR {
3406   HANDLE   handle;
3407   WIN32_FIND_DATAW info;
3408   struct dirent result;
3409 } DIR;
3410 
3411 // Implementation of POSIX opendir/closedir/readdir for Windows.
3412 static DIR *opendir(const char *name) {
3413   DIR *dir = NULL;
3414   wchar_t wpath[MAX_PATH_SIZE];
3415   DWORD attrs;
3416 
3417   if (name == NULL) {
3418     SetLastError(ERROR_BAD_ARGUMENTS);
3419   } else if ((dir = (DIR *) NS_MALLOC(sizeof(*dir))) == NULL) {
3420     SetLastError(ERROR_NOT_ENOUGH_MEMORY);
3421   } else {
3422     to_wchar(name, wpath, ARRAY_SIZE(wpath));
3423     attrs = GetFileAttributesW(wpath);
3424     if (attrs != 0xFFFFFFFF &&
3425         ((attrs & FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY)) {
3426       (void) wcscat(wpath, L"\\*");
3427       dir->handle = FindFirstFileW(wpath, &dir->info);
3428       dir->result.d_name[0] = '\0';
3429     } else {
3430       NS_FREE(dir);
3431       dir = NULL;
3432     }
3433   }
3434 
3435   return dir;
3436 }
3437 
3438 static int closedir(DIR *dir) {
3439   int result = 0;
3440 
3441   if (dir != NULL) {
3442     if (dir->handle != INVALID_HANDLE_VALUE)
3443       result = FindClose(dir->handle) ? 0 : -1;
3444 
3445     NS_FREE(dir);
3446   } else {
3447     result = -1;
3448     SetLastError(ERROR_BAD_ARGUMENTS);
3449   }
3450 
3451   return result;
3452 }
3453 
3454 static struct dirent *readdir(DIR *dir) {
3455   struct dirent *result = 0;
3456 
3457   if (dir) {
3458     if (dir->handle != INVALID_HANDLE_VALUE) {
3459       result = &dir->result;
3460       (void) WideCharToMultiByte(CP_UTF8, 0,
3461           dir->info.cFileName, -1, result->d_name,
3462           sizeof(result->d_name), NULL, NULL);
3463 
3464       if (!FindNextFileW(dir->handle, &dir->info)) {
3465         (void) FindClose(dir->handle);
3466         dir->handle = INVALID_HANDLE_VALUE;
3467       }
3468 
3469     } else {
3470       SetLastError(ERROR_FILE_NOT_FOUND);
3471     }
3472   } else {
3473     SetLastError(ERROR_BAD_ARGUMENTS);
3474   }
3475 
3476   return result;
3477 }
3478 #endif // _WIN32  POSIX opendir/closedir/readdir implementation
3479 
3480 static int scan_directory(struct connection *conn, const char *dir,
3481                           struct dir_entry **arr) {
3482   char path[MAX_PATH_SIZE];
3483   struct dir_entry *p;
3484   struct dirent *dp;
3485   int arr_size = 0, arr_ind = 0, inc = 100;
3486   DIR *dirp;
3487 
3488   *arr = NULL;
3489   if ((dirp = (opendir(dir))) == NULL) return 0;
3490 
3491   while ((dp = readdir(dirp)) != NULL) {
3492     // Do not show current dir and hidden files
3493     if (!strcmp(dp->d_name, ".") ||
3494         !strcmp(dp->d_name, "..") ||
3495         must_hide_file(conn, dp->d_name)) {
3496       continue;
3497     }
3498     mg_snprintf(path, sizeof(path), "%s%c%s", dir, '/', dp->d_name);
3499 
3500     // Resize the array if nesessary
3501     if (arr_ind >= arr_size) {
3502       if ((p = (struct dir_entry *)
3503            NS_REALLOC(*arr, (inc + arr_size) * sizeof(**arr))) != NULL) {
3504         // Memset new chunk to zero, otherwize st_mtime will have garbage which
3505         // can make strftime() segfault, see
3506         // http://code.google.com/p/mongoose/issues/detail?id=79
3507         memset(p + arr_size, 0, sizeof(**arr) * inc);
3508 
3509         *arr = p;
3510         arr_size += inc;
3511       }
3512     }
3513 
3514     if (arr_ind < arr_size) {
3515       (*arr)[arr_ind].conn = conn;
3516       (*arr)[arr_ind].file_name = strdup(dp->d_name);
3517       stat(path, &(*arr)[arr_ind].st);
3518       arr_ind++;
3519     }
3520   }
3521   closedir(dirp);
3522 
3523   return arr_ind;
3524 }
3525 
3526 size_t mg_url_encode(const char *src, size_t s_len, char *dst, size_t dst_len) {
3527   static const char *dont_escape = "._-$,;~()";
3528   static const char *hex = "0123456789abcdef";
3529   size_t i = 0, j = 0;
3530 
3531   for (i = j = 0; dst_len > 0 && i < s_len && j + 2 < dst_len - 1; i++, j++) {
3532     if (isalnum(* (const unsigned char *) (src + i)) ||
3533         strchr(dont_escape, * (const unsigned char *) (src + i)) != NULL) {
3534       dst[j] = src[i];
3535     } else if (j + 3 < dst_len) {
3536       dst[j] = '%';
3537       dst[j + 1] = hex[(* (const unsigned char *) (src + i)) >> 4];
3538       dst[j + 2] = hex[(* (const unsigned char *) (src + i)) & 0xf];
3539       j += 2;
3540     }
3541   }
3542 
3543   dst[j] = '\0';
3544   return j;
3545 }
3546 #endif  // !NO_DIRECTORY_LISTING || !MONGOOSE_NO_DAV
3547 
3548 #ifndef MONGOOSE_NO_DIRECTORY_LISTING
3549 
3550 static void print_dir_entry(const struct dir_entry *de) {
3551   char size[64], mod[64], href[MAX_PATH_SIZE * 3];
3552   int64_t fsize = de->st.st_size;
3553   int is_dir = S_ISDIR(de->st.st_mode);
3554   const char *slash = is_dir ? "/" : "";
3555 
3556   if (is_dir) {
3557     mg_snprintf(size, sizeof(size), "%s", "[DIRECTORY]");
3558   } else {
3559      // We use (signed) cast below because MSVC 6 compiler cannot
3560      // convert unsigned __int64 to double.
3561     if (fsize < 1024) {
3562       mg_snprintf(size, sizeof(size), "%d", (int) fsize);
3563     } else if (fsize < 0x100000) {
3564       mg_snprintf(size, sizeof(size), "%.1fk", (double) fsize / 1024.0);
3565     } else if (fsize < 0x40000000) {
3566       mg_snprintf(size, sizeof(size), "%.1fM", (double) fsize / 1048576);
3567     } else {
3568       mg_snprintf(size, sizeof(size), "%.1fG", (double) fsize / 1073741824);
3569     }
3570   }
3571   strftime(mod, sizeof(mod), "%d-%b-%Y %H:%M", localtime(&de->st.st_mtime));
3572   mg_url_encode(de->file_name, strlen(de->file_name), href, sizeof(href));
3573   mg_printf_data(&de->conn->mg_conn,
3574                   "<tr><td><a href=\"%s%s\">%s%s</a></td>"
3575                   "<td>&nbsp;%s</td><td>&nbsp;&nbsp;%s</td></tr>\n",
3576                   href, slash, de->file_name, slash, mod, size);
3577 }
3578 
3579 // Sort directory entries by size, or name, or modification time.
3580 // On windows, __cdecl specification is needed in case if project is built
3581 // with __stdcall convention. qsort always requires __cdels callback.
3582 static int __cdecl compare_dir_entries(const void *p1, const void *p2) {
3583   const struct dir_entry *a = (const struct dir_entry *) p1,
3584         *b = (const struct dir_entry *) p2;
3585   const char *qs = a->conn->mg_conn.query_string ?
3586     a->conn->mg_conn.query_string : "na";
3587   int cmp_result = 0;
3588 
3589   if (S_ISDIR(a->st.st_mode) && !S_ISDIR(b->st.st_mode)) {
3590     return -1;  // Always put directories on top
3591   } else if (!S_ISDIR(a->st.st_mode) && S_ISDIR(b->st.st_mode)) {
3592     return 1;   // Always put directories on top
3593   } else if (*qs == 'n') {
3594     cmp_result = strcmp(a->file_name, b->file_name);
3595   } else if (*qs == 's') {
3596     cmp_result = a->st.st_size == b->st.st_size ? 0 :
3597       a->st.st_size > b->st.st_size ? 1 : -1;
3598   } else if (*qs == 'd') {
3599     cmp_result = a->st.st_mtime == b->st.st_mtime ? 0 :
3600       a->st.st_mtime > b->st.st_mtime ? 1 : -1;
3601   }
3602 
3603   return qs[1] == 'd' ? -cmp_result : cmp_result;
3604 }
3605 
3606 static void send_directory_listing(struct connection *conn, const char *dir) {
3607   struct dir_entry *arr = NULL;
3608   int i, num_entries, sort_direction = conn->mg_conn.query_string != NULL &&
3609     conn->mg_conn.query_string[1] == 'd' ? 'a' : 'd';
3610 
3611   mg_send_header(&conn->mg_conn, "Transfer-Encoding", "chunked");
3612   mg_send_header(&conn->mg_conn, "Content-Type", "text/html; charset=utf-8");
3613 
3614   mg_printf_data(&conn->mg_conn,
3615               "<html><head><title>Index of %s</title>"
3616               "<style>th {text-align: left;}</style></head>"
3617               "<body><h1>Index of %s</h1><pre><table cellpadding=\"0\">"
3618               "<tr><th><a href=\"?n%c\">Name</a></th>"
3619               "<th><a href=\"?d%c\">Modified</a></th>"
3620               "<th><a href=\"?s%c\">Size</a></th></tr>"
3621               "<tr><td colspan=\"3\"><hr></td></tr>",
3622               conn->mg_conn.uri, conn->mg_conn.uri,
3623               sort_direction, sort_direction, sort_direction);
3624 
3625   num_entries = scan_directory(conn, dir, &arr);
3626   qsort(arr, num_entries, sizeof(arr[0]), compare_dir_entries);
3627   for (i = 0; i < num_entries; i++) {
3628     print_dir_entry(&arr[i]);
3629     NS_FREE(arr[i].file_name);
3630   }
3631   NS_FREE(arr);
3632 
3633   write_terminating_chunk(conn);
3634   close_local_endpoint(conn);
3635 }
3636 #endif  // MONGOOSE_NO_DIRECTORY_LISTING
3637 
3638 #ifndef MONGOOSE_NO_DAV
3639 static void print_props(struct connection *conn, const char *uri,
3640                         file_stat_t *stp) {
3641   char mtime[64];
3642 
3643   gmt_time_string(mtime, sizeof(mtime), &stp->st_mtime);
3644   mg_printf(&conn->mg_conn,
3645       "<d:response>"
3646        "<d:href>%s</d:href>"
3647        "<d:propstat>"
3648         "<d:prop>"
3649          "<d:resourcetype>%s</d:resourcetype>"
3650          "<d:getcontentlength>%" INT64_FMT "</d:getcontentlength>"
3651          "<d:getlastmodified>%s</d:getlastmodified>"
3652         "</d:prop>"
3653         "<d:status>HTTP/1.1 200 OK</d:status>"
3654        "</d:propstat>"
3655       "</d:response>\n",
3656       uri, S_ISDIR(stp->st_mode) ? "<d:collection/>" : "",
3657       (int64_t) stp->st_size, mtime);
3658 }
3659 
3660 static void handle_propfind(struct connection *conn, const char *path,
3661                             file_stat_t *stp, int exists) {
3662   static const char header[] = "HTTP/1.1 207 Multi-Status\r\n"
3663     "Connection: close\r\n"
3664     "Content-Type: text/xml; charset=utf-8\r\n\r\n"
3665     "<?xml version=\"1.0\" encoding=\"utf-8\"?>"
3666     "<d:multistatus xmlns:d='DAV:'>\n";
3667   static const char footer[] = "</d:multistatus>";
3668   const char *depth = mg_get_header(&conn->mg_conn, "Depth");
3669 #ifdef MONGOOSE_NO_DIRECTORY_LISTING
3670   const char *list_dir = "no";
3671 #else
3672   const char *list_dir = conn->server->config_options[ENABLE_DIRECTORY_LISTING];
3673 #endif
3674 
3675   conn->mg_conn.status_code = 207;
3676 
3677   // Print properties for the requested resource itself
3678   if (!exists) {
3679     conn->mg_conn.status_code = 404;
3680     mg_printf(&conn->mg_conn, "%s", "HTTP/1.1 404 Not Found\r\n\r\n");
3681   } else if (S_ISDIR(stp->st_mode) && mg_strcasecmp(list_dir, "yes") != 0) {
3682     conn->mg_conn.status_code = 403;
3683     mg_printf(&conn->mg_conn, "%s",
3684               "HTTP/1.1 403 Directory Listing Denied\r\n\r\n");
3685   } else {
3686     ns_send(conn->ns_conn, header, sizeof(header) - 1);
3687     print_props(conn, conn->mg_conn.uri, stp);
3688 
3689     if (S_ISDIR(stp->st_mode) &&
3690              (depth == NULL || strcmp(depth, "0") != 0)) {
3691       struct dir_entry *arr = NULL;
3692       int i, num_entries = scan_directory(conn, path, &arr);
3693 
3694       for (i = 0; i < num_entries; i++) {
3695         char buf[MAX_PATH_SIZE * 3];
3696         struct dir_entry *de = &arr[i];
3697         mg_url_encode(de->file_name, strlen(de->file_name), buf, sizeof(buf));
3698         print_props(conn, buf, &de->st);
3699         NS_FREE(de->file_name);
3700       }
3701       NS_FREE(arr);
3702     }
3703     ns_send(conn->ns_conn, footer, sizeof(footer) - 1);
3704   }
3705 
3706   close_local_endpoint(conn);
3707 }
3708 
3709 static void handle_mkcol(struct connection *conn, const char *path) {
3710   int status_code = 500;
3711 
3712   if (conn->mg_conn.content_len > 0) {
3713     status_code = 415;
3714   } else if (!mkdir(path, 0755)) {
3715     status_code = 201;
3716   } else if (errno == EEXIST) {
3717     status_code = 405;
3718   } else if (errno == EACCES) {
3719     status_code = 403;
3720   } else if (errno == ENOENT) {
3721     status_code = 409;
3722   }
3723   send_http_error(conn, status_code, NULL);
3724 }
3725 
3726 static int remove_directory(const char *dir) {
3727   char path[MAX_PATH_SIZE];
3728   struct dirent *dp;
3729   file_stat_t st;
3730   DIR *dirp;
3731 
3732   if ((dirp = opendir(dir)) == NULL) return 0;
3733 
3734   while ((dp = readdir(dirp)) != NULL) {
3735     if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, "..")) continue;
3736     mg_snprintf(path, sizeof(path), "%s%c%s", dir, '/', dp->d_name);
3737     stat(path, &st);
3738     if (S_ISDIR(st.st_mode)) {
3739       remove_directory(path);
3740     } else {
3741       remove(path);
3742     }
3743   }
3744   closedir(dirp);
3745   rmdir(dir);
3746 
3747   return 1;
3748 }
3749 
3750 static void handle_delete(struct connection *conn, const char *path) {
3751   file_stat_t st;
3752 
3753   if (stat(path, &st) != 0) {
3754     send_http_error(conn, 404, NULL);
3755   } else if (S_ISDIR(st.st_mode)) {
3756     remove_directory(path);
3757     send_http_error(conn, 204, NULL);
3758   } else if (remove(path) == 0) {
3759     send_http_error(conn, 204, NULL);
3760   } else {
3761     send_http_error(conn, 423, NULL);
3762   }
3763 }
3764 
3765 // For a given PUT path, create all intermediate subdirectories
3766 // for given path. Return 0 if the path itself is a directory,
3767 // or -1 on error, 1 if OK.
3768 static int put_dir(const char *path) {
3769   char buf[MAX_PATH_SIZE];
3770   const char *s, *p;
3771   file_stat_t st;
3772 
3773   // Create intermediate directories if they do not exist
3774   for (s = p = path + 1; (p = strchr(s, '/')) != NULL; s = ++p) {
3775     if (p - path >= (int) sizeof(buf)) return -1; // Buffer overflow
3776     memcpy(buf, path, p - path);
3777     buf[p - path] = '\0';
3778     if (stat(buf, &st) != 0 && mkdir(buf, 0755) != 0) return -1;
3779     if (p[1] == '\0') return 0;  // Path is a directory itself
3780   }
3781 
3782   return 1;
3783 }
3784 
3785 static void handle_put(struct connection *conn, const char *path) {
3786   file_stat_t st;
3787   const char *range, *cl_hdr = mg_get_header(&conn->mg_conn, "Content-Length");
3788   int64_t r1, r2;
3789   int rc;
3790 
3791   conn->mg_conn.status_code = !stat(path, &st) ? 200 : 201;
3792   if ((rc = put_dir(path)) == 0) {
3793     mg_printf(&conn->mg_conn, "HTTP/1.1 %d OK\r\n\r\n",
3794               conn->mg_conn.status_code);
3795     close_local_endpoint(conn);
3796   } else if (rc == -1) {
3797     send_http_error(conn, 500, "put_dir: %s", strerror(errno));
3798   } else if (cl_hdr == NULL) {
3799     send_http_error(conn, 411, NULL);
3800   } else if ((conn->endpoint.fd =
3801               open(path, O_RDWR | O_CREAT | O_TRUNC | O_BINARY, 0644)) < 0) {
3802     send_http_error(conn, 500, "open(%s): %s", path, strerror(errno));
3803   } else {
3804     DBG(("PUT [%s] %lu", path, (unsigned long) conn->ns_conn->recv_iobuf.len));
3805     conn->endpoint_type = EP_PUT;
3806     ns_set_close_on_exec(conn->endpoint.fd);
3807     range = mg_get_header(&conn->mg_conn, "Content-Range");
3808     conn->cl = to64(cl_hdr);
3809     r1 = r2 = 0;
3810     if (range != NULL && parse_range_header(range, &r1, &r2) > 0) {
3811       conn->mg_conn.status_code = 206;
3812       lseek(conn->endpoint.fd, r1, SEEK_SET);
3813       conn->cl = r2 > r1 ? r2 - r1 + 1: conn->cl - r1;
3814     }
3815     mg_printf(&conn->mg_conn, "HTTP/1.1 %d OK\r\nContent-Length: 0\r\n\r\n",
3816               conn->mg_conn.status_code);
3817   }
3818 }
3819 
3820 static void forward_put_data(struct connection *conn) {
3821   struct iobuf *io = &conn->ns_conn->recv_iobuf;
3822   size_t k = conn->cl < (int64_t) io->len ? conn->cl : (int64_t) io->len;   // To write
3823   size_t n = write(conn->endpoint.fd, io->buf, k);   // Write them!
3824   if (n > 0) {
3825     iobuf_remove(io, n);
3826     conn->cl -= n;
3827   }
3828   if (conn->cl <= 0) {
3829     close_local_endpoint(conn);
3830   }
3831 }
3832 #endif //  MONGOOSE_NO_DAV
3833 
3834 static void send_options(struct connection *conn) {
3835   conn->mg_conn.status_code = 200;
3836   mg_printf(&conn->mg_conn, "%s",
3837             "HTTP/1.1 200 OK\r\nAllow: GET, POST, HEAD, CONNECT, PUT, "
3838             "DELETE, OPTIONS, PROPFIND, MKCOL\r\nDAV: 1\r\n\r\n");
3839   close_local_endpoint(conn);
3840 }
3841 
3842 #ifndef MONGOOSE_NO_AUTH
3843 void mg_send_digest_auth_request(struct mg_connection *c) {
3844   struct connection *conn = MG_CONN_2_CONN(c);
3845   c->status_code = 401;
3846   mg_printf(c,
3847             "HTTP/1.1 401 Unauthorized\r\n"
3848             "WWW-Authenticate: Digest qop=\"auth\", "
3849             "realm=\"%s\", nonce=\"%lu\"\r\n\r\n",
3850             conn->server->config_options[AUTH_DOMAIN],
3851             (unsigned long) time(NULL));
3852   close_local_endpoint(conn);
3853 }
3854 
3855 // Use the global passwords file, if specified by auth_gpass option,
3856 // or search for .htpasswd in the requested directory.
3857 static FILE *open_auth_file(struct connection *conn, const char *path,
3858                             int is_directory) {
3859   char name[MAX_PATH_SIZE];
3860   const char *p, *gpass = conn->server->config_options[GLOBAL_AUTH_FILE];
3861   FILE *fp = NULL;
3862 
3863   if (gpass != NULL) {
3864     // Use global passwords file
3865     fp = fopen(gpass, "r");
3866   } else if (is_directory) {
3867     mg_snprintf(name, sizeof(name), "%s%c%s", path, '/', PASSWORDS_FILE_NAME);
3868     fp = fopen(name, "r");
3869   } else {
3870     // Try to find .htpasswd in requested directory.
3871     if ((p = strrchr(path, '/')) == NULL) p = path;
3872     mg_snprintf(name, sizeof(name), "%.*s%c%s",
3873                 (int) (p - path), path, '/', PASSWORDS_FILE_NAME);
3874     fp = fopen(name, "r");
3875   }
3876 
3877   return fp;
3878 }
3879 
3880 #if !defined(HAVE_MD5) && !defined(MONGOOSE_NO_AUTH)
3881 /*
3882  * This code implements the MD5 message-digest algorithm.
3883  * The algorithm is due to Ron Rivest.	This code was
3884  * written by Colin Plumb in 1993, no copyright is claimed.
3885  * This code is in the public domain; do with it what you wish.
3886  *
3887  * Equivalent code is available from RSA Data Security, Inc.
3888  * This code has been tested against that, and is equivalent,
3889  * except that you don't need to include two pages of legalese
3890  * with every copy.
3891  *
3892  * To compute the message digest of a chunk of bytes, declare an
3893  * MD5Context structure, pass it to MD5Init, call MD5Update as
3894  * needed on buffers full of bytes, and then call MD5Final, which
3895  * will fill a supplied 16-byte array with the digest.
3896  */
3897 
3898 typedef struct MD5Context {
3899   uint32_t buf[4];
3900   uint32_t bits[2];
3901   unsigned char in[64];
3902 } MD5_CTX;
3903 
3904 static void byteReverse(unsigned char *buf, unsigned longs) {
3905   uint32_t t;
3906 
3907   // Forrest: MD5 expect LITTLE_ENDIAN, swap if BIG_ENDIAN
3908   if (is_big_endian()) {
3909     do {
3910       t = (uint32_t) ((unsigned) buf[3] << 8 | buf[2]) << 16 |
3911         ((unsigned) buf[1] << 8 | buf[0]);
3912       * (uint32_t *) buf = t;
3913       buf += 4;
3914     } while (--longs);
3915   }
3916 }
3917 
3918 #define F1(x, y, z) (z ^ (x & (y ^ z)))
3919 #define F2(x, y, z) F1(z, x, y)
3920 #define F3(x, y, z) (x ^ y ^ z)
3921 #define F4(x, y, z) (y ^ (x | ~z))
3922 
3923 #define MD5STEP(f, w, x, y, z, data, s) \
3924   ( w += f(x, y, z) + data,  w = w<<s | w>>(32-s),  w += x )
3925 
3926 // Start MD5 accumulation.  Set bit count to 0 and buffer to mysterious
3927 // initialization constants.
3928 static void MD5Init(MD5_CTX *ctx) {
3929   ctx->buf[0] = 0x67452301;
3930   ctx->buf[1] = 0xefcdab89;
3931   ctx->buf[2] = 0x98badcfe;
3932   ctx->buf[3] = 0x10325476;
3933 
3934   ctx->bits[0] = 0;
3935   ctx->bits[1] = 0;
3936 }
3937 
3938 static void MD5Transform(uint32_t buf[4], uint32_t const in[16]) {
3939   register uint32_t a, b, c, d;
3940 
3941   a = buf[0];
3942   b = buf[1];
3943   c = buf[2];
3944   d = buf[3];
3945 
3946   MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7);
3947   MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12);
3948   MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17);
3949   MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22);
3950   MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7);
3951   MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12);
3952   MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17);
3953   MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22);
3954   MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7);
3955   MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12);
3956   MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17);
3957   MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22);
3958   MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7);
3959   MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12);
3960   MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17);
3961   MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22);
3962 
3963   MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5);
3964   MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9);
3965   MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14);
3966   MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20);
3967   MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5);
3968   MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9);
3969   MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14);
3970   MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20);
3971   MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5);
3972   MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9);
3973   MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14);
3974   MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20);
3975   MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5);
3976   MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9);
3977   MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14);
3978   MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20);
3979 
3980   MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4);
3981   MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11);
3982   MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16);
3983   MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23);
3984   MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4);
3985   MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11);
3986   MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16);
3987   MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23);
3988   MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4);
3989   MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11);
3990   MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16);
3991   MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23);
3992   MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4);
3993   MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11);
3994   MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16);
3995   MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23);
3996 
3997   MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6);
3998   MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10);
3999   MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15);
4000   MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21);
4001   MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6);
4002   MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10);
4003   MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15);
4004   MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21);
4005   MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6);
4006   MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10);
4007   MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15);
4008   MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21);
4009   MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6);
4010   MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10);
4011   MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15);
4012   MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21);
4013 
4014   buf[0] += a;
4015   buf[1] += b;
4016   buf[2] += c;
4017   buf[3] += d;
4018 }
4019 
4020 static void MD5Update(MD5_CTX *ctx, unsigned char const *buf, unsigned len) {
4021   uint32_t t;
4022 
4023   t = ctx->bits[0];
4024   if ((ctx->bits[0] = t + ((uint32_t) len << 3)) < t)
4025     ctx->bits[1]++;
4026   ctx->bits[1] += len >> 29;
4027 
4028   t = (t >> 3) & 0x3f;
4029 
4030   if (t) {
4031     unsigned char *p = (unsigned char *) ctx->in + t;
4032 
4033     t = 64 - t;
4034     if (len < t) {
4035       memcpy(p, buf, len);
4036       return;
4037     }
4038     memcpy(p, buf, t);
4039     byteReverse(ctx->in, 16);
4040     MD5Transform(ctx->buf, (uint32_t *) ctx->in);
4041     buf += t;
4042     len -= t;
4043   }
4044 
4045   while (len >= 64) {
4046     memcpy(ctx->in, buf, 64);
4047     byteReverse(ctx->in, 16);
4048     MD5Transform(ctx->buf, (uint32_t *) ctx->in);
4049     buf += 64;
4050     len -= 64;
4051   }
4052 
4053   memcpy(ctx->in, buf, len);
4054 }
4055 
4056 static void MD5Final(unsigned char digest[16], MD5_CTX *ctx) {
4057   unsigned count;
4058   unsigned char *p;
4059   uint32_t *a;
4060 
4061   count = (ctx->bits[0] >> 3) & 0x3F;
4062 
4063   p = ctx->in + count;
4064   *p++ = 0x80;
4065   count = 64 - 1 - count;
4066   if (count < 8) {
4067     memset(p, 0, count);
4068     byteReverse(ctx->in, 16);
4069     MD5Transform(ctx->buf, (uint32_t *) ctx->in);
4070     memset(ctx->in, 0, 56);
4071   } else {
4072     memset(p, 0, count - 8);
4073   }
4074   byteReverse(ctx->in, 14);
4075 
4076   a = (uint32_t *)ctx->in;
4077   a[14] = ctx->bits[0];
4078   a[15] = ctx->bits[1];
4079 
4080   MD5Transform(ctx->buf, (uint32_t *) ctx->in);
4081   byteReverse((unsigned char *) ctx->buf, 4);
4082   memcpy(digest, ctx->buf, 16);
4083   memset((char *) ctx, 0, sizeof(*ctx));
4084 }
4085 #endif // !HAVE_MD5
4086 
4087 
4088 
4089 // Stringify binary data. Output buffer must be twice as big as input,
4090 // because each byte takes 2 bytes in string representation
4091 static void bin2str(char *to, const unsigned char *p, size_t len) {
4092   static const char *hex = "0123456789abcdef";
4093 
4094   for (; len--; p++) {
4095     *to++ = hex[p[0] >> 4];
4096     *to++ = hex[p[0] & 0x0f];
4097   }
4098   *to = '\0';
4099 }
4100 
4101 // Return stringified MD5 hash for list of strings. Buffer must be 33 bytes.
4102 char *mg_md5(char buf[33], ...) {
4103   unsigned char hash[16];
4104   const char *p;
4105   va_list ap;
4106   MD5_CTX ctx;
4107 
4108   MD5Init(&ctx);
4109 
4110   va_start(ap, buf);
4111   while ((p = va_arg(ap, const char *)) != NULL) {
4112     MD5Update(&ctx, (const unsigned char *) p, (unsigned) strlen(p));
4113   }
4114   va_end(ap);
4115 
4116   MD5Final(hash, &ctx);
4117   bin2str(buf, hash, sizeof(hash));
4118   return buf;
4119 }
4120 
4121 // Check the user's password, return 1 if OK
4122 static int check_password(const char *method, const char *ha1, const char *uri,
4123                           const char *nonce, const char *nc, const char *cnonce,
4124                           const char *qop, const char *response) {
4125   char ha2[32 + 1], expected_response[32 + 1];
4126 
4127 #if 0
4128   // Check for authentication timeout
4129   if ((unsigned long) time(NULL) - (unsigned long) to64(nonce) > 3600 * 2) {
4130     return 0;
4131   }
4132 #endif
4133 
4134   mg_md5(ha2, method, ":", uri, NULL);
4135   mg_md5(expected_response, ha1, ":", nonce, ":", nc,
4136       ":", cnonce, ":", qop, ":", ha2, NULL);
4137 
4138   return mg_strcasecmp(response, expected_response) == 0 ? MG_TRUE : MG_FALSE;
4139 }
4140 
4141 
4142 // Authorize against the opened passwords file. Return 1 if authorized.
4143 int mg_authorize_digest(struct mg_connection *c, FILE *fp) {
4144   struct connection *conn = MG_CONN_2_CONN(c);
4145   const char *hdr;
4146   char line[256], f_user[256], ha1[256], f_domain[256], user[100], nonce[100],
4147        uri[MAX_REQUEST_SIZE], cnonce[100], resp[100], qop[100], nc[100];
4148 
4149   if (c == NULL || fp == NULL) return 0;
4150   if ((hdr = mg_get_header(c, "Authorization")) == NULL ||
4151       mg_strncasecmp(hdr, "Digest ", 7) != 0) return 0;
4152   if (!mg_parse_header(hdr, "username", user, sizeof(user))) return 0;
4153   if (!mg_parse_header(hdr, "cnonce", cnonce, sizeof(cnonce))) return 0;
4154   if (!mg_parse_header(hdr, "response", resp, sizeof(resp))) return 0;
4155   if (!mg_parse_header(hdr, "uri", uri, sizeof(uri))) return 0;
4156   if (!mg_parse_header(hdr, "qop", qop, sizeof(qop))) return 0;
4157   if (!mg_parse_header(hdr, "nc", nc, sizeof(nc))) return 0;
4158   if (!mg_parse_header(hdr, "nonce", nonce, sizeof(nonce))) return 0;
4159 
4160   while (fgets(line, sizeof(line), fp) != NULL) {
4161     if (sscanf(line, "%[^:]:%[^:]:%s", f_user, f_domain, ha1) == 3 &&
4162         !strcmp(user, f_user) &&
4163         // NOTE(lsm): due to a bug in MSIE, we do not compare URIs
4164         !strcmp(conn->server->config_options[AUTH_DOMAIN], f_domain))
4165       return check_password(c->request_method, ha1, uri,
4166                             nonce, nc, cnonce, qop, resp);
4167   }
4168   return MG_FALSE;
4169 }
4170 
4171 
4172 // Return 1 if request is authorised, 0 otherwise.
4173 static int is_authorized(struct connection *conn, const char *path,
4174                          int is_directory) {
4175   FILE *fp;
4176   int authorized = MG_TRUE;
4177 
4178   if ((fp = open_auth_file(conn, path, is_directory)) != NULL) {
4179     authorized = mg_authorize_digest(&conn->mg_conn, fp);
4180     fclose(fp);
4181   }
4182 
4183   return authorized;
4184 }
4185 
4186 static int is_authorized_for_dav(struct connection *conn) {
4187   const char *auth_file = conn->server->config_options[DAV_AUTH_FILE];
4188   const char *method = conn->mg_conn.request_method;
4189   FILE *fp;
4190   int authorized = MG_FALSE;
4191 
4192   // If dav_auth_file is not set, allow non-authorized PROPFIND
4193   if (method != NULL && !strcmp(method, "PROPFIND") && auth_file == NULL) {
4194     authorized = MG_TRUE;
4195   } else if (auth_file != NULL && (fp = fopen(auth_file, "r")) != NULL) {
4196     authorized = mg_authorize_digest(&conn->mg_conn, fp);
4197     fclose(fp);
4198   }
4199 
4200   return authorized;
4201 }
4202 #endif // MONGOOSE_NO_AUTH
4203 
4204 static int parse_header(const char *str, size_t str_len, const char *var_name,
4205                         char *buf, size_t buf_size) {
4206   int ch = ' ', ch1 = ',', len = 0;
4207   size_t n = strlen(var_name);
4208   const char *p, *end = str + str_len, *s = NULL;
4209 
4210   if (buf != NULL && buf_size > 0) buf[0] = '\0';
4211 
4212   // Find where variable starts
4213   for (s = str; s != NULL && s + n < end; s++) {
4214     if ((s == str || s[-1] == ch || s[-1] == ch1) && s[n] == '=' &&
4215         !memcmp(s, var_name, n)) break;
4216   }
4217 
4218   if (s != NULL && &s[n + 1] < end) {
4219     s += n + 1;
4220     if (*s == '"' || *s == '\'') ch = ch1 = *s++;
4221     p = s;
4222     while (p < end && p[0] != ch && p[0] != ch1 && len < (int) buf_size) {
4223       if (ch == ch1 && p[0] == '\\' && p[1] == ch) p++;
4224       buf[len++] = *p++;
4225     }
4226     if (len >= (int) buf_size || (ch != ' ' && *p != ch)) {
4227       len = 0;
4228     } else {
4229       if (len > 0 && s[len - 1] == ',') len--;
4230       if (len > 0 && s[len - 1] == ';') len--;
4231       buf[len] = '\0';
4232     }
4233   }
4234 
4235   return len;
4236 }
4237 
4238 int mg_parse_header(const char *s, const char *var_name, char *buf,
4239                     size_t buf_size) {
4240   return parse_header(s, s == NULL ? 0 : strlen(s), var_name, buf, buf_size);
4241 }
4242 
4243 #ifndef MONGOOSE_NO_SSI
4244 static void send_ssi_file(struct mg_connection *, const char *, FILE *, int);
4245 
4246 static void send_file_data(struct mg_connection *conn, FILE *fp) {
4247   char buf[IOBUF_SIZE];
4248   size_t n;
4249   while ((n = fread(buf, 1, sizeof(buf), fp)) > 0) {
4250     mg_write(conn, buf, n);
4251   }
4252 }
4253 
4254 static void do_ssi_include(struct mg_connection *conn, const char *ssi,
4255                            char *tag, int include_level) {
4256   char file_name[IOBUF_SIZE], path[MAX_PATH_SIZE], *p;
4257   char **opts = (MG_CONN_2_CONN(conn))->server->config_options;
4258   FILE *fp;
4259 
4260   // sscanf() is safe here, since send_ssi_file() also uses buffer
4261   // of size MG_BUF_LEN to get the tag. So strlen(tag) is always < MG_BUF_LEN.
4262   if (sscanf(tag, " virtual=\"%[^\"]\"", file_name) == 1) {
4263     // File name is relative to the webserver root
4264     mg_snprintf(path, sizeof(path), "%s%c%s",
4265                 opts[DOCUMENT_ROOT], '/', file_name);
4266   } else if (sscanf(tag, " abspath=\"%[^\"]\"", file_name) == 1) {
4267     // File name is relative to the webserver working directory
4268     // or it is absolute system path
4269     mg_snprintf(path, sizeof(path), "%s", file_name);
4270   } else if (sscanf(tag, " file=\"%[^\"]\"", file_name) == 1 ||
4271              sscanf(tag, " \"%[^\"]\"", file_name) == 1) {
4272     // File name is relative to the currect document
4273     mg_snprintf(path, sizeof(path), "%s", ssi);
4274     if ((p = strrchr(path, '/')) != NULL) {
4275       p[1] = '\0';
4276     }
4277     mg_snprintf(path + strlen(path), sizeof(path) - strlen(path), "%s",
4278                 file_name);
4279   } else {
4280     mg_printf(conn, "Bad SSI #include: [%s]", tag);
4281     return;
4282   }
4283 
4284   if ((fp = fopen(path, "rb")) == NULL) {
4285     mg_printf(conn, "Cannot open SSI #include: [%s]: fopen(%s): %s",
4286               tag, path, strerror(errno));
4287   } else {
4288     ns_set_close_on_exec(fileno(fp));
4289     if (mg_match_prefix(opts[SSI_PATTERN], strlen(opts[SSI_PATTERN]),
4290         path) > 0) {
4291       send_ssi_file(conn, path, fp, include_level + 1);
4292     } else {
4293       send_file_data(conn, fp);
4294     }
4295     fclose(fp);
4296   }
4297 }
4298 
4299 #ifndef MONGOOSE_NO_POPEN
4300 static void do_ssi_exec(struct mg_connection *conn, char *tag) {
4301   char cmd[IOBUF_SIZE];
4302   FILE *fp;
4303 
4304   if (sscanf(tag, " \"%[^\"]\"", cmd) != 1) {
4305     mg_printf(conn, "Bad SSI #exec: [%s]", tag);
4306   } else if ((fp = popen(cmd, "r")) == NULL) {
4307     mg_printf(conn, "Cannot SSI #exec: [%s]: %s", cmd, strerror(errno));
4308   } else {
4309     send_file_data(conn, fp);
4310     pclose(fp);
4311   }
4312 }
4313 #endif // !MONGOOSE_NO_POPEN
4314 
4315 static void send_ssi_file(struct mg_connection *conn, const char *path,
4316                           FILE *fp, int include_level) {
4317   char buf[IOBUF_SIZE];
4318   int ch, offset, len, in_ssi_tag;
4319 
4320   if (include_level > 10) {
4321     mg_printf(conn, "SSI #include level is too deep (%s)", path);
4322     return;
4323   }
4324 
4325   in_ssi_tag = len = offset = 0;
4326   while ((ch = fgetc(fp)) != EOF) {
4327     if (in_ssi_tag && ch == '>') {
4328       in_ssi_tag = 0;
4329       buf[len++] = (char) ch;
4330       buf[len] = '\0';
4331       assert(len <= (int) sizeof(buf));
4332       if (len < 6 || memcmp(buf, "<!--#", 5) != 0) {
4333         // Not an SSI tag, pass it
4334         (void) mg_write(conn, buf, (size_t) len);
4335       } else {
4336         if (!memcmp(buf + 5, "include", 7)) {
4337           do_ssi_include(conn, path, buf + 12, include_level);
4338 #if !defined(MONGOOSE_NO_POPEN)
4339         } else if (!memcmp(buf + 5, "exec", 4)) {
4340           do_ssi_exec(conn, buf + 9);
4341 #endif // !NO_POPEN
4342         } else {
4343           mg_printf(conn, "%s: unknown SSI " "command: \"%s\"", path, buf);
4344         }
4345       }
4346       len = 0;
4347     } else if (in_ssi_tag) {
4348       if (len == 5 && memcmp(buf, "<!--#", 5) != 0) {
4349         // Not an SSI tag
4350         in_ssi_tag = 0;
4351       } else if (len == (int) sizeof(buf) - 2) {
4352         mg_printf(conn, "%s: SSI tag is too large", path);
4353         len = 0;
4354       }
4355       buf[len++] = ch & 0xff;
4356     } else if (ch == '<') {
4357       in_ssi_tag = 1;
4358       if (len > 0) {
4359         mg_write(conn, buf, (size_t) len);
4360       }
4361       len = 0;
4362       buf[len++] = ch & 0xff;
4363     } else {
4364       buf[len++] = ch & 0xff;
4365       if (len == (int) sizeof(buf)) {
4366         mg_write(conn, buf, (size_t) len);
4367         len = 0;
4368       }
4369     }
4370   }
4371 
4372   // Send the rest of buffered data
4373   if (len > 0) {
4374     mg_write(conn, buf, (size_t) len);
4375   }
4376 }
4377 
4378 static void handle_ssi_request(struct connection *conn, const char *path) {
4379   FILE *fp;
4380   struct vec mime_vec;
4381 
4382   if ((fp = fopen(path, "rb")) == NULL) {
4383     send_http_error(conn, 500, "fopen(%s): %s", path, strerror(errno));
4384   } else {
4385     ns_set_close_on_exec(fileno(fp));
4386     get_mime_type(conn->server, path, &mime_vec);
4387     conn->mg_conn.status_code = 200;
4388     mg_printf(&conn->mg_conn,
4389               "HTTP/1.1 %d OK\r\n"
4390               "Content-Type: %.*s\r\n"
4391               "Connection: close\r\n\r\n",
4392               conn->mg_conn.status_code, (int) mime_vec.len, mime_vec.ptr);
4393     send_ssi_file(&conn->mg_conn, path, fp, 0);
4394     fclose(fp);
4395     close_local_endpoint(conn);
4396   }
4397 }
4398 #endif
4399 
4400 static void proxy_request(struct ns_connection *pc, struct mg_connection *c) {
4401   int i, sent_close_header = 0;
4402 
4403   ns_printf(pc, "%s %s%s%s HTTP/%s\r\n", c->request_method, c->uri,
4404             c->query_string ? "?" : "",
4405             c->query_string ? c->query_string : "",
4406             c->http_version);
4407   for (i = 0; i < c->num_headers; i++) {
4408     if (mg_strcasecmp(c->http_headers[i].name, "Connection") == 0) {
4409       // Force connection close, cause we don't parse proxy replies
4410       // therefore we don't know message boundaries
4411       ns_printf(pc, "%s: %s\r\n", "Connection", "close");
4412       sent_close_header = 1;
4413     } else {
4414       ns_printf(pc, "%s: %s\r\n", c->http_headers[i].name,
4415                 c->http_headers[i].value);
4416     }
4417   }
4418   if (!sent_close_header) {
4419     ns_printf(pc, "%s: %s\r\n", "Connection", "close");
4420   }
4421   ns_printf(pc, "%s", "\r\n");
4422   ns_send(pc, c->content, c->content_len);
4423 
4424 }
4425 
4426 #ifdef NS_ENABLE_SSL
4427 int mg_terminate_ssl(struct mg_connection *c, const char *cert) {
4428   static const char ok[] = "HTTP/1.0 200 OK\r\n\r\n";
4429   struct connection *conn = MG_CONN_2_CONN(c);
4430   SSL_CTX *ctx;
4431 
4432   DBG(("%p MITM", conn));
4433   if ((ctx = SSL_CTX_new(SSLv23_server_method())) == NULL) return 0;
4434 
4435   SSL_CTX_use_certificate_file(ctx, cert, 1);
4436   SSL_CTX_use_PrivateKey_file(ctx, cert, 1);
4437   SSL_CTX_use_certificate_chain_file(ctx, cert);
4438 
4439   // When clear-text reply is pushed to client, switch to SSL mode.
4440   // TODO(lsm): check for send() failure
4441   send(conn->ns_conn->sock, ok, sizeof(ok) - 1, 0);
4442   //DBG(("%p %lu %d SEND", c, (unsigned long) sizeof(ok) - 1, n));
4443   conn->ns_conn->send_iobuf.len = 0;
4444   conn->endpoint_type = EP_USER;  // To keep-alive in close_local_endpoint()
4445   close_local_endpoint(conn);     // Clean up current CONNECT request
4446   if ((conn->ns_conn->ssl = SSL_new(ctx)) != NULL) {
4447     SSL_set_fd(conn->ns_conn->ssl, conn->ns_conn->sock);
4448   }
4449   SSL_CTX_free(ctx);
4450   return 1;
4451 }
4452 #endif
4453 
4454 int mg_forward(struct mg_connection *c, const char *addr) {
4455   static const char ok[] = "HTTP/1.1 200 OK\r\n\r\n";
4456   struct connection *conn = MG_CONN_2_CONN(c);
4457   struct ns_connection *pc;
4458 
4459   if ((pc = ns_connect(&conn->server->ns_mgr, addr,
4460       mg_ev_handler, conn)) == NULL) {
4461     conn->ns_conn->flags |= NSF_CLOSE_IMMEDIATELY;
4462     return 0;
4463   }
4464 
4465   // Interlink two connections
4466   pc->flags |= MG_PROXY_CONN;
4467   conn->endpoint_type = EP_PROXY;
4468   conn->endpoint.nc = pc;
4469   DBG(("%p [%s] [%s] -> %p %p", conn, c->uri, addr, pc, conn->ns_conn->ssl));
4470 
4471   if (strcmp(c->request_method, "CONNECT") == 0) {
4472     // For CONNECT request, reply with 200 OK. Tunnel is established.
4473     // TODO(lsm): check for send() failure
4474     (void) send(conn->ns_conn->sock, ok, sizeof(ok) - 1, 0);
4475   } else {
4476     // Strip "http://host:port" part from the URI
4477     if (memcmp(c->uri, "http://", 7) == 0) c->uri += 7;
4478     while (*c->uri != '\0' && *c->uri != '/') c->uri++;
4479     proxy_request(pc, c);
4480   }
4481   return 1;
4482 }
4483 
4484 static void proxify_connection(struct connection *conn) {
4485   char proto[10], host[500], cert[500], addr[1000];
4486   unsigned short port = 80;
4487   struct mg_connection *c = &conn->mg_conn;
4488   int n = 0;
4489   const char *url = c->uri;
4490 
4491   proto[0] = host[0] = cert[0] = '\0';
4492   if (sscanf(url, "%499[^: ]:%hu%n", host, &port, &n) != 2 &&
4493       sscanf(url, "%9[a-z]://%499[^: ]:%hu%n", proto, host, &port, &n) != 3 &&
4494       sscanf(url, "%9[a-z]://%499[^/ ]%n", proto, host, &n) != 2) {
4495     n = 0;
4496   }
4497 
4498   snprintf(addr, sizeof(addr), "%s://%s:%hu",
4499            conn->ns_conn->ssl != NULL ? "ssl" : "tcp", host, port);
4500   if (n <= 0 || !mg_forward(c, addr)) {
4501     conn->ns_conn->flags |= NSF_CLOSE_IMMEDIATELY;
4502   }
4503 }
4504 
4505 #ifndef MONGOOSE_NO_FILESYSTEM
4506 void mg_send_file_internal(struct mg_connection *c, const char *file_name,
4507                            file_stat_t *st, int exists,
4508                            const char *extra_headers) {
4509   struct connection *conn = MG_CONN_2_CONN(c);
4510   char path[MAX_PATH_SIZE];
4511   const int is_directory = S_ISDIR(st->st_mode);
4512 #ifndef MONGOOSE_NO_CGI
4513   const char *cgi_pat = conn->server->config_options[CGI_PATTERN];
4514 #else
4515   const char *cgi_pat = DEFAULT_CGI_PATTERN;
4516 #endif
4517 #ifndef MONGOOSE_NO_DIRECTORY_LISTING
4518   const char *dir_lst = conn->server->config_options[ENABLE_DIRECTORY_LISTING];
4519 #else
4520   const char *dir_lst = "yes";
4521 #endif
4522 
4523   mg_snprintf(path, sizeof(path), "%s", file_name);
4524 
4525   if (!exists || must_hide_file(conn, path)) {
4526     send_http_error(conn, 404, NULL);
4527   } else if (is_directory &&
4528              conn->mg_conn.uri[strlen(conn->mg_conn.uri) - 1] != '/') {
4529     conn->mg_conn.status_code = 301;
4530     mg_printf(&conn->mg_conn, "HTTP/1.1 301 Moved Permanently\r\n"
4531               "Location: %s/\r\n\r\n", conn->mg_conn.uri);
4532     close_local_endpoint(conn);
4533   } else if (is_directory && !find_index_file(conn, path, sizeof(path), st)) {
4534     if (!mg_strcasecmp(dir_lst, "yes")) {
4535 #ifndef MONGOOSE_NO_DIRECTORY_LISTING
4536       send_directory_listing(conn, path);
4537 #else
4538       send_http_error(conn, 501, NULL);
4539 #endif
4540     } else {
4541       send_http_error(conn, 403, NULL);
4542     }
4543   } else if (mg_match_prefix(cgi_pat, strlen(cgi_pat), path) > 0) {
4544 #if !defined(MONGOOSE_NO_CGI)
4545     open_cgi_endpoint(conn, path);
4546 #else
4547     send_http_error(conn, 501, NULL);
4548 #endif // !MONGOOSE_NO_CGI
4549 #ifndef MONGOOSE_NO_SSI
4550   } else if (mg_match_prefix(conn->server->config_options[SSI_PATTERN],
4551                              strlen(conn->server->config_options[SSI_PATTERN]),
4552                              path) > 0) {
4553     handle_ssi_request(conn, path);
4554 #endif
4555   } else if (is_not_modified(conn, st)) {
4556     send_http_error(conn, 304, NULL);
4557   } else if ((conn->endpoint.fd = open(path, O_RDONLY | O_BINARY, 0)) != -1) {
4558     // O_BINARY is required for Windows, otherwise in default text mode
4559     // two bytes \r\n will be read as one.
4560     open_file_endpoint(conn, path, st, extra_headers);
4561   } else {
4562     send_http_error(conn, 404, NULL);
4563   }
4564 }
4565 void mg_send_file(struct mg_connection *c, const char *file_name,
4566                   const char *extra_headers) {
4567   file_stat_t st;
4568   const int exists = stat(file_name, &st) == 0;
4569   mg_send_file_internal(c, file_name, &st, exists, extra_headers);
4570 }
4571 #endif  // !MONGOOSE_NO_FILESYSTEM
4572 
4573 static void open_local_endpoint(struct connection *conn, int skip_user) {
4574 #ifndef MONGOOSE_NO_FILESYSTEM
4575   char path[MAX_PATH_SIZE];
4576   file_stat_t st;
4577   int exists = 0;
4578 #endif
4579 
4580   // If EP_USER was set in a prev call, reset it
4581   conn->endpoint_type = EP_NONE;
4582 
4583 #ifndef MONGOOSE_NO_AUTH
4584   if (conn->server->event_handler && call_user(conn, MG_AUTH) == MG_FALSE) {
4585     mg_send_digest_auth_request(&conn->mg_conn);
4586     return;
4587   }
4588 #endif
4589 
4590   // Call URI handler if one is registered for this URI
4591   if (skip_user == 0 && conn->server->event_handler != NULL) {
4592     conn->endpoint_type = EP_USER;
4593 #if MONGOOSE_POST_SIZE_LIMIT > 1
4594     {
4595       const char *cl = mg_get_header(&conn->mg_conn, "Content-Length");
4596       if ((strcmp(conn->mg_conn.request_method, "POST") == 0 ||
4597            strcmp(conn->mg_conn.request_method, "PUT") == 0) &&
4598           (cl == NULL || to64(cl) > MONGOOSE_POST_SIZE_LIMIT)) {
4599         send_http_error(conn, 500, "POST size > %lu",
4600                         (unsigned long) MONGOOSE_POST_SIZE_LIMIT);
4601       }
4602     }
4603 #endif
4604     return;
4605   }
4606 
4607   if (strcmp(conn->mg_conn.request_method, "CONNECT") == 0 ||
4608       mg_strncasecmp(conn->mg_conn.uri, "http", 4) == 0) {
4609     const char *enp = conn->server->config_options[ENABLE_PROXY];
4610     if (enp == NULL || strcmp(enp, "yes") != 0) {
4611       send_http_error(conn, 405, NULL);
4612     } else {
4613       proxify_connection(conn);
4614     }
4615     return;
4616   }
4617 
4618   if (!strcmp(conn->mg_conn.request_method, "OPTIONS")) {
4619     send_options(conn);
4620     return;
4621   }
4622 
4623 #ifdef MONGOOSE_NO_FILESYSTEM
4624   send_http_error(conn, 404, NULL);
4625 #else
4626   exists = convert_uri_to_file_name(conn, path, sizeof(path), &st);
4627 
4628   if (!strcmp(conn->mg_conn.request_method, "OPTIONS")) {
4629     send_options(conn);
4630   } else if (conn->server->config_options[DOCUMENT_ROOT] == NULL) {
4631     send_http_error(conn, 404, NULL);
4632 #ifndef MONGOOSE_NO_AUTH
4633   } else if ((!is_dav_request(conn) && !is_authorized(conn, path,
4634                exists && S_ISDIR(st.st_mode))) ||
4635              (is_dav_request(conn) && !is_authorized_for_dav(conn))) {
4636     mg_send_digest_auth_request(&conn->mg_conn);
4637     close_local_endpoint(conn);
4638 #endif
4639 #ifndef MONGOOSE_NO_DAV
4640   } else if (must_hide_file(conn, path)) {
4641     send_http_error(conn, 404, NULL);
4642   } else if (!strcmp(conn->mg_conn.request_method, "PROPFIND")) {
4643     handle_propfind(conn, path, &st, exists);
4644   } else if (!strcmp(conn->mg_conn.request_method, "MKCOL")) {
4645     handle_mkcol(conn, path);
4646   } else if (!strcmp(conn->mg_conn.request_method, "DELETE")) {
4647     handle_delete(conn, path);
4648   } else if (!strcmp(conn->mg_conn.request_method, "PUT")) {
4649     handle_put(conn, path);
4650 #endif
4651   } else {
4652     mg_send_file_internal(&conn->mg_conn, path, &st, exists, NULL);
4653   }
4654 #endif  // MONGOOSE_NO_FILESYSTEM
4655 }
4656 
4657 static void send_continue_if_expected(struct connection *conn) {
4658   static const char expect_response[] = "HTTP/1.1 100 Continue\r\n\r\n";
4659   const char *expect_hdr = mg_get_header(&conn->mg_conn, "Expect");
4660 
4661   if (expect_hdr != NULL && !mg_strcasecmp(expect_hdr, "100-continue")) {
4662     ns_send(conn->ns_conn, expect_response, sizeof(expect_response) - 1);
4663   }
4664 }
4665 
4666 // Conform to http://www.w3.org/Protocols/rfc2616/rfc2616-sec5.html#sec5.1.2
4667 static int is_valid_uri(const char *uri) {
4668   unsigned short n;
4669   return uri[0] == '/' ||
4670     strcmp(uri, "*") == 0 ||            // OPTIONS method can use asterisk URI
4671     mg_strncasecmp(uri, "http", 4) == 0 || // Naive check for the absolute URI
4672     sscanf(uri, "%*[^ :]:%hu", &n) > 0; // CONNECT method can use host:port
4673 }
4674 
4675 static void try_parse(struct connection *conn) {
4676   struct iobuf *io = &conn->ns_conn->recv_iobuf;
4677 
4678   if (conn->request_len == 0 &&
4679       (conn->request_len = get_request_len(io->buf, io->len)) > 0) {
4680     // If request is buffered in, remove it from the iobuf. This is because
4681     // iobuf could be reallocated, and pointers in parsed request could
4682     // become invalid.
4683     conn->request = (char *) NS_MALLOC(conn->request_len);
4684     memcpy(conn->request, io->buf, conn->request_len);
4685     //DBG(("%p [%.*s]", conn, conn->request_len, conn->request));
4686     iobuf_remove(io, conn->request_len);
4687     conn->request_len = parse_http_message(conn->request, conn->request_len,
4688                                            &conn->mg_conn);
4689     if (conn->request_len > 0) {
4690       const char *cl_hdr = mg_get_header(&conn->mg_conn, "Content-Length");
4691       conn->cl = cl_hdr == NULL ? 0 : to64(cl_hdr);
4692       conn->mg_conn.content_len = (size_t) conn->cl;
4693     }
4694   }
4695 }
4696 
4697 static void do_proxy(struct connection *conn) {
4698   if (0 && conn->request_len == 0) {
4699     try_parse(conn);
4700     DBG(("%p parsing -> %d", conn, conn->request_len));
4701     if (conn->request_len > 0 && call_user(conn, MG_REQUEST) == MG_FALSE) {
4702       proxy_request(conn->endpoint.nc, &conn->mg_conn);
4703     } else if (conn->request_len < 0) {
4704       ns_forward(conn->ns_conn, conn->endpoint.nc);
4705     }
4706   } else {
4707     DBG(("%p forwarding", conn));
4708     ns_forward(conn->ns_conn, conn->endpoint.nc);
4709   }
4710 }
4711 
4712 static void on_recv_data(struct connection *conn) {
4713   struct iobuf *io = &conn->ns_conn->recv_iobuf;
4714   int n;
4715 
4716   if (conn->endpoint_type == EP_PROXY) {
4717     if (conn->endpoint.nc != NULL) do_proxy(conn);
4718     return;
4719   }
4720 
4721   try_parse(conn);
4722   DBG(("%p %d %lu %d", conn, conn->request_len, (unsigned long)io->len,
4723        conn->ns_conn->flags));
4724   if (conn->request_len < 0 ||
4725       (conn->request_len > 0 && !is_valid_uri(conn->mg_conn.uri))) {
4726     send_http_error(conn, 400, NULL);
4727   } else if (conn->request_len == 0 && io->len > MAX_REQUEST_SIZE) {
4728     send_http_error(conn, 413, NULL);
4729   } else if (conn->request_len > 0 &&
4730              strcmp(conn->mg_conn.http_version, "1.0") != 0 &&
4731              strcmp(conn->mg_conn.http_version, "1.1") != 0) {
4732     send_http_error(conn, 505, NULL);
4733   } else if (conn->request_len > 0 && conn->endpoint_type == EP_NONE) {
4734 #ifndef MONGOOSE_NO_WEBSOCKET
4735     send_websocket_handshake_if_requested(&conn->mg_conn);
4736 #endif
4737     send_continue_if_expected(conn);
4738     open_local_endpoint(conn, 0);
4739   }
4740 
4741 #ifndef MONGOOSE_NO_CGI
4742   if (conn->endpoint_type == EP_CGI && conn->endpoint.nc != NULL) {
4743     ns_forward(conn->ns_conn, conn->endpoint.nc);
4744   }
4745 #endif
4746   if (conn->endpoint_type == EP_USER) {
4747     conn->mg_conn.content = io->buf;
4748     conn->mg_conn.content_len = io->len;
4749     n = call_user(conn, MG_RECV);
4750     if (n < 0) {
4751       conn->ns_conn->flags |= NSF_FINISHED_SENDING_DATA;
4752     } else if ((size_t) n <= io->len) {
4753       iobuf_remove(io, n);
4754     }
4755     call_request_handler_if_data_is_buffered(conn);
4756   }
4757 #ifndef MONGOOSE_NO_DAV
4758   if (conn->endpoint_type == EP_PUT && io->len > 0) {
4759     forward_put_data(conn);
4760   }
4761 #endif
4762 }
4763 
4764 static void call_http_client_handler(struct connection *conn) {
4765   //conn->mg_conn.status_code = code;
4766   // For responses without Content-Lengh, use the whole buffer
4767   if (conn->cl == 0) {
4768     conn->mg_conn.content_len = conn->ns_conn->recv_iobuf.len;
4769   }
4770   conn->mg_conn.content = conn->ns_conn->recv_iobuf.buf;
4771   if (call_user(conn, MG_REPLY) == MG_FALSE) {
4772     conn->ns_conn->flags |= NSF_CLOSE_IMMEDIATELY;
4773   }
4774   iobuf_remove(&conn->ns_conn->recv_iobuf, conn->mg_conn.content_len);
4775   conn->mg_conn.status_code = 0;
4776   conn->cl = conn->num_bytes_recv = conn->request_len = 0;
4777   NS_FREE(conn->request);
4778   conn->request = NULL;
4779 }
4780 
4781 static void process_response(struct connection *conn) {
4782   struct iobuf *io = &conn->ns_conn->recv_iobuf;
4783 
4784   try_parse(conn);
4785   DBG(("%p %d %lu", conn, conn->request_len, (unsigned long)io->len));
4786   if (conn->request_len < 0 ||
4787       (conn->request_len == 0 && io->len > MAX_REQUEST_SIZE)) {
4788     call_http_client_handler(conn);
4789   } else if ((int64_t) io->len >= conn->cl) {
4790     call_http_client_handler(conn);
4791   }
4792 }
4793 
4794 struct mg_connection *mg_connect(struct mg_server *server, const char *addr) {
4795   struct ns_connection *nsconn;
4796   struct connection *conn;
4797 
4798   nsconn = ns_connect(&server->ns_mgr, addr, mg_ev_handler, NULL);
4799   if (nsconn == NULL) return 0;
4800 
4801   if ((conn = (struct connection *) NS_CALLOC(1, sizeof(*conn))) == NULL) {
4802     nsconn->flags |= NSF_CLOSE_IMMEDIATELY;
4803     return 0;
4804   }
4805 
4806   // Interlink two structs
4807   conn->ns_conn = nsconn;
4808   nsconn->user_data = conn;
4809 
4810   conn->server = server;
4811   conn->endpoint_type = EP_CLIENT;
4812   //conn->handler = handler;
4813   conn->mg_conn.server_param = server->ns_mgr.user_data;
4814   conn->ns_conn->flags = NSF_CONNECTING;
4815 
4816   return &conn->mg_conn;
4817 }
4818 
4819 #ifndef MONGOOSE_NO_LOGGING
4820 static void log_header(const struct mg_connection *conn, const char *header,
4821                        FILE *fp) {
4822   const char *header_value;
4823 
4824   if ((header_value = mg_get_header(conn, header)) == NULL) {
4825     (void) fprintf(fp, "%s", " -");
4826   } else {
4827     (void) fprintf(fp, " \"%s\"", header_value);
4828   }
4829 }
4830 
4831 static void log_access(const struct connection *conn, const char *path) {
4832   const struct mg_connection *c = &conn->mg_conn;
4833   FILE *fp = (path == NULL) ?  NULL : fopen(path, "a+");
4834   char date[64], user[100];
4835   time_t now;
4836 
4837   if (fp == NULL) return;
4838   now = time(NULL);
4839   strftime(date, sizeof(date), "%d/%b/%Y:%H:%M:%S %z", localtime(&now));
4840 
4841   flockfile(fp);
4842   mg_parse_header(mg_get_header(&conn->mg_conn, "Authorization"), "username",
4843                   user, sizeof(user));
4844   fprintf(fp, "%s - %s [%s] \"%s %s%s%s HTTP/%s\" %d 0",
4845           c->remote_ip, user[0] == '\0' ? "-" : user, date,
4846           c->request_method ? c->request_method : "-",
4847           c->uri ? c->uri : "-", c->query_string ? "?" : "",
4848           c->query_string ? c->query_string : "",
4849           c->http_version, c->status_code);
4850   log_header(c, "Referer", fp);
4851   log_header(c, "User-Agent", fp);
4852   fputc('\n', fp);
4853   fflush(fp);
4854 
4855   funlockfile(fp);
4856   fclose(fp);
4857 }
4858 #endif
4859 
4860 static void close_local_endpoint(struct connection *conn) {
4861   struct mg_connection *c = &conn->mg_conn;
4862   // Must be done before free()
4863   int keep_alive = should_keep_alive(&conn->mg_conn) &&
4864     (conn->endpoint_type == EP_FILE || conn->endpoint_type == EP_USER);
4865   DBG(("%p %d %d %d", conn, conn->endpoint_type, keep_alive,
4866        conn->ns_conn->flags));
4867 
4868   switch (conn->endpoint_type) {
4869     case EP_PUT:
4870     case EP_FILE:
4871       close(conn->endpoint.fd);
4872       break;
4873     case EP_CGI:
4874     case EP_PROXY:
4875       if (conn->endpoint.nc != NULL) {
4876         DBG(("%p %p %p :-)", conn, conn->ns_conn, conn->endpoint.nc));
4877         conn->endpoint.nc->flags |= NSF_CLOSE_IMMEDIATELY;
4878         conn->endpoint.nc->user_data = NULL;
4879       }
4880       break;
4881     default: break;
4882   }
4883 
4884 #ifndef MONGOOSE_NO_LOGGING
4885   if (c->status_code > 0 && conn->endpoint_type != EP_CLIENT &&
4886       c->status_code != 400) {
4887     log_access(conn, conn->server->config_options[ACCESS_LOG_FILE]);
4888   }
4889 #endif
4890 
4891   // Gobble possible POST data sent to the URI handler
4892   iobuf_free(&conn->ns_conn->recv_iobuf);
4893   NS_FREE(conn->request);
4894   NS_FREE(conn->path_info);
4895   conn->endpoint.nc = NULL;
4896   conn->request = conn->path_info = NULL;
4897 
4898   conn->endpoint_type = EP_NONE;
4899   conn->cl = conn->num_bytes_recv = conn->request_len = 0;
4900   conn->ns_conn->flags &= ~(NSF_FINISHED_SENDING_DATA |
4901                             NSF_BUFFER_BUT_DONT_SEND | NSF_CLOSE_IMMEDIATELY |
4902                             MG_HEADERS_SENT | MG_USING_CHUNKED_API);
4903 
4904   // Do not memset() the whole structure, as some of the fields
4905   // (IP addresses & ports, server_param) must survive. Nullify the rest.
4906   c->request_method = c->uri = c->http_version = c->query_string = NULL;
4907   c->num_headers = c->status_code = c->is_websocket = c->content_len = 0;
4908   c->connection_param = c->callback_param = NULL;
4909 
4910   if (keep_alive) {
4911     on_recv_data(conn);  // Can call us recursively if pipelining is used
4912   } else {
4913     conn->ns_conn->flags |= conn->ns_conn->send_iobuf.len == 0 ?
4914       NSF_CLOSE_IMMEDIATELY : NSF_FINISHED_SENDING_DATA;
4915   }
4916 }
4917 
4918 static void transfer_file_data(struct connection *conn) {
4919   char buf[IOBUF_SIZE];
4920   size_t n;
4921 
4922   // If output buffer is too big, don't send anything. Wait until
4923   // mongoose drains already buffered data to the client.
4924   if (conn->ns_conn->send_iobuf.len > sizeof(buf) * 2) return;
4925 
4926   // Do not send anyt
4927   n = read(conn->endpoint.fd, buf, conn->cl < (int64_t) sizeof(buf) ?
4928            (int) conn->cl : (int) sizeof(buf));
4929 
4930   if (n <= 0) {
4931     close_local_endpoint(conn);
4932   } else if (n > 0) {
4933     conn->cl -= n;
4934     ns_send(conn->ns_conn, buf, n);
4935     if (conn->cl <= 0) {
4936       close_local_endpoint(conn);
4937     }
4938   }
4939 }
4940 
4941 time_t mg_poll_server(struct mg_server *server, int milliseconds) {
4942   return ns_mgr_poll(&server->ns_mgr, milliseconds);
4943 }
4944 
4945 void mg_destroy_server(struct mg_server **server) {
4946   if (server != NULL && *server != NULL) {
4947     struct mg_server *s = *server;
4948     int i;
4949 
4950     ns_mgr_free(&s->ns_mgr);
4951     for (i = 0; i < (int) ARRAY_SIZE(s->config_options); i++) {
4952       NS_FREE(s->config_options[i]);  // It is OK to free(NULL)
4953     }
4954     NS_FREE(s);
4955     *server = NULL;
4956   }
4957 }
4958 
4959 struct mg_connection *mg_next(struct mg_server *s, struct mg_connection *c) {
4960   struct ns_connection *nc = ns_next(&s->ns_mgr, c == NULL ? NULL :
4961                                      MG_CONN_2_CONN(c)->ns_conn);
4962   if (nc != NULL && nc->user_data != NULL) {
4963     return & ((struct connection *) nc->user_data)->mg_conn;
4964   } else {
4965     return NULL;
4966   }
4967 }
4968 
4969 static int get_var(const char *data, size_t data_len, const char *name,
4970                    char *dst, size_t dst_len) {
4971   const char *p, *e, *s;
4972   size_t name_len;
4973   int len;
4974 
4975   if (dst == NULL || dst_len == 0) {
4976     len = -2;
4977   } else if (data == NULL || name == NULL || data_len == 0) {
4978     len = -1;
4979     dst[0] = '\0';
4980   } else {
4981     name_len = strlen(name);
4982     e = data + data_len;
4983     len = -1;
4984     dst[0] = '\0';
4985 
4986     // data is "var1=val1&var2=val2...". Find variable first
4987     for (p = data; p + name_len < e; p++) {
4988       if ((p == data || p[-1] == '&') && p[name_len] == '=' &&
4989           !mg_strncasecmp(name, p, name_len)) {
4990 
4991         // Point p to variable value
4992         p += name_len + 1;
4993 
4994         // Point s to the end of the value
4995         s = (const char *) memchr(p, '&', (size_t)(e - p));
4996         if (s == NULL) {
4997           s = e;
4998         }
4999         assert(s >= p);
5000 
5001         // Decode variable into destination buffer
5002         len = mg_url_decode(p, (size_t)(s - p), dst, dst_len, 1);
5003 
5004         // Redirect error code from -1 to -2 (destination buffer too small).
5005         if (len == -1) {
5006           len = -2;
5007         }
5008         break;
5009       }
5010     }
5011   }
5012 
5013   return len;
5014 }
5015 
5016 int mg_get_var(const struct mg_connection *conn, const char *name,
5017                char *dst, size_t dst_len) {
5018   int len = get_var(conn->query_string, conn->query_string == NULL ? 0 :
5019                     strlen(conn->query_string), name, dst, dst_len);
5020   if (len < 0) {
5021     len = get_var(conn->content, conn->content_len, name, dst, dst_len);
5022   }
5023   return len;
5024 }
5025 
5026 static int get_line_len(const char *buf, int buf_len) {
5027   int len = 0;
5028   while (len < buf_len && buf[len] != '\n') len++;
5029   return buf[len] == '\n' ? len + 1: -1;
5030 }
5031 
5032 int mg_parse_multipart(const char *buf, int buf_len,
5033                        char *var_name, int var_name_len,
5034                        char *file_name, int file_name_len,
5035                        const char **data, int *data_len) {
5036   static const char cd[] = "Content-Disposition: ";
5037   //struct mg_connection c;
5038   int hl, bl, n, ll, pos, cdl = sizeof(cd) - 1;
5039   //char *p;
5040 
5041   if (buf == NULL || buf_len <= 0) return 0;
5042   if ((hl = get_request_len(buf, buf_len)) <= 0) return 0;
5043   if (buf[0] != '-' || buf[1] != '-' || buf[2] == '\n') return 0;
5044 
5045   // Get boundary length
5046   bl = get_line_len(buf, buf_len);
5047 
5048   // Loop through headers, fetch variable name and file name
5049   var_name[0] = file_name[0] = '\0';
5050   for (n = bl; (ll = get_line_len(buf + n, hl - n)) > 0; n += ll) {
5051     if (mg_strncasecmp(cd, buf + n, cdl) == 0) {
5052       parse_header(buf + n + cdl, ll - (cdl + 2), "name",
5053                    var_name, var_name_len);
5054       parse_header(buf + n + cdl, ll - (cdl + 2), "filename",
5055                    file_name, file_name_len);
5056     }
5057   }
5058 
5059   // Scan body, search for terminating boundary
5060   for (pos = hl; pos + (bl - 2) < buf_len; pos++) {
5061     if (buf[pos] == '-' && !memcmp(buf, &buf[pos], bl - 2)) {
5062       if (data_len != NULL) *data_len = (pos - 2) - hl;
5063       if (data != NULL) *data = buf + hl;
5064       return pos;
5065     }
5066   }
5067 
5068   return 0;
5069 }
5070 
5071 const char **mg_get_valid_option_names(void) {
5072   return static_config_options;
5073 }
5074 
5075 void mg_copy_listeners(struct mg_server *s, struct mg_server *to) {
5076   struct ns_connection *c;
5077   for (c = ns_next(&s->ns_mgr, NULL); c != NULL; c = ns_next(&s->ns_mgr, c)) {
5078     struct ns_connection *tmp;
5079     if ((c->flags & NSF_LISTENING) &&
5080         (tmp = (struct ns_connection *) NS_MALLOC(sizeof(*tmp))) != NULL) {
5081       memcpy(tmp, c, sizeof(*tmp));
5082       tmp->mgr = &to->ns_mgr;
5083       ns_add_conn(tmp->mgr, tmp);
5084     }
5085   }
5086 }
5087 
5088 static int get_option_index(const char *name) {
5089   int i;
5090 
5091   for (i = 0; static_config_options[i * 2] != NULL; i++) {
5092     if (strcmp(static_config_options[i * 2], name) == 0) {
5093       return i;
5094     }
5095   }
5096   return -1;
5097 }
5098 
5099 static void set_default_option_values(char **opts) {
5100   const char *value, **all_opts = mg_get_valid_option_names();
5101   int i;
5102 
5103   for (i = 0; all_opts[i * 2] != NULL; i++) {
5104     value = all_opts[i * 2 + 1];
5105     if (opts[i] == NULL && value != NULL) {
5106       opts[i] = mg_strdup(value);
5107     }
5108   }
5109 }
5110 
5111 const char *mg_set_option(struct mg_server *server, const char *name,
5112                           const char *value) {
5113   int ind = get_option_index(name);
5114   const char *error_msg = NULL;
5115   char **v = NULL;
5116 
5117   if (ind < 0) return  "No such option";
5118   v = &server->config_options[ind];
5119 
5120   // Return success immediately if setting to the same value
5121   if ((*v == NULL && value == NULL) ||
5122       (value != NULL && *v != NULL && !strcmp(value, *v))) {
5123     return NULL;
5124   }
5125 
5126   if (*v != NULL) {
5127     NS_FREE(*v);
5128     *v = NULL;
5129   }
5130 
5131   if (value == NULL || value[0] == '\0') return NULL;
5132 
5133   *v = mg_strdup(value);
5134   DBG(("%s [%s]", name, *v));
5135 
5136   if (ind == LISTENING_PORT) {
5137     char buf[500] = "";
5138     size_t n = 0;
5139     struct vec vec;
5140     /*
5141      * Ports can be specified as 0, meaning that OS has to choose any
5142      * free port that is available. In order to pass chosen port number to
5143      * the user, we rewrite all 0 port to chosen values.
5144      */
5145     while ((value = next_option(value, &vec, NULL)) != NULL) {
5146       struct ns_connection *c = ns_bind(&server->ns_mgr, vec.ptr,
5147                                         mg_ev_handler, NULL);
5148       if (c == NULL) {
5149         error_msg = "Cannot bind to port";
5150         break;
5151       } else {
5152         char buf2[50], cert[100], ca[100];
5153         union socket_address sa;
5154         int proto, use_ssl;
5155 
5156         ns_parse_address(vec.ptr, &sa, &proto, &use_ssl, cert, ca);
5157         ns_sock_to_str(c->sock, buf2, sizeof(buf2),
5158                        memchr(vec.ptr, ':', vec.len) == NULL ? 2 : 3);
5159 
5160         n += snprintf(buf + n, sizeof(buf) - n, "%s%s%s%s%s%s%s",
5161                       n > 0 ? "," : "",
5162                       use_ssl ? "ssl://" : "",
5163                       buf2, cert[0] ? ":" : "", cert, ca[0] ? ":" : "", ca);
5164       }
5165     }
5166     buf[sizeof(buf) - 1] = '\0';
5167     NS_FREE(*v);
5168     *v = mg_strdup(buf);
5169 #ifndef MONGOOSE_NO_FILESYSTEM
5170   } else if (ind == HEXDUMP_FILE) {
5171     server->ns_mgr.hexdump_file = *v;
5172 #endif
5173 #if !defined(_WIN32) && !defined(MONGOOSE_NO_USER)
5174   } else if (ind == RUN_AS_USER) {
5175     struct passwd *pw;
5176     if ((pw = getpwnam(value)) == NULL) {
5177       error_msg = "Unknown user";
5178     } else if (setgid(pw->pw_gid) != 0) {
5179       error_msg = "setgid() failed";
5180     } else if (setuid(pw->pw_uid) != 0) {
5181       error_msg = "setuid() failed";
5182     }
5183 #endif
5184   }
5185 
5186   return error_msg;
5187 }
5188 
5189 static void set_ips(struct ns_connection *nc, int is_rem) {
5190   struct connection *conn = (struct connection *) nc->user_data;
5191   struct mg_connection *c = &conn->mg_conn;
5192   char buf[100];
5193 
5194   ns_sock_to_str(nc->sock, buf, sizeof(buf), is_rem ? 7 : 3);
5195   sscanf(buf, "%47[^:]:%hu",
5196          is_rem ? c->remote_ip : c->local_ip,
5197          is_rem ? &c->remote_port : &c->local_port);
5198   //DBG(("%p %s %s", conn, is_rem ? "rem" : "loc", buf));
5199 }
5200 
5201 static void on_accept(struct ns_connection *nc, union socket_address *sa) {
5202   struct mg_server *server = (struct mg_server *) nc->mgr;
5203   struct connection *conn;
5204 
5205   if (!check_acl(server->config_options[ACCESS_CONTROL_LIST],
5206                  ntohl(* (uint32_t *) &sa->sin.sin_addr)) ||
5207       (conn = (struct connection *) NS_CALLOC(1, sizeof(*conn))) == NULL) {
5208     nc->flags |= NSF_CLOSE_IMMEDIATELY;
5209   } else {
5210     // Circularly link two connection structures
5211     nc->user_data = conn;
5212     conn->ns_conn = nc;
5213 
5214     // Initialize the rest of connection attributes
5215     conn->server = server;
5216     conn->mg_conn.server_param = nc->mgr->user_data;
5217     set_ips(nc, 1);
5218     set_ips(nc, 0);
5219   }
5220 }
5221 
5222 static void process_udp(struct ns_connection *nc) {
5223   struct iobuf *io = &nc->recv_iobuf;
5224   struct connection conn;
5225 
5226   memset(&conn, 0, sizeof(conn));
5227   conn.ns_conn = nc;
5228   conn.server = (struct mg_server *) nc->mgr;
5229   conn.request_len = parse_http_message(io->buf, io->len, &conn.mg_conn);
5230   on_recv_data(&conn);
5231   //ns_printf(nc, "%s", "HTTP/1.0 200 OK\r\n\r\n");
5232 }
5233 
5234 static void mg_ev_handler(struct ns_connection *nc, int ev, void *p) {
5235   struct connection *conn = (struct connection *) nc->user_data;
5236 
5237   // Send NS event to the handler. Note that call_user won't send an event
5238   // if conn == NULL. Therefore, repeat this for NS_ACCEPT event as well.
5239 #ifdef MONGOOSE_SEND_NS_EVENTS
5240   {
5241     struct connection *conn = (struct connection *) nc->user_data;
5242     void *param[2] = { nc, p };
5243     if (conn != NULL) conn->mg_conn.callback_param = param;
5244     call_user(conn, (enum mg_event) ev);
5245   }
5246 #endif
5247 
5248   switch (ev) {
5249     case NS_ACCEPT:
5250       on_accept(nc, (union socket_address *) p);
5251 #ifdef MONGOOSE_SEND_NS_EVENTS
5252       {
5253         struct connection *conn = (struct connection *) nc->user_data;
5254         void *param[2] = { nc, p };
5255         if (conn != NULL) conn->mg_conn.callback_param = param;
5256         call_user(conn, (enum mg_event) ev);
5257       }
5258 #endif
5259       break;
5260 
5261     case NS_CONNECT:
5262       if (nc->user_data != NULL) {
5263         set_ips(nc, 1);
5264         set_ips(nc, 0);
5265       }
5266       conn->mg_conn.status_code = * (int *) p;
5267       if (conn->mg_conn.status_code != 0 ||
5268           (!(nc->flags & MG_PROXY_CONN) &&
5269            call_user(conn, MG_CONNECT) == MG_FALSE)) {
5270         nc->flags |= NSF_CLOSE_IMMEDIATELY;
5271       }
5272       break;
5273 
5274     case NS_RECV:
5275       if (conn != NULL) {
5276         conn->num_bytes_recv += * (int *) p;
5277       }
5278 
5279       if (nc->flags & NSF_UDP) {
5280         process_udp(nc);
5281       } else if (nc->listener != NULL) {
5282         on_recv_data(conn);
5283 #ifndef MONGOOSE_NO_CGI
5284       } else if (nc->flags & MG_CGI_CONN) {
5285         on_cgi_data(nc);
5286 #endif
5287       } else if (nc->flags & MG_PROXY_CONN) {
5288         if (conn != NULL) {
5289           ns_forward(nc, conn->ns_conn);
5290         }
5291       } else {
5292         process_response(conn);
5293       }
5294       break;
5295 
5296     case NS_SEND:
5297       break;
5298 
5299     case NS_CLOSE:
5300       nc->user_data = NULL;
5301       if (nc->flags & (MG_CGI_CONN | MG_PROXY_CONN)) {
5302         DBG(("%p %p closing cgi/proxy conn", conn, nc));
5303         if (conn && conn->ns_conn) {
5304           conn->ns_conn->flags &= ~NSF_BUFFER_BUT_DONT_SEND;
5305           conn->ns_conn->flags |= conn->ns_conn->send_iobuf.len > 0 ?
5306             NSF_FINISHED_SENDING_DATA : NSF_CLOSE_IMMEDIATELY;
5307           conn->endpoint.nc = NULL;
5308         }
5309       } else if (conn != NULL) {
5310         DBG(("%p %p %d closing", conn, nc, conn->endpoint_type));
5311 
5312         if (conn->endpoint_type == EP_CLIENT && nc->recv_iobuf.len > 0) {
5313           call_http_client_handler(conn);
5314         }
5315 
5316         call_user(conn, MG_CLOSE);
5317         close_local_endpoint(conn);
5318         conn->ns_conn = NULL;
5319         NS_FREE(conn);
5320       }
5321       break;
5322 
5323     case NS_POLL:
5324       if (conn != NULL) {
5325         if (call_user(conn, MG_POLL) == MG_TRUE) {
5326           if (conn->ns_conn->flags & MG_HEADERS_SENT) {
5327             write_terminating_chunk(conn);
5328           }
5329           close_local_endpoint(conn);
5330         }
5331 
5332         if (conn->endpoint_type == EP_FILE) {
5333           transfer_file_data(conn);
5334         }
5335       }
5336 
5337       // Expire idle connections
5338       {
5339         time_t current_time = * (time_t *) p;
5340 
5341         if (conn != NULL && conn->mg_conn.is_websocket) {
5342           ping_idle_websocket_connection(conn, current_time);
5343         }
5344 
5345         if (nc->listener != NULL &&
5346             nc->last_io_time + MONGOOSE_IDLE_TIMEOUT_SECONDS < current_time) {
5347           mg_ev_handler(nc, NS_CLOSE, NULL);
5348           nc->flags |= NSF_CLOSE_IMMEDIATELY;
5349         }
5350       }
5351       break;
5352 
5353     default:
5354       break;
5355   }
5356 }
5357 
5358 static void iter2(struct ns_connection *nc, int ev, void *param) {
5359   mg_handler_t func = NULL;
5360   struct connection *conn = (struct connection *) nc->user_data;
5361   const char *msg = (const char *) param;
5362   int n;
5363   (void) ev;
5364 
5365   //DBG(("%p [%s]", conn, msg));
5366   if (sscanf(msg, "%p %n", &func, &n) && func != NULL && conn != NULL) {
5367     conn->mg_conn.callback_param = (void *) (msg + n);
5368     func(&conn->mg_conn, MG_POLL);
5369   }
5370 }
5371 
5372 void mg_wakeup_server_ex(struct mg_server *server, mg_handler_t cb,
5373                          const char *fmt, ...) {
5374   va_list ap;
5375   char buf[8 * 1024];
5376   int len;
5377 
5378   // Encode callback (cb) into a buffer
5379   len = snprintf(buf, sizeof(buf), "%p ", cb);
5380   va_start(ap, fmt);
5381   len += vsnprintf(buf + len, sizeof(buf) - len, fmt, ap);
5382   va_end(ap);
5383 
5384   // "len + 1" is to include terminating \0 in the message
5385   ns_broadcast(&server->ns_mgr, iter2, buf, len + 1);
5386 }
5387 
5388 void mg_wakeup_server(struct mg_server *server) {
5389   ns_broadcast(&server->ns_mgr, NULL, (void *) "", 0);
5390 }
5391 
5392 const char *mg_get_option(const struct mg_server *server, const char *name) {
5393   const char **opts = (const char **) server->config_options;
5394   int i = get_option_index(name);
5395   return i == -1 ? NULL : opts[i] == NULL ? "" : opts[i];
5396 }
5397 
5398 struct mg_server *mg_create_server(void *server_data, mg_handler_t handler) {
5399   struct mg_server *server = (struct mg_server *) NS_CALLOC(1, sizeof(*server));
5400   ns_mgr_init(&server->ns_mgr, server_data);
5401   set_default_option_values(server->config_options);
5402   server->event_handler = handler;
5403   return server;
5404 }
5405