Commit f55922e8b2 for openssl.org

commit f55922e8b25e663009fafb120f93824da0627bbf
Author: Dr. David von Oheimb <dev@ddvo.net>
Date:   Thu Jul 31 17:13:58 2025 +0200

    http_lib.c: fix parsing 'scheme' part in OSSL_parse_url()

    Reviewed-by: Neil Horman <nhorman@openssl.org>
    Reviewed-by: Eugene Syromiatnikov <esyr@openssl.org>
    MergeDate: Wed Jun 10 06:26:59 2026
    (Merged from https://github.com/openssl/openssl/pull/27357)

diff --git a/crypto/http/http_lib.c b/crypto/http/http_lib.c
index 122dcfb107..ab3142a32d 100644
--- a/crypto/http/http_lib.c
+++ b/crypto/http/http_lib.c
@@ -21,6 +21,7 @@
 #define NI_MAXHOST 255
 #endif
 #include "crypto/ctype.h" /* for ossl_isspace() */
+#define OSSL_URL_SCHEME_SUFFIX "://"

 static void init_pstring(char **pstr)
 {
@@ -79,16 +80,20 @@ int OSSL_parse_url(const char *url, char **pscheme, char **puser, char **phost,
         return 0;
     }

-    /* check for optional prefix "<scheme>://" */
-    scheme = scheme_end = url;
-    p = strstr(url, "://");
-    if (p == NULL) {
-        p = url;
-    } else {
-        scheme_end = p;
-        if (scheme_end == scheme)
-            goto parse_err;
-        p += strlen("://");
+    /* check for optional prefix "<scheme>://" as per RFC 3986 */
+    scheme = scheme_end = p = url;
+    if (ossl_isalpha(*p)) {
+        while (*p != '\0'
+            && (ossl_isalpha(*p)
+                || ossl_isdigit(*p)
+                || strchr("+-.", *p) != NULL))
+            p++;
+        if (HAS_PREFIX(p, OSSL_URL_SCHEME_SUFFIX)) {
+            scheme_end = p;
+            p += sizeof(OSSL_URL_SCHEME_SUFFIX) - 1;
+        } else {
+            p = url;
+        }
     }

     /* parse optional "userinfo@" */
diff --git a/test/http_test.c b/test/http_test.c
index 2776a6f7a1..6879f8b664 100644
--- a/test/http_test.c
+++ b/test/http_test.c
@@ -287,8 +287,8 @@ err:
     return res;
 }

-static int test_http_url_ok(const char *url, int exp_ssl, const char *exp_host,
-    const char *exp_port, const char *exp_path)
+static int test_http_url_frag_ok(const char *url, int exp_ssl, const char *exp_host,
+    const char *exp_port, const char *exp_path, const char *exp_frag)
 {
     char *user, *host, *port, *path, *query, *frag;
     int exp_num, num, ssl;
@@ -305,8 +305,8 @@ static int test_http_url_ok(const char *url, int exp_ssl, const char *exp_host,
         && TEST_int_eq(ssl, exp_ssl);
     if (res && *user != '\0')
         res = TEST_str_eq(user, "user:pass");
-    if (res && *frag != '\0')
-        res = TEST_str_eq(frag, "fr");
+    if (res)
+        res = TEST_str_eq(frag, exp_frag);
     if (res && *query != '\0')
         res = TEST_str_eq(query, "q");
     OPENSSL_free(user);
@@ -318,6 +318,12 @@ static int test_http_url_ok(const char *url, int exp_ssl, const char *exp_host,
     return res;
 }

+static int test_http_url_ok(const char *url, int exp_ssl, const char *exp_host,
+    const char *exp_port, const char *exp_path)
+{
+    return test_http_url_frag_ok(url, exp_ssl, exp_host, exp_port, exp_path, "");
+}
+
 static int test_http_url_path_query_ok(const char *url, const char *exp_path_qu)
 {
     char *host, *path;
@@ -349,6 +355,11 @@ static int test_http_url_dns(void)
     return test_http_url_ok("host:65535/path", 0, "host", "65535", "/path");
 }

+static int test_http_url_ip(void)
+{
+    return test_http_url_ok("1.2.3.4:5678//blahblablah", 0, "1.2.3.4", "5678", "//blahblablah");
+}
+
 static int test_http_url_timestamp(void)
 {
     return test_http_url_ok("host/p/2017-01-03T00:00:00", 0, "host", "80",
@@ -368,7 +379,9 @@ static int test_http_url_path_query(void)

 static int test_http_url_userinfo_query_fragment(void)
 {
-    return test_http_url_ok("user:pass@host/p?q#fr", 0, "host", "80", "/p");
+    return test_http_url_frag_ok("user:pass@host/p?q#fr", 0, "host", "80", "/p", "fr")
+        && test_http_url_frag_ok("host.example.org/some/path#://not-a-scheme/not.a.host:404", 0,
+            "host.example.org", "80", "/some/path", "://not-a-scheme/not.a.host:404");
 }

 static int test_http_url_at_sign_outside_authority(void)
@@ -652,6 +665,7 @@ int setup_tests(void)
         return 0;

     ADD_TEST(test_http_url_dns);
+    ADD_TEST(test_http_url_ip);
     ADD_TEST(test_http_url_timestamp);
     ADD_TEST(test_http_url_path_query);
     ADD_TEST(test_http_url_userinfo_query_fragment);