00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018 #ifdef NOEMBED_NET_SKELETON
00019 #include "net_skeleton.h"
00020 #else
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038 #ifndef NS_SKELETON_HEADER_INCLUDED
00039 #define NS_SKELETON_HEADER_INCLUDED
00040
00041 #define NS_SKELETON_VERSION "2.1.0"
00042
00043 #undef UNICODE // Use ANSI WinAPI functions
00044 #undef _UNICODE // Use multibyte encoding on Windows
00045 #define _MBCS // Use multibyte encoding on Windows
00046 #define _INTEGRAL_MAX_BITS 64 // Enable _stati64() on Windows
00047 #ifndef _CRT_SECURE_NO_WARNINGS
00048 #define _CRT_SECURE_NO_WARNINGS // Disable deprecation warning in VS2005+
00049 #endif
00050 #undef WIN32_LEAN_AND_MEAN // Let windows.h always include winsock2.h
00051 #ifdef __Linux__
00052 #define _XOPEN_SOURCE 600 // For flockfile() on Linux
00053 #endif
00054 #define __STDC_FORMAT_MACROS // <inttypes.h> wants this for C++
00055 #define __STDC_LIMIT_MACROS // C++ wants that for INT64_MAX
00056 #ifndef _LARGEFILE_SOURCE
00057 #define _LARGEFILE_SOURCE // Enable fseeko() and ftello() functions
00058 #endif
00059 #define _FILE_OFFSET_BITS 64 // Enable 64-bit file offsets
00060
00061 #ifdef _MSC_VER
00062 #pragma warning (disable : 4127) // FD_SET() emits warning, disable it
00063 #pragma warning (disable : 4204) // missing c99 support
00064 #endif
00065
00066 #if defined(_WIN32) && !defined(MONGOOSE_NO_CGI)
00067 #define MONGOOSE_ENABLE_THREADS
00068 #endif
00069
00070 #ifndef MONGOOSE_ENABLE_THREADS
00071 #define NS_DISABLE_THREADS
00072 #endif
00073
00074 #ifdef __OS2__
00075 #define _MMAP_DECLARED // Prevent dummy mmap() declaration in stdio.h
00076 #endif
00077
00078 #include <sys/types.h>
00079 #include <sys/stat.h>
00080 #include <assert.h>
00081 #include <ctype.h>
00082 #include <errno.h>
00083 #include <fcntl.h>
00084 #include <stdarg.h>
00085 #include <stddef.h>
00086 #include <stdio.h>
00087 #include <stdlib.h>
00088 #include <string.h>
00089 #include <time.h>
00090 #include <signal.h>
00091
00092 #ifdef _WIN32
00093 #ifdef _MSC_VER
00094 #pragma comment(lib, "ws2_32.lib") // Linking with winsock library
00095 #include <BaseTsd.h>
00096 typedef SSIZE_T ssize_t;
00097 #endif
00098 #include <winsock2.h>
00099 #include <ws2tcpip.h>
00100 #include <windows.h>
00101 #include <process.h>
00102 #ifndef EINPROGRESS
00103 #define EINPROGRESS WSAEINPROGRESS
00104 #endif
00105 #ifndef EWOULDBLOCK
00106 #define EWOULDBLOCK WSAEWOULDBLOCK
00107 #endif
00108 #ifndef __func__
00109 #define STRX(x) #x
00110 #define STR(x) STRX(x)
00111 #define __func__ __FILE__ ":" STR(__LINE__)
00112 #endif
00113 #ifndef va_copy
00114 #define va_copy(x,y) x = y
00115 #endif // MINGW #defines va_copy
00116 #define snprintf _snprintf
00117 #define vsnprintf _vsnprintf
00118 #define sleep(x) Sleep((x) * 1000)
00119 #define to64(x) _atoi64(x)
00120 typedef int socklen_t;
00121 typedef unsigned char uint8_t;
00122 typedef unsigned int uint32_t;
00123 typedef unsigned short uint16_t;
00124 typedef unsigned __int64 uint64_t;
00125 typedef __int64 int64_t;
00126 typedef SOCKET sock_t;
00127 typedef struct _stati64 ns_stat_t;
00128 #ifndef S_ISDIR
00129 #define S_ISDIR(x) ((x) & _S_IFDIR)
00130 #endif
00131 #else
00132 #include <errno.h>
00133 #include <fcntl.h>
00134 #include <netdb.h>
00135 #include <pthread.h>
00136 #include <stdarg.h>
00137 #include <unistd.h>
00138 #include <arpa/inet.h>
00139 #include <netinet/in.h>
00140 #include <sys/socket.h>
00141 #include <sys/select.h>
00142 #define closesocket(x) close(x)
00143 #ifndef __OS2__
00144 #define __cdecl
00145 #else
00146 #include <sys/time.h>
00147 typedef int socklen_t;
00148 #endif
00149 #define INVALID_SOCKET (-1)
00150 #define to64(x) strtoll(x, NULL, 10)
00151 typedef int sock_t;
00152 typedef struct stat ns_stat_t;
00153 #endif
00154
00155 #ifdef NS_ENABLE_DEBUG
00156 #define DBG(x) do { printf("%-20s ", __func__); printf x; putchar('\n'); \
00157 fflush(stdout); } while(0)
00158 #else
00159 #define DBG(x)
00160 #endif
00161
00162 #ifndef ARRAY_SIZE
00163 #define ARRAY_SIZE(array) (sizeof(array) / sizeof(array[0]))
00164 #endif
00165
00166 #ifdef NS_ENABLE_SSL
00167 #ifdef __APPLE__
00168 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
00169 #endif
00170 #include <openssl/ssl.h>
00171 #else
00172 typedef void *SSL;
00173 typedef void *SSL_CTX;
00174 #endif
00175
00176 #ifdef __cplusplus
00177 extern "C" {
00178 #endif // __cplusplus
00179
00180 union socket_address {
00181 struct sockaddr sa;
00182 struct sockaddr_in sin;
00183 #ifdef NS_ENABLE_IPV6
00184 struct sockaddr_in6 sin6;
00185 #else
00186 struct sockaddr sin6;
00187 #endif
00188 };
00189
00190
00191 struct ns_str {
00192 const char *p;
00193 size_t len;
00194 };
00195
00196
00197 struct iobuf {
00198 char *buf;
00199 size_t len;
00200 size_t size;
00201 };
00202
00203 void iobuf_init(struct iobuf *, size_t initial_size);
00204 void iobuf_free(struct iobuf *);
00205 size_t iobuf_append(struct iobuf *, const void *data, size_t data_size);
00206 void iobuf_remove(struct iobuf *, size_t data_size);
00207 void iobuf_resize(struct iobuf *, size_t new_size);
00208
00209
00210
00211 struct ns_connection;
00212 typedef void (*ns_callback_t)(struct ns_connection *, int event_num, void *evp);
00213
00214
00215 #define NS_POLL 0 // Sent to each connection on each call to ns_mgr_poll()
00216 #define NS_ACCEPT 1 // New connection accept()-ed. union socket_address *addr
00217 #define NS_CONNECT 2 // connect() succeeded or failed. int *success_status
00218 #define NS_RECV 3 // Data has benn received. int *num_bytes
00219 #define NS_SEND 4 // Data has been written to a socket. int *num_bytes
00220 #define NS_CLOSE 5 // Connection is closed. NULL
00221
00222
00223 struct ns_mgr {
00224 struct ns_connection *active_connections;
00225 const char *hexdump_file;
00226 sock_t ctl[2];
00227 void *user_data;
00228 };
00229
00230
00231 struct ns_connection {
00232 struct ns_connection *next, *prev;
00233 struct ns_connection *listener;
00234 struct ns_mgr *mgr;
00235
00236 sock_t sock;
00237 union socket_address sa;
00238 struct iobuf recv_iobuf;
00239 struct iobuf send_iobuf;
00240 SSL *ssl;
00241 SSL_CTX *ssl_ctx;
00242 void *user_data;
00243 void *proto_data;
00244 time_t last_io_time;
00245 ns_callback_t callback;
00246
00247 unsigned int flags;
00248 #define NSF_FINISHED_SENDING_DATA (1 << 0)
00249 #define NSF_BUFFER_BUT_DONT_SEND (1 << 1)
00250 #define NSF_SSL_HANDSHAKE_DONE (1 << 2)
00251 #define NSF_CONNECTING (1 << 3)
00252 #define NSF_CLOSE_IMMEDIATELY (1 << 4)
00253 #define NSF_WANT_READ (1 << 5)
00254 #define NSF_WANT_WRITE (1 << 6)
00255 #define NSF_LISTENING (1 << 7)
00256 #define NSF_UDP (1 << 8)
00257
00258 #define NSF_USER_1 (1 << 20)
00259 #define NSF_USER_2 (1 << 21)
00260 #define NSF_USER_3 (1 << 22)
00261 #define NSF_USER_4 (1 << 23)
00262 #define NSF_USER_5 (1 << 24)
00263 #define NSF_USER_6 (1 << 25)
00264 };
00265
00266 void ns_mgr_init(struct ns_mgr *, void *user_data);
00267 void ns_mgr_free(struct ns_mgr *);
00268 time_t ns_mgr_poll(struct ns_mgr *, int milli);
00269 void ns_broadcast(struct ns_mgr *, ns_callback_t, void *, size_t);
00270
00271 struct ns_connection *ns_next(struct ns_mgr *, struct ns_connection *);
00272 struct ns_connection *ns_add_sock(struct ns_mgr *, sock_t,
00273 ns_callback_t, void *);
00274 struct ns_connection *ns_bind(struct ns_mgr *, const char *,
00275 ns_callback_t, void *);
00276 struct ns_connection *ns_connect(struct ns_mgr *, const char *,
00277 ns_callback_t, void *);
00278
00279 int ns_send(struct ns_connection *, const void *buf, size_t len);
00280 int ns_printf(struct ns_connection *, const char *fmt, ...);
00281 int ns_vprintf(struct ns_connection *, const char *fmt, va_list ap);
00282
00283
00284 void *ns_start_thread(void *(*f)(void *), void *p);
00285 int ns_socketpair(sock_t [2]);
00286 int ns_socketpair2(sock_t [2], int sock_type);
00287 void ns_set_close_on_exec(sock_t);
00288 void ns_sock_to_str(sock_t sock, char *buf, size_t len, int flags);
00289 int ns_hexdump(const void *buf, int len, char *dst, int dst_len);
00290 int ns_avprintf(char **buf, size_t size, const char *fmt, va_list ap);
00291 int ns_resolve(const char *domain_name, char *ip_addr_buf, size_t buf_len);
00292
00293 #ifdef __cplusplus
00294 }
00295 #endif // __cplusplus
00296
00297 #endif // NS_SKELETON_HEADER_INCLUDED
00298
00299
00300
00301
00302
00303
00304
00305
00306
00307
00308
00309
00310
00311
00312
00313
00314
00315
00316
00317 #ifndef NS_MALLOC
00318 #define NS_MALLOC malloc
00319 #endif
00320
00321 #ifndef NS_REALLOC
00322 #define NS_REALLOC realloc
00323 #endif
00324
00325 #ifndef NS_FREE
00326 #define NS_FREE free
00327 #endif
00328
00329 #ifndef NS_CALLOC
00330 #define NS_CALLOC calloc
00331 #endif
00332
00333 #define NS_CTL_MSG_MESSAGE_SIZE (8 * 1024)
00334 #define NS_READ_BUFFER_SIZE 2048
00335 #define NS_UDP_RECEIVE_BUFFER_SIZE 2000
00336 #define NS_VPRINTF_BUFFER_SIZE 500
00337
00338 struct ctl_msg {
00339 ns_callback_t callback;
00340 char message[NS_CTL_MSG_MESSAGE_SIZE];
00341 };
00342
00343 void iobuf_resize(struct iobuf *io, size_t new_size) {
00344 char *p;
00345 if ((new_size > io->size || (new_size < io->size && new_size >= io->len)) &&
00346 (p = (char *) NS_REALLOC(io->buf, new_size)) != NULL) {
00347 io->size = new_size;
00348 io->buf = p;
00349 }
00350 }
00351
00352 void iobuf_init(struct iobuf *iobuf, size_t initial_size) {
00353 iobuf->len = iobuf->size = 0;
00354 iobuf->buf = NULL;
00355 iobuf_resize(iobuf, initial_size);
00356 }
00357
00358 void iobuf_free(struct iobuf *iobuf) {
00359 if (iobuf != NULL) {
00360 if (iobuf->buf != NULL) NS_FREE(iobuf->buf);
00361 iobuf_init(iobuf, 0);
00362 }
00363 }
00364
00365 size_t iobuf_append(struct iobuf *io, const void *buf, size_t len) {
00366 char *p = NULL;
00367
00368 assert(io != NULL);
00369 assert(io->len <= io->size);
00370
00371
00372 if (len > ~(size_t)0 - (size_t)(io->buf + io->len)) {
00373 return 0;
00374 }
00375
00376 if (len <= 0) {
00377 } else if (io->len + len <= io->size) {
00378 memcpy(io->buf + io->len, buf, len);
00379 io->len += len;
00380 } else if ((p = (char *) NS_REALLOC(io->buf, io->len + len)) != NULL) {
00381 io->buf = p;
00382 memcpy(io->buf + io->len, buf, len);
00383 io->len += len;
00384 io->size = io->len;
00385 } else {
00386 len = 0;
00387 }
00388
00389 return len;
00390 }
00391
00392 void iobuf_remove(struct iobuf *io, size_t n) {
00393 if (n > 0 && n <= io->len) {
00394 memmove(io->buf, io->buf + n, io->len - n);
00395 io->len -= n;
00396 }
00397 }
00398
00399 static size_t ns_out(struct ns_connection *nc, const void *buf, size_t len) {
00400 if (nc->flags & NSF_UDP) {
00401 long n = sendto(nc->sock, (const char *) buf, len, 0, &nc->sa.sa,
00402 sizeof(nc->sa.sin));
00403 DBG(("%p %d send %ld (%d %s)", nc, nc->sock, n, errno, strerror(errno)));
00404 return n < 0 ? 0 : n;
00405 } else {
00406 return iobuf_append(&nc->send_iobuf, buf, len);
00407 }
00408 }
00409
00410 #ifndef NS_DISABLE_THREADS
00411 void *ns_start_thread(void *(*f)(void *), void *p) {
00412 #ifdef _WIN32
00413 return (void *) _beginthread((void (__cdecl *)(void *)) f, 0, p);
00414 #else
00415 pthread_t thread_id = (pthread_t) 0;
00416 pthread_attr_t attr;
00417
00418 (void) pthread_attr_init(&attr);
00419 (void) pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
00420
00421 #if defined(NS_STACK_SIZE) && NS_STACK_SIZE > 1
00422 (void) pthread_attr_setstacksize(&attr, NS_STACK_SIZE);
00423 #endif
00424
00425 pthread_create(&thread_id, &attr, f, p);
00426 pthread_attr_destroy(&attr);
00427
00428 return (void *) thread_id;
00429 #endif
00430 }
00431 #endif // NS_DISABLE_THREADS
00432
00433 static void ns_add_conn(struct ns_mgr *mgr, struct ns_connection *c) {
00434 c->next = mgr->active_connections;
00435 mgr->active_connections = c;
00436 c->prev = NULL;
00437 if (c->next != NULL) c->next->prev = c;
00438 }
00439
00440 static void ns_remove_conn(struct ns_connection *conn) {
00441 if (conn->prev == NULL) conn->mgr->active_connections = conn->next;
00442 if (conn->prev) conn->prev->next = conn->next;
00443 if (conn->next) conn->next->prev = conn->prev;
00444 }
00445
00446
00447
00448
00449 int ns_avprintf(char **buf, size_t size, const char *fmt, va_list ap) {
00450 va_list ap_copy;
00451 int len;
00452
00453 va_copy(ap_copy, ap);
00454 len = vsnprintf(*buf, size, fmt, ap_copy);
00455 va_end(ap_copy);
00456
00457 if (len < 0) {
00458
00459
00460
00461 *buf = NULL;
00462 while (len < 0) {
00463 if (*buf) NS_FREE(*buf);
00464 size *= 2;
00465 if ((*buf = (char *) NS_MALLOC(size)) == NULL) break;
00466 va_copy(ap_copy, ap);
00467 len = vsnprintf(*buf, size, fmt, ap_copy);
00468 va_end(ap_copy);
00469 }
00470 } else if (len > (int) size) {
00471
00472 if ((*buf = (char *) NS_MALLOC(len + 1)) == NULL) {
00473 len = -1;
00474 } else {
00475 va_copy(ap_copy, ap);
00476 len = vsnprintf(*buf, len + 1, fmt, ap_copy);
00477 va_end(ap_copy);
00478 }
00479 }
00480
00481 return len;
00482 }
00483
00484 int ns_vprintf(struct ns_connection *nc, const char *fmt, va_list ap) {
00485 char mem[NS_VPRINTF_BUFFER_SIZE], *buf = mem;
00486 int len;
00487
00488 if ((len = ns_avprintf(&buf, sizeof(mem), fmt, ap)) > 0) {
00489 ns_out(nc, buf, len);
00490 }
00491 if (buf != mem && buf != NULL) {
00492 NS_FREE(buf);
00493 }
00494
00495 return len;
00496 }
00497
00498 int ns_printf(struct ns_connection *conn, const char *fmt, ...) {
00499 int len;
00500 va_list ap;
00501 va_start(ap, fmt);
00502 len = ns_vprintf(conn, fmt, ap);
00503 va_end(ap);
00504 return len;
00505 }
00506
00507 static void hexdump(struct ns_connection *nc, const char *path,
00508 int num_bytes, int ev) {
00509 const struct iobuf *io = ev == NS_SEND ? &nc->send_iobuf : &nc->recv_iobuf;
00510 FILE *fp;
00511 char *buf, src[60], dst[60];
00512 int buf_size = num_bytes * 5 + 100;
00513
00514 if ((fp = fopen(path, "a")) != NULL) {
00515 ns_sock_to_str(nc->sock, src, sizeof(src), 3);
00516 ns_sock_to_str(nc->sock, dst, sizeof(dst), 7);
00517 fprintf(fp, "%lu %p %s %s %s %d\n", (unsigned long) time(NULL),
00518 nc->user_data, src,
00519 ev == NS_RECV ? "<-" : ev == NS_SEND ? "->" :
00520 ev == NS_ACCEPT ? "<A" : ev == NS_CONNECT ? "C>" : "XX",
00521 dst, num_bytes);
00522 if (num_bytes > 0 && (buf = (char *) NS_MALLOC(buf_size)) != NULL) {
00523 ns_hexdump(io->buf + (ev == NS_SEND ? 0 : io->len) -
00524 (ev == NS_SEND ? 0 : num_bytes), num_bytes, buf, buf_size);
00525 fprintf(fp, "%s", buf);
00526 NS_FREE(buf);
00527 }
00528 fclose(fp);
00529 }
00530 }
00531
00532 static void ns_call(struct ns_connection *nc, int ev, void *p) {
00533 if (nc->mgr->hexdump_file != NULL && ev != NS_POLL) {
00534 int len = (ev == NS_RECV || ev == NS_SEND) ? * (int *) p : 0;
00535 hexdump(nc, nc->mgr->hexdump_file, len, ev);
00536 }
00537
00538 nc->callback(nc, ev, p);
00539 }
00540
00541 static void ns_destroy_conn(struct ns_connection *conn) {
00542 closesocket(conn->sock);
00543 iobuf_free(&conn->recv_iobuf);
00544 iobuf_free(&conn->send_iobuf);
00545 #ifdef NS_ENABLE_SSL
00546 if (conn->ssl != NULL) {
00547 SSL_free(conn->ssl);
00548 }
00549 if (conn->ssl_ctx != NULL) {
00550 SSL_CTX_free(conn->ssl_ctx);
00551 }
00552 #endif
00553 NS_FREE(conn);
00554 }
00555
00556 static void ns_close_conn(struct ns_connection *conn) {
00557 DBG(("%p %d", conn, conn->flags));
00558 ns_call(conn, NS_CLOSE, NULL);
00559 ns_remove_conn(conn);
00560 ns_destroy_conn(conn);
00561 }
00562
00563 void ns_set_close_on_exec(sock_t sock) {
00564 #ifdef _WIN32
00565 (void) SetHandleInformation((HANDLE) sock, HANDLE_FLAG_INHERIT, 0);
00566 #else
00567 fcntl(sock, F_SETFD, FD_CLOEXEC);
00568 #endif
00569 }
00570
00571 static void ns_set_non_blocking_mode(sock_t sock) {
00572 #ifdef _WIN32
00573 unsigned long on = 1;
00574 ioctlsocket(sock, FIONBIO, &on);
00575 #else
00576 int flags = fcntl(sock, F_GETFL, 0);
00577 fcntl(sock, F_SETFL, flags | O_NONBLOCK);
00578 #endif
00579 }
00580
00581 #ifndef NS_DISABLE_SOCKETPAIR
00582 int ns_socketpair2(sock_t sp[2], int sock_type) {
00583 union socket_address sa;
00584 sock_t sock;
00585 socklen_t len = sizeof(sa.sin);
00586 int ret = 0;
00587
00588 sp[0] = sp[1] = INVALID_SOCKET;
00589
00590 (void) memset(&sa, 0, sizeof(sa));
00591 sa.sin.sin_family = AF_INET;
00592 sa.sin.sin_port = htons(0);
00593 sa.sin.sin_addr.s_addr = htonl(0x7f000001);
00594
00595 if ((sock = socket(AF_INET, sock_type, 0)) != INVALID_SOCKET &&
00596 !bind(sock, &sa.sa, len) &&
00597 (sock_type == SOCK_DGRAM || !listen(sock, 1)) &&
00598 !getsockname(sock, &sa.sa, &len) &&
00599 (sp[0] = socket(AF_INET, sock_type, 0)) != INVALID_SOCKET &&
00600 !connect(sp[0], &sa.sa, len) &&
00601 (sock_type == SOCK_STREAM ||
00602 (!getsockname(sp[0], &sa.sa, &len) && !connect(sock, &sa.sa, len))) &&
00603 (sp[1] = (sock_type == SOCK_DGRAM ? sock :
00604 accept(sock, &sa.sa, &len))) != INVALID_SOCKET) {
00605 ns_set_close_on_exec(sp[0]);
00606 ns_set_close_on_exec(sp[1]);
00607 ret = 1;
00608 } else {
00609 if (sp[0] != INVALID_SOCKET) closesocket(sp[0]);
00610 if (sp[1] != INVALID_SOCKET) closesocket(sp[1]);
00611 sp[0] = sp[1] = INVALID_SOCKET;
00612 }
00613 if (sock_type != SOCK_DGRAM) closesocket(sock);
00614
00615 return ret;
00616 }
00617
00618 int ns_socketpair(sock_t sp[2]) {
00619 return ns_socketpair2(sp, SOCK_STREAM);
00620 }
00621 #endif // NS_DISABLE_SOCKETPAIR
00622
00623
00624 static int ns_resolve2(const char *host, struct in_addr *ina) {
00625 #ifdef NS_ENABLE_GETADDRINFO
00626 int rv = 0;
00627 struct addrinfo hints, *servinfo, *p;
00628 struct sockaddr_in *h = NULL;
00629
00630 memset(&hints, 0, sizeof hints);
00631 hints.ai_family = AF_INET;
00632 hints.ai_socktype = SOCK_STREAM;
00633
00634 if((rv = getaddrinfo(host, NULL , NULL, &servinfo)) != 0) {
00635 DBG(("getaddrinfo(%s) failed: %s", host, strerror(errno)));
00636 return 0;
00637 }
00638
00639 for(p = servinfo; p != NULL; p = p->ai_next) {
00640 memcpy(&h, &p->ai_addr, sizeof(struct sockaddr_in *));
00641 memcpy(ina, &h->sin_addr, sizeof(ina));
00642 }
00643
00644 freeaddrinfo(servinfo);
00645 return 1;
00646 #else
00647 struct hostent *he;
00648 if ((he = gethostbyname(host)) == NULL) {
00649 DBG(("gethostbyname(%s) failed: %s", host, strerror(errno)));
00650 } else {
00651 memcpy(ina, he->h_addr_list[0], sizeof(*ina));
00652 return 1;
00653 }
00654 return 0;
00655 #endif
00656 }
00657
00658
00659
00660 int ns_resolve(const char *host, char *buf, size_t n) {
00661 struct in_addr ad;
00662 return ns_resolve2(host, &ad) ? snprintf(buf, n, "%s", inet_ntoa(ad)) : 0;
00663 }
00664
00665
00666 static int ns_parse_address(const char *str, union socket_address *sa,
00667 int *proto, int *use_ssl, char *cert, char *ca) {
00668 unsigned int a, b, c, d, port;
00669 int n = 0, len = 0;
00670 char host[200];
00671 #ifdef NS_ENABLE_IPV6
00672 char buf[100];
00673 #endif
00674
00675
00676
00677
00678 memset(sa, 0, sizeof(*sa));
00679 sa->sin.sin_family = AF_INET;
00680
00681 *proto = SOCK_STREAM;
00682 *use_ssl = 0;
00683 cert[0] = ca[0] = '\0';
00684
00685 if (memcmp(str, "ssl://", 6) == 0) {
00686 str += 6;
00687 *use_ssl = 1;
00688 } else if (memcmp(str, "udp://", 6) == 0) {
00689 str += 6;
00690 *proto = SOCK_DGRAM;
00691 } else if (memcmp(str, "tcp://", 6) == 0) {
00692 str += 6;
00693 }
00694
00695 if (sscanf(str, "%u.%u.%u.%u:%u%n", &a, &b, &c, &d, &port, &len) == 5) {
00696
00697 sa->sin.sin_addr.s_addr = htonl((a << 24) | (b << 16) | (c << 8) | d);
00698 sa->sin.sin_port = htons((uint16_t) port);
00699 #ifdef NS_ENABLE_IPV6
00700 } else if (sscanf(str, "[%99[^]]]:%u%n", buf, &port, &len) == 2 &&
00701 inet_pton(AF_INET6, buf, &sa->sin6.sin6_addr)) {
00702
00703 sa->sin6.sin6_family = AF_INET6;
00704 sa->sin6.sin6_port = htons((uint16_t) port);
00705 #endif
00706 } else if (sscanf(str, "%199[^ :]:%u%n", host, &port, &len) == 2) {
00707 sa->sin.sin_port = htons((uint16_t) port);
00708 ns_resolve2(host, &sa->sin.sin_addr);
00709 } else if (sscanf(str, "%u%n", &port, &len) == 1) {
00710
00711 sa->sin.sin_port = htons((uint16_t) port);
00712 }
00713
00714 if (*use_ssl && (sscanf(str + len, ":%99[^:,]:%99[^:,]%n", cert, ca, &n) == 2 ||
00715 sscanf(str + len, ":%99[^:,]%n", cert, &n) == 1)) {
00716 len += n;
00717 }
00718
00719 return port < 0xffff && str[len] == '\0' ? len : 0;
00720 }
00721
00722
00723 static sock_t ns_open_listening_socket(union socket_address *sa, int proto) {
00724 socklen_t sa_len = (sa->sa.sa_family == AF_INET) ?
00725 sizeof(sa->sin) : sizeof(sa->sin6);
00726 sock_t sock = INVALID_SOCKET;
00727 #ifndef _WIN32
00728 int on = 1;
00729 #endif
00730
00731 if ((sock = socket(sa->sa.sa_family, proto, 0)) != INVALID_SOCKET &&
00732 #ifndef _WIN32
00733
00734
00735
00736
00737
00738
00739 !setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void *) &on, sizeof(on)) &&
00740 #endif
00741 !bind(sock, &sa->sa, sa_len) &&
00742 (proto == SOCK_DGRAM || listen(sock, SOMAXCONN) == 0)) {
00743 ns_set_non_blocking_mode(sock);
00744
00745 (void) getsockname(sock, &sa->sa, &sa_len);
00746 } else if (sock != INVALID_SOCKET) {
00747 closesocket(sock);
00748 sock = INVALID_SOCKET;
00749 }
00750
00751 return sock;
00752 }
00753
00754 #ifdef NS_ENABLE_SSL
00755
00756
00757
00758 static int ns_use_ca_cert(SSL_CTX *ctx, const char *cert) {
00759 if (ctx == NULL) {
00760 return -1;
00761 } else if (cert == NULL || cert[0] == '\0') {
00762 return 0;
00763 }
00764 SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, 0);
00765 return SSL_CTX_load_verify_locations(ctx, cert, NULL) == 1 ? 0 : -2;
00766 }
00767
00768 static int ns_use_cert(SSL_CTX *ctx, const char *pem_file) {
00769 if (ctx == NULL) {
00770 return -1;
00771 } else if (pem_file == NULL || pem_file[0] == '\0') {
00772 return 0;
00773 } else if (SSL_CTX_use_certificate_file(ctx, pem_file, 1) == 0 ||
00774 SSL_CTX_use_PrivateKey_file(ctx, pem_file, 1) == 0) {
00775 return -2;
00776 } else {
00777 SSL_CTX_set_mode(ctx, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
00778 SSL_CTX_use_certificate_chain_file(ctx, pem_file);
00779 return 0;
00780 }
00781 }
00782 #endif // NS_ENABLE_SSL
00783
00784 struct ns_connection *ns_bind(struct ns_mgr *srv, const char *str,
00785 ns_callback_t callback, void *user_data) {
00786 union socket_address sa;
00787 struct ns_connection *nc = NULL;
00788 int use_ssl, proto;
00789 char cert[100], ca_cert[100];
00790 sock_t sock;
00791
00792 ns_parse_address(str, &sa, &proto, &use_ssl, cert, ca_cert);
00793 if (use_ssl && cert[0] == '\0') return NULL;
00794
00795 if ((sock = ns_open_listening_socket(&sa, proto)) == INVALID_SOCKET) {
00796 } else if ((nc = ns_add_sock(srv, sock, callback, NULL)) == NULL) {
00797 closesocket(sock);
00798 } else {
00799 nc->sa = sa;
00800 nc->flags |= NSF_LISTENING;
00801 nc->user_data = user_data;
00802 nc->callback = callback;
00803
00804 if (proto == SOCK_DGRAM) {
00805 nc->flags |= NSF_UDP;
00806 }
00807
00808 #ifdef NS_ENABLE_SSL
00809 if (use_ssl) {
00810 nc->ssl_ctx = SSL_CTX_new(SSLv23_server_method());
00811 if (ns_use_cert(nc->ssl_ctx, cert) != 0 ||
00812 ns_use_ca_cert(nc->ssl_ctx, ca_cert) != 0) {
00813 ns_close_conn(nc);
00814 nc = NULL;
00815 }
00816 }
00817 #endif
00818
00819 DBG(("%p sock %d/%d ssl %p %p", nc, sock, proto, nc->ssl_ctx, nc->ssl));
00820 }
00821
00822 return nc;
00823 }
00824
00825 static struct ns_connection *accept_conn(struct ns_connection *ls) {
00826 struct ns_connection *c = NULL;
00827 union socket_address sa;
00828 socklen_t len = sizeof(sa);
00829 sock_t sock = INVALID_SOCKET;
00830
00831
00832 if ((sock = accept(ls->sock, &sa.sa, &len)) == INVALID_SOCKET) {
00833 } else if ((c = ns_add_sock(ls->mgr, sock, ls->callback,
00834 ls->user_data)) == NULL) {
00835 closesocket(sock);
00836 #ifdef NS_ENABLE_SSL
00837 } else if (ls->ssl_ctx != NULL &&
00838 ((c->ssl = SSL_new(ls->ssl_ctx)) == NULL ||
00839 SSL_set_fd(c->ssl, sock) != 1)) {
00840 DBG(("SSL error"));
00841 ns_close_conn(c);
00842 c = NULL;
00843 #endif
00844 } else {
00845 c->listener = ls;
00846 c->proto_data = ls->proto_data;
00847 ns_call(c, NS_ACCEPT, &sa);
00848 DBG(("%p %d %p %p", c, c->sock, c->ssl_ctx, c->ssl));
00849 }
00850
00851 return c;
00852 }
00853
00854 static int ns_is_error(int n) {
00855 return n == 0 ||
00856 (n < 0 && errno != EINTR && errno != EINPROGRESS &&
00857 errno != EAGAIN && errno != EWOULDBLOCK
00858 #ifdef _WIN32
00859 && WSAGetLastError() != WSAEINTR && WSAGetLastError() != WSAEWOULDBLOCK
00860 #endif
00861 );
00862 }
00863
00864 void ns_sock_to_str(sock_t sock, char *buf, size_t len, int flags) {
00865 union socket_address sa;
00866 socklen_t slen = sizeof(sa);
00867
00868 if (buf != NULL && len > 0) {
00869 buf[0] = '\0';
00870 memset(&sa, 0, sizeof(sa));
00871 if (flags & 4) {
00872 getpeername(sock, &sa.sa, &slen);
00873 } else {
00874 getsockname(sock, &sa.sa, &slen);
00875 }
00876 if (flags & 1) {
00877 #if defined(NS_ENABLE_IPV6)
00878 inet_ntop(sa.sa.sa_family, sa.sa.sa_family == AF_INET ?
00879 (void *) &sa.sin.sin_addr :
00880 (void *) &sa.sin6.sin6_addr, buf, len);
00881 #elif defined(_WIN32)
00882
00883 strncpy(buf, inet_ntoa(sa.sin.sin_addr), len);
00884 #else
00885 inet_ntop(sa.sa.sa_family, (void *) &sa.sin.sin_addr, buf,(socklen_t)len);
00886 #endif
00887 }
00888 if (flags & 2) {
00889 snprintf(buf + strlen(buf), len - (strlen(buf) + 1), "%s%d",
00890 flags & 1 ? ":" : "", (int) ntohs(sa.sin.sin_port));
00891 }
00892 }
00893 }
00894
00895 int ns_hexdump(const void *buf, int len, char *dst, int dst_len) {
00896 const unsigned char *p = (const unsigned char *) buf;
00897 char ascii[17] = "";
00898 int i, idx, n = 0;
00899
00900 for (i = 0; i < len; i++) {
00901 idx = i % 16;
00902 if (idx == 0) {
00903 if (i > 0) n += snprintf(dst + n, dst_len - n, " %s\n", ascii);
00904 n += snprintf(dst + n, dst_len - n, "%04x ", i);
00905 }
00906 n += snprintf(dst + n, dst_len - n, " %02x", p[i]);
00907 ascii[idx] = p[i] < 0x20 || p[i] > 0x7e ? '.' : p[i];
00908 ascii[idx + 1] = '\0';
00909 }
00910
00911 while (i++ % 16) n += snprintf(dst + n, dst_len - n, "%s", " ");
00912 n += snprintf(dst + n, dst_len - n, " %s\n\n", ascii);
00913
00914 return n;
00915 }
00916
00917 #ifdef NS_ENABLE_SSL
00918 static int ns_ssl_err(struct ns_connection *conn, int res) {
00919 int ssl_err = SSL_get_error(conn->ssl, res);
00920 if (ssl_err == SSL_ERROR_WANT_READ) conn->flags |= NSF_WANT_READ;
00921 if (ssl_err == SSL_ERROR_WANT_WRITE) conn->flags |= NSF_WANT_WRITE;
00922 return ssl_err;
00923 }
00924 #endif
00925
00926 static void ns_read_from_socket(struct ns_connection *conn) {
00927 char buf[NS_READ_BUFFER_SIZE];
00928 int n = 0;
00929
00930 if (conn->flags & NSF_CONNECTING) {
00931 int ok = 1, ret;
00932 socklen_t len = sizeof(ok);
00933
00934 ret = getsockopt(conn->sock, SOL_SOCKET, SO_ERROR, (char *) &ok, &len);
00935 (void) ret;
00936 #ifdef NS_ENABLE_SSL
00937 if (ret == 0 && ok == 0 && conn->ssl != NULL) {
00938 int res = SSL_connect(conn->ssl);
00939 int ssl_err = ns_ssl_err(conn, res);
00940 if (res == 1) {
00941 conn->flags |= NSF_SSL_HANDSHAKE_DONE;
00942 } else if (ssl_err == SSL_ERROR_WANT_READ ||
00943 ssl_err == SSL_ERROR_WANT_WRITE) {
00944 return;
00945 } else {
00946 ok = 1;
00947 }
00948 conn->flags &= ~(NSF_WANT_READ | NSF_WANT_WRITE);
00949 }
00950 #endif
00951 conn->flags &= ~NSF_CONNECTING;
00952 DBG(("%p ok=%d", conn, ok));
00953 if (ok != 0) {
00954 conn->flags |= NSF_CLOSE_IMMEDIATELY;
00955 }
00956 ns_call(conn, NS_CONNECT, &ok);
00957 return;
00958 }
00959
00960 #ifdef NS_ENABLE_SSL
00961 if (conn->ssl != NULL) {
00962 if (conn->flags & NSF_SSL_HANDSHAKE_DONE) {
00963
00964
00965
00966 while ((n = SSL_read(conn->ssl, buf, sizeof(buf))) > 0) {
00967 DBG(("%p %d <- %d bytes (SSL)", conn, conn->flags, n));
00968 iobuf_append(&conn->recv_iobuf, buf, n);
00969 ns_call(conn, NS_RECV, &n);
00970 }
00971 ns_ssl_err(conn, n);
00972 } else {
00973 int res = SSL_accept(conn->ssl);
00974 int ssl_err = ns_ssl_err(conn, res);
00975 if (res == 1) {
00976 conn->flags |= NSF_SSL_HANDSHAKE_DONE;
00977 conn->flags &= ~(NSF_WANT_READ | NSF_WANT_WRITE);
00978 } else if (ssl_err == SSL_ERROR_WANT_READ ||
00979 ssl_err == SSL_ERROR_WANT_WRITE) {
00980 return;
00981 } else {
00982 conn->flags |= NSF_CLOSE_IMMEDIATELY;
00983 }
00984 return;
00985 }
00986 } else
00987 #endif
00988 {
00989 while ((n = (int) recv(conn->sock, buf, sizeof(buf), 0)) > 0) {
00990 DBG(("%p %d <- %d bytes (PLAIN)", conn, conn->flags, n));
00991 iobuf_append(&conn->recv_iobuf, buf, n);
00992 ns_call(conn, NS_RECV, &n);
00993 }
00994 }
00995
00996 if (ns_is_error(n)) {
00997 conn->flags |= NSF_CLOSE_IMMEDIATELY;
00998 }
00999 }
01000
01001 static void ns_write_to_socket(struct ns_connection *conn) {
01002 struct iobuf *io = &conn->send_iobuf;
01003 int n = 0;
01004
01005 #ifdef NS_ENABLE_SSL
01006 if (conn->ssl != NULL) {
01007 n = SSL_write(conn->ssl, io->buf, io->len);
01008 if (n <= 0) {
01009 int ssl_err = ns_ssl_err(conn, n);
01010 if (ssl_err == SSL_ERROR_WANT_READ || ssl_err == SSL_ERROR_WANT_WRITE) {
01011 return;
01012 } else {
01013 conn->flags |= NSF_CLOSE_IMMEDIATELY;
01014 }
01015 } else {
01016 conn->flags &= ~(NSF_WANT_READ | NSF_WANT_WRITE);
01017 }
01018 } else
01019 #endif
01020 { n = (int) send(conn->sock, io->buf, io->len, 0); }
01021
01022 DBG(("%p %d -> %d bytes", conn, conn->flags, n));
01023
01024 ns_call(conn, NS_SEND, &n);
01025 if (ns_is_error(n)) {
01026 conn->flags |= NSF_CLOSE_IMMEDIATELY;
01027 } else if (n > 0) {
01028 iobuf_remove(io, n);
01029 }
01030 }
01031
01032 int ns_send(struct ns_connection *conn, const void *buf, size_t len) {
01033 return (int) ns_out(conn, buf, len);
01034 }
01035
01036 static void ns_handle_udp(struct ns_connection *ls) {
01037 struct ns_connection nc;
01038 char buf[NS_UDP_RECEIVE_BUFFER_SIZE];
01039 ssize_t n;
01040 socklen_t s_len = sizeof(nc.sa);
01041
01042 memset(&nc, 0, sizeof(nc));
01043 n = recvfrom(ls->sock, buf, sizeof(buf), 0, &nc.sa.sa, &s_len);
01044 if (n <= 0) {
01045 DBG(("%p recvfrom: %s", ls, strerror(errno)));
01046 } else {
01047 nc.mgr = ls->mgr;
01048 nc.recv_iobuf.buf = buf;
01049 nc.recv_iobuf.len = nc.recv_iobuf.size = n;
01050 nc.sock = ls->sock;
01051 nc.callback = ls->callback;
01052 nc.user_data = ls->user_data;
01053 nc.proto_data = ls->proto_data;
01054 nc.mgr = ls->mgr;
01055 nc.listener = ls;
01056 nc.flags = NSF_UDP;
01057 DBG(("%p %d bytes received", ls, n));
01058 ns_call(&nc, NS_RECV, &n);
01059 }
01060 }
01061
01062 static void ns_add_to_set(sock_t sock, fd_set *set, sock_t *max_fd) {
01063 if (sock != INVALID_SOCKET) {
01064 FD_SET(sock, set);
01065 if (*max_fd == INVALID_SOCKET || sock > *max_fd) {
01066 *max_fd = sock;
01067 }
01068 }
01069 }
01070
01071 time_t ns_mgr_poll(struct ns_mgr *mgr, int milli) {
01072 struct ns_connection *conn, *tmp_conn;
01073 struct timeval tv;
01074 fd_set read_set, write_set;
01075 sock_t max_fd = INVALID_SOCKET;
01076 time_t current_time = time(NULL);
01077
01078 FD_ZERO(&read_set);
01079 FD_ZERO(&write_set);
01080 ns_add_to_set(mgr->ctl[1], &read_set, &max_fd);
01081
01082 for (conn = mgr->active_connections; conn != NULL; conn = tmp_conn) {
01083 tmp_conn = conn->next;
01084 if (!(conn->flags & (NSF_LISTENING | NSF_CONNECTING))) {
01085 ns_call(conn, NS_POLL, ¤t_time);
01086 }
01087 if (conn->flags & NSF_CLOSE_IMMEDIATELY) {
01088 ns_close_conn(conn);
01089 } else {
01090 if (!(conn->flags & NSF_WANT_WRITE)) {
01091
01092 ns_add_to_set(conn->sock, &read_set, &max_fd);
01093 }
01094 if (((conn->flags & NSF_CONNECTING) && !(conn->flags & NSF_WANT_READ)) ||
01095 (conn->send_iobuf.len > 0 && !(conn->flags & NSF_CONNECTING) &&
01096 !(conn->flags & NSF_BUFFER_BUT_DONT_SEND))) {
01097
01098 ns_add_to_set(conn->sock, &write_set, &max_fd);
01099 }
01100 }
01101 }
01102
01103 tv.tv_sec = milli / 1000;
01104 tv.tv_usec = (milli % 1000) * 1000;
01105
01106 if (select((int) max_fd + 1, &read_set, &write_set, NULL, &tv) > 0) {
01107
01108
01109 current_time = time(NULL);
01110
01111
01112 if (mgr->ctl[1] != INVALID_SOCKET &&
01113 FD_ISSET(mgr->ctl[1], &read_set)) {
01114 struct ctl_msg ctl_msg;
01115 int len = (int) recv(mgr->ctl[1], (char *) &ctl_msg, sizeof(ctl_msg), 0);
01116 send(mgr->ctl[1], ctl_msg.message, 1, 0);
01117 if (len >= (int) sizeof(ctl_msg.callback) && ctl_msg.callback != NULL) {
01118 struct ns_connection *c;
01119 for (c = ns_next(mgr, NULL); c != NULL; c = ns_next(mgr, c)) {
01120 ctl_msg.callback(c, NS_POLL, ctl_msg.message);
01121 }
01122 }
01123 }
01124
01125 for (conn = mgr->active_connections; conn != NULL; conn = tmp_conn) {
01126 tmp_conn = conn->next;
01127 if (FD_ISSET(conn->sock, &read_set)) {
01128 if (conn->flags & NSF_LISTENING) {
01129 if (conn->flags & NSF_UDP) {
01130 ns_handle_udp(conn);
01131 } else {
01132
01133
01134
01135 accept_conn(conn);
01136 }
01137 } else {
01138 conn->last_io_time = current_time;
01139 ns_read_from_socket(conn);
01140 }
01141 }
01142
01143 if (FD_ISSET(conn->sock, &write_set)) {
01144 if (conn->flags & NSF_CONNECTING) {
01145 ns_read_from_socket(conn);
01146 } else if (!(conn->flags & NSF_BUFFER_BUT_DONT_SEND)) {
01147 conn->last_io_time = current_time;
01148 ns_write_to_socket(conn);
01149 }
01150 }
01151 }
01152 }
01153
01154 for (conn = mgr->active_connections; conn != NULL; conn = tmp_conn) {
01155 tmp_conn = conn->next;
01156 if ((conn->flags & NSF_CLOSE_IMMEDIATELY) ||
01157 (conn->send_iobuf.len == 0 &&
01158 (conn->flags & NSF_FINISHED_SENDING_DATA))) {
01159 ns_close_conn(conn);
01160 }
01161 }
01162
01163 return current_time;
01164 }
01165
01166 struct ns_connection *ns_connect(struct ns_mgr *mgr, const char *address,
01167 ns_callback_t callback, void *user_data) {
01168 sock_t sock = INVALID_SOCKET;
01169 struct ns_connection *nc = NULL;
01170 union socket_address sa;
01171 char cert[100], ca_cert[100];
01172 int rc, use_ssl, proto;
01173
01174 ns_parse_address(address, &sa, &proto, &use_ssl, cert, ca_cert);
01175 if ((sock = socket(AF_INET, proto, 0)) == INVALID_SOCKET) {
01176 return NULL;
01177 }
01178 ns_set_non_blocking_mode(sock);
01179 rc = (proto == SOCK_DGRAM) ? 0 : connect(sock, &sa.sa, sizeof(sa.sin));
01180
01181 if (rc != 0 && ns_is_error(rc)) {
01182 closesocket(sock);
01183 return NULL;
01184 } else if ((nc = ns_add_sock(mgr, sock, callback, user_data)) == NULL) {
01185 closesocket(sock);
01186 return NULL;
01187 }
01188
01189 nc->sa = sa;
01190 nc->flags = (proto == SOCK_DGRAM) ? NSF_UDP : NSF_CONNECTING;
01191
01192 #ifdef NS_ENABLE_SSL
01193 if (use_ssl) {
01194 if ((nc->ssl_ctx = SSL_CTX_new(SSLv23_client_method())) == NULL ||
01195 ns_use_cert(nc->ssl_ctx, cert) != 0 ||
01196 ns_use_ca_cert(nc->ssl_ctx, ca_cert) != 0 ||
01197 (nc->ssl = SSL_new(nc->ssl_ctx)) == NULL) {
01198 ns_close_conn(nc);
01199 return NULL;
01200 } else {
01201 SSL_set_fd(nc->ssl, sock);
01202 }
01203 }
01204 #endif
01205
01206 return nc;
01207 }
01208
01209 struct ns_connection *ns_add_sock(struct ns_mgr *s, sock_t sock,
01210 ns_callback_t callback, void *user_data) {
01211 struct ns_connection *conn;
01212 if ((conn = (struct ns_connection *) NS_MALLOC(sizeof(*conn))) != NULL) {
01213 memset(conn, 0, sizeof(*conn));
01214 ns_set_non_blocking_mode(sock);
01215 ns_set_close_on_exec(sock);
01216 conn->sock = sock;
01217 conn->user_data = user_data;
01218 conn->callback = callback;
01219 conn->mgr = s;
01220 conn->last_io_time = time(NULL);
01221 ns_add_conn(s, conn);
01222 DBG(("%p %d", conn, sock));
01223 }
01224 return conn;
01225 }
01226
01227 struct ns_connection *ns_next(struct ns_mgr *s, struct ns_connection *conn) {
01228 return conn == NULL ? s->active_connections : conn->next;
01229 }
01230
01231 void ns_broadcast(struct ns_mgr *mgr, ns_callback_t cb,void *data, size_t len) {
01232 struct ctl_msg ctl_msg;
01233 if (mgr->ctl[0] != INVALID_SOCKET && data != NULL &&
01234 len < sizeof(ctl_msg.message)) {
01235 ctl_msg.callback = cb;
01236 memcpy(ctl_msg.message, data, len);
01237 send(mgr->ctl[0], (char *) &ctl_msg,
01238 offsetof(struct ctl_msg, message) + len, 0);
01239 recv(mgr->ctl[0], (char *) &len, 1, 0);
01240 }
01241 }
01242
01243 void ns_mgr_init(struct ns_mgr *s, void *user_data) {
01244 memset(s, 0, sizeof(*s));
01245 s->ctl[0] = s->ctl[1] = INVALID_SOCKET;
01246 s->user_data = user_data;
01247
01248 #ifdef _WIN32
01249 { WSADATA data; WSAStartup(MAKEWORD(2, 2), &data); }
01250 #else
01251
01252
01253 signal(SIGPIPE, SIG_IGN);
01254 #endif
01255
01256 #ifndef NS_DISABLE_SOCKETPAIR
01257 do {
01258 ns_socketpair2(s->ctl, SOCK_DGRAM);
01259 } while (s->ctl[0] == INVALID_SOCKET);
01260 #endif
01261
01262 #ifdef NS_ENABLE_SSL
01263 {static int init_done; if (!init_done) { SSL_library_init(); init_done++; }}
01264 #endif
01265 }
01266
01267 void ns_mgr_free(struct ns_mgr *s) {
01268 struct ns_connection *conn, *tmp_conn;
01269
01270 DBG(("%p", s));
01271 if (s == NULL) return;
01272
01273 ns_mgr_poll(s, 0);
01274
01275 if (s->ctl[0] != INVALID_SOCKET) closesocket(s->ctl[0]);
01276 if (s->ctl[1] != INVALID_SOCKET) closesocket(s->ctl[1]);
01277 s->ctl[0] = s->ctl[1] = INVALID_SOCKET;
01278
01279 for (conn = s->active_connections; conn != NULL; conn = tmp_conn) {
01280 tmp_conn = conn->next;
01281 ns_close_conn(conn);
01282 }
01283 }
01284
01285 #endif // NOEMBED_NET_SKELETON
01286
01287 #include <ctype.h>
01288
01289 #ifdef _WIN32 //////////////// Windows specific defines and includes
01290 #include <io.h>
01291 #include <direct.h>
01292 #ifndef S_ISDIR
01293 #define S_ISDIR(x) ((x) & _S_IFDIR)
01294 #endif
01295 #ifdef stat
01296 #undef stat
01297 #endif
01298 #ifdef lseek
01299 #undef lseek
01300 #endif
01301 #ifdef popen
01302 #undef popen
01303 #endif
01304 #ifdef pclose
01305 #undef pclose
01306 #endif
01307 #define stat(x, y) mg_stat((x), (y))
01308 #define fopen(x, y) mg_fopen((x), (y))
01309 #define open(x, y, z) mg_open((x), (y), (z))
01310 #define close(x) _close(x)
01311 #define fileno(x) _fileno(x)
01312 #define lseek(x, y, z) _lseeki64((x), (y), (z))
01313 #define read(x, y, z) _read((x), (y), (z))
01314 #define write(x, y, z) _write((x), (y), (z))
01315 #define popen(x, y) _popen((x), (y))
01316 #define pclose(x) _pclose(x)
01317 #define mkdir(x, y) _mkdir(x)
01318 #define rmdir(x) _rmdir(x)
01319 #define strdup(x) _strdup(x)
01320 #ifndef __func__
01321 #define STRX(x) #x
01322 #define STR(x) STRX(x)
01323 #define __func__ __FILE__ ":" STR(__LINE__)
01324 #endif
01325 #define INT64_FMT "I64d"
01326 #define flockfile(x) ((void) (x))
01327 #define funlockfile(x) ((void) (x))
01328 typedef struct _stati64 file_stat_t;
01329 typedef HANDLE process_id_t;
01330
01331 #else ////////////// UNIX specific defines and includes
01332
01333 #if !defined(MONGOOSE_NO_FILESYSTEM) &&\
01334 (!defined(MONGOOSE_NO_DAV) || !defined(MONGOOSE_NO_DIRECTORY_LISTING))
01335 #include <dirent.h>
01336 #endif
01337 #if !defined(MONGOOSE_NO_FILESYSTEM) && !defined(MONGOOSE_NO_DL)
01338 #include <dlfcn.h>
01339 #endif
01340 #include <inttypes.h>
01341 #include <pwd.h>
01342 #if !defined(O_BINARY)
01343 #define O_BINARY 0
01344 #endif
01345 #define INT64_FMT PRId64
01346 typedef struct stat file_stat_t;
01347 typedef pid_t process_id_t;
01348 #endif //////// End of platform-specific defines and includes
01349
01350 #include "mongoose.h"
01351
01352 #define MAX_REQUEST_SIZE 16384
01353 #define IOBUF_SIZE 8192
01354 #define MAX_PATH_SIZE 8192
01355 #define DEFAULT_CGI_PATTERN "**.cgi$|**.pl$|**.php$"
01356 #define CGI_ENVIRONMENT_SIZE 8192
01357 #define MAX_CGI_ENVIR_VARS 64
01358 #define ENV_EXPORT_TO_CGI "MONGOOSE_CGI"
01359 #define PASSWORDS_FILE_NAME ".htpasswd"
01360
01361 #ifndef MONGOOSE_USE_WEBSOCKET_PING_INTERVAL
01362 #define MONGOOSE_USE_WEBSOCKET_PING_INTERVAL 5
01363 #endif
01364
01365
01366 #if !defined(MONGOOSE_USE_EXTRA_HTTP_HEADERS)
01367 #define MONGOOSE_USE_EXTRA_HTTP_HEADERS ""
01368 #endif
01369
01370 #ifndef MONGOOSE_POST_SIZE_LIMIT
01371 #define MONGOOSE_POST_SIZE_LIMIT 0
01372 #endif
01373
01374 #ifndef MONGOOSE_IDLE_TIMEOUT_SECONDS
01375 #define MONGOOSE_IDLE_TIMEOUT_SECONDS 300
01376 #endif
01377
01378 #if defined(NS_DISABLE_SOCKETPAIR) && !defined(MONGOOSE_NO_CGI)
01379 #define MONGOOSE_NO_CGI
01380 #endif
01381
01382 #ifdef MONGOOSE_NO_FILESYSTEM
01383 #define MONGOOSE_NO_AUTH
01384 #if !defined(MONGOOSE_NO_CGI)
01385 #define MONGOOSE_NO_CGI
01386 #endif
01387 #define MONGOOSE_NO_DAV
01388 #define MONGOOSE_NO_DIRECTORY_LISTING
01389 #define MONGOOSE_NO_LOGGING
01390 #define MONGOOSE_NO_SSI
01391 #define MONGOOSE_NO_DL
01392 #endif
01393
01394 struct vec {
01395 const char *ptr;
01396 size_t len;
01397 };
01398
01399
01400 struct dir_entry {
01401 struct connection *conn;
01402 char *file_name;
01403 file_stat_t st;
01404 };
01405
01406
01407 enum {
01408 ACCESS_CONTROL_LIST,
01409 #ifndef MONGOOSE_NO_FILESYSTEM
01410 ACCESS_LOG_FILE,
01411 #ifndef MONGOOSE_NO_AUTH
01412 AUTH_DOMAIN,
01413 #endif
01414 #ifndef MONGOOSE_NO_CGI
01415 CGI_INTERPRETER,
01416 CGI_PATTERN,
01417 #endif
01418 DAV_AUTH_FILE,
01419 DAV_ROOT,
01420 DOCUMENT_ROOT,
01421 #ifndef MONGOOSE_NO_DIRECTORY_LISTING
01422 ENABLE_DIRECTORY_LISTING,
01423 #endif
01424 #endif
01425 ENABLE_PROXY,
01426 EXTRA_MIME_TYPES,
01427 #if !defined(MONGOOSE_NO_FILESYSTEM) && !defined(MONGOOSE_NO_AUTH)
01428 GLOBAL_AUTH_FILE,
01429 #endif
01430 #ifndef MONGOOSE_NO_FILESYSTEM
01431 HIDE_FILES_PATTERN,
01432 HEXDUMP_FILE,
01433 INDEX_FILES,
01434 #endif
01435 LISTENING_PORT,
01436 #ifndef _WIN32
01437 RUN_AS_USER,
01438 #endif
01439 #ifndef MONGOOSE_NO_SSI
01440 SSI_PATTERN,
01441 #endif
01442 URL_REWRITES,
01443 NUM_OPTIONS
01444 };
01445
01446 static const char *static_config_options[] = {
01447 "access_control_list", NULL,
01448 #ifndef MONGOOSE_NO_FILESYSTEM
01449 "access_log_file", NULL,
01450 #ifndef MONGOOSE_NO_AUTH
01451 "auth_domain", "mydomain.com",
01452 #endif
01453 #ifndef MONGOOSE_NO_CGI
01454 "cgi_interpreter", NULL,
01455 "cgi_pattern", DEFAULT_CGI_PATTERN,
01456 #endif
01457 "dav_auth_file", NULL,
01458 "dav_root", NULL,
01459 "document_root", NULL,
01460 #ifndef MONGOOSE_NO_DIRECTORY_LISTING
01461 "enable_directory_listing", "yes",
01462 #endif
01463 #endif
01464 "enable_proxy", NULL,
01465 "extra_mime_types", NULL,
01466 #if !defined(MONGOOSE_NO_FILESYSTEM) && !defined(MONGOOSE_NO_AUTH)
01467 "global_auth_file", NULL,
01468 #endif
01469 #ifndef MONGOOSE_NO_FILESYSTEM
01470 "hide_files_patterns", NULL,
01471 "hexdump_file", NULL,
01472 "index_files","index.html,index.htm,index.shtml,index.cgi,index.php",
01473 #endif
01474 "listening_port", NULL,
01475 #ifndef _WIN32
01476 "run_as_user", NULL,
01477 #endif
01478 #ifndef MONGOOSE_NO_SSI
01479 "ssi_pattern", "**.shtml$|**.shtm$",
01480 #endif
01481 "url_rewrites", NULL,
01482 NULL
01483 };
01484
01485 struct mg_server {
01486 struct ns_mgr ns_mgr;
01487 union socket_address lsa;
01488 mg_handler_t event_handler;
01489 char *config_options[NUM_OPTIONS];
01490 };
01491
01492
01493 union endpoint {
01494 int fd;
01495 struct ns_connection *nc;
01496 };
01497
01498 enum endpoint_type {
01499 EP_NONE, EP_FILE, EP_CGI, EP_USER, EP_PUT, EP_CLIENT, EP_PROXY
01500 };
01501
01502 #define MG_HEADERS_SENT NSF_USER_1
01503 #define MG_USING_CHUNKED_API NSF_USER_2
01504 #define MG_CGI_CONN NSF_USER_3
01505 #define MG_PROXY_CONN NSF_USER_4
01506 #define MG_PROXY_DONT_PARSE NSF_USER_5
01507
01508 struct connection {
01509 struct ns_connection *ns_conn;
01510 struct mg_connection mg_conn;
01511 struct mg_server *server;
01512 union endpoint endpoint;
01513 enum endpoint_type endpoint_type;
01514 char *path_info;
01515 char *request;
01516 int64_t num_bytes_recv;
01517 int64_t cl;
01518 ssize_t request_len;
01519 };
01520
01521 #define MG_CONN_2_CONN(c) ((struct connection *) ((char *) (c) - \
01522 offsetof(struct connection, mg_conn)))
01523
01524 static void open_local_endpoint(struct connection *conn, int skip_user);
01525 static void close_local_endpoint(struct connection *conn);
01526 static void mg_ev_handler(struct ns_connection *nc, int ev, void *p);
01527
01528 static const struct {
01529 const char *extension;
01530 size_t ext_len;
01531 const char *mime_type;
01532 } static_builtin_mime_types[] = {
01533 {".html", 5, "text/html"},
01534 {".htm", 4, "text/html"},
01535 {".shtm", 5, "text/html"},
01536 {".shtml", 6, "text/html"},
01537 {".css", 4, "text/css"},
01538 {".js", 3, "application/javascript"},
01539 {".ico", 4, "image/x-icon"},
01540 {".gif", 4, "image/gif"},
01541 {".jpg", 4, "image/jpeg"},
01542 {".jpeg", 5, "image/jpeg"},
01543 {".png", 4, "image/png"},
01544 {".svg", 4, "image/svg+xml"},
01545 {".txt", 4, "text/plain"},
01546 {".torrent", 8, "application/x-bittorrent"},
01547 {".wav", 4, "audio/x-wav"},
01548 {".mp3", 4, "audio/x-mp3"},
01549 {".mid", 4, "audio/mid"},
01550 {".m3u", 4, "audio/x-mpegurl"},
01551 {".ogg", 4, "application/ogg"},
01552 {".ram", 4, "audio/x-pn-realaudio"},
01553 {".xml", 4, "text/xml"},
01554 {".json", 5, "application/json"},
01555 {".xslt", 5, "application/xml"},
01556 {".xsl", 4, "application/xml"},
01557 {".ra", 3, "audio/x-pn-realaudio"},
01558 {".doc", 4, "application/msword"},
01559 {".exe", 4, "application/octet-stream"},
01560 {".zip", 4, "application/x-zip-compressed"},
01561 {".xls", 4, "application/excel"},
01562 {".tgz", 4, "application/x-tar-gz"},
01563 {".tar", 4, "application/x-tar"},
01564 {".gz", 3, "application/x-gunzip"},
01565 {".arj", 4, "application/x-arj-compressed"},
01566 {".rar", 4, "application/x-rar-compressed"},
01567 {".rtf", 4, "application/rtf"},
01568 {".pdf", 4, "application/pdf"},
01569 {".swf", 4, "application/x-shockwave-flash"},
01570 {".mpg", 4, "video/mpeg"},
01571 {".webm", 5, "video/webm"},
01572 {".mpeg", 5, "video/mpeg"},
01573 {".mov", 4, "video/quicktime"},
01574 {".mp4", 4, "video/mp4"},
01575 {".m4v", 4, "video/x-m4v"},
01576 {".asf", 4, "video/x-ms-asf"},
01577 {".avi", 4, "video/x-msvideo"},
01578 {".bmp", 4, "image/bmp"},
01579 {".ttf", 4, "application/x-font-ttf"},
01580 {NULL, 0, NULL}
01581 };
01582
01583 #ifdef MONGOOSE_ENABLE_THREADS
01584 void *mg_start_thread(void *(*f)(void *), void *p) {
01585 return ns_start_thread(f, p);
01586 }
01587 #endif // MONGOOSE_ENABLE_THREADS
01588
01589 #ifndef MONGOOSE_NO_MMAP
01590 #ifdef _WIN32
01591 static void *mmap(void *addr, int64_t len, int prot, int flags, int fd,
01592 int offset) {
01593 HANDLE fh = (HANDLE) _get_osfhandle(fd);
01594 HANDLE mh = CreateFileMapping(fh, 0, PAGE_READONLY, 0, 0, 0);
01595 void *p = MapViewOfFile(mh, FILE_MAP_READ, 0, 0, (size_t) len);
01596 CloseHandle(mh);
01597 return p;
01598 }
01599 #define munmap(x, y) UnmapViewOfFile(x)
01600 #define MAP_FAILED NULL
01601 #define MAP_PRIVATE 0
01602 #define PROT_READ 0
01603 #elif defined(__OS2__)
01604 static void *mmap(void *addr, int64_t len, int prot, int flags, int fd,
01605 int offset) {
01606 void *p;
01607
01608 int pos = lseek( fd, 0, SEEK_CUR );
01609
01610 if (pos == -1)
01611 return NULL;
01612
01613
01614 if (lseek( fd, offset, SEEK_SET) == -1)
01615 return NULL;
01616
01617 p = malloc(len);
01618
01619
01620 if (!p || read(fd, p, len) == -1) {
01621 free(p);
01622 p = NULL;
01623 }
01624
01625
01626 lseek(fd, pos, SEEK_SET);
01627
01628 return p;
01629 }
01630 #define munmap(x, y) free(x)
01631 #define MAP_FAILED NULL
01632 #define MAP_PRIVATE 0
01633 #define PROT_READ 0
01634 #else
01635 #include <sys/mman.h>
01636 #endif
01637
01638 void *mg_mmap(FILE *fp, size_t size) {
01639 void *p = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fileno(fp), 0);
01640 return p == MAP_FAILED ? NULL : p;
01641 }
01642
01643 void mg_munmap(void *p, size_t size) {
01644 munmap(p, size);
01645 }
01646 #endif // MONGOOSE_NO_MMAP
01647
01648 #if defined(_WIN32) && !defined(MONGOOSE_NO_FILESYSTEM)
01649
01650
01651 static void to_wchar(const char *path, wchar_t *wbuf, size_t wbuf_len) {
01652 char buf[MAX_PATH_SIZE * 2], buf2[MAX_PATH_SIZE * 2], *p;
01653
01654 strncpy(buf, path, sizeof(buf));
01655 buf[sizeof(buf) - 1] = '\0';
01656
01657
01658 p = buf + strlen(buf) - 1;
01659 while (p > buf && p[-1] != ':' && (p[0] == '\\' || p[0] == '/')) *p-- = '\0';
01660
01661
01662
01663 memset(wbuf, 0, wbuf_len * sizeof(wchar_t));
01664 MultiByteToWideChar(CP_UTF8, 0, buf, -1, wbuf, (int) wbuf_len);
01665 WideCharToMultiByte(CP_UTF8, 0, wbuf, (int) wbuf_len, buf2, sizeof(buf2),
01666 NULL, NULL);
01667 if (strcmp(buf, buf2) != 0) {
01668 wbuf[0] = L'\0';
01669 }
01670 }
01671
01672 static int mg_stat(const char *path, file_stat_t *st) {
01673 wchar_t wpath[MAX_PATH_SIZE];
01674 to_wchar(path, wpath, ARRAY_SIZE(wpath));
01675 DBG(("[%ls] -> %d", wpath, _wstati64(wpath, st)));
01676 return _wstati64(wpath, st);
01677 }
01678
01679 static FILE *mg_fopen(const char *path, const char *mode) {
01680 wchar_t wpath[MAX_PATH_SIZE], wmode[10];
01681 to_wchar(path, wpath, ARRAY_SIZE(wpath));
01682 to_wchar(mode, wmode, ARRAY_SIZE(wmode));
01683 return _wfopen(wpath, wmode);
01684 }
01685
01686 static int mg_open(const char *path, int flag, int mode) {
01687 wchar_t wpath[MAX_PATH_SIZE];
01688 to_wchar(path, wpath, ARRAY_SIZE(wpath));
01689 return _wopen(wpath, flag, mode);
01690 }
01691 #endif // _WIN32 && !MONGOOSE_NO_FILESYSTEM
01692
01693
01694
01695
01696
01697
01698
01699 static const char *next_option(const char *list, struct vec *val,
01700 struct vec *eq_val) {
01701 if (list == NULL || *list == '\0') {
01702
01703 list = NULL;
01704 } else {
01705 val->ptr = list;
01706 if ((list = strchr(val->ptr, ',')) != NULL) {
01707
01708 val->len = list - val->ptr;
01709 list++;
01710 } else {
01711
01712 list = val->ptr + strlen(val->ptr);
01713 val->len = list - val->ptr;
01714 }
01715
01716 if (eq_val != NULL) {
01717
01718
01719 eq_val->len = 0;
01720 eq_val->ptr = (const char *) memchr(val->ptr, '=', val->len);
01721 if (eq_val->ptr != NULL) {
01722 eq_val->ptr++;
01723 eq_val->len = val->ptr + val->len - eq_val->ptr;
01724 val->len = (eq_val->ptr - val->ptr) - 1;
01725 }
01726 }
01727 }
01728
01729 return list;
01730 }
01731
01732
01733
01734 static int mg_vsnprintf(char *buf, size_t buflen, const char *fmt, va_list ap) {
01735 int n;
01736 if (buflen < 1) return 0;
01737 n = vsnprintf(buf, buflen, fmt, ap);
01738 if (n < 0) {
01739 n = 0;
01740 } else if (n >= (int) buflen) {
01741 n = (int) buflen - 1;
01742 }
01743 buf[n] = '\0';
01744 return n;
01745 }
01746
01747 static int mg_snprintf(char *buf, size_t buflen, const char *fmt, ...) {
01748 va_list ap;
01749 int n;
01750 va_start(ap, fmt);
01751 n = mg_vsnprintf(buf, buflen, fmt, ap);
01752 va_end(ap);
01753 return n;
01754 }
01755
01756
01757
01758
01759
01760 static int get_request_len(const char *s, size_t buf_len) {
01761 const unsigned char *buf = (unsigned char *) s;
01762 size_t i;
01763
01764 for (i = 0; i < buf_len; i++) {
01765
01766
01767 if (!isprint(buf[i]) && buf[i] != '\r' && buf[i] != '\n' && buf[i] < 128) {
01768 return -1;
01769 } else if (buf[i] == '\n' && i + 1 < buf_len && buf[i + 1] == '\n') {
01770 return i + 2;
01771 } else if (buf[i] == '\n' && i + 2 < buf_len && buf[i + 1] == '\r' &&
01772 buf[i + 2] == '\n') {
01773 return i + 3;
01774 }
01775 }
01776
01777 return 0;
01778 }
01779
01780
01781
01782
01783 static char *skip(char **buf, const char *delimiters) {
01784 char *p, *begin_word, *end_word, *end_delimiters;
01785
01786 begin_word = *buf;
01787 end_word = begin_word + strcspn(begin_word, delimiters);
01788 end_delimiters = end_word + strspn(end_word, delimiters);
01789
01790 for (p = end_word; p < end_delimiters; p++) {
01791 *p = '\0';
01792 }
01793
01794 *buf = end_delimiters;
01795
01796 return begin_word;
01797 }
01798
01799
01800
01801 static void parse_http_headers(char **buf, struct mg_connection *ri) {
01802 size_t i;
01803
01804 for (i = 0; i < ARRAY_SIZE(ri->http_headers); i++) {
01805 ri->http_headers[i].name = skip(buf, ": ");
01806 ri->http_headers[i].value = skip(buf, "\r\n");
01807 if (ri->http_headers[i].name[0] == '\0')
01808 break;
01809 ri->num_headers = i + 1;
01810 }
01811 }
01812
01813 static const char *status_code_to_str(int status_code) {
01814 switch (status_code) {
01815
01816 case 100: return "Continue";
01817 case 101: return "Switching Protocols";
01818 case 102: return "Processing";
01819
01820 case 200: return "OK";
01821 case 201: return "Created";
01822 case 202: return "Accepted";
01823 case 203: return "Non-Authoritative Information";
01824 case 204: return "No Content";
01825 case 205: return "Reset Content";
01826 case 206: return "Partial Content";
01827 case 207: return "Multi-Status";
01828 case 208: return "Already Reported";
01829 case 226: return "IM Used";
01830
01831 case 300: return "Multiple Choices";
01832 case 301: return "Moved Permanently";
01833 case 302: return "Found";
01834 case 303: return "See Other";
01835 case 304: return "Not Modified";
01836 case 305: return "Use Proxy";
01837 case 306: return "Switch Proxy";
01838 case 307: return "Temporary Redirect";
01839 case 308: return "Permanent Redirect";
01840
01841 case 400: return "Bad Request";
01842 case 401: return "Unauthorized";
01843 case 402: return "Payment Required";
01844 case 403: return "Forbidden";
01845 case 404: return "Not Found";
01846 case 405: return "Method Not Allowed";
01847 case 406: return "Not Acceptable";
01848 case 407: return "Proxy Authentication Required";
01849 case 408: return "Request Timeout";
01850 case 409: return "Conflict";
01851 case 410: return "Gone";
01852 case 411: return "Length Required";
01853 case 412: return "Precondition Failed";
01854 case 413: return "Payload Too Large";
01855 case 414: return "URI Too Long";
01856 case 415: return "Unsupported Media Type";
01857 case 416: return "Requested Range Not Satisfiable";
01858 case 417: return "Expectation Failed";
01859 case 418: return "I\'m a teapot";
01860 case 422: return "Unprocessable Entity";
01861 case 423: return "Locked";
01862 case 424: return "Failed Dependency";
01863 case 426: return "Upgrade Required";
01864 case 428: return "Precondition Required";
01865 case 429: return "Too Many Requests";
01866 case 431: return "Request Header Fields Too Large";
01867 case 451: return "Unavailable For Legal Reasons";
01868
01869 case 500: return "Internal Server Error";
01870 case 501: return "Not Implemented";
01871 case 502: return "Bad Gateway";
01872 case 503: return "Service Unavailable";
01873 case 504: return "Gateway Timeout";
01874 case 505: return "HTTP Version Not Supported";
01875 case 506: return "Variant Also Negotiates";
01876 case 507: return "Insufficient Storage";
01877 case 508: return "Loop Detected";
01878 case 510: return "Not Extended";
01879 case 511: return "Network Authentication Required";
01880
01881 default: return "Server Error";
01882 }
01883 }
01884
01885 static int call_user(struct connection *conn, enum mg_event ev) {
01886 return conn != NULL && conn->server != NULL &&
01887 conn->server->event_handler != NULL ?
01888 conn->server->event_handler(&conn->mg_conn, ev) : MG_FALSE;
01889 }
01890
01891 static void send_http_error(struct connection *conn, int code,
01892 const char *fmt, ...) {
01893 const char *message = status_code_to_str(code);
01894 const char *rewrites = conn->server->config_options[URL_REWRITES];
01895 char headers[200], body[200];
01896 struct vec a, b;
01897 va_list ap;
01898 int body_len, headers_len, match_code;
01899
01900 conn->mg_conn.status_code = code;
01901
01902
01903 if (call_user(conn, MG_HTTP_ERROR) == MG_TRUE) {
01904 close_local_endpoint(conn);
01905 return;
01906 }
01907
01908
01909 while ((rewrites = next_option(rewrites, &a, &b)) != NULL) {
01910 if ((match_code = atoi(a.ptr)) > 0 && match_code == code) {
01911 struct mg_connection *c = &conn->mg_conn;
01912 c->status_code = 302;
01913 mg_printf(c, "HTTP/1.1 %d Moved\r\n"
01914 "Location: %.*s?code=%d&orig_uri=%s&query_string=%s\r\n\r\n",
01915 c->status_code, b.len, b.ptr, code, c->uri,
01916 c->query_string == NULL ? "" : c->query_string);
01917 close_local_endpoint(conn);
01918 return;
01919 }
01920 }
01921
01922 body_len = mg_snprintf(body, sizeof(body), "%d %s\n", code, message);
01923 if (fmt != NULL) {
01924 va_start(ap, fmt);
01925 body_len += mg_vsnprintf(body + body_len, sizeof(body) - body_len, fmt, ap);
01926 va_end(ap);
01927 }
01928 if ((code >= 300 && code <= 399) || code == 204) {
01929
01930 body_len = 0;
01931 }
01932 headers_len = mg_snprintf(headers, sizeof(headers),
01933 "HTTP/1.1 %d %s\r\nContent-Length: %d\r\n"
01934 "Content-Type: text/plain\r\n\r\n",
01935 code, message, body_len);
01936 ns_send(conn->ns_conn, headers, headers_len);
01937 ns_send(conn->ns_conn, body, body_len);
01938 close_local_endpoint(conn);
01939 }
01940
01941 static void write_chunk(struct connection *conn, const char *buf, int len) {
01942 char chunk_size[50];
01943 int n = mg_snprintf(chunk_size, sizeof(chunk_size), "%X\r\n", len);
01944 ns_send(conn->ns_conn, chunk_size, n);
01945 ns_send(conn->ns_conn, buf, len);
01946 ns_send(conn->ns_conn, "\r\n", 2);
01947 }
01948
01949 size_t mg_printf(struct mg_connection *conn, const char *fmt, ...) {
01950 struct connection *c = MG_CONN_2_CONN(conn);
01951 va_list ap;
01952
01953 va_start(ap, fmt);
01954 ns_vprintf(c->ns_conn, fmt, ap);
01955 va_end(ap);
01956
01957 return c->ns_conn->send_iobuf.len;
01958 }
01959
01960 static void ns_forward(struct ns_connection *from, struct ns_connection *to) {
01961 DBG(("%p -> %p %lu bytes", from, to, (unsigned long)from->recv_iobuf.len));
01962 ns_send(to, from->recv_iobuf.buf, from->recv_iobuf.len);
01963 iobuf_remove(&from->recv_iobuf, from->recv_iobuf.len);
01964 }
01965
01966 #ifndef MONGOOSE_NO_CGI
01967 #ifdef _WIN32
01968 struct threadparam {
01969 sock_t s;
01970 HANDLE hPipe;
01971 };
01972
01973 static int wait_until_ready(sock_t sock, int for_read) {
01974 fd_set set;
01975 FD_ZERO(&set);
01976 FD_SET(sock, &set);
01977 select(sock + 1, for_read ? &set : 0, for_read ? 0 : &set, 0, 0);
01978 return 1;
01979 }
01980
01981 static void *push_to_stdin(void *arg) {
01982 struct threadparam *tp = (struct threadparam *)arg;
01983 int n, sent, stop = 0;
01984 DWORD k;
01985 char buf[IOBUF_SIZE];
01986
01987 while (!stop && wait_until_ready(tp->s, 1) &&
01988 (n = recv(tp->s, buf, sizeof(buf), 0)) > 0) {
01989 if (n == -1 && GetLastError() == WSAEWOULDBLOCK) continue;
01990 for (sent = 0; !stop && sent < n; sent += k) {
01991 if (!WriteFile(tp->hPipe, buf + sent, n - sent, &k, 0)) stop = 1;
01992 }
01993 }
01994 DBG(("%s", "FORWARED EVERYTHING TO CGI"));
01995 CloseHandle(tp->hPipe);
01996 NS_FREE(tp);
01997 _endthread();
01998 return NULL;
01999 }
02000
02001 static void *pull_from_stdout(void *arg) {
02002 struct threadparam *tp = (struct threadparam *)arg;
02003 int k = 0, stop = 0;
02004 DWORD n, sent;
02005 char buf[IOBUF_SIZE];
02006
02007 while (!stop && ReadFile(tp->hPipe, buf, sizeof(buf), &n, NULL)) {
02008 for (sent = 0; !stop && sent < n; sent += k) {
02009 if (wait_until_ready(tp->s, 0) &&
02010 (k = send(tp->s, buf + sent, n - sent, 0)) <= 0) stop = 1;
02011 }
02012 }
02013 DBG(("%s", "EOF FROM CGI"));
02014 CloseHandle(tp->hPipe);
02015 shutdown(tp->s, 2);
02016 closesocket(tp->s);
02017 NS_FREE(tp);
02018 _endthread();
02019 return NULL;
02020 }
02021
02022 static void spawn_stdio_thread(sock_t sock, HANDLE hPipe,
02023 void *(*func)(void *)) {
02024 struct threadparam *tp = (struct threadparam *)NS_MALLOC(sizeof(*tp));
02025 if (tp != NULL) {
02026 tp->s = sock;
02027 tp->hPipe = hPipe;
02028 mg_start_thread(func, tp);
02029 }
02030 }
02031
02032 static void abs_path(const char *utf8_path, char *abs_path, size_t len) {
02033 wchar_t buf[MAX_PATH_SIZE], buf2[MAX_PATH_SIZE];
02034 to_wchar(utf8_path, buf, ARRAY_SIZE(buf));
02035 GetFullPathNameW(buf, ARRAY_SIZE(buf2), buf2, NULL);
02036 WideCharToMultiByte(CP_UTF8, 0, buf2, wcslen(buf2) + 1, abs_path, len, 0, 0);
02037 }
02038
02039 static process_id_t start_process(char *interp, const char *cmd,
02040 const char *env, const char *envp[],
02041 const char *dir, sock_t sock) {
02042 STARTUPINFOW si;
02043 PROCESS_INFORMATION pi;
02044 HANDLE a[2], b[2], me = GetCurrentProcess();
02045 wchar_t wcmd[MAX_PATH_SIZE], full_dir[MAX_PATH_SIZE];
02046 char buf[MAX_PATH_SIZE], buf4[MAX_PATH_SIZE], buf5[MAX_PATH_SIZE],
02047 cmdline[MAX_PATH_SIZE], *p;
02048 DWORD flags = DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS;
02049 FILE *fp;
02050
02051 memset(&si, 0, sizeof(si));
02052 memset(&pi, 0, sizeof(pi));
02053
02054 si.cb = sizeof(si);
02055 si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
02056 si.wShowWindow = SW_HIDE;
02057 si.hStdError = GetStdHandle(STD_ERROR_HANDLE);
02058
02059 CreatePipe(&a[0], &a[1], NULL, 0);
02060 CreatePipe(&b[0], &b[1], NULL, 0);
02061 DuplicateHandle(me, a[0], me, &si.hStdInput, 0, TRUE, flags);
02062 DuplicateHandle(me, b[1], me, &si.hStdOutput, 0, TRUE, flags);
02063
02064 if (interp == NULL && (fp = fopen(cmd, "r")) != NULL) {
02065 buf[0] = buf[1] = '\0';
02066 fgets(buf, sizeof(buf), fp);
02067 buf[sizeof(buf) - 1] = '\0';
02068 if (buf[0] == '#' && buf[1] == '!') {
02069 interp = buf + 2;
02070 for (p = interp + strlen(interp) - 1;
02071 isspace(* (uint8_t *) p) && p > interp; p--) *p = '\0';
02072 }
02073 fclose(fp);
02074 }
02075
02076 if (interp != NULL) {
02077 abs_path(interp, buf4, ARRAY_SIZE(buf4));
02078 interp = buf4;
02079 }
02080 abs_path(dir, buf5, ARRAY_SIZE(buf5));
02081 to_wchar(dir, full_dir, ARRAY_SIZE(full_dir));
02082 mg_snprintf(cmdline, sizeof(cmdline), "%s%s\"%s\"",
02083 interp ? interp : "", interp ? " " : "", cmd);
02084 to_wchar(cmdline, wcmd, ARRAY_SIZE(wcmd));
02085
02086 if (CreateProcessW(NULL, wcmd, NULL, NULL, TRUE, CREATE_NEW_PROCESS_GROUP,
02087 (void *) env, full_dir, &si, &pi) != 0) {
02088 spawn_stdio_thread(sock, a[1], push_to_stdin);
02089 spawn_stdio_thread(sock, b[0], pull_from_stdout);
02090 } else {
02091 CloseHandle(a[1]);
02092 CloseHandle(b[0]);
02093 closesocket(sock);
02094 }
02095 DBG(("CGI command: [%ls] -> %p", wcmd, pi.hProcess));
02096
02097
02098 CloseHandle(si.hStdOutput);
02099 CloseHandle(si.hStdInput);
02100
02101
02102
02103 return pi.hProcess;
02104 }
02105 #else
02106 static process_id_t start_process(const char *interp, const char *cmd,
02107 const char *env, const char *envp[],
02108 const char *dir, sock_t sock) {
02109 char buf[500];
02110 process_id_t pid = fork();
02111 (void) env;
02112
02113 if (pid == 0) {
02114 (void) chdir(dir);
02115 (void) dup2(sock, 0);
02116 (void) dup2(sock, 1);
02117 closesocket(sock);
02118
02119
02120
02121
02122
02123 signal(SIGCHLD, SIG_DFL);
02124
02125 if (interp == NULL) {
02126 execle(cmd, cmd, (char *) 0, envp);
02127 } else {
02128 execle(interp, interp, cmd, (char *) 0, envp);
02129 }
02130 snprintf(buf, sizeof(buf), "Status: 500\r\n\r\n"
02131 "500 Server Error: %s%s%s: %s", interp == NULL ? "" : interp,
02132 interp == NULL ? "" : " ", cmd, strerror(errno));
02133 send(1, buf, strlen(buf), 0);
02134 exit(EXIT_FAILURE);
02135 }
02136
02137 return pid;
02138 }
02139 #endif // _WIN32
02140
02141
02142
02143
02144
02145
02146
02147
02148
02149 struct cgi_env_block {
02150 struct mg_connection *conn;
02151 char buf[CGI_ENVIRONMENT_SIZE];
02152 const char *vars[MAX_CGI_ENVIR_VARS];
02153 int len;
02154 int nvars;
02155 };
02156
02157
02158
02159 static char *addenv(struct cgi_env_block *block, const char *fmt, ...) {
02160 int n, space;
02161 char *added;
02162 va_list ap;
02163
02164
02165 space = sizeof(block->buf) - block->len - 2;
02166 assert(space >= 0);
02167
02168
02169 added = block->buf + block->len;
02170
02171
02172 va_start(ap, fmt);
02173 n = mg_vsnprintf(added, (size_t) space, fmt, ap);
02174 va_end(ap);
02175
02176
02177 if (n > 0 && n + 1 < space &&
02178 block->nvars < (int) ARRAY_SIZE(block->vars) - 2) {
02179
02180 block->vars[block->nvars++] = added;
02181
02182 block->len += n + 1;
02183 }
02184
02185 return added;
02186 }
02187
02188 static void addenv2(struct cgi_env_block *blk, const char *name) {
02189 const char *s;
02190 if ((s = getenv(name)) != NULL) addenv(blk, "%s=%s", name, s);
02191 }
02192
02193 static void prepare_cgi_environment(struct connection *conn,
02194 const char *prog,
02195 struct cgi_env_block *blk) {
02196 struct mg_connection *ri = &conn->mg_conn;
02197 const char *s, *slash;
02198 char *p, **opts = conn->server->config_options;
02199 int i;
02200
02201 blk->len = blk->nvars = 0;
02202 blk->conn = ri;
02203
02204 if ((s = getenv("SERVER_NAME")) != NULL) {
02205 addenv(blk, "SERVER_NAME=%s", s);
02206 } else {
02207 addenv(blk, "SERVER_NAME=%s", ri->local_ip);
02208 }
02209 addenv(blk, "SERVER_ROOT=%s", opts[DOCUMENT_ROOT]);
02210 addenv(blk, "DOCUMENT_ROOT=%s", opts[DOCUMENT_ROOT]);
02211 addenv(blk, "SERVER_SOFTWARE=%s/%s", "Mongoose", MONGOOSE_VERSION);
02212
02213
02214 addenv(blk, "%s", "GATEWAY_INTERFACE=CGI/1.1");
02215 addenv(blk, "%s", "SERVER_PROTOCOL=HTTP/1.1");
02216 addenv(blk, "%s", "REDIRECT_STATUS=200");
02217
02218
02219
02220
02221 addenv(blk, "REQUEST_METHOD=%s", ri->request_method);
02222 addenv(blk, "REMOTE_ADDR=%s", ri->remote_ip);
02223 addenv(blk, "REMOTE_PORT=%d", ri->remote_port);
02224 addenv(blk, "REQUEST_URI=%s%s%s", ri->uri,
02225 ri->query_string == NULL ? "" : "?",
02226 ri->query_string == NULL ? "" : ri->query_string);
02227
02228
02229 if (conn->path_info != NULL) {
02230 addenv(blk, "SCRIPT_NAME=%.*s",
02231 (int) (strlen(ri->uri) - strlen(conn->path_info)), ri->uri);
02232 addenv(blk, "PATH_INFO=%s", conn->path_info);
02233 } else {
02234 s = strrchr(prog, '/');
02235 slash = strrchr(ri->uri, '/');
02236 addenv(blk, "SCRIPT_NAME=%.*s%s",
02237 slash == NULL ? 0 : (int) (slash - ri->uri), ri->uri,
02238 s == NULL ? prog : s);
02239 }
02240
02241 addenv(blk, "SCRIPT_FILENAME=%s", prog);
02242 addenv(blk, "PATH_TRANSLATED=%s", prog);
02243 addenv(blk, "HTTPS=%s", conn->ns_conn->ssl != NULL ? "on" : "off");
02244
02245 if ((s = mg_get_header(ri, "Content-Type")) != NULL)
02246 addenv(blk, "CONTENT_TYPE=%s", s);
02247
02248 if (ri->query_string != NULL)
02249 addenv(blk, "QUERY_STRING=%s", ri->query_string);
02250
02251 if ((s = mg_get_header(ri, "Content-Length")) != NULL)
02252 addenv(blk, "CONTENT_LENGTH=%s", s);
02253
02254 addenv2(blk, "PATH");
02255 addenv2(blk, "TMP");
02256 addenv2(blk, "TEMP");
02257 addenv2(blk, "TMPDIR");
02258 addenv2(blk, "PERLLIB");
02259 addenv2(blk, ENV_EXPORT_TO_CGI);
02260
02261 #if defined(_WIN32)
02262 addenv2(blk, "COMSPEC");
02263 addenv2(blk, "SYSTEMROOT");
02264 addenv2(blk, "SystemDrive");
02265 addenv2(blk, "ProgramFiles");
02266 addenv2(blk, "ProgramFiles(x86)");
02267 addenv2(blk, "CommonProgramFiles(x86)");
02268 #else
02269 addenv2(blk, "LD_LIBRARY_PATH");
02270 #endif // _WIN32
02271
02272
02273 for (i = 0; i < ri->num_headers; i++) {
02274 p = addenv(blk, "HTTP_%s=%s",
02275 ri->http_headers[i].name, ri->http_headers[i].value);
02276
02277
02278 for (; *p != '=' && *p != '\0'; p++) {
02279 if (*p == '-')
02280 *p = '_';
02281 *p = (char) toupper(* (unsigned char *) p);
02282 }
02283 }
02284
02285 blk->vars[blk->nvars++] = NULL;
02286 blk->buf[blk->len++] = '\0';
02287
02288 assert(blk->nvars < (int) ARRAY_SIZE(blk->vars));
02289 assert(blk->len > 0);
02290 assert(blk->len < (int) sizeof(blk->buf));
02291 }
02292
02293 static const char cgi_status[] = "HTTP/1.1 200 OK\r\n";
02294
02295 static void open_cgi_endpoint(struct connection *conn, const char *prog) {
02296 struct cgi_env_block blk;
02297 char dir[MAX_PATH_SIZE];
02298 const char *p;
02299 sock_t fds[2];
02300
02301 prepare_cgi_environment(conn, prog, &blk);
02302
02303
02304
02305 if ((p = strrchr(prog, '/')) == NULL) {
02306 mg_snprintf(dir, sizeof(dir), "%s", ".");
02307 } else {
02308 mg_snprintf(dir, sizeof(dir), "%.*s", (int) (p - prog), prog);
02309 }
02310
02311
02312
02313
02314 do {
02315 ns_socketpair(fds);
02316 } while (fds[0] == INVALID_SOCKET);
02317
02318 if (start_process(conn->server->config_options[CGI_INTERPRETER],
02319 prog, blk.buf, blk.vars, dir, fds[1]) != 0) {
02320 conn->endpoint_type = EP_CGI;
02321 conn->endpoint.nc = ns_add_sock(&conn->server->ns_mgr, fds[0],
02322 mg_ev_handler, conn);
02323 conn->endpoint.nc->flags |= MG_CGI_CONN;
02324 ns_send(conn->ns_conn, cgi_status, sizeof(cgi_status) - 1);
02325 conn->mg_conn.status_code = 200;
02326 conn->ns_conn->flags |= NSF_BUFFER_BUT_DONT_SEND;
02327
02328 conn->endpoint.nc->send_iobuf = conn->ns_conn->recv_iobuf;
02329 iobuf_init(&conn->ns_conn->recv_iobuf, 0);
02330 } else {
02331 closesocket(fds[0]);
02332 send_http_error(conn, 500, "start_process(%s) failed", prog);
02333 }
02334
02335 #ifndef _WIN32
02336 closesocket(fds[1]);
02337 #endif
02338 }
02339
02340 static void on_cgi_data(struct ns_connection *nc) {
02341 struct connection *conn = (struct connection *) nc->user_data;
02342 const char *status = "500";
02343 struct mg_connection c;
02344
02345 if (!conn) return;
02346
02347
02348 ns_forward(nc, conn->ns_conn);
02349
02350
02351 if (conn->ns_conn->flags & NSF_BUFFER_BUT_DONT_SEND) {
02352 struct iobuf *io = &conn->ns_conn->send_iobuf;
02353 size_t s_len = sizeof(cgi_status) - 1;
02354 int len = get_request_len(io->buf + s_len, io->len - s_len);
02355 char buf[MAX_REQUEST_SIZE], *s = buf;
02356
02357 if (len == 0) return;
02358
02359 if (len < 0 || len > (int) sizeof(buf)) {
02360 len = io->len;
02361 iobuf_remove(io, io->len);
02362 send_http_error(conn, 500, "CGI program sent malformed headers: [%.*s]",
02363 len, io->buf);
02364 } else {
02365 memset(&c, 0, sizeof(c));
02366 memcpy(buf, io->buf + s_len, len);
02367 buf[len - 1] = '\0';
02368 parse_http_headers(&s, &c);
02369 if (mg_get_header(&c, "Location") != NULL) {
02370 status = "302";
02371 } else if ((status = (char *) mg_get_header(&c, "Status")) == NULL) {
02372 status = "200";
02373 }
02374 memcpy(io->buf + 9, status, 3);
02375 conn->mg_conn.status_code = atoi(status);
02376 }
02377 conn->ns_conn->flags &= ~NSF_BUFFER_BUT_DONT_SEND;
02378 }
02379 }
02380 #endif // !MONGOOSE_NO_CGI
02381
02382 static char *mg_strdup(const char *str) {
02383 char *copy = (char *) NS_MALLOC(strlen(str) + 1);
02384 if (copy != NULL) {
02385 strcpy(copy, str);
02386 }
02387 return copy;
02388 }
02389
02390 static int isbyte(int n) {
02391 return n >= 0 && n <= 255;
02392 }
02393
02394 static int parse_net(const char *spec, uint32_t *net, uint32_t *mask) {
02395 int n, a, b, c, d, slash = 32, len = 0;
02396
02397 if ((sscanf(spec, "%d.%d.%d.%d/%d%n", &a, &b, &c, &d, &slash, &n) == 5 ||
02398 sscanf(spec, "%d.%d.%d.%d%n", &a, &b, &c, &d, &n) == 4) &&
02399 isbyte(a) && isbyte(b) && isbyte(c) && isbyte(d) &&
02400 slash >= 0 && slash < 33) {
02401 len = n;
02402 *net = ((uint32_t)a << 24) | ((uint32_t)b << 16) | ((uint32_t)c << 8) | d;
02403 *mask = slash ? 0xffffffffU << (32 - slash) : 0;
02404 }
02405
02406 return len;
02407 }
02408
02409
02410
02411 static int check_acl(const char *acl, uint32_t remote_ip) {
02412 int allowed, flag;
02413 uint32_t net, mask;
02414 struct vec vec;
02415
02416
02417 allowed = acl == NULL ? '+' : '-';
02418
02419 while ((acl = next_option(acl, &vec, NULL)) != NULL) {
02420 flag = vec.ptr[0];
02421 if ((flag != '+' && flag != '-') ||
02422 parse_net(&vec.ptr[1], &net, &mask) == 0) {
02423 return -1;
02424 }
02425
02426 if (net == (remote_ip & mask)) {
02427 allowed = flag;
02428 }
02429 }
02430
02431 return allowed == '+';
02432 }
02433
02434
02435
02436 static void remove_double_dots_and_double_slashes(char *s) {
02437 char *p = s;
02438
02439 while (*s != '\0') {
02440 *p++ = *s++;
02441 if (s[-1] == '/' || s[-1] == '\\') {
02442
02443 while (s[0] != '\0') {
02444 if (s[0] == '/' || s[0] == '\\') { s++; }
02445 else if (s[0] == '.' && (s[1] == '/' || s[1] == '\\')) { s += 2; }
02446 else if (s[0] == '.' && s[1] == '.' && s[2] == '\0') { s += 2; }
02447 else if (s[0] == '.' && s[1] == '.' && (s[2] == '/' || s[2] == '\\')) { s += 3; }
02448 else { break; }
02449 }
02450 }
02451 }
02452 *p = '\0';
02453 }
02454
02455 int mg_url_decode(const char *src, size_t src_len, char *dst,
02456 size_t dst_len, int is_form_url_encoded) {
02457 size_t i, j = 0;
02458 int a, b;
02459 #define HEXTOI(x) (isdigit(x) ? (x) - '0' : (x) - 'W')
02460
02461 for (i = j = 0; i < src_len && j < dst_len - 1; i++, j++) {
02462 if (src[i] == '%' && i + 2 < src_len &&
02463 isxdigit(* (const unsigned char *) (src + i + 1)) &&
02464 isxdigit(* (const unsigned char *) (src + i + 2))) {
02465 a = tolower(* (const unsigned char *) (src + i + 1));
02466 b = tolower(* (const unsigned char *) (src + i + 2));
02467 dst[j] = (char) ((HEXTOI(a) << 4) | HEXTOI(b));
02468 i += 2;
02469 } else if (is_form_url_encoded && src[i] == '+') {
02470 dst[j] = ' ';
02471 } else {
02472 dst[j] = src[i];
02473 }
02474 }
02475
02476 dst[j] = '\0';
02477
02478 return i >= src_len ? j : -1;
02479 }
02480
02481 static int is_valid_http_method(const char *s) {
02482 return !strcmp(s, "GET") || !strcmp(s, "POST") || !strcmp(s, "HEAD") ||
02483 !strcmp(s, "CONNECT") || !strcmp(s, "PUT") || !strcmp(s, "DELETE") ||
02484 !strcmp(s, "OPTIONS") || !strcmp(s, "PROPFIND") || !strcmp(s, "MKCOL") ||
02485 !strcmp(s, "PATCH");
02486 }
02487
02488
02489
02490
02491
02492 static size_t parse_http_message(char *buf, size_t len,
02493 struct mg_connection *ri) {
02494 int is_request, n;
02495
02496
02497
02498 ri->request_method = ri->uri = ri->http_version = ri->query_string = NULL;
02499 ri->num_headers = ri->status_code = ri->is_websocket = ri->content_len = 0;
02500
02501 if (len < 1) return ~0;
02502
02503 buf[len - 1] = '\0';
02504
02505
02506 while (*buf != '\0' && isspace(* (unsigned char *) buf)) {
02507 buf++;
02508 }
02509 ri->request_method = skip(&buf, " ");
02510 ri->uri = skip(&buf, " ");
02511 ri->http_version = skip(&buf, "\r\n");
02512
02513
02514
02515 is_request = is_valid_http_method(ri->request_method);
02516 if ((is_request && memcmp(ri->http_version, "HTTP/", 5) != 0) ||
02517 (!is_request && memcmp(ri->request_method, "HTTP/", 5) != 0)) {
02518 len = ~0;
02519 } else {
02520 if (is_request) {
02521 ri->http_version += 5;
02522 } else {
02523 ri->status_code = atoi(ri->uri);
02524 }
02525 parse_http_headers(&buf, ri);
02526
02527 if ((ri->query_string = strchr(ri->uri, '?')) != NULL) {
02528 *(char *) ri->query_string++ = '\0';
02529 }
02530 n = (int) strlen(ri->uri);
02531 mg_url_decode(ri->uri, n, (char *) ri->uri, n + 1, 0);
02532 if (*ri->uri == '/' || *ri->uri == '.') {
02533 remove_double_dots_and_double_slashes((char *) ri->uri);
02534 }
02535 }
02536
02537 return len;
02538 }
02539
02540 static int lowercase(const char *s) {
02541 return tolower(* (const unsigned char *) s);
02542 }
02543
02544 static int mg_strcasecmp(const char *s1, const char *s2) {
02545 int diff;
02546
02547 do {
02548 diff = lowercase(s1++) - lowercase(s2++);
02549 } while (diff == 0 && s1[-1] != '\0');
02550
02551 return diff;
02552 }
02553
02554 static int mg_strncasecmp(const char *s1, const char *s2, size_t len) {
02555 int diff = 0;
02556
02557 if (len > 0)
02558 do {
02559 diff = lowercase(s1++) - lowercase(s2++);
02560 } while (diff == 0 && s1[-1] != '\0' && --len > 0);
02561
02562 return diff;
02563 }
02564
02565
02566 const char *mg_get_header(const struct mg_connection *ri, const char *s) {
02567 int i;
02568
02569 for (i = 0; i < ri->num_headers; i++)
02570 if (!mg_strcasecmp(s, ri->http_headers[i].name))
02571 return ri->http_headers[i].value;
02572
02573 return NULL;
02574 }
02575
02576
02577 int mg_match_prefix(const char *pattern, ssize_t pattern_len, const char *str) {
02578 const char *or_str;
02579 int len, res, i = 0, j = 0;
02580
02581 if ((or_str = (const char *) memchr(pattern, '|', pattern_len)) != NULL) {
02582 res = mg_match_prefix(pattern, or_str - pattern, str);
02583 return res > 0 ? res : mg_match_prefix(or_str + 1,
02584 (pattern + pattern_len) - (or_str + 1), str);
02585 }
02586
02587 for (; i < pattern_len; i++, j++) {
02588 if (pattern[i] == '?' && str[j] != '\0') {
02589 continue;
02590 } else if (pattern[i] == '$') {
02591 return str[j] == '\0' ? j : -1;
02592 } else if (pattern[i] == '*') {
02593 i++;
02594 if (pattern[i] == '*') {
02595 i++;
02596 len = (int) strlen(str + j);
02597 } else {
02598 len = (int) strcspn(str + j, "/");
02599 }
02600 if (i == pattern_len) {
02601 return j + len;
02602 }
02603 do {
02604 res = mg_match_prefix(pattern + i, pattern_len - i, str + j + len);
02605 } while (res == -1 && len-- > 0);
02606 return res == -1 ? -1 : j + res + len;
02607 } else if (lowercase(&pattern[i]) != lowercase(&str[j])) {
02608 return -1;
02609 }
02610 }
02611 return j;
02612 }
02613
02614
02615
02616
02617
02618 void mg_template(struct mg_connection *conn, const char *s,
02619 struct mg_expansion *expansions) {
02620 int i, j, pos = 0, inside_marker = 0;
02621
02622 for (i = 0; s[i] != '\0'; i++) {
02623 if (inside_marker == 0 && !memcmp(&s[i], "{{", 2)) {
02624 if (i > pos) {
02625 mg_send_data(conn, &s[pos], i - pos);
02626 }
02627 pos = i;
02628 inside_marker = 1;
02629 }
02630 if (inside_marker == 1 && !memcmp(&s[i], "}}", 2)) {
02631 for (j = 0; expansions[j].keyword != NULL; j++) {
02632 const char *kw = expansions[j].keyword;
02633 if ((int) strlen(kw) == i - (pos + 2) &&
02634 memcmp(kw, &s[pos + 2], i - (pos + 2)) == 0) {
02635 expansions[j].handler(conn);
02636 pos = i + 2;
02637 break;
02638 }
02639 }
02640 inside_marker = 0;
02641 }
02642 }
02643 if (i > pos) {
02644 mg_send_data(conn, &s[pos], i - pos);
02645 }
02646 }
02647
02648 #ifndef MONGOOSE_NO_FILESYSTEM
02649 static int is_dav_request(const struct connection *conn) {
02650 const char *s = conn->mg_conn.request_method;
02651 return !strcmp(s, "PUT") || !strcmp(s, "DELETE") ||
02652 !strcmp(s, "MKCOL") || !strcmp(s, "PROPFIND");
02653 }
02654
02655 static int must_hide_file(struct connection *conn, const char *path) {
02656 const char *pw_pattern = "**" PASSWORDS_FILE_NAME "$";
02657 const char *pattern = conn->server->config_options[HIDE_FILES_PATTERN];
02658 return mg_match_prefix(pw_pattern, strlen(pw_pattern), path) > 0 ||
02659 (pattern != NULL && mg_match_prefix(pattern, strlen(pattern), path) > 0);
02660 }
02661
02662
02663 static int convert_uri_to_file_name(struct connection *conn, char *buf,
02664 size_t buf_len, file_stat_t *st) {
02665 struct vec a, b;
02666 const char *rewrites = conn->server->config_options[URL_REWRITES];
02667 const char *root =
02668 #ifndef MONGOOSE_NO_DAV
02669 is_dav_request(conn) && conn->server->config_options[DAV_ROOT] != NULL ?
02670 conn->server->config_options[DAV_ROOT] :
02671 #endif
02672 conn->server->config_options[DOCUMENT_ROOT];
02673 #ifndef MONGOOSE_NO_CGI
02674 const char *cgi_pat = conn->server->config_options[CGI_PATTERN];
02675 char *p;
02676 #endif
02677 const char *uri = conn->mg_conn.uri;
02678 const char *domain = mg_get_header(&conn->mg_conn, "Host");
02679 size_t match_len, root_len = root == NULL ? 0 : strlen(root);
02680
02681
02682 if (rewrites != NULL && domain != NULL) {
02683 const char *colon = strchr(domain, ':');
02684 size_t domain_len = colon == NULL ? strlen(domain) : colon - domain;
02685
02686 while ((rewrites = next_option(rewrites, &a, &b)) != NULL) {
02687 if (a.len > 1 && a.ptr[0] == '@' && a.len == domain_len + 1 &&
02688 mg_strncasecmp(a.ptr + 1, domain, domain_len) == 0) {
02689 root = b.ptr;
02690 root_len = b.len;
02691 break;
02692 }
02693 }
02694 }
02695
02696
02697 if (root == NULL || root_len == 0) return 0;
02698
02699
02700 mg_snprintf(buf, buf_len, "%.*s%s", root_len, root, uri);
02701 rewrites = conn->server->config_options[URL_REWRITES];
02702 while ((rewrites = next_option(rewrites, &a, &b)) != NULL) {
02703 if ((match_len = mg_match_prefix(a.ptr, a.len, uri)) > 0) {
02704 mg_snprintf(buf, buf_len, "%.*s%s", (int) b.len, b.ptr, uri + match_len);
02705 break;
02706 }
02707 }
02708
02709 if (stat(buf, st) == 0) return 1;
02710
02711 #ifndef MONGOOSE_NO_CGI
02712
02713 for (p = buf + strlen(root) + 2; *p != '\0'; p++) {
02714 if (*p == '/') {
02715 *p = '\0';
02716 if (mg_match_prefix(cgi_pat, strlen(cgi_pat), buf) > 0 &&
02717 !stat(buf, st)) {
02718 DBG(("!!!! [%s]", buf));
02719 *p = '/';
02720 conn->path_info = mg_strdup(p);
02721 *p = '\0';
02722 return 1;
02723 }
02724 *p = '/';
02725 }
02726 }
02727 #endif
02728
02729 return 0;
02730 }
02731 #endif // MONGOOSE_NO_FILESYSTEM
02732
02733 static int should_keep_alive(const struct mg_connection *conn) {
02734 struct connection *c = MG_CONN_2_CONN(conn);
02735 const char *method = conn->request_method;
02736 const char *http_version = conn->http_version;
02737 const char *header = mg_get_header(conn, "Connection");
02738 return method != NULL &&
02739 (!strcmp(method, "GET") || c->endpoint_type == EP_USER) &&
02740 ((header != NULL && !mg_strcasecmp(header, "keep-alive")) ||
02741 (header == NULL && http_version && !strcmp(http_version, "1.1")));
02742 }
02743
02744 size_t mg_write(struct mg_connection *c, const void *buf, size_t len) {
02745 struct connection *conn = MG_CONN_2_CONN(c);
02746 ns_send(conn->ns_conn, buf, len);
02747 return conn->ns_conn->send_iobuf.len;
02748 }
02749
02750 void mg_send_status(struct mg_connection *c, int status) {
02751 struct connection *conn = MG_CONN_2_CONN(c);
02752 if (c->status_code == 0) {
02753 c->status_code = status;
02754 mg_printf(c, "HTTP/1.1 %d %s\r\n", status, status_code_to_str(status));
02755 }
02756 conn->ns_conn->flags |= MG_USING_CHUNKED_API;
02757 }
02758
02759 void mg_send_header(struct mg_connection *c, const char *name, const char *v) {
02760 struct connection *conn = MG_CONN_2_CONN(c);
02761 if (c->status_code == 0) {
02762 c->status_code = 200;
02763 mg_printf(c, "HTTP/1.1 %d %s\r\n", 200, status_code_to_str(200));
02764 }
02765 mg_printf(c, "%s: %s\r\n", name, v);
02766 conn->ns_conn->flags |= MG_USING_CHUNKED_API;
02767 }
02768
02769 static void terminate_headers(struct mg_connection *c) {
02770 struct connection *conn = MG_CONN_2_CONN(c);
02771 if (!(conn->ns_conn->flags & MG_HEADERS_SENT)) {
02772 mg_send_header(c, "Transfer-Encoding", "chunked");
02773 mg_write(c, "\r\n", 2);
02774 conn->ns_conn->flags |= MG_HEADERS_SENT;
02775 }
02776 }
02777
02778 size_t mg_send_data(struct mg_connection *c, const void *data, int data_len) {
02779 struct connection *conn = MG_CONN_2_CONN(c);
02780 terminate_headers(c);
02781 write_chunk(MG_CONN_2_CONN(c), (const char *) data, data_len);
02782 return conn->ns_conn->send_iobuf.len;
02783 }
02784
02785 size_t mg_printf_data(struct mg_connection *c, const char *fmt, ...) {
02786 struct connection *conn = MG_CONN_2_CONN(c);
02787 va_list ap;
02788 int len;
02789 char mem[IOBUF_SIZE], *buf = mem;
02790
02791 terminate_headers(c);
02792
02793 va_start(ap, fmt);
02794 len = ns_avprintf(&buf, sizeof(mem), fmt, ap);
02795 va_end(ap);
02796
02797 if (len >= 0) {
02798 write_chunk((struct connection *) conn, buf, len);
02799 }
02800 if (buf != mem && buf != NULL) {
02801 NS_FREE(buf);
02802 }
02803 return conn->ns_conn->send_iobuf.len;
02804 }
02805
02806 #if !defined(MONGOOSE_NO_WEBSOCKET) || !defined(MONGOOSE_NO_AUTH)
02807 static int is_big_endian(void) {
02808 static const int n = 1;
02809 return ((char *) &n)[0] == 0;
02810 }
02811 #endif
02812
02813 #ifndef MONGOOSE_NO_WEBSOCKET
02814
02815
02816 #define SHA1HANDSOFF
02817 #if defined(__sun)
02818 #include "solarisfixes.h"
02819 #endif
02820
02821 union char64long16 { unsigned char c[64]; uint32_t l[16]; };
02822
02823 #define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits))))
02824
02825 static uint32_t blk0(union char64long16 *block, int i) {
02826
02827 if (!is_big_endian()) {
02828 block->l[i] = (rol(block->l[i], 24) & 0xFF00FF00) |
02829 (rol(block->l[i], 8) & 0x00FF00FF);
02830 }
02831 return block->l[i];
02832 }
02833
02834
02835 #undef blk
02836 #undef R0
02837 #undef R1
02838 #undef R2
02839 #undef R3
02840 #undef R4
02841
02842 #define blk(i) (block->l[i&15] = rol(block->l[(i+13)&15]^block->l[(i+8)&15] \
02843 ^block->l[(i+2)&15]^block->l[i&15],1))
02844 #define R0(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk0(block, i)+0x5A827999+rol(v,5);w=rol(w,30);
02845 #define R1(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5);w=rol(w,30);
02846 #define R2(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=rol(w,30);
02847 #define R3(v,w,x,y,z,i) z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=rol(w,30);
02848 #define R4(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=rol(w,30);
02849
02850 typedef struct {
02851 uint32_t state[5];
02852 uint32_t count[2];
02853 unsigned char buffer[64];
02854 } SHA1_CTX;
02855
02856 static void SHA1Transform(uint32_t state[5], const unsigned char buffer[64]) {
02857 uint32_t a, b, c, d, e;
02858 union char64long16 block[1];
02859
02860 memcpy(block, buffer, 64);
02861 a = state[0];
02862 b = state[1];
02863 c = state[2];
02864 d = state[3];
02865 e = state[4];
02866 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);
02867 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);
02868 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);
02869 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);
02870 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);
02871 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);
02872 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);
02873 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);
02874 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);
02875 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);
02876 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);
02877 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);
02878 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);
02879 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);
02880 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);
02881 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);
02882 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);
02883 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);
02884 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);
02885 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);
02886 state[0] += a;
02887 state[1] += b;
02888 state[2] += c;
02889 state[3] += d;
02890 state[4] += e;
02891
02892
02893 memset(block, 0, sizeof(block));
02894 a = b = c = d = e = 0;
02895 (void) a; (void) b; (void) c; (void) d; (void) e;
02896 }
02897
02898 static void SHA1Init(SHA1_CTX *context) {
02899 context->state[0] = 0x67452301;
02900 context->state[1] = 0xEFCDAB89;
02901 context->state[2] = 0x98BADCFE;
02902 context->state[3] = 0x10325476;
02903 context->state[4] = 0xC3D2E1F0;
02904 context->count[0] = context->count[1] = 0;
02905 }
02906
02907 static void SHA1Update(SHA1_CTX *context, const unsigned char *data,
02908 size_t len) {
02909 size_t i, j;
02910
02911 j = context->count[0];
02912 if ((context->count[0] += len << 3) < j)
02913 context->count[1]++;
02914 context->count[1] += (len>>29);
02915 j = (j >> 3) & 63;
02916 if ((j + len) > 63) {
02917 memcpy(&context->buffer[j], data, (i = 64-j));
02918 SHA1Transform(context->state, context->buffer);
02919 for ( ; i + 63 < len; i += 64) {
02920 SHA1Transform(context->state, &data[i]);
02921 }
02922 j = 0;
02923 }
02924 else i = 0;
02925 memcpy(&context->buffer[j], &data[i], len - i);
02926 }
02927
02928 static void SHA1Final(unsigned char digest[20], SHA1_CTX *context) {
02929 unsigned i;
02930 unsigned char finalcount[8], c;
02931
02932 for (i = 0; i < 8; i++) {
02933 finalcount[i] = (unsigned char)((context->count[(i >= 4 ? 0 : 1)]
02934 >> ((3-(i & 3)) * 8) ) & 255);
02935 }
02936 c = 0200;
02937 SHA1Update(context, &c, 1);
02938 while ((context->count[0] & 504) != 448) {
02939 c = 0000;
02940 SHA1Update(context, &c, 1);
02941 }
02942 SHA1Update(context, finalcount, 8);
02943 for (i = 0; i < 20; i++) {
02944 digest[i] = (unsigned char)
02945 ((context->state[i>>2] >> ((3-(i & 3)) * 8) ) & 255);
02946 }
02947 memset(context, '\0', sizeof(*context));
02948 memset(&finalcount, '\0', sizeof(finalcount));
02949 }
02950
02951
02952 static void base64_encode(const unsigned char *src, int src_len, char *dst) {
02953 static const char *b64 =
02954 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
02955 int i, j, a, b, c;
02956
02957 for (i = j = 0; i < src_len; i += 3) {
02958 a = src[i];
02959 b = i + 1 >= src_len ? 0 : src[i + 1];
02960 c = i + 2 >= src_len ? 0 : src[i + 2];
02961
02962 dst[j++] = b64[a >> 2];
02963 dst[j++] = b64[((a & 3) << 4) | (b >> 4)];
02964 if (i + 1 < src_len) {
02965 dst[j++] = b64[(b & 15) << 2 | (c >> 6)];
02966 }
02967 if (i + 2 < src_len) {
02968 dst[j++] = b64[c & 63];
02969 }
02970 }
02971 while (j % 4 != 0) {
02972 dst[j++] = '=';
02973 }
02974 dst[j++] = '\0';
02975 }
02976
02977 static void send_websocket_handshake(struct mg_connection *conn,
02978 const char *key) {
02979 static const char *magic = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
02980 char buf[500], sha[20], b64_sha[sizeof(sha) * 2];
02981 SHA1_CTX sha_ctx;
02982
02983 mg_snprintf(buf, sizeof(buf), "%s%s", key, magic);
02984 SHA1Init(&sha_ctx);
02985 SHA1Update(&sha_ctx, (unsigned char *) buf, strlen(buf));
02986 SHA1Final((unsigned char *) sha, &sha_ctx);
02987 base64_encode((unsigned char *) sha, sizeof(sha), b64_sha);
02988 mg_snprintf(buf, sizeof(buf), "%s%s%s",
02989 "HTTP/1.1 101 Switching Protocols\r\n"
02990 "Upgrade: websocket\r\n"
02991 "Connection: Upgrade\r\n"
02992 "Sec-WebSocket-Accept: ", b64_sha, "\r\n\r\n");
02993
02994 mg_write(conn, buf, strlen(buf));
02995 }
02996
02997 static size_t deliver_websocket_frame(struct connection *conn) {
02998
02999 unsigned char *buf = (unsigned char *) conn->ns_conn->recv_iobuf.buf;
03000 size_t i, len, buf_len = conn->ns_conn->recv_iobuf.len, frame_len = 0,
03001 mask_len = 0, header_len = 0, data_len = 0, buffered = 0;
03002
03003 if (buf_len >= 2) {
03004 len = buf[1] & 127;
03005 mask_len = buf[1] & 128 ? 4 : 0;
03006 if (len < 126 && buf_len >= mask_len) {
03007 data_len = len;
03008 header_len = 2 + mask_len;
03009 } else if (len == 126 && buf_len >= 4 + mask_len) {
03010 header_len = 4 + mask_len;
03011 data_len = ((((size_t) buf[2]) << 8) + buf[3]);
03012 } else if (buf_len >= 10 + mask_len) {
03013 header_len = 10 + mask_len;
03014 data_len = (size_t) (((uint64_t) htonl(* (uint32_t *) &buf[2])) << 32) +
03015 htonl(* (uint32_t *) &buf[6]);
03016 }
03017 }
03018
03019 frame_len = header_len + data_len;
03020 buffered = frame_len > 0 && frame_len <= buf_len;
03021
03022 if (buffered) {
03023 conn->mg_conn.content_len = data_len;
03024 conn->mg_conn.content = (char *) buf + header_len;
03025 conn->mg_conn.wsbits = buf[0];
03026
03027
03028 if (mask_len > 0) {
03029 for (i = 0; i < data_len; i++) {
03030 buf[i + header_len] ^= (buf + header_len - mask_len)[i % 4];
03031 }
03032 }
03033
03034
03035 if (call_user(conn, MG_REQUEST) == MG_FALSE ||
03036 (buf[0] & 0x0f) == WEBSOCKET_OPCODE_CONNECTION_CLOSE) {
03037 conn->ns_conn->flags |= NSF_FINISHED_SENDING_DATA;
03038 }
03039 iobuf_remove(&conn->ns_conn->recv_iobuf, frame_len);
03040 }
03041
03042 return buffered;
03043 }
03044
03045 size_t mg_websocket_write(struct mg_connection *conn, int opcode,
03046 const char *data, size_t data_len) {
03047 unsigned char mem[4192], *copy = mem;
03048 size_t copy_len = 0;
03049
03050
03051 if (data_len > ~(size_t)0 - (size_t)10) {
03052 return 0;
03053 }
03054
03055 if (data_len + 10 > sizeof(mem) &&
03056 (copy = (unsigned char *) NS_MALLOC(data_len + 10)) == NULL) {
03057 return 0;
03058 }
03059
03060 copy[0] = 0x80 + (opcode & 0x0f);
03061
03062
03063 if (data_len < 126) {
03064
03065 copy[1] = data_len;
03066 memcpy(copy + 2, data, data_len);
03067 copy_len = 2 + data_len;
03068 } else if (data_len <= 0xFFFF) {
03069
03070 copy[1] = 126;
03071 * (uint16_t *) (copy + 2) = (uint16_t) htons((uint16_t) data_len);
03072 memcpy(copy + 4, data, data_len);
03073 copy_len = 4 + data_len;
03074 } else {
03075
03076 const uint32_t hi = htonl((uint32_t) ((uint64_t) data_len >> 32));
03077 const uint32_t lo = htonl(data_len & 0xffffffff);
03078 copy[1] = 127;
03079 memcpy(copy+2,&hi,sizeof(hi));
03080 memcpy(copy+6,&lo,sizeof(lo));
03081 memcpy(copy + 10, data, data_len);
03082 copy_len = 10 + data_len;
03083 }
03084
03085 if (copy_len > 0) {
03086 mg_write(conn, copy, copy_len);
03087 }
03088 if (copy != mem) {
03089 NS_FREE(copy);
03090 }
03091
03092
03093
03094 if (opcode == WEBSOCKET_OPCODE_CONNECTION_CLOSE) {
03095 MG_CONN_2_CONN(conn)->ns_conn->flags |= NSF_FINISHED_SENDING_DATA;
03096 }
03097
03098 return MG_CONN_2_CONN(conn)->ns_conn->send_iobuf.len;
03099 }
03100
03101 size_t mg_websocket_printf(struct mg_connection *conn, int opcode,
03102 const char *fmt, ...) {
03103 char mem[4192], *buf = mem;
03104 va_list ap;
03105 int len;
03106
03107 va_start(ap, fmt);
03108 if ((len = ns_avprintf(&buf, sizeof(mem), fmt, ap)) > 0) {
03109 mg_websocket_write(conn, opcode, buf, len);
03110 }
03111 va_end(ap);
03112
03113 if (buf != mem && buf != NULL) {
03114 NS_FREE(buf);
03115 }
03116
03117 return MG_CONN_2_CONN(conn)->ns_conn->send_iobuf.len;
03118 }
03119
03120 static void send_websocket_handshake_if_requested(struct mg_connection *conn) {
03121 const char *ver = mg_get_header(conn, "Sec-WebSocket-Version"),
03122 *key = mg_get_header(conn, "Sec-WebSocket-Key");
03123 if (ver != NULL && key != NULL) {
03124 conn->is_websocket = 1;
03125 if (call_user(MG_CONN_2_CONN(conn), MG_WS_HANDSHAKE) == MG_FALSE) {
03126 send_websocket_handshake(conn, key);
03127 }
03128 call_user(MG_CONN_2_CONN(conn), MG_WS_CONNECT);
03129 }
03130 }
03131
03132 static void ping_idle_websocket_connection(struct connection *conn, time_t t) {
03133 if (t - conn->ns_conn->last_io_time > MONGOOSE_USE_WEBSOCKET_PING_INTERVAL) {
03134 mg_websocket_write(&conn->mg_conn, WEBSOCKET_OPCODE_PING, "", 0);
03135 }
03136 }
03137 #else
03138 #define ping_idle_websocket_connection(conn, t)
03139 #endif // !MONGOOSE_NO_WEBSOCKET
03140
03141 static void write_terminating_chunk(struct connection *conn) {
03142 mg_write(&conn->mg_conn, "0\r\n\r\n", 5);
03143 }
03144
03145 static int call_request_handler(struct connection *conn) {
03146 int result;
03147 conn->mg_conn.content = conn->ns_conn->recv_iobuf.buf;
03148 if ((result = call_user(conn, MG_REQUEST)) == MG_TRUE) {
03149 if (conn->ns_conn->flags & MG_USING_CHUNKED_API) {
03150 terminate_headers(&conn->mg_conn);
03151 write_terminating_chunk(conn);
03152 }
03153 close_local_endpoint(conn);
03154 }
03155 return result;
03156 }
03157
03158 const char *mg_get_mime_type(const char *path, const char *default_mime_type) {
03159 const char *ext;
03160 size_t i, path_len;
03161
03162 path_len = strlen(path);
03163
03164 for (i = 0; static_builtin_mime_types[i].extension != NULL; i++) {
03165 ext = path + (path_len - static_builtin_mime_types[i].ext_len);
03166 if (path_len > static_builtin_mime_types[i].ext_len &&
03167 mg_strcasecmp(ext, static_builtin_mime_types[i].extension) == 0) {
03168 return static_builtin_mime_types[i].mime_type;
03169 }
03170 }
03171
03172 return default_mime_type;
03173 }
03174
03175 #ifndef MONGOOSE_NO_FILESYSTEM
03176
03177 static int get_month_index(const char *s) {
03178 static const char *month_names[] = {
03179 "Jan", "Feb", "Mar", "Apr", "May", "Jun",
03180 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
03181 };
03182 int i;
03183
03184 for (i = 0; i < (int) ARRAY_SIZE(month_names); i++)
03185 if (!strcmp(s, month_names[i]))
03186 return i;
03187
03188 return -1;
03189 }
03190
03191 static int num_leap_years(int year) {
03192 return year / 4 - year / 100 + year / 400;
03193 }
03194
03195
03196 static time_t parse_date_string(const char *datetime) {
03197 static const unsigned short days_before_month[] = {
03198 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334
03199 };
03200 char month_str[32];
03201 int second, minute, hour, day, month, year, leap_days, days;
03202 time_t result = (time_t) 0;
03203
03204 if (((sscanf(datetime, "%d/%3s/%d %d:%d:%d",
03205 &day, month_str, &year, &hour, &minute, &second) == 6) ||
03206 (sscanf(datetime, "%d %3s %d %d:%d:%d",
03207 &day, month_str, &year, &hour, &minute, &second) == 6) ||
03208 (sscanf(datetime, "%*3s, %d %3s %d %d:%d:%d",
03209 &day, month_str, &year, &hour, &minute, &second) == 6) ||
03210 (sscanf(datetime, "%d-%3s-%d %d:%d:%d",
03211 &day, month_str, &year, &hour, &minute, &second) == 6)) &&
03212 year > 1970 &&
03213 (month = get_month_index(month_str)) != -1) {
03214 leap_days = num_leap_years(year) - num_leap_years(1970);
03215 year -= 1970;
03216 days = year * 365 + days_before_month[month] + (day - 1) + leap_days;
03217 result = days * 24 * 3600 + hour * 3600 + minute * 60 + second;
03218 }
03219
03220 return result;
03221 }
03222
03223
03224
03225 static void get_mime_type(const struct mg_server *server, const char *path,
03226 struct vec *vec) {
03227 struct vec ext_vec, mime_vec;
03228 const char *list, *ext;
03229 size_t path_len;
03230
03231 path_len = strlen(path);
03232
03233
03234
03235 list = server->config_options[EXTRA_MIME_TYPES];
03236 while ((list = next_option(list, &ext_vec, &mime_vec)) != NULL) {
03237
03238 ext = path + path_len - ext_vec.len;
03239 if (mg_strncasecmp(ext, ext_vec.ptr, ext_vec.len) == 0) {
03240 *vec = mime_vec;
03241 return;
03242 }
03243 }
03244
03245 vec->ptr = mg_get_mime_type(path, "text/plain");
03246 vec->len = strlen(vec->ptr);
03247 }
03248
03249 static const char *suggest_connection_header(const struct mg_connection *conn) {
03250 return should_keep_alive(conn) ? "keep-alive" : "close";
03251 }
03252
03253 static void construct_etag(char *buf, size_t buf_len, const file_stat_t *st) {
03254 mg_snprintf(buf, buf_len, "\"%lx.%" INT64_FMT "\"",
03255 (unsigned long) st->st_mtime, (int64_t) st->st_size);
03256 }
03257
03258
03259 static int is_not_modified(const struct connection *conn,
03260 const file_stat_t *stp) {
03261 char etag[64];
03262 const char *ims = mg_get_header(&conn->mg_conn, "If-Modified-Since");
03263 const char *inm = mg_get_header(&conn->mg_conn, "If-None-Match");
03264 construct_etag(etag, sizeof(etag), stp);
03265 return (inm != NULL && !mg_strcasecmp(etag, inm)) ||
03266 (ims != NULL && stp->st_mtime <= parse_date_string(ims));
03267 }
03268
03269
03270
03271
03272 static int find_index_file(struct connection *conn, char *path,
03273 size_t path_len, file_stat_t *stp) {
03274 const char *list = conn->server->config_options[INDEX_FILES];
03275 file_stat_t st;
03276 struct vec filename_vec;
03277 size_t n = strlen(path);
03278 int found = 0;
03279
03280
03281
03282
03283 while (n > 0 && path[n - 1] == '/') {
03284 n--;
03285 }
03286 path[n] = '/';
03287
03288
03289
03290 while ((list = next_option(list, &filename_vec, NULL)) != NULL) {
03291
03292 if (path_len <= n + 2) {
03293 continue;
03294 }
03295
03296
03297 if (filename_vec.len > (path_len - (n + 2)))
03298 continue;
03299
03300
03301 strncpy(path + n + 1, filename_vec.ptr, filename_vec.len);
03302 path[n + 1 + filename_vec.len] = '\0';
03303
03304
03305
03306
03307 if (!stat(path, &st)) {
03308
03309 *stp = st;
03310 found = 1;
03311 break;
03312 }
03313 }
03314
03315
03316 if (!found) {
03317 path[n] = '\0';
03318 }
03319
03320 return found;
03321 }
03322
03323 static int parse_range_header(const char *header, int64_t *a, int64_t *b) {
03324 return sscanf(header, "bytes=%" INT64_FMT "-%" INT64_FMT, a, b);
03325 }
03326
03327 static void gmt_time_string(char *buf, size_t buf_len, time_t *t) {
03328 strftime(buf, buf_len, "%a, %d %b %Y %H:%M:%S GMT", gmtime(t));
03329 }
03330
03331 static void open_file_endpoint(struct connection *conn, const char *path,
03332 file_stat_t *st, const char *extra_headers) {
03333 char date[64], lm[64], etag[64], range[64], headers[1000];
03334 const char *msg = "OK", *hdr;
03335 time_t t, curtime = time(NULL);
03336 int64_t r1, r2;
03337 struct vec mime_vec;
03338 int n;
03339
03340 conn->endpoint_type = EP_FILE;
03341 ns_set_close_on_exec(conn->endpoint.fd);
03342 conn->mg_conn.status_code = 200;
03343
03344 get_mime_type(conn->server, path, &mime_vec);
03345 conn->cl = st->st_size;
03346 range[0] = '\0';
03347
03348
03349 r1 = r2 = 0;
03350 hdr = mg_get_header(&conn->mg_conn, "Range");
03351 if (hdr != NULL && (n = parse_range_header(hdr, &r1, &r2)) > 0 &&
03352 r1 >= 0 && r2 >= 0) {
03353 conn->mg_conn.status_code = 206;
03354 conn->cl = n == 2 ? (r2 > conn->cl ? conn->cl : r2) - r1 + 1: conn->cl - r1;
03355 mg_snprintf(range, sizeof(range), "Content-Range: bytes "
03356 "%" INT64_FMT "-%" INT64_FMT "/%" INT64_FMT "\r\n",
03357 r1, r1 + conn->cl - 1, (int64_t) st->st_size);
03358 msg = "Partial Content";
03359 lseek(conn->endpoint.fd, r1, SEEK_SET);
03360 }
03361
03362
03363
03364 gmt_time_string(date, sizeof(date), &curtime);
03365 t = st->st_mtime;
03366 gmt_time_string(lm, sizeof(lm), &t);
03367 construct_etag(etag, sizeof(etag), st);
03368
03369 n = mg_snprintf(headers, sizeof(headers),
03370 "HTTP/1.1 %d %s\r\n"
03371 "Date: %s\r\n"
03372 "Last-Modified: %s\r\n"
03373 "Etag: %s\r\n"
03374 "Content-Type: %.*s\r\n"
03375 "Content-Length: %" INT64_FMT "\r\n"
03376 "Connection: %s\r\n"
03377 "Accept-Ranges: bytes\r\n"
03378 "%s%s%s\r\n",
03379 conn->mg_conn.status_code, msg, date, lm, etag,
03380 (int) mime_vec.len, mime_vec.ptr, conn->cl,
03381 suggest_connection_header(&conn->mg_conn),
03382 range, extra_headers == NULL ? "" : extra_headers,
03383 MONGOOSE_USE_EXTRA_HTTP_HEADERS);
03384 ns_send(conn->ns_conn, headers, n);
03385
03386 if (!strcmp(conn->mg_conn.request_method, "HEAD")) {
03387 conn->ns_conn->flags |= NSF_FINISHED_SENDING_DATA;
03388 close(conn->endpoint.fd);
03389 conn->endpoint_type = EP_NONE;
03390 }
03391 }
03392
03393 void mg_send_file_data(struct mg_connection *c, int fd) {
03394 struct connection *conn = MG_CONN_2_CONN(c);
03395 conn->endpoint_type = EP_FILE;
03396 conn->endpoint.fd = fd;
03397 ns_set_close_on_exec(conn->endpoint.fd);
03398 }
03399 #endif // MONGOOSE_NO_FILESYSTEM
03400
03401 static void call_request_handler_if_data_is_buffered(struct connection *conn) {
03402 #ifndef MONGOOSE_NO_WEBSOCKET
03403 if (conn->mg_conn.is_websocket) {
03404 do { } while (deliver_websocket_frame(conn));
03405 } else
03406 #endif
03407 if (conn->num_bytes_recv >= (conn->cl + conn->request_len) &&
03408 call_request_handler(conn) == MG_FALSE) {
03409 open_local_endpoint(conn, 1);
03410 }
03411 }
03412
03413 #if !defined(MONGOOSE_NO_DIRECTORY_LISTING) || !defined(MONGOOSE_NO_DAV)
03414
03415 #ifdef _WIN32
03416 struct dirent {
03417 char d_name[MAX_PATH_SIZE];
03418 };
03419
03420 typedef struct DIR {
03421 HANDLE handle;
03422 WIN32_FIND_DATAW info;
03423 struct dirent result;
03424 } DIR;
03425
03426
03427 static DIR *opendir(const char *name) {
03428 DIR *dir = NULL;
03429 wchar_t wpath[MAX_PATH_SIZE];
03430 DWORD attrs;
03431
03432 if (name == NULL) {
03433 SetLastError(ERROR_BAD_ARGUMENTS);
03434 } else if ((dir = (DIR *) NS_MALLOC(sizeof(*dir))) == NULL) {
03435 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
03436 } else {
03437 to_wchar(name, wpath, ARRAY_SIZE(wpath));
03438 attrs = GetFileAttributesW(wpath);
03439 if (attrs != 0xFFFFFFFF &&
03440 ((attrs & FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY)) {
03441 (void) wcscat(wpath, L"\\*");
03442 dir->handle = FindFirstFileW(wpath, &dir->info);
03443 dir->result.d_name[0] = '\0';
03444 } else {
03445 NS_FREE(dir);
03446 dir = NULL;
03447 }
03448 }
03449
03450 return dir;
03451 }
03452
03453 static int closedir(DIR *dir) {
03454 int result = 0;
03455
03456 if (dir != NULL) {
03457 if (dir->handle != INVALID_HANDLE_VALUE)
03458 result = FindClose(dir->handle) ? 0 : -1;
03459
03460 NS_FREE(dir);
03461 } else {
03462 result = -1;
03463 SetLastError(ERROR_BAD_ARGUMENTS);
03464 }
03465
03466 return result;
03467 }
03468
03469 static struct dirent *readdir(DIR *dir) {
03470 struct dirent *result = 0;
03471
03472 if (dir) {
03473 if (dir->handle != INVALID_HANDLE_VALUE) {
03474 result = &dir->result;
03475 (void) WideCharToMultiByte(CP_UTF8, 0,
03476 dir->info.cFileName, -1, result->d_name,
03477 sizeof(result->d_name), NULL, NULL);
03478
03479 if (!FindNextFileW(dir->handle, &dir->info)) {
03480 (void) FindClose(dir->handle);
03481 dir->handle = INVALID_HANDLE_VALUE;
03482 }
03483
03484 } else {
03485 SetLastError(ERROR_FILE_NOT_FOUND);
03486 }
03487 } else {
03488 SetLastError(ERROR_BAD_ARGUMENTS);
03489 }
03490
03491 return result;
03492 }
03493 #endif // _WIN32 POSIX opendir/closedir/readdir implementation
03494
03495 static int scan_directory(struct connection *conn, const char *dir,
03496 struct dir_entry **arr) {
03497 char path[MAX_PATH_SIZE];
03498 struct dir_entry *p;
03499 struct dirent *dp;
03500 int arr_size = 0, arr_ind = 0, inc = 100;
03501 DIR *dirp;
03502
03503 *arr = NULL;
03504 if ((dirp = (opendir(dir))) == NULL) return 0;
03505
03506 while ((dp = readdir(dirp)) != NULL) {
03507
03508 if (!strcmp(dp->d_name, ".") ||
03509 !strcmp(dp->d_name, "..") ||
03510 must_hide_file(conn, dp->d_name)) {
03511 continue;
03512 }
03513 mg_snprintf(path, sizeof(path), "%s%c%s", dir, '/', dp->d_name);
03514
03515
03516 if (arr_ind >= arr_size) {
03517 if ((p = (struct dir_entry *)
03518 NS_REALLOC(*arr, (inc + arr_size) * sizeof(**arr))) != NULL) {
03519
03520
03521
03522 memset(p + arr_size, 0, sizeof(**arr) * inc);
03523
03524 *arr = p;
03525 arr_size += inc;
03526 }
03527 }
03528
03529 if (arr_ind < arr_size) {
03530 (*arr)[arr_ind].conn = conn;
03531 (*arr)[arr_ind].file_name = strdup(dp->d_name);
03532 stat(path, &(*arr)[arr_ind].st);
03533 arr_ind++;
03534 }
03535 }
03536 closedir(dirp);
03537
03538 return arr_ind;
03539 }
03540
03541 size_t mg_url_encode(const char *src, size_t s_len, char *dst, size_t dst_len) {
03542 static const char *dont_escape = "._-$,;~()";
03543 static const char *hex = "0123456789abcdef";
03544 size_t i = 0, j = 0;
03545
03546 for (i = j = 0; dst_len > 0 && i < s_len && j + 2 < dst_len - 1; i++, j++) {
03547 if (isalnum(* (const unsigned char *) (src + i)) ||
03548 strchr(dont_escape, * (const unsigned char *) (src + i)) != NULL) {
03549 dst[j] = src[i];
03550 } else if (j + 3 < dst_len) {
03551 dst[j] = '%';
03552 dst[j + 1] = hex[(* (const unsigned char *) (src + i)) >> 4];
03553 dst[j + 2] = hex[(* (const unsigned char *) (src + i)) & 0xf];
03554 j += 2;
03555 }
03556 }
03557
03558 dst[j] = '\0';
03559 return j;
03560 }
03561 #endif // !NO_DIRECTORY_LISTING || !MONGOOSE_NO_DAV
03562
03563 #ifndef MONGOOSE_NO_DIRECTORY_LISTING
03564
03565 static void print_dir_entry(const struct dir_entry *de) {
03566 char size[64], mod[64], href[MAX_PATH_SIZE * 3];
03567 int64_t fsize = de->st.st_size;
03568 int is_dir = S_ISDIR(de->st.st_mode);
03569 const char *slash = is_dir ? "/" : "";
03570 time_t t;
03571
03572 if (is_dir) {
03573 mg_snprintf(size, sizeof(size), "%s", "[DIRECTORY]");
03574 } else {
03575
03576
03577 if (fsize < 1024) {
03578 mg_snprintf(size, sizeof(size), "%d", (int) fsize);
03579 } else if (fsize < 0x100000) {
03580 mg_snprintf(size, sizeof(size), "%.1fk", (double) fsize / 1024.0);
03581 } else if (fsize < 0x40000000) {
03582 mg_snprintf(size, sizeof(size), "%.1fM", (double) fsize / 1048576);
03583 } else {
03584 mg_snprintf(size, sizeof(size), "%.1fG", (double) fsize / 1073741824);
03585 }
03586 }
03587 t = de->st.st_mtime;
03588 strftime(mod, sizeof(mod), "%d-%b-%Y %H:%M", localtime(&t));
03589 mg_url_encode(de->file_name, strlen(de->file_name), href, sizeof(href));
03590 mg_printf_data(&de->conn->mg_conn,
03591 "<tr><td><a href=\"%s%s\">%s%s</a></td>"
03592 "<td> %s</td><td> %s</td></tr>\n",
03593 href, slash, de->file_name, slash, mod, size);
03594 }
03595
03596
03597
03598
03599 static int __cdecl compare_dir_entries(const void *p1, const void *p2) {
03600 const struct dir_entry *a = (const struct dir_entry *) p1,
03601 *b = (const struct dir_entry *) p2;
03602 const char *qs = a->conn->mg_conn.query_string ?
03603 a->conn->mg_conn.query_string : "na";
03604 int cmp_result = 0;
03605
03606 if (S_ISDIR(a->st.st_mode) && !S_ISDIR(b->st.st_mode)) {
03607 return -1;
03608 } else if (!S_ISDIR(a->st.st_mode) && S_ISDIR(b->st.st_mode)) {
03609 return 1;
03610 } else if (*qs == 'n') {
03611 cmp_result = strcmp(a->file_name, b->file_name);
03612 } else if (*qs == 's') {
03613 cmp_result = a->st.st_size == b->st.st_size ? 0 :
03614 a->st.st_size > b->st.st_size ? 1 : -1;
03615 } else if (*qs == 'd') {
03616 cmp_result = a->st.st_mtime == b->st.st_mtime ? 0 :
03617 a->st.st_mtime > b->st.st_mtime ? 1 : -1;
03618 }
03619
03620 return qs[1] == 'd' ? -cmp_result : cmp_result;
03621 }
03622
03623 static void send_directory_listing(struct connection *conn, const char *dir) {
03624 struct dir_entry *arr = NULL;
03625 int i, num_entries, sort_direction = conn->mg_conn.query_string != NULL &&
03626 conn->mg_conn.query_string[1] == 'd' ? 'a' : 'd';
03627
03628 mg_send_header(&conn->mg_conn, "Transfer-Encoding", "chunked");
03629 mg_send_header(&conn->mg_conn, "Content-Type", "text/html; charset=utf-8");
03630
03631 mg_printf_data(&conn->mg_conn,
03632 "<html><head><title>Index of %s</title>"
03633 "<style>th {text-align: left;}</style></head>"
03634 "<body><h1>Index of %s</h1><pre><table cellpadding=\"0\">"
03635 "<tr><th><a href=\"?n%c\">Name</a></th>"
03636 "<th><a href=\"?d%c\">Modified</a></th>"
03637 "<th><a href=\"?s%c\">Size</a></th></tr>"
03638 "<tr><td colspan=\"3\"><hr></td></tr>",
03639 conn->mg_conn.uri, conn->mg_conn.uri,
03640 sort_direction, sort_direction, sort_direction);
03641
03642 num_entries = scan_directory(conn, dir, &arr);
03643 if (arr) {
03644 qsort(arr, num_entries, sizeof(arr[0]), compare_dir_entries);
03645 for (i = 0; i < num_entries; i++) {
03646 print_dir_entry(&arr[i]);
03647 NS_FREE(arr[i].file_name);
03648 }
03649 NS_FREE(arr);
03650 }
03651
03652 write_terminating_chunk(conn);
03653 close_local_endpoint(conn);
03654 }
03655 #endif // MONGOOSE_NO_DIRECTORY_LISTING
03656
03657 #ifndef MONGOOSE_NO_DAV
03658 static void print_props(struct connection *conn, const char *uri,
03659 file_stat_t *stp) {
03660 char mtime[64];
03661 time_t t = stp->st_mtime;
03662 gmt_time_string(mtime, sizeof(mtime), &t);
03663 mg_printf(&conn->mg_conn,
03664 "<d:response>"
03665 "<d:href>%s</d:href>"
03666 "<d:propstat>"
03667 "<d:prop>"
03668 "<d:resourcetype>%s</d:resourcetype>"
03669 "<d:getcontentlength>%" INT64_FMT "</d:getcontentlength>"
03670 "<d:getlastmodified>%s</d:getlastmodified>"
03671 "</d:prop>"
03672 "<d:status>HTTP/1.1 200 OK</d:status>"
03673 "</d:propstat>"
03674 "</d:response>\n",
03675 uri, S_ISDIR(stp->st_mode) ? "<d:collection/>" : "",
03676 (int64_t) stp->st_size, mtime);
03677 }
03678
03679 static void handle_propfind(struct connection *conn, const char *path,
03680 file_stat_t *stp, int exists) {
03681 static const char header[] = "HTTP/1.1 207 Multi-Status\r\n"
03682 "Connection: close\r\n"
03683 "Content-Type: text/xml; charset=utf-8\r\n\r\n"
03684 "<?xml version=\"1.0\" encoding=\"utf-8\"?>"
03685 "<d:multistatus xmlns:d='DAV:'>\n";
03686 static const char footer[] = "</d:multistatus>";
03687 const char *depth = mg_get_header(&conn->mg_conn, "Depth");
03688 #ifdef MONGOOSE_NO_DIRECTORY_LISTING
03689 const char *list_dir = "no";
03690 #else
03691 const char *list_dir = conn->server->config_options[ENABLE_DIRECTORY_LISTING];
03692 #endif
03693
03694 conn->mg_conn.status_code = 207;
03695
03696
03697 if (!exists) {
03698 conn->mg_conn.status_code = 404;
03699 mg_printf(&conn->mg_conn, "%s", "HTTP/1.1 404 Not Found\r\n\r\n");
03700 } else if (S_ISDIR(stp->st_mode) && mg_strcasecmp(list_dir, "yes") != 0) {
03701 conn->mg_conn.status_code = 403;
03702 mg_printf(&conn->mg_conn, "%s",
03703 "HTTP/1.1 403 Directory Listing Denied\r\n\r\n");
03704 } else {
03705 ns_send(conn->ns_conn, header, sizeof(header) - 1);
03706 print_props(conn, conn->mg_conn.uri, stp);
03707
03708 if (S_ISDIR(stp->st_mode) &&
03709 (depth == NULL || strcmp(depth, "0") != 0)) {
03710 struct dir_entry *arr = NULL;
03711 int i, num_entries = scan_directory(conn, path, &arr);
03712
03713 for (i = 0; i < num_entries; i++) {
03714 char buf[MAX_PATH_SIZE * 3];
03715 struct dir_entry *de = &arr[i];
03716 mg_url_encode(de->file_name, strlen(de->file_name), buf, sizeof(buf));
03717 print_props(conn, buf, &de->st);
03718 NS_FREE(de->file_name);
03719 }
03720 NS_FREE(arr);
03721 }
03722 ns_send(conn->ns_conn, footer, sizeof(footer) - 1);
03723 }
03724
03725 close_local_endpoint(conn);
03726 }
03727
03728 static void handle_mkcol(struct connection *conn, const char *path) {
03729 int status_code = 500;
03730
03731 if (conn->mg_conn.content_len > 0) {
03732 status_code = 415;
03733 } else if (!mkdir(path, 0755)) {
03734 status_code = 201;
03735 } else if (errno == EEXIST) {
03736 status_code = 405;
03737 } else if (errno == EACCES) {
03738 status_code = 403;
03739 } else if (errno == ENOENT) {
03740 status_code = 409;
03741 }
03742 send_http_error(conn, status_code, NULL);
03743 }
03744
03745 static int remove_directory(const char *dir) {
03746 char path[MAX_PATH_SIZE];
03747 struct dirent *dp;
03748 file_stat_t st;
03749 DIR *dirp;
03750
03751 if ((dirp = opendir(dir)) == NULL) return 0;
03752
03753 while ((dp = readdir(dirp)) != NULL) {
03754 if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, "..")) continue;
03755 mg_snprintf(path, sizeof(path), "%s%c%s", dir, '/', dp->d_name);
03756 stat(path, &st);
03757 if (S_ISDIR(st.st_mode)) {
03758 remove_directory(path);
03759 } else {
03760 remove(path);
03761 }
03762 }
03763 closedir(dirp);
03764 rmdir(dir);
03765
03766 return 1;
03767 }
03768
03769 static void handle_delete(struct connection *conn, const char *path) {
03770 file_stat_t st;
03771
03772 if (stat(path, &st) != 0) {
03773 send_http_error(conn, 404, NULL);
03774 } else if (S_ISDIR(st.st_mode)) {
03775 remove_directory(path);
03776 send_http_error(conn, 204, NULL);
03777 } else if (remove(path) == 0) {
03778 send_http_error(conn, 204, NULL);
03779 } else {
03780 send_http_error(conn, 423, NULL);
03781 }
03782 }
03783
03784
03785
03786
03787 static int put_dir(const char *path) {
03788 char buf[MAX_PATH_SIZE];
03789 const char *s, *p;
03790 file_stat_t st;
03791
03792
03793 for (s = p = path + 1; (p = strchr(s, '/')) != NULL; s = ++p) {
03794 if (p - path >= (int) sizeof(buf)) return -1;
03795 memcpy(buf, path, p - path);
03796 buf[p - path] = '\0';
03797 if (stat(buf, &st) != 0 && mkdir(buf, 0755) != 0) return -1;
03798 if (p[1] == '\0') return 0;
03799 }
03800
03801 return 1;
03802 }
03803
03804 static void handle_put(struct connection *conn, const char *path) {
03805 file_stat_t st;
03806 const char *range, *cl_hdr = mg_get_header(&conn->mg_conn, "Content-Length");
03807 int64_t r1, r2;
03808 int rc;
03809
03810 conn->mg_conn.status_code = !stat(path, &st) ? 200 : 201;
03811 if ((rc = put_dir(path)) == 0) {
03812 mg_printf(&conn->mg_conn, "HTTP/1.1 %d OK\r\n\r\n",
03813 conn->mg_conn.status_code);
03814 close_local_endpoint(conn);
03815 } else if (rc == -1) {
03816 send_http_error(conn, 500, "put_dir: %s", strerror(errno));
03817 } else if (cl_hdr == NULL) {
03818 send_http_error(conn, 411, NULL);
03819 } else if ((conn->endpoint.fd =
03820 open(path, O_RDWR | O_CREAT | O_TRUNC | O_BINARY, 0644)) < 0) {
03821 send_http_error(conn, 500, "open(%s): %s", path, strerror(errno));
03822 } else {
03823 DBG(("PUT [%s] %lu", path, (unsigned long) conn->ns_conn->recv_iobuf.len));
03824 conn->endpoint_type = EP_PUT;
03825 ns_set_close_on_exec(conn->endpoint.fd);
03826 range = mg_get_header(&conn->mg_conn, "Content-Range");
03827 conn->cl = to64(cl_hdr);
03828 r1 = r2 = 0;
03829 if (range != NULL && parse_range_header(range, &r1, &r2) > 0) {
03830 conn->mg_conn.status_code = 206;
03831 lseek(conn->endpoint.fd, r1, SEEK_SET);
03832 conn->cl = r2 > r1 ? r2 - r1 + 1: conn->cl - r1;
03833 }
03834 mg_printf(&conn->mg_conn, "HTTP/1.1 %d OK\r\nContent-Length: 0\r\n\r\n",
03835 conn->mg_conn.status_code);
03836 }
03837 }
03838
03839 static void forward_put_data(struct connection *conn) {
03840 struct iobuf *io = &conn->ns_conn->recv_iobuf;
03841 size_t k = conn->cl < (int64_t) io->len ? conn->cl : (int64_t) io->len;
03842 size_t n = write(conn->endpoint.fd, io->buf, k);
03843 if (n > 0) {
03844 iobuf_remove(io, n);
03845 conn->cl -= n;
03846 }
03847 if (conn->cl <= 0) {
03848 close_local_endpoint(conn);
03849 }
03850 }
03851 #endif // MONGOOSE_NO_DAV
03852
03853 static void send_options(struct connection *conn) {
03854 conn->mg_conn.status_code = 200;
03855 mg_printf(&conn->mg_conn, "%s",
03856 "HTTP/1.1 200 OK\r\nAllow: GET, POST, HEAD, CONNECT, PUT, "
03857 "DELETE, OPTIONS, PROPFIND, MKCOL\r\nDAV: 1\r\n\r\n");
03858 close_local_endpoint(conn);
03859 }
03860
03861 #ifndef MONGOOSE_NO_AUTH
03862 void mg_send_digest_auth_request(struct mg_connection *c) {
03863 struct connection *conn = MG_CONN_2_CONN(c);
03864 c->status_code = 401;
03865 mg_printf(c,
03866 "HTTP/1.1 401 Unauthorized\r\n"
03867 "Content-Length: 0\r\n"
03868 "WWW-Authenticate: Digest qop=\"auth\", "
03869 "realm=\"%s\", nonce=\"%lu\"\r\n\r\n",
03870 conn->server->config_options[AUTH_DOMAIN],
03871 (unsigned long) time(NULL));
03872 close_local_endpoint(conn);
03873 }
03874
03875
03876
03877 static FILE *open_auth_file(struct connection *conn, const char *path,
03878 int is_directory) {
03879 char name[MAX_PATH_SIZE];
03880 const char *p, *gpass = conn->server->config_options[GLOBAL_AUTH_FILE];
03881 FILE *fp = NULL;
03882
03883 if (gpass != NULL) {
03884
03885 fp = fopen(gpass, "r");
03886 } else if (is_directory) {
03887 mg_snprintf(name, sizeof(name), "%s%c%s", path, '/', PASSWORDS_FILE_NAME);
03888 fp = fopen(name, "r");
03889 } else {
03890
03891 if ((p = strrchr(path, '/')) == NULL) p = path;
03892 mg_snprintf(name, sizeof(name), "%.*s%c%s",
03893 (int) (p - path), path, '/', PASSWORDS_FILE_NAME);
03894 fp = fopen(name, "r");
03895 }
03896
03897 return fp;
03898 }
03899
03900 #if !defined(HAVE_MD5) && !defined(MONGOOSE_NO_AUTH)
03901
03902
03903
03904
03905
03906
03907
03908
03909
03910
03911
03912
03913
03914
03915
03916
03917
03918 typedef struct MD5Context {
03919 uint32_t buf[4];
03920 uint32_t bits[2];
03921 unsigned char in[64];
03922 } MD5_CTX;
03923
03924 static void byteReverse(unsigned char *buf, unsigned longs) {
03925 uint32_t t;
03926
03927
03928 if (is_big_endian()) {
03929 do {
03930 t = (uint32_t) ((unsigned) buf[3] << 8 | buf[2]) << 16 |
03931 ((unsigned) buf[1] << 8 | buf[0]);
03932 * (uint32_t *) buf = t;
03933 buf += 4;
03934 } while (--longs);
03935 }
03936 }
03937
03938 #define F1(x, y, z) (z ^ (x & (y ^ z)))
03939 #define F2(x, y, z) F1(z, x, y)
03940 #define F3(x, y, z) (x ^ y ^ z)
03941 #define F4(x, y, z) (y ^ (x | ~z))
03942
03943 #define MD5STEP(f, w, x, y, z, data, s) \
03944 ( w += f(x, y, z) + data, w = w<<s | w>>(32-s), w += x )
03945
03946
03947
03948 static void MD5Init(MD5_CTX *ctx) {
03949 ctx->buf[0] = 0x67452301;
03950 ctx->buf[1] = 0xefcdab89;
03951 ctx->buf[2] = 0x98badcfe;
03952 ctx->buf[3] = 0x10325476;
03953
03954 ctx->bits[0] = 0;
03955 ctx->bits[1] = 0;
03956 }
03957
03958 static void MD5Transform(uint32_t buf[4], uint32_t const in[16]) {
03959 register uint32_t a, b, c, d;
03960
03961 a = buf[0];
03962 b = buf[1];
03963 c = buf[2];
03964 d = buf[3];
03965
03966 MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7);
03967 MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12);
03968 MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17);
03969 MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22);
03970 MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7);
03971 MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12);
03972 MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17);
03973 MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22);
03974 MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7);
03975 MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12);
03976 MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17);
03977 MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22);
03978 MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7);
03979 MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12);
03980 MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17);
03981 MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22);
03982
03983 MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5);
03984 MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9);
03985 MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14);
03986 MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20);
03987 MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5);
03988 MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9);
03989 MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14);
03990 MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20);
03991 MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5);
03992 MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9);
03993 MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14);
03994 MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20);
03995 MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5);
03996 MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9);
03997 MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14);
03998 MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20);
03999
04000 MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4);
04001 MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11);
04002 MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16);
04003 MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23);
04004 MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4);
04005 MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11);
04006 MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16);
04007 MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23);
04008 MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4);
04009 MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11);
04010 MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16);
04011 MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23);
04012 MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4);
04013 MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11);
04014 MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16);
04015 MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23);
04016
04017 MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6);
04018 MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10);
04019 MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15);
04020 MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21);
04021 MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6);
04022 MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10);
04023 MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15);
04024 MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21);
04025 MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6);
04026 MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10);
04027 MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15);
04028 MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21);
04029 MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6);
04030 MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10);
04031 MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15);
04032 MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21);
04033
04034 buf[0] += a;
04035 buf[1] += b;
04036 buf[2] += c;
04037 buf[3] += d;
04038 }
04039
04040 static void MD5Update(MD5_CTX *ctx, unsigned char const *buf, unsigned len) {
04041 uint32_t t;
04042
04043 t = ctx->bits[0];
04044 if ((ctx->bits[0] = t + ((uint32_t) len << 3)) < t)
04045 ctx->bits[1]++;
04046 ctx->bits[1] += len >> 29;
04047
04048 t = (t >> 3) & 0x3f;
04049
04050 if (t) {
04051 unsigned char *p = (unsigned char *) ctx->in + t;
04052
04053 t = 64 - t;
04054 if (len < t) {
04055 memcpy(p, buf, len);
04056 return;
04057 }
04058 memcpy(p, buf, t);
04059 byteReverse(ctx->in, 16);
04060 MD5Transform(ctx->buf, (uint32_t *) ctx->in);
04061 buf += t;
04062 len -= t;
04063 }
04064
04065 while (len >= 64) {
04066 memcpy(ctx->in, buf, 64);
04067 byteReverse(ctx->in, 16);
04068 MD5Transform(ctx->buf, (uint32_t *) ctx->in);
04069 buf += 64;
04070 len -= 64;
04071 }
04072
04073 memcpy(ctx->in, buf, len);
04074 }
04075
04076 static void MD5Final(unsigned char digest[16], MD5_CTX *ctx) {
04077 unsigned count;
04078 unsigned char *p;
04079 uint32_t *a;
04080
04081 count = (ctx->bits[0] >> 3) & 0x3F;
04082
04083 p = ctx->in + count;
04084 *p++ = 0x80;
04085 count = 64 - 1 - count;
04086 if (count < 8) {
04087 memset(p, 0, count);
04088 byteReverse(ctx->in, 16);
04089 MD5Transform(ctx->buf, (uint32_t *) ctx->in);
04090 memset(ctx->in, 0, 56);
04091 } else {
04092 memset(p, 0, count - 8);
04093 }
04094 byteReverse(ctx->in, 14);
04095
04096 a = (uint32_t *)ctx->in;
04097 a[14] = ctx->bits[0];
04098 a[15] = ctx->bits[1];
04099
04100 MD5Transform(ctx->buf, (uint32_t *) ctx->in);
04101 byteReverse((unsigned char *) ctx->buf, 4);
04102 memcpy(digest, ctx->buf, 16);
04103 memset((char *) ctx, 0, sizeof(*ctx));
04104 }
04105 #endif // !HAVE_MD5
04106
04107
04108
04109
04110
04111 static void bin2str(char *to, const unsigned char *p, size_t len) {
04112 static const char *hex = "0123456789abcdef";
04113
04114 for (; len--; p++) {
04115 *to++ = hex[p[0] >> 4];
04116 *to++ = hex[p[0] & 0x0f];
04117 }
04118 *to = '\0';
04119 }
04120
04121
04122 char *mg_md5(char buf[33], ...) {
04123 unsigned char hash[16];
04124 const char *p;
04125 va_list ap;
04126 MD5_CTX ctx;
04127
04128 MD5Init(&ctx);
04129
04130 va_start(ap, buf);
04131 while ((p = va_arg(ap, const char *)) != NULL) {
04132 MD5Update(&ctx, (const unsigned char *) p, (unsigned) strlen(p));
04133 }
04134 va_end(ap);
04135
04136 MD5Final(hash, &ctx);
04137 bin2str(buf, hash, sizeof(hash));
04138 return buf;
04139 }
04140
04141
04142 static int check_password(const char *method, const char *ha1, const char *uri,
04143 const char *nonce, const char *nc, const char *cnonce,
04144 const char *qop, const char *response) {
04145 char ha2[32 + 1], expected_response[32 + 1];
04146
04147 #if 0
04148
04149 if ((unsigned long) time(NULL) - (unsigned long) to64(nonce) > 3600 * 2) {
04150 return 0;
04151 }
04152 #endif
04153
04154 mg_md5(ha2, method, ":", uri, NULL);
04155 mg_md5(expected_response, ha1, ":", nonce, ":", nc,
04156 ":", cnonce, ":", qop, ":", ha2, NULL);
04157
04158 return mg_strcasecmp(response, expected_response) == 0 ? MG_TRUE : MG_FALSE;
04159 }
04160
04161
04162
04163 int mg_authorize_digest(struct mg_connection *c, FILE *fp) {
04164 struct connection *conn = MG_CONN_2_CONN(c);
04165 const char *hdr;
04166 char line[256], f_user[256], ha1[256], f_domain[256], user[100], nonce[100],
04167 uri[MAX_REQUEST_SIZE], cnonce[100], resp[100], qop[100], nc[100];
04168
04169 if (c == NULL || fp == NULL) return 0;
04170 if ((hdr = mg_get_header(c, "Authorization")) == NULL ||
04171 mg_strncasecmp(hdr, "Digest ", 7) != 0) return 0;
04172 if (!mg_parse_header(hdr, "username", user, sizeof(user))) return 0;
04173 if (!mg_parse_header(hdr, "cnonce", cnonce, sizeof(cnonce))) return 0;
04174 if (!mg_parse_header(hdr, "response", resp, sizeof(resp))) return 0;
04175 if (!mg_parse_header(hdr, "uri", uri, sizeof(uri))) return 0;
04176 if (!mg_parse_header(hdr, "qop", qop, sizeof(qop))) return 0;
04177 if (!mg_parse_header(hdr, "nc", nc, sizeof(nc))) return 0;
04178 if (!mg_parse_header(hdr, "nonce", nonce, sizeof(nonce))) return 0;
04179
04180 while (fgets(line, sizeof(line), fp) != NULL) {
04181 if (sscanf(line, "%[^:]:%[^:]:%s", f_user, f_domain, ha1) == 3 &&
04182 !strcmp(user, f_user) &&
04183
04184 !strcmp(conn->server->config_options[AUTH_DOMAIN], f_domain))
04185 return check_password(c->request_method, ha1, uri,
04186 nonce, nc, cnonce, qop, resp);
04187 }
04188 return MG_FALSE;
04189 }
04190
04191
04192
04193 static int is_authorized(struct connection *conn, const char *path,
04194 int is_directory) {
04195 FILE *fp;
04196 int authorized = MG_TRUE;
04197
04198 if ((fp = open_auth_file(conn, path, is_directory)) != NULL) {
04199 authorized = mg_authorize_digest(&conn->mg_conn, fp);
04200 fclose(fp);
04201 }
04202
04203 return authorized;
04204 }
04205
04206 static int is_authorized_for_dav(struct connection *conn) {
04207 const char *auth_file = conn->server->config_options[DAV_AUTH_FILE];
04208 const char *method = conn->mg_conn.request_method;
04209 FILE *fp;
04210 int authorized = MG_FALSE;
04211
04212
04213 if (method != NULL && !strcmp(method, "PROPFIND") && auth_file == NULL) {
04214 authorized = MG_TRUE;
04215 } else if (auth_file != NULL && (fp = fopen(auth_file, "r")) != NULL) {
04216 authorized = mg_authorize_digest(&conn->mg_conn, fp);
04217 fclose(fp);
04218 }
04219
04220 return authorized;
04221 }
04222 #endif // MONGOOSE_NO_AUTH
04223
04224 static int parse_header(const char *str, size_t str_len, const char *var_name,
04225 char *buf, size_t buf_size) {
04226 int ch = ' ', ch1 = ',', len = 0;
04227 size_t n = strlen(var_name);
04228 const char *p, *end = str + str_len, *s = NULL;
04229
04230 if (buf != NULL && buf_size > 0) buf[0] = '\0';
04231
04232
04233 for (s = str; s != NULL && s + n < end; s++) {
04234 if ((s == str || s[-1] == ch || s[-1] == ch1) && s[n] == '=' &&
04235 !memcmp(s, var_name, n)) break;
04236 }
04237
04238 if (s != NULL && &s[n + 1] < end) {
04239 s += n + 1;
04240 if (*s == '"' || *s == '\'') ch = ch1 = *s++;
04241 p = s;
04242 while (p < end && p[0] != ch && p[0] != ch1 && len < (int) buf_size) {
04243 if (ch == ch1 && p[0] == '\\' && p[1] == ch) p++;
04244 buf[len++] = *p++;
04245 }
04246 if (len >= (int) buf_size || (ch != ' ' && *p != ch)) {
04247 len = 0;
04248 } else {
04249 if (len > 0 && s[len - 1] == ',') len--;
04250 if (len > 0 && s[len - 1] == ';') len--;
04251 buf[len] = '\0';
04252 }
04253 }
04254
04255 return len;
04256 }
04257
04258 int mg_parse_header(const char *s, const char *var_name, char *buf,
04259 size_t buf_size) {
04260 return parse_header(s, s == NULL ? 0 : strlen(s), var_name, buf, buf_size);
04261 }
04262
04263 #ifndef MONGOOSE_NO_SSI
04264 static void send_ssi_file(struct mg_connection *, const char *, FILE *, int);
04265
04266 static void send_file_data(struct mg_connection *conn, FILE *fp) {
04267 char buf[IOBUF_SIZE];
04268 size_t n;
04269 while ((n = fread(buf, 1, sizeof(buf), fp)) > 0) {
04270 mg_write(conn, buf, n);
04271 }
04272 }
04273
04274 static void do_ssi_include(struct mg_connection *conn, const char *ssi,
04275 char *tag, int include_level) {
04276 char file_name[IOBUF_SIZE], path[MAX_PATH_SIZE], *p;
04277 char **opts = (MG_CONN_2_CONN(conn))->server->config_options;
04278 FILE *fp;
04279
04280
04281
04282 if (sscanf(tag, " virtual=\"%[^\"]\"", file_name) == 1) {
04283
04284 mg_snprintf(path, sizeof(path), "%s%c%s",
04285 opts[DOCUMENT_ROOT], '/', file_name);
04286 } else if (sscanf(tag, " abspath=\"%[^\"]\"", file_name) == 1) {
04287
04288
04289 mg_snprintf(path, sizeof(path), "%s", file_name);
04290 } else if (sscanf(tag, " file=\"%[^\"]\"", file_name) == 1 ||
04291 sscanf(tag, " \"%[^\"]\"", file_name) == 1) {
04292
04293 mg_snprintf(path, sizeof(path), "%s", ssi);
04294 if ((p = strrchr(path, '/')) != NULL) {
04295 p[1] = '\0';
04296 }
04297 mg_snprintf(path + strlen(path), sizeof(path) - strlen(path), "%s",
04298 file_name);
04299 } else {
04300 mg_printf(conn, "Bad SSI #include: [%s]", tag);
04301 return;
04302 }
04303
04304 if ((fp = fopen(path, "rb")) == NULL) {
04305 mg_printf(conn, "Cannot open SSI #include: [%s]: fopen(%s): %s",
04306 tag, path, strerror(errno));
04307 } else {
04308 ns_set_close_on_exec(fileno(fp));
04309 if (mg_match_prefix(opts[SSI_PATTERN], strlen(opts[SSI_PATTERN]),
04310 path) > 0) {
04311 send_ssi_file(conn, path, fp, include_level + 1);
04312 } else {
04313 send_file_data(conn, fp);
04314 }
04315 fclose(fp);
04316 }
04317 }
04318
04319 #ifndef MONGOOSE_NO_POPEN
04320 static void do_ssi_exec(struct mg_connection *conn, char *tag) {
04321 char cmd[IOBUF_SIZE];
04322 FILE *fp;
04323
04324 if (sscanf(tag, " \"%[^\"]\"", cmd) != 1) {
04325 mg_printf(conn, "Bad SSI #exec: [%s]", tag);
04326 } else if ((fp = popen(cmd, "r")) == NULL) {
04327 mg_printf(conn, "Cannot SSI #exec: [%s]: %s", cmd, strerror(errno));
04328 } else {
04329 send_file_data(conn, fp);
04330 pclose(fp);
04331 }
04332 }
04333 #endif // !MONGOOSE_NO_POPEN
04334
04335 static void send_ssi_file(struct mg_connection *conn, const char *path,
04336 FILE *fp, int include_level) {
04337 char buf[IOBUF_SIZE];
04338 int ch, offset, len, in_ssi_tag;
04339
04340 if (include_level > 10) {
04341 mg_printf(conn, "SSI #include level is too deep (%s)", path);
04342 return;
04343 }
04344
04345 in_ssi_tag = len = offset = 0;
04346 while ((ch = fgetc(fp)) != EOF) {
04347 if (in_ssi_tag && ch == '>') {
04348 in_ssi_tag = 0;
04349 buf[len++] = (char) ch;
04350 buf[len] = '\0';
04351 assert(len <= (int) sizeof(buf));
04352 if (len < 6 || memcmp(buf, "<!--#", 5) != 0) {
04353
04354 (void) mg_write(conn, buf, (size_t) len);
04355 } else {
04356 if (!memcmp(buf + 5, "include", 7)) {
04357 do_ssi_include(conn, path, buf + 12, include_level);
04358 #if !defined(MONGOOSE_NO_POPEN)
04359 } else if (!memcmp(buf + 5, "exec", 4)) {
04360 do_ssi_exec(conn, buf + 9);
04361 #endif // !NO_POPEN
04362 } else {
04363 mg_printf(conn, "%s: unknown SSI " "command: \"%s\"", path, buf);
04364 }
04365 }
04366 len = 0;
04367 } else if (in_ssi_tag) {
04368 if (len == 5 && memcmp(buf, "<!--#", 5) != 0) {
04369
04370 in_ssi_tag = 0;
04371 } else if (len == (int) sizeof(buf) - 2) {
04372 mg_printf(conn, "%s: SSI tag is too large", path);
04373 len = 0;
04374 }
04375 buf[len++] = ch & 0xff;
04376 } else if (ch == '<') {
04377 in_ssi_tag = 1;
04378 if (len > 0) {
04379 mg_write(conn, buf, (size_t) len);
04380 }
04381 len = 0;
04382 buf[len++] = ch & 0xff;
04383 } else {
04384 buf[len++] = ch & 0xff;
04385 if (len == (int) sizeof(buf)) {
04386 mg_write(conn, buf, (size_t) len);
04387 len = 0;
04388 }
04389 }
04390 }
04391
04392
04393 if (len > 0) {
04394 mg_write(conn, buf, (size_t) len);
04395 }
04396 }
04397
04398 static void handle_ssi_request(struct connection *conn, const char *path) {
04399 FILE *fp;
04400 struct vec mime_vec;
04401
04402 if ((fp = fopen(path, "rb")) == NULL) {
04403 send_http_error(conn, 500, "fopen(%s): %s", path, strerror(errno));
04404 } else {
04405 ns_set_close_on_exec(fileno(fp));
04406 get_mime_type(conn->server, path, &mime_vec);
04407 conn->mg_conn.status_code = 200;
04408 mg_printf(&conn->mg_conn,
04409 "HTTP/1.1 %d OK\r\n"
04410 "Content-Type: %.*s\r\n"
04411 "Connection: close\r\n\r\n",
04412 conn->mg_conn.status_code, (int) mime_vec.len, mime_vec.ptr);
04413 send_ssi_file(&conn->mg_conn, path, fp, 0);
04414 fclose(fp);
04415 close_local_endpoint(conn);
04416 }
04417 }
04418 #endif
04419
04420 static void proxy_request(struct ns_connection *pc, struct mg_connection *c) {
04421 int i, sent_close_header = 0;
04422
04423 ns_printf(pc, "%s %s%s%s HTTP/%s\r\n", c->request_method, c->uri,
04424 c->query_string ? "?" : "",
04425 c->query_string ? c->query_string : "",
04426 c->http_version);
04427 for (i = 0; i < c->num_headers; i++) {
04428 if (mg_strcasecmp(c->http_headers[i].name, "Connection") == 0) {
04429
04430
04431 ns_printf(pc, "%s: %s\r\n", "Connection", "close");
04432 sent_close_header = 1;
04433 } else {
04434 ns_printf(pc, "%s: %s\r\n", c->http_headers[i].name,
04435 c->http_headers[i].value);
04436 }
04437 }
04438 if (!sent_close_header) {
04439 ns_printf(pc, "%s: %s\r\n", "Connection", "close");
04440 }
04441 ns_printf(pc, "%s", "\r\n");
04442 ns_send(pc, c->content, c->content_len);
04443
04444 }
04445
04446 #ifdef NS_ENABLE_SSL
04447 int mg_terminate_ssl(struct mg_connection *c, const char *cert) {
04448 static const char ok[] = "HTTP/1.0 200 OK\r\n\r\n";
04449 struct connection *conn = MG_CONN_2_CONN(c);
04450 SSL_CTX *ctx;
04451
04452 DBG(("%p MITM", conn));
04453 if ((ctx = SSL_CTX_new(SSLv23_server_method())) == NULL) return 0;
04454
04455 SSL_CTX_use_certificate_file(ctx, cert, 1);
04456 SSL_CTX_use_PrivateKey_file(ctx, cert, 1);
04457 SSL_CTX_use_certificate_chain_file(ctx, cert);
04458
04459
04460
04461 send(conn->ns_conn->sock, ok, sizeof(ok) - 1, 0);
04462
04463 conn->ns_conn->send_iobuf.len = 0;
04464 conn->endpoint_type = EP_USER;
04465 close_local_endpoint(conn);
04466 if ((conn->ns_conn->ssl = SSL_new(ctx)) != NULL) {
04467 SSL_set_fd(conn->ns_conn->ssl, conn->ns_conn->sock);
04468 }
04469 SSL_CTX_free(ctx);
04470 return 1;
04471 }
04472 #endif
04473
04474 int mg_forward(struct mg_connection *c, const char *addr) {
04475 static const char ok[] = "HTTP/1.1 200 OK\r\n\r\n";
04476 struct connection *conn = MG_CONN_2_CONN(c);
04477 struct ns_connection *pc;
04478
04479 if ((pc = ns_connect(&conn->server->ns_mgr, addr,
04480 mg_ev_handler, conn)) == NULL) {
04481 conn->ns_conn->flags |= NSF_CLOSE_IMMEDIATELY;
04482 return 0;
04483 }
04484
04485
04486 pc->flags |= MG_PROXY_CONN;
04487 conn->endpoint_type = EP_PROXY;
04488 conn->endpoint.nc = pc;
04489 DBG(("%p [%s] [%s] -> %p %p", conn, c->uri, addr, pc, conn->ns_conn->ssl));
04490
04491 if (strcmp(c->request_method, "CONNECT") == 0) {
04492
04493
04494 (void) send(conn->ns_conn->sock, ok, sizeof(ok) - 1, 0);
04495 } else {
04496
04497 if (memcmp(c->uri, "http://", 7) == 0) c->uri += 7;
04498 while (*c->uri != '\0' && *c->uri != '/') c->uri++;
04499 proxy_request(pc, c);
04500 }
04501 return 1;
04502 }
04503
04504 static void proxify_connection(struct connection *conn) {
04505 char proto[10], host[500], cert[500], addr[1000];
04506 unsigned short port = 80;
04507 struct mg_connection *c = &conn->mg_conn;
04508 int n = 0;
04509 const char *url = c->uri;
04510
04511 proto[0] = host[0] = cert[0] = '\0';
04512 if (sscanf(url, "%499[^: ]:%hu%n", host, &port, &n) != 2 &&
04513 sscanf(url, "%9[a-z]://%499[^: ]:%hu%n", proto, host, &port, &n) != 3 &&
04514 sscanf(url, "%9[a-z]://%499[^/ ]%n", proto, host, &n) != 2) {
04515 n = 0;
04516 }
04517
04518 snprintf(addr, sizeof(addr), "%s://%s:%hu",
04519 conn->ns_conn->ssl != NULL ? "ssl" : "tcp", host, port);
04520 if (n <= 0 || !mg_forward(c, addr)) {
04521 conn->ns_conn->flags |= NSF_CLOSE_IMMEDIATELY;
04522 }
04523 }
04524
04525 #ifndef MONGOOSE_NO_FILESYSTEM
04526 void mg_send_file_internal(struct mg_connection *c, const char *file_name,
04527 file_stat_t *st, int exists,
04528 const char *extra_headers) {
04529 struct connection *conn = MG_CONN_2_CONN(c);
04530 char path[MAX_PATH_SIZE];
04531 const int is_directory = S_ISDIR(st->st_mode);
04532 #ifndef MONGOOSE_NO_CGI
04533 const char *cgi_pat = conn->server->config_options[CGI_PATTERN];
04534 #else
04535 const char *cgi_pat = DEFAULT_CGI_PATTERN;
04536 #endif
04537 #ifndef MONGOOSE_NO_DIRECTORY_LISTING
04538 const char *dir_lst = conn->server->config_options[ENABLE_DIRECTORY_LISTING];
04539 #else
04540 const char *dir_lst = "yes";
04541 #endif
04542
04543 mg_snprintf(path, sizeof(path), "%s", file_name);
04544
04545 if (!exists || must_hide_file(conn, path)) {
04546 send_http_error(conn, 404, NULL);
04547 } else if (is_directory &&
04548 conn->mg_conn.uri[strlen(conn->mg_conn.uri) - 1] != '/') {
04549 conn->mg_conn.status_code = 301;
04550 mg_printf(&conn->mg_conn, "HTTP/1.1 301 Moved Permanently\r\n"
04551 "Location: %s/\r\n\r\n", conn->mg_conn.uri);
04552 close_local_endpoint(conn);
04553 } else if (is_directory && !find_index_file(conn, path, sizeof(path), st)) {
04554 if (!mg_strcasecmp(dir_lst, "yes")) {
04555 #ifndef MONGOOSE_NO_DIRECTORY_LISTING
04556 send_directory_listing(conn, path);
04557 #else
04558 send_http_error(conn, 501, NULL);
04559 #endif
04560 } else {
04561 send_http_error(conn, 403, NULL);
04562 }
04563 } else if (mg_match_prefix(cgi_pat, strlen(cgi_pat), path) > 0) {
04564 #if !defined(MONGOOSE_NO_CGI)
04565 open_cgi_endpoint(conn, path);
04566 #else
04567 send_http_error(conn, 501, NULL);
04568 #endif // !MONGOOSE_NO_CGI
04569 #ifndef MONGOOSE_NO_SSI
04570 } else if (mg_match_prefix(conn->server->config_options[SSI_PATTERN],
04571 strlen(conn->server->config_options[SSI_PATTERN]),
04572 path) > 0) {
04573 handle_ssi_request(conn, path);
04574 #endif
04575 } else if (is_not_modified(conn, st)) {
04576 send_http_error(conn, 304, NULL);
04577 } else if ((conn->endpoint.fd = open(path, O_RDONLY | O_BINARY, 0)) != -1) {
04578
04579
04580 open_file_endpoint(conn, path, st, extra_headers);
04581 } else {
04582 send_http_error(conn, 404, NULL);
04583 }
04584 }
04585 void mg_send_file(struct mg_connection *c, const char *file_name,
04586 const char *extra_headers) {
04587 file_stat_t st;
04588 const int exists = stat(file_name, &st) == 0;
04589 mg_send_file_internal(c, file_name, &st, exists, extra_headers);
04590 }
04591 #endif // !MONGOOSE_NO_FILESYSTEM
04592
04593 static void open_local_endpoint(struct connection *conn, int skip_user) {
04594 #ifndef MONGOOSE_NO_FILESYSTEM
04595 char path[MAX_PATH_SIZE];
04596 file_stat_t st;
04597 int exists = 0;
04598 #endif
04599
04600
04601 conn->endpoint_type = EP_NONE;
04602
04603 #ifndef MONGOOSE_NO_AUTH
04604 if (conn->server->event_handler && call_user(conn, MG_AUTH) == MG_FALSE) {
04605 mg_send_digest_auth_request(&conn->mg_conn);
04606 return;
04607 }
04608 #endif
04609
04610
04611 if (skip_user == 0 && conn->server->event_handler != NULL) {
04612 conn->endpoint_type = EP_USER;
04613 #if MONGOOSE_POST_SIZE_LIMIT > 1
04614 {
04615 const char *cl = mg_get_header(&conn->mg_conn, "Content-Length");
04616 if ((strcmp(conn->mg_conn.request_method, "POST") == 0 ||
04617 strcmp(conn->mg_conn.request_method, "PUT") == 0) &&
04618 (cl == NULL || to64(cl) > MONGOOSE_POST_SIZE_LIMIT)) {
04619 send_http_error(conn, 500, "POST size > %lu",
04620 (unsigned long) MONGOOSE_POST_SIZE_LIMIT);
04621 }
04622 }
04623 #endif
04624 return;
04625 }
04626
04627 if (strcmp(conn->mg_conn.request_method, "CONNECT") == 0 ||
04628 mg_strncasecmp(conn->mg_conn.uri, "http", 4) == 0) {
04629 const char *enp = conn->server->config_options[ENABLE_PROXY];
04630 if (enp == NULL || strcmp(enp, "yes") != 0) {
04631 send_http_error(conn, 405, NULL);
04632 } else {
04633 proxify_connection(conn);
04634 }
04635 return;
04636 }
04637
04638 if (!strcmp(conn->mg_conn.request_method, "OPTIONS")) {
04639 send_options(conn);
04640 return;
04641 }
04642
04643 #ifdef MONGOOSE_NO_FILESYSTEM
04644 send_http_error(conn, 404, NULL);
04645 #else
04646 exists = convert_uri_to_file_name(conn, path, sizeof(path), &st);
04647
04648 if (!strcmp(conn->mg_conn.request_method, "OPTIONS")) {
04649 send_options(conn);
04650 } else if (conn->server->config_options[DOCUMENT_ROOT] == NULL) {
04651 send_http_error(conn, 404, NULL);
04652 #ifndef MONGOOSE_NO_AUTH
04653 } else if ((!is_dav_request(conn) && !is_authorized(conn, path,
04654 exists && S_ISDIR(st.st_mode))) ||
04655 (is_dav_request(conn) && !is_authorized_for_dav(conn))) {
04656 mg_send_digest_auth_request(&conn->mg_conn);
04657 close_local_endpoint(conn);
04658 #endif
04659 #ifndef MONGOOSE_NO_DAV
04660 } else if (must_hide_file(conn, path)) {
04661 send_http_error(conn, 404, NULL);
04662 } else if (!strcmp(conn->mg_conn.request_method, "PROPFIND")) {
04663 handle_propfind(conn, path, &st, exists);
04664 } else if (!strcmp(conn->mg_conn.request_method, "MKCOL")) {
04665 handle_mkcol(conn, path);
04666 } else if (!strcmp(conn->mg_conn.request_method, "DELETE")) {
04667 handle_delete(conn, path);
04668 } else if (!strcmp(conn->mg_conn.request_method, "PUT")) {
04669 handle_put(conn, path);
04670 #endif
04671 } else {
04672 mg_send_file_internal(&conn->mg_conn, path, &st, exists, NULL);
04673 }
04674 #endif // MONGOOSE_NO_FILESYSTEM
04675 }
04676
04677 static void send_continue_if_expected(struct connection *conn) {
04678 static const char expect_response[] = "HTTP/1.1 100 Continue\r\n\r\n";
04679 const char *expect_hdr = mg_get_header(&conn->mg_conn, "Expect");
04680
04681 if (expect_hdr != NULL && !mg_strcasecmp(expect_hdr, "100-continue")) {
04682 ns_send(conn->ns_conn, expect_response, sizeof(expect_response) - 1);
04683 }
04684 }
04685
04686
04687 static int is_valid_uri(const char *uri) {
04688 unsigned short n;
04689 return uri[0] == '/' ||
04690 strcmp(uri, "*") == 0 ||
04691 mg_strncasecmp(uri, "http", 4) == 0 ||
04692 sscanf(uri, "%*[^ :]:%hu", &n) > 0;
04693 }
04694
04695 static void try_parse(struct connection *conn) {
04696 struct iobuf *io = &conn->ns_conn->recv_iobuf;
04697
04698 if (conn->request_len == 0 &&
04699 (conn->request_len = get_request_len(io->buf, io->len)) > 0) {
04700
04701
04702
04703 conn->request = (char *) NS_MALLOC(conn->request_len);
04704 if (conn->request == NULL) {
04705 conn->ns_conn->flags |= NSF_CLOSE_IMMEDIATELY;
04706 return;
04707 }
04708 memcpy(conn->request, io->buf, conn->request_len);
04709
04710 iobuf_remove(io, conn->request_len);
04711 conn->request_len = parse_http_message(conn->request, conn->request_len,
04712 &conn->mg_conn);
04713 if (conn->request_len > 0) {
04714 const char *cl_hdr = mg_get_header(&conn->mg_conn, "Content-Length");
04715 conn->cl = cl_hdr == NULL ? 0 : to64(cl_hdr);
04716 conn->mg_conn.content_len = (size_t) conn->cl;
04717 }
04718 }
04719 }
04720
04721 static void do_proxy(struct connection *conn) {
04722 if (0 && conn->request_len == 0) {
04723 try_parse(conn);
04724 DBG(("%p parsing -> %d", conn, conn->request_len));
04725 if (conn->request_len > 0 && call_user(conn, MG_REQUEST) == MG_FALSE) {
04726 proxy_request(conn->endpoint.nc, &conn->mg_conn);
04727 } else if (conn->request_len < 0) {
04728 ns_forward(conn->ns_conn, conn->endpoint.nc);
04729 }
04730 } else {
04731 DBG(("%p forwarding", conn));
04732 ns_forward(conn->ns_conn, conn->endpoint.nc);
04733 }
04734 }
04735
04736 static void on_recv_data(struct connection *conn) {
04737 struct iobuf *io = &conn->ns_conn->recv_iobuf;
04738 int n;
04739
04740 if (conn->endpoint_type == EP_PROXY) {
04741 if (conn->endpoint.nc != NULL) do_proxy(conn);
04742 return;
04743 }
04744
04745 try_parse(conn);
04746 DBG(("%p %d %lu %d", conn, conn->request_len, (unsigned long)io->len,
04747 conn->ns_conn->flags));
04748 if (conn->request_len < 0 ||
04749 (conn->request_len > 0 && !is_valid_uri(conn->mg_conn.uri))) {
04750 send_http_error(conn, 400, NULL);
04751 } else if (conn->request_len == 0 && io->len > MAX_REQUEST_SIZE) {
04752 send_http_error(conn, 413, NULL);
04753 } else if (conn->request_len > 0 &&
04754 strcmp(conn->mg_conn.http_version, "1.0") != 0 &&
04755 strcmp(conn->mg_conn.http_version, "1.1") != 0) {
04756 send_http_error(conn, 505, NULL);
04757 } else if (conn->request_len > 0 && conn->endpoint_type == EP_NONE) {
04758 #ifndef MONGOOSE_NO_WEBSOCKET
04759 send_websocket_handshake_if_requested(&conn->mg_conn);
04760 #endif
04761 send_continue_if_expected(conn);
04762 open_local_endpoint(conn, 0);
04763 }
04764
04765 #ifndef MONGOOSE_NO_CGI
04766 if (conn->endpoint_type == EP_CGI && conn->endpoint.nc != NULL) {
04767 ns_forward(conn->ns_conn, conn->endpoint.nc);
04768 }
04769 #endif
04770 if (conn->endpoint_type == EP_USER) {
04771 conn->mg_conn.content = io->buf;
04772 conn->mg_conn.content_len = io->len;
04773 n = call_user(conn, MG_RECV);
04774 if (n < 0) {
04775 conn->ns_conn->flags |= NSF_FINISHED_SENDING_DATA;
04776 } else if ((size_t) n <= io->len) {
04777 iobuf_remove(io, n);
04778 }
04779 call_request_handler_if_data_is_buffered(conn);
04780 }
04781 #ifndef MONGOOSE_NO_DAV
04782 if (conn->endpoint_type == EP_PUT && io->len > 0) {
04783 forward_put_data(conn);
04784 }
04785 #endif
04786 }
04787
04788 static void call_http_client_handler(struct connection *conn) {
04789
04790
04791 if (conn->cl == 0) {
04792 conn->mg_conn.content_len = conn->ns_conn->recv_iobuf.len;
04793 }
04794 conn->mg_conn.content = conn->ns_conn->recv_iobuf.buf;
04795 if (call_user(conn, MG_REPLY) == MG_FALSE) {
04796 conn->ns_conn->flags |= NSF_CLOSE_IMMEDIATELY;
04797 }
04798 iobuf_remove(&conn->ns_conn->recv_iobuf, conn->mg_conn.content_len);
04799 conn->mg_conn.status_code = 0;
04800 conn->cl = conn->num_bytes_recv = conn->request_len = 0;
04801 NS_FREE(conn->request);
04802 conn->request = NULL;
04803 }
04804
04805 static void process_response(struct connection *conn) {
04806 struct iobuf *io = &conn->ns_conn->recv_iobuf;
04807
04808 try_parse(conn);
04809 DBG(("%p %d %lu", conn, conn->request_len, (unsigned long)io->len));
04810 if (conn->request_len < 0 ||
04811 (conn->request_len == 0 && io->len > MAX_REQUEST_SIZE)) {
04812 call_http_client_handler(conn);
04813 } else if ((int64_t) io->len >= conn->cl) {
04814 call_http_client_handler(conn);
04815 }
04816 }
04817
04818 struct mg_connection *mg_connect(struct mg_server *server, const char *addr) {
04819 struct ns_connection *nsconn;
04820 struct connection *conn;
04821
04822 nsconn = ns_connect(&server->ns_mgr, addr, mg_ev_handler, NULL);
04823 if (nsconn == NULL) return 0;
04824
04825 if ((conn = (struct connection *) NS_CALLOC(1, sizeof(*conn))) == NULL) {
04826 nsconn->flags |= NSF_CLOSE_IMMEDIATELY;
04827 return 0;
04828 }
04829
04830
04831 conn->ns_conn = nsconn;
04832 nsconn->user_data = conn;
04833
04834 conn->server = server;
04835 conn->endpoint_type = EP_CLIENT;
04836
04837 conn->mg_conn.server_param = server->ns_mgr.user_data;
04838 conn->ns_conn->flags = NSF_CONNECTING;
04839
04840 return &conn->mg_conn;
04841 }
04842
04843 #ifndef MONGOOSE_NO_LOGGING
04844 static void log_header(const struct mg_connection *conn, const char *header,
04845 FILE *fp) {
04846 const char *header_value;
04847
04848 if ((header_value = mg_get_header(conn, header)) == NULL) {
04849 (void) fprintf(fp, "%s", " -");
04850 } else {
04851 (void) fprintf(fp, " \"%s\"", header_value);
04852 }
04853 }
04854
04855 static void log_access(const struct connection *conn, const char *path) {
04856 const struct mg_connection *c = &conn->mg_conn;
04857 FILE *fp = (path == NULL) ? NULL : fopen(path, "a+");
04858 char date[64], user[100];
04859 time_t now;
04860
04861 if (fp == NULL) return;
04862 now = time(NULL);
04863 strftime(date, sizeof(date), "%d/%b/%Y:%H:%M:%S %z", localtime(&now));
04864
04865 flockfile(fp);
04866 mg_parse_header(mg_get_header(&conn->mg_conn, "Authorization"), "username",
04867 user, sizeof(user));
04868 fprintf(fp, "%s - %s [%s] \"%s %s%s%s HTTP/%s\" %d 0",
04869 c->remote_ip, user[0] == '\0' ? "-" : user, date,
04870 c->request_method ? c->request_method : "-",
04871 c->uri ? c->uri : "-", c->query_string ? "?" : "",
04872 c->query_string ? c->query_string : "",
04873 c->http_version, c->status_code);
04874 log_header(c, "Referer", fp);
04875 log_header(c, "User-Agent", fp);
04876 fputc('\n', fp);
04877 fflush(fp);
04878
04879 funlockfile(fp);
04880 fclose(fp);
04881 }
04882 #endif
04883
04884 static void close_local_endpoint(struct connection *conn) {
04885 struct mg_connection *c = &conn->mg_conn;
04886
04887 int keep_alive = should_keep_alive(&conn->mg_conn) &&
04888 (conn->endpoint_type == EP_FILE || conn->endpoint_type == EP_USER);
04889 DBG(("%p %d %d %d", conn, conn->endpoint_type, keep_alive,
04890 conn->ns_conn->flags));
04891
04892 switch (conn->endpoint_type) {
04893 case EP_PUT:
04894 case EP_FILE:
04895 close(conn->endpoint.fd);
04896 break;
04897 case EP_CGI:
04898 case EP_PROXY:
04899 if (conn->endpoint.nc != NULL) {
04900 DBG(("%p %p %p :-)", conn, conn->ns_conn, conn->endpoint.nc));
04901 conn->endpoint.nc->flags |= NSF_CLOSE_IMMEDIATELY;
04902 conn->endpoint.nc->user_data = NULL;
04903 }
04904 break;
04905 default: break;
04906 }
04907
04908 #ifndef MONGOOSE_NO_LOGGING
04909 if (c->status_code > 0 && conn->endpoint_type != EP_CLIENT &&
04910 c->status_code != 400) {
04911 log_access(conn, conn->server->config_options[ACCESS_LOG_FILE]);
04912 }
04913 #endif
04914
04915
04916 iobuf_free(&conn->ns_conn->recv_iobuf);
04917 NS_FREE(conn->request);
04918 NS_FREE(conn->path_info);
04919 conn->endpoint.nc = NULL;
04920 conn->request = conn->path_info = NULL;
04921
04922 conn->endpoint_type = EP_NONE;
04923 conn->cl = conn->num_bytes_recv = conn->request_len = 0;
04924 conn->ns_conn->flags &= ~(NSF_FINISHED_SENDING_DATA |
04925 NSF_BUFFER_BUT_DONT_SEND | NSF_CLOSE_IMMEDIATELY |
04926 MG_HEADERS_SENT | MG_USING_CHUNKED_API);
04927
04928
04929
04930 c->request_method = c->uri = c->http_version = c->query_string = NULL;
04931 c->num_headers = c->status_code = c->is_websocket = c->content_len = 0;
04932 c->connection_param = c->callback_param = NULL;
04933
04934 if (keep_alive) {
04935 on_recv_data(conn);
04936 } else {
04937 conn->ns_conn->flags |= conn->ns_conn->send_iobuf.len == 0 ?
04938 NSF_CLOSE_IMMEDIATELY : NSF_FINISHED_SENDING_DATA;
04939 }
04940 }
04941
04942 static void transfer_file_data(struct connection *conn) {
04943 char buf[IOBUF_SIZE];
04944 size_t n;
04945
04946
04947
04948 if (conn->ns_conn->send_iobuf.len > sizeof(buf) * 2) return;
04949
04950
04951 n = read(conn->endpoint.fd, buf, conn->cl < (int64_t) sizeof(buf) ?
04952 (int) conn->cl : (int) sizeof(buf));
04953
04954 if (n <= 0) {
04955 close_local_endpoint(conn);
04956 } else if (n > 0) {
04957 conn->cl -= n;
04958 ns_send(conn->ns_conn, buf, n);
04959 if (conn->cl <= 0) {
04960 close_local_endpoint(conn);
04961 }
04962 }
04963 }
04964
04965 time_t mg_poll_server(struct mg_server *server, int milliseconds) {
04966 return ns_mgr_poll(&server->ns_mgr, milliseconds);
04967 }
04968
04969 void mg_destroy_server(struct mg_server **server) {
04970 if (server != NULL && *server != NULL) {
04971 struct mg_server *s = *server;
04972 int i;
04973
04974 ns_mgr_free(&s->ns_mgr);
04975 for (i = 0; i < (int) ARRAY_SIZE(s->config_options); i++) {
04976 NS_FREE(s->config_options[i]);
04977 }
04978 NS_FREE(s);
04979 *server = NULL;
04980 }
04981 }
04982
04983 struct mg_connection *mg_next(struct mg_server *s, struct mg_connection *c) {
04984 struct ns_connection *nc = ns_next(&s->ns_mgr, c == NULL ? NULL :
04985 MG_CONN_2_CONN(c)->ns_conn);
04986 if (nc != NULL && nc->user_data != NULL) {
04987 return & ((struct connection *) nc->user_data)->mg_conn;
04988 } else {
04989 return NULL;
04990 }
04991 }
04992
04993 static int get_var(const char *data, size_t data_len, const char *name,
04994 char *dst, size_t dst_len) {
04995 const char *p, *e, *s;
04996 size_t name_len;
04997 int len;
04998
04999 if (dst == NULL || dst_len == 0) {
05000 len = -2;
05001 } else if (data == NULL || name == NULL || data_len == 0) {
05002 len = -1;
05003 dst[0] = '\0';
05004 } else {
05005 name_len = strlen(name);
05006 e = data + data_len;
05007 len = -1;
05008 dst[0] = '\0';
05009
05010
05011 for (p = data; p + name_len < e; p++) {
05012 if ((p == data || p[-1] == '&') && p[name_len] == '=' &&
05013 !mg_strncasecmp(name, p, name_len)) {
05014
05015
05016 p += name_len + 1;
05017
05018
05019 s = (const char *) memchr(p, '&', (size_t)(e - p));
05020 if (s == NULL) {
05021 s = e;
05022 }
05023 assert(s >= p);
05024
05025
05026 len = mg_url_decode(p, (size_t)(s - p), dst, dst_len, 1);
05027
05028
05029 if (len == -1) {
05030 len = -2;
05031 }
05032 break;
05033 }
05034 }
05035 }
05036
05037 return len;
05038 }
05039
05040 int mg_get_var(const struct mg_connection *conn, const char *name,
05041 char *dst, size_t dst_len) {
05042 int len = get_var(conn->query_string, conn->query_string == NULL ? 0 :
05043 strlen(conn->query_string), name, dst, dst_len);
05044 if (len < 0) {
05045 len = get_var(conn->content, conn->content_len, name, dst, dst_len);
05046 }
05047 return len;
05048 }
05049
05050 static int get_line_len(const char *buf, int buf_len) {
05051 int len = 0;
05052 while (len < buf_len && buf[len] != '\n') len++;
05053 return buf[len] == '\n' ? len + 1: -1;
05054 }
05055
05056 int mg_parse_multipart(const char *buf, int buf_len,
05057 char *var_name, int var_name_len,
05058 char *file_name, int file_name_len,
05059 const char **data, int *data_len) {
05060 static const char cd[] = "Content-Disposition: ";
05061
05062 int hl, bl, n, ll, pos, cdl = sizeof(cd) - 1;
05063
05064
05065 if (buf == NULL || buf_len <= 0) return 0;
05066 if ((hl = get_request_len(buf, buf_len)) <= 0) return 0;
05067 if (buf[0] != '-' || buf[1] != '-' || buf[2] == '\n') return 0;
05068
05069
05070 bl = get_line_len(buf, buf_len);
05071
05072
05073 var_name[0] = file_name[0] = '\0';
05074 for (n = bl; (ll = get_line_len(buf + n, hl - n)) > 0; n += ll) {
05075 if (mg_strncasecmp(cd, buf + n, cdl) == 0) {
05076 parse_header(buf + n + cdl, ll - (cdl + 2), "name",
05077 var_name, var_name_len);
05078 parse_header(buf + n + cdl, ll - (cdl + 2), "filename",
05079 file_name, file_name_len);
05080 }
05081 }
05082
05083
05084 for (pos = hl; pos + (bl - 2) < buf_len; pos++) {
05085 if (buf[pos] == '-' && !memcmp(buf, &buf[pos], bl - 2)) {
05086 if (data_len != NULL) *data_len = (pos - 2) - hl;
05087 if (data != NULL) *data = buf + hl;
05088 return pos;
05089 }
05090 }
05091
05092 return 0;
05093 }
05094
05095 const char **mg_get_valid_option_names(void) {
05096 return static_config_options;
05097 }
05098
05099 void mg_copy_listeners(struct mg_server *s, struct mg_server *to) {
05100 struct ns_connection *c;
05101 for (c = ns_next(&s->ns_mgr, NULL); c != NULL; c = ns_next(&s->ns_mgr, c)) {
05102 struct ns_connection *tmp;
05103 if ((c->flags & NSF_LISTENING) &&
05104 (tmp = (struct ns_connection *) NS_MALLOC(sizeof(*tmp))) != NULL) {
05105 memcpy(tmp, c, sizeof(*tmp));
05106
05107 #if defined(NS_ENABLE_SSL) && defined(HEADER_SSL_H)
05108
05109 if (tmp->ssl_ctx != NULL) {
05110 tmp->ssl_ctx->references++;
05111 }
05112 #endif
05113
05114 tmp->mgr = &to->ns_mgr;
05115 ns_add_conn(tmp->mgr, tmp);
05116 }
05117 }
05118 }
05119
05120 static int get_option_index(const char *name) {
05121 int i;
05122
05123 for (i = 0; static_config_options[i * 2] != NULL; i++) {
05124 if (strcmp(static_config_options[i * 2], name) == 0) {
05125 return i;
05126 }
05127 }
05128 return -1;
05129 }
05130
05131 static void set_default_option_values(char **opts) {
05132 const char *value, **all_opts = mg_get_valid_option_names();
05133 int i;
05134
05135 for (i = 0; all_opts[i * 2] != NULL; i++) {
05136 value = all_opts[i * 2 + 1];
05137 if (opts[i] == NULL && value != NULL) {
05138 opts[i] = mg_strdup(value);
05139 }
05140 }
05141 }
05142
05143 const char *mg_set_option(struct mg_server *server, const char *name,
05144 const char *value) {
05145 int ind = get_option_index(name);
05146 const char *error_msg = NULL;
05147 char **v = NULL;
05148
05149 if (ind < 0) return "No such option";
05150 v = &server->config_options[ind];
05151
05152
05153 if ((*v == NULL && value == NULL) ||
05154 (value != NULL && *v != NULL && !strcmp(value, *v))) {
05155 return NULL;
05156 }
05157
05158 if (*v != NULL) {
05159 NS_FREE(*v);
05160 *v = NULL;
05161 }
05162
05163 if (value == NULL || value[0] == '\0') return NULL;
05164
05165 *v = mg_strdup(value);
05166 DBG(("%s [%s]", name, *v));
05167
05168 if (ind == LISTENING_PORT) {
05169 char buf[500] = "";
05170 size_t n = 0;
05171 struct vec vec;
05172
05173
05174
05175
05176
05177
05178 while ((value = next_option(value, &vec, NULL)) != NULL) {
05179 struct ns_connection *c = ns_bind(&server->ns_mgr, vec.ptr,
05180 mg_ev_handler, NULL);
05181 if (c == NULL) {
05182 error_msg = "Cannot bind to port";
05183 break;
05184 } else {
05185 char buf2[50], cert[100], ca[100];
05186 union socket_address sa;
05187 int proto, use_ssl;
05188
05189 ns_parse_address(vec.ptr, &sa, &proto, &use_ssl, cert, ca);
05190 ns_sock_to_str(c->sock, buf2, sizeof(buf2),
05191 memchr(vec.ptr, ':', vec.len) == NULL ? 2 : 3);
05192
05193 n += snprintf(buf + n, sizeof(buf) - n, "%s%s%s%s%s%s%s",
05194 n > 0 ? "," : "",
05195 use_ssl ? "ssl://" : "",
05196 buf2, cert[0] ? ":" : "", cert, ca[0] ? ":" : "", ca);
05197 }
05198 }
05199 buf[sizeof(buf) - 1] = '\0';
05200 NS_FREE(*v);
05201 *v = mg_strdup(buf);
05202 #ifndef MONGOOSE_NO_FILESYSTEM
05203 } else if (ind == HEXDUMP_FILE) {
05204 server->ns_mgr.hexdump_file = *v;
05205 #endif
05206 #if !defined(_WIN32) && !defined(MONGOOSE_NO_USER)
05207 } else if (ind == RUN_AS_USER) {
05208 struct passwd *pw;
05209 if ((pw = getpwnam(value)) == NULL) {
05210 error_msg = "Unknown user";
05211 } else if (setgid(pw->pw_gid) != 0) {
05212 error_msg = "setgid() failed";
05213 } else if (setuid(pw->pw_uid) != 0) {
05214 error_msg = "setuid() failed";
05215 }
05216 #endif
05217 }
05218
05219 return error_msg;
05220 }
05221
05222 static void set_ips(struct ns_connection *nc, int is_rem) {
05223 struct connection *conn = (struct connection *) nc->user_data;
05224 struct mg_connection *c = &conn->mg_conn;
05225 char buf[100];
05226
05227 ns_sock_to_str(nc->sock, buf, sizeof(buf), is_rem ? 7 : 3);
05228 sscanf(buf, "%47[^:]:%hu",
05229 is_rem ? c->remote_ip : c->local_ip,
05230 is_rem ? &c->remote_port : &c->local_port);
05231
05232 }
05233
05234 static void on_accept(struct ns_connection *nc, union socket_address *sa) {
05235 struct mg_server *server = (struct mg_server *) nc->mgr;
05236 struct connection *conn;
05237
05238 if (!check_acl(server->config_options[ACCESS_CONTROL_LIST],
05239 ntohl(* (uint32_t *) &sa->sin.sin_addr)) ||
05240 (conn = (struct connection *) NS_CALLOC(1, sizeof(*conn))) == NULL) {
05241 nc->flags |= NSF_CLOSE_IMMEDIATELY;
05242 } else {
05243
05244 nc->user_data = conn;
05245 conn->ns_conn = nc;
05246
05247
05248 conn->server = server;
05249 conn->mg_conn.server_param = nc->mgr->user_data;
05250 set_ips(nc, 1);
05251 set_ips(nc, 0);
05252 }
05253 }
05254
05255 static void process_udp(struct ns_connection *nc) {
05256 struct iobuf *io = &nc->recv_iobuf;
05257 struct connection conn;
05258
05259 memset(&conn, 0, sizeof(conn));
05260 conn.ns_conn = nc;
05261 conn.server = (struct mg_server *) nc->mgr;
05262 conn.request_len = parse_http_message(io->buf, io->len, &conn.mg_conn);
05263 on_recv_data(&conn);
05264
05265 }
05266
05267 static void mg_ev_handler(struct ns_connection *nc, int ev, void *p) {
05268 struct connection *conn = (struct connection *) nc->user_data;
05269
05270
05271
05272 #ifdef MONGOOSE_SEND_NS_EVENTS
05273 {
05274 struct connection *conn = (struct connection *) nc->user_data;
05275 void *param[2] = { nc, p };
05276 if (conn != NULL) conn->mg_conn.callback_param = param;
05277 call_user(conn, (enum mg_event) ev);
05278 }
05279 #endif
05280
05281 switch (ev) {
05282 case NS_ACCEPT:
05283 on_accept(nc, (union socket_address *) p);
05284 #ifdef MONGOOSE_SEND_NS_EVENTS
05285 {
05286 struct connection *conn = (struct connection *) nc->user_data;
05287 void *param[2] = { nc, p };
05288 if (conn != NULL) conn->mg_conn.callback_param = param;
05289 call_user(conn, (enum mg_event) ev);
05290 }
05291 #endif
05292 break;
05293
05294 case NS_CONNECT:
05295 if (nc->user_data != NULL) {
05296 set_ips(nc, 1);
05297 set_ips(nc, 0);
05298 }
05299 conn->mg_conn.status_code = * (int *) p;
05300 if (conn->mg_conn.status_code != 0 ||
05301 (!(nc->flags & MG_PROXY_CONN) &&
05302 call_user(conn, MG_CONNECT) == MG_FALSE)) {
05303 nc->flags |= NSF_CLOSE_IMMEDIATELY;
05304 }
05305 break;
05306
05307 case NS_RECV:
05308 if (conn != NULL) {
05309 conn->num_bytes_recv += * (int *) p;
05310 }
05311
05312 if (nc->flags & NSF_UDP) {
05313 process_udp(nc);
05314 } else if (nc->listener != NULL) {
05315 on_recv_data(conn);
05316 #ifndef MONGOOSE_NO_CGI
05317 } else if (nc->flags & MG_CGI_CONN) {
05318 on_cgi_data(nc);
05319 #endif
05320 } else if (nc->flags & MG_PROXY_CONN) {
05321 if (conn != NULL) {
05322 ns_forward(nc, conn->ns_conn);
05323 }
05324 } else {
05325 process_response(conn);
05326 }
05327 break;
05328
05329 case NS_SEND:
05330 break;
05331
05332 case NS_CLOSE:
05333 nc->user_data = NULL;
05334 if (nc->flags & (MG_CGI_CONN | MG_PROXY_CONN)) {
05335 DBG(("%p %p closing cgi/proxy conn", conn, nc));
05336 if (conn && conn->ns_conn) {
05337 conn->ns_conn->flags &= ~NSF_BUFFER_BUT_DONT_SEND;
05338 conn->ns_conn->flags |= conn->ns_conn->send_iobuf.len > 0 ?
05339 NSF_FINISHED_SENDING_DATA : NSF_CLOSE_IMMEDIATELY;
05340 conn->endpoint.nc = NULL;
05341 }
05342 } else if (conn != NULL) {
05343 DBG(("%p %p %d closing", conn, nc, conn->endpoint_type));
05344
05345 if (conn->endpoint_type == EP_CLIENT && nc->recv_iobuf.len > 0) {
05346 call_http_client_handler(conn);
05347 }
05348
05349 call_user(conn, MG_CLOSE);
05350 close_local_endpoint(conn);
05351 conn->ns_conn = NULL;
05352 NS_FREE(conn);
05353 }
05354 break;
05355
05356 case NS_POLL:
05357 if (conn != NULL) {
05358 if (call_user(conn, MG_POLL) == MG_TRUE) {
05359 if (conn->ns_conn->flags & MG_HEADERS_SENT) {
05360 write_terminating_chunk(conn);
05361 }
05362 close_local_endpoint(conn);
05363 }
05364
05365 if (conn->endpoint_type == EP_FILE) {
05366 transfer_file_data(conn);
05367 }
05368 }
05369
05370
05371 {
05372 time_t current_time = * (time_t *) p;
05373
05374 if (conn != NULL && conn->mg_conn.is_websocket) {
05375 ping_idle_websocket_connection(conn, current_time);
05376 }
05377
05378 if (nc->listener != NULL &&
05379 nc->last_io_time + MONGOOSE_IDLE_TIMEOUT_SECONDS < current_time) {
05380 mg_ev_handler(nc, NS_CLOSE, NULL);
05381 nc->flags |= NSF_CLOSE_IMMEDIATELY;
05382 }
05383 }
05384 break;
05385
05386 default:
05387 break;
05388 }
05389 }
05390
05391 static void iter2(struct ns_connection *nc, int ev, void *param) {
05392 mg_handler_t func = NULL;
05393 struct connection *conn = (struct connection *) nc->user_data;
05394 const char *msg = (const char *) param;
05395 int n;
05396 (void) ev;
05397
05398
05399 if (sscanf(msg, "%p %n", &func, &n) && func != NULL && conn != NULL) {
05400 conn->mg_conn.callback_param = (void *) (msg + n);
05401 func(&conn->mg_conn, MG_POLL);
05402 }
05403 }
05404
05405 void mg_wakeup_server_ex(struct mg_server *server, mg_handler_t cb,
05406 const char *fmt, ...) {
05407 va_list ap;
05408 char buf[8 * 1024];
05409 int len;
05410
05411
05412 len = snprintf(buf, sizeof(buf), "%p ", cb);
05413 va_start(ap, fmt);
05414 len += vsnprintf(buf + len, sizeof(buf) - len, fmt, ap);
05415 va_end(ap);
05416
05417
05418 ns_broadcast(&server->ns_mgr, iter2, buf, len + 1);
05419 }
05420
05421 void mg_wakeup_server(struct mg_server *server) {
05422 ns_broadcast(&server->ns_mgr, NULL, (void *) "", 0);
05423 }
05424
05425 const char *mg_get_option(const struct mg_server *server, const char *name) {
05426 const char **opts = (const char **) server->config_options;
05427 int i = get_option_index(name);
05428 return i == -1 ? NULL : opts[i] == NULL ? "" : opts[i];
05429 }
05430
05431 struct mg_server *mg_create_server(void *server_data, mg_handler_t handler) {
05432 struct mg_server *server = (struct mg_server *) NS_CALLOC(1, sizeof(*server));
05433 ns_mgr_init(&server->ns_mgr, server_data);
05434 set_default_option_values(server->config_options);
05435 server->event_handler = handler;
05436 return server;
05437 }