Removed init_lua() and open_file() callbacks

This commit is contained in:
Sergey Lyubka 2013-09-26 09:35:07 +01:00
parent 7eed7eab36
commit 98214ce1a4
4 changed files with 140 additions and 253 deletions

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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);

View File

@ -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) {