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, ¤t_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> %s</td><td> %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