Skip to content

Method to get port regardless of defaults #706

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
daxpedda opened this issue Apr 27, 2021 · 9 comments
Open

Method to get port regardless of defaults #706

daxpedda opened this issue Apr 27, 2021 · 9 comments

Comments

@daxpedda
Copy link

At the moment, when using the port method on an URL that uses a known scheme with none or the default port, port will return None.
port_or_known_default will always return the default port for known scheme's unless a non-default port is set in the URL.

Currently there is no way to determine if the input string contained a port or not, for applications which do not want to support any default ports, regardless of scheme's, this is a current limitation.

I propose adding a method port_int (like host_str, bikeshedding is welcome) that returns whatever port is set in the URL string, regardless of defaults.

@valenting
Copy link
Collaborator

valenting commented Apr 27, 2021

Currently there is no way to determine if the input string contained a port or not

So, the parsing algorithm removes the port if it's equal to the default.
Parsing http://example.com:80/ will be normalized as http://example.com/
Do you really need to know if the original input contained a port? Or what you really want to know is if there a non-default port set? In which case that would be equal to url.port() != None || url.port != url.port_or_known_default()

Could you explain the need for such an interface?

@daxpedda
Copy link
Author

daxpedda commented Apr 27, 2021

In my use case I'm building a library enabling a QUIC powered custom protocol implementation.

The issue is that I don't want to handle standard protocols, the user has to be forced to supply a port, letting the user rely on default protocol ports is confusing on the input level and pretends like the library is protocol-aware, which it isn't.

As an alternative I might want to disable any standard protocols the user might use, but QUIC is compatible with HTTP/3 in a way, and it would require me to filter protocols, which again, I don't want to do because this library shouldn't be protocol-aware.

I know this is pretty niche.

@valenting
Copy link
Collaborator

Could you instead do a check after parsing that the port was set in the input?

if url.port_or_known_default() != None {
  // check input contains ":port"
}

I know this is a hacky solution, but I'd rather not add maintenance burden for such a limited use case.

@daxpedda
Copy link
Author

daxpedda commented Apr 28, 2021

That is the solution I'm using for now. But it has the problems I pointed at above, there will be some protocols which have default ports, and others which don't, which is confusing during setup for a library that isn't protocol aware.

I do understand that this is a limited use-case, but I find it very useful for the Url crate to actually be able to parse URL's without any "interpretation" by RFC's and standards.
But the ability to do both, parsing URL's according to standards, which has great value in of itself, and being able to parse the actual string, in my opinion has value too.

Of course if this is something the Url crate doesn't consider to be in scope or not valuable, feel free to close this issue and my corresponding PR.

@valenting
Copy link
Collaborator

I closed the PR for now, but I'll leave this open for now. Maybe we can find a way to accommodate this use case in the future.

@nthuemmel
Copy link

I need this for a different use case: I want to set a default port, unless the user specified a port in the input.
But, the default port I want to apply is not the same as the scheme's default port!
I.e. if the scheme is https, and the user specified https://example.com, I want to transform it into https://example.com:4000.
However, if the user specified https://example.com:443, the port is discarded, and the URL is still - erronously - rewritten to https://example.com:4000!

Is there any workaround for this?

@daxpedda
Copy link
Author

This is the same use-case we need actually, you explained it way better though!

@jszwedko
Copy link

jszwedko commented Sep 29, 2021

This came up for us as well. We'd like to just retrieve the port if it is included in the URL, regardless of whether it is the default port for the scheme.

Could you instead do a check after parsing that the port was set in the input?

if url.port_or_known_default() != None {
  // check input contains ":port"
}

I know this is a hacky solution, but I'd rather not add maintenance burden for such a limited use case.

What would this actually look like though? It seems to me like we would need to parse the URL ourselves to figure out if a port was specified.

EDIT I suppose we could just search for :<port> in the string representation but this feels a bit brittle in that it could match a username:password if the password happens to start with the same number as the port.

@wpdevelopment11
Copy link

wpdevelopment11 commented Apr 13, 2025

I checked URL parsing in other languages for the ability to distinguish between https://localhost:443 and https://localhost case.

In my testing Go and Python allow that. If it's good or bad is a different story.
In some cases, the inability to distinguish these two cases can cause problems, as noted by the people above.

  • C#

    Console.WriteLine($"Port: {new Uri("https://localhost:443").Port}"); // Port: 443
    Console.WriteLine($"Port: {new Uri("https://localhost").Port}");     // Port: 443
  • JavaScript

    console.log(`Port: ${new URL("https://localhost:443").port}`) // Port:
    console.log(`Port: ${new URL("https://localhost").port}`)     // Port:
  • Dart

    print("Port: ${Uri.parse('https://localhost:443').port}"); // Port: 443
    print("Port: ${Uri.parse('https://localhost').port}");     // Port: 443
  • Go

    url1, _ := url.Parse("https://localhost:443")
    url2, _ := url.Parse("https://localhost")
    fmt.Printf("Port: %s\n", url1.Port()) // Port: 443
    fmt.Printf("Port: %s\n", url2.Port()) // Port:
  • Python

    print(f"Port: {urllib.parse.urlparse("https://localhost:443").port}") # Port: 443
    print(f"Port: {urllib.parse.urlparse("https://localhost").port}")     # Port: None

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants