[master] b908baebc RFC8941 renovation of BYTES
Poul-Henning Kamp
phk at FreeBSD.org
Fri May 21 10:42:05 UTC 2021
commit b908baebca31d422522cbd592e4ea5f7dc1cdbe4
Author: Poul-Henning Kamp <phk at FreeBSD.org>
Date: Fri May 21 10:41:41 2021 +0000
RFC8941 renovation of BYTES
diff --git a/bin/varnishtest/tests/v00033.vtc b/bin/varnishtest/tests/v00033.vtc
index 5d9b1e6b4..c5884fd9b 100644
--- a/bin/varnishtest/tests/v00033.vtc
+++ b/bin/varnishtest/tests/v00033.vtc
@@ -43,7 +43,7 @@ varnish v1 -syntax 4.0 -errvcl {Expected BYTES unit (B, KB, MB...) got '"X"'} {
}
}
}
-varnish v1 -syntax 4.0 -errvcl {Unknown BYTES unit 'X'} {
+varnish v1 -syntax 4.0 -errvcl {Unknown BYTES unit} {
sub vcl_recv {
if (storage.Transient.free_space > 4 X) {
}
diff --git a/include/vnum.h b/include/vnum.h
index 181ecee7c..859d8cbb0 100644
--- a/include/vnum.h
+++ b/include/vnum.h
@@ -35,7 +35,8 @@ double VNUM(const char *p);
double VNUMpfx(const char *p, const char **e);
vtim_dur VNUM_duration_unit(vtim_dur r, const char *b, const char *e);
vtim_dur VNUM_duration(const char *p);
-double VNUM_bytes_unit(double r, const char *b, const char *e, uintmax_t rel);
+int64_t VNUM_bytes_unit(double r, const char *b, const char *e, uintmax_t rel,
+ const char **errtxt);
const char *VNUM_2bytes(const char *p, uintmax_t *r, uintmax_t rel);
int64_t SF_Parse_Integer(const char **ipp, const char **errtxt);
@@ -44,6 +45,3 @@ double SF_Parse_Number(const char **ipp, const char **errtxt);
#define VNUM_LEGAL_DURATION \
"Legal duration units are 'ms', 's', 'm', 'h', 'd', 'w' and 'y'"
-
-#define VNUM_LEGAL_BYTES \
- "Legal byte units are 'B', 'KB', 'MB', 'GB', 'TB' and 'PB'"
diff --git a/lib/libvarnish/vnum.c b/lib/libvarnish/vnum.c
index 7397eea41..7f44c6228 100644
--- a/lib/libvarnish/vnum.c
+++ b/lib/libvarnish/vnum.c
@@ -47,7 +47,9 @@
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_suff[] = "Invalid suffix";
+static const char err_unknown_bytes[] =
+ "Unknown BYTES unit of measurement ([KMGTP][B])";
+static const char err_fractional_bytes[] = "Fractional BYTES not allowed";
#define BAIL(txt) \
do { \
@@ -265,18 +267,27 @@ VNUM_duration(const char *p)
/**********************************************************************/
-double
-VNUM_bytes_unit(double r, const char *b, const char *e, uintmax_t rel)
+int64_t
+VNUM_bytes_unit(double r, const char *b, const char *e, uintmax_t rel,
+ const char **errtxt)
{
double sc = 1.0, tmp;
+ AN(b);
+ AN(errtxt);
+ errno = 0;
if (e == NULL)
e = strchr(b, '\0');
while (b < e && vct_issp(*b))
b++;
- if (b == e)
- return (nan(""));
+ if (b == e) {
+ if (modf(r, &tmp) != 0.0) {
+ *errtxt = err_fractional_bytes;
+ errno = EINVAL;
+ }
+ return ((int64_t)trunc(sc * r));
+ }
if (rel != 0 && *b == '%') {
r *= rel * 0.01;
@@ -289,26 +300,34 @@ VNUM_bytes_unit(double r, const char *b, const char *e, uintmax_t rel)
case 't': case 'T': sc = exp2(40); b++; break;
case 'p': case 'P': sc = exp2(50); b++; break;
case 'b': case 'B':
- if (modf(r, &tmp) != 0.0)
- return (nan(""));
+ if (modf(r, &tmp) != 0.0) {
+ *errtxt = err_fractional_bytes;
+ errno = EINVAL;
+ return (0);
+ }
break;
default:
- return (nan(""));
+ *errtxt = err_unknown_bytes;
+ errno = EINVAL;
+ return (0);
}
if (b < e && (*b == 'b' || *b == 'B'))
b++;
}
while (b < e && vct_issp(*b))
b++;
- if (b < e)
- return (nan(""));
- return (sc * r);
+ if (b < e) {
+ *errtxt = err_unknown_bytes;
+ errno = EINVAL;
+ return (0);
+ }
+ return ((int64_t)trunc(sc * r));
}
const char *
VNUM_2bytes(const char *p, uintmax_t *r, uintmax_t rel)
{
- double fval, tmp;
+ double fval;
const char *errtxt;
if (p == NULL || *p == '\0')
@@ -320,16 +339,9 @@ VNUM_2bytes(const char *p, uintmax_t *r, uintmax_t rel)
if (fval < 0)
return(err_invalid_num);
- if (*p == '\0') {
- if (modf(fval, &tmp) != 0.0)
- return (err_invalid_num);
- *r = (uintmax_t)fval;
- return (NULL);
- }
-
- fval = VNUM_bytes_unit(fval, p, NULL, rel);
- if (isnan(fval))
- return (err_invalid_suff);
+ fval = VNUM_bytes_unit(fval, p, NULL, rel, &errtxt);
+ if (errno)
+ return (errtxt);
*r = (uintmax_t)round(fval);
return (NULL);
}
@@ -349,32 +361,32 @@ static struct test_case {
{ "1", (uintmax_t)0, (uintmax_t)1 },
{ "1B", (uintmax_t)0, (uintmax_t)1<<0 },
{ "1 B", (uintmax_t)0, (uintmax_t)1<<0 },
- { "1.3B", 0, 0, err_invalid_suff },
- { "1.7B", 0, 0, err_invalid_suff },
+ { "1.3B", 0, 0, err_fractional_bytes },
+ { "1.7B", 0, 0, err_fractional_bytes },
{ "1024", (uintmax_t)0, (uintmax_t)1024 },
{ "1k", (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.70kB", (uintmax_t)0, (uintmax_t)1741 },
+ { "1.70kB", (uintmax_t)0, (uintmax_t)1740 },
{ "1048576", (uintmax_t)0, (uintmax_t)1048576 },
{ "1M", (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)1363148 },
{ "1.700MB", (uintmax_t)0, (uintmax_t)1782579 },
{ "1073741824", (uintmax_t)0, (uintmax_t)1073741824 },
{ "1G", (uintmax_t)0, (uintmax_t)1<<30 },
{ "1GB", (uintmax_t)0, (uintmax_t)1<<30 },
{ "1.3GB", (uintmax_t)0, (uintmax_t)1395864371 },
- { "1.7GB", (uintmax_t)0, (uintmax_t)1825361101 },
+ { "1.7GB", (uintmax_t)0, (uintmax_t)1825361100 },
{ "1099511627776", (uintmax_t)0, (uintmax_t)1099511627776ULL },
{ "1T", (uintmax_t)0, (uintmax_t)1<<40 },
{ "1TB", (uintmax_t)0, (uintmax_t)1<<40 },
- { "1.3TB", (uintmax_t)0, (uintmax_t)1429365116109ULL },
+ { "1.3TB", (uintmax_t)0, (uintmax_t)1429365116108ULL },
{ "1.7\tTB", (uintmax_t)0, (uintmax_t)1869169767219ULL },
{ "999999999999999", (uintmax_t)0, (uintmax_t)999999999999999ULL},
@@ -387,17 +399,17 @@ static struct test_case {
{ "1.5%", (uintmax_t)1024, (uintmax_t)15 },
{ "1.501%", (uintmax_t)1024, (uintmax_t)15 },
{ "2%", (uintmax_t)1024, (uintmax_t)20 },
- { "3%", (uintmax_t)1024, (uintmax_t)31 },
+ { "3%", (uintmax_t)1024, (uintmax_t)30 },
/* Check the error checks */
{ "", 0, 0, err_miss_num },
{ "-1", 0, 0, err_invalid_num },
- { "1.3", 0, 0, err_invalid_num },
+ { "1.3", 0, 0, err_fractional_bytes},
{ "1.5011%", 0, 0, err_fatnum },
{ "-", 0, 0, err_invalid_num },
{ "m", 0, 0, err_miss_num },
- { "4%", 0, 0, err_invalid_suff },
- { "3*", 0, 0, err_invalid_suff },
+ { "4%", 0, 0, err_unknown_bytes },
+ { "3*", 0, 0, err_unknown_bytes },
/* TODO: add more */
diff --git a/lib/libvcc/vcc_utils.c b/lib/libvcc/vcc_utils.c
index 51ed651c7..47f6ab00c 100644
--- a/lib/libvcc/vcc_utils.c
+++ b/lib/libvcc/vcc_utils.c
@@ -347,10 +347,22 @@ vcc_Duration(struct vcc *tl, double *d)
void
vcc_ByteVal(struct vcc *tl, VCL_INT *d)
{
- double v, sc;
+ double v;
+ VCL_INT retval;
+ const char *p, *errtxt;
- v = vcc_DoubleVal(tl);
- ERRCHK(tl);
+ if (tl->t->tok != CNUM && tl->t->tok != FNUM) {
+ Expect(tl, CNUM);
+ return;
+ }
+ p = tl->t->b;
+ v = SF_Parse_Number(&p, &errtxt);
+ if (errno) {
+ VSB_printf(tl->sb, "Bad BYTES: %s\n", errtxt);
+ vcc_ErrWhere(tl, tl->t);
+ return;
+ }
+ vcc_NextToken(tl);
if (tl->t->tok != ID) {
VSB_cat(tl->sb, "Expected BYTES unit (B, KB, MB...) got ");
vcc_ErrToken(tl, tl->t);
@@ -358,16 +370,15 @@ vcc_ByteVal(struct vcc *tl, VCL_INT *d)
vcc_ErrWhere(tl, tl->t);
return;
}
- sc = VNUM_bytes_unit(1.0, tl->t->b, tl->t->e, 0);
- if (isnan(sc)) {
- VSB_cat(tl->sb, "Unknown BYTES unit ");
+ retval = VNUM_bytes_unit(v, tl->t->b, tl->t->e, 0, &errtxt);
+ if (errno) {
+ VSB_cat(tl->sb, errtxt);
vcc_ErrToken(tl, tl->t);
- VSB_printf(tl->sb, "\n%s\n", VNUM_LEGAL_BYTES);
vcc_ErrWhere(tl, tl->t);
return;
}
vcc_NextToken(tl);
- *d = (VCL_INT)round((v * sc));
+ *d = retval;
}
/*--------------------------------------------------------------------*/
diff --git a/vmod/vmod_std_conversions.c b/vmod/vmod_std_conversions.c
index 1a4e9b3dc..ab7f61cb4 100644
--- a/vmod/vmod_std_conversions.c
+++ b/vmod/vmod_std_conversions.c
@@ -113,6 +113,7 @@ vmod_bytes(VRT_CTX, struct VARGS(bytes) *a)
uintmax_t r;
VCL_REAL rr;
int nargs;
+ const char *errtxt;
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
@@ -121,10 +122,11 @@ vmod_bytes(VRT_CTX, struct VARGS(bytes) *a)
if (!onearg(ctx, "bytes", nargs))
return (0);
- if (a->valid_s &&
- VNUM_2bytes(a->s, &r, 0) == NULL &&
- r <= VCL_BYTES_MAX)
- return ((VCL_BYTES)r);
+ if (a->valid_s) {
+ errtxt = VNUM_2bytes(a->s, &r, 0);
+ if (errtxt == NULL && r <= VCL_BYTES_MAX)
+ return ((VCL_BYTES)r);
+ }
if (a->valid_real && !isnan(a->real) && a->real >= 0) {
rr = trunc(a->real);
More information about the varnish-commit
mailing list