|
@@ -163,7 +163,6 @@ typedef struct DIR {
|
|
|
#include <sys/wait.h>
|
|
|
#include <sys/socket.h>
|
|
|
#include <sys/select.h>
|
|
|
-#include <sys/mman.h>
|
|
|
#include <netinet/in.h>
|
|
|
#include <arpa/inet.h>
|
|
|
#include <sys/time.h>
|
|
@@ -174,15 +173,21 @@ typedef struct DIR {
|
|
|
#include <pwd.h>
|
|
|
#include <unistd.h>
|
|
|
#include <dirent.h>
|
|
|
+#if !defined(NO_SSL_DL) && !defined(NO_SSL)
|
|
|
#include <dlfcn.h>
|
|
|
+#endif
|
|
|
#include <pthread.h>
|
|
|
#if defined(__MACH__)
|
|
|
#define SSL_LIB "libssl.dylib"
|
|
|
#define CRYPTO_LIB "libcrypto.dylib"
|
|
|
#else
|
|
|
+#if !defined(SSL_LIB)
|
|
|
#define SSL_LIB "libssl.so"
|
|
|
+#endif
|
|
|
+#if !defined(CRYPTO_LIB)
|
|
|
#define CRYPTO_LIB "libcrypto.so"
|
|
|
#endif
|
|
|
+#endif
|
|
|
#define DIRSEP '/'
|
|
|
#define IS_DIRSEP_CHAR(c) ((c) == '/')
|
|
|
#define O_BINARY 0
|
|
@@ -557,7 +562,7 @@ static void mg_strlcpy(register char *dst, register const char *src, size_t n) {
|
|
|
}
|
|
|
|
|
|
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) {
|
|
@@ -1280,11 +1285,11 @@ static int64_t push(FILE *fp, SOCKET sock, SSL *ssl, const char *buf,
|
|
|
if (ssl != NULL) {
|
|
|
n = SSL_write(ssl, buf + sent, k);
|
|
|
} else if (fp != NULL) {
|
|
|
- n = fwrite(buf + sent, 1, k, fp);
|
|
|
+ n = fwrite(buf + sent, 1, (size_t)k, fp);
|
|
|
if (ferror(fp))
|
|
|
n = -1;
|
|
|
} else {
|
|
|
- n = send(sock, buf + sent, k, 0);
|
|
|
+ n = send(sock, buf + sent, (size_t)k, 0);
|
|
|
}
|
|
|
|
|
|
if (n < 0)
|
|
@@ -1304,7 +1309,10 @@ static int pull(FILE *fp, SOCKET sock, SSL *ssl, char *buf, int len) {
|
|
|
if (ssl != NULL) {
|
|
|
nread = SSL_read(ssl, buf, len);
|
|
|
} 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))
|
|
|
nread = -1;
|
|
|
} else {
|
|
@@ -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?
|
|
|
- buffered = conn->buf + conn->request_len;
|
|
|
+ buffered = conn->buf + conn->request_len + conn->consumed_content;
|
|
|
buffered_len = conn->data_len - conn->request_len;
|
|
|
assert(buffered_len >= 0);
|
|
|
|
|
@@ -1341,7 +1349,7 @@ int mg_read(struct mg_connection *conn, void *buf, size_t len) {
|
|
|
if (len < (size_t) buffered_len) {
|
|
|
buffered_len = len;
|
|
|
}
|
|
|
- memcpy(buf, buffered, buffered_len);
|
|
|
+ memcpy(buf, buffered, (size_t)buffered_len);
|
|
|
len -= buffered_len;
|
|
|
buf = (char *) buf + buffered_len;
|
|
|
conn->consumed_content += buffered_len;
|
|
@@ -1377,7 +1385,7 @@ int mg_printf(struct mg_connection *conn, const char *fmt, ...) {
|
|
|
len = mg_vsnprintf(conn, buf, sizeof(buf), fmt, 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.
|
|
@@ -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++) {
|
|
|
if (src[i] == '%' &&
|
|
|
- isxdigit(* (unsigned char *) (src + i + 1)) &&
|
|
|
- isxdigit(* (unsigned char *) (src + i + 2))) {
|
|
|
- a = tolower(* (unsigned char *) (src + i + 1));
|
|
|
- b = tolower(* (unsigned char *) (src + i + 2));
|
|
|
+ isxdigit(* (const unsigned char *) (src + i + 1)) &&
|
|
|
+ isxdigit(* (const unsigned char *) (src + i + 2))) {
|
|
|
+ a = tolower(* (const unsigned char *) (src + i + 1));
|
|
|
+ b = tolower(* (const unsigned char *) (src + i + 2));
|
|
|
dst[j] = (char) ((HEXTOI(a) << 4) | HEXTOI(b));
|
|
|
i += 2;
|
|
|
} 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,
|
|
|
p += name_len + 1;
|
|
|
|
|
|
// 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) {
|
|
|
s = e;
|
|
|
}
|
|
@@ -1442,7 +1450,7 @@ int mg_get_var(const char *buf, size_t buf_len, const char *name,
|
|
|
|
|
|
// Decode variable into destination buffer
|
|
|
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;
|
|
|
}
|
|
@@ -1477,7 +1485,7 @@ int mg_get_cookie(const struct mg_connection *conn, const char *cookie_name,
|
|
|
}
|
|
|
if ((size_t) (p - s) < dst_size) {
|
|
|
len = (p - s) + 1;
|
|
|
- mg_strlcpy(dst, s, len);
|
|
|
+ mg_strlcpy(dst, s, (size_t)len);
|
|
|
}
|
|
|
break;
|
|
|
}
|
|
@@ -1531,7 +1539,7 @@ static int sslize(struct mg_connection *conn, int (*func)(SSL *)) {
|
|
|
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) {
|
|
|
struct mg_connection *newconn = NULL;
|
|
|
struct sockaddr_in sin;
|
|
@@ -1578,8 +1586,8 @@ static int get_request_len(const char *buf, int buflen) {
|
|
|
DEBUG_TRACE(("buf: %p, len: %d", buf, buflen));
|
|
|
for (s = buf, e = s + buflen - 1; len <= 0 && s < e; s++)
|
|
|
// Control characters are not allowed but >=128 is.
|
|
|
- if (!isprint(* (unsigned char *) s) && *s != '\r' &&
|
|
|
- *s != '\n' && * (unsigned char *) s < 128) {
|
|
|
+ if (!isprint(* (const unsigned char *) s) && *s != '\r' &&
|
|
|
+ *s != '\n' && * (const unsigned char *) s < 128) {
|
|
|
len = -1;
|
|
|
} else if (s[0] == '\n' && s[1] == '\n') {
|
|
|
len = (int) (s - buf) + 2;
|
|
@@ -1757,7 +1765,7 @@ typedef struct MD5Context {
|
|
|
unsigned char in[64];
|
|
|
} MD5_CTX;
|
|
|
|
|
|
-#if __BYTE_ORDER == 1234
|
|
|
+#if defined(__BYTE_ORDER) && (__BYTE_ORDER == 1234)
|
|
|
#define byteReverse(buf, len) // Do nothing
|
|
|
#else
|
|
|
static void byteReverse(unsigned char *buf, unsigned longs) {
|
|
@@ -1961,7 +1969,7 @@ void mg_md5(char *buf, ...) {
|
|
|
|
|
|
va_start(ap, buf);
|
|
|
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);
|
|
|
|
|
@@ -2052,7 +2060,7 @@ static int parse_auth_header(struct mg_connection *conn, char *buf,
|
|
|
// Parse authorization header
|
|
|
for (;;) {
|
|
|
name = skip(&s, "=");
|
|
|
- value = skip(&s, " ");
|
|
|
+ value = skip(&s, ", "); // IE uses commas, FF uses spaces
|
|
|
|
|
|
// Handle commas: Digest username="a", realm="b", ...
|
|
|
if (value[strlen(value) - 1] == ',') {
|
|
@@ -2256,13 +2264,13 @@ static void url_encode(const char *src, char *dst, size_t dst_len) {
|
|
|
const char *end = dst + dst_len - 1;
|
|
|
|
|
|
for (; *src != '\0' && dst < end; src++, dst++) {
|
|
|
- if (isalnum(*(unsigned char *) src) ||
|
|
|
- strchr(dont_escape, * (unsigned char *) src) != NULL) {
|
|
|
+ if (isalnum(*(const unsigned char *) src) ||
|
|
|
+ strchr(dont_escape, * (const unsigned char *) src) != NULL) {
|
|
|
*dst = *src;
|
|
|
} else if (dst + 2 < end) {
|
|
|
dst[0] = '%';
|
|
|
- dst[1] = hex[(* (unsigned char *) src) >> 4];
|
|
|
- dst[2] = hex[(* (unsigned char *) src) & 0xf];
|
|
|
+ dst[1] = hex[(* (const unsigned char *) src) >> 4];
|
|
|
+ dst[2] = hex[(* (const unsigned char *) src) & 0xf];
|
|
|
dst += 2;
|
|
|
}
|
|
|
}
|
|
@@ -2306,7 +2314,7 @@ static void print_dir_entry(struct de *de) {
|
|
|
// On windows, __cdecl specification is needed in case if project is built
|
|
|
// with __stdcall convention. qsort always requires __cdels callback.
|
|
|
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;
|
|
|
int cmp_result = 0;
|
|
|
|
|
@@ -2408,7 +2416,7 @@ static void handle_directory_request(struct mg_connection *conn,
|
|
|
conn->request_info.uri, "..", "Parent directory", "-", "-");
|
|
|
|
|
|
// 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++) {
|
|
|
print_dir_entry(&entries[i]);
|
|
|
free(entries[i].file_name);
|
|
@@ -2431,11 +2439,11 @@ static void send_file_data(struct mg_connection *conn, FILE *fp, int64_t len) {
|
|
|
to_read = (int) len;
|
|
|
|
|
|
// 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;
|
|
|
|
|
|
// 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;
|
|
|
|
|
|
// Both read and were successful, adjust counters
|
|
@@ -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
|
|
|
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
|
|
|
send_file_data(conn, out, INT64_MAX);
|
|
@@ -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) {
|
|
|
char cmd[BUFSIZ];
|
|
|
FILE *fp;
|
|
@@ -3075,6 +3084,7 @@ static void do_ssi_exec(struct mg_connection *conn, char *tag) {
|
|
|
(void) pclose(fp);
|
|
|
}
|
|
|
}
|
|
|
+#endif // !NO_POPEN
|
|
|
|
|
|
static void send_ssi_file(struct mg_connection *conn, const char *path,
|
|
|
FILE *fp, int include_level) {
|
|
@@ -3097,12 +3107,14 @@ static void send_ssi_file(struct mg_connection *conn, const char *path,
|
|
|
assert(len <= (int) sizeof(buf));
|
|
|
if (len < 6 || memcmp(buf, "<!--#", 5) != 0) {
|
|
|
// Not an SSI tag, pass it
|
|
|
- (void) mg_write(conn, buf, len);
|
|
|
+ (void) mg_write(conn, buf, (size_t)len);
|
|
|
} else {
|
|
|
if (!memcmp(buf + 5, "include", 7)) {
|
|
|
do_ssi_include(conn, path, buf + 12, include_level);
|
|
|
+#if !defined(NO_POPEN)
|
|
|
} else if (!memcmp(buf + 5, "exec", 4)) {
|
|
|
do_ssi_exec(conn, buf + 9);
|
|
|
+#endif // !NO_POPEN
|
|
|
} else {
|
|
|
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,
|
|
|
} else if (ch == '<') {
|
|
|
in_ssi_tag = 1;
|
|
|
if (len > 0) {
|
|
|
- (void) mg_write(conn, buf, len);
|
|
|
+ (void) mg_write(conn, buf, (size_t)len);
|
|
|
}
|
|
|
len = 0;
|
|
|
buf[len++] = ch & 0xff;
|
|
|
} else {
|
|
|
buf[len++] = ch & 0xff;
|
|
|
if (len == (int) sizeof(buf)) {
|
|
|
- (void) mg_write(conn, buf, len);
|
|
|
+ (void) mg_write(conn, buf, (size_t)len);
|
|
|
len = 0;
|
|
|
}
|
|
|
}
|
|
@@ -3135,7 +3147,7 @@ static void send_ssi_file(struct mg_connection *conn, const char *path,
|
|
|
|
|
|
// Send the rest of buffered data
|
|
|
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) {
|
|
|
* conn->request_info.query_string++ = '\0';
|
|
|
}
|
|
|
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);
|
|
|
convert_uri_to_file_name(conn, ri->uri, path, sizeof(path));
|
|
|
|
|
@@ -3548,7 +3560,7 @@ static int set_ssl_option(struct mg_context *ctx) {
|
|
|
// Initialize locking callbacks, needed for thread safety.
|
|
|
// http://www.openssl.org/support/faq.html#PROG1
|
|
|
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());
|
|
|
return 0;
|
|
|
}
|
|
@@ -3643,7 +3655,7 @@ static void discard_current_request_from_buffer(struct mg_connection *conn) {
|
|
|
}
|
|
|
|
|
|
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) {
|
|
@@ -3706,7 +3718,7 @@ static void handle_proxy_request(struct mg_connection *conn) {
|
|
|
// Read data from the target and forward it to the client
|
|
|
while ((n = pull(NULL, conn->peer->client.sock, conn->peer->ssl,
|
|
|
buf, sizeof(buf))) > 0) {
|
|
|
- if (mg_write(conn, buf, n) != n) {
|
|
|
+ if (mg_write(conn, buf, (size_t)n) != n) {
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
@@ -3903,8 +3915,8 @@ static void master_thread(struct mg_context *ctx) {
|
|
|
add_to_set(sp->sock, &read_set, &max_fd);
|
|
|
}
|
|
|
|
|
|
- tv.tv_sec = 1;
|
|
|
- tv.tv_usec = 0;
|
|
|
+ tv.tv_sec = 0;
|
|
|
+ tv.tv_usec = 200 * 1000;
|
|
|
|
|
|
if (select(max_fd + 1, &read_set, NULL, NULL, &tv) < 0) {
|
|
|
#ifdef _WIN32
|