diff options
author | Arno Töll <arno@debian.org> | 2012-11-21 23:03:51 +0100 |
---|---|---|
committer | Arno Töll <arno@debian.org> | 2012-11-21 23:03:51 +0100 |
commit | f1532bfdd56dc641ae366f6ecd4c490c11117aac (patch) | |
tree | e58012163da210efa84fdbdcefd069ee511fd3e4 /src/mod_ssi.c | |
parent | 3f9e670856f606be4d9899e2d2a9ed4708575f10 (diff) | |
download | lighttpd-f1532bfdd56dc641ae366f6ecd4c490c11117aac.tar.gz |
Imported Upstream version 1.4.19upstream/1.4.19
Diffstat (limited to 'src/mod_ssi.c')
-rw-r--r-- | src/mod_ssi.c | 108 |
1 files changed, 76 insertions, 32 deletions
diff --git a/src/mod_ssi.c b/src/mod_ssi.c index e706e8f..d02d998 100644 --- a/src/mod_ssi.c +++ b/src/mod_ssi.c @@ -36,6 +36,11 @@ #include <sys/filio.h> #endif +#include "etag.h" + +/* The newest modified time of included files for include statement */ +static volatile time_t include_file_last_mtime = 0; + /* init the plugin data */ INIT_FUNC(mod_ssi_init) { plugin_data *p; @@ -575,6 +580,11 @@ static int process_ssi_stmt(server *srv, connection *con, plugin_data *p, break; case SSI_INCLUDE: chunkqueue_append_file(con->write_queue, p->stat_fn, 0, st.st_size); + + /* Keep the newest mtime of included files */ + if (st.st_mtime > include_file_last_mtime) + include_file_last_mtime = st.st_mtime; + break; } } else { @@ -718,50 +728,57 @@ static int process_ssi_stmt(server *srv, connection *con, plugin_data *p, /* father */ int status; ssize_t r; + int was_interrupted = 0; close(from_exec_fds[1]); /* wait for the client to end */ /* - * FIXME: if we get interrupted by a SIGCHILD we count this as error - * - * for now it only happened on OpenBSD. - * - * that leads to zombies and missing output + * OpenBSD and Solaris send a EINTR on SIGCHILD even if we ignore it */ - if (-1 == waitpid(pid, &status, 0)) { - log_error_write(srv, __FILE__, __LINE__, "ss", "waitpid failed:", strerror(errno)); - } else if (WIFEXITED(status)) { - int toread; - /* read everything from client and paste it into the output */ - - while(1) { - if (ioctl(from_exec_fds[0], FIONREAD, &toread)) { - log_error_write(srv, __FILE__, __LINE__, "s", - "unexpected end-of-file (perhaps the ssi-exec process died)"); - return -1; + do { + if (-1 == waitpid(pid, &status, 0)) { + if (errno == EINTR) { + was_interrupted++; + } else { + was_interrupted = 0; + log_error_write(srv, __FILE__, __LINE__, "ss", "waitpid failed:", strerror(errno)); } - - if (toread > 0) { - b = chunkqueue_get_append_buffer(con->write_queue); - - buffer_prepare_copy(b, toread + 1); - - if ((r = read(from_exec_fds[0], b->ptr, b->size - 1)) < 0) { - /* read failed */ - break; + } else if (WIFEXITED(status)) { + int toread; + /* read everything from client and paste it into the output */ + was_interrupted = 0; + + while(1) { + if (ioctl(from_exec_fds[0], FIONREAD, &toread)) { + log_error_write(srv, __FILE__, __LINE__, "s", + "unexpected end-of-file (perhaps the ssi-exec process died)"); + return -1; + } + + if (toread > 0) { + b = chunkqueue_get_append_buffer(con->write_queue); + + buffer_prepare_copy(b, toread + 1); + + if ((r = read(from_exec_fds[0], b->ptr, b->size - 1)) < 0) { + /* read failed */ + break; + } else { + b->used = r; + b->ptr[b->used++] = '\0'; + } } else { - b->used = r; - b->ptr[b->used++] = '\0'; + break; } - } else { - break; } + } else { + was_interrupted = 0; + log_error_write(srv, __FILE__, __LINE__, "s", "process exited abnormally"); } - } else { - log_error_write(srv, __FILE__, __LINE__, "s", "process exited abnormally"); - } + } while (was_interrupted > 0 && was_interrupted < 4); /* if waitpid() gets interrupted, retry, but max 4 times */ + close(from_exec_fds[0]); break; @@ -912,6 +929,9 @@ static int mod_ssi_handle_request(server *srv, connection *con, plugin_data *p) build_ssi_cgi_vars(srv, con, p); p->if_is_false = 0; + /* Reset the modified time of included files */ + include_file_last_mtime = 0; + if (-1 == stream_open(&s, con->physical.path)) { log_error_write(srv, __FILE__, __LINE__, "sb", "stream-open: ", con->physical.path); @@ -1010,6 +1030,30 @@ static int mod_ssi_handle_request(server *srv, connection *con, plugin_data *p) response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/html")); + { + /* Generate "ETag" & "Last-Modified" headers */ + + stat_cache_entry *sce = NULL; + time_t lm_time = 0; + buffer *mtime = NULL; + + stat_cache_get_entry(srv, con, con->physical.path, &sce); + + etag_mutate(con->physical.etag, sce->etag); + response_header_overwrite(srv, con, CONST_STR_LEN("ETag"), CONST_BUF_LEN(con->physical.etag)); + + if (sce->st.st_mtime > include_file_last_mtime) + lm_time = sce->st.st_mtime; + else + lm_time = include_file_last_mtime; + + mtime = strftime_cache_get(srv, lm_time); + response_header_overwrite(srv, con, CONST_STR_LEN("Last-Modified"), CONST_BUF_LEN(mtime)); + } + + /* Reset the modified time of included files */ + include_file_last_mtime = 0; + /* reset physical.path */ buffer_reset(con->physical.path); |