[master] 0abf0df57 RFC8941 parsing of VCL_BYTES.

Poul-Henning Kamp phk at FreeBSD.org
Thu May 20 07:57:05 UTC 2021


commit 0abf0df57f4ac5363685a7fe1e6275b3302aa0f0
Author: Poul-Henning Kamp <phk at FreeBSD.org>
Date:   Thu May 20 07:55:45 2021 +0000

    RFC8941 parsing of VCL_BYTES.

diff --git a/bin/varnishtest/tests/r03308.vtc b/bin/varnishtest/tests/r03308.vtc
index 144dcf8e9..115581be7 100644
--- a/bin/varnishtest/tests/r03308.vtc
+++ b/bin/varnishtest/tests/r03308.vtc
@@ -11,7 +11,10 @@ varnish v1 -vcl+backend {
 	import std;
 
 	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
 
diff --git a/include/vnum.h b/include/vnum.h
index 93f797e72..09523f6f3 100644
--- a/include/vnum.h
+++ b/include/vnum.h
@@ -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);
 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 \
 	"Legal duration units are 'ms', 's', 'm', 'h', 'd', 'w' and 'y'"
 
diff --git a/lib/libvarnish/vnum.c b/lib/libvarnish/vnum.c
index 84b2acff8..207a16297 100644
--- a/lib/libvarnish/vnum.c
+++ b/lib/libvarnish/vnum.c
@@ -45,9 +45,106 @@
 #include "vct.h"
 
 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";
 
+#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
  * not, return NAN.
@@ -175,7 +272,7 @@ VNUM_duration(const char *p)
 double
 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)
 		e = strchr(b, '\0');
@@ -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 'p': case 'P': sc = exp2(50); b++; break;
 		case 'b': case 'B':
+			if (modf(r, &tmp) != 0.0)
+				return (nan(""));
 			break;
 		default:
 			return (nan(""));
@@ -213,22 +312,26 @@ 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)
 {
-	double fval;
-	const char *end;
+	double fval, tmp;
+	const char *errtxt;
 
 	if (p == NULL || *p == '\0')
 		return (err_miss_num);
 
-	fval = VNUMpfx(p, &end);
-	if (isnan(fval))
-		return (err_invalid_num);
+	fval = SF_Parse_Number(&p, &errtxt);
+	if (errno)
+		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;
 		return (NULL);
 	}
 
-	fval = VNUM_bytes_unit(fval, end, NULL, rel);
+	fval = VNUM_bytes_unit(fval, p, NULL, rel);
 	if (isnan(fval))
 		return (err_invalid_suff);
 	*r = (uintmax_t)round(fval);
@@ -250,20 +353,21 @@ 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",		(uintmax_t)0,	(uintmax_t)1 },
-	{ "1.7B",		(uintmax_t)0,	(uintmax_t)2 },
+	{ "1.3B",		0,	0,	err_invalid_suff },
+	{ "1.7B",		0,	0,	err_invalid_suff },
 
 	{ "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.7kB",		(uintmax_t)0,	(uintmax_t)1741 },
+	{ "1.70kB",		(uintmax_t)0,	(uintmax_t)1741 },
 
 	{ "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.7MB",		(uintmax_t)0,	(uintmax_t)1782579 },
+	{ "1.700MB",		(uintmax_t)0,	(uintmax_t)1782579 },
 
 	{ "1073741824",		(uintmax_t)0,	(uintmax_t)1073741824 },
 	{ "1G",			(uintmax_t)0,	(uintmax_t)1<<30 },
@@ -277,24 +381,25 @@ static struct test_case {
 	{ "1.3TB",		(uintmax_t)0,	(uintmax_t)1429365116109ULL },
 	{ "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},
 	{ "1PB ",		(uintmax_t)0,	(uintmax_t)1125899906842624ULL},
 	{ "1.3 PB",		(uintmax_t)0,	(uintmax_t)1463669878895411ULL},
 
-	// highest integers not rounded for double conversion
-	{ "9007199254740988",	(uintmax_t)0,	(uintmax_t)9007199254740988ULL},
-	{ "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 },
+	{ "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 },
 
 	/* Check the error checks */
 	{ "",			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 },
 	{ "3*",			0,	0,	err_invalid_suff },
 
@@ -340,6 +445,8 @@ main(int argc, char *argv[])
 
 	(void)argc;
 
+	setbuf(stdout, NULL);
+	setbuf(stderr, NULL);
 	for (p = vec; *p != NULL; p++) {
 		e = *p;
 		d1 = VNUM(e + 1);


More information about the varnish-commit mailing list