Commit 0abf0df5 authored by Poul-Henning Kamp's avatar Poul-Henning Kamp

RFC8941 parsing of VCL_BYTES.

parent db265fd0
...@@ -11,7 +11,10 @@ varnish v1 -vcl+backend { ...@@ -11,7 +11,10 @@ varnish v1 -vcl+backend {
import std; import std;
sub vcl_deliver { sub vcl_deliver {
set resp.http.ts = std.real2time(std.real("10000000000000000000000", 0), now); set resp.http.ts = std.real2time(
std.real("999999999999.999", 0) *
std.real("999999999999.999", 0),
now);
} }
} -start } -start
......
...@@ -38,6 +38,13 @@ vtim_dur VNUM_duration(const char *p); ...@@ -38,6 +38,13 @@ vtim_dur VNUM_duration(const char *p);
double VNUM_bytes_unit(double r, const char *b, const char *e, uintmax_t rel); double VNUM_bytes_unit(double r, const char *b, const char *e, uintmax_t rel);
const char *VNUM_2bytes(const char *p, uintmax_t *r, uintmax_t rel); const char *VNUM_2bytes(const char *p, uintmax_t *r, uintmax_t rel);
#if 0
int64_t SF_Parse_Integer(const char **ipp, const char **errtxt);
double SF_Parse_Decimal(const char **ipp, const char **errtxt);
#endif
double SF_Parse_Number(const char **ipp, const char **errtxt);
#define VNUM_LEGAL_DURATION \ #define VNUM_LEGAL_DURATION \
"Legal duration units are 'ms', 's', 'm', 'h', 'd', 'w' and 'y'" "Legal duration units are 'ms', 's', 'm', 'h', 'd', 'w' and 'y'"
......
...@@ -45,9 +45,106 @@ ...@@ -45,9 +45,106 @@
#include "vct.h" #include "vct.h"
static const char err_miss_num[] = "Missing number"; static const char err_miss_num[] = "Missing number";
static const char err_fatnum[] = "Too may digits";
static const char err_invalid_num[] = "Invalid number"; static const char err_invalid_num[] = "Invalid number";
static const char err_invalid_suff[] = "Invalid suffix"; static const char err_invalid_suff[] = "Invalid suffix";
#define BAIL(txt) \
do { \
if (errtxt != NULL) \
*errtxt = (txt); \
errno = EINVAL; \
return (0); \
} while (0)
static int64_t
sf_parse_int(const char **ipp, const char **errtxt, int maxdig)
{
int64_t retval = 0;
int negative = 0, ndig = 0;
AN(ipp);
AN(*ipp);
errno = 0;
while (vct_isows(*(*ipp)))
(*ipp)++;
if(*(*ipp) == '-') {
negative = 1;
(*ipp)++;
}
while (vct_isdigit(*(*ipp))) {
ndig++;
if (ndig > maxdig)
BAIL(err_fatnum);
retval *= 10;
retval += *(*ipp)++ - 0x30;
}
if (ndig == 0)
BAIL(negative ? err_invalid_num : err_miss_num);
if (negative)
retval = -retval;
return (retval);
}
#if 0
int64_t
SF_Parse_Integer(const char **ipp, const char **errtxt)
{
return(sf_parse_int(ipp, errtxt, 15));
}
double
SF_Parse_Decimal(const char **ipp, const char **errtxt)
{
double retval;
retval = (double)sf_parse_int(ipp, errtxt, 12);
if (*(*ipp) != '.')
return (retval);
(*ipp)++;
if (!vct_isdigit(*(*ipp)))
return (retval);
retval += .1 * (*(*ipp)++ - 0x30);
if (!vct_isdigit(*(*ipp)))
return (retval);
retval += .01 * (*(*ipp)++ - 0x30);
if (!vct_isdigit(*(*ipp)))
return (retval);
retval += .001 * (*(*ipp)++ - 0x30);
if (vct_isdigit(*(*ipp)))
BAIL(err_fatnum);
return (retval);
}
#endif
double
SF_Parse_Number(const char **ipp, const char **errtxt)
{
double retval;
retval = (double)sf_parse_int(ipp, errtxt, 15);
if (*(*ipp) != '.')
return (retval);
if (retval < -999999999999 || retval > 999999999999)
BAIL(err_fatnum);
(*ipp)++;
if (!vct_isdigit(*(*ipp)))
return (retval);
retval += .1 * (*(*ipp)++ - 0x30);
if (!vct_isdigit(*(*ipp)))
return (retval);
retval += .01 * (*(*ipp)++ - 0x30);
if (!vct_isdigit(*(*ipp)))
return (retval);
retval += .001 * (*(*ipp)++ - 0x30);
if (vct_isdigit(*(*ipp)))
BAIL(err_fatnum);
return (retval);
}
/********************************************************************** /**********************************************************************
* Convert (all of!) a string to a floating point number, and if we can * Convert (all of!) a string to a floating point number, and if we can
* not, return NAN. * not, return NAN.
...@@ -175,7 +272,7 @@ VNUM_duration(const char *p) ...@@ -175,7 +272,7 @@ VNUM_duration(const char *p)
double double
VNUM_bytes_unit(double r, const char *b, const char *e, uintmax_t rel) VNUM_bytes_unit(double r, const char *b, const char *e, uintmax_t rel)
{ {
double sc = 1.0; double sc = 1.0, tmp;
if (e == NULL) if (e == NULL)
e = strchr(b, '\0'); e = strchr(b, '\0');
...@@ -196,6 +293,8 @@ VNUM_bytes_unit(double r, const char *b, const char *e, uintmax_t rel) ...@@ -196,6 +293,8 @@ VNUM_bytes_unit(double r, const char *b, const char *e, uintmax_t rel)
case 't': case 'T': sc = exp2(40); b++; break; case 't': case 'T': sc = exp2(40); b++; break;
case 'p': case 'P': sc = exp2(50); b++; break; case 'p': case 'P': sc = exp2(50); b++; break;
case 'b': case 'B': case 'b': case 'B':
if (modf(r, &tmp) != 0.0)
return (nan(""));
break; break;
default: default:
return (nan("")); return (nan(""));
...@@ -213,22 +312,26 @@ VNUM_bytes_unit(double r, const char *b, const char *e, uintmax_t rel) ...@@ -213,22 +312,26 @@ VNUM_bytes_unit(double r, const char *b, const char *e, uintmax_t rel)
const char * const char *
VNUM_2bytes(const char *p, uintmax_t *r, uintmax_t rel) VNUM_2bytes(const char *p, uintmax_t *r, uintmax_t rel)
{ {
double fval; double fval, tmp;
const char *end; const char *errtxt;
if (p == NULL || *p == '\0') if (p == NULL || *p == '\0')
return (err_miss_num); return (err_miss_num);
fval = VNUMpfx(p, &end); fval = SF_Parse_Number(&p, &errtxt);
if (isnan(fval)) if (errno)
return (err_invalid_num); return(errtxt);
if (fval < 0)
return(err_invalid_num);
if (end == NULL) { if (*p == '\0') {
if (modf(fval, &tmp) != 0.0)
return (err_invalid_num);
*r = (uintmax_t)fval; *r = (uintmax_t)fval;
return (NULL); return (NULL);
} }
fval = VNUM_bytes_unit(fval, end, NULL, rel); fval = VNUM_bytes_unit(fval, p, NULL, rel);
if (isnan(fval)) if (isnan(fval))
return (err_invalid_suff); return (err_invalid_suff);
*r = (uintmax_t)round(fval); *r = (uintmax_t)round(fval);
...@@ -250,20 +353,21 @@ static struct test_case { ...@@ -250,20 +353,21 @@ static struct test_case {
{ "1", (uintmax_t)0, (uintmax_t)1 }, { "1", (uintmax_t)0, (uintmax_t)1 },
{ "1B", (uintmax_t)0, (uintmax_t)1<<0 }, { "1B", (uintmax_t)0, (uintmax_t)1<<0 },
{ "1 B", (uintmax_t)0, (uintmax_t)1<<0 }, { "1 B", (uintmax_t)0, (uintmax_t)1<<0 },
{ "1.3B", (uintmax_t)0, (uintmax_t)1 }, { "1.3B", 0, 0, err_invalid_suff },
{ "1.7B", (uintmax_t)0, (uintmax_t)2 }, { "1.7B", 0, 0, err_invalid_suff },
{ "1024", (uintmax_t)0, (uintmax_t)1024 }, { "1024", (uintmax_t)0, (uintmax_t)1024 },
{ "1k", (uintmax_t)0, (uintmax_t)1<<10 }, { "1k", (uintmax_t)0, (uintmax_t)1<<10 },
{ "1kB", (uintmax_t)0, (uintmax_t)1<<10 }, { "1kB", (uintmax_t)0, (uintmax_t)1<<10 },
{ "0.75kB", (uintmax_t)0, (uintmax_t)768 },
{ "1.3kB", (uintmax_t)0, (uintmax_t)1331 }, { "1.3kB", (uintmax_t)0, (uintmax_t)1331 },
{ "1.7kB", (uintmax_t)0, (uintmax_t)1741 }, { "1.70kB", (uintmax_t)0, (uintmax_t)1741 },
{ "1048576", (uintmax_t)0, (uintmax_t)1048576 }, { "1048576", (uintmax_t)0, (uintmax_t)1048576 },
{ "1M", (uintmax_t)0, (uintmax_t)1<<20 }, { "1M", (uintmax_t)0, (uintmax_t)1<<20 },
{ "1MB", (uintmax_t)0, (uintmax_t)1<<20 }, { "1MB", (uintmax_t)0, (uintmax_t)1<<20 },
{ "1.3MB", (uintmax_t)0, (uintmax_t)1363149 }, { "1.3MB", (uintmax_t)0, (uintmax_t)1363149 },
{ "1.7MB", (uintmax_t)0, (uintmax_t)1782579 }, { "1.700MB", (uintmax_t)0, (uintmax_t)1782579 },
{ "1073741824", (uintmax_t)0, (uintmax_t)1073741824 }, { "1073741824", (uintmax_t)0, (uintmax_t)1073741824 },
{ "1G", (uintmax_t)0, (uintmax_t)1<<30 }, { "1G", (uintmax_t)0, (uintmax_t)1<<30 },
...@@ -277,24 +381,25 @@ static struct test_case { ...@@ -277,24 +381,25 @@ static struct test_case {
{ "1.3TB", (uintmax_t)0, (uintmax_t)1429365116109ULL }, { "1.3TB", (uintmax_t)0, (uintmax_t)1429365116109ULL },
{ "1.7\tTB", (uintmax_t)0, (uintmax_t)1869169767219ULL }, { "1.7\tTB", (uintmax_t)0, (uintmax_t)1869169767219ULL },
{ "1125899906842624", (uintmax_t)0, (uintmax_t)1125899906842624ULL}, { "999999999999999", (uintmax_t)0, (uintmax_t)999999999999999ULL},
{ "1125899906842624", 0, 0, err_fatnum },
{ "1P\t", (uintmax_t)0, (uintmax_t)1125899906842624ULL}, { "1P\t", (uintmax_t)0, (uintmax_t)1125899906842624ULL},
{ "1PB ", (uintmax_t)0, (uintmax_t)1125899906842624ULL}, { "1PB ", (uintmax_t)0, (uintmax_t)1125899906842624ULL},
{ "1.3 PB", (uintmax_t)0, (uintmax_t)1463669878895411ULL}, { "1.3 PB", (uintmax_t)0, (uintmax_t)1463669878895411ULL},
// highest integers not rounded for double conversion { "1.5%", (uintmax_t)1024, (uintmax_t)15 },
{ "9007199254740988", (uintmax_t)0, (uintmax_t)9007199254740988ULL}, { "1.501%", (uintmax_t)1024, (uintmax_t)15 },
{ "9007199254740989", (uintmax_t)0, (uintmax_t)9007199254740989ULL},
{ "9007199254740990", (uintmax_t)0, (uintmax_t)9007199254740990ULL},
{ "9007199254740991", (uintmax_t)0, (uintmax_t)9007199254740991ULL},
{ "1%", (uintmax_t)1024, (uintmax_t)10 },
{ "2%", (uintmax_t)1024, (uintmax_t)20 }, { "2%", (uintmax_t)1024, (uintmax_t)20 },
{ "3%", (uintmax_t)1024, (uintmax_t)31 }, { "3%", (uintmax_t)1024, (uintmax_t)31 },
/* Check the error checks */ /* Check the error checks */
{ "", 0, 0, err_miss_num }, { "", 0, 0, err_miss_num },
{ "m", 0, 0, err_invalid_num }, { "-1", 0, 0, err_invalid_num },
{ "1.3", 0, 0, err_invalid_num },
{ "1.5011%", 0, 0, err_fatnum },
{ "-", 0, 0, err_invalid_num },
{ "m", 0, 0, err_miss_num },
{ "4%", 0, 0, err_invalid_suff }, { "4%", 0, 0, err_invalid_suff },
{ "3*", 0, 0, err_invalid_suff }, { "3*", 0, 0, err_invalid_suff },
...@@ -340,6 +445,8 @@ main(int argc, char *argv[]) ...@@ -340,6 +445,8 @@ main(int argc, char *argv[])
(void)argc; (void)argc;
setbuf(stdout, NULL);
setbuf(stderr, NULL);
for (p = vec; *p != NULL; p++) { for (p = vec; *p != NULL; p++) {
e = *p; e = *p;
d1 = VNUM(e + 1); d1 = VNUM(e + 1);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment