Browse Source

moved last-modified handling into a exported function and let mod_cml use it

git-svn-id: svn://svn.lighttpd.net/lighttpd/branches/lighttpd-1.3.x@468 152afb58-edef-0310-8abb-c4023f1b3aa9
svn/heads/lighttpd-1.3.x
Jan Kneschke 17 years ago
parent
commit
ab054446f4
  1. 17
      src/mod_cml_lua.c
  2. 174
      src/response.c
  3. 1
      src/response.h

17
src/mod_cml_lua.c

@ -247,11 +247,21 @@ int cache_parse_lua(server *srv, connection *con, plugin_data *p, buffer *fn) {
struct stat st;
int curelem;
time_t last_mtime = 0;
lua_pushstring(L, "output_include");
curelem = lua_gettop(L);
lua_gettable(L, LUA_GLOBALSINDEX);
/* HOW-TO build a etag ?
* as we don't just have one file we have to take the stat()
* from all base files, merge them and build the etag from
* it later.
*
* The mtime of the content is the mtime of the freshest base file
*
* */
lua_pushnil(L); /* first key */
while (lua_next(L, curelem) != 0) {
@ -285,6 +295,7 @@ int cache_parse_lua(server *srv, connection *con, plugin_data *p, buffer *fn) {
}
} else {
chunkqueue_append_file(con->write_queue, b, 0, st.st_size);
if (st.st_mtime > mtime) mtime = st.st_mtime;
}
} else {
/* not a string */
@ -301,6 +312,12 @@ int cache_parse_lua(server *srv, connection *con, plugin_data *p, buffer *fn) {
if (ret == 0) {
con->file_finished = 1;
if (http_response_handle_cachable(srv, con, mtime)) {
/* ok, the client already has our content,
* no need to send it again */
chunkqueue_reset(con->write_queue);
}
} else {
chunkqueue_reset(con->write_queue);
}

174
src/response.c

@ -851,6 +851,97 @@ static int http_list_directory(server *srv, connection *con, buffer *dir) {
}
int http_response_handle_cachable(server *srv, connection *con, time_t mtime) {
if (con->http_status != 0) return 0;
/*
* 14.26 If-None-Match
* [...]
* If none of the entity tags match, then the server MAY perform the
* requested method as if the If-None-Match header field did not exist,
* but MUST also ignore any If-Modified-Since header field(s) in the
* request. That is, if no entity tags match, then the server MUST NOT
* return a 304 (Not Modified) response.
*/
/* last-modified handling */
if (con->request.http_if_none_match) {
if (etag_is_equal(con->physical.etag, con->request.http_if_none_match)) {
if (con->request.http_method == HTTP_METHOD_GET ||
con->request.http_method == HTTP_METHOD_HEAD) {
/* check if etag + last-modified */
if (con->request.http_if_modified_since) {
char buf[64];
struct tm tm;
size_t used_len;
char *semicolon;
strftime(buf, sizeof(buf)-1, "%a, %d %b %Y %H:%M:%S GMT", gmtime(&mtime));
if (NULL == (semicolon = strchr(con->request.http_if_modified_since, ';'))) {
used_len = strlen(con->request.http_if_modified_since);
} else {
used_len = semicolon - con->request.http_if_modified_since;
}
if (0 == strncmp(con->request.http_if_modified_since, buf, used_len)) {
con->http_status = 304;
return 1;
} else {
/* convert to timestamp */
if (used_len < sizeof(buf) - 1) {
time_t t;
strncpy(buf, con->request.http_if_modified_since, used_len);
buf[used_len] = '\0';
strptime(buf, "%a, %d %b %Y %H:%M:%S GMT", &tm);
if (-1 != (t = mktime(&tm)) &&
t <= mtime) {
con->http_status = 304;
return 1;
}
} else {
log_error_write(srv, __FILE__, __LINE__, "ss",
con->request.http_if_modified_since, buf);
con->http_status = 412;
return 1;
}
}
} else {
con->http_status = 304;
return 1;
}
} else {
con->http_status = 412;
return 1;
}
}
} else if (con->request.http_if_modified_since) {
char buf[64];
struct tm *tm;
size_t used_len;
char *semicolon;
tm = gmtime(&(mtime));
strftime(buf, sizeof(buf)-1, "%a, %d %b %Y %H:%M:%S GMT", tm);
if (NULL == (semicolon = strchr(con->request.http_if_modified_since, ';'))) {
used_len = strlen(con->request.http_if_modified_since);
} else {
used_len = semicolon - con->request.http_if_modified_since;
}
if (0 == strncmp(con->request.http_if_modified_since, buf, used_len)) {
con->http_status = 304;
return 1;
}
}
return 0;
}
handler_t http_response_prepare(server *srv, connection *con) {
handler_t r;
@ -1349,88 +1440,9 @@ handler_t http_response_prepare(server *srv, connection *con) {
/* generate e-tag */
etag_mutate(con->physical.etag, con->fce->etag);
/*
* 14.26 If-None-Match
* [...]
* If none of the entity tags match, then the server MAY perform the
* requested method as if the If-None-Match header field did not exist,
* but MUST also ignore any If-Modified-Since header field(s) in the
* request. That is, if no entity tags match, then the server MUST NOT
* return a 304 (Not Modified) response.
*/
/* last-modified handling */
if (con->http_status == 0 &&
con->request.http_if_none_match) {
if (etag_is_equal(con->physical.etag, con->request.http_if_none_match)) {
if (con->request.http_method == HTTP_METHOD_GET ||
con->request.http_method == HTTP_METHOD_HEAD) {
/* check if etag + last-modified */
if (con->request.http_if_modified_since) {
char buf[64];
struct tm tm;
size_t used_len;
char *semicolon;
http_response_handle_cachable(srv, con, con->fce->st.st_mtime);
strftime(buf, sizeof(buf)-1, "%a, %d %b %Y %H:%M:%S GMT", gmtime(&(con->fce->st.st_mtime)));
if (NULL == (semicolon = strchr(con->request.http_if_modified_since, ';'))) {
used_len = strlen(con->request.http_if_modified_since);
} else {
used_len = semicolon - con->request.http_if_modified_since;
}
if (0 == strncmp(con->request.http_if_modified_since, buf, used_len)) {
con->http_status = 304;
} else {
/* convert to timestamp */
if (used_len < sizeof(buf) - 1) {
time_t t;
strncpy(buf, con->request.http_if_modified_since, used_len);
buf[used_len] = '\0';
strptime(buf, "%a, %d %b %Y %H:%M:%S GMT", &tm);
if (-1 != (t = mktime(&tm)) &&
t <= con->fce->st.st_mtime) {
con->http_status = 304;
}
} else {
log_error_write(srv, __FILE__, __LINE__, "ss",
con->request.http_if_modified_since, buf);
con->http_status = 412;
}
}
} else {
con->http_status = 304;
}
} else {
con->http_status = 412;
}
}
} else if (con->http_status == 0 && con->request.http_if_modified_since) {
char buf[64];
struct tm *tm;
size_t used_len;
char *semicolon;
tm = gmtime(&(con->fce->st.st_mtime));
strftime(buf, sizeof(buf)-1, "%a, %d %b %Y %H:%M:%S GMT", tm);
if (NULL == (semicolon = strchr(con->request.http_if_modified_since, ';'))) {
used_len = strlen(con->request.http_if_modified_since);
} else {
used_len = semicolon - con->request.http_if_modified_since;
}
if (0 == strncmp(con->request.http_if_modified_since, buf, used_len)) {
con->http_status = 304;
}
}
if (con->http_status == 0 && con->request.http_range) {
http_response_parse_range(srv, con);
} else if (con->http_status == 0) {

1
src/response.h

@ -14,5 +14,6 @@ int response_header_overwrite(server *srv, connection *con, const char *key, siz
handler_t http_response_prepare(server *srv, connection *con);
int http_response_redirect_to_directory(server *srv, connection *con);
int http_response_handle_cachable(server *srv, connection *con, time_t mtime);
#endif

Loading…
Cancel
Save