Commit 98214ce1 authored by Sergey Lyubka's avatar Sergey Lyubka

Removed init_lua() and open_file() callbacks

parent 7eed7eab
...@@ -361,32 +361,29 @@ static int handle_lsp_request(struct mg_connection *conn, const char *path, ...@@ -361,32 +361,29 @@ static int handle_lsp_request(struct mg_connection *conn, const char *path,
struct file *filep, struct lua_State *ls) { struct file *filep, struct lua_State *ls) {
void *p = NULL; void *p = NULL;
lua_State *L = NULL; lua_State *L = NULL;
FILE *fp = NULL;
int error = 1; int error = 1;
// We need both mg_stat to get file size, and mg_fopen to get fd // We need both mg_stat to get file size, and mg_fopen to get fd
if (!mg_stat(conn, path, filep) || !mg_fopen(conn, path, "r", filep)) { if (!mg_stat(path, filep) || (fp = mg_fopen(path, "r")) == NULL) {
lsp_send_err(conn, ls, "File [%s] not found", path); lsp_send_err(conn, ls, "File [%s] not found", path);
} else if (filep->membuf == NULL && } else if ((p = mmap(NULL, (size_t) filep->size, PROT_READ, MAP_PRIVATE,
(p = mmap(NULL, (size_t) filep->size, PROT_READ, MAP_PRIVATE, fileno(fp), 0)) == MAP_FAILED) {
fileno(filep->fp), 0)) == MAP_FAILED) {
lsp_send_err(conn, ls, "mmap(%s, %zu, %d): %s", path, (size_t) filep->size, lsp_send_err(conn, ls, "mmap(%s, %zu, %d): %s", path, (size_t) filep->size,
fileno(filep->fp), strerror(errno)); fileno(fp), strerror(errno));
} else if ((L = ls != NULL ? ls : luaL_newstate()) == NULL) { } else if ((L = ls != NULL ? ls : luaL_newstate()) == NULL) {
send_http_error(conn, 500, http_500_error, "%s", "luaL_newstate failed"); send_http_error(conn, 500, http_500_error, "%s", "luaL_newstate failed");
} else { } else {
// We're not sending HTTP headers here, Lua page must do it. // We're not sending HTTP headers here, Lua page must do it.
if (ls == NULL) { if (ls == NULL) {
prepare_lua_environment(conn, L); prepare_lua_environment(conn, L);
if (conn->ctx->callbacks.init_lua != NULL) {
conn->ctx->callbacks.init_lua(conn, L);
}
} }
error = lsp(conn, path, filep->membuf == NULL ? p : filep->membuf, error = lsp(conn, path, p, filep->size, L);
filep->size, L);
} }
if (L != NULL && ls == NULL) lua_close(L); if (L != NULL && ls == NULL) lua_close(L);
if (p != NULL) munmap(p, filep->size); if (p != NULL) munmap(p, filep->size);
mg_fclose(filep); fclose(fp);
return error; return error;
} }
...@@ -165,8 +165,6 @@ typedef DWORD pthread_t; ...@@ -165,8 +165,6 @@ typedef DWORD pthread_t;
static int pthread_mutex_lock(pthread_mutex_t *); static int pthread_mutex_lock(pthread_mutex_t *);
static int pthread_mutex_unlock(pthread_mutex_t *); static int pthread_mutex_unlock(pthread_mutex_t *);
static void to_unicode(const char *path, wchar_t *wbuf, size_t wbuf_len); static void to_unicode(const char *path, wchar_t *wbuf, size_t wbuf_len);
struct file;
static char *mg_fgets(char *buf, size_t size, struct file *filep, char **p);
#if defined(HAVE_STDINT) #if defined(HAVE_STDINT)
#include <stdint.h> #include <stdint.h>
...@@ -432,13 +430,11 @@ struct file { ...@@ -432,13 +430,11 @@ struct file {
int is_directory; int is_directory;
time_t modification_time; time_t modification_time;
int64_t size; int64_t size;
FILE *fp;
const char *membuf; // Non-NULL if file data is in memory
// set to 1 if the content is gzipped // set to 1 if the content is gzipped
// in which case we need a content-encoding: gzip header // in which case we need a content-encoding: gzip header
int gzipped; int gzipped;
}; };
#define STRUCT_FILE_INITIALIZER {0, 0, 0, NULL, NULL, 0} #define STRUCT_FILE_INITIALIZER { 0, 0, 0, 0 }
// Describes listening socket, or socket which was accept()-ed by the master // Describes listening socket, or socket which was accept()-ed by the master
// thread and queued for future handling by the worker thread. // thread and queued for future handling by the worker thread.
...@@ -544,42 +540,15 @@ const char **mg_get_valid_option_names(void) { ...@@ -544,42 +540,15 @@ const char **mg_get_valid_option_names(void) {
return config_options; return config_options;
} }
static int is_file_in_memory(struct mg_connection *conn, const char *path, static FILE *mg_fopen(const char *path, const char *mode) {
struct file *filep) {
size_t size = 0;
if ((filep->membuf = conn->ctx->callbacks.open_file == NULL ? NULL :
conn->ctx->callbacks.open_file(conn, path, &size)) != NULL) {
// NOTE: override filep->size only on success. Otherwise, it might break
// constructs like if (!mg_stat() || !mg_fopen()) ...
filep->size = size;
}
return filep->membuf != NULL;
}
static int is_file_opened(const struct file *filep) {
return filep->membuf != NULL || filep->fp != NULL;
}
static int mg_fopen(struct mg_connection *conn, const char *path,
const char *mode, struct file *filep) {
if (!is_file_in_memory(conn, path, filep)) {
#ifdef _WIN32 #ifdef _WIN32
wchar_t wbuf[PATH_MAX], wmode[20]; wchar_t wbuf[PATH_MAX], wmode[20];
to_unicode(path, wbuf, ARRAY_SIZE(wbuf)); to_unicode(path, wbuf, ARRAY_SIZE(wbuf));
MultiByteToWideChar(CP_UTF8, 0, mode, -1, wmode, ARRAY_SIZE(wmode)); MultiByteToWideChar(CP_UTF8, 0, mode, -1, wmode, ARRAY_SIZE(wmode));
filep->fp = _wfopen(wbuf, wmode); return _wfopen(wbuf, wmode);
#else #else
filep->fp = fopen(path, mode); return fopen(path, mode);
#endif #endif
}
return is_file_opened(filep);
}
static void mg_fclose(struct file *filep) {
if (filep != NULL && filep->fp != NULL) {
fclose(filep->fp);
}
} }
static int get_option_index(const char *name) { static int get_option_index(const char *name) {
...@@ -1127,29 +1096,27 @@ static int path_cannot_disclose_cgi(const char *path) { ...@@ -1127,29 +1096,27 @@ static int path_cannot_disclose_cgi(const char *path) {
return isalnum(last) || strchr(allowed_last_characters, last) != NULL; return isalnum(last) || strchr(allowed_last_characters, last) != NULL;
} }
static int mg_stat(struct mg_connection *conn, const char *path, static int mg_stat(const char *path, struct file *filep) {
struct file *filep) {
wchar_t wbuf[PATH_MAX] = L"\\\\?\\"; wchar_t wbuf[PATH_MAX] = L"\\\\?\\";
WIN32_FILE_ATTRIBUTE_DATA info; WIN32_FILE_ATTRIBUTE_DATA info;
if (!is_file_in_memory(conn, path, filep)) { filep->modification_time = 0;
to_unicode(path, wbuf + 4, ARRAY_SIZE(wbuf) - 4); to_unicode(path, wbuf + 4, ARRAY_SIZE(wbuf) - 4);
if (GetFileAttributesExW(wbuf, GetFileExInfoStandard, &info) != 0) { if (GetFileAttributesExW(wbuf, GetFileExInfoStandard, &info) != 0) {
filep->size = MAKEUQUAD(info.nFileSizeLow, info.nFileSizeHigh); filep->size = MAKEUQUAD(info.nFileSizeLow, info.nFileSizeHigh);
filep->modification_time = SYS2UNIX_TIME( filep->modification_time = SYS2UNIX_TIME(
info.ftLastWriteTime.dwLowDateTime, info.ftLastWriteTime.dwLowDateTime,
info.ftLastWriteTime.dwHighDateTime); info.ftLastWriteTime.dwHighDateTime);
filep->is_directory = info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY; filep->is_directory = info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY;
// If file name is fishy, reset the file structure and return error. // If file name is fishy, reset the file structure and return error.
// Note it is important to reset, not just return the error, cause // Note it is important to reset, not just return the error, cause
// functions like is_file_opened() check the struct. // functions like is_file_opened() check the struct.
if (!filep->is_directory && !path_cannot_disclose_cgi(path)) { if (!filep->is_directory && !path_cannot_disclose_cgi(path)) {
memset(filep, 0, sizeof(*filep)); memset(filep, 0, sizeof(*filep));
}
} }
} }
return filep->membuf != NULL || filep->modification_time != 0; return filep->modification_time != 0;
} }
static int mg_remove(const char *path) { static int mg_remove(const char *path) {
...@@ -1305,9 +1272,9 @@ static pid_t spawn_process(struct mg_connection *conn, const char *prog, ...@@ -1305,9 +1272,9 @@ static pid_t spawn_process(struct mg_connection *conn, const char *prog,
char *envblk, char *envp[], int fdin, char *envblk, char *envp[], int fdin,
int fdout, const char *dir) { int fdout, const char *dir) {
HANDLE me; HANDLE me;
char *p, *interp, full_interp[PATH_MAX], full_dir[PATH_MAX], char *interp, full_interp[PATH_MAX], full_dir[PATH_MAX],
cmdline[PATH_MAX], buf[PATH_MAX]; cmdline[PATH_MAX], buf[PATH_MAX];
struct file file = STRUCT_FILE_INITIALIZER; FILE *fp;
STARTUPINFOA si; STARTUPINFOA si;
PROCESS_INFORMATION pi = { 0 }; PROCESS_INFORMATION pi = { 0 };
...@@ -1333,10 +1300,9 @@ static pid_t spawn_process(struct mg_connection *conn, const char *prog, ...@@ -1333,10 +1300,9 @@ static pid_t spawn_process(struct mg_connection *conn, const char *prog,
// Read the first line of the script into the buffer // Read the first line of the script into the buffer
snprintf(cmdline, sizeof(cmdline), "%s%c%s", dir, '/', prog); snprintf(cmdline, sizeof(cmdline), "%s%c%s", dir, '/', prog);
if (mg_fopen(conn, cmdline, "r", &file)) { if ((fp = mg_fopen(cmdline, "r")) != NULL) {
p = (char *) file.membuf; fgets(buf, sizeof(buf), fp);
mg_fgets(buf, sizeof(buf), &file, &p); fclose(fp);
mg_fclose(&file);
buf[sizeof(buf) - 1] = '\0'; buf[sizeof(buf) - 1] = '\0';
} }
...@@ -1379,11 +1345,11 @@ static int set_non_blocking_mode(SOCKET sock) { ...@@ -1379,11 +1345,11 @@ static int set_non_blocking_mode(SOCKET sock) {
} }
#else #else
static int mg_stat(struct mg_connection *conn, const char *path, static int mg_stat(const char *path, struct file *filep) {
struct file *filep) {
struct stat st; struct stat st;
if (!is_file_in_memory(conn, path, filep) && !stat(path, &st)) { filep->modification_time = (time_t) 0;
if (stat(path, &st) == 0) {
filep->size = st.st_size; filep->size = st.st_size;
filep->modification_time = st.st_mtime; filep->modification_time = st.st_mtime;
filep->is_directory = S_ISDIR(st.st_mode); filep->is_directory = S_ISDIR(st.st_mode);
...@@ -1394,11 +1360,9 @@ static int mg_stat(struct mg_connection *conn, const char *path, ...@@ -1394,11 +1360,9 @@ static int mg_stat(struct mg_connection *conn, const char *path,
if (filep->modification_time == (time_t) 0) { if (filep->modification_time == (time_t) 0) {
filep->modification_time = (time_t) 1; filep->modification_time = (time_t) 1;
} }
} else {
filep->modification_time = (time_t) 0;
} }
return filep->membuf != NULL || filep->modification_time != (time_t) 0; return filep->modification_time != (time_t) 0;
} }
static void set_close_on_exec(int fd) { static void set_close_on_exec(int fd) {
...@@ -1842,7 +1806,9 @@ static int convert_uri_to_file_name(struct mg_connection *conn, char *buf, ...@@ -1842,7 +1806,9 @@ static int convert_uri_to_file_name(struct mg_connection *conn, char *buf,
} }
} }
if (mg_stat(conn, buf, filep)) return 1; if (mg_stat(buf, filep)) {
return 1;
}
// if we can't find the actual file, look for the file // if we can't find the actual file, look for the file
// with the same name but a .gz extension. If we find it, // with the same name but a .gz extension. If we find it,
...@@ -1853,7 +1819,7 @@ static int convert_uri_to_file_name(struct mg_connection *conn, char *buf, ...@@ -1853,7 +1819,7 @@ static int convert_uri_to_file_name(struct mg_connection *conn, char *buf,
if ((accept_encoding = mg_get_header(conn, "Accept-Encoding")) != NULL) { if ((accept_encoding = mg_get_header(conn, "Accept-Encoding")) != NULL) {
if (strstr(accept_encoding,"gzip") != NULL) { if (strstr(accept_encoding,"gzip") != NULL) {
snprintf(gz_path, sizeof(gz_path), "%s.gz", buf); snprintf(gz_path, sizeof(gz_path), "%s.gz", buf);
if (mg_stat(conn, gz_path, filep)) { if (mg_stat(gz_path, filep)) {
filep->gzipped = 1; filep->gzipped = 1;
return 1; return 1;
} }
...@@ -1866,7 +1832,7 @@ static int convert_uri_to_file_name(struct mg_connection *conn, char *buf, ...@@ -1866,7 +1832,7 @@ static int convert_uri_to_file_name(struct mg_connection *conn, char *buf,
*p = '\0'; *p = '\0';
if (match_prefix(conn->ctx->config[CGI_EXTENSIONS], if (match_prefix(conn->ctx->config[CGI_EXTENSIONS],
strlen(conn->ctx->config[CGI_EXTENSIONS]), buf) > 0 && strlen(conn->ctx->config[CGI_EXTENSIONS]), buf) > 0 &&
mg_stat(conn, buf, filep)) { mg_stat(buf, filep)) {
// Shift PATH_INFO block one character right, e.g. // Shift PATH_INFO block one character right, e.g.
// "/x.cgi/foo/bar\x00" => "/x.cgi\x00/foo/bar\x00" // "/x.cgi/foo/bar\x00" => "/x.cgi\x00/foo/bar\x00"
// conn->path_info is pointing to the local variable "path" declared // conn->path_info is pointing to the local variable "path" declared
...@@ -2331,23 +2297,23 @@ static int check_password(const char *method, const char *ha1, const char *uri, ...@@ -2331,23 +2297,23 @@ static int check_password(const char *method, const char *ha1, const char *uri,
// Use the global passwords file, if specified by auth_gpass option, // Use the global passwords file, if specified by auth_gpass option,
// or search for .htpasswd in the requested directory. // or search for .htpasswd in the requested directory.
static void open_auth_file(struct mg_connection *conn, const char *path, static FILE *open_auth_file(struct mg_connection *conn, const char *path) {
struct file *filep) {
char name[PATH_MAX]; char name[PATH_MAX];
const char *p, *e, *gpass = conn->ctx->config[GLOBAL_PASSWORDS_FILE]; const char *p, *e, *gpass = conn->ctx->config[GLOBAL_PASSWORDS_FILE];
struct file file = STRUCT_FILE_INITIALIZER; struct file file = STRUCT_FILE_INITIALIZER;
FILE *fp = NULL;
if (gpass != NULL) { if (gpass != NULL) {
// Use global passwords file // Use global passwords file
if (!mg_fopen(conn, gpass, "r", filep)) { if ((fp = mg_fopen(gpass, "r")) == NULL) {
cry(conn, "fopen(%s): %s", gpass, strerror(ERRNO)); cry(conn, "fopen(%s): %s", gpass, strerror(ERRNO));
} }
// Important: using local struct file to test path for is_directory flag. // Important: using local struct file to test path for is_directory flag.
// If filep is used, mg_stat() makes it appear as if auth file was opened. // If filep is used, mg_stat() makes it appear as if auth file was opened.
} else if (mg_stat(conn, path, &file) && file.is_directory) { } else if (mg_stat(path, &file) && file.is_directory) {
mg_snprintf(conn, name, sizeof(name), "%s%c%s", mg_snprintf(conn, name, sizeof(name), "%s%c%s",
path, '/', PASSWORDS_FILE_NAME); path, '/', PASSWORDS_FILE_NAME);
mg_fopen(conn, name, "r", filep); fp = mg_fopen(name, "r");
} else { } else {
// Try to find .htpasswd in requested directory. // Try to find .htpasswd in requested directory.
for (p = path, e = p + strlen(p) - 1; e > p; e--) for (p = path, e = p + strlen(p) - 1; e > p; e--)
...@@ -2355,8 +2321,10 @@ static void open_auth_file(struct mg_connection *conn, const char *path, ...@@ -2355,8 +2321,10 @@ static void open_auth_file(struct mg_connection *conn, const char *path,
break; break;
mg_snprintf(conn, name, sizeof(name), "%.*s%c%s", mg_snprintf(conn, name, sizeof(name), "%.*s%c%s",
(int) (e - p), p, '/', PASSWORDS_FILE_NAME); (int) (e - p), p, '/', PASSWORDS_FILE_NAME);
mg_fopen(conn, name, "r", filep); fp = mg_fopen(name, "r");
} }
return fp;
} }
// Parsed Authorization header // Parsed Authorization header
...@@ -2428,44 +2396,17 @@ static int parse_auth_header(struct mg_connection *conn, char *buf, ...@@ -2428,44 +2396,17 @@ static int parse_auth_header(struct mg_connection *conn, char *buf,
return 1; return 1;
} }
static char *mg_fgets(char *buf, size_t size, struct file *filep, char **p) {
char *eof;
size_t len;
char *memend;
if (filep->membuf != NULL && *p != NULL) {
memend = (char *) &filep->membuf[filep->size];
// Search for \n from p till the end of stream
eof = (char *) memchr(*p, '\n', memend - *p);
if (eof != NULL) {
eof += 1; // Include \n
} else {
eof = memend; // Copy remaining data
}
len = (size_t) (eof - *p) > size - 1 ? size - 1 : (size_t) (eof - *p);
memcpy(buf, *p, len);
buf[len] = '\0';
*p += len;
return len ? eof : NULL;
} else if (filep->fp != NULL) {
return fgets(buf, size, filep->fp);
} else {
return NULL;
}
}
// Authorize against the opened passwords file. Return 1 if authorized. // Authorize against the opened passwords file. Return 1 if authorized.
static int authorize(struct mg_connection *conn, struct file *filep) { static int authorize(struct mg_connection *conn, FILE *fp) {
struct ah ah; struct ah ah;
char line[256], f_user[256], ha1[256], f_domain[256], buf[MG_BUF_LEN], *p; char line[256], f_user[256], ha1[256], f_domain[256], buf[MG_BUF_LEN];
if (!parse_auth_header(conn, buf, sizeof(buf), &ah)) { if (!parse_auth_header(conn, buf, sizeof(buf), &ah)) {
return 0; return 0;
} }
// Loop over passwords file // Loop over passwords file
p = (char *) filep->membuf; while (fgets(line, sizeof(line), fp) != NULL) {
while (mg_fgets(line, sizeof(line), filep, &p) != NULL) {
if (sscanf(line, "%[^:]:%[^:]:%s", f_user, f_domain, ha1) != 3) { if (sscanf(line, "%[^:]:%[^:]:%s", f_user, f_domain, ha1) != 3) {
continue; continue;
} }
...@@ -2484,7 +2425,7 @@ static int check_authorization(struct mg_connection *conn, const char *path) { ...@@ -2484,7 +2425,7 @@ static int check_authorization(struct mg_connection *conn, const char *path) {
char fname[PATH_MAX]; char fname[PATH_MAX];
struct vec uri_vec, filename_vec; struct vec uri_vec, filename_vec;
const char *list; const char *list;
struct file file = STRUCT_FILE_INITIALIZER; FILE *fp = NULL;
int authorized = 1; int authorized = 1;
list = conn->ctx->config[PROTECT_URI]; list = conn->ctx->config[PROTECT_URI];
...@@ -2492,20 +2433,20 @@ static int check_authorization(struct mg_connection *conn, const char *path) { ...@@ -2492,20 +2433,20 @@ static int check_authorization(struct mg_connection *conn, const char *path) {
if (!memcmp(conn->request_info.uri, uri_vec.ptr, uri_vec.len)) { if (!memcmp(conn->request_info.uri, uri_vec.ptr, uri_vec.len)) {
mg_snprintf(conn, fname, sizeof(fname), "%.*s", mg_snprintf(conn, fname, sizeof(fname), "%.*s",
(int) filename_vec.len, filename_vec.ptr); (int) filename_vec.len, filename_vec.ptr);
if (!mg_fopen(conn, fname, "r", &file)) { if ((fp = mg_fopen(fname, "r")) == NULL) {
cry(conn, "%s: cannot open %s: %s", __func__, fname, strerror(errno)); cry(conn, "%s: cannot open %s: %s", __func__, fname, strerror(errno));
} }
break; break;
} }
} }
if (!is_file_opened(&file)) { if (fp == NULL) {
open_auth_file(conn, path, &file); fp = open_auth_file(conn, path);
} }
if (is_file_opened(&file)) { if (fp != NULL) {
authorized = authorize(conn, &file); authorized = authorize(conn, fp);
mg_fclose(&file); fclose(fp);
} }
return authorized; return authorized;
...@@ -2523,13 +2464,13 @@ static void send_authorization_request(struct mg_connection *conn) { ...@@ -2523,13 +2464,13 @@ static void send_authorization_request(struct mg_connection *conn) {
} }
static int is_authorized_for_put(struct mg_connection *conn) { static int is_authorized_for_put(struct mg_connection *conn) {
struct file file = STRUCT_FILE_INITIALIZER;
const char *passfile = conn->ctx->config[PUT_DELETE_PASSWORDS_FILE]; const char *passfile = conn->ctx->config[PUT_DELETE_PASSWORDS_FILE];
FILE *fp;
int ret = 0; int ret = 0;
if (passfile != NULL && mg_fopen(conn, passfile, "r", &file)) { if (passfile != NULL && (fp = mg_fopen(passfile, "r")) != NULL) {
ret = authorize(conn, &file); ret = authorize(conn, fp);
mg_fclose(&file); fclose(fp);
} }
return ret; return ret;
...@@ -2553,7 +2494,7 @@ int mg_modify_passwords_file(const char *fname, const char *domain, ...@@ -2553,7 +2494,7 @@ int mg_modify_passwords_file(const char *fname, const char *domain,
// Create the file if does not exist // Create the file if does not exist
if ((fp = fopen(fname, "a+")) != NULL) { if ((fp = fopen(fname, "a+")) != NULL) {
(void) fclose(fp); fclose(fp);
} }
// Open the given file and temporary file // Open the given file and temporary file
...@@ -2746,7 +2687,7 @@ static int scan_directory(struct mg_connection *conn, const char *dir, ...@@ -2746,7 +2687,7 @@ static int scan_directory(struct mg_connection *conn, const char *dir,
// fails. For more details, see // fails. For more details, see
// http://code.google.com/p/mongoose/issues/detail?id=79 // http://code.google.com/p/mongoose/issues/detail?id=79
memset(&de.file, 0, sizeof(de.file)); memset(&de.file, 0, sizeof(de.file));
mg_stat(conn, path, &de.file); mg_stat(path, &de.file);
de.file_name = dp->d_name; de.file_name = dp->d_name;
cb(&de, data); cb(&de, data);
...@@ -2782,7 +2723,7 @@ static int remove_directory(struct mg_connection *conn, const char *dir) { ...@@ -2782,7 +2723,7 @@ static int remove_directory(struct mg_connection *conn, const char *dir) {
// fails. For more details, see // fails. For more details, see
// http://code.google.com/p/mongoose/issues/detail?id=79 // http://code.google.com/p/mongoose/issues/detail?id=79
memset(&de.file, 0, sizeof(de.file)); memset(&de.file, 0, sizeof(de.file));
mg_stat(conn, path, &de.file); mg_stat(path, &de.file);
if(de.file.modification_time) { if(de.file.modification_time) {
if(de.file.is_directory) { if(de.file.is_directory) {
remove_directory(conn, path); remove_directory(conn, path);
...@@ -2887,42 +2828,36 @@ static void handle_directory_request(struct mg_connection *conn, ...@@ -2887,42 +2828,36 @@ static void handle_directory_request(struct mg_connection *conn,
} }
// Send len bytes from the opened file to the client. // Send len bytes from the opened file to the client.
static void send_file_data(struct mg_connection *conn, struct file *filep, static void send_file_data(struct mg_connection *conn, FILE *fp,
int64_t offset, int64_t len) { int64_t offset, int64_t len) {
char buf[MG_BUF_LEN]; char buf[MG_BUF_LEN];
int to_read, num_read, num_written; int to_read, num_read, num_written;
// Sanity check the offset // If offset is beyond file boundaries, don't send anything
offset = offset < 0 ? 0 : offset > filep->size ? filep->size : offset; if (offset > 0 && fseeko(fp, offset, SEEK_SET) != 0) {
return;
}
if (len > 0 && filep->membuf != NULL && filep->size > 0) { while (len > 0) {
if (len > filep->size - offset) { // Calculate how much to read from the file in the buffer
len = filep->size - offset; to_read = sizeof(buf);
if ((int64_t) to_read > len) {
to_read = (int) len;
} }
mg_write(conn, filep->membuf + offset, (size_t) len);
} else if (len > 0 && filep->fp != NULL) {
fseeko(filep->fp, offset, SEEK_SET);
while (len > 0) {
// Calculate how much to read from the file in the buffer
to_read = sizeof(buf);
if ((int64_t) to_read > len) {
to_read = (int) len;
}
// Read from file, exit the loop on error
if ((num_read = fread(buf, 1, (size_t) to_read, filep->fp)) <= 0) {
break;
}
// Send read bytes to the client, exit the loop on error // Read from file, exit the loop on error
if ((num_written = mg_write(conn, buf, (size_t) num_read)) != num_read) { if ((num_read = fread(buf, 1, (size_t) to_read, fp)) <= 0) {
break; break;
} }
// Both read and were successful, adjust counters // Send read bytes to the client, exit the loop on error
conn->num_bytes_sent += num_written; if ((num_written = mg_write(conn, buf, (size_t) num_read)) != num_read) {
len -= num_written; break;
} }
// Both read and were successful, adjust counters
conn->num_bytes_sent += num_written;
len -= num_written;
} }
} }
...@@ -2940,10 +2875,10 @@ static void construct_etag(char *buf, size_t buf_len, ...@@ -2940,10 +2875,10 @@ static void construct_etag(char *buf, size_t buf_len,
(unsigned long) filep->modification_time, filep->size); (unsigned long) filep->modification_time, filep->size);
} }
static void fclose_on_exec(struct file *filep) { static void fclose_on_exec(FILE *fp) {
if (filep != NULL && filep->fp != NULL) { if (fp != NULL) {
#ifndef _WIN32 #ifndef _WIN32
fcntl(fileno(filep->fp), F_SETFD, FD_CLOEXEC); fcntl(fileno(fp), F_SETFD, FD_CLOEXEC);
#endif #endif
} }
} }
...@@ -2958,6 +2893,7 @@ static void handle_file_request(struct mg_connection *conn, const char *path, ...@@ -2958,6 +2893,7 @@ static void handle_file_request(struct mg_connection *conn, const char *path,
int n; int n;
char gz_path[PATH_MAX]; char gz_path[PATH_MAX];
char const* encoding = ""; char const* encoding = "";
FILE *fp;
get_mime_type(conn->ctx, path, &mime_vec); get_mime_type(conn->ctx, path, &mime_vec);
cl = filep->size; cl = filep->size;
...@@ -2973,13 +2909,13 @@ static void handle_file_request(struct mg_connection *conn, const char *path, ...@@ -2973,13 +2909,13 @@ static void handle_file_request(struct mg_connection *conn, const char *path,
encoding = "Content-Encoding: gzip\r\n"; encoding = "Content-Encoding: gzip\r\n";
} }
if (!mg_fopen(conn, path, "rb", filep)) { if ((fp = mg_fopen(path, "rb")) == NULL) {
send_http_error(conn, 500, http_500_error, send_http_error(conn, 500, http_500_error,
"fopen(%s): %s", path, strerror(ERRNO)); "fopen(%s): %s", path, strerror(ERRNO));
return; return;
} }
fclose_on_exec(filep); fclose_on_exec(fp);
// If Range: header specified, act accordingly // If Range: header specified, act accordingly
r1 = r2 = 0; r1 = r2 = 0;
...@@ -3024,14 +2960,14 @@ static void handle_file_request(struct mg_connection *conn, const char *path, ...@@ -3024,14 +2960,14 @@ static void handle_file_request(struct mg_connection *conn, const char *path,
EXTRA_HTTP_HEADERS); EXTRA_HTTP_HEADERS);
if (strcmp(conn->request_info.request_method, "HEAD") != 0) { if (strcmp(conn->request_info.request_method, "HEAD") != 0) {
send_file_data(conn, filep, r1, cl); send_file_data(conn, fp, r1, cl);
} }
mg_fclose(filep); fclose(fp);
} }
void mg_send_file(struct mg_connection *conn, const char *path) { void mg_send_file(struct mg_connection *conn, const char *path) {
struct file file = STRUCT_FILE_INITIALIZER; struct file file = STRUCT_FILE_INITIALIZER;
if (mg_stat(conn, path, &file)) { if (mg_stat(path, &file)) {
handle_file_request(conn, path, &file); handle_file_request(conn, path, &file);
} else { } else {
send_http_error(conn, 404, "Not Found", "%s", "File not found"); send_http_error(conn, 404, "Not Found", "%s", "File not found");
...@@ -3150,7 +3086,7 @@ static int substitute_index_file(struct mg_connection *conn, char *path, ...@@ -3150,7 +3086,7 @@ static int substitute_index_file(struct mg_connection *conn, char *path,
mg_strlcpy(path + n + 1, filename_vec.ptr, filename_vec.len + 1); mg_strlcpy(path + n + 1, filename_vec.ptr, filename_vec.len + 1);
// Does it exist? // Does it exist?
if (mg_stat(conn, path, &file)) { if (mg_stat(path, &file)) {
// Yes it does, break the loop // Yes it does, break the loop
*filep = file; *filep = file;
found = 1; found = 1;
...@@ -3417,7 +3353,6 @@ static void handle_cgi_request(struct mg_connection *conn, const char *prog) { ...@@ -3417,7 +3353,6 @@ static void handle_cgi_request(struct mg_connection *conn, const char *prog) {
struct mg_request_info ri; struct mg_request_info ri;
struct cgi_env_block blk; struct cgi_env_block blk;
FILE *in = NULL, *out = NULL; FILE *in = NULL, *out = NULL;
struct file fout = STRUCT_FILE_INITIALIZER;
pid_t pid = (pid_t) -1; pid_t pid = (pid_t) -1;
prepare_cgi_environment(conn, prog, &blk); prepare_cgi_environment(conn, prog, &blk);
...@@ -3470,7 +3405,6 @@ static void handle_cgi_request(struct mg_connection *conn, const char *prog) { ...@@ -3470,7 +3405,6 @@ static void handle_cgi_request(struct mg_connection *conn, const char *prog) {
setbuf(in, NULL); setbuf(in, NULL);
setbuf(out, NULL); setbuf(out, NULL);
fout.fp = out;
// Send POST data to the CGI process if needed // Send POST data to the CGI process if needed
if (!strcmp(conn->request_info.request_method, "POST") && if (!strcmp(conn->request_info.request_method, "POST") &&
...@@ -3532,7 +3466,7 @@ static void handle_cgi_request(struct mg_connection *conn, const char *prog) { ...@@ -3532,7 +3466,7 @@ static void handle_cgi_request(struct mg_connection *conn, const char *prog) {
(size_t)(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, &fout, 0, INT64_MAX); send_file_data(conn, out, 0, INT64_MAX);
done: done:
if (pid != (pid_t) -1) { if (pid != (pid_t) -1) {
...@@ -3562,7 +3496,7 @@ done: ...@@ -3562,7 +3496,7 @@ done:
// For a given PUT path, create all intermediate subdirectories // For a given PUT path, create all intermediate subdirectories
// for given path. Return 0 if the path itself is a directory, // for given path. Return 0 if the path itself is a directory,
// or -1 on error, 1 if OK. // or -1 on error, 1 if OK.
static int put_dir(struct mg_connection *conn, const char *path) { static int put_dir(const char *path) {
char buf[PATH_MAX]; char buf[PATH_MAX];
const char *s, *p; const char *s, *p;
struct file file = STRUCT_FILE_INITIALIZER; struct file file = STRUCT_FILE_INITIALIZER;
...@@ -3579,7 +3513,7 @@ static int put_dir(struct mg_connection *conn, const char *path) { ...@@ -3579,7 +3513,7 @@ static int put_dir(struct mg_connection *conn, const char *path) {
// Try to create intermediate directory // Try to create intermediate directory
DEBUG_TRACE(("mkdir(%s)", buf)); DEBUG_TRACE(("mkdir(%s)", buf));
if (!mg_stat(conn, buf, &file) && mg_mkdir(buf, 0755) != 0) { if (!mg_stat(buf, &file) && mg_mkdir(buf, 0755) != 0) {
res = -1; res = -1;
break; break;
} }
...@@ -3596,10 +3530,11 @@ static int put_dir(struct mg_connection *conn, const char *path) { ...@@ -3596,10 +3530,11 @@ static int put_dir(struct mg_connection *conn, const char *path) {
static void mkcol(struct mg_connection *conn, const char *path) { static void mkcol(struct mg_connection *conn, const char *path) {
int rc, body_len; int rc, body_len;
struct de de; struct de de;
memset(&de.file, 0, sizeof(de.file)); memset(&de.file, 0, sizeof(de.file));
mg_stat(conn, path, &de.file); mg_stat(path, &de.file);
if(de.file.modification_time) { if (de.file.modification_time) {
send_http_error(conn, 405, "Method Not Allowed", send_http_error(conn, 405, "Method Not Allowed",
"mkcol(%s): %s", path, strerror(ERRNO)); "mkcol(%s): %s", path, strerror(ERRNO));
return; return;
...@@ -3635,45 +3570,44 @@ static void mkcol(struct mg_connection *conn, const char *path) { ...@@ -3635,45 +3570,44 @@ static void mkcol(struct mg_connection *conn, const char *path) {
static void put_file(struct mg_connection *conn, const char *path) { static void put_file(struct mg_connection *conn, const char *path) {
struct file file = STRUCT_FILE_INITIALIZER; struct file file = STRUCT_FILE_INITIALIZER;
FILE *fp;
const char *range; const char *range;
int64_t r1, r2; int64_t r1, r2;
int rc; int rc;
conn->status_code = mg_stat(conn, path, &file) ? 200 : 201; conn->status_code = mg_stat(path, &file) ? 200 : 201;
if ((rc = put_dir(conn, path)) == 0) { if ((rc = put_dir(path)) == 0) {
mg_printf(conn, "HTTP/1.1 %d OK\r\n\r\n", conn->status_code); mg_printf(conn, "HTTP/1.1 %d OK\r\n\r\n", conn->status_code);
} else if (rc == -1) { } else if (rc == -1) {
send_http_error(conn, 500, http_500_error, send_http_error(conn, 500, http_500_error,
"put_dir(%s): %s", path, strerror(ERRNO)); "put_dir(%s): %s", path, strerror(ERRNO));
} else if (!mg_fopen(conn, path, "wb+", &file) || file.fp == NULL) { } else if ((fp = mg_fopen(path, "wb+")) == NULL) {
mg_fclose(&file); fclose(fp);
send_http_error(conn, 500, http_500_error, send_http_error(conn, 500, http_500_error,
"fopen(%s): %s", path, strerror(ERRNO)); "fopen(%s): %s", path, strerror(ERRNO));
} else { } else {
fclose_on_exec(&file); fclose_on_exec(fp);
range = mg_get_header(conn, "Content-Range"); range = mg_get_header(conn, "Content-Range");
r1 = r2 = 0; r1 = r2 = 0;
if (range != NULL && parse_range_header(range, &r1, &r2) > 0) { if (range != NULL && parse_range_header(range, &r1, &r2) > 0) {
conn->status_code = 206; conn->status_code = 206;
fseeko(file.fp, r1, SEEK_SET); fseeko(fp, r1, SEEK_SET);
} }
if (!forward_body_data(conn, file.fp, INVALID_SOCKET, NULL)) { if (!forward_body_data(conn, fp, INVALID_SOCKET, NULL)) {
conn->status_code = 500; conn->status_code = 500;
} }
mg_printf(conn, "HTTP/1.1 %d OK\r\nContent-Length: 0\r\n\r\n", mg_printf(conn, "HTTP/1.1 %d OK\r\nContent-Length: 0\r\n\r\n",
conn->status_code); conn->status_code);
mg_fclose(&file); fclose(fp);
} }
} }
static void send_ssi_file(struct mg_connection *, const char *, static void send_ssi_file(struct mg_connection *, const char *, FILE *, int);
struct file *, int);
static void do_ssi_include(struct mg_connection *conn, const char *ssi, static void do_ssi_include(struct mg_connection *conn, const char *ssi,
char *tag, int include_level) { char *tag, int include_level) {
char file_name[MG_BUF_LEN], path[PATH_MAX], *p; char file_name[MG_BUF_LEN], path[PATH_MAX], *p;
struct file file = STRUCT_FILE_INITIALIZER; FILE *fp;
// sscanf() is safe here, since send_ssi_file() also uses buffer // sscanf() is safe here, since send_ssi_file() also uses buffer
// of size MG_BUF_LEN to get the tag. So strlen(tag) is always < MG_BUF_LEN. // of size MG_BUF_LEN to get the tag. So strlen(tag) is always < MG_BUF_LEN.
...@@ -3699,49 +3633,39 @@ static void do_ssi_include(struct mg_connection *conn, const char *ssi, ...@@ -3699,49 +3633,39 @@ static void do_ssi_include(struct mg_connection *conn, const char *ssi,
return; return;
} }
if (!mg_fopen(conn, path, "rb", &file)) { if ((fp = mg_fopen(path, "rb")) == NULL) {
cry(conn, "Cannot open SSI #include: [%s]: fopen(%s): %s", cry(conn, "Cannot open SSI #include: [%s]: fopen(%s): %s",
tag, path, strerror(ERRNO)); tag, path, strerror(ERRNO));
} else { } else {
fclose_on_exec(&file); fclose_on_exec(fp);
if (match_prefix(conn->ctx->config[SSI_EXTENSIONS], if (match_prefix(conn->ctx->config[SSI_EXTENSIONS],
strlen(conn->ctx->config[SSI_EXTENSIONS]), path) > 0) { strlen(conn->ctx->config[SSI_EXTENSIONS]), path) > 0) {
send_ssi_file(conn, path, &file, include_level + 1); send_ssi_file(conn, path, fp, include_level + 1);
} else { } else {
send_file_data(conn, &file, 0, INT64_MAX); send_file_data(conn, fp, 0, INT64_MAX);
} }
mg_fclose(&file); fclose(fp);
} }
} }
#if !defined(NO_POPEN) #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[MG_BUF_LEN]; char cmd[MG_BUF_LEN];
struct file file = STRUCT_FILE_INITIALIZER; FILE *fp;
if (sscanf(tag, " \"%[^\"]\"", cmd) != 1) { if (sscanf(tag, " \"%[^\"]\"", cmd) != 1) {
cry(conn, "Bad SSI #exec: [%s]", tag); cry(conn, "Bad SSI #exec: [%s]", tag);
} else if ((file.fp = popen(cmd, "r")) == NULL) { } else if ((fp = popen(cmd, "r")) == NULL) {
cry(conn, "Cannot SSI #exec: [%s]: %s", cmd, strerror(ERRNO)); cry(conn, "Cannot SSI #exec: [%s]: %s", cmd, strerror(ERRNO));
} else { } else {
send_file_data(conn, &file, 0, INT64_MAX); send_file_data(conn, fp, 0, INT64_MAX);
pclose(file.fp); pclose(fp);
} }
} }
#endif // !NO_POPEN #endif // !NO_POPEN
static int mg_fgetc(struct file *filep, int offset) {
if (filep->membuf != NULL && offset >=0 && offset < filep->size) {
return ((unsigned char *) filep->membuf)[offset];
} else if (filep->fp != NULL) {
return fgetc(filep->fp);
} else {
return EOF;
}
}
static void send_ssi_file(struct mg_connection *conn, const char *path, static void send_ssi_file(struct mg_connection *conn, const char *path,
struct file *filep, int include_level) { FILE *fp, int include_level) {
char buf[MG_BUF_LEN]; char buf[MG_BUF_LEN];
int ch, offset, len, in_ssi_tag; int ch, offset, len, in_ssi_tag;
...@@ -3751,7 +3675,7 @@ static void send_ssi_file(struct mg_connection *conn, const char *path, ...@@ -3751,7 +3675,7 @@ static void send_ssi_file(struct mg_connection *conn, const char *path,
} }
in_ssi_tag = len = offset = 0; in_ssi_tag = len = offset = 0;
while ((ch = mg_fgetc(filep, offset)) != EOF) { while ((ch = fgetc(fp)) != EOF) {
if (in_ssi_tag && ch == '>') { if (in_ssi_tag && ch == '>') {
in_ssi_tag = 0; in_ssi_tag = 0;
buf[len++] = (char) ch; buf[len++] = (char) ch;
...@@ -3805,22 +3729,22 @@ static void send_ssi_file(struct mg_connection *conn, const char *path, ...@@ -3805,22 +3729,22 @@ static void send_ssi_file(struct mg_connection *conn, const char *path,
static void handle_ssi_file_request(struct mg_connection *conn, static void handle_ssi_file_request(struct mg_connection *conn,
const char *path) { const char *path) {
struct file file = STRUCT_FILE_INITIALIZER;
struct vec mime_vec; struct vec mime_vec;
FILE *fp;
if (!mg_fopen(conn, path, "rb", &file)) { if ((fp = mg_fopen(path, "rb")) == NULL) {
send_http_error(conn, 500, http_500_error, "fopen(%s): %s", path, send_http_error(conn, 500, http_500_error, "fopen(%s): %s", path,
strerror(ERRNO)); strerror(ERRNO));
} else { } else {
conn->must_close = 1; conn->must_close = 1;
fclose_on_exec(&file); fclose_on_exec(fp);
get_mime_type(conn->ctx, path, &mime_vec); get_mime_type(conn->ctx, path, &mime_vec);
mg_printf(conn, "HTTP/1.1 200 OK\r\n" mg_printf(conn, "HTTP/1.1 200 OK\r\n"
"Content-Type: %.*s\r\n" "Content-Type: %.*s\r\n"
"Connection: close\r\n\r\n", "Connection: close\r\n\r\n",
(int) mime_vec.len, mime_vec.ptr); (int) mime_vec.len, mime_vec.ptr);
send_ssi_file(conn, path, &file, 0); send_ssi_file(conn, path, fp, 0);
mg_fclose(&file); fclose(fp);
} }
} }
...@@ -4447,7 +4371,7 @@ static void handle_delete_request(struct mg_connection *conn, ...@@ -4447,7 +4371,7 @@ static void handle_delete_request(struct mg_connection *conn,
const char *path) { const char *path) {
struct file file = STRUCT_FILE_INITIALIZER; struct file file = STRUCT_FILE_INITIALIZER;
if (!mg_stat(conn, path, &file)) { if (!mg_stat(path, &file)) {
send_http_error(conn, 404, "Not Found", "%s", "File not found"); send_http_error(conn, 404, "Not Found", "%s", "File not found");
} else if (!file.modification_time) { } else if (!file.modification_time) {
send_http_error(conn, 500, http_500_error, "remove(%s): %s", path, send_http_error(conn, 500, http_500_error, "remove(%s): %s", path,
...@@ -4513,7 +4437,7 @@ static void handle_request(struct mg_connection *conn) { ...@@ -4513,7 +4437,7 @@ static void handle_request(struct mg_connection *conn) {
mkcol(conn, path); mkcol(conn, path);
} else if (!strcmp(ri->request_method, "DELETE")) { } else if (!strcmp(ri->request_method, "DELETE")) {
handle_delete_request(conn, path); handle_delete_request(conn, path);
} else if ((file.membuf == NULL && file.modification_time == (time_t) 0) || } else if (file.modification_time == (time_t) 0 ||
must_hide_file(conn, path)) { must_hide_file(conn, path)) {
send_http_error(conn, 404, "Not Found", "%s", "File not found"); send_http_error(conn, 404, "Not Found", "%s", "File not found");
} else if (file.is_directory && ri->uri[uri_len - 1] != '/') { } else if (file.is_directory && ri->uri[uri_len - 1] != '/') {
...@@ -4903,7 +4827,7 @@ static void uninitialize_ssl(struct mg_context *ctx) { ...@@ -4903,7 +4827,7 @@ static void uninitialize_ssl(struct mg_context *ctx) {
static int set_gpass_option(struct mg_context *ctx) { static int set_gpass_option(struct mg_context *ctx) {
struct file file = STRUCT_FILE_INITIALIZER; struct file file = STRUCT_FILE_INITIALIZER;
const char *path = ctx->config[GLOBAL_PASSWORDS_FILE]; const char *path = ctx->config[GLOBAL_PASSWORDS_FILE];
if (path != NULL && !mg_stat(fc(ctx), path, &file)) { if (path != NULL && !mg_stat(path, &file)) {
cry(fc(ctx), "Cannot open %s: %s", path, strerror(ERRNO)); cry(fc(ctx), "Cannot open %s: %s", path, strerror(ERRNO));
return 0; return 0;
} }
......
...@@ -59,9 +59,6 @@ struct mg_callbacks { ...@@ -59,9 +59,6 @@ struct mg_callbacks {
void (*websocket_ready)(struct mg_connection *); void (*websocket_ready)(struct mg_connection *);
int (*websocket_data)(struct mg_connection *, int bits, int (*websocket_data)(struct mg_connection *, int bits,
char *data, size_t data_len); char *data, size_t data_len);
const char * (*open_file)(const struct mg_connection *,
const char *path, size_t *data_len);
void (*init_lua)(struct mg_connection *, void *lua_context);
void (*upload)(struct mg_connection *, const char *file_name); void (*upload)(struct mg_connection *, const char *file_name);
void (*thread_start)(void *user_data, void **conn_data); void (*thread_start)(void *user_data, void **conn_data);
void (*thread_stop)(void *user_data, void **conn_data); void (*thread_stop)(void *user_data, void **conn_data);
......
...@@ -201,21 +201,10 @@ static char *read_file(const char *path, int *size) { ...@@ -201,21 +201,10 @@ static char *read_file(const char *path, int *size) {
} }
static const char *fetch_data = "hello world!\n"; static const char *fetch_data = "hello world!\n";
static const char *inmemory_file_data = "hi there";
static const char *upload_filename = "upload_test.txt"; static const char *upload_filename = "upload_test.txt";
static const char *upload_filename2 = "upload_test2.txt"; static const char *upload_filename2 = "upload_test2.txt";
static const char *upload_ok_message = "upload successful"; static const char *upload_ok_message = "upload successful";
static const char *open_file_cb(const struct mg_connection *conn,
const char *path, size_t *size) {
(void) conn;
if (!strcmp(path, "./blah")) {
*size = strlen(inmemory_file_data);
return inmemory_file_data;
}
return NULL;
}
static void upload_cb(struct mg_connection *conn, const char *path) { static void upload_cb(struct mg_connection *conn, const char *path) {
const struct mg_request_info *ri = mg_get_request_info(conn); const struct mg_request_info *ri = mg_get_request_info(conn);
char *p1, *p2; char *p1, *p2;
...@@ -282,7 +271,7 @@ static int log_message_cb(const struct mg_connection *conn, const char *msg) { ...@@ -282,7 +271,7 @@ static int log_message_cb(const struct mg_connection *conn, const char *msg) {
static const struct mg_callbacks CALLBACKS = { static const struct mg_callbacks CALLBACKS = {
&begin_request_handler_cb, NULL, &log_message_cb, NULL, NULL, NULL, NULL, &begin_request_handler_cb, NULL, &log_message_cb, NULL, NULL, NULL, NULL,
&open_file_cb, NULL, &upload_cb, NULL, NULL &upload_cb, NULL, NULL
}; };
static const char *OPTIONS[] = { static const char *OPTIONS[] = {
...@@ -339,25 +328,6 @@ static void test_mg_download(void) { ...@@ -339,25 +328,6 @@ static void test_mg_download(void) {
free(p1), free(p2); free(p1), free(p2);
mg_close_connection(conn); mg_close_connection(conn);
// Fetch in-memory file, should succeed.
ASSERT((conn = mg_download("localhost", port, 1, ebuf, sizeof(ebuf), "%s",
"GET /blah HTTP/1.1\r\n\r\n")) != NULL);
ASSERT((p1 = read_conn(conn, &len1)) != NULL);
ASSERT(len1 == (int) strlen(inmemory_file_data));
ASSERT(memcmp(p1, inmemory_file_data, len1) == 0);
free(p1);
mg_close_connection(conn);
// Fetch in-memory data with no Content-Length, should succeed.
ASSERT((conn = mg_download("localhost", port, 1, ebuf, sizeof(ebuf), "%s",
"GET /data HTTP/1.1\r\n\r\n")) != NULL);
ASSERT((p1 = read_conn(conn, &len1)) != NULL);
ASSERT(len1 == (int) strlen(fetch_data));
ASSERT(memcmp(p1, fetch_data, len1) == 0);
free(p1);
mg_close_connection(conn);
// Test SSL redirect, IP address // Test SSL redirect, IP address
ASSERT((conn = mg_download("localhost", atoi(HTTP_PORT), 0, ASSERT((conn = mg_download("localhost", atoi(HTTP_PORT), 0,
ebuf, sizeof(ebuf), "%s", ebuf, sizeof(ebuf), "%s",
...@@ -576,9 +546,8 @@ static void test_lua(void) { ...@@ -576,9 +546,8 @@ static void test_lua(void) {
#endif #endif
static void test_mg_stat(void) { static void test_mg_stat(void) {
static struct mg_context ctx;
struct file file = STRUCT_FILE_INITIALIZER; struct file file = STRUCT_FILE_INITIALIZER;
ASSERT(!mg_stat(fc(&ctx), " does not exist ", &file)); ASSERT(!mg_stat(" does not exist ", &file));
} }
static void test_skip_quoted(void) { static void test_skip_quoted(void) {
......
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