Redirect Non WWW to WWW [duplicate] - asp.net-core

This question already has answers here:
Redirect Non WWW to WWW using Asp.Net Core Middleware
(10 answers)
Closed 4 years ago.
On an ASP.Net Core application startup I have:
RewriteOptions rewriteOptions = new RewriteOptions();
rewriteOptions.AddRedirectToHttps();
applicationBuilder.UseRewriter(rewriteOptions);
When in Production I need to redirect all Non WWW to WWW.
For example:
domain.com/contact > www.domain.com/contact
How can I do this using Rewrite Middleware?

You could create a custom rule by creating a class and implementing the IRule interface (see below). I think there must be a better way to construct the redirectUrl though.
public class CanonicalDomainRewriteRule : IRule
{
public void ApplyRule(RewriteContext context)
{
HttpRequest request = context.HttpContext.Request;
if (request.Host.Value.StartsWith("www.", StringComparison.OrdinalIgnoreCase))
{
return;
}
else
{
HttpResponse response = context.HttpContext.Response;
string redirectUrl = $"{request.Scheme}://www.{request.Host}{request.Path}{request.QueryString}";
response.Headers[HeaderNames.Location] = redirectUrl;
response.StatusCode = StatusCodes.Status301MovedPermanently;
context.Result = RuleResult.EndResponse;
}
}
}
You can add this rule as follows in your ConfigureServices method:
RewriteOptions rewriteOptions = new RewriteOptions()
.Add(new CanonicalDomainRewriteRule());
app.UseRewriter(rewriteOptions);
See Extensions and Options: IRule-based rule for further examples.

Related

Querystring issue with .Net Core url rewrite

Working on an app in ASP.NET Core I am having a problem trying to rewrite a single url like:
https://localhost:44318/Details?content=My-url-to-rewrite&id=221
into
https://localhost:44318/mypage
The code I am using at the beginning of the Configure() method into Startup.cs is the following:
app.UseRewriter(new RewriteOptions()
.AddRewrite(#"^Details?content=My-url-to-rewrite&id=221", "/mypage", skipRemainingRules: true));
The strange thing is that if I try to rewrite the url without the querystring like the following, it works
app.UseRewriter(new RewriteOptions()
.AddRewrite(#"^Details", "/mypage", skipRemainingRules: true));
And even adding the question mark to append the querystring it works, like the following
app.UseRewriter(new RewriteOptions()
.AddRewrite(#"^Details?", "/mypage", skipRemainingRules: true));
But as soon as I add even a single character after the question mark the url is not rewritten and the page gets linked as usually without any error.
Any idea?
Thanks in advance.
You can implement your own ReWrite Middleware :
Configure :
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
....
var options = new RewriteOptions()
.Add(RedirectMyRequests);
app.UseRewriter(options);
...
}
static void RedirectMyRequests(RewriteContext context)
{
var request = context.HttpContext.Request;
// Because we're redirecting back to the same app, stop processing if the request has already been redirected
//If the modified path is similar with previous, add if statemetn to stop processing
//check the request path and request QueryString
if (request.Path.Value.StartsWith("/Details", StringComparison.OrdinalIgnoreCase) && request.QueryString.Value.StartsWith("?content", StringComparison.OrdinalIgnoreCase))
{
if (request.QueryString.Value.Split('&')[1].StartsWith("id", StringComparison.OrdinalIgnoreCase))
{
var response = context.HttpContext.Response;
response.StatusCode = StatusCodes.Status301MovedPermanently;
context.Result = RuleResult.EndResponse;
//change it with needed path, it is combined with request path and request QueryString
response.Headers[HeaderNames.Location] = "/Home/Privacy";
}
}
}

Add trailing slash at the end of URL

I'm using .NET Core 2.1. I'm trying to permanent redirect any non-file URLs (does not contain a dot) without an ending slash to a corresponding URL with the ending slash. Is there a way to accomplish this using rewriteOptions?
var rewriteOptions = new RewriteOptions()
.AddRedirect("^[^.]*$", "$1", 301)
.AddRedirectToHttpsPermanent();
The pattern should match :
/js # has no preceding segements
/www/js # has a segment
/www/test.d/js # contains a dot within preceding segments
and should not match :
/www/js/jquery.js # contains a dot at last segment
/www/js/ # has a trailing slash
/www/js/hello.d/jquery.js/ # has a trailing slash
So create such a pattern as below :
var pattern = #"^(((.*/)|(/?))[^/.]+(?!/$))$";
var options = new RewriteOptions()
.AddRedirect(pattern, "$1/",301);
and it will work .
Test cases :
should redirect :
GET https://localhost:5001/js HTTP/1.1
GET https://localhost:5001/xx/js HTTP/1.1
GET https://localhost:5001/xx/test.d/js HTTP/1.1
should not redirect :
GET https://localhost:5001/xx/js/ HTTP/1.1
GET https://localhost:5001/xx/jquery.js HTTP/1.1
GET https://localhost:5001/xx/hello.d/jquery.js HTTP/1.1
According to this documentation to add a trailing slash it's:
var options = new RewriteOptions()
.AddRedirect("(.*[^/])$", "$1/")
.AddRedirectToHttpsPermanent();
To prevent it happening to static files, make sure app.UseStaticFiles(); is called before app.UseRewriter(options);
so:
// Return static files and end the pipeline.
app.UseStaticFiles(); // <--- **before** the redirect
var options = new RewriteOptions()
.AddRedirect("(.*[^/])$", "$1/")
.AddRedirectToHttpsPermanent();
app.UseRewriter(options);
Calling UseStaticFiles() first will short-cut the pipeline for static files. So no redirects are done on the static files.
More info on Startup.Configure order here:
https://learn.microsoft.com/en-us/aspnet/core/fundamentals/middleware/?view=aspnetcore-2.1#order
Way for adding trailing slash for non file URL's is by configuring the middleware in startup.cs after app.UseStaticFiles();
public class TrailingSlashUrlMiddleware
{
private readonly RequestDelegate _next;
public TrailingSlashUrlMiddleware(RequestDelegate next)
{
_next = next;
}
public async Task Invoke(HttpContext httpContext)
{
string currentPath = httpContext.Request.Path;
if (currentPath != "/")
{
string ext = System.IO.Path.GetExtension(currentPath);
bool NeedRedirection = false;
var currentQueryString = httpContext.Request.QueryString;
if (string.IsNullOrEmpty(ext))
{
if (!currentPath.EndsWith("/"))
{
currentPath = currentPath + "/";
NeedRedirection = true;
}
//if (currentQueryString.HasValue)
//{
// string queryString = currentQueryString.Value;
// if (!queryString.EndsWith("/"))
// {
// queryString = queryString + "/";
// NeedRedirection = true;
// }
// currentPath += queryString;
//}
}
if (NeedRedirection)
{
httpContext.Response.Redirect(currentPath, true);
return;
}
}
await _next(httpContext);
}
}
if you need to apply this to query string uncomment the commented code.

How do I force https redirect on static files in ASP.NET Core 2.1?

I have a ASP.NET Core app that has HTTPS redirection enabled. The problem is that HTTPS redirection doesn´t work on static files, so the front-end is in a different port than the back-end when I enter the site with http and this causes CORS to block all requests made to the back-end. I tried allowing CORS to all requests (for testing, of course) but no matter what I did, the requests failed. Only visiting the front end with https worked.How do I force https redirect on static files with ASP.NET Core?
Based on my expeirence, you must add this code to the startup.cs file
public void ConfigureServices(IServiceCollection services)
{
services.AddHttpsRedirection(options =>
{
options.HttpsPort = 443;
});
You have to love Microsoft documentation. 6 paragraphs below the incomplete example they tell you about this requirement:
If no port is set:
Requests aren't redirected.
You can set port using the following techniques:
The port can be configured by setting the:
ASPNETCORE_HTTPS_PORT environment variable.
http_port host configuration key (for example, via hostsettings.json or a command
line argument).
HttpsRedirectionOptions.HttpsPort. See the preceding
This worked for me.
app.UseStaticFiles(new StaticFileOptions()
{
OnPrepareResponse = (context) =>
{
var request = context.Context.Request;
var response = context.Context.Response;
UrlRewriteUtils.RedirectIfHttp(request, response);
}
});
And here is the Utility method.
public class UrlRewriteUtils
{
public static void RedirectIfHttp(HttpRequest request, HttpResponse response)
{
string reqProtocol;
if (request.Headers.ContainsKey("X-Forwarded-Proto"))
reqProtocol = request.Headers["X-Forwarded-Proto"][0];
else if (request.IsLocal())
reqProtocol = "https";
else
reqProtocol = request.IsHttps ? "https" : "http";
if (reqProtocol.ToLower() != "https")
{
var newUrl = new StringBuilder()
.Append("https://").Append(request.Host)
.Append(request.PathBase).Append(request.Path)
.Append(request.QueryString);
response.Redirect(newUrl.ToString(), true);
}
}
}

How might I get to the SSL URL defined in the properties of an MVC project?

I have SSL enabled and I am trying to write my own RequireHttpsAttribute to allow easy testing with IIS Express. When it redirects, it redirects to port 44301, but I don't want to hard code this, I want to read this from the existing configuration.
public sealed class RequireHttpsAlternativePortAttribute : RequireHttpsAttribute
{
protected override void HandleNonHttpsRequest(AuthorizationContext filterContext)
{
base.HandleNonHttpsRequest(filterContext);
//alter the port in the base classes result
var baseRedirect = filterContext.Result as RedirectResult;
if (baseRedirect == null)
{
throw new Exception("No redirect was suppied from the base class");
}
var builder = new UriBuilder(baseRedirect.Url);
var targetPort = 44301; //need this from settings
if (builder.Port == targetPort) return; //already correct port
//change the port
builder.Port = targetPort;
var redirectResult = new RedirectResult(builder.ToString());
filterContext.Result = redirectResult;
}
}
44301 is defined in the MVC project properties under SSL URL. My question is, is this accessible during runtime anywhere?

Using app from Apache in Tomcat application

Basically I have 2 RESTful services: one build in Java and using Tomcat server, and other build in PHP and using Apache Server.
Is there any way to configure such that the app from Tomcat becomes a consumer of the one from Apache?
The webservice from Tomcat is at address:
http://localhost:8080/myapp1
and the app from Apache is at address:
http://localhost:80/myapp2.
What I want is to use the responses of the RESTful service on Apache in the Tomcat one, something like this to use from the Java code:
HttpGet httpget = new HttpGet(http://localhost:80/myapp2/items);
Currently I am receiving 404-Not Found. Is there any way to do this? Or is there another way to make the services communicate?
Forgot to post the answer. I feel so dumb - I was having a mistake in my code. It works as expected. Here is a simple example of calling the Apache server from Tomcat:
final static String BASE_URL = "http://localhost:80/proiect/";
private String getResponse(String title) {
HttpClient httpclient = new DefaultHttpClient();
String url = (title != null && title.length() > 0) ? BASE_URL + "?title=" + title : BASE_URL;
HttpGet httpget = new HttpGet(url);
String response;
try {
ResponseHandler<String> responseHandler = new BasicResponseHandler();
response = httpclient.execute(httpget, responseHandler);
return response;
} catch (ClientProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}