aspnet / basicmiddleware Goto Github PK
View Code? Open in Web Editor NEW[Archived] Basic middleware components for ASP.NET Core. Project moved to https://github.com/aspnet/AspNetCore
License: Apache License 2.0
[Archived] Basic middleware components for ASP.NET Core. Project moved to https://github.com/aspnet/AspNetCore
License: Apache License 2.0
I was using the following suggestion to force SSL prior to beta8: #10
It seems the same code is causing a redirect loop for some reason. I can't seem to get it to work.
Add middleware for doing HTTP response compression. Should support GZIP and Brotli. Would need to be configurable to allow control of:
E.g.:
public void Configure(IApplicationBuilder app)
{
app.UseResponseCompression();
app.UseStaticFiles();
app.Run(async context =>
{
context.Response.ContentType = "text/plain";
await context.Response.WriteAsync("Hello compressed!");
});
}
Objectives:
Right now we throw NIE instead of NSE in places where it really should be NSE. Also error messages should be beefed up, with grammar such as:
"_____ is not supported because ____"
which will be more useful for a user.
Came across this via aspnet/KestrelHttpServer#365 (comment) and I'm glad to see it in the core this round. There's a bug I see though:
X-Forwarded-For
assumes comma-separated values (OverrideHeaderMiddleware.cs#L43) (correct).X-Forwarded-Proto
assumes a single value (OverrideHeaderMiddleware.cs#L75) (incorrect).Both of these should support comma-separated values. For example if you have an edge node in europe that's HTTPS
but then HTTP
back to the origin (the load balancer adding a second entry) and then to the app, you'll get:
X-Forwarded-Proto: http, https
Or if it's HTTPS
at both hops (yay security!):
X-Forwarded-Proto: https, https
While it doesn't answer the complicated question of what the app should get in complicated scenarios (this will definitely vary with such setups), it needs to not at least not break by default. I think using the 0-th entry is correct in both cases for the basic middleware use case.
In IIS a dev can specify wildcard mime types when checking if it should compress the response. Right now the middleware can only do exact matches. It would be much simpler if devs could specify wildcards.
Note in IIS it can opt in or out with wildcards, and override with specific values. E.g. text/* can be enabled and text/foo can be disabled. Most specific match wins.
RE:
https://www.iis.net/configreference/system.webserver/httpcompression/dynamictypes
IIS/Express Defaults:
<httpCompression
directory="%SystemDrive%\inetpub\temp\IIS Temporary Compressed Files">
<scheme name="gzip" dll="%Windir%\system32\inetsrv\gzip.dll" />
<dynamicTypes>
<add mimeType="text/*" enabled="true" />
<add mimeType="message/*" enabled="true" />
<add mimeType="application/javascript" enabled="true" />
<add mimeType="*/*" enabled="false" />
</dynamicTypes>
<staticTypes>
<add mimeType="text/*" enabled="true" />
<add mimeType="message/*" enabled="true" />
<add mimeType="application/javascript" enabled="true" />
<add mimeType="*/*" enabled="false" />
</staticTypes>
</httpCompression>
X-Original-Ip
X-Original-Host
X-Original-Proto
Currently global rules are treated like normal rules, while rather they should be treated to operate on both the path and path base (AFAIK).
Global rules:
– Rules in this collection can be defined only on the server level. Global rules are used to define server-wide URL rewriting logic. These rules are defined within the ApplicationHost.config file, and they cannot be overridden or disabled on any lower configuration levels. Global rules always operate on the absolute URL's path (that is, the requested URI without the server name). These rules are evaluated early in the IIS request-processing pipeline (PreBeginRequest event).
The ForwardedHeadersMiddleware has a feature that requires the counts to match between the headers being processed. Some proxies aren't good about keeping these headers in sync. Add an option to disable this check.
Repro
var options = new RewriteOptions();
options.Rewrite("/app/(.+)", "/app?q={R:1}"); // "/app?q=$1" after #77
app.UseRewriter(options);
Request to localhost:5000/app/abcd
Expected
Rewrites to localhost:5000/app?q=abcd
Actual
No rewrite. The match condition is not met because the UrlRewriteRule
strips the leading slash
cc @ZestyBread
It calls GetCompressionProvider
for every request before checking content type.
Currently not supporting custom responses for Url Rewrite Rules (part of the match). This feature seemed rarely used, but should be considered in the final implementation.
Ex:
<action type="CustomResponse" statusCode="503"
subStatusCode="0"
statusReason="Site is unavailable"
statusDescription="Site is down for maintenance" />
I feel that eventually the Rewrite middleware should be in its own repo. It has gotten to the point where it is almost on the scale of Routing, and with the inevitable extensions that will be added, it will grow more.
Just a thought.
@Tratcher
Here a Debug Log is issued when header symmetry fails (there are other examples in this class)
The code considers the headers untrusted and returns without setting
request.Scheme = currentValues.Scheme;
The result is a redirect loop when
[HttpsRequired]
and
X-Forwarded-For
count != X-Forwarded-Proto
count
This is a common scenario for
X-Forwarded-Proto
by default so is subject to misconfiguration.X-Forwarded-Proto
is a single valueX-Forwarded-Proto
This situation is not very discoverable and can leave one scratching your head.
Why am I getting a re-direct loop?
Microsoft default LogLevel is Information , so if you look in the logs there is no indication of what actually went wrong aside from a log full of redirects.
Its also a situation which doesn't recover (browser gives up).
At the very least can we change these header checks to _logger.LogError
?
Is it a candidate for raising an exception?
The Rewrite middleware should eventually be documented within AspNetCore before 1.1 release. Stating what is implemented, references to IIS and mod_rewrite, etc.
Change WildCard
to Wildcard
https://github.com/aspnet/BasicMiddleware/blob/dev/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/PatternSyntax.cs#L9
OR
Parse the Enum ignoring case
https://github.com/aspnet/BasicMiddleware/blob/dev/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/UrlRewriteFileParser.cs#L64
Actions occur once the rule has passed. These can be consolidated into one class. Thought they needed to be distinct because of mod_rewrite allowing for more options, but we can probably construct UrlRewrite rules with defaults in mod_rewrite.
See:
https://github.com/aspnet/BasicMiddleware/blob/dev/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/ModRewriteRedirectAction.cs
Versus
https://github.com/aspnet/BasicMiddleware/blob/dev/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/RedirectAction.cs
RE: 44f03ef
OverrideHeaderMiddleware has been renamed to ForwardedHeadersMiddleware. See the following usage:
BasicMiddleware/samples/HttpOverridesSample/Startup.cs
Lines 13 to 16 in 44f03ef
The processing of forwarded headers has also changed significantly. For x-forwarded-for there are new options for KnownProxies and KnownNetworks allowing you to specify which remote parties to trust x-forwarded headers from. This will be applied recursively when there is more than one x-forwarded-for value.
All of the enabled x-forwarded headers are now applied in unison. The process aborts if there an inconsistent number of forwarders as it becomes impossible to determine which ones were applied by which proxy. There is also a ForwardLimit option which if enabled restricts the number of entries evaluated.
Credit: @pmhsfelix.
Code from IISPlatformHandler that should be moved to OverrideHeaderMiddleware to correctly handle ports.
private static void UpdateRemoteIp(HttpContext httpContext)
{
var xForwardedForHeaderValue = httpContext.Request.Headers.GetCommaSeparatedValues(XForwardedForHeaderName);
if (xForwardedForHeaderValue != null && xForwardedForHeaderValue.Length > 0)
{
IPAddress ipFromHeader;
int? port;
if (IPAddressWithPortParser.TryParse(xForwardedForHeaderValue[0], out ipFromHeader, out port))
{
var connection = httpContext.Connection;
var remoteIPString = connection.RemoteIpAddress?.ToString();
if (!string.IsNullOrEmpty(remoteIPString))
{
httpContext.Request.Headers[XOriginalIPName] = remoteIPString;
}
if (port.HasValue)
{
if (connection.RemotePort != 0)
{
httpContext.Request.Headers[XOriginalPortName] = connection.RemotePort.ToString(CultureInfo.InvariantCulture);
}
connection.RemotePort = port.Value;
}
connection.RemoteIpAddress = ipFromHeader;
}
}
}
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Net;
using Microsoft.AspNet.IISPlatformHandler;
using Xunit;
namespace Microsoft.AspNet.PipelineHandler.Tests
{
public class IPAddressWithPortParserTests
{
[Theory]
[InlineData("127.0.0.1", "127.0.0.1", null)]
[InlineData("127.0.0.1:1", "127.0.0.1", 1)]
[InlineData("1", "0.0.0.1", null)]
[InlineData("1:1", "0.0.0.1", 1)]
[InlineData("::1", "::1", null)]
[InlineData("[::1]", "::1", null)]
[InlineData("[::1]:1", "::1", 1)]
public void ParsesCorrectly(string input, string expectedAddress, int? expectedPort)
{
IPAddress address;
int? port;
var success = IPAddressWithPortParser.TryParse(input, out address, out port);
Assert.True(success);
Assert.Equal(expectedAddress, address?.ToString());
Assert.Equal(expectedPort, port);
}
[InlineData("[::1]:")]
[InlineData("[::1:")]
[InlineData("::1:")]
[InlineData("127:")]
[InlineData("127.0.0.1:")]
[InlineData("")]
[InlineData("[]")]
[InlineData("]")]
[InlineData("]:1")]
public void ShouldNotParse(string input)
{
IPAddress address;
int? port;
var success = IPAddressWithPortParser.TryParse(input, out address, out port);
Assert.False(success);
Assert.Equal(null, address);
Assert.Equal(null, port);
}
}
}
From @rynowak on February 24, 2016 23:3
It's a common pattern (like WCF activity ID) to create a correlation id and use it across multiple services with logging. This way if your logs all go to the same store you can associate all of the business processes across service/server boundaries that are part of the same unit of work.
There's 3-5 lines of boilerplate required to do steps 1,2, and 4, and we could easily make a middleware that does it for you.
We might want to add an extension method for step 3.
Copied from original issue: aspnet/Logging#371
IIS Url Rewrite has been implemented and is going through code review. We need heavy verification of all rules that can be provided. This can be done through scraping github for rules and seeing if we properly parse and apply the rules.
Mod Url Rewrite has been implemented. We need heavy verification of all rules that can be provided. This can be done through scraping github for rules and seeing if we properly parse and apply the rules.
Request filtering is a great feature in IIS for filtering the requests based on some criteria. It will be nice to have such a middleware in ASP.NET Core
FYI I already made a prototype few weeks ago https://github.com/hishamco/RequestFiltering to prove the concept
mod_rewrite specific thing. These flags modify the cookie and environment variable respectively.
See:
https://github.com/aspnet/BasicMiddleware/blob/dev/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/ChangeCookieAction.cs
https://github.com/aspnet/BasicMiddleware/blob/dev/src/Microsoft.AspNetCore.Rewrite/project.json
ASP.NET Core basic middleware for:\r\nRewrite Url module.
ASP.NET Core basic middleware for rewriting URLs. Includes:\r\n* Support for custom URL rewrite rules\r\m* Support for running IIS URL Rewrite module rules\r\n* Support for running Apache mod_rewrite rules.
(feel free to massage this a bit if it's not exactly right)https://github.com/aspnet/BasicMiddleware/blob/dev/src/Microsoft.AspNetCore.Buffering/project.json
ASP.NET Core middleware for buffering response bodies.
ASP.NET Core basic middleware for:\r\nX-Forwarded-* headers to forward headers from a proxy.\r\nHTTP method override header.
ASP.NET Core basic middleware for supporting HTTP method overrides. Includes:\r\nX-Forwarded-* headers to forward headers from a proxy.\r\nHTTP method override header.
ASP.NET Core middleware for HTTP Response compression.
Features implemented in Url Rewrite:
Elements/Attributes in rules:
Server Variables (common ones supported for now, TODO on complete list)
Features that are not implemented in UrlRewrite:
Elements/Attributes in rules:
If any exception is thrown while parsing a mod_rewrite or UrlRewrite file, we should provided the line and character index so the user knows exactly where an error is.
info: Exec
info: program: /usr/bin/env
info: commandline: bash -c ". \"/home/cesars/src/aspnet/universe/BasicMiddleware/packages/KoreBuild/build/dnvm.sh\"; dnvm run default -runtime coreclr test"
info: workingdir: test/Microsoft.AspNet.HttpOverrides.Tests
xUnit.net DNX Runner (64-bit DNXCore 5.0)
Discovering: Microsoft.AspNet.HttpOverrides.Tests
Discovered: Microsoft.AspNet.HttpOverrides.Tests
Starting: Microsoft.AspNet.HttpOverrides.Tests
Assert.Equal() Failure
↓ (pos 4)
Expected: testHost
Actual: testhost
↑ (pos 4)
Stack Trace:
at Microsoft.AspNet.HttpOverrides.OverrideMiddlewareHeaderTests.<>c__DisplayClass2_0.<XForwardedHostOverrideChangesRequestHost>b__1(HttpContext context)
at Microsoft.AspNet.HttpOverrides.OverrideHeaderMiddleware.Invoke(HttpContext context)
at Microsoft.AspNet.Hosting.Internal.RequestServicesContainerMiddleware.<Invoke>d__3.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.AspNet.Hosting.Internal.HostingEngine.<>c__DisplayClass32_0.<<Start>b__0>d.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.AspNet.TestHost.ClientHandler.<>c__DisplayClass3_0.<<SendAsync>b__0>d.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.AspNet.TestHost.ClientHandler.<SendAsync>d__3.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
at Microsoft.AspNet.HttpOverrides.OverrideMiddlewareHeaderTests.<XForwardedHostOverrideChangesRequestHost>d__2.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
Assert.Equal() Failure
↓ (pos 4)
Expected: testHost
Actual: testhost
↑ (pos 4)
Stack Trace:
at Microsoft.AspNet.HttpOverrides.OverrideMiddlewareHeaderTests.<>c__DisplayClass5_0.<AllForwardsEnabledChangeRequestRemoteIpHostandProtocol>b__1(HttpContext context)
at Microsoft.AspNet.HttpOverrides.OverrideHeaderMiddleware.Invoke(HttpContext context)
at Microsoft.AspNet.Hosting.Internal.RequestServicesContainerMiddleware.<Invoke>d__3.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.AspNet.Hosting.Internal.HostingEngine.<>c__DisplayClass32_0.<<Start>b__0>d.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.AspNet.TestHost.ClientHandler.<>c__DisplayClass3_0.<<SendAsync>b__0>d.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.AspNet.TestHost.ClientHandler.<SendAsync>d__3.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
at Microsoft.AspNet.HttpOverrides.OverrideMiddlewareHeaderTests.<AllForwardsEnabledChangeRequestRemoteIpHostandProtocol>d__5.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
Finished: Microsoft.AspNet.HttpOverrides.Tests
=== TEST EXECUTION SUMMARY ===
Microsoft.AspNet.HttpOverrides.Tests Total: 11, Errors: 0, Failed: 2, Skipped: 0, Time: 0.708s
Open items:
Testing:
Release:
In the initial sample/ review of the rewrite module, the standard builder model was used to add rules. There are a few simple examples that exist, but these should be verified for operation and more code rules should be added.
Right now we have rules like RedirectRule
or RedirectScheme
, but a review of these should be done as well as more rules added (check if file exists, rewriting query, etc).
Writes would not flush automatically in the following code.
app.Map("/slownb", a =>
{
a.UseResponseCompression();
a.Run(async w =>
{
w.Response.Headers["Content-Type"] = "text/html";
var nb = w.Features.Get<IHttpBufferingFeature>();
nb.DisableResponseBuffering();
while (!w.RequestAborted.IsCancellationRequested)
{
await w.Response.WriteAsync("1");
await Task.Delay(TimeSpan.FromSeconds(0.1));
}
});
});
Many of the server variables in UrlRewrite and mod_rewrite can obtain different aspects of the HttpRequest (in HttpContext). Though I did my best to verify these, the documentation is lacking. There is definitely some fuzziness when it comes to PathBase with Path in any url checks for conditions.
See:
https://github.com/aspnet/BasicMiddleware/blob/dev/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/ServerVariables.cs
and https://github.com/aspnet/BasicMiddleware/blob/dev/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/ServerVariables.cs
Also search for server variable definitions online (if available).
e.g.
<condtions trackAllCaptures="true">
<add input="{QUERY_STRING}" pattern="id=(20)" />
<add input="{HTTP_HOST}" pattern="(.*)" />
</conditions>
<action type="Redirect" url="https://{C:2}" />
Remember this?
<configuration>
<system.web>
<pages validateRequest="true" />
</system.web>
</configuration>
http://www.asp.net/whitepapers/request-validation
The awesome thing about IIS ASP.NET websites is that they prevented html/script injections AS A DEFAULT!
In .NET Core, it isn't even possible.
I think there should be a middleware that does validation on posted form values, http headers, etc.
Maybe some of the Microsoft employees here can ping the IIS team for the code ;)
Is there a good way to force HTTPS?
Don't just throw away the remote IP. Store it somewhere.
I'm running the following code on the official RC2 in an Azure WebApp.
using System;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.HttpOverrides;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.AspNetCore.Http;
namespace WebApplication2
{
public class Startup
{
public Startup(IHostingEnvironment env)
{
var builder = new ConfigurationBuilder()
.SetBasePath(env.ContentRootPath)
.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true)
.AddEnvironmentVariables();
Configuration = builder.Build();
}
public IConfigurationRoot Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app)
{
app.UseForwardedHeaders(new ForwardedHeadersOptions
{
ForwardedHeaders = ForwardedHeaders.All
});
app.UseHttpMethodOverride();
app.Use(async (context, next) =>
{
foreach (var header in context.Request.Headers)
{
if (header.Key.StartsWith("x-f", StringComparison.OrdinalIgnoreCase))
await context.Response.WriteAsync($"{header.Key}: {header.Value}\r\n");
}
await context.Response.WriteAsync($"Method: {context.Request.Method}\r\n");
await context.Response.WriteAsync($"Scheme: {context.Request.Scheme}\r\n");
await context.Response.WriteAsync($"IsHttps: {context.Request.IsHttps}\r\n");
await context.Response.WriteAsync("Hello World - " + DateTimeOffset.Now + Environment.NewLine);
await context.Response.WriteAsync(Environment.NewLine);
await context.Response.WriteAsync("Address:" + Environment.NewLine);
await context.Response.WriteAsync("Host: " + context.Request.Headers["Host"] + Environment.NewLine);
await context.Response.WriteAsync("PathBase: " + context.Request.PathBase.Value + Environment.NewLine);
await context.Response.WriteAsync("Query: " + context.Request.QueryString.Value + Environment.NewLine);
await context.Response.WriteAsync(Environment.NewLine);
await context.Response.WriteAsync("Connection:" + Environment.NewLine);
await context.Response.WriteAsync("RemoteIp: " + context.Connection.RemoteIpAddress + Environment.NewLine);
await context.Response.WriteAsync("RemotePort: " + context.Connection.RemotePort + Environment.NewLine);
await context.Response.WriteAsync("LocalIp: " + context.Connection.LocalIpAddress + Environment.NewLine);
await context.Response.WriteAsync("LocalPort: " + context.Connection.LocalPort + Environment.NewLine);
await context.Response.WriteAsync("ClientCert: " + context.Connection.ClientCertificate + Environment.NewLine);
await context.Response.WriteAsync(Environment.NewLine);
});
}
}
}
When issueing a request over http, the following is displayed
X-Forwarded-For: 78.192.yyy.xx:58475, 78.192.yyy.xx:58475
X-Forwarded-Proto: http
Method: GET
Scheme: http
IsHttps: False
Hello World - 5/29/2016 7:06:38 PM +00:00
Address:
Host: zzzzzzz.azurewebsites.net
PathBase:
Query: ?
Connection:
RemoteIp: 127.0.0.1
RemotePort: 50068
LocalIp: 127.0.0.1
LocalPort: 11850
ClientCert:
When issueing a request over https, the following is displayed
X-Forwarded-For: 78.192.yyy.xx:58531, 78.192.yyy.xx:58531
X-Forwarded-Proto: https
Method: GET
Scheme: http
**IsHttps: False**
RemoteIP: 127.0.0.1
RemotePort: 50132
Hello World - 5/29/2016 7:10:27 PM +00:00
Address:
Host: zzzzzzz.azurewebsites.net
PathBase:
Query: ?
Connection:
RemoteIp: 127.0.0.1
RemotePort: 50132
LocalIp: 127.0.0.1
LocalPort: 11850
ClientCert:
I must certainly be missing something obvious, but I can't see it. Any help would be greatly appreciated.
An AbortRequest action causes the URL Rewrite Module to drop the HTTP connection for the current request. The action does not have any parameters. Use of this action implies that no subsequent rules are evaluated for the current URL after this action is performed.
A CustomResponse action causes the URL Rewrite Module to respond to the HTTP client by using a user-specified status code, subcode, and reason. Use of a CustomResponse action implies that no subsequent rules are evaluated for the current URL after this action is performed.
CustomResponse action has the following configuration options:
- statusCode – Specifies the status code to use in response to the client.
- subStatusCode – Specifies the substatus code to use in response to the client.
- statusReason – Specifies the reason phrase to use with the status code.
- statusDescription – Specifies the one line description to put in the body of the response.
To improve Search Engine Optimization SEO, there should only be a single URL for each resource. Case differences and/or URL's with/without trailing slashes are treated as different URL's by search engines (See Google's comments and Bing's).
It would be greate to write an extension method for IApplicationBuilder
called UseRedirectToCanonicalUrl
that does this. Here are the special considerations:
IOptions<RouteOptions>
can be used to determine the AppendTrailingSlash
and LowercaseUrls
settings. These can be used to work out whether to add or remove a trailing slash and also whether we should be lower-casing URL's.LowercaseQueryStrings
property could be added to IOptions<RouteOptions>
.I have already written a RedirectToCanonicalUrlAttribute MVC Core filter to do the above and I've been thinking about converting it to middleware, then I saw this project and now think it can be used for this purpose. I provide two ways of providing exceptions to the rule:
[NoTrailingSlash]
[Route("robots.txt", Name = "GetRobotsText")]
public IActionResult RobotsText() {}
[NoLowercaseQueryString]
[Route("foo", Name = "GetFoo")]
public IActionResult Foo(string caseSensitiveQueryParameter) {}
@ZestyBread I watched the community standup this morning, are you still working at Microsoft? Would you be interested in a PR?
We have [RequireHttps] in MVC as a filter that redirects you to https://
- we should consider adding the same kind of thing as a middleware.
Needs to be opt in
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.