# Multiple hostname:port elements in a URL

**URL:** <https://forums.swift.org/t/multiple-hostname-port-elements-in-a-url/61022>\
**Category:** WebURL\
**Created:** [October 25, 2022, 6:58pm UTC](https://forums.swift.org/t/multiple-hostname-port-elements-in-a-url/61022 "2022-10-25T18:58:49Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![taylorswift](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/taylorswift/32/43413_2.png) [@taylorswift](https://forums.swift.org/u/taylorswift)\
**Post date:** [October 25, 2022, 6:58pm UTC](https://forums.swift.org/t/multiple-hostname-port-elements-in-a-url/61022/1 "2022-10-25T18:58:49Z")

</div>

i’m trying to parse a mongodb connection string, which has the [form](https://www.mongodb.com/docs/manual/reference/connection-string/):

```nohighlight
mongodb://[username:password@]host1[:port1][,...hostN[:portN]][/[defaultauthdb][?options]]

```

but it looks like WebURL only supports a single [`hostname`](https://karwa.github.io/swift-url/main/documentation/weburl/weburl/hostname) and port pair. is there a way to parse multiple host-port pairs with WebURL?

---

<div class="post-metadata">

**Author:** ![MPLewis](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/mplewis/32/40019_2.png) [@MPLewis](https://forums.swift.org/u/MPLewis)\
**Post date:** [October 25, 2022, 8:09pm UTC](https://forums.swift.org/t/multiple-hostname-port-elements-in-a-url/61022/2 "2022-10-25T20:09:47Z")

</div>

The URL specification indicates that:

- [A valid URL consists of at most a single host](https://url.spec.whatwg.org/#url-representation): `A URL’s host is null or a host`
- [A host may not contain `@` or `:`](https://url.spec.whatwg.org/#host-miscellaneous): `A forbidden host code point is ... U+003A (:), ... U+0040 (@)`
- [A port may only be numeric](https://url.spec.whatwg.org/#url-representation): `A URL’s port is either null or a 16-bit unsigned integer that identifies a networking port.`

The MongoDB connection string does not meet these requirements and you'll probably have to implement this parsing yourself, as anything that wants to enforce standards-compliant URL parsing will not be able to support those strings.

---

<div class="post-metadata">

**Author:** ![Karl](https://avatars.discourse-cdn.com/v4/letter/k/34f0e0/32.png) [@Karl](https://forums.swift.org/u/Karl)\
**Post date:** [October 26, 2022, 10:47am UTC](https://forums.swift.org/t/multiple-hostname-port-elements-in-a-url/61022/3 "2022-10-26T10:47:43Z")

</div>

Yeah the MongoDB connection string isn't a standards-compliant URL.

While it is true that the generic syntax only allows for a single host-and-port combo, you can go beyond the generic syntax and add substructure to any component, including the host. Because `mongodb:` is not a [special scheme](https://url.spec.whatwg.org/#special-scheme), its hostname is typically considered _opaque_ (application-defined), so it is possible to encode a list of hosts in that opaque string:

```swift
We want the whole list to be considered the "host":

monogodb://foo:42,bar:64/...
host ^^^^^^^^^^^^^ = "foo:42,bar:64"

```

Unfortunately, `:` is a reserved character, so when it is used unescaped like this, it is interpreted as a host/port delimiter within the single host-and-port combo of the generic syntax.

There are two ways around this:

1. Escape the `:`, making it clear that it is being used as a literal colon, not as a URL delimiter.

2. Use a different delimiter. For example, `$`, `*`, and `~` are all allowed, and (IMO) are unlikely to appear in the hostnames themselves.

Of course, you would need the client which ultimately processes this URL and connects to the MongoDB server to understand this - it would need to either unescape the host-port pairs when parsing the host (maybe it already does?), or accept the alternate delimiter.

---

<div class="post-metadata">

**Author:** ![taylorswift](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/taylorswift/32/43413_2.png) [@taylorswift](https://forums.swift.org/u/taylorswift)\
**Post date:** [October 26, 2022, 5:44pm UTC](https://forums.swift.org/t/multiple-hostname-port-elements-in-a-url/61022/4 "2022-10-26T17:44:45Z")

</div>

> [@Karl](#):
>
> Unfortunately, `:` is a reserved character, so when it is used unescaped like this, it is interpreted as a host/port delimiter within the single host-and-port combo of the generic syntax.

damn. is it not valid even if we consider it an opaque URI?

> [@Karl](#):
>
> There are two ways around this:

unfortunately, i cannot change the format of the connection string, because it is defined by the mongodb connection URL specification.

is there truly no way i can leverage WebURL’s URL parsing capabilities to parse these URLs?

---

<div class="post-metadata">

**Author:** ![Karl](https://avatars.discourse-cdn.com/v4/letter/k/34f0e0/32.png) [@Karl](https://forums.swift.org/u/Karl)\
**Post date:** [October 27, 2022, 11:07am UTC](https://forums.swift.org/t/multiple-hostname-port-elements-in-a-url/61022/5 "2022-10-27T11:07:44Z")

</div>

> [@taylorswift](#):
>
> is there truly no way i can leverage WebURL’s URL parsing capabilities to parse these URLs?

Well, there is [`mongodb-js/mongodb-connection-string-url`](https://github.com/mongodb-js/mongodb-connection-string-url), which is a Javascript library. They use a regex to extract the first few components, then rewrite the URL string to use a dummy hostname. The rewritten string is parsed as a WHATWG URL, and the original hostname is stored alongside.

Since WebURL conforms to the same WHATWG URL standard, you should be able to create a wrapper which does the same, and get the same result.

I know that is perhaps not the cleanest solution, but that package is used by the official MongoDB driver for NodeJS, and npm reports 1.6 million downloads/week, so it should work well.

Unfortunately, this is one of the drawbacks of custom identifiers (including incompatible forks) - they are incompatible with existing tooling.
