Hi, I have a set of patches that serve two purposes: - fixing the current date parsing - not breaking when the locale changes
--->8-------->8-------->8-------->8-------->8-------->8-------->8-------->8--- 0001-Add-a-new-function-VOID-debug.setlocale-STRING.patch This patches adds a setlocale function to the debug vmod, because only a vmod could change the locale. It also improves the test m00020 and makes it run again with a different locale. 0002-Replace-strftime-3-for-HTTP-1.1-date-formatting.patch 0003-Replace-strptime-3-for-HTTP-date-parsing.patch Straightforward replacement for strftime, a little more effort has been put in strptime's replacement (the latter is not compliant anyway). 0004-Add-a-new-VNUM_2real-function.patch Because when you think you're done, it turns out the whole libc relies on a process-wide locale. 0005-Remove-support-for-the-ISO-8601-date-format.patch Bonus patch, I don't know where the support for this date format comes from. If you decide to remove it, you can apply this patch. --->8-------->8-------->8-------->8-------->8-------->8-------->8-------->8--- I'm willing to continue looking for locale-dependant code and sending patches, I'd like to see how this patch set will be commented first. The locale part is really just for vmods that may do a library call that would lead to setlocale. If you don't want the locale part, I can send a smaller patch set that will only improve the date parsing correctness (and the test case). Best Regards, Dridi
From 4d4608c3dcc2afc6e2badbf4952449dc1eb5994d Mon Sep 17 00:00:00 2001 From: Dridi Boukelmoune <[email protected]> Date: Mon, 9 Feb 2015 21:28:44 +0100 Subject: [PATCH 1/5] Add a new function `VOID debug.setlocale(STRING)` What happens if a VMOD uses a library that leads to a call to setlocale? The test `m00020.vtc` was updated to show how vtim functions behave with a different locale, but also issues unrelated to locales. The function strptime(3) is way too permissive in comparison with the grammar defined in the RFC 2616 (section 3.3.1). For example, it will happily parse `Monday, 20-Dec-30 00:00:00 GMT` even though it should be a Friday. When looking for a `%` pattern, it allows arbitrary spaces. --- bin/varnishtest/tests/m00020.vtc | 43 +++++++++++++++++++++++++++++++++++++++- lib/libvmod_debug/vmod.vcc | 2 ++ lib/libvmod_debug/vmod_debug.c | 8 ++++++++ 3 files changed, 52 insertions(+), 1 deletion(-) diff --git a/bin/varnishtest/tests/m00020.vtc b/bin/varnishtest/tests/m00020.vtc index 3611cc4..a9af9b6 100644 --- a/bin/varnishtest/tests/m00020.vtc +++ b/bin/varnishtest/tests/m00020.vtc @@ -7,8 +7,19 @@ server s1 { varnish v1 -vcl+backend { import ${vmod_std}; + import ${vmod_debug}; + + sub vcl_recv { + if (req.http.Accept-Language) { + debug.setlocale(req.http.Accept-Language); + } + } sub vcl_deliver { + if (!req.http.x-date) { + return (deliver); + } + set resp.http.x-date = std.time(req.http.x-date, now); if (std.time(req.http.x-date, now) < now - 1y) { set resp.http.x-past = 1; } @@ -22,19 +33,49 @@ client c1 { txreq -hdr "X-Date: Mon, 20 Dec 2010 00:00:00 GMT" rxresp expect resp.http.x-past == 1 + expect resp.http.x-date == "Mon, 20 Dec 2010 00:00:00 GMT" + txreq -hdr "X-Date: Monday, 20-Dec-30 00:00:00 GMT" rxresp + expect resp.http.x-past == <undef> + expect resp.http.x-future == <undef> + + txreq -hdr "X-Date: Monday, 30-Feb-15 00:00:00 GMT" + rxresp + expect resp.http.x-past == <undef> + expect resp.http.x-future == <undef> + + txreq -hdr "X-Date: Friday, 20-Dec-30 00:00:00 GMT" + rxresp expect resp.http.x-future == 1 + expect resp.http.x-date == "Fri, 20 Dec 2030 00:00:00 GMT" + txreq -hdr "X-Date: Mon Dec 20 00:00:00 2010" rxresp expect resp.http.x-past == 1 + expect resp.http.x-date == "Mon, 20 Dec 2010 00:00:00 GMT" + txreq -hdr "X-Date: 2030-12-20T00:00:00" rxresp expect resp.http.x-future == 1 + expect resp.http.x-date == "Fri, 20 Dec 2030 00:00:00 GMT" + txreq -hdr "X-Date: 1292803200.00" rxresp expect resp.http.x-past == 1 + expect resp.http.x-date == "Mon, 20 Dec 2010 00:00:00 GMT" + txreq -hdr "X-Date: 1923955200" rxresp expect resp.http.x-future == 1 -} -run + expect resp.http.x-date == "Fri, 20 Dec 2030 00:00:00 GMT" +} + +client c2 { + txreq -hdr "Accept-Language: fr_FR" + rxresp +} + +client c1 -run +client c2 -run +client c1 -run diff --git a/lib/libvmod_debug/vmod.vcc b/lib/libvmod_debug/vmod.vcc index b5d108c..99b1dea 100644 --- a/lib/libvmod_debug/vmod.vcc +++ b/lib/libvmod_debug/vmod.vcc @@ -93,3 +93,5 @@ Encrypt the HTTP header with quad-ROT13 encryption, $Function STRING argtest(STRING one, REAL two=2, STRING three="3") $Function INT vre_limit() + +$Function VOID setlocale(STRING locale) diff --git a/lib/libvmod_debug/vmod_debug.c b/lib/libvmod_debug/vmod_debug.c index b6736fb..6a065e9 100644 --- a/lib/libvmod_debug/vmod_debug.c +++ b/lib/libvmod_debug/vmod_debug.c @@ -28,6 +28,7 @@ #include "config.h" +#include <locale.h> #include <stdlib.h> #include <stdio.h> @@ -175,3 +176,10 @@ vmod_vre_limit(VRT_CTX) (void)ctx; return (cache_param->vre_limits.match); } + +VCL_VOID +vmod_setlocale(VRT_CTX, VCL_STRING locale) +{ + (void)ctx; + setlocale(LC_ALL, locale); +} -- 1.9.3
From 75431b9507a04bce27ca857dd459e89fb404eecf Mon Sep 17 00:00:00 2001 From: Dridi Boukelmoune <[email protected]> Date: Mon, 9 Feb 2015 21:34:36 +0100 Subject: [PATCH 2/5] Replace strftime(3) for HTTP/1.1 date formatting The pattern used in `VTIM_format` is rendered according to the current locale. It is not acceptable for HTTP/1.1 dates. What is even less acceptable is the fact that POSIX doesn't really define the scope of a setlocale(3) invocation. The most likely scenario is the worst-case scenario: it is global to the process. --- lib/libvarnish/vtim.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/lib/libvarnish/vtim.c b/lib/libvarnish/vtim.c index 28b5f13..3673242 100644 --- a/lib/libvarnish/vtim.c +++ b/lib/libvarnish/vtim.c @@ -60,6 +60,12 @@ #include "vas.h" #include "vtim.h" +static const char *vtim_abday[] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", + "Sat"}; + +static const char *vtim_abmon[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", + "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}; + /* * Note on Solaris: for some reason, clock_gettime(CLOCK_MONOTONIC, &ts) is not * implemented in assembly, but falls into a syscall, while gethrtime() doesn't, @@ -108,7 +114,15 @@ VTIM_format(double t, char *p) tt = (time_t) t; (void)gmtime_r(&tt, &tm); - AN(strftime(p, VTIM_FORMAT_SIZE, "%a, %d %b %Y %T GMT", &tm)); + (void)snprintf(p, VTIM_FORMAT_SIZE, + "%s, %02d %s %4d %02d:%02d:%02d GMT", + vtim_abday[tm.tm_wday], + tm.tm_mday, + vtim_abmon[tm.tm_mon], + tm.tm_year + 1900, + tm.tm_hour, + tm.tm_min, + tm.tm_sec); } /* XXX: add statistics ? */ -- 1.9.3
From 82794118d428ce09a6471eaaf806af62e492a1c1 Mon Sep 17 00:00:00 2001 From: Dridi Boukelmoune <[email protected]> Date: Fri, 13 Feb 2015 10:20:06 +0100 Subject: [PATCH 3/5] Replace strptime(3) for HTTP date parsing Instead, we use a drop-in replacement with only a subset of patterns. Composite patterns (eg. %T) are broken down into simpler patterns and since we know the pattern strings are well formed, it makes parsing a lot easier. --- lib/libvarnish/vtim.c | 154 +++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 147 insertions(+), 7 deletions(-) diff --git a/lib/libvarnish/vtim.c b/lib/libvarnish/vtim.c index 3673242..a676a1a 100644 --- a/lib/libvarnish/vtim.c +++ b/lib/libvarnish/vtim.c @@ -49,6 +49,7 @@ #include <sys/time.h> +#include <ctype.h> #include <errno.h> #include <math.h> #include <stdio.h> @@ -60,11 +61,14 @@ #include "vas.h" #include "vtim.h" +static const char *vtim_day[] = {"Sunday", "Monday", "Tuesday", "Wednesday", + "Thursday", "Friday", "Saturday", NULL}; + static const char *vtim_abday[] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", - "Sat"}; + "Sat", NULL}; static const char *vtim_abmon[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", - "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}; + "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", NULL}; /* * Note on Solaris: for some reason, clock_gettime(CLOCK_MONOTONIC, &ts) is not @@ -127,23 +131,149 @@ VTIM_format(double t, char *p) /* XXX: add statistics ? */ static const char *fmts[] = { - "%a, %d %b %Y %T GMT", /* RFC 822 & RFC 1123 */ - "%A, %d-%b-%y %T GMT", /* RFC 850 */ - "%a %b %d %T %Y", /* ANSI-C asctime() */ - "%FT%T", /* ISO 8601 */ + "%a, %d %b %Y %H:%M:%S GMT", /* RFC 822 & RFC 1123 */ + "%A, %d-%b-%y %H:%M:%S GMT", /* RFC 850 */ + "%a %b %e %H:%M:%S %Y", /* ANSI-C asctime() */ + "%Y-%m-%dT%H:%M:%S", /* ISO 8601 */ NULL }; +static const char* +vtim_find(const char *s, int *tm_field, const char **candidates) +{ + unsigned i = 0; + size_t len; + + while (*candidates) { + len = strlen(*candidates); + + if (!strncmp(*candidates, s, len)) { + *tm_field = i; + return s + len; + } + + candidates++; + i++; + } + + return NULL; +} + +static const char* +vtim_atoi(const char *s, int *tm_field, int min, int max, int sp, int delta) +{ + int val; + char *end; + + if ((!isdigit(*s) && (*s != ' ' || !sp)) + || !isdigit(s[1]) || isdigit(s[2])) + return NULL; + + errno = 0; + val = strtol(s, &end, 10); + + assert(!errno); + assert(end == s + 2); + + if (val < min || val > max) + return NULL; + + *tm_field = val + delta; + return end; +} + +static const char* +vtim_year(const char *s, struct tm *tm, size_t len) +{ + int val; + char *end; + size_t i; + + for (i = 0; i < len; i++) + if (!isdigit(s[i])) + return NULL; + + if (isdigit(s[len])) + return NULL; + + errno = 0; + val = strtol(s, &end, 10); + + assert(!errno); + assert(end == s + len); + + if (len == 4) + val -= 1900; + + if (len == 2 && val < 68) + val += 100; + + tm->tm_year = val; + return end; +} + +static const char* +vtim_pattern(const char *s, char format, struct tm *tm) +{ + AN(tm); + AN(format); + + switch (format) { + case 'A': return vtim_find(s, &tm->tm_wday, vtim_day); + case 'a': return vtim_find(s, &tm->tm_wday, vtim_abday); + case 'b': return vtim_find(s, &tm->tm_mon, vtim_abmon); + case 'd': return vtim_atoi(s, &tm->tm_mday, 1, 31, 0, 0); + case 'e': return vtim_atoi(s, &tm->tm_mday, 1, 31, 1, 0); + case 'H': return vtim_atoi(s, &tm->tm_hour, 0, 23, 0, 0); + case 'M': return vtim_atoi(s, &tm->tm_min, 0, 59, 0, 0); + case 'm': return vtim_atoi(s, &tm->tm_mon, 1, 12, 0, -1); + case 'S': return vtim_atoi(s, &tm->tm_sec, 0, 60, 0, 0); + case 'Y': return vtim_year(s, tm, 4); + case 'y': return vtim_year(s, tm, 2); + default: + WRONG("Unsupported date pattern"); + } +} + +static const char* +vtim_strptime(const char *s, const char *format, struct tm *tm) +{ + tm->tm_wday = - 1; + + while (*format && s && *s) { + switch (*format) { + case '%': + format++; + s = vtim_pattern(s, *format, tm); + format++; + break; + default: + if (*format != *s) + return NULL; + s++; + format++; + } + } + + if (*format || (s && *s)) + return NULL; + + return s; +} + double VTIM_parse(const char *p) { double t; + int wday; struct tm tm; const char **r; for (r = fmts; *r != NULL; r++) { memset(&tm, 0, sizeof tm); - if (strptime(p, *r, &tm) != NULL) { + if (vtim_strptime(p, *r, &tm) != NULL) { + wday = tm.tm_wday; + /* * Make sure this is initialized on the off-chance * that some raving loonie would apply DST to UTC. @@ -167,6 +297,16 @@ VTIM_parse(const char *p) t = mktime(&tm); AZ(strcmp(tzname[0], "UTC")); #endif + + /* + * Both strptime() and timegm() don't seem to care + * about inconsistent week days. And worse, timegm() + * actually modifies its argument. + */ + if (wday >= 0 && tm.tm_wday != wday) { + return (0); + } + return (t); } } -- 1.9.3
From 3a1b80b8e9eb2bc1902f5b7bb354db93e4aeadeb Mon Sep 17 00:00:00 2001 From: Dridi Boukelmoune <[email protected]> Date: Mon, 16 Feb 2015 18:04:21 +0100 Subject: [PATCH 4/5] Add a new `VNUM_2real` function Unlike strtod(3) it only parses numbers looking like `-123.456`. The sign is optional and can be either '+' or '-'. For now, VNUM_2real is used in `vnum.c` and the std vmod. --- include/vnum.h | 3 +- lib/libvarnish/vnum.c | 68 ++++++++++++++++++++++++++++++++-- lib/libvmod_std/vmod_std_conversions.c | 25 ++++--------- 3 files changed, 74 insertions(+), 22 deletions(-) diff --git a/include/vnum.h b/include/vnum.h index cf55c9a..6886fc8 100644 --- a/include/vnum.h +++ b/include/vnum.h @@ -1,6 +1,6 @@ /*- * Copyright (c) 2006 Verdens Gang AS - * Copyright (c) 2006-2011 Varnish Software AS + * Copyright (c) 2006-2015 Varnish Software AS * All rights reserved. * * Author: Poul-Henning Kamp <[email protected]> @@ -30,3 +30,4 @@ /* from libvarnish/vnum.c */ const char *VNUM_2bytes(const char *p, uintmax_t *r, uintmax_t rel); +double VNUM_2real (const char *nptr, const char **endptr); diff --git a/lib/libvarnish/vnum.c b/lib/libvarnish/vnum.c index 7c27821..5ed909f 100644 --- a/lib/libvarnish/vnum.c +++ b/lib/libvarnish/vnum.c @@ -25,11 +25,14 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * Deal with numbers with data storage suffix scaling + * Deal with: + * - numbers with data storage suffix scaling + * - real numbers */ #include "config.h" +#include <ctype.h> #include <math.h> #include <stdint.h> #include <stdio.h> @@ -46,12 +49,12 @@ const char * VNUM_2bytes(const char *p, uintmax_t *r, uintmax_t rel) { double fval; - char *end; + const char *end; if (p == NULL || *p == '\0') return (err_miss_num); - fval = strtod(p, &end); + fval = VNUM_2real(p, &end); if (end == p || !isfinite(fval)) return (err_invalid_num); @@ -110,6 +113,65 @@ VNUM_2bytes(const char *p, uintmax_t *r, uintmax_t rel) return (NULL); } +/*---------------------------------------------------------------------------- + * Parse a real number with the syntax { [ '+' | '-' ] DIGITS [ '.' DIGITS ] } + * + * Intended as a locale-independant replacement of strtod, supporting a + * single format for real numbers. + */ + +double +VNUM_2real(const char *nptr, const char **endptr) +{ + const char *p = nptr; + double s = 1, v = 0, e = 0.1; + + if (!p || (!isdigit(*p) && *p != '+' && *p != '-')) + goto err; + + if (*p == '-') + s = -1; + + if (!isdigit(*p)) + p++; + + if (!isdigit(*p)) + goto err; + + while (*p) { + if (*p == '.') { + p++; + if (!isdigit(*p)) + goto err; + break; + } + else if (!isdigit(*p)) + break; + + v *= 10; + v += *p - '0'; + p++; + } + + while (*p) { + if (!isdigit(*p)) + break; + + v += (*p - '0') * e; + e *= 0.1; + p++; + } + + if (endptr) + *endptr = p; + return s * v; + +err: + if (endptr) + *endptr = nptr; + return 0.0; +} + #ifdef NUM_C_TEST /* Compile with: "cc -o foo -DNUM_C_TEST -I../.. -I../../include num.c -lm" */ diff --git a/lib/libvmod_std/vmod_std_conversions.c b/lib/libvmod_std/vmod_std_conversions.c index d27ad44..d5ff87f 100644 --- a/lib/libvmod_std/vmod_std_conversions.c +++ b/lib/libvmod_std/vmod_std_conversions.c @@ -39,6 +39,7 @@ #include "cache/cache.h" +#include "vnum.h" #include "vrt.h" #include "vsa.h" #include "vtim.h" @@ -47,7 +48,7 @@ VCL_DURATION __match_proto__(td_std_duration) vmod_duration(VRT_CTX, VCL_STRING p, VCL_DURATION d) { - char *e; + const char *e; double r; CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC); @@ -58,17 +59,11 @@ vmod_duration(VRT_CTX, VCL_STRING p, VCL_DURATION d) while(isspace(*p)) p++; - if (*p != '+' && *p != '-' && !isdigit(*p)) - return (d); - e = NULL; - r = strtod(p, &e); + r = VNUM_2real(p, &e); - if (!isfinite(r)) - return (d); - - if (e == NULL) + if (!isfinite(r) || e == p) return (d); while(isspace(*e)) @@ -170,7 +165,7 @@ vmod_ip(VRT_CTX, VCL_STRING s, VCL_IP d) VCL_REAL __match_proto__(td_std_real) vmod_real(VRT_CTX, VCL_STRING p, VCL_REAL d) { - char *e; + const char *e; double r; CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC); @@ -181,17 +176,11 @@ vmod_real(VRT_CTX, VCL_STRING p, VCL_REAL d) while (isspace(*p)) p++; - if (*p != '+' && *p != '-' && !isdigit(*p)) - return (d); - e = NULL; - r = strtod(p, &e); + r = VNUM_2real(p, &e); - if (!isfinite(r)) - return (d); - - if (e == NULL || *e != '\0') + if (!isfinite(r) || e == p || *e != '\0') return (d); return (r); -- 1.9.3
From 5f64006564b446da9cafe0cabc7226e36f9aaad8 Mon Sep 17 00:00:00 2001 From: Dridi Boukelmoune <[email protected]> Date: Mon, 16 Feb 2015 19:50:53 +0100 Subject: [PATCH 5/5] Remove support for the ISO 8601 date format It is not part of the three accepted HTTP date formats. It also releases the parsing code from the month number sepcial handling. --- bin/varnishtest/tests/m00020.vtc | 5 ----- lib/libvarnish/vtim.c | 21 +++++++++------------ lib/libvmod_std/vmod.vcc | 1 - 3 files changed, 9 insertions(+), 18 deletions(-) diff --git a/bin/varnishtest/tests/m00020.vtc b/bin/varnishtest/tests/m00020.vtc index a9af9b6..be92f07 100644 --- a/bin/varnishtest/tests/m00020.vtc +++ b/bin/varnishtest/tests/m00020.vtc @@ -55,11 +55,6 @@ client c1 { expect resp.http.x-past == 1 expect resp.http.x-date == "Mon, 20 Dec 2010 00:00:00 GMT" - txreq -hdr "X-Date: 2030-12-20T00:00:00" - rxresp - expect resp.http.x-future == 1 - expect resp.http.x-date == "Fri, 20 Dec 2030 00:00:00 GMT" - txreq -hdr "X-Date: 1292803200.00" rxresp expect resp.http.x-past == 1 diff --git a/lib/libvarnish/vtim.c b/lib/libvarnish/vtim.c index a676a1a..1ae106d 100644 --- a/lib/libvarnish/vtim.c +++ b/lib/libvarnish/vtim.c @@ -32,14 +32,13 @@ * In the highly unlikely event of performance trouble, handbuilt versions * would likely be faster than relying on the OS time functions. * - * We must parse four different formats: + * We must parse three different formats: * 000000000011111111112222222222 * 012345678901234567890123456789 * ------------------------------ - * "Sun, 06 Nov 1994 08:49:37 GMT" RFC822 & RFC1123 + * "Sun, 06 Nov 1994 08:49:37 GMT" a subset of RFC1123 (& RFC822) * "Sunday, 06-Nov-94 08:49:37 GMT" RFC850 * "Sun Nov 6 08:49:37 1994" ANSI-C asctime() - * "1994-11-06T08:49:37" ISO 8601 * * And always output the RFC1123 format. * @@ -134,7 +133,6 @@ static const char *fmts[] = { "%a, %d %b %Y %H:%M:%S GMT", /* RFC 822 & RFC 1123 */ "%A, %d-%b-%y %H:%M:%S GMT", /* RFC 850 */ "%a %b %e %H:%M:%S %Y", /* ANSI-C asctime() */ - "%Y-%m-%dT%H:%M:%S", /* ISO 8601 */ NULL }; @@ -160,7 +158,7 @@ vtim_find(const char *s, int *tm_field, const char **candidates) } static const char* -vtim_atoi(const char *s, int *tm_field, int min, int max, int sp, int delta) +vtim_atoi(const char *s, int *tm_field, int min, int max, int sp) { int val; char *end; @@ -178,7 +176,7 @@ vtim_atoi(const char *s, int *tm_field, int min, int max, int sp, int delta) if (val < min || val > max) return NULL; - *tm_field = val + delta; + *tm_field = val; return end; } @@ -222,12 +220,11 @@ vtim_pattern(const char *s, char format, struct tm *tm) case 'A': return vtim_find(s, &tm->tm_wday, vtim_day); case 'a': return vtim_find(s, &tm->tm_wday, vtim_abday); case 'b': return vtim_find(s, &tm->tm_mon, vtim_abmon); - case 'd': return vtim_atoi(s, &tm->tm_mday, 1, 31, 0, 0); - case 'e': return vtim_atoi(s, &tm->tm_mday, 1, 31, 1, 0); - case 'H': return vtim_atoi(s, &tm->tm_hour, 0, 23, 0, 0); - case 'M': return vtim_atoi(s, &tm->tm_min, 0, 59, 0, 0); - case 'm': return vtim_atoi(s, &tm->tm_mon, 1, 12, 0, -1); - case 'S': return vtim_atoi(s, &tm->tm_sec, 0, 60, 0, 0); + case 'd': return vtim_atoi(s, &tm->tm_mday, 1, 31, 0); + case 'e': return vtim_atoi(s, &tm->tm_mday, 1, 31, 1); + case 'H': return vtim_atoi(s, &tm->tm_hour, 0, 23, 0); + case 'M': return vtim_atoi(s, &tm->tm_min, 0, 59, 0); + case 'S': return vtim_atoi(s, &tm->tm_sec, 0, 60, 0); case 'Y': return vtim_year(s, tm, 4); case 'y': return vtim_year(s, tm, 2); default: diff --git a/lib/libvmod_std/vmod.vcc b/lib/libvmod_std/vmod.vcc index 93ef0b7..c1e6ca9 100644 --- a/lib/libvmod_std/vmod.vcc +++ b/lib/libvmod_std/vmod.vcc @@ -248,7 +248,6 @@ Description | "Sun, 06 Nov 1994 08:49:37 GMT" | "Sunday, 06-Nov-94 08:49:37 GMT" | "Sun Nov 6 08:49:37 1994" - | "1994-11-06T08:49:37" | "784111777.00" | "784111777" Example -- 1.9.3
_______________________________________________ varnish-dev mailing list [email protected] https://www.varnish-cache.org/lists/mailman/listinfo/varnish-dev
