Commit 9bda69f5 authored by Sergey Lyubka's avatar Sergey Lyubka

Fix issue 180 - make mg_read() handle PUT requests, too. Stop checking for...

Fix issue 180 - make mg_read() handle PUT requests, too. Stop checking for request method in mg_read().
parents fb9493a0 0db96c5b
...@@ -14,13 +14,15 @@ all: ...@@ -14,13 +14,15 @@ all:
# -DNO_SSL - disable SSL functionality (-2kb) # -DNO_SSL - disable SSL functionality (-2kb)
# -DCONFIG_FILE=\"file\" - use `file' as the default config file # -DCONFIG_FILE=\"file\" - use `file' as the default config file
# -DHAVE_STRTOUI64 - use system strtoui64() function for strtoull() # -DHAVE_STRTOUI64 - use system strtoui64() function for strtoull()
# -DSSL_LIB=\"libssl.so.<version>\" - use system versioned SSL shared object
# -DCRYPTO_LIB=\"libcrypto.so.<version>\" - use system versioned CRYPTO so
########################################################################## ##########################################################################
### UNIX build: linux, bsd, mac, rtems ### UNIX build: linux, bsd, mac, rtems
########################################################################## ##########################################################################
CFLAGS= -W -Wall -std=c99 -pedantic -O2 -fomit-frame-pointer $(COPT) CFLAGS= -W -Wall -std=c99 -pedantic -O2 $(COPT)
MAC_SHARED= -flat_namespace -bundle -undefined suppress MAC_SHARED= -flat_namespace -bundle -undefined suppress
LINFLAGS= -ldl -pthread $(CFLAGS) LINFLAGS= -ldl -pthread $(CFLAGS)
LIB= _$(PROG).so LIB= _$(PROG).so
...@@ -126,7 +128,7 @@ do_test: ...@@ -126,7 +128,7 @@ do_test:
perl test/test.pl $(TEST) perl test/test.pl $(TEST)
release: clean release: clean
F=mongoose-`perl -lne '/define\s+MONGOOSE_VERSION\s+"(\S+)"/ and print $$1' mongoose.c`.tgz ; cd .. && tar --exclude \*.hg --exclude \*.svn --exclude \*.swp --exclude \*.nfs\* --exclude win32 -czf x mongoose && mv x mongoose/$$F F=mongoose-`perl -lne '/define\s+MONGOOSE_VERSION\s+"(\S+)"/ and print $$1' mongoose.c`.tgz ; cd .. && tar --exclude \*.hg --exclude \*.svn --exclude \*.swp --exclude \*.nfs\* -czf x mongoose && mv x mongoose/$$F
clean: clean:
rm -rf *.o *.core $(PROG) *.obj $(PROG).txt *.dSYM *.tgz rm -rf *.o *.core $(PROG) *.obj $(PROG).txt *.dSYM *.tgz
...@@ -374,7 +374,7 @@ int main(void) { ...@@ -374,7 +374,7 @@ int main(void) {
srand((unsigned) time(0)); srand((unsigned) time(0));
// Setup and start Mongoose // Setup and start Mongoose
ctx = mg_start(&event_handler, options); ctx = mg_start(&event_handler, NULL, options);
assert(ctx != NULL); assert(ctx != NULL);
// Wait until enter is pressed, then exit // Wait until enter is pressed, then exit
......
...@@ -163,7 +163,6 @@ typedef struct DIR { ...@@ -163,7 +163,6 @@ typedef struct DIR {
#include <sys/wait.h> #include <sys/wait.h>
#include <sys/socket.h> #include <sys/socket.h>
#include <sys/select.h> #include <sys/select.h>
#include <sys/mman.h>
#include <netinet/in.h> #include <netinet/in.h>
#include <arpa/inet.h> #include <arpa/inet.h>
#include <sys/time.h> #include <sys/time.h>
...@@ -174,15 +173,21 @@ typedef struct DIR { ...@@ -174,15 +173,21 @@ typedef struct DIR {
#include <pwd.h> #include <pwd.h>
#include <unistd.h> #include <unistd.h>
#include <dirent.h> #include <dirent.h>
#if !defined(NO_SSL_DL) && !defined(NO_SSL)
#include <dlfcn.h> #include <dlfcn.h>
#endif
#include <pthread.h> #include <pthread.h>
#if defined(__MACH__) #if defined(__MACH__)
#define SSL_LIB "libssl.dylib" #define SSL_LIB "libssl.dylib"
#define CRYPTO_LIB "libcrypto.dylib" #define CRYPTO_LIB "libcrypto.dylib"
#else #else
#if !defined(SSL_LIB)
#define SSL_LIB "libssl.so" #define SSL_LIB "libssl.so"
#endif
#if !defined(CRYPTO_LIB)
#define CRYPTO_LIB "libcrypto.so" #define CRYPTO_LIB "libcrypto.so"
#endif #endif
#endif
#define DIRSEP '/' #define DIRSEP '/'
#define IS_DIRSEP_CHAR(c) ((c) == '/') #define IS_DIRSEP_CHAR(c) ((c) == '/')
#define O_BINARY 0 #define O_BINARY 0
...@@ -557,7 +562,7 @@ static void mg_strlcpy(register char *dst, register const char *src, size_t n) { ...@@ -557,7 +562,7 @@ static void mg_strlcpy(register char *dst, register const char *src, size_t n) {
} }
static int lowercase(const char *s) { static int lowercase(const char *s) {
return tolower(* (unsigned char *) s); return tolower(* (const unsigned char *) s);
} }
static int mg_strncasecmp(const char *s1, const char *s2, size_t len) { static int mg_strncasecmp(const char *s1, const char *s2, size_t len) {
...@@ -1280,11 +1285,11 @@ static int64_t push(FILE *fp, SOCKET sock, SSL *ssl, const char *buf, ...@@ -1280,11 +1285,11 @@ static int64_t push(FILE *fp, SOCKET sock, SSL *ssl, const char *buf,
if (ssl != NULL) { if (ssl != NULL) {
n = SSL_write(ssl, buf + sent, k); n = SSL_write(ssl, buf + sent, k);
} else if (fp != NULL) { } else if (fp != NULL) {
n = fwrite(buf + sent, 1, k, fp); n = fwrite(buf + sent, 1, (size_t)k, fp);
if (ferror(fp)) if (ferror(fp))
n = -1; n = -1;
} else { } else {
n = send(sock, buf + sent, k, 0); n = send(sock, buf + sent, (size_t)k, 0);
} }
if (n < 0) if (n < 0)
...@@ -1304,7 +1309,10 @@ static int pull(FILE *fp, SOCKET sock, SSL *ssl, char *buf, int len) { ...@@ -1304,7 +1309,10 @@ static int pull(FILE *fp, SOCKET sock, SSL *ssl, char *buf, int len) {
if (ssl != NULL) { if (ssl != NULL) {
nread = SSL_read(ssl, buf, len); nread = SSL_read(ssl, buf, len);
} else if (fp != NULL) { } else if (fp != NULL) {
nread = fread(buf, 1, (size_t) len, fp); // Use read() instead of fread(), because if we're reading from the CGI
// pipe, fread() may block until IO buffer is filled up. We cannot afford
// to block and must pass all read bytes immediately to the client.
nread = read(fileno(fp), buf, (size_t) len);
if (ferror(fp)) if (ferror(fp))
nread = -1; nread = -1;
} else { } else {
...@@ -1331,7 +1339,7 @@ int mg_read(struct mg_connection *conn, void *buf, size_t len) { ...@@ -1331,7 +1339,7 @@ int mg_read(struct mg_connection *conn, void *buf, size_t len) {
} }
// How many bytes of data we have buffered in the request buffer? // How many bytes of data we have buffered in the request buffer?
buffered = conn->buf + conn->request_len; buffered = conn->buf + conn->request_len + conn->consumed_content;
buffered_len = conn->data_len - conn->request_len; buffered_len = conn->data_len - conn->request_len;
assert(buffered_len >= 0); assert(buffered_len >= 0);
...@@ -1341,7 +1349,7 @@ int mg_read(struct mg_connection *conn, void *buf, size_t len) { ...@@ -1341,7 +1349,7 @@ int mg_read(struct mg_connection *conn, void *buf, size_t len) {
if (len < (size_t) buffered_len) { if (len < (size_t) buffered_len) {
buffered_len = len; buffered_len = len;
} }
memcpy(buf, buffered, buffered_len); memcpy(buf, buffered, (size_t)buffered_len);
len -= buffered_len; len -= buffered_len;
buf = (char *) buf + buffered_len; buf = (char *) buf + buffered_len;
conn->consumed_content += buffered_len; conn->consumed_content += buffered_len;
...@@ -1377,7 +1385,7 @@ int mg_printf(struct mg_connection *conn, const char *fmt, ...) { ...@@ -1377,7 +1385,7 @@ int mg_printf(struct mg_connection *conn, const char *fmt, ...) {
len = mg_vsnprintf(conn, buf, sizeof(buf), fmt, ap); len = mg_vsnprintf(conn, buf, sizeof(buf), fmt, ap);
va_end(ap); va_end(ap);
return mg_write(conn, buf, len); return mg_write(conn, buf, (size_t)len);
} }
// URL-decode input buffer into destination buffer. // URL-decode input buffer into destination buffer.
...@@ -1393,10 +1401,10 @@ static size_t url_decode(const char *src, size_t src_len, char *dst, ...@@ -1393,10 +1401,10 @@ static size_t url_decode(const char *src, size_t src_len, char *dst,
for (i = j = 0; i < src_len && j < dst_len - 1; i++, j++) { for (i = j = 0; i < src_len && j < dst_len - 1; i++, j++) {
if (src[i] == '%' && if (src[i] == '%' &&
isxdigit(* (unsigned char *) (src + i + 1)) && isxdigit(* (const unsigned char *) (src + i + 1)) &&
isxdigit(* (unsigned char *) (src + i + 2))) { isxdigit(* (const unsigned char *) (src + i + 2))) {
a = tolower(* (unsigned char *) (src + i + 1)); a = tolower(* (const unsigned char *) (src + i + 1));
b = tolower(* (unsigned char *) (src + i + 2)); b = tolower(* (const unsigned char *) (src + i + 2));
dst[j] = (char) ((HEXTOI(a) << 4) | HEXTOI(b)); dst[j] = (char) ((HEXTOI(a) << 4) | HEXTOI(b));
i += 2; i += 2;
} else if (is_form_url_encoded && src[i] == '+') { } else if (is_form_url_encoded && src[i] == '+') {
...@@ -1434,7 +1442,7 @@ int mg_get_var(const char *buf, size_t buf_len, const char *name, ...@@ -1434,7 +1442,7 @@ int mg_get_var(const char *buf, size_t buf_len, const char *name,
p += name_len + 1; p += name_len + 1;
// Point s to the end of the value // Point s to the end of the value
s = (const char *) memchr(p, '&', e - p); s = (const char *) memchr(p, '&', (size_t)(e - p));
if (s == NULL) { if (s == NULL) {
s = e; s = e;
} }
...@@ -1442,7 +1450,7 @@ int mg_get_var(const char *buf, size_t buf_len, const char *name, ...@@ -1442,7 +1450,7 @@ int mg_get_var(const char *buf, size_t buf_len, const char *name,
// Decode variable into destination buffer // Decode variable into destination buffer
if ((size_t) (s - p) < dst_len) { if ((size_t) (s - p) < dst_len) {
len = url_decode(p, s - p, dst, dst_len, 1); len = url_decode(p, (size_t)(s - p), dst, dst_len, 1);
} }
break; break;
} }
...@@ -1477,7 +1485,7 @@ int mg_get_cookie(const struct mg_connection *conn, const char *cookie_name, ...@@ -1477,7 +1485,7 @@ int mg_get_cookie(const struct mg_connection *conn, const char *cookie_name,
} }
if ((size_t) (p - s) < dst_size) { if ((size_t) (p - s) < dst_size) {
len = (p - s) + 1; len = (p - s) + 1;
mg_strlcpy(dst, s, len); mg_strlcpy(dst, s, (size_t)len);
} }
break; break;
} }
...@@ -1531,7 +1539,7 @@ static int sslize(struct mg_connection *conn, int (*func)(SSL *)) { ...@@ -1531,7 +1539,7 @@ static int sslize(struct mg_connection *conn, int (*func)(SSL *)) {
func(conn->ssl) == 1; func(conn->ssl) == 1;
} }
struct mg_connection *mg_connect(struct mg_connection *conn, static struct mg_connection *mg_connect(struct mg_connection *conn,
const char *host, int port, int use_ssl) { const char *host, int port, int use_ssl) {
struct mg_connection *newconn = NULL; struct mg_connection *newconn = NULL;
struct sockaddr_in sin; struct sockaddr_in sin;
...@@ -1578,8 +1586,8 @@ static int get_request_len(const char *buf, int buflen) { ...@@ -1578,8 +1586,8 @@ static int get_request_len(const char *buf, int buflen) {
DEBUG_TRACE(("buf: %p, len: %d", buf, buflen)); DEBUG_TRACE(("buf: %p, len: %d", buf, buflen));
for (s = buf, e = s + buflen - 1; len <= 0 && s < e; s++) for (s = buf, e = s + buflen - 1; len <= 0 && s < e; s++)
// Control characters are not allowed but >=128 is. // Control characters are not allowed but >=128 is.
if (!isprint(* (unsigned char *) s) && *s != '\r' && if (!isprint(* (const unsigned char *) s) && *s != '\r' &&
*s != '\n' && * (unsigned char *) s < 128) { *s != '\n' && * (const unsigned char *) s < 128) {
len = -1; len = -1;
} else if (s[0] == '\n' && s[1] == '\n') { } else if (s[0] == '\n' && s[1] == '\n') {
len = (int) (s - buf) + 2; len = (int) (s - buf) + 2;
...@@ -1757,7 +1765,7 @@ typedef struct MD5Context { ...@@ -1757,7 +1765,7 @@ typedef struct MD5Context {
unsigned char in[64]; unsigned char in[64];
} MD5_CTX; } MD5_CTX;
#if __BYTE_ORDER == 1234 #if defined(__BYTE_ORDER) && (__BYTE_ORDER == 1234)
#define byteReverse(buf, len) // Do nothing #define byteReverse(buf, len) // Do nothing
#else #else
static void byteReverse(unsigned char *buf, unsigned longs) { static void byteReverse(unsigned char *buf, unsigned longs) {
...@@ -1961,7 +1969,7 @@ void mg_md5(char *buf, ...) { ...@@ -1961,7 +1969,7 @@ void mg_md5(char *buf, ...) {
va_start(ap, buf); va_start(ap, buf);
while ((p = va_arg(ap, const char *)) != NULL) { while ((p = va_arg(ap, const char *)) != NULL) {
MD5Update(&ctx, (unsigned char *) p, (int) strlen(p)); MD5Update(&ctx, (const unsigned char *) p, (unsigned) strlen(p));
} }
va_end(ap); va_end(ap);
...@@ -2052,7 +2060,7 @@ static int parse_auth_header(struct mg_connection *conn, char *buf, ...@@ -2052,7 +2060,7 @@ static int parse_auth_header(struct mg_connection *conn, char *buf,
// Parse authorization header // Parse authorization header
for (;;) { for (;;) {
name = skip(&s, "="); name = skip(&s, "=");
value = skip(&s, " "); value = skip(&s, ", "); // IE uses commas, FF uses spaces
// Handle commas: Digest username="a", realm="b", ... // Handle commas: Digest username="a", realm="b", ...
if (value[strlen(value) - 1] == ',') { if (value[strlen(value) - 1] == ',') {
...@@ -2256,13 +2264,13 @@ static void url_encode(const char *src, char *dst, size_t dst_len) { ...@@ -2256,13 +2264,13 @@ static void url_encode(const char *src, char *dst, size_t dst_len) {
const char *end = dst + dst_len - 1; const char *end = dst + dst_len - 1;
for (; *src != '\0' && dst < end; src++, dst++) { for (; *src != '\0' && dst < end; src++, dst++) {
if (isalnum(*(unsigned char *) src) || if (isalnum(*(const unsigned char *) src) ||
strchr(dont_escape, * (unsigned char *) src) != NULL) { strchr(dont_escape, * (const unsigned char *) src) != NULL) {
*dst = *src; *dst = *src;
} else if (dst + 2 < end) { } else if (dst + 2 < end) {
dst[0] = '%'; dst[0] = '%';
dst[1] = hex[(* (unsigned char *) src) >> 4]; dst[1] = hex[(* (const unsigned char *) src) >> 4];
dst[2] = hex[(* (unsigned char *) src) & 0xf]; dst[2] = hex[(* (const unsigned char *) src) & 0xf];
dst += 2; dst += 2;
} }
} }
...@@ -2306,7 +2314,7 @@ static void print_dir_entry(struct de *de) { ...@@ -2306,7 +2314,7 @@ static void print_dir_entry(struct de *de) {
// On windows, __cdecl specification is needed in case if project is built // On windows, __cdecl specification is needed in case if project is built
// with __stdcall convention. qsort always requires __cdels callback. // with __stdcall convention. qsort always requires __cdels callback.
static int WINCDECL compare_dir_entries(const void *p1, const void *p2) { static int WINCDECL compare_dir_entries(const void *p1, const void *p2) {
const struct de *a = (struct de *) p1, *b = (struct de *) p2; const struct de *a = (const struct de *) p1, *b = (const struct de *) p2;
const char *query_string = a->conn->request_info.query_string; const char *query_string = a->conn->request_info.query_string;
int cmp_result = 0; int cmp_result = 0;
...@@ -2408,7 +2416,7 @@ static void handle_directory_request(struct mg_connection *conn, ...@@ -2408,7 +2416,7 @@ static void handle_directory_request(struct mg_connection *conn,
conn->request_info.uri, "..", "Parent directory", "-", "-"); conn->request_info.uri, "..", "Parent directory", "-", "-");
// Sort and print directory entries // Sort and print directory entries
qsort(entries, num_entries, sizeof(entries[0]), compare_dir_entries); qsort(entries, (size_t)num_entries, sizeof(entries[0]), compare_dir_entries);
for (i = 0; i < num_entries; i++) { for (i = 0; i < num_entries; i++) {
print_dir_entry(&entries[i]); print_dir_entry(&entries[i]);
free(entries[i].file_name); free(entries[i].file_name);
...@@ -2431,11 +2439,11 @@ static void send_file_data(struct mg_connection *conn, FILE *fp, int64_t len) { ...@@ -2431,11 +2439,11 @@ static void send_file_data(struct mg_connection *conn, FILE *fp, int64_t len) {
to_read = (int) len; to_read = (int) len;
// Read from file, exit the loop on error // Read from file, exit the loop on error
if ((num_read = fread(buf, 1, to_read, fp)) == 0) if ((num_read = fread(buf, 1, (size_t)to_read, fp)) == 0)
break; break;
// Send read bytes to the client, exit the loop on error // Send read bytes to the client, exit the loop on error
if ((num_written = mg_write(conn, buf, num_read)) != num_read) if ((num_written = mg_write(conn, buf, (size_t)num_read)) != num_read)
break; break;
// Both read and were successful, adjust counters // Both read and were successful, adjust counters
...@@ -2918,7 +2926,7 @@ static void handle_cgi_request(struct mg_connection *conn, const char *prog) { ...@@ -2918,7 +2926,7 @@ static void handle_cgi_request(struct mg_connection *conn, const char *prog) {
// Send chunk of data that may be read after the headers // Send chunk of data that may be read after the headers
conn->num_bytes_sent += mg_write(conn, buf + headers_len, conn->num_bytes_sent += mg_write(conn, buf + headers_len,
data_len - headers_len); (size_t)(data_len - headers_len));
// Read the rest of CGI output and send to the client // Read the rest of CGI output and send to the client
send_file_data(conn, out, INT64_MAX); send_file_data(conn, out, INT64_MAX);
...@@ -3062,6 +3070,7 @@ static void do_ssi_include(struct mg_connection *conn, const char *ssi, ...@@ -3062,6 +3070,7 @@ static void do_ssi_include(struct mg_connection *conn, const char *ssi,
} }
} }
#if !defined(NO_POPEN)
static void do_ssi_exec(struct mg_connection *conn, char *tag) { static void do_ssi_exec(struct mg_connection *conn, char *tag) {
char cmd[BUFSIZ]; char cmd[BUFSIZ];
FILE *fp; FILE *fp;
...@@ -3075,6 +3084,7 @@ static void do_ssi_exec(struct mg_connection *conn, char *tag) { ...@@ -3075,6 +3084,7 @@ static void do_ssi_exec(struct mg_connection *conn, char *tag) {
(void) pclose(fp); (void) pclose(fp);
} }
} }
#endif // !NO_POPEN
static void send_ssi_file(struct mg_connection *conn, const char *path, static void send_ssi_file(struct mg_connection *conn, const char *path,
FILE *fp, int include_level) { FILE *fp, int include_level) {
...@@ -3097,12 +3107,14 @@ static void send_ssi_file(struct mg_connection *conn, const char *path, ...@@ -3097,12 +3107,14 @@ static void send_ssi_file(struct mg_connection *conn, const char *path,
assert(len <= (int) sizeof(buf)); assert(len <= (int) sizeof(buf));
if (len < 6 || memcmp(buf, "<!--#", 5) != 0) { if (len < 6 || memcmp(buf, "<!--#", 5) != 0) {
// Not an SSI tag, pass it // Not an SSI tag, pass it
(void) mg_write(conn, buf, len); (void) mg_write(conn, buf, (size_t)len);
} else { } else {
if (!memcmp(buf + 5, "include", 7)) { if (!memcmp(buf + 5, "include", 7)) {
do_ssi_include(conn, path, buf + 12, include_level); do_ssi_include(conn, path, buf + 12, include_level);
#if !defined(NO_POPEN)
} else if (!memcmp(buf + 5, "exec", 4)) { } else if (!memcmp(buf + 5, "exec", 4)) {
do_ssi_exec(conn, buf + 9); do_ssi_exec(conn, buf + 9);
#endif // !NO_POPEN
} else { } else {
cry(conn, "%s: unknown SSI " "command: \"%s\"", path, buf); cry(conn, "%s: unknown SSI " "command: \"%s\"", path, buf);
} }
...@@ -3120,14 +3132,14 @@ static void send_ssi_file(struct mg_connection *conn, const char *path, ...@@ -3120,14 +3132,14 @@ static void send_ssi_file(struct mg_connection *conn, const char *path,
} else if (ch == '<') { } else if (ch == '<') {
in_ssi_tag = 1; in_ssi_tag = 1;
if (len > 0) { if (len > 0) {
(void) mg_write(conn, buf, len); (void) mg_write(conn, buf, (size_t)len);
} }
len = 0; len = 0;
buf[len++] = ch & 0xff; buf[len++] = ch & 0xff;
} else { } else {
buf[len++] = ch & 0xff; buf[len++] = ch & 0xff;
if (len == (int) sizeof(buf)) { if (len == (int) sizeof(buf)) {
(void) mg_write(conn, buf, len); (void) mg_write(conn, buf, (size_t)len);
len = 0; len = 0;
} }
} }
...@@ -3135,7 +3147,7 @@ static void send_ssi_file(struct mg_connection *conn, const char *path, ...@@ -3135,7 +3147,7 @@ static void send_ssi_file(struct mg_connection *conn, const char *path,
// Send the rest of buffered data // Send the rest of buffered data
if (len > 0) { if (len > 0) {
(void) mg_write(conn, buf, len); (void) mg_write(conn, buf, (size_t)len);
} }
} }
...@@ -3170,7 +3182,7 @@ static void handle_request(struct mg_connection *conn) { ...@@ -3170,7 +3182,7 @@ static void handle_request(struct mg_connection *conn) {
* conn->request_info.query_string++ = '\0'; * conn->request_info.query_string++ = '\0';
} }
uri_len = strlen(ri->uri); uri_len = strlen(ri->uri);
(void) url_decode(ri->uri, uri_len, ri->uri, uri_len + 1, 0); (void) url_decode(ri->uri, (size_t)uri_len, ri->uri, (size_t)(uri_len + 1), 0);
remove_double_dots_and_double_slashes(ri->uri); remove_double_dots_and_double_slashes(ri->uri);
convert_uri_to_file_name(conn, ri->uri, path, sizeof(path)); convert_uri_to_file_name(conn, ri->uri, path, sizeof(path));
...@@ -3548,7 +3560,7 @@ static int set_ssl_option(struct mg_context *ctx) { ...@@ -3548,7 +3560,7 @@ static int set_ssl_option(struct mg_context *ctx) {
// Initialize locking callbacks, needed for thread safety. // Initialize locking callbacks, needed for thread safety.
// http://www.openssl.org/support/faq.html#PROG1 // http://www.openssl.org/support/faq.html#PROG1
size = sizeof(pthread_mutex_t) * CRYPTO_num_locks(); size = sizeof(pthread_mutex_t) * CRYPTO_num_locks();
if ((ssl_mutexes = (pthread_mutex_t *) malloc(size)) == NULL) { if ((ssl_mutexes = (pthread_mutex_t *) malloc((size_t)size)) == NULL) {
cry(fc(ctx), "%s: cannot allocate mutexes: %s", __func__, ssl_error()); cry(fc(ctx), "%s: cannot allocate mutexes: %s", __func__, ssl_error());
return 0; return 0;
} }
...@@ -3643,7 +3655,7 @@ static void discard_current_request_from_buffer(struct mg_connection *conn) { ...@@ -3643,7 +3655,7 @@ static void discard_current_request_from_buffer(struct mg_connection *conn) {
} }
conn->data_len -= conn->request_len + body_len; conn->data_len -= conn->request_len + body_len;
memmove(conn->buf, conn->buf + conn->request_len + body_len, conn->data_len); memmove(conn->buf, conn->buf + conn->request_len + body_len, (size_t)conn->data_len);
} }
static int parse_url(const char *url, char *host, int *port) { static int parse_url(const char *url, char *host, int *port) {
...@@ -3706,7 +3718,7 @@ static void handle_proxy_request(struct mg_connection *conn) { ...@@ -3706,7 +3718,7 @@ static void handle_proxy_request(struct mg_connection *conn) {
// Read data from the target and forward it to the client // Read data from the target and forward it to the client
while ((n = pull(NULL, conn->peer->client.sock, conn->peer->ssl, while ((n = pull(NULL, conn->peer->client.sock, conn->peer->ssl,
buf, sizeof(buf))) > 0) { buf, sizeof(buf))) > 0) {
if (mg_write(conn, buf, n) != n) { if (mg_write(conn, buf, (size_t)n) != n) {
break; break;
} }
} }
...@@ -3903,8 +3915,8 @@ static void master_thread(struct mg_context *ctx) { ...@@ -3903,8 +3915,8 @@ static void master_thread(struct mg_context *ctx) {
add_to_set(sp->sock, &read_set, &max_fd); add_to_set(sp->sock, &read_set, &max_fd);
} }
tv.tv_sec = 1; tv.tv_sec = 0;
tv.tv_usec = 0; tv.tv_usec = 200 * 1000;
if (select(max_fd + 1, &read_set, NULL, NULL, &tv) < 0) { if (select(max_fd + 1, &read_set, NULL, NULL, &tv) < 0) {
#ifdef _WIN32 #ifdef _WIN32
......
...@@ -31,39 +31,45 @@ ...@@ -31,39 +31,45 @@
#include "mongoose.h" #include "mongoose.h"
#if !defined(LISTENING_PORT) #if !defined(LISTENING_PORT)
#define LISTENING_PORT "23456" #define LISTENING_PORT "23456"
#endif #endif
static const char *standard_reply = "HTTP/1.1 200 OK\r\n" static const char *standard_reply = "HTTP/1.1 200 OK\r\n"
"Content-Type: text/plain\r\n" "Content-Type: text/plain\r\n"
"Connection: close\r\n\r\n"; "Connection: close\r\n\r\n";
static void test_get_var(struct mg_connection *conn, static void test_get_var(struct mg_connection *conn,
const struct mg_request_info *ri) { const struct mg_request_info *ri) {
char *var, *buf; char *var, *buf;
size_t buf_len; size_t buf_len;
const char *cl; const char *cl;
int var_len; int var_len;
mg_printf(conn, "%s", standard_reply); mg_printf(conn, "%s", standard_reply);
buf_len = 0; buf_len = 0;
var = buf = NULL; var = buf = NULL;
cl = mg_get_header(conn, "Content-Length"); cl = mg_get_header(conn, "Content-Length");
mg_printf(conn, "cl: %p\n", cl); mg_printf(conn, "cl: %p\n", cl);
printf("reqeust method = %s\n", ri->request_method); if ((!strcmp(ri->request_method, "POST") ||
if ((!strcmp(ri->request_method, "POST") || !strcmp(ri->request_method, "PUT")) !strcmp(ri->request_method, "PUT"))
&& cl != NULL) { && cl != NULL) {
buf_len = atoi(cl); buf_len = atoi(cl);
buf = malloc(buf_len); buf = malloc(buf_len);
mg_read(conn, buf, buf_len); /* Read in two pieces, to test continuation */
if (buf_len > 2) {
mg_read(conn, buf, 2);
mg_read(conn, buf + 2, buf_len - 2);
} else {
mg_read(conn, buf, buf_len);
}
} else if (ri->query_string != NULL) { } else if (ri->query_string != NULL) {
buf_len = strlen(ri->query_string); buf_len = strlen(ri->query_string);
buf = malloc(buf_len + 1); buf = malloc(buf_len + 1);
strcpy(buf, ri->query_string); strcpy(buf, ri->query_string);
} }
var = malloc(buf_len + 1); var = malloc(buf_len + 1);
var_len = mg_get_var(buf, buf_len, "my_var", var, buf_len + 1); var_len = mg_get_var(buf, buf_len, "my_var", var, buf_len + 1);
mg_printf(conn, "Value: [%s]\n", var); mg_printf(conn, "Value: [%s]\n", var);
mg_printf(conn, "Value size: [%d]\n", var_len); mg_printf(conn, "Value size: [%d]\n", var_len);
free(buf); free(buf);
...@@ -72,50 +78,50 @@ static void test_get_var(struct mg_connection *conn, ...@@ -72,50 +78,50 @@ static void test_get_var(struct mg_connection *conn,
static void test_get_header(struct mg_connection *conn, static void test_get_header(struct mg_connection *conn,
const struct mg_request_info *ri) { const struct mg_request_info *ri) {
const char *value; const char *value;
int i; int i;
mg_printf(conn, "%s", standard_reply); mg_printf(conn, "%s", standard_reply);
printf("HTTP headers: %d\n", ri->num_headers); printf("HTTP headers: %d\n", ri->num_headers);
for (i = 0; i < ri->num_headers; i++) { for (i = 0; i < ri->num_headers; i++) {
printf("[%s]: [%s]\n", ri->http_headers[i].name, ri->http_headers[i].value); printf("[%s]: [%s]\n", ri->http_headers[i].name, ri->http_headers[i].value);
} }
value = mg_get_header(conn, "Host"); value = mg_get_header(conn, "Host");
if (value != NULL) { if (value != NULL) {
mg_printf(conn, "Value: [%s]", value); mg_printf(conn, "Value: [%s]", value);
} }
} }
static void test_get_request_info(struct mg_connection *conn, static void test_get_request_info(struct mg_connection *conn,
const struct mg_request_info *ri) { const struct mg_request_info *ri) {
int i; int i;
mg_printf(conn, "%s", standard_reply); mg_printf(conn, "%s", standard_reply);
mg_printf(conn, "Method: [%s]\n", ri->request_method); mg_printf(conn, "Method: [%s]\n", ri->request_method);
mg_printf(conn, "URI: [%s]\n", ri->uri); mg_printf(conn, "URI: [%s]\n", ri->uri);
mg_printf(conn, "HTTP version: [%s]\n", ri->http_version); mg_printf(conn, "HTTP version: [%s]\n", ri->http_version);
for (i = 0; i < ri->num_headers; i++) { for (i = 0; i < ri->num_headers; i++) {
mg_printf(conn, "HTTP header [%s]: [%s]\n", mg_printf(conn, "HTTP header [%s]: [%s]\n",
ri->http_headers[i].name, ri->http_headers[i].name,
ri->http_headers[i].value); ri->http_headers[i].value);
} }
mg_printf(conn, "Query string: [%s]\n", mg_printf(conn, "Query string: [%s]\n",
ri->query_string ? ri->query_string: ""); ri->query_string ? ri->query_string: "");
mg_printf(conn, "Remote IP: [%lu]\n", ri->remote_ip); mg_printf(conn, "Remote IP: [%lu]\n", ri->remote_ip);
mg_printf(conn, "Remote port: [%d]\n", ri->remote_port); mg_printf(conn, "Remote port: [%d]\n", ri->remote_port);
mg_printf(conn, "Remote user: [%s]\n", mg_printf(conn, "Remote user: [%s]\n",
ri->remote_user ? ri->remote_user : ""); ri->remote_user ? ri->remote_user : "");
} }
static void test_error(struct mg_connection *conn, static void test_error(struct mg_connection *conn,
const struct mg_request_info *ri) { const struct mg_request_info *ri) {
mg_printf(conn, "HTTP/1.1 %d XX\r\n" mg_printf(conn, "HTTP/1.1 %d XX\r\n"
"Conntection: close\r\n\r\n", ri->status_code); "Conntection: close\r\n\r\n", ri->status_code);
mg_printf(conn, "Error: [%d]", ri->status_code); mg_printf(conn, "Error: [%d]", ri->status_code);
} }
static void test_post(struct mg_connection *conn, static void test_post(struct mg_connection *conn,
...@@ -124,7 +130,7 @@ static void test_post(struct mg_connection *conn, ...@@ -124,7 +130,7 @@ static void test_post(struct mg_connection *conn,
char *buf; char *buf;
int len; int len;
mg_printf(conn, "%s", standard_reply); mg_printf(conn, "%s", standard_reply);
if (strcmp(ri->request_method, "POST") == 0 && if (strcmp(ri->request_method, "POST") == 0 &&
(cl = mg_get_header(conn, "Content-Length")) != NULL) { (cl = mg_get_header(conn, "Content-Length")) != NULL) {
len = atoi(cl); len = atoi(cl);
...@@ -166,10 +172,10 @@ static void *callback(enum mg_event event, ...@@ -166,10 +172,10 @@ static void *callback(enum mg_event event,
} }
int main(void) { int main(void) {
struct mg_context *ctx; struct mg_context *ctx;
const char *options[] = {"listening_ports", LISTENING_PORT, NULL}; const char *options[] = {"listening_ports", LISTENING_PORT, NULL};
ctx = mg_start(callback, NULL, options); ctx = mg_start(callback, NULL, options);
pause(); pause();
return 0; return 0;
} }
...@@ -50,7 +50,7 @@ sub get_num_of_log_entries { ...@@ -50,7 +50,7 @@ sub get_num_of_log_entries {
# Send the request to the 127.0.0.1:$port and return the reply # Send the request to the 127.0.0.1:$port and return the reply
sub req { sub req {
my ($request, $inc) = @_; my ($request, $inc, $timeout) = @_;
my $sock = IO::Socket::INET->new(Proto=>"tcp", my $sock = IO::Socket::INET->new(Proto=>"tcp",
PeerAddr=>'127.0.0.1', PeerPort=>$port); PeerAddr=>'127.0.0.1', PeerPort=>$port);
fail("Cannot connect: $!") unless $sock; fail("Cannot connect: $!") unless $sock;
...@@ -59,8 +59,12 @@ sub req { ...@@ -59,8 +59,12 @@ sub req {
last unless print $sock $byte; last unless print $sock $byte;
select undef, undef, undef, .001 if length($request) < 256; select undef, undef, undef, .001 if length($request) < 256;
} }
my @lines = <$sock>; my ($out, $buf) = ('', '');
my $out = join '', @lines; eval {
alarm $timeout if $timeout;
$out .= $buf while (sysread($sock, $buf, 1024) > 0);
alarm 0 if $timeout;
};
close $sock; close $sock;
$num_requests += defined($inc) ? $inc : 1; $num_requests += defined($inc) ? $inc : 1;
...@@ -129,6 +133,7 @@ sub kill_spawned_child { ...@@ -129,6 +133,7 @@ sub kill_spawned_child {
unlink @files_to_delete; unlink @files_to_delete;
$SIG{PIPE} = 'IGNORE'; $SIG{PIPE} = 'IGNORE';
$SIG{ALRM} = sub { die "timeout\n" };
#local $| =1; #local $| =1;
# Make sure we export only symbols that start with "mg_", and keep local # Make sure we export only symbols that start with "mg_", and keep local
...@@ -175,6 +180,14 @@ o("GET /hello.txt HTTP/1.0\n\n", 'Content-Length: 17\s', ...@@ -175,6 +180,14 @@ o("GET /hello.txt HTTP/1.0\n\n", 'Content-Length: 17\s',
o("GET /%68%65%6c%6c%6f%2e%74%78%74 HTTP/1.0\n\n", o("GET /%68%65%6c%6c%6f%2e%74%78%74 HTTP/1.0\n\n",
'HTTP/1.1 200 OK', 'URL-decoding'); 'HTTP/1.1 200 OK', 'URL-decoding');
# Break CGI reading after 1 second. We must get full output.
# Since CGI script does sleep, we sleep as well and increase request count
# manually.
fail('Slow CGI output forward ') unless
req("GET /timeout.cgi HTTP/1.0\r\n\r\n", 0, 1) =~ /Some data/s;
sleep 3;
$num_requests++;
# '+' in URI must not be URL-decoded to space # '+' in URI must not be URL-decoded to space
write_file("$root/a+.txt", ''); write_file("$root/a+.txt", '');
o("GET /a+.txt HTTP/1.0\n\n", 'HTTP/1.1 200 OK', 'URL-decoding, + in URI'); o("GET /a+.txt HTTP/1.0\n\n", 'HTTP/1.1 200 OK', 'URL-decoding, + in URI');
......
#!/usr/bin/env perl
# Make stdout unbuffered
$| = 1;
# This script outputs some content, then sleeps for 5 seconds, then exits.
# Web server should return the content immediately after it is sent,
# not waiting until the script exits.
print "Content-Type: text/html\r\n\r\n";
print "Some data";
sleep 3;
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment