diff --git a/Makefile b/Makefile index fa75c0a0..52097446 100644 --- a/Makefile +++ b/Makefile @@ -72,6 +72,7 @@ LIB_SOURCES = src/libhttp.c \ src/httplib_handle_request.c \ src/httplib_handle_websocket_request.c \ src/httplib_initialize_ssl.c \ + src/httplib_is_not_modified.c \ src/httplib_is_websocket_protocol.c \ src/httplib_load_dll.c \ src/httplib_lock_unlock_connection.c \ diff --git a/src/httplib_is_not_modified.c b/src/httplib_is_not_modified.c new file mode 100644 index 00000000..b8ecbb9d --- /dev/null +++ b/src/httplib_is_not_modified.c @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2016 Lammert Bies + * Copyright (c) 2013-2016 the Civetweb developers + * Copyright (c) 2004-2013 Sergey Lyubka + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + + + +#include "libhttp-private.h" + + + +/* + * int XX_httplib_is_not_modified( const struct mg_connection *conn, const struct file *filep ); + * + * The function XX_httplib_is_not_modified() returns true, if a resource has + * not been modified sinze a given datetime and a 304 response should therefore + * be sufficient. + */ + +#if !defined(NO_CACHING) + +int XX_httplib_is_not_modified( const struct mg_connection *conn, const struct file *filep ) { + + char etag[64]; + const char *ims = mg_get_header( conn, "If-Modified-Since" ); + const char *inm = mg_get_header( conn, "If-None-Match" ); + + XX_httplib_construct_etag( etag, sizeof(etag), filep ); + if ( filep == NULL ) return 0; + return (inm != NULL && !mg_strcasecmp(etag, inm)) || (ims != NULL && (filep->last_modified <= XX_httplib_parse_date_string(ims))); + +} /* XX_httplib_is_not_modified */ + +#endif /* !NO_CACHING */ diff --git a/src/libhttp-private.h b/src/libhttp-private.h index b96fe628..2b727b1f 100644 --- a/src/libhttp-private.h +++ b/src/libhttp-private.h @@ -888,6 +888,7 @@ void XX_httplib_close_all_listening_sockets( struct mg_context *ctx ); void XX_httplib_close_connection( struct mg_connection *conn ); void XX_httplib_close_socket_gracefully( struct mg_connection *conn ); int XX_httplib_connect_socket( struct mg_context *ctx, const char *host, int port, int use_ssl, char *ebuf, size_t ebuf_len, SOCKET *sock, union usa *sa ); +void XX_httplib_construct_etag( char *buf, size_t buf_len, const struct file *filep ); int XX_httplib_consume_socket( struct mg_context *ctx, struct socket *sp, int thread_index ); void XX_httplib_delete_file( struct mg_connection *conn, const char *path ); void XX_httplib_discard_unread_request_data( struct mg_connection *conn ); @@ -933,6 +934,7 @@ int XX_httplib_match_prefix(const char *pattern, size_t pattern_len, const cha void XX_httplib_mkcol( struct mg_connection *conn, const char *path ); int XX_httplib_must_hide_file( struct mg_connection *conn, const char *path ); const char * XX_httplib_next_option( const char *list, struct vec *val, struct vec *eq_val ); +time_t XX_httplib_parse_date_string( const char *datetime ); int XX_httplib_parse_http_headers( char **buf, struct mg_request_info *ri ); int XX_httplib_parse_http_message( char *buf, int len, struct mg_request_info *ri ); int XX_httplib_parse_net( const char *spec, uint32_t *net, uint32_t *mask ); diff --git a/src/libhttp.c b/src/libhttp.c index ad85c7dc..86840cba 100644 --- a/src/libhttp.c +++ b/src/libhttp.c @@ -3565,7 +3565,7 @@ static int get_month_index(const char *s) { /* Parse UTC date-time string, and return the corresponding time_t value. */ -static time_t parse_date_string(const char *datetime) { +time_t XX_httplib_parse_date_string( const char *datetime ) { char month_str[32] = {0}; int second; @@ -3596,7 +3596,9 @@ static time_t parse_date_string(const char *datetime) { } return result; -} + +} /* XX_httplib_parse_date_string */ + #endif /* !NO_CACHING */ @@ -4874,12 +4876,13 @@ int XX_httplib_parse_range_header( const char *header, int64_t *a, int64_t *b ) } /* XX_httplib_parse_range_header */ -static void construct_etag(char *buf, size_t buf_len, const struct file *filep) { +void XX_httplib_construct_etag( char *buf, size_t buf_len, const struct file *filep ) { if (filep != NULL && buf != NULL) { XX_httplib_snprintf(NULL, NULL, buf, buf_len, "\"%lx.%" INT64_FMT "\"", (unsigned long)filep->last_modified, filep->size); } -} + +} /* XX_httplib_construct_etag */ void XX_httplib_fclose_on_exec( struct file *filep, struct mg_connection *conn ) { @@ -4997,7 +5000,7 @@ void XX_httplib_handle_static_file_request( struct mg_connection *conn, const ch * http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.3 */ XX_httplib_gmt_time_string(date, sizeof(date), &curtime); XX_httplib_gmt_time_string(lm, sizeof(lm), &filep->last_modified); - construct_etag(etag, sizeof(etag), filep); + XX_httplib_construct_etag(etag, sizeof(etag), filep); mg_printf(conn, "HTTP/1.1 %d %s\r\n" "%s%s%s" "Date: %s\r\n", conn->status_code, msg, cors1, cors2, cors3, date); XX_httplib_send_static_cache_header(conn); @@ -5046,7 +5049,7 @@ void XX_httplib_handle_not_modified_static_file_request( struct mg_connection *c conn->status_code = 304; XX_httplib_gmt_time_string(date, sizeof(date), &curtime); XX_httplib_gmt_time_string(lm, sizeof(lm), &filep->last_modified); - construct_etag(etag, sizeof(etag), filep); + XX_httplib_construct_etag(etag, sizeof(etag), filep); mg_printf(conn, "HTTP/1.1 %d %s\r\n" "Date: %s\r\n", conn->status_code, mg_get_response_code_text(conn, conn->status_code), date); XX_httplib_send_static_cache_header(conn); @@ -5422,20 +5425,3 @@ int XX_httplib_substitute_index_file( struct mg_connection *conn, char *path, si } /* XX_httplib_substitute_index_file */ #endif - - -#if !defined(NO_CACHING) -/* Return True if we should reply 304 Not Modified. */ -int XX_httplib_is_not_modified( const struct mg_connection *conn, const struct file *filep ) { - - char etag[64]; - const char *ims = mg_get_header( conn, "If-Modified-Since" ); - const char *inm = mg_get_header( conn, "If-None-Match" ); - - construct_etag(etag, sizeof(etag), filep); - if ( filep == NULL ) return 0; - return (inm != NULL && !mg_strcasecmp(etag, inm)) || (ims != NULL && (filep->last_modified <= parse_date_string(ims))); - -} /* XX_httplib_is_not_modified */ - -#endif /* !NO_CACHING */