summaryrefslogtreecommitdiff
path: root/src/mod_ssi.c
diff options
context:
space:
mode:
authorArno Töll <arno@debian.org>2012-11-21 23:03:51 +0100
committerArno Töll <arno@debian.org>2012-11-21 23:03:51 +0100
commitf1532bfdd56dc641ae366f6ecd4c490c11117aac (patch)
treee58012163da210efa84fdbdcefd069ee511fd3e4 /src/mod_ssi.c
parent3f9e670856f606be4d9899e2d2a9ed4708575f10 (diff)
downloadlighttpd-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.c108
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);