Commit Diff


commit - 709f4c94471b5b910557420ab9bddb677c229100
commit + 8404ec301fed4f0bb5a3d1e7b5a2e184a93cc4e5
blob - d4ae6dbc8b4d2bcf6a5ef85a61e58f5aea7f27a0
blob + ad55d54f5df1052a74d68b89d92e5116af8eea50
--- ChangeLog
+++ ChangeLog
@@ -1,3 +1,7 @@
+2021-02-05  Omar Polo  <op@omarpolo.com>
+
+	* iri.c (parse_query): don't %-decode the query part.  This affects the value of QUERY_STRING for CGI scripts too, since that must be %-encoded and we're currently shipping it decoded.
+
 2021-02-04  Omar Polo  <op@omarpolo.com>
 
 	* gmid.c (main): reload configuration on SIGHUP, without disconnecting the clients
blob - efdeb11b936ab9afd973768afc980c2885d14288
blob + 8501d9ad09f196c7a2c167b718da53835856ac88
--- iri.c
+++ iri.c
@@ -43,6 +43,36 @@ sub_delimiters(int p)
 		|| p == ','
 		|| p == ';'
 		|| p == '=';
+}
+
+static int
+valid_pct_enc_string(char *s)
+{
+	if (*s != '%')
+		return 1;
+
+	if (!isxdigit(s[1]) || !isxdigit(s[2]))
+		return 0;
+
+	if (s[1] == '0' && s[2] == '0')
+		return 0;
+
+	return 1;
+}
+
+static int
+valid_pct_encoded(struct parser *p)
+{
+	if (p->iri[0] != '%')
+		return 0;
+
+	if (!valid_pct_enc_string(p->iri)) {
+		p->err = "illegal percent-encoding";
+		return 0;
+	}
+
+	p->iri += 2;
+	return 1;
 }
 
 static int
@@ -51,7 +81,7 @@ parse_pct_encoded(struct parser *p)
 	if (p->iri[0] != '%')
 		return 0;
 
-	if (!isxdigit(p->iri[1]) || !isxdigit(p->iri[2])) {
+	if (!valid_pct_enc_string(p->iri)) {
 		p->err = "illegal percent-encoding";
 		return 0;
 	}
@@ -259,7 +289,7 @@ parse_query(struct parser *p)
 	    || sub_delimiters(*p->iri)
 	    || *p->iri == '/'
 	    || *p->iri == '?'
-	    || parse_pct_encoded(p)
+	    || valid_pct_encoded(p)
 	    || valid_multibyte_utf8(p))
 		p->iri++;
 
blob - a662e79b16bb43d7de7d908265ec6ab5a51ccc4e
blob + ba5fe4bb6d0648f4f61ce8d155011ad27da9e6c9
--- regress/iri_test.c
+++ regress/iri_test.c
@@ -203,11 +203,11 @@ main(void)
 	TEST("foo://example.com/foo/?gne&foo",
 	    PASS,
 	    IRI("foo", "example.com", "", "foo/", "gne&foo", ""),
-	    "parse query strings");
-	TEST("foo://example.com/foo/?gne%2F",
-	    PASS,
-	    IRI("foo", "example.com", "", "foo/", "gne/", ""),
 	    "parse query strings");
+	/* TEST("foo://example.com/foo/?gne%2F", */
+	/*     PASS, */
+	/*     IRI("foo", "example.com", "", "foo/", "gne/", ""), */
+	/*     "parse query strings"); */
 
 	/* fragment */
 	TEST("foo://bar.co/#foo",