newest mongoose.. PRETTY sure I didn't alter anything (NW)

This commit is contained in:
Cowering 2015-07-04 18:48:18 -05:00
parent 6e855b9cf7
commit 43ef9c65e0
11 changed files with 280 additions and 110 deletions

View File

@ -1,5 +1,7 @@
# <img src="http://cesanta.com/images/mongoose_logo.png" width="64" height="64"> Mongoose Web Server
[![Join the chat at https://gitter.im/cesanta/mongoose](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/cesanta/mongoose?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
Mongoose is the most easy to use web server on the planet. A web server of choice for Web developers (PHP, Ruby, Python, etc) and Web designers.
Mongoose is built on top of Libmongoose embedded library, which can turn
@ -45,24 +47,13 @@ Download, double-click to start, run browser -- that's all!
![shot3](http://cesanta.com/images/tut_sharing/tut3.png)
![shot4](http://cesanta.com/images/tut_sharing/tut4.png)
# Acknowledgements
# Contributions
Mongoose made better thanks to the contribution of following people:
Arnout Vandecappelle, Benoît Amiaux, Boris Pek, Cody Hanson, Colin Leitner,
Daniel Oaks, Eric Bakan, Erik Oomen, Filipp Kovalev, Ger Hobbelt,
Hendrik Polczynski, Igor Okulist, Jay, Joe Mucchiello, John Safranek,
José Miguel Gonçalves, Shueng Chuan, Katerina Blinova, Konstantin Sorokin,
Marin Atanasov, Matt Healy, Mitch Hendrickson, Nigel Stewart, Pavel Khlebovich,
Sebastian Reinhard, Stefan Doehla, abadc0de, nullable.type,
T.Barmann, D.Hughes, J.C.Sloan, R.Romeo, L.E.Spencer, S.Kotay, R.M.Shorter,
W.Mar, J.Wilander, Santa from Memphis, S.Davies, C.Beck,
O.M.Vilhunen, C.Radik, G.Woodcock, M.Szczepkowski,
Eternal Lands Dev Team, T.Tollet, C.Tangerino, G.Karsai, A.Bourgett,
C.Blakemore, D.Fonaryov, T.Andrle, O.IJsselmuiden, R.Womack, M.Tomlinson,
A.Slåttå, L.Farrell, J.D.P.Ballestero, V.Albaev, B.Harker, T.Scheffel, H.Klein,
R.Merit, T.Bennett, H.Solis, A.Zincenko, M.S., S.Krul, K.Cooke, S.McCallum,
F.Morenius, and 10 others.
People who have agreed to the
[Cesanta CLA](http://cesanta.com/contributors_la.html)
can make contributions. Note that the CLA isn't a copyright
_assigment_ but rather a copyright _license_.
You retain the copyright on your contributions.
# Licensing
@ -72,11 +63,11 @@ source licenses. The GPLv2 open source License does not generally permit
incorporating this software into non-open source programs.
For those customers who do not wish to comply with the GPLv2 open
source license requirements,
[Cesanta Software](http://cesanta.com) offers a full,
[Cesanta](http://cesanta.com) offers a full,
royalty-free commercial license and professional support
without any of the GPL restrictions.
# Other products by Cesanta Software: simple and effective
# Other products by Cesanta
- [Fossa](http://github.com/cesanta/fossa) - Multi-protocol networking library
- [SSL Wrapper](https://github.com/cesanta/ssl_wrapper) - application to
@ -84,3 +75,4 @@ without any of the GPL restrictions.
- [Frozen](https://github.com/cesanta/frozen) - JSON parser and generator
- [SLRE](https://github.com/cesanta/slre) - Super Light Regular Expression
library
- [V7](https://github.com/cesanta/v7) - Embedded JavaScript engine

View File

@ -168,7 +168,7 @@ Changes in pre-compiled binaries:
since mongoose buffers all data prior to calling the callback
* keep-alive support is the default
* Dropped SSI support and throttling support
* Several configuraition parameters are gone:
* Several configuration parameters are gone:
* `cgi_environment` (replaced with MONGOOSE_CGI),
* `protect_uri` (not useful)
* `ssi_pattern` (SSI support is gone)
@ -214,5 +214,5 @@ Changes in pre-compiled binaries:
* Couple of bugfixes, thanks to contributors
Eearlier release notes could be found by searching
Earlier release notes could be found by searching
[Mongoose mailing list](https://groups.google.com/forum/#!forum/mongoose-users)

View File

@ -0,0 +1,21 @@
# Copyright (c) 2014 Cesanta Software
# All rights reserved
PROG = array_vars
CFLAGS = -W -Wall -I../.. -pthread -g -O0 $(CFLAGS_EXTRA)
SOURCES = $(PROG).c ../../mongoose.c
all: $(PROG)
run: $(PROG)
./$(PROG)
$(PROG): $(SOURCES) Makefile
$(CC) -o $(PROG) $(SOURCES) $(CFLAGS)
win:
wine cl $(SOURCES) /MD /nologo /DNDEBUG /O1 /I../.. /Fe$(PROG).exe
wine $(PROG).exe
clean:
rm -rf $(PROG) *.exe *.dSYM *.obj *.exp .*o *.lib *.gc*

View File

@ -0,0 +1,45 @@
// Copyright (c) 2014 Cesanta Software
// All rights reserved
//
// This example demostrates how to use array get variables using mg_get_n_var
// $Date: 2014-09-09 22:20:23 UTC $
#include <stdio.h>
#include <string.h>
#include "mongoose.h"
static int ev_handler(struct mg_connection *conn, enum mg_event ev) {
switch (ev) {
case MG_AUTH: return MG_TRUE;
case MG_REQUEST:
{
mg_printf_data(conn, "Hello! Requested URI is [%s] ", conn->uri);
char buffer[1024];
int i, ret;
for(i=0; (ret = mg_get_var_n(conn, "foo[]", buffer, 1024, i)) > 0; i++)
mg_printf_data(conn, "\nfoo[%d] = %s", i, buffer);
return MG_TRUE;
}
default: return MG_FALSE;
}
}
int main(void) {
struct mg_server *server;
// Create and configure the server
server = mg_create_server(NULL, ev_handler);
mg_set_option(server, "listening_port", "8080");
// Serve request. Hit Ctrl-C to terminate the program
printf("Starting on port %s\n", mg_get_option(server, "listening_port"));
for (;;) {
mg_poll_server(server, 1000);
}
// Cleanup, and free server instance
mg_destroy_server(&server);
return 0;
}

View File

@ -58,6 +58,7 @@ static int check_login_form_submission(struct mg_connection *conn) {
mg_printf(conn,
"HTTP/1.1 302 Moved\r\n"
"Set-Cookie: ssid=%s; expire=\"%s\"; http-only; HttpOnly;\r\n"
"Content-Length: 0\r\n"
"Location: /\r\n\r\n",
ssid, expire);
return MG_TRUE;

View File

@ -7,23 +7,25 @@
static int send_index_page(struct mg_connection *conn) {
const char *data;
int data_len, ofs = 0;
int data_len, n1, n2;
char var_name[100], file_name[100];
mg_printf_data(conn, "%s",
"<html><body>Upload example."
"<form method=\"POST\" action=\"/handle_post_request\" "
" enctype=\"multipart/form-data\">"
"<input type=\"file\" name=\"file\" /> <br/>"
"<input type=\"file\" name=\"file1\" /> <br/>"
"<input type=\"file\" name=\"file2\" /> <br/>"
"<input type=\"submit\" value=\"Upload\" />"
"</form>");
while ((ofs = mg_parse_multipart(conn->content + ofs, conn->content_len - ofs,
var_name, sizeof(var_name),
file_name, sizeof(file_name),
&data, &data_len)) > 0) {
n1 = n2 = 0;
while ((n2 = mg_parse_multipart(conn->content + n1, conn->content_len - n1,
var_name, sizeof(var_name), file_name,
sizeof(file_name), &data, &data_len)) > 0) {
mg_printf_data(conn, "var: %s, file_name: %s, size: %d bytes<br>",
var_name, file_name, data_len);
n1 += n2;
}
mg_printf_data(conn, "%s", "</body></html>");

View File

@ -2,7 +2,7 @@
# All rights reserved
PROG = web_server
CFLAGS = -W -Wall -I../.. -pthread -g -O0 -DMONGOOSE_ENABLE_THREADS $(CFLAGS_EXTRA)
CFLAGS = -W -Wall -I../.. -g -O0 $(CFLAGS_EXTRA)
SOURCES = $(PROG).c ../../mongoose.c
OPENSSL_FLAGS = -DNS_ENABLE_SSL -lssl
@ -13,16 +13,18 @@ SOURCES_POLAR = $(SOURCES) $(POLARSSLCOMPAT_PATH)/polarssl_compat.c
INCDIR_POLAR = -I$(POLARSSLCOMPAT_PATH) -I$(POLARSSL_PATH)/include
LDFLAGS_POLAR = -L$(POLARSSL_PATH)/lib -lmbedtls
CFLAGS_POLAR = $(CFLAGS) $(INCDIR_POLAR) -DNS_ENABLE_SSL
#
$(PROG): $(SOURCES)
$(CC) -o $(PROG) $(SOURCES) $(CFLAGS)
$(PROG).exe: $(SOURCES)
cl -Fo $(PROG) $(SOURCES) -nologo -MD -I../..
openssl:
$(CC) -o $(PROG) $(SOURCES) $(CFLAGS) $(OPENSSL_FLAGS)
polarssl:
$(CC) -o $(PROG) $(SOURCES_POLAR) $(LDFLAGS_POLAR) $(CFLAGS_POLAR)
clean:
rm -rf $(PROG) *.exe *.dSYM *.obj *.exp .*o *.lib

View File

@ -40,7 +40,9 @@
#define DIRSEP '\\'
#define snprintf _snprintf
#define vsnprintf _vsnprintf
#ifndef sleep
#define sleep(x) Sleep((x) * 1000)
#endif
#define abs_path(rel, abs, abs_size) _fullpath((abs), (rel), (abs_size))
#define SIGCHLD 0
typedef struct _stat file_stat_t;

View File

@ -63,6 +63,10 @@
#pragma warning (disable : 4204) // missing c99 support
#endif
#if defined(_WIN32) && !defined(MONGOOSE_NO_CGI)
#define MONGOOSE_ENABLE_THREADS /* Windows uses stdio threads for CGI */
#endif
#ifndef MONGOOSE_ENABLE_THREADS
#define NS_DISABLE_THREADS
#endif
@ -91,6 +95,9 @@
#include <BaseTsd.h>
typedef SSIZE_T ssize_t;
#endif
#ifndef FD_SETSIZE
#define FD_SETSIZE 1024
#endif
#include <winsock2.h>
#include <ws2tcpip.h>
#include <windows.h>
@ -231,6 +238,7 @@ struct ns_connection {
sock_t sock; // Socket
union socket_address sa; // Peer address
size_t recv_iobuf_limit; /* Max size of recv buffer */
struct iobuf recv_iobuf; // Received data
struct iobuf send_iobuf; // Data scheduled for sending
SSL *ssl;
@ -250,6 +258,7 @@ struct ns_connection {
#define NSF_WANT_WRITE (1 << 6)
#define NSF_LISTENING (1 << 7)
#define NSF_UDP (1 << 8)
#define NSF_DISCARD (1 << 9)
#define NSF_USER_1 (1 << 20)
#define NSF_USER_2 (1 << 21)
@ -326,6 +335,7 @@ int ns_resolve(const char *domain_name, char *ip_addr_buf, size_t buf_len);
#define NS_CALLOC calloc
#endif
#define NS_MAX_SOCKETPAIR_ATTEMPTS 10
#define NS_CTL_MSG_MESSAGE_SIZE (8 * 1024)
#define NS_READ_BUFFER_SIZE 2048
#define NS_UDP_RECEIVE_BUFFER_SIZE 2000
@ -854,7 +864,17 @@ static int ns_is_error(int n) {
#ifdef _WIN32
&& WSAGetLastError() != WSAEINTR && WSAGetLastError() != WSAEWOULDBLOCK
#endif
);
)
#ifdef NS_ENABLE_SSL
/*
* OpenSSL can return an error when the peer is closing the socket.
* We don't encounter this error with openssl actually, but it's returned
* by our polarssl <-> openssl wrapper who tries to speak the openssl API
* as we understood it.
*/
|| n == SSL_AD_CLOSE_NOTIFY
#endif
;
}
void ns_sock_to_str(sock_t sock, char *buf, size_t len, int flags) {
@ -1056,7 +1076,7 @@ static void ns_handle_udp(struct ns_connection *ls) {
}
static void ns_add_to_set(sock_t sock, fd_set *set, sock_t *max_fd) {
if (sock != INVALID_SOCKET) {
if ( (sock != INVALID_SOCKET) && (sock < FD_SETSIZE) ) {
FD_SET(sock, set);
if (*max_fd == INVALID_SOCKET || sock > *max_fd) {
*max_fd = sock;
@ -1099,7 +1119,9 @@ time_t ns_mgr_poll(struct ns_mgr *mgr, int milli) {
tv.tv_sec = milli / 1000;
tv.tv_usec = (milli % 1000) * 1000;
if (select((int) max_fd + 1, &read_set, &write_set, NULL, &tv) > 0) {
if (select((int) max_fd + 1, &read_set, &write_set, NULL, &tv) < 0) {
return 0;
} else {
// select() might have been waiting for a long time, reset current_time
// now to prevent last_io_time being set to the past.
current_time = time(NULL);
@ -1250,9 +1272,12 @@ void ns_mgr_init(struct ns_mgr *s, void *user_data) {
#endif
#ifndef NS_DISABLE_SOCKETPAIR
do {
ns_socketpair2(s->ctl, SOCK_DGRAM);
} while (s->ctl[0] == INVALID_SOCKET);
{
int attempts = 0, max_attempts = NS_MAX_SOCKETPAIR_ATTEMPTS;
do {
ns_socketpair2(s->ctl, SOCK_DGRAM);
} while (s->ctl[0] == INVALID_SOCKET && ++attempts < max_attempts);
}
#endif
#ifdef NS_ENABLE_SSL
@ -1404,7 +1429,7 @@ struct dir_entry {
file_stat_t st;
};
// NOTE(lsm): this enum shoulds be in sync with the config_options.
// NOTE(lsm): this enum should be in sync with the config_options.
enum {
ACCESS_CONTROL_LIST,
#ifndef MONGOOSE_NO_FILESYSTEM
@ -1948,13 +1973,21 @@ static void write_chunk(struct connection *conn, const char *buf, int len) {
}
size_t mg_printf(struct mg_connection *conn, const char *fmt, ...) {
struct connection *c = MG_CONN_2_CONN(conn);
va_list ap;
int ret;
va_start(ap, fmt);
ns_vprintf(c->ns_conn, fmt, ap);
ret = mg_vprintf(conn, fmt, ap);
va_end(ap);
return ret;
}
size_t mg_vprintf(struct mg_connection *conn, const char *fmt, va_list ap) {
struct connection *c = MG_CONN_2_CONN(conn);
ns_vprintf(c->ns_conn, fmt, ap);
return c->ns_conn->send_iobuf.len;
}
@ -1973,6 +2006,8 @@ struct threadparam {
static int wait_until_ready(sock_t sock, int for_read) {
fd_set set;
if ( (sock == INVALID_SOCKET) || (sock >= FD_SETSIZE) )
return 0;
FD_ZERO(&set);
FD_SET(sock, &set);
select(sock + 1, for_read ? &set : 0, for_read ? 0 : &set, 0, 0);
@ -1992,7 +2027,7 @@ static void *push_to_stdin(void *arg) {
if (!WriteFile(tp->hPipe, buf + sent, n - sent, &k, 0)) stop = 1;
}
}
DBG(("%s", "FORWARED EVERYTHING TO CGI"));
DBG(("%s", "FORWARDED EVERYTHING TO CGI"));
CloseHandle(tp->hPipe);
NS_FREE(tp);
_endthread();
@ -2312,9 +2347,17 @@ static void open_cgi_endpoint(struct connection *conn, const char *prog) {
// Try to create socketpair in a loop until success. ns_socketpair()
// can be interrupted by a signal and fail.
// TODO(lsm): use sigaction to restart interrupted syscall
do {
ns_socketpair(fds);
} while (fds[0] == INVALID_SOCKET);
{
int attempts = 0, max_attempts = NS_MAX_SOCKETPAIR_ATTEMPTS;
do {
ns_socketpair(fds);
} while (fds[0] == INVALID_SOCKET && ++attempts < max_attempts);
if (fds[0] == INVALID_SOCKET) {
closesocket(fds[0]);
send_http_error(conn, 500, "ns_socketpair() failed");
}
}
if (start_process(conn->server->config_options[CGI_INTERPRETER],
prog, blk.buf, blk.vars, dir, fds[1]) != 0) {
@ -2503,7 +2546,7 @@ static size_t parse_http_message(char *buf, size_t len,
buf[len - 1] = '\0';
// RFC says that all initial whitespaces should be ingored
// RFC says that all initial whitespaces should be ignored
while (*buf != '\0' && isspace(* (unsigned char *) buf)) {
buf++;
}
@ -2677,7 +2720,8 @@ static int convert_uri_to_file_name(struct connection *conn, char *buf,
#endif
const char *uri = conn->mg_conn.uri;
const char *domain = mg_get_header(&conn->mg_conn, "Host");
size_t match_len, root_len = root == NULL ? 0 : strlen(root);
// Important: match_len has to be declared as int, unless rewrites break.
int match_len, root_len = root == NULL ? 0 : strlen(root);
// Perform virtual hosting rewrites
if (rewrites != NULL && domain != NULL) {
@ -2784,16 +2828,24 @@ size_t mg_send_data(struct mg_connection *c, const void *data, int data_len) {
}
size_t mg_printf_data(struct mg_connection *c, const char *fmt, ...) {
struct connection *conn = MG_CONN_2_CONN(c);
va_list ap;
int ret;
va_start(ap, fmt);
ret = mg_vprintf_data(c, fmt, ap);
va_end(ap);
return ret;
}
size_t mg_vprintf_data(struct mg_connection *c, const char *fmt, va_list ap) {
struct connection *conn = MG_CONN_2_CONN(c);
int len;
char mem[IOBUF_SIZE], *buf = mem;
terminate_headers(c);
va_start(ap, fmt);
len = ns_avprintf(&buf, sizeof(mem), fmt, ap);
va_end(ap);
if (len >= 0) {
write_chunk((struct connection *) conn, buf, len);
@ -2816,7 +2868,7 @@ static int is_big_endian(void) {
// Copyright(c) By Steve Reid <steve@edmweb.com>
#define SHA1HANDSOFF
#if defined(__sun)
//#include "solarisfixes.h"
#include "solarisfixes.h"
#endif
union char64long16 { unsigned char c[64]; uint32_t l[16]; };
@ -3033,7 +3085,8 @@ static size_t deliver_websocket_frame(struct connection *conn) {
}
// Call the handler and remove frame from the iobuf
if (call_user(conn, MG_REQUEST) == MG_FALSE) {
if (call_user(conn, MG_REQUEST) == MG_FALSE ||
(buf[0] & 0x0f) == WEBSOCKET_OPCODE_CONNECTION_CLOSE) {
conn->ns_conn->flags |= NSF_FINISHED_SENDING_DATA;
}
iobuf_remove(&conn->ns_conn->recv_iobuf, frame_len);
@ -3314,14 +3367,17 @@ static int find_index_file(struct connection *conn, char *path,
// If no index file exists, restore directory path
if (!found) {
path[n] = '\0';
path[n] = '/';
path[n + 1] = '\0';
}
return found;
}
static int parse_range_header(const char *header, int64_t *a, int64_t *b) {
return sscanf(header, "bytes=%" INT64_FMT "-%" INT64_FMT, a, b);
// return sscanf(header, "bytes=%" INT64_FMT "-%" INT64_FMT, a, b);
// return sscanf(header, "bytes=%ld-%ld" INT64_FMT, a, b);
return 0;
}
static void gmt_time_string(char *buf, size_t buf_len, time_t *t) {
@ -3332,7 +3388,7 @@ static void open_file_endpoint(struct connection *conn, const char *path,
file_stat_t *st, const char *extra_headers) {
char date[64], lm[64], etag[64], range[64], headers[1000];
const char *msg = "OK", *hdr;
time_t curtime = time(NULL);
time_t t, curtime = time(NULL);
int64_t r1, r2;
struct vec mime_vec;
int n;
@ -3362,7 +3418,7 @@ static void open_file_endpoint(struct connection *conn, const char *path,
// Prepare Etag, Date, Last-Modified headers. Must be in UTC, according to
// http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.3
gmt_time_string(date, sizeof(date), &curtime);
time_t t = st->st_mtime;
t = st->st_mtime; // store in local variable for NDK compile
gmt_time_string(lm, sizeof(lm), &t);
construct_etag(etag, sizeof(etag), st);
@ -3512,11 +3568,11 @@ static int scan_directory(struct connection *conn, const char *dir,
}
mg_snprintf(path, sizeof(path), "%s%c%s", dir, '/', dp->d_name);
// Resize the array if nesessary
// Resize the array if necessary
if (arr_ind >= arr_size) {
if ((p = (struct dir_entry *)
NS_REALLOC(*arr, (inc + arr_size) * sizeof(**arr))) != NULL) {
// Memset new chunk to zero, otherwize st_mtime will have garbage which
// Memset new chunk to zero, otherwise st_mtime will have garbage which
// can make strftime() segfault, see
// http://code.google.com/p/mongoose/issues/detail?id=79
memset(p + arr_size, 0, sizeof(**arr) * inc);
@ -3567,6 +3623,7 @@ static void print_dir_entry(const struct dir_entry *de) {
int64_t fsize = de->st.st_size;
int is_dir = S_ISDIR(de->st.st_mode);
const char *slash = is_dir ? "/" : "";
time_t t;
if (is_dir) {
mg_snprintf(size, sizeof(size), "%s", "[DIRECTORY]");
@ -3583,7 +3640,7 @@ static void print_dir_entry(const struct dir_entry *de) {
mg_snprintf(size, sizeof(size), "%.1fG", (double) fsize / 1073741824);
}
}
time_t t = de->st.st_mtime;
t = de->st.st_mtime; // store in local variable for NDK compile
strftime(mod, sizeof(mod), "%d-%b-%Y %H:%M", localtime(&t));
mg_url_encode(de->file_name, strlen(de->file_name), href, sizeof(href));
mg_printf_data(&de->conn->mg_conn,
@ -3639,12 +3696,14 @@ static void send_directory_listing(struct connection *conn, const char *dir) {
sort_direction, sort_direction, sort_direction);
num_entries = scan_directory(conn, dir, &arr);
qsort(arr, num_entries, sizeof(arr[0]), compare_dir_entries);
for (i = 0; i < num_entries; i++) {
print_dir_entry(&arr[i]);
NS_FREE(arr[i].file_name);
if (arr) {
qsort(arr, num_entries, sizeof(arr[0]), compare_dir_entries);
for (i = 0; i < num_entries; i++) {
print_dir_entry(&arr[i]);
NS_FREE(arr[i].file_name);
}
NS_FREE(arr);
}
NS_FREE(arr);
write_terminating_chunk(conn);
close_local_endpoint(conn);
@ -3655,7 +3714,7 @@ static void send_directory_listing(struct connection *conn, const char *dir) {
static void print_props(struct connection *conn, const char *uri,
file_stat_t *stp) {
char mtime[64];
time_t t = stp->st_mtime;
time_t t = stp->st_mtime; // store in local variable for NDK compile
gmt_time_string(mtime, sizeof(mtime), &t);
mg_printf(&conn->mg_conn,
"<d:response>"
@ -3861,11 +3920,16 @@ void mg_send_digest_auth_request(struct mg_connection *c) {
c->status_code = 401;
mg_printf(c,
"HTTP/1.1 401 Unauthorized\r\n"
"Content-Length: 0\r\n"
"WWW-Authenticate: Digest qop=\"auth\", "
"realm=\"%s\", nonce=\"%lu\"\r\n\r\n",
conn->server->config_options[AUTH_DOMAIN],
(unsigned long) time(NULL));
close_local_endpoint(conn);
if (conn->cl > 0) {
conn->ns_conn->flags |= NSF_DISCARD;
} else {
close_local_endpoint(conn);
}
}
// Use the global passwords file, if specified by auth_gpass option,
@ -4285,7 +4349,7 @@ static void do_ssi_include(struct mg_connection *conn, const char *ssi,
mg_snprintf(path, sizeof(path), "%s", file_name);
} else if (sscanf(tag, " file=\"%[^\"]\"", file_name) == 1 ||
sscanf(tag, " \"%[^\"]\"", file_name) == 1) {
// File name is relative to the currect document
// File name is relative to the current document
mg_snprintf(path, sizeof(path), "%s", ssi);
if ((p = strrchr(path, '/')) != NULL) {
p[1] = '\0';
@ -4697,6 +4761,10 @@ static void try_parse(struct connection *conn) {
// iobuf could be reallocated, and pointers in parsed request could
// become invalid.
conn->request = (char *) NS_MALLOC(conn->request_len);
if (conn->request == NULL) {
conn->ns_conn->flags |= NSF_CLOSE_IMMEDIATELY;
return;
}
memcpy(conn->request, io->buf, conn->request_len);
//DBG(("%p [%.*s]", conn, conn->request_len, conn->request));
iobuf_remove(io, conn->request_len);
@ -4734,6 +4802,19 @@ static void on_recv_data(struct connection *conn) {
return;
}
if (conn->ns_conn->flags & NSF_DISCARD) {
size_t n = conn->cl;
if (n > io->len) {
n = io->len;
}
iobuf_remove(io, n);
conn->cl -= n;
if (conn->cl == 0) {
close_local_endpoint(conn);
}
return;
}
try_parse(conn);
DBG(("%p %d %lu %d", conn, conn->request_len, (unsigned long)io->len,
conn->ns_conn->flags));
@ -4913,7 +4994,7 @@ static void close_local_endpoint(struct connection *conn) {
conn->endpoint_type = EP_NONE;
conn->cl = conn->num_bytes_recv = conn->request_len = 0;
conn->ns_conn->flags &= ~(NSF_FINISHED_SENDING_DATA |
conn->ns_conn->flags &= ~(NSF_FINISHED_SENDING_DATA | NSF_DISCARD |
NSF_BUFFER_BUT_DONT_SEND | NSF_CLOSE_IMMEDIATELY |
MG_HEADERS_SENT | MG_USING_CHUNKED_API);
@ -4921,7 +5002,7 @@ static void close_local_endpoint(struct connection *conn) {
// (IP addresses & ports, server_param) must survive. Nullify the rest.
c->request_method = c->uri = c->http_version = c->query_string = NULL;
c->num_headers = c->status_code = c->is_websocket = c->content_len = 0;
c->connection_param = c->callback_param = NULL;
c->callback_param = NULL;
if (keep_alive) {
on_recv_data(conn); // Can call us recursively if pipelining is used
@ -4983,20 +5064,17 @@ struct mg_connection *mg_next(struct mg_server *s, struct mg_connection *c) {
}
static int get_var(const char *data, size_t data_len, const char *name,
char *dst, size_t dst_len) {
const char *p, *e, *s;
char *dst, size_t dst_len, int n) {
const char *p, *e = data + data_len, *s;
size_t name_len;
int len;
int i = 0, len = -1;
if (dst == NULL || dst_len == 0) {
len = -2;
} else if (data == NULL || name == NULL || data_len == 0) {
len = -1;
dst[0] = '\0';
} else {
name_len = strlen(name);
e = data + data_len;
len = -1;
dst[0] = '\0';
// data is "var1=val1&var2=val2...". Find variable first
@ -5004,6 +5082,8 @@ static int get_var(const char *data, size_t data_len, const char *name,
if ((p == data || p[-1] == '&') && p[name_len] == '=' &&
!mg_strncasecmp(name, p, name_len)) {
if (n != i++) continue;
// Point p to variable value
p += name_len + 1;
@ -5029,16 +5109,21 @@ static int get_var(const char *data, size_t data_len, const char *name,
return len;
}
int mg_get_var(const struct mg_connection *conn, const char *name,
char *dst, size_t dst_len) {
int mg_get_var_n(const struct mg_connection *conn, const char *name,
char *dst, size_t dst_len, int n) {
int len = get_var(conn->query_string, conn->query_string == NULL ? 0 :
strlen(conn->query_string), name, dst, dst_len);
if (len < 0) {
len = get_var(conn->content, conn->content_len, name, dst, dst_len);
strlen(conn->query_string), name, dst, dst_len, n);
if (len == -1) {
len = get_var(conn->content, conn->content_len, name, dst, dst_len, n);
}
return len;
}
int mg_get_var(const struct mg_connection *conn, const char *name,
char *dst, size_t dst_len) {
return mg_get_var_n(conn, name, dst, dst_len, 0);
}
static int get_line_len(const char *buf, int buf_len) {
int len = 0;
while (len < buf_len && buf[len] != '\n') len++;
@ -5095,6 +5180,14 @@ void mg_copy_listeners(struct mg_server *s, struct mg_server *to) {
if ((c->flags & NSF_LISTENING) &&
(tmp = (struct ns_connection *) NS_MALLOC(sizeof(*tmp))) != NULL) {
memcpy(tmp, c, sizeof(*tmp));
#if defined(NS_ENABLE_SSL) && defined(HEADER_SSL_H)
/* OpenSSL only. See https://github.com/cesanta/mongoose/issues/441 */
if (tmp->ssl_ctx != NULL) {
tmp->ssl_ctx->references++;
}
#endif
tmp->mgr = &to->ns_mgr;
ns_add_conn(tmp->mgr, tmp);
}
@ -5153,6 +5246,7 @@ const char *mg_set_option(struct mg_server *server, const char *name,
char buf[500] = "";
size_t n = 0;
struct vec vec;
/*
* Ports can be specified as 0, meaning that OS has to choose any
* free port that is available. In order to pass chosen port number to
@ -5247,31 +5341,32 @@ static void process_udp(struct ns_connection *nc) {
//ns_printf(nc, "%s", "HTTP/1.0 200 OK\r\n\r\n");
}
#ifdef MONGOOSE_SEND_NS_EVENTS
static void send_ns_event(struct ns_connection *nc, int ev, void *p) {
struct connection *conn = (struct connection *) nc->user_data;
if (conn != NULL) {
void *param[2] = { nc, p };
conn->mg_conn.callback_param = param;
call_user(conn, (enum mg_event) ev);
}
}
#else
static void send_ns_event(struct ns_connection *nc, int ev, void *p) {
(void) nc; (void) p; (void) ev;
}
#endif
static void mg_ev_handler(struct ns_connection *nc, int ev, void *p) {
struct connection *conn = (struct connection *) nc->user_data;
// Send NS event to the handler. Note that call_user won't send an event
// if conn == NULL. Therefore, repeat this for NS_ACCEPT event as well.
#ifdef MONGOOSE_SEND_NS_EVENTS
{
struct connection *conn = (struct connection *) nc->user_data;
void *param[2] = { nc, p };
if (conn != NULL) conn->mg_conn.callback_param = param;
call_user(conn, (enum mg_event) ev);
}
#endif
send_ns_event(nc, ev, p);
switch (ev) {
case NS_ACCEPT:
on_accept(nc, (union socket_address *) p);
#ifdef MONGOOSE_SEND_NS_EVENTS
{
struct connection *conn = (struct connection *) nc->user_data;
void *param[2] = { nc, p };
if (conn != NULL) conn->mg_conn.callback_param = param;
call_user(conn, (enum mg_event) ev);
}
#endif
send_ns_event(nc, ev, p);
break;
case NS_CONNECT:
@ -5343,6 +5438,11 @@ static void mg_ev_handler(struct ns_connection *nc, int ev, void *p) {
write_terminating_chunk(conn);
}
close_local_endpoint(conn);
/*
* MG_POLL callback returned MG_TRUE,
* i.e. data is sent, set corresponding flag
*/
conn->ns_conn->flags |= NSF_FINISHED_SENDING_DATA;
}
if (conn->endpoint_type == EP_FILE) {

View File

@ -60,7 +60,8 @@ struct mg_connection {
struct mg_server; // Opaque structure describing server instance
enum mg_result { MG_FALSE, MG_TRUE, MG_MORE };
enum mg_event {
MG_POLL = 100, // Callback return value is ignored
MG_POLL = 100, // If callback returns MG_TRUE connection closes
// after all of data is sent
MG_CONNECT, // If callback returns MG_FALSE, connect fails
MG_AUTH, // If callback returns MG_FALSE, authentication fails
MG_REQUEST, // If callback returns MG_FALSE, Mongoose continues with req
@ -103,8 +104,10 @@ void mg_send_status(struct mg_connection *, int status_code);
void mg_send_header(struct mg_connection *, const char *name, const char *val);
size_t mg_send_data(struct mg_connection *, const void *data, int data_len);
size_t mg_printf_data(struct mg_connection *, const char *format, ...);
size_t mg_vprintf_data(struct mg_connection *, const char *format, va_list ap);
size_t mg_write(struct mg_connection *, const void *buf, size_t len);
size_t mg_printf(struct mg_connection *conn, const char *fmt, ...);
size_t mg_vprintf(struct mg_connection *conn, const char *fmt, va_list ap);
size_t mg_websocket_write(struct mg_connection *, int opcode,
const char *data, size_t data_len);
@ -118,6 +121,8 @@ const char *mg_get_header(const struct mg_connection *, const char *name);
const char *mg_get_mime_type(const char *name, const char *default_mime_type);
int mg_get_var(const struct mg_connection *conn, const char *var_name,
char *buf, size_t buf_len);
int mg_get_var_n(const struct mg_connection *conn, const char *var_name,
char *buf, size_t buf_len, int n);
int mg_parse_header(const char *hdr, const char *var_name, char *buf, size_t);
int mg_parse_multipart(const char *buf, int buf_len,
char *var_name, int var_name_len,

View File

@ -169,6 +169,7 @@ static const char *test_match_prefix(void) {
ASSERT(mg_match_prefix("/api", 4, "/api") == 4);
ASSERT(mg_match_prefix("/a/", 3, "/a/b/c") == 3);
ASSERT(mg_match_prefix("/a/", 3, "/ab/c") == -1);
ASSERT(mg_match_prefix("/blog/", 6, "/") == -1);
ASSERT(mg_match_prefix("/*/", 3, "/ab/c") == 4);
ASSERT(mg_match_prefix("**", 2, "/a/b/c") == 6);
ASSERT(mg_match_prefix("/*", 2, "/a/b/c") == 2);
@ -223,29 +224,28 @@ static const char *test_remove_double_dots() {
}
static const char *test_get_var(void) {
static const char *post[] = {
"a=1&&b=2&d&=&c=3%20&e=",
"q=&st=2012%2F11%2F13+17%3A05&et=&team_id=",
NULL
};
static const char *data = "a=1&&b=2&d&=&c=3%20&e=&k=aa&a=23";
static const char *data2 = "q=&st=2012%2F11%2F13+17%3A05&et=&team_id=";
char buf[20];
ASSERT(get_var(post[0], strlen(post[0]), "a", buf, sizeof(buf)) == 1);
ASSERT(get_var(data, strlen(data), "a", buf, sizeof(buf), 0) == 1);
ASSERT(buf[0] == '1' && buf[1] == '\0');
ASSERT(get_var(post[0], strlen(post[0]), "b", buf, sizeof(buf)) == 1);
ASSERT(get_var(data, strlen(data), "a", buf, sizeof(buf), 1) == 2);
ASSERT(strcmp(buf, "23") == 0);
ASSERT(get_var(data, strlen(data), "b", buf, sizeof(buf), 0) == 1);
ASSERT(buf[0] == '2' && buf[1] == '\0');
ASSERT(get_var(post[0], strlen(post[0]), "c", buf, sizeof(buf)) == 2);
ASSERT(get_var(data, strlen(data), "c", buf, sizeof(buf), 0) == 2);
ASSERT(buf[0] == '3' && buf[1] == ' ' && buf[2] == '\0');
ASSERT(get_var(post[0], strlen(post[0]), "e", buf, sizeof(buf)) == 0);
ASSERT(get_var(data, strlen(data), "e", buf, sizeof(buf), 0) == 0);
ASSERT(buf[0] == '\0');
ASSERT(get_var(post[0], strlen(post[0]), "d", buf, sizeof(buf)) == -1);
ASSERT(get_var(post[0], strlen(post[0]), "c", buf, 2) == -2);
ASSERT(get_var(data, strlen(data), "d", buf, sizeof(buf), 0) == -1);
ASSERT(get_var(data, strlen(data), "c", buf, 2, 0) == -2);
ASSERT(get_var(post[0], strlen(post[0]), "x", NULL, 10) == -2);
ASSERT(get_var(post[0], strlen(post[0]), "x", buf, 0) == -2);
ASSERT(get_var(post[1], strlen(post[1]), "st", buf, 16) == -2);
ASSERT(get_var(post[1], strlen(post[1]), "st", buf, 17) == 16);
ASSERT(get_var(data, strlen(data), "x", NULL, 10, 0) == -2);
ASSERT(get_var(data, strlen(data), "x", buf, 0, 0) == -2);
ASSERT(get_var(data2, strlen(data2), "st", buf, 16, 0) == -2);
ASSERT(get_var(data2, strlen(data2), "st", buf, 17, 0) == 16);
return NULL;
}