Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

URL Redirection failing

So situation sketch:

I've created a website in asp.net core, i've got it up and running. A couple of days ago my hosting provider added the option to configure SSL so I did that leaving me with the problem that there was no redirection from http to https. I've started looking on the web for solutions and figured out some code that works in 3 of the 4 cases on the hosting and 4 of the 4 cases when tested locally on IIS.

So what works:

  • https://www.someurl.com -> no redirection needed
  • https://someurl.com -> redirects to https://www.someurl.com
  • http://someurl.com -> redirects to https://www.someurl.com
  • http://www.someurl.com -> gives a redirect error:ERR_TOO_MANY_REDIRECTS

The following code was used in the asp.net core site:

public void Configure(...) {
  app.UseHttpsWorldWideWebRedirect();
}

public static class HttpsWorldWideWebRedirectMiddlewareExtensions
    {
        public static IApplicationBuilder UseHttpsWorldWideWebRedirect(this IApplicationBuilder builder)
        {
            return builder.UseMiddleware<HttpsWorldWideWebRedirectMiddleware>();
        }
    }

public class HttpsWorldWideWebRedirectMiddleware
{
    private readonly RequestDelegate _next;
    private readonly ILogger<HttpsWorldWideWebRedirectMiddleware> _logger;

    public HttpsWorldWideWebRedirectMiddleware(RequestDelegate next, ILogger<HttpsWorldWideWebRedirectMiddleware> logger)
    {
        _next = next;
        _logger = logger;
        _logger.LogInformation("Https WWW redirect module loaded");
    }

    public async Task Invoke(HttpContext context)
    {
        var protoHeader = context.Request.Headers["X-Forwarded-Proto"].ToString();
        var ignoreHttps = false;
        var ignoreWww = false;

        if (context.Request.IsHttps || protoHeader.ToLower().Equals("https"))

        {
            ignoreHttps = true;
        }

        if (context.Request.Host.Host.StartsWith("www", StringComparison.OrdinalIgnoreCase) || string.Equals(context.Request.Host.Host, "localhost", StringComparison.OrdinalIgnoreCase))
        {
            ignoreWww = true;
        }

        if (ignoreWww && ignoreHttps)
        {
            await _next.Invoke(context);
        }
        else
        {
            var www = ignoreWww ? "" : "www.";
            var newPath =
                $"https://{www}{context.Request.Host.Value}{context.Request.PathBase}{context.Request.Path}{context.Request.QueryString}";
            _logger.LogDebug($"'{context.Request.GetDisplayUrl()}' was rewritten into '{newPath}'");
            context.Response.Headers["X-Forwarded-Proto"] = "https";
            context.Response.Redirect(newPath, true);
        }
    }
}

The next step I tried was adding a redirect in the web.config to cover that one case where asp.net redirection not works using the following code:

<rewrite>
  <rules>
    <rule name="Redirect to https if http://www" stopProcessing="true">
      <match url="(.*)" />
      <conditions logicalGrouping="MatchAny">
        <add input="{HTTP_HOST}" pattern="^www.*"/>
        <add input="{HTTPS}" pattern="Off" />
      </conditions>
      <action type="Redirect" url="https://{HTTP_HOST}/{R:1}" redirectType="Permanent" />
    </rule>
  </rules>
</rewrite>

As a test I added "iwork" tot this line:

The result still is err too many redirection but then with http://someurl.com/iworkiworkiworkiworkiworkiworkiworkiworkiworkiwork as resulting url.

So I'm at a loss for what exactly is going wrong and out of ideas on how to fix it, any ideas?

like image 478
woutervs Avatar asked Jan 19 '26 18:01

woutervs


2 Answers

Don't know anything about .NET Core but this can certainly be done with URL rewrite rules.

You need at least 2 rewrite rules.

  1. Redirect http requests to https with www.
  2. Redirect https request with no www. prefix to https with www.

This will reduce the redirect chain as much as possible.


<rewrite>
    <rules>
        <rule name="Redirect all http requests to https with www" stopProcessing="true">
            <match url=".*" />
            <conditions trackAllCaptures="true">
                <add input="{HTTP_HOST}" pattern="^localhost" negate="true" />
                <add input="{HTTPS}" pattern="off" />
                <add input="{HTTP_HOST}" pattern="^(?:www\.)?(.+)$" />
            </conditions>
            <action type="Redirect" url="https://www.{C:1}/{R:0}" />
        </rule>
        <rule name="Redirect https requests with no www prefix to https with www" stopProcessing="true">
            <match url=".*" />
            <conditions>
                <add input="{HTTP_HOST}" pattern="^localhost" negate="true" />
                <add input="{HTTPS}" pattern="on" />
                <add input="{HTTP_HOST}" pattern="^www\." negate="true" />
            </conditions>
            <action type="Redirect" url="https://www.{HTTP_HOST}/{R:0}" />
        </rule>
    </rules>
</rewrite>
like image 188
Kul-Tigin Avatar answered Jan 21 '26 06:01

Kul-Tigin


There is existing Middleware that will handle redirecting to HTTPS for you automatically. Just add the following at the top of your Configure() method in your Startup class:

var options = new RewriteOptions().AddRedirectToHttps();
app.UseRewriter(options);

If you're using APIs, you could also add a RequireHttpsAttribute filter to your MVC Options in ConfigureServices():

services.AddMvc(mvcOptions => 
        {
            mvcOptions.Filters.Add(new RequireHttpsAttribute());

        });
like image 33
Omar Beyhum Avatar answered Jan 21 '26 07:01

Omar Beyhum



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!