diff --git a/src/http_auth.c b/src/http_auth.c index 54a6ec2e..91299adf 100644 --- a/src/http_auth.c +++ b/src/http_auth.c @@ -67,29 +67,24 @@ static void CvtHex(const HASH Bin, char (*Hex)[33]) { handler_t auth_ldap_init(server *srv, mod_auth_plugin_config *s); static int http_auth_get_password(server *srv, mod_auth_plugin_data *p, buffer *username, buffer *realm, buffer *password) { - int ret = -1; - if (buffer_is_empty(username) || buffer_is_empty(realm)) return -1; if (p->conf.auth_backend == AUTH_BACKEND_HTDIGEST) { - stream f; - char * f_line; + FILE *fp; + char f_user[1024]; if (buffer_string_is_empty(p->conf.auth_htdigest_userfile)) return -1; - if (0 != stream_open(&f, p->conf.auth_htdigest_userfile)) { + fp = fopen(p->conf.auth_htdigest_userfile->ptr, "r"); + if (NULL == fp) { log_error_write(srv, __FILE__, __LINE__, "sbss", "opening digest-userfile", p->conf.auth_htdigest_userfile, "failed:", strerror(errno)); return -1; } - f_line = f.start; - - while (f_line - f.start != f.size) { - char *f_user, *f_pwd, *e, *f_realm; - size_t u_len, pwd_len, r_len; - - f_user = f_line; + while (NULL != fgets(f_user, sizeof(f_user), fp)) { + char *f_pwd, *f_realm; + size_t u_len, r_len; /* * htdigest format @@ -97,24 +92,20 @@ static int http_auth_get_password(server *srv, mod_auth_plugin_data *p, buffer * * user:realm:md5(user:realm:password) */ - if (NULL == (f_realm = memchr(f_user, ':', f.size - (f_user - f.start) ))) { + if (NULL == (f_realm = strchr(f_user, ':'))) { log_error_write(srv, __FILE__, __LINE__, "sbs", "parsed error in", p->conf.auth_htdigest_userfile, "expected 'username:realm:hashed password'"); - stream_close(&f); - - return -1; + continue; /* skip bad lines */ } - if (NULL == (f_pwd = memchr(f_realm + 1, ':', f.size - (f_realm + 1 - f.start)))) { + if (NULL == (f_pwd = strchr(f_realm + 1, ':'))) { log_error_write(srv, __FILE__, __LINE__, "sbs", "parsed error in", p->conf.auth_plain_userfile, "expected 'username:realm:hashed password'"); - stream_close(&f); - - return -1; + continue; /* skip bad lines */ } /* get pointers to the fields */ @@ -123,55 +114,44 @@ static int http_auth_get_password(server *srv, mod_auth_plugin_data *p, buffer * r_len = f_pwd - f_realm; f_pwd++; - if (NULL != (e = memchr(f_pwd, '\n', f.size - (f_pwd - f.start)))) { - pwd_len = e - f_pwd; - } else { - pwd_len = f.size - (f_pwd - f.start); - } - if (buffer_string_length(username) == u_len && (buffer_string_length(realm) == r_len) && (0 == strncmp(username->ptr, f_user, u_len)) && (0 == strncmp(realm->ptr, f_realm, r_len))) { /* found */ + size_t pwd_len = strlen(f_pwd); + if (f_pwd[pwd_len-1] == '\n') --pwd_len; + buffer_copy_string_len(password, f_pwd, pwd_len); - ret = 0; - break; + fclose(fp); + return 0; } - - /* EOL */ - if (!e) break; - - f_line = e + 1; } - stream_close(&f); + fclose(fp); } else if (p->conf.auth_backend == AUTH_BACKEND_HTPASSWD || p->conf.auth_backend == AUTH_BACKEND_PLAIN) { - stream f; - char * f_line; + FILE *fp; + char f_user[1024]; buffer *auth_fn; auth_fn = (p->conf.auth_backend == AUTH_BACKEND_HTPASSWD) ? p->conf.auth_htpasswd_userfile : p->conf.auth_plain_userfile; if (buffer_string_is_empty(auth_fn)) return -1; - if (0 != stream_open(&f, auth_fn)) { + fp = fopen(auth_fn->ptr, "r"); + if (NULL == fp) { log_error_write(srv, __FILE__, __LINE__, "sbss", "opening plain-userfile", auth_fn, "failed:", strerror(errno)); return -1; } - f_line = f.start; - - while (f_line - f.start != f.size) { - char *f_user, *f_pwd, *e; - size_t u_len, pwd_len; - - f_user = f_line; + while (NULL != fgets(f_user, sizeof(f_user), fp)) { + char *f_pwd; + size_t u_len; /* * htpasswd format @@ -179,50 +159,38 @@ static int http_auth_get_password(server *srv, mod_auth_plugin_data *p, buffer * * user:crypted passwd */ - if (NULL == (f_pwd = memchr(f_user, ':', f.size - (f_user - f.start) ))) { + if (NULL == (f_pwd = strchr(f_user, ':'))) { log_error_write(srv, __FILE__, __LINE__, "sbs", "parsed error in", auth_fn, "expected 'username:hashed password'"); - stream_close(&f); - - return -1; + continue; /* skip bad lines */ } /* get pointers to the fields */ u_len = f_pwd - f_user; f_pwd++; - if (NULL != (e = memchr(f_pwd, '\n', f.size - (f_pwd - f.start)))) { - pwd_len = e - f_pwd; - } else { - pwd_len = f.size - (f_pwd - f.start); - } - if (buffer_string_length(username) == u_len && (0 == strncmp(username->ptr, f_user, u_len))) { /* found */ + size_t pwd_len = strlen(f_pwd); + if (f_pwd[pwd_len-1] == '\n') --pwd_len; + buffer_copy_string_len(password, f_pwd, pwd_len); - ret = 0; - break; + fclose(fp); + return 0; } - - /* EOL */ - if (!e) break; - - f_line = e + 1; } - stream_close(&f); + fclose(fp); } else if (p->conf.auth_backend == AUTH_BACKEND_LDAP) { - ret = 0; - } else { - return -1; + return 0; } - return ret; + return -1; } int http_auth_match_rules(server *srv, array *req, const char *username, const char *group, const char *host) { diff --git a/src/mod_cgi.c b/src/mod_cgi.c index 8427ae82..e5e31bb3 100644 --- a/src/mod_cgi.c +++ b/src/mod_cgi.c @@ -817,7 +817,7 @@ static ssize_t cgi_write_file_chunk_mmap(server *srv, connection *con, int fd, c off_t offset, toSend, file_end; ssize_t r; size_t mmap_offset, mmap_avail; - const char *data; + char *data; force_assert(NULL != c); force_assert(FILE_CHUNK == c->type); @@ -848,21 +848,39 @@ static ssize_t cgi_write_file_chunk_mmap(server *srv, connection *con, int fd, c c->file.mmap.length = file_end - c->file.mmap.offset; if (MAP_FAILED == (c->file.mmap.start = mmap(NULL, c->file.mmap.length, PROT_READ, MAP_PRIVATE, c->file.fd, c->file.mmap.offset))) { - log_error_write(srv, __FILE__, __LINE__, "ssbdoo", "mmap failed:", - strerror(errno), c->file.name, c->file.fd, c->file.mmap.offset, (off_t) c->file.mmap.length); - return -1; + if (toSend > 65536) toSend = 65536; + data = malloc(toSend); + force_assert(data); + if (-1 == lseek(c->file.fd, offset, SEEK_SET) + || 0 >= (toSend = read(c->file.fd, data, toSend))) { + if (-1 == toSend) { + log_error_write(srv, __FILE__, __LINE__, "ssbdo", "lseek/read failed:", + strerror(errno), c->file.name, c->file.fd, offset); + } else { /*(0 == toSend)*/ + log_error_write(srv, __FILE__, __LINE__, "sbdo", "unexpected EOF (input truncated?):", + c->file.name, c->file.fd, offset); + } + free(data); + return -1; + } } } - force_assert(offset >= c->file.mmap.offset); - mmap_offset = offset - c->file.mmap.offset; - force_assert(c->file.mmap.length > mmap_offset); - mmap_avail = c->file.mmap.length - mmap_offset; - force_assert(toSend <= (off_t) mmap_avail); + if (MAP_FAILED != c->file.mmap.start) { + force_assert(offset >= c->file.mmap.offset); + mmap_offset = offset - c->file.mmap.offset; + force_assert(c->file.mmap.length > mmap_offset); + mmap_avail = c->file.mmap.length - mmap_offset; + force_assert(toSend <= (off_t) mmap_avail); + + data = c->file.mmap.start + mmap_offset; + } + + r = write(fd, data, toSend); - data = c->file.mmap.start + mmap_offset; + if (MAP_FAILED == c->file.mmap.start) free(data); - if ((r = write(fd, data, toSend)) < 0) { + if (r < 0) { switch (errno) { case EAGAIN: case EINTR: diff --git a/src/mod_dirlisting.c b/src/mod_dirlisting.c index 8775736c..f8946207 100644 --- a/src/mod_dirlisting.c +++ b/src/mod_dirlisting.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -476,6 +477,39 @@ static int http_list_directory_sizefmt(char *buf, size_t bufsz, off_t size) { return buflen + 3; } +/* don't want to block when open()ing a fifo */ +#if defined(O_NONBLOCK) +# define FIFO_NONBLOCK O_NONBLOCK +#else +# define FIFO_NONBLOCK 0 +#endif + +static void http_list_directory_include_file(buffer *out, buffer *path, const char *classname, int encode) { + int fd = open(path->ptr, O_RDONLY | FIFO_NONBLOCK); + ssize_t rd; + char buf[8192]; + + if (-1 == fd) return; + + if (encode) { + buffer_append_string_len(out, CONST_STR_LEN("
"));
+	}
+
+	while ((rd = read(fd, buf, sizeof(buf))) > 0) {
+		if (encode) {
+			buffer_append_string_encoded(out, buf, (size_t)rd, ENCODING_MINIMAL_XML);
+		} else {
+			buffer_append_string_len(out, buf, (size_t)rd);
+		}
+	}
+
+	if (encode) {
+		buffer_append_string_len(out, CONST_STR_LEN("
")); + } +} + static void http_list_directory_header(server *srv, connection *con, plugin_data *p, buffer *out) { UNUSED(srv); @@ -534,23 +568,13 @@ static void http_list_directory_header(server *srv, connection *con, plugin_data /* HEADER.txt */ if (p->conf.show_header) { - stream s; /* if we have a HEADER file, display it in
 */
 
 		buffer_copy_buffer(p->tmp_buf, con->physical.path);
 		buffer_append_slash(p->tmp_buf);
 		buffer_append_string_len(p->tmp_buf, CONST_STR_LEN("HEADER.txt"));
 
-		if (-1 != stream_open(&s, p->tmp_buf)) {
-			if (p->conf.encode_header) {
-				buffer_append_string_len(out, CONST_STR_LEN("
"));
-				buffer_append_string_encoded(out, s.start, s.size, ENCODING_MINIMAL_XML);
-				buffer_append_string_len(out, CONST_STR_LEN("
")); - } else { - buffer_append_string_len(out, s.start, s.size); - } - } - stream_close(&s); + http_list_directory_include_file(out, p->tmp_buf, "header", p->conf.encode_header); } buffer_append_string_len(out, CONST_STR_LEN("

Index of ")); @@ -587,23 +611,13 @@ static void http_list_directory_footer(server *srv, connection *con, plugin_data )); if (p->conf.show_readme) { - stream s; /* if we have a README file, display it in
 */
 
 		buffer_copy_buffer(p->tmp_buf,  con->physical.path);
 		buffer_append_slash(p->tmp_buf);
 		buffer_append_string_len(p->tmp_buf, CONST_STR_LEN("README.txt"));
 
-		if (-1 != stream_open(&s, p->tmp_buf)) {
-			if (p->conf.encode_readme) {
-				buffer_append_string_len(out, CONST_STR_LEN("
"));
-				buffer_append_string_encoded(out, s.start, s.size, ENCODING_MINIMAL_XML);
-				buffer_append_string_len(out, CONST_STR_LEN("
")); - } else { - buffer_append_string_len(out, s.start, s.size); - } - } - stream_close(&s); + http_list_directory_include_file(out, p->tmp_buf, "readme", p->conf.encode_readme); } if(p->conf.auto_layout) { diff --git a/src/mod_ssi.c b/src/mod_ssi.c index 09448944..9172fa2c 100644 --- a/src/mod_ssi.c +++ b/src/mod_ssi.c @@ -3,7 +3,6 @@ #include "base.h" #include "log.h" #include "buffer.h" -#include "stat_cache.h" #include "plugin.h" #include "stream.h" @@ -23,6 +22,7 @@ #include #include #include +#include #include #include @@ -140,7 +140,7 @@ SETDEFAULTS_FUNC(mod_ssi_set_defaults) { #ifdef HAVE_PCRE_H /* allow 2 params */ - if (NULL == (p->ssi_regex = pcre_compile("", 0, &errptr, &erroff, NULL))) { + if (NULL == (p->ssi_regex = pcre_compile("^$", 0, &errptr, &erroff, NULL))) { log_error_write(srv, __FILE__, __LINE__, "sds", "ssi: pcre ", erroff, errptr); @@ -155,6 +155,9 @@ SETDEFAULTS_FUNC(mod_ssi_set_defaults) { return HANDLER_GO_ON; } + +#ifdef HAVE_PCRE_H + static int ssi_env_add(array *env, const char *key, const char *val) { data_string *ds; @@ -302,7 +305,67 @@ static int build_ssi_cgi_vars(server *srv, connection *con, plugin_data *p) { return 0; } -static int process_ssi_stmt(server *srv, connection *con, plugin_data *p, const char **l, size_t n, stat_cache_entry *sce) { +static int process_ssi_stmt(server *srv, connection *con, plugin_data *p, const char **l, size_t n, struct stat *st) { + + /** + * + * + * config DONE + * errmsg -- missing + * sizefmt DONE + * timefmt DONE + * echo DONE + * var DONE + * encoding -- missing + * exec DONE + * cgi -- never + * cmd DONE + * fsize DONE + * file DONE + * virtual DONE + * flastmod DONE + * file DONE + * virtual DONE + * include DONE + * file DONE + * virtual DONE + * printenv DONE + * set DONE + * var DONE + * value DONE + * + * if DONE + * elif DONE + * else DONE + * endif DONE + * + * + * expressions + * AND, OR DONE + * comp DONE + * ${...} -- missing + * $... DONE + * '...' DONE + * ( ... ) DONE + * + * + * + * ** all DONE ** + * DATE_GMT + * The current date in Greenwich Mean Time. + * DATE_LOCAL + * The current date in the local time zone. + * DOCUMENT_NAME + * The filename (excluding directories) of the document requested by the user. + * DOCUMENT_URI + * The (%-decoded) URL path of the document requested by the user. Note that in the case of nested include files, this is not then URL for the current document. + * LAST_MODIFIED + * The last modification date of the document requested by the user. + * USER_NAME + * Contains the owner of the file which included it. + * + */ + size_t i, ssicmd = 0; char buf[255]; buffer *b = NULL; @@ -427,20 +490,20 @@ static int process_ssi_stmt(server *srv, connection *con, plugin_data *p, const b = buffer_init(); #ifdef HAVE_PWD_H - if (NULL == (pw = getpwuid(sce->st.st_uid))) { - buffer_copy_int(b, sce->st.st_uid); + if (NULL == (pw = getpwuid(st->st_uid))) { + buffer_copy_int(b, st->st_uid); } else { buffer_copy_string(b, pw->pw_name); } #else - buffer_copy_int(b, sce->st.st_uid); + buffer_copy_int(b, st->st_uid); #endif chunkqueue_append_buffer(con->write_queue, b); buffer_free(b); break; } case SSI_ECHO_LAST_MODIFIED: { - time_t t = sce->st.st_mtime; + time_t t = st->st_mtime; if (0 == strftime(buf, sizeof(buf), p->timefmt->ptr, localtime(&t))) { chunkqueue_append_mem(con->write_queue, CONST_STR_LEN("(none)")); @@ -524,7 +587,7 @@ static int process_ssi_stmt(server *srv, connection *con, plugin_data *p, const case SSI_FLASTMOD: case SSI_FSIZE: { const char * file_path = NULL, *virt_path = NULL; - struct stat st; + struct stat stb; char *sl; for (i = 2; i < n; i += 2) { @@ -590,8 +653,8 @@ static int process_ssi_stmt(server *srv, connection *con, plugin_data *p, const buffer_append_string_buffer(p->stat_fn, srv->tmp_buf); } - if (0 == stat(p->stat_fn->ptr, &st)) { - time_t t = st.st_mtime; + if (0 == stat(p->stat_fn->ptr, &stb)) { + time_t t = stb.st_mtime; switch (ssicmd) { case SSI_FSIZE: @@ -600,14 +663,14 @@ static int process_ssi_stmt(server *srv, connection *con, plugin_data *p, const int j = 0; const char *abr[] = { " B", " kB", " MB", " GB", " TB", NULL }; - off_t s = st.st_size; + off_t s = stb.st_size; for (j = 0; s > 1024 && abr[j+1]; s /= 1024, j++); buffer_copy_int(b, s); buffer_append_string(b, abr[j]); } else { - buffer_copy_int(b, st.st_size); + buffer_copy_int(b, stb.st_size); } chunkqueue_append_buffer(con->write_queue, b); buffer_free(b); @@ -620,11 +683,11 @@ static int process_ssi_stmt(server *srv, connection *con, plugin_data *p, const } break; case SSI_INCLUDE: - chunkqueue_append_file(con->write_queue, p->stat_fn, 0, st.st_size); + chunkqueue_append_file(con->write_queue, p->stat_fn, 0, stb.st_size); /* Keep the newest mtime of included files */ - if (st.st_mtime > include_file_last_mtime) - include_file_last_mtime = st.st_mtime; + if (stb.st_mtime > include_file_last_mtime) + include_file_last_mtime = stb.st_mtime; break; } @@ -960,17 +1023,139 @@ static int process_ssi_stmt(server *srv, connection *con, plugin_data *p, const } -static int mod_ssi_handle_request(server *srv, connection *con, plugin_data *p) { - stream s; -#ifdef HAVE_PCRE_H - int i, n; +static void mod_ssi_parse_ssi_stmt(server *srv, connection *con, plugin_data *p, char *s, int len, struct stat *st) { + + /** + * + */ #define N 10 int ovec[N * 3]; -#endif + int n = pcre_exec(p->ssi_regex, NULL, s, len, 0, 0, ovec, sizeof(ovec)/sizeof(*ovec)); + if (n > 0) { + const char **l; + pcre_get_substring_list(s, ovec, n, &l); + process_ssi_stmt(srv, con, p, l, n, st); + pcre_free_substring_list(l); + } else { + if (n != PCRE_ERROR_NOMATCH) { + log_error_write(srv, __FILE__, __LINE__, "sd", + "execution error while matching: ", n); + } + chunkqueue_append_mem(con->write_queue, s, len); /* append stmt as-is */ + } +} - stat_cache_entry *sce = NULL; +static int mod_ssi_stmt_len(const char *s, const int len) { + /* s must begin "" */ +} +static void mod_ssi_read_fd(server *srv, connection *con, plugin_data *p, int fd, struct stat *st) { + ssize_t rd; + size_t offset, pretag; + char buf[8192]; + + offset = 0; + pretag = 0; + while (0 < (rd = read(fd, buf+offset, sizeof(buf)-offset))) { + char *s; + size_t prelen = 0, len; + offset += (size_t)rd; + for (; (s = memchr(buf+prelen, '<', offset-prelen)); ++prelen) { + prelen = buf - s; + if (prelen + 5 <= offset) { /*("" + * (buf contains at least 5 chars for "" */ + memmove(buf, buf+prelen, offset-prelen); + offset = pretag = 0; + break; + } + } else if (prelen + 1 == offset || 0 == memcmp(s+1, "!--", offset - prelen - 1)) { + if (prelen - pretag && !p->if_is_false) { + chunkqueue_append_mem(con->write_queue, buf+pretag, prelen-pretag); + } + memcpy(buf, buf+prelen, offset-prelen); + offset = pretag = 0; + break; + } + /* loop to look for next '<' */ + } + if (offset == sizeof(buf)) { + if (!p->if_is_false) { + chunkqueue_append_mem(con->write_queue, buf+pretag, offset-pretag); + } + offset = pretag = 0; + } + } + + if (0 != rd) { + log_error_write(srv, __FILE__, __LINE__, "SsB", "read(): ", strerror(errno), con->physical.path); + } + + if (offset - pretag) { + /* copy remaining data in buf */ + if (!p->if_is_false) { + chunkqueue_append_mem(con->write_queue, buf+pretag, offset-pretag); + } + } +} + +#endif /* HAVE_PCRE_H */ + + +/* don't want to block when open()ing a fifo */ +#if defined(O_NONBLOCK) +# define FIFO_NONBLOCK O_NONBLOCK +#else +# define FIFO_NONBLOCK 0 +#endif + +static int mod_ssi_handle_request(server *srv, connection *con, plugin_data *p) { + int fd; + struct stat st; /* get a stream to the file */ @@ -984,104 +1169,25 @@ static int mod_ssi_handle_request(server *srv, connection *con, plugin_data *p) /* Reset the modified time of included files */ include_file_last_mtime = 0; - if (HANDLER_ERROR == stat_cache_get_entry(srv, con, con->physical.path, &sce)) { - log_error_write(srv, __FILE__, __LINE__, "SB", "stat_cache_get_entry failed: ", con->physical.path); - return -1; - } - - if (-1 == stream_open(&s, con->physical.path)) { + if (-1 == (fd = open(con->physical.path->ptr, O_RDONLY | FIFO_NONBLOCK))) { log_error_write(srv, __FILE__, __LINE__, "sb", - "stream-open: ", con->physical.path); + "open: ", con->physical.path); return -1; } - - /** - * - * - * config DONE - * errmsg -- missing - * sizefmt DONE - * timefmt DONE - * echo DONE - * var DONE - * encoding -- missing - * exec DONE - * cgi -- never - * cmd DONE - * fsize DONE - * file DONE - * virtual DONE - * flastmod DONE - * file DONE - * virtual DONE - * include DONE - * file DONE - * virtual DONE - * printenv DONE - * set DONE - * var DONE - * value DONE - * - * if DONE - * elif DONE - * else DONE - * endif DONE - * - * - * expressions - * AND, OR DONE - * comp DONE - * ${...} -- missing - * $... DONE - * '...' DONE - * ( ... ) DONE - * - * - * - * ** all DONE ** - * DATE_GMT - * The current date in Greenwich Mean Time. - * DATE_LOCAL - * The current date in the local time zone. - * DOCUMENT_NAME - * The filename (excluding directories) of the document requested by the user. - * DOCUMENT_URI - * The (%-decoded) URL path of the document requested by the user. Note that in the case of nested include files, this is not then URL for the current document. - * LAST_MODIFIED - * The last modification date of the document requested by the user. - * USER_NAME - * Contains the owner of the file which included it. - * - */ -#ifdef HAVE_PCRE_H - for (i = 0; (n = pcre_exec(p->ssi_regex, NULL, s.start, s.size, i, 0, ovec, N * 3)) > 0; i = ovec[1]) { - const char **l; - /* take everything from last offset to current match pos */ - - if (!p->if_is_false) chunkqueue_append_file(con->write_queue, con->physical.path, i, ovec[0] - i); - - pcre_get_substring_list(s.start, ovec, n, &l); - process_ssi_stmt(srv, con, p, l, n, sce); - pcre_free_substring_list(l); - } - - switch(n) { - case PCRE_ERROR_NOMATCH: - /* copy everything/the rest */ - chunkqueue_append_file(con->write_queue, con->physical.path, i, s.size - i); - - break; - default: - log_error_write(srv, __FILE__, __LINE__, "sd", - "execution error while matching: ", n); - break; + if (0 != fstat(fd, &st)) { + log_error_write(srv, __FILE__, __LINE__, "SB", "fstat failed: ", con->physical.path); + close(fd); + return -1; } -#endif - - stream_close(&s); + #ifdef HAVE_PCRE_H + mod_ssi_read_fd(srv, con, p, fd, &st); + #else + chunkqueue_append_file(con->write_queue, con->physical.path, 0, st.st_size); + #endif + close(fd); con->file_started = 1; con->file_finished = 1; con->mode = p->id; @@ -1094,18 +1200,16 @@ static int mod_ssi_handle_request(server *srv, connection *con, plugin_data *p) if (p->conf.conditional_requests) { /* Generate "ETag" & "Last-Modified" headers */ - time_t lm_time = 0; buffer *mtime = NULL; - etag_mutate(con->physical.etag, sce->etag); - response_header_overwrite(srv, con, CONST_STR_LEN("ETag"), CONST_BUF_LEN(con->physical.etag)); + /* use most recently modified include file for ETag and Last-Modified */ + if (st.st_mtime < include_file_last_mtime) + st.st_mtime = include_file_last_mtime; - if (sce->st.st_mtime > include_file_last_mtime) - lm_time = sce->st.st_mtime; - else - lm_time = include_file_last_mtime; + etag_create(con->physical.etag, &st, con->etag_flags); + response_header_overwrite(srv, con, CONST_STR_LEN("ETag"), CONST_BUF_LEN(con->physical.etag)); - mtime = strftime_cache_get(srv, lm_time); + mtime = strftime_cache_get(srv, st.st_mtime); response_header_overwrite(srv, con, CONST_STR_LEN("Last-Modified"), CONST_BUF_LEN(mtime)); if (HANDLER_FINISHED == http_response_handle_cachable(srv, con, mtime)) { diff --git a/src/mod_webdav.c b/src/mod_webdav.c index aba35aa0..3968a04c 100644 --- a/src/mod_webdav.c +++ b/src/mod_webdav.c @@ -661,13 +661,25 @@ static int webdav_delete_dir(server *srv, connection *con, plugin_data *p, physi return have_multi_status; } +/* don't want to block when open()ing a fifo */ +#if defined(O_NONBLOCK) +# define FIFO_NONBLOCK O_NONBLOCK +#else +# define FIFO_NONBLOCK 0 +#endif + +#ifndef O_BINARY +#define O_BINARY 0 +#endif + static int webdav_copy_file(server *srv, connection *con, plugin_data *p, physical *src, physical *dst, int overwrite) { - stream s; - int status = 0, ofd; + char *data; + ssize_t rd, wr, offset; + int status = 0, ifd, ofd; UNUSED(srv); UNUSED(con); - if (stream_open(&s, src->path)) { + if (-1 == (ifd = open(src->path->ptr, O_RDONLY | O_BINARY | FIFO_NONBLOCK))) { return 403; } @@ -688,22 +700,28 @@ static int webdav_copy_file(server *srv, connection *con, plugin_data *p, physic status = 403; break; } - stream_close(&s); + close(ifd); return status; } - if (-1 == write(ofd, s.start, s.size)) { - switch(errno) { - case ENOSPC: - status = 507; - break; - default: - status = 403; + data = malloc(131072); + force_assert(data); + + while (0 < (rd = read(ifd, data, 131072))) { + offset = 0; + do { + wr = write(ofd, data+offset, (size_t)(rd-offset)); + } while (wr >= 0 ? (offset += wr) != rd : (errno == EINTR)); + if (-1 == wr) { + status = (errno == ENOSPC) ? 507 : 403; break; } + } + if (0 != rd && 0 == status) status = 403; - stream_close(&s); + free(data); + close(ifd); close(ofd); #ifdef USE_PROPPATCH diff --git a/src/stream.c b/src/stream.c index a17079c0..cc22ca87 100644 --- a/src/stream.c +++ b/src/stream.c @@ -23,13 +23,14 @@ int stream_open(stream *f, buffer *fn) { -#ifdef HAVE_MMAP +#if !defined(__WIN32) struct stat st; int fd; f->start = NULL; f->size = 0; + f->mapped = 0; if (-1 == (fd = open(fn->ptr, O_RDONLY | O_BINARY | FIFO_NONBLOCK))) { return -1; @@ -48,13 +49,21 @@ int stream_open(stream *f, buffer *fn) { f->start = mmap(NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0); - close(fd); - if (MAP_FAILED == f->start) { - f->start = NULL; - return -1; + f->start = malloc((size_t)st.st_size); + if (NULL == f->start + || st.st_size != read(fd, f->start, (size_t)st.st_size)) { + free(f->start); + f->start = NULL; + close(fd); + return -1; + } + } else { + f->mapped = 1; } + close(fd); + f->size = st.st_size; return 0; @@ -122,15 +131,20 @@ int stream_open(stream *f, buffer *fn) { f->size = (off_t)fsize; return 0; -#else -# error no mmap found #endif } int stream_close(stream *f) { #ifdef HAVE_MMAP - if (f->start) munmap(f->start, f->size); + if (f->start) { + if (f->mapped) { + f->mapped = 0; + munmap(f->start, f->size); + } else { + free(f->start); + } + } #elif defined(__WIN32) if (f->start) UnmapViewOfFile(f->start); #endif diff --git a/src/stream.h b/src/stream.h index 11c42f97..2ef20c5f 100644 --- a/src/stream.h +++ b/src/stream.h @@ -7,6 +7,7 @@ typedef struct { char *start; off_t size; + int mapped; } stream; int stream_open(stream *f, buffer *fn);