diff --git a/build/mod_lua.c b/build/mod_lua.c index 93f05984..0d575716 100644 --- a/build/mod_lua.c +++ b/build/mod_lua.c @@ -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; } diff --git a/mongoose.c b/mongoose.c index 5b4535e7..da068a01 100644 --- a/mongoose.c +++ b/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 @@ -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; } diff --git a/mongoose.h b/mongoose.h index f3f1690c..1728963f 100644 --- a/mongoose.h +++ b/mongoose.h @@ -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); diff --git a/test/unit_test.c b/test/unit_test.c index 7aef22cb..e5a77ee4 100644 --- a/test/unit_test.c +++ b/test/unit_test.c @@ -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) {