[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