]> git.ipfire.org Git - thirdparty/curl.git/commitdiff
urlapi: use uppercase hex encoding
authorDaniel Stenberg <daniel@haxx.se>
Wed, 25 Jun 2025 06:14:58 +0000 (08:14 +0200)
committerDaniel Stenberg <daniel@haxx.se>
Wed, 25 Jun 2025 09:44:13 +0000 (11:44 +0200)
For consistency. RFC 3986 section 2.1 says:

  "URI producers and normalizers should use uppercase hexadecimal digits
  for all percent-encodings."

Reported-by: Jeroen Ooms
Fixes #17685
Closes #17739

lib/escape.c
lib/escape.h
lib/urlapi.c
lib/vtls/keylog.c
tests/data/test1138
tests/data/test472
tests/libtest/lib1560.c

index 3cd906dc6c2cfe5fcb990f6a32eeda076f13e8dc..a292ba3b6253beff4eb9e624e82642a81711f61c 100644 (file)
@@ -85,7 +85,7 @@ char *curl_easy_escape(CURL *data, const char *string,
     else {
       /* encode it */
       unsigned char out[3]={'%'};
-      Curl_hexbyte(&out[1], in, FALSE);
+      Curl_hexbyte(&out[1], in);
       if(curlx_dyn_addn(&d, out, 3))
         return NULL;
     }
@@ -212,7 +212,8 @@ void Curl_hexencode(const unsigned char *src, size_t len, /* input length */
   DEBUGASSERT(src && len && (olen >= 3));
   if(src && len && (olen >= 3)) {
     while(len-- && (olen >= 3)) {
-      Curl_hexbyte(out, *src, TRUE);
+      out[0] = Curl_ldigits[*src >> 4];
+      out[1] = Curl_ldigits[*src & 0x0F];
       ++src;
       out += 2;
       olen -= 2;
@@ -225,14 +226,11 @@ void Curl_hexencode(const unsigned char *src, size_t len, /* input length */
 
 /* Curl_hexbyte
  *
- * Output a single unsigned char as a two-digit hex number, lowercase or
- * uppercase
+ * Output a single unsigned char as a two-digit UPPERCASE hex number.
  */
 void Curl_hexbyte(unsigned char *dest, /* must fit two bytes */
-                  unsigned char val,
-                  bool lowercase)
+                  unsigned char val)
 {
-  const unsigned char *t = lowercase ? Curl_ldigits : Curl_udigits;
-  dest[0] = t[val >> 4];
-  dest[1] = t[val & 0x0F];
+  dest[0] = Curl_udigits[val >> 4];
+  dest[1] = Curl_udigits[val & 0x0F];
 }
index 1f2bac8fac2a40d060bbb545fa48378b5a90f286..a43fc38ed3212fcd5efaea3ac24449128d75f3e7 100644 (file)
@@ -42,7 +42,6 @@ void Curl_hexencode(const unsigned char *src, size_t len, /* input length */
                     unsigned char *out, size_t olen); /* output buffer size */
 
 void Curl_hexbyte(unsigned char *dest, /* must fit two bytes */
-                  unsigned char val,
-                  bool lowercase);
+                  unsigned char val);
 
 #endif /* HEADER_CURL_ESCAPE_H */
index 1a1700adb80809cbcbd362f14105614d2733c67b..87636941b730651eb01ba08800f0cca938d18029 100644 (file)
@@ -164,7 +164,7 @@ static CURLUcode urlencode_str(struct dynbuf *o, const char *url,
     }
     else if((*iptr < ' ') || (*iptr >= 0x7f)) {
       unsigned char out[3]={'%'};
-      Curl_hexbyte(&out[1], *iptr, TRUE);
+      Curl_hexbyte(&out[1], *iptr);
       result = curlx_dyn_addn(o, out, 3);
     }
     else {
@@ -1861,7 +1861,7 @@ CURLUcode curl_url_set(CURLU *u, CURLUPart what,
         }
         else {
           unsigned char out[3]={'%'};
-          Curl_hexbyte(&out[1], *i, TRUE);
+          Curl_hexbyte(&out[1], *i);
           result = curlx_dyn_addn(&enc, out, 3);
           if(result)
             return cc2cu(result);
index 8487d43e8c6b5facab07a52112b6c43ca979e21a..2fd25089d97b998f5034cf78b72f9ff2edab58ea 100644 (file)
@@ -134,14 +134,14 @@ Curl_tls_keylog_write(const char *label,
 
   /* Client Random */
   for(i = 0; i < CLIENT_RANDOM_SIZE; i++) {
-    Curl_hexbyte(&line[pos], client_random[i], FALSE);
+    Curl_hexbyte(&line[pos], client_random[i]);
     pos += 2;
   }
   line[pos++] = ' ';
 
   /* Secret */
   for(i = 0; i < secretlen; i++) {
-    Curl_hexbyte(&line[pos], secret[i], FALSE);
+    Curl_hexbyte(&line[pos], secret[i]);
     pos += 2;
   }
   line[pos++] = '\n';
index 1f125f5844627ab924d7d622615935dc232c366b..ec7048c4adaf1fea278f42bfa3fe34969b830d67 100644 (file)
@@ -62,7 +62,7 @@ Host: %HOSTIP:%HTTPPORT
 User-Agent: curl/%VERSION
 Accept: */*
 
-GET /we/are/all/moo.html/?name=%d8%a2%d8%ba%d8%a7%d8%b2-%d8%b3%d9%85-%d8%b2%d8%af%d8%a7%db%8c%db%8c-%d8%a7%d8%b2-%d8%a8%d8%a7%d8%b2%d8%a7%d8%b1-%d9%be%d9%88%d9%84&testcase=/%TESTNUMBER0002 HTTP/1.1
+GET /we/are/all/moo.html/?name=%D8%A2%D8%BA%D8%A7%D8%B2-%D8%B3%D9%85-%D8%B2%D8%AF%D8%A7%DB%8C%DB%8C-%D8%A7%D8%B2-%D8%A8%D8%A7%D8%B2%D8%A7%D8%B1-%D9%BE%D9%88%D9%84&testcase=/%TESTNUMBER0002 HTTP/1.1
 Host: %HOSTIP:%HTTPPORT
 User-Agent: curl/%VERSION
 Accept: */*
index 3b4cf74764e135d60bcecb87f35705241c289a99..d624760040d721714850051b2e2bc73f070be594 100644 (file)
@@ -48,9 +48,9 @@ aws-sigv4 with query
 # Verify data after the test has been "shot"
 <verify>
 <protocol crlf="yes">
-GET /472/a=%e3%81%82 HTTP/1.1
+GET /472/a=%E3%81%82 HTTP/1.1
 Host: fake.fake.fake:8000
-Authorization: AWS4-HMAC-SHA256 Credential=user/19700101/us-east-2/es/aws4_request, SignedHeaders=host;x-amz-date, Signature=d2f4797c813fc51d729ac555a23ac682be908fdbfae2042ba98d214c9298201b
+Authorization: AWS4-HMAC-SHA256 Credential=user/19700101/us-east-2/es/aws4_request, SignedHeaders=host;x-amz-date, Signature=b8783c8387a5249b084642126fe1f8e07e12a2847820fd5b6cd64b2047149da4
 X-Amz-Date: 19700101T000000Z
 User-Agent: curl/%VERSION
 Accept: */*
index fb8633058d2b0cf9d8b25baf2638d8616a1e8bc4..d1fc04359e35b186f24aa868664ca3ee648f6fd7 100644 (file)
@@ -242,14 +242,14 @@ static const struct testcase get_parts_list[] ={
   {"https://"
    "%e2%84%82%e1%b5%a4%e2%93%87%e2%84%92%e3%80%82%f0%9d%90%92%f0%9f%84%b4",
    "https | [11] | [12] | [13] | "
-   "%e2%84%82%e1%b5%a4%e2%93%87%e2%84%92%e3%80%82%f0%9d%90%92%f0%9f%84%b4 "
+   "%E2%84%82%E1%B5%A4%E2%93%87%E2%84%92%E3%80%82%F0%9D%90%92%F0%9F%84%B4 "
    "| [15] | / | [16] | [17]",
    0, CURLU_URLENCODE, CURLUE_OK},
   {"https://"
    "\xe2\x84\x82\xe1\xb5\xa4\xe2\x93\x87\xe2\x84\x92"
    "\xe3\x80\x82\xf0\x9d\x90\x92\xf0\x9f\x84\xb4",
    "https | [11] | [12] | [13] | "
-   "%e2%84%82%e1%b5%a4%e2%93%87%e2%84%92%e3%80%82%f0%9d%90%92%f0%9f%84%b4 "
+   "%E2%84%82%E1%B5%A4%E2%93%87%E2%84%92%E3%80%82%F0%9D%90%92%F0%9F%84%B4 "
    "| [15] | / | [16] | [17]",
    0, CURLU_URLENCODE, CURLUE_OK},
   {"https://user@example.net?he l lo",
@@ -651,7 +651,7 @@ static const struct urltestcase get_url_list[] = {
   {"http://example.com%2F127.0.0.1/", "", 0, 0, CURLUE_BAD_HOSTNAME},
   {"https://%41", "https://A/", 0, 0, CURLUE_OK},
   {"https://%20", "", 0, 0, CURLUE_BAD_HOSTNAME},
-  {"https://%41%0d", "", 0, 0, CURLUE_BAD_HOSTNAME},
+  {"https://%41%0D", "", 0, 0, CURLUE_BAD_HOSTNAME},
   {"https://%25", "", 0, 0, CURLUE_BAD_HOSTNAME},
   {"https://_%c0_", "https://_\xC0_/", 0, 0, CURLUE_OK},
   {"https://_%c0_", "https://_%C0_/", 0, CURLU_URLENCODE, CURLUE_OK},
@@ -913,11 +913,11 @@ static const struct setcase set_parts_list[] = {
    0, 0, CURLUE_OK, CURLUE_OK},
   {"https://example.com/",
    "path=one\ntwo,",
-   "https://example.com/one%0atwo",
+   "https://example.com/one%0Atwo",
    0, CURLU_URLENCODE, CURLUE_OK, CURLUE_OK},
   {"https://example.com/",
    "path=one\rtwo,",
-   "https://example.com/one%0dtwo",
+   "https://example.com/one%0Dtwo",
    0, CURLU_URLENCODE, CURLUE_OK, CURLUE_OK},
   {"https://example.com/",
    "host=%43url.se,",
@@ -1001,7 +1001,7 @@ static const struct setcase set_parts_list[] = {
 
   {"https://example.com/",
    "query=Al2cO3tDkcDZ3EWE5Lh+LX8TPHs,", /* contains '+' */
-   "https://example.com/?Al2cO3tDkcDZ3EWE5Lh%2bLX8TPHs",
+   "https://example.com/?Al2cO3tDkcDZ3EWE5Lh%2BLX8TPHs",
    CURLU_URLDECODE, /* decode on get */
    CURLU_URLENCODE, /* encode on set */
    CURLUE_OK, CURLUE_OK},
@@ -1063,7 +1063,7 @@ static const struct setcase set_parts_list[] = {
    0, 0, CURLUE_OK, CURLUE_OK},
   {NULL,
    "scheme=https,user=   @:,host=foobar,",
-   "https://%20%20%20%40%3a@foobar/",
+   "https://%20%20%20%40%3A@foobar/",
    0, CURLU_URLENCODE, CURLUE_OK, CURLUE_OK},
   /* Setting a host name with spaces is not OK: */
   {NULL,
@@ -1076,7 +1076,7 @@ static const struct setcase set_parts_list[] = {
    0, CURLU_URLENCODE, CURLUE_OK, CURLUE_OK},
   {NULL,
    "scheme=https,host=foobar,path=\xc3\xa4\xc3\xb6\xc3\xbc,",
-   "https://foobar/%c3%a4%c3%b6%c3%bc",
+   "https://foobar/%C3%A4%C3%B6%C3%BC",
    0, CURLU_URLENCODE, CURLUE_OK, CURLUE_OK},
   {"imap://user:secret;opt@host/",
    "options=updated,scheme=imaps,password=p4ssw0rd,",
@@ -1598,7 +1598,7 @@ static int get_parts(void)
 static const struct querycase append_list[] = {
   {"HTTP://test/?s", "name=joe\x02", "http://test/?s&name=joe%02",
    0, CURLU_URLENCODE, CURLUE_OK},
-  {"HTTP://test/?size=2#f", "name=joe=", "http://test/?size=2&name=joe%3d#f",
+  {"HTTP://test/?size=2#f", "name=joe=", "http://test/?size=2&name=joe%3D#f",
    0, CURLU_URLENCODE, CURLUE_OK},
   {"HTTP://test/?size=2#f", "name=joe doe",
    "http://test/?size=2&name=joe+doe#f",