create date and time to seconds since epoch processing utility function

currently NetSurf uses curl_getdate to convert textural date and time
strings into seconds since epoch. It is betetr to move this
functionality to a utility function so curl_getdate can easily be
replaced if required.
This commit is contained in:
Vincent Sanders 2016-04-16 23:27:38 +01:00
parent 33c7df0c40
commit 0bc5d2ca4c
5 changed files with 129 additions and 59 deletions

View File

@ -37,7 +37,6 @@
#include <strings.h>
#include <inttypes.h>
#include <curl/curl.h>
#include <nsutils/time.h>
#include "utils/config.h"
@ -590,59 +589,79 @@ static nserror llcache_fetch_split_header(const uint8_t *data, size_t len,
static nserror llcache_fetch_parse_header(llcache_object *object,
const uint8_t *data, size_t len, char **name, char **value)
{
nserror error;
nserror res;
/* Set fetch response time if not already set */
if (object->cache.res_time == 0)
if (object->cache.res_time == 0) {
object->cache.res_time = time(NULL);
}
/* Decompose header into name-value pair */
error = llcache_fetch_split_header(data, len, name, value);
if (error != NSERROR_OK)
return error;
res = llcache_fetch_split_header(data, len, name, value);
if (res != NSERROR_OK) {
return res;
}
/* Parse cache headers to populate cache control data */
#define SKIP_ST(p) while (*p != '\0' && (*p == ' ' || *p == '\t')) p++
if (5 < len && strcasecmp(*name, "Date") == 0) {
if ((5 < len) &&
strcasecmp(*name, "Date") == 0) {
/* extract Date header */
object->cache.date = curl_getdate(*value, NULL);
} else if (4 < len && strcasecmp(*name, "Age") == 0) {
nsc_strntimet(*value,
strlen(*value),
&object->cache.date);
} else if ((4 < len) &&
strcasecmp(*name, "Age") == 0) {
/* extract Age header */
if ('0' <= **value && **value <= '9')
if ('0' <= **value && **value <= '9') {
object->cache.age = atoi(*value);
} else if (8 < len && strcasecmp(*name, "Expires") == 0) {
}
} else if ((8 < len) &&
strcasecmp(*name, "Expires") == 0) {
/* extract Expires header */
object->cache.expires = curl_getdate(*value, NULL);
} else if (14 < len && strcasecmp(*name, "Cache-Control") == 0) {
res = nsc_strntimet(*value,
strlen(*value),
&object->cache.expires);
if (res != NSERROR_OK) {
object->cache.expires = (time_t)0x7fffffff;
}
} else if ((14 < len) &&
strcasecmp(*name, "Cache-Control") == 0) {
/* extract and parse Cache-Control header */
const char *start = *value;
const char *comma = *value;
while (*comma != '\0') {
while (*comma != '\0' && *comma != ',')
while (*comma != '\0' && *comma != ',') {
comma++;
}
if (8 < comma - start && (strncasecmp(start,
"no-cache", 8) == 0 ||
strncasecmp(start, "no-store", 8) == 0))
/* When we get a disk cache we should
* distinguish between these two */
if ((8 < comma - start) &&
(strncasecmp(start, "no-cache", 8) == 0 ||
strncasecmp(start, "no-store", 8) == 0)) {
/**
* \todo When we get a disk cache we should
* distinguish between these two.
*/
object->cache.no_cache = LLCACHE_VALIDATE_ALWAYS;
else if (7 < comma - start &&
strncasecmp(start, "max-age", 7) == 0) {
} else if ((7 < comma - start) &&
strncasecmp(start, "max-age", 7) == 0) {
/* Find '=' */
while (start < comma && *start != '=')
while (start < comma && *start != '=') {
start++;
}
/* Skip over it */
start++;
#define SKIP_ST(p) while (*p != '\0' && (*p == ' ' || *p == '\t')) p++
/* Skip whitespace */
SKIP_ST(start);
if (start < comma)
if (start < comma) {
object->cache.max_age = atoi(start);
}
}
if (*comma != '\0') {
@ -652,10 +671,13 @@ static nserror llcache_fetch_parse_header(llcache_object *object,
SKIP_ST(comma);
}
#undef SKIP_ST
/* Set start for next token */
start = comma;
}
} else if (5 < len && strcasecmp(*name, "ETag") == 0) {
} else if ((5 < len) &&
(strcasecmp(*name, "ETag") == 0)) {
/* extract ETag header */
free(object->cache.etag);
object->cache.etag = strdup(*value);
@ -664,12 +686,14 @@ static nserror llcache_fetch_parse_header(llcache_object *object,
free(*value);
return NSERROR_NOMEM;
}
} else if (14 < len && strcasecmp(*name, "Last-Modified") == 0) {
} else if ((14 < len) &&
(strcasecmp(*name, "Last-Modified") == 0)) {
/* extract Last-Modified header */
object->cache.last_modified = curl_getdate(*value, NULL);
nsc_strntimet(*value,
strlen(*value),
&object->cache.last_modified);
}
#undef SKIP_ST
return NSERROR_OK;
}

View File

@ -95,7 +95,6 @@
#include <string.h>
#include <strings.h>
#include <time.h>
#include <curl/curl.h>
#include "utils/nsoption.h"
#include "utils/log.h"
@ -103,6 +102,7 @@
#include "utils/url.h"
#include "utils/utils.h"
#include "utils/bloom.h"
#include "utils/time.h"
#include "image/bitmap.h"
#include "desktop/cookie_manager.h"
#include "desktop/gui_internal.h"
@ -1587,22 +1587,21 @@ static bool urldb_parse_avpair(struct cookie_internal_data *c, char *n,
} else if (strcasecmp(n, "Expires") == 0) {
char *datenoday;
time_t expires;
nserror res;
/* Strip dayname from date (these are hugely
* variable and liable to break the parser.
* They also serve no useful purpose) */
/* Strip dayname from date (these are hugely variable
* and liable to break the parser. They also serve no
* useful purpose) */
for (datenoday = v; *datenoday && !isdigit(*datenoday);
datenoday++)
; /* do nothing */
expires = curl_getdate(datenoday, NULL);
if (expires == -1) {
/* assume we have an unrepresentable
* date => force it to the maximum
* possible value of a 32bit time_t
* (this may break in 2038. We'll
* deal with that once we come to
* it) */
res = nsc_strntimet(datenoday, strlen(datenoday), &expires);
if (res != NSERROR_OK) {
/* assume we have an unrepresentable date =>
* force it to the maximum possible value of a
* 32bit time_t (this may break in 2038. We'll
* deal with that once we come to it) */
expires = (time_t)0x7fffffff;
}
c->expires = expires;

View File

@ -91,8 +91,8 @@ struct gui_fetch_table {
/**
* Find a MIME type for a local file
*
* @note only used in curl fetcher on RISC OS otherwise its a
* strdup of filetype.
* @note only used in curl fetcher in form file controls on
* RISC OS otherwise its a strdup of a filetype call.
*
* \param ro_path RISC OS style path to file on disk
* \return MIME type string (on heap, caller should free), or NULL

View File

@ -48,6 +48,28 @@ int nsc_sntimet(char *str, size_t size, time_t *timep);
* @param timep Pointer to result.
* @return NSERROR_OK on success or error code on faliure.
*/
nserror nsc_snptimet(char *str, size_t size, time_t *timep);
nserror nsc_snptimet(const char *str, size_t size, time_t *timep);
/**
* Converts a date string to a number of seconds since epoch
*
* returns the number of seconds since the Epoch, January 1st 1970
* 00:00:00 in the UTC time zone, for the date and time that the
* \a str parameter specifies.
*
* datetime strings passed must be in one of the formats specified in:
* - RFC 822 (updated in RFC 1123) using time zone name or time zone delta
* - RFC 850 (obsoleted by RFC 1036)
* - ANSI C's asctime() format.
*
* @param[in] str The datetime string to parse
* @param[in] size The length of the source string
* @param[out] timep Pointer to result on success unmodified on error.
* @return NSERROR_OK on success and timep updated else
* NSERROR_INVALID if the string parsing failed otherwise a suitable
* error code
*/
nserror nsc_strntimet(const char *str, size_t size, time_t *timep);
#endif

View File

@ -32,6 +32,7 @@
#include <regex.h>
#include <time.h>
#include <errno.h>
#include <curl/curl.h>
#include "utils/config.h"
#include "utils/log.h"
@ -47,13 +48,15 @@ char *remove_underscores(const char *s, bool replacespace)
char *ret;
len = strlen(s);
ret = malloc(len + 1);
if (ret == NULL)
if (ret == NULL) {
return NULL;
}
for (i = 0, ii = 0; i < len; i++) {
if (s[i] != '_')
if (s[i] != '_') {
ret[ii++] = s[i];
else if (replacespace)
} else if (replacespace) {
ret[ii++] = ' ';
}
}
ret[ii] = '\0';
return ret;
@ -94,11 +97,14 @@ char *cnv_space2nbsp(const char *s)
char *d, *d0;
unsigned int numNBS;
/* Convert space & TAB into non breaking space character (0xA0) */
for (numNBS = 0, srcP = (const char *)s; *srcP != '\0'; ++srcP)
if (*srcP == ' ' || *srcP == '\t')
for (numNBS = 0, srcP = (const char *)s; *srcP != '\0'; ++srcP) {
if (*srcP == ' ' || *srcP == '\t') {
++numNBS;
if ((d = (char *)malloc((srcP - s) + numNBS + 1)) == NULL)
}
}
if ((d = (char *)malloc((srcP - s) + numNBS + 1)) == NULL) {
return NULL;
}
for (d0 = d, srcP = (const char *)s; *srcP != '\0'; ++srcP) {
if (*srcP == ' ' || *srcP == '\t') {
*d0++ = 0xC2;
@ -116,8 +122,9 @@ bool is_dir(const char *path)
{
struct stat s;
if (stat(path, &s))
if (stat(path, &s)) {
return false;
}
return S_ISDIR(s.st_mode) ? true : false;
}
@ -227,7 +234,7 @@ nserror regcomp_wrapper(regex_t *preg, const char *regex, int cflags)
* The size of buffers within human_friendly_bytesize.
*
* We can have a fairly good estimate of how long the buffer needs to
* be. The unsigned long can store a value representing a maximum
* be. The unsigned long can store a value representing a maximum
* size of around 4 GB. Therefore the greatest space required is to
* represent 1023MB. Currently that would be represented as "1023MB"
* so 12 including a null terminator. Ideally we would be able to
@ -500,7 +507,7 @@ int uname(struct utsname *buf) {
strcpy(buf->release,"release");
strcpy(buf->version,"version");
strcpy(buf->machine,"pc");
return 0;
}
#endif
@ -526,7 +533,7 @@ int inet_aton(const char *cp, struct in_addr *inp)
unsigned int b1, b2, b3, b4;
unsigned char c;
if (strspn(cp, "0123456789.") < strlen(cp))
if (strspn(cp, "0123456789.") < strlen(cp))
return 0;
if (sscanf(cp, "%3u.%3u.%3u.%3u%c", &b1, &b2, &b3, &b4, &c) != 4)
@ -550,17 +557,17 @@ int inet_pton(int af, const char *src, void *dst)
if (af == AF_INET) {
ret = inet_aton(src, dst);
}
}
#if !defined(NO_IPV6)
else if (af == AF_INET6) {
/* TODO: implement v6 address support */
ret = -1;
errno = EAFNOSUPPORT;
}
errno = EAFNOSUPPORT;
}
#endif
else {
ret = -1;
errno = EAFNOSUPPORT;
errno = EAFNOSUPPORT;
}
return ret;
@ -588,10 +595,11 @@ int nsc_sntimet(char *str, size_t size, time_t *timep)
}
return strftime(str, size, "%s", ltm);
#endif
#endif
}
nserror nsc_snptimet(char *str, size_t size, time_t *timep)
/* exported function documented in utils/time.h */
nserror nsc_snptimet(const char *str, size_t size, time_t *timep)
{
time_t time_out;
@ -628,3 +636,20 @@ nserror nsc_snptimet(char *str, size_t size, time_t *timep)
return NSERROR_OK;
}
/* exported function documented in utils/time.h */
nserror nsc_strntimet(const char *str, size_t size, time_t *timep)
{
time_t result;
result = curl_getdate(str, NULL);
if (result == -1) {
return NSERROR_INVALID;
}
*timep = result;
return NSERROR_OK;
}