Skip to content

non-HTTP URLs with empty authorities are incorrectly parsed #22279

Description

@llimllib

I did this

Curl parses <scheme>:///path not as an empty authority section followed by a path, but as if the path were an authority.

My understanding (see below for motivation) is that this is correct in the case of the "special schemes" but not for other schemes.

Here's a repro in C, please forgive the machine-written code; I did edit it but I'm not much of a C writer. (Full bot disclaimer, this issue was discovered by me poking at trurl following discussions about the at protocol, not by a robot, but I did use the robot to help me in my investigation):

#include <curl/curl.h>
#include <stdio.h>

static void show(const char *url, unsigned int flags) {
  CURLU *u = curl_url();
  char *scheme = NULL, *host = NULL, *port = NULL, *path = NULL;
  CURLUcode rc;

  printf("== %-40s (flags=0x%x)\n", url, flags);

  rc = curl_url_set(u, CURLUPART_URL, url, flags);
  if (rc) {
    printf("   curl_url_set rc=%d (%s)\n", rc, curl_url_strerror(rc));
    curl_url_cleanup(u);
    printf("\n");
    return;
  }

  curl_url_get(u, CURLUPART_SCHEME, &scheme, 0);
  curl_url_get(u, CURLUPART_HOST, &host, CURLU_GET_EMPTY);
  curl_url_get(u, CURLUPART_PORT, &port, 0);
  curl_url_get(u, CURLUPART_PATH, &path, 0);

  printf("   scheme=%s host=\"%s\" port=%s path=%s\n",
         scheme ? scheme : "(null)", host ? host : "(null)",
         port ? port : "(null)", path ? path : "(null)");

  curl_free(scheme);
  curl_free(host);
  curl_free(port);
  curl_free(path);
  curl_url_cleanup(u);
  printf("\n");
}

int main(void) {
  /* unknown scheme, trurl-style flags */
  unsigned int f = CURLU_NON_SUPPORT_SCHEME;

  printf("--- unknown scheme path is read as authority ---\n");
  show("at:///foo", f);
  // CURLU_NO_AUTHORITY doesn't change anything here
  show("at:///foo", f | CURLU_NO_AUTHORITY);
  show(
      "at:///did:plc:vwzwgnygau7ed7b7wt5ux7y2/app.bsky.feed.post/3k5nobkf2w72g",
      f);

  printf("--- HTTP parses the path as an authority ---\n");
  show("http:///foo.com/path", 0);

  return 0;
}

I expected the following

I believe that per RFC 3986, the authority section for at:///path ought properly to be considered empty, and path to be the path.

  • Firefox and the whatwg url parser tool both parse https:///foo as a hostname foo, which matches curl's behavior
  • Firefox and the whatwg parser both parse at:///foo as an empty hostname followed by the path /foo
    • I think this is because the scheme is none of the above, so it does not enter "special authority slashes state"

So my expectation is the following:

  • If the scheme of a URL of the form scheme:///foo is any of {ftp, file, http, https, ws, and wss}
    • curl already does the right thing, parsing foo as a hostname
  • Else
    • curl ought to parse the URL with an empty hostname and a path of /foo

Why does this matter?

The at protocol accidentally specified invalid authority names, and they're considering using an empty authority section in their at URLs to remediate the situation.

That's how I noticed this issue - I wondered how trurl would parse the proposed URLs with an empty authority, and found that it parsed them incorrectly; cf the issue I filed there

It seems to be a minor edge case, but one that would be worth fixing. I'd be happy to do the work to submit a PR if you thought it was worth fixing.

curl/libcurl version

verified on curl master branch, revision 6841d59af6

operating system

Mac OS 26.5.1

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions