|
@@ -2201,18 +2201,18 @@ static struct ssl_func crypto_sw[] = {{"CRYPTO_num_locks", NULL},
|
|
|
|
|
|
|
|
|
#if !defined(NO_CACHING)
|
|
|
-static const char *month_names[] = {"Jan",
|
|
|
- "Feb",
|
|
|
- "Mar",
|
|
|
- "Apr",
|
|
|
- "May",
|
|
|
- "Jun",
|
|
|
- "Jul",
|
|
|
- "Aug",
|
|
|
- "Sep",
|
|
|
- "Oct",
|
|
|
- "Nov",
|
|
|
- "Dec"};
|
|
|
+static const char month_names[][4] = {"Jan",
|
|
|
+ "Feb",
|
|
|
+ "Mar",
|
|
|
+ "Apr",
|
|
|
+ "May",
|
|
|
+ "Jun",
|
|
|
+ "Jul",
|
|
|
+ "Aug",
|
|
|
+ "Sep",
|
|
|
+ "Oct",
|
|
|
+ "Nov",
|
|
|
+ "Dec"};
|
|
|
#endif /* !NO_CACHING */
|
|
|
|
|
|
/* Unified socket address. For IPv6 support, add IPv6 address structure in
|
|
@@ -2753,14 +2753,12 @@ struct mg_connection {
|
|
|
* throttle */
|
|
|
|
|
|
time_t last_throttle_time; /* Last time throttled data was sent */
|
|
|
- int64_t last_throttle_bytes; /* Bytes sent this second */
|
|
|
+ int last_throttle_bytes; /* Bytes sent this second */
|
|
|
pthread_mutex_t mutex; /* Used by mg_(un)lock_connection to ensure
|
|
|
* atomic transmissions for websockets */
|
|
|
#if defined(USE_LUA) && defined(USE_WEBSOCKET)
|
|
|
void *lua_websocket_state; /* Lua_State for a websocket connection */
|
|
|
#endif
|
|
|
-
|
|
|
- int thread_index; /* Thread index within ctx */
|
|
|
};
|
|
|
|
|
|
|
|
@@ -3273,7 +3271,7 @@ mg_strlcpy(register char *dst, register const char *src, size_t n)
|
|
|
static int
|
|
|
lowercase(const char *s)
|
|
|
{
|
|
|
- return tolower(*(const unsigned char *)s);
|
|
|
+ return tolower((unsigned char)*s);
|
|
|
}
|
|
|
|
|
|
|
|
@@ -5110,10 +5108,11 @@ mg_wcscasecmp(const wchar_t *s1, const wchar_t *s2)
|
|
|
int diff;
|
|
|
|
|
|
do {
|
|
|
- diff = tolower(*s1) - tolower(*s2);
|
|
|
+ diff = ((*s1 >= L'A') && (*s1 <= L'Z') ? (*s1 - L'A' + L'a') : *s1)
|
|
|
+ - ((*s2 >= L'A') && (*s2 <= L'Z') ? (*s2 - L'A' + L'a') : *s2);
|
|
|
s1++;
|
|
|
s2++;
|
|
|
- } while ((diff == 0) && (s1[-1] != '\0'));
|
|
|
+ } while ((diff == 0) && (s1[-1] != L'\0'));
|
|
|
|
|
|
return diff;
|
|
|
}
|
|
@@ -5191,19 +5190,6 @@ path_to_unicode(const struct mg_connection *conn,
|
|
|
}
|
|
|
|
|
|
|
|
|
-/* Windows happily opens files with some garbage at the end of file name.
|
|
|
- * For example, fopen("a.cgi ", "r") on Windows successfully opens
|
|
|
- * "a.cgi", despite one would expect an error back.
|
|
|
- * This function returns non-0 if path ends with some garbage. */
|
|
|
-static int
|
|
|
-path_cannot_disclose_cgi(const char *path)
|
|
|
-{
|
|
|
- static const char *allowed_last_characters = "_-";
|
|
|
- int last = path[strlen(path) - 1];
|
|
|
- return isalnum(last) || strchr(allowed_last_characters, last) != NULL;
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
static int
|
|
|
mg_stat(const struct mg_connection *conn,
|
|
|
const char *path,
|
|
@@ -5212,6 +5198,7 @@ mg_stat(const struct mg_connection *conn,
|
|
|
wchar_t wbuf[W_PATH_MAX];
|
|
|
WIN32_FILE_ATTRIBUTE_DATA info;
|
|
|
time_t creation_time;
|
|
|
+ size_t len;
|
|
|
|
|
|
if (!filep) {
|
|
|
return 0;
|
|
@@ -5248,7 +5235,12 @@ mg_stat(const struct mg_connection *conn,
|
|
|
}
|
|
|
|
|
|
path_to_unicode(conn, path, wbuf, ARRAY_SIZE(wbuf));
|
|
|
- if (GetFileAttributesExW(wbuf, GetFileExInfoStandard, &info) != 0) {
|
|
|
+ /* Windows happily opens files with some garbage at the end of file name.
|
|
|
+ * For example, fopen("a.cgi ", "r") on Windows successfully opens
|
|
|
+ * "a.cgi", despite one would expect an error back. */
|
|
|
+ len = strlen(path);
|
|
|
+ if ((len > 0) && (path[len - 1] != ' ') && (path[len - 1] != '.')
|
|
|
+ && (GetFileAttributesExW(wbuf, GetFileExInfoStandard, &info) != 0)) {
|
|
|
filep->size = MAKEUQUAD(info.nFileSizeLow, info.nFileSizeHigh);
|
|
|
filep->last_modified =
|
|
|
SYS2UNIX_TIME(info.ftLastWriteTime.dwLowDateTime,
|
|
@@ -5265,15 +5257,6 @@ mg_stat(const struct mg_connection *conn,
|
|
|
}
|
|
|
|
|
|
filep->is_directory = info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY;
|
|
|
- /* If file name is fishy, reset the file structure and return
|
|
|
- * error.
|
|
|
- * Note it is important to reset, not just return the error, cause
|
|
|
- * functions like is_file_opened() check the struct. */
|
|
|
- if (!filep->is_directory && !path_cannot_disclose_cgi(path)) {
|
|
|
- memset(filep, 0, sizeof(*filep));
|
|
|
- return 0;
|
|
|
- }
|
|
|
-
|
|
|
return 1;
|
|
|
}
|
|
|
|
|
@@ -5421,9 +5404,10 @@ poll(struct mg_pollfd *pfd, unsigned int n, int milliseconds)
|
|
|
|
|
|
for (i = 0; i < n; i++) {
|
|
|
if (pfd[i].events & POLLIN) {
|
|
|
- FD_SET((SOCKET)pfd[i].fd, &rset);
|
|
|
- } else if (pfd[i].events & POLLOUT) {
|
|
|
- FD_SET((SOCKET)pfd[i].fd, &wset);
|
|
|
+ FD_SET(pfd[i].fd, &rset);
|
|
|
+ }
|
|
|
+ if (pfd[i].events & POLLOUT) {
|
|
|
+ FD_SET(pfd[i].fd, &wset);
|
|
|
}
|
|
|
pfd[i].revents = 0;
|
|
|
|
|
@@ -5503,9 +5487,9 @@ mg_start_thread_with_id(unsigned(__stdcall *f)(void *),
|
|
|
HANDLE threadhandle;
|
|
|
int result = -1;
|
|
|
|
|
|
- uip = _beginthreadex(NULL, 0, (unsigned(__stdcall *)(void *))f, p, 0, NULL);
|
|
|
+ uip = _beginthreadex(NULL, 0, f, p, 0, NULL);
|
|
|
threadhandle = (HANDLE)uip;
|
|
|
- if ((uip != (uintptr_t)(-1L)) && (threadidptr != NULL)) {
|
|
|
+ if ((uip != 0) && (threadidptr != NULL)) {
|
|
|
*threadidptr = threadhandle;
|
|
|
result = 0;
|
|
|
}
|
|
@@ -5625,9 +5609,9 @@ waitpid(pid_t pid, int *status, int flags)
|
|
|
static void
|
|
|
trim_trailing_whitespaces(char *s)
|
|
|
{
|
|
|
- char *e = s + strlen(s) - 1;
|
|
|
- while ((e > s) && isspace(*(unsigned char *)e)) {
|
|
|
- *e-- = '\0';
|
|
|
+ char *e = s + strlen(s);
|
|
|
+ while ((e > s) && isspace((unsigned char)e[-1])) {
|
|
|
+ *(--e) = '\0';
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -5965,6 +5949,8 @@ spawn_process(struct mg_connection *conn,
|
|
|
fderr[1],
|
|
|
strerror(ERRNO));
|
|
|
} else {
|
|
|
+ struct sigaction sa;
|
|
|
+
|
|
|
/* Keep stderr and stdout in two different pipes.
|
|
|
* Stdout will be sent back to the client,
|
|
|
* stderr should go into a server error log. */
|
|
@@ -5982,7 +5968,9 @@ spawn_process(struct mg_connection *conn,
|
|
|
* POSIX.1-2001 and Linux's implementation, SIGCHLD's handler
|
|
|
* will leave unchanged after exec if it was set to be ignored.
|
|
|
* Restore it to default action. */
|
|
|
- signal(SIGCHLD, SIG_DFL);
|
|
|
+ memset(&sa, 0, sizeof(sa));
|
|
|
+ sa.sa_handler = SIG_DFL;
|
|
|
+ sigaction(SIGCHLD, &sa, NULL);
|
|
|
|
|
|
interp = conn->dom_ctx->config[CGI_INTERPRETER];
|
|
|
if (interp == NULL) {
|
|
@@ -6267,16 +6255,16 @@ push_inner(struct mg_context *ctx,
|
|
|
}
|
|
|
|
|
|
|
|
|
-static int64_t
|
|
|
+static int
|
|
|
push_all(struct mg_context *ctx,
|
|
|
FILE *fp,
|
|
|
SOCKET sock,
|
|
|
SSL *ssl,
|
|
|
const char *buf,
|
|
|
- int64_t len)
|
|
|
+ int len)
|
|
|
{
|
|
|
double timeout = -1.0;
|
|
|
- int64_t n, nwritten = 0;
|
|
|
+ int n, nwritten = 0;
|
|
|
|
|
|
if (ctx == NULL) {
|
|
|
return -1;
|
|
@@ -6287,10 +6275,10 @@ push_all(struct mg_context *ctx,
|
|
|
}
|
|
|
|
|
|
while ((len > 0) && (ctx->stop_flag == 0)) {
|
|
|
- n = push_inner(ctx, fp, sock, ssl, buf + nwritten, (int)len, timeout);
|
|
|
+ n = push_inner(ctx, fp, sock, ssl, buf + nwritten, len, timeout);
|
|
|
if (n < 0) {
|
|
|
if (nwritten == 0) {
|
|
|
- nwritten = n; /* Propagate the error */
|
|
|
+ nwritten = -1; /* Propagate the error */
|
|
|
}
|
|
|
break;
|
|
|
} else if (n == 0) {
|
|
@@ -6745,7 +6733,7 @@ mg_read(struct mg_connection *conn, void *buf, size_t len)
|
|
|
}
|
|
|
break;
|
|
|
}
|
|
|
- if (!isxdigit(lenbuf[i])) {
|
|
|
+ if (!isxdigit((unsigned char)lenbuf[i])) {
|
|
|
/* illegal character for chunk length */
|
|
|
return -1;
|
|
|
}
|
|
@@ -6772,11 +6760,14 @@ int
|
|
|
mg_write(struct mg_connection *conn, const void *buf, size_t len)
|
|
|
{
|
|
|
time_t now;
|
|
|
- int64_t n, total, allowed;
|
|
|
+ int n, total, allowed;
|
|
|
|
|
|
if (conn == NULL) {
|
|
|
return 0;
|
|
|
}
|
|
|
+ if (len > INT_MAX) {
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
|
|
|
if (conn->throttle > 0) {
|
|
|
if ((now = time(NULL)) != conn->last_throttle_time) {
|
|
@@ -6784,28 +6775,28 @@ mg_write(struct mg_connection *conn, const void *buf, size_t len)
|
|
|
conn->last_throttle_bytes = 0;
|
|
|
}
|
|
|
allowed = conn->throttle - conn->last_throttle_bytes;
|
|
|
- if (allowed > (int64_t)len) {
|
|
|
- allowed = (int64_t)len;
|
|
|
+ if (allowed > (int)len) {
|
|
|
+ allowed = (int)len;
|
|
|
}
|
|
|
if ((total = push_all(conn->phys_ctx,
|
|
|
NULL,
|
|
|
conn->client.sock,
|
|
|
conn->ssl,
|
|
|
(const char *)buf,
|
|
|
- (int64_t)allowed))
|
|
|
+ allowed))
|
|
|
== allowed) {
|
|
|
buf = (const char *)buf + total;
|
|
|
conn->last_throttle_bytes += total;
|
|
|
- while ((total < (int64_t)len) && (conn->phys_ctx->stop_flag == 0)) {
|
|
|
- allowed = (conn->throttle > ((int64_t)len - total))
|
|
|
- ? (int64_t)len - total
|
|
|
+ while ((total < (int)len) && (conn->phys_ctx->stop_flag == 0)) {
|
|
|
+ allowed = (conn->throttle > ((int)len - total))
|
|
|
+ ? (int)len - total
|
|
|
: conn->throttle;
|
|
|
if ((n = push_all(conn->phys_ctx,
|
|
|
NULL,
|
|
|
conn->client.sock,
|
|
|
conn->ssl,
|
|
|
(const char *)buf,
|
|
|
- (int64_t)allowed))
|
|
|
+ allowed))
|
|
|
!= allowed) {
|
|
|
break;
|
|
|
}
|
|
@@ -6822,12 +6813,12 @@ mg_write(struct mg_connection *conn, const void *buf, size_t len)
|
|
|
conn->client.sock,
|
|
|
conn->ssl,
|
|
|
(const char *)buf,
|
|
|
- (int64_t)len);
|
|
|
+ (int)len);
|
|
|
}
|
|
|
if (total > 0) {
|
|
|
conn->num_bytes_sent += total;
|
|
|
}
|
|
|
- return (int)total;
|
|
|
+ return total;
|
|
|
}
|
|
|
|
|
|
|
|
@@ -7018,10 +7009,10 @@ mg_url_decode(const char *src,
|
|
|
|
|
|
for (i = j = 0; (i < src_len) && (j < (dst_len - 1)); i++, j++) {
|
|
|
if ((i < src_len - 2) && (src[i] == '%')
|
|
|
- && 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));
|
|
|
+ && 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]);
|
|
|
dst[j] = (char)((HEXTOI(a) << 4) | HEXTOI(b));
|
|
|
i += 2;
|
|
|
} else if (is_form_url_encoded && (src[i] == '+')) {
|
|
@@ -7665,7 +7656,7 @@ get_http_header_len(const char *buf, int buflen)
|
|
|
int i;
|
|
|
for (i = 0; i < buflen; i++) {
|
|
|
/* Do an unsigned comparison in some conditions below */
|
|
|
- const unsigned char c = ((const unsigned char *)buf)[i];
|
|
|
+ const unsigned char c = (unsigned char)buf[i];
|
|
|
|
|
|
if ((c < 128) && ((char)c != '\r') && ((char)c != '\n')
|
|
|
&& !isprint(c)) {
|
|
@@ -8154,7 +8145,7 @@ parse_auth_header(struct mg_connection *conn,
|
|
|
/* Parse authorization header */
|
|
|
for (;;) {
|
|
|
/* Gobble initial spaces */
|
|
|
- while (isspace(*(unsigned char *)s)) {
|
|
|
+ while (isspace((unsigned char)*s)) {
|
|
|
s++;
|
|
|
}
|
|
|
name = skip_quoted(&s, "=", " ", 0);
|
|
@@ -8323,8 +8314,8 @@ read_auth_file(struct mg_file *filep,
|
|
|
while (mg_fgets(workdata->buf, sizeof(workdata->buf), filep, &p) != NULL) {
|
|
|
l = strlen(workdata->buf);
|
|
|
while (l > 0) {
|
|
|
- if (isspace(workdata->buf[l - 1])
|
|
|
- || iscntrl(workdata->buf[l - 1])) {
|
|
|
+ if (isspace((unsigned char)workdata->buf[l - 1])
|
|
|
+ || iscntrl((unsigned char)workdata->buf[l - 1])) {
|
|
|
l--;
|
|
|
workdata->buf[l] = 0;
|
|
|
} else
|
|
@@ -8629,7 +8620,7 @@ mg_modify_passwords_file(const char *fname,
|
|
|
/* Do not allow control characters like newline in user name and domain.
|
|
|
* Do not allow excessively long names either. */
|
|
|
for (i = 0; ((i < 255) && (user[i] != 0)); i++) {
|
|
|
- if (iscntrl(user[i])) {
|
|
|
+ if (iscntrl((unsigned char)user[i])) {
|
|
|
return 0;
|
|
|
}
|
|
|
}
|
|
@@ -8637,7 +8628,7 @@ mg_modify_passwords_file(const char *fname,
|
|
|
return 0;
|
|
|
}
|
|
|
for (i = 0; ((i < 255) && (domain[i] != 0)); i++) {
|
|
|
- if (iscntrl(domain[i])) {
|
|
|
+ if (iscntrl((unsigned char)domain[i])) {
|
|
|
return 0;
|
|
|
}
|
|
|
}
|
|
@@ -8989,13 +8980,13 @@ mg_url_encode(const char *src, char *dst, size_t dst_len)
|
|
|
const char *end = dst + dst_len - 1;
|
|
|
|
|
|
for (; ((*src != '\0') && (pos < end)); src++, pos++) {
|
|
|
- if (isalnum(*(const unsigned char *)src)
|
|
|
- || (strchr(dont_escape, *(const unsigned char *)src) != NULL)) {
|
|
|
+ if (isalnum((unsigned char)*src)
|
|
|
+ || (strchr(dont_escape, *src) != NULL)) {
|
|
|
*pos = *src;
|
|
|
} else if (pos + 2 < end) {
|
|
|
pos[0] = '%';
|
|
|
- pos[1] = hex[(*(const unsigned char *)src) >> 4];
|
|
|
- pos[2] = hex[(*(const unsigned char *)src) & 0xf];
|
|
|
+ pos[1] = hex[(unsigned char)*src >> 4];
|
|
|
+ pos[2] = hex[(unsigned char)*src & 0xf];
|
|
|
pos += 2;
|
|
|
} else {
|
|
|
break;
|
|
@@ -9011,8 +9002,8 @@ mg_url_encode(const char *src, char *dst, size_t dst_len)
|
|
|
static int
|
|
|
print_dir_entry(struct de *de)
|
|
|
{
|
|
|
- size_t hrefsize;
|
|
|
- char *href;
|
|
|
+ size_t namesize, escsize, i;
|
|
|
+ char *href, *esc, *p;
|
|
|
char size[64], mod[64];
|
|
|
#if defined(REENTRANT_TIME)
|
|
|
struct tm _tm;
|
|
@@ -9021,11 +9012,30 @@ print_dir_entry(struct de *de)
|
|
|
struct tm *tm;
|
|
|
#endif
|
|
|
|
|
|
- hrefsize = PATH_MAX * 3; /* worst case */
|
|
|
- href = (char *)mg_malloc(hrefsize);
|
|
|
+ /* Estimate worst case size for encoding and escaping */
|
|
|
+ namesize = strlen(de->file_name) + 1;
|
|
|
+ escsize = de->file_name[strcspn(de->file_name, "&<>")] ? namesize * 5 : 0;
|
|
|
+ href = (char *)mg_malloc(namesize * 3 + escsize);
|
|
|
if (href == NULL) {
|
|
|
return -1;
|
|
|
}
|
|
|
+ mg_url_encode(de->file_name, href, namesize * 3);
|
|
|
+ esc = NULL;
|
|
|
+ if (escsize > 0) {
|
|
|
+ /* HTML escaping needed */
|
|
|
+ esc = href + namesize * 3;
|
|
|
+ for (i = 0, p = esc; de->file_name[i]; i++, p += strlen(p)) {
|
|
|
+ mg_strlcpy(p, de->file_name + i, 2);
|
|
|
+ if (*p == '&') {
|
|
|
+ strcpy(p, "&");
|
|
|
+ } else if (*p == '<') {
|
|
|
+ strcpy(p, "<");
|
|
|
+ } else if (*p == '>') {
|
|
|
+ strcpy(p, ">");
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
if (de->file.is_directory) {
|
|
|
mg_snprintf(de->conn,
|
|
|
NULL, /* Buffer is big enough */
|
|
@@ -9081,16 +9091,15 @@ print_dir_entry(struct de *de)
|
|
|
mg_strlcpy(mod, "01-Jan-1970 00:00", sizeof(mod));
|
|
|
mod[sizeof(mod) - 1] = '\0';
|
|
|
}
|
|
|
- mg_url_encode(de->file_name, href, hrefsize);
|
|
|
mg_printf(de->conn,
|
|
|
- "<tr><td><a href=\"%s%s\">%s%s</a></td>"
|
|
|
- "<td> %s</td><td> %s</td></tr>\n",
|
|
|
- href,
|
|
|
- de->file.is_directory ? "/" : "",
|
|
|
- de->file_name,
|
|
|
- de->file.is_directory ? "/" : "",
|
|
|
- mod,
|
|
|
- size);
|
|
|
+ "<tr><td><a href=\"%s%s\">%s%s</a></td>"
|
|
|
+ "<td> %s</td><td> %s</td></tr>\n",
|
|
|
+ href,
|
|
|
+ de->file.is_directory ? "/" : "",
|
|
|
+ esc ? esc : de->file_name,
|
|
|
+ de->file.is_directory ? "/" : "",
|
|
|
+ mod,
|
|
|
+ size);
|
|
|
mg_free(href);
|
|
|
return 0;
|
|
|
}
|
|
@@ -9108,8 +9117,8 @@ compare_dir_entries(const void *p1, const void *p2)
|
|
|
const char *query_string = a->conn->request_info.query_string;
|
|
|
int cmp_result = 0;
|
|
|
|
|
|
- if (query_string == NULL) {
|
|
|
- query_string = "na";
|
|
|
+ if ((query_string == NULL) || (query_string[0] == '\0')) {
|
|
|
+ query_string = "n";
|
|
|
}
|
|
|
|
|
|
if (a->file.is_directory && !b->file.is_directory) {
|
|
@@ -9324,7 +9333,8 @@ handle_directory_request(struct mg_connection *conn, const char *dir)
|
|
|
unsigned int i;
|
|
|
int sort_direction;
|
|
|
struct dir_scan_data data = {NULL, 0, 128};
|
|
|
- char date[64];
|
|
|
+ char date[64], *esc, *p;
|
|
|
+ const char *title;
|
|
|
time_t curtime = time(NULL);
|
|
|
|
|
|
if (!scan_directory(conn, dir, &data, dir_scan_callback)) {
|
|
@@ -9342,7 +9352,29 @@ handle_directory_request(struct mg_connection *conn, const char *dir)
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
+ esc = NULL;
|
|
|
+ title = conn->request_info.local_uri;
|
|
|
+ if (title[strcspn(title, "&<>")]) {
|
|
|
+ /* HTML escaping needed */
|
|
|
+ esc = (char *)mg_malloc(strlen(title) * 5 + 1);
|
|
|
+ if (esc) {
|
|
|
+ for (i = 0, p = esc; title[i]; i++, p += strlen(p)) {
|
|
|
+ mg_strlcpy(p, title + i, 2);
|
|
|
+ if (*p == '&') {
|
|
|
+ strcpy(p, "&");
|
|
|
+ } else if (*p == '<') {
|
|
|
+ strcpy(p, "<");
|
|
|
+ } else if (*p == '>') {
|
|
|
+ strcpy(p, ">");
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ title = "";
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
sort_direction = ((conn->request_info.query_string != NULL)
|
|
|
+ && (conn->request_info.query_string[0] != '\0')
|
|
|
&& (conn->request_info.query_string[1] == 'd'))
|
|
|
? 'a'
|
|
|
: 'd';
|
|
@@ -9364,20 +9396,21 @@ handle_directory_request(struct mg_connection *conn, const char *dir)
|
|
|
"<th><a href=\"?d%c\">Modified</a></th>"
|
|
|
"<th><a href=\"?s%c\">Size</a></th></tr>"
|
|
|
"<tr><td colspan=\"3\"><hr></td></tr>",
|
|
|
- conn->request_info.local_uri,
|
|
|
- conn->request_info.local_uri,
|
|
|
+ esc ? esc : title,
|
|
|
+ esc ? esc : title,
|
|
|
sort_direction,
|
|
|
sort_direction,
|
|
|
sort_direction);
|
|
|
+ mg_free(esc);
|
|
|
|
|
|
/* Print first entry - link to a parent directory */
|
|
|
mg_printf(conn,
|
|
|
- "<tr><td><a href=\"%s\">%s</a></td>"
|
|
|
- "<td> %s</td><td> %s</td></tr>\n",
|
|
|
- "..",
|
|
|
- "Parent directory",
|
|
|
- "-",
|
|
|
- "-");
|
|
|
+ "<tr><td><a href=\"%s\">%s</a></td>"
|
|
|
+ "<td> %s</td><td> %s</td></tr>\n",
|
|
|
+ "..",
|
|
|
+ "Parent directory",
|
|
|
+ "-",
|
|
|
+ "-");
|
|
|
|
|
|
/* Sort and print directory entries */
|
|
|
if (data.entries != NULL) {
|
|
@@ -9392,7 +9425,7 @@ handle_directory_request(struct mg_connection *conn, const char *dir)
|
|
|
mg_free(data.entries);
|
|
|
}
|
|
|
|
|
|
- mg_printf(conn, "%s", "</table></body></html>");
|
|
|
+ mg_printf(conn, "%s", "</table></pre></body></html>");
|
|
|
conn->status_code = 200;
|
|
|
}
|
|
|
|
|
@@ -10028,7 +10061,7 @@ skip_to_end_of_word_and_terminate(char **ppw, int eol)
|
|
|
{
|
|
|
/* Forward until a space is found - use isgraph here */
|
|
|
/* See http://www.cplusplus.com/reference/cctype/ */
|
|
|
- while (isgraph(**ppw)) {
|
|
|
+ while (isgraph((unsigned char)**ppw)) {
|
|
|
(*ppw)++;
|
|
|
}
|
|
|
|
|
@@ -10049,12 +10082,12 @@ skip_to_end_of_word_and_terminate(char **ppw, int eol)
|
|
|
do {
|
|
|
**ppw = 0;
|
|
|
(*ppw)++;
|
|
|
- } while ((**ppw) && isspace(**ppw));
|
|
|
+ } while (isspace((unsigned char)**ppw));
|
|
|
|
|
|
/* Check after term */
|
|
|
if (!eol) {
|
|
|
/* if it's not the end of line, there must be a next word */
|
|
|
- if (!isgraph(**ppw)) {
|
|
|
+ if (!isgraph((unsigned char)**ppw)) {
|
|
|
return -1;
|
|
|
}
|
|
|
}
|
|
@@ -10239,7 +10272,7 @@ parse_http_request(char *buf, int len, struct mg_request_info *ri)
|
|
|
/* RFC says that all initial whitespaces should be ingored */
|
|
|
/* This included all leading \r and \n (isspace) */
|
|
|
/* See table: http://www.cplusplus.com/reference/cctype/ */
|
|
|
- while ((len > 0) && isspace(*(unsigned char *)buf)) {
|
|
|
+ while ((len > 0) && isspace((unsigned char)*buf)) {
|
|
|
buf++;
|
|
|
len--;
|
|
|
init_skip++;
|
|
@@ -10251,7 +10284,7 @@ parse_http_request(char *buf, int len, struct mg_request_info *ri)
|
|
|
}
|
|
|
|
|
|
/* Control characters are not allowed, including zero */
|
|
|
- if (iscntrl(*(unsigned char *)buf)) {
|
|
|
+ if (iscntrl((unsigned char)*buf)) {
|
|
|
return -1;
|
|
|
}
|
|
|
|
|
@@ -10326,7 +10359,7 @@ parse_http_response(char *buf, int len, struct mg_response_info *ri)
|
|
|
/* RFC says that all initial whitespaces should be ingored */
|
|
|
/* This included all leading \r and \n (isspace) */
|
|
|
/* See table: http://www.cplusplus.com/reference/cctype/ */
|
|
|
- while ((len > 0) && isspace(*(unsigned char *)buf)) {
|
|
|
+ while ((len > 0) && isspace((unsigned char)*buf)) {
|
|
|
buf++;
|
|
|
len--;
|
|
|
init_skip++;
|
|
@@ -10338,7 +10371,7 @@ parse_http_response(char *buf, int len, struct mg_response_info *ri)
|
|
|
}
|
|
|
|
|
|
/* Control characters are not allowed, including zero */
|
|
|
- if (iscntrl(*(unsigned char *)buf)) {
|
|
|
+ if (iscntrl((unsigned char)*buf)) {
|
|
|
return -1;
|
|
|
}
|
|
|
|
|
@@ -10360,7 +10393,7 @@ parse_http_response(char *buf, int len, struct mg_response_info *ri)
|
|
|
return -1;
|
|
|
}
|
|
|
buf += 5;
|
|
|
- if (!isgraph(buf[0])) {
|
|
|
+ if (!isgraph((unsigned char)buf[0])) {
|
|
|
/* Invalid request */
|
|
|
return -1;
|
|
|
}
|
|
@@ -10389,7 +10422,7 @@ parse_http_response(char *buf, int len, struct mg_response_info *ri)
|
|
|
|
|
|
/* Find end of status text */
|
|
|
/* isgraph or isspace = isprint */
|
|
|
- while (isprint(*buf)) {
|
|
|
+ while (isprint((unsigned char)*buf)) {
|
|
|
buf++;
|
|
|
}
|
|
|
if ((*buf != '\r') && (*buf != '\n')) {
|
|
@@ -10399,7 +10432,7 @@ parse_http_response(char *buf, int len, struct mg_response_info *ri)
|
|
|
do {
|
|
|
*buf = 0;
|
|
|
buf++;
|
|
|
- } while ((*buf) && isspace(*buf));
|
|
|
+ } while (isspace((unsigned char)*buf));
|
|
|
|
|
|
|
|
|
/* Parse all HTTP headers */
|
|
@@ -10499,7 +10532,7 @@ forward_body_data(struct mg_connection *conn, FILE *fp, SOCKET sock, SSL *ssl)
|
|
|
const char *expect, *body;
|
|
|
char buf[MG_BUF_LEN];
|
|
|
int to_read, nread, success = 0;
|
|
|
- int64_t buffered_len;
|
|
|
+ int buffered_len;
|
|
|
double timeout = -1.0;
|
|
|
|
|
|
if (!conn) {
|
|
@@ -10538,8 +10571,7 @@ forward_body_data(struct mg_connection *conn, FILE *fp, SOCKET sock, SSL *ssl)
|
|
|
conn->status_code = 200;
|
|
|
}
|
|
|
|
|
|
- buffered_len = (int64_t)(conn->data_len) - (int64_t)conn->request_len
|
|
|
- - conn->consumed_content;
|
|
|
+ buffered_len = conn->data_len - conn->request_len;
|
|
|
|
|
|
DEBUG_ASSERT(buffered_len >= 0);
|
|
|
DEBUG_ASSERT(conn->consumed_content == 0);
|
|
@@ -10553,9 +10585,8 @@ forward_body_data(struct mg_connection *conn, FILE *fp, SOCKET sock, SSL *ssl)
|
|
|
if ((int64_t)buffered_len > conn->content_len) {
|
|
|
buffered_len = (int)conn->content_len;
|
|
|
}
|
|
|
- body = conn->buf + conn->request_len + conn->consumed_content;
|
|
|
- push_all(
|
|
|
- conn->phys_ctx, fp, sock, ssl, body, (int64_t)buffered_len);
|
|
|
+ body = conn->buf + conn->request_len;
|
|
|
+ push_all(conn->phys_ctx, fp, sock, ssl, body, buffered_len);
|
|
|
conn->consumed_content += buffered_len;
|
|
|
}
|
|
|
|
|
@@ -10575,8 +10606,8 @@ forward_body_data(struct mg_connection *conn, FILE *fp, SOCKET sock, SSL *ssl)
|
|
|
!= nread) {
|
|
|
break;
|
|
|
}
|
|
|
+ conn->consumed_content += nread;
|
|
|
}
|
|
|
- conn->consumed_content += nread;
|
|
|
}
|
|
|
|
|
|
if (conn->consumed_content == conn->content_len) {
|
|
@@ -10880,7 +10911,7 @@ prepare_cgi_environment(struct mg_connection *conn,
|
|
|
if (*p == '-') {
|
|
|
*p = '_';
|
|
|
}
|
|
|
- *p = (char)toupper(*(unsigned char *)p);
|
|
|
+ *p = (char)toupper((unsigned char)*p);
|
|
|
}
|
|
|
|
|
|
addenv(env,
|
|
@@ -11215,8 +11246,7 @@ handle_cgi_request(struct mg_connection *conn, const char *prog)
|
|
|
!= NULL) {
|
|
|
conn->status_code = atoi(status);
|
|
|
status_text = status;
|
|
|
- while (isdigit(*(const unsigned char *)status_text)
|
|
|
- || *status_text == ' ') {
|
|
|
+ while (isdigit((unsigned char)*status_text) || *status_text == ' ') {
|
|
|
status_text++;
|
|
|
}
|
|
|
} else if (get_header(ri.http_headers, ri.num_headers, "Location")
|
|
@@ -11914,16 +11944,40 @@ send_options(struct mg_connection *conn)
|
|
|
|
|
|
|
|
|
/* Writes PROPFIND properties for a collection element */
|
|
|
-static void
|
|
|
+static int
|
|
|
print_props(struct mg_connection *conn,
|
|
|
const char *uri,
|
|
|
+ const char *name,
|
|
|
struct mg_file_stat *filep)
|
|
|
{
|
|
|
- char mtime[64];
|
|
|
+ size_t href_size, i, j;
|
|
|
+ int len;
|
|
|
+ char *href, mtime[64];
|
|
|
|
|
|
- if ((conn == NULL) || (uri == NULL) || (filep == NULL)) {
|
|
|
- return;
|
|
|
+ if ((conn == NULL) || (uri == NULL) || (name == NULL) || (filep == NULL)) {
|
|
|
+ return 0;
|
|
|
}
|
|
|
+ /* Estimate worst case size for encoding */
|
|
|
+ href_size = (strlen(uri) + strlen(name)) * 3 + 1;
|
|
|
+ href = (char *)mg_malloc(href_size);
|
|
|
+ if (href == NULL) {
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+ len = mg_url_encode(uri, href, href_size);
|
|
|
+ if (len >= 0) {
|
|
|
+ /* Append an extra string */
|
|
|
+ mg_url_encode(name, href + len, href_size - (size_t)len);
|
|
|
+ }
|
|
|
+ /* Directory separator should be preserved. */
|
|
|
+ for (i = j = 0; href[i]; j++) {
|
|
|
+ if (!strncmp(href + i, "%2f", 3)) {
|
|
|
+ href[j] = '/';
|
|
|
+ i += 3;
|
|
|
+ } else {
|
|
|
+ href[j] = href[i++];
|
|
|
+ }
|
|
|
+ }
|
|
|
+ href[j] = '\0';
|
|
|
|
|
|
gmt_time_string(mtime, sizeof(mtime), &filep->last_modified);
|
|
|
mg_printf(conn,
|
|
@@ -11938,45 +11992,23 @@ print_props(struct mg_connection *conn,
|
|
|
"<d:status>HTTP/1.1 200 OK</d:status>"
|
|
|
"</d:propstat>"
|
|
|
"</d:response>\n",
|
|
|
- uri,
|
|
|
+ href,
|
|
|
filep->is_directory ? "<d:collection/>" : "",
|
|
|
filep->size,
|
|
|
mtime);
|
|
|
+ mg_free(href);
|
|
|
+ return 1;
|
|
|
}
|
|
|
|
|
|
|
|
|
static int
|
|
|
print_dav_dir_entry(struct de *de, void *data)
|
|
|
{
|
|
|
- char href[PATH_MAX];
|
|
|
- int truncated;
|
|
|
-
|
|
|
struct mg_connection *conn = (struct mg_connection *)data;
|
|
|
- if (!de || !conn) {
|
|
|
+ if (!de || !conn || !print_props(conn, conn->request_info.local_uri,
|
|
|
+ de->file_name, &de->file)) {
|
|
|
return -1;
|
|
|
}
|
|
|
- mg_snprintf(conn,
|
|
|
- &truncated,
|
|
|
- href,
|
|
|
- sizeof(href),
|
|
|
- "%s%s",
|
|
|
- conn->request_info.local_uri,
|
|
|
- de->file_name);
|
|
|
-
|
|
|
- if (!truncated) {
|
|
|
- size_t href_encoded_size;
|
|
|
- char *href_encoded;
|
|
|
-
|
|
|
- href_encoded_size = PATH_MAX * 3; /* worst case */
|
|
|
- href_encoded = (char *)mg_malloc(href_encoded_size);
|
|
|
- if (href_encoded == NULL) {
|
|
|
- return -1;
|
|
|
- }
|
|
|
- mg_url_encode(href, href_encoded, href_encoded_size);
|
|
|
- print_props(conn, href_encoded, &de->file);
|
|
|
- mg_free(href_encoded);
|
|
|
- }
|
|
|
-
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
@@ -12014,7 +12046,7 @@ handle_propfind(struct mg_connection *conn,
|
|
|
"<d:multistatus xmlns:d='DAV:'>\n");
|
|
|
|
|
|
/* Print properties for the requested resource itself */
|
|
|
- print_props(conn, conn->request_info.local_uri, filep);
|
|
|
+ print_props(conn, conn->request_info.local_uri, "", filep);
|
|
|
|
|
|
/* If it is a directory, print directory entries too if Depth is not 0
|
|
|
*/
|
|
@@ -12668,7 +12700,7 @@ handle_websocket_request(struct mg_connection *conn,
|
|
|
curSubProtocol = protocol;
|
|
|
len = sep ? (unsigned long)(sep - protocol)
|
|
|
: (unsigned long)strlen(protocol);
|
|
|
- while (sep && isspace(*++sep))
|
|
|
+ while (sep && isspace((unsigned char)*++sep))
|
|
|
; // ignore leading whitespaces
|
|
|
protocol = sep;
|
|
|
|
|
@@ -12711,7 +12743,7 @@ handle_websocket_request(struct mg_connection *conn,
|
|
|
* has
|
|
|
* offered.
|
|
|
*/
|
|
|
- while (isspace(*++sep)) {
|
|
|
+ while (isspace((unsigned char)*++sep)) {
|
|
|
; /* ignore leading whitespaces */
|
|
|
}
|
|
|
conn->request_info.acceptedWebSocketSubprotocol = sep;
|
|
@@ -13045,7 +13077,7 @@ alloc_get_host(struct mg_connection *conn)
|
|
|
mg_strlcpy(buf, host_header, buflen);
|
|
|
buf[buflen - 1] = '\0';
|
|
|
host = buf;
|
|
|
- while (isspace(*host)) {
|
|
|
+ while (isspace((unsigned char)*host)) {
|
|
|
host++;
|
|
|
}
|
|
|
|
|
@@ -15107,7 +15139,7 @@ sslize(struct mg_connection *conn,
|
|
|
/* SSL functions may fail and require to be called again:
|
|
|
* see https://www.openssl.org/docs/manmaster/ssl/SSL_get_error.html
|
|
|
* Here "func" could be SSL_connect or SSL_accept. */
|
|
|
- for (i = 16; i <= timeout; i *= 2) {
|
|
|
+ for (i = 0; i <= timeout; i += 50) {
|
|
|
ret = func(conn->ssl);
|
|
|
if (ret != 1) {
|
|
|
err = SSL_get_error(conn->ssl, ret);
|
|
@@ -15115,14 +15147,24 @@ sslize(struct mg_connection *conn,
|
|
|
|| (err == SSL_ERROR_WANT_ACCEPT)
|
|
|
|| (err == SSL_ERROR_WANT_READ) || (err == SSL_ERROR_WANT_WRITE)
|
|
|
|| (err == SSL_ERROR_WANT_X509_LOOKUP)) {
|
|
|
- /* Need to retry the function call "later".
|
|
|
- * See https://linux.die.net/man/3/ssl_get_error
|
|
|
- * This is typical for non-blocking sockets. */
|
|
|
if (*stop_server) {
|
|
|
/* Don't wait if the server is going to be stopped. */
|
|
|
break;
|
|
|
}
|
|
|
- mg_sleep(i);
|
|
|
+ if (err == SSL_ERROR_WANT_X509_LOOKUP) {
|
|
|
+ /* Simply retry the function call. */
|
|
|
+ mg_sleep(50);
|
|
|
+ } else {
|
|
|
+ /* Need to retry the function call "later".
|
|
|
+ * See https://linux.die.net/man/3/ssl_get_error
|
|
|
+ * This is typical for non-blocking sockets. */
|
|
|
+ struct mg_pollfd pfd;
|
|
|
+ pfd.fd = conn->client.sock;
|
|
|
+ pfd.events = ((err == SSL_ERROR_WANT_CONNECT)
|
|
|
+ || (err == SSL_ERROR_WANT_WRITE)) ? POLLOUT
|
|
|
+ : POLLIN;
|
|
|
+ mg_poll(&pfd, 1, 50, stop_server);
|
|
|
+ }
|
|
|
|
|
|
} else if (err == SSL_ERROR_SYSCALL) {
|
|
|
/* This is an IO error. Look at errno. */
|
|
@@ -17775,17 +17817,11 @@ produce_socket(struct mg_context *ctx, const struct socket *sp)
|
|
|
#endif /* ALTERNATIVE_QUEUE */
|
|
|
|
|
|
|
|
|
-struct worker_thread_args {
|
|
|
- struct mg_context *ctx;
|
|
|
- int index;
|
|
|
-};
|
|
|
-
|
|
|
-
|
|
|
-static void *
|
|
|
-worker_thread_run(struct worker_thread_args *thread_args)
|
|
|
+static void
|
|
|
+worker_thread_run(struct mg_connection *conn)
|
|
|
{
|
|
|
- struct mg_context *ctx = thread_args->ctx;
|
|
|
- struct mg_connection *conn;
|
|
|
+ struct mg_context *ctx = conn->phys_ctx;
|
|
|
+ int thread_index;
|
|
|
struct mg_workerTLS tls;
|
|
|
#if defined(MG_LEGACY_INTERFACE)
|
|
|
uint32_t addr;
|
|
@@ -17808,15 +17844,15 @@ worker_thread_run(struct worker_thread_args *thread_args)
|
|
|
}
|
|
|
|
|
|
/* Connection structure has been pre-allocated */
|
|
|
- if (((int)thread_args->index < 0)
|
|
|
- || ((unsigned)thread_args->index
|
|
|
+ thread_index = (int)(conn - ctx->worker_connections);
|
|
|
+ if ((thread_index < 0)
|
|
|
+ || ((unsigned)thread_index
|
|
|
>= (unsigned)ctx->cfg_worker_threads)) {
|
|
|
mg_cry_internal(fc(ctx),
|
|
|
"Internal error: Invalid worker index %i",
|
|
|
- (int)thread_args->index);
|
|
|
- return NULL;
|
|
|
+ thread_index);
|
|
|
+ return;
|
|
|
}
|
|
|
- conn = ctx->worker_connections + thread_args->index;
|
|
|
|
|
|
/* Request buffers are not pre-allocated. They are private to the
|
|
|
* request and do not contain any state information that might be
|
|
@@ -17825,16 +17861,14 @@ worker_thread_run(struct worker_thread_args *thread_args)
|
|
|
if (conn->buf == NULL) {
|
|
|
mg_cry_internal(fc(ctx),
|
|
|
"Out of memory: Cannot allocate buffer for worker %i",
|
|
|
- (int)thread_args->index);
|
|
|
- return NULL;
|
|
|
+ thread_index);
|
|
|
+ return;
|
|
|
}
|
|
|
conn->buf_size = (int)ctx->max_request_size;
|
|
|
|
|
|
- conn->phys_ctx = ctx;
|
|
|
conn->dom_ctx = &(ctx->dd); /* Use default domain and default host */
|
|
|
conn->host = NULL; /* until we have more information. */
|
|
|
|
|
|
- conn->thread_index = thread_args->index;
|
|
|
conn->request_info.user_data = ctx->user_data;
|
|
|
/* Allocate a mutex for this connection to allow communication both
|
|
|
* within the request handler and from elsewhere in the application
|
|
@@ -17842,7 +17876,7 @@ worker_thread_run(struct worker_thread_args *thread_args)
|
|
|
if (0 != pthread_mutex_init(&conn->mutex, &pthread_mutex_attr)) {
|
|
|
mg_free(conn->buf);
|
|
|
mg_cry_internal(fc(ctx), "%s", "Cannot create mutex");
|
|
|
- return NULL;
|
|
|
+ return;
|
|
|
}
|
|
|
|
|
|
#if defined(USE_SERVER_STATS)
|
|
@@ -17852,7 +17886,7 @@ worker_thread_run(struct worker_thread_args *thread_args)
|
|
|
/* Call consume_socket() even when ctx->stop_flag > 0, to let it
|
|
|
* signal sq_empty condvar to wake up the master waiting in
|
|
|
* produce_socket() */
|
|
|
- while (consume_socket(ctx, &conn->client, conn->thread_index)) {
|
|
|
+ while (consume_socket(ctx, &conn->client, thread_index)) {
|
|
|
|
|
|
conn->conn_birth_time = time(NULL);
|
|
|
|
|
@@ -17943,7 +17977,6 @@ worker_thread_run(struct worker_thread_args *thread_args)
|
|
|
#endif
|
|
|
|
|
|
DEBUG_TRACE("%s", "exiting");
|
|
|
- return NULL;
|
|
|
}
|
|
|
|
|
|
|
|
@@ -17951,18 +17984,13 @@ worker_thread_run(struct worker_thread_args *thread_args)
|
|
|
#if defined(_WIN32)
|
|
|
static unsigned __stdcall worker_thread(void *thread_func_param)
|
|
|
{
|
|
|
- struct worker_thread_args *pwta =
|
|
|
- (struct worker_thread_args *)thread_func_param;
|
|
|
- worker_thread_run(pwta);
|
|
|
- mg_free(thread_func_param);
|
|
|
+ worker_thread_run((struct mg_connection *)thread_func_param);
|
|
|
return 0;
|
|
|
}
|
|
|
#else
|
|
|
static void *
|
|
|
worker_thread(void *thread_func_param)
|
|
|
{
|
|
|
- struct worker_thread_args *pwta =
|
|
|
- (struct worker_thread_args *)thread_func_param;
|
|
|
struct sigaction sa;
|
|
|
|
|
|
/* Ignore SIGPIPE */
|
|
@@ -17970,8 +17998,7 @@ worker_thread(void *thread_func_param)
|
|
|
sa.sa_handler = SIG_IGN;
|
|
|
sigaction(SIGPIPE, &sa, NULL);
|
|
|
|
|
|
- worker_thread_run(pwta);
|
|
|
- mg_free(thread_func_param);
|
|
|
+ worker_thread_run((struct mg_connection *)thread_func_param);
|
|
|
return NULL;
|
|
|
}
|
|
|
#endif /* _WIN32 */
|
|
@@ -18063,9 +18090,8 @@ accept_new_connection(const struct socket *listener, struct mg_context *ctx)
|
|
|
|
|
|
|
|
|
static void
|
|
|
-master_thread_run(void *thread_func_param)
|
|
|
+master_thread_run(struct mg_context *ctx)
|
|
|
{
|
|
|
- struct mg_context *ctx = (struct mg_context *)thread_func_param;
|
|
|
struct mg_workerTLS tls;
|
|
|
struct mg_pollfd *pfd;
|
|
|
unsigned int i;
|
|
@@ -18187,7 +18213,7 @@ master_thread_run(void *thread_func_param)
|
|
|
#if defined(_WIN32)
|
|
|
static unsigned __stdcall master_thread(void *thread_func_param)
|
|
|
{
|
|
|
- master_thread_run(thread_func_param);
|
|
|
+ master_thread_run((struct mg_context *)thread_func_param);
|
|
|
return 0;
|
|
|
}
|
|
|
#else
|
|
@@ -18201,7 +18227,7 @@ master_thread(void *thread_func_param)
|
|
|
sa.sa_handler = SIG_IGN;
|
|
|
sigaction(SIGPIPE, &sa, NULL);
|
|
|
|
|
|
- master_thread_run(thread_func_param);
|
|
|
+ master_thread_run((struct mg_context *)thread_func_param);
|
|
|
return NULL;
|
|
|
}
|
|
|
#endif /* _WIN32 */
|
|
@@ -18695,24 +18721,13 @@ mg_start(const struct mg_callbacks *callbacks,
|
|
|
|
|
|
/* Start worker threads */
|
|
|
for (i = 0; i < ctx->cfg_worker_threads; i++) {
|
|
|
- struct worker_thread_args *wta = (struct worker_thread_args *)
|
|
|
- mg_malloc_ctx(sizeof(struct worker_thread_args), ctx);
|
|
|
- if (wta) {
|
|
|
- wta->ctx = ctx;
|
|
|
- wta->index = (int)i;
|
|
|
- }
|
|
|
-
|
|
|
- if ((wta == NULL)
|
|
|
- || (mg_start_thread_with_id(worker_thread,
|
|
|
- wta,
|
|
|
- &ctx->worker_threadids[i])
|
|
|
- != 0)) {
|
|
|
+ /* worker_thread sets up the other fields */
|
|
|
+ ctx->worker_connections[i].phys_ctx = ctx;
|
|
|
+ if (mg_start_thread_with_id(worker_thread,
|
|
|
+ &ctx->worker_connections[i],
|
|
|
+ &ctx->worker_threadids[i]) != 0) {
|
|
|
|
|
|
/* thread was not created */
|
|
|
- if (wta != NULL) {
|
|
|
- mg_free(wta);
|
|
|
- }
|
|
|
-
|
|
|
if (i > 0) {
|
|
|
mg_cry_internal(fc(ctx),
|
|
|
"Cannot start worker thread %i: error %ld",
|