Changing the scheme of System.Uri
Asked Answered
C

4

56

I'm looking for canonical way of changing scheme of a given System.Uri instance with System.UriBuilder without crappy string manipulations and magic constants. Say I have

var uri = new Uri("http://localhost/hello")

and I need to change it to 'https'. My issue is in limited UriBuilder ctors and Uri.Port defaulting to 80 (should we change it to 443? hardcoding?). The code must respect all Uri properties such as possible basic auth credentials, query string, etc.

Carabiniere answered 31/7, 2013 at 10:54 Comment(0)
C
114

Ended up with this one:

var uriBuilder = new UriBuilder(requestUrl)
{
    Scheme = Uri.UriSchemeHttps,
    Port = -1 // default port for scheme
};

var uri = uriBuilder.Uri;
Carabiniere answered 31/7, 2013 at 11:26 Comment(3)
As a note - for some reason, the scheme name fields are not available for PCL projects (see here).Sibert
Just for completeness: this will not work for URIs with non-default ports (e.g. http://localhost:12345/hello will be changed to https://localhost/hello).Ducal
In the action filter I was writing I solved that by immediately using: if (filterContext.RequestContext.HttpContext.Request.IsLocal && filterContext.HttpContext.Request.Url.Host.Contains("localhost")) uriBuilder.Port = <my assigned https port>; I would prefer to pull the assigned port dynamically but I'm not sure if that's possible. Also, in my case I will never be browsing the site from the server using localhost so you might want to handle it differently if you have that requirement.Pharyngitis
D
38

UserControl's answer works fine unless you have to make sure non-default ports are preserved in the URI.

For instance, http://localhost:12345/hello should become https://localhost:12345/hello instead of https://localhost/hello.

Here's how to do that easily:

public static string ForceHttps(string requestUrl)
{
    var uri = new UriBuilder(requestUrl);

    var hadDefaultPort = uri.Uri.IsDefaultPort;
    uri.Scheme = Uri.UriSchemeHttps;
    uri.Port = hadDefaultPort ? -1 : uri.Port;

    return uri.ToString();
}

Note that we have to read uri.Uri.IsDefaultPort before setting uri.Scheme.

Here is a working example: https://dotnetfiddle.net/pDrF7s

Ducal answered 15/6, 2016 at 17:16 Comment(0)
C
9

Another iteration on Good Night Nerd Pride's answer, as an extension:

public static Uri RewriteHttps(this Uri originalUri)
{
    return new UriBuilder(originalUri)
    {
        Scheme = Uri.UriSchemeHttps,
        Port = originalUri.IsDefaultPort ? -1 : originalUri.Port // -1 => default port for scheme
    }.Uri;
}
Champac answered 22/12, 2018 at 11:53 Comment(0)
T
3

I prefer to pass the desired https port number into the ForceHttps method if you want to use a custom one otherwise omit the https port or use -1 to use the standard one (implicitly). I don't really bother with the port that is already on the url because http and https can never use the same port on the same server.

In the event that the url is already https, it will pass through unchanged leaving whatever port is there in place.

private static string ForceHttps(string requestUrl, int? httpsPort = null)
{
    var uri = new UriBuilder(requestUrl);
    // Handle https: let the httpsPort value override existing port if specified
    if (uri.Uri.Scheme.Equals(Uri.UriSchemeHttps)) {
        if (httpsPort.HasValue)
            uri.Port = httpsPort.Value;
        return uri.Uri.AbsoluteUri;
    }

    // Handle http: override the scheme and use either the specified https port or the default https port
    uri.Scheme = Uri.UriSchemeHttps;
    uri.Port = httpsPort.HasValue ? httpsPort.Value : -1;

    return uri.Uri.AbsoluteUri;
}

Usage:

ForceHttps("http://www.google.com/"); // https://www.google.com/
ForceHttps("http://www.google.com/", 225); // https://www.google.com:225/
ForceHttps("http://www.google.com/", 443); // https://www.google.com:443/
ForceHttps("https://www.google.com/"); // https://www.google.com/
ForceHttps("https://www.google.com:443/"); // https://www.google.com:443/
ForceHttps("https://www.google.com:443/", -1); // https://www.google.com/
ForceHttps("http://www.google.com:80/"); // https://www.google.com/
ForceHttps("http://www.google.com:3000/", 8080); // https://www.google.com:8080/
Tui answered 11/7, 2018 at 15:44 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.