[core] http_date.[ch] encapsulate HTTP-date parse

http_date.[ch] encapsulate HTTP-date parse/compare

(import from one of my development branches from 2015)
master
Glenn Strauss 3 years ago
parent f928f6d827
commit f8cc9fb915

@ -448,6 +448,7 @@ if 1:
'strftime',
'strstr',
'strtol',
'timegm',
'writev',
])
autoconf.haveFunc('getentropy', 'sys/random.h')

@ -1479,6 +1479,7 @@ AC_CHECK_FUNCS([\
sigaction \
signal \
srandom \
timegm \
writev \
])
AC_CHECK_HEADERS([sys/random.h], [AC_CHECK_FUNCS([getentropy])])

@ -188,6 +188,7 @@ check_function_exists(sigtimedwait HAVE_SIGTIMEDWAIT)
check_function_exists(srandom HAVE_SRANDOM)
check_function_exists(strptime HAVE_STRPTIME)
check_function_exists(syslog HAVE_SYSLOG)
check_function_exists(timegm HAVE_TIMEGM)
check_function_exists(writev HAVE_WRITEV)
check_function_exists(inet_aton HAVE_INET_ATON)
check_function_exists(issetugid HAVE_ISSETUGID)
@ -745,6 +746,7 @@ set(COMMON_SRC
configfile-glue.c
http-header-glue.c
http_auth.c
http_date.c
http_vhostdb.c
request.c
sock_addr.c

@ -84,6 +84,7 @@ common_src=base64.c buffer.c burl.c log.c \
configfile-glue.c \
http-header-glue.c \
http_auth.c \
http_date.c \
http_vhostdb.c \
rand.c \
request.c \
@ -457,7 +458,7 @@ hdr = base64.h buffer.h burl.h network.h log.h http_kv.h keyvalue.h \
response.h request.h reqpool.h chunk.h h2.h \
first.h http_chunk.h \
algo_md.h algo_md5.h algo_sha1.h algo_splaytree.h algo_xxhash.h \
http_auth.h http_header.h http_vhostdb.h stream.h \
http_auth.h http_date.h http_header.h http_vhostdb.h stream.h \
fdevent.h gw_backend.h connections.h base.h base_decls.h stat_cache.h \
plugin.h plugin_config.h \
etag.h array.h vector.h \

@ -70,6 +70,7 @@ common_src = Split("base64.c buffer.c burl.c log.c \
configfile-glue.c \
http-header-glue.c \
http_auth.c \
http_date.c \
http_vhostdb.c \
request.c \
sock_addr.c \

@ -0,0 +1,120 @@
/*
* http_date - HTTP date manipulation
*
* Copyright(c) 2015 Glenn Strauss gstrauss()gluelogic.com All rights reserved
* License: BSD 3-clause (same as lighttpd)
*/
#include "http_date.h"
#include "sys-time.h"
/**
* https://tools.ietf.org/html/rfc7231
* [RFC7231] 7.1.1.1 Date/Time Formats
* Prior to 1995, there were three different formats commonly used by
* servers to communicate timestamps. For compatibility with old
* implementations, all three are defined here. The preferred format is
* a fixed-length and single-zone subset of the date and time
* specification used by the Internet Message Format [RFC5322].
* HTTP-date = IMF-fixdate / obs-date
* An example of the preferred format is
* Sun, 06 Nov 1994 08:49:37 GMT ; IMF-fixdate
*
*
* (intended for use with strftime() and strptime())
* "%a, %d %b %Y %T GMT"
*/
#if defined(__CYGWIN__) && defined(__STRICT_ANSI__)
/* (prototype for strptime() from cygwin /usr/include/time.h) */
char *_EXFUN(strptime, (const char *__restrict,
const char *__restrict,
struct tm *__restrict));
#endif
static char *
http_date_str_to_tm (const char * const s, struct tm * const tm)
{
/* attempt strptime() using multiple date formats
* support RFC 822,1123; RFC 850; and ANSI C asctime() date strings,
* as required by [RFC7231] https://tools.ietf.org/html/rfc7231#section-7.1
* [RFC7231] 7.1.1.1 Date/Time Formats
* HTTP-date = IMF-fixdate / obs-date
* [...]
* A recipient that parses a timestamp value in an HTTP header field
* MUST accept all three HTTP-date formats.
*/
static const char *datefmts[] = {
"%a, %d %b %Y %T GMT", /* RFC 822, RFC 1123; RFC 7231 IMF-fixdate */
"%A, %d-%b-%y %T GMT", /* RFC 850 */
"%a %b %d %T %Y" /* ANSI C asctime() (obsolete in POSIX.1-2008) */
};
char *p;
int i = 0;
do {
p = strptime(s, datefmts[i], tm);
} while (__builtin_expect( (NULL == p), 0)
&& ++i < (int)(sizeof(datefmts)/sizeof(char *)));
return p; /* NULL if error; date string could not be parsed */
}
size_t
http_date_time_to_str (char * const s, const size_t max, const time_t t)
{
/*('max' is expected to be >= 30 (IMF-fixdate is 29 chars + '\0'))*/
struct tm tm;
return (__builtin_expect( (NULL != gmtime_r(&t, &tm)), 1))
? strftime(s, max, "%a, %d %b %Y %T GMT", &tm) /* IMF-fixdate format */
: 0;
}
#ifdef HAVE_TIMEGM
#define http_date_timegm(tm) timegm(tm)
#else
#ifdef _WIN32
#define http_date_timegm(tm) _mkgmtime(tm)
#else
/* If OS missing timegm(), then for best portability it is recommended to set
* $ export LC_TIME=C TZ=UTC0
*
* tm->tm_isdst = 0 for mktime() to indicate daylight saving time not in effect
* which is fine since two strings should be GMT dates, and both are converted
* with mktime() and then the results compared */
#define http_date_timegm(tm) ((tm)->tm_isdst = 0, mktime(tm))
#endif
#endif
int
http_date_if_modified_since (const char * const ifmod,
const char * const lmod, time_t lmtime)
{
/* if caller provides non-zero lmtime, it must match Last-Modified lmod,
* and will typically be same arg given to http_response_set_last_modified()
* (small opt to elide one strptime(),timegm() call)
* (In absense of timegm(), substitute mktime(), which works reasonably well
* since mktime() strings are used for comparison of If-Modified-Since)
* (use mktime() to convert both strings for compare) */
struct tm ifmodtm;
if (NULL == http_date_str_to_tm(ifmod, &ifmodtm))
return 1; /* date parse error */
#if defined(HAVE_TIMEGM) || defined(_WIN32)
if (0 == lmtime)
#endif
{
struct tm lmodtm;
if (NULL == http_date_str_to_tm(lmod, &lmodtm))
return 1; /* date parse error */
lmtime = http_date_timegm(&lmodtm);
}
const time_t ifmtime = http_date_timegm(&ifmodtm);
return (lmtime > ifmtime);
/* returns 0 if not modified since,
* returns 1 if modified since or date parse error */
}

@ -0,0 +1,29 @@
/*
* http_date - HTTP date manipulation
*
* Copyright(c) 2015 Glenn Strauss gstrauss()gluelogic.com All rights reserved
* License: BSD 3-clause (same as lighttpd)
*/
#ifndef INCLUDED_HTTP_DATE_H
#define INCLUDED_HTTP_DATE_H
#include "first.h"
#ifdef __cplusplus
extern "C" {
#endif
#define HTTP_DATE_SZ 30 /* (IMF-fixdate is 29 chars + '\0') */
size_t http_date_time_to_str (char *s, size_t max, time_t t);
int http_date_if_modified_since (const char *ifmod, const char *lmod, time_t lmtime);
#ifdef __cplusplus
}
#endif
#endif

@ -143,6 +143,7 @@ conf_data.set('HAVE_SIGTIMEDWAIT', compiler.has_function('sigtimedwait', args: d
conf_data.set('HAVE_SRANDOM', compiler.has_function('srandom', args: defs))
conf_data.set('HAVE_STRPTIME', compiler.has_function('strptime', args: defs))
conf_data.set('HAVE_SYSLOG', compiler.has_function('syslog', args: defs))
conf_data.set('HAVE_TIMEGM', compiler.has_function('timegm', args: defs))
conf_data.set('HAVE_WRITEV', compiler.has_function('writev', args: defs))
conf_data.set('HAVE_INET_ATON', compiler.has_function('inet_aton', args: defs))
conf_data.set('HAVE_ISSETUGID', compiler.has_function('issetugid', args: defs))
@ -713,6 +714,7 @@ common_src = [
'gw_backend.c',
'http_auth.c',
'http_chunk.c',
'http_date.c',
'http_header.c',
'http_kv.c',
'http_vhostdb.c',

@ -1944,6 +1944,7 @@ int main (int argc, char **argv) {
/* for nice %b handling in strftime() */
setlocale(LC_TIME, "C");
tzset();
do {
server * const srv = server_init();

Loading…
Cancel
Save