mirror of
https://github.com/cesanta/mongoose.git
synced 2024-12-27 06:51:04 +08:00
Removed init_lua() and open_file() callbacks
This commit is contained in:
parent
7eed7eab36
commit
98214ce1a4
@ -361,32 +361,29 @@ static int handle_lsp_request(struct mg_connection *conn, const char *path,
|
||||
struct file *filep, struct lua_State *ls) {
|
||||
void *p = NULL;
|
||||
lua_State *L = NULL;
|
||||
FILE *fp = NULL;
|
||||
int error = 1;
|
||||
|
||||
// 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);
|
||||
} else if (filep->membuf == NULL &&
|
||||
(p = mmap(NULL, (size_t) filep->size, PROT_READ, MAP_PRIVATE,
|
||||
fileno(filep->fp), 0)) == MAP_FAILED) {
|
||||
} else if ((p = mmap(NULL, (size_t) filep->size, PROT_READ, MAP_PRIVATE,
|
||||
fileno(fp), 0)) == MAP_FAILED) {
|
||||
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) {
|
||||
send_http_error(conn, 500, http_500_error, "%s", "luaL_newstate failed");
|
||||
} else {
|
||||
// We're not sending HTTP headers here, Lua page must do it.
|
||||
if (ls == NULL) {
|
||||
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,
|
||||
filep->size, L);
|
||||
error = lsp(conn, path, p, filep->size, L);
|
||||
}
|
||||
|
||||
if (L != NULL && ls == NULL) lua_close(L);
|
||||
if (p != NULL) munmap(p, filep->size);
|
||||
mg_fclose(filep);
|
||||
fclose(fp);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
336
mongoose.c
336
mongoose.c
@ -165,8 +165,6 @@ typedef DWORD pthread_t;
|
||||
static int pthread_mutex_lock(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);
|
||||
struct file;
|
||||
static char *mg_fgets(char *buf, size_t size, struct file *filep, char **p);
|
||||
|
||||
#if defined(HAVE_STDINT)
|
||||
#include <stdint.h>
|
||||
@ -432,13 +430,11 @@ struct file {
|
||||
int is_directory;
|
||||
time_t modification_time;
|
||||
int64_t size;
|
||||
FILE *fp;
|
||||
const char *membuf; // Non-NULL if file data is in memory
|
||||
// set to 1 if the content is gzipped
|
||||
// in which case we need a content-encoding: gzip header
|
||||
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
|
||||
// thread and queued for future handling by the worker thread.
|
||||
@ -544,42 +540,15 @@ const char **mg_get_valid_option_names(void) {
|
||||
return config_options;
|
||||
}
|
||||
|
||||
static int is_file_in_memory(struct mg_connection *conn, const char *path,
|
||||
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)) {
|
||||
static FILE *mg_fopen(const char *path, const char *mode) {
|
||||
#ifdef _WIN32
|
||||
wchar_t wbuf[PATH_MAX], wmode[20];
|
||||
to_unicode(path, wbuf, ARRAY_SIZE(wbuf));
|
||||
MultiByteToWideChar(CP_UTF8, 0, mode, -1, wmode, ARRAY_SIZE(wmode));
|
||||
filep->fp = _wfopen(wbuf, wmode);
|
||||
wchar_t wbuf[PATH_MAX], wmode[20];
|
||||
to_unicode(path, wbuf, ARRAY_SIZE(wbuf));
|
||||
MultiByteToWideChar(CP_UTF8, 0, mode, -1, wmode, ARRAY_SIZE(wmode));
|
||||
return _wfopen(wbuf, wmode);
|
||||
#else
|
||||
filep->fp = fopen(path, mode);
|
||||
return fopen(path, mode);
|
||||
#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) {
|
||||
@ -1127,29 +1096,27 @@ static int path_cannot_disclose_cgi(const char *path) {
|
||||
return isalnum(last) || strchr(allowed_last_characters, last) != NULL;
|
||||
}
|
||||
|
||||
static int mg_stat(struct mg_connection *conn, const char *path,
|
||||
struct file *filep) {
|
||||
static int mg_stat(const char *path, struct file *filep) {
|
||||
wchar_t wbuf[PATH_MAX] = L"\\\\?\\";
|
||||
WIN32_FILE_ATTRIBUTE_DATA info;
|
||||
|
||||
if (!is_file_in_memory(conn, path, filep)) {
|
||||
to_unicode(path, wbuf + 4, ARRAY_SIZE(wbuf) - 4);
|
||||
if (GetFileAttributesExW(wbuf, GetFileExInfoStandard, &info) != 0) {
|
||||
filep->size = MAKEUQUAD(info.nFileSizeLow, info.nFileSizeHigh);
|
||||
filep->modification_time = SYS2UNIX_TIME(
|
||||
info.ftLastWriteTime.dwLowDateTime,
|
||||
info.ftLastWriteTime.dwHighDateTime);
|
||||
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));
|
||||
}
|
||||
filep->modification_time = 0;
|
||||
to_unicode(path, wbuf + 4, ARRAY_SIZE(wbuf) - 4);
|
||||
if (GetFileAttributesExW(wbuf, GetFileExInfoStandard, &info) != 0) {
|
||||
filep->size = MAKEUQUAD(info.nFileSizeLow, info.nFileSizeHigh);
|
||||
filep->modification_time = SYS2UNIX_TIME(
|
||||
info.ftLastWriteTime.dwLowDateTime,
|
||||
info.ftLastWriteTime.dwHighDateTime);
|
||||
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 filep->membuf != NULL || filep->modification_time != 0;
|
||||
return filep->modification_time != 0;
|
||||
}
|
||||
|
||||
static int mg_remove(const char *path) {
|
||||
@ -1305,9 +1272,9 @@ static pid_t spawn_process(struct mg_connection *conn, const char *prog,
|
||||
char *envblk, char *envp[], int fdin,
|
||||
int fdout, const char *dir) {
|
||||
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];
|
||||
struct file file = STRUCT_FILE_INITIALIZER;
|
||||
FILE *fp;
|
||||
STARTUPINFOA si;
|
||||
PROCESS_INFORMATION pi = { 0 };
|
||||
|
||||
@ -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
|
||||
snprintf(cmdline, sizeof(cmdline), "%s%c%s", dir, '/', prog);
|
||||
if (mg_fopen(conn, cmdline, "r", &file)) {
|
||||
p = (char *) file.membuf;
|
||||
mg_fgets(buf, sizeof(buf), &file, &p);
|
||||
mg_fclose(&file);
|
||||
if ((fp = mg_fopen(cmdline, "r")) != NULL) {
|
||||
fgets(buf, sizeof(buf), fp);
|
||||
fclose(fp);
|
||||
buf[sizeof(buf) - 1] = '\0';
|
||||
}
|
||||
|
||||
@ -1379,11 +1345,11 @@ static int set_non_blocking_mode(SOCKET sock) {
|
||||
}
|
||||
|
||||
#else
|
||||
static int mg_stat(struct mg_connection *conn, const char *path,
|
||||
struct file *filep) {
|
||||
static int mg_stat(const char *path, struct file *filep) {
|
||||
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->modification_time = st.st_mtime;
|
||||
filep->is_directory = S_ISDIR(st.st_mode);
|
||||
@ -1394,11 +1360,9 @@ static int mg_stat(struct mg_connection *conn, const char *path,
|
||||
if (filep->modification_time == (time_t) 0) {
|
||||
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) {
|
||||
@ -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
|
||||
// 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,
|
||||
if ((accept_encoding = mg_get_header(conn, "Accept-Encoding")) != NULL) {
|
||||
if (strstr(accept_encoding,"gzip") != NULL) {
|
||||
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;
|
||||
return 1;
|
||||
}
|
||||
@ -1866,7 +1832,7 @@ static int convert_uri_to_file_name(struct mg_connection *conn, char *buf,
|
||||
*p = '\0';
|
||||
if (match_prefix(conn->ctx->config[CGI_EXTENSIONS],
|
||||
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.
|
||||
// "/x.cgi/foo/bar\x00" => "/x.cgi\x00/foo/bar\x00"
|
||||
// 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,
|
||||
|
||||
// Use the global passwords file, if specified by auth_gpass option,
|
||||
// or search for .htpasswd in the requested directory.
|
||||
static void open_auth_file(struct mg_connection *conn, const char *path,
|
||||
struct file *filep) {
|
||||
static FILE *open_auth_file(struct mg_connection *conn, const char *path) {
|
||||
char name[PATH_MAX];
|
||||
const char *p, *e, *gpass = conn->ctx->config[GLOBAL_PASSWORDS_FILE];
|
||||
struct file file = STRUCT_FILE_INITIALIZER;
|
||||
FILE *fp = NULL;
|
||||
|
||||
if (gpass != NULL) {
|
||||
// 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));
|
||||
}
|
||||
// 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.
|
||||
} 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",
|
||||
path, '/', PASSWORDS_FILE_NAME);
|
||||
mg_fopen(conn, name, "r", filep);
|
||||
fp = mg_fopen(name, "r");
|
||||
} else {
|
||||
// Try to find .htpasswd in requested directory.
|
||||
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,
|
||||
break;
|
||||
mg_snprintf(conn, name, sizeof(name), "%.*s%c%s",
|
||||
(int) (e - p), p, '/', PASSWORDS_FILE_NAME);
|
||||
mg_fopen(conn, name, "r", filep);
|
||||
fp = mg_fopen(name, "r");
|
||||
}
|
||||
|
||||
return fp;
|
||||
}
|
||||
|
||||
// Parsed Authorization header
|
||||
@ -2428,44 +2396,17 @@ static int parse_auth_header(struct mg_connection *conn, char *buf,
|
||||
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.
|
||||
static int authorize(struct mg_connection *conn, struct file *filep) {
|
||||
static int authorize(struct mg_connection *conn, FILE *fp) {
|
||||
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)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Loop over passwords file
|
||||
p = (char *) filep->membuf;
|
||||
while (mg_fgets(line, sizeof(line), filep, &p) != NULL) {
|
||||
while (fgets(line, sizeof(line), fp) != NULL) {
|
||||
if (sscanf(line, "%[^:]:%[^:]:%s", f_user, f_domain, ha1) != 3) {
|
||||
continue;
|
||||
}
|
||||
@ -2484,7 +2425,7 @@ static int check_authorization(struct mg_connection *conn, const char *path) {
|
||||
char fname[PATH_MAX];
|
||||
struct vec uri_vec, filename_vec;
|
||||
const char *list;
|
||||
struct file file = STRUCT_FILE_INITIALIZER;
|
||||
FILE *fp = NULL;
|
||||
int authorized = 1;
|
||||
|
||||
list = conn->ctx->config[PROTECT_URI];
|
||||
@ -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)) {
|
||||
mg_snprintf(conn, fname, sizeof(fname), "%.*s",
|
||||
(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));
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!is_file_opened(&file)) {
|
||||
open_auth_file(conn, path, &file);
|
||||
if (fp == NULL) {
|
||||
fp = open_auth_file(conn, path);
|
||||
}
|
||||
|
||||
if (is_file_opened(&file)) {
|
||||
authorized = authorize(conn, &file);
|
||||
mg_fclose(&file);
|
||||
if (fp != NULL) {
|
||||
authorized = authorize(conn, fp);
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
return authorized;
|
||||
@ -2523,13 +2464,13 @@ static void send_authorization_request(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];
|
||||
FILE *fp;
|
||||
int ret = 0;
|
||||
|
||||
if (passfile != NULL && mg_fopen(conn, passfile, "r", &file)) {
|
||||
ret = authorize(conn, &file);
|
||||
mg_fclose(&file);
|
||||
if (passfile != NULL && (fp = mg_fopen(passfile, "r")) != NULL) {
|
||||
ret = authorize(conn, fp);
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
return ret;
|
||||
@ -2553,7 +2494,7 @@ int mg_modify_passwords_file(const char *fname, const char *domain,
|
||||
|
||||
// Create the file if does not exist
|
||||
if ((fp = fopen(fname, "a+")) != NULL) {
|
||||
(void) fclose(fp);
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
// Open the given file and temporary file
|
||||
@ -2746,7 +2687,7 @@ static int scan_directory(struct mg_connection *conn, const char *dir,
|
||||
// fails. For more details, see
|
||||
// http://code.google.com/p/mongoose/issues/detail?id=79
|
||||
memset(&de.file, 0, sizeof(de.file));
|
||||
mg_stat(conn, path, &de.file);
|
||||
mg_stat(path, &de.file);
|
||||
|
||||
de.file_name = dp->d_name;
|
||||
cb(&de, data);
|
||||
@ -2782,7 +2723,7 @@ static int remove_directory(struct mg_connection *conn, const char *dir) {
|
||||
// fails. For more details, see
|
||||
// http://code.google.com/p/mongoose/issues/detail?id=79
|
||||
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.is_directory) {
|
||||
remove_directory(conn, path);
|
||||
@ -2887,42 +2828,36 @@ static void handle_directory_request(struct mg_connection *conn,
|
||||
}
|
||||
|
||||
// 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) {
|
||||
char buf[MG_BUF_LEN];
|
||||
int to_read, num_read, num_written;
|
||||
|
||||
// Sanity check the offset
|
||||
offset = offset < 0 ? 0 : offset > filep->size ? filep->size : offset;
|
||||
// If offset is beyond file boundaries, don't send anything
|
||||
if (offset > 0 && fseeko(fp, offset, SEEK_SET) != 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (len > 0 && filep->membuf != NULL && filep->size > 0) {
|
||||
if (len > filep->size - offset) {
|
||||
len = filep->size - offset;
|
||||
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;
|
||||
}
|
||||
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
|
||||
if ((num_written = mg_write(conn, buf, (size_t) num_read)) != num_read) {
|
||||
break;
|
||||
}
|
||||
|
||||
// Both read and were successful, adjust counters
|
||||
conn->num_bytes_sent += num_written;
|
||||
len -= num_written;
|
||||
// Read from file, exit the loop on error
|
||||
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, (size_t) num_read)) != num_read) {
|
||||
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,
|
||||
(unsigned long) filep->modification_time, filep->size);
|
||||
}
|
||||
|
||||
static void fclose_on_exec(struct file *filep) {
|
||||
if (filep != NULL && filep->fp != NULL) {
|
||||
static void fclose_on_exec(FILE *fp) {
|
||||
if (fp != NULL) {
|
||||
#ifndef _WIN32
|
||||
fcntl(fileno(filep->fp), F_SETFD, FD_CLOEXEC);
|
||||
fcntl(fileno(fp), F_SETFD, FD_CLOEXEC);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@ -2958,6 +2893,7 @@ static void handle_file_request(struct mg_connection *conn, const char *path,
|
||||
int n;
|
||||
char gz_path[PATH_MAX];
|
||||
char const* encoding = "";
|
||||
FILE *fp;
|
||||
|
||||
get_mime_type(conn->ctx, path, &mime_vec);
|
||||
cl = filep->size;
|
||||
@ -2973,13 +2909,13 @@ static void handle_file_request(struct mg_connection *conn, const char *path,
|
||||
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,
|
||||
"fopen(%s): %s", path, strerror(ERRNO));
|
||||
return;
|
||||
}
|
||||
|
||||
fclose_on_exec(filep);
|
||||
fclose_on_exec(fp);
|
||||
|
||||
// If Range: header specified, act accordingly
|
||||
r1 = r2 = 0;
|
||||
@ -3024,14 +2960,14 @@ static void handle_file_request(struct mg_connection *conn, const char *path,
|
||||
EXTRA_HTTP_HEADERS);
|
||||
|
||||
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) {
|
||||
struct file file = STRUCT_FILE_INITIALIZER;
|
||||
if (mg_stat(conn, path, &file)) {
|
||||
if (mg_stat(path, &file)) {
|
||||
handle_file_request(conn, path, &file);
|
||||
} else {
|
||||
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,
|
||||
mg_strlcpy(path + n + 1, filename_vec.ptr, filename_vec.len + 1);
|
||||
|
||||
// Does it exist?
|
||||
if (mg_stat(conn, path, &file)) {
|
||||
if (mg_stat(path, &file)) {
|
||||
// Yes it does, break the loop
|
||||
*filep = file;
|
||||
found = 1;
|
||||
@ -3417,7 +3353,6 @@ static void handle_cgi_request(struct mg_connection *conn, const char *prog) {
|
||||
struct mg_request_info ri;
|
||||
struct cgi_env_block blk;
|
||||
FILE *in = NULL, *out = NULL;
|
||||
struct file fout = STRUCT_FILE_INITIALIZER;
|
||||
pid_t pid = (pid_t) -1;
|
||||
|
||||
prepare_cgi_environment(conn, prog, &blk);
|
||||
@ -3470,7 +3405,6 @@ static void handle_cgi_request(struct mg_connection *conn, const char *prog) {
|
||||
|
||||
setbuf(in, NULL);
|
||||
setbuf(out, NULL);
|
||||
fout.fp = out;
|
||||
|
||||
// Send POST data to the CGI process if needed
|
||||
if (!strcmp(conn->request_info.request_method, "POST") &&
|
||||
@ -3532,7 +3466,7 @@ static void handle_cgi_request(struct mg_connection *conn, const char *prog) {
|
||||
(size_t)(data_len - headers_len));
|
||||
|
||||
// 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:
|
||||
if (pid != (pid_t) -1) {
|
||||
@ -3562,7 +3496,7 @@ done:
|
||||
// For a given PUT path, create all intermediate subdirectories
|
||||
// for given path. Return 0 if the path itself is a directory,
|
||||
// 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];
|
||||
const char *s, *p;
|
||||
struct file file = STRUCT_FILE_INITIALIZER;
|
||||
@ -3579,7 +3513,7 @@ static int put_dir(struct mg_connection *conn, const char *path) {
|
||||
|
||||
// Try to create intermediate directory
|
||||
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;
|
||||
break;
|
||||
}
|
||||
@ -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) {
|
||||
int rc, body_len;
|
||||
struct de de;
|
||||
memset(&de.file, 0, sizeof(de.file));
|
||||
mg_stat(conn, path, &de.file);
|
||||
|
||||
if(de.file.modification_time) {
|
||||
memset(&de.file, 0, sizeof(de.file));
|
||||
mg_stat(path, &de.file);
|
||||
|
||||
if (de.file.modification_time) {
|
||||
send_http_error(conn, 405, "Method Not Allowed",
|
||||
"mkcol(%s): %s", path, strerror(ERRNO));
|
||||
return;
|
||||
@ -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) {
|
||||
struct file file = STRUCT_FILE_INITIALIZER;
|
||||
FILE *fp;
|
||||
const char *range;
|
||||
int64_t r1, r2;
|
||||
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);
|
||||
} else if (rc == -1) {
|
||||
send_http_error(conn, 500, http_500_error,
|
||||
"put_dir(%s): %s", path, strerror(ERRNO));
|
||||
} else if (!mg_fopen(conn, path, "wb+", &file) || file.fp == NULL) {
|
||||
mg_fclose(&file);
|
||||
} else if ((fp = mg_fopen(path, "wb+")) == NULL) {
|
||||
fclose(fp);
|
||||
send_http_error(conn, 500, http_500_error,
|
||||
"fopen(%s): %s", path, strerror(ERRNO));
|
||||
} else {
|
||||
fclose_on_exec(&file);
|
||||
fclose_on_exec(fp);
|
||||
range = mg_get_header(conn, "Content-Range");
|
||||
r1 = r2 = 0;
|
||||
if (range != NULL && parse_range_header(range, &r1, &r2) > 0) {
|
||||
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;
|
||||
}
|
||||
mg_printf(conn, "HTTP/1.1 %d OK\r\nContent-Length: 0\r\n\r\n",
|
||||
conn->status_code);
|
||||
mg_fclose(&file);
|
||||
fclose(fp);
|
||||
}
|
||||
}
|
||||
|
||||
static void send_ssi_file(struct mg_connection *, const char *,
|
||||
struct file *, int);
|
||||
|
||||
static void send_ssi_file(struct mg_connection *, const char *, FILE *, int);
|
||||
static void do_ssi_include(struct mg_connection *conn, const char *ssi,
|
||||
char *tag, int include_level) {
|
||||
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
|
||||
// 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,
|
||||
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",
|
||||
tag, path, strerror(ERRNO));
|
||||
} else {
|
||||
fclose_on_exec(&file);
|
||||
fclose_on_exec(fp);
|
||||
if (match_prefix(conn->ctx->config[SSI_EXTENSIONS],
|
||||
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 {
|
||||
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)
|
||||
static void do_ssi_exec(struct mg_connection *conn, char *tag) {
|
||||
char cmd[MG_BUF_LEN];
|
||||
struct file file = STRUCT_FILE_INITIALIZER;
|
||||
FILE *fp;
|
||||
|
||||
if (sscanf(tag, " \"%[^\"]\"", cmd) != 1) {
|
||||
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));
|
||||
} else {
|
||||
send_file_data(conn, &file, 0, INT64_MAX);
|
||||
pclose(file.fp);
|
||||
send_file_data(conn, fp, 0, INT64_MAX);
|
||||
pclose(fp);
|
||||
}
|
||||
}
|
||||
#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,
|
||||
struct file *filep, int include_level) {
|
||||
FILE *fp, int include_level) {
|
||||
char buf[MG_BUF_LEN];
|
||||
int ch, offset, len, in_ssi_tag;
|
||||
|
||||
@ -3751,7 +3675,7 @@ static void send_ssi_file(struct mg_connection *conn, const char *path,
|
||||
}
|
||||
|
||||
in_ssi_tag = len = offset = 0;
|
||||
while ((ch = mg_fgetc(filep, offset)) != EOF) {
|
||||
while ((ch = fgetc(fp)) != EOF) {
|
||||
if (in_ssi_tag && ch == '>') {
|
||||
in_ssi_tag = 0;
|
||||
buf[len++] = (char) ch;
|
||||
@ -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,
|
||||
const char *path) {
|
||||
struct file file = STRUCT_FILE_INITIALIZER;
|
||||
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,
|
||||
strerror(ERRNO));
|
||||
} else {
|
||||
conn->must_close = 1;
|
||||
fclose_on_exec(&file);
|
||||
fclose_on_exec(fp);
|
||||
get_mime_type(conn->ctx, path, &mime_vec);
|
||||
mg_printf(conn, "HTTP/1.1 200 OK\r\n"
|
||||
"Content-Type: %.*s\r\n"
|
||||
"Connection: close\r\n\r\n",
|
||||
(int) mime_vec.len, mime_vec.ptr);
|
||||
send_ssi_file(conn, path, &file, 0);
|
||||
mg_fclose(&file);
|
||||
send_ssi_file(conn, path, fp, 0);
|
||||
fclose(fp);
|
||||
}
|
||||
}
|
||||
|
||||
@ -4447,7 +4371,7 @@ static void handle_delete_request(struct mg_connection *conn,
|
||||
const char *path) {
|
||||
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");
|
||||
} else if (!file.modification_time) {
|
||||
send_http_error(conn, 500, http_500_error, "remove(%s): %s", path,
|
||||
@ -4513,7 +4437,7 @@ static void handle_request(struct mg_connection *conn) {
|
||||
mkcol(conn, path);
|
||||
} else if (!strcmp(ri->request_method, "DELETE")) {
|
||||
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)) {
|
||||
send_http_error(conn, 404, "Not Found", "%s", "File not found");
|
||||
} else if (file.is_directory && ri->uri[uri_len - 1] != '/') {
|
||||
@ -4903,7 +4827,7 @@ static void uninitialize_ssl(struct mg_context *ctx) {
|
||||
static int set_gpass_option(struct mg_context *ctx) {
|
||||
struct file file = STRUCT_FILE_INITIALIZER;
|
||||
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));
|
||||
return 0;
|
||||
}
|
||||
|
@ -59,9 +59,6 @@ struct mg_callbacks {
|
||||
void (*websocket_ready)(struct mg_connection *);
|
||||
int (*websocket_data)(struct mg_connection *, int bits,
|
||||
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 (*thread_start)(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) {
|
||||
}
|
||||
|
||||
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_filename2 = "upload_test2.txt";
|
||||
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) {
|
||||
const struct mg_request_info *ri = mg_get_request_info(conn);
|
||||
char *p1, *p2;
|
||||
@ -282,7 +271,7 @@ static int log_message_cb(const struct mg_connection *conn, const char *msg) {
|
||||
|
||||
static const struct mg_callbacks CALLBACKS = {
|
||||
&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[] = {
|
||||
@ -339,25 +328,6 @@ static void test_mg_download(void) {
|
||||
free(p1), free(p2);
|
||||
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
|
||||
ASSERT((conn = mg_download("localhost", atoi(HTTP_PORT), 0,
|
||||
ebuf, sizeof(ebuf), "%s",
|
||||
@ -576,9 +546,8 @@ static void test_lua(void) {
|
||||
#endif
|
||||
|
||||
static void test_mg_stat(void) {
|
||||
static struct mg_context ctx;
|
||||
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) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user