From 22ed0f541650e684c2671a284daeca9814f0eb2e Mon Sep 17 00:00:00 2001 From: Murat Girgin Date: Thu, 25 Jun 2015 12:21:18 -0700 Subject: [PATCH 001/307] Initial commit --- CONTRIBUTING.md | 4 ++++ LICENSE.txt | 12 ++++++++++++ README.md | 6 ++++++ 3 files changed, 22 insertions(+) create mode 100644 CONTRIBUTING.md create mode 100644 LICENSE.txt create mode 100644 README.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000000..64ff041d5c --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,4 @@ +Contributing +====== + +Information on contributing to this repo is in the [Contributing Guide](https://github.com/aspnet/Home/blob/dev/CONTRIBUTING.md) in the Home repo. diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 0000000000..0bdc1962b6 --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,12 @@ +Copyright (c) .NET Foundation. All rights reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); you may not use +these files except in compliance with the License. You may obtain a copy of the +License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software distributed +under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +CONDITIONS OF ANY KIND, either express or implied. See the License for the +specific language governing permissions and limitations under the License. diff --git a/README.md b/README.md new file mode 100644 index 0000000000..6293ff7ce2 --- /dev/null +++ b/README.md @@ -0,0 +1,6 @@ +ASP.NET Basic Middleware Components +======== + +This repo hosts a collection of basic middleware components for ASP.NET 5. + +This project is part of ASP.NET 5. You can find samples, documentation and getting started instructions for ASP.NET 5 at the [Home](https://github.com/aspnet/home) repo. From 09f492e4a6b0dc29bce116825474e5e3b9a59003 Mon Sep 17 00:00:00 2001 From: Mikael Mengistu Date: Fri, 26 Jun 2015 10:33:06 -0700 Subject: [PATCH 002/307] Added a middleware to handle header overrides. Initial check in. --- .gitattributes | 50 +++++ .gitignore | 28 +++ .travis.yml | 4 + BasicMiddleware.sln | 41 ++++ NuGet.Config | 7 + appveyor.yml | 7 + build.cmd | 28 +++ build.sh | 39 ++++ global.json | 3 + makefile.shade | 8 + .../ForwardedHeaders.cs | 17 ++ .../HttpMethodOverrideExtensions.cs | 31 +++ .../HttpMethodOverrideMiddleware.cs | 51 +++++ .../Microsoft.AspNet.HttpOverrides.xproj | 17 ++ .../OverrideHeaderExtensions.cs | 21 ++ .../OverrideHeaderMiddleware.cs | 68 ++++++ .../OverrideHeaderOptions.cs | 10 + .../project.json | 19 ++ .../HttpMethodOverrideMiddlewareTest.cs | 73 +++++++ ...Microsoft.AspNet.HttpOverrides.Tests.xproj | 20 ++ .../OverrideHeaderMiddlewareTest.cs | 202 ++++++++++++++++++ .../project.json | 23 ++ 22 files changed, 767 insertions(+) create mode 100644 .gitattributes create mode 100644 .gitignore create mode 100644 .travis.yml create mode 100644 BasicMiddleware.sln create mode 100644 NuGet.Config create mode 100644 appveyor.yml create mode 100644 build.cmd create mode 100644 build.sh create mode 100644 global.json create mode 100644 makefile.shade create mode 100644 src/Microsoft.AspNet.HttpOverrides/ForwardedHeaders.cs create mode 100644 src/Microsoft.AspNet.HttpOverrides/HttpMethodOverrideExtensions.cs create mode 100644 src/Microsoft.AspNet.HttpOverrides/HttpMethodOverrideMiddleware.cs create mode 100644 src/Microsoft.AspNet.HttpOverrides/Microsoft.AspNet.HttpOverrides.xproj create mode 100644 src/Microsoft.AspNet.HttpOverrides/OverrideHeaderExtensions.cs create mode 100644 src/Microsoft.AspNet.HttpOverrides/OverrideHeaderMiddleware.cs create mode 100644 src/Microsoft.AspNet.HttpOverrides/OverrideHeaderOptions.cs create mode 100644 src/Microsoft.AspNet.HttpOverrides/project.json create mode 100644 test/Microsoft.AspNet.HttpOverrides.Tests/HttpMethodOverrideMiddlewareTest.cs create mode 100644 test/Microsoft.AspNet.HttpOverrides.Tests/Microsoft.AspNet.HttpOverrides.Tests.xproj create mode 100644 test/Microsoft.AspNet.HttpOverrides.Tests/OverrideHeaderMiddlewareTest.cs create mode 100644 test/Microsoft.AspNet.HttpOverrides.Tests/project.json diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000000..bdaa5ba982 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,50 @@ +*.doc diff=astextplain +*.DOC diff=astextplain +*.docx diff=astextplain +*.DOCX diff=astextplain +*.dot diff=astextplain +*.DOT diff=astextplain +*.pdf diff=astextplain +*.PDF diff=astextplain +*.rtf diff=astextplain +*.RTF diff=astextplain + +*.jpg binary +*.png binary +*.gif binary + +*.cs text=auto diff=csharp +*.vb text=auto +*.resx text=auto +*.c text=auto +*.cpp text=auto +*.cxx text=auto +*.h text=auto +*.hxx text=auto +*.py text=auto +*.rb text=auto +*.java text=auto +*.html text=auto +*.htm text=auto +*.css text=auto +*.scss text=auto +*.sass text=auto +*.less text=auto +*.js text=auto +*.lisp text=auto +*.clj text=auto +*.sql text=auto +*.php text=auto +*.lua text=auto +*.m text=auto +*.asm text=auto +*.erl text=auto +*.fs text=auto +*.fsx text=auto +*.hs text=auto + +*.csproj text=auto +*.vbproj text=auto +*.fsproj text=auto +*.dbproj text=auto +*.sln text=auto eol=crlf diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000000..566f474fe8 --- /dev/null +++ b/.gitignore @@ -0,0 +1,28 @@ +[Oo]bj/ +[Bb]in/ +TestResults/ +.nuget/ +*.sln.ide/ +_ReSharper.*/ +packages/ +artifacts/ +PublishProfiles/ +*.user +*.suo +*.cache +*.docstates +_ReSharper.* +nuget.exe +project.lock.json +*net45.csproj +*net451.csproj +*k10.csproj +*.psess +*.vsp +*.pidb +*.userprefs +*DS_Store +*.ncrunchsolution +*.*sdf +*.ipch +.vs/ \ No newline at end of file diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000000..947bf868ee --- /dev/null +++ b/.travis.yml @@ -0,0 +1,4 @@ +language: csharp +sudo: false +script: + - ./build.sh --quiet verify \ No newline at end of file diff --git a/BasicMiddleware.sln b/BasicMiddleware.sln new file mode 100644 index 0000000000..ace965aa26 --- /dev/null +++ b/BasicMiddleware.sln @@ -0,0 +1,41 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 14 +VisualStudioVersion = 14.0.23018.0 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNet.HttpOverrides", "src\Microsoft.AspNet.HttpOverrides\Microsoft.AspNet.HttpOverrides.xproj", "{517308C3-B477-4B01-B461-CAB9C10B6928}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{A5076D28-FA7E-4606-9410-FEDD0D603527}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{8437B0F3-3894-4828-A945-A9187F37631D}" +EndProject +Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNet.HttpOverrides.Tests", "test\Microsoft.AspNet.HttpOverrides.Tests\Microsoft.AspNet.HttpOverrides.Tests.xproj", "{D6341B92-3416-4F11-8DF4-CB274296175F}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{99B72A07-32D6-434D-B44D-D064E3C13E08}" + ProjectSection(SolutionItems) = preProject + global.json = global.json + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {517308C3-B477-4B01-B461-CAB9C10B6928}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {517308C3-B477-4B01-B461-CAB9C10B6928}.Debug|Any CPU.Build.0 = Debug|Any CPU + {517308C3-B477-4B01-B461-CAB9C10B6928}.Release|Any CPU.ActiveCfg = Release|Any CPU + {517308C3-B477-4B01-B461-CAB9C10B6928}.Release|Any CPU.Build.0 = Release|Any CPU + {D6341B92-3416-4F11-8DF4-CB274296175F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D6341B92-3416-4F11-8DF4-CB274296175F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D6341B92-3416-4F11-8DF4-CB274296175F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D6341B92-3416-4F11-8DF4-CB274296175F}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {517308C3-B477-4B01-B461-CAB9C10B6928} = {A5076D28-FA7E-4606-9410-FEDD0D603527} + {D6341B92-3416-4F11-8DF4-CB274296175F} = {8437B0F3-3894-4828-A945-A9187F37631D} + EndGlobalSection +EndGlobal diff --git a/NuGet.Config b/NuGet.Config new file mode 100644 index 0000000000..da57d47267 --- /dev/null +++ b/NuGet.Config @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/appveyor.yml b/appveyor.yml new file mode 100644 index 0000000000..636a7618d3 --- /dev/null +++ b/appveyor.yml @@ -0,0 +1,7 @@ +init: + - git config --global core.autocrlf true +build_script: + - build.cmd --quiet verify +clone_depth: 1 +test: off +deploy: off \ No newline at end of file diff --git a/build.cmd b/build.cmd new file mode 100644 index 0000000000..41025afb26 --- /dev/null +++ b/build.cmd @@ -0,0 +1,28 @@ +@echo off +cd %~dp0 + +SETLOCAL +SET CACHED_NUGET=%LocalAppData%\NuGet\NuGet.exe + +IF EXIST %CACHED_NUGET% goto copynuget +echo Downloading latest version of NuGet.exe... +IF NOT EXIST %LocalAppData%\NuGet md %LocalAppData%\NuGet +@powershell -NoProfile -ExecutionPolicy unrestricted -Command "$ProgressPreference = 'SilentlyContinue'; Invoke-WebRequest 'https://www.nuget.org/nuget.exe' -OutFile '%CACHED_NUGET%'" + +:copynuget +IF EXIST .nuget\nuget.exe goto restore +md .nuget +copy %CACHED_NUGET% .nuget\nuget.exe > nul + +:restore +IF EXIST packages\KoreBuild goto run +.nuget\NuGet.exe install KoreBuild -ExcludeVersion -o packages -nocache -pre +.nuget\NuGet.exe install Sake -version 0.2 -o packages -ExcludeVersion + +IF "%SKIP_DNX_INSTALL%"=="1" goto run +CALL packages\KoreBuild\build\dnvm upgrade -runtime CLR -arch x86 +CALL packages\KoreBuild\build\dnvm install default -runtime CoreCLR -arch x86 + +:run +CALL packages\KoreBuild\build\dnvm use default -runtime CLR -arch x86 +packages\Sake\tools\Sake.exe -I packages\KoreBuild\build -f makefile.shade %* diff --git a/build.sh b/build.sh new file mode 100644 index 0000000000..3ef874f9bd --- /dev/null +++ b/build.sh @@ -0,0 +1,39 @@ +#!/usr/bin/env bash + +if test `uname` = Darwin; then + cachedir=~/Library/Caches/KBuild +else + if [ -z $XDG_DATA_HOME ]; then + cachedir=$HOME/.local/share + else + cachedir=$XDG_DATA_HOME; + fi +fi +mkdir -p $cachedir + +url=https://www.nuget.org/nuget.exe + +if test ! -f $cachedir/nuget.exe; then + wget -O $cachedir/nuget.exe $url 2>/dev/null || curl -o $cachedir/nuget.exe --location $url /dev/null +fi + +if test ! -e .nuget; then + mkdir .nuget + cp $cachedir/nuget.exe .nuget/nuget.exe +fi + +if test ! -d packages/KoreBuild; then + mono .nuget/nuget.exe install KoreBuild -ExcludeVersion -o packages -nocache -pre + mono .nuget/nuget.exe install Sake -version 0.2 -o packages -ExcludeVersion +fi + +if ! type dnvm > /dev/null 2>&1; then + source packages/KoreBuild/build/dnvm.sh +fi + +if ! type dnx > /dev/null 2>&1; then + dnvm upgrade +fi + +mono packages/Sake/tools/Sake.exe -I packages/KoreBuild/build -f makefile.shade "$@" + diff --git a/global.json b/global.json new file mode 100644 index 0000000000..b0323e4281 --- /dev/null +++ b/global.json @@ -0,0 +1,3 @@ +{ + "projects": [ "src" ] +} \ No newline at end of file diff --git a/makefile.shade b/makefile.shade new file mode 100644 index 0000000000..a612302092 --- /dev/null +++ b/makefile.shade @@ -0,0 +1,8 @@ +use namespace="System.Net" + +var VERSION='0.1' +var FULL_VERSION='0.1' +var AUTHORS='Microsoft Open Technologies, Inc.' + +use-standard-lifecycle +k-standard-goals \ No newline at end of file diff --git a/src/Microsoft.AspNet.HttpOverrides/ForwardedHeaders.cs b/src/Microsoft.AspNet.HttpOverrides/ForwardedHeaders.cs new file mode 100644 index 0000000000..5b5916212e --- /dev/null +++ b/src/Microsoft.AspNet.HttpOverrides/ForwardedHeaders.cs @@ -0,0 +1,17 @@ +// 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; + +namespace Microsoft.AspNet.HttpOverrides +{ + [Flags] + public enum ForwardedHeaders + { + None = 0, + XForwardedFor = 1 << 0, + XForwardedHost = 1 << 1, + XForwardedProto = 1 << 2, + All = XForwardedFor | XForwardedHost | XForwardedProto + } +} diff --git a/src/Microsoft.AspNet.HttpOverrides/HttpMethodOverrideExtensions.cs b/src/Microsoft.AspNet.HttpOverrides/HttpMethodOverrideExtensions.cs new file mode 100644 index 0000000000..42ae6e93b8 --- /dev/null +++ b/src/Microsoft.AspNet.HttpOverrides/HttpMethodOverrideExtensions.cs @@ -0,0 +1,31 @@ +// 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 Microsoft.AspNet.HttpOverrides; + +namespace Microsoft.AspNet.Builder +{ + public static class HttpMethodOverrideExtensions + { + /// + /// Allows incoming POST request to override method type with type specified in header. + /// + /// + /// + public static IApplicationBuilder UseHttpMethodOverride(this IApplicationBuilder builder) + { + return builder.Use(next => new HttpMethodOverrideMiddleware(next).Invoke); + } + + /// + /// Allows incoming POST request to override method type with type specified in form. + /// + /// + /// Denotes the element that contains the name of the resulting method type. + /// + public static IApplicationBuilder UseHttpMethodOverride(this IApplicationBuilder builder, string formFieldInput) + { + return builder.Use(next => new HttpMethodOverrideMiddleware(next, formFieldInput).Invoke); + } + } +} diff --git a/src/Microsoft.AspNet.HttpOverrides/HttpMethodOverrideMiddleware.cs b/src/Microsoft.AspNet.HttpOverrides/HttpMethodOverrideMiddleware.cs new file mode 100644 index 0000000000..8d805d80b8 --- /dev/null +++ b/src/Microsoft.AspNet.HttpOverrides/HttpMethodOverrideMiddleware.cs @@ -0,0 +1,51 @@ +// 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; +using System.Threading.Tasks; +using Microsoft.AspNet.Builder; +using Microsoft.AspNet.Http; + +namespace Microsoft.AspNet.HttpOverrides +{ + public class HttpMethodOverrideMiddleware + { + private const string xHttpMethodOverride = "X-Http-Method-Override"; + private readonly RequestDelegate _next; + private readonly string _formFieldName; + + public HttpMethodOverrideMiddleware(RequestDelegate next, string formFieldName = null) + { + _next = next; + _formFieldName = formFieldName; + } + + public async Task Invoke(HttpContext context) + { + if (string.Equals(context.Request.Method,"POST", StringComparison.OrdinalIgnoreCase)) + { + if (_formFieldName != null) + { + if (context.Request.HasFormContentType) + { + var form = await context.Request.ReadFormAsync(); + var methodType = form[_formFieldName]; + if (!string.IsNullOrEmpty(methodType)) + { + context.Request.Method = methodType; + } + } + } + else + { + var xHttpMethodOverrideValue = context.Request.Headers.Get(xHttpMethodOverride); + if (!string.IsNullOrEmpty(xHttpMethodOverrideValue)) + { + context.Request.Method = xHttpMethodOverrideValue; + } + } + } + await _next(context); + } + } +} diff --git a/src/Microsoft.AspNet.HttpOverrides/Microsoft.AspNet.HttpOverrides.xproj b/src/Microsoft.AspNet.HttpOverrides/Microsoft.AspNet.HttpOverrides.xproj new file mode 100644 index 0000000000..0037db59b2 --- /dev/null +++ b/src/Microsoft.AspNet.HttpOverrides/Microsoft.AspNet.HttpOverrides.xproj @@ -0,0 +1,17 @@ + + + + 14.0 + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) + + + + 517308c3-b477-4b01-b461-cab9c10b6928 + ..\..\artifacts\obj\$(MSBuildProjectName) + ..\..\artifacts\bin\$(MSBuildProjectName)\ + + + 2.0 + + + \ No newline at end of file diff --git a/src/Microsoft.AspNet.HttpOverrides/OverrideHeaderExtensions.cs b/src/Microsoft.AspNet.HttpOverrides/OverrideHeaderExtensions.cs new file mode 100644 index 0000000000..04acee970c --- /dev/null +++ b/src/Microsoft.AspNet.HttpOverrides/OverrideHeaderExtensions.cs @@ -0,0 +1,21 @@ +// 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 Microsoft.AspNet.HttpOverrides; + +namespace Microsoft.AspNet.Builder +{ + public static class OverrideHeaderExtensions + { + /// + /// Forwards proxied headers onto current request + /// + /// + /// Enables the different override options. + /// + public static IApplicationBuilder UseOverrideHeaders(this IApplicationBuilder builder, OverrideHeaderMiddlewareOptions options) + { + return builder.Use(next => new OverrideHeaderMiddleware(next, options).Invoke); + } + } +} diff --git a/src/Microsoft.AspNet.HttpOverrides/OverrideHeaderMiddleware.cs b/src/Microsoft.AspNet.HttpOverrides/OverrideHeaderMiddleware.cs new file mode 100644 index 0000000000..0071ac0da5 --- /dev/null +++ b/src/Microsoft.AspNet.HttpOverrides/OverrideHeaderMiddleware.cs @@ -0,0 +1,68 @@ +// 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; +using System.Net; +using System.Threading.Tasks; +using Microsoft.AspNet.Builder; +using Microsoft.AspNet.Http; +using Microsoft.Framework.Internal; + +namespace Microsoft.AspNet.HttpOverrides +{ + public class OverrideHeaderMiddleware + { + private const string XForwardedForHeaderName = "X-Forwarded-For"; + private const string XForwardedHostHeaderName = "X-Forwarded-Host"; + private const string XForwardedProtoHeaderName = "X-Forwarded-Proto"; + private readonly OverrideHeaderMiddlewareOptions _options; + private readonly RequestDelegate _next; + + public OverrideHeaderMiddleware([NotNull] RequestDelegate next, [NotNull] OverrideHeaderMiddlewareOptions options) + { + _options = options; + _next = next; + } + + public Task Invoke(HttpContext context) + { + if ((_options.ForwardedOptions & ForwardedHeaders.XForwardedFor) != 0) + { + var xForwardedForHeaderValue = context.Request.Headers.GetCommaSeparatedValues(XForwardedForHeaderName); + if (xForwardedForHeaderValue != null && xForwardedForHeaderValue.Count > 0) + { + IPAddress originalIPAddress; + if (IPAddress.TryParse(xForwardedForHeaderValue[0], out originalIPAddress)) + { + if (context.Connection.RemoteIpAddress != null) + { + var ipList = context.Request.Headers.Get(XForwardedForHeaderName); + context.Request.Headers.Set(XForwardedForHeaderName, (ipList + "," + context.Connection.RemoteIpAddress.ToString())); + } + context.Connection.RemoteIpAddress = originalIPAddress; + } + } + } + + if ((_options.ForwardedOptions & ForwardedHeaders.XForwardedHost) != 0) + { + var xForwardHostHeaderValue = context.Request.Headers.Get(XForwardedHostHeaderName); + if (!string.IsNullOrEmpty(xForwardHostHeaderValue)) + { + context.Request.Host = HostString.FromUriComponent(xForwardHostHeaderValue); + } + } + + if ((_options.ForwardedOptions & ForwardedHeaders.XForwardedProto) != 0) + { + var xForwardProtoHeaderValue = context.Request.Headers.Get(XForwardedProtoHeaderName); + if (!string.IsNullOrEmpty(xForwardProtoHeaderValue)) + { + context.Request.Scheme = xForwardProtoHeaderValue; + } + } + + return _next(context); + } + } +} diff --git a/src/Microsoft.AspNet.HttpOverrides/OverrideHeaderOptions.cs b/src/Microsoft.AspNet.HttpOverrides/OverrideHeaderOptions.cs new file mode 100644 index 0000000000..428408ab25 --- /dev/null +++ b/src/Microsoft.AspNet.HttpOverrides/OverrideHeaderOptions.cs @@ -0,0 +1,10 @@ +// 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. + +namespace Microsoft.AspNet.HttpOverrides +{ + public class OverrideHeaderMiddlewareOptions + { + public ForwardedHeaders ForwardedOptions { get; set; } + } +} diff --git a/src/Microsoft.AspNet.HttpOverrides/project.json b/src/Microsoft.AspNet.HttpOverrides/project.json new file mode 100644 index 0000000000..39c4937409 --- /dev/null +++ b/src/Microsoft.AspNet.HttpOverrides/project.json @@ -0,0 +1,19 @@ +{ + "version": "1.0.0-*", + "description": "XForward and Method override middlewares for ASP.NET", + "dependencies": { + "Microsoft.CSharp": "4.0.0-*", + "Microsoft.AspNet.Http.Abstractions": "1.0.0-*", + "Microsoft.Framework.NotNullAttribute.Sources": { "version": "1.0.0-*", "type": "build" } + }, + "frameworks": { + "dnx451": { }, + "dnxcore50": { + "dependencies": { + "System.Collections": "4.0.10-*", + "System.Linq": "4.0.0-*", + "System.Threading": "4.0.10-*" + } + } + } +} diff --git a/test/Microsoft.AspNet.HttpOverrides.Tests/HttpMethodOverrideMiddlewareTest.cs b/test/Microsoft.AspNet.HttpOverrides.Tests/HttpMethodOverrideMiddlewareTest.cs new file mode 100644 index 0000000000..de987a4e63 --- /dev/null +++ b/test/Microsoft.AspNet.HttpOverrides.Tests/HttpMethodOverrideMiddlewareTest.cs @@ -0,0 +1,73 @@ +// 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.Http; +using System.Threading.Tasks; +using Microsoft.AspNet.Builder; +using Microsoft.AspNet.TestHost; +using Xunit; + +namespace Microsoft.AspNet.HttpOverrides +{ + public class HttpMethodOverrideMiddlewareTest + { + [Fact] + public async Task XHttpMethodOverrideHeaderAvaiableChangesRequestMethod() + { + var assertsExecuted = false; + var server = TestServer.Create(app => + { + app.UseHttpMethodOverride(); + app.Run(context => + { + assertsExecuted = true; + Assert.Equal("DELETE", context.Request.Method); + return Task.FromResult(0); + }); + }); + + var req = new HttpRequestMessage(HttpMethod.Post, ""); + req.Headers.Add("X-Http-Method-Override", "DELETE"); + await server.CreateClient().SendAsync(req); + Assert.True(assertsExecuted); + } + + [Fact] + public async Task XHttpMethodOverrideHeaderUnavaiableDoesntChangeRequestMethod() + { + var assertsExecuted = false; + var server = TestServer.Create(app => + { + app.UseHttpMethodOverride(); + app.Run(context => + { + Assert.Equal("POST",context.Request.Method); + assertsExecuted = true; + return Task.FromResult(0); + }); + }); + var req = new HttpRequestMessage(HttpMethod.Post, ""); + await server.CreateClient().SendAsync(req); + Assert.True(assertsExecuted); + } + + [Fact] + public async Task XHttpMethodOverrideFromGetRequestDoesntChangeMethodType() + { + var assertsExecuted = false; + var server = TestServer.Create(app => + { + app.UseHttpMethodOverride(); + app.Run(context => + { + Assert.Equal("GET", context.Request.Method); + assertsExecuted = true; + return Task.FromResult(0); + }); + }); + var req = new HttpRequestMessage(HttpMethod.Get, ""); + await server.CreateClient().SendAsync(req); + Assert.True(assertsExecuted); + } + } +} diff --git a/test/Microsoft.AspNet.HttpOverrides.Tests/Microsoft.AspNet.HttpOverrides.Tests.xproj b/test/Microsoft.AspNet.HttpOverrides.Tests/Microsoft.AspNet.HttpOverrides.Tests.xproj new file mode 100644 index 0000000000..9889be51ad --- /dev/null +++ b/test/Microsoft.AspNet.HttpOverrides.Tests/Microsoft.AspNet.HttpOverrides.Tests.xproj @@ -0,0 +1,20 @@ + + + + 14.0 + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) + + + + d6341b92-3416-4f11-8df4-cb274296175f + ..\..\artifacts\obj\$(MSBuildProjectName) + ..\..\artifacts\bin\$(MSBuildProjectName)\ + + + 2.0 + + + + + + \ No newline at end of file diff --git a/test/Microsoft.AspNet.HttpOverrides.Tests/OverrideHeaderMiddlewareTest.cs b/test/Microsoft.AspNet.HttpOverrides.Tests/OverrideHeaderMiddlewareTest.cs new file mode 100644 index 0000000000..003033f5a1 --- /dev/null +++ b/test/Microsoft.AspNet.HttpOverrides.Tests/OverrideHeaderMiddlewareTest.cs @@ -0,0 +1,202 @@ +// 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.Http; +using System.Threading.Tasks; +using Microsoft.AspNet.Builder; +using Microsoft.AspNet.TestHost; +using Xunit; + +namespace Microsoft.AspNet.HttpOverrides +{ + public class OverrideMiddlewareHeaderTests + { + [Fact] + public async Task XForwardedForOverrideChangesRemoteIp() + { + var assertsExecuted = false; + var options = new OverrideHeaderMiddlewareOptions(); + options.ForwardedOptions = ForwardedHeaders.XForwardedFor; + + var server = TestServer.Create(app => + { + app.UseOverrideHeaders(options); + app.Run(context => + { + Assert.Equal("11.111.111.11", context.Connection.RemoteIpAddress.ToString()); + assertsExecuted = true; + return Task.FromResult(0); + }); + }); + + var req = new HttpRequestMessage(HttpMethod.Get, ""); + req.Headers.Add("X-Forwarded-For", "11.111.111.11"); + await server.CreateClient().SendAsync(req); + Assert.True(assertsExecuted); + } + + [Fact] + public async Task XForwardedForOverrideBadIpDoesntChangeRemoteIp() + { + var assertsExecuted = false; + var options = new OverrideHeaderMiddlewareOptions(); + options.ForwardedOptions = ForwardedHeaders.XForwardedFor; + + var server = TestServer.Create(app => + { + app.UseOverrideHeaders(options); + app.Run(context => + { + Assert.Null(context.Connection.RemoteIpAddress); + assertsExecuted = true; + return Task.FromResult(0); + }); + }); + + var req = new HttpRequestMessage(HttpMethod.Get, ""); + req.Headers.Add("X-Forwarded-For", "BAD-IP"); + await server.CreateClient().SendAsync(req); + Assert.True(assertsExecuted); + } + + [Fact] + public async Task XForwardedHostOverrideChangesRequestHost() + { + var assertsExecuted = false; + var options = new OverrideHeaderMiddlewareOptions(); + options.ForwardedOptions = ForwardedHeaders.XForwardedHost; + + var server = TestServer.Create(app => + { + app.UseOverrideHeaders(options); + app.Run(context => + { + Assert.Equal("testHost", context.Request.Host.ToString()); + assertsExecuted = true; + return Task.FromResult(0); + }); + }); + + var req = new HttpRequestMessage(HttpMethod.Get, ""); + req.Headers.Add("X-Forwarded-Host", "testHost"); + await server.CreateClient().SendAsync(req); + Assert.True(assertsExecuted); + } + + [Fact] + public async Task XForwardedProtoOverrideChangesRequestProtocol() + { + var assertsExecuted = false; + var options = new OverrideHeaderMiddlewareOptions(); + options.ForwardedOptions = ForwardedHeaders.XForwardedProto; + + var server = TestServer.Create(app => + { + app.UseOverrideHeaders(options); + app.Run(context => + { + Assert.Equal("TestProtocol", context.Request.Scheme); + assertsExecuted = true; + return Task.FromResult(0); + }); + }); + + var req = new HttpRequestMessage(HttpMethod.Get, ""); + req.Headers.Add("X-Forwarded-Proto", "TestProtocol"); + await server.CreateClient().SendAsync(req); + Assert.True(assertsExecuted); + } + + [Fact] + public void AllForwardsDisabledByDefault() + { + var options = new OverrideHeaderMiddlewareOptions(); + Assert.True(options.ForwardedOptions == 0); + } + + [Fact] + public async Task AllForwardsEnabledChangeRequestRemoteIpHostandProtocol() + { + var assertsExecuted = false; + var options = new OverrideHeaderMiddlewareOptions(); + options.ForwardedOptions = ForwardedHeaders.All; + + var server = TestServer.Create(app => + { + app.UseOverrideHeaders(options); + app.Run(context => + { + Assert.Equal("11.111.111.11", context.Connection.RemoteIpAddress.ToString()); + Assert.Equal("testHost", context.Request.Host.ToString()); + Assert.Equal("Protocol", context.Request.Scheme); + assertsExecuted = true; + return Task.FromResult(0); + }); + }); + + var req = new HttpRequestMessage(HttpMethod.Get, ""); + req.Headers.Add("X-Forwarded-For", "11.111.111.11"); + req.Headers.Add("X-Forwarded-Host", "testHost"); + req.Headers.Add("X-Forwarded-Proto", "Protocol"); + await server.CreateClient().SendAsync(req); + Assert.True(assertsExecuted); + } + + [Fact] + public async Task AllOptionsDisabledRequestDoesntChange() + { + var assertsExecuted = false; + var options = new OverrideHeaderMiddlewareOptions(); + options.ForwardedOptions = ForwardedHeaders.None; + + var server = TestServer.Create(app => + { + app.UseOverrideHeaders(options); + app.Run(context => + { + Assert.Null(context.Connection.RemoteIpAddress); + Assert.Equal("localhost", context.Request.Host.ToString()); + Assert.Equal("http", context.Request.Scheme); + assertsExecuted = true; + return Task.FromResult(0); + }); + }); + + var req = new HttpRequestMessage(HttpMethod.Get, ""); + req.Headers.Add("X-Forwarded-For", "11.111.111.11"); + req.Headers.Add("X-Forwarded-Host", "otherhost"); + req.Headers.Add("X-Forwarded-Proto", "Protocol"); + await server.CreateClient().SendAsync(req); + Assert.True(assertsExecuted); + } + + [Fact] + public async Task PartiallyEnabledForwardsPartiallyChangesRequest() + { + var assertsExecuted = false; + var XForwardedForAndProto = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto; + var options = new OverrideHeaderMiddlewareOptions(); + options.ForwardedOptions = XForwardedForAndProto; + + var server = TestServer.Create(app => + { + app.UseOverrideHeaders(options); + app.Run(context => + { + Assert.Equal("11.111.111.11", context.Connection.RemoteIpAddress.ToString()); + Assert.Equal("localhost", context.Request.Host.ToString()); + Assert.Equal("Protocol", context.Request.Scheme); + assertsExecuted = true; + return Task.FromResult(0); + + }); + }); + + var req = new HttpRequestMessage(HttpMethod.Get, ""); + req.Headers.Add("X-Forwarded-For", "11.111.111.11"); + req.Headers.Add("X-Forwarded-Proto", "Protocol"); + await server.CreateClient().SendAsync(req); + Assert.True(assertsExecuted); + } + } +} \ No newline at end of file diff --git a/test/Microsoft.AspNet.HttpOverrides.Tests/project.json b/test/Microsoft.AspNet.HttpOverrides.Tests/project.json new file mode 100644 index 0000000000..a83e0c4bc7 --- /dev/null +++ b/test/Microsoft.AspNet.HttpOverrides.Tests/project.json @@ -0,0 +1,23 @@ +{ + "version": "1.0.0-*", + "dependencies": { + "Microsoft.AspNet.HttpOverrides": "1.0.0-*", + "Microsoft.AspNet.TestHost": "1.0.0-*", + "Microsoft.Framework.Logging.Testing": "1.0.0-*", + "xunit.runner.aspnet": "2.0.0-aspnet-*" + }, + "commands": { + "test": "xunit.runner.aspnet" + }, + + "frameworks": { + "dnx451": { }, + "dnxcore50": { + "dependencies": { + "System.Collections": "4.0.10-*", + "System.Linq": "4.0.0-*", + "System.Threading": "4.0.10-*" + } + } + } +} From dd8d0aa078899157ffe8e5cdf000e3c7eb5b59d6 Mon Sep 17 00:00:00 2001 From: Hisham Abdullah Bin Ateya Date: Thu, 30 Jul 2015 07:51:55 +0300 Subject: [PATCH 003/307] Add repository information --- src/Microsoft.AspNet.HttpOverrides/project.json | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Microsoft.AspNet.HttpOverrides/project.json b/src/Microsoft.AspNet.HttpOverrides/project.json index 39c4937409..11697e5424 100644 --- a/src/Microsoft.AspNet.HttpOverrides/project.json +++ b/src/Microsoft.AspNet.HttpOverrides/project.json @@ -1,6 +1,10 @@ { "version": "1.0.0-*", "description": "XForward and Method override middlewares for ASP.NET", + "repository": { + "type": "git", + "url": "git://github.com/aspnet/basicmiddleware" + }, "dependencies": { "Microsoft.CSharp": "4.0.0-*", "Microsoft.AspNet.Http.Abstractions": "1.0.0-*", From ab56ac6038780e038919177a3a2d377a117803c5 Mon Sep 17 00:00:00 2001 From: Mikael Mengistu Date: Mon, 3 Aug 2015 10:44:02 -0700 Subject: [PATCH 004/307] Added headers to store original IP, host, and protocol values --- .../OverrideHeaderMiddleware.cs | 24 ++++++++++++++----- 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/src/Microsoft.AspNet.HttpOverrides/OverrideHeaderMiddleware.cs b/src/Microsoft.AspNet.HttpOverrides/OverrideHeaderMiddleware.cs index 0071ac0da5..7f6d1a3edd 100644 --- a/src/Microsoft.AspNet.HttpOverrides/OverrideHeaderMiddleware.cs +++ b/src/Microsoft.AspNet.HttpOverrides/OverrideHeaderMiddleware.cs @@ -15,6 +15,9 @@ namespace Microsoft.AspNet.HttpOverrides private const string XForwardedForHeaderName = "X-Forwarded-For"; private const string XForwardedHostHeaderName = "X-Forwarded-Host"; private const string XForwardedProtoHeaderName = "X-Forwarded-Proto"; + private const string XOriginalIPName = "X-Original-IP"; + private const string XOriginalHostName = "X-Original-Host"; + private const string XOriginalProtoName = "X-Original-Proto"; private readonly OverrideHeaderMiddlewareOptions _options; private readonly RequestDelegate _next; @@ -31,15 +34,15 @@ namespace Microsoft.AspNet.HttpOverrides var xForwardedForHeaderValue = context.Request.Headers.GetCommaSeparatedValues(XForwardedForHeaderName); if (xForwardedForHeaderValue != null && xForwardedForHeaderValue.Count > 0) { - IPAddress originalIPAddress; - if (IPAddress.TryParse(xForwardedForHeaderValue[0], out originalIPAddress)) + IPAddress ipFromHeader; + if (IPAddress.TryParse(xForwardedForHeaderValue[0], out ipFromHeader)) { - if (context.Connection.RemoteIpAddress != null) + var remoteIPString = context.Connection.RemoteIpAddress?.ToString(); + if (!string.IsNullOrEmpty(remoteIPString)) { - var ipList = context.Request.Headers.Get(XForwardedForHeaderName); - context.Request.Headers.Set(XForwardedForHeaderName, (ipList + "," + context.Connection.RemoteIpAddress.ToString())); + context.Request.Headers.Set(XOriginalIPName, remoteIPString); } - context.Connection.RemoteIpAddress = originalIPAddress; + context.Connection.RemoteIpAddress = ipFromHeader; } } } @@ -49,6 +52,11 @@ namespace Microsoft.AspNet.HttpOverrides var xForwardHostHeaderValue = context.Request.Headers.Get(XForwardedHostHeaderName); if (!string.IsNullOrEmpty(xForwardHostHeaderValue)) { + var hostString = context.Request.Host.ToString(); + if (!string.IsNullOrEmpty(hostString)) + { + context.Request.Headers.Set(XOriginalHostName, hostString); + } context.Request.Host = HostString.FromUriComponent(xForwardHostHeaderValue); } } @@ -58,6 +66,10 @@ namespace Microsoft.AspNet.HttpOverrides var xForwardProtoHeaderValue = context.Request.Headers.Get(XForwardedProtoHeaderName); if (!string.IsNullOrEmpty(xForwardProtoHeaderValue)) { + if (!string.IsNullOrEmpty(context.Request.Scheme)) + { + context.Request.Headers.Set(XOriginalProtoName, context.Request.Scheme); + } context.Request.Scheme = xForwardProtoHeaderValue; } } From c88e7f5a44d059e173fb752760ddd316b85ea6df Mon Sep 17 00:00:00 2001 From: Kiran Challa Date: Wed, 12 Aug 2015 05:43:29 -0700 Subject: [PATCH 005/307] Enable pinning build script --- build.cmd | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/build.cmd b/build.cmd index 41025afb26..ccf195aee8 100644 --- a/build.cmd +++ b/build.cmd @@ -3,6 +3,8 @@ cd %~dp0 SETLOCAL SET CACHED_NUGET=%LocalAppData%\NuGet\NuGet.exe +SET BUILDCMD_KOREBUILD_VERSION="" +SET BUILDCMD_DNX_VERSION="" IF EXIST %CACHED_NUGET% goto copynuget echo Downloading latest version of NuGet.exe... @@ -16,13 +18,21 @@ copy %CACHED_NUGET% .nuget\nuget.exe > nul :restore IF EXIST packages\KoreBuild goto run -.nuget\NuGet.exe install KoreBuild -ExcludeVersion -o packages -nocache -pre +IF %BUILDCMD_KOREBUILD_VERSION%=="" ( + .nuget\NuGet.exe install KoreBuild -ExcludeVersion -o packages -nocache -pre +) ELSE ( + .nuget\NuGet.exe install KoreBuild -version %BUILDCMD_KOREBUILD_VERSION% -ExcludeVersion -o packages -nocache -pre +) .nuget\NuGet.exe install Sake -version 0.2 -o packages -ExcludeVersion IF "%SKIP_DNX_INSTALL%"=="1" goto run -CALL packages\KoreBuild\build\dnvm upgrade -runtime CLR -arch x86 +IF %BUILDCMD_DNX_VERSION%=="" ( + CALL packages\KoreBuild\build\dnvm upgrade -runtime CLR -arch x86 +) ELSE ( + CALL packages\KoreBuild\build\dnvm install %BUILDCMD_DNX_VERSION% -runtime CLR -arch x86 -a default +) CALL packages\KoreBuild\build\dnvm install default -runtime CoreCLR -arch x86 :run CALL packages\KoreBuild\build\dnvm use default -runtime CLR -arch x86 -packages\Sake\tools\Sake.exe -I packages\KoreBuild\build -f makefile.shade %* +packages\Sake\tools\Sake.exe -I packages\KoreBuild\build -f makefile.shade %* \ No newline at end of file From c91cc89ee32ed2160b71c964fbe1fe8b98b5829f Mon Sep 17 00:00:00 2001 From: Chris R Date: Fri, 31 Jul 2015 16:30:31 -0700 Subject: [PATCH 006/307] ResponseBuffering middleware initial checkin. Restrict buffer to reset. Add sample. Cleanup. --- BasicMiddleware.sln | 25 +- .../Properties/launchSettings.json | 21 ++ .../ResponseBufferingSample.xproj | 19 ++ samples/ResponseBufferingSample/Startup.cs | 36 +++ samples/ResponseBufferingSample/project.json | 30 ++ .../BufferingWriteStream.cs | 218 +++++++++++++ .../HttpBufferingFeature.cs | 30 ++ .../Microsoft.AspNet.Buffering.xproj | 20 ++ .../ResponseBufferingMiddleware.cs | 66 ++++ .../ResponseBufferingMiddlewareExtensions.cs | 20 ++ .../SendFileFeatureWrapper.cs | 28 ++ src/Microsoft.AspNet.Buffering/project.json | 18 ++ .../Microsoft.AspNet.Buffering.Tests.xproj | 20 ++ .../ResponseBufferingMiddlewareTests.cs | 298 ++++++++++++++++++ .../project.json | 22 ++ 15 files changed, 870 insertions(+), 1 deletion(-) create mode 100644 samples/ResponseBufferingSample/Properties/launchSettings.json create mode 100644 samples/ResponseBufferingSample/ResponseBufferingSample.xproj create mode 100644 samples/ResponseBufferingSample/Startup.cs create mode 100644 samples/ResponseBufferingSample/project.json create mode 100644 src/Microsoft.AspNet.Buffering/BufferingWriteStream.cs create mode 100644 src/Microsoft.AspNet.Buffering/HttpBufferingFeature.cs create mode 100644 src/Microsoft.AspNet.Buffering/Microsoft.AspNet.Buffering.xproj create mode 100644 src/Microsoft.AspNet.Buffering/ResponseBufferingMiddleware.cs create mode 100644 src/Microsoft.AspNet.Buffering/ResponseBufferingMiddlewareExtensions.cs create mode 100644 src/Microsoft.AspNet.Buffering/SendFileFeatureWrapper.cs create mode 100644 src/Microsoft.AspNet.Buffering/project.json create mode 100644 test/Microsoft.AspNet.Buffering.Tests/Microsoft.AspNet.Buffering.Tests.xproj create mode 100644 test/Microsoft.AspNet.Buffering.Tests/ResponseBufferingMiddlewareTests.cs create mode 100644 test/Microsoft.AspNet.Buffering.Tests/project.json diff --git a/BasicMiddleware.sln b/BasicMiddleware.sln index ace965aa26..d589e2f092 100644 --- a/BasicMiddleware.sln +++ b/BasicMiddleware.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 14 -VisualStudioVersion = 14.0.23018.0 +VisualStudioVersion = 14.0.23107.0 MinimumVisualStudioVersion = 10.0.40219.1 Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNet.HttpOverrides", "src\Microsoft.AspNet.HttpOverrides\Microsoft.AspNet.HttpOverrides.xproj", "{517308C3-B477-4B01-B461-CAB9C10B6928}" EndProject @@ -16,6 +16,14 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution global.json = global.json EndProjectSection EndProject +Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNet.Buffering", "src\Microsoft.AspNet.Buffering\Microsoft.AspNet.Buffering.xproj", "{2363D0DD-A3BF-437E-9B64-B33AE132D875}" +EndProject +Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNet.Buffering.Tests", "test\Microsoft.AspNet.Buffering.Tests\Microsoft.AspNet.Buffering.Tests.xproj", "{F5F1D123-9C81-4A9E-8644-AA46B8E578FB}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "samples", "samples", "{9587FE9F-5A17-42C4-8021-E87F59CECB98}" +EndProject +Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "ResponseBufferingSample", "samples\ResponseBufferingSample\ResponseBufferingSample.xproj", "{E5C55B80-7827-40EB-B661-32B0E0E431CA}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -30,6 +38,18 @@ Global {D6341B92-3416-4F11-8DF4-CB274296175F}.Debug|Any CPU.Build.0 = Debug|Any CPU {D6341B92-3416-4F11-8DF4-CB274296175F}.Release|Any CPU.ActiveCfg = Release|Any CPU {D6341B92-3416-4F11-8DF4-CB274296175F}.Release|Any CPU.Build.0 = Release|Any CPU + {2363D0DD-A3BF-437E-9B64-B33AE132D875}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {2363D0DD-A3BF-437E-9B64-B33AE132D875}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2363D0DD-A3BF-437E-9B64-B33AE132D875}.Release|Any CPU.ActiveCfg = Release|Any CPU + {2363D0DD-A3BF-437E-9B64-B33AE132D875}.Release|Any CPU.Build.0 = Release|Any CPU + {F5F1D123-9C81-4A9E-8644-AA46B8E578FB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F5F1D123-9C81-4A9E-8644-AA46B8E578FB}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F5F1D123-9C81-4A9E-8644-AA46B8E578FB}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F5F1D123-9C81-4A9E-8644-AA46B8E578FB}.Release|Any CPU.Build.0 = Release|Any CPU + {E5C55B80-7827-40EB-B661-32B0E0E431CA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E5C55B80-7827-40EB-B661-32B0E0E431CA}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E5C55B80-7827-40EB-B661-32B0E0E431CA}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E5C55B80-7827-40EB-B661-32B0E0E431CA}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -37,5 +57,8 @@ Global GlobalSection(NestedProjects) = preSolution {517308C3-B477-4B01-B461-CAB9C10B6928} = {A5076D28-FA7E-4606-9410-FEDD0D603527} {D6341B92-3416-4F11-8DF4-CB274296175F} = {8437B0F3-3894-4828-A945-A9187F37631D} + {2363D0DD-A3BF-437E-9B64-B33AE132D875} = {A5076D28-FA7E-4606-9410-FEDD0D603527} + {F5F1D123-9C81-4A9E-8644-AA46B8E578FB} = {8437B0F3-3894-4828-A945-A9187F37631D} + {E5C55B80-7827-40EB-B661-32B0E0E431CA} = {9587FE9F-5A17-42C4-8021-E87F59CECB98} EndGlobalSection EndGlobal diff --git a/samples/ResponseBufferingSample/Properties/launchSettings.json b/samples/ResponseBufferingSample/Properties/launchSettings.json new file mode 100644 index 0000000000..0e57697bac --- /dev/null +++ b/samples/ResponseBufferingSample/Properties/launchSettings.json @@ -0,0 +1,21 @@ +{ + "profiles": { + "IIS Express": { + "commandName": "IISExpress", + "launchBrowser": true, + "environmentVariables": { + "ASPNET_ENV": "Development" + } + }, + "web": { + "commandName": "web", + "launchBrowser": true, + "launchUrl": "http://localhost:5000/" + }, + "kestrel": { + "commandName": "kestrel", + "launchBrowser": true, + "launchUrl": "http://localhost:5001/" + } + } +} \ No newline at end of file diff --git a/samples/ResponseBufferingSample/ResponseBufferingSample.xproj b/samples/ResponseBufferingSample/ResponseBufferingSample.xproj new file mode 100644 index 0000000000..9026942e3d --- /dev/null +++ b/samples/ResponseBufferingSample/ResponseBufferingSample.xproj @@ -0,0 +1,19 @@ + + + + 14.0 + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) + + + + e5c55b80-7827-40eb-b661-32b0e0e431ca + ResponseBufferingSample + ..\..\artifacts\obj\$(MSBuildProjectName) + ..\..\artifacts\bin\$(MSBuildProjectName)\ + + + 2.0 + 46823 + + + \ No newline at end of file diff --git a/samples/ResponseBufferingSample/Startup.cs b/samples/ResponseBufferingSample/Startup.cs new file mode 100644 index 0000000000..46626e8065 --- /dev/null +++ b/samples/ResponseBufferingSample/Startup.cs @@ -0,0 +1,36 @@ +using Microsoft.AspNet.Builder; +using Microsoft.AspNet.Http; +using Microsoft.Framework.DependencyInjection; + +namespace ResponseBufferingSample +{ + public class Startup + { + // For more information on how to configure your application, visit http://go.microsoft.com/fwlink/?LinkID=398940 + public void ConfigureServices(IServiceCollection services) + { + } + + public void Configure(IApplicationBuilder app) + { + app.UseResponseBuffering(); + app.Run(async (context) => + { + // Write some stuff + context.Response.ContentType = "text/other"; + await context.Response.WriteAsync("Hello World!"); + + // ... more work ... + + // Something went wrong and we want to replace the response + context.Response.StatusCode = 200; + context.Response.Headers.Clear(); + context.Response.Body.SetLength(0); + + // Try again + context.Response.ContentType = "text/plain"; + await context.Response.WriteAsync("Hi Bob!"); + }); + } + } +} diff --git a/samples/ResponseBufferingSample/project.json b/samples/ResponseBufferingSample/project.json new file mode 100644 index 0000000000..f43d9ec282 --- /dev/null +++ b/samples/ResponseBufferingSample/project.json @@ -0,0 +1,30 @@ +{ + "webroot": "wwwroot", + "version": "1.0.0-*", + "dependencies": { + "Kestrel": "1.0.0-*", + "Microsoft.AspNet.Buffering": "1.0.0-*", + "Microsoft.AspNet.Server.IIS": "1.0.0-*", + "Microsoft.AspNet.Server.WebListener": "1.0.0-*" + }, + "commands": { + "web": "Microsoft.AspNet.Server.WebListener --server.urls=http://localhost:5000", + "kestrel": "Kestrel --server.urls=http://localhost:5001" + }, + "frameworks": { + "dnx451": { }, + "dnxcore50": { } + }, + "publishExclude": [ + "node_modules", + "bower_components", + "**.xproj", + "**.user", + "**.vspscc" + ], + "exclude": [ + "wwwroot", + "node_modules", + "bower_components" + ] +} diff --git a/src/Microsoft.AspNet.Buffering/BufferingWriteStream.cs b/src/Microsoft.AspNet.Buffering/BufferingWriteStream.cs new file mode 100644 index 0000000000..d8a04d1cdc --- /dev/null +++ b/src/Microsoft.AspNet.Buffering/BufferingWriteStream.cs @@ -0,0 +1,218 @@ +// 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; +using System.IO; +using System.Threading; +using System.Threading.Tasks; + +namespace Microsoft.AspNet.Buffering +{ + internal class BufferingWriteStream : Stream + { + private readonly Stream _innerStream; + private readonly MemoryStream _buffer = new MemoryStream(); + private bool _isBuffering = true; + + public BufferingWriteStream(Stream innerStream) + { + _innerStream = innerStream; + } + + public override bool CanRead + { + get { return false; } + } + + public override bool CanSeek + { + get { return _isBuffering; } + } + + public override bool CanWrite + { + get { return _innerStream.CanWrite; } + } + + public override long Length + { + get + { + if (_isBuffering) + { + return _buffer.Length; + } + // May throw + return _innerStream.Length; + } + } + + // Clear/Reset the buffer by setting Position, Seek, or SetLength to 0. Random access is not supported. + public override long Position + { + get + { + if (_isBuffering) + { + return _buffer.Position; + } + // May throw + return _innerStream.Position; + } + set + { + if (_isBuffering) + { + if (value != 0) + { + throw new ArgumentOutOfRangeException(nameof(value), value, nameof(Position) + " can only be set to 0."); + } + _buffer.Position = value; + _buffer.SetLength(value); + } + else + { + // May throw + _innerStream.Position = value; + } + } + } + + // Clear/Reset the buffer by setting Position, Seek, or SetLength to 0. Random access is not supported. + public override void SetLength(long value) + { + if (_isBuffering) + { + if (value != 0) + { + throw new ArgumentOutOfRangeException(nameof(value), value, nameof(Length) + " can only be set to 0."); + } + _buffer.Position = value; + _buffer.SetLength(value); + } + else + { + // May throw + _innerStream.SetLength(value); + } + } + + // Clear/Reset the buffer by setting Position, Seek, or SetLength to 0. Random access is not supported. + public override long Seek(long offset, SeekOrigin origin) + { + if (_isBuffering) + { + if (origin != SeekOrigin.Begin) + { + throw new ArgumentException(nameof(origin), nameof(Seek) + " can only be set to " + nameof(SeekOrigin.Begin) + "."); + } + if (offset != 0) + { + throw new ArgumentOutOfRangeException(nameof(offset), offset, nameof(Seek) + " can only be set to 0."); + } + _buffer.SetLength(offset); + return _buffer.Seek(offset, origin); + } + // Try the inner stream instead, but this will usually fail. + return _innerStream.Seek(offset, origin); + } + + internal void DisableBuffering() + { + _isBuffering = false; + if (_buffer.Length > 0) + { + Flush(); + } + } + + internal Task DisableBufferingAsync(CancellationToken cancellationToken) + { + _isBuffering = false; + if (_buffer.Length > 0) + { + return FlushAsync(cancellationToken); + } + return Task.FromResult(0); + } + + public override void Write(byte[] buffer, int offset, int count) + { + if (_isBuffering) + { + _buffer.Write(buffer, offset, count); + } + else + { + _innerStream.Write(buffer, offset, count); + } + } + + public override Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) + { + if (_isBuffering) + { + return _buffer.WriteAsync(buffer, offset, count, cancellationToken); + } + else + { + return _innerStream.WriteAsync(buffer, offset, count, cancellationToken); + } + } +#if !DNXCORE50 + public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object state) + { + if (_isBuffering) + { + return _buffer.BeginWrite(buffer, offset, count, callback, state); + } + else + { + return _innerStream.BeginWrite(buffer, offset, count, callback, state); + } + } + + public override void EndWrite(IAsyncResult asyncResult) + { + if (_isBuffering) + { + _buffer.EndWrite(asyncResult); + } + else + { + _innerStream.EndWrite(asyncResult); + } + } +#endif + public override void Flush() + { + _isBuffering = false; + if (_buffer.Length > 0) + { + _buffer.Seek(0, SeekOrigin.Begin); + _buffer.CopyTo(_innerStream); + _buffer.Seek(0, SeekOrigin.Begin); + _buffer.SetLength(0); + } + _innerStream.Flush(); + } + + public override async Task FlushAsync(CancellationToken cancellationToken) + { + _isBuffering = false; + if (_buffer.Length > 0) + { + _buffer.Seek(0, SeekOrigin.Begin); + await _buffer.CopyToAsync(_innerStream, 1024 * 16, cancellationToken); + _buffer.Seek(0, SeekOrigin.Begin); + _buffer.SetLength(0); + } + await _innerStream.FlushAsync(cancellationToken); + } + + public override int Read(byte[] buffer, int offset, int count) + { + throw new NotSupportedException("This Stream only supports Write operations."); + } + } +} diff --git a/src/Microsoft.AspNet.Buffering/HttpBufferingFeature.cs b/src/Microsoft.AspNet.Buffering/HttpBufferingFeature.cs new file mode 100644 index 0000000000..785f73e4e5 --- /dev/null +++ b/src/Microsoft.AspNet.Buffering/HttpBufferingFeature.cs @@ -0,0 +1,30 @@ +// 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 Microsoft.AspNet.Http.Features; + +namespace Microsoft.AspNet.Buffering +{ + internal class HttpBufferingFeature : IHttpBufferingFeature + { + private readonly BufferingWriteStream _buffer; + private readonly IHttpBufferingFeature _innerFeature; + + internal HttpBufferingFeature(BufferingWriteStream buffer, IHttpBufferingFeature innerFeature) + { + _buffer = buffer; + _innerFeature = innerFeature; + } + + public void DisableRequestBuffering() + { + _innerFeature?.DisableRequestBuffering(); + } + + public void DisableResponseBuffering() + { + _buffer.DisableBuffering(); + _innerFeature?.DisableResponseBuffering(); + } + } +} diff --git a/src/Microsoft.AspNet.Buffering/Microsoft.AspNet.Buffering.xproj b/src/Microsoft.AspNet.Buffering/Microsoft.AspNet.Buffering.xproj new file mode 100644 index 0000000000..bc40210bfc --- /dev/null +++ b/src/Microsoft.AspNet.Buffering/Microsoft.AspNet.Buffering.xproj @@ -0,0 +1,20 @@ + + + + 14.0 + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) + + + + + 2363d0dd-a3bf-437e-9b64-b33ae132d875 + Microsoft.AspNet.Buffering + ..\..\artifacts\obj\$(MSBuildProjectName) + ..\..\artifacts\bin\$(MSBuildProjectName)\ + + + + 2.0 + + + diff --git a/src/Microsoft.AspNet.Buffering/ResponseBufferingMiddleware.cs b/src/Microsoft.AspNet.Buffering/ResponseBufferingMiddleware.cs new file mode 100644 index 0000000000..ec3a230146 --- /dev/null +++ b/src/Microsoft.AspNet.Buffering/ResponseBufferingMiddleware.cs @@ -0,0 +1,66 @@ +// 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.Threading.Tasks; +using Microsoft.AspNet.Builder; +using Microsoft.AspNet.Http; +using Microsoft.AspNet.Http.Features; + +namespace Microsoft.AspNet.Buffering +{ + public class ResponseBufferingMiddleware + { + private readonly RequestDelegate _next; + + public ResponseBufferingMiddleware(RequestDelegate next) + { + _next = next; + } + + public async Task Invoke(HttpContext httpContext) + { + var originalResponseBody = httpContext.Response.Body; + + // no-op if buffering is already available. + if (originalResponseBody.CanSeek) + { + await _next(httpContext); + return; + } + + var originalBufferingFeature = httpContext.GetFeature(); + var originalSendFileFeature = httpContext.GetFeature(); + try + { + // Shim the response stream + var bufferStream = new BufferingWriteStream(originalResponseBody); + httpContext.Response.Body = bufferStream; + httpContext.SetFeature(new HttpBufferingFeature(bufferStream, originalBufferingFeature)); + if (originalSendFileFeature != null) + { + httpContext.SetFeature(new SendFileFeatureWrapper(originalSendFileFeature, bufferStream)); + } + + await _next(httpContext); + + // If we're still buffered, set the content-length header and flush the buffer. + // Only if the content-length header is not already set, and some content was buffered. + if (!httpContext.Response.HasStarted && bufferStream.CanSeek && bufferStream.Length > 0) + { + if (!httpContext.Response.ContentLength.HasValue) + { + httpContext.Response.ContentLength = bufferStream.Length; + } + await bufferStream.FlushAsync(); + } + } + finally + { + // undo everything + httpContext.SetFeature(originalBufferingFeature); + httpContext.SetFeature(originalSendFileFeature); + httpContext.Response.Body = originalResponseBody; + } + } + } +} diff --git a/src/Microsoft.AspNet.Buffering/ResponseBufferingMiddlewareExtensions.cs b/src/Microsoft.AspNet.Buffering/ResponseBufferingMiddlewareExtensions.cs new file mode 100644 index 0000000000..77a37d1658 --- /dev/null +++ b/src/Microsoft.AspNet.Buffering/ResponseBufferingMiddlewareExtensions.cs @@ -0,0 +1,20 @@ +// 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 Microsoft.AspNet.Buffering; + +namespace Microsoft.AspNet.Builder +{ + public static class ResponseBufferingMiddlewareExtensions + { + /// + /// Enables full buffering of response bodies. This can be disabled on a per request basis using IHttpBufferingFeature. + /// + /// + /// + public static IApplicationBuilder UseResponseBuffering(this IApplicationBuilder builder) + { + return builder.UseMiddleware(); + } + } +} diff --git a/src/Microsoft.AspNet.Buffering/SendFileFeatureWrapper.cs b/src/Microsoft.AspNet.Buffering/SendFileFeatureWrapper.cs new file mode 100644 index 0000000000..e3daff187f --- /dev/null +++ b/src/Microsoft.AspNet.Buffering/SendFileFeatureWrapper.cs @@ -0,0 +1,28 @@ +// 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.Threading; +using System.Threading.Tasks; +using Microsoft.AspNet.Http.Features; + +namespace Microsoft.AspNet.Buffering +{ + internal class SendFileFeatureWrapper : IHttpSendFileFeature + { + private readonly IHttpSendFileFeature _originalSendFileFeature; + private readonly BufferingWriteStream _bufferStream; + + public SendFileFeatureWrapper(IHttpSendFileFeature originalSendFileFeature, BufferingWriteStream bufferStream) + { + _originalSendFileFeature = originalSendFileFeature; + _bufferStream = bufferStream; + } + + // Flush and disable the buffer if anyone tries to call the SendFile feature. + public async Task SendFileAsync(string path, long offset, long? length, CancellationToken cancellation) + { + await _bufferStream.DisableBufferingAsync(cancellation); + await _originalSendFileFeature.SendFileAsync(path, offset, length, cancellation); + } + } +} \ No newline at end of file diff --git a/src/Microsoft.AspNet.Buffering/project.json b/src/Microsoft.AspNet.Buffering/project.json new file mode 100644 index 0000000000..9df583e0d5 --- /dev/null +++ b/src/Microsoft.AspNet.Buffering/project.json @@ -0,0 +1,18 @@ +{ + "version": "1.0.0-*", + "description": "ASP.NET middleware for buffering response bodies.", + "repository": { + "type": "git", + "url": "git://github.com/aspnet/basicmiddleware" + }, + "dependencies": { + "Microsoft.AspNet.Http.Abstractions": "1.0.0-*" + }, + "frameworks": { + "dnx451": { }, + "dnxcore50": { + "dependencies": { + } + } + } +} diff --git a/test/Microsoft.AspNet.Buffering.Tests/Microsoft.AspNet.Buffering.Tests.xproj b/test/Microsoft.AspNet.Buffering.Tests/Microsoft.AspNet.Buffering.Tests.xproj new file mode 100644 index 0000000000..16b38cf3d8 --- /dev/null +++ b/test/Microsoft.AspNet.Buffering.Tests/Microsoft.AspNet.Buffering.Tests.xproj @@ -0,0 +1,20 @@ + + + + 14.0 + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) + + + + + f5f1d123-9c81-4a9e-8644-aa46b8e578fb + Microsoft.AspNet.Buffering.Tests + ..\..\artifacts\obj\$(MSBuildProjectName) + ..\..\artifacts\bin\$(MSBuildProjectName)\ + + + + 2.0 + + + diff --git a/test/Microsoft.AspNet.Buffering.Tests/ResponseBufferingMiddlewareTests.cs b/test/Microsoft.AspNet.Buffering.Tests/ResponseBufferingMiddlewareTests.cs new file mode 100644 index 0000000000..ee7431ec28 --- /dev/null +++ b/test/Microsoft.AspNet.Buffering.Tests/ResponseBufferingMiddlewareTests.cs @@ -0,0 +1,298 @@ +// 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; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.AspNet.Builder; +using Microsoft.AspNet.Http; +using Microsoft.AspNet.Http.Features; +using Microsoft.AspNet.TestHost; +using Xunit; + +namespace Microsoft.AspNet.Buffering.Tests +{ + public class ResponseBufferingMiddlewareTests + { + [Fact] + public async Task BufferResponse_SetsContentLength() + { + var server = TestServer.Create(app => + { + app.UseResponseBuffering(); + app.Run(async context => + { + Assert.False(context.Response.HasStarted); + Assert.True(context.Response.Body.CanSeek); + await context.Response.WriteAsync("Hello World"); + Assert.False(context.Response.HasStarted); + Assert.True(context.Response.Body.CanSeek); + }); + }); + + var response = await server.CreateClient().GetAsync(""); + response.EnsureSuccessStatusCode(); + Assert.Equal("Hello World", await response.Content.ReadAsStringAsync()); + + // Set automatically by buffer + IEnumerable values; + Assert.True(response.Content.Headers.TryGetValues("Content-Length", out values)); + Assert.Equal("11", values.FirstOrDefault()); + } + + [Fact] + public async Task BufferResponseWithManualContentLength_NotReplaced() + { + var server = TestServer.Create(app => + { + app.UseResponseBuffering(); + app.Run(async context => + { + context.Response.ContentLength = 12; + Assert.False(context.Response.HasStarted); + Assert.True(context.Response.Body.CanSeek); + await context.Response.WriteAsync("Hello World"); + Assert.False(context.Response.HasStarted); + Assert.True(context.Response.Body.CanSeek); + }); + }); + + var response = await server.CreateClient().GetAsync(""); + response.EnsureSuccessStatusCode(); + Assert.Equal("Hello World", await response.Content.ReadAsStringAsync()); + + IEnumerable values; + Assert.True(response.Content.Headers.TryGetValues("Content-Length", out values)); + Assert.Equal("12", values.FirstOrDefault()); + } + + [Fact] + public async Task Seek_AllowsResttingBuffer() + { + var server = TestServer.Create(app => + { + app.UseResponseBuffering(); + app.Run(async context => + { + var body = context.Response.Body; + Assert.False(context.Response.HasStarted); + Assert.True(body.CanSeek); + Assert.Equal(0, body.Position); + Assert.Equal(0, body.Length); + + await context.Response.WriteAsync("Hello World"); + Assert.False(context.Response.HasStarted); + Assert.True(context.Response.Body.CanSeek); + Assert.Equal(11, body.Position); + Assert.Equal(11, body.Length); + + Assert.Throws(() => body.Seek(1, SeekOrigin.Begin)); + Assert.Throws(() => body.Seek(0, SeekOrigin.Current)); + Assert.Throws(() => body.Seek(0, SeekOrigin.End)); + + Assert.Equal(0, body.Seek(0, SeekOrigin.Begin)); + Assert.Equal(0, body.Position); + Assert.Equal(0, body.Length); + + await context.Response.WriteAsync("12345"); + Assert.Equal(5, body.Position); + Assert.Equal(5, body.Length); + }); + }); + + var response = await server.CreateClient().GetAsync(""); + response.EnsureSuccessStatusCode(); + Assert.Equal("12345", await response.Content.ReadAsStringAsync()); + + // Set automatically by buffer + IEnumerable values; + Assert.True(response.Content.Headers.TryGetValues("Content-Length", out values)); + Assert.Equal("5", values.FirstOrDefault()); + } + + [Fact] + public async Task SetPosition_AllowsResttingBuffer() + { + var server = TestServer.Create(app => + { + app.UseResponseBuffering(); + app.Run(async context => + { + var body = context.Response.Body; + Assert.False(context.Response.HasStarted); + Assert.True(body.CanSeek); + Assert.Equal(0, body.Position); + Assert.Equal(0, body.Length); + + await context.Response.WriteAsync("Hello World"); + Assert.False(context.Response.HasStarted); + Assert.True(context.Response.Body.CanSeek); + Assert.Equal(11, body.Position); + Assert.Equal(11, body.Length); + + Assert.Throws(() => body.Position = 1); + + body.Position = 0; + Assert.Equal(0, body.Position); + Assert.Equal(0, body.Length); + + await context.Response.WriteAsync("12345"); + Assert.Equal(5, body.Position); + Assert.Equal(5, body.Length); + }); + }); + + var response = await server.CreateClient().GetAsync(""); + response.EnsureSuccessStatusCode(); + Assert.Equal("12345", await response.Content.ReadAsStringAsync()); + + // Set automatically by buffer + IEnumerable values; + Assert.True(response.Content.Headers.TryGetValues("Content-Length", out values)); + Assert.Equal("5", values.FirstOrDefault()); + } + + [Fact] + public async Task SetLength_AllowsResttingBuffer() + { + var server = TestServer.Create(app => + { + app.UseResponseBuffering(); + app.Run(async context => + { + var body = context.Response.Body; + Assert.False(context.Response.HasStarted); + Assert.True(body.CanSeek); + Assert.Equal(0, body.Position); + Assert.Equal(0, body.Length); + + await context.Response.WriteAsync("Hello World"); + Assert.False(context.Response.HasStarted); + Assert.True(context.Response.Body.CanSeek); + Assert.Equal(11, body.Position); + Assert.Equal(11, body.Length); + + Assert.Throws(() => body.SetLength(1)); + + body.SetLength(0); + Assert.Equal(0, body.Position); + Assert.Equal(0, body.Length); + + await context.Response.WriteAsync("12345"); + Assert.Equal(5, body.Position); + Assert.Equal(5, body.Length); + }); + }); + + var response = await server.CreateClient().GetAsync(""); + response.EnsureSuccessStatusCode(); + Assert.Equal("12345", await response.Content.ReadAsStringAsync()); + + // Set automatically by buffer + IEnumerable values; + Assert.True(response.Content.Headers.TryGetValues("Content-Length", out values)); + Assert.Equal("5", values.FirstOrDefault()); + } + + [Fact] + public async Task DisableBufferingViaFeature() + { + var server = TestServer.Create(app => + { + app.UseResponseBuffering(); + app.Run(async context => + { + Assert.False(context.Response.HasStarted); + Assert.True(context.Response.Body.CanSeek); + + var bufferingFeature = context.GetFeature(); + Assert.NotNull(bufferingFeature); + bufferingFeature.DisableResponseBuffering(); + + Assert.False(context.Response.HasStarted); + Assert.False(context.Response.Body.CanSeek); + + await context.Response.WriteAsync("Hello World"); + + Assert.True(context.Response.HasStarted); + Assert.False(context.Response.Body.CanSeek); + }); + }); + + var response = await server.CreateClient().GetAsync(""); + response.EnsureSuccessStatusCode(); + Assert.Equal("Hello World", await response.Content.ReadAsStringAsync()); + IEnumerable values; + Assert.False(response.Content.Headers.TryGetValues("Content-Length", out values)); + } + + [Fact] + public async Task DisableBufferingViaFeatureAfterFirstWrite_Flushes() + { + var server = TestServer.Create(app => + { + app.UseResponseBuffering(); + app.Run(async context => + { + Assert.False(context.Response.HasStarted); + Assert.True(context.Response.Body.CanSeek); + + await context.Response.WriteAsync("Hello"); + + Assert.False(context.Response.HasStarted); + Assert.True(context.Response.Body.CanSeek); + + var bufferingFeature = context.GetFeature(); + Assert.NotNull(bufferingFeature); + bufferingFeature.DisableResponseBuffering(); + + Assert.True(context.Response.HasStarted); + Assert.False(context.Response.Body.CanSeek); + + await context.Response.WriteAsync(" World"); + + Assert.True(context.Response.HasStarted); + Assert.False(context.Response.Body.CanSeek); + }); + }); + + var response = await server.CreateClient().GetAsync(""); + response.EnsureSuccessStatusCode(); + Assert.Equal("Hello World", await response.Content.ReadAsStringAsync()); + IEnumerable values; + Assert.False(response.Content.Headers.TryGetValues("Content-Length", out values)); + } + + [Fact] + public async Task FlushDisablesBuffering() + { + var server = TestServer.Create(app => + { + app.UseResponseBuffering(); + app.Run(async context => + { + Assert.False(context.Response.HasStarted); + Assert.True(context.Response.Body.CanSeek); + + context.Response.Body.Flush(); + + Assert.True(context.Response.HasStarted); + Assert.False(context.Response.Body.CanSeek); + + await context.Response.WriteAsync("Hello World"); + + Assert.True(context.Response.HasStarted); + Assert.False(context.Response.Body.CanSeek); + }); + }); + + var response = await server.CreateClient().GetAsync(""); + response.EnsureSuccessStatusCode(); + Assert.Equal("Hello World", await response.Content.ReadAsStringAsync()); + IEnumerable values; + Assert.False(response.Content.Headers.TryGetValues("Content-Length", out values)); + } + } +} diff --git a/test/Microsoft.AspNet.Buffering.Tests/project.json b/test/Microsoft.AspNet.Buffering.Tests/project.json new file mode 100644 index 0000000000..516bc624f1 --- /dev/null +++ b/test/Microsoft.AspNet.Buffering.Tests/project.json @@ -0,0 +1,22 @@ +{ + "version": "1.0.0-*", + "dependencies": { + "Microsoft.AspNet.Buffering": "1.0.0-*", + "Microsoft.AspNet.TestHost": "1.0.0-*", + "xunit.runner.aspnet": "2.0.0-aspnet-*" + }, + "commands": { + "test": "xunit.runner.aspnet" + }, + + "frameworks": { + "dnx451": { }, + "dnxcore50": { + "dependencies": { + "System.Collections": "4.0.10-*", + "System.Linq": "4.0.0-*", + "System.Threading": "4.0.10-*" + } + } + } +} From 2af06269df36b3d0c8f95a67d404537397c1e6b9 Mon Sep 17 00:00:00 2001 From: David Fowler Date: Sat, 15 Aug 2015 02:35:17 -0700 Subject: [PATCH 007/307] Make build.sh executable --- build.sh | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 build.sh diff --git a/build.sh b/build.sh old mode 100644 new mode 100755 From 4aab903b18d2e78cdae3da9f7534da06debd2516 Mon Sep 17 00:00:00 2001 From: Chris R Date: Mon, 31 Aug 2015 09:21:35 -0700 Subject: [PATCH 008/307] React to string[] -> StringValues changes. --- .../HttpMethodOverrideMiddleware.cs | 2 +- .../OverrideHeaderMiddleware.cs | 12 ++++++------ src/Microsoft.AspNet.HttpOverrides/project.json | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/Microsoft.AspNet.HttpOverrides/HttpMethodOverrideMiddleware.cs b/src/Microsoft.AspNet.HttpOverrides/HttpMethodOverrideMiddleware.cs index 8d805d80b8..46ede451f6 100644 --- a/src/Microsoft.AspNet.HttpOverrides/HttpMethodOverrideMiddleware.cs +++ b/src/Microsoft.AspNet.HttpOverrides/HttpMethodOverrideMiddleware.cs @@ -38,7 +38,7 @@ namespace Microsoft.AspNet.HttpOverrides } else { - var xHttpMethodOverrideValue = context.Request.Headers.Get(xHttpMethodOverride); + var xHttpMethodOverrideValue = context.Request.Headers[xHttpMethodOverride]; if (!string.IsNullOrEmpty(xHttpMethodOverrideValue)) { context.Request.Method = xHttpMethodOverrideValue; diff --git a/src/Microsoft.AspNet.HttpOverrides/OverrideHeaderMiddleware.cs b/src/Microsoft.AspNet.HttpOverrides/OverrideHeaderMiddleware.cs index 7f6d1a3edd..76652eab05 100644 --- a/src/Microsoft.AspNet.HttpOverrides/OverrideHeaderMiddleware.cs +++ b/src/Microsoft.AspNet.HttpOverrides/OverrideHeaderMiddleware.cs @@ -32,7 +32,7 @@ namespace Microsoft.AspNet.HttpOverrides if ((_options.ForwardedOptions & ForwardedHeaders.XForwardedFor) != 0) { var xForwardedForHeaderValue = context.Request.Headers.GetCommaSeparatedValues(XForwardedForHeaderName); - if (xForwardedForHeaderValue != null && xForwardedForHeaderValue.Count > 0) + if (xForwardedForHeaderValue != null && xForwardedForHeaderValue.Length > 0) { IPAddress ipFromHeader; if (IPAddress.TryParse(xForwardedForHeaderValue[0], out ipFromHeader)) @@ -40,7 +40,7 @@ namespace Microsoft.AspNet.HttpOverrides var remoteIPString = context.Connection.RemoteIpAddress?.ToString(); if (!string.IsNullOrEmpty(remoteIPString)) { - context.Request.Headers.Set(XOriginalIPName, remoteIPString); + context.Request.Headers[XOriginalIPName] = remoteIPString; } context.Connection.RemoteIpAddress = ipFromHeader; } @@ -49,13 +49,13 @@ namespace Microsoft.AspNet.HttpOverrides if ((_options.ForwardedOptions & ForwardedHeaders.XForwardedHost) != 0) { - var xForwardHostHeaderValue = context.Request.Headers.Get(XForwardedHostHeaderName); + var xForwardHostHeaderValue = context.Request.Headers[XForwardedHostHeaderName]; if (!string.IsNullOrEmpty(xForwardHostHeaderValue)) { var hostString = context.Request.Host.ToString(); if (!string.IsNullOrEmpty(hostString)) { - context.Request.Headers.Set(XOriginalHostName, hostString); + context.Request.Headers[XOriginalHostName] = hostString; } context.Request.Host = HostString.FromUriComponent(xForwardHostHeaderValue); } @@ -63,12 +63,12 @@ namespace Microsoft.AspNet.HttpOverrides if ((_options.ForwardedOptions & ForwardedHeaders.XForwardedProto) != 0) { - var xForwardProtoHeaderValue = context.Request.Headers.Get(XForwardedProtoHeaderName); + var xForwardProtoHeaderValue = context.Request.Headers[XForwardedProtoHeaderName]; if (!string.IsNullOrEmpty(xForwardProtoHeaderValue)) { if (!string.IsNullOrEmpty(context.Request.Scheme)) { - context.Request.Headers.Set(XOriginalProtoName, context.Request.Scheme); + context.Request.Headers[XOriginalProtoName] = context.Request.Scheme; } context.Request.Scheme = xForwardProtoHeaderValue; } diff --git a/src/Microsoft.AspNet.HttpOverrides/project.json b/src/Microsoft.AspNet.HttpOverrides/project.json index 11697e5424..2017b9139a 100644 --- a/src/Microsoft.AspNet.HttpOverrides/project.json +++ b/src/Microsoft.AspNet.HttpOverrides/project.json @@ -7,7 +7,7 @@ }, "dependencies": { "Microsoft.CSharp": "4.0.0-*", - "Microsoft.AspNet.Http.Abstractions": "1.0.0-*", + "Microsoft.AspNet.Http.Extensions": "1.0.0-*", "Microsoft.Framework.NotNullAttribute.Sources": { "version": "1.0.0-*", "type": "build" } }, "frameworks": { From 5a3418c2bd652cdec332e85c3cac9bdcf6365a38 Mon Sep 17 00:00:00 2001 From: Chris R Date: Mon, 31 Aug 2015 09:22:11 -0700 Subject: [PATCH 009/307] Use the new HttpContext.Features API. --- .../ResponseBufferingMiddleware.cs | 12 ++++++------ .../ResponseBufferingMiddlewareTests.cs | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/Microsoft.AspNet.Buffering/ResponseBufferingMiddleware.cs b/src/Microsoft.AspNet.Buffering/ResponseBufferingMiddleware.cs index ec3a230146..e2af1cc4f6 100644 --- a/src/Microsoft.AspNet.Buffering/ResponseBufferingMiddleware.cs +++ b/src/Microsoft.AspNet.Buffering/ResponseBufferingMiddleware.cs @@ -28,17 +28,17 @@ namespace Microsoft.AspNet.Buffering return; } - var originalBufferingFeature = httpContext.GetFeature(); - var originalSendFileFeature = httpContext.GetFeature(); + var originalBufferingFeature = httpContext.Features.Get(); + var originalSendFileFeature = httpContext.Features.Get(); try { // Shim the response stream var bufferStream = new BufferingWriteStream(originalResponseBody); httpContext.Response.Body = bufferStream; - httpContext.SetFeature(new HttpBufferingFeature(bufferStream, originalBufferingFeature)); + httpContext.Features.Set(new HttpBufferingFeature(bufferStream, originalBufferingFeature)); if (originalSendFileFeature != null) { - httpContext.SetFeature(new SendFileFeatureWrapper(originalSendFileFeature, bufferStream)); + httpContext.Features.Set(new SendFileFeatureWrapper(originalSendFileFeature, bufferStream)); } await _next(httpContext); @@ -57,8 +57,8 @@ namespace Microsoft.AspNet.Buffering finally { // undo everything - httpContext.SetFeature(originalBufferingFeature); - httpContext.SetFeature(originalSendFileFeature); + httpContext.Features.Set(originalBufferingFeature); + httpContext.Features.Set(originalSendFileFeature); httpContext.Response.Body = originalResponseBody; } } diff --git a/test/Microsoft.AspNet.Buffering.Tests/ResponseBufferingMiddlewareTests.cs b/test/Microsoft.AspNet.Buffering.Tests/ResponseBufferingMiddlewareTests.cs index ee7431ec28..5569a14222 100644 --- a/test/Microsoft.AspNet.Buffering.Tests/ResponseBufferingMiddlewareTests.cs +++ b/test/Microsoft.AspNet.Buffering.Tests/ResponseBufferingMiddlewareTests.cs @@ -207,7 +207,7 @@ namespace Microsoft.AspNet.Buffering.Tests Assert.False(context.Response.HasStarted); Assert.True(context.Response.Body.CanSeek); - var bufferingFeature = context.GetFeature(); + var bufferingFeature = context.Features.Get(); Assert.NotNull(bufferingFeature); bufferingFeature.DisableResponseBuffering(); @@ -244,7 +244,7 @@ namespace Microsoft.AspNet.Buffering.Tests Assert.False(context.Response.HasStarted); Assert.True(context.Response.Body.CanSeek); - var bufferingFeature = context.GetFeature(); + var bufferingFeature = context.Features.Get(); Assert.NotNull(bufferingFeature); bufferingFeature.DisableResponseBuffering(); From 2abd87ff5aa21d43da9dd7b499e01b871e02cabd Mon Sep 17 00:00:00 2001 From: Chris R Date: Fri, 4 Sep 2015 10:57:01 -0700 Subject: [PATCH 010/307] Remove un-needed dependenecies. --- src/Microsoft.AspNet.HttpOverrides/project.json | 1 - test/Microsoft.AspNet.HttpOverrides.Tests/project.json | 8 +------- 2 files changed, 1 insertion(+), 8 deletions(-) diff --git a/src/Microsoft.AspNet.HttpOverrides/project.json b/src/Microsoft.AspNet.HttpOverrides/project.json index 2017b9139a..6e01fbd4d2 100644 --- a/src/Microsoft.AspNet.HttpOverrides/project.json +++ b/src/Microsoft.AspNet.HttpOverrides/project.json @@ -6,7 +6,6 @@ "url": "git://github.com/aspnet/basicmiddleware" }, "dependencies": { - "Microsoft.CSharp": "4.0.0-*", "Microsoft.AspNet.Http.Extensions": "1.0.0-*", "Microsoft.Framework.NotNullAttribute.Sources": { "version": "1.0.0-*", "type": "build" } }, diff --git a/test/Microsoft.AspNet.HttpOverrides.Tests/project.json b/test/Microsoft.AspNet.HttpOverrides.Tests/project.json index a83e0c4bc7..e9595a9992 100644 --- a/test/Microsoft.AspNet.HttpOverrides.Tests/project.json +++ b/test/Microsoft.AspNet.HttpOverrides.Tests/project.json @@ -12,12 +12,6 @@ "frameworks": { "dnx451": { }, - "dnxcore50": { - "dependencies": { - "System.Collections": "4.0.10-*", - "System.Linq": "4.0.0-*", - "System.Threading": "4.0.10-*" - } - } + "dnxcore50": { } } } From 6f4a9befccfe14847ba65e4c6ee6419b3af45eea Mon Sep 17 00:00:00 2001 From: Pranav K Date: Wed, 9 Sep 2015 12:30:46 -0700 Subject: [PATCH 011/307] Updating to Sake 0.2.2 --- build.cmd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.cmd b/build.cmd index ccf195aee8..7a8840cd52 100644 --- a/build.cmd +++ b/build.cmd @@ -23,7 +23,7 @@ IF %BUILDCMD_KOREBUILD_VERSION%=="" ( ) ELSE ( .nuget\NuGet.exe install KoreBuild -version %BUILDCMD_KOREBUILD_VERSION% -ExcludeVersion -o packages -nocache -pre ) -.nuget\NuGet.exe install Sake -version 0.2 -o packages -ExcludeVersion +.nuget\NuGet.exe install Sake -version 0.2.2 -o packages -ExcludeVersion IF "%SKIP_DNX_INSTALL%"=="1" goto run IF %BUILDCMD_DNX_VERSION%=="" ( From d0dc4875de87c46e75da98ceb9b4cca8be5e9622 Mon Sep 17 00:00:00 2001 From: Kiran Challa Date: Wed, 9 Sep 2015 14:56:04 -0700 Subject: [PATCH 012/307] Updating build.sh to Sake 0.2.2 --- build.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.sh b/build.sh index 3ef874f9bd..807306bf01 100755 --- a/build.sh +++ b/build.sh @@ -24,7 +24,7 @@ fi if test ! -d packages/KoreBuild; then mono .nuget/nuget.exe install KoreBuild -ExcludeVersion -o packages -nocache -pre - mono .nuget/nuget.exe install Sake -version 0.2 -o packages -ExcludeVersion + mono .nuget/nuget.exe install Sake -version 0.2.2 -o packages -ExcludeVersion fi if ! type dnvm > /dev/null 2>&1; then From bb912deea45da43ae0e299332e5bb79cd70699b5 Mon Sep 17 00:00:00 2001 From: Kiran Challa Date: Wed, 9 Sep 2015 15:16:55 -0700 Subject: [PATCH 013/307] Updating Sake to always use latest version --- build.cmd | 2 +- build.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/build.cmd b/build.cmd index 7a8840cd52..b54d91cf74 100644 --- a/build.cmd +++ b/build.cmd @@ -23,7 +23,7 @@ IF %BUILDCMD_KOREBUILD_VERSION%=="" ( ) ELSE ( .nuget\NuGet.exe install KoreBuild -version %BUILDCMD_KOREBUILD_VERSION% -ExcludeVersion -o packages -nocache -pre ) -.nuget\NuGet.exe install Sake -version 0.2.2 -o packages -ExcludeVersion +.nuget\NuGet.exe install Sake -ExcludeVersion -Source https://www.nuget.org/api/v2/ -Out packages IF "%SKIP_DNX_INSTALL%"=="1" goto run IF %BUILDCMD_DNX_VERSION%=="" ( diff --git a/build.sh b/build.sh index 807306bf01..68c3e8cb52 100755 --- a/build.sh +++ b/build.sh @@ -24,7 +24,7 @@ fi if test ! -d packages/KoreBuild; then mono .nuget/nuget.exe install KoreBuild -ExcludeVersion -o packages -nocache -pre - mono .nuget/nuget.exe install Sake -version 0.2.2 -o packages -ExcludeVersion + mono .nuget/nuget.exe install Sake -ExcludeVersion -Source https://www.nuget.org/api/v2/ -Out packages fi if ! type dnvm > /dev/null 2>&1; then From 62cc882c96645ef05675688b212d726c229c361e Mon Sep 17 00:00:00 2001 From: "N. Taylor Mullen" Date: Thu, 17 Sep 2015 18:33:50 -0700 Subject: [PATCH 014/307] Update nuget.exe and corresponding feeds to v3. --- NuGet.Config => NuGet.config | 4 ++-- build.cmd | 11 ++++++----- build.sh | 12 +++++++----- 3 files changed, 15 insertions(+), 12 deletions(-) rename NuGet.Config => NuGet.config (68%) diff --git a/NuGet.Config b/NuGet.config similarity index 68% rename from NuGet.Config rename to NuGet.config index da57d47267..dae5aba3f9 100644 --- a/NuGet.Config +++ b/NuGet.config @@ -1,7 +1,7 @@ - + - + \ No newline at end of file diff --git a/build.cmd b/build.cmd index b54d91cf74..177997c42e 100644 --- a/build.cmd +++ b/build.cmd @@ -2,14 +2,15 @@ cd %~dp0 SETLOCAL -SET CACHED_NUGET=%LocalAppData%\NuGet\NuGet.exe +SET NUGET_VERSION=latest +SET CACHED_NUGET=%LocalAppData%\NuGet\nuget.%NUGET_VERSION%.exe SET BUILDCMD_KOREBUILD_VERSION="" SET BUILDCMD_DNX_VERSION="" IF EXIST %CACHED_NUGET% goto copynuget echo Downloading latest version of NuGet.exe... IF NOT EXIST %LocalAppData%\NuGet md %LocalAppData%\NuGet -@powershell -NoProfile -ExecutionPolicy unrestricted -Command "$ProgressPreference = 'SilentlyContinue'; Invoke-WebRequest 'https://www.nuget.org/nuget.exe' -OutFile '%CACHED_NUGET%'" +@powershell -NoProfile -ExecutionPolicy unrestricted -Command "$ProgressPreference = 'SilentlyContinue'; Invoke-WebRequest 'https://dist.nuget.org/win-x86-commandline/%NUGET_VERSION%/nuget.exe' -OutFile '%CACHED_NUGET%'" :copynuget IF EXIST .nuget\nuget.exe goto restore @@ -19,11 +20,11 @@ copy %CACHED_NUGET% .nuget\nuget.exe > nul :restore IF EXIST packages\KoreBuild goto run IF %BUILDCMD_KOREBUILD_VERSION%=="" ( - .nuget\NuGet.exe install KoreBuild -ExcludeVersion -o packages -nocache -pre + .nuget\nuget.exe install KoreBuild -ExcludeVersion -o packages -nocache -pre ) ELSE ( - .nuget\NuGet.exe install KoreBuild -version %BUILDCMD_KOREBUILD_VERSION% -ExcludeVersion -o packages -nocache -pre + .nuget\nuget.exe install KoreBuild -version %BUILDCMD_KOREBUILD_VERSION% -ExcludeVersion -o packages -nocache -pre ) -.nuget\NuGet.exe install Sake -ExcludeVersion -Source https://www.nuget.org/api/v2/ -Out packages +.nuget\nuget.exe install Sake -ExcludeVersion -Out packages IF "%SKIP_DNX_INSTALL%"=="1" goto run IF %BUILDCMD_DNX_VERSION%=="" ( diff --git a/build.sh b/build.sh index 68c3e8cb52..0c66139817 100755 --- a/build.sh +++ b/build.sh @@ -10,21 +10,23 @@ else fi fi mkdir -p $cachedir +nugetVersion=latest +cachePath=$cachedir/nuget.$nugetVersion.exe -url=https://www.nuget.org/nuget.exe +url=https://dist.nuget.org/win-x86-commandline/$nugetVersion/nuget.exe -if test ! -f $cachedir/nuget.exe; then - wget -O $cachedir/nuget.exe $url 2>/dev/null || curl -o $cachedir/nuget.exe --location $url /dev/null +if test ! -f $cachePath; then + wget -O $cachePath $url 2>/dev/null || curl -o $cachePath --location $url /dev/null fi if test ! -e .nuget; then mkdir .nuget - cp $cachedir/nuget.exe .nuget/nuget.exe + cp $cachePath .nuget/nuget.exe fi if test ! -d packages/KoreBuild; then mono .nuget/nuget.exe install KoreBuild -ExcludeVersion -o packages -nocache -pre - mono .nuget/nuget.exe install Sake -ExcludeVersion -Source https://www.nuget.org/api/v2/ -Out packages + mono .nuget/nuget.exe install Sake -ExcludeVersion -Out packages fi if ! type dnvm > /dev/null 2>&1; then From 51f60b5af2cd52790a6bd35da4a613bfb1a8d093 Mon Sep 17 00:00:00 2001 From: Ajay Bhargav Baaskaran Date: Wed, 23 Sep 2015 12:33:01 -0700 Subject: [PATCH 015/307] Enabling NuGetPackageVerifier --- NuGetPackageVerifier.json | 26 +++++++++++++++++++ .../Properties/AssemblyInfo.cs | 8 ++++++ .../Properties/AssemblyInfo.cs | 8 ++++++ 3 files changed, 42 insertions(+) create mode 100644 NuGetPackageVerifier.json create mode 100644 src/Microsoft.AspNet.Buffering/Properties/AssemblyInfo.cs create mode 100644 src/Microsoft.AspNet.HttpOverrides/Properties/AssemblyInfo.cs diff --git a/NuGetPackageVerifier.json b/NuGetPackageVerifier.json new file mode 100644 index 0000000000..f9d3834ce9 --- /dev/null +++ b/NuGetPackageVerifier.json @@ -0,0 +1,26 @@ +{ + "adx": { // Packages written by the ADX team and that ship on NuGet.org + "rules": [ + "AssemblyHasDocumentFileRule", + "AssemblyHasVersionAttributesRule", + "AssemblyHasServicingAttributeRule", + "AssemblyHasNeutralResourcesLanguageAttributeRule", + "SatellitePackageRule", + "StrictSemanticVersionValidationRule" + ], + "packages": { + "Microsoft.AspNet.Buffering": { }, + "Microsoft.AspNet.HttpOverrides": { } + } + }, + "Default": { // Rules to run for packages not listed in any other set. + "rules": [ + "AssemblyHasDocumentFileRule", + "AssemblyHasVersionAttributesRule", + "AssemblyHasServicingAttributeRule", + "AssemblyHasNeutralResourcesLanguageAttributeRule", + "SatellitePackageRule", + "StrictSemanticVersionValidationRule" + ] + } +} \ No newline at end of file diff --git a/src/Microsoft.AspNet.Buffering/Properties/AssemblyInfo.cs b/src/Microsoft.AspNet.Buffering/Properties/AssemblyInfo.cs new file mode 100644 index 0000000000..e0f545c6b5 --- /dev/null +++ b/src/Microsoft.AspNet.Buffering/Properties/AssemblyInfo.cs @@ -0,0 +1,8 @@ +// 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.Reflection; +using System.Resources; + +[assembly: AssemblyMetadata("Serviceable", "True")] +[assembly: NeutralResourcesLanguage("en-us")] \ No newline at end of file diff --git a/src/Microsoft.AspNet.HttpOverrides/Properties/AssemblyInfo.cs b/src/Microsoft.AspNet.HttpOverrides/Properties/AssemblyInfo.cs new file mode 100644 index 0000000000..e0f545c6b5 --- /dev/null +++ b/src/Microsoft.AspNet.HttpOverrides/Properties/AssemblyInfo.cs @@ -0,0 +1,8 @@ +// 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.Reflection; +using System.Resources; + +[assembly: AssemblyMetadata("Serviceable", "True")] +[assembly: NeutralResourcesLanguage("en-us")] \ No newline at end of file From dfe5cd840e2d7886496b312715398ab3ce47fbba Mon Sep 17 00:00:00 2001 From: Pranav K Date: Mon, 28 Sep 2015 23:16:21 -0700 Subject: [PATCH 016/307] Updating to release NuGet.config. --- NuGet.config | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/NuGet.config b/NuGet.config index dae5aba3f9..e526481f82 100644 --- a/NuGet.config +++ b/NuGet.config @@ -1,7 +1,7 @@ - + \ No newline at end of file From 98bca199f2038e144ef89f3dc747a07e01d859c1 Mon Sep 17 00:00:00 2001 From: "N. Taylor Mullen" Date: Thu, 1 Oct 2015 11:59:05 -0700 Subject: [PATCH 017/307] Update 'build.cmd' alias parameter to use full name. --- build.cmd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.cmd b/build.cmd index 177997c42e..70d974a61f 100644 --- a/build.cmd +++ b/build.cmd @@ -30,7 +30,7 @@ IF "%SKIP_DNX_INSTALL%"=="1" goto run IF %BUILDCMD_DNX_VERSION%=="" ( CALL packages\KoreBuild\build\dnvm upgrade -runtime CLR -arch x86 ) ELSE ( - CALL packages\KoreBuild\build\dnvm install %BUILDCMD_DNX_VERSION% -runtime CLR -arch x86 -a default + CALL packages\KoreBuild\build\dnvm install %BUILDCMD_DNX_VERSION% -runtime CLR -arch x86 -alias default ) CALL packages\KoreBuild\build\dnvm install default -runtime CoreCLR -arch x86 From d41f2ccf7156d0c7812718774bc5d1086ddf5763 Mon Sep 17 00:00:00 2001 From: Pranav K Date: Sat, 3 Oct 2015 15:44:49 -0700 Subject: [PATCH 018/307] Renaming Microsoft.Framework.* -> Microsoft.Extensions.* --- samples/ResponseBufferingSample/Startup.cs | 4 ++-- .../OverrideHeaderMiddleware.cs | 4 ++-- src/Microsoft.AspNet.HttpOverrides/project.json | 4 ++-- test/Microsoft.AspNet.HttpOverrides.Tests/project.json | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/samples/ResponseBufferingSample/Startup.cs b/samples/ResponseBufferingSample/Startup.cs index 46626e8065..db8b7d9eca 100644 --- a/samples/ResponseBufferingSample/Startup.cs +++ b/samples/ResponseBufferingSample/Startup.cs @@ -1,6 +1,6 @@ -using Microsoft.AspNet.Builder; +using Microsoft.AspNet.Builder; using Microsoft.AspNet.Http; -using Microsoft.Framework.DependencyInjection; +using Microsoft.Extensions.DependencyInjection; namespace ResponseBufferingSample { diff --git a/src/Microsoft.AspNet.HttpOverrides/OverrideHeaderMiddleware.cs b/src/Microsoft.AspNet.HttpOverrides/OverrideHeaderMiddleware.cs index 76652eab05..b036b9e58a 100644 --- a/src/Microsoft.AspNet.HttpOverrides/OverrideHeaderMiddleware.cs +++ b/src/Microsoft.AspNet.HttpOverrides/OverrideHeaderMiddleware.cs @@ -1,4 +1,4 @@ -// Copyright (c) .NET Foundation. All rights reserved. +// 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; @@ -6,7 +6,7 @@ using System.Net; using System.Threading.Tasks; using Microsoft.AspNet.Builder; using Microsoft.AspNet.Http; -using Microsoft.Framework.Internal; +using Microsoft.Extensions.Internal; namespace Microsoft.AspNet.HttpOverrides { diff --git a/src/Microsoft.AspNet.HttpOverrides/project.json b/src/Microsoft.AspNet.HttpOverrides/project.json index 6e01fbd4d2..46de36765a 100644 --- a/src/Microsoft.AspNet.HttpOverrides/project.json +++ b/src/Microsoft.AspNet.HttpOverrides/project.json @@ -1,4 +1,4 @@ -{ +{ "version": "1.0.0-*", "description": "XForward and Method override middlewares for ASP.NET", "repository": { @@ -7,7 +7,7 @@ }, "dependencies": { "Microsoft.AspNet.Http.Extensions": "1.0.0-*", - "Microsoft.Framework.NotNullAttribute.Sources": { "version": "1.0.0-*", "type": "build" } + "Microsoft.Extensions.NotNullAttribute.Sources": { "version": "1.0.0-*", "type": "build" } }, "frameworks": { "dnx451": { }, diff --git a/test/Microsoft.AspNet.HttpOverrides.Tests/project.json b/test/Microsoft.AspNet.HttpOverrides.Tests/project.json index e9595a9992..e33d3add90 100644 --- a/test/Microsoft.AspNet.HttpOverrides.Tests/project.json +++ b/test/Microsoft.AspNet.HttpOverrides.Tests/project.json @@ -1,9 +1,9 @@ -{ +{ "version": "1.0.0-*", "dependencies": { "Microsoft.AspNet.HttpOverrides": "1.0.0-*", "Microsoft.AspNet.TestHost": "1.0.0-*", - "Microsoft.Framework.Logging.Testing": "1.0.0-*", + "Microsoft.Extensions.Logging.Testing": "1.0.0-*", "xunit.runner.aspnet": "2.0.0-aspnet-*" }, "commands": { From 003ad891d03e4c3c25642a1d46ab4a0d35361386 Mon Sep 17 00:00:00 2001 From: Pranav K Date: Thu, 8 Oct 2015 17:13:52 -0700 Subject: [PATCH 019/307] Replacing NotNullAttribute with thrown exceptions --- .../OverrideHeaderMiddleware.cs | 13 +++++++++++-- src/Microsoft.AspNet.HttpOverrides/project.json | 3 +-- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/src/Microsoft.AspNet.HttpOverrides/OverrideHeaderMiddleware.cs b/src/Microsoft.AspNet.HttpOverrides/OverrideHeaderMiddleware.cs index b036b9e58a..dd3cb92260 100644 --- a/src/Microsoft.AspNet.HttpOverrides/OverrideHeaderMiddleware.cs +++ b/src/Microsoft.AspNet.HttpOverrides/OverrideHeaderMiddleware.cs @@ -6,7 +6,6 @@ using System.Net; using System.Threading.Tasks; using Microsoft.AspNet.Builder; using Microsoft.AspNet.Http; -using Microsoft.Extensions.Internal; namespace Microsoft.AspNet.HttpOverrides { @@ -21,8 +20,18 @@ namespace Microsoft.AspNet.HttpOverrides private readonly OverrideHeaderMiddlewareOptions _options; private readonly RequestDelegate _next; - public OverrideHeaderMiddleware([NotNull] RequestDelegate next, [NotNull] OverrideHeaderMiddlewareOptions options) + public OverrideHeaderMiddleware(RequestDelegate next, OverrideHeaderMiddlewareOptions options) { + if (next == null) + { + throw new ArgumentNullException(nameof(next)); + } + + if (options == null) + { + throw new ArgumentNullException(nameof(options)); + } + _options = options; _next = next; } diff --git a/src/Microsoft.AspNet.HttpOverrides/project.json b/src/Microsoft.AspNet.HttpOverrides/project.json index 46de36765a..d7910084bc 100644 --- a/src/Microsoft.AspNet.HttpOverrides/project.json +++ b/src/Microsoft.AspNet.HttpOverrides/project.json @@ -6,8 +6,7 @@ "url": "git://github.com/aspnet/basicmiddleware" }, "dependencies": { - "Microsoft.AspNet.Http.Extensions": "1.0.0-*", - "Microsoft.Extensions.NotNullAttribute.Sources": { "version": "1.0.0-*", "type": "build" } + "Microsoft.AspNet.Http.Extensions": "1.0.0-*" }, "frameworks": { "dnx451": { }, From 8aa5184a334b1cdf2fa0420fe8d291d5af09e380 Mon Sep 17 00:00:00 2001 From: Doug Bunting Date: Thu, 8 Oct 2015 19:00:29 -0700 Subject: [PATCH 020/307] React to aspnet/Universe#290 fix --- build.cmd | 25 +++++++++++++------------ build.sh | 12 +++++++----- 2 files changed, 20 insertions(+), 17 deletions(-) diff --git a/build.cmd b/build.cmd index 70d974a61f..84dc87e480 100644 --- a/build.cmd +++ b/build.cmd @@ -18,22 +18,23 @@ md .nuget copy %CACHED_NUGET% .nuget\nuget.exe > nul :restore -IF EXIST packages\KoreBuild goto run +IF EXIST packages\Sake goto getdnx IF %BUILDCMD_KOREBUILD_VERSION%=="" ( - .nuget\nuget.exe install KoreBuild -ExcludeVersion -o packages -nocache -pre + .nuget\nuget.exe install KoreBuild -ExcludeVersion -o packages -nocache -pre ) ELSE ( - .nuget\nuget.exe install KoreBuild -version %BUILDCMD_KOREBUILD_VERSION% -ExcludeVersion -o packages -nocache -pre + .nuget\nuget.exe install KoreBuild -version %BUILDCMD_KOREBUILD_VERSION% -ExcludeVersion -o packages -nocache -pre ) -.nuget\nuget.exe install Sake -ExcludeVersion -Out packages +.nuget\NuGet.exe install Sake -ExcludeVersion -Source https://www.nuget.org/api/v2/ -Out packages -IF "%SKIP_DNX_INSTALL%"=="1" goto run -IF %BUILDCMD_DNX_VERSION%=="" ( - CALL packages\KoreBuild\build\dnvm upgrade -runtime CLR -arch x86 +:getdnx +IF "%SKIP_DNX_INSTALL%"=="" ( + IF "%BUILDCMD_DNX_VERSION%"=="" ( + BUILDCMD_DNX_VERSION=latest + ) + CALL packages\KoreBuild\build\dnvm install %BUILDCMD_DNX_VERSION% -runtime CoreCLR -arch x86 -alias default + CALL packages\KoreBuild\build\dnvm install default -runtime CLR -arch x86 -alias default ) ELSE ( - CALL packages\KoreBuild\build\dnvm install %BUILDCMD_DNX_VERSION% -runtime CLR -arch x86 -alias default + CALL packages\KoreBuild\build\dnvm use default -runtime CLR -arch x86 ) -CALL packages\KoreBuild\build\dnvm install default -runtime CoreCLR -arch x86 -:run -CALL packages\KoreBuild\build\dnvm use default -runtime CLR -arch x86 -packages\Sake\tools\Sake.exe -I packages\KoreBuild\build -f makefile.shade %* \ No newline at end of file +packages\Sake\tools\Sake.exe -I packages\KoreBuild\build -f makefile.shade %* diff --git a/build.sh b/build.sh index 0c66139817..da4e3fcd1c 100755 --- a/build.sh +++ b/build.sh @@ -24,18 +24,20 @@ if test ! -e .nuget; then cp $cachePath .nuget/nuget.exe fi -if test ! -d packages/KoreBuild; then +if test ! -d packages/Sake; then mono .nuget/nuget.exe install KoreBuild -ExcludeVersion -o packages -nocache -pre - mono .nuget/nuget.exe install Sake -ExcludeVersion -Out packages + mono .nuget/nuget.exe install Sake -ExcludeVersion -Source https://www.nuget.org/api/v2/ -Out packages fi if ! type dnvm > /dev/null 2>&1; then source packages/KoreBuild/build/dnvm.sh fi -if ! type dnx > /dev/null 2>&1; then - dnvm upgrade +if ! type dnx > /dev/null 2>&1 || [ -z "$SKIP_DNX_INSTALL" ]; then + dnvm install latest -runtime coreclr -alias default + dnvm install default -runtime mono -alias default +else + dnvm use default -runtime mono fi mono packages/Sake/tools/Sake.exe -I packages/KoreBuild/build -f makefile.shade "$@" - From 777d56d5d96050bb3aad9903a00d535e2345f25e Mon Sep 17 00:00:00 2001 From: Doug Bunting Date: Mon, 12 Oct 2015 12:48:06 -0700 Subject: [PATCH 021/307] Fix local build break --- build.cmd | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/build.cmd b/build.cmd index 84dc87e480..553e3929a0 100644 --- a/build.cmd +++ b/build.cmd @@ -4,8 +4,8 @@ cd %~dp0 SETLOCAL SET NUGET_VERSION=latest SET CACHED_NUGET=%LocalAppData%\NuGet\nuget.%NUGET_VERSION%.exe -SET BUILDCMD_KOREBUILD_VERSION="" -SET BUILDCMD_DNX_VERSION="" +SET BUILDCMD_KOREBUILD_VERSION= +SET BUILDCMD_DNX_VERSION= IF EXIST %CACHED_NUGET% goto copynuget echo Downloading latest version of NuGet.exe... @@ -19,7 +19,7 @@ copy %CACHED_NUGET% .nuget\nuget.exe > nul :restore IF EXIST packages\Sake goto getdnx -IF %BUILDCMD_KOREBUILD_VERSION%=="" ( +IF "%BUILDCMD_KOREBUILD_VERSION%"=="" ( .nuget\nuget.exe install KoreBuild -ExcludeVersion -o packages -nocache -pre ) ELSE ( .nuget\nuget.exe install KoreBuild -version %BUILDCMD_KOREBUILD_VERSION% -ExcludeVersion -o packages -nocache -pre @@ -27,10 +27,10 @@ IF %BUILDCMD_KOREBUILD_VERSION%=="" ( .nuget\NuGet.exe install Sake -ExcludeVersion -Source https://www.nuget.org/api/v2/ -Out packages :getdnx +IF "%BUILDCMD_DNX_VERSION%"=="" ( + SET BUILDCMD_DNX_VERSION=latest +) IF "%SKIP_DNX_INSTALL%"=="" ( - IF "%BUILDCMD_DNX_VERSION%"=="" ( - BUILDCMD_DNX_VERSION=latest - ) CALL packages\KoreBuild\build\dnvm install %BUILDCMD_DNX_VERSION% -runtime CoreCLR -arch x86 -alias default CALL packages\KoreBuild\build\dnvm install default -runtime CLR -arch x86 -alias default ) ELSE ( From c765fedb2175e7f25a8fdf1d15ccf9e7c97ccd1a Mon Sep 17 00:00:00 2001 From: Cesar Blum Silveira Date: Mon, 19 Oct 2015 14:50:46 -0700 Subject: [PATCH 022/307] Fix CoreCLR test pass on Linux (fixes #15). --- .../OverrideHeaderMiddlewareTest.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/test/Microsoft.AspNet.HttpOverrides.Tests/OverrideHeaderMiddlewareTest.cs b/test/Microsoft.AspNet.HttpOverrides.Tests/OverrideHeaderMiddlewareTest.cs index 003033f5a1..5355335e5a 100644 --- a/test/Microsoft.AspNet.HttpOverrides.Tests/OverrideHeaderMiddlewareTest.cs +++ b/test/Microsoft.AspNet.HttpOverrides.Tests/OverrideHeaderMiddlewareTest.cs @@ -71,14 +71,14 @@ namespace Microsoft.AspNet.HttpOverrides app.UseOverrideHeaders(options); app.Run(context => { - Assert.Equal("testHost", context.Request.Host.ToString()); + Assert.Equal("testhost", context.Request.Host.ToString()); assertsExecuted = true; return Task.FromResult(0); }); }); var req = new HttpRequestMessage(HttpMethod.Get, ""); - req.Headers.Add("X-Forwarded-Host", "testHost"); + req.Headers.Add("X-Forwarded-Host", "testhost"); await server.CreateClient().SendAsync(req); Assert.True(assertsExecuted); } @@ -127,7 +127,7 @@ namespace Microsoft.AspNet.HttpOverrides app.Run(context => { Assert.Equal("11.111.111.11", context.Connection.RemoteIpAddress.ToString()); - Assert.Equal("testHost", context.Request.Host.ToString()); + Assert.Equal("testhost", context.Request.Host.ToString()); Assert.Equal("Protocol", context.Request.Scheme); assertsExecuted = true; return Task.FromResult(0); @@ -136,7 +136,7 @@ namespace Microsoft.AspNet.HttpOverrides var req = new HttpRequestMessage(HttpMethod.Get, ""); req.Headers.Add("X-Forwarded-For", "11.111.111.11"); - req.Headers.Add("X-Forwarded-Host", "testHost"); + req.Headers.Add("X-Forwarded-Host", "testhost"); req.Headers.Add("X-Forwarded-Proto", "Protocol"); await server.CreateClient().SendAsync(req); Assert.True(assertsExecuted); @@ -199,4 +199,4 @@ namespace Microsoft.AspNet.HttpOverrides Assert.True(assertsExecuted); } } -} \ No newline at end of file +} From da00b1298cd69f652a0ff300c24b265b2a5a4129 Mon Sep 17 00:00:00 2001 From: Pranav K Date: Thu, 22 Oct 2015 01:11:23 -0700 Subject: [PATCH 023/307] Switching to generations TFMs --- .../BufferingWriteStream.cs | 4 ++-- src/Microsoft.AspNet.Buffering/project.json | 11 +++++------ src/Microsoft.AspNet.HttpOverrides/project.json | 6 +++--- 3 files changed, 10 insertions(+), 11 deletions(-) diff --git a/src/Microsoft.AspNet.Buffering/BufferingWriteStream.cs b/src/Microsoft.AspNet.Buffering/BufferingWriteStream.cs index d8a04d1cdc..c848b61767 100644 --- a/src/Microsoft.AspNet.Buffering/BufferingWriteStream.cs +++ b/src/Microsoft.AspNet.Buffering/BufferingWriteStream.cs @@ -1,4 +1,4 @@ -// Copyright (c) .NET Foundation. All rights reserved. +// 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; @@ -159,7 +159,7 @@ namespace Microsoft.AspNet.Buffering return _innerStream.WriteAsync(buffer, offset, count, cancellationToken); } } -#if !DNXCORE50 +#if !DOTNET5_4 public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object state) { if (_isBuffering) diff --git a/src/Microsoft.AspNet.Buffering/project.json b/src/Microsoft.AspNet.Buffering/project.json index 9df583e0d5..93d2adc8b2 100644 --- a/src/Microsoft.AspNet.Buffering/project.json +++ b/src/Microsoft.AspNet.Buffering/project.json @@ -1,4 +1,4 @@ -{ +{ "version": "1.0.0-*", "description": "ASP.NET middleware for buffering response bodies.", "repository": { @@ -9,10 +9,9 @@ "Microsoft.AspNet.Http.Abstractions": "1.0.0-*" }, "frameworks": { - "dnx451": { }, - "dnxcore50": { - "dependencies": { - } + "net451": {}, + "dotnet5.4": { + "dependencies": {} } } -} +} \ No newline at end of file diff --git a/src/Microsoft.AspNet.HttpOverrides/project.json b/src/Microsoft.AspNet.HttpOverrides/project.json index d7910084bc..c3d1e4974d 100644 --- a/src/Microsoft.AspNet.HttpOverrides/project.json +++ b/src/Microsoft.AspNet.HttpOverrides/project.json @@ -9,8 +9,8 @@ "Microsoft.AspNet.Http.Extensions": "1.0.0-*" }, "frameworks": { - "dnx451": { }, - "dnxcore50": { + "net451": {}, + "dotnet5.4": { "dependencies": { "System.Collections": "4.0.10-*", "System.Linq": "4.0.0-*", @@ -18,4 +18,4 @@ } } } -} +} \ No newline at end of file From 07230d1682a934199d918aed6355ca742d952498 Mon Sep 17 00:00:00 2001 From: Pranav K Date: Wed, 28 Oct 2015 12:43:09 -0700 Subject: [PATCH 024/307] Updating to release NuGet.config. --- NuGet.config | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/NuGet.config b/NuGet.config index dae5aba3f9..e526481f82 100644 --- a/NuGet.config +++ b/NuGet.config @@ -1,7 +1,7 @@ - + \ No newline at end of file From 1a0743391d2f4021dacf4661b192f8dc6824eb10 Mon Sep 17 00:00:00 2001 From: Cesar Blum Silveira Date: Tue, 3 Nov 2015 12:01:21 -0800 Subject: [PATCH 025/307] Strong name everything. --- src/Microsoft.AspNet.Buffering/project.json | 4 ++++ src/Microsoft.AspNet.HttpOverrides/project.json | 4 ++++ tools/Key.snk | Bin 0 -> 596 bytes 3 files changed, 8 insertions(+) create mode 100644 tools/Key.snk diff --git a/src/Microsoft.AspNet.Buffering/project.json b/src/Microsoft.AspNet.Buffering/project.json index 93d2adc8b2..6bc54431a3 100644 --- a/src/Microsoft.AspNet.Buffering/project.json +++ b/src/Microsoft.AspNet.Buffering/project.json @@ -1,5 +1,9 @@ { "version": "1.0.0-*", + "compilationOptions": { + "warningsAsErrors": true, + "keyFile": "../../tools/Key.snk" + }, "description": "ASP.NET middleware for buffering response bodies.", "repository": { "type": "git", diff --git a/src/Microsoft.AspNet.HttpOverrides/project.json b/src/Microsoft.AspNet.HttpOverrides/project.json index c3d1e4974d..860acdb1b0 100644 --- a/src/Microsoft.AspNet.HttpOverrides/project.json +++ b/src/Microsoft.AspNet.HttpOverrides/project.json @@ -1,5 +1,9 @@ { "version": "1.0.0-*", + "compilationOptions": { + "warningsAsErrors": true, + "keyFile": "../../tools/Key.snk" + }, "description": "XForward and Method override middlewares for ASP.NET", "repository": { "type": "git", diff --git a/tools/Key.snk b/tools/Key.snk new file mode 100644 index 0000000000000000000000000000000000000000..e10e4889c125d3120cd9e81582243d70f7cbb806 GIT binary patch literal 596 zcmV-a0;~N80ssI2Bme+XQ$aES1ONa50098=Iw=HCsnz~#iVhm& zj%TU(_THUee?3yHBjk$37ysB?i5#7WD$={H zV4B!OxRPrb|8)HPg~A}8P>^=#y<)56#=E&NzcjOtPK~<4n6GHt=K$ro*T(lhby_@U zEk(hLzk1H)0yXj{A_5>fk-TgNoP|q6(tP2xo8zt8i%212CWM#AeCd?`hS|4~L({h~Moo(~vy&3Z z1uI}`fd^*>o=rwbAGymj6RM^pZm(*Kfhs+Y1#`-2JPWZMK8@;ZWCk2+9bX4YP);~fj-BU*R zQPvWv$89!{Rl9wM+zR>_TSkn^voYxA?2G iKnV#iZ6Ah`K>b=@=IjYJXrxL124zR(38)nxe+&q_$QXwJ literal 0 HcmV?d00001 From cbbddda8de950df15766dc7ecc568c1da7e21c4f Mon Sep 17 00:00:00 2001 From: Doug Bunting Date: Tue, 17 Nov 2015 10:51:01 -0800 Subject: [PATCH 026/307] Explicitly choose Mono 4.0.5 - avoids future problems related to aspnet/External#48 - e.g. when Travis updates default Mono version in `csharp` bundle --- .travis.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.travis.yml b/.travis.yml index 947bf868ee..dc44c0f660 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,4 +1,6 @@ language: csharp sudo: false +mono: + - 4.0.5 script: - ./build.sh --quiet verify \ No newline at end of file From 4bb8e229b6558b8ff8140f14e9c9145bf60a2993 Mon Sep 17 00:00:00 2001 From: Doug Bunting Date: Tue, 17 Nov 2015 12:29:23 -0800 Subject: [PATCH 027/307] Move Travis to supported Linux distribution - use Ubuntu 14.04 (Trusty) - Travis support for Trusty is in Beta and currently requires `sudo` - run `dnu restore` with DNX Core since aspnet/External#49 is not fixed in Mono versions we can use - add required dependencies for DNX Core to `.travis.yml` - addresses part of aspnet/Universe#290 --- .travis.yml | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index dc44c0f660..2fc624899f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,18 @@ language: csharp -sudo: false +sudo: required +dist: trusty +addons: + apt: + packages: + - gettext + - libcurl4-openssl-dev + - libicu-dev + - libssl-dev + - libunwind8 + - zlib1g +env: + - KOREBUILD_DNU_RESTORE_CORECLR=true mono: - 4.0.5 script: - - ./build.sh --quiet verify \ No newline at end of file + - ./build.sh --quiet verify From f8b5031ff1cb2bdf5dcbf7dd3ada4f73c20dbc02 Mon Sep 17 00:00:00 2001 From: Pranav K Date: Tue, 8 Dec 2015 15:47:59 -0800 Subject: [PATCH 028/307] Removing extraneous versions --- src/Microsoft.AspNet.Buffering/project.json | 6 ++---- src/Microsoft.AspNet.HttpOverrides/project.json | 10 ++-------- test/Microsoft.AspNet.Buffering.Tests/project.json | 11 ++++------- .../Microsoft.AspNet.HttpOverrides.Tests/project.json | 3 +++ 4 files changed, 11 insertions(+), 19 deletions(-) diff --git a/src/Microsoft.AspNet.Buffering/project.json b/src/Microsoft.AspNet.Buffering/project.json index 6bc54431a3..7d1964e378 100644 --- a/src/Microsoft.AspNet.Buffering/project.json +++ b/src/Microsoft.AspNet.Buffering/project.json @@ -13,9 +13,7 @@ "Microsoft.AspNet.Http.Abstractions": "1.0.0-*" }, "frameworks": { - "net451": {}, - "dotnet5.4": { - "dependencies": {} - } + "net451": { }, + "dotnet5.4": { } } } \ No newline at end of file diff --git a/src/Microsoft.AspNet.HttpOverrides/project.json b/src/Microsoft.AspNet.HttpOverrides/project.json index 860acdb1b0..93c184ad7a 100644 --- a/src/Microsoft.AspNet.HttpOverrides/project.json +++ b/src/Microsoft.AspNet.HttpOverrides/project.json @@ -13,13 +13,7 @@ "Microsoft.AspNet.Http.Extensions": "1.0.0-*" }, "frameworks": { - "net451": {}, - "dotnet5.4": { - "dependencies": { - "System.Collections": "4.0.10-*", - "System.Linq": "4.0.0-*", - "System.Threading": "4.0.10-*" - } - } + "net451": { }, + "dotnet5.4": { } } } \ No newline at end of file diff --git a/test/Microsoft.AspNet.Buffering.Tests/project.json b/test/Microsoft.AspNet.Buffering.Tests/project.json index 516bc624f1..3b87e6bb8a 100644 --- a/test/Microsoft.AspNet.Buffering.Tests/project.json +++ b/test/Microsoft.AspNet.Buffering.Tests/project.json @@ -1,5 +1,8 @@ { "version": "1.0.0-*", + "compilationOptions": { + "warningsAsErrors": true + }, "dependencies": { "Microsoft.AspNet.Buffering": "1.0.0-*", "Microsoft.AspNet.TestHost": "1.0.0-*", @@ -11,12 +14,6 @@ "frameworks": { "dnx451": { }, - "dnxcore50": { - "dependencies": { - "System.Collections": "4.0.10-*", - "System.Linq": "4.0.0-*", - "System.Threading": "4.0.10-*" - } - } + "dnxcore50": {} } } diff --git a/test/Microsoft.AspNet.HttpOverrides.Tests/project.json b/test/Microsoft.AspNet.HttpOverrides.Tests/project.json index e33d3add90..6aa7d8aac9 100644 --- a/test/Microsoft.AspNet.HttpOverrides.Tests/project.json +++ b/test/Microsoft.AspNet.HttpOverrides.Tests/project.json @@ -1,5 +1,8 @@ { "version": "1.0.0-*", + "compilationOptions": { + "warningsAsErrors": true + }, "dependencies": { "Microsoft.AspNet.HttpOverrides": "1.0.0-*", "Microsoft.AspNet.TestHost": "1.0.0-*", From 7a865a2f39970a6ce818d7b13258ff9c98bcf18c Mon Sep 17 00:00:00 2001 From: Pranav K Date: Fri, 11 Dec 2015 12:24:33 -0800 Subject: [PATCH 029/307] Updating to release NuGet.config. --- NuGet.config | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/NuGet.config b/NuGet.config index dae5aba3f9..e526481f82 100644 --- a/NuGet.config +++ b/NuGet.config @@ -1,7 +1,7 @@ - + \ No newline at end of file From 5e3c7cbbf0a947f02763af60bf776b14f461d0de Mon Sep 17 00:00:00 2001 From: Chris R Date: Tue, 15 Dec 2015 15:28:14 -0800 Subject: [PATCH 030/307] #2 add options, #19 fix IP parser, update extensions. --- BasicMiddleware.sln | 9 ++- .../HttpOverridesSample.xproj | 25 +++++++ .../Properties/launchSettings.json | 25 +++++++ samples/HttpOverridesSample/Startup.cs | 36 +++++++++ samples/HttpOverridesSample/hosting.json | 3 + samples/HttpOverridesSample/project.json | 26 +++++++ .../HttpOverridesSample/wwwroot/web.config | 9 +++ .../HttpMethodOverrideExtensions.cs | 21 +++++- .../HttpMethodOverrideMiddleware.cs | 19 +++-- .../HttpMethodOverrideOptions.cs | 14 ++++ .../IPEndPointParser.cs | 73 +++++++++++++++++++ .../OverrideHeaderExtensions.cs | 13 +++- .../OverrideHeaderMiddleware.cs | 42 +++++++---- .../OverrideHeaderOptions.cs | 2 +- .../Microsoft.AspNet.Buffering.Tests.xproj | 7 +- .../IPEndPointParserTest.cs | 46 ++++++++++++ .../OverrideHeaderMiddlewareTest.cs | 52 +++++++------ 17 files changed, 371 insertions(+), 51 deletions(-) create mode 100644 samples/HttpOverridesSample/HttpOverridesSample.xproj create mode 100644 samples/HttpOverridesSample/Properties/launchSettings.json create mode 100644 samples/HttpOverridesSample/Startup.cs create mode 100644 samples/HttpOverridesSample/hosting.json create mode 100644 samples/HttpOverridesSample/project.json create mode 100644 samples/HttpOverridesSample/wwwroot/web.config create mode 100644 src/Microsoft.AspNet.HttpOverrides/HttpMethodOverrideOptions.cs create mode 100644 src/Microsoft.AspNet.HttpOverrides/IPEndPointParser.cs create mode 100644 test/Microsoft.AspNet.HttpOverrides.Tests/IPEndPointParserTest.cs diff --git a/BasicMiddleware.sln b/BasicMiddleware.sln index d589e2f092..a3fc740b7b 100644 --- a/BasicMiddleware.sln +++ b/BasicMiddleware.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 14 -VisualStudioVersion = 14.0.23107.0 +VisualStudioVersion = 14.0.24720.0 MinimumVisualStudioVersion = 10.0.40219.1 Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNet.HttpOverrides", "src\Microsoft.AspNet.HttpOverrides\Microsoft.AspNet.HttpOverrides.xproj", "{517308C3-B477-4B01-B461-CAB9C10B6928}" EndProject @@ -24,6 +24,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "samples", "samples", "{9587 EndProject Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "ResponseBufferingSample", "samples\ResponseBufferingSample\ResponseBufferingSample.xproj", "{E5C55B80-7827-40EB-B661-32B0E0E431CA}" EndProject +Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "HttpOverridesSample", "samples\HttpOverridesSample\HttpOverridesSample.xproj", "{7F95478D-E1D4-4A64-BA42-B041591A96EB}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -50,6 +52,10 @@ Global {E5C55B80-7827-40EB-B661-32B0E0E431CA}.Debug|Any CPU.Build.0 = Debug|Any CPU {E5C55B80-7827-40EB-B661-32B0E0E431CA}.Release|Any CPU.ActiveCfg = Release|Any CPU {E5C55B80-7827-40EB-B661-32B0E0E431CA}.Release|Any CPU.Build.0 = Release|Any CPU + {7F95478D-E1D4-4A64-BA42-B041591A96EB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {7F95478D-E1D4-4A64-BA42-B041591A96EB}.Debug|Any CPU.Build.0 = Debug|Any CPU + {7F95478D-E1D4-4A64-BA42-B041591A96EB}.Release|Any CPU.ActiveCfg = Release|Any CPU + {7F95478D-E1D4-4A64-BA42-B041591A96EB}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -60,5 +66,6 @@ Global {2363D0DD-A3BF-437E-9B64-B33AE132D875} = {A5076D28-FA7E-4606-9410-FEDD0D603527} {F5F1D123-9C81-4A9E-8644-AA46B8E578FB} = {8437B0F3-3894-4828-A945-A9187F37631D} {E5C55B80-7827-40EB-B661-32B0E0E431CA} = {9587FE9F-5A17-42C4-8021-E87F59CECB98} + {7F95478D-E1D4-4A64-BA42-B041591A96EB} = {9587FE9F-5A17-42C4-8021-E87F59CECB98} EndGlobalSection EndGlobal diff --git a/samples/HttpOverridesSample/HttpOverridesSample.xproj b/samples/HttpOverridesSample/HttpOverridesSample.xproj new file mode 100644 index 0000000000..d7dd58a746 --- /dev/null +++ b/samples/HttpOverridesSample/HttpOverridesSample.xproj @@ -0,0 +1,25 @@ + + + + 14.0 + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) + + + + + 7f95478d-e1d4-4a64-ba42-b041591a96eb + HttpOverridesSample + ..\..\artifacts\obj\$(MSBuildProjectName) + ..\..\artifacts\bin\$(MSBuildProjectName)\ + + + + 2.0 + + + + + + + + diff --git a/samples/HttpOverridesSample/Properties/launchSettings.json b/samples/HttpOverridesSample/Properties/launchSettings.json new file mode 100644 index 0000000000..553b782dd9 --- /dev/null +++ b/samples/HttpOverridesSample/Properties/launchSettings.json @@ -0,0 +1,25 @@ +{ + "iisSettings": { + "windowsAuthentication": false, + "anonymousAuthentication": true, + "iisExpress": { + "applicationUrl": "http://localhost:1658/", + "sslPort": 0 + } + }, + "profiles": { + "IIS Express": { + "commandName": "IISExpress", + "launchBrowser": true, + "environmentVariables": { + "ASPNET_ENVIRONMENT": "Development" + } + }, + "web": { + "commandName": "web", + "environmentVariables": { + "ASPNET_ENVIRONMENT": "Development" + } + } + } +} \ No newline at end of file diff --git a/samples/HttpOverridesSample/Startup.cs b/samples/HttpOverridesSample/Startup.cs new file mode 100644 index 0000000000..dc4e4ccddb --- /dev/null +++ b/samples/HttpOverridesSample/Startup.cs @@ -0,0 +1,36 @@ +using Microsoft.AspNet.Builder; +using Microsoft.AspNet.Hosting; +using Microsoft.AspNet.Http; +using Microsoft.AspNet.HttpOverrides; + +namespace HttpOverridesSample +{ + public class Startup + { + // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. + public void Configure(IApplicationBuilder app) + { + app.UseIISPlatformHandler(); + app.UseOverrideHeaders(options => + { + options.ForwardedOptions = ForwardedHeaders.All; + }); + app.UseHttpMethodOverride(); + + app.Run(async (context) => + { + foreach (var header in context.Request.Headers) + { + 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($"RemoteIP: {context.Connection.RemoteIpAddress}\r\n"); + await context.Response.WriteAsync($"RemotePort: {context.Connection.RemotePort}\r\n"); + }); + } + + // Entry point for the application. + public static void Main(string[] args) => WebApplication.Run(args); + } +} diff --git a/samples/HttpOverridesSample/hosting.json b/samples/HttpOverridesSample/hosting.json new file mode 100644 index 0000000000..f8ef14574d --- /dev/null +++ b/samples/HttpOverridesSample/hosting.json @@ -0,0 +1,3 @@ +{ + "server": "Microsoft.AspNet.Server.Kestrel" +} diff --git a/samples/HttpOverridesSample/project.json b/samples/HttpOverridesSample/project.json new file mode 100644 index 0000000000..007668ab4b --- /dev/null +++ b/samples/HttpOverridesSample/project.json @@ -0,0 +1,26 @@ +{ + "version": "1.0.0-*", + "compilationOptions": { + "emitEntryPoint": true + }, + "dependencies": { + "Microsoft.AspNet.IISPlatformHandler": "1.0.0-*", + "Microsoft.AspNet.Server.Kestrel": "1.0.0-*", + "Microsoft.AspNet.HttpOverrides": "1.0.0-*" + }, + "commands": { + "web": "HttpOverridesSample" + }, + "frameworks": { + "dnx451": { }, + "dnxcore50": { } + }, + "exclude": [ + "wwwroot", + "node_modules" + ], + "publishExclude": [ + "**.user", + "**.vspscc" + ] +} diff --git a/samples/HttpOverridesSample/wwwroot/web.config b/samples/HttpOverridesSample/wwwroot/web.config new file mode 100644 index 0000000000..8485f6719f --- /dev/null +++ b/samples/HttpOverridesSample/wwwroot/web.config @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/src/Microsoft.AspNet.HttpOverrides/HttpMethodOverrideExtensions.cs b/src/Microsoft.AspNet.HttpOverrides/HttpMethodOverrideExtensions.cs index 42ae6e93b8..66aa5953a5 100644 --- a/src/Microsoft.AspNet.HttpOverrides/HttpMethodOverrideExtensions.cs +++ b/src/Microsoft.AspNet.HttpOverrides/HttpMethodOverrideExtensions.cs @@ -1,6 +1,7 @@ // 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; using Microsoft.AspNet.HttpOverrides; namespace Microsoft.AspNet.Builder @@ -14,7 +15,11 @@ namespace Microsoft.AspNet.Builder /// public static IApplicationBuilder UseHttpMethodOverride(this IApplicationBuilder builder) { - return builder.Use(next => new HttpMethodOverrideMiddleware(next).Invoke); + if (builder == null) + { + throw new ArgumentNullException(nameof(builder)); + } + return builder.Use(next => new HttpMethodOverrideMiddleware(next, new HttpMethodOverrideOptions()).Invoke); } /// @@ -23,9 +28,19 @@ namespace Microsoft.AspNet.Builder /// /// Denotes the element that contains the name of the resulting method type. /// - public static IApplicationBuilder UseHttpMethodOverride(this IApplicationBuilder builder, string formFieldInput) + public static IApplicationBuilder UseHttpMethodOverride(this IApplicationBuilder builder, Action configureOptions) { - return builder.Use(next => new HttpMethodOverrideMiddleware(next, formFieldInput).Invoke); + if (builder == null) + { + throw new ArgumentNullException(nameof(builder)); + } + if (configureOptions == null) + { + throw new ArgumentNullException(nameof(configureOptions)); + } + var options = new HttpMethodOverrideOptions(); + configureOptions(options); + return builder.Use(next => new HttpMethodOverrideMiddleware(next, options).Invoke); } } } diff --git a/src/Microsoft.AspNet.HttpOverrides/HttpMethodOverrideMiddleware.cs b/src/Microsoft.AspNet.HttpOverrides/HttpMethodOverrideMiddleware.cs index 46ede451f6..621f355af2 100644 --- a/src/Microsoft.AspNet.HttpOverrides/HttpMethodOverrideMiddleware.cs +++ b/src/Microsoft.AspNet.HttpOverrides/HttpMethodOverrideMiddleware.cs @@ -3,7 +3,6 @@ using System; using System.Threading.Tasks; -using Microsoft.AspNet.Builder; using Microsoft.AspNet.Http; namespace Microsoft.AspNet.HttpOverrides @@ -12,24 +11,32 @@ namespace Microsoft.AspNet.HttpOverrides { private const string xHttpMethodOverride = "X-Http-Method-Override"; private readonly RequestDelegate _next; - private readonly string _formFieldName; + private readonly HttpMethodOverrideOptions _options; - public HttpMethodOverrideMiddleware(RequestDelegate next, string formFieldName = null) + public HttpMethodOverrideMiddleware(RequestDelegate next, HttpMethodOverrideOptions options) { + if (next == null) + { + throw new ArgumentNullException(nameof(next)); + } + if (options == null) + { + throw new ArgumentNullException(nameof(options)); + } _next = next; - _formFieldName = formFieldName; + _options = options; } public async Task Invoke(HttpContext context) { if (string.Equals(context.Request.Method,"POST", StringComparison.OrdinalIgnoreCase)) { - if (_formFieldName != null) + if (_options.FormFieldName != null) { if (context.Request.HasFormContentType) { var form = await context.Request.ReadFormAsync(); - var methodType = form[_formFieldName]; + var methodType = form[_options.FormFieldName]; if (!string.IsNullOrEmpty(methodType)) { context.Request.Method = methodType; diff --git a/src/Microsoft.AspNet.HttpOverrides/HttpMethodOverrideOptions.cs b/src/Microsoft.AspNet.HttpOverrides/HttpMethodOverrideOptions.cs new file mode 100644 index 0000000000..033669acab --- /dev/null +++ b/src/Microsoft.AspNet.HttpOverrides/HttpMethodOverrideOptions.cs @@ -0,0 +1,14 @@ +// 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. + +namespace Microsoft.AspNet.HttpOverrides +{ + public class HttpMethodOverrideOptions + { + /// + /// Denotes the form element that contains the name of the resulting method type. + /// If not set the X-Http-Method-Override header will be used. + /// + public string FormFieldName { get; set; } + } +} diff --git a/src/Microsoft.AspNet.HttpOverrides/IPEndPointParser.cs b/src/Microsoft.AspNet.HttpOverrides/IPEndPointParser.cs new file mode 100644 index 0000000000..b303c0d2c6 --- /dev/null +++ b/src/Microsoft.AspNet.HttpOverrides/IPEndPointParser.cs @@ -0,0 +1,73 @@ +// 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; + +namespace Microsoft.AspNet.HttpOverrides +{ + public static class IPEndPointParser + { + public static bool TryParse(string addressWithPort, out IPEndPoint endpoint) + { + string addressPart = null; + string portPart = null; + IPAddress address; + endpoint = null; + + var lastColonIndex = addressWithPort.LastIndexOf(':'); + if (lastColonIndex > 0) + { + // IPv4 with port or IPv6 + var closingIndex = addressWithPort.LastIndexOf(']'); + if (closingIndex > 0) + { + // IPv6 with brackets + addressPart = addressWithPort.Substring(1, closingIndex - 1); + if (closingIndex < lastColonIndex) + { + // IPv6 with port [::1]:80 + portPart = addressWithPort.Substring(lastColonIndex + 1); + } + } + else + { + // IPv6 without port or IPv4 + var firstColonIndex = addressWithPort.IndexOf(':'); + if (firstColonIndex != lastColonIndex) + { + // IPv6 ::1 + addressPart = addressWithPort; + } + else + { + // IPv4 with port 127.0.0.1:123 + addressPart = addressWithPort.Substring(0, firstColonIndex); + portPart = addressWithPort.Substring(firstColonIndex + 1); + } + } + } + else + { + // IPv4 without port + addressPart = addressWithPort; + } + + if (IPAddress.TryParse(addressPart, out address)) + { + if (portPart != null) + { + int port; + if (int.TryParse(portPart, out port)) + { + endpoint = new IPEndPoint(address, port); + return true; + } + return false; + } + endpoint = new IPEndPoint(address, 0); + return true; + } + return false; + } + } +} \ No newline at end of file diff --git a/src/Microsoft.AspNet.HttpOverrides/OverrideHeaderExtensions.cs b/src/Microsoft.AspNet.HttpOverrides/OverrideHeaderExtensions.cs index 04acee970c..b02d7c5191 100644 --- a/src/Microsoft.AspNet.HttpOverrides/OverrideHeaderExtensions.cs +++ b/src/Microsoft.AspNet.HttpOverrides/OverrideHeaderExtensions.cs @@ -1,6 +1,7 @@ // 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; using Microsoft.AspNet.HttpOverrides; namespace Microsoft.AspNet.Builder @@ -13,8 +14,18 @@ namespace Microsoft.AspNet.Builder /// /// Enables the different override options. /// - public static IApplicationBuilder UseOverrideHeaders(this IApplicationBuilder builder, OverrideHeaderMiddlewareOptions options) + public static IApplicationBuilder UseOverrideHeaders(this IApplicationBuilder builder, Action configureOptions) { + if (builder == null) + { + throw new ArgumentNullException(nameof(builder)); + } + if (configureOptions == null) + { + throw new ArgumentNullException(nameof(configureOptions)); + } + var options = new OverrideHeaderOptions(); + configureOptions(options); return builder.Use(next => new OverrideHeaderMiddleware(next, options).Invoke); } } diff --git a/src/Microsoft.AspNet.HttpOverrides/OverrideHeaderMiddleware.cs b/src/Microsoft.AspNet.HttpOverrides/OverrideHeaderMiddleware.cs index dd3cb92260..f300f65d56 100644 --- a/src/Microsoft.AspNet.HttpOverrides/OverrideHeaderMiddleware.cs +++ b/src/Microsoft.AspNet.HttpOverrides/OverrideHeaderMiddleware.cs @@ -4,7 +4,6 @@ using System; using System.Net; using System.Threading.Tasks; -using Microsoft.AspNet.Builder; using Microsoft.AspNet.Http; namespace Microsoft.AspNet.HttpOverrides @@ -14,19 +13,18 @@ namespace Microsoft.AspNet.HttpOverrides private const string XForwardedForHeaderName = "X-Forwarded-For"; private const string XForwardedHostHeaderName = "X-Forwarded-Host"; private const string XForwardedProtoHeaderName = "X-Forwarded-Proto"; - private const string XOriginalIPName = "X-Original-IP"; + private const string XOriginalForName = "X-Original-For"; private const string XOriginalHostName = "X-Original-Host"; private const string XOriginalProtoName = "X-Original-Proto"; - private readonly OverrideHeaderMiddlewareOptions _options; + private readonly OverrideHeaderOptions _options; private readonly RequestDelegate _next; - public OverrideHeaderMiddleware(RequestDelegate next, OverrideHeaderMiddlewareOptions options) + public OverrideHeaderMiddleware(RequestDelegate next, OverrideHeaderOptions options) { if (next == null) { throw new ArgumentNullException(nameof(next)); } - if (options == null) { throw new ArgumentNullException(nameof(options)); @@ -37,25 +35,42 @@ namespace Microsoft.AspNet.HttpOverrides } public Task Invoke(HttpContext context) + { + UpdateRemoteIp(context); + + UpdateHost(context); + + UpdateScheme(context); + + return _next(context); + } + + private void UpdateRemoteIp(HttpContext context) { if ((_options.ForwardedOptions & ForwardedHeaders.XForwardedFor) != 0) { var xForwardedForHeaderValue = context.Request.Headers.GetCommaSeparatedValues(XForwardedForHeaderName); if (xForwardedForHeaderValue != null && xForwardedForHeaderValue.Length > 0) { - IPAddress ipFromHeader; - if (IPAddress.TryParse(xForwardedForHeaderValue[0], out ipFromHeader)) + IPEndPoint endpoint; + if (IPEndPointParser.TryParse(xForwardedForHeaderValue[0], out endpoint)) { - var remoteIPString = context.Connection.RemoteIpAddress?.ToString(); - if (!string.IsNullOrEmpty(remoteIPString)) + var connection = context.Connection; + var remoteIP = connection.RemoteIpAddress; + if (remoteIP != null) { - context.Request.Headers[XOriginalIPName] = remoteIPString; + var remoteIPString = new IPEndPoint(remoteIP, connection.RemotePort).ToString(); + context.Request.Headers[XOriginalForName] = remoteIPString; } - context.Connection.RemoteIpAddress = ipFromHeader; + connection.RemoteIpAddress = endpoint.Address; + connection.RemotePort = endpoint.Port; } } } + } + private void UpdateHost(HttpContext context) + { if ((_options.ForwardedOptions & ForwardedHeaders.XForwardedHost) != 0) { var xForwardHostHeaderValue = context.Request.Headers[XForwardedHostHeaderName]; @@ -69,7 +84,10 @@ namespace Microsoft.AspNet.HttpOverrides context.Request.Host = HostString.FromUriComponent(xForwardHostHeaderValue); } } + } + private void UpdateScheme(HttpContext context) + { if ((_options.ForwardedOptions & ForwardedHeaders.XForwardedProto) != 0) { var xForwardProtoHeaderValue = context.Request.Headers[XForwardedProtoHeaderName]; @@ -82,8 +100,6 @@ namespace Microsoft.AspNet.HttpOverrides context.Request.Scheme = xForwardProtoHeaderValue; } } - - return _next(context); } } } diff --git a/src/Microsoft.AspNet.HttpOverrides/OverrideHeaderOptions.cs b/src/Microsoft.AspNet.HttpOverrides/OverrideHeaderOptions.cs index 428408ab25..8b4f0756f4 100644 --- a/src/Microsoft.AspNet.HttpOverrides/OverrideHeaderOptions.cs +++ b/src/Microsoft.AspNet.HttpOverrides/OverrideHeaderOptions.cs @@ -3,7 +3,7 @@ namespace Microsoft.AspNet.HttpOverrides { - public class OverrideHeaderMiddlewareOptions + public class OverrideHeaderOptions { public ForwardedHeaders ForwardedOptions { get; set; } } diff --git a/test/Microsoft.AspNet.Buffering.Tests/Microsoft.AspNet.Buffering.Tests.xproj b/test/Microsoft.AspNet.Buffering.Tests/Microsoft.AspNet.Buffering.Tests.xproj index 16b38cf3d8..a047e54513 100644 --- a/test/Microsoft.AspNet.Buffering.Tests/Microsoft.AspNet.Buffering.Tests.xproj +++ b/test/Microsoft.AspNet.Buffering.Tests/Microsoft.AspNet.Buffering.Tests.xproj @@ -4,7 +4,6 @@ 14.0 $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - f5f1d123-9c81-4a9e-8644-aa46b8e578fb @@ -12,9 +11,11 @@ ..\..\artifacts\obj\$(MSBuildProjectName) ..\..\artifacts\bin\$(MSBuildProjectName)\ - 2.0 + + + - + \ No newline at end of file diff --git a/test/Microsoft.AspNet.HttpOverrides.Tests/IPEndPointParserTest.cs b/test/Microsoft.AspNet.HttpOverrides.Tests/IPEndPointParserTest.cs new file mode 100644 index 0000000000..9970dd8610 --- /dev/null +++ b/test/Microsoft.AspNet.HttpOverrides.Tests/IPEndPointParserTest.cs @@ -0,0 +1,46 @@ +// 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 Xunit; + +namespace Microsoft.AspNet.HttpOverrides +{ + public class IPEndPointParserTests + { + [Theory] + [InlineData("127.0.0.1", "127.0.0.1", 0)] + [InlineData("127.0.0.1:1", "127.0.0.1", 1)] + [InlineData("1", "0.0.0.1", 0)] + [InlineData("1:1", "0.0.0.1", 1)] + [InlineData("::1", "::1", 0)] + [InlineData("[::1]", "::1", 0)] + [InlineData("[::1]:1", "::1", 1)] + public void ParsesCorrectly(string input, string expectedAddress, int expectedPort) + { + IPEndPoint endpoint; + var success = IPEndPointParser.TryParse(input, out endpoint); + Assert.True(success); + Assert.Equal(expectedAddress, endpoint.Address.ToString()); + Assert.Equal(expectedPort, endpoint.Port); + } + + [InlineData(null)] + [InlineData("[::1]:")] + [InlineData("[::1:")] + [InlineData("::1:")] + [InlineData("127:")] + [InlineData("127.0.0.1:")] + [InlineData("")] + [InlineData("[]")] + [InlineData("]")] + [InlineData("]:1")] + public void ShouldNotParse(string input) + { + IPEndPoint endpoint; + var success = IPEndPointParser.TryParse(input, out endpoint); + Assert.False(success); + Assert.Equal(null, endpoint); + } + } +} \ No newline at end of file diff --git a/test/Microsoft.AspNet.HttpOverrides.Tests/OverrideHeaderMiddlewareTest.cs b/test/Microsoft.AspNet.HttpOverrides.Tests/OverrideHeaderMiddlewareTest.cs index 5355335e5a..38db395f0a 100644 --- a/test/Microsoft.AspNet.HttpOverrides.Tests/OverrideHeaderMiddlewareTest.cs +++ b/test/Microsoft.AspNet.HttpOverrides.Tests/OverrideHeaderMiddlewareTest.cs @@ -15,12 +15,13 @@ namespace Microsoft.AspNet.HttpOverrides public async Task XForwardedForOverrideChangesRemoteIp() { var assertsExecuted = false; - var options = new OverrideHeaderMiddlewareOptions(); - options.ForwardedOptions = ForwardedHeaders.XForwardedFor; var server = TestServer.Create(app => { - app.UseOverrideHeaders(options); + app.UseOverrideHeaders(options => + { + options.ForwardedOptions = ForwardedHeaders.XForwardedFor; + }); app.Run(context => { Assert.Equal("11.111.111.11", context.Connection.RemoteIpAddress.ToString()); @@ -39,12 +40,13 @@ namespace Microsoft.AspNet.HttpOverrides public async Task XForwardedForOverrideBadIpDoesntChangeRemoteIp() { var assertsExecuted = false; - var options = new OverrideHeaderMiddlewareOptions(); - options.ForwardedOptions = ForwardedHeaders.XForwardedFor; var server = TestServer.Create(app => { - app.UseOverrideHeaders(options); + app.UseOverrideHeaders(options => + { + options.ForwardedOptions = ForwardedHeaders.XForwardedFor; + }); app.Run(context => { Assert.Null(context.Connection.RemoteIpAddress); @@ -63,12 +65,13 @@ namespace Microsoft.AspNet.HttpOverrides public async Task XForwardedHostOverrideChangesRequestHost() { var assertsExecuted = false; - var options = new OverrideHeaderMiddlewareOptions(); - options.ForwardedOptions = ForwardedHeaders.XForwardedHost; var server = TestServer.Create(app => { - app.UseOverrideHeaders(options); + app.UseOverrideHeaders(options => + { + options.ForwardedOptions = ForwardedHeaders.XForwardedHost; + }); app.Run(context => { Assert.Equal("testhost", context.Request.Host.ToString()); @@ -87,12 +90,13 @@ namespace Microsoft.AspNet.HttpOverrides public async Task XForwardedProtoOverrideChangesRequestProtocol() { var assertsExecuted = false; - var options = new OverrideHeaderMiddlewareOptions(); - options.ForwardedOptions = ForwardedHeaders.XForwardedProto; var server = TestServer.Create(app => { - app.UseOverrideHeaders(options); + app.UseOverrideHeaders(options => + { + options.ForwardedOptions = ForwardedHeaders.XForwardedProto; + }); app.Run(context => { Assert.Equal("TestProtocol", context.Request.Scheme); @@ -110,7 +114,7 @@ namespace Microsoft.AspNet.HttpOverrides [Fact] public void AllForwardsDisabledByDefault() { - var options = new OverrideHeaderMiddlewareOptions(); + var options = new OverrideHeaderOptions(); Assert.True(options.ForwardedOptions == 0); } @@ -118,12 +122,13 @@ namespace Microsoft.AspNet.HttpOverrides public async Task AllForwardsEnabledChangeRequestRemoteIpHostandProtocol() { var assertsExecuted = false; - var options = new OverrideHeaderMiddlewareOptions(); - options.ForwardedOptions = ForwardedHeaders.All; var server = TestServer.Create(app => { - app.UseOverrideHeaders(options); + app.UseOverrideHeaders(options => + { + options.ForwardedOptions = ForwardedHeaders.All; + }); app.Run(context => { Assert.Equal("11.111.111.11", context.Connection.RemoteIpAddress.ToString()); @@ -146,12 +151,13 @@ namespace Microsoft.AspNet.HttpOverrides public async Task AllOptionsDisabledRequestDoesntChange() { var assertsExecuted = false; - var options = new OverrideHeaderMiddlewareOptions(); - options.ForwardedOptions = ForwardedHeaders.None; var server = TestServer.Create(app => { - app.UseOverrideHeaders(options); + app.UseOverrideHeaders(options => + { + options.ForwardedOptions = ForwardedHeaders.None; + }); app.Run(context => { Assert.Null(context.Connection.RemoteIpAddress); @@ -174,13 +180,13 @@ namespace Microsoft.AspNet.HttpOverrides public async Task PartiallyEnabledForwardsPartiallyChangesRequest() { var assertsExecuted = false; - var XForwardedForAndProto = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto; - var options = new OverrideHeaderMiddlewareOptions(); - options.ForwardedOptions = XForwardedForAndProto; var server = TestServer.Create(app => { - app.UseOverrideHeaders(options); + app.UseOverrideHeaders(options => + { + options.ForwardedOptions = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto; + }); app.Run(context => { Assert.Equal("11.111.111.11", context.Connection.RemoteIpAddress.ToString()); From 92fff3ccf34de5a06bd7030c4bdefa00819dd660 Mon Sep 17 00:00:00 2001 From: John Luo Date: Thu, 17 Dec 2015 19:32:13 -0800 Subject: [PATCH 031/307] Reacting to new Hosting API --- samples/HttpOverridesSample/Startup.cs | 10 +- .../Properties/launchSettings.json | 18 +- samples/ResponseBufferingSample/Startup.cs | 12 + samples/ResponseBufferingSample/hosting.json | 3 + samples/ResponseBufferingSample/project.json | 11 +- .../wwwroot/web.config | 9 + .../ResponseBufferingMiddlewareTests.cs | 287 ++++++++++-------- .../HttpMethodOverrideMiddlewareTest.cs | 57 ++-- .../OverrideHeaderMiddlewareTest.cs | 181 ++++++----- 9 files changed, 332 insertions(+), 256 deletions(-) create mode 100644 samples/ResponseBufferingSample/hosting.json create mode 100644 samples/ResponseBufferingSample/wwwroot/web.config diff --git a/samples/HttpOverridesSample/Startup.cs b/samples/HttpOverridesSample/Startup.cs index dc4e4ccddb..4c71f32a93 100644 --- a/samples/HttpOverridesSample/Startup.cs +++ b/samples/HttpOverridesSample/Startup.cs @@ -31,6 +31,14 @@ namespace HttpOverridesSample } // Entry point for the application. - public static void Main(string[] args) => WebApplication.Run(args); + public static void Main(string[] args) + { + var application = new WebApplicationBuilder() + .UseConfiguration(WebApplicationConfiguration.GetDefault(args)) + .UseStartup() + .Build(); + + application.Run(); + } } } diff --git a/samples/ResponseBufferingSample/Properties/launchSettings.json b/samples/ResponseBufferingSample/Properties/launchSettings.json index 0e57697bac..2555984271 100644 --- a/samples/ResponseBufferingSample/Properties/launchSettings.json +++ b/samples/ResponseBufferingSample/Properties/launchSettings.json @@ -1,4 +1,12 @@ { + "iisSettings": { + "windowsAuthentication": false, + "anonymousAuthentication": true, + "iisExpress": { + "applicationUrl": "http://localhost:49657/", + "sslPort": 0 + } + }, "profiles": { "IIS Express": { "commandName": "IISExpress", @@ -9,13 +17,9 @@ }, "web": { "commandName": "web", - "launchBrowser": true, - "launchUrl": "http://localhost:5000/" - }, - "kestrel": { - "commandName": "kestrel", - "launchBrowser": true, - "launchUrl": "http://localhost:5001/" + "environmentVariables": { + "Hosting:Environment": "Development" + } } } } \ No newline at end of file diff --git a/samples/ResponseBufferingSample/Startup.cs b/samples/ResponseBufferingSample/Startup.cs index db8b7d9eca..78f824dce4 100644 --- a/samples/ResponseBufferingSample/Startup.cs +++ b/samples/ResponseBufferingSample/Startup.cs @@ -1,4 +1,5 @@ using Microsoft.AspNet.Builder; +using Microsoft.AspNet.Hosting; using Microsoft.AspNet.Http; using Microsoft.Extensions.DependencyInjection; @@ -32,5 +33,16 @@ namespace ResponseBufferingSample await context.Response.WriteAsync("Hi Bob!"); }); } + + // Entry point for the application. + public static void Main(string[] args) + { + var application = new WebApplicationBuilder() + .UseConfiguration(WebApplicationConfiguration.GetDefault(args)) + .UseStartup() + .Build(); + + application.Run(); + } } } diff --git a/samples/ResponseBufferingSample/hosting.json b/samples/ResponseBufferingSample/hosting.json new file mode 100644 index 0000000000..f8ef14574d --- /dev/null +++ b/samples/ResponseBufferingSample/hosting.json @@ -0,0 +1,3 @@ +{ + "server": "Microsoft.AspNet.Server.Kestrel" +} diff --git a/samples/ResponseBufferingSample/project.json b/samples/ResponseBufferingSample/project.json index f43d9ec282..08e998cddf 100644 --- a/samples/ResponseBufferingSample/project.json +++ b/samples/ResponseBufferingSample/project.json @@ -1,15 +1,14 @@ { - "webroot": "wwwroot", "version": "1.0.0-*", "dependencies": { - "Kestrel": "1.0.0-*", "Microsoft.AspNet.Buffering": "1.0.0-*", - "Microsoft.AspNet.Server.IIS": "1.0.0-*", - "Microsoft.AspNet.Server.WebListener": "1.0.0-*" + "Microsoft.AspNet.Server.Kestrel": "1.0.0-*" + }, + "compilationOptions": { + "emitEntryPoint": true }, "commands": { - "web": "Microsoft.AspNet.Server.WebListener --server.urls=http://localhost:5000", - "kestrel": "Kestrel --server.urls=http://localhost:5001" + "web": "ResponseBufferingSample" }, "frameworks": { "dnx451": { }, diff --git a/samples/ResponseBufferingSample/wwwroot/web.config b/samples/ResponseBufferingSample/wwwroot/web.config new file mode 100644 index 0000000000..9a0d90abf8 --- /dev/null +++ b/samples/ResponseBufferingSample/wwwroot/web.config @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/test/Microsoft.AspNet.Buffering.Tests/ResponseBufferingMiddlewareTests.cs b/test/Microsoft.AspNet.Buffering.Tests/ResponseBufferingMiddlewareTests.cs index 5569a14222..fc07df25ec 100644 --- a/test/Microsoft.AspNet.Buffering.Tests/ResponseBufferingMiddlewareTests.cs +++ b/test/Microsoft.AspNet.Buffering.Tests/ResponseBufferingMiddlewareTests.cs @@ -7,6 +7,7 @@ using System.IO; using System.Linq; using System.Threading.Tasks; using Microsoft.AspNet.Builder; +using Microsoft.AspNet.Hosting; using Microsoft.AspNet.Http; using Microsoft.AspNet.Http.Features; using Microsoft.AspNet.TestHost; @@ -19,18 +20,20 @@ namespace Microsoft.AspNet.Buffering.Tests [Fact] public async Task BufferResponse_SetsContentLength() { - var server = TestServer.Create(app => - { - app.UseResponseBuffering(); - app.Run(async context => + var builder = new WebApplicationBuilder() + .Configure(app => { - Assert.False(context.Response.HasStarted); - Assert.True(context.Response.Body.CanSeek); - await context.Response.WriteAsync("Hello World"); - Assert.False(context.Response.HasStarted); - Assert.True(context.Response.Body.CanSeek); + app.UseResponseBuffering(); + app.Run(async context => + { + Assert.False(context.Response.HasStarted); + Assert.True(context.Response.Body.CanSeek); + await context.Response.WriteAsync("Hello World"); + Assert.False(context.Response.HasStarted); + Assert.True(context.Response.Body.CanSeek); + }); }); - }); + var server = new TestServer(builder); var response = await server.CreateClient().GetAsync(""); response.EnsureSuccessStatusCode(); @@ -45,19 +48,21 @@ namespace Microsoft.AspNet.Buffering.Tests [Fact] public async Task BufferResponseWithManualContentLength_NotReplaced() { - var server = TestServer.Create(app => - { - app.UseResponseBuffering(); - app.Run(async context => + var builder = new WebApplicationBuilder() + .Configure(app => { - context.Response.ContentLength = 12; - Assert.False(context.Response.HasStarted); - Assert.True(context.Response.Body.CanSeek); - await context.Response.WriteAsync("Hello World"); - Assert.False(context.Response.HasStarted); - Assert.True(context.Response.Body.CanSeek); + app.UseResponseBuffering(); + app.Run(async context => + { + context.Response.ContentLength = 12; + Assert.False(context.Response.HasStarted); + Assert.True(context.Response.Body.CanSeek); + await context.Response.WriteAsync("Hello World"); + Assert.False(context.Response.HasStarted); + Assert.True(context.Response.Body.CanSeek); + }); }); - }); + var server = new TestServer(builder); var response = await server.CreateClient().GetAsync(""); response.EnsureSuccessStatusCode(); @@ -71,36 +76,38 @@ namespace Microsoft.AspNet.Buffering.Tests [Fact] public async Task Seek_AllowsResttingBuffer() { - var server = TestServer.Create(app => - { - app.UseResponseBuffering(); - app.Run(async context => + var builder = new WebApplicationBuilder() + .Configure(app => { - var body = context.Response.Body; - Assert.False(context.Response.HasStarted); - Assert.True(body.CanSeek); - Assert.Equal(0, body.Position); - Assert.Equal(0, body.Length); + app.UseResponseBuffering(); + app.Run(async context => + { + var body = context.Response.Body; + Assert.False(context.Response.HasStarted); + Assert.True(body.CanSeek); + Assert.Equal(0, body.Position); + Assert.Equal(0, body.Length); - await context.Response.WriteAsync("Hello World"); - Assert.False(context.Response.HasStarted); - Assert.True(context.Response.Body.CanSeek); - Assert.Equal(11, body.Position); - Assert.Equal(11, body.Length); + await context.Response.WriteAsync("Hello World"); + Assert.False(context.Response.HasStarted); + Assert.True(context.Response.Body.CanSeek); + Assert.Equal(11, body.Position); + Assert.Equal(11, body.Length); - Assert.Throws(() => body.Seek(1, SeekOrigin.Begin)); - Assert.Throws(() => body.Seek(0, SeekOrigin.Current)); - Assert.Throws(() => body.Seek(0, SeekOrigin.End)); + Assert.Throws(() => body.Seek(1, SeekOrigin.Begin)); + Assert.Throws(() => body.Seek(0, SeekOrigin.Current)); + Assert.Throws(() => body.Seek(0, SeekOrigin.End)); - Assert.Equal(0, body.Seek(0, SeekOrigin.Begin)); - Assert.Equal(0, body.Position); - Assert.Equal(0, body.Length); + Assert.Equal(0, body.Seek(0, SeekOrigin.Begin)); + Assert.Equal(0, body.Position); + Assert.Equal(0, body.Length); - await context.Response.WriteAsync("12345"); - Assert.Equal(5, body.Position); - Assert.Equal(5, body.Length); + await context.Response.WriteAsync("12345"); + Assert.Equal(5, body.Position); + Assert.Equal(5, body.Length); + }); }); - }); + var server = new TestServer(builder); var response = await server.CreateClient().GetAsync(""); response.EnsureSuccessStatusCode(); @@ -115,34 +122,36 @@ namespace Microsoft.AspNet.Buffering.Tests [Fact] public async Task SetPosition_AllowsResttingBuffer() { - var server = TestServer.Create(app => - { - app.UseResponseBuffering(); - app.Run(async context => + var builder = new WebApplicationBuilder() + .Configure(app => { - var body = context.Response.Body; - Assert.False(context.Response.HasStarted); - Assert.True(body.CanSeek); - Assert.Equal(0, body.Position); - Assert.Equal(0, body.Length); + app.UseResponseBuffering(); + app.Run(async context => + { + var body = context.Response.Body; + Assert.False(context.Response.HasStarted); + Assert.True(body.CanSeek); + Assert.Equal(0, body.Position); + Assert.Equal(0, body.Length); - await context.Response.WriteAsync("Hello World"); - Assert.False(context.Response.HasStarted); - Assert.True(context.Response.Body.CanSeek); - Assert.Equal(11, body.Position); - Assert.Equal(11, body.Length); + await context.Response.WriteAsync("Hello World"); + Assert.False(context.Response.HasStarted); + Assert.True(context.Response.Body.CanSeek); + Assert.Equal(11, body.Position); + Assert.Equal(11, body.Length); - Assert.Throws(() => body.Position = 1); + Assert.Throws(() => body.Position = 1); - body.Position = 0; - Assert.Equal(0, body.Position); - Assert.Equal(0, body.Length); + body.Position = 0; + Assert.Equal(0, body.Position); + Assert.Equal(0, body.Length); - await context.Response.WriteAsync("12345"); - Assert.Equal(5, body.Position); - Assert.Equal(5, body.Length); + await context.Response.WriteAsync("12345"); + Assert.Equal(5, body.Position); + Assert.Equal(5, body.Length); + }); }); - }); + var server = new TestServer(builder); var response = await server.CreateClient().GetAsync(""); response.EnsureSuccessStatusCode(); @@ -157,34 +166,36 @@ namespace Microsoft.AspNet.Buffering.Tests [Fact] public async Task SetLength_AllowsResttingBuffer() { - var server = TestServer.Create(app => - { - app.UseResponseBuffering(); - app.Run(async context => + var builder = new WebApplicationBuilder() + .Configure(app => { - var body = context.Response.Body; - Assert.False(context.Response.HasStarted); - Assert.True(body.CanSeek); - Assert.Equal(0, body.Position); - Assert.Equal(0, body.Length); + app.UseResponseBuffering(); + app.Run(async context => + { + var body = context.Response.Body; + Assert.False(context.Response.HasStarted); + Assert.True(body.CanSeek); + Assert.Equal(0, body.Position); + Assert.Equal(0, body.Length); - await context.Response.WriteAsync("Hello World"); - Assert.False(context.Response.HasStarted); - Assert.True(context.Response.Body.CanSeek); - Assert.Equal(11, body.Position); - Assert.Equal(11, body.Length); + await context.Response.WriteAsync("Hello World"); + Assert.False(context.Response.HasStarted); + Assert.True(context.Response.Body.CanSeek); + Assert.Equal(11, body.Position); + Assert.Equal(11, body.Length); - Assert.Throws(() => body.SetLength(1)); + Assert.Throws(() => body.SetLength(1)); - body.SetLength(0); - Assert.Equal(0, body.Position); - Assert.Equal(0, body.Length); + body.SetLength(0); + Assert.Equal(0, body.Position); + Assert.Equal(0, body.Length); - await context.Response.WriteAsync("12345"); - Assert.Equal(5, body.Position); - Assert.Equal(5, body.Length); + await context.Response.WriteAsync("12345"); + Assert.Equal(5, body.Position); + Assert.Equal(5, body.Length); + }); }); - }); + var server = new TestServer(builder); var response = await server.CreateClient().GetAsync(""); response.EnsureSuccessStatusCode(); @@ -199,27 +210,29 @@ namespace Microsoft.AspNet.Buffering.Tests [Fact] public async Task DisableBufferingViaFeature() { - var server = TestServer.Create(app => - { - app.UseResponseBuffering(); - app.Run(async context => + var builder = new WebApplicationBuilder() + .Configure(app => { - Assert.False(context.Response.HasStarted); - Assert.True(context.Response.Body.CanSeek); + app.UseResponseBuffering(); + app.Run(async context => + { + Assert.False(context.Response.HasStarted); + Assert.True(context.Response.Body.CanSeek); - var bufferingFeature = context.Features.Get(); - Assert.NotNull(bufferingFeature); - bufferingFeature.DisableResponseBuffering(); + var bufferingFeature = context.Features.Get(); + Assert.NotNull(bufferingFeature); + bufferingFeature.DisableResponseBuffering(); - Assert.False(context.Response.HasStarted); - Assert.False(context.Response.Body.CanSeek); + Assert.False(context.Response.HasStarted); + Assert.False(context.Response.Body.CanSeek); - await context.Response.WriteAsync("Hello World"); + await context.Response.WriteAsync("Hello World"); - Assert.True(context.Response.HasStarted); - Assert.False(context.Response.Body.CanSeek); + Assert.True(context.Response.HasStarted); + Assert.False(context.Response.Body.CanSeek); + }); }); - }); + var server = new TestServer(builder); var response = await server.CreateClient().GetAsync(""); response.EnsureSuccessStatusCode(); @@ -231,32 +244,34 @@ namespace Microsoft.AspNet.Buffering.Tests [Fact] public async Task DisableBufferingViaFeatureAfterFirstWrite_Flushes() { - var server = TestServer.Create(app => - { - app.UseResponseBuffering(); - app.Run(async context => + var builder = new WebApplicationBuilder() + .Configure(app => { - Assert.False(context.Response.HasStarted); - Assert.True(context.Response.Body.CanSeek); + app.UseResponseBuffering(); + app.Run(async context => + { + Assert.False(context.Response.HasStarted); + Assert.True(context.Response.Body.CanSeek); - await context.Response.WriteAsync("Hello"); + await context.Response.WriteAsync("Hello"); - Assert.False(context.Response.HasStarted); - Assert.True(context.Response.Body.CanSeek); + Assert.False(context.Response.HasStarted); + Assert.True(context.Response.Body.CanSeek); - var bufferingFeature = context.Features.Get(); - Assert.NotNull(bufferingFeature); - bufferingFeature.DisableResponseBuffering(); + var bufferingFeature = context.Features.Get(); + Assert.NotNull(bufferingFeature); + bufferingFeature.DisableResponseBuffering(); - Assert.True(context.Response.HasStarted); - Assert.False(context.Response.Body.CanSeek); + Assert.True(context.Response.HasStarted); + Assert.False(context.Response.Body.CanSeek); - await context.Response.WriteAsync(" World"); + await context.Response.WriteAsync(" World"); - Assert.True(context.Response.HasStarted); - Assert.False(context.Response.Body.CanSeek); + Assert.True(context.Response.HasStarted); + Assert.False(context.Response.Body.CanSeek); + }); }); - }); + var server = new TestServer(builder); var response = await server.CreateClient().GetAsync(""); response.EnsureSuccessStatusCode(); @@ -268,25 +283,27 @@ namespace Microsoft.AspNet.Buffering.Tests [Fact] public async Task FlushDisablesBuffering() { - var server = TestServer.Create(app => - { - app.UseResponseBuffering(); - app.Run(async context => + var builder = new WebApplicationBuilder() + .Configure(app => { - Assert.False(context.Response.HasStarted); - Assert.True(context.Response.Body.CanSeek); + app.UseResponseBuffering(); + app.Run(async context => + { + Assert.False(context.Response.HasStarted); + Assert.True(context.Response.Body.CanSeek); - context.Response.Body.Flush(); + context.Response.Body.Flush(); - Assert.True(context.Response.HasStarted); - Assert.False(context.Response.Body.CanSeek); + Assert.True(context.Response.HasStarted); + Assert.False(context.Response.Body.CanSeek); - await context.Response.WriteAsync("Hello World"); + await context.Response.WriteAsync("Hello World"); - Assert.True(context.Response.HasStarted); - Assert.False(context.Response.Body.CanSeek); + Assert.True(context.Response.HasStarted); + Assert.False(context.Response.Body.CanSeek); + }); }); - }); + var server = new TestServer(builder); var response = await server.CreateClient().GetAsync(""); response.EnsureSuccessStatusCode(); diff --git a/test/Microsoft.AspNet.HttpOverrides.Tests/HttpMethodOverrideMiddlewareTest.cs b/test/Microsoft.AspNet.HttpOverrides.Tests/HttpMethodOverrideMiddlewareTest.cs index de987a4e63..d077fac906 100644 --- a/test/Microsoft.AspNet.HttpOverrides.Tests/HttpMethodOverrideMiddlewareTest.cs +++ b/test/Microsoft.AspNet.HttpOverrides.Tests/HttpMethodOverrideMiddlewareTest.cs @@ -4,6 +4,7 @@ using System.Net.Http; using System.Threading.Tasks; using Microsoft.AspNet.Builder; +using Microsoft.AspNet.Hosting; using Microsoft.AspNet.TestHost; using Xunit; @@ -15,16 +16,18 @@ namespace Microsoft.AspNet.HttpOverrides public async Task XHttpMethodOverrideHeaderAvaiableChangesRequestMethod() { var assertsExecuted = false; - var server = TestServer.Create(app => - { - app.UseHttpMethodOverride(); - app.Run(context => + var builder = new WebApplicationBuilder() + .Configure(app => { - assertsExecuted = true; - Assert.Equal("DELETE", context.Request.Method); - return Task.FromResult(0); + app.UseHttpMethodOverride(); + app.Run(context => + { + assertsExecuted = true; + Assert.Equal("DELETE", context.Request.Method); + return Task.FromResult(0); + }); }); - }); + var server = new TestServer(builder); var req = new HttpRequestMessage(HttpMethod.Post, ""); req.Headers.Add("X-Http-Method-Override", "DELETE"); @@ -36,16 +39,19 @@ namespace Microsoft.AspNet.HttpOverrides public async Task XHttpMethodOverrideHeaderUnavaiableDoesntChangeRequestMethod() { var assertsExecuted = false; - var server = TestServer.Create(app => - { - app.UseHttpMethodOverride(); - app.Run(context => + var builder = new WebApplicationBuilder() + .Configure(app => { - Assert.Equal("POST",context.Request.Method); - assertsExecuted = true; - return Task.FromResult(0); + app.UseHttpMethodOverride(); + app.Run(context => + { + Assert.Equal("POST",context.Request.Method); + assertsExecuted = true; + return Task.FromResult(0); + }); }); - }); + var server = new TestServer(builder); + var req = new HttpRequestMessage(HttpMethod.Post, ""); await server.CreateClient().SendAsync(req); Assert.True(assertsExecuted); @@ -55,16 +61,19 @@ namespace Microsoft.AspNet.HttpOverrides public async Task XHttpMethodOverrideFromGetRequestDoesntChangeMethodType() { var assertsExecuted = false; - var server = TestServer.Create(app => - { - app.UseHttpMethodOverride(); - app.Run(context => + var builder = new WebApplicationBuilder() + .Configure(app => { - Assert.Equal("GET", context.Request.Method); - assertsExecuted = true; - return Task.FromResult(0); + app.UseHttpMethodOverride(); + app.Run(context => + { + Assert.Equal("GET", context.Request.Method); + assertsExecuted = true; + return Task.FromResult(0); + }); }); - }); + var server = new TestServer(builder); + var req = new HttpRequestMessage(HttpMethod.Get, ""); await server.CreateClient().SendAsync(req); Assert.True(assertsExecuted); diff --git a/test/Microsoft.AspNet.HttpOverrides.Tests/OverrideHeaderMiddlewareTest.cs b/test/Microsoft.AspNet.HttpOverrides.Tests/OverrideHeaderMiddlewareTest.cs index 38db395f0a..b6ef29b458 100644 --- a/test/Microsoft.AspNet.HttpOverrides.Tests/OverrideHeaderMiddlewareTest.cs +++ b/test/Microsoft.AspNet.HttpOverrides.Tests/OverrideHeaderMiddlewareTest.cs @@ -4,6 +4,7 @@ using System.Net.Http; using System.Threading.Tasks; using Microsoft.AspNet.Builder; +using Microsoft.AspNet.Hosting; using Microsoft.AspNet.TestHost; using Xunit; @@ -16,19 +17,21 @@ namespace Microsoft.AspNet.HttpOverrides { var assertsExecuted = false; - var server = TestServer.Create(app => - { - app.UseOverrideHeaders(options => + var builder = new WebApplicationBuilder() + .Configure(app => { - options.ForwardedOptions = ForwardedHeaders.XForwardedFor; + app.UseOverrideHeaders(options => + { + options.ForwardedOptions = ForwardedHeaders.XForwardedFor; + }); + app.Run(context => + { + Assert.Equal("11.111.111.11", context.Connection.RemoteIpAddress.ToString()); + assertsExecuted = true; + return Task.FromResult(0); + }); }); - app.Run(context => - { - Assert.Equal("11.111.111.11", context.Connection.RemoteIpAddress.ToString()); - assertsExecuted = true; - return Task.FromResult(0); - }); - }); + var server = new TestServer(builder); var req = new HttpRequestMessage(HttpMethod.Get, ""); req.Headers.Add("X-Forwarded-For", "11.111.111.11"); @@ -41,19 +44,21 @@ namespace Microsoft.AspNet.HttpOverrides { var assertsExecuted = false; - var server = TestServer.Create(app => - { - app.UseOverrideHeaders(options => + var builder = new WebApplicationBuilder() + .Configure(app => { - options.ForwardedOptions = ForwardedHeaders.XForwardedFor; + app.UseOverrideHeaders(options => + { + options.ForwardedOptions = ForwardedHeaders.XForwardedFor; + }); + app.Run(context => + { + Assert.Null(context.Connection.RemoteIpAddress); + assertsExecuted = true; + return Task.FromResult(0); + }); }); - app.Run(context => - { - Assert.Null(context.Connection.RemoteIpAddress); - assertsExecuted = true; - return Task.FromResult(0); - }); - }); + var server = new TestServer(builder); var req = new HttpRequestMessage(HttpMethod.Get, ""); req.Headers.Add("X-Forwarded-For", "BAD-IP"); @@ -66,19 +71,21 @@ namespace Microsoft.AspNet.HttpOverrides { var assertsExecuted = false; - var server = TestServer.Create(app => - { - app.UseOverrideHeaders(options => + var builder = new WebApplicationBuilder() + .Configure(app => { - options.ForwardedOptions = ForwardedHeaders.XForwardedHost; + app.UseOverrideHeaders(options => + { + options.ForwardedOptions = ForwardedHeaders.XForwardedHost; + }); + app.Run(context => + { + Assert.Equal("testhost", context.Request.Host.ToString()); + assertsExecuted = true; + return Task.FromResult(0); + }); }); - app.Run(context => - { - Assert.Equal("testhost", context.Request.Host.ToString()); - assertsExecuted = true; - return Task.FromResult(0); - }); - }); + var server = new TestServer(builder); var req = new HttpRequestMessage(HttpMethod.Get, ""); req.Headers.Add("X-Forwarded-Host", "testhost"); @@ -91,19 +98,21 @@ namespace Microsoft.AspNet.HttpOverrides { var assertsExecuted = false; - var server = TestServer.Create(app => - { - app.UseOverrideHeaders(options => + var builder = new WebApplicationBuilder() + .Configure(app => { - options.ForwardedOptions = ForwardedHeaders.XForwardedProto; + app.UseOverrideHeaders(options => + { + options.ForwardedOptions = ForwardedHeaders.XForwardedProto; + }); + app.Run(context => + { + Assert.Equal("TestProtocol", context.Request.Scheme); + assertsExecuted = true; + return Task.FromResult(0); + }); }); - app.Run(context => - { - Assert.Equal("TestProtocol", context.Request.Scheme); - assertsExecuted = true; - return Task.FromResult(0); - }); - }); + var server = new TestServer(builder); var req = new HttpRequestMessage(HttpMethod.Get, ""); req.Headers.Add("X-Forwarded-Proto", "TestProtocol"); @@ -123,21 +132,23 @@ namespace Microsoft.AspNet.HttpOverrides { var assertsExecuted = false; - var server = TestServer.Create(app => - { - app.UseOverrideHeaders(options => + var builder = new WebApplicationBuilder() + .Configure(app => { - options.ForwardedOptions = ForwardedHeaders.All; + app.UseOverrideHeaders(options => + { + options.ForwardedOptions = ForwardedHeaders.All; + }); + app.Run(context => + { + Assert.Equal("11.111.111.11", context.Connection.RemoteIpAddress.ToString()); + Assert.Equal("testhost", context.Request.Host.ToString()); + Assert.Equal("Protocol", context.Request.Scheme); + assertsExecuted = true; + return Task.FromResult(0); + }); }); - app.Run(context => - { - Assert.Equal("11.111.111.11", context.Connection.RemoteIpAddress.ToString()); - Assert.Equal("testhost", context.Request.Host.ToString()); - Assert.Equal("Protocol", context.Request.Scheme); - assertsExecuted = true; - return Task.FromResult(0); - }); - }); + var server = new TestServer(builder); var req = new HttpRequestMessage(HttpMethod.Get, ""); req.Headers.Add("X-Forwarded-For", "11.111.111.11"); @@ -152,21 +163,23 @@ namespace Microsoft.AspNet.HttpOverrides { var assertsExecuted = false; - var server = TestServer.Create(app => - { - app.UseOverrideHeaders(options => + var builder = new WebApplicationBuilder() + .Configure(app => { - options.ForwardedOptions = ForwardedHeaders.None; + app.UseOverrideHeaders(options => + { + options.ForwardedOptions = ForwardedHeaders.None; + }); + app.Run(context => + { + Assert.Null(context.Connection.RemoteIpAddress); + Assert.Equal("localhost", context.Request.Host.ToString()); + Assert.Equal("http", context.Request.Scheme); + assertsExecuted = true; + return Task.FromResult(0); + }); }); - app.Run(context => - { - Assert.Null(context.Connection.RemoteIpAddress); - Assert.Equal("localhost", context.Request.Host.ToString()); - Assert.Equal("http", context.Request.Scheme); - assertsExecuted = true; - return Task.FromResult(0); - }); - }); + var server = new TestServer(builder); var req = new HttpRequestMessage(HttpMethod.Get, ""); req.Headers.Add("X-Forwarded-For", "11.111.111.11"); @@ -181,22 +194,24 @@ namespace Microsoft.AspNet.HttpOverrides { var assertsExecuted = false; - var server = TestServer.Create(app => - { - app.UseOverrideHeaders(options => + var builder = new WebApplicationBuilder() + .Configure(app => { - options.ForwardedOptions = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto; - }); - app.Run(context => - { - Assert.Equal("11.111.111.11", context.Connection.RemoteIpAddress.ToString()); - Assert.Equal("localhost", context.Request.Host.ToString()); - Assert.Equal("Protocol", context.Request.Scheme); - assertsExecuted = true; - return Task.FromResult(0); + app.UseOverrideHeaders(options => + { + options.ForwardedOptions = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto; + }); + app.Run(context => + { + Assert.Equal("11.111.111.11", context.Connection.RemoteIpAddress.ToString()); + Assert.Equal("localhost", context.Request.Host.ToString()); + Assert.Equal("Protocol", context.Request.Scheme); + assertsExecuted = true; + return Task.FromResult(0); + }); }); - }); + var server = new TestServer(builder); var req = new HttpRequestMessage(HttpMethod.Get, ""); req.Headers.Add("X-Forwarded-For", "11.111.111.11"); From d1a0edb87ea4f24403c9b7273db41a4bfcab6e96 Mon Sep 17 00:00:00 2001 From: John Luo Date: Thu, 7 Jan 2016 13:45:40 -0800 Subject: [PATCH 032/307] Updating to new options pattern --- samples/HttpOverridesSample/Startup.cs | 4 +-- .../ResponseBufferingMiddleware.cs | 1 - .../HttpMethodOverrideExtensions.cs | 15 +++++----- .../HttpMethodOverrideMiddleware.cs | 6 ++-- .../HttpMethodOverrideOptions.cs | 2 +- .../OverrideHeaderExtensions.cs | 28 +++++++++++++++---- .../OverrideHeaderMiddleware.cs | 6 ++-- .../OverrideHeaderOptions.cs | 4 ++- .../project.json | 3 +- .../OverrideHeaderMiddlewareTest.cs | 28 +++++++++---------- 10 files changed, 60 insertions(+), 37 deletions(-) diff --git a/samples/HttpOverridesSample/Startup.cs b/samples/HttpOverridesSample/Startup.cs index 4c71f32a93..ae17a73851 100644 --- a/samples/HttpOverridesSample/Startup.cs +++ b/samples/HttpOverridesSample/Startup.cs @@ -11,9 +11,9 @@ namespace HttpOverridesSample public void Configure(IApplicationBuilder app) { app.UseIISPlatformHandler(); - app.UseOverrideHeaders(options => + app.UseOverrideHeaders(new OverrideHeaderOptions { - options.ForwardedOptions = ForwardedHeaders.All; + ForwardedOptions = ForwardedHeaders.All }); app.UseHttpMethodOverride(); diff --git a/src/Microsoft.AspNet.Buffering/ResponseBufferingMiddleware.cs b/src/Microsoft.AspNet.Buffering/ResponseBufferingMiddleware.cs index e2af1cc4f6..21e56a0ee2 100644 --- a/src/Microsoft.AspNet.Buffering/ResponseBufferingMiddleware.cs +++ b/src/Microsoft.AspNet.Buffering/ResponseBufferingMiddleware.cs @@ -2,7 +2,6 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System.Threading.Tasks; -using Microsoft.AspNet.Builder; using Microsoft.AspNet.Http; using Microsoft.AspNet.Http.Features; diff --git a/src/Microsoft.AspNet.HttpOverrides/HttpMethodOverrideExtensions.cs b/src/Microsoft.AspNet.HttpOverrides/HttpMethodOverrideExtensions.cs index 66aa5953a5..be2502dde1 100644 --- a/src/Microsoft.AspNet.HttpOverrides/HttpMethodOverrideExtensions.cs +++ b/src/Microsoft.AspNet.HttpOverrides/HttpMethodOverrideExtensions.cs @@ -3,6 +3,7 @@ using System; using Microsoft.AspNet.HttpOverrides; +using Microsoft.Extensions.Options; namespace Microsoft.AspNet.Builder { @@ -19,7 +20,8 @@ namespace Microsoft.AspNet.Builder { throw new ArgumentNullException(nameof(builder)); } - return builder.Use(next => new HttpMethodOverrideMiddleware(next, new HttpMethodOverrideOptions()).Invoke); + + return builder.UseMiddleware(); } /// @@ -28,19 +30,18 @@ namespace Microsoft.AspNet.Builder /// /// Denotes the element that contains the name of the resulting method type. /// - public static IApplicationBuilder UseHttpMethodOverride(this IApplicationBuilder builder, Action configureOptions) + public static IApplicationBuilder UseHttpMethodOverride(this IApplicationBuilder builder, HttpMethodOverrideOptions options) { if (builder == null) { throw new ArgumentNullException(nameof(builder)); } - if (configureOptions == null) + if (options == null) { - throw new ArgumentNullException(nameof(configureOptions)); + throw new ArgumentNullException(nameof(options)); } - var options = new HttpMethodOverrideOptions(); - configureOptions(options); - return builder.Use(next => new HttpMethodOverrideMiddleware(next, options).Invoke); + + return builder.UseMiddleware(Options.Create(options)); } } } diff --git a/src/Microsoft.AspNet.HttpOverrides/HttpMethodOverrideMiddleware.cs b/src/Microsoft.AspNet.HttpOverrides/HttpMethodOverrideMiddleware.cs index 621f355af2..df65207d35 100644 --- a/src/Microsoft.AspNet.HttpOverrides/HttpMethodOverrideMiddleware.cs +++ b/src/Microsoft.AspNet.HttpOverrides/HttpMethodOverrideMiddleware.cs @@ -3,7 +3,9 @@ using System; using System.Threading.Tasks; +using Microsoft.AspNet.Builder; using Microsoft.AspNet.Http; +using Microsoft.Extensions.Options; namespace Microsoft.AspNet.HttpOverrides { @@ -13,7 +15,7 @@ namespace Microsoft.AspNet.HttpOverrides private readonly RequestDelegate _next; private readonly HttpMethodOverrideOptions _options; - public HttpMethodOverrideMiddleware(RequestDelegate next, HttpMethodOverrideOptions options) + public HttpMethodOverrideMiddleware(RequestDelegate next, IOptions options) { if (next == null) { @@ -24,7 +26,7 @@ namespace Microsoft.AspNet.HttpOverrides throw new ArgumentNullException(nameof(options)); } _next = next; - _options = options; + _options = options.Value; } public async Task Invoke(HttpContext context) diff --git a/src/Microsoft.AspNet.HttpOverrides/HttpMethodOverrideOptions.cs b/src/Microsoft.AspNet.HttpOverrides/HttpMethodOverrideOptions.cs index 033669acab..e6ade4a274 100644 --- a/src/Microsoft.AspNet.HttpOverrides/HttpMethodOverrideOptions.cs +++ b/src/Microsoft.AspNet.HttpOverrides/HttpMethodOverrideOptions.cs @@ -1,7 +1,7 @@ // 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. -namespace Microsoft.AspNet.HttpOverrides +namespace Microsoft.AspNet.Builder { public class HttpMethodOverrideOptions { diff --git a/src/Microsoft.AspNet.HttpOverrides/OverrideHeaderExtensions.cs b/src/Microsoft.AspNet.HttpOverrides/OverrideHeaderExtensions.cs index b02d7c5191..e22e4af34d 100644 --- a/src/Microsoft.AspNet.HttpOverrides/OverrideHeaderExtensions.cs +++ b/src/Microsoft.AspNet.HttpOverrides/OverrideHeaderExtensions.cs @@ -3,6 +3,7 @@ using System; using Microsoft.AspNet.HttpOverrides; +using Microsoft.Extensions.Options; namespace Microsoft.AspNet.Builder { @@ -14,19 +15,34 @@ namespace Microsoft.AspNet.Builder /// /// Enables the different override options. /// - public static IApplicationBuilder UseOverrideHeaders(this IApplicationBuilder builder, Action configureOptions) + public static IApplicationBuilder UseOverrideHeaders(this IApplicationBuilder builder) { if (builder == null) { throw new ArgumentNullException(nameof(builder)); } - if (configureOptions == null) + + return builder.UseMiddleware(); + } + + /// + /// Forwards proxied headers onto current request + /// + /// + /// Enables the different override options. + /// + public static IApplicationBuilder UseOverrideHeaders(this IApplicationBuilder builder, OverrideHeaderOptions options) + { + if (builder == null) { - throw new ArgumentNullException(nameof(configureOptions)); + throw new ArgumentNullException(nameof(builder)); } - var options = new OverrideHeaderOptions(); - configureOptions(options); - return builder.Use(next => new OverrideHeaderMiddleware(next, options).Invoke); + if (options == null) + { + throw new ArgumentNullException(nameof(options)); + } + + return builder.UseMiddleware(Options.Create(options)); } } } diff --git a/src/Microsoft.AspNet.HttpOverrides/OverrideHeaderMiddleware.cs b/src/Microsoft.AspNet.HttpOverrides/OverrideHeaderMiddleware.cs index f300f65d56..9eb8564c11 100644 --- a/src/Microsoft.AspNet.HttpOverrides/OverrideHeaderMiddleware.cs +++ b/src/Microsoft.AspNet.HttpOverrides/OverrideHeaderMiddleware.cs @@ -4,7 +4,9 @@ using System; using System.Net; using System.Threading.Tasks; +using Microsoft.AspNet.Builder; using Microsoft.AspNet.Http; +using Microsoft.Extensions.Options; namespace Microsoft.AspNet.HttpOverrides { @@ -19,7 +21,7 @@ namespace Microsoft.AspNet.HttpOverrides private readonly OverrideHeaderOptions _options; private readonly RequestDelegate _next; - public OverrideHeaderMiddleware(RequestDelegate next, OverrideHeaderOptions options) + public OverrideHeaderMiddleware(RequestDelegate next, IOptions options) { if (next == null) { @@ -30,7 +32,7 @@ namespace Microsoft.AspNet.HttpOverrides throw new ArgumentNullException(nameof(options)); } - _options = options; + _options = options.Value; _next = next; } diff --git a/src/Microsoft.AspNet.HttpOverrides/OverrideHeaderOptions.cs b/src/Microsoft.AspNet.HttpOverrides/OverrideHeaderOptions.cs index 8b4f0756f4..eb63f71b58 100644 --- a/src/Microsoft.AspNet.HttpOverrides/OverrideHeaderOptions.cs +++ b/src/Microsoft.AspNet.HttpOverrides/OverrideHeaderOptions.cs @@ -1,7 +1,9 @@ // 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. -namespace Microsoft.AspNet.HttpOverrides +using Microsoft.AspNet.HttpOverrides; + +namespace Microsoft.AspNet.Builder { public class OverrideHeaderOptions { diff --git a/src/Microsoft.AspNet.HttpOverrides/project.json b/src/Microsoft.AspNet.HttpOverrides/project.json index 93c184ad7a..01612e537c 100644 --- a/src/Microsoft.AspNet.HttpOverrides/project.json +++ b/src/Microsoft.AspNet.HttpOverrides/project.json @@ -10,7 +10,8 @@ "url": "git://github.com/aspnet/basicmiddleware" }, "dependencies": { - "Microsoft.AspNet.Http.Extensions": "1.0.0-*" + "Microsoft.AspNet.Http.Extensions": "1.0.0-*", + "Microsoft.Extensions.Options": "1.0.0-*" }, "frameworks": { "net451": { }, diff --git a/test/Microsoft.AspNet.HttpOverrides.Tests/OverrideHeaderMiddlewareTest.cs b/test/Microsoft.AspNet.HttpOverrides.Tests/OverrideHeaderMiddlewareTest.cs index b6ef29b458..7f148cbe48 100644 --- a/test/Microsoft.AspNet.HttpOverrides.Tests/OverrideHeaderMiddlewareTest.cs +++ b/test/Microsoft.AspNet.HttpOverrides.Tests/OverrideHeaderMiddlewareTest.cs @@ -20,9 +20,9 @@ namespace Microsoft.AspNet.HttpOverrides var builder = new WebApplicationBuilder() .Configure(app => { - app.UseOverrideHeaders(options => + app.UseOverrideHeaders(new OverrideHeaderOptions { - options.ForwardedOptions = ForwardedHeaders.XForwardedFor; + ForwardedOptions = ForwardedHeaders.XForwardedFor }); app.Run(context => { @@ -47,9 +47,9 @@ namespace Microsoft.AspNet.HttpOverrides var builder = new WebApplicationBuilder() .Configure(app => { - app.UseOverrideHeaders(options => + app.UseOverrideHeaders(new OverrideHeaderOptions { - options.ForwardedOptions = ForwardedHeaders.XForwardedFor; + ForwardedOptions = ForwardedHeaders.XForwardedFor }); app.Run(context => { @@ -74,9 +74,9 @@ namespace Microsoft.AspNet.HttpOverrides var builder = new WebApplicationBuilder() .Configure(app => { - app.UseOverrideHeaders(options => + app.UseOverrideHeaders(new OverrideHeaderOptions { - options.ForwardedOptions = ForwardedHeaders.XForwardedHost; + ForwardedOptions = ForwardedHeaders.XForwardedHost }); app.Run(context => { @@ -101,9 +101,9 @@ namespace Microsoft.AspNet.HttpOverrides var builder = new WebApplicationBuilder() .Configure(app => { - app.UseOverrideHeaders(options => + app.UseOverrideHeaders(new OverrideHeaderOptions { - options.ForwardedOptions = ForwardedHeaders.XForwardedProto; + ForwardedOptions = ForwardedHeaders.XForwardedProto }); app.Run(context => { @@ -135,9 +135,9 @@ namespace Microsoft.AspNet.HttpOverrides var builder = new WebApplicationBuilder() .Configure(app => { - app.UseOverrideHeaders(options => + app.UseOverrideHeaders(new OverrideHeaderOptions { - options.ForwardedOptions = ForwardedHeaders.All; + ForwardedOptions = ForwardedHeaders.All }); app.Run(context => { @@ -166,9 +166,9 @@ namespace Microsoft.AspNet.HttpOverrides var builder = new WebApplicationBuilder() .Configure(app => { - app.UseOverrideHeaders(options => + app.UseOverrideHeaders(new OverrideHeaderOptions { - options.ForwardedOptions = ForwardedHeaders.None; + ForwardedOptions = ForwardedHeaders.None }); app.Run(context => { @@ -197,9 +197,9 @@ namespace Microsoft.AspNet.HttpOverrides var builder = new WebApplicationBuilder() .Configure(app => { - app.UseOverrideHeaders(options => + app.UseOverrideHeaders(new OverrideHeaderOptions { - options.ForwardedOptions = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto; + ForwardedOptions = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto }); app.Run(context => { From e1eb560c8202a1e0ce5d770cd4224c7f4bba0c7e Mon Sep 17 00:00:00 2001 From: "T. Thiery" Date: Mon, 11 Jan 2016 22:26:59 +0100 Subject: [PATCH 033/307] Added Unit Tests for form field based HTTP Method Override --- .../HttpMethodOverrideMiddleware.cs | 2 +- .../HttpMethodOverrideMiddlewareTest.cs | 94 +++++++++++++++++++ 2 files changed, 95 insertions(+), 1 deletion(-) diff --git a/src/Microsoft.AspNet.HttpOverrides/HttpMethodOverrideMiddleware.cs b/src/Microsoft.AspNet.HttpOverrides/HttpMethodOverrideMiddleware.cs index df65207d35..804e44d5f7 100644 --- a/src/Microsoft.AspNet.HttpOverrides/HttpMethodOverrideMiddleware.cs +++ b/src/Microsoft.AspNet.HttpOverrides/HttpMethodOverrideMiddleware.cs @@ -31,7 +31,7 @@ namespace Microsoft.AspNet.HttpOverrides public async Task Invoke(HttpContext context) { - if (string.Equals(context.Request.Method,"POST", StringComparison.OrdinalIgnoreCase)) + if (string.Equals(context.Request.Method, "POST", StringComparison.OrdinalIgnoreCase)) { if (_options.FormFieldName != null) { diff --git a/test/Microsoft.AspNet.HttpOverrides.Tests/HttpMethodOverrideMiddlewareTest.cs b/test/Microsoft.AspNet.HttpOverrides.Tests/HttpMethodOverrideMiddlewareTest.cs index d077fac906..d739fc1043 100644 --- a/test/Microsoft.AspNet.HttpOverrides.Tests/HttpMethodOverrideMiddlewareTest.cs +++ b/test/Microsoft.AspNet.HttpOverrides.Tests/HttpMethodOverrideMiddlewareTest.cs @@ -1,6 +1,7 @@ // 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.Collections.Generic; using System.Net.Http; using System.Threading.Tasks; using Microsoft.AspNet.Builder; @@ -78,5 +79,98 @@ namespace Microsoft.AspNet.HttpOverrides await server.CreateClient().SendAsync(req); Assert.True(assertsExecuted); } + + + [Fact] + public async Task FormFieldAvailableChangesRequestMethod() + { + var assertsExecuted = false; + var builder = new WebApplicationBuilder() + .Configure(app => + { + app.UseHttpMethodOverride(new HttpMethodOverrideOptions() + { + FormFieldName = "_METHOD" + }); + app.Run(context => + { + Assert.Equal("DELETE", context.Request.Method); + assertsExecuted = true; + return Task.FromResult(0); + }); + }); + var server = new TestServer(builder); + + var req = new HttpRequestMessage(HttpMethod.Post, ""); + req.Content = new FormUrlEncodedContent(new Dictionary() + { + { "_METHOD", "DELETE" } + }); + + + await server.CreateClient().SendAsync(req); + Assert.True(assertsExecuted); + } + + [Fact] + public async Task FormFieldUnavailableDoesNotChangeRequestMethod() + { + var assertsExecuted = false; + var builder = new WebApplicationBuilder() + .Configure(app => + { + app.UseHttpMethodOverride(new HttpMethodOverrideOptions() + { + FormFieldName = "_METHOD" + }); + app.Run(context => + { + Assert.Equal("POST", context.Request.Method); + assertsExecuted = true; + return Task.FromResult(0); + }); + }); + var server = new TestServer(builder); + + var req = new HttpRequestMessage(HttpMethod.Post, ""); + req.Content = new FormUrlEncodedContent(new Dictionary() + { + }); + + + await server.CreateClient().SendAsync(req); + Assert.True(assertsExecuted); + } + + [Fact] + public async Task FormFieldEmptyDoesNotChangeRequestMethod() + { + var assertsExecuted = false; + var builder = new WebApplicationBuilder() + .Configure(app => + { + app.UseHttpMethodOverride(new HttpMethodOverrideOptions() + { + FormFieldName = "_METHOD" + }); + app.Run(context => + { + Assert.Equal("POST", context.Request.Method); + assertsExecuted = true; + return Task.FromResult(0); + }); + }); + var server = new TestServer(builder); + + var req = new HttpRequestMessage(HttpMethod.Post, ""); + req.Content = new FormUrlEncodedContent(new Dictionary() + { + { "_METHOD", "" } + }); + + + await server.CreateClient().SendAsync(req); + Assert.True(assertsExecuted); + } } } From 529a81dc6baab746ef7e324dd4e86e3ebb66082c Mon Sep 17 00:00:00 2001 From: Chris R Date: Tue, 12 Jan 2016 15:22:02 -0800 Subject: [PATCH 034/307] React to Hosting API changes. --- samples/HttpOverridesSample/Startup.cs | 1 + samples/ResponseBufferingSample/Startup.cs | 1 + samples/ResponseBufferingSample/project.json | 1 + 3 files changed, 3 insertions(+) diff --git a/samples/HttpOverridesSample/Startup.cs b/samples/HttpOverridesSample/Startup.cs index ae17a73851..2c1bbb9a0f 100644 --- a/samples/HttpOverridesSample/Startup.cs +++ b/samples/HttpOverridesSample/Startup.cs @@ -35,6 +35,7 @@ namespace HttpOverridesSample { var application = new WebApplicationBuilder() .UseConfiguration(WebApplicationConfiguration.GetDefault(args)) + .UseIISPlatformHandlerUrl() .UseStartup() .Build(); diff --git a/samples/ResponseBufferingSample/Startup.cs b/samples/ResponseBufferingSample/Startup.cs index 78f824dce4..985c08fe44 100644 --- a/samples/ResponseBufferingSample/Startup.cs +++ b/samples/ResponseBufferingSample/Startup.cs @@ -39,6 +39,7 @@ namespace ResponseBufferingSample { var application = new WebApplicationBuilder() .UseConfiguration(WebApplicationConfiguration.GetDefault(args)) + .UseIISPlatformHandlerUrl() .UseStartup() .Build(); diff --git a/samples/ResponseBufferingSample/project.json b/samples/ResponseBufferingSample/project.json index 08e998cddf..8e84112993 100644 --- a/samples/ResponseBufferingSample/project.json +++ b/samples/ResponseBufferingSample/project.json @@ -2,6 +2,7 @@ "version": "1.0.0-*", "dependencies": { "Microsoft.AspNet.Buffering": "1.0.0-*", + "Microsoft.AspNet.IISPlatformHandler": "1.0.0-*", "Microsoft.AspNet.Server.Kestrel": "1.0.0-*" }, "compilationOptions": { From 11d048faa7e59c9a8da93957f04dcda13a2be4da Mon Sep 17 00:00:00 2001 From: Victor Hurdugaci Date: Tue, 12 Jan 2016 10:08:23 -0800 Subject: [PATCH 035/307] Build with dotnet --- .gitattributes | 1 + .gitignore | 4 +- .travis.yml | 8 ++- appveyor.yml | 2 +- build.cmd | 68 +++++++++---------- build.sh | 47 +++++++------ .../project.json | 24 +++++-- .../project.json | 24 +++++-- 8 files changed, 106 insertions(+), 72 deletions(-) diff --git a/.gitattributes b/.gitattributes index bdaa5ba982..66abdf279e 100644 --- a/.gitattributes +++ b/.gitattributes @@ -48,3 +48,4 @@ *.fsproj text=auto *.dbproj text=auto *.sln text=auto eol=crlf +*.sh eol=lf \ No newline at end of file diff --git a/.gitignore b/.gitignore index 566f474fe8..4ddb21ac5f 100644 --- a/.gitignore +++ b/.gitignore @@ -25,4 +25,6 @@ project.lock.json *.ncrunchsolution *.*sdf *.ipch -.vs/ \ No newline at end of file +.vs/ +.build/ +.testPublish/ \ No newline at end of file diff --git a/.travis.yml b/.travis.yml index 2fc624899f..bf811dc26a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,9 +10,11 @@ addons: - libssl-dev - libunwind8 - zlib1g -env: - - KOREBUILD_DNU_RESTORE_CORECLR=true mono: - 4.0.5 +os: + - linux + - osx +osx_image: xcode7.1 script: - - ./build.sh --quiet verify + - ./build.sh verify \ No newline at end of file diff --git a/appveyor.yml b/appveyor.yml index 636a7618d3..3fab83e134 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,7 +1,7 @@ init: - git config --global core.autocrlf true build_script: - - build.cmd --quiet verify + - build.cmd verify clone_depth: 1 test: off deploy: off \ No newline at end of file diff --git a/build.cmd b/build.cmd index 553e3929a0..ebb619e737 100644 --- a/build.cmd +++ b/build.cmd @@ -1,40 +1,40 @@ -@echo off -cd %~dp0 - +@ECHO off SETLOCAL + +SET REPO_FOLDER=%~dp0 +CD %REPO_FOLDER% + +SET BUILD_FOLDER=.build +SET KOREBUILD_FOLDER=%BUILD_FOLDER%\KoreBuild-dotnet +SET KOREBUILD_VERSION= + +SET NUGET_PATH=%BUILD_FOLDER%\NuGet.exe SET NUGET_VERSION=latest SET CACHED_NUGET=%LocalAppData%\NuGet\nuget.%NUGET_VERSION%.exe -SET BUILDCMD_KOREBUILD_VERSION= -SET BUILDCMD_DNX_VERSION= -IF EXIST %CACHED_NUGET% goto copynuget -echo Downloading latest version of NuGet.exe... -IF NOT EXIST %LocalAppData%\NuGet md %LocalAppData%\NuGet -@powershell -NoProfile -ExecutionPolicy unrestricted -Command "$ProgressPreference = 'SilentlyContinue'; Invoke-WebRequest 'https://dist.nuget.org/win-x86-commandline/%NUGET_VERSION%/nuget.exe' -OutFile '%CACHED_NUGET%'" - -:copynuget -IF EXIST .nuget\nuget.exe goto restore -md .nuget -copy %CACHED_NUGET% .nuget\nuget.exe > nul - -:restore -IF EXIST packages\Sake goto getdnx -IF "%BUILDCMD_KOREBUILD_VERSION%"=="" ( - .nuget\nuget.exe install KoreBuild -ExcludeVersion -o packages -nocache -pre -) ELSE ( - .nuget\nuget.exe install KoreBuild -version %BUILDCMD_KOREBUILD_VERSION% -ExcludeVersion -o packages -nocache -pre -) -.nuget\NuGet.exe install Sake -ExcludeVersion -Source https://www.nuget.org/api/v2/ -Out packages - -:getdnx -IF "%BUILDCMD_DNX_VERSION%"=="" ( - SET BUILDCMD_DNX_VERSION=latest -) -IF "%SKIP_DNX_INSTALL%"=="" ( - CALL packages\KoreBuild\build\dnvm install %BUILDCMD_DNX_VERSION% -runtime CoreCLR -arch x86 -alias default - CALL packages\KoreBuild\build\dnvm install default -runtime CLR -arch x86 -alias default -) ELSE ( - CALL packages\KoreBuild\build\dnvm use default -runtime CLR -arch x86 +IF NOT EXIST %BUILD_FOLDER% ( + md %BUILD_FOLDER% ) -packages\Sake\tools\Sake.exe -I packages\KoreBuild\build -f makefile.shade %* +IF NOT EXIST %NUGET_PATH% ( + IF NOT EXIST %CACHED_NUGET% ( + echo Downloading latest version of NuGet.exe... + IF NOT EXIST %LocalAppData%\NuGet ( + md %LocalAppData%\NuGet + ) + @powershell -NoProfile -ExecutionPolicy unrestricted -Command "$ProgressPreference = 'SilentlyContinue'; Invoke-WebRequest 'https://dist.nuget.org/win-x86-commandline/%NUGET_VERSION%/nuget.exe' -OutFile '%CACHED_NUGET%'" + ) + + copy %CACHED_NUGET% %NUGET_PATH% > nul +) + +IF NOT EXIST %KOREBUILD_FOLDER% ( + SET KOREBUILD_DOWNLOAD_ARGS= + IF NOT "%KOREBUILD_VERSION%"=="" ( + SET KOREBUILD_DOWNLOAD_ARGS=-version %KOREBUILD_VERSION% + ) + + %BUILD_FOLDER%\nuget.exe install KoreBuild-dotnet -ExcludeVersion -o %BUILD_FOLDER% -nocache -pre %KOREBUILD_DOWNLOAD_ARGS% +) + +"%KOREBUILD_FOLDER%\build\KoreBuild.cmd" %* diff --git a/build.sh b/build.sh index da4e3fcd1c..7b5e25e3a8 100755 --- a/build.sh +++ b/build.sh @@ -1,5 +1,18 @@ #!/usr/bin/env bash +SOURCE="${BASH_SOURCE[0]}" +while [ -h "$SOURCE" ]; do # resolve $SOURCE until the file is no longer a symlink + DIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )" + SOURCE="$(readlink "$SOURCE")" + [[ $SOURCE != /* ]] && SOURCE="$DIR/$SOURCE" # if $SOURCE was a relative symlink, we need to resolve it relative to the path where the symlink file was located +done +repoFolder="$( cd -P "$( dirname "$SOURCE" )" && pwd )" + +buildFolder=.build +koreBuildFolder=$buildFolder/KoreBuild-dotnet + +nugetPath=$buildFolder/nuget.exe + if test `uname` = Darwin; then cachedir=~/Library/Caches/KBuild else @@ -11,33 +24,25 @@ else fi mkdir -p $cachedir nugetVersion=latest -cachePath=$cachedir/nuget.$nugetVersion.exe +cacheNuget=$cachedir/nuget.$nugetVersion.exe -url=https://dist.nuget.org/win-x86-commandline/$nugetVersion/nuget.exe +nugetUrl=https://dist.nuget.org/win-x86-commandline/$nugetVersion/nuget.exe -if test ! -f $cachePath; then - wget -O $cachePath $url 2>/dev/null || curl -o $cachePath --location $url /dev/null +if test ! -d $buildFolder; then + mkdir $buildFolder fi -if test ! -e .nuget; then - mkdir .nuget - cp $cachePath .nuget/nuget.exe +if test ! -f $nugetPath; then + if test ! -f $cacheNuget; then + wget -O $cacheNuget $nugetUrl 2>/dev/null || curl -o $cacheNuget --location $nugetUrl /dev/null + fi + + cp $cacheNuget $nugetPath fi -if test ! -d packages/Sake; then - mono .nuget/nuget.exe install KoreBuild -ExcludeVersion -o packages -nocache -pre - mono .nuget/nuget.exe install Sake -ExcludeVersion -Source https://www.nuget.org/api/v2/ -Out packages +if test ! -d $koreBuildFolder; then + mono $nugetPath install KoreBuild-dotnet -ExcludeVersion -o $buildFolder -nocache -pre fi -if ! type dnvm > /dev/null 2>&1; then - source packages/KoreBuild/build/dnvm.sh -fi +source $koreBuildFolder/build/KoreBuild.sh -if ! type dnx > /dev/null 2>&1 || [ -z "$SKIP_DNX_INSTALL" ]; then - dnvm install latest -runtime coreclr -alias default - dnvm install default -runtime mono -alias default -else - dnvm use default -runtime mono -fi - -mono packages/Sake/tools/Sake.exe -I packages/KoreBuild/build -f makefile.shade "$@" diff --git a/test/Microsoft.AspNet.Buffering.Tests/project.json b/test/Microsoft.AspNet.Buffering.Tests/project.json index 3b87e6bb8a..560600e505 100644 --- a/test/Microsoft.AspNet.Buffering.Tests/project.json +++ b/test/Microsoft.AspNet.Buffering.Tests/project.json @@ -6,14 +6,26 @@ "dependencies": { "Microsoft.AspNet.Buffering": "1.0.0-*", "Microsoft.AspNet.TestHost": "1.0.0-*", - "xunit.runner.aspnet": "2.0.0-aspnet-*" + "xunit": "2.1.0" }, + "frameworks": { + "dnx451": { + "frameworkAssemblies": { + "System.Runtime": "", + "System.Threading.Tasks": "" + }, + "dependencies": { + "xunit.runner.console": "2.1.0" + } + }, + "dnxcore50": { + "dependencies": { + "xunit.runner.aspnet": "2.0.0-aspnet-*" + } + } + }, + "testRunner": "xunit", "commands": { "test": "xunit.runner.aspnet" - }, - - "frameworks": { - "dnx451": { }, - "dnxcore50": {} } } diff --git a/test/Microsoft.AspNet.HttpOverrides.Tests/project.json b/test/Microsoft.AspNet.HttpOverrides.Tests/project.json index 6aa7d8aac9..8502eb3c9b 100644 --- a/test/Microsoft.AspNet.HttpOverrides.Tests/project.json +++ b/test/Microsoft.AspNet.HttpOverrides.Tests/project.json @@ -7,14 +7,26 @@ "Microsoft.AspNet.HttpOverrides": "1.0.0-*", "Microsoft.AspNet.TestHost": "1.0.0-*", "Microsoft.Extensions.Logging.Testing": "1.0.0-*", - "xunit.runner.aspnet": "2.0.0-aspnet-*" + "xunit": "2.1.0" }, + "frameworks": { + "dnx451": { + "frameworkAssemblies": { + "System.Runtime": "", + "System.Threading.Tasks": "" + }, + "dependencies": { + "xunit.runner.console": "2.1.0" + } + }, + "dnxcore50": { + "dependencies": { + "xunit.runner.aspnet": "2.0.0-aspnet-*" + } + } + }, + "testRunner": "xunit", "commands": { "test": "xunit.runner.aspnet" - }, - - "frameworks": { - "dnx451": { }, - "dnxcore50": { } } } From a57f3001e8078a1201714660bea5c20b3cde9bba Mon Sep 17 00:00:00 2001 From: Nate McMaster Date: Thu, 14 Jan 2016 16:41:15 -0800 Subject: [PATCH 036/307] Updating build script --- build.sh | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/build.sh b/build.sh index 7b5e25e3a8..263fb667a8 100755 --- a/build.sh +++ b/build.sh @@ -1,13 +1,5 @@ #!/usr/bin/env bash -SOURCE="${BASH_SOURCE[0]}" -while [ -h "$SOURCE" ]; do # resolve $SOURCE until the file is no longer a symlink - DIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )" - SOURCE="$(readlink "$SOURCE")" - [[ $SOURCE != /* ]] && SOURCE="$DIR/$SOURCE" # if $SOURCE was a relative symlink, we need to resolve it relative to the path where the symlink file was located -done -repoFolder="$( cd -P "$( dirname "$SOURCE" )" && pwd )" - buildFolder=.build koreBuildFolder=$buildFolder/KoreBuild-dotnet @@ -42,7 +34,12 @@ fi if test ! -d $koreBuildFolder; then mono $nugetPath install KoreBuild-dotnet -ExcludeVersion -o $buildFolder -nocache -pre + chmod +x $koreBuildFolder/build/KoreBuild.sh fi -source $koreBuildFolder/build/KoreBuild.sh +makeFile=makefile.shade +if [ ! -e $makeFile ]; then + makeFile=$koreBuildFolder/build/makefile.shade +fi +./$koreBuildFolder/build/KoreBuild.sh -n $nugetPath -m $makeFile "$@" From 6a3ae53108f8cd216b3580f8e6d1a661b4b67528 Mon Sep 17 00:00:00 2001 From: John Luo Date: Sun, 17 Jan 2016 17:05:04 -0800 Subject: [PATCH 037/307] Reacting to hosting rename --- samples/HttpOverridesSample/Startup.cs | 6 +++--- samples/ResponseBufferingSample/Startup.cs | 6 +++--- .../ResponseBufferingMiddlewareTests.cs | 16 ++++++++-------- .../HttpMethodOverrideMiddlewareTest.cs | 12 ++++++------ .../OverrideHeaderMiddlewareTest.cs | 14 +++++++------- 5 files changed, 27 insertions(+), 27 deletions(-) diff --git a/samples/HttpOverridesSample/Startup.cs b/samples/HttpOverridesSample/Startup.cs index 2c1bbb9a0f..606fd20163 100644 --- a/samples/HttpOverridesSample/Startup.cs +++ b/samples/HttpOverridesSample/Startup.cs @@ -33,13 +33,13 @@ namespace HttpOverridesSample // Entry point for the application. public static void Main(string[] args) { - var application = new WebApplicationBuilder() - .UseConfiguration(WebApplicationConfiguration.GetDefault(args)) + var host = new WebHostBuilder() + .UseDefaultConfiguration(args) .UseIISPlatformHandlerUrl() .UseStartup() .Build(); - application.Run(); + host.Run(); } } } diff --git a/samples/ResponseBufferingSample/Startup.cs b/samples/ResponseBufferingSample/Startup.cs index 985c08fe44..035c499bc6 100644 --- a/samples/ResponseBufferingSample/Startup.cs +++ b/samples/ResponseBufferingSample/Startup.cs @@ -37,13 +37,13 @@ namespace ResponseBufferingSample // Entry point for the application. public static void Main(string[] args) { - var application = new WebApplicationBuilder() - .UseConfiguration(WebApplicationConfiguration.GetDefault(args)) + var host = new WebHostBuilder() + .UseDefaultConfiguration(args) .UseIISPlatformHandlerUrl() .UseStartup() .Build(); - application.Run(); + host.Run(); } } } diff --git a/test/Microsoft.AspNet.Buffering.Tests/ResponseBufferingMiddlewareTests.cs b/test/Microsoft.AspNet.Buffering.Tests/ResponseBufferingMiddlewareTests.cs index fc07df25ec..e2cc8da5e5 100644 --- a/test/Microsoft.AspNet.Buffering.Tests/ResponseBufferingMiddlewareTests.cs +++ b/test/Microsoft.AspNet.Buffering.Tests/ResponseBufferingMiddlewareTests.cs @@ -20,7 +20,7 @@ namespace Microsoft.AspNet.Buffering.Tests [Fact] public async Task BufferResponse_SetsContentLength() { - var builder = new WebApplicationBuilder() + var builder = new WebHostBuilder() .Configure(app => { app.UseResponseBuffering(); @@ -48,7 +48,7 @@ namespace Microsoft.AspNet.Buffering.Tests [Fact] public async Task BufferResponseWithManualContentLength_NotReplaced() { - var builder = new WebApplicationBuilder() + var builder = new WebHostBuilder() .Configure(app => { app.UseResponseBuffering(); @@ -76,7 +76,7 @@ namespace Microsoft.AspNet.Buffering.Tests [Fact] public async Task Seek_AllowsResttingBuffer() { - var builder = new WebApplicationBuilder() + var builder = new WebHostBuilder() .Configure(app => { app.UseResponseBuffering(); @@ -122,7 +122,7 @@ namespace Microsoft.AspNet.Buffering.Tests [Fact] public async Task SetPosition_AllowsResttingBuffer() { - var builder = new WebApplicationBuilder() + var builder = new WebHostBuilder() .Configure(app => { app.UseResponseBuffering(); @@ -166,7 +166,7 @@ namespace Microsoft.AspNet.Buffering.Tests [Fact] public async Task SetLength_AllowsResttingBuffer() { - var builder = new WebApplicationBuilder() + var builder = new WebHostBuilder() .Configure(app => { app.UseResponseBuffering(); @@ -210,7 +210,7 @@ namespace Microsoft.AspNet.Buffering.Tests [Fact] public async Task DisableBufferingViaFeature() { - var builder = new WebApplicationBuilder() + var builder = new WebHostBuilder() .Configure(app => { app.UseResponseBuffering(); @@ -244,7 +244,7 @@ namespace Microsoft.AspNet.Buffering.Tests [Fact] public async Task DisableBufferingViaFeatureAfterFirstWrite_Flushes() { - var builder = new WebApplicationBuilder() + var builder = new WebHostBuilder() .Configure(app => { app.UseResponseBuffering(); @@ -283,7 +283,7 @@ namespace Microsoft.AspNet.Buffering.Tests [Fact] public async Task FlushDisablesBuffering() { - var builder = new WebApplicationBuilder() + var builder = new WebHostBuilder() .Configure(app => { app.UseResponseBuffering(); diff --git a/test/Microsoft.AspNet.HttpOverrides.Tests/HttpMethodOverrideMiddlewareTest.cs b/test/Microsoft.AspNet.HttpOverrides.Tests/HttpMethodOverrideMiddlewareTest.cs index d739fc1043..5c4108ddfc 100644 --- a/test/Microsoft.AspNet.HttpOverrides.Tests/HttpMethodOverrideMiddlewareTest.cs +++ b/test/Microsoft.AspNet.HttpOverrides.Tests/HttpMethodOverrideMiddlewareTest.cs @@ -17,7 +17,7 @@ namespace Microsoft.AspNet.HttpOverrides public async Task XHttpMethodOverrideHeaderAvaiableChangesRequestMethod() { var assertsExecuted = false; - var builder = new WebApplicationBuilder() + var builder = new WebHostBuilder() .Configure(app => { app.UseHttpMethodOverride(); @@ -40,7 +40,7 @@ namespace Microsoft.AspNet.HttpOverrides public async Task XHttpMethodOverrideHeaderUnavaiableDoesntChangeRequestMethod() { var assertsExecuted = false; - var builder = new WebApplicationBuilder() + var builder = new WebHostBuilder() .Configure(app => { app.UseHttpMethodOverride(); @@ -62,7 +62,7 @@ namespace Microsoft.AspNet.HttpOverrides public async Task XHttpMethodOverrideFromGetRequestDoesntChangeMethodType() { var assertsExecuted = false; - var builder = new WebApplicationBuilder() + var builder = new WebHostBuilder() .Configure(app => { app.UseHttpMethodOverride(); @@ -85,7 +85,7 @@ namespace Microsoft.AspNet.HttpOverrides public async Task FormFieldAvailableChangesRequestMethod() { var assertsExecuted = false; - var builder = new WebApplicationBuilder() + var builder = new WebHostBuilder() .Configure(app => { app.UseHttpMethodOverride(new HttpMethodOverrideOptions() @@ -116,7 +116,7 @@ namespace Microsoft.AspNet.HttpOverrides public async Task FormFieldUnavailableDoesNotChangeRequestMethod() { var assertsExecuted = false; - var builder = new WebApplicationBuilder() + var builder = new WebHostBuilder() .Configure(app => { app.UseHttpMethodOverride(new HttpMethodOverrideOptions() @@ -146,7 +146,7 @@ namespace Microsoft.AspNet.HttpOverrides public async Task FormFieldEmptyDoesNotChangeRequestMethod() { var assertsExecuted = false; - var builder = new WebApplicationBuilder() + var builder = new WebHostBuilder() .Configure(app => { app.UseHttpMethodOverride(new HttpMethodOverrideOptions() diff --git a/test/Microsoft.AspNet.HttpOverrides.Tests/OverrideHeaderMiddlewareTest.cs b/test/Microsoft.AspNet.HttpOverrides.Tests/OverrideHeaderMiddlewareTest.cs index 7f148cbe48..1dd86d3bcd 100644 --- a/test/Microsoft.AspNet.HttpOverrides.Tests/OverrideHeaderMiddlewareTest.cs +++ b/test/Microsoft.AspNet.HttpOverrides.Tests/OverrideHeaderMiddlewareTest.cs @@ -17,7 +17,7 @@ namespace Microsoft.AspNet.HttpOverrides { var assertsExecuted = false; - var builder = new WebApplicationBuilder() + var builder = new WebHostBuilder() .Configure(app => { app.UseOverrideHeaders(new OverrideHeaderOptions @@ -44,7 +44,7 @@ namespace Microsoft.AspNet.HttpOverrides { var assertsExecuted = false; - var builder = new WebApplicationBuilder() + var builder = new WebHostBuilder() .Configure(app => { app.UseOverrideHeaders(new OverrideHeaderOptions @@ -71,7 +71,7 @@ namespace Microsoft.AspNet.HttpOverrides { var assertsExecuted = false; - var builder = new WebApplicationBuilder() + var builder = new WebHostBuilder() .Configure(app => { app.UseOverrideHeaders(new OverrideHeaderOptions @@ -98,7 +98,7 @@ namespace Microsoft.AspNet.HttpOverrides { var assertsExecuted = false; - var builder = new WebApplicationBuilder() + var builder = new WebHostBuilder() .Configure(app => { app.UseOverrideHeaders(new OverrideHeaderOptions @@ -132,7 +132,7 @@ namespace Microsoft.AspNet.HttpOverrides { var assertsExecuted = false; - var builder = new WebApplicationBuilder() + var builder = new WebHostBuilder() .Configure(app => { app.UseOverrideHeaders(new OverrideHeaderOptions @@ -163,7 +163,7 @@ namespace Microsoft.AspNet.HttpOverrides { var assertsExecuted = false; - var builder = new WebApplicationBuilder() + var builder = new WebHostBuilder() .Configure(app => { app.UseOverrideHeaders(new OverrideHeaderOptions @@ -194,7 +194,7 @@ namespace Microsoft.AspNet.HttpOverrides { var assertsExecuted = false; - var builder = new WebApplicationBuilder() + var builder = new WebHostBuilder() .Configure(app => { app.UseOverrideHeaders(new OverrideHeaderOptions From 4bbd498047f3ed8ae692a31f31a9e68be23dd02b Mon Sep 17 00:00:00 2001 From: "N. Taylor Mullen" Date: Fri, 22 Jan 2016 12:24:58 -0800 Subject: [PATCH 038/307] Rename AspNet 5 folders and files. See https://github.com/aspnet/Announcements/issues/144 for more information. --- .../BufferingWriteStream.cs | 0 .../HttpBufferingFeature.cs | 0 .../Microsoft.AspNetCore.Buffering.xproj} | 0 .../Properties/AssemblyInfo.cs | 0 .../ResponseBufferingMiddleware.cs | 0 .../ResponseBufferingMiddlewareExtensions.cs | 0 .../SendFileFeatureWrapper.cs | 0 .../project.json | 0 .../ForwardedHeaders.cs | 0 .../HttpMethodOverrideExtensions.cs | 0 .../HttpMethodOverrideMiddleware.cs | 0 .../HttpMethodOverrideOptions.cs | 0 .../IPEndPointParser.cs | 0 .../Microsoft.AspNetCore.HttpOverrides.xproj} | 0 .../OverrideHeaderExtensions.cs | 0 .../OverrideHeaderMiddleware.cs | 0 .../OverrideHeaderOptions.cs | 0 .../Properties/AssemblyInfo.cs | 0 .../project.json | 0 .../Microsoft.AspNetCore.Buffering.Tests.xproj} | 0 .../ResponseBufferingMiddlewareTests.cs | 0 .../project.json | 0 .../HttpMethodOverrideMiddlewareTest.cs | 0 .../IPEndPointParserTest.cs | 0 .../Microsoft.AspNetCore.HttpOverrides.Tests.xproj} | 0 .../OverrideHeaderMiddlewareTest.cs | 0 .../project.json | 0 27 files changed, 0 insertions(+), 0 deletions(-) rename src/{Microsoft.AspNet.Buffering => Microsoft.AspNetCore.Buffering}/BufferingWriteStream.cs (100%) rename src/{Microsoft.AspNet.Buffering => Microsoft.AspNetCore.Buffering}/HttpBufferingFeature.cs (100%) rename src/{Microsoft.AspNet.Buffering/Microsoft.AspNet.Buffering.xproj => Microsoft.AspNetCore.Buffering/Microsoft.AspNetCore.Buffering.xproj} (100%) rename src/{Microsoft.AspNet.Buffering => Microsoft.AspNetCore.Buffering}/Properties/AssemblyInfo.cs (100%) rename src/{Microsoft.AspNet.Buffering => Microsoft.AspNetCore.Buffering}/ResponseBufferingMiddleware.cs (100%) rename src/{Microsoft.AspNet.Buffering => Microsoft.AspNetCore.Buffering}/ResponseBufferingMiddlewareExtensions.cs (100%) rename src/{Microsoft.AspNet.Buffering => Microsoft.AspNetCore.Buffering}/SendFileFeatureWrapper.cs (100%) rename src/{Microsoft.AspNet.Buffering => Microsoft.AspNetCore.Buffering}/project.json (100%) rename src/{Microsoft.AspNet.HttpOverrides => Microsoft.AspNetCore.HttpOverrides}/ForwardedHeaders.cs (100%) rename src/{Microsoft.AspNet.HttpOverrides => Microsoft.AspNetCore.HttpOverrides}/HttpMethodOverrideExtensions.cs (100%) rename src/{Microsoft.AspNet.HttpOverrides => Microsoft.AspNetCore.HttpOverrides}/HttpMethodOverrideMiddleware.cs (100%) rename src/{Microsoft.AspNet.HttpOverrides => Microsoft.AspNetCore.HttpOverrides}/HttpMethodOverrideOptions.cs (100%) rename src/{Microsoft.AspNet.HttpOverrides => Microsoft.AspNetCore.HttpOverrides}/IPEndPointParser.cs (100%) rename src/{Microsoft.AspNet.HttpOverrides/Microsoft.AspNet.HttpOverrides.xproj => Microsoft.AspNetCore.HttpOverrides/Microsoft.AspNetCore.HttpOverrides.xproj} (100%) rename src/{Microsoft.AspNet.HttpOverrides => Microsoft.AspNetCore.HttpOverrides}/OverrideHeaderExtensions.cs (100%) rename src/{Microsoft.AspNet.HttpOverrides => Microsoft.AspNetCore.HttpOverrides}/OverrideHeaderMiddleware.cs (100%) rename src/{Microsoft.AspNet.HttpOverrides => Microsoft.AspNetCore.HttpOverrides}/OverrideHeaderOptions.cs (100%) rename src/{Microsoft.AspNet.HttpOverrides => Microsoft.AspNetCore.HttpOverrides}/Properties/AssemblyInfo.cs (100%) rename src/{Microsoft.AspNet.HttpOverrides => Microsoft.AspNetCore.HttpOverrides}/project.json (100%) rename test/{Microsoft.AspNet.Buffering.Tests/Microsoft.AspNet.Buffering.Tests.xproj => Microsoft.AspNetCore.Buffering.Tests/Microsoft.AspNetCore.Buffering.Tests.xproj} (100%) rename test/{Microsoft.AspNet.Buffering.Tests => Microsoft.AspNetCore.Buffering.Tests}/ResponseBufferingMiddlewareTests.cs (100%) rename test/{Microsoft.AspNet.Buffering.Tests => Microsoft.AspNetCore.Buffering.Tests}/project.json (100%) rename test/{Microsoft.AspNet.HttpOverrides.Tests => Microsoft.AspNetCore.HttpOverrides.Tests}/HttpMethodOverrideMiddlewareTest.cs (100%) rename test/{Microsoft.AspNet.HttpOverrides.Tests => Microsoft.AspNetCore.HttpOverrides.Tests}/IPEndPointParserTest.cs (100%) rename test/{Microsoft.AspNet.HttpOverrides.Tests/Microsoft.AspNet.HttpOverrides.Tests.xproj => Microsoft.AspNetCore.HttpOverrides.Tests/Microsoft.AspNetCore.HttpOverrides.Tests.xproj} (100%) rename test/{Microsoft.AspNet.HttpOverrides.Tests => Microsoft.AspNetCore.HttpOverrides.Tests}/OverrideHeaderMiddlewareTest.cs (100%) rename test/{Microsoft.AspNet.HttpOverrides.Tests => Microsoft.AspNetCore.HttpOverrides.Tests}/project.json (100%) diff --git a/src/Microsoft.AspNet.Buffering/BufferingWriteStream.cs b/src/Microsoft.AspNetCore.Buffering/BufferingWriteStream.cs similarity index 100% rename from src/Microsoft.AspNet.Buffering/BufferingWriteStream.cs rename to src/Microsoft.AspNetCore.Buffering/BufferingWriteStream.cs diff --git a/src/Microsoft.AspNet.Buffering/HttpBufferingFeature.cs b/src/Microsoft.AspNetCore.Buffering/HttpBufferingFeature.cs similarity index 100% rename from src/Microsoft.AspNet.Buffering/HttpBufferingFeature.cs rename to src/Microsoft.AspNetCore.Buffering/HttpBufferingFeature.cs diff --git a/src/Microsoft.AspNet.Buffering/Microsoft.AspNet.Buffering.xproj b/src/Microsoft.AspNetCore.Buffering/Microsoft.AspNetCore.Buffering.xproj similarity index 100% rename from src/Microsoft.AspNet.Buffering/Microsoft.AspNet.Buffering.xproj rename to src/Microsoft.AspNetCore.Buffering/Microsoft.AspNetCore.Buffering.xproj diff --git a/src/Microsoft.AspNet.Buffering/Properties/AssemblyInfo.cs b/src/Microsoft.AspNetCore.Buffering/Properties/AssemblyInfo.cs similarity index 100% rename from src/Microsoft.AspNet.Buffering/Properties/AssemblyInfo.cs rename to src/Microsoft.AspNetCore.Buffering/Properties/AssemblyInfo.cs diff --git a/src/Microsoft.AspNet.Buffering/ResponseBufferingMiddleware.cs b/src/Microsoft.AspNetCore.Buffering/ResponseBufferingMiddleware.cs similarity index 100% rename from src/Microsoft.AspNet.Buffering/ResponseBufferingMiddleware.cs rename to src/Microsoft.AspNetCore.Buffering/ResponseBufferingMiddleware.cs diff --git a/src/Microsoft.AspNet.Buffering/ResponseBufferingMiddlewareExtensions.cs b/src/Microsoft.AspNetCore.Buffering/ResponseBufferingMiddlewareExtensions.cs similarity index 100% rename from src/Microsoft.AspNet.Buffering/ResponseBufferingMiddlewareExtensions.cs rename to src/Microsoft.AspNetCore.Buffering/ResponseBufferingMiddlewareExtensions.cs diff --git a/src/Microsoft.AspNet.Buffering/SendFileFeatureWrapper.cs b/src/Microsoft.AspNetCore.Buffering/SendFileFeatureWrapper.cs similarity index 100% rename from src/Microsoft.AspNet.Buffering/SendFileFeatureWrapper.cs rename to src/Microsoft.AspNetCore.Buffering/SendFileFeatureWrapper.cs diff --git a/src/Microsoft.AspNet.Buffering/project.json b/src/Microsoft.AspNetCore.Buffering/project.json similarity index 100% rename from src/Microsoft.AspNet.Buffering/project.json rename to src/Microsoft.AspNetCore.Buffering/project.json diff --git a/src/Microsoft.AspNet.HttpOverrides/ForwardedHeaders.cs b/src/Microsoft.AspNetCore.HttpOverrides/ForwardedHeaders.cs similarity index 100% rename from src/Microsoft.AspNet.HttpOverrides/ForwardedHeaders.cs rename to src/Microsoft.AspNetCore.HttpOverrides/ForwardedHeaders.cs diff --git a/src/Microsoft.AspNet.HttpOverrides/HttpMethodOverrideExtensions.cs b/src/Microsoft.AspNetCore.HttpOverrides/HttpMethodOverrideExtensions.cs similarity index 100% rename from src/Microsoft.AspNet.HttpOverrides/HttpMethodOverrideExtensions.cs rename to src/Microsoft.AspNetCore.HttpOverrides/HttpMethodOverrideExtensions.cs diff --git a/src/Microsoft.AspNet.HttpOverrides/HttpMethodOverrideMiddleware.cs b/src/Microsoft.AspNetCore.HttpOverrides/HttpMethodOverrideMiddleware.cs similarity index 100% rename from src/Microsoft.AspNet.HttpOverrides/HttpMethodOverrideMiddleware.cs rename to src/Microsoft.AspNetCore.HttpOverrides/HttpMethodOverrideMiddleware.cs diff --git a/src/Microsoft.AspNet.HttpOverrides/HttpMethodOverrideOptions.cs b/src/Microsoft.AspNetCore.HttpOverrides/HttpMethodOverrideOptions.cs similarity index 100% rename from src/Microsoft.AspNet.HttpOverrides/HttpMethodOverrideOptions.cs rename to src/Microsoft.AspNetCore.HttpOverrides/HttpMethodOverrideOptions.cs diff --git a/src/Microsoft.AspNet.HttpOverrides/IPEndPointParser.cs b/src/Microsoft.AspNetCore.HttpOverrides/IPEndPointParser.cs similarity index 100% rename from src/Microsoft.AspNet.HttpOverrides/IPEndPointParser.cs rename to src/Microsoft.AspNetCore.HttpOverrides/IPEndPointParser.cs diff --git a/src/Microsoft.AspNet.HttpOverrides/Microsoft.AspNet.HttpOverrides.xproj b/src/Microsoft.AspNetCore.HttpOverrides/Microsoft.AspNetCore.HttpOverrides.xproj similarity index 100% rename from src/Microsoft.AspNet.HttpOverrides/Microsoft.AspNet.HttpOverrides.xproj rename to src/Microsoft.AspNetCore.HttpOverrides/Microsoft.AspNetCore.HttpOverrides.xproj diff --git a/src/Microsoft.AspNet.HttpOverrides/OverrideHeaderExtensions.cs b/src/Microsoft.AspNetCore.HttpOverrides/OverrideHeaderExtensions.cs similarity index 100% rename from src/Microsoft.AspNet.HttpOverrides/OverrideHeaderExtensions.cs rename to src/Microsoft.AspNetCore.HttpOverrides/OverrideHeaderExtensions.cs diff --git a/src/Microsoft.AspNet.HttpOverrides/OverrideHeaderMiddleware.cs b/src/Microsoft.AspNetCore.HttpOverrides/OverrideHeaderMiddleware.cs similarity index 100% rename from src/Microsoft.AspNet.HttpOverrides/OverrideHeaderMiddleware.cs rename to src/Microsoft.AspNetCore.HttpOverrides/OverrideHeaderMiddleware.cs diff --git a/src/Microsoft.AspNet.HttpOverrides/OverrideHeaderOptions.cs b/src/Microsoft.AspNetCore.HttpOverrides/OverrideHeaderOptions.cs similarity index 100% rename from src/Microsoft.AspNet.HttpOverrides/OverrideHeaderOptions.cs rename to src/Microsoft.AspNetCore.HttpOverrides/OverrideHeaderOptions.cs diff --git a/src/Microsoft.AspNet.HttpOverrides/Properties/AssemblyInfo.cs b/src/Microsoft.AspNetCore.HttpOverrides/Properties/AssemblyInfo.cs similarity index 100% rename from src/Microsoft.AspNet.HttpOverrides/Properties/AssemblyInfo.cs rename to src/Microsoft.AspNetCore.HttpOverrides/Properties/AssemblyInfo.cs diff --git a/src/Microsoft.AspNet.HttpOverrides/project.json b/src/Microsoft.AspNetCore.HttpOverrides/project.json similarity index 100% rename from src/Microsoft.AspNet.HttpOverrides/project.json rename to src/Microsoft.AspNetCore.HttpOverrides/project.json diff --git a/test/Microsoft.AspNet.Buffering.Tests/Microsoft.AspNet.Buffering.Tests.xproj b/test/Microsoft.AspNetCore.Buffering.Tests/Microsoft.AspNetCore.Buffering.Tests.xproj similarity index 100% rename from test/Microsoft.AspNet.Buffering.Tests/Microsoft.AspNet.Buffering.Tests.xproj rename to test/Microsoft.AspNetCore.Buffering.Tests/Microsoft.AspNetCore.Buffering.Tests.xproj diff --git a/test/Microsoft.AspNet.Buffering.Tests/ResponseBufferingMiddlewareTests.cs b/test/Microsoft.AspNetCore.Buffering.Tests/ResponseBufferingMiddlewareTests.cs similarity index 100% rename from test/Microsoft.AspNet.Buffering.Tests/ResponseBufferingMiddlewareTests.cs rename to test/Microsoft.AspNetCore.Buffering.Tests/ResponseBufferingMiddlewareTests.cs diff --git a/test/Microsoft.AspNet.Buffering.Tests/project.json b/test/Microsoft.AspNetCore.Buffering.Tests/project.json similarity index 100% rename from test/Microsoft.AspNet.Buffering.Tests/project.json rename to test/Microsoft.AspNetCore.Buffering.Tests/project.json diff --git a/test/Microsoft.AspNet.HttpOverrides.Tests/HttpMethodOverrideMiddlewareTest.cs b/test/Microsoft.AspNetCore.HttpOverrides.Tests/HttpMethodOverrideMiddlewareTest.cs similarity index 100% rename from test/Microsoft.AspNet.HttpOverrides.Tests/HttpMethodOverrideMiddlewareTest.cs rename to test/Microsoft.AspNetCore.HttpOverrides.Tests/HttpMethodOverrideMiddlewareTest.cs diff --git a/test/Microsoft.AspNet.HttpOverrides.Tests/IPEndPointParserTest.cs b/test/Microsoft.AspNetCore.HttpOverrides.Tests/IPEndPointParserTest.cs similarity index 100% rename from test/Microsoft.AspNet.HttpOverrides.Tests/IPEndPointParserTest.cs rename to test/Microsoft.AspNetCore.HttpOverrides.Tests/IPEndPointParserTest.cs diff --git a/test/Microsoft.AspNet.HttpOverrides.Tests/Microsoft.AspNet.HttpOverrides.Tests.xproj b/test/Microsoft.AspNetCore.HttpOverrides.Tests/Microsoft.AspNetCore.HttpOverrides.Tests.xproj similarity index 100% rename from test/Microsoft.AspNet.HttpOverrides.Tests/Microsoft.AspNet.HttpOverrides.Tests.xproj rename to test/Microsoft.AspNetCore.HttpOverrides.Tests/Microsoft.AspNetCore.HttpOverrides.Tests.xproj diff --git a/test/Microsoft.AspNet.HttpOverrides.Tests/OverrideHeaderMiddlewareTest.cs b/test/Microsoft.AspNetCore.HttpOverrides.Tests/OverrideHeaderMiddlewareTest.cs similarity index 100% rename from test/Microsoft.AspNet.HttpOverrides.Tests/OverrideHeaderMiddlewareTest.cs rename to test/Microsoft.AspNetCore.HttpOverrides.Tests/OverrideHeaderMiddlewareTest.cs diff --git a/test/Microsoft.AspNet.HttpOverrides.Tests/project.json b/test/Microsoft.AspNetCore.HttpOverrides.Tests/project.json similarity index 100% rename from test/Microsoft.AspNet.HttpOverrides.Tests/project.json rename to test/Microsoft.AspNetCore.HttpOverrides.Tests/project.json From 3c6f68acb9366ee8a5ea0d074b6f26319859a15c Mon Sep 17 00:00:00 2001 From: "N. Taylor Mullen" Date: Fri, 22 Jan 2016 12:25:01 -0800 Subject: [PATCH 039/307] Rename AspNet 5 file contents. See https://github.com/aspnet/Announcements/issues/144 for more information. --- BasicMiddleware.sln | 10 +++++----- NuGetPackageVerifier.json | 4 ++-- samples/HttpOverridesSample/Startup.cs | 8 ++++---- samples/HttpOverridesSample/hosting.json | 4 ++-- samples/HttpOverridesSample/project.json | 8 ++++---- samples/ResponseBufferingSample/Startup.cs | 6 +++--- samples/ResponseBufferingSample/hosting.json | 4 ++-- samples/ResponseBufferingSample/project.json | 8 ++++---- .../BufferingWriteStream.cs | 2 +- .../HttpBufferingFeature.cs | 6 +++--- .../Microsoft.AspNetCore.Buffering.xproj | 4 ++-- .../ResponseBufferingMiddleware.cs | 8 ++++---- .../ResponseBufferingMiddlewareExtensions.cs | 6 +++--- .../SendFileFeatureWrapper.cs | 6 +++--- src/Microsoft.AspNetCore.Buffering/project.json | 2 +- .../ForwardedHeaders.cs | 4 ++-- .../HttpMethodOverrideExtensions.cs | 6 +++--- .../HttpMethodOverrideMiddleware.cs | 8 ++++---- .../HttpMethodOverrideOptions.cs | 4 ++-- .../IPEndPointParser.cs | 4 ++-- .../OverrideHeaderExtensions.cs | 6 +++--- .../OverrideHeaderMiddleware.cs | 6 +++--- .../OverrideHeaderOptions.cs | 6 +++--- .../project.json | 2 +- .../Microsoft.AspNetCore.Buffering.Tests.xproj | 4 ++-- .../ResponseBufferingMiddlewareTests.cs | 14 +++++++------- .../project.json | 6 +++--- .../HttpMethodOverrideMiddlewareTest.cs | 10 +++++----- .../IPEndPointParserTest.cs | 4 ++-- .../OverrideHeaderMiddlewareTest.cs | 10 +++++----- .../project.json | 4 ++-- 31 files changed, 92 insertions(+), 92 deletions(-) diff --git a/BasicMiddleware.sln b/BasicMiddleware.sln index a3fc740b7b..5dcf6b1d8f 100644 --- a/BasicMiddleware.sln +++ b/BasicMiddleware.sln @@ -1,24 +1,24 @@ - + Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 14 VisualStudioVersion = 14.0.24720.0 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNet.HttpOverrides", "src\Microsoft.AspNet.HttpOverrides\Microsoft.AspNet.HttpOverrides.xproj", "{517308C3-B477-4B01-B461-CAB9C10B6928}" +Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNetCore.HttpOverrides", "src\Microsoft.AspNetCore.HttpOverrides\Microsoft.AspNetCore.HttpOverrides.xproj", "{517308C3-B477-4B01-B461-CAB9C10B6928}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{A5076D28-FA7E-4606-9410-FEDD0D603527}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{8437B0F3-3894-4828-A945-A9187F37631D}" EndProject -Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNet.HttpOverrides.Tests", "test\Microsoft.AspNet.HttpOverrides.Tests\Microsoft.AspNet.HttpOverrides.Tests.xproj", "{D6341B92-3416-4F11-8DF4-CB274296175F}" +Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNetCore.HttpOverrides.Tests", "test\Microsoft.AspNetCore.HttpOverrides.Tests\Microsoft.AspNetCore.HttpOverrides.Tests.xproj", "{D6341B92-3416-4F11-8DF4-CB274296175F}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{99B72A07-32D6-434D-B44D-D064E3C13E08}" ProjectSection(SolutionItems) = preProject global.json = global.json EndProjectSection EndProject -Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNet.Buffering", "src\Microsoft.AspNet.Buffering\Microsoft.AspNet.Buffering.xproj", "{2363D0DD-A3BF-437E-9B64-B33AE132D875}" +Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNetCore.Buffering", "src\Microsoft.AspNetCore.Buffering\Microsoft.AspNetCore.Buffering.xproj", "{2363D0DD-A3BF-437E-9B64-B33AE132D875}" EndProject -Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNet.Buffering.Tests", "test\Microsoft.AspNet.Buffering.Tests\Microsoft.AspNet.Buffering.Tests.xproj", "{F5F1D123-9C81-4A9E-8644-AA46B8E578FB}" +Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNetCore.Buffering.Tests", "test\Microsoft.AspNetCore.Buffering.Tests\Microsoft.AspNetCore.Buffering.Tests.xproj", "{F5F1D123-9C81-4A9E-8644-AA46B8E578FB}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "samples", "samples", "{9587FE9F-5A17-42C4-8021-E87F59CECB98}" EndProject diff --git a/NuGetPackageVerifier.json b/NuGetPackageVerifier.json index f9d3834ce9..9cc45712f0 100644 --- a/NuGetPackageVerifier.json +++ b/NuGetPackageVerifier.json @@ -9,8 +9,8 @@ "StrictSemanticVersionValidationRule" ], "packages": { - "Microsoft.AspNet.Buffering": { }, - "Microsoft.AspNet.HttpOverrides": { } + "Microsoft.AspNetCore.Buffering": { }, + "Microsoft.AspNetCore.HttpOverrides": { } } }, "Default": { // Rules to run for packages not listed in any other set. diff --git a/samples/HttpOverridesSample/Startup.cs b/samples/HttpOverridesSample/Startup.cs index 606fd20163..473a978a55 100644 --- a/samples/HttpOverridesSample/Startup.cs +++ b/samples/HttpOverridesSample/Startup.cs @@ -1,7 +1,7 @@ -using Microsoft.AspNet.Builder; -using Microsoft.AspNet.Hosting; -using Microsoft.AspNet.Http; -using Microsoft.AspNet.HttpOverrides; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.HttpOverrides; namespace HttpOverridesSample { diff --git a/samples/HttpOverridesSample/hosting.json b/samples/HttpOverridesSample/hosting.json index f8ef14574d..6a93dbafa8 100644 --- a/samples/HttpOverridesSample/hosting.json +++ b/samples/HttpOverridesSample/hosting.json @@ -1,3 +1,3 @@ -{ - "server": "Microsoft.AspNet.Server.Kestrel" +{ + "server": "Microsoft.AspNetCore.Server.Kestrel" } diff --git a/samples/HttpOverridesSample/project.json b/samples/HttpOverridesSample/project.json index 007668ab4b..c6c5a3bb1d 100644 --- a/samples/HttpOverridesSample/project.json +++ b/samples/HttpOverridesSample/project.json @@ -1,12 +1,12 @@ -{ +{ "version": "1.0.0-*", "compilationOptions": { "emitEntryPoint": true }, "dependencies": { - "Microsoft.AspNet.IISPlatformHandler": "1.0.0-*", - "Microsoft.AspNet.Server.Kestrel": "1.0.0-*", - "Microsoft.AspNet.HttpOverrides": "1.0.0-*" + "Microsoft.AspNetCore.IISPlatformHandler": "1.0.0-*", + "Microsoft.AspNetCore.Server.Kestrel": "1.0.0-*", + "Microsoft.AspNetCore.HttpOverrides": "1.0.0-*" }, "commands": { "web": "HttpOverridesSample" diff --git a/samples/ResponseBufferingSample/Startup.cs b/samples/ResponseBufferingSample/Startup.cs index 035c499bc6..5679fe7566 100644 --- a/samples/ResponseBufferingSample/Startup.cs +++ b/samples/ResponseBufferingSample/Startup.cs @@ -1,6 +1,6 @@ -using Microsoft.AspNet.Builder; -using Microsoft.AspNet.Hosting; -using Microsoft.AspNet.Http; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Http; using Microsoft.Extensions.DependencyInjection; namespace ResponseBufferingSample diff --git a/samples/ResponseBufferingSample/hosting.json b/samples/ResponseBufferingSample/hosting.json index f8ef14574d..6a93dbafa8 100644 --- a/samples/ResponseBufferingSample/hosting.json +++ b/samples/ResponseBufferingSample/hosting.json @@ -1,3 +1,3 @@ -{ - "server": "Microsoft.AspNet.Server.Kestrel" +{ + "server": "Microsoft.AspNetCore.Server.Kestrel" } diff --git a/samples/ResponseBufferingSample/project.json b/samples/ResponseBufferingSample/project.json index 8e84112993..97d7c2dc97 100644 --- a/samples/ResponseBufferingSample/project.json +++ b/samples/ResponseBufferingSample/project.json @@ -1,9 +1,9 @@ -{ +{ "version": "1.0.0-*", "dependencies": { - "Microsoft.AspNet.Buffering": "1.0.0-*", - "Microsoft.AspNet.IISPlatformHandler": "1.0.0-*", - "Microsoft.AspNet.Server.Kestrel": "1.0.0-*" + "Microsoft.AspNetCore.Buffering": "1.0.0-*", + "Microsoft.AspNetCore.IISPlatformHandler": "1.0.0-*", + "Microsoft.AspNetCore.Server.Kestrel": "1.0.0-*" }, "compilationOptions": { "emitEntryPoint": true diff --git a/src/Microsoft.AspNetCore.Buffering/BufferingWriteStream.cs b/src/Microsoft.AspNetCore.Buffering/BufferingWriteStream.cs index c848b61767..999e05088e 100644 --- a/src/Microsoft.AspNetCore.Buffering/BufferingWriteStream.cs +++ b/src/Microsoft.AspNetCore.Buffering/BufferingWriteStream.cs @@ -6,7 +6,7 @@ using System.IO; using System.Threading; using System.Threading.Tasks; -namespace Microsoft.AspNet.Buffering +namespace Microsoft.AspNetCore.Buffering { internal class BufferingWriteStream : Stream { diff --git a/src/Microsoft.AspNetCore.Buffering/HttpBufferingFeature.cs b/src/Microsoft.AspNetCore.Buffering/HttpBufferingFeature.cs index 785f73e4e5..746712f5c8 100644 --- a/src/Microsoft.AspNetCore.Buffering/HttpBufferingFeature.cs +++ b/src/Microsoft.AspNetCore.Buffering/HttpBufferingFeature.cs @@ -1,9 +1,9 @@ -// Copyright (c) .NET Foundation. All rights reserved. +// 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 Microsoft.AspNet.Http.Features; +using Microsoft.AspNetCore.Http.Features; -namespace Microsoft.AspNet.Buffering +namespace Microsoft.AspNetCore.Buffering { internal class HttpBufferingFeature : IHttpBufferingFeature { diff --git a/src/Microsoft.AspNetCore.Buffering/Microsoft.AspNetCore.Buffering.xproj b/src/Microsoft.AspNetCore.Buffering/Microsoft.AspNetCore.Buffering.xproj index bc40210bfc..b74126ea03 100644 --- a/src/Microsoft.AspNetCore.Buffering/Microsoft.AspNetCore.Buffering.xproj +++ b/src/Microsoft.AspNetCore.Buffering/Microsoft.AspNetCore.Buffering.xproj @@ -1,4 +1,4 @@ - + 14.0 @@ -8,7 +8,7 @@ 2363d0dd-a3bf-437e-9b64-b33ae132d875 - Microsoft.AspNet.Buffering + Microsoft.AspNetCore.Buffering ..\..\artifacts\obj\$(MSBuildProjectName) ..\..\artifacts\bin\$(MSBuildProjectName)\ diff --git a/src/Microsoft.AspNetCore.Buffering/ResponseBufferingMiddleware.cs b/src/Microsoft.AspNetCore.Buffering/ResponseBufferingMiddleware.cs index 21e56a0ee2..bd5b8e1515 100644 --- a/src/Microsoft.AspNetCore.Buffering/ResponseBufferingMiddleware.cs +++ b/src/Microsoft.AspNetCore.Buffering/ResponseBufferingMiddleware.cs @@ -1,11 +1,11 @@ -// Copyright (c) .NET Foundation. All rights reserved. +// 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.Threading.Tasks; -using Microsoft.AspNet.Http; -using Microsoft.AspNet.Http.Features; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Http.Features; -namespace Microsoft.AspNet.Buffering +namespace Microsoft.AspNetCore.Buffering { public class ResponseBufferingMiddleware { diff --git a/src/Microsoft.AspNetCore.Buffering/ResponseBufferingMiddlewareExtensions.cs b/src/Microsoft.AspNetCore.Buffering/ResponseBufferingMiddlewareExtensions.cs index 77a37d1658..5092dba3c4 100644 --- a/src/Microsoft.AspNetCore.Buffering/ResponseBufferingMiddlewareExtensions.cs +++ b/src/Microsoft.AspNetCore.Buffering/ResponseBufferingMiddlewareExtensions.cs @@ -1,9 +1,9 @@ -// Copyright (c) .NET Foundation. All rights reserved. +// 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 Microsoft.AspNet.Buffering; +using Microsoft.AspNetCore.Buffering; -namespace Microsoft.AspNet.Builder +namespace Microsoft.AspNetCore.Builder { public static class ResponseBufferingMiddlewareExtensions { diff --git a/src/Microsoft.AspNetCore.Buffering/SendFileFeatureWrapper.cs b/src/Microsoft.AspNetCore.Buffering/SendFileFeatureWrapper.cs index e3daff187f..346173e315 100644 --- a/src/Microsoft.AspNetCore.Buffering/SendFileFeatureWrapper.cs +++ b/src/Microsoft.AspNetCore.Buffering/SendFileFeatureWrapper.cs @@ -1,11 +1,11 @@ -// Copyright (c) .NET Foundation. All rights reserved. +// 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.Threading; using System.Threading.Tasks; -using Microsoft.AspNet.Http.Features; +using Microsoft.AspNetCore.Http.Features; -namespace Microsoft.AspNet.Buffering +namespace Microsoft.AspNetCore.Buffering { internal class SendFileFeatureWrapper : IHttpSendFileFeature { diff --git a/src/Microsoft.AspNetCore.Buffering/project.json b/src/Microsoft.AspNetCore.Buffering/project.json index 7d1964e378..ef4628c8c5 100644 --- a/src/Microsoft.AspNetCore.Buffering/project.json +++ b/src/Microsoft.AspNetCore.Buffering/project.json @@ -10,7 +10,7 @@ "url": "git://github.com/aspnet/basicmiddleware" }, "dependencies": { - "Microsoft.AspNet.Http.Abstractions": "1.0.0-*" + "Microsoft.AspNetCore.Http.Abstractions": "1.0.0-*" }, "frameworks": { "net451": { }, diff --git a/src/Microsoft.AspNetCore.HttpOverrides/ForwardedHeaders.cs b/src/Microsoft.AspNetCore.HttpOverrides/ForwardedHeaders.cs index 5b5916212e..f161c3aee7 100644 --- a/src/Microsoft.AspNetCore.HttpOverrides/ForwardedHeaders.cs +++ b/src/Microsoft.AspNetCore.HttpOverrides/ForwardedHeaders.cs @@ -1,9 +1,9 @@ -// Copyright (c) .NET Foundation. All rights reserved. +// 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; -namespace Microsoft.AspNet.HttpOverrides +namespace Microsoft.AspNetCore.HttpOverrides { [Flags] public enum ForwardedHeaders diff --git a/src/Microsoft.AspNetCore.HttpOverrides/HttpMethodOverrideExtensions.cs b/src/Microsoft.AspNetCore.HttpOverrides/HttpMethodOverrideExtensions.cs index be2502dde1..7ad3ecf31a 100644 --- a/src/Microsoft.AspNetCore.HttpOverrides/HttpMethodOverrideExtensions.cs +++ b/src/Microsoft.AspNetCore.HttpOverrides/HttpMethodOverrideExtensions.cs @@ -1,11 +1,11 @@ -// Copyright (c) .NET Foundation. All rights reserved. +// 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; -using Microsoft.AspNet.HttpOverrides; +using Microsoft.AspNetCore.HttpOverrides; using Microsoft.Extensions.Options; -namespace Microsoft.AspNet.Builder +namespace Microsoft.AspNetCore.Builder { public static class HttpMethodOverrideExtensions { diff --git a/src/Microsoft.AspNetCore.HttpOverrides/HttpMethodOverrideMiddleware.cs b/src/Microsoft.AspNetCore.HttpOverrides/HttpMethodOverrideMiddleware.cs index 804e44d5f7..60965e50b1 100644 --- a/src/Microsoft.AspNetCore.HttpOverrides/HttpMethodOverrideMiddleware.cs +++ b/src/Microsoft.AspNetCore.HttpOverrides/HttpMethodOverrideMiddleware.cs @@ -1,13 +1,13 @@ -// Copyright (c) .NET Foundation. All rights reserved. +// 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; using System.Threading.Tasks; -using Microsoft.AspNet.Builder; -using Microsoft.AspNet.Http; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Options; -namespace Microsoft.AspNet.HttpOverrides +namespace Microsoft.AspNetCore.HttpOverrides { public class HttpMethodOverrideMiddleware { diff --git a/src/Microsoft.AspNetCore.HttpOverrides/HttpMethodOverrideOptions.cs b/src/Microsoft.AspNetCore.HttpOverrides/HttpMethodOverrideOptions.cs index e6ade4a274..8bfb82790f 100644 --- a/src/Microsoft.AspNetCore.HttpOverrides/HttpMethodOverrideOptions.cs +++ b/src/Microsoft.AspNetCore.HttpOverrides/HttpMethodOverrideOptions.cs @@ -1,7 +1,7 @@ -// Copyright (c) .NET Foundation. All rights reserved. +// 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. -namespace Microsoft.AspNet.Builder +namespace Microsoft.AspNetCore.Builder { public class HttpMethodOverrideOptions { diff --git a/src/Microsoft.AspNetCore.HttpOverrides/IPEndPointParser.cs b/src/Microsoft.AspNetCore.HttpOverrides/IPEndPointParser.cs index b303c0d2c6..9bdd0a66cf 100644 --- a/src/Microsoft.AspNetCore.HttpOverrides/IPEndPointParser.cs +++ b/src/Microsoft.AspNetCore.HttpOverrides/IPEndPointParser.cs @@ -1,9 +1,9 @@ -// Copyright (c) .NET Foundation. All rights reserved. +// 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; -namespace Microsoft.AspNet.HttpOverrides +namespace Microsoft.AspNetCore.HttpOverrides { public static class IPEndPointParser { diff --git a/src/Microsoft.AspNetCore.HttpOverrides/OverrideHeaderExtensions.cs b/src/Microsoft.AspNetCore.HttpOverrides/OverrideHeaderExtensions.cs index e22e4af34d..8925c4bb68 100644 --- a/src/Microsoft.AspNetCore.HttpOverrides/OverrideHeaderExtensions.cs +++ b/src/Microsoft.AspNetCore.HttpOverrides/OverrideHeaderExtensions.cs @@ -1,11 +1,11 @@ -// Copyright (c) .NET Foundation. All rights reserved. +// 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; -using Microsoft.AspNet.HttpOverrides; +using Microsoft.AspNetCore.HttpOverrides; using Microsoft.Extensions.Options; -namespace Microsoft.AspNet.Builder +namespace Microsoft.AspNetCore.Builder { public static class OverrideHeaderExtensions { diff --git a/src/Microsoft.AspNetCore.HttpOverrides/OverrideHeaderMiddleware.cs b/src/Microsoft.AspNetCore.HttpOverrides/OverrideHeaderMiddleware.cs index 9eb8564c11..e23a883031 100644 --- a/src/Microsoft.AspNetCore.HttpOverrides/OverrideHeaderMiddleware.cs +++ b/src/Microsoft.AspNetCore.HttpOverrides/OverrideHeaderMiddleware.cs @@ -4,11 +4,11 @@ using System; using System.Net; using System.Threading.Tasks; -using Microsoft.AspNet.Builder; -using Microsoft.AspNet.Http; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Options; -namespace Microsoft.AspNet.HttpOverrides +namespace Microsoft.AspNetCore.HttpOverrides { public class OverrideHeaderMiddleware { diff --git a/src/Microsoft.AspNetCore.HttpOverrides/OverrideHeaderOptions.cs b/src/Microsoft.AspNetCore.HttpOverrides/OverrideHeaderOptions.cs index eb63f71b58..011c564813 100644 --- a/src/Microsoft.AspNetCore.HttpOverrides/OverrideHeaderOptions.cs +++ b/src/Microsoft.AspNetCore.HttpOverrides/OverrideHeaderOptions.cs @@ -1,9 +1,9 @@ -// Copyright (c) .NET Foundation. All rights reserved. +// 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 Microsoft.AspNet.HttpOverrides; +using Microsoft.AspNetCore.HttpOverrides; -namespace Microsoft.AspNet.Builder +namespace Microsoft.AspNetCore.Builder { public class OverrideHeaderOptions { diff --git a/src/Microsoft.AspNetCore.HttpOverrides/project.json b/src/Microsoft.AspNetCore.HttpOverrides/project.json index 01612e537c..ec8f9fd667 100644 --- a/src/Microsoft.AspNetCore.HttpOverrides/project.json +++ b/src/Microsoft.AspNetCore.HttpOverrides/project.json @@ -10,7 +10,7 @@ "url": "git://github.com/aspnet/basicmiddleware" }, "dependencies": { - "Microsoft.AspNet.Http.Extensions": "1.0.0-*", + "Microsoft.AspNetCore.Http.Extensions": "1.0.0-*", "Microsoft.Extensions.Options": "1.0.0-*" }, "frameworks": { diff --git a/test/Microsoft.AspNetCore.Buffering.Tests/Microsoft.AspNetCore.Buffering.Tests.xproj b/test/Microsoft.AspNetCore.Buffering.Tests/Microsoft.AspNetCore.Buffering.Tests.xproj index a047e54513..322999a908 100644 --- a/test/Microsoft.AspNetCore.Buffering.Tests/Microsoft.AspNetCore.Buffering.Tests.xproj +++ b/test/Microsoft.AspNetCore.Buffering.Tests/Microsoft.AspNetCore.Buffering.Tests.xproj @@ -1,4 +1,4 @@ - + 14.0 @@ -7,7 +7,7 @@ f5f1d123-9c81-4a9e-8644-aa46b8e578fb - Microsoft.AspNet.Buffering.Tests + Microsoft.AspNetCore.Buffering.Tests ..\..\artifacts\obj\$(MSBuildProjectName) ..\..\artifacts\bin\$(MSBuildProjectName)\ diff --git a/test/Microsoft.AspNetCore.Buffering.Tests/ResponseBufferingMiddlewareTests.cs b/test/Microsoft.AspNetCore.Buffering.Tests/ResponseBufferingMiddlewareTests.cs index e2cc8da5e5..81aa993e98 100644 --- a/test/Microsoft.AspNetCore.Buffering.Tests/ResponseBufferingMiddlewareTests.cs +++ b/test/Microsoft.AspNetCore.Buffering.Tests/ResponseBufferingMiddlewareTests.cs @@ -1,4 +1,4 @@ -// Copyright (c) .NET Foundation. All rights reserved. +// 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; @@ -6,14 +6,14 @@ using System.Collections.Generic; using System.IO; using System.Linq; using System.Threading.Tasks; -using Microsoft.AspNet.Builder; -using Microsoft.AspNet.Hosting; -using Microsoft.AspNet.Http; -using Microsoft.AspNet.Http.Features; -using Microsoft.AspNet.TestHost; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Http.Features; +using Microsoft.AspNetCore.TestHost; using Xunit; -namespace Microsoft.AspNet.Buffering.Tests +namespace Microsoft.AspNetCore.Buffering.Tests { public class ResponseBufferingMiddlewareTests { diff --git a/test/Microsoft.AspNetCore.Buffering.Tests/project.json b/test/Microsoft.AspNetCore.Buffering.Tests/project.json index 560600e505..1d139baac7 100644 --- a/test/Microsoft.AspNetCore.Buffering.Tests/project.json +++ b/test/Microsoft.AspNetCore.Buffering.Tests/project.json @@ -1,11 +1,11 @@ -{ +{ "version": "1.0.0-*", "compilationOptions": { "warningsAsErrors": true }, "dependencies": { - "Microsoft.AspNet.Buffering": "1.0.0-*", - "Microsoft.AspNet.TestHost": "1.0.0-*", + "Microsoft.AspNetCore.Buffering": "1.0.0-*", + "Microsoft.AspNetCore.TestHost": "1.0.0-*", "xunit": "2.1.0" }, "frameworks": { diff --git a/test/Microsoft.AspNetCore.HttpOverrides.Tests/HttpMethodOverrideMiddlewareTest.cs b/test/Microsoft.AspNetCore.HttpOverrides.Tests/HttpMethodOverrideMiddlewareTest.cs index 5c4108ddfc..fcd47da8ba 100644 --- a/test/Microsoft.AspNetCore.HttpOverrides.Tests/HttpMethodOverrideMiddlewareTest.cs +++ b/test/Microsoft.AspNetCore.HttpOverrides.Tests/HttpMethodOverrideMiddlewareTest.cs @@ -1,15 +1,15 @@ -// Copyright (c) .NET Foundation. All rights reserved. +// 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.Collections.Generic; using System.Net.Http; using System.Threading.Tasks; -using Microsoft.AspNet.Builder; -using Microsoft.AspNet.Hosting; -using Microsoft.AspNet.TestHost; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.TestHost; using Xunit; -namespace Microsoft.AspNet.HttpOverrides +namespace Microsoft.AspNetCore.HttpOverrides { public class HttpMethodOverrideMiddlewareTest { diff --git a/test/Microsoft.AspNetCore.HttpOverrides.Tests/IPEndPointParserTest.cs b/test/Microsoft.AspNetCore.HttpOverrides.Tests/IPEndPointParserTest.cs index 9970dd8610..0ba8e134ee 100644 --- a/test/Microsoft.AspNetCore.HttpOverrides.Tests/IPEndPointParserTest.cs +++ b/test/Microsoft.AspNetCore.HttpOverrides.Tests/IPEndPointParserTest.cs @@ -1,10 +1,10 @@ -// Copyright (c) .NET Foundation. All rights reserved. +// 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 Xunit; -namespace Microsoft.AspNet.HttpOverrides +namespace Microsoft.AspNetCore.HttpOverrides { public class IPEndPointParserTests { diff --git a/test/Microsoft.AspNetCore.HttpOverrides.Tests/OverrideHeaderMiddlewareTest.cs b/test/Microsoft.AspNetCore.HttpOverrides.Tests/OverrideHeaderMiddlewareTest.cs index 1dd86d3bcd..b66e57e2cd 100644 --- a/test/Microsoft.AspNetCore.HttpOverrides.Tests/OverrideHeaderMiddlewareTest.cs +++ b/test/Microsoft.AspNetCore.HttpOverrides.Tests/OverrideHeaderMiddlewareTest.cs @@ -1,14 +1,14 @@ -// Copyright (c) .NET Foundation. All rights reserved. +// 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.Http; using System.Threading.Tasks; -using Microsoft.AspNet.Builder; -using Microsoft.AspNet.Hosting; -using Microsoft.AspNet.TestHost; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.TestHost; using Xunit; -namespace Microsoft.AspNet.HttpOverrides +namespace Microsoft.AspNetCore.HttpOverrides { public class OverrideMiddlewareHeaderTests { diff --git a/test/Microsoft.AspNetCore.HttpOverrides.Tests/project.json b/test/Microsoft.AspNetCore.HttpOverrides.Tests/project.json index 8502eb3c9b..f58a6f2b3b 100644 --- a/test/Microsoft.AspNetCore.HttpOverrides.Tests/project.json +++ b/test/Microsoft.AspNetCore.HttpOverrides.Tests/project.json @@ -4,8 +4,8 @@ "warningsAsErrors": true }, "dependencies": { - "Microsoft.AspNet.HttpOverrides": "1.0.0-*", - "Microsoft.AspNet.TestHost": "1.0.0-*", + "Microsoft.AspNetCore.HttpOverrides": "1.0.0-*", + "Microsoft.AspNetCore.TestHost": "1.0.0-*", "Microsoft.Extensions.Logging.Testing": "1.0.0-*", "xunit": "2.1.0" }, From ab34d08bc1b97f601783186bb4e49ff81d6386bb Mon Sep 17 00:00:00 2001 From: "N. Taylor Mullen" Date: Fri, 22 Jan 2016 12:28:45 -0800 Subject: [PATCH 040/307] Update ASP.NET 5 versions for ASP.NET Core. See https://github.com/aspnet/Announcements/issues/144 for more information. --- samples/HttpOverridesSample/project.json | 8 ++++---- samples/ResponseBufferingSample/project.json | 10 +++++----- src/Microsoft.AspNetCore.Buffering/project.json | 6 +++--- src/Microsoft.AspNetCore.HttpOverrides/project.json | 6 +++--- test/Microsoft.AspNetCore.Buffering.Tests/project.json | 8 ++++---- .../project.json | 8 ++++---- 6 files changed, 23 insertions(+), 23 deletions(-) diff --git a/samples/HttpOverridesSample/project.json b/samples/HttpOverridesSample/project.json index c6c5a3bb1d..7550445e20 100644 --- a/samples/HttpOverridesSample/project.json +++ b/samples/HttpOverridesSample/project.json @@ -6,14 +6,14 @@ "dependencies": { "Microsoft.AspNetCore.IISPlatformHandler": "1.0.0-*", "Microsoft.AspNetCore.Server.Kestrel": "1.0.0-*", - "Microsoft.AspNetCore.HttpOverrides": "1.0.0-*" + "Microsoft.AspNetCore.HttpOverrides": "0.1.0-*" }, "commands": { "web": "HttpOverridesSample" }, "frameworks": { - "dnx451": { }, - "dnxcore50": { } + "dnx451": {}, + "dnxcore50": {} }, "exclude": [ "wwwroot", @@ -23,4 +23,4 @@ "**.user", "**.vspscc" ] -} +} \ No newline at end of file diff --git a/samples/ResponseBufferingSample/project.json b/samples/ResponseBufferingSample/project.json index 97d7c2dc97..3c5ff7f44f 100644 --- a/samples/ResponseBufferingSample/project.json +++ b/samples/ResponseBufferingSample/project.json @@ -1,7 +1,7 @@ { "version": "1.0.0-*", "dependencies": { - "Microsoft.AspNetCore.Buffering": "1.0.0-*", + "Microsoft.AspNetCore.Buffering": "0.1.0-*", "Microsoft.AspNetCore.IISPlatformHandler": "1.0.0-*", "Microsoft.AspNetCore.Server.Kestrel": "1.0.0-*" }, @@ -9,11 +9,11 @@ "emitEntryPoint": true }, "commands": { - "web": "ResponseBufferingSample" + "web": "ResponseBufferingSample" }, "frameworks": { - "dnx451": { }, - "dnxcore50": { } + "dnx451": {}, + "dnxcore50": {} }, "publishExclude": [ "node_modules", @@ -27,4 +27,4 @@ "node_modules", "bower_components" ] -} +} \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Buffering/project.json b/src/Microsoft.AspNetCore.Buffering/project.json index ef4628c8c5..6ea212875a 100644 --- a/src/Microsoft.AspNetCore.Buffering/project.json +++ b/src/Microsoft.AspNetCore.Buffering/project.json @@ -1,5 +1,5 @@ { - "version": "1.0.0-*", + "version": "0.1.0-*", "compilationOptions": { "warningsAsErrors": true, "keyFile": "../../tools/Key.snk" @@ -13,7 +13,7 @@ "Microsoft.AspNetCore.Http.Abstractions": "1.0.0-*" }, "frameworks": { - "net451": { }, - "dotnet5.4": { } + "net451": {}, + "dotnet5.4": {} } } \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.HttpOverrides/project.json b/src/Microsoft.AspNetCore.HttpOverrides/project.json index ec8f9fd667..78d4310cab 100644 --- a/src/Microsoft.AspNetCore.HttpOverrides/project.json +++ b/src/Microsoft.AspNetCore.HttpOverrides/project.json @@ -1,5 +1,5 @@ { - "version": "1.0.0-*", + "version": "0.1.0-*", "compilationOptions": { "warningsAsErrors": true, "keyFile": "../../tools/Key.snk" @@ -14,7 +14,7 @@ "Microsoft.Extensions.Options": "1.0.0-*" }, "frameworks": { - "net451": { }, - "dotnet5.4": { } + "net451": {}, + "dotnet5.4": {} } } \ No newline at end of file diff --git a/test/Microsoft.AspNetCore.Buffering.Tests/project.json b/test/Microsoft.AspNetCore.Buffering.Tests/project.json index 1d139baac7..64d93344ae 100644 --- a/test/Microsoft.AspNetCore.Buffering.Tests/project.json +++ b/test/Microsoft.AspNetCore.Buffering.Tests/project.json @@ -4,13 +4,13 @@ "warningsAsErrors": true }, "dependencies": { - "Microsoft.AspNetCore.Buffering": "1.0.0-*", + "Microsoft.AspNetCore.Buffering": "0.1.0-*", "Microsoft.AspNetCore.TestHost": "1.0.0-*", "xunit": "2.1.0" }, "frameworks": { "dnx451": { - "frameworkAssemblies": { + "frameworkAssemblies": { "System.Runtime": "", "System.Threading.Tasks": "" }, @@ -18,7 +18,7 @@ "xunit.runner.console": "2.1.0" } }, - "dnxcore50": { + "dnxcore50": { "dependencies": { "xunit.runner.aspnet": "2.0.0-aspnet-*" } @@ -28,4 +28,4 @@ "commands": { "test": "xunit.runner.aspnet" } -} +} \ No newline at end of file diff --git a/test/Microsoft.AspNetCore.HttpOverrides.Tests/project.json b/test/Microsoft.AspNetCore.HttpOverrides.Tests/project.json index f58a6f2b3b..107fcfb6ab 100644 --- a/test/Microsoft.AspNetCore.HttpOverrides.Tests/project.json +++ b/test/Microsoft.AspNetCore.HttpOverrides.Tests/project.json @@ -4,14 +4,14 @@ "warningsAsErrors": true }, "dependencies": { - "Microsoft.AspNetCore.HttpOverrides": "1.0.0-*", + "Microsoft.AspNetCore.HttpOverrides": "0.1.0-*", "Microsoft.AspNetCore.TestHost": "1.0.0-*", "Microsoft.Extensions.Logging.Testing": "1.0.0-*", "xunit": "2.1.0" }, "frameworks": { "dnx451": { - "frameworkAssemblies": { + "frameworkAssemblies": { "System.Runtime": "", "System.Threading.Tasks": "" }, @@ -19,7 +19,7 @@ "xunit.runner.console": "2.1.0" } }, - "dnxcore50": { + "dnxcore50": { "dependencies": { "xunit.runner.aspnet": "2.0.0-aspnet-*" } @@ -29,4 +29,4 @@ "commands": { "test": "xunit.runner.aspnet" } -} +} \ No newline at end of file From 44f03ef83f1d0678b1dd95f7b021378f5b54eb7d Mon Sep 17 00:00:00 2001 From: Chris R Date: Mon, 21 Dec 2015 14:45:37 -0800 Subject: [PATCH 041/307] Restrict x-forwarded-for evalutation. Credit: pmhsfelix. Use x-forwarded-for validation to restrict other forwarders. Rename OverrideHeaderMiddleware to ForwardedHeadersMiddleware. Fix tests Fix package version. --- samples/HttpOverridesSample/Startup.cs | 5 +- samples/HttpOverridesSample/project.json | 6 +- ...sions.cs => ForwardedHeadersExtensions.cs} | 15 +- .../ForwardedHeadersMiddleware.cs | 275 +++++++++ .../ForwardedHeadersOptions.cs | 34 ++ .../IPNetwork.cs | 67 +++ .../{ => Internal}/IPEndPointParser.cs | 2 +- .../OverrideHeaderMiddleware.cs | 107 ---- .../OverrideHeaderOptions.cs | 12 - .../project.json | 3 +- .../ForwardedHeadersMiddlewareTest.cs | 522 ++++++++++++++++++ .../IPEndPointParserTest.cs | 2 +- .../IPNetworkTest.cs | 33 ++ .../OverrideHeaderMiddlewareTest.cs | 223 -------- .../project.json | 2 +- 15 files changed, 948 insertions(+), 360 deletions(-) rename src/Microsoft.AspNetCore.HttpOverrides/{OverrideHeaderExtensions.cs => ForwardedHeadersExtensions.cs} (61%) create mode 100644 src/Microsoft.AspNetCore.HttpOverrides/ForwardedHeadersMiddleware.cs create mode 100644 src/Microsoft.AspNetCore.HttpOverrides/ForwardedHeadersOptions.cs create mode 100644 src/Microsoft.AspNetCore.HttpOverrides/IPNetwork.cs rename src/Microsoft.AspNetCore.HttpOverrides/{ => Internal}/IPEndPointParser.cs (97%) delete mode 100644 src/Microsoft.AspNetCore.HttpOverrides/OverrideHeaderMiddleware.cs delete mode 100644 src/Microsoft.AspNetCore.HttpOverrides/OverrideHeaderOptions.cs create mode 100644 test/Microsoft.AspNetCore.HttpOverrides.Tests/ForwardedHeadersMiddlewareTest.cs create mode 100644 test/Microsoft.AspNetCore.HttpOverrides.Tests/IPNetworkTest.cs delete mode 100644 test/Microsoft.AspNetCore.HttpOverrides.Tests/OverrideHeaderMiddlewareTest.cs diff --git a/samples/HttpOverridesSample/Startup.cs b/samples/HttpOverridesSample/Startup.cs index 473a978a55..9cacb60dc1 100644 --- a/samples/HttpOverridesSample/Startup.cs +++ b/samples/HttpOverridesSample/Startup.cs @@ -10,10 +10,9 @@ namespace HttpOverridesSample // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. public void Configure(IApplicationBuilder app) { - app.UseIISPlatformHandler(); - app.UseOverrideHeaders(new OverrideHeaderOptions + app.UseForwardedHeaders(new ForwardedHeadersOptions { - ForwardedOptions = ForwardedHeaders.All + ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto }); app.UseHttpMethodOverride(); diff --git a/samples/HttpOverridesSample/project.json b/samples/HttpOverridesSample/project.json index 7550445e20..6f7515973c 100644 --- a/samples/HttpOverridesSample/project.json +++ b/samples/HttpOverridesSample/project.json @@ -4,9 +4,9 @@ "emitEntryPoint": true }, "dependencies": { + "Microsoft.AspNetCore.HttpOverrides": "1.0.0-*", "Microsoft.AspNetCore.IISPlatformHandler": "1.0.0-*", - "Microsoft.AspNetCore.Server.Kestrel": "1.0.0-*", - "Microsoft.AspNetCore.HttpOverrides": "0.1.0-*" + "Microsoft.AspNetCore.Server.Kestrel": "1.0.0-*" }, "commands": { "web": "HttpOverridesSample" @@ -23,4 +23,4 @@ "**.user", "**.vspscc" ] -} \ No newline at end of file +} diff --git a/src/Microsoft.AspNetCore.HttpOverrides/OverrideHeaderExtensions.cs b/src/Microsoft.AspNetCore.HttpOverrides/ForwardedHeadersExtensions.cs similarity index 61% rename from src/Microsoft.AspNetCore.HttpOverrides/OverrideHeaderExtensions.cs rename to src/Microsoft.AspNetCore.HttpOverrides/ForwardedHeadersExtensions.cs index 8925c4bb68..df3c221996 100644 --- a/src/Microsoft.AspNetCore.HttpOverrides/OverrideHeaderExtensions.cs +++ b/src/Microsoft.AspNetCore.HttpOverrides/ForwardedHeadersExtensions.cs @@ -1,4 +1,4 @@ -// Copyright (c) .NET Foundation. All rights reserved. +// 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; @@ -7,31 +7,30 @@ using Microsoft.Extensions.Options; namespace Microsoft.AspNetCore.Builder { - public static class OverrideHeaderExtensions + public static class ForwardedHeadersExtensions { /// /// Forwards proxied headers onto current request /// /// - /// Enables the different override options. /// - public static IApplicationBuilder UseOverrideHeaders(this IApplicationBuilder builder) + public static IApplicationBuilder UseForwardedHeaders(this IApplicationBuilder builder) { if (builder == null) { throw new ArgumentNullException(nameof(builder)); } - return builder.UseMiddleware(); + return builder.UseMiddleware(); } /// /// Forwards proxied headers onto current request /// /// - /// Enables the different override options. + /// Enables the different forwarding options. /// - public static IApplicationBuilder UseOverrideHeaders(this IApplicationBuilder builder, OverrideHeaderOptions options) + public static IApplicationBuilder UseForwardedHeaders(this IApplicationBuilder builder, ForwardedHeadersOptions options) { if (builder == null) { @@ -42,7 +41,7 @@ namespace Microsoft.AspNetCore.Builder throw new ArgumentNullException(nameof(options)); } - return builder.UseMiddleware(Options.Create(options)); + return builder.UseMiddleware(Options.Create(options)); } } } diff --git a/src/Microsoft.AspNetCore.HttpOverrides/ForwardedHeadersMiddleware.cs b/src/Microsoft.AspNetCore.HttpOverrides/ForwardedHeadersMiddleware.cs new file mode 100644 index 0000000000..042b0887b7 --- /dev/null +++ b/src/Microsoft.AspNetCore.HttpOverrides/ForwardedHeadersMiddleware.cs @@ -0,0 +1,275 @@ +// 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; +using System.Collections.Generic; +using System.Linq; +using System.Net; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.HttpOverrides.Internal; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; +using Microsoft.Extensions.Primitives; + +namespace Microsoft.AspNetCore.HttpOverrides +{ + public class ForwardedHeadersMiddleware + { + private const string XForwardedForHeaderName = "X-Forwarded-For"; + private const string XForwardedHostHeaderName = "X-Forwarded-Host"; + private const string XForwardedProtoHeaderName = "X-Forwarded-Proto"; + private const string XOriginalForName = "X-Original-For"; + private const string XOriginalHostName = "X-Original-Host"; + private const string XOriginalProtoName = "X-Original-Proto"; + + private readonly ForwardedHeadersOptions _options; + private readonly RequestDelegate _next; + private readonly ILogger _logger; + + public ForwardedHeadersMiddleware(RequestDelegate next, ILoggerFactory loggerFactory, IOptions options) + { + if (next == null) + { + throw new ArgumentNullException(nameof(next)); + } + if (loggerFactory == null) + { + throw new ArgumentNullException(nameof(loggerFactory)); + } + if (options == null) + { + throw new ArgumentNullException(nameof(options)); + } + + _options = options.Value; + _logger = loggerFactory.CreateLogger(); + _next = next; + } + + public Task Invoke(HttpContext context) + { + ApplyForwarders(context); + return _next(context); + } + + public void ApplyForwarders(HttpContext context) + { + // Gather expected headers. Enabled headers must have the same number of entries. + string[] forwardedFor = null, forwardedProto = null, forwardedHost = null; + bool checkFor = false, checkProto = false, checkHost = false; + int entryCount = 0; + + if ((_options.ForwardedHeaders & ForwardedHeaders.XForwardedFor) == ForwardedHeaders.XForwardedFor) + { + checkFor = true; + forwardedFor = context.Request.Headers.GetCommaSeparatedValues(XForwardedForHeaderName); + if (StringValues.IsNullOrEmpty(forwardedFor)) + { + return; + } + entryCount = forwardedFor.Length; + } + + if ((_options.ForwardedHeaders & ForwardedHeaders.XForwardedProto) == ForwardedHeaders.XForwardedProto) + { + checkProto = true; + forwardedProto = context.Request.Headers.GetCommaSeparatedValues(XForwardedProtoHeaderName); + if (StringValues.IsNullOrEmpty(forwardedProto)) + { + return; + } + if (checkFor && forwardedFor.Length != forwardedProto.Length) + { + _logger.LogDebug(1, "Parameter count mismatch between X-Forwarded-For and X-Forwarded-Proto."); + return; + } + entryCount = forwardedProto.Length; + } + + if ((_options.ForwardedHeaders & ForwardedHeaders.XForwardedHost) == ForwardedHeaders.XForwardedHost) + { + checkHost = true; + forwardedHost = context.Request.Headers.GetCommaSeparatedValues(XForwardedHostHeaderName); + if (StringValues.IsNullOrEmpty(forwardedHost)) + { + return; + } + if ((checkFor && forwardedFor.Length != forwardedHost.Length) + || (checkProto && forwardedProto.Length != forwardedHost.Length)) + { + _logger.LogDebug(1, "Parameter count mismatch between X-Forwarded-Host and X-Forwarded-For or X-Forwarded-Proto."); + return; + } + entryCount = forwardedHost.Length; + } + + // Apply ForwardLimit, if any + int offset = 0; + if (_options.ForwardLimit.HasValue && entryCount > _options.ForwardLimit) + { + offset = entryCount - _options.ForwardLimit.Value; + entryCount = _options.ForwardLimit.Value; + } + + // Group the data together. + var sets = new List(entryCount); + for (int i = 0; i < entryCount; i++) + { + var set = new SetOfForwarders(); + if (checkFor) + { + set.IpAndPortText = forwardedFor[offset + i]; + } + if (checkProto) + { + set.Scheme = forwardedProto[offset + i]; + } + if (checkHost) + { + set.Host = forwardedHost[offset + i]; + } + sets.Add(set); + } + // They get processed in reverse order, right to left. + sets.Reverse(); + + // Gather initial values + var connection = context.Connection; + var request = context.Request; + var currentValues = new SetOfForwarders() + { + RemoteIpAndPort = connection.RemoteIpAddress != null ? new IPEndPoint(connection.RemoteIpAddress, connection.RemotePort) : null, + // Host and Scheme initial values are never inspected, no need to set them here. + }; + + var checkKnownIps = _options.KnownNetworks.Count > 0 || _options.KnownProxies.Count > 0; + bool applyChanges = false; + int entriesConsumed = 0; + + foreach (var set in sets) + { + if (checkFor) + { + // For the first instance, allow remoteIp to be null for servers that don't support it natively. + if (currentValues.RemoteIpAndPort != null && checkKnownIps && !CheckKnownAddress(currentValues.RemoteIpAndPort.Address)) + { + // Stop at the first unknown remote IP, but still apply changes processed so far. + _logger.LogDebug(1, $"Unknown proxy: {currentValues.RemoteIpAndPort}"); + break; + } + if (!IPEndPointParser.TryParse(set.IpAndPortText, out set.RemoteIpAndPort)) + { + _logger.LogDebug(2, $"Failed to parse forwarded IPAddress: {currentValues.IpAndPortText}"); + return; + } + } + + if (checkProto) + { + if (string.IsNullOrEmpty(set.Scheme)) + { + _logger.LogDebug(3, $"Failed to parse forwarded scheme: {set.Scheme}"); + return; + } + } + + if (checkHost) + { + if (string.IsNullOrEmpty(set.Host)) + { + _logger.LogDebug(4, $"Failed to parse forwarded host: {set.Host}"); + return; + } + } + + applyChanges = true; + currentValues = set; + entriesConsumed++; + } + + if (applyChanges) + { + if (checkFor) + { + if (connection.RemoteIpAddress != null) + { + // Save the original + request.Headers[XOriginalForName] = new IPEndPoint(connection.RemoteIpAddress, connection.RemotePort).ToString(); + } + if (forwardedFor.Length > entriesConsumed) + { + // Truncate the consumed header values + request.Headers[XForwardedForHeaderName] = forwardedFor.Take(forwardedFor.Length - entriesConsumed).ToArray(); + } + else + { + // All values were consumed + request.Headers.Remove(XForwardedForHeaderName); + } + connection.RemoteIpAddress = currentValues.RemoteIpAndPort.Address; + connection.RemotePort = currentValues.RemoteIpAndPort.Port; + } + + if (checkProto) + { + // Save the original + request.Headers[XOriginalProtoName] = request.Scheme; + if (forwardedProto.Length > entriesConsumed) + { + // Truncate the consumed header values + request.Headers[XForwardedProtoHeaderName] = forwardedProto.Take(forwardedProto.Length - entriesConsumed).ToArray(); + } + else + { + // All values were consumed + request.Headers.Remove(XForwardedProtoHeaderName); + } + request.Scheme = currentValues.Scheme; + } + + if (checkHost) + { + // Save the original + request.Headers[XOriginalHostName] = request.Host.ToString(); + if (forwardedHost.Length > entriesConsumed) + { + // Truncate the consumed header values + request.Headers[XForwardedHostHeaderName] = forwardedHost.Take(forwardedHost.Length - entriesConsumed).ToArray(); + } + else + { + // All values were consumed + request.Headers.Remove(XForwardedHostHeaderName); + } + request.Host = HostString.FromUriComponent(currentValues.Host); + } + } + } + + private bool CheckKnownAddress(IPAddress address) + { + if (_options.KnownProxies.Contains(address)) + { + return true; + } + foreach (var network in _options.KnownNetworks) + { + if (network.Contains(address)) + { + return true; + } + } + return false; + } + + private class SetOfForwarders + { + public string IpAndPortText; + public IPEndPoint RemoteIpAndPort; + public string Host; + public string Scheme; + } + } +} diff --git a/src/Microsoft.AspNetCore.HttpOverrides/ForwardedHeadersOptions.cs b/src/Microsoft.AspNetCore.HttpOverrides/ForwardedHeadersOptions.cs new file mode 100644 index 0000000000..2802e79359 --- /dev/null +++ b/src/Microsoft.AspNetCore.HttpOverrides/ForwardedHeadersOptions.cs @@ -0,0 +1,34 @@ +// 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.Collections.Generic; +using System.Net; +using Microsoft.AspNetCore.HttpOverrides; + +namespace Microsoft.AspNetCore.Builder +{ + public class ForwardedHeadersOptions + { + /// + /// Identifies which forwarders should be processed. + /// + public ForwardedHeaders ForwardedHeaders { get; set; } + + /// + /// Limits the number of entries in the headers that will be processed. The default value is 1. + /// Set to null to disable the limit, but this should only be done if + /// KnownProxies or KnownNetworks are configured. + /// + public int? ForwardLimit { get; set; } = 1; + + /// + /// Addresses of known proxies to accept forwarded headers from. + /// + public IList KnownProxies { get; } = new List() { IPAddress.IPv6Loopback }; + + /// + /// Address ranges of known proxies to accept forwarded headers from. + /// + public IList KnownNetworks { get; } = new List() { new IPNetwork(IPAddress.Loopback, 8) }; + } +} diff --git a/src/Microsoft.AspNetCore.HttpOverrides/IPNetwork.cs b/src/Microsoft.AspNetCore.HttpOverrides/IPNetwork.cs new file mode 100644 index 0000000000..034e5754b6 --- /dev/null +++ b/src/Microsoft.AspNetCore.HttpOverrides/IPNetwork.cs @@ -0,0 +1,67 @@ +// 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; + +namespace Microsoft.AspNetCore.HttpOverrides +{ + public class IPNetwork + { + public IPNetwork(IPAddress prefix, int prefixLength) + { + Prefix = prefix; + PrefixLength = prefixLength; + PrefixBytes = Prefix.GetAddressBytes(); + Mask = CreateMask(); + } + + public IPAddress Prefix { get; } + + private byte[] PrefixBytes { get; } + + /// + /// The CIDR notation of the subnet mask + /// + public int PrefixLength { get; } + + private byte[] Mask { get; } + + public bool Contains(IPAddress address) + { + if (Prefix.AddressFamily != address.AddressFamily) + { + return false; + } + + var addressBytes = address.GetAddressBytes(); + for (int i = 0; i < PrefixBytes.Length && Mask[i] != 0; i++) + { + if (PrefixBytes[i] != (addressBytes[i] & Mask[i])) + { + return false; + } + } + + return true; + } + + private byte[] CreateMask() + { + var mask = new byte[PrefixBytes.Length]; + int remainingBits = PrefixLength; + int i = 0; + while (remainingBits >= 8) + { + mask[i] = 0xFF; + i++; + remainingBits -= 8; + } + if (remainingBits > 0) + { + mask[i] = (byte)(0xFF << (8 - remainingBits)); + } + + return mask; + } + } +} diff --git a/src/Microsoft.AspNetCore.HttpOverrides/IPEndPointParser.cs b/src/Microsoft.AspNetCore.HttpOverrides/Internal/IPEndPointParser.cs similarity index 97% rename from src/Microsoft.AspNetCore.HttpOverrides/IPEndPointParser.cs rename to src/Microsoft.AspNetCore.HttpOverrides/Internal/IPEndPointParser.cs index 9bdd0a66cf..d33b44e72b 100644 --- a/src/Microsoft.AspNetCore.HttpOverrides/IPEndPointParser.cs +++ b/src/Microsoft.AspNetCore.HttpOverrides/Internal/IPEndPointParser.cs @@ -3,7 +3,7 @@ using System.Net; -namespace Microsoft.AspNetCore.HttpOverrides +namespace Microsoft.AspNetCore.HttpOverrides.Internal { public static class IPEndPointParser { diff --git a/src/Microsoft.AspNetCore.HttpOverrides/OverrideHeaderMiddleware.cs b/src/Microsoft.AspNetCore.HttpOverrides/OverrideHeaderMiddleware.cs deleted file mode 100644 index e23a883031..0000000000 --- a/src/Microsoft.AspNetCore.HttpOverrides/OverrideHeaderMiddleware.cs +++ /dev/null @@ -1,107 +0,0 @@ -// 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; -using System.Net; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Http; -using Microsoft.Extensions.Options; - -namespace Microsoft.AspNetCore.HttpOverrides -{ - public class OverrideHeaderMiddleware - { - private const string XForwardedForHeaderName = "X-Forwarded-For"; - private const string XForwardedHostHeaderName = "X-Forwarded-Host"; - private const string XForwardedProtoHeaderName = "X-Forwarded-Proto"; - private const string XOriginalForName = "X-Original-For"; - private const string XOriginalHostName = "X-Original-Host"; - private const string XOriginalProtoName = "X-Original-Proto"; - private readonly OverrideHeaderOptions _options; - private readonly RequestDelegate _next; - - public OverrideHeaderMiddleware(RequestDelegate next, IOptions options) - { - if (next == null) - { - throw new ArgumentNullException(nameof(next)); - } - if (options == null) - { - throw new ArgumentNullException(nameof(options)); - } - - _options = options.Value; - _next = next; - } - - public Task Invoke(HttpContext context) - { - UpdateRemoteIp(context); - - UpdateHost(context); - - UpdateScheme(context); - - return _next(context); - } - - private void UpdateRemoteIp(HttpContext context) - { - if ((_options.ForwardedOptions & ForwardedHeaders.XForwardedFor) != 0) - { - var xForwardedForHeaderValue = context.Request.Headers.GetCommaSeparatedValues(XForwardedForHeaderName); - if (xForwardedForHeaderValue != null && xForwardedForHeaderValue.Length > 0) - { - IPEndPoint endpoint; - if (IPEndPointParser.TryParse(xForwardedForHeaderValue[0], out endpoint)) - { - var connection = context.Connection; - var remoteIP = connection.RemoteIpAddress; - if (remoteIP != null) - { - var remoteIPString = new IPEndPoint(remoteIP, connection.RemotePort).ToString(); - context.Request.Headers[XOriginalForName] = remoteIPString; - } - connection.RemoteIpAddress = endpoint.Address; - connection.RemotePort = endpoint.Port; - } - } - } - } - - private void UpdateHost(HttpContext context) - { - if ((_options.ForwardedOptions & ForwardedHeaders.XForwardedHost) != 0) - { - var xForwardHostHeaderValue = context.Request.Headers[XForwardedHostHeaderName]; - if (!string.IsNullOrEmpty(xForwardHostHeaderValue)) - { - var hostString = context.Request.Host.ToString(); - if (!string.IsNullOrEmpty(hostString)) - { - context.Request.Headers[XOriginalHostName] = hostString; - } - context.Request.Host = HostString.FromUriComponent(xForwardHostHeaderValue); - } - } - } - - private void UpdateScheme(HttpContext context) - { - if ((_options.ForwardedOptions & ForwardedHeaders.XForwardedProto) != 0) - { - var xForwardProtoHeaderValue = context.Request.Headers[XForwardedProtoHeaderName]; - if (!string.IsNullOrEmpty(xForwardProtoHeaderValue)) - { - if (!string.IsNullOrEmpty(context.Request.Scheme)) - { - context.Request.Headers[XOriginalProtoName] = context.Request.Scheme; - } - context.Request.Scheme = xForwardProtoHeaderValue; - } - } - } - } -} diff --git a/src/Microsoft.AspNetCore.HttpOverrides/OverrideHeaderOptions.cs b/src/Microsoft.AspNetCore.HttpOverrides/OverrideHeaderOptions.cs deleted file mode 100644 index 011c564813..0000000000 --- a/src/Microsoft.AspNetCore.HttpOverrides/OverrideHeaderOptions.cs +++ /dev/null @@ -1,12 +0,0 @@ -// 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 Microsoft.AspNetCore.HttpOverrides; - -namespace Microsoft.AspNetCore.Builder -{ - public class OverrideHeaderOptions - { - public ForwardedHeaders ForwardedOptions { get; set; } - } -} diff --git a/src/Microsoft.AspNetCore.HttpOverrides/project.json b/src/Microsoft.AspNetCore.HttpOverrides/project.json index 78d4310cab..a37a16f335 100644 --- a/src/Microsoft.AspNetCore.HttpOverrides/project.json +++ b/src/Microsoft.AspNetCore.HttpOverrides/project.json @@ -1,5 +1,5 @@ { - "version": "0.1.0-*", + "version": "1.0.0-*", "compilationOptions": { "warningsAsErrors": true, "keyFile": "../../tools/Key.snk" @@ -11,6 +11,7 @@ }, "dependencies": { "Microsoft.AspNetCore.Http.Extensions": "1.0.0-*", + "Microsoft.Extensions.Logging.Abstractions": "1.0.0-*", "Microsoft.Extensions.Options": "1.0.0-*" }, "frameworks": { diff --git a/test/Microsoft.AspNetCore.HttpOverrides.Tests/ForwardedHeadersMiddlewareTest.cs b/test/Microsoft.AspNetCore.HttpOverrides.Tests/ForwardedHeadersMiddlewareTest.cs new file mode 100644 index 0000000000..6632a1bba6 --- /dev/null +++ b/test/Microsoft.AspNetCore.HttpOverrides.Tests/ForwardedHeadersMiddlewareTest.cs @@ -0,0 +1,522 @@ +// 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.Linq; +using System.Net; +using System.Net.Http; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.TestHost; +using Xunit; + +namespace Microsoft.AspNetCore.HttpOverrides +{ + public class ForwardedHeadersMiddlewareTests + { + [Fact] + public async Task XForwardedForDefaultSettingsChangeRemoteIpAndPort() + { + var assertsExecuted = false; + + var builder = new WebHostBuilder() + .Configure(app => + { + app.UseForwardedHeaders(new ForwardedHeadersOptions + { + ForwardedHeaders = ForwardedHeaders.XForwardedFor + }); + app.Run(context => + { + Assert.Equal("11.111.111.11", context.Connection.RemoteIpAddress.ToString()); + Assert.Equal(9090, context.Connection.RemotePort); + // No Original set if RemoteIpAddress started null. + Assert.False(context.Request.Headers.ContainsKey("X-Original-For")); + // Should have been consumed and removed + Assert.False(context.Request.Headers.ContainsKey("X-Forwarded-For")); + assertsExecuted = true; + return Task.FromResult(0); + }); + }); + var server = new TestServer(builder); + + var req = new HttpRequestMessage(HttpMethod.Get, ""); + req.Headers.Add("X-Forwarded-For", "11.111.111.11:9090"); + await server.CreateClient().SendAsync(req); + Assert.True(assertsExecuted); + } + + [Theory] + [InlineData(1, "11.111.111.11.12345", "10.0.0.1", 99)] // Invalid + public async Task XForwardedForFirstValueIsInvalid(int limit, string header, string expectedIp, int expectedPort) + { + var assertsExecuted = false; + + var builder = new WebHostBuilder() + .Configure(app => + { + app.Use((context, next) => + { + context.Connection.RemoteIpAddress = IPAddress.Parse("10.0.0.1"); + context.Connection.RemotePort = 99; + return next(); + }); + app.UseForwardedHeaders(new ForwardedHeadersOptions + { + ForwardedHeaders = ForwardedHeaders.XForwardedFor, + ForwardLimit = limit, + }); + app.Run(context => + { + Assert.Equal(expectedIp, context.Connection.RemoteIpAddress.ToString()); + Assert.Equal(expectedPort, context.Connection.RemotePort); + Assert.False(context.Request.Headers.ContainsKey("X-Original-For")); + Assert.True(context.Request.Headers.ContainsKey("X-Forwarded-For")); + Assert.Equal(header, context.Request.Headers["X-Forwarded-For"]); + assertsExecuted = true; + return Task.FromResult(0); + }); + }); + var server = new TestServer(builder); + + var req = new HttpRequestMessage(HttpMethod.Get, ""); + req.Headers.TryAddWithoutValidation("X-Forwarded-For", header); + await server.CreateClient().SendAsync(req); + Assert.True(assertsExecuted); + } + + [Theory] + [InlineData(1, "11.111.111.11:12345", "11.111.111.11", 12345, "")] + [InlineData(10, "11.111.111.11:12345", "11.111.111.11", 12345, "")] + [InlineData(1, "12.112.112.12:23456, 11.111.111.11:12345", "11.111.111.11", 12345, "12.112.112.12:23456")] + [InlineData(2, "12.112.112.12:23456, 11.111.111.11:12345", "12.112.112.12", 23456, "")] + [InlineData(10, "12.112.112.12:23456, 11.111.111.11:12345", "12.112.112.12", 23456, "")] + [InlineData(10, "12.112.112.12.23456, 11.111.111.11:12345", "10.0.0.1", 99, "12.112.112.12.23456, 11.111.111.11:12345")] // Invalid + [InlineData(10, "13.113.113.13:34567, 12.112.112.12.23456, 11.111.111.11:12345", "10.0.0.1", 99, + "13.113.113.13:34567, 12.112.112.12.23456, 11.111.111.11:12345")] // Invalid + [InlineData(2, "13.113.113.13:34567, 12.112.112.12:23456, 11.111.111.11:12345", "12.112.112.12", 23456, "13.113.113.13:34567")] + [InlineData(3, "13.113.113.13:34567, 12.112.112.12:23456, 11.111.111.11:12345", "13.113.113.13", 34567, "")] + public async Task XForwardedForForwardLimit(int limit, string header, string expectedIp, int expectedPort, string remainingHeader) + { + var assertsExecuted = false; + + var builder = new WebHostBuilder() + .Configure(app => + { + app.Use((context, next) => + { + context.Connection.RemoteIpAddress = IPAddress.Parse("10.0.0.1"); + context.Connection.RemotePort = 99; + return next(); + }); + var options = new ForwardedHeadersOptions + { + ForwardedHeaders = ForwardedHeaders.XForwardedFor, + ForwardLimit = limit, + }; + options.KnownProxies.Clear(); + options.KnownNetworks.Clear(); + app.UseForwardedHeaders(options); + app.Run(context => + { + Assert.Equal(expectedIp, context.Connection.RemoteIpAddress.ToString()); + Assert.Equal(expectedPort, context.Connection.RemotePort); + Assert.Equal(remainingHeader, context.Request.Headers["X-Forwarded-For"].ToString()); + assertsExecuted = true; + return Task.FromResult(0); + }); + }); + var server = new TestServer(builder); + + var req = new HttpRequestMessage(HttpMethod.Get, ""); + req.Headers.TryAddWithoutValidation("X-Forwarded-For", header); + await server.CreateClient().SendAsync(req); + Assert.True(assertsExecuted); + } + + [Theory] + [InlineData("11.111.111.11", false)] + [InlineData("127.0.0.1", true)] + [InlineData("127.0.1.1", true)] + [InlineData("::1", true)] + [InlineData("::", false)] + public async Task XForwardedForLoopback(string originalIp, bool expectForwarded) + { + var assertsExecuted = false; + + var builder = new WebHostBuilder() + .Configure(app => + { + app.Use((context, next) => + { + context.Connection.RemoteIpAddress = IPAddress.Parse(originalIp); + context.Connection.RemotePort = 99; + return next(); + }); + app.UseForwardedHeaders(new ForwardedHeadersOptions + { + ForwardedHeaders = ForwardedHeaders.XForwardedFor, + }); + app.Run(context => + { + if (expectForwarded) + { + Assert.Equal("10.0.0.1", context.Connection.RemoteIpAddress.ToString()); + Assert.Equal(1234, context.Connection.RemotePort); + Assert.True(context.Request.Headers.ContainsKey("X-Original-For")); + Assert.Equal(new IPEndPoint(IPAddress.Parse(originalIp), 99).ToString(), + context.Request.Headers["X-Original-For"]); + } + else + { + Assert.Equal(originalIp, context.Connection.RemoteIpAddress.ToString()); + Assert.Equal(99, context.Connection.RemotePort); + Assert.False(context.Request.Headers.ContainsKey("X-Original-For")); + } + assertsExecuted = true; + return Task.FromResult(0); + }); + }); + var server = new TestServer(builder); + + var req = new HttpRequestMessage(HttpMethod.Get, ""); + req.Headers.TryAddWithoutValidation("X-Forwarded-For", "10.0.0.1:1234"); + await server.CreateClient().SendAsync(req); + Assert.True(assertsExecuted); + } + + [Theory] + [InlineData(1, "11.111.111.11:12345", "20.0.0.1", "10.0.0.1", 99)] + [InlineData(1, "", "10.0.0.1", "10.0.0.1", 99)] + [InlineData(1, "11.111.111.11:12345", "10.0.0.1", "11.111.111.11", 12345)] + [InlineData(1, "12.112.112.12:23456, 11.111.111.11:12345", "10.0.0.1", "11.111.111.11", 12345)] + [InlineData(2, "12.112.112.12:23456, 11.111.111.11:12345", "10.0.0.1", "11.111.111.11", 12345)] + [InlineData(1, "12.112.112.12:23456, 11.111.111.11:12345", "10.0.0.1,11.111.111.11", "11.111.111.11", 12345)] + [InlineData(2, "12.112.112.12:23456, 11.111.111.11:12345", "10.0.0.1,11.111.111.11", "12.112.112.12", 23456)] + [InlineData(1, "12.112.112.12:23456, 11.111.111.11:12345", "10.0.0.1,11.111.111.11,12.112.112.12", "11.111.111.11", 12345)] + [InlineData(2, "12.112.112.12:23456, 11.111.111.11:12345", "10.0.0.1,11.111.111.11,12.112.112.12", "12.112.112.12", 23456)] + [InlineData(3, "13.113.113.13:34567, 12.112.112.12:23456, 11.111.111.11:12345", "10.0.0.1,11.111.111.11,12.112.112.12", "13.113.113.13", 34567)] + [InlineData(3, "13.113.113.13:34567, 12.112.112.12;23456, 11.111.111.11:12345", "10.0.0.1,11.111.111.11,12.112.112.12", "10.0.0.1", 99)] // Invalid 2nd IP + [InlineData(3, "13.113.113.13;34567, 12.112.112.12:23456, 11.111.111.11:12345", "10.0.0.1,11.111.111.11,12.112.112.12", "10.0.0.1", 99)] // Invalid 3rd IP + public async Task XForwardedForForwardKnownIps(int limit, string header, string knownIPs, string expectedIp, int expectedPort) + { + var assertsExecuted = false; + + var builder = new WebHostBuilder() + .Configure(app => + { + app.Use((context, next) => + { + context.Connection.RemoteIpAddress = IPAddress.Parse("10.0.0.1"); + context.Connection.RemotePort = 99; + return next(); + }); + var options = new ForwardedHeadersOptions + { + ForwardedHeaders = ForwardedHeaders.XForwardedFor, + ForwardLimit = limit, + }; + foreach (var ip in knownIPs.Split(',').Select(text => IPAddress.Parse(text))) + { + options.KnownProxies.Add(ip); + } + app.UseForwardedHeaders(options); + app.Run(context => + { + Assert.Equal(expectedIp, context.Connection.RemoteIpAddress.ToString()); + Assert.Equal(expectedPort, context.Connection.RemotePort); + assertsExecuted = true; + return Task.FromResult(0); + }); + }); + var server = new TestServer(builder); + + var req = new HttpRequestMessage(HttpMethod.Get, ""); + req.Headers.TryAddWithoutValidation("X-Forwarded-For", header); + await server.CreateClient().SendAsync(req); + Assert.True(assertsExecuted); + } + + [Fact] + public async Task XForwardedForOverrideBadIpDoesntChangeRemoteIp() + { + var assertsExecuted = false; + + var builder = new WebHostBuilder() + .Configure(app => + { + app.UseForwardedHeaders(new ForwardedHeadersOptions + { + ForwardedHeaders = ForwardedHeaders.XForwardedFor + }); + app.Run(context => + { + Assert.Null(context.Connection.RemoteIpAddress); + assertsExecuted = true; + return Task.FromResult(0); + }); + }); + var server = new TestServer(builder); + + var req = new HttpRequestMessage(HttpMethod.Get, ""); + req.Headers.Add("X-Forwarded-For", "BAD-IP"); + await server.CreateClient().SendAsync(req); + Assert.True(assertsExecuted); + } + + [Fact] + public async Task XForwardedHostOverrideChangesRequestHost() + { + var assertsExecuted = false; + + var builder = new WebHostBuilder() + .Configure(app => + { + app.UseForwardedHeaders(new ForwardedHeadersOptions + { + ForwardedHeaders = ForwardedHeaders.XForwardedHost + }); + app.Run(context => + { + Assert.Equal("testhost", context.Request.Host.ToString()); + assertsExecuted = true; + return Task.FromResult(0); + }); + }); + var server = new TestServer(builder); + + var req = new HttpRequestMessage(HttpMethod.Get, ""); + req.Headers.Add("X-Forwarded-Host", "testhost"); + await server.CreateClient().SendAsync(req); + Assert.True(assertsExecuted); + } + + [Theory] + [InlineData(0, "h1", "http")] + [InlineData(1, "", "http")] + [InlineData(1, "h1", "h1")] + [InlineData(3, "h1", "h1")] + [InlineData(1, "h2, h1", "h1")] + [InlineData(2, "h2, h1", "h2")] + [InlineData(10, "h3, h2, h1", "h3")] + public async Task XForwardedProtoOverrideChangesRequestProtocol(int limit, string header, string expected) + { + var assertsExecuted = false; + + var builder = new WebHostBuilder() + .Configure(app => + { + app.UseForwardedHeaders(new ForwardedHeadersOptions + { + ForwardedHeaders = ForwardedHeaders.XForwardedProto, + ForwardLimit = limit, + }); + app.Run(context => + { + Assert.Equal(expected, context.Request.Scheme); + assertsExecuted = true; + return Task.FromResult(0); + }); + }); + var server = new TestServer(builder); + + var req = new HttpRequestMessage(HttpMethod.Get, ""); + req.Headers.Add("X-Forwarded-Proto", header); + await server.CreateClient().SendAsync(req); + Assert.True(assertsExecuted); + } + + [Theory] + [InlineData(0, "h1", "::1", "http")] + [InlineData(1, "", "::1", "http")] + [InlineData(1, "h1", "::1", "h1")] + [InlineData(3, "h1", "::1", "h1")] + [InlineData(3, "h2, h1", "::1", "http")] + [InlineData(5, "h2, h1", "::1, ::1", "h2")] + [InlineData(10, "h3, h2, h1", "::1, ::1, ::1", "h3")] + [InlineData(10, "h3, h2, h1", "::1, badip, ::1", "http")] + public async Task XForwardedProtoOverrideLimitedByXForwardedForCount(int limit, string protoHeader, string forHeader, string expected) + { + var assertsExecuted = false; + + var builder = new WebHostBuilder() + .Configure(app => + { + app.UseForwardedHeaders(new ForwardedHeadersOptions + { + ForwardedHeaders = ForwardedHeaders.XForwardedProto | ForwardedHeaders.XForwardedFor, + ForwardLimit = limit, + }); + app.Run(context => + { + Assert.Equal(expected, context.Request.Scheme); + assertsExecuted = true; + return Task.FromResult(0); + }); + }); + var server = new TestServer(builder); + + var req = new HttpRequestMessage(HttpMethod.Get, ""); + req.Headers.Add("X-Forwarded-Proto", protoHeader); + req.Headers.Add("X-Forwarded-For", forHeader); + await server.CreateClient().SendAsync(req); + Assert.True(assertsExecuted); + } + + [Theory] + [InlineData("", "", "::1", false, "http")] + [InlineData("h1", "", "::1", false, "http")] + [InlineData("h1", "F::", "::1", false, "h1")] + [InlineData("h1", "F::", "E::", false, "h1")] + [InlineData("", "", "::1", true, "http")] + [InlineData("h1", "", "::1", true, "http")] + [InlineData("h1", "F::", "::1", true, "h1")] + [InlineData("h1", "", "F::", true, "http")] + [InlineData("h1", "E::", "F::", true, "http")] + [InlineData("h2, h1", "", "::1", true, "http")] + [InlineData("h2, h1", "F::, D::", "::1", true, "h1")] + [InlineData("h2, h1", "E::, D::", "F::", true, "http")] + [InlineData("h2, h1", "E::, D::", "F::", true, "http")] + public async Task XForwardedProtoOverrideLimitedByLoopback(string protoHeader, string forHeader, string remoteIp, bool loopback, string expected) + { + var assertsExecuted = false; + + var builder = new WebHostBuilder() + .Configure(app => + { + app.Use((context, next) => + { + context.Connection.RemoteIpAddress = IPAddress.Parse(remoteIp); + return next(); + }); + var options = new ForwardedHeadersOptions + { + ForwardedHeaders = ForwardedHeaders.XForwardedProto | ForwardedHeaders.XForwardedFor, + ForwardLimit = 5, + }; + if (!loopback) + { + options.KnownNetworks.Clear(); + options.KnownProxies.Clear(); + } + app.UseForwardedHeaders(options); + app.Run(context => + { + Assert.Equal(expected, context.Request.Scheme); + assertsExecuted = true; + return Task.FromResult(0); + }); + }); + var server = new TestServer(builder); + + var req = new HttpRequestMessage(HttpMethod.Get, ""); + req.Headers.Add("X-Forwarded-Proto", protoHeader); + req.Headers.Add("X-Forwarded-For", forHeader); + await server.CreateClient().SendAsync(req); + Assert.True(assertsExecuted); + } + + [Fact] + public void AllForwardsDisabledByDefault() + { + var options = new ForwardedHeadersOptions(); + Assert.True(options.ForwardedHeaders == ForwardedHeaders.None); + Assert.Equal(1, options.ForwardLimit); + Assert.Equal(1, options.KnownNetworks.Count()); + Assert.Equal(1, options.KnownProxies.Count()); + } + + [Fact] + public async Task AllForwardsEnabledChangeRequestRemoteIpHostandProtocol() + { + var assertsExecuted = false; + + var builder = new WebHostBuilder() + .Configure(app => + { + app.UseForwardedHeaders(new ForwardedHeadersOptions + { + ForwardedHeaders = ForwardedHeaders.All + }); + app.Run(context => + { + Assert.Equal("11.111.111.11", context.Connection.RemoteIpAddress.ToString()); + Assert.Equal("testhost", context.Request.Host.ToString()); + Assert.Equal("Protocol", context.Request.Scheme); + assertsExecuted = true; + return Task.FromResult(0); + }); + }); + var server = new TestServer(builder); + + var req = new HttpRequestMessage(HttpMethod.Get, ""); + req.Headers.Add("X-Forwarded-For", "11.111.111.11"); + req.Headers.Add("X-Forwarded-Host", "testhost"); + req.Headers.Add("X-Forwarded-Proto", "Protocol"); + await server.CreateClient().SendAsync(req); + Assert.True(assertsExecuted); + } + + [Fact] + public async Task AllOptionsDisabledRequestDoesntChange() + { + var assertsExecuted = false; + + var builder = new WebHostBuilder() + .Configure(app => + { + app.UseForwardedHeaders(new ForwardedHeadersOptions + { + ForwardedHeaders = ForwardedHeaders.None + }); + app.Run(context => + { + Assert.Null(context.Connection.RemoteIpAddress); + Assert.Equal("localhost", context.Request.Host.ToString()); + Assert.Equal("http", context.Request.Scheme); + assertsExecuted = true; + return Task.FromResult(0); + }); + }); + var server = new TestServer(builder); + + var req = new HttpRequestMessage(HttpMethod.Get, ""); + req.Headers.Add("X-Forwarded-For", "11.111.111.11"); + req.Headers.Add("X-Forwarded-Host", "otherhost"); + req.Headers.Add("X-Forwarded-Proto", "Protocol"); + await server.CreateClient().SendAsync(req); + Assert.True(assertsExecuted); + } + + [Fact] + public async Task PartiallyEnabledForwardsPartiallyChangesRequest() + { + var assertsExecuted = false; + + var builder = new WebHostBuilder() + .Configure(app => + { + app.UseForwardedHeaders(new ForwardedHeadersOptions + { + ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto + }); + app.Run(context => + { + Assert.Equal("11.111.111.11", context.Connection.RemoteIpAddress.ToString()); + Assert.Equal("localhost", context.Request.Host.ToString()); + Assert.Equal("Protocol", context.Request.Scheme); + assertsExecuted = true; + return Task.FromResult(0); + + }); + }); + var server = new TestServer(builder); + + var req = new HttpRequestMessage(HttpMethod.Get, ""); + req.Headers.Add("X-Forwarded-For", "11.111.111.11"); + req.Headers.Add("X-Forwarded-Proto", "Protocol"); + await server.CreateClient().SendAsync(req); + Assert.True(assertsExecuted); + } + } +} diff --git a/test/Microsoft.AspNetCore.HttpOverrides.Tests/IPEndPointParserTest.cs b/test/Microsoft.AspNetCore.HttpOverrides.Tests/IPEndPointParserTest.cs index 0ba8e134ee..f5106bd2a7 100644 --- a/test/Microsoft.AspNetCore.HttpOverrides.Tests/IPEndPointParserTest.cs +++ b/test/Microsoft.AspNetCore.HttpOverrides.Tests/IPEndPointParserTest.cs @@ -4,7 +4,7 @@ using System.Net; using Xunit; -namespace Microsoft.AspNetCore.HttpOverrides +namespace Microsoft.AspNetCore.HttpOverrides.Internal { public class IPEndPointParserTests { diff --git a/test/Microsoft.AspNetCore.HttpOverrides.Tests/IPNetworkTest.cs b/test/Microsoft.AspNetCore.HttpOverrides.Tests/IPNetworkTest.cs new file mode 100644 index 0000000000..b3700c583f --- /dev/null +++ b/test/Microsoft.AspNetCore.HttpOverrides.Tests/IPNetworkTest.cs @@ -0,0 +1,33 @@ +// 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 Xunit; + +namespace Microsoft.AspNetCore.HttpOverrides +{ + public class IPNetworkTest + { + [Theory] + [InlineData("10.1.1.0", 8, "10.1.1.10")] + [InlineData("174.0.0.0", 7, "175.1.1.10")] + [InlineData("10.174.0.0", 15, "10.175.1.10")] + [InlineData("10.168.0.0", 14, "10.171.1.10")] + public void Contains_Positive(string prefixText, int length, string addressText) + { + var network = new IPNetwork(IPAddress.Parse(prefixText), length); + Assert.True(network.Contains(IPAddress.Parse(addressText))); + } + + [Theory] + [InlineData("10.1.0.0", 16, "10.2.1.10")] + [InlineData("174.0.0.0", 7, "173.1.1.10")] + [InlineData("10.174.0.0", 15, "10.173.1.10")] + [InlineData("10.168.0.0", 14, "10.172.1.10")] + public void Contains_Negative(string prefixText, int length, string addressText) + { + var network = new IPNetwork(IPAddress.Parse(prefixText), length); + Assert.False(network.Contains(IPAddress.Parse(addressText))); + } + } +} diff --git a/test/Microsoft.AspNetCore.HttpOverrides.Tests/OverrideHeaderMiddlewareTest.cs b/test/Microsoft.AspNetCore.HttpOverrides.Tests/OverrideHeaderMiddlewareTest.cs deleted file mode 100644 index b66e57e2cd..0000000000 --- a/test/Microsoft.AspNetCore.HttpOverrides.Tests/OverrideHeaderMiddlewareTest.cs +++ /dev/null @@ -1,223 +0,0 @@ -// 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.Http; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Hosting; -using Microsoft.AspNetCore.TestHost; -using Xunit; - -namespace Microsoft.AspNetCore.HttpOverrides -{ - public class OverrideMiddlewareHeaderTests - { - [Fact] - public async Task XForwardedForOverrideChangesRemoteIp() - { - var assertsExecuted = false; - - var builder = new WebHostBuilder() - .Configure(app => - { - app.UseOverrideHeaders(new OverrideHeaderOptions - { - ForwardedOptions = ForwardedHeaders.XForwardedFor - }); - app.Run(context => - { - Assert.Equal("11.111.111.11", context.Connection.RemoteIpAddress.ToString()); - assertsExecuted = true; - return Task.FromResult(0); - }); - }); - var server = new TestServer(builder); - - var req = new HttpRequestMessage(HttpMethod.Get, ""); - req.Headers.Add("X-Forwarded-For", "11.111.111.11"); - await server.CreateClient().SendAsync(req); - Assert.True(assertsExecuted); - } - - [Fact] - public async Task XForwardedForOverrideBadIpDoesntChangeRemoteIp() - { - var assertsExecuted = false; - - var builder = new WebHostBuilder() - .Configure(app => - { - app.UseOverrideHeaders(new OverrideHeaderOptions - { - ForwardedOptions = ForwardedHeaders.XForwardedFor - }); - app.Run(context => - { - Assert.Null(context.Connection.RemoteIpAddress); - assertsExecuted = true; - return Task.FromResult(0); - }); - }); - var server = new TestServer(builder); - - var req = new HttpRequestMessage(HttpMethod.Get, ""); - req.Headers.Add("X-Forwarded-For", "BAD-IP"); - await server.CreateClient().SendAsync(req); - Assert.True(assertsExecuted); - } - - [Fact] - public async Task XForwardedHostOverrideChangesRequestHost() - { - var assertsExecuted = false; - - var builder = new WebHostBuilder() - .Configure(app => - { - app.UseOverrideHeaders(new OverrideHeaderOptions - { - ForwardedOptions = ForwardedHeaders.XForwardedHost - }); - app.Run(context => - { - Assert.Equal("testhost", context.Request.Host.ToString()); - assertsExecuted = true; - return Task.FromResult(0); - }); - }); - var server = new TestServer(builder); - - var req = new HttpRequestMessage(HttpMethod.Get, ""); - req.Headers.Add("X-Forwarded-Host", "testhost"); - await server.CreateClient().SendAsync(req); - Assert.True(assertsExecuted); - } - - [Fact] - public async Task XForwardedProtoOverrideChangesRequestProtocol() - { - var assertsExecuted = false; - - var builder = new WebHostBuilder() - .Configure(app => - { - app.UseOverrideHeaders(new OverrideHeaderOptions - { - ForwardedOptions = ForwardedHeaders.XForwardedProto - }); - app.Run(context => - { - Assert.Equal("TestProtocol", context.Request.Scheme); - assertsExecuted = true; - return Task.FromResult(0); - }); - }); - var server = new TestServer(builder); - - var req = new HttpRequestMessage(HttpMethod.Get, ""); - req.Headers.Add("X-Forwarded-Proto", "TestProtocol"); - await server.CreateClient().SendAsync(req); - Assert.True(assertsExecuted); - } - - [Fact] - public void AllForwardsDisabledByDefault() - { - var options = new OverrideHeaderOptions(); - Assert.True(options.ForwardedOptions == 0); - } - - [Fact] - public async Task AllForwardsEnabledChangeRequestRemoteIpHostandProtocol() - { - var assertsExecuted = false; - - var builder = new WebHostBuilder() - .Configure(app => - { - app.UseOverrideHeaders(new OverrideHeaderOptions - { - ForwardedOptions = ForwardedHeaders.All - }); - app.Run(context => - { - Assert.Equal("11.111.111.11", context.Connection.RemoteIpAddress.ToString()); - Assert.Equal("testhost", context.Request.Host.ToString()); - Assert.Equal("Protocol", context.Request.Scheme); - assertsExecuted = true; - return Task.FromResult(0); - }); - }); - var server = new TestServer(builder); - - var req = new HttpRequestMessage(HttpMethod.Get, ""); - req.Headers.Add("X-Forwarded-For", "11.111.111.11"); - req.Headers.Add("X-Forwarded-Host", "testhost"); - req.Headers.Add("X-Forwarded-Proto", "Protocol"); - await server.CreateClient().SendAsync(req); - Assert.True(assertsExecuted); - } - - [Fact] - public async Task AllOptionsDisabledRequestDoesntChange() - { - var assertsExecuted = false; - - var builder = new WebHostBuilder() - .Configure(app => - { - app.UseOverrideHeaders(new OverrideHeaderOptions - { - ForwardedOptions = ForwardedHeaders.None - }); - app.Run(context => - { - Assert.Null(context.Connection.RemoteIpAddress); - Assert.Equal("localhost", context.Request.Host.ToString()); - Assert.Equal("http", context.Request.Scheme); - assertsExecuted = true; - return Task.FromResult(0); - }); - }); - var server = new TestServer(builder); - - var req = new HttpRequestMessage(HttpMethod.Get, ""); - req.Headers.Add("X-Forwarded-For", "11.111.111.11"); - req.Headers.Add("X-Forwarded-Host", "otherhost"); - req.Headers.Add("X-Forwarded-Proto", "Protocol"); - await server.CreateClient().SendAsync(req); - Assert.True(assertsExecuted); - } - - [Fact] - public async Task PartiallyEnabledForwardsPartiallyChangesRequest() - { - var assertsExecuted = false; - - var builder = new WebHostBuilder() - .Configure(app => - { - app.UseOverrideHeaders(new OverrideHeaderOptions - { - ForwardedOptions = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto - }); - app.Run(context => - { - Assert.Equal("11.111.111.11", context.Connection.RemoteIpAddress.ToString()); - Assert.Equal("localhost", context.Request.Host.ToString()); - Assert.Equal("Protocol", context.Request.Scheme); - assertsExecuted = true; - return Task.FromResult(0); - - }); - }); - var server = new TestServer(builder); - - var req = new HttpRequestMessage(HttpMethod.Get, ""); - req.Headers.Add("X-Forwarded-For", "11.111.111.11"); - req.Headers.Add("X-Forwarded-Proto", "Protocol"); - await server.CreateClient().SendAsync(req); - Assert.True(assertsExecuted); - } - } -} diff --git a/test/Microsoft.AspNetCore.HttpOverrides.Tests/project.json b/test/Microsoft.AspNetCore.HttpOverrides.Tests/project.json index 107fcfb6ab..2729c1bed4 100644 --- a/test/Microsoft.AspNetCore.HttpOverrides.Tests/project.json +++ b/test/Microsoft.AspNetCore.HttpOverrides.Tests/project.json @@ -4,7 +4,7 @@ "warningsAsErrors": true }, "dependencies": { - "Microsoft.AspNetCore.HttpOverrides": "0.1.0-*", + "Microsoft.AspNetCore.HttpOverrides": "1.0.0-*", "Microsoft.AspNetCore.TestHost": "1.0.0-*", "Microsoft.Extensions.Logging.Testing": "1.0.0-*", "xunit": "2.1.0" From 6f5e764e871af770d512525d86e8bd4bf13d06ee Mon Sep 17 00:00:00 2001 From: John Luo Date: Tue, 2 Feb 2016 17:38:22 -0800 Subject: [PATCH 042/307] Updating to new CLI --- samples/HttpOverridesSample/project.json | 3 ++- samples/ResponseBufferingSample/project.json | 3 ++- test/Microsoft.AspNetCore.Buffering.Tests/project.json | 4 +++- test/Microsoft.AspNetCore.HttpOverrides.Tests/project.json | 4 +++- 4 files changed, 10 insertions(+), 4 deletions(-) diff --git a/samples/HttpOverridesSample/project.json b/samples/HttpOverridesSample/project.json index 6f7515973c..21d4956fae 100644 --- a/samples/HttpOverridesSample/project.json +++ b/samples/HttpOverridesSample/project.json @@ -6,7 +6,8 @@ "dependencies": { "Microsoft.AspNetCore.HttpOverrides": "1.0.0-*", "Microsoft.AspNetCore.IISPlatformHandler": "1.0.0-*", - "Microsoft.AspNetCore.Server.Kestrel": "1.0.0-*" + "Microsoft.AspNetCore.Server.Kestrel": "1.0.0-*", + "Microsoft.NETCore.Platforms": "1.0.1-*" }, "commands": { "web": "HttpOverridesSample" diff --git a/samples/ResponseBufferingSample/project.json b/samples/ResponseBufferingSample/project.json index 3c5ff7f44f..ec19f8549d 100644 --- a/samples/ResponseBufferingSample/project.json +++ b/samples/ResponseBufferingSample/project.json @@ -3,7 +3,8 @@ "dependencies": { "Microsoft.AspNetCore.Buffering": "0.1.0-*", "Microsoft.AspNetCore.IISPlatformHandler": "1.0.0-*", - "Microsoft.AspNetCore.Server.Kestrel": "1.0.0-*" + "Microsoft.AspNetCore.Server.Kestrel": "1.0.0-*", + "Microsoft.NETCore.Platforms": "1.0.1-*" }, "compilationOptions": { "emitEntryPoint": true diff --git a/test/Microsoft.AspNetCore.Buffering.Tests/project.json b/test/Microsoft.AspNetCore.Buffering.Tests/project.json index 64d93344ae..ad1b716655 100644 --- a/test/Microsoft.AspNetCore.Buffering.Tests/project.json +++ b/test/Microsoft.AspNetCore.Buffering.Tests/project.json @@ -6,6 +6,7 @@ "dependencies": { "Microsoft.AspNetCore.Buffering": "0.1.0-*", "Microsoft.AspNetCore.TestHost": "1.0.0-*", + "Microsoft.NETCore.Platforms": "1.0.1-*", "xunit": "2.1.0" }, "frameworks": { @@ -21,7 +22,8 @@ "dnxcore50": { "dependencies": { "xunit.runner.aspnet": "2.0.0-aspnet-*" - } + }, + "imports": "portable-net451+win8" } }, "testRunner": "xunit", diff --git a/test/Microsoft.AspNetCore.HttpOverrides.Tests/project.json b/test/Microsoft.AspNetCore.HttpOverrides.Tests/project.json index 2729c1bed4..a407964d8e 100644 --- a/test/Microsoft.AspNetCore.HttpOverrides.Tests/project.json +++ b/test/Microsoft.AspNetCore.HttpOverrides.Tests/project.json @@ -7,6 +7,7 @@ "Microsoft.AspNetCore.HttpOverrides": "1.0.0-*", "Microsoft.AspNetCore.TestHost": "1.0.0-*", "Microsoft.Extensions.Logging.Testing": "1.0.0-*", + "Microsoft.NETCore.Platforms": "1.0.1-*", "xunit": "2.1.0" }, "frameworks": { @@ -22,7 +23,8 @@ "dnxcore50": { "dependencies": { "xunit.runner.aspnet": "2.0.0-aspnet-*" - } + }, + "imports": "portable-net451+win8" } }, "testRunner": "xunit", From b8bc1e2d46eadb6c8f5dd8f6d4d92d96113c81e2 Mon Sep 17 00:00:00 2001 From: Hisham Bin Ateya Date: Thu, 4 Feb 2016 14:34:01 +0300 Subject: [PATCH 043/307] Add 'UseServer' --- samples/HttpOverridesSample/Startup.cs | 1 + samples/HttpOverridesSample/hosting.json | 3 --- samples/ResponseBufferingSample/Startup.cs | 1 + samples/ResponseBufferingSample/hosting.json | 3 --- 4 files changed, 2 insertions(+), 6 deletions(-) delete mode 100644 samples/HttpOverridesSample/hosting.json delete mode 100644 samples/ResponseBufferingSample/hosting.json diff --git a/samples/HttpOverridesSample/Startup.cs b/samples/HttpOverridesSample/Startup.cs index 9cacb60dc1..7e1af1eedc 100644 --- a/samples/HttpOverridesSample/Startup.cs +++ b/samples/HttpOverridesSample/Startup.cs @@ -34,6 +34,7 @@ namespace HttpOverridesSample { var host = new WebHostBuilder() .UseDefaultConfiguration(args) + .UseServer("Microsoft.AspNetCore.Server.Kestrel") .UseIISPlatformHandlerUrl() .UseStartup() .Build(); diff --git a/samples/HttpOverridesSample/hosting.json b/samples/HttpOverridesSample/hosting.json deleted file mode 100644 index 6a93dbafa8..0000000000 --- a/samples/HttpOverridesSample/hosting.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "server": "Microsoft.AspNetCore.Server.Kestrel" -} diff --git a/samples/ResponseBufferingSample/Startup.cs b/samples/ResponseBufferingSample/Startup.cs index 5679fe7566..1db4d55b9f 100644 --- a/samples/ResponseBufferingSample/Startup.cs +++ b/samples/ResponseBufferingSample/Startup.cs @@ -39,6 +39,7 @@ namespace ResponseBufferingSample { var host = new WebHostBuilder() .UseDefaultConfiguration(args) + .UseServer("Microsoft.AspNetCore.Server.Kestrel") .UseIISPlatformHandlerUrl() .UseStartup() .Build(); diff --git a/samples/ResponseBufferingSample/hosting.json b/samples/ResponseBufferingSample/hosting.json deleted file mode 100644 index 6a93dbafa8..0000000000 --- a/samples/ResponseBufferingSample/hosting.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "server": "Microsoft.AspNetCore.Server.Kestrel" -} From d1a5ce82c0aaf4c9e087df2edadc197e5d56ff4f Mon Sep 17 00:00:00 2001 From: Kiran Challa Date: Tue, 9 Feb 2016 23:36:14 -0800 Subject: [PATCH 044/307] Enable tests to use dotnet xunit runner --- .../project.json | 17 +++++++---------- .../project.json | 17 +++++++---------- 2 files changed, 14 insertions(+), 20 deletions(-) diff --git a/test/Microsoft.AspNetCore.Buffering.Tests/project.json b/test/Microsoft.AspNetCore.Buffering.Tests/project.json index ad1b716655..86c7d79dc6 100644 --- a/test/Microsoft.AspNetCore.Buffering.Tests/project.json +++ b/test/Microsoft.AspNetCore.Buffering.Tests/project.json @@ -10,6 +10,12 @@ "xunit": "2.1.0" }, "frameworks": { + "dnxcore50": { + "dependencies": { + "dotnet-test-xunit": "1.0.0-dev-*" + }, + "imports": "portable-net451+win8" + }, "dnx451": { "frameworkAssemblies": { "System.Runtime": "", @@ -18,16 +24,7 @@ "dependencies": { "xunit.runner.console": "2.1.0" } - }, - "dnxcore50": { - "dependencies": { - "xunit.runner.aspnet": "2.0.0-aspnet-*" - }, - "imports": "portable-net451+win8" } }, - "testRunner": "xunit", - "commands": { - "test": "xunit.runner.aspnet" - } + "testRunner": "xunit" } \ No newline at end of file diff --git a/test/Microsoft.AspNetCore.HttpOverrides.Tests/project.json b/test/Microsoft.AspNetCore.HttpOverrides.Tests/project.json index a407964d8e..acf2728d41 100644 --- a/test/Microsoft.AspNetCore.HttpOverrides.Tests/project.json +++ b/test/Microsoft.AspNetCore.HttpOverrides.Tests/project.json @@ -11,6 +11,12 @@ "xunit": "2.1.0" }, "frameworks": { + "dnxcore50": { + "dependencies": { + "dotnet-test-xunit": "1.0.0-dev-*" + }, + "imports": "portable-net451+win8" + }, "dnx451": { "frameworkAssemblies": { "System.Runtime": "", @@ -19,16 +25,7 @@ "dependencies": { "xunit.runner.console": "2.1.0" } - }, - "dnxcore50": { - "dependencies": { - "xunit.runner.aspnet": "2.0.0-aspnet-*" - }, - "imports": "portable-net451+win8" } }, - "testRunner": "xunit", - "commands": { - "test": "xunit.runner.aspnet" - } + "testRunner": "xunit" } \ No newline at end of file From 8eb737a459ef75ed7a86b7fed99fd69e0d7094f5 Mon Sep 17 00:00:00 2001 From: Ajay Bhargav Baaskaran Date: Wed, 17 Feb 2016 12:27:23 -0800 Subject: [PATCH 045/307] Enabled xml doc generation --- NuGetPackageVerifier.json | 14 ++------------ src/Microsoft.AspNetCore.Buffering/project.json | 4 +++- .../HttpMethodOverrideExtensions.cs | 4 +--- .../project.json | 4 +++- 4 files changed, 9 insertions(+), 17 deletions(-) diff --git a/NuGetPackageVerifier.json b/NuGetPackageVerifier.json index 9cc45712f0..0895735cea 100644 --- a/NuGetPackageVerifier.json +++ b/NuGetPackageVerifier.json @@ -1,12 +1,7 @@ { "adx": { // Packages written by the ADX team and that ship on NuGet.org "rules": [ - "AssemblyHasDocumentFileRule", - "AssemblyHasVersionAttributesRule", - "AssemblyHasServicingAttributeRule", - "AssemblyHasNeutralResourcesLanguageAttributeRule", - "SatellitePackageRule", - "StrictSemanticVersionValidationRule" + "AdxVerificationCompositeRule" ], "packages": { "Microsoft.AspNetCore.Buffering": { }, @@ -15,12 +10,7 @@ }, "Default": { // Rules to run for packages not listed in any other set. "rules": [ - "AssemblyHasDocumentFileRule", - "AssemblyHasVersionAttributesRule", - "AssemblyHasServicingAttributeRule", - "AssemblyHasNeutralResourcesLanguageAttributeRule", - "SatellitePackageRule", - "StrictSemanticVersionValidationRule" + "DefaultCompositeRule" ] } } \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Buffering/project.json b/src/Microsoft.AspNetCore.Buffering/project.json index 6ea212875a..f2b16827c5 100644 --- a/src/Microsoft.AspNetCore.Buffering/project.json +++ b/src/Microsoft.AspNetCore.Buffering/project.json @@ -2,7 +2,9 @@ "version": "0.1.0-*", "compilationOptions": { "warningsAsErrors": true, - "keyFile": "../../tools/Key.snk" + "keyFile": "../../tools/Key.snk", + "nowarn": [ "CS1591" ], + "xmlDoc": true }, "description": "ASP.NET middleware for buffering response bodies.", "repository": { diff --git a/src/Microsoft.AspNetCore.HttpOverrides/HttpMethodOverrideExtensions.cs b/src/Microsoft.AspNetCore.HttpOverrides/HttpMethodOverrideExtensions.cs index 7ad3ecf31a..c33d3cceae 100644 --- a/src/Microsoft.AspNetCore.HttpOverrides/HttpMethodOverrideExtensions.cs +++ b/src/Microsoft.AspNetCore.HttpOverrides/HttpMethodOverrideExtensions.cs @@ -13,7 +13,6 @@ namespace Microsoft.AspNetCore.Builder /// Allows incoming POST request to override method type with type specified in header. /// /// - /// public static IApplicationBuilder UseHttpMethodOverride(this IApplicationBuilder builder) { if (builder == null) @@ -28,8 +27,7 @@ namespace Microsoft.AspNetCore.Builder /// Allows incoming POST request to override method type with type specified in form. /// /// - /// Denotes the element that contains the name of the resulting method type. - /// + /// The . public static IApplicationBuilder UseHttpMethodOverride(this IApplicationBuilder builder, HttpMethodOverrideOptions options) { if (builder == null) diff --git a/src/Microsoft.AspNetCore.HttpOverrides/project.json b/src/Microsoft.AspNetCore.HttpOverrides/project.json index a37a16f335..659a4da10f 100644 --- a/src/Microsoft.AspNetCore.HttpOverrides/project.json +++ b/src/Microsoft.AspNetCore.HttpOverrides/project.json @@ -2,7 +2,9 @@ "version": "1.0.0-*", "compilationOptions": { "warningsAsErrors": true, - "keyFile": "../../tools/Key.snk" + "keyFile": "../../tools/Key.snk", + "nowarn": [ "CS1591" ], + "xmlDoc": true }, "description": "XForward and Method override middlewares for ASP.NET", "repository": { From 55f1d41e080bfc0901faae60586878c2175fef7b Mon Sep 17 00:00:00 2001 From: Ajay Bhargav Baaskaran Date: Wed, 17 Feb 2016 14:45:57 -0800 Subject: [PATCH 046/307] Updated missed doc comment --- .../HttpMethodOverrideExtensions.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Microsoft.AspNetCore.HttpOverrides/HttpMethodOverrideExtensions.cs b/src/Microsoft.AspNetCore.HttpOverrides/HttpMethodOverrideExtensions.cs index c33d3cceae..425a27adc2 100644 --- a/src/Microsoft.AspNetCore.HttpOverrides/HttpMethodOverrideExtensions.cs +++ b/src/Microsoft.AspNetCore.HttpOverrides/HttpMethodOverrideExtensions.cs @@ -12,7 +12,7 @@ namespace Microsoft.AspNetCore.Builder /// /// Allows incoming POST request to override method type with type specified in header. /// - /// + /// The instance this method extends. public static IApplicationBuilder UseHttpMethodOverride(this IApplicationBuilder builder) { if (builder == null) @@ -26,7 +26,7 @@ namespace Microsoft.AspNetCore.Builder /// /// Allows incoming POST request to override method type with type specified in form. /// - /// + /// The instance this method extends. /// The . public static IApplicationBuilder UseHttpMethodOverride(this IApplicationBuilder builder, HttpMethodOverrideOptions options) { From ea1e9dd01876908aeb55761372518b0e51c56ea6 Mon Sep 17 00:00:00 2001 From: John Luo Date: Thu, 18 Feb 2016 16:01:04 -0800 Subject: [PATCH 047/307] Updating test TFMs for custom test discovery --- test/Microsoft.AspNetCore.Buffering.Tests/project.json | 4 ++-- test/Microsoft.AspNetCore.HttpOverrides.Tests/project.json | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/test/Microsoft.AspNetCore.Buffering.Tests/project.json b/test/Microsoft.AspNetCore.Buffering.Tests/project.json index 86c7d79dc6..6799b57cda 100644 --- a/test/Microsoft.AspNetCore.Buffering.Tests/project.json +++ b/test/Microsoft.AspNetCore.Buffering.Tests/project.json @@ -16,7 +16,7 @@ }, "imports": "portable-net451+win8" }, - "dnx451": { + "net451": { "frameworkAssemblies": { "System.Runtime": "", "System.Threading.Tasks": "" @@ -27,4 +27,4 @@ } }, "testRunner": "xunit" -} \ No newline at end of file +} diff --git a/test/Microsoft.AspNetCore.HttpOverrides.Tests/project.json b/test/Microsoft.AspNetCore.HttpOverrides.Tests/project.json index acf2728d41..b9ef66bd53 100644 --- a/test/Microsoft.AspNetCore.HttpOverrides.Tests/project.json +++ b/test/Microsoft.AspNetCore.HttpOverrides.Tests/project.json @@ -17,7 +17,7 @@ }, "imports": "portable-net451+win8" }, - "dnx451": { + "net451": { "frameworkAssemblies": { "System.Runtime": "", "System.Threading.Tasks": "" @@ -28,4 +28,4 @@ } }, "testRunner": "xunit" -} \ No newline at end of file +} From 77c42b25a148a10885789a722e7d771b0c4643c4 Mon Sep 17 00:00:00 2001 From: Doug Bunting Date: Wed, 24 Feb 2016 12:29:21 -0800 Subject: [PATCH 048/307] Update `build.cmd` to match latest template - aspnet/Universe#347 - `%KOREBUILD_VERSION%` doesn't work without this fix --- build.cmd | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/build.cmd b/build.cmd index ebb619e737..95b049cf63 100644 --- a/build.cmd +++ b/build.cmd @@ -2,7 +2,7 @@ SETLOCAL SET REPO_FOLDER=%~dp0 -CD %REPO_FOLDER% +CD "%REPO_FOLDER%" SET BUILD_FOLDER=.build SET KOREBUILD_FOLDER=%BUILD_FOLDER%\KoreBuild-dotnet @@ -28,12 +28,11 @@ IF NOT EXIST %NUGET_PATH% ( copy %CACHED_NUGET% %NUGET_PATH% > nul ) +SET KOREBUILD_DOWNLOAD_ARGS= +IF NOT "%KOREBUILD_VERSION%"=="" ( + SET KOREBUILD_DOWNLOAD_ARGS=-version %KOREBUILD_VERSION% +) IF NOT EXIST %KOREBUILD_FOLDER% ( - SET KOREBUILD_DOWNLOAD_ARGS= - IF NOT "%KOREBUILD_VERSION%"=="" ( - SET KOREBUILD_DOWNLOAD_ARGS=-version %KOREBUILD_VERSION% - ) - %BUILD_FOLDER%\nuget.exe install KoreBuild-dotnet -ExcludeVersion -o %BUILD_FOLDER% -nocache -pre %KOREBUILD_DOWNLOAD_ARGS% ) From c99746264d86cbffc08b35e6760aeeae75030142 Mon Sep 17 00:00:00 2001 From: Victor Hurdugaci Date: Sat, 27 Feb 2016 12:51:15 -0800 Subject: [PATCH 049/307] Update the build scripts --- build.cmd | 41 ++----------------------------------- build.ps1 | 36 +++++++++++++++++++++++++++++++++ build.sh | 60 +++++++++++++++++++++++-------------------------------- 3 files changed, 63 insertions(+), 74 deletions(-) create mode 100644 build.ps1 diff --git a/build.cmd b/build.cmd index 95b049cf63..2fa024b15e 100644 --- a/build.cmd +++ b/build.cmd @@ -1,39 +1,2 @@ -@ECHO off -SETLOCAL - -SET REPO_FOLDER=%~dp0 -CD "%REPO_FOLDER%" - -SET BUILD_FOLDER=.build -SET KOREBUILD_FOLDER=%BUILD_FOLDER%\KoreBuild-dotnet -SET KOREBUILD_VERSION= - -SET NUGET_PATH=%BUILD_FOLDER%\NuGet.exe -SET NUGET_VERSION=latest -SET CACHED_NUGET=%LocalAppData%\NuGet\nuget.%NUGET_VERSION%.exe - -IF NOT EXIST %BUILD_FOLDER% ( - md %BUILD_FOLDER% -) - -IF NOT EXIST %NUGET_PATH% ( - IF NOT EXIST %CACHED_NUGET% ( - echo Downloading latest version of NuGet.exe... - IF NOT EXIST %LocalAppData%\NuGet ( - md %LocalAppData%\NuGet - ) - @powershell -NoProfile -ExecutionPolicy unrestricted -Command "$ProgressPreference = 'SilentlyContinue'; Invoke-WebRequest 'https://dist.nuget.org/win-x86-commandline/%NUGET_VERSION%/nuget.exe' -OutFile '%CACHED_NUGET%'" - ) - - copy %CACHED_NUGET% %NUGET_PATH% > nul -) - -SET KOREBUILD_DOWNLOAD_ARGS= -IF NOT "%KOREBUILD_VERSION%"=="" ( - SET KOREBUILD_DOWNLOAD_ARGS=-version %KOREBUILD_VERSION% -) -IF NOT EXIST %KOREBUILD_FOLDER% ( - %BUILD_FOLDER%\nuget.exe install KoreBuild-dotnet -ExcludeVersion -o %BUILD_FOLDER% -nocache -pre %KOREBUILD_DOWNLOAD_ARGS% -) - -"%KOREBUILD_FOLDER%\build\KoreBuild.cmd" %* +@ECHO OFF +PowerShell -NoProfile -NoLogo -ExecutionPolicy unrestricted -Command "[System.Threading.Thread]::CurrentThread.CurrentCulture = ''; [System.Threading.Thread]::CurrentThread.CurrentUICulture = '';& '%~dp0build.ps1' %*" \ No newline at end of file diff --git a/build.ps1 b/build.ps1 new file mode 100644 index 0000000000..4fd24a30d5 --- /dev/null +++ b/build.ps1 @@ -0,0 +1,36 @@ +cd $PSScriptRoot + +$repoFolder = $PSScriptRoot +$env:REPO_FOLDER = $repoFolder + +$koreBuildZip="https://github.com/aspnet/KoreBuild/archive/dev.zip" +if ($env:KOREBUILD_ZIP) +{ + $koreBuildZip=$env:KOREBUILD_ZIP +} + +$buildFolder = ".build" +$buildFile="$buildFolder\KoreBuild.ps1" + +if (!(Test-Path $buildFolder)) { + Write-Host "Downloading KoreBuild from $koreBuildZip" + + $tempFolder=$env:TEMP + "\KoreBuild-" + [guid]::NewGuid() + New-Item -Path "$tempFolder" -Type directory | Out-Null + + $localZipFile="$tempFolder\korebuild.zip" + + Invoke-WebRequest $koreBuildZip -OutFile $localZipFile + Add-Type -AssemblyName System.IO.Compression.FileSystem + [System.IO.Compression.ZipFile]::ExtractToDirectory($localZipFile, $tempFolder) + + New-Item -Path "$buildFolder" -Type directory | Out-Null + copy-item "$tempFolder\**\build\*" $buildFolder -Recurse + + # Cleanup + if (Test-Path $tempFolder) { + Remove-Item -Recurse -Force $tempFolder + } +} + +&"$buildFile" $args \ No newline at end of file diff --git a/build.sh b/build.sh index 263fb667a8..79638d06b6 100755 --- a/build.sh +++ b/build.sh @@ -1,45 +1,35 @@ #!/usr/bin/env bash +repoFolder="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" +cd $repoFolder -buildFolder=.build -koreBuildFolder=$buildFolder/KoreBuild-dotnet - -nugetPath=$buildFolder/nuget.exe - -if test `uname` = Darwin; then - cachedir=~/Library/Caches/KBuild -else - if [ -z $XDG_DATA_HOME ]; then - cachedir=$HOME/.local/share - else - cachedir=$XDG_DATA_HOME; - fi +koreBuildZip="https://github.com/aspnet/KoreBuild/archive/dev.zip" +if [ ! -z $KOREBUILD_ZIP ]; then + koreBuildZip=$KOREBUILD_ZIP fi -mkdir -p $cachedir -nugetVersion=latest -cacheNuget=$cachedir/nuget.$nugetVersion.exe -nugetUrl=https://dist.nuget.org/win-x86-commandline/$nugetVersion/nuget.exe +buildFolder=".build" +buildFile="$buildFolder/KoreBuild.sh" if test ! -d $buildFolder; then + echo "Downloading KoreBuild from $koreBuildZip" + + tempFolder="/tmp/KoreBuild-$(uuidgen)" + mkdir $tempFolder + + localZipFile="$tempFolder/korebuild.zip" + + wget -O $localZipFile $koreBuildZip 2>/dev/null || curl -o $localZipFile --location $koreBuildZip /dev/null + unzip -q -d $tempFolder $localZipFile + mkdir $buildFolder -fi - -if test ! -f $nugetPath; then - if test ! -f $cacheNuget; then - wget -O $cacheNuget $nugetUrl 2>/dev/null || curl -o $cacheNuget --location $nugetUrl /dev/null + cp -r $tempFolder/**/build/** $buildFolder + + chmod +x $buildFile + + # Cleanup + if test ! -d $tempFolder; then + rm -rf $tempFolder fi - - cp $cacheNuget $nugetPath fi -if test ! -d $koreBuildFolder; then - mono $nugetPath install KoreBuild-dotnet -ExcludeVersion -o $buildFolder -nocache -pre - chmod +x $koreBuildFolder/build/KoreBuild.sh -fi - -makeFile=makefile.shade -if [ ! -e $makeFile ]; then - makeFile=$koreBuildFolder/build/makefile.shade -fi - -./$koreBuildFolder/build/KoreBuild.sh -n $nugetPath -m $makeFile "$@" +$buildFile -r $repoFolder "$@" From 2ee543d8a236cbf11f98e83b6774f0d2fb9986f3 Mon Sep 17 00:00:00 2001 From: Victor Hurdugaci Date: Sun, 28 Feb 2016 10:12:18 -0800 Subject: [PATCH 050/307] Return the error code from build.cmd --- build.cmd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.cmd b/build.cmd index 2fa024b15e..7d4894cb4a 100644 --- a/build.cmd +++ b/build.cmd @@ -1,2 +1,2 @@ @ECHO OFF -PowerShell -NoProfile -NoLogo -ExecutionPolicy unrestricted -Command "[System.Threading.Thread]::CurrentThread.CurrentCulture = ''; [System.Threading.Thread]::CurrentThread.CurrentUICulture = '';& '%~dp0build.ps1' %*" \ No newline at end of file +PowerShell -NoProfile -NoLogo -ExecutionPolicy unrestricted -Command "[System.Threading.Thread]::CurrentThread.CurrentCulture = ''; [System.Threading.Thread]::CurrentThread.CurrentUICulture = '';& '%~dp0build.ps1' %*; exit $LASTEXITCODE" \ No newline at end of file From 7c60ec6fa5cd856e2a0e54b385e37bf79c8c3d65 Mon Sep 17 00:00:00 2001 From: "N. Taylor Mullen" Date: Tue, 1 Mar 2016 13:38:47 -0800 Subject: [PATCH 051/307] Transition to netstandard. - dotnet5.X => netstandard1.y (where y = x-1). - DNXCore50 => netstandardapp1.5. - Applied the same changes to ifdefs. --- samples/HttpOverridesSample/project.json | 8 ++++++-- samples/ResponseBufferingSample/project.json | 6 +++++- .../BufferingWriteStream.cs | 2 +- src/Microsoft.AspNetCore.Buffering/project.json | 10 ++++++++-- src/Microsoft.AspNetCore.HttpOverrides/project.json | 10 ++++++++-- test/Microsoft.AspNetCore.Buffering.Tests/project.json | 9 ++++++--- .../project.json | 9 ++++++--- 7 files changed, 40 insertions(+), 14 deletions(-) diff --git a/samples/HttpOverridesSample/project.json b/samples/HttpOverridesSample/project.json index 21d4956fae..364757c139 100644 --- a/samples/HttpOverridesSample/project.json +++ b/samples/HttpOverridesSample/project.json @@ -14,7 +14,11 @@ }, "frameworks": { "dnx451": {}, - "dnxcore50": {} + "netstandardapp1.5": { + "imports": [ + "dnxcore50" + ] + } }, "exclude": [ "wwwroot", @@ -24,4 +28,4 @@ "**.user", "**.vspscc" ] -} +} \ No newline at end of file diff --git a/samples/ResponseBufferingSample/project.json b/samples/ResponseBufferingSample/project.json index ec19f8549d..66ef9da258 100644 --- a/samples/ResponseBufferingSample/project.json +++ b/samples/ResponseBufferingSample/project.json @@ -14,7 +14,11 @@ }, "frameworks": { "dnx451": {}, - "dnxcore50": {} + "netstandardapp1.5": { + "imports": [ + "dnxcore50" + ] + } }, "publishExclude": [ "node_modules", diff --git a/src/Microsoft.AspNetCore.Buffering/BufferingWriteStream.cs b/src/Microsoft.AspNetCore.Buffering/BufferingWriteStream.cs index 999e05088e..9de26d9271 100644 --- a/src/Microsoft.AspNetCore.Buffering/BufferingWriteStream.cs +++ b/src/Microsoft.AspNetCore.Buffering/BufferingWriteStream.cs @@ -159,7 +159,7 @@ namespace Microsoft.AspNetCore.Buffering return _innerStream.WriteAsync(buffer, offset, count, cancellationToken); } } -#if !DOTNET5_4 +#if !NETSTANDARD1_3 public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object state) { if (_isBuffering) diff --git a/src/Microsoft.AspNetCore.Buffering/project.json b/src/Microsoft.AspNetCore.Buffering/project.json index f2b16827c5..8bc0487179 100644 --- a/src/Microsoft.AspNetCore.Buffering/project.json +++ b/src/Microsoft.AspNetCore.Buffering/project.json @@ -3,7 +3,9 @@ "compilationOptions": { "warningsAsErrors": true, "keyFile": "../../tools/Key.snk", - "nowarn": [ "CS1591" ], + "nowarn": [ + "CS1591" + ], "xmlDoc": true }, "description": "ASP.NET middleware for buffering response bodies.", @@ -16,6 +18,10 @@ }, "frameworks": { "net451": {}, - "dotnet5.4": {} + "netstandard1.3": { + "imports": [ + "dotnet5.4" + ] + } } } \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.HttpOverrides/project.json b/src/Microsoft.AspNetCore.HttpOverrides/project.json index 659a4da10f..20ff74debc 100644 --- a/src/Microsoft.AspNetCore.HttpOverrides/project.json +++ b/src/Microsoft.AspNetCore.HttpOverrides/project.json @@ -3,7 +3,9 @@ "compilationOptions": { "warningsAsErrors": true, "keyFile": "../../tools/Key.snk", - "nowarn": [ "CS1591" ], + "nowarn": [ + "CS1591" + ], "xmlDoc": true }, "description": "XForward and Method override middlewares for ASP.NET", @@ -18,6 +20,10 @@ }, "frameworks": { "net451": {}, - "dotnet5.4": {} + "netstandard1.3": { + "imports": [ + "dotnet5.4" + ] + } } } \ No newline at end of file diff --git a/test/Microsoft.AspNetCore.Buffering.Tests/project.json b/test/Microsoft.AspNetCore.Buffering.Tests/project.json index 6799b57cda..ef8fb2810c 100644 --- a/test/Microsoft.AspNetCore.Buffering.Tests/project.json +++ b/test/Microsoft.AspNetCore.Buffering.Tests/project.json @@ -10,11 +10,14 @@ "xunit": "2.1.0" }, "frameworks": { - "dnxcore50": { + "netstandardapp1.5": { "dependencies": { "dotnet-test-xunit": "1.0.0-dev-*" }, - "imports": "portable-net451+win8" + "imports": [ + "dnxcore50", + "portable-net451+win8" + ] }, "net451": { "frameworkAssemblies": { @@ -27,4 +30,4 @@ } }, "testRunner": "xunit" -} +} \ No newline at end of file diff --git a/test/Microsoft.AspNetCore.HttpOverrides.Tests/project.json b/test/Microsoft.AspNetCore.HttpOverrides.Tests/project.json index b9ef66bd53..8961b4e095 100644 --- a/test/Microsoft.AspNetCore.HttpOverrides.Tests/project.json +++ b/test/Microsoft.AspNetCore.HttpOverrides.Tests/project.json @@ -11,11 +11,14 @@ "xunit": "2.1.0" }, "frameworks": { - "dnxcore50": { + "netstandardapp1.5": { "dependencies": { "dotnet-test-xunit": "1.0.0-dev-*" }, - "imports": "portable-net451+win8" + "imports": [ + "dnxcore50", + "portable-net451+win8" + ] }, "net451": { "frameworkAssemblies": { @@ -28,4 +31,4 @@ } }, "testRunner": "xunit" -} +} \ No newline at end of file From be0905bf4e82bc64426fa72767fa701f51bd83c8 Mon Sep 17 00:00:00 2001 From: Doug Bunting Date: Wed, 2 Mar 2016 15:30:51 -0800 Subject: [PATCH 052/307] Remove project name from output path - aspnet/Coherence-Signed#187 - remove `` settings but maintain other unique aspects e.g. `` - in a few cases, standardize on VS version `14.0` and not something more specific --- samples/HttpOverridesSample/HttpOverridesSample.xproj | 7 ++----- .../ResponseBufferingSample.xproj | 3 +-- .../Microsoft.AspNetCore.Buffering.xproj | 9 +++------ .../Microsoft.AspNetCore.HttpOverrides.xproj | 2 +- .../Microsoft.AspNetCore.Buffering.Tests.xproj | 5 ++--- .../Microsoft.AspNetCore.HttpOverrides.Tests.xproj | 2 +- 6 files changed, 10 insertions(+), 18 deletions(-) diff --git a/samples/HttpOverridesSample/HttpOverridesSample.xproj b/samples/HttpOverridesSample/HttpOverridesSample.xproj index d7dd58a746..fc39e4566a 100644 --- a/samples/HttpOverridesSample/HttpOverridesSample.xproj +++ b/samples/HttpOverridesSample/HttpOverridesSample.xproj @@ -4,15 +4,12 @@ 14.0 $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - 7f95478d-e1d4-4a64-ba42-b041591a96eb - HttpOverridesSample ..\..\artifacts\obj\$(MSBuildProjectName) - ..\..\artifacts\bin\$(MSBuildProjectName)\ + ..\..\artifacts\bin\ - 2.0 @@ -22,4 +19,4 @@ - + \ No newline at end of file diff --git a/samples/ResponseBufferingSample/ResponseBufferingSample.xproj b/samples/ResponseBufferingSample/ResponseBufferingSample.xproj index 9026942e3d..485106b921 100644 --- a/samples/ResponseBufferingSample/ResponseBufferingSample.xproj +++ b/samples/ResponseBufferingSample/ResponseBufferingSample.xproj @@ -7,9 +7,8 @@ e5c55b80-7827-40eb-b661-32b0e0e431ca - ResponseBufferingSample ..\..\artifacts\obj\$(MSBuildProjectName) - ..\..\artifacts\bin\$(MSBuildProjectName)\ + ..\..\artifacts\bin\ 2.0 diff --git a/src/Microsoft.AspNetCore.Buffering/Microsoft.AspNetCore.Buffering.xproj b/src/Microsoft.AspNetCore.Buffering/Microsoft.AspNetCore.Buffering.xproj index b74126ea03..53319c86ce 100644 --- a/src/Microsoft.AspNetCore.Buffering/Microsoft.AspNetCore.Buffering.xproj +++ b/src/Microsoft.AspNetCore.Buffering/Microsoft.AspNetCore.Buffering.xproj @@ -1,20 +1,17 @@ - + 14.0 $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - 2363d0dd-a3bf-437e-9b64-b33ae132d875 - Microsoft.AspNetCore.Buffering ..\..\artifacts\obj\$(MSBuildProjectName) - ..\..\artifacts\bin\$(MSBuildProjectName)\ + ..\..\artifacts\bin\ - 2.0 - + \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.HttpOverrides/Microsoft.AspNetCore.HttpOverrides.xproj b/src/Microsoft.AspNetCore.HttpOverrides/Microsoft.AspNetCore.HttpOverrides.xproj index 0037db59b2..9020dedea8 100644 --- a/src/Microsoft.AspNetCore.HttpOverrides/Microsoft.AspNetCore.HttpOverrides.xproj +++ b/src/Microsoft.AspNetCore.HttpOverrides/Microsoft.AspNetCore.HttpOverrides.xproj @@ -8,7 +8,7 @@ 517308c3-b477-4b01-b461-cab9c10b6928 ..\..\artifacts\obj\$(MSBuildProjectName) - ..\..\artifacts\bin\$(MSBuildProjectName)\ + ..\..\artifacts\bin\ 2.0 diff --git a/test/Microsoft.AspNetCore.Buffering.Tests/Microsoft.AspNetCore.Buffering.Tests.xproj b/test/Microsoft.AspNetCore.Buffering.Tests/Microsoft.AspNetCore.Buffering.Tests.xproj index 322999a908..e4556bfec4 100644 --- a/test/Microsoft.AspNetCore.Buffering.Tests/Microsoft.AspNetCore.Buffering.Tests.xproj +++ b/test/Microsoft.AspNetCore.Buffering.Tests/Microsoft.AspNetCore.Buffering.Tests.xproj @@ -1,4 +1,4 @@ - + 14.0 @@ -7,9 +7,8 @@ f5f1d123-9c81-4a9e-8644-aa46b8e578fb - Microsoft.AspNetCore.Buffering.Tests ..\..\artifacts\obj\$(MSBuildProjectName) - ..\..\artifacts\bin\$(MSBuildProjectName)\ + ..\..\artifacts\bin\ 2.0 diff --git a/test/Microsoft.AspNetCore.HttpOverrides.Tests/Microsoft.AspNetCore.HttpOverrides.Tests.xproj b/test/Microsoft.AspNetCore.HttpOverrides.Tests/Microsoft.AspNetCore.HttpOverrides.Tests.xproj index 9889be51ad..ac56f6d1f2 100644 --- a/test/Microsoft.AspNetCore.HttpOverrides.Tests/Microsoft.AspNetCore.HttpOverrides.Tests.xproj +++ b/test/Microsoft.AspNetCore.HttpOverrides.Tests/Microsoft.AspNetCore.HttpOverrides.Tests.xproj @@ -8,7 +8,7 @@ d6341b92-3416-4f11-8df4-cb274296175f ..\..\artifacts\obj\$(MSBuildProjectName) - ..\..\artifacts\bin\$(MSBuildProjectName)\ + ..\..\artifacts\bin\ 2.0 From 327751690d16ba3793391880f9a774c90115741a Mon Sep 17 00:00:00 2001 From: Ajay Bhargav Baaskaran Date: Thu, 3 Mar 2016 17:33:39 -0800 Subject: [PATCH 053/307] Added Company, Copyright and Product attributes to AssemblyInfo --- .../Properties/AssemblyInfo.cs | 7 +++++-- .../Properties/AssemblyInfo.cs | 7 +++++-- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/Microsoft.AspNetCore.Buffering/Properties/AssemblyInfo.cs b/src/Microsoft.AspNetCore.Buffering/Properties/AssemblyInfo.cs index e0f545c6b5..76feceeff0 100644 --- a/src/Microsoft.AspNetCore.Buffering/Properties/AssemblyInfo.cs +++ b/src/Microsoft.AspNetCore.Buffering/Properties/AssemblyInfo.cs @@ -1,8 +1,11 @@ -// Copyright (c) .NET Foundation. All rights reserved. +// 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.Reflection; using System.Resources; [assembly: AssemblyMetadata("Serviceable", "True")] -[assembly: NeutralResourcesLanguage("en-us")] \ No newline at end of file +[assembly: NeutralResourcesLanguage("en-us")] +[assembly: AssemblyCompany("Microsoft Corporation.")] +[assembly: AssemblyCopyright("© Microsoft Corporation. All rights reserved.")] +[assembly: AssemblyProduct("Microsoft ASP.NET Core")] diff --git a/src/Microsoft.AspNetCore.HttpOverrides/Properties/AssemblyInfo.cs b/src/Microsoft.AspNetCore.HttpOverrides/Properties/AssemblyInfo.cs index e0f545c6b5..76feceeff0 100644 --- a/src/Microsoft.AspNetCore.HttpOverrides/Properties/AssemblyInfo.cs +++ b/src/Microsoft.AspNetCore.HttpOverrides/Properties/AssemblyInfo.cs @@ -1,8 +1,11 @@ -// Copyright (c) .NET Foundation. All rights reserved. +// 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.Reflection; using System.Resources; [assembly: AssemblyMetadata("Serviceable", "True")] -[assembly: NeutralResourcesLanguage("en-us")] \ No newline at end of file +[assembly: NeutralResourcesLanguage("en-us")] +[assembly: AssemblyCompany("Microsoft Corporation.")] +[assembly: AssemblyCopyright("© Microsoft Corporation. All rights reserved.")] +[assembly: AssemblyProduct("Microsoft ASP.NET Core")] From 9e7387a94100e5aa0057cfcbebf53cf0e5f1e930 Mon Sep 17 00:00:00 2001 From: Eilon Lipton Date: Sun, 6 Mar 2016 21:38:17 -0800 Subject: [PATCH 054/307] Fix package metadata --- README.md | 6 +++--- src/Microsoft.AspNetCore.Buffering/project.json | 9 +++++++-- src/Microsoft.AspNetCore.HttpOverrides/project.json | 10 ++++++++-- 3 files changed, 18 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 6293ff7ce2..4dfc5912ee 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ -ASP.NET Basic Middleware Components +ASP.NET Core Basic Middleware Components ======== -This repo hosts a collection of basic middleware components for ASP.NET 5. +This repo hosts a collection of basic middleware components for ASP.NET Core. -This project is part of ASP.NET 5. You can find samples, documentation and getting started instructions for ASP.NET 5 at the [Home](https://github.com/aspnet/home) repo. +This project is part of ASP.NET Core. You can find samples, documentation and getting started instructions for ASP.NET Core at the [Home](https://github.com/aspnet/home) repo. diff --git a/src/Microsoft.AspNetCore.Buffering/project.json b/src/Microsoft.AspNetCore.Buffering/project.json index 8bc0487179..83d05073ba 100644 --- a/src/Microsoft.AspNetCore.Buffering/project.json +++ b/src/Microsoft.AspNetCore.Buffering/project.json @@ -8,7 +8,12 @@ ], "xmlDoc": true }, - "description": "ASP.NET middleware for buffering response bodies.", + "description": "ASP.NET Core middleware for buffering response bodies.", + "tags": [ + "aspnetcore", + "buffer", + "buffering" + ], "repository": { "type": "git", "url": "git://github.com/aspnet/basicmiddleware" @@ -17,7 +22,7 @@ "Microsoft.AspNetCore.Http.Abstractions": "1.0.0-*" }, "frameworks": { - "net451": {}, + "net451": { }, "netstandard1.3": { "imports": [ "dotnet5.4" diff --git a/src/Microsoft.AspNetCore.HttpOverrides/project.json b/src/Microsoft.AspNetCore.HttpOverrides/project.json index 20ff74debc..da4b3587de 100644 --- a/src/Microsoft.AspNetCore.HttpOverrides/project.json +++ b/src/Microsoft.AspNetCore.HttpOverrides/project.json @@ -8,7 +8,13 @@ ], "xmlDoc": true }, - "description": "XForward and Method override middlewares for ASP.NET", + "description": "ASP.NET Core basic middleware for:\r\nX-Forwarded-* headers to forward headers from a proxy.\r\nHTTP method override header.", + "tags": [ + "aspnetcore", + "proxy", + "headers", + "xforwarded" + ], "repository": { "type": "git", "url": "git://github.com/aspnet/basicmiddleware" @@ -19,7 +25,7 @@ "Microsoft.Extensions.Options": "1.0.0-*" }, "frameworks": { - "net451": {}, + "net451": { }, "netstandard1.3": { "imports": [ "dotnet5.4" From 9a457c329a86c5eef2620f56582069d1eebd12ee Mon Sep 17 00:00:00 2001 From: Victor Hurdugaci Date: Mon, 7 Mar 2016 20:55:04 -0800 Subject: [PATCH 055/307] Update the build scripts to the latest version --- build.ps1 | 33 ++++++++++++++++++++++++++++++++- build.sh | 15 +++++++++++++-- 2 files changed, 45 insertions(+), 3 deletions(-) diff --git a/build.ps1 b/build.ps1 index 4fd24a30d5..8f2f99691a 100644 --- a/build.ps1 +++ b/build.ps1 @@ -1,3 +1,33 @@ +$ErrorActionPreference = "Stop" + +function DownloadWithRetry([string] $url, [string] $downloadLocation, [int] $retries) +{ + while($true) + { + try + { + Invoke-WebRequest $url -OutFile $downloadLocation + break + } + catch + { + $exceptionMessage = $_.Exception.Message + Write-Host "Failed to download '$url': $exceptionMessage" + if ($retries -gt 0) { + $retries-- + Write-Host "Waiting 10 seconds before retrying. Retries left: $retries" + Start-Sleep -Seconds 10 + + } + else + { + $exception = $_.Exception + throw $exception + } + } + } +} + cd $PSScriptRoot $repoFolder = $PSScriptRoot @@ -20,7 +50,8 @@ if (!(Test-Path $buildFolder)) { $localZipFile="$tempFolder\korebuild.zip" - Invoke-WebRequest $koreBuildZip -OutFile $localZipFile + DownloadWithRetry -url $koreBuildZip -downloadLocation $localZipFile -retries 6 + Add-Type -AssemblyName System.IO.Compression.FileSystem [System.IO.Compression.ZipFile]::ExtractToDirectory($localZipFile, $tempFolder) diff --git a/build.sh b/build.sh index 79638d06b6..f4208100eb 100755 --- a/build.sh +++ b/build.sh @@ -18,7 +18,18 @@ if test ! -d $buildFolder; then localZipFile="$tempFolder/korebuild.zip" - wget -O $localZipFile $koreBuildZip 2>/dev/null || curl -o $localZipFile --location $koreBuildZip /dev/null + retries=6 + until (wget -O $localZipFile $koreBuildZip 2>/dev/null || curl -o $localZipFile --location $koreBuildZip 2>/dev/null) + do + echo "Failed to download '$koreBuildZip'" + if [ "$retries" -le 0 ]; then + exit 1 + fi + retries=$((retries - 1)) + echo "Waiting 10 seconds before retrying. Retries left: $retries" + sleep 10s + done + unzip -q -d $tempFolder $localZipFile mkdir $buildFolder @@ -32,4 +43,4 @@ if test ! -d $buildFolder; then fi fi -$buildFile -r $repoFolder "$@" +$buildFile -r $repoFolder "$@" \ No newline at end of file From dcdffcbac171651f65b46d09b009f25bf789f604 Mon Sep 17 00:00:00 2001 From: Nate McMaster Date: Wed, 9 Mar 2016 16:35:09 -0800 Subject: [PATCH 056/307] Limit the branches that build on our public CI. [ci skip] --- .travis.yml | 6 ++++++ appveyor.yml | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/.travis.yml b/.travis.yml index bf811dc26a..dd4686f39c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -16,5 +16,11 @@ os: - linux - osx osx_image: xcode7.1 +branches: + only: + - master + - release + - dev + - /^(.*\\/)?ci-.*$/ script: - ./build.sh verify \ No newline at end of file diff --git a/appveyor.yml b/appveyor.yml index 3fab83e134..c6d5f7d997 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,5 +1,11 @@ init: - git config --global core.autocrlf true +branches: + only: + - master + - release + - dev + - /^(.*\\/)?ci-.*$/ build_script: - build.cmd verify clone_depth: 1 From a42e846ea9e52aed541c68d642a2a46ade914e18 Mon Sep 17 00:00:00 2001 From: Nate McMaster Date: Wed, 9 Mar 2016 17:44:49 -0800 Subject: [PATCH 057/307] Fix backslashes in yml config. [ci skip] --- .travis.yml | 2 +- appveyor.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index dd4686f39c..df22f7a880 100644 --- a/.travis.yml +++ b/.travis.yml @@ -21,6 +21,6 @@ branches: - master - release - dev - - /^(.*\\/)?ci-.*$/ + - /^(.*\/)?ci-.*$/ script: - ./build.sh verify \ No newline at end of file diff --git a/appveyor.yml b/appveyor.yml index c6d5f7d997..b9a9bcd1e6 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -5,7 +5,7 @@ branches: - master - release - dev - - /^(.*\\/)?ci-.*$/ + - /^(.*\/)?ci-.*$/ build_script: - build.cmd verify clone_depth: 1 From 3ffe4b5924d7a784a4068b394507d953ce038e9f Mon Sep 17 00:00:00 2001 From: Chris R Date: Fri, 18 Mar 2016 12:16:13 -0700 Subject: [PATCH 058/307] Remove IIS references to avoid circular dependency. --- .../HttpOverridesSample/Properties/launchSettings.json | 4 ++-- samples/HttpOverridesSample/Startup.cs | 2 +- samples/HttpOverridesSample/project.json | 1 - samples/HttpOverridesSample/wwwroot/web.config | 9 --------- samples/ResponseBufferingSample/Startup.cs | 2 +- samples/ResponseBufferingSample/project.json | 1 - samples/ResponseBufferingSample/wwwroot/web.config | 9 --------- 7 files changed, 4 insertions(+), 24 deletions(-) delete mode 100644 samples/HttpOverridesSample/wwwroot/web.config delete mode 100644 samples/ResponseBufferingSample/wwwroot/web.config diff --git a/samples/HttpOverridesSample/Properties/launchSettings.json b/samples/HttpOverridesSample/Properties/launchSettings.json index 553b782dd9..0cf4573d75 100644 --- a/samples/HttpOverridesSample/Properties/launchSettings.json +++ b/samples/HttpOverridesSample/Properties/launchSettings.json @@ -12,13 +12,13 @@ "commandName": "IISExpress", "launchBrowser": true, "environmentVariables": { - "ASPNET_ENVIRONMENT": "Development" + "ASPNETCORE_ENVIRONMENT": "Development" } }, "web": { "commandName": "web", "environmentVariables": { - "ASPNET_ENVIRONMENT": "Development" + "ASPNETCORE_ENVIRONMENT": "Development" } } } diff --git a/samples/HttpOverridesSample/Startup.cs b/samples/HttpOverridesSample/Startup.cs index 7e1af1eedc..c1023c7a5f 100644 --- a/samples/HttpOverridesSample/Startup.cs +++ b/samples/HttpOverridesSample/Startup.cs @@ -35,7 +35,7 @@ namespace HttpOverridesSample var host = new WebHostBuilder() .UseDefaultConfiguration(args) .UseServer("Microsoft.AspNetCore.Server.Kestrel") - .UseIISPlatformHandlerUrl() + // .UseIIS() // This repo can no longer reference IIS because IISIntegration depends on it. .UseStartup() .Build(); diff --git a/samples/HttpOverridesSample/project.json b/samples/HttpOverridesSample/project.json index 364757c139..4467913ce0 100644 --- a/samples/HttpOverridesSample/project.json +++ b/samples/HttpOverridesSample/project.json @@ -5,7 +5,6 @@ }, "dependencies": { "Microsoft.AspNetCore.HttpOverrides": "1.0.0-*", - "Microsoft.AspNetCore.IISPlatformHandler": "1.0.0-*", "Microsoft.AspNetCore.Server.Kestrel": "1.0.0-*", "Microsoft.NETCore.Platforms": "1.0.1-*" }, diff --git a/samples/HttpOverridesSample/wwwroot/web.config b/samples/HttpOverridesSample/wwwroot/web.config deleted file mode 100644 index 8485f6719f..0000000000 --- a/samples/HttpOverridesSample/wwwroot/web.config +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - diff --git a/samples/ResponseBufferingSample/Startup.cs b/samples/ResponseBufferingSample/Startup.cs index 1db4d55b9f..64c34bbf3a 100644 --- a/samples/ResponseBufferingSample/Startup.cs +++ b/samples/ResponseBufferingSample/Startup.cs @@ -40,7 +40,7 @@ namespace ResponseBufferingSample var host = new WebHostBuilder() .UseDefaultConfiguration(args) .UseServer("Microsoft.AspNetCore.Server.Kestrel") - .UseIISPlatformHandlerUrl() + // .UseIIS() // This repo can no longer reference IIS because IISIntegration depends on it. .UseStartup() .Build(); diff --git a/samples/ResponseBufferingSample/project.json b/samples/ResponseBufferingSample/project.json index 66ef9da258..766c0a3675 100644 --- a/samples/ResponseBufferingSample/project.json +++ b/samples/ResponseBufferingSample/project.json @@ -2,7 +2,6 @@ "version": "1.0.0-*", "dependencies": { "Microsoft.AspNetCore.Buffering": "0.1.0-*", - "Microsoft.AspNetCore.IISPlatformHandler": "1.0.0-*", "Microsoft.AspNetCore.Server.Kestrel": "1.0.0-*", "Microsoft.NETCore.Platforms": "1.0.1-*" }, diff --git a/samples/ResponseBufferingSample/wwwroot/web.config b/samples/ResponseBufferingSample/wwwroot/web.config deleted file mode 100644 index 9a0d90abf8..0000000000 --- a/samples/ResponseBufferingSample/wwwroot/web.config +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - \ No newline at end of file From 6b338232fd6ef2cd02f3917903e4b35dfbae0b57 Mon Sep 17 00:00:00 2001 From: John Luo Date: Tue, 22 Mar 2016 12:00:46 -0700 Subject: [PATCH 059/307] Reacting to Hosting changes --- samples/HttpOverridesSample/Startup.cs | 2 +- samples/ResponseBufferingSample/Startup.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/samples/HttpOverridesSample/Startup.cs b/samples/HttpOverridesSample/Startup.cs index c1023c7a5f..1d3286eff6 100644 --- a/samples/HttpOverridesSample/Startup.cs +++ b/samples/HttpOverridesSample/Startup.cs @@ -33,7 +33,7 @@ namespace HttpOverridesSample public static void Main(string[] args) { var host = new WebHostBuilder() - .UseDefaultConfiguration(args) + .UseDefaultHostingConfiguration(args) .UseServer("Microsoft.AspNetCore.Server.Kestrel") // .UseIIS() // This repo can no longer reference IIS because IISIntegration depends on it. .UseStartup() diff --git a/samples/ResponseBufferingSample/Startup.cs b/samples/ResponseBufferingSample/Startup.cs index 64c34bbf3a..945bfaa81a 100644 --- a/samples/ResponseBufferingSample/Startup.cs +++ b/samples/ResponseBufferingSample/Startup.cs @@ -38,7 +38,7 @@ namespace ResponseBufferingSample public static void Main(string[] args) { var host = new WebHostBuilder() - .UseDefaultConfiguration(args) + .UseDefaultHostingConfiguration(args) .UseServer("Microsoft.AspNetCore.Server.Kestrel") // .UseIIS() // This repo can no longer reference IIS because IISIntegration depends on it. .UseStartup() From 52587420e87533d02b61ecf29329a919fd46da27 Mon Sep 17 00:00:00 2001 From: David Fowler Date: Fri, 25 Mar 2016 01:05:48 -0700 Subject: [PATCH 060/307] Fix build - Hoist packages using netstandard.library - Upgrade process since it's not in the standard library --- test/Microsoft.AspNetCore.Buffering.Tests/project.json | 5 +++-- test/Microsoft.AspNetCore.HttpOverrides.Tests/project.json | 5 +++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/test/Microsoft.AspNetCore.Buffering.Tests/project.json b/test/Microsoft.AspNetCore.Buffering.Tests/project.json index ef8fb2810c..dfa1c1aaca 100644 --- a/test/Microsoft.AspNetCore.Buffering.Tests/project.json +++ b/test/Microsoft.AspNetCore.Buffering.Tests/project.json @@ -6,13 +6,14 @@ "dependencies": { "Microsoft.AspNetCore.Buffering": "0.1.0-*", "Microsoft.AspNetCore.TestHost": "1.0.0-*", - "Microsoft.NETCore.Platforms": "1.0.1-*", "xunit": "2.1.0" }, "frameworks": { "netstandardapp1.5": { "dependencies": { - "dotnet-test-xunit": "1.0.0-dev-*" + "dotnet-test-xunit": "1.0.0-dev-*", + "NETStandard.Library": "1.5.0-*", + "System.Diagnostics.Process": "4.1.0-*" }, "imports": [ "dnxcore50", diff --git a/test/Microsoft.AspNetCore.HttpOverrides.Tests/project.json b/test/Microsoft.AspNetCore.HttpOverrides.Tests/project.json index 8961b4e095..e723323e73 100644 --- a/test/Microsoft.AspNetCore.HttpOverrides.Tests/project.json +++ b/test/Microsoft.AspNetCore.HttpOverrides.Tests/project.json @@ -7,13 +7,14 @@ "Microsoft.AspNetCore.HttpOverrides": "1.0.0-*", "Microsoft.AspNetCore.TestHost": "1.0.0-*", "Microsoft.Extensions.Logging.Testing": "1.0.0-*", - "Microsoft.NETCore.Platforms": "1.0.1-*", "xunit": "2.1.0" }, "frameworks": { "netstandardapp1.5": { "dependencies": { - "dotnet-test-xunit": "1.0.0-dev-*" + "dotnet-test-xunit": "1.0.0-dev-*", + "NETStandard.Library": "1.5.0-*", + "System.Diagnostics.Process": "4.1.0-*" }, "imports": [ "dnxcore50", From c2534339f2ebf65976a75bad91326126292adc76 Mon Sep 17 00:00:00 2001 From: Victor Hurdugaci Date: Wed, 30 Mar 2016 13:57:02 -0700 Subject: [PATCH 061/307] Webhook notifications --- .travis.yml | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index df22f7a880..5a7c8837a3 100644 --- a/.travis.yml +++ b/.travis.yml @@ -23,4 +23,10 @@ branches: - dev - /^(.*\/)?ci-.*$/ script: - - ./build.sh verify \ No newline at end of file + - ./build.sh verify +notifications: + webhooks: + secure: "Quayhq8pTWtpCfsC209l4o3ZG75VhEKjTOcuOPDYoQXII4rfmVbnGUoe6A6R3VTz7/O2YTPbX3+ooBrTJufwiJXJG74xZuE35jKnRm3HQREH9tCNUYwB4BO7jzoWz9wXDDfCPs47Tkjdf46Tq0jF27nXrZhNzm6ps3JCoP6/lA+8lEfWxIYifviwxJ392S34k5SyaVYeOIs+W95Iuvmd6+ZenVZNvPaGwHzTKqVhh/NYttbQ3oUq4n2fWaIrwGVi7MC6CtINoG/CtmUU3pef+StPOYMjWfMGcUjAkikWWEsCDnUSOpmNxKREKqXXbOBPDCcC9sNkzpYa0ksHRwGQv2jagVYaAicNfGc/gtWJ3JTCnODUea6oTsmdZT7hNW1ClzOEacXHv55TzImgAb1MFD9euSoXBIa9rRNYhx1oy3JYal2Ee0crPF1nFxQJ5mVT9pGEhpMqAwdNaZBwA5urVn6bl0ptPb8W6XVw5/qgPdBvmF67Xjw+k3TDQ3J4sWClGdX4ZsfgVFLSDGk9hqudPp10XlXkAscYtpKoZIEIK5rVa7RnvI44Bh1eQRqFpqKa2m1gVquJwUQg0L8CPakZDscas29dtXY4KqHrspOOtolhtOUaVpanQCGFWgPnWxIx9m+3eDRCLSjhvrZyZwemmvqXNqFhKUILdQLo1itANDo=" + on_success: always + on_failure: always + on_start: always \ No newline at end of file From 2614ffb01d36eb67aaf23e5f794cf233d6172c0f Mon Sep 17 00:00:00 2001 From: John Luo Date: Wed, 30 Mar 2016 16:22:43 -0700 Subject: [PATCH 062/307] Reacting to Kestrel extensions --- samples/HttpOverridesSample/Startup.cs | 3 ++- samples/ResponseBufferingSample/Startup.cs | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/samples/HttpOverridesSample/Startup.cs b/samples/HttpOverridesSample/Startup.cs index 1d3286eff6..16bae2356b 100644 --- a/samples/HttpOverridesSample/Startup.cs +++ b/samples/HttpOverridesSample/Startup.cs @@ -34,7 +34,7 @@ namespace HttpOverridesSample { var host = new WebHostBuilder() .UseDefaultHostingConfiguration(args) - .UseServer("Microsoft.AspNetCore.Server.Kestrel") + .UseKestrel() // .UseIIS() // This repo can no longer reference IIS because IISIntegration depends on it. .UseStartup() .Build(); @@ -43,3 +43,4 @@ namespace HttpOverridesSample } } } + diff --git a/samples/ResponseBufferingSample/Startup.cs b/samples/ResponseBufferingSample/Startup.cs index 945bfaa81a..5c714bbf5b 100644 --- a/samples/ResponseBufferingSample/Startup.cs +++ b/samples/ResponseBufferingSample/Startup.cs @@ -39,7 +39,7 @@ namespace ResponseBufferingSample { var host = new WebHostBuilder() .UseDefaultHostingConfiguration(args) - .UseServer("Microsoft.AspNetCore.Server.Kestrel") + .UseKestrel() // .UseIIS() // This repo can no longer reference IIS because IISIntegration depends on it. .UseStartup() .Build(); @@ -48,3 +48,4 @@ namespace ResponseBufferingSample } } } + From 512ea0039800976fec36a446b3e9ec3ad5f95b45 Mon Sep 17 00:00:00 2001 From: Pranav K Date: Wed, 6 Apr 2016 09:47:56 -0700 Subject: [PATCH 063/307] Updating to release. --- NuGet.config | 2 +- build.ps1 | 2 +- build.sh | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/NuGet.config b/NuGet.config index dae5aba3f9..e526481f82 100644 --- a/NuGet.config +++ b/NuGet.config @@ -1,7 +1,7 @@ - + \ No newline at end of file diff --git a/build.ps1 b/build.ps1 index 8f2f99691a..cf8bff13bb 100644 --- a/build.ps1 +++ b/build.ps1 @@ -33,7 +33,7 @@ cd $PSScriptRoot $repoFolder = $PSScriptRoot $env:REPO_FOLDER = $repoFolder -$koreBuildZip="https://github.com/aspnet/KoreBuild/archive/dev.zip" +$koreBuildZip="https://github.com/aspnet/KoreBuild/archive/release.zip" if ($env:KOREBUILD_ZIP) { $koreBuildZip=$env:KOREBUILD_ZIP diff --git a/build.sh b/build.sh index f4208100eb..f88fe4052e 100755 --- a/build.sh +++ b/build.sh @@ -2,7 +2,7 @@ repoFolder="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" cd $repoFolder -koreBuildZip="https://github.com/aspnet/KoreBuild/archive/dev.zip" +koreBuildZip="https://github.com/aspnet/KoreBuild/archive/release.zip" if [ ! -z $KOREBUILD_ZIP ]; then koreBuildZip=$KOREBUILD_ZIP fi From 6e66c16dfe6eb8302792bb11fa692b8979acc466 Mon Sep 17 00:00:00 2001 From: Pranav K Date: Thu, 7 Apr 2016 15:53:09 -0700 Subject: [PATCH 064/307] Removing imports from src projects --- src/Microsoft.AspNetCore.Buffering/project.json | 8 ++------ src/Microsoft.AspNetCore.HttpOverrides/project.json | 8 ++------ 2 files changed, 4 insertions(+), 12 deletions(-) diff --git a/src/Microsoft.AspNetCore.Buffering/project.json b/src/Microsoft.AspNetCore.Buffering/project.json index 83d05073ba..22f4e17452 100644 --- a/src/Microsoft.AspNetCore.Buffering/project.json +++ b/src/Microsoft.AspNetCore.Buffering/project.json @@ -22,11 +22,7 @@ "Microsoft.AspNetCore.Http.Abstractions": "1.0.0-*" }, "frameworks": { - "net451": { }, - "netstandard1.3": { - "imports": [ - "dotnet5.4" - ] - } + "net451": {}, + "netstandard1.3": {} } } \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.HttpOverrides/project.json b/src/Microsoft.AspNetCore.HttpOverrides/project.json index da4b3587de..993b2c060d 100644 --- a/src/Microsoft.AspNetCore.HttpOverrides/project.json +++ b/src/Microsoft.AspNetCore.HttpOverrides/project.json @@ -25,11 +25,7 @@ "Microsoft.Extensions.Options": "1.0.0-*" }, "frameworks": { - "net451": { }, - "netstandard1.3": { - "imports": [ - "dotnet5.4" - ] - } + "net451": {}, + "netstandard1.3": {} } } \ No newline at end of file From c4f5cfaac36f9b0523a33c3f285d51d953837612 Mon Sep 17 00:00:00 2001 From: Pavel Krymets Date: Fri, 15 Apr 2016 12:07:47 -0700 Subject: [PATCH 065/307] Migrate tests, tools and samples to portable --- samples/HttpOverridesSample/project.json | 15 ++++++++++----- samples/ResponseBufferingSample/project.json | 15 ++++++++++----- .../project.json | 7 +++++-- .../project.json | 7 +++++-- 4 files changed, 30 insertions(+), 14 deletions(-) diff --git a/samples/HttpOverridesSample/project.json b/samples/HttpOverridesSample/project.json index 4467913ce0..df7f83b217 100644 --- a/samples/HttpOverridesSample/project.json +++ b/samples/HttpOverridesSample/project.json @@ -5,18 +5,23 @@ }, "dependencies": { "Microsoft.AspNetCore.HttpOverrides": "1.0.0-*", - "Microsoft.AspNetCore.Server.Kestrel": "1.0.0-*", - "Microsoft.NETCore.Platforms": "1.0.1-*" + "Microsoft.AspNetCore.Server.Kestrel": "1.0.0-*" }, "commands": { "web": "HttpOverridesSample" }, "frameworks": { - "dnx451": {}, - "netstandardapp1.5": { + "net451": {}, + "netcoreapp1.0": { "imports": [ "dnxcore50" - ] + ], + "dependencies": { + "Microsoft.NETCore.App": { + "version": "1.0.0-*", + "type": "platform" + } + } } }, "exclude": [ diff --git a/samples/ResponseBufferingSample/project.json b/samples/ResponseBufferingSample/project.json index 766c0a3675..657672d669 100644 --- a/samples/ResponseBufferingSample/project.json +++ b/samples/ResponseBufferingSample/project.json @@ -2,8 +2,7 @@ "version": "1.0.0-*", "dependencies": { "Microsoft.AspNetCore.Buffering": "0.1.0-*", - "Microsoft.AspNetCore.Server.Kestrel": "1.0.0-*", - "Microsoft.NETCore.Platforms": "1.0.1-*" + "Microsoft.AspNetCore.Server.Kestrel": "1.0.0-*" }, "compilationOptions": { "emitEntryPoint": true @@ -12,11 +11,17 @@ "web": "ResponseBufferingSample" }, "frameworks": { - "dnx451": {}, - "netstandardapp1.5": { + "net451": {}, + "netcoreapp1.0": { "imports": [ "dnxcore50" - ] + ], + "dependencies": { + "Microsoft.NETCore.App": { + "version": "1.0.0-*", + "type": "platform" + } + } } }, "publishExclude": [ diff --git a/test/Microsoft.AspNetCore.Buffering.Tests/project.json b/test/Microsoft.AspNetCore.Buffering.Tests/project.json index dfa1c1aaca..0d01a22f72 100644 --- a/test/Microsoft.AspNetCore.Buffering.Tests/project.json +++ b/test/Microsoft.AspNetCore.Buffering.Tests/project.json @@ -9,10 +9,13 @@ "xunit": "2.1.0" }, "frameworks": { - "netstandardapp1.5": { + "netcoreapp1.0": { "dependencies": { + "Microsoft.NETCore.App": { + "version": "1.0.0-*", + "type": "platform" + }, "dotnet-test-xunit": "1.0.0-dev-*", - "NETStandard.Library": "1.5.0-*", "System.Diagnostics.Process": "4.1.0-*" }, "imports": [ diff --git a/test/Microsoft.AspNetCore.HttpOverrides.Tests/project.json b/test/Microsoft.AspNetCore.HttpOverrides.Tests/project.json index e723323e73..7634747069 100644 --- a/test/Microsoft.AspNetCore.HttpOverrides.Tests/project.json +++ b/test/Microsoft.AspNetCore.HttpOverrides.Tests/project.json @@ -10,10 +10,13 @@ "xunit": "2.1.0" }, "frameworks": { - "netstandardapp1.5": { + "netcoreapp1.0": { "dependencies": { + "Microsoft.NETCore.App": { + "version": "1.0.0-*", + "type": "platform" + }, "dotnet-test-xunit": "1.0.0-dev-*", - "NETStandard.Library": "1.5.0-*", "System.Diagnostics.Process": "4.1.0-*" }, "imports": [ From 8cbd76f166b18cae0fa236be01487c1114a33330 Mon Sep 17 00:00:00 2001 From: Pavel Krymets Date: Mon, 18 Apr 2016 17:10:01 -0700 Subject: [PATCH 066/307] Bring Microsoft.NETCore.Platforms dependency back --- samples/HttpOverridesSample/project.json | 1 + samples/ResponseBufferingSample/project.json | 1 + test/Microsoft.AspNetCore.Buffering.Tests/project.json | 1 + test/Microsoft.AspNetCore.HttpOverrides.Tests/project.json | 1 + 4 files changed, 4 insertions(+) diff --git a/samples/HttpOverridesSample/project.json b/samples/HttpOverridesSample/project.json index df7f83b217..f55374058f 100644 --- a/samples/HttpOverridesSample/project.json +++ b/samples/HttpOverridesSample/project.json @@ -4,6 +4,7 @@ "emitEntryPoint": true }, "dependencies": { + "Microsoft.NETCore.Platforms": "1.0.1-*", "Microsoft.AspNetCore.HttpOverrides": "1.0.0-*", "Microsoft.AspNetCore.Server.Kestrel": "1.0.0-*" }, diff --git a/samples/ResponseBufferingSample/project.json b/samples/ResponseBufferingSample/project.json index 657672d669..f60e84b9fd 100644 --- a/samples/ResponseBufferingSample/project.json +++ b/samples/ResponseBufferingSample/project.json @@ -1,6 +1,7 @@ { "version": "1.0.0-*", "dependencies": { + "Microsoft.NETCore.Platforms": "1.0.1-*", "Microsoft.AspNetCore.Buffering": "0.1.0-*", "Microsoft.AspNetCore.Server.Kestrel": "1.0.0-*" }, diff --git a/test/Microsoft.AspNetCore.Buffering.Tests/project.json b/test/Microsoft.AspNetCore.Buffering.Tests/project.json index 0d01a22f72..6575549678 100644 --- a/test/Microsoft.AspNetCore.Buffering.Tests/project.json +++ b/test/Microsoft.AspNetCore.Buffering.Tests/project.json @@ -4,6 +4,7 @@ "warningsAsErrors": true }, "dependencies": { + "Microsoft.NETCore.Platforms": "1.0.1-*", "Microsoft.AspNetCore.Buffering": "0.1.0-*", "Microsoft.AspNetCore.TestHost": "1.0.0-*", "xunit": "2.1.0" diff --git a/test/Microsoft.AspNetCore.HttpOverrides.Tests/project.json b/test/Microsoft.AspNetCore.HttpOverrides.Tests/project.json index 7634747069..9e67d0260b 100644 --- a/test/Microsoft.AspNetCore.HttpOverrides.Tests/project.json +++ b/test/Microsoft.AspNetCore.HttpOverrides.Tests/project.json @@ -4,6 +4,7 @@ "warningsAsErrors": true }, "dependencies": { + "Microsoft.NETCore.Platforms": "1.0.1-*", "Microsoft.AspNetCore.HttpOverrides": "1.0.0-*", "Microsoft.AspNetCore.TestHost": "1.0.0-*", "Microsoft.Extensions.Logging.Testing": "1.0.0-*", From 7fd1e62322c500abc2c2b2f5cf7df00b7670d366 Mon Sep 17 00:00:00 2001 From: Pranav K Date: Tue, 19 Apr 2016 14:53:51 -0700 Subject: [PATCH 067/307] Use latest build of dotnet-test-xunit --- test/Microsoft.AspNetCore.Buffering.Tests/project.json | 2 +- test/Microsoft.AspNetCore.HttpOverrides.Tests/project.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/test/Microsoft.AspNetCore.Buffering.Tests/project.json b/test/Microsoft.AspNetCore.Buffering.Tests/project.json index 6575549678..1dae5aa4f2 100644 --- a/test/Microsoft.AspNetCore.Buffering.Tests/project.json +++ b/test/Microsoft.AspNetCore.Buffering.Tests/project.json @@ -16,7 +16,7 @@ "version": "1.0.0-*", "type": "platform" }, - "dotnet-test-xunit": "1.0.0-dev-*", + "dotnet-test-xunit": "1.0.0-*", "System.Diagnostics.Process": "4.1.0-*" }, "imports": [ diff --git a/test/Microsoft.AspNetCore.HttpOverrides.Tests/project.json b/test/Microsoft.AspNetCore.HttpOverrides.Tests/project.json index 9e67d0260b..f47a1868f0 100644 --- a/test/Microsoft.AspNetCore.HttpOverrides.Tests/project.json +++ b/test/Microsoft.AspNetCore.HttpOverrides.Tests/project.json @@ -17,7 +17,7 @@ "version": "1.0.0-*", "type": "platform" }, - "dotnet-test-xunit": "1.0.0-dev-*", + "dotnet-test-xunit": "1.0.0-*", "System.Diagnostics.Process": "4.1.0-*" }, "imports": [ From d7e509ebec588affbfb138adc962d0aa03935de5 Mon Sep 17 00:00:00 2001 From: BrennanConroy Date: Wed, 27 Apr 2016 18:45:43 -0700 Subject: [PATCH 068/307] Remove reference to UseDefaultHostConfiguration --- samples/HttpOverridesSample/Startup.cs | 1 - samples/ResponseBufferingSample/Startup.cs | 1 - 2 files changed, 2 deletions(-) diff --git a/samples/HttpOverridesSample/Startup.cs b/samples/HttpOverridesSample/Startup.cs index 16bae2356b..f90cedc702 100644 --- a/samples/HttpOverridesSample/Startup.cs +++ b/samples/HttpOverridesSample/Startup.cs @@ -33,7 +33,6 @@ namespace HttpOverridesSample public static void Main(string[] args) { var host = new WebHostBuilder() - .UseDefaultHostingConfiguration(args) .UseKestrel() // .UseIIS() // This repo can no longer reference IIS because IISIntegration depends on it. .UseStartup() diff --git a/samples/ResponseBufferingSample/Startup.cs b/samples/ResponseBufferingSample/Startup.cs index 5c714bbf5b..c2189ad1ee 100644 --- a/samples/ResponseBufferingSample/Startup.cs +++ b/samples/ResponseBufferingSample/Startup.cs @@ -38,7 +38,6 @@ namespace ResponseBufferingSample public static void Main(string[] args) { var host = new WebHostBuilder() - .UseDefaultHostingConfiguration(args) .UseKestrel() // .UseIIS() // This repo can no longer reference IIS because IISIntegration depends on it. .UseStartup() From 52869b03ec94477520137842f165bd969a9f6582 Mon Sep 17 00:00:00 2001 From: Pranav K Date: Mon, 2 May 2016 11:27:05 -0700 Subject: [PATCH 069/307] Fix build warnings --- samples/HttpOverridesSample/project.json | 2 +- samples/ResponseBufferingSample/project.json | 2 +- .../project.json | 20 +++++++++-------- .../project.json | 22 ++++++++++--------- .../project.json | 4 ++-- .../project.json | 4 ++-- 6 files changed, 29 insertions(+), 25 deletions(-) diff --git a/samples/HttpOverridesSample/project.json b/samples/HttpOverridesSample/project.json index f55374058f..57abaa20b4 100644 --- a/samples/HttpOverridesSample/project.json +++ b/samples/HttpOverridesSample/project.json @@ -1,6 +1,6 @@ { "version": "1.0.0-*", - "compilationOptions": { + "buildOptions": { "emitEntryPoint": true }, "dependencies": { diff --git a/samples/ResponseBufferingSample/project.json b/samples/ResponseBufferingSample/project.json index f60e84b9fd..5967a15f35 100644 --- a/samples/ResponseBufferingSample/project.json +++ b/samples/ResponseBufferingSample/project.json @@ -5,7 +5,7 @@ "Microsoft.AspNetCore.Buffering": "0.1.0-*", "Microsoft.AspNetCore.Server.Kestrel": "1.0.0-*" }, - "compilationOptions": { + "buildOptions": { "emitEntryPoint": true }, "commands": { diff --git a/src/Microsoft.AspNetCore.Buffering/project.json b/src/Microsoft.AspNetCore.Buffering/project.json index 22f4e17452..6603b0c065 100644 --- a/src/Microsoft.AspNetCore.Buffering/project.json +++ b/src/Microsoft.AspNetCore.Buffering/project.json @@ -1,6 +1,6 @@ { "version": "0.1.0-*", - "compilationOptions": { + "buildOptions": { "warningsAsErrors": true, "keyFile": "../../tools/Key.snk", "nowarn": [ @@ -9,14 +9,16 @@ "xmlDoc": true }, "description": "ASP.NET Core middleware for buffering response bodies.", - "tags": [ - "aspnetcore", - "buffer", - "buffering" - ], - "repository": { - "type": "git", - "url": "git://github.com/aspnet/basicmiddleware" + "packOptions": { + "repository": { + "type": "git", + "url": "git://github.com/aspnet/basicmiddleware" + }, + "tags": [ + "aspnetcore", + "buffer", + "buffering" + ] }, "dependencies": { "Microsoft.AspNetCore.Http.Abstractions": "1.0.0-*" diff --git a/src/Microsoft.AspNetCore.HttpOverrides/project.json b/src/Microsoft.AspNetCore.HttpOverrides/project.json index 993b2c060d..9cc81aa3a4 100644 --- a/src/Microsoft.AspNetCore.HttpOverrides/project.json +++ b/src/Microsoft.AspNetCore.HttpOverrides/project.json @@ -1,6 +1,6 @@ { "version": "1.0.0-*", - "compilationOptions": { + "buildOptions": { "warningsAsErrors": true, "keyFile": "../../tools/Key.snk", "nowarn": [ @@ -9,15 +9,17 @@ "xmlDoc": true }, "description": "ASP.NET Core basic middleware for:\r\nX-Forwarded-* headers to forward headers from a proxy.\r\nHTTP method override header.", - "tags": [ - "aspnetcore", - "proxy", - "headers", - "xforwarded" - ], - "repository": { - "type": "git", - "url": "git://github.com/aspnet/basicmiddleware" + "packOptions": { + "repository": { + "type": "git", + "url": "git://github.com/aspnet/basicmiddleware" + }, + "tags": [ + "aspnetcore", + "proxy", + "headers", + "xforwarded" + ] }, "dependencies": { "Microsoft.AspNetCore.Http.Extensions": "1.0.0-*", diff --git a/test/Microsoft.AspNetCore.Buffering.Tests/project.json b/test/Microsoft.AspNetCore.Buffering.Tests/project.json index 1dae5aa4f2..5e07dcf77d 100644 --- a/test/Microsoft.AspNetCore.Buffering.Tests/project.json +++ b/test/Microsoft.AspNetCore.Buffering.Tests/project.json @@ -1,9 +1,10 @@ { "version": "1.0.0-*", - "compilationOptions": { + "buildOptions": { "warningsAsErrors": true }, "dependencies": { + "dotnet-test-xunit": "1.0.0-*", "Microsoft.NETCore.Platforms": "1.0.1-*", "Microsoft.AspNetCore.Buffering": "0.1.0-*", "Microsoft.AspNetCore.TestHost": "1.0.0-*", @@ -16,7 +17,6 @@ "version": "1.0.0-*", "type": "platform" }, - "dotnet-test-xunit": "1.0.0-*", "System.Diagnostics.Process": "4.1.0-*" }, "imports": [ diff --git a/test/Microsoft.AspNetCore.HttpOverrides.Tests/project.json b/test/Microsoft.AspNetCore.HttpOverrides.Tests/project.json index f47a1868f0..832f3a3a56 100644 --- a/test/Microsoft.AspNetCore.HttpOverrides.Tests/project.json +++ b/test/Microsoft.AspNetCore.HttpOverrides.Tests/project.json @@ -1,9 +1,10 @@ { "version": "1.0.0-*", - "compilationOptions": { + "buildOptions": { "warningsAsErrors": true }, "dependencies": { + "dotnet-test-xunit": "1.0.0-*", "Microsoft.NETCore.Platforms": "1.0.1-*", "Microsoft.AspNetCore.HttpOverrides": "1.0.0-*", "Microsoft.AspNetCore.TestHost": "1.0.0-*", @@ -17,7 +18,6 @@ "version": "1.0.0-*", "type": "platform" }, - "dotnet-test-xunit": "1.0.0-*", "System.Diagnostics.Process": "4.1.0-*" }, "imports": [ From 367eec812c8260872781cab8a925abd9a5a1f0c0 Mon Sep 17 00:00:00 2001 From: Pranav K Date: Wed, 18 May 2016 21:32:57 -0700 Subject: [PATCH 070/307] Fix schema change build warnings --- samples/HttpOverridesSample/project.json | 16 +++++------- samples/ResponseBufferingSample/project.json | 27 +++++++------------- 2 files changed, 16 insertions(+), 27 deletions(-) diff --git a/samples/HttpOverridesSample/project.json b/samples/HttpOverridesSample/project.json index 57abaa20b4..44fa93e3bc 100644 --- a/samples/HttpOverridesSample/project.json +++ b/samples/HttpOverridesSample/project.json @@ -3,6 +3,12 @@ "buildOptions": { "emitEntryPoint": true }, + "publishOptions": { + "exclude": [ + "**.user", + "**.vspscc" + ] + }, "dependencies": { "Microsoft.NETCore.Platforms": "1.0.1-*", "Microsoft.AspNetCore.HttpOverrides": "1.0.0-*", @@ -24,13 +30,5 @@ } } } - }, - "exclude": [ - "wwwroot", - "node_modules" - ], - "publishExclude": [ - "**.user", - "**.vspscc" - ] + } } \ No newline at end of file diff --git a/samples/ResponseBufferingSample/project.json b/samples/ResponseBufferingSample/project.json index 5967a15f35..988bb9c8c7 100644 --- a/samples/ResponseBufferingSample/project.json +++ b/samples/ResponseBufferingSample/project.json @@ -8,15 +8,9 @@ "buildOptions": { "emitEntryPoint": true }, - "commands": { - "web": "ResponseBufferingSample" - }, "frameworks": { "net451": {}, "netcoreapp1.0": { - "imports": [ - "dnxcore50" - ], "dependencies": { "Microsoft.NETCore.App": { "version": "1.0.0-*", @@ -25,16 +19,13 @@ } } }, - "publishExclude": [ - "node_modules", - "bower_components", - "**.xproj", - "**.user", - "**.vspscc" - ], - "exclude": [ - "wwwroot", - "node_modules", - "bower_components" - ] + "publish": { + "exclude": [ + "node_modules", + "bower_components", + "**.xproj", + "**.user", + "**.vspscc" + ] + } } \ No newline at end of file From 5fe48ada426c8bdf483977f0876b777a7f8d1a60 Mon Sep 17 00:00:00 2001 From: Chris R Date: Thu, 19 May 2016 14:30:54 -0700 Subject: [PATCH 071/307] #37 Make the header length match optional. --- .../ForwardedHeadersMiddleware.cs | 88 ++++++++++--------- .../ForwardedHeadersOptions.cs | 6 ++ .../Internal/IPEndPointParser.cs | 5 ++ .../ForwardedHeadersMiddlewareTest.cs | 40 +++++++++ 4 files changed, 96 insertions(+), 43 deletions(-) diff --git a/src/Microsoft.AspNetCore.HttpOverrides/ForwardedHeadersMiddleware.cs b/src/Microsoft.AspNetCore.HttpOverrides/ForwardedHeadersMiddleware.cs index 042b0887b7..420ed7e3fd 100644 --- a/src/Microsoft.AspNetCore.HttpOverrides/ForwardedHeadersMiddleware.cs +++ b/src/Microsoft.AspNetCore.HttpOverrides/ForwardedHeadersMiddleware.cs @@ -65,75 +65,61 @@ namespace Microsoft.AspNetCore.HttpOverrides { checkFor = true; forwardedFor = context.Request.Headers.GetCommaSeparatedValues(XForwardedForHeaderName); - if (StringValues.IsNullOrEmpty(forwardedFor)) - { - return; - } - entryCount = forwardedFor.Length; + entryCount = Math.Max(forwardedFor.Length, entryCount); } if ((_options.ForwardedHeaders & ForwardedHeaders.XForwardedProto) == ForwardedHeaders.XForwardedProto) { checkProto = true; forwardedProto = context.Request.Headers.GetCommaSeparatedValues(XForwardedProtoHeaderName); - if (StringValues.IsNullOrEmpty(forwardedProto)) - { - return; - } - if (checkFor && forwardedFor.Length != forwardedProto.Length) + if (_options.RequireHeaderSymmetry && checkFor && forwardedFor.Length != forwardedProto.Length) { _logger.LogDebug(1, "Parameter count mismatch between X-Forwarded-For and X-Forwarded-Proto."); return; } - entryCount = forwardedProto.Length; + entryCount = Math.Max(forwardedProto.Length, entryCount); } if ((_options.ForwardedHeaders & ForwardedHeaders.XForwardedHost) == ForwardedHeaders.XForwardedHost) { checkHost = true; forwardedHost = context.Request.Headers.GetCommaSeparatedValues(XForwardedHostHeaderName); - if (StringValues.IsNullOrEmpty(forwardedHost)) - { - return; - } - if ((checkFor && forwardedFor.Length != forwardedHost.Length) - || (checkProto && forwardedProto.Length != forwardedHost.Length)) + if (_options.RequireHeaderSymmetry + && ((checkFor && forwardedFor.Length != forwardedHost.Length) + || (checkProto && forwardedProto.Length != forwardedHost.Length))) { _logger.LogDebug(1, "Parameter count mismatch between X-Forwarded-Host and X-Forwarded-For or X-Forwarded-Proto."); return; } - entryCount = forwardedHost.Length; + entryCount = Math.Max(forwardedHost.Length, entryCount); } // Apply ForwardLimit, if any - int offset = 0; if (_options.ForwardLimit.HasValue && entryCount > _options.ForwardLimit) { - offset = entryCount - _options.ForwardLimit.Value; entryCount = _options.ForwardLimit.Value; } // Group the data together. - var sets = new List(entryCount); - for (int i = 0; i < entryCount; i++) + var sets = new SetOfForwarders[entryCount]; + for (int i = 0; i < sets.Length; i++) { + // They get processed in reverse order, right to left. var set = new SetOfForwarders(); - if (checkFor) + if (checkFor && i < forwardedFor.Length) { - set.IpAndPortText = forwardedFor[offset + i]; + set.IpAndPortText = forwardedFor[forwardedFor.Length - i - 1]; } - if (checkProto) + if (checkProto && i < forwardedProto.Length) { - set.Scheme = forwardedProto[offset + i]; + set.Scheme = forwardedProto[forwardedProto.Length - i - 1]; } - if (checkHost) + if (checkHost && i < forwardedHost.Length) { - set.Host = forwardedHost[offset + i]; + set.Host = forwardedHost[forwardedHost.Length - i - 1]; } - sets.Add(set); + sets[i] = set; } - // They get processed in reverse order, right to left. - sets.Reverse(); // Gather initial values var connection = context.Connection; @@ -148,8 +134,9 @@ namespace Microsoft.AspNetCore.HttpOverrides bool applyChanges = false; int entriesConsumed = 0; - foreach (var set in sets) + for ( ; entriesConsumed < sets.Length; entriesConsumed++) { + var set = sets[entriesConsumed]; if (checkFor) { // For the first instance, allow remoteIp to be null for servers that don't support it natively. @@ -159,7 +146,16 @@ namespace Microsoft.AspNetCore.HttpOverrides _logger.LogDebug(1, $"Unknown proxy: {currentValues.RemoteIpAndPort}"); break; } - if (!IPEndPointParser.TryParse(set.IpAndPortText, out set.RemoteIpAndPort)) + + IPEndPoint parsedEndPoint; + if (IPEndPointParser.TryParse(set.IpAndPortText, out parsedEndPoint)) + { + applyChanges = true; + set.RemoteIpAndPort = parsedEndPoint; + currentValues.IpAndPortText = set.IpAndPortText; + currentValues.RemoteIpAndPort = set.RemoteIpAndPort; + } + else if (_options.RequireHeaderSymmetry) { _logger.LogDebug(2, $"Failed to parse forwarded IPAddress: {currentValues.IpAndPortText}"); return; @@ -168,7 +164,12 @@ namespace Microsoft.AspNetCore.HttpOverrides if (checkProto) { - if (string.IsNullOrEmpty(set.Scheme)) + if (!string.IsNullOrEmpty(set.Scheme)) + { + applyChanges = true; + currentValues.Scheme = set.Scheme; + } + else if (_options.RequireHeaderSymmetry) { _logger.LogDebug(3, $"Failed to parse forwarded scheme: {set.Scheme}"); return; @@ -177,21 +178,22 @@ namespace Microsoft.AspNetCore.HttpOverrides if (checkHost) { - if (string.IsNullOrEmpty(set.Host)) + if (!string.IsNullOrEmpty(set.Host)) + { + applyChanges = true; + currentValues.Host = set.Host; + } + else if (_options.RequireHeaderSymmetry) { _logger.LogDebug(4, $"Failed to parse forwarded host: {set.Host}"); return; } } - - applyChanges = true; - currentValues = set; - entriesConsumed++; } if (applyChanges) { - if (checkFor) + if (checkFor && currentValues.RemoteIpAndPort != null) { if (connection.RemoteIpAddress != null) { @@ -212,7 +214,7 @@ namespace Microsoft.AspNetCore.HttpOverrides connection.RemotePort = currentValues.RemoteIpAndPort.Port; } - if (checkProto) + if (checkProto && currentValues.Scheme != null) { // Save the original request.Headers[XOriginalProtoName] = request.Scheme; @@ -229,7 +231,7 @@ namespace Microsoft.AspNetCore.HttpOverrides request.Scheme = currentValues.Scheme; } - if (checkHost) + if (checkHost && currentValues.Host != null) { // Save the original request.Headers[XOriginalHostName] = request.Host.ToString(); @@ -264,7 +266,7 @@ namespace Microsoft.AspNetCore.HttpOverrides return false; } - private class SetOfForwarders + private struct SetOfForwarders { public string IpAndPortText; public IPEndPoint RemoteIpAndPort; diff --git a/src/Microsoft.AspNetCore.HttpOverrides/ForwardedHeadersOptions.cs b/src/Microsoft.AspNetCore.HttpOverrides/ForwardedHeadersOptions.cs index 2802e79359..602dd2ec1d 100644 --- a/src/Microsoft.AspNetCore.HttpOverrides/ForwardedHeadersOptions.cs +++ b/src/Microsoft.AspNetCore.HttpOverrides/ForwardedHeadersOptions.cs @@ -30,5 +30,11 @@ namespace Microsoft.AspNetCore.Builder /// Address ranges of known proxies to accept forwarded headers from. /// public IList KnownNetworks { get; } = new List() { new IPNetwork(IPAddress.Loopback, 8) }; + + /// + /// Require the number of header values to be in sync between the different headers being processed. + /// The default is 'true'. + /// + public bool RequireHeaderSymmetry { get; set; } = true; } } diff --git a/src/Microsoft.AspNetCore.HttpOverrides/Internal/IPEndPointParser.cs b/src/Microsoft.AspNetCore.HttpOverrides/Internal/IPEndPointParser.cs index d33b44e72b..a797584b94 100644 --- a/src/Microsoft.AspNetCore.HttpOverrides/Internal/IPEndPointParser.cs +++ b/src/Microsoft.AspNetCore.HttpOverrides/Internal/IPEndPointParser.cs @@ -14,6 +14,11 @@ namespace Microsoft.AspNetCore.HttpOverrides.Internal IPAddress address; endpoint = null; + if (string.IsNullOrEmpty(addressWithPort)) + { + return false; + } + var lastColonIndex = addressWithPort.LastIndexOf(':'); if (lastColonIndex > 0) { diff --git a/test/Microsoft.AspNetCore.HttpOverrides.Tests/ForwardedHeadersMiddlewareTest.cs b/test/Microsoft.AspNetCore.HttpOverrides.Tests/ForwardedHeadersMiddlewareTest.cs index 6632a1bba6..e0de87abd8 100644 --- a/test/Microsoft.AspNetCore.HttpOverrides.Tests/ForwardedHeadersMiddlewareTest.cs +++ b/test/Microsoft.AspNetCore.HttpOverrides.Tests/ForwardedHeadersMiddlewareTest.cs @@ -363,6 +363,46 @@ namespace Microsoft.AspNetCore.HttpOverrides Assert.True(assertsExecuted); } + [Theory] + [InlineData(0, "h1", "::1", "http")] + [InlineData(1, "", "::1", "http")] + [InlineData(1, "h1", "", "h1")] + [InlineData(1, "h1", "::1", "h1")] + [InlineData(3, "h1", "::1", "h1")] + [InlineData(3, "h1", "::1, ::1", "h1")] + [InlineData(3, "h2, h1", "::1", "h2")] + [InlineData(5, "h2, h1", "::1, ::1", "h2")] + [InlineData(10, "h3, h2, h1", "::1, ::1, ::1", "h3")] + [InlineData(10, "h3, h2, h1", "::1, badip, ::1", "h3")] + public async Task XForwardedProtoOverrideCanBeIndependentOfXForwardedForCount(int limit, string protoHeader, string forHeader, string expected) + { + var assertsExecuted = false; + + var builder = new WebHostBuilder() + .Configure(app => + { + app.UseForwardedHeaders(new ForwardedHeadersOptions + { + ForwardedHeaders = ForwardedHeaders.XForwardedProto | ForwardedHeaders.XForwardedFor, + RequireHeaderSymmetry = false, + ForwardLimit = limit, + }); + app.Run(context => + { + Assert.Equal(expected, context.Request.Scheme); + assertsExecuted = true; + return Task.FromResult(0); + }); + }); + var server = new TestServer(builder); + + var req = new HttpRequestMessage(HttpMethod.Get, ""); + req.Headers.Add("X-Forwarded-Proto", protoHeader); + req.Headers.Add("X-Forwarded-For", forHeader); + await server.CreateClient().SendAsync(req); + Assert.True(assertsExecuted); + } + [Theory] [InlineData("", "", "::1", false, "http")] [InlineData("h1", "", "::1", false, "http")] From b269f13b17b540454e559fe753a3d9542ca9cd6b Mon Sep 17 00:00:00 2001 From: Cesar Blum Silveira Date: Fri, 27 May 2016 11:46:28 -0700 Subject: [PATCH 072/307] Fix OSX build on Travis. --- .travis.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.travis.yml b/.travis.yml index 5a7c8837a3..709151e70a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -22,6 +22,8 @@ branches: - release - dev - /^(.*\/)?ci-.*$/ +before_install: + - if test "$TRAVIS_OS_NAME" == "osx"; then brew update; brew install openssl; brew link --force openssl; fi script: - ./build.sh verify notifications: From 3e8990530c0abaf99eba9606a98b1fc3347a7fc0 Mon Sep 17 00:00:00 2001 From: jacalvar Date: Tue, 7 Jun 2016 15:49:37 -0700 Subject: [PATCH 073/307] Remove unncessary imports --- samples/HttpOverridesSample/project.json | 3 --- 1 file changed, 3 deletions(-) diff --git a/samples/HttpOverridesSample/project.json b/samples/HttpOverridesSample/project.json index 44fa93e3bc..847538c46b 100644 --- a/samples/HttpOverridesSample/project.json +++ b/samples/HttpOverridesSample/project.json @@ -20,9 +20,6 @@ "frameworks": { "net451": {}, "netcoreapp1.0": { - "imports": [ - "dnxcore50" - ], "dependencies": { "Microsoft.NETCore.App": { "version": "1.0.0-*", From e250efeab6176c394529fe9a032d191c0d9251a8 Mon Sep 17 00:00:00 2001 From: "N. Taylor Mullen" Date: Mon, 13 Jun 2016 15:30:16 -0700 Subject: [PATCH 074/307] Remove direct Microsoft.NETCore.Platforms dependency. - Microsoft.NETCore.App now pulls this package in. aspnet/Coherence-Signed#344 --- samples/HttpOverridesSample/project.json | 1 - samples/ResponseBufferingSample/project.json | 1 - test/Microsoft.AspNetCore.Buffering.Tests/project.json | 1 - test/Microsoft.AspNetCore.HttpOverrides.Tests/project.json | 1 - 4 files changed, 4 deletions(-) diff --git a/samples/HttpOverridesSample/project.json b/samples/HttpOverridesSample/project.json index 847538c46b..39111290db 100644 --- a/samples/HttpOverridesSample/project.json +++ b/samples/HttpOverridesSample/project.json @@ -10,7 +10,6 @@ ] }, "dependencies": { - "Microsoft.NETCore.Platforms": "1.0.1-*", "Microsoft.AspNetCore.HttpOverrides": "1.0.0-*", "Microsoft.AspNetCore.Server.Kestrel": "1.0.0-*" }, diff --git a/samples/ResponseBufferingSample/project.json b/samples/ResponseBufferingSample/project.json index 988bb9c8c7..7fa4cc5f13 100644 --- a/samples/ResponseBufferingSample/project.json +++ b/samples/ResponseBufferingSample/project.json @@ -1,7 +1,6 @@ { "version": "1.0.0-*", "dependencies": { - "Microsoft.NETCore.Platforms": "1.0.1-*", "Microsoft.AspNetCore.Buffering": "0.1.0-*", "Microsoft.AspNetCore.Server.Kestrel": "1.0.0-*" }, diff --git a/test/Microsoft.AspNetCore.Buffering.Tests/project.json b/test/Microsoft.AspNetCore.Buffering.Tests/project.json index 5e07dcf77d..3203cef839 100644 --- a/test/Microsoft.AspNetCore.Buffering.Tests/project.json +++ b/test/Microsoft.AspNetCore.Buffering.Tests/project.json @@ -5,7 +5,6 @@ }, "dependencies": { "dotnet-test-xunit": "1.0.0-*", - "Microsoft.NETCore.Platforms": "1.0.1-*", "Microsoft.AspNetCore.Buffering": "0.1.0-*", "Microsoft.AspNetCore.TestHost": "1.0.0-*", "xunit": "2.1.0" diff --git a/test/Microsoft.AspNetCore.HttpOverrides.Tests/project.json b/test/Microsoft.AspNetCore.HttpOverrides.Tests/project.json index 832f3a3a56..f683ee52ae 100644 --- a/test/Microsoft.AspNetCore.HttpOverrides.Tests/project.json +++ b/test/Microsoft.AspNetCore.HttpOverrides.Tests/project.json @@ -5,7 +5,6 @@ }, "dependencies": { "dotnet-test-xunit": "1.0.0-*", - "Microsoft.NETCore.Platforms": "1.0.1-*", "Microsoft.AspNetCore.HttpOverrides": "1.0.0-*", "Microsoft.AspNetCore.TestHost": "1.0.0-*", "Microsoft.Extensions.Logging.Testing": "1.0.0-*", From 6bc0b87f1a5cb943b7fb3c8b470c7f211a58865f Mon Sep 17 00:00:00 2001 From: Pranav K Date: Tue, 14 Jun 2016 16:23:14 -0700 Subject: [PATCH 075/307] Updating to release. --- NuGet.config | 2 +- build.ps1 | 2 +- build.sh | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/NuGet.config b/NuGet.config index dae5aba3f9..e526481f82 100644 --- a/NuGet.config +++ b/NuGet.config @@ -1,7 +1,7 @@ - + \ No newline at end of file diff --git a/build.ps1 b/build.ps1 index 8f2f99691a..cf8bff13bb 100644 --- a/build.ps1 +++ b/build.ps1 @@ -33,7 +33,7 @@ cd $PSScriptRoot $repoFolder = $PSScriptRoot $env:REPO_FOLDER = $repoFolder -$koreBuildZip="https://github.com/aspnet/KoreBuild/archive/dev.zip" +$koreBuildZip="https://github.com/aspnet/KoreBuild/archive/release.zip" if ($env:KOREBUILD_ZIP) { $koreBuildZip=$env:KOREBUILD_ZIP diff --git a/build.sh b/build.sh index f4208100eb..f88fe4052e 100755 --- a/build.sh +++ b/build.sh @@ -2,7 +2,7 @@ repoFolder="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" cd $repoFolder -koreBuildZip="https://github.com/aspnet/KoreBuild/archive/dev.zip" +koreBuildZip="https://github.com/aspnet/KoreBuild/archive/release.zip" if [ ! -z $KOREBUILD_ZIP ]; then koreBuildZip=$KOREBUILD_ZIP fi From 6e7c004a50ad786c5d2619bba594a3660095fcd3 Mon Sep 17 00:00:00 2001 From: Pranav K Date: Thu, 16 Jun 2016 10:17:30 -0700 Subject: [PATCH 076/307] Updating to dev versions --- samples/HttpOverridesSample/project.json | 6 +++--- samples/ResponseBufferingSample/project.json | 6 +++--- src/Microsoft.AspNetCore.Buffering/project.json | 4 ++-- src/Microsoft.AspNetCore.HttpOverrides/project.json | 8 ++++---- test/Microsoft.AspNetCore.Buffering.Tests/project.json | 6 +++--- .../Microsoft.AspNetCore.HttpOverrides.Tests/project.json | 8 ++++---- 6 files changed, 19 insertions(+), 19 deletions(-) diff --git a/samples/HttpOverridesSample/project.json b/samples/HttpOverridesSample/project.json index 39111290db..db91d8d16f 100644 --- a/samples/HttpOverridesSample/project.json +++ b/samples/HttpOverridesSample/project.json @@ -1,5 +1,5 @@ { - "version": "1.0.0-*", + "version": "1.1.0-*", "buildOptions": { "emitEntryPoint": true }, @@ -10,8 +10,8 @@ ] }, "dependencies": { - "Microsoft.AspNetCore.HttpOverrides": "1.0.0-*", - "Microsoft.AspNetCore.Server.Kestrel": "1.0.0-*" + "Microsoft.AspNetCore.HttpOverrides": "1.1.0-*", + "Microsoft.AspNetCore.Server.Kestrel": "1.1.0-*" }, "commands": { "web": "HttpOverridesSample" diff --git a/samples/ResponseBufferingSample/project.json b/samples/ResponseBufferingSample/project.json index 7fa4cc5f13..e3c674f864 100644 --- a/samples/ResponseBufferingSample/project.json +++ b/samples/ResponseBufferingSample/project.json @@ -1,8 +1,8 @@ { - "version": "1.0.0-*", + "version": "1.1.0-*", "dependencies": { - "Microsoft.AspNetCore.Buffering": "0.1.0-*", - "Microsoft.AspNetCore.Server.Kestrel": "1.0.0-*" + "Microsoft.AspNetCore.Buffering": "0.2.0-*", + "Microsoft.AspNetCore.Server.Kestrel": "1.1.0-*" }, "buildOptions": { "emitEntryPoint": true diff --git a/src/Microsoft.AspNetCore.Buffering/project.json b/src/Microsoft.AspNetCore.Buffering/project.json index 6603b0c065..c202a5178b 100644 --- a/src/Microsoft.AspNetCore.Buffering/project.json +++ b/src/Microsoft.AspNetCore.Buffering/project.json @@ -1,5 +1,5 @@ { - "version": "0.1.0-*", + "version": "0.2.0-*", "buildOptions": { "warningsAsErrors": true, "keyFile": "../../tools/Key.snk", @@ -21,7 +21,7 @@ ] }, "dependencies": { - "Microsoft.AspNetCore.Http.Abstractions": "1.0.0-*" + "Microsoft.AspNetCore.Http.Abstractions": "1.1.0-*" }, "frameworks": { "net451": {}, diff --git a/src/Microsoft.AspNetCore.HttpOverrides/project.json b/src/Microsoft.AspNetCore.HttpOverrides/project.json index 9cc81aa3a4..6205811116 100644 --- a/src/Microsoft.AspNetCore.HttpOverrides/project.json +++ b/src/Microsoft.AspNetCore.HttpOverrides/project.json @@ -1,5 +1,5 @@ { - "version": "1.0.0-*", + "version": "1.1.0-*", "buildOptions": { "warningsAsErrors": true, "keyFile": "../../tools/Key.snk", @@ -22,9 +22,9 @@ ] }, "dependencies": { - "Microsoft.AspNetCore.Http.Extensions": "1.0.0-*", - "Microsoft.Extensions.Logging.Abstractions": "1.0.0-*", - "Microsoft.Extensions.Options": "1.0.0-*" + "Microsoft.AspNetCore.Http.Extensions": "1.1.0-*", + "Microsoft.Extensions.Logging.Abstractions": "1.1.0-*", + "Microsoft.Extensions.Options": "1.1.0-*" }, "frameworks": { "net451": {}, diff --git a/test/Microsoft.AspNetCore.Buffering.Tests/project.json b/test/Microsoft.AspNetCore.Buffering.Tests/project.json index 3203cef839..ff03dcf550 100644 --- a/test/Microsoft.AspNetCore.Buffering.Tests/project.json +++ b/test/Microsoft.AspNetCore.Buffering.Tests/project.json @@ -1,12 +1,12 @@ { - "version": "1.0.0-*", + "version": "1.1.0-*", "buildOptions": { "warningsAsErrors": true }, "dependencies": { "dotnet-test-xunit": "1.0.0-*", - "Microsoft.AspNetCore.Buffering": "0.1.0-*", - "Microsoft.AspNetCore.TestHost": "1.0.0-*", + "Microsoft.AspNetCore.Buffering": "0.2.0-*", + "Microsoft.AspNetCore.TestHost": "1.1.0-*", "xunit": "2.1.0" }, "frameworks": { diff --git a/test/Microsoft.AspNetCore.HttpOverrides.Tests/project.json b/test/Microsoft.AspNetCore.HttpOverrides.Tests/project.json index f683ee52ae..4856cf1c7c 100644 --- a/test/Microsoft.AspNetCore.HttpOverrides.Tests/project.json +++ b/test/Microsoft.AspNetCore.HttpOverrides.Tests/project.json @@ -1,13 +1,13 @@ { - "version": "1.0.0-*", + "version": "1.1.0-*", "buildOptions": { "warningsAsErrors": true }, "dependencies": { "dotnet-test-xunit": "1.0.0-*", - "Microsoft.AspNetCore.HttpOverrides": "1.0.0-*", - "Microsoft.AspNetCore.TestHost": "1.0.0-*", - "Microsoft.Extensions.Logging.Testing": "1.0.0-*", + "Microsoft.AspNetCore.HttpOverrides": "1.1.0-*", + "Microsoft.AspNetCore.TestHost": "1.1.0-*", + "Microsoft.Extensions.Logging.Testing": "1.1.0-*", "xunit": "2.1.0" }, "frameworks": { From ab98dc29ad7864a697998f61f07f78f9043067bf Mon Sep 17 00:00:00 2001 From: Pranav K Date: Wed, 29 Jun 2016 14:53:06 -0700 Subject: [PATCH 077/307] Updating to RTM builds of xunit --- .../project.json | 23 ++++--------------- .../project.json | 23 ++++--------------- 2 files changed, 10 insertions(+), 36 deletions(-) diff --git a/test/Microsoft.AspNetCore.Buffering.Tests/project.json b/test/Microsoft.AspNetCore.Buffering.Tests/project.json index ff03dcf550..47d0f4fab0 100644 --- a/test/Microsoft.AspNetCore.Buffering.Tests/project.json +++ b/test/Microsoft.AspNetCore.Buffering.Tests/project.json @@ -4,10 +4,10 @@ "warningsAsErrors": true }, "dependencies": { - "dotnet-test-xunit": "1.0.0-*", + "dotnet-test-xunit": "2.2.0-*", "Microsoft.AspNetCore.Buffering": "0.2.0-*", "Microsoft.AspNetCore.TestHost": "1.1.0-*", - "xunit": "2.1.0" + "xunit": "2.2.0-*" }, "frameworks": { "netcoreapp1.0": { @@ -15,23 +15,10 @@ "Microsoft.NETCore.App": { "version": "1.0.0-*", "type": "platform" - }, - "System.Diagnostics.Process": "4.1.0-*" - }, - "imports": [ - "dnxcore50", - "portable-net451+win8" - ] - }, - "net451": { - "frameworkAssemblies": { - "System.Runtime": "", - "System.Threading.Tasks": "" - }, - "dependencies": { - "xunit.runner.console": "2.1.0" + } } - } + }, + "net451": {} }, "testRunner": "xunit" } \ No newline at end of file diff --git a/test/Microsoft.AspNetCore.HttpOverrides.Tests/project.json b/test/Microsoft.AspNetCore.HttpOverrides.Tests/project.json index 4856cf1c7c..9ee14135a2 100644 --- a/test/Microsoft.AspNetCore.HttpOverrides.Tests/project.json +++ b/test/Microsoft.AspNetCore.HttpOverrides.Tests/project.json @@ -4,11 +4,11 @@ "warningsAsErrors": true }, "dependencies": { - "dotnet-test-xunit": "1.0.0-*", + "dotnet-test-xunit": "2.2.0-*", "Microsoft.AspNetCore.HttpOverrides": "1.1.0-*", "Microsoft.AspNetCore.TestHost": "1.1.0-*", "Microsoft.Extensions.Logging.Testing": "1.1.0-*", - "xunit": "2.1.0" + "xunit": "2.2.0-*" }, "frameworks": { "netcoreapp1.0": { @@ -16,23 +16,10 @@ "Microsoft.NETCore.App": { "version": "1.0.0-*", "type": "platform" - }, - "System.Diagnostics.Process": "4.1.0-*" - }, - "imports": [ - "dnxcore50", - "portable-net451+win8" - ] - }, - "net451": { - "frameworkAssemblies": { - "System.Runtime": "", - "System.Threading.Tasks": "" - }, - "dependencies": { - "xunit.runner.console": "2.1.0" + } } - } + }, + "net451": {} }, "testRunner": "xunit" } \ No newline at end of file From bc8785395c2b5508032552890e5073d3f29b0185 Mon Sep 17 00:00:00 2001 From: Doug Bunting Date: Wed, 6 Jul 2016 21:44:53 -0700 Subject: [PATCH 078/307] One build to rule them all - well, at least VS and command-line builds will share output - part of aspnet/Coherence-Signed#277 --- samples/HttpOverridesSample/HttpOverridesSample.xproj | 5 +++-- .../ResponseBufferingSample/ResponseBufferingSample.xproj | 4 ++-- .../Microsoft.AspNetCore.Buffering.xproj | 4 ++-- .../Microsoft.AspNetCore.HttpOverrides.xproj | 4 ++-- .../Microsoft.AspNetCore.Buffering.Tests.xproj | 4 ++-- .../Microsoft.AspNetCore.HttpOverrides.Tests.xproj | 4 ++-- 6 files changed, 13 insertions(+), 12 deletions(-) diff --git a/samples/HttpOverridesSample/HttpOverridesSample.xproj b/samples/HttpOverridesSample/HttpOverridesSample.xproj index fc39e4566a..41dce8ef60 100644 --- a/samples/HttpOverridesSample/HttpOverridesSample.xproj +++ b/samples/HttpOverridesSample/HttpOverridesSample.xproj @@ -7,8 +7,8 @@ 7f95478d-e1d4-4a64-ba42-b041591a96eb - ..\..\artifacts\obj\$(MSBuildProjectName) - ..\..\artifacts\bin\ + .\obj + .\bin\ 2.0 @@ -17,6 +17,7 @@ + \ No newline at end of file diff --git a/samples/ResponseBufferingSample/ResponseBufferingSample.xproj b/samples/ResponseBufferingSample/ResponseBufferingSample.xproj index 485106b921..b9333376fc 100644 --- a/samples/ResponseBufferingSample/ResponseBufferingSample.xproj +++ b/samples/ResponseBufferingSample/ResponseBufferingSample.xproj @@ -7,8 +7,8 @@ e5c55b80-7827-40eb-b661-32b0e0e431ca - ..\..\artifacts\obj\$(MSBuildProjectName) - ..\..\artifacts\bin\ + .\obj + .\bin\ 2.0 diff --git a/src/Microsoft.AspNetCore.Buffering/Microsoft.AspNetCore.Buffering.xproj b/src/Microsoft.AspNetCore.Buffering/Microsoft.AspNetCore.Buffering.xproj index 53319c86ce..ad20072851 100644 --- a/src/Microsoft.AspNetCore.Buffering/Microsoft.AspNetCore.Buffering.xproj +++ b/src/Microsoft.AspNetCore.Buffering/Microsoft.AspNetCore.Buffering.xproj @@ -7,8 +7,8 @@ 2363d0dd-a3bf-437e-9b64-b33ae132d875 - ..\..\artifacts\obj\$(MSBuildProjectName) - ..\..\artifacts\bin\ + .\obj + .\bin\ 2.0 diff --git a/src/Microsoft.AspNetCore.HttpOverrides/Microsoft.AspNetCore.HttpOverrides.xproj b/src/Microsoft.AspNetCore.HttpOverrides/Microsoft.AspNetCore.HttpOverrides.xproj index 9020dedea8..fbfa940ddc 100644 --- a/src/Microsoft.AspNetCore.HttpOverrides/Microsoft.AspNetCore.HttpOverrides.xproj +++ b/src/Microsoft.AspNetCore.HttpOverrides/Microsoft.AspNetCore.HttpOverrides.xproj @@ -7,8 +7,8 @@ 517308c3-b477-4b01-b461-cab9c10b6928 - ..\..\artifacts\obj\$(MSBuildProjectName) - ..\..\artifacts\bin\ + .\obj + .\bin\ 2.0 diff --git a/test/Microsoft.AspNetCore.Buffering.Tests/Microsoft.AspNetCore.Buffering.Tests.xproj b/test/Microsoft.AspNetCore.Buffering.Tests/Microsoft.AspNetCore.Buffering.Tests.xproj index e4556bfec4..c3ffee43d6 100644 --- a/test/Microsoft.AspNetCore.Buffering.Tests/Microsoft.AspNetCore.Buffering.Tests.xproj +++ b/test/Microsoft.AspNetCore.Buffering.Tests/Microsoft.AspNetCore.Buffering.Tests.xproj @@ -7,8 +7,8 @@ f5f1d123-9c81-4a9e-8644-aa46b8e578fb - ..\..\artifacts\obj\$(MSBuildProjectName) - ..\..\artifacts\bin\ + .\obj + .\bin\ 2.0 diff --git a/test/Microsoft.AspNetCore.HttpOverrides.Tests/Microsoft.AspNetCore.HttpOverrides.Tests.xproj b/test/Microsoft.AspNetCore.HttpOverrides.Tests/Microsoft.AspNetCore.HttpOverrides.Tests.xproj index ac56f6d1f2..117f3f01e7 100644 --- a/test/Microsoft.AspNetCore.HttpOverrides.Tests/Microsoft.AspNetCore.HttpOverrides.Tests.xproj +++ b/test/Microsoft.AspNetCore.HttpOverrides.Tests/Microsoft.AspNetCore.HttpOverrides.Tests.xproj @@ -7,8 +7,8 @@ d6341b92-3416-4f11-8df4-cb274296175f - ..\..\artifacts\obj\$(MSBuildProjectName) - ..\..\artifacts\bin\ + .\obj + .\bin\ 2.0 From d3816fa458b83603b9e0848baccb1772ab967402 Mon Sep 17 00:00:00 2001 From: BrennanConroy Date: Mon, 25 Jul 2016 10:02:59 -0700 Subject: [PATCH 079/307] Make middleware issues more discoverable --- .../ForwardedHeadersMiddleware.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Microsoft.AspNetCore.HttpOverrides/ForwardedHeadersMiddleware.cs b/src/Microsoft.AspNetCore.HttpOverrides/ForwardedHeadersMiddleware.cs index 420ed7e3fd..09cdfce9ca 100644 --- a/src/Microsoft.AspNetCore.HttpOverrides/ForwardedHeadersMiddleware.cs +++ b/src/Microsoft.AspNetCore.HttpOverrides/ForwardedHeadersMiddleware.cs @@ -74,7 +74,7 @@ namespace Microsoft.AspNetCore.HttpOverrides forwardedProto = context.Request.Headers.GetCommaSeparatedValues(XForwardedProtoHeaderName); if (_options.RequireHeaderSymmetry && checkFor && forwardedFor.Length != forwardedProto.Length) { - _logger.LogDebug(1, "Parameter count mismatch between X-Forwarded-For and X-Forwarded-Proto."); + _logger.LogWarning(1, "Parameter count mismatch between X-Forwarded-For and X-Forwarded-Proto."); return; } entryCount = Math.Max(forwardedProto.Length, entryCount); @@ -88,7 +88,7 @@ namespace Microsoft.AspNetCore.HttpOverrides && ((checkFor && forwardedFor.Length != forwardedHost.Length) || (checkProto && forwardedProto.Length != forwardedHost.Length))) { - _logger.LogDebug(1, "Parameter count mismatch between X-Forwarded-Host and X-Forwarded-For or X-Forwarded-Proto."); + _logger.LogWarning(1, "Parameter count mismatch between X-Forwarded-Host and X-Forwarded-For or X-Forwarded-Proto."); return; } entryCount = Math.Max(forwardedHost.Length, entryCount); @@ -157,7 +157,7 @@ namespace Microsoft.AspNetCore.HttpOverrides } else if (_options.RequireHeaderSymmetry) { - _logger.LogDebug(2, $"Failed to parse forwarded IPAddress: {currentValues.IpAndPortText}"); + _logger.LogWarning(2, $"Failed to parse forwarded IPAddress: {currentValues.IpAndPortText}"); return; } } @@ -171,7 +171,7 @@ namespace Microsoft.AspNetCore.HttpOverrides } else if (_options.RequireHeaderSymmetry) { - _logger.LogDebug(3, $"Failed to parse forwarded scheme: {set.Scheme}"); + _logger.LogWarning(3, $"Forwarded scheme is not present, this is required by {nameof(_options.RequireHeaderSymmetry)}"); return; } } @@ -185,7 +185,7 @@ namespace Microsoft.AspNetCore.HttpOverrides } else if (_options.RequireHeaderSymmetry) { - _logger.LogDebug(4, $"Failed to parse forwarded host: {set.Host}"); + _logger.LogWarning(4, $"Incorrect number of x-forwarded-proto header values, see {nameof(_options.RequireHeaderSymmetry)}."); return; } } From a9c2656404727d1be6a7ceb3a836f2d3a48a3ef2 Mon Sep 17 00:00:00 2001 From: Justin Kotalik Date: Fri, 15 Jul 2016 15:42:42 -0700 Subject: [PATCH 080/307] Url Rewrite WIP --- BasicMiddleware.sln | 24 +- .../RewriteSample/Properties/AssemblyInfo.cs | 19 ++ samples/RewriteSample/Rewrite.txt | 12 + samples/RewriteSample/RewriteSample.xproj | 21 ++ samples/RewriteSample/Startup.cs | 29 ++ samples/RewriteSample/project.json | 32 ++ .../Microsoft.AspNetCore.Rewrite.xproj | 21 ++ .../ModRewrite/Condition.cs | 18 ++ .../ModRewrite/ConditionBuilder.cs | 94 ++++++ .../ModRewrite/ConditionExpression.cs | 29 ++ .../ModRewrite/ConditionFlagType.cs | 12 + .../ModRewrite/ConditionFlags.cs | 101 +++++++ .../ModRewrite/ConditionPatternParser.cs | 230 +++++++++++++++ .../ModRewrite/ConditionTestStringParser.cs | 205 +++++++++++++ .../ModRewrite/ConditionType.cs | 13 + .../ModRewrite/ExpressionCreator.cs | 128 ++++++++ .../ModRewrite/FileParser.cs | 103 +++++++ .../ModRewrite/FlagParser.cs | 103 +++++++ .../ModRewrite/ModRewriteExtensions.cs | 73 +++++ .../ModRewrite/ModRewriteRule.cs | 209 +++++++++++++ .../ModRewrite/OperationType.cs | 23 ++ .../ModRewrite/ParsedConditionExpression.cs | 22 ++ .../ModRewrite/Pattern.cs | 69 +++++ .../ModRewrite/PatternSegment.cs | 26 ++ .../ModRewrite/RuleBuilder.cs | 122 ++++++++ .../ModRewrite/RuleFlagType.cs | 35 +++ .../ModRewrite/RuleFlags.cs | 133 +++++++++ .../ModRewrite/RuleRegexParser.cs | 26 ++ .../ModRewrite/SegmentType.cs | 13 + .../ModRewrite/ServerVariables.cs | 180 ++++++++++++ .../ModRewrite/Tokenizer.cs | 84 ++++++ .../Operands/IntegerOperand.cs | 57 ++++ .../Operands/IntegerOperation.cs | 15 + .../Operands/Operand.cs | 13 + .../Operands/PropertyOperand.cs | 44 +++ .../Operands/PropertyOperation.cs | 17 ++ .../Operands/RegexOperand.cs | 24 ++ .../Operands/StringOperand.cs | 40 +++ .../Operands/StringOperation.cs | 14 + .../ParserContext.cs | 70 +++++ .../Properties/AssemblyInfo.cs | 19 ++ .../RuleAbstraction/FunctionalRule.cs | 14 + .../RuleAbstraction/PathRule.cs | 48 +++ .../RuleAbstraction/Rule.cs | 11 + .../RuleAbstraction/RuleExpression.cs | 13 + .../RuleAbstraction/RuleResult.cs | 10 + .../RuleAbstraction/RuleTermination.cs | 14 + .../RuleAbstraction/SchemeRule.cs | 54 ++++ .../RuleAbstraction/Transformation.cs | 12 + .../UrlRewriteContext.cs | 17 ++ .../UrlRewriteExtensions.cs | 35 +++ .../UrlRewriteMiddleware.cs | 76 +++++ .../UrlRewriteOptions.cs | 21 ++ .../UrlRewriteOptionsAddRulesExtensions.cs | 108 +++++++ src/Microsoft.AspNetCore.Rewrite/project.json | 37 +++ .../IPNetworkTest.cs | 1 - .../ConditionActionTest.cs | 99 +++++++ .../FlagParserTest.cs | 58 ++++ .../Microsoft.AspNetCore.Rewrite.Tests.xproj | 22 ++ .../ModRewriteConditionBuilderTest.cs | 50 ++++ .../ModRewriteCreatorTest.cs | 9 + .../ModRewriteFlagTest.cs | 88 ++++++ .../ModRewriteMiddlewareTest.cs | 278 ++++++++++++++++++ .../ModRewriteRuleBuilderTest.cs | 14 + .../Properties/AssemblyInfo.cs | 19 ++ .../Rewrite2MiddlewareTests.cs | 92 ++++++ .../RewriteTokenizerTest.cs | 39 +++ .../RuleAbstraction/RuleRegexParserTest.cs | 33 +++ .../project.json | 25 ++ 69 files changed, 3816 insertions(+), 3 deletions(-) create mode 100644 samples/RewriteSample/Properties/AssemblyInfo.cs create mode 100644 samples/RewriteSample/Rewrite.txt create mode 100644 samples/RewriteSample/RewriteSample.xproj create mode 100644 samples/RewriteSample/Startup.cs create mode 100644 samples/RewriteSample/project.json create mode 100644 src/Microsoft.AspNetCore.Rewrite/Microsoft.AspNetCore.Rewrite.xproj create mode 100644 src/Microsoft.AspNetCore.Rewrite/ModRewrite/Condition.cs create mode 100644 src/Microsoft.AspNetCore.Rewrite/ModRewrite/ConditionBuilder.cs create mode 100644 src/Microsoft.AspNetCore.Rewrite/ModRewrite/ConditionExpression.cs create mode 100644 src/Microsoft.AspNetCore.Rewrite/ModRewrite/ConditionFlagType.cs create mode 100644 src/Microsoft.AspNetCore.Rewrite/ModRewrite/ConditionFlags.cs create mode 100644 src/Microsoft.AspNetCore.Rewrite/ModRewrite/ConditionPatternParser.cs create mode 100644 src/Microsoft.AspNetCore.Rewrite/ModRewrite/ConditionTestStringParser.cs create mode 100644 src/Microsoft.AspNetCore.Rewrite/ModRewrite/ConditionType.cs create mode 100644 src/Microsoft.AspNetCore.Rewrite/ModRewrite/ExpressionCreator.cs create mode 100644 src/Microsoft.AspNetCore.Rewrite/ModRewrite/FileParser.cs create mode 100644 src/Microsoft.AspNetCore.Rewrite/ModRewrite/FlagParser.cs create mode 100644 src/Microsoft.AspNetCore.Rewrite/ModRewrite/ModRewriteExtensions.cs create mode 100644 src/Microsoft.AspNetCore.Rewrite/ModRewrite/ModRewriteRule.cs create mode 100644 src/Microsoft.AspNetCore.Rewrite/ModRewrite/OperationType.cs create mode 100644 src/Microsoft.AspNetCore.Rewrite/ModRewrite/ParsedConditionExpression.cs create mode 100644 src/Microsoft.AspNetCore.Rewrite/ModRewrite/Pattern.cs create mode 100644 src/Microsoft.AspNetCore.Rewrite/ModRewrite/PatternSegment.cs create mode 100644 src/Microsoft.AspNetCore.Rewrite/ModRewrite/RuleBuilder.cs create mode 100644 src/Microsoft.AspNetCore.Rewrite/ModRewrite/RuleFlagType.cs create mode 100644 src/Microsoft.AspNetCore.Rewrite/ModRewrite/RuleFlags.cs create mode 100644 src/Microsoft.AspNetCore.Rewrite/ModRewrite/RuleRegexParser.cs create mode 100644 src/Microsoft.AspNetCore.Rewrite/ModRewrite/SegmentType.cs create mode 100644 src/Microsoft.AspNetCore.Rewrite/ModRewrite/ServerVariables.cs create mode 100644 src/Microsoft.AspNetCore.Rewrite/ModRewrite/Tokenizer.cs create mode 100644 src/Microsoft.AspNetCore.Rewrite/Operands/IntegerOperand.cs create mode 100644 src/Microsoft.AspNetCore.Rewrite/Operands/IntegerOperation.cs create mode 100644 src/Microsoft.AspNetCore.Rewrite/Operands/Operand.cs create mode 100644 src/Microsoft.AspNetCore.Rewrite/Operands/PropertyOperand.cs create mode 100644 src/Microsoft.AspNetCore.Rewrite/Operands/PropertyOperation.cs create mode 100644 src/Microsoft.AspNetCore.Rewrite/Operands/RegexOperand.cs create mode 100644 src/Microsoft.AspNetCore.Rewrite/Operands/StringOperand.cs create mode 100644 src/Microsoft.AspNetCore.Rewrite/Operands/StringOperation.cs create mode 100644 src/Microsoft.AspNetCore.Rewrite/ParserContext.cs create mode 100644 src/Microsoft.AspNetCore.Rewrite/Properties/AssemblyInfo.cs create mode 100644 src/Microsoft.AspNetCore.Rewrite/RuleAbstraction/FunctionalRule.cs create mode 100644 src/Microsoft.AspNetCore.Rewrite/RuleAbstraction/PathRule.cs create mode 100644 src/Microsoft.AspNetCore.Rewrite/RuleAbstraction/Rule.cs create mode 100644 src/Microsoft.AspNetCore.Rewrite/RuleAbstraction/RuleExpression.cs create mode 100644 src/Microsoft.AspNetCore.Rewrite/RuleAbstraction/RuleResult.cs create mode 100644 src/Microsoft.AspNetCore.Rewrite/RuleAbstraction/RuleTermination.cs create mode 100644 src/Microsoft.AspNetCore.Rewrite/RuleAbstraction/SchemeRule.cs create mode 100644 src/Microsoft.AspNetCore.Rewrite/RuleAbstraction/Transformation.cs create mode 100644 src/Microsoft.AspNetCore.Rewrite/UrlRewriteContext.cs create mode 100644 src/Microsoft.AspNetCore.Rewrite/UrlRewriteExtensions.cs create mode 100644 src/Microsoft.AspNetCore.Rewrite/UrlRewriteMiddleware.cs create mode 100644 src/Microsoft.AspNetCore.Rewrite/UrlRewriteOptions.cs create mode 100644 src/Microsoft.AspNetCore.Rewrite/UrlRewriteOptionsAddRulesExtensions.cs create mode 100644 src/Microsoft.AspNetCore.Rewrite/project.json create mode 100644 test/Microsoft.AspNetCore.Rewrite.Tests/ConditionActionTest.cs create mode 100644 test/Microsoft.AspNetCore.Rewrite.Tests/FlagParserTest.cs create mode 100644 test/Microsoft.AspNetCore.Rewrite.Tests/Microsoft.AspNetCore.Rewrite.Tests.xproj create mode 100644 test/Microsoft.AspNetCore.Rewrite.Tests/ModRewriteConditionBuilderTest.cs create mode 100644 test/Microsoft.AspNetCore.Rewrite.Tests/ModRewriteCreatorTest.cs create mode 100644 test/Microsoft.AspNetCore.Rewrite.Tests/ModRewriteFlagTest.cs create mode 100644 test/Microsoft.AspNetCore.Rewrite.Tests/ModRewriteMiddlewareTest.cs create mode 100644 test/Microsoft.AspNetCore.Rewrite.Tests/ModRewriteRuleBuilderTest.cs create mode 100644 test/Microsoft.AspNetCore.Rewrite.Tests/Properties/AssemblyInfo.cs create mode 100644 test/Microsoft.AspNetCore.Rewrite.Tests/Rewrite2MiddlewareTests.cs create mode 100644 test/Microsoft.AspNetCore.Rewrite.Tests/RewriteTokenizerTest.cs create mode 100644 test/Microsoft.AspNetCore.Rewrite.Tests/RuleAbstraction/RuleRegexParserTest.cs create mode 100644 test/Microsoft.AspNetCore.Rewrite.Tests/project.json diff --git a/BasicMiddleware.sln b/BasicMiddleware.sln index 5dcf6b1d8f..9ac27d55d2 100644 --- a/BasicMiddleware.sln +++ b/BasicMiddleware.sln @@ -1,7 +1,6 @@ - Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 14 -VisualStudioVersion = 14.0.24720.0 +VisualStudioVersion = 14.0.25420.1 MinimumVisualStudioVersion = 10.0.40219.1 Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNetCore.HttpOverrides", "src\Microsoft.AspNetCore.HttpOverrides\Microsoft.AspNetCore.HttpOverrides.xproj", "{517308C3-B477-4B01-B461-CAB9C10B6928}" EndProject @@ -26,6 +25,12 @@ Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "ResponseBufferingSample", " EndProject Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "HttpOverridesSample", "samples\HttpOverridesSample\HttpOverridesSample.xproj", "{7F95478D-E1D4-4A64-BA42-B041591A96EB}" EndProject +Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNetCore.Rewrite", "src\Microsoft.AspNetCore.Rewrite\Microsoft.AspNetCore.Rewrite.xproj", "{0E7CA1A7-1DC3-4CE6-B9C7-1688FE1410F1}" +EndProject +Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "RewriteSample", "samples\RewriteSample\RewriteSample.xproj", "{9E049645-13BC-4598-89E1-5B43D36E5D14}" +EndProject +Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNetCore.Rewrite.Tests", "test\Microsoft.AspNetCore.Rewrite.Tests\Microsoft.AspNetCore.Rewrite.Tests.xproj", "{31794F9E-A1AA-4535-B03C-A3233737CD1A}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -56,6 +61,18 @@ Global {7F95478D-E1D4-4A64-BA42-B041591A96EB}.Debug|Any CPU.Build.0 = Debug|Any CPU {7F95478D-E1D4-4A64-BA42-B041591A96EB}.Release|Any CPU.ActiveCfg = Release|Any CPU {7F95478D-E1D4-4A64-BA42-B041591A96EB}.Release|Any CPU.Build.0 = Release|Any CPU + {0E7CA1A7-1DC3-4CE6-B9C7-1688FE1410F1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {0E7CA1A7-1DC3-4CE6-B9C7-1688FE1410F1}.Debug|Any CPU.Build.0 = Debug|Any CPU + {0E7CA1A7-1DC3-4CE6-B9C7-1688FE1410F1}.Release|Any CPU.ActiveCfg = Release|Any CPU + {0E7CA1A7-1DC3-4CE6-B9C7-1688FE1410F1}.Release|Any CPU.Build.0 = Release|Any CPU + {9E049645-13BC-4598-89E1-5B43D36E5D14}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9E049645-13BC-4598-89E1-5B43D36E5D14}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9E049645-13BC-4598-89E1-5B43D36E5D14}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9E049645-13BC-4598-89E1-5B43D36E5D14}.Release|Any CPU.Build.0 = Release|Any CPU + {31794F9E-A1AA-4535-B03C-A3233737CD1A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {31794F9E-A1AA-4535-B03C-A3233737CD1A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {31794F9E-A1AA-4535-B03C-A3233737CD1A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {31794F9E-A1AA-4535-B03C-A3233737CD1A}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -67,5 +84,8 @@ Global {F5F1D123-9C81-4A9E-8644-AA46B8E578FB} = {8437B0F3-3894-4828-A945-A9187F37631D} {E5C55B80-7827-40EB-B661-32B0E0E431CA} = {9587FE9F-5A17-42C4-8021-E87F59CECB98} {7F95478D-E1D4-4A64-BA42-B041591A96EB} = {9587FE9F-5A17-42C4-8021-E87F59CECB98} + {0E7CA1A7-1DC3-4CE6-B9C7-1688FE1410F1} = {A5076D28-FA7E-4606-9410-FEDD0D603527} + {9E049645-13BC-4598-89E1-5B43D36E5D14} = {9587FE9F-5A17-42C4-8021-E87F59CECB98} + {31794F9E-A1AA-4535-B03C-A3233737CD1A} = {8437B0F3-3894-4828-A945-A9187F37631D} EndGlobalSection EndGlobal diff --git a/samples/RewriteSample/Properties/AssemblyInfo.cs b/samples/RewriteSample/Properties/AssemblyInfo.cs new file mode 100644 index 0000000000..22fae21612 --- /dev/null +++ b/samples/RewriteSample/Properties/AssemblyInfo.cs @@ -0,0 +1,19 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("RewriteSample")] +[assembly: AssemblyTrademark("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("9e049645-13bc-4598-89e1-5b43d36e5d14")] diff --git a/samples/RewriteSample/Rewrite.txt b/samples/RewriteSample/Rewrite.txt new file mode 100644 index 0000000000..fdc4175f86 --- /dev/null +++ b/samples/RewriteSample/Rewrite.txt @@ -0,0 +1,12 @@ +# Ensure Https +RewriteCond %{REQUEST_URI} ^foo/ +RewriteCond %{HTTPS} off +# U is a new flag to represent full URL rewrites +RewriteRule ^(.*)$ https://www.example.com$1 [L,U] + +# Rewrite path with additional sub directory +RewriteRule ^(.*)$ /foo$1 + +# Forbid a certain url from being accessed +RewriteRule /bar - [F] +RewriteRule /bar/ - [F] diff --git a/samples/RewriteSample/RewriteSample.xproj b/samples/RewriteSample/RewriteSample.xproj new file mode 100644 index 0000000000..542c81359a --- /dev/null +++ b/samples/RewriteSample/RewriteSample.xproj @@ -0,0 +1,21 @@ + + + + 14.0 + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) + + + + + 9e049645-13bc-4598-89e1-5b43d36e5d14 + RewriteSample + .\obj + .\bin\ + v4.5.2 + + + + 2.0 + + + diff --git a/samples/RewriteSample/Startup.cs b/samples/RewriteSample/Startup.cs new file mode 100644 index 0000000000..3c30c0e6cf --- /dev/null +++ b/samples/RewriteSample/Startup.cs @@ -0,0 +1,29 @@ +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.Configuration; +using Microsoft.AspNetCore.Rewrite; +using Microsoft.Extensions.DependencyInjection; + +namespace RewriteSample +{ + public class Startup + { + public void Configure(IApplicationBuilder app) + { + app.UseRewriter(new UrlRewriteOptions() + .ImportFromModRewrite("Rewrite.txt")); + app.Run(context => context.Response.WriteAsync(context.Request.Path)); + } + + public static void Main(string[] args) + { + var host = new WebHostBuilder() + .UseKestrel() + .UseStartup() + .Build(); + + host.Run(); + } + } +} diff --git a/samples/RewriteSample/project.json b/samples/RewriteSample/project.json new file mode 100644 index 0000000000..3bca09f40e --- /dev/null +++ b/samples/RewriteSample/project.json @@ -0,0 +1,32 @@ +{ + "version": "1.1.0-*", + "dependencies": { + "Microsoft.AspNetCore.Rewrite": "1.1.0-*", + "Microsoft.AspNetCore.Server.Kestrel": "1.1.0-*", + "Microsoft.AspNetCore.StaticFiles": "1.1.0-*" + }, + "buildOptions": { + "emitEntryPoint": true, + "preserveCompilationContext": true + }, + "frameworks": { + "net451": {}, + "netcoreapp1.0": { + "dependencies": { + "Microsoft.NETCore.App": { + "version": "1.0.0-*", + "type": "platform" + } + } + } + }, + "publish": { + "exclude": [ + "node_modules", + "bower_components", + "**.xproj", + "**.user", + "**.vspscc" + ] + } +} diff --git a/src/Microsoft.AspNetCore.Rewrite/Microsoft.AspNetCore.Rewrite.xproj b/src/Microsoft.AspNetCore.Rewrite/Microsoft.AspNetCore.Rewrite.xproj new file mode 100644 index 0000000000..fbaad5c7ae --- /dev/null +++ b/src/Microsoft.AspNetCore.Rewrite/Microsoft.AspNetCore.Rewrite.xproj @@ -0,0 +1,21 @@ + + + + 14.0 + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) + + + + + 0e7ca1a7-1dc3-4ce6-b9c7-1688fe1410f1 + Microsoft.AspNetCore.Rewrite + .\obj + .\bin\ + v4.5.2 + + + + 2.0 + + + diff --git a/src/Microsoft.AspNetCore.Rewrite/ModRewrite/Condition.cs b/src/Microsoft.AspNetCore.Rewrite/ModRewrite/Condition.cs new file mode 100644 index 0000000000..f3940ecaea --- /dev/null +++ b/src/Microsoft.AspNetCore.Rewrite/ModRewrite/Condition.cs @@ -0,0 +1,18 @@ +// 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. + +namespace Microsoft.AspNetCore.Rewrite.ModRewrite +{ + public class Condition + { + public Pattern TestStringSegments { get; } + public ConditionExpression ConditionExpression { get; } + public ConditionFlags Flags { get; } + public Condition(Pattern testStringSegments, ConditionExpression conditionRegex, ConditionFlags flags) + { + TestStringSegments = testStringSegments; + ConditionExpression = conditionRegex; + Flags = flags; + } + } +} diff --git a/src/Microsoft.AspNetCore.Rewrite/ModRewrite/ConditionBuilder.cs b/src/Microsoft.AspNetCore.Rewrite/ModRewrite/ConditionBuilder.cs new file mode 100644 index 0000000000..109b3b59e1 --- /dev/null +++ b/src/Microsoft.AspNetCore.Rewrite/ModRewrite/ConditionBuilder.cs @@ -0,0 +1,94 @@ +// 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; + +namespace Microsoft.AspNetCore.Rewrite.ModRewrite +{ + public class ConditionBuilder + { + private Pattern _testString; + private ParsedModRewriteExpression _pce; + private ConditionFlags _flags; + + public ConditionBuilder(string conditionString) + { + var tokens = Tokenizer.Tokenize(conditionString); + if (tokens.Count == 3) + { + CreateCondition(tokens[1], tokens[2], flagsString: null); + } + else if (tokens.Count == 4) + { + CreateCondition(tokens[1], tokens[2], tokens[3]); + } + else + { + throw new FormatException("Invalid number of tokens."); + } + } + + public ConditionBuilder(string testString, string condition) + { + CreateCondition(testString, condition, flagsString: null); + } + + public ConditionBuilder(string testString, string condition, string flags) + { + CreateCondition(testString, condition, flags); + } + + public Condition Build() + { + var expression = ExpressionCreator.CreateConditionExpression(_pce, _flags); + return new Condition(_testString, expression, _flags); + } + + private void CreateCondition(string testString, string condition, string flagsString) + { + _testString = ConditionTestStringParser.ParseConditionTestString(testString); + _pce = ConditionPatternParser.ParseActionCondition(condition); + _flags = FlagParser.ParseConditionFlags(flagsString); + } + + public void SetFlag(string flag) + { + SetFlag(flag, value: null); + } + + public void SetFlag(ConditionFlagType flag) + { + SetFlag(flag, value: null); + } + + public void SetFlag(string flag, string value) + { + if (_flags == null) + { + _flags = new ConditionFlags(); + } + _flags.SetFlag(flag, value); + } + + public void SetFlag(ConditionFlagType flag, string value) + { + if (_flags == null) + { + _flags = new ConditionFlags(); + } + _flags.SetFlag(flag, value); + } + + public void SetFlags(string flags) + { + if (_flags == null) + { + _flags = FlagParser.ParseConditionFlags(flags); + } + else + { + FlagParser.ParseConditionFlags(flags, _flags); + } + } + } +} diff --git a/src/Microsoft.AspNetCore.Rewrite/ModRewrite/ConditionExpression.cs b/src/Microsoft.AspNetCore.Rewrite/ModRewrite/ConditionExpression.cs new file mode 100644 index 0000000000..85222ba020 --- /dev/null +++ b/src/Microsoft.AspNetCore.Rewrite/ModRewrite/ConditionExpression.cs @@ -0,0 +1,29 @@ +// 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.Text.RegularExpressions; +using Microsoft.AspNetCore.Rewrite.Operands; + +namespace Microsoft.AspNetCore.Rewrite.ModRewrite +{ + /// + /// Represents the ConditionPattern for a mod_rewrite rule. + /// + public class ConditionExpression + { + public Operand Operand { get; set; } + public bool Invert { get; set; } + + /// + /// Checks if a condition matches the context. + /// + /// The UrlRewriteContext. + /// The previous condition results (for backreferences). + /// The testString created from the . + /// If the testString satisfies the condition + public bool? CheckConditionExpression(UrlRewriteContext context, Match previous, string testString) + { + return Operand.CheckOperation(previous, testString, context.FileProvider) ^ Invert; + } + } +} diff --git a/src/Microsoft.AspNetCore.Rewrite/ModRewrite/ConditionFlagType.cs b/src/Microsoft.AspNetCore.Rewrite/ModRewrite/ConditionFlagType.cs new file mode 100644 index 0000000000..e1b650e8c0 --- /dev/null +++ b/src/Microsoft.AspNetCore.Rewrite/ModRewrite/ConditionFlagType.cs @@ -0,0 +1,12 @@ +// 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. + +namespace Microsoft.AspNetCore.Rewrite.ModRewrite +{ + public enum ConditionFlagType + { + NoCase, + Or, + NoVary + } +} diff --git a/src/Microsoft.AspNetCore.Rewrite/ModRewrite/ConditionFlags.cs b/src/Microsoft.AspNetCore.Rewrite/ModRewrite/ConditionFlags.cs new file mode 100644 index 0000000000..143e008403 --- /dev/null +++ b/src/Microsoft.AspNetCore.Rewrite/ModRewrite/ConditionFlags.cs @@ -0,0 +1,101 @@ +// 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; +using System.Collections.Generic; + +namespace Microsoft.AspNetCore.Rewrite.ModRewrite +{ + // TODO Refactor Condition Flags and Rule Flags under base flag class + public class ConditionFlags + { + private IDictionary _conditionFlagLookup = new Dictionary(StringComparer.OrdinalIgnoreCase) { + { "nc", ConditionFlagType.NoCase}, + { "nocase", ConditionFlagType.NoCase }, + { "or", ConditionFlagType.Or}, + { "ornext", ConditionFlagType.Or }, + { "nv", ConditionFlagType.NoVary}, + { "novary", ConditionFlagType.NoVary} + }; + + public IDictionary FlagDictionary { get; } + + public ConditionFlags(IDictionary flags) + { + FlagDictionary = flags; + } + + public ConditionFlags() + { + FlagDictionary = new Dictionary(); + } + public void SetFlag(string flag) + { + SetFlag(flag, null); + } + + public void SetFlag(string flag, string value) + { + ConditionFlagType res; + if (!_conditionFlagLookup.TryGetValue(flag, out res)) + { + throw new ArgumentException("Invalid flag"); + } + SetFlag(res, value); + } + + public void SetFlag(ConditionFlagType flag, string value) + { + if (value == null) + { + value = string.Empty; + } + FlagDictionary[flag] = value; + } + + public string GetFlag(ConditionFlagType flag) + { + CleanupResources(); + string res; + if (!FlagDictionary.TryGetValue(flag, out res)) + { + return null; + } + return res; + } + + public string this[ConditionFlagType flag] + { + get + { + string res; + if (!FlagDictionary.TryGetValue(flag, out res)) + { + return null; + } + return res; + } + set + { + FlagDictionary[flag] = value ?? string.Empty; + } + } + + public bool HasFlag(ConditionFlagType flag) + { + CleanupResources(); + string res; + return FlagDictionary.TryGetValue(flag, out res); + } + + // If this method is called, all flags have been processed, + // therefore to clean up memory, delete dictionary. + private void CleanupResources() + { + if (_conditionFlagLookup != null) + { + _conditionFlagLookup = null; + } + } + } +} diff --git a/src/Microsoft.AspNetCore.Rewrite/ModRewrite/ConditionPatternParser.cs b/src/Microsoft.AspNetCore.Rewrite/ModRewrite/ConditionPatternParser.cs new file mode 100644 index 0000000000..24cd7e67c5 --- /dev/null +++ b/src/Microsoft.AspNetCore.Rewrite/ModRewrite/ConditionPatternParser.cs @@ -0,0 +1,230 @@ +// 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; +using Microsoft.AspNetCore.Rewrite.Internal; + +namespace Microsoft.AspNetCore.Rewrite.ModRewrite +{ + /// + /// Parses the "CondPattern" portion of the RewriteCond. + /// RewriteCond TestString CondPattern + /// + public static class ConditionPatternParser + { + private const char Not = '!'; + private const char Dash = '-'; + private const char Less = '<'; + private const char Greater = '>'; + private const char EqualSign = '='; + + /// + /// Given a CondPattern, create a ParsedConditionExpression, containing the type of operation + /// and value. + /// ParsedConditionExpression is an intermediary object, which will be made into a ConditionExpression + /// once the flags are parsed. + /// + /// The CondPattern portion of a mod_rewrite RewriteCond. + /// A new parsed condition. + public static ParsedModRewriteExpression ParseActionCondition(string condition) + { + if (condition == null) + { + condition = string.Empty; + } + var context = new ParserContext(condition); + var results = new ParsedModRewriteExpression(); + if (!context.Next()) + { + throw new FormatException(context.Error()); + } + + // If we hit a !, make sure the condition is inverted when resolving the string + if (context.Current == Not) + { + results.Invert = true; + if (!context.Next()) + { + throw new FormatException(context.Error()); + } + } + + // Control Block for strings. Set the operation and type fields based on the sign + switch (context.Current) + { + case Greater: + if (!context.Next()) + { + // Dangling ">" + throw new FormatException(context.Error()); + } + if (context.Current == EqualSign) + { + if (!context.Next()) + { + // Dangling ">=" + throw new FormatException(context.Error()); + } + results.Operation = OperationType.GreaterEqual; + results.Type = ConditionType.StringComp; + } + else + { + results.Operation = OperationType.Greater; + results.Type = ConditionType.StringComp; + } + break; + case Less: + if (!context.Next()) + { + // Dangling "<" + throw new FormatException(context.Error()); + } + if (context.Current == EqualSign) + { + if (!context.Next()) + { + // Dangling "<=" + throw new FormatException(context.Error()); + } + results.Operation = OperationType.LessEqual; + results.Type = ConditionType.StringComp; + } + else + { + results.Operation = OperationType.Less; + results.Type = ConditionType.StringComp; + } + break; + case EqualSign: + if (!context.Next()) + { + // Dangling "=" + throw new FormatException(context.Error()); + } + results.Operation = OperationType.Equal; + results.Type = ConditionType.StringComp; + break; + case Dash: + results = ParseProperty(context, results.Invert); + if (results.Type == ConditionType.PropertyTest) + { + return results; + } + context.Next(); + break; + default: + results.Type = ConditionType.Regex; + break; + } + + // Capture the rest of the string guarantee validity. + results.Operand = (condition.Substring(context.GetIndex())); + if (IsValidActionCondition(results)) + { + return results; + } + else + { + throw new FormatException(context.Error()); + } + } + + /// + /// Given that the current index is a property (ex checks for directory or regular files), create a + /// new ParsedConditionExpression with the appropriate property operation. + /// + /// + /// + /// + public static ParsedModRewriteExpression ParseProperty(ParserContext context, bool invert) + { + if (!context.Next()) + { + throw new FormatException(context.Error()); + } + switch (context.Current) + { + case 'd': + return new ParsedModRewriteExpression(invert, ConditionType.PropertyTest, OperationType.Directory, null); + case 'f': + return new ParsedModRewriteExpression(invert, ConditionType.PropertyTest, OperationType.RegularFile, null); + case 'F': + return new ParsedModRewriteExpression(invert, ConditionType.PropertyTest, OperationType.ExistingFile, null); + case 'h': + case 'L': + return new ParsedModRewriteExpression(invert, ConditionType.PropertyTest, OperationType.SymbolicLink, null); + case 's': + return new ParsedModRewriteExpression(invert, ConditionType.PropertyTest, OperationType.Size, null); + case 'U': + return new ParsedModRewriteExpression(invert, ConditionType.PropertyTest, OperationType.ExistingUrl, null); + case 'x': + return new ParsedModRewriteExpression(invert, ConditionType.PropertyTest, OperationType.Executable, null); + case 'e': + + if (!context.Next() || context.Current != 'q') + { + // Illegal statement. + throw new FormatException(context.Error()); + } + return new ParsedModRewriteExpression(invert, ConditionType.IntComp, OperationType.Equal, null); + case 'g': + if (!context.Next()) + { + throw new FormatException(context.Error()); + } + if (context.Current == 't') + { + return new ParsedModRewriteExpression(invert, ConditionType.IntComp, OperationType.Greater, null); + } + else if (context.Current == 'e') + { + return new ParsedModRewriteExpression(invert, ConditionType.IntComp, OperationType.GreaterEqual, null); + } + else + { + throw new FormatException(context.Error()); + } + case 'l': + if (!context.Next()) + { + return new ParsedModRewriteExpression(invert, ConditionType.PropertyTest, OperationType.SymbolicLink, null); + } + if (context.Current == 't') + { + return new ParsedModRewriteExpression(invert, ConditionType.IntComp, OperationType.Less, null); + } + else if (context.Current == 'e') + { + return new ParsedModRewriteExpression(invert, ConditionType.IntComp, OperationType.LessEqual, null); + } + else + { + throw new FormatException(context.Error()); + } + case 'n': + if (!context.Next() || context.Current != 'e') + { + throw new FormatException(context.Error()); + } + return new ParsedModRewriteExpression(invert, ConditionType.IntComp, OperationType.NotEqual, null); + default: + throw new FormatException(context.Error()); + } + } + + private static bool IsValidActionCondition(ParsedModRewriteExpression results) + { + if (results.Type == ConditionType.IntComp) + { + // If the type is an integer, verify operand is actually an int + int res; + if (!int.TryParse(results.Operand, out res)) + { + return false; + } + } + return true; + } + } +} diff --git a/src/Microsoft.AspNetCore.Rewrite/ModRewrite/ConditionTestStringParser.cs b/src/Microsoft.AspNetCore.Rewrite/ModRewrite/ConditionTestStringParser.cs new file mode 100644 index 0000000000..04b16b649e --- /dev/null +++ b/src/Microsoft.AspNetCore.Rewrite/ModRewrite/ConditionTestStringParser.cs @@ -0,0 +1,205 @@ +// 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; +using System.Collections.Generic; +using Microsoft.AspNetCore.Rewrite.Internal; + +namespace Microsoft.AspNetCore.Rewrite.ModRewrite +{ + /// + /// Parses the TestString segment of the mod_rewrite condition. + /// + public class ConditionTestStringParser + { + private const char Percent = '%'; + private const char Dollar = '$'; + private const char Space = ' '; + private const char Colon = ':'; + private const char OpenBrace = '{'; + private const char CloseBrace = '}'; + + /// + /// Creates a pattern, which is a template to create a new test string to + /// compare to the condition pattern. Can contain server variables, back references, etc. + /// + /// The test string portion of the RewriteCond + /// Examples: + /// %{REMOTE_ADDR} + /// /var/www/%{REQUEST_URI} + /// %1 + /// $1 + /// A new , containing a list of + public static Pattern ParseConditionTestString(string testString) + { + if (testString == null) + { + testString = string.Empty; + } + var context = new ParserContext(testString); + var results = new List(); + while (context.Next()) + { + if (context.Current == Percent) + { + // This is a server parameter, parse for a condition variable + if (!context.Next()) + { + throw new FormatException(context.Error()); + } + if (!ParseConditionParameter(context, results)) + { + throw new FormatException(context.Error()); + } + } + else if (context.Current == Dollar) + { + // This is a parameter from the rule, verify that it is a number from 0 to 9 directly after it + // and create a new Pattern Segment. + if (!context.Next()) + { + throw new FormatException(context.Error()); + } + context.Mark(); + if (context.Current >= '0' && context.Current <= '9') + { + context.Next(); + var ruleVariable = context.Capture(); + context.Back(); + results.Add(new PatternSegment(ruleVariable, SegmentType.RuleParameter)); + } + else + { + throw new FormatException(context.Error()); + } + } + else + { + // Parse for literals, which will return on either the end of the test string + // or when it hits a special character + if (!ParseLiteral(context, results)) + { + throw new FormatException(context.Error()); + } + } + } + return new Pattern(results); + } + + /// + /// Obtains the condition parameter, which could either be a condition variable or a + /// server variable. Assumes the current character is immediately after the '%'. + /// context, on return will be on the last character of variable captured, such that after + /// Next() is called, it will be on the character immediately after the condition parameter. + /// + /// The ParserContext + /// The List of results which the new condition parameter will be added. + /// true + private static bool ParseConditionParameter(ParserContext context, List results) + { + // Parse { } + if (context.Current == OpenBrace) + { + // Start of a server variable + if (!context.Next()) + { + // Dangling { + return false; + } + context.Mark(); + while (context.Current != CloseBrace) + { + if (!context.Next()) + { + // No closing } for the server variable + return false; + } + else if (context.Current == Colon) + { + // Have a segmented look up Ex: HTTP:xxxx + // TODO + } + } + + // Need to verify server variable captured exists + var rawServerVariable = context.Capture(); + if (IsValidServerVariable(rawServerVariable)) + { + results.Add(new PatternSegment(rawServerVariable, SegmentType.ServerParameter)); + } + else + { + // invalid. + return false; + } + } + else if (context.Current >= '0' && context.Current <= '9') + { + // means we have a segmented lookup + // store information in the testString result to know what to look up. + context.Mark(); + context.Next(); + var rawConditionParameter = context.Capture(); + // Once we leave this method, the while loop will call next again. Because + // capture is exclusive, we need to go one past the end index, capture, and then go back. + context.Back(); + results.Add(new PatternSegment(rawConditionParameter, SegmentType.ConditionParameter)); + } + else + { + // illegal escape of a character + return false; + } + return true; + } + + /// + /// Parse a string literal in the test string. Continues capturing until the start of a new variable type. + /// + /// + /// + /// + private static bool ParseLiteral(ParserContext context, List results) + { + context.Mark(); + string literal; + while (true) + { + if (context.Current == Percent || context.Current == Dollar) + { + literal = context.Capture(); + context.Back(); + break; + } + if (!context.Next()) + { + literal = context.Capture(); + break; + } + } + + if (IsValidLiteral(context, literal)) + { + // add results + results.Add(new PatternSegment(literal, SegmentType.Literal)); + return true; + } + else + { + return false; + } + } + + private static bool IsValidLiteral(ParserContext context, string literal) + { + // TODO Once escape characters are discussed, figure this out. + return true; + } + + private static bool IsValidServerVariable(string variable) + { + // TODO Once escape characters are discussed, figure this out. + return ServerVariables.ValidServerVariables.Contains(variable); + } + } +} diff --git a/src/Microsoft.AspNetCore.Rewrite/ModRewrite/ConditionType.cs b/src/Microsoft.AspNetCore.Rewrite/ModRewrite/ConditionType.cs new file mode 100644 index 0000000000..e30325a8e5 --- /dev/null +++ b/src/Microsoft.AspNetCore.Rewrite/ModRewrite/ConditionType.cs @@ -0,0 +1,13 @@ +// 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. + +namespace Microsoft.AspNetCore.Rewrite.ModRewrite +{ + public enum ConditionType + { + Regex, + PropertyTest, + StringComp, + IntComp + } +} diff --git a/src/Microsoft.AspNetCore.Rewrite/ModRewrite/ExpressionCreator.cs b/src/Microsoft.AspNetCore.Rewrite/ModRewrite/ExpressionCreator.cs new file mode 100644 index 0000000000..886ccea5a1 --- /dev/null +++ b/src/Microsoft.AspNetCore.Rewrite/ModRewrite/ExpressionCreator.cs @@ -0,0 +1,128 @@ +// 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; +using System.Text.RegularExpressions; +using Microsoft.AspNetCore.Rewrite.Operands; +using Microsoft.AspNetCore.Rewrite.RuleAbstraction; + +namespace Microsoft.AspNetCore.Rewrite.ModRewrite +{ + /// + /// Converts a parsed expression into a mod_rewrite condition. + /// + public class ExpressionCreator + { + private static readonly TimeSpan RegexTimeout = TimeSpan.FromMilliseconds(1); + public static ConditionExpression CreateConditionExpression(ParsedModRewriteExpression pce, ConditionFlags flags) + { + var condExp = new ConditionExpression(); + condExp.Invert = pce.Invert; + if (pce.Type == ConditionType.Regex) + { + // TODO make nullable? + if (flags != null && flags.HasFlag(ConditionFlagType.NoCase)) + { + condExp.Operand = new RegexOperand(new Regex(pce.Operand, RegexOptions.IgnoreCase | RegexOptions.Compiled, RegexTimeout)); + } + else + { + condExp.Operand = new RegexOperand(new Regex(pce.Operand, RegexOptions.Compiled, RegexTimeout)); + } + } + else if (pce.Type == ConditionType.IntComp) + { + switch (pce.Operation) + { + case OperationType.Equal: + condExp.Operand = new IntegerOperand(pce.Operand, IntegerOperationType.Equal); + break; + case OperationType.Greater: + condExp.Operand = new IntegerOperand(pce.Operand, IntegerOperationType.Greater); + break; + case OperationType.GreaterEqual: + condExp.Operand = new IntegerOperand(pce.Operand, IntegerOperationType.GreaterEqual); + break; + case OperationType.Less: + condExp.Operand = new IntegerOperand(pce.Operand, IntegerOperationType.Less); + break; + case OperationType.LessEqual: + condExp.Operand = new IntegerOperand(pce.Operand, IntegerOperationType.LessEqual); + break; + case OperationType.NotEqual: + condExp.Operand = new IntegerOperand(pce.Operand, IntegerOperationType.NotEqual); + break; + default: + throw new ArgumentException("No defined operation for integer comparison."); + } + } + else if (pce.Type == ConditionType.StringComp) + { + switch (pce.Operation) + { + case OperationType.Equal: + condExp.Operand = new StringOperand(pce.Operand, StringOperationType.Equal); + break; + case OperationType.Greater: + condExp.Operand = new StringOperand(pce.Operand, StringOperationType.Greater); + break; + case OperationType.GreaterEqual: + condExp.Operand = new StringOperand(pce.Operand, StringOperationType.GreaterEqual); + break; + case OperationType.Less: + condExp.Operand = new StringOperand(pce.Operand, StringOperationType.Less); + break; + case OperationType.LessEqual: + condExp.Operand = new StringOperand(pce.Operand, StringOperationType.LessEqual); + break; + default: + throw new ArgumentException("No defined operation for string comparison."); + } + } + else + { + switch (pce.Operation) + { + case OperationType.Directory: + condExp.Operand = new PropertyOperand(PropertyOperationType.Directory); + break; + case OperationType.RegularFile: + condExp.Operand = new PropertyOperand(PropertyOperationType.RegularFile); + break; + case OperationType.ExistingFile: + condExp.Operand = new PropertyOperand(PropertyOperationType.ExistingFile); + break; + case OperationType.SymbolicLink: + condExp.Operand = new PropertyOperand(PropertyOperationType.SymbolicLink); + break; + case OperationType.Size: + condExp.Operand = new PropertyOperand(PropertyOperationType.Size); + break; + case OperationType.ExistingUrl: + condExp.Operand = new PropertyOperand(PropertyOperationType.ExistingUrl); + break; + case OperationType.Executable: + condExp.Operand = new PropertyOperand(PropertyOperationType.Executable); + break; + default: + throw new ArgumentException("No defined operation for property comparison."); + } + } + return condExp; + } + public static RuleExpression CreateRuleExpression(ParsedModRewriteExpression pce, RuleFlags flags) + { + var ruleExp = new RuleExpression(); + ruleExp.Invert = pce.Invert; + if (flags.HasFlag(RuleFlagType.NoCase)) + { + ruleExp.Operand = new RegexOperand(new Regex(pce.Operand, RegexOptions.IgnoreCase | RegexOptions.Compiled, RegexTimeout)); + } + else + { + ruleExp.Operand = new RegexOperand(new Regex(pce.Operand, RegexOptions.Compiled, RegexTimeout)); + } + return ruleExp; + } + } +} diff --git a/src/Microsoft.AspNetCore.Rewrite/ModRewrite/FileParser.cs b/src/Microsoft.AspNetCore.Rewrite/ModRewrite/FileParser.cs new file mode 100644 index 0000000000..201fba8834 --- /dev/null +++ b/src/Microsoft.AspNetCore.Rewrite/ModRewrite/FileParser.cs @@ -0,0 +1,103 @@ +// 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; +using System.Collections.Generic; +using System.IO; +using Microsoft.AspNetCore.Rewrite.RuleAbstraction; + +namespace Microsoft.AspNetCore.Rewrite.ModRewrite +{ + /// + /// + /// + public static class FileParser + { + public static List Parse(TextReader input) + { + string line = null; + var rules = new List(); + var conditions = new List(); + // TODO consider passing Itokenizer and Ifileparser and provide implementations + while ((line = input.ReadLine()) != null) + { + if (string.IsNullOrEmpty(line)) + { + continue; + } + if (line.StartsWith("#")) + { + continue; + } + var tokens = Tokenizer.Tokenize(line); + if (tokens.Count > 4) + { + // This means the line didn't have an appropriate format, throw format exception + throw new FormatException(); + } + // TODO make a new class called rule parser that does and either return an exception or return the rule. + switch (tokens[0]) + { + case "RewriteBase": + throw new NotSupportedException(); + //if (tokens.Count == 2) + //{ + // ModRewriteBase.Base = tokens[1]; + //} + //else + //{ + // throw new FormatException(""); + //} + //break; + case "RewriteCond": + { + ConditionBuilder builder = null; + if (tokens.Count == 3) + { + builder = new ConditionBuilder(tokens[1], tokens[2]); + } + else if (tokens.Count == 4) + { + builder = new ConditionBuilder(tokens[1], tokens[2], tokens[3]); + } + else + { + throw new FormatException(); + } + conditions.Add(builder.Build()); + break; + } + case "RewriteRule": + { + RuleBuilder builder = null; + if (tokens.Count == 3) + { + builder = new RuleBuilder(tokens[1], tokens[2]); + } + else if (tokens.Count == 4) + { + builder = new RuleBuilder(tokens[1], tokens[2], tokens[3]); + } + else + { + throw new FormatException(); + } + builder.AddConditions(conditions); + rules.Add(builder.Build()); + conditions = new List(); + break; + } + case "RewriteMap": + throw new NotImplementedException("RewriteMaps to be added soon."); + case "RewriteEngine": + // Explicitly do nothing here, no notion of turning on regex engine. + break; + default: + throw new FormatException(tokens[0]); + } + } + return rules; + } + + } +} diff --git a/src/Microsoft.AspNetCore.Rewrite/ModRewrite/FlagParser.cs b/src/Microsoft.AspNetCore.Rewrite/ModRewrite/FlagParser.cs new file mode 100644 index 0000000000..b96de6e81a --- /dev/null +++ b/src/Microsoft.AspNetCore.Rewrite/ModRewrite/FlagParser.cs @@ -0,0 +1,103 @@ +// 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; + +namespace Microsoft.AspNetCore.Rewrite.ModRewrite +{ + /// + /// Parses the flags + /// + public class FlagParser + { + // TODO Refactor Rule and Condition Flags under IFlags + public static RuleFlags ParseRuleFlags(string flagString) + { + var flags = new RuleFlags(); + ParseRuleFlags(flagString, flags); + return flags; + } + + public static void ParseRuleFlags(string flagString, RuleFlags flags) + { + if (string.IsNullOrEmpty(flagString)) + { + return; + } + // Check that flags are contained within [] + if (!flagString.StartsWith("[") || !flagString.EndsWith("]")) + { + throw new FormatException(); + } + // Illegal syntax to have any spaces. + var tokens = flagString.Substring(1, flagString.Length - 2).Split(','); + // Go through tokens and verify they have meaning. + // Flags can be KVPs, delimited by '='. + foreach (string token in tokens) + { + if (string.IsNullOrEmpty(token)) + { + continue; + } + string[] kvp = token.Split('='); + if (kvp.Length == 1) + { + flags.SetFlag(kvp[0], null); + } + else if (kvp.Length == 2) + { + flags.SetFlag(kvp[0], kvp[1]); + } + else + { + throw new FormatException(); + } + } + } + + public static ConditionFlags ParseConditionFlags(string flagString) + { + var flags = new ConditionFlags(); + ParseConditionFlags(flagString, flags); + return flags; + } + + public static void ParseConditionFlags(string flagString, ConditionFlags flags) + { + if (string.IsNullOrEmpty(flagString)) + { + return; + } + // Check that flags are contained within [] + if (!flagString.StartsWith("[") || !flagString.EndsWith("]")) + { + throw new FormatException(); + } + // Lexing esque step to split all flags. + // Illegal syntax to have any spaces. + var tokens = flagString.Substring(1, flagString.Length - 2).Split(','); + // Go through tokens and verify they have meaning. + // Flags can be KVPs, delimited by '='. + foreach (string token in tokens) + { + if (string.IsNullOrEmpty(token)) + { + continue; + } + string[] kvp = token.Split('='); + if (kvp.Length == 1) + { + flags.SetFlag(kvp[0], null); + } + else if (kvp.Length == 2) + { + flags.SetFlag(kvp[0], kvp[1]); + } + else + { + throw new FormatException(); + } + } + } + } +} diff --git a/src/Microsoft.AspNetCore.Rewrite/ModRewrite/ModRewriteExtensions.cs b/src/Microsoft.AspNetCore.Rewrite/ModRewrite/ModRewriteExtensions.cs new file mode 100644 index 0000000000..445ecde591 --- /dev/null +++ b/src/Microsoft.AspNetCore.Rewrite/ModRewrite/ModRewriteExtensions.cs @@ -0,0 +1,73 @@ +// 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; +using System.IO; +using Microsoft.AspNetCore.Rewrite.ModRewrite; + +namespace Microsoft.AspNetCore.Rewrite +{ + public static class ModRewriteExtensions + { + /// + /// Imports rules from a mod_rewrite file and adds the rules to current rules. + /// + /// The UrlRewrite options. + /// The path to the file containing mod_rewrite rules. + public static UrlRewriteOptions ImportFromModRewrite(this UrlRewriteOptions options, string filePath) + { + // TODO use IHostingEnvironment as param. + if (string.IsNullOrEmpty(filePath)) + { + throw new ArgumentException(nameof(filePath)); + } + // TODO IHosting to fix! + + using (var stream = File.OpenRead(filePath)) + { + options.Rules.AddRange(FileParser.Parse(new StreamReader(stream))); + }; + return options; + } + + /// + /// Imports rules from a mod_rewrite file and adds the rules to current rules. + /// + /// The UrlRewrite options. + /// Text reader containing a stream of mod_rewrite rules. + public static UrlRewriteOptions ImportFromModRewrite(this UrlRewriteOptions options, TextReader reader) + { + options.Rules.AddRange(FileParser.Parse(reader)); + return options; + } + + /// + /// Adds a mod_rewrite rule to the current rules. + /// Additional properties (conditions, flags) for the rule can be added through the action. + /// + /// The UrlRewrite options. + /// The literal string of a mod_rewrite rule: + /// "RewriteRule Pattern Substitution [Flags]" + /// Action to perform on the + public static UrlRewriteOptions AddModRewriteRule(this UrlRewriteOptions options, string rule, Action action) + { + var builder = new RuleBuilder(rule); + action(builder); + options.Rules.Add(builder.Build()); + return options; + } + + /// + /// Adds a mod_rewrite rule to the current rules. + /// + /// The UrlRewrite options. + /// The literal string of a mod_rewrite rule: + /// "RewriteRule Pattern Substitution [Flags]" + public static UrlRewriteOptions AddModRewriteRule(this UrlRewriteOptions options, string rule) + { + var builder = new RuleBuilder(rule); + options.Rules.Add(builder.Build()); + return options; + } + } +} diff --git a/src/Microsoft.AspNetCore.Rewrite/ModRewrite/ModRewriteRule.cs b/src/Microsoft.AspNetCore.Rewrite/ModRewrite/ModRewriteRule.cs new file mode 100644 index 0000000000..364fbf7275 --- /dev/null +++ b/src/Microsoft.AspNetCore.Rewrite/ModRewrite/ModRewriteRule.cs @@ -0,0 +1,209 @@ +// 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; +using System.Collections.Generic; +using Microsoft.Net.Http.Headers; +using System.Text.RegularExpressions; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Rewrite.RuleAbstraction; + +namespace Microsoft.AspNetCore.Rewrite.ModRewrite +{ + public class ModRewriteRule : Rule + { + public List Conditions { get; set; } = new List(); + public string Description { get; set; } = string.Empty; + public RuleExpression InitialRule { get; set; } + public Pattern Transform { get; set; } + public RuleFlags Flags { get; set; } = new RuleFlags(); + public ModRewriteRule() { } + + public ModRewriteRule(List conditions, RuleExpression initialRule, Pattern transforms, RuleFlags flags, string description = "") + { + Conditions = conditions; + InitialRule = initialRule; + Transform = transforms; + Flags = flags; + Description = description; + } + + public override RuleResult ApplyRule(UrlRewriteContext context) + { + // 1. Figure out which section of the string to match for the initial rule. + var results = InitialRule.Operand.RegexOperation.Match(context.HttpContext.Request.Path.ToString()); + + string flagRes = null; + if (CheckMatchResult(results.Success)) + { + return new RuleResult { Result = RuleTerminiation.Continue }; + } + + if (Flags.HasFlag(RuleFlagType.EscapeBackreference)) + { + // TODO Escape Backreferences here. + } + + // 2. Go through all conditions and compare them to the created string + var previous = Match.Empty; + + if (!CheckCondition(context, results, previous)) + { + return new RuleResult { Result = RuleTerminiation.Continue }; + } + // TODO add chained flag + + // at this point, our rule passed, we can now apply the on match function + var result = Transform.GetPattern(context.HttpContext, results, previous); + + if (Flags.HasFlag(RuleFlagType.QSDiscard)) + { + context.HttpContext.Request.QueryString = new QueryString(); + } + + if ((flagRes = Flags.GetValue(RuleFlagType.Cookie)) != null) + { + // TODO CreateCookies(context); + // context.HttpContext.Response.Cookies.Append() + // Make sure this in on compile. + } + + if ((flagRes = Flags.GetValue(RuleFlagType.Env)) != null) + { + // TODO CreateEnv(context) + // context.HttpContext... + } + + if ((flagRes = Flags.GetValue(RuleFlagType.Next)) != null) + { + // TODO Next flag + } + + if (Flags.HasFlag(RuleFlagType.Forbidden)) + { + context.HttpContext.Response.StatusCode = StatusCodes.Status403Forbidden; + return new RuleResult { Result = RuleTerminiation.ResponseComplete }; + } + else if (Flags.HasFlag(RuleFlagType.Gone)) + { + context.HttpContext.Response.StatusCode = StatusCodes.Status410Gone; + return new RuleResult { Result = RuleTerminiation.ResponseComplete }; + } + else if (result == "-") + { + // TODO set url to result. + } + else if (Flags.HasFlag(RuleFlagType.QSAppend)) + { + context.HttpContext.Request.QueryString = context.HttpContext.Request.QueryString.Add(new QueryString(result)); + } + + if ((flagRes = Flags.GetValue(RuleFlagType.Redirect)) != null) + { + int parsedInt; + if (!int.TryParse(flagRes, out parsedInt)) + { + // TODO PERF parse the status code when the flag is parsed rather than per request + throw new FormatException("Trying to parse non-int in integer comparison."); + } + context.HttpContext.Response.StatusCode = parsedInt; + if (Flags.HasFlag(RuleFlagType.FullUrl)) + { + // TODO review escaping + context.HttpContext.Response.Headers[HeaderNames.Location] = result; + } + else + { + // TODO str cat is bad, polish, review escaping + if (result.StartsWith("/")) + { + context.HttpContext.Response.Headers[HeaderNames.Location] = result + context.HttpContext.Request.QueryString; + } + else + { + context.HttpContext.Response.Headers[HeaderNames.Location] = "/" + result + context.HttpContext.Request.QueryString; + } + } + return new RuleResult { Result = RuleTerminiation.ResponseComplete }; + } + else + { + if (Flags.HasFlag(RuleFlagType.FullUrl)) + { + ModifyHttpContextFromUri(context.HttpContext, result); + } + else + { + if (result.StartsWith("/")) + { + context.HttpContext.Request.Path = new PathString(result); + } + else + { + context.HttpContext.Request.Path = new PathString("/" + result); + } + } + if (Flags.HasFlag(RuleFlagType.Last) || Flags.HasFlag(RuleFlagType.End)) + { + return new RuleResult { Result = RuleTerminiation.StopRules }; + } + else + { + return new RuleResult { Result = RuleTerminiation.Continue }; + } + } + } + + private bool CheckMatchResult(bool? result) + { + if (result == null) + { + return false; + } + return !(result.Value ^ InitialRule.Invert); + } + + private bool CheckCondition(UrlRewriteContext context, Match results, Match previous) + { + if (Conditions == null) + { + return true; + } + + // TODO Visitor pattern here? + foreach (var condition in Conditions) + { + var concatTestString = condition.TestStringSegments.GetPattern(context.HttpContext, results, previous); + var match = condition.ConditionExpression.CheckConditionExpression(context, previous, concatTestString); + + if (match == null) + { + return false; + } + + if (!match.Value && !(condition.Flags.HasFlag(ConditionFlagType.Or))) + { + return false; + } + } + return true; + } + + private void ModifyHttpContextFromUri(HttpContext context, string uriString) + { + var uri = new Uri(uriString); + // TODO this is ugly, fix in later push. + // TODO super bad for perf, cache/locally store these and update httpcontext after all rules are applied. + var pathBase = PathString.FromUriComponent(uri); + if (!pathBase.Value.StartsWith(context.Request.PathBase)) + { + // cannot distinguish between path base and path. + throw new NotSupportedException("Modified path base from mod_rewrite rule"); + } + context.Request.Host = HostString.FromUriComponent(uri); + context.Request.Path = PathString.FromUriComponent(uri); + context.Request.QueryString = QueryString.FromUriComponent(uri); + context.Request.Scheme = uri.Scheme; + } + } +} diff --git a/src/Microsoft.AspNetCore.Rewrite/ModRewrite/OperationType.cs b/src/Microsoft.AspNetCore.Rewrite/ModRewrite/OperationType.cs new file mode 100644 index 0000000000..8f2ec10e9b --- /dev/null +++ b/src/Microsoft.AspNetCore.Rewrite/ModRewrite/OperationType.cs @@ -0,0 +1,23 @@ +// 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. + +namespace Microsoft.AspNetCore.Rewrite.ModRewrite +{ + public enum OperationType + { + None, + Equal, + Greater, + GreaterEqual, + Less, + LessEqual, + NotEqual, + Directory, + RegularFile, + ExistingFile, + SymbolicLink, + Size, + ExistingUrl, + Executable + } +} diff --git a/src/Microsoft.AspNetCore.Rewrite/ModRewrite/ParsedConditionExpression.cs b/src/Microsoft.AspNetCore.Rewrite/ModRewrite/ParsedConditionExpression.cs new file mode 100644 index 0000000000..b0402f9e99 --- /dev/null +++ b/src/Microsoft.AspNetCore.Rewrite/ModRewrite/ParsedConditionExpression.cs @@ -0,0 +1,22 @@ +// 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. + +namespace Microsoft.AspNetCore.Rewrite.ModRewrite +{ + public class ParsedModRewriteExpression + { + public bool Invert { get; set; } + public ConditionType Type { get; set; } + public OperationType Operation { get; set; } + public string Operand { get; set; } + public ParsedModRewriteExpression(bool invert, ConditionType type, OperationType operation, string operand) + { + Invert = invert; + Type = type; + Operation = operation; + Operand = operand; + } + + public ParsedModRewriteExpression() { } + } +} diff --git a/src/Microsoft.AspNetCore.Rewrite/ModRewrite/Pattern.cs b/src/Microsoft.AspNetCore.Rewrite/ModRewrite/Pattern.cs new file mode 100644 index 0000000000..b3070faf1d --- /dev/null +++ b/src/Microsoft.AspNetCore.Rewrite/ModRewrite/Pattern.cs @@ -0,0 +1,69 @@ +// 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; +using System.Collections.Generic; +using System.Text; +using System.Text.RegularExpressions; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Rewrite.ModRewrite; + +namespace Microsoft.AspNetCore.Rewrite +{ + /// + /// Contains a sequence of pattern segments, which on obtaining the context, will create the appropriate + /// test string and condition for rules and conditions. + /// + public class Pattern + { + private IReadOnlyList Segments { get; } + /// + /// Creates a new Pattern + /// + /// List of pattern segments which will be applied. + public Pattern(IReadOnlyList segments) + { + Segments = segments; + } + + /// + /// Creates the appropriate test string from the Httpcontext and Segments. + /// + /// + /// + /// + /// + public string GetPattern(HttpContext context, Match ruleMatch, Match prevCondition) + { + var res = new StringBuilder(); + foreach (var segment in Segments) + { + // TODO handle case when segment.Variable is 0 in rule and condition + switch (segment.Type) + { + case SegmentType.Literal: + res.Append(segment.Variable); + break; + case SegmentType.ServerParameter: + res.Append(ServerVariables.Resolve(segment.Variable, context)); + break; + case SegmentType.RuleParameter: + var ruleParam = ruleMatch.Groups[segment.Variable]; + if (ruleParam != null) + { + res.Append(ruleParam); + } + break; + case SegmentType.ConditionParameter: + var condParam = prevCondition.Groups[segment.Variable]; + if (condParam != null) + { + res.Append(condParam); + } + break; + } + } + return res.ToString(); + } + } +} diff --git a/src/Microsoft.AspNetCore.Rewrite/ModRewrite/PatternSegment.cs b/src/Microsoft.AspNetCore.Rewrite/ModRewrite/PatternSegment.cs new file mode 100644 index 0000000000..13a22cb50c --- /dev/null +++ b/src/Microsoft.AspNetCore.Rewrite/ModRewrite/PatternSegment.cs @@ -0,0 +1,26 @@ +// 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. + +namespace Microsoft.AspNetCore.Rewrite +{ + /// + /// A Pattern segment contains a portion of the test string/ substitution segment with a type associated. + /// This type can either be: Regex, Rule Variable, Condition Variable, or a Server Variable. + /// + public class PatternSegment + { + public string Variable { get; } // TODO make this a range s.t. we don't copy the string. + public SegmentType Type { get; } + + /// + /// Create a Pattern segment. + /// + /// + /// + public PatternSegment(string variable, SegmentType type) + { + Variable = variable; + Type = type; + } + } +} diff --git a/src/Microsoft.AspNetCore.Rewrite/ModRewrite/RuleBuilder.cs b/src/Microsoft.AspNetCore.Rewrite/ModRewrite/RuleBuilder.cs new file mode 100644 index 0000000000..35530a80bd --- /dev/null +++ b/src/Microsoft.AspNetCore.Rewrite/ModRewrite/RuleBuilder.cs @@ -0,0 +1,122 @@ +// 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; +using System.Collections.Generic; + +namespace Microsoft.AspNetCore.Rewrite.ModRewrite +{ + public class RuleBuilder + { + private ParsedModRewriteExpression _pce; + private List _conditions; + private RuleFlags _flags; + private Pattern _patterns; + public ModRewriteRule Build() + { + var ruleExpression = ExpressionCreator.CreateRuleExpression(_pce, _flags); + return new ModRewriteRule(_conditions, ruleExpression, _patterns, _flags); + } + + public RuleBuilder(string initialRule, string transformation) : + this(initialRule, transformation, flags: null) + { + } + public RuleBuilder(string rule) + { + var tokens = Tokenizer.Tokenize(rule); + if (tokens.Count == 3) + { + CreateRule(tokens[1], tokens[2], flags: null); + } + else if (tokens.Count == 4) + { + CreateRule(tokens[1], tokens[2], tokens[3]); + } + else + { + throw new ArgumentException(); + } + } + + public RuleBuilder(string initialRule, string transformation, string flags) + { + CreateRule(initialRule, transformation, flags); + } + + public void CreateRule(string initialRule, string transformation, string flags) + { + _pce = RuleRegexParser.ParseRuleRegex(initialRule); + _patterns = ConditionTestStringParser.ParseConditionTestString(transformation); + _flags = FlagParser.ParseRuleFlags(flags); + } + + public void AddCondition(string condition) + { + if (_conditions == null) + { + _conditions = new List(); + } + var condBuilder = new ConditionBuilder(condition); + _conditions.Add(condBuilder.Build()); + } + + public void AddCondition(Condition condition) + { + if (_conditions == null) + { + _conditions = new List(); + } + _conditions.Add(condition); + } + + public void AddConditions(List conditions) + { + if (_conditions == null) + { + _conditions = new List(); + } + _conditions.AddRange(conditions); + } + + public void SetFlag(string flag) + { + SetFlag(flag, value: null); + } + + public void SetFlag(RuleFlagType flag) + { + SetFlag(flag, value: null); + } + + public void SetFlag(string flag, string value) + { + if (_flags == null) + { + _flags = new RuleFlags(); + } + _flags.SetFlag(flag, value); + } + + public void SetFlag(RuleFlagType flag, string value) + { + if (_flags == null) + { + _flags = new RuleFlags(); + } + _flags.SetFlag(flag, value); + } + + public void SetFlags(string flags) + { + if (_flags == null) + { + _flags = FlagParser.ParseRuleFlags(flags); + } + else + { + FlagParser.ParseRuleFlags(flags, _flags); + } + } + } +} diff --git a/src/Microsoft.AspNetCore.Rewrite/ModRewrite/RuleFlagType.cs b/src/Microsoft.AspNetCore.Rewrite/ModRewrite/RuleFlagType.cs new file mode 100644 index 0000000000..d67e698c39 --- /dev/null +++ b/src/Microsoft.AspNetCore.Rewrite/ModRewrite/RuleFlagType.cs @@ -0,0 +1,35 @@ +// 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. + +namespace Microsoft.AspNetCore.Rewrite.ModRewrite +{ + public enum RuleFlagType + { + EscapeBackreference, + Chain, + Cookie, + DiscardPath, + Env, + End, + Forbidden, + Gone, + Handler, + Last, + Next, + NoCase, + NoEscape, + NoSubReq, + NoVary, + Or, + Proxy, + PassThrough, + QSAppend, + QSDiscard, + QSLast, + Redirect, + Skip, + Type, + // Non-modrewrite rule + FullUrl + } +} diff --git a/src/Microsoft.AspNetCore.Rewrite/ModRewrite/RuleFlags.cs b/src/Microsoft.AspNetCore.Rewrite/ModRewrite/RuleFlags.cs new file mode 100644 index 0000000000..58496996bd --- /dev/null +++ b/src/Microsoft.AspNetCore.Rewrite/ModRewrite/RuleFlags.cs @@ -0,0 +1,133 @@ +// 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; +using System.Collections.Generic; + +namespace Microsoft.AspNetCore.Rewrite.ModRewrite +{ + public class RuleFlags + { + private IDictionary _ruleFlagLookup = new Dictionary(StringComparer.OrdinalIgnoreCase) { + { "b", RuleFlagType.EscapeBackreference}, + { "c", RuleFlagType.Chain }, + { "chain", RuleFlagType.Chain}, + { "co", RuleFlagType.Cookie }, + { "cookie", RuleFlagType.Cookie }, + { "dpi", RuleFlagType.DiscardPath }, + { "discardpath", RuleFlagType.DiscardPath }, + { "e", RuleFlagType.Env}, + { "env", RuleFlagType.Env}, + { "end", RuleFlagType.End }, + { "f", RuleFlagType.Forbidden }, + { "forbidden", RuleFlagType.Forbidden }, + { "g", RuleFlagType.Gone }, + { "gone", RuleFlagType.Gone }, + { "h", RuleFlagType.Handler }, + { "handler", RuleFlagType.Handler }, + { "l", RuleFlagType.Last }, + { "last", RuleFlagType.Last }, + { "n", RuleFlagType.Next }, + { "next", RuleFlagType.Next }, + { "nc", RuleFlagType.NoCase }, + { "nocase", RuleFlagType.NoCase }, + { "ne", RuleFlagType.NoEscape }, + { "noescape", RuleFlagType.NoEscape }, + { "ns", RuleFlagType.NoSubReq }, + { "nosubreq", RuleFlagType.NoSubReq }, + { "p", RuleFlagType.Proxy }, + { "proxy", RuleFlagType.Proxy }, + { "pt", RuleFlagType.PassThrough }, + { "passthrough", RuleFlagType.PassThrough }, + { "qsa", RuleFlagType.QSAppend }, + { "qsappend", RuleFlagType.QSAppend }, + { "qsd", RuleFlagType.QSDiscard }, + { "qsdiscard", RuleFlagType.QSDiscard }, + { "qsl", RuleFlagType.QSLast }, + { "qslast", RuleFlagType.QSLast }, + { "r", RuleFlagType.Redirect }, + { "redirect", RuleFlagType.Redirect }, + { "s", RuleFlagType.Skip }, + { "skip", RuleFlagType.Skip }, + { "t", RuleFlagType.Type }, + { "type", RuleFlagType.Type }, + // TODO make this a load bool instead of a flag for the file and rules. + { "u", RuleFlagType.FullUrl }, + { "url", RuleFlagType.FullUrl } + }; + + public IDictionary FlagDictionary { get; } + + public RuleFlags(IDictionary flags) + { + // TODO use ref to check dictionary equality + FlagDictionary = flags; + } + + public RuleFlags() + { + FlagDictionary = new Dictionary(); + } + + public void SetFlag(string flag, string value) + { + RuleFlagType res; + if (!_ruleFlagLookup.TryGetValue(flag, out res)) + { + throw new FormatException("Invalid flag"); + } + SetFlag(res, value); + } + public void SetFlag(RuleFlagType flag, string value) + { + if (value == null) + { + value = string.Empty; + } + FlagDictionary[flag] = value; + } + + public string GetValue(RuleFlagType flag) + { + CleanupResources(); + string res; + if (!FlagDictionary.TryGetValue(flag, out res)) + { + return null; + } + return res; + } + + public string this[RuleFlagType flag] + { + get + { + string res; + if (!FlagDictionary.TryGetValue(flag, out res)) + { + return null; + } + return res; + } + set + { + FlagDictionary[flag] = value ?? string.Empty; + } + } + + public bool HasFlag(RuleFlagType flag) + { + CleanupResources(); + string res; + return FlagDictionary.TryGetValue(flag, out res); + } + + private void CleanupResources() + { + if (_ruleFlagLookup != null) + { + _ruleFlagLookup = null; + } + } + } +} diff --git a/src/Microsoft.AspNetCore.Rewrite/ModRewrite/RuleRegexParser.cs b/src/Microsoft.AspNetCore.Rewrite/ModRewrite/RuleRegexParser.cs new file mode 100644 index 0000000000..358eaebc15 --- /dev/null +++ b/src/Microsoft.AspNetCore.Rewrite/ModRewrite/RuleRegexParser.cs @@ -0,0 +1,26 @@ +// 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; + +namespace Microsoft.AspNetCore.Rewrite.ModRewrite +{ + public static class RuleRegexParser + { + public static ParsedModRewriteExpression ParseRuleRegex(string regex) + { + if (regex == null || regex == String.Empty) + { + throw new FormatException(); + } + if (regex.StartsWith("!")) + { + return new ParsedModRewriteExpression { Invert = true, Operand = regex.Substring(1) }; + } + else + { + return new ParsedModRewriteExpression { Invert = false, Operand = regex}; + } + } + } +} diff --git a/src/Microsoft.AspNetCore.Rewrite/ModRewrite/SegmentType.cs b/src/Microsoft.AspNetCore.Rewrite/ModRewrite/SegmentType.cs new file mode 100644 index 0000000000..b8cbb3f3c3 --- /dev/null +++ b/src/Microsoft.AspNetCore.Rewrite/ModRewrite/SegmentType.cs @@ -0,0 +1,13 @@ +// 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. + +namespace Microsoft.AspNetCore.Rewrite +{ + public enum SegmentType + { + Literal, + ServerParameter, + ConditionParameter, + RuleParameter + } +} diff --git a/src/Microsoft.AspNetCore.Rewrite/ModRewrite/ServerVariables.cs b/src/Microsoft.AspNetCore.Rewrite/ModRewrite/ServerVariables.cs new file mode 100644 index 0000000000..421ace308f --- /dev/null +++ b/src/Microsoft.AspNetCore.Rewrite/ModRewrite/ServerVariables.cs @@ -0,0 +1,180 @@ +// 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; +using System.Collections.Generic; +using System.Globalization; +using System.Net.Sockets; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Http.Features; +using Microsoft.Net.Http.Headers; + +namespace Microsoft.AspNetCore.Rewrite.ModRewrite +{ + /// + /// mod_rewrite lookups for specific string constants. + /// + public static class ServerVariables + { + public static HashSet ValidServerVariables = new HashSet() + { + "HTTP_ACCEPT", + "HTTP_COOKIE", + "HTTP_FORWARDED", + "HTTP_HOST", + "HTTP_PROXY_CONNECTION", + "HTTP_REFERER", + "HTTP_USER_AGENT", + "AUTH_TYPE", + "CONN_REMOTE_ADDR", + "CONTEXT_PREFIX", + "CONTEXT_DOCUMENT_ROOT", + "IPV6", + "PATH_INFO", + "QUERY_STRING", + "REMOTE_ADDR", + "REMOTE_HOST", + "REMOTE_IDENT", + "REMOTE_PORT", + "REMOTE_USER", + "REQUEST_METHOD", + "SCRIPT_FILENAME", + "DOCUMENT_ROOT", + "SCRIPT_GROUP", + "SCRIPT_USER", + "SERVER_ADDR", + "SERVER_ADMIN", + "SERVER_NAME", + "SERVER_PORT", + "SERVER_PROTOCOL", + "SERVER_SOFTWARE", + "TIME_YEAR", + "TIME_MON", + "TIME_DAY", + "TIME_HOUR", + "TIME_MIN", + "TIME_SEC", + "TIME_WDAY", + "TIME", + "API_VERSION", + "HTTPS", + "IS_SUBREQ", + "REQUEST_FILENAME", + "REQUEST_SCHEME", + "REQUEST_URI", + "THE_REQUEST" + + }; + + /// + /// Translates mod_rewrite server variables strings to an enum of different server variables. + /// + /// The server variable string. + /// The HttpContext context. + /// The appropriate enum if the server variable exists, else ServerVariable.None + public static string Resolve(string variable, HttpContext context) + { + // TODO talk about perf here + switch (variable) + { + case "HTTP_ACCEPT": + return context.Request.Headers[HeaderNames.Accept]; + case "HTTP_COOKIE": + return context.Request.Headers[HeaderNames.Cookie]; + case "HTTP_FORWARDED": + return context.Request.Headers["Forwarded"]; + case "HTTP_HOST": + return context.Request.Headers[HeaderNames.Host]; + case "HTTP_PROXY_CONNECTION": + return context.Request.Headers[HeaderNames.ProxyAuthenticate]; + case "HTTP_REFERER": + return context.Request.Headers[HeaderNames.Referer]; + case "HTTP_USER_AGENT": + return context.Request.Headers[HeaderNames.UserAgent]; + case "AUTH_TYPE": + throw new NotImplementedException(); + case "CONN_REMOTE_ADDR": + return context.Connection.RemoteIpAddress?.ToString(); + case "CONTEXT_PREFIX": + throw new NotImplementedException(); + case "CONTEXT_DOCUMENT_ROOT": + throw new NotImplementedException(); + case "IPV6": + return context.Connection.LocalIpAddress.AddressFamily == AddressFamily.InterNetworkV6 ? "on" : "off"; + case "PATH_INFO": + throw new NotImplementedException(); + case "QUERY_STRING": + return context.Request.QueryString.Value; + case "REMOTE_ADDR": + return context.Connection.RemoteIpAddress?.ToString(); + case "REMOTE_HOST": + throw new NotImplementedException(); + case "REMOTE_IDENT": + throw new NotImplementedException(); + case "REMOTE_PORT": + return context.Connection.RemotePort.ToString(CultureInfo.InvariantCulture); + case "REMOTE_USER": + throw new NotImplementedException(); + case "REQUEST_METHOD": + return context.Request.Method; + case "SCRIPT_FILENAME": + throw new NotImplementedException(); + case "DOCUMENT_ROOT": + throw new NotImplementedException(); + case "SCRIPT_GROUP": + throw new NotImplementedException(); + case "SCRIPT_USER": + throw new NotImplementedException(); + case "SERVER_ADDR": + return context.Connection.LocalIpAddress?.ToString(); + case "SERVER_ADMIN": + throw new NotImplementedException(); + case "SERVER_NAME": + throw new NotImplementedException(); + case "SERVER_PORT": + return context.Connection.LocalPort.ToString(CultureInfo.InvariantCulture); + case "SERVER_PROTOCOL": + return context.Features.Get()?.Protocol; + case "SERVER_SOFTWARE": + throw new NotImplementedException(); + case "TIME_YEAR": + return DateTimeOffset.UtcNow.Year.ToString(CultureInfo.InvariantCulture); + case "TIME_MON": + return DateTimeOffset.UtcNow.Month.ToString(CultureInfo.InvariantCulture); + case "TIME_DAY": + return DateTimeOffset.UtcNow.Day.ToString(CultureInfo.InvariantCulture); + case "TIME_HOUR": + return DateTimeOffset.UtcNow.Hour.ToString(CultureInfo.InvariantCulture); + case "TIME_MIN": + return DateTimeOffset.UtcNow.Minute.ToString(CultureInfo.InvariantCulture); + case "TIME_SEC": + return DateTimeOffset.UtcNow.Second.ToString(CultureInfo.InvariantCulture); + case "TIME_WDAY": + return ((int) DateTimeOffset.UtcNow.DayOfWeek).ToString(CultureInfo.InvariantCulture); + case "TIME": + return DateTimeOffset.UtcNow.ToString(CultureInfo.InvariantCulture); + case "API_VERSION": + throw new NotImplementedException(); + case "HTTPS": + return context.Request.IsHttps ? "on" : "off"; + case "HTTP2": + return context.Request.Scheme == "http2" ? "on" : "off"; + case "IS_SUBREQ": + // TODO maybe can do this? context.Request.HttpContext ? + throw new NotImplementedException(); + case "REQUEST_FILENAME": + return context.Request.Path.Value.Substring(1); + case "REQUEST_SCHEME": + return context.Request.Scheme; + case "REQUEST_URI": + // TODO This isn't an ideal solution. What this assumes is that all conditions don't have a leading slash before it. + return context.Request.Path.Value.Substring(1); + case "THE_REQUEST": + // TODO + throw new NotImplementedException(); + default: + return null; + } + } + } +} diff --git a/src/Microsoft.AspNetCore.Rewrite/ModRewrite/Tokenizer.cs b/src/Microsoft.AspNetCore.Rewrite/ModRewrite/Tokenizer.cs new file mode 100644 index 0000000000..8d6f5c0b26 --- /dev/null +++ b/src/Microsoft.AspNetCore.Rewrite/ModRewrite/Tokenizer.cs @@ -0,0 +1,84 @@ +// 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; +using System.Collections.Generic; +using Microsoft.AspNetCore.Rewrite.Internal; + +namespace Microsoft.AspNetCore.Rewrite.ModRewrite +{ + /// + /// Tokenizes a mod_rewrite rule, delimited by spaces. + /// + public static class Tokenizer + { + private const char Space = ' '; + private const char Escape = '\\'; + private const char Tab = '\t'; + + /// + /// Splits a string on whitespace, ignoring spaces, creating into a list of strings. + /// + /// The rule to tokenize. + /// A list of tokens. + public static List Tokenize(string rule) + { + // TODO make list of strings a reference to the original rule? (run into problems with escaped spaces). + // TODO handle "s and probably replace \ character with no slash. + if (string.IsNullOrEmpty(rule)) + { + return null; + } + var context = new ParserContext(rule); + if (!context.Next()) + { + return null; + } + + var tokens = new List(); + context.Mark(); + while (true) + { + if (!context.Next()) + { + // End of string. Capture. + break; + } + else if (context.Current == Escape) + { + // Need to progress such that the next character is not evaluated. + if (!context.Next()) + { + // Means that a character was not escaped appropriately Ex: "foo\" + throw new ArgumentException(); + } + } + else if (context.Current == Space || context.Current == Tab) + { + // time to capture! + // TODO: This kinda sucks, set state and skip + var token = context.Capture(); + if (!string.IsNullOrEmpty(token)) + { + tokens.Add(token); + while (context.Current == Space || context.Current == Tab) + { + if (!context.Next()) + { + // At end of string, we can return at this point. + return tokens; + } + } + context.Mark(); + } + } + } + var done = context.Capture(); + if (!string.IsNullOrEmpty(done)) + { + tokens.Add(done); + } + return tokens; + } + } +} diff --git a/src/Microsoft.AspNetCore.Rewrite/Operands/IntegerOperand.cs b/src/Microsoft.AspNetCore.Rewrite/Operands/IntegerOperand.cs new file mode 100644 index 0000000000..1d19c4a620 --- /dev/null +++ b/src/Microsoft.AspNetCore.Rewrite/Operands/IntegerOperand.cs @@ -0,0 +1,57 @@ +// 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; +using System.Globalization; +using System.Text.RegularExpressions; +using Microsoft.Extensions.FileProviders; + +namespace Microsoft.AspNetCore.Rewrite.Operands +{ + public class IntegerOperand : Operand + { + public int Value { get; } + public IntegerOperationType Operation { get; } + public IntegerOperand(int value, IntegerOperationType operation) + { + Value = value; + Operation = operation; + } + + public IntegerOperand(string value, IntegerOperationType operation) + { + int compValue; + if (!int.TryParse(value, NumberStyles.None, CultureInfo.InvariantCulture, out compValue)) + { + throw new FormatException("Syntax error for integers in comparison."); + } + Operation = operation; + } + + public override bool? CheckOperation(Match previous, string testString, IFileProvider fileProvider) + { + int compValue; + if (!int.TryParse(testString, NumberStyles.None, CultureInfo.InvariantCulture, out compValue)) + { + return false; + } + switch (Operation) + { + case IntegerOperationType.Equal: + return compValue == Value; + case IntegerOperationType.Greater: + return compValue > Value; + case IntegerOperationType.GreaterEqual: + return compValue >= Value; + case IntegerOperationType.Less: + return compValue < Value; + case IntegerOperationType.LessEqual: + return compValue <= Value; + case IntegerOperationType.NotEqual: + return compValue != Value; + default: + return null; + } + } + } +} diff --git a/src/Microsoft.AspNetCore.Rewrite/Operands/IntegerOperation.cs b/src/Microsoft.AspNetCore.Rewrite/Operands/IntegerOperation.cs new file mode 100644 index 0000000000..3abd0b3e16 --- /dev/null +++ b/src/Microsoft.AspNetCore.Rewrite/Operands/IntegerOperation.cs @@ -0,0 +1,15 @@ +// 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. + +namespace Microsoft.AspNetCore.Rewrite.Operands +{ + public enum IntegerOperationType + { + Equal, + Greater, + GreaterEqual, + Less, + LessEqual, + NotEqual + } +} diff --git a/src/Microsoft.AspNetCore.Rewrite/Operands/Operand.cs b/src/Microsoft.AspNetCore.Rewrite/Operands/Operand.cs new file mode 100644 index 0000000000..0562e14b7c --- /dev/null +++ b/src/Microsoft.AspNetCore.Rewrite/Operands/Operand.cs @@ -0,0 +1,13 @@ +// 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.Text.RegularExpressions; +using Microsoft.Extensions.FileProviders; + +namespace Microsoft.AspNetCore.Rewrite.Operands +{ + public abstract class Operand + { + public abstract bool? CheckOperation(Match previous, string concatTestString, IFileProvider fileProvider); + } +} diff --git a/src/Microsoft.AspNetCore.Rewrite/Operands/PropertyOperand.cs b/src/Microsoft.AspNetCore.Rewrite/Operands/PropertyOperand.cs new file mode 100644 index 0000000000..2637a00119 --- /dev/null +++ b/src/Microsoft.AspNetCore.Rewrite/Operands/PropertyOperand.cs @@ -0,0 +1,44 @@ +// 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; +using System.Text.RegularExpressions; +using Microsoft.Extensions.FileProviders; + +namespace Microsoft.AspNetCore.Rewrite.Operands +{ + public class PropertyOperand : Operand + { + public PropertyOperationType Operation { get; } + + public PropertyOperand(PropertyOperationType operation) + { + Operation = operation; + } + public override bool? CheckOperation(Match previous, string testString, IFileProvider fileProvider) + { + switch(Operation) + { + case PropertyOperationType.Directory: + return fileProvider.GetFileInfo(testString).IsDirectory; + case PropertyOperationType.RegularFile: + return fileProvider.GetFileInfo(testString).Exists; + case PropertyOperationType.Size: + var fileInfo = fileProvider.GetFileInfo(testString); + return fileInfo.Exists && fileInfo.Length > 0; + case PropertyOperationType.ExistingUrl: + throw new NotSupportedException("No support for internal sub requests."); + case PropertyOperationType.ExistingFile: + throw new NotSupportedException("No support for internal sub requests."); + case PropertyOperationType.SymbolicLink: + throw new NotSupportedException("No support for checking symbolic links."); + case PropertyOperationType.Executable: + throw new NotSupportedException("No support for checking executable permissions."); + default: + return false; + } + } + } + + +} diff --git a/src/Microsoft.AspNetCore.Rewrite/Operands/PropertyOperation.cs b/src/Microsoft.AspNetCore.Rewrite/Operands/PropertyOperation.cs new file mode 100644 index 0000000000..4fc409e98f --- /dev/null +++ b/src/Microsoft.AspNetCore.Rewrite/Operands/PropertyOperation.cs @@ -0,0 +1,17 @@ +// 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. + +namespace Microsoft.AspNetCore.Rewrite.Operands +{ + public enum PropertyOperationType + { + None, + Directory, + RegularFile, + ExistingFile, + SymbolicLink, + Size, + ExistingUrl, + Executable + } +} diff --git a/src/Microsoft.AspNetCore.Rewrite/Operands/RegexOperand.cs b/src/Microsoft.AspNetCore.Rewrite/Operands/RegexOperand.cs new file mode 100644 index 0000000000..e9eac3b7bb --- /dev/null +++ b/src/Microsoft.AspNetCore.Rewrite/Operands/RegexOperand.cs @@ -0,0 +1,24 @@ +// 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.Text.RegularExpressions; +using Microsoft.Extensions.FileProviders; + +namespace Microsoft.AspNetCore.Rewrite.Operands +{ + public class RegexOperand : Operand + { + public Regex RegexOperation { get; } + + public RegexOperand(Regex regex) + { + RegexOperation = regex; + } + + public override bool? CheckOperation(Match previous, string concatTestString, IFileProvider fileProvider) + { + previous = RegexOperation.Match(concatTestString); + return previous.Success; + } + } +} diff --git a/src/Microsoft.AspNetCore.Rewrite/Operands/StringOperand.cs b/src/Microsoft.AspNetCore.Rewrite/Operands/StringOperand.cs new file mode 100644 index 0000000000..06360eb38a --- /dev/null +++ b/src/Microsoft.AspNetCore.Rewrite/Operands/StringOperand.cs @@ -0,0 +1,40 @@ +// 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; +using System.Text.RegularExpressions; +using Microsoft.Extensions.FileProviders; + +namespace Microsoft.AspNetCore.Rewrite.Operands +{ + public class StringOperand : Operand + { + public string Value { get; set; } + public StringOperationType Operation { get; set; } + + public StringOperand(string value, StringOperationType operation) + { + Value = value; + Operation = operation; + } + + public override bool? CheckOperation(Match previous, string concatTestString, IFileProvider fileProvider) + { + switch (Operation) + { + case StringOperationType.Equal: + return concatTestString.CompareTo(Value) == 0; + case StringOperationType.Greater: + return concatTestString.CompareTo(Value) > 0; + case StringOperationType.GreaterEqual: + return concatTestString.CompareTo(Value) >= 0; + case StringOperationType.Less: + return concatTestString.CompareTo(Value) < 0; + case StringOperationType.LessEqual: + return concatTestString.CompareTo(Value) <= 0; + default: + return null; + } + } + } +} diff --git a/src/Microsoft.AspNetCore.Rewrite/Operands/StringOperation.cs b/src/Microsoft.AspNetCore.Rewrite/Operands/StringOperation.cs new file mode 100644 index 0000000000..51bc4ec48a --- /dev/null +++ b/src/Microsoft.AspNetCore.Rewrite/Operands/StringOperation.cs @@ -0,0 +1,14 @@ +// 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. + +namespace Microsoft.AspNetCore.Rewrite.Operands +{ + public enum StringOperationType + { + Equal, + Greater, + GreaterEqual, + Less, + LessEqual + } +} diff --git a/src/Microsoft.AspNetCore.Rewrite/ParserContext.cs b/src/Microsoft.AspNetCore.Rewrite/ParserContext.cs new file mode 100644 index 0000000000..34b78f5b67 --- /dev/null +++ b/src/Microsoft.AspNetCore.Rewrite/ParserContext.cs @@ -0,0 +1,70 @@ +// 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. + +namespace Microsoft.AspNetCore.Rewrite.Internal +{ + /// + /// Represents a string iterator, with captures. + /// + public class ParserContext + { + private readonly string _template; + private int _index; + private int? _mark; + + public ParserContext(string condition) + { + _template = condition; + _index = -1; + } + + public char Current + { + get { return (_index < _template.Length && _index >= 0) ? _template[_index] : (char)0; } + } + + public bool Back() + { + return --_index >= 0; + } + + public bool Next() + { + return ++_index < _template.Length; + } + + public bool HasNext() + { + return (_index + 1) < _template.Length; + } + + public void Mark() + { + _mark = _index; + } + + public int GetIndex() + { + return _index; + } + + public string Capture() + { + // TODO make this return a range rather than a string. + if (_mark.HasValue) + { + var value = _template.Substring(_mark.Value, _index - _mark.Value); + _mark = null; + return value; + } + else + { + return null; + } + } + public string Error() + { + return string.Format("Syntax Error at index: ", _index, " with character: ", Current); + } + } +} diff --git a/src/Microsoft.AspNetCore.Rewrite/Properties/AssemblyInfo.cs b/src/Microsoft.AspNetCore.Rewrite/Properties/AssemblyInfo.cs new file mode 100644 index 0000000000..c2ce8b42a6 --- /dev/null +++ b/src/Microsoft.AspNetCore.Rewrite/Properties/AssemblyInfo.cs @@ -0,0 +1,19 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("Microsoft.AspNetCore.Rewrite")] +[assembly: AssemblyTrademark("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("0e7ca1a7-1dc3-4ce6-b9c7-1688fe1410f1")] diff --git a/src/Microsoft.AspNetCore.Rewrite/RuleAbstraction/FunctionalRule.cs b/src/Microsoft.AspNetCore.Rewrite/RuleAbstraction/FunctionalRule.cs new file mode 100644 index 0000000000..073e31945d --- /dev/null +++ b/src/Microsoft.AspNetCore.Rewrite/RuleAbstraction/FunctionalRule.cs @@ -0,0 +1,14 @@ +// 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; + +namespace Microsoft.AspNetCore.Rewrite.RuleAbstraction +{ + public class FunctionalRule : Rule + { + public Func OnApplyRule { get; set; } + public Transformation OnCompletion { get; set; } = Transformation.Rewrite; + public override RuleResult ApplyRule(UrlRewriteContext context) => OnApplyRule(context); + } +} \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Rewrite/RuleAbstraction/PathRule.cs b/src/Microsoft.AspNetCore.Rewrite/RuleAbstraction/PathRule.cs new file mode 100644 index 0000000000..697810ef35 --- /dev/null +++ b/src/Microsoft.AspNetCore.Rewrite/RuleAbstraction/PathRule.cs @@ -0,0 +1,48 @@ +// 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.Text.RegularExpressions; + +namespace Microsoft.AspNetCore.Rewrite.RuleAbstraction +{ + public class PathRule : Rule + { + public Regex MatchPattern { get; set; } + public string OnMatch { get; set; } + public Transformation OnCompletion { get; set; } = Transformation.Rewrite; + public override RuleResult ApplyRule(UrlRewriteContext context) + { + var matches = MatchPattern.Match(context.HttpContext.Request.Path); + if (matches.Success) + { + // New method here to translate the outgoing format string to the correct value. + var path = matches.Result(OnMatch); + if (OnCompletion == Transformation.Redirect) + { + var req = context.HttpContext.Request; + var newUrl = string.Concat( + req.Scheme, + "://", + req.PathBase, + path, + req.QueryString); + context.HttpContext.Response.Redirect(newUrl); + return new RuleResult { Result = RuleTerminiation.ResponseComplete }; + } + else + { + context.HttpContext.Request.Path = path; + } + if (OnCompletion == Transformation.TerminatingRewrite) + { + return new RuleResult { Result = RuleTerminiation.StopRules }; + } + else + { + return new RuleResult { Result = RuleTerminiation.Continue }; + } + } + return new RuleResult { Result = RuleTerminiation.Continue }; + } + } +} diff --git a/src/Microsoft.AspNetCore.Rewrite/RuleAbstraction/Rule.cs b/src/Microsoft.AspNetCore.Rewrite/RuleAbstraction/Rule.cs new file mode 100644 index 0000000000..0b636120d2 --- /dev/null +++ b/src/Microsoft.AspNetCore.Rewrite/RuleAbstraction/Rule.cs @@ -0,0 +1,11 @@ +// 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. + +namespace Microsoft.AspNetCore.Rewrite.RuleAbstraction +{ + public abstract class Rule + { + public abstract RuleResult ApplyRule(UrlRewriteContext context); + } +} + diff --git a/src/Microsoft.AspNetCore.Rewrite/RuleAbstraction/RuleExpression.cs b/src/Microsoft.AspNetCore.Rewrite/RuleAbstraction/RuleExpression.cs new file mode 100644 index 0000000000..e14728e33c --- /dev/null +++ b/src/Microsoft.AspNetCore.Rewrite/RuleAbstraction/RuleExpression.cs @@ -0,0 +1,13 @@ +// 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 Microsoft.AspNetCore.Rewrite.Operands; + +namespace Microsoft.AspNetCore.Rewrite.RuleAbstraction +{ + public class RuleExpression + { + public RegexOperand Operand { get; set; } + public bool Invert { get; set; } + } +} diff --git a/src/Microsoft.AspNetCore.Rewrite/RuleAbstraction/RuleResult.cs b/src/Microsoft.AspNetCore.Rewrite/RuleAbstraction/RuleResult.cs new file mode 100644 index 0000000000..67aa51f583 --- /dev/null +++ b/src/Microsoft.AspNetCore.Rewrite/RuleAbstraction/RuleResult.cs @@ -0,0 +1,10 @@ +// 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. + +namespace Microsoft.AspNetCore.Rewrite.RuleAbstraction +{ + public class RuleResult + { + public RuleTerminiation Result { get; set; } + } +} diff --git a/src/Microsoft.AspNetCore.Rewrite/RuleAbstraction/RuleTermination.cs b/src/Microsoft.AspNetCore.Rewrite/RuleAbstraction/RuleTermination.cs new file mode 100644 index 0000000000..eae0a13ffa --- /dev/null +++ b/src/Microsoft.AspNetCore.Rewrite/RuleAbstraction/RuleTermination.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace Microsoft.AspNetCore.Rewrite.RuleAbstraction +{ + public enum RuleTerminiation + { + Continue, + ResponseComplete, + StopRules + } +} diff --git a/src/Microsoft.AspNetCore.Rewrite/RuleAbstraction/SchemeRule.cs b/src/Microsoft.AspNetCore.Rewrite/RuleAbstraction/SchemeRule.cs new file mode 100644 index 0000000000..427a38bfc6 --- /dev/null +++ b/src/Microsoft.AspNetCore.Rewrite/RuleAbstraction/SchemeRule.cs @@ -0,0 +1,54 @@ +// 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.Text; +using Microsoft.AspNetCore.Http; + +namespace Microsoft.AspNetCore.Rewrite.RuleAbstraction +{ + public class SchemeRule : Rule + { + public int? SSLPort { get; set; } + public Transformation OnCompletion { get; set; } = Transformation.Rewrite; + public override RuleResult ApplyRule(UrlRewriteContext context) + { + + // TODO this only does http to https, add more features in the future. + if (!context.HttpContext.Request.IsHttps) + { + var host = context.HttpContext.Request.Host; + if (SSLPort.HasValue && SSLPort.Value > 0) + { + // a specific SSL port is specified + host = new HostString(host.Host, SSLPort.Value); + } + else + { + // clear the port + host = new HostString(host.Host); + } + + if ((OnCompletion != Transformation.Redirect)) + { + context.HttpContext.Request.Scheme = "https"; + context.HttpContext.Request.Host = host; + if (OnCompletion == Transformation.TerminatingRewrite) + { + return new RuleResult { Result = RuleTerminiation.StopRules }; + } + else + { + return new RuleResult { Result = RuleTerminiation.Continue }; + } + } + + var req = context.HttpContext.Request; + + var newUrl = new StringBuilder().Append("https://").Append(host).Append(req.PathBase).Append(req.Path).Append(req.QueryString); + context.HttpContext.Response.Redirect(newUrl.ToString()); + return new RuleResult { Result = RuleTerminiation.ResponseComplete }; + } + return new RuleResult { Result = RuleTerminiation.Continue }; ; + } + } +} diff --git a/src/Microsoft.AspNetCore.Rewrite/RuleAbstraction/Transformation.cs b/src/Microsoft.AspNetCore.Rewrite/RuleAbstraction/Transformation.cs new file mode 100644 index 0000000000..44008b89a4 --- /dev/null +++ b/src/Microsoft.AspNetCore.Rewrite/RuleAbstraction/Transformation.cs @@ -0,0 +1,12 @@ +// 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. + +namespace Microsoft.AspNetCore.Rewrite.RuleAbstraction +{ + public enum Transformation + { + Rewrite, + Redirect, + TerminatingRewrite + } +} diff --git a/src/Microsoft.AspNetCore.Rewrite/UrlRewriteContext.cs b/src/Microsoft.AspNetCore.Rewrite/UrlRewriteContext.cs new file mode 100644 index 0000000000..ab97b358ef --- /dev/null +++ b/src/Microsoft.AspNetCore.Rewrite/UrlRewriteContext.cs @@ -0,0 +1,17 @@ +// 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 Microsoft.AspNetCore.Http; +using Microsoft.Extensions.FileProviders; + +namespace Microsoft.AspNetCore.Rewrite +{ + /// + /// The UrlRewrite Context contains the HttpContext of the request and the file provider to check conditions. + /// + public class UrlRewriteContext + { + public HttpContext HttpContext { get; set; } + public IFileProvider FileProvider { get; set; } + } +} diff --git a/src/Microsoft.AspNetCore.Rewrite/UrlRewriteExtensions.cs b/src/Microsoft.AspNetCore.Rewrite/UrlRewriteExtensions.cs new file mode 100644 index 0000000000..2c0942f110 --- /dev/null +++ b/src/Microsoft.AspNetCore.Rewrite/UrlRewriteExtensions.cs @@ -0,0 +1,35 @@ +// 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; +using Microsoft.AspNetCore.Rewrite; + +namespace Microsoft.AspNetCore.Builder +{ + /// + /// Extension methods for the + /// + public static class UrlRewriteExtensions + { + /// + /// Checks if a given Url matches rules and conditions, and modifies the HttpContext on match. + /// + /// + /// Options for urlrewrite. + /// + public static IApplicationBuilder UseRewriter(this IApplicationBuilder app, UrlRewriteOptions options) + { + if (app == null) + { + throw new ArgumentNullException(nameof(app)); + } + + if (options == null) + { + throw new ArgumentNullException(nameof(options)); + } + // put middleware in pipeline + return app.UseMiddleware(options); + } + } +} diff --git a/src/Microsoft.AspNetCore.Rewrite/UrlRewriteMiddleware.cs b/src/Microsoft.AspNetCore.Rewrite/UrlRewriteMiddleware.cs new file mode 100644 index 0000000000..deb987d647 --- /dev/null +++ b/src/Microsoft.AspNetCore.Rewrite/UrlRewriteMiddleware.cs @@ -0,0 +1,76 @@ +// 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; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Rewrite.RuleAbstraction; +using Microsoft.Extensions.FileProviders; + +namespace Microsoft.AspNetCore.Rewrite +{ + /// + /// Represents a middleware that rewrites urls imported from mod_rewrite, UrlRewrite, and code. + /// + public class UrlRewriteMiddleware + { + private readonly RequestDelegate _next; + private readonly UrlRewriteOptions _options; + private readonly IFileProvider _fileProvider; + + /// + /// Creates a new instance of + /// + /// The delegate representing the next middleware in the request pipeline. + /// The Hosting Environment. + /// The middleware options, containing the rules to apply. + public UrlRewriteMiddleware(RequestDelegate next, IHostingEnvironment hostingEnv, UrlRewriteOptions options) + { + if (next == null) + { + throw new ArgumentNullException(nameof(next)); + } + + if (options == null) + { + throw new ArgumentNullException(nameof(options)); + } + + _next = next; + _options = options; + _fileProvider = _options.FileProvider ?? hostingEnv.WebRootFileProvider; + } + + /// + /// Executes the middleware. + /// + /// The for the current request. + /// A task that represents the execution of this middleware. + public Task Invoke(HttpContext context) + { + if (context == null) + { + throw new ArgumentNullException(nameof(context)); + } + var urlContext = new UrlRewriteContext { HttpContext = context, FileProvider = _fileProvider }; + foreach (var rule in _options.Rules) + { + // Apply the rule + var result = rule.ApplyRule(urlContext); + switch (result.Result) + { + case RuleTerminiation.Continue: + // Explicitly show that we continue executing rules + break; + case RuleTerminiation.ResponseComplete: + // TODO cache task for perf + return Task.FromResult(0); + case RuleTerminiation.StopRules: + return _next(context); + } + } + return _next(context); + } + } +} diff --git a/src/Microsoft.AspNetCore.Rewrite/UrlRewriteOptions.cs b/src/Microsoft.AspNetCore.Rewrite/UrlRewriteOptions.cs new file mode 100644 index 0000000000..becea3063e --- /dev/null +++ b/src/Microsoft.AspNetCore.Rewrite/UrlRewriteOptions.cs @@ -0,0 +1,21 @@ +// 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.Collections.Generic; +using Microsoft.AspNetCore.Rewrite.RuleAbstraction; +using Microsoft.Extensions.FileProviders; + +namespace Microsoft.AspNetCore.Rewrite +{ + /// + /// Options for the + /// + public class UrlRewriteOptions + { + /// + /// The ordered list of rules to apply to the context. + /// + public List Rules { get; set; } = new List(); + public IFileProvider FileProvider { get; set; } + } +} diff --git a/src/Microsoft.AspNetCore.Rewrite/UrlRewriteOptionsAddRulesExtensions.cs b/src/Microsoft.AspNetCore.Rewrite/UrlRewriteOptionsAddRulesExtensions.cs new file mode 100644 index 0000000000..3d6601baad --- /dev/null +++ b/src/Microsoft.AspNetCore.Rewrite/UrlRewriteOptionsAddRulesExtensions.cs @@ -0,0 +1,108 @@ +// 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; +using System.Collections.Generic; +using System.IO; +using System.Text.RegularExpressions; +using Microsoft.AspNetCore.Rewrite.ModRewrite; +using Microsoft.AspNetCore.Rewrite.RuleAbstraction; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.FileProviders; + +namespace Microsoft.AspNetCore.Rewrite +{ + /// + /// The builder to a list of rules for and + /// + public static class UrlRewriteOptionsAddRulesExtensions + { + /// + /// Adds a rule to the current rules. + /// + /// The UrlRewrite options. + /// A rule to be added to the current rules. + public static UrlRewriteOptions AddRule(this UrlRewriteOptions options, Rule rule) + { + options.Rules.Add(rule); + return options; + } + + /// + /// Adds a list of rules to the current rules. + /// + /// The UrlRewrite options. + /// A list of rules. + public static UrlRewriteOptions AddRules(this UrlRewriteOptions options, List rules) + { + options.Rules.AddRange(rules); + return options; + } + + /// + /// Creates a rewrite path rule. + /// + /// The Url rewrite options. + /// The string regex pattern to compare against the http context. + /// The string to replace the path with (with capture parameters). + /// Whether or not to stop rewriting on success of rule. + /// + public static UrlRewriteOptions RewritePath(this UrlRewriteOptions options, string regex, string newPath, bool stopRewriteOnSuccess = false) + { + options.Rules.Add(new PathRule { MatchPattern = new Regex(regex, RegexOptions.Compiled, TimeSpan.FromMilliseconds(1)), OnMatch = newPath, OnCompletion = stopRewriteOnSuccess ? Transformation.TerminatingRewrite : Transformation.Rewrite }); + return options; + } + + /// + /// Rewrite http to https. + /// + /// The Url rewrite options. + /// Whether or not to stop rewriting on success of rule. + /// + public static UrlRewriteOptions RewriteScheme(this UrlRewriteOptions options, bool stopRewriteOnSuccess = false) + { + options.Rules.Add(new SchemeRule {OnCompletion = stopRewriteOnSuccess ? Transformation.TerminatingRewrite : Transformation.Rewrite }); + return options; + } + + /// + /// Redirect a path to another path. + /// + /// The Url rewrite options. + /// The string regex pattern to compare against the http context. + /// The string to replace the path with (with capture parameters). + /// Whether or not to stop rewriting on success of rule. + /// + public static UrlRewriteOptions RedirectPath(this UrlRewriteOptions options, string regex, string newPath, bool stopRewriteOnSuccess = false) + { + options.Rules.Add(new PathRule { MatchPattern = new Regex(regex, RegexOptions.Compiled, TimeSpan.FromMilliseconds(1)), OnMatch = newPath, OnCompletion = Transformation.Redirect }); + return options; + } + + /// + /// Redirect http to https. + /// + /// The Url rewrite options. + /// The port to redirect the scheme to. + /// + public static UrlRewriteOptions RedirectScheme(this UrlRewriteOptions options, int? sslPort) + { + options.Rules.Add(new SchemeRule { SSLPort = sslPort, OnCompletion = Transformation.Redirect }); + return options; + } + + /// + /// User generated rule to do a specific match on a path and what to do on success of the match. + /// + /// + /// + /// + /// + /// + public static UrlRewriteOptions CustomRule(this UrlRewriteOptions options, Func onApplyRule, Transformation transform, string description = null) + { + options.Rules.Add(new FunctionalRule { OnApplyRule = onApplyRule, OnCompletion = transform}); + return options; + } + } +} diff --git a/src/Microsoft.AspNetCore.Rewrite/project.json b/src/Microsoft.AspNetCore.Rewrite/project.json new file mode 100644 index 0000000000..e829903667 --- /dev/null +++ b/src/Microsoft.AspNetCore.Rewrite/project.json @@ -0,0 +1,37 @@ +{ + "version": "1.1.0-*", + "buildOptions": { + "warningsAsErrors": true, + "keyFile": "../../tools/Key.snk", + "nowarn": [ + "CS1591" + ], + "xmlDoc": true + }, + "description": "ASP.NET Core basic middleware for:\r\nRewrite Url module.", + "packOptions": { + "repository": { + "type": "git", + "url": "git://github.com/aspnet/basicmiddleware" + }, + "tags": [ + "aspnetcore", + "proxy", + "headers", + "xforwarded" + ] + }, + "dependencies": { + "Microsoft.AspNetCore.Hosting.Abstractions": "1.1.0-*", + "Microsoft.AspNetCore.Http.Extensions": "1.1.0-*", + "Microsoft.Extensions.Configuration.Abstractions": "1.1.0-*", + "Microsoft.Extensions.FileProviders.Physical": "1.1.0-*", + "Microsoft.Extensions.Logging.Abstractions": "1.1.0-*", + "Microsoft.Extensions.Options": "1.1.0-*", + "System.Text.RegularExpressions": "4.1.0-*" + }, + "frameworks": { + "net451": {}, + "netstandard1.3": {} + } +} \ No newline at end of file diff --git a/test/Microsoft.AspNetCore.HttpOverrides.Tests/IPNetworkTest.cs b/test/Microsoft.AspNetCore.HttpOverrides.Tests/IPNetworkTest.cs index b3700c583f..fa9a099057 100644 --- a/test/Microsoft.AspNetCore.HttpOverrides.Tests/IPNetworkTest.cs +++ b/test/Microsoft.AspNetCore.HttpOverrides.Tests/IPNetworkTest.cs @@ -1,6 +1,5 @@ // 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 Xunit; diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/ConditionActionTest.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/ConditionActionTest.cs new file mode 100644 index 0000000000..7f1a37f1b4 --- /dev/null +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/ConditionActionTest.cs @@ -0,0 +1,99 @@ +// 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 Microsoft.AspNetCore.Rewrite.ModRewrite; +using Xunit; + +namespace Microsoft.AspNetCore.Rewrite +{ + public class ConditionActionTest + { + [Theory] + [InlineData(">hey", OperationType.Greater, "hey", ConditionType.StringComp)] + [InlineData("=hey", OperationType.GreaterEqual, "hey", ConditionType.StringComp)] + [InlineData("<=hey", OperationType.LessEqual, "hey", ConditionType.StringComp)] + [InlineData("=hey", OperationType.Equal, "hey", ConditionType.StringComp)] + public void ConditionParser_CheckStringComp(string condition, OperationType operation, string variable, ConditionType conditionType) + { + var results = ConditionPatternParser.ParseActionCondition(condition); + + var expected = new ParsedModRewriteExpression { Operation = operation, Type = conditionType, Operand = variable, Invert = false }; + Assert.True(CompareConditions(results, expected)); + } + + [Fact] + public void ConditionParser_CheckRegexEqual() + { + var condition = @"(.*)"; + var results = ConditionPatternParser.ParseActionCondition(condition); + + var expected = new ParsedModRewriteExpression { Type = ConditionType.Regex, Operand = "(.*)", Invert = false }; + Assert.True(CompareConditions(results, expected)); + } + + [Theory] + [InlineData("-d", OperationType.Directory, ConditionType.PropertyTest)] + [InlineData("-f", OperationType.RegularFile, ConditionType.PropertyTest)] + [InlineData("-F", OperationType.ExistingFile, ConditionType.PropertyTest)] + [InlineData("-h", OperationType.SymbolicLink, ConditionType.PropertyTest)] + [InlineData("-L", OperationType.SymbolicLink, ConditionType.PropertyTest)] + [InlineData("-l", OperationType.SymbolicLink, ConditionType.PropertyTest)] + [InlineData("-s", OperationType.Size, ConditionType.PropertyTest)] + [InlineData("-U", OperationType.ExistingUrl, ConditionType.PropertyTest)] + [InlineData("-x", OperationType.Executable, ConditionType.PropertyTest)] + public void ConditionParser_CheckFileOperations(string condition, OperationType operation, ConditionType cond) + { + var results = ConditionPatternParser.ParseActionCondition(condition); + + var expected = new ParsedModRewriteExpression { Type = cond, Operation = operation , Invert = false }; + Assert.True(CompareConditions(results, expected)); + } + + [Theory] + [InlineData("!-d", OperationType.Directory, ConditionType.PropertyTest)] + [InlineData("!-f", OperationType.RegularFile, ConditionType.PropertyTest)] + [InlineData("!-F", OperationType.ExistingFile, ConditionType.PropertyTest)] + [InlineData("!-h", OperationType.SymbolicLink, ConditionType.PropertyTest)] + [InlineData("!-L", OperationType.SymbolicLink, ConditionType.PropertyTest)] + [InlineData("!-l", OperationType.SymbolicLink, ConditionType.PropertyTest)] + [InlineData("!-s", OperationType.Size, ConditionType.PropertyTest)] + [InlineData("!-U", OperationType.ExistingUrl, ConditionType.PropertyTest)] + [InlineData("!-x", OperationType.Executable, ConditionType.PropertyTest)] + public void ConditionParser_CheckFileOperationsInverted(string condition, OperationType operation, ConditionType cond) + { + var results = ConditionPatternParser.ParseActionCondition(condition); + + var expected = new ParsedModRewriteExpression { Type = cond, Operation = operation, Invert = true }; + Assert.True(CompareConditions(results, expected)); + } + + [Theory] + [InlineData("-gt1", OperationType.Greater, "1", ConditionType.IntComp)] + [InlineData("-lt1", OperationType.Less, "1", ConditionType.IntComp)] + [InlineData("-ge1", OperationType.GreaterEqual, "1", ConditionType.IntComp)] + [InlineData("-le1", OperationType.LessEqual, "1", ConditionType.IntComp)] + [InlineData("-eq1", OperationType.Equal, "1", ConditionType.IntComp)] + [InlineData("-ne1", OperationType.NotEqual, "1", ConditionType.IntComp)] + public void ConditionParser_CheckIntComp(string condition, OperationType operation, string variable, ConditionType cond) + { + var results = ConditionPatternParser.ParseActionCondition(condition); + + var expected = new ParsedModRewriteExpression { Type = cond, Operation = operation, Invert = false, Operand = variable }; + Assert.True(CompareConditions(results, expected)); + } + + // TODO negative tests + private bool CompareConditions(ParsedModRewriteExpression i1, ParsedModRewriteExpression i2) + { + if (i1.Operation != i2.Operation || + i1.Type != i2.Type || + i1.Operand != i2.Operand || + i1.Invert != i2.Invert) + { + return false; + } + return true; + } + } +} diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/FlagParserTest.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/FlagParserTest.cs new file mode 100644 index 0000000000..dce8be83a0 --- /dev/null +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/FlagParserTest.cs @@ -0,0 +1,58 @@ +// 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.Collections.Generic; +using System.Linq; +using Microsoft.AspNetCore.Rewrite.ModRewrite; +using Xunit; + +namespace Microsoft.AspNetCore.Rewrite +{ + public class FlagParserTest + { + [Fact] + public void FlagParser_CheckSingleTerm() + { + var results = FlagParser.ParseRuleFlags("[NC]"); + var dict = new Dictionary(); + dict.Add(RuleFlagType.NoCase, string.Empty); + var expected = new RuleFlags(dict); + + Assert.True(DictionaryContentsEqual(results.FlagDictionary, expected.FlagDictionary)); + } + + [Fact] + public void FlagParser_CheckManyTerms() + { + var results = FlagParser.ParseRuleFlags("[NC,F,L]"); + var dict = new Dictionary(); + dict.Add(RuleFlagType.NoCase, string.Empty); + dict.Add(RuleFlagType.Forbidden, string.Empty); + dict.Add(RuleFlagType.Last, string.Empty); + var expected = new RuleFlags(dict); + + Assert.True(DictionaryContentsEqual(results.FlagDictionary, expected.FlagDictionary)); + } + + [Fact] + public void FlagParser_CheckManyTermsWithEquals() + { + var results = FlagParser.ParseRuleFlags("[NC,F,R=301]"); + var dict = new Dictionary(); + dict.Add(RuleFlagType.NoCase, string.Empty); + dict.Add(RuleFlagType.Forbidden, string.Empty); + dict.Add(RuleFlagType.Redirect, "301"); + var expected = new RuleFlags(dict); + + Assert.True(DictionaryContentsEqual(results.FlagDictionary, expected.FlagDictionary)); + } + + public bool DictionaryContentsEqual(IDictionary dictionary, IDictionary other) + { + return (other ?? new Dictionary()) + .OrderBy(kvp => kvp.Key) + .SequenceEqual((dictionary ?? new Dictionary()) + .OrderBy(kvp => kvp.Key)); + } + } +} diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/Microsoft.AspNetCore.Rewrite.Tests.xproj b/test/Microsoft.AspNetCore.Rewrite.Tests/Microsoft.AspNetCore.Rewrite.Tests.xproj new file mode 100644 index 0000000000..ca7df9cddb --- /dev/null +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/Microsoft.AspNetCore.Rewrite.Tests.xproj @@ -0,0 +1,22 @@ + + + + 14.0 + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) + + + + 31794f9e-a1aa-4535-b03c-a3233737cd1a + Microsoft.AspNetCore.Rewrite.Tests + .\obj + .\bin\ + v4.5.2 + + + 2.0 + + + + + + \ No newline at end of file diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/ModRewriteConditionBuilderTest.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/ModRewriteConditionBuilderTest.cs new file mode 100644 index 0000000000..3436bcaef3 --- /dev/null +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/ModRewriteConditionBuilderTest.cs @@ -0,0 +1,50 @@ +// 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 Microsoft.AspNetCore.Rewrite.ModRewrite; +using Microsoft.AspNetCore.Rewrite.Operands; +using Xunit; + +namespace RewriteTest +{ + // This file tests an input of a list of tokens and verifies that the appropriate condition is obtained + public class ModRewriteConditionBuilderTest + { + [Fact] + public void ConditionBuilder_PassInNoFlagsFlagsEmpty() + { + var conditionString = "RewriteCond /$1 /hello"; + var builder = new ConditionBuilder(conditionString); + var results = builder.Build(); + + //var expected = new Condition( + // new Pattern( + // new List() { + // new PatternSegment("/", SegmentType.Literal), + // new PatternSegment("1", SegmentType.RuleParameter) + // }), + // new ConditionExpression { Operand = new RegexOperand {Regex = new Regex("/hello") } }, + // new ConditionFlags()); + var expected = (new ConditionBuilder("/$1", "/hello")).Build(); + + Assert.True(results.Flags.FlagDictionary.Count == 0); + Assert.True(results.Flags.FlagDictionary.Count == expected.Flags.FlagDictionary.Count); + Assert.True((results.ConditionExpression.Operand is RegexOperand) + && (expected.ConditionExpression.Operand is RegexOperand)); + } + + [Fact] + public void ConditionBuilder_PassInFlagsFlagsExist() + { + var conditionString = "RewriteCond /$1 /hello [NC]"; + var builder = new ConditionBuilder(conditionString); + var results = builder.Build(); + var expected = (new ConditionBuilder("/$1", "/hello", "[NC]")).Build(); + + Assert.True(results.Flags.FlagDictionary.Count == 1); + Assert.True(results.Flags.FlagDictionary.Count == expected.Flags.FlagDictionary.Count); + Assert.True((results.ConditionExpression.Operand is RegexOperand) + && (expected.ConditionExpression.Operand is RegexOperand)); + } + } +} diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/ModRewriteCreatorTest.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/ModRewriteCreatorTest.cs new file mode 100644 index 0000000000..c9a9dd21a1 --- /dev/null +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/ModRewriteCreatorTest.cs @@ -0,0 +1,9 @@ +// 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. + +namespace Microsoft.AspNetCore.Rewrite +{ + public class ModRewriteCreatorTest + { + } +} diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/ModRewriteFlagTest.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/ModRewriteFlagTest.cs new file mode 100644 index 0000000000..e9938eff0c --- /dev/null +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/ModRewriteFlagTest.cs @@ -0,0 +1,88 @@ +// 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.Text.RegularExpressions; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Rewrite.ModRewrite; +using Microsoft.AspNetCore.Rewrite.Operands; +using Microsoft.AspNetCore.Rewrite.RuleAbstraction; +using Xunit; + +namespace Microsoft.AspNetCore.Rewrite +{ + public class ModRewriteFlagTest + { + // Flag tests + [Fact] + public void ModRewriteRule_Check403OnForbiddenFlag() + { + var context = new UrlRewriteContext { HttpContext = CreateRequest("/", "/hey/hello") }; + var rule = new ModRewriteRule + { + InitialRule = new RuleExpression { Operand = new RegexOperand(new Regex("/hey/(.*)")) , Invert = false }, + Transform = ConditionTestStringParser.ParseConditionTestString("/$1"), + Flags = FlagParser.ParseRuleFlags("[F]") + }; + var res = rule.ApplyRule(context); + Assert.True(res.Result == RuleTerminiation.ResponseComplete); + Assert.True(context.HttpContext.Response.StatusCode == 403); + } + + [Fact] + public void ModRewriteRule_Check410OnGoneFlag() + { + var context = new UrlRewriteContext { HttpContext = CreateRequest("/", "/hey/hello") }; + var rule = new ModRewriteRule + { + InitialRule = new RuleExpression { Operand = new RegexOperand(new Regex("/hey/(.*)")), Invert = false }, + Transform = ConditionTestStringParser.ParseConditionTestString("/$1"), + Flags = FlagParser.ParseRuleFlags("[G]") + }; + var res = rule.ApplyRule(context); + Assert.True(res.Result == RuleTerminiation.ResponseComplete); + Assert.True(context.HttpContext.Response.StatusCode == 410); + } + + [Fact] + public void ModRewriteRule_CheckLastFlag() + { + var context = new UrlRewriteContext { HttpContext = CreateRequest("/", "/hey/hello") }; + var rule = new ModRewriteRule + { + InitialRule = new RuleExpression { Operand = new RegexOperand(new Regex("/hey/(.*)")), Invert = false }, + Transform = ConditionTestStringParser.ParseConditionTestString("/$1"), + Flags = FlagParser.ParseRuleFlags("[L]") + }; + var res = rule.ApplyRule(context); + Assert.True(res.Result == RuleTerminiation.StopRules); + Assert.True(context.HttpContext.Request.Path.Equals(new PathString("/hello"))); + } + + + [Fact] + public void ModRewriteRule_CheckRedirectFlag() + { + // TODO fix this test. + var context = new UrlRewriteContext { HttpContext = CreateRequest("/", "/hey/hello") }; + var rule = new ModRewriteRule + { + InitialRule = new RuleExpression { Operand = new RegexOperand(new Regex("/hey/(.*)")), Invert = false }, + Transform = ConditionTestStringParser.ParseConditionTestString("/$1"), + Flags = FlagParser.ParseRuleFlags("[G]") + }; + var res = rule.ApplyRule(context); + Assert.True(res.Result == RuleTerminiation.ResponseComplete); + Assert.True(context.HttpContext.Response.StatusCode == 410); + } + + private HttpContext CreateRequest(string basePath, string requestPath, string requestQuery = "", string hostName = "") + { + HttpContext context = new DefaultHttpContext(); + context.Request.PathBase = new PathString(basePath); + context.Request.Path = new PathString(requestPath); + context.Request.QueryString = new QueryString(requestQuery); + context.Request.Host = new HostString(hostName); + return context; + } + } +} diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/ModRewriteMiddlewareTest.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/ModRewriteMiddlewareTest.cs new file mode 100644 index 0000000000..92c6dcb327 --- /dev/null +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/ModRewriteMiddlewareTest.cs @@ -0,0 +1,278 @@ +// 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.IO; +using System.Net; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.TestHost; +using Xunit; + +namespace Microsoft.AspNetCore.Rewrite +{ + public class ModRewriteMiddlewareTest + { + [Fact] + public async Task Invoke_RewritePathWhenMatching() + { + var options = new UrlRewriteOptions().AddModRewriteRule("RewriteRule /hey/(.*) /$1 "); + var builder = new WebHostBuilder() + .Configure(app => + { + app.UseRewriter(options); + app.Run(context => context.Response.WriteAsync(context.Request.Path)); + }); + var server = new TestServer(builder); + + var response = await server.CreateClient().GetStringAsync("/hey/hello"); + + Assert.Equal(response, "/hello"); + } + + [Fact] + public async Task Invoke_RewritePathTerminatesOnFirstSuccessOfRule() + { + var options = new UrlRewriteOptions().AddModRewriteRule("RewriteRule /hey/(.*) /$1 [L]") + .AddModRewriteRule("RewriteRule /hello /what"); + var builder = new WebHostBuilder() + .Configure(app => + { + app.UseRewriter(options); + app.Run(context => context.Response.WriteAsync(context.Request.Path)); + }); + var server = new TestServer(builder); + + var response = await server.CreateClient().GetStringAsync("/hey/hello"); + + Assert.Equal(response, "/hello"); + } + + [Fact] + public async Task Invoke_RewritePathDoesNotTerminateOnFirstSuccessOfRule() + { + var options = new UrlRewriteOptions().AddModRewriteRule("RewriteRule /hey/(.*) /$1") + .AddModRewriteRule("RewriteRule /hello /what"); + var builder = new WebHostBuilder() + .Configure(app => + { + app.UseRewriter(options); + app.Run(context => context.Response.WriteAsync(context.Request.Path)); + }); + var server = new TestServer(builder); + + var response = await server.CreateClient().GetStringAsync("/hey/hello"); + + Assert.Equal(response, "/what"); + } + [Theory] + [InlineData("", true)] + public void Invoke_StringComparisonTests(string input, bool expected) + { + + } + + [Fact] + public async Task Invoke_ShouldIgnoreComments() + { + var options = new UrlRewriteOptions().ImportFromModRewrite(new StringReader("#RewriteRule ^/hey/(.*) /$1 ")); + var builder = new WebHostBuilder() + .Configure(app => + { + app.UseRewriter(options); + app.Run(context => context.Response.WriteAsync(context.Request.Path)); + }); + var server = new TestServer(builder); + + var response = await server.CreateClient().GetStringAsync("/hey/hello"); + + Assert.Equal(response, "/hey/hello"); + } + + // TODO Add tests to check '//' being handled appropriately. + + [Fact] + public async Task Invoke_ShouldRewriteHomepage() + { + var options = new UrlRewriteOptions().ImportFromModRewrite(new StringReader(@"RewriteRule ^/$ /homepage.html")); + var builder = new WebHostBuilder() + .Configure(app => + { + app.UseRewriter(options); + app.Run(context => context.Response.WriteAsync(context.Request.Path)); + }); + var server = new TestServer(builder); + + var response = await server.CreateClient().GetStringAsync("http://www.foo.org/"); + + Assert.Equal(response, "/homepage.html"); + } + + [Fact] + public async Task Invoke_ShouldIgnorePorts() + { + var options = new UrlRewriteOptions().ImportFromModRewrite(new StringReader(@"RewriteRule ^/$ /homepage.html")); + var builder = new WebHostBuilder() + .Configure(app => + { + app.UseRewriter(options); + app.Run(context => context.Response.WriteAsync(context.Request.Path)); + }); + var server = new TestServer(builder); + + var response = await server.CreateClient().GetStringAsync("http://www.foo.org:42/"); + + Assert.Equal(response, "/homepage.html"); + } + + [Fact] + public async Task Invoke_HandleNegatedRewriteRules() + { + var options = new UrlRewriteOptions().ImportFromModRewrite(new StringReader(@"RewriteRule !^/$ /homepage.html")); + var builder = new WebHostBuilder() + .Configure(app => + { + app.UseRewriter(options); + app.Run(context => context.Response.WriteAsync(context.Request.Path)); + }); + var server = new TestServer(builder); + + var response = await server.CreateClient().GetStringAsync("http://www.foo.org/"); + + Assert.Equal(response, "/"); + } + + [Fact] + public async Task Invoke_BackReferencesShouldBeApplied() + { + var options = new UrlRewriteOptions().ImportFromModRewrite(new StringReader(@"RewriteRule (.*)\.aspx $1.php")); + var builder = new WebHostBuilder() + .Configure(app => + { + app.UseRewriter(options); + app.Run(context => context.Response.WriteAsync(context.Request.Path)); + }); + var server = new TestServer(builder); + + var response = await server.CreateClient().GetStringAsync("http://www.foo.org/homepage.aspx"); + + Assert.Equal(response, "/homepage.php"); + } + + [Theory] + [InlineData("http://www.foo.org/homepage.aspx", @"RewriteRule (.*)\.aspx $1.php", "/homepage.php")] + [InlineData("http://www.foo.org/homepage.ASPX", @"RewriteRule (.*)\.aspx $1.php", "/homepage.ASPX")] + [InlineData("http://www.foo.org/homepage.aspx", @"RewriteRule (.*)\.aspx $1.php [NC]", "/homepage.php")] + [InlineData("http://www.foo.org/homepage.ASPX", @"RewriteRule (.*)\.aspx $1.php [NC]", "/homepage.php")] + [InlineData("http://www.foo.org/homepage.aspx", @"RewriteRule (.*)\.aspx $1.php [nocase]", "/homepage.php")] + [InlineData("http://www.foo.org/homepage.ASPX", @"RewriteRule (.*)\.aspx $1.php [nocase]", "/homepage.php")] + public async Task Invoke_ShouldHandleFlagNoCase(string url, string rule, string expected) + { + var options = new UrlRewriteOptions().ImportFromModRewrite(new StringReader(rule)); + var builder = new WebHostBuilder() + .Configure(app => + { + app.UseRewriter(options); + app.Run(context => context.Response.WriteAsync(context.Request.Path)); + }); + var server = new TestServer(builder); + + var response = await server.CreateClient().GetStringAsync(url); + + Assert.Equal(response, expected); + } + + [Fact(Skip="Need to handle escape characters")] + public async Task Invoke_HandleMultipleBackReferences() + { + var options = new UrlRewriteOptions() + .ImportFromModRewrite(new StringReader(@"RewriteRule ^/blog/([0-9]+)-([a-z]+) /blog/index.php?archive=$1-$2")); + var builder = new WebHostBuilder() + .Configure(app => + { + app.UseRewriter(options); + app.Run(context => context.Response.WriteAsync(context.Request.Path)); + }); + var server = new TestServer(builder); + + var response = await server.CreateClient().GetStringAsync("http://www.foo.org/blog/2016-jun"); + + Assert.Equal(response, @"/blog/index.php?archive=2016-jun"); + } + + [Fact] + public async Task Invoke_CheckFullUrlWithUFlagOnlyPath() + { + var options = new UrlRewriteOptions() + .ImportFromModRewrite(new StringReader(@"RewriteRule (.+) http://www.example.com$1/ [U]")); + var builder = new WebHostBuilder() + .Configure(app => + { + app.UseRewriter(options); + app.Run(context => context.Response.WriteAsync(context.Request.Path)); + }); + var server = new TestServer(builder); + + var response = await server.CreateClient().GetStringAsync("http://www.foo.org/blog/2016-jun"); + + Assert.Equal(response, @"/blog/2016-jun/"); + } + + [Fact] + public async Task Invoke_CheckFullUrlWithUFlag() + { + var options = new UrlRewriteOptions() + .ImportFromModRewrite(new StringReader(@"RewriteRule (.+) http://www.example.com$1/ [U]")); + var builder = new WebHostBuilder() + .Configure(app => + { + app.UseRewriter(options); + app.Run(context => context.Response.WriteAsync(context.Request.Scheme + "://" + context.Request.Host.Host + context.Request.Path + context.Request.QueryString)); + }); + var server = new TestServer(builder); + + var response = await server.CreateClient().GetStringAsync("http://www.foo.org/blog/2016-jun"); + + Assert.Equal(response, @"http://www.example.com/blog/2016-jun/"); + } + + [Fact] + public async Task Invoke_CheckModFileConditions() + { + var options = new UrlRewriteOptions() + .ImportFromModRewrite(new StringReader(@"RewriteRule (.+) http://www.example.com$1/ [U]")); + var builder = new WebHostBuilder() + .Configure(app => + { + app.UseRewriter(options); + app.Run(context => context.Response.WriteAsync(context.Request.Scheme + "://" + context.Request.Host.Host + context.Request.Path + context.Request.QueryString)); + }); + var server = new TestServer(builder); + + var response = await server.CreateClient().GetStringAsync("http://www.foo.org/blog/2016-jun"); + + Assert.Equal(response, @"http://www.example.com/blog/2016-jun/"); + } + + [Theory] + [InlineData("http://www.example.com/foo/")] + public async Task Invoke_EnsureHttps(string input) + { + var options = new UrlRewriteOptions() + .ImportFromModRewrite(new StringReader("RewriteCond %{REQUEST_URI} ^foo/ \nRewriteCond %{HTTPS} !on \nRewriteRule ^(.*)$ https://www.example.com$1 [R=301,L,U]")); + var builder = new WebHostBuilder() + .Configure(app => + { + app.UseRewriter(options); + app.Run(context => context.Response.WriteAsync(context.Request.Scheme + "://" + context.Request.Host.Host + context.Request.Path + context.Request.QueryString)); + }); + var server = new TestServer(builder); + + var response = await server.CreateClient().GetAsync(input); + + Assert.Equal(response.StatusCode, (HttpStatusCode)301); + Assert.Equal(response.Headers.Location.AbsoluteUri, @"https://www.example.com/foo/"); + } + } +} diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/ModRewriteRuleBuilderTest.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/ModRewriteRuleBuilderTest.cs new file mode 100644 index 0000000000..a871f6daa2 --- /dev/null +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/ModRewriteRuleBuilderTest.cs @@ -0,0 +1,14 @@ +// 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; +using Microsoft.AspNetCore.Http; +using Xunit; + +namespace Microsoft.AspNetCore.Rewrite +{ + public class ModRewriteRuleBuilderTest + { + + } +} diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/Properties/AssemblyInfo.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/Properties/AssemblyInfo.cs new file mode 100644 index 0000000000..3fc4674978 --- /dev/null +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/Properties/AssemblyInfo.cs @@ -0,0 +1,19 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("Microsoft.AspNetCore.Rewrite.Tests")] +[assembly: AssemblyTrademark("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("31794f9e-a1aa-4535-b03c-a3233737cd1a")] diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/Rewrite2MiddlewareTests.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/Rewrite2MiddlewareTests.cs new file mode 100644 index 0000000000..7fb8806bdd --- /dev/null +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/Rewrite2MiddlewareTests.cs @@ -0,0 +1,92 @@ +// 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.Linq; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Builder.Internal; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.TestHost; +using Xunit; + +namespace Microsoft.AspNetCore.Rewrite +{ + public class RewriteMiddlewareTests + { + + [Theory(Skip = "Adapting to TestServer")] + [InlineData("/foo", "", "/foo", "/yes")] + [InlineData("/foo", "", "/foo/", "/yes")] + [InlineData("/foo", "/Bar", "/foo", "/yes")] + [InlineData("/foo", "/Bar", "/foo/cho", "/yes")] + [InlineData("/foo", "/Bar", "/foo/cho/", "/yes")] + [InlineData("/foo/cho", "/Bar", "/foo/cho", "/yes")] + [InlineData("/foo/cho", "/Bar", "/foo/cho/do", "/yes")] + public void PathMatchFunc_RewriteDone(string matchPath, string basePath, string requestPath, string rewrite) + { + var context = CreateRequest(basePath, requestPath); + var options = new UrlRewriteOptions().RewritePath(matchPath, rewrite, false); + var builder = new ApplicationBuilder(serviceProvider: null) + .UseRewriter(options); + var app = builder.Build(); + app.Invoke(context).Wait(); + Assert.Equal(rewrite, context.Request.Path); + } + [Theory(Skip = "Adapting to TestServer")] + [InlineData(@"/(?\w+)?/(?\w+)?", @"", "/hey/hello", "/${id}/${name}", "/hello/hey")] + [InlineData(@"/(?\w+)?/(?\w+)?/(?\w+)?", @"", "/hey/hello/what", "/${temp}/${id}/${name}", "/what/hello/hey")] + public void PathMatchFunc_RegexRewriteDone(string matchPath, string basePath, string requestPath, string rewrite, string expected) + { + var context = CreateRequest(basePath, requestPath); + var options = new UrlRewriteOptions().RewritePath(matchPath, rewrite, false); + var builder = new ApplicationBuilder(serviceProvider: null) + .UseRewriter(options); + + var app = builder.Build(); + app.Invoke(context).Wait(); + Assert.Equal(expected, context.Request.Path); + } + + [Fact(Skip = "Adapting to TestServer")] + public void PathMatchFunc_RedirectScheme() + { + HttpContext context = CreateRequest("/", "/"); + context.Request.Scheme = "http"; + var options = new UrlRewriteOptions().RedirectScheme(30); + var builder = new ApplicationBuilder(serviceProvider: null) + .UseRewriter(options); + var app = builder.Build(); + app.Invoke(context).Wait(); + Assert.True(context.Response.Headers["location"].First().StartsWith("https")); + } + + [Theory(Skip = "Adapting to TestServer")] + public async Task PathMatchFunc_RewriteScheme() + { + var options = new UrlRewriteOptions().RewriteScheme(); + var builder = new WebHostBuilder() + .Configure(app => + { + app.UseRewriter(options); + + app.Run(context => context.Response.WriteAsync(context.Request.Path)); + }); + var server = new TestServer(builder); + + var response = await server.CreateClient().GetAsync("http://foo.com/bar"); + + //Assert.True(response.RequestMessage.); + } + + + private HttpContext CreateRequest(string basePath, string requestPath) + { + HttpContext context = new DefaultHttpContext(); + context.Request.PathBase = new PathString(basePath); + context.Request.Path = new PathString(requestPath); + context.Request.Host = new HostString("example.com"); + return context; + } + } +} diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/RewriteTokenizerTest.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/RewriteTokenizerTest.cs new file mode 100644 index 0000000000..2961a3bb25 --- /dev/null +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/RewriteTokenizerTest.cs @@ -0,0 +1,39 @@ +// 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.Collections.Generic; +using System.Linq; +using Microsoft.AspNetCore.Rewrite.ModRewrite; +using Xunit; +namespace Microsoft.AspNetCore.Rewrite +{ + public class RewriteTokenizerTest + { + [Fact] + public void Tokenize_RewriteCondtion() + { + var testString = "RewriteCond %{HTTPS} !-f"; + var tokens = Tokenizer.Tokenize(testString); + + var expected = new List(); + expected.Add("RewriteCond"); + expected.Add("%{HTTPS}"); + expected.Add("!-f"); + Assert.Equal(tokens, expected); + } + + [Fact] + public void Tokenize_CheckEscapedSpaceIgnored() + { + // TODO need consultation on escape characters. + var testString = @"RewriteCond %{HTTPS}\ what !-f"; + var tokens = Tokenizer.Tokenize(testString); + + var expected = new List(); + expected.Add("RewriteCond"); + expected.Add(@"%{HTTPS}\ what"); // TODO maybe just have the space here? talking point + expected.Add("!-f"); + Assert.Equal(tokens,expected); + } + } +} diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/RuleAbstraction/RuleRegexParserTest.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/RuleAbstraction/RuleRegexParserTest.cs new file mode 100644 index 0000000000..bb47b73069 --- /dev/null +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/RuleAbstraction/RuleRegexParserTest.cs @@ -0,0 +1,33 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Rewrite.ModRewrite; +using Microsoft.AspNetCore.Rewrite.Operands; +using Microsoft.AspNetCore.Rewrite.RuleAbstraction; +using Xunit; +namespace Microsoft.AspNetCore.Rewrite.Tests.RuleAbstraction +{ + public class RuleRegexParserTest + { + [Fact] + public void RuleRegexParser_ShouldThrowOnNull() + { + Assert.Throws(() => RuleRegexParser.ParseRuleRegex(null)); + } + + [Fact] + public void RuleRegexParser_ShouldThrowOnEmpty() + { + Assert.Throws(() => RuleRegexParser.ParseRuleRegex(string.Empty)); + } + + [Fact] + public void RuleRegexParser_RegularRegexExpression() + { + var results = RuleRegexParser.ParseRuleRegex("(.*)"); + Assert.False(results.Invert); + Assert.Equal(results.Operand, "(.*)"); + } + } +} diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/project.json b/test/Microsoft.AspNetCore.Rewrite.Tests/project.json new file mode 100644 index 0000000000..904880d014 --- /dev/null +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/project.json @@ -0,0 +1,25 @@ +{ + "version": "1.1.0-*", + "buildOptions": { + "warningsAsErrors": true + }, + "dependencies": { + "dotnet-test-xunit": "2.2.0-*", + "Microsoft.AspNetCore.Rewrite": "1.1.0-*", + "Microsoft.AspNetCore.TestHost": "1.1.0-*", + "Microsoft.Extensions.Logging.Testing": "1.1.0-*", + "xunit": "2.2.0-*" + }, + "frameworks": { + "netcoreapp1.0": { + "dependencies": { + "Microsoft.NETCore.App": { + "version": "1.0.0-*", + "type": "platform" + } + } + }, + "net451": {} + }, + "testRunner": "xunit" +} \ No newline at end of file From fad730441ab107d60c39495205b7e984ac54f0df Mon Sep 17 00:00:00 2001 From: Justin Kotalik Date: Mon, 25 Jul 2016 16:52:01 -0700 Subject: [PATCH 081/307] Fix Assembly Info --- .../Properties/AssemblyInfo.cs | 26 +++++++------------ 1 file changed, 9 insertions(+), 17 deletions(-) diff --git a/src/Microsoft.AspNetCore.Rewrite/Properties/AssemblyInfo.cs b/src/Microsoft.AspNetCore.Rewrite/Properties/AssemblyInfo.cs index c2ce8b42a6..2dc4003a17 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Properties/AssemblyInfo.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Properties/AssemblyInfo.cs @@ -1,19 +1,11 @@ -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; +// 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. -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("Microsoft.AspNetCore.Rewrite")] -[assembly: AssemblyTrademark("")] +using System.Reflection; +using System.Resources; -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] - -// The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("0e7ca1a7-1dc3-4ce6-b9c7-1688fe1410f1")] +[assembly: AssemblyMetadata("Serviceable", "True")] +[assembly: NeutralResourcesLanguage("en-us")] +[assembly: AssemblyCompany("Microsoft Corporation.")] +[assembly: AssemblyCopyright("© Microsoft Corporation. All rights reserved.")] +[assembly: AssemblyProduct("Microsoft ASP.NET Core")] From 68a766f2cd1807e3e8176cc556f0e45d7caaf067 Mon Sep 17 00:00:00 2001 From: Justin Kotalik Date: Tue, 26 Jul 2016 09:38:10 -0700 Subject: [PATCH 082/307] Circular Dependency with Static Files fix. --- samples/RewriteSample/Startup.cs | 2 -- samples/RewriteSample/project.json | 3 +-- src/Microsoft.AspNetCore.Rewrite/project.json | 7 +++---- 3 files changed, 4 insertions(+), 8 deletions(-) diff --git a/samples/RewriteSample/Startup.cs b/samples/RewriteSample/Startup.cs index 3c30c0e6cf..09ae531da5 100644 --- a/samples/RewriteSample/Startup.cs +++ b/samples/RewriteSample/Startup.cs @@ -1,9 +1,7 @@ using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; -using Microsoft.Extensions.Configuration; using Microsoft.AspNetCore.Rewrite; -using Microsoft.Extensions.DependencyInjection; namespace RewriteSample { diff --git a/samples/RewriteSample/project.json b/samples/RewriteSample/project.json index 3bca09f40e..8522010e25 100644 --- a/samples/RewriteSample/project.json +++ b/samples/RewriteSample/project.json @@ -2,8 +2,7 @@ "version": "1.1.0-*", "dependencies": { "Microsoft.AspNetCore.Rewrite": "1.1.0-*", - "Microsoft.AspNetCore.Server.Kestrel": "1.1.0-*", - "Microsoft.AspNetCore.StaticFiles": "1.1.0-*" + "Microsoft.AspNetCore.Server.Kestrel": "1.1.0-*" }, "buildOptions": { "emitEntryPoint": true, diff --git a/src/Microsoft.AspNetCore.Rewrite/project.json b/src/Microsoft.AspNetCore.Rewrite/project.json index e829903667..e4cef1f3c0 100644 --- a/src/Microsoft.AspNetCore.Rewrite/project.json +++ b/src/Microsoft.AspNetCore.Rewrite/project.json @@ -16,16 +16,15 @@ }, "tags": [ "aspnetcore", - "proxy", - "headers", - "xforwarded" + "urlrewrite", + "mod_rewrite" ] }, "dependencies": { "Microsoft.AspNetCore.Hosting.Abstractions": "1.1.0-*", "Microsoft.AspNetCore.Http.Extensions": "1.1.0-*", "Microsoft.Extensions.Configuration.Abstractions": "1.1.0-*", - "Microsoft.Extensions.FileProviders.Physical": "1.1.0-*", + "Microsoft.Extensions.FileProviders.Abstractions": "1.1.0-*", "Microsoft.Extensions.Logging.Abstractions": "1.1.0-*", "Microsoft.Extensions.Options": "1.1.0-*", "System.Text.RegularExpressions": "4.1.0-*" From 6b2e092aadc1ab515e34de65e3d0febce43719d1 Mon Sep 17 00:00:00 2001 From: Justin Kotalik Date: Tue, 26 Jul 2016 10:53:44 -0700 Subject: [PATCH 083/307] Fix for regex coherence error. Small clean up. --- .../UrlRewriteOptionsAddRulesExtensions.cs | 4 ---- src/Microsoft.AspNetCore.Rewrite/project.json | 16 ++++++++++++---- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/src/Microsoft.AspNetCore.Rewrite/UrlRewriteOptionsAddRulesExtensions.cs b/src/Microsoft.AspNetCore.Rewrite/UrlRewriteOptionsAddRulesExtensions.cs index 3d6601baad..9effead54a 100644 --- a/src/Microsoft.AspNetCore.Rewrite/UrlRewriteOptionsAddRulesExtensions.cs +++ b/src/Microsoft.AspNetCore.Rewrite/UrlRewriteOptionsAddRulesExtensions.cs @@ -3,12 +3,8 @@ using System; using System.Collections.Generic; -using System.IO; using System.Text.RegularExpressions; -using Microsoft.AspNetCore.Rewrite.ModRewrite; using Microsoft.AspNetCore.Rewrite.RuleAbstraction; -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.FileProviders; namespace Microsoft.AspNetCore.Rewrite { diff --git a/src/Microsoft.AspNetCore.Rewrite/project.json b/src/Microsoft.AspNetCore.Rewrite/project.json index e4cef1f3c0..e50df4e012 100644 --- a/src/Microsoft.AspNetCore.Rewrite/project.json +++ b/src/Microsoft.AspNetCore.Rewrite/project.json @@ -26,11 +26,19 @@ "Microsoft.Extensions.Configuration.Abstractions": "1.1.0-*", "Microsoft.Extensions.FileProviders.Abstractions": "1.1.0-*", "Microsoft.Extensions.Logging.Abstractions": "1.1.0-*", - "Microsoft.Extensions.Options": "1.1.0-*", - "System.Text.RegularExpressions": "4.1.0-*" + "Microsoft.Extensions.Options": "1.1.0-*" }, "frameworks": { - "net451": {}, - "netstandard1.3": {} + "net451": { + "frameworkAssemblies": { + "System.Xml.Linq": "" + } + }, + "netstandard1.3": { + "dependencies": { + "System.Text.RegularExpressions": "4.1.0-*", + "System.Xml.XDocument": "4.0.11-*" + } + } } } \ No newline at end of file From 4687aad61e1f8bfd62058960313c2321207c589a Mon Sep 17 00:00:00 2001 From: Justin Kotalik Date: Wed, 27 Jul 2016 09:05:16 -0700 Subject: [PATCH 084/307] Fixing language on comment --- src/Microsoft.AspNetCore.Rewrite/ModRewrite/Tokenizer.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Microsoft.AspNetCore.Rewrite/ModRewrite/Tokenizer.cs b/src/Microsoft.AspNetCore.Rewrite/ModRewrite/Tokenizer.cs index 8d6f5c0b26..9d08094baa 100644 --- a/src/Microsoft.AspNetCore.Rewrite/ModRewrite/Tokenizer.cs +++ b/src/Microsoft.AspNetCore.Rewrite/ModRewrite/Tokenizer.cs @@ -56,7 +56,6 @@ namespace Microsoft.AspNetCore.Rewrite.ModRewrite else if (context.Current == Space || context.Current == Tab) { // time to capture! - // TODO: This kinda sucks, set state and skip var token = context.Capture(); if (!string.IsNullOrEmpty(token)) { From a62e327c23c42890f7957084be8ec8523161150e Mon Sep 17 00:00:00 2001 From: Justin Kotalik Date: Wed, 27 Jul 2016 14:47:32 -0700 Subject: [PATCH 085/307] IIS UrlRewrite parsing. --- BasicMiddleware.sln | 1 + NuGetPackageVerifier.json | 3 +- samples/RewriteSample/Rewrite.txt | 1 - samples/RewriteSample/Startup.cs | 8 +- samples/RewriteSample/UrlRewrite.xml | 19 ++ .../ModRewrite/ModRewriteExtensions.cs | 19 +- .../ModRewrite/Pattern.cs | 2 +- .../ModRewrite/PatternSegment.cs | 2 +- .../Operands/IntegerOperand.cs | 1 + .../UrlRewrite/ActionType.cs | 14 ++ .../UrlRewrite/Condition.cs | 16 ++ .../UrlRewrite/Conditions.cs | 14 ++ .../UrlRewrite/InitialMatch.cs | 14 ++ .../UrlRewrite/InputParser.cs | 197 +++++++++++++++ .../UrlRewrite/LogicalGrouping.cs | 11 + .../UrlRewrite/MatchType.cs | 12 + .../UrlRewrite/Pattern.cs | 30 +++ .../UrlRewrite/PatternSegment.cs | 15 ++ .../PatternSegments/ConditionMatchSegment.cs | 23 ++ .../PatternSegments/HeaderSegment.cs | 23 ++ .../PatternSegments/IsHttpsSegment.cs | 16 ++ .../PatternSegments/LiteralSegment.cs | 23 ++ .../PatternSegments/LocalAddressSegment.cs | 16 ++ .../PatternSegments/QueryStringSegment.cs | 16 ++ .../PatternSegments/RemoteAddressSegment.cs | 16 ++ .../PatternSegments/RemotePortSegment.cs | 17 ++ .../PatternSegments/RuleMatchSegment.cs | 23 ++ .../PatternSegments/ToLowerSegment.cs | 24 ++ .../PatternSegments/UrlEncodeSegment.cs | 25 ++ .../UrlRewrite/PatternSegments/UrlSegment.cs | 16 ++ .../UrlRewrite/PatternSyntax.cs | 12 + .../UrlRewrite/RedirectType.cs | 13 + .../UrlRewrite/RewriteTags.cs | 34 +++ .../UrlRewrite/ServerVariables.cs | 61 +++++ .../UrlRewrite/UrlAction.cs | 14 ++ .../UrlRewrite/UrlRewriteExtensions.cs | 44 ++++ .../UrlRewrite/UrlRewriteFileParser.cs | 228 ++++++++++++++++++ .../UrlRewrite/UrlRewriteRule.cs | 25 ++ src/Microsoft.AspNetCore.Rewrite/project.json | 1 + .../UrlRewrite/FileParserTests.cs | 212 ++++++++++++++++ .../UrlRewrite/InputParserTests.cs | 113 +++++++++ 41 files changed, 1363 insertions(+), 11 deletions(-) create mode 100644 samples/RewriteSample/UrlRewrite.xml create mode 100644 src/Microsoft.AspNetCore.Rewrite/UrlRewrite/ActionType.cs create mode 100644 src/Microsoft.AspNetCore.Rewrite/UrlRewrite/Condition.cs create mode 100644 src/Microsoft.AspNetCore.Rewrite/UrlRewrite/Conditions.cs create mode 100644 src/Microsoft.AspNetCore.Rewrite/UrlRewrite/InitialMatch.cs create mode 100644 src/Microsoft.AspNetCore.Rewrite/UrlRewrite/InputParser.cs create mode 100644 src/Microsoft.AspNetCore.Rewrite/UrlRewrite/LogicalGrouping.cs create mode 100644 src/Microsoft.AspNetCore.Rewrite/UrlRewrite/MatchType.cs create mode 100644 src/Microsoft.AspNetCore.Rewrite/UrlRewrite/Pattern.cs create mode 100644 src/Microsoft.AspNetCore.Rewrite/UrlRewrite/PatternSegment.cs create mode 100644 src/Microsoft.AspNetCore.Rewrite/UrlRewrite/PatternSegments/ConditionMatchSegment.cs create mode 100644 src/Microsoft.AspNetCore.Rewrite/UrlRewrite/PatternSegments/HeaderSegment.cs create mode 100644 src/Microsoft.AspNetCore.Rewrite/UrlRewrite/PatternSegments/IsHttpsSegment.cs create mode 100644 src/Microsoft.AspNetCore.Rewrite/UrlRewrite/PatternSegments/LiteralSegment.cs create mode 100644 src/Microsoft.AspNetCore.Rewrite/UrlRewrite/PatternSegments/LocalAddressSegment.cs create mode 100644 src/Microsoft.AspNetCore.Rewrite/UrlRewrite/PatternSegments/QueryStringSegment.cs create mode 100644 src/Microsoft.AspNetCore.Rewrite/UrlRewrite/PatternSegments/RemoteAddressSegment.cs create mode 100644 src/Microsoft.AspNetCore.Rewrite/UrlRewrite/PatternSegments/RemotePortSegment.cs create mode 100644 src/Microsoft.AspNetCore.Rewrite/UrlRewrite/PatternSegments/RuleMatchSegment.cs create mode 100644 src/Microsoft.AspNetCore.Rewrite/UrlRewrite/PatternSegments/ToLowerSegment.cs create mode 100644 src/Microsoft.AspNetCore.Rewrite/UrlRewrite/PatternSegments/UrlEncodeSegment.cs create mode 100644 src/Microsoft.AspNetCore.Rewrite/UrlRewrite/PatternSegments/UrlSegment.cs create mode 100644 src/Microsoft.AspNetCore.Rewrite/UrlRewrite/PatternSyntax.cs create mode 100644 src/Microsoft.AspNetCore.Rewrite/UrlRewrite/RedirectType.cs create mode 100644 src/Microsoft.AspNetCore.Rewrite/UrlRewrite/RewriteTags.cs create mode 100644 src/Microsoft.AspNetCore.Rewrite/UrlRewrite/ServerVariables.cs create mode 100644 src/Microsoft.AspNetCore.Rewrite/UrlRewrite/UrlAction.cs create mode 100644 src/Microsoft.AspNetCore.Rewrite/UrlRewrite/UrlRewriteExtensions.cs create mode 100644 src/Microsoft.AspNetCore.Rewrite/UrlRewrite/UrlRewriteFileParser.cs create mode 100644 src/Microsoft.AspNetCore.Rewrite/UrlRewrite/UrlRewriteRule.cs create mode 100644 test/Microsoft.AspNetCore.Rewrite.Tests/UrlRewrite/FileParserTests.cs create mode 100644 test/Microsoft.AspNetCore.Rewrite.Tests/UrlRewrite/InputParserTests.cs diff --git a/BasicMiddleware.sln b/BasicMiddleware.sln index 9ac27d55d2..a431cdab18 100644 --- a/BasicMiddleware.sln +++ b/BasicMiddleware.sln @@ -13,6 +13,7 @@ EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{99B72A07-32D6-434D-B44D-D064E3C13E08}" ProjectSection(SolutionItems) = preProject global.json = global.json + NuGetPackageVerifier.json = NuGetPackageVerifier.json EndProjectSection EndProject Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNetCore.Buffering", "src\Microsoft.AspNetCore.Buffering\Microsoft.AspNetCore.Buffering.xproj", "{2363D0DD-A3BF-437E-9B64-B33AE132D875}" diff --git a/NuGetPackageVerifier.json b/NuGetPackageVerifier.json index 0895735cea..5fc01f59bd 100644 --- a/NuGetPackageVerifier.json +++ b/NuGetPackageVerifier.json @@ -5,7 +5,8 @@ ], "packages": { "Microsoft.AspNetCore.Buffering": { }, - "Microsoft.AspNetCore.HttpOverrides": { } + "Microsoft.AspNetCore.HttpOverrides": { }, + "Microsoft.AspNetCore.Rewrite": { } } }, "Default": { // Rules to run for packages not listed in any other set. diff --git a/samples/RewriteSample/Rewrite.txt b/samples/RewriteSample/Rewrite.txt index fdc4175f86..ed2ae33ce1 100644 --- a/samples/RewriteSample/Rewrite.txt +++ b/samples/RewriteSample/Rewrite.txt @@ -1,5 +1,4 @@ # Ensure Https -RewriteCond %{REQUEST_URI} ^foo/ RewriteCond %{HTTPS} off # U is a new flag to represent full URL rewrites RewriteRule ^(.*)$ https://www.example.com$1 [L,U] diff --git a/samples/RewriteSample/Startup.cs b/samples/RewriteSample/Startup.cs index 09ae531da5..f476c62dd5 100644 --- a/samples/RewriteSample/Startup.cs +++ b/samples/RewriteSample/Startup.cs @@ -7,11 +7,13 @@ namespace RewriteSample { public class Startup { - public void Configure(IApplicationBuilder app) - { + public void Configure(IApplicationBuilder app, IHostingEnvironment hostingEnv) + { app.UseRewriter(new UrlRewriteOptions() - .ImportFromModRewrite("Rewrite.txt")); + .ImportFromUrlRewrite(hostingEnv, "UrlRewrite.xml") + .ImportFromModRewrite(hostingEnv, "Rewrite.txt")); app.Run(context => context.Response.WriteAsync(context.Request.Path)); + } public static void Main(string[] args) diff --git a/samples/RewriteSample/UrlRewrite.xml b/samples/RewriteSample/UrlRewrite.xml new file mode 100644 index 0000000000..708ef0e8be --- /dev/null +++ b/samples/RewriteSample/UrlRewrite.xml @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Rewrite/ModRewrite/ModRewriteExtensions.cs b/src/Microsoft.AspNetCore.Rewrite/ModRewrite/ModRewriteExtensions.cs index 445ecde591..a5c4986e53 100644 --- a/src/Microsoft.AspNetCore.Rewrite/ModRewrite/ModRewriteExtensions.cs +++ b/src/Microsoft.AspNetCore.Rewrite/ModRewrite/ModRewriteExtensions.cs @@ -3,6 +3,7 @@ using System; using System.IO; +using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Rewrite.ModRewrite; namespace Microsoft.AspNetCore.Rewrite @@ -13,17 +14,27 @@ namespace Microsoft.AspNetCore.Rewrite /// Imports rules from a mod_rewrite file and adds the rules to current rules. /// /// The UrlRewrite options. + /// /// The path to the file containing mod_rewrite rules. - public static UrlRewriteOptions ImportFromModRewrite(this UrlRewriteOptions options, string filePath) + public static UrlRewriteOptions ImportFromModRewrite(this UrlRewriteOptions options, IHostingEnvironment hostingEnv, string filePath) { - // TODO use IHostingEnvironment as param. + if (options == null) + { + throw new ArgumentNullException("UrlRewriteOptions is null"); + } + + if (hostingEnv == null) + { + throw new ArgumentNullException("HostingEnvironment is null"); + } + if (string.IsNullOrEmpty(filePath)) { throw new ArgumentException(nameof(filePath)); } - // TODO IHosting to fix! - using (var stream = File.OpenRead(filePath)) + var path = Path.Combine(hostingEnv.ContentRootPath, filePath); + using (var stream = File.OpenRead(path)) { options.Rules.AddRange(FileParser.Parse(new StreamReader(stream))); }; diff --git a/src/Microsoft.AspNetCore.Rewrite/ModRewrite/Pattern.cs b/src/Microsoft.AspNetCore.Rewrite/ModRewrite/Pattern.cs index b3070faf1d..8adcad99dd 100644 --- a/src/Microsoft.AspNetCore.Rewrite/ModRewrite/Pattern.cs +++ b/src/Microsoft.AspNetCore.Rewrite/ModRewrite/Pattern.cs @@ -8,7 +8,7 @@ using System.Text.RegularExpressions; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Rewrite.ModRewrite; -namespace Microsoft.AspNetCore.Rewrite +namespace Microsoft.AspNetCore.Rewrite.ModRewrite { /// /// Contains a sequence of pattern segments, which on obtaining the context, will create the appropriate diff --git a/src/Microsoft.AspNetCore.Rewrite/ModRewrite/PatternSegment.cs b/src/Microsoft.AspNetCore.Rewrite/ModRewrite/PatternSegment.cs index 13a22cb50c..8cb0e961b7 100644 --- a/src/Microsoft.AspNetCore.Rewrite/ModRewrite/PatternSegment.cs +++ b/src/Microsoft.AspNetCore.Rewrite/ModRewrite/PatternSegment.cs @@ -1,7 +1,7 @@ // 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. -namespace Microsoft.AspNetCore.Rewrite +namespace Microsoft.AspNetCore.Rewrite.ModRewrite { /// /// A Pattern segment contains a portion of the test string/ substitution segment with a type associated. diff --git a/src/Microsoft.AspNetCore.Rewrite/Operands/IntegerOperand.cs b/src/Microsoft.AspNetCore.Rewrite/Operands/IntegerOperand.cs index 1d19c4a620..e65d7bac93 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Operands/IntegerOperand.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Operands/IntegerOperand.cs @@ -25,6 +25,7 @@ namespace Microsoft.AspNetCore.Rewrite.Operands { throw new FormatException("Syntax error for integers in comparison."); } + Value = compValue; Operation = operation; } diff --git a/src/Microsoft.AspNetCore.Rewrite/UrlRewrite/ActionType.cs b/src/Microsoft.AspNetCore.Rewrite/UrlRewrite/ActionType.cs new file mode 100644 index 0000000000..a7eff7669d --- /dev/null +++ b/src/Microsoft.AspNetCore.Rewrite/UrlRewrite/ActionType.cs @@ -0,0 +1,14 @@ +// 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. + +namespace Microsoft.AspNetCore.Rewrite.UrlRewrite +{ + public enum ActionType + { + None, + Rewrite, + Redirect, + CustomResponse, + AbortRequest + } +} diff --git a/src/Microsoft.AspNetCore.Rewrite/UrlRewrite/Condition.cs b/src/Microsoft.AspNetCore.Rewrite/UrlRewrite/Condition.cs new file mode 100644 index 0000000000..17030d2d5f --- /dev/null +++ b/src/Microsoft.AspNetCore.Rewrite/UrlRewrite/Condition.cs @@ -0,0 +1,16 @@ +// 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.Text.RegularExpressions; + +namespace Microsoft.AspNetCore.Rewrite.UrlRewrite +{ + public class Condition + { + public Pattern Input { get; set; } + public Regex MatchPattern { get; set; } + public bool Negate { get; set; } + public bool IgnoreCase { get; set; } = true; + public MatchType MatchType { get; set; } = MatchType.Pattern; + } +} diff --git a/src/Microsoft.AspNetCore.Rewrite/UrlRewrite/Conditions.cs b/src/Microsoft.AspNetCore.Rewrite/UrlRewrite/Conditions.cs new file mode 100644 index 0000000000..0e3ec81df7 --- /dev/null +++ b/src/Microsoft.AspNetCore.Rewrite/UrlRewrite/Conditions.cs @@ -0,0 +1,14 @@ +// 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.Collections.Generic; + +namespace Microsoft.AspNetCore.Rewrite.UrlRewrite +{ + public class Conditions + { + public List ConditionList { get; set; } = new List(); + public LogicalGrouping MatchType { get; set; } // default is MatchAll + public bool TrackingAllCaptures { get; set; } + } +} diff --git a/src/Microsoft.AspNetCore.Rewrite/UrlRewrite/InitialMatch.cs b/src/Microsoft.AspNetCore.Rewrite/UrlRewrite/InitialMatch.cs new file mode 100644 index 0000000000..bfbdcad006 --- /dev/null +++ b/src/Microsoft.AspNetCore.Rewrite/UrlRewrite/InitialMatch.cs @@ -0,0 +1,14 @@ +// 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.Text.RegularExpressions; + +namespace Microsoft.AspNetCore.Rewrite.UrlRewrite +{ + public class InitialMatch + { + public Regex Url { get; set; } // TODO must be a non-empty string, throw in check after parsing? + public bool IgnoreCase { get; set; } = true; + public bool Negate { get; set; } + } +} diff --git a/src/Microsoft.AspNetCore.Rewrite/UrlRewrite/InputParser.cs b/src/Microsoft.AspNetCore.Rewrite/UrlRewrite/InputParser.cs new file mode 100644 index 0000000000..eb8bbd0410 --- /dev/null +++ b/src/Microsoft.AspNetCore.Rewrite/UrlRewrite/InputParser.cs @@ -0,0 +1,197 @@ +// 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; +using System.Collections.Generic; +using System.Text.Encodings.Web; +using Microsoft.AspNetCore.Rewrite.Internal; +using Microsoft.AspNetCore.Rewrite.UrlRewrite.PatternSegments; + +namespace Microsoft.AspNetCore.Rewrite.UrlRewrite +{ + /// + /// + public class InputParser + { + private const char Colon = ':'; + private const char OpenBrace = '{'; + private const char CloseBrace = '}'; + + /// + /// Creates a pattern, which is a template to create a new test string to + /// compare to the condition. Can contain server variables, back references, etc. + /// + /// + /// A new , containing a list of + public static Pattern ParseInputString(string testString) + { + if (testString == null) + { + testString = string.Empty; + } + + var context = new ParserContext(testString); + return ParseString(context); + } + + private static Pattern ParseString(ParserContext context) + { + var results = new List(); + while (context.Next()) + { + if (context.Current == OpenBrace) + { + // This is a server parameter, parse for a condition variable + if (!context.Next()) + { + throw new FormatException(context.Error()); + } + ParseParameter(context, results); + } + else if (context.Current == CloseBrace) + { + // TODO we should be throwing a syntax error if we have uneven close braces + // Can fix by keeping track of the number of '{' and '}' with an int, where { + // increments and } decrements. Throw if < 0. + return new Pattern(results); + } + else + { + // Parse for literals, which will return on either the end of the test string + // or when it hits a special character + ParseLiteral(context, results); + } + } + return new Pattern(results); + } + + private static void ParseParameter(ParserContext context, List results) + { + context.Mark(); + // Four main cases: + // 1. {NAME} - Server Variable, create lambda to get the part of the context + // 2. {R:1} - Rule parameter + // 3. {C:1} - Condition Parameter + // 4. {function:xxx} - String function + // TODO consider perf here. This is on startup and will only happen one time + // (unless we support Reload) + string parameter; + while (context.Next()) + { + if (context.Current == CloseBrace) + { + // This is just a server variable, so we do a lookup and verify the server variable exists. + parameter = context.Capture(); + results.Add(ServerVariables.FindServerVariable(parameter)); + return; + } + else if (context.Current == Colon) + { + parameter = context.Capture(); + + // Only 5 strings to expect here. Case sensitive. + switch (parameter) + { + case "ToLower": + { + var pattern = ParseString(context); + results.Add(new ToLowerSegment(pattern)); + + // at this point, we expect our context to be on the ending closing brace, + // because the ParseString() call will increment the context until it + // has processed the new string. + if (context.Current != CloseBrace) + { + throw new FormatException("Lacking close brace for parameter at index: " + context.GetIndex()); + } + } + break; + case "UrlDecode": + { + throw new NotImplementedException("UrlDecode is not supported."); + } + case "UrlEncode": + { + var pattern = ParseString(context); + results.Add(new UrlEncodeSegment(pattern)); + + if (context.Current != CloseBrace) + { + throw new FormatException("Lacking close brace for parameter at index: " + context.GetIndex()); + } + } + break; + case "R": + { + var index = GetBackReferenceIndex(context); + results.Add(new RuleMatchSegment(index)); + return; + } + case "C": + { + var index = GetBackReferenceIndex(context); + results.Add(new ConditionMatchSegment(index)); + return; + } + default: + throw new FormatException("Unrecognized parameter type: " + parameter + ", terminated at index: " + context.GetIndex()); + } + } + } + } + + private static int GetBackReferenceIndex(ParserContext context) + { + if (!context.Next()) + { + throw new FormatException("No index avaible for backreference at index: " + context.GetIndex()); + } + + context.Mark(); + while (context.Current != CloseBrace) + { + if (!context.Next()) + { + throw new FormatException("Lacking close brace for parameter at index: " + context.GetIndex()); + } + } + + var res = context.Capture(); + int index; + if (!int.TryParse(res, out index)) + { + throw new FormatException("Syntax error, invalid integer in response parameter at index: " + context.GetIndex()); + } + + if (index > 9 || index < 0) + { + throw new FormatException("Invalid integer into backreference " + index + "at index: " + context.GetIndex()); + } + return index; + } + + private static bool ParseLiteral(ParserContext context, List results) + { + context.Mark(); + string literal; + while (true) + { + if (context.Current == OpenBrace || context.Current == CloseBrace) + { + literal = context.Capture(); + context.Back(); + break; + } + + if (!context.Next()) + { + literal = context.Capture(); + break; + } + } + + results.Add(new LiteralSegment(literal)); + return true; + } + } +} diff --git a/src/Microsoft.AspNetCore.Rewrite/UrlRewrite/LogicalGrouping.cs b/src/Microsoft.AspNetCore.Rewrite/UrlRewrite/LogicalGrouping.cs new file mode 100644 index 0000000000..5f2568c8e6 --- /dev/null +++ b/src/Microsoft.AspNetCore.Rewrite/UrlRewrite/LogicalGrouping.cs @@ -0,0 +1,11 @@ +// 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. + +namespace Microsoft.AspNetCore.Rewrite.UrlRewrite +{ + public enum LogicalGrouping + { + MatchAll, + MatchAny + } +} diff --git a/src/Microsoft.AspNetCore.Rewrite/UrlRewrite/MatchType.cs b/src/Microsoft.AspNetCore.Rewrite/UrlRewrite/MatchType.cs new file mode 100644 index 0000000000..260ecba3d0 --- /dev/null +++ b/src/Microsoft.AspNetCore.Rewrite/UrlRewrite/MatchType.cs @@ -0,0 +1,12 @@ +// 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. + +namespace Microsoft.AspNetCore.Rewrite.UrlRewrite +{ + public enum MatchType + { + Pattern, + IsFile, + IsDirectory + } +} diff --git a/src/Microsoft.AspNetCore.Rewrite/UrlRewrite/Pattern.cs b/src/Microsoft.AspNetCore.Rewrite/UrlRewrite/Pattern.cs new file mode 100644 index 0000000000..aa62e3c825 --- /dev/null +++ b/src/Microsoft.AspNetCore.Rewrite/UrlRewrite/Pattern.cs @@ -0,0 +1,30 @@ +// 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.Collections.Generic; +using System.Text; +using System.Text.RegularExpressions; +using Microsoft.AspNetCore.Http; + +namespace Microsoft.AspNetCore.Rewrite.UrlRewrite +{ + public class Pattern + { + public IList PatternSegments { get; } + + public Pattern(List patternSegments) + { + PatternSegments = patternSegments; + } + + public string Evaluate(HttpContext context, Match ruleMatch, Match condMatch) + { + var strBuilder = new StringBuilder(); + foreach (var pattern in PatternSegments) + { + strBuilder.Append(pattern.Evaluate(context, ruleMatch, condMatch)); + } + return strBuilder.ToString(); + } + } +} diff --git a/src/Microsoft.AspNetCore.Rewrite/UrlRewrite/PatternSegment.cs b/src/Microsoft.AspNetCore.Rewrite/UrlRewrite/PatternSegment.cs new file mode 100644 index 0000000000..d80755d77a --- /dev/null +++ b/src/Microsoft.AspNetCore.Rewrite/UrlRewrite/PatternSegment.cs @@ -0,0 +1,15 @@ +// 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; +using System.Text.RegularExpressions; +using Microsoft.AspNetCore.Http; + +namespace Microsoft.AspNetCore.Rewrite.UrlRewrite +{ + public abstract class PatternSegment + { + // Match from prevRule, Match from prevCond + public abstract string Evaluate(HttpContext context, Match ruleMatch, Match condMatch); + } +} diff --git a/src/Microsoft.AspNetCore.Rewrite/UrlRewrite/PatternSegments/ConditionMatchSegment.cs b/src/Microsoft.AspNetCore.Rewrite/UrlRewrite/PatternSegments/ConditionMatchSegment.cs new file mode 100644 index 0000000000..ec53c1549a --- /dev/null +++ b/src/Microsoft.AspNetCore.Rewrite/UrlRewrite/PatternSegments/ConditionMatchSegment.cs @@ -0,0 +1,23 @@ +// 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.Text.RegularExpressions; +using Microsoft.AspNetCore.Http; + +namespace Microsoft.AspNetCore.Rewrite.UrlRewrite.PatternSegments +{ + public class ConditionMatchSegment : PatternSegment + { + public int Index { get; set; } + + public ConditionMatchSegment(int index) + { + Index = index; + } + + public override string Evaluate(HttpContext context, Match ruleMatch, Match condMatch) + { + return condMatch?.Groups[Index]?.Value; + } + } +} diff --git a/src/Microsoft.AspNetCore.Rewrite/UrlRewrite/PatternSegments/HeaderSegment.cs b/src/Microsoft.AspNetCore.Rewrite/UrlRewrite/PatternSegments/HeaderSegment.cs new file mode 100644 index 0000000000..0353598bea --- /dev/null +++ b/src/Microsoft.AspNetCore.Rewrite/UrlRewrite/PatternSegments/HeaderSegment.cs @@ -0,0 +1,23 @@ +// 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.Text.RegularExpressions; +using Microsoft.AspNetCore.Http; + +namespace Microsoft.AspNetCore.Rewrite.UrlRewrite.PatternSegments +{ + public class HeaderSegment : PatternSegment + { + public string Header { get; set; } + + public HeaderSegment(string header) + { + Header = header; + } + + public override string Evaluate(HttpContext context, Match ruleMatch, Match condMatch) + { + return context.Request.Headers[Header]; + } + } +} diff --git a/src/Microsoft.AspNetCore.Rewrite/UrlRewrite/PatternSegments/IsHttpsSegment.cs b/src/Microsoft.AspNetCore.Rewrite/UrlRewrite/PatternSegments/IsHttpsSegment.cs new file mode 100644 index 0000000000..ff6be8e823 --- /dev/null +++ b/src/Microsoft.AspNetCore.Rewrite/UrlRewrite/PatternSegments/IsHttpsSegment.cs @@ -0,0 +1,16 @@ +// 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.Text.RegularExpressions; +using Microsoft.AspNetCore.Http; + +namespace Microsoft.AspNetCore.Rewrite.UrlRewrite.PatternSegments +{ + public class IsHttpsSegment : PatternSegment + { + public override string Evaluate(HttpContext context, Match ruleMatch, Match condMatch) + { + return context.Request.IsHttps ? "ON" : "OFF"; + } + } +} diff --git a/src/Microsoft.AspNetCore.Rewrite/UrlRewrite/PatternSegments/LiteralSegment.cs b/src/Microsoft.AspNetCore.Rewrite/UrlRewrite/PatternSegments/LiteralSegment.cs new file mode 100644 index 0000000000..43b45fec9c --- /dev/null +++ b/src/Microsoft.AspNetCore.Rewrite/UrlRewrite/PatternSegments/LiteralSegment.cs @@ -0,0 +1,23 @@ +// 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.Text.RegularExpressions; +using Microsoft.AspNetCore.Http; + +namespace Microsoft.AspNetCore.Rewrite.UrlRewrite.PatternSegments +{ + public class LiteralSegment : PatternSegment + { + public string Literal { get; set; } + + public LiteralSegment(string literal) + { + Literal = literal; + } + + public override string Evaluate(HttpContext context, Match ruleMatch, Match condMatch) + { + return Literal; + } + } +} diff --git a/src/Microsoft.AspNetCore.Rewrite/UrlRewrite/PatternSegments/LocalAddressSegment.cs b/src/Microsoft.AspNetCore.Rewrite/UrlRewrite/PatternSegments/LocalAddressSegment.cs new file mode 100644 index 0000000000..a26e79238b --- /dev/null +++ b/src/Microsoft.AspNetCore.Rewrite/UrlRewrite/PatternSegments/LocalAddressSegment.cs @@ -0,0 +1,16 @@ +// 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.Text.RegularExpressions; +using Microsoft.AspNetCore.Http; + +namespace Microsoft.AspNetCore.Rewrite.UrlRewrite.PatternSegments +{ + public class LocalAddressSegment : PatternSegment + { + public override string Evaluate(HttpContext context, Match ruleMatch, Match condMatch) + { + return context.Connection.LocalIpAddress?.ToString(); + } + } +} diff --git a/src/Microsoft.AspNetCore.Rewrite/UrlRewrite/PatternSegments/QueryStringSegment.cs b/src/Microsoft.AspNetCore.Rewrite/UrlRewrite/PatternSegments/QueryStringSegment.cs new file mode 100644 index 0000000000..5b51d8f98c --- /dev/null +++ b/src/Microsoft.AspNetCore.Rewrite/UrlRewrite/PatternSegments/QueryStringSegment.cs @@ -0,0 +1,16 @@ +// 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.Text.RegularExpressions; +using Microsoft.AspNetCore.Http; + +namespace Microsoft.AspNetCore.Rewrite.UrlRewrite.PatternSegments +{ + public class QueryStringSegment : PatternSegment + { + public override string Evaluate(HttpContext context, Match ruleMatch, Match condMatch) + { + return context.Request.QueryString.ToString(); + } + } +} diff --git a/src/Microsoft.AspNetCore.Rewrite/UrlRewrite/PatternSegments/RemoteAddressSegment.cs b/src/Microsoft.AspNetCore.Rewrite/UrlRewrite/PatternSegments/RemoteAddressSegment.cs new file mode 100644 index 0000000000..20bf50c523 --- /dev/null +++ b/src/Microsoft.AspNetCore.Rewrite/UrlRewrite/PatternSegments/RemoteAddressSegment.cs @@ -0,0 +1,16 @@ +// 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.Text.RegularExpressions; +using Microsoft.AspNetCore.Http; + +namespace Microsoft.AspNetCore.Rewrite.UrlRewrite.PatternSegments +{ + public class RemoteAddressSegment : PatternSegment + { + public override string Evaluate(HttpContext context, Match ruleMatch, Match condMatch) + { + return context.Connection.RemoteIpAddress?.ToString(); + } + } +} \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Rewrite/UrlRewrite/PatternSegments/RemotePortSegment.cs b/src/Microsoft.AspNetCore.Rewrite/UrlRewrite/PatternSegments/RemotePortSegment.cs new file mode 100644 index 0000000000..bb1c391b29 --- /dev/null +++ b/src/Microsoft.AspNetCore.Rewrite/UrlRewrite/PatternSegments/RemotePortSegment.cs @@ -0,0 +1,17 @@ +// 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.Globalization; +using System.Text.RegularExpressions; +using Microsoft.AspNetCore.Http; + +namespace Microsoft.AspNetCore.Rewrite.UrlRewrite.PatternSegments +{ + public class RemotePortSegment : PatternSegment + { + public override string Evaluate(HttpContext context, Match ruleMatch, Match condMatch) + { + return context.Connection.RemotePort.ToString(CultureInfo.InvariantCulture); + } + } +} diff --git a/src/Microsoft.AspNetCore.Rewrite/UrlRewrite/PatternSegments/RuleMatchSegment.cs b/src/Microsoft.AspNetCore.Rewrite/UrlRewrite/PatternSegments/RuleMatchSegment.cs new file mode 100644 index 0000000000..2ebbb0f61c --- /dev/null +++ b/src/Microsoft.AspNetCore.Rewrite/UrlRewrite/PatternSegments/RuleMatchSegment.cs @@ -0,0 +1,23 @@ +// 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.Text.RegularExpressions; +using Microsoft.AspNetCore.Http; + +namespace Microsoft.AspNetCore.Rewrite.UrlRewrite.PatternSegments +{ + public class RuleMatchSegment : PatternSegment + { + public int Index { get; set; } + + public RuleMatchSegment(int index) + { + Index = index; + } + + public override string Evaluate(HttpContext context, Match ruleMatch, Match condMatch) + { + return ruleMatch?.Groups[Index]?.Value; + } + } +} diff --git a/src/Microsoft.AspNetCore.Rewrite/UrlRewrite/PatternSegments/ToLowerSegment.cs b/src/Microsoft.AspNetCore.Rewrite/UrlRewrite/PatternSegments/ToLowerSegment.cs new file mode 100644 index 0000000000..945bdd19f8 --- /dev/null +++ b/src/Microsoft.AspNetCore.Rewrite/UrlRewrite/PatternSegments/ToLowerSegment.cs @@ -0,0 +1,24 @@ +// 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.Text.RegularExpressions; +using Microsoft.AspNetCore.Http; + +namespace Microsoft.AspNetCore.Rewrite.UrlRewrite.PatternSegments +{ + public class ToLowerSegment : PatternSegment + { + public Pattern Pattern { get; set; } + + public ToLowerSegment(Pattern pattern) + { + Pattern = pattern; + } + + public override string Evaluate(HttpContext context, Match ruleMatch, Match condMatch) + { + var pattern = Pattern.Evaluate(context, ruleMatch, condMatch); + return pattern.ToLowerInvariant(); + } + } +} diff --git a/src/Microsoft.AspNetCore.Rewrite/UrlRewrite/PatternSegments/UrlEncodeSegment.cs b/src/Microsoft.AspNetCore.Rewrite/UrlRewrite/PatternSegments/UrlEncodeSegment.cs new file mode 100644 index 0000000000..4f97346a8d --- /dev/null +++ b/src/Microsoft.AspNetCore.Rewrite/UrlRewrite/PatternSegments/UrlEncodeSegment.cs @@ -0,0 +1,25 @@ +// 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.Text.Encodings.Web; +using System.Text.RegularExpressions; +using Microsoft.AspNetCore.Http; + +namespace Microsoft.AspNetCore.Rewrite.UrlRewrite.PatternSegments +{ + public class UrlEncodeSegment : PatternSegment + { + public Pattern Pattern { get; set; } + + public UrlEncodeSegment(Pattern pattern) + { + Pattern = pattern; + } + + public override string Evaluate(HttpContext context, Match ruleMatch, Match condMatch) + { + var pattern = Pattern.Evaluate(context, ruleMatch, condMatch); + return UrlEncoder.Default.Encode(pattern); + } + } +} diff --git a/src/Microsoft.AspNetCore.Rewrite/UrlRewrite/PatternSegments/UrlSegment.cs b/src/Microsoft.AspNetCore.Rewrite/UrlRewrite/PatternSegments/UrlSegment.cs new file mode 100644 index 0000000000..9dc24ec930 --- /dev/null +++ b/src/Microsoft.AspNetCore.Rewrite/UrlRewrite/PatternSegments/UrlSegment.cs @@ -0,0 +1,16 @@ +// 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.Text.RegularExpressions; +using Microsoft.AspNetCore.Http; + +namespace Microsoft.AspNetCore.Rewrite.UrlRewrite.PatternSegments +{ + public class UrlSegment : PatternSegment + { + public override string Evaluate(HttpContext context, Match ruleMatch, Match condMatch) + { + return context.Request.Path.ToString(); + } + } +} diff --git a/src/Microsoft.AspNetCore.Rewrite/UrlRewrite/PatternSyntax.cs b/src/Microsoft.AspNetCore.Rewrite/UrlRewrite/PatternSyntax.cs new file mode 100644 index 0000000000..efdf403427 --- /dev/null +++ b/src/Microsoft.AspNetCore.Rewrite/UrlRewrite/PatternSyntax.cs @@ -0,0 +1,12 @@ +// 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. + +namespace Microsoft.AspNetCore.Rewrite.UrlRewrite +{ + public enum PatternSyntax + { + ECMAScript, + WildCard, + ExactMatch + } +} diff --git a/src/Microsoft.AspNetCore.Rewrite/UrlRewrite/RedirectType.cs b/src/Microsoft.AspNetCore.Rewrite/UrlRewrite/RedirectType.cs new file mode 100644 index 0000000000..5d842c57d4 --- /dev/null +++ b/src/Microsoft.AspNetCore.Rewrite/UrlRewrite/RedirectType.cs @@ -0,0 +1,13 @@ +// 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. + +namespace Microsoft.AspNetCore.Rewrite.UrlRewrite +{ + public enum RedirectType + { + Permanent = 301, + Found = 302, + SeeOther = 303, + Temporary = 307 + } +} diff --git a/src/Microsoft.AspNetCore.Rewrite/UrlRewrite/RewriteTags.cs b/src/Microsoft.AspNetCore.Rewrite/UrlRewrite/RewriteTags.cs new file mode 100644 index 0000000000..5e4d23242d --- /dev/null +++ b/src/Microsoft.AspNetCore.Rewrite/UrlRewrite/RewriteTags.cs @@ -0,0 +1,34 @@ +// 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. + +namespace Microsoft.AspNetCore.Rewrite.UrlRewrite +{ + public static class RewriteTags + { + // TODO More strings to be added later once further implementations are added. + public const string Rewrite = "rewrite"; + public const string GlobalRules = "globalRules"; + public const string Rules = "rules"; + public const string Rule = "rule"; + public const string Action = "action"; + public const string Name = "name"; + public const string Enabled = "enabled"; + public const string PatternSyntax = "patternSyntax"; + public const string StopProcessing = "stopProcessing"; + public const string Match = "match"; + public const string Conditions = "conditions"; + public const string IgnoreCase = "ignoreCase"; + public const string Negate = "negate"; + public const string Url = "url"; + public const string MatchType = "matchType"; + public const string Add = "add"; + public const string TrackingAllCaptures = "trackingAllCaptures"; + public const string MatchPattern = "matchPattern"; + public const string Input = "input"; + public const string Pattern = "pattern"; + public const string Type = "type"; + public const string AppendQuery = "appendQuery"; + public const string LogRewrittenUrl = "logRewrittenUrl"; + public const string RedirectType = "redirectType"; + } +} diff --git a/src/Microsoft.AspNetCore.Rewrite/UrlRewrite/ServerVariables.cs b/src/Microsoft.AspNetCore.Rewrite/UrlRewrite/ServerVariables.cs new file mode 100644 index 0000000000..7ffb9a5da4 --- /dev/null +++ b/src/Microsoft.AspNetCore.Rewrite/UrlRewrite/ServerVariables.cs @@ -0,0 +1,61 @@ +// 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; +using System.Globalization; +using System.Text.RegularExpressions; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Rewrite.UrlRewrite.PatternSegments; +using Microsoft.Net.Http.Headers; + +namespace Microsoft.AspNetCore.Rewrite.UrlRewrite +{ + public static class ServerVariables + { + public static PatternSegment FindServerVariable(string serverVariable) + { + switch(serverVariable) + { + // TODO Add all server variables here. + case "ALL_RAW": + throw new NotImplementedException(); + case "APP_POOL_ID": + throw new NotImplementedException(); + case "CONTENT_LENGTH": + return new HeaderSegment(HeaderNames.ContentLength); + case "CONTENT_TYPE": + return new HeaderSegment(HeaderNames.ContentType); + case "HTTP_ACCEPT": + return new HeaderSegment(HeaderNames.Accept); + case "HTTP_COOKIE": + return new HeaderSegment(HeaderNames.Cookie); + case "HTTP_HOST": + return new HeaderSegment(HeaderNames.Host); + case "HTTP_PROXY_CONNECTION": + return new HeaderSegment(HeaderNames.ProxyAuthenticate); + case "HTTP_REFERER": + return new HeaderSegment(HeaderNames.Referer); + case "HTTP_USER_AGENT": + return new HeaderSegment(HeaderNames.UserAgent); + case "HTTP_CONNECTION": + return new HeaderSegment(HeaderNames.Connection); + case "HTTP_URL": + return new UrlSegment(); + case "HTTPS": + return new IsHttpsSegment(); + case "LOCAL_ADDR": + return new LocalAddressSegment(); + case "QUERY_STRING": + return new QueryStringSegment(); + case "REMOTE_ADDR": + return new RemoteAddressSegment(); + case "REMOTE_HOST": + throw new NotImplementedException(); + case "REMOTE_PORT": + return new RemotePortSegment(); + default: + throw new FormatException("Unrecognized server variable."); + } + } + } +} diff --git a/src/Microsoft.AspNetCore.Rewrite/UrlRewrite/UrlAction.cs b/src/Microsoft.AspNetCore.Rewrite/UrlRewrite/UrlAction.cs new file mode 100644 index 0000000000..c0d56f603a --- /dev/null +++ b/src/Microsoft.AspNetCore.Rewrite/UrlRewrite/UrlAction.cs @@ -0,0 +1,14 @@ +// 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. + +namespace Microsoft.AspNetCore.Rewrite.UrlRewrite +{ + public class UrlAction + { + public ActionType Type { get; set; } + public Pattern Url { get; set; } + public bool AppendQueryString { get; set; } + public bool LogRewrittenUrl { get; set; } + public RedirectType RedirectType { get; set; } = RedirectType.Permanent; + } +} diff --git a/src/Microsoft.AspNetCore.Rewrite/UrlRewrite/UrlRewriteExtensions.cs b/src/Microsoft.AspNetCore.Rewrite/UrlRewrite/UrlRewriteExtensions.cs new file mode 100644 index 0000000000..b958d2ed60 --- /dev/null +++ b/src/Microsoft.AspNetCore.Rewrite/UrlRewrite/UrlRewriteExtensions.cs @@ -0,0 +1,44 @@ +// 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; +using System.IO; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Rewrite.UrlRewrite; + +namespace Microsoft.AspNetCore.Rewrite +{ + public static class UrlRewriteExtensions + { + /// + /// Imports rules from a mod_rewrite file and adds the rules to current rules. + /// + /// The UrlRewrite options. + /// + /// The path to the file containing urlrewrite rules. + public static UrlRewriteOptions ImportFromUrlRewrite(this UrlRewriteOptions options, IHostingEnvironment hostingEnv, string filePath) + { + if (options == null) + { + throw new ArgumentNullException("UrlRewriteOptions is null"); + } + + if (hostingEnv == null) + { + throw new ArgumentNullException("HostingEnvironment is null"); + } + + if (string.IsNullOrEmpty(filePath)) + { + throw new ArgumentException(nameof(filePath)); + } + + var path = Path.Combine(hostingEnv.ContentRootPath, filePath); + using (var stream = File.OpenRead(path)) + { + options.Rules.AddRange(UrlRewriteFileParser.Parse(new StreamReader(stream))); + }; + return options; + } + } +} diff --git a/src/Microsoft.AspNetCore.Rewrite/UrlRewrite/UrlRewriteFileParser.cs b/src/Microsoft.AspNetCore.Rewrite/UrlRewrite/UrlRewriteFileParser.cs new file mode 100644 index 0000000000..454555c79e --- /dev/null +++ b/src/Microsoft.AspNetCore.Rewrite/UrlRewrite/UrlRewriteFileParser.cs @@ -0,0 +1,228 @@ +// 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; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text.RegularExpressions; +using System.Xml.Linq; + +namespace Microsoft.AspNetCore.Rewrite.UrlRewrite +{ + // TODO rename + public static class UrlRewriteFileParser + { + private static readonly TimeSpan RegexTimeout = TimeSpan.FromMilliseconds(1); + public static List Parse(TextReader reader) + { + var temp = XDocument.Load(reader); + var xmlRoot = temp.Descendants(RewriteTags.Rewrite); + var rules = new List(); + + if (xmlRoot != null) + { + // there is a valid rewrite block, go through each rule and process + GetGlobalRules(xmlRoot.Descendants(RewriteTags.GlobalRules), rules); + GetRules(xmlRoot.Descendants(RewriteTags.Rules), rules); + } + return rules; + } + + private static void GetGlobalRules(IEnumerable globalRules, List result) + { + foreach (var rule in globalRules.Elements(RewriteTags.Rule) ?? Enumerable.Empty()) + { + var res = new UrlRewriteRule(); + SetRuleAttributes(rule, res); + // TODO handle full url with global rules - may or may not support + res.Action = CreateUrlAction(rule.Element(RewriteTags.Action)); + result.Add(res); + } + } + + private static void GetRules(IEnumerable rules, List result) + { + // TODO Better null check? + foreach (var rule in rules.Elements(RewriteTags.Rule) ?? Enumerable.Empty()) + { + var res = new UrlRewriteRule(); + SetRuleAttributes(rule, res); + res.Action = CreateUrlAction(rule.Element(RewriteTags.Action)); + result.Add(res); + } + } + + private static void SetRuleAttributes(XElement rule, UrlRewriteRule res) + { + if (rule == null) + { + return; + } + + res.Name = rule.Attribute(RewriteTags.Name)?.Value; + + bool enabled; + if (bool.TryParse(rule.Attribute(RewriteTags.Enabled)?.Value, out enabled)) + { + res.Enabled = enabled; + } + + PatternSyntax patternSyntax; + if (Enum.TryParse(rule.Attribute(RewriteTags.PatternSyntax)?.Value, out patternSyntax)) + { + res.PatternSyntax = patternSyntax; + } + + bool stopProcessing; + if (bool.TryParse(rule.Attribute(RewriteTags.StopProcessing)?.Value, out stopProcessing)) + { + res.StopProcessing = stopProcessing; + } + + res.Match = CreateMatch(rule.Element(RewriteTags.Match)); + res.Conditions = CreateConditions(rule.Element(RewriteTags.Conditions)); + } + + private static InitialMatch CreateMatch(XElement match) + { + if (match == null) + { + return null; + } + + var matchRes = new InitialMatch(); + + bool parBool; + if (bool.TryParse(match.Attribute(RewriteTags.IgnoreCase)?.Value, out parBool)) + { + matchRes.IgnoreCase = parBool; + } + + if (bool.TryParse(match.Attribute(RewriteTags.Negate)?.Value, out parBool)) + { + matchRes.Negate = parBool; + } + + var parsedInputString = match.Attribute(RewriteTags.Url)?.Value; + + if (matchRes.IgnoreCase) + { + matchRes.Url = new Regex(parsedInputString, RegexOptions.IgnoreCase | RegexOptions.Compiled, RegexTimeout); + } + else + { + matchRes.Url = new Regex(parsedInputString, RegexOptions.Compiled, RegexTimeout); + } + return matchRes; + } + + + private static Conditions CreateConditions(XElement conditions) + { + var condRes = new Conditions(); + if (conditions == null) + { + return condRes; // TODO make sure no null exception on Conditions + } + + LogicalGrouping grouping; + if (Enum.TryParse(conditions.Attribute(RewriteTags.MatchType)?.Value, out grouping)) + { + condRes.MatchType = grouping; + } + + bool parBool; + if (bool.TryParse(conditions.Attribute(RewriteTags.TrackingAllCaptures)?.Value, out parBool)) + { + condRes.TrackingAllCaptures = parBool; + } + + foreach (var cond in conditions.Elements(RewriteTags.Add)) + { + condRes.ConditionList.Add(CreateCondition(cond)); + } + return condRes; + } + + private static Condition CreateCondition(XElement condition) + { + if (condition == null) + { + return null; + } + + var condRes = new Condition(); + + bool parBool; + if (bool.TryParse(condition.Attribute(RewriteTags.IgnoreCase)?.Value, out parBool)) + { + condRes.IgnoreCase = parBool; + } + + if (bool.TryParse(condition.Attribute(RewriteTags.Negate)?.Value, out parBool)) + { + condRes.Negate = parBool; + } + + MatchType matchType; + if (Enum.TryParse(condition.Attribute(RewriteTags.MatchPattern)?.Value, out matchType)) + { + condRes.MatchType = matchType; + } + + var parsedInputString = condition.Attribute(RewriteTags.Input)?.Value; + if (parsedInputString != null) + { + condRes.Input = InputParser.ParseInputString(parsedInputString); + } + + parsedInputString = condition.Attribute(RewriteTags.Pattern)?.Value; + + if (condRes.IgnoreCase) + { + condRes.MatchPattern = new Regex(parsedInputString, RegexOptions.IgnoreCase | RegexOptions.Compiled, RegexTimeout); + } + else + { + condRes.MatchPattern = new Regex(parsedInputString, RegexOptions.Compiled, RegexTimeout); + } + return condRes; + } + + private static UrlAction CreateUrlAction(XElement urlAction) + { + if (urlAction == null) + { + throw new FormatException("Action is a required element of a rule."); + } + var actionRes = new UrlAction(); + + ActionType actionType; + if (Enum.TryParse(urlAction.Attribute(RewriteTags.Type)?.Value, out actionType)) + { + actionRes.Type = actionType; + } + + bool parseBool; + if (bool.TryParse(urlAction.Attribute(RewriteTags.AppendQuery)?.Value, out parseBool)) + { + actionRes.AppendQueryString = parseBool; + } + + if (bool.TryParse(urlAction.Attribute(RewriteTags.LogRewrittenUrl)?.Value, out parseBool)) + { + actionRes.LogRewrittenUrl = parseBool; + } + + RedirectType redirectType; + if (Enum.TryParse(urlAction.Attribute(RewriteTags.RedirectType)?.Value, out redirectType)) + { + actionRes.RedirectType = redirectType; + } + + actionRes.Url = InputParser.ParseInputString(urlAction.Attribute(RewriteTags.Url)?.Value); + return actionRes; + } + } +} diff --git a/src/Microsoft.AspNetCore.Rewrite/UrlRewrite/UrlRewriteRule.cs b/src/Microsoft.AspNetCore.Rewrite/UrlRewrite/UrlRewriteRule.cs new file mode 100644 index 0000000000..db33219ed0 --- /dev/null +++ b/src/Microsoft.AspNetCore.Rewrite/UrlRewrite/UrlRewriteRule.cs @@ -0,0 +1,25 @@ +// 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; +using Microsoft.AspNetCore.Rewrite.RuleAbstraction; + +namespace Microsoft.AspNetCore.Rewrite.UrlRewrite +{ + public class UrlRewriteRule : Rule + { + public string Name { get; set; } + public bool Enabled { get; set; } = true; + public PatternSyntax PatternSyntax { get; set; } + public bool StopProcessing { get; set; } + public InitialMatch Match { get; set; } + public Conditions Conditions { get; set; } + public UrlAction Action { get; set; } + + public override RuleResult ApplyRule(UrlRewriteContext context) + { + // TODO + throw new NotImplementedException(); + } + } +} diff --git a/src/Microsoft.AspNetCore.Rewrite/project.json b/src/Microsoft.AspNetCore.Rewrite/project.json index e50df4e012..866c21b8a2 100644 --- a/src/Microsoft.AspNetCore.Rewrite/project.json +++ b/src/Microsoft.AspNetCore.Rewrite/project.json @@ -31,6 +31,7 @@ "frameworks": { "net451": { "frameworkAssemblies": { + "System.Xml": "", "System.Xml.Linq": "" } }, diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/UrlRewrite/FileParserTests.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/UrlRewrite/FileParserTests.cs new file mode 100644 index 0000000000..d2f42c21a3 --- /dev/null +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/UrlRewrite/FileParserTests.cs @@ -0,0 +1,212 @@ +// 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.Collections.Generic; +using System.IO; +using System.Text.RegularExpressions; +using Microsoft.AspNetCore.Rewrite.UrlRewrite; +using Xunit; + +namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite +{ + public class FileParserTests + { + [Fact] + public void RuleParse_ParseTypicalRule() + { + // arrange + var xml = @" + + + + + + + "; + + var expected = new List(); + expected.Add(CreateTestRule(new List(), + Url: "^article/([0-9]+)/([_0-9a-z-]+)", + name: "Rewrite to article.aspx", + actionType: ActionType.Rewrite, + pattern: "article.aspx?id={R:1}&title={R:2}")); + + // act + var res = UrlRewriteFileParser.Parse(new StringReader(xml)); + + // assert + AssertUrlRewriteRuleEquality(res, expected); + } + + [Fact] + public void RuleParse_ParseSingleRuleWithSingleCondition() + { + // arrange + var xml = @" + + + + + + + + + + "; + + var condList = new List(); + condList.Add(new Condition + { + Input = InputParser.ParseInputString("{HTTPS}"), + MatchPattern = new Regex("^OFF$") + }); + + var expected = new List(); + expected.Add(CreateTestRule(condList, + Url: "^article/([0-9]+)/([_0-9a-z-]+)", + name: "Rewrite to article.aspx", + actionType: ActionType.Rewrite, + pattern: "article.aspx?id={R:1}&title={R:2}")); + + // act + var res = UrlRewriteFileParser.Parse(new StringReader(xml)); + + // assert + AssertUrlRewriteRuleEquality(expected, res); + } + + [Fact] + public void RuleParse_ParseMultipleRules() + { + // arrange + var xml = @" + + + + + + + + + + + + + + + + + "; + + var condList = new List(); + condList.Add(new Condition + { + Input = InputParser.ParseInputString("{HTTPS}"), + MatchPattern = new Regex("^OFF$") + }); + + var expected = new List(); + expected.Add(CreateTestRule(condList, + Url: "^article/([0-9]+)/([_0-9a-z-]+)", + name: "Rewrite to article.aspx", + actionType: ActionType.Rewrite, + pattern: "article.aspx?id={R:1}&title={R:2}")); + expected.Add(CreateTestRule(condList, + Url: "^article/([0-9]+)/([_0-9a-z-]+)", + name: "Rewrite to article.aspx", + actionType: ActionType.Redirect, + pattern: "article.aspx?id={R:1}&title={R:2}")); + + // act + var res = UrlRewriteFileParser.Parse(new StringReader(xml)); + + // assert + AssertUrlRewriteRuleEquality(expected, res); + } + + // Creates a rule with appropriate default values of the url rewrite rule. + private UrlRewriteRule CreateTestRule(List conditions, + LogicalGrouping condGrouping = LogicalGrouping.MatchAll, + bool condTracking = false, + string name = "", + bool enabled = true, + PatternSyntax patternSyntax = PatternSyntax.ECMAScript, + bool stopProcessing = false, + string Url = "", + bool ignoreCase = true, + bool negate = false, + ActionType actionType = ActionType.None, + string pattern = "", + bool appendQueryString = false, + bool rewrittenUrl = false, + RedirectType redirectType = RedirectType.Permanent + ) + { + return new UrlRewriteRule + { + Action = new UrlAction + { + Url = InputParser.ParseInputString(pattern), + Type = actionType, + AppendQueryString = appendQueryString, + LogRewrittenUrl = rewrittenUrl, + RedirectType = redirectType + }, + Name = name, + Enabled = enabled, + StopProcessing = stopProcessing, + PatternSyntax = patternSyntax, + Match = new InitialMatch + { + Url = new Regex(Url), + IgnoreCase = ignoreCase, + Negate = negate + }, + Conditions = new Conditions + { + ConditionList = conditions, + MatchType = condGrouping, + TrackingAllCaptures = condTracking + } + }; + } + + private void AssertUrlRewriteRuleEquality(List expected, List actual) + { + Assert.Equal(expected.Count, actual.Count); + for (var i = 0; i < expected.Count; i++) + { + var r1 = expected[i]; + var r2 = actual[i]; + + Assert.Equal(r1.Name, r2.Name); + Assert.Equal(r1.Enabled, r2.Enabled); + Assert.Equal(r1.StopProcessing, r2.StopProcessing); + Assert.Equal(r1.PatternSyntax, r2.PatternSyntax); + + Assert.Equal(r1.Match.IgnoreCase, r2.Match.IgnoreCase); + Assert.Equal(r1.Match.Negate, r2.Match.Negate); + + Assert.Equal(r1.Action.Type, r2.Action.Type); + Assert.Equal(r1.Action.AppendQueryString, r2.Action.AppendQueryString); + Assert.Equal(r1.Action.RedirectType, r2.Action.RedirectType); + Assert.Equal(r1.Action.LogRewrittenUrl, r2.Action.LogRewrittenUrl); + + // TODO conditions, url pattern, initial match regex + Assert.Equal(r1.Conditions.MatchType, r2.Conditions.MatchType); + Assert.Equal(r1.Conditions.TrackingAllCaptures, r2.Conditions.TrackingAllCaptures); + Assert.Equal(r1.Conditions.ConditionList.Count, r2.Conditions.ConditionList.Count); + + for (var j = 0; j < r1.Conditions.ConditionList.Count; j++) + { + var c1 = r1.Conditions.ConditionList[j]; + var c2 = r2.Conditions.ConditionList[j]; + Assert.Equal(c1.IgnoreCase, c2.IgnoreCase); + Assert.Equal(c1.Negate, c2.Negate); + Assert.Equal(c1.MatchType, c2.MatchType); + Assert.Equal(c1.Input.PatternSegments.Count, c2.Input.PatternSegments.Count); + } + } + } + } +} diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/UrlRewrite/InputParserTests.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/UrlRewrite/InputParserTests.cs new file mode 100644 index 0000000000..037804f267 --- /dev/null +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/UrlRewrite/InputParserTests.cs @@ -0,0 +1,113 @@ +// 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; +using System.Collections.Generic; +using System.Linq; +using System.Text.RegularExpressions; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Rewrite.UrlRewrite; +using Xunit; + +namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite +{ + public class InputParserTests + { + [Fact] + public void InputParser_ParseLiteralString() + { + var testString = "hello/hey/what"; + var result = InputParser.ParseInputString(testString); + Assert.Equal(result.PatternSegments.Count, 1); + } + + // Tests sizes of the pattern segments. These are all anonyomus lambdas, so cant check contents. + [Theory] + [InlineData("foo/bar/{R:1}/what", 3)] + [InlineData("foo/{R:1}", 2)] + [InlineData("foo/{R:1}/{C:2}", 4)] + [InlineData("foo/{R:1}{C:2}", 3)] + [InlineData("foo/", 1)] + public void InputParser_ParseStringWithBackReference(string testString, int expected) + { + var result = InputParser.ParseInputString(testString); + Assert.Equal(result.PatternSegments.Count, expected); + } + + // Test actual evaluation of the lambdas, verifying the correct string comes from the evalation + [Theory] + [InlineData("hey/hello/what", "hey/hello/what")] + [InlineData("hey/{R:1}/what", "hey/foo/what")] + [InlineData("hey/{R:2}/what", "hey/bar/what")] + [InlineData("hey/{R:3}/what", "hey/baz/what")] + [InlineData("hey/{C:1}/what", "hey/foo/what")] + [InlineData("hey/{C:2}/what", "hey/bar/what")] + [InlineData("hey/{C:3}/what", "hey/baz/what")] + [InlineData("hey/{R:1}/{C:1}", "hey/foo/foo")] + public void EvaluateBackReferenceRule(string testString, string expected) + { + var middle = InputParser.ParseInputString(testString); + var result = middle.Evaluate(CreateTestHttpContext(), CreateTestRuleMatch(), CreateTestCondMatch()); + Assert.Equal(result, expected); + } + + [Theory] + [InlineData("hey/{ToLower:HEY}", "hey/hey")] + [InlineData("hey/{ToLower:{R:1}}", "hey/foo")] + [InlineData("hey/{ToLower:{C:1}}", "hey/foo")] + [InlineData("hey/{ToLower:{C:1}/what}", "hey/foo/what")] + [InlineData("hey/ToLower:/what", "hey/ToLower:/what")] + public void EvaluatToLowerRule(string testString, string expected) + { + var middle = InputParser.ParseInputString(testString); + var result = middle.Evaluate(CreateTestHttpContext(), CreateTestRuleMatch(), CreateTestCondMatch()); + Assert.Equal(result, expected); + } + + [Theory] + [InlineData("hey/{UrlEncode:}", "hey/%3Chey%3E")] + public void EvaluatUriEncodeRule(string testString, string expected) + { + var middle = InputParser.ParseInputString(testString); + var result = middle.Evaluate(CreateTestHttpContext(), CreateTestRuleMatch(), CreateTestCondMatch()); + Assert.Equal(result, expected); + } + + [Theory] + [InlineData("{")] + [InlineData("{:}")] + [InlineData("{R:")] + [InlineData("{R:1")] + [InlineData("{R:A}")] + [InlineData("{R:10}")] + [InlineData("{R:-1}")] + [InlineData("{foo:1")] + [InlineData("{UrlEncode:{R:}}")] + [InlineData("{UrlEncode:{R:1}")] + public void FormatExceptionsOnBadSyntax(string testString) + { + Assert.Throws(() => InputParser.ParseInputString(testString)); + } + + private HttpContext CreateTestHttpContext() + { + + HttpContext context = new DefaultHttpContext(); + // TODO add fields if necessary + return context; + } + + private Match CreateTestRuleMatch() + { + var match = Regex.Match("foo/bar/baz", "(.*)/(.*)/(.*)"); + return match; + } + + private Match CreateTestCondMatch() + { + var match = Regex.Match("foo/bar/baz", "(.*)/(.*)/(.*)"); + return match; + } + } +} From bb4f5420d3fe69ee2925eeca75cbc1052cb9173c Mon Sep 17 00:00:00 2001 From: BrennanConroy Date: Tue, 2 Aug 2016 13:05:01 -0700 Subject: [PATCH 086/307] Update .travis.yml --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 709151e70a..b35f525a0e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -23,7 +23,7 @@ branches: - dev - /^(.*\/)?ci-.*$/ before_install: - - if test "$TRAVIS_OS_NAME" == "osx"; then brew update; brew install openssl; brew link --force openssl; fi + - if test "$TRAVIS_OS_NAME" == "osx"; then brew update; brew install openssl; ln -s /usr/local/opt/openssl/lib/libcrypto.1.0.0.dylib /usr/local/lib/; ln -s /usr/local/opt/openssl/lib/libssl.1.0.0.dylib /usr/local/lib/; fi script: - ./build.sh verify notifications: @@ -31,4 +31,4 @@ notifications: secure: "Quayhq8pTWtpCfsC209l4o3ZG75VhEKjTOcuOPDYoQXII4rfmVbnGUoe6A6R3VTz7/O2YTPbX3+ooBrTJufwiJXJG74xZuE35jKnRm3HQREH9tCNUYwB4BO7jzoWz9wXDDfCPs47Tkjdf46Tq0jF27nXrZhNzm6ps3JCoP6/lA+8lEfWxIYifviwxJ392S34k5SyaVYeOIs+W95Iuvmd6+ZenVZNvPaGwHzTKqVhh/NYttbQ3oUq4n2fWaIrwGVi7MC6CtINoG/CtmUU3pef+StPOYMjWfMGcUjAkikWWEsCDnUSOpmNxKREKqXXbOBPDCcC9sNkzpYa0ksHRwGQv2jagVYaAicNfGc/gtWJ3JTCnODUea6oTsmdZT7hNW1ClzOEacXHv55TzImgAb1MFD9euSoXBIa9rRNYhx1oy3JYal2Ee0crPF1nFxQJ5mVT9pGEhpMqAwdNaZBwA5urVn6bl0ptPb8W6XVw5/qgPdBvmF67Xjw+k3TDQ3J4sWClGdX4ZsfgVFLSDGk9hqudPp10XlXkAscYtpKoZIEIK5rVa7RnvI44Bh1eQRqFpqKa2m1gVquJwUQg0L8CPakZDscas29dtXY4KqHrspOOtolhtOUaVpanQCGFWgPnWxIx9m+3eDRCLSjhvrZyZwemmvqXNqFhKUILdQLo1itANDo=" on_success: always on_failure: always - on_start: always \ No newline at end of file + on_start: always From 5052a94cf7f81f194e1b77794594b4f46d82c363 Mon Sep 17 00:00:00 2001 From: Justin Kotalik Date: Wed, 27 Jul 2016 14:47:32 -0700 Subject: [PATCH 087/307] IIS UrlRewrite Rule Application --- samples/RewriteSample/Startup.cs | 9 +- samples/RewriteSample/UrlRewrite.xml | 17 +- ...Extensions.cs => CodeRewriteExtensions.cs} | 20 +- .../FunctionalRule.cs | 6 +- .../{ => Internal}/ModRewrite/Condition.cs | 2 +- .../ModRewrite/ConditionBuilder.cs | 2 +- .../ModRewrite/ConditionExpression.cs | 6 +- .../ModRewrite/ConditionFlagType.cs | 2 +- .../ModRewrite/ConditionFlags.cs | 2 +- .../ModRewrite/ConditionPatternParser.cs | 2 +- .../ModRewrite/ConditionTestStringParser.cs | 2 +- .../ModRewrite/ConditionType.cs | 2 +- .../ModRewrite/ExpressionCreator.cs | 5 +- .../{ => Internal}/ModRewrite/FileParser.cs | 4 +- .../{ => Internal}/ModRewrite/FlagParser.cs | 2 +- .../ModRewrite}/Operands/IntegerOperand.cs | 2 +- .../ModRewrite}/Operands/IntegerOperation.cs | 2 +- .../ModRewrite}/Operands/Operand.cs | 2 +- .../ModRewrite}/Operands/PropertyOperand.cs | 2 +- .../ModRewrite}/Operands/PropertyOperation.cs | 2 +- .../ModRewrite}/Operands/RegexOperand.cs | 2 +- .../ModRewrite}/Operands/StringOperand.cs | 2 +- .../ModRewrite}/Operands/StringOperation.cs | 2 +- .../ModRewrite/OperationType.cs | 2 +- .../ModRewrite/ParsedConditionExpression.cs | 2 +- .../{ => Internal}/ModRewrite/Pattern.cs | 4 +- .../ModRewrite/PatternSegment.cs | 2 +- .../{ => Internal}/ModRewrite/RuleBuilder.cs | 2 +- .../{ => Internal}/ModRewrite/RuleFlagType.cs | 2 +- .../{ => Internal}/ModRewrite/RuleFlags.cs | 2 +- .../ModRewrite/RuleRegexParser.cs | 2 +- .../{ => Internal}/ModRewrite/SegmentType.cs | 0 .../ModRewrite/ServerVariables.cs | 2 +- .../{ => Internal}/ModRewrite/Tokenizer.cs | 2 +- .../ModRewriteRule.cs | 21 +- .../{ => Internal}/ParserContext.cs | 0 .../{RuleAbstraction => Internal}/PathRule.cs | 12 +- .../{RuleAbstraction => Internal}/Rule.cs | 4 +- .../RuleExpression.cs | 4 +- .../Internal/RuleResult.cs | 14 + .../Internal/RuleTermination.cs | 7 +- .../SchemeRule.cs | 12 +- .../Transformation.cs | 2 +- .../{ => Internal}/UrlRewrite/ActionType.cs | 2 +- .../Internal/UrlRewrite/Condition.cs | 16 + .../Internal/UrlRewrite/Conditions.cs | 27 ++ .../{ => Internal}/UrlRewrite/InputParser.cs | 6 +- .../UrlRewrite/LogicalGrouping.cs | 2 +- .../Internal/UrlRewrite/MatchResults.cs | 13 + .../{ => Internal}/UrlRewrite/MatchType.cs | 2 +- .../UrlRewrite/ParsedCondition.cs} | 8 +- .../UrlRewrite/ParsedUrlAction.cs} | 8 +- .../UrlRewrite/ParsedUrlMatch.cs} | 7 +- .../{ => Internal}/UrlRewrite/Pattern.cs | 8 +- .../UrlRewrite/PatternSegment.cs | 6 +- .../PatternSegments/ConditionMatchSegment.cs | 7 +- .../PatternSegments/HeaderSegment.cs | 5 +- .../PatternSegments/IsHttpsSegment.cs | 5 +- .../PatternSegments/LiteralSegment.cs | 5 +- .../PatternSegments/LocalAddressSegment.cs | 5 +- .../PatternSegments/QueryStringSegment.cs | 5 +- .../PatternSegments/RemoteAddressSegment.cs | 5 +- .../PatternSegments/RemotePortSegment.cs | 5 +- .../PatternSegments/RequestFilenameSegment.cs | 15 + .../PatternSegments/RuleMatchSegment.cs | 7 +- .../PatternSegments/ToLowerSegment.cs | 5 +- .../PatternSegments/UrlEncodeSegment.cs | 5 +- .../UrlRewrite/PatternSegments/UrlSegment.cs | 7 +- .../UrlRewrite/PatternSyntax.cs | 2 +- .../{ => Internal}/UrlRewrite/RedirectType.cs | 2 +- .../{ => Internal}/UrlRewrite/RewriteTags.cs | 5 +- .../UrlRewrite/ServerVariables.cs | 11 +- .../Internal/UrlRewrite/UrlAction.cs | 14 + .../UrlRewrite/UrlActions/RedirectAction.cs | 42 +++ .../UrlActions/RedirectClearQueryAction.cs | 29 ++ .../UrlRewrite/UrlActions/RewriteAction.cs | 60 ++++ .../UrlRewrite/UrlActions/VoidAction.cs | 17 + .../Internal/UrlRewrite/UrlMatch.cs | 11 + .../UrlRewrite/UrlMatches/ExactMatch.cs | 24 ++ .../UrlRewrite/UrlMatches/IsDirectoryMatch.cs | 19 ++ .../UrlRewrite/UrlMatches/IsFileMatch.cs | 19 ++ .../UrlRewrite/UrlMatches/RegexMatch.cs | 27 ++ .../UrlRewrite/UrlRewriteFileParser.cs | 316 ++++++++++++++++++ .../Internal/UrlRewriteRule.cs | 41 +++ .../Microsoft.AspNetCore.Rewrite.xproj | 4 +- .../{ModRewrite => }/ModRewriteExtensions.cs | 45 +-- ...UrlRewriteContext.cs => RewriteContext.cs} | 2 +- .../RewriteExtensions.cs | 35 ++ ...riteMiddleware.cs => RewriteMiddleware.cs} | 12 +- ...UrlRewriteOptions.cs => RewriteOptions.cs} | 6 +- .../RuleAbstraction/RuleTermination.cs | 14 - .../UrlRewrite/Conditions.cs | 14 - .../UrlRewrite/InitialMatch.cs | 14 - .../UrlRewrite/UrlRewriteExtensions.cs | 44 --- .../UrlRewrite/UrlRewriteFileParser.cs | 228 ------------- .../UrlRewrite/UrlRewriteRule.cs | 25 -- .../UrlRewriteExtensions.cs | 67 +++- .../{ => ModRewrite}/ConditionActionTest.cs | 4 +- .../{ => ModRewrite}/FlagParserTest.cs | 4 +- .../ModRewriteConditionBuilderTest.cs | 6 +- .../{ => ModRewrite}/ModRewriteFlagTest.cs | 16 +- .../ModRewriteMiddlewareTest.cs | 46 +-- .../{ => ModRewrite}/RewriteTokenizerTest.cs | 6 +- .../RuleRegexParserTest.cs | 15 +- .../ModRewriteRuleBuilderTest.cs | 14 - .../Rewrite2MiddlewareTests.cs | 92 ----- .../UrlRewrite/FileParserTests.cs | 52 +-- .../UrlRewrite/InputParserTests.cs | 19 +- .../UrlRewrite/MiddleWareTests.cs | 259 ++++++++++++++ 109 files changed, 1295 insertions(+), 770 deletions(-) rename src/Microsoft.AspNetCore.Rewrite/{UrlRewriteOptionsAddRulesExtensions.cs => CodeRewriteExtensions.cs} (77%) rename src/Microsoft.AspNetCore.Rewrite/{RuleAbstraction => Internal}/FunctionalRule.cs (58%) rename src/Microsoft.AspNetCore.Rewrite/{ => Internal}/ModRewrite/Condition.cs (91%) rename src/Microsoft.AspNetCore.Rewrite/{ => Internal}/ModRewrite/ConditionBuilder.cs (97%) rename src/Microsoft.AspNetCore.Rewrite/{ => Internal}/ModRewrite/ConditionExpression.cs (81%) rename src/Microsoft.AspNetCore.Rewrite/{ => Internal}/ModRewrite/ConditionFlagType.cs (81%) rename src/Microsoft.AspNetCore.Rewrite/{ => Internal}/ModRewrite/ConditionFlags.cs (98%) rename src/Microsoft.AspNetCore.Rewrite/{ => Internal}/ModRewrite/ConditionPatternParser.cs (99%) rename src/Microsoft.AspNetCore.Rewrite/{ => Internal}/ModRewrite/ConditionTestStringParser.cs (99%) rename src/Microsoft.AspNetCore.Rewrite/{ => Internal}/ModRewrite/ConditionType.cs (83%) rename src/Microsoft.AspNetCore.Rewrite/{ => Internal}/ModRewrite/ExpressionCreator.cs (97%) rename src/Microsoft.AspNetCore.Rewrite/{ => Internal}/ModRewrite/FileParser.cs (97%) rename src/Microsoft.AspNetCore.Rewrite/{ => Internal}/ModRewrite/FlagParser.cs (98%) rename src/Microsoft.AspNetCore.Rewrite/{ => Internal/ModRewrite}/Operands/IntegerOperand.cs (96%) rename src/Microsoft.AspNetCore.Rewrite/{ => Internal/ModRewrite}/Operands/IntegerOperation.cs (82%) rename src/Microsoft.AspNetCore.Rewrite/{ => Internal/ModRewrite}/Operands/Operand.cs (85%) rename src/Microsoft.AspNetCore.Rewrite/{ => Internal/ModRewrite}/Operands/PropertyOperand.cs (96%) rename src/Microsoft.AspNetCore.Rewrite/{ => Internal/ModRewrite}/Operands/PropertyOperation.cs (84%) rename src/Microsoft.AspNetCore.Rewrite/{ => Internal/ModRewrite}/Operands/RegexOperand.cs (90%) rename src/Microsoft.AspNetCore.Rewrite/{ => Internal/ModRewrite}/Operands/StringOperand.cs (95%) rename src/Microsoft.AspNetCore.Rewrite/{ => Internal/ModRewrite}/Operands/StringOperation.cs (81%) rename src/Microsoft.AspNetCore.Rewrite/{ => Internal}/ModRewrite/OperationType.cs (88%) rename src/Microsoft.AspNetCore.Rewrite/{ => Internal}/ModRewrite/ParsedConditionExpression.cs (92%) rename src/Microsoft.AspNetCore.Rewrite/{ => Internal}/ModRewrite/Pattern.cs (95%) rename src/Microsoft.AspNetCore.Rewrite/{ => Internal}/ModRewrite/PatternSegment.cs (93%) rename src/Microsoft.AspNetCore.Rewrite/{ => Internal}/ModRewrite/RuleBuilder.cs (98%) rename src/Microsoft.AspNetCore.Rewrite/{ => Internal}/ModRewrite/RuleFlagType.cs (91%) rename src/Microsoft.AspNetCore.Rewrite/{ => Internal}/ModRewrite/RuleFlags.cs (98%) rename src/Microsoft.AspNetCore.Rewrite/{ => Internal}/ModRewrite/RuleRegexParser.cs (92%) rename src/Microsoft.AspNetCore.Rewrite/{ => Internal}/ModRewrite/SegmentType.cs (100%) rename src/Microsoft.AspNetCore.Rewrite/{ => Internal}/ModRewrite/ServerVariables.cs (99%) rename src/Microsoft.AspNetCore.Rewrite/{ => Internal}/ModRewrite/Tokenizer.cs (98%) rename src/Microsoft.AspNetCore.Rewrite/{ModRewrite => Internal}/ModRewriteRule.cs (89%) rename src/Microsoft.AspNetCore.Rewrite/{ => Internal}/ParserContext.cs (100%) rename src/Microsoft.AspNetCore.Rewrite/{RuleAbstraction => Internal}/PathRule.cs (76%) rename src/Microsoft.AspNetCore.Rewrite/{RuleAbstraction => Internal}/Rule.cs (63%) rename src/Microsoft.AspNetCore.Rewrite/{RuleAbstraction => Internal}/RuleExpression.cs (73%) create mode 100644 src/Microsoft.AspNetCore.Rewrite/Internal/RuleResult.cs rename test/Microsoft.AspNetCore.Rewrite.Tests/ModRewriteCreatorTest.cs => src/Microsoft.AspNetCore.Rewrite/Internal/RuleTermination.cs (56%) rename src/Microsoft.AspNetCore.Rewrite/{RuleAbstraction => Internal}/SchemeRule.cs (78%) rename src/Microsoft.AspNetCore.Rewrite/{RuleAbstraction => Internal}/Transformation.cs (83%) rename src/Microsoft.AspNetCore.Rewrite/{ => Internal}/UrlRewrite/ActionType.cs (83%) create mode 100644 src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/Condition.cs create mode 100644 src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/Conditions.cs rename src/Microsoft.AspNetCore.Rewrite/{ => Internal}/UrlRewrite/InputParser.cs (97%) rename src/Microsoft.AspNetCore.Rewrite/{ => Internal}/UrlRewrite/LogicalGrouping.cs (81%) create mode 100644 src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/MatchResults.cs rename src/Microsoft.AspNetCore.Rewrite/{ => Internal}/UrlRewrite/MatchType.cs (81%) rename src/Microsoft.AspNetCore.Rewrite/{UrlRewrite/Condition.cs => Internal/UrlRewrite/ParsedCondition.cs} (62%) rename src/Microsoft.AspNetCore.Rewrite/{UrlRewrite/UrlAction.cs => Internal/UrlRewrite/ParsedUrlAction.cs} (61%) rename src/Microsoft.AspNetCore.Rewrite/{RuleAbstraction/RuleResult.cs => Internal/UrlRewrite/ParsedUrlMatch.cs} (51%) rename src/Microsoft.AspNetCore.Rewrite/{ => Internal}/UrlRewrite/Pattern.cs (76%) rename src/Microsoft.AspNetCore.Rewrite/{ => Internal}/UrlRewrite/PatternSegment.cs (76%) rename src/Microsoft.AspNetCore.Rewrite/{ => Internal}/UrlRewrite/PatternSegments/ConditionMatchSegment.cs (72%) rename src/Microsoft.AspNetCore.Rewrite/{ => Internal}/UrlRewrite/PatternSegments/HeaderSegment.cs (80%) rename src/Microsoft.AspNetCore.Rewrite/{ => Internal}/UrlRewrite/PatternSegments/IsHttpsSegment.cs (75%) rename src/Microsoft.AspNetCore.Rewrite/{ => Internal}/UrlRewrite/PatternSegments/LiteralSegment.cs (79%) rename src/Microsoft.AspNetCore.Rewrite/{ => Internal}/UrlRewrite/PatternSegments/LocalAddressSegment.cs (75%) rename src/Microsoft.AspNetCore.Rewrite/{ => Internal}/UrlRewrite/PatternSegments/QueryStringSegment.cs (75%) rename src/Microsoft.AspNetCore.Rewrite/{ => Internal}/UrlRewrite/PatternSegments/RemoteAddressSegment.cs (75%) rename src/Microsoft.AspNetCore.Rewrite/{ => Internal}/UrlRewrite/PatternSegments/RemotePortSegment.cs (77%) create mode 100644 src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/PatternSegments/RequestFilenameSegment.cs rename src/Microsoft.AspNetCore.Rewrite/{ => Internal}/UrlRewrite/PatternSegments/RuleMatchSegment.cs (72%) rename src/Microsoft.AspNetCore.Rewrite/{ => Internal}/UrlRewrite/PatternSegments/ToLowerSegment.cs (82%) rename src/Microsoft.AspNetCore.Rewrite/{ => Internal}/UrlRewrite/PatternSegments/UrlEncodeSegment.cs (83%) rename src/Microsoft.AspNetCore.Rewrite/{ => Internal}/UrlRewrite/PatternSegments/UrlSegment.cs (65%) rename src/Microsoft.AspNetCore.Rewrite/{ => Internal}/UrlRewrite/PatternSyntax.cs (82%) rename src/Microsoft.AspNetCore.Rewrite/{ => Internal}/UrlRewrite/RedirectType.cs (84%) rename src/Microsoft.AspNetCore.Rewrite/{ => Internal}/UrlRewrite/RewriteTags.cs (87%) rename src/Microsoft.AspNetCore.Rewrite/{ => Internal}/UrlRewrite/ServerVariables.cs (90%) create mode 100644 src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/UrlAction.cs create mode 100644 src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/UrlActions/RedirectAction.cs create mode 100644 src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/UrlActions/RedirectClearQueryAction.cs create mode 100644 src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/UrlActions/RewriteAction.cs create mode 100644 src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/UrlActions/VoidAction.cs create mode 100644 src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/UrlMatch.cs create mode 100644 src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/UrlMatches/ExactMatch.cs create mode 100644 src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/UrlMatches/IsDirectoryMatch.cs create mode 100644 src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/UrlMatches/IsFileMatch.cs create mode 100644 src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/UrlMatches/RegexMatch.cs create mode 100644 src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/UrlRewriteFileParser.cs create mode 100644 src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewriteRule.cs rename src/Microsoft.AspNetCore.Rewrite/{ModRewrite => }/ModRewriteExtensions.cs (60%) rename src/Microsoft.AspNetCore.Rewrite/{UrlRewriteContext.cs => RewriteContext.cs} (94%) create mode 100644 src/Microsoft.AspNetCore.Rewrite/RewriteExtensions.cs rename src/Microsoft.AspNetCore.Rewrite/{UrlRewriteMiddleware.cs => RewriteMiddleware.cs} (85%) rename src/Microsoft.AspNetCore.Rewrite/{UrlRewriteOptions.cs => RewriteOptions.cs} (79%) delete mode 100644 src/Microsoft.AspNetCore.Rewrite/RuleAbstraction/RuleTermination.cs delete mode 100644 src/Microsoft.AspNetCore.Rewrite/UrlRewrite/Conditions.cs delete mode 100644 src/Microsoft.AspNetCore.Rewrite/UrlRewrite/InitialMatch.cs delete mode 100644 src/Microsoft.AspNetCore.Rewrite/UrlRewrite/UrlRewriteExtensions.cs delete mode 100644 src/Microsoft.AspNetCore.Rewrite/UrlRewrite/UrlRewriteFileParser.cs delete mode 100644 src/Microsoft.AspNetCore.Rewrite/UrlRewrite/UrlRewriteRule.cs rename test/Microsoft.AspNetCore.Rewrite.Tests/{ => ModRewrite}/ConditionActionTest.cs (97%) rename test/Microsoft.AspNetCore.Rewrite.Tests/{ => ModRewrite}/FlagParserTest.cs (95%) rename test/Microsoft.AspNetCore.Rewrite.Tests/{ => ModRewrite}/ModRewriteConditionBuilderTest.cs (92%) rename test/Microsoft.AspNetCore.Rewrite.Tests/{ => ModRewrite}/ModRewriteFlagTest.cs (84%) rename test/Microsoft.AspNetCore.Rewrite.Tests/{ => ModRewrite}/ModRewriteMiddlewareTest.cs (82%) rename test/Microsoft.AspNetCore.Rewrite.Tests/{ => ModRewrite}/RewriteTokenizerTest.cs (91%) rename test/Microsoft.AspNetCore.Rewrite.Tests/{RuleAbstraction => ModRewrite}/RuleRegexParserTest.cs (69%) delete mode 100644 test/Microsoft.AspNetCore.Rewrite.Tests/ModRewriteRuleBuilderTest.cs delete mode 100644 test/Microsoft.AspNetCore.Rewrite.Tests/Rewrite2MiddlewareTests.cs create mode 100644 test/Microsoft.AspNetCore.Rewrite.Tests/UrlRewrite/MiddleWareTests.cs diff --git a/samples/RewriteSample/Startup.cs b/samples/RewriteSample/Startup.cs index f476c62dd5..5fe6a3840c 100644 --- a/samples/RewriteSample/Startup.cs +++ b/samples/RewriteSample/Startup.cs @@ -1,4 +1,8 @@ -using Microsoft.AspNetCore.Builder; +// 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.IO; +using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Rewrite; @@ -9,7 +13,7 @@ namespace RewriteSample { public void Configure(IApplicationBuilder app, IHostingEnvironment hostingEnv) { - app.UseRewriter(new UrlRewriteOptions() + app.UseRewriter(new RewriteOptions() .ImportFromUrlRewrite(hostingEnv, "UrlRewrite.xml") .ImportFromModRewrite(hostingEnv, "Rewrite.txt")); app.Run(context => context.Response.WriteAsync(context.Request.Path)); @@ -21,6 +25,7 @@ namespace RewriteSample var host = new WebHostBuilder() .UseKestrel() .UseStartup() + .UseContentRoot(Directory.GetCurrentDirectory()) .Build(); host.Run(); diff --git a/samples/RewriteSample/UrlRewrite.xml b/samples/RewriteSample/UrlRewrite.xml index 708ef0e8be..4f5bac7a31 100644 --- a/samples/RewriteSample/UrlRewrite.xml +++ b/samples/RewriteSample/UrlRewrite.xml @@ -1,19 +1,12 @@  - - + + - + + - - - - - - - - - + \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Rewrite/UrlRewriteOptionsAddRulesExtensions.cs b/src/Microsoft.AspNetCore.Rewrite/CodeRewriteExtensions.cs similarity index 77% rename from src/Microsoft.AspNetCore.Rewrite/UrlRewriteOptionsAddRulesExtensions.cs rename to src/Microsoft.AspNetCore.Rewrite/CodeRewriteExtensions.cs index 9effead54a..51060ebdfc 100644 --- a/src/Microsoft.AspNetCore.Rewrite/UrlRewriteOptionsAddRulesExtensions.cs +++ b/src/Microsoft.AspNetCore.Rewrite/CodeRewriteExtensions.cs @@ -4,21 +4,21 @@ using System; using System.Collections.Generic; using System.Text.RegularExpressions; -using Microsoft.AspNetCore.Rewrite.RuleAbstraction; +using Microsoft.AspNetCore.Rewrite.Internal; namespace Microsoft.AspNetCore.Rewrite { /// - /// The builder to a list of rules for and + /// The builder to a list of rules for and /// - public static class UrlRewriteOptionsAddRulesExtensions + public static class CodeRewriteExtensions { /// /// Adds a rule to the current rules. /// /// The UrlRewrite options. /// A rule to be added to the current rules. - public static UrlRewriteOptions AddRule(this UrlRewriteOptions options, Rule rule) + public static RewriteOptions AddRule(this RewriteOptions options, Rule rule) { options.Rules.Add(rule); return options; @@ -29,7 +29,7 @@ namespace Microsoft.AspNetCore.Rewrite /// /// The UrlRewrite options. /// A list of rules. - public static UrlRewriteOptions AddRules(this UrlRewriteOptions options, List rules) + public static RewriteOptions AddRules(this RewriteOptions options, List rules) { options.Rules.AddRange(rules); return options; @@ -43,7 +43,7 @@ namespace Microsoft.AspNetCore.Rewrite /// The string to replace the path with (with capture parameters). /// Whether or not to stop rewriting on success of rule. /// - public static UrlRewriteOptions RewritePath(this UrlRewriteOptions options, string regex, string newPath, bool stopRewriteOnSuccess = false) + public static RewriteOptions RewritePath(this RewriteOptions options, string regex, string newPath, bool stopRewriteOnSuccess = false) { options.Rules.Add(new PathRule { MatchPattern = new Regex(regex, RegexOptions.Compiled, TimeSpan.FromMilliseconds(1)), OnMatch = newPath, OnCompletion = stopRewriteOnSuccess ? Transformation.TerminatingRewrite : Transformation.Rewrite }); return options; @@ -55,7 +55,7 @@ namespace Microsoft.AspNetCore.Rewrite /// The Url rewrite options. /// Whether or not to stop rewriting on success of rule. /// - public static UrlRewriteOptions RewriteScheme(this UrlRewriteOptions options, bool stopRewriteOnSuccess = false) + public static RewriteOptions RewriteScheme(this RewriteOptions options, bool stopRewriteOnSuccess = false) { options.Rules.Add(new SchemeRule {OnCompletion = stopRewriteOnSuccess ? Transformation.TerminatingRewrite : Transformation.Rewrite }); return options; @@ -69,7 +69,7 @@ namespace Microsoft.AspNetCore.Rewrite /// The string to replace the path with (with capture parameters). /// Whether or not to stop rewriting on success of rule. /// - public static UrlRewriteOptions RedirectPath(this UrlRewriteOptions options, string regex, string newPath, bool stopRewriteOnSuccess = false) + public static RewriteOptions RedirectPath(this RewriteOptions options, string regex, string newPath, bool stopRewriteOnSuccess = false) { options.Rules.Add(new PathRule { MatchPattern = new Regex(regex, RegexOptions.Compiled, TimeSpan.FromMilliseconds(1)), OnMatch = newPath, OnCompletion = Transformation.Redirect }); return options; @@ -81,7 +81,7 @@ namespace Microsoft.AspNetCore.Rewrite /// The Url rewrite options. /// The port to redirect the scheme to. /// - public static UrlRewriteOptions RedirectScheme(this UrlRewriteOptions options, int? sslPort) + public static RewriteOptions RedirectScheme(this RewriteOptions options, int? sslPort) { options.Rules.Add(new SchemeRule { SSLPort = sslPort, OnCompletion = Transformation.Redirect }); return options; @@ -95,7 +95,7 @@ namespace Microsoft.AspNetCore.Rewrite /// /// /// - public static UrlRewriteOptions CustomRule(this UrlRewriteOptions options, Func onApplyRule, Transformation transform, string description = null) + public static RewriteOptions CustomRule(this RewriteOptions options, Func onApplyRule, Transformation transform, string description = null) { options.Rules.Add(new FunctionalRule { OnApplyRule = onApplyRule, OnCompletion = transform}); return options; diff --git a/src/Microsoft.AspNetCore.Rewrite/RuleAbstraction/FunctionalRule.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/FunctionalRule.cs similarity index 58% rename from src/Microsoft.AspNetCore.Rewrite/RuleAbstraction/FunctionalRule.cs rename to src/Microsoft.AspNetCore.Rewrite/Internal/FunctionalRule.cs index 073e31945d..5704a23a40 100644 --- a/src/Microsoft.AspNetCore.Rewrite/RuleAbstraction/FunctionalRule.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/FunctionalRule.cs @@ -3,12 +3,12 @@ using System; -namespace Microsoft.AspNetCore.Rewrite.RuleAbstraction +namespace Microsoft.AspNetCore.Rewrite.Internal { public class FunctionalRule : Rule { - public Func OnApplyRule { get; set; } + public Func OnApplyRule { get; set; } public Transformation OnCompletion { get; set; } = Transformation.Rewrite; - public override RuleResult ApplyRule(UrlRewriteContext context) => OnApplyRule(context); + public override RuleResult ApplyRule(RewriteContext context) => OnApplyRule(context); } } \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Rewrite/ModRewrite/Condition.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/Condition.cs similarity index 91% rename from src/Microsoft.AspNetCore.Rewrite/ModRewrite/Condition.cs rename to src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/Condition.cs index f3940ecaea..e1af53bda7 100644 --- a/src/Microsoft.AspNetCore.Rewrite/ModRewrite/Condition.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/Condition.cs @@ -1,7 +1,7 @@ // 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. -namespace Microsoft.AspNetCore.Rewrite.ModRewrite +namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite { public class Condition { diff --git a/src/Microsoft.AspNetCore.Rewrite/ModRewrite/ConditionBuilder.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/ConditionBuilder.cs similarity index 97% rename from src/Microsoft.AspNetCore.Rewrite/ModRewrite/ConditionBuilder.cs rename to src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/ConditionBuilder.cs index 109b3b59e1..743b2d8a33 100644 --- a/src/Microsoft.AspNetCore.Rewrite/ModRewrite/ConditionBuilder.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/ConditionBuilder.cs @@ -3,7 +3,7 @@ using System; -namespace Microsoft.AspNetCore.Rewrite.ModRewrite +namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite { public class ConditionBuilder { diff --git a/src/Microsoft.AspNetCore.Rewrite/ModRewrite/ConditionExpression.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/ConditionExpression.cs similarity index 81% rename from src/Microsoft.AspNetCore.Rewrite/ModRewrite/ConditionExpression.cs rename to src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/ConditionExpression.cs index 85222ba020..4d16a03ede 100644 --- a/src/Microsoft.AspNetCore.Rewrite/ModRewrite/ConditionExpression.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/ConditionExpression.cs @@ -2,9 +2,9 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System.Text.RegularExpressions; -using Microsoft.AspNetCore.Rewrite.Operands; +using Microsoft.AspNetCore.Rewrite.Internal.ModRewrite.Operands; -namespace Microsoft.AspNetCore.Rewrite.ModRewrite +namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite { /// /// Represents the ConditionPattern for a mod_rewrite rule. @@ -21,7 +21,7 @@ namespace Microsoft.AspNetCore.Rewrite.ModRewrite /// The previous condition results (for backreferences). /// The testString created from the . /// If the testString satisfies the condition - public bool? CheckConditionExpression(UrlRewriteContext context, Match previous, string testString) + public bool? CheckConditionExpression(RewriteContext context, Match previous, string testString) { return Operand.CheckOperation(previous, testString, context.FileProvider) ^ Invert; } diff --git a/src/Microsoft.AspNetCore.Rewrite/ModRewrite/ConditionFlagType.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/ConditionFlagType.cs similarity index 81% rename from src/Microsoft.AspNetCore.Rewrite/ModRewrite/ConditionFlagType.cs rename to src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/ConditionFlagType.cs index e1b650e8c0..06c7559090 100644 --- a/src/Microsoft.AspNetCore.Rewrite/ModRewrite/ConditionFlagType.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/ConditionFlagType.cs @@ -1,7 +1,7 @@ // 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. -namespace Microsoft.AspNetCore.Rewrite.ModRewrite +namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite { public enum ConditionFlagType { diff --git a/src/Microsoft.AspNetCore.Rewrite/ModRewrite/ConditionFlags.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/ConditionFlags.cs similarity index 98% rename from src/Microsoft.AspNetCore.Rewrite/ModRewrite/ConditionFlags.cs rename to src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/ConditionFlags.cs index 143e008403..e9687f8dce 100644 --- a/src/Microsoft.AspNetCore.Rewrite/ModRewrite/ConditionFlags.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/ConditionFlags.cs @@ -4,7 +4,7 @@ using System; using System.Collections.Generic; -namespace Microsoft.AspNetCore.Rewrite.ModRewrite +namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite { // TODO Refactor Condition Flags and Rule Flags under base flag class public class ConditionFlags diff --git a/src/Microsoft.AspNetCore.Rewrite/ModRewrite/ConditionPatternParser.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/ConditionPatternParser.cs similarity index 99% rename from src/Microsoft.AspNetCore.Rewrite/ModRewrite/ConditionPatternParser.cs rename to src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/ConditionPatternParser.cs index 24cd7e67c5..2d14d9c7d0 100644 --- a/src/Microsoft.AspNetCore.Rewrite/ModRewrite/ConditionPatternParser.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/ConditionPatternParser.cs @@ -4,7 +4,7 @@ using System; using Microsoft.AspNetCore.Rewrite.Internal; -namespace Microsoft.AspNetCore.Rewrite.ModRewrite +namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite { /// /// Parses the "CondPattern" portion of the RewriteCond. diff --git a/src/Microsoft.AspNetCore.Rewrite/ModRewrite/ConditionTestStringParser.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/ConditionTestStringParser.cs similarity index 99% rename from src/Microsoft.AspNetCore.Rewrite/ModRewrite/ConditionTestStringParser.cs rename to src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/ConditionTestStringParser.cs index 04b16b649e..e3f8b1a18e 100644 --- a/src/Microsoft.AspNetCore.Rewrite/ModRewrite/ConditionTestStringParser.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/ConditionTestStringParser.cs @@ -5,7 +5,7 @@ using System; using System.Collections.Generic; using Microsoft.AspNetCore.Rewrite.Internal; -namespace Microsoft.AspNetCore.Rewrite.ModRewrite +namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite { /// /// Parses the TestString segment of the mod_rewrite condition. diff --git a/src/Microsoft.AspNetCore.Rewrite/ModRewrite/ConditionType.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/ConditionType.cs similarity index 83% rename from src/Microsoft.AspNetCore.Rewrite/ModRewrite/ConditionType.cs rename to src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/ConditionType.cs index e30325a8e5..f8f6818979 100644 --- a/src/Microsoft.AspNetCore.Rewrite/ModRewrite/ConditionType.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/ConditionType.cs @@ -1,7 +1,7 @@ // 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. -namespace Microsoft.AspNetCore.Rewrite.ModRewrite +namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite { public enum ConditionType { diff --git a/src/Microsoft.AspNetCore.Rewrite/ModRewrite/ExpressionCreator.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/ExpressionCreator.cs similarity index 97% rename from src/Microsoft.AspNetCore.Rewrite/ModRewrite/ExpressionCreator.cs rename to src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/ExpressionCreator.cs index 886ccea5a1..0fab8c0d3f 100644 --- a/src/Microsoft.AspNetCore.Rewrite/ModRewrite/ExpressionCreator.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/ExpressionCreator.cs @@ -3,10 +3,9 @@ using System; using System.Text.RegularExpressions; -using Microsoft.AspNetCore.Rewrite.Operands; -using Microsoft.AspNetCore.Rewrite.RuleAbstraction; +using Microsoft.AspNetCore.Rewrite.Internal.ModRewrite.Operands; -namespace Microsoft.AspNetCore.Rewrite.ModRewrite +namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite { /// /// Converts a parsed expression into a mod_rewrite condition. diff --git a/src/Microsoft.AspNetCore.Rewrite/ModRewrite/FileParser.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/FileParser.cs similarity index 97% rename from src/Microsoft.AspNetCore.Rewrite/ModRewrite/FileParser.cs rename to src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/FileParser.cs index 201fba8834..3cee0d1e72 100644 --- a/src/Microsoft.AspNetCore.Rewrite/ModRewrite/FileParser.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/FileParser.cs @@ -4,9 +4,9 @@ using System; using System.Collections.Generic; using System.IO; -using Microsoft.AspNetCore.Rewrite.RuleAbstraction; +using Microsoft.AspNetCore.Rewrite.Internal; -namespace Microsoft.AspNetCore.Rewrite.ModRewrite +namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite { /// /// diff --git a/src/Microsoft.AspNetCore.Rewrite/ModRewrite/FlagParser.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/FlagParser.cs similarity index 98% rename from src/Microsoft.AspNetCore.Rewrite/ModRewrite/FlagParser.cs rename to src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/FlagParser.cs index b96de6e81a..4053ea8d7e 100644 --- a/src/Microsoft.AspNetCore.Rewrite/ModRewrite/FlagParser.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/FlagParser.cs @@ -3,7 +3,7 @@ using System; -namespace Microsoft.AspNetCore.Rewrite.ModRewrite +namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite { /// /// Parses the flags diff --git a/src/Microsoft.AspNetCore.Rewrite/Operands/IntegerOperand.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/Operands/IntegerOperand.cs similarity index 96% rename from src/Microsoft.AspNetCore.Rewrite/Operands/IntegerOperand.cs rename to src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/Operands/IntegerOperand.cs index e65d7bac93..227d1c2bbe 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Operands/IntegerOperand.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/Operands/IntegerOperand.cs @@ -6,7 +6,7 @@ using System.Globalization; using System.Text.RegularExpressions; using Microsoft.Extensions.FileProviders; -namespace Microsoft.AspNetCore.Rewrite.Operands +namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite.Operands { public class IntegerOperand : Operand { diff --git a/src/Microsoft.AspNetCore.Rewrite/Operands/IntegerOperation.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/Operands/IntegerOperation.cs similarity index 82% rename from src/Microsoft.AspNetCore.Rewrite/Operands/IntegerOperation.cs rename to src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/Operands/IntegerOperation.cs index 3abd0b3e16..873846e123 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Operands/IntegerOperation.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/Operands/IntegerOperation.cs @@ -1,7 +1,7 @@ // 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. -namespace Microsoft.AspNetCore.Rewrite.Operands +namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite.Operands { public enum IntegerOperationType { diff --git a/src/Microsoft.AspNetCore.Rewrite/Operands/Operand.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/Operands/Operand.cs similarity index 85% rename from src/Microsoft.AspNetCore.Rewrite/Operands/Operand.cs rename to src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/Operands/Operand.cs index 0562e14b7c..565cd932fc 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Operands/Operand.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/Operands/Operand.cs @@ -4,7 +4,7 @@ using System.Text.RegularExpressions; using Microsoft.Extensions.FileProviders; -namespace Microsoft.AspNetCore.Rewrite.Operands +namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite.Operands { public abstract class Operand { diff --git a/src/Microsoft.AspNetCore.Rewrite/Operands/PropertyOperand.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/Operands/PropertyOperand.cs similarity index 96% rename from src/Microsoft.AspNetCore.Rewrite/Operands/PropertyOperand.cs rename to src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/Operands/PropertyOperand.cs index 2637a00119..fd7f649e7d 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Operands/PropertyOperand.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/Operands/PropertyOperand.cs @@ -5,7 +5,7 @@ using System; using System.Text.RegularExpressions; using Microsoft.Extensions.FileProviders; -namespace Microsoft.AspNetCore.Rewrite.Operands +namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite.Operands { public class PropertyOperand : Operand { diff --git a/src/Microsoft.AspNetCore.Rewrite/Operands/PropertyOperation.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/Operands/PropertyOperation.cs similarity index 84% rename from src/Microsoft.AspNetCore.Rewrite/Operands/PropertyOperation.cs rename to src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/Operands/PropertyOperation.cs index 4fc409e98f..f151c1db64 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Operands/PropertyOperation.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/Operands/PropertyOperation.cs @@ -1,7 +1,7 @@ // 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. -namespace Microsoft.AspNetCore.Rewrite.Operands +namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite.Operands { public enum PropertyOperationType { diff --git a/src/Microsoft.AspNetCore.Rewrite/Operands/RegexOperand.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/Operands/RegexOperand.cs similarity index 90% rename from src/Microsoft.AspNetCore.Rewrite/Operands/RegexOperand.cs rename to src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/Operands/RegexOperand.cs index e9eac3b7bb..e7159b8e43 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Operands/RegexOperand.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/Operands/RegexOperand.cs @@ -4,7 +4,7 @@ using System.Text.RegularExpressions; using Microsoft.Extensions.FileProviders; -namespace Microsoft.AspNetCore.Rewrite.Operands +namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite.Operands { public class RegexOperand : Operand { diff --git a/src/Microsoft.AspNetCore.Rewrite/Operands/StringOperand.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/Operands/StringOperand.cs similarity index 95% rename from src/Microsoft.AspNetCore.Rewrite/Operands/StringOperand.cs rename to src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/Operands/StringOperand.cs index 06360eb38a..a48b929eff 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Operands/StringOperand.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/Operands/StringOperand.cs @@ -5,7 +5,7 @@ using System; using System.Text.RegularExpressions; using Microsoft.Extensions.FileProviders; -namespace Microsoft.AspNetCore.Rewrite.Operands +namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite.Operands { public class StringOperand : Operand { diff --git a/src/Microsoft.AspNetCore.Rewrite/Operands/StringOperation.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/Operands/StringOperation.cs similarity index 81% rename from src/Microsoft.AspNetCore.Rewrite/Operands/StringOperation.cs rename to src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/Operands/StringOperation.cs index 51bc4ec48a..a35a51bf9e 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Operands/StringOperation.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/Operands/StringOperation.cs @@ -1,7 +1,7 @@ // 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. -namespace Microsoft.AspNetCore.Rewrite.Operands +namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite.Operands { public enum StringOperationType { diff --git a/src/Microsoft.AspNetCore.Rewrite/ModRewrite/OperationType.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/OperationType.cs similarity index 88% rename from src/Microsoft.AspNetCore.Rewrite/ModRewrite/OperationType.cs rename to src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/OperationType.cs index 8f2ec10e9b..4019c1cc11 100644 --- a/src/Microsoft.AspNetCore.Rewrite/ModRewrite/OperationType.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/OperationType.cs @@ -1,7 +1,7 @@ // 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. -namespace Microsoft.AspNetCore.Rewrite.ModRewrite +namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite { public enum OperationType { diff --git a/src/Microsoft.AspNetCore.Rewrite/ModRewrite/ParsedConditionExpression.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/ParsedConditionExpression.cs similarity index 92% rename from src/Microsoft.AspNetCore.Rewrite/ModRewrite/ParsedConditionExpression.cs rename to src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/ParsedConditionExpression.cs index b0402f9e99..5bb69e6e8d 100644 --- a/src/Microsoft.AspNetCore.Rewrite/ModRewrite/ParsedConditionExpression.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/ParsedConditionExpression.cs @@ -1,7 +1,7 @@ // 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. -namespace Microsoft.AspNetCore.Rewrite.ModRewrite +namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite { public class ParsedModRewriteExpression { diff --git a/src/Microsoft.AspNetCore.Rewrite/ModRewrite/Pattern.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/Pattern.cs similarity index 95% rename from src/Microsoft.AspNetCore.Rewrite/ModRewrite/Pattern.cs rename to src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/Pattern.cs index 8adcad99dd..8d7de10791 100644 --- a/src/Microsoft.AspNetCore.Rewrite/ModRewrite/Pattern.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/Pattern.cs @@ -1,14 +1,12 @@ // 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; using System.Collections.Generic; using System.Text; using System.Text.RegularExpressions; using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Rewrite.ModRewrite; -namespace Microsoft.AspNetCore.Rewrite.ModRewrite +namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite { /// /// Contains a sequence of pattern segments, which on obtaining the context, will create the appropriate diff --git a/src/Microsoft.AspNetCore.Rewrite/ModRewrite/PatternSegment.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/PatternSegment.cs similarity index 93% rename from src/Microsoft.AspNetCore.Rewrite/ModRewrite/PatternSegment.cs rename to src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/PatternSegment.cs index 8cb0e961b7..8a59179b5a 100644 --- a/src/Microsoft.AspNetCore.Rewrite/ModRewrite/PatternSegment.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/PatternSegment.cs @@ -1,7 +1,7 @@ // 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. -namespace Microsoft.AspNetCore.Rewrite.ModRewrite +namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite { /// /// A Pattern segment contains a portion of the test string/ substitution segment with a type associated. diff --git a/src/Microsoft.AspNetCore.Rewrite/ModRewrite/RuleBuilder.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/RuleBuilder.cs similarity index 98% rename from src/Microsoft.AspNetCore.Rewrite/ModRewrite/RuleBuilder.cs rename to src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/RuleBuilder.cs index 35530a80bd..9c288b00c3 100644 --- a/src/Microsoft.AspNetCore.Rewrite/ModRewrite/RuleBuilder.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/RuleBuilder.cs @@ -4,7 +4,7 @@ using System; using System.Collections.Generic; -namespace Microsoft.AspNetCore.Rewrite.ModRewrite +namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite { public class RuleBuilder { diff --git a/src/Microsoft.AspNetCore.Rewrite/ModRewrite/RuleFlagType.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/RuleFlagType.cs similarity index 91% rename from src/Microsoft.AspNetCore.Rewrite/ModRewrite/RuleFlagType.cs rename to src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/RuleFlagType.cs index d67e698c39..acdb289d2b 100644 --- a/src/Microsoft.AspNetCore.Rewrite/ModRewrite/RuleFlagType.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/RuleFlagType.cs @@ -1,7 +1,7 @@ // 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. -namespace Microsoft.AspNetCore.Rewrite.ModRewrite +namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite { public enum RuleFlagType { diff --git a/src/Microsoft.AspNetCore.Rewrite/ModRewrite/RuleFlags.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/RuleFlags.cs similarity index 98% rename from src/Microsoft.AspNetCore.Rewrite/ModRewrite/RuleFlags.cs rename to src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/RuleFlags.cs index 58496996bd..1c2d632d41 100644 --- a/src/Microsoft.AspNetCore.Rewrite/ModRewrite/RuleFlags.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/RuleFlags.cs @@ -4,7 +4,7 @@ using System; using System.Collections.Generic; -namespace Microsoft.AspNetCore.Rewrite.ModRewrite +namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite { public class RuleFlags { diff --git a/src/Microsoft.AspNetCore.Rewrite/ModRewrite/RuleRegexParser.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/RuleRegexParser.cs similarity index 92% rename from src/Microsoft.AspNetCore.Rewrite/ModRewrite/RuleRegexParser.cs rename to src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/RuleRegexParser.cs index 358eaebc15..3d8254e44d 100644 --- a/src/Microsoft.AspNetCore.Rewrite/ModRewrite/RuleRegexParser.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/RuleRegexParser.cs @@ -3,7 +3,7 @@ using System; -namespace Microsoft.AspNetCore.Rewrite.ModRewrite +namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite { public static class RuleRegexParser { diff --git a/src/Microsoft.AspNetCore.Rewrite/ModRewrite/SegmentType.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/SegmentType.cs similarity index 100% rename from src/Microsoft.AspNetCore.Rewrite/ModRewrite/SegmentType.cs rename to src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/SegmentType.cs diff --git a/src/Microsoft.AspNetCore.Rewrite/ModRewrite/ServerVariables.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/ServerVariables.cs similarity index 99% rename from src/Microsoft.AspNetCore.Rewrite/ModRewrite/ServerVariables.cs rename to src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/ServerVariables.cs index 421ace308f..ec219142d2 100644 --- a/src/Microsoft.AspNetCore.Rewrite/ModRewrite/ServerVariables.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/ServerVariables.cs @@ -9,7 +9,7 @@ using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http.Features; using Microsoft.Net.Http.Headers; -namespace Microsoft.AspNetCore.Rewrite.ModRewrite +namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite { /// /// mod_rewrite lookups for specific string constants. diff --git a/src/Microsoft.AspNetCore.Rewrite/ModRewrite/Tokenizer.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/Tokenizer.cs similarity index 98% rename from src/Microsoft.AspNetCore.Rewrite/ModRewrite/Tokenizer.cs rename to src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/Tokenizer.cs index 9d08094baa..18979e29a0 100644 --- a/src/Microsoft.AspNetCore.Rewrite/ModRewrite/Tokenizer.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/Tokenizer.cs @@ -5,7 +5,7 @@ using System; using System.Collections.Generic; using Microsoft.AspNetCore.Rewrite.Internal; -namespace Microsoft.AspNetCore.Rewrite.ModRewrite +namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite { /// /// Tokenizes a mod_rewrite rule, delimited by spaces. diff --git a/src/Microsoft.AspNetCore.Rewrite/ModRewrite/ModRewriteRule.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewriteRule.cs similarity index 89% rename from src/Microsoft.AspNetCore.Rewrite/ModRewrite/ModRewriteRule.cs rename to src/Microsoft.AspNetCore.Rewrite/Internal/ModRewriteRule.cs index 364fbf7275..529ae08eb5 100644 --- a/src/Microsoft.AspNetCore.Rewrite/ModRewrite/ModRewriteRule.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewriteRule.cs @@ -6,9 +6,8 @@ using System.Collections.Generic; using Microsoft.Net.Http.Headers; using System.Text.RegularExpressions; using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Rewrite.RuleAbstraction; -namespace Microsoft.AspNetCore.Rewrite.ModRewrite +namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite { public class ModRewriteRule : Rule { @@ -28,7 +27,7 @@ namespace Microsoft.AspNetCore.Rewrite.ModRewrite Description = description; } - public override RuleResult ApplyRule(UrlRewriteContext context) + public override RuleResult ApplyRule(RewriteContext context) { // 1. Figure out which section of the string to match for the initial rule. var results = InitialRule.Operand.RegexOperation.Match(context.HttpContext.Request.Path.ToString()); @@ -36,7 +35,7 @@ namespace Microsoft.AspNetCore.Rewrite.ModRewrite string flagRes = null; if (CheckMatchResult(results.Success)) { - return new RuleResult { Result = RuleTerminiation.Continue }; + return RuleResult.Continue; } if (Flags.HasFlag(RuleFlagType.EscapeBackreference)) @@ -49,7 +48,7 @@ namespace Microsoft.AspNetCore.Rewrite.ModRewrite if (!CheckCondition(context, results, previous)) { - return new RuleResult { Result = RuleTerminiation.Continue }; + return RuleResult.Continue; } // TODO add chained flag @@ -82,12 +81,12 @@ namespace Microsoft.AspNetCore.Rewrite.ModRewrite if (Flags.HasFlag(RuleFlagType.Forbidden)) { context.HttpContext.Response.StatusCode = StatusCodes.Status403Forbidden; - return new RuleResult { Result = RuleTerminiation.ResponseComplete }; + return RuleResult.ResponseComplete; } else if (Flags.HasFlag(RuleFlagType.Gone)) { context.HttpContext.Response.StatusCode = StatusCodes.Status410Gone; - return new RuleResult { Result = RuleTerminiation.ResponseComplete }; + return RuleResult.ResponseComplete; } else if (result == "-") { @@ -124,7 +123,7 @@ namespace Microsoft.AspNetCore.Rewrite.ModRewrite context.HttpContext.Response.Headers[HeaderNames.Location] = "/" + result + context.HttpContext.Request.QueryString; } } - return new RuleResult { Result = RuleTerminiation.ResponseComplete }; + return RuleResult.ResponseComplete; } else { @@ -145,11 +144,11 @@ namespace Microsoft.AspNetCore.Rewrite.ModRewrite } if (Flags.HasFlag(RuleFlagType.Last) || Flags.HasFlag(RuleFlagType.End)) { - return new RuleResult { Result = RuleTerminiation.StopRules }; + return RuleResult.StopRules; } else { - return new RuleResult { Result = RuleTerminiation.Continue }; + return RuleResult.Continue; } } } @@ -163,7 +162,7 @@ namespace Microsoft.AspNetCore.Rewrite.ModRewrite return !(result.Value ^ InitialRule.Invert); } - private bool CheckCondition(UrlRewriteContext context, Match results, Match previous) + private bool CheckCondition(RewriteContext context, Match results, Match previous) { if (Conditions == null) { diff --git a/src/Microsoft.AspNetCore.Rewrite/ParserContext.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/ParserContext.cs similarity index 100% rename from src/Microsoft.AspNetCore.Rewrite/ParserContext.cs rename to src/Microsoft.AspNetCore.Rewrite/Internal/ParserContext.cs diff --git a/src/Microsoft.AspNetCore.Rewrite/RuleAbstraction/PathRule.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/PathRule.cs similarity index 76% rename from src/Microsoft.AspNetCore.Rewrite/RuleAbstraction/PathRule.cs rename to src/Microsoft.AspNetCore.Rewrite/Internal/PathRule.cs index 697810ef35..88b07e6cde 100644 --- a/src/Microsoft.AspNetCore.Rewrite/RuleAbstraction/PathRule.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/PathRule.cs @@ -3,14 +3,14 @@ using System.Text.RegularExpressions; -namespace Microsoft.AspNetCore.Rewrite.RuleAbstraction +namespace Microsoft.AspNetCore.Rewrite.Internal { public class PathRule : Rule { public Regex MatchPattern { get; set; } public string OnMatch { get; set; } public Transformation OnCompletion { get; set; } = Transformation.Rewrite; - public override RuleResult ApplyRule(UrlRewriteContext context) + public override RuleResult ApplyRule(RewriteContext context) { var matches = MatchPattern.Match(context.HttpContext.Request.Path); if (matches.Success) @@ -27,7 +27,7 @@ namespace Microsoft.AspNetCore.Rewrite.RuleAbstraction path, req.QueryString); context.HttpContext.Response.Redirect(newUrl); - return new RuleResult { Result = RuleTerminiation.ResponseComplete }; + return RuleResult.ResponseComplete; } else { @@ -35,14 +35,14 @@ namespace Microsoft.AspNetCore.Rewrite.RuleAbstraction } if (OnCompletion == Transformation.TerminatingRewrite) { - return new RuleResult { Result = RuleTerminiation.StopRules }; + return RuleResult.StopRules; } else { - return new RuleResult { Result = RuleTerminiation.Continue }; + return RuleResult.Continue; } } - return new RuleResult { Result = RuleTerminiation.Continue }; + return RuleResult.Continue; } } } diff --git a/src/Microsoft.AspNetCore.Rewrite/RuleAbstraction/Rule.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/Rule.cs similarity index 63% rename from src/Microsoft.AspNetCore.Rewrite/RuleAbstraction/Rule.cs rename to src/Microsoft.AspNetCore.Rewrite/Internal/Rule.cs index 0b636120d2..3ba6067f42 100644 --- a/src/Microsoft.AspNetCore.Rewrite/RuleAbstraction/Rule.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/Rule.cs @@ -1,11 +1,11 @@ // 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. -namespace Microsoft.AspNetCore.Rewrite.RuleAbstraction +namespace Microsoft.AspNetCore.Rewrite.Internal { public abstract class Rule { - public abstract RuleResult ApplyRule(UrlRewriteContext context); + public abstract RuleResult ApplyRule(RewriteContext context); } } diff --git a/src/Microsoft.AspNetCore.Rewrite/RuleAbstraction/RuleExpression.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/RuleExpression.cs similarity index 73% rename from src/Microsoft.AspNetCore.Rewrite/RuleAbstraction/RuleExpression.cs rename to src/Microsoft.AspNetCore.Rewrite/Internal/RuleExpression.cs index e14728e33c..52458cc542 100644 --- a/src/Microsoft.AspNetCore.Rewrite/RuleAbstraction/RuleExpression.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/RuleExpression.cs @@ -1,9 +1,9 @@ // 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 Microsoft.AspNetCore.Rewrite.Operands; +using Microsoft.AspNetCore.Rewrite.Internal.ModRewrite.Operands; -namespace Microsoft.AspNetCore.Rewrite.RuleAbstraction +namespace Microsoft.AspNetCore.Rewrite.Internal { public class RuleExpression { diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/RuleResult.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/RuleResult.cs new file mode 100644 index 0000000000..f7b6c2b45b --- /dev/null +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/RuleResult.cs @@ -0,0 +1,14 @@ +// 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. + +namespace Microsoft.AspNetCore.Rewrite.Internal +{ + public class RuleResult + { + public static RuleResult Continue = new RuleResult { Result = RuleTerminiation.Continue }; + public static RuleResult ResponseComplete = new RuleResult { Result = RuleTerminiation.ResponseComplete }; + public static RuleResult StopRules = new RuleResult { Result = RuleTerminiation.StopRules }; + + public RuleTerminiation Result { get; set; } + } +} diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/ModRewriteCreatorTest.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/RuleTermination.cs similarity index 56% rename from test/Microsoft.AspNetCore.Rewrite.Tests/ModRewriteCreatorTest.cs rename to src/Microsoft.AspNetCore.Rewrite/Internal/RuleTermination.cs index c9a9dd21a1..449a422944 100644 --- a/test/Microsoft.AspNetCore.Rewrite.Tests/ModRewriteCreatorTest.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/RuleTermination.cs @@ -1,9 +1,12 @@ // 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. -namespace Microsoft.AspNetCore.Rewrite +namespace Microsoft.AspNetCore.Rewrite.Internal { - public class ModRewriteCreatorTest + public enum RuleTerminiation { + Continue, + ResponseComplete, + StopRules } } diff --git a/src/Microsoft.AspNetCore.Rewrite/RuleAbstraction/SchemeRule.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/SchemeRule.cs similarity index 78% rename from src/Microsoft.AspNetCore.Rewrite/RuleAbstraction/SchemeRule.cs rename to src/Microsoft.AspNetCore.Rewrite/Internal/SchemeRule.cs index 427a38bfc6..87a08544e8 100644 --- a/src/Microsoft.AspNetCore.Rewrite/RuleAbstraction/SchemeRule.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/SchemeRule.cs @@ -4,13 +4,13 @@ using System.Text; using Microsoft.AspNetCore.Http; -namespace Microsoft.AspNetCore.Rewrite.RuleAbstraction +namespace Microsoft.AspNetCore.Rewrite.Internal { public class SchemeRule : Rule { public int? SSLPort { get; set; } public Transformation OnCompletion { get; set; } = Transformation.Rewrite; - public override RuleResult ApplyRule(UrlRewriteContext context) + public override RuleResult ApplyRule(RewriteContext context) { // TODO this only does http to https, add more features in the future. @@ -34,11 +34,11 @@ namespace Microsoft.AspNetCore.Rewrite.RuleAbstraction context.HttpContext.Request.Host = host; if (OnCompletion == Transformation.TerminatingRewrite) { - return new RuleResult { Result = RuleTerminiation.StopRules }; + return RuleResult.StopRules; } else { - return new RuleResult { Result = RuleTerminiation.Continue }; + return RuleResult.Continue; } } @@ -46,9 +46,9 @@ namespace Microsoft.AspNetCore.Rewrite.RuleAbstraction var newUrl = new StringBuilder().Append("https://").Append(host).Append(req.PathBase).Append(req.Path).Append(req.QueryString); context.HttpContext.Response.Redirect(newUrl.ToString()); - return new RuleResult { Result = RuleTerminiation.ResponseComplete }; + return RuleResult.ResponseComplete; } - return new RuleResult { Result = RuleTerminiation.Continue }; ; + return RuleResult.Continue; } } } diff --git a/src/Microsoft.AspNetCore.Rewrite/RuleAbstraction/Transformation.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/Transformation.cs similarity index 83% rename from src/Microsoft.AspNetCore.Rewrite/RuleAbstraction/Transformation.cs rename to src/Microsoft.AspNetCore.Rewrite/Internal/Transformation.cs index 44008b89a4..01ca2dc9cf 100644 --- a/src/Microsoft.AspNetCore.Rewrite/RuleAbstraction/Transformation.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/Transformation.cs @@ -1,7 +1,7 @@ // 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. -namespace Microsoft.AspNetCore.Rewrite.RuleAbstraction +namespace Microsoft.AspNetCore.Rewrite.Internal { public enum Transformation { diff --git a/src/Microsoft.AspNetCore.Rewrite/UrlRewrite/ActionType.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/ActionType.cs similarity index 83% rename from src/Microsoft.AspNetCore.Rewrite/UrlRewrite/ActionType.cs rename to src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/ActionType.cs index a7eff7669d..877871073b 100644 --- a/src/Microsoft.AspNetCore.Rewrite/UrlRewrite/ActionType.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/ActionType.cs @@ -1,7 +1,7 @@ // 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. -namespace Microsoft.AspNetCore.Rewrite.UrlRewrite +namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite { public enum ActionType { diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/Condition.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/Condition.cs new file mode 100644 index 0000000000..f6541d48f9 --- /dev/null +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/Condition.cs @@ -0,0 +1,16 @@ +// 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. + +namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite +{ + public class Condition + { + public Pattern Input { get; set; } + public UrlMatch Match { get; set; } + public MatchResults Evaluate(RewriteContext context, MatchResults ruleMatch, MatchResults condMatch) + { + var pattern = Input.Evaluate(context.HttpContext, ruleMatch, condMatch); + return Match.Evaluate(pattern, context); + } + } +} diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/Conditions.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/Conditions.cs new file mode 100644 index 0000000000..b9ffa5b26c --- /dev/null +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/Conditions.cs @@ -0,0 +1,27 @@ +// 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.Collections.Generic; + +namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite +{ + public class Conditions + { + public List ConditionList { get; set; } = new List(); + public LogicalGrouping MatchType { get; set; } // default is MatchAll + public bool TrackingAllCaptures { get; set; } + + public MatchResults Evaluate(RewriteContext context, MatchResults ruleMatch) + { + MatchResults prevCond = null; + var success = true; + foreach (var condition in ConditionList) + { + var res = condition.Evaluate(context, ruleMatch, prevCond); + success = (MatchType == LogicalGrouping.MatchAll ? (success && res.Success) : (success || res.Success)); + prevCond = res; + } + return new MatchResults { Success = success, BackReference = prevCond?.BackReference }; + } + } +} diff --git a/src/Microsoft.AspNetCore.Rewrite/UrlRewrite/InputParser.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/InputParser.cs similarity index 97% rename from src/Microsoft.AspNetCore.Rewrite/UrlRewrite/InputParser.cs rename to src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/InputParser.cs index eb8bbd0410..8d45ac0433 100644 --- a/src/Microsoft.AspNetCore.Rewrite/UrlRewrite/InputParser.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/InputParser.cs @@ -3,11 +3,9 @@ using System; using System.Collections.Generic; -using System.Text.Encodings.Web; -using Microsoft.AspNetCore.Rewrite.Internal; -using Microsoft.AspNetCore.Rewrite.UrlRewrite.PatternSegments; +using Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite.PatternSegments; -namespace Microsoft.AspNetCore.Rewrite.UrlRewrite +namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite { /// /// diff --git a/src/Microsoft.AspNetCore.Rewrite/UrlRewrite/LogicalGrouping.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/LogicalGrouping.cs similarity index 81% rename from src/Microsoft.AspNetCore.Rewrite/UrlRewrite/LogicalGrouping.cs rename to src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/LogicalGrouping.cs index 5f2568c8e6..275d317b65 100644 --- a/src/Microsoft.AspNetCore.Rewrite/UrlRewrite/LogicalGrouping.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/LogicalGrouping.cs @@ -1,7 +1,7 @@ // 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. -namespace Microsoft.AspNetCore.Rewrite.UrlRewrite +namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite { public enum LogicalGrouping { diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/MatchResults.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/MatchResults.cs new file mode 100644 index 0000000000..6f182109f8 --- /dev/null +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/MatchResults.cs @@ -0,0 +1,13 @@ +// 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.Text.RegularExpressions; + +namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite +{ + public class MatchResults + { + public GroupCollection BackReference { get; set; } + public bool Success { get; set; } + } +} diff --git a/src/Microsoft.AspNetCore.Rewrite/UrlRewrite/MatchType.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/MatchType.cs similarity index 81% rename from src/Microsoft.AspNetCore.Rewrite/UrlRewrite/MatchType.cs rename to src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/MatchType.cs index 260ecba3d0..cfb763dcfb 100644 --- a/src/Microsoft.AspNetCore.Rewrite/UrlRewrite/MatchType.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/MatchType.cs @@ -1,7 +1,7 @@ // 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. -namespace Microsoft.AspNetCore.Rewrite.UrlRewrite +namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite { public enum MatchType { diff --git a/src/Microsoft.AspNetCore.Rewrite/UrlRewrite/Condition.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/ParsedCondition.cs similarity index 62% rename from src/Microsoft.AspNetCore.Rewrite/UrlRewrite/Condition.cs rename to src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/ParsedCondition.cs index 17030d2d5f..e34ccdb00f 100644 --- a/src/Microsoft.AspNetCore.Rewrite/UrlRewrite/Condition.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/ParsedCondition.cs @@ -1,14 +1,10 @@ // 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.Text.RegularExpressions; - -namespace Microsoft.AspNetCore.Rewrite.UrlRewrite +namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite { - public class Condition + public class ParsedCondition { - public Pattern Input { get; set; } - public Regex MatchPattern { get; set; } public bool Negate { get; set; } public bool IgnoreCase { get; set; } = true; public MatchType MatchType { get; set; } = MatchType.Pattern; diff --git a/src/Microsoft.AspNetCore.Rewrite/UrlRewrite/UrlAction.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/ParsedUrlAction.cs similarity index 61% rename from src/Microsoft.AspNetCore.Rewrite/UrlRewrite/UrlAction.cs rename to src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/ParsedUrlAction.cs index c0d56f603a..857c2f16cd 100644 --- a/src/Microsoft.AspNetCore.Rewrite/UrlRewrite/UrlAction.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/ParsedUrlAction.cs @@ -1,14 +1,14 @@ // 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. -namespace Microsoft.AspNetCore.Rewrite.UrlRewrite +namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite { - public class UrlAction + public class ParsedUrlAction { public ActionType Type { get; set; } public Pattern Url { get; set; } - public bool AppendQueryString { get; set; } - public bool LogRewrittenUrl { get; set; } + public bool AppendQueryString { get; set; } = true; + public bool LogRewrittenUrl { get; set; } // Ignoring this flag. public RedirectType RedirectType { get; set; } = RedirectType.Permanent; } } diff --git a/src/Microsoft.AspNetCore.Rewrite/RuleAbstraction/RuleResult.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/ParsedUrlMatch.cs similarity index 51% rename from src/Microsoft.AspNetCore.Rewrite/RuleAbstraction/RuleResult.cs rename to src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/ParsedUrlMatch.cs index 67aa51f583..9f183fadc3 100644 --- a/src/Microsoft.AspNetCore.Rewrite/RuleAbstraction/RuleResult.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/ParsedUrlMatch.cs @@ -1,10 +1,11 @@ // 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. -namespace Microsoft.AspNetCore.Rewrite.RuleAbstraction +namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite { - public class RuleResult + public class ParsedUrlMatch { - public RuleTerminiation Result { get; set; } + public bool IgnoreCase { get; set; } + public bool Negate { get; set; } } } diff --git a/src/Microsoft.AspNetCore.Rewrite/UrlRewrite/Pattern.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/Pattern.cs similarity index 76% rename from src/Microsoft.AspNetCore.Rewrite/UrlRewrite/Pattern.cs rename to src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/Pattern.cs index aa62e3c825..a796da468f 100644 --- a/src/Microsoft.AspNetCore.Rewrite/UrlRewrite/Pattern.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/Pattern.cs @@ -3,23 +3,23 @@ using System.Collections.Generic; using System.Text; -using System.Text.RegularExpressions; using Microsoft.AspNetCore.Http; -namespace Microsoft.AspNetCore.Rewrite.UrlRewrite +namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite { public class Pattern { public IList PatternSegments { get; } - public Pattern(List patternSegments) { PatternSegments = patternSegments; } - public string Evaluate(HttpContext context, Match ruleMatch, Match condMatch) + public string Evaluate(HttpContext context, MatchResults ruleMatch, MatchResults condMatch) { var strBuilder = new StringBuilder(); + + // TODO consider thread static for string builder - DAVID PERF foreach (var pattern in PatternSegments) { strBuilder.Append(pattern.Evaluate(context, ruleMatch, condMatch)); diff --git a/src/Microsoft.AspNetCore.Rewrite/UrlRewrite/PatternSegment.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/PatternSegment.cs similarity index 76% rename from src/Microsoft.AspNetCore.Rewrite/UrlRewrite/PatternSegment.cs rename to src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/PatternSegment.cs index d80755d77a..820d5cdfb4 100644 --- a/src/Microsoft.AspNetCore.Rewrite/UrlRewrite/PatternSegment.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/PatternSegment.cs @@ -1,15 +1,13 @@ // 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; -using System.Text.RegularExpressions; using Microsoft.AspNetCore.Http; -namespace Microsoft.AspNetCore.Rewrite.UrlRewrite +namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite { public abstract class PatternSegment { // Match from prevRule, Match from prevCond - public abstract string Evaluate(HttpContext context, Match ruleMatch, Match condMatch); + public abstract string Evaluate(HttpContext context, MatchResults ruleMatch, MatchResults condMatch); } } diff --git a/src/Microsoft.AspNetCore.Rewrite/UrlRewrite/PatternSegments/ConditionMatchSegment.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/PatternSegments/ConditionMatchSegment.cs similarity index 72% rename from src/Microsoft.AspNetCore.Rewrite/UrlRewrite/PatternSegments/ConditionMatchSegment.cs rename to src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/PatternSegments/ConditionMatchSegment.cs index ec53c1549a..1c65243e16 100644 --- a/src/Microsoft.AspNetCore.Rewrite/UrlRewrite/PatternSegments/ConditionMatchSegment.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/PatternSegments/ConditionMatchSegment.cs @@ -1,10 +1,9 @@ // 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.Text.RegularExpressions; using Microsoft.AspNetCore.Http; -namespace Microsoft.AspNetCore.Rewrite.UrlRewrite.PatternSegments +namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite.PatternSegments { public class ConditionMatchSegment : PatternSegment { @@ -15,9 +14,9 @@ namespace Microsoft.AspNetCore.Rewrite.UrlRewrite.PatternSegments Index = index; } - public override string Evaluate(HttpContext context, Match ruleMatch, Match condMatch) + public override string Evaluate(HttpContext context, MatchResults ruleMatch, MatchResults condMatch) { - return condMatch?.Groups[Index]?.Value; + return condMatch?.BackReference[Index]?.Value; } } } diff --git a/src/Microsoft.AspNetCore.Rewrite/UrlRewrite/PatternSegments/HeaderSegment.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/PatternSegments/HeaderSegment.cs similarity index 80% rename from src/Microsoft.AspNetCore.Rewrite/UrlRewrite/PatternSegments/HeaderSegment.cs rename to src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/PatternSegments/HeaderSegment.cs index 0353598bea..c83b2cf6ad 100644 --- a/src/Microsoft.AspNetCore.Rewrite/UrlRewrite/PatternSegments/HeaderSegment.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/PatternSegments/HeaderSegment.cs @@ -1,10 +1,9 @@ // 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.Text.RegularExpressions; using Microsoft.AspNetCore.Http; -namespace Microsoft.AspNetCore.Rewrite.UrlRewrite.PatternSegments +namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite.PatternSegments { public class HeaderSegment : PatternSegment { @@ -15,7 +14,7 @@ namespace Microsoft.AspNetCore.Rewrite.UrlRewrite.PatternSegments Header = header; } - public override string Evaluate(HttpContext context, Match ruleMatch, Match condMatch) + public override string Evaluate(HttpContext context, MatchResults ruleMatch, MatchResults condMatch) { return context.Request.Headers[Header]; } diff --git a/src/Microsoft.AspNetCore.Rewrite/UrlRewrite/PatternSegments/IsHttpsSegment.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/PatternSegments/IsHttpsSegment.cs similarity index 75% rename from src/Microsoft.AspNetCore.Rewrite/UrlRewrite/PatternSegments/IsHttpsSegment.cs rename to src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/PatternSegments/IsHttpsSegment.cs index ff6be8e823..5ffece8e11 100644 --- a/src/Microsoft.AspNetCore.Rewrite/UrlRewrite/PatternSegments/IsHttpsSegment.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/PatternSegments/IsHttpsSegment.cs @@ -1,14 +1,13 @@ // 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.Text.RegularExpressions; using Microsoft.AspNetCore.Http; -namespace Microsoft.AspNetCore.Rewrite.UrlRewrite.PatternSegments +namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite.PatternSegments { public class IsHttpsSegment : PatternSegment { - public override string Evaluate(HttpContext context, Match ruleMatch, Match condMatch) + public override string Evaluate(HttpContext context, MatchResults ruleMatch, MatchResults condMatch) { return context.Request.IsHttps ? "ON" : "OFF"; } diff --git a/src/Microsoft.AspNetCore.Rewrite/UrlRewrite/PatternSegments/LiteralSegment.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/PatternSegments/LiteralSegment.cs similarity index 79% rename from src/Microsoft.AspNetCore.Rewrite/UrlRewrite/PatternSegments/LiteralSegment.cs rename to src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/PatternSegments/LiteralSegment.cs index 43b45fec9c..390459c6c8 100644 --- a/src/Microsoft.AspNetCore.Rewrite/UrlRewrite/PatternSegments/LiteralSegment.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/PatternSegments/LiteralSegment.cs @@ -1,10 +1,9 @@ // 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.Text.RegularExpressions; using Microsoft.AspNetCore.Http; -namespace Microsoft.AspNetCore.Rewrite.UrlRewrite.PatternSegments +namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite.PatternSegments { public class LiteralSegment : PatternSegment { @@ -15,7 +14,7 @@ namespace Microsoft.AspNetCore.Rewrite.UrlRewrite.PatternSegments Literal = literal; } - public override string Evaluate(HttpContext context, Match ruleMatch, Match condMatch) + public override string Evaluate(HttpContext context, MatchResults ruleMatch, MatchResults condMatch) { return Literal; } diff --git a/src/Microsoft.AspNetCore.Rewrite/UrlRewrite/PatternSegments/LocalAddressSegment.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/PatternSegments/LocalAddressSegment.cs similarity index 75% rename from src/Microsoft.AspNetCore.Rewrite/UrlRewrite/PatternSegments/LocalAddressSegment.cs rename to src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/PatternSegments/LocalAddressSegment.cs index a26e79238b..10d77aeb02 100644 --- a/src/Microsoft.AspNetCore.Rewrite/UrlRewrite/PatternSegments/LocalAddressSegment.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/PatternSegments/LocalAddressSegment.cs @@ -1,14 +1,13 @@ // 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.Text.RegularExpressions; using Microsoft.AspNetCore.Http; -namespace Microsoft.AspNetCore.Rewrite.UrlRewrite.PatternSegments +namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite.PatternSegments { public class LocalAddressSegment : PatternSegment { - public override string Evaluate(HttpContext context, Match ruleMatch, Match condMatch) + public override string Evaluate(HttpContext context, MatchResults ruleMatch, MatchResults condMatch) { return context.Connection.LocalIpAddress?.ToString(); } diff --git a/src/Microsoft.AspNetCore.Rewrite/UrlRewrite/PatternSegments/QueryStringSegment.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/PatternSegments/QueryStringSegment.cs similarity index 75% rename from src/Microsoft.AspNetCore.Rewrite/UrlRewrite/PatternSegments/QueryStringSegment.cs rename to src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/PatternSegments/QueryStringSegment.cs index 5b51d8f98c..d5081a4e6a 100644 --- a/src/Microsoft.AspNetCore.Rewrite/UrlRewrite/PatternSegments/QueryStringSegment.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/PatternSegments/QueryStringSegment.cs @@ -1,14 +1,13 @@ // 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.Text.RegularExpressions; using Microsoft.AspNetCore.Http; -namespace Microsoft.AspNetCore.Rewrite.UrlRewrite.PatternSegments +namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite.PatternSegments { public class QueryStringSegment : PatternSegment { - public override string Evaluate(HttpContext context, Match ruleMatch, Match condMatch) + public override string Evaluate(HttpContext context, MatchResults ruleMatch, MatchResults condMatch) { return context.Request.QueryString.ToString(); } diff --git a/src/Microsoft.AspNetCore.Rewrite/UrlRewrite/PatternSegments/RemoteAddressSegment.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/PatternSegments/RemoteAddressSegment.cs similarity index 75% rename from src/Microsoft.AspNetCore.Rewrite/UrlRewrite/PatternSegments/RemoteAddressSegment.cs rename to src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/PatternSegments/RemoteAddressSegment.cs index 20bf50c523..499b5a3e91 100644 --- a/src/Microsoft.AspNetCore.Rewrite/UrlRewrite/PatternSegments/RemoteAddressSegment.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/PatternSegments/RemoteAddressSegment.cs @@ -1,14 +1,13 @@ // 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.Text.RegularExpressions; using Microsoft.AspNetCore.Http; -namespace Microsoft.AspNetCore.Rewrite.UrlRewrite.PatternSegments +namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite.PatternSegments { public class RemoteAddressSegment : PatternSegment { - public override string Evaluate(HttpContext context, Match ruleMatch, Match condMatch) + public override string Evaluate(HttpContext context, MatchResults ruleMatch, MatchResults condMatch) { return context.Connection.RemoteIpAddress?.ToString(); } diff --git a/src/Microsoft.AspNetCore.Rewrite/UrlRewrite/PatternSegments/RemotePortSegment.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/PatternSegments/RemotePortSegment.cs similarity index 77% rename from src/Microsoft.AspNetCore.Rewrite/UrlRewrite/PatternSegments/RemotePortSegment.cs rename to src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/PatternSegments/RemotePortSegment.cs index bb1c391b29..25456dc102 100644 --- a/src/Microsoft.AspNetCore.Rewrite/UrlRewrite/PatternSegments/RemotePortSegment.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/PatternSegments/RemotePortSegment.cs @@ -2,14 +2,13 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System.Globalization; -using System.Text.RegularExpressions; using Microsoft.AspNetCore.Http; -namespace Microsoft.AspNetCore.Rewrite.UrlRewrite.PatternSegments +namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite.PatternSegments { public class RemotePortSegment : PatternSegment { - public override string Evaluate(HttpContext context, Match ruleMatch, Match condMatch) + public override string Evaluate(HttpContext context, MatchResults ruleMatch, MatchResults condMatch) { return context.Connection.RemotePort.ToString(CultureInfo.InvariantCulture); } diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/PatternSegments/RequestFilenameSegment.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/PatternSegments/RequestFilenameSegment.cs new file mode 100644 index 0000000000..8d467684f6 --- /dev/null +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/PatternSegments/RequestFilenameSegment.cs @@ -0,0 +1,15 @@ +// 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 Microsoft.AspNetCore.Http; + +namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite.PatternSegments +{ + public class RequestFileNameSegment : PatternSegment + { + public override string Evaluate(HttpContext context, MatchResults ruleMatch, MatchResults condMatch) + { + return context.Request.Path; + } + } +} diff --git a/src/Microsoft.AspNetCore.Rewrite/UrlRewrite/PatternSegments/RuleMatchSegment.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/PatternSegments/RuleMatchSegment.cs similarity index 72% rename from src/Microsoft.AspNetCore.Rewrite/UrlRewrite/PatternSegments/RuleMatchSegment.cs rename to src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/PatternSegments/RuleMatchSegment.cs index 2ebbb0f61c..b8384aaa49 100644 --- a/src/Microsoft.AspNetCore.Rewrite/UrlRewrite/PatternSegments/RuleMatchSegment.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/PatternSegments/RuleMatchSegment.cs @@ -1,10 +1,9 @@ // 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.Text.RegularExpressions; using Microsoft.AspNetCore.Http; -namespace Microsoft.AspNetCore.Rewrite.UrlRewrite.PatternSegments +namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite.PatternSegments { public class RuleMatchSegment : PatternSegment { @@ -15,9 +14,9 @@ namespace Microsoft.AspNetCore.Rewrite.UrlRewrite.PatternSegments Index = index; } - public override string Evaluate(HttpContext context, Match ruleMatch, Match condMatch) + public override string Evaluate(HttpContext context, MatchResults ruleMatch, MatchResults condMatch) { - return ruleMatch?.Groups[Index]?.Value; + return ruleMatch?.BackReference[Index]?.Value; } } } diff --git a/src/Microsoft.AspNetCore.Rewrite/UrlRewrite/PatternSegments/ToLowerSegment.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/PatternSegments/ToLowerSegment.cs similarity index 82% rename from src/Microsoft.AspNetCore.Rewrite/UrlRewrite/PatternSegments/ToLowerSegment.cs rename to src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/PatternSegments/ToLowerSegment.cs index 945bdd19f8..b2c9d85679 100644 --- a/src/Microsoft.AspNetCore.Rewrite/UrlRewrite/PatternSegments/ToLowerSegment.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/PatternSegments/ToLowerSegment.cs @@ -1,10 +1,9 @@ // 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.Text.RegularExpressions; using Microsoft.AspNetCore.Http; -namespace Microsoft.AspNetCore.Rewrite.UrlRewrite.PatternSegments +namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite.PatternSegments { public class ToLowerSegment : PatternSegment { @@ -15,7 +14,7 @@ namespace Microsoft.AspNetCore.Rewrite.UrlRewrite.PatternSegments Pattern = pattern; } - public override string Evaluate(HttpContext context, Match ruleMatch, Match condMatch) + public override string Evaluate(HttpContext context, MatchResults ruleMatch, MatchResults condMatch) { var pattern = Pattern.Evaluate(context, ruleMatch, condMatch); return pattern.ToLowerInvariant(); diff --git a/src/Microsoft.AspNetCore.Rewrite/UrlRewrite/PatternSegments/UrlEncodeSegment.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/PatternSegments/UrlEncodeSegment.cs similarity index 83% rename from src/Microsoft.AspNetCore.Rewrite/UrlRewrite/PatternSegments/UrlEncodeSegment.cs rename to src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/PatternSegments/UrlEncodeSegment.cs index 4f97346a8d..83edb5019c 100644 --- a/src/Microsoft.AspNetCore.Rewrite/UrlRewrite/PatternSegments/UrlEncodeSegment.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/PatternSegments/UrlEncodeSegment.cs @@ -2,10 +2,9 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System.Text.Encodings.Web; -using System.Text.RegularExpressions; using Microsoft.AspNetCore.Http; -namespace Microsoft.AspNetCore.Rewrite.UrlRewrite.PatternSegments +namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite.PatternSegments { public class UrlEncodeSegment : PatternSegment { @@ -16,7 +15,7 @@ namespace Microsoft.AspNetCore.Rewrite.UrlRewrite.PatternSegments Pattern = pattern; } - public override string Evaluate(HttpContext context, Match ruleMatch, Match condMatch) + public override string Evaluate(HttpContext context, MatchResults ruleMatch, MatchResults condMatch) { var pattern = Pattern.Evaluate(context, ruleMatch, condMatch); return UrlEncoder.Default.Encode(pattern); diff --git a/src/Microsoft.AspNetCore.Rewrite/UrlRewrite/PatternSegments/UrlSegment.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/PatternSegments/UrlSegment.cs similarity index 65% rename from src/Microsoft.AspNetCore.Rewrite/UrlRewrite/PatternSegments/UrlSegment.cs rename to src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/PatternSegments/UrlSegment.cs index 9dc24ec930..dca3bfb5de 100644 --- a/src/Microsoft.AspNetCore.Rewrite/UrlRewrite/PatternSegments/UrlSegment.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/PatternSegments/UrlSegment.cs @@ -1,16 +1,15 @@ // 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.Text.RegularExpressions; using Microsoft.AspNetCore.Http; -namespace Microsoft.AspNetCore.Rewrite.UrlRewrite.PatternSegments +namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite.PatternSegments { public class UrlSegment : PatternSegment { - public override string Evaluate(HttpContext context, Match ruleMatch, Match condMatch) + public override string Evaluate(HttpContext context, MatchResults ruleMatch, MatchResults condMatch) { - return context.Request.Path.ToString(); + return context.Request.Path; } } } diff --git a/src/Microsoft.AspNetCore.Rewrite/UrlRewrite/PatternSyntax.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/PatternSyntax.cs similarity index 82% rename from src/Microsoft.AspNetCore.Rewrite/UrlRewrite/PatternSyntax.cs rename to src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/PatternSyntax.cs index efdf403427..c32b04f844 100644 --- a/src/Microsoft.AspNetCore.Rewrite/UrlRewrite/PatternSyntax.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/PatternSyntax.cs @@ -1,7 +1,7 @@ // 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. -namespace Microsoft.AspNetCore.Rewrite.UrlRewrite +namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite { public enum PatternSyntax { diff --git a/src/Microsoft.AspNetCore.Rewrite/UrlRewrite/RedirectType.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/RedirectType.cs similarity index 84% rename from src/Microsoft.AspNetCore.Rewrite/UrlRewrite/RedirectType.cs rename to src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/RedirectType.cs index 5d842c57d4..ce52d9d408 100644 --- a/src/Microsoft.AspNetCore.Rewrite/UrlRewrite/RedirectType.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/RedirectType.cs @@ -1,7 +1,7 @@ // 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. -namespace Microsoft.AspNetCore.Rewrite.UrlRewrite +namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite { public enum RedirectType { diff --git a/src/Microsoft.AspNetCore.Rewrite/UrlRewrite/RewriteTags.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/RewriteTags.cs similarity index 87% rename from src/Microsoft.AspNetCore.Rewrite/UrlRewrite/RewriteTags.cs rename to src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/RewriteTags.cs index 5e4d23242d..16074abfb3 100644 --- a/src/Microsoft.AspNetCore.Rewrite/UrlRewrite/RewriteTags.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/RewriteTags.cs @@ -1,11 +1,10 @@ // 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. -namespace Microsoft.AspNetCore.Rewrite.UrlRewrite +namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite { public static class RewriteTags { - // TODO More strings to be added later once further implementations are added. public const string Rewrite = "rewrite"; public const string GlobalRules = "globalRules"; public const string Rules = "rules"; @@ -27,7 +26,7 @@ namespace Microsoft.AspNetCore.Rewrite.UrlRewrite public const string Input = "input"; public const string Pattern = "pattern"; public const string Type = "type"; - public const string AppendQuery = "appendQuery"; + public const string AppendQuery = "appendQueryString"; public const string LogRewrittenUrl = "logRewrittenUrl"; public const string RedirectType = "redirectType"; } diff --git a/src/Microsoft.AspNetCore.Rewrite/UrlRewrite/ServerVariables.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/ServerVariables.cs similarity index 90% rename from src/Microsoft.AspNetCore.Rewrite/UrlRewrite/ServerVariables.cs rename to src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/ServerVariables.cs index 7ffb9a5da4..2b0fcad556 100644 --- a/src/Microsoft.AspNetCore.Rewrite/UrlRewrite/ServerVariables.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/ServerVariables.cs @@ -2,16 +2,13 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; -using System.Globalization; -using System.Text.RegularExpressions; -using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Rewrite.UrlRewrite.PatternSegments; +using Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite.PatternSegments; using Microsoft.Net.Http.Headers; -namespace Microsoft.AspNetCore.Rewrite.UrlRewrite +namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite { public static class ServerVariables - { + { public static PatternSegment FindServerVariable(string serverVariable) { switch(serverVariable) @@ -53,6 +50,8 @@ namespace Microsoft.AspNetCore.Rewrite.UrlRewrite throw new NotImplementedException(); case "REMOTE_PORT": return new RemotePortSegment(); + case "REQUEST_FILENAME": + return new RequestFileNameSegment(); default: throw new FormatException("Unrecognized server variable."); } diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/UrlAction.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/UrlAction.cs new file mode 100644 index 0000000000..404561b25b --- /dev/null +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/UrlAction.cs @@ -0,0 +1,14 @@ +// 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 Microsoft.AspNetCore.Http; + +namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite +{ + public abstract class UrlAction + { + public Pattern Url { get; set; } + + public abstract RuleResult ApplyAction(HttpContext context, MatchResults ruleMatch, MatchResults condMatch); + } +} diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/UrlActions/RedirectAction.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/UrlActions/RedirectAction.cs new file mode 100644 index 0000000000..a990c346dc --- /dev/null +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/UrlActions/RedirectAction.cs @@ -0,0 +1,42 @@ +// 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 Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Rewrite.Internal; +using Microsoft.Net.Http.Headers; + +namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite.UrlActions +{ + public class RedirectAction : UrlAction + { + public int StatusCode { get; } + public RedirectAction(int statusCode, Pattern pattern) + { + StatusCode = statusCode; + Url = pattern; + } + + public override RuleResult ApplyAction(HttpContext context, MatchResults ruleMatch, MatchResults condMatch) + { + + var pattern = Url.Evaluate(context, ruleMatch, condMatch); + context.Response.StatusCode = StatusCode; + + // url can either contain the full url or the path and query + // always add to location header. + // TODO check for false positives + var split = pattern.IndexOf('?'); + if (split >= 0) + { + var query = context.Request.QueryString.Add(new QueryString(pattern.Substring(split))); + // not using the response.redirect here because status codes may be 301, 302, 307, 308 + context.Response.Headers[HeaderNames.Location] = pattern.Substring(0, split) + query; + } + else + { + context.Response.Headers[HeaderNames.Location] = pattern; + } + return RuleResult.ResponseComplete; + } + } +} diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/UrlActions/RedirectClearQueryAction.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/UrlActions/RedirectClearQueryAction.cs new file mode 100644 index 0000000000..a6439811c5 --- /dev/null +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/UrlActions/RedirectClearQueryAction.cs @@ -0,0 +1,29 @@ +// 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 Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Rewrite.Internal; +using Microsoft.Net.Http.Headers; + +namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite.UrlActions +{ + public class RedirectClearQueryAction : UrlAction + { + public int StatusCode { get; } + public RedirectClearQueryAction(int statusCode, Pattern pattern) + { + StatusCode = statusCode; + Url = pattern; + } + + public override RuleResult ApplyAction(HttpContext context, MatchResults ruleMatch, MatchResults condMatch) + { + var pattern = Url.Evaluate(context, ruleMatch, condMatch); + context.Response.StatusCode = StatusCode; + + // we are clearing the query, so just put the pattern in the location header + context.Response.Headers[HeaderNames.Location] = pattern; + return RuleResult.ResponseComplete; + } + } +} diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/UrlActions/RewriteAction.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/UrlActions/RewriteAction.cs new file mode 100644 index 0000000000..9c7c463b82 --- /dev/null +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/UrlActions/RewriteAction.cs @@ -0,0 +1,60 @@ +// 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 Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Http.Extensions; + +namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite.UrlActions +{ + public class RewriteAction : UrlAction + { + public RuleTerminiation Result { get; } + public bool ClearQuery { get; } + + public RewriteAction(RuleTerminiation result, Pattern pattern, bool clearQuery) + { + Result = result; + Url = pattern; + ClearQuery = clearQuery; + } + + public override RuleResult ApplyAction(HttpContext context, MatchResults ruleMatch, MatchResults condMatch) + { + var pattern = Url.Evaluate(context, ruleMatch, condMatch); + + if (ClearQuery) + { + context.Request.QueryString = new QueryString(); + } + // TODO PERF, substrings, object creation, etc. + if (pattern.IndexOf("://") >= 0) + { + string scheme = null; + var host = new HostString(); + var path = new PathString(); + var query = new QueryString(); + var fragment = new FragmentString(); + UriHelper.FromAbsolute(pattern, out scheme, out host, out path, out query, out fragment); + + context.Request.Scheme = scheme; + context.Request.Host = host; + context.Request.Path = path; + context.Request.QueryString = query.Add(context.Request.QueryString); + } + else + { + var split = pattern.IndexOf('?'); + if (split >= 0) + { + context.Request.Path = new PathString("/" + pattern.Substring(0, split)); + context.Request.QueryString = context.Request.QueryString.Add(new QueryString(pattern.Substring(split))); + } + else + { + context.Request.Path = new PathString("/" + pattern); + } + } + return new RuleResult { Result = Result }; + } + } +} diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/UrlActions/VoidAction.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/UrlActions/VoidAction.cs new file mode 100644 index 0000000000..5098a06ee6 --- /dev/null +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/UrlActions/VoidAction.cs @@ -0,0 +1,17 @@ +// 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 Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Rewrite.Internal; + +namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite.UrlActions +{ + public class VoidAction : UrlAction + { + // Explicitly say that nothing happens + public override RuleResult ApplyAction(HttpContext context, MatchResults ruleMatch, MatchResults condMatch) + { + return RuleResult.Continue; + } + } +} diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/UrlMatch.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/UrlMatch.cs new file mode 100644 index 0000000000..5cd97d9c94 --- /dev/null +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/UrlMatch.cs @@ -0,0 +1,11 @@ +// 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. + +namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite +{ + public abstract class UrlMatch + { + public bool Negate { get; set; } + public abstract MatchResults Evaluate(string input, RewriteContext context); + } +} diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/UrlMatches/ExactMatch.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/UrlMatches/ExactMatch.cs new file mode 100644 index 0000000000..a42fe3e6a1 --- /dev/null +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/UrlMatches/ExactMatch.cs @@ -0,0 +1,24 @@ +// 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. + +namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite.UrlMatches +{ + public class ExactMatch : UrlMatch + { + public bool IgnoreCase { get; } + public string StringMatch { get; } + + public ExactMatch(bool ignoreCase, string input, bool negate) + { + IgnoreCase = ignoreCase; + StringMatch = input; + Negate = negate; + } + + public override MatchResults Evaluate(string pattern, RewriteContext context) + { + var pathMatch = string.Compare(pattern, StringMatch, IgnoreCase); + return new MatchResults { Success = ((pathMatch == 0) != Negate) }; + } + } +} diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/UrlMatches/IsDirectoryMatch.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/UrlMatches/IsDirectoryMatch.cs new file mode 100644 index 0000000000..9c1068ada0 --- /dev/null +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/UrlMatches/IsDirectoryMatch.cs @@ -0,0 +1,19 @@ +// 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. + +namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite.UrlMatches +{ + public class IsDirectoryMatch : UrlMatch + { + public IsDirectoryMatch( bool negate) + { + Negate = negate; + } + + public override MatchResults Evaluate(string pattern, RewriteContext context) + { + var res = context.FileProvider.GetFileInfo(pattern).IsDirectory; + return new MatchResults { Success = (res != Negate) }; + } + } +} diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/UrlMatches/IsFileMatch.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/UrlMatches/IsFileMatch.cs new file mode 100644 index 0000000000..ebce79b655 --- /dev/null +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/UrlMatches/IsFileMatch.cs @@ -0,0 +1,19 @@ +// 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. + +namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite.UrlMatches +{ + public class IsFileMatch : UrlMatch + { + public IsFileMatch(bool negate) + { + Negate = negate; + } + + public override MatchResults Evaluate(string pattern, RewriteContext context) + { + var res = context.FileProvider.GetFileInfo(pattern).Exists; + return new MatchResults { Success = (res != Negate) }; + } + } +} diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/UrlMatches/RegexMatch.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/UrlMatches/RegexMatch.cs new file mode 100644 index 0000000000..a1859a9370 --- /dev/null +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/UrlMatches/RegexMatch.cs @@ -0,0 +1,27 @@ +// 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; +using System.Text.RegularExpressions; + +namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite.UrlMatches +{ + public class RegexMatch : UrlMatch + { + private static readonly TimeSpan RegexTimeout = TimeSpan.FromMilliseconds(1); + + public Regex Match { get; } + + public RegexMatch(Regex match, bool negate) + { + Match = match; + Negate = negate; + } + + public override MatchResults Evaluate(string pattern, RewriteContext context) + { + var res = Match.Match(pattern); + return new MatchResults { BackReference = res.Groups, Success = (res.Success != Negate)}; + } + } +} diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/UrlRewriteFileParser.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/UrlRewriteFileParser.cs new file mode 100644 index 0000000000..289d9567e9 --- /dev/null +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/UrlRewriteFileParser.cs @@ -0,0 +1,316 @@ +// 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; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text.RegularExpressions; +using System.Xml.Linq; +using Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite.UrlActions; +using Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite.UrlMatches; + +namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite +{ + public static class UrlRewriteFileParser + { + private static readonly TimeSpan RegexTimeout = TimeSpan.FromMilliseconds(1); + + public static List Parse(TextReader reader) + { + var temp = XDocument.Load(reader); + var xmlRoot = temp.Descendants(RewriteTags.Rewrite).FirstOrDefault(); + + if (xmlRoot != null) + { + var result = new List(); + // TODO Global rules are currently not treated differently than normal rules, fix. + // See: https://github.com/aspnet/BasicMiddleware/issues/59 + ParseRules(xmlRoot.Descendants(RewriteTags.GlobalRules).FirstOrDefault(), result, isGlobalRule: true); + ParseRules(xmlRoot.Descendants(RewriteTags.Rules).FirstOrDefault(), result, isGlobalRule: false); + return result; + } + return null; + } + + private static void ParseRules(XElement rules, List result, bool isGlobalRule) + { + if (rules == null) + { + return; + } + + foreach (var rule in rules.Elements(RewriteTags.Rule)) + { + var res = new UrlRewriteRule(); + SetRuleAttributes(rule, res); + CreateUrlAction(rule.Element(RewriteTags.Action), res, isGlobalRule); + if (res.Enabled) + { + result.Add(res); + } + } + } + + private static void SetRuleAttributes(XElement rule, UrlRewriteRule res) + { + + res.Name = rule.Attribute(RewriteTags.Name)?.Value; + + bool enabled; + if (bool.TryParse(rule.Attribute(RewriteTags.Enabled)?.Value, out enabled)) + { + res.Enabled = enabled; + } + + PatternSyntax patternSyntax; + if (Enum.TryParse(rule.Attribute(RewriteTags.PatternSyntax)?.Value, out patternSyntax)) + { + res.PatternSyntax = patternSyntax; + } + + bool stopProcessing; + if (bool.TryParse(rule.Attribute(RewriteTags.StopProcessing)?.Value, out stopProcessing)) + { + res.StopProcessing = stopProcessing; + } + + CreateMatch(rule.Element(RewriteTags.Match), res); + CreateConditions(rule.Element(RewriteTags.Conditions), res); + } + + private static void CreateMatch(XElement match, UrlRewriteRule res) + { + if (match == null) + { + throw new FormatException("Rules must have an associated match."); + } + + var matchRes = new ParsedUrlMatch(); + + bool parBool; + if (bool.TryParse(match.Attribute(RewriteTags.IgnoreCase)?.Value, out parBool)) + { + matchRes.IgnoreCase = parBool; + } + + if (bool.TryParse(match.Attribute(RewriteTags.Negate)?.Value, out parBool)) + { + matchRes.Negate = parBool; + } + + var parsedInputString = match.Attribute(RewriteTags.Url)?.Value; + + switch (res.PatternSyntax) + { + case PatternSyntax.ECMAScript: + { + if (matchRes.IgnoreCase) + { + var regex = new Regex(parsedInputString, RegexOptions.Compiled | RegexOptions.IgnoreCase, RegexTimeout); + res.InitialMatch = new RegexMatch(regex, matchRes.Negate); + } + else + { + var regex = new Regex(parsedInputString, RegexOptions.Compiled, RegexTimeout); + res.InitialMatch = new RegexMatch(regex, matchRes.Negate); + } + } + break; + case PatternSyntax.WildCard: + throw new NotImplementedException("Wildcard syntax is not supported."); + case PatternSyntax.ExactMatch: + res.InitialMatch = new ExactMatch(matchRes.IgnoreCase, parsedInputString, matchRes.Negate); + break; + } + } + + + private static void CreateConditions(XElement conditions, UrlRewriteRule res) + { + // This is to avoid nullptr exception on referencing conditions. + res.Conditions = new Conditions(); + if (conditions == null) + { + return; + } + + LogicalGrouping grouping; + if (Enum.TryParse(conditions.Attribute(RewriteTags.MatchType)?.Value, out grouping)) + { + res.Conditions.MatchType = grouping; + } + + bool parBool; + if (bool.TryParse(conditions.Attribute(RewriteTags.TrackingAllCaptures)?.Value, out parBool)) + { + res.Conditions.TrackingAllCaptures = parBool; + } + + foreach (var cond in conditions.Elements(RewriteTags.Add)) + { + CreateCondition(cond, res); + } + } + + private static void CreateCondition(XElement condition, UrlRewriteRule res) + { + + var parsedCondRes = new ParsedCondition(); + + bool parBool; + if (bool.TryParse(condition.Attribute(RewriteTags.IgnoreCase)?.Value, out parBool)) + { + parsedCondRes.IgnoreCase = parBool; + } + + if (bool.TryParse(condition.Attribute(RewriteTags.Negate)?.Value, out parBool)) + { + parsedCondRes.Negate = parBool; + } + + MatchType matchType; + if (Enum.TryParse(condition.Attribute(RewriteTags.MatchType)?.Value, out matchType)) + { + parsedCondRes.MatchType = matchType; + } + + var parsedString = condition.Attribute(RewriteTags.Input)?.Value; + if (parsedString == null) + { + throw new FormatException("Null input for condition"); + } + + var input = InputParser.ParseInputString(parsedString); + + switch (res.PatternSyntax) + { + case PatternSyntax.ECMAScript: + { + switch (parsedCondRes.MatchType) + { + case MatchType.Pattern: + { + parsedString = condition.Attribute(RewriteTags.Pattern)?.Value; + if (parsedString == null) + { + throw new FormatException("Pattern match does not have an associated pattern attribute in condition."); + } + Regex regex = null; + + if (parsedCondRes.IgnoreCase) + { + regex = new Regex(parsedString, RegexOptions.Compiled | RegexOptions.IgnoreCase, RegexTimeout); + } + else + { + regex = new Regex(parsedString, RegexOptions.Compiled, RegexTimeout); + } + + res.Conditions.ConditionList.Add(new Condition { Input = input, Match = new RegexMatch(regex, parsedCondRes.Negate) }); + } + break; + case MatchType.IsDirectory: + { + res.Conditions.ConditionList.Add(new Condition { Input = input, Match = new IsDirectoryMatch(parsedCondRes.Negate) }); + } + break; + case MatchType.IsFile: + { + res.Conditions.ConditionList.Add(new Condition { Input = input, Match = new IsFileMatch(parsedCondRes.Negate) }); + } + break; + default: + throw new FormatException("Unrecognized matchType."); + } + + } + break; + case PatternSyntax.WildCard: + throw new NotImplementedException("Wildcard syntax is not supported."); + case PatternSyntax.ExactMatch: + parsedString = condition.Attribute(RewriteTags.Pattern)?.Value; + if (parsedString == null) + { + throw new FormatException("Pattern match does not have an associated pattern attribute in condition."); + } + res.Conditions.ConditionList.Add(new Condition { Input = input, Match = new ExactMatch(parsedCondRes.IgnoreCase, parsedString, parsedCondRes.Negate) }); + break; + default: + throw new FormatException("Unrecognized pattern syntax."); + } + } + + private static void CreateUrlAction(XElement urlAction, UrlRewriteRule res, bool globalRule) + { + if (urlAction == null) + { + throw new FormatException("Action is a required element of a rule."); + } + + var actionRes = new ParsedUrlAction(); + + ActionType actionType; + if (Enum.TryParse(urlAction.Attribute(RewriteTags.Type)?.Value, out actionType)) + { + actionRes.Type = actionType; + } + + bool parseBool; + if (bool.TryParse(urlAction.Attribute(RewriteTags.AppendQuery)?.Value, out parseBool)) + { + actionRes.AppendQueryString = parseBool; + } + + if (bool.TryParse(urlAction.Attribute(RewriteTags.LogRewrittenUrl)?.Value, out parseBool)) + { + actionRes.LogRewrittenUrl = parseBool; + } + + RedirectType redirectType; + if (Enum.TryParse(urlAction.Attribute(RewriteTags.RedirectType)?.Value, out redirectType)) + { + actionRes.RedirectType = redirectType; + } + + actionRes.Url = InputParser.ParseInputString(urlAction.Attribute(RewriteTags.Url)?.Value); + + CreateUrlActionFromParsedAction(actionRes, globalRule, res); + } + + public static void CreateUrlActionFromParsedAction(ParsedUrlAction actionRes, bool globalRule, UrlRewriteRule res) + { + switch (actionRes.Type) + { + case ActionType.None: + res.Action = new VoidAction(); + break; + case ActionType.Rewrite: + if (actionRes.AppendQueryString) + { + res.Action = new RewriteAction(res.StopProcessing ? RuleTerminiation.StopRules : RuleTerminiation.Continue, actionRes.Url, clearQuery: false); + } + else + { + res.Action = new RewriteAction(res.StopProcessing ? RuleTerminiation.StopRules : RuleTerminiation.Continue, actionRes.Url, clearQuery: true); + } + break; + case ActionType.Redirect: + if (actionRes.AppendQueryString) + { + res.Action = new RedirectAction((int)actionRes.RedirectType, actionRes.Url); + } + else + { + res.Action = new RedirectClearQueryAction((int)actionRes.RedirectType, actionRes.Url); + } + break; + case ActionType.AbortRequest: + throw new FormatException("Abort requests are not supported."); + case ActionType.CustomResponse: + // TODO + throw new FormatException("Custom Responses are not supported"); + } + } + } +} \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewriteRule.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewriteRule.cs new file mode 100644 index 0000000000..9bd9c7e155 --- /dev/null +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewriteRule.cs @@ -0,0 +1,41 @@ +// 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. + +namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite +{ + public class UrlRewriteRule : Rule + { + public string Name { get; set; } + public bool Enabled { get; set; } = true; + public PatternSyntax PatternSyntax { get; set; } + public bool StopProcessing { get; set; } + public UrlMatch InitialMatch { get; set; } + public Conditions Conditions { get; set; } + public UrlAction Action { get; set; } + + public override RuleResult ApplyRule(RewriteContext context) + { + if (!Enabled) + { + return RuleResult.Continue; + } + // Due to the path string always having a leading slash, + // remove it from the path before regex comparison + var initMatchRes = InitialMatch.Evaluate(context.HttpContext.Request.Path.ToString().Substring(1), context); + + if (!initMatchRes.Success) + { + return RuleResult.Continue; + } + + var condMatchRes = Conditions.Evaluate(context, initMatchRes); + if (!condMatchRes.Success) + { + return RuleResult.Continue; + } + + // at this point we know the rule passed, evaluate the replacement. + return Action.ApplyAction(context.HttpContext, initMatchRes, condMatchRes); + } + } +} \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Rewrite/Microsoft.AspNetCore.Rewrite.xproj b/src/Microsoft.AspNetCore.Rewrite/Microsoft.AspNetCore.Rewrite.xproj index fbaad5c7ae..08f543fc53 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Microsoft.AspNetCore.Rewrite.xproj +++ b/src/Microsoft.AspNetCore.Rewrite/Microsoft.AspNetCore.Rewrite.xproj @@ -5,7 +5,7 @@ $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - + 0e7ca1a7-1dc3-4ce6-b9c7-1688fe1410f1 Microsoft.AspNetCore.Rewrite @@ -17,5 +17,5 @@ 2.0 - + diff --git a/src/Microsoft.AspNetCore.Rewrite/ModRewrite/ModRewriteExtensions.cs b/src/Microsoft.AspNetCore.Rewrite/ModRewriteExtensions.cs similarity index 60% rename from src/Microsoft.AspNetCore.Rewrite/ModRewrite/ModRewriteExtensions.cs rename to src/Microsoft.AspNetCore.Rewrite/ModRewriteExtensions.cs index a5c4986e53..c8af9432cc 100644 --- a/src/Microsoft.AspNetCore.Rewrite/ModRewrite/ModRewriteExtensions.cs +++ b/src/Microsoft.AspNetCore.Rewrite/ModRewriteExtensions.cs @@ -4,7 +4,7 @@ using System; using System.IO; using Microsoft.AspNetCore.Hosting; -using Microsoft.AspNetCore.Rewrite.ModRewrite; +using Microsoft.AspNetCore.Rewrite.Internal.ModRewrite; namespace Microsoft.AspNetCore.Rewrite { @@ -16,16 +16,16 @@ namespace Microsoft.AspNetCore.Rewrite /// The UrlRewrite options. /// /// The path to the file containing mod_rewrite rules. - public static UrlRewriteOptions ImportFromModRewrite(this UrlRewriteOptions options, IHostingEnvironment hostingEnv, string filePath) + public static RewriteOptions ImportFromModRewrite(this RewriteOptions options, IHostingEnvironment hostingEnv, string filePath) { if (options == null) { - throw new ArgumentNullException("UrlRewriteOptions is null"); + throw new ArgumentNullException(nameof(options)); } if (hostingEnv == null) { - throw new ArgumentNullException("HostingEnvironment is null"); + throw new ArgumentNullException(nameof(hostingEnv)); } if (string.IsNullOrEmpty(filePath)) @@ -46,36 +46,39 @@ namespace Microsoft.AspNetCore.Rewrite /// /// The UrlRewrite options. /// Text reader containing a stream of mod_rewrite rules. - public static UrlRewriteOptions ImportFromModRewrite(this UrlRewriteOptions options, TextReader reader) + public static RewriteOptions ImportFromModRewrite(this RewriteOptions options, TextReader reader) { + if (options == null) + { + throw new ArgumentNullException(nameof(options)); + } + + if (reader == null) + { + throw new ArgumentNullException(nameof(reader)); + } options.Rules.AddRange(FileParser.Parse(reader)); return options; } /// /// Adds a mod_rewrite rule to the current rules. - /// Additional properties (conditions, flags) for the rule can be added through the action. /// /// The UrlRewrite options. /// The literal string of a mod_rewrite rule: /// "RewriteRule Pattern Substitution [Flags]" - /// Action to perform on the - public static UrlRewriteOptions AddModRewriteRule(this UrlRewriteOptions options, string rule, Action action) + public static RewriteOptions AddModRewriteRule(this RewriteOptions options, string rule) { - var builder = new RuleBuilder(rule); - action(builder); - options.Rules.Add(builder.Build()); - return options; - } + if (options == null) + { + throw new ArgumentNullException(nameof(options)); + } + + if (rule == null) + { + throw new ArgumentNullException(nameof(rule)); + } - /// - /// Adds a mod_rewrite rule to the current rules. - /// - /// The UrlRewrite options. - /// The literal string of a mod_rewrite rule: - /// "RewriteRule Pattern Substitution [Flags]" - public static UrlRewriteOptions AddModRewriteRule(this UrlRewriteOptions options, string rule) - { var builder = new RuleBuilder(rule); options.Rules.Add(builder.Build()); return options; diff --git a/src/Microsoft.AspNetCore.Rewrite/UrlRewriteContext.cs b/src/Microsoft.AspNetCore.Rewrite/RewriteContext.cs similarity index 94% rename from src/Microsoft.AspNetCore.Rewrite/UrlRewriteContext.cs rename to src/Microsoft.AspNetCore.Rewrite/RewriteContext.cs index ab97b358ef..12b1da7a48 100644 --- a/src/Microsoft.AspNetCore.Rewrite/UrlRewriteContext.cs +++ b/src/Microsoft.AspNetCore.Rewrite/RewriteContext.cs @@ -9,7 +9,7 @@ namespace Microsoft.AspNetCore.Rewrite /// /// The UrlRewrite Context contains the HttpContext of the request and the file provider to check conditions. /// - public class UrlRewriteContext + public class RewriteContext { public HttpContext HttpContext { get; set; } public IFileProvider FileProvider { get; set; } diff --git a/src/Microsoft.AspNetCore.Rewrite/RewriteExtensions.cs b/src/Microsoft.AspNetCore.Rewrite/RewriteExtensions.cs new file mode 100644 index 0000000000..50026ddc83 --- /dev/null +++ b/src/Microsoft.AspNetCore.Rewrite/RewriteExtensions.cs @@ -0,0 +1,35 @@ +// 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; +using Microsoft.AspNetCore.Rewrite; + +namespace Microsoft.AspNetCore.Builder +{ + /// + /// Extension methods for the + /// + public static class RewriteExtensions + { + /// + /// Checks if a given Url matches rules and conditions, and modifies the HttpContext on match. + /// + /// + /// Options for urlrewrite. + /// + public static IApplicationBuilder UseRewriter(this IApplicationBuilder app, RewriteOptions options) + { + if (app == null) + { + throw new ArgumentNullException(nameof(app)); + } + + if (options == null) + { + throw new ArgumentNullException(nameof(options)); + } + // put middleware in pipeline + return app.UseMiddleware(options); + } + } +} diff --git a/src/Microsoft.AspNetCore.Rewrite/UrlRewriteMiddleware.cs b/src/Microsoft.AspNetCore.Rewrite/RewriteMiddleware.cs similarity index 85% rename from src/Microsoft.AspNetCore.Rewrite/UrlRewriteMiddleware.cs rename to src/Microsoft.AspNetCore.Rewrite/RewriteMiddleware.cs index deb987d647..01c8b17d0a 100644 --- a/src/Microsoft.AspNetCore.Rewrite/UrlRewriteMiddleware.cs +++ b/src/Microsoft.AspNetCore.Rewrite/RewriteMiddleware.cs @@ -5,7 +5,7 @@ using System; using System.Threading.Tasks; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Rewrite.RuleAbstraction; +using Microsoft.AspNetCore.Rewrite.Internal; using Microsoft.Extensions.FileProviders; namespace Microsoft.AspNetCore.Rewrite @@ -13,19 +13,19 @@ namespace Microsoft.AspNetCore.Rewrite /// /// Represents a middleware that rewrites urls imported from mod_rewrite, UrlRewrite, and code. /// - public class UrlRewriteMiddleware + public class RewriteMiddleware { private readonly RequestDelegate _next; - private readonly UrlRewriteOptions _options; + private readonly RewriteOptions _options; private readonly IFileProvider _fileProvider; /// - /// Creates a new instance of + /// Creates a new instance of /// /// The delegate representing the next middleware in the request pipeline. /// The Hosting Environment. /// The middleware options, containing the rules to apply. - public UrlRewriteMiddleware(RequestDelegate next, IHostingEnvironment hostingEnv, UrlRewriteOptions options) + public RewriteMiddleware(RequestDelegate next, IHostingEnvironment hostingEnv, RewriteOptions options) { if (next == null) { @@ -53,7 +53,7 @@ namespace Microsoft.AspNetCore.Rewrite { throw new ArgumentNullException(nameof(context)); } - var urlContext = new UrlRewriteContext { HttpContext = context, FileProvider = _fileProvider }; + var urlContext = new RewriteContext { HttpContext = context, FileProvider = _fileProvider }; foreach (var rule in _options.Rules) { // Apply the rule diff --git a/src/Microsoft.AspNetCore.Rewrite/UrlRewriteOptions.cs b/src/Microsoft.AspNetCore.Rewrite/RewriteOptions.cs similarity index 79% rename from src/Microsoft.AspNetCore.Rewrite/UrlRewriteOptions.cs rename to src/Microsoft.AspNetCore.Rewrite/RewriteOptions.cs index becea3063e..71eb2fef99 100644 --- a/src/Microsoft.AspNetCore.Rewrite/UrlRewriteOptions.cs +++ b/src/Microsoft.AspNetCore.Rewrite/RewriteOptions.cs @@ -2,15 +2,15 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System.Collections.Generic; -using Microsoft.AspNetCore.Rewrite.RuleAbstraction; +using Microsoft.AspNetCore.Rewrite.Internal; using Microsoft.Extensions.FileProviders; namespace Microsoft.AspNetCore.Rewrite { /// - /// Options for the + /// Options for the /// - public class UrlRewriteOptions + public class RewriteOptions { /// /// The ordered list of rules to apply to the context. diff --git a/src/Microsoft.AspNetCore.Rewrite/RuleAbstraction/RuleTermination.cs b/src/Microsoft.AspNetCore.Rewrite/RuleAbstraction/RuleTermination.cs deleted file mode 100644 index eae0a13ffa..0000000000 --- a/src/Microsoft.AspNetCore.Rewrite/RuleAbstraction/RuleTermination.cs +++ /dev/null @@ -1,14 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; - -namespace Microsoft.AspNetCore.Rewrite.RuleAbstraction -{ - public enum RuleTerminiation - { - Continue, - ResponseComplete, - StopRules - } -} diff --git a/src/Microsoft.AspNetCore.Rewrite/UrlRewrite/Conditions.cs b/src/Microsoft.AspNetCore.Rewrite/UrlRewrite/Conditions.cs deleted file mode 100644 index 0e3ec81df7..0000000000 --- a/src/Microsoft.AspNetCore.Rewrite/UrlRewrite/Conditions.cs +++ /dev/null @@ -1,14 +0,0 @@ -// 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.Collections.Generic; - -namespace Microsoft.AspNetCore.Rewrite.UrlRewrite -{ - public class Conditions - { - public List ConditionList { get; set; } = new List(); - public LogicalGrouping MatchType { get; set; } // default is MatchAll - public bool TrackingAllCaptures { get; set; } - } -} diff --git a/src/Microsoft.AspNetCore.Rewrite/UrlRewrite/InitialMatch.cs b/src/Microsoft.AspNetCore.Rewrite/UrlRewrite/InitialMatch.cs deleted file mode 100644 index bfbdcad006..0000000000 --- a/src/Microsoft.AspNetCore.Rewrite/UrlRewrite/InitialMatch.cs +++ /dev/null @@ -1,14 +0,0 @@ -// 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.Text.RegularExpressions; - -namespace Microsoft.AspNetCore.Rewrite.UrlRewrite -{ - public class InitialMatch - { - public Regex Url { get; set; } // TODO must be a non-empty string, throw in check after parsing? - public bool IgnoreCase { get; set; } = true; - public bool Negate { get; set; } - } -} diff --git a/src/Microsoft.AspNetCore.Rewrite/UrlRewrite/UrlRewriteExtensions.cs b/src/Microsoft.AspNetCore.Rewrite/UrlRewrite/UrlRewriteExtensions.cs deleted file mode 100644 index b958d2ed60..0000000000 --- a/src/Microsoft.AspNetCore.Rewrite/UrlRewrite/UrlRewriteExtensions.cs +++ /dev/null @@ -1,44 +0,0 @@ -// 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; -using System.IO; -using Microsoft.AspNetCore.Hosting; -using Microsoft.AspNetCore.Rewrite.UrlRewrite; - -namespace Microsoft.AspNetCore.Rewrite -{ - public static class UrlRewriteExtensions - { - /// - /// Imports rules from a mod_rewrite file and adds the rules to current rules. - /// - /// The UrlRewrite options. - /// - /// The path to the file containing urlrewrite rules. - public static UrlRewriteOptions ImportFromUrlRewrite(this UrlRewriteOptions options, IHostingEnvironment hostingEnv, string filePath) - { - if (options == null) - { - throw new ArgumentNullException("UrlRewriteOptions is null"); - } - - if (hostingEnv == null) - { - throw new ArgumentNullException("HostingEnvironment is null"); - } - - if (string.IsNullOrEmpty(filePath)) - { - throw new ArgumentException(nameof(filePath)); - } - - var path = Path.Combine(hostingEnv.ContentRootPath, filePath); - using (var stream = File.OpenRead(path)) - { - options.Rules.AddRange(UrlRewriteFileParser.Parse(new StreamReader(stream))); - }; - return options; - } - } -} diff --git a/src/Microsoft.AspNetCore.Rewrite/UrlRewrite/UrlRewriteFileParser.cs b/src/Microsoft.AspNetCore.Rewrite/UrlRewrite/UrlRewriteFileParser.cs deleted file mode 100644 index 454555c79e..0000000000 --- a/src/Microsoft.AspNetCore.Rewrite/UrlRewrite/UrlRewriteFileParser.cs +++ /dev/null @@ -1,228 +0,0 @@ -// 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; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Text.RegularExpressions; -using System.Xml.Linq; - -namespace Microsoft.AspNetCore.Rewrite.UrlRewrite -{ - // TODO rename - public static class UrlRewriteFileParser - { - private static readonly TimeSpan RegexTimeout = TimeSpan.FromMilliseconds(1); - public static List Parse(TextReader reader) - { - var temp = XDocument.Load(reader); - var xmlRoot = temp.Descendants(RewriteTags.Rewrite); - var rules = new List(); - - if (xmlRoot != null) - { - // there is a valid rewrite block, go through each rule and process - GetGlobalRules(xmlRoot.Descendants(RewriteTags.GlobalRules), rules); - GetRules(xmlRoot.Descendants(RewriteTags.Rules), rules); - } - return rules; - } - - private static void GetGlobalRules(IEnumerable globalRules, List result) - { - foreach (var rule in globalRules.Elements(RewriteTags.Rule) ?? Enumerable.Empty()) - { - var res = new UrlRewriteRule(); - SetRuleAttributes(rule, res); - // TODO handle full url with global rules - may or may not support - res.Action = CreateUrlAction(rule.Element(RewriteTags.Action)); - result.Add(res); - } - } - - private static void GetRules(IEnumerable rules, List result) - { - // TODO Better null check? - foreach (var rule in rules.Elements(RewriteTags.Rule) ?? Enumerable.Empty()) - { - var res = new UrlRewriteRule(); - SetRuleAttributes(rule, res); - res.Action = CreateUrlAction(rule.Element(RewriteTags.Action)); - result.Add(res); - } - } - - private static void SetRuleAttributes(XElement rule, UrlRewriteRule res) - { - if (rule == null) - { - return; - } - - res.Name = rule.Attribute(RewriteTags.Name)?.Value; - - bool enabled; - if (bool.TryParse(rule.Attribute(RewriteTags.Enabled)?.Value, out enabled)) - { - res.Enabled = enabled; - } - - PatternSyntax patternSyntax; - if (Enum.TryParse(rule.Attribute(RewriteTags.PatternSyntax)?.Value, out patternSyntax)) - { - res.PatternSyntax = patternSyntax; - } - - bool stopProcessing; - if (bool.TryParse(rule.Attribute(RewriteTags.StopProcessing)?.Value, out stopProcessing)) - { - res.StopProcessing = stopProcessing; - } - - res.Match = CreateMatch(rule.Element(RewriteTags.Match)); - res.Conditions = CreateConditions(rule.Element(RewriteTags.Conditions)); - } - - private static InitialMatch CreateMatch(XElement match) - { - if (match == null) - { - return null; - } - - var matchRes = new InitialMatch(); - - bool parBool; - if (bool.TryParse(match.Attribute(RewriteTags.IgnoreCase)?.Value, out parBool)) - { - matchRes.IgnoreCase = parBool; - } - - if (bool.TryParse(match.Attribute(RewriteTags.Negate)?.Value, out parBool)) - { - matchRes.Negate = parBool; - } - - var parsedInputString = match.Attribute(RewriteTags.Url)?.Value; - - if (matchRes.IgnoreCase) - { - matchRes.Url = new Regex(parsedInputString, RegexOptions.IgnoreCase | RegexOptions.Compiled, RegexTimeout); - } - else - { - matchRes.Url = new Regex(parsedInputString, RegexOptions.Compiled, RegexTimeout); - } - return matchRes; - } - - - private static Conditions CreateConditions(XElement conditions) - { - var condRes = new Conditions(); - if (conditions == null) - { - return condRes; // TODO make sure no null exception on Conditions - } - - LogicalGrouping grouping; - if (Enum.TryParse(conditions.Attribute(RewriteTags.MatchType)?.Value, out grouping)) - { - condRes.MatchType = grouping; - } - - bool parBool; - if (bool.TryParse(conditions.Attribute(RewriteTags.TrackingAllCaptures)?.Value, out parBool)) - { - condRes.TrackingAllCaptures = parBool; - } - - foreach (var cond in conditions.Elements(RewriteTags.Add)) - { - condRes.ConditionList.Add(CreateCondition(cond)); - } - return condRes; - } - - private static Condition CreateCondition(XElement condition) - { - if (condition == null) - { - return null; - } - - var condRes = new Condition(); - - bool parBool; - if (bool.TryParse(condition.Attribute(RewriteTags.IgnoreCase)?.Value, out parBool)) - { - condRes.IgnoreCase = parBool; - } - - if (bool.TryParse(condition.Attribute(RewriteTags.Negate)?.Value, out parBool)) - { - condRes.Negate = parBool; - } - - MatchType matchType; - if (Enum.TryParse(condition.Attribute(RewriteTags.MatchPattern)?.Value, out matchType)) - { - condRes.MatchType = matchType; - } - - var parsedInputString = condition.Attribute(RewriteTags.Input)?.Value; - if (parsedInputString != null) - { - condRes.Input = InputParser.ParseInputString(parsedInputString); - } - - parsedInputString = condition.Attribute(RewriteTags.Pattern)?.Value; - - if (condRes.IgnoreCase) - { - condRes.MatchPattern = new Regex(parsedInputString, RegexOptions.IgnoreCase | RegexOptions.Compiled, RegexTimeout); - } - else - { - condRes.MatchPattern = new Regex(parsedInputString, RegexOptions.Compiled, RegexTimeout); - } - return condRes; - } - - private static UrlAction CreateUrlAction(XElement urlAction) - { - if (urlAction == null) - { - throw new FormatException("Action is a required element of a rule."); - } - var actionRes = new UrlAction(); - - ActionType actionType; - if (Enum.TryParse(urlAction.Attribute(RewriteTags.Type)?.Value, out actionType)) - { - actionRes.Type = actionType; - } - - bool parseBool; - if (bool.TryParse(urlAction.Attribute(RewriteTags.AppendQuery)?.Value, out parseBool)) - { - actionRes.AppendQueryString = parseBool; - } - - if (bool.TryParse(urlAction.Attribute(RewriteTags.LogRewrittenUrl)?.Value, out parseBool)) - { - actionRes.LogRewrittenUrl = parseBool; - } - - RedirectType redirectType; - if (Enum.TryParse(urlAction.Attribute(RewriteTags.RedirectType)?.Value, out redirectType)) - { - actionRes.RedirectType = redirectType; - } - - actionRes.Url = InputParser.ParseInputString(urlAction.Attribute(RewriteTags.Url)?.Value); - return actionRes; - } - } -} diff --git a/src/Microsoft.AspNetCore.Rewrite/UrlRewrite/UrlRewriteRule.cs b/src/Microsoft.AspNetCore.Rewrite/UrlRewrite/UrlRewriteRule.cs deleted file mode 100644 index db33219ed0..0000000000 --- a/src/Microsoft.AspNetCore.Rewrite/UrlRewrite/UrlRewriteRule.cs +++ /dev/null @@ -1,25 +0,0 @@ -// 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; -using Microsoft.AspNetCore.Rewrite.RuleAbstraction; - -namespace Microsoft.AspNetCore.Rewrite.UrlRewrite -{ - public class UrlRewriteRule : Rule - { - public string Name { get; set; } - public bool Enabled { get; set; } = true; - public PatternSyntax PatternSyntax { get; set; } - public bool StopProcessing { get; set; } - public InitialMatch Match { get; set; } - public Conditions Conditions { get; set; } - public UrlAction Action { get; set; } - - public override RuleResult ApplyRule(UrlRewriteContext context) - { - // TODO - throw new NotImplementedException(); - } - } -} diff --git a/src/Microsoft.AspNetCore.Rewrite/UrlRewriteExtensions.cs b/src/Microsoft.AspNetCore.Rewrite/UrlRewriteExtensions.cs index 2c0942f110..944426b055 100644 --- a/src/Microsoft.AspNetCore.Rewrite/UrlRewriteExtensions.cs +++ b/src/Microsoft.AspNetCore.Rewrite/UrlRewriteExtensions.cs @@ -2,34 +2,67 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; -using Microsoft.AspNetCore.Rewrite; +using System.IO; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite; -namespace Microsoft.AspNetCore.Builder +namespace Microsoft.AspNetCore.Rewrite { - /// - /// Extension methods for the - /// public static class UrlRewriteExtensions { /// - /// Checks if a given Url matches rules and conditions, and modifies the HttpContext on match. + /// Imports rules from a mod_rewrite file and adds the rules to current rules. /// - /// - /// Options for urlrewrite. - /// - public static IApplicationBuilder UseRewriter(this IApplicationBuilder app, UrlRewriteOptions options) + /// The UrlRewrite options. + /// + /// The path to the file containing urlrewrite rules. + public static RewriteOptions ImportFromUrlRewrite(this RewriteOptions options, IHostingEnvironment hostingEnv, string filePath) { - if (app == null) - { - throw new ArgumentNullException(nameof(app)); - } - if (options == null) { throw new ArgumentNullException(nameof(options)); } - // put middleware in pipeline - return app.UseMiddleware(options); + + if (hostingEnv == null) + { + throw new ArgumentNullException(nameof(hostingEnv)); + } + + if (string.IsNullOrEmpty(filePath)) + { + throw new ArgumentException(nameof(filePath)); + } + + var path = Path.Combine(hostingEnv.ContentRootPath, filePath); + using (var stream = File.OpenRead(path)) + { + options.Rules.AddRange(UrlRewriteFileParser.Parse(new StreamReader(stream))); + }; + return options; + } + + /// + /// Imports rules from a mod_rewrite file and adds the rules to current rules. + /// + /// The UrlRewrite options. + /// The text reader stream. + public static RewriteOptions ImportFromUrlRewrite(this RewriteOptions options, TextReader stream) + { + if (options == null) + { + throw new ArgumentNullException(nameof(options)); + } + + if (stream == null) + { + throw new ArgumentException(nameof(stream)); + } + + using (stream) + { + options.Rules.AddRange(UrlRewriteFileParser.Parse(stream)); + }; + return options; } } } diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/ConditionActionTest.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/ModRewrite/ConditionActionTest.cs similarity index 97% rename from test/Microsoft.AspNetCore.Rewrite.Tests/ConditionActionTest.cs rename to test/Microsoft.AspNetCore.Rewrite.Tests/ModRewrite/ConditionActionTest.cs index 7f1a37f1b4..d49d9ef695 100644 --- a/test/Microsoft.AspNetCore.Rewrite.Tests/ConditionActionTest.cs +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/ModRewrite/ConditionActionTest.cs @@ -1,10 +1,10 @@ // 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 Microsoft.AspNetCore.Rewrite.ModRewrite; +using Microsoft.AspNetCore.Rewrite.Internal.ModRewrite; using Xunit; -namespace Microsoft.AspNetCore.Rewrite +namespace Microsoft.AspNetCore.Rewrite.Tests.ModRewrite { public class ConditionActionTest { diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/FlagParserTest.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/ModRewrite/FlagParserTest.cs similarity index 95% rename from test/Microsoft.AspNetCore.Rewrite.Tests/FlagParserTest.cs rename to test/Microsoft.AspNetCore.Rewrite.Tests/ModRewrite/FlagParserTest.cs index dce8be83a0..572f376f2f 100644 --- a/test/Microsoft.AspNetCore.Rewrite.Tests/FlagParserTest.cs +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/ModRewrite/FlagParserTest.cs @@ -3,10 +3,10 @@ using System.Collections.Generic; using System.Linq; -using Microsoft.AspNetCore.Rewrite.ModRewrite; +using Microsoft.AspNetCore.Rewrite.Internal.ModRewrite; using Xunit; -namespace Microsoft.AspNetCore.Rewrite +namespace Microsoft.AspNetCore.Rewrite.Tests.ModRewrite { public class FlagParserTest { diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/ModRewriteConditionBuilderTest.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/ModRewrite/ModRewriteConditionBuilderTest.cs similarity index 92% rename from test/Microsoft.AspNetCore.Rewrite.Tests/ModRewriteConditionBuilderTest.cs rename to test/Microsoft.AspNetCore.Rewrite.Tests/ModRewrite/ModRewriteConditionBuilderTest.cs index 3436bcaef3..05f610046a 100644 --- a/test/Microsoft.AspNetCore.Rewrite.Tests/ModRewriteConditionBuilderTest.cs +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/ModRewrite/ModRewriteConditionBuilderTest.cs @@ -1,11 +1,11 @@ // 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 Microsoft.AspNetCore.Rewrite.ModRewrite; -using Microsoft.AspNetCore.Rewrite.Operands; +using Microsoft.AspNetCore.Rewrite.Internal.ModRewrite; +using Microsoft.AspNetCore.Rewrite.Internal.ModRewrite.Operands; using Xunit; -namespace RewriteTest +namespace Microsoft.AspNetCore.Rewrite.Tests.ModRewrite { // This file tests an input of a list of tokens and verifies that the appropriate condition is obtained public class ModRewriteConditionBuilderTest diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/ModRewriteFlagTest.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/ModRewrite/ModRewriteFlagTest.cs similarity index 84% rename from test/Microsoft.AspNetCore.Rewrite.Tests/ModRewriteFlagTest.cs rename to test/Microsoft.AspNetCore.Rewrite.Tests/ModRewrite/ModRewriteFlagTest.cs index e9938eff0c..ddc7329b37 100644 --- a/test/Microsoft.AspNetCore.Rewrite.Tests/ModRewriteFlagTest.cs +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/ModRewrite/ModRewriteFlagTest.cs @@ -3,12 +3,12 @@ using System.Text.RegularExpressions; using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Rewrite.ModRewrite; -using Microsoft.AspNetCore.Rewrite.Operands; -using Microsoft.AspNetCore.Rewrite.RuleAbstraction; +using Microsoft.AspNetCore.Rewrite.Internal.ModRewrite; +using Microsoft.AspNetCore.Rewrite.Internal.ModRewrite.Operands; +using Microsoft.AspNetCore.Rewrite.Internal; using Xunit; -namespace Microsoft.AspNetCore.Rewrite +namespace Microsoft.AspNetCore.Rewrite.Tests.ModRewrite { public class ModRewriteFlagTest { @@ -16,7 +16,7 @@ namespace Microsoft.AspNetCore.Rewrite [Fact] public void ModRewriteRule_Check403OnForbiddenFlag() { - var context = new UrlRewriteContext { HttpContext = CreateRequest("/", "/hey/hello") }; + var context = new RewriteContext { HttpContext = CreateRequest("/", "/hey/hello") }; var rule = new ModRewriteRule { InitialRule = new RuleExpression { Operand = new RegexOperand(new Regex("/hey/(.*)")) , Invert = false }, @@ -31,7 +31,7 @@ namespace Microsoft.AspNetCore.Rewrite [Fact] public void ModRewriteRule_Check410OnGoneFlag() { - var context = new UrlRewriteContext { HttpContext = CreateRequest("/", "/hey/hello") }; + var context = new RewriteContext { HttpContext = CreateRequest("/", "/hey/hello") }; var rule = new ModRewriteRule { InitialRule = new RuleExpression { Operand = new RegexOperand(new Regex("/hey/(.*)")), Invert = false }, @@ -46,7 +46,7 @@ namespace Microsoft.AspNetCore.Rewrite [Fact] public void ModRewriteRule_CheckLastFlag() { - var context = new UrlRewriteContext { HttpContext = CreateRequest("/", "/hey/hello") }; + var context = new RewriteContext { HttpContext = CreateRequest("/", "/hey/hello") }; var rule = new ModRewriteRule { InitialRule = new RuleExpression { Operand = new RegexOperand(new Regex("/hey/(.*)")), Invert = false }, @@ -63,7 +63,7 @@ namespace Microsoft.AspNetCore.Rewrite public void ModRewriteRule_CheckRedirectFlag() { // TODO fix this test. - var context = new UrlRewriteContext { HttpContext = CreateRequest("/", "/hey/hello") }; + var context = new RewriteContext { HttpContext = CreateRequest("/", "/hey/hello") }; var rule = new ModRewriteRule { InitialRule = new RuleExpression { Operand = new RegexOperand(new Regex("/hey/(.*)")), Invert = false }, diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/ModRewriteMiddlewareTest.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/ModRewrite/ModRewriteMiddlewareTest.cs similarity index 82% rename from test/Microsoft.AspNetCore.Rewrite.Tests/ModRewriteMiddlewareTest.cs rename to test/Microsoft.AspNetCore.Rewrite.Tests/ModRewrite/ModRewriteMiddlewareTest.cs index 92c6dcb327..90a5d6dba1 100644 --- a/test/Microsoft.AspNetCore.Rewrite.Tests/ModRewriteMiddlewareTest.cs +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/ModRewrite/ModRewriteMiddlewareTest.cs @@ -10,14 +10,14 @@ using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.TestHost; using Xunit; -namespace Microsoft.AspNetCore.Rewrite +namespace Microsoft.AspNetCore.Rewrite.Tests.ModRewrite { public class ModRewriteMiddlewareTest { [Fact] public async Task Invoke_RewritePathWhenMatching() { - var options = new UrlRewriteOptions().AddModRewriteRule("RewriteRule /hey/(.*) /$1 "); + var options = new RewriteOptions().AddModRewriteRule("RewriteRule /hey/(.*) /$1 "); var builder = new WebHostBuilder() .Configure(app => { @@ -34,7 +34,7 @@ namespace Microsoft.AspNetCore.Rewrite [Fact] public async Task Invoke_RewritePathTerminatesOnFirstSuccessOfRule() { - var options = new UrlRewriteOptions().AddModRewriteRule("RewriteRule /hey/(.*) /$1 [L]") + var options = new RewriteOptions().AddModRewriteRule("RewriteRule /hey/(.*) /$1 [L]") .AddModRewriteRule("RewriteRule /hello /what"); var builder = new WebHostBuilder() .Configure(app => @@ -52,7 +52,7 @@ namespace Microsoft.AspNetCore.Rewrite [Fact] public async Task Invoke_RewritePathDoesNotTerminateOnFirstSuccessOfRule() { - var options = new UrlRewriteOptions().AddModRewriteRule("RewriteRule /hey/(.*) /$1") + var options = new RewriteOptions().AddModRewriteRule("RewriteRule /hey/(.*) /$1") .AddModRewriteRule("RewriteRule /hello /what"); var builder = new WebHostBuilder() .Configure(app => @@ -76,7 +76,7 @@ namespace Microsoft.AspNetCore.Rewrite [Fact] public async Task Invoke_ShouldIgnoreComments() { - var options = new UrlRewriteOptions().ImportFromModRewrite(new StringReader("#RewriteRule ^/hey/(.*) /$1 ")); + var options = new RewriteOptions().ImportFromModRewrite(new StringReader("#RewriteRule ^/hey/(.*) /$1 ")); var builder = new WebHostBuilder() .Configure(app => { @@ -95,7 +95,7 @@ namespace Microsoft.AspNetCore.Rewrite [Fact] public async Task Invoke_ShouldRewriteHomepage() { - var options = new UrlRewriteOptions().ImportFromModRewrite(new StringReader(@"RewriteRule ^/$ /homepage.html")); + var options = new RewriteOptions().ImportFromModRewrite(new StringReader(@"RewriteRule ^/$ /homepage.html")); var builder = new WebHostBuilder() .Configure(app => { @@ -112,7 +112,7 @@ namespace Microsoft.AspNetCore.Rewrite [Fact] public async Task Invoke_ShouldIgnorePorts() { - var options = new UrlRewriteOptions().ImportFromModRewrite(new StringReader(@"RewriteRule ^/$ /homepage.html")); + var options = new RewriteOptions().ImportFromModRewrite(new StringReader(@"RewriteRule ^/$ /homepage.html")); var builder = new WebHostBuilder() .Configure(app => { @@ -129,7 +129,7 @@ namespace Microsoft.AspNetCore.Rewrite [Fact] public async Task Invoke_HandleNegatedRewriteRules() { - var options = new UrlRewriteOptions().ImportFromModRewrite(new StringReader(@"RewriteRule !^/$ /homepage.html")); + var options = new RewriteOptions().ImportFromModRewrite(new StringReader(@"RewriteRule !^/$ /homepage.html")); var builder = new WebHostBuilder() .Configure(app => { @@ -146,7 +146,7 @@ namespace Microsoft.AspNetCore.Rewrite [Fact] public async Task Invoke_BackReferencesShouldBeApplied() { - var options = new UrlRewriteOptions().ImportFromModRewrite(new StringReader(@"RewriteRule (.*)\.aspx $1.php")); + var options = new RewriteOptions().ImportFromModRewrite(new StringReader(@"RewriteRule (.*)\.aspx $1.php")); var builder = new WebHostBuilder() .Configure(app => { @@ -169,7 +169,7 @@ namespace Microsoft.AspNetCore.Rewrite [InlineData("http://www.foo.org/homepage.ASPX", @"RewriteRule (.*)\.aspx $1.php [nocase]", "/homepage.php")] public async Task Invoke_ShouldHandleFlagNoCase(string url, string rule, string expected) { - var options = new UrlRewriteOptions().ImportFromModRewrite(new StringReader(rule)); + var options = new RewriteOptions().ImportFromModRewrite(new StringReader(rule)); var builder = new WebHostBuilder() .Configure(app => { @@ -183,28 +183,10 @@ namespace Microsoft.AspNetCore.Rewrite Assert.Equal(response, expected); } - [Fact(Skip="Need to handle escape characters")] - public async Task Invoke_HandleMultipleBackReferences() - { - var options = new UrlRewriteOptions() - .ImportFromModRewrite(new StringReader(@"RewriteRule ^/blog/([0-9]+)-([a-z]+) /blog/index.php?archive=$1-$2")); - var builder = new WebHostBuilder() - .Configure(app => - { - app.UseRewriter(options); - app.Run(context => context.Response.WriteAsync(context.Request.Path)); - }); - var server = new TestServer(builder); - - var response = await server.CreateClient().GetStringAsync("http://www.foo.org/blog/2016-jun"); - - Assert.Equal(response, @"/blog/index.php?archive=2016-jun"); - } - [Fact] public async Task Invoke_CheckFullUrlWithUFlagOnlyPath() { - var options = new UrlRewriteOptions() + var options = new RewriteOptions() .ImportFromModRewrite(new StringReader(@"RewriteRule (.+) http://www.example.com$1/ [U]")); var builder = new WebHostBuilder() .Configure(app => @@ -222,7 +204,7 @@ namespace Microsoft.AspNetCore.Rewrite [Fact] public async Task Invoke_CheckFullUrlWithUFlag() { - var options = new UrlRewriteOptions() + var options = new RewriteOptions() .ImportFromModRewrite(new StringReader(@"RewriteRule (.+) http://www.example.com$1/ [U]")); var builder = new WebHostBuilder() .Configure(app => @@ -240,7 +222,7 @@ namespace Microsoft.AspNetCore.Rewrite [Fact] public async Task Invoke_CheckModFileConditions() { - var options = new UrlRewriteOptions() + var options = new RewriteOptions() .ImportFromModRewrite(new StringReader(@"RewriteRule (.+) http://www.example.com$1/ [U]")); var builder = new WebHostBuilder() .Configure(app => @@ -259,7 +241,7 @@ namespace Microsoft.AspNetCore.Rewrite [InlineData("http://www.example.com/foo/")] public async Task Invoke_EnsureHttps(string input) { - var options = new UrlRewriteOptions() + var options = new RewriteOptions() .ImportFromModRewrite(new StringReader("RewriteCond %{REQUEST_URI} ^foo/ \nRewriteCond %{HTTPS} !on \nRewriteRule ^(.*)$ https://www.example.com$1 [R=301,L,U]")); var builder = new WebHostBuilder() .Configure(app => diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/RewriteTokenizerTest.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/ModRewrite/RewriteTokenizerTest.cs similarity index 91% rename from test/Microsoft.AspNetCore.Rewrite.Tests/RewriteTokenizerTest.cs rename to test/Microsoft.AspNetCore.Rewrite.Tests/ModRewrite/RewriteTokenizerTest.cs index 2961a3bb25..fdcaf6b35d 100644 --- a/test/Microsoft.AspNetCore.Rewrite.Tests/RewriteTokenizerTest.cs +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/ModRewrite/RewriteTokenizerTest.cs @@ -2,10 +2,10 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System.Collections.Generic; -using System.Linq; -using Microsoft.AspNetCore.Rewrite.ModRewrite; +using Microsoft.AspNetCore.Rewrite.Internal.ModRewrite; using Xunit; -namespace Microsoft.AspNetCore.Rewrite + +namespace Microsoft.AspNetCore.Rewrite.Tests.ModRewrite { public class RewriteTokenizerTest { diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/RuleAbstraction/RuleRegexParserTest.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/ModRewrite/RuleRegexParserTest.cs similarity index 69% rename from test/Microsoft.AspNetCore.Rewrite.Tests/RuleAbstraction/RuleRegexParserTest.cs rename to test/Microsoft.AspNetCore.Rewrite.Tests/ModRewrite/RuleRegexParserTest.cs index bb47b73069..5b3081a220 100644 --- a/test/Microsoft.AspNetCore.Rewrite.Tests/RuleAbstraction/RuleRegexParserTest.cs +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/ModRewrite/RuleRegexParserTest.cs @@ -1,12 +1,11 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Rewrite.ModRewrite; -using Microsoft.AspNetCore.Rewrite.Operands; -using Microsoft.AspNetCore.Rewrite.RuleAbstraction; +// 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; +using Microsoft.AspNetCore.Rewrite.Internal.ModRewrite; using Xunit; -namespace Microsoft.AspNetCore.Rewrite.Tests.RuleAbstraction + +namespace Microsoft.AspNetCore.Rewrite.Tests.ModRewrite { public class RuleRegexParserTest { diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/ModRewriteRuleBuilderTest.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/ModRewriteRuleBuilderTest.cs deleted file mode 100644 index a871f6daa2..0000000000 --- a/test/Microsoft.AspNetCore.Rewrite.Tests/ModRewriteRuleBuilderTest.cs +++ /dev/null @@ -1,14 +0,0 @@ -// 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; -using Microsoft.AspNetCore.Http; -using Xunit; - -namespace Microsoft.AspNetCore.Rewrite -{ - public class ModRewriteRuleBuilderTest - { - - } -} diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/Rewrite2MiddlewareTests.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/Rewrite2MiddlewareTests.cs deleted file mode 100644 index 7fb8806bdd..0000000000 --- a/test/Microsoft.AspNetCore.Rewrite.Tests/Rewrite2MiddlewareTests.cs +++ /dev/null @@ -1,92 +0,0 @@ -// 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.Linq; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Builder.Internal; -using Microsoft.AspNetCore.Hosting; -using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.TestHost; -using Xunit; - -namespace Microsoft.AspNetCore.Rewrite -{ - public class RewriteMiddlewareTests - { - - [Theory(Skip = "Adapting to TestServer")] - [InlineData("/foo", "", "/foo", "/yes")] - [InlineData("/foo", "", "/foo/", "/yes")] - [InlineData("/foo", "/Bar", "/foo", "/yes")] - [InlineData("/foo", "/Bar", "/foo/cho", "/yes")] - [InlineData("/foo", "/Bar", "/foo/cho/", "/yes")] - [InlineData("/foo/cho", "/Bar", "/foo/cho", "/yes")] - [InlineData("/foo/cho", "/Bar", "/foo/cho/do", "/yes")] - public void PathMatchFunc_RewriteDone(string matchPath, string basePath, string requestPath, string rewrite) - { - var context = CreateRequest(basePath, requestPath); - var options = new UrlRewriteOptions().RewritePath(matchPath, rewrite, false); - var builder = new ApplicationBuilder(serviceProvider: null) - .UseRewriter(options); - var app = builder.Build(); - app.Invoke(context).Wait(); - Assert.Equal(rewrite, context.Request.Path); - } - [Theory(Skip = "Adapting to TestServer")] - [InlineData(@"/(?\w+)?/(?\w+)?", @"", "/hey/hello", "/${id}/${name}", "/hello/hey")] - [InlineData(@"/(?\w+)?/(?\w+)?/(?\w+)?", @"", "/hey/hello/what", "/${temp}/${id}/${name}", "/what/hello/hey")] - public void PathMatchFunc_RegexRewriteDone(string matchPath, string basePath, string requestPath, string rewrite, string expected) - { - var context = CreateRequest(basePath, requestPath); - var options = new UrlRewriteOptions().RewritePath(matchPath, rewrite, false); - var builder = new ApplicationBuilder(serviceProvider: null) - .UseRewriter(options); - - var app = builder.Build(); - app.Invoke(context).Wait(); - Assert.Equal(expected, context.Request.Path); - } - - [Fact(Skip = "Adapting to TestServer")] - public void PathMatchFunc_RedirectScheme() - { - HttpContext context = CreateRequest("/", "/"); - context.Request.Scheme = "http"; - var options = new UrlRewriteOptions().RedirectScheme(30); - var builder = new ApplicationBuilder(serviceProvider: null) - .UseRewriter(options); - var app = builder.Build(); - app.Invoke(context).Wait(); - Assert.True(context.Response.Headers["location"].First().StartsWith("https")); - } - - [Theory(Skip = "Adapting to TestServer")] - public async Task PathMatchFunc_RewriteScheme() - { - var options = new UrlRewriteOptions().RewriteScheme(); - var builder = new WebHostBuilder() - .Configure(app => - { - app.UseRewriter(options); - - app.Run(context => context.Response.WriteAsync(context.Request.Path)); - }); - var server = new TestServer(builder); - - var response = await server.CreateClient().GetAsync("http://foo.com/bar"); - - //Assert.True(response.RequestMessage.); - } - - - private HttpContext CreateRequest(string basePath, string requestPath) - { - HttpContext context = new DefaultHttpContext(); - context.Request.PathBase = new PathString(basePath); - context.Request.Path = new PathString(requestPath); - context.Request.Host = new HostString("example.com"); - return context; - } - } -} diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/UrlRewrite/FileParserTests.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/UrlRewrite/FileParserTests.cs index d2f42c21a3..4cdfe347aa 100644 --- a/test/Microsoft.AspNetCore.Rewrite.Tests/UrlRewrite/FileParserTests.cs +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/UrlRewrite/FileParserTests.cs @@ -4,7 +4,10 @@ using System.Collections.Generic; using System.IO; using System.Text.RegularExpressions; -using Microsoft.AspNetCore.Rewrite.UrlRewrite; +using Microsoft.AspNetCore.Rewrite.Internal; +using Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite; +using Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite.UrlActions; +using Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite.UrlMatches; using Xunit; namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite @@ -35,7 +38,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite var res = UrlRewriteFileParser.Parse(new StringReader(xml)); // assert - AssertUrlRewriteRuleEquality(res, expected); + AssertUrlRewriteRuleEquality(res, expected); } [Fact] @@ -58,7 +61,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite condList.Add(new Condition { Input = InputParser.ParseInputString("{HTTPS}"), - MatchPattern = new Regex("^OFF$") + Match = new RegexMatch(new Regex("^OFF$"), false) }); var expected = new List(); @@ -70,9 +73,9 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite // act var res = UrlRewriteFileParser.Parse(new StringReader(xml)); - + // assert - AssertUrlRewriteRuleEquality(expected, res); + AssertUrlRewriteRuleEquality(res, expected); } [Fact] @@ -88,12 +91,12 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite - + - + "; @@ -102,7 +105,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite condList.Add(new Condition { Input = InputParser.ParseInputString("{HTTPS}"), - MatchPattern = new Regex("^OFF$") + Match = new RegexMatch(new Regex("^OFF$"), false) }); var expected = new List(); @@ -113,15 +116,15 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite pattern: "article.aspx?id={R:1}&title={R:2}")); expected.Add(CreateTestRule(condList, Url: "^article/([0-9]+)/([_0-9a-z-]+)", - name: "Rewrite to article.aspx", - actionType: ActionType.Redirect, + name: "Rewrite to another article.aspx", + actionType: ActionType.Rewrite, pattern: "article.aspx?id={R:1}&title={R:2}")); // act var res = UrlRewriteFileParser.Parse(new StringReader(xml)); // assert - AssertUrlRewriteRuleEquality(expected, res); + AssertUrlRewriteRuleEquality(res, expected); } // Creates a rule with appropriate default values of the url rewrite rule. @@ -144,23 +147,13 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite { return new UrlRewriteRule { - Action = new UrlAction - { - Url = InputParser.ParseInputString(pattern), - Type = actionType, - AppendQueryString = appendQueryString, - LogRewrittenUrl = rewrittenUrl, - RedirectType = redirectType - }, + Action = new RewriteAction(RuleTerminiation.Continue, InputParser.ParseInputString(Url), clearQuery: false), Name = name, Enabled = enabled, StopProcessing = stopProcessing, PatternSyntax = patternSyntax, - Match = new InitialMatch + InitialMatch = new RegexMatch(new Regex("^OFF$"), false) { - Url = new Regex(Url), - IgnoreCase = ignoreCase, - Negate = negate }, Conditions = new Conditions { @@ -184,14 +177,6 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite Assert.Equal(r1.StopProcessing, r2.StopProcessing); Assert.Equal(r1.PatternSyntax, r2.PatternSyntax); - Assert.Equal(r1.Match.IgnoreCase, r2.Match.IgnoreCase); - Assert.Equal(r1.Match.Negate, r2.Match.Negate); - - Assert.Equal(r1.Action.Type, r2.Action.Type); - Assert.Equal(r1.Action.AppendQueryString, r2.Action.AppendQueryString); - Assert.Equal(r1.Action.RedirectType, r2.Action.RedirectType); - Assert.Equal(r1.Action.LogRewrittenUrl, r2.Action.LogRewrittenUrl); - // TODO conditions, url pattern, initial match regex Assert.Equal(r1.Conditions.MatchType, r2.Conditions.MatchType); Assert.Equal(r1.Conditions.TrackingAllCaptures, r2.Conditions.TrackingAllCaptures); @@ -201,12 +186,9 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite { var c1 = r1.Conditions.ConditionList[j]; var c2 = r2.Conditions.ConditionList[j]; - Assert.Equal(c1.IgnoreCase, c2.IgnoreCase); - Assert.Equal(c1.Negate, c2.Negate); - Assert.Equal(c1.MatchType, c2.MatchType); Assert.Equal(c1.Input.PatternSegments.Count, c2.Input.PatternSegments.Count); } } } } -} +} \ No newline at end of file diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/UrlRewrite/InputParserTests.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/UrlRewrite/InputParserTests.cs index 037804f267..bfcc08fc6d 100644 --- a/test/Microsoft.AspNetCore.Rewrite.Tests/UrlRewrite/InputParserTests.cs +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/UrlRewrite/InputParserTests.cs @@ -2,12 +2,9 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; -using System.Collections.Generic; -using System.Linq; using System.Text.RegularExpressions; -using System.Threading.Tasks; using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Rewrite.UrlRewrite; +using Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite; using Xunit; namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite @@ -21,8 +18,8 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite var result = InputParser.ParseInputString(testString); Assert.Equal(result.PatternSegments.Count, 1); } - - // Tests sizes of the pattern segments. These are all anonyomus lambdas, so cant check contents. + + // TODO update tests to check type [Theory] [InlineData("foo/bar/{R:1}/what", 3)] [InlineData("foo/{R:1}", 2)] @@ -35,7 +32,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite Assert.Equal(result.PatternSegments.Count, expected); } - // Test actual evaluation of the lambdas, verifying the correct string comes from the evalation + // Test actual evaluation of the types, verifying the correct string comes from the evalation [Theory] [InlineData("hey/hello/what", "hey/hello/what")] [InlineData("hey/{R:1}/what", "hey/foo/what")] @@ -98,16 +95,16 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite return context; } - private Match CreateTestRuleMatch() + private MatchResults CreateTestRuleMatch() { var match = Regex.Match("foo/bar/baz", "(.*)/(.*)/(.*)"); - return match; + return new MatchResults { BackReference = match.Groups, Success = match.Success }; } - private Match CreateTestCondMatch() + private MatchResults CreateTestCondMatch() { var match = Regex.Match("foo/bar/baz", "(.*)/(.*)/(.*)"); - return match; + return new MatchResults { BackReference = match.Groups, Success = match.Success }; } } } diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/UrlRewrite/MiddleWareTests.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/UrlRewrite/MiddleWareTests.cs new file mode 100644 index 0000000000..a34101b375 --- /dev/null +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/UrlRewrite/MiddleWareTests.cs @@ -0,0 +1,259 @@ +// 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; +using System.IO; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.TestHost; +using Microsoft.Net.Http.Headers; +using Xunit; + +namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite +{ + public class MiddlewareTests + { + [Fact] + public async Task Invoke_RedirectPathToPathAndQuery() + { + var options = new RewriteOptions().ImportFromUrlRewrite(new StringReader(@" + + + + + + + ")); + var builder = new WebHostBuilder() + .Configure(app => + { + app.UseRewriter(options); + app.Run(context => context.Response.WriteAsync(context.Response.Headers[HeaderNames.Location])); + }); + var server = new TestServer(builder); + + var response = await server.CreateClient().GetAsync("article/10/hey"); + + Assert.Equal(response.Headers.Location.OriginalString, "article.aspx?id=10&title=hey"); + } + + [Fact] + public async Task Invoke_RewritePathToPathAndQuery() + { + var options = new RewriteOptions().ImportFromUrlRewrite(new StringReader(@" + + + + + + + ")); + var builder = new WebHostBuilder() + .Configure(app => + { + app.UseRewriter(options); + app.Run(context => context.Response.WriteAsync(context.Request.Path + context.Request.QueryString)); + }); + var server = new TestServer(builder); + + var response = await server.CreateClient().GetStringAsync("/article/10/hey"); + + Assert.Equal(response, "/article.aspx?id=10&title=hey"); + } + + [Fact] + public async Task Invoke_RewriteBasedOnQueryStringParameters() + { + var options = new RewriteOptions().ImportFromUrlRewrite(new StringReader(@" + + + + + + + + + + + ")); + var builder = new WebHostBuilder() + .Configure(app => + { + app.UseRewriter(options); + app.Run(context => context.Response.WriteAsync(context.Request.Path + context.Request.QueryString)); + }); + var server = new TestServer(builder); + + var response = await server.CreateClient().GetStringAsync("page.asp?p2=321&p1=123"); + + Assert.Equal(response, "/newpage.aspx?param1=123¶m2=321"); + } + + [Fact] + public async Task Invoke_RedirectToLowerCase() + { + var options = new RewriteOptions().ImportFromUrlRewrite(new StringReader(@" + + + + + + + ")); + var builder = new WebHostBuilder() + .Configure(app => + { + app.UseRewriter(options); + app.Run(context => context.Response.WriteAsync(context.Response.Headers[HeaderNames.Location])); + }); + var server = new TestServer(builder); + + var response = await server.CreateClient().GetAsync("HElLo"); + + Assert.Equal(response.Headers.Location.OriginalString, "hello"); + } + + [Fact] + public async Task Invoke_RedirectRemoveTrailingSlash() + { + var options = new RewriteOptions().ImportFromUrlRewrite(new StringReader(@" + + + + + + + + + + + ")); + var builder = new WebHostBuilder() + .Configure(app => + { + app.UseRewriter(options); + }); + var server = new TestServer(builder); + + var response = await server.CreateClient().GetAsync("hey/hello/"); + + Assert.Equal(response.Headers.Location.OriginalString, "hey/hello"); + } + + [Fact] + public async Task Invoke_RedirectAddTrailingSlash() + { + var options = new RewriteOptions().ImportFromUrlRewrite(new StringReader(@" + + + + + + + + + + + ")); + var builder = new WebHostBuilder() + .Configure(app => + { + app.UseRewriter(options); + }); + var server = new TestServer(builder); + + var response = await server.CreateClient().GetAsync("hey/hello"); + + Assert.Equal(response.Headers.Location.OriginalString, "hey/hello/"); + } + + [Fact] + public async Task Invoke_RedirectToHttps() + { + var options = new RewriteOptions().ImportFromUrlRewrite(new StringReader(@" + + + + + + + + + + ")); + var builder = new WebHostBuilder() + .Configure(app => + { + app.UseRewriter(options); + }); + var server = new TestServer(builder); + + var response = await server.CreateClient().GetAsync(new Uri("http://example.com")); + + Assert.Equal(response.Headers.Location.OriginalString, "https://example.com/"); + } + + [Fact] + public async Task Invoke_RewriteToHttps() + { + var options = new RewriteOptions().ImportFromUrlRewrite(new StringReader(@" + + + + + + + + + + ")); + var builder = new WebHostBuilder() + .Configure(app => + { + app.UseRewriter(options); + app.Run(context => context.Response.WriteAsync( + context.Request.Scheme + + "://" + + context.Request.Host + + context.Request.Path + + context.Request.QueryString)); + }); + var server = new TestServer(builder); + + var response = await server.CreateClient().GetStringAsync(new Uri("http://example.com")); + + Assert.Equal(response, "https://example.com/"); + } + + [Fact] + public async Task Invoke_ReverseProxyToAnotherSite() + { + var options = new RewriteOptions().ImportFromUrlRewrite(new StringReader(@" + + + + + + + ")); + var builder = new WebHostBuilder() + .Configure(app => + { + app.UseRewriter(options); + app.Run(context => context.Response.WriteAsync( + context.Request.Scheme + + "://" + + context.Request.Host + + context.Request.Path + + context.Request.QueryString)); + }); + var server = new TestServer(builder); + + var response = await server.CreateClient().GetStringAsync(new Uri("http://example.com/")); + + Assert.Equal(response, "http://internalserver/"); + } + } +} From 4ce3b8da6a2c4baa7473355e4f13aa7ee25bc27c Mon Sep 17 00:00:00 2001 From: Justin Kotalik Date: Fri, 5 Aug 2016 16:43:56 -0700 Subject: [PATCH 088/307] Updating tests, Exception handling cleanup. --- .../Internal/ParserContext.cs | 20 +-- .../Internal/UrlRewrite/InputParser.cs | 22 +-- .../Internal/UrlRewrite/ServerVariables.cs | 6 +- .../UrlRewrite/UrlActions/RewriteAction.cs | 20 ++- .../UrlRewrite/UrlRewriteFileParser.cs | 92 ++++++++---- .../Properties/Resources.Designer.cs | 126 ++++++++++++++++ .../Resources.resx | 138 ++++++++++++++++++ .../FormatExceptionHandlingTests.cs | 120 +++++++++++++++ .../UrlRewrite/InputParserTests.cs | 1 + .../UrlRewrite/ServerVariableTests.cs | 63 ++++++++ 10 files changed, 557 insertions(+), 51 deletions(-) create mode 100644 src/Microsoft.AspNetCore.Rewrite/Properties/Resources.Designer.cs create mode 100644 src/Microsoft.AspNetCore.Rewrite/Resources.resx create mode 100644 test/Microsoft.AspNetCore.Rewrite.Tests/UrlRewrite/FormatExceptionHandlingTests.cs create mode 100644 test/Microsoft.AspNetCore.Rewrite.Tests/UrlRewrite/ServerVariableTests.cs diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/ParserContext.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/ParserContext.cs index 34b78f5b67..18b7833889 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/ParserContext.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/ParserContext.cs @@ -9,43 +9,43 @@ namespace Microsoft.AspNetCore.Rewrite.Internal public class ParserContext { private readonly string _template; - private int _index; + public int Index { get; set; } private int? _mark; public ParserContext(string condition) { _template = condition; - _index = -1; + Index = -1; } public char Current { - get { return (_index < _template.Length && _index >= 0) ? _template[_index] : (char)0; } + get { return (Index < _template.Length && Index >= 0) ? _template[Index] : (char)0; } } public bool Back() { - return --_index >= 0; + return --Index >= 0; } public bool Next() { - return ++_index < _template.Length; + return ++Index < _template.Length; } public bool HasNext() { - return (_index + 1) < _template.Length; + return (Index + 1) < _template.Length; } public void Mark() { - _mark = _index; + _mark = Index; } public int GetIndex() { - return _index; + return Index; } public string Capture() @@ -53,7 +53,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal // TODO make this return a range rather than a string. if (_mark.HasValue) { - var value = _template.Substring(_mark.Value, _index - _mark.Value); + var value = _template.Substring(_mark.Value, Index - _mark.Value); _mark = null; return value; } @@ -64,7 +64,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal } public string Error() { - return string.Format("Syntax Error at index: ", _index, " with character: ", Current); + return string.Format("Syntax Error at index: ", Index, " with character: ", Current); } } } diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/InputParser.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/InputParser.cs index 8d45ac0433..08b666634b 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/InputParser.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/InputParser.cs @@ -42,7 +42,8 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite // This is a server parameter, parse for a condition variable if (!context.Next()) { - throw new FormatException(context.Error()); + // missing { + throw new FormatException(Resources.FormatError_InputParserMissingCloseBrace(context.Index)); } ParseParameter(context, results); } @@ -100,10 +101,10 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite // has processed the new string. if (context.Current != CloseBrace) { - throw new FormatException("Lacking close brace for parameter at index: " + context.GetIndex()); + throw new FormatException(Resources.FormatError_InputParserMissingCloseBrace(context.Index)); } + return; } - break; case "UrlDecode": { throw new NotImplementedException("UrlDecode is not supported."); @@ -115,10 +116,10 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite if (context.Current != CloseBrace) { - throw new FormatException("Lacking close brace for parameter at index: " + context.GetIndex()); + throw new FormatException(Resources.FormatError_InputParserMissingCloseBrace(context.Index)); } + return; } - break; case "R": { var index = GetBackReferenceIndex(context); @@ -132,17 +133,18 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite return; } default: - throw new FormatException("Unrecognized parameter type: " + parameter + ", terminated at index: " + context.GetIndex()); + throw new FormatException(Resources.FormatError_InputParserUnrecognizedParameter(parameter, context.Index)); } } } + throw new FormatException(Resources.FormatError_InputParserMissingCloseBrace(context.Index)); } private static int GetBackReferenceIndex(ParserContext context) { if (!context.Next()) { - throw new FormatException("No index avaible for backreference at index: " + context.GetIndex()); + throw new FormatException(Resources.FormatError_InputParserNoBackreference(context.Index)); } context.Mark(); @@ -150,7 +152,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite { if (!context.Next()) { - throw new FormatException("Lacking close brace for parameter at index: " + context.GetIndex()); + throw new FormatException(Resources.FormatError_InputParserMissingCloseBrace(context.Index)); } } @@ -158,12 +160,12 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite int index; if (!int.TryParse(res, out index)) { - throw new FormatException("Syntax error, invalid integer in response parameter at index: " + context.GetIndex()); + throw new FormatException(Resources.FormatError_InputParserInvalidInteger(res, context.Index)); } if (index > 9 || index < 0) { - throw new FormatException("Invalid integer into backreference " + index + "at index: " + context.GetIndex()); + throw new FormatException(Resources.FormatError_InputParserIndexOutOfRange(res, context.Index)); } return index; } diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/ServerVariables.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/ServerVariables.cs index 2b0fcad556..9fa1a84bcc 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/ServerVariables.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/ServerVariables.cs @@ -28,8 +28,6 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite return new HeaderSegment(HeaderNames.Cookie); case "HTTP_HOST": return new HeaderSegment(HeaderNames.Host); - case "HTTP_PROXY_CONNECTION": - return new HeaderSegment(HeaderNames.ProxyAuthenticate); case "HTTP_REFERER": return new HeaderSegment(HeaderNames.Referer); case "HTTP_USER_AGENT": @@ -42,6 +40,8 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite return new IsHttpsSegment(); case "LOCAL_ADDR": return new LocalAddressSegment(); + case "HTTP_PROXY_CONNECTION": + throw new NotSupportedException("Proxy Connections not supported"); case "QUERY_STRING": return new QueryStringSegment(); case "REMOTE_ADDR": @@ -52,6 +52,8 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite return new RemotePortSegment(); case "REQUEST_FILENAME": return new RequestFileNameSegment(); + case "REQUEST_URI": + return new UrlSegment(); default: throw new FormatException("Unrecognized server variable."); } diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/UrlActions/RewriteAction.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/UrlActions/RewriteAction.cs index 9c7c463b82..105b023dd8 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/UrlActions/RewriteAction.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/UrlActions/RewriteAction.cs @@ -8,6 +8,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite.UrlActions { public class RewriteAction : UrlAction { + private readonly string ForwardSlash = "/"; public RuleTerminiation Result { get; } public bool ClearQuery { get; } @@ -46,12 +47,27 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite.UrlActions var split = pattern.IndexOf('?'); if (split >= 0) { - context.Request.Path = new PathString("/" + pattern.Substring(0, split)); + var path = pattern.Substring(0, split); + if (path.StartsWith(ForwardSlash)) + { + context.Request.Path = new PathString(path); + } + else + { + context.Request.Path = new PathString(ForwardSlash + path); + } context.Request.QueryString = context.Request.QueryString.Add(new QueryString(pattern.Substring(split))); } else { - context.Request.Path = new PathString("/" + pattern); + if (pattern.StartsWith(ForwardSlash)) + { + context.Request.Path = new PathString(pattern); + } + else + { + context.Request.Path = new PathString(ForwardSlash + pattern); + } } } return new RuleResult { Result = Result }; diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/UrlRewriteFileParser.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/UrlRewriteFileParser.cs index 289d9567e9..b5acf1c00f 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/UrlRewriteFileParser.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/UrlRewriteFileParser.cs @@ -6,6 +6,7 @@ using System.Collections.Generic; using System.IO; using System.Linq; using System.Text.RegularExpressions; +using System.Xml; using System.Xml.Linq; using Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite.UrlActions; using Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite.UrlMatches; @@ -18,8 +19,8 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite public static List Parse(TextReader reader) { - var temp = XDocument.Load(reader); - var xmlRoot = temp.Descendants(RewriteTags.Rewrite).FirstOrDefault(); + var xmlDoc = XDocument.Load(reader, LoadOptions.SetLineInfo); + var xmlRoot = xmlDoc.Descendants(RewriteTags.Rewrite).FirstOrDefault(); if (xmlRoot != null) { @@ -44,7 +45,12 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite { var res = new UrlRewriteRule(); SetRuleAttributes(rule, res); - CreateUrlAction(rule.Element(RewriteTags.Action), res, isGlobalRule); + var action = rule.Element(RewriteTags.Action); + if (action == null) + { + ThrowUrlFormatException(rule, "Rule does not have an associated action attribute"); + } + CreateUrlAction(action, res, isGlobalRule); if (res.Enabled) { result.Add(res); @@ -74,18 +80,17 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite { res.StopProcessing = stopProcessing; } - - CreateMatch(rule.Element(RewriteTags.Match), res); + var match = rule.Element(RewriteTags.Match); + if (match == null) + { + ThrowUrlFormatException(rule, "Cannot have rule without match"); + } + CreateMatch(match, res); CreateConditions(rule.Element(RewriteTags.Conditions), res); } private static void CreateMatch(XElement match, UrlRewriteRule res) { - if (match == null) - { - throw new FormatException("Rules must have an associated match."); - } - var matchRes = new ParsedUrlMatch(); bool parBool; @@ -100,6 +105,10 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite } var parsedInputString = match.Attribute(RewriteTags.Url)?.Value; + if (parsedInputString == null) + { + ThrowUrlFormatException(match, "Match must have Url Attribute"); + } switch (res.PatternSyntax) { @@ -178,10 +187,18 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite var parsedString = condition.Attribute(RewriteTags.Input)?.Value; if (parsedString == null) { - throw new FormatException("Null input for condition"); + ThrowUrlFormatException(condition, "Conditions must have an input attribute"); } - var input = InputParser.ParseInputString(parsedString); + Pattern input = null; + try + { + input = InputParser.ParseInputString(parsedString); + } + catch (FormatException fe) + { + ThrowUrlFormatException(condition, fe.Message, fe); + } switch (res.PatternSyntax) { @@ -194,7 +211,8 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite parsedString = condition.Attribute(RewriteTags.Pattern)?.Value; if (parsedString == null) { - throw new FormatException("Pattern match does not have an associated pattern attribute in condition."); + ThrowUrlFormatException(condition, "Match does not have an associated pattern attribute in condition"); + } Regex regex = null; @@ -221,32 +239,30 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite } break; default: - throw new FormatException("Unrecognized matchType."); + // TODO don't this this can ever be thrown + ThrowUrlFormatException(condition, "Unrecognized matchType"); + break; } - } break; case PatternSyntax.WildCard: - throw new NotImplementedException("Wildcard syntax is not supported."); + throw new NotImplementedException("Wildcard syntax is not supported"); case PatternSyntax.ExactMatch: parsedString = condition.Attribute(RewriteTags.Pattern)?.Value; if (parsedString == null) { - throw new FormatException("Pattern match does not have an associated pattern attribute in condition."); + ThrowUrlFormatException(condition, "Pattern match does not have an associated pattern attribute in condition"); } res.Conditions.ConditionList.Add(new Condition { Input = input, Match = new ExactMatch(parsedCondRes.IgnoreCase, parsedString, parsedCondRes.Negate) }); break; default: - throw new FormatException("Unrecognized pattern syntax."); + ThrowUrlFormatException(condition, "Unrecognized pattern syntax"); + break; } } private static void CreateUrlAction(XElement urlAction, UrlRewriteRule res, bool globalRule) { - if (urlAction == null) - { - throw new FormatException("Action is a required element of a rule."); - } var actionRes = new ParsedUrlAction(); @@ -273,12 +289,19 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite actionRes.RedirectType = redirectType; } - actionRes.Url = InputParser.ParseInputString(urlAction.Attribute(RewriteTags.Url)?.Value); + try + { + actionRes.Url = InputParser.ParseInputString(urlAction.Attribute(RewriteTags.Url)?.Value); + } + catch (FormatException fe) + { + ThrowUrlFormatException(urlAction, fe.Message, fe); + } - CreateUrlActionFromParsedAction(actionRes, globalRule, res); + CreateUrlActionFromParsedAction(urlAction, actionRes, globalRule, res); } - public static void CreateUrlActionFromParsedAction(ParsedUrlAction actionRes, bool globalRule, UrlRewriteRule res) + private static void CreateUrlActionFromParsedAction(XElement urlAction, ParsedUrlAction actionRes, bool globalRule, UrlRewriteRule res) { switch (actionRes.Type) { @@ -306,11 +329,26 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite } break; case ActionType.AbortRequest: - throw new FormatException("Abort requests are not supported."); + ThrowUrlFormatException(urlAction, "Abort Requests are not supported."); + break; case ActionType.CustomResponse: // TODO - throw new FormatException("Custom Responses are not supported"); + ThrowUrlFormatException(urlAction, "Custom Responses are not supported"); + break; } } + + private static void ThrowUrlFormatException(XElement element, string message) + { + var line = ((IXmlLineInfo)element).LineNumber; + var col = ((IXmlLineInfo)element).LinePosition; + throw new FormatException(Resources.FormatError_UrlRewriteParseError(message, line, col)); + } + private static void ThrowUrlFormatException(XElement element, string message, Exception ex) + { + var line = ((IXmlLineInfo)element).LineNumber; + var col = ((IXmlLineInfo)element).LinePosition; + throw new FormatException(Resources.FormatError_UrlRewriteParseError(message, line, col), ex); + } } } \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Rewrite/Properties/Resources.Designer.cs b/src/Microsoft.AspNetCore.Rewrite/Properties/Resources.Designer.cs new file mode 100644 index 0000000000..3be99059c0 --- /dev/null +++ b/src/Microsoft.AspNetCore.Rewrite/Properties/Resources.Designer.cs @@ -0,0 +1,126 @@ +// +namespace Microsoft.AspNetCore.Rewrite +{ + using System.Globalization; + using System.Reflection; + using System.Resources; + + internal static class Resources + { + private static readonly ResourceManager _resourceManager + = new ResourceManager("Microsoft.AspNetCore.Rewrite.Resources", typeof(Resources).GetTypeInfo().Assembly); + + /// + /// Could not parse the UrlRewrite file. Message: '{0}'. Line number '{1}': '{2}'. + /// + internal static string Error_UrlRewriteParseError + { + get { return GetString("Error_UrlRewriteParseError"); } + } + + /// + /// Could not parse the UrlRewrite file. Message: '{0}'. Line number '{1}': '{2}'. + /// + internal static string FormatError_UrlRewriteParseError(object p0, object p1, object p2) + { + return string.Format(CultureInfo.CurrentCulture, GetString("Error_UrlRewriteParseError"), p0, p1, p2); + } + + /// + /// Index out of range for backreference: '{0}' at string index: '{1}' + /// + internal static string Error_InputParserIndexOutOfRange + { + get { return GetString("Error_InputParserIndexOutOfRange"); } + } + + /// + /// Index out of range for backreference: '{0}' at string index: '{1}' + /// + internal static string FormatError_InputParserIndexOutOfRange(object p0, object p1) + { + return string.Format(CultureInfo.CurrentCulture, GetString("Error_InputParserIndexOutOfRange"), p0, p1); + } + + /// + /// Cannot parse '{0}' to integer at string index: '{1}' + /// + internal static string Error_InputParserInvalidInteger + { + get { return GetString("Error_InputParserInvalidInteger"); } + } + + /// + /// Cannot parse '{0}' to integer at string index: '{1}' + /// + internal static string FormatError_InputParserInvalidInteger(object p0, object p1) + { + return string.Format(CultureInfo.CurrentCulture, GetString("Error_InputParserInvalidInteger"), p0, p1); + } + + /// + /// Missing close brace for parameter at string index: '{0}' + /// + internal static string Error_InputParserMissingCloseBrace + { + get { return GetString("Error_InputParserMissingCloseBrace"); } + } + + /// + /// Missing close brace for parameter at string index: '{0}' + /// + internal static string FormatError_InputParserMissingCloseBrace(object p0) + { + return string.Format(CultureInfo.CurrentCulture, GetString("Error_InputParserMissingCloseBrace"), p0); + } + + /// + /// Missing backreference for parameter at string index: '{0}' + /// + internal static string Error_InputParserNoBackreference + { + get { return GetString("Error_InputParserNoBackreference"); } + } + + /// + /// Missing backreference for parameter at string index: '{0}' + /// + internal static string FormatError_InputParserNoBackreference(object p0) + { + return string.Format(CultureInfo.CurrentCulture, GetString("Error_InputParserNoBackreference"), p0); + } + + /// + /// Unrecognized parameter type: '{0}', terminated at string index: '{1}' + /// + internal static string Error_InputParserUnrecognizedParameter + { + get { return GetString("Error_InputParserUnrecognizedParameter"); } + } + + /// + /// Unrecognized parameter type: '{0}', terminated at string index: '{1}' + /// + internal static string FormatError_InputParserUnrecognizedParameter(object p0, object p1) + { + return string.Format(CultureInfo.CurrentCulture, GetString("Error_InputParserUnrecognizedParameter"), p0, p1); + } + + private static string GetString(string name, params string[] formatterNames) + { + var value = _resourceManager.GetString(name); + + System.Diagnostics.Debug.Assert(value != null); + + if (formatterNames != null) + { + for (var i = 0; i < formatterNames.Length; i++) + { + value = value.Replace("{" + formatterNames[i] + "}", "{" + i + "}"); + } + } + + return value; + } + } +} diff --git a/src/Microsoft.AspNetCore.Rewrite/Resources.resx b/src/Microsoft.AspNetCore.Rewrite/Resources.resx new file mode 100644 index 0000000000..ae034489ee --- /dev/null +++ b/src/Microsoft.AspNetCore.Rewrite/Resources.resx @@ -0,0 +1,138 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Could not parse the UrlRewrite file. Message: '{0}'. Line number '{1}': '{2}'. + + + Index out of range for backreference: '{0}' at string index: '{1}' + + + Cannot parse '{0}' to integer at string index: '{1}' + + + Missing close brace for parameter at string index: '{0}' + + + Missing backreference for parameter at string index: '{0}' + + + Unrecognized parameter type: '{0}', terminated at string index: '{1}' + + \ No newline at end of file diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/UrlRewrite/FormatExceptionHandlingTests.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/UrlRewrite/FormatExceptionHandlingTests.cs new file mode 100644 index 0000000000..6a4f5f47e0 --- /dev/null +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/UrlRewrite/FormatExceptionHandlingTests.cs @@ -0,0 +1,120 @@ +// 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; +using System.IO; +using Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite; +using Xunit; + +namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite +{ + public class FormatExceptionHandlingTests + { + [Theory] + [InlineData( +@" + + + + +", + "Could not parse the UrlRewrite file. Message: 'Cannot have rule without match'. Line number '3': '10'.")] + [InlineData( +@" + + + + + + +", + "Could not parse the UrlRewrite file. Message: 'Missing close brace for parameter at string index: '1''. Line number '5': '14'.")] + [InlineData( +@" + + + + + + +", + "Could not parse the UrlRewrite file. Message: 'Abort Requests are not supported.'. Line number '5': '14'.")] + [InlineData( +@" + + + + + + +", + "Could not parse the UrlRewrite file. Message: 'Custom Responses are not supported'. Line number '5': '14'.")] + [InlineData( +@" + + + + + +", + "Could not parse the UrlRewrite file. Message: 'Match must have Url Attribute'. Line number '4': '14'.")] + [InlineData( +@" + + + + + + + + + +", + "Could not parse the UrlRewrite file. Message: 'Missing close brace for parameter at string index: '6''. Line number '6': '18'.")] + [InlineData( +@" + + + + + + + + + +", + "Could not parse the UrlRewrite file. Message: 'Conditions must have an input attribute'. Line number '6': '18'.")] + [InlineData( +@" + + + + + + + + + +", + "Could not parse the UrlRewrite file. Message: 'Match does not have an associated pattern attribute in condition'. Line number '6': '18'.")] + [InlineData( +@" + + + + + + + + + +", + "Could not parse the UrlRewrite file. Message: 'Match does not have an associated pattern attribute in condition'. Line number '6': '18'.")] + public void ThrowFormatExceptionWithCorrectMessage(string input, string expected) + { + // Arrange, Act, Assert + var ex = Assert.Throws(() => UrlRewriteFileParser.Parse(new StringReader(input))); + Assert.Equal(ex.Message, expected); + } + } +} diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/UrlRewrite/InputParserTests.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/UrlRewrite/InputParserTests.cs index bfcc08fc6d..31f6a2e984 100644 --- a/test/Microsoft.AspNetCore.Rewrite.Tests/UrlRewrite/InputParserTests.cs +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/UrlRewrite/InputParserTests.cs @@ -82,6 +82,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite [InlineData("{foo:1")] [InlineData("{UrlEncode:{R:}}")] [InlineData("{UrlEncode:{R:1}")] + [InlineData("{HTTPS")] public void FormatExceptionsOnBadSyntax(string testString) { Assert.Throws(() => InputParser.ParseInputString(testString)); diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/UrlRewrite/ServerVariableTests.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/UrlRewrite/ServerVariableTests.cs new file mode 100644 index 0000000000..6f11a3c21f --- /dev/null +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/UrlRewrite/ServerVariableTests.cs @@ -0,0 +1,63 @@ +// 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.Text.RegularExpressions; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite; +using Microsoft.Net.Http.Headers; +using Xunit; + +namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite +{ + public class ServerVariableTests + { + [Theory] + [InlineData("CONTENT_LENGTH", "10")] + [InlineData("CONTENT_TYPE", "json")] + [InlineData("HTTP_ACCEPT", "accept")] + [InlineData("HTTP_COOKIE", "cookie")] + [InlineData("HTTP_HOST", "example.com")] + [InlineData("HTTP_REFERER", "referer")] + [InlineData("HTTP_USER_AGENT", "useragent")] + [InlineData("HTTP_CONNECTION", "connection")] + [InlineData("HTTP_URL", "/foo")] + [InlineData("QUERY_STRING", "?bar=1")] + [InlineData("REQUEST_FILENAME", "/foo")] + public void CheckServerVariableParsingAndApplication(string variable, string expected) + { + // Arrange and Act + var serverVar = ServerVariables.FindServerVariable(variable); + var lookup = serverVar.Evaluate(CreateTestHttpContext(), CreateTestRuleMatch(), CreateTestCondMatch()); + // Assert + Assert.Equal(expected, lookup); + } + + private HttpContext CreateTestHttpContext() + { + var context = new DefaultHttpContext(); + context.Request.Host = new HostString("example.com"); + context.Request.Path = new PathString("/foo"); + context.Request.QueryString = new QueryString("?bar=1"); + context.Request.ContentLength = 10; + context.Request.ContentType = "json"; + context.Request.Headers[HeaderNames.Accept] = "accept"; + context.Request.Headers[HeaderNames.Cookie] = "cookie"; + context.Request.Headers[HeaderNames.Referer] = "referer"; + context.Request.Headers[HeaderNames.UserAgent] = "useragent"; + context.Request.Headers[HeaderNames.Connection] = "connection"; + return context; + } + + private MatchResults CreateTestRuleMatch() + { + var match = Regex.Match("foo/bar/baz", "(.*)/(.*)/(.*)"); + return new MatchResults { BackReference = match.Groups, Success = match.Success }; + } + + private MatchResults CreateTestCondMatch() + { + var match = Regex.Match("foo/bar/baz", "(.*)/(.*)/(.*)"); + return new MatchResults { BackReference = match.Groups, Success = match.Success }; + } + } +} From ade05fb068b2c582570f75e6e5bc15be43abda29 Mon Sep 17 00:00:00 2001 From: Pranav K Date: Tue, 9 Aug 2016 14:56:10 -0700 Subject: [PATCH 089/307] Switching to dotnet.myget.org feed --- NuGet.config | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/NuGet.config b/NuGet.config index dae5aba3f9..a696a0a743 100644 --- a/NuGet.config +++ b/NuGet.config @@ -1,7 +1,7 @@ - + - + \ No newline at end of file From 52c7a94db3ff4af2bb2a6a25d5794fb807efe7da Mon Sep 17 00:00:00 2001 From: Pranav K Date: Tue, 9 Aug 2016 15:32:38 -0700 Subject: [PATCH 090/307] Don't use abbreviations --- .../Internal/UrlRewrite/UrlRewriteFileParser.cs | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/UrlRewriteFileParser.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/UrlRewriteFileParser.cs index b5acf1c00f..350e697b24 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/UrlRewriteFileParser.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/UrlRewriteFileParser.cs @@ -134,7 +134,6 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite } } - private static void CreateConditions(XElement conditions, UrlRewriteRule res) { // This is to avoid nullptr exception on referencing conditions. @@ -164,7 +163,6 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite private static void CreateCondition(XElement condition, UrlRewriteRule res) { - var parsedCondRes = new ParsedCondition(); bool parBool; @@ -195,9 +193,9 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite { input = InputParser.ParseInputString(parsedString); } - catch (FormatException fe) + catch (FormatException formatException) { - ThrowUrlFormatException(condition, fe.Message, fe); + ThrowUrlFormatException(condition, formatException.Message, formatException); } switch (res.PatternSyntax) @@ -293,9 +291,9 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite { actionRes.Url = InputParser.ParseInputString(urlAction.Attribute(RewriteTags.Url)?.Value); } - catch (FormatException fe) + catch (FormatException formatException) { - ThrowUrlFormatException(urlAction, fe.Message, fe); + ThrowUrlFormatException(urlAction, formatException.Message, formatException); } CreateUrlActionFromParsedAction(urlAction, actionRes, globalRule, res); @@ -351,4 +349,4 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite throw new FormatException(Resources.FormatError_UrlRewriteParseError(message, line, col), ex); } } -} \ No newline at end of file +} From 903949cc74cd95f10f2dc2cf80191bb0001d9bb8 Mon Sep 17 00:00:00 2001 From: Justin Kotalik Date: Mon, 8 Aug 2016 14:26:57 -0700 Subject: [PATCH 091/307] Update structure of code rules, refactor to IISRewrite --- BasicMiddleware.sln | 3 + samples/RewriteSample/Startup.cs | 23 +- .../CodeRewriteExtensions.cs | 95 +++--- .../{ => CodeRules}/FunctionalRule.cs | 3 +- .../RedirectToHttpsRule.cs} | 22 +- .../Internal/CodeRules/RewriteToHttpsRule.cs | 42 +++ .../{ => ModRewrite}/RuleExpression.cs | 2 +- .../Internal/PathRule.cs | 48 --- .../Internal/Transformation.cs | 12 - .../Internal/UrlRewrite/ParsedCondition.cs | 12 - .../Internal/UrlRewrite/ParsedUrlAction.cs | 14 - .../Internal/UrlRewrite/ParsedUrlMatch.cs | 11 - .../Internal/UrlRewrite/RewriteTags.cs | 2 +- .../Internal/UrlRewrite/UrlAction.cs | 1 - .../UrlRewrite/UrlRewriteFileParser.cs | 275 +++++------------- .../UrlRewrite/UrlRewriteRuleBuilder.cs | 168 +++++++++++ .../Internal/UrlRewriteRule.cs | 14 +- .../CodeRules/MiddlewareTests.cs | 90 ++++++ .../UrlRewrite/FileParserTests.cs | 40 +-- .../FormatExceptionHandlingTests.cs | 3 +- .../UrlRewrite/MiddleWareTests.cs | 96 +++--- 21 files changed, 538 insertions(+), 438 deletions(-) rename src/Microsoft.AspNetCore.Rewrite/Internal/{ => CodeRules}/FunctionalRule.cs (75%) rename src/Microsoft.AspNetCore.Rewrite/Internal/{SchemeRule.cs => CodeRules/RedirectToHttpsRule.cs} (65%) create mode 100644 src/Microsoft.AspNetCore.Rewrite/Internal/CodeRules/RewriteToHttpsRule.cs rename src/Microsoft.AspNetCore.Rewrite/Internal/{ => ModRewrite}/RuleExpression.cs (86%) delete mode 100644 src/Microsoft.AspNetCore.Rewrite/Internal/PathRule.cs delete mode 100644 src/Microsoft.AspNetCore.Rewrite/Internal/Transformation.cs delete mode 100644 src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/ParsedCondition.cs delete mode 100644 src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/ParsedUrlAction.cs delete mode 100644 src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/ParsedUrlMatch.cs create mode 100644 src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/UrlRewriteRuleBuilder.cs create mode 100644 test/Microsoft.AspNetCore.Rewrite.Tests/CodeRules/MiddlewareTests.cs diff --git a/BasicMiddleware.sln b/BasicMiddleware.sln index a431cdab18..dd15eee89b 100644 --- a/BasicMiddleware.sln +++ b/BasicMiddleware.sln @@ -5,6 +5,9 @@ MinimumVisualStudioVersion = 10.0.40219.1 Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNetCore.HttpOverrides", "src\Microsoft.AspNetCore.HttpOverrides\Microsoft.AspNetCore.HttpOverrides.xproj", "{517308C3-B477-4B01-B461-CAB9C10B6928}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{A5076D28-FA7E-4606-9410-FEDD0D603527}" + ProjectSection(SolutionItems) = preProject + global.json = global.json + EndProjectSection EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{8437B0F3-3894-4828-A945-A9187F37631D}" EndProject diff --git a/samples/RewriteSample/Startup.cs b/samples/RewriteSample/Startup.cs index 5fe6a3840c..b83d5677e7 100644 --- a/samples/RewriteSample/Startup.cs +++ b/samples/RewriteSample/Startup.cs @@ -6,6 +6,7 @@ using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Rewrite; +using Microsoft.AspNetCore.Rewrite.Internal; namespace RewriteSample { @@ -13,9 +14,29 @@ namespace RewriteSample { public void Configure(IApplicationBuilder app, IHostingEnvironment hostingEnv) { + // Four main use cases for Rewrite Options. + // 1. Importing from a UrlRewrite file, which are IIS Rewrite rules. + // This file is in xml format, starting with the tag. + // 2. Importing from a mod_rewrite file, which are mod_rewrite rules. + // This file is in standard mod_rewrite format which only contains rewrite information. + // 3. Inline rules in code, where you can specify rules such as rewrites and redirects + // based on certain conditions. Ex: RedirectToHttps will check if the request is https, + // else it will redirect the request with https. + // 4. Functional rules. If a user has a very specific function they would like to implement + // (ex StringReplace) that are easy to implement in code, they can do so by calling + // AddFunctionalRule(Func); + // TODO make this startup do something useful. app.UseRewriter(new RewriteOptions() .ImportFromUrlRewrite(hostingEnv, "UrlRewrite.xml") - .ImportFromModRewrite(hostingEnv, "Rewrite.txt")); + .ImportFromModRewrite(hostingEnv, "Rewrite.txt") + .RedirectToHttps(StatusCodes.Status307TemporaryRedirect) + .RewriteRule("/foo/(.*)/bar", "{R:1}/bar") + .AddRule(ctx => + { + ctx.HttpContext.Request.Path = "/index"; + return RuleResult.Continue; + })); + app.Run(context => context.Response.WriteAsync(context.Request.Path)); } diff --git a/src/Microsoft.AspNetCore.Rewrite/CodeRewriteExtensions.cs b/src/Microsoft.AspNetCore.Rewrite/CodeRewriteExtensions.cs index 51060ebdfc..9da5101c96 100644 --- a/src/Microsoft.AspNetCore.Rewrite/CodeRewriteExtensions.cs +++ b/src/Microsoft.AspNetCore.Rewrite/CodeRewriteExtensions.cs @@ -3,8 +3,9 @@ using System; using System.Collections.Generic; -using System.Text.RegularExpressions; using Microsoft.AspNetCore.Rewrite.Internal; +using Microsoft.AspNetCore.Rewrite.Internal.CodeRules; +using Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite; namespace Microsoft.AspNetCore.Rewrite { @@ -35,69 +36,69 @@ namespace Microsoft.AspNetCore.Rewrite return options; } - /// - /// Creates a rewrite path rule. - /// - /// The Url rewrite options. - /// The string regex pattern to compare against the http context. - /// The string to replace the path with (with capture parameters). - /// Whether or not to stop rewriting on success of rule. - /// - public static RewriteOptions RewritePath(this RewriteOptions options, string regex, string newPath, bool stopRewriteOnSuccess = false) + public static RewriteOptions RewriteRule(this RewriteOptions options, string regex, string onMatch) { - options.Rules.Add(new PathRule { MatchPattern = new Regex(regex, RegexOptions.Compiled, TimeSpan.FromMilliseconds(1)), OnMatch = newPath, OnCompletion = stopRewriteOnSuccess ? Transformation.TerminatingRewrite : Transformation.Rewrite }); + return RewriteRule(options, regex, onMatch, stopProcessing: false); + } + + public static RewriteOptions RewriteRule(this RewriteOptions options, string regex, string onMatch, bool stopProcessing) + { + var builder = new UrlRewriteRuleBuilder(); + var pattern = InputParser.ParseInputString(onMatch); + + builder.AddUrlMatch(regex); + builder.AddUrlAction(pattern, actionType: ActionType.Rewrite, stopProcessing: stopProcessing); + options.Rules.Add(builder.Build()); return options; } - /// - /// Rewrite http to https. - /// - /// The Url rewrite options. - /// Whether or not to stop rewriting on success of rule. - /// - public static RewriteOptions RewriteScheme(this RewriteOptions options, bool stopRewriteOnSuccess = false) + public static RewriteOptions RedirectRule(this RewriteOptions options, string regex, string onMatch, int statusCode) { - options.Rules.Add(new SchemeRule {OnCompletion = stopRewriteOnSuccess ? Transformation.TerminatingRewrite : Transformation.Rewrite }); + return RedirectRule(options, regex, onMatch, statusCode, stopProcessing: false); + } + + public static RewriteOptions RedirectRule(this RewriteOptions options, string regex, string onMatch, int statusCode, bool stopProcessing) + { + var builder = new UrlRewriteRuleBuilder(); + var pattern = InputParser.ParseInputString(onMatch); + + builder.AddUrlMatch(regex); + builder.AddUrlAction(pattern, actionType: ActionType.Redirect, stopProcessing: stopProcessing); + options.Rules.Add(builder.Build()); return options; } - /// - /// Redirect a path to another path. - /// - /// The Url rewrite options. - /// The string regex pattern to compare against the http context. - /// The string to replace the path with (with capture parameters). - /// Whether or not to stop rewriting on success of rule. - /// - public static RewriteOptions RedirectPath(this RewriteOptions options, string regex, string newPath, bool stopRewriteOnSuccess = false) + public static RewriteOptions RedirectToHttps(this RewriteOptions options, int statusCode) { - options.Rules.Add(new PathRule { MatchPattern = new Regex(regex, RegexOptions.Compiled, TimeSpan.FromMilliseconds(1)), OnMatch = newPath, OnCompletion = Transformation.Redirect }); + return RedirectToHttps(options, statusCode, null); + } + + // TODO Don't do this, it doesn't work in all cases. Will refactor tonight/ tomorrow. + public static RewriteOptions RedirectToHttps(this RewriteOptions options, int statusCode, int? sslPort) + { + options.Rules.Add(new RedirectToHttpsRule { StatusCode = statusCode, SSLPort = sslPort }); return options; } - /// - /// Redirect http to https. - /// - /// The Url rewrite options. - /// The port to redirect the scheme to. - /// - public static RewriteOptions RedirectScheme(this RewriteOptions options, int? sslPort) + public static RewriteOptions RewriteToHttps(this RewriteOptions options) + { + return RewriteToHttps(options, sslPort: null, stopProcessing: false); + } + + public static RewriteOptions RewriteToHttps(this RewriteOptions options, int? sslPort) { - options.Rules.Add(new SchemeRule { SSLPort = sslPort, OnCompletion = Transformation.Redirect }); + return RewriteToHttps(options, sslPort, stopProcessing: false); + } + + public static RewriteOptions RewriteToHttps(this RewriteOptions options, int? sslPort, bool stopProcessing) + { + options.Rules.Add(new RewriteToHttpsRule {SSLPort = sslPort, stopProcessing = stopProcessing }); return options; } - /// - /// User generated rule to do a specific match on a path and what to do on success of the match. - /// - /// - /// - /// - /// - /// - public static RewriteOptions CustomRule(this RewriteOptions options, Func onApplyRule, Transformation transform, string description = null) + public static RewriteOptions AddRule(this RewriteOptions options, Func rule) { - options.Rules.Add(new FunctionalRule { OnApplyRule = onApplyRule, OnCompletion = transform}); + options.Rules.Add(new FunctionalRule { OnApplyRule = rule}); return options; } } diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/FunctionalRule.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/CodeRules/FunctionalRule.cs similarity index 75% rename from src/Microsoft.AspNetCore.Rewrite/Internal/FunctionalRule.cs rename to src/Microsoft.AspNetCore.Rewrite/Internal/CodeRules/FunctionalRule.cs index 5704a23a40..eccf9e735f 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/FunctionalRule.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/CodeRules/FunctionalRule.cs @@ -3,12 +3,11 @@ using System; -namespace Microsoft.AspNetCore.Rewrite.Internal +namespace Microsoft.AspNetCore.Rewrite.Internal.CodeRules { public class FunctionalRule : Rule { public Func OnApplyRule { get; set; } - public Transformation OnCompletion { get; set; } = Transformation.Rewrite; public override RuleResult ApplyRule(RewriteContext context) => OnApplyRule(context); } } \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/SchemeRule.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/CodeRules/RedirectToHttpsRule.cs similarity index 65% rename from src/Microsoft.AspNetCore.Rewrite/Internal/SchemeRule.cs rename to src/Microsoft.AspNetCore.Rewrite/Internal/CodeRules/RedirectToHttpsRule.cs index 87a08544e8..3dd9d6df39 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/SchemeRule.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/CodeRules/RedirectToHttpsRule.cs @@ -4,12 +4,12 @@ using System.Text; using Microsoft.AspNetCore.Http; -namespace Microsoft.AspNetCore.Rewrite.Internal +namespace Microsoft.AspNetCore.Rewrite.Internal.CodeRules { - public class SchemeRule : Rule + public class RedirectToHttpsRule : Rule { public int? SSLPort { get; set; } - public Transformation OnCompletion { get; set; } = Transformation.Rewrite; + public int StatusCode { get; set; } public override RuleResult ApplyRule(RewriteContext context) { @@ -28,20 +28,6 @@ namespace Microsoft.AspNetCore.Rewrite.Internal host = new HostString(host.Host); } - if ((OnCompletion != Transformation.Redirect)) - { - context.HttpContext.Request.Scheme = "https"; - context.HttpContext.Request.Host = host; - if (OnCompletion == Transformation.TerminatingRewrite) - { - return RuleResult.StopRules; - } - else - { - return RuleResult.Continue; - } - } - var req = context.HttpContext.Request; var newUrl = new StringBuilder().Append("https://").Append(host).Append(req.PathBase).Append(req.Path).Append(req.QueryString); @@ -51,4 +37,4 @@ namespace Microsoft.AspNetCore.Rewrite.Internal return RuleResult.Continue; } } -} +} \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/CodeRules/RewriteToHttpsRule.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/CodeRules/RewriteToHttpsRule.cs new file mode 100644 index 0000000000..cccb76e6d1 --- /dev/null +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/CodeRules/RewriteToHttpsRule.cs @@ -0,0 +1,42 @@ + +using Microsoft.AspNetCore.Http; + +namespace Microsoft.AspNetCore.Rewrite.Internal.CodeRules +{ + public class RewriteToHttpsRule : Rule + { + + public bool stopProcessing { get; set; } + public int? SSLPort { get; set; } + public override RuleResult ApplyRule(RewriteContext context) + { + // TODO this only does http to https, add more features in the future. + if (!context.HttpContext.Request.IsHttps) + { + var host = context.HttpContext.Request.Host; + if (SSLPort.HasValue && SSLPort.Value > 0) + { + // a specific SSL port is specified + host = new HostString(host.Host, SSLPort.Value); + } + else + { + // clear the port + host = new HostString(host.Host); + } + + context.HttpContext.Request.Scheme = "https"; + context.HttpContext.Request.Host = host; + if (stopProcessing) + { + return RuleResult.StopRules; + } + else + { + return RuleResult.Continue; + } + } + return RuleResult.Continue; + } + } +} diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/RuleExpression.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/RuleExpression.cs similarity index 86% rename from src/Microsoft.AspNetCore.Rewrite/Internal/RuleExpression.cs rename to src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/RuleExpression.cs index 52458cc542..1c29b18f0e 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/RuleExpression.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/RuleExpression.cs @@ -3,7 +3,7 @@ using Microsoft.AspNetCore.Rewrite.Internal.ModRewrite.Operands; -namespace Microsoft.AspNetCore.Rewrite.Internal +namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite { public class RuleExpression { diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/PathRule.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/PathRule.cs deleted file mode 100644 index 88b07e6cde..0000000000 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/PathRule.cs +++ /dev/null @@ -1,48 +0,0 @@ -// 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.Text.RegularExpressions; - -namespace Microsoft.AspNetCore.Rewrite.Internal -{ - public class PathRule : Rule - { - public Regex MatchPattern { get; set; } - public string OnMatch { get; set; } - public Transformation OnCompletion { get; set; } = Transformation.Rewrite; - public override RuleResult ApplyRule(RewriteContext context) - { - var matches = MatchPattern.Match(context.HttpContext.Request.Path); - if (matches.Success) - { - // New method here to translate the outgoing format string to the correct value. - var path = matches.Result(OnMatch); - if (OnCompletion == Transformation.Redirect) - { - var req = context.HttpContext.Request; - var newUrl = string.Concat( - req.Scheme, - "://", - req.PathBase, - path, - req.QueryString); - context.HttpContext.Response.Redirect(newUrl); - return RuleResult.ResponseComplete; - } - else - { - context.HttpContext.Request.Path = path; - } - if (OnCompletion == Transformation.TerminatingRewrite) - { - return RuleResult.StopRules; - } - else - { - return RuleResult.Continue; - } - } - return RuleResult.Continue; - } - } -} diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/Transformation.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/Transformation.cs deleted file mode 100644 index 01ca2dc9cf..0000000000 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/Transformation.cs +++ /dev/null @@ -1,12 +0,0 @@ -// 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. - -namespace Microsoft.AspNetCore.Rewrite.Internal -{ - public enum Transformation - { - Rewrite, - Redirect, - TerminatingRewrite - } -} diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/ParsedCondition.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/ParsedCondition.cs deleted file mode 100644 index e34ccdb00f..0000000000 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/ParsedCondition.cs +++ /dev/null @@ -1,12 +0,0 @@ -// 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. - -namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite -{ - public class ParsedCondition - { - public bool Negate { get; set; } - public bool IgnoreCase { get; set; } = true; - public MatchType MatchType { get; set; } = MatchType.Pattern; - } -} diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/ParsedUrlAction.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/ParsedUrlAction.cs deleted file mode 100644 index 857c2f16cd..0000000000 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/ParsedUrlAction.cs +++ /dev/null @@ -1,14 +0,0 @@ -// 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. - -namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite -{ - public class ParsedUrlAction - { - public ActionType Type { get; set; } - public Pattern Url { get; set; } - public bool AppendQueryString { get; set; } = true; - public bool LogRewrittenUrl { get; set; } // Ignoring this flag. - public RedirectType RedirectType { get; set; } = RedirectType.Permanent; - } -} diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/ParsedUrlMatch.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/ParsedUrlMatch.cs deleted file mode 100644 index 9f183fadc3..0000000000 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/ParsedUrlMatch.cs +++ /dev/null @@ -1,11 +0,0 @@ -// 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. - -namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite -{ - public class ParsedUrlMatch - { - public bool IgnoreCase { get; set; } - public bool Negate { get; set; } - } -} diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/RewriteTags.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/RewriteTags.cs index 16074abfb3..2421fe2eb5 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/RewriteTags.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/RewriteTags.cs @@ -26,7 +26,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite public const string Input = "input"; public const string Pattern = "pattern"; public const string Type = "type"; - public const string AppendQuery = "appendQueryString"; + public const string AppendQueryString = "appendQueryString"; public const string LogRewrittenUrl = "logRewrittenUrl"; public const string RedirectType = "redirectType"; } diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/UrlAction.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/UrlAction.cs index 404561b25b..489f4a6b53 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/UrlAction.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/UrlAction.cs @@ -8,7 +8,6 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite public abstract class UrlAction { public Pattern Url { get; set; } - public abstract RuleResult ApplyAction(HttpContext context, MatchResults ruleMatch, MatchResults condMatch); } } diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/UrlRewriteFileParser.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/UrlRewriteFileParser.cs index 350e697b24..4f9e0bbc22 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/UrlRewriteFileParser.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/UrlRewriteFileParser.cs @@ -5,11 +5,8 @@ using System; using System.Collections.Generic; using System.IO; using System.Linq; -using System.Text.RegularExpressions; using System.Xml; using System.Xml.Linq; -using Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite.UrlActions; -using Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite.UrlMatches; namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite { @@ -27,14 +24,14 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite var result = new List(); // TODO Global rules are currently not treated differently than normal rules, fix. // See: https://github.com/aspnet/BasicMiddleware/issues/59 - ParseRules(xmlRoot.Descendants(RewriteTags.GlobalRules).FirstOrDefault(), result, isGlobalRule: true); - ParseRules(xmlRoot.Descendants(RewriteTags.Rules).FirstOrDefault(), result, isGlobalRule: false); + ParseRules(xmlRoot.Descendants(RewriteTags.GlobalRules).FirstOrDefault(), result); + ParseRules(xmlRoot.Descendants(RewriteTags.Rules).FirstOrDefault(), result); return result; } return null; } - private static void ParseRules(XElement rules, List result, bool isGlobalRule) + private static void ParseRules(XElement rules, List result) { if (rules == null) { @@ -43,297 +40,176 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite foreach (var rule in rules.Elements(RewriteTags.Rule)) { - var res = new UrlRewriteRule(); - SetRuleAttributes(rule, res); - var action = rule.Element(RewriteTags.Action); - if (action == null) + var builder = new UrlRewriteRuleBuilder(); + ParseRuleAttributes(rule, builder); + + if (builder.Enabled) { - ThrowUrlFormatException(rule, "Rule does not have an associated action attribute"); - } - CreateUrlAction(action, res, isGlobalRule); - if (res.Enabled) - { - result.Add(res); + result.Add(builder.Build()); } } } - private static void SetRuleAttributes(XElement rule, UrlRewriteRule res) + private static void ParseRuleAttributes(XElement rule, UrlRewriteRuleBuilder builder) { - - res.Name = rule.Attribute(RewriteTags.Name)?.Value; + builder.Name = rule.Attribute(RewriteTags.Name)?.Value; bool enabled; - if (bool.TryParse(rule.Attribute(RewriteTags.Enabled)?.Value, out enabled)) + if (!bool.TryParse(rule.Attribute(RewriteTags.Enabled)?.Value, out enabled)) { - res.Enabled = enabled; + builder.Enabled = true; } PatternSyntax patternSyntax; - if (Enum.TryParse(rule.Attribute(RewriteTags.PatternSyntax)?.Value, out patternSyntax)) + if (!Enum.TryParse(rule.Attribute(RewriteTags.PatternSyntax)?.Value, out patternSyntax)) { - res.PatternSyntax = patternSyntax; + patternSyntax = PatternSyntax.ECMAScript; } bool stopProcessing; - if (bool.TryParse(rule.Attribute(RewriteTags.StopProcessing)?.Value, out stopProcessing)) + if (!bool.TryParse(rule.Attribute(RewriteTags.StopProcessing)?.Value, out stopProcessing)) { - res.StopProcessing = stopProcessing; + stopProcessing = false; } + var match = rule.Element(RewriteTags.Match); if (match == null) { ThrowUrlFormatException(rule, "Cannot have rule without match"); } - CreateMatch(match, res); - CreateConditions(rule.Element(RewriteTags.Conditions), res); + + var action = rule.Element(RewriteTags.Action); + if (action == null) + { + ThrowUrlFormatException(rule, "Rule does not have an associated action attribute"); + } + + ParseMatch(match, builder, patternSyntax); + ParseConditions(rule.Element(RewriteTags.Conditions), builder, patternSyntax); + ParseUrlAction(action, builder, stopProcessing); } - private static void CreateMatch(XElement match, UrlRewriteRule res) + private static void ParseMatch(XElement match, UrlRewriteRuleBuilder builder, PatternSyntax patternSyntax) { - var matchRes = new ParsedUrlMatch(); - - bool parBool; - if (bool.TryParse(match.Attribute(RewriteTags.IgnoreCase)?.Value, out parBool)) - { - matchRes.IgnoreCase = parBool; - } - - if (bool.TryParse(match.Attribute(RewriteTags.Negate)?.Value, out parBool)) - { - matchRes.Negate = parBool; - } - var parsedInputString = match.Attribute(RewriteTags.Url)?.Value; if (parsedInputString == null) { ThrowUrlFormatException(match, "Match must have Url Attribute"); } - switch (res.PatternSyntax) + bool ignoreCase; + if (!bool.TryParse(match.Attribute(RewriteTags.IgnoreCase)?.Value, out ignoreCase)) { - case PatternSyntax.ECMAScript: - { - if (matchRes.IgnoreCase) - { - var regex = new Regex(parsedInputString, RegexOptions.Compiled | RegexOptions.IgnoreCase, RegexTimeout); - res.InitialMatch = new RegexMatch(regex, matchRes.Negate); - } - else - { - var regex = new Regex(parsedInputString, RegexOptions.Compiled, RegexTimeout); - res.InitialMatch = new RegexMatch(regex, matchRes.Negate); - } - } - break; - case PatternSyntax.WildCard: - throw new NotImplementedException("Wildcard syntax is not supported."); - case PatternSyntax.ExactMatch: - res.InitialMatch = new ExactMatch(matchRes.IgnoreCase, parsedInputString, matchRes.Negate); - break; + ignoreCase = true; // default } + + bool negate; + if (!bool.TryParse(match.Attribute(RewriteTags.Negate)?.Value, out negate)) + { + negate = false; + } + builder.AddUrlMatch(parsedInputString, ignoreCase, negate, patternSyntax); } - private static void CreateConditions(XElement conditions, UrlRewriteRule res) + + + private static void ParseConditions(XElement conditions, UrlRewriteRuleBuilder builder, PatternSyntax patternSyntax) { - // This is to avoid nullptr exception on referencing conditions. - res.Conditions = new Conditions(); if (conditions == null) { return; } LogicalGrouping grouping; - if (Enum.TryParse(conditions.Attribute(RewriteTags.MatchType)?.Value, out grouping)) + if (!Enum.TryParse(conditions.Attribute(RewriteTags.MatchType)?.Value, out grouping)) { - res.Conditions.MatchType = grouping; + grouping = LogicalGrouping.MatchAll; } - bool parBool; - if (bool.TryParse(conditions.Attribute(RewriteTags.TrackingAllCaptures)?.Value, out parBool)) + bool trackingAllCaptures; + if (!bool.TryParse(conditions.Attribute(RewriteTags.TrackingAllCaptures)?.Value, out trackingAllCaptures)) { - res.Conditions.TrackingAllCaptures = parBool; + trackingAllCaptures = false; } + builder.AddUrlConditions(grouping, trackingAllCaptures); + foreach (var cond in conditions.Elements(RewriteTags.Add)) { - CreateCondition(cond, res); + ParseCondition(cond, builder, patternSyntax); } } - private static void CreateCondition(XElement condition, UrlRewriteRule res) + private static void ParseCondition(XElement condition, UrlRewriteRuleBuilder builder, PatternSyntax patternSyntax) { - var parsedCondRes = new ParsedCondition(); - - bool parBool; - if (bool.TryParse(condition.Attribute(RewriteTags.IgnoreCase)?.Value, out parBool)) + bool ignoreCase; + if (!bool.TryParse(condition.Attribute(RewriteTags.IgnoreCase)?.Value, out ignoreCase)) { - parsedCondRes.IgnoreCase = parBool; + ignoreCase = true; } - if (bool.TryParse(condition.Attribute(RewriteTags.Negate)?.Value, out parBool)) + bool negate; + if (!bool.TryParse(condition.Attribute(RewriteTags.Negate)?.Value, out negate)) { - parsedCondRes.Negate = parBool; + ignoreCase = false; } MatchType matchType; - if (Enum.TryParse(condition.Attribute(RewriteTags.MatchType)?.Value, out matchType)) + if (!Enum.TryParse(condition.Attribute(RewriteTags.MatchType)?.Value, out matchType)) { - parsedCondRes.MatchType = matchType; + matchType = MatchType.Pattern; } - var parsedString = condition.Attribute(RewriteTags.Input)?.Value; - if (parsedString == null) + var parsedInputString = condition.Attribute(RewriteTags.Input)?.Value; + if (parsedInputString == null) { ThrowUrlFormatException(condition, "Conditions must have an input attribute"); } + var parsedPatternString = condition.Attribute(RewriteTags.Pattern)?.Value; + Pattern input = null; try { - input = InputParser.ParseInputString(parsedString); + input = InputParser.ParseInputString(parsedInputString); + builder.AddUrlCondition(input, parsedPatternString, patternSyntax, matchType, ignoreCase, negate); + } catch (FormatException formatException) { ThrowUrlFormatException(condition, formatException.Message, formatException); } - - switch (res.PatternSyntax) - { - case PatternSyntax.ECMAScript: - { - switch (parsedCondRes.MatchType) - { - case MatchType.Pattern: - { - parsedString = condition.Attribute(RewriteTags.Pattern)?.Value; - if (parsedString == null) - { - ThrowUrlFormatException(condition, "Match does not have an associated pattern attribute in condition"); - - } - Regex regex = null; - - if (parsedCondRes.IgnoreCase) - { - regex = new Regex(parsedString, RegexOptions.Compiled | RegexOptions.IgnoreCase, RegexTimeout); - } - else - { - regex = new Regex(parsedString, RegexOptions.Compiled, RegexTimeout); - } - - res.Conditions.ConditionList.Add(new Condition { Input = input, Match = new RegexMatch(regex, parsedCondRes.Negate) }); - } - break; - case MatchType.IsDirectory: - { - res.Conditions.ConditionList.Add(new Condition { Input = input, Match = new IsDirectoryMatch(parsedCondRes.Negate) }); - } - break; - case MatchType.IsFile: - { - res.Conditions.ConditionList.Add(new Condition { Input = input, Match = new IsFileMatch(parsedCondRes.Negate) }); - } - break; - default: - // TODO don't this this can ever be thrown - ThrowUrlFormatException(condition, "Unrecognized matchType"); - break; - } - } - break; - case PatternSyntax.WildCard: - throw new NotImplementedException("Wildcard syntax is not supported"); - case PatternSyntax.ExactMatch: - parsedString = condition.Attribute(RewriteTags.Pattern)?.Value; - if (parsedString == null) - { - ThrowUrlFormatException(condition, "Pattern match does not have an associated pattern attribute in condition"); - } - res.Conditions.ConditionList.Add(new Condition { Input = input, Match = new ExactMatch(parsedCondRes.IgnoreCase, parsedString, parsedCondRes.Negate) }); - break; - default: - ThrowUrlFormatException(condition, "Unrecognized pattern syntax"); - break; - } } - private static void CreateUrlAction(XElement urlAction, UrlRewriteRule res, bool globalRule) + private static void ParseUrlAction(XElement urlAction, UrlRewriteRuleBuilder builder, bool stopProcessing) { - - var actionRes = new ParsedUrlAction(); - ActionType actionType; - if (Enum.TryParse(urlAction.Attribute(RewriteTags.Type)?.Value, out actionType)) + if (!Enum.TryParse(urlAction.Attribute(RewriteTags.Type)?.Value, out actionType)) { - actionRes.Type = actionType; + actionType = ActionType.None; } - bool parseBool; - if (bool.TryParse(urlAction.Attribute(RewriteTags.AppendQuery)?.Value, out parseBool)) + bool appendQuery; + if (!bool.TryParse(urlAction.Attribute(RewriteTags.AppendQueryString)?.Value, out appendQuery)) { - actionRes.AppendQueryString = parseBool; - } - - if (bool.TryParse(urlAction.Attribute(RewriteTags.LogRewrittenUrl)?.Value, out parseBool)) - { - actionRes.LogRewrittenUrl = parseBool; + appendQuery = true; } RedirectType redirectType; - if (Enum.TryParse(urlAction.Attribute(RewriteTags.RedirectType)?.Value, out redirectType)) + if (!Enum.TryParse(urlAction.Attribute(RewriteTags.RedirectType)?.Value, out redirectType)) { - actionRes.RedirectType = redirectType; + redirectType = RedirectType.Permanent; } try { - actionRes.Url = InputParser.ParseInputString(urlAction.Attribute(RewriteTags.Url)?.Value); + var input = InputParser.ParseInputString(urlAction.Attribute(RewriteTags.Url)?.Value); + builder.AddUrlAction(input, actionType, appendQuery, stopProcessing, (int)redirectType); } catch (FormatException formatException) { ThrowUrlFormatException(urlAction, formatException.Message, formatException); } - - CreateUrlActionFromParsedAction(urlAction, actionRes, globalRule, res); - } - - private static void CreateUrlActionFromParsedAction(XElement urlAction, ParsedUrlAction actionRes, bool globalRule, UrlRewriteRule res) - { - switch (actionRes.Type) - { - case ActionType.None: - res.Action = new VoidAction(); - break; - case ActionType.Rewrite: - if (actionRes.AppendQueryString) - { - res.Action = new RewriteAction(res.StopProcessing ? RuleTerminiation.StopRules : RuleTerminiation.Continue, actionRes.Url, clearQuery: false); - } - else - { - res.Action = new RewriteAction(res.StopProcessing ? RuleTerminiation.StopRules : RuleTerminiation.Continue, actionRes.Url, clearQuery: true); - } - break; - case ActionType.Redirect: - if (actionRes.AppendQueryString) - { - res.Action = new RedirectAction((int)actionRes.RedirectType, actionRes.Url); - } - else - { - res.Action = new RedirectClearQueryAction((int)actionRes.RedirectType, actionRes.Url); - } - break; - case ActionType.AbortRequest: - ThrowUrlFormatException(urlAction, "Abort Requests are not supported."); - break; - case ActionType.CustomResponse: - // TODO - ThrowUrlFormatException(urlAction, "Custom Responses are not supported"); - break; - } } private static void ThrowUrlFormatException(XElement element, string message) @@ -342,6 +218,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite var col = ((IXmlLineInfo)element).LinePosition; throw new FormatException(Resources.FormatError_UrlRewriteParseError(message, line, col)); } + private static void ThrowUrlFormatException(XElement element, string message, Exception ex) { var line = ((IXmlLineInfo)element).LineNumber; diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/UrlRewriteRuleBuilder.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/UrlRewriteRuleBuilder.cs new file mode 100644 index 0000000000..ccee529c0a --- /dev/null +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/UrlRewriteRuleBuilder.cs @@ -0,0 +1,168 @@ +// 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; +using System.Collections.Generic; +using System.Text.RegularExpressions; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite.UrlActions; +using Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite.UrlMatches; + +namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite +{ + public class UrlRewriteRuleBuilder + { + private readonly TimeSpan RegexTimeout = TimeSpan.FromMilliseconds(1); + + public string Name { get; set; } + public bool Enabled { get; set; } + + private UrlMatch _initialMatch; + private Conditions _conditions; + private UrlAction _action; + + public UrlRewriteRule Build() + { + // TODO some of these are required fields, throw if null? + var rule = new UrlRewriteRule(); + rule.Action = _action; + rule.Conditions = _conditions; + rule.InitialMatch = _initialMatch; + rule.Name = Name; + return rule; + } + + public void AddUrlAction(Pattern url, ActionType actionType = ActionType.None, bool appendQueryString = true, bool stopProcessing = false, int statusCode = StatusCodes.Status301MovedPermanently) + { + switch (actionType) + { + case ActionType.None: + _action = new VoidAction(); + break; + case ActionType.Rewrite: + if (appendQueryString) + { + _action = new RewriteAction(stopProcessing ? RuleTerminiation.StopRules : RuleTerminiation.Continue, url, clearQuery: false); + } + else + { + _action = new RewriteAction(stopProcessing ? RuleTerminiation.StopRules : RuleTerminiation.Continue, url, clearQuery: true); + } + break; + case ActionType.Redirect: + if (appendQueryString) + { + _action = new RedirectAction(statusCode, url); + } + else + { + _action = new RedirectClearQueryAction(statusCode, url); + } + break; + case ActionType.AbortRequest: + throw new FormatException("Abort Requests are not supported"); + case ActionType.CustomResponse: + // TODO + throw new FormatException("Custom Responses are not supported"); + } + } + + public void AddUrlMatch(string input, bool ignoreCase = true, bool negate = false, PatternSyntax patternSyntax = PatternSyntax.ECMAScript) + { + switch (patternSyntax) + { + case PatternSyntax.ECMAScript: + { + if (ignoreCase) + { + var regex = new Regex(input, RegexOptions.Compiled | RegexOptions.IgnoreCase, RegexTimeout); + _initialMatch = new RegexMatch(regex, negate); + } + else + { + var regex = new Regex(input, RegexOptions.Compiled, RegexTimeout); + _initialMatch = new RegexMatch(regex, negate); + } + break; + } + case PatternSyntax.WildCard: + throw new NotImplementedException("Wildcard syntax is not supported"); + case PatternSyntax.ExactMatch: + _initialMatch = new ExactMatch(ignoreCase, input, negate); + break; + } + } + + // TODO make this take two overloads and handle regex vs non regex case. + public void AddUrlCondition(Pattern input, string pattern, PatternSyntax patternSyntax, MatchType matchType, bool ignoreCase, bool negate) + { + if (_conditions == null) + { + AddUrlConditions(LogicalGrouping.MatchAll, trackingAllCaptures: false); + } + switch (patternSyntax) + { + case PatternSyntax.ECMAScript: + { + switch (matchType) + { + case MatchType.Pattern: + { + if (pattern == null) + { + throw new FormatException("Match does not have an associated pattern attribute in condition"); + } + + Regex regex = null; + if (ignoreCase) + { + regex = new Regex(pattern, RegexOptions.Compiled | RegexOptions.IgnoreCase, RegexTimeout); + } + else + { + regex = new Regex(pattern, RegexOptions.Compiled, RegexTimeout); + } + + _conditions.ConditionList.Add(new Condition { Input = input, Match = new RegexMatch(regex, negate) }); + break; + } + case MatchType.IsDirectory: + { + _conditions.ConditionList.Add(new Condition { Input = input, Match = new IsDirectoryMatch(negate) }); + break; + } + case MatchType.IsFile: + { + _conditions.ConditionList.Add(new Condition { Input = input, Match = new IsFileMatch(negate) }); + break; + } + default: + // TODO new exception handling + throw new FormatException("Unrecognized matchType"); + } + break; + } + case PatternSyntax.WildCard: + throw new NotImplementedException("Wildcard syntax is not supported"); + case PatternSyntax.ExactMatch: + if (pattern == null) + { + throw new FormatException("Match does not have an associated pattern attribute in condition"); + } + _conditions.ConditionList.Add(new Condition { Input = input, Match = new ExactMatch(ignoreCase, pattern, negate) }); + break; + default: + throw new FormatException("Unrecognized pattern syntax"); + } + } + + public void AddUrlConditions(LogicalGrouping logicalGrouping, bool trackingAllCaptures) + { + var conditions = new Conditions(); + conditions.ConditionList = new List(); + conditions.MatchType = logicalGrouping; + conditions.TrackingAllCaptures = trackingAllCaptures; + _conditions = conditions; + } + } +} diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewriteRule.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewriteRule.cs index 9bd9c7e155..4295548204 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewriteRule.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewriteRule.cs @@ -7,8 +7,6 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite { public string Name { get; set; } public bool Enabled { get; set; } = true; - public PatternSyntax PatternSyntax { get; set; } - public bool StopProcessing { get; set; } public UrlMatch InitialMatch { get; set; } public Conditions Conditions { get; set; } public UrlAction Action { get; set; } @@ -19,8 +17,10 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite { return RuleResult.Continue; } + // Due to the path string always having a leading slash, // remove it from the path before regex comparison + // TODO may need to check if there is a leading slash and remove conditionally var initMatchRes = InitialMatch.Evaluate(context.HttpContext.Request.Path.ToString().Substring(1), context); if (!initMatchRes.Success) @@ -28,10 +28,14 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite return RuleResult.Continue; } - var condMatchRes = Conditions.Evaluate(context, initMatchRes); - if (!condMatchRes.Success) + MatchResults condMatchRes = null; + if (Conditions != null) { - return RuleResult.Continue; + condMatchRes = Conditions.Evaluate(context, initMatchRes); + if (!condMatchRes.Success) + { + return RuleResult.Continue; + } } // at this point we know the rule passed, evaluate the replacement. diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/CodeRules/MiddlewareTests.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/CodeRules/MiddlewareTests.cs new file mode 100644 index 0000000000..1f08becb6c --- /dev/null +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/CodeRules/MiddlewareTests.cs @@ -0,0 +1,90 @@ +// 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; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.TestHost; +using Xunit; + +namespace Microsoft.AspNetCore.Rewrite.Tests.CodeRules +{ + public class MiddlewareTests + { + [Fact] + public async Task CheckRewritePath() + { + var options = new RewriteOptions().RewriteRule("(.*)", "http://example.com/{R:1}"); + var builder = new WebHostBuilder() + .Configure(app => + { + app.UseRewriter(options); + app.UseRewriter(options); + app.Run(context => context.Response.WriteAsync( + context.Request.Scheme + + "://" + + context.Request.Host + + context.Request.Path + + context.Request.QueryString)); + }); + var server = new TestServer(builder); + + var response = await server.CreateClient().GetStringAsync("foo"); + + Assert.Equal(response, "http://example.com/foo"); + } + + [Fact] + public async Task CheckRedirectPath() + { + var options = new RewriteOptions().RedirectRule("(.*)","http://example.com/{R:1}", statusCode: 301); + var builder = new WebHostBuilder() + .Configure(app => + { + app.UseRewriter(options); + }); + var server = new TestServer(builder); + + var response = await server.CreateClient().GetAsync("foo"); + + Assert.Equal(response.Headers.Location.OriginalString, "http://example.com/foo"); + } + + [Fact] + public async Task CheckRewriteToHttps() + { + var options = new RewriteOptions().RewriteToHttps(); + var builder = new WebHostBuilder() + .Configure(app => + { + app.UseRewriter(options); + app.UseRewriter(options); + app.Run(context => context.Response.WriteAsync( + context.Request.Scheme)); + }); + var server = new TestServer(builder); + + var response = await server.CreateClient().GetStringAsync(new Uri("http://example.com")); + + Assert.Equal(response, "https"); + } + + [Fact] + public async Task CheckRedirectToHttps() + { + var options = new RewriteOptions().RedirectToHttps(statusCode: 301); + var builder = new WebHostBuilder() + .Configure(app => + { + app.UseRewriter(options); + }); + var server = new TestServer(builder); + + var response = await server.CreateClient().GetAsync(new Uri("http://example.com")); + + Assert.Equal(response.Headers.Location.OriginalString, "https://example.com/"); + } + } +} diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/UrlRewrite/FileParserTests.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/UrlRewrite/FileParserTests.cs index 4cdfe347aa..214bc87991 100644 --- a/test/Microsoft.AspNetCore.Rewrite.Tests/UrlRewrite/FileParserTests.cs +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/UrlRewrite/FileParserTests.cs @@ -150,8 +150,6 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite Action = new RewriteAction(RuleTerminiation.Continue, InputParser.ParseInputString(Url), clearQuery: false), Name = name, Enabled = enabled, - StopProcessing = stopProcessing, - PatternSyntax = patternSyntax, InitialMatch = new RegexMatch(new Regex("^OFF$"), false) { }, @@ -164,29 +162,37 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite }; } - private void AssertUrlRewriteRuleEquality(List expected, List actual) + private void AssertUrlRewriteRuleEquality(List actual, List expected) { - Assert.Equal(expected.Count, actual.Count); - for (var i = 0; i < expected.Count; i++) + Assert.Equal(actual.Count, expected.Count); + for (var i = 0; i < actual.Count; i++) { - var r1 = expected[i]; - var r2 = actual[i]; + var r1 = actual[i]; + var r2 = expected[i]; Assert.Equal(r1.Name, r2.Name); Assert.Equal(r1.Enabled, r2.Enabled); - Assert.Equal(r1.StopProcessing, r2.StopProcessing); - Assert.Equal(r1.PatternSyntax, r2.PatternSyntax); // TODO conditions, url pattern, initial match regex - Assert.Equal(r1.Conditions.MatchType, r2.Conditions.MatchType); - Assert.Equal(r1.Conditions.TrackingAllCaptures, r2.Conditions.TrackingAllCaptures); - Assert.Equal(r1.Conditions.ConditionList.Count, r2.Conditions.ConditionList.Count); - - for (var j = 0; j < r1.Conditions.ConditionList.Count; j++) + if (r1.Conditions == null) { - var c1 = r1.Conditions.ConditionList[j]; - var c2 = r2.Conditions.ConditionList[j]; - Assert.Equal(c1.Input.PatternSegments.Count, c2.Input.PatternSegments.Count); + Assert.Equal(r2.Conditions.ConditionList.Count, 0); + } + else if (r2.Conditions == null) + { + Assert.Equal(r1.Conditions.ConditionList.Count, 0); + } + else + { + Assert.Equal(r1.Conditions.MatchType, r2.Conditions.MatchType); + Assert.Equal(r1.Conditions.TrackingAllCaptures, r2.Conditions.TrackingAllCaptures); + Assert.Equal(r1.Conditions.ConditionList.Count, r2.Conditions.ConditionList.Count); + for (var j = 0; j < r1.Conditions.ConditionList.Count; j++) + { + var c1 = r1.Conditions.ConditionList[j]; + var c2 = r2.Conditions.ConditionList[j]; + Assert.Equal(c1.Input.PatternSegments.Count, c2.Input.PatternSegments.Count); + } } } } diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/UrlRewrite/FormatExceptionHandlingTests.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/UrlRewrite/FormatExceptionHandlingTests.cs index 6a4f5f47e0..7ba0bc07a0 100644 --- a/test/Microsoft.AspNetCore.Rewrite.Tests/UrlRewrite/FormatExceptionHandlingTests.cs +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/UrlRewrite/FormatExceptionHandlingTests.cs @@ -38,7 +38,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite ", - "Could not parse the UrlRewrite file. Message: 'Abort Requests are not supported.'. Line number '5': '14'.")] + "Could not parse the UrlRewrite file. Message: 'Abort Requests are not supported'. Line number '5': '14'.")] [InlineData( @" @@ -54,6 +54,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite + ", diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/UrlRewrite/MiddleWareTests.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/UrlRewrite/MiddleWareTests.cs index a34101b375..f2018d20b9 100644 --- a/test/Microsoft.AspNetCore.Rewrite.Tests/UrlRewrite/MiddleWareTests.cs +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/UrlRewrite/MiddleWareTests.cs @@ -19,13 +19,13 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite public async Task Invoke_RedirectPathToPathAndQuery() { var options = new RewriteOptions().ImportFromUrlRewrite(new StringReader(@" - - - - - - - ")); + + + + + + + ")); var builder = new WebHostBuilder() .Configure(app => { @@ -43,13 +43,13 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite public async Task Invoke_RewritePathToPathAndQuery() { var options = new RewriteOptions().ImportFromUrlRewrite(new StringReader(@" - - - - - - - ")); + + + + + + + ")); var builder = new WebHostBuilder() .Configure(app => { @@ -121,13 +121,13 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite var options = new RewriteOptions().ImportFromUrlRewrite(new StringReader(@" - - - - - - - + + + + + + + ")); var builder = new WebHostBuilder() @@ -148,13 +148,13 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite var options = new RewriteOptions().ImportFromUrlRewrite(new StringReader(@" - - - - - - - + + + + + + + ")); var builder = new WebHostBuilder() @@ -174,13 +174,13 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite { var options = new RewriteOptions().ImportFromUrlRewrite(new StringReader(@" - - - - - - - + + + + + + + ")); var builder = new WebHostBuilder() @@ -200,13 +200,13 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite { var options = new RewriteOptions().ImportFromUrlRewrite(new StringReader(@" - - - - - - - + + + + + + + ")); var builder = new WebHostBuilder() @@ -214,10 +214,10 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite { app.UseRewriter(options); app.Run(context => context.Response.WriteAsync( - context.Request.Scheme + + context.Request.Scheme + "://" + context.Request.Host + - context.Request.Path + + context.Request.Path + context.Request.QueryString)); }); var server = new TestServer(builder); @@ -232,10 +232,10 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite { var options = new RewriteOptions().ImportFromUrlRewrite(new StringReader(@" - - - - + + + + ")); var builder = new WebHostBuilder() From 7a560738353690fa3c6d1f5eaff43b9d384af57b Mon Sep 17 00:00:00 2001 From: Justin Kotalik Date: Wed, 10 Aug 2016 14:56:42 -0700 Subject: [PATCH 092/307] Mod_rewrite refactor with cleanup --- samples/RewriteSample/Rewrite.txt | 3 +- samples/RewriteSample/Startup.cs | 19 +- samples/RewriteSample/UrlRewrite.xml | 10 +- .../Internal/CodeRules/RedirectToHttpsRule.cs | 2 - .../Internal/CodeRules/RewriteToHttpsRule.cs | 14 +- .../Internal/{UrlRewrite => }/Condition.cs | 6 +- .../Internal/Conditions.cs | 43 +++ .../Internal/{UrlRewrite => }/MatchResults.cs | 5 +- .../Internal/ModRewrite/Condition.cs | 18 -- .../Internal/ModRewrite/ConditionBuilder.cs | 94 ------ .../ModRewrite/ConditionExpression.cs | 29 -- .../Internal/ModRewrite/ConditionFlagType.cs | 12 - .../Internal/ModRewrite/ConditionFlags.cs | 101 ------- .../ModRewrite/ConditionPatternParser.cs | 98 +++--- .../Internal/ModRewrite/ExpressionCreator.cs | 127 -------- .../Internal/ModRewrite/FileParser.cs | 91 +++--- .../Internal/ModRewrite/FlagParser.cs | 83 +----- .../{RuleFlagType.cs => FlagType.cs} | 6 +- .../Internal/ModRewrite/Flags.cs | 125 ++++++++ .../ModRewrite/ModRewriteRedirectAction.cs | 77 +++++ .../ModRewrite/ModRewriteRewriteAction.cs | 98 ++++++ .../Internal/ModRewrite/Operands/Operand.cs | 13 - .../ModRewrite/Operands/PropertyOperand.cs | 44 --- .../ModRewrite/Operands/PropertyOperation.cs | 17 -- .../ModRewrite/Operands/RegexOperand.cs | 24 -- .../ModRewrite/Operands/StringOperand.cs | 40 --- ...ession.cs => ParsedModRewriteCondition.cs} | 17 +- .../Internal/ModRewrite/Pattern.cs | 67 ----- .../Internal/ModRewrite/PatternSegment.cs | 26 -- .../Internal/ModRewrite/RuleBuilder.cs | 278 ++++++++++++------ .../Internal/ModRewrite/RuleExpression.cs | 13 - .../Internal/ModRewrite/RuleFlags.cs | 133 --------- .../Internal/ModRewrite/RuleRegexParser.cs | 10 +- .../Internal/ModRewrite/SegmentType.cs | 2 +- .../Internal/ModRewrite/ServerVariables.cs | 159 ++++------ ...estStringParser.cs => TestStringParser.cs} | 85 ++---- .../Internal/ModRewrite/Tokenizer.cs | 3 +- .../Internal/ModRewriteRule.cs | 196 ++---------- .../Internal/ParserContext.cs | 12 +- .../Internal/{UrlRewrite => }/Pattern.cs | 14 +- .../{UrlRewrite => }/PatternSegment.cs | 5 +- .../PatternSegments/ConditionMatchSegment.cs | 6 +- .../PatternSegments/DateTimeSegment.cs | 81 +++++ .../PatternSegments/HeaderSegment.cs | 8 +- .../PatternSegments/IsHttpsModSegment.cs | 13 + .../PatternSegments/IsHttpsSegment.cs | 13 + .../Internal/PatternSegments/IsIPV6Segment.cs | 20 ++ .../PatternSegments/LiteralSegment.cs | 6 +- .../PatternSegments/LocalAddressSegment.cs | 13 + .../PatternSegments/LocalPortSegment.cs | 15 + .../PatternSegments/QueryStringSegment.cs | 13 + .../PatternSegments/RemoteAddressSegment.cs | 13 + .../PatternSegments/RemotePortSegment.cs | 15 + .../PatternSegments/RequestFilenameSegment.cs | 8 +- .../PatternSegments/RequestMethodSegment.cs | 13 + .../PatternSegments/RuleMatchSegment.cs | 6 +- .../Internal/PatternSegments/SchemeSegment.cs | 13 + .../PatternSegments/ServerProtocolSegment.cs | 15 + .../PatternSegments/ToLowerSegment.cs | 11 +- .../PatternSegments/UrlEncodeSegment.cs | 9 +- .../Internal/PatternSegments/UrlSegment.cs | 13 + .../Internal/PreAction.cs | 11 + .../PreActions/ChangeCookiePreAction.cs | 23 ++ .../PreActions/ChangeEnvironmentPreAction.cs | 22 ++ .../Internal/{UrlRewrite => }/UrlAction.cs | 5 +- .../Internal/UrlActions/ForbiddenAction.cs | 16 + .../Internal/UrlActions/GoneAction.cs | 16 + .../UrlActions/RedirectAction.cs | 15 +- .../UrlActions/RedirectClearQueryAction.cs | 9 +- .../UrlActions/RewriteAction.cs | 32 +- .../{UrlRewrite => }/UrlActions/VoidAction.cs | 5 +- .../Internal/{UrlRewrite => }/UrlMatch.cs | 2 +- .../{UrlRewrite => }/UrlMatches/ExactMatch.cs | 2 +- .../Internal/UrlMatches/FileSizeMatch.cs | 19 ++ .../IntegerMatch.cs} | 29 +- .../IntegerOperation.cs | 2 +- .../UrlMatches/IsDirectoryMatch.cs | 2 +- .../UrlMatches/IsFileMatch.cs | 2 +- .../{UrlRewrite => }/UrlMatches/RegexMatch.cs | 2 +- .../Internal/UrlMatches/StringMatch.cs | 36 +++ .../StringOperation.cs | 2 +- .../Internal/UrlRewrite/Conditions.cs | 27 -- .../Internal/UrlRewrite/InputParser.cs | 5 +- .../PatternSegments/IsHttpsSegment.cs | 15 - .../PatternSegments/LocalAddressSegment.cs | 15 - .../PatternSegments/QueryStringSegment.cs | 15 - .../PatternSegments/RemoteAddressSegment.cs | 15 - .../PatternSegments/RemotePortSegment.cs | 16 - .../UrlRewrite/PatternSegments/UrlSegment.cs | 15 - .../Internal/UrlRewrite/ServerVariables.cs | 9 +- .../UrlRewrite/UrlRewriteFileParser.cs | 3 +- .../UrlRewrite/UrlRewriteRuleBuilder.cs | 19 +- .../Internal/UrlRewriteRule.cs | 9 +- .../ModRewriteExtensions.cs | 7 +- .../Properties/Resources.Designer.cs | 32 ++ .../Resources.resx | 6 + .../RewriteContext.cs | 3 + .../ModRewrite/ConditionActionTest.cs | 16 +- .../ModRewrite/FlagParserTest.cs | 32 +- .../ModRewrite/FormatExceptionTests.cs | 38 +++ .../ModRewriteConditionBuilderTest.cs | 50 ---- .../ModRewrite/ModRewriteFlagTest.cs | 88 ------ .../ModRewrite/ModRewriteMiddlewareTest.cs | 18 +- .../UrlRewrite/FileParserTests.cs | 10 +- .../UrlRewrite/InputParserTests.cs | 13 +- .../UrlRewrite/ServerVariableTests.cs | 5 +- 106 files changed, 1421 insertions(+), 1835 deletions(-) rename src/Microsoft.AspNetCore.Rewrite/Internal/{UrlRewrite => }/Condition.cs (74%) create mode 100644 src/Microsoft.AspNetCore.Rewrite/Internal/Conditions.cs rename src/Microsoft.AspNetCore.Rewrite/Internal/{UrlRewrite => }/MatchResults.cs (55%) delete mode 100644 src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/Condition.cs delete mode 100644 src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/ConditionBuilder.cs delete mode 100644 src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/ConditionExpression.cs delete mode 100644 src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/ConditionFlagType.cs delete mode 100644 src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/ConditionFlags.cs delete mode 100644 src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/ExpressionCreator.cs rename src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/{RuleFlagType.cs => FlagType.cs} (87%) create mode 100644 src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/Flags.cs create mode 100644 src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/ModRewriteRedirectAction.cs create mode 100644 src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/ModRewriteRewriteAction.cs delete mode 100644 src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/Operands/Operand.cs delete mode 100644 src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/Operands/PropertyOperand.cs delete mode 100644 src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/Operands/PropertyOperation.cs delete mode 100644 src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/Operands/RegexOperand.cs delete mode 100644 src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/Operands/StringOperand.cs rename src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/{ParsedConditionExpression.cs => ParsedModRewriteCondition.cs} (50%) delete mode 100644 src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/Pattern.cs delete mode 100644 src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/PatternSegment.cs delete mode 100644 src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/RuleExpression.cs delete mode 100644 src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/RuleFlags.cs rename src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/{ConditionTestStringParser.cs => TestStringParser.cs} (72%) rename src/Microsoft.AspNetCore.Rewrite/Internal/{UrlRewrite => }/Pattern.cs (61%) rename src/Microsoft.AspNetCore.Rewrite/Internal/{UrlRewrite => }/PatternSegment.cs (62%) rename src/Microsoft.AspNetCore.Rewrite/Internal/{UrlRewrite => }/PatternSegments/ConditionMatchSegment.cs (67%) create mode 100644 src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/DateTimeSegment.cs rename src/Microsoft.AspNetCore.Rewrite/Internal/{UrlRewrite => }/PatternSegments/HeaderSegment.cs (59%) create mode 100644 src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/IsHttpsModSegment.cs create mode 100644 src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/IsHttpsSegment.cs create mode 100644 src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/IsIPV6Segment.cs rename src/Microsoft.AspNetCore.Rewrite/Internal/{UrlRewrite => }/PatternSegments/LiteralSegment.cs (66%) create mode 100644 src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/LocalAddressSegment.cs create mode 100644 src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/LocalPortSegment.cs create mode 100644 src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/QueryStringSegment.cs create mode 100644 src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/RemoteAddressSegment.cs create mode 100644 src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/RemotePortSegment.cs rename src/Microsoft.AspNetCore.Rewrite/Internal/{UrlRewrite => }/PatternSegments/RequestFilenameSegment.cs (50%) create mode 100644 src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/RequestMethodSegment.cs rename src/Microsoft.AspNetCore.Rewrite/Internal/{UrlRewrite => }/PatternSegments/RuleMatchSegment.cs (67%) create mode 100644 src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/SchemeSegment.cs create mode 100644 src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/ServerProtocolSegment.cs rename src/Microsoft.AspNetCore.Rewrite/Internal/{UrlRewrite => }/PatternSegments/ToLowerSegment.cs (51%) rename src/Microsoft.AspNetCore.Rewrite/Internal/{UrlRewrite => }/PatternSegments/UrlEncodeSegment.cs (63%) create mode 100644 src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/UrlSegment.cs create mode 100644 src/Microsoft.AspNetCore.Rewrite/Internal/PreAction.cs create mode 100644 src/Microsoft.AspNetCore.Rewrite/Internal/PreActions/ChangeCookiePreAction.cs create mode 100644 src/Microsoft.AspNetCore.Rewrite/Internal/PreActions/ChangeEnvironmentPreAction.cs rename src/Microsoft.AspNetCore.Rewrite/Internal/{UrlRewrite => }/UrlAction.cs (57%) create mode 100644 src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/ForbiddenAction.cs create mode 100644 src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/GoneAction.cs rename src/Microsoft.AspNetCore.Rewrite/Internal/{UrlRewrite => }/UrlActions/RedirectAction.cs (58%) rename src/Microsoft.AspNetCore.Rewrite/Internal/{UrlRewrite => }/UrlActions/RedirectClearQueryAction.cs (67%) rename src/Microsoft.AspNetCore.Rewrite/Internal/{UrlRewrite => }/UrlActions/RewriteAction.cs (58%) rename src/Microsoft.AspNetCore.Rewrite/Internal/{UrlRewrite => }/UrlActions/VoidAction.cs (61%) rename src/Microsoft.AspNetCore.Rewrite/Internal/{UrlRewrite => }/UrlMatch.cs (85%) rename src/Microsoft.AspNetCore.Rewrite/Internal/{UrlRewrite => }/UrlMatches/ExactMatch.cs (91%) create mode 100644 src/Microsoft.AspNetCore.Rewrite/Internal/UrlMatches/FileSizeMatch.cs rename src/Microsoft.AspNetCore.Rewrite/Internal/{ModRewrite/Operands/IntegerOperand.cs => UrlMatches/IntegerMatch.cs} (52%) rename src/Microsoft.AspNetCore.Rewrite/Internal/{ModRewrite/Operands => UrlMatches}/IntegerOperation.cs (82%) rename src/Microsoft.AspNetCore.Rewrite/Internal/{UrlRewrite => }/UrlMatches/IsDirectoryMatch.cs (89%) rename src/Microsoft.AspNetCore.Rewrite/Internal/{UrlRewrite => }/UrlMatches/IsFileMatch.cs (88%) rename src/Microsoft.AspNetCore.Rewrite/Internal/{UrlRewrite => }/UrlMatches/RegexMatch.cs (91%) create mode 100644 src/Microsoft.AspNetCore.Rewrite/Internal/UrlMatches/StringMatch.cs rename src/Microsoft.AspNetCore.Rewrite/Internal/{ModRewrite/Operands => UrlMatches}/StringOperation.cs (81%) delete mode 100644 src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/Conditions.cs delete mode 100644 src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/PatternSegments/IsHttpsSegment.cs delete mode 100644 src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/PatternSegments/LocalAddressSegment.cs delete mode 100644 src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/PatternSegments/QueryStringSegment.cs delete mode 100644 src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/PatternSegments/RemoteAddressSegment.cs delete mode 100644 src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/PatternSegments/RemotePortSegment.cs delete mode 100644 src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/PatternSegments/UrlSegment.cs create mode 100644 test/Microsoft.AspNetCore.Rewrite.Tests/ModRewrite/FormatExceptionTests.cs delete mode 100644 test/Microsoft.AspNetCore.Rewrite.Tests/ModRewrite/ModRewriteConditionBuilderTest.cs delete mode 100644 test/Microsoft.AspNetCore.Rewrite.Tests/ModRewrite/ModRewriteFlagTest.cs diff --git a/samples/RewriteSample/Rewrite.txt b/samples/RewriteSample/Rewrite.txt index ed2ae33ce1..574f251600 100644 --- a/samples/RewriteSample/Rewrite.txt +++ b/samples/RewriteSample/Rewrite.txt @@ -1,7 +1,6 @@ # Ensure Https RewriteCond %{HTTPS} off -# U is a new flag to represent full URL rewrites -RewriteRule ^(.*)$ https://www.example.com$1 [L,U] +RewriteRule ^(.*)$ https://www.example.com$1 [L] # Rewrite path with additional sub directory RewriteRule ^(.*)$ /foo$1 diff --git a/samples/RewriteSample/Startup.cs b/samples/RewriteSample/Startup.cs index b83d5677e7..1dbcb048e5 100644 --- a/samples/RewriteSample/Startup.cs +++ b/samples/RewriteSample/Startup.cs @@ -27,18 +27,17 @@ namespace RewriteSample // AddFunctionalRule(Func); // TODO make this startup do something useful. app.UseRewriter(new RewriteOptions() - .ImportFromUrlRewrite(hostingEnv, "UrlRewrite.xml") - .ImportFromModRewrite(hostingEnv, "Rewrite.txt") - .RedirectToHttps(StatusCodes.Status307TemporaryRedirect) - .RewriteRule("/foo/(.*)/bar", "{R:1}/bar") - .AddRule(ctx => - { - ctx.HttpContext.Request.Path = "/index"; - return RuleResult.Continue; - })); + .ImportFromUrlRewrite(hostingEnv, "UrlRewrite.xml") + .ImportFromModRewrite(hostingEnv, "Rewrite.txt") + .RedirectToHttps(StatusCodes.Status307TemporaryRedirect) + .RewriteRule("/foo/(.*)/bar", "{R:1}/bar") + .AddRule(ctx => + { + ctx.HttpContext.Request.Path = "/index"; + return RuleResult.Continue; + })); app.Run(context => context.Response.WriteAsync(context.Request.Path)); - } public static void Main(string[] args) diff --git a/samples/RewriteSample/UrlRewrite.xml b/samples/RewriteSample/UrlRewrite.xml index 4f5bac7a31..9ef1097666 100644 --- a/samples/RewriteSample/UrlRewrite.xml +++ b/samples/RewriteSample/UrlRewrite.xml @@ -1,12 +1,8 @@  - - - - - - - + + + \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/CodeRules/RedirectToHttpsRule.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/CodeRules/RedirectToHttpsRule.cs index 3dd9d6df39..04b1c8dd97 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/CodeRules/RedirectToHttpsRule.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/CodeRules/RedirectToHttpsRule.cs @@ -12,8 +12,6 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.CodeRules public int StatusCode { get; set; } public override RuleResult ApplyRule(RewriteContext context) { - - // TODO this only does http to https, add more features in the future. if (!context.HttpContext.Request.IsHttps) { var host = context.HttpContext.Request.Host; diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/CodeRules/RewriteToHttpsRule.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/CodeRules/RewriteToHttpsRule.cs index cccb76e6d1..e276baa85b 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/CodeRules/RewriteToHttpsRule.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/CodeRules/RewriteToHttpsRule.cs @@ -1,4 +1,6 @@ - +// 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 Microsoft.AspNetCore.Http; namespace Microsoft.AspNetCore.Rewrite.Internal.CodeRules @@ -10,7 +12,6 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.CodeRules public int? SSLPort { get; set; } public override RuleResult ApplyRule(RewriteContext context) { - // TODO this only does http to https, add more features in the future. if (!context.HttpContext.Request.IsHttps) { var host = context.HttpContext.Request.Host; @@ -27,14 +28,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.CodeRules context.HttpContext.Request.Scheme = "https"; context.HttpContext.Request.Host = host; - if (stopProcessing) - { - return RuleResult.StopRules; - } - else - { - return RuleResult.Continue; - } + return stopProcessing ? RuleResult.StopRules: RuleResult.Continue; } return RuleResult.Continue; } diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/Condition.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/Condition.cs similarity index 74% rename from src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/Condition.cs rename to src/Microsoft.AspNetCore.Rewrite/Internal/Condition.cs index f6541d48f9..5c60e38d82 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/Condition.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/Condition.cs @@ -1,15 +1,17 @@ // 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. -namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite +namespace Microsoft.AspNetCore.Rewrite.Internal { public class Condition { public Pattern Input { get; set; } public UrlMatch Match { get; set; } + public bool OrNext { get; set; } + public MatchResults Evaluate(RewriteContext context, MatchResults ruleMatch, MatchResults condMatch) { - var pattern = Input.Evaluate(context.HttpContext, ruleMatch, condMatch); + var pattern = Input.Evaluate(context, ruleMatch, condMatch); return Match.Evaluate(pattern, context); } } diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/Conditions.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/Conditions.cs new file mode 100644 index 0000000000..d8154c6b1d --- /dev/null +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/Conditions.cs @@ -0,0 +1,43 @@ +// 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.Collections.Generic; + +namespace Microsoft.AspNetCore.Rewrite.Internal +{ + public class Conditions + { + public List ConditionList { get; set; } = new List(); + + public MatchResults Evaluate(RewriteContext context, MatchResults ruleMatch) + { + MatchResults prevCond = null; + var orSucceeded = false; + foreach (var condition in ConditionList) + { + if (orSucceeded && condition.OrNext) + { + continue; + } + else if (orSucceeded) + { + orSucceeded = false; + continue; + } + + prevCond = condition.Evaluate(context, ruleMatch, prevCond); + + if (condition.OrNext) + { + orSucceeded = prevCond.Success; + continue; + } + else if (!prevCond.Success) + { + return prevCond; + } + } + return prevCond; + } + } +} diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/MatchResults.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/MatchResults.cs similarity index 55% rename from src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/MatchResults.cs rename to src/Microsoft.AspNetCore.Rewrite/Internal/MatchResults.cs index 6f182109f8..71eb20b8da 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/MatchResults.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/MatchResults.cs @@ -3,10 +3,13 @@ using System.Text.RegularExpressions; -namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite +namespace Microsoft.AspNetCore.Rewrite.Internal { public class MatchResults { + public static readonly MatchResults EmptySuccess = new MatchResults { BackReference = null, Success = true }; + public static readonly MatchResults EmptyFailure = new MatchResults { BackReference = null, Success = false }; + public GroupCollection BackReference { get; set; } public bool Success { get; set; } } diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/Condition.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/Condition.cs deleted file mode 100644 index e1af53bda7..0000000000 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/Condition.cs +++ /dev/null @@ -1,18 +0,0 @@ -// 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. - -namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite -{ - public class Condition - { - public Pattern TestStringSegments { get; } - public ConditionExpression ConditionExpression { get; } - public ConditionFlags Flags { get; } - public Condition(Pattern testStringSegments, ConditionExpression conditionRegex, ConditionFlags flags) - { - TestStringSegments = testStringSegments; - ConditionExpression = conditionRegex; - Flags = flags; - } - } -} diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/ConditionBuilder.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/ConditionBuilder.cs deleted file mode 100644 index 743b2d8a33..0000000000 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/ConditionBuilder.cs +++ /dev/null @@ -1,94 +0,0 @@ -// 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; - -namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite -{ - public class ConditionBuilder - { - private Pattern _testString; - private ParsedModRewriteExpression _pce; - private ConditionFlags _flags; - - public ConditionBuilder(string conditionString) - { - var tokens = Tokenizer.Tokenize(conditionString); - if (tokens.Count == 3) - { - CreateCondition(tokens[1], tokens[2], flagsString: null); - } - else if (tokens.Count == 4) - { - CreateCondition(tokens[1], tokens[2], tokens[3]); - } - else - { - throw new FormatException("Invalid number of tokens."); - } - } - - public ConditionBuilder(string testString, string condition) - { - CreateCondition(testString, condition, flagsString: null); - } - - public ConditionBuilder(string testString, string condition, string flags) - { - CreateCondition(testString, condition, flags); - } - - public Condition Build() - { - var expression = ExpressionCreator.CreateConditionExpression(_pce, _flags); - return new Condition(_testString, expression, _flags); - } - - private void CreateCondition(string testString, string condition, string flagsString) - { - _testString = ConditionTestStringParser.ParseConditionTestString(testString); - _pce = ConditionPatternParser.ParseActionCondition(condition); - _flags = FlagParser.ParseConditionFlags(flagsString); - } - - public void SetFlag(string flag) - { - SetFlag(flag, value: null); - } - - public void SetFlag(ConditionFlagType flag) - { - SetFlag(flag, value: null); - } - - public void SetFlag(string flag, string value) - { - if (_flags == null) - { - _flags = new ConditionFlags(); - } - _flags.SetFlag(flag, value); - } - - public void SetFlag(ConditionFlagType flag, string value) - { - if (_flags == null) - { - _flags = new ConditionFlags(); - } - _flags.SetFlag(flag, value); - } - - public void SetFlags(string flags) - { - if (_flags == null) - { - _flags = FlagParser.ParseConditionFlags(flags); - } - else - { - FlagParser.ParseConditionFlags(flags, _flags); - } - } - } -} diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/ConditionExpression.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/ConditionExpression.cs deleted file mode 100644 index 4d16a03ede..0000000000 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/ConditionExpression.cs +++ /dev/null @@ -1,29 +0,0 @@ -// 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.Text.RegularExpressions; -using Microsoft.AspNetCore.Rewrite.Internal.ModRewrite.Operands; - -namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite -{ - /// - /// Represents the ConditionPattern for a mod_rewrite rule. - /// - public class ConditionExpression - { - public Operand Operand { get; set; } - public bool Invert { get; set; } - - /// - /// Checks if a condition matches the context. - /// - /// The UrlRewriteContext. - /// The previous condition results (for backreferences). - /// The testString created from the . - /// If the testString satisfies the condition - public bool? CheckConditionExpression(RewriteContext context, Match previous, string testString) - { - return Operand.CheckOperation(previous, testString, context.FileProvider) ^ Invert; - } - } -} diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/ConditionFlagType.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/ConditionFlagType.cs deleted file mode 100644 index 06c7559090..0000000000 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/ConditionFlagType.cs +++ /dev/null @@ -1,12 +0,0 @@ -// 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. - -namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite -{ - public enum ConditionFlagType - { - NoCase, - Or, - NoVary - } -} diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/ConditionFlags.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/ConditionFlags.cs deleted file mode 100644 index e9687f8dce..0000000000 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/ConditionFlags.cs +++ /dev/null @@ -1,101 +0,0 @@ -// 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; -using System.Collections.Generic; - -namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite -{ - // TODO Refactor Condition Flags and Rule Flags under base flag class - public class ConditionFlags - { - private IDictionary _conditionFlagLookup = new Dictionary(StringComparer.OrdinalIgnoreCase) { - { "nc", ConditionFlagType.NoCase}, - { "nocase", ConditionFlagType.NoCase }, - { "or", ConditionFlagType.Or}, - { "ornext", ConditionFlagType.Or }, - { "nv", ConditionFlagType.NoVary}, - { "novary", ConditionFlagType.NoVary} - }; - - public IDictionary FlagDictionary { get; } - - public ConditionFlags(IDictionary flags) - { - FlagDictionary = flags; - } - - public ConditionFlags() - { - FlagDictionary = new Dictionary(); - } - public void SetFlag(string flag) - { - SetFlag(flag, null); - } - - public void SetFlag(string flag, string value) - { - ConditionFlagType res; - if (!_conditionFlagLookup.TryGetValue(flag, out res)) - { - throw new ArgumentException("Invalid flag"); - } - SetFlag(res, value); - } - - public void SetFlag(ConditionFlagType flag, string value) - { - if (value == null) - { - value = string.Empty; - } - FlagDictionary[flag] = value; - } - - public string GetFlag(ConditionFlagType flag) - { - CleanupResources(); - string res; - if (!FlagDictionary.TryGetValue(flag, out res)) - { - return null; - } - return res; - } - - public string this[ConditionFlagType flag] - { - get - { - string res; - if (!FlagDictionary.TryGetValue(flag, out res)) - { - return null; - } - return res; - } - set - { - FlagDictionary[flag] = value ?? string.Empty; - } - } - - public bool HasFlag(ConditionFlagType flag) - { - CleanupResources(); - string res; - return FlagDictionary.TryGetValue(flag, out res); - } - - // If this method is called, all flags have been processed, - // therefore to clean up memory, delete dictionary. - private void CleanupResources() - { - if (_conditionFlagLookup != null) - { - _conditionFlagLookup = null; - } - } - } -} diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/ConditionPatternParser.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/ConditionPatternParser.cs index 2d14d9c7d0..8279da7831 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/ConditionPatternParser.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/ConditionPatternParser.cs @@ -26,17 +26,17 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite /// /// The CondPattern portion of a mod_rewrite RewriteCond. /// A new parsed condition. - public static ParsedModRewriteExpression ParseActionCondition(string condition) + public static ParsedModRewriteInput ParseActionCondition(string condition) { - if (condition == null) + if (condition == null) { condition = string.Empty; } var context = new ParserContext(condition); - var results = new ParsedModRewriteExpression(); + var results = new ParsedModRewriteInput(); if (!context.Next()) { - throw new FormatException(context.Error()); + throw new FormatException(Resources.FormatError_InputParserUnrecognizedParameter(condition, context.Index)); } // If we hit a !, make sure the condition is inverted when resolving the string @@ -45,88 +45,90 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite results.Invert = true; if (!context.Next()) { - throw new FormatException(context.Error()); + // Dangling ! + throw new FormatException(Resources.FormatError_InputParserUnrecognizedParameter(condition, context.Index)); } } // Control Block for strings. Set the operation and type fields based on the sign + // Switch on current character switch (context.Current) { case Greater: if (!context.Next()) { // Dangling ">" - throw new FormatException(context.Error()); + throw new FormatException(Resources.FormatError_InputParserUnrecognizedParameter(condition, context.Index)); } if (context.Current == EqualSign) { if (!context.Next()) { // Dangling ">=" - throw new FormatException(context.Error()); + throw new FormatException(Resources.FormatError_InputParserUnrecognizedParameter(condition, context.Index)); } - results.Operation = OperationType.GreaterEqual; - results.Type = ConditionType.StringComp; + results.OperationType = OperationType.GreaterEqual; + results.ConditionType = ConditionType.StringComp; } else { - results.Operation = OperationType.Greater; - results.Type = ConditionType.StringComp; + results.OperationType = OperationType.Greater; + results.ConditionType = ConditionType.StringComp; } break; case Less: if (!context.Next()) { // Dangling "<" - throw new FormatException(context.Error()); + throw new FormatException(Resources.FormatError_InputParserUnrecognizedParameter(condition, context.Index)); } if (context.Current == EqualSign) { if (!context.Next()) { // Dangling "<=" - throw new FormatException(context.Error()); + throw new FormatException(Resources.FormatError_InputParserUnrecognizedParameter(condition, context.Index)); } - results.Operation = OperationType.LessEqual; - results.Type = ConditionType.StringComp; + results.OperationType = OperationType.LessEqual; + results.ConditionType = ConditionType.StringComp; } else { - results.Operation = OperationType.Less; - results.Type = ConditionType.StringComp; + results.OperationType = OperationType.Less; + results.ConditionType = ConditionType.StringComp; } break; case EqualSign: if (!context.Next()) { // Dangling "=" - throw new FormatException(context.Error()); + throw new FormatException(Resources.FormatError_InputParserUnrecognizedParameter(condition, context.Index)); } - results.Operation = OperationType.Equal; - results.Type = ConditionType.StringComp; + results.OperationType = OperationType.Equal; + results.ConditionType = ConditionType.StringComp; break; case Dash: results = ParseProperty(context, results.Invert); - if (results.Type == ConditionType.PropertyTest) + if (results.ConditionType == ConditionType.PropertyTest) { return results; } context.Next(); break; default: - results.Type = ConditionType.Regex; + results.ConditionType = ConditionType.Regex; break; } // Capture the rest of the string guarantee validity. - results.Operand = (condition.Substring(context.GetIndex())); + results.Operand = condition.Substring(context.GetIndex()); if (IsValidActionCondition(results)) { return results; } else { - throw new FormatException(context.Error()); + throw new FormatException(Resources.FormatError_InputParserUnrecognizedParameter(condition, context.Index)); } } @@ -137,37 +139,37 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite /// /// /// - public static ParsedModRewriteExpression ParseProperty(ParserContext context, bool invert) + public static ParsedModRewriteInput ParseProperty(ParserContext context, bool invert) { if (!context.Next()) { - throw new FormatException(context.Error()); + throw new FormatException(Resources.FormatError_InputParserUnrecognizedParameter(context.Template, context.Index)); } + switch (context.Current) { case 'd': - return new ParsedModRewriteExpression(invert, ConditionType.PropertyTest, OperationType.Directory, null); + return new ParsedModRewriteInput(invert, ConditionType.PropertyTest, OperationType.Directory, operand: null); case 'f': - return new ParsedModRewriteExpression(invert, ConditionType.PropertyTest, OperationType.RegularFile, null); + return new ParsedModRewriteInput(invert, ConditionType.PropertyTest, OperationType.RegularFile, operand: null); case 'F': - return new ParsedModRewriteExpression(invert, ConditionType.PropertyTest, OperationType.ExistingFile, null); + return new ParsedModRewriteInput(invert, ConditionType.PropertyTest, OperationType.ExistingFile, operand: null); case 'h': case 'L': - return new ParsedModRewriteExpression(invert, ConditionType.PropertyTest, OperationType.SymbolicLink, null); + return new ParsedModRewriteInput(invert, ConditionType.PropertyTest, OperationType.SymbolicLink, operand: null); case 's': - return new ParsedModRewriteExpression(invert, ConditionType.PropertyTest, OperationType.Size, null); + return new ParsedModRewriteInput(invert, ConditionType.PropertyTest, OperationType.Size, operand: null); case 'U': - return new ParsedModRewriteExpression(invert, ConditionType.PropertyTest, OperationType.ExistingUrl, null); + return new ParsedModRewriteInput(invert, ConditionType.PropertyTest, OperationType.ExistingUrl, operand: null); case 'x': - return new ParsedModRewriteExpression(invert, ConditionType.PropertyTest, OperationType.Executable, null); + return new ParsedModRewriteInput(invert, ConditionType.PropertyTest, OperationType.Executable, operand: null); case 'e': - if (!context.Next() || context.Current != 'q') { // Illegal statement. - throw new FormatException(context.Error()); + throw new FormatException(Resources.FormatError_InputParserUnrecognizedParameter(context.Template, context.Index)); } - return new ParsedModRewriteExpression(invert, ConditionType.IntComp, OperationType.Equal, null); + return new ParsedModRewriteInput(invert, ConditionType.IntComp, OperationType.Equal, operand: null); case 'g': if (!context.Next()) { @@ -175,47 +177,49 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite } if (context.Current == 't') { - return new ParsedModRewriteExpression(invert, ConditionType.IntComp, OperationType.Greater, null); + return new ParsedModRewriteInput(invert, ConditionType.IntComp, OperationType.Greater, operand: null); } else if (context.Current == 'e') { - return new ParsedModRewriteExpression(invert, ConditionType.IntComp, OperationType.GreaterEqual, null); + return new ParsedModRewriteInput(invert, ConditionType.IntComp, OperationType.GreaterEqual, operand: null); } else { throw new FormatException(context.Error()); } case 'l': + // name conflict with -l and -lt/-le, so the assumption is if there is no + // charcters after -l, we assume it a symbolic link if (!context.Next()) { - return new ParsedModRewriteExpression(invert, ConditionType.PropertyTest, OperationType.SymbolicLink, null); + return new ParsedModRewriteInput(invert, ConditionType.PropertyTest, OperationType.SymbolicLink, operand: null); } if (context.Current == 't') { - return new ParsedModRewriteExpression(invert, ConditionType.IntComp, OperationType.Less, null); + return new ParsedModRewriteInput(invert, ConditionType.IntComp, OperationType.Less, operand: null); } else if (context.Current == 'e') { - return new ParsedModRewriteExpression(invert, ConditionType.IntComp, OperationType.LessEqual, null); + return new ParsedModRewriteInput(invert, ConditionType.IntComp, OperationType.LessEqual, operand: null); } else { - throw new FormatException(context.Error()); + throw new FormatException(Resources.FormatError_InputParserUnrecognizedParameter(context.Template, context.Index)); } case 'n': if (!context.Next() || context.Current != 'e') { - throw new FormatException(context.Error()); + throw new FormatException(Resources.FormatError_InputParserUnrecognizedParameter(context.Template, context.Index)); } - return new ParsedModRewriteExpression(invert, ConditionType.IntComp, OperationType.NotEqual, null); + return new ParsedModRewriteInput(invert, ConditionType.IntComp, OperationType.NotEqual, operand: null); default: - throw new FormatException(context.Error()); + throw new FormatException(Resources.FormatError_InputParserUnrecognizedParameter(context.Template, context.Index)); } } - private static bool IsValidActionCondition(ParsedModRewriteExpression results) + private static bool IsValidActionCondition(ParsedModRewriteInput results) { - if (results.Type == ConditionType.IntComp) + if (results.ConditionType == ConditionType.IntComp) { // If the type is an integer, verify operand is actually an int int res; diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/ExpressionCreator.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/ExpressionCreator.cs deleted file mode 100644 index 0fab8c0d3f..0000000000 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/ExpressionCreator.cs +++ /dev/null @@ -1,127 +0,0 @@ -// 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; -using System.Text.RegularExpressions; -using Microsoft.AspNetCore.Rewrite.Internal.ModRewrite.Operands; - -namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite -{ - /// - /// Converts a parsed expression into a mod_rewrite condition. - /// - public class ExpressionCreator - { - private static readonly TimeSpan RegexTimeout = TimeSpan.FromMilliseconds(1); - public static ConditionExpression CreateConditionExpression(ParsedModRewriteExpression pce, ConditionFlags flags) - { - var condExp = new ConditionExpression(); - condExp.Invert = pce.Invert; - if (pce.Type == ConditionType.Regex) - { - // TODO make nullable? - if (flags != null && flags.HasFlag(ConditionFlagType.NoCase)) - { - condExp.Operand = new RegexOperand(new Regex(pce.Operand, RegexOptions.IgnoreCase | RegexOptions.Compiled, RegexTimeout)); - } - else - { - condExp.Operand = new RegexOperand(new Regex(pce.Operand, RegexOptions.Compiled, RegexTimeout)); - } - } - else if (pce.Type == ConditionType.IntComp) - { - switch (pce.Operation) - { - case OperationType.Equal: - condExp.Operand = new IntegerOperand(pce.Operand, IntegerOperationType.Equal); - break; - case OperationType.Greater: - condExp.Operand = new IntegerOperand(pce.Operand, IntegerOperationType.Greater); - break; - case OperationType.GreaterEqual: - condExp.Operand = new IntegerOperand(pce.Operand, IntegerOperationType.GreaterEqual); - break; - case OperationType.Less: - condExp.Operand = new IntegerOperand(pce.Operand, IntegerOperationType.Less); - break; - case OperationType.LessEqual: - condExp.Operand = new IntegerOperand(pce.Operand, IntegerOperationType.LessEqual); - break; - case OperationType.NotEqual: - condExp.Operand = new IntegerOperand(pce.Operand, IntegerOperationType.NotEqual); - break; - default: - throw new ArgumentException("No defined operation for integer comparison."); - } - } - else if (pce.Type == ConditionType.StringComp) - { - switch (pce.Operation) - { - case OperationType.Equal: - condExp.Operand = new StringOperand(pce.Operand, StringOperationType.Equal); - break; - case OperationType.Greater: - condExp.Operand = new StringOperand(pce.Operand, StringOperationType.Greater); - break; - case OperationType.GreaterEqual: - condExp.Operand = new StringOperand(pce.Operand, StringOperationType.GreaterEqual); - break; - case OperationType.Less: - condExp.Operand = new StringOperand(pce.Operand, StringOperationType.Less); - break; - case OperationType.LessEqual: - condExp.Operand = new StringOperand(pce.Operand, StringOperationType.LessEqual); - break; - default: - throw new ArgumentException("No defined operation for string comparison."); - } - } - else - { - switch (pce.Operation) - { - case OperationType.Directory: - condExp.Operand = new PropertyOperand(PropertyOperationType.Directory); - break; - case OperationType.RegularFile: - condExp.Operand = new PropertyOperand(PropertyOperationType.RegularFile); - break; - case OperationType.ExistingFile: - condExp.Operand = new PropertyOperand(PropertyOperationType.ExistingFile); - break; - case OperationType.SymbolicLink: - condExp.Operand = new PropertyOperand(PropertyOperationType.SymbolicLink); - break; - case OperationType.Size: - condExp.Operand = new PropertyOperand(PropertyOperationType.Size); - break; - case OperationType.ExistingUrl: - condExp.Operand = new PropertyOperand(PropertyOperationType.ExistingUrl); - break; - case OperationType.Executable: - condExp.Operand = new PropertyOperand(PropertyOperationType.Executable); - break; - default: - throw new ArgumentException("No defined operation for property comparison."); - } - } - return condExp; - } - public static RuleExpression CreateRuleExpression(ParsedModRewriteExpression pce, RuleFlags flags) - { - var ruleExp = new RuleExpression(); - ruleExp.Invert = pce.Invert; - if (flags.HasFlag(RuleFlagType.NoCase)) - { - ruleExp.Operand = new RegexOperand(new Regex(pce.Operand, RegexOptions.IgnoreCase | RegexOptions.Compiled, RegexTimeout)); - } - else - { - ruleExp.Operand = new RegexOperand(new Regex(pce.Operand, RegexOptions.Compiled, RegexTimeout)); - } - return ruleExp; - } - } -} diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/FileParser.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/FileParser.cs index 3cee0d1e72..de38c0ce3b 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/FileParser.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/FileParser.cs @@ -4,23 +4,20 @@ using System; using System.Collections.Generic; using System.IO; -using Microsoft.AspNetCore.Rewrite.Internal; namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite { - /// - /// - /// - public static class FileParser + public class FileParser { - public static List Parse(TextReader input) + public List Parse(TextReader input) { string line = null; var rules = new List(); - var conditions = new List(); - // TODO consider passing Itokenizer and Ifileparser and provide implementations + var builder = new RuleBuilder(); + var lineNum = 0; while ((line = input.ReadLine()) != null) { + lineNum++; if (string.IsNullOrEmpty(line)) { continue; @@ -33,71 +30,65 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite if (tokens.Count > 4) { // This means the line didn't have an appropriate format, throw format exception - throw new FormatException(); + throw new FormatException(Resources.FormatError_ModRewriteParseError("Too many tokens on line", lineNum)); } - // TODO make a new class called rule parser that does and either return an exception or return the rule. + switch (tokens[0]) { case "RewriteBase": - throw new NotSupportedException(); - //if (tokens.Count == 2) - //{ - // ModRewriteBase.Base = tokens[1]; - //} - //else - //{ - // throw new FormatException(""); - //} - //break; + throw new NotImplementedException("RewriteBase is not implemented"); case "RewriteCond": + try { - ConditionBuilder builder = null; - if (tokens.Count == 3) + var pattern = TestStringParser.Parse(tokens[1]); + var condActionParsed = ConditionPatternParser.ParseActionCondition(tokens[2]); + + var flags = new Flags(); + if (tokens.Count == 4) { - builder = new ConditionBuilder(tokens[1], tokens[2]); + flags = FlagParser.Parse(tokens[3]); } - else if (tokens.Count == 4) - { - builder = new ConditionBuilder(tokens[1], tokens[2], tokens[3]); - } - else - { - throw new FormatException(); - } - conditions.Add(builder.Build()); - break; + + builder.AddConditionFromParts(pattern, condActionParsed, flags); } + catch (FormatException formatException) + { + throw new FormatException(Resources.FormatError_ModRewriteGeneralParseError(lineNum), formatException); + } + break; case "RewriteRule": + try { - RuleBuilder builder = null; - if (tokens.Count == 3) + var regex = RuleRegexParser.ParseRuleRegex(tokens[1]); + var pattern = TestStringParser.Parse(tokens[2]); + + // TODO see if we can have flags be null. + var flags = new Flags(); + if (tokens.Count == 4) { - builder = new RuleBuilder(tokens[1], tokens[2]); + flags = FlagParser.Parse(tokens[3]); } - else if (tokens.Count == 4) - { - builder = new RuleBuilder(tokens[1], tokens[2], tokens[3]); - } - else - { - throw new FormatException(); - } - builder.AddConditions(conditions); + + builder.AddMatch(regex, flags); + builder.AddAction(pattern, flags); rules.Add(builder.Build()); - conditions = new List(); - break; + builder = new RuleBuilder(); + } + catch (FormatException formatException) + { + throw new FormatException(Resources.FormatError_ModRewriteGeneralParseError(lineNum), formatException); } + break; case "RewriteMap": - throw new NotImplementedException("RewriteMaps to be added soon."); + throw new NotImplementedException("RewriteMap to be added soon."); case "RewriteEngine": // Explicitly do nothing here, no notion of turning on regex engine. break; default: - throw new FormatException(tokens[0]); + throw new FormatException(Resources.FormatError_ModRewriteParseError("Unrecognized keyword: " + tokens[0], lineNum)); } } return rules; } - } } diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/FlagParser.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/FlagParser.cs index 4053ea8d7e..8252c89637 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/FlagParser.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/FlagParser.cs @@ -5,99 +5,38 @@ using System; namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite { - /// - /// Parses the flags - /// public class FlagParser - { - // TODO Refactor Rule and Condition Flags under IFlags - public static RuleFlags ParseRuleFlags(string flagString) - { - var flags = new RuleFlags(); - ParseRuleFlags(flagString, flags); - return flags; - } - - public static void ParseRuleFlags(string flagString, RuleFlags flags) + { + public static Flags Parse(string flagString) { if (string.IsNullOrEmpty(flagString)) { - return; + return null; } + // Check that flags are contained within [] if (!flagString.StartsWith("[") || !flagString.EndsWith("]")) { throw new FormatException(); } - // Illegal syntax to have any spaces. - var tokens = flagString.Substring(1, flagString.Length - 2).Split(','); - // Go through tokens and verify they have meaning. - // Flags can be KVPs, delimited by '='. - foreach (string token in tokens) - { - if (string.IsNullOrEmpty(token)) - { - continue; - } - string[] kvp = token.Split('='); - if (kvp.Length == 1) - { - flags.SetFlag(kvp[0], null); - } - else if (kvp.Length == 2) - { - flags.SetFlag(kvp[0], kvp[1]); - } - else - { - throw new FormatException(); - } - } - } - public static ConditionFlags ParseConditionFlags(string flagString) - { - var flags = new ConditionFlags(); - ParseConditionFlags(flagString, flags); - return flags; - } - - public static void ParseConditionFlags(string flagString, ConditionFlags flags) - { - if (string.IsNullOrEmpty(flagString)) - { - return; - } - // Check that flags are contained within [] - if (!flagString.StartsWith("[") || !flagString.EndsWith("]")) - { - throw new FormatException(); - } // Lexing esque step to split all flags. - // Illegal syntax to have any spaces. + // Invalid syntax to have any spaces. var tokens = flagString.Substring(1, flagString.Length - 2).Split(','); - // Go through tokens and verify they have meaning. - // Flags can be KVPs, delimited by '='. + var flags = new Flags(); foreach (string token in tokens) { - if (string.IsNullOrEmpty(token)) + var hasPayload = token.Split('='); + if (hasPayload.Length == 2) { - continue; - } - string[] kvp = token.Split('='); - if (kvp.Length == 1) - { - flags.SetFlag(kvp[0], null); - } - else if (kvp.Length == 2) - { - flags.SetFlag(kvp[0], kvp[1]); + flags.SetFlag(hasPayload[0], hasPayload[1]); } else { - throw new FormatException(); + flags.SetFlag(hasPayload[0], string.Empty); } } + return flags; } } } diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/RuleFlagType.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/FlagType.cs similarity index 87% rename from src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/RuleFlagType.cs rename to src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/FlagType.cs index acdb289d2b..85919a7a41 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/RuleFlagType.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/FlagType.cs @@ -3,7 +3,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite { - public enum RuleFlagType + public enum FlagType { EscapeBackreference, Chain, @@ -28,8 +28,6 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite QSLast, Redirect, Skip, - Type, - // Non-modrewrite rule - FullUrl + Type } } diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/Flags.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/Flags.cs new file mode 100644 index 0000000000..29d3ea5fc5 --- /dev/null +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/Flags.cs @@ -0,0 +1,125 @@ +// 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; +using System.Collections.Generic; + +namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite +{ + // For more information of flags, and what flags we currently support: + // https://github.com/aspnet/BasicMiddleware/issues/66 + // http://httpd.apache.org/docs/current/expr.html#vars + public class Flags + { + private static IDictionary _ruleFlagLookup = new Dictionary(StringComparer.OrdinalIgnoreCase) { + { "b", FlagType.EscapeBackreference}, + { "c", FlagType.Chain }, + { "chain", FlagType.Chain}, + { "co", FlagType.Cookie }, + { "cookie", FlagType.Cookie }, + { "dpi", FlagType.DiscardPath }, + { "discardpath", FlagType.DiscardPath }, + { "e", FlagType.Env}, + { "env", FlagType.Env}, + { "end", FlagType.End }, + { "f", FlagType.Forbidden }, + { "forbidden", FlagType.Forbidden }, + { "g", FlagType.Gone }, + { "gone", FlagType.Gone }, + { "h", FlagType.Handler }, + { "handler", FlagType.Handler }, + { "l", FlagType.Last }, + { "last", FlagType.Last }, + { "n", FlagType.Next }, + { "next", FlagType.Next }, + { "nc", FlagType.NoCase }, + { "nocase", FlagType.NoCase }, + { "ne", FlagType.NoEscape }, + { "noescape", FlagType.NoEscape }, + { "ns", FlagType.NoSubReq }, + { "nosubreq", FlagType.NoSubReq }, + { "p", FlagType.Proxy }, + { "proxy", FlagType.Proxy }, + { "pt", FlagType.PassThrough }, + { "passthrough", FlagType.PassThrough }, + { "qsa", FlagType.QSAppend }, + { "qsappend", FlagType.QSAppend }, + { "qsd", FlagType.QSDiscard }, + { "qsdiscard", FlagType.QSDiscard }, + { "qsl", FlagType.QSLast }, + { "qslast", FlagType.QSLast }, + { "r", FlagType.Redirect }, + { "redirect", FlagType.Redirect }, + { "s", FlagType.Skip }, + { "skip", FlagType.Skip }, + { "t", FlagType.Type }, + { "type", FlagType.Type }, + }; + + public IDictionary FlagDictionary { get; } + + public Flags(IDictionary flags) + { + FlagDictionary = flags; + } + + public Flags() + { + FlagDictionary = new Dictionary(); + } + + public void SetFlag(string flag, string value) + { + FlagType res; + if (!_ruleFlagLookup.TryGetValue(flag, out res)) + { + throw new FormatException("Unrecognized flag"); + } + SetFlag(res, value); + } + + public void SetFlag(FlagType flag, string value) + { + if (value == null) + { + value = string.Empty; + } + FlagDictionary[flag] = value; + } + + public bool GetValue(FlagType flag, out string value) + { + string res; + if (!FlagDictionary.TryGetValue(flag, out res)) + { + value = null; + return false; + } + value = res; + return true; + } + + public string this[FlagType flag] + { + get + { + string res; + if (!FlagDictionary.TryGetValue(flag, out res)) + { + return null; + } + return res; + } + set + { + FlagDictionary[flag] = value ?? string.Empty; + } + } + + public bool HasFlag(FlagType flag) + { + string res; + return FlagDictionary.TryGetValue(flag, out res); + } + } +} diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/ModRewriteRedirectAction.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/ModRewriteRedirectAction.cs new file mode 100644 index 0000000000..35c2ecd0df --- /dev/null +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/ModRewriteRedirectAction.cs @@ -0,0 +1,77 @@ +// 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; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Rewrite.Internal; +using Microsoft.Net.Http.Headers; + +namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite +{ + public class ModRewriteRedirectAction : UrlAction + { + public int StatusCode { get; } + public bool QueryStringAppend { get; } + public bool QueryStringDelete { get; } + public bool EscapeBackReferences { get; } + + public ModRewriteRedirectAction( + int statusCode, + Pattern pattern, + bool queryStringAppend, + bool queryStringDelete, + bool escapeBackReferences) + { + StatusCode = statusCode; + Url = pattern; + QueryStringAppend = queryStringAppend; + QueryStringDelete = queryStringDelete; + EscapeBackReferences = escapeBackReferences; + } + + public override RuleResult ApplyAction(RewriteContext context, MatchResults ruleMatch, MatchResults condMatch) + { + var pattern = Url.Evaluate(context, ruleMatch, condMatch); + if (EscapeBackReferences) + { + // TODO right way to escape backreferences? + pattern = Uri.EscapeDataString(pattern); + } + context.HttpContext.Response.StatusCode = StatusCode; + + // url can either contain the full url or the path and query + // always add to location header. + // TODO check for false positives + var split = pattern.IndexOf('?'); + if (split >= 0) + { + QueryString query; + if (QueryStringAppend) + { + query = context.HttpContext.Request.QueryString.Add(new QueryString(pattern.Substring(split))); + } + else + { + query = new QueryString(pattern.Substring(split)); + } + + // not using the response.redirect here because status codes may be 301, 302, 307, 308 + context.HttpContext.Response.Headers[HeaderNames.Location] = pattern.Substring(0, split) + query; + } + else + { + // If the request url has a query string and the target does not, append the query string + // by default. + if (QueryStringDelete) + { + context.HttpContext.Response.Headers[HeaderNames.Location] = pattern; + } + else + { + context.HttpContext.Response.Headers[HeaderNames.Location] = pattern + context.HttpContext.Request.QueryString; + } + } + return RuleResult.ResponseComplete; + } + } +} diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/ModRewriteRewriteAction.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/ModRewriteRewriteAction.cs new file mode 100644 index 0000000000..2fd6a0940c --- /dev/null +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/ModRewriteRewriteAction.cs @@ -0,0 +1,98 @@ +// 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 Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Http.Extensions; +using Microsoft.AspNetCore.Rewrite.Internal; + +namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite +{ + public class ModRewriteRewriteAction : UrlAction + { + private readonly string ForwardSlash = "/"; + public RuleResult Result { get; } + public bool QueryStringAppend { get; } + public bool QueryStringDelete { get; } + public bool EscapeBackReferences { get; } + + public ModRewriteRewriteAction( + RuleResult result, + Pattern pattern, + bool queryStringAppend, + bool queryStringDelete, + bool escapeBackReferences) + { + Result = result; + Url = pattern; + QueryStringAppend = queryStringAppend; + QueryStringDelete = queryStringDelete; + EscapeBackReferences = escapeBackReferences; + } + + public override RuleResult ApplyAction(RewriteContext context, MatchResults ruleMatch, MatchResults condMatch) + { + var pattern = Url.Evaluate(context, ruleMatch, condMatch); + + // TODO PERF, substrings, object creation, etc. + if (pattern.IndexOf("://") >= 0) + { + string scheme = null; + HostString host; + PathString path; + QueryString query; + FragmentString fragment; + UriHelper.FromAbsolute(pattern, out scheme, out host, out path, out query, out fragment); + + if (query.HasValue) + { + if (QueryStringAppend) + { + context.HttpContext.Request.QueryString = context.HttpContext.Request.QueryString.Add(query); + } + else + { + context.HttpContext.Request.QueryString = query; + } + } + else if (QueryStringDelete) + { + context.HttpContext.Request.QueryString = QueryString.Empty; + } + + context.HttpContext.Request.Scheme = scheme; + context.HttpContext.Request.Host = host; + context.HttpContext.Request.Path = path; + } + else + { + // TODO fix with redirect action logic + var split = pattern.IndexOf('?'); + if (split >= 0) + { + var path = pattern.Substring(0, split); + if (path.StartsWith(ForwardSlash)) + { + context.HttpContext.Request.Path = PathString.FromUriComponent(path); + } + else + { + context.HttpContext.Request.Path = PathString.FromUriComponent(ForwardSlash + path); + } + context.HttpContext.Request.QueryString = context.HttpContext.Request.QueryString.Add(new QueryString(pattern.Substring(split))); + } + else + { + if (pattern.StartsWith(ForwardSlash)) + { + context.HttpContext.Request.Path = PathString.FromUriComponent(pattern); + } + else + { + context.HttpContext.Request.Path = PathString.FromUriComponent(ForwardSlash + pattern); + } + } + } + return Result; + } + } +} diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/Operands/Operand.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/Operands/Operand.cs deleted file mode 100644 index 565cd932fc..0000000000 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/Operands/Operand.cs +++ /dev/null @@ -1,13 +0,0 @@ -// 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.Text.RegularExpressions; -using Microsoft.Extensions.FileProviders; - -namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite.Operands -{ - public abstract class Operand - { - public abstract bool? CheckOperation(Match previous, string concatTestString, IFileProvider fileProvider); - } -} diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/Operands/PropertyOperand.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/Operands/PropertyOperand.cs deleted file mode 100644 index fd7f649e7d..0000000000 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/Operands/PropertyOperand.cs +++ /dev/null @@ -1,44 +0,0 @@ -// 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; -using System.Text.RegularExpressions; -using Microsoft.Extensions.FileProviders; - -namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite.Operands -{ - public class PropertyOperand : Operand - { - public PropertyOperationType Operation { get; } - - public PropertyOperand(PropertyOperationType operation) - { - Operation = operation; - } - public override bool? CheckOperation(Match previous, string testString, IFileProvider fileProvider) - { - switch(Operation) - { - case PropertyOperationType.Directory: - return fileProvider.GetFileInfo(testString).IsDirectory; - case PropertyOperationType.RegularFile: - return fileProvider.GetFileInfo(testString).Exists; - case PropertyOperationType.Size: - var fileInfo = fileProvider.GetFileInfo(testString); - return fileInfo.Exists && fileInfo.Length > 0; - case PropertyOperationType.ExistingUrl: - throw new NotSupportedException("No support for internal sub requests."); - case PropertyOperationType.ExistingFile: - throw new NotSupportedException("No support for internal sub requests."); - case PropertyOperationType.SymbolicLink: - throw new NotSupportedException("No support for checking symbolic links."); - case PropertyOperationType.Executable: - throw new NotSupportedException("No support for checking executable permissions."); - default: - return false; - } - } - } - - -} diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/Operands/PropertyOperation.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/Operands/PropertyOperation.cs deleted file mode 100644 index f151c1db64..0000000000 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/Operands/PropertyOperation.cs +++ /dev/null @@ -1,17 +0,0 @@ -// 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. - -namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite.Operands -{ - public enum PropertyOperationType - { - None, - Directory, - RegularFile, - ExistingFile, - SymbolicLink, - Size, - ExistingUrl, - Executable - } -} diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/Operands/RegexOperand.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/Operands/RegexOperand.cs deleted file mode 100644 index e7159b8e43..0000000000 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/Operands/RegexOperand.cs +++ /dev/null @@ -1,24 +0,0 @@ -// 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.Text.RegularExpressions; -using Microsoft.Extensions.FileProviders; - -namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite.Operands -{ - public class RegexOperand : Operand - { - public Regex RegexOperation { get; } - - public RegexOperand(Regex regex) - { - RegexOperation = regex; - } - - public override bool? CheckOperation(Match previous, string concatTestString, IFileProvider fileProvider) - { - previous = RegexOperation.Match(concatTestString); - return previous.Success; - } - } -} diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/Operands/StringOperand.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/Operands/StringOperand.cs deleted file mode 100644 index a48b929eff..0000000000 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/Operands/StringOperand.cs +++ /dev/null @@ -1,40 +0,0 @@ -// 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; -using System.Text.RegularExpressions; -using Microsoft.Extensions.FileProviders; - -namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite.Operands -{ - public class StringOperand : Operand - { - public string Value { get; set; } - public StringOperationType Operation { get; set; } - - public StringOperand(string value, StringOperationType operation) - { - Value = value; - Operation = operation; - } - - public override bool? CheckOperation(Match previous, string concatTestString, IFileProvider fileProvider) - { - switch (Operation) - { - case StringOperationType.Equal: - return concatTestString.CompareTo(Value) == 0; - case StringOperationType.Greater: - return concatTestString.CompareTo(Value) > 0; - case StringOperationType.GreaterEqual: - return concatTestString.CompareTo(Value) >= 0; - case StringOperationType.Less: - return concatTestString.CompareTo(Value) < 0; - case StringOperationType.LessEqual: - return concatTestString.CompareTo(Value) <= 0; - default: - return null; - } - } - } -} diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/ParsedConditionExpression.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/ParsedModRewriteCondition.cs similarity index 50% rename from src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/ParsedConditionExpression.cs rename to src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/ParsedModRewriteCondition.cs index 5bb69e6e8d..e854343fe5 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/ParsedConditionExpression.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/ParsedModRewriteCondition.cs @@ -3,20 +3,21 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite { - public class ParsedModRewriteExpression + public class ParsedModRewriteInput { public bool Invert { get; set; } - public ConditionType Type { get; set; } - public OperationType Operation { get; set; } + public ConditionType ConditionType { get; set; } + public OperationType OperationType { get; set; } public string Operand { get; set; } - public ParsedModRewriteExpression(bool invert, ConditionType type, OperationType operation, string operand) + + public ParsedModRewriteInput() { } + + public ParsedModRewriteInput(bool invert, ConditionType conditionType, OperationType operationType, string operand) { Invert = invert; - Type = type; - Operation = operation; + ConditionType = conditionType; + OperationType = operationType; Operand = operand; } - - public ParsedModRewriteExpression() { } } } diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/Pattern.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/Pattern.cs deleted file mode 100644 index 8d7de10791..0000000000 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/Pattern.cs +++ /dev/null @@ -1,67 +0,0 @@ -// 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.Collections.Generic; -using System.Text; -using System.Text.RegularExpressions; -using Microsoft.AspNetCore.Http; - -namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite -{ - /// - /// Contains a sequence of pattern segments, which on obtaining the context, will create the appropriate - /// test string and condition for rules and conditions. - /// - public class Pattern - { - private IReadOnlyList Segments { get; } - /// - /// Creates a new Pattern - /// - /// List of pattern segments which will be applied. - public Pattern(IReadOnlyList segments) - { - Segments = segments; - } - - /// - /// Creates the appropriate test string from the Httpcontext and Segments. - /// - /// - /// - /// - /// - public string GetPattern(HttpContext context, Match ruleMatch, Match prevCondition) - { - var res = new StringBuilder(); - foreach (var segment in Segments) - { - // TODO handle case when segment.Variable is 0 in rule and condition - switch (segment.Type) - { - case SegmentType.Literal: - res.Append(segment.Variable); - break; - case SegmentType.ServerParameter: - res.Append(ServerVariables.Resolve(segment.Variable, context)); - break; - case SegmentType.RuleParameter: - var ruleParam = ruleMatch.Groups[segment.Variable]; - if (ruleParam != null) - { - res.Append(ruleParam); - } - break; - case SegmentType.ConditionParameter: - var condParam = prevCondition.Groups[segment.Variable]; - if (condParam != null) - { - res.Append(condParam); - } - break; - } - } - return res.ToString(); - } - } -} diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/PatternSegment.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/PatternSegment.cs deleted file mode 100644 index 8a59179b5a..0000000000 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/PatternSegment.cs +++ /dev/null @@ -1,26 +0,0 @@ -// 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. - -namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite -{ - /// - /// A Pattern segment contains a portion of the test string/ substitution segment with a type associated. - /// This type can either be: Regex, Rule Variable, Condition Variable, or a Server Variable. - /// - public class PatternSegment - { - public string Variable { get; } // TODO make this a range s.t. we don't copy the string. - public SegmentType Type { get; } - - /// - /// Create a Pattern segment. - /// - /// - /// - public PatternSegment(string variable, SegmentType type) - { - Variable = variable; - Type = type; - } - } -} diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/RuleBuilder.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/RuleBuilder.cs index 9c288b00c3..0510803c4f 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/RuleBuilder.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/RuleBuilder.cs @@ -3,119 +3,221 @@ using System; using System.Collections.Generic; +using System.Text.RegularExpressions; +using Microsoft.AspNetCore.Rewrite.Internal; +using Microsoft.AspNetCore.Rewrite.Internal.PreActions; +using Microsoft.AspNetCore.Rewrite.Internal.UrlActions; +using Microsoft.AspNetCore.Rewrite.Internal.UrlMatches; namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite { public class RuleBuilder { - private ParsedModRewriteExpression _pce; - private List _conditions; - private RuleFlags _flags; - private Pattern _patterns; + private Conditions _conditions; + private UrlAction _action; + private UrlMatch _match; + private List _preActions; + + private readonly TimeSpan RegexTimeout = TimeSpan.FromMilliseconds(1); + public ModRewriteRule Build() { - var ruleExpression = ExpressionCreator.CreateRuleExpression(_pce, _flags); - return new ModRewriteRule(_conditions, ruleExpression, _patterns, _flags); + if (_action == null || _match == null) + { + // TODO throw an exception here, find apporpriate exception + } + return new ModRewriteRule(_match, _conditions, _action, _preActions); } - public RuleBuilder(string initialRule, string transformation) : - this(initialRule, transformation, flags: null) - { - } - public RuleBuilder(string rule) + public void AddRule(string rule) { + // TODO var tokens = Tokenizer.Tokenize(rule); - if (tokens.Count == 3) + var regex = RuleRegexParser.ParseRuleRegex(tokens[1]); + var pattern = TestStringParser.Parse(tokens[2]); + var flags = new Flags(); + if (tokens.Count == 4) { - CreateRule(tokens[1], tokens[2], flags: null); + flags = FlagParser.Parse(tokens[3]); } - else if (tokens.Count == 4) + AddMatch(regex, flags); + AddAction(pattern, flags); + } + + public void AddConditionFromParts( + Pattern pattern, + ParsedModRewriteInput input, + Flags flags) + { + if (_conditions == null) { - CreateRule(tokens[1], tokens[2], tokens[3]); + _conditions = new Conditions(); + } + + var condition = new Condition(); + + condition.OrNext = flags.HasFlag(FlagType.Or); + condition.Input = pattern; + + if (input.ConditionType == ConditionType.Regex) + { + // TODO make nullable? + if (flags.HasFlag(FlagType.NoCase)) + { + condition.Match = new RegexMatch(new Regex(input.Operand, RegexOptions.Compiled | RegexOptions.IgnoreCase, RegexTimeout), input.Invert); + } + else + { + condition.Match = new RegexMatch(new Regex(input.Operand, RegexOptions.Compiled, RegexTimeout), input.Invert); + } + } + else if (input.ConditionType == ConditionType.IntComp) + { + switch (input.OperationType) + { + case OperationType.Equal: + condition.Match = new IntegerMatch(input.Operand, IntegerOperationType.Equal); + break; + case OperationType.Greater: + condition.Match = new IntegerMatch(input.Operand, IntegerOperationType.Greater); + break; + case OperationType.GreaterEqual: + condition.Match = new IntegerMatch(input.Operand, IntegerOperationType.GreaterEqual); + break; + case OperationType.Less: + condition.Match = new IntegerMatch(input.Operand, IntegerOperationType.Less); + break; + case OperationType.LessEqual: + condition.Match = new IntegerMatch(input.Operand, IntegerOperationType.LessEqual); + break; + case OperationType.NotEqual: + condition.Match = new IntegerMatch(input.Operand, IntegerOperationType.NotEqual); + break; + default: + throw new ArgumentException("Invalid operation for integer comparison."); + } + } + else if (input.ConditionType == ConditionType.StringComp) + { + switch (input.OperationType) + { + case OperationType.Equal: + condition.Match = new StringMatch(input.Operand, StringOperationType.Equal); + break; + case OperationType.Greater: + condition.Match = new StringMatch(input.Operand, StringOperationType.Greater); + break; + case OperationType.GreaterEqual: + condition.Match = new StringMatch(input.Operand, StringOperationType.GreaterEqual); + break; + case OperationType.Less: + condition.Match = new StringMatch(input.Operand, StringOperationType.Less); + break; + case OperationType.LessEqual: + condition.Match = new StringMatch(input.Operand, StringOperationType.LessEqual); + break; + default: + throw new ArgumentException("Invalid operation for string comparison."); + } } else { - throw new ArgumentException(); + switch (input.OperationType) + { + case OperationType.Directory: + condition.Match = new IsDirectoryMatch(input.Invert); + break; + case OperationType.RegularFile: + condition.Match = new IsFileMatch(input.Invert); + break; + case OperationType.ExistingFile: + condition.Match = new IsFileMatch(input.Invert); + break; + case OperationType.SymbolicLink: + throw new NotImplementedException("Symbolic links are not implemented"); + case OperationType.Size: + condition.Match = new FileSizeMatch(input.Invert); + break; + case OperationType.ExistingUrl: + throw new NotImplementedException("Existing Url lookups not implemented"); + case OperationType.Executable: + throw new NotImplementedException("Executable Property search is not implemented"); + default: + // TODO change exception + throw new ArgumentException("Invalid operation for property comparison."); + } } + _conditions.ConditionList.Add(condition); } - public RuleBuilder(string initialRule, string transformation, string flags) + public void AddMatch( + ParsedModRewriteInput input, + Flags flags) { - CreateRule(initialRule, transformation, flags); - } - - public void CreateRule(string initialRule, string transformation, string flags) - { - _pce = RuleRegexParser.ParseRuleRegex(initialRule); - _patterns = ConditionTestStringParser.ParseConditionTestString(transformation); - _flags = FlagParser.ParseRuleFlags(flags); - } - - public void AddCondition(string condition) - { - if (_conditions == null) + if (flags.HasFlag(FlagType.NoCase)) { - _conditions = new List(); - } - var condBuilder = new ConditionBuilder(condition); - _conditions.Add(condBuilder.Build()); - } - - public void AddCondition(Condition condition) - { - if (_conditions == null) - { - _conditions = new List(); - } - _conditions.Add(condition); - } - - public void AddConditions(List conditions) - { - if (_conditions == null) - { - _conditions = new List(); - } - _conditions.AddRange(conditions); - } - - public void SetFlag(string flag) - { - SetFlag(flag, value: null); - } - - public void SetFlag(RuleFlagType flag) - { - SetFlag(flag, value: null); - } - - public void SetFlag(string flag, string value) - { - if (_flags == null) - { - _flags = new RuleFlags(); - } - _flags.SetFlag(flag, value); - } - - public void SetFlag(RuleFlagType flag, string value) - { - if (_flags == null) - { - _flags = new RuleFlags(); - } - _flags.SetFlag(flag, value); - } - - public void SetFlags(string flags) - { - if (_flags == null) - { - _flags = FlagParser.ParseRuleFlags(flags); + _match = new RegexMatch(new Regex(input.Operand, RegexOptions.Compiled | RegexOptions.IgnoreCase, RegexTimeout), input.Invert); } else { - FlagParser.ParseRuleFlags(flags, _flags); + _match = new RegexMatch(new Regex(input.Operand, RegexOptions.Compiled, RegexTimeout), input.Invert); + } + } + + public void AddAction( + Pattern pattern, + Flags flags) + { + // first create pre conditions + if (_preActions == null) + { + _preActions = new List(); + } + + string flag; + if (flags.GetValue(FlagType.Cookie, out flag)) + { + // parse cookie + _preActions.Add(new ChangeCookiePreAction(flag)); + } + + if (flags.GetValue(FlagType.Env, out flag)) + { + // parse env + _preActions.Add(new ChangeEnvironmentPreAction(flag)); + } + + if (flags.HasFlag(FlagType.Forbidden)) + { + _action = new ForbiddenAction(); + } + else if (flags.HasFlag(FlagType.Gone)) + { + _action = new GoneAction(); + } + else + { + var escapeBackReference = flags.HasFlag(FlagType.EscapeBackreference); + var queryStringAppend = flags.HasFlag(FlagType.QSAppend); + var queryStringDelete = flags.HasFlag(FlagType.QSDiscard); + + // is redirect? + string statusCode; + if (flags.GetValue(FlagType.Redirect, out statusCode)) + { + int res; + if (!int.TryParse(statusCode, out res)) + { + throw new FormatException(Resources.FormatError_InputParserInvalidInteger(statusCode, -1)); + } + _action = new ModRewriteRedirectAction(res, pattern, queryStringAppend, queryStringDelete, escapeBackReference); + } + else + { + var last = flags.HasFlag(FlagType.End) || flags.HasFlag(FlagType.Last); + var redirect = last ? RuleResult.StopRules : RuleResult.Continue; + _action = new ModRewriteRewriteAction(redirect, pattern, queryStringAppend, queryStringDelete, escapeBackReference); + } } } } diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/RuleExpression.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/RuleExpression.cs deleted file mode 100644 index 1c29b18f0e..0000000000 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/RuleExpression.cs +++ /dev/null @@ -1,13 +0,0 @@ -// 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 Microsoft.AspNetCore.Rewrite.Internal.ModRewrite.Operands; - -namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite -{ - public class RuleExpression - { - public RegexOperand Operand { get; set; } - public bool Invert { get; set; } - } -} diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/RuleFlags.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/RuleFlags.cs deleted file mode 100644 index 1c2d632d41..0000000000 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/RuleFlags.cs +++ /dev/null @@ -1,133 +0,0 @@ -// 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; -using System.Collections.Generic; - -namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite -{ - public class RuleFlags - { - private IDictionary _ruleFlagLookup = new Dictionary(StringComparer.OrdinalIgnoreCase) { - { "b", RuleFlagType.EscapeBackreference}, - { "c", RuleFlagType.Chain }, - { "chain", RuleFlagType.Chain}, - { "co", RuleFlagType.Cookie }, - { "cookie", RuleFlagType.Cookie }, - { "dpi", RuleFlagType.DiscardPath }, - { "discardpath", RuleFlagType.DiscardPath }, - { "e", RuleFlagType.Env}, - { "env", RuleFlagType.Env}, - { "end", RuleFlagType.End }, - { "f", RuleFlagType.Forbidden }, - { "forbidden", RuleFlagType.Forbidden }, - { "g", RuleFlagType.Gone }, - { "gone", RuleFlagType.Gone }, - { "h", RuleFlagType.Handler }, - { "handler", RuleFlagType.Handler }, - { "l", RuleFlagType.Last }, - { "last", RuleFlagType.Last }, - { "n", RuleFlagType.Next }, - { "next", RuleFlagType.Next }, - { "nc", RuleFlagType.NoCase }, - { "nocase", RuleFlagType.NoCase }, - { "ne", RuleFlagType.NoEscape }, - { "noescape", RuleFlagType.NoEscape }, - { "ns", RuleFlagType.NoSubReq }, - { "nosubreq", RuleFlagType.NoSubReq }, - { "p", RuleFlagType.Proxy }, - { "proxy", RuleFlagType.Proxy }, - { "pt", RuleFlagType.PassThrough }, - { "passthrough", RuleFlagType.PassThrough }, - { "qsa", RuleFlagType.QSAppend }, - { "qsappend", RuleFlagType.QSAppend }, - { "qsd", RuleFlagType.QSDiscard }, - { "qsdiscard", RuleFlagType.QSDiscard }, - { "qsl", RuleFlagType.QSLast }, - { "qslast", RuleFlagType.QSLast }, - { "r", RuleFlagType.Redirect }, - { "redirect", RuleFlagType.Redirect }, - { "s", RuleFlagType.Skip }, - { "skip", RuleFlagType.Skip }, - { "t", RuleFlagType.Type }, - { "type", RuleFlagType.Type }, - // TODO make this a load bool instead of a flag for the file and rules. - { "u", RuleFlagType.FullUrl }, - { "url", RuleFlagType.FullUrl } - }; - - public IDictionary FlagDictionary { get; } - - public RuleFlags(IDictionary flags) - { - // TODO use ref to check dictionary equality - FlagDictionary = flags; - } - - public RuleFlags() - { - FlagDictionary = new Dictionary(); - } - - public void SetFlag(string flag, string value) - { - RuleFlagType res; - if (!_ruleFlagLookup.TryGetValue(flag, out res)) - { - throw new FormatException("Invalid flag"); - } - SetFlag(res, value); - } - public void SetFlag(RuleFlagType flag, string value) - { - if (value == null) - { - value = string.Empty; - } - FlagDictionary[flag] = value; - } - - public string GetValue(RuleFlagType flag) - { - CleanupResources(); - string res; - if (!FlagDictionary.TryGetValue(flag, out res)) - { - return null; - } - return res; - } - - public string this[RuleFlagType flag] - { - get - { - string res; - if (!FlagDictionary.TryGetValue(flag, out res)) - { - return null; - } - return res; - } - set - { - FlagDictionary[flag] = value ?? string.Empty; - } - } - - public bool HasFlag(RuleFlagType flag) - { - CleanupResources(); - string res; - return FlagDictionary.TryGetValue(flag, out res); - } - - private void CleanupResources() - { - if (_ruleFlagLookup != null) - { - _ruleFlagLookup = null; - } - } - } -} diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/RuleRegexParser.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/RuleRegexParser.cs index 3d8254e44d..e063b36bc4 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/RuleRegexParser.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/RuleRegexParser.cs @@ -7,19 +7,19 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite { public static class RuleRegexParser { - public static ParsedModRewriteExpression ParseRuleRegex(string regex) + public static ParsedModRewriteInput ParseRuleRegex(string regex) { - if (regex == null || regex == String.Empty) + if (regex == null || regex == string.Empty) { - throw new FormatException(); + throw new FormatException("Regex expression is null"); } if (regex.StartsWith("!")) { - return new ParsedModRewriteExpression { Invert = true, Operand = regex.Substring(1) }; + return new ParsedModRewriteInput { Invert = true, Operand = regex.Substring(1) }; } else { - return new ParsedModRewriteExpression { Invert = false, Operand = regex}; + return new ParsedModRewriteInput { Invert = false, Operand = regex}; } } } diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/SegmentType.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/SegmentType.cs index b8cbb3f3c3..2e86cde344 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/SegmentType.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/SegmentType.cs @@ -1,7 +1,7 @@ // 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. -namespace Microsoft.AspNetCore.Rewrite +namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite { public enum SegmentType { diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/ServerVariables.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/ServerVariables.cs index ec219142d2..5b664f4172 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/ServerVariables.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/ServerVariables.cs @@ -2,11 +2,8 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; -using System.Collections.Generic; -using System.Globalization; -using System.Net.Sockets; -using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Http.Features; +using Microsoft.AspNetCore.Rewrite.Internal; +using Microsoft.AspNetCore.Rewrite.Internal.PatternSegments; using Microsoft.Net.Http.Headers; namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite @@ -16,164 +13,112 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite /// public static class ServerVariables { - public static HashSet ValidServerVariables = new HashSet() - { - "HTTP_ACCEPT", - "HTTP_COOKIE", - "HTTP_FORWARDED", - "HTTP_HOST", - "HTTP_PROXY_CONNECTION", - "HTTP_REFERER", - "HTTP_USER_AGENT", - "AUTH_TYPE", - "CONN_REMOTE_ADDR", - "CONTEXT_PREFIX", - "CONTEXT_DOCUMENT_ROOT", - "IPV6", - "PATH_INFO", - "QUERY_STRING", - "REMOTE_ADDR", - "REMOTE_HOST", - "REMOTE_IDENT", - "REMOTE_PORT", - "REMOTE_USER", - "REQUEST_METHOD", - "SCRIPT_FILENAME", - "DOCUMENT_ROOT", - "SCRIPT_GROUP", - "SCRIPT_USER", - "SERVER_ADDR", - "SERVER_ADMIN", - "SERVER_NAME", - "SERVER_PORT", - "SERVER_PROTOCOL", - "SERVER_SOFTWARE", - "TIME_YEAR", - "TIME_MON", - "TIME_DAY", - "TIME_HOUR", - "TIME_MIN", - "TIME_SEC", - "TIME_WDAY", - "TIME", - "API_VERSION", - "HTTPS", - "IS_SUBREQ", - "REQUEST_FILENAME", - "REQUEST_SCHEME", - "REQUEST_URI", - "THE_REQUEST" - - }; /// /// Translates mod_rewrite server variables strings to an enum of different server variables. /// /// The server variable string. - /// The HttpContext context. + /// The Parser context /// The appropriate enum if the server variable exists, else ServerVariable.None - public static string Resolve(string variable, HttpContext context) + public static PatternSegment FindServerVariable(string variable, ParserContext context) { - // TODO talk about perf here switch (variable) { case "HTTP_ACCEPT": - return context.Request.Headers[HeaderNames.Accept]; + return new HeaderSegment(HeaderNames.Accept); case "HTTP_COOKIE": - return context.Request.Headers[HeaderNames.Cookie]; - case "HTTP_FORWARDED": - return context.Request.Headers["Forwarded"]; + return new HeaderSegment(HeaderNames.Cookie); case "HTTP_HOST": - return context.Request.Headers[HeaderNames.Host]; - case "HTTP_PROXY_CONNECTION": - return context.Request.Headers[HeaderNames.ProxyAuthenticate]; + return new HeaderSegment(HeaderNames.Host); case "HTTP_REFERER": - return context.Request.Headers[HeaderNames.Referer]; + return new HeaderSegment(HeaderNames.Referer); case "HTTP_USER_AGENT": - return context.Request.Headers[HeaderNames.UserAgent]; + return new HeaderSegment(HeaderNames.UserAgent); + case "HTTP_CONNECTION": + return new HeaderSegment(HeaderNames.Connection); + case "HTTP_FORWARDED": + return new HeaderSegment("Forwarded"); case "AUTH_TYPE": - throw new NotImplementedException(); + throw new NotImplementedException("Auth-Type server variable is not supported"); case "CONN_REMOTE_ADDR": - return context.Connection.RemoteIpAddress?.ToString(); + return new RemoteAddressSegment(); case "CONTEXT_PREFIX": - throw new NotImplementedException(); + throw new NotImplementedException("Context-prefix server variable is not supported"); case "CONTEXT_DOCUMENT_ROOT": - throw new NotImplementedException(); + throw new NotImplementedException("Context-Document-Root server variable is not supported"); case "IPV6": - return context.Connection.LocalIpAddress.AddressFamily == AddressFamily.InterNetworkV6 ? "on" : "off"; + return new IsIPV6Segment(); case "PATH_INFO": - throw new NotImplementedException(); + throw new NotImplementedException("Path-Info server variable is not supported"); case "QUERY_STRING": - return context.Request.QueryString.Value; + return new QueryStringSegment(); case "REMOTE_ADDR": - return context.Connection.RemoteIpAddress?.ToString(); + return new RemoteAddressSegment(); case "REMOTE_HOST": - throw new NotImplementedException(); + throw new NotImplementedException("Remote-Host server variable is not supported"); case "REMOTE_IDENT": - throw new NotImplementedException(); + throw new NotImplementedException("Remote-Identity server variable is not supported"); case "REMOTE_PORT": - return context.Connection.RemotePort.ToString(CultureInfo.InvariantCulture); + return new RemotePortSegment(); case "REMOTE_USER": - throw new NotImplementedException(); + throw new NotImplementedException("Remote-User server variable is not supported"); case "REQUEST_METHOD": - return context.Request.Method; + return new RequestMethodSegment(); case "SCRIPT_FILENAME": - throw new NotImplementedException(); + throw new NotImplementedException("Script-Filename server variable is not supported"); case "DOCUMENT_ROOT": - throw new NotImplementedException(); + throw new NotImplementedException("Document-Root server variable is not supported"); case "SCRIPT_GROUP": - throw new NotImplementedException(); + throw new NotImplementedException("Script-Group server variable is not supported"); case "SCRIPT_USER": - throw new NotImplementedException(); + throw new NotImplementedException("Script-User server variable is not supported"); case "SERVER_ADDR": - return context.Connection.LocalIpAddress?.ToString(); + return new LocalAddressSegment(); case "SERVER_ADMIN": - throw new NotImplementedException(); + throw new NotImplementedException("Server-Admin server variable is not supported"); case "SERVER_NAME": - throw new NotImplementedException(); + throw new NotImplementedException("Server-Name server variable is not supported"); case "SERVER_PORT": - return context.Connection.LocalPort.ToString(CultureInfo.InvariantCulture); + return new LocalPortSegment(); case "SERVER_PROTOCOL": - return context.Features.Get()?.Protocol; + return new ServerProtocolSegment(); case "SERVER_SOFTWARE": - throw new NotImplementedException(); + throw new NotImplementedException("Server-Software server variable is not supported"); case "TIME_YEAR": - return DateTimeOffset.UtcNow.Year.ToString(CultureInfo.InvariantCulture); + return new DateTimeSegment(variable); case "TIME_MON": - return DateTimeOffset.UtcNow.Month.ToString(CultureInfo.InvariantCulture); + return new DateTimeSegment(variable); case "TIME_DAY": - return DateTimeOffset.UtcNow.Day.ToString(CultureInfo.InvariantCulture); + return new DateTimeSegment(variable); case "TIME_HOUR": - return DateTimeOffset.UtcNow.Hour.ToString(CultureInfo.InvariantCulture); + return new DateTimeSegment(variable); case "TIME_MIN": - return DateTimeOffset.UtcNow.Minute.ToString(CultureInfo.InvariantCulture); + return new DateTimeSegment(variable); case "TIME_SEC": - return DateTimeOffset.UtcNow.Second.ToString(CultureInfo.InvariantCulture); + return new DateTimeSegment(variable); case "TIME_WDAY": - return ((int) DateTimeOffset.UtcNow.DayOfWeek).ToString(CultureInfo.InvariantCulture); + return new DateTimeSegment(variable); case "TIME": - return DateTimeOffset.UtcNow.ToString(CultureInfo.InvariantCulture); + return new DateTimeSegment(variable); case "API_VERSION": throw new NotImplementedException(); case "HTTPS": - return context.Request.IsHttps ? "on" : "off"; + return new IsHttpsModSegment(); case "HTTP2": - return context.Request.Scheme == "http2" ? "on" : "off"; + throw new NotImplementedException("Http2 server variable is not supported"); case "IS_SUBREQ": // TODO maybe can do this? context.Request.HttpContext ? - throw new NotImplementedException(); + throw new NotImplementedException("Is-Subrequest server variable is not supported"); case "REQUEST_FILENAME": - return context.Request.Path.Value.Substring(1); + return new RequestFileNameSegment(); case "REQUEST_SCHEME": - return context.Request.Scheme; + return new SchemeSegment(); case "REQUEST_URI": - // TODO This isn't an ideal solution. What this assumes is that all conditions don't have a leading slash before it. - return context.Request.Path.Value.Substring(1); + return new UrlSegment(); case "THE_REQUEST": - // TODO - throw new NotImplementedException(); + throw new NotImplementedException("The-Request server variable is not supported"); default: - return null; + throw new FormatException(Resources.FormatError_InputParserUnrecognizedParameter(variable, context.Index)); } } } diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/ConditionTestStringParser.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/TestStringParser.cs similarity index 72% rename from src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/ConditionTestStringParser.cs rename to src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/TestStringParser.cs index e3f8b1a18e..4564c3cba1 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/ConditionTestStringParser.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/TestStringParser.cs @@ -4,13 +4,14 @@ using System; using System.Collections.Generic; using Microsoft.AspNetCore.Rewrite.Internal; +using Microsoft.AspNetCore.Rewrite.Internal.PatternSegments; namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite { /// /// Parses the TestString segment of the mod_rewrite condition. /// - public class ConditionTestStringParser + public class TestStringParser { private const char Percent = '%'; private const char Dollar = '$'; @@ -30,7 +31,8 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite /// %1 /// $1 /// A new , containing a list of - public static Pattern ParseConditionTestString(string testString) + /// http://httpd.apache.org/docs/current/mod/mod_rewrite.html + public static Pattern Parse(string testString) { if (testString == null) { @@ -45,12 +47,9 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite // This is a server parameter, parse for a condition variable if (!context.Next()) { - throw new FormatException(context.Error()); - } - if (!ParseConditionParameter(context, results)) - { - throw new FormatException(context.Error()); + throw new FormatException(Resources.FormatError_InputParserUnrecognizedParameter(testString, context.Index)); } + ParseConditionParameter(context, results); } else if (context.Current == Dollar) { @@ -58,7 +57,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite // and create a new Pattern Segment. if (!context.Next()) { - throw new FormatException(context.Error()); + throw new FormatException(Resources.FormatError_InputParserNoBackreference(context.Index)); } context.Mark(); if (context.Current >= '0' && context.Current <= '9') @@ -66,21 +65,24 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite context.Next(); var ruleVariable = context.Capture(); context.Back(); - results.Add(new PatternSegment(ruleVariable, SegmentType.RuleParameter)); + int parsedIndex; + if (!int.TryParse(ruleVariable, out parsedIndex)) + { + // TODO this should always pass, remove try parse? + throw new FormatException(Resources.FormatError_InputParserInvalidInteger(ruleVariable, context.Index)); + } + results.Add(new RuleMatchSegment(parsedIndex)); } else { - throw new FormatException(context.Error()); + throw new FormatException(Resources.FormatError_InputParserInvalidInteger(testString, context.Index)); } } else { // Parse for literals, which will return on either the end of the test string // or when it hits a special character - if (!ParseLiteral(context, results)) - { - throw new FormatException(context.Error()); - } + ParseLiteral(context, results); } } return new Pattern(results); @@ -95,7 +97,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite /// The ParserContext /// The List of results which the new condition parameter will be added. /// true - private static bool ParseConditionParameter(ParserContext context, List results) + private static void ParseConditionParameter(ParserContext context, List results) { // Parse { } if (context.Current == OpenBrace) @@ -104,34 +106,26 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite if (!context.Next()) { // Dangling { - return false; + throw new FormatException(Resources.FormatError_InputParserMissingCloseBrace(context.Index)); } context.Mark(); while (context.Current != CloseBrace) { if (!context.Next()) { - // No closing } for the server variable - return false; + throw new FormatException(Resources.FormatError_InputParserMissingCloseBrace(context.Index)); } else if (context.Current == Colon) { // Have a segmented look up Ex: HTTP:xxxx // TODO + throw new NotImplementedException("Segmented Lookups no implemented"); } } // Need to verify server variable captured exists var rawServerVariable = context.Capture(); - if (IsValidServerVariable(rawServerVariable)) - { - results.Add(new PatternSegment(rawServerVariable, SegmentType.ServerParameter)); - } - else - { - // invalid. - return false; - } + results.Add(ServerVariables.FindServerVariable(rawServerVariable, context)); } else if (context.Current >= '0' && context.Current <= '9') { @@ -143,14 +137,18 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite // Once we leave this method, the while loop will call next again. Because // capture is exclusive, we need to go one past the end index, capture, and then go back. context.Back(); - results.Add(new PatternSegment(rawConditionParameter, SegmentType.ConditionParameter)); + int parsedIndex; + if (!int.TryParse(rawConditionParameter, out parsedIndex)) + { + throw new FormatException(Resources.FormatError_InputParserInvalidInteger(rawConditionParameter, context.Index)); + } + results.Add(new ConditionMatchSegment(parsedIndex)); } else { // illegal escape of a character - return false; + throw new FormatException(Resources.FormatError_InputParserUnrecognizedParameter(context.Template, context.Index)); } - return true; } /// @@ -159,7 +157,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite /// /// /// - private static bool ParseLiteral(ParserContext context, List results) + private static void ParseLiteral(ParserContext context, List results) { context.Mark(); string literal; @@ -177,29 +175,8 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite break; } } - - if (IsValidLiteral(context, literal)) - { - // add results - results.Add(new PatternSegment(literal, SegmentType.Literal)); - return true; - } - else - { - return false; - } - } - - private static bool IsValidLiteral(ParserContext context, string literal) - { - // TODO Once escape characters are discussed, figure this out. - return true; - } - - private static bool IsValidServerVariable(string variable) - { - // TODO Once escape characters are discussed, figure this out. - return ServerVariables.ValidServerVariables.Contains(variable); + // add results + results.Add(new LiteralSegment(literal)); } } } diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/Tokenizer.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/Tokenizer.cs index 18979e29a0..a13bdeb9ef 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/Tokenizer.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/Tokenizer.cs @@ -3,7 +3,6 @@ using System; using System.Collections.Generic; -using Microsoft.AspNetCore.Rewrite.Internal; namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite { @@ -50,7 +49,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite if (!context.Next()) { // Means that a character was not escaped appropriately Ex: "foo\" - throw new ArgumentException(); + throw new FormatException("Invalid escaper character in string " + rule); } } else if (context.Current == Space || context.Current == Tab) diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewriteRule.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewriteRule.cs index 529ae08eb5..6d7e090b9a 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewriteRule.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewriteRule.cs @@ -1,208 +1,54 @@ // 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; using System.Collections.Generic; -using Microsoft.Net.Http.Headers; -using System.Text.RegularExpressions; -using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Rewrite.Internal; -namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite +namespace Microsoft.AspNetCore.Rewrite.Internal { public class ModRewriteRule : Rule { - public List Conditions { get; set; } = new List(); - public string Description { get; set; } = string.Empty; - public RuleExpression InitialRule { get; set; } - public Pattern Transform { get; set; } - public RuleFlags Flags { get; set; } = new RuleFlags(); - public ModRewriteRule() { } + public UrlMatch InitialMatch { get; set; } + public Conditions Conditions { get; set; } + public UrlAction Action { get; set; } + public List PreActions { get; set; } - public ModRewriteRule(List conditions, RuleExpression initialRule, Pattern transforms, RuleFlags flags, string description = "") + public ModRewriteRule(UrlMatch initialMatch, Conditions conditions, UrlAction urlAction, List preActions) { Conditions = conditions; - InitialRule = initialRule; - Transform = transforms; - Flags = flags; - Description = description; + InitialMatch = initialMatch; + Action = urlAction; + PreActions = preActions; } public override RuleResult ApplyRule(RewriteContext context) { // 1. Figure out which section of the string to match for the initial rule. - var results = InitialRule.Operand.RegexOperation.Match(context.HttpContext.Request.Path.ToString()); + var initMatchRes = InitialMatch.Evaluate(context.HttpContext.Request.Path, context); - string flagRes = null; - if (CheckMatchResult(results.Success)) + if (!initMatchRes.Success) { return RuleResult.Continue; } - if (Flags.HasFlag(RuleFlagType.EscapeBackreference)) + MatchResults condMatchRes = null; + if (Conditions != null) { - // TODO Escape Backreferences here. - } - - // 2. Go through all conditions and compare them to the created string - var previous = Match.Empty; - - if (!CheckCondition(context, results, previous)) - { - return RuleResult.Continue; - } - // TODO add chained flag - - // at this point, our rule passed, we can now apply the on match function - var result = Transform.GetPattern(context.HttpContext, results, previous); - - if (Flags.HasFlag(RuleFlagType.QSDiscard)) - { - context.HttpContext.Request.QueryString = new QueryString(); - } - - if ((flagRes = Flags.GetValue(RuleFlagType.Cookie)) != null) - { - // TODO CreateCookies(context); - // context.HttpContext.Response.Cookies.Append() - // Make sure this in on compile. - } - - if ((flagRes = Flags.GetValue(RuleFlagType.Env)) != null) - { - // TODO CreateEnv(context) - // context.HttpContext... - } - - if ((flagRes = Flags.GetValue(RuleFlagType.Next)) != null) - { - // TODO Next flag - } - - if (Flags.HasFlag(RuleFlagType.Forbidden)) - { - context.HttpContext.Response.StatusCode = StatusCodes.Status403Forbidden; - return RuleResult.ResponseComplete; - } - else if (Flags.HasFlag(RuleFlagType.Gone)) - { - context.HttpContext.Response.StatusCode = StatusCodes.Status410Gone; - return RuleResult.ResponseComplete; - } - else if (result == "-") - { - // TODO set url to result. - } - else if (Flags.HasFlag(RuleFlagType.QSAppend)) - { - context.HttpContext.Request.QueryString = context.HttpContext.Request.QueryString.Add(new QueryString(result)); - } - - if ((flagRes = Flags.GetValue(RuleFlagType.Redirect)) != null) - { - int parsedInt; - if (!int.TryParse(flagRes, out parsedInt)) - { - // TODO PERF parse the status code when the flag is parsed rather than per request - throw new FormatException("Trying to parse non-int in integer comparison."); - } - context.HttpContext.Response.StatusCode = parsedInt; - if (Flags.HasFlag(RuleFlagType.FullUrl)) - { - // TODO review escaping - context.HttpContext.Response.Headers[HeaderNames.Location] = result; - } - else - { - // TODO str cat is bad, polish, review escaping - if (result.StartsWith("/")) - { - context.HttpContext.Response.Headers[HeaderNames.Location] = result + context.HttpContext.Request.QueryString; - } - else - { - context.HttpContext.Response.Headers[HeaderNames.Location] = "/" + result + context.HttpContext.Request.QueryString; - } - } - return RuleResult.ResponseComplete; - } - else - { - if (Flags.HasFlag(RuleFlagType.FullUrl)) - { - ModifyHttpContextFromUri(context.HttpContext, result); - } - else - { - if (result.StartsWith("/")) - { - context.HttpContext.Request.Path = new PathString(result); - } - else - { - context.HttpContext.Request.Path = new PathString("/" + result); - } - } - if (Flags.HasFlag(RuleFlagType.Last) || Flags.HasFlag(RuleFlagType.End)) - { - return RuleResult.StopRules; - } - else + condMatchRes = Conditions.Evaluate(context, initMatchRes); + if (!condMatchRes.Success) { return RuleResult.Continue; } } - } - private bool CheckMatchResult(bool? result) - { - if (result == null) + // At this point, we know our rule passed, first apply pre conditions, + // which can modify things like the cookie or env, and then apply the action + foreach (var preAction in PreActions) { - return false; - } - return !(result.Value ^ InitialRule.Invert); - } - - private bool CheckCondition(RewriteContext context, Match results, Match previous) - { - if (Conditions == null) - { - return true; + preAction.ApplyAction(context.HttpContext, initMatchRes, condMatchRes); } - // TODO Visitor pattern here? - foreach (var condition in Conditions) - { - var concatTestString = condition.TestStringSegments.GetPattern(context.HttpContext, results, previous); - var match = condition.ConditionExpression.CheckConditionExpression(context, previous, concatTestString); - - if (match == null) - { - return false; - } - - if (!match.Value && !(condition.Flags.HasFlag(ConditionFlagType.Or))) - { - return false; - } - } - return true; - } - - private void ModifyHttpContextFromUri(HttpContext context, string uriString) - { - var uri = new Uri(uriString); - // TODO this is ugly, fix in later push. - // TODO super bad for perf, cache/locally store these and update httpcontext after all rules are applied. - var pathBase = PathString.FromUriComponent(uri); - if (!pathBase.Value.StartsWith(context.Request.PathBase)) - { - // cannot distinguish between path base and path. - throw new NotSupportedException("Modified path base from mod_rewrite rule"); - } - context.Request.Host = HostString.FromUriComponent(uri); - context.Request.Path = PathString.FromUriComponent(uri); - context.Request.QueryString = QueryString.FromUriComponent(uri); - context.Request.Scheme = uri.Scheme; + return Action.ApplyAction(context, initMatchRes, condMatchRes); } } } diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/ParserContext.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/ParserContext.cs index 18b7833889..815f3012d8 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/ParserContext.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/ParserContext.cs @@ -8,19 +8,19 @@ namespace Microsoft.AspNetCore.Rewrite.Internal /// public class ParserContext { - private readonly string _template; + public readonly string Template; public int Index { get; set; } private int? _mark; public ParserContext(string condition) { - _template = condition; + Template = condition; Index = -1; } public char Current { - get { return (Index < _template.Length && Index >= 0) ? _template[Index] : (char)0; } + get { return (Index < Template.Length && Index >= 0) ? Template[Index] : (char)0; } } public bool Back() @@ -30,12 +30,12 @@ namespace Microsoft.AspNetCore.Rewrite.Internal public bool Next() { - return ++Index < _template.Length; + return ++Index < Template.Length; } public bool HasNext() { - return (Index + 1) < _template.Length; + return (Index + 1) < Template.Length; } public void Mark() @@ -53,7 +53,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal // TODO make this return a range rather than a string. if (_mark.HasValue) { - var value = _template.Substring(_mark.Value, Index - _mark.Value); + var value = Template.Substring(_mark.Value, Index - _mark.Value); _mark = null; return value; } diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/Pattern.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/Pattern.cs similarity index 61% rename from src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/Pattern.cs rename to src/Microsoft.AspNetCore.Rewrite/Internal/Pattern.cs index a796da468f..2c6367ea67 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/Pattern.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/Pattern.cs @@ -2,10 +2,8 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System.Collections.Generic; -using System.Text; -using Microsoft.AspNetCore.Http; -namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite +namespace Microsoft.AspNetCore.Rewrite.Internal { public class Pattern { @@ -15,16 +13,16 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite PatternSegments = patternSegments; } - public string Evaluate(HttpContext context, MatchResults ruleMatch, MatchResults condMatch) + public string Evaluate(RewriteContext context, MatchResults ruleMatch, MatchResults condMatch) { - var strBuilder = new StringBuilder(); - // TODO consider thread static for string builder - DAVID PERF foreach (var pattern in PatternSegments) { - strBuilder.Append(pattern.Evaluate(context, ruleMatch, condMatch)); + context.Builder.Append(pattern.Evaluate(context, ruleMatch, condMatch)); } - return strBuilder.ToString(); + var retVal = context.Builder.ToString(); + context.Builder.Clear(); + return retVal; } } } diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/PatternSegment.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegment.cs similarity index 62% rename from src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/PatternSegment.cs rename to src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegment.cs index 820d5cdfb4..6ea96b915f 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/PatternSegment.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegment.cs @@ -2,12 +2,13 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite; -namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite +namespace Microsoft.AspNetCore.Rewrite.Internal { public abstract class PatternSegment { // Match from prevRule, Match from prevCond - public abstract string Evaluate(HttpContext context, MatchResults ruleMatch, MatchResults condMatch); + public abstract string Evaluate(RewriteContext context, MatchResults ruleMatch, MatchResults condMatch); } } diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/PatternSegments/ConditionMatchSegment.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/ConditionMatchSegment.cs similarity index 67% rename from src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/PatternSegments/ConditionMatchSegment.cs rename to src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/ConditionMatchSegment.cs index 1c65243e16..057164a4cc 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/PatternSegments/ConditionMatchSegment.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/ConditionMatchSegment.cs @@ -1,9 +1,7 @@ // 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 Microsoft.AspNetCore.Http; - -namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite.PatternSegments +namespace Microsoft.AspNetCore.Rewrite.Internal.PatternSegments { public class ConditionMatchSegment : PatternSegment { @@ -14,7 +12,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite.PatternSegments Index = index; } - public override string Evaluate(HttpContext context, MatchResults ruleMatch, MatchResults condMatch) + public override string Evaluate(RewriteContext context, MatchResults ruleMatch, MatchResults condMatch) { return condMatch?.BackReference[Index]?.Value; } diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/DateTimeSegment.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/DateTimeSegment.cs new file mode 100644 index 0000000000..bb535d5178 --- /dev/null +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/DateTimeSegment.cs @@ -0,0 +1,81 @@ +// 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; +using System.Globalization; + +namespace Microsoft.AspNetCore.Rewrite.Internal.PatternSegments +{ + public class DateTimeSegment : PatternSegment + { + private DateTimePortion _portion; + + public DateTimeSegment(string segment) + { + switch(segment) + { + case "TIME_YEAR": + _portion = DateTimePortion.Year; + break; + case "TIME_MON": + _portion = DateTimePortion.Month; + break; + case "TIME_DAY": + _portion = DateTimePortion.Day; + break; + case "TIME_HOUR": + _portion = DateTimePortion.Day; + break; + case "TIME_MIN": + _portion = DateTimePortion.Day; + break; + case "TIME_SEC": + _portion = DateTimePortion.Day; + break; + case "TIME_WDAY": + _portion = DateTimePortion.Day; + break; + case "TIME": + _portion = DateTimePortion.Day; + break; + default: + throw new FormatException("Unsupported segment: " + segment); + } + } + + public override string Evaluate(RewriteContext context, MatchResults ruleMatch, MatchResults condMatch) + { + switch (_portion) { + case DateTimePortion.Year: + return DateTimeOffset.UtcNow.Year.ToString(CultureInfo.InvariantCulture); + case DateTimePortion.Month: + return DateTimeOffset.UtcNow.Month.ToString(CultureInfo.InvariantCulture); + case DateTimePortion.Day: + return DateTimeOffset.UtcNow.Day.ToString(CultureInfo.InvariantCulture); + case DateTimePortion.Hour: + return DateTimeOffset.UtcNow.Hour.ToString(CultureInfo.InvariantCulture); + case DateTimePortion.Minute: + return DateTimeOffset.UtcNow.Minute.ToString(CultureInfo.InvariantCulture); + case DateTimePortion.Second: + return DateTimeOffset.UtcNow.Second.ToString(CultureInfo.InvariantCulture); + case DateTimePortion.DayOfWeek: + return ((int)DateTimeOffset.UtcNow.DayOfWeek).ToString(CultureInfo.InvariantCulture); + case DateTimePortion.Time: + return DateTimeOffset.UtcNow.ToString(CultureInfo.InvariantCulture); + default: + return string.Empty; + } + } + + private enum DateTimePortion { + Year, + Month, + Day, + Hour, + Minute, + Second, + DayOfWeek, + Time + } + } +} diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/PatternSegments/HeaderSegment.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/HeaderSegment.cs similarity index 59% rename from src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/PatternSegments/HeaderSegment.cs rename to src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/HeaderSegment.cs index c83b2cf6ad..116dca22c4 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/PatternSegments/HeaderSegment.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/HeaderSegment.cs @@ -1,9 +1,7 @@ // 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 Microsoft.AspNetCore.Http; - -namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite.PatternSegments +namespace Microsoft.AspNetCore.Rewrite.Internal.PatternSegments { public class HeaderSegment : PatternSegment { @@ -14,9 +12,9 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite.PatternSegments Header = header; } - public override string Evaluate(HttpContext context, MatchResults ruleMatch, MatchResults condMatch) + public override string Evaluate(RewriteContext context, MatchResults ruleMatch, MatchResults condMatch) { - return context.Request.Headers[Header]; + return context.HttpContext.Request.Headers[Header]; } } } diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/IsHttpsModSegment.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/IsHttpsModSegment.cs new file mode 100644 index 0000000000..c5a72eef55 --- /dev/null +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/IsHttpsModSegment.cs @@ -0,0 +1,13 @@ +// 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. + +namespace Microsoft.AspNetCore.Rewrite.Internal.PatternSegments +{ + public class IsHttpsModSegment : PatternSegment + { + public override string Evaluate(RewriteContext context, MatchResults ruleMatch, MatchResults condMatch) + { + return context.HttpContext.Request.IsHttps ? "on" : "off"; + } + } +} diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/IsHttpsSegment.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/IsHttpsSegment.cs new file mode 100644 index 0000000000..be940dd284 --- /dev/null +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/IsHttpsSegment.cs @@ -0,0 +1,13 @@ +// 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. + +namespace Microsoft.AspNetCore.Rewrite.Internal.PatternSegments +{ + public class IsHttpsSegment : PatternSegment + { + public override string Evaluate(RewriteContext context, MatchResults ruleMatch, MatchResults condMatch) + { + return context.HttpContext.Request.IsHttps ? "ON" : "OFF"; + } + } +} diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/IsIPV6Segment.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/IsIPV6Segment.cs new file mode 100644 index 0000000000..8131ae59a5 --- /dev/null +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/IsIPV6Segment.cs @@ -0,0 +1,20 @@ +// 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.Sockets; + +namespace Microsoft.AspNetCore.Rewrite.Internal.PatternSegments +{ + + public class IsIPV6Segment : PatternSegment + { + public override string Evaluate(RewriteContext context, MatchResults ruleMatch, MatchResults condMatch) + { + if (context.HttpContext.Connection.RemoteIpAddress == null) + { + return "off"; + } + return context.HttpContext.Connection.RemoteIpAddress.AddressFamily == AddressFamily.InterNetworkV6 ? "on" : "off"; + } + } +} diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/PatternSegments/LiteralSegment.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/LiteralSegment.cs similarity index 66% rename from src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/PatternSegments/LiteralSegment.cs rename to src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/LiteralSegment.cs index 390459c6c8..676a9e3d29 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/PatternSegments/LiteralSegment.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/LiteralSegment.cs @@ -1,9 +1,7 @@ // 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 Microsoft.AspNetCore.Http; - -namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite.PatternSegments +namespace Microsoft.AspNetCore.Rewrite.Internal.PatternSegments { public class LiteralSegment : PatternSegment { @@ -14,7 +12,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite.PatternSegments Literal = literal; } - public override string Evaluate(HttpContext context, MatchResults ruleMatch, MatchResults condMatch) + public override string Evaluate(RewriteContext context, MatchResults ruleMatch, MatchResults condMatch) { return Literal; } diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/LocalAddressSegment.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/LocalAddressSegment.cs new file mode 100644 index 0000000000..5fc5ef8c95 --- /dev/null +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/LocalAddressSegment.cs @@ -0,0 +1,13 @@ +// 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. + +namespace Microsoft.AspNetCore.Rewrite.Internal.PatternSegments +{ + public class LocalAddressSegment : PatternSegment + { + public override string Evaluate(RewriteContext context, MatchResults ruleMatch, MatchResults condMatch) + { + return context.HttpContext.Connection.LocalIpAddress?.ToString(); + } + } +} diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/LocalPortSegment.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/LocalPortSegment.cs new file mode 100644 index 0000000000..d7f62e2905 --- /dev/null +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/LocalPortSegment.cs @@ -0,0 +1,15 @@ +// 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.Globalization; + +namespace Microsoft.AspNetCore.Rewrite.Internal.PatternSegments +{ + public class LocalPortSegment : PatternSegment + { + public override string Evaluate(RewriteContext context, MatchResults ruleMatch, MatchResults condMatch) + { + return context.HttpContext.Connection.LocalPort.ToString(CultureInfo.InvariantCulture); + } + } +} diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/QueryStringSegment.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/QueryStringSegment.cs new file mode 100644 index 0000000000..86341bc5a8 --- /dev/null +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/QueryStringSegment.cs @@ -0,0 +1,13 @@ +// 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. + +namespace Microsoft.AspNetCore.Rewrite.Internal.PatternSegments +{ + public class QueryStringSegment : PatternSegment + { + public override string Evaluate(RewriteContext context, MatchResults ruleMatch, MatchResults condMatch) + { + return context.HttpContext.Request.QueryString.ToString(); + } + } +} diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/RemoteAddressSegment.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/RemoteAddressSegment.cs new file mode 100644 index 0000000000..c18ec14ab7 --- /dev/null +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/RemoteAddressSegment.cs @@ -0,0 +1,13 @@ +// 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. + +namespace Microsoft.AspNetCore.Rewrite.Internal.PatternSegments +{ + public class RemoteAddressSegment : PatternSegment + { + public override string Evaluate(RewriteContext context, MatchResults ruleMatch, MatchResults condMatch) + { + return context.HttpContext.Connection.RemoteIpAddress?.ToString(); + } + } +} \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/RemotePortSegment.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/RemotePortSegment.cs new file mode 100644 index 0000000000..9c0e0257bb --- /dev/null +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/RemotePortSegment.cs @@ -0,0 +1,15 @@ +// 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.Globalization; + +namespace Microsoft.AspNetCore.Rewrite.Internal.PatternSegments +{ + public class RemotePortSegment : PatternSegment + { + public override string Evaluate(RewriteContext context, MatchResults ruleMatch, MatchResults condMatch) + { + return context.HttpContext.Connection.RemotePort.ToString(CultureInfo.InvariantCulture); + } + } +} diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/PatternSegments/RequestFilenameSegment.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/RequestFilenameSegment.cs similarity index 50% rename from src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/PatternSegments/RequestFilenameSegment.cs rename to src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/RequestFilenameSegment.cs index 8d467684f6..fe74df5c2b 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/PatternSegments/RequestFilenameSegment.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/RequestFilenameSegment.cs @@ -1,15 +1,13 @@ // 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 Microsoft.AspNetCore.Http; - -namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite.PatternSegments +namespace Microsoft.AspNetCore.Rewrite.Internal.PatternSegments { public class RequestFileNameSegment : PatternSegment { - public override string Evaluate(HttpContext context, MatchResults ruleMatch, MatchResults condMatch) + public override string Evaluate(RewriteContext context, MatchResults ruleMatch, MatchResults condMatch) { - return context.Request.Path; + return context.HttpContext.Request.Path; } } } diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/RequestMethodSegment.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/RequestMethodSegment.cs new file mode 100644 index 0000000000..b10103ebf5 --- /dev/null +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/RequestMethodSegment.cs @@ -0,0 +1,13 @@ +// 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. + +namespace Microsoft.AspNetCore.Rewrite.Internal.PatternSegments +{ + public class RequestMethodSegment : PatternSegment + { + public override string Evaluate(RewriteContext context, MatchResults ruleMatch, MatchResults condMatch) + { + return context.HttpContext.Request.Method; + } + } +} diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/PatternSegments/RuleMatchSegment.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/RuleMatchSegment.cs similarity index 67% rename from src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/PatternSegments/RuleMatchSegment.cs rename to src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/RuleMatchSegment.cs index b8384aaa49..e54c08000b 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/PatternSegments/RuleMatchSegment.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/RuleMatchSegment.cs @@ -1,9 +1,7 @@ // 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 Microsoft.AspNetCore.Http; - -namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite.PatternSegments +namespace Microsoft.AspNetCore.Rewrite.Internal.PatternSegments { public class RuleMatchSegment : PatternSegment { @@ -14,7 +12,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite.PatternSegments Index = index; } - public override string Evaluate(HttpContext context, MatchResults ruleMatch, MatchResults condMatch) + public override string Evaluate(RewriteContext context, MatchResults ruleMatch, MatchResults condMatch) { return ruleMatch?.BackReference[Index]?.Value; } diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/SchemeSegment.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/SchemeSegment.cs new file mode 100644 index 0000000000..cd2bff5c06 --- /dev/null +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/SchemeSegment.cs @@ -0,0 +1,13 @@ +// 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. + +namespace Microsoft.AspNetCore.Rewrite.Internal.PatternSegments +{ + public class SchemeSegment : PatternSegment + { + public override string Evaluate(RewriteContext context, MatchResults ruleMatch, MatchResults condMatch) + { + return context.HttpContext.Request.Scheme; + } + } +} diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/ServerProtocolSegment.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/ServerProtocolSegment.cs new file mode 100644 index 0000000000..d2b1d8e6ec --- /dev/null +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/ServerProtocolSegment.cs @@ -0,0 +1,15 @@ +// 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 Microsoft.AspNetCore.Http.Features; + +namespace Microsoft.AspNetCore.Rewrite.Internal.PatternSegments +{ + public class ServerProtocolSegment : PatternSegment + { + public override string Evaluate(RewriteContext context, MatchResults ruleMatch, MatchResults condMatch) + { + return context.HttpContext.Features.Get()?.Protocol; + } + } +} diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/PatternSegments/ToLowerSegment.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/ToLowerSegment.cs similarity index 51% rename from src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/PatternSegments/ToLowerSegment.cs rename to src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/ToLowerSegment.cs index b2c9d85679..c61e056331 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/PatternSegments/ToLowerSegment.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/ToLowerSegment.cs @@ -1,9 +1,9 @@ // 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 Microsoft.AspNetCore.Http; +using System.Text; -namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite.PatternSegments +namespace Microsoft.AspNetCore.Rewrite.Internal.PatternSegments { public class ToLowerSegment : PatternSegment { @@ -14,9 +14,14 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite.PatternSegments Pattern = pattern; } - public override string Evaluate(HttpContext context, MatchResults ruleMatch, MatchResults condMatch) + public override string Evaluate(RewriteContext context, MatchResults ruleMatch, MatchResults condMatch) { + // PERF as we share the string builder across the context, we need to make a new one here to evaluate + // lowercase segments. + var tempBuilder = context.Builder; + context.Builder = new StringBuilder(64); var pattern = Pattern.Evaluate(context, ruleMatch, condMatch); + context.Builder = tempBuilder; return pattern.ToLowerInvariant(); } } diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/PatternSegments/UrlEncodeSegment.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/UrlEncodeSegment.cs similarity index 63% rename from src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/PatternSegments/UrlEncodeSegment.cs rename to src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/UrlEncodeSegment.cs index 83edb5019c..f64bb33cc6 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/PatternSegments/UrlEncodeSegment.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/UrlEncodeSegment.cs @@ -1,10 +1,10 @@ // 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.Text; using System.Text.Encodings.Web; -using Microsoft.AspNetCore.Http; -namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite.PatternSegments +namespace Microsoft.AspNetCore.Rewrite.Internal.PatternSegments { public class UrlEncodeSegment : PatternSegment { @@ -15,9 +15,12 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite.PatternSegments Pattern = pattern; } - public override string Evaluate(HttpContext context, MatchResults ruleMatch, MatchResults condMatch) + public override string Evaluate(RewriteContext context, MatchResults ruleMatch, MatchResults condMatch) { + var tempBuilder = context.Builder; + context.Builder = new StringBuilder(64); var pattern = Pattern.Evaluate(context, ruleMatch, condMatch); + context.Builder = tempBuilder; return UrlEncoder.Default.Encode(pattern); } } diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/UrlSegment.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/UrlSegment.cs new file mode 100644 index 0000000000..da8adce3f7 --- /dev/null +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/UrlSegment.cs @@ -0,0 +1,13 @@ +// 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. + +namespace Microsoft.AspNetCore.Rewrite.Internal.PatternSegments +{ + public class UrlSegment : PatternSegment + { + public override string Evaluate(RewriteContext context, MatchResults ruleMatch, MatchResults condMatch) + { + return context.HttpContext.Request.Path; + } + } +} diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/PreAction.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/PreAction.cs new file mode 100644 index 0000000000..08b1014c1c --- /dev/null +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/PreAction.cs @@ -0,0 +1,11 @@ + +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite; + +namespace Microsoft.AspNetCore.Rewrite.Internal +{ + public abstract class PreAction + { + public abstract void ApplyAction(HttpContext context, MatchResults ruleMatch, MatchResults condMatch); + } +} diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/PreActions/ChangeCookiePreAction.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/PreActions/ChangeCookiePreAction.cs new file mode 100644 index 0000000000..13d2dd3ba9 --- /dev/null +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/PreActions/ChangeCookiePreAction.cs @@ -0,0 +1,23 @@ +// 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; +using Microsoft.AspNetCore.Http; + +namespace Microsoft.AspNetCore.Rewrite.Internal.PreActions +{ + public class ChangeCookiePreAction : PreAction + { + public ChangeCookiePreAction(string cookie) + { + // TODO + throw new NotImplementedException(cookie); + } + + public override void ApplyAction(HttpContext context, MatchResults ruleMatch, MatchResults condMatch) + { + // modify the cookies + + } + } +} diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/PreActions/ChangeEnvironmentPreAction.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/PreActions/ChangeEnvironmentPreAction.cs new file mode 100644 index 0000000000..79e84bde7f --- /dev/null +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/PreActions/ChangeEnvironmentPreAction.cs @@ -0,0 +1,22 @@ +// 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; +using Microsoft.AspNetCore.Http; + +namespace Microsoft.AspNetCore.Rewrite.Internal.PreActions +{ + public class ChangeEnvironmentPreAction : PreAction + { + public ChangeEnvironmentPreAction(string env) + { + // TODO + throw new NotImplementedException(); + } + + public override void ApplyAction(HttpContext context, MatchResults ruleMatch, MatchResults condMatch) + { + // Do stuff to modify the env + } + } +} diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/UrlAction.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlAction.cs similarity index 57% rename from src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/UrlAction.cs rename to src/Microsoft.AspNetCore.Rewrite/Internal/UrlAction.cs index 489f4a6b53..f1676c7d79 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/UrlAction.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlAction.cs @@ -2,12 +2,13 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite; -namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite +namespace Microsoft.AspNetCore.Rewrite.Internal { public abstract class UrlAction { public Pattern Url { get; set; } - public abstract RuleResult ApplyAction(HttpContext context, MatchResults ruleMatch, MatchResults condMatch); + public abstract RuleResult ApplyAction(RewriteContext context, MatchResults ruleMatch, MatchResults condMatch); } } diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/ForbiddenAction.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/ForbiddenAction.cs new file mode 100644 index 0000000000..43589509f3 --- /dev/null +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/ForbiddenAction.cs @@ -0,0 +1,16 @@ +// 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 Microsoft.AspNetCore.Http; + +namespace Microsoft.AspNetCore.Rewrite.Internal.UrlActions +{ + public class ForbiddenAction : UrlAction + { + public override RuleResult ApplyAction(RewriteContext context, MatchResults ruleMatch, MatchResults condMatch) + { + context.HttpContext.Response.StatusCode = StatusCodes.Status403Forbidden; + return RuleResult.ResponseComplete; + } + } +} diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/GoneAction.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/GoneAction.cs new file mode 100644 index 0000000000..d56eb09744 --- /dev/null +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/GoneAction.cs @@ -0,0 +1,16 @@ +// 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 Microsoft.AspNetCore.Http; + +namespace Microsoft.AspNetCore.Rewrite.Internal.UrlActions +{ + public class GoneAction : UrlAction + { + public override RuleResult ApplyAction(RewriteContext context, MatchResults ruleMatch, MatchResults condMatch) + { + context.HttpContext.Response.StatusCode = StatusCodes.Status410Gone; + return RuleResult.ResponseComplete; + } + } +} diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/UrlActions/RedirectAction.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/RedirectAction.cs similarity index 58% rename from src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/UrlActions/RedirectAction.cs rename to src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/RedirectAction.cs index a990c346dc..245d1020f1 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/UrlActions/RedirectAction.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/RedirectAction.cs @@ -2,10 +2,9 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Rewrite.Internal; using Microsoft.Net.Http.Headers; -namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite.UrlActions +namespace Microsoft.AspNetCore.Rewrite.Internal.UrlActions { public class RedirectAction : UrlAction { @@ -16,11 +15,11 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite.UrlActions Url = pattern; } - public override RuleResult ApplyAction(HttpContext context, MatchResults ruleMatch, MatchResults condMatch) + public override RuleResult ApplyAction(RewriteContext context, MatchResults ruleMatch, MatchResults condMatch) { var pattern = Url.Evaluate(context, ruleMatch, condMatch); - context.Response.StatusCode = StatusCode; + context.HttpContext.Response.StatusCode = StatusCode; // url can either contain the full url or the path and query // always add to location header. @@ -28,13 +27,13 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite.UrlActions var split = pattern.IndexOf('?'); if (split >= 0) { - var query = context.Request.QueryString.Add(new QueryString(pattern.Substring(split))); - // not using the response.redirect here because status codes may be 301, 302, 307, 308 - context.Response.Headers[HeaderNames.Location] = pattern.Substring(0, split) + query; + var query = context.HttpContext.Request.QueryString.Add(new QueryString(pattern.Substring(split))); + // not using the HttpContext.Response.redirect here because status codes may be 301, 302, 307, 308 + context.HttpContext.Response.Headers[HeaderNames.Location] = pattern.Substring(0, split) + query; } else { - context.Response.Headers[HeaderNames.Location] = pattern; + context.HttpContext.Response.Headers[HeaderNames.Location] = pattern; } return RuleResult.ResponseComplete; } diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/UrlActions/RedirectClearQueryAction.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/RedirectClearQueryAction.cs similarity index 67% rename from src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/UrlActions/RedirectClearQueryAction.cs rename to src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/RedirectClearQueryAction.cs index a6439811c5..c48bb00202 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/UrlActions/RedirectClearQueryAction.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/RedirectClearQueryAction.cs @@ -2,10 +2,9 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Rewrite.Internal; using Microsoft.Net.Http.Headers; -namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite.UrlActions +namespace Microsoft.AspNetCore.Rewrite.Internal.UrlActions { public class RedirectClearQueryAction : UrlAction { @@ -16,13 +15,13 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite.UrlActions Url = pattern; } - public override RuleResult ApplyAction(HttpContext context, MatchResults ruleMatch, MatchResults condMatch) + public override RuleResult ApplyAction(RewriteContext context, MatchResults ruleMatch, MatchResults condMatch) { var pattern = Url.Evaluate(context, ruleMatch, condMatch); - context.Response.StatusCode = StatusCode; + context.HttpContext.Response.StatusCode = StatusCode; // we are clearing the query, so just put the pattern in the location header - context.Response.Headers[HeaderNames.Location] = pattern; + context.HttpContext.Response.Headers[HeaderNames.Location] = pattern; return RuleResult.ResponseComplete; } } diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/UrlActions/RewriteAction.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/RewriteAction.cs similarity index 58% rename from src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/UrlActions/RewriteAction.cs rename to src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/RewriteAction.cs index 105b023dd8..1574c2310e 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/UrlActions/RewriteAction.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/RewriteAction.cs @@ -4,7 +4,7 @@ using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http.Extensions; -namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite.UrlActions +namespace Microsoft.AspNetCore.Rewrite.Internal.UrlActions { public class RewriteAction : UrlAction { @@ -19,28 +19,28 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite.UrlActions ClearQuery = clearQuery; } - public override RuleResult ApplyAction(HttpContext context, MatchResults ruleMatch, MatchResults condMatch) + public override RuleResult ApplyAction(RewriteContext context, MatchResults ruleMatch, MatchResults condMatch) { var pattern = Url.Evaluate(context, ruleMatch, condMatch); if (ClearQuery) { - context.Request.QueryString = new QueryString(); + context.HttpContext.Request.QueryString = new QueryString(); } // TODO PERF, substrings, object creation, etc. if (pattern.IndexOf("://") >= 0) { string scheme = null; - var host = new HostString(); - var path = new PathString(); - var query = new QueryString(); - var fragment = new FragmentString(); + HostString host; + PathString path; + QueryString query; + FragmentString fragment; UriHelper.FromAbsolute(pattern, out scheme, out host, out path, out query, out fragment); - context.Request.Scheme = scheme; - context.Request.Host = host; - context.Request.Path = path; - context.Request.QueryString = query.Add(context.Request.QueryString); + context.HttpContext.Request.Scheme = scheme; + context.HttpContext.Request.Host = host; + context.HttpContext.Request.Path = path; + context.HttpContext.Request.QueryString = query.Add(context.HttpContext.Request.QueryString); } else { @@ -50,23 +50,23 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite.UrlActions var path = pattern.Substring(0, split); if (path.StartsWith(ForwardSlash)) { - context.Request.Path = new PathString(path); + context.HttpContext.Request.Path = PathString.FromUriComponent(path); } else { - context.Request.Path = new PathString(ForwardSlash + path); + context.HttpContext.Request.Path = PathString.FromUriComponent(ForwardSlash + path); } - context.Request.QueryString = context.Request.QueryString.Add(new QueryString(pattern.Substring(split))); + context.HttpContext.Request.QueryString = context.HttpContext.Request.QueryString.Add(new QueryString(pattern.Substring(split))); } else { if (pattern.StartsWith(ForwardSlash)) { - context.Request.Path = new PathString(pattern); + context.HttpContext.Request.Path = PathString.FromUriComponent(pattern); } else { - context.Request.Path = new PathString(ForwardSlash + pattern); + context.HttpContext.Request.Path = PathString.FromUriComponent(ForwardSlash + pattern); } } } diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/UrlActions/VoidAction.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/VoidAction.cs similarity index 61% rename from src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/UrlActions/VoidAction.cs rename to src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/VoidAction.cs index 5098a06ee6..7bf14afb11 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/UrlActions/VoidAction.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/VoidAction.cs @@ -2,14 +2,13 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Rewrite.Internal; -namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite.UrlActions +namespace Microsoft.AspNetCore.Rewrite.Internal.UrlActions { public class VoidAction : UrlAction { // Explicitly say that nothing happens - public override RuleResult ApplyAction(HttpContext context, MatchResults ruleMatch, MatchResults condMatch) + public override RuleResult ApplyAction(RewriteContext context, MatchResults ruleMatch, MatchResults condMatch) { return RuleResult.Continue; } diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/UrlMatch.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlMatch.cs similarity index 85% rename from src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/UrlMatch.cs rename to src/Microsoft.AspNetCore.Rewrite/Internal/UrlMatch.cs index 5cd97d9c94..428c24ea75 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/UrlMatch.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlMatch.cs @@ -1,7 +1,7 @@ // 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. -namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite +namespace Microsoft.AspNetCore.Rewrite.Internal { public abstract class UrlMatch { diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/UrlMatches/ExactMatch.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlMatches/ExactMatch.cs similarity index 91% rename from src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/UrlMatches/ExactMatch.cs rename to src/Microsoft.AspNetCore.Rewrite/Internal/UrlMatches/ExactMatch.cs index a42fe3e6a1..39b6449524 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/UrlMatches/ExactMatch.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlMatches/ExactMatch.cs @@ -1,7 +1,7 @@ // 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. -namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite.UrlMatches +namespace Microsoft.AspNetCore.Rewrite.Internal.UrlMatches { public class ExactMatch : UrlMatch { diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlMatches/FileSizeMatch.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlMatches/FileSizeMatch.cs new file mode 100644 index 0000000000..d2d6397408 --- /dev/null +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlMatches/FileSizeMatch.cs @@ -0,0 +1,19 @@ +// 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. + +namespace Microsoft.AspNetCore.Rewrite.Internal.UrlMatches +{ + public class FileSizeMatch : UrlMatch + { + public FileSizeMatch(bool negate) + { + Negate = negate; + } + + public override MatchResults Evaluate(string input, RewriteContext context) + { + var fileInfo = context.FileProvider.GetFileInfo(input); + return fileInfo.Exists && fileInfo.Length > 0 ? MatchResults.EmptySuccess : MatchResults.EmptyFailure; + } + } +} diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/Operands/IntegerOperand.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlMatches/IntegerMatch.cs similarity index 52% rename from src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/Operands/IntegerOperand.cs rename to src/Microsoft.AspNetCore.Rewrite/Internal/UrlMatches/IntegerMatch.cs index 227d1c2bbe..185c8de53e 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/Operands/IntegerOperand.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlMatches/IntegerMatch.cs @@ -3,22 +3,20 @@ using System; using System.Globalization; -using System.Text.RegularExpressions; -using Microsoft.Extensions.FileProviders; -namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite.Operands +namespace Microsoft.AspNetCore.Rewrite.Internal.UrlMatches { - public class IntegerOperand : Operand + public class IntegerMatch : UrlMatch { public int Value { get; } public IntegerOperationType Operation { get; } - public IntegerOperand(int value, IntegerOperationType operation) + public IntegerMatch(int value, IntegerOperationType operation) { Value = value; Operation = operation; } - public IntegerOperand(string value, IntegerOperationType operation) + public IntegerMatch(string value, IntegerOperationType operation) { int compValue; if (!int.TryParse(value, NumberStyles.None, CultureInfo.InvariantCulture, out compValue)) @@ -29,27 +27,28 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite.Operands Operation = operation; } - public override bool? CheckOperation(Match previous, string testString, IFileProvider fileProvider) + public override MatchResults Evaluate(string input, RewriteContext context) { int compValue; - if (!int.TryParse(testString, NumberStyles.None, CultureInfo.InvariantCulture, out compValue)) + if (!int.TryParse(input, NumberStyles.None, CultureInfo.InvariantCulture, out compValue)) { - return false; + return MatchResults.EmptyFailure; } + switch (Operation) { case IntegerOperationType.Equal: - return compValue == Value; + return compValue == Value ? MatchResults.EmptySuccess : MatchResults.EmptyFailure; case IntegerOperationType.Greater: - return compValue > Value; + return compValue > Value ? MatchResults.EmptySuccess : MatchResults.EmptyFailure; case IntegerOperationType.GreaterEqual: - return compValue >= Value; + return compValue >= Value ? MatchResults.EmptySuccess : MatchResults.EmptyFailure; case IntegerOperationType.Less: - return compValue < Value; + return compValue < Value ? MatchResults.EmptySuccess : MatchResults.EmptyFailure; case IntegerOperationType.LessEqual: - return compValue <= Value; + return compValue <= Value ? MatchResults.EmptySuccess : MatchResults.EmptyFailure; case IntegerOperationType.NotEqual: - return compValue != Value; + return compValue != Value ? MatchResults.EmptySuccess : MatchResults.EmptyFailure; default: return null; } diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/Operands/IntegerOperation.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlMatches/IntegerOperation.cs similarity index 82% rename from src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/Operands/IntegerOperation.cs rename to src/Microsoft.AspNetCore.Rewrite/Internal/UrlMatches/IntegerOperation.cs index 873846e123..fce53e3844 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/Operands/IntegerOperation.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlMatches/IntegerOperation.cs @@ -1,7 +1,7 @@ // 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. -namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite.Operands +namespace Microsoft.AspNetCore.Rewrite.Internal.UrlMatches { public enum IntegerOperationType { diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/UrlMatches/IsDirectoryMatch.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlMatches/IsDirectoryMatch.cs similarity index 89% rename from src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/UrlMatches/IsDirectoryMatch.cs rename to src/Microsoft.AspNetCore.Rewrite/Internal/UrlMatches/IsDirectoryMatch.cs index 9c1068ada0..97d1177714 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/UrlMatches/IsDirectoryMatch.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlMatches/IsDirectoryMatch.cs @@ -1,7 +1,7 @@ // 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. -namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite.UrlMatches +namespace Microsoft.AspNetCore.Rewrite.Internal.UrlMatches { public class IsDirectoryMatch : UrlMatch { diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/UrlMatches/IsFileMatch.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlMatches/IsFileMatch.cs similarity index 88% rename from src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/UrlMatches/IsFileMatch.cs rename to src/Microsoft.AspNetCore.Rewrite/Internal/UrlMatches/IsFileMatch.cs index ebce79b655..6dc8d9ea0b 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/UrlMatches/IsFileMatch.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlMatches/IsFileMatch.cs @@ -1,7 +1,7 @@ // 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. -namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite.UrlMatches +namespace Microsoft.AspNetCore.Rewrite.Internal.UrlMatches { public class IsFileMatch : UrlMatch { diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/UrlMatches/RegexMatch.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlMatches/RegexMatch.cs similarity index 91% rename from src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/UrlMatches/RegexMatch.cs rename to src/Microsoft.AspNetCore.Rewrite/Internal/UrlMatches/RegexMatch.cs index a1859a9370..a932d869f6 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/UrlMatches/RegexMatch.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlMatches/RegexMatch.cs @@ -4,7 +4,7 @@ using System; using System.Text.RegularExpressions; -namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite.UrlMatches +namespace Microsoft.AspNetCore.Rewrite.Internal.UrlMatches { public class RegexMatch : UrlMatch { diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlMatches/StringMatch.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlMatches/StringMatch.cs new file mode 100644 index 0000000000..81332401fe --- /dev/null +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlMatches/StringMatch.cs @@ -0,0 +1,36 @@ +// 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. + +namespace Microsoft.AspNetCore.Rewrite.Internal.UrlMatches +{ + public class StringMatch : UrlMatch + { + public string Value { get; set; } + public StringOperationType Operation { get; set; } + public bool IgnoreCase { get; set; } + public StringMatch(string value, StringOperationType operation) + { + Value = value; + Operation = operation; + } + + public override MatchResults Evaluate(string input, RewriteContext context) + { + switch (Operation) + { + case StringOperationType.Equal: + return string.Compare(input, Value, IgnoreCase) == 0 ? MatchResults.EmptySuccess : MatchResults.EmptyFailure; + case StringOperationType.Greater: + return string.Compare(input, Value, IgnoreCase) > 0 ? MatchResults.EmptySuccess : MatchResults.EmptyFailure; + case StringOperationType.GreaterEqual: + return string.Compare(input, Value, IgnoreCase) >= 0 ? MatchResults.EmptySuccess : MatchResults.EmptyFailure; + case StringOperationType.Less: + return string.Compare(input, Value, IgnoreCase) < 0 ? MatchResults.EmptySuccess : MatchResults.EmptyFailure; + case StringOperationType.LessEqual: + return string.Compare(input, Value, IgnoreCase) <= 0 ? MatchResults.EmptySuccess : MatchResults.EmptyFailure; + default: + return null; + } + } + } +} diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/Operands/StringOperation.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlMatches/StringOperation.cs similarity index 81% rename from src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/Operands/StringOperation.cs rename to src/Microsoft.AspNetCore.Rewrite/Internal/UrlMatches/StringOperation.cs index a35a51bf9e..15ff45d5f0 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/Operands/StringOperation.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlMatches/StringOperation.cs @@ -1,7 +1,7 @@ // 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. -namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite.Operands +namespace Microsoft.AspNetCore.Rewrite.Internal.UrlMatches { public enum StringOperationType { diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/Conditions.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/Conditions.cs deleted file mode 100644 index b9ffa5b26c..0000000000 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/Conditions.cs +++ /dev/null @@ -1,27 +0,0 @@ -// 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.Collections.Generic; - -namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite -{ - public class Conditions - { - public List ConditionList { get; set; } = new List(); - public LogicalGrouping MatchType { get; set; } // default is MatchAll - public bool TrackingAllCaptures { get; set; } - - public MatchResults Evaluate(RewriteContext context, MatchResults ruleMatch) - { - MatchResults prevCond = null; - var success = true; - foreach (var condition in ConditionList) - { - var res = condition.Evaluate(context, ruleMatch, prevCond); - success = (MatchType == LogicalGrouping.MatchAll ? (success && res.Success) : (success || res.Success)); - prevCond = res; - } - return new MatchResults { Success = success, BackReference = prevCond?.BackReference }; - } - } -} diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/InputParser.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/InputParser.cs index 08b666634b..a4e33665a3 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/InputParser.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/InputParser.cs @@ -3,12 +3,11 @@ using System; using System.Collections.Generic; -using Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite.PatternSegments; +using Microsoft.AspNetCore.Rewrite.Internal; +using Microsoft.AspNetCore.Rewrite.Internal.PatternSegments; namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite { - /// - /// public class InputParser { private const char Colon = ':'; diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/PatternSegments/IsHttpsSegment.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/PatternSegments/IsHttpsSegment.cs deleted file mode 100644 index 5ffece8e11..0000000000 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/PatternSegments/IsHttpsSegment.cs +++ /dev/null @@ -1,15 +0,0 @@ -// 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 Microsoft.AspNetCore.Http; - -namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite.PatternSegments -{ - public class IsHttpsSegment : PatternSegment - { - public override string Evaluate(HttpContext context, MatchResults ruleMatch, MatchResults condMatch) - { - return context.Request.IsHttps ? "ON" : "OFF"; - } - } -} diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/PatternSegments/LocalAddressSegment.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/PatternSegments/LocalAddressSegment.cs deleted file mode 100644 index 10d77aeb02..0000000000 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/PatternSegments/LocalAddressSegment.cs +++ /dev/null @@ -1,15 +0,0 @@ -// 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 Microsoft.AspNetCore.Http; - -namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite.PatternSegments -{ - public class LocalAddressSegment : PatternSegment - { - public override string Evaluate(HttpContext context, MatchResults ruleMatch, MatchResults condMatch) - { - return context.Connection.LocalIpAddress?.ToString(); - } - } -} diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/PatternSegments/QueryStringSegment.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/PatternSegments/QueryStringSegment.cs deleted file mode 100644 index d5081a4e6a..0000000000 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/PatternSegments/QueryStringSegment.cs +++ /dev/null @@ -1,15 +0,0 @@ -// 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 Microsoft.AspNetCore.Http; - -namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite.PatternSegments -{ - public class QueryStringSegment : PatternSegment - { - public override string Evaluate(HttpContext context, MatchResults ruleMatch, MatchResults condMatch) - { - return context.Request.QueryString.ToString(); - } - } -} diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/PatternSegments/RemoteAddressSegment.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/PatternSegments/RemoteAddressSegment.cs deleted file mode 100644 index 499b5a3e91..0000000000 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/PatternSegments/RemoteAddressSegment.cs +++ /dev/null @@ -1,15 +0,0 @@ -// 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 Microsoft.AspNetCore.Http; - -namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite.PatternSegments -{ - public class RemoteAddressSegment : PatternSegment - { - public override string Evaluate(HttpContext context, MatchResults ruleMatch, MatchResults condMatch) - { - return context.Connection.RemoteIpAddress?.ToString(); - } - } -} \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/PatternSegments/RemotePortSegment.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/PatternSegments/RemotePortSegment.cs deleted file mode 100644 index 25456dc102..0000000000 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/PatternSegments/RemotePortSegment.cs +++ /dev/null @@ -1,16 +0,0 @@ -// 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.Globalization; -using Microsoft.AspNetCore.Http; - -namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite.PatternSegments -{ - public class RemotePortSegment : PatternSegment - { - public override string Evaluate(HttpContext context, MatchResults ruleMatch, MatchResults condMatch) - { - return context.Connection.RemotePort.ToString(CultureInfo.InvariantCulture); - } - } -} diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/PatternSegments/UrlSegment.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/PatternSegments/UrlSegment.cs deleted file mode 100644 index dca3bfb5de..0000000000 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/PatternSegments/UrlSegment.cs +++ /dev/null @@ -1,15 +0,0 @@ -// 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 Microsoft.AspNetCore.Http; - -namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite.PatternSegments -{ - public class UrlSegment : PatternSegment - { - public override string Evaluate(HttpContext context, MatchResults ruleMatch, MatchResults condMatch) - { - return context.Request.Path; - } - } -} diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/ServerVariables.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/ServerVariables.cs index 9fa1a84bcc..aa5845a872 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/ServerVariables.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/ServerVariables.cs @@ -2,7 +2,8 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; -using Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite.PatternSegments; +using Microsoft.AspNetCore.Rewrite.Internal; +using Microsoft.AspNetCore.Rewrite.Internal.PatternSegments; using Microsoft.Net.Http.Headers; namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite @@ -15,9 +16,9 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite { // TODO Add all server variables here. case "ALL_RAW": - throw new NotImplementedException(); + throw new NotImplementedException("All-Raw server variable not implemented"); case "APP_POOL_ID": - throw new NotImplementedException(); + throw new NotImplementedException("All-Pool-Id server variable not implemented"); case "CONTENT_LENGTH": return new HeaderSegment(HeaderNames.ContentLength); case "CONTENT_TYPE": @@ -47,7 +48,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite case "REMOTE_ADDR": return new RemoteAddressSegment(); case "REMOTE_HOST": - throw new NotImplementedException(); + throw new NotImplementedException("Remote-Host server variable not implemented"); case "REMOTE_PORT": return new RemotePortSegment(); case "REQUEST_FILENAME": diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/UrlRewriteFileParser.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/UrlRewriteFileParser.cs index 4f9e0bbc22..39703c5e2e 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/UrlRewriteFileParser.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/UrlRewriteFileParser.cs @@ -7,6 +7,7 @@ using System.IO; using System.Linq; using System.Xml; using System.Xml.Linq; +using Microsoft.AspNetCore.Rewrite.Internal; namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite { @@ -111,8 +112,6 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite builder.AddUrlMatch(parsedInputString, ignoreCase, negate, patternSyntax); } - - private static void ParseConditions(XElement conditions, UrlRewriteRuleBuilder builder, PatternSyntax patternSyntax) { if (conditions == null) diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/UrlRewriteRuleBuilder.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/UrlRewriteRuleBuilder.cs index ccee529c0a..2c4b9814ab 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/UrlRewriteRuleBuilder.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/UrlRewriteRuleBuilder.cs @@ -5,8 +5,9 @@ using System; using System.Collections.Generic; using System.Text.RegularExpressions; using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite.UrlActions; -using Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite.UrlMatches; +using Microsoft.AspNetCore.Rewrite.Internal; +using Microsoft.AspNetCore.Rewrite.Internal.UrlActions; +using Microsoft.AspNetCore.Rewrite.Internal.UrlMatches; namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite { @@ -20,6 +21,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite private UrlMatch _initialMatch; private Conditions _conditions; private UrlAction _action; + private bool _matchAny; public UrlRewriteRule Build() { @@ -96,10 +98,12 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite // TODO make this take two overloads and handle regex vs non regex case. public void AddUrlCondition(Pattern input, string pattern, PatternSyntax patternSyntax, MatchType matchType, bool ignoreCase, bool negate) { + // If there are no conditions specified, if (_conditions == null) { AddUrlConditions(LogicalGrouping.MatchAll, trackingAllCaptures: false); } + switch (patternSyntax) { case PatternSyntax.ECMAScript: @@ -123,17 +127,17 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite regex = new Regex(pattern, RegexOptions.Compiled, RegexTimeout); } - _conditions.ConditionList.Add(new Condition { Input = input, Match = new RegexMatch(regex, negate) }); + _conditions.ConditionList.Add(new Condition { Input = input, Match = new RegexMatch(regex, negate), OrNext = _matchAny}); break; } case MatchType.IsDirectory: { - _conditions.ConditionList.Add(new Condition { Input = input, Match = new IsDirectoryMatch(negate) }); + _conditions.ConditionList.Add(new Condition { Input = input, Match = new IsDirectoryMatch(negate), OrNext = _matchAny }); break; } case MatchType.IsFile: { - _conditions.ConditionList.Add(new Condition { Input = input, Match = new IsFileMatch(negate) }); + _conditions.ConditionList.Add(new Condition { Input = input, Match = new IsFileMatch(negate), OrNext = _matchAny }); break; } default: @@ -149,7 +153,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite { throw new FormatException("Match does not have an associated pattern attribute in condition"); } - _conditions.ConditionList.Add(new Condition { Input = input, Match = new ExactMatch(ignoreCase, pattern, negate) }); + _conditions.ConditionList.Add(new Condition { Input = input, Match = new ExactMatch(ignoreCase, pattern, negate), OrNext = _matchAny }); break; default: throw new FormatException("Unrecognized pattern syntax"); @@ -160,8 +164,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite { var conditions = new Conditions(); conditions.ConditionList = new List(); - conditions.MatchType = logicalGrouping; - conditions.TrackingAllCaptures = trackingAllCaptures; + _matchAny = logicalGrouping == LogicalGrouping.MatchAny; _conditions = conditions; } } diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewriteRule.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewriteRule.cs index 4295548204..35ed34065f 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewriteRule.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewriteRule.cs @@ -1,7 +1,12 @@ // 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. -namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite +using System; +using System.Diagnostics; +using System.Text.RegularExpressions; +using Microsoft.AspNetCore.Rewrite.Internal; + +namespace Microsoft.AspNetCore.Rewrite.Internal { public class UrlRewriteRule : Rule { @@ -39,7 +44,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite } // at this point we know the rule passed, evaluate the replacement. - return Action.ApplyAction(context.HttpContext, initMatchRes, condMatchRes); + return Action.ApplyAction(context, initMatchRes, condMatchRes); } } } \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Rewrite/ModRewriteExtensions.cs b/src/Microsoft.AspNetCore.Rewrite/ModRewriteExtensions.cs index c8af9432cc..77dc019956 100644 --- a/src/Microsoft.AspNetCore.Rewrite/ModRewriteExtensions.cs +++ b/src/Microsoft.AspNetCore.Rewrite/ModRewriteExtensions.cs @@ -36,7 +36,7 @@ namespace Microsoft.AspNetCore.Rewrite var path = Path.Combine(hostingEnv.ContentRootPath, filePath); using (var stream = File.OpenRead(path)) { - options.Rules.AddRange(FileParser.Parse(new StreamReader(stream))); + options.Rules.AddRange(new FileParser().Parse(new StreamReader(stream))); }; return options; } @@ -57,7 +57,7 @@ namespace Microsoft.AspNetCore.Rewrite { throw new ArgumentNullException(nameof(reader)); } - options.Rules.AddRange(FileParser.Parse(reader)); + options.Rules.AddRange(new FileParser().Parse(reader)); return options; } @@ -79,7 +79,8 @@ namespace Microsoft.AspNetCore.Rewrite throw new ArgumentNullException(nameof(rule)); } - var builder = new RuleBuilder(rule); + var builder = new RuleBuilder(); + builder.AddRule(rule); options.Rules.Add(builder.Build()); return options; } diff --git a/src/Microsoft.AspNetCore.Rewrite/Properties/Resources.Designer.cs b/src/Microsoft.AspNetCore.Rewrite/Properties/Resources.Designer.cs index 3be99059c0..4ab56f4ce3 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Properties/Resources.Designer.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Properties/Resources.Designer.cs @@ -106,6 +106,38 @@ namespace Microsoft.AspNetCore.Rewrite return string.Format(CultureInfo.CurrentCulture, GetString("Error_InputParserUnrecognizedParameter"), p0, p1); } + /// + /// Could not parse the mod_rewrite file. Message: '{0}'. Line number '{1}'. + /// + internal static string Error_ModRewriteParseError + { + get { return GetString("Error_ModRewriteParseError"); } + } + + /// + /// Could not parse the mod_rewrite file. Message: '{0}'. Line number '{1}'. + /// + internal static string FormatError_ModRewriteParseError(object p0, object p1) + { + return string.Format(CultureInfo.CurrentCulture, GetString("Error_ModRewriteParseError"), p0, p1); + } + + /// + /// Could not parse the mod_rewrite file. Line number '{0}'. + /// + internal static string Error_ModRewriteGeneralParseError + { + get { return GetString("Error_ModRewriteGeneralParseError"); } + } + + /// + /// Could not parse the mod_rewrite file. Line number '{0}'. + /// + internal static string FormatError_ModRewriteGeneralParseError(object p0) + { + return string.Format(CultureInfo.CurrentCulture, GetString("Error_ModRewriteGeneralParseError"), p0); + } + private static string GetString(string name, params string[] formatterNames) { var value = _resourceManager.GetString(name); diff --git a/src/Microsoft.AspNetCore.Rewrite/Resources.resx b/src/Microsoft.AspNetCore.Rewrite/Resources.resx index ae034489ee..cb7277289a 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Resources.resx +++ b/src/Microsoft.AspNetCore.Rewrite/Resources.resx @@ -135,4 +135,10 @@ Unrecognized parameter type: '{0}', terminated at string index: '{1}' + + Could not parse the mod_rewrite file. Message: '{0}'. Line number '{1}'. + + + Could not parse the mod_rewrite file. Line number '{0}'. + \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Rewrite/RewriteContext.cs b/src/Microsoft.AspNetCore.Rewrite/RewriteContext.cs index 12b1da7a48..be7108787d 100644 --- a/src/Microsoft.AspNetCore.Rewrite/RewriteContext.cs +++ b/src/Microsoft.AspNetCore.Rewrite/RewriteContext.cs @@ -1,6 +1,7 @@ // 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.Text; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.FileProviders; @@ -13,5 +14,7 @@ namespace Microsoft.AspNetCore.Rewrite { public HttpContext HttpContext { get; set; } public IFileProvider FileProvider { get; set; } + // PERF: share the same string builder per request + internal StringBuilder Builder { get; set; } = new StringBuilder(64); } } diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/ModRewrite/ConditionActionTest.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/ModRewrite/ConditionActionTest.cs index d49d9ef695..d0d7ac7f57 100644 --- a/test/Microsoft.AspNetCore.Rewrite.Tests/ModRewrite/ConditionActionTest.cs +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/ModRewrite/ConditionActionTest.cs @@ -18,7 +18,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.ModRewrite { var results = ConditionPatternParser.ParseActionCondition(condition); - var expected = new ParsedModRewriteExpression { Operation = operation, Type = conditionType, Operand = variable, Invert = false }; + var expected = new ParsedModRewriteInput { OperationType = operation, ConditionType = conditionType, Operand = variable, Invert = false }; Assert.True(CompareConditions(results, expected)); } @@ -28,7 +28,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.ModRewrite var condition = @"(.*)"; var results = ConditionPatternParser.ParseActionCondition(condition); - var expected = new ParsedModRewriteExpression { Type = ConditionType.Regex, Operand = "(.*)", Invert = false }; + var expected = new ParsedModRewriteInput { ConditionType = ConditionType.Regex, Operand = "(.*)", Invert = false }; Assert.True(CompareConditions(results, expected)); } @@ -46,7 +46,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.ModRewrite { var results = ConditionPatternParser.ParseActionCondition(condition); - var expected = new ParsedModRewriteExpression { Type = cond, Operation = operation , Invert = false }; + var expected = new ParsedModRewriteInput { ConditionType = cond, OperationType = operation , Invert = false }; Assert.True(CompareConditions(results, expected)); } @@ -64,7 +64,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.ModRewrite { var results = ConditionPatternParser.ParseActionCondition(condition); - var expected = new ParsedModRewriteExpression { Type = cond, Operation = operation, Invert = true }; + var expected = new ParsedModRewriteInput { ConditionType = cond, OperationType = operation, Invert = true }; Assert.True(CompareConditions(results, expected)); } @@ -79,15 +79,15 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.ModRewrite { var results = ConditionPatternParser.ParseActionCondition(condition); - var expected = new ParsedModRewriteExpression { Type = cond, Operation = operation, Invert = false, Operand = variable }; + var expected = new ParsedModRewriteInput { ConditionType = cond, OperationType = operation, Invert = false, Operand = variable }; Assert.True(CompareConditions(results, expected)); } // TODO negative tests - private bool CompareConditions(ParsedModRewriteExpression i1, ParsedModRewriteExpression i2) + private bool CompareConditions(ParsedModRewriteInput i1, ParsedModRewriteInput i2) { - if (i1.Operation != i2.Operation || - i1.Type != i2.Type || + if (i1.OperationType != i2.OperationType || + i1.ConditionType != i2.ConditionType || i1.Operand != i2.Operand || i1.Invert != i2.Invert) { diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/ModRewrite/FlagParserTest.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/ModRewrite/FlagParserTest.cs index 572f376f2f..39c6cedb24 100644 --- a/test/Microsoft.AspNetCore.Rewrite.Tests/ModRewrite/FlagParserTest.cs +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/ModRewrite/FlagParserTest.cs @@ -13,10 +13,10 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.ModRewrite [Fact] public void FlagParser_CheckSingleTerm() { - var results = FlagParser.ParseRuleFlags("[NC]"); - var dict = new Dictionary(); - dict.Add(RuleFlagType.NoCase, string.Empty); - var expected = new RuleFlags(dict); + var results = FlagParser.Parse("[NC]"); + var dict = new Dictionary(); + dict.Add(FlagType.NoCase, string.Empty); + var expected = new Flags(dict); Assert.True(DictionaryContentsEqual(results.FlagDictionary, expected.FlagDictionary)); } @@ -24,12 +24,12 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.ModRewrite [Fact] public void FlagParser_CheckManyTerms() { - var results = FlagParser.ParseRuleFlags("[NC,F,L]"); - var dict = new Dictionary(); - dict.Add(RuleFlagType.NoCase, string.Empty); - dict.Add(RuleFlagType.Forbidden, string.Empty); - dict.Add(RuleFlagType.Last, string.Empty); - var expected = new RuleFlags(dict); + var results = FlagParser.Parse("[NC,F,L]"); + var dict = new Dictionary(); + dict.Add(FlagType.NoCase, string.Empty); + dict.Add(FlagType.Forbidden, string.Empty); + dict.Add(FlagType.Last, string.Empty); + var expected = new Flags(dict); Assert.True(DictionaryContentsEqual(results.FlagDictionary, expected.FlagDictionary)); } @@ -37,12 +37,12 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.ModRewrite [Fact] public void FlagParser_CheckManyTermsWithEquals() { - var results = FlagParser.ParseRuleFlags("[NC,F,R=301]"); - var dict = new Dictionary(); - dict.Add(RuleFlagType.NoCase, string.Empty); - dict.Add(RuleFlagType.Forbidden, string.Empty); - dict.Add(RuleFlagType.Redirect, "301"); - var expected = new RuleFlags(dict); + var results = FlagParser.Parse("[NC,F,R=301]"); + var dict = new Dictionary(); + dict.Add(FlagType.NoCase, string.Empty); + dict.Add(FlagType.Forbidden, string.Empty); + dict.Add(FlagType.Redirect, "301"); + var expected = new Flags(dict); Assert.True(DictionaryContentsEqual(results.FlagDictionary, expected.FlagDictionary)); } diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/ModRewrite/FormatExceptionTests.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/ModRewrite/FormatExceptionTests.cs new file mode 100644 index 0000000000..73d9f3c4c6 --- /dev/null +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/ModRewrite/FormatExceptionTests.cs @@ -0,0 +1,38 @@ +// 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; +using System.IO; +using Microsoft.AspNetCore.Rewrite.Internal.ModRewrite; +using Xunit; + +namespace Microsoft.AspNetCore.Rewrite.Tests.ModRewrite +{ + public class FormatExceptionTests + { + [Theory] + [InlineData(@"RewriteCond 1 2\", @"Invalid escaper character in string RewriteCond 1 2\")] + [InlineData("BadExpression 1 2 3 4", "Could not parse the mod_rewrite file. Message: 'Too many tokens on line'. Line number '1'.")] + [InlineData("RewriteCond % 2", "Could not parse the mod_rewrite file. Line number '1'.")] + [InlineData("RewriteCond %{ 2", "Could not parse the mod_rewrite file. Line number '1'.")] + [InlineData("RewriteCond %{asdf} 2", "Could not parse the mod_rewrite file. Line number '1'.")] + [InlineData("RewriteCond %z 2", "Could not parse the mod_rewrite file. Line number '1'.")] + [InlineData("RewriteCond $ 2", "Could not parse the mod_rewrite file. Line number '1'.")] + [InlineData("RewriteCond $z 2", "Could not parse the mod_rewrite file. Line number '1'.")] + [InlineData("RewriteCond %1 !", "Could not parse the mod_rewrite file. Line number '1'.")] + [InlineData("RewriteCond %1 >", "Could not parse the mod_rewrite file. Line number '1'.")] + [InlineData("RewriteCond %1 >=", "Could not parse the mod_rewrite file. Line number '1'.")] + [InlineData("RewriteCond %1 <", "Could not parse the mod_rewrite file. Line number '1'.")] + [InlineData("RewriteCond %1 <=", "Could not parse the mod_rewrite file. Line number '1'.")] + [InlineData("RewriteCond %1 =", "Could not parse the mod_rewrite file. Line number '1'.")] + [InlineData("RewriteCond %1 -", "Could not parse the mod_rewrite file. Line number '1'.")] + [InlineData("RewriteCond %1 -a", "Could not parse the mod_rewrite file. Line number '1'.")] + [InlineData("RewriteCond %1 -getemp", "Could not parse the mod_rewrite file. Line number '1'.")] + public void ThrowFormatExceptionWithCorrectMessage(string input, string expected) + { + // Arrange, Act, Assert + var ex = Assert.Throws(() => new FileParser().Parse(new StringReader(input))); + Assert.Equal(ex.Message, expected); + } + } +} diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/ModRewrite/ModRewriteConditionBuilderTest.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/ModRewrite/ModRewriteConditionBuilderTest.cs deleted file mode 100644 index 05f610046a..0000000000 --- a/test/Microsoft.AspNetCore.Rewrite.Tests/ModRewrite/ModRewriteConditionBuilderTest.cs +++ /dev/null @@ -1,50 +0,0 @@ -// 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 Microsoft.AspNetCore.Rewrite.Internal.ModRewrite; -using Microsoft.AspNetCore.Rewrite.Internal.ModRewrite.Operands; -using Xunit; - -namespace Microsoft.AspNetCore.Rewrite.Tests.ModRewrite -{ - // This file tests an input of a list of tokens and verifies that the appropriate condition is obtained - public class ModRewriteConditionBuilderTest - { - [Fact] - public void ConditionBuilder_PassInNoFlagsFlagsEmpty() - { - var conditionString = "RewriteCond /$1 /hello"; - var builder = new ConditionBuilder(conditionString); - var results = builder.Build(); - - //var expected = new Condition( - // new Pattern( - // new List() { - // new PatternSegment("/", SegmentType.Literal), - // new PatternSegment("1", SegmentType.RuleParameter) - // }), - // new ConditionExpression { Operand = new RegexOperand {Regex = new Regex("/hello") } }, - // new ConditionFlags()); - var expected = (new ConditionBuilder("/$1", "/hello")).Build(); - - Assert.True(results.Flags.FlagDictionary.Count == 0); - Assert.True(results.Flags.FlagDictionary.Count == expected.Flags.FlagDictionary.Count); - Assert.True((results.ConditionExpression.Operand is RegexOperand) - && (expected.ConditionExpression.Operand is RegexOperand)); - } - - [Fact] - public void ConditionBuilder_PassInFlagsFlagsExist() - { - var conditionString = "RewriteCond /$1 /hello [NC]"; - var builder = new ConditionBuilder(conditionString); - var results = builder.Build(); - var expected = (new ConditionBuilder("/$1", "/hello", "[NC]")).Build(); - - Assert.True(results.Flags.FlagDictionary.Count == 1); - Assert.True(results.Flags.FlagDictionary.Count == expected.Flags.FlagDictionary.Count); - Assert.True((results.ConditionExpression.Operand is RegexOperand) - && (expected.ConditionExpression.Operand is RegexOperand)); - } - } -} diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/ModRewrite/ModRewriteFlagTest.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/ModRewrite/ModRewriteFlagTest.cs deleted file mode 100644 index ddc7329b37..0000000000 --- a/test/Microsoft.AspNetCore.Rewrite.Tests/ModRewrite/ModRewriteFlagTest.cs +++ /dev/null @@ -1,88 +0,0 @@ -// 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.Text.RegularExpressions; -using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Rewrite.Internal.ModRewrite; -using Microsoft.AspNetCore.Rewrite.Internal.ModRewrite.Operands; -using Microsoft.AspNetCore.Rewrite.Internal; -using Xunit; - -namespace Microsoft.AspNetCore.Rewrite.Tests.ModRewrite -{ - public class ModRewriteFlagTest - { - // Flag tests - [Fact] - public void ModRewriteRule_Check403OnForbiddenFlag() - { - var context = new RewriteContext { HttpContext = CreateRequest("/", "/hey/hello") }; - var rule = new ModRewriteRule - { - InitialRule = new RuleExpression { Operand = new RegexOperand(new Regex("/hey/(.*)")) , Invert = false }, - Transform = ConditionTestStringParser.ParseConditionTestString("/$1"), - Flags = FlagParser.ParseRuleFlags("[F]") - }; - var res = rule.ApplyRule(context); - Assert.True(res.Result == RuleTerminiation.ResponseComplete); - Assert.True(context.HttpContext.Response.StatusCode == 403); - } - - [Fact] - public void ModRewriteRule_Check410OnGoneFlag() - { - var context = new RewriteContext { HttpContext = CreateRequest("/", "/hey/hello") }; - var rule = new ModRewriteRule - { - InitialRule = new RuleExpression { Operand = new RegexOperand(new Regex("/hey/(.*)")), Invert = false }, - Transform = ConditionTestStringParser.ParseConditionTestString("/$1"), - Flags = FlagParser.ParseRuleFlags("[G]") - }; - var res = rule.ApplyRule(context); - Assert.True(res.Result == RuleTerminiation.ResponseComplete); - Assert.True(context.HttpContext.Response.StatusCode == 410); - } - - [Fact] - public void ModRewriteRule_CheckLastFlag() - { - var context = new RewriteContext { HttpContext = CreateRequest("/", "/hey/hello") }; - var rule = new ModRewriteRule - { - InitialRule = new RuleExpression { Operand = new RegexOperand(new Regex("/hey/(.*)")), Invert = false }, - Transform = ConditionTestStringParser.ParseConditionTestString("/$1"), - Flags = FlagParser.ParseRuleFlags("[L]") - }; - var res = rule.ApplyRule(context); - Assert.True(res.Result == RuleTerminiation.StopRules); - Assert.True(context.HttpContext.Request.Path.Equals(new PathString("/hello"))); - } - - - [Fact] - public void ModRewriteRule_CheckRedirectFlag() - { - // TODO fix this test. - var context = new RewriteContext { HttpContext = CreateRequest("/", "/hey/hello") }; - var rule = new ModRewriteRule - { - InitialRule = new RuleExpression { Operand = new RegexOperand(new Regex("/hey/(.*)")), Invert = false }, - Transform = ConditionTestStringParser.ParseConditionTestString("/$1"), - Flags = FlagParser.ParseRuleFlags("[G]") - }; - var res = rule.ApplyRule(context); - Assert.True(res.Result == RuleTerminiation.ResponseComplete); - Assert.True(context.HttpContext.Response.StatusCode == 410); - } - - private HttpContext CreateRequest(string basePath, string requestPath, string requestQuery = "", string hostName = "") - { - HttpContext context = new DefaultHttpContext(); - context.Request.PathBase = new PathString(basePath); - context.Request.Path = new PathString(requestPath); - context.Request.QueryString = new QueryString(requestQuery); - context.Request.Host = new HostString(hostName); - return context; - } - } -} diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/ModRewrite/ModRewriteMiddlewareTest.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/ModRewrite/ModRewriteMiddlewareTest.cs index 90a5d6dba1..62903412d5 100644 --- a/test/Microsoft.AspNetCore.Rewrite.Tests/ModRewrite/ModRewriteMiddlewareTest.cs +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/ModRewrite/ModRewriteMiddlewareTest.cs @@ -66,12 +66,6 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.ModRewrite Assert.Equal(response, "/what"); } - [Theory] - [InlineData("", true)] - public void Invoke_StringComparisonTests(string input, bool expected) - { - - } [Fact] public async Task Invoke_ShouldIgnoreComments() @@ -89,8 +83,6 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.ModRewrite Assert.Equal(response, "/hey/hello"); } - - // TODO Add tests to check '//' being handled appropriately. [Fact] public async Task Invoke_ShouldRewriteHomepage() @@ -184,10 +176,10 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.ModRewrite } [Fact] - public async Task Invoke_CheckFullUrlWithUFlagOnlyPath() + public async Task Invoke_CheckFullUrlWithOnlyPath() { var options = new RewriteOptions() - .ImportFromModRewrite(new StringReader(@"RewriteRule (.+) http://www.example.com$1/ [U]")); + .ImportFromModRewrite(new StringReader(@"RewriteRule (.+) http://www.example.com$1/")); var builder = new WebHostBuilder() .Configure(app => { @@ -205,7 +197,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.ModRewrite public async Task Invoke_CheckFullUrlWithUFlag() { var options = new RewriteOptions() - .ImportFromModRewrite(new StringReader(@"RewriteRule (.+) http://www.example.com$1/ [U]")); + .ImportFromModRewrite(new StringReader(@"RewriteRule (.+) http://www.example.com$1/")); var builder = new WebHostBuilder() .Configure(app => { @@ -223,7 +215,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.ModRewrite public async Task Invoke_CheckModFileConditions() { var options = new RewriteOptions() - .ImportFromModRewrite(new StringReader(@"RewriteRule (.+) http://www.example.com$1/ [U]")); + .ImportFromModRewrite(new StringReader(@"RewriteRule (.+) http://www.example.com$1/")); var builder = new WebHostBuilder() .Configure(app => { @@ -242,7 +234,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.ModRewrite public async Task Invoke_EnsureHttps(string input) { var options = new RewriteOptions() - .ImportFromModRewrite(new StringReader("RewriteCond %{REQUEST_URI} ^foo/ \nRewriteCond %{HTTPS} !on \nRewriteRule ^(.*)$ https://www.example.com$1 [R=301,L,U]")); + .ImportFromModRewrite(new StringReader("RewriteCond %{REQUEST_URI} /foo/ \nRewriteCond %{HTTPS} !on \nRewriteRule ^(.*)$ https://www.example.com$1 [R=301,L]")); var builder = new WebHostBuilder() .Configure(app => { diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/UrlRewrite/FileParserTests.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/UrlRewrite/FileParserTests.cs index 214bc87991..e9599a43d4 100644 --- a/test/Microsoft.AspNetCore.Rewrite.Tests/UrlRewrite/FileParserTests.cs +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/UrlRewrite/FileParserTests.cs @@ -5,9 +5,9 @@ using System.Collections.Generic; using System.IO; using System.Text.RegularExpressions; using Microsoft.AspNetCore.Rewrite.Internal; +using Microsoft.AspNetCore.Rewrite.Internal.UrlActions; +using Microsoft.AspNetCore.Rewrite.Internal.UrlMatches; using Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite; -using Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite.UrlActions; -using Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite.UrlMatches; using Xunit; namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite @@ -155,9 +155,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite }, Conditions = new Conditions { - ConditionList = conditions, - MatchType = condGrouping, - TrackingAllCaptures = condTracking + ConditionList = conditions } }; } @@ -184,8 +182,6 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite } else { - Assert.Equal(r1.Conditions.MatchType, r2.Conditions.MatchType); - Assert.Equal(r1.Conditions.TrackingAllCaptures, r2.Conditions.TrackingAllCaptures); Assert.Equal(r1.Conditions.ConditionList.Count, r2.Conditions.ConditionList.Count); for (var j = 0; j < r1.Conditions.ConditionList.Count; j++) { diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/UrlRewrite/InputParserTests.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/UrlRewrite/InputParserTests.cs index 31f6a2e984..0fa95393c0 100644 --- a/test/Microsoft.AspNetCore.Rewrite.Tests/UrlRewrite/InputParserTests.cs +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/UrlRewrite/InputParserTests.cs @@ -4,6 +4,7 @@ using System; using System.Text.RegularExpressions; using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Rewrite.Internal; using Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite; using Xunit; @@ -45,7 +46,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite public void EvaluateBackReferenceRule(string testString, string expected) { var middle = InputParser.ParseInputString(testString); - var result = middle.Evaluate(CreateTestHttpContext(), CreateTestRuleMatch(), CreateTestCondMatch()); + var result = middle.Evaluate(CreateTestRewriteContext(), CreateTestRuleMatch(), CreateTestCondMatch()); Assert.Equal(result, expected); } @@ -58,7 +59,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite public void EvaluatToLowerRule(string testString, string expected) { var middle = InputParser.ParseInputString(testString); - var result = middle.Evaluate(CreateTestHttpContext(), CreateTestRuleMatch(), CreateTestCondMatch()); + var result = middle.Evaluate(CreateTestRewriteContext(), CreateTestRuleMatch(), CreateTestCondMatch()); Assert.Equal(result, expected); } @@ -67,7 +68,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite public void EvaluatUriEncodeRule(string testString, string expected) { var middle = InputParser.ParseInputString(testString); - var result = middle.Evaluate(CreateTestHttpContext(), CreateTestRuleMatch(), CreateTestCondMatch()); + var result = middle.Evaluate(CreateTestRewriteContext(), CreateTestRuleMatch(), CreateTestCondMatch()); Assert.Equal(result, expected); } @@ -88,12 +89,12 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite Assert.Throws(() => InputParser.ParseInputString(testString)); } - private HttpContext CreateTestHttpContext() + private RewriteContext CreateTestRewriteContext() { - HttpContext context = new DefaultHttpContext(); + var context = new DefaultHttpContext(); // TODO add fields if necessary - return context; + return new RewriteContext { HttpContext = context, FileProvider = null }; } private MatchResults CreateTestRuleMatch() diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/UrlRewrite/ServerVariableTests.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/UrlRewrite/ServerVariableTests.cs index 6f11a3c21f..e0847cda75 100644 --- a/test/Microsoft.AspNetCore.Rewrite.Tests/UrlRewrite/ServerVariableTests.cs +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/UrlRewrite/ServerVariableTests.cs @@ -3,6 +3,7 @@ using System.Text.RegularExpressions; using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Rewrite.Internal; using Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite; using Microsoft.Net.Http.Headers; using Xunit; @@ -32,7 +33,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite Assert.Equal(expected, lookup); } - private HttpContext CreateTestHttpContext() + private RewriteContext CreateTestHttpContext() { var context = new DefaultHttpContext(); context.Request.Host = new HostString("example.com"); @@ -45,7 +46,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite context.Request.Headers[HeaderNames.Referer] = "referer"; context.Request.Headers[HeaderNames.UserAgent] = "useragent"; context.Request.Headers[HeaderNames.Connection] = "connection"; - return context; + return new RewriteContext { HttpContext = context }; } private MatchResults CreateTestRuleMatch() From d1ab35db87b729b7f135259dd184f0787f4fbece Mon Sep 17 00:00:00 2001 From: Justin Kotalik Date: Thu, 18 Aug 2016 10:18:15 -0700 Subject: [PATCH 093/307] Parsers are now non-static (when appropriate) --- .../CodeRewriteExtensions.cs | 4 +- .../Internal/CodeRules/RedirectToHttpsRule.cs | 1 + .../Internal/CodeRules/RewriteToHttpsRule.cs | 1 + .../ModRewrite/ConditionPatternParser.cs | 9 ++- .../Internal/ModRewrite/FileParser.cs | 29 +++++--- .../Internal/ModRewrite/FlagParser.cs | 67 +++++++++++++++++-- .../Internal/ModRewrite/Flags.cs | 56 ---------------- .../ModRewrite/ModRewriteRedirectAction.cs | 1 - .../ModRewrite/ModRewriteRewriteAction.cs | 1 - .../Internal/ModRewrite/RuleBuilder.cs | 16 +++-- .../Internal/ModRewrite/RuleRegexParser.cs | 4 +- .../Internal/ModRewrite/ServerVariables.cs | 1 - .../Internal/ModRewrite/TestStringParser.cs | 3 +- .../Internal/ModRewrite/Tokenizer.cs | 4 +- .../Internal/Pattern.cs | 1 - ...{UrlRewriteFileParser.cs => FileParser.cs} | 27 ++++---- .../Internal/UrlRewrite/InputParser.cs | 2 +- .../UrlRewrite/UrlRewriteRuleBuilder.cs | 1 - .../UrlRewriteExtensions.cs | 4 +- .../ModRewrite/ConditionActionTest.cs | 10 +-- .../ModRewrite/FlagParserTest.cs | 6 +- .../ModRewrite/RewriteTokenizerTest.cs | 4 +- .../ModRewrite/RuleRegexParserTest.cs | 6 +- .../UrlRewrite/FileParserTests.cs | 15 +++-- .../FormatExceptionHandlingTests.cs | 2 +- .../UrlRewrite/InputParserTests.cs | 12 ++-- 26 files changed, 149 insertions(+), 138 deletions(-) rename src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/{UrlRewriteFileParser.cs => FileParser.cs} (86%) diff --git a/src/Microsoft.AspNetCore.Rewrite/CodeRewriteExtensions.cs b/src/Microsoft.AspNetCore.Rewrite/CodeRewriteExtensions.cs index 9da5101c96..b31cf14cad 100644 --- a/src/Microsoft.AspNetCore.Rewrite/CodeRewriteExtensions.cs +++ b/src/Microsoft.AspNetCore.Rewrite/CodeRewriteExtensions.cs @@ -44,7 +44,7 @@ namespace Microsoft.AspNetCore.Rewrite public static RewriteOptions RewriteRule(this RewriteOptions options, string regex, string onMatch, bool stopProcessing) { var builder = new UrlRewriteRuleBuilder(); - var pattern = InputParser.ParseInputString(onMatch); + var pattern = new InputParser().ParseInputString(onMatch); builder.AddUrlMatch(regex); builder.AddUrlAction(pattern, actionType: ActionType.Rewrite, stopProcessing: stopProcessing); @@ -60,7 +60,7 @@ namespace Microsoft.AspNetCore.Rewrite public static RewriteOptions RedirectRule(this RewriteOptions options, string regex, string onMatch, int statusCode, bool stopProcessing) { var builder = new UrlRewriteRuleBuilder(); - var pattern = InputParser.ParseInputString(onMatch); + var pattern = new InputParser().ParseInputString(onMatch); builder.AddUrlMatch(regex); builder.AddUrlAction(pattern, actionType: ActionType.Redirect, stopProcessing: stopProcessing); diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/CodeRules/RedirectToHttpsRule.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/CodeRules/RedirectToHttpsRule.cs index 04b1c8dd97..558810b50a 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/CodeRules/RedirectToHttpsRule.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/CodeRules/RedirectToHttpsRule.cs @@ -10,6 +10,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.CodeRules { public int? SSLPort { get; set; } public int StatusCode { get; set; } + public override RuleResult ApplyRule(RewriteContext context) { if (!context.HttpContext.Request.IsHttps) diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/CodeRules/RewriteToHttpsRule.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/CodeRules/RewriteToHttpsRule.cs index e276baa85b..c4fa07f54d 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/CodeRules/RewriteToHttpsRule.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/CodeRules/RewriteToHttpsRule.cs @@ -10,6 +10,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.CodeRules public bool stopProcessing { get; set; } public int? SSLPort { get; set; } + public override RuleResult ApplyRule(RewriteContext context) { if (!context.HttpContext.Request.IsHttps) diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/ConditionPatternParser.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/ConditionPatternParser.cs index 8279da7831..ea678502de 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/ConditionPatternParser.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/ConditionPatternParser.cs @@ -2,7 +2,6 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; -using Microsoft.AspNetCore.Rewrite.Internal; namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite { @@ -10,7 +9,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite /// Parses the "CondPattern" portion of the RewriteCond. /// RewriteCond TestString CondPattern /// - public static class ConditionPatternParser + public class ConditionPatternParser { private const char Not = '!'; private const char Dash = '-'; @@ -26,7 +25,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite /// /// The CondPattern portion of a mod_rewrite RewriteCond. /// A new parsed condition. - public static ParsedModRewriteInput ParseActionCondition(string condition) + public ParsedModRewriteInput ParseActionCondition(string condition) { if (condition == null) { @@ -39,7 +38,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite throw new FormatException(Resources.FormatError_InputParserUnrecognizedParameter(condition, context.Index)); } - // If we hit a !, make sure the condition is inverted when resolving the string + // If we hit a !, invert the condition if (context.Current == Not) { results.Invert = true; @@ -139,7 +138,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite /// /// /// - public static ParsedModRewriteInput ParseProperty(ParserContext context, bool invert) + private static ParsedModRewriteInput ParseProperty(ParserContext context, bool invert) { if (!context.Next()) { diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/FileParser.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/FileParser.cs index de38c0ce3b..4610619ebf 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/FileParser.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/FileParser.cs @@ -15,6 +15,14 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite var rules = new List(); var builder = new RuleBuilder(); var lineNum = 0; + + // parsers + var testStringParser = new TestStringParser(); + var conditionParser = new ConditionPatternParser(); + var regexParser = new RuleRegexParser(); + var flagsParser = new FlagParser(); + var tokenizer = new Tokenizer(); + while ((line = input.ReadLine()) != null) { lineNum++; @@ -26,7 +34,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite { continue; } - var tokens = Tokenizer.Tokenize(line); + var tokens = tokenizer.Tokenize(line); if (tokens.Count > 4) { // This means the line didn't have an appropriate format, throw format exception @@ -40,13 +48,13 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite case "RewriteCond": try { - var pattern = TestStringParser.Parse(tokens[1]); - var condActionParsed = ConditionPatternParser.ParseActionCondition(tokens[2]); + var pattern = testStringParser.Parse(tokens[1]); + var condActionParsed = conditionParser.ParseActionCondition(tokens[2]); var flags = new Flags(); if (tokens.Count == 4) { - flags = FlagParser.Parse(tokens[3]); + flags = flagsParser.Parse(tokens[3]); } builder.AddConditionFromParts(pattern, condActionParsed, flags); @@ -59,14 +67,17 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite case "RewriteRule": try { - var regex = RuleRegexParser.ParseRuleRegex(tokens[1]); - var pattern = TestStringParser.Parse(tokens[2]); + var regex = regexParser.ParseRuleRegex(tokens[1]); + var pattern = testStringParser.Parse(tokens[2]); - // TODO see if we can have flags be null. - var flags = new Flags(); + Flags flags; if (tokens.Count == 4) { - flags = FlagParser.Parse(tokens[3]); + flags = flagsParser.Parse(tokens[3]); + } + else + { + flags = new Flags(); } builder.AddMatch(regex, flags); diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/FlagParser.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/FlagParser.cs index 8252c89637..16a0900815 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/FlagParser.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/FlagParser.cs @@ -2,22 +2,68 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; +using System.Collections.Generic; namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite { public class FlagParser - { - public static Flags Parse(string flagString) + { + private readonly IDictionary _ruleFlagLookup = new Dictionary(StringComparer.OrdinalIgnoreCase) { + { "b", FlagType.EscapeBackreference}, + { "c", FlagType.Chain }, + { "chain", FlagType.Chain}, + { "co", FlagType.Cookie }, + { "cookie", FlagType.Cookie }, + { "dpi", FlagType.DiscardPath }, + { "discardpath", FlagType.DiscardPath }, + { "e", FlagType.Env}, + { "env", FlagType.Env}, + { "end", FlagType.End }, + { "f", FlagType.Forbidden }, + { "forbidden", FlagType.Forbidden }, + { "g", FlagType.Gone }, + { "gone", FlagType.Gone }, + { "h", FlagType.Handler }, + { "handler", FlagType.Handler }, + { "l", FlagType.Last }, + { "last", FlagType.Last }, + { "n", FlagType.Next }, + { "next", FlagType.Next }, + { "nc", FlagType.NoCase }, + { "nocase", FlagType.NoCase }, + { "ne", FlagType.NoEscape }, + { "noescape", FlagType.NoEscape }, + { "ns", FlagType.NoSubReq }, + { "nosubreq", FlagType.NoSubReq }, + { "p", FlagType.Proxy }, + { "proxy", FlagType.Proxy }, + { "pt", FlagType.PassThrough }, + { "passthrough", FlagType.PassThrough }, + { "qsa", FlagType.QSAppend }, + { "qsappend", FlagType.QSAppend }, + { "qsd", FlagType.QSDiscard }, + { "qsdiscard", FlagType.QSDiscard }, + { "qsl", FlagType.QSLast }, + { "qslast", FlagType.QSLast }, + { "r", FlagType.Redirect }, + { "redirect", FlagType.Redirect }, + { "s", FlagType.Skip }, + { "skip", FlagType.Skip }, + { "t", FlagType.Type }, + { "type", FlagType.Type }, + }; + + public Flags Parse(string flagString) { if (string.IsNullOrEmpty(flagString)) { - return null; + throw new ArgumentNullException(nameof(flagString)); } // Check that flags are contained within [] - if (!flagString.StartsWith("[") || !flagString.EndsWith("]")) + if (!(flagString.StartsWith("[") && flagString.EndsWith("]"))) { - throw new FormatException(); + throw new FormatException("Flags should start and end with square brackets: [flags]"); } // Lexing esque step to split all flags. @@ -27,13 +73,20 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite foreach (string token in tokens) { var hasPayload = token.Split('='); + + FlagType flag; + if (!_ruleFlagLookup.TryGetValue(hasPayload[0], out flag)) + { + throw new FormatException($"Unrecognized flag: {hasPayload[0]}"); + } + if (hasPayload.Length == 2) { - flags.SetFlag(hasPayload[0], hasPayload[1]); + flags.SetFlag(flag, hasPayload[1]); } else { - flags.SetFlag(hasPayload[0], string.Empty); + flags.SetFlag(flag, string.Empty); } } return flags; diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/Flags.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/Flags.cs index 29d3ea5fc5..5df8cc09be 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/Flags.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/Flags.cs @@ -1,7 +1,6 @@ // 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; using System.Collections.Generic; namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite @@ -11,51 +10,6 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite // http://httpd.apache.org/docs/current/expr.html#vars public class Flags { - private static IDictionary _ruleFlagLookup = new Dictionary(StringComparer.OrdinalIgnoreCase) { - { "b", FlagType.EscapeBackreference}, - { "c", FlagType.Chain }, - { "chain", FlagType.Chain}, - { "co", FlagType.Cookie }, - { "cookie", FlagType.Cookie }, - { "dpi", FlagType.DiscardPath }, - { "discardpath", FlagType.DiscardPath }, - { "e", FlagType.Env}, - { "env", FlagType.Env}, - { "end", FlagType.End }, - { "f", FlagType.Forbidden }, - { "forbidden", FlagType.Forbidden }, - { "g", FlagType.Gone }, - { "gone", FlagType.Gone }, - { "h", FlagType.Handler }, - { "handler", FlagType.Handler }, - { "l", FlagType.Last }, - { "last", FlagType.Last }, - { "n", FlagType.Next }, - { "next", FlagType.Next }, - { "nc", FlagType.NoCase }, - { "nocase", FlagType.NoCase }, - { "ne", FlagType.NoEscape }, - { "noescape", FlagType.NoEscape }, - { "ns", FlagType.NoSubReq }, - { "nosubreq", FlagType.NoSubReq }, - { "p", FlagType.Proxy }, - { "proxy", FlagType.Proxy }, - { "pt", FlagType.PassThrough }, - { "passthrough", FlagType.PassThrough }, - { "qsa", FlagType.QSAppend }, - { "qsappend", FlagType.QSAppend }, - { "qsd", FlagType.QSDiscard }, - { "qsdiscard", FlagType.QSDiscard }, - { "qsl", FlagType.QSLast }, - { "qslast", FlagType.QSLast }, - { "r", FlagType.Redirect }, - { "redirect", FlagType.Redirect }, - { "s", FlagType.Skip }, - { "skip", FlagType.Skip }, - { "t", FlagType.Type }, - { "type", FlagType.Type }, - }; - public IDictionary FlagDictionary { get; } public Flags(IDictionary flags) @@ -68,16 +22,6 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite FlagDictionary = new Dictionary(); } - public void SetFlag(string flag, string value) - { - FlagType res; - if (!_ruleFlagLookup.TryGetValue(flag, out res)) - { - throw new FormatException("Unrecognized flag"); - } - SetFlag(res, value); - } - public void SetFlag(FlagType flag, string value) { if (value == null) diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/ModRewriteRedirectAction.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/ModRewriteRedirectAction.cs index 35c2ecd0df..a935946829 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/ModRewriteRedirectAction.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/ModRewriteRedirectAction.cs @@ -3,7 +3,6 @@ using System; using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Rewrite.Internal; using Microsoft.Net.Http.Headers; namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/ModRewriteRewriteAction.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/ModRewriteRewriteAction.cs index 2fd6a0940c..23b4be1eed 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/ModRewriteRewriteAction.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/ModRewriteRewriteAction.cs @@ -3,7 +3,6 @@ using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http.Extensions; -using Microsoft.AspNetCore.Rewrite.Internal; namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite { diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/RuleBuilder.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/RuleBuilder.cs index 0510803c4f..4095fb3da4 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/RuleBuilder.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/RuleBuilder.cs @@ -4,7 +4,6 @@ using System; using System.Collections.Generic; using System.Text.RegularExpressions; -using Microsoft.AspNetCore.Rewrite.Internal; using Microsoft.AspNetCore.Rewrite.Internal.PreActions; using Microsoft.AspNetCore.Rewrite.Internal.UrlActions; using Microsoft.AspNetCore.Rewrite.Internal.UrlMatches; @@ -32,13 +31,18 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite public void AddRule(string rule) { // TODO - var tokens = Tokenizer.Tokenize(rule); - var regex = RuleRegexParser.ParseRuleRegex(tokens[1]); - var pattern = TestStringParser.Parse(tokens[2]); - var flags = new Flags(); + var tokens = new Tokenizer().Tokenize(rule); + var regex = new RuleRegexParser().ParseRuleRegex(tokens[1]); + var pattern = new TestStringParser().Parse(tokens[2]); + + Flags flags; if (tokens.Count == 4) { - flags = FlagParser.Parse(tokens[3]); + flags = new FlagParser().Parse(tokens[3]); + } + else + { + flags = new Flags(); } AddMatch(regex, flags); AddAction(pattern, flags); diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/RuleRegexParser.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/RuleRegexParser.cs index e063b36bc4..272faf96e0 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/RuleRegexParser.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/RuleRegexParser.cs @@ -5,9 +5,9 @@ using System; namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite { - public static class RuleRegexParser + public class RuleRegexParser { - public static ParsedModRewriteInput ParseRuleRegex(string regex) + public ParsedModRewriteInput ParseRuleRegex(string regex) { if (regex == null || regex == string.Empty) { diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/ServerVariables.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/ServerVariables.cs index 5b664f4172..863fd44bba 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/ServerVariables.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/ServerVariables.cs @@ -2,7 +2,6 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; -using Microsoft.AspNetCore.Rewrite.Internal; using Microsoft.AspNetCore.Rewrite.Internal.PatternSegments; using Microsoft.Net.Http.Headers; diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/TestStringParser.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/TestStringParser.cs index 4564c3cba1..bcedbb214f 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/TestStringParser.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/TestStringParser.cs @@ -3,7 +3,6 @@ using System; using System.Collections.Generic; -using Microsoft.AspNetCore.Rewrite.Internal; using Microsoft.AspNetCore.Rewrite.Internal.PatternSegments; namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite @@ -32,7 +31,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite /// $1 /// A new , containing a list of /// http://httpd.apache.org/docs/current/mod/mod_rewrite.html - public static Pattern Parse(string testString) + public Pattern Parse(string testString) { if (testString == null) { diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/Tokenizer.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/Tokenizer.cs index a13bdeb9ef..69c7880f50 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/Tokenizer.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/Tokenizer.cs @@ -9,7 +9,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite /// /// Tokenizes a mod_rewrite rule, delimited by spaces. /// - public static class Tokenizer + public class Tokenizer { private const char Space = ' '; private const char Escape = '\\'; @@ -20,7 +20,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite /// /// The rule to tokenize. /// A list of tokens. - public static List Tokenize(string rule) + public List Tokenize(string rule) { // TODO make list of strings a reference to the original rule? (run into problems with escaped spaces). // TODO handle "s and probably replace \ character with no slash. diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/Pattern.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/Pattern.cs index 2c6367ea67..99f8f014f4 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/Pattern.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/Pattern.cs @@ -15,7 +15,6 @@ namespace Microsoft.AspNetCore.Rewrite.Internal public string Evaluate(RewriteContext context, MatchResults ruleMatch, MatchResults condMatch) { - // TODO consider thread static for string builder - DAVID PERF foreach (var pattern in PatternSegments) { context.Builder.Append(pattern.Evaluate(context, ruleMatch, condMatch)); diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/UrlRewriteFileParser.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/FileParser.cs similarity index 86% rename from src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/UrlRewriteFileParser.cs rename to src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/FileParser.cs index 39703c5e2e..b6b9d5ae16 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/UrlRewriteFileParser.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/FileParser.cs @@ -7,15 +7,16 @@ using System.IO; using System.Linq; using System.Xml; using System.Xml.Linq; -using Microsoft.AspNetCore.Rewrite.Internal; namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite { - public static class UrlRewriteFileParser + public class FileParser { private static readonly TimeSpan RegexTimeout = TimeSpan.FromMilliseconds(1); - public static List Parse(TextReader reader) + private InputParser _inputParser = new InputParser(); + + public List Parse(TextReader reader) { var xmlDoc = XDocument.Load(reader, LoadOptions.SetLineInfo); var xmlRoot = xmlDoc.Descendants(RewriteTags.Rewrite).FirstOrDefault(); @@ -32,7 +33,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite return null; } - private static void ParseRules(XElement rules, List result) + private void ParseRules(XElement rules, List result) { if (rules == null) { @@ -51,7 +52,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite } } - private static void ParseRuleAttributes(XElement rule, UrlRewriteRuleBuilder builder) + private void ParseRuleAttributes(XElement rule, UrlRewriteRuleBuilder builder) { builder.Name = rule.Attribute(RewriteTags.Name)?.Value; @@ -90,7 +91,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite ParseUrlAction(action, builder, stopProcessing); } - private static void ParseMatch(XElement match, UrlRewriteRuleBuilder builder, PatternSyntax patternSyntax) + private void ParseMatch(XElement match, UrlRewriteRuleBuilder builder, PatternSyntax patternSyntax) { var parsedInputString = match.Attribute(RewriteTags.Url)?.Value; if (parsedInputString == null) @@ -112,7 +113,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite builder.AddUrlMatch(parsedInputString, ignoreCase, negate, patternSyntax); } - private static void ParseConditions(XElement conditions, UrlRewriteRuleBuilder builder, PatternSyntax patternSyntax) + private void ParseConditions(XElement conditions, UrlRewriteRuleBuilder builder, PatternSyntax patternSyntax) { if (conditions == null) { @@ -139,7 +140,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite } } - private static void ParseCondition(XElement condition, UrlRewriteRuleBuilder builder, PatternSyntax patternSyntax) + private void ParseCondition(XElement condition, UrlRewriteRuleBuilder builder, PatternSyntax patternSyntax) { bool ignoreCase; if (!bool.TryParse(condition.Attribute(RewriteTags.IgnoreCase)?.Value, out ignoreCase)) @@ -170,7 +171,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite Pattern input = null; try { - input = InputParser.ParseInputString(parsedInputString); + input = _inputParser.ParseInputString(parsedInputString); builder.AddUrlCondition(input, parsedPatternString, patternSyntax, matchType, ignoreCase, negate); } @@ -180,7 +181,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite } } - private static void ParseUrlAction(XElement urlAction, UrlRewriteRuleBuilder builder, bool stopProcessing) + private void ParseUrlAction(XElement urlAction, UrlRewriteRuleBuilder builder, bool stopProcessing) { ActionType actionType; if (!Enum.TryParse(urlAction.Attribute(RewriteTags.Type)?.Value, out actionType)) @@ -202,7 +203,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite try { - var input = InputParser.ParseInputString(urlAction.Attribute(RewriteTags.Url)?.Value); + var input = _inputParser.ParseInputString(urlAction.Attribute(RewriteTags.Url)?.Value); builder.AddUrlAction(input, actionType, appendQuery, stopProcessing, (int)redirectType); } catch (FormatException formatException) @@ -211,14 +212,14 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite } } - private static void ThrowUrlFormatException(XElement element, string message) + private void ThrowUrlFormatException(XElement element, string message) { var line = ((IXmlLineInfo)element).LineNumber; var col = ((IXmlLineInfo)element).LinePosition; throw new FormatException(Resources.FormatError_UrlRewriteParseError(message, line, col)); } - private static void ThrowUrlFormatException(XElement element, string message, Exception ex) + private void ThrowUrlFormatException(XElement element, string message, Exception ex) { var line = ((IXmlLineInfo)element).LineNumber; var col = ((IXmlLineInfo)element).LinePosition; diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/InputParser.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/InputParser.cs index a4e33665a3..2e03d415f2 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/InputParser.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/InputParser.cs @@ -20,7 +20,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite /// /// /// A new , containing a list of - public static Pattern ParseInputString(string testString) + public Pattern ParseInputString(string testString) { if (testString == null) { diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/UrlRewriteRuleBuilder.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/UrlRewriteRuleBuilder.cs index 2c4b9814ab..b8803c116b 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/UrlRewriteRuleBuilder.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/UrlRewriteRuleBuilder.cs @@ -5,7 +5,6 @@ using System; using System.Collections.Generic; using System.Text.RegularExpressions; using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Rewrite.Internal; using Microsoft.AspNetCore.Rewrite.Internal.UrlActions; using Microsoft.AspNetCore.Rewrite.Internal.UrlMatches; diff --git a/src/Microsoft.AspNetCore.Rewrite/UrlRewriteExtensions.cs b/src/Microsoft.AspNetCore.Rewrite/UrlRewriteExtensions.cs index 944426b055..fb362718a5 100644 --- a/src/Microsoft.AspNetCore.Rewrite/UrlRewriteExtensions.cs +++ b/src/Microsoft.AspNetCore.Rewrite/UrlRewriteExtensions.cs @@ -36,7 +36,7 @@ namespace Microsoft.AspNetCore.Rewrite var path = Path.Combine(hostingEnv.ContentRootPath, filePath); using (var stream = File.OpenRead(path)) { - options.Rules.AddRange(UrlRewriteFileParser.Parse(new StreamReader(stream))); + options.Rules.AddRange(new FileParser().Parse(new StreamReader(stream))); }; return options; } @@ -60,7 +60,7 @@ namespace Microsoft.AspNetCore.Rewrite using (stream) { - options.Rules.AddRange(UrlRewriteFileParser.Parse(stream)); + options.Rules.AddRange(new FileParser().Parse(stream)); }; return options; } diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/ModRewrite/ConditionActionTest.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/ModRewrite/ConditionActionTest.cs index d0d7ac7f57..c1a47b26da 100644 --- a/test/Microsoft.AspNetCore.Rewrite.Tests/ModRewrite/ConditionActionTest.cs +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/ModRewrite/ConditionActionTest.cs @@ -16,7 +16,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.ModRewrite [InlineData("=hey", OperationType.Equal, "hey", ConditionType.StringComp)] public void ConditionParser_CheckStringComp(string condition, OperationType operation, string variable, ConditionType conditionType) { - var results = ConditionPatternParser.ParseActionCondition(condition); + var results = new ConditionPatternParser().ParseActionCondition(condition); var expected = new ParsedModRewriteInput { OperationType = operation, ConditionType = conditionType, Operand = variable, Invert = false }; Assert.True(CompareConditions(results, expected)); @@ -26,7 +26,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.ModRewrite public void ConditionParser_CheckRegexEqual() { var condition = @"(.*)"; - var results = ConditionPatternParser.ParseActionCondition(condition); + var results = new ConditionPatternParser().ParseActionCondition(condition); var expected = new ParsedModRewriteInput { ConditionType = ConditionType.Regex, Operand = "(.*)", Invert = false }; Assert.True(CompareConditions(results, expected)); @@ -44,7 +44,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.ModRewrite [InlineData("-x", OperationType.Executable, ConditionType.PropertyTest)] public void ConditionParser_CheckFileOperations(string condition, OperationType operation, ConditionType cond) { - var results = ConditionPatternParser.ParseActionCondition(condition); + var results = new ConditionPatternParser().ParseActionCondition(condition); var expected = new ParsedModRewriteInput { ConditionType = cond, OperationType = operation , Invert = false }; Assert.True(CompareConditions(results, expected)); @@ -62,7 +62,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.ModRewrite [InlineData("!-x", OperationType.Executable, ConditionType.PropertyTest)] public void ConditionParser_CheckFileOperationsInverted(string condition, OperationType operation, ConditionType cond) { - var results = ConditionPatternParser.ParseActionCondition(condition); + var results = new ConditionPatternParser().ParseActionCondition(condition); var expected = new ParsedModRewriteInput { ConditionType = cond, OperationType = operation, Invert = true }; Assert.True(CompareConditions(results, expected)); @@ -77,7 +77,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.ModRewrite [InlineData("-ne1", OperationType.NotEqual, "1", ConditionType.IntComp)] public void ConditionParser_CheckIntComp(string condition, OperationType operation, string variable, ConditionType cond) { - var results = ConditionPatternParser.ParseActionCondition(condition); + var results = new ConditionPatternParser().ParseActionCondition(condition); var expected = new ParsedModRewriteInput { ConditionType = cond, OperationType = operation, Invert = false, Operand = variable }; Assert.True(CompareConditions(results, expected)); diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/ModRewrite/FlagParserTest.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/ModRewrite/FlagParserTest.cs index 39c6cedb24..1cc8aa9a6f 100644 --- a/test/Microsoft.AspNetCore.Rewrite.Tests/ModRewrite/FlagParserTest.cs +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/ModRewrite/FlagParserTest.cs @@ -13,7 +13,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.ModRewrite [Fact] public void FlagParser_CheckSingleTerm() { - var results = FlagParser.Parse("[NC]"); + var results = new FlagParser().Parse("[NC]"); var dict = new Dictionary(); dict.Add(FlagType.NoCase, string.Empty); var expected = new Flags(dict); @@ -24,7 +24,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.ModRewrite [Fact] public void FlagParser_CheckManyTerms() { - var results = FlagParser.Parse("[NC,F,L]"); + var results = new FlagParser().Parse("[NC,F,L]"); var dict = new Dictionary(); dict.Add(FlagType.NoCase, string.Empty); dict.Add(FlagType.Forbidden, string.Empty); @@ -37,7 +37,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.ModRewrite [Fact] public void FlagParser_CheckManyTermsWithEquals() { - var results = FlagParser.Parse("[NC,F,R=301]"); + var results = new FlagParser().Parse("[NC,F,R=301]"); var dict = new Dictionary(); dict.Add(FlagType.NoCase, string.Empty); dict.Add(FlagType.Forbidden, string.Empty); diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/ModRewrite/RewriteTokenizerTest.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/ModRewrite/RewriteTokenizerTest.cs index fdcaf6b35d..7b8b5a74f5 100644 --- a/test/Microsoft.AspNetCore.Rewrite.Tests/ModRewrite/RewriteTokenizerTest.cs +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/ModRewrite/RewriteTokenizerTest.cs @@ -13,7 +13,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.ModRewrite public void Tokenize_RewriteCondtion() { var testString = "RewriteCond %{HTTPS} !-f"; - var tokens = Tokenizer.Tokenize(testString); + var tokens = new Tokenizer().Tokenize(testString); var expected = new List(); expected.Add("RewriteCond"); @@ -27,7 +27,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.ModRewrite { // TODO need consultation on escape characters. var testString = @"RewriteCond %{HTTPS}\ what !-f"; - var tokens = Tokenizer.Tokenize(testString); + var tokens = new Tokenizer().Tokenize(testString); var expected = new List(); expected.Add("RewriteCond"); diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/ModRewrite/RuleRegexParserTest.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/ModRewrite/RuleRegexParserTest.cs index 5b3081a220..16a7954700 100644 --- a/test/Microsoft.AspNetCore.Rewrite.Tests/ModRewrite/RuleRegexParserTest.cs +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/ModRewrite/RuleRegexParserTest.cs @@ -12,19 +12,19 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.ModRewrite [Fact] public void RuleRegexParser_ShouldThrowOnNull() { - Assert.Throws(() => RuleRegexParser.ParseRuleRegex(null)); + Assert.Throws(() => new RuleRegexParser().ParseRuleRegex(null)); } [Fact] public void RuleRegexParser_ShouldThrowOnEmpty() { - Assert.Throws(() => RuleRegexParser.ParseRuleRegex(string.Empty)); + Assert.Throws(() => new RuleRegexParser().ParseRuleRegex(string.Empty)); } [Fact] public void RuleRegexParser_RegularRegexExpression() { - var results = RuleRegexParser.ParseRuleRegex("(.*)"); + var results = new RuleRegexParser().ParseRuleRegex("(.*)"); Assert.False(results.Invert); Assert.Equal(results.Operand, "(.*)"); } diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/UrlRewrite/FileParserTests.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/UrlRewrite/FileParserTests.cs index e9599a43d4..450c840f5d 100644 --- a/test/Microsoft.AspNetCore.Rewrite.Tests/UrlRewrite/FileParserTests.cs +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/UrlRewrite/FileParserTests.cs @@ -35,7 +35,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite pattern: "article.aspx?id={R:1}&title={R:2}")); // act - var res = UrlRewriteFileParser.Parse(new StringReader(xml)); + var res = new FileParser().Parse(new StringReader(xml)); // assert AssertUrlRewriteRuleEquality(res, expected); @@ -60,7 +60,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite var condList = new List(); condList.Add(new Condition { - Input = InputParser.ParseInputString("{HTTPS}"), + Input = new InputParser().ParseInputString("{HTTPS}"), Match = new RegexMatch(new Regex("^OFF$"), false) }); @@ -72,7 +72,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite pattern: "article.aspx?id={R:1}&title={R:2}")); // act - var res = UrlRewriteFileParser.Parse(new StringReader(xml)); + var res = new FileParser().Parse(new StringReader(xml)); // assert AssertUrlRewriteRuleEquality(res, expected); @@ -104,7 +104,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite var condList = new List(); condList.Add(new Condition { - Input = InputParser.ParseInputString("{HTTPS}"), + Input = new InputParser().ParseInputString("{HTTPS}"), Match = new RegexMatch(new Regex("^OFF$"), false) }); @@ -121,7 +121,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite pattern: "article.aspx?id={R:1}&title={R:2}")); // act - var res = UrlRewriteFileParser.Parse(new StringReader(xml)); + var res = new FileParser().Parse(new StringReader(xml)); // assert AssertUrlRewriteRuleEquality(res, expected); @@ -147,7 +147,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite { return new UrlRewriteRule { - Action = new RewriteAction(RuleTerminiation.Continue, InputParser.ParseInputString(Url), clearQuery: false), + Action = new RewriteAction(RuleTerminiation.Continue, new InputParser().ParseInputString(Url), clearQuery: false), Name = name, Enabled = enabled, InitialMatch = new RegexMatch(new Regex("^OFF$"), false) @@ -190,6 +190,9 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite Assert.Equal(c1.Input.PatternSegments.Count, c2.Input.PatternSegments.Count); } } + + Assert.Equal(r1.Action.GetType(), r2.Action.GetType()); + Assert.Equal(r1.InitialMatch.GetType(), r2.InitialMatch.GetType()); } } } diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/UrlRewrite/FormatExceptionHandlingTests.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/UrlRewrite/FormatExceptionHandlingTests.cs index 7ba0bc07a0..18011f4d40 100644 --- a/test/Microsoft.AspNetCore.Rewrite.Tests/UrlRewrite/FormatExceptionHandlingTests.cs +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/UrlRewrite/FormatExceptionHandlingTests.cs @@ -114,7 +114,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite public void ThrowFormatExceptionWithCorrectMessage(string input, string expected) { // Arrange, Act, Assert - var ex = Assert.Throws(() => UrlRewriteFileParser.Parse(new StringReader(input))); + var ex = Assert.Throws(() => new FileParser().Parse(new StringReader(input))); Assert.Equal(ex.Message, expected); } } diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/UrlRewrite/InputParserTests.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/UrlRewrite/InputParserTests.cs index 0fa95393c0..4ed8edf88a 100644 --- a/test/Microsoft.AspNetCore.Rewrite.Tests/UrlRewrite/InputParserTests.cs +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/UrlRewrite/InputParserTests.cs @@ -16,7 +16,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite public void InputParser_ParseLiteralString() { var testString = "hello/hey/what"; - var result = InputParser.ParseInputString(testString); + var result = new InputParser().ParseInputString(testString); Assert.Equal(result.PatternSegments.Count, 1); } @@ -29,7 +29,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite [InlineData("foo/", 1)] public void InputParser_ParseStringWithBackReference(string testString, int expected) { - var result = InputParser.ParseInputString(testString); + var result = new InputParser().ParseInputString(testString); Assert.Equal(result.PatternSegments.Count, expected); } @@ -45,7 +45,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite [InlineData("hey/{R:1}/{C:1}", "hey/foo/foo")] public void EvaluateBackReferenceRule(string testString, string expected) { - var middle = InputParser.ParseInputString(testString); + var middle = new InputParser().ParseInputString(testString); var result = middle.Evaluate(CreateTestRewriteContext(), CreateTestRuleMatch(), CreateTestCondMatch()); Assert.Equal(result, expected); } @@ -58,7 +58,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite [InlineData("hey/ToLower:/what", "hey/ToLower:/what")] public void EvaluatToLowerRule(string testString, string expected) { - var middle = InputParser.ParseInputString(testString); + var middle = new InputParser().ParseInputString(testString); var result = middle.Evaluate(CreateTestRewriteContext(), CreateTestRuleMatch(), CreateTestCondMatch()); Assert.Equal(result, expected); } @@ -67,7 +67,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite [InlineData("hey/{UrlEncode:}", "hey/%3Chey%3E")] public void EvaluatUriEncodeRule(string testString, string expected) { - var middle = InputParser.ParseInputString(testString); + var middle = new InputParser().ParseInputString(testString); var result = middle.Evaluate(CreateTestRewriteContext(), CreateTestRuleMatch(), CreateTestCondMatch()); Assert.Equal(result, expected); } @@ -86,7 +86,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite [InlineData("{HTTPS")] public void FormatExceptionsOnBadSyntax(string testString) { - Assert.Throws(() => InputParser.ParseInputString(testString)); + Assert.Throws(() => new InputParser().ParseInputString(testString)); } private RewriteContext CreateTestRewriteContext() From 73e0d531e06ef55d646d62755077ef4feab7831a Mon Sep 17 00:00:00 2001 From: Justin Kotalik Date: Thu, 18 Aug 2016 16:15:17 -0700 Subject: [PATCH 094/307] Adds mod_rewrite tests, small refactors to exception messages and types --- .../Internal/ModRewrite/FlagParser.cs | 2 +- .../Internal/ModRewrite/TestStringParser.cs | 2 +- .../Internal/ModRewrite/Tokenizer.cs | 23 ++- ...nTest.cs => ConditionPatternParserTest.cs} | 34 +++-- .../ModRewrite/FlagParserTest.cs | 19 +++ .../ModRewrite/FormatExceptionTests.cs | 2 +- .../ModRewrite/RewriteTokenizerTest.cs | 41 ++++- .../ModRewrite/TestStringParserTests.cs | 141 ++++++++++++++++++ 8 files changed, 238 insertions(+), 26 deletions(-) rename test/Microsoft.AspNetCore.Rewrite.Tests/ModRewrite/{ConditionActionTest.cs => ConditionPatternParserTest.cs} (70%) create mode 100644 test/Microsoft.AspNetCore.Rewrite.Tests/ModRewrite/TestStringParserTests.cs diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/FlagParser.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/FlagParser.cs index 16a0900815..d06085df59 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/FlagParser.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/FlagParser.cs @@ -77,7 +77,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite FlagType flag; if (!_ruleFlagLookup.TryGetValue(hasPayload[0], out flag)) { - throw new FormatException($"Unrecognized flag: {hasPayload[0]}"); + throw new FormatException($"Unrecognized flag: '{hasPayload[0]}'"); } if (hasPayload.Length == 2) diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/TestStringParser.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/TestStringParser.cs index bcedbb214f..787ef16e7c 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/TestStringParser.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/TestStringParser.cs @@ -146,7 +146,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite else { // illegal escape of a character - throw new FormatException(Resources.FormatError_InputParserUnrecognizedParameter(context.Template, context.Index)); + throw new FormatException(Resources.FormatError_InputParserInvalidInteger(context.Template, context.Index)); } } diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/Tokenizer.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/Tokenizer.cs index 69c7880f50..2546f6e059 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/Tokenizer.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/Tokenizer.cs @@ -29,27 +29,19 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite return null; } var context = new ParserContext(rule); - if (!context.Next()) - { - return null; - } - + context.Next(); + var tokens = new List(); context.Mark(); while (true) { - if (!context.Next()) - { - // End of string. Capture. - break; - } - else if (context.Current == Escape) + if (context.Current == Escape) { // Need to progress such that the next character is not evaluated. if (!context.Next()) { // Means that a character was not escaped appropriately Ex: "foo\" - throw new FormatException("Invalid escaper character in string " + rule); + throw new FormatException($"Invalid escaper character in string: {rule}"); } } else if (context.Current == Space || context.Current == Tab) @@ -68,14 +60,21 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite } } context.Mark(); + context.Back(); } } + if (!context.Next()) + { + // End of string. Capture. + break; + } } var done = context.Capture(); if (!string.IsNullOrEmpty(done)) { tokens.Add(done); } + return tokens; } } diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/ModRewrite/ConditionActionTest.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/ModRewrite/ConditionPatternParserTest.cs similarity index 70% rename from test/Microsoft.AspNetCore.Rewrite.Tests/ModRewrite/ConditionActionTest.cs rename to test/Microsoft.AspNetCore.Rewrite.Tests/ModRewrite/ConditionPatternParserTest.cs index c1a47b26da..7d67317e1b 100644 --- a/test/Microsoft.AspNetCore.Rewrite.Tests/ModRewrite/ConditionActionTest.cs +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/ModRewrite/ConditionPatternParserTest.cs @@ -1,12 +1,13 @@ // 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; using Microsoft.AspNetCore.Rewrite.Internal.ModRewrite; using Xunit; namespace Microsoft.AspNetCore.Rewrite.Tests.ModRewrite { - public class ConditionActionTest + public class ConditionPatternParserTest { [Theory] [InlineData(">hey", OperationType.Greater, "hey", ConditionType.StringComp)] @@ -14,7 +15,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.ModRewrite [InlineData(">=hey", OperationType.GreaterEqual, "hey", ConditionType.StringComp)] [InlineData("<=hey", OperationType.LessEqual, "hey", ConditionType.StringComp)] [InlineData("=hey", OperationType.Equal, "hey", ConditionType.StringComp)] - public void ConditionParser_CheckStringComp(string condition, OperationType operation, string variable, ConditionType conditionType) + public void ConditionPatternParser_CheckStringComp(string condition, OperationType operation, string variable, ConditionType conditionType) { var results = new ConditionPatternParser().ParseActionCondition(condition); @@ -23,12 +24,12 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.ModRewrite } [Fact] - public void ConditionParser_CheckRegexEqual() + public void ConditionPatternParser_CheckRegexEqual() { var condition = @"(.*)"; var results = new ConditionPatternParser().ParseActionCondition(condition); - var expected = new ParsedModRewriteInput { ConditionType = ConditionType.Regex, Operand = "(.*)", Invert = false }; + var expected = new ParsedModRewriteInput { ConditionType = ConditionType.Regex, Operand = "(.*)", Invert = false }; Assert.True(CompareConditions(results, expected)); } @@ -42,11 +43,11 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.ModRewrite [InlineData("-s", OperationType.Size, ConditionType.PropertyTest)] [InlineData("-U", OperationType.ExistingUrl, ConditionType.PropertyTest)] [InlineData("-x", OperationType.Executable, ConditionType.PropertyTest)] - public void ConditionParser_CheckFileOperations(string condition, OperationType operation, ConditionType cond) + public void ConditionPatternParser_CheckFileOperations(string condition, OperationType operation, ConditionType cond) { var results = new ConditionPatternParser().ParseActionCondition(condition); - var expected = new ParsedModRewriteInput { ConditionType = cond, OperationType = operation , Invert = false }; + var expected = new ParsedModRewriteInput { ConditionType = cond, OperationType = operation, Invert = false }; Assert.True(CompareConditions(results, expected)); } @@ -60,7 +61,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.ModRewrite [InlineData("!-s", OperationType.Size, ConditionType.PropertyTest)] [InlineData("!-U", OperationType.ExistingUrl, ConditionType.PropertyTest)] [InlineData("!-x", OperationType.Executable, ConditionType.PropertyTest)] - public void ConditionParser_CheckFileOperationsInverted(string condition, OperationType operation, ConditionType cond) + public void ConditionPatternParser_CheckFileOperationsInverted(string condition, OperationType operation, ConditionType cond) { var results = new ConditionPatternParser().ParseActionCondition(condition); @@ -75,7 +76,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.ModRewrite [InlineData("-le1", OperationType.LessEqual, "1", ConditionType.IntComp)] [InlineData("-eq1", OperationType.Equal, "1", ConditionType.IntComp)] [InlineData("-ne1", OperationType.NotEqual, "1", ConditionType.IntComp)] - public void ConditionParser_CheckIntComp(string condition, OperationType operation, string variable, ConditionType cond) + public void ConditionPatternParser_CheckIntComp(string condition, OperationType operation, string variable, ConditionType cond) { var results = new ConditionPatternParser().ParseActionCondition(condition); @@ -83,7 +84,22 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.ModRewrite Assert.True(CompareConditions(results, expected)); } - // TODO negative tests + [Theory] + [InlineData("", "Unrecognized parameter type: '', terminated at string index: '0'")] + [InlineData("!", "Unrecognized parameter type: '!', terminated at string index: '1'")] + [InlineData(">", "Unrecognized parameter type: '>', terminated at string index: '1'")] + [InlineData("<", "Unrecognized parameter type: '<', terminated at string index: '1'")] + [InlineData("=", "Unrecognized parameter type: '=', terminated at string index: '1'")] + [InlineData(">=", "Unrecognized parameter type: '>=', terminated at string index: '2'")] + [InlineData("<=", "Unrecognized parameter type: '<=', terminated at string index: '2'")] + [InlineData("-a", "Unrecognized parameter type: '-a', terminated at string index: '1'")] + [InlineData("-gewow", "Unrecognized parameter type: '-gewow', terminated at string index: '3'")] + public void ConditionPatternParser_AssertBadInputThrowsFormatException(string input, string expected) + { + var ex = Assert.Throws(() => new ConditionPatternParser().ParseActionCondition(input)); + Assert.Equal(expected, ex.Message); + } + private bool CompareConditions(ParsedModRewriteInput i1, ParsedModRewriteInput i2) { if (i1.OperationType != i2.OperationType || diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/ModRewrite/FlagParserTest.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/ModRewrite/FlagParserTest.cs index 1cc8aa9a6f..d788fa25b9 100644 --- a/test/Microsoft.AspNetCore.Rewrite.Tests/ModRewrite/FlagParserTest.cs +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/ModRewrite/FlagParserTest.cs @@ -1,6 +1,7 @@ // 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; using System.Collections.Generic; using System.Linq; using Microsoft.AspNetCore.Rewrite.Internal.ModRewrite; @@ -47,6 +48,24 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.ModRewrite Assert.True(DictionaryContentsEqual(results.FlagDictionary, expected.FlagDictionary)); } + [Theory] + [InlineData("]", "Flags should start and end with square brackets: [flags]")] + [InlineData("[", "Flags should start and end with square brackets: [flags]")] + [InlineData("[R, L]", "Unrecognized flag: ' L'")] // cannot have spaces after , + [InlineData("[RL]", "Unrecognized flag: 'RL'")] + public void FlagParser_AssertFormatErrorWhenFlagsArePoorlyConstructed(string input, string expected) + { + var ex = Assert.Throws(() => new FlagParser().Parse(input)); + Assert.Equal(expected, ex.Message); + } + + [Fact] + public void FlagParser_AssertArgumentExceptionWhenFlagsAreNullOrEmpty() + { + Assert.Throws(() => new FlagParser().Parse(null)); + Assert.Throws(() => new FlagParser().Parse(string.Empty)); + } + public bool DictionaryContentsEqual(IDictionary dictionary, IDictionary other) { return (other ?? new Dictionary()) diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/ModRewrite/FormatExceptionTests.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/ModRewrite/FormatExceptionTests.cs index 73d9f3c4c6..6c0913565a 100644 --- a/test/Microsoft.AspNetCore.Rewrite.Tests/ModRewrite/FormatExceptionTests.cs +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/ModRewrite/FormatExceptionTests.cs @@ -11,7 +11,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.ModRewrite public class FormatExceptionTests { [Theory] - [InlineData(@"RewriteCond 1 2\", @"Invalid escaper character in string RewriteCond 1 2\")] + [InlineData(@"RewriteCond 1 2\", @"Invalid escaper character in string: RewriteCond 1 2\")] [InlineData("BadExpression 1 2 3 4", "Could not parse the mod_rewrite file. Message: 'Too many tokens on line'. Line number '1'.")] [InlineData("RewriteCond % 2", "Could not parse the mod_rewrite file. Line number '1'.")] [InlineData("RewriteCond %{ 2", "Could not parse the mod_rewrite file. Line number '1'.")] diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/ModRewrite/RewriteTokenizerTest.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/ModRewrite/RewriteTokenizerTest.cs index 7b8b5a74f5..4c211f4bae 100644 --- a/test/Microsoft.AspNetCore.Rewrite.Tests/ModRewrite/RewriteTokenizerTest.cs +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/ModRewrite/RewriteTokenizerTest.cs @@ -1,6 +1,7 @@ // 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; using System.Collections.Generic; using Microsoft.AspNetCore.Rewrite.Internal.ModRewrite; using Xunit; @@ -31,9 +32,45 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.ModRewrite var expected = new List(); expected.Add("RewriteCond"); - expected.Add(@"%{HTTPS}\ what"); // TODO maybe just have the space here? talking point + expected.Add(@"%{HTTPS}\ what"); expected.Add("!-f"); - Assert.Equal(tokens,expected); + Assert.Equal(tokens, expected); + } + + [Fact] + public void Tokenize_CheckWhiteSpaceDirectlyFollowedByEscapeCharacter_CorrectSplit() + { + var testString = @"RewriteCond %{HTTPS} \ what !-f"; + var tokens = new Tokenizer().Tokenize(testString); + + var expected = new List(); + expected.Add(@"RewriteCond"); + expected.Add(@"%{HTTPS}"); + expected.Add(@"\ what"); + expected.Add(@"!-f"); + Assert.Equal(tokens, expected); + } + + [Fact] + public void Tokenize_CheckWhiteSpaceAtEndOfString_CorrectSplit() + { + var testString = @"RewriteCond %{HTTPS} \ what !-f "; + var tokens = new Tokenizer().Tokenize(testString); + + var expected = new List(); + expected.Add(@"RewriteCond"); + expected.Add(@"%{HTTPS}"); + expected.Add(@"\ what"); + expected.Add(@"!-f"); + Assert.Equal(expected, tokens); + } + + [Fact] + public void Tokenize_AssertFormatExceptionWhenEscapeCharacterIsAtEndOfString() + { + + var ex = Assert.Throws(() => new Tokenizer().Tokenize("\\")); + Assert.Equal(@"Invalid escaper character in string: \", ex.Message); } } } diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/ModRewrite/TestStringParserTests.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/ModRewrite/TestStringParserTests.cs new file mode 100644 index 0000000000..a362137d10 --- /dev/null +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/ModRewrite/TestStringParserTests.cs @@ -0,0 +1,141 @@ +// 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; +using System.Collections.Generic; +using Microsoft.AspNetCore.Rewrite.Internal; +using Microsoft.AspNetCore.Rewrite.Internal.ModRewrite; +using Microsoft.AspNetCore.Rewrite.Internal.PatternSegments; +using Xunit; + +namespace Microsoft.AspNetCore.Rewrite +{ + public class TestStringParserTests + { + [Fact] + public void ConditionParser_SingleServerVariable() + { + var serverVar = "%{HTTPS}"; + + var result = new TestStringParser().Parse(serverVar); + + var list = new List(); + list.Add(new IsHttpsModSegment()); + var expected = new Pattern(list); + AssertPatternsEqual(expected, result); + } + + [Fact] + public void ConditionParser_MultipleServerVariables() + { + var serverVar = "%{HTTPS}%{REQUEST_URI}"; + var result = new TestStringParser().Parse(serverVar); + + var list = new List(); + list.Add(new IsHttpsModSegment()); + list.Add(new UrlSegment()); + var expected = new Pattern(list); + AssertPatternsEqual(expected, result); + } + + [Fact] + public void ConditionParser_ParseLiteral() + { + var serverVar = "Hello!"; + var result = new TestStringParser().Parse(serverVar); + + var list = new List(); + list.Add(new LiteralSegment(serverVar)); + var expected = new Pattern(list); + AssertPatternsEqual(expected, result); + } + + [Fact] + public void ConditionParser_ParseConditionParameters() + { + var serverVar = "%1"; + var result = new TestStringParser().Parse(serverVar); + + var list = new List(); + list.Add(new ConditionMatchSegment(1)); + var expected = new Pattern(list); + AssertPatternsEqual(expected, result); + } + + [Fact] + public void ConditionParser_ParseMultipleConditionParameters() + { + var serverVar = "%1%2"; + var result = new TestStringParser().Parse(serverVar); + + var list = new List(); + list.Add(new ConditionMatchSegment(1)); + list.Add(new ConditionMatchSegment(2)); + var expected = new Pattern(list); + AssertPatternsEqual(expected, result); + } + + [Fact] + public void ConditionParser_ParseRuleVariable() + { + var serverVar = "$1"; + var result = new TestStringParser().Parse(serverVar); + + var list = new List(); + list.Add(new RuleMatchSegment(1)); + var expected = new Pattern(list); + AssertPatternsEqual(expected, result); + } + [Fact] + public void ConditionParser_ParseMultipleRuleVariables() + { + var serverVar = "$1$2"; + var result = new TestStringParser().Parse(serverVar); + + var list = new List(); + list.Add(new RuleMatchSegment(1)); + list.Add(new RuleMatchSegment(2)); + var expected = new Pattern(list); + AssertPatternsEqual(expected, result); + } + + [Fact] + public void ConditionParser_ParserComplexRequest() + { + var serverVar = "%{HTTPS}/$1"; + var result = new TestStringParser().Parse(serverVar); + + var list = new List(); + list.Add(new IsHttpsModSegment()); + list.Add(new LiteralSegment("/")); + list.Add(new RuleMatchSegment(1)); + var expected = new Pattern(list); + AssertPatternsEqual(expected, result); + } + + [Theory] + [InlineData(@"%}", "Cannot parse '%}' to integer at string index: '1'")] // no } at end + [InlineData(@"%{", "Missing close brace for parameter at string index: '2'")] // no closing } + [InlineData(@"%a", "Cannot parse '%a' to integer at string index: '1'")] // invalid character after % + [InlineData(@"$a", "Cannot parse '$a' to integer at string index: '1'")] // invalid character after $ + [InlineData(@"%{asdf", "Missing close brace for parameter at string index: '6'")] // no closing } with characters + public void ConditionParser_Bad(string testString, string expected) + { + var ex = Assert.Throws(() => new TestStringParser().Parse(testString)); + Assert.Equal(ex.Message, expected); + } + + private void AssertPatternsEqual(Pattern p1, Pattern p2) + { + Assert.Equal(p1.PatternSegments.Count, p2.PatternSegments.Count); + + for (int i = 0; i < p1.PatternSegments.Count; i++) + { + var s1 = p1.PatternSegments[i]; + var s2 = p2.PatternSegments[i]; + + Assert.Equal(s1.GetType(), s2.GetType()); + } + } + } +} From aea655c2d63b1b228a1b63a0da59b07855523291 Mon Sep 17 00:00:00 2001 From: Justin Kotalik Date: Fri, 19 Aug 2016 12:26:04 -0700 Subject: [PATCH 095/307] Cleaning up a bunch of todos --- .../CodeRewriteExtensions.cs | 1 - .../Internal/CodeRules/RewriteToHttpsRule.cs | 1 - .../ModRewrite/ModRewriteRedirectAction.cs | 8 +++++--- .../ModRewrite/ModRewriteRewriteAction.cs | 19 ++++++++++++++++-- .../Internal/ModRewrite/RuleBuilder.cs | 5 +---- .../Internal/ModRewrite/TestStringParser.cs | 17 +++++----------- .../Internal/ParserContext.cs | 1 + .../PreActions/ChangeEnvironmentPreAction.cs | 1 + .../Internal/UrlAction.cs | 3 --- .../Internal/UrlActions/RedirectAction.cs | 4 +++- .../UrlActions/RedirectClearQueryAction.cs | 1 - .../Internal/UrlActions/RewriteAction.cs | 6 ++++-- .../Internal/UrlActions/VoidAction.cs | 2 -- .../Internal/UrlRewrite/InputParser.cs | 4 ---- .../UrlRewrite/UrlRewriteRuleBuilder.cs | 11 +++++----- .../RewriteMiddleware.cs | 5 +++-- .../ModRewrite/RewriteTokenizerTest.cs | 1 - .../UrlRewrite/FileParserTests.cs | 1 - .../FormatExceptionHandlingTests.cs | 20 ------------------- .../UrlRewrite/InputParserTests.cs | 4 +--- .../UrlRewrite/ServerVariableTests.cs | 4 ++-- 21 files changed, 49 insertions(+), 70 deletions(-) diff --git a/src/Microsoft.AspNetCore.Rewrite/CodeRewriteExtensions.cs b/src/Microsoft.AspNetCore.Rewrite/CodeRewriteExtensions.cs index b31cf14cad..0a76169605 100644 --- a/src/Microsoft.AspNetCore.Rewrite/CodeRewriteExtensions.cs +++ b/src/Microsoft.AspNetCore.Rewrite/CodeRewriteExtensions.cs @@ -73,7 +73,6 @@ namespace Microsoft.AspNetCore.Rewrite return RedirectToHttps(options, statusCode, null); } - // TODO Don't do this, it doesn't work in all cases. Will refactor tonight/ tomorrow. public static RewriteOptions RedirectToHttps(this RewriteOptions options, int statusCode, int? sslPort) { options.Rules.Add(new RedirectToHttpsRule { StatusCode = statusCode, SSLPort = sslPort }); diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/CodeRules/RewriteToHttpsRule.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/CodeRules/RewriteToHttpsRule.cs index c4fa07f54d..fb5744e8c2 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/CodeRules/RewriteToHttpsRule.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/CodeRules/RewriteToHttpsRule.cs @@ -7,7 +7,6 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.CodeRules { public class RewriteToHttpsRule : Rule { - public bool stopProcessing { get; set; } public int? SSLPort { get; set; } diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/ModRewriteRedirectAction.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/ModRewriteRedirectAction.cs index a935946829..0e47a527ef 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/ModRewriteRedirectAction.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/ModRewriteRedirectAction.cs @@ -33,7 +33,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite var pattern = Url.Evaluate(context, ruleMatch, condMatch); if (EscapeBackReferences) { - // TODO right way to escape backreferences? + // because escapebackreferences will be encapsulated by the pattern, just escape the pattern pattern = Uri.EscapeDataString(pattern); } context.HttpContext.Response.StatusCode = StatusCode; @@ -47,11 +47,13 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite QueryString query; if (QueryStringAppend) { - query = context.HttpContext.Request.QueryString.Add(new QueryString(pattern.Substring(split))); + query = context.HttpContext.Request.QueryString.Add( + QueryString.FromUriComponent( + pattern.Substring(split))); } else { - query = new QueryString(pattern.Substring(split)); + query = QueryString.FromUriComponent(pattern.Substring(split)); } // not using the response.redirect here because status codes may be 301, 302, 307, 308 diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/ModRewriteRewriteAction.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/ModRewriteRewriteAction.cs index 23b4be1eed..10404e1f20 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/ModRewriteRewriteAction.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/ModRewriteRewriteAction.cs @@ -64,7 +64,6 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite } else { - // TODO fix with redirect action logic var split = pattern.IndexOf('?'); if (split >= 0) { @@ -77,7 +76,18 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite { context.HttpContext.Request.Path = PathString.FromUriComponent(ForwardSlash + path); } - context.HttpContext.Request.QueryString = context.HttpContext.Request.QueryString.Add(new QueryString(pattern.Substring(split))); + + if (QueryStringAppend) + { + context.HttpContext.Request.QueryString = context.HttpContext.Request.QueryString.Add( + QueryString.FromUriComponent( + pattern.Substring(split))); + } + else + { + context.HttpContext.Request.QueryString = QueryString.FromUriComponent( + pattern.Substring(split)); + } } else { @@ -89,6 +99,11 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite { context.HttpContext.Request.Path = PathString.FromUriComponent(ForwardSlash + pattern); } + + if (QueryStringDelete) + { + context.HttpContext.Request.QueryString = QueryString.Empty; + } } } return Result; diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/RuleBuilder.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/RuleBuilder.cs index 4095fb3da4..e19cf3cdda 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/RuleBuilder.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/RuleBuilder.cs @@ -23,14 +23,13 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite { if (_action == null || _match == null) { - // TODO throw an exception here, find apporpriate exception + throw new InvalidOperationException("Cannot create ModRewriteRule without action and match"); } return new ModRewriteRule(_match, _conditions, _action, _preActions); } public void AddRule(string rule) { - // TODO var tokens = new Tokenizer().Tokenize(rule); var regex = new RuleRegexParser().ParseRuleRegex(tokens[1]); var pattern = new TestStringParser().Parse(tokens[2]); @@ -65,7 +64,6 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite if (input.ConditionType == ConditionType.Regex) { - // TODO make nullable? if (flags.HasFlag(FlagType.NoCase)) { condition.Match = new RegexMatch(new Regex(input.Operand, RegexOptions.Compiled | RegexOptions.IgnoreCase, RegexTimeout), input.Invert); @@ -147,7 +145,6 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite case OperationType.Executable: throw new NotImplementedException("Executable Property search is not implemented"); default: - // TODO change exception throw new ArgumentException("Invalid operation for property comparison."); } } diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/TestStringParser.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/TestStringParser.cs index 787ef16e7c..557cc0bf24 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/TestStringParser.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/TestStringParser.cs @@ -64,12 +64,8 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite context.Next(); var ruleVariable = context.Capture(); context.Back(); - int parsedIndex; - if (!int.TryParse(ruleVariable, out parsedIndex)) - { - // TODO this should always pass, remove try parse? - throw new FormatException(Resources.FormatError_InputParserInvalidInteger(ruleVariable, context.Index)); - } + var parsedIndex = int.Parse(ruleVariable); + results.Add(new RuleMatchSegment(parsedIndex)); } else @@ -117,7 +113,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite else if (context.Current == Colon) { // Have a segmented look up Ex: HTTP:xxxx - // TODO + // Most of these we can't handle throw new NotImplementedException("Segmented Lookups no implemented"); } } @@ -133,14 +129,11 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite context.Mark(); context.Next(); var rawConditionParameter = context.Capture(); + // Once we leave this method, the while loop will call next again. Because // capture is exclusive, we need to go one past the end index, capture, and then go back. context.Back(); - int parsedIndex; - if (!int.TryParse(rawConditionParameter, out parsedIndex)) - { - throw new FormatException(Resources.FormatError_InputParserInvalidInteger(rawConditionParameter, context.Index)); - } + var parsedIndex = int.Parse(rawConditionParameter); results.Add(new ConditionMatchSegment(parsedIndex)); } else diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/ParserContext.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/ParserContext.cs index 815f3012d8..e394ddc4d4 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/ParserContext.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/ParserContext.cs @@ -62,6 +62,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal return null; } } + public string Error() { return string.Format("Syntax Error at index: ", Index, " with character: ", Current); diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/PreActions/ChangeEnvironmentPreAction.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/PreActions/ChangeEnvironmentPreAction.cs index 79e84bde7f..4e79c0f300 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/PreActions/ChangeEnvironmentPreAction.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/PreActions/ChangeEnvironmentPreAction.cs @@ -17,6 +17,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.PreActions public override void ApplyAction(HttpContext context, MatchResults ruleMatch, MatchResults condMatch) { // Do stuff to modify the env + throw new NotImplementedException(); } } } diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlAction.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlAction.cs index f1676c7d79..8f2a8496c8 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlAction.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlAction.cs @@ -1,9 +1,6 @@ // 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 Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite; - namespace Microsoft.AspNetCore.Rewrite.Internal { public abstract class UrlAction diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/RedirectAction.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/RedirectAction.cs index 245d1020f1..98df716b27 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/RedirectAction.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/RedirectAction.cs @@ -27,7 +27,9 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlActions var split = pattern.IndexOf('?'); if (split >= 0) { - var query = context.HttpContext.Request.QueryString.Add(new QueryString(pattern.Substring(split))); + var query = context.HttpContext.Request.QueryString.Add( + QueryString.FromUriComponent( + pattern.Substring(split))); // not using the HttpContext.Response.redirect here because status codes may be 301, 302, 307, 308 context.HttpContext.Response.Headers[HeaderNames.Location] = pattern.Substring(0, split) + query; } diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/RedirectClearQueryAction.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/RedirectClearQueryAction.cs index c48bb00202..ec51cf748c 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/RedirectClearQueryAction.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/RedirectClearQueryAction.cs @@ -1,7 +1,6 @@ // 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 Microsoft.AspNetCore.Http; using Microsoft.Net.Http.Headers; namespace Microsoft.AspNetCore.Rewrite.Internal.UrlActions diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/RewriteAction.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/RewriteAction.cs index 1574c2310e..ef16e84e76 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/RewriteAction.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/RewriteAction.cs @@ -25,7 +25,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlActions if (ClearQuery) { - context.HttpContext.Request.QueryString = new QueryString(); + context.HttpContext.Request.QueryString = QueryString.Empty; } // TODO PERF, substrings, object creation, etc. if (pattern.IndexOf("://") >= 0) @@ -56,7 +56,9 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlActions { context.HttpContext.Request.Path = PathString.FromUriComponent(ForwardSlash + path); } - context.HttpContext.Request.QueryString = context.HttpContext.Request.QueryString.Add(new QueryString(pattern.Substring(split))); + context.HttpContext.Request.QueryString = context.HttpContext.Request.QueryString.Add( + QueryString.FromUriComponent( + pattern.Substring(split))); } else { diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/VoidAction.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/VoidAction.cs index 7bf14afb11..82825872eb 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/VoidAction.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/VoidAction.cs @@ -1,8 +1,6 @@ // 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 Microsoft.AspNetCore.Http; - namespace Microsoft.AspNetCore.Rewrite.Internal.UrlActions { public class VoidAction : UrlAction diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/InputParser.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/InputParser.cs index 2e03d415f2..c721657b25 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/InputParser.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/InputParser.cs @@ -48,9 +48,6 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite } else if (context.Current == CloseBrace) { - // TODO we should be throwing a syntax error if we have uneven close braces - // Can fix by keeping track of the number of '{' and '}' with an int, where { - // increments and } decrements. Throw if < 0. return new Pattern(results); } else @@ -71,7 +68,6 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite // 2. {R:1} - Rule parameter // 3. {C:1} - Condition Parameter // 4. {function:xxx} - String function - // TODO consider perf here. This is on startup and will only happen one time // (unless we support Reload) string parameter; while (context.Next()) diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/UrlRewriteRuleBuilder.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/UrlRewriteRuleBuilder.cs index b8803c116b..413b81076a 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/UrlRewriteRuleBuilder.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/UrlRewriteRuleBuilder.cs @@ -24,7 +24,10 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite public UrlRewriteRule Build() { - // TODO some of these are required fields, throw if null? + if (_initialMatch == null || _action == null) + { + throw new InvalidOperationException("Cannot create UrlRewriteRule without action and match"); + } var rule = new UrlRewriteRule(); rule.Action = _action; rule.Conditions = _conditions; @@ -61,10 +64,10 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite } break; case ActionType.AbortRequest: - throw new FormatException("Abort Requests are not supported"); + throw new NotImplementedException("Abort Requests are not supported"); case ActionType.CustomResponse: // TODO - throw new FormatException("Custom Responses are not supported"); + throw new NotImplementedException("Custom Responses are not supported"); } } @@ -94,7 +97,6 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite } } - // TODO make this take two overloads and handle regex vs non regex case. public void AddUrlCondition(Pattern input, string pattern, PatternSyntax patternSyntax, MatchType matchType, bool ignoreCase, bool negate) { // If there are no conditions specified, @@ -140,7 +142,6 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite break; } default: - // TODO new exception handling throw new FormatException("Unrecognized matchType"); } break; diff --git a/src/Microsoft.AspNetCore.Rewrite/RewriteMiddleware.cs b/src/Microsoft.AspNetCore.Rewrite/RewriteMiddleware.cs index 01c8b17d0a..eebc8e9ffc 100644 --- a/src/Microsoft.AspNetCore.Rewrite/RewriteMiddleware.cs +++ b/src/Microsoft.AspNetCore.Rewrite/RewriteMiddleware.cs @@ -15,6 +15,8 @@ namespace Microsoft.AspNetCore.Rewrite /// public class RewriteMiddleware { + private static readonly Task CompletedTask = Task.FromResult(0); + private readonly RequestDelegate _next; private readonly RewriteOptions _options; private readonly IFileProvider _fileProvider; @@ -64,8 +66,7 @@ namespace Microsoft.AspNetCore.Rewrite // Explicitly show that we continue executing rules break; case RuleTerminiation.ResponseComplete: - // TODO cache task for perf - return Task.FromResult(0); + return CompletedTask; case RuleTerminiation.StopRules: return _next(context); } diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/ModRewrite/RewriteTokenizerTest.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/ModRewrite/RewriteTokenizerTest.cs index 4c211f4bae..c08d372555 100644 --- a/test/Microsoft.AspNetCore.Rewrite.Tests/ModRewrite/RewriteTokenizerTest.cs +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/ModRewrite/RewriteTokenizerTest.cs @@ -26,7 +26,6 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.ModRewrite [Fact] public void Tokenize_CheckEscapedSpaceIgnored() { - // TODO need consultation on escape characters. var testString = @"RewriteCond %{HTTPS}\ what !-f"; var tokens = new Tokenizer().Tokenize(testString); diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/UrlRewrite/FileParserTests.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/UrlRewrite/FileParserTests.cs index 450c840f5d..2c45fa8f02 100644 --- a/test/Microsoft.AspNetCore.Rewrite.Tests/UrlRewrite/FileParserTests.cs +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/UrlRewrite/FileParserTests.cs @@ -171,7 +171,6 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite Assert.Equal(r1.Name, r2.Name); Assert.Equal(r1.Enabled, r2.Enabled); - // TODO conditions, url pattern, initial match regex if (r1.Conditions == null) { Assert.Equal(r2.Conditions.ConditionList.Count, 0); diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/UrlRewrite/FormatExceptionHandlingTests.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/UrlRewrite/FormatExceptionHandlingTests.cs index 18011f4d40..b1e0a6f45b 100644 --- a/test/Microsoft.AspNetCore.Rewrite.Tests/UrlRewrite/FormatExceptionHandlingTests.cs +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/UrlRewrite/FormatExceptionHandlingTests.cs @@ -30,26 +30,6 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite ", "Could not parse the UrlRewrite file. Message: 'Missing close brace for parameter at string index: '1''. Line number '5': '14'.")] [InlineData( -@" - - - - - - -", - "Could not parse the UrlRewrite file. Message: 'Abort Requests are not supported'. Line number '5': '14'.")] - [InlineData( -@" - - - - - - -", - "Could not parse the UrlRewrite file. Message: 'Custom Responses are not supported'. Line number '5': '14'.")] - [InlineData( @" diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/UrlRewrite/InputParserTests.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/UrlRewrite/InputParserTests.cs index 4ed8edf88a..0a69cdf8ad 100644 --- a/test/Microsoft.AspNetCore.Rewrite.Tests/UrlRewrite/InputParserTests.cs +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/UrlRewrite/InputParserTests.cs @@ -19,8 +19,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite var result = new InputParser().ParseInputString(testString); Assert.Equal(result.PatternSegments.Count, 1); } - - // TODO update tests to check type + [Theory] [InlineData("foo/bar/{R:1}/what", 3)] [InlineData("foo/{R:1}", 2)] @@ -93,7 +92,6 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite { var context = new DefaultHttpContext(); - // TODO add fields if necessary return new RewriteContext { HttpContext = context, FileProvider = null }; } diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/UrlRewrite/ServerVariableTests.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/UrlRewrite/ServerVariableTests.cs index e0847cda75..206544b447 100644 --- a/test/Microsoft.AspNetCore.Rewrite.Tests/UrlRewrite/ServerVariableTests.cs +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/UrlRewrite/ServerVariableTests.cs @@ -37,8 +37,8 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite { var context = new DefaultHttpContext(); context.Request.Host = new HostString("example.com"); - context.Request.Path = new PathString("/foo"); - context.Request.QueryString = new QueryString("?bar=1"); + context.Request.Path = PathString.FromUriComponent("/foo"); + context.Request.QueryString = QueryString.FromUriComponent("?bar=1"); context.Request.ContentLength = 10; context.Request.ContentType = "json"; context.Request.Headers[HeaderNames.Accept] = "accept"; From 74b0b7945df4c9fe2a87fce64745275e8b81c7fa Mon Sep 17 00:00:00 2001 From: Justin Kotalik Date: Mon, 22 Aug 2016 14:19:02 -0700 Subject: [PATCH 096/307] Properly parse quotes and white space --- .../Internal/ModRewrite/Tokenizer.cs | 35 +++++++++++++++++-- .../ModRewrite/RewriteTokenizerTest.cs | 28 ++++++++++++--- 2 files changed, 57 insertions(+), 6 deletions(-) diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/Tokenizer.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/Tokenizer.cs index 2546f6e059..529d8e23b5 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/Tokenizer.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/Tokenizer.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using System.Text.RegularExpressions; namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite { @@ -30,7 +31,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite } var context = new ParserContext(rule); context.Next(); - + var tokens = new List(); context.Mark(); while (true) @@ -44,6 +45,21 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite throw new FormatException($"Invalid escaper character in string: {rule}"); } } + else if (context.Current == '"') + { + // Ignore all characters until the next quote is hit + if (!context.Next()) + { + throw new FormatException($"Mismatched number of quotes: {rule}"); + } + while (context.Current != '"') + { + if (!context.Next()) + { + throw new FormatException($"Mismatched number of quotes: {rule}"); + } + } + } else if (context.Current == Space || context.Current == Tab) { // time to capture! @@ -56,6 +72,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite if (!context.Next()) { // At end of string, we can return at this point. + RemoveQuotesAndEscapeCharacters(tokens); return tokens; } } @@ -74,8 +91,22 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite { tokens.Add(done); } - + + RemoveQuotesAndEscapeCharacters(tokens); return tokens; } + + // Need to remove leading and trailing slashes if they exist. + // This is on start-up, so more forgivening towards substrings/ new strings + // If this is a perf/memory problem, discuss later. + private void RemoveQuotesAndEscapeCharacters(List tokens) + { + for (int i = 0; i < tokens.Count; i++) + { + var token = tokens[i]; + var trimmed = token.Trim('\"'); + tokens[i] = Regex.Unescape(trimmed); + } + } } } diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/ModRewrite/RewriteTokenizerTest.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/ModRewrite/RewriteTokenizerTest.cs index c08d372555..c3f4ba28ff 100644 --- a/test/Microsoft.AspNetCore.Rewrite.Tests/ModRewrite/RewriteTokenizerTest.cs +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/ModRewrite/RewriteTokenizerTest.cs @@ -31,7 +31,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.ModRewrite var expected = new List(); expected.Add("RewriteCond"); - expected.Add(@"%{HTTPS}\ what"); + expected.Add(@"%{HTTPS} what"); expected.Add("!-f"); Assert.Equal(tokens, expected); } @@ -45,7 +45,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.ModRewrite var expected = new List(); expected.Add(@"RewriteCond"); expected.Add(@"%{HTTPS}"); - expected.Add(@"\ what"); + expected.Add(@" what"); expected.Add(@"!-f"); Assert.Equal(tokens, expected); } @@ -59,7 +59,21 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.ModRewrite var expected = new List(); expected.Add(@"RewriteCond"); expected.Add(@"%{HTTPS}"); - expected.Add(@"\ what"); + expected.Add(@" what"); + expected.Add(@"!-f"); + Assert.Equal(expected, tokens); + } + + [Fact] + public void Tokenize_CheckQuotesAreProperlyRemovedFromString() + { + var testString = "RewriteCond \"%{HTTPS}\" \"\\ what\" \"!-f\" "; + var tokens = new Tokenizer().Tokenize(testString); + + var expected = new List(); + expected.Add(@"RewriteCond"); + expected.Add(@"%{HTTPS}"); + expected.Add(@" what"); expected.Add(@"!-f"); Assert.Equal(expected, tokens); } @@ -67,9 +81,15 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.ModRewrite [Fact] public void Tokenize_AssertFormatExceptionWhenEscapeCharacterIsAtEndOfString() { - var ex = Assert.Throws(() => new Tokenizer().Tokenize("\\")); Assert.Equal(@"Invalid escaper character in string: \", ex.Message); } + + [Fact] + public void Tokenize_AssertFormatExceptionWhenUnevenNumberOfQuotes() + { + var ex = Assert.Throws(() => new Tokenizer().Tokenize("\"")); + Assert.Equal("Mismatched number of quotes: \"", ex.Message); + } } } From 0cb7445921a7eb077e42895b4ab3e3f7833e19a2 Mon Sep 17 00:00:00 2001 From: Justin Kotalik Date: Tue, 23 Aug 2016 13:46:39 -0700 Subject: [PATCH 097/307] General bugfixes and style cleanup --- samples/RewriteSample/Startup.cs | 2 +- .../CodeRewriteExtensions.cs | 2 +- .../Internal/CodeRules/RewriteToHttpsRule.cs | 4 +- .../ModRewrite/ConditionPatternParser.cs | 36 ++-- .../Internal/ModRewrite/FileParser.cs | 2 +- .../Internal/ModRewrite/FlagParser.cs | 2 +- .../ModRewrite/ModRewriteRewriteAction.cs | 5 +- .../Internal/ModRewrite/RuleBuilder.cs | 171 +++++++++--------- .../Internal/ModRewrite/RuleRegexParser.cs | 2 +- .../Internal/ModRewrite/TestStringParser.cs | 69 ++++--- .../Internal/ModRewrite/Tokenizer.cs | 73 ++++---- .../Internal/ParserContext.cs | 10 +- .../Internal/Pattern.cs | 2 +- .../PatternSegments/ConditionMatchSegment.cs | 6 +- .../PatternSegments/DateTimeSegment.cs | 2 +- .../Internal/PatternSegments/HeaderSegment.cs | 6 +- .../PatternSegments/LiteralSegment.cs | 6 +- .../PatternSegments/RuleMatchSegment.cs | 6 +- .../PatternSegments/ToLowerSegment.cs | 6 +- .../PatternSegments/UrlEncodeSegment.cs | 6 +- .../Internal/PreAction.cs | 5 +- .../Internal/UrlActions/RewriteAction.cs | 3 +- .../Internal/UrlActions/VoidAction.cs | 8 +- .../Internal/UrlMatch.cs | 2 +- .../Internal/UrlMatches/ExactMatch.cs | 10 +- .../Internal/UrlMatches/IntegerMatch.cs | 26 +-- .../Internal/UrlMatches/IsDirectoryMatch.cs | 2 +- .../Internal/UrlMatches/RegexMatch.cs | 9 +- .../Internal/UrlMatches/StringMatch.cs | 26 +-- .../Internal/UrlRewrite/FileParser.cs | 12 +- .../Internal/UrlRewrite/InputParser.cs | 3 +- .../UrlRewrite/UrlRewriteRuleBuilder.cs | 10 +- .../Internal/UrlRewriteRule.cs | 22 ++- .../RewriteMiddleware.cs | 2 + .../UrlRewrite/UrlRewriteApplicationTests.cs | 56 ++++++ 35 files changed, 333 insertions(+), 281 deletions(-) create mode 100644 test/Microsoft.AspNetCore.Rewrite.Tests/UrlRewrite/UrlRewriteApplicationTests.cs diff --git a/samples/RewriteSample/Startup.cs b/samples/RewriteSample/Startup.cs index 1dbcb048e5..a232a4bf45 100644 --- a/samples/RewriteSample/Startup.cs +++ b/samples/RewriteSample/Startup.cs @@ -37,7 +37,7 @@ namespace RewriteSample return RuleResult.Continue; })); - app.Run(context => context.Response.WriteAsync(context.Request.Path)); + app.Run(context => context.Response.WriteAsync($"Rewritten Url: {context.Request.Path + context.Request.QueryString}")); } public static void Main(string[] args) diff --git a/src/Microsoft.AspNetCore.Rewrite/CodeRewriteExtensions.cs b/src/Microsoft.AspNetCore.Rewrite/CodeRewriteExtensions.cs index 0a76169605..983ae1e36a 100644 --- a/src/Microsoft.AspNetCore.Rewrite/CodeRewriteExtensions.cs +++ b/src/Microsoft.AspNetCore.Rewrite/CodeRewriteExtensions.cs @@ -91,7 +91,7 @@ namespace Microsoft.AspNetCore.Rewrite public static RewriteOptions RewriteToHttps(this RewriteOptions options, int? sslPort, bool stopProcessing) { - options.Rules.Add(new RewriteToHttpsRule {SSLPort = sslPort, stopProcessing = stopProcessing }); + options.Rules.Add(new RewriteToHttpsRule {SSLPort = sslPort, StopProcessing = stopProcessing }); return options; } diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/CodeRules/RewriteToHttpsRule.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/CodeRules/RewriteToHttpsRule.cs index fb5744e8c2..bcb15fda25 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/CodeRules/RewriteToHttpsRule.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/CodeRules/RewriteToHttpsRule.cs @@ -7,7 +7,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.CodeRules { public class RewriteToHttpsRule : Rule { - public bool stopProcessing { get; set; } + public bool StopProcessing { get; set; } public int? SSLPort { get; set; } public override RuleResult ApplyRule(RewriteContext context) @@ -28,7 +28,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.CodeRules context.HttpContext.Request.Scheme = "https"; context.HttpContext.Request.Host = host; - return stopProcessing ? RuleResult.StopRules: RuleResult.Continue; + return StopProcessing ? RuleResult.StopRules: RuleResult.Continue; } return RuleResult.Continue; } diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/ConditionPatternParser.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/ConditionPatternParser.cs index ea678502de..dc9c8328be 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/ConditionPatternParser.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/ConditionPatternParser.cs @@ -172,19 +172,16 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite case 'g': if (!context.Next()) { - throw new FormatException(context.Error()); + throw new FormatException(Resources.FormatError_InputParserUnrecognizedParameter(context.Template, context.Index)); } - if (context.Current == 't') + switch (context.Current) { - return new ParsedModRewriteInput(invert, ConditionType.IntComp, OperationType.Greater, operand: null); - } - else if (context.Current == 'e') - { - return new ParsedModRewriteInput(invert, ConditionType.IntComp, OperationType.GreaterEqual, operand: null); - } - else - { - throw new FormatException(context.Error()); + case 't': + return new ParsedModRewriteInput(invert, ConditionType.IntComp, OperationType.Greater, operand: null); + case 'e': + return new ParsedModRewriteInput(invert, ConditionType.IntComp, OperationType.GreaterEqual, operand: null); + default: + throw new FormatException(Resources.FormatError_InputParserUnrecognizedParameter(context.Template, context.Index)); } case 'l': // name conflict with -l and -lt/-le, so the assumption is if there is no @@ -193,17 +190,14 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite { return new ParsedModRewriteInput(invert, ConditionType.PropertyTest, OperationType.SymbolicLink, operand: null); } - if (context.Current == 't') + switch (context.Current) { - return new ParsedModRewriteInput(invert, ConditionType.IntComp, OperationType.Less, operand: null); - } - else if (context.Current == 'e') - { - return new ParsedModRewriteInput(invert, ConditionType.IntComp, OperationType.LessEqual, operand: null); - } - else - { - throw new FormatException(Resources.FormatError_InputParserUnrecognizedParameter(context.Template, context.Index)); + case 't': + return new ParsedModRewriteInput(invert, ConditionType.IntComp, OperationType.Less, operand: null); + case 'e': + return new ParsedModRewriteInput(invert, ConditionType.IntComp, OperationType.LessEqual, operand: null); + default: + throw new FormatException(Resources.FormatError_InputParserUnrecognizedParameter(context.Template, context.Index)); } case 'n': if (!context.Next() || context.Current != 'e') diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/FileParser.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/FileParser.cs index 4610619ebf..2f16c8af08 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/FileParser.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/FileParser.cs @@ -11,7 +11,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite { public List Parse(TextReader input) { - string line = null; + string line; var rules = new List(); var builder = new RuleBuilder(); var lineNum = 0; diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/FlagParser.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/FlagParser.cs index d06085df59..895dcb16d4 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/FlagParser.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/FlagParser.cs @@ -70,7 +70,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite // Invalid syntax to have any spaces. var tokens = flagString.Substring(1, flagString.Length - 2).Split(','); var flags = new Flags(); - foreach (string token in tokens) + foreach (var token in tokens) { var hasPayload = token.Split('='); diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/ModRewriteRewriteAction.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/ModRewriteRewriteAction.cs index 10404e1f20..419bd0f440 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/ModRewriteRewriteAction.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/ModRewriteRewriteAction.cs @@ -1,6 +1,7 @@ // 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; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http.Extensions; @@ -33,9 +34,9 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite var pattern = Url.Evaluate(context, ruleMatch, condMatch); // TODO PERF, substrings, object creation, etc. - if (pattern.IndexOf("://") >= 0) + if (pattern.IndexOf("://", StringComparison.Ordinal) >= 0) { - string scheme = null; + string scheme; HostString host; PathString path; QueryString query; diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/RuleBuilder.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/RuleBuilder.cs index e19cf3cdda..db0490745c 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/RuleBuilder.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/RuleBuilder.cs @@ -62,91 +62,90 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite condition.OrNext = flags.HasFlag(FlagType.Or); condition.Input = pattern; - if (input.ConditionType == ConditionType.Regex) + switch (input.ConditionType) { - if (flags.HasFlag(FlagType.NoCase)) - { - condition.Match = new RegexMatch(new Regex(input.Operand, RegexOptions.Compiled | RegexOptions.IgnoreCase, RegexTimeout), input.Invert); - } - else - { - condition.Match = new RegexMatch(new Regex(input.Operand, RegexOptions.Compiled, RegexTimeout), input.Invert); - } - } - else if (input.ConditionType == ConditionType.IntComp) - { - switch (input.OperationType) - { - case OperationType.Equal: - condition.Match = new IntegerMatch(input.Operand, IntegerOperationType.Equal); - break; - case OperationType.Greater: - condition.Match = new IntegerMatch(input.Operand, IntegerOperationType.Greater); - break; - case OperationType.GreaterEqual: - condition.Match = new IntegerMatch(input.Operand, IntegerOperationType.GreaterEqual); - break; - case OperationType.Less: - condition.Match = new IntegerMatch(input.Operand, IntegerOperationType.Less); - break; - case OperationType.LessEqual: - condition.Match = new IntegerMatch(input.Operand, IntegerOperationType.LessEqual); - break; - case OperationType.NotEqual: - condition.Match = new IntegerMatch(input.Operand, IntegerOperationType.NotEqual); - break; - default: - throw new ArgumentException("Invalid operation for integer comparison."); - } - } - else if (input.ConditionType == ConditionType.StringComp) - { - switch (input.OperationType) - { - case OperationType.Equal: - condition.Match = new StringMatch(input.Operand, StringOperationType.Equal); - break; - case OperationType.Greater: - condition.Match = new StringMatch(input.Operand, StringOperationType.Greater); - break; - case OperationType.GreaterEqual: - condition.Match = new StringMatch(input.Operand, StringOperationType.GreaterEqual); - break; - case OperationType.Less: - condition.Match = new StringMatch(input.Operand, StringOperationType.Less); - break; - case OperationType.LessEqual: - condition.Match = new StringMatch(input.Operand, StringOperationType.LessEqual); - break; - default: - throw new ArgumentException("Invalid operation for string comparison."); - } - } - else - { - switch (input.OperationType) - { - case OperationType.Directory: - condition.Match = new IsDirectoryMatch(input.Invert); - break; - case OperationType.RegularFile: - condition.Match = new IsFileMatch(input.Invert); - break; - case OperationType.ExistingFile: - condition.Match = new IsFileMatch(input.Invert); - break; - case OperationType.SymbolicLink: - throw new NotImplementedException("Symbolic links are not implemented"); - case OperationType.Size: - condition.Match = new FileSizeMatch(input.Invert); - break; - case OperationType.ExistingUrl: - throw new NotImplementedException("Existing Url lookups not implemented"); - case OperationType.Executable: - throw new NotImplementedException("Executable Property search is not implemented"); - default: - throw new ArgumentException("Invalid operation for property comparison."); - } + case ConditionType.Regex: + if (flags.HasFlag(FlagType.NoCase)) + { + condition.Match = new RegexMatch(new Regex(input.Operand, RegexOptions.CultureInvariant | RegexOptions.Compiled | RegexOptions.IgnoreCase, RegexTimeout), input.Invert); + } + else + { + condition.Match = new RegexMatch(new Regex(input.Operand, RegexOptions.CultureInvariant | RegexOptions.Compiled, RegexTimeout), input.Invert); + } + break; + case ConditionType.IntComp: + switch (input.OperationType) + { + case OperationType.Equal: + condition.Match = new IntegerMatch(input.Operand, IntegerOperationType.Equal); + break; + case OperationType.Greater: + condition.Match = new IntegerMatch(input.Operand, IntegerOperationType.Greater); + break; + case OperationType.GreaterEqual: + condition.Match = new IntegerMatch(input.Operand, IntegerOperationType.GreaterEqual); + break; + case OperationType.Less: + condition.Match = new IntegerMatch(input.Operand, IntegerOperationType.Less); + break; + case OperationType.LessEqual: + condition.Match = new IntegerMatch(input.Operand, IntegerOperationType.LessEqual); + break; + case OperationType.NotEqual: + condition.Match = new IntegerMatch(input.Operand, IntegerOperationType.NotEqual); + break; + default: + throw new ArgumentException("Invalid operation for integer comparison."); + } + break; + case ConditionType.StringComp: + switch (input.OperationType) + { + case OperationType.Equal: + condition.Match = new StringMatch(input.Operand, StringOperationType.Equal, input.Invert); + break; + case OperationType.Greater: + condition.Match = new StringMatch(input.Operand, StringOperationType.Greater, input.Invert); + break; + case OperationType.GreaterEqual: + condition.Match = new StringMatch(input.Operand, StringOperationType.GreaterEqual, input.Invert); + break; + case OperationType.Less: + condition.Match = new StringMatch(input.Operand, StringOperationType.Less, input.Invert); + break; + case OperationType.LessEqual: + condition.Match = new StringMatch(input.Operand, StringOperationType.LessEqual, input.Invert); + break; + default: + throw new ArgumentException("Invalid operation for string comparison."); + } + break; + default: + switch (input.OperationType) + { + case OperationType.Directory: + condition.Match = new IsDirectoryMatch(input.Invert); + break; + case OperationType.RegularFile: + condition.Match = new IsFileMatch(input.Invert); + break; + case OperationType.ExistingFile: + condition.Match = new IsFileMatch(input.Invert); + break; + case OperationType.SymbolicLink: + throw new NotImplementedException("Symbolic links are not implemented"); + case OperationType.Size: + condition.Match = new FileSizeMatch(input.Invert); + break; + case OperationType.ExistingUrl: + throw new NotImplementedException("Existing Url lookups not implemented"); + case OperationType.Executable: + throw new NotImplementedException("Executable Property search is not implemented"); + default: + throw new ArgumentException("Invalid operation for property comparison."); + } + break; } _conditions.ConditionList.Add(condition); } @@ -157,11 +156,11 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite { if (flags.HasFlag(FlagType.NoCase)) { - _match = new RegexMatch(new Regex(input.Operand, RegexOptions.Compiled | RegexOptions.IgnoreCase, RegexTimeout), input.Invert); + _match = new RegexMatch(new Regex(input.Operand, RegexOptions.CultureInvariant | RegexOptions.Compiled | RegexOptions.IgnoreCase, RegexTimeout), input.Invert); } else { - _match = new RegexMatch(new Regex(input.Operand, RegexOptions.Compiled, RegexTimeout), input.Invert); + _match = new RegexMatch(new Regex(input.Operand, RegexOptions.CultureInvariant | RegexOptions.Compiled, RegexTimeout), input.Invert); } } diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/RuleRegexParser.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/RuleRegexParser.cs index 272faf96e0..67368cc6df 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/RuleRegexParser.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/RuleRegexParser.cs @@ -9,7 +9,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite { public ParsedModRewriteInput ParseRuleRegex(string regex) { - if (regex == null || regex == string.Empty) + if (string.IsNullOrEmpty(regex)) { throw new FormatException("Regex expression is null"); } diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/TestStringParser.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/TestStringParser.cs index 557cc0bf24..002c69fa40 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/TestStringParser.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/TestStringParser.cs @@ -14,7 +14,6 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite { private const char Percent = '%'; private const char Dollar = '$'; - private const char Space = ' '; private const char Colon = ':'; private const char OpenBrace = '{'; private const char CloseBrace = '}'; @@ -41,43 +40,41 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite var results = new List(); while (context.Next()) { - if (context.Current == Percent) + switch (context.Current) { - // This is a server parameter, parse for a condition variable - if (!context.Next()) - { - throw new FormatException(Resources.FormatError_InputParserUnrecognizedParameter(testString, context.Index)); - } - ParseConditionParameter(context, results); - } - else if (context.Current == Dollar) - { - // This is a parameter from the rule, verify that it is a number from 0 to 9 directly after it - // and create a new Pattern Segment. - if (!context.Next()) - { - throw new FormatException(Resources.FormatError_InputParserNoBackreference(context.Index)); - } - context.Mark(); - if (context.Current >= '0' && context.Current <= '9') - { - context.Next(); - var ruleVariable = context.Capture(); - context.Back(); - var parsedIndex = int.Parse(ruleVariable); + case Percent: + // This is a server parameter, parse for a condition variable + if (!context.Next()) + { + throw new FormatException(Resources.FormatError_InputParserUnrecognizedParameter(testString, context.Index)); + } + ParseConditionParameter(context, results); + break; + case Dollar: + // This is a parameter from the rule, verify that it is a number from 0 to 9 directly after it + // and create a new Pattern Segment. + if (!context.Next()) + { + throw new FormatException(Resources.FormatError_InputParserNoBackreference(context.Index)); + } + context.Mark(); + if (context.Current >= '0' && context.Current <= '9') + { + context.Next(); + var ruleVariable = context.Capture(); + context.Back(); + var parsedIndex = int.Parse(ruleVariable); - results.Add(new RuleMatchSegment(parsedIndex)); - } - else - { - throw new FormatException(Resources.FormatError_InputParserInvalidInteger(testString, context.Index)); - } - } - else - { - // Parse for literals, which will return on either the end of the test string - // or when it hits a special character - ParseLiteral(context, results); + results.Add(new RuleMatchSegment(parsedIndex)); + } + else + { + throw new FormatException(Resources.FormatError_InputParserInvalidInteger(testString, context.Index)); + } + break; + default: + ParseLiteral(context, results); + break; } } return new Pattern(results); diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/Tokenizer.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/Tokenizer.cs index 529d8e23b5..6b51553dbb 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/Tokenizer.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/Tokenizer.cs @@ -15,6 +15,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite private const char Space = ' '; private const char Escape = '\\'; private const char Tab = '\t'; + private const char Quote = '"'; /// /// Splits a string on whitespace, ignoring spaces, creating into a list of strings. @@ -36,49 +37,51 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite context.Mark(); while (true) { - if (context.Current == Escape) + switch (context.Current) { - // Need to progress such that the next character is not evaluated. - if (!context.Next()) - { - // Means that a character was not escaped appropriately Ex: "foo\" - throw new FormatException($"Invalid escaper character in string: {rule}"); - } - } - else if (context.Current == '"') - { - // Ignore all characters until the next quote is hit - if (!context.Next()) - { - throw new FormatException($"Mismatched number of quotes: {rule}"); - } - while (context.Current != '"') - { + case Escape: + // Need to progress such that the next character is not evaluated. + if (!context.Next()) + { + // Means that a character was not escaped appropriately Ex: "foo\" + throw new FormatException($"Invalid escaper character in string: {rule}"); + } + break; + case Quote: + // Ignore all characters until the next quote is hit if (!context.Next()) { throw new FormatException($"Mismatched number of quotes: {rule}"); } - } - } - else if (context.Current == Space || context.Current == Tab) - { - // time to capture! - var token = context.Capture(); - if (!string.IsNullOrEmpty(token)) - { - tokens.Add(token); - while (context.Current == Space || context.Current == Tab) + + while (context.Current != Quote) { if (!context.Next()) { - // At end of string, we can return at this point. - RemoveQuotesAndEscapeCharacters(tokens); - return tokens; + throw new FormatException($"Mismatched number of quotes: {rule}"); } } - context.Mark(); - context.Back(); - } + break; + case Space: + case Tab: + // time to capture! + var token = context.Capture(); + if (!string.IsNullOrEmpty(token)) + { + tokens.Add(token); + do + { + if (!context.Next()) + { + // At end of string, we can return at this point. + RemoveQuotesAndEscapeCharacters(tokens); + return tokens; + } + } while (context.Current == Space || context.Current == Tab); + context.Mark(); + context.Back(); + } + break; } if (!context.Next()) { @@ -99,9 +102,9 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite // Need to remove leading and trailing slashes if they exist. // This is on start-up, so more forgivening towards substrings/ new strings // If this is a perf/memory problem, discuss later. - private void RemoveQuotesAndEscapeCharacters(List tokens) + private static void RemoveQuotesAndEscapeCharacters(IList tokens) { - for (int i = 0; i < tokens.Count; i++) + for (var i = 0; i < tokens.Count; i++) { var token = tokens[i]; var trimmed = token.Trim('\"'); diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/ParserContext.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/ParserContext.cs index e394ddc4d4..50d0d3998a 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/ParserContext.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/ParserContext.cs @@ -18,10 +18,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal Index = -1; } - public char Current - { - get { return (Index < Template.Length && Index >= 0) ? Template[Index] : (char)0; } - } + public char Current => (Index < Template.Length && Index >= 0) ? Template[Index] : (char)0; public bool Back() { @@ -62,10 +59,5 @@ namespace Microsoft.AspNetCore.Rewrite.Internal return null; } } - - public string Error() - { - return string.Format("Syntax Error at index: ", Index, " with character: ", Current); - } } } diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/Pattern.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/Pattern.cs index 99f8f014f4..590bdccdb4 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/Pattern.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/Pattern.cs @@ -8,7 +8,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal public class Pattern { public IList PatternSegments { get; } - public Pattern(List patternSegments) + public Pattern(IList patternSegments) { PatternSegments = patternSegments; } diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/ConditionMatchSegment.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/ConditionMatchSegment.cs index 057164a4cc..5ca4cc2b97 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/ConditionMatchSegment.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/ConditionMatchSegment.cs @@ -5,16 +5,16 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.PatternSegments { public class ConditionMatchSegment : PatternSegment { - public int Index { get; set; } + private readonly int _index; public ConditionMatchSegment(int index) { - Index = index; + _index = index; } public override string Evaluate(RewriteContext context, MatchResults ruleMatch, MatchResults condMatch) { - return condMatch?.BackReference[Index]?.Value; + return condMatch?.BackReference[_index].Value; } } } diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/DateTimeSegment.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/DateTimeSegment.cs index bb535d5178..4238ebb0fb 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/DateTimeSegment.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/DateTimeSegment.cs @@ -8,7 +8,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.PatternSegments { public class DateTimeSegment : PatternSegment { - private DateTimePortion _portion; + private readonly DateTimePortion _portion; public DateTimeSegment(string segment) { diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/HeaderSegment.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/HeaderSegment.cs index 116dca22c4..cd506c75d2 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/HeaderSegment.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/HeaderSegment.cs @@ -5,16 +5,16 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.PatternSegments { public class HeaderSegment : PatternSegment { - public string Header { get; set; } + private readonly string _header; public HeaderSegment(string header) { - Header = header; + _header = header; } public override string Evaluate(RewriteContext context, MatchResults ruleMatch, MatchResults condMatch) { - return context.HttpContext.Request.Headers[Header]; + return context.HttpContext.Request.Headers[_header]; } } } diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/LiteralSegment.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/LiteralSegment.cs index 676a9e3d29..17d240db4a 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/LiteralSegment.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/LiteralSegment.cs @@ -5,16 +5,16 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.PatternSegments { public class LiteralSegment : PatternSegment { - public string Literal { get; set; } + private readonly string _literal; public LiteralSegment(string literal) { - Literal = literal; + _literal = literal; } public override string Evaluate(RewriteContext context, MatchResults ruleMatch, MatchResults condMatch) { - return Literal; + return _literal; } } } diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/RuleMatchSegment.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/RuleMatchSegment.cs index e54c08000b..2b008c6109 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/RuleMatchSegment.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/RuleMatchSegment.cs @@ -5,16 +5,16 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.PatternSegments { public class RuleMatchSegment : PatternSegment { - public int Index { get; set; } + private readonly int _index; public RuleMatchSegment(int index) { - Index = index; + _index = index; } public override string Evaluate(RewriteContext context, MatchResults ruleMatch, MatchResults condMatch) { - return ruleMatch?.BackReference[Index]?.Value; + return ruleMatch?.BackReference[_index].Value; } } } diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/ToLowerSegment.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/ToLowerSegment.cs index c61e056331..0588b2b526 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/ToLowerSegment.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/ToLowerSegment.cs @@ -7,11 +7,11 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.PatternSegments { public class ToLowerSegment : PatternSegment { - public Pattern Pattern { get; set; } + private readonly Pattern _pattern; public ToLowerSegment(Pattern pattern) { - Pattern = pattern; + _pattern = pattern; } public override string Evaluate(RewriteContext context, MatchResults ruleMatch, MatchResults condMatch) @@ -20,7 +20,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.PatternSegments // lowercase segments. var tempBuilder = context.Builder; context.Builder = new StringBuilder(64); - var pattern = Pattern.Evaluate(context, ruleMatch, condMatch); + var pattern = _pattern.Evaluate(context, ruleMatch, condMatch); context.Builder = tempBuilder; return pattern.ToLowerInvariant(); } diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/UrlEncodeSegment.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/UrlEncodeSegment.cs index f64bb33cc6..5bca22d5ff 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/UrlEncodeSegment.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/UrlEncodeSegment.cs @@ -8,18 +8,18 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.PatternSegments { public class UrlEncodeSegment : PatternSegment { - public Pattern Pattern { get; set; } + private readonly Pattern _pattern; public UrlEncodeSegment(Pattern pattern) { - Pattern = pattern; + _pattern = pattern; } public override string Evaluate(RewriteContext context, MatchResults ruleMatch, MatchResults condMatch) { var tempBuilder = context.Builder; context.Builder = new StringBuilder(64); - var pattern = Pattern.Evaluate(context, ruleMatch, condMatch); + var pattern = _pattern.Evaluate(context, ruleMatch, condMatch); context.Builder = tempBuilder; return UrlEncoder.Default.Encode(pattern); } diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/PreAction.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/PreAction.cs index 08b1014c1c..e86bc03f3c 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/PreAction.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/PreAction.cs @@ -1,6 +1,7 @@ - +// 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 Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite; namespace Microsoft.AspNetCore.Rewrite.Internal { diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/RewriteAction.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/RewriteAction.cs index ef16e84e76..eb8d59dda2 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/RewriteAction.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/RewriteAction.cs @@ -1,6 +1,7 @@ // 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; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http.Extensions; @@ -30,7 +31,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlActions // TODO PERF, substrings, object creation, etc. if (pattern.IndexOf("://") >= 0) { - string scheme = null; + string scheme; HostString host; PathString path; QueryString query; diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/VoidAction.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/VoidAction.cs index 82825872eb..c58c6e94cd 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/VoidAction.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/VoidAction.cs @@ -5,10 +5,16 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlActions { public class VoidAction : UrlAction { + private readonly RuleResult _results; + + public VoidAction(RuleResult results) + { + _results = results; + } // Explicitly say that nothing happens public override RuleResult ApplyAction(RewriteContext context, MatchResults ruleMatch, MatchResults condMatch) { - return RuleResult.Continue; + return _results; } } } diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlMatch.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlMatch.cs index 428c24ea75..9d78d63d67 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlMatch.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlMatch.cs @@ -5,7 +5,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal { public abstract class UrlMatch { - public bool Negate { get; set; } + protected bool Negate { get; set; } public abstract MatchResults Evaluate(string input, RewriteContext context); } } diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlMatches/ExactMatch.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlMatches/ExactMatch.cs index 39b6449524..58cc914b84 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlMatches/ExactMatch.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlMatches/ExactMatch.cs @@ -5,19 +5,19 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlMatches { public class ExactMatch : UrlMatch { - public bool IgnoreCase { get; } - public string StringMatch { get; } + private readonly bool _ignoreCase; + private readonly string _stringMatch; public ExactMatch(bool ignoreCase, string input, bool negate) { - IgnoreCase = ignoreCase; - StringMatch = input; + _ignoreCase = ignoreCase; + _stringMatch = input; Negate = negate; } public override MatchResults Evaluate(string pattern, RewriteContext context) { - var pathMatch = string.Compare(pattern, StringMatch, IgnoreCase); + var pathMatch = string.Compare(pattern, _stringMatch, _ignoreCase); return new MatchResults { Success = ((pathMatch == 0) != Negate) }; } } diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlMatches/IntegerMatch.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlMatches/IntegerMatch.cs index 185c8de53e..770bbbd6d1 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlMatches/IntegerMatch.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlMatches/IntegerMatch.cs @@ -8,12 +8,12 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlMatches { public class IntegerMatch : UrlMatch { - public int Value { get; } - public IntegerOperationType Operation { get; } + private readonly int _value; + private readonly IntegerOperationType _operation; public IntegerMatch(int value, IntegerOperationType operation) { - Value = value; - Operation = operation; + _value = value; + _operation = operation; } public IntegerMatch(string value, IntegerOperationType operation) @@ -23,8 +23,8 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlMatches { throw new FormatException("Syntax error for integers in comparison."); } - Value = compValue; - Operation = operation; + _value = compValue; + _operation = operation; } public override MatchResults Evaluate(string input, RewriteContext context) @@ -35,20 +35,20 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlMatches return MatchResults.EmptyFailure; } - switch (Operation) + switch (_operation) { case IntegerOperationType.Equal: - return compValue == Value ? MatchResults.EmptySuccess : MatchResults.EmptyFailure; + return compValue == _value ? MatchResults.EmptySuccess : MatchResults.EmptyFailure; case IntegerOperationType.Greater: - return compValue > Value ? MatchResults.EmptySuccess : MatchResults.EmptyFailure; + return compValue > _value ? MatchResults.EmptySuccess : MatchResults.EmptyFailure; case IntegerOperationType.GreaterEqual: - return compValue >= Value ? MatchResults.EmptySuccess : MatchResults.EmptyFailure; + return compValue >= _value ? MatchResults.EmptySuccess : MatchResults.EmptyFailure; case IntegerOperationType.Less: - return compValue < Value ? MatchResults.EmptySuccess : MatchResults.EmptyFailure; + return compValue < _value ? MatchResults.EmptySuccess : MatchResults.EmptyFailure; case IntegerOperationType.LessEqual: - return compValue <= Value ? MatchResults.EmptySuccess : MatchResults.EmptyFailure; + return compValue <= _value ? MatchResults.EmptySuccess : MatchResults.EmptyFailure; case IntegerOperationType.NotEqual: - return compValue != Value ? MatchResults.EmptySuccess : MatchResults.EmptyFailure; + return compValue != _value ? MatchResults.EmptySuccess : MatchResults.EmptyFailure; default: return null; } diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlMatches/IsDirectoryMatch.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlMatches/IsDirectoryMatch.cs index 97d1177714..113ff88e2e 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlMatches/IsDirectoryMatch.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlMatches/IsDirectoryMatch.cs @@ -5,7 +5,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlMatches { public class IsDirectoryMatch : UrlMatch { - public IsDirectoryMatch( bool negate) + public IsDirectoryMatch(bool negate) { Negate = negate; } diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlMatches/RegexMatch.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlMatches/RegexMatch.cs index a932d869f6..b869285b20 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlMatches/RegexMatch.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlMatches/RegexMatch.cs @@ -1,26 +1,23 @@ // 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; using System.Text.RegularExpressions; namespace Microsoft.AspNetCore.Rewrite.Internal.UrlMatches { public class RegexMatch : UrlMatch { - private static readonly TimeSpan RegexTimeout = TimeSpan.FromMilliseconds(1); - - public Regex Match { get; } + private readonly Regex _match; public RegexMatch(Regex match, bool negate) { - Match = match; + _match = match; Negate = negate; } public override MatchResults Evaluate(string pattern, RewriteContext context) { - var res = Match.Match(pattern); + var res = _match.Match(pattern); return new MatchResults { BackReference = res.Groups, Success = (res.Success != Negate)}; } } diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlMatches/StringMatch.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlMatches/StringMatch.cs index 81332401fe..e991144f2d 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlMatches/StringMatch.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlMatches/StringMatch.cs @@ -5,29 +5,31 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlMatches { public class StringMatch : UrlMatch { - public string Value { get; set; } - public StringOperationType Operation { get; set; } - public bool IgnoreCase { get; set; } - public StringMatch(string value, StringOperationType operation) + private readonly string _value; + private readonly StringOperationType _operation; + private readonly bool _ignoreCase; + + public StringMatch(string value, StringOperationType operation, bool ignoreCase) { - Value = value; - Operation = operation; + _value = value; + _operation = operation; + _ignoreCase = ignoreCase; } public override MatchResults Evaluate(string input, RewriteContext context) { - switch (Operation) + switch (_operation) { case StringOperationType.Equal: - return string.Compare(input, Value, IgnoreCase) == 0 ? MatchResults.EmptySuccess : MatchResults.EmptyFailure; + return string.Compare(input, _value, _ignoreCase) == 0 ? MatchResults.EmptySuccess : MatchResults.EmptyFailure; case StringOperationType.Greater: - return string.Compare(input, Value, IgnoreCase) > 0 ? MatchResults.EmptySuccess : MatchResults.EmptyFailure; + return string.Compare(input, _value, _ignoreCase) > 0 ? MatchResults.EmptySuccess : MatchResults.EmptyFailure; case StringOperationType.GreaterEqual: - return string.Compare(input, Value, IgnoreCase) >= 0 ? MatchResults.EmptySuccess : MatchResults.EmptyFailure; + return string.Compare(input, _value, _ignoreCase) >= 0 ? MatchResults.EmptySuccess : MatchResults.EmptyFailure; case StringOperationType.Less: - return string.Compare(input, Value, IgnoreCase) < 0 ? MatchResults.EmptySuccess : MatchResults.EmptyFailure; + return string.Compare(input, _value, _ignoreCase) < 0 ? MatchResults.EmptySuccess : MatchResults.EmptyFailure; case StringOperationType.LessEqual: - return string.Compare(input, Value, IgnoreCase) <= 0 ? MatchResults.EmptySuccess : MatchResults.EmptyFailure; + return string.Compare(input, _value, _ignoreCase) <= 0 ? MatchResults.EmptySuccess : MatchResults.EmptyFailure; default: return null; } diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/FileParser.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/FileParser.cs index b6b9d5ae16..6e6cd6419d 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/FileParser.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/FileParser.cs @@ -12,9 +12,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite { public class FileParser { - private static readonly TimeSpan RegexTimeout = TimeSpan.FromMilliseconds(1); - - private InputParser _inputParser = new InputParser(); + private readonly InputParser _inputParser = new InputParser(); public List Parse(TextReader reader) { @@ -168,12 +166,10 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite var parsedPatternString = condition.Attribute(RewriteTags.Pattern)?.Value; - Pattern input = null; try { - input = _inputParser.ParseInputString(parsedInputString); + var input = _inputParser.ParseInputString(parsedInputString); builder.AddUrlCondition(input, parsedPatternString, patternSyntax, matchType, ignoreCase, negate); - } catch (FormatException formatException) { @@ -212,14 +208,14 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite } } - private void ThrowUrlFormatException(XElement element, string message) + private static void ThrowUrlFormatException(XElement element, string message) { var line = ((IXmlLineInfo)element).LineNumber; var col = ((IXmlLineInfo)element).LinePosition; throw new FormatException(Resources.FormatError_UrlRewriteParseError(message, line, col)); } - private void ThrowUrlFormatException(XElement element, string message, Exception ex) + private static void ThrowUrlFormatException(XElement element, string message, Exception ex) { var line = ((IXmlLineInfo)element).LineNumber; var col = ((IXmlLineInfo)element).LinePosition; diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/InputParser.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/InputParser.cs index c721657b25..5fe5038eef 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/InputParser.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/InputParser.cs @@ -165,7 +165,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite return index; } - private static bool ParseLiteral(ParserContext context, List results) + private static void ParseLiteral(ParserContext context, List results) { context.Mark(); string literal; @@ -186,7 +186,6 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite } results.Add(new LiteralSegment(literal)); - return true; } } } diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/UrlRewriteRuleBuilder.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/UrlRewriteRuleBuilder.cs index 413b81076a..2dad4efcd0 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/UrlRewriteRuleBuilder.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/UrlRewriteRuleBuilder.cs @@ -41,7 +41,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite switch (actionType) { case ActionType.None: - _action = new VoidAction(); + _action = new VoidAction(stopProcessing ? RuleResult.StopRules : RuleResult.Continue); break; case ActionType.Rewrite: if (appendQueryString) @@ -79,12 +79,12 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite { if (ignoreCase) { - var regex = new Regex(input, RegexOptions.Compiled | RegexOptions.IgnoreCase, RegexTimeout); + var regex = new Regex(input, RegexOptions.CultureInvariant | RegexOptions.Compiled | RegexOptions.IgnoreCase, RegexTimeout); _initialMatch = new RegexMatch(regex, negate); } else { - var regex = new Regex(input, RegexOptions.Compiled, RegexTimeout); + var regex = new Regex(input, RegexOptions.CultureInvariant | RegexOptions.Compiled, RegexTimeout); _initialMatch = new RegexMatch(regex, negate); } break; @@ -121,11 +121,11 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite Regex regex = null; if (ignoreCase) { - regex = new Regex(pattern, RegexOptions.Compiled | RegexOptions.IgnoreCase, RegexTimeout); + regex = new Regex(pattern, RegexOptions.CultureInvariant | RegexOptions.Compiled | RegexOptions.IgnoreCase, RegexTimeout); } else { - regex = new Regex(pattern, RegexOptions.Compiled, RegexTimeout); + regex = new Regex(pattern, RegexOptions.CultureInvariant | RegexOptions.Compiled, RegexTimeout); } _conditions.ConditionList.Add(new Condition { Input = input, Match = new RegexMatch(regex, negate), OrNext = _matchAny}); diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewriteRule.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewriteRule.cs index 35ed34065f..736290b4fa 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewriteRule.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewriteRule.cs @@ -1,10 +1,7 @@ // 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; -using System.Diagnostics; -using System.Text.RegularExpressions; -using Microsoft.AspNetCore.Rewrite.Internal; +using Microsoft.AspNetCore.Http; namespace Microsoft.AspNetCore.Rewrite.Internal { @@ -26,9 +23,18 @@ namespace Microsoft.AspNetCore.Rewrite.Internal // Due to the path string always having a leading slash, // remove it from the path before regex comparison // TODO may need to check if there is a leading slash and remove conditionally - var initMatchRes = InitialMatch.Evaluate(context.HttpContext.Request.Path.ToString().Substring(1), context); + var path = context.HttpContext.Request.Path; + MatchResults initMatchResults; + if (path == PathString.Empty) + { + initMatchResults = InitialMatch.Evaluate(path.ToString(), context); + } + else + { + initMatchResults = InitialMatch.Evaluate(path.ToString().Substring(1), context); + } - if (!initMatchRes.Success) + if (!initMatchResults.Success) { return RuleResult.Continue; } @@ -36,7 +42,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal MatchResults condMatchRes = null; if (Conditions != null) { - condMatchRes = Conditions.Evaluate(context, initMatchRes); + condMatchRes = Conditions.Evaluate(context, initMatchResults); if (!condMatchRes.Success) { return RuleResult.Continue; @@ -44,7 +50,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal } // at this point we know the rule passed, evaluate the replacement. - return Action.ApplyAction(context, initMatchRes, condMatchRes); + return Action.ApplyAction(context, initMatchResults, condMatchRes); } } } \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Rewrite/RewriteMiddleware.cs b/src/Microsoft.AspNetCore.Rewrite/RewriteMiddleware.cs index eebc8e9ffc..61c332b7c6 100644 --- a/src/Microsoft.AspNetCore.Rewrite/RewriteMiddleware.cs +++ b/src/Microsoft.AspNetCore.Rewrite/RewriteMiddleware.cs @@ -69,6 +69,8 @@ namespace Microsoft.AspNetCore.Rewrite return CompletedTask; case RuleTerminiation.StopRules: return _next(context); + default: + throw new ArgumentOutOfRangeException($"Invalid rule termination {result}"); } } return _next(context); diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/UrlRewrite/UrlRewriteApplicationTests.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/UrlRewrite/UrlRewriteApplicationTests.cs new file mode 100644 index 0000000000..6c5abfedb5 --- /dev/null +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/UrlRewrite/UrlRewriteApplicationTests.cs @@ -0,0 +1,56 @@ +// 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; +using System.IO; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Rewrite.Internal; +using Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite; +using Microsoft.AspNetCore.TestHost; +using Xunit; + +namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite +{ + // TODO add more of these + public class UrlRewriteApplicationTests + { + [Fact] + public void ApplyRule_AssertStopProcessingFlagWillTerminateOnNoAction() + { + var xml = new StringReader(@" + + + + + + + "); + var rules = new FileParser().Parse(xml); + + Assert.Equal(rules.Count, 1); + var ruleResults = rules.FirstOrDefault().ApplyRule(new RewriteContext {HttpContext = new DefaultHttpContext()}); + Assert.Equal(ruleResults.Result, RuleTerminiation.StopRules); + } + + [Fact] + public void ApplyRule_AssertNoTerminateFlagWillNotTerminateOnNoAction() + { + var xml = new StringReader(@" + + + + + + + "); + var rules = new FileParser().Parse(xml); + + Assert.Equal(rules.Count, 1); + var ruleResults = rules.FirstOrDefault().ApplyRule(new RewriteContext { HttpContext = new DefaultHttpContext() }); + Assert.Equal(ruleResults.Result, RuleTerminiation.Continue); + } + } +} From f3b4658c2c2966d1ee65a0f88b02dc6a6ecc89a5 Mon Sep 17 00:00:00 2001 From: ZestyBread Date: Wed, 24 Aug 2016 12:30:21 -0700 Subject: [PATCH 098/307] Feedback from David and API Review/ Tests --- samples/RewriteSample/Rewrite.txt | 13 +- samples/RewriteSample/Startup.cs | 12 +- samples/RewriteSample/UrlRewrite.xml | 6 +- .../CodeRewriteExtensions.cs | 104 -------------- .../{FunctionalRule.cs => DelegateRule.cs} | 11 +- .../Internal/CodeRules/RewriteToHttpsRule.cs | 36 ----- .../{Conditions.cs => ConditionEvaluator.cs} | 8 +- .../ModRewrite/ConditionPatternParser.cs | 4 +- .../Internal/ModRewrite/FileParser.cs | 4 +- .../ModRewrite/ModRewriteRedirectAction.cs | 24 ++-- .../ModRewrite/ModRewriteRewriteAction.cs | 4 +- .../Internal/ModRewrite/RuleBuilder.cs | 6 +- .../Internal/ModRewrite/RuleRegexParser.cs | 2 +- .../Internal/ModRewrite/ServerVariables.cs | 1 - .../Internal/ModRewrite/TestStringParser.cs | 6 +- .../Internal/ModRewrite/Tokenizer.cs | 2 +- .../Internal/ModRewriteRule.cs | 17 ++- .../Internal/PatternSegment.cs | 4 - .../PatternSegments/DateTimeSegment.cs | 20 +-- .../Internal/PatternSegments/HeaderSegment.cs | 2 +- .../PatternSegments/UrlEncodeSegment.cs | 10 +- .../PreActions/ChangeCookiePreAction.cs | 2 +- .../Internal/UrlAction.cs | 2 +- .../Internal/UrlActions/RedirectAction.cs | 17 ++- .../UrlActions/RedirectClearQueryAction.cs | 27 ---- .../Internal/UrlActions/RewriteAction.cs | 8 +- .../Internal/UrlMatches/FileSizeMatch.cs | 2 +- .../Internal/UrlMatches/IsDirectoryMatch.cs | 4 +- .../Internal/UrlMatches/IsFileMatch.cs | 4 +- .../Internal/UrlMatches/RegexMatch.cs | 2 +- .../Internal/UrlRewrite/InputParser.cs | 7 +- .../Internal/UrlRewrite/ServerVariables.cs | 3 +- ...{FileParser.cs => UrlRewriteFileParser.cs} | 6 +- .../UrlRewrite/UrlRewriteRuleBuilder.cs | 74 ++++------ .../Internal/UrlRewriteRule.cs | 33 +++-- .../RewriteMiddlewareLoggingExtensions.cs | 88 ++++++++++++ ...ions.cs => ModRewriteOptionsExtensions.cs} | 53 +++---- ...ensions.cs => RewriteBuilderExtensions.cs} | 4 +- .../RewriteContext.cs | 7 +- .../RewriteMiddleware.cs | 36 +++-- .../RewriteOptions.cs | 9 +- .../RewriteOptionsExtensions.cs | 135 ++++++++++++++++++ .../{Internal => }/Rule.cs | 3 +- .../{Internal => }/RuleResult.cs | 10 +- .../{Internal => }/RuleTermination.cs | 4 +- ...ions.cs => UrlRewriteOptionsExtensions.cs} | 33 ++--- .../CodeRules/MiddlewareTests.cs | 23 +-- .../ModRewrite/ModRewriteMiddlewareTest.cs | 10 +- .../ModRewrite/TestStringParserTests.cs | 4 +- .../ConditionMatchSegmentTests.cs | 37 +++++ .../PatternSegments/DateTimeSegmentTests.cs | 44 ++++++ .../PatternSegments/HeaderSegmentTests.cs | 43 ++++++ .../PatternSegments/IsHttpsModSegmentTests.cs | 30 ++++ .../PatternSegments/IsHttpsSegmentTests.cs | 30 ++++ .../PatternSegments/IsIPV6SegmentTests.cs | 59 ++++++++ .../PatternSegments/LIteralSegmentTests.cs | 24 ++++ .../LocalAddressSegmentTests.cs | 41 ++++++ .../PatternSegments/LocalPortSegmentTests.cs | 28 ++++ .../QueryStringSegmentTests.cs | 27 ++++ .../RemoteAddressSegmentTests.cs | 40 ++++++ .../PatternSegments/RemotePortSegmentTests.cs | 26 ++++ .../RequestFilenameSegmentTests.cs | 26 ++++ .../RequestMethodSegmentTests.cs | 26 ++++ .../PatternSegments/RuleMatchSegmentTests.cs | 36 +++++ .../PatternSegments/SchemeSegmentTests.cs | 26 ++++ .../ServerProtocolSegmentTests.cs | 28 ++++ .../PatternSegments/ToLowerSegmentTests.cs | 32 +++++ .../PatternSegments/UrlEncodeSegmentTests.cs | 32 +++++ .../PatternSegments/UrlSegmentTests.cs | 26 ++++ .../UrlActions/ForbiddenActionTests.cs | 28 ++++ .../UrlActions/GoneActionTests.cs | 28 ++++ .../UrlRewrite/FileParserTests.cs | 47 +++--- .../FormatExceptionHandlingTests.cs | 2 +- .../UrlRewrite/InputParserTests.cs | 2 +- .../UrlRewrite/MiddleWareTests.cs | 8 +- .../UrlRewrite/UrlRewriteApplicationTests.cs | 13 +- 76 files changed, 1209 insertions(+), 486 deletions(-) delete mode 100644 src/Microsoft.AspNetCore.Rewrite/CodeRewriteExtensions.cs rename src/Microsoft.AspNetCore.Rewrite/Internal/CodeRules/{FunctionalRule.cs => DelegateRule.cs} (53%) delete mode 100644 src/Microsoft.AspNetCore.Rewrite/Internal/CodeRules/RewriteToHttpsRule.cs rename src/Microsoft.AspNetCore.Rewrite/Internal/{Conditions.cs => ConditionEvaluator.cs} (78%) delete mode 100644 src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/RedirectClearQueryAction.cs rename src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/{FileParser.cs => UrlRewriteFileParser.cs} (97%) create mode 100644 src/Microsoft.AspNetCore.Rewrite/Logging/RewriteMiddlewareLoggingExtensions.cs rename src/Microsoft.AspNetCore.Rewrite/{ModRewriteExtensions.cs => ModRewriteOptionsExtensions.cs} (55%) rename src/Microsoft.AspNetCore.Rewrite/{RewriteExtensions.cs => RewriteBuilderExtensions.cs} (90%) create mode 100644 src/Microsoft.AspNetCore.Rewrite/RewriteOptionsExtensions.cs rename src/Microsoft.AspNetCore.Rewrite/{Internal => }/Rule.cs (78%) rename src/Microsoft.AspNetCore.Rewrite/{Internal => }/RuleResult.cs (64%) rename src/Microsoft.AspNetCore.Rewrite/{Internal => }/RuleTermination.cs (75%) rename src/Microsoft.AspNetCore.Rewrite/{UrlRewriteExtensions.cs => UrlRewriteOptionsExtensions.cs} (68%) create mode 100644 test/Microsoft.AspNetCore.Rewrite.Tests/PatternSegments/ConditionMatchSegmentTests.cs create mode 100644 test/Microsoft.AspNetCore.Rewrite.Tests/PatternSegments/DateTimeSegmentTests.cs create mode 100644 test/Microsoft.AspNetCore.Rewrite.Tests/PatternSegments/HeaderSegmentTests.cs create mode 100644 test/Microsoft.AspNetCore.Rewrite.Tests/PatternSegments/IsHttpsModSegmentTests.cs create mode 100644 test/Microsoft.AspNetCore.Rewrite.Tests/PatternSegments/IsHttpsSegmentTests.cs create mode 100644 test/Microsoft.AspNetCore.Rewrite.Tests/PatternSegments/IsIPV6SegmentTests.cs create mode 100644 test/Microsoft.AspNetCore.Rewrite.Tests/PatternSegments/LIteralSegmentTests.cs create mode 100644 test/Microsoft.AspNetCore.Rewrite.Tests/PatternSegments/LocalAddressSegmentTests.cs create mode 100644 test/Microsoft.AspNetCore.Rewrite.Tests/PatternSegments/LocalPortSegmentTests.cs create mode 100644 test/Microsoft.AspNetCore.Rewrite.Tests/PatternSegments/QueryStringSegmentTests.cs create mode 100644 test/Microsoft.AspNetCore.Rewrite.Tests/PatternSegments/RemoteAddressSegmentTests.cs create mode 100644 test/Microsoft.AspNetCore.Rewrite.Tests/PatternSegments/RemotePortSegmentTests.cs create mode 100644 test/Microsoft.AspNetCore.Rewrite.Tests/PatternSegments/RequestFilenameSegmentTests.cs create mode 100644 test/Microsoft.AspNetCore.Rewrite.Tests/PatternSegments/RequestMethodSegmentTests.cs create mode 100644 test/Microsoft.AspNetCore.Rewrite.Tests/PatternSegments/RuleMatchSegmentTests.cs create mode 100644 test/Microsoft.AspNetCore.Rewrite.Tests/PatternSegments/SchemeSegmentTests.cs create mode 100644 test/Microsoft.AspNetCore.Rewrite.Tests/PatternSegments/ServerProtocolSegmentTests.cs create mode 100644 test/Microsoft.AspNetCore.Rewrite.Tests/PatternSegments/ToLowerSegmentTests.cs create mode 100644 test/Microsoft.AspNetCore.Rewrite.Tests/PatternSegments/UrlEncodeSegmentTests.cs create mode 100644 test/Microsoft.AspNetCore.Rewrite.Tests/PatternSegments/UrlSegmentTests.cs create mode 100644 test/Microsoft.AspNetCore.Rewrite.Tests/UrlActions/ForbiddenActionTests.cs create mode 100644 test/Microsoft.AspNetCore.Rewrite.Tests/UrlActions/GoneActionTests.cs diff --git a/samples/RewriteSample/Rewrite.txt b/samples/RewriteSample/Rewrite.txt index 574f251600..23d4948c18 100644 --- a/samples/RewriteSample/Rewrite.txt +++ b/samples/RewriteSample/Rewrite.txt @@ -1,10 +1,3 @@ -# Ensure Https -RewriteCond %{HTTPS} off -RewriteRule ^(.*)$ https://www.example.com$1 [L] - -# Rewrite path with additional sub directory -RewriteRule ^(.*)$ /foo$1 - -# Forbid a certain url from being accessed -RewriteRule /bar - [F] -RewriteRule /bar/ - [F] +# Rewrite path with additional sub directory +RewriteCond %{QUERY_STRING} id=20 +RewriteRule ^(.*)$ - [G] diff --git a/samples/RewriteSample/Startup.cs b/samples/RewriteSample/Startup.cs index a232a4bf45..ea80638c30 100644 --- a/samples/RewriteSample/Startup.cs +++ b/samples/RewriteSample/Startup.cs @@ -6,7 +6,6 @@ using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Rewrite; -using Microsoft.AspNetCore.Rewrite.Internal; namespace RewriteSample { @@ -26,16 +25,11 @@ namespace RewriteSample // (ex StringReplace) that are easy to implement in code, they can do so by calling // AddFunctionalRule(Func); // TODO make this startup do something useful. + app.UseRewriter(new RewriteOptions() + .Rewrite(@"foo/(\d+)", "foo?id={R:1}") .ImportFromUrlRewrite(hostingEnv, "UrlRewrite.xml") - .ImportFromModRewrite(hostingEnv, "Rewrite.txt") - .RedirectToHttps(StatusCodes.Status307TemporaryRedirect) - .RewriteRule("/foo/(.*)/bar", "{R:1}/bar") - .AddRule(ctx => - { - ctx.HttpContext.Request.Path = "/index"; - return RuleResult.Continue; - })); + .ImportFromModRewrite(hostingEnv, "Rewrite.txt")); app.Run(context => context.Response.WriteAsync($"Rewritten Url: {context.Request.Path + context.Request.QueryString}")); } diff --git a/samples/RewriteSample/UrlRewrite.xml b/samples/RewriteSample/UrlRewrite.xml index 9ef1097666..9d9e089676 100644 --- a/samples/RewriteSample/UrlRewrite.xml +++ b/samples/RewriteSample/UrlRewrite.xml @@ -1,8 +1,8 @@  - - - + + + \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Rewrite/CodeRewriteExtensions.cs b/src/Microsoft.AspNetCore.Rewrite/CodeRewriteExtensions.cs deleted file mode 100644 index 983ae1e36a..0000000000 --- a/src/Microsoft.AspNetCore.Rewrite/CodeRewriteExtensions.cs +++ /dev/null @@ -1,104 +0,0 @@ -// 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; -using System.Collections.Generic; -using Microsoft.AspNetCore.Rewrite.Internal; -using Microsoft.AspNetCore.Rewrite.Internal.CodeRules; -using Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite; - -namespace Microsoft.AspNetCore.Rewrite -{ - /// - /// The builder to a list of rules for and - /// - public static class CodeRewriteExtensions - { - /// - /// Adds a rule to the current rules. - /// - /// The UrlRewrite options. - /// A rule to be added to the current rules. - public static RewriteOptions AddRule(this RewriteOptions options, Rule rule) - { - options.Rules.Add(rule); - return options; - } - - /// - /// Adds a list of rules to the current rules. - /// - /// The UrlRewrite options. - /// A list of rules. - public static RewriteOptions AddRules(this RewriteOptions options, List rules) - { - options.Rules.AddRange(rules); - return options; - } - - public static RewriteOptions RewriteRule(this RewriteOptions options, string regex, string onMatch) - { - return RewriteRule(options, regex, onMatch, stopProcessing: false); - } - - public static RewriteOptions RewriteRule(this RewriteOptions options, string regex, string onMatch, bool stopProcessing) - { - var builder = new UrlRewriteRuleBuilder(); - var pattern = new InputParser().ParseInputString(onMatch); - - builder.AddUrlMatch(regex); - builder.AddUrlAction(pattern, actionType: ActionType.Rewrite, stopProcessing: stopProcessing); - options.Rules.Add(builder.Build()); - return options; - } - - public static RewriteOptions RedirectRule(this RewriteOptions options, string regex, string onMatch, int statusCode) - { - return RedirectRule(options, regex, onMatch, statusCode, stopProcessing: false); - } - - public static RewriteOptions RedirectRule(this RewriteOptions options, string regex, string onMatch, int statusCode, bool stopProcessing) - { - var builder = new UrlRewriteRuleBuilder(); - var pattern = new InputParser().ParseInputString(onMatch); - - builder.AddUrlMatch(regex); - builder.AddUrlAction(pattern, actionType: ActionType.Redirect, stopProcessing: stopProcessing); - options.Rules.Add(builder.Build()); - return options; - } - - public static RewriteOptions RedirectToHttps(this RewriteOptions options, int statusCode) - { - return RedirectToHttps(options, statusCode, null); - } - - public static RewriteOptions RedirectToHttps(this RewriteOptions options, int statusCode, int? sslPort) - { - options.Rules.Add(new RedirectToHttpsRule { StatusCode = statusCode, SSLPort = sslPort }); - return options; - } - - public static RewriteOptions RewriteToHttps(this RewriteOptions options) - { - return RewriteToHttps(options, sslPort: null, stopProcessing: false); - } - - public static RewriteOptions RewriteToHttps(this RewriteOptions options, int? sslPort) - { - return RewriteToHttps(options, sslPort, stopProcessing: false); - } - - public static RewriteOptions RewriteToHttps(this RewriteOptions options, int? sslPort, bool stopProcessing) - { - options.Rules.Add(new RewriteToHttpsRule {SSLPort = sslPort, StopProcessing = stopProcessing }); - return options; - } - - public static RewriteOptions AddRule(this RewriteOptions options, Func rule) - { - options.Rules.Add(new FunctionalRule { OnApplyRule = rule}); - return options; - } - } -} diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/CodeRules/FunctionalRule.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/CodeRules/DelegateRule.cs similarity index 53% rename from src/Microsoft.AspNetCore.Rewrite/Internal/CodeRules/FunctionalRule.cs rename to src/Microsoft.AspNetCore.Rewrite/Internal/CodeRules/DelegateRule.cs index eccf9e735f..72216f0abc 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/CodeRules/FunctionalRule.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/CodeRules/DelegateRule.cs @@ -5,9 +5,14 @@ using System; namespace Microsoft.AspNetCore.Rewrite.Internal.CodeRules { - public class FunctionalRule : Rule + public class DelegateRule : Rule { - public Func OnApplyRule { get; set; } - public override RuleResult ApplyRule(RewriteContext context) => OnApplyRule(context); + private readonly Func _onApplyRule; + + public DelegateRule(Func onApplyRule) + { + _onApplyRule = onApplyRule; + } + public override RuleResult ApplyRule(RewriteContext context) => _onApplyRule(context); } } \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/CodeRules/RewriteToHttpsRule.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/CodeRules/RewriteToHttpsRule.cs deleted file mode 100644 index bcb15fda25..0000000000 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/CodeRules/RewriteToHttpsRule.cs +++ /dev/null @@ -1,36 +0,0 @@ -// 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 Microsoft.AspNetCore.Http; - -namespace Microsoft.AspNetCore.Rewrite.Internal.CodeRules -{ - public class RewriteToHttpsRule : Rule - { - public bool StopProcessing { get; set; } - public int? SSLPort { get; set; } - - public override RuleResult ApplyRule(RewriteContext context) - { - if (!context.HttpContext.Request.IsHttps) - { - var host = context.HttpContext.Request.Host; - if (SSLPort.HasValue && SSLPort.Value > 0) - { - // a specific SSL port is specified - host = new HostString(host.Host, SSLPort.Value); - } - else - { - // clear the port - host = new HostString(host.Host); - } - - context.HttpContext.Request.Scheme = "https"; - context.HttpContext.Request.Host = host; - return StopProcessing ? RuleResult.StopRules: RuleResult.Continue; - } - return RuleResult.Continue; - } - } -} diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/Conditions.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/ConditionEvaluator.cs similarity index 78% rename from src/Microsoft.AspNetCore.Rewrite/Internal/Conditions.cs rename to src/Microsoft.AspNetCore.Rewrite/Internal/ConditionEvaluator.cs index d8154c6b1d..4407ec3ce8 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/Conditions.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/ConditionEvaluator.cs @@ -5,15 +5,14 @@ using System.Collections.Generic; namespace Microsoft.AspNetCore.Rewrite.Internal { - public class Conditions + public static class ConditionHelper { - public List ConditionList { get; set; } = new List(); - public MatchResults Evaluate(RewriteContext context, MatchResults ruleMatch) + public static MatchResults Evaluate(IEnumerable conditions, RewriteContext context, MatchResults ruleMatch) { MatchResults prevCond = null; var orSucceeded = false; - foreach (var condition in ConditionList) + foreach (var condition in conditions) { if (orSucceeded && condition.OrNext) { @@ -30,7 +29,6 @@ namespace Microsoft.AspNetCore.Rewrite.Internal if (condition.OrNext) { orSucceeded = prevCond.Success; - continue; } else if (!prevCond.Success) { diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/ConditionPatternParser.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/ConditionPatternParser.cs index dc9c8328be..fadd570f97 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/ConditionPatternParser.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/ConditionPatternParser.cs @@ -27,7 +27,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite /// A new parsed condition. public ParsedModRewriteInput ParseActionCondition(string condition) { - if (condition == null) + if (condition == null) { condition = string.Empty; } @@ -120,7 +120,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite } // Capture the rest of the string guarantee validity. - results.Operand = condition.Substring(context.GetIndex()); + results.Operand = condition.Substring(context.GetIndex()); if (IsValidActionCondition(results)) { return results; diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/FileParser.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/FileParser.cs index 2f16c8af08..baec9e2c4f 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/FileParser.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/FileParser.cs @@ -9,7 +9,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite { public class FileParser { - public List Parse(TextReader input) + public IList Parse(TextReader input) { string line; var rules = new List(); @@ -84,7 +84,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite builder.AddAction(pattern, flags); rules.Add(builder.Build()); builder = new RuleBuilder(); - } + } catch (FormatException formatException) { throw new FormatException(Resources.FormatError_ModRewriteGeneralParseError(lineNum), formatException); diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/ModRewriteRedirectAction.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/ModRewriteRedirectAction.cs index 0e47a527ef..75bc8aa0cc 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/ModRewriteRedirectAction.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/ModRewriteRedirectAction.cs @@ -15,10 +15,10 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite public bool EscapeBackReferences { get; } public ModRewriteRedirectAction( - int statusCode, - Pattern pattern, - bool queryStringAppend, - bool queryStringDelete, + int statusCode, + Pattern pattern, + bool queryStringAppend, + bool queryStringDelete, bool escapeBackReferences) { StatusCode = statusCode; @@ -42,19 +42,11 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite // always add to location header. // TODO check for false positives var split = pattern.IndexOf('?'); - if (split >= 0) + if (split >= 0 && QueryStringAppend) { - QueryString query; - if (QueryStringAppend) - { - query = context.HttpContext.Request.QueryString.Add( - QueryString.FromUriComponent( - pattern.Substring(split))); - } - else - { - query = QueryString.FromUriComponent(pattern.Substring(split)); - } + var query = context.HttpContext.Request.QueryString.Add( + QueryString.FromUriComponent( + pattern.Substring(split))); // not using the response.redirect here because status codes may be 301, 302, 307, 308 context.HttpContext.Response.Headers[HeaderNames.Location] = pattern.Substring(0, split) + query; diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/ModRewriteRewriteAction.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/ModRewriteRewriteAction.cs index 419bd0f440..01cb99dd24 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/ModRewriteRewriteAction.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/ModRewriteRewriteAction.cs @@ -16,8 +16,8 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite public bool EscapeBackReferences { get; } public ModRewriteRewriteAction( - RuleResult result, - Pattern pattern, + RuleResult result, + Pattern pattern, bool queryStringAppend, bool queryStringDelete, bool escapeBackReferences) diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/RuleBuilder.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/RuleBuilder.cs index db0490745c..8190431803 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/RuleBuilder.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/RuleBuilder.cs @@ -12,7 +12,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite { public class RuleBuilder { - private Conditions _conditions; + private IList _conditions; private UrlAction _action; private UrlMatch _match; private List _preActions; @@ -54,7 +54,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite { if (_conditions == null) { - _conditions = new Conditions(); + _conditions = new List(); } var condition = new Condition(); @@ -147,7 +147,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite } break; } - _conditions.ConditionList.Add(condition); + _conditions.Add(condition); } public void AddMatch( diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/RuleRegexParser.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/RuleRegexParser.cs index 67368cc6df..bdc6273d02 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/RuleRegexParser.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/RuleRegexParser.cs @@ -19,7 +19,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite } else { - return new ParsedModRewriteInput { Invert = false, Operand = regex}; + return new ParsedModRewriteInput { Invert = false, Operand = regex }; } } } diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/ServerVariables.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/ServerVariables.cs index 863fd44bba..ebddffba19 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/ServerVariables.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/ServerVariables.cs @@ -106,7 +106,6 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite case "HTTP2": throw new NotImplementedException("Http2 server variable is not supported"); case "IS_SUBREQ": - // TODO maybe can do this? context.Request.HttpContext ? throw new NotImplementedException("Is-Subrequest server variable is not supported"); case "REQUEST_FILENAME": return new RequestFileNameSegment(); diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/TestStringParser.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/TestStringParser.cs index 002c69fa40..a87d9b1ed6 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/TestStringParser.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/TestStringParser.cs @@ -64,7 +64,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite var ruleVariable = context.Capture(); context.Back(); var parsedIndex = int.Parse(ruleVariable); - + results.Add(new RuleMatchSegment(parsedIndex)); } else @@ -89,7 +89,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite /// The ParserContext /// The List of results which the new condition parameter will be added. /// true - private static void ParseConditionParameter(ParserContext context, List results) + private static void ParseConditionParameter(ParserContext context, IList results) { // Parse { } if (context.Current == OpenBrace) @@ -146,7 +146,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite /// /// /// - private static void ParseLiteral(ParserContext context, List results) + private static void ParseLiteral(ParserContext context, IList results) { context.Mark(); string literal; diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/Tokenizer.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/Tokenizer.cs index 6b51553dbb..1ecabd093d 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/Tokenizer.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/Tokenizer.cs @@ -22,7 +22,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite /// /// The rule to tokenize. /// A list of tokens. - public List Tokenize(string rule) + public IList Tokenize(string rule) { // TODO make list of strings a reference to the original rule? (run into problems with escaped spaces). // TODO handle "s and probably replace \ character with no slash. diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewriteRule.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewriteRule.cs index 6d7e090b9a..eb54eed72a 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewriteRule.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewriteRule.cs @@ -2,18 +2,18 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System.Collections.Generic; -using Microsoft.AspNetCore.Rewrite.Internal; +using Microsoft.AspNetCore.Rewrite.Logging; namespace Microsoft.AspNetCore.Rewrite.Internal { public class ModRewriteRule : Rule { - public UrlMatch InitialMatch { get; set; } - public Conditions Conditions { get; set; } - public UrlAction Action { get; set; } - public List PreActions { get; set; } + public UrlMatch InitialMatch { get; } + public IList Conditions { get; } + public UrlAction Action { get; } + public IList PreActions { get; } - public ModRewriteRule(UrlMatch initialMatch, Conditions conditions, UrlAction urlAction, List preActions) + public ModRewriteRule(UrlMatch initialMatch, IList conditions, UrlAction urlAction, IList preActions) { Conditions = conditions; InitialMatch = initialMatch; @@ -28,21 +28,24 @@ namespace Microsoft.AspNetCore.Rewrite.Internal if (!initMatchRes.Success) { + context.Logger?.ModRewriteDidNotMatchRule(); return RuleResult.Continue; } MatchResults condMatchRes = null; if (Conditions != null) { - condMatchRes = Conditions.Evaluate(context, initMatchRes); + condMatchRes = ConditionHelper.Evaluate(Conditions, context, initMatchRes); if (!condMatchRes.Success) { + context.Logger?.ModRewriteDidNotMatchRule(); return RuleResult.Continue; } } // At this point, we know our rule passed, first apply pre conditions, // which can modify things like the cookie or env, and then apply the action + context.Logger?.ModRewriteMatchedRule(); foreach (var preAction in PreActions) { preAction.ApplyAction(context.HttpContext, initMatchRes, condMatchRes); diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegment.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegment.cs index 6ea96b915f..0cc7b7ddce 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegment.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegment.cs @@ -1,14 +1,10 @@ // 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 Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite; - namespace Microsoft.AspNetCore.Rewrite.Internal { public abstract class PatternSegment { - // Match from prevRule, Match from prevCond public abstract string Evaluate(RewriteContext context, MatchResults ruleMatch, MatchResults condMatch); } } diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/DateTimeSegment.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/DateTimeSegment.cs index 4238ebb0fb..2d5202eeb8 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/DateTimeSegment.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/DateTimeSegment.cs @@ -12,7 +12,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.PatternSegments public DateTimeSegment(string segment) { - switch(segment) + switch (segment) { case "TIME_YEAR": _portion = DateTimePortion.Year; @@ -24,28 +24,29 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.PatternSegments _portion = DateTimePortion.Day; break; case "TIME_HOUR": - _portion = DateTimePortion.Day; + _portion = DateTimePortion.Hour; break; case "TIME_MIN": - _portion = DateTimePortion.Day; + _portion = DateTimePortion.Minute; break; case "TIME_SEC": - _portion = DateTimePortion.Day; + _portion = DateTimePortion.Second; break; case "TIME_WDAY": - _portion = DateTimePortion.Day; + _portion = DateTimePortion.DayOfWeek; break; case "TIME": - _portion = DateTimePortion.Day; + _portion = DateTimePortion.Time; break; default: - throw new FormatException("Unsupported segment: " + segment); + throw new FormatException($"Unsupported segment: '{segment}'"); } } public override string Evaluate(RewriteContext context, MatchResults ruleMatch, MatchResults condMatch) { - switch (_portion) { + switch (_portion) + { case DateTimePortion.Year: return DateTimeOffset.UtcNow.Year.ToString(CultureInfo.InvariantCulture); case DateTimePortion.Month: @@ -67,7 +68,8 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.PatternSegments } } - private enum DateTimePortion { + private enum DateTimePortion + { Year, Month, Day, diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/HeaderSegment.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/HeaderSegment.cs index cd506c75d2..5327c969fb 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/HeaderSegment.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/HeaderSegment.cs @@ -6,7 +6,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.PatternSegments public class HeaderSegment : PatternSegment { private readonly string _header; - + public HeaderSegment(string header) { _header = header; diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/UrlEncodeSegment.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/UrlEncodeSegment.cs index 5bca22d5ff..e5ad2aac30 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/UrlEncodeSegment.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/UrlEncodeSegment.cs @@ -9,7 +9,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.PatternSegments public class UrlEncodeSegment : PatternSegment { private readonly Pattern _pattern; - + public UrlEncodeSegment(Pattern pattern) { _pattern = pattern; @@ -17,10 +17,14 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.PatternSegments public override string Evaluate(RewriteContext context, MatchResults ruleMatch, MatchResults condMatch) { - var tempBuilder = context.Builder; + var oldBuilder = context.Builder; + // PERF + // Because we need to be able to evaluate multiple nested patterns, + // we provided a new string builder and evaluate the new pattern, + // and restore it after evaluation. context.Builder = new StringBuilder(64); var pattern = _pattern.Evaluate(context, ruleMatch, condMatch); - context.Builder = tempBuilder; + context.Builder = oldBuilder; return UrlEncoder.Default.Encode(pattern); } } diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/PreActions/ChangeCookiePreAction.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/PreActions/ChangeCookiePreAction.cs index 13d2dd3ba9..a08506158f 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/PreActions/ChangeCookiePreAction.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/PreActions/ChangeCookiePreAction.cs @@ -17,7 +17,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.PreActions public override void ApplyAction(HttpContext context, MatchResults ruleMatch, MatchResults condMatch) { // modify the cookies - + } } } diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlAction.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlAction.cs index 8f2a8496c8..326d22b377 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlAction.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlAction.cs @@ -5,7 +5,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal { public abstract class UrlAction { - public Pattern Url { get; set; } + protected Pattern Url { get; set; } public abstract RuleResult ApplyAction(RewriteContext context, MatchResults ruleMatch, MatchResults condMatch); } } diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/RedirectAction.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/RedirectAction.cs index 98df716b27..f0cac6afb7 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/RedirectAction.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/RedirectAction.cs @@ -1,6 +1,7 @@ // 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; using Microsoft.AspNetCore.Http; using Microsoft.Net.Http.Headers; @@ -9,25 +10,33 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlActions public class RedirectAction : UrlAction { public int StatusCode { get; } - public RedirectAction(int statusCode, Pattern pattern) + public bool AppendQueryString { get; } + + public RedirectAction(int statusCode, Pattern pattern, bool appendQueryString) { StatusCode = statusCode; Url = pattern; + AppendQueryString = appendQueryString; } public override RuleResult ApplyAction(RewriteContext context, MatchResults ruleMatch, MatchResults condMatch) { - var pattern = Url.Evaluate(context, ruleMatch, condMatch); context.HttpContext.Response.StatusCode = StatusCode; + // TODO IIS guarantees that there will be a leading slash + if (pattern.IndexOf("://", StringComparison.Ordinal) == -1 && !pattern.StartsWith("/")) + { + pattern = '/' + pattern; + } + // url can either contain the full url or the path and query // always add to location header. // TODO check for false positives var split = pattern.IndexOf('?'); - if (split >= 0) + if (split >= 0 && AppendQueryString) { - var query = context.HttpContext.Request.QueryString.Add( + var query = context.HttpContext.Request.QueryString.Add( QueryString.FromUriComponent( pattern.Substring(split))); // not using the HttpContext.Response.redirect here because status codes may be 301, 302, 307, 308 diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/RedirectClearQueryAction.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/RedirectClearQueryAction.cs deleted file mode 100644 index ec51cf748c..0000000000 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/RedirectClearQueryAction.cs +++ /dev/null @@ -1,27 +0,0 @@ -// 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 Microsoft.Net.Http.Headers; - -namespace Microsoft.AspNetCore.Rewrite.Internal.UrlActions -{ - public class RedirectClearQueryAction : UrlAction - { - public int StatusCode { get; } - public RedirectClearQueryAction(int statusCode, Pattern pattern) - { - StatusCode = statusCode; - Url = pattern; - } - - public override RuleResult ApplyAction(RewriteContext context, MatchResults ruleMatch, MatchResults condMatch) - { - var pattern = Url.Evaluate(context, ruleMatch, condMatch); - context.HttpContext.Response.StatusCode = StatusCode; - - // we are clearing the query, so just put the pattern in the location header - context.HttpContext.Response.Headers[HeaderNames.Location] = pattern; - return RuleResult.ResponseComplete; - } - } -} diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/RewriteAction.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/RewriteAction.cs index eb8d59dda2..7c9cd06103 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/RewriteAction.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/RewriteAction.cs @@ -10,10 +10,10 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlActions public class RewriteAction : UrlAction { private readonly string ForwardSlash = "/"; - public RuleTerminiation Result { get; } + public RuleTermination Result { get; } public bool ClearQuery { get; } - public RewriteAction(RuleTerminiation result, Pattern pattern, bool clearQuery) + public RewriteAction(RuleTermination result, Pattern pattern, bool clearQuery) { Result = result; Url = pattern; @@ -28,8 +28,8 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlActions { context.HttpContext.Request.QueryString = QueryString.Empty; } - // TODO PERF, substrings, object creation, etc. - if (pattern.IndexOf("://") >= 0) + + if (pattern.IndexOf("://", StringComparison.Ordinal) >= 0) { string scheme; HostString host; diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlMatches/FileSizeMatch.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlMatches/FileSizeMatch.cs index d2d6397408..e798b0191c 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlMatches/FileSizeMatch.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlMatches/FileSizeMatch.cs @@ -12,7 +12,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlMatches public override MatchResults Evaluate(string input, RewriteContext context) { - var fileInfo = context.FileProvider.GetFileInfo(input); + var fileInfo = context.StaticFileProvider.GetFileInfo(input); return fileInfo.Exists && fileInfo.Length > 0 ? MatchResults.EmptySuccess : MatchResults.EmptyFailure; } } diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlMatches/IsDirectoryMatch.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlMatches/IsDirectoryMatch.cs index 113ff88e2e..b4361c5d31 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlMatches/IsDirectoryMatch.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlMatches/IsDirectoryMatch.cs @@ -6,13 +6,13 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlMatches public class IsDirectoryMatch : UrlMatch { public IsDirectoryMatch(bool negate) - { + { Negate = negate; } public override MatchResults Evaluate(string pattern, RewriteContext context) { - var res = context.FileProvider.GetFileInfo(pattern).IsDirectory; + var res = context.StaticFileProvider.GetFileInfo(pattern).IsDirectory; return new MatchResults { Success = (res != Negate) }; } } diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlMatches/IsFileMatch.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlMatches/IsFileMatch.cs index 6dc8d9ea0b..e4d4816133 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlMatches/IsFileMatch.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlMatches/IsFileMatch.cs @@ -4,7 +4,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlMatches { public class IsFileMatch : UrlMatch - { + { public IsFileMatch(bool negate) { Negate = negate; @@ -12,7 +12,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlMatches public override MatchResults Evaluate(string pattern, RewriteContext context) { - var res = context.FileProvider.GetFileInfo(pattern).Exists; + var res = context.StaticFileProvider.GetFileInfo(pattern).Exists; return new MatchResults { Success = (res != Negate) }; } } diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlMatches/RegexMatch.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlMatches/RegexMatch.cs index b869285b20..eb880c18ec 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlMatches/RegexMatch.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlMatches/RegexMatch.cs @@ -18,7 +18,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlMatches public override MatchResults Evaluate(string pattern, RewriteContext context) { var res = _match.Match(pattern); - return new MatchResults { BackReference = res.Groups, Success = (res.Success != Negate)}; + return new MatchResults { BackReference = res.Groups, Success = (res.Success != Negate) }; } } } diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/InputParser.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/InputParser.cs index 5fe5038eef..ada89f938d 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/InputParser.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/InputParser.cs @@ -3,7 +3,6 @@ using System; using System.Collections.Generic; -using Microsoft.AspNetCore.Rewrite.Internal; using Microsoft.AspNetCore.Rewrite.Internal.PatternSegments; namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite @@ -60,7 +59,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite return new Pattern(results); } - private static void ParseParameter(ParserContext context, List results) + private static void ParseParameter(ParserContext context, IList results) { context.Mark(); // Four main cases: @@ -82,7 +81,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite else if (context.Current == Colon) { parameter = context.Capture(); - + // Only 5 strings to expect here. Case sensitive. switch (parameter) { @@ -165,7 +164,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite return index; } - private static void ParseLiteral(ParserContext context, List results) + private static void ParseLiteral(ParserContext context, IList results) { context.Mark(); string literal; diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/ServerVariables.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/ServerVariables.cs index aa5845a872..8a0fad4150 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/ServerVariables.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/ServerVariables.cs @@ -2,7 +2,6 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; -using Microsoft.AspNetCore.Rewrite.Internal; using Microsoft.AspNetCore.Rewrite.Internal.PatternSegments; using Microsoft.Net.Http.Headers; @@ -12,7 +11,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite { public static PatternSegment FindServerVariable(string serverVariable) { - switch(serverVariable) + switch (serverVariable) { // TODO Add all server variables here. case "ALL_RAW": diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/FileParser.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/UrlRewriteFileParser.cs similarity index 97% rename from src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/FileParser.cs rename to src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/UrlRewriteFileParser.cs index 6e6cd6419d..9dcd7f4a4a 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/FileParser.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/UrlRewriteFileParser.cs @@ -10,11 +10,11 @@ using System.Xml.Linq; namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite { - public class FileParser + public class UrlRewriteFileParser { private readonly InputParser _inputParser = new InputParser(); - public List Parse(TextReader reader) + public IList Parse(TextReader reader) { var xmlDoc = XDocument.Load(reader, LoadOptions.SetLineInfo); var xmlRoot = xmlDoc.Descendants(RewriteTags.Rewrite).FirstOrDefault(); @@ -31,7 +31,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite return null; } - private void ParseRules(XElement rules, List result) + private void ParseRules(XElement rules, IList result) { if (rules == null) { diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/UrlRewriteRuleBuilder.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/UrlRewriteRuleBuilder.cs index 2dad4efcd0..90da1e57d9 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/UrlRewriteRuleBuilder.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/UrlRewriteRuleBuilder.cs @@ -13,12 +13,12 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite public class UrlRewriteRuleBuilder { private readonly TimeSpan RegexTimeout = TimeSpan.FromMilliseconds(1); - + public string Name { get; set; } public bool Enabled { get; set; } private UrlMatch _initialMatch; - private Conditions _conditions; + private IList _conditions; private UrlAction _action; private bool _matchAny; @@ -28,40 +28,28 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite { throw new InvalidOperationException("Cannot create UrlRewriteRule without action and match"); } - var rule = new UrlRewriteRule(); - rule.Action = _action; - rule.Conditions = _conditions; - rule.InitialMatch = _initialMatch; - rule.Name = Name; - return rule; + + return new UrlRewriteRule(Name, _initialMatch, _conditions, _action); } - - public void AddUrlAction(Pattern url, ActionType actionType = ActionType.None, bool appendQueryString = true, bool stopProcessing = false, int statusCode = StatusCodes.Status301MovedPermanently) + + public void AddUrlAction( + Pattern url, + ActionType actionType = ActionType.None, + bool appendQueryString = true, + bool stopProcessing = false, + int statusCode = StatusCodes.Status301MovedPermanently) { switch (actionType) { case ActionType.None: - _action = new VoidAction(stopProcessing ? RuleResult.StopRules : RuleResult.Continue); + _action = new VoidAction(stopProcessing ? RuleResult.StopRules : RuleResult.Continue); break; case ActionType.Rewrite: - if (appendQueryString) - { - _action = new RewriteAction(stopProcessing ? RuleTerminiation.StopRules : RuleTerminiation.Continue, url, clearQuery: false); - } - else - { - _action = new RewriteAction(stopProcessing ? RuleTerminiation.StopRules : RuleTerminiation.Continue, url, clearQuery: true); - } + _action = new RewriteAction(stopProcessing ? RuleTermination.StopRules : RuleTermination.Continue, + url, clearQuery: !appendQueryString); break; case ActionType.Redirect: - if (appendQueryString) - { - _action = new RedirectAction(statusCode, url); - } - else - { - _action = new RedirectClearQueryAction(statusCode, url); - } + _action = new RedirectAction(statusCode, url, appendQueryString); break; case ActionType.AbortRequest: throw new NotImplementedException("Abort Requests are not supported"); @@ -85,14 +73,14 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite else { var regex = new Regex(input, RegexOptions.CultureInvariant | RegexOptions.Compiled, RegexTimeout); - _initialMatch = new RegexMatch(regex, negate); + _initialMatch = new RegexMatch(regex, negate); } break; } case PatternSyntax.WildCard: throw new NotImplementedException("Wildcard syntax is not supported"); case PatternSyntax.ExactMatch: - _initialMatch = new ExactMatch(ignoreCase, input, negate); + _initialMatch = new ExactMatch(ignoreCase, input, negate); break; } } @@ -118,27 +106,23 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite throw new FormatException("Match does not have an associated pattern attribute in condition"); } - Regex regex = null; - if (ignoreCase) - { - regex = new Regex(pattern, RegexOptions.CultureInvariant | RegexOptions.Compiled | RegexOptions.IgnoreCase, RegexTimeout); - } - else - { - regex = new Regex(pattern, RegexOptions.CultureInvariant | RegexOptions.Compiled, RegexTimeout); - } - - _conditions.ConditionList.Add(new Condition { Input = input, Match = new RegexMatch(regex, negate), OrNext = _matchAny}); + var regex = new Regex( + pattern, + ignoreCase ? RegexOptions.CultureInvariant | RegexOptions.Compiled | RegexOptions.IgnoreCase : + RegexOptions.CultureInvariant | RegexOptions.Compiled, + RegexTimeout); + + _conditions.Add(new Condition { Input = input, Match = new RegexMatch(regex, negate), OrNext = _matchAny }); break; } case MatchType.IsDirectory: { - _conditions.ConditionList.Add(new Condition { Input = input, Match = new IsDirectoryMatch(negate), OrNext = _matchAny }); + _conditions.Add(new Condition { Input = input, Match = new IsDirectoryMatch(negate), OrNext = _matchAny }); break; } case MatchType.IsFile: { - _conditions.ConditionList.Add(new Condition { Input = input, Match = new IsFileMatch(negate), OrNext = _matchAny }); + _conditions.Add(new Condition { Input = input, Match = new IsFileMatch(negate), OrNext = _matchAny }); break; } default: @@ -153,7 +137,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite { throw new FormatException("Match does not have an associated pattern attribute in condition"); } - _conditions.ConditionList.Add(new Condition { Input = input, Match = new ExactMatch(ignoreCase, pattern, negate), OrNext = _matchAny }); + _conditions.Add(new Condition { Input = input, Match = new ExactMatch(ignoreCase, pattern, negate), OrNext = _matchAny }); break; default: throw new FormatException("Unrecognized pattern syntax"); @@ -162,10 +146,8 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite public void AddUrlConditions(LogicalGrouping logicalGrouping, bool trackingAllCaptures) { - var conditions = new Conditions(); - conditions.ConditionList = new List(); + _conditions = new List(); _matchAny = logicalGrouping == LogicalGrouping.MatchAny; - _conditions = conditions; } } } diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewriteRule.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewriteRule.cs index 736290b4fa..94a88763ff 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewriteRule.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewriteRule.cs @@ -1,28 +1,34 @@ // 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.Collections.Generic; using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Rewrite.Logging; namespace Microsoft.AspNetCore.Rewrite.Internal { public class UrlRewriteRule : Rule { - public string Name { get; set; } - public bool Enabled { get; set; } = true; - public UrlMatch InitialMatch { get; set; } - public Conditions Conditions { get; set; } - public UrlAction Action { get; set; } + public string Name { get; } + public UrlMatch InitialMatch { get; } + public IList Conditions { get; } + public UrlAction Action { get; } + + public UrlRewriteRule(string name, + UrlMatch initialMatch, + IList conditions, + UrlAction action) + { + Name = name; + InitialMatch = initialMatch; + Conditions = conditions; + Action = action; + } public override RuleResult ApplyRule(RewriteContext context) { - if (!Enabled) - { - return RuleResult.Continue; - } - // Due to the path string always having a leading slash, // remove it from the path before regex comparison - // TODO may need to check if there is a leading slash and remove conditionally var path = context.HttpContext.Request.Path; MatchResults initMatchResults; if (path == PathString.Empty) @@ -36,19 +42,22 @@ namespace Microsoft.AspNetCore.Rewrite.Internal if (!initMatchResults.Success) { + context.Logger?.UrlRewriteDidNotMatchRule(Name); return RuleResult.Continue; } MatchResults condMatchRes = null; if (Conditions != null) { - condMatchRes = Conditions.Evaluate(context, initMatchResults); + condMatchRes = ConditionHelper.Evaluate(Conditions, context, initMatchResults); if (!condMatchRes.Success) { + context.Logger?.UrlRewriteDidNotMatchRule(Name); return RuleResult.Continue; } } + context.Logger?.UrlRewriteMatchedRule(Name); // at this point we know the rule passed, evaluate the replacement. return Action.ApplyAction(context, initMatchResults, condMatchRes); } diff --git a/src/Microsoft.AspNetCore.Rewrite/Logging/RewriteMiddlewareLoggingExtensions.cs b/src/Microsoft.AspNetCore.Rewrite/Logging/RewriteMiddlewareLoggingExtensions.cs new file mode 100644 index 0000000000..0d32fe6cfa --- /dev/null +++ b/src/Microsoft.AspNetCore.Rewrite/Logging/RewriteMiddlewareLoggingExtensions.cs @@ -0,0 +1,88 @@ +// 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; +using Microsoft.Extensions.Logging; + +namespace Microsoft.AspNetCore.Rewrite.Logging +{ + internal static class RewriteMiddlewareLoggingExtensions + { + private static readonly Action _requestContinueResults; + private static readonly Action _requestResponseComplete; + private static readonly Action _requestStopRules; + private static readonly Action _urlRewriteDidNotMatchRule; + private static readonly Action _urlRewriteMatchedRule; + private static readonly Action _modRewriteDidNotMatchRule; + private static readonly Action _modRewriteMatchedRule; + + static RewriteMiddlewareLoggingExtensions() + { + _requestContinueResults = LoggerMessage.Define( + LogLevel.Debug, + 1, + "Request is continuing in applying rules."); + _requestResponseComplete = LoggerMessage.Define( + LogLevel.Debug, + 2, + "Request is done processing, Location header '{Location}' with status code '{StatusCode}'."); + _requestStopRules = LoggerMessage.Define( + LogLevel.Debug, + 3, + "Request is done applying rules."); + _urlRewriteDidNotMatchRule = LoggerMessage.Define( + LogLevel.Debug, + 4, + "Request did not match current rule '{Name}'."); + + _urlRewriteMatchedRule = LoggerMessage.Define( + LogLevel.Debug, + 5, + "Request matched current UrlRewriteRule '{Name}'."); + + _modRewriteDidNotMatchRule = LoggerMessage.Define( + LogLevel.Debug, + 6, + "Request matched current ModRewriteRule."); + + _modRewriteMatchedRule = LoggerMessage.Define( + LogLevel.Debug, + 7, + "Request matched current ModRewriteRule."); + } + + public static void RewriteMiddlewareRequestContinueResults(this ILogger logger) + { + _requestContinueResults(logger, null); + } + + public static void RewriteMiddlewareRequestResponseComplete(this ILogger logger, string location, int statusCode) + { + _requestResponseComplete(logger, location, statusCode, null); + } + + public static void RewriteMiddlewareRequestStopRules(this ILogger logger) + { + _requestStopRules(logger, null); + } + + public static void UrlRewriteDidNotMatchRule(this ILogger logger, string name) + { + _urlRewriteDidNotMatchRule(logger, name, null); + } + + public static void UrlRewriteMatchedRule(this ILogger logger, string name) + { + _urlRewriteMatchedRule(logger, name, null); + } + + public static void ModRewriteDidNotMatchRule(this ILogger logger) + { + _modRewriteDidNotMatchRule(logger, null); + } + public static void ModRewriteMatchedRule(this ILogger logger) + { + _modRewriteMatchedRule(logger, null); + } + } +} diff --git a/src/Microsoft.AspNetCore.Rewrite/ModRewriteExtensions.cs b/src/Microsoft.AspNetCore.Rewrite/ModRewriteOptionsExtensions.cs similarity index 55% rename from src/Microsoft.AspNetCore.Rewrite/ModRewriteExtensions.cs rename to src/Microsoft.AspNetCore.Rewrite/ModRewriteOptionsExtensions.cs index 77dc019956..1ad897b90e 100644 --- a/src/Microsoft.AspNetCore.Rewrite/ModRewriteExtensions.cs +++ b/src/Microsoft.AspNetCore.Rewrite/ModRewriteOptionsExtensions.cs @@ -8,24 +8,24 @@ using Microsoft.AspNetCore.Rewrite.Internal.ModRewrite; namespace Microsoft.AspNetCore.Rewrite { - public static class ModRewriteExtensions + public static class ModRewriteOptionsExtensions { /// /// Imports rules from a mod_rewrite file and adds the rules to current rules. /// - /// The UrlRewrite options. - /// + /// The Rewrite options. + /// The Hosting Environment /// The path to the file containing mod_rewrite rules. - public static RewriteOptions ImportFromModRewrite(this RewriteOptions options, IHostingEnvironment hostingEnv, string filePath) + public static RewriteOptions ImportFromModRewrite(this RewriteOptions options, IHostingEnvironment hostingEnvironment, string filePath) { if (options == null) { throw new ArgumentNullException(nameof(options)); } - if (hostingEnv == null) + if (hostingEnvironment == null) { - throw new ArgumentNullException(nameof(hostingEnv)); + throw new ArgumentNullException(nameof(hostingEnvironment)); } if (string.IsNullOrEmpty(filePath)) @@ -33,18 +33,17 @@ namespace Microsoft.AspNetCore.Rewrite throw new ArgumentException(nameof(filePath)); } - var path = Path.Combine(hostingEnv.ContentRootPath, filePath); + var path = Path.Combine(hostingEnvironment.ContentRootPath, filePath); using (var stream = File.OpenRead(path)) { - options.Rules.AddRange(new FileParser().Parse(new StreamReader(stream))); - }; - return options; + return options.ImportFromModRewrite(new StreamReader(stream)); + } } /// /// Imports rules from a mod_rewrite file and adds the rules to current rules. /// - /// The UrlRewrite options. + /// The Rewrite options. /// Text reader containing a stream of mod_rewrite rules. public static RewriteOptions ImportFromModRewrite(this RewriteOptions options, TextReader reader) { @@ -52,37 +51,19 @@ namespace Microsoft.AspNetCore.Rewrite { throw new ArgumentNullException(nameof(options)); } - + if (reader == null) { throw new ArgumentNullException(nameof(reader)); } - options.Rules.AddRange(new FileParser().Parse(reader)); + var rules = new FileParser().Parse(reader); + + foreach (var rule in rules) + { + options.Rules.Add(rule); + } return options; } - /// - /// Adds a mod_rewrite rule to the current rules. - /// - /// The UrlRewrite options. - /// The literal string of a mod_rewrite rule: - /// "RewriteRule Pattern Substitution [Flags]" - public static RewriteOptions AddModRewriteRule(this RewriteOptions options, string rule) - { - if (options == null) - { - throw new ArgumentNullException(nameof(options)); - } - - if (rule == null) - { - throw new ArgumentNullException(nameof(rule)); - } - - var builder = new RuleBuilder(); - builder.AddRule(rule); - options.Rules.Add(builder.Build()); - return options; - } } } diff --git a/src/Microsoft.AspNetCore.Rewrite/RewriteExtensions.cs b/src/Microsoft.AspNetCore.Rewrite/RewriteBuilderExtensions.cs similarity index 90% rename from src/Microsoft.AspNetCore.Rewrite/RewriteExtensions.cs rename to src/Microsoft.AspNetCore.Rewrite/RewriteBuilderExtensions.cs index 50026ddc83..88d7676c30 100644 --- a/src/Microsoft.AspNetCore.Rewrite/RewriteExtensions.cs +++ b/src/Microsoft.AspNetCore.Rewrite/RewriteBuilderExtensions.cs @@ -9,13 +9,13 @@ namespace Microsoft.AspNetCore.Builder /// /// Extension methods for the /// - public static class RewriteExtensions + public static class RewriteBuilderExtensions { /// /// Checks if a given Url matches rules and conditions, and modifies the HttpContext on match. /// /// - /// Options for urlrewrite. + /// Options for rewrite. /// public static IApplicationBuilder UseRewriter(this IApplicationBuilder app, RewriteOptions options) { diff --git a/src/Microsoft.AspNetCore.Rewrite/RewriteContext.cs b/src/Microsoft.AspNetCore.Rewrite/RewriteContext.cs index be7108787d..4b4fb8e8db 100644 --- a/src/Microsoft.AspNetCore.Rewrite/RewriteContext.cs +++ b/src/Microsoft.AspNetCore.Rewrite/RewriteContext.cs @@ -4,16 +4,19 @@ using System.Text; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.FileProviders; +using Microsoft.Extensions.Logging; namespace Microsoft.AspNetCore.Rewrite { /// - /// The UrlRewrite Context contains the HttpContext of the request and the file provider to check conditions. + /// The UrlRewrite Context contains the HttpContext of the request, the file provider, and the logger. + /// There is also a shared string builder across the application of rules. /// public class RewriteContext { public HttpContext HttpContext { get; set; } - public IFileProvider FileProvider { get; set; } + public IFileProvider StaticFileProvider { get; set; } + public ILogger Logger { get; set; } // PERF: share the same string builder per request internal StringBuilder Builder { get; set; } = new StringBuilder(64); } diff --git a/src/Microsoft.AspNetCore.Rewrite/RewriteMiddleware.cs b/src/Microsoft.AspNetCore.Rewrite/RewriteMiddleware.cs index 61c332b7c6..afcbcb576f 100644 --- a/src/Microsoft.AspNetCore.Rewrite/RewriteMiddleware.cs +++ b/src/Microsoft.AspNetCore.Rewrite/RewriteMiddleware.cs @@ -6,7 +6,10 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Rewrite.Internal; +using Microsoft.AspNetCore.Rewrite.Logging; using Microsoft.Extensions.FileProviders; +using Microsoft.Extensions.Logging; +using Microsoft.Net.Http.Headers; namespace Microsoft.AspNetCore.Rewrite { @@ -20,14 +23,20 @@ namespace Microsoft.AspNetCore.Rewrite private readonly RequestDelegate _next; private readonly RewriteOptions _options; private readonly IFileProvider _fileProvider; + private readonly ILogger _logger; /// /// Creates a new instance of /// /// The delegate representing the next middleware in the request pipeline. - /// The Hosting Environment. + /// The Hosting Environment. + /// The Logger Factory. /// The middleware options, containing the rules to apply. - public RewriteMiddleware(RequestDelegate next, IHostingEnvironment hostingEnv, RewriteOptions options) + public RewriteMiddleware( + RequestDelegate next, + IHostingEnvironment hostingEnvironment, + ILoggerFactory loggerFactory, + RewriteOptions options) { if (next == null) { @@ -41,7 +50,8 @@ namespace Microsoft.AspNetCore.Rewrite _next = next; _options = options; - _fileProvider = _options.FileProvider ?? hostingEnv.WebRootFileProvider; + _fileProvider = _options.StaticFileProvider ?? hostingEnvironment.WebRootFileProvider; + _logger = loggerFactory.CreateLogger(); } /// @@ -55,19 +65,27 @@ namespace Microsoft.AspNetCore.Rewrite { throw new ArgumentNullException(nameof(context)); } - var urlContext = new RewriteContext { HttpContext = context, FileProvider = _fileProvider }; + var urlContext = new RewriteContext { + HttpContext = context, + StaticFileProvider = _fileProvider, + Logger = _logger + }; + foreach (var rule in _options.Rules) { - // Apply the rule var result = rule.ApplyRule(urlContext); switch (result.Result) { - case RuleTerminiation.Continue: - // Explicitly show that we continue executing rules + case RuleTermination.Continue: + _logger.RewriteMiddlewareRequestContinueResults(); break; - case RuleTerminiation.ResponseComplete: + case RuleTermination.ResponseComplete: + _logger.RewriteMiddlewareRequestResponseComplete( + urlContext.HttpContext.Response.Headers[HeaderNames.Location], + urlContext.HttpContext.Response.StatusCode); return CompletedTask; - case RuleTerminiation.StopRules: + case RuleTermination.StopRules: + _logger.RewriteMiddlewareRequestStopRules(); return _next(context); default: throw new ArgumentOutOfRangeException($"Invalid rule termination {result}"); diff --git a/src/Microsoft.AspNetCore.Rewrite/RewriteOptions.cs b/src/Microsoft.AspNetCore.Rewrite/RewriteOptions.cs index 71eb2fef99..270c7a9313 100644 --- a/src/Microsoft.AspNetCore.Rewrite/RewriteOptions.cs +++ b/src/Microsoft.AspNetCore.Rewrite/RewriteOptions.cs @@ -2,7 +2,6 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System.Collections.Generic; -using Microsoft.AspNetCore.Rewrite.Internal; using Microsoft.Extensions.FileProviders; namespace Microsoft.AspNetCore.Rewrite @@ -12,10 +11,8 @@ namespace Microsoft.AspNetCore.Rewrite /// public class RewriteOptions { - /// - /// The ordered list of rules to apply to the context. - /// - public List Rules { get; set; } = new List(); - public IFileProvider FileProvider { get; set; } + // TODO doc comments + public IList Rules { get; } = new List(); + public IFileProvider StaticFileProvider { get; set; } } } diff --git a/src/Microsoft.AspNetCore.Rewrite/RewriteOptionsExtensions.cs b/src/Microsoft.AspNetCore.Rewrite/RewriteOptionsExtensions.cs new file mode 100644 index 0000000000..0861fa50f1 --- /dev/null +++ b/src/Microsoft.AspNetCore.Rewrite/RewriteOptionsExtensions.cs @@ -0,0 +1,135 @@ +// 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; +using Microsoft.AspNetCore.Rewrite.Internal; +using Microsoft.AspNetCore.Rewrite.Internal.CodeRules; +using Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite; + +namespace Microsoft.AspNetCore.Rewrite +{ + /// + /// The builder to a list of rules for and + /// + public static class RewriteOptionsExtensions + { + /// + /// Adds a rule to the current rules. + /// + /// The UrlRewrite options. + /// A rule to be added to the current rules. + /// The Rewrite options. + public static RewriteOptions Add(this RewriteOptions options, Rule rule) + { + options.Rules.Add(rule); + return options; + } + + /// + /// Adds a rule to the current rules. + /// + /// The Rewrite options. + /// A Func that checks and applies the rule. + /// + public static RewriteOptions Add(this RewriteOptions options, Func applyRule) + { + options.Rules.Add(new DelegateRule(applyRule)); + return options; + } + + /// + /// Rewrites the path if the regex matches the HttpContext's PathString + /// + /// The Rewrite options. + /// The regex string to compare with. + /// If the regex matches, what to replace HttpContext with. + /// The Rewrite options. + public static RewriteOptions Rewrite(this RewriteOptions options, string regex, string urlPattern) + { + return Rewrite(options, regex, urlPattern, stopProcessing: false); + } + + /// + /// Rewrites the path if the regex matches the HttpContext's PathString + /// + /// The Rewrite options. + /// The regex string to compare with. + /// If the regex matches, what to replace the uri with. + /// If the regex matches, conditionally stop processing other rules. + /// The Rewrite options. + public static RewriteOptions Rewrite(this RewriteOptions options, string regex, string urlPattern, bool stopProcessing) + { + var builder = new UrlRewriteRuleBuilder(); + var pattern = new InputParser().ParseInputString(urlPattern); + + builder.AddUrlMatch(regex); + builder.AddUrlAction(pattern, actionType: ActionType.Rewrite, stopProcessing: stopProcessing); + options.Rules.Add(builder.Build()); + return options; + } + + /// + /// Redirect the request if the regex matches the HttpContext's PathString + /// + /// The Rewrite options. + /// The regex string to compare with. + /// If the regex matches, what to replace the uri with. + /// The Rewrite options. + public static RewriteOptions Redirect(this RewriteOptions options, string regex, string urlPattern) + { + return Redirect(options, regex, urlPattern, statusCode: 302); + } + + /// + /// Redirect the request if the regex matches the HttpContext's PathString + /// + /// The Rewrite options. + /// The regex string to compare with. + /// If the regex matches, what to replace the uri with. + /// The status code to add to the response. + /// The Rewrite options. + public static RewriteOptions Redirect(this RewriteOptions options, string regex, string urlPattern, int statusCode) + { + var builder = new UrlRewriteRuleBuilder(); + var pattern = new InputParser().ParseInputString(urlPattern); + + builder.AddUrlMatch(regex); + builder.AddUrlAction(pattern, actionType: ActionType.Redirect, stopProcessing: false); + options.Rules.Add(builder.Build()); + return options; + } + + // TODO 301 overload + + /// + /// Redirect a request to https if the incoming request is http + /// + /// The Rewrite options. + public static RewriteOptions RedirectToHttps(this RewriteOptions options) + { + return RedirectToHttps(options, statusCode: 302, sslPort: null); + } + + /// + /// Redirect a request to https if the incoming request is http + /// + /// The Rewrite options. + /// The status code to add to the response. + public static RewriteOptions RedirectToHttps(this RewriteOptions options, int statusCode) + { + return RedirectToHttps(options, statusCode, sslPort: null); + } + + /// + /// Redirect a request to https if the incoming request is http + /// + /// The Rewrite options. + /// The status code to add to the response. + /// The SSL port to add to the response. + public static RewriteOptions RedirectToHttps(this RewriteOptions options, int statusCode, int? sslPort) + { + options.Rules.Add(new RedirectToHttpsRule { StatusCode = statusCode, SSLPort = sslPort }); + return options; + } + } +} diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/Rule.cs b/src/Microsoft.AspNetCore.Rewrite/Rule.cs similarity index 78% rename from src/Microsoft.AspNetCore.Rewrite/Internal/Rule.cs rename to src/Microsoft.AspNetCore.Rewrite/Rule.cs index 3ba6067f42..82a70dabc5 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/Rule.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Rule.cs @@ -1,8 +1,9 @@ // 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. -namespace Microsoft.AspNetCore.Rewrite.Internal +namespace Microsoft.AspNetCore.Rewrite { + // make this public and doc comements public abstract class Rule { public abstract RuleResult ApplyRule(RewriteContext context); diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/RuleResult.cs b/src/Microsoft.AspNetCore.Rewrite/RuleResult.cs similarity index 64% rename from src/Microsoft.AspNetCore.Rewrite/Internal/RuleResult.cs rename to src/Microsoft.AspNetCore.Rewrite/RuleResult.cs index f7b6c2b45b..2b2bb4abf3 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/RuleResult.cs +++ b/src/Microsoft.AspNetCore.Rewrite/RuleResult.cs @@ -1,14 +1,14 @@ // 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. -namespace Microsoft.AspNetCore.Rewrite.Internal +namespace Microsoft.AspNetCore.Rewrite { public class RuleResult { - public static RuleResult Continue = new RuleResult { Result = RuleTerminiation.Continue }; - public static RuleResult ResponseComplete = new RuleResult { Result = RuleTerminiation.ResponseComplete }; - public static RuleResult StopRules = new RuleResult { Result = RuleTerminiation.StopRules }; + public static RuleResult Continue = new RuleResult { Result = RuleTermination.Continue }; + public static RuleResult ResponseComplete = new RuleResult { Result = RuleTermination.ResponseComplete }; + public static RuleResult StopRules = new RuleResult { Result = RuleTermination.StopRules }; - public RuleTerminiation Result { get; set; } + public RuleTermination Result { get; set; } } } diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/RuleTermination.cs b/src/Microsoft.AspNetCore.Rewrite/RuleTermination.cs similarity index 75% rename from src/Microsoft.AspNetCore.Rewrite/Internal/RuleTermination.cs rename to src/Microsoft.AspNetCore.Rewrite/RuleTermination.cs index 449a422944..dff816d9cc 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/RuleTermination.cs +++ b/src/Microsoft.AspNetCore.Rewrite/RuleTermination.cs @@ -1,9 +1,9 @@ // 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. -namespace Microsoft.AspNetCore.Rewrite.Internal +namespace Microsoft.AspNetCore.Rewrite { - public enum RuleTerminiation + public enum RuleTermination { Continue, ResponseComplete, diff --git a/src/Microsoft.AspNetCore.Rewrite/UrlRewriteExtensions.cs b/src/Microsoft.AspNetCore.Rewrite/UrlRewriteOptionsExtensions.cs similarity index 68% rename from src/Microsoft.AspNetCore.Rewrite/UrlRewriteExtensions.cs rename to src/Microsoft.AspNetCore.Rewrite/UrlRewriteOptionsExtensions.cs index fb362718a5..1ca090fdbe 100644 --- a/src/Microsoft.AspNetCore.Rewrite/UrlRewriteExtensions.cs +++ b/src/Microsoft.AspNetCore.Rewrite/UrlRewriteOptionsExtensions.cs @@ -8,24 +8,24 @@ using Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite; namespace Microsoft.AspNetCore.Rewrite { - public static class UrlRewriteExtensions + public static class UrlRewriteOptionsExtensions { /// /// Imports rules from a mod_rewrite file and adds the rules to current rules. /// /// The UrlRewrite options. - /// + /// /// The path to the file containing urlrewrite rules. - public static RewriteOptions ImportFromUrlRewrite(this RewriteOptions options, IHostingEnvironment hostingEnv, string filePath) + public static RewriteOptions ImportFromUrlRewrite(this RewriteOptions options, IHostingEnvironment hostingEnvironment, string filePath) { if (options == null) { throw new ArgumentNullException(nameof(options)); } - if (hostingEnv == null) + if (hostingEnvironment == null) { - throw new ArgumentNullException(nameof(hostingEnv)); + throw new ArgumentNullException(nameof(hostingEnvironment)); } if (string.IsNullOrEmpty(filePath)) @@ -33,35 +33,36 @@ namespace Microsoft.AspNetCore.Rewrite throw new ArgumentException(nameof(filePath)); } - var path = Path.Combine(hostingEnv.ContentRootPath, filePath); + var path = Path.Combine(hostingEnvironment.ContentRootPath, filePath); using (var stream = File.OpenRead(path)) { - options.Rules.AddRange(new FileParser().Parse(new StreamReader(stream))); - }; - return options; + return ImportFromUrlRewrite(options, new StreamReader(stream)); + } } /// /// Imports rules from a mod_rewrite file and adds the rules to current rules. /// /// The UrlRewrite options. - /// The text reader stream. - public static RewriteOptions ImportFromUrlRewrite(this RewriteOptions options, TextReader stream) + /// The text reader stream. + public static RewriteOptions ImportFromUrlRewrite(this RewriteOptions options, TextReader reader) { if (options == null) { throw new ArgumentNullException(nameof(options)); } - if (stream == null) + if (reader == null) { - throw new ArgumentException(nameof(stream)); + throw new ArgumentException(nameof(reader)); } - using (stream) + var rules = new UrlRewriteFileParser().Parse(reader); + + foreach (var rule in rules) { - options.Rules.AddRange(new FileParser().Parse(stream)); - }; + options.Rules.Add(rule); + } return options; } } diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/CodeRules/MiddlewareTests.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/CodeRules/MiddlewareTests.cs index 1f08becb6c..ce73843067 100644 --- a/test/Microsoft.AspNetCore.Rewrite.Tests/CodeRules/MiddlewareTests.cs +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/CodeRules/MiddlewareTests.cs @@ -16,7 +16,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.CodeRules [Fact] public async Task CheckRewritePath() { - var options = new RewriteOptions().RewriteRule("(.*)", "http://example.com/{R:1}"); + var options = new RewriteOptions().Rewrite("(.*)", "http://example.com/{R:1}"); var builder = new WebHostBuilder() .Configure(app => { @@ -39,7 +39,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.CodeRules [Fact] public async Task CheckRedirectPath() { - var options = new RewriteOptions().RedirectRule("(.*)","http://example.com/{R:1}", statusCode: 301); + var options = new RewriteOptions().Redirect("(.*)","http://example.com/{R:1}", statusCode: 301); var builder = new WebHostBuilder() .Configure(app => { @@ -52,25 +52,6 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.CodeRules Assert.Equal(response.Headers.Location.OriginalString, "http://example.com/foo"); } - [Fact] - public async Task CheckRewriteToHttps() - { - var options = new RewriteOptions().RewriteToHttps(); - var builder = new WebHostBuilder() - .Configure(app => - { - app.UseRewriter(options); - app.UseRewriter(options); - app.Run(context => context.Response.WriteAsync( - context.Request.Scheme)); - }); - var server = new TestServer(builder); - - var response = await server.CreateClient().GetStringAsync(new Uri("http://example.com")); - - Assert.Equal(response, "https"); - } - [Fact] public async Task CheckRedirectToHttps() { diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/ModRewrite/ModRewriteMiddlewareTest.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/ModRewrite/ModRewriteMiddlewareTest.cs index 62903412d5..7b358c265f 100644 --- a/test/Microsoft.AspNetCore.Rewrite.Tests/ModRewrite/ModRewriteMiddlewareTest.cs +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/ModRewrite/ModRewriteMiddlewareTest.cs @@ -17,7 +17,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.ModRewrite [Fact] public async Task Invoke_RewritePathWhenMatching() { - var options = new RewriteOptions().AddModRewriteRule("RewriteRule /hey/(.*) /$1 "); + var options = new RewriteOptions().ImportFromModRewrite(new StringReader("RewriteRule /hey/(.*) /$1 ")); var builder = new WebHostBuilder() .Configure(app => { @@ -34,8 +34,8 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.ModRewrite [Fact] public async Task Invoke_RewritePathTerminatesOnFirstSuccessOfRule() { - var options = new RewriteOptions().AddModRewriteRule("RewriteRule /hey/(.*) /$1 [L]") - .AddModRewriteRule("RewriteRule /hello /what"); + var options = new RewriteOptions().ImportFromModRewrite(new StringReader("RewriteRule /hey/(.*) /$1 [L]")) + .ImportFromModRewrite(new StringReader("RewriteRule /hello /what")); var builder = new WebHostBuilder() .Configure(app => { @@ -52,8 +52,8 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.ModRewrite [Fact] public async Task Invoke_RewritePathDoesNotTerminateOnFirstSuccessOfRule() { - var options = new RewriteOptions().AddModRewriteRule("RewriteRule /hey/(.*) /$1") - .AddModRewriteRule("RewriteRule /hello /what"); + var options = new RewriteOptions().ImportFromModRewrite(new StringReader("RewriteRule /hey/(.*) /$1")) + .ImportFromModRewrite(new StringReader("RewriteRule /hello /what")); var builder = new WebHostBuilder() .Configure(app => { diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/ModRewrite/TestStringParserTests.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/ModRewrite/TestStringParserTests.cs index a362137d10..b07dcdd7c6 100644 --- a/test/Microsoft.AspNetCore.Rewrite.Tests/ModRewrite/TestStringParserTests.cs +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/ModRewrite/TestStringParserTests.cs @@ -8,7 +8,7 @@ using Microsoft.AspNetCore.Rewrite.Internal.ModRewrite; using Microsoft.AspNetCore.Rewrite.Internal.PatternSegments; using Xunit; -namespace Microsoft.AspNetCore.Rewrite +namespace Microsoft.AspNetCore.Rewrite.Tests.ModRewrite { public class TestStringParserTests { @@ -119,7 +119,7 @@ namespace Microsoft.AspNetCore.Rewrite [InlineData(@"%a", "Cannot parse '%a' to integer at string index: '1'")] // invalid character after % [InlineData(@"$a", "Cannot parse '$a' to integer at string index: '1'")] // invalid character after $ [InlineData(@"%{asdf", "Missing close brace for parameter at string index: '6'")] // no closing } with characters - public void ConditionParser_Bad(string testString, string expected) + public void ConditionParser_InvalidInput(string testString, string expected) { var ex = Assert.Throws(() => new TestStringParser().Parse(testString)); Assert.Equal(ex.Message, expected); diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/PatternSegments/ConditionMatchSegmentTests.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/PatternSegments/ConditionMatchSegmentTests.cs new file mode 100644 index 0000000000..51208cbba5 --- /dev/null +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/PatternSegments/ConditionMatchSegmentTests.cs @@ -0,0 +1,37 @@ +// 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.Text.RegularExpressions; +using Microsoft.AspNetCore.Rewrite.Internal; +using Microsoft.AspNetCore.Rewrite.Internal.PatternSegments; +using Xunit; + +namespace Microsoft.AspNetCore.Rewrite.Tests.PatternSegments +{ + public class ConditionMatchSegmentTests + { + + [Theory] + [InlineData(1, "foo")] + [InlineData(2, "bar")] + [InlineData(3, "baz")] + public void ConditionMatch_AssertBackreferencesObtainsCorrectValue(int index, string expected) + { + // Arrange + var condMatch = CreateTestMatch(); + var segment = new ConditionMatchSegment(index); + + // Act + var results = segment.Evaluate(null, null, condMatch); + + // Assert + Assert.Equal(expected, results); + } + + private static MatchResults CreateTestMatch() + { + var match = Regex.Match("foo/bar/baz", "(.*)/(.*)/(.*)"); + return new MatchResults {BackReference = match.Groups, Success = match.Success}; + } + } +} diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/PatternSegments/DateTimeSegmentTests.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/PatternSegments/DateTimeSegmentTests.cs new file mode 100644 index 0000000000..9e478da8e4 --- /dev/null +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/PatternSegments/DateTimeSegmentTests.cs @@ -0,0 +1,44 @@ +// 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; +using Microsoft.AspNetCore.Rewrite.Internal.PatternSegments; +using Xunit; + +namespace Microsoft.AspNetCore.Rewrite.Tests.PatternSegments +{ + public class DateTimeSegmentTests + { + [Theory] + [InlineData("TIME_YEAR")] + [InlineData("TIME_MON")] + [InlineData("TIME_DAY")] + [InlineData("TIME_HOUR")] + [InlineData("TIME_MIN")] + [InlineData("TIME_SEC")] + [InlineData("TIME_WDAY")] + [InlineData("TIME")] + public void DateTime_AssertDoesntThrowOnCheckOfSegment(string input) + { + // Arrange + var segment = new DateTimeSegment(input); + + // Act + var results = segment.Evaluate(null, null, null); + + // TODO testing dates is hard, could use moq + // currently just assert that the segment doesn't throw. + } + + [Theory] + [InlineData("foo", "Unsupported segment: 'foo'")] + [InlineData("wow", "Unsupported segment: 'wow'")] + public void DateTime_AssertThrowsOnInvalidInput(string input, string expected) + { + + // Act And Assert + var ex = Assert.Throws(() => new DateTimeSegment(input)); + Assert.Equal(ex.Message, expected); + } + } +} diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/PatternSegments/HeaderSegmentTests.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/PatternSegments/HeaderSegmentTests.cs new file mode 100644 index 0000000000..b8472929b7 --- /dev/null +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/PatternSegments/HeaderSegmentTests.cs @@ -0,0 +1,43 @@ +// 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 Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Rewrite.Internal.PatternSegments; +using Microsoft.Net.Http.Headers; +using Xunit; + +namespace Microsoft.AspNetCore.Rewrite.Tests.PatternSegments +{ + public class HeaderSegmentTests + { + [Fact] + public void HeaderSegment_AssertGettingWithHeaderReturnsCorrectValue() + { + // Arrange + var context = new RewriteContext { HttpContext = new DefaultHttpContext() }; + + context.HttpContext.Request.Headers[HeaderNames.Location] = "foo"; + var segment = new HeaderSegment(HeaderNames.Location); + + // Act + var results = segment.Evaluate(context, null, null); + + // Assert + Assert.Equal("foo", results); + } + + [Fact] + public void HeaderSegment_AssertGettingANonExistantHeaderReturnsNull() + { + // Arrange + var context = new RewriteContext { HttpContext = new DefaultHttpContext() }; + var segment = new HeaderSegment(HeaderNames.Location); + + // Act + var results = segment.Evaluate(context, null, null); + + // Assert + Assert.Null(results); + } + } +} diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/PatternSegments/IsHttpsModSegmentTests.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/PatternSegments/IsHttpsModSegmentTests.cs new file mode 100644 index 0000000000..323f3198b4 --- /dev/null +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/PatternSegments/IsHttpsModSegmentTests.cs @@ -0,0 +1,30 @@ +// 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 Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Rewrite.Internal.PatternSegments; +using Xunit; + +namespace Microsoft.AspNetCore.Rewrite.Tests.PatternSegments +{ + public class IsHttpsModSegmentTests + { + [Theory] + [InlineData("http", "off")] + [InlineData("https", "on")] + public void IsHttps_AssertCorrectBehaviorWhenProvidedHttpContext(string input, string expected) + { + // Arrange + var segement = new IsHttpsModSegment(); + var context = new RewriteContext { HttpContext = new DefaultHttpContext() }; + context.HttpContext.Request.Scheme = input; + + // Act + var results = segement.Evaluate(context, null, null); + + // Assert + Assert.Equal(expected, results); + } + } +} diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/PatternSegments/IsHttpsSegmentTests.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/PatternSegments/IsHttpsSegmentTests.cs new file mode 100644 index 0000000000..c3d3b6eccc --- /dev/null +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/PatternSegments/IsHttpsSegmentTests.cs @@ -0,0 +1,30 @@ +// 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 Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Rewrite.Internal.PatternSegments; +using Xunit; + +namespace Microsoft.AspNetCore.Rewrite.Tests.PatternSegments +{ + public class IsHttpsSegmentTests + { + [Theory] + [InlineData("http", "OFF")] + [InlineData("https", "ON")] + public void IsHttps_AssertCorrectBehaviorWhenProvidedHttpContext(string input, string expected) + { + // Arrange + var segement = new IsHttpsSegment(); + var context = new RewriteContext { HttpContext = new DefaultHttpContext() }; + context.HttpContext.Request.Scheme = input; + + // Act + var results = segement.Evaluate(context, null, null); + + // Assert + Assert.Equal(expected, results); + } + } +} diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/PatternSegments/IsIPV6SegmentTests.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/PatternSegments/IsIPV6SegmentTests.cs new file mode 100644 index 0000000000..c787998e9c --- /dev/null +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/PatternSegments/IsIPV6SegmentTests.cs @@ -0,0 +1,59 @@ +// 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.AspNetCore.Http; +using Microsoft.AspNetCore.Rewrite.Internal.PatternSegments; +using Xunit; + +namespace Microsoft.AspNetCore.Rewrite.Tests.PatternSegments +{ + public class IsIPV6SegmentTests + { + [Fact] + public void IsIPv6_AssertNullRemoteIpAddressReportsCorrectValue() + { + // Arrange + var segement = new IsIPV6Segment(); + var context = new RewriteContext { HttpContext = new DefaultHttpContext() }; + context.HttpContext.Connection.RemoteIpAddress = null; + + // Act + var results = segement.Evaluate(context, null, null); + + // Assert + Assert.Equal("off", results); + } + + [Fact] + public void IsIPv6_AssertCorrectBehaviorWhenIPv6IsUsed() + { + // Arrange + var segement = new IsIPV6Segment(); + var context = new RewriteContext { HttpContext = new DefaultHttpContext() }; + context.HttpContext.Connection.RemoteIpAddress = IPAddress.Parse("2001:0db8:85a3:0000:0000:8a2e:0370:7334"); + + // Act + var results = segement.Evaluate(context, null, null); + + // Assert + Assert.Equal("on", results); + } + + [Fact] + public void IsIPv6_AssertCorrectBehaviorWhenIPv4IsUsed() + { + // Arrange + var segement = new IsIPV6Segment(); + var context = new RewriteContext { HttpContext = new DefaultHttpContext() }; + context.HttpContext.Connection.RemoteIpAddress = IPAddress.Parse("20.30.40.50"); + + // Act + var results = segement.Evaluate(context, null, null); + + // Assert + Assert.Equal("off", results); + } + } +} diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/PatternSegments/LIteralSegmentTests.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/PatternSegments/LIteralSegmentTests.cs new file mode 100644 index 0000000000..1bf3e74fee --- /dev/null +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/PatternSegments/LIteralSegmentTests.cs @@ -0,0 +1,24 @@ +// 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 Microsoft.AspNetCore.Rewrite.Internal.PatternSegments; +using Xunit; + +namespace Microsoft.AspNetCore.Rewrite.Tests.PatternSegments +{ + public class LiteralSegmentTests + { + [Fact] + public void LiteralSegment_AssertSegmentIsCorrect() + { + // Arrange + var segement = new LiteralSegment("foo"); + + // Act + var results = segement.Evaluate(null, null, null); + + // Assert + Assert.Equal("foo", results); + } + } +} diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/PatternSegments/LocalAddressSegmentTests.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/PatternSegments/LocalAddressSegmentTests.cs new file mode 100644 index 0000000000..07d7254574 --- /dev/null +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/PatternSegments/LocalAddressSegmentTests.cs @@ -0,0 +1,41 @@ +// 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.AspNetCore.Http; +using Microsoft.AspNetCore.Rewrite.Internal.PatternSegments; +using Xunit; + +namespace Microsoft.AspNetCore.Rewrite.Tests.PatternSegments +{ + public class LocalAddressSegmentTests + { + [Fact] + public void LocalAddress_AssertSegmentIsCorrect() + { + // Arrange + var segement = new LocalAddressSegment(); + var context = new RewriteContext { HttpContext = new DefaultHttpContext() }; + context.HttpContext.Connection.LocalIpAddress = IPAddress.Parse("20.30.40.50"); + // Act + var results = segement.Evaluate(context, null, null); + + // Assert + Assert.Equal("20.30.40.50", results); + } + + [Fact] + public void LocalAddress_AssertNullLocalIpAddressReturnsNull() + { + var segement = new LocalAddressSegment(); + var context = new RewriteContext { HttpContext = new DefaultHttpContext() }; + context.HttpContext.Connection.LocalIpAddress = null; + // Act + var results = segement.Evaluate(context, null, null); + + // Assert + Assert.Null( results); + } + } +} diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/PatternSegments/LocalPortSegmentTests.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/PatternSegments/LocalPortSegmentTests.cs new file mode 100644 index 0000000000..1a3dad1896 --- /dev/null +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/PatternSegments/LocalPortSegmentTests.cs @@ -0,0 +1,28 @@ +// 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.Globalization; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Rewrite.Internal.PatternSegments; +using Xunit; + +namespace Microsoft.AspNetCore.Rewrite.Tests.PatternSegments +{ + public class LocalPortSegmentTests + { + [Fact] + public void LocalPortSegment_AssertSegmentIsCorrect() + { + // Arrange + var segement = new LocalPortSegment(); + var context = new RewriteContext { HttpContext = new DefaultHttpContext() }; + context.HttpContext.Connection.LocalPort = 800; + // Act + var results = segement.Evaluate(context, null, null); + + // Assert + Assert.Equal("800", results); + } + } +} diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/PatternSegments/QueryStringSegmentTests.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/PatternSegments/QueryStringSegmentTests.cs new file mode 100644 index 0000000000..a02986fc16 --- /dev/null +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/PatternSegments/QueryStringSegmentTests.cs @@ -0,0 +1,27 @@ +// 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 Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Rewrite.Internal.PatternSegments; +using Xunit; + +namespace Microsoft.AspNetCore.Rewrite.Tests.PatternSegments +{ + public class QueryStringSegmentTests + { + [Fact] + public void QueryString_AssertSegmentIsCorrect() + { + // Arrange + var segement = new QueryStringSegment(); + var context = new RewriteContext { HttpContext = new DefaultHttpContext() }; + context.HttpContext.Request.QueryString = new QueryString("?hey=1"); + + // Act + var results = segement.Evaluate(context, null, null); + + // Assert + Assert.Equal("?hey=1", results); + } + } +} diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/PatternSegments/RemoteAddressSegmentTests.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/PatternSegments/RemoteAddressSegmentTests.cs new file mode 100644 index 0000000000..c7f5ede0dc --- /dev/null +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/PatternSegments/RemoteAddressSegmentTests.cs @@ -0,0 +1,40 @@ +// 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.AspNetCore.Http; +using Microsoft.AspNetCore.Rewrite.Internal.PatternSegments; +using Xunit; + +namespace Microsoft.AspNetCore.Rewrite.Tests.PatternSegments +{ + public class RemoteAddressSegmentTests + { + [Fact] + public void RemoteAddress_AssertSegmentIsCorrect() + { + // Arrange + var segement = new RemoteAddressSegment(); + var context = new RewriteContext { HttpContext = new DefaultHttpContext() }; + context.HttpContext.Connection.RemoteIpAddress = IPAddress.Parse("20.30.40.50"); + // Act + var results = segement.Evaluate(context, null, null); + + // Assert + Assert.Equal("20.30.40.50", results); + } + + [Fact] + public void RemoteAddress_AssertNullLocalIpAddressReturnsNull() + { + var segement = new RemoteAddressSegment(); + var context = new RewriteContext { HttpContext = new DefaultHttpContext() }; + context.HttpContext.Connection.RemoteIpAddress = null; + // Act + var results = segement.Evaluate(context, null, null); + + // Assert + Assert.Null(results); + } + } +} diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/PatternSegments/RemotePortSegmentTests.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/PatternSegments/RemotePortSegmentTests.cs new file mode 100644 index 0000000000..6980e2379f --- /dev/null +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/PatternSegments/RemotePortSegmentTests.cs @@ -0,0 +1,26 @@ +// 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 Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Rewrite.Internal.PatternSegments; +using Xunit; + +namespace Microsoft.AspNetCore.Rewrite.Tests.PatternSegments +{ + public class RemotePortSegmentTests + { + [Fact] + public void RemotePort_AssertSegmentIsCorrect() + { + // Arrange + var segement = new RemotePortSegment(); + var context = new RewriteContext { HttpContext = new DefaultHttpContext() }; + context.HttpContext.Connection.RemotePort = 800; + // Act + var results = segement.Evaluate(context, null, null); + + // Assert + Assert.Equal("800", results); + } + } +} diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/PatternSegments/RequestFilenameSegmentTests.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/PatternSegments/RequestFilenameSegmentTests.cs new file mode 100644 index 0000000000..16e051d7af --- /dev/null +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/PatternSegments/RequestFilenameSegmentTests.cs @@ -0,0 +1,26 @@ +// 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 Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Rewrite.Internal.PatternSegments; +using Xunit; + +namespace Microsoft.AspNetCore.Rewrite.Tests.PatternSegments +{ + public class RequestFilenameSegmentTests + { + [Fact] + public void RequestFilename_AssertSegmentIsCorrect() + { + // Arrange + var segement = new RequestFileNameSegment(); + var context = new RewriteContext { HttpContext = new DefaultHttpContext() }; + context.HttpContext.Request.Path = new PathString("/foo/bar"); + // Act + var results = segement.Evaluate(context, null, null); + + // Assert + Assert.Equal("/foo/bar", results); + } + } +} diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/PatternSegments/RequestMethodSegmentTests.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/PatternSegments/RequestMethodSegmentTests.cs new file mode 100644 index 0000000000..fc9ac14b01 --- /dev/null +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/PatternSegments/RequestMethodSegmentTests.cs @@ -0,0 +1,26 @@ +// 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 Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Rewrite.Internal.PatternSegments; +using Xunit; + +namespace Microsoft.AspNetCore.Rewrite.Tests.PatternSegments +{ + public class RequestMethodSegmentTests + { + [Fact] + public void RequestMethod_AssertSegmentIsCorrect() + { + // Arrange + var segement = new RequestMethodSegment(); + var context = new RewriteContext { HttpContext = new DefaultHttpContext() }; + context.HttpContext.Request.Method = "GET"; + // Act + var results = segement.Evaluate(context, null, null); + + // Assert + Assert.Equal("GET", results); + } + } +} diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/PatternSegments/RuleMatchSegmentTests.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/PatternSegments/RuleMatchSegmentTests.cs new file mode 100644 index 0000000000..8e4d8ccfc4 --- /dev/null +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/PatternSegments/RuleMatchSegmentTests.cs @@ -0,0 +1,36 @@ +// 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.Text.RegularExpressions; +using Microsoft.AspNetCore.Rewrite.Internal; +using Microsoft.AspNetCore.Rewrite.Internal.PatternSegments; +using Xunit; + +namespace Microsoft.AspNetCore.Rewrite.Tests.PatternSegments +{ + public class RuleMatchSegmentTests + { + [Theory] + [InlineData(1, "foo")] + [InlineData(2, "bar")] + [InlineData(3, "baz")] + public void RuleMatch_AssertBackreferencesObtainsCorrectValue(int index, string expected) + { + // Arrange + var ruleMatch = CreateTestMatch(); + var segment = new RuleMatchSegment(index); + + // Act + var results = segment.Evaluate(null, ruleMatch, null); + + // Assert + Assert.Equal(expected, results); + } + + private static MatchResults CreateTestMatch() + { + var match = Regex.Match("foo/bar/baz", "(.*)/(.*)/(.*)"); + return new MatchResults { BackReference = match.Groups, Success = match.Success }; + } + } +} diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/PatternSegments/SchemeSegmentTests.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/PatternSegments/SchemeSegmentTests.cs new file mode 100644 index 0000000000..3caac305c6 --- /dev/null +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/PatternSegments/SchemeSegmentTests.cs @@ -0,0 +1,26 @@ +// 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 Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Rewrite.Internal.PatternSegments; +using Xunit; + +namespace Microsoft.AspNetCore.Rewrite.Tests.PatternSegments +{ + public class SchemeSegmentTests + { + [Fact] + public void SchemeSegment_AssertSegmentIsCorrect() + { + // Arrange + var segement = new SchemeSegment(); + var context = new RewriteContext { HttpContext = new DefaultHttpContext() }; + context.HttpContext.Request.Scheme = "http"; + // Act + var results = segement.Evaluate(context, null, null); + + // Assert + Assert.Equal("http", results); + } + } +} diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/PatternSegments/ServerProtocolSegmentTests.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/PatternSegments/ServerProtocolSegmentTests.cs new file mode 100644 index 0000000000..9128ef6b32 --- /dev/null +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/PatternSegments/ServerProtocolSegmentTests.cs @@ -0,0 +1,28 @@ +// 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 Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Http.Features; +using Microsoft.AspNetCore.Rewrite.Internal.PatternSegments; +using Xunit; + +namespace Microsoft.AspNetCore.Rewrite.Tests.PatternSegments +{ + public class ServerProtocolSegmentTests + { + [Fact] + public void ServerProtocol_AssertSegmentIsCorrect() + { + // Arrange + var segement = new ServerProtocolSegment(); + var context = new RewriteContext { HttpContext = new DefaultHttpContext() }; + context.HttpContext.Features.Set(new HttpRequestFeature { Protocol = "http" }); + + // Act + var results = segement.Evaluate(context, null, null); + + // Assert + Assert.Equal("http", results); + } + } +} diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/PatternSegments/ToLowerSegmentTests.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/PatternSegments/ToLowerSegmentTests.cs new file mode 100644 index 0000000000..a6b434ff3d --- /dev/null +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/PatternSegments/ToLowerSegmentTests.cs @@ -0,0 +1,32 @@ +// 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.Collections.Generic; +using Microsoft.AspNetCore.Rewrite.Internal; +using Microsoft.AspNetCore.Rewrite.Internal.PatternSegments; +using Xunit; + +namespace Microsoft.AspNetCore.Rewrite.Tests.PatternSegments +{ + public class ToLowerSegmentTests + { + [Theory] + [InlineData("Hello", "hello")] + [InlineData("WHAT", "what")] + [InlineData("hey", "hey")] + public void ToLower_AssertLowerCaseWorksAppropriately(string input, string expected) + { + // Arrange + var pattern = new Pattern(new List()); + pattern.PatternSegments.Add(new LiteralSegment(input)); + var segement = new ToLowerSegment(pattern); + var context = new RewriteContext(); + + // Act + var results = segement.Evaluate(context, null, null); + + // Assert + Assert.Equal(expected, results); + } + } +} diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/PatternSegments/UrlEncodeSegmentTests.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/PatternSegments/UrlEncodeSegmentTests.cs new file mode 100644 index 0000000000..767876a9a5 --- /dev/null +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/PatternSegments/UrlEncodeSegmentTests.cs @@ -0,0 +1,32 @@ +// 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.Collections.Generic; +using Microsoft.AspNetCore.Rewrite.Internal; +using Microsoft.AspNetCore.Rewrite.Internal.PatternSegments; +using Xunit; + +namespace Microsoft.AspNetCore.Rewrite.Tests.PatternSegments +{ + public class UrlEncodeSegmentTests + { + [Theory] + [InlineData(" ", "%20")] + [InlineData("x&y", "x%26y")] + [InlineData("hey", "hey")] + public void ToLower_AssertLowerCaseWorksAppropriately(string input, string expected) + { + // Arrange + var pattern = new Pattern(new List()); + pattern.PatternSegments.Add(new LiteralSegment(input)); + var segement = new UrlEncodeSegment(pattern); + var context = new RewriteContext(); + + // Act + var results = segement.Evaluate(context, null, null); + + // Assert + Assert.Equal(expected, results); + } + } +} diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/PatternSegments/UrlSegmentTests.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/PatternSegments/UrlSegmentTests.cs new file mode 100644 index 0000000000..d23c2a5fb4 --- /dev/null +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/PatternSegments/UrlSegmentTests.cs @@ -0,0 +1,26 @@ +// 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 Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Rewrite.Internal.PatternSegments; +using Xunit; + +namespace Microsoft.AspNetCore.Rewrite.Tests.PatternSegments +{ + public class UrlSegmentTests + { + [Fact] + public void LocalPortSegment_AssertSegmentIsCorrect() + { + // Arrange + var segement = new UrlSegment(); + var context = new RewriteContext { HttpContext = new DefaultHttpContext() }; + context.HttpContext.Request.Path = new PathString("/foo/bar"); + // Act + var results = segement.Evaluate(context, null, null); + + // Assert + Assert.Equal("/foo/bar", results); + } + } +} diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/UrlActions/ForbiddenActionTests.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/UrlActions/ForbiddenActionTests.cs new file mode 100644 index 0000000000..27e2bcca40 --- /dev/null +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/UrlActions/ForbiddenActionTests.cs @@ -0,0 +1,28 @@ +// 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 Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Rewrite.Internal; +using Microsoft.AspNetCore.Rewrite.Internal.UrlActions; +using Xunit; + +namespace Microsoft.AspNetCore.Rewrite.Tests.UrlActions +{ + public class ForbiddenActionTests + { + [Fact] + public void Forbidden_Verify403IsInStatusCode() + { + // Arrange + var context = new RewriteContext {HttpContext = new DefaultHttpContext()}; + var action = new ForbiddenAction(); + + // Act + var results = action.ApplyAction(context, null, null); + + // Assert + Assert.Equal(results.Result, RuleTermination.ResponseComplete); + Assert.Equal(context.HttpContext.Response.StatusCode, StatusCodes.Status403Forbidden); + } + } +} diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/UrlActions/GoneActionTests.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/UrlActions/GoneActionTests.cs new file mode 100644 index 0000000000..1daccb17f2 --- /dev/null +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/UrlActions/GoneActionTests.cs @@ -0,0 +1,28 @@ +// 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 Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Rewrite.Internal; +using Microsoft.AspNetCore.Rewrite.Internal.UrlActions; +using Xunit; + +namespace Microsoft.AspNetCore.Rewrite.Tests.UrlActions +{ + public class GoneActionTests + { + [Fact] + public void Gone_Verify410IsInStatusCode() + { + // Arrange + var context = new RewriteContext { HttpContext = new DefaultHttpContext() }; + var action = new GoneAction(); + + // Act + var results = action.ApplyAction(context, null, null); + + // Assert + Assert.Equal(results.Result, RuleTermination.ResponseComplete); + Assert.Equal(context.HttpContext.Response.StatusCode, StatusCodes.Status410Gone); + } + } +} diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/UrlRewrite/FileParserTests.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/UrlRewrite/FileParserTests.cs index 2c45fa8f02..43a8bac189 100644 --- a/test/Microsoft.AspNetCore.Rewrite.Tests/UrlRewrite/FileParserTests.cs +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/UrlRewrite/FileParserTests.cs @@ -29,13 +29,13 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite var expected = new List(); expected.Add(CreateTestRule(new List(), - Url: "^article/([0-9]+)/([_0-9a-z-]+)", + url: "^article/([0-9]+)/([_0-9a-z-]+)", name: "Rewrite to article.aspx", actionType: ActionType.Rewrite, pattern: "article.aspx?id={R:1}&title={R:2}")); // act - var res = new FileParser().Parse(new StringReader(xml)); + var res = new UrlRewriteFileParser().Parse(new StringReader(xml)); // assert AssertUrlRewriteRuleEquality(res, expected); @@ -66,13 +66,13 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite var expected = new List(); expected.Add(CreateTestRule(condList, - Url: "^article/([0-9]+)/([_0-9a-z-]+)", + url: "^article/([0-9]+)/([_0-9a-z-]+)", name: "Rewrite to article.aspx", actionType: ActionType.Rewrite, pattern: "article.aspx?id={R:1}&title={R:2}")); // act - var res = new FileParser().Parse(new StringReader(xml)); + var res = new UrlRewriteFileParser().Parse(new StringReader(xml)); // assert AssertUrlRewriteRuleEquality(res, expected); @@ -110,18 +110,18 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite var expected = new List(); expected.Add(CreateTestRule(condList, - Url: "^article/([0-9]+)/([_0-9a-z-]+)", + url: "^article/([0-9]+)/([_0-9a-z-]+)", name: "Rewrite to article.aspx", actionType: ActionType.Rewrite, pattern: "article.aspx?id={R:1}&title={R:2}")); expected.Add(CreateTestRule(condList, - Url: "^article/([0-9]+)/([_0-9a-z-]+)", + url: "^article/([0-9]+)/([_0-9a-z-]+)", name: "Rewrite to another article.aspx", actionType: ActionType.Rewrite, pattern: "article.aspx?id={R:1}&title={R:2}")); // act - var res = new FileParser().Parse(new StringReader(xml)); + var res = new UrlRewriteFileParser().Parse(new StringReader(xml)); // assert AssertUrlRewriteRuleEquality(res, expected); @@ -135,7 +135,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite bool enabled = true, PatternSyntax patternSyntax = PatternSyntax.ECMAScript, bool stopProcessing = false, - string Url = "", + string url = "", bool ignoreCase = true, bool negate = false, ActionType actionType = ActionType.None, @@ -145,22 +145,12 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite RedirectType redirectType = RedirectType.Permanent ) { - return new UrlRewriteRule - { - Action = new RewriteAction(RuleTerminiation.Continue, new InputParser().ParseInputString(Url), clearQuery: false), - Name = name, - Enabled = enabled, - InitialMatch = new RegexMatch(new Regex("^OFF$"), false) - { - }, - Conditions = new Conditions - { - ConditionList = conditions - } - }; + return new UrlRewriteRule(name, new RegexMatch(new Regex("^OFF$"), false), conditions, + new RewriteAction(RuleTermination.Continue, new InputParser().ParseInputString(url), clearQuery: false)); } - private void AssertUrlRewriteRuleEquality(List actual, List expected) + // TODO make rules comparable? + private void AssertUrlRewriteRuleEquality(IList actual, IList expected) { Assert.Equal(actual.Count, expected.Count); for (var i = 0; i < actual.Count; i++) @@ -169,23 +159,22 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite var r2 = expected[i]; Assert.Equal(r1.Name, r2.Name); - Assert.Equal(r1.Enabled, r2.Enabled); if (r1.Conditions == null) { - Assert.Equal(r2.Conditions.ConditionList.Count, 0); + Assert.Equal(r2.Conditions.Count, 0); } else if (r2.Conditions == null) { - Assert.Equal(r1.Conditions.ConditionList.Count, 0); + Assert.Equal(r1.Conditions.Count, 0); } else { - Assert.Equal(r1.Conditions.ConditionList.Count, r2.Conditions.ConditionList.Count); - for (var j = 0; j < r1.Conditions.ConditionList.Count; j++) + Assert.Equal(r1.Conditions.Count, r2.Conditions.Count); + for (var j = 0; j < r1.Conditions.Count; j++) { - var c1 = r1.Conditions.ConditionList[j]; - var c2 = r2.Conditions.ConditionList[j]; + var c1 = r1.Conditions[j]; + var c2 = r2.Conditions[j]; Assert.Equal(c1.Input.PatternSegments.Count, c2.Input.PatternSegments.Count); } } diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/UrlRewrite/FormatExceptionHandlingTests.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/UrlRewrite/FormatExceptionHandlingTests.cs index b1e0a6f45b..db70d69e4a 100644 --- a/test/Microsoft.AspNetCore.Rewrite.Tests/UrlRewrite/FormatExceptionHandlingTests.cs +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/UrlRewrite/FormatExceptionHandlingTests.cs @@ -94,7 +94,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite public void ThrowFormatExceptionWithCorrectMessage(string input, string expected) { // Arrange, Act, Assert - var ex = Assert.Throws(() => new FileParser().Parse(new StringReader(input))); + var ex = Assert.Throws(() => new UrlRewriteFileParser().Parse(new StringReader(input))); Assert.Equal(ex.Message, expected); } } diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/UrlRewrite/InputParserTests.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/UrlRewrite/InputParserTests.cs index 0a69cdf8ad..0f4b2ba7fb 100644 --- a/test/Microsoft.AspNetCore.Rewrite.Tests/UrlRewrite/InputParserTests.cs +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/UrlRewrite/InputParserTests.cs @@ -92,7 +92,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite { var context = new DefaultHttpContext(); - return new RewriteContext { HttpContext = context, FileProvider = null }; + return new RewriteContext { HttpContext = context, StaticFileProvider = null }; } private MatchResults CreateTestRuleMatch() diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/UrlRewrite/MiddleWareTests.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/UrlRewrite/MiddleWareTests.cs index f2018d20b9..eadddbd60d 100644 --- a/test/Microsoft.AspNetCore.Rewrite.Tests/UrlRewrite/MiddleWareTests.cs +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/UrlRewrite/MiddleWareTests.cs @@ -36,7 +36,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite var response = await server.CreateClient().GetAsync("article/10/hey"); - Assert.Equal(response.Headers.Location.OriginalString, "article.aspx?id=10&title=hey"); + Assert.Equal(response.Headers.Location.OriginalString, "/article.aspx?id=10&title=hey"); } [Fact] @@ -112,7 +112,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite var response = await server.CreateClient().GetAsync("HElLo"); - Assert.Equal(response.Headers.Location.OriginalString, "hello"); + Assert.Equal(response.Headers.Location.OriginalString, "/hello"); } [Fact] @@ -139,7 +139,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite var response = await server.CreateClient().GetAsync("hey/hello/"); - Assert.Equal(response.Headers.Location.OriginalString, "hey/hello"); + Assert.Equal(response.Headers.Location.OriginalString, "/hey/hello"); } [Fact] @@ -166,7 +166,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite var response = await server.CreateClient().GetAsync("hey/hello"); - Assert.Equal(response.Headers.Location.OriginalString, "hey/hello/"); + Assert.Equal(response.Headers.Location.OriginalString, "/hey/hello/"); } [Fact] diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/UrlRewrite/UrlRewriteApplicationTests.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/UrlRewrite/UrlRewriteApplicationTests.cs index 6c5abfedb5..6d6864d398 100644 --- a/test/Microsoft.AspNetCore.Rewrite.Tests/UrlRewrite/UrlRewriteApplicationTests.cs +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/UrlRewrite/UrlRewriteApplicationTests.cs @@ -1,15 +1,10 @@ // 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; using System.IO; using System.Linq; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Rewrite.Internal; using Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite; -using Microsoft.AspNetCore.TestHost; using Xunit; namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite @@ -28,11 +23,11 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite "); - var rules = new FileParser().Parse(xml); + var rules = new UrlRewriteFileParser().Parse(xml); Assert.Equal(rules.Count, 1); var ruleResults = rules.FirstOrDefault().ApplyRule(new RewriteContext {HttpContext = new DefaultHttpContext()}); - Assert.Equal(ruleResults.Result, RuleTerminiation.StopRules); + Assert.Equal(ruleResults.Result, RuleTermination.StopRules); } [Fact] @@ -46,11 +41,11 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite "); - var rules = new FileParser().Parse(xml); + var rules = new UrlRewriteFileParser().Parse(xml); Assert.Equal(rules.Count, 1); var ruleResults = rules.FirstOrDefault().ApplyRule(new RewriteContext { HttpContext = new DefaultHttpContext() }); - Assert.Equal(ruleResults.Result, RuleTerminiation.Continue); + Assert.Equal(ruleResults.Result, RuleTermination.Continue); } } } From 28133b6808224a55348dc7054f24ce455c0937d7 Mon Sep 17 00:00:00 2001 From: Justin Kotalik Date: Sun, 28 Aug 2016 22:05:44 -0700 Subject: [PATCH 099/307] Remove RuleResult, added to context. --- .../Internal/CodeRules/DelegateRule.cs | 6 +++--- .../Internal/CodeRules/RedirectToHttpsRule.cs | 5 ++--- .../ModRewrite/ModRewriteRedirectAction.cs | 4 ++-- .../ModRewrite/ModRewriteRewriteAction.cs | 8 ++++---- .../Internal/ModRewrite/RuleBuilder.cs | 4 ++-- .../Internal/ModRewriteRule.cs | 8 ++++---- .../Internal/UrlAction.cs | 2 +- .../Internal/UrlActions/ForbiddenAction.cs | 4 ++-- .../Internal/UrlActions/GoneAction.cs | 4 ++-- .../Internal/UrlActions/RedirectAction.cs | 4 ++-- .../Internal/UrlActions/RewriteAction.cs | 4 ++-- .../Internal/UrlActions/VoidAction.cs | 10 +++++----- .../Internal/UrlRewrite/UrlRewriteRuleBuilder.cs | 2 +- .../Internal/UrlRewriteRule.cs | 8 ++++---- .../RewriteContext.cs | 1 + .../RewriteMiddleware.cs | 15 ++++++++------- .../RewriteOptionsExtensions.cs | 2 +- src/Microsoft.AspNetCore.Rewrite/Rule.cs | 3 ++- src/Microsoft.AspNetCore.Rewrite/RuleResult.cs | 14 -------------- .../UrlActions/ForbiddenActionTests.cs | 5 ++--- .../UrlActions/GoneActionTests.cs | 5 ++--- .../UrlRewrite/UrlRewriteApplicationTests.cs | 12 +++++++----- 22 files changed, 59 insertions(+), 71 deletions(-) delete mode 100644 src/Microsoft.AspNetCore.Rewrite/RuleResult.cs diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/CodeRules/DelegateRule.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/CodeRules/DelegateRule.cs index 72216f0abc..869e773c37 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/CodeRules/DelegateRule.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/CodeRules/DelegateRule.cs @@ -7,12 +7,12 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.CodeRules { public class DelegateRule : Rule { - private readonly Func _onApplyRule; + private readonly Action _onApplyRule; - public DelegateRule(Func onApplyRule) + public DelegateRule(Action onApplyRule) { _onApplyRule = onApplyRule; } - public override RuleResult ApplyRule(RewriteContext context) => _onApplyRule(context); + public override void ApplyRule(RewriteContext context) => _onApplyRule(context); } } \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/CodeRules/RedirectToHttpsRule.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/CodeRules/RedirectToHttpsRule.cs index 558810b50a..a4b99de157 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/CodeRules/RedirectToHttpsRule.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/CodeRules/RedirectToHttpsRule.cs @@ -11,7 +11,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.CodeRules public int? SSLPort { get; set; } public int StatusCode { get; set; } - public override RuleResult ApplyRule(RewriteContext context) + public override void ApplyRule(RewriteContext context) { if (!context.HttpContext.Request.IsHttps) { @@ -31,9 +31,8 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.CodeRules var newUrl = new StringBuilder().Append("https://").Append(host).Append(req.PathBase).Append(req.Path).Append(req.QueryString); context.HttpContext.Response.Redirect(newUrl.ToString()); - return RuleResult.ResponseComplete; + context.Result = RuleTermination.ResponseComplete; } - return RuleResult.Continue; } } } \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/ModRewriteRedirectAction.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/ModRewriteRedirectAction.cs index 75bc8aa0cc..6198b1a35e 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/ModRewriteRedirectAction.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/ModRewriteRedirectAction.cs @@ -28,7 +28,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite EscapeBackReferences = escapeBackReferences; } - public override RuleResult ApplyAction(RewriteContext context, MatchResults ruleMatch, MatchResults condMatch) + public override void ApplyAction(RewriteContext context, MatchResults ruleMatch, MatchResults condMatch) { var pattern = Url.Evaluate(context, ruleMatch, condMatch); if (EscapeBackReferences) @@ -64,7 +64,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite context.HttpContext.Response.Headers[HeaderNames.Location] = pattern + context.HttpContext.Request.QueryString; } } - return RuleResult.ResponseComplete; + context.Result = RuleTermination.ResponseComplete; } } } diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/ModRewriteRewriteAction.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/ModRewriteRewriteAction.cs index 01cb99dd24..1186f3f8f9 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/ModRewriteRewriteAction.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/ModRewriteRewriteAction.cs @@ -10,13 +10,13 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite public class ModRewriteRewriteAction : UrlAction { private readonly string ForwardSlash = "/"; - public RuleResult Result { get; } + public RuleTermination Result { get; } public bool QueryStringAppend { get; } public bool QueryStringDelete { get; } public bool EscapeBackReferences { get; } public ModRewriteRewriteAction( - RuleResult result, + RuleTermination result, Pattern pattern, bool queryStringAppend, bool queryStringDelete, @@ -29,7 +29,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite EscapeBackReferences = escapeBackReferences; } - public override RuleResult ApplyAction(RewriteContext context, MatchResults ruleMatch, MatchResults condMatch) + public override void ApplyAction(RewriteContext context, MatchResults ruleMatch, MatchResults condMatch) { var pattern = Url.Evaluate(context, ruleMatch, condMatch); @@ -107,7 +107,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite } } } - return Result; + context.Result = Result; } } } diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/RuleBuilder.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/RuleBuilder.cs index 8190431803..be83b1f76e 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/RuleBuilder.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/RuleBuilder.cs @@ -215,8 +215,8 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite else { var last = flags.HasFlag(FlagType.End) || flags.HasFlag(FlagType.Last); - var redirect = last ? RuleResult.StopRules : RuleResult.Continue; - _action = new ModRewriteRewriteAction(redirect, pattern, queryStringAppend, queryStringDelete, escapeBackReference); + var termination = last ? RuleTermination.StopRules : RuleTermination.Continue; + _action = new ModRewriteRewriteAction(termination, pattern, queryStringAppend, queryStringDelete, escapeBackReference); } } } diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewriteRule.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewriteRule.cs index eb54eed72a..3a2bcb21dd 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewriteRule.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewriteRule.cs @@ -21,7 +21,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal PreActions = preActions; } - public override RuleResult ApplyRule(RewriteContext context) + public override void ApplyRule(RewriteContext context) { // 1. Figure out which section of the string to match for the initial rule. var initMatchRes = InitialMatch.Evaluate(context.HttpContext.Request.Path, context); @@ -29,7 +29,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal if (!initMatchRes.Success) { context.Logger?.ModRewriteDidNotMatchRule(); - return RuleResult.Continue; + return; } MatchResults condMatchRes = null; @@ -39,7 +39,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal if (!condMatchRes.Success) { context.Logger?.ModRewriteDidNotMatchRule(); - return RuleResult.Continue; + return; } } @@ -51,7 +51,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal preAction.ApplyAction(context.HttpContext, initMatchRes, condMatchRes); } - return Action.ApplyAction(context, initMatchRes, condMatchRes); + Action.ApplyAction(context, initMatchRes, condMatchRes); } } } diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlAction.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlAction.cs index 326d22b377..a833ee9b17 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlAction.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlAction.cs @@ -6,6 +6,6 @@ namespace Microsoft.AspNetCore.Rewrite.Internal public abstract class UrlAction { protected Pattern Url { get; set; } - public abstract RuleResult ApplyAction(RewriteContext context, MatchResults ruleMatch, MatchResults condMatch); + public abstract void ApplyAction(RewriteContext context, MatchResults ruleMatch, MatchResults condMatch); } } diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/ForbiddenAction.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/ForbiddenAction.cs index 43589509f3..08ad531d08 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/ForbiddenAction.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/ForbiddenAction.cs @@ -7,10 +7,10 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlActions { public class ForbiddenAction : UrlAction { - public override RuleResult ApplyAction(RewriteContext context, MatchResults ruleMatch, MatchResults condMatch) + public override void ApplyAction(RewriteContext context, MatchResults ruleMatch, MatchResults condMatch) { context.HttpContext.Response.StatusCode = StatusCodes.Status403Forbidden; - return RuleResult.ResponseComplete; + context.Result = RuleTermination.ResponseComplete; } } } diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/GoneAction.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/GoneAction.cs index d56eb09744..4a753c61da 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/GoneAction.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/GoneAction.cs @@ -7,10 +7,10 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlActions { public class GoneAction : UrlAction { - public override RuleResult ApplyAction(RewriteContext context, MatchResults ruleMatch, MatchResults condMatch) + public override void ApplyAction(RewriteContext context, MatchResults ruleMatch, MatchResults condMatch) { context.HttpContext.Response.StatusCode = StatusCodes.Status410Gone; - return RuleResult.ResponseComplete; + context.Result = RuleTermination.ResponseComplete; } } } diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/RedirectAction.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/RedirectAction.cs index f0cac6afb7..f73baad942 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/RedirectAction.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/RedirectAction.cs @@ -19,7 +19,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlActions AppendQueryString = appendQueryString; } - public override RuleResult ApplyAction(RewriteContext context, MatchResults ruleMatch, MatchResults condMatch) + public override void ApplyAction(RewriteContext context, MatchResults ruleMatch, MatchResults condMatch) { var pattern = Url.Evaluate(context, ruleMatch, condMatch); context.HttpContext.Response.StatusCode = StatusCode; @@ -46,7 +46,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlActions { context.HttpContext.Response.Headers[HeaderNames.Location] = pattern; } - return RuleResult.ResponseComplete; + context.Result = RuleTermination.ResponseComplete; } } } diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/RewriteAction.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/RewriteAction.cs index 7c9cd06103..13683a875f 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/RewriteAction.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/RewriteAction.cs @@ -20,7 +20,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlActions ClearQuery = clearQuery; } - public override RuleResult ApplyAction(RewriteContext context, MatchResults ruleMatch, MatchResults condMatch) + public override void ApplyAction(RewriteContext context, MatchResults ruleMatch, MatchResults condMatch) { var pattern = Url.Evaluate(context, ruleMatch, condMatch); @@ -73,7 +73,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlActions } } } - return new RuleResult { Result = Result }; + context.Result = Result; } } } diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/VoidAction.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/VoidAction.cs index c58c6e94cd..4ac2a08144 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/VoidAction.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/VoidAction.cs @@ -5,16 +5,16 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlActions { public class VoidAction : UrlAction { - private readonly RuleResult _results; + public RuleTermination Result { get; } - public VoidAction(RuleResult results) + public VoidAction(RuleTermination result) { - _results = results; + Result = result; } // Explicitly say that nothing happens - public override RuleResult ApplyAction(RewriteContext context, MatchResults ruleMatch, MatchResults condMatch) + public override void ApplyAction(RewriteContext context, MatchResults ruleMatch, MatchResults condMatch) { - return _results; + context.Result = Result; } } } diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/UrlRewriteRuleBuilder.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/UrlRewriteRuleBuilder.cs index 90da1e57d9..bb8f2e8e7c 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/UrlRewriteRuleBuilder.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/UrlRewriteRuleBuilder.cs @@ -42,7 +42,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite switch (actionType) { case ActionType.None: - _action = new VoidAction(stopProcessing ? RuleResult.StopRules : RuleResult.Continue); + _action = new VoidAction(stopProcessing ? RuleTermination.StopRules : RuleTermination.Continue); break; case ActionType.Rewrite: _action = new RewriteAction(stopProcessing ? RuleTermination.StopRules : RuleTermination.Continue, diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewriteRule.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewriteRule.cs index 94a88763ff..6923445187 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewriteRule.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewriteRule.cs @@ -25,7 +25,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal Action = action; } - public override RuleResult ApplyRule(RewriteContext context) + public override void ApplyRule(RewriteContext context) { // Due to the path string always having a leading slash, // remove it from the path before regex comparison @@ -43,7 +43,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal if (!initMatchResults.Success) { context.Logger?.UrlRewriteDidNotMatchRule(Name); - return RuleResult.Continue; + return; } MatchResults condMatchRes = null; @@ -53,13 +53,13 @@ namespace Microsoft.AspNetCore.Rewrite.Internal if (!condMatchRes.Success) { context.Logger?.UrlRewriteDidNotMatchRule(Name); - return RuleResult.Continue; + return; } } context.Logger?.UrlRewriteMatchedRule(Name); // at this point we know the rule passed, evaluate the replacement. - return Action.ApplyAction(context, initMatchResults, condMatchRes); + Action.ApplyAction(context, initMatchResults, condMatchRes); } } } \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Rewrite/RewriteContext.cs b/src/Microsoft.AspNetCore.Rewrite/RewriteContext.cs index 4b4fb8e8db..76dd9c6989 100644 --- a/src/Microsoft.AspNetCore.Rewrite/RewriteContext.cs +++ b/src/Microsoft.AspNetCore.Rewrite/RewriteContext.cs @@ -17,6 +17,7 @@ namespace Microsoft.AspNetCore.Rewrite public HttpContext HttpContext { get; set; } public IFileProvider StaticFileProvider { get; set; } public ILogger Logger { get; set; } + public RuleTermination Result { get; set; } // PERF: share the same string builder per request internal StringBuilder Builder { get; set; } = new StringBuilder(64); } diff --git a/src/Microsoft.AspNetCore.Rewrite/RewriteMiddleware.cs b/src/Microsoft.AspNetCore.Rewrite/RewriteMiddleware.cs index afcbcb576f..10e1a0a1a1 100644 --- a/src/Microsoft.AspNetCore.Rewrite/RewriteMiddleware.cs +++ b/src/Microsoft.AspNetCore.Rewrite/RewriteMiddleware.cs @@ -65,30 +65,31 @@ namespace Microsoft.AspNetCore.Rewrite { throw new ArgumentNullException(nameof(context)); } - var urlContext = new RewriteContext { + var rewriteContext = new RewriteContext { HttpContext = context, StaticFileProvider = _fileProvider, - Logger = _logger + Logger = _logger, + Result = RuleTermination.Continue }; foreach (var rule in _options.Rules) { - var result = rule.ApplyRule(urlContext); - switch (result.Result) + rule.ApplyRule(rewriteContext); + switch (rewriteContext.Result) { case RuleTermination.Continue: _logger.RewriteMiddlewareRequestContinueResults(); break; case RuleTermination.ResponseComplete: _logger.RewriteMiddlewareRequestResponseComplete( - urlContext.HttpContext.Response.Headers[HeaderNames.Location], - urlContext.HttpContext.Response.StatusCode); + context.Response.Headers[HeaderNames.Location], + context.Response.StatusCode); return CompletedTask; case RuleTermination.StopRules: _logger.RewriteMiddlewareRequestStopRules(); return _next(context); default: - throw new ArgumentOutOfRangeException($"Invalid rule termination {result}"); + throw new ArgumentOutOfRangeException($"Invalid rule termination {rewriteContext.Result}"); } } return _next(context); diff --git a/src/Microsoft.AspNetCore.Rewrite/RewriteOptionsExtensions.cs b/src/Microsoft.AspNetCore.Rewrite/RewriteOptionsExtensions.cs index 0861fa50f1..e0cf65479f 100644 --- a/src/Microsoft.AspNetCore.Rewrite/RewriteOptionsExtensions.cs +++ b/src/Microsoft.AspNetCore.Rewrite/RewriteOptionsExtensions.cs @@ -31,7 +31,7 @@ namespace Microsoft.AspNetCore.Rewrite /// The Rewrite options. /// A Func that checks and applies the rule. /// - public static RewriteOptions Add(this RewriteOptions options, Func applyRule) + public static RewriteOptions Add(this RewriteOptions options, Action applyRule) { options.Rules.Add(new DelegateRule(applyRule)); return options; diff --git a/src/Microsoft.AspNetCore.Rewrite/Rule.cs b/src/Microsoft.AspNetCore.Rewrite/Rule.cs index 82a70dabc5..90eef4b050 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Rule.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Rule.cs @@ -4,9 +4,10 @@ namespace Microsoft.AspNetCore.Rewrite { // make this public and doc comements + // caller must set the context.Results field appropriately in rule. public abstract class Rule { - public abstract RuleResult ApplyRule(RewriteContext context); + public abstract void ApplyRule(RewriteContext context); } } diff --git a/src/Microsoft.AspNetCore.Rewrite/RuleResult.cs b/src/Microsoft.AspNetCore.Rewrite/RuleResult.cs deleted file mode 100644 index 2b2bb4abf3..0000000000 --- a/src/Microsoft.AspNetCore.Rewrite/RuleResult.cs +++ /dev/null @@ -1,14 +0,0 @@ -// 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. - -namespace Microsoft.AspNetCore.Rewrite -{ - public class RuleResult - { - public static RuleResult Continue = new RuleResult { Result = RuleTermination.Continue }; - public static RuleResult ResponseComplete = new RuleResult { Result = RuleTermination.ResponseComplete }; - public static RuleResult StopRules = new RuleResult { Result = RuleTermination.StopRules }; - - public RuleTermination Result { get; set; } - } -} diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/UrlActions/ForbiddenActionTests.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/UrlActions/ForbiddenActionTests.cs index 27e2bcca40..fa668e29d6 100644 --- a/test/Microsoft.AspNetCore.Rewrite.Tests/UrlActions/ForbiddenActionTests.cs +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/UrlActions/ForbiddenActionTests.cs @@ -2,7 +2,6 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Rewrite.Internal; using Microsoft.AspNetCore.Rewrite.Internal.UrlActions; using Xunit; @@ -18,10 +17,10 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlActions var action = new ForbiddenAction(); // Act - var results = action.ApplyAction(context, null, null); + action.ApplyAction(context, null, null); // Assert - Assert.Equal(results.Result, RuleTermination.ResponseComplete); + Assert.Equal(context.Result, RuleTermination.ResponseComplete); Assert.Equal(context.HttpContext.Response.StatusCode, StatusCodes.Status403Forbidden); } } diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/UrlActions/GoneActionTests.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/UrlActions/GoneActionTests.cs index 1daccb17f2..ed061dd929 100644 --- a/test/Microsoft.AspNetCore.Rewrite.Tests/UrlActions/GoneActionTests.cs +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/UrlActions/GoneActionTests.cs @@ -2,7 +2,6 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Rewrite.Internal; using Microsoft.AspNetCore.Rewrite.Internal.UrlActions; using Xunit; @@ -18,10 +17,10 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlActions var action = new GoneAction(); // Act - var results = action.ApplyAction(context, null, null); + action.ApplyAction(context, null, null); // Assert - Assert.Equal(results.Result, RuleTermination.ResponseComplete); + Assert.Equal(context.Result, RuleTermination.ResponseComplete); Assert.Equal(context.HttpContext.Response.StatusCode, StatusCodes.Status410Gone); } } diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/UrlRewrite/UrlRewriteApplicationTests.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/UrlRewrite/UrlRewriteApplicationTests.cs index 6d6864d398..8892155eff 100644 --- a/test/Microsoft.AspNetCore.Rewrite.Tests/UrlRewrite/UrlRewriteApplicationTests.cs +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/UrlRewrite/UrlRewriteApplicationTests.cs @@ -24,10 +24,11 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite "); var rules = new UrlRewriteFileParser().Parse(xml); - + Assert.Equal(rules.Count, 1); - var ruleResults = rules.FirstOrDefault().ApplyRule(new RewriteContext {HttpContext = new DefaultHttpContext()}); - Assert.Equal(ruleResults.Result, RuleTermination.StopRules); + var context = new RewriteContext { HttpContext = new DefaultHttpContext() }; + rules.FirstOrDefault().ApplyRule(context); + Assert.Equal(context.Result, RuleTermination.StopRules); } [Fact] @@ -44,8 +45,9 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite var rules = new UrlRewriteFileParser().Parse(xml); Assert.Equal(rules.Count, 1); - var ruleResults = rules.FirstOrDefault().ApplyRule(new RewriteContext { HttpContext = new DefaultHttpContext() }); - Assert.Equal(ruleResults.Result, RuleTermination.Continue); + var context = new RewriteContext { HttpContext = new DefaultHttpContext() }; + rules.FirstOrDefault().ApplyRule(context); + Assert.Equal(context.Result, RuleTermination.Continue); } } } From 4a06b37280ee7368aa61a2266a9189cf69dc8c11 Mon Sep 17 00:00:00 2001 From: Justin Kotalik Date: Mon, 29 Aug 2016 13:55:44 -0700 Subject: [PATCH 100/307] Modifies .Rewrite and .Redirect to use normal regex syntax for backreferences --- samples/RewriteSample/Startup.cs | 2 +- .../Internal/CodeRules/RedirectRule.cs | 66 ++++++++++ .../Internal/CodeRules/RewriteRule.cs | 94 +++++++++++++++ .../ModRewrite/ModRewriteRedirectAction.cs | 70 ----------- .../ModRewrite/ModRewriteRewriteAction.cs | 113 ------------------ .../Internal/ModRewrite/RuleBuilder.cs | 4 +- .../Internal/UrlActions/RedirectAction.cs | 59 +++++++-- .../Internal/UrlActions/RewriteAction.cs | 87 +++++++++++--- .../UrlRewrite/UrlRewriteRuleBuilder.cs | 3 +- .../RewriteOptionsExtensions.cs | 39 +++--- .../CodeRules/MiddlewareTests.cs | 4 +- .../UrlRewrite/FileParserTests.cs | 3 +- 12 files changed, 305 insertions(+), 239 deletions(-) create mode 100644 src/Microsoft.AspNetCore.Rewrite/Internal/CodeRules/RedirectRule.cs create mode 100644 src/Microsoft.AspNetCore.Rewrite/Internal/CodeRules/RewriteRule.cs delete mode 100644 src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/ModRewriteRedirectAction.cs delete mode 100644 src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/ModRewriteRewriteAction.cs diff --git a/samples/RewriteSample/Startup.cs b/samples/RewriteSample/Startup.cs index ea80638c30..85918d2459 100644 --- a/samples/RewriteSample/Startup.cs +++ b/samples/RewriteSample/Startup.cs @@ -27,7 +27,7 @@ namespace RewriteSample // TODO make this startup do something useful. app.UseRewriter(new RewriteOptions() - .Rewrite(@"foo/(\d+)", "foo?id={R:1}") + .Rewrite(@"foo/(\d+)", "foo?id=$1") .ImportFromUrlRewrite(hostingEnv, "UrlRewrite.xml") .ImportFromModRewrite(hostingEnv, "Rewrite.txt")); diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/CodeRules/RedirectRule.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/CodeRules/RedirectRule.cs new file mode 100644 index 0000000000..7c33bd426f --- /dev/null +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/CodeRules/RedirectRule.cs @@ -0,0 +1,66 @@ +// 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; +using System.Text.RegularExpressions; +using Microsoft.AspNetCore.Http; +using Microsoft.Net.Http.Headers; + +namespace Microsoft.AspNetCore.Rewrite.Internal.CodeRules +{ + public class RedirectRule : Rule + { + private readonly TimeSpan _regexTimeout = TimeSpan.FromSeconds(1); + public Regex InitialMatch { get; } + public string Replacement { get; } + public int StatusCode { get; } + public RedirectRule(string regex, string replacement, int statusCode) + { + InitialMatch = new Regex(regex, RegexOptions.Compiled | RegexOptions.CultureInvariant, _regexTimeout); + Replacement = replacement; + StatusCode = statusCode; + } + + public override void ApplyRule(RewriteContext context) + { + var path = context.HttpContext.Request.Path; + Match initMatchResults; + if (path == PathString.Empty) + { + initMatchResults = InitialMatch.Match(path.ToString()); + } + else + { + initMatchResults = InitialMatch.Match(path.ToString().Substring(1)); + } + + if (initMatchResults.Success) + { + var newPath = initMatchResults.Result(Replacement); + var response = context.HttpContext.Response; + response.StatusCode = StatusCode; + + if (newPath.IndexOf("://", StringComparison.Ordinal) == -1 && !newPath.StartsWith("/")) + { + newPath = '/' + newPath; + } + + var split = newPath.IndexOf('?'); + if (split >= 0) + { + var query = context.HttpContext.Request.QueryString.Add( + QueryString.FromUriComponent( + newPath.Substring(split))); + // not using the HttpContext.Response.redirect here because status codes may be 301, 302, 307, 308 + response.Headers[HeaderNames.Location] = newPath.Substring(0, split) + query; + } + else + { + response.Headers[HeaderNames.Location] = newPath; + } + + context.Result = RuleTermination.ResponseComplete; + } + } + } +} diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/CodeRules/RewriteRule.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/CodeRules/RewriteRule.cs new file mode 100644 index 0000000000..4892a3d467 --- /dev/null +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/CodeRules/RewriteRule.cs @@ -0,0 +1,94 @@ +// 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; +using System.Text.RegularExpressions; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Http.Extensions; + +namespace Microsoft.AspNetCore.Rewrite.Internal.CodeRules +{ + public class RewriteRule : Rule + { + private readonly string ForwardSlash = "/"; + private readonly TimeSpan _regexTimeout = TimeSpan.FromSeconds(1); + public Regex InitialMatch { get; } + public string Replacement { get; } + public bool StopProcessing { get; } + public RewriteRule(string regex, string replacement, bool stopProcessing) + { + InitialMatch = new Regex(regex, RegexOptions.Compiled | RegexOptions.CultureInvariant, _regexTimeout); + Replacement = replacement; + StopProcessing = stopProcessing; + } + + public override void ApplyRule(RewriteContext context) + { + var path = context.HttpContext.Request.Path; + Match initMatchResults; + if (path == PathString.Empty) + { + initMatchResults = InitialMatch.Match(path.ToString()); + } + else + { + initMatchResults = InitialMatch.Match(path.ToString().Substring(1)); + } + + if (initMatchResults.Success) + { + var result = initMatchResults.Result(Replacement); + var request = context.HttpContext.Request; + + if (result.IndexOf("://", StringComparison.Ordinal) >= 0) + { + string scheme; + HostString host; + PathString pathString; + QueryString query; + FragmentString fragment; + UriHelper.FromAbsolute(result, out scheme, out host, out pathString, out query, out fragment); + + request.Scheme = scheme; + request.Host = host; + request.Path = pathString; + request.QueryString = query.Add(request.QueryString); + } + else + { + var split = result.IndexOf('?'); + if (split >= 0) + { + var newPath = result.Substring(0, split); + if (newPath.StartsWith(ForwardSlash)) + { + request.Path = PathString.FromUriComponent(newPath); + } + else + { + request.Path = PathString.FromUriComponent(ForwardSlash + newPath); + } + request.QueryString = request.QueryString.Add( + QueryString.FromUriComponent( + result.Substring(split))); + } + else + { + if (result.StartsWith(ForwardSlash)) + { + request.Path = PathString.FromUriComponent(result); + } + else + { + request.Path = PathString.FromUriComponent(ForwardSlash + result); + } + } + } + if (StopProcessing) + { + context.Result = RuleTermination.StopRules; + } + } + } + } +} diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/ModRewriteRedirectAction.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/ModRewriteRedirectAction.cs deleted file mode 100644 index 6198b1a35e..0000000000 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/ModRewriteRedirectAction.cs +++ /dev/null @@ -1,70 +0,0 @@ -// 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; -using Microsoft.AspNetCore.Http; -using Microsoft.Net.Http.Headers; - -namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite -{ - public class ModRewriteRedirectAction : UrlAction - { - public int StatusCode { get; } - public bool QueryStringAppend { get; } - public bool QueryStringDelete { get; } - public bool EscapeBackReferences { get; } - - public ModRewriteRedirectAction( - int statusCode, - Pattern pattern, - bool queryStringAppend, - bool queryStringDelete, - bool escapeBackReferences) - { - StatusCode = statusCode; - Url = pattern; - QueryStringAppend = queryStringAppend; - QueryStringDelete = queryStringDelete; - EscapeBackReferences = escapeBackReferences; - } - - public override void ApplyAction(RewriteContext context, MatchResults ruleMatch, MatchResults condMatch) - { - var pattern = Url.Evaluate(context, ruleMatch, condMatch); - if (EscapeBackReferences) - { - // because escapebackreferences will be encapsulated by the pattern, just escape the pattern - pattern = Uri.EscapeDataString(pattern); - } - context.HttpContext.Response.StatusCode = StatusCode; - - // url can either contain the full url or the path and query - // always add to location header. - // TODO check for false positives - var split = pattern.IndexOf('?'); - if (split >= 0 && QueryStringAppend) - { - var query = context.HttpContext.Request.QueryString.Add( - QueryString.FromUriComponent( - pattern.Substring(split))); - - // not using the response.redirect here because status codes may be 301, 302, 307, 308 - context.HttpContext.Response.Headers[HeaderNames.Location] = pattern.Substring(0, split) + query; - } - else - { - // If the request url has a query string and the target does not, append the query string - // by default. - if (QueryStringDelete) - { - context.HttpContext.Response.Headers[HeaderNames.Location] = pattern; - } - else - { - context.HttpContext.Response.Headers[HeaderNames.Location] = pattern + context.HttpContext.Request.QueryString; - } - } - context.Result = RuleTermination.ResponseComplete; - } - } -} diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/ModRewriteRewriteAction.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/ModRewriteRewriteAction.cs deleted file mode 100644 index 1186f3f8f9..0000000000 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/ModRewriteRewriteAction.cs +++ /dev/null @@ -1,113 +0,0 @@ -// 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; -using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Http.Extensions; - -namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite -{ - public class ModRewriteRewriteAction : UrlAction - { - private readonly string ForwardSlash = "/"; - public RuleTermination Result { get; } - public bool QueryStringAppend { get; } - public bool QueryStringDelete { get; } - public bool EscapeBackReferences { get; } - - public ModRewriteRewriteAction( - RuleTermination result, - Pattern pattern, - bool queryStringAppend, - bool queryStringDelete, - bool escapeBackReferences) - { - Result = result; - Url = pattern; - QueryStringAppend = queryStringAppend; - QueryStringDelete = queryStringDelete; - EscapeBackReferences = escapeBackReferences; - } - - public override void ApplyAction(RewriteContext context, MatchResults ruleMatch, MatchResults condMatch) - { - var pattern = Url.Evaluate(context, ruleMatch, condMatch); - - // TODO PERF, substrings, object creation, etc. - if (pattern.IndexOf("://", StringComparison.Ordinal) >= 0) - { - string scheme; - HostString host; - PathString path; - QueryString query; - FragmentString fragment; - UriHelper.FromAbsolute(pattern, out scheme, out host, out path, out query, out fragment); - - if (query.HasValue) - { - if (QueryStringAppend) - { - context.HttpContext.Request.QueryString = context.HttpContext.Request.QueryString.Add(query); - } - else - { - context.HttpContext.Request.QueryString = query; - } - } - else if (QueryStringDelete) - { - context.HttpContext.Request.QueryString = QueryString.Empty; - } - - context.HttpContext.Request.Scheme = scheme; - context.HttpContext.Request.Host = host; - context.HttpContext.Request.Path = path; - } - else - { - var split = pattern.IndexOf('?'); - if (split >= 0) - { - var path = pattern.Substring(0, split); - if (path.StartsWith(ForwardSlash)) - { - context.HttpContext.Request.Path = PathString.FromUriComponent(path); - } - else - { - context.HttpContext.Request.Path = PathString.FromUriComponent(ForwardSlash + path); - } - - if (QueryStringAppend) - { - context.HttpContext.Request.QueryString = context.HttpContext.Request.QueryString.Add( - QueryString.FromUriComponent( - pattern.Substring(split))); - } - else - { - context.HttpContext.Request.QueryString = QueryString.FromUriComponent( - pattern.Substring(split)); - } - } - else - { - if (pattern.StartsWith(ForwardSlash)) - { - context.HttpContext.Request.Path = PathString.FromUriComponent(pattern); - } - else - { - context.HttpContext.Request.Path = PathString.FromUriComponent(ForwardSlash + pattern); - } - - if (QueryStringDelete) - { - context.HttpContext.Request.QueryString = QueryString.Empty; - } - } - } - context.Result = Result; - } - } -} diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/RuleBuilder.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/RuleBuilder.cs index be83b1f76e..8d578feed8 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/RuleBuilder.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/RuleBuilder.cs @@ -210,13 +210,13 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite { throw new FormatException(Resources.FormatError_InputParserInvalidInteger(statusCode, -1)); } - _action = new ModRewriteRedirectAction(res, pattern, queryStringAppend, queryStringDelete, escapeBackReference); + _action = new RedirectAction(res, pattern, queryStringAppend, queryStringDelete, escapeBackReference); } else { var last = flags.HasFlag(FlagType.End) || flags.HasFlag(FlagType.Last); var termination = last ? RuleTermination.StopRules : RuleTermination.Continue; - _action = new ModRewriteRewriteAction(termination, pattern, queryStringAppend, queryStringDelete, escapeBackReference); + _action = new RewriteAction(termination, pattern, queryStringAppend, queryStringDelete, escapeBackReference); } } } diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/RedirectAction.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/RedirectAction.cs index f73baad942..ef616c16b5 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/RedirectAction.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/RedirectAction.cs @@ -2,7 +2,9 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; +using System.Collections.Generic; using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Rewrite.Internal.PatternSegments; using Microsoft.Net.Http.Headers; namespace Microsoft.AspNetCore.Rewrite.Internal.UrlActions @@ -10,41 +12,80 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlActions public class RedirectAction : UrlAction { public int StatusCode { get; } - public bool AppendQueryString { get; } + public bool QueryStringAppend { get; } + public bool QueryStringDelete { get; } + public bool EscapeBackReferences { get; } - public RedirectAction(int statusCode, Pattern pattern, bool appendQueryString) + public RedirectAction( + int statusCode, + Pattern pattern, + bool queryStringAppend, + bool queryStringDelete, + bool escapeBackReferences) { StatusCode = statusCode; Url = pattern; - AppendQueryString = appendQueryString; + QueryStringAppend = queryStringAppend; + QueryStringDelete = queryStringDelete; + EscapeBackReferences = escapeBackReferences; + } + + public RedirectAction( + int statusCode, + Pattern pattern, + bool queryStringAppend) + : this( + statusCode, + pattern, + queryStringAppend, + queryStringDelete: true, + escapeBackReferences: false) + { + } public override void ApplyAction(RewriteContext context, MatchResults ruleMatch, MatchResults condMatch) { var pattern = Url.Evaluate(context, ruleMatch, condMatch); - context.HttpContext.Response.StatusCode = StatusCode; + var response = context.HttpContext.Response; + if (EscapeBackReferences) + { + // because escapebackreferences will be encapsulated by the pattern, just escape the pattern + pattern = Uri.EscapeDataString(pattern); + } - // TODO IIS guarantees that there will be a leading slash if (pattern.IndexOf("://", StringComparison.Ordinal) == -1 && !pattern.StartsWith("/")) { pattern = '/' + pattern; } + response.StatusCode = StatusCode; + // url can either contain the full url or the path and query // always add to location header. // TODO check for false positives var split = pattern.IndexOf('?'); - if (split >= 0 && AppendQueryString) + if (split >= 0 && QueryStringAppend) { var query = context.HttpContext.Request.QueryString.Add( QueryString.FromUriComponent( pattern.Substring(split))); - // not using the HttpContext.Response.redirect here because status codes may be 301, 302, 307, 308 - context.HttpContext.Response.Headers[HeaderNames.Location] = pattern.Substring(0, split) + query; + + // not using the response.redirect here because status codes may be 301, 302, 307, 308 + response.Headers[HeaderNames.Location] = pattern.Substring(0, split) + query; } else { - context.HttpContext.Response.Headers[HeaderNames.Location] = pattern; + // If the request url has a query string and the target does not, append the query string + // by default. + if (QueryStringDelete) + { + response.Headers[HeaderNames.Location] = pattern; + } + else + { + response.Headers[HeaderNames.Location] = pattern + context.HttpContext.Request.QueryString; + } } context.Result = RuleTermination.ResponseComplete; } diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/RewriteAction.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/RewriteAction.cs index 13683a875f..c95bf909a6 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/RewriteAction.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/RewriteAction.cs @@ -11,24 +11,48 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlActions { private readonly string ForwardSlash = "/"; public RuleTermination Result { get; } - public bool ClearQuery { get; } + public bool QueryStringAppend { get; } + public bool QueryStringDelete { get; } + public bool EscapeBackReferences { get; } - public RewriteAction(RuleTermination result, Pattern pattern, bool clearQuery) + public RewriteAction( + RuleTermination result, + Pattern pattern, + bool queryStringAppend, + bool queryStringDelete, + bool escapeBackReferences) { Result = result; Url = pattern; - ClearQuery = clearQuery; + QueryStringAppend = queryStringAppend; + QueryStringDelete = queryStringDelete; + EscapeBackReferences = escapeBackReferences; + } + + public RewriteAction( + RuleTermination result, + Pattern pattern, + bool queryStringAppend): + this (result, + pattern, + queryStringAppend, + queryStringDelete: false, + escapeBackReferences: false) + { + } public override void ApplyAction(RewriteContext context, MatchResults ruleMatch, MatchResults condMatch) { var pattern = Url.Evaluate(context, ruleMatch, condMatch); - - if (ClearQuery) + var request = context.HttpContext.Request; + if (EscapeBackReferences) { - context.HttpContext.Request.QueryString = QueryString.Empty; + // because escapebackreferences will be encapsulated by the pattern, just escape the pattern + pattern = Uri.EscapeDataString(pattern); } + // TODO PERF, substrings, object creation, etc. if (pattern.IndexOf("://", StringComparison.Ordinal) >= 0) { string scheme; @@ -38,10 +62,25 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlActions FragmentString fragment; UriHelper.FromAbsolute(pattern, out scheme, out host, out path, out query, out fragment); - context.HttpContext.Request.Scheme = scheme; - context.HttpContext.Request.Host = host; - context.HttpContext.Request.Path = path; - context.HttpContext.Request.QueryString = query.Add(context.HttpContext.Request.QueryString); + if (query.HasValue) + { + if (QueryStringAppend) + { + request.QueryString = request.QueryString.Add(query); + } + else + { + request.QueryString = query; + } + } + else if (QueryStringDelete) + { + request.QueryString = QueryString.Empty; + } + + request.Scheme = scheme; + request.Host = host; + request.Path = path; } else { @@ -51,25 +90,39 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlActions var path = pattern.Substring(0, split); if (path.StartsWith(ForwardSlash)) { - context.HttpContext.Request.Path = PathString.FromUriComponent(path); + request.Path = PathString.FromUriComponent(path); } else { - context.HttpContext.Request.Path = PathString.FromUriComponent(ForwardSlash + path); + request.Path = PathString.FromUriComponent(ForwardSlash + path); + } + + if (QueryStringAppend) + { + request.QueryString = request.QueryString.Add( + QueryString.FromUriComponent( + pattern.Substring(split))); + } + else + { + request.QueryString = QueryString.FromUriComponent( + pattern.Substring(split)); } - context.HttpContext.Request.QueryString = context.HttpContext.Request.QueryString.Add( - QueryString.FromUriComponent( - pattern.Substring(split))); } else { if (pattern.StartsWith(ForwardSlash)) { - context.HttpContext.Request.Path = PathString.FromUriComponent(pattern); + request.Path = PathString.FromUriComponent(pattern); } else { - context.HttpContext.Request.Path = PathString.FromUriComponent(ForwardSlash + pattern); + request.Path = PathString.FromUriComponent(ForwardSlash + pattern); + } + + if (QueryStringDelete) + { + request.QueryString = QueryString.Empty; } } } diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/UrlRewriteRuleBuilder.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/UrlRewriteRuleBuilder.cs index bb8f2e8e7c..38d942912c 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/UrlRewriteRuleBuilder.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/UrlRewriteRuleBuilder.cs @@ -5,6 +5,7 @@ using System; using System.Collections.Generic; using System.Text.RegularExpressions; using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Rewrite.Internal.ModRewrite; using Microsoft.AspNetCore.Rewrite.Internal.UrlActions; using Microsoft.AspNetCore.Rewrite.Internal.UrlMatches; @@ -46,7 +47,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite break; case ActionType.Rewrite: _action = new RewriteAction(stopProcessing ? RuleTermination.StopRules : RuleTermination.Continue, - url, clearQuery: !appendQueryString); + url, appendQueryString); break; case ActionType.Redirect: _action = new RedirectAction(statusCode, url, appendQueryString); diff --git a/src/Microsoft.AspNetCore.Rewrite/RewriteOptionsExtensions.cs b/src/Microsoft.AspNetCore.Rewrite/RewriteOptionsExtensions.cs index e0cf65479f..76c4a1e791 100644 --- a/src/Microsoft.AspNetCore.Rewrite/RewriteOptionsExtensions.cs +++ b/src/Microsoft.AspNetCore.Rewrite/RewriteOptionsExtensions.cs @@ -42,11 +42,11 @@ namespace Microsoft.AspNetCore.Rewrite /// /// The Rewrite options. /// The regex string to compare with. - /// If the regex matches, what to replace HttpContext with. + /// If the regex matches, what to replace HttpContext with. /// The Rewrite options. - public static RewriteOptions Rewrite(this RewriteOptions options, string regex, string urlPattern) + public static RewriteOptions Rewrite(this RewriteOptions options, string regex, string replacement) { - return Rewrite(options, regex, urlPattern, stopProcessing: false); + return Rewrite(options, regex, replacement, stopProcessing: false); } /// @@ -54,17 +54,12 @@ namespace Microsoft.AspNetCore.Rewrite /// /// The Rewrite options. /// The regex string to compare with. - /// If the regex matches, what to replace the uri with. + /// If the regex matches, what to replace the uri with. /// If the regex matches, conditionally stop processing other rules. /// The Rewrite options. - public static RewriteOptions Rewrite(this RewriteOptions options, string regex, string urlPattern, bool stopProcessing) + public static RewriteOptions Rewrite(this RewriteOptions options, string regex, string replacement, bool stopProcessing) { - var builder = new UrlRewriteRuleBuilder(); - var pattern = new InputParser().ParseInputString(urlPattern); - - builder.AddUrlMatch(regex); - builder.AddUrlAction(pattern, actionType: ActionType.Rewrite, stopProcessing: stopProcessing); - options.Rules.Add(builder.Build()); + options.Rules.Add(new RewriteRule(regex, replacement, stopProcessing)); return options; } @@ -73,11 +68,11 @@ namespace Microsoft.AspNetCore.Rewrite /// /// The Rewrite options. /// The regex string to compare with. - /// If the regex matches, what to replace the uri with. + /// If the regex matches, what to replace the uri with. /// The Rewrite options. - public static RewriteOptions Redirect(this RewriteOptions options, string regex, string urlPattern) + public static RewriteOptions Redirect(this RewriteOptions options, string regex, string replacement) { - return Redirect(options, regex, urlPattern, statusCode: 302); + return Redirect(options, regex, replacement, statusCode: 302); } /// @@ -85,21 +80,19 @@ namespace Microsoft.AspNetCore.Rewrite /// /// The Rewrite options. /// The regex string to compare with. - /// If the regex matches, what to replace the uri with. + /// If the regex matches, what to replace the uri with. /// The status code to add to the response. /// The Rewrite options. - public static RewriteOptions Redirect(this RewriteOptions options, string regex, string urlPattern, int statusCode) + public static RewriteOptions Redirect(this RewriteOptions options, string regex, string replacement, int statusCode) { - var builder = new UrlRewriteRuleBuilder(); - var pattern = new InputParser().ParseInputString(urlPattern); - - builder.AddUrlMatch(regex); - builder.AddUrlAction(pattern, actionType: ActionType.Redirect, stopProcessing: false); - options.Rules.Add(builder.Build()); + options.Rules.Add(new RedirectRule(regex, replacement, statusCode)); return options; } - // TODO 301 overload + public static RewriteOptions RedirectToHttpsPermanent(this RewriteOptions options) + { + return RedirectToHttps(options, statusCode: 301, sslPort: null); + } /// /// Redirect a request to https if the incoming request is http diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/CodeRules/MiddlewareTests.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/CodeRules/MiddlewareTests.cs index ce73843067..bb284b74a5 100644 --- a/test/Microsoft.AspNetCore.Rewrite.Tests/CodeRules/MiddlewareTests.cs +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/CodeRules/MiddlewareTests.cs @@ -16,7 +16,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.CodeRules [Fact] public async Task CheckRewritePath() { - var options = new RewriteOptions().Rewrite("(.*)", "http://example.com/{R:1}"); + var options = new RewriteOptions().Rewrite("(.*)", "http://example.com/$1"); var builder = new WebHostBuilder() .Configure(app => { @@ -39,7 +39,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.CodeRules [Fact] public async Task CheckRedirectPath() { - var options = new RewriteOptions().Redirect("(.*)","http://example.com/{R:1}", statusCode: 301); + var options = new RewriteOptions().Redirect("(.*)","http://example.com/$1", statusCode: 301); var builder = new WebHostBuilder() .Configure(app => { diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/UrlRewrite/FileParserTests.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/UrlRewrite/FileParserTests.cs index 43a8bac189..4512d9328b 100644 --- a/test/Microsoft.AspNetCore.Rewrite.Tests/UrlRewrite/FileParserTests.cs +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/UrlRewrite/FileParserTests.cs @@ -5,6 +5,7 @@ using System.Collections.Generic; using System.IO; using System.Text.RegularExpressions; using Microsoft.AspNetCore.Rewrite.Internal; +using Microsoft.AspNetCore.Rewrite.Internal.ModRewrite; using Microsoft.AspNetCore.Rewrite.Internal.UrlActions; using Microsoft.AspNetCore.Rewrite.Internal.UrlMatches; using Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite; @@ -146,7 +147,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite ) { return new UrlRewriteRule(name, new RegexMatch(new Regex("^OFF$"), false), conditions, - new RewriteAction(RuleTermination.Continue, new InputParser().ParseInputString(url), clearQuery: false)); + new RewriteAction(RuleTermination.Continue, new InputParser().ParseInputString(url), queryStringAppend: false)); } // TODO make rules comparable? From af2c1acee392229942d63517f37aed33ab3e2052 Mon Sep 17 00:00:00 2001 From: Justin Kotalik Date: Mon, 29 Aug 2016 13:55:44 -0700 Subject: [PATCH 101/307] Adds XML comments and feedback from 1on1 with Nate. --- samples/RewriteSample/Rewrite.txt | 5 +-- samples/RewriteSample/Startup.cs | 25 +++++---------- samples/RewriteSample/UrlRewrite.xml | 7 ++-- ...s => ApacheModRewriteOptionsExtensions.cs} | 13 +++++--- ...s.cs => IISUrlRewriteOptionsExtensions.cs} | 11 ++++--- .../Internal/CodeRules/RewriteRule.cs | 1 - .../Internal/ModRewrite/FlagParser.cs | 2 ++ .../Internal/ModRewrite/RuleBuilder.cs | 25 ++++++--------- .../Internal/ModRewriteRule.cs | 17 ++++------ .../PatternSegments/IsHttpsModSegment.cs | 2 ++ ...IsHttpsSegment.cs => IsHttpsUrlSegment.cs} | 6 ++-- .../Internal/PreAction.cs | 12 ------- .../ChangeCookieAction.cs} | 8 ++--- .../ChangeEnvironmentAction.cs} | 8 ++--- .../Internal/UrlActions/RedirectAction.cs | 2 -- .../Internal/UrlActions/RewriteAction.cs | 1 + .../Internal/UrlRewrite/ServerVariables.cs | 2 +- .../RewriteContext.cs | 20 ++++++++++-- .../RewriteMiddleware.cs | 1 - .../RewriteOptions.cs | 8 ++++- .../RewriteOptionsExtensions.cs | 32 +++++++++++-------- src/Microsoft.AspNetCore.Rewrite/Rule.cs | 11 +++++-- .../RuleTermination.cs | 12 +++++++ .../CodeRules/MiddlewareTests.cs | 6 ++-- .../ModRewrite/ModRewriteMiddlewareTest.cs | 30 ++++++++--------- .../PatternSegments/IsHttpsSegmentTests.cs | 2 +- .../UrlRewrite/MiddleWareTests.cs | 18 +++++------ 27 files changed, 158 insertions(+), 129 deletions(-) rename src/Microsoft.AspNetCore.Rewrite/{ModRewriteOptionsExtensions.cs => ApacheModRewriteOptionsExtensions.cs} (77%) rename src/Microsoft.AspNetCore.Rewrite/{UrlRewriteOptionsExtensions.cs => IISUrlRewriteOptionsExtensions.cs} (80%) rename src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/{IsHttpsSegment.cs => IsHttpsUrlSegment.cs} (69%) delete mode 100644 src/Microsoft.AspNetCore.Rewrite/Internal/PreAction.cs rename src/Microsoft.AspNetCore.Rewrite/Internal/{PreActions/ChangeCookiePreAction.cs => UrlActions/ChangeCookieAction.cs} (58%) rename src/Microsoft.AspNetCore.Rewrite/Internal/{PreActions/ChangeEnvironmentPreAction.cs => UrlActions/ChangeEnvironmentAction.cs} (60%) diff --git a/samples/RewriteSample/Rewrite.txt b/samples/RewriteSample/Rewrite.txt index 23d4948c18..a803234457 100644 --- a/samples/RewriteSample/Rewrite.txt +++ b/samples/RewriteSample/Rewrite.txt @@ -1,3 +1,4 @@ # Rewrite path with additional sub directory -RewriteCond %{QUERY_STRING} id=20 -RewriteRule ^(.*)$ - [G] +RewriteCond %{HTTP_HOST} !^www\.example\.com [NC,OR] +RewriteCond %{SERVER_PORT} !^5000$ +RewriteRule ^/(.*) http://www.example.com/$1 [L,R=302] \ No newline at end of file diff --git a/samples/RewriteSample/Startup.cs b/samples/RewriteSample/Startup.cs index 85918d2459..6a76d5df3e 100644 --- a/samples/RewriteSample/Startup.cs +++ b/samples/RewriteSample/Startup.cs @@ -11,25 +11,16 @@ namespace RewriteSample { public class Startup { - public void Configure(IApplicationBuilder app, IHostingEnvironment hostingEnv) + public void Configure(IApplicationBuilder app, IHostingEnvironment hostingEnvironment) { - // Four main use cases for Rewrite Options. - // 1. Importing from a UrlRewrite file, which are IIS Rewrite rules. - // This file is in xml format, starting with the tag. - // 2. Importing from a mod_rewrite file, which are mod_rewrite rules. - // This file is in standard mod_rewrite format which only contains rewrite information. - // 3. Inline rules in code, where you can specify rules such as rewrites and redirects - // based on certain conditions. Ex: RedirectToHttps will check if the request is https, - // else it will redirect the request with https. - // 4. Functional rules. If a user has a very specific function they would like to implement - // (ex StringReplace) that are easy to implement in code, they can do so by calling - // AddFunctionalRule(Func); - // TODO make this startup do something useful. + var options = new RewriteOptions() + .AddRedirect("(.*)/$", "$1") + .AddRewrite(@"app/(\d+)", "app?id=$1") + .AddRedirectToHttps(302) + .AddIISUrlRewrite(hostingEnvironment, "UrlRewrite.xml") + .AddApacheModRewrite(hostingEnvironment, "Rewrite.txt"); - app.UseRewriter(new RewriteOptions() - .Rewrite(@"foo/(\d+)", "foo?id=$1") - .ImportFromUrlRewrite(hostingEnv, "UrlRewrite.xml") - .ImportFromModRewrite(hostingEnv, "Rewrite.txt")); + app.UseRewriter(options); app.Run(context => context.Response.WriteAsync($"Rewritten Url: {context.Request.Path + context.Request.QueryString}")); } diff --git a/samples/RewriteSample/UrlRewrite.xml b/samples/RewriteSample/UrlRewrite.xml index 9d9e089676..fee831050c 100644 --- a/samples/RewriteSample/UrlRewrite.xml +++ b/samples/RewriteSample/UrlRewrite.xml @@ -1,8 +1,11 @@  - - + + + + + \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Rewrite/ModRewriteOptionsExtensions.cs b/src/Microsoft.AspNetCore.Rewrite/ApacheModRewriteOptionsExtensions.cs similarity index 77% rename from src/Microsoft.AspNetCore.Rewrite/ModRewriteOptionsExtensions.cs rename to src/Microsoft.AspNetCore.Rewrite/ApacheModRewriteOptionsExtensions.cs index 1ad897b90e..e237c7610c 100644 --- a/src/Microsoft.AspNetCore.Rewrite/ModRewriteOptionsExtensions.cs +++ b/src/Microsoft.AspNetCore.Rewrite/ApacheModRewriteOptionsExtensions.cs @@ -8,7 +8,10 @@ using Microsoft.AspNetCore.Rewrite.Internal.ModRewrite; namespace Microsoft.AspNetCore.Rewrite { - public static class ModRewriteOptionsExtensions + /// + /// Apache mod_rewrite extensions on top of the + /// + public static class ApacheModRewriteOptionsExtensions { /// /// Imports rules from a mod_rewrite file and adds the rules to current rules. @@ -16,7 +19,7 @@ namespace Microsoft.AspNetCore.Rewrite /// The Rewrite options. /// The Hosting Environment /// The path to the file containing mod_rewrite rules. - public static RewriteOptions ImportFromModRewrite(this RewriteOptions options, IHostingEnvironment hostingEnvironment, string filePath) + public static RewriteOptions AddApacheModRewrite(this RewriteOptions options, IHostingEnvironment hostingEnvironment, string filePath) { if (options == null) { @@ -36,7 +39,7 @@ namespace Microsoft.AspNetCore.Rewrite var path = Path.Combine(hostingEnvironment.ContentRootPath, filePath); using (var stream = File.OpenRead(path)) { - return options.ImportFromModRewrite(new StreamReader(stream)); + return options.AddApacheModRewrite(new StreamReader(stream)); } } @@ -44,8 +47,8 @@ namespace Microsoft.AspNetCore.Rewrite /// Imports rules from a mod_rewrite file and adds the rules to current rules. /// /// The Rewrite options. - /// Text reader containing a stream of mod_rewrite rules. - public static RewriteOptions ImportFromModRewrite(this RewriteOptions options, TextReader reader) + /// A stream of mod_rewrite rules. + public static RewriteOptions AddApacheModRewrite(this RewriteOptions options, TextReader reader) { if (options == null) { diff --git a/src/Microsoft.AspNetCore.Rewrite/UrlRewriteOptionsExtensions.cs b/src/Microsoft.AspNetCore.Rewrite/IISUrlRewriteOptionsExtensions.cs similarity index 80% rename from src/Microsoft.AspNetCore.Rewrite/UrlRewriteOptionsExtensions.cs rename to src/Microsoft.AspNetCore.Rewrite/IISUrlRewriteOptionsExtensions.cs index 1ca090fdbe..21658e5649 100644 --- a/src/Microsoft.AspNetCore.Rewrite/UrlRewriteOptionsExtensions.cs +++ b/src/Microsoft.AspNetCore.Rewrite/IISUrlRewriteOptionsExtensions.cs @@ -8,7 +8,10 @@ using Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite; namespace Microsoft.AspNetCore.Rewrite { - public static class UrlRewriteOptionsExtensions + /// + /// IIS Url rewrite extensions on top of the + /// + public static class IISUrlRewriteOptionsExtensions { /// /// Imports rules from a mod_rewrite file and adds the rules to current rules. @@ -16,7 +19,7 @@ namespace Microsoft.AspNetCore.Rewrite /// The UrlRewrite options. /// /// The path to the file containing urlrewrite rules. - public static RewriteOptions ImportFromUrlRewrite(this RewriteOptions options, IHostingEnvironment hostingEnvironment, string filePath) + public static RewriteOptions AddIISUrlRewrite(this RewriteOptions options, IHostingEnvironment hostingEnvironment, string filePath) { if (options == null) { @@ -36,7 +39,7 @@ namespace Microsoft.AspNetCore.Rewrite var path = Path.Combine(hostingEnvironment.ContentRootPath, filePath); using (var stream = File.OpenRead(path)) { - return ImportFromUrlRewrite(options, new StreamReader(stream)); + return AddIISUrlRewrite(options, new StreamReader(stream)); } } @@ -45,7 +48,7 @@ namespace Microsoft.AspNetCore.Rewrite /// /// The UrlRewrite options. /// The text reader stream. - public static RewriteOptions ImportFromUrlRewrite(this RewriteOptions options, TextReader reader) + public static RewriteOptions AddIISUrlRewrite(this RewriteOptions options, TextReader reader) { if (options == null) { diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/CodeRules/RewriteRule.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/CodeRules/RewriteRule.cs index 4892a3d467..dd82c6fcde 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/CodeRules/RewriteRule.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/CodeRules/RewriteRule.cs @@ -39,7 +39,6 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.CodeRules { var result = initMatchResults.Result(Replacement); var request = context.HttpContext.Request; - if (result.IndexOf("://", StringComparison.Ordinal) >= 0) { string scheme; diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/FlagParser.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/FlagParser.cs index 895dcb16d4..265c4acf22 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/FlagParser.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/FlagParser.cs @@ -35,6 +35,8 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite { "noescape", FlagType.NoEscape }, { "ns", FlagType.NoSubReq }, { "nosubreq", FlagType.NoSubReq }, + { "or", FlagType.Or }, + { "ornext", FlagType.Or }, { "p", FlagType.Proxy }, { "proxy", FlagType.Proxy }, { "pt", FlagType.PassThrough }, diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/RuleBuilder.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/RuleBuilder.cs index 8d578feed8..ece600a965 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/RuleBuilder.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/RuleBuilder.cs @@ -4,7 +4,6 @@ using System; using System.Collections.Generic; using System.Text.RegularExpressions; -using Microsoft.AspNetCore.Rewrite.Internal.PreActions; using Microsoft.AspNetCore.Rewrite.Internal.UrlActions; using Microsoft.AspNetCore.Rewrite.Internal.UrlMatches; @@ -13,19 +12,18 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite public class RuleBuilder { private IList _conditions; - private UrlAction _action; + private IList _actions = new List(); private UrlMatch _match; - private List _preActions; private readonly TimeSpan RegexTimeout = TimeSpan.FromMilliseconds(1); public ModRewriteRule Build() { - if (_action == null || _match == null) + if (_actions.Count == 0 || _match == null) { throw new InvalidOperationException("Cannot create ModRewriteRule without action and match"); } - return new ModRewriteRule(_match, _conditions, _action, _preActions); + return new ModRewriteRule(_match, _conditions, _actions); } public void AddRule(string rule) @@ -169,31 +167,26 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite Flags flags) { // first create pre conditions - if (_preActions == null) - { - _preActions = new List(); - } - string flag; if (flags.GetValue(FlagType.Cookie, out flag)) { // parse cookie - _preActions.Add(new ChangeCookiePreAction(flag)); + _actions.Add(new ChangeCookieAction(flag)); } if (flags.GetValue(FlagType.Env, out flag)) { // parse env - _preActions.Add(new ChangeEnvironmentPreAction(flag)); + _actions.Add(new ChangeEnvironmentAction(flag)); } if (flags.HasFlag(FlagType.Forbidden)) { - _action = new ForbiddenAction(); + _actions.Add(new ForbiddenAction()); } else if (flags.HasFlag(FlagType.Gone)) { - _action = new GoneAction(); + _actions.Add(new GoneAction()); } else { @@ -210,13 +203,13 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite { throw new FormatException(Resources.FormatError_InputParserInvalidInteger(statusCode, -1)); } - _action = new RedirectAction(res, pattern, queryStringAppend, queryStringDelete, escapeBackReference); + _actions.Add(new RedirectAction(res, pattern, queryStringAppend, queryStringDelete, escapeBackReference)); } else { var last = flags.HasFlag(FlagType.End) || flags.HasFlag(FlagType.Last); var termination = last ? RuleTermination.StopRules : RuleTermination.Continue; - _action = new RewriteAction(termination, pattern, queryStringAppend, queryStringDelete, escapeBackReference); + _actions.Add(new RewriteAction(termination, pattern, queryStringAppend, queryStringDelete, escapeBackReference)); } } } diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewriteRule.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewriteRule.cs index 3a2bcb21dd..11daadce68 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewriteRule.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewriteRule.cs @@ -10,15 +10,13 @@ namespace Microsoft.AspNetCore.Rewrite.Internal { public UrlMatch InitialMatch { get; } public IList Conditions { get; } - public UrlAction Action { get; } - public IList PreActions { get; } + public IList Actions { get; } - public ModRewriteRule(UrlMatch initialMatch, IList conditions, UrlAction urlAction, IList preActions) + public ModRewriteRule(UrlMatch initialMatch, IList conditions, IList urlActions) { Conditions = conditions; InitialMatch = initialMatch; - Action = urlAction; - PreActions = preActions; + Actions = urlActions; } public override void ApplyRule(RewriteContext context) @@ -46,12 +44,11 @@ namespace Microsoft.AspNetCore.Rewrite.Internal // At this point, we know our rule passed, first apply pre conditions, // which can modify things like the cookie or env, and then apply the action context.Logger?.ModRewriteMatchedRule(); - foreach (var preAction in PreActions) - { - preAction.ApplyAction(context.HttpContext, initMatchRes, condMatchRes); - } - Action.ApplyAction(context, initMatchRes, condMatchRes); + foreach (var action in Actions) + { + action.ApplyAction(context, initMatchRes, condMatchRes); + } } } } diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/IsHttpsModSegment.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/IsHttpsModSegment.cs index c5a72eef55..3b3f39339d 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/IsHttpsModSegment.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/IsHttpsModSegment.cs @@ -5,6 +5,8 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.PatternSegments { public class IsHttpsModSegment : PatternSegment { + // Note: Mod rewrite pattern matches on lower case "on" and "off" + // while IIS looks for capitalized "ON" and "OFF" public override string Evaluate(RewriteContext context, MatchResults ruleMatch, MatchResults condMatch) { return context.HttpContext.Request.IsHttps ? "on" : "off"; diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/IsHttpsSegment.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/IsHttpsUrlSegment.cs similarity index 69% rename from src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/IsHttpsSegment.cs rename to src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/IsHttpsUrlSegment.cs index be940dd284..21beccc746 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/IsHttpsSegment.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/IsHttpsUrlSegment.cs @@ -3,8 +3,10 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.PatternSegments { - public class IsHttpsSegment : PatternSegment - { + public class IsHttpsUrlSegment : PatternSegment + { + // Note: Mod rewrite pattern matches on lower case "on" and "off" + // while IIS looks for capitalized "ON" and "OFF" public override string Evaluate(RewriteContext context, MatchResults ruleMatch, MatchResults condMatch) { return context.HttpContext.Request.IsHttps ? "ON" : "OFF"; diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/PreAction.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/PreAction.cs deleted file mode 100644 index e86bc03f3c..0000000000 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/PreAction.cs +++ /dev/null @@ -1,12 +0,0 @@ -// 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 Microsoft.AspNetCore.Http; - -namespace Microsoft.AspNetCore.Rewrite.Internal -{ - public abstract class PreAction - { - public abstract void ApplyAction(HttpContext context, MatchResults ruleMatch, MatchResults condMatch); - } -} diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/PreActions/ChangeCookiePreAction.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/ChangeCookieAction.cs similarity index 58% rename from src/Microsoft.AspNetCore.Rewrite/Internal/PreActions/ChangeCookiePreAction.cs rename to src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/ChangeCookieAction.cs index a08506158f..3f666abb79 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/PreActions/ChangeCookiePreAction.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/ChangeCookieAction.cs @@ -4,17 +4,17 @@ using System; using Microsoft.AspNetCore.Http; -namespace Microsoft.AspNetCore.Rewrite.Internal.PreActions +namespace Microsoft.AspNetCore.Rewrite.Internal.UrlActions { - public class ChangeCookiePreAction : PreAction + public class ChangeCookieAction : UrlAction { - public ChangeCookiePreAction(string cookie) + public ChangeCookieAction(string cookie) { // TODO throw new NotImplementedException(cookie); } - public override void ApplyAction(HttpContext context, MatchResults ruleMatch, MatchResults condMatch) + public override void ApplyAction(RewriteContext context, MatchResults ruleMatch, MatchResults condMatch) { // modify the cookies diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/PreActions/ChangeEnvironmentPreAction.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/ChangeEnvironmentAction.cs similarity index 60% rename from src/Microsoft.AspNetCore.Rewrite/Internal/PreActions/ChangeEnvironmentPreAction.cs rename to src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/ChangeEnvironmentAction.cs index 4e79c0f300..09710350e4 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/PreActions/ChangeEnvironmentPreAction.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/ChangeEnvironmentAction.cs @@ -4,17 +4,17 @@ using System; using Microsoft.AspNetCore.Http; -namespace Microsoft.AspNetCore.Rewrite.Internal.PreActions +namespace Microsoft.AspNetCore.Rewrite.Internal.UrlActions { - public class ChangeEnvironmentPreAction : PreAction + public class ChangeEnvironmentAction : UrlAction { - public ChangeEnvironmentPreAction(string env) + public ChangeEnvironmentAction(string env) { // TODO throw new NotImplementedException(); } - public override void ApplyAction(HttpContext context, MatchResults ruleMatch, MatchResults condMatch) + public override void ApplyAction(RewriteContext context, MatchResults ruleMatch, MatchResults condMatch) { // Do stuff to modify the env throw new NotImplementedException(); diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/RedirectAction.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/RedirectAction.cs index ef616c16b5..9e6b636205 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/RedirectAction.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/RedirectAction.cs @@ -41,7 +41,6 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlActions queryStringDelete: true, escapeBackReferences: false) { - } public override void ApplyAction(RewriteContext context, MatchResults ruleMatch, MatchResults condMatch) @@ -58,7 +57,6 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlActions { pattern = '/' + pattern; } - response.StatusCode = StatusCode; // url can either contain the full url or the path and query diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/RewriteAction.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/RewriteAction.cs index c95bf909a6..efb8468ed3 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/RewriteAction.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/RewriteAction.cs @@ -46,6 +46,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlActions { var pattern = Url.Evaluate(context, ruleMatch, condMatch); var request = context.HttpContext.Request; + if (EscapeBackReferences) { // because escapebackreferences will be encapsulated by the pattern, just escape the pattern diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/ServerVariables.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/ServerVariables.cs index 8a0fad4150..0bb2764aa4 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/ServerVariables.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/ServerVariables.cs @@ -37,7 +37,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite case "HTTP_URL": return new UrlSegment(); case "HTTPS": - return new IsHttpsSegment(); + return new IsHttpsUrlSegment(); case "LOCAL_ADDR": return new LocalAddressSegment(); case "HTTP_PROXY_CONNECTION": diff --git a/src/Microsoft.AspNetCore.Rewrite/RewriteContext.cs b/src/Microsoft.AspNetCore.Rewrite/RewriteContext.cs index 76dd9c6989..d7dec645f7 100644 --- a/src/Microsoft.AspNetCore.Rewrite/RewriteContext.cs +++ b/src/Microsoft.AspNetCore.Rewrite/RewriteContext.cs @@ -9,15 +9,31 @@ using Microsoft.Extensions.Logging; namespace Microsoft.AspNetCore.Rewrite { /// - /// The UrlRewrite Context contains the HttpContext of the request, the file provider, and the logger. - /// There is also a shared string builder across the application of rules. + /// A context object for /// public class RewriteContext { + /// + /// Gets and sets the + /// public HttpContext HttpContext { get; set; } + + /// + /// Gets and sets the File Provider for file and directory checks. + /// public IFileProvider StaticFileProvider { get; set; } + + /// + /// Gets and sets the logger + /// public ILogger Logger { get; set; } + + /// + /// A shared result that is set appropriately by each rule for the next action that + /// should be take. See + /// public RuleTermination Result { get; set; } + // PERF: share the same string builder per request internal StringBuilder Builder { get; set; } = new StringBuilder(64); } diff --git a/src/Microsoft.AspNetCore.Rewrite/RewriteMiddleware.cs b/src/Microsoft.AspNetCore.Rewrite/RewriteMiddleware.cs index 10e1a0a1a1..d02a28a6db 100644 --- a/src/Microsoft.AspNetCore.Rewrite/RewriteMiddleware.cs +++ b/src/Microsoft.AspNetCore.Rewrite/RewriteMiddleware.cs @@ -5,7 +5,6 @@ using System; using System.Threading.Tasks; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Rewrite.Internal; using Microsoft.AspNetCore.Rewrite.Logging; using Microsoft.Extensions.FileProviders; using Microsoft.Extensions.Logging; diff --git a/src/Microsoft.AspNetCore.Rewrite/RewriteOptions.cs b/src/Microsoft.AspNetCore.Rewrite/RewriteOptions.cs index 270c7a9313..f4370cabb4 100644 --- a/src/Microsoft.AspNetCore.Rewrite/RewriteOptions.cs +++ b/src/Microsoft.AspNetCore.Rewrite/RewriteOptions.cs @@ -11,8 +11,14 @@ namespace Microsoft.AspNetCore.Rewrite /// public class RewriteOptions { - // TODO doc comments + /// + /// A list of that will be applied in order upon a request. + /// public IList Rules { get; } = new List(); + + /// + /// Gets and sets the File Provider for file and directory checks. + /// public IFileProvider StaticFileProvider { get; set; } } } diff --git a/src/Microsoft.AspNetCore.Rewrite/RewriteOptionsExtensions.cs b/src/Microsoft.AspNetCore.Rewrite/RewriteOptionsExtensions.cs index 76c4a1e791..4d89e13d3c 100644 --- a/src/Microsoft.AspNetCore.Rewrite/RewriteOptionsExtensions.cs +++ b/src/Microsoft.AspNetCore.Rewrite/RewriteOptionsExtensions.cs @@ -44,9 +44,9 @@ namespace Microsoft.AspNetCore.Rewrite /// The regex string to compare with. /// If the regex matches, what to replace HttpContext with. /// The Rewrite options. - public static RewriteOptions Rewrite(this RewriteOptions options, string regex, string replacement) + public static RewriteOptions AddRewrite(this RewriteOptions options, string regex, string replacement) { - return Rewrite(options, regex, replacement, stopProcessing: false); + return AddRewrite(options, regex, replacement, stopProcessing: false); } /// @@ -57,7 +57,7 @@ namespace Microsoft.AspNetCore.Rewrite /// If the regex matches, what to replace the uri with. /// If the regex matches, conditionally stop processing other rules. /// The Rewrite options. - public static RewriteOptions Rewrite(this RewriteOptions options, string regex, string replacement, bool stopProcessing) + public static RewriteOptions AddRewrite(this RewriteOptions options, string regex, string replacement, bool stopProcessing) { options.Rules.Add(new RewriteRule(regex, replacement, stopProcessing)); return options; @@ -70,9 +70,9 @@ namespace Microsoft.AspNetCore.Rewrite /// The regex string to compare with. /// If the regex matches, what to replace the uri with. /// The Rewrite options. - public static RewriteOptions Redirect(this RewriteOptions options, string regex, string replacement) + public static RewriteOptions AddRedirect(this RewriteOptions options, string regex, string replacement) { - return Redirect(options, regex, replacement, statusCode: 302); + return AddRedirect(options, regex, replacement, statusCode: 302); } /// @@ -83,24 +83,30 @@ namespace Microsoft.AspNetCore.Rewrite /// If the regex matches, what to replace the uri with. /// The status code to add to the response. /// The Rewrite options. - public static RewriteOptions Redirect(this RewriteOptions options, string regex, string replacement, int statusCode) + public static RewriteOptions AddRedirect(this RewriteOptions options, string regex, string replacement, int statusCode) { options.Rules.Add(new RedirectRule(regex, replacement, statusCode)); return options; } - public static RewriteOptions RedirectToHttpsPermanent(this RewriteOptions options) + /// + /// Redirect a request to https if the incoming request is http, with returning a 301 + /// status code for permanently redirected. + /// + /// + /// + public static RewriteOptions AddRedirectToHttpsPermanent(this RewriteOptions options) { - return RedirectToHttps(options, statusCode: 301, sslPort: null); + return AddRedirectToHttps(options, statusCode: 301, sslPort: null); } /// /// Redirect a request to https if the incoming request is http /// /// The Rewrite options. - public static RewriteOptions RedirectToHttps(this RewriteOptions options) + public static RewriteOptions AddRedirectToHttps(this RewriteOptions options) { - return RedirectToHttps(options, statusCode: 302, sslPort: null); + return AddRedirectToHttps(options, statusCode: 302, sslPort: null); } /// @@ -108,9 +114,9 @@ namespace Microsoft.AspNetCore.Rewrite /// /// The Rewrite options. /// The status code to add to the response. - public static RewriteOptions RedirectToHttps(this RewriteOptions options, int statusCode) + public static RewriteOptions AddRedirectToHttps(this RewriteOptions options, int statusCode) { - return RedirectToHttps(options, statusCode, sslPort: null); + return AddRedirectToHttps(options, statusCode, sslPort: null); } /// @@ -119,7 +125,7 @@ namespace Microsoft.AspNetCore.Rewrite /// The Rewrite options. /// The status code to add to the response. /// The SSL port to add to the response. - public static RewriteOptions RedirectToHttps(this RewriteOptions options, int statusCode, int? sslPort) + public static RewriteOptions AddRedirectToHttps(this RewriteOptions options, int statusCode, int? sslPort) { options.Rules.Add(new RedirectToHttpsRule { StatusCode = statusCode, SSLPort = sslPort }); return options; diff --git a/src/Microsoft.AspNetCore.Rewrite/Rule.cs b/src/Microsoft.AspNetCore.Rewrite/Rule.cs index 90eef4b050..22b5a253e0 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Rule.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Rule.cs @@ -3,10 +3,17 @@ namespace Microsoft.AspNetCore.Rewrite { - // make this public and doc comements - // caller must set the context.Results field appropriately in rule. + /// + /// Represents an abstract rule. + /// public abstract class Rule { + /// + /// Applies the rule. + /// Implementations of ApplyRule should set the value for RewriteContext.Results + /// (defaults to RuleTermination.Continue) + /// + /// public abstract void ApplyRule(RewriteContext context); } } diff --git a/src/Microsoft.AspNetCore.Rewrite/RuleTermination.cs b/src/Microsoft.AspNetCore.Rewrite/RuleTermination.cs index dff816d9cc..70f5c9f39f 100644 --- a/src/Microsoft.AspNetCore.Rewrite/RuleTermination.cs +++ b/src/Microsoft.AspNetCore.Rewrite/RuleTermination.cs @@ -3,10 +3,22 @@ namespace Microsoft.AspNetCore.Rewrite { + /// + /// An enum representing the result of a rule. + /// public enum RuleTermination { + /// + /// Default value, continue applying rules. + /// Continue, + /// + /// Redirect occured, should send back new rewritten url. + /// ResponseComplete, + /// + /// Stop applying rules and send context to the next middleware + /// StopRules } } diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/CodeRules/MiddlewareTests.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/CodeRules/MiddlewareTests.cs index bb284b74a5..1e4e10beb3 100644 --- a/test/Microsoft.AspNetCore.Rewrite.Tests/CodeRules/MiddlewareTests.cs +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/CodeRules/MiddlewareTests.cs @@ -16,7 +16,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.CodeRules [Fact] public async Task CheckRewritePath() { - var options = new RewriteOptions().Rewrite("(.*)", "http://example.com/$1"); + var options = new RewriteOptions().AddRewrite("(.*)", "http://example.com/$1"); var builder = new WebHostBuilder() .Configure(app => { @@ -39,7 +39,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.CodeRules [Fact] public async Task CheckRedirectPath() { - var options = new RewriteOptions().Redirect("(.*)","http://example.com/$1", statusCode: 301); + var options = new RewriteOptions().AddRedirect("(.*)","http://example.com/$1", statusCode: 301); var builder = new WebHostBuilder() .Configure(app => { @@ -55,7 +55,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.CodeRules [Fact] public async Task CheckRedirectToHttps() { - var options = new RewriteOptions().RedirectToHttps(statusCode: 301); + var options = new RewriteOptions().AddRedirectToHttps(statusCode: 301); var builder = new WebHostBuilder() .Configure(app => { diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/ModRewrite/ModRewriteMiddlewareTest.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/ModRewrite/ModRewriteMiddlewareTest.cs index 7b358c265f..2fd055a7cb 100644 --- a/test/Microsoft.AspNetCore.Rewrite.Tests/ModRewrite/ModRewriteMiddlewareTest.cs +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/ModRewrite/ModRewriteMiddlewareTest.cs @@ -17,7 +17,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.ModRewrite [Fact] public async Task Invoke_RewritePathWhenMatching() { - var options = new RewriteOptions().ImportFromModRewrite(new StringReader("RewriteRule /hey/(.*) /$1 ")); + var options = new RewriteOptions().AddApacheModRewrite(new StringReader("RewriteRule /hey/(.*) /$1 ")); var builder = new WebHostBuilder() .Configure(app => { @@ -34,8 +34,8 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.ModRewrite [Fact] public async Task Invoke_RewritePathTerminatesOnFirstSuccessOfRule() { - var options = new RewriteOptions().ImportFromModRewrite(new StringReader("RewriteRule /hey/(.*) /$1 [L]")) - .ImportFromModRewrite(new StringReader("RewriteRule /hello /what")); + var options = new RewriteOptions().AddApacheModRewrite(new StringReader("RewriteRule /hey/(.*) /$1 [L]")) + .AddApacheModRewrite(new StringReader("RewriteRule /hello /what")); var builder = new WebHostBuilder() .Configure(app => { @@ -52,8 +52,8 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.ModRewrite [Fact] public async Task Invoke_RewritePathDoesNotTerminateOnFirstSuccessOfRule() { - var options = new RewriteOptions().ImportFromModRewrite(new StringReader("RewriteRule /hey/(.*) /$1")) - .ImportFromModRewrite(new StringReader("RewriteRule /hello /what")); + var options = new RewriteOptions().AddApacheModRewrite(new StringReader("RewriteRule /hey/(.*) /$1")) + .AddApacheModRewrite(new StringReader("RewriteRule /hello /what")); var builder = new WebHostBuilder() .Configure(app => { @@ -70,7 +70,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.ModRewrite [Fact] public async Task Invoke_ShouldIgnoreComments() { - var options = new RewriteOptions().ImportFromModRewrite(new StringReader("#RewriteRule ^/hey/(.*) /$1 ")); + var options = new RewriteOptions().AddApacheModRewrite(new StringReader("#RewriteRule ^/hey/(.*) /$1 ")); var builder = new WebHostBuilder() .Configure(app => { @@ -87,7 +87,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.ModRewrite [Fact] public async Task Invoke_ShouldRewriteHomepage() { - var options = new RewriteOptions().ImportFromModRewrite(new StringReader(@"RewriteRule ^/$ /homepage.html")); + var options = new RewriteOptions().AddApacheModRewrite(new StringReader(@"RewriteRule ^/$ /homepage.html")); var builder = new WebHostBuilder() .Configure(app => { @@ -104,7 +104,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.ModRewrite [Fact] public async Task Invoke_ShouldIgnorePorts() { - var options = new RewriteOptions().ImportFromModRewrite(new StringReader(@"RewriteRule ^/$ /homepage.html")); + var options = new RewriteOptions().AddApacheModRewrite(new StringReader(@"RewriteRule ^/$ /homepage.html")); var builder = new WebHostBuilder() .Configure(app => { @@ -121,7 +121,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.ModRewrite [Fact] public async Task Invoke_HandleNegatedRewriteRules() { - var options = new RewriteOptions().ImportFromModRewrite(new StringReader(@"RewriteRule !^/$ /homepage.html")); + var options = new RewriteOptions().AddApacheModRewrite(new StringReader(@"RewriteRule !^/$ /homepage.html")); var builder = new WebHostBuilder() .Configure(app => { @@ -138,7 +138,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.ModRewrite [Fact] public async Task Invoke_BackReferencesShouldBeApplied() { - var options = new RewriteOptions().ImportFromModRewrite(new StringReader(@"RewriteRule (.*)\.aspx $1.php")); + var options = new RewriteOptions().AddApacheModRewrite(new StringReader(@"RewriteRule (.*)\.aspx $1.php")); var builder = new WebHostBuilder() .Configure(app => { @@ -161,7 +161,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.ModRewrite [InlineData("http://www.foo.org/homepage.ASPX", @"RewriteRule (.*)\.aspx $1.php [nocase]", "/homepage.php")] public async Task Invoke_ShouldHandleFlagNoCase(string url, string rule, string expected) { - var options = new RewriteOptions().ImportFromModRewrite(new StringReader(rule)); + var options = new RewriteOptions().AddApacheModRewrite(new StringReader(rule)); var builder = new WebHostBuilder() .Configure(app => { @@ -179,7 +179,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.ModRewrite public async Task Invoke_CheckFullUrlWithOnlyPath() { var options = new RewriteOptions() - .ImportFromModRewrite(new StringReader(@"RewriteRule (.+) http://www.example.com$1/")); + .AddApacheModRewrite(new StringReader(@"RewriteRule (.+) http://www.example.com$1/")); var builder = new WebHostBuilder() .Configure(app => { @@ -197,7 +197,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.ModRewrite public async Task Invoke_CheckFullUrlWithUFlag() { var options = new RewriteOptions() - .ImportFromModRewrite(new StringReader(@"RewriteRule (.+) http://www.example.com$1/")); + .AddApacheModRewrite(new StringReader(@"RewriteRule (.+) http://www.example.com$1/")); var builder = new WebHostBuilder() .Configure(app => { @@ -215,7 +215,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.ModRewrite public async Task Invoke_CheckModFileConditions() { var options = new RewriteOptions() - .ImportFromModRewrite(new StringReader(@"RewriteRule (.+) http://www.example.com$1/")); + .AddApacheModRewrite(new StringReader(@"RewriteRule (.+) http://www.example.com$1/")); var builder = new WebHostBuilder() .Configure(app => { @@ -234,7 +234,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.ModRewrite public async Task Invoke_EnsureHttps(string input) { var options = new RewriteOptions() - .ImportFromModRewrite(new StringReader("RewriteCond %{REQUEST_URI} /foo/ \nRewriteCond %{HTTPS} !on \nRewriteRule ^(.*)$ https://www.example.com$1 [R=301,L]")); + .AddApacheModRewrite(new StringReader("RewriteCond %{REQUEST_URI} /foo/ \nRewriteCond %{HTTPS} !on \nRewriteRule ^(.*)$ https://www.example.com$1 [R=301,L]")); var builder = new WebHostBuilder() .Configure(app => { diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/PatternSegments/IsHttpsSegmentTests.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/PatternSegments/IsHttpsSegmentTests.cs index c3d3b6eccc..789f94e670 100644 --- a/test/Microsoft.AspNetCore.Rewrite.Tests/PatternSegments/IsHttpsSegmentTests.cs +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/PatternSegments/IsHttpsSegmentTests.cs @@ -16,7 +16,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.PatternSegments public void IsHttps_AssertCorrectBehaviorWhenProvidedHttpContext(string input, string expected) { // Arrange - var segement = new IsHttpsSegment(); + var segement = new IsHttpsUrlSegment(); var context = new RewriteContext { HttpContext = new DefaultHttpContext() }; context.HttpContext.Request.Scheme = input; diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/UrlRewrite/MiddleWareTests.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/UrlRewrite/MiddleWareTests.cs index eadddbd60d..af460e9f13 100644 --- a/test/Microsoft.AspNetCore.Rewrite.Tests/UrlRewrite/MiddleWareTests.cs +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/UrlRewrite/MiddleWareTests.cs @@ -18,7 +18,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite [Fact] public async Task Invoke_RedirectPathToPathAndQuery() { - var options = new RewriteOptions().ImportFromUrlRewrite(new StringReader(@" + var options = new RewriteOptions().AddIISUrlRewrite(new StringReader(@" @@ -42,7 +42,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite [Fact] public async Task Invoke_RewritePathToPathAndQuery() { - var options = new RewriteOptions().ImportFromUrlRewrite(new StringReader(@" + var options = new RewriteOptions().AddIISUrlRewrite(new StringReader(@" @@ -66,7 +66,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite [Fact] public async Task Invoke_RewriteBasedOnQueryStringParameters() { - var options = new RewriteOptions().ImportFromUrlRewrite(new StringReader(@" + var options = new RewriteOptions().AddIISUrlRewrite(new StringReader(@" @@ -94,7 +94,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite [Fact] public async Task Invoke_RedirectToLowerCase() { - var options = new RewriteOptions().ImportFromUrlRewrite(new StringReader(@" + var options = new RewriteOptions().AddIISUrlRewrite(new StringReader(@" @@ -118,7 +118,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite [Fact] public async Task Invoke_RedirectRemoveTrailingSlash() { - var options = new RewriteOptions().ImportFromUrlRewrite(new StringReader(@" + var options = new RewriteOptions().AddIISUrlRewrite(new StringReader(@" @@ -145,7 +145,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite [Fact] public async Task Invoke_RedirectAddTrailingSlash() { - var options = new RewriteOptions().ImportFromUrlRewrite(new StringReader(@" + var options = new RewriteOptions().AddIISUrlRewrite(new StringReader(@" @@ -172,7 +172,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite [Fact] public async Task Invoke_RedirectToHttps() { - var options = new RewriteOptions().ImportFromUrlRewrite(new StringReader(@" + var options = new RewriteOptions().AddIISUrlRewrite(new StringReader(@" @@ -198,7 +198,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite [Fact] public async Task Invoke_RewriteToHttps() { - var options = new RewriteOptions().ImportFromUrlRewrite(new StringReader(@" + var options = new RewriteOptions().AddIISUrlRewrite(new StringReader(@" @@ -230,7 +230,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite [Fact] public async Task Invoke_ReverseProxyToAnotherSite() { - var options = new RewriteOptions().ImportFromUrlRewrite(new StringReader(@" + var options = new RewriteOptions().AddIISUrlRewrite(new StringReader(@" From 65e7f7f44b5bf86d11e86e3cee70b85c56f23e76 Mon Sep 17 00:00:00 2001 From: Justin Kotalik Date: Wed, 31 Aug 2016 14:37:33 -0700 Subject: [PATCH 102/307] Removes startsWith in favor of array index, guarantee that string is non-empty in someplaces --- .../Internal/CodeRules/RedirectRule.cs | 24 ++++++-- .../Internal/CodeRules/RewriteRule.cs | 34 +++++++++--- .../Internal/ModRewrite/FlagParser.cs | 3 +- .../Internal/ModRewrite/RuleRegexParser.cs | 2 +- .../Internal/UrlActions/RedirectAction.cs | 9 ++- .../Internal/UrlActions/RewriteAction.cs | 17 ++++-- .../UrlRewrite/UrlRewriteFileParser.cs | 13 ++++- .../UrlRewrite/UrlRewriteRuleBuilder.cs | 2 +- .../CodeRules/MiddlewareTests.cs | 35 ++++++++++++ .../ModRewrite/ModRewriteMiddlewareTest.cs | 38 +++++++++++++ .../FormatExceptionHandlingTests.cs | 10 ++++ .../UrlRewrite/MiddleWareTests.cs | 55 +++++++++++++++++++ 12 files changed, 218 insertions(+), 24 deletions(-) diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/CodeRules/RedirectRule.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/CodeRules/RedirectRule.cs index 7c33bd426f..90ddf74273 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/CodeRules/RedirectRule.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/CodeRules/RedirectRule.cs @@ -16,6 +16,16 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.CodeRules public int StatusCode { get; } public RedirectRule(string regex, string replacement, int statusCode) { + if (string.IsNullOrEmpty(regex)) + { + throw new ArgumentNullException(nameof(regex)); + } + + if (string.IsNullOrEmpty(replacement)) + { + throw new ArgumentNullException(nameof(replacement)); + } + InitialMatch = new Regex(regex, RegexOptions.Compiled | RegexOptions.CultureInvariant, _regexTimeout); Replacement = replacement; StatusCode = statusCode; @@ -38,9 +48,17 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.CodeRules { var newPath = initMatchResults.Result(Replacement); var response = context.HttpContext.Response; - response.StatusCode = StatusCode; - if (newPath.IndexOf("://", StringComparison.Ordinal) == -1 && !newPath.StartsWith("/")) + response.StatusCode = StatusCode; + context.Result = RuleTermination.ResponseComplete; + + if (string.IsNullOrEmpty(newPath)) + { + response.Headers[HeaderNames.Location] = "/"; + return; + } + + if (newPath.IndexOf("://", StringComparison.Ordinal) == -1 && newPath[0] != '/') { newPath = '/' + newPath; } @@ -58,8 +76,6 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.CodeRules { response.Headers[HeaderNames.Location] = newPath; } - - context.Result = RuleTermination.ResponseComplete; } } } diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/CodeRules/RewriteRule.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/CodeRules/RewriteRule.cs index dd82c6fcde..d930a2b279 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/CodeRules/RewriteRule.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/CodeRules/RewriteRule.cs @@ -10,13 +10,22 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.CodeRules { public class RewriteRule : Rule { - private readonly string ForwardSlash = "/"; private readonly TimeSpan _regexTimeout = TimeSpan.FromSeconds(1); public Regex InitialMatch { get; } public string Replacement { get; } public bool StopProcessing { get; } public RewriteRule(string regex, string replacement, bool stopProcessing) { + if (string.IsNullOrEmpty(regex)) + { + throw new ArgumentNullException(nameof(regex)); + } + + if (string.IsNullOrEmpty(replacement)) + { + throw new ArgumentNullException(nameof(replacement)); + } + InitialMatch = new Regex(regex, RegexOptions.Compiled | RegexOptions.CultureInvariant, _regexTimeout); Replacement = replacement; StopProcessing = stopProcessing; @@ -39,6 +48,17 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.CodeRules { var result = initMatchResults.Result(Replacement); var request = context.HttpContext.Request; + + if (StopProcessing) + { + context.Result = RuleTermination.StopRules; + } + + if (string.IsNullOrEmpty(result)) + { + result = "/"; + } + if (result.IndexOf("://", StringComparison.Ordinal) >= 0) { string scheme; @@ -59,13 +79,13 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.CodeRules if (split >= 0) { var newPath = result.Substring(0, split); - if (newPath.StartsWith(ForwardSlash)) + if (newPath[0] == '/') { request.Path = PathString.FromUriComponent(newPath); } else { - request.Path = PathString.FromUriComponent(ForwardSlash + newPath); + request.Path = PathString.FromUriComponent('/' + newPath); } request.QueryString = request.QueryString.Add( QueryString.FromUriComponent( @@ -73,20 +93,16 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.CodeRules } else { - if (result.StartsWith(ForwardSlash)) + if (result[0] == '/') { request.Path = PathString.FromUriComponent(result); } else { - request.Path = PathString.FromUriComponent(ForwardSlash + result); + request.Path = PathString.FromUriComponent('/' + result); } } } - if (StopProcessing) - { - context.Result = RuleTermination.StopRules; - } } } } diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/FlagParser.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/FlagParser.cs index 265c4acf22..0888f614ab 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/FlagParser.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/FlagParser.cs @@ -63,7 +63,8 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite } // Check that flags are contained within [] - if (!(flagString.StartsWith("[") && flagString.EndsWith("]"))) + // Guaranteed to have a length of at least 1 here, so this will never throw for indexing. + if (!(flagString[0] == '[' && flagString[flagString.Length - 1] == ']')) { throw new FormatException("Flags should start and end with square brackets: [flags]"); } diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/RuleRegexParser.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/RuleRegexParser.cs index bdc6273d02..e9cbb8a36c 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/RuleRegexParser.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/RuleRegexParser.cs @@ -13,7 +13,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite { throw new FormatException("Regex expression is null"); } - if (regex.StartsWith("!")) + if (regex[0] == '!') { return new ParsedModRewriteInput { Invert = true, Operand = regex.Substring(1) }; } diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/RedirectAction.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/RedirectAction.cs index 9e6b636205..dfac28fc80 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/RedirectAction.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/RedirectAction.cs @@ -53,7 +53,14 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlActions pattern = Uri.EscapeDataString(pattern); } - if (pattern.IndexOf("://", StringComparison.Ordinal) == -1 && !pattern.StartsWith("/")) + if (string.IsNullOrEmpty(pattern)) + { + response.Headers[HeaderNames.Location] = "/"; + return; + } + + + if (pattern.IndexOf("://", StringComparison.Ordinal) == -1 && pattern[0] != '/') { pattern = '/' + pattern; } diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/RewriteAction.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/RewriteAction.cs index efb8468ed3..92a4b9c070 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/RewriteAction.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/RewriteAction.cs @@ -9,7 +9,6 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlActions { public class RewriteAction : UrlAction { - private readonly string ForwardSlash = "/"; public RuleTermination Result { get; } public bool QueryStringAppend { get; } public bool QueryStringDelete { get; } @@ -22,6 +21,8 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlActions bool queryStringDelete, bool escapeBackReferences) { + // For the replacement, we must have at least + // one segment (cannot have an empty replacement) Result = result; Url = pattern; QueryStringAppend = queryStringAppend; @@ -47,12 +48,18 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlActions var pattern = Url.Evaluate(context, ruleMatch, condMatch); var request = context.HttpContext.Request; + if (string.IsNullOrEmpty(pattern)) + { + pattern = "/"; + } + if (EscapeBackReferences) { // because escapebackreferences will be encapsulated by the pattern, just escape the pattern pattern = Uri.EscapeDataString(pattern); } + // TODO PERF, substrings, object creation, etc. if (pattern.IndexOf("://", StringComparison.Ordinal) >= 0) { @@ -89,13 +96,13 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlActions if (split >= 0) { var path = pattern.Substring(0, split); - if (path.StartsWith(ForwardSlash)) + if (path[0] == '/') { request.Path = PathString.FromUriComponent(path); } else { - request.Path = PathString.FromUriComponent(ForwardSlash + path); + request.Path = PathString.FromUriComponent('/' + path); } if (QueryStringAppend) @@ -112,13 +119,13 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlActions } else { - if (pattern.StartsWith(ForwardSlash)) + if (pattern[0] == '/') { request.Path = PathString.FromUriComponent(pattern); } else { - request.Path = PathString.FromUriComponent(ForwardSlash + pattern); + request.Path = PathString.FromUriComponent('/' + pattern); } if (QueryStringDelete) diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/UrlRewriteFileParser.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/UrlRewriteFileParser.cs index 9dcd7f4a4a..d3d071585c 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/UrlRewriteFileParser.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/UrlRewriteFileParser.cs @@ -165,7 +165,6 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite } var parsedPatternString = condition.Attribute(RewriteTags.Pattern)?.Value; - try { var input = _inputParser.ParseInputString(parsedInputString); @@ -197,9 +196,19 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite redirectType = RedirectType.Permanent; } + string url = string.Empty; + if (urlAction.Attribute(RewriteTags.Url) != null) + { + url = urlAction.Attribute(RewriteTags.Url).Value; + if (string.IsNullOrEmpty(url)) + { + ThrowUrlFormatException(urlAction, "Url attribute cannot contain an empty string"); + } + } + try { - var input = _inputParser.ParseInputString(urlAction.Attribute(RewriteTags.Url)?.Value); + var input = _inputParser.ParseInputString(url); builder.AddUrlAction(input, actionType, appendQuery, stopProcessing, (int)redirectType); } catch (FormatException formatException) diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/UrlRewriteRuleBuilder.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/UrlRewriteRuleBuilder.cs index 38d942912c..104fb0e91b 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/UrlRewriteRuleBuilder.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/UrlRewriteRuleBuilder.cs @@ -102,7 +102,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite { case MatchType.Pattern: { - if (pattern == null) + if (string.IsNullOrEmpty(pattern)) { throw new FormatException("Match does not have an associated pattern attribute in condition"); } diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/CodeRules/MiddlewareTests.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/CodeRules/MiddlewareTests.cs index 1e4e10beb3..51456357c6 100644 --- a/test/Microsoft.AspNetCore.Rewrite.Tests/CodeRules/MiddlewareTests.cs +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/CodeRules/MiddlewareTests.cs @@ -67,5 +67,40 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.CodeRules Assert.Equal(response.Headers.Location.OriginalString, "https://example.com/"); } + + + [Fact] + public async Task CheckIfEmptyStringRedirectCorrectly() + { + var options = new RewriteOptions().AddRedirect("(.*)", "$1", statusCode: 301); + var builder = new WebHostBuilder() + .Configure(app => + { + app.UseRewriter(options); + }); + var server = new TestServer(builder); + + var response = await server.CreateClient().GetAsync(""); + Assert.Equal(response.Headers.Location.OriginalString, "/"); + } + + [Fact] + public async Task CheckIfEmptyStringRewriteCorrectly() + { + var options = new RewriteOptions().AddRewrite("(.*)", "$1"); + var builder = new WebHostBuilder() + .Configure(app => + { + app.UseRewriter(options); + app.Run(context => context.Response.WriteAsync( + context.Request.Path + + context.Request.QueryString)); + }); + var server = new TestServer(builder); + + var response = await server.CreateClient().GetStringAsync(""); + + Assert.Equal(response, "/"); + } } } diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/ModRewrite/ModRewriteMiddlewareTest.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/ModRewrite/ModRewriteMiddlewareTest.cs index 2fd055a7cb..57daef1bc3 100644 --- a/test/Microsoft.AspNetCore.Rewrite.Tests/ModRewrite/ModRewriteMiddlewareTest.cs +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/ModRewrite/ModRewriteMiddlewareTest.cs @@ -248,5 +248,43 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.ModRewrite Assert.Equal(response.StatusCode, (HttpStatusCode)301); Assert.Equal(response.Headers.Location.AbsoluteUri, @"https://www.example.com/foo/"); } + + [Theory] + [InlineData("http://www.example.com/")] + public async Task Invoke_CaptureEmptyStringInRegexAssertRedirectLocationHasForwardSlash(string input) + { + var options = new RewriteOptions() + .AddApacheModRewrite(new StringReader("RewriteRule ^(.*)$ $1 [R=301,L]")); + var builder = new WebHostBuilder() + .Configure(app => + { + app.UseRewriter(options); + app.Run(context => context.Response.WriteAsync(context.Request.Scheme + "://" + context.Request.Host.Host + context.Request.Path + context.Request.QueryString)); + }); + var server = new TestServer(builder); + + var response = await server.CreateClient().GetAsync(input); + + Assert.Equal(response.StatusCode, (HttpStatusCode)301); + Assert.Equal(response.Headers.Location.OriginalString, "/"); + } + + [Theory] + [InlineData("http://www.example.com/")] + public async Task Invoke_CaptureEmptyStringInRegexAssertRewriteHasForwardSlash(string input) + { + var options = new RewriteOptions() + .AddApacheModRewrite(new StringReader("RewriteRule ^(.*)$ $1 [L]")); + var builder = new WebHostBuilder() + .Configure(app => + { + app.UseRewriter(options); + app.Run(context => context.Response.WriteAsync(context.Request.Path + context.Request.QueryString)); + }); + var server = new TestServer(builder); + + var response = await server.CreateClient().GetStringAsync(input); + Assert.Equal(response, "/"); + } } } diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/UrlRewrite/FormatExceptionHandlingTests.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/UrlRewrite/FormatExceptionHandlingTests.cs index db70d69e4a..41adf2fbbc 100644 --- a/test/Microsoft.AspNetCore.Rewrite.Tests/UrlRewrite/FormatExceptionHandlingTests.cs +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/UrlRewrite/FormatExceptionHandlingTests.cs @@ -91,6 +91,16 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite ", "Could not parse the UrlRewrite file. Message: 'Match does not have an associated pattern attribute in condition'. Line number '6': '18'.")] + [InlineData( +@" + + + + + + +", + "Could not parse the UrlRewrite file. Message: 'Url attribute cannot contain an empty string'. Line number '5': '14'.")] public void ThrowFormatExceptionWithCorrectMessage(string input, string expected) { // Arrange, Act, Assert diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/UrlRewrite/MiddleWareTests.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/UrlRewrite/MiddleWareTests.cs index af460e9f13..e20c5b9419 100644 --- a/test/Microsoft.AspNetCore.Rewrite.Tests/UrlRewrite/MiddleWareTests.cs +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/UrlRewrite/MiddleWareTests.cs @@ -255,5 +255,60 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite Assert.Equal(response, "http://internalserver/"); } + + [Fact] + public async Task Invoke_CaptureEmptyStringInRegexAssertRedirectLocationHasForwardSlash() + { + var options = new RewriteOptions().AddIISUrlRewrite(new StringReader(@" + + + + + + + ")); + var builder = new WebHostBuilder() + .Configure(app => + { + app.UseRewriter(options); + app.Run(context => context.Response.WriteAsync( + context.Request.Scheme + + "://" + + context.Request.Host + + context.Request.Path + + context.Request.QueryString)); + }); + var server = new TestServer(builder); + + var response = await server.CreateClient().GetAsync(new Uri("http://example.com/")); + + Assert.Equal(response.Headers.Location.OriginalString, "/"); + } + + [Fact] + public async Task Invoke_CaptureEmptyStringInRegexAssertRewriteLocationHasForwardSlash() + { + var options = new RewriteOptions().AddIISUrlRewrite(new StringReader(@" + + + + + + + ")); + var builder = new WebHostBuilder() + .Configure(app => + { + app.UseRewriter(options); + app.Run(context => context.Response.WriteAsync( + context.Request.Path + + context.Request.QueryString)); + }); + var server = new TestServer(builder); + + var response = await server.CreateClient().GetStringAsync(new Uri("http://example.com/")); + + Assert.Equal(response, "/"); + } } } From 51cd14efba91aca94808dcf7758329dc9da1a73c Mon Sep 17 00:00:00 2001 From: Justin Kotalik Date: Wed, 31 Aug 2016 10:10:20 -0700 Subject: [PATCH 103/307] Exceptions more descriptive and more NSE --- .../Internal/ModRewrite/FileParser.cs | 5 ++- .../Internal/ModRewrite/RuleBuilder.cs | 12 ++++--- .../Internal/ModRewrite/ServerVariables.cs | 36 +++++++++---------- .../Internal/UrlActions/ChangeCookieAction.cs | 4 +-- .../UrlActions/ChangeEnvironmentAction.cs | 4 +-- .../Internal/UrlRewrite/InputParser.cs | 2 +- .../Internal/UrlRewrite/ServerVariables.cs | 10 +++--- .../UrlRewrite/UrlRewriteRuleBuilder.cs | 9 +++-- 8 files changed, 43 insertions(+), 39 deletions(-) diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/FileParser.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/FileParser.cs index baec9e2c4f..5eb4bb6d76 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/FileParser.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/FileParser.cs @@ -44,6 +44,8 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite switch (tokens[0]) { case "RewriteBase": + // the notion of the path base spans across all rules, not just mod_rewrite + // So not implemented for now throw new NotImplementedException("RewriteBase is not implemented"); case "RewriteCond": try @@ -91,7 +93,8 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite } break; case "RewriteMap": - throw new NotImplementedException("RewriteMap to be added soon."); + // Lack of use + throw new NotImplementedException("RewriteMap are not implemented"); case "RewriteEngine": // Explicitly do nothing here, no notion of turning on regex engine. break; diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/RuleBuilder.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/RuleBuilder.cs index ece600a965..c2dcdf2128 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/RuleBuilder.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/RuleBuilder.cs @@ -132,16 +132,19 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite condition.Match = new IsFileMatch(input.Invert); break; case OperationType.SymbolicLink: - throw new NotImplementedException("Symbolic links are not implemented"); + // TODO see if FileAttributes.ReparsePoint works for this? + throw new NotImplementedException("Symbolic links are not supported because " + + "of cross platform implementation"); case OperationType.Size: condition.Match = new FileSizeMatch(input.Invert); break; case OperationType.ExistingUrl: - throw new NotImplementedException("Existing Url lookups not implemented"); + throw new NotSupportedException("Existing Url lookups not supported because it requires a subrequest"); case OperationType.Executable: - throw new NotImplementedException("Executable Property search is not implemented"); + throw new NotSupportedException("Executable Property is not supported because Windows " + + "requires a pinvoke to get this property"); default: - throw new ArgumentException("Invalid operation for property comparison."); + throw new ArgumentException("Invalid operation for property comparison"); } break; } @@ -166,7 +169,6 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite Pattern pattern, Flags flags) { - // first create pre conditions string flag; if (flags.GetValue(FlagType.Cookie, out flag)) { diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/ServerVariables.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/ServerVariables.cs index ebddffba19..7d295f84f8 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/ServerVariables.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/ServerVariables.cs @@ -38,51 +38,51 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite case "HTTP_FORWARDED": return new HeaderSegment("Forwarded"); case "AUTH_TYPE": - throw new NotImplementedException("Auth-Type server variable is not supported"); + throw new NotSupportedException("Rules using the AUTH_TYPE server variable are not supported"); case "CONN_REMOTE_ADDR": return new RemoteAddressSegment(); case "CONTEXT_PREFIX": - throw new NotImplementedException("Context-prefix server variable is not supported"); + throw new NotSupportedException("Rules using the CONTEXT_PREFIX server variable are not supported"); case "CONTEXT_DOCUMENT_ROOT": - throw new NotImplementedException("Context-Document-Root server variable is not supported"); + throw new NotSupportedException("Rules using the CONTEXT_DOCUMENT_ROOT server variable are not supported"); case "IPV6": return new IsIPV6Segment(); case "PATH_INFO": - throw new NotImplementedException("Path-Info server variable is not supported"); + throw new NotImplementedException("Rules using the PATH_INFO server variable are not implemented"); case "QUERY_STRING": return new QueryStringSegment(); case "REMOTE_ADDR": return new RemoteAddressSegment(); case "REMOTE_HOST": - throw new NotImplementedException("Remote-Host server variable is not supported"); + throw new NotSupportedException("Rules using the REMOTE_HOST server variable are not supported"); case "REMOTE_IDENT": - throw new NotImplementedException("Remote-Identity server variable is not supported"); + throw new NotSupportedException("Rules using the REMOTE_IDENT server variable are not supported"); case "REMOTE_PORT": return new RemotePortSegment(); case "REMOTE_USER": - throw new NotImplementedException("Remote-User server variable is not supported"); + throw new NotSupportedException("Rules using the REMOTE_USER server variable are not supported"); case "REQUEST_METHOD": return new RequestMethodSegment(); case "SCRIPT_FILENAME": - throw new NotImplementedException("Script-Filename server variable is not supported"); + return new RequestFileNameSegment(); case "DOCUMENT_ROOT": - throw new NotImplementedException("Document-Root server variable is not supported"); + throw new NotSupportedException("Rules using the DOCUMENT_ROOT server variable are not supported"); case "SCRIPT_GROUP": - throw new NotImplementedException("Script-Group server variable is not supported"); + throw new NotSupportedException("Rules using the SCRIPT_GROUP server variable are not supported"); case "SCRIPT_USER": - throw new NotImplementedException("Script-User server variable is not supported"); + throw new NotSupportedException("Rules using the SCRIPT_USER server variable are not supported"); case "SERVER_ADDR": return new LocalAddressSegment(); case "SERVER_ADMIN": - throw new NotImplementedException("Server-Admin server variable is not supported"); + throw new NotSupportedException("Rules using the SERVER_ADMIN server variable are not supported"); case "SERVER_NAME": - throw new NotImplementedException("Server-Name server variable is not supported"); + throw new NotSupportedException("Rules using the SERVER_NAME server variable are not supported"); case "SERVER_PORT": return new LocalPortSegment(); case "SERVER_PROTOCOL": return new ServerProtocolSegment(); case "SERVER_SOFTWARE": - throw new NotImplementedException("Server-Software server variable is not supported"); + throw new NotSupportedException("Rules using the SERVER_SOFTWARE server variable are not supported"); case "TIME_YEAR": return new DateTimeSegment(variable); case "TIME_MON": @@ -100,13 +100,13 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite case "TIME": return new DateTimeSegment(variable); case "API_VERSION": - throw new NotImplementedException(); + throw new NotSupportedException(); case "HTTPS": return new IsHttpsModSegment(); case "HTTP2": - throw new NotImplementedException("Http2 server variable is not supported"); + throw new NotSupportedException("Rules using the HTTP2 server variable are not supported"); case "IS_SUBREQ": - throw new NotImplementedException("Is-Subrequest server variable is not supported"); + throw new NotSupportedException("Rules using the IS_SUBREQ server variable are not supported"); case "REQUEST_FILENAME": return new RequestFileNameSegment(); case "REQUEST_SCHEME": @@ -114,7 +114,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite case "REQUEST_URI": return new UrlSegment(); case "THE_REQUEST": - throw new NotImplementedException("The-Request server variable is not supported"); + throw new NotSupportedException("Rules using the THE_REQUEST server variable are not supported"); default: throw new FormatException(Resources.FormatError_InputParserUnrecognizedParameter(variable, context.Index)); } diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/ChangeCookieAction.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/ChangeCookieAction.cs index 3f666abb79..5bc7d0ee87 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/ChangeCookieAction.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/ChangeCookieAction.cs @@ -11,13 +11,13 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlActions public ChangeCookieAction(string cookie) { // TODO - throw new NotImplementedException(cookie); + throw new NotImplementedException("Changing the cookie is not implemented"); } public override void ApplyAction(RewriteContext context, MatchResults ruleMatch, MatchResults condMatch) { // modify the cookies - + throw new NotImplementedException("Changing the cookie is not implemented"); } } } diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/ChangeEnvironmentAction.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/ChangeEnvironmentAction.cs index 09710350e4..9854155678 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/ChangeEnvironmentAction.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/ChangeEnvironmentAction.cs @@ -11,13 +11,13 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlActions public ChangeEnvironmentAction(string env) { // TODO - throw new NotImplementedException(); + throw new NotImplementedException("Changing the environment is not implemented"); } public override void ApplyAction(RewriteContext context, MatchResults ruleMatch, MatchResults condMatch) { // Do stuff to modify the env - throw new NotImplementedException(); + throw new NotImplementedException("Changing the environment is not implemented"); } } } diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/InputParser.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/InputParser.cs index ada89f938d..218a380dff 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/InputParser.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/InputParser.cs @@ -101,7 +101,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite } case "UrlDecode": { - throw new NotImplementedException("UrlDecode is not supported."); + throw new NotImplementedException("UrlDecode is not implemented because of no great library available"); } case "UrlEncode": { diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/ServerVariables.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/ServerVariables.cs index 0bb2764aa4..acb996f77a 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/ServerVariables.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/ServerVariables.cs @@ -15,9 +15,9 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite { // TODO Add all server variables here. case "ALL_RAW": - throw new NotImplementedException("All-Raw server variable not implemented"); + throw new NotSupportedException("Rules using the AUTH_TYPE server variable are not supported"); case "APP_POOL_ID": - throw new NotImplementedException("All-Pool-Id server variable not implemented"); + throw new NotSupportedException("Rules using the AUTH_TYPE server variable are not supported"); case "CONTENT_LENGTH": return new HeaderSegment(HeaderNames.ContentLength); case "CONTENT_TYPE": @@ -41,13 +41,13 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite case "LOCAL_ADDR": return new LocalAddressSegment(); case "HTTP_PROXY_CONNECTION": - throw new NotSupportedException("Proxy Connections not supported"); + throw new NotSupportedException("Rules using the AUTH_TYPE server variable are not supported"); case "QUERY_STRING": return new QueryStringSegment(); case "REMOTE_ADDR": return new RemoteAddressSegment(); case "REMOTE_HOST": - throw new NotImplementedException("Remote-Host server variable not implemented"); + throw new NotSupportedException("Rules using the REMOTE_HOST server variable are not supported"); case "REMOTE_PORT": return new RemotePortSegment(); case "REQUEST_FILENAME": @@ -55,7 +55,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite case "REQUEST_URI": return new UrlSegment(); default: - throw new FormatException("Unrecognized server variable."); + throw new FormatException("Unrecognized server variable"); } } } diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/UrlRewriteRuleBuilder.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/UrlRewriteRuleBuilder.cs index 104fb0e91b..cf9467ad9e 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/UrlRewriteRuleBuilder.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/UrlRewriteRuleBuilder.cs @@ -53,10 +53,9 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite _action = new RedirectAction(statusCode, url, appendQueryString); break; case ActionType.AbortRequest: - throw new NotImplementedException("Abort Requests are not supported"); + throw new NotImplementedException("Abort Requests are not implemented"); case ActionType.CustomResponse: - // TODO - throw new NotImplementedException("Custom Responses are not supported"); + throw new NotImplementedException("Custom Responses are not implemented"); } } @@ -79,7 +78,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite break; } case PatternSyntax.WildCard: - throw new NotImplementedException("Wildcard syntax is not supported"); + throw new NotSupportedException("Wildcard syntax is not supported"); case PatternSyntax.ExactMatch: _initialMatch = new ExactMatch(ignoreCase, input, negate); break; @@ -132,7 +131,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite break; } case PatternSyntax.WildCard: - throw new NotImplementedException("Wildcard syntax is not supported"); + throw new NotSupportedException("Wildcard syntax is not supported"); case PatternSyntax.ExactMatch: if (pattern == null) { From f99a9be4d032218f250a87d3e5c2fdbc60bcbe60 Mon Sep 17 00:00:00 2001 From: Justin Kotalik Date: Fri, 2 Sep 2016 09:41:17 -0700 Subject: [PATCH 104/307] quick readme update --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 4dfc5912ee..b037519abc 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,7 @@ ASP.NET Core Basic Middleware Components ======== -This repo hosts a collection of basic middleware components for ASP.NET Core. +This repo hosts a collection of basic middleware components for ASP.NET Core. This includes Buffering, HTTP Overrides, and URL Rewriting. +The Rewrite middleware can import rules from IIS's UrlRewrite and Apache's mod_rewrite. This project is part of ASP.NET Core. You can find samples, documentation and getting started instructions for ASP.NET Core at the [Home](https://github.com/aspnet/home) repo. From 57c1f877e37ccc49ba5d2224d5095d27add49246 Mon Sep 17 00:00:00 2001 From: Justin Kotalik Date: Fri, 2 Sep 2016 10:12:59 -0700 Subject: [PATCH 105/307] Adds path base to redirect location and tests --- .../Internal/CodeRules/RedirectRule.cs | 8 +++--- .../Internal/UrlActions/RedirectAction.cs | 9 ++++--- .../CodeRules/MiddlewareTests.cs | 19 ++++++++++++++ .../ModRewrite/ModRewriteMiddlewareTest.cs | 20 ++++++++++++++ .../UrlRewrite/MiddleWareTests.cs | 26 +++++++++++++++++++ 5 files changed, 75 insertions(+), 7 deletions(-) diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/CodeRules/RedirectRule.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/CodeRules/RedirectRule.cs index 90ddf74273..2a68eb1b3c 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/CodeRules/RedirectRule.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/CodeRules/RedirectRule.cs @@ -34,6 +34,8 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.CodeRules public override void ApplyRule(RewriteContext context) { var path = context.HttpContext.Request.Path; + var pathBase = context.HttpContext.Request.PathBase; + Match initMatchResults; if (path == PathString.Empty) { @@ -54,7 +56,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.CodeRules if (string.IsNullOrEmpty(newPath)) { - response.Headers[HeaderNames.Location] = "/"; + response.Headers[HeaderNames.Location] = pathBase.HasValue ? pathBase.Value : "/"; return; } @@ -70,11 +72,11 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.CodeRules QueryString.FromUriComponent( newPath.Substring(split))); // not using the HttpContext.Response.redirect here because status codes may be 301, 302, 307, 308 - response.Headers[HeaderNames.Location] = newPath.Substring(0, split) + query; + response.Headers[HeaderNames.Location] = pathBase + newPath.Substring(0, split) + query; } else { - response.Headers[HeaderNames.Location] = newPath; + response.Headers[HeaderNames.Location] = pathBase + newPath; } } } diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/RedirectAction.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/RedirectAction.cs index dfac28fc80..b295804064 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/RedirectAction.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/RedirectAction.cs @@ -47,6 +47,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlActions { var pattern = Url.Evaluate(context, ruleMatch, condMatch); var response = context.HttpContext.Response; + var pathBase = context.HttpContext.Request.PathBase; if (EscapeBackReferences) { // because escapebackreferences will be encapsulated by the pattern, just escape the pattern @@ -55,7 +56,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlActions if (string.IsNullOrEmpty(pattern)) { - response.Headers[HeaderNames.Location] = "/"; + response.Headers[HeaderNames.Location] = pathBase.HasValue ? pathBase.Value : "/"; return; } @@ -77,7 +78,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlActions pattern.Substring(split))); // not using the response.redirect here because status codes may be 301, 302, 307, 308 - response.Headers[HeaderNames.Location] = pattern.Substring(0, split) + query; + response.Headers[HeaderNames.Location] = pathBase + pattern.Substring(0, split) + query; } else { @@ -85,11 +86,11 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlActions // by default. if (QueryStringDelete) { - response.Headers[HeaderNames.Location] = pattern; + response.Headers[HeaderNames.Location] = pathBase + pattern; } else { - response.Headers[HeaderNames.Location] = pattern + context.HttpContext.Request.QueryString; + response.Headers[HeaderNames.Location] = pathBase + pattern + context.HttpContext.Request.QueryString; } } context.Result = RuleTermination.ResponseComplete; diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/CodeRules/MiddlewareTests.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/CodeRules/MiddlewareTests.cs index 51456357c6..9a6f4d9c46 100644 --- a/test/Microsoft.AspNetCore.Rewrite.Tests/CodeRules/MiddlewareTests.cs +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/CodeRules/MiddlewareTests.cs @@ -102,5 +102,24 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.CodeRules Assert.Equal(response, "/"); } + + [Fact] + public async Task SettingPathBase() + { + var options = new RewriteOptions().AddRedirect("(.*)", "$1"); + var builder = new WebHostBuilder() + .Configure(app => + { + app.UseRewriter(options); + app.Run(context => context.Response.WriteAsync( + context.Request.Path + + context.Request.QueryString)); + }); + var server = new TestServer(builder) {BaseAddress = new Uri("http://localhost:5000/foo")}; + + var response = await server.CreateClient().GetAsync(""); + + Assert.Equal(response.Headers.Location.OriginalString, "/foo"); + } } } diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/ModRewrite/ModRewriteMiddlewareTest.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/ModRewrite/ModRewriteMiddlewareTest.cs index 57daef1bc3..0c3b943636 100644 --- a/test/Microsoft.AspNetCore.Rewrite.Tests/ModRewrite/ModRewriteMiddlewareTest.cs +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/ModRewrite/ModRewriteMiddlewareTest.cs @@ -1,6 +1,7 @@ // 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; using System.IO; using System.Net; using System.Threading.Tasks; @@ -286,5 +287,24 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.ModRewrite var response = await server.CreateClient().GetStringAsync(input); Assert.Equal(response, "/"); } + + [Fact] + public async Task Invoke_CaptureEmptyStringInRegexAssertLocationHeaderContainsPathBase() + { + var options = new RewriteOptions().AddApacheModRewrite(new StringReader(@"RewriteRule ^(.*)$ $1 [R=301,L]")); + var builder = new WebHostBuilder() + .Configure(app => + { + app.UseRewriter(options); + app.Run(context => context.Response.WriteAsync( + context.Request.Path + + context.Request.QueryString)); + }); + var server = new TestServer(builder) { BaseAddress = new Uri("http://localhost:5000/foo") }; + + var response = await server.CreateClient().GetAsync(""); + + Assert.Equal(response.Headers.Location.OriginalString, "/foo"); + } } } diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/UrlRewrite/MiddleWareTests.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/UrlRewrite/MiddleWareTests.cs index e20c5b9419..dcc7cb98c4 100644 --- a/test/Microsoft.AspNetCore.Rewrite.Tests/UrlRewrite/MiddleWareTests.cs +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/UrlRewrite/MiddleWareTests.cs @@ -310,5 +310,31 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite Assert.Equal(response, "/"); } + + [Fact] + public async Task Invoke_CaptureEmptyStringInRegexAssertLocationHeaderContainsPathBase() + { + var options = new RewriteOptions().AddIISUrlRewrite(new StringReader(@" + + + + + + + ")); + var builder = new WebHostBuilder() + .Configure(app => + { + app.UseRewriter(options); + app.Run(context => context.Response.WriteAsync( + context.Request.Path + + context.Request.QueryString)); + }); + var server = new TestServer(builder) { BaseAddress = new Uri("http://localhost:5000/foo") }; + + var response = await server.CreateClient().GetAsync(""); + + Assert.Equal(response.Headers.Location.OriginalString, "/foo"); + } } } From a5ff9d800374c60a92e8b1722166f41a6f7607bd Mon Sep 17 00:00:00 2001 From: Nate McMaster Date: Tue, 6 Sep 2016 10:51:19 -0700 Subject: [PATCH 106/307] Add 'Apache' and 'IIS' to internal namespaces and classes --- .gitignore | 5 ++++- .../ApacheModRewriteOptionsExtensions.cs | 2 +- .../IISUrlRewriteOptionsExtensions.cs | 2 +- .../ApacheModRewriteRule.cs} | 6 +++--- .../ConditionPatternParser.cs | 2 +- .../ConditionType.cs | 2 +- .../FileParser.cs | 2 +- .../FlagParser.cs | 2 +- .../{ModRewrite => ApacheModRewrite}/FlagType.cs | 2 +- .../{ModRewrite => ApacheModRewrite}/Flags.cs | 2 +- .../OperationType.cs | 2 +- .../ParsedModRewriteCondition.cs | 2 +- .../RuleBuilder.cs | 6 +++--- .../RuleRegexParser.cs | 2 +- .../SegmentType.cs | 2 +- .../ServerVariables.cs | 2 +- .../TestStringParser.cs | 2 +- .../Tokenizer.cs | 2 +- .../Internal/{CodeRules => }/DelegateRule.cs | 2 +- .../{UrlRewrite => IISUrlRewrite}/ActionType.cs | 2 +- .../IISUrlRewriteRule.cs} | 6 +++--- .../{UrlRewrite => IISUrlRewrite}/InputParser.cs | 2 +- .../LogicalGrouping.cs | 2 +- .../{UrlRewrite => IISUrlRewrite}/MatchType.cs | 2 +- .../PatternSyntax.cs | 2 +- .../RedirectType.cs | 2 +- .../{UrlRewrite => IISUrlRewrite}/RewriteTags.cs | 2 +- .../ServerVariables.cs | 2 +- .../UrlRewriteFileParser.cs | 12 ++++++------ .../UrlRewriteRuleBuilder.cs | 11 +++++------ .../Internal/{CodeRules => }/RedirectRule.cs | 4 ++-- .../{CodeRules => }/RedirectToHttpsRule.cs | 2 +- .../Internal/{CodeRules => }/RewriteRule.cs | 2 +- .../Internal/UrlActions/ChangeCookieAction.cs | 1 - .../UrlActions/ChangeEnvironmentAction.cs | 1 - .../Internal/UrlActions/RedirectAction.cs | 2 -- .../Internal/UrlActions/RewriteAction.cs | 6 +++--- .../RewriteMiddleware.cs | 10 ++++++---- .../RewriteOptionsExtensions.cs | 6 ++---- .../ConditionPatternParserTest.cs | 2 +- .../FlagParserTest.cs | 2 +- .../FormatExceptionTests.cs | 2 +- .../ModRewriteMiddlewareTest.cs | 0 .../RewriteTokenizerTest.cs | 2 +- .../RuleRegexParserTest.cs | 2 +- .../TestStringParserTests.cs | 2 +- .../FileParserTests.cs | 16 ++++++++-------- .../FormatExceptionHandlingTests.cs | 2 +- .../InputParserTests.cs | 2 +- .../MiddleWareTests.cs | 0 .../ServerVariableTests.cs | 2 +- .../UrlRewriteApplicationTests.cs | 2 +- .../{CodeRules => }/MiddlewareTests.cs | 0 53 files changed, 81 insertions(+), 83 deletions(-) rename src/Microsoft.AspNetCore.Rewrite/Internal/{ModRewriteRule.cs => ApacheModRewrite/ApacheModRewriteRule.cs} (88%) rename src/Microsoft.AspNetCore.Rewrite/Internal/{ModRewrite => ApacheModRewrite}/ConditionPatternParser.cs (99%) rename src/Microsoft.AspNetCore.Rewrite/Internal/{ModRewrite => ApacheModRewrite}/ConditionType.cs (81%) rename src/Microsoft.AspNetCore.Rewrite/Internal/{ModRewrite => ApacheModRewrite}/FileParser.cs (98%) rename src/Microsoft.AspNetCore.Rewrite/Internal/{ModRewrite => ApacheModRewrite}/FlagParser.cs (98%) rename src/Microsoft.AspNetCore.Rewrite/Internal/{ModRewrite => ApacheModRewrite}/FlagType.cs (90%) rename src/Microsoft.AspNetCore.Rewrite/Internal/{ModRewrite => ApacheModRewrite}/Flags.cs (96%) rename src/Microsoft.AspNetCore.Rewrite/Internal/{ModRewrite => ApacheModRewrite}/OperationType.cs (87%) rename src/Microsoft.AspNetCore.Rewrite/Internal/{ModRewrite => ApacheModRewrite}/ParsedModRewriteCondition.cs (92%) rename src/Microsoft.AspNetCore.Rewrite/Internal/{ModRewrite => ApacheModRewrite}/RuleBuilder.cs (98%) rename src/Microsoft.AspNetCore.Rewrite/Internal/{ModRewrite => ApacheModRewrite}/RuleRegexParser.cs (92%) rename src/Microsoft.AspNetCore.Rewrite/Internal/{ModRewrite => ApacheModRewrite}/SegmentType.cs (82%) rename src/Microsoft.AspNetCore.Rewrite/Internal/{ModRewrite => ApacheModRewrite}/ServerVariables.cs (98%) rename src/Microsoft.AspNetCore.Rewrite/Internal/{ModRewrite => ApacheModRewrite}/TestStringParser.cs (99%) rename src/Microsoft.AspNetCore.Rewrite/Internal/{ModRewrite => ApacheModRewrite}/Tokenizer.cs (98%) rename src/Microsoft.AspNetCore.Rewrite/Internal/{CodeRules => }/DelegateRule.cs (89%) rename src/Microsoft.AspNetCore.Rewrite/Internal/{UrlRewrite => IISUrlRewrite}/ActionType.cs (83%) rename src/Microsoft.AspNetCore.Rewrite/Internal/{UrlRewriteRule.cs => IISUrlRewrite/IISUrlRewriteRule.cs} (93%) rename src/Microsoft.AspNetCore.Rewrite/Internal/{UrlRewrite => IISUrlRewrite}/InputParser.cs (99%) rename src/Microsoft.AspNetCore.Rewrite/Internal/{UrlRewrite => IISUrlRewrite}/LogicalGrouping.cs (80%) rename src/Microsoft.AspNetCore.Rewrite/Internal/{UrlRewrite => IISUrlRewrite}/MatchType.cs (81%) rename src/Microsoft.AspNetCore.Rewrite/Internal/{UrlRewrite => IISUrlRewrite}/PatternSyntax.cs (81%) rename src/Microsoft.AspNetCore.Rewrite/Internal/{UrlRewrite => IISUrlRewrite}/RedirectType.cs (83%) rename src/Microsoft.AspNetCore.Rewrite/Internal/{UrlRewrite => IISUrlRewrite}/RewriteTags.cs (95%) rename src/Microsoft.AspNetCore.Rewrite/Internal/{UrlRewrite => IISUrlRewrite}/ServerVariables.cs (97%) rename src/Microsoft.AspNetCore.Rewrite/Internal/{UrlRewrite => IISUrlRewrite}/UrlRewriteFileParser.cs (96%) rename src/Microsoft.AspNetCore.Rewrite/Internal/{UrlRewrite => IISUrlRewrite}/UrlRewriteRuleBuilder.cs (95%) rename src/Microsoft.AspNetCore.Rewrite/Internal/{CodeRules => }/RedirectRule.cs (96%) rename src/Microsoft.AspNetCore.Rewrite/Internal/{CodeRules => }/RedirectToHttpsRule.cs (95%) rename src/Microsoft.AspNetCore.Rewrite/Internal/{CodeRules => }/RewriteRule.cs (98%) rename test/Microsoft.AspNetCore.Rewrite.Tests/{ModRewrite => ApacheModRewrite}/ConditionPatternParserTest.cs (99%) rename test/Microsoft.AspNetCore.Rewrite.Tests/{ModRewrite => ApacheModRewrite}/FlagParserTest.cs (98%) rename test/Microsoft.AspNetCore.Rewrite.Tests/{ModRewrite => ApacheModRewrite}/FormatExceptionTests.cs (97%) rename test/Microsoft.AspNetCore.Rewrite.Tests/{ModRewrite => ApacheModRewrite}/ModRewriteMiddlewareTest.cs (100%) rename test/Microsoft.AspNetCore.Rewrite.Tests/{ModRewrite => ApacheModRewrite}/RewriteTokenizerTest.cs (98%) rename test/Microsoft.AspNetCore.Rewrite.Tests/{ModRewrite => ApacheModRewrite}/RuleRegexParserTest.cs (93%) rename test/Microsoft.AspNetCore.Rewrite.Tests/{ModRewrite => ApacheModRewrite}/TestStringParserTests.cs (98%) rename test/Microsoft.AspNetCore.Rewrite.Tests/{UrlRewrite => IISUrlRewrite}/FileParserTests.cs (92%) rename test/Microsoft.AspNetCore.Rewrite.Tests/{UrlRewrite => IISUrlRewrite}/FormatExceptionHandlingTests.cs (98%) rename test/Microsoft.AspNetCore.Rewrite.Tests/{UrlRewrite => IISUrlRewrite}/InputParserTests.cs (98%) rename test/Microsoft.AspNetCore.Rewrite.Tests/{UrlRewrite => IISUrlRewrite}/MiddleWareTests.cs (100%) rename test/Microsoft.AspNetCore.Rewrite.Tests/{UrlRewrite => IISUrlRewrite}/ServerVariableTests.cs (97%) rename test/Microsoft.AspNetCore.Rewrite.Tests/{UrlRewrite => IISUrlRewrite}/UrlRewriteApplicationTests.cs (96%) rename test/Microsoft.AspNetCore.Rewrite.Tests/{CodeRules => }/MiddlewareTests.cs (100%) diff --git a/.gitignore b/.gitignore index 4ddb21ac5f..abc642dc8d 100644 --- a/.gitignore +++ b/.gitignore @@ -27,4 +27,7 @@ project.lock.json *.ipch .vs/ .build/ -.testPublish/ \ No newline at end of file +.testPublish/ +.idea/ +.vscode/ + diff --git a/src/Microsoft.AspNetCore.Rewrite/ApacheModRewriteOptionsExtensions.cs b/src/Microsoft.AspNetCore.Rewrite/ApacheModRewriteOptionsExtensions.cs index e237c7610c..99aa31ada4 100644 --- a/src/Microsoft.AspNetCore.Rewrite/ApacheModRewriteOptionsExtensions.cs +++ b/src/Microsoft.AspNetCore.Rewrite/ApacheModRewriteOptionsExtensions.cs @@ -4,7 +4,7 @@ using System; using System.IO; using Microsoft.AspNetCore.Hosting; -using Microsoft.AspNetCore.Rewrite.Internal.ModRewrite; +using Microsoft.AspNetCore.Rewrite.Internal.ApacheModRewrite; namespace Microsoft.AspNetCore.Rewrite { diff --git a/src/Microsoft.AspNetCore.Rewrite/IISUrlRewriteOptionsExtensions.cs b/src/Microsoft.AspNetCore.Rewrite/IISUrlRewriteOptionsExtensions.cs index 21658e5649..05d49b9ac8 100644 --- a/src/Microsoft.AspNetCore.Rewrite/IISUrlRewriteOptionsExtensions.cs +++ b/src/Microsoft.AspNetCore.Rewrite/IISUrlRewriteOptionsExtensions.cs @@ -4,7 +4,7 @@ using System; using System.IO; using Microsoft.AspNetCore.Hosting; -using Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite; +using Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite; namespace Microsoft.AspNetCore.Rewrite { diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewriteRule.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/ApacheModRewrite/ApacheModRewriteRule.cs similarity index 88% rename from src/Microsoft.AspNetCore.Rewrite/Internal/ModRewriteRule.cs rename to src/Microsoft.AspNetCore.Rewrite/Internal/ApacheModRewrite/ApacheModRewriteRule.cs index 11daadce68..6fb201e12f 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewriteRule.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/ApacheModRewrite/ApacheModRewriteRule.cs @@ -4,15 +4,15 @@ using System.Collections.Generic; using Microsoft.AspNetCore.Rewrite.Logging; -namespace Microsoft.AspNetCore.Rewrite.Internal +namespace Microsoft.AspNetCore.Rewrite.Internal.ApacheModRewrite { - public class ModRewriteRule : Rule + public class ApacheModRewriteRule : Rule { public UrlMatch InitialMatch { get; } public IList Conditions { get; } public IList Actions { get; } - public ModRewriteRule(UrlMatch initialMatch, IList conditions, IList urlActions) + public ApacheModRewriteRule(UrlMatch initialMatch, IList conditions, IList urlActions) { Conditions = conditions; InitialMatch = initialMatch; diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/ConditionPatternParser.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/ApacheModRewrite/ConditionPatternParser.cs similarity index 99% rename from src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/ConditionPatternParser.cs rename to src/Microsoft.AspNetCore.Rewrite/Internal/ApacheModRewrite/ConditionPatternParser.cs index fadd570f97..9523b897df 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/ConditionPatternParser.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/ApacheModRewrite/ConditionPatternParser.cs @@ -3,7 +3,7 @@ using System; -namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite +namespace Microsoft.AspNetCore.Rewrite.Internal.ApacheModRewrite { /// /// Parses the "CondPattern" portion of the RewriteCond. diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/ConditionType.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/ApacheModRewrite/ConditionType.cs similarity index 81% rename from src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/ConditionType.cs rename to src/Microsoft.AspNetCore.Rewrite/Internal/ApacheModRewrite/ConditionType.cs index f8f6818979..0624bbfede 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/ConditionType.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/ApacheModRewrite/ConditionType.cs @@ -1,7 +1,7 @@ // 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. -namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite +namespace Microsoft.AspNetCore.Rewrite.Internal.ApacheModRewrite { public enum ConditionType { diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/FileParser.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/ApacheModRewrite/FileParser.cs similarity index 98% rename from src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/FileParser.cs rename to src/Microsoft.AspNetCore.Rewrite/Internal/ApacheModRewrite/FileParser.cs index 5eb4bb6d76..c2525f409f 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/FileParser.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/ApacheModRewrite/FileParser.cs @@ -5,7 +5,7 @@ using System; using System.Collections.Generic; using System.IO; -namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite +namespace Microsoft.AspNetCore.Rewrite.Internal.ApacheModRewrite { public class FileParser { diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/FlagParser.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/ApacheModRewrite/FlagParser.cs similarity index 98% rename from src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/FlagParser.cs rename to src/Microsoft.AspNetCore.Rewrite/Internal/ApacheModRewrite/FlagParser.cs index 0888f614ab..b3e957a5c7 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/FlagParser.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/ApacheModRewrite/FlagParser.cs @@ -4,7 +4,7 @@ using System; using System.Collections.Generic; -namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite +namespace Microsoft.AspNetCore.Rewrite.Internal.ApacheModRewrite { public class FlagParser { diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/FlagType.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/ApacheModRewrite/FlagType.cs similarity index 90% rename from src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/FlagType.cs rename to src/Microsoft.AspNetCore.Rewrite/Internal/ApacheModRewrite/FlagType.cs index 85919a7a41..67ea9875bf 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/FlagType.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/ApacheModRewrite/FlagType.cs @@ -1,7 +1,7 @@ // 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. -namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite +namespace Microsoft.AspNetCore.Rewrite.Internal.ApacheModRewrite { public enum FlagType { diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/Flags.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/ApacheModRewrite/Flags.cs similarity index 96% rename from src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/Flags.cs rename to src/Microsoft.AspNetCore.Rewrite/Internal/ApacheModRewrite/Flags.cs index 5df8cc09be..0f5fac2c25 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/Flags.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/ApacheModRewrite/Flags.cs @@ -3,7 +3,7 @@ using System.Collections.Generic; -namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite +namespace Microsoft.AspNetCore.Rewrite.Internal.ApacheModRewrite { // For more information of flags, and what flags we currently support: // https://github.com/aspnet/BasicMiddleware/issues/66 diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/OperationType.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/ApacheModRewrite/OperationType.cs similarity index 87% rename from src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/OperationType.cs rename to src/Microsoft.AspNetCore.Rewrite/Internal/ApacheModRewrite/OperationType.cs index 4019c1cc11..1f22902d57 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/OperationType.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/ApacheModRewrite/OperationType.cs @@ -1,7 +1,7 @@ // 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. -namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite +namespace Microsoft.AspNetCore.Rewrite.Internal.ApacheModRewrite { public enum OperationType { diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/ParsedModRewriteCondition.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/ApacheModRewrite/ParsedModRewriteCondition.cs similarity index 92% rename from src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/ParsedModRewriteCondition.cs rename to src/Microsoft.AspNetCore.Rewrite/Internal/ApacheModRewrite/ParsedModRewriteCondition.cs index e854343fe5..759ab51307 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/ParsedModRewriteCondition.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/ApacheModRewrite/ParsedModRewriteCondition.cs @@ -1,7 +1,7 @@ // 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. -namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite +namespace Microsoft.AspNetCore.Rewrite.Internal.ApacheModRewrite { public class ParsedModRewriteInput { diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/RuleBuilder.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/ApacheModRewrite/RuleBuilder.cs similarity index 98% rename from src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/RuleBuilder.cs rename to src/Microsoft.AspNetCore.Rewrite/Internal/ApacheModRewrite/RuleBuilder.cs index c2dcdf2128..bec58de1bc 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/RuleBuilder.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/ApacheModRewrite/RuleBuilder.cs @@ -7,7 +7,7 @@ using System.Text.RegularExpressions; using Microsoft.AspNetCore.Rewrite.Internal.UrlActions; using Microsoft.AspNetCore.Rewrite.Internal.UrlMatches; -namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite +namespace Microsoft.AspNetCore.Rewrite.Internal.ApacheModRewrite { public class RuleBuilder { @@ -17,13 +17,13 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite private readonly TimeSpan RegexTimeout = TimeSpan.FromMilliseconds(1); - public ModRewriteRule Build() + public ApacheModRewriteRule Build() { if (_actions.Count == 0 || _match == null) { throw new InvalidOperationException("Cannot create ModRewriteRule without action and match"); } - return new ModRewriteRule(_match, _conditions, _actions); + return new ApacheModRewriteRule(_match, _conditions, _actions); } public void AddRule(string rule) diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/RuleRegexParser.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/ApacheModRewrite/RuleRegexParser.cs similarity index 92% rename from src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/RuleRegexParser.cs rename to src/Microsoft.AspNetCore.Rewrite/Internal/ApacheModRewrite/RuleRegexParser.cs index e9cbb8a36c..e8c0eeec69 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/RuleRegexParser.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/ApacheModRewrite/RuleRegexParser.cs @@ -3,7 +3,7 @@ using System; -namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite +namespace Microsoft.AspNetCore.Rewrite.Internal.ApacheModRewrite { public class RuleRegexParser { diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/SegmentType.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/ApacheModRewrite/SegmentType.cs similarity index 82% rename from src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/SegmentType.cs rename to src/Microsoft.AspNetCore.Rewrite/Internal/ApacheModRewrite/SegmentType.cs index 2e86cde344..ee47c978cf 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/SegmentType.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/ApacheModRewrite/SegmentType.cs @@ -1,7 +1,7 @@ // 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. -namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite +namespace Microsoft.AspNetCore.Rewrite.Internal.ApacheModRewrite { public enum SegmentType { diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/ServerVariables.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/ApacheModRewrite/ServerVariables.cs similarity index 98% rename from src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/ServerVariables.cs rename to src/Microsoft.AspNetCore.Rewrite/Internal/ApacheModRewrite/ServerVariables.cs index 7d295f84f8..eb3e73f895 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/ServerVariables.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/ApacheModRewrite/ServerVariables.cs @@ -5,7 +5,7 @@ using System; using Microsoft.AspNetCore.Rewrite.Internal.PatternSegments; using Microsoft.Net.Http.Headers; -namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite +namespace Microsoft.AspNetCore.Rewrite.Internal.ApacheModRewrite { /// /// mod_rewrite lookups for specific string constants. diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/TestStringParser.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/ApacheModRewrite/TestStringParser.cs similarity index 99% rename from src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/TestStringParser.cs rename to src/Microsoft.AspNetCore.Rewrite/Internal/ApacheModRewrite/TestStringParser.cs index a87d9b1ed6..151a9c7c10 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/TestStringParser.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/ApacheModRewrite/TestStringParser.cs @@ -5,7 +5,7 @@ using System; using System.Collections.Generic; using Microsoft.AspNetCore.Rewrite.Internal.PatternSegments; -namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite +namespace Microsoft.AspNetCore.Rewrite.Internal.ApacheModRewrite { /// /// Parses the TestString segment of the mod_rewrite condition. diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/Tokenizer.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/ApacheModRewrite/Tokenizer.cs similarity index 98% rename from src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/Tokenizer.cs rename to src/Microsoft.AspNetCore.Rewrite/Internal/ApacheModRewrite/Tokenizer.cs index 1ecabd093d..b9d19bd8c7 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/Tokenizer.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/ApacheModRewrite/Tokenizer.cs @@ -5,7 +5,7 @@ using System; using System.Collections.Generic; using System.Text.RegularExpressions; -namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite +namespace Microsoft.AspNetCore.Rewrite.Internal.ApacheModRewrite { /// /// Tokenizes a mod_rewrite rule, delimited by spaces. diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/CodeRules/DelegateRule.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/DelegateRule.cs similarity index 89% rename from src/Microsoft.AspNetCore.Rewrite/Internal/CodeRules/DelegateRule.cs rename to src/Microsoft.AspNetCore.Rewrite/Internal/DelegateRule.cs index 869e773c37..60a670a7fc 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/CodeRules/DelegateRule.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/DelegateRule.cs @@ -3,7 +3,7 @@ using System; -namespace Microsoft.AspNetCore.Rewrite.Internal.CodeRules +namespace Microsoft.AspNetCore.Rewrite.Internal { public class DelegateRule : Rule { diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/ActionType.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/ActionType.cs similarity index 83% rename from src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/ActionType.cs rename to src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/ActionType.cs index 877871073b..75bda6efa7 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/ActionType.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/ActionType.cs @@ -1,7 +1,7 @@ // 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. -namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite +namespace Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite { public enum ActionType { diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewriteRule.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/IISUrlRewriteRule.cs similarity index 93% rename from src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewriteRule.cs rename to src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/IISUrlRewriteRule.cs index 6923445187..ba6b718cd3 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewriteRule.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/IISUrlRewriteRule.cs @@ -5,16 +5,16 @@ using System.Collections.Generic; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Rewrite.Logging; -namespace Microsoft.AspNetCore.Rewrite.Internal +namespace Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite { - public class UrlRewriteRule : Rule + public class IISUrlRewriteRule : Rule { public string Name { get; } public UrlMatch InitialMatch { get; } public IList Conditions { get; } public UrlAction Action { get; } - public UrlRewriteRule(string name, + public IISUrlRewriteRule(string name, UrlMatch initialMatch, IList conditions, UrlAction action) diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/InputParser.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/InputParser.cs similarity index 99% rename from src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/InputParser.cs rename to src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/InputParser.cs index 218a380dff..e471248868 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/InputParser.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/InputParser.cs @@ -5,7 +5,7 @@ using System; using System.Collections.Generic; using Microsoft.AspNetCore.Rewrite.Internal.PatternSegments; -namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite +namespace Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite { public class InputParser { diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/LogicalGrouping.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/LogicalGrouping.cs similarity index 80% rename from src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/LogicalGrouping.cs rename to src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/LogicalGrouping.cs index 275d317b65..85dc616e89 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/LogicalGrouping.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/LogicalGrouping.cs @@ -1,7 +1,7 @@ // 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. -namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite +namespace Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite { public enum LogicalGrouping { diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/MatchType.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/MatchType.cs similarity index 81% rename from src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/MatchType.cs rename to src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/MatchType.cs index cfb763dcfb..4f02dc48ce 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/MatchType.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/MatchType.cs @@ -1,7 +1,7 @@ // 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. -namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite +namespace Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite { public enum MatchType { diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/PatternSyntax.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/PatternSyntax.cs similarity index 81% rename from src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/PatternSyntax.cs rename to src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/PatternSyntax.cs index c32b04f844..b068016e72 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/PatternSyntax.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/PatternSyntax.cs @@ -1,7 +1,7 @@ // 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. -namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite +namespace Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite { public enum PatternSyntax { diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/RedirectType.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/RedirectType.cs similarity index 83% rename from src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/RedirectType.cs rename to src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/RedirectType.cs index ce52d9d408..2221d5412b 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/RedirectType.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/RedirectType.cs @@ -1,7 +1,7 @@ // 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. -namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite +namespace Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite { public enum RedirectType { diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/RewriteTags.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/RewriteTags.cs similarity index 95% rename from src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/RewriteTags.cs rename to src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/RewriteTags.cs index 2421fe2eb5..420e8e461d 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/RewriteTags.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/RewriteTags.cs @@ -1,7 +1,7 @@ // 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. -namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite +namespace Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite { public static class RewriteTags { diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/ServerVariables.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/ServerVariables.cs similarity index 97% rename from src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/ServerVariables.cs rename to src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/ServerVariables.cs index acb996f77a..35112b78bb 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/ServerVariables.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/ServerVariables.cs @@ -5,7 +5,7 @@ using System; using Microsoft.AspNetCore.Rewrite.Internal.PatternSegments; using Microsoft.Net.Http.Headers; -namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite +namespace Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite { public static class ServerVariables { diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/UrlRewriteFileParser.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/UrlRewriteFileParser.cs similarity index 96% rename from src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/UrlRewriteFileParser.cs rename to src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/UrlRewriteFileParser.cs index d3d071585c..3a2f603c07 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/UrlRewriteFileParser.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/UrlRewriteFileParser.cs @@ -8,20 +8,20 @@ using System.Linq; using System.Xml; using System.Xml.Linq; -namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite +namespace Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite { public class UrlRewriteFileParser { private readonly InputParser _inputParser = new InputParser(); - public IList Parse(TextReader reader) + public IList Parse(TextReader reader) { var xmlDoc = XDocument.Load(reader, LoadOptions.SetLineInfo); var xmlRoot = xmlDoc.Descendants(RewriteTags.Rewrite).FirstOrDefault(); if (xmlRoot != null) { - var result = new List(); + var result = new List(); // TODO Global rules are currently not treated differently than normal rules, fix. // See: https://github.com/aspnet/BasicMiddleware/issues/59 ParseRules(xmlRoot.Descendants(RewriteTags.GlobalRules).FirstOrDefault(), result); @@ -31,7 +31,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite return null; } - private void ParseRules(XElement rules, IList result) + private void ParseRules(XElement rules, IList result) { if (rules == null) { @@ -42,7 +42,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite { var builder = new UrlRewriteRuleBuilder(); ParseRuleAttributes(rule, builder); - + if (builder.Enabled) { result.Add(builder.Build()); @@ -121,7 +121,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite LogicalGrouping grouping; if (!Enum.TryParse(conditions.Attribute(RewriteTags.MatchType)?.Value, out grouping)) { - grouping = LogicalGrouping.MatchAll; + grouping = LogicalGrouping.MatchAll; } bool trackingAllCaptures; diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/UrlRewriteRuleBuilder.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/UrlRewriteRuleBuilder.cs similarity index 95% rename from src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/UrlRewriteRuleBuilder.cs rename to src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/UrlRewriteRuleBuilder.cs index cf9467ad9e..b4bf4260c4 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/UrlRewriteRuleBuilder.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/UrlRewriteRuleBuilder.cs @@ -5,11 +5,10 @@ using System; using System.Collections.Generic; using System.Text.RegularExpressions; using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Rewrite.Internal.ModRewrite; using Microsoft.AspNetCore.Rewrite.Internal.UrlActions; using Microsoft.AspNetCore.Rewrite.Internal.UrlMatches; -namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite +namespace Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite { public class UrlRewriteRuleBuilder { @@ -23,14 +22,14 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite private UrlAction _action; private bool _matchAny; - public UrlRewriteRule Build() + public IISUrlRewriteRule Build() { if (_initialMatch == null || _action == null) { throw new InvalidOperationException("Cannot create UrlRewriteRule without action and match"); } - return new UrlRewriteRule(Name, _initialMatch, _conditions, _action); + return new IISUrlRewriteRule(Name, _initialMatch, _conditions, _action); } public void AddUrlAction( @@ -107,11 +106,11 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite } var regex = new Regex( - pattern, + pattern, ignoreCase ? RegexOptions.CultureInvariant | RegexOptions.Compiled | RegexOptions.IgnoreCase : RegexOptions.CultureInvariant | RegexOptions.Compiled, RegexTimeout); - + _conditions.Add(new Condition { Input = input, Match = new RegexMatch(regex, negate), OrNext = _matchAny }); break; } diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/CodeRules/RedirectRule.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/RedirectRule.cs similarity index 96% rename from src/Microsoft.AspNetCore.Rewrite/Internal/CodeRules/RedirectRule.cs rename to src/Microsoft.AspNetCore.Rewrite/Internal/RedirectRule.cs index 2a68eb1b3c..449ae293a4 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/CodeRules/RedirectRule.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/RedirectRule.cs @@ -6,7 +6,7 @@ using System.Text.RegularExpressions; using Microsoft.AspNetCore.Http; using Microsoft.Net.Http.Headers; -namespace Microsoft.AspNetCore.Rewrite.Internal.CodeRules +namespace Microsoft.AspNetCore.Rewrite.Internal { public class RedirectRule : Rule { @@ -71,7 +71,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.CodeRules var query = context.HttpContext.Request.QueryString.Add( QueryString.FromUriComponent( newPath.Substring(split))); - // not using the HttpContext.Response.redirect here because status codes may be 301, 302, 307, 308 + // not using the HttpContext.Response.redirect here because status codes may be 301, 302, 307, 308 response.Headers[HeaderNames.Location] = pathBase + newPath.Substring(0, split) + query; } else diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/CodeRules/RedirectToHttpsRule.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/RedirectToHttpsRule.cs similarity index 95% rename from src/Microsoft.AspNetCore.Rewrite/Internal/CodeRules/RedirectToHttpsRule.cs rename to src/Microsoft.AspNetCore.Rewrite/Internal/RedirectToHttpsRule.cs index a4b99de157..139b70d3e4 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/CodeRules/RedirectToHttpsRule.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/RedirectToHttpsRule.cs @@ -4,7 +4,7 @@ using System.Text; using Microsoft.AspNetCore.Http; -namespace Microsoft.AspNetCore.Rewrite.Internal.CodeRules +namespace Microsoft.AspNetCore.Rewrite.Internal { public class RedirectToHttpsRule : Rule { diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/CodeRules/RewriteRule.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/RewriteRule.cs similarity index 98% rename from src/Microsoft.AspNetCore.Rewrite/Internal/CodeRules/RewriteRule.cs rename to src/Microsoft.AspNetCore.Rewrite/Internal/RewriteRule.cs index d930a2b279..9bacf4963d 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/CodeRules/RewriteRule.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/RewriteRule.cs @@ -6,7 +6,7 @@ using System.Text.RegularExpressions; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http.Extensions; -namespace Microsoft.AspNetCore.Rewrite.Internal.CodeRules +namespace Microsoft.AspNetCore.Rewrite.Internal { public class RewriteRule : Rule { diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/ChangeCookieAction.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/ChangeCookieAction.cs index 5bc7d0ee87..3bdd95e990 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/ChangeCookieAction.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/ChangeCookieAction.cs @@ -2,7 +2,6 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; -using Microsoft.AspNetCore.Http; namespace Microsoft.AspNetCore.Rewrite.Internal.UrlActions { diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/ChangeEnvironmentAction.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/ChangeEnvironmentAction.cs index 9854155678..c0b314a643 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/ChangeEnvironmentAction.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/ChangeEnvironmentAction.cs @@ -2,7 +2,6 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; -using Microsoft.AspNetCore.Http; namespace Microsoft.AspNetCore.Rewrite.Internal.UrlActions { diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/RedirectAction.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/RedirectAction.cs index b295804064..4d85531c87 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/RedirectAction.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/RedirectAction.cs @@ -2,9 +2,7 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; -using System.Collections.Generic; using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Rewrite.Internal.PatternSegments; using Microsoft.Net.Http.Headers; namespace Microsoft.AspNetCore.Rewrite.Internal.UrlActions diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/RewriteAction.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/RewriteAction.cs index 92a4b9c070..74264a9079 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/RewriteAction.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/RewriteAction.cs @@ -33,14 +33,14 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlActions public RewriteAction( RuleTermination result, Pattern pattern, - bool queryStringAppend): - this (result, + bool queryStringAppend) : + this(result, pattern, queryStringAppend, queryStringDelete: false, escapeBackReferences: false) { - + } public override void ApplyAction(RewriteContext context, MatchResults ruleMatch, MatchResults condMatch) diff --git a/src/Microsoft.AspNetCore.Rewrite/RewriteMiddleware.cs b/src/Microsoft.AspNetCore.Rewrite/RewriteMiddleware.cs index d02a28a6db..032b2250ee 100644 --- a/src/Microsoft.AspNetCore.Rewrite/RewriteMiddleware.cs +++ b/src/Microsoft.AspNetCore.Rewrite/RewriteMiddleware.cs @@ -32,9 +32,9 @@ namespace Microsoft.AspNetCore.Rewrite /// The Logger Factory. /// The middleware options, containing the rules to apply. public RewriteMiddleware( - RequestDelegate next, - IHostingEnvironment hostingEnvironment, - ILoggerFactory loggerFactory, + RequestDelegate next, + IHostingEnvironment hostingEnvironment, + ILoggerFactory loggerFactory, RewriteOptions options) { if (next == null) @@ -64,7 +64,9 @@ namespace Microsoft.AspNetCore.Rewrite { throw new ArgumentNullException(nameof(context)); } - var rewriteContext = new RewriteContext { + + var rewriteContext = new RewriteContext + { HttpContext = context, StaticFileProvider = _fileProvider, Logger = _logger, diff --git a/src/Microsoft.AspNetCore.Rewrite/RewriteOptionsExtensions.cs b/src/Microsoft.AspNetCore.Rewrite/RewriteOptionsExtensions.cs index 4d89e13d3c..906c107952 100644 --- a/src/Microsoft.AspNetCore.Rewrite/RewriteOptionsExtensions.cs +++ b/src/Microsoft.AspNetCore.Rewrite/RewriteOptionsExtensions.cs @@ -3,13 +3,11 @@ using System; using Microsoft.AspNetCore.Rewrite.Internal; -using Microsoft.AspNetCore.Rewrite.Internal.CodeRules; -using Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite; namespace Microsoft.AspNetCore.Rewrite { /// - /// The builder to a list of rules for and + /// The builder to a list of rules for and /// public static class RewriteOptionsExtensions { @@ -90,7 +88,7 @@ namespace Microsoft.AspNetCore.Rewrite } /// - /// Redirect a request to https if the incoming request is http, with returning a 301 + /// Redirect a request to https if the incoming request is http, with returning a 301 /// status code for permanently redirected. /// /// diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/ModRewrite/ConditionPatternParserTest.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/ApacheModRewrite/ConditionPatternParserTest.cs similarity index 99% rename from test/Microsoft.AspNetCore.Rewrite.Tests/ModRewrite/ConditionPatternParserTest.cs rename to test/Microsoft.AspNetCore.Rewrite.Tests/ApacheModRewrite/ConditionPatternParserTest.cs index 7d67317e1b..99a58c0b88 100644 --- a/test/Microsoft.AspNetCore.Rewrite.Tests/ModRewrite/ConditionPatternParserTest.cs +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/ApacheModRewrite/ConditionPatternParserTest.cs @@ -2,7 +2,7 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; -using Microsoft.AspNetCore.Rewrite.Internal.ModRewrite; +using Microsoft.AspNetCore.Rewrite.Internal.ApacheModRewrite; using Xunit; namespace Microsoft.AspNetCore.Rewrite.Tests.ModRewrite diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/ModRewrite/FlagParserTest.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/ApacheModRewrite/FlagParserTest.cs similarity index 98% rename from test/Microsoft.AspNetCore.Rewrite.Tests/ModRewrite/FlagParserTest.cs rename to test/Microsoft.AspNetCore.Rewrite.Tests/ApacheModRewrite/FlagParserTest.cs index d788fa25b9..8270bc07cc 100644 --- a/test/Microsoft.AspNetCore.Rewrite.Tests/ModRewrite/FlagParserTest.cs +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/ApacheModRewrite/FlagParserTest.cs @@ -4,7 +4,7 @@ using System; using System.Collections.Generic; using System.Linq; -using Microsoft.AspNetCore.Rewrite.Internal.ModRewrite; +using Microsoft.AspNetCore.Rewrite.Internal.ApacheModRewrite; using Xunit; namespace Microsoft.AspNetCore.Rewrite.Tests.ModRewrite diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/ModRewrite/FormatExceptionTests.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/ApacheModRewrite/FormatExceptionTests.cs similarity index 97% rename from test/Microsoft.AspNetCore.Rewrite.Tests/ModRewrite/FormatExceptionTests.cs rename to test/Microsoft.AspNetCore.Rewrite.Tests/ApacheModRewrite/FormatExceptionTests.cs index 6c0913565a..acf46b3765 100644 --- a/test/Microsoft.AspNetCore.Rewrite.Tests/ModRewrite/FormatExceptionTests.cs +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/ApacheModRewrite/FormatExceptionTests.cs @@ -3,7 +3,7 @@ using System; using System.IO; -using Microsoft.AspNetCore.Rewrite.Internal.ModRewrite; +using Microsoft.AspNetCore.Rewrite.Internal.ApacheModRewrite; using Xunit; namespace Microsoft.AspNetCore.Rewrite.Tests.ModRewrite diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/ModRewrite/ModRewriteMiddlewareTest.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/ApacheModRewrite/ModRewriteMiddlewareTest.cs similarity index 100% rename from test/Microsoft.AspNetCore.Rewrite.Tests/ModRewrite/ModRewriteMiddlewareTest.cs rename to test/Microsoft.AspNetCore.Rewrite.Tests/ApacheModRewrite/ModRewriteMiddlewareTest.cs diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/ModRewrite/RewriteTokenizerTest.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/ApacheModRewrite/RewriteTokenizerTest.cs similarity index 98% rename from test/Microsoft.AspNetCore.Rewrite.Tests/ModRewrite/RewriteTokenizerTest.cs rename to test/Microsoft.AspNetCore.Rewrite.Tests/ApacheModRewrite/RewriteTokenizerTest.cs index c3f4ba28ff..98e556df50 100644 --- a/test/Microsoft.AspNetCore.Rewrite.Tests/ModRewrite/RewriteTokenizerTest.cs +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/ApacheModRewrite/RewriteTokenizerTest.cs @@ -3,7 +3,7 @@ using System; using System.Collections.Generic; -using Microsoft.AspNetCore.Rewrite.Internal.ModRewrite; +using Microsoft.AspNetCore.Rewrite.Internal.ApacheModRewrite; using Xunit; namespace Microsoft.AspNetCore.Rewrite.Tests.ModRewrite diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/ModRewrite/RuleRegexParserTest.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/ApacheModRewrite/RuleRegexParserTest.cs similarity index 93% rename from test/Microsoft.AspNetCore.Rewrite.Tests/ModRewrite/RuleRegexParserTest.cs rename to test/Microsoft.AspNetCore.Rewrite.Tests/ApacheModRewrite/RuleRegexParserTest.cs index 16a7954700..fefc5f2b2e 100644 --- a/test/Microsoft.AspNetCore.Rewrite.Tests/ModRewrite/RuleRegexParserTest.cs +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/ApacheModRewrite/RuleRegexParserTest.cs @@ -2,7 +2,7 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; -using Microsoft.AspNetCore.Rewrite.Internal.ModRewrite; +using Microsoft.AspNetCore.Rewrite.Internal.ApacheModRewrite; using Xunit; namespace Microsoft.AspNetCore.Rewrite.Tests.ModRewrite diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/ModRewrite/TestStringParserTests.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/ApacheModRewrite/TestStringParserTests.cs similarity index 98% rename from test/Microsoft.AspNetCore.Rewrite.Tests/ModRewrite/TestStringParserTests.cs rename to test/Microsoft.AspNetCore.Rewrite.Tests/ApacheModRewrite/TestStringParserTests.cs index b07dcdd7c6..917e628040 100644 --- a/test/Microsoft.AspNetCore.Rewrite.Tests/ModRewrite/TestStringParserTests.cs +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/ApacheModRewrite/TestStringParserTests.cs @@ -4,7 +4,7 @@ using System; using System.Collections.Generic; using Microsoft.AspNetCore.Rewrite.Internal; -using Microsoft.AspNetCore.Rewrite.Internal.ModRewrite; +using Microsoft.AspNetCore.Rewrite.Internal.ApacheModRewrite; using Microsoft.AspNetCore.Rewrite.Internal.PatternSegments; using Xunit; diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/UrlRewrite/FileParserTests.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/FileParserTests.cs similarity index 92% rename from test/Microsoft.AspNetCore.Rewrite.Tests/UrlRewrite/FileParserTests.cs rename to test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/FileParserTests.cs index 4512d9328b..afa76bb395 100644 --- a/test/Microsoft.AspNetCore.Rewrite.Tests/UrlRewrite/FileParserTests.cs +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/FileParserTests.cs @@ -5,10 +5,10 @@ using System.Collections.Generic; using System.IO; using System.Text.RegularExpressions; using Microsoft.AspNetCore.Rewrite.Internal; -using Microsoft.AspNetCore.Rewrite.Internal.ModRewrite; +using Microsoft.AspNetCore.Rewrite.Internal.ApacheModRewrite; using Microsoft.AspNetCore.Rewrite.Internal.UrlActions; using Microsoft.AspNetCore.Rewrite.Internal.UrlMatches; -using Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite; +using Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite; using Xunit; namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite @@ -28,7 +28,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite "; - var expected = new List(); + var expected = new List(); expected.Add(CreateTestRule(new List(), url: "^article/([0-9]+)/([_0-9a-z-]+)", name: "Rewrite to article.aspx", @@ -65,7 +65,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite Match = new RegexMatch(new Regex("^OFF$"), false) }); - var expected = new List(); + var expected = new List(); expected.Add(CreateTestRule(condList, url: "^article/([0-9]+)/([_0-9a-z-]+)", name: "Rewrite to article.aspx", @@ -109,7 +109,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite Match = new RegexMatch(new Regex("^OFF$"), false) }); - var expected = new List(); + var expected = new List(); expected.Add(CreateTestRule(condList, url: "^article/([0-9]+)/([_0-9a-z-]+)", name: "Rewrite to article.aspx", @@ -129,7 +129,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite } // Creates a rule with appropriate default values of the url rewrite rule. - private UrlRewriteRule CreateTestRule(List conditions, + private IISUrlRewriteRule CreateTestRule(List conditions, LogicalGrouping condGrouping = LogicalGrouping.MatchAll, bool condTracking = false, string name = "", @@ -146,12 +146,12 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite RedirectType redirectType = RedirectType.Permanent ) { - return new UrlRewriteRule(name, new RegexMatch(new Regex("^OFF$"), false), conditions, + return new IISUrlRewriteRule(name, new RegexMatch(new Regex("^OFF$"), false), conditions, new RewriteAction(RuleTermination.Continue, new InputParser().ParseInputString(url), queryStringAppend: false)); } // TODO make rules comparable? - private void AssertUrlRewriteRuleEquality(IList actual, IList expected) + private void AssertUrlRewriteRuleEquality(IList actual, IList expected) { Assert.Equal(actual.Count, expected.Count); for (var i = 0; i < actual.Count; i++) diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/UrlRewrite/FormatExceptionHandlingTests.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/FormatExceptionHandlingTests.cs similarity index 98% rename from test/Microsoft.AspNetCore.Rewrite.Tests/UrlRewrite/FormatExceptionHandlingTests.cs rename to test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/FormatExceptionHandlingTests.cs index 41adf2fbbc..3b77f78290 100644 --- a/test/Microsoft.AspNetCore.Rewrite.Tests/UrlRewrite/FormatExceptionHandlingTests.cs +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/FormatExceptionHandlingTests.cs @@ -3,7 +3,7 @@ using System; using System.IO; -using Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite; +using Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite; using Xunit; namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/UrlRewrite/InputParserTests.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/InputParserTests.cs similarity index 98% rename from test/Microsoft.AspNetCore.Rewrite.Tests/UrlRewrite/InputParserTests.cs rename to test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/InputParserTests.cs index 0f4b2ba7fb..29299a9287 100644 --- a/test/Microsoft.AspNetCore.Rewrite.Tests/UrlRewrite/InputParserTests.cs +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/InputParserTests.cs @@ -5,7 +5,7 @@ using System; using System.Text.RegularExpressions; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Rewrite.Internal; -using Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite; +using Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite; using Xunit; namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/UrlRewrite/MiddleWareTests.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/MiddleWareTests.cs similarity index 100% rename from test/Microsoft.AspNetCore.Rewrite.Tests/UrlRewrite/MiddleWareTests.cs rename to test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/MiddleWareTests.cs diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/UrlRewrite/ServerVariableTests.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/ServerVariableTests.cs similarity index 97% rename from test/Microsoft.AspNetCore.Rewrite.Tests/UrlRewrite/ServerVariableTests.cs rename to test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/ServerVariableTests.cs index 206544b447..3235ab7d1e 100644 --- a/test/Microsoft.AspNetCore.Rewrite.Tests/UrlRewrite/ServerVariableTests.cs +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/ServerVariableTests.cs @@ -4,7 +4,7 @@ using System.Text.RegularExpressions; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Rewrite.Internal; -using Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite; +using Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite; using Microsoft.Net.Http.Headers; using Xunit; diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/UrlRewrite/UrlRewriteApplicationTests.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/UrlRewriteApplicationTests.cs similarity index 96% rename from test/Microsoft.AspNetCore.Rewrite.Tests/UrlRewrite/UrlRewriteApplicationTests.cs rename to test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/UrlRewriteApplicationTests.cs index 8892155eff..bbb04f1f7e 100644 --- a/test/Microsoft.AspNetCore.Rewrite.Tests/UrlRewrite/UrlRewriteApplicationTests.cs +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/UrlRewriteApplicationTests.cs @@ -4,7 +4,7 @@ using System.IO; using System.Linq; using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite; +using Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite; using Xunit; namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/CodeRules/MiddlewareTests.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/MiddlewareTests.cs similarity index 100% rename from test/Microsoft.AspNetCore.Rewrite.Tests/CodeRules/MiddlewareTests.cs rename to test/Microsoft.AspNetCore.Rewrite.Tests/MiddlewareTests.cs From 7e4c9aaebc1e9313bfdcb05d9f9b370c47fb7b33 Mon Sep 17 00:00:00 2001 From: Doug Bunting Date: Sat, 3 Sep 2016 22:14:30 -0700 Subject: [PATCH 107/307] Increase .travis.yml consistency between repos - aspnet/Universe#349 - minimize `dotnet` setup time; no need for caching - build with `--quiet` --- .travis.yml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index b35f525a0e..6c42dd8a71 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,6 +10,10 @@ addons: - libssl-dev - libunwind8 - zlib1g +env: + global: + - DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true + - DOTNET_CLI_TELEMETRY_OPTOUT: 1 mono: - 4.0.5 os: @@ -25,7 +29,7 @@ branches: before_install: - if test "$TRAVIS_OS_NAME" == "osx"; then brew update; brew install openssl; ln -s /usr/local/opt/openssl/lib/libcrypto.1.0.0.dylib /usr/local/lib/; ln -s /usr/local/opt/openssl/lib/libssl.1.0.0.dylib /usr/local/lib/; fi script: - - ./build.sh verify + - ./build.sh --quiet verify notifications: webhooks: secure: "Quayhq8pTWtpCfsC209l4o3ZG75VhEKjTOcuOPDYoQXII4rfmVbnGUoe6A6R3VTz7/O2YTPbX3+ooBrTJufwiJXJG74xZuE35jKnRm3HQREH9tCNUYwB4BO7jzoWz9wXDDfCPs47Tkjdf46Tq0jF27nXrZhNzm6ps3JCoP6/lA+8lEfWxIYifviwxJ392S34k5SyaVYeOIs+W95Iuvmd6+ZenVZNvPaGwHzTKqVhh/NYttbQ3oUq4n2fWaIrwGVi7MC6CtINoG/CtmUU3pef+StPOYMjWfMGcUjAkikWWEsCDnUSOpmNxKREKqXXbOBPDCcC9sNkzpYa0ksHRwGQv2jagVYaAicNfGc/gtWJ3JTCnODUea6oTsmdZT7hNW1ClzOEacXHv55TzImgAb1MFD9euSoXBIa9rRNYhx1oy3JYal2Ee0crPF1nFxQJ5mVT9pGEhpMqAwdNaZBwA5urVn6bl0ptPb8W6XVw5/qgPdBvmF67Xjw+k3TDQ3J4sWClGdX4ZsfgVFLSDGk9hqudPp10XlXkAscYtpKoZIEIK5rVa7RnvI44Bh1eQRqFpqKa2m1gVquJwUQg0L8CPakZDscas29dtXY4KqHrspOOtolhtOUaVpanQCGFWgPnWxIx9m+3eDRCLSjhvrZyZwemmvqXNqFhKUILdQLo1itANDo=" From 2807e0b4361008f015ea478d4555b3bb1e4a0ce7 Mon Sep 17 00:00:00 2001 From: Pavel Krymets Date: Wed, 7 Sep 2016 10:17:04 -0700 Subject: [PATCH 108/307] Use TaskCache class from Microsoft.Extensions.TaskCache.Sources instead of Task.FromResult(0) (#99) --- src/Microsoft.AspNetCore.Buffering/BufferingWriteStream.cs | 3 ++- src/Microsoft.AspNetCore.Buffering/project.json | 6 +++++- src/Microsoft.AspNetCore.Rewrite/RewriteMiddleware.cs | 5 ++--- src/Microsoft.AspNetCore.Rewrite/project.json | 6 +++++- 4 files changed, 14 insertions(+), 6 deletions(-) diff --git a/src/Microsoft.AspNetCore.Buffering/BufferingWriteStream.cs b/src/Microsoft.AspNetCore.Buffering/BufferingWriteStream.cs index 9de26d9271..f3f4dbe8fe 100644 --- a/src/Microsoft.AspNetCore.Buffering/BufferingWriteStream.cs +++ b/src/Microsoft.AspNetCore.Buffering/BufferingWriteStream.cs @@ -5,6 +5,7 @@ using System; using System.IO; using System.Threading; using System.Threading.Tasks; +using Microsoft.Extensions.Internal; namespace Microsoft.AspNetCore.Buffering { @@ -133,7 +134,7 @@ namespace Microsoft.AspNetCore.Buffering { return FlushAsync(cancellationToken); } - return Task.FromResult(0); + return TaskCache.CompletedTask; } public override void Write(byte[] buffer, int offset, int count) diff --git a/src/Microsoft.AspNetCore.Buffering/project.json b/src/Microsoft.AspNetCore.Buffering/project.json index c202a5178b..fa9d8bf0ad 100644 --- a/src/Microsoft.AspNetCore.Buffering/project.json +++ b/src/Microsoft.AspNetCore.Buffering/project.json @@ -21,7 +21,11 @@ ] }, "dependencies": { - "Microsoft.AspNetCore.Http.Abstractions": "1.1.0-*" + "Microsoft.AspNetCore.Http.Abstractions": "1.1.0-*", + "Microsoft.Extensions.TaskCache.Sources": { + "version": "1.1.0-*", + "type": "build" + } }, "frameworks": { "net451": {}, diff --git a/src/Microsoft.AspNetCore.Rewrite/RewriteMiddleware.cs b/src/Microsoft.AspNetCore.Rewrite/RewriteMiddleware.cs index 032b2250ee..7838ecbc0a 100644 --- a/src/Microsoft.AspNetCore.Rewrite/RewriteMiddleware.cs +++ b/src/Microsoft.AspNetCore.Rewrite/RewriteMiddleware.cs @@ -7,6 +7,7 @@ using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Rewrite.Logging; using Microsoft.Extensions.FileProviders; +using Microsoft.Extensions.Internal; using Microsoft.Extensions.Logging; using Microsoft.Net.Http.Headers; @@ -17,8 +18,6 @@ namespace Microsoft.AspNetCore.Rewrite /// public class RewriteMiddleware { - private static readonly Task CompletedTask = Task.FromResult(0); - private readonly RequestDelegate _next; private readonly RewriteOptions _options; private readonly IFileProvider _fileProvider; @@ -85,7 +84,7 @@ namespace Microsoft.AspNetCore.Rewrite _logger.RewriteMiddlewareRequestResponseComplete( context.Response.Headers[HeaderNames.Location], context.Response.StatusCode); - return CompletedTask; + return TaskCache.CompletedTask; case RuleTermination.StopRules: _logger.RewriteMiddlewareRequestStopRules(); return _next(context); diff --git a/src/Microsoft.AspNetCore.Rewrite/project.json b/src/Microsoft.AspNetCore.Rewrite/project.json index 866c21b8a2..b88732b107 100644 --- a/src/Microsoft.AspNetCore.Rewrite/project.json +++ b/src/Microsoft.AspNetCore.Rewrite/project.json @@ -26,7 +26,11 @@ "Microsoft.Extensions.Configuration.Abstractions": "1.1.0-*", "Microsoft.Extensions.FileProviders.Abstractions": "1.1.0-*", "Microsoft.Extensions.Logging.Abstractions": "1.1.0-*", - "Microsoft.Extensions.Options": "1.1.0-*" + "Microsoft.Extensions.Options": "1.1.0-*", + "Microsoft.Extensions.TaskCache.Sources": { + "version": "1.1.0-*", + "type": "build" + } }, "frameworks": { "net451": { From d2913edf61a094a75cf9e9393c727c7e6db3d5d2 Mon Sep 17 00:00:00 2001 From: Mikael Mengistu Date: Mon, 12 Sep 2016 10:50:30 -0700 Subject: [PATCH 109/307] Added tests for ExactMatch, IntegerMatch and StringMatch in the Rewrite project. --- .../Internal/UrlMatches/IntegerMatch.cs | 3 +- .../Properties/AssemblyInfo.cs | 2 + .../Properties/Resources.Designer.cs | 16 ++++++++ .../Resources.resx | 3 ++ .../UrlMatches/ExactMatchTests.cs | 27 ++++++++++++ .../UrlMatches/IntegerMatchTests.cs | 41 +++++++++++++++++++ .../UrlMatches/StringMatchTests.cs | 29 +++++++++++++ .../project.json | 8 +++- 8 files changed, 127 insertions(+), 2 deletions(-) create mode 100644 test/Microsoft.AspNetCore.Rewrite.Tests/UrlMatches/ExactMatchTests.cs create mode 100644 test/Microsoft.AspNetCore.Rewrite.Tests/UrlMatches/IntegerMatchTests.cs create mode 100644 test/Microsoft.AspNetCore.Rewrite.Tests/UrlMatches/StringMatchTests.cs diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlMatches/IntegerMatch.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlMatches/IntegerMatch.cs index 770bbbd6d1..73b814731f 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlMatches/IntegerMatch.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlMatches/IntegerMatch.cs @@ -3,6 +3,7 @@ using System; using System.Globalization; +using Microsoft.AspNetCore.Rewrite; namespace Microsoft.AspNetCore.Rewrite.Internal.UrlMatches { @@ -21,7 +22,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlMatches int compValue; if (!int.TryParse(value, NumberStyles.None, CultureInfo.InvariantCulture, out compValue)) { - throw new FormatException("Syntax error for integers in comparison."); + throw new FormatException(Resources.Error_IntegerMatch_FormatExceptionMessage); } _value = compValue; _operation = operation; diff --git a/src/Microsoft.AspNetCore.Rewrite/Properties/AssemblyInfo.cs b/src/Microsoft.AspNetCore.Rewrite/Properties/AssemblyInfo.cs index 2dc4003a17..b56ddcf4e4 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Properties/AssemblyInfo.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Properties/AssemblyInfo.cs @@ -3,9 +3,11 @@ using System.Reflection; using System.Resources; +using System.Runtime.CompilerServices; [assembly: AssemblyMetadata("Serviceable", "True")] [assembly: NeutralResourcesLanguage("en-us")] [assembly: AssemblyCompany("Microsoft Corporation.")] [assembly: AssemblyCopyright("© Microsoft Corporation. All rights reserved.")] [assembly: AssemblyProduct("Microsoft ASP.NET Core")] +[assembly: InternalsVisibleTo("Microsoft.AspNetCore.Rewrite.Tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")] diff --git a/src/Microsoft.AspNetCore.Rewrite/Properties/Resources.Designer.cs b/src/Microsoft.AspNetCore.Rewrite/Properties/Resources.Designer.cs index 4ab56f4ce3..25261d8664 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Properties/Resources.Designer.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Properties/Resources.Designer.cs @@ -138,6 +138,22 @@ namespace Microsoft.AspNetCore.Rewrite return string.Format(CultureInfo.CurrentCulture, GetString("Error_ModRewriteGeneralParseError"), p0); } + /// + /// Syntax error for integers in comparison. + /// + internal static string Error_IntegerMatch_FormatExceptionMessage + { + get { return GetString("Error_IntegerMatch_FormatExceptionMessage"); } + } + + /// + /// Syntax error for integers in comparison. + /// + internal static string FormatError_IntegerMatch_FormatExceptionMessage() + { + return GetString("Error_IntegerMatch_FormatExceptionMessage"); + } + private static string GetString(string name, params string[] formatterNames) { var value = _resourceManager.GetString(name); diff --git a/src/Microsoft.AspNetCore.Rewrite/Resources.resx b/src/Microsoft.AspNetCore.Rewrite/Resources.resx index cb7277289a..70a314f06b 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Resources.resx +++ b/src/Microsoft.AspNetCore.Rewrite/Resources.resx @@ -141,4 +141,7 @@ Could not parse the mod_rewrite file. Line number '{0}'. + + Syntax error for integers in comparison. + \ No newline at end of file diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/UrlMatches/ExactMatchTests.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/UrlMatches/ExactMatchTests.cs new file mode 100644 index 0000000000..9b85354adc --- /dev/null +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/UrlMatches/ExactMatchTests.cs @@ -0,0 +1,27 @@ +// 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 Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Rewrite.Internal; +using Microsoft.AspNetCore.Rewrite.Internal.UrlActions; +using Microsoft.AspNetCore.Rewrite.Internal.UrlMatches; +using Xunit; + +namespace Microsoft.AspNetCore.Rewrite.Tests.UrlMatches +{ + public class ExactMatchTests + { + [Theory] + [InlineDataAttribute(true,"string",false,"string",true)] + [InlineDataAttribute(true, "string", true, "string", false)] + [InlineDataAttribute(false, "STRING", false, "string",false)] + [InlineDataAttribute(false, "STRING", true, "string", true)] + public void ExactMatch_Case_Sensitivity_Negate_Tests(bool ignoreCase, string inputString, bool negate, string pattern, bool expectedResult) + { + var context = new RewriteContext { HttpContext = new DefaultHttpContext() }; + var Match = new ExactMatch(ignoreCase, inputString, negate); + var matchResults = Match.Evaluate(pattern, context); + Assert.Equal(matchResults.Success, expectedResult); + } + } +} diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/UrlMatches/IntegerMatchTests.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/UrlMatches/IntegerMatchTests.cs new file mode 100644 index 0000000000..bb7408d9f6 --- /dev/null +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/UrlMatches/IntegerMatchTests.cs @@ -0,0 +1,41 @@ +// 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; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Rewrite; +using Microsoft.AspNetCore.Rewrite.Internal; +using Microsoft.AspNetCore.Rewrite.Internal.UrlActions; +using Microsoft.AspNetCore.Rewrite.Internal.UrlMatches; +using Xunit; + +namespace Microsoft.AspNetCore.Rewrite.Tests.UrlMatches +{ + public class IntegerMatchTests + { + [Fact] + public void IntegerMatch_Constructor_Integer_Parse_Excetion() + { + var ex = Assert.Throws(() => new IntegerMatch("Not an int", IntegerOperationType.Equal)); + Assert.Equal(ex.Message, Resources.Error_IntegerMatch_FormatExceptionMessage); + } + + [Theory] + [InlineData(1,IntegerOperationType.Equal,"1",true)] + [InlineData(1, IntegerOperationType.NotEqual, "2", true)] + [InlineData(2, IntegerOperationType.Less, "1", true)] + [InlineData(1, IntegerOperationType.LessEqual, "2", false)] + [InlineData(1, IntegerOperationType.Greater, "2", true)] + [InlineData(2, IntegerOperationType.GreaterEqual, "1", false)] + [InlineData(1, IntegerOperationType.Equal, "Not an int", false)] + [InlineData(1, IntegerOperationType.Equal, "", false)] + [InlineData(1, IntegerOperationType.Equal, "2147483648", false)] + public void IntegerMatch_Evaluation_Cases_Tests(int value,IntegerOperationType operation, string input,bool expectedResult) + { + var context = new RewriteContext { HttpContext = new DefaultHttpContext() }; + var integerMatch = new IntegerMatch(value, operation); + var matchResult = integerMatch.Evaluate(input, context); + Assert.Equal(matchResult.Success, expectedResult); + } + } +} diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/UrlMatches/StringMatchTests.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/UrlMatches/StringMatchTests.cs new file mode 100644 index 0000000000..0cd62e1f91 --- /dev/null +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/UrlMatches/StringMatchTests.cs @@ -0,0 +1,29 @@ +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Rewrite.Internal.UrlMatches; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Xunit; + +namespace Microsoft.AspNetCore.Rewrite.Tests.UrlMatches +{ + public class StringMatchTests + { + [Theory] + [InlineData("hi", StringOperationType.Equal,true,"hi",true)] + [InlineData("a", StringOperationType.Greater, true, "b", true)] + [InlineData("a", StringOperationType.GreaterEqual, true, "b", true)] + [InlineData("b", StringOperationType.Less,true, "a", true)] + [InlineData("b", StringOperationType.LessEqual, true, "a", true)] + [InlineData("", StringOperationType.Equal, true, "", true)] + [InlineData(null, StringOperationType.Equal, true, null, true)] + public void StringMatch_Evaluation_Check_Cases(string value, StringOperationType operation, bool ignoreCase, string input, bool expectedResult) + { + var context = new RewriteContext { HttpContext = new DefaultHttpContext() }; + var stringMatch = new StringMatch(value, operation, ignoreCase); + var matchResult = stringMatch.Evaluate(input, context); + Assert.Equal(matchResult.Success, expectedResult); + } + } +} diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/project.json b/test/Microsoft.AspNetCore.Rewrite.Tests/project.json index 904880d014..53270ebe77 100644 --- a/test/Microsoft.AspNetCore.Rewrite.Tests/project.json +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/project.json @@ -1,7 +1,8 @@ { "version": "1.1.0-*", "buildOptions": { - "warningsAsErrors": true + "warningsAsErrors": true, + "keyFile": "../../tools/Key.snk" }, "dependencies": { "dotnet-test-xunit": "2.2.0-*", @@ -12,7 +13,12 @@ }, "frameworks": { "netcoreapp1.0": { + "imports": "dnxcore50", "dependencies": { + "Microsoft.CodeCoverage": { + "type": "build", + "version": "1.0.1" + }, "Microsoft.NETCore.App": { "version": "1.0.0-*", "type": "platform" From d2fb2cd77685134a25bd4ff959c2158764e31dea Mon Sep 17 00:00:00 2001 From: Nate McMaster Date: Tue, 6 Sep 2016 11:07:41 -0700 Subject: [PATCH 110/307] Change the IHostingEnvironment parameter to IFileProvider for top-level IIS and Apache extension methods Also fixup some xmldocs --- samples/RewriteSample/Startup.cs | 6 ++-- .../ApacheModRewriteOptionsExtensions.cs | 29 +++++++---------- .../RewriteMiddlewareLoggingExtensions.cs | 0 .../IISUrlRewriteOptionsExtensions.cs | 31 +++++++++---------- .../RewriteBuilderExtensions.cs | 2 +- .../RewriteMiddleware.cs | 2 +- .../RewriteOptions.cs | 3 +- .../RewriteOptionsExtensions.cs | 20 ++++++------ src/Microsoft.AspNetCore.Rewrite/Rule.cs | 4 +-- 9 files changed, 45 insertions(+), 52 deletions(-) rename src/Microsoft.AspNetCore.Rewrite/{Logging => Extensions}/RewriteMiddlewareLoggingExtensions.cs (100%) diff --git a/samples/RewriteSample/Startup.cs b/samples/RewriteSample/Startup.cs index 6a76d5df3e..b4bfa3c977 100644 --- a/samples/RewriteSample/Startup.cs +++ b/samples/RewriteSample/Startup.cs @@ -11,14 +11,14 @@ namespace RewriteSample { public class Startup { - public void Configure(IApplicationBuilder app, IHostingEnvironment hostingEnvironment) + public void Configure(IApplicationBuilder app, IHostingEnvironment env) { var options = new RewriteOptions() .AddRedirect("(.*)/$", "$1") .AddRewrite(@"app/(\d+)", "app?id=$1") .AddRedirectToHttps(302) - .AddIISUrlRewrite(hostingEnvironment, "UrlRewrite.xml") - .AddApacheModRewrite(hostingEnvironment, "Rewrite.txt"); + .AddIISUrlRewrite(env.ContentRootFileProvider, "UrlRewrite.xml") + .AddApacheModRewrite(env.ContentRootFileProvider, "Rewrite.txt"); app.UseRewriter(options); diff --git a/src/Microsoft.AspNetCore.Rewrite/ApacheModRewriteOptionsExtensions.cs b/src/Microsoft.AspNetCore.Rewrite/ApacheModRewriteOptionsExtensions.cs index 99aa31ada4..b4779aece7 100644 --- a/src/Microsoft.AspNetCore.Rewrite/ApacheModRewriteOptionsExtensions.cs +++ b/src/Microsoft.AspNetCore.Rewrite/ApacheModRewriteOptionsExtensions.cs @@ -3,50 +3,45 @@ using System; using System.IO; -using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Rewrite.Internal.ApacheModRewrite; +using Microsoft.Extensions.FileProviders; namespace Microsoft.AspNetCore.Rewrite { /// - /// Apache mod_rewrite extensions on top of the + /// Extensions for adding Apache mod_rewrite rules to /// public static class ApacheModRewriteOptionsExtensions { /// - /// Imports rules from a mod_rewrite file and adds the rules to current rules. + /// Add rules from an Apache mod_rewrite file /// - /// The Rewrite options. - /// The Hosting Environment + /// The + /// The /// The path to the file containing mod_rewrite rules. - public static RewriteOptions AddApacheModRewrite(this RewriteOptions options, IHostingEnvironment hostingEnvironment, string filePath) + public static RewriteOptions AddApacheModRewrite(this RewriteOptions options, IFileProvider fileProvider, string filePath) { if (options == null) { throw new ArgumentNullException(nameof(options)); } - if (hostingEnvironment == null) + if (fileProvider == null) { - throw new ArgumentNullException(nameof(hostingEnvironment)); + throw new ArgumentNullException(nameof(fileProvider)); } - if (string.IsNullOrEmpty(filePath)) - { - throw new ArgumentException(nameof(filePath)); - } - - var path = Path.Combine(hostingEnvironment.ContentRootPath, filePath); - using (var stream = File.OpenRead(path)) + var fileInfo = fileProvider.GetFileInfo(filePath); + using (var stream = fileInfo.CreateReadStream()) { return options.AddApacheModRewrite(new StreamReader(stream)); } } /// - /// Imports rules from a mod_rewrite file and adds the rules to current rules. + /// Add rules from an Apache mod_rewrite file /// - /// The Rewrite options. + /// The /// A stream of mod_rewrite rules. public static RewriteOptions AddApacheModRewrite(this RewriteOptions options, TextReader reader) { diff --git a/src/Microsoft.AspNetCore.Rewrite/Logging/RewriteMiddlewareLoggingExtensions.cs b/src/Microsoft.AspNetCore.Rewrite/Extensions/RewriteMiddlewareLoggingExtensions.cs similarity index 100% rename from src/Microsoft.AspNetCore.Rewrite/Logging/RewriteMiddlewareLoggingExtensions.cs rename to src/Microsoft.AspNetCore.Rewrite/Extensions/RewriteMiddlewareLoggingExtensions.cs diff --git a/src/Microsoft.AspNetCore.Rewrite/IISUrlRewriteOptionsExtensions.cs b/src/Microsoft.AspNetCore.Rewrite/IISUrlRewriteOptionsExtensions.cs index 05d49b9ac8..bed837ae44 100644 --- a/src/Microsoft.AspNetCore.Rewrite/IISUrlRewriteOptionsExtensions.cs +++ b/src/Microsoft.AspNetCore.Rewrite/IISUrlRewriteOptionsExtensions.cs @@ -3,50 +3,46 @@ using System; using System.IO; -using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite; +using Microsoft.Extensions.FileProviders; namespace Microsoft.AspNetCore.Rewrite { /// - /// IIS Url rewrite extensions on top of the + /// Extensions for adding IIS Url Rewrite rules to /// public static class IISUrlRewriteOptionsExtensions { /// - /// Imports rules from a mod_rewrite file and adds the rules to current rules. + /// Add rules from a IIS config file containing Url Rewrite rules /// - /// The UrlRewrite options. - /// - /// The path to the file containing urlrewrite rules. - public static RewriteOptions AddIISUrlRewrite(this RewriteOptions options, IHostingEnvironment hostingEnvironment, string filePath) + /// The + /// The + /// The path to the file containing UrlRewrite rules. + public static RewriteOptions AddIISUrlRewrite(this RewriteOptions options, IFileProvider fileProvider, string filePath) { if (options == null) { throw new ArgumentNullException(nameof(options)); } - if (hostingEnvironment == null) + if (fileProvider == null) { - throw new ArgumentNullException(nameof(hostingEnvironment)); + throw new ArgumentNullException(nameof(fileProvider)); } - if (string.IsNullOrEmpty(filePath)) - { - throw new ArgumentException(nameof(filePath)); - } + var file = fileProvider.GetFileInfo(filePath); - var path = Path.Combine(hostingEnvironment.ContentRootPath, filePath); - using (var stream = File.OpenRead(path)) + using (var stream = file.CreateReadStream()) { return AddIISUrlRewrite(options, new StreamReader(stream)); } } /// - /// Imports rules from a mod_rewrite file and adds the rules to current rules. + /// Add rules from a IIS config file containing Url Rewrite rules /// - /// The UrlRewrite options. + /// The /// The text reader stream. public static RewriteOptions AddIISUrlRewrite(this RewriteOptions options, TextReader reader) { @@ -66,6 +62,7 @@ namespace Microsoft.AspNetCore.Rewrite { options.Rules.Add(rule); } + return options; } } diff --git a/src/Microsoft.AspNetCore.Rewrite/RewriteBuilderExtensions.cs b/src/Microsoft.AspNetCore.Rewrite/RewriteBuilderExtensions.cs index 88d7676c30..724dccf3d1 100644 --- a/src/Microsoft.AspNetCore.Rewrite/RewriteBuilderExtensions.cs +++ b/src/Microsoft.AspNetCore.Rewrite/RewriteBuilderExtensions.cs @@ -14,7 +14,7 @@ namespace Microsoft.AspNetCore.Builder /// /// Checks if a given Url matches rules and conditions, and modifies the HttpContext on match. /// - /// + /// The /// Options for rewrite. /// public static IApplicationBuilder UseRewriter(this IApplicationBuilder app, RewriteOptions options) diff --git a/src/Microsoft.AspNetCore.Rewrite/RewriteMiddleware.cs b/src/Microsoft.AspNetCore.Rewrite/RewriteMiddleware.cs index 7838ecbc0a..9f3802d395 100644 --- a/src/Microsoft.AspNetCore.Rewrite/RewriteMiddleware.cs +++ b/src/Microsoft.AspNetCore.Rewrite/RewriteMiddleware.cs @@ -14,7 +14,7 @@ using Microsoft.Net.Http.Headers; namespace Microsoft.AspNetCore.Rewrite { /// - /// Represents a middleware that rewrites urls imported from mod_rewrite, UrlRewrite, and code. + /// Represents a middleware that rewrites urls /// public class RewriteMiddleware { diff --git a/src/Microsoft.AspNetCore.Rewrite/RewriteOptions.cs b/src/Microsoft.AspNetCore.Rewrite/RewriteOptions.cs index f4370cabb4..8e51c78071 100644 --- a/src/Microsoft.AspNetCore.Rewrite/RewriteOptions.cs +++ b/src/Microsoft.AspNetCore.Rewrite/RewriteOptions.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using Microsoft.Extensions.FileProviders; +using Microsoft.AspNetCore.Hosting; namespace Microsoft.AspNetCore.Rewrite { @@ -17,7 +18,7 @@ namespace Microsoft.AspNetCore.Rewrite public IList Rules { get; } = new List(); /// - /// Gets and sets the File Provider for file and directory checks. + /// Gets and sets the File Provider for file and directory checks. Defaults to /// public IFileProvider StaticFileProvider { get; set; } } diff --git a/src/Microsoft.AspNetCore.Rewrite/RewriteOptionsExtensions.cs b/src/Microsoft.AspNetCore.Rewrite/RewriteOptionsExtensions.cs index 906c107952..5b9eec9e88 100644 --- a/src/Microsoft.AspNetCore.Rewrite/RewriteOptionsExtensions.cs +++ b/src/Microsoft.AspNetCore.Rewrite/RewriteOptionsExtensions.cs @@ -14,7 +14,7 @@ namespace Microsoft.AspNetCore.Rewrite /// /// Adds a rule to the current rules. /// - /// The UrlRewrite options. + /// The . /// A rule to be added to the current rules. /// The Rewrite options. public static RewriteOptions Add(this RewriteOptions options, Rule rule) @@ -26,7 +26,7 @@ namespace Microsoft.AspNetCore.Rewrite /// /// Adds a rule to the current rules. /// - /// The Rewrite options. + /// The . /// A Func that checks and applies the rule. /// public static RewriteOptions Add(this RewriteOptions options, Action applyRule) @@ -38,7 +38,7 @@ namespace Microsoft.AspNetCore.Rewrite /// /// Rewrites the path if the regex matches the HttpContext's PathString /// - /// The Rewrite options. + /// The . /// The regex string to compare with. /// If the regex matches, what to replace HttpContext with. /// The Rewrite options. @@ -50,7 +50,7 @@ namespace Microsoft.AspNetCore.Rewrite /// /// Rewrites the path if the regex matches the HttpContext's PathString /// - /// The Rewrite options. + /// The . /// The regex string to compare with. /// If the regex matches, what to replace the uri with. /// If the regex matches, conditionally stop processing other rules. @@ -64,7 +64,7 @@ namespace Microsoft.AspNetCore.Rewrite /// /// Redirect the request if the regex matches the HttpContext's PathString /// - /// The Rewrite options. + /// The . /// The regex string to compare with. /// If the regex matches, what to replace the uri with. /// The Rewrite options. @@ -76,7 +76,7 @@ namespace Microsoft.AspNetCore.Rewrite /// /// Redirect the request if the regex matches the HttpContext's PathString /// - /// The Rewrite options. + /// The . /// The regex string to compare with. /// If the regex matches, what to replace the uri with. /// The status code to add to the response. @@ -91,7 +91,7 @@ namespace Microsoft.AspNetCore.Rewrite /// Redirect a request to https if the incoming request is http, with returning a 301 /// status code for permanently redirected. /// - /// + /// The . /// public static RewriteOptions AddRedirectToHttpsPermanent(this RewriteOptions options) { @@ -101,7 +101,7 @@ namespace Microsoft.AspNetCore.Rewrite /// /// Redirect a request to https if the incoming request is http /// - /// The Rewrite options. + /// The . public static RewriteOptions AddRedirectToHttps(this RewriteOptions options) { return AddRedirectToHttps(options, statusCode: 302, sslPort: null); @@ -110,7 +110,7 @@ namespace Microsoft.AspNetCore.Rewrite /// /// Redirect a request to https if the incoming request is http /// - /// The Rewrite options. + /// The . /// The status code to add to the response. public static RewriteOptions AddRedirectToHttps(this RewriteOptions options, int statusCode) { @@ -120,7 +120,7 @@ namespace Microsoft.AspNetCore.Rewrite /// /// Redirect a request to https if the incoming request is http /// - /// The Rewrite options. + /// The . /// The status code to add to the response. /// The SSL port to add to the response. public static RewriteOptions AddRedirectToHttps(this RewriteOptions options, int statusCode, int? sslPort) diff --git a/src/Microsoft.AspNetCore.Rewrite/Rule.cs b/src/Microsoft.AspNetCore.Rewrite/Rule.cs index 22b5a253e0..b86d0e454d 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Rule.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Rule.cs @@ -10,8 +10,8 @@ namespace Microsoft.AspNetCore.Rewrite { /// /// Applies the rule. - /// Implementations of ApplyRule should set the value for RewriteContext.Results - /// (defaults to RuleTermination.Continue) + /// Implementations of ApplyRule should set the value for + /// (defaults to ) /// /// public abstract void ApplyRule(RewriteContext context); From ead052324c911604a18a64594672613cca211115 Mon Sep 17 00:00:00 2001 From: Mikael Mengistu Date: Wed, 21 Sep 2016 12:31:36 -0700 Subject: [PATCH 111/307] Changed the abstract class Rule to an interface IRule. Renamed the RuleTermination enum to RuleResult and renamed the values --- .../{Rule.cs => IRule.cs} | 10 +++++----- .../ApacheModRewrite/ApacheModRewriteRule.cs | 4 ++-- .../Internal/ApacheModRewrite/FileParser.cs | 4 ++-- .../Internal/ApacheModRewrite/RuleBuilder.cs | 2 +- .../Internal/DelegateRule.cs | 4 ++-- .../Internal/IISUrlRewrite/IISUrlRewriteRule.cs | 4 ++-- .../Internal/IISUrlRewrite/InputParser.cs | 4 ++-- .../Internal/IISUrlRewrite/UrlRewriteFileParser.cs | 2 +- .../Internal/IISUrlRewrite/UrlRewriteRuleBuilder.cs | 4 ++-- .../Internal/RedirectRule.cs | 6 +++--- .../Internal/RedirectToHttpsRule.cs | 6 +++--- .../Internal/RewriteRule.cs | 6 +++--- .../Internal/UrlActions/ForbiddenAction.cs | 2 +- .../Internal/UrlActions/GoneAction.cs | 2 +- .../Internal/UrlActions/RedirectAction.cs | 2 +- .../Internal/UrlActions/RewriteAction.cs | 6 +++--- .../Internal/UrlActions/VoidAction.cs | 4 ++-- .../RewriteBuilderExtensions.cs | 2 +- src/Microsoft.AspNetCore.Rewrite/RewriteContext.cs | 7 +++---- .../RewriteMiddleware.cs | 8 ++++---- src/Microsoft.AspNetCore.Rewrite/RewriteOptions.cs | 6 +++--- .../RewriteOptionsExtensions.cs | 10 +++++----- .../{RuleTermination.cs => RuleResult.cs} | 12 ++++++------ .../IISUrlRewrite/FileParserTests.cs | 2 +- .../IISUrlRewrite/UrlRewriteApplicationTests.cs | 12 ++++++------ .../UrlActions/ForbiddenActionTests.cs | 2 +- .../UrlActions/GoneActionTests.cs | 2 +- 27 files changed, 67 insertions(+), 68 deletions(-) rename src/Microsoft.AspNetCore.Rewrite/{Rule.cs => IRule.cs} (65%) rename src/Microsoft.AspNetCore.Rewrite/{RuleTermination.cs => RuleResult.cs} (74%) diff --git a/src/Microsoft.AspNetCore.Rewrite/Rule.cs b/src/Microsoft.AspNetCore.Rewrite/IRule.cs similarity index 65% rename from src/Microsoft.AspNetCore.Rewrite/Rule.cs rename to src/Microsoft.AspNetCore.Rewrite/IRule.cs index b86d0e454d..60fcdb037a 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Rule.cs +++ b/src/Microsoft.AspNetCore.Rewrite/IRule.cs @@ -4,17 +4,17 @@ namespace Microsoft.AspNetCore.Rewrite { /// - /// Represents an abstract rule. + /// Represents a rule. /// - public abstract class Rule + public interface IRule { /// /// Applies the rule. - /// Implementations of ApplyRule should set the value for - /// (defaults to ) + /// Implementations of ApplyRule should set the value for + /// (defaults to RuleResult.ContinueRules) /// /// - public abstract void ApplyRule(RewriteContext context); + void ApplyRule(RewriteContext context); } } diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/ApacheModRewrite/ApacheModRewriteRule.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/ApacheModRewrite/ApacheModRewriteRule.cs index 6fb201e12f..ffb907f304 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/ApacheModRewrite/ApacheModRewriteRule.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/ApacheModRewrite/ApacheModRewriteRule.cs @@ -6,7 +6,7 @@ using Microsoft.AspNetCore.Rewrite.Logging; namespace Microsoft.AspNetCore.Rewrite.Internal.ApacheModRewrite { - public class ApacheModRewriteRule : Rule + public class ApacheModRewriteRule : IRule { public UrlMatch InitialMatch { get; } public IList Conditions { get; } @@ -19,7 +19,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.ApacheModRewrite Actions = urlActions; } - public override void ApplyRule(RewriteContext context) + public virtual void ApplyRule(RewriteContext context) { // 1. Figure out which section of the string to match for the initial rule. var initMatchRes = InitialMatch.Evaluate(context.HttpContext.Request.Path, context); diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/ApacheModRewrite/FileParser.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/ApacheModRewrite/FileParser.cs index c2525f409f..d301a401a3 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/ApacheModRewrite/FileParser.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/ApacheModRewrite/FileParser.cs @@ -9,10 +9,10 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.ApacheModRewrite { public class FileParser { - public IList Parse(TextReader input) + public IList Parse(TextReader input) { string line; - var rules = new List(); + var rules = new List(); var builder = new RuleBuilder(); var lineNum = 0; diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/ApacheModRewrite/RuleBuilder.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/ApacheModRewrite/RuleBuilder.cs index bec58de1bc..e9bc6b36df 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/ApacheModRewrite/RuleBuilder.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/ApacheModRewrite/RuleBuilder.cs @@ -210,7 +210,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.ApacheModRewrite else { var last = flags.HasFlag(FlagType.End) || flags.HasFlag(FlagType.Last); - var termination = last ? RuleTermination.StopRules : RuleTermination.Continue; + var termination = last ? RuleResult.SkipRemainingRules : RuleResult.ContinueRules; _actions.Add(new RewriteAction(termination, pattern, queryStringAppend, queryStringDelete, escapeBackReference)); } } diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/DelegateRule.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/DelegateRule.cs index 60a670a7fc..ab8e75d1bf 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/DelegateRule.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/DelegateRule.cs @@ -5,7 +5,7 @@ using System; namespace Microsoft.AspNetCore.Rewrite.Internal { - public class DelegateRule : Rule + public class DelegateRule : IRule { private readonly Action _onApplyRule; @@ -13,6 +13,6 @@ namespace Microsoft.AspNetCore.Rewrite.Internal { _onApplyRule = onApplyRule; } - public override void ApplyRule(RewriteContext context) => _onApplyRule(context); + public void ApplyRule(RewriteContext context) => _onApplyRule(context); } } \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/IISUrlRewriteRule.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/IISUrlRewriteRule.cs index ba6b718cd3..3dc0bce3f4 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/IISUrlRewriteRule.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/IISUrlRewriteRule.cs @@ -7,7 +7,7 @@ using Microsoft.AspNetCore.Rewrite.Logging; namespace Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite { - public class IISUrlRewriteRule : Rule + public class IISUrlRewriteRule : IRule { public string Name { get; } public UrlMatch InitialMatch { get; } @@ -25,7 +25,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite Action = action; } - public override void ApplyRule(RewriteContext context) + public virtual void ApplyRule(RewriteContext context) { // Due to the path string always having a leading slash, // remove it from the path before regex comparison diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/InputParser.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/InputParser.cs index e471248868..392680376f 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/InputParser.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/InputParser.cs @@ -14,7 +14,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite private const char CloseBrace = '}'; /// - /// Creates a pattern, which is a template to create a new test string to + /// Creates a pattern, which is a template to create a new test string to /// compare to the condition. Can contain server variables, back references, etc. /// /// @@ -64,7 +64,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite context.Mark(); // Four main cases: // 1. {NAME} - Server Variable, create lambda to get the part of the context - // 2. {R:1} - Rule parameter + // 2. {R:1} - IRule parameter // 3. {C:1} - Condition Parameter // 4. {function:xxx} - String function // (unless we support Reload) diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/UrlRewriteFileParser.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/UrlRewriteFileParser.cs index 3a2f603c07..a7f624f82f 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/UrlRewriteFileParser.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/UrlRewriteFileParser.cs @@ -22,7 +22,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite if (xmlRoot != null) { var result = new List(); - // TODO Global rules are currently not treated differently than normal rules, fix. + // TODO Global rules are currently not treated differently than normal rules, fix. // See: https://github.com/aspnet/BasicMiddleware/issues/59 ParseRules(xmlRoot.Descendants(RewriteTags.GlobalRules).FirstOrDefault(), result); ParseRules(xmlRoot.Descendants(RewriteTags.Rules).FirstOrDefault(), result); diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/UrlRewriteRuleBuilder.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/UrlRewriteRuleBuilder.cs index b4bf4260c4..c4edf77cca 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/UrlRewriteRuleBuilder.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/UrlRewriteRuleBuilder.cs @@ -42,10 +42,10 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite switch (actionType) { case ActionType.None: - _action = new VoidAction(stopProcessing ? RuleTermination.StopRules : RuleTermination.Continue); + _action = new VoidAction(stopProcessing ? RuleResult.SkipRemainingRules : RuleResult.ContinueRules); break; case ActionType.Rewrite: - _action = new RewriteAction(stopProcessing ? RuleTermination.StopRules : RuleTermination.Continue, + _action = new RewriteAction(stopProcessing ? RuleResult.SkipRemainingRules : RuleResult.ContinueRules, url, appendQueryString); break; case ActionType.Redirect: diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/RedirectRule.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/RedirectRule.cs index 449ae293a4..2c9f471040 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/RedirectRule.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/RedirectRule.cs @@ -8,7 +8,7 @@ using Microsoft.Net.Http.Headers; namespace Microsoft.AspNetCore.Rewrite.Internal { - public class RedirectRule : Rule + public class RedirectRule : IRule { private readonly TimeSpan _regexTimeout = TimeSpan.FromSeconds(1); public Regex InitialMatch { get; } @@ -31,7 +31,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal StatusCode = statusCode; } - public override void ApplyRule(RewriteContext context) + public virtual void ApplyRule(RewriteContext context) { var path = context.HttpContext.Request.Path; var pathBase = context.HttpContext.Request.PathBase; @@ -52,7 +52,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal var response = context.HttpContext.Response; response.StatusCode = StatusCode; - context.Result = RuleTermination.ResponseComplete; + context.Result = RuleResult.EndResponse; if (string.IsNullOrEmpty(newPath)) { diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/RedirectToHttpsRule.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/RedirectToHttpsRule.cs index 139b70d3e4..6127785b06 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/RedirectToHttpsRule.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/RedirectToHttpsRule.cs @@ -6,12 +6,12 @@ using Microsoft.AspNetCore.Http; namespace Microsoft.AspNetCore.Rewrite.Internal { - public class RedirectToHttpsRule : Rule + public class RedirectToHttpsRule : IRule { public int? SSLPort { get; set; } public int StatusCode { get; set; } - public override void ApplyRule(RewriteContext context) + public virtual void ApplyRule(RewriteContext context) { if (!context.HttpContext.Request.IsHttps) { @@ -31,7 +31,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal var newUrl = new StringBuilder().Append("https://").Append(host).Append(req.PathBase).Append(req.Path).Append(req.QueryString); context.HttpContext.Response.Redirect(newUrl.ToString()); - context.Result = RuleTermination.ResponseComplete; + context.Result = RuleResult.EndResponse; } } } diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/RewriteRule.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/RewriteRule.cs index 9bacf4963d..336c2ba87d 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/RewriteRule.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/RewriteRule.cs @@ -8,7 +8,7 @@ using Microsoft.AspNetCore.Http.Extensions; namespace Microsoft.AspNetCore.Rewrite.Internal { - public class RewriteRule : Rule + public class RewriteRule : IRule { private readonly TimeSpan _regexTimeout = TimeSpan.FromSeconds(1); public Regex InitialMatch { get; } @@ -31,7 +31,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal StopProcessing = stopProcessing; } - public override void ApplyRule(RewriteContext context) + public virtual void ApplyRule(RewriteContext context) { var path = context.HttpContext.Request.Path; Match initMatchResults; @@ -51,7 +51,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal if (StopProcessing) { - context.Result = RuleTermination.StopRules; + context.Result = RuleResult.SkipRemainingRules; } if (string.IsNullOrEmpty(result)) diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/ForbiddenAction.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/ForbiddenAction.cs index 08ad531d08..8e4058cc97 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/ForbiddenAction.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/ForbiddenAction.cs @@ -10,7 +10,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlActions public override void ApplyAction(RewriteContext context, MatchResults ruleMatch, MatchResults condMatch) { context.HttpContext.Response.StatusCode = StatusCodes.Status403Forbidden; - context.Result = RuleTermination.ResponseComplete; + context.Result = RuleResult.EndResponse; } } } diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/GoneAction.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/GoneAction.cs index 4a753c61da..a1e7b964e6 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/GoneAction.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/GoneAction.cs @@ -10,7 +10,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlActions public override void ApplyAction(RewriteContext context, MatchResults ruleMatch, MatchResults condMatch) { context.HttpContext.Response.StatusCode = StatusCodes.Status410Gone; - context.Result = RuleTermination.ResponseComplete; + context.Result = RuleResult.EndResponse; } } } diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/RedirectAction.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/RedirectAction.cs index 4d85531c87..9c917ed9a7 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/RedirectAction.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/RedirectAction.cs @@ -91,7 +91,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlActions response.Headers[HeaderNames.Location] = pathBase + pattern + context.HttpContext.Request.QueryString; } } - context.Result = RuleTermination.ResponseComplete; + context.Result = RuleResult.EndResponse; } } } diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/RewriteAction.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/RewriteAction.cs index 74264a9079..f6637747d5 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/RewriteAction.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/RewriteAction.cs @@ -9,13 +9,13 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlActions { public class RewriteAction : UrlAction { - public RuleTermination Result { get; } + public RuleResult Result { get; } public bool QueryStringAppend { get; } public bool QueryStringDelete { get; } public bool EscapeBackReferences { get; } public RewriteAction( - RuleTermination result, + RuleResult result, Pattern pattern, bool queryStringAppend, bool queryStringDelete, @@ -31,7 +31,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlActions } public RewriteAction( - RuleTermination result, + RuleResult result, Pattern pattern, bool queryStringAppend) : this(result, diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/VoidAction.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/VoidAction.cs index 4ac2a08144..6023b23a7a 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/VoidAction.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/VoidAction.cs @@ -5,9 +5,9 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlActions { public class VoidAction : UrlAction { - public RuleTermination Result { get; } + public RuleResult Result { get; } - public VoidAction(RuleTermination result) + public VoidAction(RuleResult result) { Result = result; } diff --git a/src/Microsoft.AspNetCore.Rewrite/RewriteBuilderExtensions.cs b/src/Microsoft.AspNetCore.Rewrite/RewriteBuilderExtensions.cs index 724dccf3d1..0d577c3fd0 100644 --- a/src/Microsoft.AspNetCore.Rewrite/RewriteBuilderExtensions.cs +++ b/src/Microsoft.AspNetCore.Rewrite/RewriteBuilderExtensions.cs @@ -7,7 +7,7 @@ using Microsoft.AspNetCore.Rewrite; namespace Microsoft.AspNetCore.Builder { /// - /// Extension methods for the + /// Extension methods for the /// public static class RewriteBuilderExtensions { diff --git a/src/Microsoft.AspNetCore.Rewrite/RewriteContext.cs b/src/Microsoft.AspNetCore.Rewrite/RewriteContext.cs index d7dec645f7..061c45a18f 100644 --- a/src/Microsoft.AspNetCore.Rewrite/RewriteContext.cs +++ b/src/Microsoft.AspNetCore.Rewrite/RewriteContext.cs @@ -24,17 +24,16 @@ namespace Microsoft.AspNetCore.Rewrite public IFileProvider StaticFileProvider { get; set; } /// - /// Gets and sets the logger + /// Gets and sets the logger /// public ILogger Logger { get; set; } /// /// A shared result that is set appropriately by each rule for the next action that - /// should be take. See + /// should be taken. See /// - public RuleTermination Result { get; set; } + public RuleResult Result { get; set; } - // PERF: share the same string builder per request internal StringBuilder Builder { get; set; } = new StringBuilder(64); } } diff --git a/src/Microsoft.AspNetCore.Rewrite/RewriteMiddleware.cs b/src/Microsoft.AspNetCore.Rewrite/RewriteMiddleware.cs index 9f3802d395..58cd935690 100644 --- a/src/Microsoft.AspNetCore.Rewrite/RewriteMiddleware.cs +++ b/src/Microsoft.AspNetCore.Rewrite/RewriteMiddleware.cs @@ -69,7 +69,7 @@ namespace Microsoft.AspNetCore.Rewrite HttpContext = context, StaticFileProvider = _fileProvider, Logger = _logger, - Result = RuleTermination.Continue + Result = RuleResult.ContinueRules }; foreach (var rule in _options.Rules) @@ -77,15 +77,15 @@ namespace Microsoft.AspNetCore.Rewrite rule.ApplyRule(rewriteContext); switch (rewriteContext.Result) { - case RuleTermination.Continue: + case RuleResult.ContinueRules: _logger.RewriteMiddlewareRequestContinueResults(); break; - case RuleTermination.ResponseComplete: + case RuleResult.EndResponse: _logger.RewriteMiddlewareRequestResponseComplete( context.Response.Headers[HeaderNames.Location], context.Response.StatusCode); return TaskCache.CompletedTask; - case RuleTermination.StopRules: + case RuleResult.SkipRemainingRules: _logger.RewriteMiddlewareRequestStopRules(); return _next(context); default: diff --git a/src/Microsoft.AspNetCore.Rewrite/RewriteOptions.cs b/src/Microsoft.AspNetCore.Rewrite/RewriteOptions.cs index 8e51c78071..cbff5975fd 100644 --- a/src/Microsoft.AspNetCore.Rewrite/RewriteOptions.cs +++ b/src/Microsoft.AspNetCore.Rewrite/RewriteOptions.cs @@ -8,14 +8,14 @@ using Microsoft.AspNetCore.Hosting; namespace Microsoft.AspNetCore.Rewrite { /// - /// Options for the + /// Options for the /// public class RewriteOptions { /// - /// A list of that will be applied in order upon a request. + /// A list of that will be applied in order upon a request. /// - public IList Rules { get; } = new List(); + public IList Rules { get; } = new List(); /// /// Gets and sets the File Provider for file and directory checks. Defaults to diff --git a/src/Microsoft.AspNetCore.Rewrite/RewriteOptionsExtensions.cs b/src/Microsoft.AspNetCore.Rewrite/RewriteOptionsExtensions.cs index 5b9eec9e88..b1b4057cd4 100644 --- a/src/Microsoft.AspNetCore.Rewrite/RewriteOptionsExtensions.cs +++ b/src/Microsoft.AspNetCore.Rewrite/RewriteOptionsExtensions.cs @@ -17,7 +17,7 @@ namespace Microsoft.AspNetCore.Rewrite /// The . /// A rule to be added to the current rules. /// The Rewrite options. - public static RewriteOptions Add(this RewriteOptions options, Rule rule) + public static RewriteOptions Add(this RewriteOptions options, IRule rule) { options.Rules.Add(rule); return options; @@ -44,7 +44,7 @@ namespace Microsoft.AspNetCore.Rewrite /// The Rewrite options. public static RewriteOptions AddRewrite(this RewriteOptions options, string regex, string replacement) { - return AddRewrite(options, regex, replacement, stopProcessing: false); + return AddRewrite(options, regex, replacement, skipRemainingRules: false); } /// @@ -53,11 +53,11 @@ namespace Microsoft.AspNetCore.Rewrite /// The . /// The regex string to compare with. /// If the regex matches, what to replace the uri with. - /// If the regex matches, conditionally stop processing other rules. + /// If the regex matches, conditionally stop processing other rules. /// The Rewrite options. - public static RewriteOptions AddRewrite(this RewriteOptions options, string regex, string replacement, bool stopProcessing) + public static RewriteOptions AddRewrite(this RewriteOptions options, string regex, string replacement, bool skipRemainingRules) { - options.Rules.Add(new RewriteRule(regex, replacement, stopProcessing)); + options.Rules.Add(new RewriteRule(regex, replacement, skipRemainingRules)); return options; } diff --git a/src/Microsoft.AspNetCore.Rewrite/RuleTermination.cs b/src/Microsoft.AspNetCore.Rewrite/RuleResult.cs similarity index 74% rename from src/Microsoft.AspNetCore.Rewrite/RuleTermination.cs rename to src/Microsoft.AspNetCore.Rewrite/RuleResult.cs index 70f5c9f39f..9e62b0511b 100644 --- a/src/Microsoft.AspNetCore.Rewrite/RuleTermination.cs +++ b/src/Microsoft.AspNetCore.Rewrite/RuleResult.cs @@ -6,19 +6,19 @@ namespace Microsoft.AspNetCore.Rewrite /// /// An enum representing the result of a rule. /// - public enum RuleTermination + public enum RuleResult { /// /// Default value, continue applying rules. /// - Continue, + ContinueRules, /// - /// Redirect occured, should send back new rewritten url. - /// - ResponseComplete, + /// The rule ended the request by providing a response. + /// + EndResponse, /// /// Stop applying rules and send context to the next middleware /// - StopRules + SkipRemainingRules } } diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/FileParserTests.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/FileParserTests.cs index afa76bb395..b891b3a2c5 100644 --- a/test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/FileParserTests.cs +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/FileParserTests.cs @@ -147,7 +147,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite ) { return new IISUrlRewriteRule(name, new RegexMatch(new Regex("^OFF$"), false), conditions, - new RewriteAction(RuleTermination.Continue, new InputParser().ParseInputString(url), queryStringAppend: false)); + new RewriteAction(RuleResult.ContinueRules, new InputParser().ParseInputString(url), queryStringAppend: false)); } // TODO make rules comparable? diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/UrlRewriteApplicationTests.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/UrlRewriteApplicationTests.cs index bbb04f1f7e..83958e6c99 100644 --- a/test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/UrlRewriteApplicationTests.cs +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/UrlRewriteApplicationTests.cs @@ -9,7 +9,7 @@ using Xunit; namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite { - // TODO add more of these + // TODO add more of these public class UrlRewriteApplicationTests { [Fact] @@ -17,10 +17,10 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite { var xml = new StringReader(@" - + - + "); var rules = new UrlRewriteFileParser().Parse(xml); @@ -28,7 +28,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite Assert.Equal(rules.Count, 1); var context = new RewriteContext { HttpContext = new DefaultHttpContext() }; rules.FirstOrDefault().ApplyRule(context); - Assert.Equal(context.Result, RuleTermination.StopRules); + Assert.Equal(context.Result, RuleResult.SkipRemainingRules); } [Fact] @@ -39,7 +39,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite - + "); var rules = new UrlRewriteFileParser().Parse(xml); @@ -47,7 +47,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite Assert.Equal(rules.Count, 1); var context = new RewriteContext { HttpContext = new DefaultHttpContext() }; rules.FirstOrDefault().ApplyRule(context); - Assert.Equal(context.Result, RuleTermination.Continue); + Assert.Equal(context.Result, RuleResult.ContinueRules); } } } diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/UrlActions/ForbiddenActionTests.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/UrlActions/ForbiddenActionTests.cs index fa668e29d6..fa141844cc 100644 --- a/test/Microsoft.AspNetCore.Rewrite.Tests/UrlActions/ForbiddenActionTests.cs +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/UrlActions/ForbiddenActionTests.cs @@ -20,7 +20,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlActions action.ApplyAction(context, null, null); // Assert - Assert.Equal(context.Result, RuleTermination.ResponseComplete); + Assert.Equal(context.Result, RuleResult.EndResponse); Assert.Equal(context.HttpContext.Response.StatusCode, StatusCodes.Status403Forbidden); } } diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/UrlActions/GoneActionTests.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/UrlActions/GoneActionTests.cs index ed061dd929..e72c6c67ce 100644 --- a/test/Microsoft.AspNetCore.Rewrite.Tests/UrlActions/GoneActionTests.cs +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/UrlActions/GoneActionTests.cs @@ -20,7 +20,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlActions action.ApplyAction(context, null, null); // Assert - Assert.Equal(context.Result, RuleTermination.ResponseComplete); + Assert.Equal(context.Result, RuleResult.EndResponse); Assert.Equal(context.HttpContext.Response.StatusCode, StatusCodes.Status410Gone); } } From 58ef98b184df83efb69ce7177dafc60171afd655 Mon Sep 17 00:00:00 2001 From: Mikael Mengistu Date: Wed, 21 Sep 2016 22:02:45 -0700 Subject: [PATCH 112/307] Sample project can now redirect to HTTPS (#106) Sample project can now redirect to HTTPS --- samples/RewriteSample/Startup.cs | 8 ++++++-- samples/RewriteSample/project.json | 3 ++- samples/RewriteSample/testCert.pfx | Bin 0 -> 2483 bytes .../UrlActions/ForbiddenActionTests.cs | 6 ++---- .../UrlActions/GoneActionTests.cs | 3 --- 5 files changed, 10 insertions(+), 10 deletions(-) create mode 100644 samples/RewriteSample/testCert.pfx diff --git a/samples/RewriteSample/Startup.cs b/samples/RewriteSample/Startup.cs index b4bfa3c977..e1285d0666 100644 --- a/samples/RewriteSample/Startup.cs +++ b/samples/RewriteSample/Startup.cs @@ -16,7 +16,7 @@ namespace RewriteSample var options = new RewriteOptions() .AddRedirect("(.*)/$", "$1") .AddRewrite(@"app/(\d+)", "app?id=$1") - .AddRedirectToHttps(302) + .AddRedirectToHttps(302, 5001) .AddIISUrlRewrite(env.ContentRootFileProvider, "UrlRewrite.xml") .AddApacheModRewrite(env.ContentRootFileProvider, "Rewrite.txt"); @@ -28,7 +28,11 @@ namespace RewriteSample public static void Main(string[] args) { var host = new WebHostBuilder() - .UseKestrel() + .UseKestrel(options => + { + options.UseHttps("testCert.pfx", "testPassword"); + }) + .UseUrls("http://localhost:5000", "https://localhost:5001") .UseStartup() .UseContentRoot(Directory.GetCurrentDirectory()) .Build(); diff --git a/samples/RewriteSample/project.json b/samples/RewriteSample/project.json index 8522010e25..c34d3bd910 100644 --- a/samples/RewriteSample/project.json +++ b/samples/RewriteSample/project.json @@ -2,7 +2,8 @@ "version": "1.1.0-*", "dependencies": { "Microsoft.AspNetCore.Rewrite": "1.1.0-*", - "Microsoft.AspNetCore.Server.Kestrel": "1.1.0-*" + "Microsoft.AspNetCore.Server.Kestrel": "1.1.0-*", + "Microsoft.AspNetCore.Server.Kestrel.Https": "1.1.0-*" }, "buildOptions": { "emitEntryPoint": true, diff --git a/samples/RewriteSample/testCert.pfx b/samples/RewriteSample/testCert.pfx new file mode 100644 index 0000000000000000000000000000000000000000..7118908c2d730670c16e9f8b2c532a262c951989 GIT binary patch literal 2483 zcmaKuc|27A8pqF>IWr86E&Q@(n=B)p$ug!;QVB6xij*z;uPLG!yCz#DQB)+9G$9m9 zQU)=DWXU?*EZIwG!+0d++P@yZ4Xhoagg?p6B~|Ue7tN=Ny=UD?x#1n1MTq z#c9MHh+D#gd|(a(cN}8i91v^=GcdgW3SmA$49p~gM-dys3jVWdg8+!iVL)pz1LDE5 zSb=|GAn(@R=(Ux!MfS9@}sFu-xDd zIt2+mqSq$glwy_6UNs<2?(qERU!gJ;5j}Pp&6trxG=wi)=@k(w2+fJVnc+qvXVzy(>Om4;L|^)R`t*3nTpAmEmTl(#i!RV#a0t#u6>Q9mY`-Nmcs7$XjXT7 zUmCD`O~_j7!%R#I?cG-7C^hcH)@l?WC1vyw$FFu_(r)jhOq6p}W8sG7NO{YTy8tG4 zrb$tTkag*G?(7lfoGx$4YWui>{{@}-FB2ub=}RX{1zx?j)s-##J9|G7E1@-;7Nuln z9MQoX7FJ76+D#XXT@ZZmLZCufIdf3@OigG6m8I7!GT=7VD|>?6e!z9=eT}*E_tSn6 zl+clHCZ-kcIR#gen#LjMJW8>0QtViaQB#FhqsCb0YPYr3;jRITl@V9Aph24D?r2d` zetCyyCg<*O-u+M& zW^ptmT|}p$VAOZpmbQ1{5fK-6ytEvre#Po}6c2URn`viQAF2+e?Z~PK2&pd>7=7)I zTCYm)@3PFRu_6a6Kb)IpCzQ%e3l%O#SDA+$Pq{Dk{HCqi7z>qd{nVpebffL7h{c4( zmhXn~G+C27S3(IfC)q2KON=YwqHXEo%zc40DgWLzF{%RIdr@RcLu90qMSHf!Y}JaqP<={8_Rfe;ddR5= zKEo;^Yip&^m((#{czE{kUga3-@`*;&EwO}Jt>QdURP2P>ob^j-A!qld-0S_pm)kjs zkNo48oZnMt){W~o8g^f;4#?lRLr-T@f}wH1o~-Iq=NEVtTVEZ`vrW~!>2yh%;Bc~H zHl&OK>n@d`*e19*9#v>zZpU?I);f7}IPIfSSk#N|ujE492Itg)l!)TJ19@FE^x|p= zH16NC7OfK&|6_!AnWfTIf^YPOa&`|nbk3VR0vql6&s@y1V3QOU%(`Re+kJgrz?r9!{^wOQ4W-eng23gc}f(LxIs zH_Ls~5izbjcRQH#WH6s6hR;zn>j_R8aJ$A)6xNneu8UI-vWV8Z@HZu&WwvG5q{1ZS zdZeVf{Pv5-u281~y;aJe*x%Uv0@biMZ$vPbKj}O`(SOWQc~kJX` zXR&d4DtAe@2RH$^ z0os5*;0eIUeJi3Uh`A%44x(XzjClG8BO~-r_A}odiRuHo2-86#`mhrgN5p~<$RLY? zq(kynfFA5{v#p+EA1 z5aoe1763EQHorRm`C&ktKn(OQ1n)$Q{GZz&jRb`eDEMpl<0O#+)DMV(T7nsIzCG{QuM->B9g7Lrl2SE&gW`M!~(un|y0fIn=b^6_$ z9{zEzgYI~39xn0ZP*9qBL%fg7rg$ttt&TOmvfNNO<6FT0ZavM$Y4CYLQGIcIYv9Y& zBGPUh&QTfW;V2!)oIra@s&d968y-y}Y|ww(R$GzWS*V&)k@W0>Slem{|HdTCjm;_5 zwY*A8W3nUbemE^_f0ng$tbd<`sr?TO-_&VCw+F#7P@LkIl$1PzTBoPY1b88EIO>UO zP-NK7+g2yD3U6g3i|iA6+su>54sf_Sk0F=)1|9odnCM4u2Rs z=&Y?-V&VquSN%3FJ2~ZGweP~iLs|w=l@9yu$tj@}Dp?e-2JUsqOoswdXb=E%&0te_ zA2M+{5Hf-dqD7=yw*r@A*xkn(1IS~nfP}k}e?4Bt|9g(eph4hFX_|S6nj1&Sz9z^= zRw~<&-9d@FzTn6S*RVE{Wj5lgLJr9HLB8S9CgOm*>XA8*y4`JE;^s$=bqD#U4;e5C&x&ggKIAVL zrQ)Yd8|{>7Z(6*B&7&4&9(*vDOfHMuR-Dk1IZia*XM^EZUD^{?cWG>J>KrtElc*{K zaVl(7SN2cH4I6Q$bZOpJ8e5LKaG7p;?tJ~#+9QrTYU@f#5`Vo7cEX!szCT}iX-K^2 w#3o+=C+lQz2J+SOEzVX(eJ)e7=eicC{rr9U2VGDcdH?_b literal 0 HcmV?d00001 diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/UrlActions/ForbiddenActionTests.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/UrlActions/ForbiddenActionTests.cs index fa141844cc..0ab9a6f439 100644 --- a/test/Microsoft.AspNetCore.Rewrite.Tests/UrlActions/ForbiddenActionTests.cs +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/UrlActions/ForbiddenActionTests.cs @@ -12,14 +12,12 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlActions [Fact] public void Forbidden_Verify403IsInStatusCode() { - // Arrange + var context = new RewriteContext {HttpContext = new DefaultHttpContext()}; var action = new ForbiddenAction(); - // Act action.ApplyAction(context, null, null); - - // Assert + Assert.Equal(context.Result, RuleResult.EndResponse); Assert.Equal(context.HttpContext.Response.StatusCode, StatusCodes.Status403Forbidden); } diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/UrlActions/GoneActionTests.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/UrlActions/GoneActionTests.cs index e72c6c67ce..1a18fe7d19 100644 --- a/test/Microsoft.AspNetCore.Rewrite.Tests/UrlActions/GoneActionTests.cs +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/UrlActions/GoneActionTests.cs @@ -12,14 +12,11 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlActions [Fact] public void Gone_Verify410IsInStatusCode() { - // Arrange var context = new RewriteContext { HttpContext = new DefaultHttpContext() }; var action = new GoneAction(); - // Act action.ApplyAction(context, null, null); - // Assert Assert.Equal(context.Result, RuleResult.EndResponse); Assert.Equal(context.HttpContext.Response.StatusCode, StatusCodes.Status410Gone); } From e003594fd89790ed652fb8daeec507bbf8c957e3 Mon Sep 17 00:00:00 2001 From: Nate McMaster Date: Fri, 23 Sep 2016 16:05:46 -0700 Subject: [PATCH 113/307] Remove ChangeEnvironmentAction class and throw when env flag is set in mod_rewrite rule --- .gitignore | 3 +- .../Internal/ApacheModRewrite/RuleBuilder.cs | 3 +- .../UrlActions/ChangeEnvironmentAction.cs | 22 ------- .../Properties/Resources.Designer.cs | 16 ++++++ .../Resources.resx | 57 ++++++++++--------- .../ApacheModRewrite/RuleBuilderTest.cs | 24 ++++++++ 6 files changed, 73 insertions(+), 52 deletions(-) delete mode 100644 src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/ChangeEnvironmentAction.cs create mode 100644 test/Microsoft.AspNetCore.Rewrite.Tests/ApacheModRewrite/RuleBuilderTest.cs diff --git a/.gitignore b/.gitignore index abc642dc8d..4b5208332f 100644 --- a/.gitignore +++ b/.gitignore @@ -30,4 +30,5 @@ project.lock.json .testPublish/ .idea/ .vscode/ - +*.nuget.props +*.nuget.targets diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/ApacheModRewrite/RuleBuilder.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/ApacheModRewrite/RuleBuilder.cs index e9bc6b36df..8e93d1db16 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/ApacheModRewrite/RuleBuilder.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/ApacheModRewrite/RuleBuilder.cs @@ -178,8 +178,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.ApacheModRewrite if (flags.GetValue(FlagType.Env, out flag)) { - // parse env - _actions.Add(new ChangeEnvironmentAction(flag)); + throw new NotSupportedException(Resources.Error_ChangeEnvironmentNotSupported); } if (flags.HasFlag(FlagType.Forbidden)) diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/ChangeEnvironmentAction.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/ChangeEnvironmentAction.cs deleted file mode 100644 index c0b314a643..0000000000 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/ChangeEnvironmentAction.cs +++ /dev/null @@ -1,22 +0,0 @@ -// 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; - -namespace Microsoft.AspNetCore.Rewrite.Internal.UrlActions -{ - public class ChangeEnvironmentAction : UrlAction - { - public ChangeEnvironmentAction(string env) - { - // TODO - throw new NotImplementedException("Changing the environment is not implemented"); - } - - public override void ApplyAction(RewriteContext context, MatchResults ruleMatch, MatchResults condMatch) - { - // Do stuff to modify the env - throw new NotImplementedException("Changing the environment is not implemented"); - } - } -} diff --git a/src/Microsoft.AspNetCore.Rewrite/Properties/Resources.Designer.cs b/src/Microsoft.AspNetCore.Rewrite/Properties/Resources.Designer.cs index 25261d8664..3c2e0d6b64 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Properties/Resources.Designer.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Properties/Resources.Designer.cs @@ -154,6 +154,22 @@ namespace Microsoft.AspNetCore.Rewrite return GetString("Error_IntegerMatch_FormatExceptionMessage"); } + /// + /// Error adding a mod_rewrite rule. The change environment flag is not supported. + /// + internal static string Error_ChangeEnvironmentNotSupported + { + get { return GetString("Error_ChangeEnvironmentNotSupported"); } + } + + /// + /// Error adding a mod_rewrite rule. The change environment flag is not supported. + /// + internal static string FormatError_ChangeEnvironmentNotSupported() + { + return GetString("Error_ChangeEnvironmentNotSupported"); + } + private static string GetString(string name, params string[] formatterNames) { var value = _resourceManager.GetString(name); diff --git a/src/Microsoft.AspNetCore.Rewrite/Resources.resx b/src/Microsoft.AspNetCore.Rewrite/Resources.resx index 70a314f06b..7b477cc447 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Resources.resx +++ b/src/Microsoft.AspNetCore.Rewrite/Resources.resx @@ -1,17 +1,17 @@  - @@ -144,4 +144,7 @@ Syntax error for integers in comparison. + + Error adding a mod_rewrite rule. The change environment flag is not supported. + \ No newline at end of file diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/ApacheModRewrite/RuleBuilderTest.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/ApacheModRewrite/RuleBuilderTest.cs new file mode 100644 index 0000000000..df1a16adf1 --- /dev/null +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/ApacheModRewrite/RuleBuilderTest.cs @@ -0,0 +1,24 @@ +// 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; +using Microsoft.AspNetCore.Rewrite.Internal.ApacheModRewrite; +using Xunit; + +namespace Microsoft.AspNetCore.Rewrite.Tests +{ + public class RuleBuilderTest + { + [Fact] + // see https://httpd.apache.org/docs/2.4/rewrite/advanced.html#setenvvars + public void AddAction_Throws_ChangeEnvNotSupported() + { + var builder = new RuleBuilder(); + var flags = new Flags(); + flags.SetFlag(FlagType.Env, "rewritten:1"); + + var ex = Assert.Throws(() => builder.AddAction(null, flags)); + Assert.Equal(Resources.Error_ChangeEnvironmentNotSupported, ex.Message); + } + } +} \ No newline at end of file From 2a402abefe44e9565deac41a4f0cf51f738c835b Mon Sep 17 00:00:00 2001 From: Yves57 Date: Thu, 4 Aug 2016 02:20:42 +0200 Subject: [PATCH 114/307] Response Compression middleware --- BasicMiddleware.sln | 21 ++ .../ResponseCompressionSample/LoremIpsum.cs | 12 + .../Properties/launchSettings.json | 25 ++ .../ResponseCompressionSample.xproj | 18 ++ samples/ResponseCompressionSample/Startup.cs | 37 +++ .../ResponseCompressionSample/project.json | 31 +++ .../BodyWrapperStream.cs | 192 ++++++++++++++ .../GzipResponseCompressionProvider.cs | 34 +++ .../IResponseCompressionProvider.cs | 25 ++ ...osoft.AspNetCore.ResponseCompression.xproj | 17 ++ .../Properties/AssemblyInfo.cs | 11 + .../ResponseCompressionExtensions.cs | 34 +++ .../ResponseCompressionMiddleware.cs | 125 +++++++++ .../ResponseCompressionOptions.cs | 32 +++ .../ResponseCompressionUtils.cs | 49 ++++ .../project.json | 31 +++ ...AspNetCore.ResponseCompression.Tests.xproj | 20 ++ .../ResponseCompressionMiddlewareTest.cs | 242 ++++++++++++++++++ .../ResponseCompressionUtilsTest.cs | 69 +++++ .../project.json | 26 ++ 20 files changed, 1051 insertions(+) create mode 100644 samples/ResponseCompressionSample/LoremIpsum.cs create mode 100644 samples/ResponseCompressionSample/Properties/launchSettings.json create mode 100644 samples/ResponseCompressionSample/ResponseCompressionSample.xproj create mode 100644 samples/ResponseCompressionSample/Startup.cs create mode 100644 samples/ResponseCompressionSample/project.json create mode 100644 src/Microsoft.AspNetCore.ResponseCompression/BodyWrapperStream.cs create mode 100644 src/Microsoft.AspNetCore.ResponseCompression/GzipResponseCompressionProvider.cs create mode 100644 src/Microsoft.AspNetCore.ResponseCompression/IResponseCompressionProvider.cs create mode 100644 src/Microsoft.AspNetCore.ResponseCompression/Microsoft.AspNetCore.ResponseCompression.xproj create mode 100644 src/Microsoft.AspNetCore.ResponseCompression/Properties/AssemblyInfo.cs create mode 100644 src/Microsoft.AspNetCore.ResponseCompression/ResponseCompressionExtensions.cs create mode 100644 src/Microsoft.AspNetCore.ResponseCompression/ResponseCompressionMiddleware.cs create mode 100644 src/Microsoft.AspNetCore.ResponseCompression/ResponseCompressionOptions.cs create mode 100644 src/Microsoft.AspNetCore.ResponseCompression/ResponseCompressionUtils.cs create mode 100644 src/Microsoft.AspNetCore.ResponseCompression/project.json create mode 100644 test/Microsoft.AspNetCore.ResponseCompression.Tests/Microsoft.AspNetCore.ResponseCompression.Tests.xproj create mode 100644 test/Microsoft.AspNetCore.ResponseCompression.Tests/ResponseCompressionMiddlewareTest.cs create mode 100644 test/Microsoft.AspNetCore.ResponseCompression.Tests/ResponseCompressionUtilsTest.cs create mode 100644 test/Microsoft.AspNetCore.ResponseCompression.Tests/project.json diff --git a/BasicMiddleware.sln b/BasicMiddleware.sln index dd15eee89b..7ef684b555 100644 --- a/BasicMiddleware.sln +++ b/BasicMiddleware.sln @@ -35,6 +35,12 @@ Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "RewriteSample", "samples\Re EndProject Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNetCore.Rewrite.Tests", "test\Microsoft.AspNetCore.Rewrite.Tests\Microsoft.AspNetCore.Rewrite.Tests.xproj", "{31794F9E-A1AA-4535-B03C-A3233737CD1A}" EndProject +Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNetCore.ResponseCompression", "src\Microsoft.AspNetCore.ResponseCompression\Microsoft.AspNetCore.ResponseCompression.xproj", "{45308A9D-F4C6-46A8-A24F-E73D995CC223}" +EndProject +Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNetCore.ResponseCompression.Tests", "test\Microsoft.AspNetCore.ResponseCompression.Tests\Microsoft.AspNetCore.ResponseCompression.Tests.xproj", "{3360A5D1-70C0-49EE-9051-04A6A6B836DC}" +EndProject +Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "ResponseCompressionSample", "samples\ResponseCompressionSample\ResponseCompressionSample.xproj", "{B2A3CE38-51B2-4486-982C-98C380AF140E}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -77,6 +83,18 @@ Global {31794F9E-A1AA-4535-B03C-A3233737CD1A}.Debug|Any CPU.Build.0 = Debug|Any CPU {31794F9E-A1AA-4535-B03C-A3233737CD1A}.Release|Any CPU.ActiveCfg = Release|Any CPU {31794F9E-A1AA-4535-B03C-A3233737CD1A}.Release|Any CPU.Build.0 = Release|Any CPU + {45308A9D-F4C6-46A8-A24F-E73D995CC223}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {45308A9D-F4C6-46A8-A24F-E73D995CC223}.Debug|Any CPU.Build.0 = Debug|Any CPU + {45308A9D-F4C6-46A8-A24F-E73D995CC223}.Release|Any CPU.ActiveCfg = Release|Any CPU + {45308A9D-F4C6-46A8-A24F-E73D995CC223}.Release|Any CPU.Build.0 = Release|Any CPU + {3360A5D1-70C0-49EE-9051-04A6A6B836DC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {3360A5D1-70C0-49EE-9051-04A6A6B836DC}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3360A5D1-70C0-49EE-9051-04A6A6B836DC}.Release|Any CPU.ActiveCfg = Release|Any CPU + {3360A5D1-70C0-49EE-9051-04A6A6B836DC}.Release|Any CPU.Build.0 = Release|Any CPU + {B2A3CE38-51B2-4486-982C-98C380AF140E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B2A3CE38-51B2-4486-982C-98C380AF140E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B2A3CE38-51B2-4486-982C-98C380AF140E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B2A3CE38-51B2-4486-982C-98C380AF140E}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -91,5 +109,8 @@ Global {0E7CA1A7-1DC3-4CE6-B9C7-1688FE1410F1} = {A5076D28-FA7E-4606-9410-FEDD0D603527} {9E049645-13BC-4598-89E1-5B43D36E5D14} = {9587FE9F-5A17-42C4-8021-E87F59CECB98} {31794F9E-A1AA-4535-B03C-A3233737CD1A} = {8437B0F3-3894-4828-A945-A9187F37631D} + {45308A9D-F4C6-46A8-A24F-E73D995CC223} = {A5076D28-FA7E-4606-9410-FEDD0D603527} + {3360A5D1-70C0-49EE-9051-04A6A6B836DC} = {8437B0F3-3894-4828-A945-A9187F37631D} + {B2A3CE38-51B2-4486-982C-98C380AF140E} = {9587FE9F-5A17-42C4-8021-E87F59CECB98} EndGlobalSection EndGlobal diff --git a/samples/ResponseCompressionSample/LoremIpsum.cs b/samples/ResponseCompressionSample/LoremIpsum.cs new file mode 100644 index 0000000000..34eaab215a --- /dev/null +++ b/samples/ResponseCompressionSample/LoremIpsum.cs @@ -0,0 +1,12 @@ +// 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. + +namespace ResponseCompressionSample +{ + internal static class LoremIpsum + { + internal const string Text = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed non risus. Suspendisse lectus tortor, dignissim sit amet, adipiscing nec, ultricies sed, dolor. Cras elementum ultrices diam. Maecenas ligula massa, varius a, semper congue, euismod non, mi. Proin porttitor, orci nec nonummy molestie, enim est eleifend mi, non fermentum diam nisl sit amet erat. Duis semper. Duis arcu massa, scelerisque vitae, consequat in, pretium a, enim. Pellentesque congue. Ut in risus volutpat libero pharetra tempor. Cras vestibulum bibendum augue. Praesent egestas leo in pede. Praesent blandit odio eu enim. Pellentesque sed dui ut augue blandit sodales. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Aliquam nibh. Mauris ac mauris sed pede pellentesque fermentum. Maecenas adipiscing ante non diam sodales hendrerit." + + "Ut velit mauris, egestas sed, gravida nec, ornare ut, mi. Aenean ut orci vel massa suscipit pulvinar.Nulla sollicitudin.Fusce varius, ligula non tempus aliquam, nunc turpis ullamcorper nibh, in tempus sapien eros vitae ligula.Pellentesque rhoncus nunc et augue.Integer id felis.Curabitur aliquet pellentesque diam. Integer quis metus vitae elit lobortis egestas.Lorem ipsum dolor sit amet, consectetuer adipiscing elit.Morbi vel erat non mauris convallis vehicula.Nulla et sapien.Integer tortor tellus, aliquam faucibus, convallis id, congue eu, quam.Mauris ullamcorper felis vitae erat.Proin feugiat, augue non elementum posuere, metus purus iaculis lectus, et tristique ligula justo vitae magna." + + "Aliquam convallis sollicitudin purus. Praesent aliquam, enim at fermentum mollis, ligula massa adipiscing nisl, ac euismod nibh nisl eu lectus. Fusce vulputate sem at sapien.Vivamus leo. Aliquam euismod libero eu enim.Nulla nec felis sed leo placerat imperdiet.Aenean suscipit nulla in justo.Suspendisse cursus rutrum augue. Nulla tincidunt tincidunt mi. Curabitur iaculis, lorem vel rhoncus faucibus, felis magna fermentum augue, et ultricies lacus lorem varius purus. Curabitur eu amet."; + } +} diff --git a/samples/ResponseCompressionSample/Properties/launchSettings.json b/samples/ResponseCompressionSample/Properties/launchSettings.json new file mode 100644 index 0000000000..22f9a79116 --- /dev/null +++ b/samples/ResponseCompressionSample/Properties/launchSettings.json @@ -0,0 +1,25 @@ +{ + "iisSettings": { + "windowsAuthentication": false, + "anonymousAuthentication": true, + "iisExpress": { + "applicationUrl": "http://localhost:49658/", + "sslPort": 0 + } + }, + "profiles": { + "IIS Express": { + "commandName": "IISExpress", + "launchBrowser": true, + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + }, + "web": { + "commandName": "web", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + } + } +} \ No newline at end of file diff --git a/samples/ResponseCompressionSample/ResponseCompressionSample.xproj b/samples/ResponseCompressionSample/ResponseCompressionSample.xproj new file mode 100644 index 0000000000..66a15a5b7e --- /dev/null +++ b/samples/ResponseCompressionSample/ResponseCompressionSample.xproj @@ -0,0 +1,18 @@ + + + + 14.0 + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) + + + + b2a3ce38-51b2-4486-982c-98c380af140e + .\obj + .\bin\ + + + 2.0 + 46824 + + + \ No newline at end of file diff --git a/samples/ResponseCompressionSample/Startup.cs b/samples/ResponseCompressionSample/Startup.cs new file mode 100644 index 0000000000..63addfa7eb --- /dev/null +++ b/samples/ResponseCompressionSample/Startup.cs @@ -0,0 +1,37 @@ +// 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 Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.ResponseCompression; + +namespace ResponseCompressionSample +{ + public class Startup + { + public void Configure(IApplicationBuilder app) + { + app.UseResponseCompression(new ResponseCompressionOptions() + { + ShouldCompressResponse = ResponseCompressionUtils.CreateShouldCompressResponseDelegate(new string[] { "text/plain" }) + }); + + app.Run(async context => + { + context.Response.Headers["Content-Type"] = "text/plain"; + await context.Response.WriteAsync(LoremIpsum.Text); + }); + } + + public static void Main(string[] args) + { + var host = new WebHostBuilder() + .UseKestrel() + .UseStartup() + .Build(); + + host.Run(); + } + } +} diff --git a/samples/ResponseCompressionSample/project.json b/samples/ResponseCompressionSample/project.json new file mode 100644 index 0000000000..7ad12a138a --- /dev/null +++ b/samples/ResponseCompressionSample/project.json @@ -0,0 +1,31 @@ +{ + "version": "1.1.0-*", + "dependencies": { + "Microsoft.AspNetCore.ResponseCompression": "0.1.0-*", + "Microsoft.AspNetCore.Server.Kestrel": "1.1.0-*" + }, + "buildOptions": { + "emitEntryPoint": true, + "preserveCompilationContext": true + }, + "frameworks": { + "net451": {}, + "netcoreapp1.0": { + "dependencies": { + "Microsoft.NETCore.App": { + "version": "1.0.0-*", + "type": "platform" + } + } + } + }, + "publish": { + "exclude": [ + "node_modules", + "bower_components", + "**.xproj", + "**.user", + "**.vspscc" + ] + } +} diff --git a/src/Microsoft.AspNetCore.ResponseCompression/BodyWrapperStream.cs b/src/Microsoft.AspNetCore.ResponseCompression/BodyWrapperStream.cs new file mode 100644 index 0000000000..8862e92db5 --- /dev/null +++ b/src/Microsoft.AspNetCore.ResponseCompression/BodyWrapperStream.cs @@ -0,0 +1,192 @@ +// 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; +using System.Collections.Generic; +using System.IO; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.Primitives; +using Microsoft.Net.Http.Headers; + +namespace Microsoft.AspNetCore.ResponseCompression +{ + /// + /// Stream wrapper that create specific compression stream only if necessary. + /// + internal class BodyWrapperStream : Stream + { + private readonly HttpResponse _response; + + private readonly Stream _bodyOriginalStream; + + private readonly Func _shouldCompressResponse; + + private readonly IResponseCompressionProvider _compressionProvider; + + private bool _compressionChecked = false; + + private Stream _compressionStream = null; + + internal BodyWrapperStream(HttpResponse response, Stream bodyOriginalStream, Func shouldCompressResponse, IResponseCompressionProvider compressionProvider) + { + _response = response; + _bodyOriginalStream = bodyOriginalStream; + _shouldCompressResponse = shouldCompressResponse; + _compressionProvider = compressionProvider; + } + + protected override void Dispose(bool disposing) + { + if (_compressionStream != null) + { + _compressionStream.Dispose(); + _compressionStream = null; + } + } + + public override bool CanRead => _bodyOriginalStream.CanRead; + + public override bool CanSeek => _bodyOriginalStream.CanSeek; + + public override bool CanWrite => _bodyOriginalStream.CanWrite; + + public override long Length + { + get + { + throw new NotSupportedException(); + } + } + + public override long Position + { + get + { + throw new NotSupportedException(); + } + + set + { + throw new NotSupportedException(); + } + } + + public override void Flush() + { + OnWrite(); + + if (_compressionStream != null) + { + _compressionStream.Flush(); + } + else + { + _bodyOriginalStream.Flush(); + } + } + + public override Task FlushAsync(CancellationToken cancellationToken) + { + OnWrite(); + + if (_compressionStream != null) + { + return _compressionStream.FlushAsync(cancellationToken); + } + return _bodyOriginalStream.FlushAsync(cancellationToken); + } + + public override int Read(byte[] buffer, int offset, int count) + { + throw new NotSupportedException(); + } + + public override long Seek(long offset, SeekOrigin origin) + { + throw new NotSupportedException(); + } + + public override void SetLength(long value) + { + throw new NotSupportedException(); + } + + public override void Write(byte[] buffer, int offset, int count) + { + OnWrite(); + + if (_compressionStream != null) + { + _compressionStream.Write(buffer, offset, count); + } + else + { + _bodyOriginalStream.Write(buffer, offset, count); + } + } + +#if NET451 + public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object state) + { + OnWrite(); + + if (_compressionStream != null) + { + return _compressionStream.BeginWrite(buffer, offset, count, callback, state); + } + return _bodyOriginalStream.BeginWrite(buffer, offset, count, callback, state); + } + + public override void EndWrite(IAsyncResult asyncResult) + { + OnWrite(); + + if (_compressionStream != null) + { + _compressionStream.EndWrite(asyncResult); + } + else + { + _bodyOriginalStream.EndWrite(asyncResult); + } + } +#endif + + public override Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) + { + OnWrite(); + + if (_compressionStream != null) + { + return _compressionStream.WriteAsync(buffer, offset, count, cancellationToken); + } + return _bodyOriginalStream.WriteAsync(buffer, offset, count, cancellationToken); + } + + private void OnWrite() + { + if (!_compressionChecked) + { + if (IsCompressable()) + { + _response.Headers[HeaderNames.ContentEncoding] = _compressionProvider.EncodingName; + _response.Headers.Remove(HeaderNames.ContentMD5); // Reset the MD5 because the content changed. + _response.Headers.Remove(HeaderNames.ContentLength); + + _compressionStream = _compressionProvider.CreateStream(_bodyOriginalStream); + } + + _compressionChecked = true; + } + } + + private bool IsCompressable() + { + return _response.Headers[HeaderNames.ContentRange] == StringValues.Empty && // The response is not partial + _response.Headers[HeaderNames.ContentEncoding] == StringValues.Empty && // Not specific encoding already set + _shouldCompressResponse(_response.HttpContext); + } + } +} diff --git a/src/Microsoft.AspNetCore.ResponseCompression/GzipResponseCompressionProvider.cs b/src/Microsoft.AspNetCore.ResponseCompression/GzipResponseCompressionProvider.cs new file mode 100644 index 0000000000..9496f95197 --- /dev/null +++ b/src/Microsoft.AspNetCore.ResponseCompression/GzipResponseCompressionProvider.cs @@ -0,0 +1,34 @@ +// 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.IO; +using System.IO.Compression; + +namespace Microsoft.AspNetCore.ResponseCompression +{ + /// + /// GZIP compression provider. + /// + public class GzipResponseCompressionProvider : IResponseCompressionProvider + { + private readonly CompressionLevel _level; + + /// + /// Initialize a new . + /// + /// The compression level. + public GzipResponseCompressionProvider(CompressionLevel level) + { + _level = level; + } + + /// + public string EncodingName { get; } = "gzip"; + + /// + public Stream CreateStream(Stream outputStream) + { + return new GZipStream(outputStream, _level, true); + } + } +} diff --git a/src/Microsoft.AspNetCore.ResponseCompression/IResponseCompressionProvider.cs b/src/Microsoft.AspNetCore.ResponseCompression/IResponseCompressionProvider.cs new file mode 100644 index 0000000000..b91ed1db8d --- /dev/null +++ b/src/Microsoft.AspNetCore.ResponseCompression/IResponseCompressionProvider.cs @@ -0,0 +1,25 @@ +// 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.IO; + +namespace Microsoft.AspNetCore.ResponseCompression +{ + /// + /// Provides methods to be able to compress HTTP responses. + /// + public interface IResponseCompressionProvider + { + /// + /// The name that will be searched in the 'Accept-Encoding' request header. + /// + string EncodingName { get; } + + /// + /// Create a new compression stream. + /// + /// The stream where the compressed data have to be written. + /// The new stream. + Stream CreateStream(Stream outputStream); + } +} diff --git a/src/Microsoft.AspNetCore.ResponseCompression/Microsoft.AspNetCore.ResponseCompression.xproj b/src/Microsoft.AspNetCore.ResponseCompression/Microsoft.AspNetCore.ResponseCompression.xproj new file mode 100644 index 0000000000..0bd5bdaa35 --- /dev/null +++ b/src/Microsoft.AspNetCore.ResponseCompression/Microsoft.AspNetCore.ResponseCompression.xproj @@ -0,0 +1,17 @@ + + + + 14.0 + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) + + + + 45308a9d-f4c6-46a8-a24f-e73d995cc223 + .\obj + .\bin\ + + + 2.0 + + + diff --git a/src/Microsoft.AspNetCore.ResponseCompression/Properties/AssemblyInfo.cs b/src/Microsoft.AspNetCore.ResponseCompression/Properties/AssemblyInfo.cs new file mode 100644 index 0000000000..2dc4003a17 --- /dev/null +++ b/src/Microsoft.AspNetCore.ResponseCompression/Properties/AssemblyInfo.cs @@ -0,0 +1,11 @@ +// 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.Reflection; +using System.Resources; + +[assembly: AssemblyMetadata("Serviceable", "True")] +[assembly: NeutralResourcesLanguage("en-us")] +[assembly: AssemblyCompany("Microsoft Corporation.")] +[assembly: AssemblyCopyright("© Microsoft Corporation. All rights reserved.")] +[assembly: AssemblyProduct("Microsoft ASP.NET Core")] diff --git a/src/Microsoft.AspNetCore.ResponseCompression/ResponseCompressionExtensions.cs b/src/Microsoft.AspNetCore.ResponseCompression/ResponseCompressionExtensions.cs new file mode 100644 index 0000000000..720d9c30f0 --- /dev/null +++ b/src/Microsoft.AspNetCore.ResponseCompression/ResponseCompressionExtensions.cs @@ -0,0 +1,34 @@ +// 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; +using Microsoft.AspNetCore.ResponseCompression; +using Microsoft.Extensions.Options; + +namespace Microsoft.AspNetCore.Builder +{ + /// + /// Extension methods for the ResponseCompression middleware. + /// + public static class ResponseCompressionExtensions + { + /// + /// Allows to compress HTTP Responses. + /// + /// The instance this method extends. + /// The . + public static IApplicationBuilder UseResponseCompression(this IApplicationBuilder builder, ResponseCompressionOptions options) + { + if (builder == null) + { + throw new ArgumentNullException(nameof(builder)); + } + if (options == null) + { + throw new ArgumentNullException(nameof(options)); + } + + return builder.UseMiddleware(Options.Create(options)); + } + } +} diff --git a/src/Microsoft.AspNetCore.ResponseCompression/ResponseCompressionMiddleware.cs b/src/Microsoft.AspNetCore.ResponseCompression/ResponseCompressionMiddleware.cs new file mode 100644 index 0000000000..4d9a0e611c --- /dev/null +++ b/src/Microsoft.AspNetCore.ResponseCompression/ResponseCompressionMiddleware.cs @@ -0,0 +1,125 @@ +// 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; +using System.Collections.Generic; +using System.IO.Compression; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.Options; +using Microsoft.Extensions.Primitives; +using Microsoft.Net.Http.Headers; + +namespace Microsoft.AspNetCore.ResponseCompression +{ + /// + /// Enable HTTP response compression. + /// + public class ResponseCompressionMiddleware + { + private readonly RequestDelegate _next; + + private readonly Dictionary _compressionProviders; + + private readonly Func _shouldCompressResponse; + + private readonly bool _enableHttps; + + /// + /// Initialize the Response Compression middleware. + /// + /// + /// + public ResponseCompressionMiddleware(RequestDelegate next, IOptions options) + { + if (options.Value.ShouldCompressResponse == null) + { + throw new ArgumentException($"{nameof(options.Value.ShouldCompressResponse)} is not provided in argument {nameof(options)}"); + } + _shouldCompressResponse = options.Value.ShouldCompressResponse; + + _next = next; + + var providers = options.Value.Providers; + if (providers == null) + { + providers = new IResponseCompressionProvider[] + { + new GzipResponseCompressionProvider(CompressionLevel.Fastest) + }; + } + else if (!providers.Any()) + { + throw new ArgumentException($"{nameof(options.Value.Providers)} cannot be empty in argument {nameof(options)}"); + } + + _compressionProviders = providers.ToDictionary(p => p.EncodingName, StringComparer.OrdinalIgnoreCase); + _compressionProviders.Add("*", providers.First()); + _compressionProviders.Add("identity", null); + + _enableHttps = options.Value.EnableHttps; + } + + /// + /// Invoke the middleware. + /// + /// + /// + public async Task Invoke(HttpContext context) + { + IResponseCompressionProvider compressionProvider = null; + + if (!context.Request.IsHttps || _enableHttps) + { + compressionProvider = SelectProvider(context.Request.Headers[HeaderNames.AcceptEncoding]); + } + + if (compressionProvider == null) + { + await _next(context); + return; + } + + var bodyStream = context.Response.Body; + + using (var bodyWrapperStream = new BodyWrapperStream(context.Response, bodyStream, _shouldCompressResponse, compressionProvider)) + { + context.Response.Body = bodyWrapperStream; + + try + { + await _next(context); + } + finally + { + context.Response.Body = bodyStream; + } + } + } + + private IResponseCompressionProvider SelectProvider(StringValues acceptEncoding) + { + IList unsorted; + + if (StringWithQualityHeaderValue.TryParseList(acceptEncoding, out unsorted) && unsorted != null) + { + var sorted = unsorted + .Where(s => s.Quality.GetValueOrDefault(1) > 0) + .OrderByDescending(s => s.Quality.GetValueOrDefault(1)); + + foreach (var encoding in sorted) + { + IResponseCompressionProvider provider; + + if (_compressionProviders.TryGetValue(encoding.Value, out provider)) + { + return provider; + } + } + } + + return null; + } + } +} diff --git a/src/Microsoft.AspNetCore.ResponseCompression/ResponseCompressionOptions.cs b/src/Microsoft.AspNetCore.ResponseCompression/ResponseCompressionOptions.cs new file mode 100644 index 0000000000..b3548bbb45 --- /dev/null +++ b/src/Microsoft.AspNetCore.ResponseCompression/ResponseCompressionOptions.cs @@ -0,0 +1,32 @@ +// 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; +using System.Collections.Generic; +using Microsoft.AspNetCore.Http; + +namespace Microsoft.AspNetCore.ResponseCompression +{ + /// + /// Options for the HTTP response compression middleware. + /// + public class ResponseCompressionOptions + { + /// + /// Called when an HTTP request accepts a compatible compression algorithm, and returns True + /// if the response should be compressed. + /// + public Func ShouldCompressResponse { get; set; } + + /// + /// The compression providers. If 'null', the GZIP provider is set as default. + /// + public IEnumerable Providers { get; set; } + + /// + /// 'False' to enable compression only on HTTP requests. Enable compression on HTTPS requests + /// may lead to security problems. + /// + public bool EnableHttps { get; set; } = false; + } +} diff --git a/src/Microsoft.AspNetCore.ResponseCompression/ResponseCompressionUtils.cs b/src/Microsoft.AspNetCore.ResponseCompression/ResponseCompressionUtils.cs new file mode 100644 index 0000000000..525dc33ae6 --- /dev/null +++ b/src/Microsoft.AspNetCore.ResponseCompression/ResponseCompressionUtils.cs @@ -0,0 +1,49 @@ +// 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; +using System.Collections.Generic; +using Microsoft.AspNetCore.Http; + +namespace Microsoft.AspNetCore.ResponseCompression +{ + /// + /// Response Compression middleware utility methods. + /// + public static class ResponseCompressionUtils + { + /// + /// Create a delegate that propose to compress response, depending on a list of authorized + /// MIME types for the HTTP response. + /// + public static Func CreateShouldCompressResponseDelegate(IEnumerable mimeTypes) + { + if (mimeTypes == null) + { + throw new ArgumentNullException(nameof(mimeTypes)); + } + + var mimeTypeSet = new HashSet(mimeTypes); + + return (httpContext) => + { + var mimeType = httpContext.Response.ContentType; + + if (string.IsNullOrEmpty(mimeType)) + { + return false; + } + + var separator = mimeType.IndexOf(';'); + if (separator >= 0) + { + // Remove the content-type optional parameters + mimeType = mimeType.Substring(0, separator); + mimeType = mimeType.Trim(); + } + + return mimeTypeSet.Contains(mimeType); + }; + } + } +} diff --git a/src/Microsoft.AspNetCore.ResponseCompression/project.json b/src/Microsoft.AspNetCore.ResponseCompression/project.json new file mode 100644 index 0000000000..effe3df4a6 --- /dev/null +++ b/src/Microsoft.AspNetCore.ResponseCompression/project.json @@ -0,0 +1,31 @@ +{ + "version": "0.1.0-*", + "buildOptions": { + "warningsAsErrors": true, + "keyFile": "../../tools/Key.snk", + "xmlDoc": true + }, + "description": "ASP.NET Core middleware for HTTP Response compression.", + "packOptions": { + "repository": { + "type": "git", + "url": "git://github.com/aspnet/basicmiddleware" + }, + "tags": [ + "aspnetcore" + ] + }, + "dependencies": { + "Microsoft.AspNetCore.Http.Abstractions": "1.1.0-*", + "Microsoft.Extensions.Options": "1.1.0-*", + "Microsoft.Net.Http.Headers": "1.1.0-*" + }, + "frameworks": { + "net451": {}, + "netstandard1.3": { + "dependencies": { + "System.IO.Compression": "4.1.0-*" + } + } + } +} \ No newline at end of file diff --git a/test/Microsoft.AspNetCore.ResponseCompression.Tests/Microsoft.AspNetCore.ResponseCompression.Tests.xproj b/test/Microsoft.AspNetCore.ResponseCompression.Tests/Microsoft.AspNetCore.ResponseCompression.Tests.xproj new file mode 100644 index 0000000000..756da5af61 --- /dev/null +++ b/test/Microsoft.AspNetCore.ResponseCompression.Tests/Microsoft.AspNetCore.ResponseCompression.Tests.xproj @@ -0,0 +1,20 @@ + + + + 14.0 + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) + + + + 3360a5d1-70c0-49ee-9051-04a6a6b836dc + .\obj + .\bin\ + + + 2.0 + + + + + + diff --git a/test/Microsoft.AspNetCore.ResponseCompression.Tests/ResponseCompressionMiddlewareTest.cs b/test/Microsoft.AspNetCore.ResponseCompression.Tests/ResponseCompressionMiddlewareTest.cs new file mode 100644 index 0000000000..76cdcc9f14 --- /dev/null +++ b/test/Microsoft.AspNetCore.ResponseCompression.Tests/ResponseCompressionMiddlewareTest.cs @@ -0,0 +1,242 @@ +// 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; +using System.Collections.Generic; +using System.IO; +using System.IO.Compression; +using System.Net.Http; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.TestHost; +using Microsoft.Extensions.Options; +using Microsoft.Net.Http.Headers; +using Xunit; + +namespace Microsoft.AspNetCore.ResponseCompression.Tests +{ + public class ResponseCompressionMiddlewareTest + { + private const string TextPlain = "text/plain"; + + [Fact] + public void Options_NullShouldCompressResponse() + { + Assert.Throws(() => + { + new ResponseCompressionMiddleware(null, Options.Create(new ResponseCompressionOptions() + { + ShouldCompressResponse = null + })); + }); + } + + [Fact] + public void Options_HttpsDisabledByDefault() + { + var options = new ResponseCompressionOptions(); + + Assert.False(options.EnableHttps); + } + + [Fact] + public void Options_EmptyProviderList() + { + Assert.Throws(() => + { + new ResponseCompressionMiddleware(null, Options.Create(new ResponseCompressionOptions() + { + ShouldCompressResponse = _ => true, + Providers = new IResponseCompressionProvider[0] + })); + }); + } + + [Fact] + public async Task Request_Uncompressed() + { + var response = await InvokeMiddleware(100, requestAcceptEncodings: null, responseType: TextPlain); + + CheckResponseNotCompressed(response, expectedBodyLength: 100); + } + + [Fact] + public async Task Request_CompressGzip() + { + var response = await InvokeMiddleware(100, requestAcceptEncodings: new string[] { "gzip", "deflate" }, responseType: TextPlain); + + CheckResponseCompressed(response, expectedBodyLength: 24); + } + + [Fact] + public async Task Request_CompressUnknown() + { + var response = await InvokeMiddleware(100, requestAcceptEncodings: new string[] { "unknown" }, responseType: TextPlain); + + CheckResponseNotCompressed(response, expectedBodyLength: 100); + } + + [Fact] + public async Task Request_CompressStar() + { + var response = await InvokeMiddleware(100, requestAcceptEncodings: new string[] { "*" }, responseType: TextPlain); + + CheckResponseCompressed(response, expectedBodyLength: 24); + } + + [Fact] + public async Task Request_CompressIdentity() + { + var response = await InvokeMiddleware(100, requestAcceptEncodings: new string[] { "identity" }, responseType: TextPlain); + + CheckResponseNotCompressed(response, expectedBodyLength: 100); + } + + [Theory] + [InlineData(new string[] { "identity;q=0.5", "gzip;q=1" }, 24)] + [InlineData(new string[] { "identity;q=0", "gzip;q=0.8" }, 24)] + [InlineData(new string[] { "identity;q=0.5", "gzip" }, 24)] + public async Task Request_CompressQuality_Compressed(string[] acceptEncodings, int expectedBodyLength) + { + var response = await InvokeMiddleware(100, requestAcceptEncodings: acceptEncodings, responseType: TextPlain); + + CheckResponseCompressed(response, expectedBodyLength: expectedBodyLength); + } + + [Theory] + [InlineData(new string[] { "gzip;q=0.5", "identity;q=0.8" }, 100)] + public async Task Request_CompressQuality_NotCompressed(string[] acceptEncodings, int expectedBodyLength) + { + var response = await InvokeMiddleware(100, requestAcceptEncodings: acceptEncodings, responseType: TextPlain); + + CheckResponseNotCompressed(response, expectedBodyLength: expectedBodyLength); + } + + [Fact] + public async Task Request_UnauthorizedMimeType() + { + var response = await InvokeMiddleware(100, requestAcceptEncodings: new string[] { "gzip" }, responseType: "text/html"); + + CheckResponseNotCompressed(response, expectedBodyLength: 100); + } + + [Fact] + public async Task Request_ResponseWithContentRange() + { + var response = await InvokeMiddleware(50, requestAcceptEncodings: new string[] { "gzip" }, responseType: TextPlain, addResponseAction: (r) => + { + r.Headers[HeaderNames.ContentRange] = "1-2/*"; + }); + + CheckResponseNotCompressed(response, expectedBodyLength: 50); + } + + [Fact] + public async Task Request_ResponseWithContentEncodingAlreadySet() + { + var otherContentEncoding = "something"; + + var response = await InvokeMiddleware(50, requestAcceptEncodings: new string[] { "gzip" }, responseType: TextPlain, addResponseAction: (r) => + { + r.Headers[HeaderNames.ContentEncoding] = otherContentEncoding; + }); + + Assert.NotNull(response.Headers.GetValues(HeaderNames.ContentMD5)); + Assert.Single(response.Content.Headers.ContentEncoding, otherContentEncoding); + Assert.Equal(50, response.Content.Headers.ContentLength); + } + + [Theory] + [InlineData(false, 100)] + [InlineData(true, 24)] + public async Task Request_Https(bool enableHttps, int expectedLength) + { + var options = new ResponseCompressionOptions() + { + ShouldCompressResponse = _ => true, + Providers = new IResponseCompressionProvider[] + { + new GzipResponseCompressionProvider(CompressionLevel.Optimal) + }, + EnableHttps = enableHttps + }; + + var middleware = new ResponseCompressionMiddleware(async context => + { + context.Response.ContentType = TextPlain; + await context.Response.WriteAsync(new string('a', 100)); + }, Options.Create(options)); + + var httpContext = new DefaultHttpContext(); + httpContext.Request.Headers[HeaderNames.AcceptEncoding] = "gzip"; + httpContext.Request.IsHttps = true; + + httpContext.Response.Body = new MemoryStream(); + + await middleware.Invoke(httpContext); + + Assert.Equal(expectedLength, httpContext.Response.Body.Length); + } + + private Task InvokeMiddleware(int uncompressedBodyLength, string[] requestAcceptEncodings, string responseType, Action addResponseAction = null) + { + var options = new ResponseCompressionOptions() + { + ShouldCompressResponse = ctx => + { + var contentType = ctx.Response.Headers[HeaderNames.ContentType]; + return contentType.ToString().IndexOf(TextPlain) >= 0; + }, + Providers = new IResponseCompressionProvider[] + { + new GzipResponseCompressionProvider(CompressionLevel.Optimal) + } + }; + + var builder = new WebHostBuilder() + .Configure(app => + { + app.UseResponseCompression(options); + app.Run(context => + { + context.Response.Headers[HeaderNames.ContentMD5] = "MD5"; + context.Response.ContentType = responseType; + if (addResponseAction != null) + { + addResponseAction(context.Response); + } + return context.Response.WriteAsync(new string('a', uncompressedBodyLength)); + }); + }); + + var server = new TestServer(builder); + var client = server.CreateClient(); + + var request = new HttpRequestMessage(HttpMethod.Get, ""); + for (var i = 0; i < requestAcceptEncodings?.Length; i++) + { + request.Headers.AcceptEncoding.Add(System.Net.Http.Headers.StringWithQualityHeaderValue.Parse(requestAcceptEncodings[i])); + } + + return client.SendAsync(request); + } + + private void CheckResponseCompressed(HttpResponseMessage response, int expectedBodyLength) + { + IEnumerable contentMD5 = null; + + Assert.False(response.Headers.TryGetValues(HeaderNames.ContentMD5, out contentMD5)); + Assert.Single(response.Content.Headers.ContentEncoding, "gzip"); + Assert.Equal(expectedBodyLength, response.Content.Headers.ContentLength); + } + + private void CheckResponseNotCompressed(HttpResponseMessage response, int expectedBodyLength) + { + Assert.NotNull(response.Headers.GetValues(HeaderNames.ContentMD5)); + Assert.Empty(response.Content.Headers.ContentEncoding); + Assert.Equal(expectedBodyLength, response.Content.Headers.ContentLength); + } + } +} diff --git a/test/Microsoft.AspNetCore.ResponseCompression.Tests/ResponseCompressionUtilsTest.cs b/test/Microsoft.AspNetCore.ResponseCompression.Tests/ResponseCompressionUtilsTest.cs new file mode 100644 index 0000000000..9efcc79cb3 --- /dev/null +++ b/test/Microsoft.AspNetCore.ResponseCompression.Tests/ResponseCompressionUtilsTest.cs @@ -0,0 +1,69 @@ +// 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; +using System.Linq; +using Microsoft.AspNetCore.Http; +using Xunit; + +namespace Microsoft.AspNetCore.ResponseCompression.Tests +{ + public class ResponseCompressionUtilsTest + { + private const string TextPlain = "text/plain"; + + [Fact] + public void CreateShouldCompressResponseDelegate_NullMimeTypes() + { + Assert.Throws(() => + { + ResponseCompressionUtils.CreateShouldCompressResponseDelegate(null); + }); + } + + [Fact] + public void CreateShouldCompressResponseDelegate_Empty() + { + var httpContext = new DefaultHttpContext(); + httpContext.Response.ContentType = TextPlain; + + var func = ResponseCompressionUtils.CreateShouldCompressResponseDelegate(Enumerable.Empty()); + + var result = func(httpContext); + + Assert.False(result); + } + + [Theory] + [InlineData("text/plain")] + [InlineData("text/plain; charset=ISO-8859-4")] + [InlineData("text/plain ; charset=ISO-8859-4")] + public void CreateShouldCompressResponseDelegate_True(string contentType) + { + var httpContext = new DefaultHttpContext(); + httpContext.Response.ContentType = contentType; + + var func = ResponseCompressionUtils.CreateShouldCompressResponseDelegate(new string[] { TextPlain }); + + var result = func(httpContext); + + Assert.True(result); + } + + [Theory] + [InlineData("")] + [InlineData("text/plain2")] + [InlineData("text/PLAIN")] + public void CreateShouldCompressResponseDelegate_False(string contentType) + { + var httpContext = new DefaultHttpContext(); + httpContext.Response.ContentType = contentType; + + var func = ResponseCompressionUtils.CreateShouldCompressResponseDelegate(new string[] { TextPlain }); + + var result = func(httpContext); + + Assert.False(result); + } + } +} diff --git a/test/Microsoft.AspNetCore.ResponseCompression.Tests/project.json b/test/Microsoft.AspNetCore.ResponseCompression.Tests/project.json new file mode 100644 index 0000000000..f95326556d --- /dev/null +++ b/test/Microsoft.AspNetCore.ResponseCompression.Tests/project.json @@ -0,0 +1,26 @@ +{ + "version": "1.1.0-*", + "buildOptions": { + "warningsAsErrors": true + }, + "dependencies": { + "dotnet-test-xunit": "2.2.0-*", + "Microsoft.AspNetCore.ResponseCompression": "0.1.0-*", + "Microsoft.AspNetCore.TestHost": "1.1.0-*", + "xunit": "2.2.0-*", + "Microsoft.AspNetCore.Http": "1.1.0-*", + "Microsoft.Net.Http.Headers": "1.1.0-*" + }, + "frameworks": { + "netcoreapp1.0": { + "dependencies": { + "Microsoft.NETCore.App": { + "version": "1.0.0-*", + "type": "platform" + } + } + }, + "net451": {} + }, + "testRunner": "xunit" +} \ No newline at end of file From ea04e340621b183e1a7defcd87ccc67515090719 Mon Sep 17 00:00:00 2001 From: Chris R Date: Mon, 26 Sep 2016 12:10:41 -0700 Subject: [PATCH 115/307] Add ResponseCompression to NuGetPackageVerifier --- NuGetPackageVerifier.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/NuGetPackageVerifier.json b/NuGetPackageVerifier.json index 5fc01f59bd..328612811e 100644 --- a/NuGetPackageVerifier.json +++ b/NuGetPackageVerifier.json @@ -6,7 +6,8 @@ "packages": { "Microsoft.AspNetCore.Buffering": { }, "Microsoft.AspNetCore.HttpOverrides": { }, - "Microsoft.AspNetCore.Rewrite": { } + "Microsoft.AspNetCore.Rewrite": { }, + "Microsoft.AspNetCore.ResponseCompression": { } } }, "Default": { // Rules to run for packages not listed in any other set. From 665f2f8773194b6d6d984de85a6196222c292cb8 Mon Sep 17 00:00:00 2001 From: Chris R Date: Mon, 26 Sep 2016 12:11:45 -0700 Subject: [PATCH 116/307] ResponseCompression style cleanup --- .../ResponseCompressionSample/project.json | 4 +-- .../BodyWrapperStream.cs | 28 ++++++------------- .../ResponseCompressionMiddleware.cs | 1 + .../ResponseCompressionMiddlewareTest.cs | 26 ++++++++--------- .../ResponseCompressionUtilsTest.cs | 8 +++--- 5 files changed, 28 insertions(+), 39 deletions(-) diff --git a/samples/ResponseCompressionSample/project.json b/samples/ResponseCompressionSample/project.json index 7ad12a138a..0ad34fd2b2 100644 --- a/samples/ResponseCompressionSample/project.json +++ b/samples/ResponseCompressionSample/project.json @@ -1,12 +1,10 @@ { - "version": "1.1.0-*", "dependencies": { "Microsoft.AspNetCore.ResponseCompression": "0.1.0-*", "Microsoft.AspNetCore.Server.Kestrel": "1.1.0-*" }, "buildOptions": { - "emitEntryPoint": true, - "preserveCompilationContext": true + "emitEntryPoint": true }, "frameworks": { "net451": {}, diff --git a/src/Microsoft.AspNetCore.ResponseCompression/BodyWrapperStream.cs b/src/Microsoft.AspNetCore.ResponseCompression/BodyWrapperStream.cs index 8862e92db5..50e8ede353 100644 --- a/src/Microsoft.AspNetCore.ResponseCompression/BodyWrapperStream.cs +++ b/src/Microsoft.AspNetCore.ResponseCompression/BodyWrapperStream.cs @@ -46,31 +46,21 @@ namespace Microsoft.AspNetCore.ResponseCompression } } - public override bool CanRead => _bodyOriginalStream.CanRead; + public override bool CanRead => false; - public override bool CanSeek => _bodyOriginalStream.CanSeek; + public override bool CanSeek => false; public override bool CanWrite => _bodyOriginalStream.CanWrite; public override long Length { - get - { - throw new NotSupportedException(); - } + get { throw new NotSupportedException(); } } public override long Position { - get - { - throw new NotSupportedException(); - } - - set - { - throw new NotSupportedException(); - } + get { throw new NotSupportedException(); } + set { throw new NotSupportedException(); } } public override void Flush() @@ -169,16 +159,16 @@ namespace Microsoft.AspNetCore.ResponseCompression { if (!_compressionChecked) { + _compressionChecked = true; + if (IsCompressable()) { - _response.Headers[HeaderNames.ContentEncoding] = _compressionProvider.EncodingName; - _response.Headers.Remove(HeaderNames.ContentMD5); // Reset the MD5 because the content changed. + _response.Headers.Append(HeaderNames.ContentEncoding, _compressionProvider.EncodingName); + _response.Headers.Remove(HeaderNames.ContentMD5); // Reset the MD5 because the content changed. _response.Headers.Remove(HeaderNames.ContentLength); _compressionStream = _compressionProvider.CreateStream(_bodyOriginalStream); } - - _compressionChecked = true; } } diff --git a/src/Microsoft.AspNetCore.ResponseCompression/ResponseCompressionMiddleware.cs b/src/Microsoft.AspNetCore.ResponseCompression/ResponseCompressionMiddleware.cs index 4d9a0e611c..aa0620b3fe 100644 --- a/src/Microsoft.AspNetCore.ResponseCompression/ResponseCompressionMiddleware.cs +++ b/src/Microsoft.AspNetCore.ResponseCompression/ResponseCompressionMiddleware.cs @@ -37,6 +37,7 @@ namespace Microsoft.AspNetCore.ResponseCompression { throw new ArgumentException($"{nameof(options.Value.ShouldCompressResponse)} is not provided in argument {nameof(options)}"); } + _shouldCompressResponse = options.Value.ShouldCompressResponse; _next = next; diff --git a/test/Microsoft.AspNetCore.ResponseCompression.Tests/ResponseCompressionMiddlewareTest.cs b/test/Microsoft.AspNetCore.ResponseCompression.Tests/ResponseCompressionMiddlewareTest.cs index 76cdcc9f14..b526582b93 100644 --- a/test/Microsoft.AspNetCore.ResponseCompression.Tests/ResponseCompressionMiddlewareTest.cs +++ b/test/Microsoft.AspNetCore.ResponseCompression.Tests/ResponseCompressionMiddlewareTest.cs @@ -22,7 +22,7 @@ namespace Microsoft.AspNetCore.ResponseCompression.Tests private const string TextPlain = "text/plain"; [Fact] - public void Options_NullShouldCompressResponse() + public void Options_NullShouldCompressResponse_Throws() { Assert.Throws(() => { @@ -42,7 +42,7 @@ namespace Microsoft.AspNetCore.ResponseCompression.Tests } [Fact] - public void Options_EmptyProviderList() + public void Options_EmptyProviderList_Throws() { Assert.Throws(() => { @@ -55,7 +55,7 @@ namespace Microsoft.AspNetCore.ResponseCompression.Tests } [Fact] - public async Task Request_Uncompressed() + public async Task Request_NoAcceptEncoding_Uncompressed() { var response = await InvokeMiddleware(100, requestAcceptEncodings: null, responseType: TextPlain); @@ -63,7 +63,7 @@ namespace Microsoft.AspNetCore.ResponseCompression.Tests } [Fact] - public async Task Request_CompressGzip() + public async Task Request_AcceptGzipDeflate_ComrpessedGzip() { var response = await InvokeMiddleware(100, requestAcceptEncodings: new string[] { "gzip", "deflate" }, responseType: TextPlain); @@ -71,7 +71,7 @@ namespace Microsoft.AspNetCore.ResponseCompression.Tests } [Fact] - public async Task Request_CompressUnknown() + public async Task Request_AcceptUnknown_NotCompressed() { var response = await InvokeMiddleware(100, requestAcceptEncodings: new string[] { "unknown" }, responseType: TextPlain); @@ -79,7 +79,7 @@ namespace Microsoft.AspNetCore.ResponseCompression.Tests } [Fact] - public async Task Request_CompressStar() + public async Task Request_AcceptStar_Compressed() { var response = await InvokeMiddleware(100, requestAcceptEncodings: new string[] { "*" }, responseType: TextPlain); @@ -87,7 +87,7 @@ namespace Microsoft.AspNetCore.ResponseCompression.Tests } [Fact] - public async Task Request_CompressIdentity() + public async Task Request_AcceptIdentity_NotCompressed() { var response = await InvokeMiddleware(100, requestAcceptEncodings: new string[] { "identity" }, responseType: TextPlain); @@ -98,7 +98,7 @@ namespace Microsoft.AspNetCore.ResponseCompression.Tests [InlineData(new string[] { "identity;q=0.5", "gzip;q=1" }, 24)] [InlineData(new string[] { "identity;q=0", "gzip;q=0.8" }, 24)] [InlineData(new string[] { "identity;q=0.5", "gzip" }, 24)] - public async Task Request_CompressQuality_Compressed(string[] acceptEncodings, int expectedBodyLength) + public async Task Request_AcceptWithHigherCompressionQuality_Compressed(string[] acceptEncodings, int expectedBodyLength) { var response = await InvokeMiddleware(100, requestAcceptEncodings: acceptEncodings, responseType: TextPlain); @@ -107,7 +107,7 @@ namespace Microsoft.AspNetCore.ResponseCompression.Tests [Theory] [InlineData(new string[] { "gzip;q=0.5", "identity;q=0.8" }, 100)] - public async Task Request_CompressQuality_NotCompressed(string[] acceptEncodings, int expectedBodyLength) + public async Task Request_AcceptWithhigherIdentityQuality_NotCompressed(string[] acceptEncodings, int expectedBodyLength) { var response = await InvokeMiddleware(100, requestAcceptEncodings: acceptEncodings, responseType: TextPlain); @@ -115,7 +115,7 @@ namespace Microsoft.AspNetCore.ResponseCompression.Tests } [Fact] - public async Task Request_UnauthorizedMimeType() + public async Task Response_UnauthorizedMimeType_NotCompressed() { var response = await InvokeMiddleware(100, requestAcceptEncodings: new string[] { "gzip" }, responseType: "text/html"); @@ -123,7 +123,7 @@ namespace Microsoft.AspNetCore.ResponseCompression.Tests } [Fact] - public async Task Request_ResponseWithContentRange() + public async Task Response_WithContentRange_NotCompressed() { var response = await InvokeMiddleware(50, requestAcceptEncodings: new string[] { "gzip" }, responseType: TextPlain, addResponseAction: (r) => { @@ -134,7 +134,7 @@ namespace Microsoft.AspNetCore.ResponseCompression.Tests } [Fact] - public async Task Request_ResponseWithContentEncodingAlreadySet() + public async Task Response_WithContentEncodingAlreadySet_NotCompressed() { var otherContentEncoding = "something"; @@ -151,7 +151,7 @@ namespace Microsoft.AspNetCore.ResponseCompression.Tests [Theory] [InlineData(false, 100)] [InlineData(true, 24)] - public async Task Request_Https(bool enableHttps, int expectedLength) + public async Task Request_Https_CompressedIfEnabled(bool enableHttps, int expectedLength) { var options = new ResponseCompressionOptions() { diff --git a/test/Microsoft.AspNetCore.ResponseCompression.Tests/ResponseCompressionUtilsTest.cs b/test/Microsoft.AspNetCore.ResponseCompression.Tests/ResponseCompressionUtilsTest.cs index 9efcc79cb3..aae7752479 100644 --- a/test/Microsoft.AspNetCore.ResponseCompression.Tests/ResponseCompressionUtilsTest.cs +++ b/test/Microsoft.AspNetCore.ResponseCompression.Tests/ResponseCompressionUtilsTest.cs @@ -13,7 +13,7 @@ namespace Microsoft.AspNetCore.ResponseCompression.Tests private const string TextPlain = "text/plain"; [Fact] - public void CreateShouldCompressResponseDelegate_NullMimeTypes() + public void CreateShouldCompressResponseDelegate_NullMimeTypes_Throws() { Assert.Throws(() => { @@ -22,7 +22,7 @@ namespace Microsoft.AspNetCore.ResponseCompression.Tests } [Fact] - public void CreateShouldCompressResponseDelegate_Empty() + public void CreateShouldCompressResponseDelegate_Empty_DontCompress() { var httpContext = new DefaultHttpContext(); httpContext.Response.ContentType = TextPlain; @@ -38,7 +38,7 @@ namespace Microsoft.AspNetCore.ResponseCompression.Tests [InlineData("text/plain")] [InlineData("text/plain; charset=ISO-8859-4")] [InlineData("text/plain ; charset=ISO-8859-4")] - public void CreateShouldCompressResponseDelegate_True(string contentType) + public void CreateShouldCompressResponseDelegate_WithCharset_Compress(string contentType) { var httpContext = new DefaultHttpContext(); httpContext.Response.ContentType = contentType; @@ -54,7 +54,7 @@ namespace Microsoft.AspNetCore.ResponseCompression.Tests [InlineData("")] [InlineData("text/plain2")] [InlineData("text/PLAIN")] - public void CreateShouldCompressResponseDelegate_False(string contentType) + public void CreateShouldCompressResponseDelegate_OtherContentTypes_NoMatch(string contentType) { var httpContext = new DefaultHttpContext(); httpContext.Response.ContentType = contentType; From 89a6f453ce5eb85a0c41cf3153d8f790a5fa2103 Mon Sep 17 00:00:00 2001 From: Chris R Date: Mon, 26 Sep 2016 15:35:30 -0700 Subject: [PATCH 117/307] [ResponseCompression] Compare MimeTypes as case insensitive --- .../ResponseCompressionUtils.cs | 2 +- .../ResponseCompressionUtilsTest.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Microsoft.AspNetCore.ResponseCompression/ResponseCompressionUtils.cs b/src/Microsoft.AspNetCore.ResponseCompression/ResponseCompressionUtils.cs index 525dc33ae6..1e917b595f 100644 --- a/src/Microsoft.AspNetCore.ResponseCompression/ResponseCompressionUtils.cs +++ b/src/Microsoft.AspNetCore.ResponseCompression/ResponseCompressionUtils.cs @@ -23,7 +23,7 @@ namespace Microsoft.AspNetCore.ResponseCompression throw new ArgumentNullException(nameof(mimeTypes)); } - var mimeTypeSet = new HashSet(mimeTypes); + var mimeTypeSet = new HashSet(mimeTypes, StringComparer.OrdinalIgnoreCase); return (httpContext) => { diff --git a/test/Microsoft.AspNetCore.ResponseCompression.Tests/ResponseCompressionUtilsTest.cs b/test/Microsoft.AspNetCore.ResponseCompression.Tests/ResponseCompressionUtilsTest.cs index aae7752479..73fd2caea3 100644 --- a/test/Microsoft.AspNetCore.ResponseCompression.Tests/ResponseCompressionUtilsTest.cs +++ b/test/Microsoft.AspNetCore.ResponseCompression.Tests/ResponseCompressionUtilsTest.cs @@ -36,6 +36,7 @@ namespace Microsoft.AspNetCore.ResponseCompression.Tests [Theory] [InlineData("text/plain")] + [InlineData("text/PLAIN")] [InlineData("text/plain; charset=ISO-8859-4")] [InlineData("text/plain ; charset=ISO-8859-4")] public void CreateShouldCompressResponseDelegate_WithCharset_Compress(string contentType) @@ -53,7 +54,6 @@ namespace Microsoft.AspNetCore.ResponseCompression.Tests [Theory] [InlineData("")] [InlineData("text/plain2")] - [InlineData("text/PLAIN")] public void CreateShouldCompressResponseDelegate_OtherContentTypes_NoMatch(string contentType) { var httpContext = new DefaultHttpContext(); From 2a386b7b761690aa70c62cdbcdaaf7b0f932ea1b Mon Sep 17 00:00:00 2001 From: Mikael Mengistu Date: Tue, 27 Sep 2016 17:29:26 -0700 Subject: [PATCH 118/307] Removed unnecessary import --- test/Microsoft.AspNetCore.Rewrite.Tests/project.json | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/project.json b/test/Microsoft.AspNetCore.Rewrite.Tests/project.json index 53270ebe77..acbd1fdc82 100644 --- a/test/Microsoft.AspNetCore.Rewrite.Tests/project.json +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/project.json @@ -13,11 +13,10 @@ }, "frameworks": { "netcoreapp1.0": { - "imports": "dnxcore50", "dependencies": { "Microsoft.CodeCoverage": { "type": "build", - "version": "1.0.1" + "version": "1.0.2" }, "Microsoft.NETCore.App": { "version": "1.0.0-*", From 3e119a87be97a8c8b7c13ebc76865fe990251437 Mon Sep 17 00:00:00 2001 From: Nate McMaster Date: Wed, 28 Sep 2016 17:57:49 -0600 Subject: [PATCH 119/307] Remove rewrite rule API with default assumptions about skip remaining rules (#105) --- samples/RewriteSample/Startup.cs | 2 +- .../RewriteOptionsExtensions.cs | 16 ++-------------- .../MiddlewareTests.cs | 4 ++-- 3 files changed, 5 insertions(+), 17 deletions(-) diff --git a/samples/RewriteSample/Startup.cs b/samples/RewriteSample/Startup.cs index e1285d0666..7ef08d2f99 100644 --- a/samples/RewriteSample/Startup.cs +++ b/samples/RewriteSample/Startup.cs @@ -15,7 +15,7 @@ namespace RewriteSample { var options = new RewriteOptions() .AddRedirect("(.*)/$", "$1") - .AddRewrite(@"app/(\d+)", "app?id=$1") + .AddRewrite(@"app/(\d+)", "app?id=$1", skipRemainingRules: false) .AddRedirectToHttps(302, 5001) .AddIISUrlRewrite(env.ContentRootFileProvider, "UrlRewrite.xml") .AddApacheModRewrite(env.ContentRootFileProvider, "Rewrite.txt"); diff --git a/src/Microsoft.AspNetCore.Rewrite/RewriteOptionsExtensions.cs b/src/Microsoft.AspNetCore.Rewrite/RewriteOptionsExtensions.cs index b1b4057cd4..550d6e8211 100644 --- a/src/Microsoft.AspNetCore.Rewrite/RewriteOptionsExtensions.cs +++ b/src/Microsoft.AspNetCore.Rewrite/RewriteOptionsExtensions.cs @@ -1,4 +1,4 @@ -// Copyright (c) .NET Foundation. All rights reserved. +// 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; @@ -36,19 +36,7 @@ namespace Microsoft.AspNetCore.Rewrite } /// - /// Rewrites the path if the regex matches the HttpContext's PathString - /// - /// The . - /// The regex string to compare with. - /// If the regex matches, what to replace HttpContext with. - /// The Rewrite options. - public static RewriteOptions AddRewrite(this RewriteOptions options, string regex, string replacement) - { - return AddRewrite(options, regex, replacement, skipRemainingRules: false); - } - - /// - /// Rewrites the path if the regex matches the HttpContext's PathString + /// Adds a rule that rewrites the path if the regex matches the HttpContext's PathString. /// /// The . /// The regex string to compare with. diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/MiddlewareTests.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/MiddlewareTests.cs index 9a6f4d9c46..67802e031f 100644 --- a/test/Microsoft.AspNetCore.Rewrite.Tests/MiddlewareTests.cs +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/MiddlewareTests.cs @@ -16,7 +16,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.CodeRules [Fact] public async Task CheckRewritePath() { - var options = new RewriteOptions().AddRewrite("(.*)", "http://example.com/$1"); + var options = new RewriteOptions().AddRewrite("(.*)", "http://example.com/$1", skipRemainingRules: false); var builder = new WebHostBuilder() .Configure(app => { @@ -87,7 +87,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.CodeRules [Fact] public async Task CheckIfEmptyStringRewriteCorrectly() { - var options = new RewriteOptions().AddRewrite("(.*)", "$1"); + var options = new RewriteOptions().AddRewrite("(.*)", "$1", skipRemainingRules: false); var builder = new WebHostBuilder() .Configure(app => { From 9bc8a83a392545bdca11d47383f0f3ba0e7a2a28 Mon Sep 17 00:00:00 2001 From: Chris R Date: Fri, 30 Sep 2016 10:15:46 -0700 Subject: [PATCH 120/307] #108 Change ResponseCompression to be DI centric --- .../CustomCompressionProvider.cs | 16 ++ .../Properties/launchSettings.json | 19 +- samples/ResponseCompressionSample/Startup.cs | 15 +- .../BodyWrapperStream.cs | 15 +- ...Provider.cs => GzipCompressionProvider.cs} | 19 +- .../ICompressionProvider.cs | 25 +++ .../IResponseCompressionProvider.cs | 18 +- .../ResponseCompressionExtensions.cs | 50 ++++- .../ResponseCompressionMiddleware.cs | 76 ++------ .../ResponseCompressionOptions.cs | 16 +- .../ResponseCompressionProvider.cs | 114 +++++++++++ .../ResponseCompressionUtils.cs | 49 ----- .../ResponseCompressionMiddlewareTest.cs | 184 +++++++++++------- .../ResponseCompressionUtilsTest.cs | 69 ------- 14 files changed, 374 insertions(+), 311 deletions(-) create mode 100644 samples/ResponseCompressionSample/CustomCompressionProvider.cs rename src/Microsoft.AspNetCore.ResponseCompression/{GzipResponseCompressionProvider.cs => GzipCompressionProvider.cs} (53%) create mode 100644 src/Microsoft.AspNetCore.ResponseCompression/ICompressionProvider.cs create mode 100644 src/Microsoft.AspNetCore.ResponseCompression/ResponseCompressionProvider.cs delete mode 100644 src/Microsoft.AspNetCore.ResponseCompression/ResponseCompressionUtils.cs delete mode 100644 test/Microsoft.AspNetCore.ResponseCompression.Tests/ResponseCompressionUtilsTest.cs diff --git a/samples/ResponseCompressionSample/CustomCompressionProvider.cs b/samples/ResponseCompressionSample/CustomCompressionProvider.cs new file mode 100644 index 0000000000..f9d4781bbf --- /dev/null +++ b/samples/ResponseCompressionSample/CustomCompressionProvider.cs @@ -0,0 +1,16 @@ +using System.IO; +using Microsoft.AspNetCore.ResponseCompression; + +namespace ResponseCompressionSample +{ + public class CustomCompressionProvider : ICompressionProvider + { + public string EncodingName => "custom"; + + public Stream CreateStream(Stream outputStream) + { + // Create a custom compression stream wrapper here + return outputStream; + } + } +} diff --git a/samples/ResponseCompressionSample/Properties/launchSettings.json b/samples/ResponseCompressionSample/Properties/launchSettings.json index 22f9a79116..f6c233feed 100644 --- a/samples/ResponseCompressionSample/Properties/launchSettings.json +++ b/samples/ResponseCompressionSample/Properties/launchSettings.json @@ -1,22 +1,9 @@ { - "iisSettings": { - "windowsAuthentication": false, - "anonymousAuthentication": true, - "iisExpress": { - "applicationUrl": "http://localhost:49658/", - "sslPort": 0 - } - }, "profiles": { - "IIS Express": { - "commandName": "IISExpress", + "ResponseCompressionSample": { + "commandName": "Project", "launchBrowser": true, - "environmentVariables": { - "ASPNETCORE_ENVIRONMENT": "Development" - } - }, - "web": { - "commandName": "web", + "launchUrl": "http://localhost:5000/", "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development" } diff --git a/samples/ResponseCompressionSample/Startup.cs b/samples/ResponseCompressionSample/Startup.cs index 63addfa7eb..f5fdd6126c 100644 --- a/samples/ResponseCompressionSample/Startup.cs +++ b/samples/ResponseCompressionSample/Startup.cs @@ -5,21 +5,26 @@ using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.ResponseCompression; +using Microsoft.Extensions.DependencyInjection; namespace ResponseCompressionSample { public class Startup { + public void ConfigureServices(IServiceCollection services) + { + services.AddTransient(); + services.AddTransient(); + services.AddResponseCompression("text/plain", "text/html"); + } + public void Configure(IApplicationBuilder app) { - app.UseResponseCompression(new ResponseCompressionOptions() - { - ShouldCompressResponse = ResponseCompressionUtils.CreateShouldCompressResponseDelegate(new string[] { "text/plain" }) - }); + app.UseResponseCompression(); app.Run(async context => { - context.Response.Headers["Content-Type"] = "text/plain"; + context.Response.ContentType = "text/plain"; await context.Response.WriteAsync(LoremIpsum.Text); }); } diff --git a/src/Microsoft.AspNetCore.ResponseCompression/BodyWrapperStream.cs b/src/Microsoft.AspNetCore.ResponseCompression/BodyWrapperStream.cs index 50e8ede353..453ede8899 100644 --- a/src/Microsoft.AspNetCore.ResponseCompression/BodyWrapperStream.cs +++ b/src/Microsoft.AspNetCore.ResponseCompression/BodyWrapperStream.cs @@ -2,12 +2,10 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; -using System.Collections.Generic; using System.IO; using System.Threading; using System.Threading.Tasks; using Microsoft.AspNetCore.Http; -using Microsoft.Extensions.Primitives; using Microsoft.Net.Http.Headers; namespace Microsoft.AspNetCore.ResponseCompression @@ -21,19 +19,19 @@ namespace Microsoft.AspNetCore.ResponseCompression private readonly Stream _bodyOriginalStream; - private readonly Func _shouldCompressResponse; + private readonly IResponseCompressionProvider _provider; - private readonly IResponseCompressionProvider _compressionProvider; + private readonly ICompressionProvider _compressionProvider; private bool _compressionChecked = false; private Stream _compressionStream = null; - internal BodyWrapperStream(HttpResponse response, Stream bodyOriginalStream, Func shouldCompressResponse, IResponseCompressionProvider compressionProvider) + internal BodyWrapperStream(HttpResponse response, Stream bodyOriginalStream, IResponseCompressionProvider provider, ICompressionProvider compressionProvider) { _response = response; _bodyOriginalStream = bodyOriginalStream; - _shouldCompressResponse = shouldCompressResponse; + _provider = provider; _compressionProvider = compressionProvider; } @@ -174,9 +172,8 @@ namespace Microsoft.AspNetCore.ResponseCompression private bool IsCompressable() { - return _response.Headers[HeaderNames.ContentRange] == StringValues.Empty && // The response is not partial - _response.Headers[HeaderNames.ContentEncoding] == StringValues.Empty && // Not specific encoding already set - _shouldCompressResponse(_response.HttpContext); + return !_response.Headers.ContainsKey(HeaderNames.ContentRange) && // The response is not partial + _provider.ShouldCompressResponse(_response.HttpContext); } } } diff --git a/src/Microsoft.AspNetCore.ResponseCompression/GzipResponseCompressionProvider.cs b/src/Microsoft.AspNetCore.ResponseCompression/GzipCompressionProvider.cs similarity index 53% rename from src/Microsoft.AspNetCore.ResponseCompression/GzipResponseCompressionProvider.cs rename to src/Microsoft.AspNetCore.ResponseCompression/GzipCompressionProvider.cs index 9496f95197..ff2c20c9b7 100644 --- a/src/Microsoft.AspNetCore.ResponseCompression/GzipResponseCompressionProvider.cs +++ b/src/Microsoft.AspNetCore.ResponseCompression/GzipCompressionProvider.cs @@ -9,26 +9,27 @@ namespace Microsoft.AspNetCore.ResponseCompression /// /// GZIP compression provider. /// - public class GzipResponseCompressionProvider : IResponseCompressionProvider + public class GzipCompressionProvider : ICompressionProvider { - private readonly CompressionLevel _level; - /// - /// Initialize a new . + /// Initialize a new . /// - /// The compression level. - public GzipResponseCompressionProvider(CompressionLevel level) + public GzipCompressionProvider() { - _level = level; } /// - public string EncodingName { get; } = "gzip"; + public string EncodingName => "gzip"; + + /// + /// What level of compression to use for the stream. + /// + public CompressionLevel Level { get; set; } = CompressionLevel.Fastest; /// public Stream CreateStream(Stream outputStream) { - return new GZipStream(outputStream, _level, true); + return new GZipStream(outputStream, Level, leaveOpen: true); } } } diff --git a/src/Microsoft.AspNetCore.ResponseCompression/ICompressionProvider.cs b/src/Microsoft.AspNetCore.ResponseCompression/ICompressionProvider.cs new file mode 100644 index 0000000000..66ae5cca51 --- /dev/null +++ b/src/Microsoft.AspNetCore.ResponseCompression/ICompressionProvider.cs @@ -0,0 +1,25 @@ +// 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.IO; + +namespace Microsoft.AspNetCore.ResponseCompression +{ + /// + /// Provides a specific compression implementation to compress HTTP responses. + /// + public interface ICompressionProvider + { + /// + /// The encoding name used in the 'Accept-Encoding' request header and 'Content-Encoding' response header. + /// + string EncodingName { get; } + + /// + /// Create a new compression stream. + /// + /// The stream where the compressed data have to be written. + /// The compression stream. + Stream CreateStream(Stream outputStream); + } +} diff --git a/src/Microsoft.AspNetCore.ResponseCompression/IResponseCompressionProvider.cs b/src/Microsoft.AspNetCore.ResponseCompression/IResponseCompressionProvider.cs index b91ed1db8d..8b118a2d89 100644 --- a/src/Microsoft.AspNetCore.ResponseCompression/IResponseCompressionProvider.cs +++ b/src/Microsoft.AspNetCore.ResponseCompression/IResponseCompressionProvider.cs @@ -1,25 +1,27 @@ // 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.IO; +using Microsoft.AspNetCore.Http; namespace Microsoft.AspNetCore.ResponseCompression { /// - /// Provides methods to be able to compress HTTP responses. + /// Used to examine requests and responses to see if compression should be enabled. /// public interface IResponseCompressionProvider { /// - /// The name that will be searched in the 'Accept-Encoding' request header. + /// Examines the request and selects an acceptable compression provider, if any. /// - string EncodingName { get; } + /// + /// A compression provider or null if compression should not be used. + ICompressionProvider GetCompressionProvider(HttpContext context); /// - /// Create a new compression stream. + /// Examines the response on first write to see if compression should be used. /// - /// The stream where the compressed data have to be written. - /// The new stream. - Stream CreateStream(Stream outputStream); + /// + /// + bool ShouldCompressResponse(HttpContext context); } } diff --git a/src/Microsoft.AspNetCore.ResponseCompression/ResponseCompressionExtensions.cs b/src/Microsoft.AspNetCore.ResponseCompression/ResponseCompressionExtensions.cs index 720d9c30f0..cb827c4fd1 100644 --- a/src/Microsoft.AspNetCore.ResponseCompression/ResponseCompressionExtensions.cs +++ b/src/Microsoft.AspNetCore.ResponseCompression/ResponseCompressionExtensions.cs @@ -3,7 +3,8 @@ using System; using Microsoft.AspNetCore.ResponseCompression; -using Microsoft.Extensions.Options; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection.Extensions; namespace Microsoft.AspNetCore.Builder { @@ -13,22 +14,53 @@ namespace Microsoft.AspNetCore.Builder public static class ResponseCompressionExtensions { /// - /// Allows to compress HTTP Responses. + /// Add response compression services and enable compression for responses with the given MIME types. + /// + /// The for adding services. + /// Response Content-Type MIME types to enable compression for. + /// + public static IServiceCollection AddResponseCompression(this IServiceCollection services, params string[] mimeTypes) + { + return services.AddResponseCompression(options => + { + options.MimeTypes = mimeTypes; + }); + } + + /// + /// Add response compression services and configure the related options. + /// + /// The for adding services. + /// A delegate to configure the . + /// + public static IServiceCollection AddResponseCompression(this IServiceCollection services, Action configureOptions) + { + if (services == null) + { + throw new ArgumentNullException(nameof(services)); + } + if (configureOptions == null) + { + throw new ArgumentNullException(nameof(configureOptions)); + } + + services.Configure(configureOptions); + services.TryAddTransient(); + return services; + } + + /// + /// Adds middleware for dynamically compressing HTTP Responses. /// /// The instance this method extends. - /// The . - public static IApplicationBuilder UseResponseCompression(this IApplicationBuilder builder, ResponseCompressionOptions options) + public static IApplicationBuilder UseResponseCompression(this IApplicationBuilder builder) { if (builder == null) { throw new ArgumentNullException(nameof(builder)); } - if (options == null) - { - throw new ArgumentNullException(nameof(options)); - } - return builder.UseMiddleware(Options.Create(options)); + return builder.UseMiddleware(); } } } diff --git a/src/Microsoft.AspNetCore.ResponseCompression/ResponseCompressionMiddleware.cs b/src/Microsoft.AspNetCore.ResponseCompression/ResponseCompressionMiddleware.cs index aa0620b3fe..96e6c7af46 100644 --- a/src/Microsoft.AspNetCore.ResponseCompression/ResponseCompressionMiddleware.cs +++ b/src/Microsoft.AspNetCore.ResponseCompression/ResponseCompressionMiddleware.cs @@ -2,14 +2,9 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; -using System.Collections.Generic; -using System.IO.Compression; -using System.Linq; using System.Threading.Tasks; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Options; -using Microsoft.Extensions.Primitives; -using Microsoft.Net.Http.Headers; namespace Microsoft.AspNetCore.ResponseCompression { @@ -20,9 +15,7 @@ namespace Microsoft.AspNetCore.ResponseCompression { private readonly RequestDelegate _next; - private readonly Dictionary _compressionProviders; - - private readonly Func _shouldCompressResponse; + private readonly IResponseCompressionProvider _provider; private readonly bool _enableHttps; @@ -30,35 +23,24 @@ namespace Microsoft.AspNetCore.ResponseCompression /// Initialize the Response Compression middleware. /// /// + /// /// - public ResponseCompressionMiddleware(RequestDelegate next, IOptions options) + public ResponseCompressionMiddleware(RequestDelegate next, IResponseCompressionProvider provider, IOptions options) { - if (options.Value.ShouldCompressResponse == null) + if (next == null) { - throw new ArgumentException($"{nameof(options.Value.ShouldCompressResponse)} is not provided in argument {nameof(options)}"); + throw new ArgumentNullException(nameof(next)); + } + if (provider == null) + { + throw new ArgumentNullException(nameof(provider)); + } + if (options == null) + { + throw new ArgumentNullException(nameof(options)); } - - _shouldCompressResponse = options.Value.ShouldCompressResponse; - _next = next; - - var providers = options.Value.Providers; - if (providers == null) - { - providers = new IResponseCompressionProvider[] - { - new GzipResponseCompressionProvider(CompressionLevel.Fastest) - }; - } - else if (!providers.Any()) - { - throw new ArgumentException($"{nameof(options.Value.Providers)} cannot be empty in argument {nameof(options)}"); - } - - _compressionProviders = providers.ToDictionary(p => p.EncodingName, StringComparer.OrdinalIgnoreCase); - _compressionProviders.Add("*", providers.First()); - _compressionProviders.Add("identity", null); - + _provider = provider; _enableHttps = options.Value.EnableHttps; } @@ -69,11 +51,11 @@ namespace Microsoft.AspNetCore.ResponseCompression /// public async Task Invoke(HttpContext context) { - IResponseCompressionProvider compressionProvider = null; + ICompressionProvider compressionProvider = null; if (!context.Request.IsHttps || _enableHttps) { - compressionProvider = SelectProvider(context.Request.Headers[HeaderNames.AcceptEncoding]); + compressionProvider = _provider.GetCompressionProvider(context); } if (compressionProvider == null) @@ -84,7 +66,7 @@ namespace Microsoft.AspNetCore.ResponseCompression var bodyStream = context.Response.Body; - using (var bodyWrapperStream = new BodyWrapperStream(context.Response, bodyStream, _shouldCompressResponse, compressionProvider)) + using (var bodyWrapperStream = new BodyWrapperStream(context.Response, bodyStream, _provider, compressionProvider)) { context.Response.Body = bodyWrapperStream; @@ -98,29 +80,5 @@ namespace Microsoft.AspNetCore.ResponseCompression } } } - - private IResponseCompressionProvider SelectProvider(StringValues acceptEncoding) - { - IList unsorted; - - if (StringWithQualityHeaderValue.TryParseList(acceptEncoding, out unsorted) && unsorted != null) - { - var sorted = unsorted - .Where(s => s.Quality.GetValueOrDefault(1) > 0) - .OrderByDescending(s => s.Quality.GetValueOrDefault(1)); - - foreach (var encoding in sorted) - { - IResponseCompressionProvider provider; - - if (_compressionProviders.TryGetValue(encoding.Value, out provider)) - { - return provider; - } - } - } - - return null; - } } } diff --git a/src/Microsoft.AspNetCore.ResponseCompression/ResponseCompressionOptions.cs b/src/Microsoft.AspNetCore.ResponseCompression/ResponseCompressionOptions.cs index b3548bbb45..7d3b049984 100644 --- a/src/Microsoft.AspNetCore.ResponseCompression/ResponseCompressionOptions.cs +++ b/src/Microsoft.AspNetCore.ResponseCompression/ResponseCompressionOptions.cs @@ -1,9 +1,7 @@ // 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; using System.Collections.Generic; -using Microsoft.AspNetCore.Http; namespace Microsoft.AspNetCore.ResponseCompression { @@ -13,19 +11,13 @@ namespace Microsoft.AspNetCore.ResponseCompression public class ResponseCompressionOptions { /// - /// Called when an HTTP request accepts a compatible compression algorithm, and returns True - /// if the response should be compressed. + /// Response Content-Type MIME types to compress. /// - public Func ShouldCompressResponse { get; set; } + public IEnumerable MimeTypes { get; set; } /// - /// The compression providers. If 'null', the GZIP provider is set as default. - /// - public IEnumerable Providers { get; set; } - - /// - /// 'False' to enable compression only on HTTP requests. Enable compression on HTTPS requests - /// may lead to security problems. + /// Indicates if responses over HTTPS connections should be compressed. The default is 'false'. + /// Enable compression on HTTPS connections may expose security problems. /// public bool EnableHttps { get; set; } = false; } diff --git a/src/Microsoft.AspNetCore.ResponseCompression/ResponseCompressionProvider.cs b/src/Microsoft.AspNetCore.ResponseCompression/ResponseCompressionProvider.cs new file mode 100644 index 0000000000..64963b124a --- /dev/null +++ b/src/Microsoft.AspNetCore.ResponseCompression/ResponseCompressionProvider.cs @@ -0,0 +1,114 @@ +// 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; +using System.Collections.Generic; +using System.Linq; +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.Options; +using Microsoft.Extensions.Primitives; +using Microsoft.Net.Http.Headers; + +namespace Microsoft.AspNetCore.ResponseCompression +{ + /// + public class ResponseCompressionProvider : IResponseCompressionProvider + { + private readonly ICompressionProvider[] _providers; + private readonly HashSet _mimeTypes; + + /// + /// If no compression providers are specified then GZip is used by default. + /// + /// Compression providers to use, if any. + /// + public ResponseCompressionProvider(IEnumerable providers, IOptions options) + { + if (providers == null) + { + throw new ArgumentNullException(nameof(providers)); + } + if (options == null) + { + throw new ArgumentNullException(nameof(options)); + } + + _providers = providers.ToArray(); + if (_providers.Length == 0) + { + _providers = new [] { new GzipCompressionProvider() }; + } + + if (options.Value.MimeTypes == null || !options.Value.MimeTypes.Any()) + { + throw new InvalidOperationException("No mime types specified"); + } + _mimeTypes = new HashSet(options.Value.MimeTypes, StringComparer.OrdinalIgnoreCase); + } + + /// + public virtual ICompressionProvider GetCompressionProvider(HttpContext context) + { + IList unsorted; + + // e.g. Accept-Encoding: gzip, deflate, sdch + var accept = context.Request.Headers[HeaderNames.AcceptEncoding]; + if (!StringValues.IsNullOrEmpty(accept) + && StringWithQualityHeaderValue.TryParseList(accept, out unsorted) + && unsorted != null && unsorted.Count > 0) + { + // TODO PERF: clients don't usually include quality values so this sort will not have any effect. Fast-path? + var sorted = unsorted + .Where(s => s.Quality.GetValueOrDefault(1) > 0) + .OrderByDescending(s => s.Quality.GetValueOrDefault(1)); + + foreach (var encoding in sorted) + { + // There will rarely be more than three providers, and there's only one by default + foreach (var provider in _providers) + { + if (string.Equals(provider.EncodingName, encoding.Value, StringComparison.OrdinalIgnoreCase)) + { + return provider; + } + } + + // Uncommon but valid options + if (string.Equals("*", encoding.Value, StringComparison.Ordinal)) + { + // Any + return _providers[0]; + } + if (string.Equals("identity", encoding.Value, StringComparison.OrdinalIgnoreCase)) + { + // No compression + return null; + } + } + } + + return null; + } + + /// + public virtual bool ShouldCompressResponse(HttpContext context) + { + var mimeType = context.Response.ContentType; + + if (string.IsNullOrEmpty(mimeType)) + { + return false; + } + + var separator = mimeType.IndexOf(';'); + if (separator >= 0) + { + // Remove the content-type optional parameters + mimeType = mimeType.Substring(0, separator); + mimeType = mimeType.Trim(); + } + + return _mimeTypes.Contains(mimeType); + } + } +} diff --git a/src/Microsoft.AspNetCore.ResponseCompression/ResponseCompressionUtils.cs b/src/Microsoft.AspNetCore.ResponseCompression/ResponseCompressionUtils.cs deleted file mode 100644 index 1e917b595f..0000000000 --- a/src/Microsoft.AspNetCore.ResponseCompression/ResponseCompressionUtils.cs +++ /dev/null @@ -1,49 +0,0 @@ -// 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; -using System.Collections.Generic; -using Microsoft.AspNetCore.Http; - -namespace Microsoft.AspNetCore.ResponseCompression -{ - /// - /// Response Compression middleware utility methods. - /// - public static class ResponseCompressionUtils - { - /// - /// Create a delegate that propose to compress response, depending on a list of authorized - /// MIME types for the HTTP response. - /// - public static Func CreateShouldCompressResponseDelegate(IEnumerable mimeTypes) - { - if (mimeTypes == null) - { - throw new ArgumentNullException(nameof(mimeTypes)); - } - - var mimeTypeSet = new HashSet(mimeTypes, StringComparer.OrdinalIgnoreCase); - - return (httpContext) => - { - var mimeType = httpContext.Response.ContentType; - - if (string.IsNullOrEmpty(mimeType)) - { - return false; - } - - var separator = mimeType.IndexOf(';'); - if (separator >= 0) - { - // Remove the content-type optional parameters - mimeType = mimeType.Substring(0, separator); - mimeType = mimeType.Trim(); - } - - return mimeTypeSet.Contains(mimeType); - }; - } - } -} diff --git a/test/Microsoft.AspNetCore.ResponseCompression.Tests/ResponseCompressionMiddlewareTest.cs b/test/Microsoft.AspNetCore.ResponseCompression.Tests/ResponseCompressionMiddlewareTest.cs index b526582b93..1e362fcc48 100644 --- a/test/Microsoft.AspNetCore.ResponseCompression.Tests/ResponseCompressionMiddlewareTest.cs +++ b/test/Microsoft.AspNetCore.ResponseCompression.Tests/ResponseCompressionMiddlewareTest.cs @@ -3,15 +3,12 @@ using System; using System.Collections.Generic; -using System.IO; -using System.IO.Compression; using System.Net.Http; using System.Threading.Tasks; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.TestHost; -using Microsoft.Extensions.Options; using Microsoft.Net.Http.Headers; using Xunit; @@ -21,18 +18,6 @@ namespace Microsoft.AspNetCore.ResponseCompression.Tests { private const string TextPlain = "text/plain"; - [Fact] - public void Options_NullShouldCompressResponse_Throws() - { - Assert.Throws(() => - { - new ResponseCompressionMiddleware(null, Options.Create(new ResponseCompressionOptions() - { - ShouldCompressResponse = null - })); - }); - } - [Fact] public void Options_HttpsDisabledByDefault() { @@ -41,19 +26,6 @@ namespace Microsoft.AspNetCore.ResponseCompression.Tests Assert.False(options.EnableHttps); } - [Fact] - public void Options_EmptyProviderList_Throws() - { - Assert.Throws(() => - { - new ResponseCompressionMiddleware(null, Options.Create(new ResponseCompressionOptions() - { - ShouldCompressResponse = _ => true, - Providers = new IResponseCompressionProvider[0] - })); - }); - } - [Fact] public async Task Request_NoAcceptEncoding_Uncompressed() { @@ -78,6 +50,91 @@ namespace Microsoft.AspNetCore.ResponseCompression.Tests CheckResponseNotCompressed(response, expectedBodyLength: 100); } + [Fact] + public void NoMimeTypes_Throws() + { + var builder = new WebHostBuilder() + .ConfigureServices(services => + { + services.AddResponseCompression(); + }) + .Configure(app => + { + app.UseResponseCompression(); + app.Run(context => + { + context.Response.ContentType = TextPlain; + return context.Response.WriteAsync(new string('a', 100)); + }); + }); + + Assert.Throws(() => new TestServer(builder)); + } + + [Theory] + [InlineData("text/plain")] + [InlineData("text/PLAIN")] + [InlineData("text/plain; charset=ISO-8859-4")] + [InlineData("text/plain ; charset=ISO-8859-4")] + public async Task ContentType_WithCharset_Compress(string contentType) + { + var builder = new WebHostBuilder() + .ConfigureServices(services => + { + services.AddResponseCompression(TextPlain); + }) + .Configure(app => + { + app.UseResponseCompression(); + app.Run(context => + { + context.Response.ContentType = contentType; + return context.Response.WriteAsync(new string('a', 100)); + }); + }); + + var server = new TestServer(builder); + var client = server.CreateClient(); + + var request = new HttpRequestMessage(HttpMethod.Get, ""); + request.Headers.AcceptEncoding.ParseAdd("gzip"); + + var response = await client.SendAsync(request); + + Assert.Equal(24, response.Content.ReadAsByteArrayAsync().Result.Length); + } + + [Theory] + [InlineData("")] + [InlineData("text/plain2")] + public async Task MimeTypes_OtherContentTypes_NoMatch(string contentType) + { + var builder = new WebHostBuilder() + .ConfigureServices(services => + { + services.AddResponseCompression(TextPlain); + }) + .Configure(app => + { + app.UseResponseCompression(); + app.Run(context => + { + context.Response.ContentType = contentType; + return context.Response.WriteAsync(new string('a', 100)); + }); + }); + + var server = new TestServer(builder); + var client = server.CreateClient(); + + var request = new HttpRequestMessage(HttpMethod.Get, ""); + request.Headers.AcceptEncoding.ParseAdd("gzip"); + + var response = await client.SendAsync(request); + + Assert.Equal(100, response.Content.ReadAsByteArrayAsync().Result.Length); + } + [Fact] public async Task Request_AcceptStar_Compressed() { @@ -134,7 +191,7 @@ namespace Microsoft.AspNetCore.ResponseCompression.Tests } [Fact] - public async Task Response_WithContentEncodingAlreadySet_NotCompressed() + public async Task Response_WithContentEncodingAlreadySet_Stacked() { var otherContentEncoding = "something"; @@ -143,9 +200,9 @@ namespace Microsoft.AspNetCore.ResponseCompression.Tests r.Headers[HeaderNames.ContentEncoding] = otherContentEncoding; }); - Assert.NotNull(response.Headers.GetValues(HeaderNames.ContentMD5)); - Assert.Single(response.Content.Headers.ContentEncoding, otherContentEncoding); - Assert.Equal(50, response.Content.Headers.ContentLength); + Assert.True(response.Content.Headers.ContentEncoding.Contains(otherContentEncoding)); + Assert.True(response.Content.Headers.ContentEncoding.Contains("gzip")); + Assert.Equal(24, response.Content.Headers.ContentLength); } [Theory] @@ -153,52 +210,47 @@ namespace Microsoft.AspNetCore.ResponseCompression.Tests [InlineData(true, 24)] public async Task Request_Https_CompressedIfEnabled(bool enableHttps, int expectedLength) { - var options = new ResponseCompressionOptions() - { - ShouldCompressResponse = _ => true, - Providers = new IResponseCompressionProvider[] + var builder = new WebHostBuilder() + .ConfigureServices(services => { - new GzipResponseCompressionProvider(CompressionLevel.Optimal) - }, - EnableHttps = enableHttps - }; + services.AddResponseCompression(options => + { + options.EnableHttps = enableHttps; + options.MimeTypes = new[] { TextPlain }; + }); + }) + .Configure(app => + { + app.UseResponseCompression(); + app.Run(context => + { + context.Response.ContentType = TextPlain; + return context.Response.WriteAsync(new string('a', 100)); + }); + }); - var middleware = new ResponseCompressionMiddleware(async context => - { - context.Response.ContentType = TextPlain; - await context.Response.WriteAsync(new string('a', 100)); - }, Options.Create(options)); + var server = new TestServer(builder); + server.BaseAddress = new Uri("https://localhost/"); + var client = server.CreateClient(); - var httpContext = new DefaultHttpContext(); - httpContext.Request.Headers[HeaderNames.AcceptEncoding] = "gzip"; - httpContext.Request.IsHttps = true; + var request = new HttpRequestMessage(HttpMethod.Get, ""); + request.Headers.AcceptEncoding.ParseAdd("gzip"); - httpContext.Response.Body = new MemoryStream(); + var response = await client.SendAsync(request); - await middleware.Invoke(httpContext); - - Assert.Equal(expectedLength, httpContext.Response.Body.Length); + Assert.Equal(expectedLength, response.Content.ReadAsByteArrayAsync().Result.Length); } private Task InvokeMiddleware(int uncompressedBodyLength, string[] requestAcceptEncodings, string responseType, Action addResponseAction = null) { - var options = new ResponseCompressionOptions() - { - ShouldCompressResponse = ctx => - { - var contentType = ctx.Response.Headers[HeaderNames.ContentType]; - return contentType.ToString().IndexOf(TextPlain) >= 0; - }, - Providers = new IResponseCompressionProvider[] - { - new GzipResponseCompressionProvider(CompressionLevel.Optimal) - } - }; - var builder = new WebHostBuilder() + .ConfigureServices(services => + { + services.AddResponseCompression(TextPlain); + }) .Configure(app => { - app.UseResponseCompression(options); + app.UseResponseCompression(); app.Run(context => { context.Response.Headers[HeaderNames.ContentMD5] = "MD5"; diff --git a/test/Microsoft.AspNetCore.ResponseCompression.Tests/ResponseCompressionUtilsTest.cs b/test/Microsoft.AspNetCore.ResponseCompression.Tests/ResponseCompressionUtilsTest.cs deleted file mode 100644 index 73fd2caea3..0000000000 --- a/test/Microsoft.AspNetCore.ResponseCompression.Tests/ResponseCompressionUtilsTest.cs +++ /dev/null @@ -1,69 +0,0 @@ -// 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; -using System.Linq; -using Microsoft.AspNetCore.Http; -using Xunit; - -namespace Microsoft.AspNetCore.ResponseCompression.Tests -{ - public class ResponseCompressionUtilsTest - { - private const string TextPlain = "text/plain"; - - [Fact] - public void CreateShouldCompressResponseDelegate_NullMimeTypes_Throws() - { - Assert.Throws(() => - { - ResponseCompressionUtils.CreateShouldCompressResponseDelegate(null); - }); - } - - [Fact] - public void CreateShouldCompressResponseDelegate_Empty_DontCompress() - { - var httpContext = new DefaultHttpContext(); - httpContext.Response.ContentType = TextPlain; - - var func = ResponseCompressionUtils.CreateShouldCompressResponseDelegate(Enumerable.Empty()); - - var result = func(httpContext); - - Assert.False(result); - } - - [Theory] - [InlineData("text/plain")] - [InlineData("text/PLAIN")] - [InlineData("text/plain; charset=ISO-8859-4")] - [InlineData("text/plain ; charset=ISO-8859-4")] - public void CreateShouldCompressResponseDelegate_WithCharset_Compress(string contentType) - { - var httpContext = new DefaultHttpContext(); - httpContext.Response.ContentType = contentType; - - var func = ResponseCompressionUtils.CreateShouldCompressResponseDelegate(new string[] { TextPlain }); - - var result = func(httpContext); - - Assert.True(result); - } - - [Theory] - [InlineData("")] - [InlineData("text/plain2")] - public void CreateShouldCompressResponseDelegate_OtherContentTypes_NoMatch(string contentType) - { - var httpContext = new DefaultHttpContext(); - httpContext.Response.ContentType = contentType; - - var func = ResponseCompressionUtils.CreateShouldCompressResponseDelegate(new string[] { TextPlain }); - - var result = func(httpContext); - - Assert.False(result); - } - } -} From 76256446f55b47d989a1d6443b7ef5e053dfb135 Mon Sep 17 00:00:00 2001 From: Morten Andersen Date: Mon, 3 Oct 2016 19:16:03 +0200 Subject: [PATCH 121/307] Forward custom header names (#102) * Forward custom header names --- .../ForwardedHeadersDefaults.cs | 42 +++++++++++++++++ .../ForwardedHeadersMiddleware.cs | 47 +++++++++++-------- .../ForwardedHeadersOptions.cs | 36 ++++++++++++++ 3 files changed, 106 insertions(+), 19 deletions(-) create mode 100644 src/Microsoft.AspNetCore.HttpOverrides/ForwardedHeadersDefaults.cs diff --git a/src/Microsoft.AspNetCore.HttpOverrides/ForwardedHeadersDefaults.cs b/src/Microsoft.AspNetCore.HttpOverrides/ForwardedHeadersDefaults.cs new file mode 100644 index 0000000000..959dc295d3 --- /dev/null +++ b/src/Microsoft.AspNetCore.HttpOverrides/ForwardedHeadersDefaults.cs @@ -0,0 +1,42 @@ +// 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. + +namespace Microsoft.AspNetCore.HttpOverrides +{ + /// + /// Default values related to middleware + /// + /// + public static class ForwardedHeadersDefaults + { + /// + /// X-Forwarded-For + /// + public static string XForwardedForHeaderName { get; } = "X-Forwarded-For"; + + /// + /// X-Forwarded-Host + /// + public static string XForwardedHostHeaderName { get; } = "X-Forwarded-Host"; + + /// + /// X-Forwarded-Proto + /// + public static string XForwardedProtoHeaderName { get; } = "X-Forwarded-Proto"; + + /// + /// X-Original-For + /// + public static string XOriginalForHeaderName { get; } = "X-Original-For"; + + /// + /// X-Original-Host + /// + public static string XOriginalHostHeaderName { get; } = "X-Original-Host"; + + /// + /// X-Original-Proto + /// + public static string XOriginalProtoHeaderName { get; } = "X-Original-Proto"; + } +} diff --git a/src/Microsoft.AspNetCore.HttpOverrides/ForwardedHeadersMiddleware.cs b/src/Microsoft.AspNetCore.HttpOverrides/ForwardedHeadersMiddleware.cs index 09cdfce9ca..2882dfdf8d 100644 --- a/src/Microsoft.AspNetCore.HttpOverrides/ForwardedHeadersMiddleware.cs +++ b/src/Microsoft.AspNetCore.HttpOverrides/ForwardedHeadersMiddleware.cs @@ -17,13 +17,6 @@ namespace Microsoft.AspNetCore.HttpOverrides { public class ForwardedHeadersMiddleware { - private const string XForwardedForHeaderName = "X-Forwarded-For"; - private const string XForwardedHostHeaderName = "X-Forwarded-Host"; - private const string XForwardedProtoHeaderName = "X-Forwarded-Proto"; - private const string XOriginalForName = "X-Original-For"; - private const string XOriginalHostName = "X-Original-Host"; - private const string XOriginalProtoName = "X-Original-Proto"; - private readonly ForwardedHeadersOptions _options; private readonly RequestDelegate _next; private readonly ILogger _logger; @@ -43,11 +36,27 @@ namespace Microsoft.AspNetCore.HttpOverrides throw new ArgumentNullException(nameof(options)); } + // Make sure required options is not null or whitespace + EnsureOptionNotNullorWhitespace(options.Value.ForwardedForHeaderName, nameof(options.Value.ForwardedForHeaderName)); + EnsureOptionNotNullorWhitespace(options.Value.ForwardedHostHeaderName, nameof(options.Value.ForwardedHostHeaderName)); + EnsureOptionNotNullorWhitespace(options.Value.ForwardedProtoHeaderName, nameof(options.Value.ForwardedProtoHeaderName)); + EnsureOptionNotNullorWhitespace(options.Value.OriginalForHeaderName, nameof(options.Value.OriginalForHeaderName)); + EnsureOptionNotNullorWhitespace(options.Value.OriginalHostHeaderName, nameof(options.Value.OriginalHostHeaderName)); + EnsureOptionNotNullorWhitespace(options.Value.OriginalProtoHeaderName, nameof(options.Value.OriginalProtoHeaderName)); + _options = options.Value; _logger = loggerFactory.CreateLogger(); _next = next; } + private static void EnsureOptionNotNullorWhitespace(string value, string propertyName) + { + if (string.IsNullOrWhiteSpace(value)) + { + throw new ArgumentException($"options.{propertyName} is required", "options"); + } + } + public Task Invoke(HttpContext context) { ApplyForwarders(context); @@ -64,14 +73,14 @@ namespace Microsoft.AspNetCore.HttpOverrides if ((_options.ForwardedHeaders & ForwardedHeaders.XForwardedFor) == ForwardedHeaders.XForwardedFor) { checkFor = true; - forwardedFor = context.Request.Headers.GetCommaSeparatedValues(XForwardedForHeaderName); + forwardedFor = context.Request.Headers.GetCommaSeparatedValues(_options.ForwardedForHeaderName); entryCount = Math.Max(forwardedFor.Length, entryCount); } if ((_options.ForwardedHeaders & ForwardedHeaders.XForwardedProto) == ForwardedHeaders.XForwardedProto) { checkProto = true; - forwardedProto = context.Request.Headers.GetCommaSeparatedValues(XForwardedProtoHeaderName); + forwardedProto = context.Request.Headers.GetCommaSeparatedValues(_options.ForwardedProtoHeaderName); if (_options.RequireHeaderSymmetry && checkFor && forwardedFor.Length != forwardedProto.Length) { _logger.LogWarning(1, "Parameter count mismatch between X-Forwarded-For and X-Forwarded-Proto."); @@ -83,7 +92,7 @@ namespace Microsoft.AspNetCore.HttpOverrides if ((_options.ForwardedHeaders & ForwardedHeaders.XForwardedHost) == ForwardedHeaders.XForwardedHost) { checkHost = true; - forwardedHost = context.Request.Headers.GetCommaSeparatedValues(XForwardedHostHeaderName); + forwardedHost = context.Request.Headers.GetCommaSeparatedValues(_options.ForwardedHostHeaderName); if (_options.RequireHeaderSymmetry && ((checkFor && forwardedFor.Length != forwardedHost.Length) || (checkProto && forwardedProto.Length != forwardedHost.Length))) @@ -198,17 +207,17 @@ namespace Microsoft.AspNetCore.HttpOverrides if (connection.RemoteIpAddress != null) { // Save the original - request.Headers[XOriginalForName] = new IPEndPoint(connection.RemoteIpAddress, connection.RemotePort).ToString(); + request.Headers[_options.OriginalForHeaderName] = new IPEndPoint(connection.RemoteIpAddress, connection.RemotePort).ToString(); } if (forwardedFor.Length > entriesConsumed) { // Truncate the consumed header values - request.Headers[XForwardedForHeaderName] = forwardedFor.Take(forwardedFor.Length - entriesConsumed).ToArray(); + request.Headers[_options.ForwardedForHeaderName] = forwardedFor.Take(forwardedFor.Length - entriesConsumed).ToArray(); } else { // All values were consumed - request.Headers.Remove(XForwardedForHeaderName); + request.Headers.Remove(_options.ForwardedForHeaderName); } connection.RemoteIpAddress = currentValues.RemoteIpAndPort.Address; connection.RemotePort = currentValues.RemoteIpAndPort.Port; @@ -217,16 +226,16 @@ namespace Microsoft.AspNetCore.HttpOverrides if (checkProto && currentValues.Scheme != null) { // Save the original - request.Headers[XOriginalProtoName] = request.Scheme; + request.Headers[_options.OriginalProtoHeaderName] = request.Scheme; if (forwardedProto.Length > entriesConsumed) { // Truncate the consumed header values - request.Headers[XForwardedProtoHeaderName] = forwardedProto.Take(forwardedProto.Length - entriesConsumed).ToArray(); + request.Headers[_options.ForwardedProtoHeaderName] = forwardedProto.Take(forwardedProto.Length - entriesConsumed).ToArray(); } else { // All values were consumed - request.Headers.Remove(XForwardedProtoHeaderName); + request.Headers.Remove(_options.ForwardedProtoHeaderName); } request.Scheme = currentValues.Scheme; } @@ -234,16 +243,16 @@ namespace Microsoft.AspNetCore.HttpOverrides if (checkHost && currentValues.Host != null) { // Save the original - request.Headers[XOriginalHostName] = request.Host.ToString(); + request.Headers[_options.OriginalHostHeaderName] = request.Host.ToString(); if (forwardedHost.Length > entriesConsumed) { // Truncate the consumed header values - request.Headers[XForwardedHostHeaderName] = forwardedHost.Take(forwardedHost.Length - entriesConsumed).ToArray(); + request.Headers[_options.ForwardedHostHeaderName] = forwardedHost.Take(forwardedHost.Length - entriesConsumed).ToArray(); } else { // All values were consumed - request.Headers.Remove(XForwardedHostHeaderName); + request.Headers.Remove(_options.ForwardedHostHeaderName); } request.Host = HostString.FromUriComponent(currentValues.Host); } diff --git a/src/Microsoft.AspNetCore.HttpOverrides/ForwardedHeadersOptions.cs b/src/Microsoft.AspNetCore.HttpOverrides/ForwardedHeadersOptions.cs index 602dd2ec1d..556c8acc3d 100644 --- a/src/Microsoft.AspNetCore.HttpOverrides/ForwardedHeadersOptions.cs +++ b/src/Microsoft.AspNetCore.HttpOverrides/ForwardedHeadersOptions.cs @@ -9,6 +9,42 @@ namespace Microsoft.AspNetCore.Builder { public class ForwardedHeadersOptions { + /// + /// Use this header instead of + /// + /// + public string ForwardedForHeaderName { get; set; } = ForwardedHeadersDefaults.XForwardedForHeaderName; + + /// + /// Use this header instead of + /// + /// + public string ForwardedHostHeaderName { get; set; } = ForwardedHeadersDefaults.XForwardedHostHeaderName; + + /// + /// Use this header instead of + /// + /// + public string ForwardedProtoHeaderName { get; set; } = ForwardedHeadersDefaults.XForwardedProtoHeaderName; + + /// + /// Use this header instead of + /// + /// + public string OriginalForHeaderName { get; set; } = ForwardedHeadersDefaults.XOriginalForHeaderName; + + /// + /// Use this header instead of + /// + /// + public string OriginalHostHeaderName { get; set; } = ForwardedHeadersDefaults.XOriginalHostHeaderName; + + /// + /// Use this header instead of + /// + /// + public string OriginalProtoHeaderName { get; set; } = ForwardedHeadersDefaults.XOriginalProtoHeaderName; + /// /// Identifies which forwarders should be processed. /// From 733c8f77e2c8dca0c0366f1467f1c6460066e774 Mon Sep 17 00:00:00 2001 From: Mikael Mengistu Date: Mon, 3 Oct 2016 16:56:29 -0700 Subject: [PATCH 122/307] Refactoring a lot of tests in the Rewrite project * Removed extra newline --- .../ConditionPatternParserTest.cs | 10 +- .../ApacheModRewrite/FlagParserTest.cs | 6 +- .../ApacheModRewrite/FormatExceptionTests.cs | 2 +- .../ModRewriteMiddlewareTest.cs | 36 ++--- .../ApacheModRewrite/RewriteTokenizerTest.cs | 6 +- .../ApacheModRewrite/RuleRegexParserTest.cs | 2 +- .../ApacheModRewrite/TestStringParserTests.cs | 2 +- .../IISUrlRewrite/FileParserTests.cs | 28 ++-- .../FormatExceptionHandlingTests.cs | 36 ++--- .../IISUrlRewrite/InputParserTests.cs | 12 +- .../IISUrlRewrite/MiddleWareTests.cs | 138 +++++++++--------- .../UrlRewriteApplicationTests.cs | 4 +- .../MiddlewareTests.cs | 7 +- .../PatternSegments/DateTimeSegmentTests.cs | 3 +- .../PatternSegments/IsHttpsModSegmentTests.cs | 2 +- .../RequestMethodSegmentTests.cs | 4 +- .../UrlActions/ForbiddenActionTests.cs | 4 +- .../UrlActions/GoneActionTests.cs | 4 +- .../UrlMatches/ExactMatchTests.cs | 2 +- .../UrlMatches/IntegerMatchTests.cs | 2 +- .../UrlMatches/StringMatchTests.cs | 2 +- 21 files changed, 155 insertions(+), 157 deletions(-) diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/ApacheModRewrite/ConditionPatternParserTest.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/ApacheModRewrite/ConditionPatternParserTest.cs index 99a58c0b88..d9dc2a5cf8 100644 --- a/test/Microsoft.AspNetCore.Rewrite.Tests/ApacheModRewrite/ConditionPatternParserTest.cs +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/ApacheModRewrite/ConditionPatternParserTest.cs @@ -20,7 +20,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.ModRewrite var results = new ConditionPatternParser().ParseActionCondition(condition); var expected = new ParsedModRewriteInput { OperationType = operation, ConditionType = conditionType, Operand = variable, Invert = false }; - Assert.True(CompareConditions(results, expected)); + Assert.True(CompareConditions(expected, results)); } [Fact] @@ -30,7 +30,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.ModRewrite var results = new ConditionPatternParser().ParseActionCondition(condition); var expected = new ParsedModRewriteInput { ConditionType = ConditionType.Regex, Operand = "(.*)", Invert = false }; - Assert.True(CompareConditions(results, expected)); + Assert.True(CompareConditions(expected, results)); } [Theory] @@ -48,7 +48,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.ModRewrite var results = new ConditionPatternParser().ParseActionCondition(condition); var expected = new ParsedModRewriteInput { ConditionType = cond, OperationType = operation, Invert = false }; - Assert.True(CompareConditions(results, expected)); + Assert.True(CompareConditions(expected, results)); } [Theory] @@ -66,7 +66,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.ModRewrite var results = new ConditionPatternParser().ParseActionCondition(condition); var expected = new ParsedModRewriteInput { ConditionType = cond, OperationType = operation, Invert = true }; - Assert.True(CompareConditions(results, expected)); + Assert.True(CompareConditions(expected, results)); } [Theory] @@ -81,7 +81,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.ModRewrite var results = new ConditionPatternParser().ParseActionCondition(condition); var expected = new ParsedModRewriteInput { ConditionType = cond, OperationType = operation, Invert = false, Operand = variable }; - Assert.True(CompareConditions(results, expected)); + Assert.True(CompareConditions(expected, results)); } [Theory] diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/ApacheModRewrite/FlagParserTest.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/ApacheModRewrite/FlagParserTest.cs index 8270bc07cc..8f8d0cf7a8 100644 --- a/test/Microsoft.AspNetCore.Rewrite.Tests/ApacheModRewrite/FlagParserTest.cs +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/ApacheModRewrite/FlagParserTest.cs @@ -19,7 +19,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.ModRewrite dict.Add(FlagType.NoCase, string.Empty); var expected = new Flags(dict); - Assert.True(DictionaryContentsEqual(results.FlagDictionary, expected.FlagDictionary)); + Assert.True(DictionaryContentsEqual(expected.FlagDictionary, results.FlagDictionary)); } [Fact] @@ -32,7 +32,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.ModRewrite dict.Add(FlagType.Last, string.Empty); var expected = new Flags(dict); - Assert.True(DictionaryContentsEqual(results.FlagDictionary, expected.FlagDictionary)); + Assert.True(DictionaryContentsEqual(expected.FlagDictionary, results.FlagDictionary)); } [Fact] @@ -45,7 +45,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.ModRewrite dict.Add(FlagType.Redirect, "301"); var expected = new Flags(dict); - Assert.True(DictionaryContentsEqual(results.FlagDictionary, expected.FlagDictionary)); + Assert.True(DictionaryContentsEqual(expected.FlagDictionary, results.FlagDictionary)); } [Theory] diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/ApacheModRewrite/FormatExceptionTests.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/ApacheModRewrite/FormatExceptionTests.cs index acf46b3765..20db752b1f 100644 --- a/test/Microsoft.AspNetCore.Rewrite.Tests/ApacheModRewrite/FormatExceptionTests.cs +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/ApacheModRewrite/FormatExceptionTests.cs @@ -32,7 +32,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.ModRewrite { // Arrange, Act, Assert var ex = Assert.Throws(() => new FileParser().Parse(new StringReader(input))); - Assert.Equal(ex.Message, expected); + Assert.Equal(expected, ex.Message); } } } diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/ApacheModRewrite/ModRewriteMiddlewareTest.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/ApacheModRewrite/ModRewriteMiddlewareTest.cs index 0c3b943636..bf0669ce26 100644 --- a/test/Microsoft.AspNetCore.Rewrite.Tests/ApacheModRewrite/ModRewriteMiddlewareTest.cs +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/ApacheModRewrite/ModRewriteMiddlewareTest.cs @@ -17,7 +17,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.ModRewrite { [Fact] public async Task Invoke_RewritePathWhenMatching() - { + { var options = new RewriteOptions().AddApacheModRewrite(new StringReader("RewriteRule /hey/(.*) /$1 ")); var builder = new WebHostBuilder() .Configure(app => @@ -29,7 +29,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.ModRewrite var response = await server.CreateClient().GetStringAsync("/hey/hello"); - Assert.Equal(response, "/hello"); + Assert.Equal("/hello", response); } [Fact] @@ -47,7 +47,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.ModRewrite var response = await server.CreateClient().GetStringAsync("/hey/hello"); - Assert.Equal(response, "/hello"); + Assert.Equal("/hello", response); } [Fact] @@ -65,7 +65,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.ModRewrite var response = await server.CreateClient().GetStringAsync("/hey/hello"); - Assert.Equal(response, "/what"); + Assert.Equal("/what", response); } [Fact] @@ -82,9 +82,9 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.ModRewrite var response = await server.CreateClient().GetStringAsync("/hey/hello"); - Assert.Equal(response, "/hey/hello"); + Assert.Equal("/hey/hello", response); } - + [Fact] public async Task Invoke_ShouldRewriteHomepage() { @@ -99,7 +99,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.ModRewrite var response = await server.CreateClient().GetStringAsync("http://www.foo.org/"); - Assert.Equal(response, "/homepage.html"); + Assert.Equal("/homepage.html", response); } [Fact] @@ -116,7 +116,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.ModRewrite var response = await server.CreateClient().GetStringAsync("http://www.foo.org:42/"); - Assert.Equal(response, "/homepage.html"); + Assert.Equal("/homepage.html", response); } [Fact] @@ -133,7 +133,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.ModRewrite var response = await server.CreateClient().GetStringAsync("http://www.foo.org/"); - Assert.Equal(response, "/"); + Assert.Equal("/", response); } [Fact] @@ -150,7 +150,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.ModRewrite var response = await server.CreateClient().GetStringAsync("http://www.foo.org/homepage.aspx"); - Assert.Equal(response, "/homepage.php"); + Assert.Equal("/homepage.php", response); } [Theory] @@ -173,7 +173,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.ModRewrite var response = await server.CreateClient().GetStringAsync(url); - Assert.Equal(response, expected); + Assert.Equal(expected, response); } [Fact] @@ -191,7 +191,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.ModRewrite var response = await server.CreateClient().GetStringAsync("http://www.foo.org/blog/2016-jun"); - Assert.Equal(response, @"/blog/2016-jun/"); + Assert.Equal(@"/blog/2016-jun/", response); } [Fact] @@ -209,7 +209,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.ModRewrite var response = await server.CreateClient().GetStringAsync("http://www.foo.org/blog/2016-jun"); - Assert.Equal(response, @"http://www.example.com/blog/2016-jun/"); + Assert.Equal(@"http://www.example.com/blog/2016-jun/", response); } [Fact] @@ -227,7 +227,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.ModRewrite var response = await server.CreateClient().GetStringAsync("http://www.foo.org/blog/2016-jun"); - Assert.Equal(response, @"http://www.example.com/blog/2016-jun/"); + Assert.Equal(@"http://www.example.com/blog/2016-jun/", response); } [Theory] @@ -266,8 +266,8 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.ModRewrite var response = await server.CreateClient().GetAsync(input); - Assert.Equal(response.StatusCode, (HttpStatusCode)301); - Assert.Equal(response.Headers.Location.OriginalString, "/"); + Assert.Equal(HttpStatusCode.MovedPermanently, response.StatusCode); + Assert.Equal("/", response.Headers.Location.OriginalString); } [Theory] @@ -285,7 +285,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.ModRewrite var server = new TestServer(builder); var response = await server.CreateClient().GetStringAsync(input); - Assert.Equal(response, "/"); + Assert.Equal("/", response); } [Fact] @@ -304,7 +304,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.ModRewrite var response = await server.CreateClient().GetAsync(""); - Assert.Equal(response.Headers.Location.OriginalString, "/foo"); + Assert.Equal("/foo", response.Headers.Location.OriginalString); } } } diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/ApacheModRewrite/RewriteTokenizerTest.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/ApacheModRewrite/RewriteTokenizerTest.cs index 98e556df50..04a7071d7b 100644 --- a/test/Microsoft.AspNetCore.Rewrite.Tests/ApacheModRewrite/RewriteTokenizerTest.cs +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/ApacheModRewrite/RewriteTokenizerTest.cs @@ -20,7 +20,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.ModRewrite expected.Add("RewriteCond"); expected.Add("%{HTTPS}"); expected.Add("!-f"); - Assert.Equal(tokens, expected); + Assert.Equal(expected, tokens); } [Fact] @@ -33,7 +33,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.ModRewrite expected.Add("RewriteCond"); expected.Add(@"%{HTTPS} what"); expected.Add("!-f"); - Assert.Equal(tokens, expected); + Assert.Equal(expected, tokens); } [Fact] @@ -47,7 +47,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.ModRewrite expected.Add(@"%{HTTPS}"); expected.Add(@" what"); expected.Add(@"!-f"); - Assert.Equal(tokens, expected); + Assert.Equal(expected, tokens); } [Fact] diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/ApacheModRewrite/RuleRegexParserTest.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/ApacheModRewrite/RuleRegexParserTest.cs index fefc5f2b2e..20f54abba5 100644 --- a/test/Microsoft.AspNetCore.Rewrite.Tests/ApacheModRewrite/RuleRegexParserTest.cs +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/ApacheModRewrite/RuleRegexParserTest.cs @@ -26,7 +26,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.ModRewrite { var results = new RuleRegexParser().ParseRuleRegex("(.*)"); Assert.False(results.Invert); - Assert.Equal(results.Operand, "(.*)"); + Assert.Equal("(.*)", results.Operand); } } } diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/ApacheModRewrite/TestStringParserTests.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/ApacheModRewrite/TestStringParserTests.cs index 917e628040..eafb814ab1 100644 --- a/test/Microsoft.AspNetCore.Rewrite.Tests/ApacheModRewrite/TestStringParserTests.cs +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/ApacheModRewrite/TestStringParserTests.cs @@ -122,7 +122,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.ModRewrite public void ConditionParser_InvalidInput(string testString, string expected) { var ex = Assert.Throws(() => new TestStringParser().Parse(testString)); - Assert.Equal(ex.Message, expected); + Assert.Equal(expected, ex.Message); } private void AssertPatternsEqual(Pattern p1, Pattern p2) diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/FileParserTests.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/FileParserTests.cs index b891b3a2c5..dd55225c2b 100644 --- a/test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/FileParserTests.cs +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/FileParserTests.cs @@ -39,7 +39,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite var res = new UrlRewriteFileParser().Parse(new StringReader(xml)); // assert - AssertUrlRewriteRuleEquality(res, expected); + AssertUrlRewriteRuleEquality(expected, res); } [Fact] @@ -50,9 +50,9 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite - - - + + + @@ -76,7 +76,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite var res = new UrlRewriteFileParser().Parse(new StringReader(xml)); // assert - AssertUrlRewriteRuleEquality(res, expected); + AssertUrlRewriteRuleEquality(expected, res); } [Fact] @@ -87,16 +87,16 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite - - - + + + - - - + + + @@ -125,7 +125,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite var res = new UrlRewriteFileParser().Parse(new StringReader(xml)); // assert - AssertUrlRewriteRuleEquality(res, expected); + AssertUrlRewriteRuleEquality(expected, res); } // Creates a rule with appropriate default values of the url rewrite rule. @@ -163,11 +163,11 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite if (r1.Conditions == null) { - Assert.Equal(r2.Conditions.Count, 0); + Assert.Equal(0, r2.Conditions.Count); } else if (r2.Conditions == null) { - Assert.Equal(r1.Conditions.Count, 0); + Assert.Equal(0, r1.Conditions.Count); } else { diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/FormatExceptionHandlingTests.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/FormatExceptionHandlingTests.cs index 3b77f78290..6398da1e95 100644 --- a/test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/FormatExceptionHandlingTests.cs +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/FormatExceptionHandlingTests.cs @@ -27,7 +27,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite -", +", "Could not parse the UrlRewrite file. Message: 'Missing close brace for parameter at string index: '1''. Line number '5': '14'.")] [InlineData( @" @@ -37,16 +37,16 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite -", +", "Could not parse the UrlRewrite file. Message: 'Match must have Url Attribute'. Line number '4': '14'.")] [InlineData( @" - - - + + + @@ -57,39 +57,39 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite - - - + + + -", +", "Could not parse the UrlRewrite file. Message: 'Conditions must have an input attribute'. Line number '6': '18'.")] [InlineData( @" - - - + + + -", +", "Could not parse the UrlRewrite file. Message: 'Match does not have an associated pattern attribute in condition'. Line number '6': '18'.")] [InlineData( @" - - - + + + -", +", "Could not parse the UrlRewrite file. Message: 'Match does not have an associated pattern attribute in condition'. Line number '6': '18'.")] [InlineData( @" @@ -105,7 +105,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite { // Arrange, Act, Assert var ex = Assert.Throws(() => new UrlRewriteFileParser().Parse(new StringReader(input))); - Assert.Equal(ex.Message, expected); + Assert.Equal(expected, ex.Message); } } } diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/InputParserTests.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/InputParserTests.cs index 29299a9287..df59ae4596 100644 --- a/test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/InputParserTests.cs +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/InputParserTests.cs @@ -17,7 +17,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite { var testString = "hello/hey/what"; var result = new InputParser().ParseInputString(testString); - Assert.Equal(result.PatternSegments.Count, 1); + Assert.Equal(1, result.PatternSegments.Count); } [Theory] @@ -29,7 +29,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite public void InputParser_ParseStringWithBackReference(string testString, int expected) { var result = new InputParser().ParseInputString(testString); - Assert.Equal(result.PatternSegments.Count, expected); + Assert.Equal(expected, result.PatternSegments.Count); } // Test actual evaluation of the types, verifying the correct string comes from the evalation @@ -46,9 +46,9 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite { var middle = new InputParser().ParseInputString(testString); var result = middle.Evaluate(CreateTestRewriteContext(), CreateTestRuleMatch(), CreateTestCondMatch()); - Assert.Equal(result, expected); + Assert.Equal(expected, result); } - + [Theory] [InlineData("hey/{ToLower:HEY}", "hey/hey")] [InlineData("hey/{ToLower:{R:1}}", "hey/foo")] @@ -59,7 +59,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite { var middle = new InputParser().ParseInputString(testString); var result = middle.Evaluate(CreateTestRewriteContext(), CreateTestRuleMatch(), CreateTestCondMatch()); - Assert.Equal(result, expected); + Assert.Equal(expected, result); } [Theory] @@ -68,7 +68,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite { var middle = new InputParser().ParseInputString(testString); var result = middle.Evaluate(CreateTestRewriteContext(), CreateTestRuleMatch(), CreateTestCondMatch()); - Assert.Equal(result, expected); + Assert.Equal(expected, result); } [Theory] diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/MiddleWareTests.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/MiddleWareTests.cs index dcc7cb98c4..e18f0325c1 100644 --- a/test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/MiddleWareTests.cs +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/MiddleWareTests.cs @@ -36,7 +36,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite var response = await server.CreateClient().GetAsync("article/10/hey"); - Assert.Equal(response.Headers.Location.OriginalString, "/article.aspx?id=10&title=hey"); + Assert.Equal("/article.aspx?id=10&title=hey", response.Headers.Location.OriginalString); } [Fact] @@ -60,7 +60,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite var response = await server.CreateClient().GetStringAsync("/article/10/hey"); - Assert.Equal(response, "/article.aspx?id=10&title=hey"); + Assert.Equal("/article.aspx?id=10&title=hey", response); } [Fact] @@ -68,14 +68,14 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite { var options = new RewriteOptions().AddIISUrlRewrite(new StringReader(@" - - - - - - - - + + + + + + + + ")); var builder = new WebHostBuilder() @@ -88,7 +88,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite var response = await server.CreateClient().GetStringAsync("page.asp?p2=321&p1=123"); - Assert.Equal(response, "/newpage.aspx?param1=123¶m2=321"); + Assert.Equal("/newpage.aspx?param1=123¶m2=321", response); } [Fact] @@ -96,10 +96,10 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite { var options = new RewriteOptions().AddIISUrlRewrite(new StringReader(@" - - - - + + + + ")); var builder = new WebHostBuilder() @@ -112,7 +112,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite var response = await server.CreateClient().GetAsync("HElLo"); - Assert.Equal(response.Headers.Location.OriginalString, "/hello"); + Assert.Equal("/hello", response.Headers.Location.OriginalString); } [Fact] @@ -120,14 +120,14 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite { var options = new RewriteOptions().AddIISUrlRewrite(new StringReader(@" - - - - - - - - + + + + + + + + ")); var builder = new WebHostBuilder() @@ -139,7 +139,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite var response = await server.CreateClient().GetAsync("hey/hello/"); - Assert.Equal(response.Headers.Location.OriginalString, "/hey/hello"); + Assert.Equal("/hey/hello", response.Headers.Location.OriginalString); } [Fact] @@ -147,14 +147,14 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite { var options = new RewriteOptions().AddIISUrlRewrite(new StringReader(@" - - - - - - - - + + + + + + + + ")); var builder = new WebHostBuilder() @@ -166,7 +166,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite var response = await server.CreateClient().GetAsync("hey/hello"); - Assert.Equal(response.Headers.Location.OriginalString, "/hey/hello/"); + Assert.Equal("/hey/hello/", response.Headers.Location.OriginalString); } [Fact] @@ -174,13 +174,13 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite { var options = new RewriteOptions().AddIISUrlRewrite(new StringReader(@" - - - - - - - + + + + + + + ")); var builder = new WebHostBuilder() @@ -192,7 +192,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite var response = await server.CreateClient().GetAsync(new Uri("http://example.com")); - Assert.Equal(response.Headers.Location.OriginalString, "https://example.com/"); + Assert.Equal("https://example.com/", response.Headers.Location.OriginalString); } [Fact] @@ -200,13 +200,13 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite { var options = new RewriteOptions().AddIISUrlRewrite(new StringReader(@" - - - - - - - + + + + + + + ")); var builder = new WebHostBuilder() @@ -224,7 +224,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite var response = await server.CreateClient().GetStringAsync(new Uri("http://example.com")); - Assert.Equal(response, "https://example.com/"); + Assert.Equal("https://example.com/", response); } [Fact] @@ -232,10 +232,10 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite { var options = new RewriteOptions().AddIISUrlRewrite(new StringReader(@" - - - - + + + + ")); var builder = new WebHostBuilder() @@ -253,7 +253,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite var response = await server.CreateClient().GetStringAsync(new Uri("http://example.com/")); - Assert.Equal(response, "http://internalserver/"); + Assert.Equal("http://internalserver/", response); } [Fact] @@ -261,10 +261,10 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite { var options = new RewriteOptions().AddIISUrlRewrite(new StringReader(@" - - - - + + + + ")); var builder = new WebHostBuilder() @@ -282,7 +282,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite var response = await server.CreateClient().GetAsync(new Uri("http://example.com/")); - Assert.Equal(response.Headers.Location.OriginalString, "/"); + Assert.Equal("/", response.Headers.Location.OriginalString); } [Fact] @@ -290,10 +290,10 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite { var options = new RewriteOptions().AddIISUrlRewrite(new StringReader(@" - - - - + + + + ")); var builder = new WebHostBuilder() @@ -308,7 +308,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite var response = await server.CreateClient().GetStringAsync(new Uri("http://example.com/")); - Assert.Equal(response, "/"); + Assert.Equal("/", response); } [Fact] @@ -316,10 +316,10 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite { var options = new RewriteOptions().AddIISUrlRewrite(new StringReader(@" - - - - + + + + ")); var builder = new WebHostBuilder() diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/UrlRewriteApplicationTests.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/UrlRewriteApplicationTests.cs index 83958e6c99..87fcfdbae0 100644 --- a/test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/UrlRewriteApplicationTests.cs +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/UrlRewriteApplicationTests.cs @@ -28,7 +28,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite Assert.Equal(rules.Count, 1); var context = new RewriteContext { HttpContext = new DefaultHttpContext() }; rules.FirstOrDefault().ApplyRule(context); - Assert.Equal(context.Result, RuleResult.SkipRemainingRules); + Assert.Equal(RuleResult.SkipRemainingRules, context.Result); } [Fact] @@ -47,7 +47,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite Assert.Equal(rules.Count, 1); var context = new RewriteContext { HttpContext = new DefaultHttpContext() }; rules.FirstOrDefault().ApplyRule(context); - Assert.Equal(context.Result, RuleResult.ContinueRules); + Assert.Equal(RuleResult.ContinueRules, context.Result); } } } diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/MiddlewareTests.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/MiddlewareTests.cs index 67802e031f..ce041ff52c 100644 --- a/test/Microsoft.AspNetCore.Rewrite.Tests/MiddlewareTests.cs +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/MiddlewareTests.cs @@ -20,7 +20,6 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.CodeRules var builder = new WebHostBuilder() .Configure(app => { - app.UseRewriter(options); app.UseRewriter(options); app.Run(context => context.Response.WriteAsync( context.Request.Scheme + @@ -33,7 +32,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.CodeRules var response = await server.CreateClient().GetStringAsync("foo"); - Assert.Equal(response, "http://example.com/foo"); + Assert.Equal("http://example.com/foo", response); } [Fact] @@ -49,7 +48,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.CodeRules var response = await server.CreateClient().GetAsync("foo"); - Assert.Equal(response.Headers.Location.OriginalString, "http://example.com/foo"); + Assert.Equal("http://example.com/foo", response.Headers.Location.OriginalString); } [Fact] @@ -65,7 +64,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.CodeRules var response = await server.CreateClient().GetAsync(new Uri("http://example.com")); - Assert.Equal(response.Headers.Location.OriginalString, "https://example.com/"); + Assert.Equal("https://example.com/", response.Headers.Location.OriginalString); } diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/PatternSegments/DateTimeSegmentTests.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/PatternSegments/DateTimeSegmentTests.cs index 9e478da8e4..8f5ef184a8 100644 --- a/test/Microsoft.AspNetCore.Rewrite.Tests/PatternSegments/DateTimeSegmentTests.cs +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/PatternSegments/DateTimeSegmentTests.cs @@ -35,10 +35,9 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.PatternSegments [InlineData("wow", "Unsupported segment: 'wow'")] public void DateTime_AssertThrowsOnInvalidInput(string input, string expected) { - // Act And Assert var ex = Assert.Throws(() => new DateTimeSegment(input)); - Assert.Equal(ex.Message, expected); + Assert.Equal(expected, ex.Message); } } } diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/PatternSegments/IsHttpsModSegmentTests.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/PatternSegments/IsHttpsModSegmentTests.cs index 323f3198b4..b578b31bac 100644 --- a/test/Microsoft.AspNetCore.Rewrite.Tests/PatternSegments/IsHttpsModSegmentTests.cs +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/PatternSegments/IsHttpsModSegmentTests.cs @@ -22,7 +22,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.PatternSegments // Act var results = segement.Evaluate(context, null, null); - + // Assert Assert.Equal(expected, results); } diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/PatternSegments/RequestMethodSegmentTests.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/PatternSegments/RequestMethodSegmentTests.cs index fc9ac14b01..0fa65a8182 100644 --- a/test/Microsoft.AspNetCore.Rewrite.Tests/PatternSegments/RequestMethodSegmentTests.cs +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/PatternSegments/RequestMethodSegmentTests.cs @@ -15,12 +15,12 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.PatternSegments // Arrange var segement = new RequestMethodSegment(); var context = new RewriteContext { HttpContext = new DefaultHttpContext() }; - context.HttpContext.Request.Method = "GET"; + context.HttpContext.Request.Method = HttpMethods.Get; // Act var results = segement.Evaluate(context, null, null); // Assert - Assert.Equal("GET", results); + Assert.Equal(HttpMethods.Get, results); } } } diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/UrlActions/ForbiddenActionTests.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/UrlActions/ForbiddenActionTests.cs index 0ab9a6f439..b15354b672 100644 --- a/test/Microsoft.AspNetCore.Rewrite.Tests/UrlActions/ForbiddenActionTests.cs +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/UrlActions/ForbiddenActionTests.cs @@ -18,8 +18,8 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlActions action.ApplyAction(context, null, null); - Assert.Equal(context.Result, RuleResult.EndResponse); - Assert.Equal(context.HttpContext.Response.StatusCode, StatusCodes.Status403Forbidden); + Assert.Equal(RuleResult.EndResponse, context.Result); + Assert.Equal(StatusCodes.Status403Forbidden, context.HttpContext.Response.StatusCode); } } } diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/UrlActions/GoneActionTests.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/UrlActions/GoneActionTests.cs index 1a18fe7d19..00720f85ef 100644 --- a/test/Microsoft.AspNetCore.Rewrite.Tests/UrlActions/GoneActionTests.cs +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/UrlActions/GoneActionTests.cs @@ -17,8 +17,8 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlActions action.ApplyAction(context, null, null); - Assert.Equal(context.Result, RuleResult.EndResponse); - Assert.Equal(context.HttpContext.Response.StatusCode, StatusCodes.Status410Gone); + Assert.Equal(RuleResult.EndResponse, context.Result); + Assert.Equal(StatusCodes.Status410Gone, context.HttpContext.Response.StatusCode); } } } diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/UrlMatches/ExactMatchTests.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/UrlMatches/ExactMatchTests.cs index 9b85354adc..7f7e82b9b2 100644 --- a/test/Microsoft.AspNetCore.Rewrite.Tests/UrlMatches/ExactMatchTests.cs +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/UrlMatches/ExactMatchTests.cs @@ -21,7 +21,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlMatches var context = new RewriteContext { HttpContext = new DefaultHttpContext() }; var Match = new ExactMatch(ignoreCase, inputString, negate); var matchResults = Match.Evaluate(pattern, context); - Assert.Equal(matchResults.Success, expectedResult); + Assert.Equal(expectedResult, matchResults.Success); } } } diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/UrlMatches/IntegerMatchTests.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/UrlMatches/IntegerMatchTests.cs index bb7408d9f6..5dd87ca4ad 100644 --- a/test/Microsoft.AspNetCore.Rewrite.Tests/UrlMatches/IntegerMatchTests.cs +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/UrlMatches/IntegerMatchTests.cs @@ -35,7 +35,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlMatches var context = new RewriteContext { HttpContext = new DefaultHttpContext() }; var integerMatch = new IntegerMatch(value, operation); var matchResult = integerMatch.Evaluate(input, context); - Assert.Equal(matchResult.Success, expectedResult); + Assert.Equal(expectedResult, matchResult.Success); } } } diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/UrlMatches/StringMatchTests.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/UrlMatches/StringMatchTests.cs index 0cd62e1f91..a562fec6e2 100644 --- a/test/Microsoft.AspNetCore.Rewrite.Tests/UrlMatches/StringMatchTests.cs +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/UrlMatches/StringMatchTests.cs @@ -23,7 +23,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlMatches var context = new RewriteContext { HttpContext = new DefaultHttpContext() }; var stringMatch = new StringMatch(value, operation, ignoreCase); var matchResult = stringMatch.Evaluate(input, context); - Assert.Equal(matchResult.Success, expectedResult); + Assert.Equal(expectedResult, matchResult.Success); } } } From 7be02fa146bd85e7a764dda9b69e863a09e8e2c6 Mon Sep 17 00:00:00 2001 From: Pranav K Date: Tue, 27 Sep 2016 16:02:38 -0700 Subject: [PATCH 123/307] Updating partner package versions --- samples/HttpOverridesSample/project.json | 2 +- samples/ResponseBufferingSample/project.json | 2 +- .../ResponseCompressionSample/project.json | 54 +++++++++---------- samples/RewriteSample/project.json | 6 +-- .../project.json | 3 +- .../project.json | 3 +- .../project.json | 53 +++++++++--------- src/Microsoft.AspNetCore.Rewrite/project.json | 10 ++-- .../project.json | 2 +- .../project.json | 2 +- .../project.json | 46 ++++++++-------- .../project.json | 4 +- 12 files changed, 91 insertions(+), 96 deletions(-) diff --git a/samples/HttpOverridesSample/project.json b/samples/HttpOverridesSample/project.json index db91d8d16f..9c93a8e1c0 100644 --- a/samples/HttpOverridesSample/project.json +++ b/samples/HttpOverridesSample/project.json @@ -21,7 +21,7 @@ "netcoreapp1.0": { "dependencies": { "Microsoft.NETCore.App": { - "version": "1.0.0-*", + "version": "1.1.0-*", "type": "platform" } } diff --git a/samples/ResponseBufferingSample/project.json b/samples/ResponseBufferingSample/project.json index e3c674f864..d48a3acd1e 100644 --- a/samples/ResponseBufferingSample/project.json +++ b/samples/ResponseBufferingSample/project.json @@ -12,7 +12,7 @@ "netcoreapp1.0": { "dependencies": { "Microsoft.NETCore.App": { - "version": "1.0.0-*", + "version": "1.1.0-*", "type": "platform" } } diff --git a/samples/ResponseCompressionSample/project.json b/samples/ResponseCompressionSample/project.json index 0ad34fd2b2..24f85c5aae 100644 --- a/samples/ResponseCompressionSample/project.json +++ b/samples/ResponseCompressionSample/project.json @@ -1,29 +1,29 @@ -{ - "dependencies": { - "Microsoft.AspNetCore.ResponseCompression": "0.1.0-*", - "Microsoft.AspNetCore.Server.Kestrel": "1.1.0-*" - }, - "buildOptions": { - "emitEntryPoint": true - }, - "frameworks": { - "net451": {}, - "netcoreapp1.0": { - "dependencies": { - "Microsoft.NETCore.App": { - "version": "1.0.0-*", - "type": "platform" - } - } +{ + "dependencies": { + "Microsoft.AspNetCore.ResponseCompression": "0.1.0-*", + "Microsoft.AspNetCore.Server.Kestrel": "1.1.0-*" + }, + "buildOptions": { + "emitEntryPoint": true + }, + "frameworks": { + "net451": {}, + "netcoreapp1.0": { + "dependencies": { + "Microsoft.NETCore.App": { + "version": "1.1.0-*", + "type": "platform" } - }, - "publish": { - "exclude": [ - "node_modules", - "bower_components", - "**.xproj", - "**.user", - "**.vspscc" - ] + } } -} + }, + "publish": { + "exclude": [ + "node_modules", + "bower_components", + "**.xproj", + "**.user", + "**.vspscc" + ] + } +} \ No newline at end of file diff --git a/samples/RewriteSample/project.json b/samples/RewriteSample/project.json index c34d3bd910..c70f27ff4e 100644 --- a/samples/RewriteSample/project.json +++ b/samples/RewriteSample/project.json @@ -1,4 +1,4 @@ -{ +{ "version": "1.1.0-*", "dependencies": { "Microsoft.AspNetCore.Rewrite": "1.1.0-*", @@ -14,7 +14,7 @@ "netcoreapp1.0": { "dependencies": { "Microsoft.NETCore.App": { - "version": "1.0.0-*", + "version": "1.1.0-*", "type": "platform" } } @@ -29,4 +29,4 @@ "**.vspscc" ] } -} +} \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Buffering/project.json b/src/Microsoft.AspNetCore.Buffering/project.json index fa9d8bf0ad..6e2f2da65a 100644 --- a/src/Microsoft.AspNetCore.Buffering/project.json +++ b/src/Microsoft.AspNetCore.Buffering/project.json @@ -25,7 +25,8 @@ "Microsoft.Extensions.TaskCache.Sources": { "version": "1.1.0-*", "type": "build" - } + }, + "NETStandard.Library": "1.6.1-*" }, "frameworks": { "net451": {}, diff --git a/src/Microsoft.AspNetCore.HttpOverrides/project.json b/src/Microsoft.AspNetCore.HttpOverrides/project.json index 6205811116..fd3441eefc 100644 --- a/src/Microsoft.AspNetCore.HttpOverrides/project.json +++ b/src/Microsoft.AspNetCore.HttpOverrides/project.json @@ -24,7 +24,8 @@ "dependencies": { "Microsoft.AspNetCore.Http.Extensions": "1.1.0-*", "Microsoft.Extensions.Logging.Abstractions": "1.1.0-*", - "Microsoft.Extensions.Options": "1.1.0-*" + "Microsoft.Extensions.Options": "1.1.0-*", + "NETStandard.Library": "1.6.1-*" }, "frameworks": { "net451": {}, diff --git a/src/Microsoft.AspNetCore.ResponseCompression/project.json b/src/Microsoft.AspNetCore.ResponseCompression/project.json index effe3df4a6..3cea610ec4 100644 --- a/src/Microsoft.AspNetCore.ResponseCompression/project.json +++ b/src/Microsoft.AspNetCore.ResponseCompression/project.json @@ -1,31 +1,28 @@ { - "version": "0.1.0-*", - "buildOptions": { - "warningsAsErrors": true, - "keyFile": "../../tools/Key.snk", - "xmlDoc": true + "version": "0.1.0-*", + "buildOptions": { + "warningsAsErrors": true, + "keyFile": "../../tools/Key.snk", + "xmlDoc": true + }, + "description": "ASP.NET Core middleware for HTTP Response compression.", + "packOptions": { + "repository": { + "type": "git", + "url": "git://github.com/aspnet/basicmiddleware" }, - "description": "ASP.NET Core middleware for HTTP Response compression.", - "packOptions": { - "repository": { - "type": "git", - "url": "git://github.com/aspnet/basicmiddleware" - }, - "tags": [ - "aspnetcore" - ] - }, - "dependencies": { - "Microsoft.AspNetCore.Http.Abstractions": "1.1.0-*", - "Microsoft.Extensions.Options": "1.1.0-*", - "Microsoft.Net.Http.Headers": "1.1.0-*" - }, - "frameworks": { - "net451": {}, - "netstandard1.3": { - "dependencies": { - "System.IO.Compression": "4.1.0-*" - } - } - } + "tags": [ + "aspnetcore" + ] + }, + "dependencies": { + "Microsoft.AspNetCore.Http.Abstractions": "1.1.0-*", + "Microsoft.Extensions.Options": "1.1.0-*", + "Microsoft.Net.Http.Headers": "1.1.0-*", + "NETStandard.Library": "1.6.1-*" + }, + "frameworks": { + "net451": {}, + "netstandard1.3": {} + } } \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Rewrite/project.json b/src/Microsoft.AspNetCore.Rewrite/project.json index b88732b107..3b852df223 100644 --- a/src/Microsoft.AspNetCore.Rewrite/project.json +++ b/src/Microsoft.AspNetCore.Rewrite/project.json @@ -30,7 +30,8 @@ "Microsoft.Extensions.TaskCache.Sources": { "version": "1.1.0-*", "type": "build" - } + }, + "NETStandard.Library": "1.6.1-*" }, "frameworks": { "net451": { @@ -39,11 +40,6 @@ "System.Xml.Linq": "" } }, - "netstandard1.3": { - "dependencies": { - "System.Text.RegularExpressions": "4.1.0-*", - "System.Xml.XDocument": "4.0.11-*" - } - } + "netstandard1.3": {} } } \ No newline at end of file diff --git a/test/Microsoft.AspNetCore.Buffering.Tests/project.json b/test/Microsoft.AspNetCore.Buffering.Tests/project.json index 47d0f4fab0..feaf435f3f 100644 --- a/test/Microsoft.AspNetCore.Buffering.Tests/project.json +++ b/test/Microsoft.AspNetCore.Buffering.Tests/project.json @@ -13,7 +13,7 @@ "netcoreapp1.0": { "dependencies": { "Microsoft.NETCore.App": { - "version": "1.0.0-*", + "version": "1.1.0-*", "type": "platform" } } diff --git a/test/Microsoft.AspNetCore.HttpOverrides.Tests/project.json b/test/Microsoft.AspNetCore.HttpOverrides.Tests/project.json index 9ee14135a2..e738c8d56f 100644 --- a/test/Microsoft.AspNetCore.HttpOverrides.Tests/project.json +++ b/test/Microsoft.AspNetCore.HttpOverrides.Tests/project.json @@ -14,7 +14,7 @@ "netcoreapp1.0": { "dependencies": { "Microsoft.NETCore.App": { - "version": "1.0.0-*", + "version": "1.1.0-*", "type": "platform" } } diff --git a/test/Microsoft.AspNetCore.ResponseCompression.Tests/project.json b/test/Microsoft.AspNetCore.ResponseCompression.Tests/project.json index f95326556d..26238aab92 100644 --- a/test/Microsoft.AspNetCore.ResponseCompression.Tests/project.json +++ b/test/Microsoft.AspNetCore.ResponseCompression.Tests/project.json @@ -1,26 +1,26 @@ { - "version": "1.1.0-*", - "buildOptions": { - "warningsAsErrors": true + "version": "1.1.0-*", + "buildOptions": { + "warningsAsErrors": true + }, + "dependencies": { + "dotnet-test-xunit": "2.2.0-*", + "Microsoft.AspNetCore.Http": "1.1.0-*", + "Microsoft.AspNetCore.ResponseCompression": "0.1.0-*", + "Microsoft.AspNetCore.TestHost": "1.1.0-*", + "Microsoft.Net.Http.Headers": "1.1.0-*", + "xunit": "2.2.0-*" + }, + "frameworks": { + "netcoreapp1.0": { + "dependencies": { + "Microsoft.NETCore.App": { + "version": "1.1.0-*", + "type": "platform" + } + } }, - "dependencies": { - "dotnet-test-xunit": "2.2.0-*", - "Microsoft.AspNetCore.ResponseCompression": "0.1.0-*", - "Microsoft.AspNetCore.TestHost": "1.1.0-*", - "xunit": "2.2.0-*", - "Microsoft.AspNetCore.Http": "1.1.0-*", - "Microsoft.Net.Http.Headers": "1.1.0-*" - }, - "frameworks": { - "netcoreapp1.0": { - "dependencies": { - "Microsoft.NETCore.App": { - "version": "1.0.0-*", - "type": "platform" - } - } - }, - "net451": {} - }, - "testRunner": "xunit" + "net451": {} + }, + "testRunner": "xunit" } \ No newline at end of file diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/project.json b/test/Microsoft.AspNetCore.Rewrite.Tests/project.json index acbd1fdc82..2126a3177f 100644 --- a/test/Microsoft.AspNetCore.Rewrite.Tests/project.json +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/project.json @@ -1,4 +1,4 @@ -{ +{ "version": "1.1.0-*", "buildOptions": { "warningsAsErrors": true, @@ -19,7 +19,7 @@ "version": "1.0.2" }, "Microsoft.NETCore.App": { - "version": "1.0.0-*", + "version": "1.1.0-*", "type": "platform" } } From 3cb0fc640a925a54530ed8dc04b42709ee8785b8 Mon Sep 17 00:00:00 2001 From: Chris R Date: Tue, 4 Oct 2016 13:10:06 -0700 Subject: [PATCH 124/307] #108 Make flush work for response compression --- .../CustomCompressionProvider.cs | 2 + samples/ResponseCompressionSample/Startup.cs | 30 +- .../ResponseCompressionSample/project.json | 3 +- .../BodyWrapperStream.cs | 51 ++- .../GzipCompressionProvider.cs | 22 +- .../ICompressionProvider.cs | 5 + .../ResponseCompressionMiddleware.cs | 28 +- .../ResponseCompressionProvider.cs | 1 + .../ResponseCompressionMiddlewareTest.cs | 344 +++++++++++++++++- 9 files changed, 458 insertions(+), 28 deletions(-) diff --git a/samples/ResponseCompressionSample/CustomCompressionProvider.cs b/samples/ResponseCompressionSample/CustomCompressionProvider.cs index f9d4781bbf..9bbd4c09a2 100644 --- a/samples/ResponseCompressionSample/CustomCompressionProvider.cs +++ b/samples/ResponseCompressionSample/CustomCompressionProvider.cs @@ -7,6 +7,8 @@ namespace ResponseCompressionSample { public string EncodingName => "custom"; + public bool SupportsFlush => true; + public Stream CreateStream(Stream outputStream) { // Create a custom compression stream wrapper here diff --git a/samples/ResponseCompressionSample/Startup.cs b/samples/ResponseCompressionSample/Startup.cs index f5fdd6126c..98af8aea6b 100644 --- a/samples/ResponseCompressionSample/Startup.cs +++ b/samples/ResponseCompressionSample/Startup.cs @@ -1,11 +1,15 @@ // 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; +using System.Threading.Tasks; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Http.Features; using Microsoft.AspNetCore.ResponseCompression; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; namespace ResponseCompressionSample { @@ -22,6 +26,23 @@ namespace ResponseCompressionSample { app.UseResponseCompression(); + app.Map("/trickle", trickleApp => + { + trickleApp.Run(async context => + { + context.Response.ContentType = "text/plain"; + // Disables compression on net451 because that GZipStream does not implement Flush. + context.Features.Get()?.DisableResponseBuffering(); + + for (int i = 0; i < 100; i++) + { + await context.Response.WriteAsync("a"); + await context.Response.Body.FlushAsync(); + await Task.Delay(TimeSpan.FromSeconds(1)); + } + }); + }); + app.Run(async context => { context.Response.ContentType = "text/plain"; @@ -32,7 +53,14 @@ namespace ResponseCompressionSample public static void Main(string[] args) { var host = new WebHostBuilder() - .UseKestrel() + .UseKestrel(options => + { + options.UseConnectionLogging(); + }) + .ConfigureLogging(factory => + { + factory.AddConsole(LogLevel.Debug); + }) .UseStartup() .Build(); diff --git a/samples/ResponseCompressionSample/project.json b/samples/ResponseCompressionSample/project.json index 24f85c5aae..fb7bb30810 100644 --- a/samples/ResponseCompressionSample/project.json +++ b/samples/ResponseCompressionSample/project.json @@ -1,7 +1,8 @@ { "dependencies": { "Microsoft.AspNetCore.ResponseCompression": "0.1.0-*", - "Microsoft.AspNetCore.Server.Kestrel": "1.1.0-*" + "Microsoft.AspNetCore.Server.Kestrel": "1.1.0-*", + "Microsoft.Extensions.Logging.Console": "1.1.0-*" }, "buildOptions": { "emitEntryPoint": true diff --git a/src/Microsoft.AspNetCore.ResponseCompression/BodyWrapperStream.cs b/src/Microsoft.AspNetCore.ResponseCompression/BodyWrapperStream.cs index 453ede8899..3b31b1f357 100644 --- a/src/Microsoft.AspNetCore.ResponseCompression/BodyWrapperStream.cs +++ b/src/Microsoft.AspNetCore.ResponseCompression/BodyWrapperStream.cs @@ -6,6 +6,7 @@ using System.IO; using System.Threading; using System.Threading.Tasks; using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Http.Features; using Microsoft.Net.Http.Headers; namespace Microsoft.AspNetCore.ResponseCompression @@ -13,7 +14,7 @@ namespace Microsoft.AspNetCore.ResponseCompression /// /// Stream wrapper that create specific compression stream only if necessary. /// - internal class BodyWrapperStream : Stream + internal class BodyWrapperStream : Stream, IHttpBufferingFeature { private readonly HttpResponse _response; @@ -23,16 +24,20 @@ namespace Microsoft.AspNetCore.ResponseCompression private readonly ICompressionProvider _compressionProvider; + private readonly IHttpBufferingFeature _innerBufferFeature; + private bool _compressionChecked = false; private Stream _compressionStream = null; - internal BodyWrapperStream(HttpResponse response, Stream bodyOriginalStream, IResponseCompressionProvider provider, ICompressionProvider compressionProvider) + internal BodyWrapperStream(HttpResponse response, Stream bodyOriginalStream, IResponseCompressionProvider provider, ICompressionProvider compressionProvider, + IHttpBufferingFeature innerBufferFeature) { _response = response; _bodyOriginalStream = bodyOriginalStream; _provider = provider; _compressionProvider = compressionProvider; + _innerBufferFeature = innerBufferFeature; } protected override void Dispose(bool disposing) @@ -63,7 +68,14 @@ namespace Microsoft.AspNetCore.ResponseCompression public override void Flush() { - OnWrite(); + if (!_compressionChecked) + { + OnWrite(); + // Flush the original stream to send the headers. Flushing the compression stream won't + // flush the original stream if no data has been written yet. + _bodyOriginalStream.Flush(); + return; + } if (_compressionStream != null) { @@ -77,12 +89,19 @@ namespace Microsoft.AspNetCore.ResponseCompression public override Task FlushAsync(CancellationToken cancellationToken) { - OnWrite(); + if (!_compressionChecked) + { + OnWrite(); + // Flush the original stream to send the headers. Flushing the compression stream won't + // flush the original stream if no data has been written yet. + return _bodyOriginalStream.FlushAsync(cancellationToken); + } if (_compressionStream != null) { return _compressionStream.FlushAsync(cancellationToken); } + return _bodyOriginalStream.FlushAsync(cancellationToken); } @@ -129,7 +148,10 @@ namespace Microsoft.AspNetCore.ResponseCompression public override void EndWrite(IAsyncResult asyncResult) { - OnWrite(); + if (!_compressionChecked) + { + throw new InvalidOperationException("BeginWrite was not called before EndWrite"); + } if (_compressionStream != null) { @@ -175,5 +197,24 @@ namespace Microsoft.AspNetCore.ResponseCompression return !_response.Headers.ContainsKey(HeaderNames.ContentRange) && // The response is not partial _provider.ShouldCompressResponse(_response.HttpContext); } + + public void DisableRequestBuffering() + { + // Unrelated + _innerBufferFeature?.DisableRequestBuffering(); + } + + // For this to be effective it needs to be called before the first write. + public void DisableResponseBuffering() + { + if (!_compressionProvider.SupportsFlush) + { + // Don't compress, some of the providers don't implement Flush (e.g. .NET 4.5.1 GZip/Deflate stream) + // which would block real-time responses like SignalR. + _compressionChecked = true; + } + + _innerBufferFeature?.DisableResponseBuffering(); + } } } diff --git a/src/Microsoft.AspNetCore.ResponseCompression/GzipCompressionProvider.cs b/src/Microsoft.AspNetCore.ResponseCompression/GzipCompressionProvider.cs index ff2c20c9b7..d605937492 100644 --- a/src/Microsoft.AspNetCore.ResponseCompression/GzipCompressionProvider.cs +++ b/src/Microsoft.AspNetCore.ResponseCompression/GzipCompressionProvider.cs @@ -11,16 +11,24 @@ namespace Microsoft.AspNetCore.ResponseCompression /// public class GzipCompressionProvider : ICompressionProvider { - /// - /// Initialize a new . - /// - public GzipCompressionProvider() - { - } - /// public string EncodingName => "gzip"; + /// + public bool SupportsFlush + { + get + { +#if NET451 + return false; +#elif NETSTANDARD1_3 + return true; +#else + // Not implemented, compiler break +#endif + } + } + /// /// What level of compression to use for the stream. /// diff --git a/src/Microsoft.AspNetCore.ResponseCompression/ICompressionProvider.cs b/src/Microsoft.AspNetCore.ResponseCompression/ICompressionProvider.cs index 66ae5cca51..e9f184596f 100644 --- a/src/Microsoft.AspNetCore.ResponseCompression/ICompressionProvider.cs +++ b/src/Microsoft.AspNetCore.ResponseCompression/ICompressionProvider.cs @@ -15,6 +15,11 @@ namespace Microsoft.AspNetCore.ResponseCompression /// string EncodingName { get; } + /// + /// Indicates if the given provider supports Flush and FlushAsync. If not, compression may be disabled in some scenarios. + /// + bool SupportsFlush { get; } + /// /// Create a new compression stream. /// diff --git a/src/Microsoft.AspNetCore.ResponseCompression/ResponseCompressionMiddleware.cs b/src/Microsoft.AspNetCore.ResponseCompression/ResponseCompressionMiddleware.cs index 96e6c7af46..6e2e784bc5 100644 --- a/src/Microsoft.AspNetCore.ResponseCompression/ResponseCompressionMiddleware.cs +++ b/src/Microsoft.AspNetCore.ResponseCompression/ResponseCompressionMiddleware.cs @@ -4,6 +4,7 @@ using System; using System.Threading.Tasks; using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Http.Features; using Microsoft.Extensions.Options; namespace Microsoft.AspNetCore.ResponseCompression @@ -39,6 +40,7 @@ namespace Microsoft.AspNetCore.ResponseCompression { throw new ArgumentNullException(nameof(options)); } + _next = next; _provider = provider; _enableHttps = options.Value.EnableHttps; @@ -65,19 +67,23 @@ namespace Microsoft.AspNetCore.ResponseCompression } var bodyStream = context.Response.Body; + var originalBufferFeature = context.Features.Get(); - using (var bodyWrapperStream = new BodyWrapperStream(context.Response, bodyStream, _provider, compressionProvider)) + var bodyWrapperStream = new BodyWrapperStream(context.Response, bodyStream, _provider, compressionProvider, originalBufferFeature); + context.Response.Body = bodyWrapperStream; + context.Features.Set(bodyWrapperStream); + + try { - context.Response.Body = bodyWrapperStream; - - try - { - await _next(context); - } - finally - { - context.Response.Body = bodyStream; - } + await _next(context); + // This is not disposed via a using statement because we don't want to flush the compression buffer for unhandled exceptions, + // that may cause secondary exceptions. + bodyWrapperStream.Dispose(); + } + finally + { + context.Response.Body = bodyStream; + context.Features.Set(originalBufferFeature); } } } diff --git a/src/Microsoft.AspNetCore.ResponseCompression/ResponseCompressionProvider.cs b/src/Microsoft.AspNetCore.ResponseCompression/ResponseCompressionProvider.cs index 64963b124a..32376413c1 100644 --- a/src/Microsoft.AspNetCore.ResponseCompression/ResponseCompressionProvider.cs +++ b/src/Microsoft.AspNetCore.ResponseCompression/ResponseCompressionProvider.cs @@ -108,6 +108,7 @@ namespace Microsoft.AspNetCore.ResponseCompression mimeType = mimeType.Trim(); } + // TODO PERF: StringSegments? return _mimeTypes.Contains(mimeType); } } diff --git a/test/Microsoft.AspNetCore.ResponseCompression.Tests/ResponseCompressionMiddlewareTest.cs b/test/Microsoft.AspNetCore.ResponseCompression.Tests/ResponseCompressionMiddlewareTest.cs index 1e362fcc48..f76f56d704 100644 --- a/test/Microsoft.AspNetCore.ResponseCompression.Tests/ResponseCompressionMiddlewareTest.cs +++ b/test/Microsoft.AspNetCore.ResponseCompression.Tests/ResponseCompressionMiddlewareTest.cs @@ -4,10 +4,12 @@ using System; using System.Collections.Generic; using System.Net.Http; +using System.Threading; using System.Threading.Tasks; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Http.Features; using Microsoft.AspNetCore.TestHost; using Microsoft.Net.Http.Headers; using Xunit; @@ -35,7 +37,7 @@ namespace Microsoft.AspNetCore.ResponseCompression.Tests } [Fact] - public async Task Request_AcceptGzipDeflate_ComrpessedGzip() + public async Task Request_AcceptGzipDeflate_CompressedGzip() { var response = await InvokeMiddleware(100, requestAcceptEncodings: new string[] { "gzip", "deflate" }, responseType: TextPlain); @@ -88,6 +90,7 @@ namespace Microsoft.AspNetCore.ResponseCompression.Tests app.UseResponseCompression(); app.Run(context => { + context.Response.Headers[HeaderNames.ContentMD5] = "MD5"; context.Response.ContentType = contentType; return context.Response.WriteAsync(new string('a', 100)); }); @@ -101,7 +104,7 @@ namespace Microsoft.AspNetCore.ResponseCompression.Tests var response = await client.SendAsync(request); - Assert.Equal(24, response.Content.ReadAsByteArrayAsync().Result.Length); + CheckResponseCompressed(response, expectedBodyLength: 24); } [Theory] @@ -119,6 +122,7 @@ namespace Microsoft.AspNetCore.ResponseCompression.Tests app.UseResponseCompression(); app.Run(context => { + context.Response.Headers[HeaderNames.ContentMD5] = "MD5"; context.Response.ContentType = contentType; return context.Response.WriteAsync(new string('a', 100)); }); @@ -132,7 +136,43 @@ namespace Microsoft.AspNetCore.ResponseCompression.Tests var response = await client.SendAsync(request); - Assert.Equal(100, response.Content.ReadAsByteArrayAsync().Result.Length); + CheckResponseNotCompressed(response, expectedBodyLength: 100); + } + + [Theory] + [InlineData("")] + [InlineData("text/plain")] + [InlineData("text/PLAIN")] + [InlineData("text/plain; charset=ISO-8859-4")] + [InlineData("text/plain ; charset=ISO-8859-4")] + [InlineData("text/plain2")] + public async Task NoBody_NotCompressed(string contentType) + { + var builder = new WebHostBuilder() + .ConfigureServices(services => + { + services.AddResponseCompression(TextPlain); + }) + .Configure(app => + { + app.UseResponseCompression(); + app.Run(context => + { + context.Response.Headers[HeaderNames.ContentMD5] = "MD5"; + context.Response.ContentType = contentType; + return Task.FromResult(0); + }); + }); + + var server = new TestServer(builder); + var client = server.CreateClient(); + + var request = new HttpRequestMessage(HttpMethod.Get, ""); + request.Headers.AcceptEncoding.ParseAdd("gzip"); + + var response = await client.SendAsync(request); + + CheckResponseNotCompressed(response, expectedBodyLength: 0); } [Fact] @@ -241,6 +281,304 @@ namespace Microsoft.AspNetCore.ResponseCompression.Tests Assert.Equal(expectedLength, response.Content.ReadAsByteArrayAsync().Result.Length); } + [Fact] + public async Task FlushHeaders_SendsHeaders_Compresses() + { + var responseReceived = new ManualResetEvent(false); + + var builder = new WebHostBuilder() + .ConfigureServices(services => + { + services.AddResponseCompression(TextPlain); + }) + .Configure(app => + { + app.UseResponseCompression(); + app.Run(context => + { + context.Response.Headers[HeaderNames.ContentMD5] = "MD5"; + context.Response.ContentType = TextPlain; + context.Response.Body.Flush(); + Assert.True(responseReceived.WaitOne(TimeSpan.FromSeconds(3))); + return context.Response.WriteAsync(new string('a', 100)); + }); + }); + + var server = new TestServer(builder); + var client = server.CreateClient(); + + var request = new HttpRequestMessage(HttpMethod.Get, ""); + request.Headers.AcceptEncoding.ParseAdd("gzip"); + + var response = await client.SendAsync(request, HttpCompletionOption.ResponseHeadersRead); + responseReceived.Set(); + + await response.Content.LoadIntoBufferAsync(); + + CheckResponseCompressed(response, expectedBodyLength: 24); + } + + [Fact] + public async Task FlushAsyncHeaders_SendsHeaders_Compresses() + { + var responseReceived = new ManualResetEvent(false); + + var builder = new WebHostBuilder() + .ConfigureServices(services => + { + services.AddResponseCompression(TextPlain); + }) + .Configure(app => + { + app.UseResponseCompression(); + app.Run(async context => + { + context.Response.Headers[HeaderNames.ContentMD5] = "MD5"; + context.Response.ContentType = TextPlain; + await context.Response.Body.FlushAsync(); + Assert.True(responseReceived.WaitOne(TimeSpan.FromSeconds(3))); + await context.Response.WriteAsync(new string('a', 100)); + }); + }); + + var server = new TestServer(builder); + var client = server.CreateClient(); + + var request = new HttpRequestMessage(HttpMethod.Get, ""); + request.Headers.AcceptEncoding.ParseAdd("gzip"); + + var response = await client.SendAsync(request, HttpCompletionOption.ResponseHeadersRead); + responseReceived.Set(); + + await response.Content.LoadIntoBufferAsync(); + + CheckResponseCompressed(response, expectedBodyLength: 24); + } + + [Fact] + public async Task FlushBody_CompressesAndFlushes() + { + var responseReceived = new ManualResetEvent(false); + + var builder = new WebHostBuilder() + .ConfigureServices(services => + { + services.AddResponseCompression(TextPlain); + }) + .Configure(app => + { + app.UseResponseCompression(); + app.Run(context => + { + context.Response.Headers[HeaderNames.ContentMD5] = "MD5"; + context.Response.ContentType = TextPlain; + context.Response.Body.Write(new byte[10], 0, 10); + context.Response.Body.Flush(); + Assert.True(responseReceived.WaitOne(TimeSpan.FromSeconds(3))); + context.Response.Body.Write(new byte[90], 0, 90); + return Task.FromResult(0); + }); + }); + + var server = new TestServer(builder); + var client = server.CreateClient(); + + var request = new HttpRequestMessage(HttpMethod.Get, ""); + request.Headers.AcceptEncoding.ParseAdd("gzip"); + + var response = await client.SendAsync(request, HttpCompletionOption.ResponseHeadersRead); + + IEnumerable contentMD5 = null; + Assert.False(response.Headers.TryGetValues(HeaderNames.ContentMD5, out contentMD5)); + Assert.Single(response.Content.Headers.ContentEncoding, "gzip"); + + var body = await response.Content.ReadAsStreamAsync(); + var read = await body.ReadAsync(new byte[100], 0, 100); + Assert.True(read > 0); + + responseReceived.Set(); + + read = await body.ReadAsync(new byte[100], 0, 100); + Assert.True(read > 0); + } + + [Fact] + public async Task FlushAsyncBody_CompressesAndFlushes() + { + var responseReceived = new ManualResetEvent(false); + + var builder = new WebHostBuilder() + .ConfigureServices(services => + { + services.AddResponseCompression(TextPlain); + }) + .Configure(app => + { + app.UseResponseCompression(); + app.Run(async context => + { + context.Response.Headers[HeaderNames.ContentMD5] = "MD5"; + context.Response.ContentType = TextPlain; + await context.Response.WriteAsync(new string('a', 10)); + await context.Response.Body.FlushAsync(); + Assert.True(responseReceived.WaitOne(TimeSpan.FromSeconds(3))); + await context.Response.WriteAsync(new string('a', 90)); + }); + }); + + var server = new TestServer(builder); + var client = server.CreateClient(); + + var request = new HttpRequestMessage(HttpMethod.Get, ""); + request.Headers.AcceptEncoding.ParseAdd("gzip"); + + var response = await client.SendAsync(request, HttpCompletionOption.ResponseHeadersRead); + + IEnumerable contentMD5 = null; + Assert.False(response.Headers.TryGetValues(HeaderNames.ContentMD5, out contentMD5)); + Assert.Single(response.Content.Headers.ContentEncoding, "gzip"); + + var body = await response.Content.ReadAsStreamAsync(); + var read = await body.ReadAsync(new byte[100], 0, 100); + Assert.True(read > 0); + + responseReceived.Set(); + + read = await body.ReadAsync(new byte[100], 0, 100); + Assert.True(read > 0); + } + + [Fact] + public async Task TrickleWriteAndFlush_FlushesEachWrite() + { + var responseReceived = new[] + { + new ManualResetEvent(false), + new ManualResetEvent(false), + new ManualResetEvent(false), + new ManualResetEvent(false), + new ManualResetEvent(false), + }; + + var builder = new WebHostBuilder() + .ConfigureServices(services => + { + services.AddResponseCompression(TextPlain); + }) + .Configure(app => + { + app.UseResponseCompression(); + app.Run(context => + { + context.Response.Headers[HeaderNames.ContentMD5] = "MD5"; + context.Response.ContentType = TextPlain; + context.Features.Get()?.DisableResponseBuffering(); + + foreach (var signal in responseReceived) + { + context.Response.Body.Write(new byte[1], 0, 1); + context.Response.Body.Flush(); + Assert.True(signal.WaitOne(TimeSpan.FromSeconds(3))); + } + return Task.FromResult(0); + }); + }); + + var server = new TestServer(builder); + var client = server.CreateClient(); + + var request = new HttpRequestMessage(HttpMethod.Get, ""); + request.Headers.AcceptEncoding.ParseAdd("gzip"); + + var response = await client.SendAsync(request, HttpCompletionOption.ResponseHeadersRead); + +#if NET451 // Flush not supported, compression disabled + Assert.NotNull(response.Headers.GetValues(HeaderNames.ContentMD5)); + Assert.Empty(response.Content.Headers.ContentEncoding); +#elif NETCOREAPP1_0 // Flush supported, compression enabled + IEnumerable contentMD5 = null; + Assert.False(response.Headers.TryGetValues(HeaderNames.ContentMD5, out contentMD5)); + Assert.Single(response.Content.Headers.ContentEncoding, "gzip"); +#else + Not implemented, compiler break +#endif + + var body = await response.Content.ReadAsStreamAsync(); + + foreach (var signal in responseReceived) + { + var read = await body.ReadAsync(new byte[100], 0, 100); + Assert.True(read > 0); + + signal.Set(); + } + } + + [Fact] + public async Task TrickleWriteAndFlushAsync_FlushesEachWrite() + { + var responseReceived = new[] + { + new ManualResetEvent(false), + new ManualResetEvent(false), + new ManualResetEvent(false), + new ManualResetEvent(false), + new ManualResetEvent(false), + }; + + var builder = new WebHostBuilder() + .ConfigureServices(services => + { + services.AddResponseCompression(TextPlain); + }) + .Configure(app => + { + app.UseResponseCompression(); + app.Run(async context => + { + context.Response.Headers[HeaderNames.ContentMD5] = "MD5"; + context.Response.ContentType = TextPlain; + context.Features.Get()?.DisableResponseBuffering(); + + foreach (var signal in responseReceived) + { + await context.Response.WriteAsync("a"); + await context.Response.Body.FlushAsync(); + Assert.True(signal.WaitOne(TimeSpan.FromSeconds(3))); + } + }); + }); + + var server = new TestServer(builder); + var client = server.CreateClient(); + + var request = new HttpRequestMessage(HttpMethod.Get, ""); + request.Headers.AcceptEncoding.ParseAdd("gzip"); + + var response = await client.SendAsync(request, HttpCompletionOption.ResponseHeadersRead); + +#if NET451 // Flush not supported, compression disabled + Assert.NotNull(response.Headers.GetValues(HeaderNames.ContentMD5)); + Assert.Empty(response.Content.Headers.ContentEncoding); +#elif NETCOREAPP1_0 // Flush supported, compression enabled + IEnumerable contentMD5 = null; + Assert.False(response.Headers.TryGetValues(HeaderNames.ContentMD5, out contentMD5)); + Assert.Single(response.Content.Headers.ContentEncoding, "gzip"); +#else + Not implemented, compiler break +#endif + + var body = await response.Content.ReadAsStreamAsync(); + + foreach (var signal in responseReceived) + { + var read = await body.ReadAsync(new byte[100], 0, 100); + Assert.True(read > 0); + + signal.Set(); + } + } + private Task InvokeMiddleware(int uncompressedBodyLength, string[] requestAcceptEncodings, string responseType, Action addResponseAction = null) { var builder = new WebHostBuilder() From 1db5a9e58f5b40d316af7a82d92022fa35fe3cc0 Mon Sep 17 00:00:00 2001 From: Nate McMaster Date: Tue, 4 Oct 2016 14:13:03 -0700 Subject: [PATCH 125/307] Implement ChangeCookieAction and add factory to parse from mod_rewrite. Resolves #94 --- .../ApacheModRewrite/CookieActionFactory.cs | 120 ++++++++++++++++++ .../Internal/ApacheModRewrite/FlagParser.cs | 2 +- .../Internal/ApacheModRewrite/RuleBuilder.cs | 5 +- .../Internal/RedirectRule.cs | 4 +- .../Internal/RewriteRule.cs | 4 +- .../Internal/UrlActions/ChangeCookieAction.cs | 63 ++++++++- .../Properties/Resources.Designer.cs | 88 +++++++++---- .../Resources.resx | 20 ++- .../CookieActionFactoryTest.cs | 93 ++++++++++++++ .../ApacheModRewrite/FlagParserTest.cs | 16 ++- .../UrlActions/ChangeCookieActionTests.cs | 66 ++++++++++ .../UrlActions/ForbiddenActionTests.cs | 2 +- 12 files changed, 433 insertions(+), 50 deletions(-) create mode 100644 src/Microsoft.AspNetCore.Rewrite/Internal/ApacheModRewrite/CookieActionFactory.cs create mode 100644 test/Microsoft.AspNetCore.Rewrite.Tests/ApacheModRewrite/CookieActionFactoryTest.cs create mode 100644 test/Microsoft.AspNetCore.Rewrite.Tests/UrlActions/ChangeCookieActionTests.cs diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/ApacheModRewrite/CookieActionFactory.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/ApacheModRewrite/CookieActionFactory.cs new file mode 100644 index 0000000000..27cb805064 --- /dev/null +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/ApacheModRewrite/CookieActionFactory.cs @@ -0,0 +1,120 @@ +// 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; +using System.Globalization; +using Microsoft.AspNetCore.Rewrite.Internal.UrlActions; + +namespace Microsoft.AspNetCore.Rewrite.Internal.ApacheModRewrite +{ + public class CookieActionFactory + { + /// + /// Creates a for details. + /// + /// The flag + /// The action + public ChangeCookieAction Create(string flagValue) + { + if (string.IsNullOrEmpty(flagValue)) + { + throw new ArgumentException(nameof(flagValue)); + } + + var i = 0; + var separator = ':'; + if (flagValue[0] == ';') + { + separator = ';'; + i++; + } + + ChangeCookieAction action = null; + var currentField = Fields.Name; + var start = i; + for (; i < flagValue.Length; i++) + { + if (flagValue[i] == separator) + { + var length = i - start; + SetActionOption(flagValue.Substring(start, length).Trim(), currentField, ref action); + + currentField++; + start = i + 1; + } + } + + if (i != start) + { + SetActionOption(flagValue.Substring(start).Trim(new[] { ' ', separator }), currentField, ref action); + } + + if (currentField < Fields.Domain) + { + throw new FormatException(Resources.FormatError_InvalidChangeCookieFlag(flagValue)); + } + + return action; + } + + private static void SetActionOption(string value, Fields tokenType, ref ChangeCookieAction action) + { + switch (tokenType) + { + case Fields.Name: + action = new ChangeCookieAction(value); + break; + case Fields.Value: + action.Value = value; + break; + case Fields.Domain: + // despite what spec says, an empty domain field is allowed in mod_rewrite + // by specifying NAME:VALUE:; + action.Domain = string.IsNullOrEmpty(value) || value == ";" + ? null + : value; + break; + case Fields.Lifetime: + if (string.IsNullOrEmpty(value)) + { + break; + } + + uint minutes; + if (!uint.TryParse(value, NumberStyles.Any, CultureInfo.InvariantCulture, out minutes)) + { + throw new FormatException(Resources.FormatError_CouldNotParseInteger(value)); + } + + action.Lifetime = TimeSpan.FromMinutes(minutes); + break; + case Fields.Path: + action.Path = value; + break; + case Fields.Secure: + action.Secure = "secure".Equals(value, StringComparison.OrdinalIgnoreCase) + || "true".Equals(value, StringComparison.OrdinalIgnoreCase) + || value == "1"; + break; + case Fields.HttpOnly: + action.HttpOnly = "httponly".Equals(value, StringComparison.OrdinalIgnoreCase) + || "true".Equals(value, StringComparison.OrdinalIgnoreCase) + || value == "1"; + break; + } + } + + // order matters + // see https://httpd.apache.org/docs/current/rewrite/flags.html#flag_co + private enum Fields + { + Name, + Value, + Domain, + Lifetime, + Path, + Secure, + HttpOnly + } + } +} \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/ApacheModRewrite/FlagParser.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/ApacheModRewrite/FlagParser.cs index b3e957a5c7..3d736d7b56 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/ApacheModRewrite/FlagParser.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/ApacheModRewrite/FlagParser.cs @@ -59,7 +59,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.ApacheModRewrite { if (string.IsNullOrEmpty(flagString)) { - throw new ArgumentNullException(nameof(flagString)); + throw new ArgumentException(nameof(flagString)); } // Check that flags are contained within [] diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/ApacheModRewrite/RuleBuilder.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/ApacheModRewrite/RuleBuilder.cs index 8e93d1db16..7bb0d1cd3f 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/ApacheModRewrite/RuleBuilder.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/ApacheModRewrite/RuleBuilder.cs @@ -14,6 +14,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.ApacheModRewrite private IList _conditions; private IList _actions = new List(); private UrlMatch _match; + private CookieActionFactory _cookieActionFactory = new CookieActionFactory(); private readonly TimeSpan RegexTimeout = TimeSpan.FromMilliseconds(1); @@ -172,8 +173,8 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.ApacheModRewrite string flag; if (flags.GetValue(FlagType.Cookie, out flag)) { - // parse cookie - _actions.Add(new ChangeCookieAction(flag)); + var action = _cookieActionFactory.Create(flag); + _actions.Add(action); } if (flags.GetValue(FlagType.Env, out flag)) diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/RedirectRule.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/RedirectRule.cs index 2c9f471040..1198f27a6a 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/RedirectRule.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/RedirectRule.cs @@ -18,12 +18,12 @@ namespace Microsoft.AspNetCore.Rewrite.Internal { if (string.IsNullOrEmpty(regex)) { - throw new ArgumentNullException(nameof(regex)); + throw new ArgumentException(nameof(regex)); } if (string.IsNullOrEmpty(replacement)) { - throw new ArgumentNullException(nameof(replacement)); + throw new ArgumentException(nameof(replacement)); } InitialMatch = new Regex(regex, RegexOptions.Compiled | RegexOptions.CultureInvariant, _regexTimeout); diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/RewriteRule.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/RewriteRule.cs index 336c2ba87d..d6452e8bc8 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/RewriteRule.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/RewriteRule.cs @@ -18,12 +18,12 @@ namespace Microsoft.AspNetCore.Rewrite.Internal { if (string.IsNullOrEmpty(regex)) { - throw new ArgumentNullException(nameof(regex)); + throw new ArgumentException(nameof(regex)); } if (string.IsNullOrEmpty(replacement)) { - throw new ArgumentNullException(nameof(replacement)); + throw new ArgumentException(nameof(replacement)); } InitialMatch = new Regex(regex, RegexOptions.Compiled | RegexOptions.CultureInvariant, _regexTimeout); diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/ChangeCookieAction.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/ChangeCookieAction.cs index 3bdd95e990..640a022672 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/ChangeCookieAction.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/ChangeCookieAction.cs @@ -2,21 +2,74 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; +using Microsoft.AspNetCore.Http; namespace Microsoft.AspNetCore.Rewrite.Internal.UrlActions { public class ChangeCookieAction : UrlAction { - public ChangeCookieAction(string cookie) + private readonly Func _timeSource; + private CookieOptions _cachedOptions; + + public ChangeCookieAction(string name) + : this(name, () => DateTimeOffset.UtcNow) { - // TODO - throw new NotImplementedException("Changing the cookie is not implemented"); } + // for testing + internal ChangeCookieAction(string name, Func timeSource) + { + _timeSource = timeSource; + + if (string.IsNullOrEmpty(name)) + { + throw new ArgumentException(nameof(name)); + } + + Name = name; + } + + public string Name { get; } + public string Value { get; set; } + public string Domain { get; set; } + public TimeSpan Lifetime { get; set; } + public string Path { get; set; } + public bool Secure { get; set; } + public bool HttpOnly { get; set; } + public override void ApplyAction(RewriteContext context, MatchResults ruleMatch, MatchResults condMatch) { - // modify the cookies - throw new NotImplementedException("Changing the cookie is not implemented"); + var options = GetOrCreateOptions(); + context.HttpContext.Response.Cookies.Append(Name, Value ?? string.Empty, options); + } + + private CookieOptions GetOrCreateOptions() + { + if (Lifetime > TimeSpan.Zero) + { + var now = _timeSource(); + return new CookieOptions() + { + Domain = Domain, + HttpOnly = HttpOnly, + Secure = Secure, + Path = Path, + Expires = now.Add(Lifetime) + }; + } + + if (_cachedOptions == null) + { + _cachedOptions = new CookieOptions() + { + Domain = Domain, + HttpOnly = HttpOnly, + Secure = Secure, + Path = Path + }; + } + + return _cachedOptions; } } } diff --git a/src/Microsoft.AspNetCore.Rewrite/Properties/Resources.Designer.cs b/src/Microsoft.AspNetCore.Rewrite/Properties/Resources.Designer.cs index 3c2e0d6b64..bda94e5268 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Properties/Resources.Designer.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Properties/Resources.Designer.cs @@ -11,19 +11,35 @@ namespace Microsoft.AspNetCore.Rewrite = new ResourceManager("Microsoft.AspNetCore.Rewrite.Resources", typeof(Resources).GetTypeInfo().Assembly); /// - /// Could not parse the UrlRewrite file. Message: '{0}'. Line number '{1}': '{2}'. + /// Error adding a mod_rewrite rule. The change environment flag is not supported. /// - internal static string Error_UrlRewriteParseError + internal static string Error_ChangeEnvironmentNotSupported { - get { return GetString("Error_UrlRewriteParseError"); } + get { return GetString("Error_ChangeEnvironmentNotSupported"); } } /// - /// Could not parse the UrlRewrite file. Message: '{0}'. Line number '{1}': '{2}'. + /// Error adding a mod_rewrite rule. The change environment flag is not supported. /// - internal static string FormatError_UrlRewriteParseError(object p0, object p1, object p2) + internal static string FormatError_ChangeEnvironmentNotSupported() { - return string.Format(CultureInfo.CurrentCulture, GetString("Error_UrlRewriteParseError"), p0, p1, p2); + return GetString("Error_ChangeEnvironmentNotSupported"); + } + + /// + /// Could not parse integer from value '{0}'. + /// + internal static string Error_CouldNotParseInteger + { + get { return GetString("Error_CouldNotParseInteger"); } + } + + /// + /// Could not parse integer from value '{0}'. + /// + internal static string FormatError_CouldNotParseInteger(object p0) + { + return string.Format(CultureInfo.CurrentCulture, GetString("Error_CouldNotParseInteger"), p0); } /// @@ -106,6 +122,38 @@ namespace Microsoft.AspNetCore.Rewrite return string.Format(CultureInfo.CurrentCulture, GetString("Error_InputParserUnrecognizedParameter"), p0, p1); } + /// + /// Syntax error for integers in comparison. + /// + internal static string Error_IntegerMatch_FormatExceptionMessage + { + get { return GetString("Error_IntegerMatch_FormatExceptionMessage"); } + } + + /// + /// Syntax error for integers in comparison. + /// + internal static string FormatError_IntegerMatch_FormatExceptionMessage() + { + return GetString("Error_IntegerMatch_FormatExceptionMessage"); + } + + /// + /// Error parsing the mod_rewrite rule. The cookie flag (CO) has an incorrect format '{0}'. + /// + internal static string Error_InvalidChangeCookieFlag + { + get { return GetString("Error_InvalidChangeCookieFlag"); } + } + + /// + /// Error parsing the mod_rewrite rule. The cookie flag (CO) has an incorrect format '{0}'. + /// + internal static string FormatError_InvalidChangeCookieFlag(object p0) + { + return string.Format(CultureInfo.CurrentCulture, GetString("Error_InvalidChangeCookieFlag"), p0); + } + /// /// Could not parse the mod_rewrite file. Message: '{0}'. Line number '{1}'. /// @@ -139,35 +187,19 @@ namespace Microsoft.AspNetCore.Rewrite } /// - /// Syntax error for integers in comparison. + /// Could not parse the UrlRewrite file. Message: '{0}'. Line number '{1}': '{2}'. /// - internal static string Error_IntegerMatch_FormatExceptionMessage + internal static string Error_UrlRewriteParseError { - get { return GetString("Error_IntegerMatch_FormatExceptionMessage"); } + get { return GetString("Error_UrlRewriteParseError"); } } /// - /// Syntax error for integers in comparison. + /// Could not parse the UrlRewrite file. Message: '{0}'. Line number '{1}': '{2}'. /// - internal static string FormatError_IntegerMatch_FormatExceptionMessage() + internal static string FormatError_UrlRewriteParseError(object p0, object p1, object p2) { - return GetString("Error_IntegerMatch_FormatExceptionMessage"); - } - - /// - /// Error adding a mod_rewrite rule. The change environment flag is not supported. - /// - internal static string Error_ChangeEnvironmentNotSupported - { - get { return GetString("Error_ChangeEnvironmentNotSupported"); } - } - - /// - /// Error adding a mod_rewrite rule. The change environment flag is not supported. - /// - internal static string FormatError_ChangeEnvironmentNotSupported() - { - return GetString("Error_ChangeEnvironmentNotSupported"); + return string.Format(CultureInfo.CurrentCulture, GetString("Error_UrlRewriteParseError"), p0, p1, p2); } private static string GetString(string name, params string[] formatterNames) diff --git a/src/Microsoft.AspNetCore.Rewrite/Resources.resx b/src/Microsoft.AspNetCore.Rewrite/Resources.resx index 7b477cc447..2c68d33ec3 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Resources.resx +++ b/src/Microsoft.AspNetCore.Rewrite/Resources.resx @@ -117,8 +117,11 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - Could not parse the UrlRewrite file. Message: '{0}'. Line number '{1}': '{2}'. + + Error adding a mod_rewrite rule. The change environment flag is not supported. + + + Could not parse integer from value '{0}'. Index out of range for backreference: '{0}' at string index: '{1}' @@ -135,16 +138,19 @@ Unrecognized parameter type: '{0}', terminated at string index: '{1}' + + Syntax error for integers in comparison. + + + Error parsing the mod_rewrite rule. The cookie flag (CO) has an incorrect format '{0}'. + Could not parse the mod_rewrite file. Message: '{0}'. Line number '{1}'. Could not parse the mod_rewrite file. Line number '{0}'. - - Syntax error for integers in comparison. - - - Error adding a mod_rewrite rule. The change environment flag is not supported. + + Could not parse the UrlRewrite file. Message: '{0}'. Line number '{1}': '{2}'. \ No newline at end of file diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/ApacheModRewrite/CookieActionFactoryTest.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/ApacheModRewrite/CookieActionFactoryTest.cs new file mode 100644 index 0000000000..d992eb7937 --- /dev/null +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/ApacheModRewrite/CookieActionFactoryTest.cs @@ -0,0 +1,93 @@ +// 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; +using Microsoft.AspNetCore.Rewrite.Internal.ApacheModRewrite; +using Xunit; + +namespace Microsoft.AspNetCore.Rewrite.Test +{ + public class CookieActionFactoryTest + { + [Fact] + public void Creates_OneCookie() + { + var cookie = new CookieActionFactory().Create("NAME:VALUE:DOMAIN:1440:path:secure:httponly"); + + Assert.Equal("NAME", cookie.Name); + Assert.Equal("VALUE", cookie.Value); + Assert.Equal("DOMAIN", cookie.Domain); + Assert.Equal(TimeSpan.FromMinutes(1440), cookie.Lifetime); + Assert.Equal("path", cookie.Path); + Assert.True(cookie.Secure); + Assert.True(cookie.HttpOnly); + } + + [Fact] + public void Creates_OneCookie_AltSeparator() + { + var action = new CookieActionFactory().Create(";NAME;VALUE:WithColon;DOMAIN;1440;path;secure;httponly"); + + Assert.Equal("NAME", action.Name); + Assert.Equal("VALUE:WithColon", action.Value); + Assert.Equal("DOMAIN", action.Domain); + Assert.Equal(TimeSpan.FromMinutes(1440), action.Lifetime); + Assert.Equal("path", action.Path); + Assert.True(action.Secure); + Assert.True(action.HttpOnly); + } + + [Fact] + public void Creates_HttpOnly() + { + var action = new CookieActionFactory().Create(";NAME;VALUE;DOMAIN;;;;httponly"); + + Assert.Equal("NAME", action.Name); + Assert.Equal("VALUE", action.Value); + Assert.Equal("DOMAIN", action.Domain); + Assert.Equal(0, action.Lifetime.TotalSeconds); + Assert.Equal(string.Empty, action.Path); + Assert.False(action.Secure); + Assert.True(action.HttpOnly); + } + + [Theory] + [InlineData("NAME::", "", null)] + [InlineData("NAME::domain", "", "domain")] + [InlineData("NAME:VALUE:;", "VALUE", null)] // special case with dangling ';' + [InlineData("NAME:value:", "value", null)] + [InlineData(" NAME : v : ", "v", null)] // trims values + public void TrimsValues(string flagValue, string value, string domain) + { + var factory = new CookieActionFactory(); + var action = factory.Create(flagValue); + Assert.Equal("NAME", action.Name); + Assert.NotNull(action.Value); + Assert.Equal(value, action.Value); + Assert.Equal(domain, action.Domain); + } + + [Theory] + [InlineData("NAME")] // missing value and domain + [InlineData("NAME: ")] // missing domain + [InlineData("NAME:VALUE")] // missing domain + [InlineData(";NAME;VAL:UE")] // missing domain + public void ThrowsForInvalidFormat(string flagValue) + { + var factory = new CookieActionFactory(); + var ex = Assert.Throws(() => factory.Create(flagValue)); + Assert.Equal(Resources.FormatError_InvalidChangeCookieFlag(flagValue), ex.Message); + } + + [Theory] + [InlineData("bad_number")] + [InlineData("-1")] + [InlineData("0.9")] + public void ThrowsForInvalidIntFormat(string badInt) + { + var factory = new CookieActionFactory(); + var ex = Assert.Throws(() => factory.Create("NAME:VALUE:DOMAIN:" + badInt)); + Assert.Equal(Resources.FormatError_CouldNotParseInteger(badInt), ex.Message); + } + } +} \ No newline at end of file diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/ApacheModRewrite/FlagParserTest.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/ApacheModRewrite/FlagParserTest.cs index 8f8d0cf7a8..bfb4c6420f 100644 --- a/test/Microsoft.AspNetCore.Rewrite.Tests/ApacheModRewrite/FlagParserTest.cs +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/ApacheModRewrite/FlagParserTest.cs @@ -62,8 +62,20 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.ModRewrite [Fact] public void FlagParser_AssertArgumentExceptionWhenFlagsAreNullOrEmpty() { - Assert.Throws(() => new FlagParser().Parse(null)); - Assert.Throws(() => new FlagParser().Parse(string.Empty)); + Assert.Throws(() => new FlagParser().Parse(null)); + Assert.Throws(() => new FlagParser().Parse(string.Empty)); + } + + [Theory] + [InlineData("[CO=VAR:VAL]", "VAR:VAL")] + [InlineData("[CO=!VAR]", "!VAR")] + [InlineData("[CO=;NAME:VALUE;ABC:123]", ";NAME:VALUE;ABC:123")] + public void Flag_ParserHandlesComplexFlags(string flagString, string expected) + { + var results = new FlagParser().Parse(flagString); + string value; + Assert.True(results.GetValue(FlagType.Cookie, out value)); + Assert.Equal(expected, value); } public bool DictionaryContentsEqual(IDictionary dictionary, IDictionary other) diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/UrlActions/ChangeCookieActionTests.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/UrlActions/ChangeCookieActionTests.cs new file mode 100644 index 0000000000..20096ef162 --- /dev/null +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/UrlActions/ChangeCookieActionTests.cs @@ -0,0 +1,66 @@ +// 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; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Rewrite.Internal.UrlActions; +using Microsoft.Net.Http.Headers; +using Xunit; + +namespace Microsoft.AspNetCore.Rewrite.Tests.UrlActions +{ + public class ChangeCookieActionTests + { + [Fact] + public void SetsCookie() + { + var now = DateTimeOffset.UtcNow; + var context = new RewriteContext { HttpContext = new DefaultHttpContext() }; + var action = new ChangeCookieAction("Cookie", () => now) + { + Value = "Chocolate Chip", + Domain = "contoso.com", + Lifetime = TimeSpan.FromMinutes(1440), + Path = "/recipes", + Secure = true, + HttpOnly = true + }; + + action.ApplyAction(context, null, null); + + var cookieHeaders = context.HttpContext.Response.Headers[HeaderNames.SetCookie]; + var header = Assert.Single(cookieHeaders); + Assert.Equal($"Cookie=Chocolate%20Chip; expires={HeaderUtilities.FormatDate(now.AddMinutes(1440))}; domain=contoso.com; path=/recipes; secure; httponly", header); + } + + [Fact] + public void ZeroLifetime() + { + var context = new RewriteContext { HttpContext = new DefaultHttpContext() }; + var action = new ChangeCookieAction("Cookie") + { + Value = "Chocolate Chip", + }; + + action.ApplyAction(context, null, null); + + var cookieHeaders = context.HttpContext.Response.Headers[HeaderNames.SetCookie]; + var header = Assert.Single(cookieHeaders); + Assert.Equal($"Cookie=Chocolate%20Chip", header); + } + + + [Fact] + public void UnsetCookie() + { + var context = new RewriteContext { HttpContext = new DefaultHttpContext() }; + var action = new ChangeCookieAction("Cookie"); + + action.ApplyAction(context, null, null); + + var cookieHeaders = context.HttpContext.Response.Headers[HeaderNames.SetCookie]; + var header = Assert.Single(cookieHeaders); + Assert.Equal($"Cookie=", header); + } + } +} diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/UrlActions/ForbiddenActionTests.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/UrlActions/ForbiddenActionTests.cs index b15354b672..a9eac5a807 100644 --- a/test/Microsoft.AspNetCore.Rewrite.Tests/UrlActions/ForbiddenActionTests.cs +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/UrlActions/ForbiddenActionTests.cs @@ -13,7 +13,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlActions public void Forbidden_Verify403IsInStatusCode() { - var context = new RewriteContext {HttpContext = new DefaultHttpContext()}; + var context = new RewriteContext { HttpContext = new DefaultHttpContext() }; var action = new ForbiddenAction(); action.ApplyAction(context, null, null); From cd833a7d63ce7d549e51ac40f7a5857f766c0bae Mon Sep 17 00:00:00 2001 From: Chris R Date: Wed, 5 Oct 2016 16:00:12 -0700 Subject: [PATCH 126/307] #108 Have response compression replace IHttpSendFileFeature --- samples/ResponseCompressionSample/Startup.cs | 11 + .../ResponseCompressionSample/project.json | 4 + .../ResponseCompressionSample/testfile1kb.txt | 1 + .../BodyWrapperStream.cs | 57 +++++- .../ResponseCompressionMiddleware.cs | 12 +- .../project.json | 3 +- .../ResponseCompressionMiddlewareTest.cs | 191 ++++++++++++++++++ .../project.json | 3 + .../testfile1kb.txt | 1 + 9 files changed, 273 insertions(+), 10 deletions(-) create mode 100644 samples/ResponseCompressionSample/testfile1kb.txt create mode 100644 test/Microsoft.AspNetCore.ResponseCompression.Tests/testfile1kb.txt diff --git a/samples/ResponseCompressionSample/Startup.cs b/samples/ResponseCompressionSample/Startup.cs index 98af8aea6b..17dd97bd39 100644 --- a/samples/ResponseCompressionSample/Startup.cs +++ b/samples/ResponseCompressionSample/Startup.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; +using System.IO; using System.Threading.Tasks; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; @@ -26,6 +27,15 @@ namespace ResponseCompressionSample { app.UseResponseCompression(); + app.Map("/testfile1kb.txt", fileApp => + { + fileApp.Run(context => + { + context.Response.ContentType = "text/plain"; + return context.Response.SendFileAsync("testfile1kb.txt"); + }); + }); + app.Map("/trickle", trickleApp => { trickleApp.Run(async context => @@ -57,6 +67,7 @@ namespace ResponseCompressionSample { options.UseConnectionLogging(); }) + // .UseWebListener() .ConfigureLogging(factory => { factory.AddConsole(LogLevel.Debug); diff --git a/samples/ResponseCompressionSample/project.json b/samples/ResponseCompressionSample/project.json index fb7bb30810..07bfa7363d 100644 --- a/samples/ResponseCompressionSample/project.json +++ b/samples/ResponseCompressionSample/project.json @@ -2,9 +2,13 @@ "dependencies": { "Microsoft.AspNetCore.ResponseCompression": "0.1.0-*", "Microsoft.AspNetCore.Server.Kestrel": "1.1.0-*", + "Microsoft.AspNetCore.Server.WebListener": "1.1.0-*", "Microsoft.Extensions.Logging.Console": "1.1.0-*" }, "buildOptions": { + "copyToOutput": [ + "testfile1kb.txt" + ], "emitEntryPoint": true }, "frameworks": { diff --git a/samples/ResponseCompressionSample/testfile1kb.txt b/samples/ResponseCompressionSample/testfile1kb.txt new file mode 100644 index 0000000000..24baa4c608 --- /dev/null +++ b/samples/ResponseCompressionSample/testfile1kb.txt @@ -0,0 +1 @@ +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.ResponseCompression/BodyWrapperStream.cs b/src/Microsoft.AspNetCore.ResponseCompression/BodyWrapperStream.cs index 3b31b1f357..1b82521668 100644 --- a/src/Microsoft.AspNetCore.ResponseCompression/BodyWrapperStream.cs +++ b/src/Microsoft.AspNetCore.ResponseCompression/BodyWrapperStream.cs @@ -6,6 +6,7 @@ using System.IO; using System.Threading; using System.Threading.Tasks; using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Http.Extensions; using Microsoft.AspNetCore.Http.Features; using Microsoft.Net.Http.Headers; @@ -14,30 +15,27 @@ namespace Microsoft.AspNetCore.ResponseCompression /// /// Stream wrapper that create specific compression stream only if necessary. /// - internal class BodyWrapperStream : Stream, IHttpBufferingFeature + internal class BodyWrapperStream : Stream, IHttpBufferingFeature, IHttpSendFileFeature { private readonly HttpResponse _response; - private readonly Stream _bodyOriginalStream; - private readonly IResponseCompressionProvider _provider; - private readonly ICompressionProvider _compressionProvider; - private readonly IHttpBufferingFeature _innerBufferFeature; + private readonly IHttpSendFileFeature _innerSendFileFeature; private bool _compressionChecked = false; - private Stream _compressionStream = null; internal BodyWrapperStream(HttpResponse response, Stream bodyOriginalStream, IResponseCompressionProvider provider, ICompressionProvider compressionProvider, - IHttpBufferingFeature innerBufferFeature) + IHttpBufferingFeature innerBufferFeature, IHttpSendFileFeature innerSendFileFeature) { _response = response; _bodyOriginalStream = bodyOriginalStream; _provider = provider; _compressionProvider = compressionProvider; _innerBufferFeature = innerBufferFeature; + _innerSendFileFeature = innerSendFileFeature; } protected override void Dispose(bool disposing) @@ -216,5 +214,50 @@ namespace Microsoft.AspNetCore.ResponseCompression _innerBufferFeature?.DisableResponseBuffering(); } + + // The IHttpSendFileFeature feature will only be registered if _innerSendFileFeature exists. + public Task SendFileAsync(string path, long offset, long? count, CancellationToken cancellation) + { + OnWrite(); + + if (_compressionStream != null) + { + return InnerSendFileAsync(path, offset, count, cancellation); + } + + return _innerSendFileFeature.SendFileAsync(path, offset, count, cancellation); + } + + private async Task InnerSendFileAsync(string path, long offset, long? count, CancellationToken cancellation) + { + cancellation.ThrowIfCancellationRequested(); + + var fileInfo = new FileInfo(path); + if (offset < 0 || offset > fileInfo.Length) + { + throw new ArgumentOutOfRangeException(nameof(offset), offset, string.Empty); + } + if (count.HasValue && + (count.Value < 0 || count.Value > fileInfo.Length - offset)) + { + throw new ArgumentOutOfRangeException(nameof(count), count, string.Empty); + } + + int bufferSize = 1024 * 16; + + var fileStream = new FileStream( + path, + FileMode.Open, + FileAccess.Read, + FileShare.ReadWrite, + bufferSize: bufferSize, + options: FileOptions.Asynchronous | FileOptions.SequentialScan); + + using (fileStream) + { + fileStream.Seek(offset, SeekOrigin.Begin); + await StreamCopyOperation.CopyToAsync(fileStream, _compressionStream, count, cancellation); + } + } } } diff --git a/src/Microsoft.AspNetCore.ResponseCompression/ResponseCompressionMiddleware.cs b/src/Microsoft.AspNetCore.ResponseCompression/ResponseCompressionMiddleware.cs index 6e2e784bc5..692d77f643 100644 --- a/src/Microsoft.AspNetCore.ResponseCompression/ResponseCompressionMiddleware.cs +++ b/src/Microsoft.AspNetCore.ResponseCompression/ResponseCompressionMiddleware.cs @@ -68,10 +68,16 @@ namespace Microsoft.AspNetCore.ResponseCompression var bodyStream = context.Response.Body; var originalBufferFeature = context.Features.Get(); + var originalSendFileFeature = context.Features.Get(); - var bodyWrapperStream = new BodyWrapperStream(context.Response, bodyStream, _provider, compressionProvider, originalBufferFeature); + var bodyWrapperStream = new BodyWrapperStream(context.Response, bodyStream, _provider, compressionProvider, + originalBufferFeature, originalSendFileFeature); context.Response.Body = bodyWrapperStream; context.Features.Set(bodyWrapperStream); + if (originalSendFileFeature != null) + { + context.Features.Set(bodyWrapperStream); + } try { @@ -84,6 +90,10 @@ namespace Microsoft.AspNetCore.ResponseCompression { context.Response.Body = bodyStream; context.Features.Set(originalBufferFeature); + if (originalSendFileFeature != null) + { + context.Features.Set(originalSendFileFeature); + } } } } diff --git a/src/Microsoft.AspNetCore.ResponseCompression/project.json b/src/Microsoft.AspNetCore.ResponseCompression/project.json index 3cea610ec4..cc3a281c15 100644 --- a/src/Microsoft.AspNetCore.ResponseCompression/project.json +++ b/src/Microsoft.AspNetCore.ResponseCompression/project.json @@ -16,9 +16,8 @@ ] }, "dependencies": { - "Microsoft.AspNetCore.Http.Abstractions": "1.1.0-*", + "Microsoft.AspNetCore.Http.Extensions": "1.1.0-*", "Microsoft.Extensions.Options": "1.1.0-*", - "Microsoft.Net.Http.Headers": "1.1.0-*", "NETStandard.Library": "1.6.1-*" }, "frameworks": { diff --git a/test/Microsoft.AspNetCore.ResponseCompression.Tests/ResponseCompressionMiddlewareTest.cs b/test/Microsoft.AspNetCore.ResponseCompression.Tests/ResponseCompressionMiddlewareTest.cs index f76f56d704..8f468d8b03 100644 --- a/test/Microsoft.AspNetCore.ResponseCompression.Tests/ResponseCompressionMiddlewareTest.cs +++ b/test/Microsoft.AspNetCore.ResponseCompression.Tests/ResponseCompressionMiddlewareTest.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using System.IO; using System.Net.Http; using System.Threading; using System.Threading.Tasks; @@ -579,6 +580,168 @@ namespace Microsoft.AspNetCore.ResponseCompression.Tests } } + [Fact] + public async Task SendFileAsync_OnlySetIfFeatureAlreadyExists() + { + var builder = new WebHostBuilder() + .ConfigureServices(services => + { + services.AddResponseCompression(TextPlain); + }) + .Configure(app => + { + app.UseResponseCompression(); + app.Run(context => + { + context.Response.Headers[HeaderNames.ContentMD5] = "MD5"; + context.Response.ContentType = TextPlain; + context.Response.ContentLength = 1024; + var sendFile = context.Features.Get(); + Assert.Null(sendFile); + return Task.FromResult(0); + }); + }); + + var server = new TestServer(builder); + var client = server.CreateClient(); + + var request = new HttpRequestMessage(HttpMethod.Get, ""); + request.Headers.AcceptEncoding.ParseAdd("gzip"); + + var response = await client.SendAsync(request); + response.EnsureSuccessStatusCode(); + } + + [Fact] + public async Task SendFileAsync_DifferentContentType_NotBypassed() + { + FakeSendFileFeature fakeSendFile = null; + + var builder = new WebHostBuilder() + .ConfigureServices(services => + { + services.AddResponseCompression(TextPlain); + }) + .Configure(app => + { + app.Use((context, next) => + { + fakeSendFile = new FakeSendFileFeature(context.Response.Body); + context.Features.Set(fakeSendFile); + return next(); + }); + app.UseResponseCompression(); + app.Run(context => + { + context.Response.Headers[HeaderNames.ContentMD5] = "MD5"; + context.Response.ContentType = "custom/type"; + context.Response.ContentLength = 1024; + var sendFile = context.Features.Get(); + Assert.NotNull(sendFile); + return sendFile.SendFileAsync("testfile1kb.txt", 0, null, CancellationToken.None); + }); + }); + + var server = new TestServer(builder); + var client = server.CreateClient(); + + var request = new HttpRequestMessage(HttpMethod.Get, ""); + request.Headers.AcceptEncoding.ParseAdd("gzip"); + + var response = await client.SendAsync(request); + + CheckResponseNotCompressed(response, expectedBodyLength: 1024); + + Assert.True(fakeSendFile.Invoked); + } + + [Fact] + public async Task SendFileAsync_FirstWrite_CompressesAndFlushes() + { + FakeSendFileFeature fakeSendFile = null; + + var builder = new WebHostBuilder() + .ConfigureServices(services => + { + services.AddResponseCompression(TextPlain); + }) + .Configure(app => + { + app.Use((context, next) => + { + fakeSendFile = new FakeSendFileFeature(context.Response.Body); + context.Features.Set(fakeSendFile); + return next(); + }); + app.UseResponseCompression(); + app.Run(context => + { + context.Response.Headers[HeaderNames.ContentMD5] = "MD5"; + context.Response.ContentType = TextPlain; + context.Response.ContentLength = 1024; + var sendFile = context.Features.Get(); + Assert.NotNull(sendFile); + return sendFile.SendFileAsync("testfile1kb.txt", 0, null, CancellationToken.None); + }); + }); + + var server = new TestServer(builder); + var client = server.CreateClient(); + + var request = new HttpRequestMessage(HttpMethod.Get, ""); + request.Headers.AcceptEncoding.ParseAdd("gzip"); + + var response = await client.SendAsync(request); + + CheckResponseCompressed(response, expectedBodyLength: 34); + + Assert.False(fakeSendFile.Invoked); + } + + [Fact] + public async Task SendFileAsync_AfterFirstWrite_CompressesAndFlushes() + { + FakeSendFileFeature fakeSendFile = null; + + var builder = new WebHostBuilder() + .ConfigureServices(services => + { + services.AddResponseCompression(TextPlain); + }) + .Configure(app => + { + app.Use((context, next) => + { + fakeSendFile = new FakeSendFileFeature(context.Response.Body); + context.Features.Set(fakeSendFile); + return next(); + }); + app.UseResponseCompression(); + app.Run(async context => + { + context.Response.Headers[HeaderNames.ContentMD5] = "MD5"; + context.Response.ContentType = TextPlain; + var sendFile = context.Features.Get(); + Assert.NotNull(sendFile); + + await context.Response.WriteAsync(new string('a', 100)); + await sendFile.SendFileAsync("testfile1kb.txt", 0, null, CancellationToken.None); + }); + }); + + var server = new TestServer(builder); + var client = server.CreateClient(); + + var request = new HttpRequestMessage(HttpMethod.Get, ""); + request.Headers.AcceptEncoding.ParseAdd("gzip"); + + var response = await client.SendAsync(request); + + CheckResponseCompressed(response, expectedBodyLength: 40); + + Assert.False(fakeSendFile.Invoked); + } + private Task InvokeMiddleware(int uncompressedBodyLength, string[] requestAcceptEncodings, string responseType, Action addResponseAction = null) { var builder = new WebHostBuilder() @@ -593,6 +756,7 @@ namespace Microsoft.AspNetCore.ResponseCompression.Tests { context.Response.Headers[HeaderNames.ContentMD5] = "MD5"; context.Response.ContentType = responseType; + Assert.Null(context.Features.Get()); if (addResponseAction != null) { addResponseAction(context.Response); @@ -628,5 +792,32 @@ namespace Microsoft.AspNetCore.ResponseCompression.Tests Assert.Empty(response.Content.Headers.ContentEncoding); Assert.Equal(expectedBodyLength, response.Content.Headers.ContentLength); } + + private class FakeSendFileFeature : IHttpSendFileFeature + { + private readonly Stream _innerBody; + + public FakeSendFileFeature(Stream innerBody) + { + _innerBody = innerBody; + } + + public bool Invoked { get; set; } + + public async Task SendFileAsync(string path, long offset, long? count, CancellationToken cancellation) + { + // This implementation should only be delegated to if compression is disabled. + Invoked = true; + using (var file = new FileStream(path, FileMode.Open)) + { + file.Seek(offset, SeekOrigin.Begin); + if (count.HasValue) + { + throw new NotImplementedException("Not implemented for testing"); + } + await file.CopyToAsync(_innerBody, 81920, cancellation); + } + } + } } } diff --git a/test/Microsoft.AspNetCore.ResponseCompression.Tests/project.json b/test/Microsoft.AspNetCore.ResponseCompression.Tests/project.json index 26238aab92..af9226646a 100644 --- a/test/Microsoft.AspNetCore.ResponseCompression.Tests/project.json +++ b/test/Microsoft.AspNetCore.ResponseCompression.Tests/project.json @@ -1,6 +1,9 @@ { "version": "1.1.0-*", "buildOptions": { + "copyToOutput": [ + "testfile1kb.txt" + ], "warningsAsErrors": true }, "dependencies": { diff --git a/test/Microsoft.AspNetCore.ResponseCompression.Tests/testfile1kb.txt b/test/Microsoft.AspNetCore.ResponseCompression.Tests/testfile1kb.txt new file mode 100644 index 0000000000..24baa4c608 --- /dev/null +++ b/test/Microsoft.AspNetCore.ResponseCompression.Tests/testfile1kb.txt @@ -0,0 +1 @@ +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa \ No newline at end of file From 9814f3bfbcf3a11dc86c4047fbfc2fe48744f96c Mon Sep 17 00:00:00 2001 From: Mikael Mengistu Date: Thu, 6 Oct 2016 16:23:55 -0700 Subject: [PATCH 127/307] Use status code constants --- .../Internal/IISUrlRewrite/RedirectType.cs | 10 ++++++---- .../Internal/UrlActions/RedirectAction.cs | 2 +- .../RewriteOptionsExtensions.cs | 7 ++++--- .../ApacheModRewrite/ModRewriteMiddlewareTest.cs | 2 +- .../MiddlewareTests.cs | 6 +++--- 5 files changed, 15 insertions(+), 12 deletions(-) diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/RedirectType.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/RedirectType.cs index 2221d5412b..012cc77ded 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/RedirectType.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/RedirectType.cs @@ -1,13 +1,15 @@ // 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 Microsoft.AspNetCore.Http; + namespace Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite { public enum RedirectType { - Permanent = 301, - Found = 302, - SeeOther = 303, - Temporary = 307 + Permanent = StatusCodes.Status301MovedPermanently, + Found = StatusCodes.Status302Found, + SeeOther = StatusCodes.Status303SeeOther, + Temporary = StatusCodes.Status307TemporaryRedirect } } diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/RedirectAction.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/RedirectAction.cs index 9c917ed9a7..06eba46b04 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/RedirectAction.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/RedirectAction.cs @@ -75,7 +75,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlActions QueryString.FromUriComponent( pattern.Substring(split))); - // not using the response.redirect here because status codes may be 301, 302, 307, 308 + // not using the response.redirect here because status codes may be 301, 302, 307, 308 response.Headers[HeaderNames.Location] = pathBase + pattern.Substring(0, split) + query; } else diff --git a/src/Microsoft.AspNetCore.Rewrite/RewriteOptionsExtensions.cs b/src/Microsoft.AspNetCore.Rewrite/RewriteOptionsExtensions.cs index 550d6e8211..c1aa2b69ed 100644 --- a/src/Microsoft.AspNetCore.Rewrite/RewriteOptionsExtensions.cs +++ b/src/Microsoft.AspNetCore.Rewrite/RewriteOptionsExtensions.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; +using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Rewrite.Internal; namespace Microsoft.AspNetCore.Rewrite @@ -58,7 +59,7 @@ namespace Microsoft.AspNetCore.Rewrite /// The Rewrite options. public static RewriteOptions AddRedirect(this RewriteOptions options, string regex, string replacement) { - return AddRedirect(options, regex, replacement, statusCode: 302); + return AddRedirect(options, regex, replacement, statusCode: StatusCodes.Status302Found); } /// @@ -83,7 +84,7 @@ namespace Microsoft.AspNetCore.Rewrite /// public static RewriteOptions AddRedirectToHttpsPermanent(this RewriteOptions options) { - return AddRedirectToHttps(options, statusCode: 301, sslPort: null); + return AddRedirectToHttps(options, statusCode: StatusCodes.Status301MovedPermanently, sslPort: null); } /// @@ -92,7 +93,7 @@ namespace Microsoft.AspNetCore.Rewrite /// The . public static RewriteOptions AddRedirectToHttps(this RewriteOptions options) { - return AddRedirectToHttps(options, statusCode: 302, sslPort: null); + return AddRedirectToHttps(options, statusCode: StatusCodes.Status302Found, sslPort: null); } /// diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/ApacheModRewrite/ModRewriteMiddlewareTest.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/ApacheModRewrite/ModRewriteMiddlewareTest.cs index bf0669ce26..3b1d962751 100644 --- a/test/Microsoft.AspNetCore.Rewrite.Tests/ApacheModRewrite/ModRewriteMiddlewareTest.cs +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/ApacheModRewrite/ModRewriteMiddlewareTest.cs @@ -247,7 +247,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.ModRewrite var response = await server.CreateClient().GetAsync(input); Assert.Equal(response.StatusCode, (HttpStatusCode)301); - Assert.Equal(response.Headers.Location.AbsoluteUri, @"https://www.example.com/foo/"); + Assert.Equal(@"https://www.example.com/foo/", response.Headers.Location.AbsoluteUri); } [Theory] diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/MiddlewareTests.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/MiddlewareTests.cs index ce041ff52c..43853ddfe5 100644 --- a/test/Microsoft.AspNetCore.Rewrite.Tests/MiddlewareTests.cs +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/MiddlewareTests.cs @@ -38,7 +38,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.CodeRules [Fact] public async Task CheckRedirectPath() { - var options = new RewriteOptions().AddRedirect("(.*)","http://example.com/$1", statusCode: 301); + var options = new RewriteOptions().AddRedirect("(.*)","http://example.com/$1", statusCode: StatusCodes.Status301MovedPermanently); var builder = new WebHostBuilder() .Configure(app => { @@ -54,7 +54,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.CodeRules [Fact] public async Task CheckRedirectToHttps() { - var options = new RewriteOptions().AddRedirectToHttps(statusCode: 301); + var options = new RewriteOptions().AddRedirectToHttps(statusCode: StatusCodes.Status301MovedPermanently); var builder = new WebHostBuilder() .Configure(app => { @@ -71,7 +71,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.CodeRules [Fact] public async Task CheckIfEmptyStringRedirectCorrectly() { - var options = new RewriteOptions().AddRedirect("(.*)", "$1", statusCode: 301); + var options = new RewriteOptions().AddRedirect("(.*)", "$1", statusCode: StatusCodes.Status301MovedPermanently); var builder = new WebHostBuilder() .Configure(app => { From 03b63e2c2a5ec27deef4be692ff2119188b67d73 Mon Sep 17 00:00:00 2001 From: Mikael Mengistu Date: Mon, 10 Oct 2016 16:16:56 -0700 Subject: [PATCH 128/307] Added more logging for rewrite/redirect scenarios --- samples/RewriteSample/UrlRewrite.xml | 4 +- .../RewriteMiddlewareLoggingExtensions.cs | 59 +++++++++++++++---- .../Internal/RedirectRule.cs | 4 ++ .../Internal/RedirectToHttpsRule.cs | 2 + .../Internal/RewriteRule.cs | 3 + .../RewriteMiddleware.cs | 7 ++- 6 files changed, 63 insertions(+), 16 deletions(-) diff --git a/samples/RewriteSample/UrlRewrite.xml b/samples/RewriteSample/UrlRewrite.xml index fee831050c..7ace7ba834 100644 --- a/samples/RewriteSample/UrlRewrite.xml +++ b/samples/RewriteSample/UrlRewrite.xml @@ -1,9 +1,9 @@  - + - + diff --git a/src/Microsoft.AspNetCore.Rewrite/Extensions/RewriteMiddlewareLoggingExtensions.cs b/src/Microsoft.AspNetCore.Rewrite/Extensions/RewriteMiddlewareLoggingExtensions.cs index 0d32fe6cfa..296a38fc83 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Extensions/RewriteMiddlewareLoggingExtensions.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Extensions/RewriteMiddlewareLoggingExtensions.cs @@ -8,28 +8,34 @@ namespace Microsoft.AspNetCore.Rewrite.Logging { internal static class RewriteMiddlewareLoggingExtensions { - private static readonly Action _requestContinueResults; + private static readonly Action _requestContinueResults; private static readonly Action _requestResponseComplete; - private static readonly Action _requestStopRules; + private static readonly Action _requestStopRules; private static readonly Action _urlRewriteDidNotMatchRule; private static readonly Action _urlRewriteMatchedRule; private static readonly Action _modRewriteDidNotMatchRule; private static readonly Action _modRewriteMatchedRule; + private static readonly Action _redirectedToHttps; + private static readonly Action _redirectSummary; + private static readonly Action _rewriteSummary; static RewriteMiddlewareLoggingExtensions() { - _requestContinueResults = LoggerMessage.Define( + _requestContinueResults = LoggerMessage.Define( LogLevel.Debug, 1, - "Request is continuing in applying rules."); + "Request is continuing in applying rules. Current url is {currentUrl}"); + _requestResponseComplete = LoggerMessage.Define( LogLevel.Debug, 2, - "Request is done processing, Location header '{Location}' with status code '{StatusCode}'."); - _requestStopRules = LoggerMessage.Define( + "Request is done processing. Location header '{Location}' with status code '{StatusCode}'."); + + _requestStopRules = LoggerMessage.Define( LogLevel.Debug, 3, - "Request is done applying rules."); + "Request is done applying rules. Url was rewritten to {rewrittenUrl}"); + _urlRewriteDidNotMatchRule = LoggerMessage.Define( LogLevel.Debug, 4, @@ -49,11 +55,26 @@ namespace Microsoft.AspNetCore.Rewrite.Logging LogLevel.Debug, 7, "Request matched current ModRewriteRule."); + + _redirectedToHttps = LoggerMessage.Define( + LogLevel.Information, + 8, + "Request redirected to HTTPS"); + + _redirectSummary = LoggerMessage.Define( + LogLevel.Information, + 9, + "Request was redirected to {redirectedUrl}"); + + _rewriteSummary = LoggerMessage.Define( + LogLevel.Information, + 10, + "Request was rewritten to {rewrittenUrl}"); } - public static void RewriteMiddlewareRequestContinueResults(this ILogger logger) + public static void RewriteMiddlewareRequestContinueResults(this ILogger logger, string currentUrl) { - _requestContinueResults(logger, null); + _requestContinueResults(logger, currentUrl, null); } public static void RewriteMiddlewareRequestResponseComplete(this ILogger logger, string location, int statusCode) @@ -61,9 +82,9 @@ namespace Microsoft.AspNetCore.Rewrite.Logging _requestResponseComplete(logger, location, statusCode, null); } - public static void RewriteMiddlewareRequestStopRules(this ILogger logger) + public static void RewriteMiddlewareRequestStopRules(this ILogger logger, string rewrittenUrl) { - _requestStopRules(logger, null); + _requestStopRules(logger, rewrittenUrl, null); } public static void UrlRewriteDidNotMatchRule(this ILogger logger, string name) @@ -80,9 +101,25 @@ namespace Microsoft.AspNetCore.Rewrite.Logging { _modRewriteDidNotMatchRule(logger, null); } + public static void ModRewriteMatchedRule(this ILogger logger) { _modRewriteMatchedRule(logger, null); } + + public static void RedirectedToHttps(this ILogger logger) + { + _redirectedToHttps(logger, null); + } + + public static void RedirectedSummary(this ILogger logger, string redirectedUrl) + { + _redirectSummary(logger, redirectedUrl, null); + } + + public static void RewriteSummary(this ILogger logger, string rewrittenUrl) + { + _rewriteSummary(logger, rewrittenUrl, null); + } } } diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/RedirectRule.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/RedirectRule.cs index 1198f27a6a..4f63bf6dd4 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/RedirectRule.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/RedirectRule.cs @@ -5,6 +5,7 @@ using System; using System.Text.RegularExpressions; using Microsoft.AspNetCore.Http; using Microsoft.Net.Http.Headers; +using Microsoft.AspNetCore.Rewrite.Logging; namespace Microsoft.AspNetCore.Rewrite.Internal { @@ -46,6 +47,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal initMatchResults = InitialMatch.Match(path.ToString().Substring(1)); } + if (initMatchResults.Success) { var newPath = initMatchResults.Result(Replacement); @@ -78,6 +80,8 @@ namespace Microsoft.AspNetCore.Rewrite.Internal { response.Headers[HeaderNames.Location] = pathBase + newPath; } + + context.Logger?.RedirectedSummary(newPath); } } } diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/RedirectToHttpsRule.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/RedirectToHttpsRule.cs index 6127785b06..6fb1fbf2b7 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/RedirectToHttpsRule.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/RedirectToHttpsRule.cs @@ -3,6 +3,7 @@ using System.Text; using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Rewrite.Logging; namespace Microsoft.AspNetCore.Rewrite.Internal { @@ -32,6 +33,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal var newUrl = new StringBuilder().Append("https://").Append(host).Append(req.PathBase).Append(req.Path).Append(req.QueryString); context.HttpContext.Response.Redirect(newUrl.ToString()); context.Result = RuleResult.EndResponse; + context.Logger?.RedirectedToHttps(); } } } diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/RewriteRule.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/RewriteRule.cs index d6452e8bc8..d9e0050857 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/RewriteRule.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/RewriteRule.cs @@ -5,6 +5,7 @@ using System; using System.Text.RegularExpressions; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http.Extensions; +using Microsoft.AspNetCore.Rewrite.Logging; namespace Microsoft.AspNetCore.Rewrite.Internal { @@ -103,6 +104,8 @@ namespace Microsoft.AspNetCore.Rewrite.Internal } } } + + context.Logger?.RewriteSummary(result); } } } diff --git a/src/Microsoft.AspNetCore.Rewrite/RewriteMiddleware.cs b/src/Microsoft.AspNetCore.Rewrite/RewriteMiddleware.cs index 58cd935690..953e5896c5 100644 --- a/src/Microsoft.AspNetCore.Rewrite/RewriteMiddleware.cs +++ b/src/Microsoft.AspNetCore.Rewrite/RewriteMiddleware.cs @@ -24,7 +24,7 @@ namespace Microsoft.AspNetCore.Rewrite private readonly ILogger _logger; /// - /// Creates a new instance of + /// Creates a new instance of /// /// The delegate representing the next middleware in the request pipeline. /// The Hosting Environment. @@ -75,10 +75,11 @@ namespace Microsoft.AspNetCore.Rewrite foreach (var rule in _options.Rules) { rule.ApplyRule(rewriteContext); + var currentUrl = new Lazy(() => context.Request.Path + context.Request.QueryString); switch (rewriteContext.Result) { case RuleResult.ContinueRules: - _logger.RewriteMiddlewareRequestContinueResults(); + _logger.RewriteMiddlewareRequestContinueResults(currentUrl.Value); break; case RuleResult.EndResponse: _logger.RewriteMiddlewareRequestResponseComplete( @@ -86,7 +87,7 @@ namespace Microsoft.AspNetCore.Rewrite context.Response.StatusCode); return TaskCache.CompletedTask; case RuleResult.SkipRemainingRules: - _logger.RewriteMiddlewareRequestStopRules(); + _logger.RewriteMiddlewareRequestStopRules(currentUrl.Value); return _next(context); default: throw new ArgumentOutOfRangeException($"Invalid rule termination {rewriteContext.Result}"); From 511d711620a0c26d8d6b82022c74216a4ff2a392 Mon Sep 17 00:00:00 2001 From: Chris R Date: Wed, 12 Oct 2016 11:28:50 -0700 Subject: [PATCH 129/307] #108 compression code cleanup --- samples/ResponseCompressionSample/Startup.cs | 4 +-- .../ResponseCompressionBuilderExtensions.cs | 30 +++++++++++++++++++ .../ResponseCompressionMiddleware.cs | 6 ++-- .../ResponseCompressionOptions.cs | 2 +- .../ResponseCompressionProvider.cs | 2 +- ... ResponseCompressionServicesExtensions.cs} | 18 ++--------- .../ResponseCompressionMiddlewareTest.cs | 4 +-- 7 files changed, 41 insertions(+), 25 deletions(-) create mode 100644 src/Microsoft.AspNetCore.ResponseCompression/ResponseCompressionBuilderExtensions.cs rename src/Microsoft.AspNetCore.ResponseCompression/{ResponseCompressionExtensions.cs => ResponseCompressionServicesExtensions.cs} (76%) diff --git a/samples/ResponseCompressionSample/Startup.cs b/samples/ResponseCompressionSample/Startup.cs index 17dd97bd39..142c8c1012 100644 --- a/samples/ResponseCompressionSample/Startup.cs +++ b/samples/ResponseCompressionSample/Startup.cs @@ -18,8 +18,8 @@ namespace ResponseCompressionSample { public void ConfigureServices(IServiceCollection services) { - services.AddTransient(); - services.AddTransient(); + services.AddSingleton(); + services.AddSingleton(); services.AddResponseCompression("text/plain", "text/html"); } diff --git a/src/Microsoft.AspNetCore.ResponseCompression/ResponseCompressionBuilderExtensions.cs b/src/Microsoft.AspNetCore.ResponseCompression/ResponseCompressionBuilderExtensions.cs new file mode 100644 index 0000000000..774aa5049a --- /dev/null +++ b/src/Microsoft.AspNetCore.ResponseCompression/ResponseCompressionBuilderExtensions.cs @@ -0,0 +1,30 @@ +// 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; +using Microsoft.AspNetCore.ResponseCompression; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection.Extensions; + +namespace Microsoft.AspNetCore.Builder +{ + /// + /// Extension methods for the ResponseCompression middleware. + /// + public static class ResponseCompressionBuilderExtensions + { + /// + /// Adds middleware for dynamically compressing HTTP Responses. + /// + /// The instance this method extends. + public static IApplicationBuilder UseResponseCompression(this IApplicationBuilder builder) + { + if (builder == null) + { + throw new ArgumentNullException(nameof(builder)); + } + + return builder.UseMiddleware(); + } + } +} diff --git a/src/Microsoft.AspNetCore.ResponseCompression/ResponseCompressionMiddleware.cs b/src/Microsoft.AspNetCore.ResponseCompression/ResponseCompressionMiddleware.cs index 692d77f643..b6841454d2 100644 --- a/src/Microsoft.AspNetCore.ResponseCompression/ResponseCompressionMiddleware.cs +++ b/src/Microsoft.AspNetCore.ResponseCompression/ResponseCompressionMiddleware.cs @@ -18,7 +18,7 @@ namespace Microsoft.AspNetCore.ResponseCompression private readonly IResponseCompressionProvider _provider; - private readonly bool _enableHttps; + private readonly bool _enableForHttps; /// /// Initialize the Response Compression middleware. @@ -43,7 +43,7 @@ namespace Microsoft.AspNetCore.ResponseCompression _next = next; _provider = provider; - _enableHttps = options.Value.EnableHttps; + _enableForHttps = options.Value.EnableForHttps; } /// @@ -55,7 +55,7 @@ namespace Microsoft.AspNetCore.ResponseCompression { ICompressionProvider compressionProvider = null; - if (!context.Request.IsHttps || _enableHttps) + if (!context.Request.IsHttps || _enableForHttps) { compressionProvider = _provider.GetCompressionProvider(context); } diff --git a/src/Microsoft.AspNetCore.ResponseCompression/ResponseCompressionOptions.cs b/src/Microsoft.AspNetCore.ResponseCompression/ResponseCompressionOptions.cs index 7d3b049984..e8d492efbd 100644 --- a/src/Microsoft.AspNetCore.ResponseCompression/ResponseCompressionOptions.cs +++ b/src/Microsoft.AspNetCore.ResponseCompression/ResponseCompressionOptions.cs @@ -19,6 +19,6 @@ namespace Microsoft.AspNetCore.ResponseCompression /// Indicates if responses over HTTPS connections should be compressed. The default is 'false'. /// Enable compression on HTTPS connections may expose security problems. /// - public bool EnableHttps { get; set; } = false; + public bool EnableForHttps { get; set; } = false; } } diff --git a/src/Microsoft.AspNetCore.ResponseCompression/ResponseCompressionProvider.cs b/src/Microsoft.AspNetCore.ResponseCompression/ResponseCompressionProvider.cs index 32376413c1..c37cfdcc66 100644 --- a/src/Microsoft.AspNetCore.ResponseCompression/ResponseCompressionProvider.cs +++ b/src/Microsoft.AspNetCore.ResponseCompression/ResponseCompressionProvider.cs @@ -41,7 +41,7 @@ namespace Microsoft.AspNetCore.ResponseCompression if (options.Value.MimeTypes == null || !options.Value.MimeTypes.Any()) { - throw new InvalidOperationException("No mime types specified"); + throw new InvalidOperationException("No MIME types specified"); } _mimeTypes = new HashSet(options.Value.MimeTypes, StringComparer.OrdinalIgnoreCase); } diff --git a/src/Microsoft.AspNetCore.ResponseCompression/ResponseCompressionExtensions.cs b/src/Microsoft.AspNetCore.ResponseCompression/ResponseCompressionServicesExtensions.cs similarity index 76% rename from src/Microsoft.AspNetCore.ResponseCompression/ResponseCompressionExtensions.cs rename to src/Microsoft.AspNetCore.ResponseCompression/ResponseCompressionServicesExtensions.cs index cb827c4fd1..6cd04a132c 100644 --- a/src/Microsoft.AspNetCore.ResponseCompression/ResponseCompressionExtensions.cs +++ b/src/Microsoft.AspNetCore.ResponseCompression/ResponseCompressionServicesExtensions.cs @@ -11,7 +11,7 @@ namespace Microsoft.AspNetCore.Builder /// /// Extension methods for the ResponseCompression middleware. /// - public static class ResponseCompressionExtensions + public static class ResponseCompressionServicesExtensions { /// /// Add response compression services and enable compression for responses with the given MIME types. @@ -45,22 +45,8 @@ namespace Microsoft.AspNetCore.Builder } services.Configure(configureOptions); - services.TryAddTransient(); + services.TryAddSingleton(); return services; } - - /// - /// Adds middleware for dynamically compressing HTTP Responses. - /// - /// The instance this method extends. - public static IApplicationBuilder UseResponseCompression(this IApplicationBuilder builder) - { - if (builder == null) - { - throw new ArgumentNullException(nameof(builder)); - } - - return builder.UseMiddleware(); - } } } diff --git a/test/Microsoft.AspNetCore.ResponseCompression.Tests/ResponseCompressionMiddlewareTest.cs b/test/Microsoft.AspNetCore.ResponseCompression.Tests/ResponseCompressionMiddlewareTest.cs index 8f468d8b03..08e3f88138 100644 --- a/test/Microsoft.AspNetCore.ResponseCompression.Tests/ResponseCompressionMiddlewareTest.cs +++ b/test/Microsoft.AspNetCore.ResponseCompression.Tests/ResponseCompressionMiddlewareTest.cs @@ -26,7 +26,7 @@ namespace Microsoft.AspNetCore.ResponseCompression.Tests { var options = new ResponseCompressionOptions(); - Assert.False(options.EnableHttps); + Assert.False(options.EnableForHttps); } [Fact] @@ -256,7 +256,7 @@ namespace Microsoft.AspNetCore.ResponseCompression.Tests { services.AddResponseCompression(options => { - options.EnableHttps = enableHttps; + options.EnableForHttps = enableHttps; options.MimeTypes = new[] { TextPlain }; }); }) From 151bb91997df83a8a060aeca9d2a65eda801e478 Mon Sep 17 00:00:00 2001 From: Pranav K Date: Wed, 12 Oct 2016 13:44:49 -0700 Subject: [PATCH 130/307] Updating to netcoreapp1.1 --- samples/HttpOverridesSample/project.json | 2 +- samples/ResponseBufferingSample/project.json | 2 +- samples/ResponseCompressionSample/project.json | 2 +- samples/RewriteSample/project.json | 2 +- test/Microsoft.AspNetCore.Buffering.Tests/project.json | 2 +- test/Microsoft.AspNetCore.HttpOverrides.Tests/project.json | 2 +- .../ResponseCompressionMiddlewareTest.cs | 6 +++--- .../project.json | 2 +- test/Microsoft.AspNetCore.Rewrite.Tests/project.json | 2 +- 9 files changed, 11 insertions(+), 11 deletions(-) diff --git a/samples/HttpOverridesSample/project.json b/samples/HttpOverridesSample/project.json index 9c93a8e1c0..2d0730a7d1 100644 --- a/samples/HttpOverridesSample/project.json +++ b/samples/HttpOverridesSample/project.json @@ -18,7 +18,7 @@ }, "frameworks": { "net451": {}, - "netcoreapp1.0": { + "netcoreapp1.1": { "dependencies": { "Microsoft.NETCore.App": { "version": "1.1.0-*", diff --git a/samples/ResponseBufferingSample/project.json b/samples/ResponseBufferingSample/project.json index d48a3acd1e..1cf3d053af 100644 --- a/samples/ResponseBufferingSample/project.json +++ b/samples/ResponseBufferingSample/project.json @@ -9,7 +9,7 @@ }, "frameworks": { "net451": {}, - "netcoreapp1.0": { + "netcoreapp1.1": { "dependencies": { "Microsoft.NETCore.App": { "version": "1.1.0-*", diff --git a/samples/ResponseCompressionSample/project.json b/samples/ResponseCompressionSample/project.json index 07bfa7363d..c5b1475701 100644 --- a/samples/ResponseCompressionSample/project.json +++ b/samples/ResponseCompressionSample/project.json @@ -13,7 +13,7 @@ }, "frameworks": { "net451": {}, - "netcoreapp1.0": { + "netcoreapp1.1": { "dependencies": { "Microsoft.NETCore.App": { "version": "1.1.0-*", diff --git a/samples/RewriteSample/project.json b/samples/RewriteSample/project.json index c70f27ff4e..3002dcf5a8 100644 --- a/samples/RewriteSample/project.json +++ b/samples/RewriteSample/project.json @@ -11,7 +11,7 @@ }, "frameworks": { "net451": {}, - "netcoreapp1.0": { + "netcoreapp1.1": { "dependencies": { "Microsoft.NETCore.App": { "version": "1.1.0-*", diff --git a/test/Microsoft.AspNetCore.Buffering.Tests/project.json b/test/Microsoft.AspNetCore.Buffering.Tests/project.json index feaf435f3f..0fa3b7ef85 100644 --- a/test/Microsoft.AspNetCore.Buffering.Tests/project.json +++ b/test/Microsoft.AspNetCore.Buffering.Tests/project.json @@ -10,7 +10,7 @@ "xunit": "2.2.0-*" }, "frameworks": { - "netcoreapp1.0": { + "netcoreapp1.1": { "dependencies": { "Microsoft.NETCore.App": { "version": "1.1.0-*", diff --git a/test/Microsoft.AspNetCore.HttpOverrides.Tests/project.json b/test/Microsoft.AspNetCore.HttpOverrides.Tests/project.json index e738c8d56f..461246f3db 100644 --- a/test/Microsoft.AspNetCore.HttpOverrides.Tests/project.json +++ b/test/Microsoft.AspNetCore.HttpOverrides.Tests/project.json @@ -11,7 +11,7 @@ "xunit": "2.2.0-*" }, "frameworks": { - "netcoreapp1.0": { + "netcoreapp1.1": { "dependencies": { "Microsoft.NETCore.App": { "version": "1.1.0-*", diff --git a/test/Microsoft.AspNetCore.ResponseCompression.Tests/ResponseCompressionMiddlewareTest.cs b/test/Microsoft.AspNetCore.ResponseCompression.Tests/ResponseCompressionMiddlewareTest.cs index 08e3f88138..048dc103f8 100644 --- a/test/Microsoft.AspNetCore.ResponseCompression.Tests/ResponseCompressionMiddlewareTest.cs +++ b/test/Microsoft.AspNetCore.ResponseCompression.Tests/ResponseCompressionMiddlewareTest.cs @@ -1,4 +1,4 @@ -// Copyright (c) .NET Foundation. All rights reserved. +// 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; @@ -496,7 +496,7 @@ namespace Microsoft.AspNetCore.ResponseCompression.Tests #if NET451 // Flush not supported, compression disabled Assert.NotNull(response.Headers.GetValues(HeaderNames.ContentMD5)); Assert.Empty(response.Content.Headers.ContentEncoding); -#elif NETCOREAPP1_0 // Flush supported, compression enabled +#elif NETCOREAPP1_1 // Flush supported, compression enabled IEnumerable contentMD5 = null; Assert.False(response.Headers.TryGetValues(HeaderNames.ContentMD5, out contentMD5)); Assert.Single(response.Content.Headers.ContentEncoding, "gzip"); @@ -561,7 +561,7 @@ namespace Microsoft.AspNetCore.ResponseCompression.Tests #if NET451 // Flush not supported, compression disabled Assert.NotNull(response.Headers.GetValues(HeaderNames.ContentMD5)); Assert.Empty(response.Content.Headers.ContentEncoding); -#elif NETCOREAPP1_0 // Flush supported, compression enabled +#elif NETCOREAPP1_1 // Flush supported, compression enabled IEnumerable contentMD5 = null; Assert.False(response.Headers.TryGetValues(HeaderNames.ContentMD5, out contentMD5)); Assert.Single(response.Content.Headers.ContentEncoding, "gzip"); diff --git a/test/Microsoft.AspNetCore.ResponseCompression.Tests/project.json b/test/Microsoft.AspNetCore.ResponseCompression.Tests/project.json index af9226646a..f9948f9d5d 100644 --- a/test/Microsoft.AspNetCore.ResponseCompression.Tests/project.json +++ b/test/Microsoft.AspNetCore.ResponseCompression.Tests/project.json @@ -15,7 +15,7 @@ "xunit": "2.2.0-*" }, "frameworks": { - "netcoreapp1.0": { + "netcoreapp1.1": { "dependencies": { "Microsoft.NETCore.App": { "version": "1.1.0-*", diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/project.json b/test/Microsoft.AspNetCore.Rewrite.Tests/project.json index 2126a3177f..cfdad1e4d5 100644 --- a/test/Microsoft.AspNetCore.Rewrite.Tests/project.json +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/project.json @@ -12,7 +12,7 @@ "xunit": "2.2.0-*" }, "frameworks": { - "netcoreapp1.0": { + "netcoreapp1.1": { "dependencies": { "Microsoft.CodeCoverage": { "type": "build", From 887bd70fd35495fdf4756927f5b966b2b883c355 Mon Sep 17 00:00:00 2001 From: Pranav K Date: Wed, 12 Oct 2016 16:07:55 -0700 Subject: [PATCH 131/307] Revert "Updating to netcoreapp1.1" This reverts commit 151bb91997df83a8a060aeca9d2a65eda801e478. --- samples/HttpOverridesSample/project.json | 2 +- samples/ResponseBufferingSample/project.json | 2 +- samples/ResponseCompressionSample/project.json | 2 +- samples/RewriteSample/project.json | 2 +- test/Microsoft.AspNetCore.Buffering.Tests/project.json | 2 +- test/Microsoft.AspNetCore.HttpOverrides.Tests/project.json | 2 +- .../ResponseCompressionMiddlewareTest.cs | 6 +++--- .../project.json | 2 +- test/Microsoft.AspNetCore.Rewrite.Tests/project.json | 2 +- 9 files changed, 11 insertions(+), 11 deletions(-) diff --git a/samples/HttpOverridesSample/project.json b/samples/HttpOverridesSample/project.json index 2d0730a7d1..9c93a8e1c0 100644 --- a/samples/HttpOverridesSample/project.json +++ b/samples/HttpOverridesSample/project.json @@ -18,7 +18,7 @@ }, "frameworks": { "net451": {}, - "netcoreapp1.1": { + "netcoreapp1.0": { "dependencies": { "Microsoft.NETCore.App": { "version": "1.1.0-*", diff --git a/samples/ResponseBufferingSample/project.json b/samples/ResponseBufferingSample/project.json index 1cf3d053af..d48a3acd1e 100644 --- a/samples/ResponseBufferingSample/project.json +++ b/samples/ResponseBufferingSample/project.json @@ -9,7 +9,7 @@ }, "frameworks": { "net451": {}, - "netcoreapp1.1": { + "netcoreapp1.0": { "dependencies": { "Microsoft.NETCore.App": { "version": "1.1.0-*", diff --git a/samples/ResponseCompressionSample/project.json b/samples/ResponseCompressionSample/project.json index c5b1475701..07bfa7363d 100644 --- a/samples/ResponseCompressionSample/project.json +++ b/samples/ResponseCompressionSample/project.json @@ -13,7 +13,7 @@ }, "frameworks": { "net451": {}, - "netcoreapp1.1": { + "netcoreapp1.0": { "dependencies": { "Microsoft.NETCore.App": { "version": "1.1.0-*", diff --git a/samples/RewriteSample/project.json b/samples/RewriteSample/project.json index 3002dcf5a8..c70f27ff4e 100644 --- a/samples/RewriteSample/project.json +++ b/samples/RewriteSample/project.json @@ -11,7 +11,7 @@ }, "frameworks": { "net451": {}, - "netcoreapp1.1": { + "netcoreapp1.0": { "dependencies": { "Microsoft.NETCore.App": { "version": "1.1.0-*", diff --git a/test/Microsoft.AspNetCore.Buffering.Tests/project.json b/test/Microsoft.AspNetCore.Buffering.Tests/project.json index 0fa3b7ef85..feaf435f3f 100644 --- a/test/Microsoft.AspNetCore.Buffering.Tests/project.json +++ b/test/Microsoft.AspNetCore.Buffering.Tests/project.json @@ -10,7 +10,7 @@ "xunit": "2.2.0-*" }, "frameworks": { - "netcoreapp1.1": { + "netcoreapp1.0": { "dependencies": { "Microsoft.NETCore.App": { "version": "1.1.0-*", diff --git a/test/Microsoft.AspNetCore.HttpOverrides.Tests/project.json b/test/Microsoft.AspNetCore.HttpOverrides.Tests/project.json index 461246f3db..e738c8d56f 100644 --- a/test/Microsoft.AspNetCore.HttpOverrides.Tests/project.json +++ b/test/Microsoft.AspNetCore.HttpOverrides.Tests/project.json @@ -11,7 +11,7 @@ "xunit": "2.2.0-*" }, "frameworks": { - "netcoreapp1.1": { + "netcoreapp1.0": { "dependencies": { "Microsoft.NETCore.App": { "version": "1.1.0-*", diff --git a/test/Microsoft.AspNetCore.ResponseCompression.Tests/ResponseCompressionMiddlewareTest.cs b/test/Microsoft.AspNetCore.ResponseCompression.Tests/ResponseCompressionMiddlewareTest.cs index 048dc103f8..08e3f88138 100644 --- a/test/Microsoft.AspNetCore.ResponseCompression.Tests/ResponseCompressionMiddlewareTest.cs +++ b/test/Microsoft.AspNetCore.ResponseCompression.Tests/ResponseCompressionMiddlewareTest.cs @@ -1,4 +1,4 @@ -// Copyright (c) .NET Foundation. All rights reserved. +// 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; @@ -496,7 +496,7 @@ namespace Microsoft.AspNetCore.ResponseCompression.Tests #if NET451 // Flush not supported, compression disabled Assert.NotNull(response.Headers.GetValues(HeaderNames.ContentMD5)); Assert.Empty(response.Content.Headers.ContentEncoding); -#elif NETCOREAPP1_1 // Flush supported, compression enabled +#elif NETCOREAPP1_0 // Flush supported, compression enabled IEnumerable contentMD5 = null; Assert.False(response.Headers.TryGetValues(HeaderNames.ContentMD5, out contentMD5)); Assert.Single(response.Content.Headers.ContentEncoding, "gzip"); @@ -561,7 +561,7 @@ namespace Microsoft.AspNetCore.ResponseCompression.Tests #if NET451 // Flush not supported, compression disabled Assert.NotNull(response.Headers.GetValues(HeaderNames.ContentMD5)); Assert.Empty(response.Content.Headers.ContentEncoding); -#elif NETCOREAPP1_1 // Flush supported, compression enabled +#elif NETCOREAPP1_0 // Flush supported, compression enabled IEnumerable contentMD5 = null; Assert.False(response.Headers.TryGetValues(HeaderNames.ContentMD5, out contentMD5)); Assert.Single(response.Content.Headers.ContentEncoding, "gzip"); diff --git a/test/Microsoft.AspNetCore.ResponseCompression.Tests/project.json b/test/Microsoft.AspNetCore.ResponseCompression.Tests/project.json index f9948f9d5d..af9226646a 100644 --- a/test/Microsoft.AspNetCore.ResponseCompression.Tests/project.json +++ b/test/Microsoft.AspNetCore.ResponseCompression.Tests/project.json @@ -15,7 +15,7 @@ "xunit": "2.2.0-*" }, "frameworks": { - "netcoreapp1.1": { + "netcoreapp1.0": { "dependencies": { "Microsoft.NETCore.App": { "version": "1.1.0-*", diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/project.json b/test/Microsoft.AspNetCore.Rewrite.Tests/project.json index cfdad1e4d5..2126a3177f 100644 --- a/test/Microsoft.AspNetCore.Rewrite.Tests/project.json +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/project.json @@ -12,7 +12,7 @@ "xunit": "2.2.0-*" }, "frameworks": { - "netcoreapp1.1": { + "netcoreapp1.0": { "dependencies": { "Microsoft.CodeCoverage": { "type": "build", From 61c8f49e3e1eef80099d190f36f4681bf48fbe98 Mon Sep 17 00:00:00 2001 From: Mikael Mengistu Date: Thu, 13 Oct 2016 10:13:52 -0700 Subject: [PATCH 132/307] Changing Rewrite version to 1.0.0 --- samples/RewriteSample/project.json | 3 +-- src/Microsoft.AspNetCore.Rewrite/project.json | 2 +- test/Microsoft.AspNetCore.Rewrite.Tests/project.json | 3 +-- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/samples/RewriteSample/project.json b/samples/RewriteSample/project.json index c70f27ff4e..f7b2714ddc 100644 --- a/samples/RewriteSample/project.json +++ b/samples/RewriteSample/project.json @@ -1,7 +1,6 @@ { - "version": "1.1.0-*", "dependencies": { - "Microsoft.AspNetCore.Rewrite": "1.1.0-*", + "Microsoft.AspNetCore.Rewrite": "1.0.0-*", "Microsoft.AspNetCore.Server.Kestrel": "1.1.0-*", "Microsoft.AspNetCore.Server.Kestrel.Https": "1.1.0-*" }, diff --git a/src/Microsoft.AspNetCore.Rewrite/project.json b/src/Microsoft.AspNetCore.Rewrite/project.json index 3b852df223..69833fe8f0 100644 --- a/src/Microsoft.AspNetCore.Rewrite/project.json +++ b/src/Microsoft.AspNetCore.Rewrite/project.json @@ -1,5 +1,5 @@ { - "version": "1.1.0-*", + "version": "1.0.0-*", "buildOptions": { "warningsAsErrors": true, "keyFile": "../../tools/Key.snk", diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/project.json b/test/Microsoft.AspNetCore.Rewrite.Tests/project.json index 2126a3177f..55fff74061 100644 --- a/test/Microsoft.AspNetCore.Rewrite.Tests/project.json +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/project.json @@ -1,12 +1,11 @@ { - "version": "1.1.0-*", "buildOptions": { "warningsAsErrors": true, "keyFile": "../../tools/Key.snk" }, "dependencies": { "dotnet-test-xunit": "2.2.0-*", - "Microsoft.AspNetCore.Rewrite": "1.1.0-*", + "Microsoft.AspNetCore.Rewrite": "1.0.0-*", "Microsoft.AspNetCore.TestHost": "1.1.0-*", "Microsoft.Extensions.Logging.Testing": "1.1.0-*", "xunit": "2.2.0-*" From 88b78e723397a22c18f01339cd6c1efadd881ee1 Mon Sep 17 00:00:00 2001 From: Pranav K Date: Thu, 13 Oct 2016 11:11:48 -0700 Subject: [PATCH 133/307] Updating to netcoreapp1.1 --- samples/HttpOverridesSample/project.json | 2 +- samples/ResponseBufferingSample/project.json | 2 +- samples/ResponseCompressionSample/project.json | 2 +- samples/RewriteSample/project.json | 2 +- test/Microsoft.AspNetCore.Buffering.Tests/project.json | 2 +- test/Microsoft.AspNetCore.HttpOverrides.Tests/project.json | 2 +- .../ResponseCompressionMiddlewareTest.cs | 6 +++--- .../project.json | 2 +- test/Microsoft.AspNetCore.Rewrite.Tests/project.json | 2 +- 9 files changed, 11 insertions(+), 11 deletions(-) diff --git a/samples/HttpOverridesSample/project.json b/samples/HttpOverridesSample/project.json index 9c93a8e1c0..2d0730a7d1 100644 --- a/samples/HttpOverridesSample/project.json +++ b/samples/HttpOverridesSample/project.json @@ -18,7 +18,7 @@ }, "frameworks": { "net451": {}, - "netcoreapp1.0": { + "netcoreapp1.1": { "dependencies": { "Microsoft.NETCore.App": { "version": "1.1.0-*", diff --git a/samples/ResponseBufferingSample/project.json b/samples/ResponseBufferingSample/project.json index d48a3acd1e..1cf3d053af 100644 --- a/samples/ResponseBufferingSample/project.json +++ b/samples/ResponseBufferingSample/project.json @@ -9,7 +9,7 @@ }, "frameworks": { "net451": {}, - "netcoreapp1.0": { + "netcoreapp1.1": { "dependencies": { "Microsoft.NETCore.App": { "version": "1.1.0-*", diff --git a/samples/ResponseCompressionSample/project.json b/samples/ResponseCompressionSample/project.json index 07bfa7363d..c5b1475701 100644 --- a/samples/ResponseCompressionSample/project.json +++ b/samples/ResponseCompressionSample/project.json @@ -13,7 +13,7 @@ }, "frameworks": { "net451": {}, - "netcoreapp1.0": { + "netcoreapp1.1": { "dependencies": { "Microsoft.NETCore.App": { "version": "1.1.0-*", diff --git a/samples/RewriteSample/project.json b/samples/RewriteSample/project.json index f7b2714ddc..eacc7ebe39 100644 --- a/samples/RewriteSample/project.json +++ b/samples/RewriteSample/project.json @@ -10,7 +10,7 @@ }, "frameworks": { "net451": {}, - "netcoreapp1.0": { + "netcoreapp1.1": { "dependencies": { "Microsoft.NETCore.App": { "version": "1.1.0-*", diff --git a/test/Microsoft.AspNetCore.Buffering.Tests/project.json b/test/Microsoft.AspNetCore.Buffering.Tests/project.json index feaf435f3f..0fa3b7ef85 100644 --- a/test/Microsoft.AspNetCore.Buffering.Tests/project.json +++ b/test/Microsoft.AspNetCore.Buffering.Tests/project.json @@ -10,7 +10,7 @@ "xunit": "2.2.0-*" }, "frameworks": { - "netcoreapp1.0": { + "netcoreapp1.1": { "dependencies": { "Microsoft.NETCore.App": { "version": "1.1.0-*", diff --git a/test/Microsoft.AspNetCore.HttpOverrides.Tests/project.json b/test/Microsoft.AspNetCore.HttpOverrides.Tests/project.json index e738c8d56f..461246f3db 100644 --- a/test/Microsoft.AspNetCore.HttpOverrides.Tests/project.json +++ b/test/Microsoft.AspNetCore.HttpOverrides.Tests/project.json @@ -11,7 +11,7 @@ "xunit": "2.2.0-*" }, "frameworks": { - "netcoreapp1.0": { + "netcoreapp1.1": { "dependencies": { "Microsoft.NETCore.App": { "version": "1.1.0-*", diff --git a/test/Microsoft.AspNetCore.ResponseCompression.Tests/ResponseCompressionMiddlewareTest.cs b/test/Microsoft.AspNetCore.ResponseCompression.Tests/ResponseCompressionMiddlewareTest.cs index 08e3f88138..048dc103f8 100644 --- a/test/Microsoft.AspNetCore.ResponseCompression.Tests/ResponseCompressionMiddlewareTest.cs +++ b/test/Microsoft.AspNetCore.ResponseCompression.Tests/ResponseCompressionMiddlewareTest.cs @@ -1,4 +1,4 @@ -// Copyright (c) .NET Foundation. All rights reserved. +// 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; @@ -496,7 +496,7 @@ namespace Microsoft.AspNetCore.ResponseCompression.Tests #if NET451 // Flush not supported, compression disabled Assert.NotNull(response.Headers.GetValues(HeaderNames.ContentMD5)); Assert.Empty(response.Content.Headers.ContentEncoding); -#elif NETCOREAPP1_0 // Flush supported, compression enabled +#elif NETCOREAPP1_1 // Flush supported, compression enabled IEnumerable contentMD5 = null; Assert.False(response.Headers.TryGetValues(HeaderNames.ContentMD5, out contentMD5)); Assert.Single(response.Content.Headers.ContentEncoding, "gzip"); @@ -561,7 +561,7 @@ namespace Microsoft.AspNetCore.ResponseCompression.Tests #if NET451 // Flush not supported, compression disabled Assert.NotNull(response.Headers.GetValues(HeaderNames.ContentMD5)); Assert.Empty(response.Content.Headers.ContentEncoding); -#elif NETCOREAPP1_0 // Flush supported, compression enabled +#elif NETCOREAPP1_1 // Flush supported, compression enabled IEnumerable contentMD5 = null; Assert.False(response.Headers.TryGetValues(HeaderNames.ContentMD5, out contentMD5)); Assert.Single(response.Content.Headers.ContentEncoding, "gzip"); diff --git a/test/Microsoft.AspNetCore.ResponseCompression.Tests/project.json b/test/Microsoft.AspNetCore.ResponseCompression.Tests/project.json index af9226646a..f9948f9d5d 100644 --- a/test/Microsoft.AspNetCore.ResponseCompression.Tests/project.json +++ b/test/Microsoft.AspNetCore.ResponseCompression.Tests/project.json @@ -15,7 +15,7 @@ "xunit": "2.2.0-*" }, "frameworks": { - "netcoreapp1.0": { + "netcoreapp1.1": { "dependencies": { "Microsoft.NETCore.App": { "version": "1.1.0-*", diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/project.json b/test/Microsoft.AspNetCore.Rewrite.Tests/project.json index 55fff74061..d0ad72b857 100644 --- a/test/Microsoft.AspNetCore.Rewrite.Tests/project.json +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/project.json @@ -11,7 +11,7 @@ "xunit": "2.2.0-*" }, "frameworks": { - "netcoreapp1.0": { + "netcoreapp1.1": { "dependencies": { "Microsoft.CodeCoverage": { "type": "build", From e7b41c4f53a5a511d9fd5c0bee86c4e22692418d Mon Sep 17 00:00:00 2001 From: Chris R Date: Thu, 13 Oct 2016 15:50:45 -0700 Subject: [PATCH 134/307] #108 Move compression providers back to options --- samples/ResponseCompressionSample/Startup.cs | 17 ++++--- .../CompressionProviderCollection.cs | 51 +++++++++++++++++++ .../CompressionProviderFactory.cs | 48 +++++++++++++++++ .../GzipCompressionProvider.cs | 25 ++++++--- .../GzipCompressionProviderOptions.cs | 23 +++++++++ .../ResponseCompressionOptions.cs | 5 ++ .../ResponseCompressionProvider.cs | 23 ++++++--- .../ResponseCompressionMiddlewareTest.cs | 33 ++++++++++++ 8 files changed, 204 insertions(+), 21 deletions(-) create mode 100644 src/Microsoft.AspNetCore.ResponseCompression/CompressionProviderCollection.cs create mode 100644 src/Microsoft.AspNetCore.ResponseCompression/CompressionProviderFactory.cs create mode 100644 src/Microsoft.AspNetCore.ResponseCompression/GzipCompressionProviderOptions.cs diff --git a/samples/ResponseCompressionSample/Startup.cs b/samples/ResponseCompressionSample/Startup.cs index 142c8c1012..3e297a88ec 100644 --- a/samples/ResponseCompressionSample/Startup.cs +++ b/samples/ResponseCompressionSample/Startup.cs @@ -2,7 +2,7 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; -using System.IO; +using System.IO.Compression; using System.Threading.Tasks; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; @@ -18,9 +18,13 @@ namespace ResponseCompressionSample { public void ConfigureServices(IServiceCollection services) { - services.AddSingleton(); - services.AddSingleton(); - services.AddResponseCompression("text/plain", "text/html"); + services.Configure(options => options.Level = CompressionLevel.Fastest); + services.AddResponseCompression(options => + { + options.Providers.Add(); + options.Providers.Add(); + options.MimeTypes = new[] { "text/plain", "text/html" }; + }); } public void Configure(IApplicationBuilder app) @@ -63,10 +67,7 @@ namespace ResponseCompressionSample public static void Main(string[] args) { var host = new WebHostBuilder() - .UseKestrel(options => - { - options.UseConnectionLogging(); - }) + .UseKestrel() // .UseWebListener() .ConfigureLogging(factory => { diff --git a/src/Microsoft.AspNetCore.ResponseCompression/CompressionProviderCollection.cs b/src/Microsoft.AspNetCore.ResponseCompression/CompressionProviderCollection.cs new file mode 100644 index 0000000000..71c6a6958f --- /dev/null +++ b/src/Microsoft.AspNetCore.ResponseCompression/CompressionProviderCollection.cs @@ -0,0 +1,51 @@ +// 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; +using System.Collections.ObjectModel; +#if NETSTANDARD1_3 +using System.Reflection; +#endif + +namespace Microsoft.AspNetCore.ResponseCompression +{ + /// + /// A Collection of ICompressionProvider's that also allows them to be instantiated from an . + /// + public class CompressionProviderCollection : Collection + { + /// + /// Adds a type representing an . + /// + /// + /// Provider instances will be created using an . + /// + public void Add() where TCompressionProvider : ICompressionProvider + { + Add(typeof(TCompressionProvider)); + } + + /// + /// Adds a type representing an . + /// + /// Type representing an . + /// + /// Provider instances will be created using an . + /// + public void Add(Type providerType) + { + if (providerType == null) + { + throw new ArgumentNullException(nameof(providerType)); + } + + if (!typeof(ICompressionProvider).IsAssignableFrom(providerType)) + { + throw new ArgumentException($"The provider must implement {nameof(ICompressionProvider)}", nameof(providerType)); + } + + var factory = new CompressionProviderFactory(providerType); + Add(factory); + } + } +} diff --git a/src/Microsoft.AspNetCore.ResponseCompression/CompressionProviderFactory.cs b/src/Microsoft.AspNetCore.ResponseCompression/CompressionProviderFactory.cs new file mode 100644 index 0000000000..715b0dfab1 --- /dev/null +++ b/src/Microsoft.AspNetCore.ResponseCompression/CompressionProviderFactory.cs @@ -0,0 +1,48 @@ +// 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; +using System.IO; +using Microsoft.Extensions.DependencyInjection; + +namespace Microsoft.AspNetCore.ResponseCompression +{ + /// + /// This is a placeholder for the CompressionProviderCollection that allows creating the given type via + /// an . + /// + internal class CompressionProviderFactory : ICompressionProvider + { + internal CompressionProviderFactory(Type providerType) + { + ProviderType = providerType; + } + + internal Type ProviderType { get; } + + internal ICompressionProvider CreateInstance(IServiceProvider serviceProvider) + { + if (serviceProvider == null) + { + throw new ArgumentNullException(nameof(serviceProvider)); + } + + return (ICompressionProvider)ActivatorUtilities.CreateInstance(serviceProvider, ProviderType, Type.EmptyTypes); + } + + string ICompressionProvider.EncodingName + { + get { throw new NotSupportedException(); } + } + + bool ICompressionProvider.SupportsFlush + { + get { throw new NotSupportedException(); } + } + + Stream ICompressionProvider.CreateStream(Stream outputStream) + { + throw new NotSupportedException(); + } + } +} \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.ResponseCompression/GzipCompressionProvider.cs b/src/Microsoft.AspNetCore.ResponseCompression/GzipCompressionProvider.cs index d605937492..b8c3c08517 100644 --- a/src/Microsoft.AspNetCore.ResponseCompression/GzipCompressionProvider.cs +++ b/src/Microsoft.AspNetCore.ResponseCompression/GzipCompressionProvider.cs @@ -1,8 +1,10 @@ // 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; using System.IO; using System.IO.Compression; +using Microsoft.Extensions.Options; namespace Microsoft.AspNetCore.ResponseCompression { @@ -11,6 +13,22 @@ namespace Microsoft.AspNetCore.ResponseCompression /// public class GzipCompressionProvider : ICompressionProvider { + /// + /// Creates a new instance of GzipCompressionProvider with options. + /// + /// + public GzipCompressionProvider(IOptions options) + { + if (options == null) + { + throw new ArgumentNullException(nameof(options)); + } + + Options = options.Value; + } + + private GzipCompressionProviderOptions Options { get; } + /// public string EncodingName => "gzip"; @@ -29,15 +47,10 @@ namespace Microsoft.AspNetCore.ResponseCompression } } - /// - /// What level of compression to use for the stream. - /// - public CompressionLevel Level { get; set; } = CompressionLevel.Fastest; - /// public Stream CreateStream(Stream outputStream) { - return new GZipStream(outputStream, Level, leaveOpen: true); + return new GZipStream(outputStream, Options.Level, leaveOpen: true); } } } diff --git a/src/Microsoft.AspNetCore.ResponseCompression/GzipCompressionProviderOptions.cs b/src/Microsoft.AspNetCore.ResponseCompression/GzipCompressionProviderOptions.cs new file mode 100644 index 0000000000..67993f602e --- /dev/null +++ b/src/Microsoft.AspNetCore.ResponseCompression/GzipCompressionProviderOptions.cs @@ -0,0 +1,23 @@ +// 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; +using System.IO.Compression; +using Microsoft.Extensions.Options; + +namespace Microsoft.AspNetCore.ResponseCompression +{ + /// + /// Options for the GzipCompressionProvider + /// + public class GzipCompressionProviderOptions : IOptions + { + /// + /// What level of compression to use for the stream. The default is Fastest. + /// + public CompressionLevel Level { get; set; } = CompressionLevel.Fastest; + + /// + GzipCompressionProviderOptions IOptions.Value => this; + } +} diff --git a/src/Microsoft.AspNetCore.ResponseCompression/ResponseCompressionOptions.cs b/src/Microsoft.AspNetCore.ResponseCompression/ResponseCompressionOptions.cs index e8d492efbd..c6b33c9737 100644 --- a/src/Microsoft.AspNetCore.ResponseCompression/ResponseCompressionOptions.cs +++ b/src/Microsoft.AspNetCore.ResponseCompression/ResponseCompressionOptions.cs @@ -20,5 +20,10 @@ namespace Microsoft.AspNetCore.ResponseCompression /// Enable compression on HTTPS connections may expose security problems. /// public bool EnableForHttps { get; set; } = false; + + /// + /// The ICompressionProviders to use for responses. + /// + public CompressionProviderCollection Providers { get; } = new CompressionProviderCollection(); } } diff --git a/src/Microsoft.AspNetCore.ResponseCompression/ResponseCompressionProvider.cs b/src/Microsoft.AspNetCore.ResponseCompression/ResponseCompressionProvider.cs index c37cfdcc66..696b0f3f43 100644 --- a/src/Microsoft.AspNetCore.ResponseCompression/ResponseCompressionProvider.cs +++ b/src/Microsoft.AspNetCore.ResponseCompression/ResponseCompressionProvider.cs @@ -20,28 +20,37 @@ namespace Microsoft.AspNetCore.ResponseCompression /// /// If no compression providers are specified then GZip is used by default. /// - /// Compression providers to use, if any. + /// Services to use when instantiating compression providers. /// - public ResponseCompressionProvider(IEnumerable providers, IOptions options) + public ResponseCompressionProvider(IServiceProvider services, IOptions options) { - if (providers == null) + if (services == null) { - throw new ArgumentNullException(nameof(providers)); + throw new ArgumentNullException(nameof(services)); } if (options == null) { throw new ArgumentNullException(nameof(options)); } - _providers = providers.ToArray(); + _providers = options.Value.Providers.ToArray(); if (_providers.Length == 0) { - _providers = new [] { new GzipCompressionProvider() }; + // Use the factory so it can resolve IOptions from DI. + _providers = new ICompressionProvider[] { new CompressionProviderFactory(typeof(GzipCompressionProvider)) }; + } + for (var i = 0; i < _providers.Length; i++) + { + var factory = _providers[i] as CompressionProviderFactory; + if (factory != null) + { + _providers[i] = factory.CreateInstance(services); + } } if (options.Value.MimeTypes == null || !options.Value.MimeTypes.Any()) { - throw new InvalidOperationException("No MIME types specified"); + throw new InvalidOperationException("No MIME types specified."); } _mimeTypes = new HashSet(options.Value.MimeTypes, StringComparer.OrdinalIgnoreCase); } diff --git a/test/Microsoft.AspNetCore.ResponseCompression.Tests/ResponseCompressionMiddlewareTest.cs b/test/Microsoft.AspNetCore.ResponseCompression.Tests/ResponseCompressionMiddlewareTest.cs index 048dc103f8..15f8750be1 100644 --- a/test/Microsoft.AspNetCore.ResponseCompression.Tests/ResponseCompressionMiddlewareTest.cs +++ b/test/Microsoft.AspNetCore.ResponseCompression.Tests/ResponseCompressionMiddlewareTest.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; using System.IO; +using System.IO.Compression; using System.Net.Http; using System.Threading; using System.Threading.Tasks; @@ -12,6 +13,7 @@ using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http.Features; using Microsoft.AspNetCore.TestHost; +using Microsoft.Extensions.DependencyInjection; using Microsoft.Net.Http.Headers; using Xunit; @@ -108,6 +110,37 @@ namespace Microsoft.AspNetCore.ResponseCompression.Tests CheckResponseCompressed(response, expectedBodyLength: 24); } + [Fact] + public async Task GZipCompressionProvider_OptionsSetInDI_Compress() + { + var builder = new WebHostBuilder() + .ConfigureServices(services => + { + services.Configure(options => options.Level = CompressionLevel.NoCompression); + services.AddResponseCompression(TextPlain); + }) + .Configure(app => + { + app.UseResponseCompression(); + app.Run(context => + { + context.Response.Headers[HeaderNames.ContentMD5] = "MD5"; + context.Response.ContentType = TextPlain; + return context.Response.WriteAsync(new string('a', 100)); + }); + }); + + var server = new TestServer(builder); + var client = server.CreateClient(); + + var request = new HttpRequestMessage(HttpMethod.Get, ""); + request.Headers.AcceptEncoding.ParseAdd("gzip"); + + var response = await client.SendAsync(request); + + CheckResponseCompressed(response, expectedBodyLength: 123); + } + [Theory] [InlineData("")] [InlineData("text/plain2")] From 1bd071de7a1d47be2d2d05fbdb3eedea47078515 Mon Sep 17 00:00:00 2001 From: Chris R Date: Fri, 14 Oct 2016 10:18:20 -0700 Subject: [PATCH 135/307] #108 Set default mime types to compress --- samples/ResponseCompressionSample/Startup.cs | 4 +- .../CompressionProviderCollection.cs | 2 +- .../CompressionProviderFactory.cs | 6 +- .../ResponseCompressionDefaults.cs | 32 +++++++++++ .../ResponseCompressionProvider.cs | 7 ++- .../ResponseCompressionServicesExtensions.cs | 14 +++-- .../ResponseCompressionMiddlewareTest.cs | 55 ++++++------------- 7 files changed, 68 insertions(+), 52 deletions(-) create mode 100644 src/Microsoft.AspNetCore.ResponseCompression/ResponseCompressionDefaults.cs diff --git a/samples/ResponseCompressionSample/Startup.cs b/samples/ResponseCompressionSample/Startup.cs index 3e297a88ec..bd49d928ad 100644 --- a/samples/ResponseCompressionSample/Startup.cs +++ b/samples/ResponseCompressionSample/Startup.cs @@ -3,6 +3,7 @@ using System; using System.IO.Compression; +using System.Linq; using System.Threading.Tasks; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; @@ -23,7 +24,8 @@ namespace ResponseCompressionSample { options.Providers.Add(); options.Providers.Add(); - options.MimeTypes = new[] { "text/plain", "text/html" }; + // .Append(TItem) is only available on Core. + options.MimeTypes = ResponseCompressionDefaults.MimeTypes.Concat(new[] { "image/svg+xml" }); }); } diff --git a/src/Microsoft.AspNetCore.ResponseCompression/CompressionProviderCollection.cs b/src/Microsoft.AspNetCore.ResponseCompression/CompressionProviderCollection.cs index 71c6a6958f..a04e920922 100644 --- a/src/Microsoft.AspNetCore.ResponseCompression/CompressionProviderCollection.cs +++ b/src/Microsoft.AspNetCore.ResponseCompression/CompressionProviderCollection.cs @@ -41,7 +41,7 @@ namespace Microsoft.AspNetCore.ResponseCompression if (!typeof(ICompressionProvider).IsAssignableFrom(providerType)) { - throw new ArgumentException($"The provider must implement {nameof(ICompressionProvider)}", nameof(providerType)); + throw new ArgumentException($"The provider must implement {nameof(ICompressionProvider)}.", nameof(providerType)); } var factory = new CompressionProviderFactory(providerType); diff --git a/src/Microsoft.AspNetCore.ResponseCompression/CompressionProviderFactory.cs b/src/Microsoft.AspNetCore.ResponseCompression/CompressionProviderFactory.cs index 715b0dfab1..50bfd267b3 100644 --- a/src/Microsoft.AspNetCore.ResponseCompression/CompressionProviderFactory.cs +++ b/src/Microsoft.AspNetCore.ResponseCompression/CompressionProviderFactory.cs @@ -13,14 +13,14 @@ namespace Microsoft.AspNetCore.ResponseCompression /// internal class CompressionProviderFactory : ICompressionProvider { - internal CompressionProviderFactory(Type providerType) + public CompressionProviderFactory(Type providerType) { ProviderType = providerType; } - internal Type ProviderType { get; } + private Type ProviderType { get; } - internal ICompressionProvider CreateInstance(IServiceProvider serviceProvider) + public ICompressionProvider CreateInstance(IServiceProvider serviceProvider) { if (serviceProvider == null) { diff --git a/src/Microsoft.AspNetCore.ResponseCompression/ResponseCompressionDefaults.cs b/src/Microsoft.AspNetCore.ResponseCompression/ResponseCompressionDefaults.cs new file mode 100644 index 0000000000..510d18786e --- /dev/null +++ b/src/Microsoft.AspNetCore.ResponseCompression/ResponseCompressionDefaults.cs @@ -0,0 +1,32 @@ +// 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.Collections.Generic; + +namespace Microsoft.AspNetCore.ResponseCompression +{ + /// + /// Defaults for the ResponseCompressionMiddleware + /// + public class ResponseCompressionDefaults + { + /// + /// Default MIME types to compress responses for. + /// + // This list is not intended to be exhaustive, it's a baseline for the 90% case. + public static readonly IEnumerable MimeTypes = new[] + { + // General + "text/plain", + // Static files + "text/css", + "application/javascript", + // MVC + "text/html", + "application/xml", + "text/xml", + "application/json", + "text/json", + }; + } +} diff --git a/src/Microsoft.AspNetCore.ResponseCompression/ResponseCompressionProvider.cs b/src/Microsoft.AspNetCore.ResponseCompression/ResponseCompressionProvider.cs index 696b0f3f43..b546a6045a 100644 --- a/src/Microsoft.AspNetCore.ResponseCompression/ResponseCompressionProvider.cs +++ b/src/Microsoft.AspNetCore.ResponseCompression/ResponseCompressionProvider.cs @@ -48,11 +48,12 @@ namespace Microsoft.AspNetCore.ResponseCompression } } - if (options.Value.MimeTypes == null || !options.Value.MimeTypes.Any()) + var mimeTypes = options.Value.MimeTypes; + if (mimeTypes == null || !mimeTypes.Any()) { - throw new InvalidOperationException("No MIME types specified."); + mimeTypes = ResponseCompressionDefaults.MimeTypes; } - _mimeTypes = new HashSet(options.Value.MimeTypes, StringComparer.OrdinalIgnoreCase); + _mimeTypes = new HashSet(mimeTypes, StringComparer.OrdinalIgnoreCase); } /// diff --git a/src/Microsoft.AspNetCore.ResponseCompression/ResponseCompressionServicesExtensions.cs b/src/Microsoft.AspNetCore.ResponseCompression/ResponseCompressionServicesExtensions.cs index 6cd04a132c..8d0b1ed2b3 100644 --- a/src/Microsoft.AspNetCore.ResponseCompression/ResponseCompressionServicesExtensions.cs +++ b/src/Microsoft.AspNetCore.ResponseCompression/ResponseCompressionServicesExtensions.cs @@ -14,17 +14,19 @@ namespace Microsoft.AspNetCore.Builder public static class ResponseCompressionServicesExtensions { /// - /// Add response compression services and enable compression for responses with the given MIME types. + /// Add response compression services. /// /// The for adding services. - /// Response Content-Type MIME types to enable compression for. /// - public static IServiceCollection AddResponseCompression(this IServiceCollection services, params string[] mimeTypes) + public static IServiceCollection AddResponseCompression(this IServiceCollection services) { - return services.AddResponseCompression(options => + if (services == null) { - options.MimeTypes = mimeTypes; - }); + throw new ArgumentNullException(nameof(services)); + } + + services.TryAddSingleton(); + return services; } /// diff --git a/test/Microsoft.AspNetCore.ResponseCompression.Tests/ResponseCompressionMiddlewareTest.cs b/test/Microsoft.AspNetCore.ResponseCompression.Tests/ResponseCompressionMiddlewareTest.cs index 15f8750be1..9c26de630d 100644 --- a/test/Microsoft.AspNetCore.ResponseCompression.Tests/ResponseCompressionMiddlewareTest.cs +++ b/test/Microsoft.AspNetCore.ResponseCompression.Tests/ResponseCompressionMiddlewareTest.cs @@ -55,27 +55,6 @@ namespace Microsoft.AspNetCore.ResponseCompression.Tests CheckResponseNotCompressed(response, expectedBodyLength: 100); } - [Fact] - public void NoMimeTypes_Throws() - { - var builder = new WebHostBuilder() - .ConfigureServices(services => - { - services.AddResponseCompression(); - }) - .Configure(app => - { - app.UseResponseCompression(); - app.Run(context => - { - context.Response.ContentType = TextPlain; - return context.Response.WriteAsync(new string('a', 100)); - }); - }); - - Assert.Throws(() => new TestServer(builder)); - } - [Theory] [InlineData("text/plain")] [InlineData("text/PLAIN")] @@ -86,7 +65,7 @@ namespace Microsoft.AspNetCore.ResponseCompression.Tests var builder = new WebHostBuilder() .ConfigureServices(services => { - services.AddResponseCompression(TextPlain); + services.AddResponseCompression(); }) .Configure(app => { @@ -117,7 +96,7 @@ namespace Microsoft.AspNetCore.ResponseCompression.Tests .ConfigureServices(services => { services.Configure(options => options.Level = CompressionLevel.NoCompression); - services.AddResponseCompression(TextPlain); + services.AddResponseCompression(); }) .Configure(app => { @@ -149,7 +128,7 @@ namespace Microsoft.AspNetCore.ResponseCompression.Tests var builder = new WebHostBuilder() .ConfigureServices(services => { - services.AddResponseCompression(TextPlain); + services.AddResponseCompression(); }) .Configure(app => { @@ -185,7 +164,7 @@ namespace Microsoft.AspNetCore.ResponseCompression.Tests var builder = new WebHostBuilder() .ConfigureServices(services => { - services.AddResponseCompression(TextPlain); + services.AddResponseCompression(); }) .Configure(app => { @@ -246,9 +225,9 @@ namespace Microsoft.AspNetCore.ResponseCompression.Tests } [Fact] - public async Task Response_UnauthorizedMimeType_NotCompressed() + public async Task Response_UnknownMimeType_NotCompressed() { - var response = await InvokeMiddleware(100, requestAcceptEncodings: new string[] { "gzip" }, responseType: "text/html"); + var response = await InvokeMiddleware(100, requestAcceptEncodings: new string[] { "gzip" }, responseType: "text/custom"); CheckResponseNotCompressed(response, expectedBodyLength: 100); } @@ -323,7 +302,7 @@ namespace Microsoft.AspNetCore.ResponseCompression.Tests var builder = new WebHostBuilder() .ConfigureServices(services => { - services.AddResponseCompression(TextPlain); + services.AddResponseCompression(); }) .Configure(app => { @@ -360,7 +339,7 @@ namespace Microsoft.AspNetCore.ResponseCompression.Tests var builder = new WebHostBuilder() .ConfigureServices(services => { - services.AddResponseCompression(TextPlain); + services.AddResponseCompression(); }) .Configure(app => { @@ -397,7 +376,7 @@ namespace Microsoft.AspNetCore.ResponseCompression.Tests var builder = new WebHostBuilder() .ConfigureServices(services => { - services.AddResponseCompression(TextPlain); + services.AddResponseCompression(); }) .Configure(app => { @@ -444,7 +423,7 @@ namespace Microsoft.AspNetCore.ResponseCompression.Tests var builder = new WebHostBuilder() .ConfigureServices(services => { - services.AddResponseCompression(TextPlain); + services.AddResponseCompression(); }) .Configure(app => { @@ -497,7 +476,7 @@ namespace Microsoft.AspNetCore.ResponseCompression.Tests var builder = new WebHostBuilder() .ConfigureServices(services => { - services.AddResponseCompression(TextPlain); + services.AddResponseCompression(); }) .Configure(app => { @@ -563,7 +542,7 @@ namespace Microsoft.AspNetCore.ResponseCompression.Tests var builder = new WebHostBuilder() .ConfigureServices(services => { - services.AddResponseCompression(TextPlain); + services.AddResponseCompression(); }) .Configure(app => { @@ -619,7 +598,7 @@ namespace Microsoft.AspNetCore.ResponseCompression.Tests var builder = new WebHostBuilder() .ConfigureServices(services => { - services.AddResponseCompression(TextPlain); + services.AddResponseCompression(); }) .Configure(app => { @@ -653,7 +632,7 @@ namespace Microsoft.AspNetCore.ResponseCompression.Tests var builder = new WebHostBuilder() .ConfigureServices(services => { - services.AddResponseCompression(TextPlain); + services.AddResponseCompression(); }) .Configure(app => { @@ -696,7 +675,7 @@ namespace Microsoft.AspNetCore.ResponseCompression.Tests var builder = new WebHostBuilder() .ConfigureServices(services => { - services.AddResponseCompression(TextPlain); + services.AddResponseCompression(); }) .Configure(app => { @@ -739,7 +718,7 @@ namespace Microsoft.AspNetCore.ResponseCompression.Tests var builder = new WebHostBuilder() .ConfigureServices(services => { - services.AddResponseCompression(TextPlain); + services.AddResponseCompression(); }) .Configure(app => { @@ -780,7 +759,7 @@ namespace Microsoft.AspNetCore.ResponseCompression.Tests var builder = new WebHostBuilder() .ConfigureServices(services => { - services.AddResponseCompression(TextPlain); + services.AddResponseCompression(); }) .Configure(app => { From cfe8518fa4a987f9aaeec969ec498098b68b0714 Mon Sep 17 00:00:00 2001 From: Chris R Date: Fri, 14 Oct 2016 11:12:36 -0700 Subject: [PATCH 136/307] Raise ResponseCompression version from 0.1 to 1.0 --- samples/ResponseCompressionSample/project.json | 2 +- src/Microsoft.AspNetCore.ResponseCompression/project.json | 2 +- .../project.json | 3 +-- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/samples/ResponseCompressionSample/project.json b/samples/ResponseCompressionSample/project.json index c5b1475701..66e8ca15f8 100644 --- a/samples/ResponseCompressionSample/project.json +++ b/samples/ResponseCompressionSample/project.json @@ -1,6 +1,6 @@ { "dependencies": { - "Microsoft.AspNetCore.ResponseCompression": "0.1.0-*", + "Microsoft.AspNetCore.ResponseCompression": "1.0.0-*", "Microsoft.AspNetCore.Server.Kestrel": "1.1.0-*", "Microsoft.AspNetCore.Server.WebListener": "1.1.0-*", "Microsoft.Extensions.Logging.Console": "1.1.0-*" diff --git a/src/Microsoft.AspNetCore.ResponseCompression/project.json b/src/Microsoft.AspNetCore.ResponseCompression/project.json index cc3a281c15..a5ec506c84 100644 --- a/src/Microsoft.AspNetCore.ResponseCompression/project.json +++ b/src/Microsoft.AspNetCore.ResponseCompression/project.json @@ -1,5 +1,5 @@ { - "version": "0.1.0-*", + "version": "1.0.0-*", "buildOptions": { "warningsAsErrors": true, "keyFile": "../../tools/Key.snk", diff --git a/test/Microsoft.AspNetCore.ResponseCompression.Tests/project.json b/test/Microsoft.AspNetCore.ResponseCompression.Tests/project.json index f9948f9d5d..27f2b146f3 100644 --- a/test/Microsoft.AspNetCore.ResponseCompression.Tests/project.json +++ b/test/Microsoft.AspNetCore.ResponseCompression.Tests/project.json @@ -1,5 +1,4 @@ { - "version": "1.1.0-*", "buildOptions": { "copyToOutput": [ "testfile1kb.txt" @@ -9,7 +8,7 @@ "dependencies": { "dotnet-test-xunit": "2.2.0-*", "Microsoft.AspNetCore.Http": "1.1.0-*", - "Microsoft.AspNetCore.ResponseCompression": "0.1.0-*", + "Microsoft.AspNetCore.ResponseCompression": "1.0.0-*", "Microsoft.AspNetCore.TestHost": "1.1.0-*", "Microsoft.Net.Http.Headers": "1.1.0-*", "xunit": "2.2.0-*" From 13c145780c9902605a14e06c36f8c165f491650b Mon Sep 17 00:00:00 2001 From: Mikael Mengistu Date: Fri, 14 Oct 2016 17:21:41 -0700 Subject: [PATCH 137/307] Changed url rewrite sample regex to be more specific --- samples/RewriteSample/UrlRewrite.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/samples/RewriteSample/UrlRewrite.xml b/samples/RewriteSample/UrlRewrite.xml index 7ace7ba834..3d3d057787 100644 --- a/samples/RewriteSample/UrlRewrite.xml +++ b/samples/RewriteSample/UrlRewrite.xml @@ -1,7 +1,7 @@  - + From 7fc30f60bb1df613907f61f3e4889adbfdf49ff8 Mon Sep 17 00:00:00 2001 From: Pranav K Date: Mon, 17 Oct 2016 09:48:39 -0700 Subject: [PATCH 138/307] Branching for 1.1.0-preview1 --- NuGet.config | 4 ++-- build.ps1 | 2 +- build.sh | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/NuGet.config b/NuGet.config index a696a0a743..1b1203d77e 100644 --- a/NuGet.config +++ b/NuGet.config @@ -1,7 +1,7 @@ - + - + \ No newline at end of file diff --git a/build.ps1 b/build.ps1 index 8f2f99691a..787f63ac02 100644 --- a/build.ps1 +++ b/build.ps1 @@ -33,7 +33,7 @@ cd $PSScriptRoot $repoFolder = $PSScriptRoot $env:REPO_FOLDER = $repoFolder -$koreBuildZip="https://github.com/aspnet/KoreBuild/archive/dev.zip" +$koreBuildZip="https://github.com/aspnet/KoreBuild/archive/rel/1.1.0-preview1.zip" if ($env:KOREBUILD_ZIP) { $koreBuildZip=$env:KOREBUILD_ZIP diff --git a/build.sh b/build.sh index f4208100eb..355c682856 100755 --- a/build.sh +++ b/build.sh @@ -2,7 +2,7 @@ repoFolder="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" cd $repoFolder -koreBuildZip="https://github.com/aspnet/KoreBuild/archive/dev.zip" +koreBuildZip="https://github.com/aspnet/KoreBuild/archive/rel/1.1.0-preview1.zip" if [ ! -z $KOREBUILD_ZIP ]; then koreBuildZip=$KOREBUILD_ZIP fi From 061f22be61ca796a58835ca11d3194889bdb9eef Mon Sep 17 00:00:00 2001 From: Mikael Mengistu Date: Mon, 17 Oct 2016 11:23:29 -0700 Subject: [PATCH 139/307] Updated package descriptions for the HttpOveride and Rewrite middleware --- src/Microsoft.AspNetCore.HttpOverrides/project.json | 2 +- src/Microsoft.AspNetCore.Rewrite/project.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Microsoft.AspNetCore.HttpOverrides/project.json b/src/Microsoft.AspNetCore.HttpOverrides/project.json index fd3441eefc..14af60066c 100644 --- a/src/Microsoft.AspNetCore.HttpOverrides/project.json +++ b/src/Microsoft.AspNetCore.HttpOverrides/project.json @@ -8,7 +8,7 @@ ], "xmlDoc": true }, - "description": "ASP.NET Core basic middleware for:\r\nX-Forwarded-* headers to forward headers from a proxy.\r\nHTTP method override header.", + "description": "ASP.NET Core basic middleware for supporting HTTP method overrides. Includes:\r\n* X-Forwarded-* headers to forward headers from a proxy.\r\n* HTTP method override header.", "packOptions": { "repository": { "type": "git", diff --git a/src/Microsoft.AspNetCore.Rewrite/project.json b/src/Microsoft.AspNetCore.Rewrite/project.json index 69833fe8f0..e9f3c91ce5 100644 --- a/src/Microsoft.AspNetCore.Rewrite/project.json +++ b/src/Microsoft.AspNetCore.Rewrite/project.json @@ -8,7 +8,7 @@ ], "xmlDoc": true }, - "description": "ASP.NET Core basic middleware for:\r\nRewrite Url module.", + "description": "ASP.NET Core basic middleware for rewriting URLs. Includes:\r\n* Support for custom URL rewrite rules\r\n* Support for running IIS URL Rewrite module rules\r\n* Support for running Apache mod_rewrite rules.", "packOptions": { "repository": { "type": "git", From 88aff41b78dcf8a4c00d71f2c2fa4c34757cafcf Mon Sep 17 00:00:00 2001 From: Mikael Mengistu Date: Mon, 24 Oct 2016 11:34:33 -0700 Subject: [PATCH 140/307] Fixed exception messages for server variable parsing --- .../ApacheModRewrite/ServerVariables.cs | 26 +++++++++---------- .../Internal/IISUrlRewrite/InputParser.cs | 2 +- .../Internal/IISUrlRewrite/ServerVariables.cs | 10 +++---- .../IISUrlRewrite/ServerVariableTests.cs | 3 ++- 4 files changed, 21 insertions(+), 20 deletions(-) diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/ApacheModRewrite/ServerVariables.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/ApacheModRewrite/ServerVariables.cs index eb3e73f895..2b44331a15 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/ApacheModRewrite/ServerVariables.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/ApacheModRewrite/ServerVariables.cs @@ -16,12 +16,12 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.ApacheModRewrite /// /// Translates mod_rewrite server variables strings to an enum of different server variables. /// - /// The server variable string. + /// The server variable string. /// The Parser context /// The appropriate enum if the server variable exists, else ServerVariable.None - public static PatternSegment FindServerVariable(string variable, ParserContext context) + public static PatternSegment FindServerVariable(string serverVariable, ParserContext context) { - switch (variable) + switch (serverVariable) { case "HTTP_ACCEPT": return new HeaderSegment(HeaderNames.Accept); @@ -84,23 +84,23 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.ApacheModRewrite case "SERVER_SOFTWARE": throw new NotSupportedException("Rules using the SERVER_SOFTWARE server variable are not supported"); case "TIME_YEAR": - return new DateTimeSegment(variable); + return new DateTimeSegment(serverVariable); case "TIME_MON": - return new DateTimeSegment(variable); + return new DateTimeSegment(serverVariable); case "TIME_DAY": - return new DateTimeSegment(variable); + return new DateTimeSegment(serverVariable); case "TIME_HOUR": - return new DateTimeSegment(variable); + return new DateTimeSegment(serverVariable); case "TIME_MIN": - return new DateTimeSegment(variable); + return new DateTimeSegment(serverVariable); case "TIME_SEC": - return new DateTimeSegment(variable); + return new DateTimeSegment(serverVariable); case "TIME_WDAY": - return new DateTimeSegment(variable); + return new DateTimeSegment(serverVariable); case "TIME": - return new DateTimeSegment(variable); + return new DateTimeSegment(serverVariable); case "API_VERSION": - throw new NotSupportedException(); + throw new NotSupportedException("Rules using the API_VERSION server variable are not supported"); case "HTTPS": return new IsHttpsModSegment(); case "HTTP2": @@ -116,7 +116,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.ApacheModRewrite case "THE_REQUEST": throw new NotSupportedException("Rules using the THE_REQUEST server variable are not supported"); default: - throw new FormatException(Resources.FormatError_InputParserUnrecognizedParameter(variable, context.Index)); + throw new FormatException(Resources.FormatError_InputParserUnrecognizedParameter(serverVariable, context.Index)); } } } diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/InputParser.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/InputParser.cs index 392680376f..8a944972da 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/InputParser.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/InputParser.cs @@ -75,7 +75,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite { // This is just a server variable, so we do a lookup and verify the server variable exists. parameter = context.Capture(); - results.Add(ServerVariables.FindServerVariable(parameter)); + results.Add(ServerVariables.FindServerVariable(parameter, context)); return; } else if (context.Current == Colon) diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/ServerVariables.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/ServerVariables.cs index 35112b78bb..a9c92a9a6c 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/ServerVariables.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/ServerVariables.cs @@ -9,15 +9,15 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite { public static class ServerVariables { - public static PatternSegment FindServerVariable(string serverVariable) + public static PatternSegment FindServerVariable(string serverVariable, ParserContext context) { switch (serverVariable) { // TODO Add all server variables here. case "ALL_RAW": - throw new NotSupportedException("Rules using the AUTH_TYPE server variable are not supported"); + throw new NotSupportedException("Rules using the ALL_RAW server variable are not supported"); case "APP_POOL_ID": - throw new NotSupportedException("Rules using the AUTH_TYPE server variable are not supported"); + throw new NotSupportedException("Rules using the APP_POOL_ID server variable are not supported"); case "CONTENT_LENGTH": return new HeaderSegment(HeaderNames.ContentLength); case "CONTENT_TYPE": @@ -41,7 +41,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite case "LOCAL_ADDR": return new LocalAddressSegment(); case "HTTP_PROXY_CONNECTION": - throw new NotSupportedException("Rules using the AUTH_TYPE server variable are not supported"); + throw new NotSupportedException("Rules using the HTTP_PROXY_CONNECTION server variable are not supported"); case "QUERY_STRING": return new QueryStringSegment(); case "REMOTE_ADDR": @@ -55,7 +55,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite case "REQUEST_URI": return new UrlSegment(); default: - throw new FormatException("Unrecognized server variable"); + throw new FormatException(Resources.FormatError_InputParserUnrecognizedParameter(serverVariable, context.Index)); } } } diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/ServerVariableTests.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/ServerVariableTests.cs index 3235ab7d1e..dd35c76c25 100644 --- a/test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/ServerVariableTests.cs +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/ServerVariableTests.cs @@ -27,7 +27,8 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite public void CheckServerVariableParsingAndApplication(string variable, string expected) { // Arrange and Act - var serverVar = ServerVariables.FindServerVariable(variable); + var testParserContext = new ParserContext("test"); + var serverVar = ServerVariables.FindServerVariable(variable, testParserContext); var lookup = serverVar.Evaluate(CreateTestHttpContext(), CreateTestRuleMatch(), CreateTestCondMatch()); // Assert Assert.Equal(expected, lookup); From 2a153b38fea095bb49285f65dde7c47b1c3986b5 Mon Sep 17 00:00:00 2001 From: Mikael Mengistu Date: Mon, 24 Oct 2016 12:39:42 -0700 Subject: [PATCH 141/307] Fixed enable and negate flag issue. --- .../IISUrlRewrite/UrlRewriteFileParser.cs | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/UrlRewriteFileParser.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/UrlRewriteFileParser.cs index a7f624f82f..e73df77bb4 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/UrlRewriteFileParser.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/UrlRewriteFileParser.cs @@ -38,6 +38,11 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite return; } + if (string.Equals(rules.Name.ToString(), "GlobalRules", StringComparison.OrdinalIgnoreCase)) + { + throw new NotSupportedException("Support for global rules has not been implemented yet"); + } + foreach (var rule in rules.Elements(RewriteTags.Rule)) { var builder = new UrlRewriteRuleBuilder(); @@ -59,6 +64,17 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite { builder.Enabled = true; } + else + { + if (enabled) + { + builder.Enabled = enabled; + } + else + { + return; + } + } PatternSyntax patternSyntax; if (!Enum.TryParse(rule.Attribute(RewriteTags.PatternSyntax)?.Value, out patternSyntax)) @@ -149,7 +165,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite bool negate; if (!bool.TryParse(condition.Attribute(RewriteTags.Negate)?.Value, out negate)) { - ignoreCase = false; + negate = false; } MatchType matchType; From 67c93a9acd8d002a935875a03f1d127a5fb2a416 Mon Sep 17 00:00:00 2001 From: Mikael Mengistu Date: Wed, 26 Oct 2016 14:06:29 -0700 Subject: [PATCH 142/307] Removed the ? prefix from the QUERY_STRING server variable --- .../Internal/PatternSegments/QueryStringSegment.cs | 9 ++++++++- .../IISUrlRewrite/ServerVariableTests.cs | 14 +++++++++++++- .../PatternSegments/QueryStringSegmentTests.cs | 5 +---- 3 files changed, 22 insertions(+), 6 deletions(-) diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/QueryStringSegment.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/QueryStringSegment.cs index 86341bc5a8..bb1118e864 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/QueryStringSegment.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/QueryStringSegment.cs @@ -7,7 +7,14 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.PatternSegments { public override string Evaluate(RewriteContext context, MatchResults ruleMatch, MatchResults condMatch) { - return context.HttpContext.Request.QueryString.ToString(); + var queryString = context.HttpContext.Request.QueryString.ToString(); + + if (!string.IsNullOrEmpty(queryString)) + { + return queryString.Substring(1); + } + + return queryString; } } } diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/ServerVariableTests.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/ServerVariableTests.cs index dd35c76c25..19c49d8a66 100644 --- a/test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/ServerVariableTests.cs +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/ServerVariableTests.cs @@ -22,7 +22,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite [InlineData("HTTP_USER_AGENT", "useragent")] [InlineData("HTTP_CONNECTION", "connection")] [InlineData("HTTP_URL", "/foo")] - [InlineData("QUERY_STRING", "?bar=1")] + [InlineData("QUERY_STRING", "bar=1")] [InlineData("REQUEST_FILENAME", "/foo")] public void CheckServerVariableParsingAndApplication(string variable, string expected) { @@ -61,5 +61,17 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite var match = Regex.Match("foo/bar/baz", "(.*)/(.*)/(.*)"); return new MatchResults { BackReference = match.Groups, Success = match.Success }; } + + [Fact] + private void EmptyQueryStringCheck() + { + var context = new DefaultHttpContext(); + var rewriteContext = new RewriteContext { HttpContext = context }; + var testParserContext = new ParserContext("test"); + var serverVar = ServerVariables.FindServerVariable("QUERY_STRING", testParserContext); + var lookup = serverVar.Evaluate(rewriteContext, CreateTestRuleMatch(), CreateTestCondMatch()); + + Assert.Equal(string.Empty, lookup); + } } } diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/PatternSegments/QueryStringSegmentTests.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/PatternSegments/QueryStringSegmentTests.cs index a02986fc16..3e7190ef9d 100644 --- a/test/Microsoft.AspNetCore.Rewrite.Tests/PatternSegments/QueryStringSegmentTests.cs +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/PatternSegments/QueryStringSegmentTests.cs @@ -12,16 +12,13 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.PatternSegments [Fact] public void QueryString_AssertSegmentIsCorrect() { - // Arrange var segement = new QueryStringSegment(); var context = new RewriteContext { HttpContext = new DefaultHttpContext() }; context.HttpContext.Request.QueryString = new QueryString("?hey=1"); - // Act var results = segement.Evaluate(context, null, null); - // Assert - Assert.Equal("?hey=1", results); + Assert.Equal("hey=1", results); } } } From f0b44ac7b51ffd53051aeef3846c1cdaf07e9bc6 Mon Sep 17 00:00:00 2001 From: Pavel Krymets Date: Thu, 27 Oct 2016 14:12:59 -0700 Subject: [PATCH 143/307] Check Accept-Encoding headers before creating compression provider (#154) --- .../BodyWrapperStream.cs | 115 +++++++--- .../IResponseCompressionProvider.cs | 7 + .../Properties/AssemblyInfo.cs | 3 + .../ResponseCompressionMiddleware.cs | 20 +- .../ResponseCompressionProvider.cs | 18 ++ .../BodyWrapperStreamTests.cs | 211 ++++++++++++++++++ .../project.json | 2 + 7 files changed, 325 insertions(+), 51 deletions(-) create mode 100644 test/Microsoft.AspNetCore.ResponseCompression.Tests/BodyWrapperStreamTests.cs diff --git a/src/Microsoft.AspNetCore.ResponseCompression/BodyWrapperStream.cs b/src/Microsoft.AspNetCore.ResponseCompression/BodyWrapperStream.cs index 1b82521668..93197fa1a2 100644 --- a/src/Microsoft.AspNetCore.ResponseCompression/BodyWrapperStream.cs +++ b/src/Microsoft.AspNetCore.ResponseCompression/BodyWrapperStream.cs @@ -17,23 +17,24 @@ namespace Microsoft.AspNetCore.ResponseCompression /// internal class BodyWrapperStream : Stream, IHttpBufferingFeature, IHttpSendFileFeature { - private readonly HttpResponse _response; + private readonly HttpContext _context; private readonly Stream _bodyOriginalStream; private readonly IResponseCompressionProvider _provider; - private readonly ICompressionProvider _compressionProvider; private readonly IHttpBufferingFeature _innerBufferFeature; private readonly IHttpSendFileFeature _innerSendFileFeature; + private ICompressionProvider _compressionProvider = null; private bool _compressionChecked = false; private Stream _compressionStream = null; + private bool _providerCreated = false; + private bool _autoFlush = false; - internal BodyWrapperStream(HttpResponse response, Stream bodyOriginalStream, IResponseCompressionProvider provider, ICompressionProvider compressionProvider, + internal BodyWrapperStream(HttpContext context, Stream bodyOriginalStream, IResponseCompressionProvider provider, IHttpBufferingFeature innerBufferFeature, IHttpSendFileFeature innerSendFileFeature) { - _response = response; + _context = context; _bodyOriginalStream = bodyOriginalStream; _provider = provider; - _compressionProvider = compressionProvider; _innerBufferFeature = innerBufferFeature; _innerSendFileFeature = innerSendFileFeature; } @@ -125,6 +126,10 @@ namespace Microsoft.AspNetCore.ResponseCompression if (_compressionStream != null) { _compressionStream.Write(buffer, offset, count); + if (_autoFlush) + { + _compressionStream.Flush(); + } } else { @@ -133,44 +138,70 @@ namespace Microsoft.AspNetCore.ResponseCompression } #if NET451 - public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object state) + public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, Object state) { - OnWrite(); + var tcs = new TaskCompletionSource(state); + InternalWriteAsync(buffer, offset, count, callback, tcs); + return tcs.Task; + } - if (_compressionStream != null) + private async void InternalWriteAsync(byte[] buffer, int offset, int count, AsyncCallback callback, TaskCompletionSource tcs) + { + try { - return _compressionStream.BeginWrite(buffer, offset, count, callback, state); + await WriteAsync(buffer, offset, count); + tcs.TrySetResult(null); + } + catch (Exception ex) + { + tcs.TrySetException(ex); + } + + if (callback != null) + { + // Offload callbacks to avoid stack dives on sync completions. + var ignored = Task.Run(() => + { + try + { + callback(tcs.Task); + } + catch (Exception) + { + // Suppress exceptions on background threads. + } + }); } - return _bodyOriginalStream.BeginWrite(buffer, offset, count, callback, state); } public override void EndWrite(IAsyncResult asyncResult) { - if (!_compressionChecked) + if (asyncResult == null) { - throw new InvalidOperationException("BeginWrite was not called before EndWrite"); + throw new ArgumentNullException(nameof(asyncResult)); } - if (_compressionStream != null) - { - _compressionStream.EndWrite(asyncResult); - } - else - { - _bodyOriginalStream.EndWrite(asyncResult); - } + var task = (Task)asyncResult; + task.GetAwaiter().GetResult(); } #endif - public override Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) + public override async Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) { OnWrite(); if (_compressionStream != null) { - return _compressionStream.WriteAsync(buffer, offset, count, cancellationToken); + await _compressionStream.WriteAsync(buffer, offset, count, cancellationToken); + if (_autoFlush) + { + await _compressionStream.FlushAsync(cancellationToken); + } + } + else + { + await _bodyOriginalStream.WriteAsync(buffer, offset, count, cancellationToken); } - return _bodyOriginalStream.WriteAsync(buffer, offset, count, cancellationToken); } private void OnWrite() @@ -178,22 +209,30 @@ namespace Microsoft.AspNetCore.ResponseCompression if (!_compressionChecked) { _compressionChecked = true; - - if (IsCompressable()) + if (_provider.ShouldCompressResponse(_context)) { - _response.Headers.Append(HeaderNames.ContentEncoding, _compressionProvider.EncodingName); - _response.Headers.Remove(HeaderNames.ContentMD5); // Reset the MD5 because the content changed. - _response.Headers.Remove(HeaderNames.ContentLength); + var compressionProvider = ResolveCompressionProvider(); + if (compressionProvider != null) + { + _context.Response.Headers.Append(HeaderNames.ContentEncoding, compressionProvider.EncodingName); + _context.Response.Headers.Remove(HeaderNames.ContentMD5); // Reset the MD5 because the content changed. + _context.Response.Headers.Remove(HeaderNames.ContentLength); - _compressionStream = _compressionProvider.CreateStream(_bodyOriginalStream); + _compressionStream = compressionProvider.CreateStream(_bodyOriginalStream); + } } } } - private bool IsCompressable() + private ICompressionProvider ResolveCompressionProvider() { - return !_response.Headers.ContainsKey(HeaderNames.ContentRange) && // The response is not partial - _provider.ShouldCompressResponse(_response.HttpContext); + if (!_providerCreated) + { + _providerCreated = true; + _compressionProvider = _provider.GetCompressionProvider(_context); + } + + return _compressionProvider; } public void DisableRequestBuffering() @@ -205,13 +244,16 @@ namespace Microsoft.AspNetCore.ResponseCompression // For this to be effective it needs to be called before the first write. public void DisableResponseBuffering() { - if (!_compressionProvider.SupportsFlush) + if (ResolveCompressionProvider()?.SupportsFlush == false) { // Don't compress, some of the providers don't implement Flush (e.g. .NET 4.5.1 GZip/Deflate stream) // which would block real-time responses like SignalR. _compressionChecked = true; } - + else + { + _autoFlush = true; + } _innerBufferFeature?.DisableResponseBuffering(); } @@ -257,6 +299,11 @@ namespace Microsoft.AspNetCore.ResponseCompression { fileStream.Seek(offset, SeekOrigin.Begin); await StreamCopyOperation.CopyToAsync(fileStream, _compressionStream, count, cancellation); + + if (_autoFlush) + { + await _compressionStream.FlushAsync(cancellation); + } } } } diff --git a/src/Microsoft.AspNetCore.ResponseCompression/IResponseCompressionProvider.cs b/src/Microsoft.AspNetCore.ResponseCompression/IResponseCompressionProvider.cs index 8b118a2d89..c206acbb57 100644 --- a/src/Microsoft.AspNetCore.ResponseCompression/IResponseCompressionProvider.cs +++ b/src/Microsoft.AspNetCore.ResponseCompression/IResponseCompressionProvider.cs @@ -23,5 +23,12 @@ namespace Microsoft.AspNetCore.ResponseCompression /// /// bool ShouldCompressResponse(HttpContext context); + + /// + /// Examines the request to see if compression should be used for response. + /// + /// + /// + bool CheckRequestAcceptsCompression(HttpContext context); } } diff --git a/src/Microsoft.AspNetCore.ResponseCompression/Properties/AssemblyInfo.cs b/src/Microsoft.AspNetCore.ResponseCompression/Properties/AssemblyInfo.cs index 2dc4003a17..58848c06bb 100644 --- a/src/Microsoft.AspNetCore.ResponseCompression/Properties/AssemblyInfo.cs +++ b/src/Microsoft.AspNetCore.ResponseCompression/Properties/AssemblyInfo.cs @@ -3,6 +3,9 @@ using System.Reflection; using System.Resources; +using System.Runtime.CompilerServices; + +[assembly: InternalsVisibleTo("Microsoft.AspNetCore.ResponseCompression.Tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")] [assembly: AssemblyMetadata("Serviceable", "True")] [assembly: NeutralResourcesLanguage("en-us")] diff --git a/src/Microsoft.AspNetCore.ResponseCompression/ResponseCompressionMiddleware.cs b/src/Microsoft.AspNetCore.ResponseCompression/ResponseCompressionMiddleware.cs index b6841454d2..7fac9333e4 100644 --- a/src/Microsoft.AspNetCore.ResponseCompression/ResponseCompressionMiddleware.cs +++ b/src/Microsoft.AspNetCore.ResponseCompression/ResponseCompressionMiddleware.cs @@ -18,15 +18,13 @@ namespace Microsoft.AspNetCore.ResponseCompression private readonly IResponseCompressionProvider _provider; - private readonly bool _enableForHttps; /// /// Initialize the Response Compression middleware. /// /// /// - /// - public ResponseCompressionMiddleware(RequestDelegate next, IResponseCompressionProvider provider, IOptions options) + public ResponseCompressionMiddleware(RequestDelegate next, IResponseCompressionProvider provider) { if (next == null) { @@ -36,14 +34,9 @@ namespace Microsoft.AspNetCore.ResponseCompression { throw new ArgumentNullException(nameof(provider)); } - if (options == null) - { - throw new ArgumentNullException(nameof(options)); - } _next = next; _provider = provider; - _enableForHttps = options.Value.EnableForHttps; } /// @@ -53,14 +46,7 @@ namespace Microsoft.AspNetCore.ResponseCompression /// public async Task Invoke(HttpContext context) { - ICompressionProvider compressionProvider = null; - - if (!context.Request.IsHttps || _enableForHttps) - { - compressionProvider = _provider.GetCompressionProvider(context); - } - - if (compressionProvider == null) + if (!_provider.CheckRequestAcceptsCompression(context)) { await _next(context); return; @@ -70,7 +56,7 @@ namespace Microsoft.AspNetCore.ResponseCompression var originalBufferFeature = context.Features.Get(); var originalSendFileFeature = context.Features.Get(); - var bodyWrapperStream = new BodyWrapperStream(context.Response, bodyStream, _provider, compressionProvider, + var bodyWrapperStream = new BodyWrapperStream(context, bodyStream, _provider, originalBufferFeature, originalSendFileFeature); context.Response.Body = bodyWrapperStream; context.Features.Set(bodyWrapperStream); diff --git a/src/Microsoft.AspNetCore.ResponseCompression/ResponseCompressionProvider.cs b/src/Microsoft.AspNetCore.ResponseCompression/ResponseCompressionProvider.cs index b546a6045a..e16e6a1568 100644 --- a/src/Microsoft.AspNetCore.ResponseCompression/ResponseCompressionProvider.cs +++ b/src/Microsoft.AspNetCore.ResponseCompression/ResponseCompressionProvider.cs @@ -16,6 +16,7 @@ namespace Microsoft.AspNetCore.ResponseCompression { private readonly ICompressionProvider[] _providers; private readonly HashSet _mimeTypes; + private readonly bool _enableForHttps; /// /// If no compression providers are specified then GZip is used by default. @@ -54,6 +55,8 @@ namespace Microsoft.AspNetCore.ResponseCompression mimeTypes = ResponseCompressionDefaults.MimeTypes; } _mimeTypes = new HashSet(mimeTypes, StringComparer.OrdinalIgnoreCase); + + _enableForHttps = options.Value.EnableForHttps; } /// @@ -103,6 +106,11 @@ namespace Microsoft.AspNetCore.ResponseCompression /// public virtual bool ShouldCompressResponse(HttpContext context) { + if (context.Response.Headers.ContainsKey(HeaderNames.ContentRange)) + { + return false; + } + var mimeType = context.Response.ContentType; if (string.IsNullOrEmpty(mimeType)) @@ -121,5 +129,15 @@ namespace Microsoft.AspNetCore.ResponseCompression // TODO PERF: StringSegments? return _mimeTypes.Contains(mimeType); } + + /// + public bool CheckRequestAcceptsCompression(HttpContext context) + { + if (context.Request.IsHttps && !_enableForHttps) + { + return false; + } + return !string.IsNullOrEmpty(context.Request.Headers[HeaderNames.AcceptEncoding]); + } } } diff --git a/test/Microsoft.AspNetCore.ResponseCompression.Tests/BodyWrapperStreamTests.cs b/test/Microsoft.AspNetCore.ResponseCompression.Tests/BodyWrapperStreamTests.cs new file mode 100644 index 0000000000..75ca3d7d88 --- /dev/null +++ b/test/Microsoft.AspNetCore.ResponseCompression.Tests/BodyWrapperStreamTests.cs @@ -0,0 +1,211 @@ +// 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; +using System.IO; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Http; +using Moq; +using Xunit; + +namespace Microsoft.AspNetCore.ResponseCompression.Tests +{ + public class BodyWrapperStreamTests + { + [Theory] + [InlineData(true)] + [InlineData(false)] + public void Write_IsPassedToUnderlyingStream_WhenDisableResponseBuffering(bool flushable) + { + + var buffer = new byte[] { 1 }; + byte[] written = null; + + var mock = new Mock(); + mock.SetupGet(s => s.CanWrite).Returns(true); + mock.Setup(s => s.Write(It.IsAny(), It.IsAny(), It.IsAny())) + .Callback((b, o, c) => + { + written = new ArraySegment(b, 0, c).ToArray(); + }); + + var stream = new BodyWrapperStream(new DefaultHttpContext(), mock.Object, new MockResponseCompressionProvider(flushable), null, null); + + stream.DisableResponseBuffering(); + stream.Write(buffer, 0, buffer.Length); + + Assert.Equal(buffer, written); + } + + [Theory] + [InlineData(true)] + [InlineData(false)] + public async Task WriteAsync_IsPassedToUnderlyingStream_WhenDisableResponseBuffering(bool flushable) + { + var buffer = new byte[] { 1 }; + byte[] written = null; + + var mock = new Mock(); + mock.SetupGet(s => s.CanWrite).Returns(true); + mock.Setup(s => s.WriteAsync(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) + .Callback((b, o, c, t) => + { + written = new ArraySegment(b, 0, c).ToArray(); + }) + .Returns(Task.FromResult(0)); + + var stream = new BodyWrapperStream(new DefaultHttpContext(), mock.Object, new MockResponseCompressionProvider(flushable), null, null); + + stream.DisableResponseBuffering(); + await stream.WriteAsync(buffer, 0, buffer.Length); + + Assert.Equal(buffer, written); + } + + [Fact] + public async Task SendFileAsync_IsPassedToUnderlyingStream_WhenDisableResponseBuffering() + { + byte[] written = null; + + var mock = new Mock(); + mock.SetupGet(s => s.CanWrite).Returns(true); + mock.Setup(s => s.WriteAsync(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) + .Callback((b, o, c, t) => + { + written = new ArraySegment(b, 0, c).ToArray(); + }) + .Returns(Task.FromResult(0)); + + var stream = new BodyWrapperStream(new DefaultHttpContext(), mock.Object, new MockResponseCompressionProvider(true), null, null); + + stream.DisableResponseBuffering(); + + var path = "testfile1kb.txt"; + await stream.SendFileAsync(path, 0, null, CancellationToken.None); + + Assert.Equal(File.ReadAllBytes(path), written); + } + +#if NET451 + [Theory] + [InlineData(true)] + [InlineData(false)] + public void BeginWrite_IsPassedToUnderlyingStream_WhenDisableResponseBuffering(bool flushable) + { + var buffer = new byte[] { 1 }; + byte[] written = null; + + var mock = new Mock(); + mock.SetupGet(s => s.CanWrite).Returns(true); + mock.Setup(s => s.WriteAsync(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) + .Callback((b, o, c, t) => + { + written = new ArraySegment(b, 0, c).ToArray(); + }) + .Returns(Task.FromResult(0)); + + var stream = new BodyWrapperStream(new DefaultHttpContext(), mock.Object, new MockResponseCompressionProvider(flushable), null, null); + + stream.DisableResponseBuffering(); + stream.BeginWrite(buffer, 0, buffer.Length, (o) => {}, null); + + Assert.Equal(buffer, written); + } +#endif + + private class MockResponseCompressionProvider: IResponseCompressionProvider + { + private readonly bool _flushable; + + public MockResponseCompressionProvider(bool flushable) + { + _flushable = flushable; + } + + public ICompressionProvider GetCompressionProvider(HttpContext context) + { + return new MockCompressionProvider(_flushable); + } + + public bool ShouldCompressResponse(HttpContext context) + { + return true; + } + + public bool CheckRequestAcceptsCompression(HttpContext context) + { + return true; + } + } + + + private class MockCompressionProvider : ICompressionProvider + { + public MockCompressionProvider(bool flushable) + { + SupportsFlush = flushable; + } + + public string EncodingName { get; } + + public bool SupportsFlush { get; } + + public Stream CreateStream(Stream outputStream) + { + if (SupportsFlush) + { + return new BufferedStream(outputStream); + } + else + { + return new NoFlushBufferedStream(outputStream); + } + + } + } + + private class NoFlushBufferedStream : Stream + { + private readonly BufferedStream _bufferedStream; + + public NoFlushBufferedStream(Stream outputStream) + { + _bufferedStream = new BufferedStream(outputStream); + } + + public override void Flush() + { + } + + public override int Read(byte[] buffer, int offset, int count) => _bufferedStream.Read(buffer, offset, count); + + public override long Seek(long offset, SeekOrigin origin) => _bufferedStream.Seek(offset, origin); + + public override void SetLength(long value) => _bufferedStream.SetLength(value); + + public override void Write(byte[] buffer, int offset, int count) => _bufferedStream.Write(buffer, offset, count); + + public override bool CanRead => _bufferedStream.CanRead; + + public override bool CanSeek => _bufferedStream.CanSeek; + + public override bool CanWrite => _bufferedStream.CanWrite; + + public override long Length => _bufferedStream.Length; + + public override long Position + { + get { return _bufferedStream.Position; } + set { _bufferedStream.Position = value; } + } + + protected override void Dispose(bool disposing) + { + base.Dispose(disposing); + _bufferedStream.Flush(); + } + } + } +} diff --git a/test/Microsoft.AspNetCore.ResponseCompression.Tests/project.json b/test/Microsoft.AspNetCore.ResponseCompression.Tests/project.json index 27f2b146f3..18ac32240e 100644 --- a/test/Microsoft.AspNetCore.ResponseCompression.Tests/project.json +++ b/test/Microsoft.AspNetCore.ResponseCompression.Tests/project.json @@ -1,5 +1,6 @@ { "buildOptions": { + "keyFile": "../../tools/Key.snk", "copyToOutput": [ "testfile1kb.txt" ], @@ -11,6 +12,7 @@ "Microsoft.AspNetCore.ResponseCompression": "1.0.0-*", "Microsoft.AspNetCore.TestHost": "1.1.0-*", "Microsoft.Net.Http.Headers": "1.1.0-*", + "Moq": "4.6.36-*", "xunit": "2.2.0-*" }, "frameworks": { From c0425c62536d9727ad7ceb02d62d5b21ec33e901 Mon Sep 17 00:00:00 2001 From: Mikael Mengistu Date: Thu, 27 Oct 2016 14:53:37 -0700 Subject: [PATCH 144/307] Fixed url rewrite enum parsing. --- .../Internal/IISUrlRewrite/PatternSyntax.cs | 2 +- .../Internal/IISUrlRewrite/RewriteTags.cs | 39 ++++++------- .../IISUrlRewrite/UrlRewriteFileParser.cs | 50 +++++++++++++---- .../IISUrlRewrite/UrlRewriteRuleBuilder.cs | 6 +- .../FormatExceptionHandlingTests.cs | 56 +++++++++++++++++++ .../IISUrlRewrite/MiddleWareTests.cs | 30 ++++++++++ 6 files changed, 150 insertions(+), 33 deletions(-) diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/PatternSyntax.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/PatternSyntax.cs index b068016e72..f27d2c7256 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/PatternSyntax.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/PatternSyntax.cs @@ -6,7 +6,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite public enum PatternSyntax { ECMAScript, - WildCard, + Wildcard, ExactMatch } } diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/RewriteTags.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/RewriteTags.cs index 420e8e461d..5b60674d41 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/RewriteTags.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/RewriteTags.cs @@ -5,29 +5,30 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite { public static class RewriteTags { - public const string Rewrite = "rewrite"; - public const string GlobalRules = "globalRules"; - public const string Rules = "rules"; - public const string Rule = "rule"; public const string Action = "action"; - public const string Name = "name"; - public const string Enabled = "enabled"; - public const string PatternSyntax = "patternSyntax"; - public const string StopProcessing = "stopProcessing"; - public const string Match = "match"; - public const string Conditions = "conditions"; - public const string IgnoreCase = "ignoreCase"; - public const string Negate = "negate"; - public const string Url = "url"; - public const string MatchType = "matchType"; public const string Add = "add"; - public const string TrackingAllCaptures = "trackingAllCaptures"; - public const string MatchPattern = "matchPattern"; - public const string Input = "input"; - public const string Pattern = "pattern"; - public const string Type = "type"; public const string AppendQueryString = "appendQueryString"; + public const string Conditions = "conditions"; + public const string Enabled = "enabled"; + public const string GlobalRules = "globalRules"; + public const string IgnoreCase = "ignoreCase"; + public const string Input = "input"; + public const string LogicalGrouping = "logicalGrouping"; public const string LogRewrittenUrl = "logRewrittenUrl"; + public const string Match = "match"; + public const string MatchPattern = "matchPattern"; + public const string MatchType = "matchType"; + public const string Name = "name"; + public const string Negate = "negate"; + public const string Pattern = "pattern"; + public const string PatternSyntax = "patternSyntax"; + public const string Rewrite = "rewrite"; public const string RedirectType = "redirectType"; + public const string Rule = "rule"; + public const string Rules = "rules"; + public const string StopProcessing = "stopProcessing"; + public const string TrackingAllCaptures = "trackingAllCaptures"; + public const string Type = "type"; + public const string Url = "url"; } } diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/UrlRewriteFileParser.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/UrlRewriteFileParser.cs index e73df77bb4..24b17e78ab 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/UrlRewriteFileParser.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/UrlRewriteFileParser.cs @@ -77,10 +77,14 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite } PatternSyntax patternSyntax; - if (!Enum.TryParse(rule.Attribute(RewriteTags.PatternSyntax)?.Value, out patternSyntax)) + if (rule.Attribute(RewriteTags.PatternSyntax) == null) { patternSyntax = PatternSyntax.ECMAScript; } + else if (!Enum.TryParse(rule.Attribute(RewriteTags.PatternSyntax).Value, ignoreCase: true, result: out patternSyntax)) + { + ThrowParameterFormatException(rule, $"The {RewriteTags.PatternSyntax} parameter '{rule.Attribute(RewriteTags.PatternSyntax).Value}' was not recognized"); + } bool stopProcessing; if (!bool.TryParse(rule.Attribute(RewriteTags.StopProcessing)?.Value, out stopProcessing)) @@ -116,7 +120,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite bool ignoreCase; if (!bool.TryParse(match.Attribute(RewriteTags.IgnoreCase)?.Value, out ignoreCase)) { - ignoreCase = true; // default + ignoreCase = true; } bool negate; @@ -135,10 +139,14 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite } LogicalGrouping grouping; - if (!Enum.TryParse(conditions.Attribute(RewriteTags.MatchType)?.Value, out grouping)) + if (conditions.Attribute(RewriteTags.LogicalGrouping) == null) { grouping = LogicalGrouping.MatchAll; } + else if (!Enum.TryParse(conditions.Attribute(RewriteTags.LogicalGrouping).Value, ignoreCase: true, result: out grouping)) + { + ThrowParameterFormatException(conditions, $"The {RewriteTags.LogicalGrouping} parameter '{conditions.Attribute(RewriteTags.LogicalGrouping).Value}' was not recognized"); + } bool trackingAllCaptures; if (!bool.TryParse(conditions.Attribute(RewriteTags.TrackingAllCaptures)?.Value, out trackingAllCaptures)) @@ -169,10 +177,14 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite } MatchType matchType; - if (!Enum.TryParse(condition.Attribute(RewriteTags.MatchType)?.Value, out matchType)) + if (condition.Attribute(RewriteTags.MatchType) == null) { matchType = MatchType.Pattern; } + else if (!Enum.TryParse(condition.Attribute(RewriteTags.MatchType).Value, ignoreCase: true, result: out matchType)) + { + ThrowParameterFormatException(condition, $"The {RewriteTags.MatchType} parameter '{condition.Attribute(RewriteTags.MatchType).Value}' was not recognized"); + } var parsedInputString = condition.Attribute(RewriteTags.Input)?.Value; if (parsedInputString == null) @@ -195,10 +207,14 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite private void ParseUrlAction(XElement urlAction, UrlRewriteRuleBuilder builder, bool stopProcessing) { ActionType actionType; - if (!Enum.TryParse(urlAction.Attribute(RewriteTags.Type)?.Value, out actionType)) + if (urlAction.Attribute(RewriteTags.Type) == null) { actionType = ActionType.None; } + else if (!Enum.TryParse(urlAction.Attribute(RewriteTags.Type).Value, ignoreCase: true, result: out actionType)) + { + ThrowParameterFormatException(urlAction, $"The {RewriteTags.Type} parameter '{urlAction.Attribute(RewriteTags.Type).Value}' was not recognized"); + } bool appendQuery; if (!bool.TryParse(urlAction.Attribute(RewriteTags.AppendQueryString)?.Value, out appendQuery)) @@ -207,10 +223,14 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite } RedirectType redirectType; - if (!Enum.TryParse(urlAction.Attribute(RewriteTags.RedirectType)?.Value, out redirectType)) + if (urlAction.Attribute(RewriteTags.RedirectType) == null) { redirectType = RedirectType.Permanent; } + else if (!Enum.TryParse(urlAction.Attribute(RewriteTags.RedirectType).Value, ignoreCase: true, result: out redirectType)) + { + ThrowParameterFormatException(urlAction, $"The {RewriteTags.RedirectType} parameter '{urlAction.Attribute(RewriteTags.RedirectType).Value}' was not recognized"); + } string url = string.Empty; if (urlAction.Attribute(RewriteTags.Url) != null) @@ -235,16 +255,26 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite private static void ThrowUrlFormatException(XElement element, string message) { - var line = ((IXmlLineInfo)element).LineNumber; - var col = ((IXmlLineInfo)element).LinePosition; + var lineInfo = (IXmlLineInfo)element; + var line = lineInfo.LineNumber; + var col = lineInfo.LinePosition; throw new FormatException(Resources.FormatError_UrlRewriteParseError(message, line, col)); } private static void ThrowUrlFormatException(XElement element, string message, Exception ex) { - var line = ((IXmlLineInfo)element).LineNumber; - var col = ((IXmlLineInfo)element).LinePosition; + var lineInfo = (IXmlLineInfo)element; + var line = lineInfo.LineNumber; + var col = lineInfo.LinePosition; throw new FormatException(Resources.FormatError_UrlRewriteParseError(message, line, col), ex); } + + private static void ThrowParameterFormatException(XElement element, string message) + { + var lineInfo = (IXmlLineInfo)element; + var line = lineInfo.LineNumber; + var col = lineInfo.LinePosition; + throw new FormatException(Resources.FormatError_UrlRewriteParseError(message, line, col)); + } } } diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/UrlRewriteRuleBuilder.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/UrlRewriteRuleBuilder.cs index c4edf77cca..172c5ea457 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/UrlRewriteRuleBuilder.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/UrlRewriteRuleBuilder.cs @@ -76,7 +76,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite } break; } - case PatternSyntax.WildCard: + case PatternSyntax.Wildcard: throw new NotSupportedException("Wildcard syntax is not supported"); case PatternSyntax.ExactMatch: _initialMatch = new ExactMatch(ignoreCase, input, negate); @@ -86,7 +86,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite public void AddUrlCondition(Pattern input, string pattern, PatternSyntax patternSyntax, MatchType matchType, bool ignoreCase, bool negate) { - // If there are no conditions specified, + // If there are no conditions specified if (_conditions == null) { AddUrlConditions(LogicalGrouping.MatchAll, trackingAllCaptures: false); @@ -129,7 +129,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite } break; } - case PatternSyntax.WildCard: + case PatternSyntax.Wildcard: throw new NotSupportedException("Wildcard syntax is not supported"); case PatternSyntax.ExactMatch: if (pattern == null) diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/FormatExceptionHandlingTests.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/FormatExceptionHandlingTests.cs index 6398da1e95..7aca36e9f1 100644 --- a/test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/FormatExceptionHandlingTests.cs +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/FormatExceptionHandlingTests.cs @@ -101,6 +101,62 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite ", "Could not parse the UrlRewrite file. Message: 'Url attribute cannot contain an empty string'. Line number '5': '14'.")] + [InlineData( +@" + + + + + + +", + "Could not parse the UrlRewrite file. Message: 'The redirectType parameter 'foo' was not recognized'. Line number '5': '14'.")] + [InlineData( +@" + + + + + + +", + "Could not parse the UrlRewrite file. Message: 'The type parameter 'foo' was not recognized'. Line number '5': '14'.")] + [InlineData( +@" + + + + + + + + + +", + "Could not parse the UrlRewrite file. Message: 'The logicalGrouping parameter 'foo' was not recognized'. Line number '5': '14'.")] + [InlineData( +@" + + + + + + +", + "Could not parse the UrlRewrite file. Message: 'The patternSyntax parameter 'foo' was not recognized'. Line number '3': '10'.")] + [InlineData( +@" + + + + + + + + + +", + "Could not parse the UrlRewrite file. Message: 'The matchType parameter 'foo' was not recognized'. Line number '6': '18'.")] public void ThrowFormatExceptionWithCorrectMessage(string input, string expected) { // Arrange, Act, Assert diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/MiddleWareTests.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/MiddleWareTests.cs index e18f0325c1..2951b9777e 100644 --- a/test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/MiddleWareTests.cs +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/MiddleWareTests.cs @@ -336,5 +336,35 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite Assert.Equal(response.Headers.Location.OriginalString, "/foo"); } + + [Theory] + [InlineData("IsFile")] + [InlineData("isfile")] + [InlineData("IsDirectory")] + [InlineData("isdirectory")] + public async Task VerifyIsFileAndIsDirectoryParsing(string matchType) + { + var options = new RewriteOptions().AddIISUrlRewrite(new StringReader($@" + + + + + + + + + + ")); + var builder = new WebHostBuilder() + .Configure(app => + { + app.UseRewriter(options); + }); + var server = new TestServer(builder); + + var response = await server.CreateClient().GetAsync("hey/hello"); + + Assert.Equal("/hey/hello/", response.Headers.Location.OriginalString); ; + } } } From 7948a76f745069d9843fde03cd25bad9ca5b7c37 Mon Sep 17 00:00:00 2001 From: Mikael Mengistu Date: Mon, 31 Oct 2016 14:19:11 -0700 Subject: [PATCH 145/307] Added support for the AbortRequest action --- .../RewriteMiddlewareLoggingExtensions.cs | 11 ++++++++++ .../IISUrlRewrite/UrlRewriteRuleBuilder.cs | 3 ++- .../Internal/UrlActions/AbortAction.cs | 17 ++++++++++++++ .../Internal/UrlActions/RewriteAction.cs | 2 +- .../UrlActions/AbortActionTests.cs | 22 +++++++++++++++++++ 5 files changed, 53 insertions(+), 2 deletions(-) create mode 100644 src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/AbortAction.cs create mode 100644 test/Microsoft.AspNetCore.Rewrite.Tests/UrlActions/AbortActionTests.cs diff --git a/src/Microsoft.AspNetCore.Rewrite/Extensions/RewriteMiddlewareLoggingExtensions.cs b/src/Microsoft.AspNetCore.Rewrite/Extensions/RewriteMiddlewareLoggingExtensions.cs index 296a38fc83..eaa1b0e345 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Extensions/RewriteMiddlewareLoggingExtensions.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Extensions/RewriteMiddlewareLoggingExtensions.cs @@ -18,6 +18,7 @@ namespace Microsoft.AspNetCore.Rewrite.Logging private static readonly Action _redirectedToHttps; private static readonly Action _redirectSummary; private static readonly Action _rewriteSummary; + private static readonly Action _abortedRequest; static RewriteMiddlewareLoggingExtensions() { @@ -70,6 +71,11 @@ namespace Microsoft.AspNetCore.Rewrite.Logging LogLevel.Information, 10, "Request was rewritten to {rewrittenUrl}"); + + _abortedRequest = LoggerMessage.Define( + LogLevel.Debug, + 11, + "Request to {requestedUrl} was aborted"); } public static void RewriteMiddlewareRequestContinueResults(this ILogger logger, string currentUrl) @@ -121,5 +127,10 @@ namespace Microsoft.AspNetCore.Rewrite.Logging { _rewriteSummary(logger, rewrittenUrl, null); } + + public static void AbortedRequest(this ILogger logger, string requestedUrl) + { + _abortedRequest(logger, requestedUrl, null); + } } } diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/UrlRewriteRuleBuilder.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/UrlRewriteRuleBuilder.cs index 172c5ea457..311a503cca 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/UrlRewriteRuleBuilder.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/UrlRewriteRuleBuilder.cs @@ -52,7 +52,8 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite _action = new RedirectAction(statusCode, url, appendQueryString); break; case ActionType.AbortRequest: - throw new NotImplementedException("Abort Requests are not implemented"); + _action = new AbortAction(); + break; case ActionType.CustomResponse: throw new NotImplementedException("Custom Responses are not implemented"); } diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/AbortAction.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/AbortAction.cs new file mode 100644 index 0000000000..e0ac36396c --- /dev/null +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/AbortAction.cs @@ -0,0 +1,17 @@ +// 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 Microsoft.AspNetCore.Rewrite.Logging; + +namespace Microsoft.AspNetCore.Rewrite.Internal.UrlActions +{ + public class AbortAction : UrlAction + { + public override void ApplyAction(RewriteContext context, MatchResults ruleMatch, MatchResults condMatch) + { + context.HttpContext.Abort(); + context.Result = RuleResult.EndResponse; + context.Logger?.AbortedRequest(context.HttpContext.Request.Path + context.HttpContext.Request.QueryString); + } + } +} diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/RewriteAction.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/RewriteAction.cs index f6637747d5..bd9a7fd63b 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/RewriteAction.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/RewriteAction.cs @@ -21,7 +21,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlActions bool queryStringDelete, bool escapeBackReferences) { - // For the replacement, we must have at least + // For the replacement, we must have at least // one segment (cannot have an empty replacement) Result = result; Url = pattern; diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/UrlActions/AbortActionTests.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/UrlActions/AbortActionTests.cs new file mode 100644 index 0000000000..e39e58fb84 --- /dev/null +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/UrlActions/AbortActionTests.cs @@ -0,0 +1,22 @@ +// 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 Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Rewrite.Internal.UrlActions; +using Xunit; + +namespace Microsoft.AspNetCore.Rewrite.Tests.UrlActions +{ + public class AbortActionTests + { + public void AbortAction_VerifyEndResponseResult() + { + var context = new RewriteContext { HttpContext = new DefaultHttpContext() }; + var action = new AbortAction(); + + action.ApplyAction(context, null, null); + + Assert.Equal(RuleResult.EndResponse, context.Result); + } + } +} From a52301f8861bfa3795b0b98913a08f775e6225da Mon Sep 17 00:00:00 2001 From: Mikael Mengistu Date: Tue, 1 Nov 2016 20:29:46 -0700 Subject: [PATCH 146/307] Refactor url rewrite bool and enum parsing --- .../IISUrlRewrite/UrlRewriteFileParser.cs | 145 ++++++------------ .../FormatExceptionHandlingTests.cs | 101 ++++++++++++ 2 files changed, 147 insertions(+), 99 deletions(-) diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/UrlRewriteFileParser.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/UrlRewriteFileParser.cs index 24b17e78ab..90ea82a770 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/UrlRewriteFileParser.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/UrlRewriteFileParser.cs @@ -59,38 +59,17 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite { builder.Name = rule.Attribute(RewriteTags.Name)?.Value; - bool enabled; - if (!bool.TryParse(rule.Attribute(RewriteTags.Enabled)?.Value, out enabled)) + if (ParseBool(rule, RewriteTags.Enabled, defaultValue: true)) { builder.Enabled = true; } else { - if (enabled) - { - builder.Enabled = enabled; - } - else - { - return; - } + return; } - PatternSyntax patternSyntax; - if (rule.Attribute(RewriteTags.PatternSyntax) == null) - { - patternSyntax = PatternSyntax.ECMAScript; - } - else if (!Enum.TryParse(rule.Attribute(RewriteTags.PatternSyntax).Value, ignoreCase: true, result: out patternSyntax)) - { - ThrowParameterFormatException(rule, $"The {RewriteTags.PatternSyntax} parameter '{rule.Attribute(RewriteTags.PatternSyntax).Value}' was not recognized"); - } - - bool stopProcessing; - if (!bool.TryParse(rule.Attribute(RewriteTags.StopProcessing)?.Value, out stopProcessing)) - { - stopProcessing = false; - } + var patternSyntax = ParseEnum(rule, RewriteTags.PatternSyntax, PatternSyntax.ECMAScript); + var stopProcessing = ParseBool(rule, RewriteTags.StopProcessing, defaultValue: false); var match = rule.Element(RewriteTags.Match); if (match == null) @@ -117,17 +96,8 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite ThrowUrlFormatException(match, "Match must have Url Attribute"); } - bool ignoreCase; - if (!bool.TryParse(match.Attribute(RewriteTags.IgnoreCase)?.Value, out ignoreCase)) - { - ignoreCase = true; - } - - bool negate; - if (!bool.TryParse(match.Attribute(RewriteTags.Negate)?.Value, out negate)) - { - negate = false; - } + var ignoreCase = ParseBool(match, RewriteTags.IgnoreCase, defaultValue: true); + var negate = ParseBool(match, RewriteTags.Negate, defaultValue: false); builder.AddUrlMatch(parsedInputString, ignoreCase, negate, patternSyntax); } @@ -138,22 +108,8 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite return; } - LogicalGrouping grouping; - if (conditions.Attribute(RewriteTags.LogicalGrouping) == null) - { - grouping = LogicalGrouping.MatchAll; - } - else if (!Enum.TryParse(conditions.Attribute(RewriteTags.LogicalGrouping).Value, ignoreCase: true, result: out grouping)) - { - ThrowParameterFormatException(conditions, $"The {RewriteTags.LogicalGrouping} parameter '{conditions.Attribute(RewriteTags.LogicalGrouping).Value}' was not recognized"); - } - - bool trackingAllCaptures; - if (!bool.TryParse(conditions.Attribute(RewriteTags.TrackingAllCaptures)?.Value, out trackingAllCaptures)) - { - trackingAllCaptures = false; - } - + var grouping = ParseEnum(conditions, RewriteTags.LogicalGrouping, LogicalGrouping.MatchAll); + var trackingAllCaptures = ParseBool(conditions, RewriteTags.TrackingAllCaptures, defaultValue: false); builder.AddUrlConditions(grouping, trackingAllCaptures); foreach (var cond in conditions.Elements(RewriteTags.Add)) @@ -164,29 +120,11 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite private void ParseCondition(XElement condition, UrlRewriteRuleBuilder builder, PatternSyntax patternSyntax) { - bool ignoreCase; - if (!bool.TryParse(condition.Attribute(RewriteTags.IgnoreCase)?.Value, out ignoreCase)) - { - ignoreCase = true; - } - - bool negate; - if (!bool.TryParse(condition.Attribute(RewriteTags.Negate)?.Value, out negate)) - { - negate = false; - } - - MatchType matchType; - if (condition.Attribute(RewriteTags.MatchType) == null) - { - matchType = MatchType.Pattern; - } - else if (!Enum.TryParse(condition.Attribute(RewriteTags.MatchType).Value, ignoreCase: true, result: out matchType)) - { - ThrowParameterFormatException(condition, $"The {RewriteTags.MatchType} parameter '{condition.Attribute(RewriteTags.MatchType).Value}' was not recognized"); - } - + var ignoreCase = ParseBool(condition, RewriteTags.IgnoreCase, defaultValue: true); + var negate = ParseBool(condition, RewriteTags.Negate, defaultValue: false); + var matchType = ParseEnum(condition, RewriteTags.MatchType, MatchType.Pattern); var parsedInputString = condition.Attribute(RewriteTags.Input)?.Value; + if (parsedInputString == null) { ThrowUrlFormatException(condition, "Conditions must have an input attribute"); @@ -206,31 +144,9 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite private void ParseUrlAction(XElement urlAction, UrlRewriteRuleBuilder builder, bool stopProcessing) { - ActionType actionType; - if (urlAction.Attribute(RewriteTags.Type) == null) - { - actionType = ActionType.None; - } - else if (!Enum.TryParse(urlAction.Attribute(RewriteTags.Type).Value, ignoreCase: true, result: out actionType)) - { - ThrowParameterFormatException(urlAction, $"The {RewriteTags.Type} parameter '{urlAction.Attribute(RewriteTags.Type).Value}' was not recognized"); - } - - bool appendQuery; - if (!bool.TryParse(urlAction.Attribute(RewriteTags.AppendQueryString)?.Value, out appendQuery)) - { - appendQuery = true; - } - - RedirectType redirectType; - if (urlAction.Attribute(RewriteTags.RedirectType) == null) - { - redirectType = RedirectType.Permanent; - } - else if (!Enum.TryParse(urlAction.Attribute(RewriteTags.RedirectType).Value, ignoreCase: true, result: out redirectType)) - { - ThrowParameterFormatException(urlAction, $"The {RewriteTags.RedirectType} parameter '{urlAction.Attribute(RewriteTags.RedirectType).Value}' was not recognized"); - } + var actionType = ParseEnum(urlAction, RewriteTags.Type, ActionType.None); + var redirectType = ParseEnum(urlAction, RewriteTags.RedirectType, RedirectType.Permanent); + var appendQuery = ParseBool(urlAction, RewriteTags.AppendQueryString, defaultValue: true); string url = string.Empty; if (urlAction.Attribute(RewriteTags.Url) != null) @@ -276,5 +192,36 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite var col = lineInfo.LinePosition; throw new FormatException(Resources.FormatError_UrlRewriteParseError(message, line, col)); } + + private bool ParseBool(XElement element, string rewriteTag, bool defaultValue) + { + bool result; + var attribute = element.Attribute(rewriteTag); + if (attribute == null) + { + return defaultValue; + } + else if (!bool.TryParse(attribute.Value, out result)) + { + ThrowParameterFormatException(element, $"The {rewriteTag} parameter '{attribute.Value}' was not recognized"); + } + return result; + } + + private TEnum ParseEnum(XElement element, string rewriteTag, TEnum defaultValue) + where TEnum : struct + { + TEnum enumResult = default(TEnum); + var attribute = element.Attribute(rewriteTag); + if (attribute == null) + { + return defaultValue; + } + else if(!Enum.TryParse(attribute.Value, ignoreCase: true, result: out enumResult)) + { + ThrowParameterFormatException(element, $"The {rewriteTag} parameter '{attribute.Value}' was not recognized"); + } + return enumResult; + } } } diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/FormatExceptionHandlingTests.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/FormatExceptionHandlingTests.cs index 7aca36e9f1..6e8be8053c 100644 --- a/test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/FormatExceptionHandlingTests.cs +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/FormatExceptionHandlingTests.cs @@ -157,6 +157,107 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite ", "Could not parse the UrlRewrite file. Message: 'The matchType parameter 'foo' was not recognized'. Line number '6': '18'.")] + [InlineData( +@" + + + + + + + + + +", + "Could not parse the UrlRewrite file. Message: 'The enabled parameter 'foo' was not recognized'. Line number '3': '10'.")] + [InlineData( +@" + + + + + + + + + +", + "Could not parse the UrlRewrite file. Message: 'The stopProcessing parameter 'foo' was not recognized'. Line number '3': '10'.")] + [InlineData( +@" + + + + + + + + + +", + "Could not parse the UrlRewrite file. Message: 'The ignoreCase parameter 'foo' was not recognized'. Line number '4': '14'.")] + [InlineData( +@" + + + + + + + + + +", + "Could not parse the UrlRewrite file. Message: 'The ignoreCase parameter 'foo' was not recognized'. Line number '6': '18'.")] + [InlineData( +@" + + + + + + + + + +", + "Could not parse the UrlRewrite file. Message: 'The negate parameter 'foo' was not recognized'. Line number '4': '14'.")] + [InlineData( +@" + + + + + + + + + +", + "Could not parse the UrlRewrite file. Message: 'The negate parameter 'foo' was not recognized'. Line number '6': '18'.")] + [InlineData( +@" + + + + + + + + + +", + "Could not parse the UrlRewrite file. Message: 'The trackingAllCaptures parameter 'foo' was not recognized'. Line number '5': '14'.")] + [InlineData( +@" + + + + + + +", + "Could not parse the UrlRewrite file. Message: 'The appendQueryString parameter 'foo' was not recognized'. Line number '5': '14'.")] public void ThrowFormatExceptionWithCorrectMessage(string input, string expected) { // Arrange, Act, Assert From 222addf2644047db93b38ce1d744617bdaf88a1b Mon Sep 17 00:00:00 2001 From: Mikael Mengistu Date: Thu, 3 Nov 2016 13:22:10 -0700 Subject: [PATCH 147/307] Added a default status code for redirects in mod_rewrite --- .../Internal/ApacheModRewrite/RuleBuilder.cs | 14 ++++++++++---- .../ApacheModRewrite/RuleBuilderTest.cs | 18 ++++++++++++++++++ 2 files changed, 28 insertions(+), 4 deletions(-) diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/ApacheModRewrite/RuleBuilder.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/ApacheModRewrite/RuleBuilder.cs index 7bb0d1cd3f..638192b602 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/ApacheModRewrite/RuleBuilder.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/ApacheModRewrite/RuleBuilder.cs @@ -3,7 +3,9 @@ using System; using System.Collections.Generic; +using System.Globalization; using System.Text.RegularExpressions; +using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Rewrite.Internal.UrlActions; using Microsoft.AspNetCore.Rewrite.Internal.UrlMatches; @@ -12,7 +14,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.ApacheModRewrite public class RuleBuilder { private IList _conditions; - private IList _actions = new List(); + internal IList _actions = new List(); private UrlMatch _match; private CookieActionFactory _cookieActionFactory = new CookieActionFactory(); @@ -200,12 +202,16 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.ApacheModRewrite string statusCode; if (flags.GetValue(FlagType.Redirect, out statusCode)) { - int res; - if (!int.TryParse(statusCode, out res)) + int responseStatusCode; + if (string.IsNullOrEmpty(statusCode)) + { + responseStatusCode = StatusCodes.Status302Found; + } + else if (!int.TryParse(statusCode, NumberStyles.None, CultureInfo.InvariantCulture, out responseStatusCode)) { throw new FormatException(Resources.FormatError_InputParserInvalidInteger(statusCode, -1)); } - _actions.Add(new RedirectAction(res, pattern, queryStringAppend, queryStringDelete, escapeBackReference)); + _actions.Add(new RedirectAction(responseStatusCode, pattern, queryStringAppend, queryStringDelete, escapeBackReference)); } else { diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/ApacheModRewrite/RuleBuilderTest.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/ApacheModRewrite/RuleBuilderTest.cs index df1a16adf1..ec0b46803f 100644 --- a/test/Microsoft.AspNetCore.Rewrite.Tests/ApacheModRewrite/RuleBuilderTest.cs +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/ApacheModRewrite/RuleBuilderTest.cs @@ -2,7 +2,11 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; +using System.Collections.Generic; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Rewrite.Internal; using Microsoft.AspNetCore.Rewrite.Internal.ApacheModRewrite; +using Microsoft.AspNetCore.Rewrite.Internal.UrlActions; using Xunit; namespace Microsoft.AspNetCore.Rewrite.Tests @@ -20,5 +24,19 @@ namespace Microsoft.AspNetCore.Rewrite.Tests var ex = Assert.Throws(() => builder.AddAction(null, flags)); Assert.Equal(Resources.Error_ChangeEnvironmentNotSupported, ex.Message); } + + [Fact] + public void AddAction_DefaultRedirectStatusCode() + { + var builder = new RuleBuilder(); + var flags = new Flags(); + var pattern = new Pattern(new List()); + flags.SetFlag(FlagType.Redirect, string.Empty); + + builder.AddAction(pattern, flags); + var redirectAction = (RedirectAction)builder._actions[0]; + + Assert.Equal(StatusCodes.Status302Found, redirectAction.StatusCode); + } } } \ No newline at end of file From 623333a919c34e63ae98a276564e03f31f9cb1cf Mon Sep 17 00:00:00 2001 From: Mikael Mengistu Date: Thu, 3 Nov 2016 16:45:33 -0700 Subject: [PATCH 148/307] Fix server variable exception messages --- .../ApacheModRewrite/ServerVariables.cs | 34 +++++------ .../Internal/IISUrlRewrite/ServerVariables.cs | 8 +-- .../Properties/Resources.Designer.cs | 16 ++++++ .../Resources.resx | 57 ++++++++++--------- 4 files changed, 67 insertions(+), 48 deletions(-) diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/ApacheModRewrite/ServerVariables.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/ApacheModRewrite/ServerVariables.cs index 2b44331a15..afb3a72053 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/ApacheModRewrite/ServerVariables.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/ApacheModRewrite/ServerVariables.cs @@ -38,51 +38,51 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.ApacheModRewrite case "HTTP_FORWARDED": return new HeaderSegment("Forwarded"); case "AUTH_TYPE": - throw new NotSupportedException("Rules using the AUTH_TYPE server variable are not supported"); + throw new NotSupportedException(Resources.FormatError_UnsupportedServerVariable(serverVariable)); case "CONN_REMOTE_ADDR": return new RemoteAddressSegment(); case "CONTEXT_PREFIX": - throw new NotSupportedException("Rules using the CONTEXT_PREFIX server variable are not supported"); + throw new NotSupportedException(Resources.FormatError_UnsupportedServerVariable(serverVariable)); case "CONTEXT_DOCUMENT_ROOT": - throw new NotSupportedException("Rules using the CONTEXT_DOCUMENT_ROOT server variable are not supported"); + throw new NotSupportedException(Resources.FormatError_UnsupportedServerVariable(serverVariable)); case "IPV6": return new IsIPV6Segment(); case "PATH_INFO": - throw new NotImplementedException("Rules using the PATH_INFO server variable are not implemented"); + throw new NotImplementedException(Resources.FormatError_UnsupportedServerVariable(serverVariable)); case "QUERY_STRING": return new QueryStringSegment(); case "REMOTE_ADDR": return new RemoteAddressSegment(); case "REMOTE_HOST": - throw new NotSupportedException("Rules using the REMOTE_HOST server variable are not supported"); + throw new NotSupportedException(Resources.FormatError_UnsupportedServerVariable(serverVariable)); case "REMOTE_IDENT": - throw new NotSupportedException("Rules using the REMOTE_IDENT server variable are not supported"); + throw new NotSupportedException(Resources.FormatError_UnsupportedServerVariable(serverVariable)); case "REMOTE_PORT": return new RemotePortSegment(); case "REMOTE_USER": - throw new NotSupportedException("Rules using the REMOTE_USER server variable are not supported"); + throw new NotSupportedException(Resources.FormatError_UnsupportedServerVariable(serverVariable)); case "REQUEST_METHOD": return new RequestMethodSegment(); case "SCRIPT_FILENAME": return new RequestFileNameSegment(); case "DOCUMENT_ROOT": - throw new NotSupportedException("Rules using the DOCUMENT_ROOT server variable are not supported"); + throw new NotSupportedException(Resources.FormatError_UnsupportedServerVariable(serverVariable)); case "SCRIPT_GROUP": - throw new NotSupportedException("Rules using the SCRIPT_GROUP server variable are not supported"); + throw new NotSupportedException(Resources.FormatError_UnsupportedServerVariable(serverVariable)); case "SCRIPT_USER": - throw new NotSupportedException("Rules using the SCRIPT_USER server variable are not supported"); + throw new NotSupportedException(Resources.FormatError_UnsupportedServerVariable(serverVariable)); case "SERVER_ADDR": return new LocalAddressSegment(); case "SERVER_ADMIN": - throw new NotSupportedException("Rules using the SERVER_ADMIN server variable are not supported"); + throw new NotSupportedException(Resources.FormatError_UnsupportedServerVariable(serverVariable)); case "SERVER_NAME": - throw new NotSupportedException("Rules using the SERVER_NAME server variable are not supported"); + throw new NotSupportedException(Resources.FormatError_UnsupportedServerVariable(serverVariable)); case "SERVER_PORT": return new LocalPortSegment(); case "SERVER_PROTOCOL": return new ServerProtocolSegment(); case "SERVER_SOFTWARE": - throw new NotSupportedException("Rules using the SERVER_SOFTWARE server variable are not supported"); + throw new NotSupportedException(Resources.FormatError_UnsupportedServerVariable(serverVariable)); case "TIME_YEAR": return new DateTimeSegment(serverVariable); case "TIME_MON": @@ -100,13 +100,13 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.ApacheModRewrite case "TIME": return new DateTimeSegment(serverVariable); case "API_VERSION": - throw new NotSupportedException("Rules using the API_VERSION server variable are not supported"); + throw new NotSupportedException(Resources.FormatError_UnsupportedServerVariable(serverVariable)); case "HTTPS": return new IsHttpsModSegment(); case "HTTP2": - throw new NotSupportedException("Rules using the HTTP2 server variable are not supported"); + throw new NotSupportedException(Resources.FormatError_UnsupportedServerVariable(serverVariable)); case "IS_SUBREQ": - throw new NotSupportedException("Rules using the IS_SUBREQ server variable are not supported"); + throw new NotSupportedException(Resources.FormatError_UnsupportedServerVariable(serverVariable)); case "REQUEST_FILENAME": return new RequestFileNameSegment(); case "REQUEST_SCHEME": @@ -114,7 +114,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.ApacheModRewrite case "REQUEST_URI": return new UrlSegment(); case "THE_REQUEST": - throw new NotSupportedException("Rules using the THE_REQUEST server variable are not supported"); + throw new NotSupportedException(Resources.FormatError_UnsupportedServerVariable(serverVariable)); default: throw new FormatException(Resources.FormatError_InputParserUnrecognizedParameter(serverVariable, context.Index)); } diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/ServerVariables.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/ServerVariables.cs index a9c92a9a6c..12367e142c 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/ServerVariables.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/ServerVariables.cs @@ -15,9 +15,9 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite { // TODO Add all server variables here. case "ALL_RAW": - throw new NotSupportedException("Rules using the ALL_RAW server variable are not supported"); + throw new NotSupportedException(Resources.FormatError_UnsupportedServerVariable(serverVariable)); case "APP_POOL_ID": - throw new NotSupportedException("Rules using the APP_POOL_ID server variable are not supported"); + throw new NotSupportedException(Resources.FormatError_UnsupportedServerVariable(serverVariable)); case "CONTENT_LENGTH": return new HeaderSegment(HeaderNames.ContentLength); case "CONTENT_TYPE": @@ -41,13 +41,13 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite case "LOCAL_ADDR": return new LocalAddressSegment(); case "HTTP_PROXY_CONNECTION": - throw new NotSupportedException("Rules using the HTTP_PROXY_CONNECTION server variable are not supported"); + throw new NotSupportedException(Resources.FormatError_UnsupportedServerVariable(serverVariable)); case "QUERY_STRING": return new QueryStringSegment(); case "REMOTE_ADDR": return new RemoteAddressSegment(); case "REMOTE_HOST": - throw new NotSupportedException("Rules using the REMOTE_HOST server variable are not supported"); + throw new NotSupportedException(Resources.FormatError_UnsupportedServerVariable(serverVariable)); case "REMOTE_PORT": return new RemotePortSegment(); case "REQUEST_FILENAME": diff --git a/src/Microsoft.AspNetCore.Rewrite/Properties/Resources.Designer.cs b/src/Microsoft.AspNetCore.Rewrite/Properties/Resources.Designer.cs index bda94e5268..f52b4232a8 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Properties/Resources.Designer.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Properties/Resources.Designer.cs @@ -202,6 +202,22 @@ namespace Microsoft.AspNetCore.Rewrite return string.Format(CultureInfo.CurrentCulture, GetString("Error_UrlRewriteParseError"), p0, p1, p2); } + /// + /// Rules using the '{0}' server variable are not supported + /// + internal static string Error_UnsupportedServerVariable + { + get { return GetString("Error_UnsupportedServerVariable"); } + } + + /// + /// Rules using the '{0}' server variable are not supported + /// + internal static string FormatError_UnsupportedServerVariable(object p0) + { + return string.Format(CultureInfo.CurrentCulture, GetString("Error_UnsupportedServerVariable"), p0); + } + private static string GetString(string name, params string[] formatterNames) { var value = _resourceManager.GetString(name); diff --git a/src/Microsoft.AspNetCore.Rewrite/Resources.resx b/src/Microsoft.AspNetCore.Rewrite/Resources.resx index 2c68d33ec3..7574b71b2f 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Resources.resx +++ b/src/Microsoft.AspNetCore.Rewrite/Resources.resx @@ -1,17 +1,17 @@  - @@ -153,4 +153,7 @@ Could not parse the UrlRewrite file. Message: '{0}'. Line number '{1}': '{2}'. + + Rules using the '{0}' server variable are not supported + \ No newline at end of file From c8b5a48b767efbd4048e9335f20951f93396909e Mon Sep 17 00:00:00 2001 From: Mikael Mengistu Date: Thu, 3 Nov 2016 19:48:25 -0700 Subject: [PATCH 149/307] Fixed trackAllCaptures enum naming --- .../Internal/IISUrlRewrite/RewriteTags.cs | 2 +- .../Internal/IISUrlRewrite/UrlRewriteFileParser.cs | 4 ++-- .../Internal/IISUrlRewrite/UrlRewriteRuleBuilder.cs | 4 ++-- .../IISUrlRewrite/FormatExceptionHandlingTests.cs | 4 ++-- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/RewriteTags.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/RewriteTags.cs index 5b60674d41..9b62b26511 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/RewriteTags.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/RewriteTags.cs @@ -27,7 +27,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite public const string Rule = "rule"; public const string Rules = "rules"; public const string StopProcessing = "stopProcessing"; - public const string TrackingAllCaptures = "trackingAllCaptures"; + public const string TrackAllCaptures = "trackAllCaptures"; public const string Type = "type"; public const string Url = "url"; } diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/UrlRewriteFileParser.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/UrlRewriteFileParser.cs index 90ea82a770..c8d20bedb8 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/UrlRewriteFileParser.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/UrlRewriteFileParser.cs @@ -109,8 +109,8 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite } var grouping = ParseEnum(conditions, RewriteTags.LogicalGrouping, LogicalGrouping.MatchAll); - var trackingAllCaptures = ParseBool(conditions, RewriteTags.TrackingAllCaptures, defaultValue: false); - builder.AddUrlConditions(grouping, trackingAllCaptures); + var trackAllCaptures = ParseBool(conditions, RewriteTags.TrackAllCaptures, defaultValue: false); + builder.AddUrlConditions(grouping, trackAllCaptures); foreach (var cond in conditions.Elements(RewriteTags.Add)) { diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/UrlRewriteRuleBuilder.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/UrlRewriteRuleBuilder.cs index 311a503cca..f6603b2df8 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/UrlRewriteRuleBuilder.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/UrlRewriteRuleBuilder.cs @@ -90,7 +90,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite // If there are no conditions specified if (_conditions == null) { - AddUrlConditions(LogicalGrouping.MatchAll, trackingAllCaptures: false); + AddUrlConditions(LogicalGrouping.MatchAll, trackAllCaptures: false); } switch (patternSyntax) @@ -144,7 +144,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite } } - public void AddUrlConditions(LogicalGrouping logicalGrouping, bool trackingAllCaptures) + public void AddUrlConditions(LogicalGrouping logicalGrouping, bool trackAllCaptures) { _conditions = new List(); _matchAny = logicalGrouping == LogicalGrouping.MatchAny; diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/FormatExceptionHandlingTests.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/FormatExceptionHandlingTests.cs index 6e8be8053c..c14f062e64 100644 --- a/test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/FormatExceptionHandlingTests.cs +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/FormatExceptionHandlingTests.cs @@ -240,14 +240,14 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite - + ", - "Could not parse the UrlRewrite file. Message: 'The trackingAllCaptures parameter 'foo' was not recognized'. Line number '5': '14'.")] + "Could not parse the UrlRewrite file. Message: 'The trackAllCaptures parameter 'foo' was not recognized'. Line number '5': '14'.")] [InlineData( @" From fa8ec4131ffd4093573270df96b9a71cf0338e4e Mon Sep 17 00:00:00 2001 From: jacalvar Date: Fri, 4 Nov 2016 11:07:52 -0700 Subject: [PATCH 150/307] Created public API baselines --- .../baseline.net45.json | 452 ++++++++++++++++++ .../baseline.netcore.json | 452 ++++++++++++++++++ 2 files changed, 904 insertions(+) create mode 100644 src/Microsoft.AspNetCore.HttpOverrides/baseline.net45.json create mode 100644 src/Microsoft.AspNetCore.HttpOverrides/baseline.netcore.json diff --git a/src/Microsoft.AspNetCore.HttpOverrides/baseline.net45.json b/src/Microsoft.AspNetCore.HttpOverrides/baseline.net45.json new file mode 100644 index 0000000000..4a5e5a6e3e --- /dev/null +++ b/src/Microsoft.AspNetCore.HttpOverrides/baseline.net45.json @@ -0,0 +1,452 @@ +{ + "AssemblyIdentity": "Microsoft.AspNetCore.HttpOverrides, Version=1.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60", + "Types": [ + { + "Name": "Microsoft.AspNetCore.Builder.ForwardedHeadersExtensions", + "Visibility": "Public", + "Kind": "Class", + "Abstract": true, + "Static": true, + "Sealed": true, + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Method", + "Name": "UseForwardedHeaders", + "Parameters": [ + { + "Name": "builder", + "Type": "Microsoft.AspNetCore.Builder.IApplicationBuilder" + } + ], + "ReturnType": "Microsoft.AspNetCore.Builder.IApplicationBuilder", + "Static": true, + "Extension": true, + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "UseForwardedHeaders", + "Parameters": [ + { + "Name": "builder", + "Type": "Microsoft.AspNetCore.Builder.IApplicationBuilder" + }, + { + "Name": "options", + "Type": "Microsoft.AspNetCore.Builder.ForwardedHeadersOptions" + } + ], + "ReturnType": "Microsoft.AspNetCore.Builder.IApplicationBuilder", + "Static": true, + "Extension": true, + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.Builder.ForwardedHeadersOptions", + "Visibility": "Public", + "Kind": "Class", + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Method", + "Name": "get_ForwardedHeaders", + "Parameters": [], + "ReturnType": "Microsoft.AspNetCore.HttpOverrides.ForwardedHeaders", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "set_ForwardedHeaders", + "Parameters": [ + { + "Name": "value", + "Type": "Microsoft.AspNetCore.HttpOverrides.ForwardedHeaders" + } + ], + "ReturnType": "System.Void", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "get_ForwardLimit", + "Parameters": [], + "ReturnType": "System.Nullable", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "set_ForwardLimit", + "Parameters": [ + { + "Name": "value", + "Type": "System.Nullable" + } + ], + "ReturnType": "System.Void", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "get_KnownProxies", + "Parameters": [], + "ReturnType": "System.Collections.Generic.IList", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "get_KnownNetworks", + "Parameters": [], + "ReturnType": "System.Collections.Generic.IList", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "get_RequireHeaderSymmetry", + "Parameters": [], + "ReturnType": "System.Boolean", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "set_RequireHeaderSymmetry", + "Parameters": [ + { + "Name": "value", + "Type": "System.Boolean" + } + ], + "ReturnType": "System.Void", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [], + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.Builder.HttpMethodOverrideExtensions", + "Visibility": "Public", + "Kind": "Class", + "Abstract": true, + "Static": true, + "Sealed": true, + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Method", + "Name": "UseHttpMethodOverride", + "Parameters": [ + { + "Name": "builder", + "Type": "Microsoft.AspNetCore.Builder.IApplicationBuilder" + } + ], + "ReturnType": "Microsoft.AspNetCore.Builder.IApplicationBuilder", + "Static": true, + "Extension": true, + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "UseHttpMethodOverride", + "Parameters": [ + { + "Name": "builder", + "Type": "Microsoft.AspNetCore.Builder.IApplicationBuilder" + }, + { + "Name": "options", + "Type": "Microsoft.AspNetCore.Builder.HttpMethodOverrideOptions" + } + ], + "ReturnType": "Microsoft.AspNetCore.Builder.IApplicationBuilder", + "Static": true, + "Extension": true, + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.Builder.HttpMethodOverrideOptions", + "Visibility": "Public", + "Kind": "Class", + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Method", + "Name": "get_FormFieldName", + "Parameters": [], + "ReturnType": "System.String", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "set_FormFieldName", + "Parameters": [ + { + "Name": "value", + "Type": "System.String" + } + ], + "ReturnType": "System.Void", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [], + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.HttpOverrides.ForwardedHeaders", + "Visibility": "Public", + "Kind": "Enumeration", + "Sealed": true, + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Field", + "Name": "None", + "Parameters": [], + "GenericParameter": [], + "Literal": "0" + }, + { + "Kind": "Field", + "Name": "XForwardedFor", + "Parameters": [], + "GenericParameter": [], + "Literal": "1" + }, + { + "Kind": "Field", + "Name": "XForwardedHost", + "Parameters": [], + "GenericParameter": [], + "Literal": "2" + }, + { + "Kind": "Field", + "Name": "XForwardedProto", + "Parameters": [], + "GenericParameter": [], + "Literal": "4" + }, + { + "Kind": "Field", + "Name": "All", + "Parameters": [], + "GenericParameter": [], + "Literal": "7" + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.HttpOverrides.ForwardedHeadersMiddleware", + "Visibility": "Public", + "Kind": "Class", + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Method", + "Name": "Invoke", + "Parameters": [ + { + "Name": "context", + "Type": "Microsoft.AspNetCore.Http.HttpContext" + } + ], + "ReturnType": "System.Threading.Tasks.Task", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "ApplyForwarders", + "Parameters": [ + { + "Name": "context", + "Type": "Microsoft.AspNetCore.Http.HttpContext" + } + ], + "ReturnType": "System.Void", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [ + { + "Name": "next", + "Type": "Microsoft.AspNetCore.Http.RequestDelegate" + }, + { + "Name": "loggerFactory", + "Type": "Microsoft.Extensions.Logging.ILoggerFactory" + }, + { + "Name": "options", + "Type": "Microsoft.Extensions.Options.IOptions" + } + ], + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.HttpOverrides.HttpMethodOverrideMiddleware", + "Visibility": "Public", + "Kind": "Class", + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Method", + "Name": "Invoke", + "Parameters": [ + { + "Name": "context", + "Type": "Microsoft.AspNetCore.Http.HttpContext" + } + ], + "ReturnType": "System.Threading.Tasks.Task", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [ + { + "Name": "next", + "Type": "Microsoft.AspNetCore.Http.RequestDelegate" + }, + { + "Name": "options", + "Type": "Microsoft.Extensions.Options.IOptions" + } + ], + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.HttpOverrides.IPNetwork", + "Visibility": "Public", + "Kind": "Class", + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Method", + "Name": "get_Prefix", + "Parameters": [], + "ReturnType": "System.Net.IPAddress", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "get_PrefixLength", + "Parameters": [], + "ReturnType": "System.Int32", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "Contains", + "Parameters": [ + { + "Name": "address", + "Type": "System.Net.IPAddress" + } + ], + "ReturnType": "System.Boolean", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [ + { + "Name": "prefix", + "Type": "System.Net.IPAddress" + }, + { + "Name": "prefixLength", + "Type": "System.Int32" + } + ], + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.HttpOverrides.Internal.IPEndPointParser", + "Visibility": "Public", + "Kind": "Class", + "Abstract": true, + "Static": true, + "Sealed": true, + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Method", + "Name": "TryParse", + "Parameters": [ + { + "Name": "addressWithPort", + "Type": "System.String" + }, + { + "Name": "endpoint", + "Type": "System.Net.IPEndPoint", + "Direction": "Out" + } + ], + "ReturnType": "System.Boolean", + "Static": true, + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + } + ] +} \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.HttpOverrides/baseline.netcore.json b/src/Microsoft.AspNetCore.HttpOverrides/baseline.netcore.json new file mode 100644 index 0000000000..4a5e5a6e3e --- /dev/null +++ b/src/Microsoft.AspNetCore.HttpOverrides/baseline.netcore.json @@ -0,0 +1,452 @@ +{ + "AssemblyIdentity": "Microsoft.AspNetCore.HttpOverrides, Version=1.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60", + "Types": [ + { + "Name": "Microsoft.AspNetCore.Builder.ForwardedHeadersExtensions", + "Visibility": "Public", + "Kind": "Class", + "Abstract": true, + "Static": true, + "Sealed": true, + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Method", + "Name": "UseForwardedHeaders", + "Parameters": [ + { + "Name": "builder", + "Type": "Microsoft.AspNetCore.Builder.IApplicationBuilder" + } + ], + "ReturnType": "Microsoft.AspNetCore.Builder.IApplicationBuilder", + "Static": true, + "Extension": true, + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "UseForwardedHeaders", + "Parameters": [ + { + "Name": "builder", + "Type": "Microsoft.AspNetCore.Builder.IApplicationBuilder" + }, + { + "Name": "options", + "Type": "Microsoft.AspNetCore.Builder.ForwardedHeadersOptions" + } + ], + "ReturnType": "Microsoft.AspNetCore.Builder.IApplicationBuilder", + "Static": true, + "Extension": true, + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.Builder.ForwardedHeadersOptions", + "Visibility": "Public", + "Kind": "Class", + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Method", + "Name": "get_ForwardedHeaders", + "Parameters": [], + "ReturnType": "Microsoft.AspNetCore.HttpOverrides.ForwardedHeaders", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "set_ForwardedHeaders", + "Parameters": [ + { + "Name": "value", + "Type": "Microsoft.AspNetCore.HttpOverrides.ForwardedHeaders" + } + ], + "ReturnType": "System.Void", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "get_ForwardLimit", + "Parameters": [], + "ReturnType": "System.Nullable", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "set_ForwardLimit", + "Parameters": [ + { + "Name": "value", + "Type": "System.Nullable" + } + ], + "ReturnType": "System.Void", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "get_KnownProxies", + "Parameters": [], + "ReturnType": "System.Collections.Generic.IList", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "get_KnownNetworks", + "Parameters": [], + "ReturnType": "System.Collections.Generic.IList", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "get_RequireHeaderSymmetry", + "Parameters": [], + "ReturnType": "System.Boolean", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "set_RequireHeaderSymmetry", + "Parameters": [ + { + "Name": "value", + "Type": "System.Boolean" + } + ], + "ReturnType": "System.Void", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [], + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.Builder.HttpMethodOverrideExtensions", + "Visibility": "Public", + "Kind": "Class", + "Abstract": true, + "Static": true, + "Sealed": true, + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Method", + "Name": "UseHttpMethodOverride", + "Parameters": [ + { + "Name": "builder", + "Type": "Microsoft.AspNetCore.Builder.IApplicationBuilder" + } + ], + "ReturnType": "Microsoft.AspNetCore.Builder.IApplicationBuilder", + "Static": true, + "Extension": true, + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "UseHttpMethodOverride", + "Parameters": [ + { + "Name": "builder", + "Type": "Microsoft.AspNetCore.Builder.IApplicationBuilder" + }, + { + "Name": "options", + "Type": "Microsoft.AspNetCore.Builder.HttpMethodOverrideOptions" + } + ], + "ReturnType": "Microsoft.AspNetCore.Builder.IApplicationBuilder", + "Static": true, + "Extension": true, + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.Builder.HttpMethodOverrideOptions", + "Visibility": "Public", + "Kind": "Class", + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Method", + "Name": "get_FormFieldName", + "Parameters": [], + "ReturnType": "System.String", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "set_FormFieldName", + "Parameters": [ + { + "Name": "value", + "Type": "System.String" + } + ], + "ReturnType": "System.Void", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [], + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.HttpOverrides.ForwardedHeaders", + "Visibility": "Public", + "Kind": "Enumeration", + "Sealed": true, + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Field", + "Name": "None", + "Parameters": [], + "GenericParameter": [], + "Literal": "0" + }, + { + "Kind": "Field", + "Name": "XForwardedFor", + "Parameters": [], + "GenericParameter": [], + "Literal": "1" + }, + { + "Kind": "Field", + "Name": "XForwardedHost", + "Parameters": [], + "GenericParameter": [], + "Literal": "2" + }, + { + "Kind": "Field", + "Name": "XForwardedProto", + "Parameters": [], + "GenericParameter": [], + "Literal": "4" + }, + { + "Kind": "Field", + "Name": "All", + "Parameters": [], + "GenericParameter": [], + "Literal": "7" + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.HttpOverrides.ForwardedHeadersMiddleware", + "Visibility": "Public", + "Kind": "Class", + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Method", + "Name": "Invoke", + "Parameters": [ + { + "Name": "context", + "Type": "Microsoft.AspNetCore.Http.HttpContext" + } + ], + "ReturnType": "System.Threading.Tasks.Task", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "ApplyForwarders", + "Parameters": [ + { + "Name": "context", + "Type": "Microsoft.AspNetCore.Http.HttpContext" + } + ], + "ReturnType": "System.Void", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [ + { + "Name": "next", + "Type": "Microsoft.AspNetCore.Http.RequestDelegate" + }, + { + "Name": "loggerFactory", + "Type": "Microsoft.Extensions.Logging.ILoggerFactory" + }, + { + "Name": "options", + "Type": "Microsoft.Extensions.Options.IOptions" + } + ], + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.HttpOverrides.HttpMethodOverrideMiddleware", + "Visibility": "Public", + "Kind": "Class", + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Method", + "Name": "Invoke", + "Parameters": [ + { + "Name": "context", + "Type": "Microsoft.AspNetCore.Http.HttpContext" + } + ], + "ReturnType": "System.Threading.Tasks.Task", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [ + { + "Name": "next", + "Type": "Microsoft.AspNetCore.Http.RequestDelegate" + }, + { + "Name": "options", + "Type": "Microsoft.Extensions.Options.IOptions" + } + ], + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.HttpOverrides.IPNetwork", + "Visibility": "Public", + "Kind": "Class", + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Method", + "Name": "get_Prefix", + "Parameters": [], + "ReturnType": "System.Net.IPAddress", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "get_PrefixLength", + "Parameters": [], + "ReturnType": "System.Int32", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "Contains", + "Parameters": [ + { + "Name": "address", + "Type": "System.Net.IPAddress" + } + ], + "ReturnType": "System.Boolean", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [ + { + "Name": "prefix", + "Type": "System.Net.IPAddress" + }, + { + "Name": "prefixLength", + "Type": "System.Int32" + } + ], + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.HttpOverrides.Internal.IPEndPointParser", + "Visibility": "Public", + "Kind": "Class", + "Abstract": true, + "Static": true, + "Sealed": true, + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Method", + "Name": "TryParse", + "Parameters": [ + { + "Name": "addressWithPort", + "Type": "System.String" + }, + { + "Name": "endpoint", + "Type": "System.Net.IPEndPoint", + "Direction": "Out" + } + ], + "ReturnType": "System.Boolean", + "Static": true, + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + } + ] +} \ No newline at end of file From 5d6fcb07da752931416fc2a2cbf38376b7607573 Mon Sep 17 00:00:00 2001 From: Mikael Mengistu Date: Fri, 4 Nov 2016 17:59:04 -0700 Subject: [PATCH 151/307] Throw for trackAllCaptures --- .../IISUrlRewrite/UrlRewriteFileParser.cs | 4 ++++ .../FormatExceptionHandlingTests.cs | 21 +++++++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/UrlRewriteFileParser.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/UrlRewriteFileParser.cs index c8d20bedb8..889d3e209a 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/UrlRewriteFileParser.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/UrlRewriteFileParser.cs @@ -110,6 +110,10 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite var grouping = ParseEnum(conditions, RewriteTags.LogicalGrouping, LogicalGrouping.MatchAll); var trackAllCaptures = ParseBool(conditions, RewriteTags.TrackAllCaptures, defaultValue: false); + if (trackAllCaptures) + { + throw new NotSupportedException("Support for trackAllCaptures has not been implemented yet"); + } builder.AddUrlConditions(grouping, trackAllCaptures); foreach (var cond in conditions.Elements(RewriteTags.Add)) diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/FormatExceptionHandlingTests.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/FormatExceptionHandlingTests.cs index c14f062e64..575135b543 100644 --- a/test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/FormatExceptionHandlingTests.cs +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/FormatExceptionHandlingTests.cs @@ -264,5 +264,26 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite var ex = Assert.Throws(() => new UrlRewriteFileParser().Parse(new StringReader(input))); Assert.Equal(expected, ex.Message); } + + [Theory] + [InlineData( +@" + + + + + + + + + +", + "Support for trackAllCaptures has not been implemented yet")] + public void ThrowNotSupportedExceptionWithCorrectMessage(string input, string expected) + { + // Arrange, Act, Assert + var ex = Assert.Throws(() => new UrlRewriteFileParser().Parse(new StringReader(input))); + Assert.Equal(expected, ex.Message); + } } } From 40da77eb17f090f51186014bd20e639c83f4f9dc Mon Sep 17 00:00:00 2001 From: Mikael Mengistu Date: Mon, 7 Nov 2016 14:16:53 -0800 Subject: [PATCH 152/307] RedirectToHttps uses status code parameter --- .../Internal/RedirectToHttpsRule.cs | 6 ++- .../MiddlewareTests.cs | 46 +++++++++++++++++-- 2 files changed, 47 insertions(+), 5 deletions(-) diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/RedirectToHttpsRule.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/RedirectToHttpsRule.cs index 6fb1fbf2b7..46d434d128 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/RedirectToHttpsRule.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/RedirectToHttpsRule.cs @@ -4,6 +4,7 @@ using System.Text; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Rewrite.Logging; +using Microsoft.Net.Http.Headers; namespace Microsoft.AspNetCore.Rewrite.Internal { @@ -29,9 +30,10 @@ namespace Microsoft.AspNetCore.Rewrite.Internal } var req = context.HttpContext.Request; - var newUrl = new StringBuilder().Append("https://").Append(host).Append(req.PathBase).Append(req.Path).Append(req.QueryString); - context.HttpContext.Response.Redirect(newUrl.ToString()); + var response = context.HttpContext.Response; + response.StatusCode = StatusCode; + response.Headers[HeaderNames.Location] = newUrl.ToString(); context.Result = RuleResult.EndResponse; context.Logger?.RedirectedToHttps(); } diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/MiddlewareTests.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/MiddlewareTests.cs index 43853ddfe5..74f4e599d8 100644 --- a/test/Microsoft.AspNetCore.Rewrite.Tests/MiddlewareTests.cs +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/MiddlewareTests.cs @@ -51,10 +51,14 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.CodeRules Assert.Equal("http://example.com/foo", response.Headers.Location.OriginalString); } - [Fact] - public async Task CheckRedirectToHttps() + [Theory] + [InlineData(StatusCodes.Status301MovedPermanently)] + [InlineData(StatusCodes.Status302Found)] + [InlineData(StatusCodes.Status307TemporaryRedirect)] + [InlineData(StatusCodes.Status308PermanentRedirect)] + public async Task CheckRedirectToHttps(int statusCode) { - var options = new RewriteOptions().AddRedirectToHttps(statusCode: StatusCodes.Status301MovedPermanently); + var options = new RewriteOptions().AddRedirectToHttps(statusCode: statusCode); var builder = new WebHostBuilder() .Configure(app => { @@ -65,8 +69,44 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.CodeRules var response = await server.CreateClient().GetAsync(new Uri("http://example.com")); Assert.Equal("https://example.com/", response.Headers.Location.OriginalString); + Assert.Equal(statusCode, (int)response.StatusCode); } + [Fact] + public async Task CheckPermanentRedirectToHttps() + { + var options = new RewriteOptions().AddRedirectToHttpsPermanent(); + var builder = new WebHostBuilder() + .Configure(app => + { + app.UseRewriter(options); + }); + var server = new TestServer(builder); + + var response = await server.CreateClient().GetAsync(new Uri("http://example.com")); + + Assert.Equal("https://example.com/", response.Headers.Location.OriginalString); + Assert.Equal(StatusCodes.Status301MovedPermanently, (int)response.StatusCode); + } + + [Theory] + [InlineData(25, "https://example.com:25/")] + [InlineData(-25, "https://example.com/")] + public async Task CheckRedirectToHttpsWithSslPort(int sslPort,string expected) + { + var options = new RewriteOptions().AddRedirectToHttps(statusCode: StatusCodes.Status301MovedPermanently, sslPort:sslPort); + var builder = new WebHostBuilder() + .Configure(app => + { + app.UseRewriter(options); + }); + var server = new TestServer(builder); + + var response = await server.CreateClient().GetAsync(new Uri("http://example.com")); + + Assert.Equal(expected, response.Headers.Location.OriginalString); + Assert.Equal(StatusCodes.Status301MovedPermanently, (int)response.StatusCode); + } [Fact] public async Task CheckIfEmptyStringRedirectCorrectly() From 4a422dba9b5be58137f099a7f10040795a4034cf Mon Sep 17 00:00:00 2001 From: Pranav K Date: Wed, 9 Nov 2016 11:29:11 -0800 Subject: [PATCH 153/307] Branching for 1.1.0 --- NuGet.config | 4 ++-- build.ps1 | 2 +- build.sh | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/NuGet.config b/NuGet.config index a696a0a743..1b1203d77e 100644 --- a/NuGet.config +++ b/NuGet.config @@ -1,7 +1,7 @@ - + - + \ No newline at end of file diff --git a/build.ps1 b/build.ps1 index 8f2f99691a..24ca167cf6 100644 --- a/build.ps1 +++ b/build.ps1 @@ -33,7 +33,7 @@ cd $PSScriptRoot $repoFolder = $PSScriptRoot $env:REPO_FOLDER = $repoFolder -$koreBuildZip="https://github.com/aspnet/KoreBuild/archive/dev.zip" +$koreBuildZip="https://github.com/aspnet/KoreBuild/archive/rel/1.1.0.zip" if ($env:KOREBUILD_ZIP) { $koreBuildZip=$env:KOREBUILD_ZIP diff --git a/build.sh b/build.sh index f4208100eb..fea9ac64ad 100755 --- a/build.sh +++ b/build.sh @@ -2,7 +2,7 @@ repoFolder="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" cd $repoFolder -koreBuildZip="https://github.com/aspnet/KoreBuild/archive/dev.zip" +koreBuildZip="https://github.com/aspnet/KoreBuild/archive/rel/1.1.0.zip" if [ ! -z $KOREBUILD_ZIP ]; then koreBuildZip=$KOREBUILD_ZIP fi From 445dcd9f1a0a185f0a47be545b523345d9dd84a3 Mon Sep 17 00:00:00 2001 From: Pranav K Date: Wed, 9 Nov 2016 14:12:31 -0800 Subject: [PATCH 154/307] Updating versions to 1.2.0-* --- samples/HttpOverridesSample/project.json | 6 +++--- samples/ResponseBufferingSample/project.json | 4 ++-- samples/ResponseCompressionSample/project.json | 6 +++--- samples/RewriteSample/project.json | 4 ++-- src/Microsoft.AspNetCore.Buffering/project.json | 6 +++--- .../project.json | 8 ++++---- .../project.json | 6 +++--- src/Microsoft.AspNetCore.Rewrite/project.json | 16 ++++++++-------- .../project.json | 4 ++-- .../project.json | 8 ++++---- .../project.json | 6 +++--- .../project.json | 4 ++-- 12 files changed, 39 insertions(+), 39 deletions(-) diff --git a/samples/HttpOverridesSample/project.json b/samples/HttpOverridesSample/project.json index 2d0730a7d1..de87878e69 100644 --- a/samples/HttpOverridesSample/project.json +++ b/samples/HttpOverridesSample/project.json @@ -1,5 +1,5 @@ { - "version": "1.1.0-*", + "version": "1.2.0-*", "buildOptions": { "emitEntryPoint": true }, @@ -10,8 +10,8 @@ ] }, "dependencies": { - "Microsoft.AspNetCore.HttpOverrides": "1.1.0-*", - "Microsoft.AspNetCore.Server.Kestrel": "1.1.0-*" + "Microsoft.AspNetCore.HttpOverrides": "1.2.0-*", + "Microsoft.AspNetCore.Server.Kestrel": "1.2.0-*" }, "commands": { "web": "HttpOverridesSample" diff --git a/samples/ResponseBufferingSample/project.json b/samples/ResponseBufferingSample/project.json index 1cf3d053af..4df898b0ed 100644 --- a/samples/ResponseBufferingSample/project.json +++ b/samples/ResponseBufferingSample/project.json @@ -1,8 +1,8 @@ { - "version": "1.1.0-*", + "version": "1.2.0-*", "dependencies": { "Microsoft.AspNetCore.Buffering": "0.2.0-*", - "Microsoft.AspNetCore.Server.Kestrel": "1.1.0-*" + "Microsoft.AspNetCore.Server.Kestrel": "1.2.0-*" }, "buildOptions": { "emitEntryPoint": true diff --git a/samples/ResponseCompressionSample/project.json b/samples/ResponseCompressionSample/project.json index 66e8ca15f8..8c3e7f211b 100644 --- a/samples/ResponseCompressionSample/project.json +++ b/samples/ResponseCompressionSample/project.json @@ -1,9 +1,9 @@ { "dependencies": { "Microsoft.AspNetCore.ResponseCompression": "1.0.0-*", - "Microsoft.AspNetCore.Server.Kestrel": "1.1.0-*", - "Microsoft.AspNetCore.Server.WebListener": "1.1.0-*", - "Microsoft.Extensions.Logging.Console": "1.1.0-*" + "Microsoft.AspNetCore.Server.Kestrel": "1.2.0-*", + "Microsoft.AspNetCore.Server.WebListener": "1.2.0-*", + "Microsoft.Extensions.Logging.Console": "1.2.0-*" }, "buildOptions": { "copyToOutput": [ diff --git a/samples/RewriteSample/project.json b/samples/RewriteSample/project.json index eacc7ebe39..d017962809 100644 --- a/samples/RewriteSample/project.json +++ b/samples/RewriteSample/project.json @@ -1,8 +1,8 @@ { "dependencies": { "Microsoft.AspNetCore.Rewrite": "1.0.0-*", - "Microsoft.AspNetCore.Server.Kestrel": "1.1.0-*", - "Microsoft.AspNetCore.Server.Kestrel.Https": "1.1.0-*" + "Microsoft.AspNetCore.Server.Kestrel": "1.2.0-*", + "Microsoft.AspNetCore.Server.Kestrel.Https": "1.2.0-*" }, "buildOptions": { "emitEntryPoint": true, diff --git a/src/Microsoft.AspNetCore.Buffering/project.json b/src/Microsoft.AspNetCore.Buffering/project.json index 6e2f2da65a..5a3b7b54be 100644 --- a/src/Microsoft.AspNetCore.Buffering/project.json +++ b/src/Microsoft.AspNetCore.Buffering/project.json @@ -1,5 +1,5 @@ { - "version": "0.2.0-*", + "version": "1.2.0-*", "buildOptions": { "warningsAsErrors": true, "keyFile": "../../tools/Key.snk", @@ -21,9 +21,9 @@ ] }, "dependencies": { - "Microsoft.AspNetCore.Http.Abstractions": "1.1.0-*", + "Microsoft.AspNetCore.Http.Abstractions": "1.2.0-*", "Microsoft.Extensions.TaskCache.Sources": { - "version": "1.1.0-*", + "version": "1.2.0-*", "type": "build" }, "NETStandard.Library": "1.6.1-*" diff --git a/src/Microsoft.AspNetCore.HttpOverrides/project.json b/src/Microsoft.AspNetCore.HttpOverrides/project.json index 14af60066c..a98d971159 100644 --- a/src/Microsoft.AspNetCore.HttpOverrides/project.json +++ b/src/Microsoft.AspNetCore.HttpOverrides/project.json @@ -1,5 +1,5 @@ { - "version": "1.1.0-*", + "version": "1.2.0-*", "buildOptions": { "warningsAsErrors": true, "keyFile": "../../tools/Key.snk", @@ -22,9 +22,9 @@ ] }, "dependencies": { - "Microsoft.AspNetCore.Http.Extensions": "1.1.0-*", - "Microsoft.Extensions.Logging.Abstractions": "1.1.0-*", - "Microsoft.Extensions.Options": "1.1.0-*", + "Microsoft.AspNetCore.Http.Extensions": "1.2.0-*", + "Microsoft.Extensions.Logging.Abstractions": "1.2.0-*", + "Microsoft.Extensions.Options": "1.2.0-*", "NETStandard.Library": "1.6.1-*" }, "frameworks": { diff --git a/src/Microsoft.AspNetCore.ResponseCompression/project.json b/src/Microsoft.AspNetCore.ResponseCompression/project.json index a5ec506c84..be72b6f541 100644 --- a/src/Microsoft.AspNetCore.ResponseCompression/project.json +++ b/src/Microsoft.AspNetCore.ResponseCompression/project.json @@ -1,5 +1,5 @@ { - "version": "1.0.0-*", + "version": "1.2.0-*", "buildOptions": { "warningsAsErrors": true, "keyFile": "../../tools/Key.snk", @@ -16,8 +16,8 @@ ] }, "dependencies": { - "Microsoft.AspNetCore.Http.Extensions": "1.1.0-*", - "Microsoft.Extensions.Options": "1.1.0-*", + "Microsoft.AspNetCore.Http.Extensions": "1.2.0-*", + "Microsoft.Extensions.Options": "1.2.0-*", "NETStandard.Library": "1.6.1-*" }, "frameworks": { diff --git a/src/Microsoft.AspNetCore.Rewrite/project.json b/src/Microsoft.AspNetCore.Rewrite/project.json index e9f3c91ce5..8aab89db04 100644 --- a/src/Microsoft.AspNetCore.Rewrite/project.json +++ b/src/Microsoft.AspNetCore.Rewrite/project.json @@ -1,5 +1,5 @@ { - "version": "1.0.0-*", + "version": "1.2.0-*", "buildOptions": { "warningsAsErrors": true, "keyFile": "../../tools/Key.snk", @@ -21,14 +21,14 @@ ] }, "dependencies": { - "Microsoft.AspNetCore.Hosting.Abstractions": "1.1.0-*", - "Microsoft.AspNetCore.Http.Extensions": "1.1.0-*", - "Microsoft.Extensions.Configuration.Abstractions": "1.1.0-*", - "Microsoft.Extensions.FileProviders.Abstractions": "1.1.0-*", - "Microsoft.Extensions.Logging.Abstractions": "1.1.0-*", - "Microsoft.Extensions.Options": "1.1.0-*", + "Microsoft.AspNetCore.Hosting.Abstractions": "1.2.0-*", + "Microsoft.AspNetCore.Http.Extensions": "1.2.0-*", + "Microsoft.Extensions.Configuration.Abstractions": "1.2.0-*", + "Microsoft.Extensions.FileProviders.Abstractions": "1.2.0-*", + "Microsoft.Extensions.Logging.Abstractions": "1.2.0-*", + "Microsoft.Extensions.Options": "1.2.0-*", "Microsoft.Extensions.TaskCache.Sources": { - "version": "1.1.0-*", + "version": "1.2.0-*", "type": "build" }, "NETStandard.Library": "1.6.1-*" diff --git a/test/Microsoft.AspNetCore.Buffering.Tests/project.json b/test/Microsoft.AspNetCore.Buffering.Tests/project.json index 0fa3b7ef85..c4cdf63dcf 100644 --- a/test/Microsoft.AspNetCore.Buffering.Tests/project.json +++ b/test/Microsoft.AspNetCore.Buffering.Tests/project.json @@ -1,12 +1,12 @@ { - "version": "1.1.0-*", + "version": "1.2.0-*", "buildOptions": { "warningsAsErrors": true }, "dependencies": { "dotnet-test-xunit": "2.2.0-*", "Microsoft.AspNetCore.Buffering": "0.2.0-*", - "Microsoft.AspNetCore.TestHost": "1.1.0-*", + "Microsoft.AspNetCore.TestHost": "1.2.0-*", "xunit": "2.2.0-*" }, "frameworks": { diff --git a/test/Microsoft.AspNetCore.HttpOverrides.Tests/project.json b/test/Microsoft.AspNetCore.HttpOverrides.Tests/project.json index 461246f3db..79d4c760be 100644 --- a/test/Microsoft.AspNetCore.HttpOverrides.Tests/project.json +++ b/test/Microsoft.AspNetCore.HttpOverrides.Tests/project.json @@ -1,13 +1,13 @@ { - "version": "1.1.0-*", + "version": "1.2.0-*", "buildOptions": { "warningsAsErrors": true }, "dependencies": { "dotnet-test-xunit": "2.2.0-*", - "Microsoft.AspNetCore.HttpOverrides": "1.1.0-*", - "Microsoft.AspNetCore.TestHost": "1.1.0-*", - "Microsoft.Extensions.Logging.Testing": "1.1.0-*", + "Microsoft.AspNetCore.HttpOverrides": "1.2.0-*", + "Microsoft.AspNetCore.TestHost": "1.2.0-*", + "Microsoft.Extensions.Logging.Testing": "1.2.0-*", "xunit": "2.2.0-*" }, "frameworks": { diff --git a/test/Microsoft.AspNetCore.ResponseCompression.Tests/project.json b/test/Microsoft.AspNetCore.ResponseCompression.Tests/project.json index 18ac32240e..488f348374 100644 --- a/test/Microsoft.AspNetCore.ResponseCompression.Tests/project.json +++ b/test/Microsoft.AspNetCore.ResponseCompression.Tests/project.json @@ -8,10 +8,10 @@ }, "dependencies": { "dotnet-test-xunit": "2.2.0-*", - "Microsoft.AspNetCore.Http": "1.1.0-*", + "Microsoft.AspNetCore.Http": "1.2.0-*", "Microsoft.AspNetCore.ResponseCompression": "1.0.0-*", - "Microsoft.AspNetCore.TestHost": "1.1.0-*", - "Microsoft.Net.Http.Headers": "1.1.0-*", + "Microsoft.AspNetCore.TestHost": "1.2.0-*", + "Microsoft.Net.Http.Headers": "1.2.0-*", "Moq": "4.6.36-*", "xunit": "2.2.0-*" }, diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/project.json b/test/Microsoft.AspNetCore.Rewrite.Tests/project.json index d0ad72b857..f42fc6eb79 100644 --- a/test/Microsoft.AspNetCore.Rewrite.Tests/project.json +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/project.json @@ -6,8 +6,8 @@ "dependencies": { "dotnet-test-xunit": "2.2.0-*", "Microsoft.AspNetCore.Rewrite": "1.0.0-*", - "Microsoft.AspNetCore.TestHost": "1.1.0-*", - "Microsoft.Extensions.Logging.Testing": "1.1.0-*", + "Microsoft.AspNetCore.TestHost": "1.2.0-*", + "Microsoft.Extensions.Logging.Testing": "1.2.0-*", "xunit": "2.2.0-*" }, "frameworks": { From e35814ac583fa3f11f876182f90fd9e319de673f Mon Sep 17 00:00:00 2001 From: Pranav K Date: Wed, 9 Nov 2016 14:25:04 -0800 Subject: [PATCH 155/307] Fix versioning --- samples/HttpOverridesSample/project.json | 1 - samples/ResponseBufferingSample/project.json | 3 +-- src/Microsoft.AspNetCore.Buffering/project.json | 2 +- test/Microsoft.AspNetCore.Buffering.Tests/project.json | 2 +- 4 files changed, 3 insertions(+), 5 deletions(-) diff --git a/samples/HttpOverridesSample/project.json b/samples/HttpOverridesSample/project.json index de87878e69..1a4c261a77 100644 --- a/samples/HttpOverridesSample/project.json +++ b/samples/HttpOverridesSample/project.json @@ -1,5 +1,4 @@ { - "version": "1.2.0-*", "buildOptions": { "emitEntryPoint": true }, diff --git a/samples/ResponseBufferingSample/project.json b/samples/ResponseBufferingSample/project.json index 4df898b0ed..d68ffcf804 100644 --- a/samples/ResponseBufferingSample/project.json +++ b/samples/ResponseBufferingSample/project.json @@ -1,7 +1,6 @@ { - "version": "1.2.0-*", "dependencies": { - "Microsoft.AspNetCore.Buffering": "0.2.0-*", + "Microsoft.AspNetCore.Buffering": "0.3.0-*", "Microsoft.AspNetCore.Server.Kestrel": "1.2.0-*" }, "buildOptions": { diff --git a/src/Microsoft.AspNetCore.Buffering/project.json b/src/Microsoft.AspNetCore.Buffering/project.json index 5a3b7b54be..41a108d367 100644 --- a/src/Microsoft.AspNetCore.Buffering/project.json +++ b/src/Microsoft.AspNetCore.Buffering/project.json @@ -1,5 +1,5 @@ { - "version": "1.2.0-*", + "version": "0.3.0-*", "buildOptions": { "warningsAsErrors": true, "keyFile": "../../tools/Key.snk", diff --git a/test/Microsoft.AspNetCore.Buffering.Tests/project.json b/test/Microsoft.AspNetCore.Buffering.Tests/project.json index c4cdf63dcf..1683c84807 100644 --- a/test/Microsoft.AspNetCore.Buffering.Tests/project.json +++ b/test/Microsoft.AspNetCore.Buffering.Tests/project.json @@ -5,7 +5,7 @@ }, "dependencies": { "dotnet-test-xunit": "2.2.0-*", - "Microsoft.AspNetCore.Buffering": "0.2.0-*", + "Microsoft.AspNetCore.Buffering": "0.3.0-*", "Microsoft.AspNetCore.TestHost": "1.2.0-*", "xunit": "2.2.0-*" }, From ea0042c685ba2228d0d4b85df41fa45a0b360f00 Mon Sep 17 00:00:00 2001 From: Pranav K Date: Thu, 10 Nov 2016 08:01:34 -0800 Subject: [PATCH 156/307] Fix more versioning --- samples/ResponseCompressionSample/project.json | 2 +- samples/RewriteSample/project.json | 2 +- src/Microsoft.AspNetCore.ResponseCompression/project.json | 2 +- src/Microsoft.AspNetCore.Rewrite/project.json | 2 +- .../Microsoft.AspNetCore.ResponseCompression.Tests/project.json | 2 +- test/Microsoft.AspNetCore.Rewrite.Tests/project.json | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/samples/ResponseCompressionSample/project.json b/samples/ResponseCompressionSample/project.json index 8c3e7f211b..ab2b8280bc 100644 --- a/samples/ResponseCompressionSample/project.json +++ b/samples/ResponseCompressionSample/project.json @@ -1,6 +1,6 @@ { "dependencies": { - "Microsoft.AspNetCore.ResponseCompression": "1.0.0-*", + "Microsoft.AspNetCore.ResponseCompression": "1.1.0-*", "Microsoft.AspNetCore.Server.Kestrel": "1.2.0-*", "Microsoft.AspNetCore.Server.WebListener": "1.2.0-*", "Microsoft.Extensions.Logging.Console": "1.2.0-*" diff --git a/samples/RewriteSample/project.json b/samples/RewriteSample/project.json index d017962809..18031712b1 100644 --- a/samples/RewriteSample/project.json +++ b/samples/RewriteSample/project.json @@ -1,6 +1,6 @@ { "dependencies": { - "Microsoft.AspNetCore.Rewrite": "1.0.0-*", + "Microsoft.AspNetCore.Rewrite": "1.1.0-*", "Microsoft.AspNetCore.Server.Kestrel": "1.2.0-*", "Microsoft.AspNetCore.Server.Kestrel.Https": "1.2.0-*" }, diff --git a/src/Microsoft.AspNetCore.ResponseCompression/project.json b/src/Microsoft.AspNetCore.ResponseCompression/project.json index be72b6f541..3da8e8223f 100644 --- a/src/Microsoft.AspNetCore.ResponseCompression/project.json +++ b/src/Microsoft.AspNetCore.ResponseCompression/project.json @@ -1,5 +1,5 @@ { - "version": "1.2.0-*", + "version": "1.1.0-*", "buildOptions": { "warningsAsErrors": true, "keyFile": "../../tools/Key.snk", diff --git a/src/Microsoft.AspNetCore.Rewrite/project.json b/src/Microsoft.AspNetCore.Rewrite/project.json index 8aab89db04..608a7908eb 100644 --- a/src/Microsoft.AspNetCore.Rewrite/project.json +++ b/src/Microsoft.AspNetCore.Rewrite/project.json @@ -1,5 +1,5 @@ { - "version": "1.2.0-*", + "version": "1.1.0-*", "buildOptions": { "warningsAsErrors": true, "keyFile": "../../tools/Key.snk", diff --git a/test/Microsoft.AspNetCore.ResponseCompression.Tests/project.json b/test/Microsoft.AspNetCore.ResponseCompression.Tests/project.json index 488f348374..99b439dbf9 100644 --- a/test/Microsoft.AspNetCore.ResponseCompression.Tests/project.json +++ b/test/Microsoft.AspNetCore.ResponseCompression.Tests/project.json @@ -9,7 +9,7 @@ "dependencies": { "dotnet-test-xunit": "2.2.0-*", "Microsoft.AspNetCore.Http": "1.2.0-*", - "Microsoft.AspNetCore.ResponseCompression": "1.0.0-*", + "Microsoft.AspNetCore.ResponseCompression": "1.1.0-*", "Microsoft.AspNetCore.TestHost": "1.2.0-*", "Microsoft.Net.Http.Headers": "1.2.0-*", "Moq": "4.6.36-*", diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/project.json b/test/Microsoft.AspNetCore.Rewrite.Tests/project.json index f42fc6eb79..7120835f39 100644 --- a/test/Microsoft.AspNetCore.Rewrite.Tests/project.json +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/project.json @@ -5,7 +5,7 @@ }, "dependencies": { "dotnet-test-xunit": "2.2.0-*", - "Microsoft.AspNetCore.Rewrite": "1.0.0-*", + "Microsoft.AspNetCore.Rewrite": "1.1.0-*", "Microsoft.AspNetCore.TestHost": "1.2.0-*", "Microsoft.Extensions.Logging.Testing": "1.2.0-*", "xunit": "2.2.0-*" From 111dc60d825b8cf2075ef6d0de4634aac0eaf50c Mon Sep 17 00:00:00 2001 From: Nate McMaster Date: Fri, 18 Nov 2016 10:56:56 -0800 Subject: [PATCH 157/307] Clean tmp folder after unzipping KoreBuild --- build.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.sh b/build.sh index f4208100eb..4fd7ede788 100755 --- a/build.sh +++ b/build.sh @@ -38,7 +38,7 @@ if test ! -d $buildFolder; then chmod +x $buildFile # Cleanup - if test ! -d $tempFolder; then + if test -d $tempFolder; then rm -rf $tempFolder fi fi From 4d9ef3ffeaea94324a58d663d2539d4024971e39 Mon Sep 17 00:00:00 2001 From: "N. Taylor Mullen" Date: Wed, 23 Nov 2016 16:00:46 -0800 Subject: [PATCH 158/307] Pin global.json SDK to 1.0.0-preview2-1-003177. --- global.json | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/global.json b/global.json index b0323e4281..f45e8cc925 100644 --- a/global.json +++ b/global.json @@ -1,3 +1,8 @@ { - "projects": [ "src" ] + "projects": [ + "src" + ], + "sdk": { + "version": "1.0.0-preview2-1-003177" + } } \ No newline at end of file From 515b5f6803e52c08cfc42490dfb8911a70739928 Mon Sep 17 00:00:00 2001 From: "N. Taylor Mullen" Date: Thu, 8 Dec 2016 10:04:33 -0800 Subject: [PATCH 159/307] Update .travis.yml osx image to xcode7.3. --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 6c42dd8a71..d7ee9c7df8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -19,7 +19,7 @@ mono: os: - linux - osx -osx_image: xcode7.1 +osx_image: xcode7.3 branches: only: - master From 46adbc3e8f2158801d491995477f8fae91da5c15 Mon Sep 17 00:00:00 2001 From: Ajay Bhargav Baaskaran Date: Mon, 12 Dec 2016 00:41:24 -0800 Subject: [PATCH 160/307] Removed packages list in NuGetPackageVerifier.json --- NuGetPackageVerifier.json | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/NuGetPackageVerifier.json b/NuGetPackageVerifier.json index 328612811e..b153ab1515 100644 --- a/NuGetPackageVerifier.json +++ b/NuGetPackageVerifier.json @@ -1,16 +1,5 @@ { - "adx": { // Packages written by the ADX team and that ship on NuGet.org - "rules": [ - "AdxVerificationCompositeRule" - ], - "packages": { - "Microsoft.AspNetCore.Buffering": { }, - "Microsoft.AspNetCore.HttpOverrides": { }, - "Microsoft.AspNetCore.Rewrite": { }, - "Microsoft.AspNetCore.ResponseCompression": { } - } - }, - "Default": { // Rules to run for packages not listed in any other set. + "Default": { "rules": [ "DefaultCompositeRule" ] From f813ee4d970dc7130acd4afd410cb95ab2305cfa Mon Sep 17 00:00:00 2001 From: Chris R Date: Tue, 20 Dec 2016 15:36:10 -0800 Subject: [PATCH 161/307] Adding support for trackAllCaptures (#178) --- .../ApacheModRewrite/ApacheModRewriteRule.cs | 8 +- .../Internal/BackReferenceCollection.cs | 53 +++++++++++ .../Internal/Condition.cs | 4 +- .../Internal/ConditionEvaluator.cs | 32 +++++-- .../IISUrlRewrite/IISUrlRewriteRule.cs | 13 +-- .../IISUrlRewrite/UrlRewriteFileParser.cs | 10 +-- .../IISUrlRewrite/UrlRewriteRuleBuilder.cs | 8 +- .../Internal/MatchResults.cs | 6 +- .../Internal/Pattern.cs | 4 +- .../Internal/PatternSegment.cs | 2 +- .../PatternSegments/ConditionMatchSegment.cs | 4 +- .../PatternSegments/DateTimeSegment.cs | 2 +- .../Internal/PatternSegments/HeaderSegment.cs | 2 +- .../PatternSegments/IsHttpsModSegment.cs | 4 +- .../PatternSegments/IsHttpsUrlSegment.cs | 6 +- .../Internal/PatternSegments/IsIPV6Segment.cs | 2 +- .../PatternSegments/LiteralSegment.cs | 2 +- .../PatternSegments/LocalAddressSegment.cs | 2 +- .../PatternSegments/LocalPortSegment.cs | 2 +- .../PatternSegments/QueryStringSegment.cs | 2 +- .../PatternSegments/RemoteAddressSegment.cs | 2 +- .../PatternSegments/RemotePortSegment.cs | 2 +- .../PatternSegments/RequestFilenameSegment.cs | 2 +- .../PatternSegments/RequestMethodSegment.cs | 2 +- .../PatternSegments/RuleMatchSegment.cs | 4 +- .../Internal/PatternSegments/SchemeSegment.cs | 2 +- .../PatternSegments/ServerProtocolSegment.cs | 2 +- .../PatternSegments/ToLowerSegment.cs | 4 +- .../PatternSegments/UrlEncodeSegment.cs | 4 +- .../Internal/PatternSegments/UrlSegment.cs | 2 +- .../Internal/UrlAction.cs | 2 +- .../Internal/UrlActions/AbortAction.cs | 2 +- .../Internal/UrlActions/ChangeCookieAction.cs | 2 +- .../Internal/UrlActions/ForbiddenAction.cs | 2 +- .../Internal/UrlActions/GoneAction.cs | 2 +- .../Internal/UrlActions/RedirectAction.cs | 4 +- .../Internal/UrlActions/RewriteAction.cs | 4 +- .../Internal/UrlActions/VoidAction.cs | 2 +- .../Internal/UrlMatches/ExactMatch.cs | 10 ++- .../Internal/UrlMatches/RegexMatch.cs | 2 +- .../ModRewriteMiddlewareTest.cs | 12 +-- .../IISUrlRewrite/FileParserTests.cs | 2 +- .../FormatExceptionHandlingTests.cs | 21 ----- .../IISUrlRewrite/InputParserTests.cs | 14 +-- .../IISUrlRewrite/MiddleWareTests.cs | 87 ++++++++++++++++++- .../IISUrlRewrite/ServerVariableTests.cs | 8 +- .../UrlRewriteApplicationTests.cs | 23 +++++ .../ConditionMatchSegmentTests.cs | 4 +- .../PatternSegments/RuleMatchSegmentTests.cs | 4 +- .../project.json | 1 + 50 files changed, 284 insertions(+), 118 deletions(-) create mode 100644 src/Microsoft.AspNetCore.Rewrite/Internal/BackReferenceCollection.cs diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/ApacheModRewrite/ApacheModRewriteRule.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/ApacheModRewrite/ApacheModRewriteRule.cs index ffb907f304..a6d03b7fba 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/ApacheModRewrite/ApacheModRewriteRule.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/ApacheModRewrite/ApacheModRewriteRule.cs @@ -30,11 +30,11 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.ApacheModRewrite return; } - MatchResults condMatchRes = null; + BackReferenceCollection condBackReferences = null; if (Conditions != null) { - condMatchRes = ConditionHelper.Evaluate(Conditions, context, initMatchRes); - if (!condMatchRes.Success) + var condResult = ConditionHelper.Evaluate(Conditions, context, initMatchRes.BackReferences); + if (!condResult.Success) { context.Logger?.ModRewriteDidNotMatchRule(); return; @@ -47,7 +47,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.ApacheModRewrite foreach (var action in Actions) { - action.ApplyAction(context, initMatchRes, condMatchRes); + action.ApplyAction(context, initMatchRes?.BackReferences, condBackReferences); } } } diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/BackReferenceCollection.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/BackReferenceCollection.cs new file mode 100644 index 0000000000..32b91a19ce --- /dev/null +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/BackReferenceCollection.cs @@ -0,0 +1,53 @@ +// 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; +using System.Collections.Generic; +using System.Text.RegularExpressions; + +namespace Microsoft.AspNetCore.Rewrite.Internal +{ + public class BackReferenceCollection + { + private List _backReferences = new List(); + + public BackReferenceCollection(GroupCollection references) + { + if (references != null) + { + for (var i = 0; i < references.Count; i++) + { + _backReferences.Add(references[i].Value); + } + } + } + + public BackReferenceCollection(string reference) + { + _backReferences.Add(reference); + } + + public string this[int index] + { + get + { + if (index < _backReferences.Count) + { + return _backReferences[index]; + } + else + { + throw new IndexOutOfRangeException($"Cannot access back reference at index {index}. Only {_backReferences.Count} back references were captured."); + } + } + } + + public void Add(BackReferenceCollection references) + { + if (references != null) + { + _backReferences.AddRange(references._backReferences); + } + } + } +} diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/Condition.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/Condition.cs index 5c60e38d82..314e63a62c 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/Condition.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/Condition.cs @@ -9,9 +9,9 @@ namespace Microsoft.AspNetCore.Rewrite.Internal public UrlMatch Match { get; set; } public bool OrNext { get; set; } - public MatchResults Evaluate(RewriteContext context, MatchResults ruleMatch, MatchResults condMatch) + public MatchResults Evaluate(RewriteContext context, BackReferenceCollection ruleBackReferences, BackReferenceCollection conditionBackReferences) { - var pattern = Input.Evaluate(context, ruleMatch, condMatch); + var pattern = Input.Evaluate(context, ruleBackReferences, conditionBackReferences); return Match.Evaluate(pattern, context); } } diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/ConditionEvaluator.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/ConditionEvaluator.cs index 4407ec3ce8..7a3c4365c1 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/ConditionEvaluator.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/ConditionEvaluator.cs @@ -7,10 +7,15 @@ namespace Microsoft.AspNetCore.Rewrite.Internal { public static class ConditionHelper { - - public static MatchResults Evaluate(IEnumerable conditions, RewriteContext context, MatchResults ruleMatch) + public static MatchResults Evaluate(IEnumerable conditions, RewriteContext context, BackReferenceCollection backReferences) { - MatchResults prevCond = null; + return Evaluate(conditions, context, backReferences, trackAllCaptures: false); + } + + public static MatchResults Evaluate(IEnumerable conditions, RewriteContext context, BackReferenceCollection backReferences, bool trackAllCaptures) + { + BackReferenceCollection prevBackReferences = null; + MatchResults condResult = null; var orSucceeded = false; foreach (var condition in conditions) { @@ -24,18 +29,27 @@ namespace Microsoft.AspNetCore.Rewrite.Internal continue; } - prevCond = condition.Evaluate(context, ruleMatch, prevCond); - + condResult = condition.Evaluate(context, backReferences, prevBackReferences); + var currentBackReferences = condResult.BackReferences; if (condition.OrNext) { - orSucceeded = prevCond.Success; + orSucceeded = condResult.Success; } - else if (!prevCond.Success) + else if (!condResult.Success) { - return prevCond; + return condResult; } + + if (condResult.Success && trackAllCaptures && prevBackReferences!= null) + { + prevBackReferences.Add(currentBackReferences); + currentBackReferences = prevBackReferences; + } + + prevBackReferences = currentBackReferences; } - return prevCond; + + return new MatchResults { BackReferences = prevBackReferences, Success = condResult.Success }; ; } } } diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/IISUrlRewriteRule.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/IISUrlRewriteRule.cs index 3dc0bce3f4..d2c9b41acd 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/IISUrlRewriteRule.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/IISUrlRewriteRule.cs @@ -13,16 +13,19 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite public UrlMatch InitialMatch { get; } public IList Conditions { get; } public UrlAction Action { get; } + public bool TrackAllCaptures { get; } public IISUrlRewriteRule(string name, UrlMatch initialMatch, IList conditions, - UrlAction action) + UrlAction action, + bool trackAllCaptures) { Name = name; InitialMatch = initialMatch; Conditions = conditions; Action = action; + TrackAllCaptures = trackAllCaptures; } public virtual void ApplyRule(RewriteContext context) @@ -46,11 +49,11 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite return; } - MatchResults condMatchRes = null; + MatchResults condResult = null; if (Conditions != null) { - condMatchRes = ConditionHelper.Evaluate(Conditions, context, initMatchResults); - if (!condMatchRes.Success) + condResult = ConditionHelper.Evaluate(Conditions, context, initMatchResults.BackReferences, TrackAllCaptures); + if (!condResult.Success) { context.Logger?.UrlRewriteDidNotMatchRule(Name); return; @@ -59,7 +62,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite context.Logger?.UrlRewriteMatchedRule(Name); // at this point we know the rule passed, evaluate the replacement. - Action.ApplyAction(context, initMatchResults, condMatchRes); + Action.ApplyAction(context, initMatchResults?.BackReferences, condResult?.BackReferences); } } } \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/UrlRewriteFileParser.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/UrlRewriteFileParser.cs index 889d3e209a..02ecde3562 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/UrlRewriteFileParser.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/UrlRewriteFileParser.cs @@ -110,19 +110,15 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite var grouping = ParseEnum(conditions, RewriteTags.LogicalGrouping, LogicalGrouping.MatchAll); var trackAllCaptures = ParseBool(conditions, RewriteTags.TrackAllCaptures, defaultValue: false); - if (trackAllCaptures) - { - throw new NotSupportedException("Support for trackAllCaptures has not been implemented yet"); - } builder.AddUrlConditions(grouping, trackAllCaptures); foreach (var cond in conditions.Elements(RewriteTags.Add)) { - ParseCondition(cond, builder, patternSyntax); + ParseCondition(cond, builder, patternSyntax, trackAllCaptures); } } - private void ParseCondition(XElement condition, UrlRewriteRuleBuilder builder, PatternSyntax patternSyntax) + private void ParseCondition(XElement condition, UrlRewriteRuleBuilder builder, PatternSyntax patternSyntax, bool trackAllCaptures) { var ignoreCase = ParseBool(condition, RewriteTags.IgnoreCase, defaultValue: true); var negate = ParseBool(condition, RewriteTags.Negate, defaultValue: false); @@ -138,7 +134,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite try { var input = _inputParser.ParseInputString(parsedInputString); - builder.AddUrlCondition(input, parsedPatternString, patternSyntax, matchType, ignoreCase, negate); + builder.AddUrlCondition(input, parsedPatternString, patternSyntax, matchType, ignoreCase, negate, trackAllCaptures); } catch (FormatException formatException) { diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/UrlRewriteRuleBuilder.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/UrlRewriteRuleBuilder.cs index f6603b2df8..e7587ba5da 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/UrlRewriteRuleBuilder.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/UrlRewriteRuleBuilder.cs @@ -21,6 +21,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite private IList _conditions; private UrlAction _action; private bool _matchAny; + private bool _trackAllCaptures; public IISUrlRewriteRule Build() { @@ -29,7 +30,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite throw new InvalidOperationException("Cannot create UrlRewriteRule without action and match"); } - return new IISUrlRewriteRule(Name, _initialMatch, _conditions, _action); + return new IISUrlRewriteRule(Name, _initialMatch, _conditions, _action, _trackAllCaptures); } public void AddUrlAction( @@ -85,12 +86,12 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite } } - public void AddUrlCondition(Pattern input, string pattern, PatternSyntax patternSyntax, MatchType matchType, bool ignoreCase, bool negate) + public void AddUrlCondition(Pattern input, string pattern, PatternSyntax patternSyntax, MatchType matchType, bool ignoreCase, bool negate, bool trackAllCaptures) { // If there are no conditions specified if (_conditions == null) { - AddUrlConditions(LogicalGrouping.MatchAll, trackAllCaptures: false); + AddUrlConditions(LogicalGrouping.MatchAll, trackAllCaptures); } switch (patternSyntax) @@ -148,6 +149,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite { _conditions = new List(); _matchAny = logicalGrouping == LogicalGrouping.MatchAny; + _trackAllCaptures = trackAllCaptures; } } } diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/MatchResults.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/MatchResults.cs index 71eb20b8da..13c505d8f0 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/MatchResults.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/MatchResults.cs @@ -7,10 +7,10 @@ namespace Microsoft.AspNetCore.Rewrite.Internal { public class MatchResults { - public static readonly MatchResults EmptySuccess = new MatchResults { BackReference = null, Success = true }; - public static readonly MatchResults EmptyFailure = new MatchResults { BackReference = null, Success = false }; + public static readonly MatchResults EmptySuccess = new MatchResults { Success = true }; + public static readonly MatchResults EmptyFailure = new MatchResults { Success = false }; - public GroupCollection BackReference { get; set; } public bool Success { get; set; } + public BackReferenceCollection BackReferences { get; set; } } } diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/Pattern.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/Pattern.cs index 590bdccdb4..fe33dfa628 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/Pattern.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/Pattern.cs @@ -13,11 +13,11 @@ namespace Microsoft.AspNetCore.Rewrite.Internal PatternSegments = patternSegments; } - public string Evaluate(RewriteContext context, MatchResults ruleMatch, MatchResults condMatch) + public string Evaluate(RewriteContext context, BackReferenceCollection ruleBackReferences, BackReferenceCollection conditionBackReferences) { foreach (var pattern in PatternSegments) { - context.Builder.Append(pattern.Evaluate(context, ruleMatch, condMatch)); + context.Builder.Append(pattern.Evaluate(context, ruleBackReferences, conditionBackReferences)); } var retVal = context.Builder.ToString(); context.Builder.Clear(); diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegment.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegment.cs index 0cc7b7ddce..ef2b342065 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegment.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegment.cs @@ -5,6 +5,6 @@ namespace Microsoft.AspNetCore.Rewrite.Internal { public abstract class PatternSegment { - public abstract string Evaluate(RewriteContext context, MatchResults ruleMatch, MatchResults condMatch); + public abstract string Evaluate(RewriteContext context, BackReferenceCollection ruleBackReferences, BackReferenceCollection conditionBackReferences); } } diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/ConditionMatchSegment.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/ConditionMatchSegment.cs index 5ca4cc2b97..6c131e2c1c 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/ConditionMatchSegment.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/ConditionMatchSegment.cs @@ -12,9 +12,9 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.PatternSegments _index = index; } - public override string Evaluate(RewriteContext context, MatchResults ruleMatch, MatchResults condMatch) + public override string Evaluate(RewriteContext context, BackReferenceCollection ruleBackReferences, BackReferenceCollection conditionBackReferences) { - return condMatch?.BackReference[_index].Value; + return conditionBackReferences?[_index]; } } } diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/DateTimeSegment.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/DateTimeSegment.cs index 2d5202eeb8..588a19de27 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/DateTimeSegment.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/DateTimeSegment.cs @@ -43,7 +43,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.PatternSegments } } - public override string Evaluate(RewriteContext context, MatchResults ruleMatch, MatchResults condMatch) + public override string Evaluate(RewriteContext context, BackReferenceCollection ruleBackReferences, BackReferenceCollection conditionBackReference) { switch (_portion) { diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/HeaderSegment.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/HeaderSegment.cs index 5327c969fb..83bb5918e9 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/HeaderSegment.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/HeaderSegment.cs @@ -12,7 +12,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.PatternSegments _header = header; } - public override string Evaluate(RewriteContext context, MatchResults ruleMatch, MatchResults condMatch) + public override string Evaluate(RewriteContext context, BackReferenceCollection ruleBackReferences, BackReferenceCollection conditionBackReferences) { return context.HttpContext.Request.Headers[_header]; } diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/IsHttpsModSegment.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/IsHttpsModSegment.cs index 3b3f39339d..ba42a8ce03 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/IsHttpsModSegment.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/IsHttpsModSegment.cs @@ -5,9 +5,9 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.PatternSegments { public class IsHttpsModSegment : PatternSegment { - // Note: Mod rewrite pattern matches on lower case "on" and "off" + // Note: Mod rewrite pattern matches on lower case "on" and "off" // while IIS looks for capitalized "ON" and "OFF" - public override string Evaluate(RewriteContext context, MatchResults ruleMatch, MatchResults condMatch) + public override string Evaluate(RewriteContext context, BackReferenceCollection ruleBackReferences, BackReferenceCollection conditionBackReferences) { return context.HttpContext.Request.IsHttps ? "on" : "off"; } diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/IsHttpsUrlSegment.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/IsHttpsUrlSegment.cs index 21beccc746..106bc089c7 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/IsHttpsUrlSegment.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/IsHttpsUrlSegment.cs @@ -4,10 +4,10 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.PatternSegments { public class IsHttpsUrlSegment : PatternSegment - { - // Note: Mod rewrite pattern matches on lower case "on" and "off" + { + // Note: Mod rewrite pattern matches on lower case "on" and "off" // while IIS looks for capitalized "ON" and "OFF" - public override string Evaluate(RewriteContext context, MatchResults ruleMatch, MatchResults condMatch) + public override string Evaluate(RewriteContext context, BackReferenceCollection ruleBackReferences, BackReferenceCollection conditionBackReferences) { return context.HttpContext.Request.IsHttps ? "ON" : "OFF"; } diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/IsIPV6Segment.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/IsIPV6Segment.cs index 8131ae59a5..858dd45c85 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/IsIPV6Segment.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/IsIPV6Segment.cs @@ -8,7 +8,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.PatternSegments public class IsIPV6Segment : PatternSegment { - public override string Evaluate(RewriteContext context, MatchResults ruleMatch, MatchResults condMatch) + public override string Evaluate(RewriteContext context, BackReferenceCollection ruleBackReferences, BackReferenceCollection conditionBackReferences) { if (context.HttpContext.Connection.RemoteIpAddress == null) { diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/LiteralSegment.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/LiteralSegment.cs index 17d240db4a..c89818c09b 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/LiteralSegment.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/LiteralSegment.cs @@ -12,7 +12,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.PatternSegments _literal = literal; } - public override string Evaluate(RewriteContext context, MatchResults ruleMatch, MatchResults condMatch) + public override string Evaluate(RewriteContext context, BackReferenceCollection ruleBackReferences, BackReferenceCollection conditionBackReferences) { return _literal; } diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/LocalAddressSegment.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/LocalAddressSegment.cs index 5fc5ef8c95..5b6e0a2c66 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/LocalAddressSegment.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/LocalAddressSegment.cs @@ -5,7 +5,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.PatternSegments { public class LocalAddressSegment : PatternSegment { - public override string Evaluate(RewriteContext context, MatchResults ruleMatch, MatchResults condMatch) + public override string Evaluate(RewriteContext context, BackReferenceCollection ruleBackReferences, BackReferenceCollection conditionBackReferences) { return context.HttpContext.Connection.LocalIpAddress?.ToString(); } diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/LocalPortSegment.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/LocalPortSegment.cs index d7f62e2905..dc39080723 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/LocalPortSegment.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/LocalPortSegment.cs @@ -7,7 +7,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.PatternSegments { public class LocalPortSegment : PatternSegment { - public override string Evaluate(RewriteContext context, MatchResults ruleMatch, MatchResults condMatch) + public override string Evaluate(RewriteContext context, BackReferenceCollection ruleBackReferences, BackReferenceCollection conditionBackReferences) { return context.HttpContext.Connection.LocalPort.ToString(CultureInfo.InvariantCulture); } diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/QueryStringSegment.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/QueryStringSegment.cs index bb1118e864..c2b2c56c39 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/QueryStringSegment.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/QueryStringSegment.cs @@ -5,7 +5,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.PatternSegments { public class QueryStringSegment : PatternSegment { - public override string Evaluate(RewriteContext context, MatchResults ruleMatch, MatchResults condMatch) + public override string Evaluate(RewriteContext context, BackReferenceCollection ruleBackRefernces, BackReferenceCollection conditionBackReferences) { var queryString = context.HttpContext.Request.QueryString.ToString(); diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/RemoteAddressSegment.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/RemoteAddressSegment.cs index c18ec14ab7..acdb9f3a41 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/RemoteAddressSegment.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/RemoteAddressSegment.cs @@ -5,7 +5,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.PatternSegments { public class RemoteAddressSegment : PatternSegment { - public override string Evaluate(RewriteContext context, MatchResults ruleMatch, MatchResults condMatch) + public override string Evaluate(RewriteContext context, BackReferenceCollection ruleBackReferences, BackReferenceCollection conditionBackReferences) { return context.HttpContext.Connection.RemoteIpAddress?.ToString(); } diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/RemotePortSegment.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/RemotePortSegment.cs index 9c0e0257bb..720e5493ca 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/RemotePortSegment.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/RemotePortSegment.cs @@ -7,7 +7,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.PatternSegments { public class RemotePortSegment : PatternSegment { - public override string Evaluate(RewriteContext context, MatchResults ruleMatch, MatchResults condMatch) + public override string Evaluate(RewriteContext context, BackReferenceCollection ruleBackReferences, BackReferenceCollection conditionBackReferences) { return context.HttpContext.Connection.RemotePort.ToString(CultureInfo.InvariantCulture); } diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/RequestFilenameSegment.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/RequestFilenameSegment.cs index fe74df5c2b..fb3615b9c0 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/RequestFilenameSegment.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/RequestFilenameSegment.cs @@ -5,7 +5,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.PatternSegments { public class RequestFileNameSegment : PatternSegment { - public override string Evaluate(RewriteContext context, MatchResults ruleMatch, MatchResults condMatch) + public override string Evaluate(RewriteContext context, BackReferenceCollection ruleBackReferences, BackReferenceCollection conditionBackReferences) { return context.HttpContext.Request.Path; } diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/RequestMethodSegment.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/RequestMethodSegment.cs index b10103ebf5..ffd106380c 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/RequestMethodSegment.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/RequestMethodSegment.cs @@ -5,7 +5,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.PatternSegments { public class RequestMethodSegment : PatternSegment { - public override string Evaluate(RewriteContext context, MatchResults ruleMatch, MatchResults condMatch) + public override string Evaluate(RewriteContext context, BackReferenceCollection ruleBackReferences, BackReferenceCollection conditionBackReferences) { return context.HttpContext.Request.Method; } diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/RuleMatchSegment.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/RuleMatchSegment.cs index 2b008c6109..cdd4b38e24 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/RuleMatchSegment.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/RuleMatchSegment.cs @@ -12,9 +12,9 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.PatternSegments _index = index; } - public override string Evaluate(RewriteContext context, MatchResults ruleMatch, MatchResults condMatch) + public override string Evaluate(RewriteContext context, BackReferenceCollection ruleBackReferences, BackReferenceCollection conditionBackReferences) { - return ruleMatch?.BackReference[_index].Value; + return ruleBackReferences[_index]; } } } diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/SchemeSegment.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/SchemeSegment.cs index cd2bff5c06..bea7073308 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/SchemeSegment.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/SchemeSegment.cs @@ -5,7 +5,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.PatternSegments { public class SchemeSegment : PatternSegment { - public override string Evaluate(RewriteContext context, MatchResults ruleMatch, MatchResults condMatch) + public override string Evaluate(RewriteContext context, BackReferenceCollection ruleBackReferences, BackReferenceCollection conditionBackReferences) { return context.HttpContext.Request.Scheme; } diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/ServerProtocolSegment.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/ServerProtocolSegment.cs index d2b1d8e6ec..bf7f355194 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/ServerProtocolSegment.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/ServerProtocolSegment.cs @@ -7,7 +7,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.PatternSegments { public class ServerProtocolSegment : PatternSegment { - public override string Evaluate(RewriteContext context, MatchResults ruleMatch, MatchResults condMatch) + public override string Evaluate(RewriteContext context, BackReferenceCollection ruleBackReferences, BackReferenceCollection conditionBackReferences) { return context.HttpContext.Features.Get()?.Protocol; } diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/ToLowerSegment.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/ToLowerSegment.cs index 0588b2b526..dec2029658 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/ToLowerSegment.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/ToLowerSegment.cs @@ -14,13 +14,13 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.PatternSegments _pattern = pattern; } - public override string Evaluate(RewriteContext context, MatchResults ruleMatch, MatchResults condMatch) + public override string Evaluate(RewriteContext context, BackReferenceCollection ruleBackReferences, BackReferenceCollection conditionBackReferences) { // PERF as we share the string builder across the context, we need to make a new one here to evaluate // lowercase segments. var tempBuilder = context.Builder; context.Builder = new StringBuilder(64); - var pattern = _pattern.Evaluate(context, ruleMatch, condMatch); + var pattern = _pattern.Evaluate(context, ruleBackReferences, conditionBackReferences); context.Builder = tempBuilder; return pattern.ToLowerInvariant(); } diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/UrlEncodeSegment.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/UrlEncodeSegment.cs index e5ad2aac30..dc99dd4d51 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/UrlEncodeSegment.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/UrlEncodeSegment.cs @@ -15,7 +15,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.PatternSegments _pattern = pattern; } - public override string Evaluate(RewriteContext context, MatchResults ruleMatch, MatchResults condMatch) + public override string Evaluate(RewriteContext context, BackReferenceCollection ruleBackReferences, BackReferenceCollection conditionBackReferences) { var oldBuilder = context.Builder; // PERF @@ -23,7 +23,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.PatternSegments // we provided a new string builder and evaluate the new pattern, // and restore it after evaluation. context.Builder = new StringBuilder(64); - var pattern = _pattern.Evaluate(context, ruleMatch, condMatch); + var pattern = _pattern.Evaluate(context, ruleBackReferences, conditionBackReferences); context.Builder = oldBuilder; return UrlEncoder.Default.Encode(pattern); } diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/UrlSegment.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/UrlSegment.cs index da8adce3f7..005a335f8c 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/UrlSegment.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/UrlSegment.cs @@ -5,7 +5,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.PatternSegments { public class UrlSegment : PatternSegment { - public override string Evaluate(RewriteContext context, MatchResults ruleMatch, MatchResults condMatch) + public override string Evaluate(RewriteContext context, BackReferenceCollection ruleBackReferences, BackReferenceCollection conditionBackReferences) { return context.HttpContext.Request.Path; } diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlAction.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlAction.cs index a833ee9b17..b01e0c1bd8 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlAction.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlAction.cs @@ -6,6 +6,6 @@ namespace Microsoft.AspNetCore.Rewrite.Internal public abstract class UrlAction { protected Pattern Url { get; set; } - public abstract void ApplyAction(RewriteContext context, MatchResults ruleMatch, MatchResults condMatch); + public abstract void ApplyAction(RewriteContext context, BackReferenceCollection ruleBackReferences, BackReferenceCollection conditionBackReferences); } } diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/AbortAction.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/AbortAction.cs index e0ac36396c..32367f5f7b 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/AbortAction.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/AbortAction.cs @@ -7,7 +7,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlActions { public class AbortAction : UrlAction { - public override void ApplyAction(RewriteContext context, MatchResults ruleMatch, MatchResults condMatch) + public override void ApplyAction(RewriteContext context, BackReferenceCollection ruleBackReferences, BackReferenceCollection conditionBackReferences) { context.HttpContext.Abort(); context.Result = RuleResult.EndResponse; diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/ChangeCookieAction.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/ChangeCookieAction.cs index 640a022672..c758111ca1 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/ChangeCookieAction.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/ChangeCookieAction.cs @@ -37,7 +37,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlActions public bool Secure { get; set; } public bool HttpOnly { get; set; } - public override void ApplyAction(RewriteContext context, MatchResults ruleMatch, MatchResults condMatch) + public override void ApplyAction(RewriteContext context, BackReferenceCollection ruleBackReferences, BackReferenceCollection conditionBackReferences) { var options = GetOrCreateOptions(); context.HttpContext.Response.Cookies.Append(Name, Value ?? string.Empty, options); diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/ForbiddenAction.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/ForbiddenAction.cs index 8e4058cc97..3a1c14e75f 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/ForbiddenAction.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/ForbiddenAction.cs @@ -7,7 +7,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlActions { public class ForbiddenAction : UrlAction { - public override void ApplyAction(RewriteContext context, MatchResults ruleMatch, MatchResults condMatch) + public override void ApplyAction(RewriteContext context, BackReferenceCollection ruleBackReferences, BackReferenceCollection conditionBackReferences) { context.HttpContext.Response.StatusCode = StatusCodes.Status403Forbidden; context.Result = RuleResult.EndResponse; diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/GoneAction.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/GoneAction.cs index a1e7b964e6..f85cd22e3b 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/GoneAction.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/GoneAction.cs @@ -7,7 +7,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlActions { public class GoneAction : UrlAction { - public override void ApplyAction(RewriteContext context, MatchResults ruleMatch, MatchResults condMatch) + public override void ApplyAction(RewriteContext context, BackReferenceCollection ruleBackReferences, BackReferenceCollection conditionBackReferences) { context.HttpContext.Response.StatusCode = StatusCodes.Status410Gone; context.Result = RuleResult.EndResponse; diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/RedirectAction.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/RedirectAction.cs index 06eba46b04..f3ac9d3196 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/RedirectAction.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/RedirectAction.cs @@ -41,9 +41,9 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlActions { } - public override void ApplyAction(RewriteContext context, MatchResults ruleMatch, MatchResults condMatch) + public override void ApplyAction(RewriteContext context, BackReferenceCollection ruleBackReferences, BackReferenceCollection conditionBackReferences) { - var pattern = Url.Evaluate(context, ruleMatch, condMatch); + var pattern = Url.Evaluate(context, ruleBackReferences, conditionBackReferences); var response = context.HttpContext.Response; var pathBase = context.HttpContext.Request.PathBase; if (EscapeBackReferences) diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/RewriteAction.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/RewriteAction.cs index bd9a7fd63b..8f9c5818d3 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/RewriteAction.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/RewriteAction.cs @@ -43,9 +43,9 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlActions } - public override void ApplyAction(RewriteContext context, MatchResults ruleMatch, MatchResults condMatch) + public override void ApplyAction(RewriteContext context, BackReferenceCollection ruleBackReferences, BackReferenceCollection conditionBackReferences) { - var pattern = Url.Evaluate(context, ruleMatch, condMatch); + var pattern = Url.Evaluate(context, ruleBackReferences, conditionBackReferences); var request = context.HttpContext.Request; if (string.IsNullOrEmpty(pattern)) diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/VoidAction.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/VoidAction.cs index 6023b23a7a..95a092a0f8 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/VoidAction.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/VoidAction.cs @@ -12,7 +12,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlActions Result = result; } // Explicitly say that nothing happens - public override void ApplyAction(RewriteContext context, MatchResults ruleMatch, MatchResults condMatch) + public override void ApplyAction(RewriteContext context, BackReferenceCollection ruleBackReferences, BackReferenceCollection conditionBackReferences) { context.Result = Result; } diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlMatches/ExactMatch.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlMatches/ExactMatch.cs index 58cc914b84..23db120580 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlMatches/ExactMatch.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlMatches/ExactMatch.cs @@ -18,7 +18,15 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlMatches public override MatchResults Evaluate(string pattern, RewriteContext context) { var pathMatch = string.Compare(pattern, _stringMatch, _ignoreCase); - return new MatchResults { Success = ((pathMatch == 0) != Negate) }; + var success = ((pathMatch == 0) != Negate); + if (success) + { + return new MatchResults { Success = success, BackReferences = new BackReferenceCollection(pattern) }; + } + else + { + return MatchResults.EmptyFailure; + } } } } diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlMatches/RegexMatch.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlMatches/RegexMatch.cs index eb880c18ec..131eea8f9d 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlMatches/RegexMatch.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlMatches/RegexMatch.cs @@ -18,7 +18,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlMatches public override MatchResults Evaluate(string pattern, RewriteContext context) { var res = _match.Match(pattern); - return new MatchResults { BackReference = res.Groups, Success = (res.Success != Negate) }; + return new MatchResults { BackReferences = new BackReferenceCollection(res.Groups), Success = (res.Success != Negate) }; } } } diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/ApacheModRewrite/ModRewriteMiddlewareTest.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/ApacheModRewrite/ModRewriteMiddlewareTest.cs index 3b1d962751..f22f340f18 100644 --- a/test/Microsoft.AspNetCore.Rewrite.Tests/ApacheModRewrite/ModRewriteMiddlewareTest.cs +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/ApacheModRewrite/ModRewriteMiddlewareTest.cs @@ -136,10 +136,12 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.ModRewrite Assert.Equal("/", response); } - [Fact] - public async Task Invoke_BackReferencesShouldBeApplied() + [Theory] + [InlineData("http://www.foo.org/homepage.aspx", @"RewriteRule (.*)\.aspx $1.php", "/homepage.php")] + [InlineData("http://www.foo.org/pages/homepage.aspx", @"RewriteRule (.*)/(.*)\.aspx $2.php", "/homepage.php")] + public async Task Invoke_BackReferencesShouldBeApplied(string url, string rule, string expected) { - var options = new RewriteOptions().AddApacheModRewrite(new StringReader(@"RewriteRule (.*)\.aspx $1.php")); + var options = new RewriteOptions().AddApacheModRewrite(new StringReader(rule)); var builder = new WebHostBuilder() .Configure(app => { @@ -148,9 +150,9 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.ModRewrite }); var server = new TestServer(builder); - var response = await server.CreateClient().GetStringAsync("http://www.foo.org/homepage.aspx"); + var response = await server.CreateClient().GetStringAsync(url); - Assert.Equal("/homepage.php", response); + Assert.Equal(expected, response); } [Theory] diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/FileParserTests.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/FileParserTests.cs index dd55225c2b..1a8aaeab43 100644 --- a/test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/FileParserTests.cs +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/FileParserTests.cs @@ -147,7 +147,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite ) { return new IISUrlRewriteRule(name, new RegexMatch(new Regex("^OFF$"), false), conditions, - new RewriteAction(RuleResult.ContinueRules, new InputParser().ParseInputString(url), queryStringAppend: false)); + new RewriteAction(RuleResult.ContinueRules, new InputParser().ParseInputString(url), queryStringAppend: false), trackAllCaptures: false); } // TODO make rules comparable? diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/FormatExceptionHandlingTests.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/FormatExceptionHandlingTests.cs index 575135b543..c14f062e64 100644 --- a/test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/FormatExceptionHandlingTests.cs +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/FormatExceptionHandlingTests.cs @@ -264,26 +264,5 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite var ex = Assert.Throws(() => new UrlRewriteFileParser().Parse(new StringReader(input))); Assert.Equal(expected, ex.Message); } - - [Theory] - [InlineData( -@" - - - - - - - - - -", - "Support for trackAllCaptures has not been implemented yet")] - public void ThrowNotSupportedExceptionWithCorrectMessage(string input, string expected) - { - // Arrange, Act, Assert - var ex = Assert.Throws(() => new UrlRewriteFileParser().Parse(new StringReader(input))); - Assert.Equal(expected, ex.Message); - } } } diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/InputParserTests.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/InputParserTests.cs index df59ae4596..590785c3d3 100644 --- a/test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/InputParserTests.cs +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/InputParserTests.cs @@ -45,7 +45,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite public void EvaluateBackReferenceRule(string testString, string expected) { var middle = new InputParser().ParseInputString(testString); - var result = middle.Evaluate(CreateTestRewriteContext(), CreateTestRuleMatch(), CreateTestCondMatch()); + var result = middle.Evaluate(CreateTestRewriteContext(), CreateTestRuleBackReferences(), CreateTestCondBackReferences()); Assert.Equal(expected, result); } @@ -58,7 +58,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite public void EvaluatToLowerRule(string testString, string expected) { var middle = new InputParser().ParseInputString(testString); - var result = middle.Evaluate(CreateTestRewriteContext(), CreateTestRuleMatch(), CreateTestCondMatch()); + var result = middle.Evaluate(CreateTestRewriteContext(), CreateTestRuleBackReferences(), CreateTestCondBackReferences()); Assert.Equal(expected, result); } @@ -67,7 +67,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite public void EvaluatUriEncodeRule(string testString, string expected) { var middle = new InputParser().ParseInputString(testString); - var result = middle.Evaluate(CreateTestRewriteContext(), CreateTestRuleMatch(), CreateTestCondMatch()); + var result = middle.Evaluate(CreateTestRewriteContext(), CreateTestRuleBackReferences(), CreateTestCondBackReferences()); Assert.Equal(expected, result); } @@ -95,16 +95,16 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite return new RewriteContext { HttpContext = context, StaticFileProvider = null }; } - private MatchResults CreateTestRuleMatch() + private BackReferenceCollection CreateTestRuleBackReferences() { var match = Regex.Match("foo/bar/baz", "(.*)/(.*)/(.*)"); - return new MatchResults { BackReference = match.Groups, Success = match.Success }; + return new BackReferenceCollection(match.Groups); } - private MatchResults CreateTestCondMatch() + private BackReferenceCollection CreateTestCondBackReferences() { var match = Regex.Match("foo/bar/baz", "(.*)/(.*)/(.*)"); - return new MatchResults { BackReference = match.Groups, Success = match.Success }; + return new BackReferenceCollection(match.Groups); } } } diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/MiddleWareTests.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/MiddleWareTests.cs index 2951b9777e..b2724e8d58 100644 --- a/test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/MiddleWareTests.cs +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/MiddleWareTests.cs @@ -364,7 +364,92 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite var response = await server.CreateClient().GetAsync("hey/hello"); - Assert.Equal("/hey/hello/", response.Headers.Location.OriginalString); ; + Assert.Equal("/hey/hello/", response.Headers.Location.OriginalString); + } + + [Fact] + public async Task VerifyTrackAllCaptures() + { + var options = new RewriteOptions().AddIISUrlRewrite(new StringReader(@" + + + + + + + + + + + + ")); + var builder = new WebHostBuilder() + .Configure(app => + { + app.UseRewriter(options); + }); + var server = new TestServer(builder); + + var response = await server.CreateClient().GetAsync("article/23?p1=123&p2=abc"); + + Assert.Equal("/blogposts/article/abc", response.Headers.Location.OriginalString); + } + + [Fact] + public async Task VerifyTrackAllCapturesRuleAndConditionCapture() + { + var options = new RewriteOptions().AddIISUrlRewrite(new StringReader(@" + + + + + + + + + + + + ")); + var builder = new WebHostBuilder() + .Configure(app => + { + app.UseRewriter(options); + }); + var server = new TestServer(builder); + + var response = await server.CreateClient().GetAsync("article/23?p1=123&p2=abc"); + + Assert.Equal("/blog/article/23/abc", response.Headers.Location.OriginalString); + } + + [Fact] + public async Task ThrowIndexOutOfRangeExceptionWithCorrectMessage() + { + // Arrange, Act, Assert + var options = new RewriteOptions().AddIISUrlRewrite(new StringReader(@" + + + + + + + + + + + + ")); + var builder = new WebHostBuilder() + .Configure(app => + { + app.UseRewriter(options); + }); + var server = new TestServer(builder); + + var ex = await Assert.ThrowsAsync(() => server.CreateClient().GetAsync("article/23?p1=123&p2=abc")); + + Assert.Equal("Cannot access back reference at index 9. Only 5 back references were captured.", ex.Message); } } } diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/ServerVariableTests.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/ServerVariableTests.cs index 19c49d8a66..1d0f0154df 100644 --- a/test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/ServerVariableTests.cs +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/ServerVariableTests.cs @@ -29,7 +29,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite // Arrange and Act var testParserContext = new ParserContext("test"); var serverVar = ServerVariables.FindServerVariable(variable, testParserContext); - var lookup = serverVar.Evaluate(CreateTestHttpContext(), CreateTestRuleMatch(), CreateTestCondMatch()); + var lookup = serverVar.Evaluate(CreateTestHttpContext(), CreateTestRuleMatch().BackReferences, CreateTestCondMatch().BackReferences); // Assert Assert.Equal(expected, lookup); } @@ -53,13 +53,13 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite private MatchResults CreateTestRuleMatch() { var match = Regex.Match("foo/bar/baz", "(.*)/(.*)/(.*)"); - return new MatchResults { BackReference = match.Groups, Success = match.Success }; + return new MatchResults { BackReferences = new BackReferenceCollection(match.Groups), Success = match.Success }; } private MatchResults CreateTestCondMatch() { var match = Regex.Match("foo/bar/baz", "(.*)/(.*)/(.*)"); - return new MatchResults { BackReference = match.Groups, Success = match.Success }; + return new MatchResults { BackReferences = new BackReferenceCollection(match.Groups), Success = match.Success }; } [Fact] @@ -69,7 +69,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite var rewriteContext = new RewriteContext { HttpContext = context }; var testParserContext = new ParserContext("test"); var serverVar = ServerVariables.FindServerVariable("QUERY_STRING", testParserContext); - var lookup = serverVar.Evaluate(rewriteContext, CreateTestRuleMatch(), CreateTestCondMatch()); + var lookup = serverVar.Evaluate(rewriteContext, CreateTestRuleMatch().BackReferences, CreateTestCondMatch().BackReferences); Assert.Equal(string.Empty, lookup); } diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/UrlRewriteApplicationTests.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/UrlRewriteApplicationTests.cs index 87fcfdbae0..592492a17f 100644 --- a/test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/UrlRewriteApplicationTests.cs +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/UrlRewriteApplicationTests.cs @@ -49,5 +49,28 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite rules.FirstOrDefault().ApplyRule(context); Assert.Equal(RuleResult.ContinueRules, context.Result); } + + [Fact] + public void ApplyRule_TrackAllCaptures() + { + var xml = new StringReader(@" + + + + + + + + + + "); + var rules = new UrlRewriteFileParser().Parse(xml); + + Assert.Equal(rules.Count, 1); + Assert.True(rules[0].TrackAllCaptures); + var context = new RewriteContext { HttpContext = new DefaultHttpContext() }; + rules.FirstOrDefault().ApplyRule(context); + Assert.Equal(RuleResult.ContinueRules, context.Result); + } } } diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/PatternSegments/ConditionMatchSegmentTests.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/PatternSegments/ConditionMatchSegmentTests.cs index 51208cbba5..a67113954f 100644 --- a/test/Microsoft.AspNetCore.Rewrite.Tests/PatternSegments/ConditionMatchSegmentTests.cs +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/PatternSegments/ConditionMatchSegmentTests.cs @@ -22,7 +22,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.PatternSegments var segment = new ConditionMatchSegment(index); // Act - var results = segment.Evaluate(null, null, condMatch); + var results = segment.Evaluate(null, null, condMatch.BackReferences); // Assert Assert.Equal(expected, results); @@ -31,7 +31,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.PatternSegments private static MatchResults CreateTestMatch() { var match = Regex.Match("foo/bar/baz", "(.*)/(.*)/(.*)"); - return new MatchResults {BackReference = match.Groups, Success = match.Success}; + return new MatchResults { BackReferences = new BackReferenceCollection(match.Groups), Success = match.Success }; } } } diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/PatternSegments/RuleMatchSegmentTests.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/PatternSegments/RuleMatchSegmentTests.cs index 8e4d8ccfc4..56189c9bee 100644 --- a/test/Microsoft.AspNetCore.Rewrite.Tests/PatternSegments/RuleMatchSegmentTests.cs +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/PatternSegments/RuleMatchSegmentTests.cs @@ -21,7 +21,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.PatternSegments var segment = new RuleMatchSegment(index); // Act - var results = segment.Evaluate(null, ruleMatch, null); + var results = segment.Evaluate(null, ruleMatch.BackReferences, null); // Assert Assert.Equal(expected, results); @@ -30,7 +30,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.PatternSegments private static MatchResults CreateTestMatch() { var match = Regex.Match("foo/bar/baz", "(.*)/(.*)/(.*)"); - return new MatchResults { BackReference = match.Groups, Success = match.Success }; + return new MatchResults { BackReferences = new BackReferenceCollection(match.Groups), Success = match.Success }; } } } diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/project.json b/test/Microsoft.AspNetCore.Rewrite.Tests/project.json index 7120835f39..725a723427 100644 --- a/test/Microsoft.AspNetCore.Rewrite.Tests/project.json +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/project.json @@ -5,6 +5,7 @@ }, "dependencies": { "dotnet-test-xunit": "2.2.0-*", + "Microsoft.AspNetCore.Hosting": "1.2.0-*", "Microsoft.AspNetCore.Rewrite": "1.1.0-*", "Microsoft.AspNetCore.TestHost": "1.2.0-*", "Microsoft.Extensions.Logging.Testing": "1.2.0-*", From 5c61ae5f0218277ec4d1b020b547b2301d6c1d49 Mon Sep 17 00:00:00 2001 From: Pranav K Date: Mon, 5 Dec 2016 09:01:38 -0800 Subject: [PATCH 162/307] Updating to 4.4 CoreFx packages --- global.json | 2 +- samples/HttpOverridesSample/project.json | 2 +- samples/ResponseBufferingSample/project.json | 2 +- samples/ResponseCompressionSample/project.json | 2 +- samples/RewriteSample/project.json | 2 +- src/Microsoft.AspNetCore.Buffering/project.json | 2 +- src/Microsoft.AspNetCore.HttpOverrides/project.json | 2 +- src/Microsoft.AspNetCore.ResponseCompression/project.json | 2 +- src/Microsoft.AspNetCore.Rewrite/project.json | 2 +- test/Microsoft.AspNetCore.Buffering.Tests/project.json | 2 +- test/Microsoft.AspNetCore.HttpOverrides.Tests/project.json | 2 +- .../Microsoft.AspNetCore.ResponseCompression.Tests/project.json | 2 +- test/Microsoft.AspNetCore.Rewrite.Tests/project.json | 2 +- 13 files changed, 13 insertions(+), 13 deletions(-) diff --git a/global.json b/global.json index f45e8cc925..0ad1995dd2 100644 --- a/global.json +++ b/global.json @@ -3,6 +3,6 @@ "src" ], "sdk": { - "version": "1.0.0-preview2-1-003177" + "version": "1.0.0-preview2-1-003180" } } \ No newline at end of file diff --git a/samples/HttpOverridesSample/project.json b/samples/HttpOverridesSample/project.json index 1a4c261a77..ef305e6b52 100644 --- a/samples/HttpOverridesSample/project.json +++ b/samples/HttpOverridesSample/project.json @@ -20,7 +20,7 @@ "netcoreapp1.1": { "dependencies": { "Microsoft.NETCore.App": { - "version": "1.1.0-*", + "version": "1.2.0-*", "type": "platform" } } diff --git a/samples/ResponseBufferingSample/project.json b/samples/ResponseBufferingSample/project.json index d68ffcf804..f1ace1a005 100644 --- a/samples/ResponseBufferingSample/project.json +++ b/samples/ResponseBufferingSample/project.json @@ -11,7 +11,7 @@ "netcoreapp1.1": { "dependencies": { "Microsoft.NETCore.App": { - "version": "1.1.0-*", + "version": "1.2.0-*", "type": "platform" } } diff --git a/samples/ResponseCompressionSample/project.json b/samples/ResponseCompressionSample/project.json index ab2b8280bc..5a4acef515 100644 --- a/samples/ResponseCompressionSample/project.json +++ b/samples/ResponseCompressionSample/project.json @@ -16,7 +16,7 @@ "netcoreapp1.1": { "dependencies": { "Microsoft.NETCore.App": { - "version": "1.1.0-*", + "version": "1.2.0-*", "type": "platform" } } diff --git a/samples/RewriteSample/project.json b/samples/RewriteSample/project.json index 18031712b1..fdfd4c818f 100644 --- a/samples/RewriteSample/project.json +++ b/samples/RewriteSample/project.json @@ -13,7 +13,7 @@ "netcoreapp1.1": { "dependencies": { "Microsoft.NETCore.App": { - "version": "1.1.0-*", + "version": "1.2.0-*", "type": "platform" } } diff --git a/src/Microsoft.AspNetCore.Buffering/project.json b/src/Microsoft.AspNetCore.Buffering/project.json index 41a108d367..2bad7720a1 100644 --- a/src/Microsoft.AspNetCore.Buffering/project.json +++ b/src/Microsoft.AspNetCore.Buffering/project.json @@ -26,7 +26,7 @@ "version": "1.2.0-*", "type": "build" }, - "NETStandard.Library": "1.6.1-*" + "NETStandard.Library": "1.6.2-*" }, "frameworks": { "net451": {}, diff --git a/src/Microsoft.AspNetCore.HttpOverrides/project.json b/src/Microsoft.AspNetCore.HttpOverrides/project.json index a98d971159..0f41715dfa 100644 --- a/src/Microsoft.AspNetCore.HttpOverrides/project.json +++ b/src/Microsoft.AspNetCore.HttpOverrides/project.json @@ -25,7 +25,7 @@ "Microsoft.AspNetCore.Http.Extensions": "1.2.0-*", "Microsoft.Extensions.Logging.Abstractions": "1.2.0-*", "Microsoft.Extensions.Options": "1.2.0-*", - "NETStandard.Library": "1.6.1-*" + "NETStandard.Library": "1.6.2-*" }, "frameworks": { "net451": {}, diff --git a/src/Microsoft.AspNetCore.ResponseCompression/project.json b/src/Microsoft.AspNetCore.ResponseCompression/project.json index 3da8e8223f..8f1a19cdae 100644 --- a/src/Microsoft.AspNetCore.ResponseCompression/project.json +++ b/src/Microsoft.AspNetCore.ResponseCompression/project.json @@ -18,7 +18,7 @@ "dependencies": { "Microsoft.AspNetCore.Http.Extensions": "1.2.0-*", "Microsoft.Extensions.Options": "1.2.0-*", - "NETStandard.Library": "1.6.1-*" + "NETStandard.Library": "1.6.2-*" }, "frameworks": { "net451": {}, diff --git a/src/Microsoft.AspNetCore.Rewrite/project.json b/src/Microsoft.AspNetCore.Rewrite/project.json index 608a7908eb..0b9bb3a594 100644 --- a/src/Microsoft.AspNetCore.Rewrite/project.json +++ b/src/Microsoft.AspNetCore.Rewrite/project.json @@ -31,7 +31,7 @@ "version": "1.2.0-*", "type": "build" }, - "NETStandard.Library": "1.6.1-*" + "NETStandard.Library": "1.6.2-*" }, "frameworks": { "net451": { diff --git a/test/Microsoft.AspNetCore.Buffering.Tests/project.json b/test/Microsoft.AspNetCore.Buffering.Tests/project.json index 1683c84807..e352fdf740 100644 --- a/test/Microsoft.AspNetCore.Buffering.Tests/project.json +++ b/test/Microsoft.AspNetCore.Buffering.Tests/project.json @@ -13,7 +13,7 @@ "netcoreapp1.1": { "dependencies": { "Microsoft.NETCore.App": { - "version": "1.1.0-*", + "version": "1.2.0-*", "type": "platform" } } diff --git a/test/Microsoft.AspNetCore.HttpOverrides.Tests/project.json b/test/Microsoft.AspNetCore.HttpOverrides.Tests/project.json index 79d4c760be..fcc8302c38 100644 --- a/test/Microsoft.AspNetCore.HttpOverrides.Tests/project.json +++ b/test/Microsoft.AspNetCore.HttpOverrides.Tests/project.json @@ -14,7 +14,7 @@ "netcoreapp1.1": { "dependencies": { "Microsoft.NETCore.App": { - "version": "1.1.0-*", + "version": "1.2.0-*", "type": "platform" } } diff --git a/test/Microsoft.AspNetCore.ResponseCompression.Tests/project.json b/test/Microsoft.AspNetCore.ResponseCompression.Tests/project.json index 99b439dbf9..55df362b78 100644 --- a/test/Microsoft.AspNetCore.ResponseCompression.Tests/project.json +++ b/test/Microsoft.AspNetCore.ResponseCompression.Tests/project.json @@ -19,7 +19,7 @@ "netcoreapp1.1": { "dependencies": { "Microsoft.NETCore.App": { - "version": "1.1.0-*", + "version": "1.2.0-*", "type": "platform" } } diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/project.json b/test/Microsoft.AspNetCore.Rewrite.Tests/project.json index 725a723427..16c8c03f89 100644 --- a/test/Microsoft.AspNetCore.Rewrite.Tests/project.json +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/project.json @@ -19,7 +19,7 @@ "version": "1.0.2" }, "Microsoft.NETCore.App": { - "version": "1.1.0-*", + "version": "1.2.0-*", "type": "platform" } } From f51c601d612ef188d1db92065a7390dbeabccd81 Mon Sep 17 00:00:00 2001 From: Chris R Date: Tue, 3 Jan 2017 15:45:15 -0800 Subject: [PATCH 163/307] Remove unused WebListener reference. --- samples/ResponseCompressionSample/Startup.cs | 1 - samples/ResponseCompressionSample/project.json | 1 - 2 files changed, 2 deletions(-) diff --git a/samples/ResponseCompressionSample/Startup.cs b/samples/ResponseCompressionSample/Startup.cs index bd49d928ad..59afeccd42 100644 --- a/samples/ResponseCompressionSample/Startup.cs +++ b/samples/ResponseCompressionSample/Startup.cs @@ -70,7 +70,6 @@ namespace ResponseCompressionSample { var host = new WebHostBuilder() .UseKestrel() - // .UseWebListener() .ConfigureLogging(factory => { factory.AddConsole(LogLevel.Debug); diff --git a/samples/ResponseCompressionSample/project.json b/samples/ResponseCompressionSample/project.json index 5a4acef515..eeae3ac002 100644 --- a/samples/ResponseCompressionSample/project.json +++ b/samples/ResponseCompressionSample/project.json @@ -2,7 +2,6 @@ "dependencies": { "Microsoft.AspNetCore.ResponseCompression": "1.1.0-*", "Microsoft.AspNetCore.Server.Kestrel": "1.2.0-*", - "Microsoft.AspNetCore.Server.WebListener": "1.2.0-*", "Microsoft.Extensions.Logging.Console": "1.2.0-*" }, "buildOptions": { From 0a95102f5a26b7454ae8caf64ced9380e79da70b Mon Sep 17 00:00:00 2001 From: Stephen Halter Date: Mon, 9 Jan 2017 20:07:51 -0800 Subject: [PATCH 164/307] React to UseHttps change --- samples/RewriteSample/Startup.cs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/samples/RewriteSample/Startup.cs b/samples/RewriteSample/Startup.cs index 7ef08d2f99..2d423eb6c6 100644 --- a/samples/RewriteSample/Startup.cs +++ b/samples/RewriteSample/Startup.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System.IO; +using System.Net; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; @@ -30,9 +31,13 @@ namespace RewriteSample var host = new WebHostBuilder() .UseKestrel(options => { - options.UseHttps("testCert.pfx", "testPassword"); + options.Listen(IPAddress.Loopback, 5000); + options.Listen(IPAddress.Loopback, 5001, listenOptions => + { + // Configure SSL + listenOptions.UseHttps("testCert.pfx", "testPassword"); + }); }) - .UseUrls("http://localhost:5000", "https://localhost:5001") .UseStartup() .UseContentRoot(Directory.GetCurrentDirectory()) .Build(); From 6855f9bca19e88603ae065a1f62c9d763c010b2b Mon Sep 17 00:00:00 2001 From: John Luo Date: Wed, 11 Jan 2017 15:35:18 -0800 Subject: [PATCH 165/307] Add Vary: Accept-Encoding if response MIME type is compressible --- .../BodyWrapperStream.cs | 18 +++++++ .../BodyWrapperStreamTests.cs | 20 ++++++++ .../ResponseCompressionMiddlewareTest.cs | 49 ++++++++++++++----- 3 files changed, 76 insertions(+), 11 deletions(-) diff --git a/src/Microsoft.AspNetCore.ResponseCompression/BodyWrapperStream.cs b/src/Microsoft.AspNetCore.ResponseCompression/BodyWrapperStream.cs index 93197fa1a2..4906e0e2a6 100644 --- a/src/Microsoft.AspNetCore.ResponseCompression/BodyWrapperStream.cs +++ b/src/Microsoft.AspNetCore.ResponseCompression/BodyWrapperStream.cs @@ -211,6 +211,24 @@ namespace Microsoft.AspNetCore.ResponseCompression _compressionChecked = true; if (_provider.ShouldCompressResponse(_context)) { + // If the MIME type indicates that the response could be compressed, caches will need to vary by the Accept-Encoding header + var varyValues = _context.Response.Headers.GetCommaSeparatedValues(HeaderNames.Vary); + var varyByAcceptEncoding = false; + + for (var i = 0; i < varyValues.Length; i++) + { + if (string.Equals(varyValues[i], HeaderNames.AcceptEncoding, StringComparison.OrdinalIgnoreCase)) + { + varyByAcceptEncoding = true; + break; + } + } + + if (!varyByAcceptEncoding) + { + _context.Response.Headers.Append(HeaderNames.Vary, HeaderNames.AcceptEncoding); + } + var compressionProvider = ResolveCompressionProvider(); if (compressionProvider != null) { diff --git a/test/Microsoft.AspNetCore.ResponseCompression.Tests/BodyWrapperStreamTests.cs b/test/Microsoft.AspNetCore.ResponseCompression.Tests/BodyWrapperStreamTests.cs index 75ca3d7d88..f5aa703528 100644 --- a/test/Microsoft.AspNetCore.ResponseCompression.Tests/BodyWrapperStreamTests.cs +++ b/test/Microsoft.AspNetCore.ResponseCompression.Tests/BodyWrapperStreamTests.cs @@ -7,6 +7,7 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; using Microsoft.AspNetCore.Http; +using Microsoft.Net.Http.Headers; using Moq; using Xunit; @@ -14,6 +15,25 @@ namespace Microsoft.AspNetCore.ResponseCompression.Tests { public class BodyWrapperStreamTests { + [Theory] + [InlineData(null, "Accept-Encoding")] + [InlineData("", "Accept-Encoding")] + [InlineData("AnotherHeader", "AnotherHeader,Accept-Encoding")] + [InlineData("Accept-Encoding", "Accept-Encoding")] + [InlineData("accepT-encodinG", "accepT-encodinG")] + [InlineData("accept-encoding,AnotherHeader", "accept-encoding,AnotherHeader")] + public void OnWrite_AppendsAcceptEncodingToVaryHeader_IfNotPresent(string providedVaryHeader, string expectedVaryHeader) + { + var httpContext = new DefaultHttpContext(); + httpContext.Response.Headers[HeaderNames.Vary] = providedVaryHeader; + var stream = new BodyWrapperStream(httpContext, new MemoryStream(), new MockResponseCompressionProvider(flushable: true), null, null); + + stream.Write(new byte[] { }, 0, 0); + + + Assert.Equal(expectedVaryHeader, httpContext.Response.Headers[HeaderNames.Vary]); + } + [Theory] [InlineData(true)] [InlineData(false)] diff --git a/test/Microsoft.AspNetCore.ResponseCompression.Tests/ResponseCompressionMiddlewareTest.cs b/test/Microsoft.AspNetCore.ResponseCompression.Tests/ResponseCompressionMiddlewareTest.cs index 9c26de630d..8328716c89 100644 --- a/test/Microsoft.AspNetCore.ResponseCompression.Tests/ResponseCompressionMiddlewareTest.cs +++ b/test/Microsoft.AspNetCore.ResponseCompression.Tests/ResponseCompressionMiddlewareTest.cs @@ -36,7 +36,7 @@ namespace Microsoft.AspNetCore.ResponseCompression.Tests { var response = await InvokeMiddleware(100, requestAcceptEncodings: null, responseType: TextPlain); - CheckResponseNotCompressed(response, expectedBodyLength: 100); + CheckResponseNotCompressed(response, expectedBodyLength: 100, sendVaryHeader: false); } [Fact] @@ -52,7 +52,7 @@ namespace Microsoft.AspNetCore.ResponseCompression.Tests { var response = await InvokeMiddleware(100, requestAcceptEncodings: new string[] { "unknown" }, responseType: TextPlain); - CheckResponseNotCompressed(response, expectedBodyLength: 100); + CheckResponseNotCompressed(response, expectedBodyLength: 100, sendVaryHeader: true); } [Theory] @@ -149,7 +149,7 @@ namespace Microsoft.AspNetCore.ResponseCompression.Tests var response = await client.SendAsync(request); - CheckResponseNotCompressed(response, expectedBodyLength: 100); + CheckResponseNotCompressed(response, expectedBodyLength: 100, sendVaryHeader: false); } [Theory] @@ -185,7 +185,7 @@ namespace Microsoft.AspNetCore.ResponseCompression.Tests var response = await client.SendAsync(request); - CheckResponseNotCompressed(response, expectedBodyLength: 0); + CheckResponseNotCompressed(response, expectedBodyLength: 0, sendVaryHeader: false); } [Fact] @@ -201,7 +201,7 @@ namespace Microsoft.AspNetCore.ResponseCompression.Tests { var response = await InvokeMiddleware(100, requestAcceptEncodings: new string[] { "identity" }, responseType: TextPlain); - CheckResponseNotCompressed(response, expectedBodyLength: 100); + CheckResponseNotCompressed(response, expectedBodyLength: 100, sendVaryHeader: true); } [Theory] @@ -221,7 +221,7 @@ namespace Microsoft.AspNetCore.ResponseCompression.Tests { var response = await InvokeMiddleware(100, requestAcceptEncodings: acceptEncodings, responseType: TextPlain); - CheckResponseNotCompressed(response, expectedBodyLength: expectedBodyLength); + CheckResponseNotCompressed(response, expectedBodyLength: expectedBodyLength, sendVaryHeader: true); } [Fact] @@ -229,7 +229,7 @@ namespace Microsoft.AspNetCore.ResponseCompression.Tests { var response = await InvokeMiddleware(100, requestAcceptEncodings: new string[] { "gzip" }, responseType: "text/custom"); - CheckResponseNotCompressed(response, expectedBodyLength: 100); + CheckResponseNotCompressed(response, expectedBodyLength: 100, sendVaryHeader: false); } [Fact] @@ -240,7 +240,7 @@ namespace Microsoft.AspNetCore.ResponseCompression.Tests r.Headers[HeaderNames.ContentRange] = "1-2/*"; }); - CheckResponseNotCompressed(response, expectedBodyLength: 50); + CheckResponseNotCompressed(response, expectedBodyLength: 50, sendVaryHeader: false); } [Fact] @@ -446,7 +446,7 @@ namespace Microsoft.AspNetCore.ResponseCompression.Tests request.Headers.AcceptEncoding.ParseAdd("gzip"); var response = await client.SendAsync(request, HttpCompletionOption.ResponseHeadersRead); - + IEnumerable contentMD5 = null; Assert.False(response.Headers.TryGetValues(HeaderNames.ContentMD5, out contentMD5)); Assert.Single(response.Content.Headers.ContentEncoding, "gzip"); @@ -662,7 +662,7 @@ namespace Microsoft.AspNetCore.ResponseCompression.Tests var response = await client.SendAsync(request); - CheckResponseNotCompressed(response, expectedBodyLength: 1024); + CheckResponseNotCompressed(response, expectedBodyLength: 1024, sendVaryHeader: false); Assert.True(fakeSendFile.Invoked); } @@ -793,13 +793,40 @@ namespace Microsoft.AspNetCore.ResponseCompression.Tests { IEnumerable contentMD5 = null; + var containsVaryAcceptEncoding = false; + foreach (var value in response.Headers.GetValues(HeaderNames.Vary)) + { + if (value.Contains(HeaderNames.AcceptEncoding)) + { + containsVaryAcceptEncoding = true; + break; + } + } + Assert.True(containsVaryAcceptEncoding); Assert.False(response.Headers.TryGetValues(HeaderNames.ContentMD5, out contentMD5)); Assert.Single(response.Content.Headers.ContentEncoding, "gzip"); Assert.Equal(expectedBodyLength, response.Content.Headers.ContentLength); } - private void CheckResponseNotCompressed(HttpResponseMessage response, int expectedBodyLength) + private void CheckResponseNotCompressed(HttpResponseMessage response, int expectedBodyLength, bool sendVaryHeader) { + if (sendVaryHeader) + { + var containsVaryAcceptEncoding = false; + foreach (var value in response.Headers.GetValues(HeaderNames.Vary)) + { + if (value.Contains(HeaderNames.AcceptEncoding)) + { + containsVaryAcceptEncoding = true; + break; + } + } + Assert.True(containsVaryAcceptEncoding); + } + else + { + Assert.False(response.Headers.Contains(HeaderNames.Vary)); + } Assert.NotNull(response.Headers.GetValues(HeaderNames.ContentMD5)); Assert.Empty(response.Content.Headers.ContentEncoding); Assert.Equal(expectedBodyLength, response.Content.Headers.ContentLength); From 24a95f6c5dc7587fee24154f49bc8a42ddaafa3e Mon Sep 17 00:00:00 2001 From: Nate McMaster Date: Mon, 30 Jan 2017 14:56:48 -0800 Subject: [PATCH 166/307] Upgrade to VS 2017 --- BasicMiddleware.sln | 37 ++++++-------- NuGet.config | 7 +-- appveyor.yml | 3 +- build.ps1 | 2 +- build.sh | 2 +- {tools => build}/Key.snk | Bin build/common.props | 24 ++++++++++ global.json | 8 ---- .../HttpOverridesSample.csproj | 15 ++++++ .../HttpOverridesSample.xproj | 23 --------- samples/HttpOverridesSample/project.json | 29 ----------- .../ResponseBufferingSample.csproj | 15 ++++++ .../ResponseBufferingSample.xproj | 18 ------- samples/ResponseBufferingSample/project.json | 29 ----------- .../Properties/launchSettings.json | 15 ++++++ .../ResponseCompressionSample.csproj | 20 ++++++++ .../ResponseCompressionSample.xproj | 18 ------- .../ResponseCompressionSample/project.json | 33 ------------- .../RewriteSample/Properties/AssemblyInfo.cs | 19 -------- .../Properties/launchSettings.json | 22 +++++++++ samples/RewriteSample/RewriteSample.csproj | 17 +++++++ samples/RewriteSample/RewriteSample.xproj | 21 -------- samples/RewriteSample/project.json | 31 ------------ .../Microsoft.AspNetCore.Buffering.csproj | 19 ++++++++ .../Microsoft.AspNetCore.Buffering.xproj | 17 ------- .../Properties/AssemblyInfo.cs | 11 ----- .../project.json | 35 -------------- .../Microsoft.AspNetCore.HttpOverrides.csproj | 22 +++++++++ .../Microsoft.AspNetCore.HttpOverrides.xproj | 17 ------- .../Properties/AssemblyInfo.cs | 11 ----- .../project.json | 34 ------------- ...soft.AspNetCore.ResponseCompression.csproj | 18 +++++++ ...osoft.AspNetCore.ResponseCompression.xproj | 17 ------- .../Properties/AssemblyInfo.cs | 8 ---- .../project.json | 27 ----------- .../Microsoft.AspNetCore.Rewrite.csproj | 27 +++++++++++ .../Microsoft.AspNetCore.Rewrite.xproj | 21 -------- .../Properties/AssemblyInfo.cs | 7 --- src/Microsoft.AspNetCore.Rewrite/project.json | 45 ------------------ ...icrosoft.AspNetCore.Buffering.Tests.csproj | 17 +++++++ ...Microsoft.AspNetCore.Buffering.Tests.xproj | 20 -------- .../project.json | 24 ---------- ...soft.AspNetCore.HttpOverrides.Tests.csproj | 18 +++++++ ...osoft.AspNetCore.HttpOverrides.Tests.xproj | 20 -------- .../project.json | 25 ---------- ...spNetCore.ResponseCompression.Tests.csproj | 24 ++++++++++ ...AspNetCore.ResponseCompression.Tests.xproj | 20 -------- .../project.json | 30 ------------ .../Microsoft.AspNetCore.Rewrite.Tests.csproj | 19 ++++++++ .../Microsoft.AspNetCore.Rewrite.Tests.xproj | 22 --------- .../Properties/AssemblyInfo.cs | 19 -------- .../project.json | 30 ------------ version.props | 6 +++ 53 files changed, 320 insertions(+), 718 deletions(-) rename {tools => build}/Key.snk (100%) create mode 100644 build/common.props delete mode 100644 global.json create mode 100644 samples/HttpOverridesSample/HttpOverridesSample.csproj delete mode 100644 samples/HttpOverridesSample/HttpOverridesSample.xproj delete mode 100644 samples/HttpOverridesSample/project.json create mode 100644 samples/ResponseBufferingSample/ResponseBufferingSample.csproj delete mode 100644 samples/ResponseBufferingSample/ResponseBufferingSample.xproj delete mode 100644 samples/ResponseBufferingSample/project.json create mode 100644 samples/ResponseCompressionSample/ResponseCompressionSample.csproj delete mode 100644 samples/ResponseCompressionSample/ResponseCompressionSample.xproj delete mode 100644 samples/ResponseCompressionSample/project.json delete mode 100644 samples/RewriteSample/Properties/AssemblyInfo.cs create mode 100644 samples/RewriteSample/Properties/launchSettings.json create mode 100644 samples/RewriteSample/RewriteSample.csproj delete mode 100644 samples/RewriteSample/RewriteSample.xproj delete mode 100644 samples/RewriteSample/project.json create mode 100644 src/Microsoft.AspNetCore.Buffering/Microsoft.AspNetCore.Buffering.csproj delete mode 100644 src/Microsoft.AspNetCore.Buffering/Microsoft.AspNetCore.Buffering.xproj delete mode 100644 src/Microsoft.AspNetCore.Buffering/Properties/AssemblyInfo.cs delete mode 100644 src/Microsoft.AspNetCore.Buffering/project.json create mode 100644 src/Microsoft.AspNetCore.HttpOverrides/Microsoft.AspNetCore.HttpOverrides.csproj delete mode 100644 src/Microsoft.AspNetCore.HttpOverrides/Microsoft.AspNetCore.HttpOverrides.xproj delete mode 100644 src/Microsoft.AspNetCore.HttpOverrides/Properties/AssemblyInfo.cs delete mode 100644 src/Microsoft.AspNetCore.HttpOverrides/project.json create mode 100644 src/Microsoft.AspNetCore.ResponseCompression/Microsoft.AspNetCore.ResponseCompression.csproj delete mode 100644 src/Microsoft.AspNetCore.ResponseCompression/Microsoft.AspNetCore.ResponseCompression.xproj delete mode 100644 src/Microsoft.AspNetCore.ResponseCompression/project.json create mode 100644 src/Microsoft.AspNetCore.Rewrite/Microsoft.AspNetCore.Rewrite.csproj delete mode 100644 src/Microsoft.AspNetCore.Rewrite/Microsoft.AspNetCore.Rewrite.xproj delete mode 100644 src/Microsoft.AspNetCore.Rewrite/project.json create mode 100644 test/Microsoft.AspNetCore.Buffering.Tests/Microsoft.AspNetCore.Buffering.Tests.csproj delete mode 100644 test/Microsoft.AspNetCore.Buffering.Tests/Microsoft.AspNetCore.Buffering.Tests.xproj delete mode 100644 test/Microsoft.AspNetCore.Buffering.Tests/project.json create mode 100644 test/Microsoft.AspNetCore.HttpOverrides.Tests/Microsoft.AspNetCore.HttpOverrides.Tests.csproj delete mode 100644 test/Microsoft.AspNetCore.HttpOverrides.Tests/Microsoft.AspNetCore.HttpOverrides.Tests.xproj delete mode 100644 test/Microsoft.AspNetCore.HttpOverrides.Tests/project.json create mode 100644 test/Microsoft.AspNetCore.ResponseCompression.Tests/Microsoft.AspNetCore.ResponseCompression.Tests.csproj delete mode 100644 test/Microsoft.AspNetCore.ResponseCompression.Tests/Microsoft.AspNetCore.ResponseCompression.Tests.xproj delete mode 100644 test/Microsoft.AspNetCore.ResponseCompression.Tests/project.json create mode 100644 test/Microsoft.AspNetCore.Rewrite.Tests/Microsoft.AspNetCore.Rewrite.Tests.csproj delete mode 100644 test/Microsoft.AspNetCore.Rewrite.Tests/Microsoft.AspNetCore.Rewrite.Tests.xproj delete mode 100644 test/Microsoft.AspNetCore.Rewrite.Tests/Properties/AssemblyInfo.cs delete mode 100644 test/Microsoft.AspNetCore.Rewrite.Tests/project.json create mode 100644 version.props diff --git a/BasicMiddleware.sln b/BasicMiddleware.sln index 7ef684b555..91ffb2b952 100644 --- a/BasicMiddleware.sln +++ b/BasicMiddleware.sln @@ -1,45 +1,36 @@ Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 14 -VisualStudioVersion = 14.0.25420.1 +# Visual Studio 15 +VisualStudioVersion = 15.0.26127.0 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNetCore.HttpOverrides", "src\Microsoft.AspNetCore.HttpOverrides\Microsoft.AspNetCore.HttpOverrides.xproj", "{517308C3-B477-4B01-B461-CAB9C10B6928}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.HttpOverrides", "src\Microsoft.AspNetCore.HttpOverrides\Microsoft.AspNetCore.HttpOverrides.csproj", "{517308C3-B477-4B01-B461-CAB9C10B6928}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{A5076D28-FA7E-4606-9410-FEDD0D603527}" - ProjectSection(SolutionItems) = preProject - global.json = global.json - EndProjectSection EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{8437B0F3-3894-4828-A945-A9187F37631D}" EndProject -Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNetCore.HttpOverrides.Tests", "test\Microsoft.AspNetCore.HttpOverrides.Tests\Microsoft.AspNetCore.HttpOverrides.Tests.xproj", "{D6341B92-3416-4F11-8DF4-CB274296175F}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.HttpOverrides.Tests", "test\Microsoft.AspNetCore.HttpOverrides.Tests\Microsoft.AspNetCore.HttpOverrides.Tests.csproj", "{D6341B92-3416-4F11-8DF4-CB274296175F}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{99B72A07-32D6-434D-B44D-D064E3C13E08}" - ProjectSection(SolutionItems) = preProject - global.json = global.json - NuGetPackageVerifier.json = NuGetPackageVerifier.json - EndProjectSection +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Buffering", "src\Microsoft.AspNetCore.Buffering\Microsoft.AspNetCore.Buffering.csproj", "{2363D0DD-A3BF-437E-9B64-B33AE132D875}" EndProject -Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNetCore.Buffering", "src\Microsoft.AspNetCore.Buffering\Microsoft.AspNetCore.Buffering.xproj", "{2363D0DD-A3BF-437E-9B64-B33AE132D875}" -EndProject -Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNetCore.Buffering.Tests", "test\Microsoft.AspNetCore.Buffering.Tests\Microsoft.AspNetCore.Buffering.Tests.xproj", "{F5F1D123-9C81-4A9E-8644-AA46B8E578FB}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Buffering.Tests", "test\Microsoft.AspNetCore.Buffering.Tests\Microsoft.AspNetCore.Buffering.Tests.csproj", "{F5F1D123-9C81-4A9E-8644-AA46B8E578FB}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "samples", "samples", "{9587FE9F-5A17-42C4-8021-E87F59CECB98}" EndProject -Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "ResponseBufferingSample", "samples\ResponseBufferingSample\ResponseBufferingSample.xproj", "{E5C55B80-7827-40EB-B661-32B0E0E431CA}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ResponseBufferingSample", "samples\ResponseBufferingSample\ResponseBufferingSample.csproj", "{E5C55B80-7827-40EB-B661-32B0E0E431CA}" EndProject -Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "HttpOverridesSample", "samples\HttpOverridesSample\HttpOverridesSample.xproj", "{7F95478D-E1D4-4A64-BA42-B041591A96EB}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "HttpOverridesSample", "samples\HttpOverridesSample\HttpOverridesSample.csproj", "{7F95478D-E1D4-4A64-BA42-B041591A96EB}" EndProject -Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNetCore.Rewrite", "src\Microsoft.AspNetCore.Rewrite\Microsoft.AspNetCore.Rewrite.xproj", "{0E7CA1A7-1DC3-4CE6-B9C7-1688FE1410F1}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Rewrite", "src\Microsoft.AspNetCore.Rewrite\Microsoft.AspNetCore.Rewrite.csproj", "{0E7CA1A7-1DC3-4CE6-B9C7-1688FE1410F1}" EndProject -Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "RewriteSample", "samples\RewriteSample\RewriteSample.xproj", "{9E049645-13BC-4598-89E1-5B43D36E5D14}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RewriteSample", "samples\RewriteSample\RewriteSample.csproj", "{9E049645-13BC-4598-89E1-5B43D36E5D14}" EndProject -Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNetCore.Rewrite.Tests", "test\Microsoft.AspNetCore.Rewrite.Tests\Microsoft.AspNetCore.Rewrite.Tests.xproj", "{31794F9E-A1AA-4535-B03C-A3233737CD1A}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Rewrite.Tests", "test\Microsoft.AspNetCore.Rewrite.Tests\Microsoft.AspNetCore.Rewrite.Tests.csproj", "{31794F9E-A1AA-4535-B03C-A3233737CD1A}" EndProject -Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNetCore.ResponseCompression", "src\Microsoft.AspNetCore.ResponseCompression\Microsoft.AspNetCore.ResponseCompression.xproj", "{45308A9D-F4C6-46A8-A24F-E73D995CC223}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.ResponseCompression", "src\Microsoft.AspNetCore.ResponseCompression\Microsoft.AspNetCore.ResponseCompression.csproj", "{45308A9D-F4C6-46A8-A24F-E73D995CC223}" EndProject -Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNetCore.ResponseCompression.Tests", "test\Microsoft.AspNetCore.ResponseCompression.Tests\Microsoft.AspNetCore.ResponseCompression.Tests.xproj", "{3360A5D1-70C0-49EE-9051-04A6A6B836DC}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.ResponseCompression.Tests", "test\Microsoft.AspNetCore.ResponseCompression.Tests\Microsoft.AspNetCore.ResponseCompression.Tests.csproj", "{3360A5D1-70C0-49EE-9051-04A6A6B836DC}" EndProject -Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "ResponseCompressionSample", "samples\ResponseCompressionSample\ResponseCompressionSample.xproj", "{B2A3CE38-51B2-4486-982C-98C380AF140E}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ResponseCompressionSample", "samples\ResponseCompressionSample\ResponseCompressionSample.csproj", "{B2A3CE38-51B2-4486-982C-98C380AF140E}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution diff --git a/NuGet.config b/NuGet.config index a696a0a743..8e65695611 100644 --- a/NuGet.config +++ b/NuGet.config @@ -1,7 +1,8 @@ - + - + + - \ No newline at end of file + diff --git a/appveyor.yml b/appveyor.yml index b9a9bcd1e6..741873cbe5 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -10,4 +10,5 @@ build_script: - build.cmd verify clone_depth: 1 test: off -deploy: off \ No newline at end of file +deploy: off +os: Visual Studio 2015 diff --git a/build.ps1 b/build.ps1 index 8f2f99691a..0605b59c01 100644 --- a/build.ps1 +++ b/build.ps1 @@ -33,7 +33,7 @@ cd $PSScriptRoot $repoFolder = $PSScriptRoot $env:REPO_FOLDER = $repoFolder -$koreBuildZip="https://github.com/aspnet/KoreBuild/archive/dev.zip" +$koreBuildZip="https://github.com/aspnet/KoreBuild/archive/feature/msbuild.zip" if ($env:KOREBUILD_ZIP) { $koreBuildZip=$env:KOREBUILD_ZIP diff --git a/build.sh b/build.sh index 4fd7ede788..07997d6c83 100755 --- a/build.sh +++ b/build.sh @@ -2,7 +2,7 @@ repoFolder="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" cd $repoFolder -koreBuildZip="https://github.com/aspnet/KoreBuild/archive/dev.zip" +koreBuildZip="https://github.com/aspnet/KoreBuild/archive/feature/msbuild.zip" if [ ! -z $KOREBUILD_ZIP ]; then koreBuildZip=$KOREBUILD_ZIP fi diff --git a/tools/Key.snk b/build/Key.snk similarity index 100% rename from tools/Key.snk rename to build/Key.snk diff --git a/build/common.props b/build/common.props new file mode 100644 index 0000000000..6cc1dddc23 --- /dev/null +++ b/build/common.props @@ -0,0 +1,24 @@ + + + + + Microsoft ASP.NET Core + https://github.com/aspnet/BasicMiddleware + git + $(MSBuildThisFileDirectory)Key.snk + true + true + 1.2.0-* + 1.6.2-* + $(VersionSuffix)-$(BuildNumber) + + + + + + + + + + + diff --git a/global.json b/global.json deleted file mode 100644 index 0ad1995dd2..0000000000 --- a/global.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "projects": [ - "src" - ], - "sdk": { - "version": "1.0.0-preview2-1-003180" - } -} \ No newline at end of file diff --git a/samples/HttpOverridesSample/HttpOverridesSample.csproj b/samples/HttpOverridesSample/HttpOverridesSample.csproj new file mode 100644 index 0000000000..00119f3640 --- /dev/null +++ b/samples/HttpOverridesSample/HttpOverridesSample.csproj @@ -0,0 +1,15 @@ + + + + net451;netcoreapp1.1 + win7-x64 + Exe + 1.2.0-* + + + + + + + + diff --git a/samples/HttpOverridesSample/HttpOverridesSample.xproj b/samples/HttpOverridesSample/HttpOverridesSample.xproj deleted file mode 100644 index 41dce8ef60..0000000000 --- a/samples/HttpOverridesSample/HttpOverridesSample.xproj +++ /dev/null @@ -1,23 +0,0 @@ - - - - 14.0 - $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - - - - 7f95478d-e1d4-4a64-ba42-b041591a96eb - .\obj - .\bin\ - - - 2.0 - - - - - - - - - \ No newline at end of file diff --git a/samples/HttpOverridesSample/project.json b/samples/HttpOverridesSample/project.json deleted file mode 100644 index ef305e6b52..0000000000 --- a/samples/HttpOverridesSample/project.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "buildOptions": { - "emitEntryPoint": true - }, - "publishOptions": { - "exclude": [ - "**.user", - "**.vspscc" - ] - }, - "dependencies": { - "Microsoft.AspNetCore.HttpOverrides": "1.2.0-*", - "Microsoft.AspNetCore.Server.Kestrel": "1.2.0-*" - }, - "commands": { - "web": "HttpOverridesSample" - }, - "frameworks": { - "net451": {}, - "netcoreapp1.1": { - "dependencies": { - "Microsoft.NETCore.App": { - "version": "1.2.0-*", - "type": "platform" - } - } - } - } -} \ No newline at end of file diff --git a/samples/ResponseBufferingSample/ResponseBufferingSample.csproj b/samples/ResponseBufferingSample/ResponseBufferingSample.csproj new file mode 100644 index 0000000000..e7d85de3b0 --- /dev/null +++ b/samples/ResponseBufferingSample/ResponseBufferingSample.csproj @@ -0,0 +1,15 @@ + + + + net451;netcoreapp1.1 + win7-x64 + Exe + 1.2.0-* + + + + + + + + diff --git a/samples/ResponseBufferingSample/ResponseBufferingSample.xproj b/samples/ResponseBufferingSample/ResponseBufferingSample.xproj deleted file mode 100644 index b9333376fc..0000000000 --- a/samples/ResponseBufferingSample/ResponseBufferingSample.xproj +++ /dev/null @@ -1,18 +0,0 @@ - - - - 14.0 - $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - - - - e5c55b80-7827-40eb-b661-32b0e0e431ca - .\obj - .\bin\ - - - 2.0 - 46823 - - - \ No newline at end of file diff --git a/samples/ResponseBufferingSample/project.json b/samples/ResponseBufferingSample/project.json deleted file mode 100644 index f1ace1a005..0000000000 --- a/samples/ResponseBufferingSample/project.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "dependencies": { - "Microsoft.AspNetCore.Buffering": "0.3.0-*", - "Microsoft.AspNetCore.Server.Kestrel": "1.2.0-*" - }, - "buildOptions": { - "emitEntryPoint": true - }, - "frameworks": { - "net451": {}, - "netcoreapp1.1": { - "dependencies": { - "Microsoft.NETCore.App": { - "version": "1.2.0-*", - "type": "platform" - } - } - } - }, - "publish": { - "exclude": [ - "node_modules", - "bower_components", - "**.xproj", - "**.user", - "**.vspscc" - ] - } -} \ No newline at end of file diff --git a/samples/ResponseCompressionSample/Properties/launchSettings.json b/samples/ResponseCompressionSample/Properties/launchSettings.json index f6c233feed..67a091c37a 100644 --- a/samples/ResponseCompressionSample/Properties/launchSettings.json +++ b/samples/ResponseCompressionSample/Properties/launchSettings.json @@ -1,5 +1,20 @@ { + "iisSettings": { + "windowsAuthentication": false, + "anonymousAuthentication": true, + "iisExpress": { + "applicationUrl": "http://localhost:6164/", + "sslPort": 0 + } + }, "profiles": { + "IIS Express": { + "commandName": "IISExpress", + "launchBrowser": true, + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + }, "ResponseCompressionSample": { "commandName": "Project", "launchBrowser": true, diff --git a/samples/ResponseCompressionSample/ResponseCompressionSample.csproj b/samples/ResponseCompressionSample/ResponseCompressionSample.csproj new file mode 100644 index 0000000000..9d24167bdc --- /dev/null +++ b/samples/ResponseCompressionSample/ResponseCompressionSample.csproj @@ -0,0 +1,20 @@ + + + + net451;netcoreapp1.1 + win7-x64 + Exe + 1.2.0-* + + + + + + + + + + + + + diff --git a/samples/ResponseCompressionSample/ResponseCompressionSample.xproj b/samples/ResponseCompressionSample/ResponseCompressionSample.xproj deleted file mode 100644 index 66a15a5b7e..0000000000 --- a/samples/ResponseCompressionSample/ResponseCompressionSample.xproj +++ /dev/null @@ -1,18 +0,0 @@ - - - - 14.0 - $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - - - - b2a3ce38-51b2-4486-982c-98c380af140e - .\obj - .\bin\ - - - 2.0 - 46824 - - - \ No newline at end of file diff --git a/samples/ResponseCompressionSample/project.json b/samples/ResponseCompressionSample/project.json deleted file mode 100644 index eeae3ac002..0000000000 --- a/samples/ResponseCompressionSample/project.json +++ /dev/null @@ -1,33 +0,0 @@ -{ - "dependencies": { - "Microsoft.AspNetCore.ResponseCompression": "1.1.0-*", - "Microsoft.AspNetCore.Server.Kestrel": "1.2.0-*", - "Microsoft.Extensions.Logging.Console": "1.2.0-*" - }, - "buildOptions": { - "copyToOutput": [ - "testfile1kb.txt" - ], - "emitEntryPoint": true - }, - "frameworks": { - "net451": {}, - "netcoreapp1.1": { - "dependencies": { - "Microsoft.NETCore.App": { - "version": "1.2.0-*", - "type": "platform" - } - } - } - }, - "publish": { - "exclude": [ - "node_modules", - "bower_components", - "**.xproj", - "**.user", - "**.vspscc" - ] - } -} \ No newline at end of file diff --git a/samples/RewriteSample/Properties/AssemblyInfo.cs b/samples/RewriteSample/Properties/AssemblyInfo.cs deleted file mode 100644 index 22fae21612..0000000000 --- a/samples/RewriteSample/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,19 +0,0 @@ -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("RewriteSample")] -[assembly: AssemblyTrademark("")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] - -// The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("9e049645-13bc-4598-89e1-5b43d36e5d14")] diff --git a/samples/RewriteSample/Properties/launchSettings.json b/samples/RewriteSample/Properties/launchSettings.json new file mode 100644 index 0000000000..4d5d4a7ad7 --- /dev/null +++ b/samples/RewriteSample/Properties/launchSettings.json @@ -0,0 +1,22 @@ +{ + "iisSettings": { + "windowsAuthentication": false, + "anonymousAuthentication": true, + "iisExpress": { + "applicationUrl": "http://localhost:6156/", + "sslPort": 0 + } + }, + "profiles": { + "IIS Express": { + "commandName": "IISExpress", + "launchBrowser": true, + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + }, + "RewriteSample": { + "commandName": "Project" + } + } +} \ No newline at end of file diff --git a/samples/RewriteSample/RewriteSample.csproj b/samples/RewriteSample/RewriteSample.csproj new file mode 100644 index 0000000000..3fe834ccb1 --- /dev/null +++ b/samples/RewriteSample/RewriteSample.csproj @@ -0,0 +1,17 @@ + + + + net451;netcoreapp1.1 + win7-x64 + true + Exe + 1.2.0-* + + + + + + + + + diff --git a/samples/RewriteSample/RewriteSample.xproj b/samples/RewriteSample/RewriteSample.xproj deleted file mode 100644 index 542c81359a..0000000000 --- a/samples/RewriteSample/RewriteSample.xproj +++ /dev/null @@ -1,21 +0,0 @@ - - - - 14.0 - $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - - - - - 9e049645-13bc-4598-89e1-5b43d36e5d14 - RewriteSample - .\obj - .\bin\ - v4.5.2 - - - - 2.0 - - - diff --git a/samples/RewriteSample/project.json b/samples/RewriteSample/project.json deleted file mode 100644 index fdfd4c818f..0000000000 --- a/samples/RewriteSample/project.json +++ /dev/null @@ -1,31 +0,0 @@ -{ - "dependencies": { - "Microsoft.AspNetCore.Rewrite": "1.1.0-*", - "Microsoft.AspNetCore.Server.Kestrel": "1.2.0-*", - "Microsoft.AspNetCore.Server.Kestrel.Https": "1.2.0-*" - }, - "buildOptions": { - "emitEntryPoint": true, - "preserveCompilationContext": true - }, - "frameworks": { - "net451": {}, - "netcoreapp1.1": { - "dependencies": { - "Microsoft.NETCore.App": { - "version": "1.2.0-*", - "type": "platform" - } - } - } - }, - "publish": { - "exclude": [ - "node_modules", - "bower_components", - "**.xproj", - "**.user", - "**.vspscc" - ] - } -} \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Buffering/Microsoft.AspNetCore.Buffering.csproj b/src/Microsoft.AspNetCore.Buffering/Microsoft.AspNetCore.Buffering.csproj new file mode 100644 index 0000000000..40aff99c24 --- /dev/null +++ b/src/Microsoft.AspNetCore.Buffering/Microsoft.AspNetCore.Buffering.csproj @@ -0,0 +1,19 @@ + + + + + + 0.3.0 + ASP.NET Core middleware for buffering response bodies. + net451;netstandard1.3 + $(NoWarn);CS1591 + true + aspnetcore;buffer;buffering + + + + + + + + diff --git a/src/Microsoft.AspNetCore.Buffering/Microsoft.AspNetCore.Buffering.xproj b/src/Microsoft.AspNetCore.Buffering/Microsoft.AspNetCore.Buffering.xproj deleted file mode 100644 index ad20072851..0000000000 --- a/src/Microsoft.AspNetCore.Buffering/Microsoft.AspNetCore.Buffering.xproj +++ /dev/null @@ -1,17 +0,0 @@ - - - - 14.0 - $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - - - - 2363d0dd-a3bf-437e-9b64-b33ae132d875 - .\obj - .\bin\ - - - 2.0 - - - \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Buffering/Properties/AssemblyInfo.cs b/src/Microsoft.AspNetCore.Buffering/Properties/AssemblyInfo.cs deleted file mode 100644 index 76feceeff0..0000000000 --- a/src/Microsoft.AspNetCore.Buffering/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,11 +0,0 @@ -// 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.Reflection; -using System.Resources; - -[assembly: AssemblyMetadata("Serviceable", "True")] -[assembly: NeutralResourcesLanguage("en-us")] -[assembly: AssemblyCompany("Microsoft Corporation.")] -[assembly: AssemblyCopyright("© Microsoft Corporation. All rights reserved.")] -[assembly: AssemblyProduct("Microsoft ASP.NET Core")] diff --git a/src/Microsoft.AspNetCore.Buffering/project.json b/src/Microsoft.AspNetCore.Buffering/project.json deleted file mode 100644 index 2bad7720a1..0000000000 --- a/src/Microsoft.AspNetCore.Buffering/project.json +++ /dev/null @@ -1,35 +0,0 @@ -{ - "version": "0.3.0-*", - "buildOptions": { - "warningsAsErrors": true, - "keyFile": "../../tools/Key.snk", - "nowarn": [ - "CS1591" - ], - "xmlDoc": true - }, - "description": "ASP.NET Core middleware for buffering response bodies.", - "packOptions": { - "repository": { - "type": "git", - "url": "git://github.com/aspnet/basicmiddleware" - }, - "tags": [ - "aspnetcore", - "buffer", - "buffering" - ] - }, - "dependencies": { - "Microsoft.AspNetCore.Http.Abstractions": "1.2.0-*", - "Microsoft.Extensions.TaskCache.Sources": { - "version": "1.2.0-*", - "type": "build" - }, - "NETStandard.Library": "1.6.2-*" - }, - "frameworks": { - "net451": {}, - "netstandard1.3": {} - } -} \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.HttpOverrides/Microsoft.AspNetCore.HttpOverrides.csproj b/src/Microsoft.AspNetCore.HttpOverrides/Microsoft.AspNetCore.HttpOverrides.csproj new file mode 100644 index 0000000000..8441e6b677 --- /dev/null +++ b/src/Microsoft.AspNetCore.HttpOverrides/Microsoft.AspNetCore.HttpOverrides.csproj @@ -0,0 +1,22 @@ + + + + + + 1.2.0 + ASP.NET Core basic middleware for supporting HTTP method overrides. Includes: +* X-Forwarded-* headers to forward headers from a proxy. +* HTTP method override header. + net451;netstandard1.3 + $(NoWarn);CS1591 + true + aspnetcore;proxy;headers;xforwarded + + + + + + + + + diff --git a/src/Microsoft.AspNetCore.HttpOverrides/Microsoft.AspNetCore.HttpOverrides.xproj b/src/Microsoft.AspNetCore.HttpOverrides/Microsoft.AspNetCore.HttpOverrides.xproj deleted file mode 100644 index fbfa940ddc..0000000000 --- a/src/Microsoft.AspNetCore.HttpOverrides/Microsoft.AspNetCore.HttpOverrides.xproj +++ /dev/null @@ -1,17 +0,0 @@ - - - - 14.0 - $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - - - - 517308c3-b477-4b01-b461-cab9c10b6928 - .\obj - .\bin\ - - - 2.0 - - - \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.HttpOverrides/Properties/AssemblyInfo.cs b/src/Microsoft.AspNetCore.HttpOverrides/Properties/AssemblyInfo.cs deleted file mode 100644 index 76feceeff0..0000000000 --- a/src/Microsoft.AspNetCore.HttpOverrides/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,11 +0,0 @@ -// 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.Reflection; -using System.Resources; - -[assembly: AssemblyMetadata("Serviceable", "True")] -[assembly: NeutralResourcesLanguage("en-us")] -[assembly: AssemblyCompany("Microsoft Corporation.")] -[assembly: AssemblyCopyright("© Microsoft Corporation. All rights reserved.")] -[assembly: AssemblyProduct("Microsoft ASP.NET Core")] diff --git a/src/Microsoft.AspNetCore.HttpOverrides/project.json b/src/Microsoft.AspNetCore.HttpOverrides/project.json deleted file mode 100644 index 0f41715dfa..0000000000 --- a/src/Microsoft.AspNetCore.HttpOverrides/project.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "version": "1.2.0-*", - "buildOptions": { - "warningsAsErrors": true, - "keyFile": "../../tools/Key.snk", - "nowarn": [ - "CS1591" - ], - "xmlDoc": true - }, - "description": "ASP.NET Core basic middleware for supporting HTTP method overrides. Includes:\r\n* X-Forwarded-* headers to forward headers from a proxy.\r\n* HTTP method override header.", - "packOptions": { - "repository": { - "type": "git", - "url": "git://github.com/aspnet/basicmiddleware" - }, - "tags": [ - "aspnetcore", - "proxy", - "headers", - "xforwarded" - ] - }, - "dependencies": { - "Microsoft.AspNetCore.Http.Extensions": "1.2.0-*", - "Microsoft.Extensions.Logging.Abstractions": "1.2.0-*", - "Microsoft.Extensions.Options": "1.2.0-*", - "NETStandard.Library": "1.6.2-*" - }, - "frameworks": { - "net451": {}, - "netstandard1.3": {} - } -} \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.ResponseCompression/Microsoft.AspNetCore.ResponseCompression.csproj b/src/Microsoft.AspNetCore.ResponseCompression/Microsoft.AspNetCore.ResponseCompression.csproj new file mode 100644 index 0000000000..4fa5ea9444 --- /dev/null +++ b/src/Microsoft.AspNetCore.ResponseCompression/Microsoft.AspNetCore.ResponseCompression.csproj @@ -0,0 +1,18 @@ + + + + + + 1.1.0 + ASP.NET Core middleware for HTTP Response compression. + net451;netstandard1.3 + true + aspnetcore + + + + + + + + diff --git a/src/Microsoft.AspNetCore.ResponseCompression/Microsoft.AspNetCore.ResponseCompression.xproj b/src/Microsoft.AspNetCore.ResponseCompression/Microsoft.AspNetCore.ResponseCompression.xproj deleted file mode 100644 index 0bd5bdaa35..0000000000 --- a/src/Microsoft.AspNetCore.ResponseCompression/Microsoft.AspNetCore.ResponseCompression.xproj +++ /dev/null @@ -1,17 +0,0 @@ - - - - 14.0 - $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - - - - 45308a9d-f4c6-46a8-a24f-e73d995cc223 - .\obj - .\bin\ - - - 2.0 - - - diff --git a/src/Microsoft.AspNetCore.ResponseCompression/Properties/AssemblyInfo.cs b/src/Microsoft.AspNetCore.ResponseCompression/Properties/AssemblyInfo.cs index 58848c06bb..b1067e327c 100644 --- a/src/Microsoft.AspNetCore.ResponseCompression/Properties/AssemblyInfo.cs +++ b/src/Microsoft.AspNetCore.ResponseCompression/Properties/AssemblyInfo.cs @@ -1,14 +1,6 @@ // 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.Reflection; -using System.Resources; using System.Runtime.CompilerServices; [assembly: InternalsVisibleTo("Microsoft.AspNetCore.ResponseCompression.Tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")] - -[assembly: AssemblyMetadata("Serviceable", "True")] -[assembly: NeutralResourcesLanguage("en-us")] -[assembly: AssemblyCompany("Microsoft Corporation.")] -[assembly: AssemblyCopyright("© Microsoft Corporation. All rights reserved.")] -[assembly: AssemblyProduct("Microsoft ASP.NET Core")] diff --git a/src/Microsoft.AspNetCore.ResponseCompression/project.json b/src/Microsoft.AspNetCore.ResponseCompression/project.json deleted file mode 100644 index 8f1a19cdae..0000000000 --- a/src/Microsoft.AspNetCore.ResponseCompression/project.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "version": "1.1.0-*", - "buildOptions": { - "warningsAsErrors": true, - "keyFile": "../../tools/Key.snk", - "xmlDoc": true - }, - "description": "ASP.NET Core middleware for HTTP Response compression.", - "packOptions": { - "repository": { - "type": "git", - "url": "git://github.com/aspnet/basicmiddleware" - }, - "tags": [ - "aspnetcore" - ] - }, - "dependencies": { - "Microsoft.AspNetCore.Http.Extensions": "1.2.0-*", - "Microsoft.Extensions.Options": "1.2.0-*", - "NETStandard.Library": "1.6.2-*" - }, - "frameworks": { - "net451": {}, - "netstandard1.3": {} - } -} \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Rewrite/Microsoft.AspNetCore.Rewrite.csproj b/src/Microsoft.AspNetCore.Rewrite/Microsoft.AspNetCore.Rewrite.csproj new file mode 100644 index 0000000000..c2ed91e277 --- /dev/null +++ b/src/Microsoft.AspNetCore.Rewrite/Microsoft.AspNetCore.Rewrite.csproj @@ -0,0 +1,27 @@ + + + + + + 1.1.0 + ASP.NET Core basic middleware for rewriting URLs. Includes: +* Support for custom URL rewrite rules +* Support for running IIS URL Rewrite module rules +* Support for running Apache mod_rewrite rules. + net451;netstandard1.3 + $(NoWarn);CS1591 + true + aspnetcore;urlrewrite;mod_rewrite + + + + + + + + + + + + + diff --git a/src/Microsoft.AspNetCore.Rewrite/Microsoft.AspNetCore.Rewrite.xproj b/src/Microsoft.AspNetCore.Rewrite/Microsoft.AspNetCore.Rewrite.xproj deleted file mode 100644 index 08f543fc53..0000000000 --- a/src/Microsoft.AspNetCore.Rewrite/Microsoft.AspNetCore.Rewrite.xproj +++ /dev/null @@ -1,21 +0,0 @@ - - - - 14.0 - $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - - - - - 0e7ca1a7-1dc3-4ce6-b9c7-1688fe1410f1 - Microsoft.AspNetCore.Rewrite - .\obj - .\bin\ - v4.5.2 - - - - 2.0 - - - diff --git a/src/Microsoft.AspNetCore.Rewrite/Properties/AssemblyInfo.cs b/src/Microsoft.AspNetCore.Rewrite/Properties/AssemblyInfo.cs index b56ddcf4e4..3b64da0cff 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Properties/AssemblyInfo.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Properties/AssemblyInfo.cs @@ -1,13 +1,6 @@ // 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.Reflection; -using System.Resources; using System.Runtime.CompilerServices; -[assembly: AssemblyMetadata("Serviceable", "True")] -[assembly: NeutralResourcesLanguage("en-us")] -[assembly: AssemblyCompany("Microsoft Corporation.")] -[assembly: AssemblyCopyright("© Microsoft Corporation. All rights reserved.")] -[assembly: AssemblyProduct("Microsoft ASP.NET Core")] [assembly: InternalsVisibleTo("Microsoft.AspNetCore.Rewrite.Tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")] diff --git a/src/Microsoft.AspNetCore.Rewrite/project.json b/src/Microsoft.AspNetCore.Rewrite/project.json deleted file mode 100644 index 0b9bb3a594..0000000000 --- a/src/Microsoft.AspNetCore.Rewrite/project.json +++ /dev/null @@ -1,45 +0,0 @@ -{ - "version": "1.1.0-*", - "buildOptions": { - "warningsAsErrors": true, - "keyFile": "../../tools/Key.snk", - "nowarn": [ - "CS1591" - ], - "xmlDoc": true - }, - "description": "ASP.NET Core basic middleware for rewriting URLs. Includes:\r\n* Support for custom URL rewrite rules\r\n* Support for running IIS URL Rewrite module rules\r\n* Support for running Apache mod_rewrite rules.", - "packOptions": { - "repository": { - "type": "git", - "url": "git://github.com/aspnet/basicmiddleware" - }, - "tags": [ - "aspnetcore", - "urlrewrite", - "mod_rewrite" - ] - }, - "dependencies": { - "Microsoft.AspNetCore.Hosting.Abstractions": "1.2.0-*", - "Microsoft.AspNetCore.Http.Extensions": "1.2.0-*", - "Microsoft.Extensions.Configuration.Abstractions": "1.2.0-*", - "Microsoft.Extensions.FileProviders.Abstractions": "1.2.0-*", - "Microsoft.Extensions.Logging.Abstractions": "1.2.0-*", - "Microsoft.Extensions.Options": "1.2.0-*", - "Microsoft.Extensions.TaskCache.Sources": { - "version": "1.2.0-*", - "type": "build" - }, - "NETStandard.Library": "1.6.2-*" - }, - "frameworks": { - "net451": { - "frameworkAssemblies": { - "System.Xml": "", - "System.Xml.Linq": "" - } - }, - "netstandard1.3": {} - } -} \ No newline at end of file diff --git a/test/Microsoft.AspNetCore.Buffering.Tests/Microsoft.AspNetCore.Buffering.Tests.csproj b/test/Microsoft.AspNetCore.Buffering.Tests/Microsoft.AspNetCore.Buffering.Tests.csproj new file mode 100644 index 0000000000..18713da3ed --- /dev/null +++ b/test/Microsoft.AspNetCore.Buffering.Tests/Microsoft.AspNetCore.Buffering.Tests.csproj @@ -0,0 +1,17 @@ + + + + + + netcoreapp1.1;net451 + + + + + + + + + + + diff --git a/test/Microsoft.AspNetCore.Buffering.Tests/Microsoft.AspNetCore.Buffering.Tests.xproj b/test/Microsoft.AspNetCore.Buffering.Tests/Microsoft.AspNetCore.Buffering.Tests.xproj deleted file mode 100644 index c3ffee43d6..0000000000 --- a/test/Microsoft.AspNetCore.Buffering.Tests/Microsoft.AspNetCore.Buffering.Tests.xproj +++ /dev/null @@ -1,20 +0,0 @@ - - - - 14.0 - $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - - - - f5f1d123-9c81-4a9e-8644-aa46b8e578fb - .\obj - .\bin\ - - - 2.0 - - - - - - \ No newline at end of file diff --git a/test/Microsoft.AspNetCore.Buffering.Tests/project.json b/test/Microsoft.AspNetCore.Buffering.Tests/project.json deleted file mode 100644 index e352fdf740..0000000000 --- a/test/Microsoft.AspNetCore.Buffering.Tests/project.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "version": "1.2.0-*", - "buildOptions": { - "warningsAsErrors": true - }, - "dependencies": { - "dotnet-test-xunit": "2.2.0-*", - "Microsoft.AspNetCore.Buffering": "0.3.0-*", - "Microsoft.AspNetCore.TestHost": "1.2.0-*", - "xunit": "2.2.0-*" - }, - "frameworks": { - "netcoreapp1.1": { - "dependencies": { - "Microsoft.NETCore.App": { - "version": "1.2.0-*", - "type": "platform" - } - } - }, - "net451": {} - }, - "testRunner": "xunit" -} \ No newline at end of file diff --git a/test/Microsoft.AspNetCore.HttpOverrides.Tests/Microsoft.AspNetCore.HttpOverrides.Tests.csproj b/test/Microsoft.AspNetCore.HttpOverrides.Tests/Microsoft.AspNetCore.HttpOverrides.Tests.csproj new file mode 100644 index 0000000000..98f046a40d --- /dev/null +++ b/test/Microsoft.AspNetCore.HttpOverrides.Tests/Microsoft.AspNetCore.HttpOverrides.Tests.csproj @@ -0,0 +1,18 @@ + + + + + + netcoreapp1.1;net451 + + + + + + + + + + + + diff --git a/test/Microsoft.AspNetCore.HttpOverrides.Tests/Microsoft.AspNetCore.HttpOverrides.Tests.xproj b/test/Microsoft.AspNetCore.HttpOverrides.Tests/Microsoft.AspNetCore.HttpOverrides.Tests.xproj deleted file mode 100644 index 117f3f01e7..0000000000 --- a/test/Microsoft.AspNetCore.HttpOverrides.Tests/Microsoft.AspNetCore.HttpOverrides.Tests.xproj +++ /dev/null @@ -1,20 +0,0 @@ - - - - 14.0 - $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - - - - d6341b92-3416-4f11-8df4-cb274296175f - .\obj - .\bin\ - - - 2.0 - - - - - - \ No newline at end of file diff --git a/test/Microsoft.AspNetCore.HttpOverrides.Tests/project.json b/test/Microsoft.AspNetCore.HttpOverrides.Tests/project.json deleted file mode 100644 index fcc8302c38..0000000000 --- a/test/Microsoft.AspNetCore.HttpOverrides.Tests/project.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "version": "1.2.0-*", - "buildOptions": { - "warningsAsErrors": true - }, - "dependencies": { - "dotnet-test-xunit": "2.2.0-*", - "Microsoft.AspNetCore.HttpOverrides": "1.2.0-*", - "Microsoft.AspNetCore.TestHost": "1.2.0-*", - "Microsoft.Extensions.Logging.Testing": "1.2.0-*", - "xunit": "2.2.0-*" - }, - "frameworks": { - "netcoreapp1.1": { - "dependencies": { - "Microsoft.NETCore.App": { - "version": "1.2.0-*", - "type": "platform" - } - } - }, - "net451": {} - }, - "testRunner": "xunit" -} \ No newline at end of file diff --git a/test/Microsoft.AspNetCore.ResponseCompression.Tests/Microsoft.AspNetCore.ResponseCompression.Tests.csproj b/test/Microsoft.AspNetCore.ResponseCompression.Tests/Microsoft.AspNetCore.ResponseCompression.Tests.csproj new file mode 100644 index 0000000000..dd2bbf56c9 --- /dev/null +++ b/test/Microsoft.AspNetCore.ResponseCompression.Tests/Microsoft.AspNetCore.ResponseCompression.Tests.csproj @@ -0,0 +1,24 @@ + + + + + + netcoreapp1.1;net451 + + + + + + + + + + + + + + + + + + diff --git a/test/Microsoft.AspNetCore.ResponseCompression.Tests/Microsoft.AspNetCore.ResponseCompression.Tests.xproj b/test/Microsoft.AspNetCore.ResponseCompression.Tests/Microsoft.AspNetCore.ResponseCompression.Tests.xproj deleted file mode 100644 index 756da5af61..0000000000 --- a/test/Microsoft.AspNetCore.ResponseCompression.Tests/Microsoft.AspNetCore.ResponseCompression.Tests.xproj +++ /dev/null @@ -1,20 +0,0 @@ - - - - 14.0 - $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - - - - 3360a5d1-70c0-49ee-9051-04a6a6b836dc - .\obj - .\bin\ - - - 2.0 - - - - - - diff --git a/test/Microsoft.AspNetCore.ResponseCompression.Tests/project.json b/test/Microsoft.AspNetCore.ResponseCompression.Tests/project.json deleted file mode 100644 index 55df362b78..0000000000 --- a/test/Microsoft.AspNetCore.ResponseCompression.Tests/project.json +++ /dev/null @@ -1,30 +0,0 @@ -{ - "buildOptions": { - "keyFile": "../../tools/Key.snk", - "copyToOutput": [ - "testfile1kb.txt" - ], - "warningsAsErrors": true - }, - "dependencies": { - "dotnet-test-xunit": "2.2.0-*", - "Microsoft.AspNetCore.Http": "1.2.0-*", - "Microsoft.AspNetCore.ResponseCompression": "1.1.0-*", - "Microsoft.AspNetCore.TestHost": "1.2.0-*", - "Microsoft.Net.Http.Headers": "1.2.0-*", - "Moq": "4.6.36-*", - "xunit": "2.2.0-*" - }, - "frameworks": { - "netcoreapp1.1": { - "dependencies": { - "Microsoft.NETCore.App": { - "version": "1.2.0-*", - "type": "platform" - } - } - }, - "net451": {} - }, - "testRunner": "xunit" -} \ No newline at end of file diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/Microsoft.AspNetCore.Rewrite.Tests.csproj b/test/Microsoft.AspNetCore.Rewrite.Tests/Microsoft.AspNetCore.Rewrite.Tests.csproj new file mode 100644 index 0000000000..7e008b87f0 --- /dev/null +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/Microsoft.AspNetCore.Rewrite.Tests.csproj @@ -0,0 +1,19 @@ + + + + + + netcoreapp1.1;net451 + + + + + + + + + + + + + diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/Microsoft.AspNetCore.Rewrite.Tests.xproj b/test/Microsoft.AspNetCore.Rewrite.Tests/Microsoft.AspNetCore.Rewrite.Tests.xproj deleted file mode 100644 index ca7df9cddb..0000000000 --- a/test/Microsoft.AspNetCore.Rewrite.Tests/Microsoft.AspNetCore.Rewrite.Tests.xproj +++ /dev/null @@ -1,22 +0,0 @@ - - - - 14.0 - $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - - - - 31794f9e-a1aa-4535-b03c-a3233737cd1a - Microsoft.AspNetCore.Rewrite.Tests - .\obj - .\bin\ - v4.5.2 - - - 2.0 - - - - - - \ No newline at end of file diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/Properties/AssemblyInfo.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/Properties/AssemblyInfo.cs deleted file mode 100644 index 3fc4674978..0000000000 --- a/test/Microsoft.AspNetCore.Rewrite.Tests/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,19 +0,0 @@ -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("Microsoft.AspNetCore.Rewrite.Tests")] -[assembly: AssemblyTrademark("")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] - -// The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("31794f9e-a1aa-4535-b03c-a3233737cd1a")] diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/project.json b/test/Microsoft.AspNetCore.Rewrite.Tests/project.json deleted file mode 100644 index 16c8c03f89..0000000000 --- a/test/Microsoft.AspNetCore.Rewrite.Tests/project.json +++ /dev/null @@ -1,30 +0,0 @@ -{ - "buildOptions": { - "warningsAsErrors": true, - "keyFile": "../../tools/Key.snk" - }, - "dependencies": { - "dotnet-test-xunit": "2.2.0-*", - "Microsoft.AspNetCore.Hosting": "1.2.0-*", - "Microsoft.AspNetCore.Rewrite": "1.1.0-*", - "Microsoft.AspNetCore.TestHost": "1.2.0-*", - "Microsoft.Extensions.Logging.Testing": "1.2.0-*", - "xunit": "2.2.0-*" - }, - "frameworks": { - "netcoreapp1.1": { - "dependencies": { - "Microsoft.CodeCoverage": { - "type": "build", - "version": "1.0.2" - }, - "Microsoft.NETCore.App": { - "version": "1.2.0-*", - "type": "platform" - } - } - }, - "net451": {} - }, - "testRunner": "xunit" -} \ No newline at end of file diff --git a/version.props b/version.props new file mode 100644 index 0000000000..68a61ffe6e --- /dev/null +++ b/version.props @@ -0,0 +1,6 @@ + + + + preview1 + + From 4fa6ed37922e934232f3d01a29d2ad864d5cf7b7 Mon Sep 17 00:00:00 2001 From: David Peden Date: Fri, 3 Feb 2017 18:20:41 -0600 Subject: [PATCH 167/307] Added support for IIS global rules (#169) --- .../IISUrlRewrite/IISUrlRewriteRule.cs | 12 +++++ .../Internal/IISUrlRewrite/InputParser.cs | 17 +++---- .../Internal/IISUrlRewrite/ServerVariables.cs | 14 ++++-- .../IISUrlRewrite/UrlRewriteFileParser.cs | 35 ++++++-------- .../IISUrlRewrite/UrlRewriteRuleBuilder.cs | 4 +- .../PatternSegments/GlobalRuleUrlSegment.cs | 15 ++++++ .../Internal/PatternSegments/UrlSegment.cs | 2 +- .../RewriteMiddleware.cs | 7 +-- .../IISUrlRewrite/FileParserTests.cs | 37 +++++++++++++-- .../IISUrlRewrite/InputParserTests.cs | 12 ++--- .../IISUrlRewrite/MiddleWareTests.cs | 29 ++++++++++++ .../IISUrlRewrite/ServerVariableTests.cs | 32 +++++++------ .../GlobalRuleUrlSegmentTests.cs | 47 +++++++++++++++++++ .../PatternSegments/UrlSegmentTests.cs | 25 ++++++---- 14 files changed, 219 insertions(+), 69 deletions(-) create mode 100644 src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/GlobalRuleUrlSegment.cs create mode 100644 test/Microsoft.AspNetCore.Rewrite.Tests/PatternSegments/GlobalRuleUrlSegmentTests.cs diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/IISUrlRewriteRule.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/IISUrlRewriteRule.cs index d2c9b41acd..86a9faf1c6 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/IISUrlRewriteRule.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/IISUrlRewriteRule.cs @@ -14,18 +14,30 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite public IList Conditions { get; } public UrlAction Action { get; } public bool TrackAllCaptures { get; } + public bool Global { get; } public IISUrlRewriteRule(string name, UrlMatch initialMatch, IList conditions, UrlAction action, bool trackAllCaptures) + : this(name, initialMatch, conditions, action, trackAllCaptures, false) + { + } + + public IISUrlRewriteRule(string name, + UrlMatch initialMatch, + IList conditions, + UrlAction action, + bool trackAllCaptures, + bool global) { Name = name; InitialMatch = initialMatch; Conditions = conditions; Action = action; TrackAllCaptures = trackAllCaptures; + Global = global; } public virtual void ApplyRule(RewriteContext context) diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/InputParser.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/InputParser.cs index 8a944972da..c99790cb43 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/InputParser.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/InputParser.cs @@ -18,8 +18,9 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite /// compare to the condition. Can contain server variables, back references, etc. /// /// + /// /// A new , containing a list of - public Pattern ParseInputString(string testString) + public Pattern ParseInputString(string testString, bool global) { if (testString == null) { @@ -27,10 +28,10 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite } var context = new ParserContext(testString); - return ParseString(context); + return ParseString(context, global); } - private static Pattern ParseString(ParserContext context) + private static Pattern ParseString(ParserContext context, bool global) { var results = new List(); while (context.Next()) @@ -43,7 +44,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite // missing { throw new FormatException(Resources.FormatError_InputParserMissingCloseBrace(context.Index)); } - ParseParameter(context, results); + ParseParameter(context, results, global); } else if (context.Current == CloseBrace) { @@ -59,7 +60,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite return new Pattern(results); } - private static void ParseParameter(ParserContext context, IList results) + private static void ParseParameter(ParserContext context, IList results, bool global) { context.Mark(); // Four main cases: @@ -75,7 +76,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite { // This is just a server variable, so we do a lookup and verify the server variable exists. parameter = context.Capture(); - results.Add(ServerVariables.FindServerVariable(parameter, context)); + results.Add(ServerVariables.FindServerVariable(parameter, context, global)); return; } else if (context.Current == Colon) @@ -87,7 +88,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite { case "ToLower": { - var pattern = ParseString(context); + var pattern = ParseString(context, global); results.Add(new ToLowerSegment(pattern)); // at this point, we expect our context to be on the ending closing brace, @@ -105,7 +106,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite } case "UrlEncode": { - var pattern = ParseString(context); + var pattern = ParseString(context, global); results.Add(new UrlEncodeSegment(pattern)); if (context.Current != CloseBrace) diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/ServerVariables.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/ServerVariables.cs index 12367e142c..54df27a19e 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/ServerVariables.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/ServerVariables.cs @@ -9,7 +9,15 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite { public static class ServerVariables { - public static PatternSegment FindServerVariable(string serverVariable, ParserContext context) + /// + /// Returns the matching for the given + /// + /// The server variable + /// The parser context which is utilized when an exception is thrown + /// Indicates if the rule being parsed is a global rule + /// Thrown when the server variable is unknown + /// The matching + public static PatternSegment FindServerVariable(string serverVariable, ParserContext context, bool global) { switch (serverVariable) { @@ -35,7 +43,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite case "HTTP_CONNECTION": return new HeaderSegment(HeaderNames.Connection); case "HTTP_URL": - return new UrlSegment(); + return global ? (PatternSegment)new GlobalRuleUrlSegment() : (PatternSegment)new UrlSegment(); case "HTTPS": return new IsHttpsUrlSegment(); case "LOCAL_ADDR": @@ -53,7 +61,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite case "REQUEST_FILENAME": return new RequestFileNameSegment(); case "REQUEST_URI": - return new UrlSegment(); + return global ? (PatternSegment)new GlobalRuleUrlSegment() : (PatternSegment)new UrlSegment(); default: throw new FormatException(Resources.FormatError_InputParserUnrecognizedParameter(serverVariable, context.Index)); } diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/UrlRewriteFileParser.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/UrlRewriteFileParser.cs index 02ecde3562..e4d8296c7c 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/UrlRewriteFileParser.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/UrlRewriteFileParser.cs @@ -22,40 +22,33 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite if (xmlRoot != null) { var result = new List(); - // TODO Global rules are currently not treated differently than normal rules, fix. - // See: https://github.com/aspnet/BasicMiddleware/issues/59 - ParseRules(xmlRoot.Descendants(RewriteTags.GlobalRules).FirstOrDefault(), result); - ParseRules(xmlRoot.Descendants(RewriteTags.Rules).FirstOrDefault(), result); + ParseRules(xmlRoot.Descendants(RewriteTags.GlobalRules).FirstOrDefault(), result, global: true); + ParseRules(xmlRoot.Descendants(RewriteTags.Rules).FirstOrDefault(), result, global: false); return result; } return null; } - private void ParseRules(XElement rules, IList result) + private void ParseRules(XElement rules, IList result, bool global) { if (rules == null) { return; } - if (string.Equals(rules.Name.ToString(), "GlobalRules", StringComparison.OrdinalIgnoreCase)) - { - throw new NotSupportedException("Support for global rules has not been implemented yet"); - } - foreach (var rule in rules.Elements(RewriteTags.Rule)) { var builder = new UrlRewriteRuleBuilder(); - ParseRuleAttributes(rule, builder); + ParseRuleAttributes(rule, builder, global); if (builder.Enabled) { - result.Add(builder.Build()); + result.Add(builder.Build(global)); } } } - private void ParseRuleAttributes(XElement rule, UrlRewriteRuleBuilder builder) + private void ParseRuleAttributes(XElement rule, UrlRewriteRuleBuilder builder, bool global) { builder.Name = rule.Attribute(RewriteTags.Name)?.Value; @@ -84,8 +77,8 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite } ParseMatch(match, builder, patternSyntax); - ParseConditions(rule.Element(RewriteTags.Conditions), builder, patternSyntax); - ParseUrlAction(action, builder, stopProcessing); + ParseConditions(rule.Element(RewriteTags.Conditions), builder, patternSyntax, global); + ParseUrlAction(action, builder, stopProcessing, global); } private void ParseMatch(XElement match, UrlRewriteRuleBuilder builder, PatternSyntax patternSyntax) @@ -101,7 +94,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite builder.AddUrlMatch(parsedInputString, ignoreCase, negate, patternSyntax); } - private void ParseConditions(XElement conditions, UrlRewriteRuleBuilder builder, PatternSyntax patternSyntax) + private void ParseConditions(XElement conditions, UrlRewriteRuleBuilder builder, PatternSyntax patternSyntax, bool global) { if (conditions == null) { @@ -114,11 +107,11 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite foreach (var cond in conditions.Elements(RewriteTags.Add)) { - ParseCondition(cond, builder, patternSyntax, trackAllCaptures); + ParseCondition(cond, builder, patternSyntax, trackAllCaptures, global); } } - private void ParseCondition(XElement condition, UrlRewriteRuleBuilder builder, PatternSyntax patternSyntax, bool trackAllCaptures) + private void ParseCondition(XElement condition, UrlRewriteRuleBuilder builder, PatternSyntax patternSyntax, bool trackAllCaptures, bool global) { var ignoreCase = ParseBool(condition, RewriteTags.IgnoreCase, defaultValue: true); var negate = ParseBool(condition, RewriteTags.Negate, defaultValue: false); @@ -133,7 +126,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite var parsedPatternString = condition.Attribute(RewriteTags.Pattern)?.Value; try { - var input = _inputParser.ParseInputString(parsedInputString); + var input = _inputParser.ParseInputString(parsedInputString, global); builder.AddUrlCondition(input, parsedPatternString, patternSyntax, matchType, ignoreCase, negate, trackAllCaptures); } catch (FormatException formatException) @@ -142,7 +135,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite } } - private void ParseUrlAction(XElement urlAction, UrlRewriteRuleBuilder builder, bool stopProcessing) + private void ParseUrlAction(XElement urlAction, UrlRewriteRuleBuilder builder, bool stopProcessing, bool global) { var actionType = ParseEnum(urlAction, RewriteTags.Type, ActionType.None); var redirectType = ParseEnum(urlAction, RewriteTags.RedirectType, RedirectType.Permanent); @@ -160,7 +153,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite try { - var input = _inputParser.ParseInputString(url); + var input = _inputParser.ParseInputString(url, global); builder.AddUrlAction(input, actionType, appendQuery, stopProcessing, (int)redirectType); } catch (FormatException formatException) diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/UrlRewriteRuleBuilder.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/UrlRewriteRuleBuilder.cs index e7587ba5da..26951d5f9c 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/UrlRewriteRuleBuilder.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/UrlRewriteRuleBuilder.cs @@ -23,14 +23,14 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite private bool _matchAny; private bool _trackAllCaptures; - public IISUrlRewriteRule Build() + public IISUrlRewriteRule Build(bool global) { if (_initialMatch == null || _action == null) { throw new InvalidOperationException("Cannot create UrlRewriteRule without action and match"); } - return new IISUrlRewriteRule(Name, _initialMatch, _conditions, _action, _trackAllCaptures); + return new IISUrlRewriteRule(Name, _initialMatch, _conditions, _action, _trackAllCaptures, global); } public void AddUrlAction( diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/GlobalRuleUrlSegment.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/GlobalRuleUrlSegment.cs new file mode 100644 index 0000000000..1a83837b98 --- /dev/null +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/GlobalRuleUrlSegment.cs @@ -0,0 +1,15 @@ +// 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 Microsoft.AspNetCore.Http.Extensions; + +namespace Microsoft.AspNetCore.Rewrite.Internal.PatternSegments +{ + public class GlobalRuleUrlSegment : PatternSegment + { + public override string Evaluate(RewriteContext context, BackReferenceCollection ruleBackReferences, BackReferenceCollection conditionBackReferences) + { + return context.HttpContext.Request.GetEncodedUrl(); + } + } +} \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/UrlSegment.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/UrlSegment.cs index 005a335f8c..d655268c03 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/UrlSegment.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/UrlSegment.cs @@ -10,4 +10,4 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.PatternSegments return context.HttpContext.Request.Path; } } -} +} \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Rewrite/RewriteMiddleware.cs b/src/Microsoft.AspNetCore.Rewrite/RewriteMiddleware.cs index 953e5896c5..cc27a90ab2 100644 --- a/src/Microsoft.AspNetCore.Rewrite/RewriteMiddleware.cs +++ b/src/Microsoft.AspNetCore.Rewrite/RewriteMiddleware.cs @@ -5,6 +5,8 @@ using System; using System.Threading.Tasks; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Http.Extensions; +using Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite; using Microsoft.AspNetCore.Rewrite.Logging; using Microsoft.Extensions.FileProviders; using Microsoft.Extensions.Internal; @@ -75,11 +77,10 @@ namespace Microsoft.AspNetCore.Rewrite foreach (var rule in _options.Rules) { rule.ApplyRule(rewriteContext); - var currentUrl = new Lazy(() => context.Request.Path + context.Request.QueryString); switch (rewriteContext.Result) { case RuleResult.ContinueRules: - _logger.RewriteMiddlewareRequestContinueResults(currentUrl.Value); + _logger.RewriteMiddlewareRequestContinueResults(context.Request.GetEncodedUrl()); break; case RuleResult.EndResponse: _logger.RewriteMiddlewareRequestResponseComplete( @@ -87,7 +88,7 @@ namespace Microsoft.AspNetCore.Rewrite context.Response.StatusCode); return TaskCache.CompletedTask; case RuleResult.SkipRemainingRules: - _logger.RewriteMiddlewareRequestStopRules(currentUrl.Value); + _logger.RewriteMiddlewareRequestStopRules(context.Request.GetEncodedUrl()); return _next(context); default: throw new ArgumentOutOfRangeException($"Invalid rule termination {rewriteContext.Result}"); diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/FileParserTests.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/FileParserTests.cs index 1a8aaeab43..edc93076a4 100644 --- a/test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/FileParserTests.cs +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/FileParserTests.cs @@ -61,7 +61,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite var condList = new List(); condList.Add(new Condition { - Input = new InputParser().ParseInputString("{HTTPS}"), + Input = new InputParser().ParseInputString("{HTTPS}", global: false), Match = new RegexMatch(new Regex("^OFF$"), false) }); @@ -105,7 +105,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite var condList = new List(); condList.Add(new Condition { - Input = new InputParser().ParseInputString("{HTTPS}"), + Input = new InputParser().ParseInputString("{HTTPS}", global: false), Match = new RegexMatch(new Regex("^OFF$"), false) }); @@ -128,6 +128,37 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite AssertUrlRewriteRuleEquality(expected, res); } + [Fact] + public void Should_parse_global_rules() + { + // arrange + var xml = @" + + + + + + + + + + + + + + + + "; + + // act + var rules = new UrlRewriteFileParser().Parse(new StringReader(xml)); + + // assert + Assert.Equal(2, rules.Count); + Assert.True(rules[0].Global); + Assert.False(rules[1].Global); + } + // Creates a rule with appropriate default values of the url rewrite rule. private IISUrlRewriteRule CreateTestRule(List conditions, LogicalGrouping condGrouping = LogicalGrouping.MatchAll, @@ -147,7 +178,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite ) { return new IISUrlRewriteRule(name, new RegexMatch(new Regex("^OFF$"), false), conditions, - new RewriteAction(RuleResult.ContinueRules, new InputParser().ParseInputString(url), queryStringAppend: false), trackAllCaptures: false); + new RewriteAction(RuleResult.ContinueRules, new InputParser().ParseInputString(url, global: false), queryStringAppend: false), trackAllCaptures: false); } // TODO make rules comparable? diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/InputParserTests.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/InputParserTests.cs index 590785c3d3..ea3d4819d0 100644 --- a/test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/InputParserTests.cs +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/InputParserTests.cs @@ -16,7 +16,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite public void InputParser_ParseLiteralString() { var testString = "hello/hey/what"; - var result = new InputParser().ParseInputString(testString); + var result = new InputParser().ParseInputString(testString, global: false); Assert.Equal(1, result.PatternSegments.Count); } @@ -28,7 +28,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite [InlineData("foo/", 1)] public void InputParser_ParseStringWithBackReference(string testString, int expected) { - var result = new InputParser().ParseInputString(testString); + var result = new InputParser().ParseInputString(testString, global: false); Assert.Equal(expected, result.PatternSegments.Count); } @@ -44,7 +44,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite [InlineData("hey/{R:1}/{C:1}", "hey/foo/foo")] public void EvaluateBackReferenceRule(string testString, string expected) { - var middle = new InputParser().ParseInputString(testString); + var middle = new InputParser().ParseInputString(testString, global: false); var result = middle.Evaluate(CreateTestRewriteContext(), CreateTestRuleBackReferences(), CreateTestCondBackReferences()); Assert.Equal(expected, result); } @@ -57,7 +57,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite [InlineData("hey/ToLower:/what", "hey/ToLower:/what")] public void EvaluatToLowerRule(string testString, string expected) { - var middle = new InputParser().ParseInputString(testString); + var middle = new InputParser().ParseInputString(testString, global: false); var result = middle.Evaluate(CreateTestRewriteContext(), CreateTestRuleBackReferences(), CreateTestCondBackReferences()); Assert.Equal(expected, result); } @@ -66,7 +66,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite [InlineData("hey/{UrlEncode:}", "hey/%3Chey%3E")] public void EvaluatUriEncodeRule(string testString, string expected) { - var middle = new InputParser().ParseInputString(testString); + var middle = new InputParser().ParseInputString(testString, global: false); var result = middle.Evaluate(CreateTestRewriteContext(), CreateTestRuleBackReferences(), CreateTestCondBackReferences()); Assert.Equal(expected, result); } @@ -85,7 +85,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite [InlineData("{HTTPS")] public void FormatExceptionsOnBadSyntax(string testString) { - Assert.Throws(() => new InputParser().ParseInputString(testString)); + Assert.Throws(() => new InputParser().ParseInputString(testString, global: false)); } private RewriteContext CreateTestRewriteContext() diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/MiddleWareTests.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/MiddleWareTests.cs index b2724e8d58..a720a58b65 100644 --- a/test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/MiddleWareTests.cs +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/MiddleWareTests.cs @@ -7,6 +7,7 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Http.Extensions; using Microsoft.AspNetCore.TestHost; using Microsoft.Net.Http.Headers; using Xunit; @@ -451,5 +452,33 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite Assert.Equal("Cannot access back reference at index 9. Only 5 back references were captured.", ex.Message); } + + [Fact] + public async Task Invoke_GlobalRuleConditionMatchesAgainstFullUri() + { + var xml = @" + + + + + + + + + + "; + var options = new RewriteOptions().AddIISUrlRewrite(new StringReader(xml)); + var builder = new WebHostBuilder() + .Configure(app => + { + app.UseRewriter(options); + app.Run(context => context.Response.WriteAsync(context.Request.GetEncodedUrl())); + }); + var server = new TestServer(builder); + + var response = await server.CreateClient().GetStringAsync($"http://localhost/{Guid.NewGuid()}/foo/bar"); + + Assert.Equal("http://www.test.com/foo/bar", response); + } } } diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/ServerVariableTests.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/ServerVariableTests.cs index 1d0f0154df..c8716e144f 100644 --- a/test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/ServerVariableTests.cs +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/ServerVariableTests.cs @@ -13,22 +13,25 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite public class ServerVariableTests { [Theory] - [InlineData("CONTENT_LENGTH", "10")] - [InlineData("CONTENT_TYPE", "json")] - [InlineData("HTTP_ACCEPT", "accept")] - [InlineData("HTTP_COOKIE", "cookie")] - [InlineData("HTTP_HOST", "example.com")] - [InlineData("HTTP_REFERER", "referer")] - [InlineData("HTTP_USER_AGENT", "useragent")] - [InlineData("HTTP_CONNECTION", "connection")] - [InlineData("HTTP_URL", "/foo")] - [InlineData("QUERY_STRING", "bar=1")] - [InlineData("REQUEST_FILENAME", "/foo")] - public void CheckServerVariableParsingAndApplication(string variable, string expected) + [InlineData("CONTENT_LENGTH", "10", false)] + [InlineData("CONTENT_TYPE", "json", false)] + [InlineData("HTTP_ACCEPT", "accept", false)] + [InlineData("HTTP_COOKIE", "cookie", false)] + [InlineData("HTTP_HOST", "example.com", false)] + [InlineData("HTTP_REFERER", "referer", false)] + [InlineData("HTTP_USER_AGENT", "useragent", false)] + [InlineData("HTTP_CONNECTION", "connection", false)] + [InlineData("HTTP_URL", "/foo", false)] + [InlineData("HTTP_URL", "http://example.com/foo?bar=1", true)] + [InlineData("QUERY_STRING", "bar=1", false)] + [InlineData("REQUEST_FILENAME", "/foo", false)] + [InlineData("REQUEST_URI", "/foo", false)] + [InlineData("REQUEST_URI", "http://example.com/foo?bar=1", true)] + public void CheckServerVariableParsingAndApplication(string variable, string expected, bool global) { // Arrange and Act var testParserContext = new ParserContext("test"); - var serverVar = ServerVariables.FindServerVariable(variable, testParserContext); + var serverVar = ServerVariables.FindServerVariable(variable, testParserContext, global); var lookup = serverVar.Evaluate(CreateTestHttpContext(), CreateTestRuleMatch().BackReferences, CreateTestCondMatch().BackReferences); // Assert Assert.Equal(expected, lookup); @@ -37,6 +40,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite private RewriteContext CreateTestHttpContext() { var context = new DefaultHttpContext(); + context.Request.Scheme = "http"; context.Request.Host = new HostString("example.com"); context.Request.Path = PathString.FromUriComponent("/foo"); context.Request.QueryString = QueryString.FromUriComponent("?bar=1"); @@ -68,7 +72,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite var context = new DefaultHttpContext(); var rewriteContext = new RewriteContext { HttpContext = context }; var testParserContext = new ParserContext("test"); - var serverVar = ServerVariables.FindServerVariable("QUERY_STRING", testParserContext); + var serverVar = ServerVariables.FindServerVariable("QUERY_STRING", testParserContext, global: false); var lookup = serverVar.Evaluate(rewriteContext, CreateTestRuleMatch().BackReferences, CreateTestCondMatch().BackReferences); Assert.Equal(string.Empty, lookup); diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/PatternSegments/GlobalRuleUrlSegmentTests.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/PatternSegments/GlobalRuleUrlSegmentTests.cs new file mode 100644 index 0000000000..ca41021c75 --- /dev/null +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/PatternSegments/GlobalRuleUrlSegmentTests.cs @@ -0,0 +1,47 @@ +// 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 Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Rewrite.Internal.PatternSegments; +using Xunit; + +namespace Microsoft.AspNetCore.Rewrite.Tests.PatternSegments +{ + public class GlobalRuleUrlSegmentTests + { + [Theory] + [InlineData("http", "localhost", 80, null, null, "http://localhost:80/")] + [InlineData("http", "localhost", 80, "/foo/bar", null, "http://localhost:80/foo/bar")] + [InlineData("http", "localhost", 80, "/foo bar", null, "http://localhost:80/foo%20bar")] + [InlineData("http", "localhost", 81, "/foo/bar", null, "http://localhost:81/foo/bar")] + [InlineData("http", "localhost", 80, null, "?foo=bar", "http://localhost:80/?foo=bar")] + [InlineData("https", "localhost", 443, "/foo/bar", null, "https://localhost:443/foo/bar")] + public void AssertSegmentIsCorrect(string scheme, string host, int port, string path, string queryString, string expectedResult) + { + // Arrange + var httpContext = new DefaultHttpContext(); + httpContext.Request.Scheme = scheme; + httpContext.Request.Host = new HostString(host, port); + + if (!string.IsNullOrEmpty(path)) + { + httpContext.Request.Path = new PathString(path); + } + + if (!string.IsNullOrEmpty(queryString)) + { + httpContext.Request.QueryString = new QueryString(queryString); + } + + var context = new RewriteContext { HttpContext = httpContext }; + context.HttpContext = httpContext; + + // Act + var segment = new GlobalRuleUrlSegment(); + var results = segment.Evaluate(context, null, null); + + // Assert + Assert.Equal(expectedResult, results); + } + } +} \ No newline at end of file diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/PatternSegments/UrlSegmentTests.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/PatternSegments/UrlSegmentTests.cs index d23c2a5fb4..ee53d56a42 100644 --- a/test/Microsoft.AspNetCore.Rewrite.Tests/PatternSegments/UrlSegmentTests.cs +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/PatternSegments/UrlSegmentTests.cs @@ -9,18 +9,27 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.PatternSegments { public class UrlSegmentTests { - [Fact] - public void LocalPortSegment_AssertSegmentIsCorrect() + [Theory] + [InlineData("http", "localhost", 80, "/foo/bar", "/foo/bar")] + [InlineData("http", "localhost", 80, "/foo:bar", "/foo:bar")] + [InlineData("http", "localhost", 80, "/foo bar", "/foo%20bar")] + public void AssertSegmentIsCorrect(string scheme, string host, int port, string path, string expectedResult) { // Arrange - var segement = new UrlSegment(); - var context = new RewriteContext { HttpContext = new DefaultHttpContext() }; - context.HttpContext.Request.Path = new PathString("/foo/bar"); + var httpContext = new DefaultHttpContext(); + httpContext.Request.Scheme = scheme; + httpContext.Request.Host = new HostString(host, port); + httpContext.Request.Path = new PathString(path); + + var context = new RewriteContext { HttpContext = httpContext }; + context.HttpContext = httpContext; + // Act - var results = segement.Evaluate(context, null, null); + var segment = new UrlSegment(); + var results = segment.Evaluate(context, null, null); // Assert - Assert.Equal("/foo/bar", results); + Assert.Equal(expectedResult, results); } } -} +} \ No newline at end of file From 3faa3de14dec25cce37b5df2f3b2af95510defe7 Mon Sep 17 00:00:00 2001 From: David Peden Date: Tue, 7 Feb 2017 14:37:23 -0600 Subject: [PATCH 168/307] Add IIS rewrite map support (#168) --- .../IISUrlRewriteOptionsExtensions.cs | 2 +- .../Internal/IISUrlRewrite/IISRewriteMap.cs | 45 +++++++++++++++ .../IISUrlRewrite/IISRewriteMapCollection.cs | 42 ++++++++++++++ .../Internal/IISUrlRewrite/InputParser.cs | 21 ++++++- .../IISUrlRewrite/RewriteMapParser.cs | 39 +++++++++++++ .../Internal/IISUrlRewrite/RewriteTags.cs | 6 +- .../IISUrlRewrite/UrlRewriteFileParser.cs | 21 ++++--- .../PatternSegments/RewriteMapSegment.cs | 25 +++++++++ .../IISUrlRewrite/InputParserTests.cs | 56 ++++++++++++++++++- .../IISUrlRewrite/MiddleWareTests.cs | 36 ++++++++++++ .../IISUrlRewrite/RewriteMapParserTests.cs | 43 ++++++++++++++ 11 files changed, 323 insertions(+), 13 deletions(-) create mode 100644 src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/IISRewriteMap.cs create mode 100644 src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/IISRewriteMapCollection.cs create mode 100644 src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/RewriteMapParser.cs create mode 100644 src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/RewriteMapSegment.cs create mode 100644 test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/RewriteMapParserTests.cs diff --git a/src/Microsoft.AspNetCore.Rewrite/IISUrlRewriteOptionsExtensions.cs b/src/Microsoft.AspNetCore.Rewrite/IISUrlRewriteOptionsExtensions.cs index bed837ae44..e31819b111 100644 --- a/src/Microsoft.AspNetCore.Rewrite/IISUrlRewriteOptionsExtensions.cs +++ b/src/Microsoft.AspNetCore.Rewrite/IISUrlRewriteOptionsExtensions.cs @@ -66,4 +66,4 @@ namespace Microsoft.AspNetCore.Rewrite return options; } } -} +} \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/IISRewriteMap.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/IISRewriteMap.cs new file mode 100644 index 0000000000..0cd52338b9 --- /dev/null +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/IISRewriteMap.cs @@ -0,0 +1,45 @@ +// 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; +using System.Collections.Generic; + +namespace Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite +{ + public class IISRewriteMap + { + private readonly Dictionary _map = new Dictionary(); + + public IISRewriteMap(string name) + { + if (string.IsNullOrEmpty(name)) + { + throw new ArgumentException(nameof(name)); + } + Name = name; + } + + public string Name { get; } + + public string this[string key] + { + get + { + string value; + return _map.TryGetValue(key, out value) ? value : null; + } + set + { + if (string.IsNullOrEmpty(key)) + { + throw new ArgumentException(nameof(key)); + } + if (string.IsNullOrEmpty(value)) + { + throw new ArgumentException(nameof(value)); + } + _map[key] = value; + } + } + } +} \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/IISRewriteMapCollection.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/IISRewriteMapCollection.cs new file mode 100644 index 0000000000..4f8a900623 --- /dev/null +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/IISRewriteMapCollection.cs @@ -0,0 +1,42 @@ +// 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.Collections; +using System.Collections.Generic; + +namespace Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite +{ + public class IISRewriteMapCollection : IEnumerable + { + private readonly Dictionary _rewriteMaps = new Dictionary(); + + public void Add(IISRewriteMap rewriteMap) + { + if (rewriteMap != null) + { + _rewriteMaps[rewriteMap.Name] = rewriteMap; + } + } + + public int Count => _rewriteMaps.Count; + + public IISRewriteMap this[string key] + { + get + { + IISRewriteMap value; + return _rewriteMaps.TryGetValue(key, out value) ? value : null; + } + } + + IEnumerator IEnumerable.GetEnumerator() + { + return _rewriteMaps.Values.GetEnumerator(); + } + + public IEnumerator GetEnumerator() + { + return _rewriteMaps.Values.GetEnumerator(); + } + } +} \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/InputParser.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/InputParser.cs index c99790cb43..d73e561d50 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/InputParser.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/InputParser.cs @@ -12,6 +12,16 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite private const char Colon = ':'; private const char OpenBrace = '{'; private const char CloseBrace = '}'; + private readonly IISRewriteMapCollection _rewriteMaps; + + public InputParser() + { + } + + public InputParser(IISRewriteMapCollection rewriteMaps) + { + _rewriteMaps = rewriteMaps; + } /// /// Creates a pattern, which is a template to create a new test string to @@ -31,7 +41,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite return ParseString(context, global); } - private static Pattern ParseString(ParserContext context, bool global) + private Pattern ParseString(ParserContext context, bool global) { var results = new List(); while (context.Next()) @@ -60,7 +70,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite return new Pattern(results); } - private static void ParseParameter(ParserContext context, IList results, bool global) + private void ParseParameter(ParserContext context, IList results, bool global) { context.Mark(); // Four main cases: @@ -128,6 +138,13 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite return; } default: + var rewriteMap = _rewriteMaps?[parameter]; + if (rewriteMap != null) + { + var pattern = ParseString(context, global); + results.Add(new RewriteMapSegment(rewriteMap, pattern)); + return; + } throw new FormatException(Resources.FormatError_InputParserUnrecognizedParameter(parameter, context.Index)); } } diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/RewriteMapParser.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/RewriteMapParser.cs new file mode 100644 index 0000000000..4e9b21d800 --- /dev/null +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/RewriteMapParser.cs @@ -0,0 +1,39 @@ +// 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; +using System.Linq; +using System.Xml.Linq; + +namespace Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite +{ + public static class RewriteMapParser + { + public static IISRewriteMapCollection Parse(XElement xmlRoot) + { + if (xmlRoot == null) + { + throw new ArgumentNullException(nameof(xmlRoot)); + } + + var mapsElement = xmlRoot.Descendants(RewriteTags.RewriteMaps).SingleOrDefault(); + if (mapsElement == null) + { + return null; + } + + var rewriteMaps = new IISRewriteMapCollection(); + foreach (var mapElement in mapsElement.Elements(RewriteTags.RewriteMap)) + { + var map = new IISRewriteMap(mapElement.Attribute(RewriteTags.Name)?.Value); + foreach (var addElement in mapElement.Elements(RewriteTags.Add)) + { + map[addElement.Attribute(RewriteTags.Key).Value.ToLowerInvariant()] = addElement.Attribute(RewriteTags.Value).Value; + } + rewriteMaps.Add(map); + } + + return rewriteMaps; + } + } +} \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/RewriteTags.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/RewriteTags.cs index 9b62b26511..42a8e5aa83 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/RewriteTags.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/RewriteTags.cs @@ -13,6 +13,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite public const string GlobalRules = "globalRules"; public const string IgnoreCase = "ignoreCase"; public const string Input = "input"; + public const string Key = "key"; public const string LogicalGrouping = "logicalGrouping"; public const string LogRewrittenUrl = "logRewrittenUrl"; public const string Match = "match"; @@ -22,13 +23,16 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite public const string Negate = "negate"; public const string Pattern = "pattern"; public const string PatternSyntax = "patternSyntax"; - public const string Rewrite = "rewrite"; public const string RedirectType = "redirectType"; + public const string Rewrite = "rewrite"; + public const string RewriteMap = "rewriteMap"; + public const string RewriteMaps = "rewriteMaps"; public const string Rule = "rule"; public const string Rules = "rules"; public const string StopProcessing = "stopProcessing"; public const string TrackAllCaptures = "trackAllCaptures"; public const string Type = "type"; public const string Url = "url"; + public const string Value = "value"; } } diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/UrlRewriteFileParser.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/UrlRewriteFileParser.cs index e4d8296c7c..cb96c8b03a 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/UrlRewriteFileParser.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/UrlRewriteFileParser.cs @@ -12,21 +12,28 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite { public class UrlRewriteFileParser { - private readonly InputParser _inputParser = new InputParser(); + private InputParser _inputParser; + /// + /// Parse an IIS rewrite section into a list of s. + /// + /// The reader containing the rewrite XML public IList Parse(TextReader reader) { var xmlDoc = XDocument.Load(reader, LoadOptions.SetLineInfo); var xmlRoot = xmlDoc.Descendants(RewriteTags.Rewrite).FirstOrDefault(); - if (xmlRoot != null) + if (xmlRoot == null) { - var result = new List(); - ParseRules(xmlRoot.Descendants(RewriteTags.GlobalRules).FirstOrDefault(), result, global: true); - ParseRules(xmlRoot.Descendants(RewriteTags.Rules).FirstOrDefault(), result, global: false); - return result; + return null; } - return null; + + _inputParser = new InputParser(RewriteMapParser.Parse(xmlRoot)); + + var result = new List(); + ParseRules(xmlRoot.Descendants(RewriteTags.GlobalRules).FirstOrDefault(), result, global: true); + ParseRules(xmlRoot.Descendants(RewriteTags.Rules).FirstOrDefault(), result, global: false); + return result; } private void ParseRules(XElement rules, IList result, bool global) diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/RewriteMapSegment.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/RewriteMapSegment.cs new file mode 100644 index 0000000000..3dd50c9fec --- /dev/null +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/RewriteMapSegment.cs @@ -0,0 +1,25 @@ +// 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 Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite; + +namespace Microsoft.AspNetCore.Rewrite.Internal.PatternSegments +{ + public class RewriteMapSegment : PatternSegment + { + private readonly IISRewriteMap _rewriteMap; + private readonly Pattern _pattern; + + public RewriteMapSegment(IISRewriteMap rewriteMap, Pattern pattern) + { + _rewriteMap = rewriteMap; + _pattern = pattern; + } + + public override string Evaluate(RewriteContext context, BackReferenceCollection ruleBackReferences, BackReferenceCollection conditionBackReferences) + { + var key = _pattern.Evaluate(context, ruleBackReferences, conditionBackReferences).ToLowerInvariant(); + return _rewriteMap[key]; + } + } +} \ No newline at end of file diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/InputParserTests.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/InputParserTests.cs index ea3d4819d0..d636f152e8 100644 --- a/test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/InputParserTests.cs +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/InputParserTests.cs @@ -2,10 +2,13 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; +using System.Linq; using System.Text.RegularExpressions; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Rewrite.Internal; using Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite; +using Microsoft.AspNetCore.Rewrite.Internal.PatternSegments; +using Microsoft.Extensions.Logging.Testing; using Xunit; namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite @@ -88,11 +91,48 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite Assert.Throws(() => new InputParser().ParseInputString(testString, global: false)); } + [Fact] + public void Should_throw_FormatException_if_no_rewrite_maps_are_defined() + { + Assert.Throws(() => new InputParser(null).ParseInputString("{apiMap:{R:1}}", global: false)); + } + + [Fact] + public void Should_throw_FormatException_if_rewrite_map_not_found() + { + const string definedMapName = "testMap"; + const string undefinedMapName = "apiMap"; + var map = new IISRewriteMap(definedMapName); + var maps = new IISRewriteMapCollection { map }; + Assert.Throws(() => new InputParser(maps).ParseInputString($"{{{undefinedMapName}:{{R:1}}}}", global: false)); + } + + [Fact] + public void Should_parse_RewriteMapSegment_and_successfully_evaluate_result() + { + const string expectedMapName = "apiMap"; + const string expectedKey = "api.test.com"; + const string expectedValue = "test.com/api"; + var map = new IISRewriteMap(expectedMapName); + map[expectedKey] = expectedValue; + var maps = new IISRewriteMapCollection { map }; + + var inputString = $"{{{expectedMapName}:{{R:1}}}}"; + var pattern = new InputParser(maps).ParseInputString(inputString, global: false); + Assert.Equal(1, pattern.PatternSegments.Count); + + var segment = pattern.PatternSegments.Single(); + var rewriteMapSegment = segment as RewriteMapSegment; + Assert.NotNull(rewriteMapSegment); + + var result = rewriteMapSegment.Evaluate(CreateTestRewriteContext(), CreateRewriteMapRuleMatch(expectedKey).BackReferences, CreateRewriteMapConditionMatch(inputString).BackReferences); + Assert.Equal(expectedValue, result); + } + private RewriteContext CreateTestRewriteContext() { - var context = new DefaultHttpContext(); - return new RewriteContext { HttpContext = context, StaticFileProvider = null }; + return new RewriteContext { HttpContext = context, StaticFileProvider = null, Logger = new NullLogger() }; } private BackReferenceCollection CreateTestRuleBackReferences() @@ -106,5 +146,17 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite var match = Regex.Match("foo/bar/baz", "(.*)/(.*)/(.*)"); return new BackReferenceCollection(match.Groups); } + + private MatchResults CreateRewriteMapRuleMatch(string input) + { + var match = Regex.Match(input, "([^/]*)/?(.*)"); + return new MatchResults { BackReferences = new BackReferenceCollection(match.Groups), Success = match.Success }; + } + + private MatchResults CreateRewriteMapConditionMatch(string input) + { + var match = Regex.Match(input, "(.+)"); + return new MatchResults { BackReferences = new BackReferenceCollection(match.Groups), Success = match.Success }; + } } } diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/MiddleWareTests.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/MiddleWareTests.cs index a720a58b65..ed5d95ffe8 100644 --- a/test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/MiddleWareTests.cs +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/MiddleWareTests.cs @@ -8,6 +8,7 @@ using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http.Extensions; +using Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite; using Microsoft.AspNetCore.TestHost; using Microsoft.Net.Http.Headers; using Xunit; @@ -480,5 +481,40 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite Assert.Equal("http://www.test.com/foo/bar", response); } + + [Theory] + [InlineData("http://fetch.environment.local/dev/path", "http://1.1.1.1/path")] + [InlineData("http://fetch.environment.local/qa/path", "http://fetch.environment.local/qa/path")] + public async Task Invoke_ReverseProxyToAnotherSiteUsingXmlConfiguredRewriteMap(string requestUri, string expectedRewrittenUri) + { + var options = new RewriteOptions().AddIISUrlRewrite(new StringReader(@" + + + + + + + + + + + + + + + + ")); + var builder = new WebHostBuilder() + .Configure(app => + { + app.UseRewriter(options); + app.Run(context => context.Response.WriteAsync(context.Request.GetEncodedUrl())); + }); + var server = new TestServer(builder); + + var response = await server.CreateClient().GetStringAsync(new Uri(requestUri)); + + Assert.Equal(expectedRewrittenUri, response); + } } } diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/RewriteMapParserTests.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/RewriteMapParserTests.cs new file mode 100644 index 0000000000..a917e675f7 --- /dev/null +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/RewriteMapParserTests.cs @@ -0,0 +1,43 @@ +// 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.IO; +using System.Linq; +using System.Xml.Linq; +using Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite; +using Xunit; + +namespace Microsoft.AspNetCore.Rewrite.Tests.IISUrlRewrite +{ + public class RewriteMapParserTests + { + [Fact] + public void Should_parse_rewrite_map() + { + // arrange + const string expectedMapName = "apiMap"; + const string expectedKey = "api.test.com"; + const string expectedValue = "test.com/api"; + var xml = $@" + + + + + + "; + + // act + var xmlDoc = XDocument.Load(new StringReader(xml), LoadOptions.SetLineInfo); + var xmlRoot = xmlDoc.Descendants(RewriteTags.Rewrite).FirstOrDefault(); + var actualMaps = RewriteMapParser.Parse(xmlRoot); + + // assert + Assert.Equal(1, actualMaps.Count); + + var actualMap = actualMaps[expectedMapName]; + Assert.NotNull(actualMap); + Assert.Equal(expectedMapName, actualMap.Name); + Assert.Equal(expectedValue, actualMap[expectedKey]); + } + } +} \ No newline at end of file From bed294c554f0958c774613bc3ba31aff8f810917 Mon Sep 17 00:00:00 2001 From: David Peden Date: Wed, 8 Feb 2017 12:22:55 -0600 Subject: [PATCH 169/307] Added support for custom responses (#200) --- BasicMiddleware.sln | 2 +- .../RewriteMiddlewareLoggingExtensions.cs | 11 + .../InvalidUrlRewriteFormatException.cs | 34 +++ .../Internal/IISUrlRewrite/RewriteTags.cs | 4 + .../IISUrlRewrite/UrlRewriteFileParser.cs | 127 +++++----- .../IISUrlRewrite/UrlRewriteRuleBuilder.cs | 28 +-- .../UrlActions/CustomResponseAction.cs | 45 ++++ .../{VoidAction.cs => NoneAction.cs} | 4 +- .../FormatExceptionHandlingTests.cs | 218 +----------------- ...dUrlRewriteFormatExceptionHandlingTests.cs | 218 ++++++++++++++++++ .../IISUrlRewrite/MiddleWareTests.cs | 27 +++ 11 files changed, 423 insertions(+), 295 deletions(-) create mode 100644 src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/InvalidUrlRewriteFormatException.cs create mode 100644 src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/CustomResponseAction.cs rename src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/{VoidAction.cs => NoneAction.cs} (87%) create mode 100644 test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/InvalidUrlRewriteFormatExceptionHandlingTests.cs diff --git a/BasicMiddleware.sln b/BasicMiddleware.sln index 91ffb2b952..2fbc9f4838 100644 --- a/BasicMiddleware.sln +++ b/BasicMiddleware.sln @@ -1,6 +1,6 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 15 -VisualStudioVersion = 15.0.26127.0 +VisualStudioVersion = 15.0.26127.3 MinimumVisualStudioVersion = 10.0.40219.1 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.HttpOverrides", "src\Microsoft.AspNetCore.HttpOverrides\Microsoft.AspNetCore.HttpOverrides.csproj", "{517308C3-B477-4B01-B461-CAB9C10B6928}" EndProject diff --git a/src/Microsoft.AspNetCore.Rewrite/Extensions/RewriteMiddlewareLoggingExtensions.cs b/src/Microsoft.AspNetCore.Rewrite/Extensions/RewriteMiddlewareLoggingExtensions.cs index eaa1b0e345..3ad1e699dd 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Extensions/RewriteMiddlewareLoggingExtensions.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Extensions/RewriteMiddlewareLoggingExtensions.cs @@ -19,6 +19,7 @@ namespace Microsoft.AspNetCore.Rewrite.Logging private static readonly Action _redirectSummary; private static readonly Action _rewriteSummary; private static readonly Action _abortedRequest; + private static readonly Action _customResponse; static RewriteMiddlewareLoggingExtensions() { @@ -76,6 +77,11 @@ namespace Microsoft.AspNetCore.Rewrite.Logging LogLevel.Debug, 11, "Request to {requestedUrl} was aborted"); + + _customResponse = LoggerMessage.Define( + LogLevel.Debug, + 12, + "Request to {requestedUrl} was ended"); } public static void RewriteMiddlewareRequestContinueResults(this ILogger logger, string currentUrl) @@ -132,5 +138,10 @@ namespace Microsoft.AspNetCore.Rewrite.Logging { _abortedRequest(logger, requestedUrl, null); } + + public static void CustomResponse(this ILogger logger, string requestedUrl) + { + _customResponse(logger, requestedUrl, null); + } } } diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/InvalidUrlRewriteFormatException.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/InvalidUrlRewriteFormatException.cs new file mode 100644 index 0000000000..8e2bac3937 --- /dev/null +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/InvalidUrlRewriteFormatException.cs @@ -0,0 +1,34 @@ +// 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; +using System.Xml; +using System.Xml.Linq; + +namespace Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite +{ + public class InvalidUrlRewriteFormatException : FormatException + { + public int LineNumber { get; } + public int LinePosition { get; } + + public InvalidUrlRewriteFormatException(XElement element, string message) + : base(FormatMessage(element, message)) + { + } + + public InvalidUrlRewriteFormatException(XElement element, string message, Exception innerException) + : base(FormatMessage(element, message), innerException) + { + var xmlLineInfo = (IXmlLineInfo)element; + LineNumber = xmlLineInfo.LineNumber; + LinePosition = xmlLineInfo.LinePosition; + } + + private static string FormatMessage(XElement element, string message) + { + var xmlLineInfo = (IXmlLineInfo)element; + return Resources.FormatError_UrlRewriteParseError(message, xmlLineInfo.LineNumber, xmlLineInfo.LinePosition); + } + } +} \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/RewriteTags.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/RewriteTags.cs index 42a8e5aa83..d6d482bdd4 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/RewriteTags.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/RewriteTags.cs @@ -29,6 +29,10 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite public const string RewriteMaps = "rewriteMaps"; public const string Rule = "rule"; public const string Rules = "rules"; + public const string StatusCode = "statusCode"; + public const string SubStatusCode = "subStatusCode"; + public const string StatusDescription = "statusDescription"; + public const string StatusReason = "statusReason"; public const string StopProcessing = "stopProcessing"; public const string TrackAllCaptures = "trackAllCaptures"; public const string Type = "type"; diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/UrlRewriteFileParser.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/UrlRewriteFileParser.cs index cb96c8b03a..0cf093b091 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/UrlRewriteFileParser.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/UrlRewriteFileParser.cs @@ -5,8 +5,8 @@ using System; using System.Collections.Generic; using System.IO; using System.Linq; -using System.Xml; using System.Xml.Linq; +using Microsoft.AspNetCore.Rewrite.Internal.UrlActions; namespace Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite { @@ -74,13 +74,13 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite var match = rule.Element(RewriteTags.Match); if (match == null) { - ThrowUrlFormatException(rule, "Cannot have rule without match"); + throw new InvalidUrlRewriteFormatException(rule, "Condition must have an associated match"); } var action = rule.Element(RewriteTags.Action); if (action == null) { - ThrowUrlFormatException(rule, "Rule does not have an associated action attribute"); + throw new InvalidUrlRewriteFormatException(rule, "Rule does not have an associated action attribute"); } ParseMatch(match, builder, patternSyntax); @@ -93,7 +93,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite var parsedInputString = match.Attribute(RewriteTags.Url)?.Value; if (parsedInputString == null) { - ThrowUrlFormatException(match, "Match must have Url Attribute"); + throw new InvalidUrlRewriteFormatException(match, "Match must have Url Attribute"); } var ignoreCase = ParseBool(match, RewriteTags.IgnoreCase, defaultValue: true); @@ -127,70 +127,77 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite if (parsedInputString == null) { - ThrowUrlFormatException(condition, "Conditions must have an input attribute"); + throw new InvalidUrlRewriteFormatException(condition, "Conditions must have an input attribute"); } var parsedPatternString = condition.Attribute(RewriteTags.Pattern)?.Value; - try - { - var input = _inputParser.ParseInputString(parsedInputString, global); - builder.AddUrlCondition(input, parsedPatternString, patternSyntax, matchType, ignoreCase, negate, trackAllCaptures); - } - catch (FormatException formatException) - { - ThrowUrlFormatException(condition, formatException.Message, formatException); - } + var input = _inputParser.ParseInputString(parsedInputString, global); + builder.AddUrlCondition(input, parsedPatternString, patternSyntax, matchType, ignoreCase, negate, trackAllCaptures); } private void ParseUrlAction(XElement urlAction, UrlRewriteRuleBuilder builder, bool stopProcessing, bool global) { var actionType = ParseEnum(urlAction, RewriteTags.Type, ActionType.None); - var redirectType = ParseEnum(urlAction, RewriteTags.RedirectType, RedirectType.Permanent); - var appendQuery = ParseBool(urlAction, RewriteTags.AppendQueryString, defaultValue: true); - - string url = string.Empty; - if (urlAction.Attribute(RewriteTags.Url) != null) + UrlAction action; + switch (actionType) { - url = urlAction.Attribute(RewriteTags.Url).Value; - if (string.IsNullOrEmpty(url)) - { - ThrowUrlFormatException(urlAction, "Url attribute cannot contain an empty string"); - } + case ActionType.None: + action = new NoneAction(stopProcessing ? RuleResult.SkipRemainingRules : RuleResult.ContinueRules); + break; + case ActionType.Rewrite: + case ActionType.Redirect: + var url = string.Empty; + if (urlAction.Attribute(RewriteTags.Url) != null) + { + url = urlAction.Attribute(RewriteTags.Url).Value; + if (string.IsNullOrEmpty(url)) + { + throw new InvalidUrlRewriteFormatException(urlAction, "Url attribute cannot contain an empty string"); + } + } + + var urlPattern = _inputParser.ParseInputString(url, global); + var appendQuery = ParseBool(urlAction, RewriteTags.AppendQueryString, defaultValue: true); + + if (actionType == ActionType.Rewrite) + { + action = new RewriteAction(stopProcessing ? RuleResult.SkipRemainingRules : RuleResult.ContinueRules, urlPattern, appendQuery); + } + else + { + var redirectType = ParseEnum(urlAction, RewriteTags.RedirectType, RedirectType.Permanent); + action = new RedirectAction((int)redirectType, urlPattern, appendQuery); + } + break; + case ActionType.AbortRequest: + action = new AbortAction(); + break; + case ActionType.CustomResponse: + int statusCode; + if (!int.TryParse(urlAction.Attribute(RewriteTags.StatusCode)?.Value, out statusCode)) + { + throw new InvalidUrlRewriteFormatException(urlAction, "A valid status code is required"); + } + + if (statusCode < 200 || statusCode > 999) + { + throw new NotSupportedException("Status codes must be between 200 and 999 (inclusive)"); + } + + if (!string.IsNullOrEmpty(urlAction.Attribute(RewriteTags.SubStatusCode)?.Value)) + { + throw new NotSupportedException("Substatus codes are not supported"); + } + + var statusReason = urlAction.Attribute(RewriteTags.StatusReason)?.Value; + var statusDescription = urlAction.Attribute(RewriteTags.StatusDescription)?.Value; + + action = new CustomResponseAction(statusCode) { StatusReason = statusReason, StatusDescription = statusDescription }; + break; + default: + throw new NotSupportedException($"The action type {actionType} wasn't recognized"); } - - try - { - var input = _inputParser.ParseInputString(url, global); - builder.AddUrlAction(input, actionType, appendQuery, stopProcessing, (int)redirectType); - } - catch (FormatException formatException) - { - ThrowUrlFormatException(urlAction, formatException.Message, formatException); - } - } - - private static void ThrowUrlFormatException(XElement element, string message) - { - var lineInfo = (IXmlLineInfo)element; - var line = lineInfo.LineNumber; - var col = lineInfo.LinePosition; - throw new FormatException(Resources.FormatError_UrlRewriteParseError(message, line, col)); - } - - private static void ThrowUrlFormatException(XElement element, string message, Exception ex) - { - var lineInfo = (IXmlLineInfo)element; - var line = lineInfo.LineNumber; - var col = lineInfo.LinePosition; - throw new FormatException(Resources.FormatError_UrlRewriteParseError(message, line, col), ex); - } - - private static void ThrowParameterFormatException(XElement element, string message) - { - var lineInfo = (IXmlLineInfo)element; - var line = lineInfo.LineNumber; - var col = lineInfo.LinePosition; - throw new FormatException(Resources.FormatError_UrlRewriteParseError(message, line, col)); + builder.AddUrlAction(action); } private bool ParseBool(XElement element, string rewriteTag, bool defaultValue) @@ -203,7 +210,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite } else if (!bool.TryParse(attribute.Value, out result)) { - ThrowParameterFormatException(element, $"The {rewriteTag} parameter '{attribute.Value}' was not recognized"); + throw new InvalidUrlRewriteFormatException(element, $"The {rewriteTag} parameter '{attribute.Value}' was not recognized"); } return result; } @@ -219,7 +226,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite } else if(!Enum.TryParse(attribute.Value, ignoreCase: true, result: out enumResult)) { - ThrowParameterFormatException(element, $"The {rewriteTag} parameter '{attribute.Value}' was not recognized"); + throw new InvalidUrlRewriteFormatException(element, $"The {rewriteTag} parameter '{attribute.Value}' was not recognized"); } return enumResult; } diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/UrlRewriteRuleBuilder.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/UrlRewriteRuleBuilder.cs index 26951d5f9c..8cf927e7b2 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/UrlRewriteRuleBuilder.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/UrlRewriteRuleBuilder.cs @@ -4,8 +4,6 @@ using System; using System.Collections.Generic; using System.Text.RegularExpressions; -using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Rewrite.Internal.UrlActions; using Microsoft.AspNetCore.Rewrite.Internal.UrlMatches; namespace Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite @@ -33,31 +31,13 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite return new IISUrlRewriteRule(Name, _initialMatch, _conditions, _action, _trackAllCaptures, global); } - public void AddUrlAction( - Pattern url, - ActionType actionType = ActionType.None, - bool appendQueryString = true, - bool stopProcessing = false, - int statusCode = StatusCodes.Status301MovedPermanently) + public void AddUrlAction(UrlAction action) { - switch (actionType) + if (action == null) { - case ActionType.None: - _action = new VoidAction(stopProcessing ? RuleResult.SkipRemainingRules : RuleResult.ContinueRules); - break; - case ActionType.Rewrite: - _action = new RewriteAction(stopProcessing ? RuleResult.SkipRemainingRules : RuleResult.ContinueRules, - url, appendQueryString); - break; - case ActionType.Redirect: - _action = new RedirectAction(statusCode, url, appendQueryString); - break; - case ActionType.AbortRequest: - _action = new AbortAction(); - break; - case ActionType.CustomResponse: - throw new NotImplementedException("Custom Responses are not implemented"); + throw new ArgumentNullException(nameof(action), "Rules must contain an action"); } + _action = action; } public void AddUrlMatch(string input, bool ignoreCase = true, bool negate = false, PatternSyntax patternSyntax = PatternSyntax.ECMAScript) diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/CustomResponseAction.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/CustomResponseAction.cs new file mode 100644 index 0000000000..b7cc36eeda --- /dev/null +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/CustomResponseAction.cs @@ -0,0 +1,45 @@ +// 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.Text; +using Microsoft.AspNetCore.Http.Extensions; +using Microsoft.AspNetCore.Http.Features; +using Microsoft.AspNetCore.Rewrite.Logging; + +namespace Microsoft.AspNetCore.Rewrite.Internal.UrlActions +{ + public class CustomResponseAction : UrlAction + { + public int StatusCode { get; } + public string StatusReason { get; set; } + public string StatusDescription { get; set; } + + public CustomResponseAction(int statusCode) + { + StatusCode = statusCode; + } + + public override void ApplyAction(RewriteContext context, BackReferenceCollection ruleBackReferences, BackReferenceCollection conditionBackReferences) + { + var response = context.HttpContext.Response; + response.StatusCode = StatusCode; + + if (!string.IsNullOrEmpty(StatusReason)) + { + context.HttpContext.Features.Get().ReasonPhrase = StatusReason; + } + + if (!string.IsNullOrEmpty(StatusDescription)) + { + var content = Encoding.UTF8.GetBytes(StatusDescription); + response.ContentLength = content.Length; + response.ContentType = "text/plain; charset=utf-8"; + response.Body.Write(content, 0, content.Length); + } + + context.Result = RuleResult.EndResponse; + + context.Logger?.CustomResponse(context.HttpContext.Request.GetEncodedUrl()); + } + } +} \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/VoidAction.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/NoneAction.cs similarity index 87% rename from src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/VoidAction.cs rename to src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/NoneAction.cs index 95a092a0f8..4ba171bb5e 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/VoidAction.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/NoneAction.cs @@ -3,11 +3,11 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlActions { - public class VoidAction : UrlAction + public class NoneAction : UrlAction { public RuleResult Result { get; } - public VoidAction(RuleResult result) + public NoneAction(RuleResult result) { Result = result; } diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/FormatExceptionHandlingTests.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/FormatExceptionHandlingTests.cs index c14f062e64..f6771dddfe 100644 --- a/test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/FormatExceptionHandlingTests.cs +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/FormatExceptionHandlingTests.cs @@ -12,60 +12,6 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite { [Theory] [InlineData( -@" - - - - -", - "Could not parse the UrlRewrite file. Message: 'Cannot have rule without match'. Line number '3': '10'.")] - [InlineData( -@" - - - - - - -", - "Could not parse the UrlRewrite file. Message: 'Missing close brace for parameter at string index: '1''. Line number '5': '14'.")] - [InlineData( -@" - - - - - - -", - "Could not parse the UrlRewrite file. Message: 'Match must have Url Attribute'. Line number '4': '14'.")] - [InlineData( -@" - - - - - - - - - -", - "Could not parse the UrlRewrite file. Message: 'Missing close brace for parameter at string index: '6''. Line number '6': '18'.")] - [InlineData( -@" - - - - - - - - - -", - "Could not parse the UrlRewrite file. Message: 'Conditions must have an input attribute'. Line number '6': '18'.")] - [InlineData( @" @@ -77,7 +23,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite ", - "Could not parse the UrlRewrite file. Message: 'Match does not have an associated pattern attribute in condition'. Line number '6': '18'.")] + "Match does not have an associated pattern attribute in condition")] [InlineData( @" @@ -90,174 +36,30 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite ", - "Could not parse the UrlRewrite file. Message: 'Match does not have an associated pattern attribute in condition'. Line number '6': '18'.")] + "Match does not have an associated pattern attribute in condition")] [InlineData( @" - - - -", - "Could not parse the UrlRewrite file. Message: 'Url attribute cannot contain an empty string'. Line number '5': '14'.")] - [InlineData( -@" - - - - - - -", - "Could not parse the UrlRewrite file. Message: 'The redirectType parameter 'foo' was not recognized'. Line number '5': '14'.")] - [InlineData( -@" - - - - - - -", - "Could not parse the UrlRewrite file. Message: 'The type parameter 'foo' was not recognized'. Line number '5': '14'.")] - [InlineData( -@" - - - - - - - - - -", - "Could not parse the UrlRewrite file. Message: 'The logicalGrouping parameter 'foo' was not recognized'. Line number '5': '14'.")] - [InlineData( -@" - - - - - - -", - "Could not parse the UrlRewrite file. Message: 'The patternSyntax parameter 'foo' was not recognized'. Line number '3': '10'.")] - [InlineData( -@" - - - - + - + ", - "Could not parse the UrlRewrite file. Message: 'The matchType parameter 'foo' was not recognized'. Line number '6': '18'.")] + "Missing close brace for parameter at string index: '6'")] [InlineData( @" - - - - - - + + + ", - "Could not parse the UrlRewrite file. Message: 'The enabled parameter 'foo' was not recognized'. Line number '3': '10'.")] - [InlineData( -@" - - - - - - - - - -", - "Could not parse the UrlRewrite file. Message: 'The stopProcessing parameter 'foo' was not recognized'. Line number '3': '10'.")] - [InlineData( -@" - - - - - - - - - -", - "Could not parse the UrlRewrite file. Message: 'The ignoreCase parameter 'foo' was not recognized'. Line number '4': '14'.")] - [InlineData( -@" - - - - - - - - - -", - "Could not parse the UrlRewrite file. Message: 'The ignoreCase parameter 'foo' was not recognized'. Line number '6': '18'.")] - [InlineData( -@" - - - - - - - - - -", - "Could not parse the UrlRewrite file. Message: 'The negate parameter 'foo' was not recognized'. Line number '4': '14'.")] - [InlineData( -@" - - - - - - - - - -", - "Could not parse the UrlRewrite file. Message: 'The negate parameter 'foo' was not recognized'. Line number '6': '18'.")] - [InlineData( -@" - - - - - - - - - -", - "Could not parse the UrlRewrite file. Message: 'The trackAllCaptures parameter 'foo' was not recognized'. Line number '5': '14'.")] - [InlineData( -@" - - - - - - -", - "Could not parse the UrlRewrite file. Message: 'The appendQueryString parameter 'foo' was not recognized'. Line number '5': '14'.")] + "Missing close brace for parameter at string index: '1'")] public void ThrowFormatExceptionWithCorrectMessage(string input, string expected) { // Arrange, Act, Assert @@ -265,4 +67,4 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite Assert.Equal(expected, ex.Message); } } -} +} \ No newline at end of file diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/InvalidUrlRewriteFormatExceptionHandlingTests.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/InvalidUrlRewriteFormatExceptionHandlingTests.cs new file mode 100644 index 0000000000..5c2e26fc5f --- /dev/null +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/InvalidUrlRewriteFormatExceptionHandlingTests.cs @@ -0,0 +1,218 @@ +// 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.IO; +using Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite; +using Xunit; + +namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite +{ + public class InvalidUrlRewriteFormatExceptionHandlingTests + { + [Theory] + [InlineData( + @" + + + + +", + "Could not parse the UrlRewrite file. Message: 'Condition must have an associated match'. Line number '3': '10'.")] + [InlineData( + @" + + + + + + +", + "Could not parse the UrlRewrite file. Message: 'Match must have Url Attribute'. Line number '4': '14'.")] + [InlineData( + @" + + + + + + + + + +", + "Could not parse the UrlRewrite file. Message: 'Conditions must have an input attribute'. Line number '6': '18'.")] + [InlineData( + @" + + + + + + +", + "Could not parse the UrlRewrite file. Message: 'Url attribute cannot contain an empty string'. Line number '5': '14'.")] + [InlineData( + @" + + + + + + +", + "Could not parse the UrlRewrite file. Message: 'The redirectType parameter 'foo' was not recognized'. Line number '5': '14'.")] + [InlineData( + @" + + + + + + +", + "Could not parse the UrlRewrite file. Message: 'The type parameter 'foo' was not recognized'. Line number '5': '14'.")] + [InlineData( + @" + + + + + + + + + +", + "Could not parse the UrlRewrite file. Message: 'The logicalGrouping parameter 'foo' was not recognized'. Line number '5': '14'.")] + [InlineData( + @" + + + + + + +", + "Could not parse the UrlRewrite file. Message: 'The patternSyntax parameter 'foo' was not recognized'. Line number '3': '10'.")] + [InlineData( + @" + + + + + + + + + +", + "Could not parse the UrlRewrite file. Message: 'The matchType parameter 'foo' was not recognized'. Line number '6': '18'.")] + [InlineData( + @" + + + + + + + + + +", + "Could not parse the UrlRewrite file. Message: 'The enabled parameter 'foo' was not recognized'. Line number '3': '10'.")] + [InlineData( + @" + + + + + + + + + +", + "Could not parse the UrlRewrite file. Message: 'The stopProcessing parameter 'foo' was not recognized'. Line number '3': '10'.")] + [InlineData( + @" + + + + + + + + + +", + "Could not parse the UrlRewrite file. Message: 'The ignoreCase parameter 'foo' was not recognized'. Line number '4': '14'.")] + [InlineData( + @" + + + + + + + + + +", + "Could not parse the UrlRewrite file. Message: 'The ignoreCase parameter 'foo' was not recognized'. Line number '6': '18'.")] + [InlineData( + @" + + + + + + + + + +", + "Could not parse the UrlRewrite file. Message: 'The negate parameter 'foo' was not recognized'. Line number '4': '14'.")] + [InlineData( + @" + + + + + + + + + +", + "Could not parse the UrlRewrite file. Message: 'The negate parameter 'foo' was not recognized'. Line number '6': '18'.")] + [InlineData( + @" + + + + + + + + + +", + "Could not parse the UrlRewrite file. Message: 'The trackAllCaptures parameter 'foo' was not recognized'. Line number '5': '14'.")] + [InlineData( + @" + + + + + + +", + "Could not parse the UrlRewrite file. Message: 'The appendQueryString parameter 'foo' was not recognized'. Line number '5': '14'.")] + public void ThrowInvalidUrlRewriteFormatExceptionWithCorrectMessage(string input, string expected) + { + // Arrange, Act, Assert + var ex = Assert.Throws(() => new UrlRewriteFileParser().Parse(new StringReader(input))); + Assert.Equal(expected, ex.Message); + } + } +} \ No newline at end of file diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/MiddleWareTests.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/MiddleWareTests.cs index ed5d95ffe8..006c88f4e7 100644 --- a/test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/MiddleWareTests.cs +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/MiddleWareTests.cs @@ -3,6 +3,7 @@ using System; using System.IO; +using System.Net; using System.Threading.Tasks; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; @@ -516,5 +517,31 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite Assert.Equal(expectedRewrittenUri, response); } + + [Fact] + public async Task Invoke_CustomResponse() + { + var options = new RewriteOptions().AddIISUrlRewrite(new StringReader(@" + + + + + + + ")); + var builder = new WebHostBuilder() + .Configure(app => + { + app.UseRewriter(options); + }); + var server = new TestServer(builder); + + var response = await server.CreateClient().GetAsync("article/10/hey"); + var content = await response.Content.ReadAsStringAsync(); + + Assert.Equal(HttpStatusCode.Forbidden, response.StatusCode); + Assert.Equal("reason", response.ReasonPhrase); + Assert.Equal("description", content); + } } } From b254f42d1964c2f0dd0e5375c4c8f141b8eeb2b1 Mon Sep 17 00:00:00 2001 From: Nate McMaster Date: Thu, 9 Feb 2017 17:29:48 -0800 Subject: [PATCH 170/307] Delete makefile.shade --- makefile.shade | 8 -------- 1 file changed, 8 deletions(-) delete mode 100644 makefile.shade diff --git a/makefile.shade b/makefile.shade deleted file mode 100644 index a612302092..0000000000 --- a/makefile.shade +++ /dev/null @@ -1,8 +0,0 @@ -use namespace="System.Net" - -var VERSION='0.1' -var FULL_VERSION='0.1' -var AUTHORS='Microsoft Open Technologies, Inc.' - -use-standard-lifecycle -k-standard-goals \ No newline at end of file From ae7d0b958252ce3735f8c7c72be2c43acaa8c140 Mon Sep 17 00:00:00 2001 From: David Peden Date: Mon, 13 Feb 2017 17:35:20 -0600 Subject: [PATCH 171/307] Make condition collection a first class citizen (#198) --- samples/RewriteSample/Startup.cs | 1 - .../ApacheModRewrite/ApacheModRewriteRule.cs | 4 +- .../{ => ApacheModRewrite}/Condition.cs | 4 +- .../ConditionEvaluator.cs | 10 +-- .../Internal/ApacheModRewrite/RuleBuilder.cs | 2 +- .../Internal/IISUrlRewrite/Condition.cs | 17 ++++ .../IISUrlRewrite/ConditionCollection.cs | 68 +++++++++++++++ .../IISUrlRewrite/ConditionEvaluator.cs | 49 +++++++++++ .../IISUrlRewrite/IISUrlRewriteRule.cs | 17 ++-- .../Internal/IISUrlRewrite/InputParser.cs | 31 ++++--- .../Internal/IISUrlRewrite/ServerVariables.cs | 8 +- .../IISUrlRewrite/UriMatchCondition.cs | 22 +++++ .../Internal/IISUrlRewrite/UriMatchPart.cs | 11 +++ .../IISUrlRewrite/UrlRewriteFileParser.cs | 85 ++++++++++++++----- .../IISUrlRewrite/UrlRewriteRuleBuilder.cs | 83 +++++------------- .../PatternSegments/GlobalRuleUrlSegment.cs | 15 ---- .../Internal/PatternSegments/UrlSegment.cs | 17 +++- .../IISUrlRewrite/FileParserTests.cs | 25 +++--- .../IISUrlRewrite/InputParserTests.cs | 18 ++-- .../IISUrlRewrite/MiddleWareTests.cs | 57 ++++++++++++- .../IISUrlRewrite/ServerVariableTests.cs | 34 ++++---- .../UrlRewriteApplicationTests.cs | 2 +- .../GlobalRuleUrlSegmentTests.cs | 47 ---------- .../PatternSegments/UrlSegmentTests.cs | 20 +++-- 24 files changed, 423 insertions(+), 224 deletions(-) rename src/Microsoft.AspNetCore.Rewrite/Internal/{ => ApacheModRewrite}/Condition.cs (90%) rename src/Microsoft.AspNetCore.Rewrite/Internal/{ => ApacheModRewrite}/ConditionEvaluator.cs (91%) create mode 100644 src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/Condition.cs create mode 100644 src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/ConditionCollection.cs create mode 100644 src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/ConditionEvaluator.cs create mode 100644 src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/UriMatchCondition.cs create mode 100644 src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/UriMatchPart.cs delete mode 100644 src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/GlobalRuleUrlSegment.cs delete mode 100644 test/Microsoft.AspNetCore.Rewrite.Tests/PatternSegments/GlobalRuleUrlSegmentTests.cs diff --git a/samples/RewriteSample/Startup.cs b/samples/RewriteSample/Startup.cs index 2d423eb6c6..c5b1ceb895 100644 --- a/samples/RewriteSample/Startup.cs +++ b/samples/RewriteSample/Startup.cs @@ -22,7 +22,6 @@ namespace RewriteSample .AddApacheModRewrite(env.ContentRootFileProvider, "Rewrite.txt"); app.UseRewriter(options); - app.Run(context => context.Response.WriteAsync($"Rewritten Url: {context.Request.Path + context.Request.QueryString}")); } diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/ApacheModRewrite/ApacheModRewriteRule.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/ApacheModRewrite/ApacheModRewriteRule.cs index a6d03b7fba..03b3a1ab6c 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/ApacheModRewrite/ApacheModRewriteRule.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/ApacheModRewrite/ApacheModRewriteRule.cs @@ -33,7 +33,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.ApacheModRewrite BackReferenceCollection condBackReferences = null; if (Conditions != null) { - var condResult = ConditionHelper.Evaluate(Conditions, context, initMatchRes.BackReferences); + var condResult = ConditionEvaluator.Evaluate(Conditions, context, initMatchRes.BackReferences); if (!condResult.Success) { context.Logger?.ModRewriteDidNotMatchRule(); @@ -51,4 +51,4 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.ApacheModRewrite } } } -} +} \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/Condition.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/ApacheModRewrite/Condition.cs similarity index 90% rename from src/Microsoft.AspNetCore.Rewrite/Internal/Condition.cs rename to src/Microsoft.AspNetCore.Rewrite/Internal/ApacheModRewrite/Condition.cs index 314e63a62c..01db0eb1bd 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/Condition.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/ApacheModRewrite/Condition.cs @@ -1,7 +1,7 @@ // 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. -namespace Microsoft.AspNetCore.Rewrite.Internal +namespace Microsoft.AspNetCore.Rewrite.Internal.ApacheModRewrite { public class Condition { @@ -15,4 +15,4 @@ namespace Microsoft.AspNetCore.Rewrite.Internal return Match.Evaluate(pattern, context); } } -} +} \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/ConditionEvaluator.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/ApacheModRewrite/ConditionEvaluator.cs similarity index 91% rename from src/Microsoft.AspNetCore.Rewrite/Internal/ConditionEvaluator.cs rename to src/Microsoft.AspNetCore.Rewrite/Internal/ApacheModRewrite/ConditionEvaluator.cs index 7a3c4365c1..0038c5bab2 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/ConditionEvaluator.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/ApacheModRewrite/ConditionEvaluator.cs @@ -3,9 +3,9 @@ using System.Collections.Generic; -namespace Microsoft.AspNetCore.Rewrite.Internal +namespace Microsoft.AspNetCore.Rewrite.Internal.ApacheModRewrite { - public static class ConditionHelper + public static class ConditionEvaluator { public static MatchResults Evaluate(IEnumerable conditions, RewriteContext context, BackReferenceCollection backReferences) { @@ -40,7 +40,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal return condResult; } - if (condResult.Success && trackAllCaptures && prevBackReferences!= null) + if (condResult.Success && trackAllCaptures && prevBackReferences != null) { prevBackReferences.Add(currentBackReferences); currentBackReferences = prevBackReferences; @@ -49,7 +49,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal prevBackReferences = currentBackReferences; } - return new MatchResults { BackReferences = prevBackReferences, Success = condResult.Success }; ; + return new MatchResults { BackReferences = prevBackReferences, Success = condResult.Success }; } } -} +} \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/ApacheModRewrite/RuleBuilder.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/ApacheModRewrite/RuleBuilder.cs index 638192b602..33473ddbf7 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/ApacheModRewrite/RuleBuilder.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/ApacheModRewrite/RuleBuilder.cs @@ -222,4 +222,4 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.ApacheModRewrite } } } -} +} \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/Condition.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/Condition.cs new file mode 100644 index 0000000000..18a24c1925 --- /dev/null +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/Condition.cs @@ -0,0 +1,17 @@ +// 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. + +namespace Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite +{ + public class Condition + { + public Pattern Input { get; set; } + public UrlMatch Match { get; set; } + + public MatchResults Evaluate(RewriteContext context, BackReferenceCollection ruleBackReferences, BackReferenceCollection conditionBackReferences) + { + var pattern = Input.Evaluate(context, ruleBackReferences, conditionBackReferences); + return Match.Evaluate(pattern, context); + } + } +} diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/ConditionCollection.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/ConditionCollection.cs new file mode 100644 index 0000000000..3aec4fe960 --- /dev/null +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/ConditionCollection.cs @@ -0,0 +1,68 @@ +// 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; +using System.Collections; +using System.Collections.Generic; + +namespace Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite +{ + public class ConditionCollection : IEnumerable + { + private readonly List _conditions = new List(); + + public LogicalGrouping Grouping { get; } + public bool TrackAllCaptures { get; } + + public ConditionCollection() + :this(LogicalGrouping.MatchAll, trackAllCaptures: false) + { + } + + public ConditionCollection(LogicalGrouping grouping, bool trackAllCaptures) + { + Grouping = grouping; + TrackAllCaptures = trackAllCaptures; + } + + public int Count => _conditions.Count; + + public Condition this[int index] + { + get + { + if (index < _conditions.Count) + { + return _conditions[index]; + } + throw new IndexOutOfRangeException($"Cannot access condition at index {index}. Only {_conditions.Count} conditions were captured."); + } + } + + public void Add(Condition condition) + { + if (condition != null) + { + _conditions.Add(condition); + } + } + + public void AddConditions(IEnumerable conditions) + { + if (conditions != null) + { + _conditions.AddRange(conditions); + } + } + + IEnumerator IEnumerable.GetEnumerator() + { + return _conditions.GetEnumerator(); + } + + public IEnumerator GetEnumerator() + { + return _conditions.GetEnumerator(); + } + } +} \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/ConditionEvaluator.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/ConditionEvaluator.cs new file mode 100644 index 0000000000..2d50739e78 --- /dev/null +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/ConditionEvaluator.cs @@ -0,0 +1,49 @@ +// 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. + +namespace Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite +{ + public static class ConditionEvaluator + { + public static MatchResults Evaluate(ConditionCollection conditions, RewriteContext context, BackReferenceCollection backReferences) + { + BackReferenceCollection prevBackReferences = null; + MatchResults condResult = null; + var orSucceeded = false; + foreach (var condition in conditions) + { + if (orSucceeded && conditions.Grouping == LogicalGrouping.MatchAny) + { + continue; + } + + if (orSucceeded) + { + orSucceeded = false; + continue; + } + + condResult = condition.Evaluate(context, backReferences, prevBackReferences); + var currentBackReferences = condResult.BackReferences; + if (conditions.Grouping == LogicalGrouping.MatchAny) + { + orSucceeded = condResult.Success; + } + else if (!condResult.Success) + { + return condResult; + } + + if (condResult.Success && conditions.TrackAllCaptures && prevBackReferences!= null) + { + prevBackReferences.Add(currentBackReferences); + currentBackReferences = prevBackReferences; + } + + prevBackReferences = currentBackReferences; + } + + return new MatchResults { BackReferences = prevBackReferences, Success = condResult.Success }; + } + } +} \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/IISUrlRewriteRule.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/IISUrlRewriteRule.cs index 86a9faf1c6..678486d592 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/IISUrlRewriteRule.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/IISUrlRewriteRule.cs @@ -1,7 +1,6 @@ // 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.Collections.Generic; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Rewrite.Logging; @@ -11,32 +10,28 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite { public string Name { get; } public UrlMatch InitialMatch { get; } - public IList Conditions { get; } + public ConditionCollection Conditions { get; } public UrlAction Action { get; } - public bool TrackAllCaptures { get; } public bool Global { get; } public IISUrlRewriteRule(string name, UrlMatch initialMatch, - IList conditions, - UrlAction action, - bool trackAllCaptures) - : this(name, initialMatch, conditions, action, trackAllCaptures, false) + ConditionCollection conditions, + UrlAction action) + : this(name, initialMatch, conditions, action, false) { } public IISUrlRewriteRule(string name, UrlMatch initialMatch, - IList conditions, + ConditionCollection conditions, UrlAction action, - bool trackAllCaptures, bool global) { Name = name; InitialMatch = initialMatch; Conditions = conditions; Action = action; - TrackAllCaptures = trackAllCaptures; Global = global; } @@ -64,7 +59,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite MatchResults condResult = null; if (Conditions != null) { - condResult = ConditionHelper.Evaluate(Conditions, context, initMatchResults.BackReferences, TrackAllCaptures); + condResult = ConditionEvaluator.Evaluate(Conditions, context, initMatchResults.BackReferences); if (!condResult.Success) { context.Logger?.UrlRewriteDidNotMatchRule(Name); diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/InputParser.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/InputParser.cs index d73e561d50..7dc3f8d638 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/InputParser.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/InputParser.cs @@ -28,9 +28,20 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite /// compare to the condition. Can contain server variables, back references, etc. /// /// - /// /// A new , containing a list of - public Pattern ParseInputString(string testString, bool global) + public Pattern ParseInputString(string testString) + { + return ParseInputString(testString, UriMatchPart.Path); + } + + /// + /// Creates a pattern, which is a template to create a new test string to + /// compare to the condition. Can contain server variables, back references, etc. + /// + /// + /// When testString evaluates to a URL segment, specify which part of the URI to evaluate. + /// A new , containing a list of + public Pattern ParseInputString(string testString, UriMatchPart uriMatchPart) { if (testString == null) { @@ -38,10 +49,10 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite } var context = new ParserContext(testString); - return ParseString(context, global); + return ParseString(context, uriMatchPart); } - private Pattern ParseString(ParserContext context, bool global) + private Pattern ParseString(ParserContext context, UriMatchPart uriMatchPart) { var results = new List(); while (context.Next()) @@ -54,7 +65,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite // missing { throw new FormatException(Resources.FormatError_InputParserMissingCloseBrace(context.Index)); } - ParseParameter(context, results, global); + ParseParameter(context, results, uriMatchPart); } else if (context.Current == CloseBrace) { @@ -70,7 +81,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite return new Pattern(results); } - private void ParseParameter(ParserContext context, IList results, bool global) + private void ParseParameter(ParserContext context, IList results, UriMatchPart uriMatchPart) { context.Mark(); // Four main cases: @@ -86,7 +97,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite { // This is just a server variable, so we do a lookup and verify the server variable exists. parameter = context.Capture(); - results.Add(ServerVariables.FindServerVariable(parameter, context, global)); + results.Add(ServerVariables.FindServerVariable(parameter, context, uriMatchPart)); return; } else if (context.Current == Colon) @@ -98,7 +109,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite { case "ToLower": { - var pattern = ParseString(context, global); + var pattern = ParseString(context, uriMatchPart); results.Add(new ToLowerSegment(pattern)); // at this point, we expect our context to be on the ending closing brace, @@ -116,7 +127,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite } case "UrlEncode": { - var pattern = ParseString(context, global); + var pattern = ParseString(context, uriMatchPart); results.Add(new UrlEncodeSegment(pattern)); if (context.Current != CloseBrace) @@ -141,7 +152,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite var rewriteMap = _rewriteMaps?[parameter]; if (rewriteMap != null) { - var pattern = ParseString(context, global); + var pattern = ParseString(context, uriMatchPart); results.Add(new RewriteMapSegment(rewriteMap, pattern)); return; } diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/ServerVariables.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/ServerVariables.cs index 54df27a19e..6bfdc59156 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/ServerVariables.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/ServerVariables.cs @@ -14,10 +14,10 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite /// /// The server variable /// The parser context which is utilized when an exception is thrown - /// Indicates if the rule being parsed is a global rule + /// Indicates whether the full URI or the path should be evaluated for URL segments /// Thrown when the server variable is unknown /// The matching - public static PatternSegment FindServerVariable(string serverVariable, ParserContext context, bool global) + public static PatternSegment FindServerVariable(string serverVariable, ParserContext context, UriMatchPart uriMatchPart) { switch (serverVariable) { @@ -43,7 +43,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite case "HTTP_CONNECTION": return new HeaderSegment(HeaderNames.Connection); case "HTTP_URL": - return global ? (PatternSegment)new GlobalRuleUrlSegment() : (PatternSegment)new UrlSegment(); + return new UrlSegment(uriMatchPart); case "HTTPS": return new IsHttpsUrlSegment(); case "LOCAL_ADDR": @@ -61,7 +61,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite case "REQUEST_FILENAME": return new RequestFileNameSegment(); case "REQUEST_URI": - return global ? (PatternSegment)new GlobalRuleUrlSegment() : (PatternSegment)new UrlSegment(); + return new UrlSegment(uriMatchPart); default: throw new FormatException(Resources.FormatError_InputParserUnrecognizedParameter(serverVariable, context.Index)); } diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/UriMatchCondition.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/UriMatchCondition.cs new file mode 100644 index 0000000000..9f39d46670 --- /dev/null +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/UriMatchCondition.cs @@ -0,0 +1,22 @@ +// 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; +using System.Text.RegularExpressions; +using Microsoft.AspNetCore.Rewrite.Internal.UrlMatches; + +namespace Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite +{ + public class UriMatchCondition : Condition + { + public UriMatchCondition(InputParser inputParser, string input, string pattern, UriMatchPart uriMatchPart, bool ignoreCase, bool negate) + { + var regex = new Regex( + pattern, + ignoreCase ? RegexOptions.CultureInvariant | RegexOptions.Compiled | RegexOptions.IgnoreCase : RegexOptions.CultureInvariant | RegexOptions.Compiled, + TimeSpan.FromMilliseconds(1)); + Input = inputParser.ParseInputString(input, uriMatchPart); + Match = new RegexMatch(regex, negate); + } + } +} \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/UriMatchPart.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/UriMatchPart.cs new file mode 100644 index 0000000000..25da940689 --- /dev/null +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/UriMatchPart.cs @@ -0,0 +1,11 @@ +// 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. + +namespace Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite +{ + public enum UriMatchPart + { + Full, + Path + } +} \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/UrlRewriteFileParser.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/UrlRewriteFileParser.cs index 0cf093b091..2a5b0f24a9 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/UrlRewriteFileParser.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/UrlRewriteFileParser.cs @@ -7,6 +7,7 @@ using System.IO; using System.Linq; using System.Xml.Linq; using Microsoft.AspNetCore.Rewrite.Internal.UrlActions; +using Microsoft.AspNetCore.Rewrite.Internal.UrlMatches; namespace Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite { @@ -45,17 +46,17 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite foreach (var rule in rules.Elements(RewriteTags.Rule)) { - var builder = new UrlRewriteRuleBuilder(); - ParseRuleAttributes(rule, builder, global); + var builder = new UrlRewriteRuleBuilder { Global = global }; + ParseRuleAttributes(rule, builder); if (builder.Enabled) { - result.Add(builder.Build(global)); + result.Add(builder.Build()); } } } - private void ParseRuleAttributes(XElement rule, UrlRewriteRuleBuilder builder, bool global) + private void ParseRuleAttributes(XElement rule, UrlRewriteRuleBuilder builder) { builder.Name = rule.Attribute(RewriteTags.Name)?.Value; @@ -84,8 +85,8 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite } ParseMatch(match, builder, patternSyntax); - ParseConditions(rule.Element(RewriteTags.Conditions), builder, patternSyntax, global); - ParseUrlAction(action, builder, stopProcessing, global); + ParseConditions(rule.Element(RewriteTags.Conditions), builder, patternSyntax); + ParseUrlAction(action, builder, stopProcessing); } private void ParseMatch(XElement match, UrlRewriteRuleBuilder builder, PatternSyntax patternSyntax) @@ -101,7 +102,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite builder.AddUrlMatch(parsedInputString, ignoreCase, negate, patternSyntax); } - private void ParseConditions(XElement conditions, UrlRewriteRuleBuilder builder, PatternSyntax patternSyntax, bool global) + private void ParseConditions(XElement conditions, UrlRewriteRuleBuilder builder, PatternSyntax patternSyntax) { if (conditions == null) { @@ -110,32 +111,76 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite var grouping = ParseEnum(conditions, RewriteTags.LogicalGrouping, LogicalGrouping.MatchAll); var trackAllCaptures = ParseBool(conditions, RewriteTags.TrackAllCaptures, defaultValue: false); - builder.AddUrlConditions(grouping, trackAllCaptures); + builder.ConfigureConditionBehavior(grouping, trackAllCaptures); foreach (var cond in conditions.Elements(RewriteTags.Add)) { - ParseCondition(cond, builder, patternSyntax, trackAllCaptures, global); + ParseCondition(cond, builder, patternSyntax); } } - private void ParseCondition(XElement condition, UrlRewriteRuleBuilder builder, PatternSyntax patternSyntax, bool trackAllCaptures, bool global) + private void ParseCondition(XElement conditionElement, UrlRewriteRuleBuilder builder, PatternSyntax patternSyntax) { - var ignoreCase = ParseBool(condition, RewriteTags.IgnoreCase, defaultValue: true); - var negate = ParseBool(condition, RewriteTags.Negate, defaultValue: false); - var matchType = ParseEnum(condition, RewriteTags.MatchType, MatchType.Pattern); - var parsedInputString = condition.Attribute(RewriteTags.Input)?.Value; + var ignoreCase = ParseBool(conditionElement, RewriteTags.IgnoreCase, defaultValue: true); + var negate = ParseBool(conditionElement, RewriteTags.Negate, defaultValue: false); + var matchType = ParseEnum(conditionElement, RewriteTags.MatchType, MatchType.Pattern); + var parsedInputString = conditionElement.Attribute(RewriteTags.Input)?.Value; if (parsedInputString == null) { - throw new InvalidUrlRewriteFormatException(condition, "Conditions must have an input attribute"); + throw new InvalidUrlRewriteFormatException(conditionElement, "Conditions must have an input attribute"); } - var parsedPatternString = condition.Attribute(RewriteTags.Pattern)?.Value; - var input = _inputParser.ParseInputString(parsedInputString, global); - builder.AddUrlCondition(input, parsedPatternString, patternSyntax, matchType, ignoreCase, negate, trackAllCaptures); + var parsedPatternString = conditionElement.Attribute(RewriteTags.Pattern)?.Value; + Condition condition; + + switch (patternSyntax) + { + case PatternSyntax.ECMAScript: + { + switch (matchType) + { + case MatchType.Pattern: + { + if (string.IsNullOrEmpty(parsedPatternString)) + { + throw new FormatException("Match does not have an associated pattern attribute in condition"); + } + condition = new UriMatchCondition(_inputParser, parsedInputString, parsedPatternString, builder.UriMatchPart, ignoreCase, negate); + break; + } + case MatchType.IsDirectory: + { + condition = new Condition { Input = _inputParser.ParseInputString(parsedInputString, builder.UriMatchPart), Match = new IsDirectoryMatch(negate) }; + break; + } + case MatchType.IsFile: + { + condition = new Condition { Input = _inputParser.ParseInputString(parsedInputString, builder.UriMatchPart), Match = new IsFileMatch(negate) }; + break; + } + default: + throw new FormatException("Unrecognized matchType"); + } + break; + } + case PatternSyntax.Wildcard: + throw new NotSupportedException("Wildcard syntax is not supported"); + case PatternSyntax.ExactMatch: + if (string.IsNullOrEmpty(parsedPatternString)) + { + throw new FormatException("Match does not have an associated pattern attribute in condition"); + } + condition = new Condition { Input = _inputParser.ParseInputString(parsedInputString, builder.UriMatchPart), Match = new ExactMatch(ignoreCase, parsedPatternString, negate) }; + break; + default: + throw new FormatException("Unrecognized pattern syntax"); + } + + builder.AddUrlCondition(condition); } - private void ParseUrlAction(XElement urlAction, UrlRewriteRuleBuilder builder, bool stopProcessing, bool global) + private void ParseUrlAction(XElement urlAction, UrlRewriteRuleBuilder builder, bool stopProcessing) { var actionType = ParseEnum(urlAction, RewriteTags.Type, ActionType.None); UrlAction action; @@ -156,7 +201,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite } } - var urlPattern = _inputParser.ParseInputString(url, global); + var urlPattern = _inputParser.ParseInputString(url, builder.UriMatchPart); var appendQuery = ParseBool(urlAction, RewriteTags.AppendQueryString, defaultValue: true); if (actionType == ActionType.Rewrite) diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/UrlRewriteRuleBuilder.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/UrlRewriteRuleBuilder.cs index 8cf927e7b2..ea855fb4a4 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/UrlRewriteRuleBuilder.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/UrlRewriteRuleBuilder.cs @@ -14,21 +14,21 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite public string Name { get; set; } public bool Enabled { get; set; } + public bool Global { get; set; } + public UriMatchPart UriMatchPart => Global ? UriMatchPart.Full : UriMatchPart.Path; private UrlMatch _initialMatch; - private IList _conditions; + private ConditionCollection _conditions; private UrlAction _action; - private bool _matchAny; - private bool _trackAllCaptures; - public IISUrlRewriteRule Build(bool global) + public IISUrlRewriteRule Build() { if (_initialMatch == null || _action == null) { throw new InvalidOperationException("Cannot create UrlRewriteRule without action and match"); } - return new IISUrlRewriteRule(Name, _initialMatch, _conditions, _action, _trackAllCaptures, global); + return new IISUrlRewriteRule(Name, _initialMatch, _conditions, _action, Global); } public void AddUrlAction(UrlAction action) @@ -66,70 +66,31 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite } } - public void AddUrlCondition(Pattern input, string pattern, PatternSyntax patternSyntax, MatchType matchType, bool ignoreCase, bool negate, bool trackAllCaptures) + public void ConfigureConditionBehavior(LogicalGrouping logicalGrouping, bool trackAllCaptures) + { + _conditions = new ConditionCollection(logicalGrouping, trackAllCaptures); + } + + public void AddUrlCondition(Condition condition) { - // If there are no conditions specified if (_conditions == null) { - AddUrlConditions(LogicalGrouping.MatchAll, trackAllCaptures); + throw new InvalidOperationException($"You must first configure condition behavior by calling {nameof(ConfigureConditionBehavior)}"); } - - switch (patternSyntax) + if (condition == null) { - case PatternSyntax.ECMAScript: - { - switch (matchType) - { - case MatchType.Pattern: - { - if (string.IsNullOrEmpty(pattern)) - { - throw new FormatException("Match does not have an associated pattern attribute in condition"); - } - - var regex = new Regex( - pattern, - ignoreCase ? RegexOptions.CultureInvariant | RegexOptions.Compiled | RegexOptions.IgnoreCase : - RegexOptions.CultureInvariant | RegexOptions.Compiled, - RegexTimeout); - - _conditions.Add(new Condition { Input = input, Match = new RegexMatch(regex, negate), OrNext = _matchAny }); - break; - } - case MatchType.IsDirectory: - { - _conditions.Add(new Condition { Input = input, Match = new IsDirectoryMatch(negate), OrNext = _matchAny }); - break; - } - case MatchType.IsFile: - { - _conditions.Add(new Condition { Input = input, Match = new IsFileMatch(negate), OrNext = _matchAny }); - break; - } - default: - throw new FormatException("Unrecognized matchType"); - } - break; - } - case PatternSyntax.Wildcard: - throw new NotSupportedException("Wildcard syntax is not supported"); - case PatternSyntax.ExactMatch: - if (pattern == null) - { - throw new FormatException("Match does not have an associated pattern attribute in condition"); - } - _conditions.Add(new Condition { Input = input, Match = new ExactMatch(ignoreCase, pattern, negate), OrNext = _matchAny }); - break; - default: - throw new FormatException("Unrecognized pattern syntax"); + throw new ArgumentNullException(nameof(condition)); } + _conditions.Add(condition); } - public void AddUrlConditions(LogicalGrouping logicalGrouping, bool trackAllCaptures) + public void AddUrlConditions(IEnumerable conditions) { - _conditions = new List(); - _matchAny = logicalGrouping == LogicalGrouping.MatchAny; - _trackAllCaptures = trackAllCaptures; + if (_conditions == null) + { + throw new InvalidOperationException($"You must first configure condition behavior by calling {nameof(ConfigureConditionBehavior)}"); + } + _conditions.AddConditions(conditions); } } -} +} \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/GlobalRuleUrlSegment.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/GlobalRuleUrlSegment.cs deleted file mode 100644 index 1a83837b98..0000000000 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/GlobalRuleUrlSegment.cs +++ /dev/null @@ -1,15 +0,0 @@ -// 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 Microsoft.AspNetCore.Http.Extensions; - -namespace Microsoft.AspNetCore.Rewrite.Internal.PatternSegments -{ - public class GlobalRuleUrlSegment : PatternSegment - { - public override string Evaluate(RewriteContext context, BackReferenceCollection ruleBackReferences, BackReferenceCollection conditionBackReferences) - { - return context.HttpContext.Request.GetEncodedUrl(); - } - } -} \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/UrlSegment.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/UrlSegment.cs index d655268c03..431d5cd5fb 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/UrlSegment.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/UrlSegment.cs @@ -1,13 +1,28 @@ // 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 Microsoft.AspNetCore.Http.Extensions; +using Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite; + namespace Microsoft.AspNetCore.Rewrite.Internal.PatternSegments { public class UrlSegment : PatternSegment { + private readonly UriMatchPart _uriMatchPart; + + public UrlSegment() + : this(UriMatchPart.Path) + { + } + + public UrlSegment(UriMatchPart uriMatchPart) + { + _uriMatchPart = uriMatchPart; + } + public override string Evaluate(RewriteContext context, BackReferenceCollection ruleBackReferences, BackReferenceCollection conditionBackReferences) { - return context.HttpContext.Request.Path; + return _uriMatchPart == UriMatchPart.Full ? context.HttpContext.Request.GetEncodedUrl() : (string)context.HttpContext.Request.Path; } } } \ No newline at end of file diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/FileParserTests.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/FileParserTests.cs index edc93076a4..18f1a246d0 100644 --- a/test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/FileParserTests.cs +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/FileParserTests.cs @@ -5,7 +5,6 @@ using System.Collections.Generic; using System.IO; using System.Text.RegularExpressions; using Microsoft.AspNetCore.Rewrite.Internal; -using Microsoft.AspNetCore.Rewrite.Internal.ApacheModRewrite; using Microsoft.AspNetCore.Rewrite.Internal.UrlActions; using Microsoft.AspNetCore.Rewrite.Internal.UrlMatches; using Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite; @@ -29,7 +28,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite "; var expected = new List(); - expected.Add(CreateTestRule(new List(), + expected.Add(CreateTestRule(new ConditionCollection(), url: "^article/([0-9]+)/([_0-9a-z-]+)", name: "Rewrite to article.aspx", actionType: ActionType.Rewrite, @@ -58,10 +57,10 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite "; - var condList = new List(); + var condList = new ConditionCollection(); condList.Add(new Condition { - Input = new InputParser().ParseInputString("{HTTPS}", global: false), + Input = new InputParser().ParseInputString("{HTTPS}"), Match = new RegexMatch(new Regex("^OFF$"), false) }); @@ -102,10 +101,10 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite "; - var condList = new List(); + var condList = new ConditionCollection(); condList.Add(new Condition { - Input = new InputParser().ParseInputString("{HTTPS}", global: false), + Input = new InputParser().ParseInputString("{HTTPS}"), Match = new RegexMatch(new Regex("^OFF$"), false) }); @@ -160,9 +159,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite } // Creates a rule with appropriate default values of the url rewrite rule. - private IISUrlRewriteRule CreateTestRule(List conditions, - LogicalGrouping condGrouping = LogicalGrouping.MatchAll, - bool condTracking = false, + private IISUrlRewriteRule CreateTestRule(ConditionCollection conditions, string name = "", bool enabled = true, PatternSyntax patternSyntax = PatternSyntax.ECMAScript, @@ -174,11 +171,17 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite string pattern = "", bool appendQueryString = false, bool rewrittenUrl = false, + bool global = false, + UriMatchPart uriMatchPart = UriMatchPart.Path, RedirectType redirectType = RedirectType.Permanent ) { - return new IISUrlRewriteRule(name, new RegexMatch(new Regex("^OFF$"), false), conditions, - new RewriteAction(RuleResult.ContinueRules, new InputParser().ParseInputString(url, global: false), queryStringAppend: false), trackAllCaptures: false); + return new IISUrlRewriteRule( + name, + new RegexMatch(new Regex("^OFF$"), negate), + conditions, + new RewriteAction(RuleResult.ContinueRules, new InputParser().ParseInputString(url, uriMatchPart), queryStringAppend: false), + global); } // TODO make rules comparable? diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/InputParserTests.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/InputParserTests.cs index d636f152e8..62246a8948 100644 --- a/test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/InputParserTests.cs +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/InputParserTests.cs @@ -19,7 +19,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite public void InputParser_ParseLiteralString() { var testString = "hello/hey/what"; - var result = new InputParser().ParseInputString(testString, global: false); + var result = new InputParser().ParseInputString(testString, UriMatchPart.Path); Assert.Equal(1, result.PatternSegments.Count); } @@ -31,7 +31,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite [InlineData("foo/", 1)] public void InputParser_ParseStringWithBackReference(string testString, int expected) { - var result = new InputParser().ParseInputString(testString, global: false); + var result = new InputParser().ParseInputString(testString, UriMatchPart.Path); Assert.Equal(expected, result.PatternSegments.Count); } @@ -47,7 +47,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite [InlineData("hey/{R:1}/{C:1}", "hey/foo/foo")] public void EvaluateBackReferenceRule(string testString, string expected) { - var middle = new InputParser().ParseInputString(testString, global: false); + var middle = new InputParser().ParseInputString(testString, UriMatchPart.Path); var result = middle.Evaluate(CreateTestRewriteContext(), CreateTestRuleBackReferences(), CreateTestCondBackReferences()); Assert.Equal(expected, result); } @@ -60,7 +60,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite [InlineData("hey/ToLower:/what", "hey/ToLower:/what")] public void EvaluatToLowerRule(string testString, string expected) { - var middle = new InputParser().ParseInputString(testString, global: false); + var middle = new InputParser().ParseInputString(testString, UriMatchPart.Path); var result = middle.Evaluate(CreateTestRewriteContext(), CreateTestRuleBackReferences(), CreateTestCondBackReferences()); Assert.Equal(expected, result); } @@ -69,7 +69,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite [InlineData("hey/{UrlEncode:}", "hey/%3Chey%3E")] public void EvaluatUriEncodeRule(string testString, string expected) { - var middle = new InputParser().ParseInputString(testString, global: false); + var middle = new InputParser().ParseInputString(testString, UriMatchPart.Path); var result = middle.Evaluate(CreateTestRewriteContext(), CreateTestRuleBackReferences(), CreateTestCondBackReferences()); Assert.Equal(expected, result); } @@ -88,13 +88,13 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite [InlineData("{HTTPS")] public void FormatExceptionsOnBadSyntax(string testString) { - Assert.Throws(() => new InputParser().ParseInputString(testString, global: false)); + Assert.Throws(() => new InputParser().ParseInputString(testString, UriMatchPart.Path)); } [Fact] public void Should_throw_FormatException_if_no_rewrite_maps_are_defined() { - Assert.Throws(() => new InputParser(null).ParseInputString("{apiMap:{R:1}}", global: false)); + Assert.Throws(() => new InputParser(null).ParseInputString("{apiMap:{R:1}}", UriMatchPart.Path)); } [Fact] @@ -104,7 +104,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite const string undefinedMapName = "apiMap"; var map = new IISRewriteMap(definedMapName); var maps = new IISRewriteMapCollection { map }; - Assert.Throws(() => new InputParser(maps).ParseInputString($"{{{undefinedMapName}:{{R:1}}}}", global: false)); + Assert.Throws(() => new InputParser(maps).ParseInputString($"{{{undefinedMapName}:{{R:1}}}}", UriMatchPart.Path)); } [Fact] @@ -118,7 +118,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite var maps = new IISRewriteMapCollection { map }; var inputString = $"{{{expectedMapName}:{{R:1}}}}"; - var pattern = new InputParser(maps).ParseInputString(inputString, global: false); + var pattern = new InputParser(maps).ParseInputString(inputString, UriMatchPart.Path); Assert.Equal(1, pattern.PatternSegments.Count); var segment = pattern.PatternSegments.Single(); diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/MiddleWareTests.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/MiddleWareTests.cs index 006c88f4e7..542cd88060 100644 --- a/test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/MiddleWareTests.cs +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/MiddleWareTests.cs @@ -2,14 +2,19 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; +using System.Collections.Generic; using System.IO; using System.Net; +using System.Text.RegularExpressions; using System.Threading.Tasks; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http.Extensions; +using Microsoft.AspNetCore.Rewrite.Internal; using Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite; +using Microsoft.AspNetCore.Rewrite.Internal.UrlActions; +using Microsoft.AspNetCore.Rewrite.Internal.UrlMatches; using Microsoft.AspNetCore.TestHost; using Microsoft.Net.Http.Headers; using Xunit; @@ -456,8 +461,9 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite } [Fact] - public async Task Invoke_GlobalRuleConditionMatchesAgainstFullUri() + public async Task Invoke_GlobalRuleConditionMatchesAgainstFullUri_ParsedRule() { + // arrange var xml = @" @@ -478,8 +484,10 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite }); var server = new TestServer(builder); + // act var response = await server.CreateClient().GetStringAsync($"http://localhost/{Guid.NewGuid()}/foo/bar"); + // assert Assert.Equal("http://www.test.com/foo/bar", response); } @@ -543,5 +551,52 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite Assert.Equal("reason", response.ReasonPhrase); Assert.Equal("description", content); } + + [Theory] + [InlineData(@"^http://localhost(/.*)", "http://localhost/foo/bar", UriMatchPart.Path)] + [InlineData(@"^http://localhost(/.*)", "http://www.test.com/foo/bar", UriMatchPart.Full)] + public async Task Invoke_GlobalRuleConditionMatchesAgainstFullUri_CodedRule(string conditionInputPattern, string expectedResult, UriMatchPart uriMatchPart) + { + // arrange + var inputParser = new InputParser(); + + var ruleBuilder = new UrlRewriteRuleBuilder + { + Name = "test", + Global = false + }; + ruleBuilder.AddUrlMatch(".*"); + + var condition = new UriMatchCondition( + inputParser, + "{REQUEST_URI}", + conditionInputPattern, + uriMatchPart, + ignoreCase: true, + negate: false); + ruleBuilder.ConfigureConditionBehavior(LogicalGrouping.MatchAll, trackAllCaptures: true); + ruleBuilder.AddUrlCondition(condition); + + var action = new RewriteAction( + RuleResult.SkipRemainingRules, + inputParser.ParseInputString(@"http://www.test.com{C:1}", uriMatchPart), + queryStringAppend: false); + ruleBuilder.AddUrlAction(action); + + var options = new RewriteOptions().Add(ruleBuilder.Build()); + var builder = new WebHostBuilder() + .Configure(app => + { + app.UseRewriter(options); + app.Run(context => context.Response.WriteAsync(context.Request.GetEncodedUrl())); + }); + var server = new TestServer(builder); + + // act + var response = await server.CreateClient().GetStringAsync("http://localhost/foo/bar"); + + // assert + Assert.Equal(expectedResult, response); + } } } diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/ServerVariableTests.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/ServerVariableTests.cs index c8716e144f..b9acf1442c 100644 --- a/test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/ServerVariableTests.cs +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/ServerVariableTests.cs @@ -13,25 +13,25 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite public class ServerVariableTests { [Theory] - [InlineData("CONTENT_LENGTH", "10", false)] - [InlineData("CONTENT_TYPE", "json", false)] - [InlineData("HTTP_ACCEPT", "accept", false)] - [InlineData("HTTP_COOKIE", "cookie", false)] - [InlineData("HTTP_HOST", "example.com", false)] - [InlineData("HTTP_REFERER", "referer", false)] - [InlineData("HTTP_USER_AGENT", "useragent", false)] - [InlineData("HTTP_CONNECTION", "connection", false)] - [InlineData("HTTP_URL", "/foo", false)] - [InlineData("HTTP_URL", "http://example.com/foo?bar=1", true)] - [InlineData("QUERY_STRING", "bar=1", false)] - [InlineData("REQUEST_FILENAME", "/foo", false)] - [InlineData("REQUEST_URI", "/foo", false)] - [InlineData("REQUEST_URI", "http://example.com/foo?bar=1", true)] - public void CheckServerVariableParsingAndApplication(string variable, string expected, bool global) + [InlineData("CONTENT_LENGTH", "10", UriMatchPart.Path)] + [InlineData("CONTENT_TYPE", "json", UriMatchPart.Path)] + [InlineData("HTTP_ACCEPT", "accept", UriMatchPart.Path)] + [InlineData("HTTP_COOKIE", "cookie", UriMatchPart.Path)] + [InlineData("HTTP_HOST", "example.com", UriMatchPart.Path)] + [InlineData("HTTP_REFERER", "referer", UriMatchPart.Path)] + [InlineData("HTTP_USER_AGENT", "useragent", UriMatchPart.Path)] + [InlineData("HTTP_CONNECTION", "connection", UriMatchPart.Path)] + [InlineData("HTTP_URL", "/foo", UriMatchPart.Path)] + [InlineData("HTTP_URL", "http://example.com/foo?bar=1", UriMatchPart.Full)] + [InlineData("QUERY_STRING", "bar=1", UriMatchPart.Path)] + [InlineData("REQUEST_FILENAME", "/foo", UriMatchPart.Path)] + [InlineData("REQUEST_URI", "/foo", UriMatchPart.Path)] + [InlineData("REQUEST_URI", "http://example.com/foo?bar=1", UriMatchPart.Full)] + public void CheckServerVariableParsingAndApplication(string variable, string expected, UriMatchPart uriMatchPart) { // Arrange and Act var testParserContext = new ParserContext("test"); - var serverVar = ServerVariables.FindServerVariable(variable, testParserContext, global); + var serverVar = ServerVariables.FindServerVariable(variable, testParserContext, uriMatchPart); var lookup = serverVar.Evaluate(CreateTestHttpContext(), CreateTestRuleMatch().BackReferences, CreateTestCondMatch().BackReferences); // Assert Assert.Equal(expected, lookup); @@ -72,7 +72,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite var context = new DefaultHttpContext(); var rewriteContext = new RewriteContext { HttpContext = context }; var testParserContext = new ParserContext("test"); - var serverVar = ServerVariables.FindServerVariable("QUERY_STRING", testParserContext, global: false); + var serverVar = ServerVariables.FindServerVariable("QUERY_STRING", testParserContext, UriMatchPart.Path); var lookup = serverVar.Evaluate(rewriteContext, CreateTestRuleMatch().BackReferences, CreateTestCondMatch().BackReferences); Assert.Equal(string.Empty, lookup); diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/UrlRewriteApplicationTests.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/UrlRewriteApplicationTests.cs index 592492a17f..ff9e9f8a59 100644 --- a/test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/UrlRewriteApplicationTests.cs +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/UrlRewriteApplicationTests.cs @@ -67,7 +67,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite var rules = new UrlRewriteFileParser().Parse(xml); Assert.Equal(rules.Count, 1); - Assert.True(rules[0].TrackAllCaptures); + Assert.True(rules[0].Conditions.TrackAllCaptures); var context = new RewriteContext { HttpContext = new DefaultHttpContext() }; rules.FirstOrDefault().ApplyRule(context); Assert.Equal(RuleResult.ContinueRules, context.Result); diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/PatternSegments/GlobalRuleUrlSegmentTests.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/PatternSegments/GlobalRuleUrlSegmentTests.cs deleted file mode 100644 index ca41021c75..0000000000 --- a/test/Microsoft.AspNetCore.Rewrite.Tests/PatternSegments/GlobalRuleUrlSegmentTests.cs +++ /dev/null @@ -1,47 +0,0 @@ -// 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 Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Rewrite.Internal.PatternSegments; -using Xunit; - -namespace Microsoft.AspNetCore.Rewrite.Tests.PatternSegments -{ - public class GlobalRuleUrlSegmentTests - { - [Theory] - [InlineData("http", "localhost", 80, null, null, "http://localhost:80/")] - [InlineData("http", "localhost", 80, "/foo/bar", null, "http://localhost:80/foo/bar")] - [InlineData("http", "localhost", 80, "/foo bar", null, "http://localhost:80/foo%20bar")] - [InlineData("http", "localhost", 81, "/foo/bar", null, "http://localhost:81/foo/bar")] - [InlineData("http", "localhost", 80, null, "?foo=bar", "http://localhost:80/?foo=bar")] - [InlineData("https", "localhost", 443, "/foo/bar", null, "https://localhost:443/foo/bar")] - public void AssertSegmentIsCorrect(string scheme, string host, int port, string path, string queryString, string expectedResult) - { - // Arrange - var httpContext = new DefaultHttpContext(); - httpContext.Request.Scheme = scheme; - httpContext.Request.Host = new HostString(host, port); - - if (!string.IsNullOrEmpty(path)) - { - httpContext.Request.Path = new PathString(path); - } - - if (!string.IsNullOrEmpty(queryString)) - { - httpContext.Request.QueryString = new QueryString(queryString); - } - - var context = new RewriteContext { HttpContext = httpContext }; - context.HttpContext = httpContext; - - // Act - var segment = new GlobalRuleUrlSegment(); - var results = segment.Evaluate(context, null, null); - - // Assert - Assert.Equal(expectedResult, results); - } - } -} \ No newline at end of file diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/PatternSegments/UrlSegmentTests.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/PatternSegments/UrlSegmentTests.cs index ee53d56a42..e85c5662b4 100644 --- a/test/Microsoft.AspNetCore.Rewrite.Tests/PatternSegments/UrlSegmentTests.cs +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/PatternSegments/UrlSegmentTests.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite; using Microsoft.AspNetCore.Rewrite.Internal.PatternSegments; using Xunit; @@ -10,10 +11,19 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.PatternSegments public class UrlSegmentTests { [Theory] - [InlineData("http", "localhost", 80, "/foo/bar", "/foo/bar")] - [InlineData("http", "localhost", 80, "/foo:bar", "/foo:bar")] - [InlineData("http", "localhost", 80, "/foo bar", "/foo%20bar")] - public void AssertSegmentIsCorrect(string scheme, string host, int port, string path, string expectedResult) + [InlineData("http", "localhost", 80, null, UriMatchPart.Path, "")] + [InlineData("http", "localhost", 80, "", UriMatchPart.Path, "")] + [InlineData("http", "localhost", 80, "/foo/bar", UriMatchPart.Path, "/foo/bar")] + [InlineData("http", "localhost", 80, "/foo:bar", UriMatchPart.Path, "/foo:bar")] + [InlineData("http", "localhost", 80, "/foo bar", UriMatchPart.Path, "/foo%20bar")] + [InlineData("http", "localhost", 80, null, UriMatchPart.Full, "http://localhost:80/")] + [InlineData("http", "localhost", 80, "", UriMatchPart.Full, "http://localhost:80/")] + [InlineData("http", "localhost", 80, "/foo:bar", UriMatchPart.Full, "http://localhost:80/foo:bar")] + [InlineData("http", "localhost", 80, "/foo bar", UriMatchPart.Full, "http://localhost:80/foo%20bar")] + [InlineData("http", "localhost", 80, "/foo/bar", UriMatchPart.Full, "http://localhost:80/foo/bar")] + [InlineData("http", "localhost", 81, "/foo/bar", UriMatchPart.Full, "http://localhost:81/foo/bar")] + [InlineData("https", "localhost", 443, "/foo/bar", UriMatchPart.Full, "https://localhost:443/foo/bar")] + public void AssertSegmentIsCorrect(string scheme, string host, int port, string path, UriMatchPart uriMatchPart, string expectedResult) { // Arrange var httpContext = new DefaultHttpContext(); @@ -25,7 +35,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.PatternSegments context.HttpContext = httpContext; // Act - var segment = new UrlSegment(); + var segment = new UrlSegment(uriMatchPart); var results = segment.Evaluate(context, null, null); // Assert From f1231e81ec0bd1c3d49f7436ce904ed452c8b954 Mon Sep 17 00:00:00 2001 From: Doug Bunting Date: Tue, 14 Feb 2017 12:15:29 -0800 Subject: [PATCH 172/307] Bump test projects up to .NET 4.5.2 - aspnet/Testing#248 - xUnit no longer supports .NET 4.5.1 - build tests for desktop .NET only on Windows --- .../Microsoft.AspNetCore.Buffering.Tests.csproj | 3 ++- .../Microsoft.AspNetCore.HttpOverrides.Tests.csproj | 3 ++- .../BodyWrapperStreamTests.cs | 2 +- .../Microsoft.AspNetCore.ResponseCompression.Tests.csproj | 3 ++- .../ResponseCompressionMiddlewareTest.cs | 4 ++-- .../Microsoft.AspNetCore.Rewrite.Tests.csproj | 3 ++- 6 files changed, 11 insertions(+), 7 deletions(-) diff --git a/test/Microsoft.AspNetCore.Buffering.Tests/Microsoft.AspNetCore.Buffering.Tests.csproj b/test/Microsoft.AspNetCore.Buffering.Tests/Microsoft.AspNetCore.Buffering.Tests.csproj index 18713da3ed..d062668356 100644 --- a/test/Microsoft.AspNetCore.Buffering.Tests/Microsoft.AspNetCore.Buffering.Tests.csproj +++ b/test/Microsoft.AspNetCore.Buffering.Tests/Microsoft.AspNetCore.Buffering.Tests.csproj @@ -3,7 +3,8 @@ - netcoreapp1.1;net451 + netcoreapp1.1;net452 + netcoreapp1.1 diff --git a/test/Microsoft.AspNetCore.HttpOverrides.Tests/Microsoft.AspNetCore.HttpOverrides.Tests.csproj b/test/Microsoft.AspNetCore.HttpOverrides.Tests/Microsoft.AspNetCore.HttpOverrides.Tests.csproj index 98f046a40d..f77f81033a 100644 --- a/test/Microsoft.AspNetCore.HttpOverrides.Tests/Microsoft.AspNetCore.HttpOverrides.Tests.csproj +++ b/test/Microsoft.AspNetCore.HttpOverrides.Tests/Microsoft.AspNetCore.HttpOverrides.Tests.csproj @@ -3,7 +3,8 @@ - netcoreapp1.1;net451 + netcoreapp1.1;net452 + netcoreapp1.1 diff --git a/test/Microsoft.AspNetCore.ResponseCompression.Tests/BodyWrapperStreamTests.cs b/test/Microsoft.AspNetCore.ResponseCompression.Tests/BodyWrapperStreamTests.cs index f5aa703528..cb89f8f2d9 100644 --- a/test/Microsoft.AspNetCore.ResponseCompression.Tests/BodyWrapperStreamTests.cs +++ b/test/Microsoft.AspNetCore.ResponseCompression.Tests/BodyWrapperStreamTests.cs @@ -108,7 +108,7 @@ namespace Microsoft.AspNetCore.ResponseCompression.Tests Assert.Equal(File.ReadAllBytes(path), written); } -#if NET451 +#if NET452 [Theory] [InlineData(true)] [InlineData(false)] diff --git a/test/Microsoft.AspNetCore.ResponseCompression.Tests/Microsoft.AspNetCore.ResponseCompression.Tests.csproj b/test/Microsoft.AspNetCore.ResponseCompression.Tests/Microsoft.AspNetCore.ResponseCompression.Tests.csproj index dd2bbf56c9..1d0877be61 100644 --- a/test/Microsoft.AspNetCore.ResponseCompression.Tests/Microsoft.AspNetCore.ResponseCompression.Tests.csproj +++ b/test/Microsoft.AspNetCore.ResponseCompression.Tests/Microsoft.AspNetCore.ResponseCompression.Tests.csproj @@ -3,7 +3,8 @@ - netcoreapp1.1;net451 + netcoreapp1.1;net452 + netcoreapp1.1 diff --git a/test/Microsoft.AspNetCore.ResponseCompression.Tests/ResponseCompressionMiddlewareTest.cs b/test/Microsoft.AspNetCore.ResponseCompression.Tests/ResponseCompressionMiddlewareTest.cs index 8328716c89..0494896c11 100644 --- a/test/Microsoft.AspNetCore.ResponseCompression.Tests/ResponseCompressionMiddlewareTest.cs +++ b/test/Microsoft.AspNetCore.ResponseCompression.Tests/ResponseCompressionMiddlewareTest.cs @@ -505,7 +505,7 @@ namespace Microsoft.AspNetCore.ResponseCompression.Tests var response = await client.SendAsync(request, HttpCompletionOption.ResponseHeadersRead); -#if NET451 // Flush not supported, compression disabled +#if NET452 // Flush not supported, compression disabled Assert.NotNull(response.Headers.GetValues(HeaderNames.ContentMD5)); Assert.Empty(response.Content.Headers.ContentEncoding); #elif NETCOREAPP1_1 // Flush supported, compression enabled @@ -570,7 +570,7 @@ namespace Microsoft.AspNetCore.ResponseCompression.Tests var response = await client.SendAsync(request, HttpCompletionOption.ResponseHeadersRead); -#if NET451 // Flush not supported, compression disabled +#if NET452 // Flush not supported, compression disabled Assert.NotNull(response.Headers.GetValues(HeaderNames.ContentMD5)); Assert.Empty(response.Content.Headers.ContentEncoding); #elif NETCOREAPP1_1 // Flush supported, compression enabled diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/Microsoft.AspNetCore.Rewrite.Tests.csproj b/test/Microsoft.AspNetCore.Rewrite.Tests/Microsoft.AspNetCore.Rewrite.Tests.csproj index 7e008b87f0..ebf1c61363 100644 --- a/test/Microsoft.AspNetCore.Rewrite.Tests/Microsoft.AspNetCore.Rewrite.Tests.csproj +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/Microsoft.AspNetCore.Rewrite.Tests.csproj @@ -3,7 +3,8 @@ - netcoreapp1.1;net451 + netcoreapp1.1;net452 + netcoreapp1.1 From f1c0a1a441c5800e6a8de46fdf9de45ced80af8e Mon Sep 17 00:00:00 2001 From: Nate McMaster Date: Tue, 14 Feb 2017 16:03:53 -0800 Subject: [PATCH 173/307] Downgrade to stable packages --- build/common.props | 3 +-- build/dependencies.props | 6 ++++++ samples/HttpOverridesSample/HttpOverridesSample.csproj | 1 - .../ResponseBufferingSample/ResponseBufferingSample.csproj | 1 - .../ResponseCompressionSample.csproj | 1 - samples/RewriteSample/RewriteSample.csproj | 1 - 6 files changed, 7 insertions(+), 6 deletions(-) create mode 100644 build/dependencies.props diff --git a/build/common.props b/build/common.props index 6cc1dddc23..1722b8038b 100644 --- a/build/common.props +++ b/build/common.props @@ -1,4 +1,5 @@ + @@ -8,8 +9,6 @@ $(MSBuildThisFileDirectory)Key.snk true true - 1.2.0-* - 1.6.2-* $(VersionSuffix)-$(BuildNumber) diff --git a/build/dependencies.props b/build/dependencies.props new file mode 100644 index 0000000000..e704edaec0 --- /dev/null +++ b/build/dependencies.props @@ -0,0 +1,6 @@ + + + 1.6.1 + 4.3.0 + + diff --git a/samples/HttpOverridesSample/HttpOverridesSample.csproj b/samples/HttpOverridesSample/HttpOverridesSample.csproj index 00119f3640..c42b39140c 100644 --- a/samples/HttpOverridesSample/HttpOverridesSample.csproj +++ b/samples/HttpOverridesSample/HttpOverridesSample.csproj @@ -4,7 +4,6 @@ net451;netcoreapp1.1 win7-x64 Exe - 1.2.0-* diff --git a/samples/ResponseBufferingSample/ResponseBufferingSample.csproj b/samples/ResponseBufferingSample/ResponseBufferingSample.csproj index e7d85de3b0..ad46ed87fe 100644 --- a/samples/ResponseBufferingSample/ResponseBufferingSample.csproj +++ b/samples/ResponseBufferingSample/ResponseBufferingSample.csproj @@ -4,7 +4,6 @@ net451;netcoreapp1.1 win7-x64 Exe - 1.2.0-* diff --git a/samples/ResponseCompressionSample/ResponseCompressionSample.csproj b/samples/ResponseCompressionSample/ResponseCompressionSample.csproj index 9d24167bdc..a30cbd620c 100644 --- a/samples/ResponseCompressionSample/ResponseCompressionSample.csproj +++ b/samples/ResponseCompressionSample/ResponseCompressionSample.csproj @@ -4,7 +4,6 @@ net451;netcoreapp1.1 win7-x64 Exe - 1.2.0-* diff --git a/samples/RewriteSample/RewriteSample.csproj b/samples/RewriteSample/RewriteSample.csproj index 3fe834ccb1..45959c138d 100644 --- a/samples/RewriteSample/RewriteSample.csproj +++ b/samples/RewriteSample/RewriteSample.csproj @@ -5,7 +5,6 @@ win7-x64 true Exe - 1.2.0-* From ec8216b756a760511de67e94c80a5067a0a1de8c Mon Sep 17 00:00:00 2001 From: Nate McMaster Date: Wed, 1 Mar 2017 18:14:13 -0800 Subject: [PATCH 174/307] Change korebuild branch and fix argument forwarding in bootstrapper --- build.ps1 | 16 ++++++++-------- build.sh | 22 +++++++++++----------- 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/build.ps1 b/build.ps1 index 0605b59c01..5bf0e2c113 100644 --- a/build.ps1 +++ b/build.ps1 @@ -1,6 +1,6 @@ $ErrorActionPreference = "Stop" -function DownloadWithRetry([string] $url, [string] $downloadLocation, [int] $retries) +function DownloadWithRetry([string] $url, [string] $downloadLocation, [int] $retries) { while($true) { @@ -19,7 +19,7 @@ function DownloadWithRetry([string] $url, [string] $downloadLocation, [int] $ret Start-Sleep -Seconds 10 } - else + else { $exception = $_.Exception throw $exception @@ -33,7 +33,7 @@ cd $PSScriptRoot $repoFolder = $PSScriptRoot $env:REPO_FOLDER = $repoFolder -$koreBuildZip="https://github.com/aspnet/KoreBuild/archive/feature/msbuild.zip" +$koreBuildZip="https://github.com/aspnet/KoreBuild/archive/dev.zip" if ($env:KOREBUILD_ZIP) { $koreBuildZip=$env:KOREBUILD_ZIP @@ -43,18 +43,18 @@ $buildFolder = ".build" $buildFile="$buildFolder\KoreBuild.ps1" if (!(Test-Path $buildFolder)) { - Write-Host "Downloading KoreBuild from $koreBuildZip" - + Write-Host "Downloading KoreBuild from $koreBuildZip" + $tempFolder=$env:TEMP + "\KoreBuild-" + [guid]::NewGuid() New-Item -Path "$tempFolder" -Type directory | Out-Null $localZipFile="$tempFolder\korebuild.zip" - + DownloadWithRetry -url $koreBuildZip -downloadLocation $localZipFile -retries 6 Add-Type -AssemblyName System.IO.Compression.FileSystem [System.IO.Compression.ZipFile]::ExtractToDirectory($localZipFile, $tempFolder) - + New-Item -Path "$buildFolder" -Type directory | Out-Null copy-item "$tempFolder\**\build\*" $buildFolder -Recurse @@ -64,4 +64,4 @@ if (!(Test-Path $buildFolder)) { } } -&"$buildFile" $args \ No newline at end of file +&"$buildFile" @args diff --git a/build.sh b/build.sh index 07997d6c83..b0bcadb579 100755 --- a/build.sh +++ b/build.sh @@ -2,7 +2,7 @@ repoFolder="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" cd $repoFolder -koreBuildZip="https://github.com/aspnet/KoreBuild/archive/feature/msbuild.zip" +koreBuildZip="https://github.com/aspnet/KoreBuild/archive/dev.zip" if [ ! -z $KOREBUILD_ZIP ]; then koreBuildZip=$KOREBUILD_ZIP fi @@ -12,12 +12,12 @@ buildFile="$buildFolder/KoreBuild.sh" if test ! -d $buildFolder; then echo "Downloading KoreBuild from $koreBuildZip" - - tempFolder="/tmp/KoreBuild-$(uuidgen)" + + tempFolder="/tmp/KoreBuild-$(uuidgen)" mkdir $tempFolder - + localZipFile="$tempFolder/korebuild.zip" - + retries=6 until (wget -O $localZipFile $koreBuildZip 2>/dev/null || curl -o $localZipFile --location $koreBuildZip 2>/dev/null) do @@ -29,18 +29,18 @@ if test ! -d $buildFolder; then echo "Waiting 10 seconds before retrying. Retries left: $retries" sleep 10s done - + unzip -q -d $tempFolder $localZipFile - + mkdir $buildFolder cp -r $tempFolder/**/build/** $buildFolder - + chmod +x $buildFile - + # Cleanup if test -d $tempFolder; then - rm -rf $tempFolder + rm -rf $tempFolder fi fi -$buildFile -r $repoFolder "$@" \ No newline at end of file +$buildFile -r $repoFolder "$@" From 4743b057e0de21efc4066e0fb11fdda69ff949f1 Mon Sep 17 00:00:00 2001 From: Nate McMaster Date: Wed, 1 Mar 2017 18:25:52 -0800 Subject: [PATCH 175/307] Update AppVeyor and Travis settings --- .travis.yml | 2 +- appveyor.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index d7ee9c7df8..46e125d65b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -29,7 +29,7 @@ branches: before_install: - if test "$TRAVIS_OS_NAME" == "osx"; then brew update; brew install openssl; ln -s /usr/local/opt/openssl/lib/libcrypto.1.0.0.dylib /usr/local/lib/; ln -s /usr/local/opt/openssl/lib/libssl.1.0.0.dylib /usr/local/lib/; fi script: - - ./build.sh --quiet verify + - ./build.sh notifications: webhooks: secure: "Quayhq8pTWtpCfsC209l4o3ZG75VhEKjTOcuOPDYoQXII4rfmVbnGUoe6A6R3VTz7/O2YTPbX3+ooBrTJufwiJXJG74xZuE35jKnRm3HQREH9tCNUYwB4BO7jzoWz9wXDDfCPs47Tkjdf46Tq0jF27nXrZhNzm6ps3JCoP6/lA+8lEfWxIYifviwxJ392S34k5SyaVYeOIs+W95Iuvmd6+ZenVZNvPaGwHzTKqVhh/NYttbQ3oUq4n2fWaIrwGVi7MC6CtINoG/CtmUU3pef+StPOYMjWfMGcUjAkikWWEsCDnUSOpmNxKREKqXXbOBPDCcC9sNkzpYa0ksHRwGQv2jagVYaAicNfGc/gtWJ3JTCnODUea6oTsmdZT7hNW1ClzOEacXHv55TzImgAb1MFD9euSoXBIa9rRNYhx1oy3JYal2Ee0crPF1nFxQJ5mVT9pGEhpMqAwdNaZBwA5urVn6bl0ptPb8W6XVw5/qgPdBvmF67Xjw+k3TDQ3J4sWClGdX4ZsfgVFLSDGk9hqudPp10XlXkAscYtpKoZIEIK5rVa7RnvI44Bh1eQRqFpqKa2m1gVquJwUQg0L8CPakZDscas29dtXY4KqHrspOOtolhtOUaVpanQCGFWgPnWxIx9m+3eDRCLSjhvrZyZwemmvqXNqFhKUILdQLo1itANDo=" diff --git a/appveyor.yml b/appveyor.yml index 741873cbe5..4af9de6b8a 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -7,7 +7,7 @@ branches: - dev - /^(.*\/)?ci-.*$/ build_script: - - build.cmd verify + - ps: .\build.ps1 clone_depth: 1 test: off deploy: off From 5b4ed10bb4375032afe8c76a8f75918aa4c54cff Mon Sep 17 00:00:00 2001 From: Mikael Mengistu Date: Wed, 8 Mar 2017 14:43:35 -0800 Subject: [PATCH 176/307] Added AppVeyor Travis badges (#213) --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index b037519abc..02ff28aeb5 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,10 @@ ASP.NET Core Basic Middleware Components ======== +AppVeyor: [![AppVeyor](https://ci.appveyor.com/api/projects/status/02a73gv9gq02jw0j/branch/dev?svg=true)](https://ci.appveyor.com/project/aspnetci/basicmiddleware/branch/dev) + +Travis: [![Travis](https://travis-ci.org/aspnet/BasicMiddleware.svg?branch=dev)](https://travis-ci.org/aspnet/BasicMiddleware) + This repo hosts a collection of basic middleware components for ASP.NET Core. This includes Buffering, HTTP Overrides, and URL Rewriting. The Rewrite middleware can import rules from IIS's UrlRewrite and Apache's mod_rewrite. From 42df57ae46db9954068824d0e1c4641e182ddb7f Mon Sep 17 00:00:00 2001 From: David Fowler Date: Thu, 9 Mar 2017 11:21:35 -0800 Subject: [PATCH 177/307] Update .travis.yml (#214) --- .travis.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 46e125d65b..71c8ceff43 100644 --- a/.travis.yml +++ b/.travis.yml @@ -14,8 +14,7 @@ env: global: - DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true - DOTNET_CLI_TELEMETRY_OPTOUT: 1 -mono: - - 4.0.5 +mono: none os: - linux - osx From 42119e2276714921bcb2112aeaf590e223be29d3 Mon Sep 17 00:00:00 2001 From: Mikael Mengistu Date: Mon, 13 Mar 2017 16:33:48 -0700 Subject: [PATCH 178/307] Added Response Compression to README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 02ff28aeb5..1ce333f1b4 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ AppVeyor: [![AppVeyor](https://ci.appveyor.com/api/projects/status/02a73gv9gq02j Travis: [![Travis](https://travis-ci.org/aspnet/BasicMiddleware.svg?branch=dev)](https://travis-ci.org/aspnet/BasicMiddleware) -This repo hosts a collection of basic middleware components for ASP.NET Core. This includes Buffering, HTTP Overrides, and URL Rewriting. +This repo hosts a collection of basic middleware components for ASP.NET Core. This includes Buffering, HTTP Overrides, Response Compression, and URL Rewriting. The Rewrite middleware can import rules from IIS's UrlRewrite and Apache's mod_rewrite. This project is part of ASP.NET Core. You can find samples, documentation and getting started instructions for ASP.NET Core at the [Home](https://github.com/aspnet/home) repo. From cccfc0de2269f123946a86c998f11b356fd744c8 Mon Sep 17 00:00:00 2001 From: Ajay Bhargav Baaskaran Date: Tue, 14 Mar 2017 12:12:47 -0700 Subject: [PATCH 179/307] Using NullLogger types from Logging.Abstractions (#215) --- .../IISUrlRewrite/InputParserTests.cs | 4 ++-- .../Microsoft.AspNetCore.Rewrite.Tests.csproj | 1 - 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/InputParserTests.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/InputParserTests.cs index 62246a8948..ebc32becdc 100644 --- a/test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/InputParserTests.cs +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/InputParserTests.cs @@ -8,7 +8,7 @@ using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Rewrite.Internal; using Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite; using Microsoft.AspNetCore.Rewrite.Internal.PatternSegments; -using Microsoft.Extensions.Logging.Testing; +using Microsoft.Extensions.Logging.Abstractions; using Xunit; namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite @@ -132,7 +132,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite private RewriteContext CreateTestRewriteContext() { var context = new DefaultHttpContext(); - return new RewriteContext { HttpContext = context, StaticFileProvider = null, Logger = new NullLogger() }; + return new RewriteContext { HttpContext = context, StaticFileProvider = null, Logger = NullLogger.Instance }; } private BackReferenceCollection CreateTestRuleBackReferences() diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/Microsoft.AspNetCore.Rewrite.Tests.csproj b/test/Microsoft.AspNetCore.Rewrite.Tests/Microsoft.AspNetCore.Rewrite.Tests.csproj index ebf1c61363..3e5b6e7cf7 100644 --- a/test/Microsoft.AspNetCore.Rewrite.Tests/Microsoft.AspNetCore.Rewrite.Tests.csproj +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/Microsoft.AspNetCore.Rewrite.Tests.csproj @@ -13,7 +13,6 @@ - From f92b3022a71f9c540d5972be6d2c34183ec1e5b1 Mon Sep 17 00:00:00 2001 From: Nate McMaster Date: Tue, 14 Mar 2017 13:39:36 -0700 Subject: [PATCH 180/307] Update appveyor and travis settings --- .travis.yml | 1 - appveyor.yml | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 71c8ceff43..10713bf2e1 100644 --- a/.travis.yml +++ b/.travis.yml @@ -18,7 +18,6 @@ mono: none os: - linux - osx -osx_image: xcode7.3 branches: only: - master diff --git a/appveyor.yml b/appveyor.yml index 4af9de6b8a..1041615c68 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -11,4 +11,4 @@ build_script: clone_depth: 1 test: off deploy: off -os: Visual Studio 2015 +os: Visual Studio 2017 From 0e4442284daeb80dcea7b2a715abcdac90d3551a Mon Sep 17 00:00:00 2001 From: Nate McMaster Date: Wed, 15 Mar 2017 12:43:29 -0700 Subject: [PATCH 181/307] Unify dependency versions to one file and remove workarounds --- build/dependencies.props | 6 +++++- .../HttpOverridesSample.csproj | 9 ++++++--- .../ResponseBufferingSample.csproj | 9 ++++++--- .../ResponseCompressionSample.csproj | 11 +++++++---- samples/RewriteSample/RewriteSample.csproj | 12 +++++++----- .../Microsoft.AspNetCore.Buffering.csproj | 4 ++-- .../Microsoft.AspNetCore.HttpOverrides.csproj | 6 +++--- ...rosoft.AspNetCore.ResponseCompression.csproj | 4 ++-- .../Microsoft.AspNetCore.Rewrite.csproj | 14 +++++++------- .../Microsoft.AspNetCore.Buffering.Tests.csproj | 11 +++++++---- ...rosoft.AspNetCore.HttpOverrides.Tests.csproj | 13 ++++++++----- ....AspNetCore.ResponseCompression.Tests.csproj | 17 ++++++++++------- .../Microsoft.AspNetCore.Rewrite.Tests.csproj | 13 ++++++++----- 13 files changed, 78 insertions(+), 51 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index e704edaec0..c153f0e3f9 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -1,6 +1,10 @@ - 1.6.1 + 1.2.0-* 4.3.0 + 4.7.1 + 1.6.1 + 15.0.0 + 2.2.0 diff --git a/samples/HttpOverridesSample/HttpOverridesSample.csproj b/samples/HttpOverridesSample/HttpOverridesSample.csproj index c42b39140c..2cf83ecfad 100644 --- a/samples/HttpOverridesSample/HttpOverridesSample.csproj +++ b/samples/HttpOverridesSample/HttpOverridesSample.csproj @@ -1,14 +1,17 @@ + + net451;netcoreapp1.1 - win7-x64 - Exe - + + + + diff --git a/samples/ResponseBufferingSample/ResponseBufferingSample.csproj b/samples/ResponseBufferingSample/ResponseBufferingSample.csproj index ad46ed87fe..90bf35c252 100644 --- a/samples/ResponseBufferingSample/ResponseBufferingSample.csproj +++ b/samples/ResponseBufferingSample/ResponseBufferingSample.csproj @@ -1,14 +1,17 @@ + + net451;netcoreapp1.1 - win7-x64 - Exe - + + + + diff --git a/samples/ResponseCompressionSample/ResponseCompressionSample.csproj b/samples/ResponseCompressionSample/ResponseCompressionSample.csproj index a30cbd620c..7c668a7ced 100644 --- a/samples/ResponseCompressionSample/ResponseCompressionSample.csproj +++ b/samples/ResponseCompressionSample/ResponseCompressionSample.csproj @@ -1,9 +1,9 @@ + + net451;netcoreapp1.1 - win7-x64 - Exe @@ -12,8 +12,11 @@ - - + + + + + diff --git a/samples/RewriteSample/RewriteSample.csproj b/samples/RewriteSample/RewriteSample.csproj index 45959c138d..56e834d177 100644 --- a/samples/RewriteSample/RewriteSample.csproj +++ b/samples/RewriteSample/RewriteSample.csproj @@ -1,16 +1,18 @@ + + net451;netcoreapp1.1 - win7-x64 - true - Exe - - + + + + + diff --git a/src/Microsoft.AspNetCore.Buffering/Microsoft.AspNetCore.Buffering.csproj b/src/Microsoft.AspNetCore.Buffering/Microsoft.AspNetCore.Buffering.csproj index 40aff99c24..81bf91be82 100644 --- a/src/Microsoft.AspNetCore.Buffering/Microsoft.AspNetCore.Buffering.csproj +++ b/src/Microsoft.AspNetCore.Buffering/Microsoft.AspNetCore.Buffering.csproj @@ -12,8 +12,8 @@ - - + + diff --git a/src/Microsoft.AspNetCore.HttpOverrides/Microsoft.AspNetCore.HttpOverrides.csproj b/src/Microsoft.AspNetCore.HttpOverrides/Microsoft.AspNetCore.HttpOverrides.csproj index 8441e6b677..7d8b86ce59 100644 --- a/src/Microsoft.AspNetCore.HttpOverrides/Microsoft.AspNetCore.HttpOverrides.csproj +++ b/src/Microsoft.AspNetCore.HttpOverrides/Microsoft.AspNetCore.HttpOverrides.csproj @@ -14,9 +14,9 @@ - - - + + + diff --git a/src/Microsoft.AspNetCore.ResponseCompression/Microsoft.AspNetCore.ResponseCompression.csproj b/src/Microsoft.AspNetCore.ResponseCompression/Microsoft.AspNetCore.ResponseCompression.csproj index 4fa5ea9444..f542b01c5b 100644 --- a/src/Microsoft.AspNetCore.ResponseCompression/Microsoft.AspNetCore.ResponseCompression.csproj +++ b/src/Microsoft.AspNetCore.ResponseCompression/Microsoft.AspNetCore.ResponseCompression.csproj @@ -11,8 +11,8 @@ - - + + diff --git a/src/Microsoft.AspNetCore.Rewrite/Microsoft.AspNetCore.Rewrite.csproj b/src/Microsoft.AspNetCore.Rewrite/Microsoft.AspNetCore.Rewrite.csproj index c2ed91e277..958f598489 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Microsoft.AspNetCore.Rewrite.csproj +++ b/src/Microsoft.AspNetCore.Rewrite/Microsoft.AspNetCore.Rewrite.csproj @@ -15,13 +15,13 @@ - - - - - - - + + + + + + + diff --git a/test/Microsoft.AspNetCore.Buffering.Tests/Microsoft.AspNetCore.Buffering.Tests.csproj b/test/Microsoft.AspNetCore.Buffering.Tests/Microsoft.AspNetCore.Buffering.Tests.csproj index d062668356..041439c9a9 100644 --- a/test/Microsoft.AspNetCore.Buffering.Tests/Microsoft.AspNetCore.Buffering.Tests.csproj +++ b/test/Microsoft.AspNetCore.Buffering.Tests/Microsoft.AspNetCore.Buffering.Tests.csproj @@ -9,10 +9,13 @@ - - - - + + + + + + + diff --git a/test/Microsoft.AspNetCore.HttpOverrides.Tests/Microsoft.AspNetCore.HttpOverrides.Tests.csproj b/test/Microsoft.AspNetCore.HttpOverrides.Tests/Microsoft.AspNetCore.HttpOverrides.Tests.csproj index f77f81033a..0cdff3e302 100644 --- a/test/Microsoft.AspNetCore.HttpOverrides.Tests/Microsoft.AspNetCore.HttpOverrides.Tests.csproj +++ b/test/Microsoft.AspNetCore.HttpOverrides.Tests/Microsoft.AspNetCore.HttpOverrides.Tests.csproj @@ -9,11 +9,14 @@ - - - - - + + + + + + + + diff --git a/test/Microsoft.AspNetCore.ResponseCompression.Tests/Microsoft.AspNetCore.ResponseCompression.Tests.csproj b/test/Microsoft.AspNetCore.ResponseCompression.Tests/Microsoft.AspNetCore.ResponseCompression.Tests.csproj index 1d0877be61..5240a9ea71 100644 --- a/test/Microsoft.AspNetCore.ResponseCompression.Tests/Microsoft.AspNetCore.ResponseCompression.Tests.csproj +++ b/test/Microsoft.AspNetCore.ResponseCompression.Tests/Microsoft.AspNetCore.ResponseCompression.Tests.csproj @@ -13,13 +13,16 @@ - - - - - - - + + + + + + + + + + diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/Microsoft.AspNetCore.Rewrite.Tests.csproj b/test/Microsoft.AspNetCore.Rewrite.Tests/Microsoft.AspNetCore.Rewrite.Tests.csproj index 3e5b6e7cf7..e29c1884e8 100644 --- a/test/Microsoft.AspNetCore.Rewrite.Tests/Microsoft.AspNetCore.Rewrite.Tests.csproj +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/Microsoft.AspNetCore.Rewrite.Tests.csproj @@ -9,11 +9,14 @@ - - - - - + + + + + + + + From 876a025543337387e85aa50085f367fdf1a981ee Mon Sep 17 00:00:00 2001 From: Nate McMaster Date: Tue, 21 Mar 2017 12:01:57 -0700 Subject: [PATCH 182/307] Update Travis to macOS Sierra [skip appveyor] --- .travis.yml | 19 +++---------------- 1 file changed, 3 insertions(+), 16 deletions(-) diff --git a/.travis.yml b/.travis.yml index 10713bf2e1..bf8044fd45 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,15 +1,6 @@ language: csharp -sudo: required +sudo: false dist: trusty -addons: - apt: - packages: - - gettext - - libcurl4-openssl-dev - - libicu-dev - - libssl-dev - - libunwind8 - - zlib1g env: global: - DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true @@ -18,6 +9,7 @@ mono: none os: - linux - osx +osx_image: xcode8.2 branches: only: - master @@ -28,9 +20,4 @@ before_install: - if test "$TRAVIS_OS_NAME" == "osx"; then brew update; brew install openssl; ln -s /usr/local/opt/openssl/lib/libcrypto.1.0.0.dylib /usr/local/lib/; ln -s /usr/local/opt/openssl/lib/libssl.1.0.0.dylib /usr/local/lib/; fi script: - ./build.sh -notifications: - webhooks: - secure: "Quayhq8pTWtpCfsC209l4o3ZG75VhEKjTOcuOPDYoQXII4rfmVbnGUoe6A6R3VTz7/O2YTPbX3+ooBrTJufwiJXJG74xZuE35jKnRm3HQREH9tCNUYwB4BO7jzoWz9wXDDfCPs47Tkjdf46Tq0jF27nXrZhNzm6ps3JCoP6/lA+8lEfWxIYifviwxJ392S34k5SyaVYeOIs+W95Iuvmd6+ZenVZNvPaGwHzTKqVhh/NYttbQ3oUq4n2fWaIrwGVi7MC6CtINoG/CtmUU3pef+StPOYMjWfMGcUjAkikWWEsCDnUSOpmNxKREKqXXbOBPDCcC9sNkzpYa0ksHRwGQv2jagVYaAicNfGc/gtWJ3JTCnODUea6oTsmdZT7hNW1ClzOEacXHv55TzImgAb1MFD9euSoXBIa9rRNYhx1oy3JYal2Ee0crPF1nFxQJ5mVT9pGEhpMqAwdNaZBwA5urVn6bl0ptPb8W6XVw5/qgPdBvmF67Xjw+k3TDQ3J4sWClGdX4ZsfgVFLSDGk9hqudPp10XlXkAscYtpKoZIEIK5rVa7RnvI44Bh1eQRqFpqKa2m1gVquJwUQg0L8CPakZDscas29dtXY4KqHrspOOtolhtOUaVpanQCGFWgPnWxIx9m+3eDRCLSjhvrZyZwemmvqXNqFhKUILdQLo1itANDo=" - on_success: always - on_failure: always - on_start: always + From 7e9b92072e87fa0ab84e885e23ea9971103921d2 Mon Sep 17 00:00:00 2001 From: Kiran Challa Date: Wed, 22 Mar 2017 23:31:22 -0700 Subject: [PATCH 183/307] Converted samples and test projects to run on netcoreapp2.0 --- build/dependencies.props | 1 + samples/HttpOverridesSample/HttpOverridesSample.csproj | 2 +- .../ResponseBufferingSample.csproj | 2 +- .../ResponseCompressionSample.csproj | 2 +- samples/RewriteSample/RewriteSample.csproj | 2 +- .../Microsoft.AspNetCore.Buffering.Tests.csproj | 4 ++-- .../Microsoft.AspNetCore.HttpOverrides.Tests.csproj | 4 ++-- .../BodyWrapperStreamTests.cs | 3 +++ .../Microsoft.AspNetCore.ResponseCompression.Tests.csproj | 4 ++-- .../ResponseCompressionMiddlewareTest.cs | 8 ++++---- .../Microsoft.AspNetCore.Rewrite.Tests.csproj | 4 ++-- 11 files changed, 20 insertions(+), 16 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index c153f0e3f9..35c5cad19a 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -4,6 +4,7 @@ 4.3.0 4.7.1 1.6.1 + 2.0.0-* 15.0.0 2.2.0 diff --git a/samples/HttpOverridesSample/HttpOverridesSample.csproj b/samples/HttpOverridesSample/HttpOverridesSample.csproj index 2cf83ecfad..e6ff05beb5 100644 --- a/samples/HttpOverridesSample/HttpOverridesSample.csproj +++ b/samples/HttpOverridesSample/HttpOverridesSample.csproj @@ -3,7 +3,7 @@ - net451;netcoreapp1.1 + net451;netcoreapp2.0 diff --git a/samples/ResponseBufferingSample/ResponseBufferingSample.csproj b/samples/ResponseBufferingSample/ResponseBufferingSample.csproj index 90bf35c252..72a62c9228 100644 --- a/samples/ResponseBufferingSample/ResponseBufferingSample.csproj +++ b/samples/ResponseBufferingSample/ResponseBufferingSample.csproj @@ -3,7 +3,7 @@ - net451;netcoreapp1.1 + net451;netcoreapp2.0 diff --git a/samples/ResponseCompressionSample/ResponseCompressionSample.csproj b/samples/ResponseCompressionSample/ResponseCompressionSample.csproj index 7c668a7ced..42ff9ed947 100644 --- a/samples/ResponseCompressionSample/ResponseCompressionSample.csproj +++ b/samples/ResponseCompressionSample/ResponseCompressionSample.csproj @@ -3,7 +3,7 @@ - net451;netcoreapp1.1 + net451;netcoreapp2.0 diff --git a/samples/RewriteSample/RewriteSample.csproj b/samples/RewriteSample/RewriteSample.csproj index 56e834d177..d2b8a51d9e 100644 --- a/samples/RewriteSample/RewriteSample.csproj +++ b/samples/RewriteSample/RewriteSample.csproj @@ -3,7 +3,7 @@ - net451;netcoreapp1.1 + net451;netcoreapp2.0 diff --git a/test/Microsoft.AspNetCore.Buffering.Tests/Microsoft.AspNetCore.Buffering.Tests.csproj b/test/Microsoft.AspNetCore.Buffering.Tests/Microsoft.AspNetCore.Buffering.Tests.csproj index 041439c9a9..7f9b782173 100644 --- a/test/Microsoft.AspNetCore.Buffering.Tests/Microsoft.AspNetCore.Buffering.Tests.csproj +++ b/test/Microsoft.AspNetCore.Buffering.Tests/Microsoft.AspNetCore.Buffering.Tests.csproj @@ -3,8 +3,8 @@ - netcoreapp1.1;net452 - netcoreapp1.1 + netcoreapp2.0;net452 + netcoreapp2.0 diff --git a/test/Microsoft.AspNetCore.HttpOverrides.Tests/Microsoft.AspNetCore.HttpOverrides.Tests.csproj b/test/Microsoft.AspNetCore.HttpOverrides.Tests/Microsoft.AspNetCore.HttpOverrides.Tests.csproj index 0cdff3e302..faa3154a73 100644 --- a/test/Microsoft.AspNetCore.HttpOverrides.Tests/Microsoft.AspNetCore.HttpOverrides.Tests.csproj +++ b/test/Microsoft.AspNetCore.HttpOverrides.Tests/Microsoft.AspNetCore.HttpOverrides.Tests.csproj @@ -3,8 +3,8 @@ - netcoreapp1.1;net452 - netcoreapp1.1 + netcoreapp2.0;net452 + netcoreapp2.0 diff --git a/test/Microsoft.AspNetCore.ResponseCompression.Tests/BodyWrapperStreamTests.cs b/test/Microsoft.AspNetCore.ResponseCompression.Tests/BodyWrapperStreamTests.cs index cb89f8f2d9..05b5accf37 100644 --- a/test/Microsoft.AspNetCore.ResponseCompression.Tests/BodyWrapperStreamTests.cs +++ b/test/Microsoft.AspNetCore.ResponseCompression.Tests/BodyWrapperStreamTests.cs @@ -133,6 +133,9 @@ namespace Microsoft.AspNetCore.ResponseCompression.Tests Assert.Equal(buffer, written); } +#elif NETCOREAPP2_0 +#else +#error Target framework needs to be updated #endif private class MockResponseCompressionProvider: IResponseCompressionProvider diff --git a/test/Microsoft.AspNetCore.ResponseCompression.Tests/Microsoft.AspNetCore.ResponseCompression.Tests.csproj b/test/Microsoft.AspNetCore.ResponseCompression.Tests/Microsoft.AspNetCore.ResponseCompression.Tests.csproj index 5240a9ea71..471129dc94 100644 --- a/test/Microsoft.AspNetCore.ResponseCompression.Tests/Microsoft.AspNetCore.ResponseCompression.Tests.csproj +++ b/test/Microsoft.AspNetCore.ResponseCompression.Tests/Microsoft.AspNetCore.ResponseCompression.Tests.csproj @@ -3,8 +3,8 @@ - netcoreapp1.1;net452 - netcoreapp1.1 + netcoreapp2.0;net452 + netcoreapp2.0 diff --git a/test/Microsoft.AspNetCore.ResponseCompression.Tests/ResponseCompressionMiddlewareTest.cs b/test/Microsoft.AspNetCore.ResponseCompression.Tests/ResponseCompressionMiddlewareTest.cs index 0494896c11..96847d5d6f 100644 --- a/test/Microsoft.AspNetCore.ResponseCompression.Tests/ResponseCompressionMiddlewareTest.cs +++ b/test/Microsoft.AspNetCore.ResponseCompression.Tests/ResponseCompressionMiddlewareTest.cs @@ -508,12 +508,12 @@ namespace Microsoft.AspNetCore.ResponseCompression.Tests #if NET452 // Flush not supported, compression disabled Assert.NotNull(response.Headers.GetValues(HeaderNames.ContentMD5)); Assert.Empty(response.Content.Headers.ContentEncoding); -#elif NETCOREAPP1_1 // Flush supported, compression enabled +#elif NETCOREAPP2_0 // Flush supported, compression enabled IEnumerable contentMD5 = null; Assert.False(response.Headers.TryGetValues(HeaderNames.ContentMD5, out contentMD5)); Assert.Single(response.Content.Headers.ContentEncoding, "gzip"); #else - Not implemented, compiler break +#error Target framework needs to be updated #endif var body = await response.Content.ReadAsStreamAsync(); @@ -573,12 +573,12 @@ namespace Microsoft.AspNetCore.ResponseCompression.Tests #if NET452 // Flush not supported, compression disabled Assert.NotNull(response.Headers.GetValues(HeaderNames.ContentMD5)); Assert.Empty(response.Content.Headers.ContentEncoding); -#elif NETCOREAPP1_1 // Flush supported, compression enabled +#elif NETCOREAPP2_0 // Flush supported, compression enabled IEnumerable contentMD5 = null; Assert.False(response.Headers.TryGetValues(HeaderNames.ContentMD5, out contentMD5)); Assert.Single(response.Content.Headers.ContentEncoding, "gzip"); #else - Not implemented, compiler break +#error Target framework needs to be updated #endif var body = await response.Content.ReadAsStreamAsync(); diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/Microsoft.AspNetCore.Rewrite.Tests.csproj b/test/Microsoft.AspNetCore.Rewrite.Tests/Microsoft.AspNetCore.Rewrite.Tests.csproj index e29c1884e8..2febee9e55 100644 --- a/test/Microsoft.AspNetCore.Rewrite.Tests/Microsoft.AspNetCore.Rewrite.Tests.csproj +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/Microsoft.AspNetCore.Rewrite.Tests.csproj @@ -3,8 +3,8 @@ - netcoreapp1.1;net452 - netcoreapp1.1 + netcoreapp2.0;net452 + netcoreapp2.0 From a641231f663f5ead72ebb84cac7fbd4f012af64d Mon Sep 17 00:00:00 2001 From: Pranav K Date: Thu, 23 Mar 2017 09:59:11 -0700 Subject: [PATCH 184/307] Remove net451 as a cross-compile target --- .gitignore | 1 + samples/HttpOverridesSample/HttpOverridesSample.csproj | 2 +- .../ResponseBufferingSample/ResponseBufferingSample.csproj | 2 +- .../ResponseCompressionSample.csproj | 2 +- samples/RewriteSample/RewriteSample.csproj | 2 +- src/Microsoft.AspNetCore.Buffering/BufferingWriteStream.cs | 5 ++++- .../Microsoft.AspNetCore.Buffering.csproj | 2 +- .../Microsoft.AspNetCore.HttpOverrides.csproj | 2 +- .../BodyWrapperStream.cs | 5 ++++- .../GzipCompressionProvider.cs | 4 ++-- .../Microsoft.AspNetCore.ResponseCompression.csproj | 2 +- .../Microsoft.AspNetCore.Rewrite.csproj | 2 +- .../Microsoft.AspNetCore.Buffering.Tests.csproj | 4 +++- .../Microsoft.AspNetCore.HttpOverrides.Tests.csproj | 4 +++- .../BodyWrapperStreamTests.cs | 2 +- .../Microsoft.AspNetCore.ResponseCompression.Tests.csproj | 4 +++- .../ResponseCompressionMiddlewareTest.cs | 6 +++--- .../Microsoft.AspNetCore.Rewrite.Tests.csproj | 4 +++- 18 files changed, 35 insertions(+), 20 deletions(-) diff --git a/.gitignore b/.gitignore index 4b5208332f..c8dd6c52d5 100644 --- a/.gitignore +++ b/.gitignore @@ -32,3 +32,4 @@ project.lock.json .vscode/ *.nuget.props *.nuget.targets +global.json diff --git a/samples/HttpOverridesSample/HttpOverridesSample.csproj b/samples/HttpOverridesSample/HttpOverridesSample.csproj index e6ff05beb5..c163d00c5f 100644 --- a/samples/HttpOverridesSample/HttpOverridesSample.csproj +++ b/samples/HttpOverridesSample/HttpOverridesSample.csproj @@ -3,7 +3,7 @@ - net451;netcoreapp2.0 + net46;netcoreapp2.0 diff --git a/samples/ResponseBufferingSample/ResponseBufferingSample.csproj b/samples/ResponseBufferingSample/ResponseBufferingSample.csproj index 72a62c9228..0a99f5017f 100644 --- a/samples/ResponseBufferingSample/ResponseBufferingSample.csproj +++ b/samples/ResponseBufferingSample/ResponseBufferingSample.csproj @@ -3,7 +3,7 @@ - net451;netcoreapp2.0 + net46;netcoreapp2.0 diff --git a/samples/ResponseCompressionSample/ResponseCompressionSample.csproj b/samples/ResponseCompressionSample/ResponseCompressionSample.csproj index 42ff9ed947..37e37f9c6c 100644 --- a/samples/ResponseCompressionSample/ResponseCompressionSample.csproj +++ b/samples/ResponseCompressionSample/ResponseCompressionSample.csproj @@ -3,7 +3,7 @@ - net451;netcoreapp2.0 + net46;netcoreapp2.0 diff --git a/samples/RewriteSample/RewriteSample.csproj b/samples/RewriteSample/RewriteSample.csproj index d2b8a51d9e..8dc059dc1d 100644 --- a/samples/RewriteSample/RewriteSample.csproj +++ b/samples/RewriteSample/RewriteSample.csproj @@ -3,7 +3,7 @@ - net451;netcoreapp2.0 + net46;netcoreapp2.0 diff --git a/src/Microsoft.AspNetCore.Buffering/BufferingWriteStream.cs b/src/Microsoft.AspNetCore.Buffering/BufferingWriteStream.cs index f3f4dbe8fe..29ab23bde2 100644 --- a/src/Microsoft.AspNetCore.Buffering/BufferingWriteStream.cs +++ b/src/Microsoft.AspNetCore.Buffering/BufferingWriteStream.cs @@ -160,7 +160,7 @@ namespace Microsoft.AspNetCore.Buffering return _innerStream.WriteAsync(buffer, offset, count, cancellationToken); } } -#if !NETSTANDARD1_3 +#if NET46 public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object state) { if (_isBuffering) @@ -184,6 +184,9 @@ namespace Microsoft.AspNetCore.Buffering _innerStream.EndWrite(asyncResult); } } +#elif NETSTANDARD1_3 +#else +#error target frameworks need to be updated #endif public override void Flush() { diff --git a/src/Microsoft.AspNetCore.Buffering/Microsoft.AspNetCore.Buffering.csproj b/src/Microsoft.AspNetCore.Buffering/Microsoft.AspNetCore.Buffering.csproj index 81bf91be82..658f4a836d 100644 --- a/src/Microsoft.AspNetCore.Buffering/Microsoft.AspNetCore.Buffering.csproj +++ b/src/Microsoft.AspNetCore.Buffering/Microsoft.AspNetCore.Buffering.csproj @@ -5,7 +5,7 @@ 0.3.0 ASP.NET Core middleware for buffering response bodies. - net451;netstandard1.3 + net46;netstandard1.3 $(NoWarn);CS1591 true aspnetcore;buffer;buffering diff --git a/src/Microsoft.AspNetCore.HttpOverrides/Microsoft.AspNetCore.HttpOverrides.csproj b/src/Microsoft.AspNetCore.HttpOverrides/Microsoft.AspNetCore.HttpOverrides.csproj index 7d8b86ce59..9e175ad34b 100644 --- a/src/Microsoft.AspNetCore.HttpOverrides/Microsoft.AspNetCore.HttpOverrides.csproj +++ b/src/Microsoft.AspNetCore.HttpOverrides/Microsoft.AspNetCore.HttpOverrides.csproj @@ -7,7 +7,7 @@ ASP.NET Core basic middleware for supporting HTTP method overrides. Includes: * X-Forwarded-* headers to forward headers from a proxy. * HTTP method override header. - net451;netstandard1.3 + netstandard1.3 $(NoWarn);CS1591 true aspnetcore;proxy;headers;xforwarded diff --git a/src/Microsoft.AspNetCore.ResponseCompression/BodyWrapperStream.cs b/src/Microsoft.AspNetCore.ResponseCompression/BodyWrapperStream.cs index 4906e0e2a6..ff25fe8b71 100644 --- a/src/Microsoft.AspNetCore.ResponseCompression/BodyWrapperStream.cs +++ b/src/Microsoft.AspNetCore.ResponseCompression/BodyWrapperStream.cs @@ -137,7 +137,7 @@ namespace Microsoft.AspNetCore.ResponseCompression } } -#if NET451 +#if NET46 public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, Object state) { var tcs = new TaskCompletionSource(state); @@ -184,6 +184,9 @@ namespace Microsoft.AspNetCore.ResponseCompression var task = (Task)asyncResult; task.GetAwaiter().GetResult(); } +#elif NETSTANDARD1_3 +#else +#error target frameworks need to be updated #endif public override async Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) diff --git a/src/Microsoft.AspNetCore.ResponseCompression/GzipCompressionProvider.cs b/src/Microsoft.AspNetCore.ResponseCompression/GzipCompressionProvider.cs index b8c3c08517..0588995dd5 100644 --- a/src/Microsoft.AspNetCore.ResponseCompression/GzipCompressionProvider.cs +++ b/src/Microsoft.AspNetCore.ResponseCompression/GzipCompressionProvider.cs @@ -37,12 +37,12 @@ namespace Microsoft.AspNetCore.ResponseCompression { get { -#if NET451 +#if NET46 return false; #elif NETSTANDARD1_3 return true; #else - // Not implemented, compiler break +#error target frameworks need to be updated #endif } } diff --git a/src/Microsoft.AspNetCore.ResponseCompression/Microsoft.AspNetCore.ResponseCompression.csproj b/src/Microsoft.AspNetCore.ResponseCompression/Microsoft.AspNetCore.ResponseCompression.csproj index f542b01c5b..376cfee8c9 100644 --- a/src/Microsoft.AspNetCore.ResponseCompression/Microsoft.AspNetCore.ResponseCompression.csproj +++ b/src/Microsoft.AspNetCore.ResponseCompression/Microsoft.AspNetCore.ResponseCompression.csproj @@ -5,7 +5,7 @@ 1.1.0 ASP.NET Core middleware for HTTP Response compression. - net451;netstandard1.3 + net46;netstandard1.3 true aspnetcore diff --git a/src/Microsoft.AspNetCore.Rewrite/Microsoft.AspNetCore.Rewrite.csproj b/src/Microsoft.AspNetCore.Rewrite/Microsoft.AspNetCore.Rewrite.csproj index 958f598489..bee8ab2673 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Microsoft.AspNetCore.Rewrite.csproj +++ b/src/Microsoft.AspNetCore.Rewrite/Microsoft.AspNetCore.Rewrite.csproj @@ -8,7 +8,7 @@ * Support for custom URL rewrite rules * Support for running IIS URL Rewrite module rules * Support for running Apache mod_rewrite rules. - net451;netstandard1.3 + netstandard1.3 $(NoWarn);CS1591 true aspnetcore;urlrewrite;mod_rewrite diff --git a/test/Microsoft.AspNetCore.Buffering.Tests/Microsoft.AspNetCore.Buffering.Tests.csproj b/test/Microsoft.AspNetCore.Buffering.Tests/Microsoft.AspNetCore.Buffering.Tests.csproj index 7f9b782173..2af1f9b194 100644 --- a/test/Microsoft.AspNetCore.Buffering.Tests/Microsoft.AspNetCore.Buffering.Tests.csproj +++ b/test/Microsoft.AspNetCore.Buffering.Tests/Microsoft.AspNetCore.Buffering.Tests.csproj @@ -3,8 +3,10 @@ - netcoreapp2.0;net452 + netcoreapp2.0;net46 netcoreapp2.0 + true + true diff --git a/test/Microsoft.AspNetCore.HttpOverrides.Tests/Microsoft.AspNetCore.HttpOverrides.Tests.csproj b/test/Microsoft.AspNetCore.HttpOverrides.Tests/Microsoft.AspNetCore.HttpOverrides.Tests.csproj index faa3154a73..b525b8926b 100644 --- a/test/Microsoft.AspNetCore.HttpOverrides.Tests/Microsoft.AspNetCore.HttpOverrides.Tests.csproj +++ b/test/Microsoft.AspNetCore.HttpOverrides.Tests/Microsoft.AspNetCore.HttpOverrides.Tests.csproj @@ -3,8 +3,10 @@ - netcoreapp2.0;net452 + netcoreapp2.0;net46 netcoreapp2.0 + true + true diff --git a/test/Microsoft.AspNetCore.ResponseCompression.Tests/BodyWrapperStreamTests.cs b/test/Microsoft.AspNetCore.ResponseCompression.Tests/BodyWrapperStreamTests.cs index 05b5accf37..a1efd4a458 100644 --- a/test/Microsoft.AspNetCore.ResponseCompression.Tests/BodyWrapperStreamTests.cs +++ b/test/Microsoft.AspNetCore.ResponseCompression.Tests/BodyWrapperStreamTests.cs @@ -108,7 +108,7 @@ namespace Microsoft.AspNetCore.ResponseCompression.Tests Assert.Equal(File.ReadAllBytes(path), written); } -#if NET452 +#if NET46 [Theory] [InlineData(true)] [InlineData(false)] diff --git a/test/Microsoft.AspNetCore.ResponseCompression.Tests/Microsoft.AspNetCore.ResponseCompression.Tests.csproj b/test/Microsoft.AspNetCore.ResponseCompression.Tests/Microsoft.AspNetCore.ResponseCompression.Tests.csproj index 471129dc94..27ab922297 100644 --- a/test/Microsoft.AspNetCore.ResponseCompression.Tests/Microsoft.AspNetCore.ResponseCompression.Tests.csproj +++ b/test/Microsoft.AspNetCore.ResponseCompression.Tests/Microsoft.AspNetCore.ResponseCompression.Tests.csproj @@ -3,8 +3,10 @@ - netcoreapp2.0;net452 + netcoreapp2.0;net46 netcoreapp2.0 + true + true diff --git a/test/Microsoft.AspNetCore.ResponseCompression.Tests/ResponseCompressionMiddlewareTest.cs b/test/Microsoft.AspNetCore.ResponseCompression.Tests/ResponseCompressionMiddlewareTest.cs index 96847d5d6f..34fd5f2c83 100644 --- a/test/Microsoft.AspNetCore.ResponseCompression.Tests/ResponseCompressionMiddlewareTest.cs +++ b/test/Microsoft.AspNetCore.ResponseCompression.Tests/ResponseCompressionMiddlewareTest.cs @@ -505,7 +505,7 @@ namespace Microsoft.AspNetCore.ResponseCompression.Tests var response = await client.SendAsync(request, HttpCompletionOption.ResponseHeadersRead); -#if NET452 // Flush not supported, compression disabled +#if NET46 // Flush not supported, compression disabled Assert.NotNull(response.Headers.GetValues(HeaderNames.ContentMD5)); Assert.Empty(response.Content.Headers.ContentEncoding); #elif NETCOREAPP2_0 // Flush supported, compression enabled @@ -513,7 +513,7 @@ namespace Microsoft.AspNetCore.ResponseCompression.Tests Assert.False(response.Headers.TryGetValues(HeaderNames.ContentMD5, out contentMD5)); Assert.Single(response.Content.Headers.ContentEncoding, "gzip"); #else -#error Target framework needs to be updated +#error Target frameworks need to be updated. #endif var body = await response.Content.ReadAsStreamAsync(); @@ -570,7 +570,7 @@ namespace Microsoft.AspNetCore.ResponseCompression.Tests var response = await client.SendAsync(request, HttpCompletionOption.ResponseHeadersRead); -#if NET452 // Flush not supported, compression disabled +#if NET46 // Flush not supported, compression disabled Assert.NotNull(response.Headers.GetValues(HeaderNames.ContentMD5)); Assert.Empty(response.Content.Headers.ContentEncoding); #elif NETCOREAPP2_0 // Flush supported, compression enabled diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/Microsoft.AspNetCore.Rewrite.Tests.csproj b/test/Microsoft.AspNetCore.Rewrite.Tests/Microsoft.AspNetCore.Rewrite.Tests.csproj index 2febee9e55..79c1c1c298 100644 --- a/test/Microsoft.AspNetCore.Rewrite.Tests/Microsoft.AspNetCore.Rewrite.Tests.csproj +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/Microsoft.AspNetCore.Rewrite.Tests.csproj @@ -3,8 +3,10 @@ - netcoreapp2.0;net452 + netcoreapp2.0;net46 netcoreapp2.0 + true + true From a6caa5760838740135c6ee9ad1c8c8178b50d951 Mon Sep 17 00:00:00 2001 From: Pranav K Date: Wed, 29 Mar 2017 11:30:31 -0700 Subject: [PATCH 185/307] Updating to 2.0.0 Internal.AspNetCore.Sdk --- build/common.props | 2 +- build/dependencies.props | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/build/common.props b/build/common.props index 1722b8038b..e2ad603d26 100644 --- a/build/common.props +++ b/build/common.props @@ -13,7 +13,7 @@ - + diff --git a/build/dependencies.props b/build/dependencies.props index 35c5cad19a..cf4424fae5 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -2,10 +2,11 @@ 1.2.0-* 4.3.0 + 2.0.0-* 4.7.1 1.6.1 2.0.0-* 15.0.0 2.2.0 - + \ No newline at end of file From 6c5f812d77d2e43b0a7c49a50d238f51a9eb665f Mon Sep 17 00:00:00 2001 From: Pranav K Date: Mon, 3 Apr 2017 21:41:08 -0700 Subject: [PATCH 186/307] Updating versions to 2.0.0-preview1 --- build/dependencies.props | 2 +- .../Microsoft.AspNetCore.HttpOverrides.csproj | 2 +- .../Microsoft.AspNetCore.ResponseCompression.csproj | 2 +- .../Microsoft.AspNetCore.Rewrite.csproj | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index cf4424fae5..afc72a267b 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -1,6 +1,6 @@ - 1.2.0-* + 2.0.0-* 4.3.0 2.0.0-* 4.7.1 diff --git a/src/Microsoft.AspNetCore.HttpOverrides/Microsoft.AspNetCore.HttpOverrides.csproj b/src/Microsoft.AspNetCore.HttpOverrides/Microsoft.AspNetCore.HttpOverrides.csproj index 9e175ad34b..ab49dd26db 100644 --- a/src/Microsoft.AspNetCore.HttpOverrides/Microsoft.AspNetCore.HttpOverrides.csproj +++ b/src/Microsoft.AspNetCore.HttpOverrides/Microsoft.AspNetCore.HttpOverrides.csproj @@ -3,7 +3,7 @@ - 1.2.0 + 2.0.0 ASP.NET Core basic middleware for supporting HTTP method overrides. Includes: * X-Forwarded-* headers to forward headers from a proxy. * HTTP method override header. diff --git a/src/Microsoft.AspNetCore.ResponseCompression/Microsoft.AspNetCore.ResponseCompression.csproj b/src/Microsoft.AspNetCore.ResponseCompression/Microsoft.AspNetCore.ResponseCompression.csproj index 376cfee8c9..80e48518c7 100644 --- a/src/Microsoft.AspNetCore.ResponseCompression/Microsoft.AspNetCore.ResponseCompression.csproj +++ b/src/Microsoft.AspNetCore.ResponseCompression/Microsoft.AspNetCore.ResponseCompression.csproj @@ -3,7 +3,7 @@ - 1.1.0 + 2.0.0 ASP.NET Core middleware for HTTP Response compression. net46;netstandard1.3 true diff --git a/src/Microsoft.AspNetCore.Rewrite/Microsoft.AspNetCore.Rewrite.csproj b/src/Microsoft.AspNetCore.Rewrite/Microsoft.AspNetCore.Rewrite.csproj index bee8ab2673..028eaeaa9c 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Microsoft.AspNetCore.Rewrite.csproj +++ b/src/Microsoft.AspNetCore.Rewrite/Microsoft.AspNetCore.Rewrite.csproj @@ -3,7 +3,7 @@ - 1.1.0 + 2.0.0 ASP.NET Core basic middleware for rewriting URLs. Includes: * Support for custom URL rewrite rules * Support for running IIS URL Rewrite module rules From 1ade06fd3461fcbb5204daee3cc6fec553cd2e90 Mon Sep 17 00:00:00 2001 From: Chris R Date: Fri, 21 Apr 2017 19:01:37 -0700 Subject: [PATCH 187/307] #190 Change RequireHeaderSymmetry default to false, improve consistency. (#226) --- .../ForwardedHeadersMiddleware.cs | 8 +- .../ForwardedHeadersOptions.cs | 4 +- .../ForwardedHeadersMiddlewareTest.cs | 74 ++++++++++++------- 3 files changed, 57 insertions(+), 29 deletions(-) diff --git a/src/Microsoft.AspNetCore.HttpOverrides/ForwardedHeadersMiddleware.cs b/src/Microsoft.AspNetCore.HttpOverrides/ForwardedHeadersMiddleware.cs index 2882dfdf8d..1863087c0e 100644 --- a/src/Microsoft.AspNetCore.HttpOverrides/ForwardedHeadersMiddleware.cs +++ b/src/Microsoft.AspNetCore.HttpOverrides/ForwardedHeadersMiddleware.cs @@ -164,9 +164,15 @@ namespace Microsoft.AspNetCore.HttpOverrides currentValues.IpAndPortText = set.IpAndPortText; currentValues.RemoteIpAndPort = set.RemoteIpAndPort; } + else if (!string.IsNullOrEmpty(set.IpAndPortText)) + { + // Stop at the first unparsable IP, but still apply changes processed so far. + _logger.LogDebug(1, $"Unparsable IP: {set.IpAndPortText}"); + break; + } else if (_options.RequireHeaderSymmetry) { - _logger.LogWarning(2, $"Failed to parse forwarded IPAddress: {currentValues.IpAndPortText}"); + _logger.LogWarning(2, $"Missing forwarded IPAddress."); return; } } diff --git a/src/Microsoft.AspNetCore.HttpOverrides/ForwardedHeadersOptions.cs b/src/Microsoft.AspNetCore.HttpOverrides/ForwardedHeadersOptions.cs index 556c8acc3d..cbe00baaa1 100644 --- a/src/Microsoft.AspNetCore.HttpOverrides/ForwardedHeadersOptions.cs +++ b/src/Microsoft.AspNetCore.HttpOverrides/ForwardedHeadersOptions.cs @@ -69,8 +69,8 @@ namespace Microsoft.AspNetCore.Builder /// /// Require the number of header values to be in sync between the different headers being processed. - /// The default is 'true'. + /// The default is 'false'. /// - public bool RequireHeaderSymmetry { get; set; } = true; + public bool RequireHeaderSymmetry { get; set; } = false; } } diff --git a/test/Microsoft.AspNetCore.HttpOverrides.Tests/ForwardedHeadersMiddlewareTest.cs b/test/Microsoft.AspNetCore.HttpOverrides.Tests/ForwardedHeadersMiddlewareTest.cs index e0de87abd8..250774b5f4 100644 --- a/test/Microsoft.AspNetCore.HttpOverrides.Tests/ForwardedHeadersMiddlewareTest.cs +++ b/test/Microsoft.AspNetCore.HttpOverrides.Tests/ForwardedHeadersMiddlewareTest.cs @@ -86,17 +86,25 @@ namespace Microsoft.AspNetCore.HttpOverrides } [Theory] - [InlineData(1, "11.111.111.11:12345", "11.111.111.11", 12345, "")] - [InlineData(10, "11.111.111.11:12345", "11.111.111.11", 12345, "")] - [InlineData(1, "12.112.112.12:23456, 11.111.111.11:12345", "11.111.111.11", 12345, "12.112.112.12:23456")] - [InlineData(2, "12.112.112.12:23456, 11.111.111.11:12345", "12.112.112.12", 23456, "")] - [InlineData(10, "12.112.112.12:23456, 11.111.111.11:12345", "12.112.112.12", 23456, "")] - [InlineData(10, "12.112.112.12.23456, 11.111.111.11:12345", "10.0.0.1", 99, "12.112.112.12.23456, 11.111.111.11:12345")] // Invalid - [InlineData(10, "13.113.113.13:34567, 12.112.112.12.23456, 11.111.111.11:12345", "10.0.0.1", 99, - "13.113.113.13:34567, 12.112.112.12.23456, 11.111.111.11:12345")] // Invalid - [InlineData(2, "13.113.113.13:34567, 12.112.112.12:23456, 11.111.111.11:12345", "12.112.112.12", 23456, "13.113.113.13:34567")] - [InlineData(3, "13.113.113.13:34567, 12.112.112.12:23456, 11.111.111.11:12345", "13.113.113.13", 34567, "")] - public async Task XForwardedForForwardLimit(int limit, string header, string expectedIp, int expectedPort, string remainingHeader) + [InlineData(1, "11.111.111.11:12345", "11.111.111.11", 12345, "", false)] + [InlineData(1, "11.111.111.11:12345", "11.111.111.11", 12345, "", true)] + [InlineData(10, "11.111.111.11:12345", "11.111.111.11", 12345, "", false)] + [InlineData(10, "11.111.111.11:12345", "11.111.111.11", 12345, "", true)] + [InlineData(1, "12.112.112.12:23456, 11.111.111.11:12345", "11.111.111.11", 12345, "12.112.112.12:23456", false)] + [InlineData(1, "12.112.112.12:23456, 11.111.111.11:12345", "11.111.111.11", 12345, "12.112.112.12:23456", true)] + [InlineData(2, "12.112.112.12:23456, 11.111.111.11:12345", "12.112.112.12", 23456, "", false)] + [InlineData(2, "12.112.112.12:23456, 11.111.111.11:12345", "12.112.112.12", 23456, "", true)] + [InlineData(10, "12.112.112.12:23456, 11.111.111.11:12345", "12.112.112.12", 23456, "", false)] + [InlineData(10, "12.112.112.12:23456, 11.111.111.11:12345", "12.112.112.12", 23456, "", true)] + [InlineData(10, "12.112.112.12.23456, 11.111.111.11:12345", "11.111.111.11", 12345, "12.112.112.12.23456", false)] // Invalid 2nd value + [InlineData(10, "12.112.112.12.23456, 11.111.111.11:12345", "11.111.111.11", 12345, "12.112.112.12.23456", true)] // Invalid 2nd value + [InlineData(10, "13.113.113.13:34567, 12.112.112.12.23456, 11.111.111.11:12345", "11.111.111.11", 12345, "13.113.113.13:34567,12.112.112.12.23456", false)] // Invalid 2nd value + [InlineData(10, "13.113.113.13:34567, 12.112.112.12.23456, 11.111.111.11:12345", "11.111.111.11", 12345, "13.113.113.13:34567,12.112.112.12.23456", true)] // Invalid 2nd value + [InlineData(2, "13.113.113.13:34567, 12.112.112.12:23456, 11.111.111.11:12345", "12.112.112.12", 23456, "13.113.113.13:34567", false)] + [InlineData(2, "13.113.113.13:34567, 12.112.112.12:23456, 11.111.111.11:12345", "12.112.112.12", 23456, "13.113.113.13:34567", true)] + [InlineData(3, "13.113.113.13:34567, 12.112.112.12:23456, 11.111.111.11:12345", "13.113.113.13", 34567, "", false)] + [InlineData(3, "13.113.113.13:34567, 12.112.112.12:23456, 11.111.111.11:12345", "13.113.113.13", 34567, "", true)] + public async Task XForwardedForForwardLimit(int limit, string header, string expectedIp, int expectedPort, string remainingHeader, bool requireSymmetry) { var assertsExecuted = false; @@ -112,6 +120,7 @@ namespace Microsoft.AspNetCore.HttpOverrides var options = new ForwardedHeadersOptions { ForwardedHeaders = ForwardedHeaders.XForwardedFor, + RequireHeaderSymmetry = requireSymmetry, ForwardLimit = limit, }; options.KnownProxies.Clear(); @@ -186,19 +195,29 @@ namespace Microsoft.AspNetCore.HttpOverrides } [Theory] - [InlineData(1, "11.111.111.11:12345", "20.0.0.1", "10.0.0.1", 99)] - [InlineData(1, "", "10.0.0.1", "10.0.0.1", 99)] - [InlineData(1, "11.111.111.11:12345", "10.0.0.1", "11.111.111.11", 12345)] - [InlineData(1, "12.112.112.12:23456, 11.111.111.11:12345", "10.0.0.1", "11.111.111.11", 12345)] - [InlineData(2, "12.112.112.12:23456, 11.111.111.11:12345", "10.0.0.1", "11.111.111.11", 12345)] - [InlineData(1, "12.112.112.12:23456, 11.111.111.11:12345", "10.0.0.1,11.111.111.11", "11.111.111.11", 12345)] - [InlineData(2, "12.112.112.12:23456, 11.111.111.11:12345", "10.0.0.1,11.111.111.11", "12.112.112.12", 23456)] - [InlineData(1, "12.112.112.12:23456, 11.111.111.11:12345", "10.0.0.1,11.111.111.11,12.112.112.12", "11.111.111.11", 12345)] - [InlineData(2, "12.112.112.12:23456, 11.111.111.11:12345", "10.0.0.1,11.111.111.11,12.112.112.12", "12.112.112.12", 23456)] - [InlineData(3, "13.113.113.13:34567, 12.112.112.12:23456, 11.111.111.11:12345", "10.0.0.1,11.111.111.11,12.112.112.12", "13.113.113.13", 34567)] - [InlineData(3, "13.113.113.13:34567, 12.112.112.12;23456, 11.111.111.11:12345", "10.0.0.1,11.111.111.11,12.112.112.12", "10.0.0.1", 99)] // Invalid 2nd IP - [InlineData(3, "13.113.113.13;34567, 12.112.112.12:23456, 11.111.111.11:12345", "10.0.0.1,11.111.111.11,12.112.112.12", "10.0.0.1", 99)] // Invalid 3rd IP - public async Task XForwardedForForwardKnownIps(int limit, string header, string knownIPs, string expectedIp, int expectedPort) + [InlineData(1, "11.111.111.11:12345", "20.0.0.1", "10.0.0.1", 99, false)] + [InlineData(1, "11.111.111.11:12345", "20.0.0.1", "10.0.0.1", 99, true)] + [InlineData(1, "", "10.0.0.1", "10.0.0.1", 99, false)] + [InlineData(1, "", "10.0.0.1", "10.0.0.1", 99, true)] + [InlineData(1, "11.111.111.11:12345", "10.0.0.1", "11.111.111.11", 12345, false)] + [InlineData(1, "11.111.111.11:12345", "10.0.0.1", "11.111.111.11", 12345, true)] + [InlineData(1, "12.112.112.12:23456, 11.111.111.11:12345", "10.0.0.1", "11.111.111.11", 12345, false)] + [InlineData(1, "12.112.112.12:23456, 11.111.111.11:12345", "10.0.0.1", "11.111.111.11", 12345, true)] + [InlineData(1, "12.112.112.12:23456, 11.111.111.11:12345", "10.0.0.1,11.111.111.11", "11.111.111.11", 12345, false)] + [InlineData(1, "12.112.112.12:23456, 11.111.111.11:12345", "10.0.0.1,11.111.111.11", "11.111.111.11", 12345, true)] + [InlineData(2, "12.112.112.12:23456, 11.111.111.11:12345", "10.0.0.1,11.111.111.11", "12.112.112.12", 23456, false)] + [InlineData(2, "12.112.112.12:23456, 11.111.111.11:12345", "10.0.0.1,11.111.111.11", "12.112.112.12", 23456, true)] + [InlineData(1, "12.112.112.12:23456, 11.111.111.11:12345", "10.0.0.1,11.111.111.11,12.112.112.12", "11.111.111.11", 12345, false)] + [InlineData(1, "12.112.112.12:23456, 11.111.111.11:12345", "10.0.0.1,11.111.111.11,12.112.112.12", "11.111.111.11", 12345, true)] + [InlineData(2, "12.112.112.12:23456, 11.111.111.11:12345", "10.0.0.1,11.111.111.11,12.112.112.12", "12.112.112.12", 23456, false)] + [InlineData(2, "12.112.112.12:23456, 11.111.111.11:12345", "10.0.0.1,11.111.111.11,12.112.112.12", "12.112.112.12", 23456, true)] + [InlineData(3, "13.113.113.13:34567, 12.112.112.12:23456, 11.111.111.11:12345", "10.0.0.1,11.111.111.11,12.112.112.12", "13.113.113.13", 34567, false)] + [InlineData(3, "13.113.113.13:34567, 12.112.112.12:23456, 11.111.111.11:12345", "10.0.0.1,11.111.111.11,12.112.112.12", "13.113.113.13", 34567, true)] + [InlineData(3, "13.113.113.13:34567, 12.112.112.12;23456, 11.111.111.11:12345", "10.0.0.1,11.111.111.11,12.112.112.12", "11.111.111.11", 12345, false)] // Invalid 2nd IP + [InlineData(3, "13.113.113.13:34567, 12.112.112.12;23456, 11.111.111.11:12345", "10.0.0.1,11.111.111.11,12.112.112.12", "11.111.111.11", 12345, true)] // Invalid 2nd IP + [InlineData(3, "13.113.113.13;34567, 12.112.112.12:23456, 11.111.111.11:12345", "10.0.0.1,11.111.111.11,12.112.112.12", "12.112.112.12", 23456, false)] // Invalid 3rd IP + [InlineData(3, "13.113.113.13;34567, 12.112.112.12:23456, 11.111.111.11:12345", "10.0.0.1,11.111.111.11,12.112.112.12", "12.112.112.12", 23456, true)] // Invalid 3rd IP + public async Task XForwardedForForwardKnownIps(int limit, string header, string knownIPs, string expectedIp, int expectedPort, bool requireSymmetry) { var assertsExecuted = false; @@ -214,6 +233,7 @@ namespace Microsoft.AspNetCore.HttpOverrides var options = new ForwardedHeadersOptions { ForwardedHeaders = ForwardedHeaders.XForwardedFor, + RequireHeaderSymmetry = requireSymmetry, ForwardLimit = limit, }; foreach (var ip in knownIPs.Split(',').Select(text => IPAddress.Parse(text))) @@ -334,7 +354,7 @@ namespace Microsoft.AspNetCore.HttpOverrides [InlineData(3, "h2, h1", "::1", "http")] [InlineData(5, "h2, h1", "::1, ::1", "h2")] [InlineData(10, "h3, h2, h1", "::1, ::1, ::1", "h3")] - [InlineData(10, "h3, h2, h1", "::1, badip, ::1", "http")] + [InlineData(10, "h3, h2, h1", "::1, badip, ::1", "h1")] public async Task XForwardedProtoOverrideLimitedByXForwardedForCount(int limit, string protoHeader, string forHeader, string expected) { var assertsExecuted = false; @@ -345,6 +365,7 @@ namespace Microsoft.AspNetCore.HttpOverrides app.UseForwardedHeaders(new ForwardedHeadersOptions { ForwardedHeaders = ForwardedHeaders.XForwardedProto | ForwardedHeaders.XForwardedFor, + RequireHeaderSymmetry = true, ForwardLimit = limit, }); app.Run(context => @@ -373,7 +394,7 @@ namespace Microsoft.AspNetCore.HttpOverrides [InlineData(3, "h2, h1", "::1", "h2")] [InlineData(5, "h2, h1", "::1, ::1", "h2")] [InlineData(10, "h3, h2, h1", "::1, ::1, ::1", "h3")] - [InlineData(10, "h3, h2, h1", "::1, badip, ::1", "h3")] + [InlineData(10, "h3, h2, h1", "::1, badip, ::1", "h1")] public async Task XForwardedProtoOverrideCanBeIndependentOfXForwardedForCount(int limit, string protoHeader, string forHeader, string expected) { var assertsExecuted = false; @@ -432,6 +453,7 @@ namespace Microsoft.AspNetCore.HttpOverrides var options = new ForwardedHeadersOptions { ForwardedHeaders = ForwardedHeaders.XForwardedProto | ForwardedHeaders.XForwardedFor, + RequireHeaderSymmetry = true, ForwardLimit = 5, }; if (!loopback) From 20e21c57bf5558562262569235b1e92d19bf4e57 Mon Sep 17 00:00:00 2001 From: Pranav K Date: Tue, 25 Apr 2017 11:04:07 -0700 Subject: [PATCH 188/307] Use Bundled NETStandard.Library \ NETCoreApp versions instead of explicitly specifying one --- build/common.props | 2 +- build/dependencies.props | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/build/common.props b/build/common.props index e2ad603d26..2d92eff547 100644 --- a/build/common.props +++ b/build/common.props @@ -17,7 +17,7 @@ - + diff --git a/build/dependencies.props b/build/dependencies.props index afc72a267b..8587abb455 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -4,9 +4,7 @@ 4.3.0 2.0.0-* 4.7.1 - 1.6.1 - 2.0.0-* 15.0.0 2.2.0 - \ No newline at end of file + From d2122ea7d7e5a85678b0bd3d4e977ff43456c82b Mon Sep 17 00:00:00 2001 From: Pranav K Date: Tue, 25 Apr 2017 22:00:43 -0700 Subject: [PATCH 189/307] Branching for 2.0.0-preview1 --- NuGet.config | 2 +- build.ps1 | 2 +- build.sh | 2 +- build/dependencies.props | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/NuGet.config b/NuGet.config index 8e65695611..fa4304af9c 100644 --- a/NuGet.config +++ b/NuGet.config @@ -1,7 +1,7 @@ - + diff --git a/build.ps1 b/build.ps1 index 5bf0e2c113..225b1fe450 100644 --- a/build.ps1 +++ b/build.ps1 @@ -33,7 +33,7 @@ cd $PSScriptRoot $repoFolder = $PSScriptRoot $env:REPO_FOLDER = $repoFolder -$koreBuildZip="https://github.com/aspnet/KoreBuild/archive/dev.zip" +$koreBuildZip="https://github.com/aspnet/KoreBuild/archive/rel/2.0.0-preview1.zip" if ($env:KOREBUILD_ZIP) { $koreBuildZip=$env:KOREBUILD_ZIP diff --git a/build.sh b/build.sh index b0bcadb579..702b25c636 100755 --- a/build.sh +++ b/build.sh @@ -2,7 +2,7 @@ repoFolder="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" cd $repoFolder -koreBuildZip="https://github.com/aspnet/KoreBuild/archive/dev.zip" +koreBuildZip="https://github.com/aspnet/KoreBuild/archive/rel/2.0.0-preview1.zip" if [ ! -z $KOREBUILD_ZIP ]; then koreBuildZip=$KOREBUILD_ZIP fi diff --git a/build/dependencies.props b/build/dependencies.props index 8587abb455..61dccd8321 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -1,6 +1,6 @@ - 2.0.0-* + 2.0.0-preview1-* 4.3.0 2.0.0-* 4.7.1 From 3aa2d49ffd76d3f91882fa273c76cfa4bb02728c Mon Sep 17 00:00:00 2001 From: Pranav K Date: Wed, 26 Apr 2017 07:12:33 -0700 Subject: [PATCH 190/307] Updating package version to preview2 --- version.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.props b/version.props index 68a61ffe6e..cf71e822fe 100644 --- a/version.props +++ b/version.props @@ -1,6 +1,6 @@ - preview1 + preview2 From 5e82e3fdc84c7ed23d28bb3c9e85a6d33e300f8c Mon Sep 17 00:00:00 2001 From: Pranav K Date: Mon, 1 May 2017 12:38:54 -0700 Subject: [PATCH 191/307] Use the bundled NETStandard.Library package in netstandard targeting libraries --- build/dependencies.props | 1 + 1 file changed, 1 insertion(+) diff --git a/build/dependencies.props b/build/dependencies.props index 61dccd8321..50283ae2ae 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -4,6 +4,7 @@ 4.3.0 2.0.0-* 4.7.1 + $(BundledNETStandardPackageVersion) 15.0.0 2.2.0 From 5c4cf91984acad75f58a967e49bb75cac5135b8d Mon Sep 17 00:00:00 2001 From: Pavel Krymets Date: Fri, 5 May 2017 10:12:32 -0700 Subject: [PATCH 192/307] Update InternalAspNetCoreSdkVersion --- build/dependencies.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/dependencies.props b/build/dependencies.props index 50283ae2ae..a353b25211 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -2,7 +2,7 @@ 2.0.0-preview1-* 4.3.0 - 2.0.0-* + 2.1.0-* 4.7.1 $(BundledNETStandardPackageVersion) 15.0.0 From 733e24f9bc8b060993b8fd46fcf1a2b0ec859eb3 Mon Sep 17 00:00:00 2001 From: Pavel Krymets Date: Fri, 5 May 2017 12:01:15 -0700 Subject: [PATCH 193/307] netcoreapp2.0 (#228) --- .../HttpOverridesSample/HttpOverridesSample.csproj | 2 +- .../ResponseBufferingSample.csproj | 2 +- .../ResponseCompressionSample.csproj | 2 +- samples/RewriteSample/RewriteSample.csproj | 2 +- .../BufferingWriteStream.cs | 7 ++----- .../Microsoft.AspNetCore.Buffering.csproj | 2 +- .../Microsoft.AspNetCore.HttpOverrides.csproj | 2 +- .../BodyWrapperStream.cs | 5 ----- .../CompressionProviderCollection.cs | 3 --- .../GzipCompressionProvider.cs | 6 ------ ...Microsoft.AspNetCore.ResponseCompression.csproj | 2 +- .../Microsoft.AspNetCore.Rewrite.csproj | 2 +- .../Microsoft.AspNetCore.Buffering.Tests.csproj | 5 +---- ...Microsoft.AspNetCore.HttpOverrides.Tests.csproj | 5 +---- .../BodyWrapperStreamTests.cs | 5 ----- ...oft.AspNetCore.ResponseCompression.Tests.csproj | 5 +---- .../ResponseCompressionMiddlewareTest.cs | 14 -------------- .../Microsoft.AspNetCore.Rewrite.Tests.csproj | 5 +---- 18 files changed, 14 insertions(+), 62 deletions(-) diff --git a/samples/HttpOverridesSample/HttpOverridesSample.csproj b/samples/HttpOverridesSample/HttpOverridesSample.csproj index c163d00c5f..a81f0815c1 100644 --- a/samples/HttpOverridesSample/HttpOverridesSample.csproj +++ b/samples/HttpOverridesSample/HttpOverridesSample.csproj @@ -3,7 +3,7 @@ - net46;netcoreapp2.0 + netcoreapp2.0 diff --git a/samples/ResponseBufferingSample/ResponseBufferingSample.csproj b/samples/ResponseBufferingSample/ResponseBufferingSample.csproj index 0a99f5017f..cec354e0f9 100644 --- a/samples/ResponseBufferingSample/ResponseBufferingSample.csproj +++ b/samples/ResponseBufferingSample/ResponseBufferingSample.csproj @@ -3,7 +3,7 @@ - net46;netcoreapp2.0 + netcoreapp2.0 diff --git a/samples/ResponseCompressionSample/ResponseCompressionSample.csproj b/samples/ResponseCompressionSample/ResponseCompressionSample.csproj index 37e37f9c6c..7de989af16 100644 --- a/samples/ResponseCompressionSample/ResponseCompressionSample.csproj +++ b/samples/ResponseCompressionSample/ResponseCompressionSample.csproj @@ -3,7 +3,7 @@ - net46;netcoreapp2.0 + netcoreapp2.0 diff --git a/samples/RewriteSample/RewriteSample.csproj b/samples/RewriteSample/RewriteSample.csproj index 8dc059dc1d..a63cca0480 100644 --- a/samples/RewriteSample/RewriteSample.csproj +++ b/samples/RewriteSample/RewriteSample.csproj @@ -3,7 +3,7 @@ - net46;netcoreapp2.0 + netcoreapp2.0 diff --git a/src/Microsoft.AspNetCore.Buffering/BufferingWriteStream.cs b/src/Microsoft.AspNetCore.Buffering/BufferingWriteStream.cs index 29ab23bde2..b81b70922b 100644 --- a/src/Microsoft.AspNetCore.Buffering/BufferingWriteStream.cs +++ b/src/Microsoft.AspNetCore.Buffering/BufferingWriteStream.cs @@ -160,7 +160,7 @@ namespace Microsoft.AspNetCore.Buffering return _innerStream.WriteAsync(buffer, offset, count, cancellationToken); } } -#if NET46 + public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object state) { if (_isBuffering) @@ -184,10 +184,7 @@ namespace Microsoft.AspNetCore.Buffering _innerStream.EndWrite(asyncResult); } } -#elif NETSTANDARD1_3 -#else -#error target frameworks need to be updated -#endif + public override void Flush() { _isBuffering = false; diff --git a/src/Microsoft.AspNetCore.Buffering/Microsoft.AspNetCore.Buffering.csproj b/src/Microsoft.AspNetCore.Buffering/Microsoft.AspNetCore.Buffering.csproj index 658f4a836d..36915fa214 100644 --- a/src/Microsoft.AspNetCore.Buffering/Microsoft.AspNetCore.Buffering.csproj +++ b/src/Microsoft.AspNetCore.Buffering/Microsoft.AspNetCore.Buffering.csproj @@ -5,7 +5,7 @@ 0.3.0 ASP.NET Core middleware for buffering response bodies. - net46;netstandard1.3 + netcoreapp2.0 $(NoWarn);CS1591 true aspnetcore;buffer;buffering diff --git a/src/Microsoft.AspNetCore.HttpOverrides/Microsoft.AspNetCore.HttpOverrides.csproj b/src/Microsoft.AspNetCore.HttpOverrides/Microsoft.AspNetCore.HttpOverrides.csproj index ab49dd26db..01cfb31fd3 100644 --- a/src/Microsoft.AspNetCore.HttpOverrides/Microsoft.AspNetCore.HttpOverrides.csproj +++ b/src/Microsoft.AspNetCore.HttpOverrides/Microsoft.AspNetCore.HttpOverrides.csproj @@ -7,7 +7,7 @@ ASP.NET Core basic middleware for supporting HTTP method overrides. Includes: * X-Forwarded-* headers to forward headers from a proxy. * HTTP method override header. - netstandard1.3 + netcoreapp2.0 $(NoWarn);CS1591 true aspnetcore;proxy;headers;xforwarded diff --git a/src/Microsoft.AspNetCore.ResponseCompression/BodyWrapperStream.cs b/src/Microsoft.AspNetCore.ResponseCompression/BodyWrapperStream.cs index ff25fe8b71..d315d82dfa 100644 --- a/src/Microsoft.AspNetCore.ResponseCompression/BodyWrapperStream.cs +++ b/src/Microsoft.AspNetCore.ResponseCompression/BodyWrapperStream.cs @@ -137,7 +137,6 @@ namespace Microsoft.AspNetCore.ResponseCompression } } -#if NET46 public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, Object state) { var tcs = new TaskCompletionSource(state); @@ -184,10 +183,6 @@ namespace Microsoft.AspNetCore.ResponseCompression var task = (Task)asyncResult; task.GetAwaiter().GetResult(); } -#elif NETSTANDARD1_3 -#else -#error target frameworks need to be updated -#endif public override async Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) { diff --git a/src/Microsoft.AspNetCore.ResponseCompression/CompressionProviderCollection.cs b/src/Microsoft.AspNetCore.ResponseCompression/CompressionProviderCollection.cs index a04e920922..e4d15ef5b7 100644 --- a/src/Microsoft.AspNetCore.ResponseCompression/CompressionProviderCollection.cs +++ b/src/Microsoft.AspNetCore.ResponseCompression/CompressionProviderCollection.cs @@ -3,9 +3,6 @@ using System; using System.Collections.ObjectModel; -#if NETSTANDARD1_3 -using System.Reflection; -#endif namespace Microsoft.AspNetCore.ResponseCompression { diff --git a/src/Microsoft.AspNetCore.ResponseCompression/GzipCompressionProvider.cs b/src/Microsoft.AspNetCore.ResponseCompression/GzipCompressionProvider.cs index 0588995dd5..b7716f1746 100644 --- a/src/Microsoft.AspNetCore.ResponseCompression/GzipCompressionProvider.cs +++ b/src/Microsoft.AspNetCore.ResponseCompression/GzipCompressionProvider.cs @@ -37,13 +37,7 @@ namespace Microsoft.AspNetCore.ResponseCompression { get { -#if NET46 - return false; -#elif NETSTANDARD1_3 return true; -#else -#error target frameworks need to be updated -#endif } } diff --git a/src/Microsoft.AspNetCore.ResponseCompression/Microsoft.AspNetCore.ResponseCompression.csproj b/src/Microsoft.AspNetCore.ResponseCompression/Microsoft.AspNetCore.ResponseCompression.csproj index 80e48518c7..fc5f1b53b6 100644 --- a/src/Microsoft.AspNetCore.ResponseCompression/Microsoft.AspNetCore.ResponseCompression.csproj +++ b/src/Microsoft.AspNetCore.ResponseCompression/Microsoft.AspNetCore.ResponseCompression.csproj @@ -5,7 +5,7 @@ 2.0.0 ASP.NET Core middleware for HTTP Response compression. - net46;netstandard1.3 + netcoreapp2.0 true aspnetcore diff --git a/src/Microsoft.AspNetCore.Rewrite/Microsoft.AspNetCore.Rewrite.csproj b/src/Microsoft.AspNetCore.Rewrite/Microsoft.AspNetCore.Rewrite.csproj index 028eaeaa9c..530e010f35 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Microsoft.AspNetCore.Rewrite.csproj +++ b/src/Microsoft.AspNetCore.Rewrite/Microsoft.AspNetCore.Rewrite.csproj @@ -8,7 +8,7 @@ * Support for custom URL rewrite rules * Support for running IIS URL Rewrite module rules * Support for running Apache mod_rewrite rules. - netstandard1.3 + netcoreapp2.0 $(NoWarn);CS1591 true aspnetcore;urlrewrite;mod_rewrite diff --git a/test/Microsoft.AspNetCore.Buffering.Tests/Microsoft.AspNetCore.Buffering.Tests.csproj b/test/Microsoft.AspNetCore.Buffering.Tests/Microsoft.AspNetCore.Buffering.Tests.csproj index 2af1f9b194..1a2e0b4be2 100644 --- a/test/Microsoft.AspNetCore.Buffering.Tests/Microsoft.AspNetCore.Buffering.Tests.csproj +++ b/test/Microsoft.AspNetCore.Buffering.Tests/Microsoft.AspNetCore.Buffering.Tests.csproj @@ -3,10 +3,7 @@ - netcoreapp2.0;net46 - netcoreapp2.0 - true - true + netcoreapp2.0 diff --git a/test/Microsoft.AspNetCore.HttpOverrides.Tests/Microsoft.AspNetCore.HttpOverrides.Tests.csproj b/test/Microsoft.AspNetCore.HttpOverrides.Tests/Microsoft.AspNetCore.HttpOverrides.Tests.csproj index b525b8926b..2b04e2965c 100644 --- a/test/Microsoft.AspNetCore.HttpOverrides.Tests/Microsoft.AspNetCore.HttpOverrides.Tests.csproj +++ b/test/Microsoft.AspNetCore.HttpOverrides.Tests/Microsoft.AspNetCore.HttpOverrides.Tests.csproj @@ -3,10 +3,7 @@ - netcoreapp2.0;net46 - netcoreapp2.0 - true - true + netcoreapp2.0 diff --git a/test/Microsoft.AspNetCore.ResponseCompression.Tests/BodyWrapperStreamTests.cs b/test/Microsoft.AspNetCore.ResponseCompression.Tests/BodyWrapperStreamTests.cs index a1efd4a458..46c7fb46d3 100644 --- a/test/Microsoft.AspNetCore.ResponseCompression.Tests/BodyWrapperStreamTests.cs +++ b/test/Microsoft.AspNetCore.ResponseCompression.Tests/BodyWrapperStreamTests.cs @@ -108,7 +108,6 @@ namespace Microsoft.AspNetCore.ResponseCompression.Tests Assert.Equal(File.ReadAllBytes(path), written); } -#if NET46 [Theory] [InlineData(true)] [InlineData(false)] @@ -133,10 +132,6 @@ namespace Microsoft.AspNetCore.ResponseCompression.Tests Assert.Equal(buffer, written); } -#elif NETCOREAPP2_0 -#else -#error Target framework needs to be updated -#endif private class MockResponseCompressionProvider: IResponseCompressionProvider { diff --git a/test/Microsoft.AspNetCore.ResponseCompression.Tests/Microsoft.AspNetCore.ResponseCompression.Tests.csproj b/test/Microsoft.AspNetCore.ResponseCompression.Tests/Microsoft.AspNetCore.ResponseCompression.Tests.csproj index 27ab922297..faf0649719 100644 --- a/test/Microsoft.AspNetCore.ResponseCompression.Tests/Microsoft.AspNetCore.ResponseCompression.Tests.csproj +++ b/test/Microsoft.AspNetCore.ResponseCompression.Tests/Microsoft.AspNetCore.ResponseCompression.Tests.csproj @@ -3,10 +3,7 @@ - netcoreapp2.0;net46 - netcoreapp2.0 - true - true + netcoreapp2.0 diff --git a/test/Microsoft.AspNetCore.ResponseCompression.Tests/ResponseCompressionMiddlewareTest.cs b/test/Microsoft.AspNetCore.ResponseCompression.Tests/ResponseCompressionMiddlewareTest.cs index 34fd5f2c83..4fa7b92ed6 100644 --- a/test/Microsoft.AspNetCore.ResponseCompression.Tests/ResponseCompressionMiddlewareTest.cs +++ b/test/Microsoft.AspNetCore.ResponseCompression.Tests/ResponseCompressionMiddlewareTest.cs @@ -505,16 +505,9 @@ namespace Microsoft.AspNetCore.ResponseCompression.Tests var response = await client.SendAsync(request, HttpCompletionOption.ResponseHeadersRead); -#if NET46 // Flush not supported, compression disabled - Assert.NotNull(response.Headers.GetValues(HeaderNames.ContentMD5)); - Assert.Empty(response.Content.Headers.ContentEncoding); -#elif NETCOREAPP2_0 // Flush supported, compression enabled IEnumerable contentMD5 = null; Assert.False(response.Headers.TryGetValues(HeaderNames.ContentMD5, out contentMD5)); Assert.Single(response.Content.Headers.ContentEncoding, "gzip"); -#else -#error Target frameworks need to be updated. -#endif var body = await response.Content.ReadAsStreamAsync(); @@ -570,16 +563,9 @@ namespace Microsoft.AspNetCore.ResponseCompression.Tests var response = await client.SendAsync(request, HttpCompletionOption.ResponseHeadersRead); -#if NET46 // Flush not supported, compression disabled - Assert.NotNull(response.Headers.GetValues(HeaderNames.ContentMD5)); - Assert.Empty(response.Content.Headers.ContentEncoding); -#elif NETCOREAPP2_0 // Flush supported, compression enabled IEnumerable contentMD5 = null; Assert.False(response.Headers.TryGetValues(HeaderNames.ContentMD5, out contentMD5)); Assert.Single(response.Content.Headers.ContentEncoding, "gzip"); -#else -#error Target framework needs to be updated -#endif var body = await response.Content.ReadAsStreamAsync(); diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/Microsoft.AspNetCore.Rewrite.Tests.csproj b/test/Microsoft.AspNetCore.Rewrite.Tests/Microsoft.AspNetCore.Rewrite.Tests.csproj index 79c1c1c298..bbff9efe12 100644 --- a/test/Microsoft.AspNetCore.Rewrite.Tests/Microsoft.AspNetCore.Rewrite.Tests.csproj +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/Microsoft.AspNetCore.Rewrite.Tests.csproj @@ -3,10 +3,7 @@ - netcoreapp2.0;net46 - netcoreapp2.0 - true - true + netcoreapp2.0 From 2181158eb51be97b88ce00085edfd96684ec87a5 Mon Sep 17 00:00:00 2001 From: "Chris Ross (ASP.NET)" Date: Tue, 9 May 2017 09:07:09 -0700 Subject: [PATCH 194/307] React to Content-Md5 fix --- .../ResponseCompressionMiddlewareTest.cs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/test/Microsoft.AspNetCore.ResponseCompression.Tests/ResponseCompressionMiddlewareTest.cs b/test/Microsoft.AspNetCore.ResponseCompression.Tests/ResponseCompressionMiddlewareTest.cs index 4fa7b92ed6..7b77fea061 100644 --- a/test/Microsoft.AspNetCore.ResponseCompression.Tests/ResponseCompressionMiddlewareTest.cs +++ b/test/Microsoft.AspNetCore.ResponseCompression.Tests/ResponseCompressionMiddlewareTest.cs @@ -402,7 +402,7 @@ namespace Microsoft.AspNetCore.ResponseCompression.Tests var response = await client.SendAsync(request, HttpCompletionOption.ResponseHeadersRead); IEnumerable contentMD5 = null; - Assert.False(response.Headers.TryGetValues(HeaderNames.ContentMD5, out contentMD5)); + Assert.False(response.Content.Headers.TryGetValues(HeaderNames.ContentMD5, out contentMD5)); Assert.Single(response.Content.Headers.ContentEncoding, "gzip"); var body = await response.Content.ReadAsStreamAsync(); @@ -448,7 +448,7 @@ namespace Microsoft.AspNetCore.ResponseCompression.Tests var response = await client.SendAsync(request, HttpCompletionOption.ResponseHeadersRead); IEnumerable contentMD5 = null; - Assert.False(response.Headers.TryGetValues(HeaderNames.ContentMD5, out contentMD5)); + Assert.False(response.Content.Headers.TryGetValues(HeaderNames.ContentMD5, out contentMD5)); Assert.Single(response.Content.Headers.ContentEncoding, "gzip"); var body = await response.Content.ReadAsStreamAsync(); @@ -506,7 +506,7 @@ namespace Microsoft.AspNetCore.ResponseCompression.Tests var response = await client.SendAsync(request, HttpCompletionOption.ResponseHeadersRead); IEnumerable contentMD5 = null; - Assert.False(response.Headers.TryGetValues(HeaderNames.ContentMD5, out contentMD5)); + Assert.False(response.Content.Headers.TryGetValues(HeaderNames.ContentMD5, out contentMD5)); Assert.Single(response.Content.Headers.ContentEncoding, "gzip"); var body = await response.Content.ReadAsStreamAsync(); @@ -564,7 +564,7 @@ namespace Microsoft.AspNetCore.ResponseCompression.Tests var response = await client.SendAsync(request, HttpCompletionOption.ResponseHeadersRead); IEnumerable contentMD5 = null; - Assert.False(response.Headers.TryGetValues(HeaderNames.ContentMD5, out contentMD5)); + Assert.False(response.Content.Headers.TryGetValues(HeaderNames.ContentMD5, out contentMD5)); Assert.Single(response.Content.Headers.ContentEncoding, "gzip"); var body = await response.Content.ReadAsStreamAsync(); @@ -789,7 +789,7 @@ namespace Microsoft.AspNetCore.ResponseCompression.Tests } } Assert.True(containsVaryAcceptEncoding); - Assert.False(response.Headers.TryGetValues(HeaderNames.ContentMD5, out contentMD5)); + Assert.False(response.Content.Headers.TryGetValues(HeaderNames.ContentMD5, out contentMD5)); Assert.Single(response.Content.Headers.ContentEncoding, "gzip"); Assert.Equal(expectedBodyLength, response.Content.Headers.ContentLength); } @@ -813,7 +813,7 @@ namespace Microsoft.AspNetCore.ResponseCompression.Tests { Assert.False(response.Headers.Contains(HeaderNames.Vary)); } - Assert.NotNull(response.Headers.GetValues(HeaderNames.ContentMD5)); + Assert.NotNull(response.Content.Headers.GetValues(HeaderNames.ContentMD5)); Assert.Empty(response.Content.Headers.ContentEncoding); Assert.Equal(expectedBodyLength, response.Content.Headers.ContentLength); } From 08a8493ecc2681668b5a1fff49add9c4c0d8dde0 Mon Sep 17 00:00:00 2001 From: Pavel Krymets Date: Wed, 10 May 2017 11:30:17 -0700 Subject: [PATCH 195/307] Remove unnecessary package references (#230) --- build/dependencies.props | 1 - 1 file changed, 1 deletion(-) diff --git a/build/dependencies.props b/build/dependencies.props index 8738a88691..0a6c8d6eb5 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -1,7 +1,6 @@ 2.0.0-* - 4.3.0 2.1.0-* 4.7.1 $(BundledNETStandardPackageVersion) From 5b4299d4df52553ba4415947dbd8613f40f79eed Mon Sep 17 00:00:00 2001 From: Nate McMaster Date: Fri, 12 May 2017 16:50:59 -0700 Subject: [PATCH 196/307] Update test framework versions and fix test issues --- build/dependencies.props | 4 ++-- .../IPEndPointParserTest.cs | 5 +++-- .../IISUrlRewrite/MiddleWareTests.cs | 8 ++++---- .../IISUrlRewrite/UrlRewriteApplicationTests.cs | 6 +++--- .../Microsoft.AspNetCore.Rewrite.Tests/MiddlewareTests.cs | 6 +++--- 5 files changed, 15 insertions(+), 14 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index 0a6c8d6eb5..226b77c333 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -4,7 +4,7 @@ 2.1.0-* 4.7.1 $(BundledNETStandardPackageVersion) - 15.0.0 - 2.2.0 + 15.3.0-* + 2.3.0-beta2-* diff --git a/test/Microsoft.AspNetCore.HttpOverrides.Tests/IPEndPointParserTest.cs b/test/Microsoft.AspNetCore.HttpOverrides.Tests/IPEndPointParserTest.cs index f5106bd2a7..11d13c401d 100644 --- a/test/Microsoft.AspNetCore.HttpOverrides.Tests/IPEndPointParserTest.cs +++ b/test/Microsoft.AspNetCore.HttpOverrides.Tests/IPEndPointParserTest.cs @@ -25,6 +25,7 @@ namespace Microsoft.AspNetCore.HttpOverrides.Internal Assert.Equal(expectedPort, endpoint.Port); } + [Theory] [InlineData(null)] [InlineData("[::1]:")] [InlineData("[::1:")] @@ -40,7 +41,7 @@ namespace Microsoft.AspNetCore.HttpOverrides.Internal IPEndPoint endpoint; var success = IPEndPointParser.TryParse(input, out endpoint); Assert.False(success); - Assert.Equal(null, endpoint); + Assert.Null(endpoint); } } -} \ No newline at end of file +} diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/MiddleWareTests.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/MiddleWareTests.cs index 542cd88060..ce146b1df1 100644 --- a/test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/MiddleWareTests.cs +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/MiddleWareTests.cs @@ -342,7 +342,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite var response = await server.CreateClient().GetAsync(""); - Assert.Equal(response.Headers.Location.OriginalString, "/foo"); + Assert.Equal("/foo", response.Headers.Location.OriginalString); } [Theory] @@ -570,7 +570,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite var condition = new UriMatchCondition( inputParser, "{REQUEST_URI}", - conditionInputPattern, + conditionInputPattern, uriMatchPart, ignoreCase: true, negate: false); @@ -578,8 +578,8 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite ruleBuilder.AddUrlCondition(condition); var action = new RewriteAction( - RuleResult.SkipRemainingRules, - inputParser.ParseInputString(@"http://www.test.com{C:1}", uriMatchPart), + RuleResult.SkipRemainingRules, + inputParser.ParseInputString(@"http://www.test.com{C:1}", uriMatchPart), queryStringAppend: false); ruleBuilder.AddUrlAction(action); diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/UrlRewriteApplicationTests.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/UrlRewriteApplicationTests.cs index ff9e9f8a59..ecc753a620 100644 --- a/test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/UrlRewriteApplicationTests.cs +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/UrlRewriteApplicationTests.cs @@ -25,7 +25,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite "); var rules = new UrlRewriteFileParser().Parse(xml); - Assert.Equal(rules.Count, 1); + Assert.Equal(1, rules.Count); var context = new RewriteContext { HttpContext = new DefaultHttpContext() }; rules.FirstOrDefault().ApplyRule(context); Assert.Equal(RuleResult.SkipRemainingRules, context.Result); @@ -44,7 +44,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite "); var rules = new UrlRewriteFileParser().Parse(xml); - Assert.Equal(rules.Count, 1); + Assert.Equal(1, rules.Count); var context = new RewriteContext { HttpContext = new DefaultHttpContext() }; rules.FirstOrDefault().ApplyRule(context); Assert.Equal(RuleResult.ContinueRules, context.Result); @@ -66,7 +66,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite "); var rules = new UrlRewriteFileParser().Parse(xml); - Assert.Equal(rules.Count, 1); + Assert.Equal(1, rules.Count); Assert.True(rules[0].Conditions.TrackAllCaptures); var context = new RewriteContext { HttpContext = new DefaultHttpContext() }; rules.FirstOrDefault().ApplyRule(context); diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/MiddlewareTests.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/MiddlewareTests.cs index 74f4e599d8..137448b1e7 100644 --- a/test/Microsoft.AspNetCore.Rewrite.Tests/MiddlewareTests.cs +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/MiddlewareTests.cs @@ -120,7 +120,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.CodeRules var server = new TestServer(builder); var response = await server.CreateClient().GetAsync(""); - Assert.Equal(response.Headers.Location.OriginalString, "/"); + Assert.Equal("/", response.Headers.Location.OriginalString); } [Fact] @@ -139,7 +139,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.CodeRules var response = await server.CreateClient().GetStringAsync(""); - Assert.Equal(response, "/"); + Assert.Equal("/", response); } [Fact] @@ -158,7 +158,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.CodeRules var response = await server.CreateClient().GetAsync(""); - Assert.Equal(response.Headers.Location.OriginalString, "/foo"); + Assert.Equal("/foo", response.Headers.Location.OriginalString); } } } From 565b94e3afceb5c972a6343d8a286d89ed3edc6f Mon Sep 17 00:00:00 2001 From: Ajay Bhargav Baaskaran Date: Fri, 19 May 2017 17:05:50 -0700 Subject: [PATCH 197/307] Target .NET Standard 2.0 --- build/common.props | 4 ++-- build/dependencies.props | 2 +- samples/HttpOverridesSample/HttpOverridesSample.csproj | 3 ++- .../ResponseBufferingSample/ResponseBufferingSample.csproj | 3 ++- .../ResponseCompressionSample.csproj | 3 ++- samples/RewriteSample/RewriteSample.csproj | 3 ++- .../Microsoft.AspNetCore.Buffering.csproj | 2 +- .../Microsoft.AspNetCore.HttpOverrides.csproj | 2 +- .../Microsoft.AspNetCore.ResponseCompression.csproj | 2 +- .../Microsoft.AspNetCore.Rewrite.csproj | 2 +- .../Microsoft.AspNetCore.Buffering.Tests.csproj | 3 ++- .../Microsoft.AspNetCore.HttpOverrides.Tests.csproj | 3 ++- .../Microsoft.AspNetCore.ResponseCompression.Tests.csproj | 3 ++- .../Microsoft.AspNetCore.Rewrite.Tests.csproj | 3 ++- 14 files changed, 23 insertions(+), 15 deletions(-) diff --git a/build/common.props b/build/common.props index 2d92eff547..1f336eb45d 100644 --- a/build/common.props +++ b/build/common.props @@ -16,8 +16,8 @@ - - + + diff --git a/build/dependencies.props b/build/dependencies.props index 226b77c333..1a75c90b26 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -3,7 +3,7 @@ 2.0.0-* 2.1.0-* 4.7.1 - $(BundledNETStandardPackageVersion) + 2.0.0-* 15.3.0-* 2.3.0-beta2-* diff --git a/samples/HttpOverridesSample/HttpOverridesSample.csproj b/samples/HttpOverridesSample/HttpOverridesSample.csproj index a81f0815c1..9c8dc4616a 100644 --- a/samples/HttpOverridesSample/HttpOverridesSample.csproj +++ b/samples/HttpOverridesSample/HttpOverridesSample.csproj @@ -3,7 +3,8 @@ - netcoreapp2.0 + net461;netcoreapp2.0 + netcoreapp2.0 diff --git a/samples/ResponseBufferingSample/ResponseBufferingSample.csproj b/samples/ResponseBufferingSample/ResponseBufferingSample.csproj index cec354e0f9..f0aa4a439a 100644 --- a/samples/ResponseBufferingSample/ResponseBufferingSample.csproj +++ b/samples/ResponseBufferingSample/ResponseBufferingSample.csproj @@ -3,7 +3,8 @@ - netcoreapp2.0 + net461;netcoreapp2.0 + netcoreapp2.0 diff --git a/samples/ResponseCompressionSample/ResponseCompressionSample.csproj b/samples/ResponseCompressionSample/ResponseCompressionSample.csproj index 7de989af16..a5792ad3e8 100644 --- a/samples/ResponseCompressionSample/ResponseCompressionSample.csproj +++ b/samples/ResponseCompressionSample/ResponseCompressionSample.csproj @@ -3,7 +3,8 @@ - netcoreapp2.0 + net461;netcoreapp2.0 + netcoreapp2.0 diff --git a/samples/RewriteSample/RewriteSample.csproj b/samples/RewriteSample/RewriteSample.csproj index a63cca0480..f9c78e7131 100644 --- a/samples/RewriteSample/RewriteSample.csproj +++ b/samples/RewriteSample/RewriteSample.csproj @@ -3,7 +3,8 @@ - netcoreapp2.0 + net461;netcoreapp2.0 + netcoreapp2.0 diff --git a/src/Microsoft.AspNetCore.Buffering/Microsoft.AspNetCore.Buffering.csproj b/src/Microsoft.AspNetCore.Buffering/Microsoft.AspNetCore.Buffering.csproj index 36915fa214..545b87b140 100644 --- a/src/Microsoft.AspNetCore.Buffering/Microsoft.AspNetCore.Buffering.csproj +++ b/src/Microsoft.AspNetCore.Buffering/Microsoft.AspNetCore.Buffering.csproj @@ -5,7 +5,7 @@ 0.3.0 ASP.NET Core middleware for buffering response bodies. - netcoreapp2.0 + netstandard2.0 $(NoWarn);CS1591 true aspnetcore;buffer;buffering diff --git a/src/Microsoft.AspNetCore.HttpOverrides/Microsoft.AspNetCore.HttpOverrides.csproj b/src/Microsoft.AspNetCore.HttpOverrides/Microsoft.AspNetCore.HttpOverrides.csproj index 01cfb31fd3..5ebd793c2d 100644 --- a/src/Microsoft.AspNetCore.HttpOverrides/Microsoft.AspNetCore.HttpOverrides.csproj +++ b/src/Microsoft.AspNetCore.HttpOverrides/Microsoft.AspNetCore.HttpOverrides.csproj @@ -7,7 +7,7 @@ ASP.NET Core basic middleware for supporting HTTP method overrides. Includes: * X-Forwarded-* headers to forward headers from a proxy. * HTTP method override header. - netcoreapp2.0 + netstandard2.0 $(NoWarn);CS1591 true aspnetcore;proxy;headers;xforwarded diff --git a/src/Microsoft.AspNetCore.ResponseCompression/Microsoft.AspNetCore.ResponseCompression.csproj b/src/Microsoft.AspNetCore.ResponseCompression/Microsoft.AspNetCore.ResponseCompression.csproj index fc5f1b53b6..d87066a572 100644 --- a/src/Microsoft.AspNetCore.ResponseCompression/Microsoft.AspNetCore.ResponseCompression.csproj +++ b/src/Microsoft.AspNetCore.ResponseCompression/Microsoft.AspNetCore.ResponseCompression.csproj @@ -5,7 +5,7 @@ 2.0.0 ASP.NET Core middleware for HTTP Response compression. - netcoreapp2.0 + netstandard2.0 true aspnetcore diff --git a/src/Microsoft.AspNetCore.Rewrite/Microsoft.AspNetCore.Rewrite.csproj b/src/Microsoft.AspNetCore.Rewrite/Microsoft.AspNetCore.Rewrite.csproj index 530e010f35..c3577cb2e8 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Microsoft.AspNetCore.Rewrite.csproj +++ b/src/Microsoft.AspNetCore.Rewrite/Microsoft.AspNetCore.Rewrite.csproj @@ -8,7 +8,7 @@ * Support for custom URL rewrite rules * Support for running IIS URL Rewrite module rules * Support for running Apache mod_rewrite rules. - netcoreapp2.0 + netstandard2.0 $(NoWarn);CS1591 true aspnetcore;urlrewrite;mod_rewrite diff --git a/test/Microsoft.AspNetCore.Buffering.Tests/Microsoft.AspNetCore.Buffering.Tests.csproj b/test/Microsoft.AspNetCore.Buffering.Tests/Microsoft.AspNetCore.Buffering.Tests.csproj index 1a2e0b4be2..84ce6801da 100644 --- a/test/Microsoft.AspNetCore.Buffering.Tests/Microsoft.AspNetCore.Buffering.Tests.csproj +++ b/test/Microsoft.AspNetCore.Buffering.Tests/Microsoft.AspNetCore.Buffering.Tests.csproj @@ -3,7 +3,8 @@ - netcoreapp2.0 + net461;netcoreapp2.0 + netcoreapp2.0 diff --git a/test/Microsoft.AspNetCore.HttpOverrides.Tests/Microsoft.AspNetCore.HttpOverrides.Tests.csproj b/test/Microsoft.AspNetCore.HttpOverrides.Tests/Microsoft.AspNetCore.HttpOverrides.Tests.csproj index 2b04e2965c..2cb29a9fca 100644 --- a/test/Microsoft.AspNetCore.HttpOverrides.Tests/Microsoft.AspNetCore.HttpOverrides.Tests.csproj +++ b/test/Microsoft.AspNetCore.HttpOverrides.Tests/Microsoft.AspNetCore.HttpOverrides.Tests.csproj @@ -3,7 +3,8 @@ - netcoreapp2.0 + net461;netcoreapp2.0 + netcoreapp2.0 diff --git a/test/Microsoft.AspNetCore.ResponseCompression.Tests/Microsoft.AspNetCore.ResponseCompression.Tests.csproj b/test/Microsoft.AspNetCore.ResponseCompression.Tests/Microsoft.AspNetCore.ResponseCompression.Tests.csproj index faf0649719..c689c1b6f0 100644 --- a/test/Microsoft.AspNetCore.ResponseCompression.Tests/Microsoft.AspNetCore.ResponseCompression.Tests.csproj +++ b/test/Microsoft.AspNetCore.ResponseCompression.Tests/Microsoft.AspNetCore.ResponseCompression.Tests.csproj @@ -3,7 +3,8 @@ - netcoreapp2.0 + net461;netcoreapp2.0 + netcoreapp2.0 diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/Microsoft.AspNetCore.Rewrite.Tests.csproj b/test/Microsoft.AspNetCore.Rewrite.Tests/Microsoft.AspNetCore.Rewrite.Tests.csproj index bbff9efe12..5d5d66e3a6 100644 --- a/test/Microsoft.AspNetCore.Rewrite.Tests/Microsoft.AspNetCore.Rewrite.Tests.csproj +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/Microsoft.AspNetCore.Rewrite.Tests.csproj @@ -3,7 +3,8 @@ - netcoreapp2.0 + net461;netcoreapp2.0 + netcoreapp2.0 From 8b506cf36c85197a9b5bec4cf11d91be31ca06ae Mon Sep 17 00:00:00 2001 From: John Luo Date: Sat, 20 May 2017 11:58:55 -0700 Subject: [PATCH 198/307] Cross-compile Response Compression - GZipStream is not flushable on .NET Framework --- .../HttpOverridesSample/HttpOverridesSample.csproj | 4 ++++ .../ResponseBufferingSample.csproj | 4 ++++ .../ResponseCompressionSample.csproj | 4 ++++ samples/RewriteSample/RewriteSample.csproj | 4 ++++ .../GzipCompressionProvider.cs | 6 ++++++ ...Microsoft.AspNetCore.ResponseCompression.csproj | 2 +- .../ResponseCompressionMiddlewareTest.cs | 14 ++++++++++++++ 7 files changed, 37 insertions(+), 1 deletion(-) diff --git a/samples/HttpOverridesSample/HttpOverridesSample.csproj b/samples/HttpOverridesSample/HttpOverridesSample.csproj index 9c8dc4616a..5caa62c82e 100644 --- a/samples/HttpOverridesSample/HttpOverridesSample.csproj +++ b/samples/HttpOverridesSample/HttpOverridesSample.csproj @@ -15,4 +15,8 @@ + + + + diff --git a/samples/ResponseBufferingSample/ResponseBufferingSample.csproj b/samples/ResponseBufferingSample/ResponseBufferingSample.csproj index f0aa4a439a..1678ae4078 100644 --- a/samples/ResponseBufferingSample/ResponseBufferingSample.csproj +++ b/samples/ResponseBufferingSample/ResponseBufferingSample.csproj @@ -15,4 +15,8 @@ + + + + diff --git a/samples/ResponseCompressionSample/ResponseCompressionSample.csproj b/samples/ResponseCompressionSample/ResponseCompressionSample.csproj index a5792ad3e8..9f5ab99de7 100644 --- a/samples/ResponseCompressionSample/ResponseCompressionSample.csproj +++ b/samples/ResponseCompressionSample/ResponseCompressionSample.csproj @@ -20,4 +20,8 @@ + + + + diff --git a/samples/RewriteSample/RewriteSample.csproj b/samples/RewriteSample/RewriteSample.csproj index f9c78e7131..416d269729 100644 --- a/samples/RewriteSample/RewriteSample.csproj +++ b/samples/RewriteSample/RewriteSample.csproj @@ -16,4 +16,8 @@ + + + + diff --git a/src/Microsoft.AspNetCore.ResponseCompression/GzipCompressionProvider.cs b/src/Microsoft.AspNetCore.ResponseCompression/GzipCompressionProvider.cs index b7716f1746..e825b37976 100644 --- a/src/Microsoft.AspNetCore.ResponseCompression/GzipCompressionProvider.cs +++ b/src/Microsoft.AspNetCore.ResponseCompression/GzipCompressionProvider.cs @@ -37,7 +37,13 @@ namespace Microsoft.AspNetCore.ResponseCompression { get { +#if NET461 + return false; +#elif NETSTANDARD2_0 return true; +#else +#error target frameworks need to be updated +#endif } } diff --git a/src/Microsoft.AspNetCore.ResponseCompression/Microsoft.AspNetCore.ResponseCompression.csproj b/src/Microsoft.AspNetCore.ResponseCompression/Microsoft.AspNetCore.ResponseCompression.csproj index d87066a572..261c6cc988 100644 --- a/src/Microsoft.AspNetCore.ResponseCompression/Microsoft.AspNetCore.ResponseCompression.csproj +++ b/src/Microsoft.AspNetCore.ResponseCompression/Microsoft.AspNetCore.ResponseCompression.csproj @@ -5,7 +5,7 @@ 2.0.0 ASP.NET Core middleware for HTTP Response compression. - netstandard2.0 + net461;netstandard2.0 true aspnetcore diff --git a/test/Microsoft.AspNetCore.ResponseCompression.Tests/ResponseCompressionMiddlewareTest.cs b/test/Microsoft.AspNetCore.ResponseCompression.Tests/ResponseCompressionMiddlewareTest.cs index 7b77fea061..fd9a989564 100644 --- a/test/Microsoft.AspNetCore.ResponseCompression.Tests/ResponseCompressionMiddlewareTest.cs +++ b/test/Microsoft.AspNetCore.ResponseCompression.Tests/ResponseCompressionMiddlewareTest.cs @@ -505,9 +505,16 @@ namespace Microsoft.AspNetCore.ResponseCompression.Tests var response = await client.SendAsync(request, HttpCompletionOption.ResponseHeadersRead); +#if NET461 // Flush not supported, compression disabled + Assert.NotNull(response.Content.Headers.GetValues(HeaderNames.ContentMD5)); + Assert.Empty(response.Content.Headers.ContentEncoding); +#elif NETCOREAPP2_0 // Flush supported, compression enabled IEnumerable contentMD5 = null; Assert.False(response.Content.Headers.TryGetValues(HeaderNames.ContentMD5, out contentMD5)); Assert.Single(response.Content.Headers.ContentEncoding, "gzip"); +#else +#error Target frameworks need to be updated. +#endif var body = await response.Content.ReadAsStreamAsync(); @@ -563,9 +570,16 @@ namespace Microsoft.AspNetCore.ResponseCompression.Tests var response = await client.SendAsync(request, HttpCompletionOption.ResponseHeadersRead); +#if NET461 // Flush not supported, compression disabled + Assert.NotNull(response.Content.Headers.GetValues(HeaderNames.ContentMD5)); + Assert.Empty(response.Content.Headers.ContentEncoding); +#elif NETCOREAPP2_0 // Flush supported, compression enabled IEnumerable contentMD5 = null; Assert.False(response.Content.Headers.TryGetValues(HeaderNames.ContentMD5, out contentMD5)); Assert.Single(response.Content.Headers.ContentEncoding, "gzip"); +#else +#error Target framework needs to be updated +#endif var body = await response.Content.ReadAsStreamAsync(); From b8f87eaee335cc5c21fea2059026ca7f0e1f1d74 Mon Sep 17 00:00:00 2001 From: John Luo Date: Mon, 22 May 2017 17:05:16 -0700 Subject: [PATCH 199/307] React to cookies changes --- .../UrlActions/ChangeCookieActionTests.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/UrlActions/ChangeCookieActionTests.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/UrlActions/ChangeCookieActionTests.cs index 20096ef162..08a658e19e 100644 --- a/test/Microsoft.AspNetCore.Rewrite.Tests/UrlActions/ChangeCookieActionTests.cs +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/UrlActions/ChangeCookieActionTests.cs @@ -30,7 +30,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlActions var cookieHeaders = context.HttpContext.Response.Headers[HeaderNames.SetCookie]; var header = Assert.Single(cookieHeaders); - Assert.Equal($"Cookie=Chocolate%20Chip; expires={HeaderUtilities.FormatDate(now.AddMinutes(1440))}; domain=contoso.com; path=/recipes; secure; httponly", header); + Assert.Equal($"Cookie=Chocolate%20Chip; expires={HeaderUtilities.FormatDate(now.AddMinutes(1440))}; domain=contoso.com; path=/recipes; secure; samesite=lax; httponly", header); } [Fact] @@ -46,7 +46,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlActions var cookieHeaders = context.HttpContext.Response.Headers[HeaderNames.SetCookie]; var header = Assert.Single(cookieHeaders); - Assert.Equal($"Cookie=Chocolate%20Chip", header); + Assert.Equal($"Cookie=Chocolate%20Chip; samesite=lax", header); } @@ -60,7 +60,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlActions var cookieHeaders = context.HttpContext.Response.Headers[HeaderNames.SetCookie]; var header = Assert.Single(cookieHeaders); - Assert.Equal($"Cookie=", header); + Assert.Equal($"Cookie=; samesite=lax", header); } } } From d0034864a04d2a9dea519cc719f59cc9308d7e4a Mon Sep 17 00:00:00 2001 From: Chris R Date: Fri, 19 May 2017 10:56:33 -0700 Subject: [PATCH 200/307] React to StringSegment changes --- .../ResponseCompressionProvider.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Microsoft.AspNetCore.ResponseCompression/ResponseCompressionProvider.cs b/src/Microsoft.AspNetCore.ResponseCompression/ResponseCompressionProvider.cs index e16e6a1568..e5f577f00d 100644 --- a/src/Microsoft.AspNetCore.ResponseCompression/ResponseCompressionProvider.cs +++ b/src/Microsoft.AspNetCore.ResponseCompression/ResponseCompressionProvider.cs @@ -80,19 +80,19 @@ namespace Microsoft.AspNetCore.ResponseCompression // There will rarely be more than three providers, and there's only one by default foreach (var provider in _providers) { - if (string.Equals(provider.EncodingName, encoding.Value, StringComparison.OrdinalIgnoreCase)) + if (StringSegment.Equals(provider.EncodingName, encoding.Value, StringComparison.OrdinalIgnoreCase)) { return provider; } } // Uncommon but valid options - if (string.Equals("*", encoding.Value, StringComparison.Ordinal)) + if (StringSegment.Equals("*", encoding.Value, StringComparison.Ordinal)) { // Any return _providers[0]; } - if (string.Equals("identity", encoding.Value, StringComparison.OrdinalIgnoreCase)) + if (StringSegment.Equals("identity", encoding.Value, StringComparison.OrdinalIgnoreCase)) { // No compression return null; From aae6b449009fefd592ec921885b6dd1390b6d8c6 Mon Sep 17 00:00:00 2001 From: Kiran Challa Date: Fri, 26 May 2017 12:37:59 -0700 Subject: [PATCH 201/307] Updated to use the latest shared runtime --- build/dependencies.props | 1 + 1 file changed, 1 insertion(+) diff --git a/build/dependencies.props b/build/dependencies.props index 1a75c90b26..a5d8ef58f7 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -4,6 +4,7 @@ 2.1.0-* 4.7.1 2.0.0-* + 2.0.0-* 15.3.0-* 2.3.0-beta2-* From 65c78d12b5382f9f44a764bc7266e17af1ab6af4 Mon Sep 17 00:00:00 2001 From: Mikael Mengistu Date: Tue, 30 May 2017 20:42:28 -0400 Subject: [PATCH 202/307] Preserve redirect query string (#237) --- .../Internal/RedirectRule.cs | 2 +- .../MiddlewareTests.cs | 16 ++++++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/RedirectRule.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/RedirectRule.cs index 4f63bf6dd4..1c5efaa581 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/RedirectRule.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/RedirectRule.cs @@ -78,7 +78,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal } else { - response.Headers[HeaderNames.Location] = pathBase + newPath; + response.Headers[HeaderNames.Location] = pathBase + newPath + context.HttpContext.Request.QueryString; } context.Logger?.RedirectedSummary(newPath); diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/MiddlewareTests.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/MiddlewareTests.cs index 137448b1e7..682c9c09ab 100644 --- a/test/Microsoft.AspNetCore.Rewrite.Tests/MiddlewareTests.cs +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/MiddlewareTests.cs @@ -51,6 +51,22 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.CodeRules Assert.Equal("http://example.com/foo", response.Headers.Location.OriginalString); } + [Fact] + public async Task CheckRedirectPathWithQueryString() + { + var options = new RewriteOptions().AddRedirect("(.*)","http://example.com/$1", statusCode: StatusCodes.Status301MovedPermanently); + var builder = new WebHostBuilder() + .Configure(app => + { + app.UseRewriter(options); + }); + var server = new TestServer(builder); + + var response = await server.CreateClient().GetAsync("foo?bar=1"); + + Assert.Equal("http://example.com/foo?bar=1", response.Headers.Location.OriginalString); + } + [Theory] [InlineData(StatusCodes.Status301MovedPermanently)] [InlineData(StatusCodes.Status302Found)] From 63d13e66f7bc9487d6210be146f8ba7eb1d4a81b Mon Sep 17 00:00:00 2001 From: Pranav K Date: Wed, 31 May 2017 19:36:05 -0700 Subject: [PATCH 203/307] Branching for rel/2.0.0-preview2 --- NuGet.config | 7 ++++--- build/dependencies.props | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/NuGet.config b/NuGet.config index 8e65695611..c4bc056c4d 100644 --- a/NuGet.config +++ b/NuGet.config @@ -1,8 +1,9 @@ - + - + + - + \ No newline at end of file diff --git a/build/dependencies.props b/build/dependencies.props index a5d8ef58f7..eb851f4ef6 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -1,6 +1,6 @@ - 2.0.0-* + 2.0.0-preview2-* 2.1.0-* 4.7.1 2.0.0-* From 302308c8275a99c572baf7590f1b6b1aca3935a3 Mon Sep 17 00:00:00 2001 From: Pranav K Date: Wed, 31 May 2017 19:53:09 -0700 Subject: [PATCH 204/307] Updating build scripts to point to 2.0.0-preview2 KoreBuild --- build.ps1 | 2 +- build.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/build.ps1 b/build.ps1 index 5bf0e2c113..3a2476b2b4 100644 --- a/build.ps1 +++ b/build.ps1 @@ -33,7 +33,7 @@ cd $PSScriptRoot $repoFolder = $PSScriptRoot $env:REPO_FOLDER = $repoFolder -$koreBuildZip="https://github.com/aspnet/KoreBuild/archive/dev.zip" +$koreBuildZip="https://github.com/aspnet/KoreBuild/archive/rel/2.0.0-preview2.zip" if ($env:KOREBUILD_ZIP) { $koreBuildZip=$env:KOREBUILD_ZIP diff --git a/build.sh b/build.sh index b0bcadb579..a40bdb87b1 100755 --- a/build.sh +++ b/build.sh @@ -2,7 +2,7 @@ repoFolder="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" cd $repoFolder -koreBuildZip="https://github.com/aspnet/KoreBuild/archive/dev.zip" +koreBuildZip="https://github.com/aspnet/KoreBuild/archive/rel/2.0.0-preview2.zip" if [ ! -z $KOREBUILD_ZIP ]; then koreBuildZip=$KOREBUILD_ZIP fi From 6646352bcd42c6f5a26da6f15e9992bf9a833932 Mon Sep 17 00:00:00 2001 From: Pranav K Date: Thu, 1 Jun 2017 10:46:29 -0700 Subject: [PATCH 205/307] Updating versions to preview3 --- NuGet.config | 3 ++- version.props | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/NuGet.config b/NuGet.config index 8e65695611..4e8a1f6de1 100644 --- a/NuGet.config +++ b/NuGet.config @@ -1,6 +1,7 @@ - + + diff --git a/version.props b/version.props index cf71e822fe..28b0d089e3 100644 --- a/version.props +++ b/version.props @@ -1,6 +1,6 @@ - preview2 + preview3 From 9ff653f42131e0dda687d472ebc56872cf8bedf3 Mon Sep 17 00:00:00 2001 From: Pavel Krymets Date: Fri, 2 Jun 2017 08:33:59 -0700 Subject: [PATCH 206/307] React to logging in DI changes (#239) --- samples/ResponseCompressionSample/Startup.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/samples/ResponseCompressionSample/Startup.cs b/samples/ResponseCompressionSample/Startup.cs index 59afeccd42..e10baad03c 100644 --- a/samples/ResponseCompressionSample/Startup.cs +++ b/samples/ResponseCompressionSample/Startup.cs @@ -72,7 +72,8 @@ namespace ResponseCompressionSample .UseKestrel() .ConfigureLogging(factory => { - factory.AddConsole(LogLevel.Debug); + factory.AddConsole() + .SetMinimumLevel(LogLevel.Debug); }) .UseStartup() .Build(); From cea5965bd3da7d2cd92af2d614646341ab8bbbcf Mon Sep 17 00:00:00 2001 From: Pranav K Date: Thu, 8 Jun 2017 08:27:55 -0700 Subject: [PATCH 207/307] Remove usage of TaskCache --- src/Microsoft.AspNetCore.Buffering/BufferingWriteStream.cs | 3 +-- .../Microsoft.AspNetCore.Buffering.csproj | 1 - .../Microsoft.AspNetCore.Rewrite.csproj | 1 - src/Microsoft.AspNetCore.Rewrite/RewriteMiddleware.cs | 2 +- 4 files changed, 2 insertions(+), 5 deletions(-) diff --git a/src/Microsoft.AspNetCore.Buffering/BufferingWriteStream.cs b/src/Microsoft.AspNetCore.Buffering/BufferingWriteStream.cs index b81b70922b..db3aacf5dd 100644 --- a/src/Microsoft.AspNetCore.Buffering/BufferingWriteStream.cs +++ b/src/Microsoft.AspNetCore.Buffering/BufferingWriteStream.cs @@ -5,7 +5,6 @@ using System; using System.IO; using System.Threading; using System.Threading.Tasks; -using Microsoft.Extensions.Internal; namespace Microsoft.AspNetCore.Buffering { @@ -134,7 +133,7 @@ namespace Microsoft.AspNetCore.Buffering { return FlushAsync(cancellationToken); } - return TaskCache.CompletedTask; + return Task.CompletedTask; } public override void Write(byte[] buffer, int offset, int count) diff --git a/src/Microsoft.AspNetCore.Buffering/Microsoft.AspNetCore.Buffering.csproj b/src/Microsoft.AspNetCore.Buffering/Microsoft.AspNetCore.Buffering.csproj index 545b87b140..ea677dbd36 100644 --- a/src/Microsoft.AspNetCore.Buffering/Microsoft.AspNetCore.Buffering.csproj +++ b/src/Microsoft.AspNetCore.Buffering/Microsoft.AspNetCore.Buffering.csproj @@ -13,7 +13,6 @@ - diff --git a/src/Microsoft.AspNetCore.Rewrite/Microsoft.AspNetCore.Rewrite.csproj b/src/Microsoft.AspNetCore.Rewrite/Microsoft.AspNetCore.Rewrite.csproj index c3577cb2e8..a6d014cafb 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Microsoft.AspNetCore.Rewrite.csproj +++ b/src/Microsoft.AspNetCore.Rewrite/Microsoft.AspNetCore.Rewrite.csproj @@ -21,7 +21,6 @@ - diff --git a/src/Microsoft.AspNetCore.Rewrite/RewriteMiddleware.cs b/src/Microsoft.AspNetCore.Rewrite/RewriteMiddleware.cs index cc27a90ab2..256c1cbe1b 100644 --- a/src/Microsoft.AspNetCore.Rewrite/RewriteMiddleware.cs +++ b/src/Microsoft.AspNetCore.Rewrite/RewriteMiddleware.cs @@ -86,7 +86,7 @@ namespace Microsoft.AspNetCore.Rewrite _logger.RewriteMiddlewareRequestResponseComplete( context.Response.Headers[HeaderNames.Location], context.Response.StatusCode); - return TaskCache.CompletedTask; + return Task.CompletedTask; case RuleResult.SkipRemainingRules: _logger.RewriteMiddlewareRequestStopRules(context.Request.GetEncodedUrl()); return _next(context); From 80ec97c132c9079f50d8346c27b0bd9fd6e0bf89 Mon Sep 17 00:00:00 2001 From: Robert Mooney Date: Thu, 8 Jun 2017 13:34:34 -0700 Subject: [PATCH 208/307] Enable tests in the explorer (#245) --- .../Microsoft.AspNetCore.Buffering.Tests.csproj | 2 +- .../Microsoft.AspNetCore.HttpOverrides.Tests.csproj | 2 +- .../Microsoft.AspNetCore.ResponseCompression.Tests.csproj | 2 +- .../Microsoft.AspNetCore.Rewrite.Tests.csproj | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/test/Microsoft.AspNetCore.Buffering.Tests/Microsoft.AspNetCore.Buffering.Tests.csproj b/test/Microsoft.AspNetCore.Buffering.Tests/Microsoft.AspNetCore.Buffering.Tests.csproj index 84ce6801da..2f816560e1 100644 --- a/test/Microsoft.AspNetCore.Buffering.Tests/Microsoft.AspNetCore.Buffering.Tests.csproj +++ b/test/Microsoft.AspNetCore.Buffering.Tests/Microsoft.AspNetCore.Buffering.Tests.csproj @@ -3,7 +3,7 @@ - net461;netcoreapp2.0 + netcoreapp2.0;net461 netcoreapp2.0 diff --git a/test/Microsoft.AspNetCore.HttpOverrides.Tests/Microsoft.AspNetCore.HttpOverrides.Tests.csproj b/test/Microsoft.AspNetCore.HttpOverrides.Tests/Microsoft.AspNetCore.HttpOverrides.Tests.csproj index 2cb29a9fca..66d615c52a 100644 --- a/test/Microsoft.AspNetCore.HttpOverrides.Tests/Microsoft.AspNetCore.HttpOverrides.Tests.csproj +++ b/test/Microsoft.AspNetCore.HttpOverrides.Tests/Microsoft.AspNetCore.HttpOverrides.Tests.csproj @@ -3,7 +3,7 @@ - net461;netcoreapp2.0 + netcoreapp2.0;net461 netcoreapp2.0 diff --git a/test/Microsoft.AspNetCore.ResponseCompression.Tests/Microsoft.AspNetCore.ResponseCompression.Tests.csproj b/test/Microsoft.AspNetCore.ResponseCompression.Tests/Microsoft.AspNetCore.ResponseCompression.Tests.csproj index c689c1b6f0..06e467442b 100644 --- a/test/Microsoft.AspNetCore.ResponseCompression.Tests/Microsoft.AspNetCore.ResponseCompression.Tests.csproj +++ b/test/Microsoft.AspNetCore.ResponseCompression.Tests/Microsoft.AspNetCore.ResponseCompression.Tests.csproj @@ -3,7 +3,7 @@ - net461;netcoreapp2.0 + netcoreapp2.0;net461 netcoreapp2.0 diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/Microsoft.AspNetCore.Rewrite.Tests.csproj b/test/Microsoft.AspNetCore.Rewrite.Tests/Microsoft.AspNetCore.Rewrite.Tests.csproj index 5d5d66e3a6..fcf17701e3 100644 --- a/test/Microsoft.AspNetCore.Rewrite.Tests/Microsoft.AspNetCore.Rewrite.Tests.csproj +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/Microsoft.AspNetCore.Rewrite.Tests.csproj @@ -3,7 +3,7 @@ - net461;netcoreapp2.0 + netcoreapp2.0;net461 netcoreapp2.0 From 00343d2b479c7fbae22348973c27f1743bc5d937 Mon Sep 17 00:00:00 2001 From: David Fowler Date: Thu, 8 Jun 2017 14:01:04 -1000 Subject: [PATCH 209/307] Support IOptions (#243) - Added a test - Updated the sample to use services --- samples/RewriteSample/Startup.cs | 33 ++++++++++++++----- .../RewriteBuilderExtensions.cs | 19 ++++++++++- .../RewriteMiddleware.cs | 6 ++-- .../MiddlewareTests.cs | 33 ++++++++++++++++--- 4 files changed, 74 insertions(+), 17 deletions(-) diff --git a/samples/RewriteSample/Startup.cs b/samples/RewriteSample/Startup.cs index c5b1ceb895..fcf3a93314 100644 --- a/samples/RewriteSample/Startup.cs +++ b/samples/RewriteSample/Startup.cs @@ -7,22 +7,39 @@ using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Rewrite; +using Microsoft.Extensions.DependencyInjection; namespace RewriteSample { public class Startup { + public Startup(IHostingEnvironment environment) + { + Environment = environment; + } + + public IHostingEnvironment Environment { get; private set; } + + public void ConfigureServices(IServiceCollection services) + { + services.Configure(options => + { + options.AddRedirect("(.*)/$", "$1") + .AddRewrite(@"app/(\d+)", "app?id=$1", skipRemainingRules: false) + .AddRedirectToHttps(302, 5001) + .AddIISUrlRewrite(Environment.ContentRootFileProvider, "UrlRewrite.xml") + .AddApacheModRewrite(Environment.ContentRootFileProvider, "Rewrite.txt"); + }); + } + public void Configure(IApplicationBuilder app, IHostingEnvironment env) { - var options = new RewriteOptions() - .AddRedirect("(.*)/$", "$1") - .AddRewrite(@"app/(\d+)", "app?id=$1", skipRemainingRules: false) - .AddRedirectToHttps(302, 5001) - .AddIISUrlRewrite(env.ContentRootFileProvider, "UrlRewrite.xml") - .AddApacheModRewrite(env.ContentRootFileProvider, "Rewrite.txt"); + app.UseRewriter(); - app.UseRewriter(options); - app.Run(context => context.Response.WriteAsync($"Rewritten Url: {context.Request.Path + context.Request.QueryString}")); + app.Run(context => + { + return context.Response.WriteAsync($"Rewritten Url: {context.Request.Path + context.Request.QueryString}"); + }); } public static void Main(string[] args) diff --git a/src/Microsoft.AspNetCore.Rewrite/RewriteBuilderExtensions.cs b/src/Microsoft.AspNetCore.Rewrite/RewriteBuilderExtensions.cs index 0d577c3fd0..fb073fec59 100644 --- a/src/Microsoft.AspNetCore.Rewrite/RewriteBuilderExtensions.cs +++ b/src/Microsoft.AspNetCore.Rewrite/RewriteBuilderExtensions.cs @@ -3,6 +3,7 @@ using System; using Microsoft.AspNetCore.Rewrite; +using Microsoft.Extensions.Options; namespace Microsoft.AspNetCore.Builder { @@ -11,6 +12,21 @@ namespace Microsoft.AspNetCore.Builder /// public static class RewriteBuilderExtensions { + /// + /// Checks if a given Url matches rules and conditions, and modifies the HttpContext on match. + /// + /// The + /// + public static IApplicationBuilder UseRewriter(this IApplicationBuilder app) + { + if (app == null) + { + throw new ArgumentNullException(nameof(app)); + } + + return app.UseMiddleware(); + } + /// /// Checks if a given Url matches rules and conditions, and modifies the HttpContext on match. /// @@ -28,8 +44,9 @@ namespace Microsoft.AspNetCore.Builder { throw new ArgumentNullException(nameof(options)); } + // put middleware in pipeline - return app.UseMiddleware(options); + return app.UseMiddleware(Options.Create(options)); } } } diff --git a/src/Microsoft.AspNetCore.Rewrite/RewriteMiddleware.cs b/src/Microsoft.AspNetCore.Rewrite/RewriteMiddleware.cs index 256c1cbe1b..df62984425 100644 --- a/src/Microsoft.AspNetCore.Rewrite/RewriteMiddleware.cs +++ b/src/Microsoft.AspNetCore.Rewrite/RewriteMiddleware.cs @@ -6,11 +6,11 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http.Extensions; -using Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite; using Microsoft.AspNetCore.Rewrite.Logging; using Microsoft.Extensions.FileProviders; using Microsoft.Extensions.Internal; using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; using Microsoft.Net.Http.Headers; namespace Microsoft.AspNetCore.Rewrite @@ -36,7 +36,7 @@ namespace Microsoft.AspNetCore.Rewrite RequestDelegate next, IHostingEnvironment hostingEnvironment, ILoggerFactory loggerFactory, - RewriteOptions options) + IOptions options) { if (next == null) { @@ -49,7 +49,7 @@ namespace Microsoft.AspNetCore.Rewrite } _next = next; - _options = options; + _options = options.Value; _fileProvider = _options.StaticFileProvider ?? hostingEnvironment.WebRootFileProvider; _logger = loggerFactory.CreateLogger(); } diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/MiddlewareTests.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/MiddlewareTests.cs index 682c9c09ab..c75ef98c50 100644 --- a/test/Microsoft.AspNetCore.Rewrite.Tests/MiddlewareTests.cs +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/MiddlewareTests.cs @@ -7,6 +7,7 @@ using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.TestHost; +using Microsoft.Extensions.DependencyInjection; using Xunit; namespace Microsoft.AspNetCore.Rewrite.Tests.CodeRules @@ -38,7 +39,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.CodeRules [Fact] public async Task CheckRedirectPath() { - var options = new RewriteOptions().AddRedirect("(.*)","http://example.com/$1", statusCode: StatusCodes.Status301MovedPermanently); + var options = new RewriteOptions().AddRedirect("(.*)", "http://example.com/$1", statusCode: StatusCodes.Status301MovedPermanently); var builder = new WebHostBuilder() .Configure(app => { @@ -51,10 +52,32 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.CodeRules Assert.Equal("http://example.com/foo", response.Headers.Location.OriginalString); } + [Fact] + public async Task RewriteRulesCanComeFromConfigureOptions() + { + var builder = new WebHostBuilder() + .ConfigureServices(services => + { + services.Configure(options => + { + options.AddRedirect("(.*)", "http://example.com/$1", statusCode: StatusCodes.Status301MovedPermanently); + }); + }) + .Configure(app => + { + app.UseRewriter(); + }); + var server = new TestServer(builder); + + var response = await server.CreateClient().GetAsync("foo"); + + Assert.Equal("http://example.com/foo", response.Headers.Location.OriginalString); + } + [Fact] public async Task CheckRedirectPathWithQueryString() { - var options = new RewriteOptions().AddRedirect("(.*)","http://example.com/$1", statusCode: StatusCodes.Status301MovedPermanently); + var options = new RewriteOptions().AddRedirect("(.*)", "http://example.com/$1", statusCode: StatusCodes.Status301MovedPermanently); var builder = new WebHostBuilder() .Configure(app => { @@ -108,9 +131,9 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.CodeRules [Theory] [InlineData(25, "https://example.com:25/")] [InlineData(-25, "https://example.com/")] - public async Task CheckRedirectToHttpsWithSslPort(int sslPort,string expected) + public async Task CheckRedirectToHttpsWithSslPort(int sslPort, string expected) { - var options = new RewriteOptions().AddRedirectToHttps(statusCode: StatusCodes.Status301MovedPermanently, sslPort:sslPort); + var options = new RewriteOptions().AddRedirectToHttps(statusCode: StatusCodes.Status301MovedPermanently, sslPort: sslPort); var builder = new WebHostBuilder() .Configure(app => { @@ -170,7 +193,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.CodeRules context.Request.Path + context.Request.QueryString)); }); - var server = new TestServer(builder) {BaseAddress = new Uri("http://localhost:5000/foo")}; + var server = new TestServer(builder) { BaseAddress = new Uri("http://localhost:5000/foo") }; var response = await server.CreateClient().GetAsync(""); From 02a05cccacbeb0742b56db435ff6248ee67a685a Mon Sep 17 00:00:00 2001 From: Kiran Challa Date: Thu, 15 Jun 2017 04:50:47 -0700 Subject: [PATCH 210/307] Fixed sample projects to refernce NETStandard.Library.NETFramework conditionally --- samples/HttpOverridesSample/HttpOverridesSample.csproj | 2 +- samples/ResponseBufferingSample/ResponseBufferingSample.csproj | 2 +- .../ResponseCompressionSample/ResponseCompressionSample.csproj | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/samples/HttpOverridesSample/HttpOverridesSample.csproj b/samples/HttpOverridesSample/HttpOverridesSample.csproj index 5caa62c82e..bfa8adbf5e 100644 --- a/samples/HttpOverridesSample/HttpOverridesSample.csproj +++ b/samples/HttpOverridesSample/HttpOverridesSample.csproj @@ -15,7 +15,7 @@ - + diff --git a/samples/ResponseBufferingSample/ResponseBufferingSample.csproj b/samples/ResponseBufferingSample/ResponseBufferingSample.csproj index 1678ae4078..013a6ab3bc 100644 --- a/samples/ResponseBufferingSample/ResponseBufferingSample.csproj +++ b/samples/ResponseBufferingSample/ResponseBufferingSample.csproj @@ -15,7 +15,7 @@ - + diff --git a/samples/ResponseCompressionSample/ResponseCompressionSample.csproj b/samples/ResponseCompressionSample/ResponseCompressionSample.csproj index 9f5ab99de7..570dc81ca6 100644 --- a/samples/ResponseCompressionSample/ResponseCompressionSample.csproj +++ b/samples/ResponseCompressionSample/ResponseCompressionSample.csproj @@ -20,7 +20,7 @@ - + From 13e01db0d2096e2eb8c73501bfdb3ed5c1a15be9 Mon Sep 17 00:00:00 2001 From: Nate McMaster Date: Fri, 16 Jun 2017 11:24:45 -0700 Subject: [PATCH 211/307] Fix minor bugs in samples and their NS.Library.NETFramework reference --- samples/HttpOverridesSample/HttpOverridesSample.csproj | 2 +- .../ResponseBufferingSample/ResponseBufferingSample.csproj | 2 +- .../ResponseCompressionSample.csproj | 2 +- samples/RewriteSample/RewriteSample.csproj | 4 ++-- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/samples/HttpOverridesSample/HttpOverridesSample.csproj b/samples/HttpOverridesSample/HttpOverridesSample.csproj index bfa8adbf5e..45d5c65fed 100644 --- a/samples/HttpOverridesSample/HttpOverridesSample.csproj +++ b/samples/HttpOverridesSample/HttpOverridesSample.csproj @@ -16,7 +16,7 @@ - + diff --git a/samples/ResponseBufferingSample/ResponseBufferingSample.csproj b/samples/ResponseBufferingSample/ResponseBufferingSample.csproj index 013a6ab3bc..c26d9d3ce7 100644 --- a/samples/ResponseBufferingSample/ResponseBufferingSample.csproj +++ b/samples/ResponseBufferingSample/ResponseBufferingSample.csproj @@ -16,7 +16,7 @@ - + diff --git a/samples/ResponseCompressionSample/ResponseCompressionSample.csproj b/samples/ResponseCompressionSample/ResponseCompressionSample.csproj index 570dc81ca6..7ce9c8b8d1 100644 --- a/samples/ResponseCompressionSample/ResponseCompressionSample.csproj +++ b/samples/ResponseCompressionSample/ResponseCompressionSample.csproj @@ -21,7 +21,7 @@ - + diff --git a/samples/RewriteSample/RewriteSample.csproj b/samples/RewriteSample/RewriteSample.csproj index 416d269729..f621a9b1dd 100644 --- a/samples/RewriteSample/RewriteSample.csproj +++ b/samples/RewriteSample/RewriteSample.csproj @@ -16,8 +16,8 @@ - - + + From 83140c0cfe1c787a0dc7e6e015c7f7667759bcc9 Mon Sep 17 00:00:00 2001 From: Nate McMaster Date: Mon, 26 Jun 2017 09:33:21 -0700 Subject: [PATCH 212/307] Adding libunwind8 to .travis.yml [skip appveyor] --- .travis.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.travis.yml b/.travis.yml index bf8044fd45..eeb63bfa9f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,6 +10,10 @@ os: - linux - osx osx_image: xcode8.2 +addons: + apt: + packages: + - libunwind8 branches: only: - master From f520fbd3d1cc21eb7bbc5eb3339d7200dc66aeff Mon Sep 17 00:00:00 2001 From: Pranav K Date: Thu, 29 Jun 2017 07:23:13 -0700 Subject: [PATCH 213/307] Update dependencies.props * Update Moq to 4.7.49. * Add NETStandardImplicitPackageVersion --- build/dependencies.props | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index a5d8ef58f7..787a051c3a 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -1,8 +1,9 @@ - + 2.0.0-* 2.1.0-* - 4.7.1 + 4.7.49 + 2.0.0-* 2.0.0-* 2.0.0-* 15.3.0-* From ee6346b068d532b103d830bde8d2af9f2776de6f Mon Sep 17 00:00:00 2001 From: Pranav K Date: Thu, 29 Jun 2017 07:26:26 -0700 Subject: [PATCH 214/307] Remove duplicate theory data --- .../ForwardedHeadersMiddlewareTest.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/test/Microsoft.AspNetCore.HttpOverrides.Tests/ForwardedHeadersMiddlewareTest.cs b/test/Microsoft.AspNetCore.HttpOverrides.Tests/ForwardedHeadersMiddlewareTest.cs index 250774b5f4..a346712a8c 100644 --- a/test/Microsoft.AspNetCore.HttpOverrides.Tests/ForwardedHeadersMiddlewareTest.cs +++ b/test/Microsoft.AspNetCore.HttpOverrides.Tests/ForwardedHeadersMiddlewareTest.cs @@ -437,7 +437,6 @@ namespace Microsoft.AspNetCore.HttpOverrides [InlineData("h2, h1", "", "::1", true, "http")] [InlineData("h2, h1", "F::, D::", "::1", true, "h1")] [InlineData("h2, h1", "E::, D::", "F::", true, "http")] - [InlineData("h2, h1", "E::, D::", "F::", true, "http")] public async Task XForwardedProtoOverrideLimitedByLoopback(string protoHeader, string forHeader, string remoteIp, bool loopback, string expected) { var assertsExecuted = false; From 0af181e3a0ac16ff9905169c29efcef1b61e2f51 Mon Sep 17 00:00:00 2001 From: Ryan Brandenburg Date: Wed, 28 Jun 2017 16:39:49 -0700 Subject: [PATCH 215/307] Remove NETStandard.Library.NETFramework and update Moq --- build/common.props | 4 ---- 1 file changed, 4 deletions(-) diff --git a/build/common.props b/build/common.props index 1f336eb45d..6e1ee82520 100644 --- a/build/common.props +++ b/build/common.props @@ -16,8 +16,4 @@ - - - - From 6eab2991920ac0adfe1727ddaf73560a633d0647 Mon Sep 17 00:00:00 2001 From: Pranav K Date: Mon, 3 Jul 2017 14:04:33 -0700 Subject: [PATCH 216/307] Update LICENSE.txt text --- LICENSE.txt | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/LICENSE.txt b/LICENSE.txt index 0bdc1962b6..7b2956ecee 100644 --- a/LICENSE.txt +++ b/LICENSE.txt @@ -1,10 +1,12 @@ -Copyright (c) .NET Foundation. All rights reserved. +Copyright (c) .NET Foundation and Contributors + +All rights reserved. Licensed under the Apache License, Version 2.0 (the "License"); you may not use -these files except in compliance with the License. You may obtain a copy of the +this file except in compliance with the License. You may obtain a copy of the License at -http://www.apache.org/licenses/LICENSE-2.0 + http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR From b70ca8056e0c513d394666968437bdb15479ed2e Mon Sep 17 00:00:00 2001 From: Mike Harder Date: Mon, 3 Jul 2017 17:38:48 -0700 Subject: [PATCH 217/307] Set "TreatWarningsAsErrors" before NuGet restore (#249) * Ensures our build stays clean of NuGet warnings --- build/common.props | 1 + 1 file changed, 1 insertion(+) diff --git a/build/common.props b/build/common.props index 6e1ee82520..18f14b103d 100644 --- a/build/common.props +++ b/build/common.props @@ -10,6 +10,7 @@ true true $(VersionSuffix)-$(BuildNumber) + true From 1a9fcc69511ecb410ac64bf9d3346b5e8e61a381 Mon Sep 17 00:00:00 2001 From: Nate McMaster Date: Thu, 6 Jul 2017 10:36:19 -0700 Subject: [PATCH 218/307] React to aspnet/BuildTools#293 [ci skip] --- build/dependencies.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/dependencies.props b/build/dependencies.props index 787a051c3a..20d47945e9 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -1,7 +1,7 @@  2.0.0-* - 2.1.0-* + 2.0.1-* 4.7.49 2.0.0-* 2.0.0-* From 52206f7afbd949ee9b6c982b04e604cefa66f1c9 Mon Sep 17 00:00:00 2001 From: Pranav K Date: Thu, 6 Jul 2017 15:07:53 -0700 Subject: [PATCH 219/307] Update version suffix for 2.0.0 RTM release --- version.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.props b/version.props index 28b0d089e3..1589187a38 100644 --- a/version.props +++ b/version.props @@ -1,6 +1,6 @@ - preview3 + rtm From ec56c0c96321326f2ef61f97eff8f0b296204eca Mon Sep 17 00:00:00 2001 From: Ryan Brandenburg Date: Thu, 6 Jul 2017 15:24:16 -0700 Subject: [PATCH 220/307] Remove NETSTandard.Library.NETFramework --- samples/HttpOverridesSample/HttpOverridesSample.csproj | 4 ---- .../ResponseBufferingSample/ResponseBufferingSample.csproj | 4 ---- .../ResponseCompressionSample.csproj | 4 ---- samples/RewriteSample/RewriteSample.csproj | 4 ---- 4 files changed, 16 deletions(-) diff --git a/samples/HttpOverridesSample/HttpOverridesSample.csproj b/samples/HttpOverridesSample/HttpOverridesSample.csproj index 45d5c65fed..9c8dc4616a 100644 --- a/samples/HttpOverridesSample/HttpOverridesSample.csproj +++ b/samples/HttpOverridesSample/HttpOverridesSample.csproj @@ -15,8 +15,4 @@ - - - - diff --git a/samples/ResponseBufferingSample/ResponseBufferingSample.csproj b/samples/ResponseBufferingSample/ResponseBufferingSample.csproj index c26d9d3ce7..f0aa4a439a 100644 --- a/samples/ResponseBufferingSample/ResponseBufferingSample.csproj +++ b/samples/ResponseBufferingSample/ResponseBufferingSample.csproj @@ -15,8 +15,4 @@ - - - - diff --git a/samples/ResponseCompressionSample/ResponseCompressionSample.csproj b/samples/ResponseCompressionSample/ResponseCompressionSample.csproj index 7ce9c8b8d1..a5792ad3e8 100644 --- a/samples/ResponseCompressionSample/ResponseCompressionSample.csproj +++ b/samples/ResponseCompressionSample/ResponseCompressionSample.csproj @@ -20,8 +20,4 @@ - - - - diff --git a/samples/RewriteSample/RewriteSample.csproj b/samples/RewriteSample/RewriteSample.csproj index f621a9b1dd..f9c78e7131 100644 --- a/samples/RewriteSample/RewriteSample.csproj +++ b/samples/RewriteSample/RewriteSample.csproj @@ -16,8 +16,4 @@ - - - - From efce8448b00768d4f86aec347fbe5ac6fc800052 Mon Sep 17 00:00:00 2001 From: Pranav K Date: Mon, 10 Jul 2017 11:40:42 -0700 Subject: [PATCH 221/307] Branching for 2.0.0 rtm --- NuGet.config | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/NuGet.config b/NuGet.config index 4e8a1f6de1..37f0d27ea0 100644 --- a/NuGet.config +++ b/NuGet.config @@ -2,7 +2,7 @@ - + From 34eec6c9488ab4c6d3ac55d69fdd65c83d500706 Mon Sep 17 00:00:00 2001 From: Pranav K Date: Mon, 10 Jul 2017 11:57:54 -0700 Subject: [PATCH 222/307] Updating KoreBuild branch --- build.ps1 | 2 +- build.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/build.ps1 b/build.ps1 index 5bf0e2c113..1785334385 100644 --- a/build.ps1 +++ b/build.ps1 @@ -33,7 +33,7 @@ cd $PSScriptRoot $repoFolder = $PSScriptRoot $env:REPO_FOLDER = $repoFolder -$koreBuildZip="https://github.com/aspnet/KoreBuild/archive/dev.zip" +$koreBuildZip="https://github.com/aspnet/KoreBuild/archive/rel/2.0.0.zip" if ($env:KOREBUILD_ZIP) { $koreBuildZip=$env:KOREBUILD_ZIP diff --git a/build.sh b/build.sh index b0bcadb579..5e27ed8efb 100755 --- a/build.sh +++ b/build.sh @@ -2,7 +2,7 @@ repoFolder="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" cd $repoFolder -koreBuildZip="https://github.com/aspnet/KoreBuild/archive/dev.zip" +koreBuildZip="https://github.com/aspnet/KoreBuild/archive/rel/2.0.0.zip" if [ ! -z $KOREBUILD_ZIP ]; then koreBuildZip=$KOREBUILD_ZIP fi From 13dff802e1d204fbd24ea9e675d48b15bd4c7f77 Mon Sep 17 00:00:00 2001 From: Ryan Brandenburg Date: Fri, 7 Jul 2017 14:54:05 -0700 Subject: [PATCH 223/307] Skip first time experience on Appveyor --- appveyor.yml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index 1041615c68..31efd8196f 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,4 +1,4 @@ -init: +init: - git config --global core.autocrlf true branches: only: @@ -9,6 +9,10 @@ branches: build_script: - ps: .\build.ps1 clone_depth: 1 +environment: + global: + DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true + DOTNET_CLI_TELEMETRY_OPTOUT: 1 test: off deploy: off os: Visual Studio 2017 From 96ee291aff9e3f3f38cf7e42a03bcfab14c7369c Mon Sep 17 00:00:00 2001 From: Ryan Brandenburg Date: Fri, 21 Jul 2017 12:56:41 -0700 Subject: [PATCH 224/307] 2.0.0-rtm to 2.1.0-preview1 --- version.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.props b/version.props index 1589187a38..68a61ffe6e 100644 --- a/version.props +++ b/version.props @@ -1,6 +1,6 @@ - rtm + preview1 From 1ba55a047a7580b2306d87d6a548e6237eaf8dcf Mon Sep 17 00:00:00 2001 From: Ryan Brandenburg Date: Mon, 24 Jul 2017 15:57:29 -0700 Subject: [PATCH 225/307] Normalize VersionPrefix --- build/dependencies.props | 2 +- .../Microsoft.AspNetCore.Buffering.csproj | 2 +- .../Microsoft.AspNetCore.HttpOverrides.csproj | 1 - .../Microsoft.AspNetCore.ResponseCompression.csproj | 1 - .../Microsoft.AspNetCore.Rewrite.csproj | 1 - version.props | 1 + 6 files changed, 3 insertions(+), 5 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index 20d47945e9..8c8a8dc874 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -1,6 +1,6 @@  - 2.0.0-* + 2.1.0-* 2.0.1-* 4.7.49 2.0.0-* diff --git a/src/Microsoft.AspNetCore.Buffering/Microsoft.AspNetCore.Buffering.csproj b/src/Microsoft.AspNetCore.Buffering/Microsoft.AspNetCore.Buffering.csproj index ea677dbd36..a3d42c869d 100644 --- a/src/Microsoft.AspNetCore.Buffering/Microsoft.AspNetCore.Buffering.csproj +++ b/src/Microsoft.AspNetCore.Buffering/Microsoft.AspNetCore.Buffering.csproj @@ -3,7 +3,7 @@ - 0.3.0 + 0.4.0 ASP.NET Core middleware for buffering response bodies. netstandard2.0 $(NoWarn);CS1591 diff --git a/src/Microsoft.AspNetCore.HttpOverrides/Microsoft.AspNetCore.HttpOverrides.csproj b/src/Microsoft.AspNetCore.HttpOverrides/Microsoft.AspNetCore.HttpOverrides.csproj index 5ebd793c2d..7b8ae08a7c 100644 --- a/src/Microsoft.AspNetCore.HttpOverrides/Microsoft.AspNetCore.HttpOverrides.csproj +++ b/src/Microsoft.AspNetCore.HttpOverrides/Microsoft.AspNetCore.HttpOverrides.csproj @@ -3,7 +3,6 @@ - 2.0.0 ASP.NET Core basic middleware for supporting HTTP method overrides. Includes: * X-Forwarded-* headers to forward headers from a proxy. * HTTP method override header. diff --git a/src/Microsoft.AspNetCore.ResponseCompression/Microsoft.AspNetCore.ResponseCompression.csproj b/src/Microsoft.AspNetCore.ResponseCompression/Microsoft.AspNetCore.ResponseCompression.csproj index 261c6cc988..78c240a0ec 100644 --- a/src/Microsoft.AspNetCore.ResponseCompression/Microsoft.AspNetCore.ResponseCompression.csproj +++ b/src/Microsoft.AspNetCore.ResponseCompression/Microsoft.AspNetCore.ResponseCompression.csproj @@ -3,7 +3,6 @@ - 2.0.0 ASP.NET Core middleware for HTTP Response compression. net461;netstandard2.0 true diff --git a/src/Microsoft.AspNetCore.Rewrite/Microsoft.AspNetCore.Rewrite.csproj b/src/Microsoft.AspNetCore.Rewrite/Microsoft.AspNetCore.Rewrite.csproj index a6d014cafb..87f5d80c07 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Microsoft.AspNetCore.Rewrite.csproj +++ b/src/Microsoft.AspNetCore.Rewrite/Microsoft.AspNetCore.Rewrite.csproj @@ -3,7 +3,6 @@ - 2.0.0 ASP.NET Core basic middleware for rewriting URLs. Includes: * Support for custom URL rewrite rules * Support for running IIS URL Rewrite module rules diff --git a/version.props b/version.props index 68a61ffe6e..1ea46af42a 100644 --- a/version.props +++ b/version.props @@ -1,6 +1,7 @@ + 2.1.0 preview1 From 5b79150606123f7451420abf1aa3499ddc4ab8ea Mon Sep 17 00:00:00 2001 From: Pranav K Date: Tue, 25 Jul 2017 15:12:16 -0700 Subject: [PATCH 226/307] Updating to InternalAspNetCoreSdkVersion 2.1.1-* --- build/dependencies.props | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index 8c8a8dc874..3945007fb2 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -1,7 +1,7 @@ - + 2.1.0-* - 2.0.1-* + 2.1.1-* 4.7.49 2.0.0-* 2.0.0-* From bd5e35d56adca7527624dc0e6f9730392b8f6493 Mon Sep 17 00:00:00 2001 From: Nate McMaster Date: Tue, 25 Jul 2017 16:30:35 -0700 Subject: [PATCH 227/307] Update bootstrappers to use the compiled version of KoreBuild [ci skip] --- .gitignore | 1 + build.cmd | 2 +- build.ps1 | 218 +++++++++++++++++++++++++--------- build.sh | 224 +++++++++++++++++++++++++++++------ build/common.props | 2 +- version.props => version.xml | 3 +- 6 files changed, 356 insertions(+), 94 deletions(-) rename version.props => version.xml (55%) diff --git a/.gitignore b/.gitignore index c8dd6c52d5..2f73223257 100644 --- a/.gitignore +++ b/.gitignore @@ -33,3 +33,4 @@ project.lock.json *.nuget.props *.nuget.targets global.json +korebuild-lock.txt diff --git a/build.cmd b/build.cmd index 7d4894cb4a..b6c8d24864 100644 --- a/build.cmd +++ b/build.cmd @@ -1,2 +1,2 @@ @ECHO OFF -PowerShell -NoProfile -NoLogo -ExecutionPolicy unrestricted -Command "[System.Threading.Thread]::CurrentThread.CurrentCulture = ''; [System.Threading.Thread]::CurrentThread.CurrentUICulture = '';& '%~dp0build.ps1' %*; exit $LASTEXITCODE" \ No newline at end of file +PowerShell -NoProfile -NoLogo -ExecutionPolicy unrestricted -Command "[System.Threading.Thread]::CurrentThread.CurrentCulture = ''; [System.Threading.Thread]::CurrentThread.CurrentUICulture = '';& '%~dp0build.ps1' %*; exit $LASTEXITCODE" diff --git a/build.ps1 b/build.ps1 index 5bf0e2c113..d5eb4d5cf2 100644 --- a/build.ps1 +++ b/build.ps1 @@ -1,67 +1,177 @@ -$ErrorActionPreference = "Stop" +#!/usr/bin/env powershell +#requires -version 4 -function DownloadWithRetry([string] $url, [string] $downloadLocation, [int] $retries) -{ - while($true) - { - try - { - Invoke-WebRequest $url -OutFile $downloadLocation - break - } - catch - { - $exceptionMessage = $_.Exception.Message - Write-Host "Failed to download '$url': $exceptionMessage" - if ($retries -gt 0) { - $retries-- - Write-Host "Waiting 10 seconds before retrying. Retries left: $retries" - Start-Sleep -Seconds 10 +<# +.SYNOPSIS +Build this repository +.DESCRIPTION +Downloads korebuild if required. Then builds the repository. + +.PARAMETER Path +The folder to build. Defaults to the folder containing this script. + +.PARAMETER Channel +The channel of KoreBuild to download. Overrides the value from the config file. + +.PARAMETER DotNetHome +The directory where .NET Core tools will be stored. + +.PARAMETER ToolsSource +The base url where build tools can be downloaded. Overrides the value from the config file. + +.PARAMETER Update +Updates KoreBuild to the latest version even if a lock file is present. + +.PARAMETER ConfigFile +The path to the configuration file that stores values. Defaults to version.xml. + +.PARAMETER MSBuildArgs +Arguments to be passed to MSBuild + +.NOTES +This function will create a file $PSScriptRoot/korebuild-lock.txt. This lock file can be committed to source, but does not have to be. +When the lockfile is not present, KoreBuild will create one using latest available version from $Channel. + +The $ConfigFile is expected to be an XML file. It is optional, and the configuration values in it are optional as well. + +.EXAMPLE +Example config file: +```xml + + + + dev + https://aspnetcore.blob.core.windows.net/buildtools + + +``` +#> +[CmdletBinding(PositionalBinding = $false)] +param( + [string]$Path = $PSScriptRoot, + [Alias('c')] + [string]$Channel, + [Alias('d')] + [string]$DotNetHome, + [Alias('s')] + [string]$ToolsSource, + [Alias('u')] + [switch]$Update, + [string]$ConfigFile = (Join-Path $PSScriptRoot 'version.xml'), + [Parameter(ValueFromRemainingArguments = $true)] + [string[]]$MSBuildArgs +) + +Set-StrictMode -Version 2 +$ErrorActionPreference = 'Stop' + +# +# Functions +# + +function Get-KoreBuild { + + $lockFile = Join-Path $Path 'korebuild-lock.txt' + + if (!(Test-Path $lockFile) -or $Update) { + Get-RemoteFile "$ToolsSource/korebuild/channels/$Channel/latest.txt" $lockFile + } + + $version = Get-Content $lockFile | Where-Object { $_ -like 'version:*' } | Select-Object -first 1 + if (!$version) { + Write-Error "Failed to parse version from $lockFile. Expected a line that begins with 'version:'" + } + $version = $version.TrimStart('version:').Trim() + $korebuildPath = Join-Paths $DotNetHome ('buildtools', 'korebuild', $version) + + if (!(Test-Path $korebuildPath)) { + Write-Host -ForegroundColor Magenta "Downloading KoreBuild $version" + New-Item -ItemType Directory -Path $korebuildPath | Out-Null + $remotePath = "$ToolsSource/korebuild/artifacts/$version/korebuild.$version.zip" + + try { + $tmpfile = Join-Path ([IO.Path]::GetTempPath()) "KoreBuild-$([guid]::NewGuid()).zip" + Get-RemoteFile $remotePath $tmpfile + if (Get-Command -Name 'Expand-Archive' -ErrorAction Ignore) { + # Use built-in commands where possible as they are cross-plat compatible + Expand-Archive -Path $tmpfile -DestinationPath $korebuildPath } - else - { - $exception = $_.Exception - throw $exception + else { + # Fallback to old approach for old installations of PowerShell + Add-Type -AssemblyName System.IO.Compression.FileSystem + [System.IO.Compression.ZipFile]::ExtractToDirectory($tmpfile, $korebuildPath) } } + catch { + Remove-Item -Recurse -Force $korebuildPath -ErrorAction Ignore + throw + } + finally { + Remove-Item $tmpfile -ErrorAction Ignore + } } + + return $korebuildPath } -cd $PSScriptRoot - -$repoFolder = $PSScriptRoot -$env:REPO_FOLDER = $repoFolder - -$koreBuildZip="https://github.com/aspnet/KoreBuild/archive/dev.zip" -if ($env:KOREBUILD_ZIP) -{ - $koreBuildZip=$env:KOREBUILD_ZIP +function Join-Paths([string]$path, [string[]]$childPaths) { + $childPaths | ForEach-Object { $path = Join-Path $path $_ } + return $path } -$buildFolder = ".build" -$buildFile="$buildFolder\KoreBuild.ps1" - -if (!(Test-Path $buildFolder)) { - Write-Host "Downloading KoreBuild from $koreBuildZip" - - $tempFolder=$env:TEMP + "\KoreBuild-" + [guid]::NewGuid() - New-Item -Path "$tempFolder" -Type directory | Out-Null - - $localZipFile="$tempFolder\korebuild.zip" - - DownloadWithRetry -url $koreBuildZip -downloadLocation $localZipFile -retries 6 - - Add-Type -AssemblyName System.IO.Compression.FileSystem - [System.IO.Compression.ZipFile]::ExtractToDirectory($localZipFile, $tempFolder) - - New-Item -Path "$buildFolder" -Type directory | Out-Null - copy-item "$tempFolder\**\build\*" $buildFolder -Recurse - - # Cleanup - if (Test-Path $tempFolder) { - Remove-Item -Recurse -Force $tempFolder +function Get-RemoteFile([string]$RemotePath, [string]$LocalPath) { + if ($RemotePath -notlike 'http*') { + Copy-Item $RemotePath $LocalPath + return } + + $retries = 10 + while ($retries -gt 0) { + $retries -= 1 + try { + Invoke-WebRequest -UseBasicParsing -Uri $RemotePath -OutFile $LocalPath + return + } + catch { + Write-Verbose "Request failed. $retries retries remaining" + } + } + + Write-Error "Download failed: '$RemotePath'." } -&"$buildFile" @args +# +# Main +# + +# Load configuration or set defaults + +if (Test-Path $ConfigFile) { + [xml] $config = Get-Content $ConfigFile + if (!($Channel)) { [string] $Channel = Select-Xml -Xml $config -XPath '/Project/PropertyGroup/KoreBuildChannel' } + if (!($ToolsSource)) { [string] $ToolsSource = Select-Xml -Xml $config -XPath '/Project/PropertyGroup/KoreBuildToolsSource' } +} + +if (!$DotNetHome) { + $DotNetHome = if ($env:DOTNET_HOME) { $env:DOTNET_HOME } ` + elseif ($env:USERPROFILE) { Join-Path $env:USERPROFILE '.dotnet'} ` + elseif ($env:HOME) {Join-Path $env:HOME '.dotnet'}` + else { Join-Path $PSScriptRoot '.dotnet'} +} + +if (!$Channel) { $Channel = 'dev' } +if (!$ToolsSource) { $ToolsSource = 'https://aspnetcore.blob.core.windows.net/buildtools' } + +# Execute + +$korebuildPath = Get-KoreBuild +Import-Module -Force -Scope Local (Join-Path $korebuildPath 'KoreBuild.psd1') + +try { + Install-Tools $ToolsSource $DotNetHome + Invoke-RepositoryBuild $Path @MSBuildArgs +} +finally { + Remove-Module 'KoreBuild' -ErrorAction Ignore +} diff --git a/build.sh b/build.sh index b0bcadb579..ab590e62f1 100755 --- a/build.sh +++ b/build.sh @@ -1,46 +1,196 @@ #!/usr/bin/env bash -repoFolder="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" -cd $repoFolder -koreBuildZip="https://github.com/aspnet/KoreBuild/archive/dev.zip" -if [ ! -z $KOREBUILD_ZIP ]; then - koreBuildZip=$KOREBUILD_ZIP -fi +set -euo pipefail -buildFolder=".build" -buildFile="$buildFolder/KoreBuild.sh" +# +# variables +# -if test ! -d $buildFolder; then - echo "Downloading KoreBuild from $koreBuildZip" +RESET="\033[0m" +RED="\033[0;31m" +MAGENTA="\033[0;95m" +DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" +[ -z "${DOTNET_HOME:-}"] && DOTNET_HOME="$HOME/.dotnet" +config_file="$DIR/version.xml" +verbose=false +update=false +repo_path="$DIR" +channel='' +tools_source='' - tempFolder="/tmp/KoreBuild-$(uuidgen)" - mkdir $tempFolder +# +# Functions +# +__usage() { + echo "Usage: $(basename ${BASH_SOURCE[0]}) [options] [[--] ...]" + echo "" + echo "Arguments:" + echo " ... Arguments passed to MSBuild. Variable number of arguments allowed." + echo "" + echo "Options:" + echo " --verbose Show verbose output." + echo " -c|--channel The channel of KoreBuild to download. Overrides the value from the config file.." + echo " --config-file TThe path to the configuration file that stores values. Defaults to version.xml." + echo " -d|--dotnet-home The directory where .NET Core tools will be stored. Defaults to '\$DOTNET_HOME' or '\$HOME/.dotnet." + echo " --path The directory to build. Defaults to the directory containing the script." + echo " -s|--tools-source The base url where build tools can be downloaded. Overrides the value from the config file." + echo " -u|--update Update to the latest KoreBuild even if the lock file is present." + echo "" + echo "Description:" + echo " This function will create a file \$DIR/korebuild-lock.txt. This lock file can be committed to source, but does not have to be." + echo " When the lockfile is not present, KoreBuild will create one using latest available version from \$channel." - localZipFile="$tempFolder/korebuild.zip" - - retries=6 - until (wget -O $localZipFile $koreBuildZip 2>/dev/null || curl -o $localZipFile --location $koreBuildZip 2>/dev/null) - do - echo "Failed to download '$koreBuildZip'" - if [ "$retries" -le 0 ]; then - exit 1 - fi - retries=$((retries - 1)) - echo "Waiting 10 seconds before retrying. Retries left: $retries" - sleep 10s - done - - unzip -q -d $tempFolder $localZipFile - - mkdir $buildFolder - cp -r $tempFolder/**/build/** $buildFolder - - chmod +x $buildFile - - # Cleanup - if test -d $tempFolder; then - rm -rf $tempFolder + if [[ "${1:-}" != '--no-exit' ]]; then + exit 2 fi +} + +get_korebuild() { + local lock_file="$repo_path/korebuild-lock.txt" + if [ ! -f $lock_file ] || [ "$update" = true ]; then + __get_remote_file "$tools_source/korebuild/channels/$channel/latest.txt" $lock_file + fi + local version="$(grep 'version:*' -m 1 $lock_file)" + if [[ "$version" == '' ]]; then + __error "Failed to parse version from $lock_file. Expected a line that begins with 'version:'" + return 1 + fi + version="$(echo ${version#version:} | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//')" + local korebuild_path="$DOTNET_HOME/buildtools/korebuild/$version" + + { + if [ ! -d "$korebuild_path" ]; then + mkdir -p "$korebuild_path" + local remote_path="$tools_source/korebuild/artifacts/$version/korebuild.$version.zip" + tmpfile="$(mktemp)" + echo -e "${MAGENTA}Downloading KoreBuild ${version}${RESET}" + if __get_remote_file $remote_path $tmpfile; then + unzip -q -d "$korebuild_path" $tmpfile + fi + rm $tmpfile || true + fi + + source "$korebuild_path/KoreBuild.sh" + } || { + if [ -d "$korebuild_path" ]; then + echo "Cleaning up after failed installation" + rm -rf "$korebuild_path" || true + fi + return 1 + } +} + +__error() { + echo -e "${RED}$@${RESET}" 1>&2 +} + +__machine_has() { + hash "$1" > /dev/null 2>&1 + return $? +} + +__get_remote_file() { + local remote_path=$1 + local local_path=$2 + + if [[ "$remote_path" != 'http'* ]]; then + cp $remote_path $local_path + return 0 + fi + + failed=false + if __machine_has wget; then + wget --tries 10 --quiet -O $local_path $remote_path || failed=true + fi + + if [ "$failed" = true ] && __machine_has curl; then + failed=false + curl --retry 10 -sSL -f --create-dirs -o $local_path $remote_path || failed=true + fi + + if [ "$failed" = true ]; then + __error "Download failed: $remote_path" 1>&2 + return 1 + fi +} + +__read_dom () { local IFS=\> ; read -d \< ENTITY CONTENT ;} + +# +# main +# + +while [[ $# > 0 ]]; do + case $1 in + -\?|-h|--help) + __usage --no-exit + exit 0 + ;; + -c|--channel|-Channel) + shift + channel=${1:-} + [ -z "$channel" ] && __usage + ;; + --config-file|-ConfigFile) + shift + config_file="${1:-}" + [ -z "$config_file" ] && __usage + ;; + -d|--dotnet-home|-DotNetHome) + shift + DOTNET_HOME=${1:-} + [ -z "$DOTNET_HOME" ] && __usage + ;; + --path|-Path) + shift + repo_path="${1:-}" + [ -z "$repo_path" ] && __usage + ;; + -s|--tools-source|-ToolsSource) + shift + tools_source="${1:-}" + [ -z "$tools_source" ] && __usage + ;; + -u|--update|-Update) + update=true + ;; + --verbose|-Verbose) + verbose=true + ;; + --) + shift + break + ;; + *) + break + ;; + esac + shift +done + +if ! __machine_has unzip; then + __error 'Missing required command: unzip' + exit 1 fi -$buildFile -r $repoFolder "$@" +if ! __machine_has curl && ! __machine_has wget; then + __error 'Missing required command. Either wget or curl is required.' + exit 1 +fi + +if [ -f $config_file ]; then + comment=false + while __read_dom; do + if [ "$comment" = true ]; then [[ $CONTENT == *'-->'* ]] && comment=false ; continue; fi + if [[ $ENTITY == '!--'* ]]; then comment=true; continue; fi + if [ -z "$channel" ] && [[ $ENTITY == "KoreBuildChannel" ]]; then channel=$CONTENT; fi + if [ -z "$tools_source" ] && [[ $ENTITY == "KoreBuildToolsSource" ]]; then tools_source=$CONTENT; fi + done < $config_file +fi + +[ -z "$channel" ] && channel='dev' +[ -z "$tools_source" ] && tools_source='https://aspnetcore.blob.core.windows.net/buildtools' + +get_korebuild +install_tools "$tools_source" "$DOTNET_HOME" +invoke_repository_build "$repo_path" $@ diff --git a/build/common.props b/build/common.props index 18f14b103d..f3bb8ac834 100644 --- a/build/common.props +++ b/build/common.props @@ -1,6 +1,6 @@ - + Microsoft ASP.NET Core diff --git a/version.props b/version.xml similarity index 55% rename from version.props rename to version.xml index 1ea46af42a..3c05022b7d 100644 --- a/version.props +++ b/version.xml @@ -1,6 +1,7 @@ - + + dev 2.1.0 preview1 From d517c5924844fd7a8522f76f356a4a00351d908d Mon Sep 17 00:00:00 2001 From: Nate McMaster Date: Wed, 26 Jul 2017 10:26:30 -0700 Subject: [PATCH 228/307] Fix syntax warning when running build.sh on older versions of bash [ci skip] --- build.sh | 41 +++++++++++++++++++++-------------------- 1 file changed, 21 insertions(+), 20 deletions(-) diff --git a/build.sh b/build.sh index ab590e62f1..5568c6182a 100755 --- a/build.sh +++ b/build.sh @@ -10,7 +10,7 @@ RESET="\033[0m" RED="\033[0;31m" MAGENTA="\033[0;95m" DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" -[ -z "${DOTNET_HOME:-}"] && DOTNET_HOME="$HOME/.dotnet" +[ -z "${DOTNET_HOME:-}" ] && DOTNET_HOME="$HOME/.dotnet" config_file="$DIR/version.xml" verbose=false update=false @@ -22,7 +22,7 @@ tools_source='' # Functions # __usage() { - echo "Usage: $(basename ${BASH_SOURCE[0]}) [options] [[--] ...]" + echo "Usage: $(basename "${BASH_SOURCE[0]}") [options] [[--] ...]" echo "" echo "Arguments:" echo " ... Arguments passed to MSBuild. Variable number of arguments allowed." @@ -46,16 +46,17 @@ __usage() { } get_korebuild() { + local version local lock_file="$repo_path/korebuild-lock.txt" - if [ ! -f $lock_file ] || [ "$update" = true ]; then - __get_remote_file "$tools_source/korebuild/channels/$channel/latest.txt" $lock_file + if [ ! -f "$lock_file" ] || [ "$update" = true ]; then + __get_remote_file "$tools_source/korebuild/channels/$channel/latest.txt" "$lock_file" fi - local version="$(grep 'version:*' -m 1 $lock_file)" + version="$(grep 'version:*' -m 1 "$lock_file")" if [[ "$version" == '' ]]; then __error "Failed to parse version from $lock_file. Expected a line that begins with 'version:'" return 1 fi - version="$(echo ${version#version:} | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//')" + version="$(echo "${version#version:}" | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//')" local korebuild_path="$DOTNET_HOME/buildtools/korebuild/$version" { @@ -64,10 +65,10 @@ get_korebuild() { local remote_path="$tools_source/korebuild/artifacts/$version/korebuild.$version.zip" tmpfile="$(mktemp)" echo -e "${MAGENTA}Downloading KoreBuild ${version}${RESET}" - if __get_remote_file $remote_path $tmpfile; then - unzip -q -d "$korebuild_path" $tmpfile + if __get_remote_file "$remote_path" "$tmpfile"; then + unzip -q -d "$korebuild_path" "$tmpfile" fi - rm $tmpfile || true + rm "$tmpfile" || true fi source "$korebuild_path/KoreBuild.sh" @@ -81,7 +82,7 @@ get_korebuild() { } __error() { - echo -e "${RED}$@${RESET}" 1>&2 + echo -e "${RED}$*${RESET}" 1>&2 } __machine_has() { @@ -94,18 +95,18 @@ __get_remote_file() { local local_path=$2 if [[ "$remote_path" != 'http'* ]]; then - cp $remote_path $local_path + cp "$remote_path" "$local_path" return 0 fi failed=false if __machine_has wget; then - wget --tries 10 --quiet -O $local_path $remote_path || failed=true + wget --tries 10 --quiet -O "$local_path" "$remote_path" || failed=true fi if [ "$failed" = true ] && __machine_has curl; then failed=false - curl --retry 10 -sSL -f --create-dirs -o $local_path $remote_path || failed=true + curl --retry 10 -sSL -f --create-dirs -o "$local_path" "$remote_path" || failed=true fi if [ "$failed" = true ]; then @@ -114,13 +115,13 @@ __get_remote_file() { fi } -__read_dom () { local IFS=\> ; read -d \< ENTITY CONTENT ;} +__read_dom () { local IFS=\> ; read -r -d \< ENTITY CONTENT ;} # # main # -while [[ $# > 0 ]]; do +while [[ $# -gt 0 ]]; do case $1 in -\?|-h|--help) __usage --no-exit @@ -128,7 +129,7 @@ while [[ $# > 0 ]]; do ;; -c|--channel|-Channel) shift - channel=${1:-} + channel="${1:-}" [ -z "$channel" ] && __usage ;; --config-file|-ConfigFile) @@ -138,7 +139,7 @@ while [[ $# > 0 ]]; do ;; -d|--dotnet-home|-DotNetHome) shift - DOTNET_HOME=${1:-} + DOTNET_HOME="${1:-}" [ -z "$DOTNET_HOME" ] && __usage ;; --path|-Path) @@ -178,14 +179,14 @@ if ! __machine_has curl && ! __machine_has wget; then exit 1 fi -if [ -f $config_file ]; then +if [ -f "$config_file" ]; then comment=false while __read_dom; do if [ "$comment" = true ]; then [[ $CONTENT == *'-->'* ]] && comment=false ; continue; fi if [[ $ENTITY == '!--'* ]]; then comment=true; continue; fi if [ -z "$channel" ] && [[ $ENTITY == "KoreBuildChannel" ]]; then channel=$CONTENT; fi if [ -z "$tools_source" ] && [[ $ENTITY == "KoreBuildToolsSource" ]]; then tools_source=$CONTENT; fi - done < $config_file + done < "$config_file" fi [ -z "$channel" ] && channel='dev' @@ -193,4 +194,4 @@ fi get_korebuild install_tools "$tools_source" "$DOTNET_HOME" -invoke_repository_build "$repo_path" $@ +invoke_repository_build "$repo_path" "$@" From 9dd92656bf1d8f0fdc1167f47122f5f3f4909099 Mon Sep 17 00:00:00 2001 From: John Luo Date: Wed, 2 Aug 2017 12:44:42 -0700 Subject: [PATCH 229/307] Update __get_remote_file logic --- build.sh | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/build.sh b/build.sh index 5568c6182a..8eace4c20d 100755 --- a/build.sh +++ b/build.sh @@ -99,17 +99,16 @@ __get_remote_file() { return 0 fi - failed=false + local succeeded=false if __machine_has wget; then - wget --tries 10 --quiet -O "$local_path" "$remote_path" || failed=true + wget --tries 10 --quiet -O "$local_path" "$remote_path" && succeeded=true fi - if [ "$failed" = true ] && __machine_has curl; then - failed=false - curl --retry 10 -sSL -f --create-dirs -o "$local_path" "$remote_path" || failed=true + if [ "$succeeded" = false ] && __machine_has curl; then + curl --retry 10 -sSL -f --create-dirs -o "$local_path" "$remote_path" && succeeded=true fi - if [ "$failed" = true ]; then + if [ "$succeeded" = false ]; then __error "Download failed: $remote_path" 1>&2 return 1 fi From 0eaa1138ec97cd10e449ac6d3c145ede55860cc2 Mon Sep 17 00:00:00 2001 From: John Luo Date: Wed, 2 Aug 2017 14:30:32 -0700 Subject: [PATCH 230/307] Ensure fallback to curl after failed wget --- build.sh | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/build.sh b/build.sh index 8eace4c20d..11cdbe5504 100755 --- a/build.sh +++ b/build.sh @@ -99,16 +99,19 @@ __get_remote_file() { return 0 fi - local succeeded=false + local failed=false if __machine_has wget; then - wget --tries 10 --quiet -O "$local_path" "$remote_path" && succeeded=true + wget --tries 10 --quiet -O "$local_path" "$remote_path" || failed=true + else + failed=true fi - if [ "$succeeded" = false ] && __machine_has curl; then - curl --retry 10 -sSL -f --create-dirs -o "$local_path" "$remote_path" && succeeded=true + if [ "$failed" = true ] && __machine_has curl; then + failed=false + curl --retry 10 -sSL -f --create-dirs -o "$local_path" "$remote_path" || failed=true fi - if [ "$succeeded" = false ]; then + if [ "$failed" = true ]; then __error "Download failed: $remote_path" 1>&2 return 1 fi From 793a49fe111d86895f22300297fa70f710459406 Mon Sep 17 00:00:00 2001 From: Nate McMaster Date: Tue, 22 Aug 2017 10:54:50 -0700 Subject: [PATCH 231/307] Upgrade xunit to 2.3.0-beta4 and use Directory.Build.props/targets --- appveyor.yml => .appveyor.yml | 0 BasicMiddleware.sln | 30 ++++++++++++++++++- build/common.props => Directory.Build.props | 10 ++----- Directory.Build.targets | 2 ++ build/dependencies.props | 5 ++-- .../HttpOverridesSample.csproj | 2 -- .../ResponseBufferingSample.csproj | 2 -- .../ResponseCompressionSample.csproj | 2 -- samples/RewriteSample/RewriteSample.csproj | 2 -- src/Directory.Build.props | 7 +++++ .../Microsoft.AspNetCore.Buffering.csproj | 2 -- .../Microsoft.AspNetCore.HttpOverrides.csproj | 2 -- ...soft.AspNetCore.ResponseCompression.csproj | 2 -- .../Microsoft.AspNetCore.Rewrite.csproj | 2 -- test/Directory.Build.props | 12 ++++++++ ...icrosoft.AspNetCore.Buffering.Tests.csproj | 9 ------ .../ForwardedHeadersMiddlewareTest.cs | 4 +-- ...soft.AspNetCore.HttpOverrides.Tests.csproj | 6 ---- ...spNetCore.ResponseCompression.Tests.csproj | 6 ---- .../Microsoft.AspNetCore.Rewrite.Tests.csproj | 10 ------- 20 files changed, 58 insertions(+), 59 deletions(-) rename appveyor.yml => .appveyor.yml (100%) rename build/common.props => Directory.Build.props (61%) create mode 100644 Directory.Build.targets create mode 100644 src/Directory.Build.props create mode 100644 test/Directory.Build.props diff --git a/appveyor.yml b/.appveyor.yml similarity index 100% rename from appveyor.yml rename to .appveyor.yml diff --git a/BasicMiddleware.sln b/BasicMiddleware.sln index 2fbc9f4838..b3f0434ba6 100644 --- a/BasicMiddleware.sln +++ b/BasicMiddleware.sln @@ -1,12 +1,18 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 15 -VisualStudioVersion = 15.0.26127.3 +VisualStudioVersion = 15.0.26817.0 MinimumVisualStudioVersion = 10.0.40219.1 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.HttpOverrides", "src\Microsoft.AspNetCore.HttpOverrides\Microsoft.AspNetCore.HttpOverrides.csproj", "{517308C3-B477-4B01-B461-CAB9C10B6928}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{A5076D28-FA7E-4606-9410-FEDD0D603527}" + ProjectSection(SolutionItems) = preProject + src\Directory.Build.props = src\Directory.Build.props + EndProjectSection EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{8437B0F3-3894-4828-A945-A9187F37631D}" + ProjectSection(SolutionItems) = preProject + test\Directory.Build.props = test\Directory.Build.props + EndProjectSection EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.HttpOverrides.Tests", "test\Microsoft.AspNetCore.HttpOverrides.Tests\Microsoft.AspNetCore.HttpOverrides.Tests.csproj", "{D6341B92-3416-4F11-8DF4-CB274296175F}" EndProject @@ -32,6 +38,25 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Respon EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ResponseCompressionSample", "samples\ResponseCompressionSample\ResponseCompressionSample.csproj", "{B2A3CE38-51B2-4486-982C-98C380AF140E}" EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{59A9B64C-E9BE-409E-89A2-58D72E2918F5}" + ProjectSection(SolutionItems) = preProject + .appveyor.yml = .appveyor.yml + .gitattributes = .gitattributes + .gitignore = .gitignore + .travis.yml = .travis.yml + build.cmd = build.cmd + build.ps1 = build.ps1 + build.sh = build.sh + CONTRIBUTING.md = CONTRIBUTING.md + Directory.Build.props = Directory.Build.props + Directory.Build.targets = Directory.Build.targets + LICENSE.txt = LICENSE.txt + NuGet.config = NuGet.config + NuGetPackageVerifier.json = NuGetPackageVerifier.json + README.md = README.md + version.xml = version.xml + EndProjectSection +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -104,4 +129,7 @@ Global {3360A5D1-70C0-49EE-9051-04A6A6B836DC} = {8437B0F3-3894-4828-A945-A9187F37631D} {B2A3CE38-51B2-4486-982C-98C380AF140E} = {9587FE9F-5A17-42C4-8021-E87F59CECB98} EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {4518E9CE-3680-4E05-9259-B64EA7807158} + EndGlobalSection EndGlobal diff --git a/build/common.props b/Directory.Build.props similarity index 61% rename from build/common.props rename to Directory.Build.props index f3bb8ac834..ffb3cd28ae 100644 --- a/build/common.props +++ b/Directory.Build.props @@ -1,20 +1,16 @@ - - + + Microsoft ASP.NET Core https://github.com/aspnet/BasicMiddleware git - $(MSBuildThisFileDirectory)Key.snk + $(MSBuildThisFileDirectory)build\Key.snk true true $(VersionSuffix)-$(BuildNumber) true - - - - diff --git a/Directory.Build.targets b/Directory.Build.targets new file mode 100644 index 0000000000..8c119d5413 --- /dev/null +++ b/Directory.Build.targets @@ -0,0 +1,2 @@ + + diff --git a/build/dependencies.props b/build/dependencies.props index 3945007fb2..8f3cbae099 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -6,7 +6,8 @@ 2.0.0-* 2.0.0-* 2.0.0-* - 15.3.0-* - 2.3.0-beta2-* + 15.3.0 + 2.3.0-beta4-build3742 + 0.6.1 diff --git a/samples/HttpOverridesSample/HttpOverridesSample.csproj b/samples/HttpOverridesSample/HttpOverridesSample.csproj index 9c8dc4616a..c975c27d60 100644 --- a/samples/HttpOverridesSample/HttpOverridesSample.csproj +++ b/samples/HttpOverridesSample/HttpOverridesSample.csproj @@ -1,7 +1,5 @@ - - net461;netcoreapp2.0 netcoreapp2.0 diff --git a/samples/ResponseBufferingSample/ResponseBufferingSample.csproj b/samples/ResponseBufferingSample/ResponseBufferingSample.csproj index f0aa4a439a..14545ef8ae 100644 --- a/samples/ResponseBufferingSample/ResponseBufferingSample.csproj +++ b/samples/ResponseBufferingSample/ResponseBufferingSample.csproj @@ -1,7 +1,5 @@ - - net461;netcoreapp2.0 netcoreapp2.0 diff --git a/samples/ResponseCompressionSample/ResponseCompressionSample.csproj b/samples/ResponseCompressionSample/ResponseCompressionSample.csproj index a5792ad3e8..ed18dc8e09 100644 --- a/samples/ResponseCompressionSample/ResponseCompressionSample.csproj +++ b/samples/ResponseCompressionSample/ResponseCompressionSample.csproj @@ -1,7 +1,5 @@ - - net461;netcoreapp2.0 netcoreapp2.0 diff --git a/samples/RewriteSample/RewriteSample.csproj b/samples/RewriteSample/RewriteSample.csproj index f9c78e7131..d53d958c42 100644 --- a/samples/RewriteSample/RewriteSample.csproj +++ b/samples/RewriteSample/RewriteSample.csproj @@ -1,7 +1,5 @@ - - net461;netcoreapp2.0 netcoreapp2.0 diff --git a/src/Directory.Build.props b/src/Directory.Build.props new file mode 100644 index 0000000000..e150035ea9 --- /dev/null +++ b/src/Directory.Build.props @@ -0,0 +1,7 @@ + + + + + + + diff --git a/src/Microsoft.AspNetCore.Buffering/Microsoft.AspNetCore.Buffering.csproj b/src/Microsoft.AspNetCore.Buffering/Microsoft.AspNetCore.Buffering.csproj index a3d42c869d..34282135bd 100644 --- a/src/Microsoft.AspNetCore.Buffering/Microsoft.AspNetCore.Buffering.csproj +++ b/src/Microsoft.AspNetCore.Buffering/Microsoft.AspNetCore.Buffering.csproj @@ -1,7 +1,5 @@  - - 0.4.0 ASP.NET Core middleware for buffering response bodies. diff --git a/src/Microsoft.AspNetCore.HttpOverrides/Microsoft.AspNetCore.HttpOverrides.csproj b/src/Microsoft.AspNetCore.HttpOverrides/Microsoft.AspNetCore.HttpOverrides.csproj index 7b8ae08a7c..914d51a16e 100644 --- a/src/Microsoft.AspNetCore.HttpOverrides/Microsoft.AspNetCore.HttpOverrides.csproj +++ b/src/Microsoft.AspNetCore.HttpOverrides/Microsoft.AspNetCore.HttpOverrides.csproj @@ -1,7 +1,5 @@  - - ASP.NET Core basic middleware for supporting HTTP method overrides. Includes: * X-Forwarded-* headers to forward headers from a proxy. diff --git a/src/Microsoft.AspNetCore.ResponseCompression/Microsoft.AspNetCore.ResponseCompression.csproj b/src/Microsoft.AspNetCore.ResponseCompression/Microsoft.AspNetCore.ResponseCompression.csproj index 78c240a0ec..2b574db3d6 100644 --- a/src/Microsoft.AspNetCore.ResponseCompression/Microsoft.AspNetCore.ResponseCompression.csproj +++ b/src/Microsoft.AspNetCore.ResponseCompression/Microsoft.AspNetCore.ResponseCompression.csproj @@ -1,7 +1,5 @@  - - ASP.NET Core middleware for HTTP Response compression. net461;netstandard2.0 diff --git a/src/Microsoft.AspNetCore.Rewrite/Microsoft.AspNetCore.Rewrite.csproj b/src/Microsoft.AspNetCore.Rewrite/Microsoft.AspNetCore.Rewrite.csproj index 87f5d80c07..2fd7e40f48 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Microsoft.AspNetCore.Rewrite.csproj +++ b/src/Microsoft.AspNetCore.Rewrite/Microsoft.AspNetCore.Rewrite.csproj @@ -1,7 +1,5 @@  - - ASP.NET Core basic middleware for rewriting URLs. Includes: * Support for custom URL rewrite rules diff --git a/test/Directory.Build.props b/test/Directory.Build.props new file mode 100644 index 0000000000..531ce09c1d --- /dev/null +++ b/test/Directory.Build.props @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/test/Microsoft.AspNetCore.Buffering.Tests/Microsoft.AspNetCore.Buffering.Tests.csproj b/test/Microsoft.AspNetCore.Buffering.Tests/Microsoft.AspNetCore.Buffering.Tests.csproj index 2f816560e1..b1938055cc 100644 --- a/test/Microsoft.AspNetCore.Buffering.Tests/Microsoft.AspNetCore.Buffering.Tests.csproj +++ b/test/Microsoft.AspNetCore.Buffering.Tests/Microsoft.AspNetCore.Buffering.Tests.csproj @@ -1,7 +1,5 @@  - - netcoreapp2.0;net461 netcoreapp2.0 @@ -11,11 +9,4 @@ - - - - - - - diff --git a/test/Microsoft.AspNetCore.HttpOverrides.Tests/ForwardedHeadersMiddlewareTest.cs b/test/Microsoft.AspNetCore.HttpOverrides.Tests/ForwardedHeadersMiddlewareTest.cs index a346712a8c..216cc608a1 100644 --- a/test/Microsoft.AspNetCore.HttpOverrides.Tests/ForwardedHeadersMiddlewareTest.cs +++ b/test/Microsoft.AspNetCore.HttpOverrides.Tests/ForwardedHeadersMiddlewareTest.cs @@ -483,8 +483,8 @@ namespace Microsoft.AspNetCore.HttpOverrides var options = new ForwardedHeadersOptions(); Assert.True(options.ForwardedHeaders == ForwardedHeaders.None); Assert.Equal(1, options.ForwardLimit); - Assert.Equal(1, options.KnownNetworks.Count()); - Assert.Equal(1, options.KnownProxies.Count()); + Assert.Single(options.KnownNetworks); + Assert.Single(options.KnownProxies); } [Fact] diff --git a/test/Microsoft.AspNetCore.HttpOverrides.Tests/Microsoft.AspNetCore.HttpOverrides.Tests.csproj b/test/Microsoft.AspNetCore.HttpOverrides.Tests/Microsoft.AspNetCore.HttpOverrides.Tests.csproj index 66d615c52a..213f7edb49 100644 --- a/test/Microsoft.AspNetCore.HttpOverrides.Tests/Microsoft.AspNetCore.HttpOverrides.Tests.csproj +++ b/test/Microsoft.AspNetCore.HttpOverrides.Tests/Microsoft.AspNetCore.HttpOverrides.Tests.csproj @@ -1,7 +1,5 @@  - - netcoreapp2.0;net461 netcoreapp2.0 @@ -12,11 +10,7 @@ - - - - diff --git a/test/Microsoft.AspNetCore.ResponseCompression.Tests/Microsoft.AspNetCore.ResponseCompression.Tests.csproj b/test/Microsoft.AspNetCore.ResponseCompression.Tests/Microsoft.AspNetCore.ResponseCompression.Tests.csproj index 06e467442b..3c95d83443 100644 --- a/test/Microsoft.AspNetCore.ResponseCompression.Tests/Microsoft.AspNetCore.ResponseCompression.Tests.csproj +++ b/test/Microsoft.AspNetCore.ResponseCompression.Tests/Microsoft.AspNetCore.ResponseCompression.Tests.csproj @@ -1,7 +1,5 @@  - - netcoreapp2.0;net461 netcoreapp2.0 @@ -17,12 +15,8 @@ - - - - diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/Microsoft.AspNetCore.Rewrite.Tests.csproj b/test/Microsoft.AspNetCore.Rewrite.Tests/Microsoft.AspNetCore.Rewrite.Tests.csproj index fcf17701e3..ebefe2dd1e 100644 --- a/test/Microsoft.AspNetCore.Rewrite.Tests/Microsoft.AspNetCore.Rewrite.Tests.csproj +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/Microsoft.AspNetCore.Rewrite.Tests.csproj @@ -1,7 +1,5 @@  - - netcoreapp2.0;net461 netcoreapp2.0 @@ -11,12 +9,4 @@ - - - - - - - - From 347d1abfce8c257125bea17067f10cf30ce85396 Mon Sep 17 00:00:00 2001 From: Nate McMaster Date: Wed, 30 Aug 2017 17:20:14 -0700 Subject: [PATCH 232/307] Use PackageLineup to manage PackageReference versions --- Directory.Build.props | 3 +-- Directory.Build.targets | 14 +++++++++++++- NuGet.config | 1 - build/dependencies.props | 13 ------------- build/repo.props | 6 ++++++ .../HttpOverridesSample/HttpOverridesSample.csproj | 4 ++-- .../ResponseBufferingSample.csproj | 4 ++-- .../ResponseCompressionSample.csproj | 6 +++--- samples/RewriteSample/RewriteSample.csproj | 6 +++--- src/Directory.Build.props | 4 ++-- .../Microsoft.AspNetCore.Buffering.csproj | 2 +- .../Microsoft.AspNetCore.HttpOverrides.csproj | 6 +++--- ...Microsoft.AspNetCore.ResponseCompression.csproj | 4 ++-- .../Microsoft.AspNetCore.Rewrite.csproj | 12 ++++++------ test/Directory.Build.props | 14 +++++++------- ...Microsoft.AspNetCore.HttpOverrides.Tests.csproj | 2 +- ...oft.AspNetCore.ResponseCompression.Tests.csproj | 6 +++--- 17 files changed, 55 insertions(+), 52 deletions(-) delete mode 100644 build/dependencies.props create mode 100644 build/repo.props diff --git a/Directory.Build.props b/Directory.Build.props index ffb3cd28ae..5dc2aa7c7b 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -1,5 +1,4 @@ - - + diff --git a/Directory.Build.targets b/Directory.Build.targets index 8c119d5413..bc118fd907 100644 --- a/Directory.Build.targets +++ b/Directory.Build.targets @@ -1,2 +1,14 @@ - + + + + <_BootstrapperFile Condition=" $([MSBuild]::IsOSUnixLike()) ">build.sh + <_BootstrapperFile Condition="! $([MSBuild]::IsOSUnixLike()) ">build.cmd + <_BootstrapperError> + Package references have not been pinned. Run './$(_BootstrapperFile) /t:Pin'. + Also, you can run './$(_BootstrapperFile) /t:Restore' which will pin *and* restore packages. '$(_BootstrapperFile)' can be found in '$(MSBuildThisFileDirectory)'. + + + + + diff --git a/NuGet.config b/NuGet.config index 4e8a1f6de1..20060c934e 100644 --- a/NuGet.config +++ b/NuGet.config @@ -3,7 +3,6 @@ - diff --git a/build/dependencies.props b/build/dependencies.props deleted file mode 100644 index 8f3cbae099..0000000000 --- a/build/dependencies.props +++ /dev/null @@ -1,13 +0,0 @@ - - - 2.1.0-* - 2.1.1-* - 4.7.49 - 2.0.0-* - 2.0.0-* - 2.0.0-* - 15.3.0 - 2.3.0-beta4-build3742 - 0.6.1 - - diff --git a/build/repo.props b/build/repo.props new file mode 100644 index 0000000000..13fe1c296a --- /dev/null +++ b/build/repo.props @@ -0,0 +1,6 @@ + + + + + + diff --git a/samples/HttpOverridesSample/HttpOverridesSample.csproj b/samples/HttpOverridesSample/HttpOverridesSample.csproj index c975c27d60..51d4942a9c 100644 --- a/samples/HttpOverridesSample/HttpOverridesSample.csproj +++ b/samples/HttpOverridesSample/HttpOverridesSample.csproj @@ -1,4 +1,4 @@ - + net461;netcoreapp2.0 @@ -10,7 +10,7 @@ - + diff --git a/samples/ResponseBufferingSample/ResponseBufferingSample.csproj b/samples/ResponseBufferingSample/ResponseBufferingSample.csproj index 14545ef8ae..fd2c6deb51 100644 --- a/samples/ResponseBufferingSample/ResponseBufferingSample.csproj +++ b/samples/ResponseBufferingSample/ResponseBufferingSample.csproj @@ -1,4 +1,4 @@ - + net461;netcoreapp2.0 @@ -10,7 +10,7 @@ - + diff --git a/samples/ResponseCompressionSample/ResponseCompressionSample.csproj b/samples/ResponseCompressionSample/ResponseCompressionSample.csproj index ed18dc8e09..d194cac2b7 100644 --- a/samples/ResponseCompressionSample/ResponseCompressionSample.csproj +++ b/samples/ResponseCompressionSample/ResponseCompressionSample.csproj @@ -1,4 +1,4 @@ - + net461;netcoreapp2.0 @@ -14,8 +14,8 @@ - - + + diff --git a/samples/RewriteSample/RewriteSample.csproj b/samples/RewriteSample/RewriteSample.csproj index d53d958c42..824c440f23 100644 --- a/samples/RewriteSample/RewriteSample.csproj +++ b/samples/RewriteSample/RewriteSample.csproj @@ -1,4 +1,4 @@ - + net461;netcoreapp2.0 @@ -10,8 +10,8 @@ - - + + diff --git a/src/Directory.Build.props b/src/Directory.Build.props index e150035ea9..9d9a3de33a 100644 --- a/src/Directory.Build.props +++ b/src/Directory.Build.props @@ -1,7 +1,7 @@ - + - + diff --git a/src/Microsoft.AspNetCore.Buffering/Microsoft.AspNetCore.Buffering.csproj b/src/Microsoft.AspNetCore.Buffering/Microsoft.AspNetCore.Buffering.csproj index 34282135bd..1ee8961e76 100644 --- a/src/Microsoft.AspNetCore.Buffering/Microsoft.AspNetCore.Buffering.csproj +++ b/src/Microsoft.AspNetCore.Buffering/Microsoft.AspNetCore.Buffering.csproj @@ -10,7 +10,7 @@ - + diff --git a/src/Microsoft.AspNetCore.HttpOverrides/Microsoft.AspNetCore.HttpOverrides.csproj b/src/Microsoft.AspNetCore.HttpOverrides/Microsoft.AspNetCore.HttpOverrides.csproj index 914d51a16e..74998e7f89 100644 --- a/src/Microsoft.AspNetCore.HttpOverrides/Microsoft.AspNetCore.HttpOverrides.csproj +++ b/src/Microsoft.AspNetCore.HttpOverrides/Microsoft.AspNetCore.HttpOverrides.csproj @@ -11,9 +11,9 @@ - - - + + + diff --git a/src/Microsoft.AspNetCore.ResponseCompression/Microsoft.AspNetCore.ResponseCompression.csproj b/src/Microsoft.AspNetCore.ResponseCompression/Microsoft.AspNetCore.ResponseCompression.csproj index 2b574db3d6..a9f7efac7f 100644 --- a/src/Microsoft.AspNetCore.ResponseCompression/Microsoft.AspNetCore.ResponseCompression.csproj +++ b/src/Microsoft.AspNetCore.ResponseCompression/Microsoft.AspNetCore.ResponseCompression.csproj @@ -8,8 +8,8 @@ - - + + diff --git a/src/Microsoft.AspNetCore.Rewrite/Microsoft.AspNetCore.Rewrite.csproj b/src/Microsoft.AspNetCore.Rewrite/Microsoft.AspNetCore.Rewrite.csproj index 2fd7e40f48..b23ccdf3cc 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Microsoft.AspNetCore.Rewrite.csproj +++ b/src/Microsoft.AspNetCore.Rewrite/Microsoft.AspNetCore.Rewrite.csproj @@ -12,12 +12,12 @@ - - - - - - + + + + + + diff --git a/test/Directory.Build.props b/test/Directory.Build.props index 531ce09c1d..546a887055 100644 --- a/test/Directory.Build.props +++ b/test/Directory.Build.props @@ -1,12 +1,12 @@ - + - - - - - - + + + + + + diff --git a/test/Microsoft.AspNetCore.HttpOverrides.Tests/Microsoft.AspNetCore.HttpOverrides.Tests.csproj b/test/Microsoft.AspNetCore.HttpOverrides.Tests/Microsoft.AspNetCore.HttpOverrides.Tests.csproj index 213f7edb49..c84cc3b395 100644 --- a/test/Microsoft.AspNetCore.HttpOverrides.Tests/Microsoft.AspNetCore.HttpOverrides.Tests.csproj +++ b/test/Microsoft.AspNetCore.HttpOverrides.Tests/Microsoft.AspNetCore.HttpOverrides.Tests.csproj @@ -10,7 +10,7 @@ - + diff --git a/test/Microsoft.AspNetCore.ResponseCompression.Tests/Microsoft.AspNetCore.ResponseCompression.Tests.csproj b/test/Microsoft.AspNetCore.ResponseCompression.Tests/Microsoft.AspNetCore.ResponseCompression.Tests.csproj index 3c95d83443..59949c5036 100644 --- a/test/Microsoft.AspNetCore.ResponseCompression.Tests/Microsoft.AspNetCore.ResponseCompression.Tests.csproj +++ b/test/Microsoft.AspNetCore.ResponseCompression.Tests/Microsoft.AspNetCore.ResponseCompression.Tests.csproj @@ -14,9 +14,9 @@ - - - + + + From 7fb18354fe7cd1d6d65c0022f54e7ddbf294fcbf Mon Sep 17 00:00:00 2001 From: Justin Kotalik Date: Thu, 21 Sep 2017 17:42:11 -0700 Subject: [PATCH 233/307] Increase Minimum Version of Visual Studio to 15.3.0 --- BasicMiddleware.sln | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/BasicMiddleware.sln b/BasicMiddleware.sln index b3f0434ba6..d915ed2016 100644 --- a/BasicMiddleware.sln +++ b/BasicMiddleware.sln @@ -1,7 +1,7 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 15 VisualStudioVersion = 15.0.26817.0 -MinimumVisualStudioVersion = 10.0.40219.1 +MinimumVisualStudioVersion = 15.0.26730.03 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.HttpOverrides", "src\Microsoft.AspNetCore.HttpOverrides\Microsoft.AspNetCore.HttpOverrides.csproj", "{517308C3-B477-4B01-B461-CAB9C10B6928}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{A5076D28-FA7E-4606-9410-FEDD0D603527}" From 83d139633094f9842d7496a8d832f45b9fbaf2a0 Mon Sep 17 00:00:00 2001 From: Ryan Brandenburg Date: Wed, 20 Sep 2017 13:18:02 -0700 Subject: [PATCH 234/307] Update bootstrappers --- .appveyor.yml | 4 +- build.cmd | 2 +- build.sh | 197 +------------------------------------- run.cmd | 2 + build.ps1 => run.ps1 | 56 +++++++---- run.sh | 223 +++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 266 insertions(+), 218 deletions(-) create mode 100644 run.cmd rename build.ps1 => run.ps1 (73%) create mode 100755 run.sh diff --git a/.appveyor.yml b/.appveyor.yml index 31efd8196f..46038786c9 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -1,4 +1,4 @@ -init: +init: - git config --global core.autocrlf true branches: only: @@ -7,7 +7,7 @@ branches: - dev - /^(.*\/)?ci-.*$/ build_script: - - ps: .\build.ps1 + - ps: .\run.ps1 default-build clone_depth: 1 environment: global: diff --git a/build.cmd b/build.cmd index b6c8d24864..c0050bda12 100644 --- a/build.cmd +++ b/build.cmd @@ -1,2 +1,2 @@ @ECHO OFF -PowerShell -NoProfile -NoLogo -ExecutionPolicy unrestricted -Command "[System.Threading.Thread]::CurrentThread.CurrentCulture = ''; [System.Threading.Thread]::CurrentThread.CurrentUICulture = '';& '%~dp0build.ps1' %*; exit $LASTEXITCODE" +PowerShell -NoProfile -NoLogo -ExecutionPolicy unrestricted -Command "[System.Threading.Thread]::CurrentThread.CurrentCulture = ''; [System.Threading.Thread]::CurrentThread.CurrentUICulture = '';& '%~dp0run.ps1' default-build %*; exit $LASTEXITCODE" diff --git a/build.sh b/build.sh index 11cdbe5504..98a4b22765 100755 --- a/build.sh +++ b/build.sh @@ -1,199 +1,8 @@ #!/usr/bin/env bash set -euo pipefail - -# -# variables -# - -RESET="\033[0m" -RED="\033[0;31m" -MAGENTA="\033[0;95m" DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" -[ -z "${DOTNET_HOME:-}" ] && DOTNET_HOME="$HOME/.dotnet" -config_file="$DIR/version.xml" -verbose=false -update=false -repo_path="$DIR" -channel='' -tools_source='' -# -# Functions -# -__usage() { - echo "Usage: $(basename "${BASH_SOURCE[0]}") [options] [[--] ...]" - echo "" - echo "Arguments:" - echo " ... Arguments passed to MSBuild. Variable number of arguments allowed." - echo "" - echo "Options:" - echo " --verbose Show verbose output." - echo " -c|--channel The channel of KoreBuild to download. Overrides the value from the config file.." - echo " --config-file TThe path to the configuration file that stores values. Defaults to version.xml." - echo " -d|--dotnet-home The directory where .NET Core tools will be stored. Defaults to '\$DOTNET_HOME' or '\$HOME/.dotnet." - echo " --path The directory to build. Defaults to the directory containing the script." - echo " -s|--tools-source The base url where build tools can be downloaded. Overrides the value from the config file." - echo " -u|--update Update to the latest KoreBuild even if the lock file is present." - echo "" - echo "Description:" - echo " This function will create a file \$DIR/korebuild-lock.txt. This lock file can be committed to source, but does not have to be." - echo " When the lockfile is not present, KoreBuild will create one using latest available version from \$channel." - - if [[ "${1:-}" != '--no-exit' ]]; then - exit 2 - fi -} - -get_korebuild() { - local version - local lock_file="$repo_path/korebuild-lock.txt" - if [ ! -f "$lock_file" ] || [ "$update" = true ]; then - __get_remote_file "$tools_source/korebuild/channels/$channel/latest.txt" "$lock_file" - fi - version="$(grep 'version:*' -m 1 "$lock_file")" - if [[ "$version" == '' ]]; then - __error "Failed to parse version from $lock_file. Expected a line that begins with 'version:'" - return 1 - fi - version="$(echo "${version#version:}" | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//')" - local korebuild_path="$DOTNET_HOME/buildtools/korebuild/$version" - - { - if [ ! -d "$korebuild_path" ]; then - mkdir -p "$korebuild_path" - local remote_path="$tools_source/korebuild/artifacts/$version/korebuild.$version.zip" - tmpfile="$(mktemp)" - echo -e "${MAGENTA}Downloading KoreBuild ${version}${RESET}" - if __get_remote_file "$remote_path" "$tmpfile"; then - unzip -q -d "$korebuild_path" "$tmpfile" - fi - rm "$tmpfile" || true - fi - - source "$korebuild_path/KoreBuild.sh" - } || { - if [ -d "$korebuild_path" ]; then - echo "Cleaning up after failed installation" - rm -rf "$korebuild_path" || true - fi - return 1 - } -} - -__error() { - echo -e "${RED}$*${RESET}" 1>&2 -} - -__machine_has() { - hash "$1" > /dev/null 2>&1 - return $? -} - -__get_remote_file() { - local remote_path=$1 - local local_path=$2 - - if [[ "$remote_path" != 'http'* ]]; then - cp "$remote_path" "$local_path" - return 0 - fi - - local failed=false - if __machine_has wget; then - wget --tries 10 --quiet -O "$local_path" "$remote_path" || failed=true - else - failed=true - fi - - if [ "$failed" = true ] && __machine_has curl; then - failed=false - curl --retry 10 -sSL -f --create-dirs -o "$local_path" "$remote_path" || failed=true - fi - - if [ "$failed" = true ]; then - __error "Download failed: $remote_path" 1>&2 - return 1 - fi -} - -__read_dom () { local IFS=\> ; read -r -d \< ENTITY CONTENT ;} - -# -# main -# - -while [[ $# -gt 0 ]]; do - case $1 in - -\?|-h|--help) - __usage --no-exit - exit 0 - ;; - -c|--channel|-Channel) - shift - channel="${1:-}" - [ -z "$channel" ] && __usage - ;; - --config-file|-ConfigFile) - shift - config_file="${1:-}" - [ -z "$config_file" ] && __usage - ;; - -d|--dotnet-home|-DotNetHome) - shift - DOTNET_HOME="${1:-}" - [ -z "$DOTNET_HOME" ] && __usage - ;; - --path|-Path) - shift - repo_path="${1:-}" - [ -z "$repo_path" ] && __usage - ;; - -s|--tools-source|-ToolsSource) - shift - tools_source="${1:-}" - [ -z "$tools_source" ] && __usage - ;; - -u|--update|-Update) - update=true - ;; - --verbose|-Verbose) - verbose=true - ;; - --) - shift - break - ;; - *) - break - ;; - esac - shift -done - -if ! __machine_has unzip; then - __error 'Missing required command: unzip' - exit 1 -fi - -if ! __machine_has curl && ! __machine_has wget; then - __error 'Missing required command. Either wget or curl is required.' - exit 1 -fi - -if [ -f "$config_file" ]; then - comment=false - while __read_dom; do - if [ "$comment" = true ]; then [[ $CONTENT == *'-->'* ]] && comment=false ; continue; fi - if [[ $ENTITY == '!--'* ]]; then comment=true; continue; fi - if [ -z "$channel" ] && [[ $ENTITY == "KoreBuildChannel" ]]; then channel=$CONTENT; fi - if [ -z "$tools_source" ] && [[ $ENTITY == "KoreBuildToolsSource" ]]; then tools_source=$CONTENT; fi - done < "$config_file" -fi - -[ -z "$channel" ] && channel='dev' -[ -z "$tools_source" ] && tools_source='https://aspnetcore.blob.core.windows.net/buildtools' - -get_korebuild -install_tools "$tools_source" "$DOTNET_HOME" -invoke_repository_build "$repo_path" "$@" +# Call "sync" between "chmod" and execution to prevent "text file busy" error in Docker (aufs) +chmod +x "$DIR/run.sh"; sync +"$DIR/run.sh" default-build "$@" diff --git a/run.cmd b/run.cmd new file mode 100644 index 0000000000..d52d5c7e68 --- /dev/null +++ b/run.cmd @@ -0,0 +1,2 @@ +@ECHO OFF +PowerShell -NoProfile -NoLogo -ExecutionPolicy unrestricted -Command "[System.Threading.Thread]::CurrentThread.CurrentCulture = ''; [System.Threading.Thread]::CurrentThread.CurrentUICulture = '';& '%~dp0run.ps1' %*; exit $LASTEXITCODE" diff --git a/build.ps1 b/run.ps1 similarity index 73% rename from build.ps1 rename to run.ps1 index d5eb4d5cf2..49c2899856 100644 --- a/build.ps1 +++ b/run.ps1 @@ -3,10 +3,13 @@ <# .SYNOPSIS -Build this repository +Executes KoreBuild commands. .DESCRIPTION -Downloads korebuild if required. Then builds the repository. +Downloads korebuild if required. Then executes the KoreBuild command. To see available commands, execute with `-Command help`. + +.PARAMETER Command +The KoreBuild command to run. .PARAMETER Path The folder to build. Defaults to the folder containing this script. @@ -24,31 +27,32 @@ The base url where build tools can be downloaded. Overrides the value from the c Updates KoreBuild to the latest version even if a lock file is present. .PARAMETER ConfigFile -The path to the configuration file that stores values. Defaults to version.xml. +The path to the configuration file that stores values. Defaults to korebuild.json. -.PARAMETER MSBuildArgs -Arguments to be passed to MSBuild +.PARAMETER Arguments +Arguments to be passed to the command .NOTES This function will create a file $PSScriptRoot/korebuild-lock.txt. This lock file can be committed to source, but does not have to be. When the lockfile is not present, KoreBuild will create one using latest available version from $Channel. -The $ConfigFile is expected to be an XML file. It is optional, and the configuration values in it are optional as well. +The $ConfigFile is expected to be an JSON file. It is optional, and the configuration values in it are optional as well. Any options set +in the file are overridden by command line parameters. .EXAMPLE Example config file: -```xml - - - - dev - https://aspnetcore.blob.core.windows.net/buildtools - - +```json +{ + "$schema": "https://raw.githubusercontent.com/aspnet/BuildTools/dev/tools/korebuild.schema.json", + "channel": "dev", + "toolsSource": "https://aspnetcore.blob.core.windows.net/buildtools" +} ``` #> [CmdletBinding(PositionalBinding = $false)] param( + [Parameter(Mandatory=$true, Position = 0)] + [string]$Command, [string]$Path = $PSScriptRoot, [Alias('c')] [string]$Channel, @@ -58,9 +62,9 @@ param( [string]$ToolsSource, [Alias('u')] [switch]$Update, - [string]$ConfigFile = (Join-Path $PSScriptRoot 'version.xml'), + [string]$ConfigFile, [Parameter(ValueFromRemainingArguments = $true)] - [string[]]$MSBuildArgs + [string[]]$Arguments ) Set-StrictMode -Version 2 @@ -147,10 +151,20 @@ function Get-RemoteFile([string]$RemotePath, [string]$LocalPath) { # Load configuration or set defaults +$Path = Resolve-Path $Path +if (!$ConfigFile) { $ConfigFile = Join-Path $Path 'korebuild.json' } + if (Test-Path $ConfigFile) { - [xml] $config = Get-Content $ConfigFile - if (!($Channel)) { [string] $Channel = Select-Xml -Xml $config -XPath '/Project/PropertyGroup/KoreBuildChannel' } - if (!($ToolsSource)) { [string] $ToolsSource = Select-Xml -Xml $config -XPath '/Project/PropertyGroup/KoreBuildToolsSource' } + try { + $config = Get-Content -Raw -Encoding UTF8 -Path $ConfigFile | ConvertFrom-Json + if ($config) { + if (!($Channel) -and (Get-Member -Name 'channel' -InputObject $config)) { [string] $Channel = $config.channel } + if (!($ToolsSource) -and (Get-Member -Name 'toolsSource' -InputObject $config)) { [string] $ToolsSource = $config.toolsSource} + } + } catch { + Write-Warning "$ConfigFile could not be read. Its settings will be ignored." + Write-Warning $Error[0] + } } if (!$DotNetHome) { @@ -169,8 +183,8 @@ $korebuildPath = Get-KoreBuild Import-Module -Force -Scope Local (Join-Path $korebuildPath 'KoreBuild.psd1') try { - Install-Tools $ToolsSource $DotNetHome - Invoke-RepositoryBuild $Path @MSBuildArgs + Set-KoreBuildSettings -ToolsSource $ToolsSource -DotNetHome $DotNetHome -RepoPath $Path -ConfigFile $ConfigFile + Invoke-KoreBuildCommand $Command @Arguments } finally { Remove-Module 'KoreBuild' -ErrorAction Ignore diff --git a/run.sh b/run.sh new file mode 100755 index 0000000000..c278423acc --- /dev/null +++ b/run.sh @@ -0,0 +1,223 @@ +#!/usr/bin/env bash + +set -euo pipefail + +# +# variables +# + +RESET="\033[0m" +RED="\033[0;31m" +YELLOW="\033[0;33m" +MAGENTA="\033[0;95m" +DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" +[ -z "${DOTNET_HOME:-}" ] && DOTNET_HOME="$HOME/.dotnet" +verbose=false +update=false +repo_path="$DIR" +channel='' +tools_source='' + +# +# Functions +# +__usage() { + echo "Usage: $(basename "${BASH_SOURCE[0]}") command [options] [[--] ...]" + echo "" + echo "Arguments:" + echo " command The command to be run." + echo " ... Arguments passed to the command. Variable number of arguments allowed." + echo "" + echo "Options:" + echo " --verbose Show verbose output." + echo " -c|--channel The channel of KoreBuild to download. Overrides the value from the config file.." + echo " --config-file The path to the configuration file that stores values. Defaults to korebuild.json." + echo " -d|--dotnet-home The directory where .NET Core tools will be stored. Defaults to '\$DOTNET_HOME' or '\$HOME/.dotnet." + echo " --path The directory to build. Defaults to the directory containing the script." + echo " -s|--tools-source|-ToolsSource The base url where build tools can be downloaded. Overrides the value from the config file." + echo " -u|--update Update to the latest KoreBuild even if the lock file is present." + echo "" + echo "Description:" + echo " This function will create a file \$DIR/korebuild-lock.txt. This lock file can be committed to source, but does not have to be." + echo " When the lockfile is not present, KoreBuild will create one using latest available version from \$channel." + + if [[ "${1:-}" != '--no-exit' ]]; then + exit 2 + fi +} + +get_korebuild() { + local version + local lock_file="$repo_path/korebuild-lock.txt" + if [ ! -f "$lock_file" ] || [ "$update" = true ]; then + __get_remote_file "$tools_source/korebuild/channels/$channel/latest.txt" "$lock_file" + fi + version="$(grep 'version:*' -m 1 "$lock_file")" + if [[ "$version" == '' ]]; then + __error "Failed to parse version from $lock_file. Expected a line that begins with 'version:'" + return 1 + fi + version="$(echo "${version#version:}" | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//')" + local korebuild_path="$DOTNET_HOME/buildtools/korebuild/$version" + + { + if [ ! -d "$korebuild_path" ]; then + mkdir -p "$korebuild_path" + local remote_path="$tools_source/korebuild/artifacts/$version/korebuild.$version.zip" + tmpfile="$(mktemp)" + echo -e "${MAGENTA}Downloading KoreBuild ${version}${RESET}" + if __get_remote_file "$remote_path" "$tmpfile"; then + unzip -q -d "$korebuild_path" "$tmpfile" + fi + rm "$tmpfile" || true + fi + + source "$korebuild_path/KoreBuild.sh" + } || { + if [ -d "$korebuild_path" ]; then + echo "Cleaning up after failed installation" + rm -rf "$korebuild_path" || true + fi + return 1 + } +} + +__error() { + echo -e "${RED}error: $*${RESET}" 1>&2 +} + +__warn() { + echo -e "${YELLOW}warning: $*${RESET}" +} + +__machine_has() { + hash "$1" > /dev/null 2>&1 + return $? +} + +__get_remote_file() { + local remote_path=$1 + local local_path=$2 + + if [[ "$remote_path" != 'http'* ]]; then + cp "$remote_path" "$local_path" + return 0 + fi + + local failed=false + if __machine_has wget; then + wget --tries 10 --quiet -O "$local_path" "$remote_path" || failed=true + else + failed=true + fi + + if [ "$failed" = true ] && __machine_has curl; then + failed=false + curl --retry 10 -sSL -f --create-dirs -o "$local_path" "$remote_path" || failed=true + fi + + if [ "$failed" = true ]; then + __error "Download failed: $remote_path" 1>&2 + return 1 + fi +} + +# +# main +# + +command="${1:-}" +shift + +while [[ $# -gt 0 ]]; do + case $1 in + -\?|-h|--help) + __usage --no-exit + exit 0 + ;; + -c|--channel|-Channel) + shift + channel="${1:-}" + [ -z "$channel" ] && __usage + ;; + --config-file|-ConfigFile) + shift + config_file="${1:-}" + [ -z "$config_file" ] && __usage + if [ ! -f "$config_file" ]; then + __error "Invalid value for --config-file. $config_file does not exist." + exit 1 + fi + ;; + -d|--dotnet-home|-DotNetHome) + shift + DOTNET_HOME="${1:-}" + [ -z "$DOTNET_HOME" ] && __usage + ;; + --path|-Path) + shift + repo_path="${1:-}" + [ -z "$repo_path" ] && __usage + ;; + -s|--tools-source|-ToolsSource) + shift + tools_source="${1:-}" + [ -z "$tools_source" ] && __usage + ;; + -u|--update|-Update) + update=true + ;; + --verbose|-Verbose) + verbose=true + ;; + --) + shift + break + ;; + *) + break + ;; + esac + shift +done + +if ! __machine_has unzip; then + __error 'Missing required command: unzip' + exit 1 +fi + +if ! __machine_has curl && ! __machine_has wget; then + __error 'Missing required command. Either wget or curl is required.' + exit 1 +fi + +[ -z "${config_file:-}" ] && config_file="$repo_path/korebuild.json" +if [ -f "$config_file" ]; then + if __machine_has jq ; then + if jq '.' "$config_file" >/dev/null ; then + config_channel="$(jq -r 'select(.channel!=null) | .channel' "$config_file")" + config_tools_source="$(jq -r 'select(.toolsSource!=null) | .toolsSource' "$config_file")" + else + __warn "$config_file is invalid JSON. Its settings will be ignored." + fi + elif __machine_has python ; then + if python -c "import json,codecs;obj=json.load(codecs.open('$config_file', 'r', 'utf-8-sig'))" >/dev/null ; then + config_channel="$(python -c "import json,codecs;obj=json.load(codecs.open('$config_file', 'r', 'utf-8-sig'));print(obj['channel'] if 'channel' in obj else '')")" + config_tools_source="$(python -c "import json,codecs;obj=json.load(codecs.open('$config_file', 'r', 'utf-8-sig'));print(obj['toolsSource'] if 'toolsSource' in obj else '')")" + else + __warn "$config_file is invalid JSON. Its settings will be ignored." + fi + else + __warn 'Missing required command: jq or pyton. Could not parse the JSON file. Its settings will be ignored.' + fi + + [ ! -z "${config_channel:-}" ] && channel="$config_channel" + [ ! -z "${config_tools_source:-}" ] && tools_source="$config_tools_source" +fi + +[ -z "$channel" ] && channel='dev' +[ -z "$tools_source" ] && tools_source='https://aspnetcore.blob.core.windows.net/buildtools' + +get_korebuild +set_korebuildsettings "$tools_source" "$DOTNET_HOME" "$repo_path" "$config_file" +invoke_korebuild_command "$command" "$@" From 758f9fcea590dbaf7294c940b2f7f32f01927379 Mon Sep 17 00:00:00 2001 From: Justin Kotalik Date: Fri, 13 Oct 2017 12:15:35 -0700 Subject: [PATCH 235/307] Adds Https Redirection and Hsts Middlewares (#264) --- BasicMiddleware.sln | 21 +++ .../HttpsPolicySample.csproj | 17 +++ .../Properties/launchSettings.json | 27 ++++ samples/HttpsPolicySample/Startup.cs | 71 ++++++++++ samples/HttpsPolicySample/testCert.pfx | Bin 0 -> 2483 bytes .../HstsBuilderExtensions.cs | 30 ++++ .../HstsMiddleware.cs | 68 ++++++++++ .../HstsOptions.cs | 39 ++++++ .../HstsServicesExtensions.cs | 36 +++++ .../HttpsRedirectionBuilderExtensions.cs | 44 ++++++ .../HttpsRedirectionOptions.cs | 26 ++++ .../HttpsRedirectionServicesExtensions.cs | 36 +++++ .../Microsoft.AspNetCore.HttpsPolicy.csproj | 16 +++ .../HstsMiddlewareTests.cs | 128 ++++++++++++++++++ .../HttpsPolicyTests.cs | 76 +++++++++++ .../HttpsRedirectionMiddlewareTests.cs | 125 +++++++++++++++++ ...rosoft.AspNetCore.HttpsPolicy.Tests.csproj | 10 ++ 17 files changed, 770 insertions(+) create mode 100644 samples/HttpsPolicySample/HttpsPolicySample.csproj create mode 100644 samples/HttpsPolicySample/Properties/launchSettings.json create mode 100644 samples/HttpsPolicySample/Startup.cs create mode 100644 samples/HttpsPolicySample/testCert.pfx create mode 100644 src/Microsoft.AspNetCore.HttpsPolicy/HstsBuilderExtensions.cs create mode 100644 src/Microsoft.AspNetCore.HttpsPolicy/HstsMiddleware.cs create mode 100644 src/Microsoft.AspNetCore.HttpsPolicy/HstsOptions.cs create mode 100644 src/Microsoft.AspNetCore.HttpsPolicy/HstsServicesExtensions.cs create mode 100644 src/Microsoft.AspNetCore.HttpsPolicy/HttpsRedirectionBuilderExtensions.cs create mode 100644 src/Microsoft.AspNetCore.HttpsPolicy/HttpsRedirectionOptions.cs create mode 100644 src/Microsoft.AspNetCore.HttpsPolicy/HttpsRedirectionServicesExtensions.cs create mode 100644 src/Microsoft.AspNetCore.HttpsPolicy/Microsoft.AspNetCore.HttpsPolicy.csproj create mode 100644 test/Microsoft.AspNetCore.HttpsEnforcement.Tests/HstsMiddlewareTests.cs create mode 100644 test/Microsoft.AspNetCore.HttpsEnforcement.Tests/HttpsPolicyTests.cs create mode 100644 test/Microsoft.AspNetCore.HttpsEnforcement.Tests/HttpsRedirectionMiddlewareTests.cs create mode 100644 test/Microsoft.AspNetCore.HttpsEnforcement.Tests/Microsoft.AspNetCore.HttpsPolicy.Tests.csproj diff --git a/BasicMiddleware.sln b/BasicMiddleware.sln index d915ed2016..c123191126 100644 --- a/BasicMiddleware.sln +++ b/BasicMiddleware.sln @@ -57,6 +57,12 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution version.xml = version.xml EndProjectSection EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.HttpsPolicy", "src\Microsoft.AspNetCore.HttpsPolicy\Microsoft.AspNetCore.HttpsPolicy.csproj", "{4D39C29B-4EC8-497C-B411-922DA494D71B}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "HttpsPolicySample", "samples\HttpsPolicySample\HttpsPolicySample.csproj", "{AC424AEE-4883-49C6-945F-2FC916B8CA1C}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.HttpsPolicy.Tests", "test\Microsoft.AspNetCore.HttpsEnforcement.Tests\Microsoft.AspNetCore.HttpsPolicy.Tests.csproj", "{1C67B0F1-6E70-449E-A2F1-98B9D5C576CE}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -111,6 +117,18 @@ Global {B2A3CE38-51B2-4486-982C-98C380AF140E}.Debug|Any CPU.Build.0 = Debug|Any CPU {B2A3CE38-51B2-4486-982C-98C380AF140E}.Release|Any CPU.ActiveCfg = Release|Any CPU {B2A3CE38-51B2-4486-982C-98C380AF140E}.Release|Any CPU.Build.0 = Release|Any CPU + {4D39C29B-4EC8-497C-B411-922DA494D71B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {4D39C29B-4EC8-497C-B411-922DA494D71B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {4D39C29B-4EC8-497C-B411-922DA494D71B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {4D39C29B-4EC8-497C-B411-922DA494D71B}.Release|Any CPU.Build.0 = Release|Any CPU + {AC424AEE-4883-49C6-945F-2FC916B8CA1C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {AC424AEE-4883-49C6-945F-2FC916B8CA1C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {AC424AEE-4883-49C6-945F-2FC916B8CA1C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {AC424AEE-4883-49C6-945F-2FC916B8CA1C}.Release|Any CPU.Build.0 = Release|Any CPU + {1C67B0F1-6E70-449E-A2F1-98B9D5C576CE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1C67B0F1-6E70-449E-A2F1-98B9D5C576CE}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1C67B0F1-6E70-449E-A2F1-98B9D5C576CE}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1C67B0F1-6E70-449E-A2F1-98B9D5C576CE}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -128,6 +146,9 @@ Global {45308A9D-F4C6-46A8-A24F-E73D995CC223} = {A5076D28-FA7E-4606-9410-FEDD0D603527} {3360A5D1-70C0-49EE-9051-04A6A6B836DC} = {8437B0F3-3894-4828-A945-A9187F37631D} {B2A3CE38-51B2-4486-982C-98C380AF140E} = {9587FE9F-5A17-42C4-8021-E87F59CECB98} + {4D39C29B-4EC8-497C-B411-922DA494D71B} = {A5076D28-FA7E-4606-9410-FEDD0D603527} + {AC424AEE-4883-49C6-945F-2FC916B8CA1C} = {9587FE9F-5A17-42C4-8021-E87F59CECB98} + {1C67B0F1-6E70-449E-A2F1-98B9D5C576CE} = {8437B0F3-3894-4828-A945-A9187F37631D} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {4518E9CE-3680-4E05-9259-B64EA7807158} diff --git a/samples/HttpsPolicySample/HttpsPolicySample.csproj b/samples/HttpsPolicySample/HttpsPolicySample.csproj new file mode 100644 index 0000000000..a9d5f11b71 --- /dev/null +++ b/samples/HttpsPolicySample/HttpsPolicySample.csproj @@ -0,0 +1,17 @@ + + + + net461;netcoreapp2.0 + netcoreapp2.0 + + + + + + + + + + + + diff --git a/samples/HttpsPolicySample/Properties/launchSettings.json b/samples/HttpsPolicySample/Properties/launchSettings.json new file mode 100644 index 0000000000..fbffc1f457 --- /dev/null +++ b/samples/HttpsPolicySample/Properties/launchSettings.json @@ -0,0 +1,27 @@ +{ + "iisSettings": { + "windowsAuthentication": false, + "anonymousAuthentication": true, + "iisExpress": { + "applicationUrl": "http://localhost:31894/", + "sslPort": 0 + } + }, + "profiles": { + "IIS Express": { + "commandName": "IISExpress", + "launchBrowser": true, + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + }, + "HttpsSample": { + "commandName": "Project", + "launchBrowser": true, + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + }, + "applicationUrl": "http://localhost:31895/" + } + } +} diff --git a/samples/HttpsPolicySample/Startup.cs b/samples/HttpsPolicySample/Startup.cs new file mode 100644 index 0000000000..4fb7e62871 --- /dev/null +++ b/samples/HttpsPolicySample/Startup.cs @@ -0,0 +1,71 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Net; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.HttpsPolicy; +using Microsoft.Extensions.DependencyInjection; + +namespace HttpsSample +{ + public class Startup + { + // This method gets called by the runtime. Use this method to add services to the container. + // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940 + public void ConfigureServices(IServiceCollection services) + { + services.AddHttpsRedirection(options => + { + options.RedirectStatusCode = StatusCodes.Status301MovedPermanently; + options.TlsPort = 5001; + }); + + services.AddHsts(options => + { + options.MaxAge = TimeSpan.FromDays(30); + options.Preload = true; + options.IncludeSubDomains = true; + }); + } + + public void Configure(IApplicationBuilder app, IHostingEnvironment environment) + { + if (!environment.IsDevelopment()) + { + app.UseHsts(); + } + app.UseHttpsRedirection(); + + app.Run(async context => + { + await context.Response.WriteAsync("Hello world!"); + }); + } + + // Entry point for the application. + public static void Main(string[] args) + { + var host = new WebHostBuilder() + .UseKestrel( + options => + { + options.Listen(new IPEndPoint(IPAddress.Loopback, 5001), listenOptions => + { + listenOptions.UseHttps("testCert.pfx", "testPassword"); + }); + options.Listen(new IPEndPoint(IPAddress.Loopback, 5000), listenOptions => + { + }); + }) + .UseContentRoot(Directory.GetCurrentDirectory()) // for the cert file + .UseStartup() + .Build(); + + host.Run(); + } + } +} diff --git a/samples/HttpsPolicySample/testCert.pfx b/samples/HttpsPolicySample/testCert.pfx new file mode 100644 index 0000000000000000000000000000000000000000..7118908c2d730670c16e9f8b2c532a262c951989 GIT binary patch literal 2483 zcmaKuc|27A8pqF>IWr86E&Q@(n=B)p$ug!;QVB6xij*z;uPLG!yCz#DQB)+9G$9m9 zQU)=DWXU?*EZIwG!+0d++P@yZ4Xhoagg?p6B~|Ue7tN=Ny=UD?x#1n1MTq z#c9MHh+D#gd|(a(cN}8i91v^=GcdgW3SmA$49p~gM-dys3jVWdg8+!iVL)pz1LDE5 zSb=|GAn(@R=(Ux!MfS9@}sFu-xDd zIt2+mqSq$glwy_6UNs<2?(qERU!gJ;5j}Pp&6trxG=wi)=@k(w2+fJVnc+qvXVzy(>Om4;L|^)R`t*3nTpAmEmTl(#i!RV#a0t#u6>Q9mY`-Nmcs7$XjXT7 zUmCD`O~_j7!%R#I?cG-7C^hcH)@l?WC1vyw$FFu_(r)jhOq6p}W8sG7NO{YTy8tG4 zrb$tTkag*G?(7lfoGx$4YWui>{{@}-FB2ub=}RX{1zx?j)s-##J9|G7E1@-;7Nuln z9MQoX7FJ76+D#XXT@ZZmLZCufIdf3@OigG6m8I7!GT=7VD|>?6e!z9=eT}*E_tSn6 zl+clHCZ-kcIR#gen#LjMJW8>0QtViaQB#FhqsCb0YPYr3;jRITl@V9Aph24D?r2d` zetCyyCg<*O-u+M& zW^ptmT|}p$VAOZpmbQ1{5fK-6ytEvre#Po}6c2URn`viQAF2+e?Z~PK2&pd>7=7)I zTCYm)@3PFRu_6a6Kb)IpCzQ%e3l%O#SDA+$Pq{Dk{HCqi7z>qd{nVpebffL7h{c4( zmhXn~G+C27S3(IfC)q2KON=YwqHXEo%zc40DgWLzF{%RIdr@RcLu90qMSHf!Y}JaqP<={8_Rfe;ddR5= zKEo;^Yip&^m((#{czE{kUga3-@`*;&EwO}Jt>QdURP2P>ob^j-A!qld-0S_pm)kjs zkNo48oZnMt){W~o8g^f;4#?lRLr-T@f}wH1o~-Iq=NEVtTVEZ`vrW~!>2yh%;Bc~H zHl&OK>n@d`*e19*9#v>zZpU?I);f7}IPIfSSk#N|ujE492Itg)l!)TJ19@FE^x|p= zH16NC7OfK&|6_!AnWfTIf^YPOa&`|nbk3VR0vql6&s@y1V3QOU%(`Re+kJgrz?r9!{^wOQ4W-eng23gc}f(LxIs zH_Ls~5izbjcRQH#WH6s6hR;zn>j_R8aJ$A)6xNneu8UI-vWV8Z@HZu&WwvG5q{1ZS zdZeVf{Pv5-u281~y;aJe*x%Uv0@biMZ$vPbKj}O`(SOWQc~kJX` zXR&d4DtAe@2RH$^ z0os5*;0eIUeJi3Uh`A%44x(XzjClG8BO~-r_A}odiRuHo2-86#`mhrgN5p~<$RLY? zq(kynfFA5{v#p+EA1 z5aoe1763EQHorRm`C&ktKn(OQ1n)$Q{GZz&jRb`eDEMpl<0O#+)DMV(T7nsIzCG{QuM->B9g7Lrl2SE&gW`M!~(un|y0fIn=b^6_$ z9{zEzgYI~39xn0ZP*9qBL%fg7rg$ttt&TOmvfNNO<6FT0ZavM$Y4CYLQGIcIYv9Y& zBGPUh&QTfW;V2!)oIra@s&d968y-y}Y|ww(R$GzWS*V&)k@W0>Slem{|HdTCjm;_5 zwY*A8W3nUbemE^_f0ng$tbd<`sr?TO-_&VCw+F#7P@LkIl$1PzTBoPY1b88EIO>UO zP-NK7+g2yD3U6g3i|iA6+su>54sf_Sk0F=)1|9odnCM4u2Rs z=&Y?-V&VquSN%3FJ2~ZGweP~iLs|w=l@9yu$tj@}Dp?e-2JUsqOoswdXb=E%&0te_ zA2M+{5Hf-dqD7=yw*r@A*xkn(1IS~nfP}k}e?4Bt|9g(eph4hFX_|S6nj1&Sz9z^= zRw~<&-9d@FzTn6S*RVE{Wj5lgLJr9HLB8S9CgOm*>XA8*y4`JE;^s$=bqD#U4;e5C&x&ggKIAVL zrQ)Yd8|{>7Z(6*B&7&4&9(*vDOfHMuR-Dk1IZia*XM^EZUD^{?cWG>J>KrtElc*{K zaVl(7SN2cH4I6Q$bZOpJ8e5LKaG7p;?tJ~#+9QrTYU@f#5`Vo7cEX!szCT}iX-K^2 w#3o+=C+lQz2J+SOEzVX(eJ)e7=eicC{rr9U2VGDcdH?_b literal 0 HcmV?d00001 diff --git a/src/Microsoft.AspNetCore.HttpsPolicy/HstsBuilderExtensions.cs b/src/Microsoft.AspNetCore.HttpsPolicy/HstsBuilderExtensions.cs new file mode 100644 index 0000000000..840593c5fb --- /dev/null +++ b/src/Microsoft.AspNetCore.HttpsPolicy/HstsBuilderExtensions.cs @@ -0,0 +1,30 @@ +// 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; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.HttpsPolicy; +using Microsoft.Extensions.Options; + +namespace Microsoft.AspNetCore.Builder +{ + /// + /// Extension methods for the HSTS middleware. + /// + public static class HstsBuilderExtensions + { + /// + /// Adds middleware for using HSTS, which adds the Strict-Transport-Security header. + /// + /// The instance this method extends. + public static IApplicationBuilder UseHsts(this IApplicationBuilder app) + { + if (app == null) + { + throw new ArgumentNullException(nameof(app)); + } + + return app.UseMiddleware(); + } + } +} diff --git a/src/Microsoft.AspNetCore.HttpsPolicy/HstsMiddleware.cs b/src/Microsoft.AspNetCore.HttpsPolicy/HstsMiddleware.cs new file mode 100644 index 0000000000..f67543c880 --- /dev/null +++ b/src/Microsoft.AspNetCore.HttpsPolicy/HstsMiddleware.cs @@ -0,0 +1,68 @@ +// 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; +using System.Globalization; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.Options; +using Microsoft.Extensions.Primitives; +using Microsoft.Net.Http.Headers; + +namespace Microsoft.AspNetCore.HttpsPolicy +{ + /// + /// Enables HTTP Strict Transport Security (HSTS) + /// See https://tools.ietf.org/html/rfc6797. + /// + public class HstsMiddleware + { + private const string IncludeSubDomains = "; includeSubDomains"; + private const string Preload = "; preload"; + + private readonly RequestDelegate _next; + private readonly StringValues _strictTransportSecurityValue; + + /// + /// Initialize the HSTS middleware. + /// + /// + /// + public HstsMiddleware(RequestDelegate next, IOptions options) + { + if (next == null) + { + throw new ArgumentNullException(nameof(next)); + } + + if (options == null) + { + throw new ArgumentNullException(nameof(options)); + } + + _next = next; + + var hstsOptions = options.Value; + var maxAge = Convert.ToInt64(Math.Floor(hstsOptions.MaxAge.TotalSeconds)) + .ToString(CultureInfo.InvariantCulture); + var includeSubdomains = hstsOptions.IncludeSubDomains ? IncludeSubDomains : StringSegment.Empty; + var preload = hstsOptions.Preload ? Preload : StringSegment.Empty; + _strictTransportSecurityValue = new StringValues($"max-age={maxAge}{includeSubdomains}{preload}"); + } + + /// + /// Invoke the middleware. + /// + /// The . + /// + public Task Invoke(HttpContext context) + { + if (context.Request.IsHttps) + { + context.Response.Headers[HeaderNames.StrictTransportSecurity] = _strictTransportSecurityValue; + } + + return _next(context); + } + } +} diff --git a/src/Microsoft.AspNetCore.HttpsPolicy/HstsOptions.cs b/src/Microsoft.AspNetCore.HttpsPolicy/HstsOptions.cs new file mode 100644 index 0000000000..77d1d76254 --- /dev/null +++ b/src/Microsoft.AspNetCore.HttpsPolicy/HstsOptions.cs @@ -0,0 +1,39 @@ +// 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; + +namespace Microsoft.AspNetCore.HttpsPolicy +{ + /// + /// Options for the Hsts Middleware + /// + public class HstsOptions + { + /// + /// Sets the max-age parameter of the Strict-Transport-Security header. + /// + /// + /// Max-age is required; defaults to 30 days. + /// See: https://tools.ietf.org/html/rfc6797#section-6.1.1 + /// + public TimeSpan MaxAge { get; set; } = TimeSpan.FromDays(30); + + /// + /// Enables includeSubDomain parameter of the Strict-Transport-Security header. + /// + /// + /// See: https://tools.ietf.org/html/rfc6797#section-6.1.2 + /// + public bool IncludeSubDomains { get; set; } + + /// + /// Sets the preload parameter of the Strict-Transport-Security header. + /// + /// + /// Preload is not part of the RFC specification, but is supported by web browsers + /// to preload HSTS sites on fresh install. See https://hstspreload.org/. + /// + public bool Preload { get; set; } + } +} diff --git a/src/Microsoft.AspNetCore.HttpsPolicy/HstsServicesExtensions.cs b/src/Microsoft.AspNetCore.HttpsPolicy/HstsServicesExtensions.cs new file mode 100644 index 0000000000..425ec9040c --- /dev/null +++ b/src/Microsoft.AspNetCore.HttpsPolicy/HstsServicesExtensions.cs @@ -0,0 +1,36 @@ +// 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; +using Microsoft.AspNetCore.HttpsPolicy; +using Microsoft.Extensions.DependencyInjection; + +namespace Microsoft.AspNetCore.Builder +{ + /// + /// Extension methods for the HSTS middleware. + /// + public static class HstsServicesExtensions + { + /// + /// Adds HSTS services. + /// + /// The for adding services. + /// A delegate to configure the . + /// + public static IServiceCollection AddHsts(this IServiceCollection services, Action configureOptions) + { + if (services == null) + { + throw new ArgumentNullException(nameof(services)); + } + if (configureOptions == null) + { + throw new ArgumentNullException(nameof(configureOptions)); + } + + services.Configure(configureOptions); + return services; + } + } +} diff --git a/src/Microsoft.AspNetCore.HttpsPolicy/HttpsRedirectionBuilderExtensions.cs b/src/Microsoft.AspNetCore.HttpsPolicy/HttpsRedirectionBuilderExtensions.cs new file mode 100644 index 0000000000..89823a0e7c --- /dev/null +++ b/src/Microsoft.AspNetCore.HttpsPolicy/HttpsRedirectionBuilderExtensions.cs @@ -0,0 +1,44 @@ +// 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; +using Microsoft.AspNetCore.HttpsPolicy; +using Microsoft.AspNetCore.Rewrite; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Options; + +namespace Microsoft.AspNetCore.Builder +{ + /// + /// Extension methods for the HttpsRedirection middleware. + /// + public static class HttpsPolicyBuilderExtensions + { + /// + /// Adds middleware for redirecting HTTP Requests to HTTPS. + /// + /// The instance this method extends. + /// The for HttpsRedirection. + /// + /// HTTPS Enforcement interanlly uses the UrlRewrite middleware to redirect HTTP requests to HTTPS. + /// + public static IApplicationBuilder UseHttpsRedirection(this IApplicationBuilder app) + { + if (app == null) + { + throw new ArgumentNullException(nameof(app)); + } + + var options = app.ApplicationServices.GetRequiredService>().Value; + + var rewriteOptions = new RewriteOptions(); + rewriteOptions.AddRedirectToHttps( + options.RedirectStatusCode, + options.TlsPort); + + app.UseRewriter(rewriteOptions); + + return app; + } + } +} diff --git a/src/Microsoft.AspNetCore.HttpsPolicy/HttpsRedirectionOptions.cs b/src/Microsoft.AspNetCore.HttpsPolicy/HttpsRedirectionOptions.cs new file mode 100644 index 0000000000..d73df4d59b --- /dev/null +++ b/src/Microsoft.AspNetCore.HttpsPolicy/HttpsRedirectionOptions.cs @@ -0,0 +1,26 @@ +// 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 Microsoft.AspNetCore.Http; + +namespace Microsoft.AspNetCore.HttpsPolicy +{ + /// + /// Options for the HttpsRedirection middleware + /// + public class HttpsRedirectionOptions + { + /// + /// The status code to redirect the response to. + /// + public int RedirectStatusCode { get; set; } = StatusCodes.Status301MovedPermanently; + + /// + /// The TLS port to be added to the redirected URL. + /// + /// + /// Defaults to 443 if not provided. + /// + public int? TlsPort { get; set; } + } +} diff --git a/src/Microsoft.AspNetCore.HttpsPolicy/HttpsRedirectionServicesExtensions.cs b/src/Microsoft.AspNetCore.HttpsPolicy/HttpsRedirectionServicesExtensions.cs new file mode 100644 index 0000000000..cdc6f005bc --- /dev/null +++ b/src/Microsoft.AspNetCore.HttpsPolicy/HttpsRedirectionServicesExtensions.cs @@ -0,0 +1,36 @@ +// 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; +using Microsoft.AspNetCore.HttpsPolicy; +using Microsoft.Extensions.DependencyInjection; + +namespace Microsoft.AspNetCore.Builder +{ + /// + /// Extension methods for the HttpsRedirection middleware. + /// + public static class HttpsRedirectionServicesExtensions + { + /// + /// Adds HTTPS redirection services. + /// + /// The for adding services. + /// A delegate to configure the . + /// + public static IServiceCollection AddHttpsRedirection(this IServiceCollection services, Action configureOptions) + { + if (services == null) + { + throw new ArgumentNullException(nameof(services)); + } + if (configureOptions == null) + { + throw new ArgumentNullException(nameof(configureOptions)); + } + + services.Configure(configureOptions); + return services; + } + } +} diff --git a/src/Microsoft.AspNetCore.HttpsPolicy/Microsoft.AspNetCore.HttpsPolicy.csproj b/src/Microsoft.AspNetCore.HttpsPolicy/Microsoft.AspNetCore.HttpsPolicy.csproj new file mode 100644 index 0000000000..b68d33b7dc --- /dev/null +++ b/src/Microsoft.AspNetCore.HttpsPolicy/Microsoft.AspNetCore.HttpsPolicy.csproj @@ -0,0 +1,16 @@ + + + + + ASP.NET Core basic middleware for supporting HTTPS Redirection and HTTP Strict-Transport-Security. + + netstandard2.0 + $(NoWarn);CS1591 + true + aspnetcore;https;hsts + + + + + + diff --git a/test/Microsoft.AspNetCore.HttpsEnforcement.Tests/HstsMiddlewareTests.cs b/test/Microsoft.AspNetCore.HttpsEnforcement.Tests/HstsMiddlewareTests.cs new file mode 100644 index 0000000000..e6d325769f --- /dev/null +++ b/test/Microsoft.AspNetCore.HttpsEnforcement.Tests/HstsMiddlewareTests.cs @@ -0,0 +1,128 @@ +// 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; +using System.Linq; +using System.Net; +using System.Net.Http; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.TestHost; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Net.Http.Headers; +using Xunit; + +namespace Microsoft.AspNetCore.HttpsPolicy.Tests +{ + public class HstsMiddlewareTests + { + [Fact] + public async Task SetOptionsWithDefault_SetsMaxAgeToCorrectValue() + { + var builder = new WebHostBuilder() + .UseUrls("https://*:5050") + .ConfigureServices(services => + { + }) + .Configure(app => + { + app.UseHsts(); + app.Run(context => + { + return context.Response.WriteAsync("Hello world"); + }); + }); + + var server = new TestServer(builder); + var client = server.CreateClient(); + client.BaseAddress = new Uri("https://localhost:5050"); + + var request = new HttpRequestMessage(HttpMethod.Get, ""); + + var response = await client.SendAsync(request); + + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + Assert.Equal("max-age=2592000", response.Headers.GetValues(HeaderNames.StrictTransportSecurity).FirstOrDefault()); + } + + [Theory] + [InlineData(0, false, false, "max-age=0")] + [InlineData(-1, false, false, "max-age=-1")] + [InlineData(0, true, false, "max-age=0; includeSubDomains")] + [InlineData(50000, false, true, "max-age=50000; preload")] + [InlineData(0, true, true, "max-age=0; includeSubDomains; preload")] + [InlineData(50000, true, true, "max-age=50000; includeSubDomains; preload")] + public async Task SetOptionsThroughConfigure_SetsHeaderCorrectly(int maxAge, bool includeSubDomains, bool preload, string expected) + { + var builder = new WebHostBuilder() + .UseUrls("https://*:5050") + .ConfigureServices(services => + { + services.Configure(options => { + options.Preload = preload; + options.IncludeSubDomains = includeSubDomains; + options.MaxAge = TimeSpan.FromSeconds(maxAge); + }); + }) + .Configure(app => + { + app.UseHsts(); + app.Run(context => + { + return context.Response.WriteAsync("Hello world"); + }); + }); + + var server = new TestServer(builder); + var client = server.CreateClient(); + client.BaseAddress = new Uri("https://localhost:5050"); + var request = new HttpRequestMessage(HttpMethod.Get, ""); + + var response = await client.SendAsync(request); + + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + Assert.Equal(expected, response.Headers.GetValues(HeaderNames.StrictTransportSecurity).FirstOrDefault()); + } + + [Theory] + [InlineData(0, false, false, "max-age=0")] + [InlineData(-1, false, false, "max-age=-1")] + [InlineData(0, true, false, "max-age=0; includeSubDomains")] + [InlineData(50000, false, true, "max-age=50000; preload")] + [InlineData(0, true, true, "max-age=0; includeSubDomains; preload")] + [InlineData(50000, true, true, "max-age=50000; includeSubDomains; preload")] + public async Task SetOptionsThroughHelper_SetsHeaderCorrectly(int maxAge, bool includeSubDomains, bool preload, string expected) + { + var builder = new WebHostBuilder() + .UseUrls("https://*:5050") + .ConfigureServices(services => + { + services.AddHsts(options => { + options.Preload = preload; + options.IncludeSubDomains = includeSubDomains; + options.MaxAge = TimeSpan.FromSeconds(maxAge); + }); + }) + .Configure(app => + { + app.UseHsts(); + app.Run(context => + { + return context.Response.WriteAsync("Hello world"); + }); + }); + + var server = new TestServer(builder); + var client = server.CreateClient(); + client.BaseAddress = new Uri("https://localhost:5050"); + var request = new HttpRequestMessage(HttpMethod.Get, ""); + + var response = await client.SendAsync(request); + + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + Assert.Equal(expected, response.Headers.GetValues(HeaderNames.StrictTransportSecurity).FirstOrDefault()); + } + } +} diff --git a/test/Microsoft.AspNetCore.HttpsEnforcement.Tests/HttpsPolicyTests.cs b/test/Microsoft.AspNetCore.HttpsEnforcement.Tests/HttpsPolicyTests.cs new file mode 100644 index 0000000000..58a0be138c --- /dev/null +++ b/test/Microsoft.AspNetCore.HttpsEnforcement.Tests/HttpsPolicyTests.cs @@ -0,0 +1,76 @@ +// 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; +using System.Linq; +using System.Net; +using System.Net.Http; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.TestHost; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Net.Http.Headers; +using Xunit; + +namespace Microsoft.AspNetCore.HttpsPolicy.Tests +{ + public class HttpsPolicyTests + { + [Theory] + [InlineData(302, null, 2592000, false, false, "max-age=2592000", "https://localhost/")] + [InlineData(301, 5050, 2592000, false, false, "max-age=2592000", "https://localhost:5050/")] + [InlineData(301, 443, 2592000, false, false, "max-age=2592000", "https://localhost/")] + [InlineData(301, 443, 2592000, true, false, "max-age=2592000; includeSubDomains", "https://localhost/")] + [InlineData(301, 443, 2592000, false, true, "max-age=2592000; preload", "https://localhost/")] + [InlineData(301, null, 2592000, true, true, "max-age=2592000; includeSubDomains; preload", "https://localhost/")] + [InlineData(302, 5050, 2592000, true, true, "max-age=2592000; includeSubDomains; preload", "https://localhost:5050/")] + public async Task SetsBothHstsAndHttpsRedirection_RedirectOnFirstRequest_HstsOnSecondRequest(int statusCode, int? tlsPort, int maxAge, bool includeSubDomains, bool preload, string expectedHstsHeader, string expectedUrl) + { + + var builder = new WebHostBuilder() + .UseUrls("https://*:5050", "http://*:5050") + .ConfigureServices(services => + { + services.Configure(options => + { + options.RedirectStatusCode = statusCode; + options.TlsPort = tlsPort; + }); + services.Configure(options => + { + options.IncludeSubDomains = includeSubDomains; + options.MaxAge = TimeSpan.FromSeconds(maxAge); + options.Preload = preload; + }); + }) + .Configure(app => + { + app.UseHttpsRedirection(); + app.UseHsts(); + app.Run(context => + { + return context.Response.WriteAsync("Hello world"); + }); + }); + + var server = new TestServer(builder); + var client = server.CreateClient(); + + var request = new HttpRequestMessage(HttpMethod.Get, ""); + + var response = await client.SendAsync(request); + + Assert.Equal(statusCode, (int)response.StatusCode); + Assert.Equal(expectedUrl, response.Headers.Location.ToString()); + + client = server.CreateClient(); + client.BaseAddress = new Uri(response.Headers.Location.ToString()); + request = new HttpRequestMessage(HttpMethod.Get, ""); + response = await client.SendAsync(request); + + Assert.Equal(expectedHstsHeader, response.Headers.GetValues(HeaderNames.StrictTransportSecurity).FirstOrDefault()); + } + } +} diff --git a/test/Microsoft.AspNetCore.HttpsEnforcement.Tests/HttpsRedirectionMiddlewareTests.cs b/test/Microsoft.AspNetCore.HttpsEnforcement.Tests/HttpsRedirectionMiddlewareTests.cs new file mode 100644 index 0000000000..1e77683bf7 --- /dev/null +++ b/test/Microsoft.AspNetCore.HttpsEnforcement.Tests/HttpsRedirectionMiddlewareTests.cs @@ -0,0 +1,125 @@ +// 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; +using System.Linq; +using System.Net; +using System.Net.Http; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.TestHost; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Net.Http.Headers; +using Xunit; + +namespace Microsoft.AspNetCore.HttpsPolicy.Tests +{ + public class HttpsRedirectionMiddlewareTests + { + [Fact] + public async Task SetOptions_DefaultsSetCorrectly() + { + var builder = new WebHostBuilder() + .ConfigureServices(services => + { + }) + .Configure(app => + { + app.UseHttpsRedirection(); + app.Run(context => + { + return context.Response.WriteAsync("Hello world"); + }); + }); + + var server = new TestServer(builder); + var client = server.CreateClient(); + + var request = new HttpRequestMessage(HttpMethod.Get, ""); + + var response = await client.SendAsync(request); + + Assert.Equal(HttpStatusCode.MovedPermanently, response.StatusCode); + Assert.Equal("https://localhost/", response.Headers.Location.ToString()); + } + + [Theory] + [InlineData(301, null, "https://localhost/")] + [InlineData(302, null, "https://localhost/")] + [InlineData(307, null, "https://localhost/")] + [InlineData(308, null, "https://localhost/")] + [InlineData(301, 5050, "https://localhost:5050/")] + [InlineData(301, 443, "https://localhost/")] + public async Task SetOptions_SetStatusCodeTlsPort(int statusCode, int? tlsPort, string expected) + { + + var builder = new WebHostBuilder() + .ConfigureServices(services => + { + services.Configure(options => + { + options.RedirectStatusCode = statusCode; + options.TlsPort = tlsPort; + }); + }) + .Configure(app => + { + app.UseHttpsRedirection(); + app.Run(context => + { + return context.Response.WriteAsync("Hello world"); + }); + }); + + var server = new TestServer(builder); + var client = server.CreateClient(); + + var request = new HttpRequestMessage(HttpMethod.Get, ""); + + var response = await client.SendAsync(request); + + Assert.Equal(statusCode, (int)response.StatusCode); + Assert.Equal(expected, response.Headers.Location.ToString()); + } + + [Theory] + [InlineData(301, null, "https://localhost/")] + [InlineData(302, null, "https://localhost/")] + [InlineData(307, null, "https://localhost/")] + [InlineData(308, null, "https://localhost/")] + [InlineData(301, 5050, "https://localhost:5050/")] + [InlineData(301, 443, "https://localhost/")] + public async Task SetOptionsThroughHelperMethod_SetStatusCodeTlsPort(int statusCode, int? tlsPort, string expectedUrl) + { + var builder = new WebHostBuilder() + .ConfigureServices(services => + { + services.AddHttpsRedirection(options => + { + options.RedirectStatusCode = statusCode; + options.TlsPort = tlsPort; + }); + }) + .Configure(app => + { + app.UseHttpsRedirection(); + app.Run(context => + { + return context.Response.WriteAsync("Hello world"); + }); + }); + + var server = new TestServer(builder); + var client = server.CreateClient(); + + var request = new HttpRequestMessage(HttpMethod.Get, ""); + + var response = await client.SendAsync(request); + + Assert.Equal(statusCode, (int)response.StatusCode); + Assert.Equal(expectedUrl, response.Headers.Location.ToString()); + } + } +} diff --git a/test/Microsoft.AspNetCore.HttpsEnforcement.Tests/Microsoft.AspNetCore.HttpsPolicy.Tests.csproj b/test/Microsoft.AspNetCore.HttpsEnforcement.Tests/Microsoft.AspNetCore.HttpsPolicy.Tests.csproj new file mode 100644 index 0000000000..acdd245d85 --- /dev/null +++ b/test/Microsoft.AspNetCore.HttpsEnforcement.Tests/Microsoft.AspNetCore.HttpsPolicy.Tests.csproj @@ -0,0 +1,10 @@ + + + + netcoreapp2.0 + + + + + + From 8119c974ad20df89173bd4c169238600831fddde Mon Sep 17 00:00:00 2001 From: Ryan Brandenburg Date: Mon, 16 Oct 2017 12:47:33 -0700 Subject: [PATCH 236/307] Add RepositoryRoot --- Directory.Build.props | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Directory.Build.props b/Directory.Build.props index 5dc2aa7c7b..9eb2018330 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -1,10 +1,11 @@ - + Microsoft ASP.NET Core https://github.com/aspnet/BasicMiddleware git + $(MSBuildThisFileDirectory) $(MSBuildThisFileDirectory)build\Key.snk true true From ff5aed132bd04e85a17ba3273490fc873fb4e4e3 Mon Sep 17 00:00:00 2001 From: Justin Kotalik Date: Mon, 30 Oct 2017 18:20:06 -0700 Subject: [PATCH 237/307] Use ASPNETCORE_HTTPS_PORT to get port from config (#266) --- samples/HttpsPolicySample/Startup.cs | 2 +- .../HttpsRedirectionBuilderExtensions.cs | 18 +++++++- .../HttpsRedirectionOptions.cs | 2 +- .../HttpsRedirectionServicesExtensions.cs | 1 - .../HttpsPolicyTests.cs | 2 +- .../HttpsRedirectionMiddlewareTests.cs | 44 +++++++++++++++++-- 6 files changed, 60 insertions(+), 9 deletions(-) diff --git a/samples/HttpsPolicySample/Startup.cs b/samples/HttpsPolicySample/Startup.cs index 4fb7e62871..1c9f11fcad 100644 --- a/samples/HttpsPolicySample/Startup.cs +++ b/samples/HttpsPolicySample/Startup.cs @@ -21,7 +21,7 @@ namespace HttpsSample services.AddHttpsRedirection(options => { options.RedirectStatusCode = StatusCodes.Status301MovedPermanently; - options.TlsPort = 5001; + options.HttpsPort = 5001; }); services.AddHsts(options => diff --git a/src/Microsoft.AspNetCore.HttpsPolicy/HttpsRedirectionBuilderExtensions.cs b/src/Microsoft.AspNetCore.HttpsPolicy/HttpsRedirectionBuilderExtensions.cs index 89823a0e7c..d6b827caab 100644 --- a/src/Microsoft.AspNetCore.HttpsPolicy/HttpsRedirectionBuilderExtensions.cs +++ b/src/Microsoft.AspNetCore.HttpsPolicy/HttpsRedirectionBuilderExtensions.cs @@ -4,6 +4,7 @@ using System; using Microsoft.AspNetCore.HttpsPolicy; using Microsoft.AspNetCore.Rewrite; +using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Options; @@ -31,10 +32,25 @@ namespace Microsoft.AspNetCore.Builder var options = app.ApplicationServices.GetRequiredService>().Value; + // The tls port set in options will have priority over the one in configuration. + var httpsPort = options.HttpsPort; + if (httpsPort == null) + { + // Only read configuration if there is no httpsPort + var config = app.ApplicationServices.GetRequiredService(); + var configHttpsPort = config["HTTPS_PORT"]; + // If the string isn't empty, try to parse it. + if (!string.IsNullOrEmpty(configHttpsPort) + && int.TryParse(configHttpsPort, out var intHttpsPort)) + { + httpsPort = intHttpsPort; + } + } + var rewriteOptions = new RewriteOptions(); rewriteOptions.AddRedirectToHttps( options.RedirectStatusCode, - options.TlsPort); + httpsPort); app.UseRewriter(rewriteOptions); diff --git a/src/Microsoft.AspNetCore.HttpsPolicy/HttpsRedirectionOptions.cs b/src/Microsoft.AspNetCore.HttpsPolicy/HttpsRedirectionOptions.cs index d73df4d59b..38f7026e25 100644 --- a/src/Microsoft.AspNetCore.HttpsPolicy/HttpsRedirectionOptions.cs +++ b/src/Microsoft.AspNetCore.HttpsPolicy/HttpsRedirectionOptions.cs @@ -21,6 +21,6 @@ namespace Microsoft.AspNetCore.HttpsPolicy /// /// Defaults to 443 if not provided. /// - public int? TlsPort { get; set; } + public int? HttpsPort { get; set; } } } diff --git a/src/Microsoft.AspNetCore.HttpsPolicy/HttpsRedirectionServicesExtensions.cs b/src/Microsoft.AspNetCore.HttpsPolicy/HttpsRedirectionServicesExtensions.cs index cdc6f005bc..24c9e114e8 100644 --- a/src/Microsoft.AspNetCore.HttpsPolicy/HttpsRedirectionServicesExtensions.cs +++ b/src/Microsoft.AspNetCore.HttpsPolicy/HttpsRedirectionServicesExtensions.cs @@ -28,7 +28,6 @@ namespace Microsoft.AspNetCore.Builder { throw new ArgumentNullException(nameof(configureOptions)); } - services.Configure(configureOptions); return services; } diff --git a/test/Microsoft.AspNetCore.HttpsEnforcement.Tests/HttpsPolicyTests.cs b/test/Microsoft.AspNetCore.HttpsEnforcement.Tests/HttpsPolicyTests.cs index 58a0be138c..57e3546153 100644 --- a/test/Microsoft.AspNetCore.HttpsEnforcement.Tests/HttpsPolicyTests.cs +++ b/test/Microsoft.AspNetCore.HttpsEnforcement.Tests/HttpsPolicyTests.cs @@ -36,7 +36,7 @@ namespace Microsoft.AspNetCore.HttpsPolicy.Tests services.Configure(options => { options.RedirectStatusCode = statusCode; - options.TlsPort = tlsPort; + options.HttpsPort = tlsPort; }); services.Configure(options => { diff --git a/test/Microsoft.AspNetCore.HttpsEnforcement.Tests/HttpsRedirectionMiddlewareTests.cs b/test/Microsoft.AspNetCore.HttpsEnforcement.Tests/HttpsRedirectionMiddlewareTests.cs index 1e77683bf7..e9312decba 100644 --- a/test/Microsoft.AspNetCore.HttpsEnforcement.Tests/HttpsRedirectionMiddlewareTests.cs +++ b/test/Microsoft.AspNetCore.HttpsEnforcement.Tests/HttpsRedirectionMiddlewareTests.cs @@ -52,7 +52,7 @@ namespace Microsoft.AspNetCore.HttpsPolicy.Tests [InlineData(308, null, "https://localhost/")] [InlineData(301, 5050, "https://localhost:5050/")] [InlineData(301, 443, "https://localhost/")] - public async Task SetOptions_SetStatusCodeTlsPort(int statusCode, int? tlsPort, string expected) + public async Task SetOptions_SetStatusCodeHttpsPort(int statusCode, int? httpsPort, string expected) { var builder = new WebHostBuilder() @@ -61,7 +61,7 @@ namespace Microsoft.AspNetCore.HttpsPolicy.Tests services.Configure(options => { options.RedirectStatusCode = statusCode; - options.TlsPort = tlsPort; + options.HttpsPort = httpsPort; }); }) .Configure(app => @@ -91,7 +91,7 @@ namespace Microsoft.AspNetCore.HttpsPolicy.Tests [InlineData(308, null, "https://localhost/")] [InlineData(301, 5050, "https://localhost:5050/")] [InlineData(301, 443, "https://localhost/")] - public async Task SetOptionsThroughHelperMethod_SetStatusCodeTlsPort(int statusCode, int? tlsPort, string expectedUrl) + public async Task SetOptionsThroughHelperMethod_SetStatusCodeAndHttpsPort(int statusCode, int? httpsPort, string expectedUrl) { var builder = new WebHostBuilder() .ConfigureServices(services => @@ -99,7 +99,7 @@ namespace Microsoft.AspNetCore.HttpsPolicy.Tests services.AddHttpsRedirection(options => { options.RedirectStatusCode = statusCode; - options.TlsPort = tlsPort; + options.HttpsPort = httpsPort; }); }) .Configure(app => @@ -121,5 +121,41 @@ namespace Microsoft.AspNetCore.HttpsPolicy.Tests Assert.Equal(statusCode, (int)response.StatusCode); Assert.Equal(expectedUrl, response.Headers.Location.ToString()); } + + [Theory] + [InlineData(null, null, "https://localhost/")] + [InlineData(null, "5000", "https://localhost:5000/")] + [InlineData(null, "443", "https://localhost/")] + [InlineData(443, "5000", "https://localhost/")] + [InlineData(4000, "5000", "https://localhost:4000/")] + [InlineData(5000, null, "https://localhost:5000/")] + public async Task SetHttpsPortEnvironmentVariable_ReturnsCorrectStatusCodeOnResponse(int? optionsHttpsPort, string configHttpsPort, string expectedUrl) + { + var builder = new WebHostBuilder() + .ConfigureServices(services => + { + services.AddHttpsRedirection(options => + { + options.HttpsPort = optionsHttpsPort; + }); + }) + .Configure(app => + { + app.UseHttpsRedirection(); + app.Run(context => + { + return context.Response.WriteAsync("Hello world"); + }); + }); + builder.UseSetting("HTTPS_PORT", configHttpsPort); + var server = new TestServer(builder); + var client = server.CreateClient(); + + var request = new HttpRequestMessage(HttpMethod.Get, ""); + + var response = await client.SendAsync(request); + + Assert.Equal(expectedUrl, response.Headers.Location.ToString()); + } } } From 76af959e99a1e509bd596393a592f177a0b74740 Mon Sep 17 00:00:00 2001 From: Nate McMaster Date: Tue, 31 Oct 2017 17:40:53 -0700 Subject: [PATCH 238/307] Pin tool and package versions to make builds more repeatable --- .gitignore | 1 - Directory.Build.props | 6 ++-- Directory.Build.targets | 17 +++-------- NuGet.config | 1 + build/dependencies.props | 29 +++++++++++++++++++ build/repo.props | 11 +++---- korebuild-lock.txt | 2 ++ korebuild.json | 4 +++ .../HttpOverridesSample.csproj | 2 +- .../HttpsPolicySample.csproj | 4 +-- .../ResponseBufferingSample.csproj | 2 +- .../ResponseCompressionSample.csproj | 4 +-- samples/RewriteSample/RewriteSample.csproj | 4 +-- src/Directory.Build.props | 4 +-- .../Microsoft.AspNetCore.Buffering.csproj | 5 ++-- .../Microsoft.AspNetCore.HttpOverrides.csproj | 6 ++-- ...soft.AspNetCore.ResponseCompression.csproj | 4 +-- .../Microsoft.AspNetCore.Rewrite.csproj | 12 ++++---- test/Directory.Build.props | 14 ++++----- ...soft.AspNetCore.HttpOverrides.Tests.csproj | 2 +- ...spNetCore.ResponseCompression.Tests.csproj | 6 ++-- version.props | 11 +++++++ version.xml | 8 ----- 23 files changed, 95 insertions(+), 64 deletions(-) create mode 100644 build/dependencies.props create mode 100644 korebuild-lock.txt create mode 100644 korebuild.json create mode 100644 version.props delete mode 100644 version.xml diff --git a/.gitignore b/.gitignore index 2f73223257..c8dd6c52d5 100644 --- a/.gitignore +++ b/.gitignore @@ -33,4 +33,3 @@ project.lock.json *.nuget.props *.nuget.targets global.json -korebuild-lock.txt diff --git a/Directory.Build.props b/Directory.Build.props index 9eb2018330..fb21f30265 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -1,5 +1,6 @@ - - + + + Microsoft ASP.NET Core @@ -9,7 +10,6 @@ $(MSBuildThisFileDirectory)build\Key.snk true true - $(VersionSuffix)-$(BuildNumber) true diff --git a/Directory.Build.targets b/Directory.Build.targets index bc118fd907..e83ff95e39 100644 --- a/Directory.Build.targets +++ b/Directory.Build.targets @@ -1,14 +1,5 @@ - - - - <_BootstrapperFile Condition=" $([MSBuild]::IsOSUnixLike()) ">build.sh - <_BootstrapperFile Condition="! $([MSBuild]::IsOSUnixLike()) ">build.cmd - <_BootstrapperError> - Package references have not been pinned. Run './$(_BootstrapperFile) /t:Pin'. - Also, you can run './$(_BootstrapperFile) /t:Restore' which will pin *and* restore packages. '$(_BootstrapperFile)' can be found in '$(MSBuildThisFileDirectory)'. - - - - - + + + $(MicrosoftNETCoreApp20PackageVersion) + diff --git a/NuGet.config b/NuGet.config index 20060c934e..4e8a1f6de1 100644 --- a/NuGet.config +++ b/NuGet.config @@ -3,6 +3,7 @@ + diff --git a/build/dependencies.props b/build/dependencies.props new file mode 100644 index 0000000000..70ea21dfa6 --- /dev/null +++ b/build/dependencies.props @@ -0,0 +1,29 @@ + + + $(MSBuildAllProjects);$(MSBuildThisFileFullPath) + + + 2.1.0-preview1-15549 + 2.1.0-preview1-27480 + 2.1.0-preview1-27480 + 2.1.0-preview1-27480 + 2.1.0-preview1-27480 + 2.1.0-preview1-27480 + 2.1.0-preview1-27480 + 2.1.0-preview1-27480 + 2.1.0-preview1-27480 + 2.1.0-preview1-27480 + 2.1.0-preview1-27480 + 2.1.0-preview1-27480 + 2.1.0-preview1-27480 + 2.1.0-preview1-27480 + 2.0.0 + 2.1.0-preview1-27480 + 15.3.0 + 4.7.49 + 0.7.0 + 2.3.0 + 2.3.0 + + + diff --git a/build/repo.props b/build/repo.props index 13fe1c296a..20e96b5d3c 100644 --- a/build/repo.props +++ b/build/repo.props @@ -1,6 +1,7 @@ - - - - - + + + + Internal.AspNetCore.Universe.Lineup + https://dotnet.myget.org/F/aspnetcore-ci-dev/api/v3/index.json + diff --git a/korebuild-lock.txt b/korebuild-lock.txt new file mode 100644 index 0000000000..45463cc71e --- /dev/null +++ b/korebuild-lock.txt @@ -0,0 +1,2 @@ +version:2.1.0-preview1-15549 +commithash:f570e08585fec510dd60cd4bfe8795388b757a95 diff --git a/korebuild.json b/korebuild.json new file mode 100644 index 0000000000..bd5d51a51b --- /dev/null +++ b/korebuild.json @@ -0,0 +1,4 @@ +{ + "$schema": "https://raw.githubusercontent.com/aspnet/BuildTools/dev/tools/korebuild.schema.json", + "channel": "dev" +} diff --git a/samples/HttpOverridesSample/HttpOverridesSample.csproj b/samples/HttpOverridesSample/HttpOverridesSample.csproj index 51d4942a9c..b4962cd5be 100644 --- a/samples/HttpOverridesSample/HttpOverridesSample.csproj +++ b/samples/HttpOverridesSample/HttpOverridesSample.csproj @@ -10,7 +10,7 @@ - + diff --git a/samples/HttpsPolicySample/HttpsPolicySample.csproj b/samples/HttpsPolicySample/HttpsPolicySample.csproj index a9d5f11b71..3ab7f8c7cb 100644 --- a/samples/HttpsPolicySample/HttpsPolicySample.csproj +++ b/samples/HttpsPolicySample/HttpsPolicySample.csproj @@ -6,8 +6,8 @@ - - + + diff --git a/samples/ResponseBufferingSample/ResponseBufferingSample.csproj b/samples/ResponseBufferingSample/ResponseBufferingSample.csproj index fd2c6deb51..f2c65f721f 100644 --- a/samples/ResponseBufferingSample/ResponseBufferingSample.csproj +++ b/samples/ResponseBufferingSample/ResponseBufferingSample.csproj @@ -10,7 +10,7 @@ - + diff --git a/samples/ResponseCompressionSample/ResponseCompressionSample.csproj b/samples/ResponseCompressionSample/ResponseCompressionSample.csproj index d194cac2b7..ed417e69a2 100644 --- a/samples/ResponseCompressionSample/ResponseCompressionSample.csproj +++ b/samples/ResponseCompressionSample/ResponseCompressionSample.csproj @@ -14,8 +14,8 @@ - - + + diff --git a/samples/RewriteSample/RewriteSample.csproj b/samples/RewriteSample/RewriteSample.csproj index 824c440f23..cc73c47aff 100644 --- a/samples/RewriteSample/RewriteSample.csproj +++ b/samples/RewriteSample/RewriteSample.csproj @@ -10,8 +10,8 @@ - - + + diff --git a/src/Directory.Build.props b/src/Directory.Build.props index 9d9a3de33a..4b89a431e7 100644 --- a/src/Directory.Build.props +++ b/src/Directory.Build.props @@ -1,7 +1,7 @@ - + - + diff --git a/src/Microsoft.AspNetCore.Buffering/Microsoft.AspNetCore.Buffering.csproj b/src/Microsoft.AspNetCore.Buffering/Microsoft.AspNetCore.Buffering.csproj index 1ee8961e76..8b4cd9cefc 100644 --- a/src/Microsoft.AspNetCore.Buffering/Microsoft.AspNetCore.Buffering.csproj +++ b/src/Microsoft.AspNetCore.Buffering/Microsoft.AspNetCore.Buffering.csproj @@ -1,7 +1,8 @@  - 0.4.0 + $(ExperimentalProjectVersionPrefix) + false ASP.NET Core middleware for buffering response bodies. netstandard2.0 $(NoWarn);CS1591 @@ -10,7 +11,7 @@ - + diff --git a/src/Microsoft.AspNetCore.HttpOverrides/Microsoft.AspNetCore.HttpOverrides.csproj b/src/Microsoft.AspNetCore.HttpOverrides/Microsoft.AspNetCore.HttpOverrides.csproj index 74998e7f89..c922f7f94f 100644 --- a/src/Microsoft.AspNetCore.HttpOverrides/Microsoft.AspNetCore.HttpOverrides.csproj +++ b/src/Microsoft.AspNetCore.HttpOverrides/Microsoft.AspNetCore.HttpOverrides.csproj @@ -11,9 +11,9 @@ - - - + + + diff --git a/src/Microsoft.AspNetCore.ResponseCompression/Microsoft.AspNetCore.ResponseCompression.csproj b/src/Microsoft.AspNetCore.ResponseCompression/Microsoft.AspNetCore.ResponseCompression.csproj index a9f7efac7f..e652961322 100644 --- a/src/Microsoft.AspNetCore.ResponseCompression/Microsoft.AspNetCore.ResponseCompression.csproj +++ b/src/Microsoft.AspNetCore.ResponseCompression/Microsoft.AspNetCore.ResponseCompression.csproj @@ -8,8 +8,8 @@ - - + + diff --git a/src/Microsoft.AspNetCore.Rewrite/Microsoft.AspNetCore.Rewrite.csproj b/src/Microsoft.AspNetCore.Rewrite/Microsoft.AspNetCore.Rewrite.csproj index b23ccdf3cc..03c3e53b64 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Microsoft.AspNetCore.Rewrite.csproj +++ b/src/Microsoft.AspNetCore.Rewrite/Microsoft.AspNetCore.Rewrite.csproj @@ -12,12 +12,12 @@ - - - - - - + + + + + + diff --git a/test/Directory.Build.props b/test/Directory.Build.props index 546a887055..33f658f32d 100644 --- a/test/Directory.Build.props +++ b/test/Directory.Build.props @@ -1,12 +1,12 @@ - + - - - - - - + + + + + + diff --git a/test/Microsoft.AspNetCore.HttpOverrides.Tests/Microsoft.AspNetCore.HttpOverrides.Tests.csproj b/test/Microsoft.AspNetCore.HttpOverrides.Tests/Microsoft.AspNetCore.HttpOverrides.Tests.csproj index c84cc3b395..c78b062129 100644 --- a/test/Microsoft.AspNetCore.HttpOverrides.Tests/Microsoft.AspNetCore.HttpOverrides.Tests.csproj +++ b/test/Microsoft.AspNetCore.HttpOverrides.Tests/Microsoft.AspNetCore.HttpOverrides.Tests.csproj @@ -10,7 +10,7 @@ - + diff --git a/test/Microsoft.AspNetCore.ResponseCompression.Tests/Microsoft.AspNetCore.ResponseCompression.Tests.csproj b/test/Microsoft.AspNetCore.ResponseCompression.Tests/Microsoft.AspNetCore.ResponseCompression.Tests.csproj index 59949c5036..1d29ce2135 100644 --- a/test/Microsoft.AspNetCore.ResponseCompression.Tests/Microsoft.AspNetCore.ResponseCompression.Tests.csproj +++ b/test/Microsoft.AspNetCore.ResponseCompression.Tests/Microsoft.AspNetCore.ResponseCompression.Tests.csproj @@ -14,9 +14,9 @@ - - - + + + diff --git a/version.props b/version.props new file mode 100644 index 0000000000..d1791a6a89 --- /dev/null +++ b/version.props @@ -0,0 +1,11 @@ + + + 2.1.0 + 0.4.0 + preview1 + $(VersionPrefix) + $(VersionPrefix)-$(VersionSuffix)-final + t000 + $(VersionSuffix)-$(BuildNumber) + + diff --git a/version.xml b/version.xml deleted file mode 100644 index 3c05022b7d..0000000000 --- a/version.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - dev - 2.1.0 - preview1 - - From 9f3ed006a12fdaddf2f5134cdc647433a0548946 Mon Sep 17 00:00:00 2001 From: "Chris Ross (ASP.NET)" Date: Sat, 28 Oct 2017 08:55:44 -0700 Subject: [PATCH 239/307] Consume new HttpContext test pattern --- .../ForwardedHeadersMiddlewareTest.cs | 370 +++++++----------- .../HstsMiddlewareTests.cs | 3 - .../HttpsPolicyTests.cs | 1 - 3 files changed, 132 insertions(+), 242 deletions(-) diff --git a/test/Microsoft.AspNetCore.HttpOverrides.Tests/ForwardedHeadersMiddlewareTest.cs b/test/Microsoft.AspNetCore.HttpOverrides.Tests/ForwardedHeadersMiddlewareTest.cs index 216cc608a1..ea905dace0 100644 --- a/test/Microsoft.AspNetCore.HttpOverrides.Tests/ForwardedHeadersMiddlewareTest.cs +++ b/test/Microsoft.AspNetCore.HttpOverrides.Tests/ForwardedHeadersMiddlewareTest.cs @@ -3,7 +3,6 @@ using System.Linq; using System.Net; -using System.Net.Http; using System.Threading.Tasks; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; @@ -17,8 +16,6 @@ namespace Microsoft.AspNetCore.HttpOverrides [Fact] public async Task XForwardedForDefaultSettingsChangeRemoteIpAndPort() { - var assertsExecuted = false; - var builder = new WebHostBuilder() .Configure(app => { @@ -26,63 +23,49 @@ namespace Microsoft.AspNetCore.HttpOverrides { ForwardedHeaders = ForwardedHeaders.XForwardedFor }); - app.Run(context => - { - Assert.Equal("11.111.111.11", context.Connection.RemoteIpAddress.ToString()); - Assert.Equal(9090, context.Connection.RemotePort); - // No Original set if RemoteIpAddress started null. - Assert.False(context.Request.Headers.ContainsKey("X-Original-For")); - // Should have been consumed and removed - Assert.False(context.Request.Headers.ContainsKey("X-Forwarded-For")); - assertsExecuted = true; - return Task.FromResult(0); - }); }); var server = new TestServer(builder); - var req = new HttpRequestMessage(HttpMethod.Get, ""); - req.Headers.Add("X-Forwarded-For", "11.111.111.11:9090"); - await server.CreateClient().SendAsync(req); - Assert.True(assertsExecuted); + var context = await server.SendAsync(c => + { + c.Request.Headers["X-Forwarded-For"] = "11.111.111.11:9090"; + }); + + Assert.Equal("11.111.111.11", context.Connection.RemoteIpAddress.ToString()); + Assert.Equal(9090, context.Connection.RemotePort); + // No Original set if RemoteIpAddress started null. + Assert.False(context.Request.Headers.ContainsKey("X-Original-For")); + // Should have been consumed and removed + Assert.False(context.Request.Headers.ContainsKey("X-Forwarded-For")); } [Theory] [InlineData(1, "11.111.111.11.12345", "10.0.0.1", 99)] // Invalid public async Task XForwardedForFirstValueIsInvalid(int limit, string header, string expectedIp, int expectedPort) { - var assertsExecuted = false; - var builder = new WebHostBuilder() .Configure(app => { - app.Use((context, next) => - { - context.Connection.RemoteIpAddress = IPAddress.Parse("10.0.0.1"); - context.Connection.RemotePort = 99; - return next(); - }); app.UseForwardedHeaders(new ForwardedHeadersOptions { ForwardedHeaders = ForwardedHeaders.XForwardedFor, ForwardLimit = limit, }); - app.Run(context => - { - Assert.Equal(expectedIp, context.Connection.RemoteIpAddress.ToString()); - Assert.Equal(expectedPort, context.Connection.RemotePort); - Assert.False(context.Request.Headers.ContainsKey("X-Original-For")); - Assert.True(context.Request.Headers.ContainsKey("X-Forwarded-For")); - Assert.Equal(header, context.Request.Headers["X-Forwarded-For"]); - assertsExecuted = true; - return Task.FromResult(0); - }); }); var server = new TestServer(builder); - var req = new HttpRequestMessage(HttpMethod.Get, ""); - req.Headers.TryAddWithoutValidation("X-Forwarded-For", header); - await server.CreateClient().SendAsync(req); - Assert.True(assertsExecuted); + var context = await server.SendAsync(c => + { + c.Request.Headers["X-Forwarded-For"] = header; + c.Connection.RemoteIpAddress = IPAddress.Parse("10.0.0.1"); + c.Connection.RemotePort = 99; + }); + + Assert.Equal(expectedIp, context.Connection.RemoteIpAddress.ToString()); + Assert.Equal(expectedPort, context.Connection.RemotePort); + Assert.False(context.Request.Headers.ContainsKey("X-Original-For")); + Assert.True(context.Request.Headers.ContainsKey("X-Forwarded-For")); + Assert.Equal(header, context.Request.Headers["X-Forwarded-For"]); } [Theory] @@ -106,17 +89,9 @@ namespace Microsoft.AspNetCore.HttpOverrides [InlineData(3, "13.113.113.13:34567, 12.112.112.12:23456, 11.111.111.11:12345", "13.113.113.13", 34567, "", true)] public async Task XForwardedForForwardLimit(int limit, string header, string expectedIp, int expectedPort, string remainingHeader, bool requireSymmetry) { - var assertsExecuted = false; - var builder = new WebHostBuilder() .Configure(app => { - app.Use((context, next) => - { - context.Connection.RemoteIpAddress = IPAddress.Parse("10.0.0.1"); - context.Connection.RemotePort = 99; - return next(); - }); var options = new ForwardedHeadersOptions { ForwardedHeaders = ForwardedHeaders.XForwardedFor, @@ -126,21 +101,19 @@ namespace Microsoft.AspNetCore.HttpOverrides options.KnownProxies.Clear(); options.KnownNetworks.Clear(); app.UseForwardedHeaders(options); - app.Run(context => - { - Assert.Equal(expectedIp, context.Connection.RemoteIpAddress.ToString()); - Assert.Equal(expectedPort, context.Connection.RemotePort); - Assert.Equal(remainingHeader, context.Request.Headers["X-Forwarded-For"].ToString()); - assertsExecuted = true; - return Task.FromResult(0); - }); }); var server = new TestServer(builder); - var req = new HttpRequestMessage(HttpMethod.Get, ""); - req.Headers.TryAddWithoutValidation("X-Forwarded-For", header); - await server.CreateClient().SendAsync(req); - Assert.True(assertsExecuted); + var context = await server.SendAsync(c => + { + c.Request.Headers["X-Forwarded-For"] = header; + c.Connection.RemoteIpAddress = IPAddress.Parse("10.0.0.1"); + c.Connection.RemotePort = 99; + }); + + Assert.Equal(expectedIp, context.Connection.RemoteIpAddress.ToString()); + Assert.Equal(expectedPort, context.Connection.RemotePort); + Assert.Equal(remainingHeader, context.Request.Headers["X-Forwarded-For"].ToString()); } [Theory] @@ -151,47 +124,37 @@ namespace Microsoft.AspNetCore.HttpOverrides [InlineData("::", false)] public async Task XForwardedForLoopback(string originalIp, bool expectForwarded) { - var assertsExecuted = false; - var builder = new WebHostBuilder() .Configure(app => { - app.Use((context, next) => - { - context.Connection.RemoteIpAddress = IPAddress.Parse(originalIp); - context.Connection.RemotePort = 99; - return next(); - }); app.UseForwardedHeaders(new ForwardedHeadersOptions { ForwardedHeaders = ForwardedHeaders.XForwardedFor, }); - app.Run(context => - { - if (expectForwarded) - { - Assert.Equal("10.0.0.1", context.Connection.RemoteIpAddress.ToString()); - Assert.Equal(1234, context.Connection.RemotePort); - Assert.True(context.Request.Headers.ContainsKey("X-Original-For")); - Assert.Equal(new IPEndPoint(IPAddress.Parse(originalIp), 99).ToString(), - context.Request.Headers["X-Original-For"]); - } - else - { - Assert.Equal(originalIp, context.Connection.RemoteIpAddress.ToString()); - Assert.Equal(99, context.Connection.RemotePort); - Assert.False(context.Request.Headers.ContainsKey("X-Original-For")); - } - assertsExecuted = true; - return Task.FromResult(0); - }); }); var server = new TestServer(builder); - var req = new HttpRequestMessage(HttpMethod.Get, ""); - req.Headers.TryAddWithoutValidation("X-Forwarded-For", "10.0.0.1:1234"); - await server.CreateClient().SendAsync(req); - Assert.True(assertsExecuted); + var context = await server.SendAsync(c => + { + c.Request.Headers["X-Forwarded-For"] = "10.0.0.1:1234"; + c.Connection.RemoteIpAddress = IPAddress.Parse(originalIp); + c.Connection.RemotePort = 99; + }); + + if (expectForwarded) + { + Assert.Equal("10.0.0.1", context.Connection.RemoteIpAddress.ToString()); + Assert.Equal(1234, context.Connection.RemotePort); + Assert.True(context.Request.Headers.ContainsKey("X-Original-For")); + Assert.Equal(new IPEndPoint(IPAddress.Parse(originalIp), 99).ToString(), + context.Request.Headers["X-Original-For"]); + } + else + { + Assert.Equal(originalIp, context.Connection.RemoteIpAddress.ToString()); + Assert.Equal(99, context.Connection.RemotePort); + Assert.False(context.Request.Headers.ContainsKey("X-Original-For")); + } } [Theory] @@ -219,17 +182,9 @@ namespace Microsoft.AspNetCore.HttpOverrides [InlineData(3, "13.113.113.13;34567, 12.112.112.12:23456, 11.111.111.11:12345", "10.0.0.1,11.111.111.11,12.112.112.12", "12.112.112.12", 23456, true)] // Invalid 3rd IP public async Task XForwardedForForwardKnownIps(int limit, string header, string knownIPs, string expectedIp, int expectedPort, bool requireSymmetry) { - var assertsExecuted = false; - var builder = new WebHostBuilder() .Configure(app => { - app.Use((context, next) => - { - context.Connection.RemoteIpAddress = IPAddress.Parse("10.0.0.1"); - context.Connection.RemotePort = 99; - return next(); - }); var options = new ForwardedHeadersOptions { ForwardedHeaders = ForwardedHeaders.XForwardedFor, @@ -241,27 +196,23 @@ namespace Microsoft.AspNetCore.HttpOverrides options.KnownProxies.Add(ip); } app.UseForwardedHeaders(options); - app.Run(context => - { - Assert.Equal(expectedIp, context.Connection.RemoteIpAddress.ToString()); - Assert.Equal(expectedPort, context.Connection.RemotePort); - assertsExecuted = true; - return Task.FromResult(0); - }); }); var server = new TestServer(builder); - var req = new HttpRequestMessage(HttpMethod.Get, ""); - req.Headers.TryAddWithoutValidation("X-Forwarded-For", header); - await server.CreateClient().SendAsync(req); - Assert.True(assertsExecuted); + var context = await server.SendAsync(c => + { + c.Request.Headers["X-Forwarded-For"] = header; + c.Connection.RemoteIpAddress = IPAddress.Parse("10.0.0.1"); + c.Connection.RemotePort = 99; + }); + + Assert.Equal(expectedIp, context.Connection.RemoteIpAddress.ToString()); + Assert.Equal(expectedPort, context.Connection.RemotePort); } [Fact] public async Task XForwardedForOverrideBadIpDoesntChangeRemoteIp() { - var assertsExecuted = false; - var builder = new WebHostBuilder() .Configure(app => { @@ -269,26 +220,20 @@ namespace Microsoft.AspNetCore.HttpOverrides { ForwardedHeaders = ForwardedHeaders.XForwardedFor }); - app.Run(context => - { - Assert.Null(context.Connection.RemoteIpAddress); - assertsExecuted = true; - return Task.FromResult(0); - }); }); var server = new TestServer(builder); - var req = new HttpRequestMessage(HttpMethod.Get, ""); - req.Headers.Add("X-Forwarded-For", "BAD-IP"); - await server.CreateClient().SendAsync(req); - Assert.True(assertsExecuted); + var context = await server.SendAsync(c => + { + c.Request.Headers["X-Forwarded-For"] = "BAD-IP"; + }); + + Assert.Null(context.Connection.RemoteIpAddress); } [Fact] public async Task XForwardedHostOverrideChangesRequestHost() { - var assertsExecuted = false; - var builder = new WebHostBuilder() .Configure(app => { @@ -296,19 +241,15 @@ namespace Microsoft.AspNetCore.HttpOverrides { ForwardedHeaders = ForwardedHeaders.XForwardedHost }); - app.Run(context => - { - Assert.Equal("testhost", context.Request.Host.ToString()); - assertsExecuted = true; - return Task.FromResult(0); - }); }); var server = new TestServer(builder); - var req = new HttpRequestMessage(HttpMethod.Get, ""); - req.Headers.Add("X-Forwarded-Host", "testhost"); - await server.CreateClient().SendAsync(req); - Assert.True(assertsExecuted); + var context = await server.SendAsync(c => + { + c.Request.Headers["X-Forwarded-Host"] = "testhost"; + }); + + Assert.Equal("testhost", context.Request.Host.ToString()); } [Theory] @@ -321,8 +262,6 @@ namespace Microsoft.AspNetCore.HttpOverrides [InlineData(10, "h3, h2, h1", "h3")] public async Task XForwardedProtoOverrideChangesRequestProtocol(int limit, string header, string expected) { - var assertsExecuted = false; - var builder = new WebHostBuilder() .Configure(app => { @@ -331,19 +270,15 @@ namespace Microsoft.AspNetCore.HttpOverrides ForwardedHeaders = ForwardedHeaders.XForwardedProto, ForwardLimit = limit, }); - app.Run(context => - { - Assert.Equal(expected, context.Request.Scheme); - assertsExecuted = true; - return Task.FromResult(0); - }); }); var server = new TestServer(builder); - var req = new HttpRequestMessage(HttpMethod.Get, ""); - req.Headers.Add("X-Forwarded-Proto", header); - await server.CreateClient().SendAsync(req); - Assert.True(assertsExecuted); + var context = await server.SendAsync(c => + { + c.Request.Headers["X-Forwarded-Proto"] = header; + }); + + Assert.Equal(expected, context.Request.Scheme); } [Theory] @@ -357,8 +292,6 @@ namespace Microsoft.AspNetCore.HttpOverrides [InlineData(10, "h3, h2, h1", "::1, badip, ::1", "h1")] public async Task XForwardedProtoOverrideLimitedByXForwardedForCount(int limit, string protoHeader, string forHeader, string expected) { - var assertsExecuted = false; - var builder = new WebHostBuilder() .Configure(app => { @@ -368,20 +301,16 @@ namespace Microsoft.AspNetCore.HttpOverrides RequireHeaderSymmetry = true, ForwardLimit = limit, }); - app.Run(context => - { - Assert.Equal(expected, context.Request.Scheme); - assertsExecuted = true; - return Task.FromResult(0); - }); }); var server = new TestServer(builder); - var req = new HttpRequestMessage(HttpMethod.Get, ""); - req.Headers.Add("X-Forwarded-Proto", protoHeader); - req.Headers.Add("X-Forwarded-For", forHeader); - await server.CreateClient().SendAsync(req); - Assert.True(assertsExecuted); + var context = await server.SendAsync(c => + { + c.Request.Headers["X-Forwarded-Proto"] = protoHeader; + c.Request.Headers["X-Forwarded-For"] = forHeader; + }); + + Assert.Equal(expected, context.Request.Scheme); } [Theory] @@ -397,8 +326,6 @@ namespace Microsoft.AspNetCore.HttpOverrides [InlineData(10, "h3, h2, h1", "::1, badip, ::1", "h1")] public async Task XForwardedProtoOverrideCanBeIndependentOfXForwardedForCount(int limit, string protoHeader, string forHeader, string expected) { - var assertsExecuted = false; - var builder = new WebHostBuilder() .Configure(app => { @@ -408,20 +335,16 @@ namespace Microsoft.AspNetCore.HttpOverrides RequireHeaderSymmetry = false, ForwardLimit = limit, }); - app.Run(context => - { - Assert.Equal(expected, context.Request.Scheme); - assertsExecuted = true; - return Task.FromResult(0); - }); }); var server = new TestServer(builder); - var req = new HttpRequestMessage(HttpMethod.Get, ""); - req.Headers.Add("X-Forwarded-Proto", protoHeader); - req.Headers.Add("X-Forwarded-For", forHeader); - await server.CreateClient().SendAsync(req); - Assert.True(assertsExecuted); + var context = await server.SendAsync(c => + { + c.Request.Headers["X-Forwarded-Proto"] = protoHeader; + c.Request.Headers["X-Forwarded-For"] = forHeader; + }); + + Assert.Equal(expected, context.Request.Scheme); } [Theory] @@ -439,16 +362,9 @@ namespace Microsoft.AspNetCore.HttpOverrides [InlineData("h2, h1", "E::, D::", "F::", true, "http")] public async Task XForwardedProtoOverrideLimitedByLoopback(string protoHeader, string forHeader, string remoteIp, bool loopback, string expected) { - var assertsExecuted = false; - var builder = new WebHostBuilder() .Configure(app => { - app.Use((context, next) => - { - context.Connection.RemoteIpAddress = IPAddress.Parse(remoteIp); - return next(); - }); var options = new ForwardedHeadersOptions { ForwardedHeaders = ForwardedHeaders.XForwardedProto | ForwardedHeaders.XForwardedFor, @@ -461,20 +377,17 @@ namespace Microsoft.AspNetCore.HttpOverrides options.KnownProxies.Clear(); } app.UseForwardedHeaders(options); - app.Run(context => - { - Assert.Equal(expected, context.Request.Scheme); - assertsExecuted = true; - return Task.FromResult(0); - }); }); var server = new TestServer(builder); - var req = new HttpRequestMessage(HttpMethod.Get, ""); - req.Headers.Add("X-Forwarded-Proto", protoHeader); - req.Headers.Add("X-Forwarded-For", forHeader); - await server.CreateClient().SendAsync(req); - Assert.True(assertsExecuted); + var context = await server.SendAsync(c => + { + c.Request.Headers["X-Forwarded-Proto"] = protoHeader; + c.Request.Headers["X-Forwarded-For"] = forHeader; + c.Connection.RemoteIpAddress = IPAddress.Parse(remoteIp); + }); + + Assert.Equal(expected, context.Request.Scheme); } [Fact] @@ -490,8 +403,6 @@ namespace Microsoft.AspNetCore.HttpOverrides [Fact] public async Task AllForwardsEnabledChangeRequestRemoteIpHostandProtocol() { - var assertsExecuted = false; - var builder = new WebHostBuilder() .Configure(app => { @@ -499,30 +410,24 @@ namespace Microsoft.AspNetCore.HttpOverrides { ForwardedHeaders = ForwardedHeaders.All }); - app.Run(context => - { - Assert.Equal("11.111.111.11", context.Connection.RemoteIpAddress.ToString()); - Assert.Equal("testhost", context.Request.Host.ToString()); - Assert.Equal("Protocol", context.Request.Scheme); - assertsExecuted = true; - return Task.FromResult(0); - }); }); var server = new TestServer(builder); - var req = new HttpRequestMessage(HttpMethod.Get, ""); - req.Headers.Add("X-Forwarded-For", "11.111.111.11"); - req.Headers.Add("X-Forwarded-Host", "testhost"); - req.Headers.Add("X-Forwarded-Proto", "Protocol"); - await server.CreateClient().SendAsync(req); - Assert.True(assertsExecuted); + var context = await server.SendAsync(c => + { + c.Request.Headers["X-Forwarded-Proto"] = "Protocol"; + c.Request.Headers["X-Forwarded-For"] = "11.111.111.11"; + c.Request.Headers["X-Forwarded-Host"] = "testhost"; + }); + + Assert.Equal("11.111.111.11", context.Connection.RemoteIpAddress.ToString()); + Assert.Equal("testhost", context.Request.Host.ToString()); + Assert.Equal("Protocol", context.Request.Scheme); } [Fact] public async Task AllOptionsDisabledRequestDoesntChange() { - var assertsExecuted = false; - var builder = new WebHostBuilder() .Configure(app => { @@ -530,30 +435,24 @@ namespace Microsoft.AspNetCore.HttpOverrides { ForwardedHeaders = ForwardedHeaders.None }); - app.Run(context => - { - Assert.Null(context.Connection.RemoteIpAddress); - Assert.Equal("localhost", context.Request.Host.ToString()); - Assert.Equal("http", context.Request.Scheme); - assertsExecuted = true; - return Task.FromResult(0); - }); }); var server = new TestServer(builder); - var req = new HttpRequestMessage(HttpMethod.Get, ""); - req.Headers.Add("X-Forwarded-For", "11.111.111.11"); - req.Headers.Add("X-Forwarded-Host", "otherhost"); - req.Headers.Add("X-Forwarded-Proto", "Protocol"); - await server.CreateClient().SendAsync(req); - Assert.True(assertsExecuted); + var context = await server.SendAsync(c => + { + c.Request.Headers["X-Forwarded-Proto"] = "Protocol"; + c.Request.Headers["X-Forwarded-For"] = "11.111.111.11"; + c.Request.Headers["X-Forwarded-Host"] = "otherhost"; + }); + + Assert.Null(context.Connection.RemoteIpAddress); + Assert.Equal("localhost", context.Request.Host.ToString()); + Assert.Equal("http", context.Request.Scheme); } [Fact] public async Task PartiallyEnabledForwardsPartiallyChangesRequest() { - var assertsExecuted = false; - var builder = new WebHostBuilder() .Configure(app => { @@ -561,23 +460,18 @@ namespace Microsoft.AspNetCore.HttpOverrides { ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto }); - app.Run(context => - { - Assert.Equal("11.111.111.11", context.Connection.RemoteIpAddress.ToString()); - Assert.Equal("localhost", context.Request.Host.ToString()); - Assert.Equal("Protocol", context.Request.Scheme); - assertsExecuted = true; - return Task.FromResult(0); - - }); }); var server = new TestServer(builder); - var req = new HttpRequestMessage(HttpMethod.Get, ""); - req.Headers.Add("X-Forwarded-For", "11.111.111.11"); - req.Headers.Add("X-Forwarded-Proto", "Protocol"); - await server.CreateClient().SendAsync(req); - Assert.True(assertsExecuted); + var context = await server.SendAsync(c => + { + c.Request.Headers["X-Forwarded-Proto"] = "Protocol"; + c.Request.Headers["X-Forwarded-For"] = "11.111.111.11"; + }); + + Assert.Equal("11.111.111.11", context.Connection.RemoteIpAddress.ToString()); + Assert.Equal("localhost", context.Request.Host.ToString()); + Assert.Equal("Protocol", context.Request.Scheme); } } } diff --git a/test/Microsoft.AspNetCore.HttpsEnforcement.Tests/HstsMiddlewareTests.cs b/test/Microsoft.AspNetCore.HttpsEnforcement.Tests/HstsMiddlewareTests.cs index e6d325769f..64917f3e74 100644 --- a/test/Microsoft.AspNetCore.HttpsEnforcement.Tests/HstsMiddlewareTests.cs +++ b/test/Microsoft.AspNetCore.HttpsEnforcement.Tests/HstsMiddlewareTests.cs @@ -22,7 +22,6 @@ namespace Microsoft.AspNetCore.HttpsPolicy.Tests public async Task SetOptionsWithDefault_SetsMaxAgeToCorrectValue() { var builder = new WebHostBuilder() - .UseUrls("https://*:5050") .ConfigureServices(services => { }) @@ -57,7 +56,6 @@ namespace Microsoft.AspNetCore.HttpsPolicy.Tests public async Task SetOptionsThroughConfigure_SetsHeaderCorrectly(int maxAge, bool includeSubDomains, bool preload, string expected) { var builder = new WebHostBuilder() - .UseUrls("https://*:5050") .ConfigureServices(services => { services.Configure(options => { @@ -96,7 +94,6 @@ namespace Microsoft.AspNetCore.HttpsPolicy.Tests public async Task SetOptionsThroughHelper_SetsHeaderCorrectly(int maxAge, bool includeSubDomains, bool preload, string expected) { var builder = new WebHostBuilder() - .UseUrls("https://*:5050") .ConfigureServices(services => { services.AddHsts(options => { diff --git a/test/Microsoft.AspNetCore.HttpsEnforcement.Tests/HttpsPolicyTests.cs b/test/Microsoft.AspNetCore.HttpsEnforcement.Tests/HttpsPolicyTests.cs index 57e3546153..53fd91dde5 100644 --- a/test/Microsoft.AspNetCore.HttpsEnforcement.Tests/HttpsPolicyTests.cs +++ b/test/Microsoft.AspNetCore.HttpsEnforcement.Tests/HttpsPolicyTests.cs @@ -30,7 +30,6 @@ namespace Microsoft.AspNetCore.HttpsPolicy.Tests { var builder = new WebHostBuilder() - .UseUrls("https://*:5050", "http://*:5050") .ConfigureServices(services => { services.Configure(options => From ad39e596bb6c44860c1a88fe88edab9c55728b39 Mon Sep 17 00:00:00 2001 From: John Luo Date: Thu, 2 Nov 2017 15:38:23 -0700 Subject: [PATCH 240/307] Update to latest versions Picking up latest hosting changes --- build/dependencies.props | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index 70ea21dfa6..7e38cc7bec 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -1,24 +1,24 @@ - + $(MSBuildAllProjects);$(MSBuildThisFileFullPath) 2.1.0-preview1-15549 - 2.1.0-preview1-27480 - 2.1.0-preview1-27480 - 2.1.0-preview1-27480 - 2.1.0-preview1-27480 - 2.1.0-preview1-27480 - 2.1.0-preview1-27480 - 2.1.0-preview1-27480 - 2.1.0-preview1-27480 - 2.1.0-preview1-27480 - 2.1.0-preview1-27480 - 2.1.0-preview1-27480 - 2.1.0-preview1-27480 - 2.1.0-preview1-27480 + 2.1.0-preview1-27501 + 2.1.0-preview1-27501 + 2.1.0-preview1-27501 + 2.1.0-preview1-27501 + 2.1.0-preview1-27501 + 2.1.0-preview1-27501 + 2.1.0-preview1-27501 + 2.1.0-preview1-27501 + 2.1.0-preview1-27501 + 2.1.0-preview1-27501 + 2.1.0-preview1-27501 + 2.1.0-preview1-27501 + 2.1.0-preview1-27501 2.0.0 - 2.1.0-preview1-27480 + 2.1.0-preview1-27501 15.3.0 4.7.49 0.7.0 From 759148da4c19bff0a5150ee9d89731ffc01a9fa7 Mon Sep 17 00:00:00 2001 From: Pranav K Date: Tue, 14 Nov 2017 09:54:42 -0800 Subject: [PATCH 241/307] Update samples and tests to target netcoreapp2.1 --- Directory.Build.props | 4 ++++ korebuild-lock.txt | 4 ++-- samples/HttpOverridesSample/HttpOverridesSample.csproj | 3 +-- .../ResponseBufferingSample/ResponseBufferingSample.csproj | 3 +-- .../ResponseCompressionSample.csproj | 3 +-- samples/RewriteSample/RewriteSample.csproj | 3 +-- test/Directory.Build.props | 7 +++++++ .../Microsoft.AspNetCore.Buffering.Tests.csproj | 3 +-- .../Microsoft.AspNetCore.HttpOverrides.Tests.csproj | 3 +-- .../Microsoft.AspNetCore.HttpsPolicy.Tests.csproj | 3 ++- .../Microsoft.AspNetCore.ResponseCompression.Tests.csproj | 3 +-- .../ResponseCompressionMiddlewareTest.cs | 4 ++-- .../Microsoft.AspNetCore.Rewrite.Tests.csproj | 3 +-- 13 files changed, 25 insertions(+), 21 deletions(-) diff --git a/Directory.Build.props b/Directory.Build.props index fb21f30265..9af0b2f45c 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -1,4 +1,8 @@  + + diff --git a/korebuild-lock.txt b/korebuild-lock.txt index 45463cc71e..95f4613014 100644 --- a/korebuild-lock.txt +++ b/korebuild-lock.txt @@ -1,2 +1,2 @@ -version:2.1.0-preview1-15549 -commithash:f570e08585fec510dd60cd4bfe8795388b757a95 +version:2.1.0-preview1-15567 +commithash:903e3104807b1bb8cddd28bdef205b1e2dc021d1 diff --git a/samples/HttpOverridesSample/HttpOverridesSample.csproj b/samples/HttpOverridesSample/HttpOverridesSample.csproj index b4962cd5be..e966dd09a7 100644 --- a/samples/HttpOverridesSample/HttpOverridesSample.csproj +++ b/samples/HttpOverridesSample/HttpOverridesSample.csproj @@ -1,8 +1,7 @@  - net461;netcoreapp2.0 - netcoreapp2.0 + netcoreapp2.1;net461 diff --git a/samples/ResponseBufferingSample/ResponseBufferingSample.csproj b/samples/ResponseBufferingSample/ResponseBufferingSample.csproj index f2c65f721f..b9595a89d8 100644 --- a/samples/ResponseBufferingSample/ResponseBufferingSample.csproj +++ b/samples/ResponseBufferingSample/ResponseBufferingSample.csproj @@ -1,8 +1,7 @@  - net461;netcoreapp2.0 - netcoreapp2.0 + netcoreapp2.1;net461 diff --git a/samples/ResponseCompressionSample/ResponseCompressionSample.csproj b/samples/ResponseCompressionSample/ResponseCompressionSample.csproj index ed417e69a2..2a7f4cfbb7 100644 --- a/samples/ResponseCompressionSample/ResponseCompressionSample.csproj +++ b/samples/ResponseCompressionSample/ResponseCompressionSample.csproj @@ -1,8 +1,7 @@  - net461;netcoreapp2.0 - netcoreapp2.0 + netcoreapp2.1;net461 diff --git a/samples/RewriteSample/RewriteSample.csproj b/samples/RewriteSample/RewriteSample.csproj index cc73c47aff..a74fc45b85 100644 --- a/samples/RewriteSample/RewriteSample.csproj +++ b/samples/RewriteSample/RewriteSample.csproj @@ -1,8 +1,7 @@  - net461;netcoreapp2.0 - netcoreapp2.0 + netcoreapp2.1;net461 diff --git a/test/Directory.Build.props b/test/Directory.Build.props index 33f658f32d..b936409242 100644 --- a/test/Directory.Build.props +++ b/test/Directory.Build.props @@ -1,6 +1,13 @@ + + netcoreapp2.1 + $(DeveloperBuildTestTfms) + netcoreapp2.1;netcoreapp2.0 + $(StandardTestTfms);net461 + + diff --git a/test/Microsoft.AspNetCore.Buffering.Tests/Microsoft.AspNetCore.Buffering.Tests.csproj b/test/Microsoft.AspNetCore.Buffering.Tests/Microsoft.AspNetCore.Buffering.Tests.csproj index b1938055cc..5f8209ea44 100644 --- a/test/Microsoft.AspNetCore.Buffering.Tests/Microsoft.AspNetCore.Buffering.Tests.csproj +++ b/test/Microsoft.AspNetCore.Buffering.Tests/Microsoft.AspNetCore.Buffering.Tests.csproj @@ -1,8 +1,7 @@  - netcoreapp2.0;net461 - netcoreapp2.0 + $(StandardTestTfms) diff --git a/test/Microsoft.AspNetCore.HttpOverrides.Tests/Microsoft.AspNetCore.HttpOverrides.Tests.csproj b/test/Microsoft.AspNetCore.HttpOverrides.Tests/Microsoft.AspNetCore.HttpOverrides.Tests.csproj index c78b062129..dc9bc780b0 100644 --- a/test/Microsoft.AspNetCore.HttpOverrides.Tests/Microsoft.AspNetCore.HttpOverrides.Tests.csproj +++ b/test/Microsoft.AspNetCore.HttpOverrides.Tests/Microsoft.AspNetCore.HttpOverrides.Tests.csproj @@ -1,8 +1,7 @@  - netcoreapp2.0;net461 - netcoreapp2.0 + $(StandardTestTfms) diff --git a/test/Microsoft.AspNetCore.HttpsEnforcement.Tests/Microsoft.AspNetCore.HttpsPolicy.Tests.csproj b/test/Microsoft.AspNetCore.HttpsEnforcement.Tests/Microsoft.AspNetCore.HttpsPolicy.Tests.csproj index acdd245d85..af610a24a8 100644 --- a/test/Microsoft.AspNetCore.HttpsEnforcement.Tests/Microsoft.AspNetCore.HttpsPolicy.Tests.csproj +++ b/test/Microsoft.AspNetCore.HttpsEnforcement.Tests/Microsoft.AspNetCore.HttpsPolicy.Tests.csproj @@ -1,7 +1,8 @@ - netcoreapp2.0 + netcoreapp2.1 + $(TargetFrameworks);netcoreapp2.0 diff --git a/test/Microsoft.AspNetCore.ResponseCompression.Tests/Microsoft.AspNetCore.ResponseCompression.Tests.csproj b/test/Microsoft.AspNetCore.ResponseCompression.Tests/Microsoft.AspNetCore.ResponseCompression.Tests.csproj index 1d29ce2135..902449b486 100644 --- a/test/Microsoft.AspNetCore.ResponseCompression.Tests/Microsoft.AspNetCore.ResponseCompression.Tests.csproj +++ b/test/Microsoft.AspNetCore.ResponseCompression.Tests/Microsoft.AspNetCore.ResponseCompression.Tests.csproj @@ -1,8 +1,7 @@  - netcoreapp2.0;net461 - netcoreapp2.0 + $(StandardTestTfms) diff --git a/test/Microsoft.AspNetCore.ResponseCompression.Tests/ResponseCompressionMiddlewareTest.cs b/test/Microsoft.AspNetCore.ResponseCompression.Tests/ResponseCompressionMiddlewareTest.cs index fd9a989564..213a4c8fd7 100644 --- a/test/Microsoft.AspNetCore.ResponseCompression.Tests/ResponseCompressionMiddlewareTest.cs +++ b/test/Microsoft.AspNetCore.ResponseCompression.Tests/ResponseCompressionMiddlewareTest.cs @@ -508,7 +508,7 @@ namespace Microsoft.AspNetCore.ResponseCompression.Tests #if NET461 // Flush not supported, compression disabled Assert.NotNull(response.Content.Headers.GetValues(HeaderNames.ContentMD5)); Assert.Empty(response.Content.Headers.ContentEncoding); -#elif NETCOREAPP2_0 // Flush supported, compression enabled +#elif NETCOREAPP2_0 || NETCOREAPP2_1 // Flush supported, compression enabled IEnumerable contentMD5 = null; Assert.False(response.Content.Headers.TryGetValues(HeaderNames.ContentMD5, out contentMD5)); Assert.Single(response.Content.Headers.ContentEncoding, "gzip"); @@ -573,7 +573,7 @@ namespace Microsoft.AspNetCore.ResponseCompression.Tests #if NET461 // Flush not supported, compression disabled Assert.NotNull(response.Content.Headers.GetValues(HeaderNames.ContentMD5)); Assert.Empty(response.Content.Headers.ContentEncoding); -#elif NETCOREAPP2_0 // Flush supported, compression enabled +#elif NETCOREAPP2_0 || NETCOREAPP2_1 // Flush supported, compression enabled IEnumerable contentMD5 = null; Assert.False(response.Content.Headers.TryGetValues(HeaderNames.ContentMD5, out contentMD5)); Assert.Single(response.Content.Headers.ContentEncoding, "gzip"); diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/Microsoft.AspNetCore.Rewrite.Tests.csproj b/test/Microsoft.AspNetCore.Rewrite.Tests/Microsoft.AspNetCore.Rewrite.Tests.csproj index ebefe2dd1e..ef02b99631 100644 --- a/test/Microsoft.AspNetCore.Rewrite.Tests/Microsoft.AspNetCore.Rewrite.Tests.csproj +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/Microsoft.AspNetCore.Rewrite.Tests.csproj @@ -1,8 +1,7 @@  - netcoreapp2.0;net461 - netcoreapp2.0 + $(StandardTestTfms) From 727efaec4959494935dfb93baa98942a53eb6037 Mon Sep 17 00:00:00 2001 From: Justin Kotalik Date: Fri, 17 Nov 2017 09:51:54 -0800 Subject: [PATCH 242/307] Changes Https Redirect default from 301 to 302 (#272) --- src/Microsoft.AspNetCore.HttpsPolicy/HttpsRedirectionOptions.cs | 2 +- .../HttpsRedirectionMiddlewareTests.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Microsoft.AspNetCore.HttpsPolicy/HttpsRedirectionOptions.cs b/src/Microsoft.AspNetCore.HttpsPolicy/HttpsRedirectionOptions.cs index 38f7026e25..238f2eb484 100644 --- a/src/Microsoft.AspNetCore.HttpsPolicy/HttpsRedirectionOptions.cs +++ b/src/Microsoft.AspNetCore.HttpsPolicy/HttpsRedirectionOptions.cs @@ -13,7 +13,7 @@ namespace Microsoft.AspNetCore.HttpsPolicy /// /// The status code to redirect the response to. /// - public int RedirectStatusCode { get; set; } = StatusCodes.Status301MovedPermanently; + public int RedirectStatusCode { get; set; } = StatusCodes.Status302Found; /// /// The TLS port to be added to the redirected URL. diff --git a/test/Microsoft.AspNetCore.HttpsEnforcement.Tests/HttpsRedirectionMiddlewareTests.cs b/test/Microsoft.AspNetCore.HttpsEnforcement.Tests/HttpsRedirectionMiddlewareTests.cs index e9312decba..aabba1324e 100644 --- a/test/Microsoft.AspNetCore.HttpsEnforcement.Tests/HttpsRedirectionMiddlewareTests.cs +++ b/test/Microsoft.AspNetCore.HttpsEnforcement.Tests/HttpsRedirectionMiddlewareTests.cs @@ -41,7 +41,7 @@ namespace Microsoft.AspNetCore.HttpsPolicy.Tests var response = await client.SendAsync(request); - Assert.Equal(HttpStatusCode.MovedPermanently, response.StatusCode); + Assert.Equal(HttpStatusCode.Found, response.StatusCode); Assert.Equal("https://localhost/", response.Headers.Location.ToString()); } From d763ee071c0520445cc78cdca5f2360d3d49de01 Mon Sep 17 00:00:00 2001 From: Pranav K Date: Fri, 17 Nov 2017 13:00:24 -0800 Subject: [PATCH 243/307] Use MicrosoftNETCoreApp21PackageVersion to determine the runtime framework in netcoreapp2.1 --- Directory.Build.targets | 1 + build/dependencies.props | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/Directory.Build.targets b/Directory.Build.targets index e83ff95e39..894b1d0cf8 100644 --- a/Directory.Build.targets +++ b/Directory.Build.targets @@ -1,5 +1,6 @@  $(MicrosoftNETCoreApp20PackageVersion) + $(MicrosoftNETCoreApp21PackageVersion) diff --git a/build/dependencies.props b/build/dependencies.props index 7e38cc7bec..270fca6d61 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -1,4 +1,4 @@ - + $(MSBuildAllProjects);$(MSBuildThisFileFullPath) @@ -18,6 +18,7 @@ 2.1.0-preview1-27501 2.1.0-preview1-27501 2.0.0 + 2.1.0-preview1-25907-02 2.1.0-preview1-27501 15.3.0 4.7.49 From d46f3894b1976d8ea4a62a67c305e652e93c536d Mon Sep 17 00:00:00 2001 From: Nate McMaster Date: Mon, 20 Nov 2017 12:15:38 -0800 Subject: [PATCH 244/307] Use MSBuild to set NuGet feeds instead of NuGet.config --- Directory.Build.props | 1 + NuGet.config | 4 +--- build/sources.props | 16 ++++++++++++++++ 3 files changed, 18 insertions(+), 3 deletions(-) create mode 100644 build/sources.props diff --git a/Directory.Build.props b/Directory.Build.props index 9af0b2f45c..0600ee6c34 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -5,6 +5,7 @@ + Microsoft ASP.NET Core diff --git a/NuGet.config b/NuGet.config index 4e8a1f6de1..e32bddfd51 100644 --- a/NuGet.config +++ b/NuGet.config @@ -2,8 +2,6 @@ - - - + diff --git a/build/sources.props b/build/sources.props new file mode 100644 index 0000000000..c03f3ddb60 --- /dev/null +++ b/build/sources.props @@ -0,0 +1,16 @@ + + + + + $(DotNetRestoreSources) + + $(RestoreSources); + https://dotnet.myget.org/F/aspnetcore-ci-dev/api/v3/index.json; + https://dotnet.myget.org/F/aspnetcore-tools/api/v3/index.json; + + + $(RestoreSources); + https://api.nuget.org/v3/index.json; + + + From faa075a3483f4d4482d125a17998a9df401ae986 Mon Sep 17 00:00:00 2001 From: Pranav K Date: Tue, 21 Nov 2017 16:26:55 -0800 Subject: [PATCH 245/307] Replace aspnetcore-ci-dev feed with aspnetcore-dev --- build/dependencies.props | 32 ++++++++++++++++---------------- build/repo.props | 4 ++-- build/sources.props | 2 +- korebuild-lock.txt | 4 ++-- 4 files changed, 21 insertions(+), 21 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index 270fca6d61..0e232a77d6 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -1,25 +1,25 @@ - + $(MSBuildAllProjects);$(MSBuildThisFileFullPath) - 2.1.0-preview1-15549 - 2.1.0-preview1-27501 - 2.1.0-preview1-27501 - 2.1.0-preview1-27501 - 2.1.0-preview1-27501 - 2.1.0-preview1-27501 - 2.1.0-preview1-27501 - 2.1.0-preview1-27501 - 2.1.0-preview1-27501 - 2.1.0-preview1-27501 - 2.1.0-preview1-27501 - 2.1.0-preview1-27501 - 2.1.0-preview1-27501 - 2.1.0-preview1-27501 + 2.1.0-preview1-15576 + 2.1.0-preview1-27644 + 2.1.0-preview1-27644 + 2.1.0-preview1-27644 + 2.1.0-preview1-27644 + 2.1.0-preview1-27644 + 2.1.0-preview1-27644 + 2.1.0-preview1-27644 + 2.1.0-preview1-27644 + 2.1.0-preview1-27644 + 2.1.0-preview1-27644 + 2.1.0-preview1-27644 + 2.1.0-preview1-27644 + 2.1.0-preview1-27644 2.0.0 2.1.0-preview1-25907-02 - 2.1.0-preview1-27501 + 2.1.0-preview1-27644 15.3.0 4.7.49 0.7.0 diff --git a/build/repo.props b/build/repo.props index 20e96b5d3c..07c5f08325 100644 --- a/build/repo.props +++ b/build/repo.props @@ -1,7 +1,7 @@ - + Internal.AspNetCore.Universe.Lineup - https://dotnet.myget.org/F/aspnetcore-ci-dev/api/v3/index.json + https://dotnet.myget.org/F/aspnetcore-dev/api/v3/index.json diff --git a/build/sources.props b/build/sources.props index c03f3ddb60..9feff29d09 100644 --- a/build/sources.props +++ b/build/sources.props @@ -5,7 +5,7 @@ $(DotNetRestoreSources) $(RestoreSources); - https://dotnet.myget.org/F/aspnetcore-ci-dev/api/v3/index.json; + https://dotnet.myget.org/F/aspnetcore-dev/api/v3/index.json; https://dotnet.myget.org/F/aspnetcore-tools/api/v3/index.json; diff --git a/korebuild-lock.txt b/korebuild-lock.txt index 95f4613014..1a99066b7c 100644 --- a/korebuild-lock.txt +++ b/korebuild-lock.txt @@ -1,2 +1,2 @@ -version:2.1.0-preview1-15567 -commithash:903e3104807b1bb8cddd28bdef205b1e2dc021d1 +version:2.1.0-preview1-15576 +commithash:2f3856d2ba4f659fcb9253215b83946a06794a27 From 52abda04ffc74d35949388125544a36ebb09d946 Mon Sep 17 00:00:00 2001 From: Pranav K Date: Wed, 29 Nov 2017 14:09:24 -0800 Subject: [PATCH 246/307] Specify runtime versions to install --- build/repo.props | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/build/repo.props b/build/repo.props index 07c5f08325..78b0ce5879 100644 --- a/build/repo.props +++ b/build/repo.props @@ -1,7 +1,14 @@  + + Internal.AspNetCore.Universe.Lineup https://dotnet.myget.org/F/aspnetcore-dev/api/v3/index.json + + + + + From 8248a3bf1fa6c8c91ed0ffad6ab6fc48091a954a Mon Sep 17 00:00:00 2001 From: Ryan Brandenburg Date: Fri, 1 Dec 2017 10:20:49 -0800 Subject: [PATCH 247/307] Update bootstrappers --- run.ps1 | 17 +++++++++++------ run.sh | 30 +++++++++++++++++++----------- 2 files changed, 30 insertions(+), 17 deletions(-) diff --git a/run.ps1 b/run.ps1 index 49c2899856..27dcf848f8 100644 --- a/run.ps1 +++ b/run.ps1 @@ -29,6 +29,9 @@ Updates KoreBuild to the latest version even if a lock file is present. .PARAMETER ConfigFile The path to the configuration file that stores values. Defaults to korebuild.json. +.PARAMETER ToolsSourceSuffix +The Suffix to append to the end of the ToolsSource. Useful for query strings in blob stores. + .PARAMETER Arguments Arguments to be passed to the command @@ -51,7 +54,7 @@ Example config file: #> [CmdletBinding(PositionalBinding = $false)] param( - [Parameter(Mandatory=$true, Position = 0)] + [Parameter(Mandatory = $true, Position = 0)] [string]$Command, [string]$Path = $PSScriptRoot, [Alias('c')] @@ -63,6 +66,7 @@ param( [Alias('u')] [switch]$Update, [string]$ConfigFile, + [string]$ToolsSourceSuffix, [Parameter(ValueFromRemainingArguments = $true)] [string[]]$Arguments ) @@ -79,7 +83,7 @@ function Get-KoreBuild { $lockFile = Join-Path $Path 'korebuild-lock.txt' if (!(Test-Path $lockFile) -or $Update) { - Get-RemoteFile "$ToolsSource/korebuild/channels/$Channel/latest.txt" $lockFile + Get-RemoteFile "$ToolsSource/korebuild/channels/$Channel/latest.txt" $lockFile $ToolsSourceSuffix } $version = Get-Content $lockFile | Where-Object { $_ -like 'version:*' } | Select-Object -first 1 @@ -96,7 +100,7 @@ function Get-KoreBuild { try { $tmpfile = Join-Path ([IO.Path]::GetTempPath()) "KoreBuild-$([guid]::NewGuid()).zip" - Get-RemoteFile $remotePath $tmpfile + Get-RemoteFile $remotePath $tmpfile $ToolsSourceSuffix if (Get-Command -Name 'Expand-Archive' -ErrorAction Ignore) { # Use built-in commands where possible as they are cross-plat compatible Expand-Archive -Path $tmpfile -DestinationPath $korebuildPath @@ -124,7 +128,7 @@ function Join-Paths([string]$path, [string[]]$childPaths) { return $path } -function Get-RemoteFile([string]$RemotePath, [string]$LocalPath) { +function Get-RemoteFile([string]$RemotePath, [string]$LocalPath, [string]$RemoteSuffix) { if ($RemotePath -notlike 'http*') { Copy-Item $RemotePath $LocalPath return @@ -134,7 +138,7 @@ function Get-RemoteFile([string]$RemotePath, [string]$LocalPath) { while ($retries -gt 0) { $retries -= 1 try { - Invoke-WebRequest -UseBasicParsing -Uri $RemotePath -OutFile $LocalPath + Invoke-WebRequest -UseBasicParsing -Uri $($RemotePath + $RemoteSuffix) -OutFile $LocalPath return } catch { @@ -161,7 +165,8 @@ if (Test-Path $ConfigFile) { if (!($Channel) -and (Get-Member -Name 'channel' -InputObject $config)) { [string] $Channel = $config.channel } if (!($ToolsSource) -and (Get-Member -Name 'toolsSource' -InputObject $config)) { [string] $ToolsSource = $config.toolsSource} } - } catch { + } + catch { Write-Warning "$ConfigFile could not be read. Its settings will be ignored." Write-Warning $Error[0] } diff --git a/run.sh b/run.sh index c278423acc..834961fc3a 100755 --- a/run.sh +++ b/run.sh @@ -17,6 +17,7 @@ update=false repo_path="$DIR" channel='' tools_source='' +tools_source_suffix='' # # Functions @@ -29,13 +30,14 @@ __usage() { echo " ... Arguments passed to the command. Variable number of arguments allowed." echo "" echo "Options:" - echo " --verbose Show verbose output." - echo " -c|--channel The channel of KoreBuild to download. Overrides the value from the config file.." - echo " --config-file The path to the configuration file that stores values. Defaults to korebuild.json." - echo " -d|--dotnet-home The directory where .NET Core tools will be stored. Defaults to '\$DOTNET_HOME' or '\$HOME/.dotnet." - echo " --path The directory to build. Defaults to the directory containing the script." - echo " -s|--tools-source|-ToolsSource The base url where build tools can be downloaded. Overrides the value from the config file." - echo " -u|--update Update to the latest KoreBuild even if the lock file is present." + echo " --verbose Show verbose output." + echo " -c|--channel The channel of KoreBuild to download. Overrides the value from the config file.." + echo " --config-file The path to the configuration file that stores values. Defaults to korebuild.json." + echo " -d|--dotnet-home The directory where .NET Core tools will be stored. Defaults to '\$DOTNET_HOME' or '\$HOME/.dotnet." + echo " --path The directory to build. Defaults to the directory containing the script." + echo " -s|--tools-source|-ToolsSource The base url where build tools can be downloaded. Overrides the value from the config file." + echo " --tools-source-suffix|-ToolsSourceSuffix The suffix to append to tools-source. Useful for query strings." + echo " -u|--update Update to the latest KoreBuild even if the lock file is present." echo "" echo "Description:" echo " This function will create a file \$DIR/korebuild-lock.txt. This lock file can be committed to source, but does not have to be." @@ -50,7 +52,7 @@ get_korebuild() { local version local lock_file="$repo_path/korebuild-lock.txt" if [ ! -f "$lock_file" ] || [ "$update" = true ]; then - __get_remote_file "$tools_source/korebuild/channels/$channel/latest.txt" "$lock_file" + __get_remote_file "$tools_source/korebuild/channels/$channel/latest.txt" "$lock_file" "$tools_source_suffix" fi version="$(grep 'version:*' -m 1 "$lock_file")" if [[ "$version" == '' ]]; then @@ -66,7 +68,7 @@ get_korebuild() { local remote_path="$tools_source/korebuild/artifacts/$version/korebuild.$version.zip" tmpfile="$(mktemp)" echo -e "${MAGENTA}Downloading KoreBuild ${version}${RESET}" - if __get_remote_file "$remote_path" "$tmpfile"; then + if __get_remote_file "$remote_path" "$tmpfile" "$tools_source_suffix"; then unzip -q -d "$korebuild_path" "$tmpfile" fi rm "$tmpfile" || true @@ -98,6 +100,7 @@ __machine_has() { __get_remote_file() { local remote_path=$1 local local_path=$2 + local remote_path_suffix=$3 if [[ "$remote_path" != 'http'* ]]; then cp "$remote_path" "$local_path" @@ -106,14 +109,14 @@ __get_remote_file() { local failed=false if __machine_has wget; then - wget --tries 10 --quiet -O "$local_path" "$remote_path" || failed=true + wget --tries 10 --quiet -O "$local_path" "${remote_path}${remote_path_suffix}" || failed=true else failed=true fi if [ "$failed" = true ] && __machine_has curl; then failed=false - curl --retry 10 -sSL -f --create-dirs -o "$local_path" "$remote_path" || failed=true + curl --retry 10 -sSL -f --create-dirs -o "$local_path" "${remote_path}${remote_path_suffix}" || failed=true fi if [ "$failed" = true ]; then @@ -164,6 +167,11 @@ while [[ $# -gt 0 ]]; do tools_source="${1:-}" [ -z "$tools_source" ] && __usage ;; + --tools-source-suffix|-ToolsSourceSuffix) + shift + tools_source_suffix="${1:-}" + [ -z "$tools_source_suffix" ] && __usage + ;; -u|--update|-Update) update=true ;; From 3488c24804384d4050db0bec2f7641c4ad833840 Mon Sep 17 00:00:00 2001 From: "ASP.NET CI" Date: Sun, 10 Dec 2017 12:10:38 -0800 Subject: [PATCH 248/307] Update dependencies.props [auto-updated: dependencies] --- build/dependencies.props | 38 +++++++++++++++++++------------------- korebuild-lock.txt | 4 ++-- 2 files changed, 21 insertions(+), 21 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index 0e232a77d6..581df37b75 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -3,28 +3,28 @@ $(MSBuildAllProjects);$(MSBuildThisFileFullPath) - 2.1.0-preview1-15576 - 2.1.0-preview1-27644 - 2.1.0-preview1-27644 - 2.1.0-preview1-27644 - 2.1.0-preview1-27644 - 2.1.0-preview1-27644 - 2.1.0-preview1-27644 - 2.1.0-preview1-27644 - 2.1.0-preview1-27644 - 2.1.0-preview1-27644 - 2.1.0-preview1-27644 - 2.1.0-preview1-27644 - 2.1.0-preview1-27644 - 2.1.0-preview1-27644 + 2.1.0-preview1-15618 + 2.1.0-preview1-27773 + 2.1.0-preview1-27773 + 2.1.0-preview1-27773 + 2.1.0-preview1-27773 + 2.1.0-preview1-27773 + 2.1.0-preview1-27773 + 2.1.0-preview1-27773 + 2.1.0-preview1-27773 + 2.1.0-preview1-27773 + 2.1.0-preview1-27773 + 2.1.0-preview1-27773 + 2.1.0-preview1-27773 + 2.1.0-preview1-27773 2.0.0 - 2.1.0-preview1-25907-02 - 2.1.0-preview1-27644 + 2.1.0-preview1-25915-01 + 2.1.0-preview1-27773 15.3.0 4.7.49 - 0.7.0 - 2.3.0 - 2.3.0 + 0.8.0 + 2.3.1 + 2.3.1 diff --git a/korebuild-lock.txt b/korebuild-lock.txt index 1a99066b7c..e7cce93009 100644 --- a/korebuild-lock.txt +++ b/korebuild-lock.txt @@ -1,2 +1,2 @@ -version:2.1.0-preview1-15576 -commithash:2f3856d2ba4f659fcb9253215b83946a06794a27 +version:2.1.0-preview1-15618 +commithash:00ce1383114015fe89b221146036e59e6bc11219 From 892cebb27eb1487a10e07d70967e490ecb38bce8 Mon Sep 17 00:00:00 2001 From: Justin Kotalik Date: Tue, 12 Dec 2017 14:12:26 -0800 Subject: [PATCH 249/307] Exclude setting HSTS on localhost and allow for user to specify excluded domains. (#274) --- BasicMiddleware.sln | 2 +- .../HstsMiddleware.cs | 33 ++++-- .../HstsOptions.cs | 11 ++ .../HstsMiddlewareTests.cs | 100 +++++++++++++++++- .../HttpsPolicyTests.cs | 1 + .../HttpsRedirectionMiddlewareTests.cs | 0 ...rosoft.AspNetCore.HttpsPolicy.Tests.csproj | 0 7 files changed, 134 insertions(+), 13 deletions(-) rename test/{Microsoft.AspNetCore.HttpsEnforcement.Tests => Microsoft.AspNetCore.HttpsPolicy.Tests}/HstsMiddlewareTests.cs (57%) rename test/{Microsoft.AspNetCore.HttpsEnforcement.Tests => Microsoft.AspNetCore.HttpsPolicy.Tests}/HttpsPolicyTests.cs (97%) rename test/{Microsoft.AspNetCore.HttpsEnforcement.Tests => Microsoft.AspNetCore.HttpsPolicy.Tests}/HttpsRedirectionMiddlewareTests.cs (100%) rename test/{Microsoft.AspNetCore.HttpsEnforcement.Tests => Microsoft.AspNetCore.HttpsPolicy.Tests}/Microsoft.AspNetCore.HttpsPolicy.Tests.csproj (100%) diff --git a/BasicMiddleware.sln b/BasicMiddleware.sln index c123191126..a4452cd103 100644 --- a/BasicMiddleware.sln +++ b/BasicMiddleware.sln @@ -61,7 +61,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.HttpsP EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "HttpsPolicySample", "samples\HttpsPolicySample\HttpsPolicySample.csproj", "{AC424AEE-4883-49C6-945F-2FC916B8CA1C}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.HttpsPolicy.Tests", "test\Microsoft.AspNetCore.HttpsEnforcement.Tests\Microsoft.AspNetCore.HttpsPolicy.Tests.csproj", "{1C67B0F1-6E70-449E-A2F1-98B9D5C576CE}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.HttpsPolicy.Tests", "test\Microsoft.AspNetCore.HttpsPolicy.Tests\Microsoft.AspNetCore.HttpsPolicy.Tests.csproj", "{1C67B0F1-6E70-449E-A2F1-98B9D5C576CE}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution diff --git a/src/Microsoft.AspNetCore.HttpsPolicy/HstsMiddleware.cs b/src/Microsoft.AspNetCore.HttpsPolicy/HstsMiddleware.cs index f67543c880..252ae44c1e 100644 --- a/src/Microsoft.AspNetCore.HttpsPolicy/HstsMiddleware.cs +++ b/src/Microsoft.AspNetCore.HttpsPolicy/HstsMiddleware.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; +using System.Collections.Generic; using System.Globalization; using System.Threading.Tasks; using Microsoft.AspNetCore.Http; @@ -22,6 +23,7 @@ namespace Microsoft.AspNetCore.HttpsPolicy private readonly RequestDelegate _next; private readonly StringValues _strictTransportSecurityValue; + private readonly IList _excludedHosts; /// /// Initialize the HSTS middleware. @@ -30,24 +32,20 @@ namespace Microsoft.AspNetCore.HttpsPolicy /// public HstsMiddleware(RequestDelegate next, IOptions options) { - if (next == null) - { - throw new ArgumentNullException(nameof(next)); - } - if (options == null) { throw new ArgumentNullException(nameof(options)); } - _next = next; + _next = next ?? throw new ArgumentNullException(nameof(next)); var hstsOptions = options.Value; var maxAge = Convert.ToInt64(Math.Floor(hstsOptions.MaxAge.TotalSeconds)) - .ToString(CultureInfo.InvariantCulture); + .ToString(CultureInfo.InvariantCulture); var includeSubdomains = hstsOptions.IncludeSubDomains ? IncludeSubDomains : StringSegment.Empty; var preload = hstsOptions.Preload ? Preload : StringSegment.Empty; _strictTransportSecurityValue = new StringValues($"max-age={maxAge}{includeSubdomains}{preload}"); + _excludedHosts = hstsOptions.ExcludedHosts; } /// @@ -57,12 +55,29 @@ namespace Microsoft.AspNetCore.HttpsPolicy /// public Task Invoke(HttpContext context) { - if (context.Request.IsHttps) + if (context.Request.IsHttps && !IsHostExcluded(context.Request.Host.Host)) { context.Response.Headers[HeaderNames.StrictTransportSecurity] = _strictTransportSecurityValue; } - return _next(context); + return _next(context); + } + + private bool IsHostExcluded(string host) + { + if (_excludedHosts == null) + { + return false; + } + + for (var i = 0; i < _excludedHosts.Count; i++) + { + if (string.Equals(host, _excludedHosts[i], StringComparison.OrdinalIgnoreCase)) + { + return true; + } + } + return false; } } } diff --git a/src/Microsoft.AspNetCore.HttpsPolicy/HstsOptions.cs b/src/Microsoft.AspNetCore.HttpsPolicy/HstsOptions.cs index 77d1d76254..92803963eb 100644 --- a/src/Microsoft.AspNetCore.HttpsPolicy/HstsOptions.cs +++ b/src/Microsoft.AspNetCore.HttpsPolicy/HstsOptions.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; +using System.Collections.Generic; namespace Microsoft.AspNetCore.HttpsPolicy { @@ -35,5 +36,15 @@ namespace Microsoft.AspNetCore.HttpsPolicy /// to preload HSTS sites on fresh install. See https://hstspreload.org/. /// public bool Preload { get; set; } + + /// + /// A list of host names that will not add the HSTS header. + /// + public IList ExcludedHosts { get; } = new List + { + "localhost", + "127.0.0.1", // ipv4 + "[::1]" // ipv6 + }; } } diff --git a/test/Microsoft.AspNetCore.HttpsEnforcement.Tests/HstsMiddlewareTests.cs b/test/Microsoft.AspNetCore.HttpsPolicy.Tests/HstsMiddlewareTests.cs similarity index 57% rename from test/Microsoft.AspNetCore.HttpsEnforcement.Tests/HstsMiddlewareTests.cs rename to test/Microsoft.AspNetCore.HttpsPolicy.Tests/HstsMiddlewareTests.cs index 64917f3e74..08df78f7c2 100644 --- a/test/Microsoft.AspNetCore.HttpsEnforcement.Tests/HstsMiddlewareTests.cs +++ b/test/Microsoft.AspNetCore.HttpsPolicy.Tests/HstsMiddlewareTests.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; +using System.Collections.Generic; using System.Linq; using System.Net; using System.Net.Http; @@ -36,7 +37,7 @@ namespace Microsoft.AspNetCore.HttpsPolicy.Tests var server = new TestServer(builder); var client = server.CreateClient(); - client.BaseAddress = new Uri("https://localhost:5050"); + client.BaseAddress = new Uri("https://example.com:5050"); var request = new HttpRequestMessage(HttpMethod.Get, ""); @@ -75,7 +76,7 @@ namespace Microsoft.AspNetCore.HttpsPolicy.Tests var server = new TestServer(builder); var client = server.CreateClient(); - client.BaseAddress = new Uri("https://localhost:5050"); + client.BaseAddress = new Uri("https://example.com:5050"); var request = new HttpRequestMessage(HttpMethod.Get, ""); var response = await client.SendAsync(request); @@ -113,7 +114,7 @@ namespace Microsoft.AspNetCore.HttpsPolicy.Tests var server = new TestServer(builder); var client = server.CreateClient(); - client.BaseAddress = new Uri("https://localhost:5050"); + client.BaseAddress = new Uri("https://example.com:5050"); var request = new HttpRequestMessage(HttpMethod.Get, ""); var response = await client.SendAsync(request); @@ -121,5 +122,98 @@ namespace Microsoft.AspNetCore.HttpsPolicy.Tests Assert.Equal(HttpStatusCode.OK, response.StatusCode); Assert.Equal(expected, response.Headers.GetValues(HeaderNames.StrictTransportSecurity).FirstOrDefault()); } + + [Theory] + [InlineData("localhost")] + [InlineData("Localhost")] + [InlineData("LOCALHOST")] + [InlineData("127.0.0.1")] + [InlineData("[::1]")] + public async Task DefaultExcludesCommonLocalhostDomains_DoesNotSetHstsHeader(string host) + { + var builder = new WebHostBuilder() + .Configure(app => + { + app.UseHsts(); + app.Run(context => + { + return context.Response.WriteAsync("Hello world"); + }); + }); + var server = new TestServer(builder); + var client = server.CreateClient(); + client.BaseAddress = new Uri($"https://{host}:5050"); + var request = new HttpRequestMessage(HttpMethod.Get, ""); + + var response = await client.SendAsync(request); + + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + Assert.Empty(response.Headers); + } + + [Theory] + [InlineData("localhost")] + [InlineData("127.0.0.1")] + [InlineData("[::1]")] + public async Task AllowLocalhostDomainsIfListIsReset_SetHstsHeader(string host) + { + var builder = new WebHostBuilder() + .ConfigureServices(services => + { + services.AddHsts(options => + { + options.ExcludedHosts.Clear(); + }); + }) + .Configure(app => + { + app.UseHsts(); + app.Run(context => + { + return context.Response.WriteAsync("Hello world"); + }); + }); + var server = new TestServer(builder); + var client = server.CreateClient(); + client.BaseAddress = new Uri($"https://{host}:5050"); + var request = new HttpRequestMessage(HttpMethod.Get, ""); + + var response = await client.SendAsync(request); + + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + Assert.Single(response.Headers); + } + + [Theory] + [InlineData("example.com")] + [InlineData("Example.com")] + [InlineData("EXAMPLE.COM")] + public async Task AddExcludedDomains_DoesNotAddHstsHeader(string host) + { + var builder = new WebHostBuilder() + .ConfigureServices(services => + { + services.AddHsts(options => { + options.ExcludedHosts.Add(host); + }); + }) + .Configure(app => + { + app.UseHsts(); + app.Run(context => + { + return context.Response.WriteAsync("Hello world"); + }); + }); + var server = new TestServer(builder); + var client = server.CreateClient(); + client.BaseAddress = new Uri($"https://{host}:5050"); + var request = new HttpRequestMessage(HttpMethod.Get, ""); + + var response = await client.SendAsync(request); + + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + Assert.Empty(response.Headers); + } } } diff --git a/test/Microsoft.AspNetCore.HttpsEnforcement.Tests/HttpsPolicyTests.cs b/test/Microsoft.AspNetCore.HttpsPolicy.Tests/HttpsPolicyTests.cs similarity index 97% rename from test/Microsoft.AspNetCore.HttpsEnforcement.Tests/HttpsPolicyTests.cs rename to test/Microsoft.AspNetCore.HttpsPolicy.Tests/HttpsPolicyTests.cs index 53fd91dde5..49a3d0a29a 100644 --- a/test/Microsoft.AspNetCore.HttpsEnforcement.Tests/HttpsPolicyTests.cs +++ b/test/Microsoft.AspNetCore.HttpsPolicy.Tests/HttpsPolicyTests.cs @@ -42,6 +42,7 @@ namespace Microsoft.AspNetCore.HttpsPolicy.Tests options.IncludeSubDomains = includeSubDomains; options.MaxAge = TimeSpan.FromSeconds(maxAge); options.Preload = preload; + options.ExcludedHosts.Clear(); // allowing localhost for testing }); }) .Configure(app => diff --git a/test/Microsoft.AspNetCore.HttpsEnforcement.Tests/HttpsRedirectionMiddlewareTests.cs b/test/Microsoft.AspNetCore.HttpsPolicy.Tests/HttpsRedirectionMiddlewareTests.cs similarity index 100% rename from test/Microsoft.AspNetCore.HttpsEnforcement.Tests/HttpsRedirectionMiddlewareTests.cs rename to test/Microsoft.AspNetCore.HttpsPolicy.Tests/HttpsRedirectionMiddlewareTests.cs diff --git a/test/Microsoft.AspNetCore.HttpsEnforcement.Tests/Microsoft.AspNetCore.HttpsPolicy.Tests.csproj b/test/Microsoft.AspNetCore.HttpsPolicy.Tests/Microsoft.AspNetCore.HttpsPolicy.Tests.csproj similarity index 100% rename from test/Microsoft.AspNetCore.HttpsEnforcement.Tests/Microsoft.AspNetCore.HttpsPolicy.Tests.csproj rename to test/Microsoft.AspNetCore.HttpsPolicy.Tests/Microsoft.AspNetCore.HttpsPolicy.Tests.csproj From 0fd9eb4b2f8273a935086d609873fc9df23d2713 Mon Sep 17 00:00:00 2001 From: "ASP.NET CI" Date: Wed, 13 Dec 2017 20:16:16 +0000 Subject: [PATCH 250/307] Update dependencies.props [auto-updated: dependencies] --- build/dependencies.props | 32 ++++++++++++++++---------------- korebuild-lock.txt | 4 ++-- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index 581df37b75..bff8fb947b 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -3,23 +3,23 @@ $(MSBuildAllProjects);$(MSBuildThisFileFullPath) - 2.1.0-preview1-15618 - 2.1.0-preview1-27773 - 2.1.0-preview1-27773 - 2.1.0-preview1-27773 - 2.1.0-preview1-27773 - 2.1.0-preview1-27773 - 2.1.0-preview1-27773 - 2.1.0-preview1-27773 - 2.1.0-preview1-27773 - 2.1.0-preview1-27773 - 2.1.0-preview1-27773 - 2.1.0-preview1-27773 - 2.1.0-preview1-27773 - 2.1.0-preview1-27773 + 2.1.0-preview1-15626 + 2.1.0-preview1-27807 + 2.1.0-preview1-27807 + 2.1.0-preview1-27807 + 2.1.0-preview1-27807 + 2.1.0-preview1-27807 + 2.1.0-preview1-27807 + 2.1.0-preview1-27807 + 2.1.0-preview1-27807 + 2.1.0-preview1-27807 + 2.1.0-preview1-27807 + 2.1.0-preview1-27807 + 2.1.0-preview1-27807 + 2.1.0-preview1-27807 2.0.0 - 2.1.0-preview1-25915-01 - 2.1.0-preview1-27773 + 2.1.0-preview1-26008-01 + 2.1.0-preview1-27807 15.3.0 4.7.49 0.8.0 diff --git a/korebuild-lock.txt b/korebuild-lock.txt index e7cce93009..8d52a6128c 100644 --- a/korebuild-lock.txt +++ b/korebuild-lock.txt @@ -1,2 +1,2 @@ -version:2.1.0-preview1-15618 -commithash:00ce1383114015fe89b221146036e59e6bc11219 +version:2.1.0-preview1-15626 +commithash:fd6410e9c90c428bc01238372303ad09cb9ec889 From 414430635913b568b7fb5c97f0b6b110e1a47dd6 Mon Sep 17 00:00:00 2001 From: "ASP.NET CI" Date: Mon, 18 Dec 2017 16:29:46 -0800 Subject: [PATCH 251/307] Update dependencies.props [auto-updated: dependencies] --- build/dependencies.props | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index bff8fb947b..229023f5d0 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -4,22 +4,22 @@ 2.1.0-preview1-15626 - 2.1.0-preview1-27807 - 2.1.0-preview1-27807 - 2.1.0-preview1-27807 - 2.1.0-preview1-27807 - 2.1.0-preview1-27807 - 2.1.0-preview1-27807 - 2.1.0-preview1-27807 - 2.1.0-preview1-27807 - 2.1.0-preview1-27807 - 2.1.0-preview1-27807 - 2.1.0-preview1-27807 - 2.1.0-preview1-27807 - 2.1.0-preview1-27807 + 2.1.0-preview1-27849 + 2.1.0-preview1-27849 + 2.1.0-preview1-27849 + 2.1.0-preview1-27849 + 2.1.0-preview1-27849 + 2.1.0-preview1-27849 + 2.1.0-preview1-27849 + 2.1.0-preview1-27849 + 2.1.0-preview1-27849 + 2.1.0-preview1-27849 + 2.1.0-preview1-27849 + 2.1.0-preview1-27849 + 2.1.0-preview1-27849 2.0.0 - 2.1.0-preview1-26008-01 - 2.1.0-preview1-27807 + 2.1.0-preview1-26016-05 + 2.1.0-preview1-27849 15.3.0 4.7.49 0.8.0 From fd4cd6f58b2412d4ca6e264803356af5fc474e5a Mon Sep 17 00:00:00 2001 From: Justin Kotalik Date: Tue, 19 Dec 2017 22:44:24 -0800 Subject: [PATCH 252/307] Read from IServerAddressesFeature for HTTPS port (#276) --- build/dependencies.props | 32 ++-- korebuild-lock.txt | 4 +- .../HttpsRedirectionBuilderExtensions.cs | 24 +-- .../HttpsRedirectionMiddleware.cs | 124 +++++++++++++++ .../HttpsRedirectionOptions.cs | 7 +- .../Microsoft.AspNetCore.HttpsPolicy.csproj | 6 +- .../HttpsPolicyTests.cs | 6 +- .../HttpsRedirectionMiddlewareTests.cs | 145 ++++++++++++++++-- 8 files changed, 294 insertions(+), 54 deletions(-) create mode 100644 src/Microsoft.AspNetCore.HttpsPolicy/HttpsRedirectionMiddleware.cs diff --git a/build/dependencies.props b/build/dependencies.props index 229023f5d0..853f6f2f0e 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -3,23 +3,25 @@ $(MSBuildAllProjects);$(MSBuildThisFileFullPath) - 2.1.0-preview1-15626 - 2.1.0-preview1-27849 - 2.1.0-preview1-27849 - 2.1.0-preview1-27849 - 2.1.0-preview1-27849 - 2.1.0-preview1-27849 - 2.1.0-preview1-27849 - 2.1.0-preview1-27849 - 2.1.0-preview1-27849 - 2.1.0-preview1-27849 - 2.1.0-preview1-27849 - 2.1.0-preview1-27849 - 2.1.0-preview1-27849 - 2.1.0-preview1-27849 + 2.1.0-preview1-15638 + 2.1.0-preview1-27855 + 2.1.0-preview1-27855 + 2.1.0-preview1-27855 + 2.1.0-preview1-27855 + 2.1.0-preview1-27855 + 2.1.0-preview1-27855 + 2.1.0-preview1-27855 + 2.1.0-preview1-27855 + 2.1.0-preview1-27855 + 2.1.0-preview1-27855 + 2.1.0-preview1-27855 + 2.1.0-preview1-27855 + 2.1.0-preview1-27855 + 2.1.0-preview1-27855 + 2.1.0-preview1-27855 2.0.0 2.1.0-preview1-26016-05 - 2.1.0-preview1-27849 + 2.1.0-preview1-27855 15.3.0 4.7.49 0.8.0 diff --git a/korebuild-lock.txt b/korebuild-lock.txt index 8d52a6128c..2e540bdffd 100644 --- a/korebuild-lock.txt +++ b/korebuild-lock.txt @@ -1,2 +1,2 @@ -version:2.1.0-preview1-15626 -commithash:fd6410e9c90c428bc01238372303ad09cb9ec889 +version:2.1.0-preview1-15638 +commithash:1d3a0c725dc6b8ae6b0e47800fd6b4d8f8b8d545 diff --git a/src/Microsoft.AspNetCore.HttpsPolicy/HttpsRedirectionBuilderExtensions.cs b/src/Microsoft.AspNetCore.HttpsPolicy/HttpsRedirectionBuilderExtensions.cs index d6b827caab..600e29fead 100644 --- a/src/Microsoft.AspNetCore.HttpsPolicy/HttpsRedirectionBuilderExtensions.cs +++ b/src/Microsoft.AspNetCore.HttpsPolicy/HttpsRedirectionBuilderExtensions.cs @@ -2,8 +2,8 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; +using Microsoft.AspNetCore.Hosting.Server.Features; using Microsoft.AspNetCore.HttpsPolicy; -using Microsoft.AspNetCore.Rewrite; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Options; @@ -32,27 +32,7 @@ namespace Microsoft.AspNetCore.Builder var options = app.ApplicationServices.GetRequiredService>().Value; - // The tls port set in options will have priority over the one in configuration. - var httpsPort = options.HttpsPort; - if (httpsPort == null) - { - // Only read configuration if there is no httpsPort - var config = app.ApplicationServices.GetRequiredService(); - var configHttpsPort = config["HTTPS_PORT"]; - // If the string isn't empty, try to parse it. - if (!string.IsNullOrEmpty(configHttpsPort) - && int.TryParse(configHttpsPort, out var intHttpsPort)) - { - httpsPort = intHttpsPort; - } - } - - var rewriteOptions = new RewriteOptions(); - rewriteOptions.AddRedirectToHttps( - options.RedirectStatusCode, - httpsPort); - - app.UseRewriter(rewriteOptions); + app.UseMiddleware(app.ServerFeatures.Get()); return app; } diff --git a/src/Microsoft.AspNetCore.HttpsPolicy/HttpsRedirectionMiddleware.cs b/src/Microsoft.AspNetCore.HttpsPolicy/HttpsRedirectionMiddleware.cs new file mode 100644 index 0000000000..f500bbb2bc --- /dev/null +++ b/src/Microsoft.AspNetCore.HttpsPolicy/HttpsRedirectionMiddleware.cs @@ -0,0 +1,124 @@ +// 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; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Hosting.Server.Features; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Http.Extensions; +using Microsoft.AspNetCore.Http.Internal; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Options; +using Microsoft.Net.Http.Headers; + +namespace Microsoft.AspNetCore.HttpsPolicy +{ + public class HttpsRedirectionMiddleware + { + private readonly RequestDelegate _next; + private int? _httpsPort; + private readonly int _statusCode; + + private readonly IServerAddressesFeature _serverAddressesFeature; + private readonly IConfiguration _config; + + /// + /// Initializes the HttpsRedirectionMiddleware + /// + /// + /// The + /// + /// + public HttpsRedirectionMiddleware(RequestDelegate next, IServerAddressesFeature serverAddressesFeature, IOptions options, IConfiguration config) + { + if (options == null) + { + throw new ArgumentNullException(nameof(options)); + } + _config = config ?? throw new ArgumentException(nameof(config)); + _next = next ?? throw new ArgumentNullException(nameof(next)); + _serverAddressesFeature = serverAddressesFeature ?? throw new ArgumentNullException(nameof(serverAddressesFeature)); + + var httpsRedirectionOptions = options.Value; + _httpsPort = httpsRedirectionOptions.HttpsPort; + _statusCode = httpsRedirectionOptions.RedirectStatusCode; + } + + /// + /// Invokes the HttpsRedirectionMiddleware + /// + /// + /// + public Task Invoke(HttpContext context) + { + if (context.Request.IsHttps) + { + return _next(context); + } + + if (!_httpsPort.HasValue) + { + CheckForHttpsPorts(); + } + + var host = context.Request.Host; + if (_httpsPort != 443) + { + host = new HostString(host.Host, _httpsPort.Value); + } + else + { + host = new HostString(host.Host); + } + + var request = context.Request; + var redirectUrl = UriHelper.BuildAbsolute( + "https", + host, + request.PathBase, + request.Path, + request.QueryString); + + context.Response.StatusCode = _statusCode; + context.Response.Headers[HeaderNames.Location] = redirectUrl; + + return Task.CompletedTask; + } + + private void CheckForHttpsPorts() + { + // The IServerAddressesFeature will not be ready until the middleware is Invoked, + // Order for finding the HTTPS port: + // 1. Set in the HttpsRedirectionOptions + // 2. HTTPS_PORT environment variable + // 3. IServerAddressesFeature + // 4. 443 (or not set) + + _httpsPort = _config.GetValue("HTTPS_PORT"); + if (_httpsPort.HasValue) + { + return; + } + + int? httpsPort = null; + foreach (var address in _serverAddressesFeature.Addresses) + { + var bindingAddress = BindingAddress.Parse(address); + if (bindingAddress.Scheme.Equals("https", StringComparison.OrdinalIgnoreCase)) + { + // If we find multiple different https ports specified, throw + if (httpsPort.HasValue && httpsPort != bindingAddress.Port) + { + throw new ArgumentException("Cannot determine the https port from IServerAddressesFeature, multiple values were found. " + + "Please set the desired port explicitly on HttpsRedirectionOptions.HttpsPort."); + } + else + { + httpsPort = bindingAddress.Port; + } + } + } + _httpsPort = httpsPort ?? 443; + } + } +} diff --git a/src/Microsoft.AspNetCore.HttpsPolicy/HttpsRedirectionOptions.cs b/src/Microsoft.AspNetCore.HttpsPolicy/HttpsRedirectionOptions.cs index 238f2eb484..52f2b09def 100644 --- a/src/Microsoft.AspNetCore.HttpsPolicy/HttpsRedirectionOptions.cs +++ b/src/Microsoft.AspNetCore.HttpsPolicy/HttpsRedirectionOptions.cs @@ -16,10 +16,13 @@ namespace Microsoft.AspNetCore.HttpsPolicy public int RedirectStatusCode { get; set; } = StatusCodes.Status302Found; /// - /// The TLS port to be added to the redirected URL. + /// The HTTPS port to be added to the redirected URL. /// /// - /// Defaults to 443 if not provided. + /// If the HttpsPort is not set, we will try to get the HttpsPort from the following: + /// 1. HTTPS_PORT environment variable + /// 2. IServerAddressesFeature + /// 3. 443 (or not set) /// public int? HttpsPort { get; set; } } diff --git a/src/Microsoft.AspNetCore.HttpsPolicy/Microsoft.AspNetCore.HttpsPolicy.csproj b/src/Microsoft.AspNetCore.HttpsPolicy/Microsoft.AspNetCore.HttpsPolicy.csproj index b68d33b7dc..ee7e611a47 100644 --- a/src/Microsoft.AspNetCore.HttpsPolicy/Microsoft.AspNetCore.HttpsPolicy.csproj +++ b/src/Microsoft.AspNetCore.HttpsPolicy/Microsoft.AspNetCore.HttpsPolicy.csproj @@ -11,6 +11,10 @@ - + + + + + diff --git a/test/Microsoft.AspNetCore.HttpsPolicy.Tests/HttpsPolicyTests.cs b/test/Microsoft.AspNetCore.HttpsPolicy.Tests/HttpsPolicyTests.cs index 49a3d0a29a..aa874fb8cd 100644 --- a/test/Microsoft.AspNetCore.HttpsPolicy.Tests/HttpsPolicyTests.cs +++ b/test/Microsoft.AspNetCore.HttpsPolicy.Tests/HttpsPolicyTests.cs @@ -8,7 +8,9 @@ using System.Net.Http; using System.Threading.Tasks; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Hosting.Server.Features; using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Http.Features; using Microsoft.AspNetCore.TestHost; using Microsoft.Extensions.DependencyInjection; using Microsoft.Net.Http.Headers; @@ -55,7 +57,9 @@ namespace Microsoft.AspNetCore.HttpsPolicy.Tests }); }); - var server = new TestServer(builder); + var featureCollection = new FeatureCollection(); + featureCollection.Set(new ServerAddressesFeature()); + var server = new TestServer(builder, featureCollection); var client = server.CreateClient(); var request = new HttpRequestMessage(HttpMethod.Get, ""); diff --git a/test/Microsoft.AspNetCore.HttpsPolicy.Tests/HttpsRedirectionMiddlewareTests.cs b/test/Microsoft.AspNetCore.HttpsPolicy.Tests/HttpsRedirectionMiddlewareTests.cs index aabba1324e..14f7c5444f 100644 --- a/test/Microsoft.AspNetCore.HttpsPolicy.Tests/HttpsRedirectionMiddlewareTests.cs +++ b/test/Microsoft.AspNetCore.HttpsPolicy.Tests/HttpsRedirectionMiddlewareTests.cs @@ -8,7 +8,9 @@ using System.Net.Http; using System.Threading.Tasks; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Hosting.Server.Features; using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Http.Features; using Microsoft.AspNetCore.TestHost; using Microsoft.Extensions.DependencyInjection; using Microsoft.Net.Http.Headers; @@ -34,7 +36,9 @@ namespace Microsoft.AspNetCore.HttpsPolicy.Tests }); }); - var server = new TestServer(builder); + var featureCollection = new FeatureCollection(); + featureCollection.Set(new ServerAddressesFeature()); + var server = new TestServer(builder, featureCollection); var client = server.CreateClient(); var request = new HttpRequestMessage(HttpMethod.Get, ""); @@ -73,7 +77,9 @@ namespace Microsoft.AspNetCore.HttpsPolicy.Tests }); }); - var server = new TestServer(builder); + var featureCollection = new FeatureCollection(); + featureCollection.Set(new ServerAddressesFeature()); + var server = new TestServer(builder, featureCollection); var client = server.CreateClient(); var request = new HttpRequestMessage(HttpMethod.Get, ""); @@ -111,7 +117,9 @@ namespace Microsoft.AspNetCore.HttpsPolicy.Tests }); }); - var server = new TestServer(builder); + var featureCollection = new FeatureCollection(); + featureCollection.Set(new ServerAddressesFeature()); + var server = new TestServer(builder, featureCollection); var client = server.CreateClient(); var request = new HttpRequestMessage(HttpMethod.Get, ""); @@ -123,13 +131,17 @@ namespace Microsoft.AspNetCore.HttpsPolicy.Tests } [Theory] - [InlineData(null, null, "https://localhost/")] - [InlineData(null, "5000", "https://localhost:5000/")] - [InlineData(null, "443", "https://localhost/")] - [InlineData(443, "5000", "https://localhost/")] - [InlineData(4000, "5000", "https://localhost:4000/")] - [InlineData(5000, null, "https://localhost:5000/")] - public async Task SetHttpsPortEnvironmentVariable_ReturnsCorrectStatusCodeOnResponse(int? optionsHttpsPort, string configHttpsPort, string expectedUrl) + [InlineData(null, null, null, "https://localhost/")] + [InlineData(null, null, "https://localhost:4444/", "https://localhost:4444/")] + [InlineData(null, null, "https://localhost:443/", "https://localhost/")] + [InlineData(null, null, "http://localhost:5044/", "https://localhost/")] + [InlineData(null, null, "https://localhost/", "https://localhost/")] + [InlineData(null, "5000", "https://localhost:4444/", "https://localhost:5000/")] + [InlineData(null, "443", "https://localhost:4444/", "https://localhost/")] + [InlineData(443, "5000", "https://localhost:4444/", "https://localhost/")] + [InlineData(4000, "5000", "https://localhost:4444/", "https://localhost:4000/")] + [InlineData(5000, null, "https://localhost:4444/", "https://localhost:5000/")] + public async Task SetHttpsPortEnvironmentVariableAndServerFeature_ReturnsCorrectStatusCodeOnResponse(int? optionsHttpsPort, string configHttpsPort, string serverAddressFeatureUrl, string expectedUrl) { var builder = new WebHostBuilder() .ConfigureServices(services => @@ -147,8 +159,18 @@ namespace Microsoft.AspNetCore.HttpsPolicy.Tests return context.Response.WriteAsync("Hello world"); }); }); + builder.UseSetting("HTTPS_PORT", configHttpsPort); - var server = new TestServer(builder); + + var featureCollection = new FeatureCollection(); + featureCollection.Set(new ServerAddressesFeature()); + + var server = new TestServer(builder, featureCollection); + if (serverAddressFeatureUrl != null) + { + server.Features.Get().Addresses.Add(serverAddressFeatureUrl); + } + var client = server.CreateClient(); var request = new HttpRequestMessage(HttpMethod.Get, ""); @@ -157,5 +179,106 @@ namespace Microsoft.AspNetCore.HttpsPolicy.Tests Assert.Equal(expectedUrl, response.Headers.Location.ToString()); } + + [Fact] + public async Task SetServerAddressesFeature_SingleHttpsAddress_Success() + { + var builder = new WebHostBuilder() + .ConfigureServices(services => + { + services.AddHttpsRedirection(options => + { + }); + }) + .Configure(app => + { + app.UseHttpsRedirection(); + app.Run(context => + { + return context.Response.WriteAsync("Hello world"); + }); + }); + + var featureCollection = new FeatureCollection(); + featureCollection.Set(new ServerAddressesFeature()); + var server = new TestServer(builder, featureCollection); + + server.Features.Get().Addresses.Add("https://localhost:5050"); + var client = server.CreateClient(); + + var request = new HttpRequestMessage(HttpMethod.Get, ""); + + var response = await client.SendAsync(request); + + Assert.Equal("https://localhost:5050/", response.Headers.Location.ToString()); + } + + [Fact] + public async Task SetServerAddressesFeature_MultipleHttpsAddresses_ThrowInMiddleware() + { + var builder = new WebHostBuilder() + .ConfigureServices(services => + { + services.AddHttpsRedirection(options => + { + }); + }) + .Configure(app => + { + app.UseHttpsRedirection(); + app.Run(context => + { + return context.Response.WriteAsync("Hello world"); + }); + }); + + var featureCollection = new FeatureCollection(); + featureCollection.Set(new ServerAddressesFeature()); + var server = new TestServer(builder, featureCollection); + + server.Features.Get().Addresses.Add("https://localhost:5050"); + server.Features.Get().Addresses.Add("https://localhost:5051"); + + var client = server.CreateClient(); + + var request = new HttpRequestMessage(HttpMethod.Get, ""); + + await Assert.ThrowsAsync(async () => await client.SendAsync(request)); + } + + [Fact] + public async Task SetServerAddressesFeature_MultipleHttpsAddressesWithSamePort_Success() + { + var builder = new WebHostBuilder() + .ConfigureServices(services => + { + services.AddHttpsRedirection(options => + { + }); + }) + .Configure(app => + { + app.UseHttpsRedirection(); + app.Run(context => + { + return context.Response.WriteAsync("Hello world"); + }); + }); + + var featureCollection = new FeatureCollection(); + featureCollection.Set(new ServerAddressesFeature()); + var server = new TestServer(builder, featureCollection); + + server.Features.Get().Addresses.Add("https://localhost:5050"); + server.Features.Get().Addresses.Add("https://localhost:5050"); + + var client = server.CreateClient(); + + var request = new HttpRequestMessage(HttpMethod.Get, ""); + + var response = await client.SendAsync(request); + + Assert.Equal("https://localhost:5050/", response.Headers.Location.ToString()); + } } } From 8f0cc61808e09d646ba6c32e8785a6cd8f56be29 Mon Sep 17 00:00:00 2001 From: "ASP.NET CI" Date: Sun, 31 Dec 2017 20:30:12 +0000 Subject: [PATCH 253/307] Update dependencies.props [auto-updated: dependencies] --- build/dependencies.props | 34 +++++++++++++++++----------------- korebuild-lock.txt | 4 ++-- 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index 853f6f2f0e..9ff27fb6ed 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -3,25 +3,25 @@ $(MSBuildAllProjects);$(MSBuildThisFileFullPath) - 2.1.0-preview1-15638 - 2.1.0-preview1-27855 - 2.1.0-preview1-27855 - 2.1.0-preview1-27855 - 2.1.0-preview1-27855 - 2.1.0-preview1-27855 - 2.1.0-preview1-27855 - 2.1.0-preview1-27855 - 2.1.0-preview1-27855 - 2.1.0-preview1-27855 - 2.1.0-preview1-27855 - 2.1.0-preview1-27855 - 2.1.0-preview1-27855 - 2.1.0-preview1-27855 - 2.1.0-preview1-27855 - 2.1.0-preview1-27855 + 2.1.0-preview1-15651 + 2.1.0-preview1-27942 + 2.1.0-preview1-27942 + 2.1.0-preview1-27942 + 2.1.0-preview1-27942 + 2.1.0-preview1-27942 + 2.1.0-preview1-27942 + 2.1.0-preview1-27942 + 2.1.0-preview1-27942 + 2.1.0-preview1-27942 + 2.1.0-preview1-27942 + 2.1.0-preview1-27942 + 2.1.0-preview1-27942 + 2.1.0-preview1-27942 + 2.1.0-preview1-27942 + 2.1.0-preview1-27942 2.0.0 2.1.0-preview1-26016-05 - 2.1.0-preview1-27855 + 2.1.0-preview1-27942 15.3.0 4.7.49 0.8.0 diff --git a/korebuild-lock.txt b/korebuild-lock.txt index 2e540bdffd..7c2e97aa79 100644 --- a/korebuild-lock.txt +++ b/korebuild-lock.txt @@ -1,2 +1,2 @@ -version:2.1.0-preview1-15638 -commithash:1d3a0c725dc6b8ae6b0e47800fd6b4d8f8b8d545 +version:2.1.0-preview1-15651 +commithash:ebf2365121c2c6a6a0fbfa9b0f37bb5effc89323 From d866293e9eb82e70f9947415b278f3cc8c71afdb Mon Sep 17 00:00:00 2001 From: Justin Kotalik Date: Wed, 3 Jan 2018 12:37:02 -0800 Subject: [PATCH 254/307] Increases timeout on Regex in Rewrite. (#280) --- .../Internal/ApacheModRewrite/RuleBuilder.cs | 10 +++++----- .../Internal/IISUrlRewrite/UriMatchCondition.cs | 9 +++++++-- .../Internal/IISUrlRewrite/UrlRewriteRuleBuilder.cs | 6 +++--- 3 files changed, 15 insertions(+), 10 deletions(-) diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/ApacheModRewrite/RuleBuilder.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/ApacheModRewrite/RuleBuilder.cs index 33473ddbf7..2dd1c58c9e 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/ApacheModRewrite/RuleBuilder.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/ApacheModRewrite/RuleBuilder.cs @@ -18,7 +18,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.ApacheModRewrite private UrlMatch _match; private CookieActionFactory _cookieActionFactory = new CookieActionFactory(); - private readonly TimeSpan RegexTimeout = TimeSpan.FromMilliseconds(1); + private readonly TimeSpan _regexTimeout = TimeSpan.FromSeconds(1); public ApacheModRewriteRule Build() { @@ -68,11 +68,11 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.ApacheModRewrite case ConditionType.Regex: if (flags.HasFlag(FlagType.NoCase)) { - condition.Match = new RegexMatch(new Regex(input.Operand, RegexOptions.CultureInvariant | RegexOptions.Compiled | RegexOptions.IgnoreCase, RegexTimeout), input.Invert); + condition.Match = new RegexMatch(new Regex(input.Operand, RegexOptions.CultureInvariant | RegexOptions.Compiled | RegexOptions.IgnoreCase, _regexTimeout), input.Invert); } else { - condition.Match = new RegexMatch(new Regex(input.Operand, RegexOptions.CultureInvariant | RegexOptions.Compiled, RegexTimeout), input.Invert); + condition.Match = new RegexMatch(new Regex(input.Operand, RegexOptions.CultureInvariant | RegexOptions.Compiled, _regexTimeout), input.Invert); } break; case ConditionType.IntComp: @@ -160,11 +160,11 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.ApacheModRewrite { if (flags.HasFlag(FlagType.NoCase)) { - _match = new RegexMatch(new Regex(input.Operand, RegexOptions.CultureInvariant | RegexOptions.Compiled | RegexOptions.IgnoreCase, RegexTimeout), input.Invert); + _match = new RegexMatch(new Regex(input.Operand, RegexOptions.CultureInvariant | RegexOptions.Compiled | RegexOptions.IgnoreCase, _regexTimeout), input.Invert); } else { - _match = new RegexMatch(new Regex(input.Operand, RegexOptions.CultureInvariant | RegexOptions.Compiled, RegexTimeout), input.Invert); + _match = new RegexMatch(new Regex(input.Operand, RegexOptions.CultureInvariant | RegexOptions.Compiled, _regexTimeout), input.Invert); } } diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/UriMatchCondition.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/UriMatchCondition.cs index 9f39d46670..c8378c6b77 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/UriMatchCondition.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/UriMatchCondition.cs @@ -9,12 +9,17 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite { public class UriMatchCondition : Condition { + private TimeSpan _regexTimeout = TimeSpan.FromSeconds(1); + public UriMatchCondition(InputParser inputParser, string input, string pattern, UriMatchPart uriMatchPart, bool ignoreCase, bool negate) { + var regexOptions = RegexOptions.CultureInvariant | RegexOptions.Compiled; + regexOptions = ignoreCase ? regexOptions | RegexOptions.IgnoreCase : regexOptions; var regex = new Regex( pattern, - ignoreCase ? RegexOptions.CultureInvariant | RegexOptions.Compiled | RegexOptions.IgnoreCase : RegexOptions.CultureInvariant | RegexOptions.Compiled, - TimeSpan.FromMilliseconds(1)); + regexOptions, + _regexTimeout + ); Input = inputParser.ParseInputString(input, uriMatchPart); Match = new RegexMatch(regex, negate); } diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/UrlRewriteRuleBuilder.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/UrlRewriteRuleBuilder.cs index ea855fb4a4..69ed962154 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/UrlRewriteRuleBuilder.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/UrlRewriteRuleBuilder.cs @@ -10,7 +10,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite { public class UrlRewriteRuleBuilder { - private readonly TimeSpan RegexTimeout = TimeSpan.FromMilliseconds(1); + private readonly TimeSpan _regexTimeout = TimeSpan.FromSeconds(1); public string Name { get; set; } public bool Enabled { get; set; } @@ -48,12 +48,12 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite { if (ignoreCase) { - var regex = new Regex(input, RegexOptions.CultureInvariant | RegexOptions.Compiled | RegexOptions.IgnoreCase, RegexTimeout); + var regex = new Regex(input, RegexOptions.CultureInvariant | RegexOptions.Compiled | RegexOptions.IgnoreCase, _regexTimeout); _initialMatch = new RegexMatch(regex, negate); } else { - var regex = new Regex(input, RegexOptions.CultureInvariant | RegexOptions.Compiled, RegexTimeout); + var regex = new Regex(input, RegexOptions.CultureInvariant | RegexOptions.Compiled, _regexTimeout); _initialMatch = new RegexMatch(regex, negate); } break; From b22f4b11b90f1fb1e9fbe11bdc78964c1420fc9d Mon Sep 17 00:00:00 2001 From: "ASP.NET CI" Date: Thu, 4 Jan 2018 00:36:28 +0000 Subject: [PATCH 255/307] Update dependencies.props [auto-updated: dependencies] --- build/dependencies.props | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index 9ff27fb6ed..49adf6aa26 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -4,24 +4,24 @@ 2.1.0-preview1-15651 - 2.1.0-preview1-27942 - 2.1.0-preview1-27942 - 2.1.0-preview1-27942 - 2.1.0-preview1-27942 - 2.1.0-preview1-27942 - 2.1.0-preview1-27942 - 2.1.0-preview1-27942 - 2.1.0-preview1-27942 - 2.1.0-preview1-27942 - 2.1.0-preview1-27942 - 2.1.0-preview1-27942 - 2.1.0-preview1-27942 - 2.1.0-preview1-27942 - 2.1.0-preview1-27942 - 2.1.0-preview1-27942 + 2.1.0-preview1-27965 + 2.1.0-preview1-27965 + 2.1.0-preview1-27965 + 2.1.0-preview1-27965 + 2.1.0-preview1-27965 + 2.1.0-preview1-27965 + 2.1.0-preview1-27965 + 2.1.0-preview1-27965 + 2.1.0-preview1-27965 + 2.1.0-preview1-27965 + 2.1.0-preview1-27965 + 2.1.0-preview1-27965 + 2.1.0-preview1-27965 + 2.1.0-preview1-27965 + 2.1.0-preview1-27965 2.0.0 2.1.0-preview1-26016-05 - 2.1.0-preview1-27942 + 2.1.0-preview1-27965 15.3.0 4.7.49 0.8.0 From 0cace7688d99e6e24593f41977e2529c10641fa5 Mon Sep 17 00:00:00 2001 From: "Chris Ross (ASP.NET)" Date: Wed, 3 Jan 2018 10:26:56 -0800 Subject: [PATCH 256/307] Https Redirect: Change default status code to 307. #210 --- .../HttpsRedirectionOptions.cs | 4 ++-- .../HttpsRedirectionMiddlewareTests.cs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Microsoft.AspNetCore.HttpsPolicy/HttpsRedirectionOptions.cs b/src/Microsoft.AspNetCore.HttpsPolicy/HttpsRedirectionOptions.cs index 52f2b09def..cc46b0155a 100644 --- a/src/Microsoft.AspNetCore.HttpsPolicy/HttpsRedirectionOptions.cs +++ b/src/Microsoft.AspNetCore.HttpsPolicy/HttpsRedirectionOptions.cs @@ -11,9 +11,9 @@ namespace Microsoft.AspNetCore.HttpsPolicy public class HttpsRedirectionOptions { /// - /// The status code to redirect the response to. + /// The status code used for the redirect response. The default is 307. /// - public int RedirectStatusCode { get; set; } = StatusCodes.Status302Found; + public int RedirectStatusCode { get; set; } = StatusCodes.Status307TemporaryRedirect; /// /// The HTTPS port to be added to the redirected URL. diff --git a/test/Microsoft.AspNetCore.HttpsPolicy.Tests/HttpsRedirectionMiddlewareTests.cs b/test/Microsoft.AspNetCore.HttpsPolicy.Tests/HttpsRedirectionMiddlewareTests.cs index 14f7c5444f..95888d614f 100644 --- a/test/Microsoft.AspNetCore.HttpsPolicy.Tests/HttpsRedirectionMiddlewareTests.cs +++ b/test/Microsoft.AspNetCore.HttpsPolicy.Tests/HttpsRedirectionMiddlewareTests.cs @@ -45,7 +45,7 @@ namespace Microsoft.AspNetCore.HttpsPolicy.Tests var response = await client.SendAsync(request); - Assert.Equal(HttpStatusCode.Found, response.StatusCode); + Assert.Equal(HttpStatusCode.RedirectKeepVerb, response.StatusCode); Assert.Equal("https://localhost/", response.Headers.Location.ToString()); } From 7db86f0591b594595116d40330a9b16e93f59f2c Mon Sep 17 00:00:00 2001 From: "ASP.NET CI" Date: Sat, 6 Jan 2018 14:06:58 -0800 Subject: [PATCH 257/307] Update dependencies.props [auto-updated: dependencies] --- korebuild-lock.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/korebuild-lock.txt b/korebuild-lock.txt index 7c2e97aa79..2146d006d7 100644 --- a/korebuild-lock.txt +++ b/korebuild-lock.txt @@ -1,2 +1,2 @@ -version:2.1.0-preview1-15651 -commithash:ebf2365121c2c6a6a0fbfa9b0f37bb5effc89323 +version:2.1.0-preview1-15661 +commithash:c9349d4c8a495d3085d9b879214d80f2f45e2193 From 726035e3fb8c4ee31a32522c16ff73278b9b13e7 Mon Sep 17 00:00:00 2001 From: Justin Kotalik Date: Fri, 12 Jan 2018 13:20:06 -0800 Subject: [PATCH 258/307] Allow null SeverAddressFeature in Redirection Middleware (#289) --- .../HttpsRedirectionBuilderExtensions.cs | 14 +++-- .../HttpsRedirectionMiddleware.cs | 32 +++++++--- .../HttpsRedirectionMiddlewareTests.cs | 59 ++++++++++++++++++- 3 files changed, 91 insertions(+), 14 deletions(-) diff --git a/src/Microsoft.AspNetCore.HttpsPolicy/HttpsRedirectionBuilderExtensions.cs b/src/Microsoft.AspNetCore.HttpsPolicy/HttpsRedirectionBuilderExtensions.cs index 600e29fead..429f0f0ee2 100644 --- a/src/Microsoft.AspNetCore.HttpsPolicy/HttpsRedirectionBuilderExtensions.cs +++ b/src/Microsoft.AspNetCore.HttpsPolicy/HttpsRedirectionBuilderExtensions.cs @@ -29,11 +29,15 @@ namespace Microsoft.AspNetCore.Builder { throw new ArgumentNullException(nameof(app)); } - - var options = app.ApplicationServices.GetRequiredService>().Value; - - app.UseMiddleware(app.ServerFeatures.Get()); - + var serverAddressFeature = app.ServerFeatures.Get(); + if (serverAddressFeature != null) + { + app.UseMiddleware(serverAddressFeature); + } + else + { + app.UseMiddleware(); + } return app; } } diff --git a/src/Microsoft.AspNetCore.HttpsPolicy/HttpsRedirectionMiddleware.cs b/src/Microsoft.AspNetCore.HttpsPolicy/HttpsRedirectionMiddleware.cs index f500bbb2bc..a4a9cc034d 100644 --- a/src/Microsoft.AspNetCore.HttpsPolicy/HttpsRedirectionMiddleware.cs +++ b/src/Microsoft.AspNetCore.HttpsPolicy/HttpsRedirectionMiddleware.cs @@ -26,24 +26,36 @@ namespace Microsoft.AspNetCore.HttpsPolicy /// Initializes the HttpsRedirectionMiddleware /// /// - /// The /// /// - public HttpsRedirectionMiddleware(RequestDelegate next, IServerAddressesFeature serverAddressesFeature, IOptions options, IConfiguration config) + public HttpsRedirectionMiddleware(RequestDelegate next, IOptions options, IConfiguration config) + { + _next = next ?? throw new ArgumentNullException(nameof(next)); + _config = config ?? throw new ArgumentNullException(nameof(config)); + if (options == null) { throw new ArgumentNullException(nameof(options)); } - _config = config ?? throw new ArgumentException(nameof(config)); - _next = next ?? throw new ArgumentNullException(nameof(next)); - _serverAddressesFeature = serverAddressesFeature ?? throw new ArgumentNullException(nameof(serverAddressesFeature)); - var httpsRedirectionOptions = options.Value; _httpsPort = httpsRedirectionOptions.HttpsPort; _statusCode = httpsRedirectionOptions.RedirectStatusCode; } + /// + /// Initializes the HttpsRedirectionMiddleware + /// + /// + /// + /// + /// The + public HttpsRedirectionMiddleware(RequestDelegate next, IOptions options, IConfiguration config, IServerAddressesFeature serverAddressesFeature) + : this(next, options, config) + { + _serverAddressesFeature = serverAddressesFeature ?? throw new ArgumentNullException(nameof(serverAddressesFeature)); + } + /// /// Invokes the HttpsRedirectionMiddleware /// @@ -98,7 +110,13 @@ namespace Microsoft.AspNetCore.HttpsPolicy if (_httpsPort.HasValue) { return; - } + } + + if (_serverAddressesFeature == null) + { + _httpsPort = 443; + return; + } int? httpsPort = null; foreach (var address in _serverAddressesFeature.Addresses) diff --git a/test/Microsoft.AspNetCore.HttpsPolicy.Tests/HttpsRedirectionMiddlewareTests.cs b/test/Microsoft.AspNetCore.HttpsPolicy.Tests/HttpsRedirectionMiddlewareTests.cs index 95888d614f..9d482151ca 100644 --- a/test/Microsoft.AspNetCore.HttpsPolicy.Tests/HttpsRedirectionMiddlewareTests.cs +++ b/test/Microsoft.AspNetCore.HttpsPolicy.Tests/HttpsRedirectionMiddlewareTests.cs @@ -2,7 +2,6 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; -using System.Linq; using System.Net; using System.Net.Http; using System.Threading.Tasks; @@ -13,7 +12,6 @@ using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http.Features; using Microsoft.AspNetCore.TestHost; using Microsoft.Extensions.DependencyInjection; -using Microsoft.Net.Http.Headers; using Xunit; namespace Microsoft.AspNetCore.HttpsPolicy.Tests @@ -280,5 +278,62 @@ namespace Microsoft.AspNetCore.HttpsPolicy.Tests Assert.Equal("https://localhost:5050/", response.Headers.Location.ToString()); } + + [Fact] + public async Task NoServerAddressFeature_DoesNotThrow_DefaultsTo443() + { + var builder = new WebHostBuilder() + .ConfigureServices(services => + { + services.AddHttpsRedirection(options => + { + }); + }) + .Configure(app => + { + app.UseHttpsRedirection(); + app.Run(context => + { + return context.Response.WriteAsync("Hello world"); + }); + }); + + var server = new TestServer(builder); + var client = server.CreateClient(); + var request = new HttpRequestMessage(HttpMethod.Get, ""); + var response = await client.SendAsync(request); + + Assert.Equal("https://localhost/", response.Headers.Location.ToString()); + } + + [Fact] + public async Task SetNullAddressFeature_DoesNotThrow() + { + var builder = new WebHostBuilder() + .ConfigureServices(services => + { + services.AddHttpsRedirection(options => + { + }); + }) + .Configure(app => + { + app.UseHttpsRedirection(); + app.Run(context => + { + return context.Response.WriteAsync("Hello world"); + }); + }); + + var featureCollection = new FeatureCollection(); + featureCollection.Set(null); + var server = new TestServer(builder, featureCollection); + + var client = server.CreateClient(); + var request = new HttpRequestMessage(HttpMethod.Get, ""); + var response = await client.SendAsync(request); + + Assert.Equal("https://localhost/", response.Headers.Location.ToString()); + } } } From aa0395847f50ed4c1e6573d7aed46549c8819f6b Mon Sep 17 00:00:00 2001 From: Pranav K Date: Tue, 23 Jan 2018 15:30:03 -0800 Subject: [PATCH 259/307] Branching for 2.1.0-preview1 --- build/dependencies.props | 36 ++++++++++++++++++------------------ build/repo.props | 4 ++-- build/sources.props | 4 ++-- korebuild-lock.txt | 4 ++-- 4 files changed, 24 insertions(+), 24 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index 49adf6aa26..5f3752bc26 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -3,25 +3,25 @@ $(MSBuildAllProjects);$(MSBuildThisFileFullPath) - 2.1.0-preview1-15651 - 2.1.0-preview1-27965 - 2.1.0-preview1-27965 - 2.1.0-preview1-27965 - 2.1.0-preview1-27965 - 2.1.0-preview1-27965 - 2.1.0-preview1-27965 - 2.1.0-preview1-27965 - 2.1.0-preview1-27965 - 2.1.0-preview1-27965 - 2.1.0-preview1-27965 - 2.1.0-preview1-27965 - 2.1.0-preview1-27965 - 2.1.0-preview1-27965 - 2.1.0-preview1-27965 - 2.1.0-preview1-27965 + 2.1.0-preview1-15679 + 2.1.0-preview1-28153 + 2.1.0-preview1-28153 + 2.1.0-preview1-28153 + 2.1.0-preview1-28153 + 2.1.0-preview1-28153 + 2.1.0-preview1-28153 + 2.1.0-preview1-28153 + 2.1.0-preview1-28153 + 2.1.0-preview1-28153 + 2.1.0-preview1-28153 + 2.1.0-preview1-28153 + 2.1.0-preview1-28153 + 2.1.0-preview1-28153 + 2.1.0-preview1-28153 + 2.1.0-preview1-28153 2.0.0 - 2.1.0-preview1-26016-05 - 2.1.0-preview1-27965 + 2.1.0-preview1-26115-03 + 2.1.0-preview1-28153 15.3.0 4.7.49 0.8.0 diff --git a/build/repo.props b/build/repo.props index 78b0ce5879..d94ff7d00d 100644 --- a/build/repo.props +++ b/build/repo.props @@ -1,10 +1,10 @@ - + Internal.AspNetCore.Universe.Lineup - https://dotnet.myget.org/F/aspnetcore-dev/api/v3/index.json + https://dotnet.myget.org/F/aspnetcore-release/api/v3/index.json diff --git a/build/sources.props b/build/sources.props index 9feff29d09..5d66393335 100644 --- a/build/sources.props +++ b/build/sources.props @@ -1,11 +1,11 @@ - + $(DotNetRestoreSources) $(RestoreSources); - https://dotnet.myget.org/F/aspnetcore-dev/api/v3/index.json; + https://dotnet.myget.org/F/aspnetcore-release/api/v3/index.json; https://dotnet.myget.org/F/aspnetcore-tools/api/v3/index.json; diff --git a/korebuild-lock.txt b/korebuild-lock.txt index 2146d006d7..a474bc0e35 100644 --- a/korebuild-lock.txt +++ b/korebuild-lock.txt @@ -1,2 +1,2 @@ -version:2.1.0-preview1-15661 -commithash:c9349d4c8a495d3085d9b879214d80f2f45e2193 +version:2.1.0-preview1-15679 +commithash:5347461137cb45a77ddcc0b55b2478092de43338 From dd038387285bf9fa8dc52910ef762b9843ff22e4 Mon Sep 17 00:00:00 2001 From: Pranav K Date: Wed, 24 Jan 2018 15:00:26 -0800 Subject: [PATCH 260/307] Updating version to preview2 --- version.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.props b/version.props index d1791a6a89..6025bea086 100644 --- a/version.props +++ b/version.props @@ -2,7 +2,7 @@ 2.1.0 0.4.0 - preview1 + preview2 $(VersionPrefix) $(VersionPrefix)-$(VersionSuffix)-final t000 From f2676babd3b7780573c40800dd916c7ad9195285 Mon Sep 17 00:00:00 2001 From: Mikael Mengistu Date: Wed, 31 Jan 2018 10:41:28 -0800 Subject: [PATCH 261/307] Add support for REQUEST_METHOD server variable (#294) --- .../Internal/IISUrlRewrite/ServerVariables.cs | 2 ++ .../IISUrlRewrite/ServerVariableTests.cs | 2 ++ 2 files changed, 4 insertions(+) diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/ServerVariables.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/ServerVariables.cs index 6bfdc59156..35e6ce1237 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/ServerVariables.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/ServerVariables.cs @@ -60,6 +60,8 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite return new RemotePortSegment(); case "REQUEST_FILENAME": return new RequestFileNameSegment(); + case "REQUEST_METHOD": + return new RequestMethodSegment(); case "REQUEST_URI": return new UrlSegment(uriMatchPart); default: diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/ServerVariableTests.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/ServerVariableTests.cs index b9acf1442c..b56a8c7854 100644 --- a/test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/ServerVariableTests.cs +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/ServerVariableTests.cs @@ -27,6 +27,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite [InlineData("REQUEST_FILENAME", "/foo", UriMatchPart.Path)] [InlineData("REQUEST_URI", "/foo", UriMatchPart.Path)] [InlineData("REQUEST_URI", "http://example.com/foo?bar=1", UriMatchPart.Full)] + [InlineData("REQUEST_METHOD", "GET", UriMatchPart.Full)] public void CheckServerVariableParsingAndApplication(string variable, string expected, UriMatchPart uriMatchPart) { // Arrange and Act @@ -40,6 +41,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite private RewriteContext CreateTestHttpContext() { var context = new DefaultHttpContext(); + context.Request.Method = HttpMethods.Get; context.Request.Scheme = "http"; context.Request.Host = new HostString("example.com"); context.Request.Path = PathString.FromUriComponent("/foo"); From b85d69c882fbd6aa2d6b0caa4b5b59d58f407140 Mon Sep 17 00:00:00 2001 From: Mikael Mengistu Date: Wed, 31 Jan 2018 11:47:08 -0800 Subject: [PATCH 262/307] Merge release/2.1 - Add support for REQUEST_METHOD server variable --- .../Internal/IISUrlRewrite/ServerVariables.cs | 2 ++ .../IISUrlRewrite/ServerVariableTests.cs | 2 ++ 2 files changed, 4 insertions(+) diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/ServerVariables.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/ServerVariables.cs index 6bfdc59156..35e6ce1237 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/ServerVariables.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/ServerVariables.cs @@ -60,6 +60,8 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite return new RemotePortSegment(); case "REQUEST_FILENAME": return new RequestFileNameSegment(); + case "REQUEST_METHOD": + return new RequestMethodSegment(); case "REQUEST_URI": return new UrlSegment(uriMatchPart); default: diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/ServerVariableTests.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/ServerVariableTests.cs index b9acf1442c..b56a8c7854 100644 --- a/test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/ServerVariableTests.cs +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/ServerVariableTests.cs @@ -27,6 +27,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite [InlineData("REQUEST_FILENAME", "/foo", UriMatchPart.Path)] [InlineData("REQUEST_URI", "/foo", UriMatchPart.Path)] [InlineData("REQUEST_URI", "http://example.com/foo?bar=1", UriMatchPart.Full)] + [InlineData("REQUEST_METHOD", "GET", UriMatchPart.Full)] public void CheckServerVariableParsingAndApplication(string variable, string expected, UriMatchPart uriMatchPart) { // Arrange and Act @@ -40,6 +41,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite private RewriteContext CreateTestHttpContext() { var context = new DefaultHttpContext(); + context.Request.Method = HttpMethods.Get; context.Request.Scheme = "http"; context.Request.Host = new HostString("example.com"); context.Request.Path = PathString.FromUriComponent("/foo"); From 237ae410ffd57e1976f634b52cdf7e75623814a7 Mon Sep 17 00:00:00 2001 From: Nate McMaster Date: Wed, 31 Jan 2018 15:01:10 -0800 Subject: [PATCH 263/307] Update dependencies.props to 2.1.0-preview-28193, build tools to 2.1.0-preview1-1010 [ci skip] Scripted changes: - updated travis and appveyor.yml files to only build dev, ci, and release branches - updated dependencies.props - updated korebuild-lock.txt - updated korebuild.json to release/2.1 channel --- .appveyor.yml | 15 +++++++-------- .travis.yml | 24 ++++++++++++------------ build/dependencies.props | 36 ++++++++++++++++++------------------ korebuild-lock.txt | 4 ++-- korebuild.json | 4 ++-- 5 files changed, 41 insertions(+), 42 deletions(-) diff --git a/.appveyor.yml b/.appveyor.yml index 46038786c9..4eea96ab69 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -1,18 +1,17 @@ init: - - git config --global core.autocrlf true +- git config --global core.autocrlf true branches: only: - - master - - release - - dev - - /^(.*\/)?ci-.*$/ + - dev + - /^release\/.*$/ + - /^(.*\/)?ci-.*$/ build_script: - - ps: .\run.ps1 default-build +- ps: .\run.ps1 default-build clone_depth: 1 environment: global: DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true DOTNET_CLI_TELEMETRY_OPTOUT: 1 -test: off -deploy: off +test: 'off' +deploy: 'off' os: Visual Studio 2017 diff --git a/.travis.yml b/.travis.yml index eeb63bfa9f..64bdbb4441 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,25 +3,25 @@ sudo: false dist: trusty env: global: - - DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true - - DOTNET_CLI_TELEMETRY_OPTOUT: 1 + - DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true + - DOTNET_CLI_TELEMETRY_OPTOUT: 1 mono: none os: - - linux - - osx +- linux +- osx osx_image: xcode8.2 addons: apt: packages: - - libunwind8 + - libunwind8 branches: only: - - master - - release - - dev - - /^(.*\/)?ci-.*$/ + - dev + - /^release\/.*$/ + - /^(.*\/)?ci-.*$/ before_install: - - if test "$TRAVIS_OS_NAME" == "osx"; then brew update; brew install openssl; ln -s /usr/local/opt/openssl/lib/libcrypto.1.0.0.dylib /usr/local/lib/; ln -s /usr/local/opt/openssl/lib/libssl.1.0.0.dylib /usr/local/lib/; fi +- if test "$TRAVIS_OS_NAME" == "osx"; then brew update; brew install openssl; ln -s + /usr/local/opt/openssl/lib/libcrypto.1.0.0.dylib /usr/local/lib/; ln -s /usr/local/opt/openssl/lib/libssl.1.0.0.dylib + /usr/local/lib/; fi script: - - ./build.sh - +- ./build.sh diff --git a/build/dependencies.props b/build/dependencies.props index 5f3752bc26..5abbb8d678 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -3,25 +3,25 @@ $(MSBuildAllProjects);$(MSBuildThisFileFullPath) - 2.1.0-preview1-15679 - 2.1.0-preview1-28153 - 2.1.0-preview1-28153 - 2.1.0-preview1-28153 - 2.1.0-preview1-28153 - 2.1.0-preview1-28153 - 2.1.0-preview1-28153 - 2.1.0-preview1-28153 - 2.1.0-preview1-28153 - 2.1.0-preview1-28153 - 2.1.0-preview1-28153 - 2.1.0-preview1-28153 - 2.1.0-preview1-28153 - 2.1.0-preview1-28153 - 2.1.0-preview1-28153 - 2.1.0-preview1-28153 + 2.1.0-preview1-1010 + 2.1.0-preview1-28193 + 2.1.0-preview1-28193 + 2.1.0-preview1-28193 + 2.1.0-preview1-28193 + 2.1.0-preview1-28193 + 2.1.0-preview1-28193 + 2.1.0-preview1-28193 + 2.1.0-preview1-28193 + 2.1.0-preview1-28193 + 2.1.0-preview1-28193 + 2.1.0-preview1-28193 + 2.1.0-preview1-28193 + 2.1.0-preview1-28193 + 2.1.0-preview1-28193 + 2.1.0-preview1-28193 2.0.0 - 2.1.0-preview1-26115-03 - 2.1.0-preview1-28153 + 2.1.0-preview1-26122-01 + 2.1.0-preview1-28193 15.3.0 4.7.49 0.8.0 diff --git a/korebuild-lock.txt b/korebuild-lock.txt index a474bc0e35..851bfbf203 100644 --- a/korebuild-lock.txt +++ b/korebuild-lock.txt @@ -1,2 +1,2 @@ -version:2.1.0-preview1-15679 -commithash:5347461137cb45a77ddcc0b55b2478092de43338 +version:2.1.0-preview1-1010 +commithash:75ca924dfbd673c38841025b04c4dcd93b84f56d diff --git a/korebuild.json b/korebuild.json index bd5d51a51b..678d8bb948 100644 --- a/korebuild.json +++ b/korebuild.json @@ -1,4 +1,4 @@ { - "$schema": "https://raw.githubusercontent.com/aspnet/BuildTools/dev/tools/korebuild.schema.json", - "channel": "dev" + "$schema": "https://raw.githubusercontent.com/aspnet/BuildTools/release/2.1/tools/korebuild.schema.json", + "channel": "release/2.1" } From 9b0f9d824659a2498ed46f1ed2f83d50dd479c18 Mon Sep 17 00:00:00 2001 From: "ASP.NET CI" Date: Thu, 1 Feb 2018 02:52:55 +0000 Subject: [PATCH 264/307] Update dependencies.props [auto-updated: dependencies] --- build/dependencies.props | 36 ++++++++++++++++++------------------ korebuild-lock.txt | 4 ++-- 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index 49adf6aa26..706a1b16ac 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -3,25 +3,25 @@ $(MSBuildAllProjects);$(MSBuildThisFileFullPath) - 2.1.0-preview1-15651 - 2.1.0-preview1-27965 - 2.1.0-preview1-27965 - 2.1.0-preview1-27965 - 2.1.0-preview1-27965 - 2.1.0-preview1-27965 - 2.1.0-preview1-27965 - 2.1.0-preview1-27965 - 2.1.0-preview1-27965 - 2.1.0-preview1-27965 - 2.1.0-preview1-27965 - 2.1.0-preview1-27965 - 2.1.0-preview1-27965 - 2.1.0-preview1-27965 - 2.1.0-preview1-27965 - 2.1.0-preview1-27965 + 2.1.0-preview2-15692 + 2.1.0-preview2-28215 + 2.1.0-preview2-28215 + 2.1.0-preview2-28215 + 2.1.0-preview2-28215 + 2.1.0-preview2-28215 + 2.1.0-preview2-28215 + 2.1.0-preview2-28215 + 2.1.0-preview2-28215 + 2.1.0-preview2-28215 + 2.1.0-preview2-28215 + 2.1.0-preview2-28215 + 2.1.0-preview2-28215 + 2.1.0-preview2-28215 + 2.1.0-preview2-28215 + 2.1.0-preview2-28215 2.0.0 - 2.1.0-preview1-26016-05 - 2.1.0-preview1-27965 + 2.1.0-preview2-26130-04 + 2.1.0-preview2-28215 15.3.0 4.7.49 0.8.0 diff --git a/korebuild-lock.txt b/korebuild-lock.txt index 2146d006d7..232cb858c2 100644 --- a/korebuild-lock.txt +++ b/korebuild-lock.txt @@ -1,2 +1,2 @@ -version:2.1.0-preview1-15661 -commithash:c9349d4c8a495d3085d9b879214d80f2f45e2193 +version:2.1.0-preview2-15692 +commithash:5d9f445ce3f8492451a6f461df7e739bbed6a7f8 From 5c3fc3770fd9c88f2a6126c47ab741d40e48b034 Mon Sep 17 00:00:00 2001 From: "ASP.NET CI" Date: Sat, 3 Feb 2018 02:36:37 +0000 Subject: [PATCH 265/307] Update dependencies.props [auto-updated: dependencies] --- build/dependencies.props | 34 +++++++++++++++++----------------- korebuild-lock.txt | 4 ++-- 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index 706a1b16ac..67561b9d93 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -3,25 +3,25 @@ $(MSBuildAllProjects);$(MSBuildThisFileFullPath) - 2.1.0-preview2-15692 - 2.1.0-preview2-28215 - 2.1.0-preview2-28215 - 2.1.0-preview2-28215 - 2.1.0-preview2-28215 - 2.1.0-preview2-28215 - 2.1.0-preview2-28215 - 2.1.0-preview2-28215 - 2.1.0-preview2-28215 - 2.1.0-preview2-28215 - 2.1.0-preview2-28215 - 2.1.0-preview2-28215 - 2.1.0-preview2-28215 - 2.1.0-preview2-28215 - 2.1.0-preview2-28215 - 2.1.0-preview2-28215 + 2.1.0-preview2-15694 + 2.1.0-preview2-30020 + 2.1.0-preview2-30020 + 2.1.0-preview2-30020 + 2.1.0-preview2-30020 + 2.1.0-preview2-30020 + 2.1.0-preview2-30020 + 2.1.0-preview2-30020 + 2.1.0-preview2-30020 + 2.1.0-preview2-30020 + 2.1.0-preview2-30020 + 2.1.0-preview2-30020 + 2.1.0-preview2-30020 + 2.1.0-preview2-30020 + 2.1.0-preview2-30020 + 2.1.0-preview2-30020 2.0.0 2.1.0-preview2-26130-04 - 2.1.0-preview2-28215 + 2.1.0-preview2-30020 15.3.0 4.7.49 0.8.0 diff --git a/korebuild-lock.txt b/korebuild-lock.txt index 232cb858c2..6f294ef0e6 100644 --- a/korebuild-lock.txt +++ b/korebuild-lock.txt @@ -1,2 +1,2 @@ -version:2.1.0-preview2-15692 -commithash:5d9f445ce3f8492451a6f461df7e739bbed6a7f8 +version:2.1.0-preview2-15694 +commithash:f61af02b48e89592c9aadb7ebaebe84228666c3b From 840756bdde61c825de24793a94e25eeb1693f66f Mon Sep 17 00:00:00 2001 From: "ASP.NET CI" Date: Fri, 9 Feb 2018 11:33:58 -0800 Subject: [PATCH 266/307] Update dependencies.props [auto-updated: dependencies] --- build/dependencies.props | 34 +++++++++++++++++----------------- korebuild-lock.txt | 4 ++-- 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index 67561b9d93..eac9dbcf45 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -3,25 +3,25 @@ $(MSBuildAllProjects);$(MSBuildThisFileFullPath) - 2.1.0-preview2-15694 - 2.1.0-preview2-30020 - 2.1.0-preview2-30020 - 2.1.0-preview2-30020 - 2.1.0-preview2-30020 - 2.1.0-preview2-30020 - 2.1.0-preview2-30020 - 2.1.0-preview2-30020 - 2.1.0-preview2-30020 - 2.1.0-preview2-30020 - 2.1.0-preview2-30020 - 2.1.0-preview2-30020 - 2.1.0-preview2-30020 - 2.1.0-preview2-30020 - 2.1.0-preview2-30020 - 2.1.0-preview2-30020 + 2.1.0-preview2-15698 + 2.1.0-preview2-30066 + 2.1.0-preview2-30066 + 2.1.0-preview2-30066 + 2.1.0-preview2-30066 + 2.1.0-preview2-30066 + 2.1.0-preview2-30066 + 2.1.0-preview2-30066 + 2.1.0-preview2-30066 + 2.1.0-preview2-30066 + 2.1.0-preview2-30066 + 2.1.0-preview2-30066 + 2.1.0-preview2-30066 + 2.1.0-preview2-30066 + 2.1.0-preview2-30066 + 2.1.0-preview2-30066 2.0.0 2.1.0-preview2-26130-04 - 2.1.0-preview2-30020 + 2.1.0-preview2-30066 15.3.0 4.7.49 0.8.0 diff --git a/korebuild-lock.txt b/korebuild-lock.txt index 6f294ef0e6..3e2b56b91b 100644 --- a/korebuild-lock.txt +++ b/korebuild-lock.txt @@ -1,2 +1,2 @@ -version:2.1.0-preview2-15694 -commithash:f61af02b48e89592c9aadb7ebaebe84228666c3b +version:2.1.0-preview2-15698 +commithash:7216e5068cb1957e09d45fcbe58a744dd5c2de73 From 103190796f04026a9cd7001881646d730f8ba8f1 Mon Sep 17 00:00:00 2001 From: Colin Farr Date: Fri, 9 Feb 2018 22:13:43 +0000 Subject: [PATCH 267/307] Adding RedirectToWwwRule and extension (#297) --- .../RewriteMiddlewareLoggingExtensions.cs | 11 +++ .../Internal/RedirectToWwwRule.cs | 45 ++++++++++ .../RewriteOptionsExtensions.cs | 30 +++++++ .../MiddlewareTests.cs | 85 +++++++++++++++++++ 4 files changed, 171 insertions(+) create mode 100644 src/Microsoft.AspNetCore.Rewrite/Internal/RedirectToWwwRule.cs diff --git a/src/Microsoft.AspNetCore.Rewrite/Extensions/RewriteMiddlewareLoggingExtensions.cs b/src/Microsoft.AspNetCore.Rewrite/Extensions/RewriteMiddlewareLoggingExtensions.cs index 3ad1e699dd..8b500b4338 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Extensions/RewriteMiddlewareLoggingExtensions.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Extensions/RewriteMiddlewareLoggingExtensions.cs @@ -16,6 +16,7 @@ namespace Microsoft.AspNetCore.Rewrite.Logging private static readonly Action _modRewriteDidNotMatchRule; private static readonly Action _modRewriteMatchedRule; private static readonly Action _redirectedToHttps; + private static readonly Action _redirectedToWww; private static readonly Action _redirectSummary; private static readonly Action _rewriteSummary; private static readonly Action _abortedRequest; @@ -82,6 +83,11 @@ namespace Microsoft.AspNetCore.Rewrite.Logging LogLevel.Debug, 12, "Request to {requestedUrl} was ended"); + + _redirectedToWww = LoggerMessage.Define( + LogLevel.Information, + 13, + "Request redirected to www"); } public static void RewriteMiddlewareRequestContinueResults(this ILogger logger, string currentUrl) @@ -124,6 +130,11 @@ namespace Microsoft.AspNetCore.Rewrite.Logging _redirectedToHttps(logger, null); } + public static void RedirectedToWww(this ILogger logger) + { + _redirectedToWww(logger, null); + } + public static void RedirectedSummary(this ILogger logger, string redirectedUrl) { _redirectSummary(logger, redirectedUrl, null); diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/RedirectToWwwRule.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/RedirectToWwwRule.cs new file mode 100644 index 0000000000..4675476e60 --- /dev/null +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/RedirectToWwwRule.cs @@ -0,0 +1,45 @@ +// 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; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Http.Extensions; +using Microsoft.AspNetCore.Rewrite.Logging; +using Microsoft.Net.Http.Headers; + +namespace Microsoft.AspNetCore.Rewrite.Internal +{ + public class RedirectToWwwRule : IRule + { + public readonly int _statusCode; + + public RedirectToWwwRule(int statusCode) + { + _statusCode = statusCode; + } + + public virtual void ApplyRule(RewriteContext context) + { + var req = context.HttpContext.Request; + if (req.Host.Host.Equals("localhost", StringComparison.OrdinalIgnoreCase)) + { + context.Result = RuleResult.ContinueRules; + return; + } + + if (req.Host.Value.StartsWith("www.", StringComparison.OrdinalIgnoreCase)) + { + context.Result = RuleResult.ContinueRules; + return; + } + + var wwwHost = new HostString($"www.{req.Host.Value}"); + var newUrl = UriHelper.BuildAbsolute(req.Scheme, wwwHost, req.PathBase, req.Path, req.QueryString); + var response = context.HttpContext.Response; + response.StatusCode = _statusCode; + response.Headers[HeaderNames.Location] = newUrl; + context.Result = RuleResult.EndResponse; + context.Logger?.RedirectedToWww(); + } + } +} \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Rewrite/RewriteOptionsExtensions.cs b/src/Microsoft.AspNetCore.Rewrite/RewriteOptionsExtensions.cs index c1aa2b69ed..d1c839899c 100644 --- a/src/Microsoft.AspNetCore.Rewrite/RewriteOptionsExtensions.cs +++ b/src/Microsoft.AspNetCore.Rewrite/RewriteOptionsExtensions.cs @@ -117,5 +117,35 @@ namespace Microsoft.AspNetCore.Rewrite options.Rules.Add(new RedirectToHttpsRule { StatusCode = statusCode, SSLPort = sslPort }); return options; } + + /// + /// Permanently redirects the request to the www subdomain if the request is non-www. + /// + /// The . + /// + public static RewriteOptions AddRedirectToWwwPermanent(this RewriteOptions options) + { + return AddRedirectToWww(options, statusCode: StatusCodes.Status308PermanentRedirect); + } + + /// + /// Redirect the request to the www subdomain if the incoming request is non-www. + /// + /// The . + public static RewriteOptions AddRedirectToWww(this RewriteOptions options) + { + return AddRedirectToWww(options, statusCode: StatusCodes.Status307TemporaryRedirect); + } + + /// + /// Redirect the request to the www subdomain if the incoming request is non-www. + /// + /// The . + /// The status code to add to the response. + public static RewriteOptions AddRedirectToWww(this RewriteOptions options, int statusCode) + { + options.Rules.Add(new RedirectToWwwRule(statusCode)); + return options; + } } } diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/MiddlewareTests.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/MiddlewareTests.cs index c75ef98c50..5c6fb1e4ec 100644 --- a/test/Microsoft.AspNetCore.Rewrite.Tests/MiddlewareTests.cs +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/MiddlewareTests.cs @@ -147,6 +147,91 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.CodeRules Assert.Equal(StatusCodes.Status301MovedPermanently, (int)response.StatusCode); } + [Theory] + [InlineData(StatusCodes.Status301MovedPermanently)] + [InlineData(StatusCodes.Status302Found)] + [InlineData(StatusCodes.Status307TemporaryRedirect)] + [InlineData(StatusCodes.Status308PermanentRedirect)] + public async Task CheckRedirectToWwwWithStatusCode(int statusCode) + { + var options = new RewriteOptions().AddRedirectToWww(statusCode: statusCode); + var builder = new WebHostBuilder() + .Configure(app => + { + app.UseRewriter(options); + }); + var server = new TestServer(builder); + + var response = await server.CreateClient().GetAsync(new Uri("https://example.com")); + + Assert.Equal("https://www.example.com/", response.Headers.Location.OriginalString); + Assert.Equal(statusCode, (int)response.StatusCode); + } + + [Theory] + [InlineData("http://example.com", "http://www.example.com/")] + [InlineData("https://example.com", "https://www.example.com/")] + [InlineData("http://example.com:8081", "http://www.example.com:8081/")] + [InlineData("http://example.com:8081/example?q=1", "http://www.example.com:8081/example?q=1")] + public async Task CheckRedirectToWww(string requestUri, string redirectUri) + { + var options = new RewriteOptions().AddRedirectToWww(); + var builder = new WebHostBuilder() + .Configure(app => + { + app.UseRewriter(options); + }); + var server = new TestServer(builder); + + var response = await server.CreateClient().GetAsync(new Uri(requestUri)); + + Assert.Equal(redirectUri, response.Headers.Location.OriginalString); + Assert.Equal(StatusCodes.Status307TemporaryRedirect, (int)response.StatusCode); + } + + [Fact] + public async Task CheckPermanentRedirectToWww() + { + var options = new RewriteOptions().AddRedirectToWwwPermanent(); + var builder = new WebHostBuilder() + .Configure(app => + { + app.UseRewriter(options); + }); + var server = new TestServer(builder); + + var response = await server.CreateClient().GetAsync(new Uri("https://example.com")); + + Assert.Equal("https://www.example.com/", response.Headers.Location.OriginalString); + Assert.Equal(StatusCodes.Status308PermanentRedirect, (int)response.StatusCode); + } + + [Theory] + [InlineData("http://www.example.com")] + [InlineData("https://www.example.com")] + [InlineData("http://www.example.com:8081")] + [InlineData("https://www.example.com:8081")] + [InlineData("https://www.example.com:8081/example?q=1")] + [InlineData("http://localhost")] + [InlineData("https://localhost")] + [InlineData("http://localhost:8081")] + [InlineData("https://localhost:8081")] + [InlineData("https://localhost:8081/example?q=1")] + public async Task CheckNoRedirectToWww(string requestUri) + { + var options = new RewriteOptions().AddRedirectToWww(); + var builder = new WebHostBuilder() + .Configure(app => + { + app.UseRewriter(options); + }); + var server = new TestServer(builder); + + var response = await server.CreateClient().GetAsync(new Uri(requestUri)); + + Assert.Null(response.Headers.Location); + } + [Fact] public async Task CheckIfEmptyStringRedirectCorrectly() { From 5a3f9d930329aaed5d641cf1612f4e1df8f5e491 Mon Sep 17 00:00:00 2001 From: "ASP.NET CI" Date: Sun, 11 Feb 2018 12:15:25 -0800 Subject: [PATCH 268/307] Update dependencies.props [auto-updated: dependencies] --- build/dependencies.props | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index eac9dbcf45..d6b81e0f55 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -4,29 +4,29 @@ 2.1.0-preview2-15698 - 2.1.0-preview2-30066 - 2.1.0-preview2-30066 - 2.1.0-preview2-30066 - 2.1.0-preview2-30066 - 2.1.0-preview2-30066 - 2.1.0-preview2-30066 - 2.1.0-preview2-30066 - 2.1.0-preview2-30066 - 2.1.0-preview2-30066 - 2.1.0-preview2-30066 - 2.1.0-preview2-30066 - 2.1.0-preview2-30066 - 2.1.0-preview2-30066 - 2.1.0-preview2-30066 - 2.1.0-preview2-30066 + 2.1.0-preview2-30077 + 2.1.0-preview2-30077 + 2.1.0-preview2-30077 + 2.1.0-preview2-30077 + 2.1.0-preview2-30077 + 2.1.0-preview2-30077 + 2.1.0-preview2-30077 + 2.1.0-preview2-30077 + 2.1.0-preview2-30077 + 2.1.0-preview2-30077 + 2.1.0-preview2-30077 + 2.1.0-preview2-30077 + 2.1.0-preview2-30077 + 2.1.0-preview2-30077 + 2.1.0-preview2-30077 2.0.0 2.1.0-preview2-26130-04 - 2.1.0-preview2-30066 + 2.1.0-preview2-30077 15.3.0 4.7.49 0.8.0 2.3.1 - 2.3.1 + 2.4.0-beta.1.build3945 From ade44786c934c1300dab85aa02efdd99fc0ea81c Mon Sep 17 00:00:00 2001 From: Ryan Brandenburg Date: Thu, 15 Feb 2018 10:05:28 -0800 Subject: [PATCH 269/307] Use ExperimentalPackageVersion --- build/dependencies.props | 50 +++++++++---------- .../Microsoft.AspNetCore.Buffering.csproj | 6 ++- version.props | 4 +- 3 files changed, 32 insertions(+), 28 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index 5abbb8d678..4556459ec0 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -2,31 +2,31 @@ $(MSBuildAllProjects);$(MSBuildThisFileFullPath) - - 2.1.0-preview1-1010 - 2.1.0-preview1-28193 - 2.1.0-preview1-28193 - 2.1.0-preview1-28193 - 2.1.0-preview1-28193 - 2.1.0-preview1-28193 - 2.1.0-preview1-28193 - 2.1.0-preview1-28193 - 2.1.0-preview1-28193 - 2.1.0-preview1-28193 - 2.1.0-preview1-28193 - 2.1.0-preview1-28193 - 2.1.0-preview1-28193 - 2.1.0-preview1-28193 - 2.1.0-preview1-28193 - 2.1.0-preview1-28193 - 2.0.0 - 2.1.0-preview1-26122-01 - 2.1.0-preview1-28193 - 15.3.0 - 4.7.49 - 0.8.0 - 2.3.1 - 2.3.1 + + 2.1.0-preview1-1010 + 2.1.0-preview1-28274 + 2.1.0-preview1-28274 + 2.1.0-preview1-28274 + 2.1.0-preview1-28274 + 2.1.0-preview1-28274 + 2.1.0-preview1-28274 + 2.1.0-preview1-28274 + 2.1.0-preview1-28274 + 2.1.0-preview1-28274 + 2.1.0-preview1-28274 + 2.1.0-preview1-28274 + 2.1.0-preview1-28274 + 2.1.0-preview1-28274 + 2.1.0-preview1-28274 + 2.1.0-preview1-28274 + 2.0.0 + 2.1.0-preview1-26208-06 + 2.1.0-preview1-28274 + 15.3.0 + 4.7.49 + 0.8.0 + 2.3.1 + 2.3.1 diff --git a/src/Microsoft.AspNetCore.Buffering/Microsoft.AspNetCore.Buffering.csproj b/src/Microsoft.AspNetCore.Buffering/Microsoft.AspNetCore.Buffering.csproj index 8b4cd9cefc..2ea53b2d92 100644 --- a/src/Microsoft.AspNetCore.Buffering/Microsoft.AspNetCore.Buffering.csproj +++ b/src/Microsoft.AspNetCore.Buffering/Microsoft.AspNetCore.Buffering.csproj @@ -1,8 +1,10 @@  - $(ExperimentalProjectVersionPrefix) - false + $(ExperimentalProjectVersionPrefix) + $(ExperimentalVersionSuffix) + false + $(ExperimentalPackageVersion) ASP.NET Core middleware for buffering response bodies. netstandard2.0 $(NoWarn);CS1591 diff --git a/version.props b/version.props index d1791a6a89..d01d5acfda 100644 --- a/version.props +++ b/version.props @@ -1,7 +1,9 @@ 2.1.0 - 0.4.0 + 0.4.0 + alpha1 + $(ExperimentalVersionPrefix)-$(ExperimentalVersionSuffix)-final preview1 $(VersionPrefix) $(VersionPrefix)-$(VersionSuffix)-final From d7957ed50cb6d58ee11f80731a3eff90c71139f6 Mon Sep 17 00:00:00 2001 From: Ryan Brandenburg Date: Thu, 15 Feb 2018 12:24:46 -0800 Subject: [PATCH 270/307] No more ExperimentalProjectVersionPrefix --- .../Microsoft.AspNetCore.Buffering.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Microsoft.AspNetCore.Buffering/Microsoft.AspNetCore.Buffering.csproj b/src/Microsoft.AspNetCore.Buffering/Microsoft.AspNetCore.Buffering.csproj index 2ea53b2d92..953716c6c1 100644 --- a/src/Microsoft.AspNetCore.Buffering/Microsoft.AspNetCore.Buffering.csproj +++ b/src/Microsoft.AspNetCore.Buffering/Microsoft.AspNetCore.Buffering.csproj @@ -1,7 +1,7 @@  - $(ExperimentalProjectVersionPrefix) + $(ExperimentalVersionPrefix) $(ExperimentalVersionSuffix) false $(ExperimentalPackageVersion) From 30f7c7c3809b42eb09d25370983f187c71024e8e Mon Sep 17 00:00:00 2001 From: Ryan Brandenburg Date: Fri, 16 Feb 2018 13:43:22 -0800 Subject: [PATCH 271/307] BuildNumber on ExperimentalVersionSuffix --- version.props | 1 + 1 file changed, 1 insertion(+) diff --git a/version.props b/version.props index d01d5acfda..05cdc2c8d4 100644 --- a/version.props +++ b/version.props @@ -3,6 +3,7 @@ 2.1.0 0.4.0 alpha1 + $(ExperimentalVersionSuffix)-$(BuildNumber) $(ExperimentalVersionPrefix)-$(ExperimentalVersionSuffix)-final preview1 $(VersionPrefix) From 39167584eba2164e7be7aefec6d8e4670e51a0a6 Mon Sep 17 00:00:00 2001 From: Ryan Brandenburg Date: Fri, 16 Feb 2018 14:10:43 -0800 Subject: [PATCH 272/307] Duplicate logic for Experimental --- version.props | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/version.props b/version.props index 05cdc2c8d4..af807f0f09 100644 --- a/version.props +++ b/version.props @@ -1,14 +1,16 @@ 2.1.0 - 0.4.0 - alpha1 - $(ExperimentalVersionSuffix)-$(BuildNumber) - $(ExperimentalVersionPrefix)-$(ExperimentalVersionSuffix)-final preview1 $(VersionPrefix) $(VersionPrefix)-$(VersionSuffix)-final t000 $(VersionSuffix)-$(BuildNumber) + + 0.4.0 + alpha1 + $(ExperimentalVersionPrefix) + $(ExperimentalVersionPrefix)-$(ExperimentalVersionSuffix)-final + $(ExperimentalVersionSuffix)-$(BuildNumber) From c4ce0830c84b9dd948968c88fa96392b8c76b348 Mon Sep 17 00:00:00 2001 From: "ASP.NET CI" Date: Sun, 18 Feb 2018 12:10:51 -0800 Subject: [PATCH 273/307] Update dependencies.props [auto-updated: dependencies] --- build/dependencies.props | 34 +++++++++++++++++----------------- korebuild-lock.txt | 4 ++-- 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index d6b81e0f55..997af09b6d 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -3,25 +3,25 @@ $(MSBuildAllProjects);$(MSBuildThisFileFullPath) - 2.1.0-preview2-15698 - 2.1.0-preview2-30077 - 2.1.0-preview2-30077 - 2.1.0-preview2-30077 - 2.1.0-preview2-30077 - 2.1.0-preview2-30077 - 2.1.0-preview2-30077 - 2.1.0-preview2-30077 - 2.1.0-preview2-30077 - 2.1.0-preview2-30077 - 2.1.0-preview2-30077 - 2.1.0-preview2-30077 - 2.1.0-preview2-30077 - 2.1.0-preview2-30077 - 2.1.0-preview2-30077 - 2.1.0-preview2-30077 + 2.1.0-preview2-15707 + 2.1.0-preview2-30131 + 2.1.0-preview2-30131 + 2.1.0-preview2-30131 + 2.1.0-preview2-30131 + 2.1.0-preview2-30131 + 2.1.0-preview2-30131 + 2.1.0-preview2-30131 + 2.1.0-preview2-30131 + 2.1.0-preview2-30131 + 2.1.0-preview2-30131 + 2.1.0-preview2-30131 + 2.1.0-preview2-30131 + 2.1.0-preview2-30131 + 2.1.0-preview2-30131 + 2.1.0-preview2-30131 2.0.0 2.1.0-preview2-26130-04 - 2.1.0-preview2-30077 + 2.1.0-preview2-30131 15.3.0 4.7.49 0.8.0 diff --git a/korebuild-lock.txt b/korebuild-lock.txt index 3e2b56b91b..89d0ad3d15 100644 --- a/korebuild-lock.txt +++ b/korebuild-lock.txt @@ -1,2 +1,2 @@ -version:2.1.0-preview2-15698 -commithash:7216e5068cb1957e09d45fcbe58a744dd5c2de73 +version:2.1.0-preview2-15707 +commithash:e74e53f129ab34332947fea7ac7b7591b027cb22 From a174d5a7335eb288d5b7824c711d12bd3424ede8 Mon Sep 17 00:00:00 2001 From: Pranav K Date: Wed, 21 Feb 2018 18:26:48 -0800 Subject: [PATCH 274/307] Use FeatureBranchVersionSuffix when generating VersionSuffix --- version.props | 1 + 1 file changed, 1 insertion(+) diff --git a/version.props b/version.props index 6025bea086..f9146b2125 100644 --- a/version.props +++ b/version.props @@ -6,6 +6,7 @@ $(VersionPrefix) $(VersionPrefix)-$(VersionSuffix)-final t000 + $(VersionSuffix)-$([System.Text.RegularExpressions.Regex]::Replace('$(FeatureBranchVersionSuffix)', '[^\w-]', '-')) $(VersionSuffix)-$(BuildNumber) From 996f0545b0166e9161d1f860cb536acce4f4f303 Mon Sep 17 00:00:00 2001 From: "ASP.NET CI" Date: Mon, 26 Feb 2018 10:54:34 -0800 Subject: [PATCH 275/307] Update dependencies.props [auto-updated: dependencies] --- build/dependencies.props | 36 ++++++++++++++++++------------------ korebuild-lock.txt | 4 ++-- 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index 997af09b6d..fbba92b398 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -3,26 +3,26 @@ $(MSBuildAllProjects);$(MSBuildThisFileFullPath) - 2.1.0-preview2-15707 - 2.1.0-preview2-30131 - 2.1.0-preview2-30131 - 2.1.0-preview2-30131 - 2.1.0-preview2-30131 - 2.1.0-preview2-30131 - 2.1.0-preview2-30131 - 2.1.0-preview2-30131 - 2.1.0-preview2-30131 - 2.1.0-preview2-30131 - 2.1.0-preview2-30131 - 2.1.0-preview2-30131 - 2.1.0-preview2-30131 - 2.1.0-preview2-30131 - 2.1.0-preview2-30131 - 2.1.0-preview2-30131 + 2.1.0-preview2-15721 + 2.1.0-preview2-30187 + 2.1.0-preview2-30187 + 2.1.0-preview2-30187 + 2.1.0-preview2-30187 + 2.1.0-preview2-30187 + 2.1.0-preview2-30187 + 2.1.0-preview2-30187 + 2.1.0-preview2-30187 + 2.1.0-preview2-30187 + 2.1.0-preview2-30187 + 2.1.0-preview2-30187 + 2.1.0-preview2-30187 + 2.1.0-preview2-30187 + 2.1.0-preview2-30187 + 2.1.0-preview2-30187 2.0.0 2.1.0-preview2-26130-04 - 2.1.0-preview2-30131 - 15.3.0 + 2.1.0-preview2-30187 + 15.6.0 4.7.49 0.8.0 2.3.1 diff --git a/korebuild-lock.txt b/korebuild-lock.txt index 89d0ad3d15..e6c7fddffa 100644 --- a/korebuild-lock.txt +++ b/korebuild-lock.txt @@ -1,2 +1,2 @@ -version:2.1.0-preview2-15707 -commithash:e74e53f129ab34332947fea7ac7b7591b027cb22 +version:2.1.0-preview2-15721 +commithash:f9bb4be59e39938ec59a6975257e26099b0d03c1 From 7a9eb9a9f2a2a0d953a91333a1afba18eae9db81 Mon Sep 17 00:00:00 2001 From: Pranav K Date: Tue, 6 Mar 2018 10:02:29 -0800 Subject: [PATCH 276/307] Use dotnet-core feed in repos --- build/sources.props | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/build/sources.props b/build/sources.props index 9feff29d09..9215df9751 100644 --- a/build/sources.props +++ b/build/sources.props @@ -1,10 +1,11 @@ - + $(DotNetRestoreSources) $(RestoreSources); + https://dotnet.myget.org/F/dotnet-core/api/v3/index.json; https://dotnet.myget.org/F/aspnetcore-dev/api/v3/index.json; https://dotnet.myget.org/F/aspnetcore-tools/api/v3/index.json; From 36a6d859318662ee99630e37fdcf4fe965d8590b Mon Sep 17 00:00:00 2001 From: Pranav K Date: Tue, 6 Mar 2018 10:02:29 -0800 Subject: [PATCH 277/307] Prepend FeatureBranchVersionPrefix if FeatureBranchVersionSuffix is specified --- version.props | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/version.props b/version.props index 7377a3af54..b9dfed9383 100644 --- a/version.props +++ b/version.props @@ -5,7 +5,8 @@ $(VersionPrefix) $(VersionPrefix)-$(VersionSuffix)-final t000 - $(VersionSuffix)-$([System.Text.RegularExpressions.Regex]::Replace('$(FeatureBranchVersionSuffix)', '[^\w-]', '-')) + a- + $(FeatureBranchVersionPrefix)$(VersionSuffix)-$([System.Text.RegularExpressions.Regex]::Replace('$(FeatureBranchVersionSuffix)', '[^\w-]', '-')) $(VersionSuffix)-$(BuildNumber) 0.4.0 From daa40cea431ea9e1a50b9eec17c7a7542845470a Mon Sep 17 00:00:00 2001 From: "ASP.NET CI" Date: Thu, 8 Mar 2018 12:53:10 -0800 Subject: [PATCH 278/307] Update dependencies.props [auto-updated: dependencies] --- build/dependencies.props | 36 ++++++++++++++++++------------------ korebuild-lock.txt | 4 ++-- 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index fbba92b398..953d1cc1aa 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -3,25 +3,25 @@ $(MSBuildAllProjects);$(MSBuildThisFileFullPath) - 2.1.0-preview2-15721 - 2.1.0-preview2-30187 - 2.1.0-preview2-30187 - 2.1.0-preview2-30187 - 2.1.0-preview2-30187 - 2.1.0-preview2-30187 - 2.1.0-preview2-30187 - 2.1.0-preview2-30187 - 2.1.0-preview2-30187 - 2.1.0-preview2-30187 - 2.1.0-preview2-30187 - 2.1.0-preview2-30187 - 2.1.0-preview2-30187 - 2.1.0-preview2-30187 - 2.1.0-preview2-30187 - 2.1.0-preview2-30187 + 2.1.0-preview2-15728 + 2.1.0-preview2-30272 + 2.1.0-preview2-30272 + 2.1.0-preview2-30272 + 2.1.0-preview2-30272 + 2.1.0-preview2-30272 + 2.1.0-preview2-30272 + 2.1.0-preview2-30272 + 2.1.0-preview2-30272 + 2.1.0-preview2-30272 + 2.1.0-preview2-30272 + 2.1.0-preview2-30272 + 2.1.0-preview2-30272 + 2.1.0-preview2-30272 + 2.1.0-preview2-30272 + 2.1.0-preview2-30272 2.0.0 - 2.1.0-preview2-26130-04 - 2.1.0-preview2-30187 + 2.1.0-preview2-26225-03 + 2.1.0-preview2-30272 15.6.0 4.7.49 0.8.0 diff --git a/korebuild-lock.txt b/korebuild-lock.txt index e6c7fddffa..138d848db1 100644 --- a/korebuild-lock.txt +++ b/korebuild-lock.txt @@ -1,2 +1,2 @@ -version:2.1.0-preview2-15721 -commithash:f9bb4be59e39938ec59a6975257e26099b0d03c1 +version:2.1.0-preview2-15728 +commithash:393377068ddcf51dfee0536536d455f57a828b06 From 47c1e2ccdf7613687d1269fa5658b719aa7ad0f2 Mon Sep 17 00:00:00 2001 From: "Chris Ross (ASP.NET)" Date: Fri, 9 Mar 2018 11:02:05 -0800 Subject: [PATCH 279/307] React to CoreFx Stream changes --- build/dependencies.props | 34 +++++++------- .../BodyWrapperStreamTests.cs | 44 ++++--------------- 2 files changed, 26 insertions(+), 52 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index 953d1cc1aa..97d1862813 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -4,24 +4,24 @@ 2.1.0-preview2-15728 - 2.1.0-preview2-30272 - 2.1.0-preview2-30272 - 2.1.0-preview2-30272 - 2.1.0-preview2-30272 - 2.1.0-preview2-30272 - 2.1.0-preview2-30272 - 2.1.0-preview2-30272 - 2.1.0-preview2-30272 - 2.1.0-preview2-30272 - 2.1.0-preview2-30272 - 2.1.0-preview2-30272 - 2.1.0-preview2-30272 - 2.1.0-preview2-30272 - 2.1.0-preview2-30272 - 2.1.0-preview2-30272 + 2.1.0-preview2-30281 + 2.1.0-preview2-30281 + 2.1.0-preview2-30281 + 2.1.0-preview2-30281 + 2.1.0-preview2-30281 + 2.1.0-preview2-30281 + 2.1.0-preview2-30281 + 2.1.0-preview2-30281 + 2.1.0-preview2-30281 + 2.1.0-preview2-30281 + 2.1.0-preview2-30281 + 2.1.0-preview2-30281 + 2.1.0-preview2-30281 + 2.1.0-preview2-30281 + 2.1.0-preview2-30281 2.0.0 - 2.1.0-preview2-26225-03 - 2.1.0-preview2-30272 + 2.1.0-preview2-26308-01 + 2.1.0-preview2-30281 15.6.0 4.7.49 0.8.0 diff --git a/test/Microsoft.AspNetCore.ResponseCompression.Tests/BodyWrapperStreamTests.cs b/test/Microsoft.AspNetCore.ResponseCompression.Tests/BodyWrapperStreamTests.cs index 46c7fb46d3..4ffd70b745 100644 --- a/test/Microsoft.AspNetCore.ResponseCompression.Tests/BodyWrapperStreamTests.cs +++ b/test/Microsoft.AspNetCore.ResponseCompression.Tests/BodyWrapperStreamTests.cs @@ -65,47 +65,29 @@ namespace Microsoft.AspNetCore.ResponseCompression.Tests public async Task WriteAsync_IsPassedToUnderlyingStream_WhenDisableResponseBuffering(bool flushable) { var buffer = new byte[] { 1 }; - byte[] written = null; - var mock = new Mock(); - mock.SetupGet(s => s.CanWrite).Returns(true); - mock.Setup(s => s.WriteAsync(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) - .Callback((b, o, c, t) => - { - written = new ArraySegment(b, 0, c).ToArray(); - }) - .Returns(Task.FromResult(0)); - - var stream = new BodyWrapperStream(new DefaultHttpContext(), mock.Object, new MockResponseCompressionProvider(flushable), null, null); + var memoryStream = new MemoryStream(); + var stream = new BodyWrapperStream(new DefaultHttpContext(), memoryStream, new MockResponseCompressionProvider(flushable), null, null); stream.DisableResponseBuffering(); await stream.WriteAsync(buffer, 0, buffer.Length); - Assert.Equal(buffer, written); + Assert.Equal(buffer, memoryStream.ToArray()); } [Fact] public async Task SendFileAsync_IsPassedToUnderlyingStream_WhenDisableResponseBuffering() { - byte[] written = null; + var memoryStream = new MemoryStream(); - var mock = new Mock(); - mock.SetupGet(s => s.CanWrite).Returns(true); - mock.Setup(s => s.WriteAsync(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) - .Callback((b, o, c, t) => - { - written = new ArraySegment(b, 0, c).ToArray(); - }) - .Returns(Task.FromResult(0)); - - var stream = new BodyWrapperStream(new DefaultHttpContext(), mock.Object, new MockResponseCompressionProvider(true), null, null); + var stream = new BodyWrapperStream(new DefaultHttpContext(), memoryStream, new MockResponseCompressionProvider(true), null, null); stream.DisableResponseBuffering(); var path = "testfile1kb.txt"; await stream.SendFileAsync(path, 0, null, CancellationToken.None); - Assert.Equal(File.ReadAllBytes(path), written); + Assert.Equal(File.ReadAllBytes(path), memoryStream.ToArray()); } [Theory] @@ -114,23 +96,15 @@ namespace Microsoft.AspNetCore.ResponseCompression.Tests public void BeginWrite_IsPassedToUnderlyingStream_WhenDisableResponseBuffering(bool flushable) { var buffer = new byte[] { 1 }; - byte[] written = null; - var mock = new Mock(); - mock.SetupGet(s => s.CanWrite).Returns(true); - mock.Setup(s => s.WriteAsync(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) - .Callback((b, o, c, t) => - { - written = new ArraySegment(b, 0, c).ToArray(); - }) - .Returns(Task.FromResult(0)); + var memoryStream = new MemoryStream(); - var stream = new BodyWrapperStream(new DefaultHttpContext(), mock.Object, new MockResponseCompressionProvider(flushable), null, null); + var stream = new BodyWrapperStream(new DefaultHttpContext(), memoryStream, new MockResponseCompressionProvider(flushable), null, null); stream.DisableResponseBuffering(); stream.BeginWrite(buffer, 0, buffer.Length, (o) => {}, null); - Assert.Equal(buffer, written); + Assert.Equal(buffer, memoryStream.ToArray()); } private class MockResponseCompressionProvider: IResponseCompressionProvider From 8b58a9a0917315cef4aac6d0ffb44144d9df9bf1 Mon Sep 17 00:00:00 2001 From: "Chris Ross (ASP.NET)" Date: Fri, 12 Jan 2018 12:58:56 -0800 Subject: [PATCH 280/307] Scheme and Host value validation --- .../ForwardedHeadersMiddleware.cs | 165 +++++++++++- .../ForwardedHeadersMiddlewareTest.cs | 234 ++++++++++++++++++ 2 files changed, 395 insertions(+), 4 deletions(-) diff --git a/src/Microsoft.AspNetCore.HttpOverrides/ForwardedHeadersMiddleware.cs b/src/Microsoft.AspNetCore.HttpOverrides/ForwardedHeadersMiddleware.cs index 1863087c0e..d5e074de57 100644 --- a/src/Microsoft.AspNetCore.HttpOverrides/ForwardedHeadersMiddleware.cs +++ b/src/Microsoft.AspNetCore.HttpOverrides/ForwardedHeadersMiddleware.cs @@ -2,25 +2,63 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; -using System.Collections.Generic; using System.Linq; using System.Net; +using System.Runtime.CompilerServices; using System.Threading.Tasks; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.HttpOverrides.Internal; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; -using Microsoft.Extensions.Primitives; namespace Microsoft.AspNetCore.HttpOverrides { public class ForwardedHeadersMiddleware { + private static readonly bool[] HostCharValidity = new bool[127]; + private static readonly bool[] SchemeCharValidity = new bool[123]; + private readonly ForwardedHeadersOptions _options; private readonly RequestDelegate _next; private readonly ILogger _logger; + static ForwardedHeadersMiddleware() + { + // RFC 3986 scheme = ALPHA * (ALPHA / DIGIT / "+" / "-" / ".") + SchemeCharValidity['+'] = true; + SchemeCharValidity['-'] = true; + SchemeCharValidity['.'] = true; + + // Host Matches Http.Sys and Kestrel + // Host Matches RFC 3986 except "*" / "+" / "," / ";" / "=" and "%" HEXDIG HEXDIG which are not allowed by Http.Sys + HostCharValidity['!'] = true; + HostCharValidity['$'] = true; + HostCharValidity['&'] = true; + HostCharValidity['\''] = true; + HostCharValidity['('] = true; + HostCharValidity[')'] = true; + HostCharValidity['-'] = true; + HostCharValidity['.'] = true; + HostCharValidity['_'] = true; + HostCharValidity['~'] = true; + for (var ch = '0'; ch <= '9'; ch++) + { + SchemeCharValidity[ch] = true; + HostCharValidity[ch] = true; + } + for (var ch = 'A'; ch <= 'Z'; ch++) + { + SchemeCharValidity[ch] = true; + HostCharValidity[ch] = true; + } + for (var ch = 'a'; ch <= 'z'; ch++) + { + SchemeCharValidity[ch] = true; + HostCharValidity[ch] = true; + } + } + public ForwardedHeadersMiddleware(RequestDelegate next, ILoggerFactory loggerFactory, IOptions options) { if (next == null) @@ -179,7 +217,7 @@ namespace Microsoft.AspNetCore.HttpOverrides if (checkProto) { - if (!string.IsNullOrEmpty(set.Scheme)) + if (!string.IsNullOrEmpty(set.Scheme) && TryValidateScheme(set.Scheme)) { applyChanges = true; currentValues.Scheme = set.Scheme; @@ -193,7 +231,7 @@ namespace Microsoft.AspNetCore.HttpOverrides if (checkHost) { - if (!string.IsNullOrEmpty(set.Host)) + if (!string.IsNullOrEmpty(set.Host) && TryValidateHost(set.Host)) { applyChanges = true; currentValues.Host = set.Host; @@ -288,5 +326,124 @@ namespace Microsoft.AspNetCore.HttpOverrides public string Host; public string Scheme; } + + // Empty was checked for by the caller + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private bool TryValidateScheme(string scheme) + { + for (var i = 0; i < scheme.Length; i++) + { + if (!IsValidSchemeChar(scheme[i])) + { + return false; + } + } + return true; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static bool IsValidSchemeChar(char ch) + { + return ch < SchemeCharValidity.Length && SchemeCharValidity[ch]; + } + + // Empty was checked for by the caller + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private bool TryValidateHost(string host) + { + if (host[0] == '[') + { + return TryValidateIPv6Host(host); + } + + if (host[0] == ':') + { + // Only a port + return false; + } + + var i = 0; + for (; i < host.Length; i++) + { + if (!IsValidHostChar(host[i])) + { + break; + } + } + return TryValidateHostPort(host, i); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static bool IsValidHostChar(char ch) + { + return ch < HostCharValidity.Length && HostCharValidity[ch]; + } + + // The lead '[' was already checked + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private bool TryValidateIPv6Host(string hostText) + { + for (var i = 1; i < hostText.Length; i++) + { + var ch = hostText[i]; + if (ch == ']') + { + // [::1] is the shortest valid IPv6 host + if (i < 4) + { + return false; + } + return TryValidateHostPort(hostText, i + 1); + } + + if (!IsHex(ch) && ch != ':' && ch != '.') + { + return false; + } + } + + // Must contain a ']' + return false; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private bool TryValidateHostPort(string hostText, int offset) + { + if (offset == hostText.Length) + { + // No port + return true; + } + + if (hostText[offset] != ':' || hostText.Length == offset + 1) + { + // Must have at least one number after the colon if present. + return false; + } + + for (var i = offset + 1; i < hostText.Length; i++) + { + if (!IsNumeric(hostText[i])) + { + return false; + } + } + + return true; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private bool IsNumeric(char ch) + { + return '0' <= ch && ch <= '9'; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private bool IsHex(char ch) + { + return IsNumeric(ch) + || ('a' <= ch && ch <= 'f') + || ('A' <= ch && ch <= 'F'); + } } } diff --git a/test/Microsoft.AspNetCore.HttpOverrides.Tests/ForwardedHeadersMiddlewareTest.cs b/test/Microsoft.AspNetCore.HttpOverrides.Tests/ForwardedHeadersMiddlewareTest.cs index ea905dace0..81d6ccf15a 100644 --- a/test/Microsoft.AspNetCore.HttpOverrides.Tests/ForwardedHeadersMiddlewareTest.cs +++ b/test/Microsoft.AspNetCore.HttpOverrides.Tests/ForwardedHeadersMiddlewareTest.cs @@ -252,6 +252,146 @@ namespace Microsoft.AspNetCore.HttpOverrides Assert.Equal("testhost", context.Request.Host.ToString()); } + public static TheoryData HostHeaderData + { + get + { + return new TheoryData() { + "z", + "1", + "y:1", + "1:1", + "[ABCdef]", + "[abcDEF]:0", + "[abcdef:127.2355.1246.114]:0", + "[::1]:80", + "127.0.0.1:80", + "900.900.900.900:9523547852", + "foo", + "foo:234", + "foo.bar.baz", + "foo.BAR.baz:46245", + "foo.ba-ar.baz:46245", + "-foo:1234", + "xn--c1yn36f:134", + "-", + "_", + "~", + "!", + "$", + "'", + "(", + ")", + }; + } + } + + [Theory] + [MemberData(nameof(HostHeaderData))] + public async Task XForwardedHostAllowsValidCharacters(string host) + { + var assertsExecuted = false; + + var builder = new WebHostBuilder() + .Configure(app => + { + app.UseForwardedHeaders(new ForwardedHeadersOptions + { + ForwardedHeaders = ForwardedHeaders.XForwardedHost + }); + app.Run(context => + { + Assert.Equal(host, context.Request.Host.ToString()); + assertsExecuted = true; + return Task.FromResult(0); + }); + }); + var server = new TestServer(builder); + + await server.SendAsync(c => + { + c.Request.Headers["X-Forwarded-Host"] = host; + }); + Assert.True(assertsExecuted); + } + + public static TheoryData HostHeaderInvalidData + { + get + { + // see https://tools.ietf.org/html/rfc7230#section-5.4 + var data = new TheoryData() { + "", // Empty + "[]", // Too short + "[::]", // Too short + "[ghijkl]", // Non-hex + "[afd:adf:123", // Incomplete + "[afd:adf]123", // Missing : + "[afd:adf]:", // Missing port digits + "[afd adf]", // Space + "[ad-314]", // dash + ":1234", // Missing host + "a:b:c", // Missing [] + "::1", // Missing [] + "::", // Missing everything + "abcd:1abcd", // Letters in port + "abcd:1.2", // Dot in port + "1.2.3.4:", // Missing port digits + "1.2 .4", // Space + }; + + // These aren't allowed anywhere in the host header + var invalid = "\"#%*+/;<=>?@[]\\^`{}|"; + foreach (var ch in invalid) + { + data.Add(ch.ToString()); + } + + invalid = "!\"#$%&'()*+,/;<=>?@[]\\^_`{}|~-"; + foreach (var ch in invalid) + { + data.Add("[abd" + ch + "]:1234"); + } + + invalid = "!\"#$%&'()*+/;<=>?@[]\\^_`{}|~:abcABC-."; + foreach (var ch in invalid) + { + data.Add("a.b.c:" + ch); + } + + return data; + } + } + + [Theory] + [MemberData(nameof(HostHeaderInvalidData))] + public async Task XForwardedHostFailsForInvalidCharacters(string host) + { + var assertsExecuted = false; + + var builder = new WebHostBuilder() + .Configure(app => + { + app.UseForwardedHeaders(new ForwardedHeadersOptions + { + ForwardedHeaders = ForwardedHeaders.XForwardedHost + }); + app.Run(context => + { + Assert.NotEqual(host, context.Request.Host.Value); + assertsExecuted = true; + return Task.FromResult(0); + }); + }); + var server = new TestServer(builder); + + await server.SendAsync(c => + { + c.Request.Headers["X-Forwarded-Host"] = host; + }); + Assert.True(assertsExecuted); + } + [Theory] [InlineData(0, "h1", "http")] [InlineData(1, "", "http")] @@ -281,6 +421,100 @@ namespace Microsoft.AspNetCore.HttpOverrides Assert.Equal(expected, context.Request.Scheme); } + public static TheoryData ProtoHeaderData + { + get + { + // ALPHA *( ALPHA / DIGIT / "+" / "-" / "." ) + return new TheoryData() { + "z", + "Z", + "1", + "y+", + "1-", + "a.", + }; + } + } + + [Theory] + [MemberData(nameof(ProtoHeaderData))] + public async Task XForwardedProtoAcceptsValidProtocols(string scheme) + { + var assertsExecuted = false; + + var builder = new WebHostBuilder() + .Configure(app => + { + app.UseForwardedHeaders(new ForwardedHeadersOptions + { + ForwardedHeaders = ForwardedHeaders.XForwardedProto + }); + app.Run(context => + { + Assert.Equal(scheme, context.Request.Scheme); + assertsExecuted = true; + return Task.FromResult(0); + }); + }); + var server = new TestServer(builder); + + await server.SendAsync(c => + { + c.Request.Headers["X-Forwarded-Proto"] = scheme; + }); + Assert.True(assertsExecuted); + } + + public static TheoryData ProtoHeaderInvalidData + { + get + { + // ALPHA *( ALPHA / DIGIT / "+" / "-" / "." ) + var data = new TheoryData() { + "a b", // Space + }; + + // These aren't allowed anywhere in the scheme header + var invalid = "!\"#$%&'()*/:;<=>?@[]\\^_`{}|~"; + foreach (var ch in invalid) + { + data.Add(ch.ToString()); + } + + return data; + } + } + + [Theory] + [MemberData(nameof(ProtoHeaderInvalidData))] + public async Task XForwardedProtoRejectsInvalidProtocols(string scheme) + { + var assertsExecuted = false; + + var builder = new WebHostBuilder() + .Configure(app => + { + app.UseForwardedHeaders(new ForwardedHeadersOptions + { + ForwardedHeaders = ForwardedHeaders.XForwardedProto, + }); + app.Run(context => + { + Assert.Equal("http", context.Request.Scheme); + assertsExecuted = true; + return Task.FromResult(0); + }); + }); + var server = new TestServer(builder); + + await server.SendAsync(c => + { + c.Request.Headers["X-Forwarded-Proto"] = scheme; + }); + Assert.True(assertsExecuted); + } + [Theory] [InlineData(0, "h1", "::1", "http")] [InlineData(1, "", "::1", "http")] From 2b80c905549110c312644400b7eea32119009710 Mon Sep 17 00:00:00 2001 From: "Chris Ross (ASP.NET)" Date: Mon, 5 Feb 2018 15:38:55 -0800 Subject: [PATCH 281/307] Add host filtering middleware --- BasicMiddleware.sln | 31 ++- build/dependencies.props | 1 + .../HostFilteringSample.csproj | 29 +++ samples/HostFilteringSample/Program.cs | 37 ++++ .../Properties/launchSettings.json | 27 +++ samples/HostFilteringSample/Startup.cs | 41 ++++ .../appsettings.Development.json | 3 + .../appsettings.Production.json | 3 + samples/HostFilteringSample/appsettings.json | 3 + .../HostFilteringBuilderExtensions.cs | 32 +++ .../HostFilteringMiddleware.cs | 166 ++++++++++++++++ .../HostFilteringOptions.cs | 44 +++++ .../HostFilteringServicesExtensions.cs | 36 ++++ .../Microsoft.AspNetCore.HostFiltering.csproj | 18 ++ .../ForwardedHeadersMiddleware.cs | 46 ++++- .../ForwardedHeadersOptions.cs | 16 ++ .../HttpsRedirectionBuilderExtensions.cs | 8 +- .../HostFilteringMiddlewareTests.cs | 183 ++++++++++++++++++ ...soft.AspNetCore.HostFiltering.Tests.csproj | 11 ++ .../ForwardedHeadersMiddlewareTest.cs | 115 +++++++++++ .../HttpsRedirectionMiddlewareTests.cs | 33 +--- 21 files changed, 845 insertions(+), 38 deletions(-) create mode 100644 samples/HostFilteringSample/HostFilteringSample.csproj create mode 100644 samples/HostFilteringSample/Program.cs create mode 100644 samples/HostFilteringSample/Properties/launchSettings.json create mode 100644 samples/HostFilteringSample/Startup.cs create mode 100644 samples/HostFilteringSample/appsettings.Development.json create mode 100644 samples/HostFilteringSample/appsettings.Production.json create mode 100644 samples/HostFilteringSample/appsettings.json create mode 100644 src/Microsoft.AspNetCore.HostFiltering/HostFilteringBuilderExtensions.cs create mode 100644 src/Microsoft.AspNetCore.HostFiltering/HostFilteringMiddleware.cs create mode 100644 src/Microsoft.AspNetCore.HostFiltering/HostFilteringOptions.cs create mode 100644 src/Microsoft.AspNetCore.HostFiltering/HostFilteringServicesExtensions.cs create mode 100644 src/Microsoft.AspNetCore.HostFiltering/Microsoft.AspNetCore.HostFiltering.csproj create mode 100644 test/Microsoft.AspNetCore.HostFiltering.Tests/HostFilteringMiddlewareTests.cs create mode 100644 test/Microsoft.AspNetCore.HostFiltering.Tests/Microsoft.AspNetCore.HostFiltering.Tests.csproj diff --git a/BasicMiddleware.sln b/BasicMiddleware.sln index a4452cd103..8810201f5a 100644 --- a/BasicMiddleware.sln +++ b/BasicMiddleware.sln @@ -1,6 +1,6 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 15 -VisualStudioVersion = 15.0.26817.0 +VisualStudioVersion = 15.0.27130.2027 MinimumVisualStudioVersion = 15.0.26730.03 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.HttpOverrides", "src\Microsoft.AspNetCore.HttpOverrides\Microsoft.AspNetCore.HttpOverrides.csproj", "{517308C3-B477-4B01-B461-CAB9C10B6928}" EndProject @@ -63,6 +63,19 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "HttpsPolicySample", "sample EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.HttpsPolicy.Tests", "test\Microsoft.AspNetCore.HttpsPolicy.Tests\Microsoft.AspNetCore.HttpsPolicy.Tests.csproj", "{1C67B0F1-6E70-449E-A2F1-98B9D5C576CE}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "HostFilteringSample", "samples\HostFilteringSample\HostFilteringSample.csproj", "{368B00A2-992A-4B0E-9085-A8136A22922D}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "build", "build", "{5CEA6F31-A829-4A02-8CD5-EC3DDD4CC1EA}" + ProjectSection(SolutionItems) = preProject + build\dependencies.props = build\dependencies.props + build\repo.props = build\repo.props + build\sources.props = build\sources.props + EndProjectSection +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.HostFiltering.Tests", "test\Microsoft.AspNetCore.HostFiltering.Tests\Microsoft.AspNetCore.HostFiltering.Tests.csproj", "{4BC947ED-13B8-4BE6-82A4-96A48D86980B}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.HostFiltering", "src\Microsoft.AspNetCore.HostFiltering\Microsoft.AspNetCore.HostFiltering.csproj", "{762F7276-C916-4111-A6C0-41668ABB3823}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -129,6 +142,18 @@ Global {1C67B0F1-6E70-449E-A2F1-98B9D5C576CE}.Debug|Any CPU.Build.0 = Debug|Any CPU {1C67B0F1-6E70-449E-A2F1-98B9D5C576CE}.Release|Any CPU.ActiveCfg = Release|Any CPU {1C67B0F1-6E70-449E-A2F1-98B9D5C576CE}.Release|Any CPU.Build.0 = Release|Any CPU + {368B00A2-992A-4B0E-9085-A8136A22922D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {368B00A2-992A-4B0E-9085-A8136A22922D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {368B00A2-992A-4B0E-9085-A8136A22922D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {368B00A2-992A-4B0E-9085-A8136A22922D}.Release|Any CPU.Build.0 = Release|Any CPU + {4BC947ED-13B8-4BE6-82A4-96A48D86980B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {4BC947ED-13B8-4BE6-82A4-96A48D86980B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {4BC947ED-13B8-4BE6-82A4-96A48D86980B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {4BC947ED-13B8-4BE6-82A4-96A48D86980B}.Release|Any CPU.Build.0 = Release|Any CPU + {762F7276-C916-4111-A6C0-41668ABB3823}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {762F7276-C916-4111-A6C0-41668ABB3823}.Debug|Any CPU.Build.0 = Debug|Any CPU + {762F7276-C916-4111-A6C0-41668ABB3823}.Release|Any CPU.ActiveCfg = Release|Any CPU + {762F7276-C916-4111-A6C0-41668ABB3823}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -149,6 +174,10 @@ Global {4D39C29B-4EC8-497C-B411-922DA494D71B} = {A5076D28-FA7E-4606-9410-FEDD0D603527} {AC424AEE-4883-49C6-945F-2FC916B8CA1C} = {9587FE9F-5A17-42C4-8021-E87F59CECB98} {1C67B0F1-6E70-449E-A2F1-98B9D5C576CE} = {8437B0F3-3894-4828-A945-A9187F37631D} + {368B00A2-992A-4B0E-9085-A8136A22922D} = {9587FE9F-5A17-42C4-8021-E87F59CECB98} + {5CEA6F31-A829-4A02-8CD5-EC3DDD4CC1EA} = {59A9B64C-E9BE-409E-89A2-58D72E2918F5} + {4BC947ED-13B8-4BE6-82A4-96A48D86980B} = {8437B0F3-3894-4828-A945-A9187F37631D} + {762F7276-C916-4111-A6C0-41668ABB3823} = {A5076D28-FA7E-4606-9410-FEDD0D603527} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {4518E9CE-3680-4E05-9259-B64EA7807158} diff --git a/build/dependencies.props b/build/dependencies.props index 97d1862813..4dadaa5ffa 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -14,6 +14,7 @@ 2.1.0-preview2-30281 2.1.0-preview2-30281 2.1.0-preview2-30281 + 2.1.0-preview2-30281 2.1.0-preview2-30281 2.1.0-preview2-30281 2.1.0-preview2-30281 diff --git a/samples/HostFilteringSample/HostFilteringSample.csproj b/samples/HostFilteringSample/HostFilteringSample.csproj new file mode 100644 index 0000000000..7818be1fb0 --- /dev/null +++ b/samples/HostFilteringSample/HostFilteringSample.csproj @@ -0,0 +1,29 @@ + + + + netcoreapp2.1;net461 + + + + + + + + + + + + + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + + diff --git a/samples/HostFilteringSample/Program.cs b/samples/HostFilteringSample/Program.cs new file mode 100644 index 0000000000..0d4ffa9324 --- /dev/null +++ b/samples/HostFilteringSample/Program.cs @@ -0,0 +1,37 @@ +// 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 Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Logging; + +namespace HostFilteringSample +{ + public class Program + { + public static void Main(string[] args) + { + BuildWebHost(args).Run(); + } + + public static IWebHost BuildWebHost(string[] args) + { + var hostBuilder = new WebHostBuilder() + .ConfigureLogging((_, factory) => + { + factory.SetMinimumLevel(LogLevel.Debug); + factory.AddConsole(); + }) + .ConfigureAppConfiguration((hostingContext, config) => + { + var env = hostingContext.HostingEnvironment; + config.AddJsonFile("appsettings.json", optional: true) + .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true); + }) + .UseKestrel() + .UseStartup(); + + return hostBuilder.Build(); + } + } +} diff --git a/samples/HostFilteringSample/Properties/launchSettings.json b/samples/HostFilteringSample/Properties/launchSettings.json new file mode 100644 index 0000000000..a0ee1d227c --- /dev/null +++ b/samples/HostFilteringSample/Properties/launchSettings.json @@ -0,0 +1,27 @@ +{ + "iisSettings": { + "windowsAuthentication": false, + "anonymousAuthentication": true, + "iisExpress": { + "applicationUrl": "http://localhost:14124/", + "sslPort": 0 + } + }, + "profiles": { + "IIS Express": { + "commandName": "IISExpress", + "launchBrowser": true, + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + }, + "HostFilteringSample": { + "commandName": "Project", + "launchBrowser": true, + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + }, + "applicationUrl": "http://localhost:14125/" + } + } +} \ No newline at end of file diff --git a/samples/HostFilteringSample/Startup.cs b/samples/HostFilteringSample/Startup.cs new file mode 100644 index 0000000000..93c217b71c --- /dev/null +++ b/samples/HostFilteringSample/Startup.cs @@ -0,0 +1,41 @@ +// 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.Collections.Generic; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; + +namespace HostFilteringSample +{ + public class Startup + { + public IConfiguration Config { get; } + + public Startup(IConfiguration config) + { + Config = config; + } + + public void ConfigureServices(IServiceCollection services) + { + services.AddHostFiltering(options => + { + // If this is excluded then it will fall back to the server's addresses + options.AllowedHosts = Config.GetSection("AllowedHosts").Get>(); + }); + } + + public void Configure(IApplicationBuilder app, IHostingEnvironment env) + { + app.UseHostFiltering(); + + app.Run(context => + { + return context.Response.WriteAsync("Hello World! " + context.Request.Host); + }); + } + } +} diff --git a/samples/HostFilteringSample/appsettings.Development.json b/samples/HostFilteringSample/appsettings.Development.json new file mode 100644 index 0000000000..7c2d8e26dc --- /dev/null +++ b/samples/HostFilteringSample/appsettings.Development.json @@ -0,0 +1,3 @@ +{ + "AllowedHosts": [ "localhost", "127.0.0.1", "[::1]" ] +} diff --git a/samples/HostFilteringSample/appsettings.Production.json b/samples/HostFilteringSample/appsettings.Production.json new file mode 100644 index 0000000000..f2fc90c390 --- /dev/null +++ b/samples/HostFilteringSample/appsettings.Production.json @@ -0,0 +1,3 @@ +{ + "AllowedHosts": [ "example.com", "localhost" ] +} diff --git a/samples/HostFilteringSample/appsettings.json b/samples/HostFilteringSample/appsettings.json new file mode 100644 index 0000000000..29091fa582 --- /dev/null +++ b/samples/HostFilteringSample/appsettings.json @@ -0,0 +1,3 @@ +{ + +} \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.HostFiltering/HostFilteringBuilderExtensions.cs b/src/Microsoft.AspNetCore.HostFiltering/HostFilteringBuilderExtensions.cs new file mode 100644 index 0000000000..b8722de1c7 --- /dev/null +++ b/src/Microsoft.AspNetCore.HostFiltering/HostFilteringBuilderExtensions.cs @@ -0,0 +1,32 @@ +// 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; +using Microsoft.AspNetCore.HostFiltering; + +namespace Microsoft.AspNetCore.Builder +{ + /// + /// Extension methods for the HostFiltering middleware. + /// + public static class HostFilteringBuilderExtensions + { + /// + /// Adds middleware for filtering requests by allowed host headers. Invalid requests will be rejected with a + /// 400 status code. + /// + /// The instance this method extends. + /// The original . + public static IApplicationBuilder UseHostFiltering(this IApplicationBuilder app) + { + if (app == null) + { + throw new ArgumentNullException(nameof(app)); + } + + app.UseMiddleware(); + + return app; + } + } +} diff --git a/src/Microsoft.AspNetCore.HostFiltering/HostFilteringMiddleware.cs b/src/Microsoft.AspNetCore.HostFiltering/HostFilteringMiddleware.cs new file mode 100644 index 0000000000..e1e38eca37 --- /dev/null +++ b/src/Microsoft.AspNetCore.HostFiltering/HostFilteringMiddleware.cs @@ -0,0 +1,166 @@ +// 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; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; +using Microsoft.Extensions.Primitives; +using Microsoft.Net.Http.Headers; + +namespace Microsoft.AspNetCore.HostFiltering +{ + /// + /// A middleware used to filter requests by their Host header. + /// + public class HostFilteringMiddleware + { + // Matches Http.Sys. + private static readonly byte[] DefaultResponse = Encoding.ASCII.GetBytes( + "\r\n" + + "Bad Request\r\n" + + "\r\n" + + "

Bad Request - Invalid Hostname

\r\n" + + "

HTTP Error 400. The request hostname is invalid.

\r\n" + + ""); + + private readonly RequestDelegate _next; + private readonly ILogger _logger; + private readonly HostFilteringOptions _options; + private IList _allowedHosts; + private bool? _allowAnyNonEmptyHost; + + /// + /// A middleware used to filter requests by their Host header. + /// + /// + /// + /// + public HostFilteringMiddleware(RequestDelegate next, ILogger logger, + IOptions options) + { + _next = next ?? throw new ArgumentNullException(nameof(next)); + _logger = logger ?? throw new ArgumentNullException(nameof(logger)); + _options = options?.Value ?? throw new ArgumentNullException(nameof(options)); + } + + /// + /// Processes requests + /// + /// + /// + public Task Invoke(HttpContext context) + { + EnsureConfigured(); + + if (!CheckHost(context)) + { + context.Response.StatusCode = 400; + if (_options.IncludeFailureMessage) + { + context.Response.ContentLength = DefaultResponse.Length; + context.Response.ContentType = "text/html"; + return context.Response.Body.WriteAsync(DefaultResponse, 0, DefaultResponse.Length); + } + return Task.CompletedTask; + } + + return _next(context); + } + + private void EnsureConfigured() + { + if (_allowAnyNonEmptyHost == true || _allowedHosts?.Count > 0) + { + return; + } + + var allowedHosts = new List(); + if (_options.AllowedHosts?.Count > 0 && !TryProcessHosts(_options.AllowedHosts, allowedHosts)) + { + _logger.LogDebug("Wildcard detected, all requests with hosts will be allowed."); + _allowAnyNonEmptyHost = true; + return; + } + + if (allowedHosts.Count == 0) + { + throw new InvalidOperationException("No allowed hosts were configured."); + } + + _logger.LogDebug("Allowed hosts: " + string.Join("; ", allowedHosts)); + _allowedHosts = allowedHosts; + } + + // returns false if any wildcards were found + private bool TryProcessHosts(IEnumerable incoming, IList results) + { + foreach (var entry in incoming) + { + // Punycode. Http.Sys requires you to register Unicode hosts, but the headers contain punycode. + var host = new HostString(entry).ToUriComponent(); + + if (IsTopLevelWildcard(host)) + { + // Disable filtering + return false; + } + + if (!results.Contains(host, StringSegmentComparer.OrdinalIgnoreCase)) + { + results.Add(host); + } + } + + return true; + } + + private bool IsTopLevelWildcard(string host) + { + return (string.Equals("*", host, StringComparison.Ordinal) // HttpSys wildcard + || string.Equals("[::]", host, StringComparison.Ordinal) // Kestrel wildcard, IPv6 Any + || string.Equals("0.0.0.0", host, StringComparison.Ordinal)); // IPv4 Any + } + + // This does not duplicate format validations that are expected to be performed by the host. + private bool CheckHost(HttpContext context) + { + var host = new StringSegment(context.Request.Headers[HeaderNames.Host].ToString()).Trim(); + + if (StringSegment.IsNullOrEmpty(host)) + { + // Http/1.0 does not require the host header. + // Http/1.1 requires the header but the value may be empty. + if (!_options.AllowEmptyHosts) + { + _logger.LogInformation($"{context.Request.Protocol} request rejected due to missing or empty host header."); + return false; + } + if (_logger.IsEnabled(LogLevel.Debug)) + { + _logger.LogDebug($"{context.Request.Protocol} request allowed with missing or empty host header."); + } + return true; + } + + if (_allowAnyNonEmptyHost == true) + { + _logger.LogTrace($"All hosts are allowed."); + return true; + } + + if (HostString.MatchesAny(host, _allowedHosts)) + { + _logger.LogTrace($"The host '{host}' matches an allowed host."); + return true; + } + + _logger.LogInformation($"The host '{host}' does not match an allowed host."); + return false; + } + } +} diff --git a/src/Microsoft.AspNetCore.HostFiltering/HostFilteringOptions.cs b/src/Microsoft.AspNetCore.HostFiltering/HostFilteringOptions.cs new file mode 100644 index 0000000000..1645591579 --- /dev/null +++ b/src/Microsoft.AspNetCore.HostFiltering/HostFilteringOptions.cs @@ -0,0 +1,44 @@ +// 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.Collections.Generic; + +namespace Microsoft.AspNetCore.HostFiltering +{ + /// + /// Options for the HostFiltering middleware + /// + public class HostFilteringOptions + { + /// + /// The hosts headers that are allowed to access this site. At least one value is required. + /// + /// + /// + /// Port numbers must be excluded. + /// A top level wildcard "*" allows all non-empty hosts. + /// Subdomain wildcards are permitted. E.g. "*.example.com" matches subdomains like foo.example.com, + /// but not the parent domain example.com. + /// Unicode host names are allowed but will be converted to punycode for matching. + /// IPv6 addresses must include their bounding brackets and be in their normalized form. + /// + /// + public IList AllowedHosts { get; set; } = new List(); + + /// + /// Indicates if requests without hosts are allowed. The default is true. + /// + /// + /// HTTP/1.0 does not require a host header. + /// Http/1.1 requires a host header, but says the value may be empty. + /// + public bool AllowEmptyHosts { get; set; } = true; + + // Note if this were disabled then things like the status code middleware may try to re-execute + // the request. This is a low level protocol violation, pretty error pages should not be required. + /// + /// Indicates if the 400 response should include a default message or be empty. This is enabled by default. + /// + public bool IncludeFailureMessage { get; set; } = true; + } +} diff --git a/src/Microsoft.AspNetCore.HostFiltering/HostFilteringServicesExtensions.cs b/src/Microsoft.AspNetCore.HostFiltering/HostFilteringServicesExtensions.cs new file mode 100644 index 0000000000..81b48444a8 --- /dev/null +++ b/src/Microsoft.AspNetCore.HostFiltering/HostFilteringServicesExtensions.cs @@ -0,0 +1,36 @@ +// 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; +using Microsoft.AspNetCore.HostFiltering; +using Microsoft.Extensions.DependencyInjection; + +namespace Microsoft.AspNetCore.Builder +{ + /// + /// Extension methods for the host filtering middleware. + /// + public static class HostFilteringServicesExtensions + { + /// + /// Adds services and options for the host filtering middleware. + /// + /// The for adding services. + /// A delegate to configure the . + /// + public static IServiceCollection AddHostFiltering(this IServiceCollection services, Action configureOptions) + { + if (services == null) + { + throw new ArgumentNullException(nameof(services)); + } + if (configureOptions == null) + { + throw new ArgumentNullException(nameof(configureOptions)); + } + + services.Configure(configureOptions); + return services; + } + } +} diff --git a/src/Microsoft.AspNetCore.HostFiltering/Microsoft.AspNetCore.HostFiltering.csproj b/src/Microsoft.AspNetCore.HostFiltering/Microsoft.AspNetCore.HostFiltering.csproj new file mode 100644 index 0000000000..ec6d642340 --- /dev/null +++ b/src/Microsoft.AspNetCore.HostFiltering/Microsoft.AspNetCore.HostFiltering.csproj @@ -0,0 +1,18 @@ + + + + + ASP.NET Core middleware for filtering out requests with unknown HTTP host headers. + + netstandard2.0 + true + aspnetcore + + + + + + + + + diff --git a/src/Microsoft.AspNetCore.HttpOverrides/ForwardedHeadersMiddleware.cs b/src/Microsoft.AspNetCore.HttpOverrides/ForwardedHeadersMiddleware.cs index d5e074de57..decda81d58 100644 --- a/src/Microsoft.AspNetCore.HttpOverrides/ForwardedHeadersMiddleware.cs +++ b/src/Microsoft.AspNetCore.HttpOverrides/ForwardedHeadersMiddleware.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; +using System.Collections.Generic; using System.Linq; using System.Net; using System.Runtime.CompilerServices; @@ -11,6 +12,7 @@ using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.HttpOverrides.Internal; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; +using Microsoft.Extensions.Primitives; namespace Microsoft.AspNetCore.HttpOverrides { @@ -22,6 +24,8 @@ namespace Microsoft.AspNetCore.HttpOverrides private readonly ForwardedHeadersOptions _options; private readonly RequestDelegate _next; private readonly ILogger _logger; + private bool _allowAllHosts; + private IList _allowedHosts; static ForwardedHeadersMiddleware() { @@ -85,6 +89,8 @@ namespace Microsoft.AspNetCore.HttpOverrides _options = options.Value; _logger = loggerFactory.CreateLogger(); _next = next; + + PreProcessHosts(); } private static void EnsureOptionNotNullorWhitespace(string value, string propertyName) @@ -95,6 +101,43 @@ namespace Microsoft.AspNetCore.HttpOverrides } } + private void PreProcessHosts() + { + if (_options.AllowedHosts == null || _options.AllowedHosts.Count == 0) + { + _allowAllHosts = true; + return; + } + + var allowedHosts = new List(); + foreach (var entry in _options.AllowedHosts) + { + // Punycode. Http.Sys requires you to register Unicode hosts, but the headers contain punycode. + var host = new HostString(entry).ToUriComponent(); + + if (IsTopLevelWildcard(host)) + { + // Disable filtering + _allowAllHosts = true; + return; + } + + if (!allowedHosts.Contains(host, StringSegmentComparer.OrdinalIgnoreCase)) + { + allowedHosts.Add(host); + } + } + + _allowedHosts = allowedHosts; + } + + private bool IsTopLevelWildcard(string host) + { + return (string.Equals("*", host, StringComparison.Ordinal) // HttpSys wildcard + || string.Equals("[::]", host, StringComparison.Ordinal) // Kestrel wildcard, IPv6 Any + || string.Equals("0.0.0.0", host, StringComparison.Ordinal)); // IPv4 Any + } + public Task Invoke(HttpContext context) { ApplyForwarders(context); @@ -231,7 +274,8 @@ namespace Microsoft.AspNetCore.HttpOverrides if (checkHost) { - if (!string.IsNullOrEmpty(set.Host) && TryValidateHost(set.Host)) + if (!string.IsNullOrEmpty(set.Host) && TryValidateHost(set.Host) + && (_allowAllHosts || HostString.MatchesAny(set.Host, _allowedHosts))) { applyChanges = true; currentValues.Host = set.Host; diff --git a/src/Microsoft.AspNetCore.HttpOverrides/ForwardedHeadersOptions.cs b/src/Microsoft.AspNetCore.HttpOverrides/ForwardedHeadersOptions.cs index cbe00baaa1..3507d9bea5 100644 --- a/src/Microsoft.AspNetCore.HttpOverrides/ForwardedHeadersOptions.cs +++ b/src/Microsoft.AspNetCore.HttpOverrides/ForwardedHeadersOptions.cs @@ -67,6 +67,22 @@ namespace Microsoft.AspNetCore.Builder ///
public IList KnownNetworks { get; } = new List() { new IPNetwork(IPAddress.Loopback, 8) }; + /// + /// The allowed values from x-forwarded-host. If the list is empty then all hosts are allowed. + /// Failing to restrict this these values may allow an attacker to spoof links generated by your service. + /// + /// + /// + /// Port numbers must be excluded. + /// A top level wildcard "*" allows all non-empty hosts. + /// Subdomain wildcards are permitted. E.g. "*.example.com" matches subdomains like foo.example.com, + /// but not the parent domain example.com. + /// Unicode host names are allowed but will be converted to punycode for matching. + /// IPv6 addresses must include their bounding brackets and be in their normalized form. + /// + /// + public IList AllowedHosts { get; set; } = new List(); + /// /// Require the number of header values to be in sync between the different headers being processed. /// The default is 'false'. diff --git a/src/Microsoft.AspNetCore.HttpsPolicy/HttpsRedirectionBuilderExtensions.cs b/src/Microsoft.AspNetCore.HttpsPolicy/HttpsRedirectionBuilderExtensions.cs index 429f0f0ee2..c6f804763f 100644 --- a/src/Microsoft.AspNetCore.HttpsPolicy/HttpsRedirectionBuilderExtensions.cs +++ b/src/Microsoft.AspNetCore.HttpsPolicy/HttpsRedirectionBuilderExtensions.cs @@ -2,11 +2,9 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; +using System.Collections.Generic; using Microsoft.AspNetCore.Hosting.Server.Features; using Microsoft.AspNetCore.HttpsPolicy; -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Options; namespace Microsoft.AspNetCore.Builder { @@ -20,15 +18,13 @@ namespace Microsoft.AspNetCore.Builder /// /// The instance this method extends. /// The for HttpsRedirection. - /// - /// HTTPS Enforcement interanlly uses the UrlRewrite middleware to redirect HTTP requests to HTTPS. - /// public static IApplicationBuilder UseHttpsRedirection(this IApplicationBuilder app) { if (app == null) { throw new ArgumentNullException(nameof(app)); } + var serverAddressFeature = app.ServerFeatures.Get(); if (serverAddressFeature != null) { diff --git a/test/Microsoft.AspNetCore.HostFiltering.Tests/HostFilteringMiddlewareTests.cs b/test/Microsoft.AspNetCore.HostFiltering.Tests/HostFilteringMiddlewareTests.cs new file mode 100644 index 0000000000..2fc7b8c713 --- /dev/null +++ b/test/Microsoft.AspNetCore.HostFiltering.Tests/HostFilteringMiddlewareTests.cs @@ -0,0 +1,183 @@ +// 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; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.TestHost; +using Microsoft.Extensions.Primitives; +using Microsoft.Net.Http.Headers; +using Xunit; + +namespace Microsoft.AspNetCore.HostFiltering +{ + public class HostFilteringMiddlewareTests + { + [Fact] + public async Task MissingConfigThrows() + { + var builder = new WebHostBuilder() + .Configure(app => + { + app.UseHostFiltering(); + }); + await Assert.ThrowsAsync(() => new TestServer(builder).SendAsync(_ => { })); + } + + [Theory] + [InlineData(true, 200)] + [InlineData(false, 400)] + public async Task AllowsMissingHost(bool allowed, int status) + { + var builder = new WebHostBuilder() + .ConfigureServices(services => + { + services.AddHostFiltering(options => + { + options.AllowEmptyHosts = allowed; + options.AllowedHosts.Add("Localhost"); + }); + }) + .Configure(app => + { + app.Use((ctx, next) => + { + ctx.Request.Headers.Remove(HeaderNames.Host); + return next(); + }); + app.UseHostFiltering(); + app.Run(c => + { + Assert.False(c.Request.Headers.TryGetValue(HeaderNames.Host, out var host)); + return Task.CompletedTask; + }); + }); + var server = new TestServer(builder); + var response = await server.CreateClient().GetAsync("/"); + Assert.Equal(status, (int)response.StatusCode); + } + + [Theory] + [InlineData(true, 200)] + [InlineData(false, 400)] + public async Task AllowsEmptyHost(bool allowed, int status) + { + var builder = new WebHostBuilder() + .ConfigureServices(services => + { + services.AddHostFiltering(options => + { + options.AllowEmptyHosts = allowed; + options.AllowedHosts.Add("Localhost"); + }); + }) + .Configure(app => + { + app.Use((ctx, next) => + { + ctx.Request.Headers[HeaderNames.Host] = " "; + return next(); + }); + app.UseHostFiltering(); + app.Run(c => + { + Assert.True(c.Request.Headers.TryGetValue(HeaderNames.Host, out var host)); + Assert.True(StringValues.Equals(" ", host)); + return Task.CompletedTask; + }); + app.Run(c => Task.CompletedTask); + }); + var server = new TestServer(builder); + var response = await server.CreateClient().GetAsync("/"); + Assert.Equal(status, (int)response.StatusCode); + } + + [Theory] + [InlineData("localHost", "localhost")] + [InlineData("localHost", "*")] // Any - Used by HttpSys + [InlineData("localHost", "[::]")] // IPv6 Any - This is what Kestrel reports when binding to * + [InlineData("localHost", "0.0.0.0")] // IPv4 Any + [InlineData("localhost:9090", "example.com;localHost")] + [InlineData("example.com:443", "example.com;localhost")] + [InlineData("localHost:80", "localhost;")] + [InlineData("foo.eXample.com:443", "*.exampLe.com")] + [InlineData("f.eXample.com:443", "*.exampLe.com")] + [InlineData("127.0.0.1", "127.0.0.1")] + [InlineData("127.0.0.1:443", "127.0.0.1")] + [InlineData("xn--c1yn36f:443", "xn--c1yn36f")] + [InlineData("xn--c1yn36f:443", "點看")] + [InlineData("[::ABC]", "[::aBc]")] + [InlineData("[::1]:80", "[::1]")] + public async Task AllowsSpecifiedHost(string host, string allowedHost) + { + var builder = new WebHostBuilder() + .ConfigureServices(services => + { + services.AddHostFiltering(options => + { + options.AllowedHosts = allowedHost.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries); + }); + }) + .Configure(app => + { + app.Use((ctx, next) => + { + // TestHost's ClientHandler doesn't let you set the host header, only the host in the URI + // and that would over-normalize some of our test conditions like casing. + ctx.Request.Headers[HeaderNames.Host] = host; + return next(); + }); + app.UseHostFiltering(); + app.Run(c => Task.CompletedTask); + }); + var server = new TestServer(builder); + var response = await server.CreateRequest("/").GetAsync(); + Assert.Equal(200, (int)response.StatusCode); + } + + [Theory] + [InlineData("example.com", "localhost")] + [InlineData("localhost:9090", "example.com;")] + [InlineData(";", "example.com;localhost")] + [InlineData(";:80", "example.com;localhost")] + [InlineData(":80", "localhost")] + [InlineData(":", "localhost")] + [InlineData("example.com:443", "*.example.com")] + [InlineData(".example.com:443", "*.example.com")] + [InlineData("foo.com:443", "*.example.com")] + [InlineData("foo.example.com.bar:443", "*.example.com")] + [InlineData(".com:443", "*.com")] + // Unicode in the host shouldn't be allowed without punycode anyways. This match fails because the middleware converts + // its input to punycode. + [InlineData("點看", "點看")] + [InlineData("[::1", "[::1]")] + [InlineData("[::1:80", "[::1]")] + public async Task RejectsMismatchedHosts(string host, string allowedHost) + { + var builder = new WebHostBuilder() + .ConfigureServices(services => + { + services.AddHostFiltering(options => + { + options.AllowedHosts = allowedHost.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries); + }); + }) + .Configure(app => + { + app.Use((ctx, next) => + { + // TestHost's ClientHandler doesn't let you set the host header, only the host in the URI + // and that would reject some of our test conditions. + ctx.Request.Headers[HeaderNames.Host] = host; + return next(); + }); + app.UseHostFiltering(); + app.Run(c => throw new NotImplementedException("App")); + }); + var server = new TestServer(builder); + var response = await server.CreateRequest("/").GetAsync(); + Assert.Equal(400, (int)response.StatusCode); + } + } +} diff --git a/test/Microsoft.AspNetCore.HostFiltering.Tests/Microsoft.AspNetCore.HostFiltering.Tests.csproj b/test/Microsoft.AspNetCore.HostFiltering.Tests/Microsoft.AspNetCore.HostFiltering.Tests.csproj new file mode 100644 index 0000000000..d71805c949 --- /dev/null +++ b/test/Microsoft.AspNetCore.HostFiltering.Tests/Microsoft.AspNetCore.HostFiltering.Tests.csproj @@ -0,0 +1,11 @@ + + + + $(StandardTestTfms) + + + + + + + diff --git a/test/Microsoft.AspNetCore.HttpOverrides.Tests/ForwardedHeadersMiddlewareTest.cs b/test/Microsoft.AspNetCore.HttpOverrides.Tests/ForwardedHeadersMiddlewareTest.cs index 81d6ccf15a..f88243c9e7 100644 --- a/test/Microsoft.AspNetCore.HttpOverrides.Tests/ForwardedHeadersMiddlewareTest.cs +++ b/test/Microsoft.AspNetCore.HttpOverrides.Tests/ForwardedHeadersMiddlewareTest.cs @@ -1,12 +1,14 @@ // 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; using System.Linq; using System.Net; using System.Threading.Tasks; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.TestHost; +using Microsoft.Net.Http.Headers; using Xunit; namespace Microsoft.AspNetCore.HttpOverrides @@ -392,6 +394,119 @@ namespace Microsoft.AspNetCore.HttpOverrides Assert.True(assertsExecuted); } + [Theory] + [InlineData("localHost", "localhost")] + [InlineData("localHost", "*")] // Any - Used by HttpSys + [InlineData("localHost", "[::]")] // IPv6 Any - This is what Kestrel reports when binding to * + [InlineData("localHost", "0.0.0.0")] // IPv4 Any + [InlineData("localhost:9090", "example.com;localHost")] + [InlineData("example.com:443", "example.com;localhost")] + [InlineData("localHost:80", "localhost;")] + [InlineData("foo.eXample.com:443", "*.exampLe.com")] + [InlineData("f.eXample.com:443", "*.exampLe.com")] + [InlineData("127.0.0.1", "127.0.0.1")] + [InlineData("127.0.0.1:443", "127.0.0.1")] + [InlineData("xn--c1yn36f:443", "xn--c1yn36f")] + [InlineData("xn--c1yn36f:443", "點看")] + [InlineData("[::ABC]", "[::aBc]")] + [InlineData("[::1]:80", "[::1]")] + public async Task XForwardedHostAllowsSpecifiedHost(string host, string allowedHost) + { + bool assertsExecuted = false; + var builder = new WebHostBuilder() + .Configure(app => + { + app.UseForwardedHeaders(new ForwardedHeadersOptions + { + ForwardedHeaders = ForwardedHeaders.XForwardedHost, + AllowedHosts = allowedHost.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries) + }); + app.Run(context => + { + Assert.Equal(host, context.Request.Headers[HeaderNames.Host]); + assertsExecuted = true; + return Task.FromResult(0); + }); + }); + var server = new TestServer(builder); + var response = await server.SendAsync(ctx => + { + ctx.Request.Headers["X-forwarded-Host"] = host; + }); + Assert.True(assertsExecuted); + } + + [Theory] + [InlineData("example.com", "localhost")] + [InlineData("localhost:9090", "example.com;")] + [InlineData(";", "example.com;localhost")] + [InlineData(";:80", "example.com;localhost")] + [InlineData(":80", "localhost")] + [InlineData(":", "localhost")] + [InlineData("example.com:443", "*.example.com")] + [InlineData(".example.com:443", "*.example.com")] + [InlineData("foo.com:443", "*.example.com")] + [InlineData("foo.example.com.bar:443", "*.example.com")] + [InlineData(".com:443", "*.com")] + // Unicode in the host shouldn't be allowed without punycode anyways. This match fails because the middleware converts + // its input to punycode. + [InlineData("點看", "點看")] + [InlineData("[::1", "[::1]")] + [InlineData("[::1:80", "[::1]")] + public async Task XForwardedHostFailsMismatchedHosts(string host, string allowedHost) + { + bool assertsExecuted = false; + var builder = new WebHostBuilder() + .Configure(app => + { + app.UseForwardedHeaders(new ForwardedHeadersOptions + { + ForwardedHeaders = ForwardedHeaders.XForwardedHost, + AllowedHosts = new[] { allowedHost } + }); + app.Run(context => + { + Assert.NotEqual(host, context.Request.Headers[HeaderNames.Host]); + assertsExecuted = true; + return Task.FromResult(0); + }); + }); + var server = new TestServer(builder); + var response = await server.SendAsync(ctx => + { + ctx.Request.Headers["X-forwarded-Host"] = host; + }); + Assert.True(assertsExecuted); + } + + [Fact] + public async Task XForwardedHostStopsAtFirstUnspecifiedHost() + { + bool assertsExecuted = false; + var builder = new WebHostBuilder() + .Configure(app => + { + app.UseForwardedHeaders(new ForwardedHeadersOptions + { + ForwardedHeaders = ForwardedHeaders.XForwardedHost, + ForwardLimit = 10, + AllowedHosts = new[] { "bar.com", "*.foo.com" } + }); + app.Run(context => + { + Assert.Equal("bar.foo.com:432", context.Request.Headers[HeaderNames.Host]); + assertsExecuted = true; + return Task.FromResult(0); + }); + }); + var server = new TestServer(builder); + var response = await server.SendAsync(ctx => + { + ctx.Request.Headers["X-forwarded-Host"] = "stuff:523, bar.foo.com:432, bar.com:80"; + }); + Assert.True(assertsExecuted); + } + [Theory] [InlineData(0, "h1", "http")] [InlineData(1, "", "http")] diff --git a/test/Microsoft.AspNetCore.HttpsPolicy.Tests/HttpsRedirectionMiddlewareTests.cs b/test/Microsoft.AspNetCore.HttpsPolicy.Tests/HttpsRedirectionMiddlewareTests.cs index 9d482151ca..b55c195272 100644 --- a/test/Microsoft.AspNetCore.HttpsPolicy.Tests/HttpsRedirectionMiddlewareTests.cs +++ b/test/Microsoft.AspNetCore.HttpsPolicy.Tests/HttpsRedirectionMiddlewareTests.cs @@ -22,9 +22,6 @@ namespace Microsoft.AspNetCore.HttpsPolicy.Tests public async Task SetOptions_DefaultsSetCorrectly() { var builder = new WebHostBuilder() - .ConfigureServices(services => - { - }) .Configure(app => { app.UseHttpsRedirection(); @@ -34,9 +31,7 @@ namespace Microsoft.AspNetCore.HttpsPolicy.Tests }); }); - var featureCollection = new FeatureCollection(); - featureCollection.Set(new ServerAddressesFeature()); - var server = new TestServer(builder, featureCollection); + var server = new TestServer(builder); var client = server.CreateClient(); var request = new HttpRequestMessage(HttpMethod.Get, ""); @@ -75,9 +70,7 @@ namespace Microsoft.AspNetCore.HttpsPolicy.Tests }); }); - var featureCollection = new FeatureCollection(); - featureCollection.Set(new ServerAddressesFeature()); - var server = new TestServer(builder, featureCollection); + var server = new TestServer(builder); var client = server.CreateClient(); var request = new HttpRequestMessage(HttpMethod.Get, ""); @@ -115,9 +108,7 @@ namespace Microsoft.AspNetCore.HttpsPolicy.Tests }); }); - var featureCollection = new FeatureCollection(); - featureCollection.Set(new ServerAddressesFeature()); - var server = new TestServer(builder, featureCollection); + var server = new TestServer(builder); var client = server.CreateClient(); var request = new HttpRequestMessage(HttpMethod.Get, ""); @@ -182,12 +173,6 @@ namespace Microsoft.AspNetCore.HttpsPolicy.Tests public async Task SetServerAddressesFeature_SingleHttpsAddress_Success() { var builder = new WebHostBuilder() - .ConfigureServices(services => - { - services.AddHttpsRedirection(options => - { - }); - }) .Configure(app => { app.UseHttpsRedirection(); @@ -215,12 +200,6 @@ namespace Microsoft.AspNetCore.HttpsPolicy.Tests public async Task SetServerAddressesFeature_MultipleHttpsAddresses_ThrowInMiddleware() { var builder = new WebHostBuilder() - .ConfigureServices(services => - { - services.AddHttpsRedirection(options => - { - }); - }) .Configure(app => { app.UseHttpsRedirection(); @@ -248,12 +227,6 @@ namespace Microsoft.AspNetCore.HttpsPolicy.Tests public async Task SetServerAddressesFeature_MultipleHttpsAddressesWithSamePort_Success() { var builder = new WebHostBuilder() - .ConfigureServices(services => - { - services.AddHttpsRedirection(options => - { - }); - }) .Configure(app => { app.UseHttpsRedirection(); From 0e09114c3bcb66a568e4b7ea4c4778b6a5c12849 Mon Sep 17 00:00:00 2001 From: Pranav K Date: Fri, 16 Mar 2018 11:12:46 -0700 Subject: [PATCH 282/307] Branching for 2.1.0-preview2 --- build/dependencies.props | 38 +++++++++++++++++++------------------- build/repo.props | 4 ++-- build/sources.props | 2 +- korebuild-lock.txt | 4 ++-- 4 files changed, 24 insertions(+), 24 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index 4dadaa5ffa..6eb9c5da57 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -3,26 +3,26 @@ $(MSBuildAllProjects);$(MSBuildThisFileFullPath) - 2.1.0-preview2-15728 - 2.1.0-preview2-30281 - 2.1.0-preview2-30281 - 2.1.0-preview2-30281 - 2.1.0-preview2-30281 - 2.1.0-preview2-30281 - 2.1.0-preview2-30281 - 2.1.0-preview2-30281 - 2.1.0-preview2-30281 - 2.1.0-preview2-30281 - 2.1.0-preview2-30281 - 2.1.0-preview2-30281 - 2.1.0-preview2-30281 - 2.1.0-preview2-30281 - 2.1.0-preview2-30281 - 2.1.0-preview2-30281 - 2.1.0-preview2-30281 + 2.1.0-preview2-15742 + 2.1.0-preview2-30355 + 2.1.0-preview2-30355 + 2.1.0-preview2-30355 + 2.1.0-preview2-30355 + 2.1.0-preview2-30355 + 2.1.0-preview2-30355 + 2.1.0-preview2-30355 + 2.1.0-preview2-30355 + 2.1.0-preview2-30355 + 2.1.0-preview2-30355 + 2.1.0-preview2-30355 + 2.1.0-preview2-30355 + 2.1.0-preview2-30355 + 2.1.0-preview2-30355 + 2.1.0-preview2-30355 + 2.1.0-preview2-30355 2.0.0 - 2.1.0-preview2-26308-01 - 2.1.0-preview2-30281 + 2.1.0-preview2-26314-02 + 2.1.0-preview2-30355 15.6.0 4.7.49 0.8.0 diff --git a/build/repo.props b/build/repo.props index 78b0ce5879..d94ff7d00d 100644 --- a/build/repo.props +++ b/build/repo.props @@ -1,10 +1,10 @@ - + Internal.AspNetCore.Universe.Lineup - https://dotnet.myget.org/F/aspnetcore-dev/api/v3/index.json + https://dotnet.myget.org/F/aspnetcore-release/api/v3/index.json diff --git a/build/sources.props b/build/sources.props index 9215df9751..36045f12b5 100644 --- a/build/sources.props +++ b/build/sources.props @@ -6,7 +6,7 @@ $(RestoreSources); https://dotnet.myget.org/F/dotnet-core/api/v3/index.json; - https://dotnet.myget.org/F/aspnetcore-dev/api/v3/index.json; + https://dotnet.myget.org/F/aspnetcore-release/api/v3/index.json; https://dotnet.myget.org/F/aspnetcore-tools/api/v3/index.json; diff --git a/korebuild-lock.txt b/korebuild-lock.txt index 138d848db1..e40ef6651b 100644 --- a/korebuild-lock.txt +++ b/korebuild-lock.txt @@ -1,2 +1,2 @@ -version:2.1.0-preview2-15728 -commithash:393377068ddcf51dfee0536536d455f57a828b06 +version:2.1.0-preview2-15742 +commithash:21fbb0f2c3fe4a9216e2d59632b98cfd7d685962 From 56f045b5398f68e480c63d6dcc01bad157e38a3b Mon Sep 17 00:00:00 2001 From: Pranav K Date: Fri, 16 Mar 2018 11:24:58 -0700 Subject: [PATCH 283/307] Update version prefix to preview3 --- version.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.props b/version.props index b9dfed9383..36fad116cd 100644 --- a/version.props +++ b/version.props @@ -1,7 +1,7 @@ 2.1.0 - preview2 + preview3 $(VersionPrefix) $(VersionPrefix)-$(VersionSuffix)-final t000 From b54111e5ec75789928e171acf2df027076c9cc9a Mon Sep 17 00:00:00 2001 From: Pranav K Date: Fri, 16 Mar 2018 12:27:32 -0700 Subject: [PATCH 284/307] Update KoreBuild channel --- korebuild.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/korebuild.json b/korebuild.json index bd5d51a51b..678d8bb948 100644 --- a/korebuild.json +++ b/korebuild.json @@ -1,4 +1,4 @@ { - "$schema": "https://raw.githubusercontent.com/aspnet/BuildTools/dev/tools/korebuild.schema.json", - "channel": "dev" + "$schema": "https://raw.githubusercontent.com/aspnet/BuildTools/release/2.1/tools/korebuild.schema.json", + "channel": "release/2.1" } From 45a0b246807ab66a96cfb1133f1f368a169b7faa Mon Sep 17 00:00:00 2001 From: Ryan Brandenburg Date: Wed, 21 Mar 2018 14:49:20 -0700 Subject: [PATCH 285/307] Updating baselines --- .../baseline.netcore.json | 194 +- .../baseline.netcore.json | 509 ++ .../baseline.netframework.json | 509 ++ .../baseline.netcore.json | 5915 +++++++++++++++++ 4 files changed, 7126 insertions(+), 1 deletion(-) create mode 100644 src/Microsoft.AspNetCore.ResponseCompression/baseline.netcore.json create mode 100644 src/Microsoft.AspNetCore.ResponseCompression/baseline.netframework.json create mode 100644 src/Microsoft.AspNetCore.Rewrite/baseline.netcore.json diff --git a/src/Microsoft.AspNetCore.HttpOverrides/baseline.netcore.json b/src/Microsoft.AspNetCore.HttpOverrides/baseline.netcore.json index 4a5e5a6e3e..d5d1fac25e 100644 --- a/src/Microsoft.AspNetCore.HttpOverrides/baseline.netcore.json +++ b/src/Microsoft.AspNetCore.HttpOverrides/baseline.netcore.json @@ -1,5 +1,5 @@ { - "AssemblyIdentity": "Microsoft.AspNetCore.HttpOverrides, Version=1.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60", + "AssemblyIdentity": "Microsoft.AspNetCore.HttpOverrides, Version=2.0.2.0, Culture=neutral, PublicKeyToken=adb9793829ddae60", "Types": [ { "Name": "Microsoft.AspNetCore.Builder.ForwardedHeadersExtensions", @@ -53,6 +53,132 @@ "Kind": "Class", "ImplementedInterfaces": [], "Members": [ + { + "Kind": "Method", + "Name": "get_ForwardedForHeaderName", + "Parameters": [], + "ReturnType": "System.String", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "set_ForwardedForHeaderName", + "Parameters": [ + { + "Name": "value", + "Type": "System.String" + } + ], + "ReturnType": "System.Void", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "get_ForwardedHostHeaderName", + "Parameters": [], + "ReturnType": "System.String", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "set_ForwardedHostHeaderName", + "Parameters": [ + { + "Name": "value", + "Type": "System.String" + } + ], + "ReturnType": "System.Void", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "get_ForwardedProtoHeaderName", + "Parameters": [], + "ReturnType": "System.String", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "set_ForwardedProtoHeaderName", + "Parameters": [ + { + "Name": "value", + "Type": "System.String" + } + ], + "ReturnType": "System.Void", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "get_OriginalForHeaderName", + "Parameters": [], + "ReturnType": "System.String", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "set_OriginalForHeaderName", + "Parameters": [ + { + "Name": "value", + "Type": "System.String" + } + ], + "ReturnType": "System.Void", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "get_OriginalHostHeaderName", + "Parameters": [], + "ReturnType": "System.String", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "set_OriginalHostHeaderName", + "Parameters": [ + { + "Name": "value", + "Type": "System.String" + } + ], + "ReturnType": "System.Void", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "get_OriginalProtoHeaderName", + "Parameters": [], + "ReturnType": "System.String", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "set_OriginalProtoHeaderName", + "Parameters": [ + { + "Name": "value", + "Type": "System.String" + } + ], + "ReturnType": "System.Void", + "Visibility": "Public", + "GenericParameter": [] + }, { "Kind": "Method", "Name": "get_ForwardedHeaders", @@ -270,6 +396,72 @@ ], "GenericParameters": [] }, + { + "Name": "Microsoft.AspNetCore.HttpOverrides.ForwardedHeadersDefaults", + "Visibility": "Public", + "Kind": "Class", + "Abstract": true, + "Static": true, + "Sealed": true, + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Method", + "Name": "get_XForwardedForHeaderName", + "Parameters": [], + "ReturnType": "System.String", + "Static": true, + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "get_XForwardedHostHeaderName", + "Parameters": [], + "ReturnType": "System.String", + "Static": true, + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "get_XForwardedProtoHeaderName", + "Parameters": [], + "ReturnType": "System.String", + "Static": true, + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "get_XOriginalForHeaderName", + "Parameters": [], + "ReturnType": "System.String", + "Static": true, + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "get_XOriginalHostHeaderName", + "Parameters": [], + "ReturnType": "System.String", + "Static": true, + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "get_XOriginalProtoHeaderName", + "Parameters": [], + "ReturnType": "System.String", + "Static": true, + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, { "Name": "Microsoft.AspNetCore.HttpOverrides.ForwardedHeadersMiddleware", "Visibility": "Public", diff --git a/src/Microsoft.AspNetCore.ResponseCompression/baseline.netcore.json b/src/Microsoft.AspNetCore.ResponseCompression/baseline.netcore.json new file mode 100644 index 0000000000..4677b668c5 --- /dev/null +++ b/src/Microsoft.AspNetCore.ResponseCompression/baseline.netcore.json @@ -0,0 +1,509 @@ +{ + "AssemblyIdentity": "Microsoft.AspNetCore.ResponseCompression, Version=2.0.2.0, Culture=neutral, PublicKeyToken=adb9793829ddae60", + "Types": [ + { + "Name": "Microsoft.AspNetCore.Builder.ResponseCompressionBuilderExtensions", + "Visibility": "Public", + "Kind": "Class", + "Abstract": true, + "Static": true, + "Sealed": true, + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Method", + "Name": "UseResponseCompression", + "Parameters": [ + { + "Name": "builder", + "Type": "Microsoft.AspNetCore.Builder.IApplicationBuilder" + } + ], + "ReturnType": "Microsoft.AspNetCore.Builder.IApplicationBuilder", + "Static": true, + "Extension": true, + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.Builder.ResponseCompressionServicesExtensions", + "Visibility": "Public", + "Kind": "Class", + "Abstract": true, + "Static": true, + "Sealed": true, + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Method", + "Name": "AddResponseCompression", + "Parameters": [ + { + "Name": "services", + "Type": "Microsoft.Extensions.DependencyInjection.IServiceCollection" + } + ], + "ReturnType": "Microsoft.Extensions.DependencyInjection.IServiceCollection", + "Static": true, + "Extension": true, + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "AddResponseCompression", + "Parameters": [ + { + "Name": "services", + "Type": "Microsoft.Extensions.DependencyInjection.IServiceCollection" + }, + { + "Name": "configureOptions", + "Type": "System.Action" + } + ], + "ReturnType": "Microsoft.Extensions.DependencyInjection.IServiceCollection", + "Static": true, + "Extension": true, + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.ResponseCompression.CompressionProviderCollection", + "Visibility": "Public", + "Kind": "Class", + "BaseType": "System.Collections.ObjectModel.Collection", + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Method", + "Name": "Add", + "Parameters": [], + "ReturnType": "System.Void", + "Visibility": "Public", + "GenericParameter": [ + { + "ParameterName": "TCompressionProvider", + "ParameterPosition": 0, + "BaseTypeOrInterfaces": [ + "Microsoft.AspNetCore.ResponseCompression.ICompressionProvider" + ] + } + ] + }, + { + "Kind": "Method", + "Name": "Add", + "Parameters": [ + { + "Name": "providerType", + "Type": "System.Type" + } + ], + "ReturnType": "System.Void", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [], + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.ResponseCompression.GzipCompressionProvider", + "Visibility": "Public", + "Kind": "Class", + "ImplementedInterfaces": [ + "Microsoft.AspNetCore.ResponseCompression.ICompressionProvider" + ], + "Members": [ + { + "Kind": "Method", + "Name": "get_EncodingName", + "Parameters": [], + "ReturnType": "System.String", + "Sealed": true, + "Virtual": true, + "ImplementedInterface": "Microsoft.AspNetCore.ResponseCompression.ICompressionProvider", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "get_SupportsFlush", + "Parameters": [], + "ReturnType": "System.Boolean", + "Sealed": true, + "Virtual": true, + "ImplementedInterface": "Microsoft.AspNetCore.ResponseCompression.ICompressionProvider", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "CreateStream", + "Parameters": [ + { + "Name": "outputStream", + "Type": "System.IO.Stream" + } + ], + "ReturnType": "System.IO.Stream", + "Sealed": true, + "Virtual": true, + "ImplementedInterface": "Microsoft.AspNetCore.ResponseCompression.ICompressionProvider", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [ + { + "Name": "options", + "Type": "Microsoft.Extensions.Options.IOptions" + } + ], + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.ResponseCompression.GzipCompressionProviderOptions", + "Visibility": "Public", + "Kind": "Class", + "ImplementedInterfaces": [ + "Microsoft.Extensions.Options.IOptions" + ], + "Members": [ + { + "Kind": "Method", + "Name": "get_Level", + "Parameters": [], + "ReturnType": "System.IO.Compression.CompressionLevel", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "set_Level", + "Parameters": [ + { + "Name": "value", + "Type": "System.IO.Compression.CompressionLevel" + } + ], + "ReturnType": "System.Void", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [], + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.ResponseCompression.ICompressionProvider", + "Visibility": "Public", + "Kind": "Interface", + "Abstract": true, + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Method", + "Name": "get_EncodingName", + "Parameters": [], + "ReturnType": "System.String", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "get_SupportsFlush", + "Parameters": [], + "ReturnType": "System.Boolean", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "CreateStream", + "Parameters": [ + { + "Name": "outputStream", + "Type": "System.IO.Stream" + } + ], + "ReturnType": "System.IO.Stream", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.ResponseCompression.IResponseCompressionProvider", + "Visibility": "Public", + "Kind": "Interface", + "Abstract": true, + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Method", + "Name": "GetCompressionProvider", + "Parameters": [ + { + "Name": "context", + "Type": "Microsoft.AspNetCore.Http.HttpContext" + } + ], + "ReturnType": "Microsoft.AspNetCore.ResponseCompression.ICompressionProvider", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "ShouldCompressResponse", + "Parameters": [ + { + "Name": "context", + "Type": "Microsoft.AspNetCore.Http.HttpContext" + } + ], + "ReturnType": "System.Boolean", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "CheckRequestAcceptsCompression", + "Parameters": [ + { + "Name": "context", + "Type": "Microsoft.AspNetCore.Http.HttpContext" + } + ], + "ReturnType": "System.Boolean", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.ResponseCompression.ResponseCompressionDefaults", + "Visibility": "Public", + "Kind": "Class", + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [], + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Field", + "Name": "MimeTypes", + "Parameters": [], + "ReturnType": "System.Collections.Generic.IEnumerable", + "Static": true, + "ReadOnly": true, + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.ResponseCompression.ResponseCompressionMiddleware", + "Visibility": "Public", + "Kind": "Class", + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Method", + "Name": "Invoke", + "Parameters": [ + { + "Name": "context", + "Type": "Microsoft.AspNetCore.Http.HttpContext" + } + ], + "ReturnType": "System.Threading.Tasks.Task", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [ + { + "Name": "next", + "Type": "Microsoft.AspNetCore.Http.RequestDelegate" + }, + { + "Name": "provider", + "Type": "Microsoft.AspNetCore.ResponseCompression.IResponseCompressionProvider" + } + ], + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.ResponseCompression.ResponseCompressionOptions", + "Visibility": "Public", + "Kind": "Class", + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Method", + "Name": "get_MimeTypes", + "Parameters": [], + "ReturnType": "System.Collections.Generic.IEnumerable", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "set_MimeTypes", + "Parameters": [ + { + "Name": "value", + "Type": "System.Collections.Generic.IEnumerable" + } + ], + "ReturnType": "System.Void", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "get_EnableForHttps", + "Parameters": [], + "ReturnType": "System.Boolean", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "set_EnableForHttps", + "Parameters": [ + { + "Name": "value", + "Type": "System.Boolean" + } + ], + "ReturnType": "System.Void", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "get_Providers", + "Parameters": [], + "ReturnType": "Microsoft.AspNetCore.ResponseCompression.CompressionProviderCollection", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [], + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.ResponseCompression.ResponseCompressionProvider", + "Visibility": "Public", + "Kind": "Class", + "ImplementedInterfaces": [ + "Microsoft.AspNetCore.ResponseCompression.IResponseCompressionProvider" + ], + "Members": [ + { + "Kind": "Method", + "Name": "GetCompressionProvider", + "Parameters": [ + { + "Name": "context", + "Type": "Microsoft.AspNetCore.Http.HttpContext" + } + ], + "ReturnType": "Microsoft.AspNetCore.ResponseCompression.ICompressionProvider", + "Virtual": true, + "ImplementedInterface": "Microsoft.AspNetCore.ResponseCompression.IResponseCompressionProvider", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "ShouldCompressResponse", + "Parameters": [ + { + "Name": "context", + "Type": "Microsoft.AspNetCore.Http.HttpContext" + } + ], + "ReturnType": "System.Boolean", + "Virtual": true, + "ImplementedInterface": "Microsoft.AspNetCore.ResponseCompression.IResponseCompressionProvider", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "CheckRequestAcceptsCompression", + "Parameters": [ + { + "Name": "context", + "Type": "Microsoft.AspNetCore.Http.HttpContext" + } + ], + "ReturnType": "System.Boolean", + "Sealed": true, + "Virtual": true, + "ImplementedInterface": "Microsoft.AspNetCore.ResponseCompression.IResponseCompressionProvider", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [ + { + "Name": "services", + "Type": "System.IServiceProvider" + }, + { + "Name": "options", + "Type": "Microsoft.Extensions.Options.IOptions" + } + ], + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + } + ] +} \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.ResponseCompression/baseline.netframework.json b/src/Microsoft.AspNetCore.ResponseCompression/baseline.netframework.json new file mode 100644 index 0000000000..4677b668c5 --- /dev/null +++ b/src/Microsoft.AspNetCore.ResponseCompression/baseline.netframework.json @@ -0,0 +1,509 @@ +{ + "AssemblyIdentity": "Microsoft.AspNetCore.ResponseCompression, Version=2.0.2.0, Culture=neutral, PublicKeyToken=adb9793829ddae60", + "Types": [ + { + "Name": "Microsoft.AspNetCore.Builder.ResponseCompressionBuilderExtensions", + "Visibility": "Public", + "Kind": "Class", + "Abstract": true, + "Static": true, + "Sealed": true, + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Method", + "Name": "UseResponseCompression", + "Parameters": [ + { + "Name": "builder", + "Type": "Microsoft.AspNetCore.Builder.IApplicationBuilder" + } + ], + "ReturnType": "Microsoft.AspNetCore.Builder.IApplicationBuilder", + "Static": true, + "Extension": true, + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.Builder.ResponseCompressionServicesExtensions", + "Visibility": "Public", + "Kind": "Class", + "Abstract": true, + "Static": true, + "Sealed": true, + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Method", + "Name": "AddResponseCompression", + "Parameters": [ + { + "Name": "services", + "Type": "Microsoft.Extensions.DependencyInjection.IServiceCollection" + } + ], + "ReturnType": "Microsoft.Extensions.DependencyInjection.IServiceCollection", + "Static": true, + "Extension": true, + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "AddResponseCompression", + "Parameters": [ + { + "Name": "services", + "Type": "Microsoft.Extensions.DependencyInjection.IServiceCollection" + }, + { + "Name": "configureOptions", + "Type": "System.Action" + } + ], + "ReturnType": "Microsoft.Extensions.DependencyInjection.IServiceCollection", + "Static": true, + "Extension": true, + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.ResponseCompression.CompressionProviderCollection", + "Visibility": "Public", + "Kind": "Class", + "BaseType": "System.Collections.ObjectModel.Collection", + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Method", + "Name": "Add", + "Parameters": [], + "ReturnType": "System.Void", + "Visibility": "Public", + "GenericParameter": [ + { + "ParameterName": "TCompressionProvider", + "ParameterPosition": 0, + "BaseTypeOrInterfaces": [ + "Microsoft.AspNetCore.ResponseCompression.ICompressionProvider" + ] + } + ] + }, + { + "Kind": "Method", + "Name": "Add", + "Parameters": [ + { + "Name": "providerType", + "Type": "System.Type" + } + ], + "ReturnType": "System.Void", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [], + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.ResponseCompression.GzipCompressionProvider", + "Visibility": "Public", + "Kind": "Class", + "ImplementedInterfaces": [ + "Microsoft.AspNetCore.ResponseCompression.ICompressionProvider" + ], + "Members": [ + { + "Kind": "Method", + "Name": "get_EncodingName", + "Parameters": [], + "ReturnType": "System.String", + "Sealed": true, + "Virtual": true, + "ImplementedInterface": "Microsoft.AspNetCore.ResponseCompression.ICompressionProvider", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "get_SupportsFlush", + "Parameters": [], + "ReturnType": "System.Boolean", + "Sealed": true, + "Virtual": true, + "ImplementedInterface": "Microsoft.AspNetCore.ResponseCompression.ICompressionProvider", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "CreateStream", + "Parameters": [ + { + "Name": "outputStream", + "Type": "System.IO.Stream" + } + ], + "ReturnType": "System.IO.Stream", + "Sealed": true, + "Virtual": true, + "ImplementedInterface": "Microsoft.AspNetCore.ResponseCompression.ICompressionProvider", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [ + { + "Name": "options", + "Type": "Microsoft.Extensions.Options.IOptions" + } + ], + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.ResponseCompression.GzipCompressionProviderOptions", + "Visibility": "Public", + "Kind": "Class", + "ImplementedInterfaces": [ + "Microsoft.Extensions.Options.IOptions" + ], + "Members": [ + { + "Kind": "Method", + "Name": "get_Level", + "Parameters": [], + "ReturnType": "System.IO.Compression.CompressionLevel", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "set_Level", + "Parameters": [ + { + "Name": "value", + "Type": "System.IO.Compression.CompressionLevel" + } + ], + "ReturnType": "System.Void", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [], + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.ResponseCompression.ICompressionProvider", + "Visibility": "Public", + "Kind": "Interface", + "Abstract": true, + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Method", + "Name": "get_EncodingName", + "Parameters": [], + "ReturnType": "System.String", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "get_SupportsFlush", + "Parameters": [], + "ReturnType": "System.Boolean", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "CreateStream", + "Parameters": [ + { + "Name": "outputStream", + "Type": "System.IO.Stream" + } + ], + "ReturnType": "System.IO.Stream", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.ResponseCompression.IResponseCompressionProvider", + "Visibility": "Public", + "Kind": "Interface", + "Abstract": true, + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Method", + "Name": "GetCompressionProvider", + "Parameters": [ + { + "Name": "context", + "Type": "Microsoft.AspNetCore.Http.HttpContext" + } + ], + "ReturnType": "Microsoft.AspNetCore.ResponseCompression.ICompressionProvider", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "ShouldCompressResponse", + "Parameters": [ + { + "Name": "context", + "Type": "Microsoft.AspNetCore.Http.HttpContext" + } + ], + "ReturnType": "System.Boolean", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "CheckRequestAcceptsCompression", + "Parameters": [ + { + "Name": "context", + "Type": "Microsoft.AspNetCore.Http.HttpContext" + } + ], + "ReturnType": "System.Boolean", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.ResponseCompression.ResponseCompressionDefaults", + "Visibility": "Public", + "Kind": "Class", + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [], + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Field", + "Name": "MimeTypes", + "Parameters": [], + "ReturnType": "System.Collections.Generic.IEnumerable", + "Static": true, + "ReadOnly": true, + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.ResponseCompression.ResponseCompressionMiddleware", + "Visibility": "Public", + "Kind": "Class", + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Method", + "Name": "Invoke", + "Parameters": [ + { + "Name": "context", + "Type": "Microsoft.AspNetCore.Http.HttpContext" + } + ], + "ReturnType": "System.Threading.Tasks.Task", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [ + { + "Name": "next", + "Type": "Microsoft.AspNetCore.Http.RequestDelegate" + }, + { + "Name": "provider", + "Type": "Microsoft.AspNetCore.ResponseCompression.IResponseCompressionProvider" + } + ], + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.ResponseCompression.ResponseCompressionOptions", + "Visibility": "Public", + "Kind": "Class", + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Method", + "Name": "get_MimeTypes", + "Parameters": [], + "ReturnType": "System.Collections.Generic.IEnumerable", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "set_MimeTypes", + "Parameters": [ + { + "Name": "value", + "Type": "System.Collections.Generic.IEnumerable" + } + ], + "ReturnType": "System.Void", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "get_EnableForHttps", + "Parameters": [], + "ReturnType": "System.Boolean", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "set_EnableForHttps", + "Parameters": [ + { + "Name": "value", + "Type": "System.Boolean" + } + ], + "ReturnType": "System.Void", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "get_Providers", + "Parameters": [], + "ReturnType": "Microsoft.AspNetCore.ResponseCompression.CompressionProviderCollection", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [], + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.ResponseCompression.ResponseCompressionProvider", + "Visibility": "Public", + "Kind": "Class", + "ImplementedInterfaces": [ + "Microsoft.AspNetCore.ResponseCompression.IResponseCompressionProvider" + ], + "Members": [ + { + "Kind": "Method", + "Name": "GetCompressionProvider", + "Parameters": [ + { + "Name": "context", + "Type": "Microsoft.AspNetCore.Http.HttpContext" + } + ], + "ReturnType": "Microsoft.AspNetCore.ResponseCompression.ICompressionProvider", + "Virtual": true, + "ImplementedInterface": "Microsoft.AspNetCore.ResponseCompression.IResponseCompressionProvider", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "ShouldCompressResponse", + "Parameters": [ + { + "Name": "context", + "Type": "Microsoft.AspNetCore.Http.HttpContext" + } + ], + "ReturnType": "System.Boolean", + "Virtual": true, + "ImplementedInterface": "Microsoft.AspNetCore.ResponseCompression.IResponseCompressionProvider", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "CheckRequestAcceptsCompression", + "Parameters": [ + { + "Name": "context", + "Type": "Microsoft.AspNetCore.Http.HttpContext" + } + ], + "ReturnType": "System.Boolean", + "Sealed": true, + "Virtual": true, + "ImplementedInterface": "Microsoft.AspNetCore.ResponseCompression.IResponseCompressionProvider", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [ + { + "Name": "services", + "Type": "System.IServiceProvider" + }, + { + "Name": "options", + "Type": "Microsoft.Extensions.Options.IOptions" + } + ], + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + } + ] +} \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Rewrite/baseline.netcore.json b/src/Microsoft.AspNetCore.Rewrite/baseline.netcore.json new file mode 100644 index 0000000000..64ce09c61d --- /dev/null +++ b/src/Microsoft.AspNetCore.Rewrite/baseline.netcore.json @@ -0,0 +1,5915 @@ +{ + "AssemblyIdentity": "Microsoft.AspNetCore.Rewrite, Version=2.0.2.0, Culture=neutral, PublicKeyToken=adb9793829ddae60", + "Types": [ + { + "Name": "Microsoft.AspNetCore.Builder.RewriteBuilderExtensions", + "Visibility": "Public", + "Kind": "Class", + "Abstract": true, + "Static": true, + "Sealed": true, + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Method", + "Name": "UseRewriter", + "Parameters": [ + { + "Name": "app", + "Type": "Microsoft.AspNetCore.Builder.IApplicationBuilder" + } + ], + "ReturnType": "Microsoft.AspNetCore.Builder.IApplicationBuilder", + "Static": true, + "Extension": true, + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "UseRewriter", + "Parameters": [ + { + "Name": "app", + "Type": "Microsoft.AspNetCore.Builder.IApplicationBuilder" + }, + { + "Name": "options", + "Type": "Microsoft.AspNetCore.Rewrite.RewriteOptions" + } + ], + "ReturnType": "Microsoft.AspNetCore.Builder.IApplicationBuilder", + "Static": true, + "Extension": true, + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.Rewrite.ApacheModRewriteOptionsExtensions", + "Visibility": "Public", + "Kind": "Class", + "Abstract": true, + "Static": true, + "Sealed": true, + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Method", + "Name": "AddApacheModRewrite", + "Parameters": [ + { + "Name": "options", + "Type": "Microsoft.AspNetCore.Rewrite.RewriteOptions" + }, + { + "Name": "fileProvider", + "Type": "Microsoft.Extensions.FileProviders.IFileProvider" + }, + { + "Name": "filePath", + "Type": "System.String" + } + ], + "ReturnType": "Microsoft.AspNetCore.Rewrite.RewriteOptions", + "Static": true, + "Extension": true, + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "AddApacheModRewrite", + "Parameters": [ + { + "Name": "options", + "Type": "Microsoft.AspNetCore.Rewrite.RewriteOptions" + }, + { + "Name": "reader", + "Type": "System.IO.TextReader" + } + ], + "ReturnType": "Microsoft.AspNetCore.Rewrite.RewriteOptions", + "Static": true, + "Extension": true, + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.Rewrite.IISUrlRewriteOptionsExtensions", + "Visibility": "Public", + "Kind": "Class", + "Abstract": true, + "Static": true, + "Sealed": true, + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Method", + "Name": "AddIISUrlRewrite", + "Parameters": [ + { + "Name": "options", + "Type": "Microsoft.AspNetCore.Rewrite.RewriteOptions" + }, + { + "Name": "fileProvider", + "Type": "Microsoft.Extensions.FileProviders.IFileProvider" + }, + { + "Name": "filePath", + "Type": "System.String" + } + ], + "ReturnType": "Microsoft.AspNetCore.Rewrite.RewriteOptions", + "Static": true, + "Extension": true, + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "AddIISUrlRewrite", + "Parameters": [ + { + "Name": "options", + "Type": "Microsoft.AspNetCore.Rewrite.RewriteOptions" + }, + { + "Name": "reader", + "Type": "System.IO.TextReader" + } + ], + "ReturnType": "Microsoft.AspNetCore.Rewrite.RewriteOptions", + "Static": true, + "Extension": true, + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.Rewrite.IRule", + "Visibility": "Public", + "Kind": "Interface", + "Abstract": true, + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Method", + "Name": "ApplyRule", + "Parameters": [ + { + "Name": "context", + "Type": "Microsoft.AspNetCore.Rewrite.RewriteContext" + } + ], + "ReturnType": "System.Void", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.Rewrite.RewriteContext", + "Visibility": "Public", + "Kind": "Class", + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Method", + "Name": "get_HttpContext", + "Parameters": [], + "ReturnType": "Microsoft.AspNetCore.Http.HttpContext", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "set_HttpContext", + "Parameters": [ + { + "Name": "value", + "Type": "Microsoft.AspNetCore.Http.HttpContext" + } + ], + "ReturnType": "System.Void", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "get_StaticFileProvider", + "Parameters": [], + "ReturnType": "Microsoft.Extensions.FileProviders.IFileProvider", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "set_StaticFileProvider", + "Parameters": [ + { + "Name": "value", + "Type": "Microsoft.Extensions.FileProviders.IFileProvider" + } + ], + "ReturnType": "System.Void", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "get_Logger", + "Parameters": [], + "ReturnType": "Microsoft.Extensions.Logging.ILogger", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "set_Logger", + "Parameters": [ + { + "Name": "value", + "Type": "Microsoft.Extensions.Logging.ILogger" + } + ], + "ReturnType": "System.Void", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "get_Result", + "Parameters": [], + "ReturnType": "Microsoft.AspNetCore.Rewrite.RuleResult", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "set_Result", + "Parameters": [ + { + "Name": "value", + "Type": "Microsoft.AspNetCore.Rewrite.RuleResult" + } + ], + "ReturnType": "System.Void", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [], + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.Rewrite.RewriteMiddleware", + "Visibility": "Public", + "Kind": "Class", + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Method", + "Name": "Invoke", + "Parameters": [ + { + "Name": "context", + "Type": "Microsoft.AspNetCore.Http.HttpContext" + } + ], + "ReturnType": "System.Threading.Tasks.Task", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [ + { + "Name": "next", + "Type": "Microsoft.AspNetCore.Http.RequestDelegate" + }, + { + "Name": "hostingEnvironment", + "Type": "Microsoft.AspNetCore.Hosting.IHostingEnvironment" + }, + { + "Name": "loggerFactory", + "Type": "Microsoft.Extensions.Logging.ILoggerFactory" + }, + { + "Name": "options", + "Type": "Microsoft.Extensions.Options.IOptions" + } + ], + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.Rewrite.RewriteOptions", + "Visibility": "Public", + "Kind": "Class", + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Method", + "Name": "get_Rules", + "Parameters": [], + "ReturnType": "System.Collections.Generic.IList", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "get_StaticFileProvider", + "Parameters": [], + "ReturnType": "Microsoft.Extensions.FileProviders.IFileProvider", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "set_StaticFileProvider", + "Parameters": [ + { + "Name": "value", + "Type": "Microsoft.Extensions.FileProviders.IFileProvider" + } + ], + "ReturnType": "System.Void", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [], + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.Rewrite.RewriteOptionsExtensions", + "Visibility": "Public", + "Kind": "Class", + "Abstract": true, + "Static": true, + "Sealed": true, + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Method", + "Name": "Add", + "Parameters": [ + { + "Name": "options", + "Type": "Microsoft.AspNetCore.Rewrite.RewriteOptions" + }, + { + "Name": "rule", + "Type": "Microsoft.AspNetCore.Rewrite.IRule" + } + ], + "ReturnType": "Microsoft.AspNetCore.Rewrite.RewriteOptions", + "Static": true, + "Extension": true, + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "Add", + "Parameters": [ + { + "Name": "options", + "Type": "Microsoft.AspNetCore.Rewrite.RewriteOptions" + }, + { + "Name": "applyRule", + "Type": "System.Action" + } + ], + "ReturnType": "Microsoft.AspNetCore.Rewrite.RewriteOptions", + "Static": true, + "Extension": true, + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "AddRewrite", + "Parameters": [ + { + "Name": "options", + "Type": "Microsoft.AspNetCore.Rewrite.RewriteOptions" + }, + { + "Name": "regex", + "Type": "System.String" + }, + { + "Name": "replacement", + "Type": "System.String" + }, + { + "Name": "skipRemainingRules", + "Type": "System.Boolean" + } + ], + "ReturnType": "Microsoft.AspNetCore.Rewrite.RewriteOptions", + "Static": true, + "Extension": true, + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "AddRedirect", + "Parameters": [ + { + "Name": "options", + "Type": "Microsoft.AspNetCore.Rewrite.RewriteOptions" + }, + { + "Name": "regex", + "Type": "System.String" + }, + { + "Name": "replacement", + "Type": "System.String" + } + ], + "ReturnType": "Microsoft.AspNetCore.Rewrite.RewriteOptions", + "Static": true, + "Extension": true, + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "AddRedirect", + "Parameters": [ + { + "Name": "options", + "Type": "Microsoft.AspNetCore.Rewrite.RewriteOptions" + }, + { + "Name": "regex", + "Type": "System.String" + }, + { + "Name": "replacement", + "Type": "System.String" + }, + { + "Name": "statusCode", + "Type": "System.Int32" + } + ], + "ReturnType": "Microsoft.AspNetCore.Rewrite.RewriteOptions", + "Static": true, + "Extension": true, + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "AddRedirectToHttpsPermanent", + "Parameters": [ + { + "Name": "options", + "Type": "Microsoft.AspNetCore.Rewrite.RewriteOptions" + } + ], + "ReturnType": "Microsoft.AspNetCore.Rewrite.RewriteOptions", + "Static": true, + "Extension": true, + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "AddRedirectToHttps", + "Parameters": [ + { + "Name": "options", + "Type": "Microsoft.AspNetCore.Rewrite.RewriteOptions" + } + ], + "ReturnType": "Microsoft.AspNetCore.Rewrite.RewriteOptions", + "Static": true, + "Extension": true, + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "AddRedirectToHttps", + "Parameters": [ + { + "Name": "options", + "Type": "Microsoft.AspNetCore.Rewrite.RewriteOptions" + }, + { + "Name": "statusCode", + "Type": "System.Int32" + } + ], + "ReturnType": "Microsoft.AspNetCore.Rewrite.RewriteOptions", + "Static": true, + "Extension": true, + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "AddRedirectToHttps", + "Parameters": [ + { + "Name": "options", + "Type": "Microsoft.AspNetCore.Rewrite.RewriteOptions" + }, + { + "Name": "statusCode", + "Type": "System.Int32" + }, + { + "Name": "sslPort", + "Type": "System.Nullable" + } + ], + "ReturnType": "Microsoft.AspNetCore.Rewrite.RewriteOptions", + "Static": true, + "Extension": true, + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.Rewrite.RuleResult", + "Visibility": "Public", + "Kind": "Enumeration", + "Sealed": true, + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Field", + "Name": "ContinueRules", + "Parameters": [], + "GenericParameter": [], + "Literal": "0" + }, + { + "Kind": "Field", + "Name": "EndResponse", + "Parameters": [], + "GenericParameter": [], + "Literal": "1" + }, + { + "Kind": "Field", + "Name": "SkipRemainingRules", + "Parameters": [], + "GenericParameter": [], + "Literal": "2" + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.Rewrite.Internal.BackReferenceCollection", + "Visibility": "Public", + "Kind": "Class", + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Method", + "Name": "get_Item", + "Parameters": [ + { + "Name": "index", + "Type": "System.Int32" + } + ], + "ReturnType": "System.String", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "Add", + "Parameters": [ + { + "Name": "references", + "Type": "Microsoft.AspNetCore.Rewrite.Internal.BackReferenceCollection" + } + ], + "ReturnType": "System.Void", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [ + { + "Name": "references", + "Type": "System.Text.RegularExpressions.GroupCollection" + } + ], + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [ + { + "Name": "reference", + "Type": "System.String" + } + ], + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.Rewrite.Internal.DelegateRule", + "Visibility": "Public", + "Kind": "Class", + "ImplementedInterfaces": [ + "Microsoft.AspNetCore.Rewrite.IRule" + ], + "Members": [ + { + "Kind": "Method", + "Name": "ApplyRule", + "Parameters": [ + { + "Name": "context", + "Type": "Microsoft.AspNetCore.Rewrite.RewriteContext" + } + ], + "ReturnType": "System.Void", + "Sealed": true, + "Virtual": true, + "ImplementedInterface": "Microsoft.AspNetCore.Rewrite.IRule", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [ + { + "Name": "onApplyRule", + "Type": "System.Action" + } + ], + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.Rewrite.Internal.MatchResults", + "Visibility": "Public", + "Kind": "Class", + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Method", + "Name": "get_Success", + "Parameters": [], + "ReturnType": "System.Boolean", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "set_Success", + "Parameters": [ + { + "Name": "value", + "Type": "System.Boolean" + } + ], + "ReturnType": "System.Void", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "get_BackReferences", + "Parameters": [], + "ReturnType": "Microsoft.AspNetCore.Rewrite.Internal.BackReferenceCollection", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "set_BackReferences", + "Parameters": [ + { + "Name": "value", + "Type": "Microsoft.AspNetCore.Rewrite.Internal.BackReferenceCollection" + } + ], + "ReturnType": "System.Void", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [], + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Field", + "Name": "EmptySuccess", + "Parameters": [], + "ReturnType": "Microsoft.AspNetCore.Rewrite.Internal.MatchResults", + "Static": true, + "ReadOnly": true, + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Field", + "Name": "EmptyFailure", + "Parameters": [], + "ReturnType": "Microsoft.AspNetCore.Rewrite.Internal.MatchResults", + "Static": true, + "ReadOnly": true, + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.Rewrite.Internal.ParserContext", + "Visibility": "Public", + "Kind": "Class", + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Method", + "Name": "get_Index", + "Parameters": [], + "ReturnType": "System.Int32", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "set_Index", + "Parameters": [ + { + "Name": "value", + "Type": "System.Int32" + } + ], + "ReturnType": "System.Void", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "get_Current", + "Parameters": [], + "ReturnType": "System.Char", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "Back", + "Parameters": [], + "ReturnType": "System.Boolean", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "Next", + "Parameters": [], + "ReturnType": "System.Boolean", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "HasNext", + "Parameters": [], + "ReturnType": "System.Boolean", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "Mark", + "Parameters": [], + "ReturnType": "System.Void", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "GetIndex", + "Parameters": [], + "ReturnType": "System.Int32", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "Capture", + "Parameters": [], + "ReturnType": "System.String", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [ + { + "Name": "condition", + "Type": "System.String" + } + ], + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Field", + "Name": "Template", + "Parameters": [], + "ReturnType": "System.String", + "ReadOnly": true, + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.Rewrite.Internal.Pattern", + "Visibility": "Public", + "Kind": "Class", + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Method", + "Name": "get_PatternSegments", + "Parameters": [], + "ReturnType": "System.Collections.Generic.IList", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "Evaluate", + "Parameters": [ + { + "Name": "context", + "Type": "Microsoft.AspNetCore.Rewrite.RewriteContext" + }, + { + "Name": "ruleBackReferences", + "Type": "Microsoft.AspNetCore.Rewrite.Internal.BackReferenceCollection" + }, + { + "Name": "conditionBackReferences", + "Type": "Microsoft.AspNetCore.Rewrite.Internal.BackReferenceCollection" + } + ], + "ReturnType": "System.String", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [ + { + "Name": "patternSegments", + "Type": "System.Collections.Generic.IList" + } + ], + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.Rewrite.Internal.PatternSegment", + "Visibility": "Public", + "Kind": "Class", + "Abstract": true, + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Method", + "Name": "Evaluate", + "Parameters": [ + { + "Name": "context", + "Type": "Microsoft.AspNetCore.Rewrite.RewriteContext" + }, + { + "Name": "ruleBackReferences", + "Type": "Microsoft.AspNetCore.Rewrite.Internal.BackReferenceCollection" + }, + { + "Name": "conditionBackReferences", + "Type": "Microsoft.AspNetCore.Rewrite.Internal.BackReferenceCollection" + } + ], + "ReturnType": "System.String", + "Virtual": true, + "Abstract": true, + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [], + "Visibility": "Protected", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.Rewrite.Internal.RedirectRule", + "Visibility": "Public", + "Kind": "Class", + "ImplementedInterfaces": [ + "Microsoft.AspNetCore.Rewrite.IRule" + ], + "Members": [ + { + "Kind": "Method", + "Name": "get_InitialMatch", + "Parameters": [], + "ReturnType": "System.Text.RegularExpressions.Regex", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "get_Replacement", + "Parameters": [], + "ReturnType": "System.String", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "get_StatusCode", + "Parameters": [], + "ReturnType": "System.Int32", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "ApplyRule", + "Parameters": [ + { + "Name": "context", + "Type": "Microsoft.AspNetCore.Rewrite.RewriteContext" + } + ], + "ReturnType": "System.Void", + "Virtual": true, + "ImplementedInterface": "Microsoft.AspNetCore.Rewrite.IRule", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [ + { + "Name": "regex", + "Type": "System.String" + }, + { + "Name": "replacement", + "Type": "System.String" + }, + { + "Name": "statusCode", + "Type": "System.Int32" + } + ], + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.Rewrite.Internal.RedirectToHttpsRule", + "Visibility": "Public", + "Kind": "Class", + "ImplementedInterfaces": [ + "Microsoft.AspNetCore.Rewrite.IRule" + ], + "Members": [ + { + "Kind": "Method", + "Name": "get_SSLPort", + "Parameters": [], + "ReturnType": "System.Nullable", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "set_SSLPort", + "Parameters": [ + { + "Name": "value", + "Type": "System.Nullable" + } + ], + "ReturnType": "System.Void", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "get_StatusCode", + "Parameters": [], + "ReturnType": "System.Int32", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "set_StatusCode", + "Parameters": [ + { + "Name": "value", + "Type": "System.Int32" + } + ], + "ReturnType": "System.Void", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "ApplyRule", + "Parameters": [ + { + "Name": "context", + "Type": "Microsoft.AspNetCore.Rewrite.RewriteContext" + } + ], + "ReturnType": "System.Void", + "Virtual": true, + "ImplementedInterface": "Microsoft.AspNetCore.Rewrite.IRule", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [], + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.Rewrite.Internal.RewriteRule", + "Visibility": "Public", + "Kind": "Class", + "ImplementedInterfaces": [ + "Microsoft.AspNetCore.Rewrite.IRule" + ], + "Members": [ + { + "Kind": "Method", + "Name": "get_InitialMatch", + "Parameters": [], + "ReturnType": "System.Text.RegularExpressions.Regex", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "get_Replacement", + "Parameters": [], + "ReturnType": "System.String", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "get_StopProcessing", + "Parameters": [], + "ReturnType": "System.Boolean", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "ApplyRule", + "Parameters": [ + { + "Name": "context", + "Type": "Microsoft.AspNetCore.Rewrite.RewriteContext" + } + ], + "ReturnType": "System.Void", + "Virtual": true, + "ImplementedInterface": "Microsoft.AspNetCore.Rewrite.IRule", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [ + { + "Name": "regex", + "Type": "System.String" + }, + { + "Name": "replacement", + "Type": "System.String" + }, + { + "Name": "stopProcessing", + "Type": "System.Boolean" + } + ], + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.Rewrite.Internal.UrlAction", + "Visibility": "Public", + "Kind": "Class", + "Abstract": true, + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Method", + "Name": "get_Url", + "Parameters": [], + "ReturnType": "Microsoft.AspNetCore.Rewrite.Internal.Pattern", + "Visibility": "Protected", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "set_Url", + "Parameters": [ + { + "Name": "value", + "Type": "Microsoft.AspNetCore.Rewrite.Internal.Pattern" + } + ], + "ReturnType": "System.Void", + "Visibility": "Protected", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "ApplyAction", + "Parameters": [ + { + "Name": "context", + "Type": "Microsoft.AspNetCore.Rewrite.RewriteContext" + }, + { + "Name": "ruleBackReferences", + "Type": "Microsoft.AspNetCore.Rewrite.Internal.BackReferenceCollection" + }, + { + "Name": "conditionBackReferences", + "Type": "Microsoft.AspNetCore.Rewrite.Internal.BackReferenceCollection" + } + ], + "ReturnType": "System.Void", + "Virtual": true, + "Abstract": true, + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [], + "Visibility": "Protected", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.Rewrite.Internal.UrlMatch", + "Visibility": "Public", + "Kind": "Class", + "Abstract": true, + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Method", + "Name": "get_Negate", + "Parameters": [], + "ReturnType": "System.Boolean", + "Visibility": "Protected", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "set_Negate", + "Parameters": [ + { + "Name": "value", + "Type": "System.Boolean" + } + ], + "ReturnType": "System.Void", + "Visibility": "Protected", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "Evaluate", + "Parameters": [ + { + "Name": "input", + "Type": "System.String" + }, + { + "Name": "context", + "Type": "Microsoft.AspNetCore.Rewrite.RewriteContext" + } + ], + "ReturnType": "Microsoft.AspNetCore.Rewrite.Internal.MatchResults", + "Virtual": true, + "Abstract": true, + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [], + "Visibility": "Protected", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.Rewrite.Internal.UrlMatches.ExactMatch", + "Visibility": "Public", + "Kind": "Class", + "BaseType": "Microsoft.AspNetCore.Rewrite.Internal.UrlMatch", + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Method", + "Name": "Evaluate", + "Parameters": [ + { + "Name": "pattern", + "Type": "System.String" + }, + { + "Name": "context", + "Type": "Microsoft.AspNetCore.Rewrite.RewriteContext" + } + ], + "ReturnType": "Microsoft.AspNetCore.Rewrite.Internal.MatchResults", + "Virtual": true, + "Override": true, + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [ + { + "Name": "ignoreCase", + "Type": "System.Boolean" + }, + { + "Name": "input", + "Type": "System.String" + }, + { + "Name": "negate", + "Type": "System.Boolean" + } + ], + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.Rewrite.Internal.UrlMatches.FileSizeMatch", + "Visibility": "Public", + "Kind": "Class", + "BaseType": "Microsoft.AspNetCore.Rewrite.Internal.UrlMatch", + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Method", + "Name": "Evaluate", + "Parameters": [ + { + "Name": "input", + "Type": "System.String" + }, + { + "Name": "context", + "Type": "Microsoft.AspNetCore.Rewrite.RewriteContext" + } + ], + "ReturnType": "Microsoft.AspNetCore.Rewrite.Internal.MatchResults", + "Virtual": true, + "Override": true, + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [ + { + "Name": "negate", + "Type": "System.Boolean" + } + ], + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.Rewrite.Internal.UrlMatches.IntegerMatch", + "Visibility": "Public", + "Kind": "Class", + "BaseType": "Microsoft.AspNetCore.Rewrite.Internal.UrlMatch", + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Method", + "Name": "Evaluate", + "Parameters": [ + { + "Name": "input", + "Type": "System.String" + }, + { + "Name": "context", + "Type": "Microsoft.AspNetCore.Rewrite.RewriteContext" + } + ], + "ReturnType": "Microsoft.AspNetCore.Rewrite.Internal.MatchResults", + "Virtual": true, + "Override": true, + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [ + { + "Name": "value", + "Type": "System.Int32" + }, + { + "Name": "operation", + "Type": "Microsoft.AspNetCore.Rewrite.Internal.UrlMatches.IntegerOperationType" + } + ], + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [ + { + "Name": "value", + "Type": "System.String" + }, + { + "Name": "operation", + "Type": "Microsoft.AspNetCore.Rewrite.Internal.UrlMatches.IntegerOperationType" + } + ], + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.Rewrite.Internal.UrlMatches.IntegerOperationType", + "Visibility": "Public", + "Kind": "Enumeration", + "Sealed": true, + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Field", + "Name": "Equal", + "Parameters": [], + "GenericParameter": [], + "Literal": "0" + }, + { + "Kind": "Field", + "Name": "Greater", + "Parameters": [], + "GenericParameter": [], + "Literal": "1" + }, + { + "Kind": "Field", + "Name": "GreaterEqual", + "Parameters": [], + "GenericParameter": [], + "Literal": "2" + }, + { + "Kind": "Field", + "Name": "Less", + "Parameters": [], + "GenericParameter": [], + "Literal": "3" + }, + { + "Kind": "Field", + "Name": "LessEqual", + "Parameters": [], + "GenericParameter": [], + "Literal": "4" + }, + { + "Kind": "Field", + "Name": "NotEqual", + "Parameters": [], + "GenericParameter": [], + "Literal": "5" + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.Rewrite.Internal.UrlMatches.IsDirectoryMatch", + "Visibility": "Public", + "Kind": "Class", + "BaseType": "Microsoft.AspNetCore.Rewrite.Internal.UrlMatch", + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Method", + "Name": "Evaluate", + "Parameters": [ + { + "Name": "pattern", + "Type": "System.String" + }, + { + "Name": "context", + "Type": "Microsoft.AspNetCore.Rewrite.RewriteContext" + } + ], + "ReturnType": "Microsoft.AspNetCore.Rewrite.Internal.MatchResults", + "Virtual": true, + "Override": true, + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [ + { + "Name": "negate", + "Type": "System.Boolean" + } + ], + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.Rewrite.Internal.UrlMatches.IsFileMatch", + "Visibility": "Public", + "Kind": "Class", + "BaseType": "Microsoft.AspNetCore.Rewrite.Internal.UrlMatch", + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Method", + "Name": "Evaluate", + "Parameters": [ + { + "Name": "pattern", + "Type": "System.String" + }, + { + "Name": "context", + "Type": "Microsoft.AspNetCore.Rewrite.RewriteContext" + } + ], + "ReturnType": "Microsoft.AspNetCore.Rewrite.Internal.MatchResults", + "Virtual": true, + "Override": true, + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [ + { + "Name": "negate", + "Type": "System.Boolean" + } + ], + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.Rewrite.Internal.UrlMatches.RegexMatch", + "Visibility": "Public", + "Kind": "Class", + "BaseType": "Microsoft.AspNetCore.Rewrite.Internal.UrlMatch", + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Method", + "Name": "Evaluate", + "Parameters": [ + { + "Name": "pattern", + "Type": "System.String" + }, + { + "Name": "context", + "Type": "Microsoft.AspNetCore.Rewrite.RewriteContext" + } + ], + "ReturnType": "Microsoft.AspNetCore.Rewrite.Internal.MatchResults", + "Virtual": true, + "Override": true, + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [ + { + "Name": "match", + "Type": "System.Text.RegularExpressions.Regex" + }, + { + "Name": "negate", + "Type": "System.Boolean" + } + ], + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.Rewrite.Internal.UrlMatches.StringMatch", + "Visibility": "Public", + "Kind": "Class", + "BaseType": "Microsoft.AspNetCore.Rewrite.Internal.UrlMatch", + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Method", + "Name": "Evaluate", + "Parameters": [ + { + "Name": "input", + "Type": "System.String" + }, + { + "Name": "context", + "Type": "Microsoft.AspNetCore.Rewrite.RewriteContext" + } + ], + "ReturnType": "Microsoft.AspNetCore.Rewrite.Internal.MatchResults", + "Virtual": true, + "Override": true, + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [ + { + "Name": "value", + "Type": "System.String" + }, + { + "Name": "operation", + "Type": "Microsoft.AspNetCore.Rewrite.Internal.UrlMatches.StringOperationType" + }, + { + "Name": "ignoreCase", + "Type": "System.Boolean" + } + ], + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.Rewrite.Internal.UrlMatches.StringOperationType", + "Visibility": "Public", + "Kind": "Enumeration", + "Sealed": true, + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Field", + "Name": "Equal", + "Parameters": [], + "GenericParameter": [], + "Literal": "0" + }, + { + "Kind": "Field", + "Name": "Greater", + "Parameters": [], + "GenericParameter": [], + "Literal": "1" + }, + { + "Kind": "Field", + "Name": "GreaterEqual", + "Parameters": [], + "GenericParameter": [], + "Literal": "2" + }, + { + "Kind": "Field", + "Name": "Less", + "Parameters": [], + "GenericParameter": [], + "Literal": "3" + }, + { + "Kind": "Field", + "Name": "LessEqual", + "Parameters": [], + "GenericParameter": [], + "Literal": "4" + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.Rewrite.Internal.UrlActions.AbortAction", + "Visibility": "Public", + "Kind": "Class", + "BaseType": "Microsoft.AspNetCore.Rewrite.Internal.UrlAction", + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Method", + "Name": "ApplyAction", + "Parameters": [ + { + "Name": "context", + "Type": "Microsoft.AspNetCore.Rewrite.RewriteContext" + }, + { + "Name": "ruleBackReferences", + "Type": "Microsoft.AspNetCore.Rewrite.Internal.BackReferenceCollection" + }, + { + "Name": "conditionBackReferences", + "Type": "Microsoft.AspNetCore.Rewrite.Internal.BackReferenceCollection" + } + ], + "ReturnType": "System.Void", + "Virtual": true, + "Override": true, + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [], + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.Rewrite.Internal.UrlActions.ChangeCookieAction", + "Visibility": "Public", + "Kind": "Class", + "BaseType": "Microsoft.AspNetCore.Rewrite.Internal.UrlAction", + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Method", + "Name": "get_Name", + "Parameters": [], + "ReturnType": "System.String", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "get_Value", + "Parameters": [], + "ReturnType": "System.String", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "set_Value", + "Parameters": [ + { + "Name": "value", + "Type": "System.String" + } + ], + "ReturnType": "System.Void", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "get_Domain", + "Parameters": [], + "ReturnType": "System.String", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "set_Domain", + "Parameters": [ + { + "Name": "value", + "Type": "System.String" + } + ], + "ReturnType": "System.Void", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "get_Lifetime", + "Parameters": [], + "ReturnType": "System.TimeSpan", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "set_Lifetime", + "Parameters": [ + { + "Name": "value", + "Type": "System.TimeSpan" + } + ], + "ReturnType": "System.Void", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "get_Path", + "Parameters": [], + "ReturnType": "System.String", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "set_Path", + "Parameters": [ + { + "Name": "value", + "Type": "System.String" + } + ], + "ReturnType": "System.Void", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "get_Secure", + "Parameters": [], + "ReturnType": "System.Boolean", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "set_Secure", + "Parameters": [ + { + "Name": "value", + "Type": "System.Boolean" + } + ], + "ReturnType": "System.Void", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "get_HttpOnly", + "Parameters": [], + "ReturnType": "System.Boolean", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "set_HttpOnly", + "Parameters": [ + { + "Name": "value", + "Type": "System.Boolean" + } + ], + "ReturnType": "System.Void", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "ApplyAction", + "Parameters": [ + { + "Name": "context", + "Type": "Microsoft.AspNetCore.Rewrite.RewriteContext" + }, + { + "Name": "ruleBackReferences", + "Type": "Microsoft.AspNetCore.Rewrite.Internal.BackReferenceCollection" + }, + { + "Name": "conditionBackReferences", + "Type": "Microsoft.AspNetCore.Rewrite.Internal.BackReferenceCollection" + } + ], + "ReturnType": "System.Void", + "Virtual": true, + "Override": true, + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [ + { + "Name": "name", + "Type": "System.String" + } + ], + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.Rewrite.Internal.UrlActions.CustomResponseAction", + "Visibility": "Public", + "Kind": "Class", + "BaseType": "Microsoft.AspNetCore.Rewrite.Internal.UrlAction", + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Method", + "Name": "get_StatusCode", + "Parameters": [], + "ReturnType": "System.Int32", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "get_StatusReason", + "Parameters": [], + "ReturnType": "System.String", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "set_StatusReason", + "Parameters": [ + { + "Name": "value", + "Type": "System.String" + } + ], + "ReturnType": "System.Void", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "get_StatusDescription", + "Parameters": [], + "ReturnType": "System.String", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "set_StatusDescription", + "Parameters": [ + { + "Name": "value", + "Type": "System.String" + } + ], + "ReturnType": "System.Void", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "ApplyAction", + "Parameters": [ + { + "Name": "context", + "Type": "Microsoft.AspNetCore.Rewrite.RewriteContext" + }, + { + "Name": "ruleBackReferences", + "Type": "Microsoft.AspNetCore.Rewrite.Internal.BackReferenceCollection" + }, + { + "Name": "conditionBackReferences", + "Type": "Microsoft.AspNetCore.Rewrite.Internal.BackReferenceCollection" + } + ], + "ReturnType": "System.Void", + "Virtual": true, + "Override": true, + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [ + { + "Name": "statusCode", + "Type": "System.Int32" + } + ], + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.Rewrite.Internal.UrlActions.ForbiddenAction", + "Visibility": "Public", + "Kind": "Class", + "BaseType": "Microsoft.AspNetCore.Rewrite.Internal.UrlAction", + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Method", + "Name": "ApplyAction", + "Parameters": [ + { + "Name": "context", + "Type": "Microsoft.AspNetCore.Rewrite.RewriteContext" + }, + { + "Name": "ruleBackReferences", + "Type": "Microsoft.AspNetCore.Rewrite.Internal.BackReferenceCollection" + }, + { + "Name": "conditionBackReferences", + "Type": "Microsoft.AspNetCore.Rewrite.Internal.BackReferenceCollection" + } + ], + "ReturnType": "System.Void", + "Virtual": true, + "Override": true, + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [], + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.Rewrite.Internal.UrlActions.GoneAction", + "Visibility": "Public", + "Kind": "Class", + "BaseType": "Microsoft.AspNetCore.Rewrite.Internal.UrlAction", + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Method", + "Name": "ApplyAction", + "Parameters": [ + { + "Name": "context", + "Type": "Microsoft.AspNetCore.Rewrite.RewriteContext" + }, + { + "Name": "ruleBackReferences", + "Type": "Microsoft.AspNetCore.Rewrite.Internal.BackReferenceCollection" + }, + { + "Name": "conditionBackReferences", + "Type": "Microsoft.AspNetCore.Rewrite.Internal.BackReferenceCollection" + } + ], + "ReturnType": "System.Void", + "Virtual": true, + "Override": true, + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [], + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.Rewrite.Internal.UrlActions.NoneAction", + "Visibility": "Public", + "Kind": "Class", + "BaseType": "Microsoft.AspNetCore.Rewrite.Internal.UrlAction", + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Method", + "Name": "get_Result", + "Parameters": [], + "ReturnType": "Microsoft.AspNetCore.Rewrite.RuleResult", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "ApplyAction", + "Parameters": [ + { + "Name": "context", + "Type": "Microsoft.AspNetCore.Rewrite.RewriteContext" + }, + { + "Name": "ruleBackReferences", + "Type": "Microsoft.AspNetCore.Rewrite.Internal.BackReferenceCollection" + }, + { + "Name": "conditionBackReferences", + "Type": "Microsoft.AspNetCore.Rewrite.Internal.BackReferenceCollection" + } + ], + "ReturnType": "System.Void", + "Virtual": true, + "Override": true, + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [ + { + "Name": "result", + "Type": "Microsoft.AspNetCore.Rewrite.RuleResult" + } + ], + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.Rewrite.Internal.UrlActions.RedirectAction", + "Visibility": "Public", + "Kind": "Class", + "BaseType": "Microsoft.AspNetCore.Rewrite.Internal.UrlAction", + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Method", + "Name": "get_StatusCode", + "Parameters": [], + "ReturnType": "System.Int32", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "get_QueryStringAppend", + "Parameters": [], + "ReturnType": "System.Boolean", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "get_QueryStringDelete", + "Parameters": [], + "ReturnType": "System.Boolean", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "get_EscapeBackReferences", + "Parameters": [], + "ReturnType": "System.Boolean", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "ApplyAction", + "Parameters": [ + { + "Name": "context", + "Type": "Microsoft.AspNetCore.Rewrite.RewriteContext" + }, + { + "Name": "ruleBackReferences", + "Type": "Microsoft.AspNetCore.Rewrite.Internal.BackReferenceCollection" + }, + { + "Name": "conditionBackReferences", + "Type": "Microsoft.AspNetCore.Rewrite.Internal.BackReferenceCollection" + } + ], + "ReturnType": "System.Void", + "Virtual": true, + "Override": true, + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [ + { + "Name": "statusCode", + "Type": "System.Int32" + }, + { + "Name": "pattern", + "Type": "Microsoft.AspNetCore.Rewrite.Internal.Pattern" + }, + { + "Name": "queryStringAppend", + "Type": "System.Boolean" + }, + { + "Name": "queryStringDelete", + "Type": "System.Boolean" + }, + { + "Name": "escapeBackReferences", + "Type": "System.Boolean" + } + ], + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [ + { + "Name": "statusCode", + "Type": "System.Int32" + }, + { + "Name": "pattern", + "Type": "Microsoft.AspNetCore.Rewrite.Internal.Pattern" + }, + { + "Name": "queryStringAppend", + "Type": "System.Boolean" + } + ], + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.Rewrite.Internal.UrlActions.RewriteAction", + "Visibility": "Public", + "Kind": "Class", + "BaseType": "Microsoft.AspNetCore.Rewrite.Internal.UrlAction", + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Method", + "Name": "get_Result", + "Parameters": [], + "ReturnType": "Microsoft.AspNetCore.Rewrite.RuleResult", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "get_QueryStringAppend", + "Parameters": [], + "ReturnType": "System.Boolean", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "get_QueryStringDelete", + "Parameters": [], + "ReturnType": "System.Boolean", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "get_EscapeBackReferences", + "Parameters": [], + "ReturnType": "System.Boolean", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "ApplyAction", + "Parameters": [ + { + "Name": "context", + "Type": "Microsoft.AspNetCore.Rewrite.RewriteContext" + }, + { + "Name": "ruleBackReferences", + "Type": "Microsoft.AspNetCore.Rewrite.Internal.BackReferenceCollection" + }, + { + "Name": "conditionBackReferences", + "Type": "Microsoft.AspNetCore.Rewrite.Internal.BackReferenceCollection" + } + ], + "ReturnType": "System.Void", + "Virtual": true, + "Override": true, + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [ + { + "Name": "result", + "Type": "Microsoft.AspNetCore.Rewrite.RuleResult" + }, + { + "Name": "pattern", + "Type": "Microsoft.AspNetCore.Rewrite.Internal.Pattern" + }, + { + "Name": "queryStringAppend", + "Type": "System.Boolean" + }, + { + "Name": "queryStringDelete", + "Type": "System.Boolean" + }, + { + "Name": "escapeBackReferences", + "Type": "System.Boolean" + } + ], + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [ + { + "Name": "result", + "Type": "Microsoft.AspNetCore.Rewrite.RuleResult" + }, + { + "Name": "pattern", + "Type": "Microsoft.AspNetCore.Rewrite.Internal.Pattern" + }, + { + "Name": "queryStringAppend", + "Type": "System.Boolean" + } + ], + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.Rewrite.Internal.PatternSegments.ConditionMatchSegment", + "Visibility": "Public", + "Kind": "Class", + "BaseType": "Microsoft.AspNetCore.Rewrite.Internal.PatternSegment", + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Method", + "Name": "Evaluate", + "Parameters": [ + { + "Name": "context", + "Type": "Microsoft.AspNetCore.Rewrite.RewriteContext" + }, + { + "Name": "ruleBackReferences", + "Type": "Microsoft.AspNetCore.Rewrite.Internal.BackReferenceCollection" + }, + { + "Name": "conditionBackReferences", + "Type": "Microsoft.AspNetCore.Rewrite.Internal.BackReferenceCollection" + } + ], + "ReturnType": "System.String", + "Virtual": true, + "Override": true, + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [ + { + "Name": "index", + "Type": "System.Int32" + } + ], + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.Rewrite.Internal.PatternSegments.DateTimeSegment", + "Visibility": "Public", + "Kind": "Class", + "BaseType": "Microsoft.AspNetCore.Rewrite.Internal.PatternSegment", + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Method", + "Name": "Evaluate", + "Parameters": [ + { + "Name": "context", + "Type": "Microsoft.AspNetCore.Rewrite.RewriteContext" + }, + { + "Name": "ruleBackReferences", + "Type": "Microsoft.AspNetCore.Rewrite.Internal.BackReferenceCollection" + }, + { + "Name": "conditionBackReference", + "Type": "Microsoft.AspNetCore.Rewrite.Internal.BackReferenceCollection" + } + ], + "ReturnType": "System.String", + "Virtual": true, + "Override": true, + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [ + { + "Name": "segment", + "Type": "System.String" + } + ], + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.Rewrite.Internal.PatternSegments.HeaderSegment", + "Visibility": "Public", + "Kind": "Class", + "BaseType": "Microsoft.AspNetCore.Rewrite.Internal.PatternSegment", + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Method", + "Name": "Evaluate", + "Parameters": [ + { + "Name": "context", + "Type": "Microsoft.AspNetCore.Rewrite.RewriteContext" + }, + { + "Name": "ruleBackReferences", + "Type": "Microsoft.AspNetCore.Rewrite.Internal.BackReferenceCollection" + }, + { + "Name": "conditionBackReferences", + "Type": "Microsoft.AspNetCore.Rewrite.Internal.BackReferenceCollection" + } + ], + "ReturnType": "System.String", + "Virtual": true, + "Override": true, + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [ + { + "Name": "header", + "Type": "System.String" + } + ], + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.Rewrite.Internal.PatternSegments.IsHttpsModSegment", + "Visibility": "Public", + "Kind": "Class", + "BaseType": "Microsoft.AspNetCore.Rewrite.Internal.PatternSegment", + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Method", + "Name": "Evaluate", + "Parameters": [ + { + "Name": "context", + "Type": "Microsoft.AspNetCore.Rewrite.RewriteContext" + }, + { + "Name": "ruleBackReferences", + "Type": "Microsoft.AspNetCore.Rewrite.Internal.BackReferenceCollection" + }, + { + "Name": "conditionBackReferences", + "Type": "Microsoft.AspNetCore.Rewrite.Internal.BackReferenceCollection" + } + ], + "ReturnType": "System.String", + "Virtual": true, + "Override": true, + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [], + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.Rewrite.Internal.PatternSegments.IsHttpsUrlSegment", + "Visibility": "Public", + "Kind": "Class", + "BaseType": "Microsoft.AspNetCore.Rewrite.Internal.PatternSegment", + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Method", + "Name": "Evaluate", + "Parameters": [ + { + "Name": "context", + "Type": "Microsoft.AspNetCore.Rewrite.RewriteContext" + }, + { + "Name": "ruleBackReferences", + "Type": "Microsoft.AspNetCore.Rewrite.Internal.BackReferenceCollection" + }, + { + "Name": "conditionBackReferences", + "Type": "Microsoft.AspNetCore.Rewrite.Internal.BackReferenceCollection" + } + ], + "ReturnType": "System.String", + "Virtual": true, + "Override": true, + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [], + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.Rewrite.Internal.PatternSegments.IsIPV6Segment", + "Visibility": "Public", + "Kind": "Class", + "BaseType": "Microsoft.AspNetCore.Rewrite.Internal.PatternSegment", + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Method", + "Name": "Evaluate", + "Parameters": [ + { + "Name": "context", + "Type": "Microsoft.AspNetCore.Rewrite.RewriteContext" + }, + { + "Name": "ruleBackReferences", + "Type": "Microsoft.AspNetCore.Rewrite.Internal.BackReferenceCollection" + }, + { + "Name": "conditionBackReferences", + "Type": "Microsoft.AspNetCore.Rewrite.Internal.BackReferenceCollection" + } + ], + "ReturnType": "System.String", + "Virtual": true, + "Override": true, + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [], + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.Rewrite.Internal.PatternSegments.LiteralSegment", + "Visibility": "Public", + "Kind": "Class", + "BaseType": "Microsoft.AspNetCore.Rewrite.Internal.PatternSegment", + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Method", + "Name": "Evaluate", + "Parameters": [ + { + "Name": "context", + "Type": "Microsoft.AspNetCore.Rewrite.RewriteContext" + }, + { + "Name": "ruleBackReferences", + "Type": "Microsoft.AspNetCore.Rewrite.Internal.BackReferenceCollection" + }, + { + "Name": "conditionBackReferences", + "Type": "Microsoft.AspNetCore.Rewrite.Internal.BackReferenceCollection" + } + ], + "ReturnType": "System.String", + "Virtual": true, + "Override": true, + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [ + { + "Name": "literal", + "Type": "System.String" + } + ], + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.Rewrite.Internal.PatternSegments.LocalAddressSegment", + "Visibility": "Public", + "Kind": "Class", + "BaseType": "Microsoft.AspNetCore.Rewrite.Internal.PatternSegment", + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Method", + "Name": "Evaluate", + "Parameters": [ + { + "Name": "context", + "Type": "Microsoft.AspNetCore.Rewrite.RewriteContext" + }, + { + "Name": "ruleBackReferences", + "Type": "Microsoft.AspNetCore.Rewrite.Internal.BackReferenceCollection" + }, + { + "Name": "conditionBackReferences", + "Type": "Microsoft.AspNetCore.Rewrite.Internal.BackReferenceCollection" + } + ], + "ReturnType": "System.String", + "Virtual": true, + "Override": true, + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [], + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.Rewrite.Internal.PatternSegments.LocalPortSegment", + "Visibility": "Public", + "Kind": "Class", + "BaseType": "Microsoft.AspNetCore.Rewrite.Internal.PatternSegment", + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Method", + "Name": "Evaluate", + "Parameters": [ + { + "Name": "context", + "Type": "Microsoft.AspNetCore.Rewrite.RewriteContext" + }, + { + "Name": "ruleBackReferences", + "Type": "Microsoft.AspNetCore.Rewrite.Internal.BackReferenceCollection" + }, + { + "Name": "conditionBackReferences", + "Type": "Microsoft.AspNetCore.Rewrite.Internal.BackReferenceCollection" + } + ], + "ReturnType": "System.String", + "Virtual": true, + "Override": true, + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [], + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.Rewrite.Internal.PatternSegments.QueryStringSegment", + "Visibility": "Public", + "Kind": "Class", + "BaseType": "Microsoft.AspNetCore.Rewrite.Internal.PatternSegment", + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Method", + "Name": "Evaluate", + "Parameters": [ + { + "Name": "context", + "Type": "Microsoft.AspNetCore.Rewrite.RewriteContext" + }, + { + "Name": "ruleBackRefernces", + "Type": "Microsoft.AspNetCore.Rewrite.Internal.BackReferenceCollection" + }, + { + "Name": "conditionBackReferences", + "Type": "Microsoft.AspNetCore.Rewrite.Internal.BackReferenceCollection" + } + ], + "ReturnType": "System.String", + "Virtual": true, + "Override": true, + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [], + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.Rewrite.Internal.PatternSegments.RemoteAddressSegment", + "Visibility": "Public", + "Kind": "Class", + "BaseType": "Microsoft.AspNetCore.Rewrite.Internal.PatternSegment", + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Method", + "Name": "Evaluate", + "Parameters": [ + { + "Name": "context", + "Type": "Microsoft.AspNetCore.Rewrite.RewriteContext" + }, + { + "Name": "ruleBackReferences", + "Type": "Microsoft.AspNetCore.Rewrite.Internal.BackReferenceCollection" + }, + { + "Name": "conditionBackReferences", + "Type": "Microsoft.AspNetCore.Rewrite.Internal.BackReferenceCollection" + } + ], + "ReturnType": "System.String", + "Virtual": true, + "Override": true, + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [], + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.Rewrite.Internal.PatternSegments.RemotePortSegment", + "Visibility": "Public", + "Kind": "Class", + "BaseType": "Microsoft.AspNetCore.Rewrite.Internal.PatternSegment", + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Method", + "Name": "Evaluate", + "Parameters": [ + { + "Name": "context", + "Type": "Microsoft.AspNetCore.Rewrite.RewriteContext" + }, + { + "Name": "ruleBackReferences", + "Type": "Microsoft.AspNetCore.Rewrite.Internal.BackReferenceCollection" + }, + { + "Name": "conditionBackReferences", + "Type": "Microsoft.AspNetCore.Rewrite.Internal.BackReferenceCollection" + } + ], + "ReturnType": "System.String", + "Virtual": true, + "Override": true, + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [], + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.Rewrite.Internal.PatternSegments.RequestFileNameSegment", + "Visibility": "Public", + "Kind": "Class", + "BaseType": "Microsoft.AspNetCore.Rewrite.Internal.PatternSegment", + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Method", + "Name": "Evaluate", + "Parameters": [ + { + "Name": "context", + "Type": "Microsoft.AspNetCore.Rewrite.RewriteContext" + }, + { + "Name": "ruleBackReferences", + "Type": "Microsoft.AspNetCore.Rewrite.Internal.BackReferenceCollection" + }, + { + "Name": "conditionBackReferences", + "Type": "Microsoft.AspNetCore.Rewrite.Internal.BackReferenceCollection" + } + ], + "ReturnType": "System.String", + "Virtual": true, + "Override": true, + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [], + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.Rewrite.Internal.PatternSegments.RequestMethodSegment", + "Visibility": "Public", + "Kind": "Class", + "BaseType": "Microsoft.AspNetCore.Rewrite.Internal.PatternSegment", + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Method", + "Name": "Evaluate", + "Parameters": [ + { + "Name": "context", + "Type": "Microsoft.AspNetCore.Rewrite.RewriteContext" + }, + { + "Name": "ruleBackReferences", + "Type": "Microsoft.AspNetCore.Rewrite.Internal.BackReferenceCollection" + }, + { + "Name": "conditionBackReferences", + "Type": "Microsoft.AspNetCore.Rewrite.Internal.BackReferenceCollection" + } + ], + "ReturnType": "System.String", + "Virtual": true, + "Override": true, + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [], + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.Rewrite.Internal.PatternSegments.RewriteMapSegment", + "Visibility": "Public", + "Kind": "Class", + "BaseType": "Microsoft.AspNetCore.Rewrite.Internal.PatternSegment", + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Method", + "Name": "Evaluate", + "Parameters": [ + { + "Name": "context", + "Type": "Microsoft.AspNetCore.Rewrite.RewriteContext" + }, + { + "Name": "ruleBackReferences", + "Type": "Microsoft.AspNetCore.Rewrite.Internal.BackReferenceCollection" + }, + { + "Name": "conditionBackReferences", + "Type": "Microsoft.AspNetCore.Rewrite.Internal.BackReferenceCollection" + } + ], + "ReturnType": "System.String", + "Virtual": true, + "Override": true, + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [ + { + "Name": "rewriteMap", + "Type": "Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite.IISRewriteMap" + }, + { + "Name": "pattern", + "Type": "Microsoft.AspNetCore.Rewrite.Internal.Pattern" + } + ], + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.Rewrite.Internal.PatternSegments.RuleMatchSegment", + "Visibility": "Public", + "Kind": "Class", + "BaseType": "Microsoft.AspNetCore.Rewrite.Internal.PatternSegment", + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Method", + "Name": "Evaluate", + "Parameters": [ + { + "Name": "context", + "Type": "Microsoft.AspNetCore.Rewrite.RewriteContext" + }, + { + "Name": "ruleBackReferences", + "Type": "Microsoft.AspNetCore.Rewrite.Internal.BackReferenceCollection" + }, + { + "Name": "conditionBackReferences", + "Type": "Microsoft.AspNetCore.Rewrite.Internal.BackReferenceCollection" + } + ], + "ReturnType": "System.String", + "Virtual": true, + "Override": true, + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [ + { + "Name": "index", + "Type": "System.Int32" + } + ], + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.Rewrite.Internal.PatternSegments.SchemeSegment", + "Visibility": "Public", + "Kind": "Class", + "BaseType": "Microsoft.AspNetCore.Rewrite.Internal.PatternSegment", + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Method", + "Name": "Evaluate", + "Parameters": [ + { + "Name": "context", + "Type": "Microsoft.AspNetCore.Rewrite.RewriteContext" + }, + { + "Name": "ruleBackReferences", + "Type": "Microsoft.AspNetCore.Rewrite.Internal.BackReferenceCollection" + }, + { + "Name": "conditionBackReferences", + "Type": "Microsoft.AspNetCore.Rewrite.Internal.BackReferenceCollection" + } + ], + "ReturnType": "System.String", + "Virtual": true, + "Override": true, + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [], + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.Rewrite.Internal.PatternSegments.ServerProtocolSegment", + "Visibility": "Public", + "Kind": "Class", + "BaseType": "Microsoft.AspNetCore.Rewrite.Internal.PatternSegment", + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Method", + "Name": "Evaluate", + "Parameters": [ + { + "Name": "context", + "Type": "Microsoft.AspNetCore.Rewrite.RewriteContext" + }, + { + "Name": "ruleBackReferences", + "Type": "Microsoft.AspNetCore.Rewrite.Internal.BackReferenceCollection" + }, + { + "Name": "conditionBackReferences", + "Type": "Microsoft.AspNetCore.Rewrite.Internal.BackReferenceCollection" + } + ], + "ReturnType": "System.String", + "Virtual": true, + "Override": true, + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [], + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.Rewrite.Internal.PatternSegments.ToLowerSegment", + "Visibility": "Public", + "Kind": "Class", + "BaseType": "Microsoft.AspNetCore.Rewrite.Internal.PatternSegment", + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Method", + "Name": "Evaluate", + "Parameters": [ + { + "Name": "context", + "Type": "Microsoft.AspNetCore.Rewrite.RewriteContext" + }, + { + "Name": "ruleBackReferences", + "Type": "Microsoft.AspNetCore.Rewrite.Internal.BackReferenceCollection" + }, + { + "Name": "conditionBackReferences", + "Type": "Microsoft.AspNetCore.Rewrite.Internal.BackReferenceCollection" + } + ], + "ReturnType": "System.String", + "Virtual": true, + "Override": true, + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [ + { + "Name": "pattern", + "Type": "Microsoft.AspNetCore.Rewrite.Internal.Pattern" + } + ], + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.Rewrite.Internal.PatternSegments.UrlEncodeSegment", + "Visibility": "Public", + "Kind": "Class", + "BaseType": "Microsoft.AspNetCore.Rewrite.Internal.PatternSegment", + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Method", + "Name": "Evaluate", + "Parameters": [ + { + "Name": "context", + "Type": "Microsoft.AspNetCore.Rewrite.RewriteContext" + }, + { + "Name": "ruleBackReferences", + "Type": "Microsoft.AspNetCore.Rewrite.Internal.BackReferenceCollection" + }, + { + "Name": "conditionBackReferences", + "Type": "Microsoft.AspNetCore.Rewrite.Internal.BackReferenceCollection" + } + ], + "ReturnType": "System.String", + "Virtual": true, + "Override": true, + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [ + { + "Name": "pattern", + "Type": "Microsoft.AspNetCore.Rewrite.Internal.Pattern" + } + ], + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.Rewrite.Internal.PatternSegments.UrlSegment", + "Visibility": "Public", + "Kind": "Class", + "BaseType": "Microsoft.AspNetCore.Rewrite.Internal.PatternSegment", + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Method", + "Name": "Evaluate", + "Parameters": [ + { + "Name": "context", + "Type": "Microsoft.AspNetCore.Rewrite.RewriteContext" + }, + { + "Name": "ruleBackReferences", + "Type": "Microsoft.AspNetCore.Rewrite.Internal.BackReferenceCollection" + }, + { + "Name": "conditionBackReferences", + "Type": "Microsoft.AspNetCore.Rewrite.Internal.BackReferenceCollection" + } + ], + "ReturnType": "System.String", + "Virtual": true, + "Override": true, + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [], + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [ + { + "Name": "uriMatchPart", + "Type": "Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite.UriMatchPart" + } + ], + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite.ActionType", + "Visibility": "Public", + "Kind": "Enumeration", + "Sealed": true, + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Field", + "Name": "None", + "Parameters": [], + "GenericParameter": [], + "Literal": "0" + }, + { + "Kind": "Field", + "Name": "Rewrite", + "Parameters": [], + "GenericParameter": [], + "Literal": "1" + }, + { + "Kind": "Field", + "Name": "Redirect", + "Parameters": [], + "GenericParameter": [], + "Literal": "2" + }, + { + "Kind": "Field", + "Name": "CustomResponse", + "Parameters": [], + "GenericParameter": [], + "Literal": "3" + }, + { + "Kind": "Field", + "Name": "AbortRequest", + "Parameters": [], + "GenericParameter": [], + "Literal": "4" + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite.Condition", + "Visibility": "Public", + "Kind": "Class", + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Method", + "Name": "get_Input", + "Parameters": [], + "ReturnType": "Microsoft.AspNetCore.Rewrite.Internal.Pattern", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "set_Input", + "Parameters": [ + { + "Name": "value", + "Type": "Microsoft.AspNetCore.Rewrite.Internal.Pattern" + } + ], + "ReturnType": "System.Void", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "get_Match", + "Parameters": [], + "ReturnType": "Microsoft.AspNetCore.Rewrite.Internal.UrlMatch", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "set_Match", + "Parameters": [ + { + "Name": "value", + "Type": "Microsoft.AspNetCore.Rewrite.Internal.UrlMatch" + } + ], + "ReturnType": "System.Void", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "Evaluate", + "Parameters": [ + { + "Name": "context", + "Type": "Microsoft.AspNetCore.Rewrite.RewriteContext" + }, + { + "Name": "ruleBackReferences", + "Type": "Microsoft.AspNetCore.Rewrite.Internal.BackReferenceCollection" + }, + { + "Name": "conditionBackReferences", + "Type": "Microsoft.AspNetCore.Rewrite.Internal.BackReferenceCollection" + } + ], + "ReturnType": "Microsoft.AspNetCore.Rewrite.Internal.MatchResults", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [], + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite.ConditionCollection", + "Visibility": "Public", + "Kind": "Class", + "ImplementedInterfaces": [ + "System.Collections.Generic.IEnumerable" + ], + "Members": [ + { + "Kind": "Method", + "Name": "get_Grouping", + "Parameters": [], + "ReturnType": "Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite.LogicalGrouping", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "get_TrackAllCaptures", + "Parameters": [], + "ReturnType": "System.Boolean", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "get_Count", + "Parameters": [], + "ReturnType": "System.Int32", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "get_Item", + "Parameters": [ + { + "Name": "index", + "Type": "System.Int32" + } + ], + "ReturnType": "Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite.Condition", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "Add", + "Parameters": [ + { + "Name": "condition", + "Type": "Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite.Condition" + } + ], + "ReturnType": "System.Void", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "AddConditions", + "Parameters": [ + { + "Name": "conditions", + "Type": "System.Collections.Generic.IEnumerable" + } + ], + "ReturnType": "System.Void", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "GetEnumerator", + "Parameters": [], + "ReturnType": "System.Collections.Generic.IEnumerator", + "Sealed": true, + "Virtual": true, + "ImplementedInterface": "System.Collections.Generic.IEnumerable", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [], + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [ + { + "Name": "grouping", + "Type": "Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite.LogicalGrouping" + }, + { + "Name": "trackAllCaptures", + "Type": "System.Boolean" + } + ], + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite.ConditionEvaluator", + "Visibility": "Public", + "Kind": "Class", + "Abstract": true, + "Static": true, + "Sealed": true, + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Method", + "Name": "Evaluate", + "Parameters": [ + { + "Name": "conditions", + "Type": "Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite.ConditionCollection" + }, + { + "Name": "context", + "Type": "Microsoft.AspNetCore.Rewrite.RewriteContext" + }, + { + "Name": "backReferences", + "Type": "Microsoft.AspNetCore.Rewrite.Internal.BackReferenceCollection" + } + ], + "ReturnType": "Microsoft.AspNetCore.Rewrite.Internal.MatchResults", + "Static": true, + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite.IISRewriteMap", + "Visibility": "Public", + "Kind": "Class", + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Method", + "Name": "get_Name", + "Parameters": [], + "ReturnType": "System.String", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "get_Item", + "Parameters": [ + { + "Name": "key", + "Type": "System.String" + } + ], + "ReturnType": "System.String", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "set_Item", + "Parameters": [ + { + "Name": "key", + "Type": "System.String" + }, + { + "Name": "value", + "Type": "System.String" + } + ], + "ReturnType": "System.Void", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [ + { + "Name": "name", + "Type": "System.String" + } + ], + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite.IISRewriteMapCollection", + "Visibility": "Public", + "Kind": "Class", + "ImplementedInterfaces": [ + "System.Collections.Generic.IEnumerable" + ], + "Members": [ + { + "Kind": "Method", + "Name": "Add", + "Parameters": [ + { + "Name": "rewriteMap", + "Type": "Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite.IISRewriteMap" + } + ], + "ReturnType": "System.Void", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "get_Count", + "Parameters": [], + "ReturnType": "System.Int32", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "get_Item", + "Parameters": [ + { + "Name": "key", + "Type": "System.String" + } + ], + "ReturnType": "Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite.IISRewriteMap", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "GetEnumerator", + "Parameters": [], + "ReturnType": "System.Collections.Generic.IEnumerator", + "Sealed": true, + "Virtual": true, + "ImplementedInterface": "System.Collections.Generic.IEnumerable", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [], + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite.IISUrlRewriteRule", + "Visibility": "Public", + "Kind": "Class", + "ImplementedInterfaces": [ + "Microsoft.AspNetCore.Rewrite.IRule" + ], + "Members": [ + { + "Kind": "Method", + "Name": "get_Name", + "Parameters": [], + "ReturnType": "System.String", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "get_InitialMatch", + "Parameters": [], + "ReturnType": "Microsoft.AspNetCore.Rewrite.Internal.UrlMatch", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "get_Conditions", + "Parameters": [], + "ReturnType": "Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite.ConditionCollection", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "get_Action", + "Parameters": [], + "ReturnType": "Microsoft.AspNetCore.Rewrite.Internal.UrlAction", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "get_Global", + "Parameters": [], + "ReturnType": "System.Boolean", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "ApplyRule", + "Parameters": [ + { + "Name": "context", + "Type": "Microsoft.AspNetCore.Rewrite.RewriteContext" + } + ], + "ReturnType": "System.Void", + "Virtual": true, + "ImplementedInterface": "Microsoft.AspNetCore.Rewrite.IRule", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [ + { + "Name": "name", + "Type": "System.String" + }, + { + "Name": "initialMatch", + "Type": "Microsoft.AspNetCore.Rewrite.Internal.UrlMatch" + }, + { + "Name": "conditions", + "Type": "Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite.ConditionCollection" + }, + { + "Name": "action", + "Type": "Microsoft.AspNetCore.Rewrite.Internal.UrlAction" + } + ], + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [ + { + "Name": "name", + "Type": "System.String" + }, + { + "Name": "initialMatch", + "Type": "Microsoft.AspNetCore.Rewrite.Internal.UrlMatch" + }, + { + "Name": "conditions", + "Type": "Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite.ConditionCollection" + }, + { + "Name": "action", + "Type": "Microsoft.AspNetCore.Rewrite.Internal.UrlAction" + }, + { + "Name": "global", + "Type": "System.Boolean" + } + ], + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite.InputParser", + "Visibility": "Public", + "Kind": "Class", + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Method", + "Name": "ParseInputString", + "Parameters": [ + { + "Name": "testString", + "Type": "System.String" + } + ], + "ReturnType": "Microsoft.AspNetCore.Rewrite.Internal.Pattern", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "ParseInputString", + "Parameters": [ + { + "Name": "testString", + "Type": "System.String" + }, + { + "Name": "uriMatchPart", + "Type": "Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite.UriMatchPart" + } + ], + "ReturnType": "Microsoft.AspNetCore.Rewrite.Internal.Pattern", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [], + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [ + { + "Name": "rewriteMaps", + "Type": "Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite.IISRewriteMapCollection" + } + ], + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite.InvalidUrlRewriteFormatException", + "Visibility": "Public", + "Kind": "Class", + "BaseType": "System.FormatException", + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Method", + "Name": "get_LineNumber", + "Parameters": [], + "ReturnType": "System.Int32", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "get_LinePosition", + "Parameters": [], + "ReturnType": "System.Int32", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [ + { + "Name": "element", + "Type": "System.Xml.Linq.XElement" + }, + { + "Name": "message", + "Type": "System.String" + } + ], + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [ + { + "Name": "element", + "Type": "System.Xml.Linq.XElement" + }, + { + "Name": "message", + "Type": "System.String" + }, + { + "Name": "innerException", + "Type": "System.Exception" + } + ], + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite.LogicalGrouping", + "Visibility": "Public", + "Kind": "Enumeration", + "Sealed": true, + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Field", + "Name": "MatchAll", + "Parameters": [], + "GenericParameter": [], + "Literal": "0" + }, + { + "Kind": "Field", + "Name": "MatchAny", + "Parameters": [], + "GenericParameter": [], + "Literal": "1" + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite.MatchType", + "Visibility": "Public", + "Kind": "Enumeration", + "Sealed": true, + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Field", + "Name": "Pattern", + "Parameters": [], + "GenericParameter": [], + "Literal": "0" + }, + { + "Kind": "Field", + "Name": "IsFile", + "Parameters": [], + "GenericParameter": [], + "Literal": "1" + }, + { + "Kind": "Field", + "Name": "IsDirectory", + "Parameters": [], + "GenericParameter": [], + "Literal": "2" + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite.PatternSyntax", + "Visibility": "Public", + "Kind": "Enumeration", + "Sealed": true, + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Field", + "Name": "ECMAScript", + "Parameters": [], + "GenericParameter": [], + "Literal": "0" + }, + { + "Kind": "Field", + "Name": "Wildcard", + "Parameters": [], + "GenericParameter": [], + "Literal": "1" + }, + { + "Kind": "Field", + "Name": "ExactMatch", + "Parameters": [], + "GenericParameter": [], + "Literal": "2" + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite.RedirectType", + "Visibility": "Public", + "Kind": "Enumeration", + "Sealed": true, + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Field", + "Name": "Permanent", + "Parameters": [], + "GenericParameter": [], + "Literal": "301" + }, + { + "Kind": "Field", + "Name": "Found", + "Parameters": [], + "GenericParameter": [], + "Literal": "302" + }, + { + "Kind": "Field", + "Name": "SeeOther", + "Parameters": [], + "GenericParameter": [], + "Literal": "303" + }, + { + "Kind": "Field", + "Name": "Temporary", + "Parameters": [], + "GenericParameter": [], + "Literal": "307" + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite.RewriteMapParser", + "Visibility": "Public", + "Kind": "Class", + "Abstract": true, + "Static": true, + "Sealed": true, + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Method", + "Name": "Parse", + "Parameters": [ + { + "Name": "xmlRoot", + "Type": "System.Xml.Linq.XElement" + } + ], + "ReturnType": "Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite.IISRewriteMapCollection", + "Static": true, + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite.RewriteTags", + "Visibility": "Public", + "Kind": "Class", + "Abstract": true, + "Static": true, + "Sealed": true, + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Field", + "Name": "Action", + "Parameters": [], + "ReturnType": "System.String", + "Static": true, + "Visibility": "Public", + "GenericParameter": [], + "Constant": true, + "Literal": "\"action\"" + }, + { + "Kind": "Field", + "Name": "Add", + "Parameters": [], + "ReturnType": "System.String", + "Static": true, + "Visibility": "Public", + "GenericParameter": [], + "Constant": true, + "Literal": "\"add\"" + }, + { + "Kind": "Field", + "Name": "AppendQueryString", + "Parameters": [], + "ReturnType": "System.String", + "Static": true, + "Visibility": "Public", + "GenericParameter": [], + "Constant": true, + "Literal": "\"appendQueryString\"" + }, + { + "Kind": "Field", + "Name": "Conditions", + "Parameters": [], + "ReturnType": "System.String", + "Static": true, + "Visibility": "Public", + "GenericParameter": [], + "Constant": true, + "Literal": "\"conditions\"" + }, + { + "Kind": "Field", + "Name": "Enabled", + "Parameters": [], + "ReturnType": "System.String", + "Static": true, + "Visibility": "Public", + "GenericParameter": [], + "Constant": true, + "Literal": "\"enabled\"" + }, + { + "Kind": "Field", + "Name": "GlobalRules", + "Parameters": [], + "ReturnType": "System.String", + "Static": true, + "Visibility": "Public", + "GenericParameter": [], + "Constant": true, + "Literal": "\"globalRules\"" + }, + { + "Kind": "Field", + "Name": "IgnoreCase", + "Parameters": [], + "ReturnType": "System.String", + "Static": true, + "Visibility": "Public", + "GenericParameter": [], + "Constant": true, + "Literal": "\"ignoreCase\"" + }, + { + "Kind": "Field", + "Name": "Input", + "Parameters": [], + "ReturnType": "System.String", + "Static": true, + "Visibility": "Public", + "GenericParameter": [], + "Constant": true, + "Literal": "\"input\"" + }, + { + "Kind": "Field", + "Name": "Key", + "Parameters": [], + "ReturnType": "System.String", + "Static": true, + "Visibility": "Public", + "GenericParameter": [], + "Constant": true, + "Literal": "\"key\"" + }, + { + "Kind": "Field", + "Name": "LogicalGrouping", + "Parameters": [], + "ReturnType": "System.String", + "Static": true, + "Visibility": "Public", + "GenericParameter": [], + "Constant": true, + "Literal": "\"logicalGrouping\"" + }, + { + "Kind": "Field", + "Name": "LogRewrittenUrl", + "Parameters": [], + "ReturnType": "System.String", + "Static": true, + "Visibility": "Public", + "GenericParameter": [], + "Constant": true, + "Literal": "\"logRewrittenUrl\"" + }, + { + "Kind": "Field", + "Name": "Match", + "Parameters": [], + "ReturnType": "System.String", + "Static": true, + "Visibility": "Public", + "GenericParameter": [], + "Constant": true, + "Literal": "\"match\"" + }, + { + "Kind": "Field", + "Name": "MatchPattern", + "Parameters": [], + "ReturnType": "System.String", + "Static": true, + "Visibility": "Public", + "GenericParameter": [], + "Constant": true, + "Literal": "\"matchPattern\"" + }, + { + "Kind": "Field", + "Name": "MatchType", + "Parameters": [], + "ReturnType": "System.String", + "Static": true, + "Visibility": "Public", + "GenericParameter": [], + "Constant": true, + "Literal": "\"matchType\"" + }, + { + "Kind": "Field", + "Name": "Name", + "Parameters": [], + "ReturnType": "System.String", + "Static": true, + "Visibility": "Public", + "GenericParameter": [], + "Constant": true, + "Literal": "\"name\"" + }, + { + "Kind": "Field", + "Name": "Negate", + "Parameters": [], + "ReturnType": "System.String", + "Static": true, + "Visibility": "Public", + "GenericParameter": [], + "Constant": true, + "Literal": "\"negate\"" + }, + { + "Kind": "Field", + "Name": "Pattern", + "Parameters": [], + "ReturnType": "System.String", + "Static": true, + "Visibility": "Public", + "GenericParameter": [], + "Constant": true, + "Literal": "\"pattern\"" + }, + { + "Kind": "Field", + "Name": "PatternSyntax", + "Parameters": [], + "ReturnType": "System.String", + "Static": true, + "Visibility": "Public", + "GenericParameter": [], + "Constant": true, + "Literal": "\"patternSyntax\"" + }, + { + "Kind": "Field", + "Name": "RedirectType", + "Parameters": [], + "ReturnType": "System.String", + "Static": true, + "Visibility": "Public", + "GenericParameter": [], + "Constant": true, + "Literal": "\"redirectType\"" + }, + { + "Kind": "Field", + "Name": "Rewrite", + "Parameters": [], + "ReturnType": "System.String", + "Static": true, + "Visibility": "Public", + "GenericParameter": [], + "Constant": true, + "Literal": "\"rewrite\"" + }, + { + "Kind": "Field", + "Name": "RewriteMap", + "Parameters": [], + "ReturnType": "System.String", + "Static": true, + "Visibility": "Public", + "GenericParameter": [], + "Constant": true, + "Literal": "\"rewriteMap\"" + }, + { + "Kind": "Field", + "Name": "RewriteMaps", + "Parameters": [], + "ReturnType": "System.String", + "Static": true, + "Visibility": "Public", + "GenericParameter": [], + "Constant": true, + "Literal": "\"rewriteMaps\"" + }, + { + "Kind": "Field", + "Name": "Rule", + "Parameters": [], + "ReturnType": "System.String", + "Static": true, + "Visibility": "Public", + "GenericParameter": [], + "Constant": true, + "Literal": "\"rule\"" + }, + { + "Kind": "Field", + "Name": "Rules", + "Parameters": [], + "ReturnType": "System.String", + "Static": true, + "Visibility": "Public", + "GenericParameter": [], + "Constant": true, + "Literal": "\"rules\"" + }, + { + "Kind": "Field", + "Name": "StatusCode", + "Parameters": [], + "ReturnType": "System.String", + "Static": true, + "Visibility": "Public", + "GenericParameter": [], + "Constant": true, + "Literal": "\"statusCode\"" + }, + { + "Kind": "Field", + "Name": "SubStatusCode", + "Parameters": [], + "ReturnType": "System.String", + "Static": true, + "Visibility": "Public", + "GenericParameter": [], + "Constant": true, + "Literal": "\"subStatusCode\"" + }, + { + "Kind": "Field", + "Name": "StatusDescription", + "Parameters": [], + "ReturnType": "System.String", + "Static": true, + "Visibility": "Public", + "GenericParameter": [], + "Constant": true, + "Literal": "\"statusDescription\"" + }, + { + "Kind": "Field", + "Name": "StatusReason", + "Parameters": [], + "ReturnType": "System.String", + "Static": true, + "Visibility": "Public", + "GenericParameter": [], + "Constant": true, + "Literal": "\"statusReason\"" + }, + { + "Kind": "Field", + "Name": "StopProcessing", + "Parameters": [], + "ReturnType": "System.String", + "Static": true, + "Visibility": "Public", + "GenericParameter": [], + "Constant": true, + "Literal": "\"stopProcessing\"" + }, + { + "Kind": "Field", + "Name": "TrackAllCaptures", + "Parameters": [], + "ReturnType": "System.String", + "Static": true, + "Visibility": "Public", + "GenericParameter": [], + "Constant": true, + "Literal": "\"trackAllCaptures\"" + }, + { + "Kind": "Field", + "Name": "Type", + "Parameters": [], + "ReturnType": "System.String", + "Static": true, + "Visibility": "Public", + "GenericParameter": [], + "Constant": true, + "Literal": "\"type\"" + }, + { + "Kind": "Field", + "Name": "Url", + "Parameters": [], + "ReturnType": "System.String", + "Static": true, + "Visibility": "Public", + "GenericParameter": [], + "Constant": true, + "Literal": "\"url\"" + }, + { + "Kind": "Field", + "Name": "Value", + "Parameters": [], + "ReturnType": "System.String", + "Static": true, + "Visibility": "Public", + "GenericParameter": [], + "Constant": true, + "Literal": "\"value\"" + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite.ServerVariables", + "Visibility": "Public", + "Kind": "Class", + "Abstract": true, + "Static": true, + "Sealed": true, + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Method", + "Name": "FindServerVariable", + "Parameters": [ + { + "Name": "serverVariable", + "Type": "System.String" + }, + { + "Name": "context", + "Type": "Microsoft.AspNetCore.Rewrite.Internal.ParserContext" + }, + { + "Name": "uriMatchPart", + "Type": "Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite.UriMatchPart" + } + ], + "ReturnType": "Microsoft.AspNetCore.Rewrite.Internal.PatternSegment", + "Static": true, + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite.UriMatchCondition", + "Visibility": "Public", + "Kind": "Class", + "BaseType": "Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite.Condition", + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [ + { + "Name": "inputParser", + "Type": "Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite.InputParser" + }, + { + "Name": "input", + "Type": "System.String" + }, + { + "Name": "pattern", + "Type": "System.String" + }, + { + "Name": "uriMatchPart", + "Type": "Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite.UriMatchPart" + }, + { + "Name": "ignoreCase", + "Type": "System.Boolean" + }, + { + "Name": "negate", + "Type": "System.Boolean" + } + ], + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite.UriMatchPart", + "Visibility": "Public", + "Kind": "Enumeration", + "Sealed": true, + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Field", + "Name": "Full", + "Parameters": [], + "GenericParameter": [], + "Literal": "0" + }, + { + "Kind": "Field", + "Name": "Path", + "Parameters": [], + "GenericParameter": [], + "Literal": "1" + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite.UrlRewriteFileParser", + "Visibility": "Public", + "Kind": "Class", + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Method", + "Name": "Parse", + "Parameters": [ + { + "Name": "reader", + "Type": "System.IO.TextReader" + } + ], + "ReturnType": "System.Collections.Generic.IList", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [], + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite.UrlRewriteRuleBuilder", + "Visibility": "Public", + "Kind": "Class", + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Method", + "Name": "get_Name", + "Parameters": [], + "ReturnType": "System.String", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "set_Name", + "Parameters": [ + { + "Name": "value", + "Type": "System.String" + } + ], + "ReturnType": "System.Void", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "get_Enabled", + "Parameters": [], + "ReturnType": "System.Boolean", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "set_Enabled", + "Parameters": [ + { + "Name": "value", + "Type": "System.Boolean" + } + ], + "ReturnType": "System.Void", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "get_Global", + "Parameters": [], + "ReturnType": "System.Boolean", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "set_Global", + "Parameters": [ + { + "Name": "value", + "Type": "System.Boolean" + } + ], + "ReturnType": "System.Void", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "get_UriMatchPart", + "Parameters": [], + "ReturnType": "Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite.UriMatchPart", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "Build", + "Parameters": [], + "ReturnType": "Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite.IISUrlRewriteRule", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "AddUrlAction", + "Parameters": [ + { + "Name": "action", + "Type": "Microsoft.AspNetCore.Rewrite.Internal.UrlAction" + } + ], + "ReturnType": "System.Void", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "AddUrlMatch", + "Parameters": [ + { + "Name": "input", + "Type": "System.String" + }, + { + "Name": "ignoreCase", + "Type": "System.Boolean", + "DefaultValue": "True" + }, + { + "Name": "negate", + "Type": "System.Boolean", + "DefaultValue": "False" + }, + { + "Name": "patternSyntax", + "Type": "Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite.PatternSyntax", + "DefaultValue": "0" + } + ], + "ReturnType": "System.Void", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "ConfigureConditionBehavior", + "Parameters": [ + { + "Name": "logicalGrouping", + "Type": "Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite.LogicalGrouping" + }, + { + "Name": "trackAllCaptures", + "Type": "System.Boolean" + } + ], + "ReturnType": "System.Void", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "AddUrlCondition", + "Parameters": [ + { + "Name": "condition", + "Type": "Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite.Condition" + } + ], + "ReturnType": "System.Void", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "AddUrlConditions", + "Parameters": [ + { + "Name": "conditions", + "Type": "System.Collections.Generic.IEnumerable" + } + ], + "ReturnType": "System.Void", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [], + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.Rewrite.Internal.ApacheModRewrite.ApacheModRewriteRule", + "Visibility": "Public", + "Kind": "Class", + "ImplementedInterfaces": [ + "Microsoft.AspNetCore.Rewrite.IRule" + ], + "Members": [ + { + "Kind": "Method", + "Name": "get_InitialMatch", + "Parameters": [], + "ReturnType": "Microsoft.AspNetCore.Rewrite.Internal.UrlMatch", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "get_Conditions", + "Parameters": [], + "ReturnType": "System.Collections.Generic.IList", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "get_Actions", + "Parameters": [], + "ReturnType": "System.Collections.Generic.IList", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "ApplyRule", + "Parameters": [ + { + "Name": "context", + "Type": "Microsoft.AspNetCore.Rewrite.RewriteContext" + } + ], + "ReturnType": "System.Void", + "Virtual": true, + "ImplementedInterface": "Microsoft.AspNetCore.Rewrite.IRule", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [ + { + "Name": "initialMatch", + "Type": "Microsoft.AspNetCore.Rewrite.Internal.UrlMatch" + }, + { + "Name": "conditions", + "Type": "System.Collections.Generic.IList" + }, + { + "Name": "urlActions", + "Type": "System.Collections.Generic.IList" + } + ], + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.Rewrite.Internal.ApacheModRewrite.Condition", + "Visibility": "Public", + "Kind": "Class", + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Method", + "Name": "get_Input", + "Parameters": [], + "ReturnType": "Microsoft.AspNetCore.Rewrite.Internal.Pattern", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "set_Input", + "Parameters": [ + { + "Name": "value", + "Type": "Microsoft.AspNetCore.Rewrite.Internal.Pattern" + } + ], + "ReturnType": "System.Void", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "get_Match", + "Parameters": [], + "ReturnType": "Microsoft.AspNetCore.Rewrite.Internal.UrlMatch", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "set_Match", + "Parameters": [ + { + "Name": "value", + "Type": "Microsoft.AspNetCore.Rewrite.Internal.UrlMatch" + } + ], + "ReturnType": "System.Void", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "get_OrNext", + "Parameters": [], + "ReturnType": "System.Boolean", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "set_OrNext", + "Parameters": [ + { + "Name": "value", + "Type": "System.Boolean" + } + ], + "ReturnType": "System.Void", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "Evaluate", + "Parameters": [ + { + "Name": "context", + "Type": "Microsoft.AspNetCore.Rewrite.RewriteContext" + }, + { + "Name": "ruleBackReferences", + "Type": "Microsoft.AspNetCore.Rewrite.Internal.BackReferenceCollection" + }, + { + "Name": "conditionBackReferences", + "Type": "Microsoft.AspNetCore.Rewrite.Internal.BackReferenceCollection" + } + ], + "ReturnType": "Microsoft.AspNetCore.Rewrite.Internal.MatchResults", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [], + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.Rewrite.Internal.ApacheModRewrite.ConditionEvaluator", + "Visibility": "Public", + "Kind": "Class", + "Abstract": true, + "Static": true, + "Sealed": true, + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Method", + "Name": "Evaluate", + "Parameters": [ + { + "Name": "conditions", + "Type": "System.Collections.Generic.IEnumerable" + }, + { + "Name": "context", + "Type": "Microsoft.AspNetCore.Rewrite.RewriteContext" + }, + { + "Name": "backReferences", + "Type": "Microsoft.AspNetCore.Rewrite.Internal.BackReferenceCollection" + } + ], + "ReturnType": "Microsoft.AspNetCore.Rewrite.Internal.MatchResults", + "Static": true, + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "Evaluate", + "Parameters": [ + { + "Name": "conditions", + "Type": "System.Collections.Generic.IEnumerable" + }, + { + "Name": "context", + "Type": "Microsoft.AspNetCore.Rewrite.RewriteContext" + }, + { + "Name": "backReferences", + "Type": "Microsoft.AspNetCore.Rewrite.Internal.BackReferenceCollection" + }, + { + "Name": "trackAllCaptures", + "Type": "System.Boolean" + } + ], + "ReturnType": "Microsoft.AspNetCore.Rewrite.Internal.MatchResults", + "Static": true, + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.Rewrite.Internal.ApacheModRewrite.ConditionPatternParser", + "Visibility": "Public", + "Kind": "Class", + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Method", + "Name": "ParseActionCondition", + "Parameters": [ + { + "Name": "condition", + "Type": "System.String" + } + ], + "ReturnType": "Microsoft.AspNetCore.Rewrite.Internal.ApacheModRewrite.ParsedModRewriteInput", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [], + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.Rewrite.Internal.ApacheModRewrite.ConditionType", + "Visibility": "Public", + "Kind": "Enumeration", + "Sealed": true, + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Field", + "Name": "Regex", + "Parameters": [], + "GenericParameter": [], + "Literal": "0" + }, + { + "Kind": "Field", + "Name": "PropertyTest", + "Parameters": [], + "GenericParameter": [], + "Literal": "1" + }, + { + "Kind": "Field", + "Name": "StringComp", + "Parameters": [], + "GenericParameter": [], + "Literal": "2" + }, + { + "Kind": "Field", + "Name": "IntComp", + "Parameters": [], + "GenericParameter": [], + "Literal": "3" + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.Rewrite.Internal.ApacheModRewrite.CookieActionFactory", + "Visibility": "Public", + "Kind": "Class", + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Method", + "Name": "Create", + "Parameters": [ + { + "Name": "flagValue", + "Type": "System.String" + } + ], + "ReturnType": "Microsoft.AspNetCore.Rewrite.Internal.UrlActions.ChangeCookieAction", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [], + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.Rewrite.Internal.ApacheModRewrite.FileParser", + "Visibility": "Public", + "Kind": "Class", + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Method", + "Name": "Parse", + "Parameters": [ + { + "Name": "input", + "Type": "System.IO.TextReader" + } + ], + "ReturnType": "System.Collections.Generic.IList", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [], + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.Rewrite.Internal.ApacheModRewrite.FlagParser", + "Visibility": "Public", + "Kind": "Class", + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Method", + "Name": "Parse", + "Parameters": [ + { + "Name": "flagString", + "Type": "System.String" + } + ], + "ReturnType": "Microsoft.AspNetCore.Rewrite.Internal.ApacheModRewrite.Flags", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [], + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.Rewrite.Internal.ApacheModRewrite.Flags", + "Visibility": "Public", + "Kind": "Class", + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Method", + "Name": "get_FlagDictionary", + "Parameters": [], + "ReturnType": "System.Collections.Generic.IDictionary", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "SetFlag", + "Parameters": [ + { + "Name": "flag", + "Type": "Microsoft.AspNetCore.Rewrite.Internal.ApacheModRewrite.FlagType" + }, + { + "Name": "value", + "Type": "System.String" + } + ], + "ReturnType": "System.Void", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "GetValue", + "Parameters": [ + { + "Name": "flag", + "Type": "Microsoft.AspNetCore.Rewrite.Internal.ApacheModRewrite.FlagType" + }, + { + "Name": "value", + "Type": "System.String", + "Direction": "Out" + } + ], + "ReturnType": "System.Boolean", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "get_Item", + "Parameters": [ + { + "Name": "flag", + "Type": "Microsoft.AspNetCore.Rewrite.Internal.ApacheModRewrite.FlagType" + } + ], + "ReturnType": "System.String", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "set_Item", + "Parameters": [ + { + "Name": "flag", + "Type": "Microsoft.AspNetCore.Rewrite.Internal.ApacheModRewrite.FlagType" + }, + { + "Name": "value", + "Type": "System.String" + } + ], + "ReturnType": "System.Void", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "HasFlag", + "Parameters": [ + { + "Name": "flag", + "Type": "Microsoft.AspNetCore.Rewrite.Internal.ApacheModRewrite.FlagType" + } + ], + "ReturnType": "System.Boolean", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [ + { + "Name": "flags", + "Type": "System.Collections.Generic.IDictionary" + } + ], + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [], + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.Rewrite.Internal.ApacheModRewrite.FlagType", + "Visibility": "Public", + "Kind": "Enumeration", + "Sealed": true, + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Field", + "Name": "EscapeBackreference", + "Parameters": [], + "GenericParameter": [], + "Literal": "0" + }, + { + "Kind": "Field", + "Name": "Chain", + "Parameters": [], + "GenericParameter": [], + "Literal": "1" + }, + { + "Kind": "Field", + "Name": "Cookie", + "Parameters": [], + "GenericParameter": [], + "Literal": "2" + }, + { + "Kind": "Field", + "Name": "DiscardPath", + "Parameters": [], + "GenericParameter": [], + "Literal": "3" + }, + { + "Kind": "Field", + "Name": "Env", + "Parameters": [], + "GenericParameter": [], + "Literal": "4" + }, + { + "Kind": "Field", + "Name": "End", + "Parameters": [], + "GenericParameter": [], + "Literal": "5" + }, + { + "Kind": "Field", + "Name": "Forbidden", + "Parameters": [], + "GenericParameter": [], + "Literal": "6" + }, + { + "Kind": "Field", + "Name": "Gone", + "Parameters": [], + "GenericParameter": [], + "Literal": "7" + }, + { + "Kind": "Field", + "Name": "Handler", + "Parameters": [], + "GenericParameter": [], + "Literal": "8" + }, + { + "Kind": "Field", + "Name": "Last", + "Parameters": [], + "GenericParameter": [], + "Literal": "9" + }, + { + "Kind": "Field", + "Name": "Next", + "Parameters": [], + "GenericParameter": [], + "Literal": "10" + }, + { + "Kind": "Field", + "Name": "NoCase", + "Parameters": [], + "GenericParameter": [], + "Literal": "11" + }, + { + "Kind": "Field", + "Name": "NoEscape", + "Parameters": [], + "GenericParameter": [], + "Literal": "12" + }, + { + "Kind": "Field", + "Name": "NoSubReq", + "Parameters": [], + "GenericParameter": [], + "Literal": "13" + }, + { + "Kind": "Field", + "Name": "NoVary", + "Parameters": [], + "GenericParameter": [], + "Literal": "14" + }, + { + "Kind": "Field", + "Name": "Or", + "Parameters": [], + "GenericParameter": [], + "Literal": "15" + }, + { + "Kind": "Field", + "Name": "Proxy", + "Parameters": [], + "GenericParameter": [], + "Literal": "16" + }, + { + "Kind": "Field", + "Name": "PassThrough", + "Parameters": [], + "GenericParameter": [], + "Literal": "17" + }, + { + "Kind": "Field", + "Name": "QSAppend", + "Parameters": [], + "GenericParameter": [], + "Literal": "18" + }, + { + "Kind": "Field", + "Name": "QSDiscard", + "Parameters": [], + "GenericParameter": [], + "Literal": "19" + }, + { + "Kind": "Field", + "Name": "QSLast", + "Parameters": [], + "GenericParameter": [], + "Literal": "20" + }, + { + "Kind": "Field", + "Name": "Redirect", + "Parameters": [], + "GenericParameter": [], + "Literal": "21" + }, + { + "Kind": "Field", + "Name": "Skip", + "Parameters": [], + "GenericParameter": [], + "Literal": "22" + }, + { + "Kind": "Field", + "Name": "Type", + "Parameters": [], + "GenericParameter": [], + "Literal": "23" + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.Rewrite.Internal.ApacheModRewrite.OperationType", + "Visibility": "Public", + "Kind": "Enumeration", + "Sealed": true, + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Field", + "Name": "None", + "Parameters": [], + "GenericParameter": [], + "Literal": "0" + }, + { + "Kind": "Field", + "Name": "Equal", + "Parameters": [], + "GenericParameter": [], + "Literal": "1" + }, + { + "Kind": "Field", + "Name": "Greater", + "Parameters": [], + "GenericParameter": [], + "Literal": "2" + }, + { + "Kind": "Field", + "Name": "GreaterEqual", + "Parameters": [], + "GenericParameter": [], + "Literal": "3" + }, + { + "Kind": "Field", + "Name": "Less", + "Parameters": [], + "GenericParameter": [], + "Literal": "4" + }, + { + "Kind": "Field", + "Name": "LessEqual", + "Parameters": [], + "GenericParameter": [], + "Literal": "5" + }, + { + "Kind": "Field", + "Name": "NotEqual", + "Parameters": [], + "GenericParameter": [], + "Literal": "6" + }, + { + "Kind": "Field", + "Name": "Directory", + "Parameters": [], + "GenericParameter": [], + "Literal": "7" + }, + { + "Kind": "Field", + "Name": "RegularFile", + "Parameters": [], + "GenericParameter": [], + "Literal": "8" + }, + { + "Kind": "Field", + "Name": "ExistingFile", + "Parameters": [], + "GenericParameter": [], + "Literal": "9" + }, + { + "Kind": "Field", + "Name": "SymbolicLink", + "Parameters": [], + "GenericParameter": [], + "Literal": "10" + }, + { + "Kind": "Field", + "Name": "Size", + "Parameters": [], + "GenericParameter": [], + "Literal": "11" + }, + { + "Kind": "Field", + "Name": "ExistingUrl", + "Parameters": [], + "GenericParameter": [], + "Literal": "12" + }, + { + "Kind": "Field", + "Name": "Executable", + "Parameters": [], + "GenericParameter": [], + "Literal": "13" + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.Rewrite.Internal.ApacheModRewrite.ParsedModRewriteInput", + "Visibility": "Public", + "Kind": "Class", + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Method", + "Name": "get_Invert", + "Parameters": [], + "ReturnType": "System.Boolean", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "set_Invert", + "Parameters": [ + { + "Name": "value", + "Type": "System.Boolean" + } + ], + "ReturnType": "System.Void", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "get_ConditionType", + "Parameters": [], + "ReturnType": "Microsoft.AspNetCore.Rewrite.Internal.ApacheModRewrite.ConditionType", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "set_ConditionType", + "Parameters": [ + { + "Name": "value", + "Type": "Microsoft.AspNetCore.Rewrite.Internal.ApacheModRewrite.ConditionType" + } + ], + "ReturnType": "System.Void", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "get_OperationType", + "Parameters": [], + "ReturnType": "Microsoft.AspNetCore.Rewrite.Internal.ApacheModRewrite.OperationType", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "set_OperationType", + "Parameters": [ + { + "Name": "value", + "Type": "Microsoft.AspNetCore.Rewrite.Internal.ApacheModRewrite.OperationType" + } + ], + "ReturnType": "System.Void", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "get_Operand", + "Parameters": [], + "ReturnType": "System.String", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "set_Operand", + "Parameters": [ + { + "Name": "value", + "Type": "System.String" + } + ], + "ReturnType": "System.Void", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [], + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [ + { + "Name": "invert", + "Type": "System.Boolean" + }, + { + "Name": "conditionType", + "Type": "Microsoft.AspNetCore.Rewrite.Internal.ApacheModRewrite.ConditionType" + }, + { + "Name": "operationType", + "Type": "Microsoft.AspNetCore.Rewrite.Internal.ApacheModRewrite.OperationType" + }, + { + "Name": "operand", + "Type": "System.String" + } + ], + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.Rewrite.Internal.ApacheModRewrite.RuleBuilder", + "Visibility": "Public", + "Kind": "Class", + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Method", + "Name": "Build", + "Parameters": [], + "ReturnType": "Microsoft.AspNetCore.Rewrite.Internal.ApacheModRewrite.ApacheModRewriteRule", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "AddRule", + "Parameters": [ + { + "Name": "rule", + "Type": "System.String" + } + ], + "ReturnType": "System.Void", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "AddConditionFromParts", + "Parameters": [ + { + "Name": "pattern", + "Type": "Microsoft.AspNetCore.Rewrite.Internal.Pattern" + }, + { + "Name": "input", + "Type": "Microsoft.AspNetCore.Rewrite.Internal.ApacheModRewrite.ParsedModRewriteInput" + }, + { + "Name": "flags", + "Type": "Microsoft.AspNetCore.Rewrite.Internal.ApacheModRewrite.Flags" + } + ], + "ReturnType": "System.Void", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "AddMatch", + "Parameters": [ + { + "Name": "input", + "Type": "Microsoft.AspNetCore.Rewrite.Internal.ApacheModRewrite.ParsedModRewriteInput" + }, + { + "Name": "flags", + "Type": "Microsoft.AspNetCore.Rewrite.Internal.ApacheModRewrite.Flags" + } + ], + "ReturnType": "System.Void", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "AddAction", + "Parameters": [ + { + "Name": "pattern", + "Type": "Microsoft.AspNetCore.Rewrite.Internal.Pattern" + }, + { + "Name": "flags", + "Type": "Microsoft.AspNetCore.Rewrite.Internal.ApacheModRewrite.Flags" + } + ], + "ReturnType": "System.Void", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [], + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.Rewrite.Internal.ApacheModRewrite.RuleRegexParser", + "Visibility": "Public", + "Kind": "Class", + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Method", + "Name": "ParseRuleRegex", + "Parameters": [ + { + "Name": "regex", + "Type": "System.String" + } + ], + "ReturnType": "Microsoft.AspNetCore.Rewrite.Internal.ApacheModRewrite.ParsedModRewriteInput", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [], + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.Rewrite.Internal.ApacheModRewrite.SegmentType", + "Visibility": "Public", + "Kind": "Enumeration", + "Sealed": true, + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Field", + "Name": "Literal", + "Parameters": [], + "GenericParameter": [], + "Literal": "0" + }, + { + "Kind": "Field", + "Name": "ServerParameter", + "Parameters": [], + "GenericParameter": [], + "Literal": "1" + }, + { + "Kind": "Field", + "Name": "ConditionParameter", + "Parameters": [], + "GenericParameter": [], + "Literal": "2" + }, + { + "Kind": "Field", + "Name": "RuleParameter", + "Parameters": [], + "GenericParameter": [], + "Literal": "3" + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.Rewrite.Internal.ApacheModRewrite.ServerVariables", + "Visibility": "Public", + "Kind": "Class", + "Abstract": true, + "Static": true, + "Sealed": true, + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Method", + "Name": "FindServerVariable", + "Parameters": [ + { + "Name": "serverVariable", + "Type": "System.String" + }, + { + "Name": "context", + "Type": "Microsoft.AspNetCore.Rewrite.Internal.ParserContext" + } + ], + "ReturnType": "Microsoft.AspNetCore.Rewrite.Internal.PatternSegment", + "Static": true, + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.Rewrite.Internal.ApacheModRewrite.TestStringParser", + "Visibility": "Public", + "Kind": "Class", + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Method", + "Name": "Parse", + "Parameters": [ + { + "Name": "testString", + "Type": "System.String" + } + ], + "ReturnType": "Microsoft.AspNetCore.Rewrite.Internal.Pattern", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [], + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.Rewrite.Internal.ApacheModRewrite.Tokenizer", + "Visibility": "Public", + "Kind": "Class", + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Method", + "Name": "Tokenize", + "Parameters": [ + { + "Name": "rule", + "Type": "System.String" + } + ], + "ReturnType": "System.Collections.Generic.IList", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [], + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + } + ] +} \ No newline at end of file From 2a7bf185221d147e20595f537d81d49850bdba50 Mon Sep 17 00:00:00 2001 From: "ASP.NET CI" Date: Sun, 25 Mar 2018 15:30:50 -0700 Subject: [PATCH 286/307] Update dependencies.props [auto-updated: dependencies] --- build/dependencies.props | 40 ++++++++++++++++++++-------------------- korebuild-lock.txt | 4 ++-- 2 files changed, 22 insertions(+), 22 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index 4dadaa5ffa..3e32144dde 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -3,27 +3,27 @@ $(MSBuildAllProjects);$(MSBuildThisFileFullPath) - 2.1.0-preview2-15728 - 2.1.0-preview2-30281 - 2.1.0-preview2-30281 - 2.1.0-preview2-30281 - 2.1.0-preview2-30281 - 2.1.0-preview2-30281 - 2.1.0-preview2-30281 - 2.1.0-preview2-30281 - 2.1.0-preview2-30281 - 2.1.0-preview2-30281 - 2.1.0-preview2-30281 - 2.1.0-preview2-30281 - 2.1.0-preview2-30281 - 2.1.0-preview2-30281 - 2.1.0-preview2-30281 - 2.1.0-preview2-30281 - 2.1.0-preview2-30281 + 2.1.0-preview3-17001 + 2.1.0-preview3-32037 + 2.1.0-preview3-32037 + 2.1.0-preview3-32037 + 2.1.0-preview3-32037 + 2.1.0-preview3-32037 + 2.1.0-preview3-32037 + 2.1.0-preview3-32037 + 2.1.0-preview3-32037 + 2.1.0-preview3-32037 + 2.1.0-preview3-32037 + 2.1.0-preview3-32037 + 2.1.0-preview3-32037 + 2.1.0-preview3-32037 + 2.1.0-preview3-32037 + 2.1.0-preview3-32037 + 2.1.0-preview3-32037 2.0.0 - 2.1.0-preview2-26308-01 - 2.1.0-preview2-30281 - 15.6.0 + 2.1.0-preview2-26314-02 + 2.1.0-preview3-32037 + 15.6.1 4.7.49 0.8.0 2.3.1 diff --git a/korebuild-lock.txt b/korebuild-lock.txt index 138d848db1..3a326c7d58 100644 --- a/korebuild-lock.txt +++ b/korebuild-lock.txt @@ -1,2 +1,2 @@ -version:2.1.0-preview2-15728 -commithash:393377068ddcf51dfee0536536d455f57a828b06 +version:2.1.0-preview3-17001 +commithash:dda68c56abf0d3b911fe6a2315872c446b314585 From 6a20718bf4dbd4ef8bd200926f996b0d88e338d7 Mon Sep 17 00:00:00 2001 From: "Nate McMaster (automated)" Date: Wed, 28 Mar 2018 10:33:25 -0700 Subject: [PATCH 287/307] Update dependencies.props [auto-updated: dependencies] --- build/dependencies.props | 40 ++++++++++++++++++++-------------------- korebuild-lock.txt | 4 ++-- 2 files changed, 22 insertions(+), 22 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index 6eb9c5da57..8150c4cf1e 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -3,27 +3,27 @@ $(MSBuildAllProjects);$(MSBuildThisFileFullPath) - 2.1.0-preview2-15742 - 2.1.0-preview2-30355 - 2.1.0-preview2-30355 - 2.1.0-preview2-30355 - 2.1.0-preview2-30355 - 2.1.0-preview2-30355 - 2.1.0-preview2-30355 - 2.1.0-preview2-30355 - 2.1.0-preview2-30355 - 2.1.0-preview2-30355 - 2.1.0-preview2-30355 - 2.1.0-preview2-30355 - 2.1.0-preview2-30355 - 2.1.0-preview2-30355 - 2.1.0-preview2-30355 - 2.1.0-preview2-30355 - 2.1.0-preview2-30355 + 2.1.0-preview2-15749 + 2.1.0-preview2-30478 + 2.1.0-preview2-30478 + 2.1.0-preview2-30478 + 2.1.0-preview2-30478 + 2.1.0-preview2-30478 + 2.1.0-preview2-30478 + 2.1.0-preview2-30478 + 2.1.0-preview2-30478 + 2.1.0-preview2-30478 + 2.1.0-preview2-30478 + 2.1.0-preview2-30478 + 2.1.0-preview2-30478 + 2.1.0-preview2-30478 + 2.1.0-preview2-30478 + 2.1.0-preview2-30478 + 2.1.0-preview2-30478 2.0.0 - 2.1.0-preview2-26314-02 - 2.1.0-preview2-30355 - 15.6.0 + 2.1.0-preview2-26326-03 + 2.1.0-preview2-30478 + 15.6.1 4.7.49 0.8.0 2.3.1 diff --git a/korebuild-lock.txt b/korebuild-lock.txt index e40ef6651b..b8e036fe2c 100644 --- a/korebuild-lock.txt +++ b/korebuild-lock.txt @@ -1,2 +1,2 @@ -version:2.1.0-preview2-15742 -commithash:21fbb0f2c3fe4a9216e2d59632b98cfd7d685962 +version:2.1.0-preview2-15749 +commithash:5544c9ab20fa5e24b9e155d8958a3c3b6f5f9df9 From 77095e93bf0b41b420450ca8284c2c211e1bebb2 Mon Sep 17 00:00:00 2001 From: "ASP.NET CI" Date: Tue, 3 Apr 2018 22:18:18 +0000 Subject: [PATCH 288/307] Update dependencies.props [auto-updated: dependencies] --- build/dependencies.props | 38 +++++++++++++++++++------------------- korebuild-lock.txt | 4 ++-- 2 files changed, 21 insertions(+), 21 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index 3e32144dde..8b795c771b 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -3,26 +3,26 @@ $(MSBuildAllProjects);$(MSBuildThisFileFullPath) - 2.1.0-preview3-17001 - 2.1.0-preview3-32037 - 2.1.0-preview3-32037 - 2.1.0-preview3-32037 - 2.1.0-preview3-32037 - 2.1.0-preview3-32037 - 2.1.0-preview3-32037 - 2.1.0-preview3-32037 - 2.1.0-preview3-32037 - 2.1.0-preview3-32037 - 2.1.0-preview3-32037 - 2.1.0-preview3-32037 - 2.1.0-preview3-32037 - 2.1.0-preview3-32037 - 2.1.0-preview3-32037 - 2.1.0-preview3-32037 - 2.1.0-preview3-32037 + 2.1.0-preview3-17002 + 2.1.0-preview3-32110 + 2.1.0-preview3-32110 + 2.1.0-preview3-32110 + 2.1.0-preview3-32110 + 2.1.0-preview3-32110 + 2.1.0-preview3-32110 + 2.1.0-preview3-32110 + 2.1.0-preview3-32110 + 2.1.0-preview3-32110 + 2.1.0-preview3-32110 + 2.1.0-preview3-32110 + 2.1.0-preview3-32110 + 2.1.0-preview3-32110 + 2.1.0-preview3-32110 + 2.1.0-preview3-32110 + 2.1.0-preview3-32110 2.0.0 - 2.1.0-preview2-26314-02 - 2.1.0-preview3-32037 + 2.1.0-preview3-26331-01 + 2.1.0-preview3-32110 15.6.1 4.7.49 0.8.0 diff --git a/korebuild-lock.txt b/korebuild-lock.txt index 3a326c7d58..b3af0b8bce 100644 --- a/korebuild-lock.txt +++ b/korebuild-lock.txt @@ -1,2 +1,2 @@ -version:2.1.0-preview3-17001 -commithash:dda68c56abf0d3b911fe6a2315872c446b314585 +version:2.1.0-preview3-17002 +commithash:b8e4e6ab104adc94c0719bb74229870e9b584a7f From fc3ab083d27f20438df3fe323ba8afa6e2e25890 Mon Sep 17 00:00:00 2001 From: Nate McMaster Date: Fri, 6 Apr 2018 12:34:25 -0700 Subject: [PATCH 289/307] Ensure experimental package version is 0.4.0-preview3-final, not 0.4.0-preview3-buildnumber-final --- version.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.props b/version.props index 36fad116cd..9124b26738 100644 --- a/version.props +++ b/version.props @@ -10,7 +10,7 @@ $(VersionSuffix)-$(BuildNumber) 0.4.0 - $(VersionSuffix) + preview3 $(ExperimentalVersionPrefix) $(ExperimentalVersionPrefix)-$(ExperimentalVersionSuffix)-final $(ExperimentalVersionSuffix)-$(BuildNumber) From 768cad8a8a17766c790cec04b340185a90d3b0cc Mon Sep 17 00:00:00 2001 From: "Chris Ross (ASP.NET)" Date: Wed, 11 Apr 2018 11:44:58 -0700 Subject: [PATCH 290/307] Reload HostFilter options on change #317 --- build/dependencies.props | 1 + samples/HostFilteringSample/Program.cs | 4 +- samples/HostFilteringSample/Startup.cs | 20 ++++++- .../appsettings.Development.json | 2 +- .../appsettings.Production.json | 2 +- .../HostFilteringMiddleware.cs | 33 +++++++---- .../HostFilteringMiddlewareTests.cs | 57 +++++++++++++++++++ ...soft.AspNetCore.HostFiltering.Tests.csproj | 1 + 8 files changed, 103 insertions(+), 17 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index 8b795c771b..620c2bd49d 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -14,6 +14,7 @@ 2.1.0-preview3-32110 2.1.0-preview3-32110 2.1.0-preview3-32110 + 2.1.0-preview3-32110 2.1.0-preview3-32110 2.1.0-preview3-32110 2.1.0-preview3-32110 diff --git a/samples/HostFilteringSample/Program.cs b/samples/HostFilteringSample/Program.cs index 0d4ffa9324..0ccc7cdb2e 100644 --- a/samples/HostFilteringSample/Program.cs +++ b/samples/HostFilteringSample/Program.cs @@ -25,8 +25,8 @@ namespace HostFilteringSample .ConfigureAppConfiguration((hostingContext, config) => { var env = hostingContext.HostingEnvironment; - config.AddJsonFile("appsettings.json", optional: true) - .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true); + config.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true) + .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true, reloadOnChange: true); }) .UseKestrel() .UseStartup(); diff --git a/samples/HostFilteringSample/Startup.cs b/samples/HostFilteringSample/Startup.cs index 93c217b71c..283d8ee7f9 100644 --- a/samples/HostFilteringSample/Startup.cs +++ b/samples/HostFilteringSample/Startup.cs @@ -1,12 +1,15 @@ // 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; using System.Collections.Generic; using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.HostFiltering; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Options; namespace HostFilteringSample { @@ -23,9 +26,22 @@ namespace HostFilteringSample { services.AddHostFiltering(options => { - // If this is excluded then it will fall back to the server's addresses - options.AllowedHosts = Config.GetSection("AllowedHosts").Get>(); + }); + + // Fallback + services.PostConfigure(options => + { + if (options.AllowedHosts == null || options.AllowedHosts.Count == 0) + { + // "AllowedHosts": "localhost;127.0.0.1;[::1]" + var hosts = Config["AllowedHosts"]?.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries); + // Fall back to "*" to disable. + options.AllowedHosts = (hosts?.Length > 0 ? hosts : new[] { "*" }); + } + }); + // Change notification + services.AddSingleton>(new ConfigurationChangeTokenSource(Config)); } public void Configure(IApplicationBuilder app, IHostingEnvironment env) diff --git a/samples/HostFilteringSample/appsettings.Development.json b/samples/HostFilteringSample/appsettings.Development.json index 7c2d8e26dc..b8d74ac7a2 100644 --- a/samples/HostFilteringSample/appsettings.Development.json +++ b/samples/HostFilteringSample/appsettings.Development.json @@ -1,3 +1,3 @@ { - "AllowedHosts": [ "localhost", "127.0.0.1", "[::1]" ] + "AllowedHosts": "localhost;127.0.0.1;[::1]" } diff --git a/samples/HostFilteringSample/appsettings.Production.json b/samples/HostFilteringSample/appsettings.Production.json index f2fc90c390..0c6fabda95 100644 --- a/samples/HostFilteringSample/appsettings.Production.json +++ b/samples/HostFilteringSample/appsettings.Production.json @@ -1,3 +1,3 @@ { - "AllowedHosts": [ "example.com", "localhost" ] + "AllowedHosts": "example.com;localhost" } diff --git a/src/Microsoft.AspNetCore.HostFiltering/HostFilteringMiddleware.cs b/src/Microsoft.AspNetCore.HostFiltering/HostFilteringMiddleware.cs index e1e38eca37..d355edd0fc 100644 --- a/src/Microsoft.AspNetCore.HostFiltering/HostFilteringMiddleware.cs +++ b/src/Microsoft.AspNetCore.HostFiltering/HostFilteringMiddleware.cs @@ -30,7 +30,8 @@ namespace Microsoft.AspNetCore.HostFiltering private readonly RequestDelegate _next; private readonly ILogger _logger; - private readonly HostFilteringOptions _options; + private readonly IOptionsMonitor _optionsMonitor; + private HostFilteringOptions _options; private IList _allowedHosts; private bool? _allowAnyNonEmptyHost; @@ -39,13 +40,21 @@ namespace Microsoft.AspNetCore.HostFiltering ///
/// /// - /// + /// public HostFilteringMiddleware(RequestDelegate next, ILogger logger, - IOptions options) + IOptionsMonitor optionsMonitor) { _next = next ?? throw new ArgumentNullException(nameof(next)); _logger = logger ?? throw new ArgumentNullException(nameof(logger)); - _options = options?.Value ?? throw new ArgumentNullException(nameof(options)); + _optionsMonitor = optionsMonitor ?? throw new ArgumentNullException(nameof(optionsMonitor)); + _options = _optionsMonitor.CurrentValue; + _optionsMonitor.OnChange(options => + { + // Clear the cached settings so the next EnsureConfigured will re-evaluate. + _options = options; + _allowedHosts = new List(); + _allowAnyNonEmptyHost = null; + }); } /// @@ -55,9 +64,9 @@ namespace Microsoft.AspNetCore.HostFiltering /// public Task Invoke(HttpContext context) { - EnsureConfigured(); + var allowedHosts = EnsureConfigured(); - if (!CheckHost(context)) + if (!CheckHost(context, allowedHosts)) { context.Response.StatusCode = 400; if (_options.IncludeFailureMessage) @@ -72,19 +81,20 @@ namespace Microsoft.AspNetCore.HostFiltering return _next(context); } - private void EnsureConfigured() + private IList EnsureConfigured() { if (_allowAnyNonEmptyHost == true || _allowedHosts?.Count > 0) { - return; + return _allowedHosts; } var allowedHosts = new List(); if (_options.AllowedHosts?.Count > 0 && !TryProcessHosts(_options.AllowedHosts, allowedHosts)) { _logger.LogDebug("Wildcard detected, all requests with hosts will be allowed."); + _allowedHosts = allowedHosts; _allowAnyNonEmptyHost = true; - return; + return _allowedHosts; } if (allowedHosts.Count == 0) @@ -94,6 +104,7 @@ namespace Microsoft.AspNetCore.HostFiltering _logger.LogDebug("Allowed hosts: " + string.Join("; ", allowedHosts)); _allowedHosts = allowedHosts; + return _allowedHosts; } // returns false if any wildcards were found @@ -127,7 +138,7 @@ namespace Microsoft.AspNetCore.HostFiltering } // This does not duplicate format validations that are expected to be performed by the host. - private bool CheckHost(HttpContext context) + private bool CheckHost(HttpContext context, IList allowedHosts) { var host = new StringSegment(context.Request.Headers[HeaderNames.Host].ToString()).Trim(); @@ -153,7 +164,7 @@ namespace Microsoft.AspNetCore.HostFiltering return true; } - if (HostString.MatchesAny(host, _allowedHosts)) + if (HostString.MatchesAny(host, allowedHosts)) { _logger.LogTrace($"The host '{host}' matches an allowed host."); return true; diff --git a/test/Microsoft.AspNetCore.HostFiltering.Tests/HostFilteringMiddlewareTests.cs b/test/Microsoft.AspNetCore.HostFiltering.Tests/HostFilteringMiddlewareTests.cs index 2fc7b8c713..ab45bc9554 100644 --- a/test/Microsoft.AspNetCore.HostFiltering.Tests/HostFilteringMiddlewareTests.cs +++ b/test/Microsoft.AspNetCore.HostFiltering.Tests/HostFilteringMiddlewareTests.cs @@ -2,10 +2,14 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; +using System.Collections.Generic; using System.Threading.Tasks; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.TestHost; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Options; using Microsoft.Extensions.Primitives; using Microsoft.Net.Http.Headers; using Xunit; @@ -179,5 +183,58 @@ namespace Microsoft.AspNetCore.HostFiltering var response = await server.CreateRequest("/").GetAsync(); Assert.Equal(400, (int)response.StatusCode); } + + [Fact] + public async Task SupportsDynamicOptionsReload() + { + var config = new ConfigurationBuilder().Add(new ReloadableMemorySource()).Build(); + config["AllowedHosts"] = "localhost"; + var currentHost = "otherHost"; + + var builder = new WebHostBuilder() + .ConfigureServices(services => + { + services.AddHostFiltering(options => + { + options.AllowedHosts = new[] { config["AllowedHosts"] }; + }); + services.AddSingleton>(new ConfigurationChangeTokenSource(config)); + }) + .Configure(app => + { + app.Use((ctx, next) => + { + ctx.Request.Headers[HeaderNames.Host] = currentHost; + return next(); + }); + app.UseHostFiltering(); + app.Run(c => Task.CompletedTask); + }); + var server = new TestServer(builder); + var response = await server.CreateRequest("/").GetAsync(); + Assert.Equal(400, (int)response.StatusCode); + + config["AllowedHosts"] = "otherHost"; + + response = await server.CreateRequest("/").GetAsync(); + Assert.Equal(200, (int)response.StatusCode); + } + + private class ReloadableMemorySource : IConfigurationSource + { + public IConfigurationProvider Build(IConfigurationBuilder builder) + { + return new ReloadableMemoryProvider(); + } + } + + internal class ReloadableMemoryProvider : ConfigurationProvider + { + public override void Set(string key, string value) + { + base.Set(key, value); + OnReload(); + } + } } } diff --git a/test/Microsoft.AspNetCore.HostFiltering.Tests/Microsoft.AspNetCore.HostFiltering.Tests.csproj b/test/Microsoft.AspNetCore.HostFiltering.Tests/Microsoft.AspNetCore.HostFiltering.Tests.csproj index d71805c949..94262065fa 100644 --- a/test/Microsoft.AspNetCore.HostFiltering.Tests/Microsoft.AspNetCore.HostFiltering.Tests.csproj +++ b/test/Microsoft.AspNetCore.HostFiltering.Tests/Microsoft.AspNetCore.HostFiltering.Tests.csproj @@ -6,6 +6,7 @@ + From 553ce6471a368c08c5f848158b819f713f6e86e9 Mon Sep 17 00:00:00 2001 From: "Chris Ross (ASP.NET)" Date: Thu, 12 Apr 2018 11:41:00 -0700 Subject: [PATCH 291/307] Fix dependency typo --- build/dependencies.props | 2 +- .../Microsoft.AspNetCore.HostFiltering.Tests.csproj | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index 620c2bd49d..3d8397f50f 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -14,13 +14,13 @@ 2.1.0-preview3-32110 2.1.0-preview3-32110 2.1.0-preview3-32110 - 2.1.0-preview3-32110 2.1.0-preview3-32110 2.1.0-preview3-32110 2.1.0-preview3-32110 2.1.0-preview3-32110 2.1.0-preview3-32110 2.1.0-preview3-32110 + 2.1.0-preview3-32110 2.0.0 2.1.0-preview3-26331-01 2.1.0-preview3-32110 diff --git a/test/Microsoft.AspNetCore.HostFiltering.Tests/Microsoft.AspNetCore.HostFiltering.Tests.csproj b/test/Microsoft.AspNetCore.HostFiltering.Tests/Microsoft.AspNetCore.HostFiltering.Tests.csproj index 94262065fa..407ecdef0f 100644 --- a/test/Microsoft.AspNetCore.HostFiltering.Tests/Microsoft.AspNetCore.HostFiltering.Tests.csproj +++ b/test/Microsoft.AspNetCore.HostFiltering.Tests/Microsoft.AspNetCore.HostFiltering.Tests.csproj @@ -1,4 +1,4 @@ - + $(StandardTestTfms) @@ -6,7 +6,7 @@ - + From 0c31fcdf305f24abffeb53a261a9e298c97b2524 Mon Sep 17 00:00:00 2001 From: "ASP.NET CI" Date: Sun, 15 Apr 2018 14:01:06 -0700 Subject: [PATCH 292/307] Update dependencies.props [auto-updated: dependencies] --- build/dependencies.props | 40 ++++++++++++++++++++-------------------- korebuild-lock.txt | 4 ++-- 2 files changed, 22 insertions(+), 22 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index 3d8397f50f..7ddd689238 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -3,27 +3,27 @@ $(MSBuildAllProjects);$(MSBuildThisFileFullPath) - 2.1.0-preview3-17002 - 2.1.0-preview3-32110 - 2.1.0-preview3-32110 - 2.1.0-preview3-32110 - 2.1.0-preview3-32110 - 2.1.0-preview3-32110 - 2.1.0-preview3-32110 - 2.1.0-preview3-32110 - 2.1.0-preview3-32110 - 2.1.0-preview3-32110 - 2.1.0-preview3-32110 - 2.1.0-preview3-32110 - 2.1.0-preview3-32110 - 2.1.0-preview3-32110 - 2.1.0-preview3-32110 - 2.1.0-preview3-32110 - 2.1.0-preview3-32110 - 2.1.0-preview3-32110 + 2.1.0-preview3-17018 + 2.1.0-preview3-32233 + 2.1.0-preview3-32233 + 2.1.0-preview3-32233 + 2.1.0-preview3-32233 + 2.1.0-preview3-32233 + 2.1.0-preview3-32233 + 2.1.0-preview3-32233 + 2.1.0-preview3-32233 + 2.1.0-preview3-32233 + 2.1.0-preview3-32233 + 2.1.0-preview3-32233 + 2.1.0-preview3-32233 + 2.1.0-preview3-32233 + 2.1.0-preview3-32233 + 2.1.0-preview3-32233 + 2.1.0-preview3-32233 + 2.1.0-preview3-32233 2.0.0 - 2.1.0-preview3-26331-01 - 2.1.0-preview3-32110 + 2.1.0-preview3-26413-05 + 2.1.0-preview3-32233 15.6.1 4.7.49 0.8.0 diff --git a/korebuild-lock.txt b/korebuild-lock.txt index b3af0b8bce..b419d767b9 100644 --- a/korebuild-lock.txt +++ b/korebuild-lock.txt @@ -1,2 +1,2 @@ -version:2.1.0-preview3-17002 -commithash:b8e4e6ab104adc94c0719bb74229870e9b584a7f +version:2.1.0-preview3-17018 +commithash:af264ca131f212b5ba8aafbc5110fc0fc510a2be From 0a876cece7b72b11e4e9bcedd9442ac29effdd22 Mon Sep 17 00:00:00 2001 From: "Chris Ross (ASP.NET)" Date: Fri, 13 Apr 2018 15:55:42 -0700 Subject: [PATCH 293/307] Make https redirect no-op if no port is available #318 --- .../HttpsPolicySample.csproj | 3 +- .../Properties/launchSettings.json | 4 +- samples/HttpsPolicySample/Startup.cs | 6 + .../HttpsRedirectionMiddleware.cs | 65 +++++-- .../internal/HttpsLoggingExtensions.cs | 53 ++++++ .../HttpsPolicyTests.cs | 6 +- .../HttpsRedirectionMiddlewareTests.cs | 162 +++++++++++++++--- ...rosoft.AspNetCore.HttpsPolicy.Tests.csproj | 6 +- 8 files changed, 252 insertions(+), 53 deletions(-) create mode 100644 src/Microsoft.AspNetCore.HttpsPolicy/internal/HttpsLoggingExtensions.cs diff --git a/samples/HttpsPolicySample/HttpsPolicySample.csproj b/samples/HttpsPolicySample/HttpsPolicySample.csproj index 3ab7f8c7cb..fdfa716478 100644 --- a/samples/HttpsPolicySample/HttpsPolicySample.csproj +++ b/samples/HttpsPolicySample/HttpsPolicySample.csproj @@ -1,4 +1,4 @@ - + net461;netcoreapp2.0 @@ -8,6 +8,7 @@ + diff --git a/samples/HttpsPolicySample/Properties/launchSettings.json b/samples/HttpsPolicySample/Properties/launchSettings.json index fbffc1f457..a35390177b 100644 --- a/samples/HttpsPolicySample/Properties/launchSettings.json +++ b/samples/HttpsPolicySample/Properties/launchSettings.json @@ -21,7 +21,7 @@ "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development" }, - "applicationUrl": "http://localhost:31895/" + "applicationUrl": "http://localhost:5000/" } } -} +} \ No newline at end of file diff --git a/samples/HttpsPolicySample/Startup.cs b/samples/HttpsPolicySample/Startup.cs index 1c9f11fcad..91888a01b4 100644 --- a/samples/HttpsPolicySample/Startup.cs +++ b/samples/HttpsPolicySample/Startup.cs @@ -9,6 +9,7 @@ using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.HttpsPolicy; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; namespace HttpsSample { @@ -62,6 +63,11 @@ namespace HttpsSample }); }) .UseContentRoot(Directory.GetCurrentDirectory()) // for the cert file + .ConfigureLogging(factory => + { + factory.SetMinimumLevel(LogLevel.Debug); + factory.AddConsole(); + }) .UseStartup() .Build(); diff --git a/src/Microsoft.AspNetCore.HttpsPolicy/HttpsRedirectionMiddleware.cs b/src/Microsoft.AspNetCore.HttpsPolicy/HttpsRedirectionMiddleware.cs index a4a9cc034d..192845f7db 100644 --- a/src/Microsoft.AspNetCore.HttpsPolicy/HttpsRedirectionMiddleware.cs +++ b/src/Microsoft.AspNetCore.HttpsPolicy/HttpsRedirectionMiddleware.cs @@ -7,7 +7,9 @@ using Microsoft.AspNetCore.Hosting.Server.Features; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http.Extensions; using Microsoft.AspNetCore.Http.Internal; +using Microsoft.AspNetCore.HttpsPolicy.Internal; using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using Microsoft.Net.Http.Headers; @@ -16,11 +18,13 @@ namespace Microsoft.AspNetCore.HttpsPolicy public class HttpsRedirectionMiddleware { private readonly RequestDelegate _next; + private bool _portEvaluated = false; private int? _httpsPort; private readonly int _statusCode; private readonly IServerAddressesFeature _serverAddressesFeature; private readonly IConfiguration _config; + private readonly ILogger _logger; /// /// Initializes the HttpsRedirectionMiddleware @@ -28,7 +32,8 @@ namespace Microsoft.AspNetCore.HttpsPolicy /// /// /// - public HttpsRedirectionMiddleware(RequestDelegate next, IOptions options, IConfiguration config) + /// + public HttpsRedirectionMiddleware(RequestDelegate next, IOptions options, IConfiguration config, ILoggerFactory loggerFactory) { _next = next ?? throw new ArgumentNullException(nameof(next)); @@ -40,7 +45,9 @@ namespace Microsoft.AspNetCore.HttpsPolicy } var httpsRedirectionOptions = options.Value; _httpsPort = httpsRedirectionOptions.HttpsPort; + _portEvaluated = _httpsPort.HasValue; _statusCode = httpsRedirectionOptions.RedirectStatusCode; + _logger = loggerFactory.CreateLogger(); } /// @@ -49,9 +56,11 @@ namespace Microsoft.AspNetCore.HttpsPolicy /// /// /// + /// /// The - public HttpsRedirectionMiddleware(RequestDelegate next, IOptions options, IConfiguration config, IServerAddressesFeature serverAddressesFeature) - : this(next, options, config) + public HttpsRedirectionMiddleware(RequestDelegate next, IOptions options, IConfiguration config, ILoggerFactory loggerFactory, + IServerAddressesFeature serverAddressesFeature) + : this(next, options, config, loggerFactory) { _serverAddressesFeature = serverAddressesFeature ?? throw new ArgumentNullException(nameof(serverAddressesFeature)); } @@ -63,20 +72,15 @@ namespace Microsoft.AspNetCore.HttpsPolicy /// public Task Invoke(HttpContext context) { - if (context.Request.IsHttps) + if (context.Request.IsHttps || !TryGetHttpsPort(out var port)) { return _next(context); } - if (!_httpsPort.HasValue) - { - CheckForHttpsPorts(); - } - var host = context.Request.Host; - if (_httpsPort != 443) + if (port != 443) { - host = new HostString(host.Host, _httpsPort.Value); + host = new HostString(host.Host, port); } else { @@ -94,28 +98,41 @@ namespace Microsoft.AspNetCore.HttpsPolicy context.Response.StatusCode = _statusCode; context.Response.Headers[HeaderNames.Location] = redirectUrl; + _logger.RedirectingToHttps(redirectUrl); + return Task.CompletedTask; } - private void CheckForHttpsPorts() + private bool TryGetHttpsPort(out int port) { // The IServerAddressesFeature will not be ready until the middleware is Invoked, // Order for finding the HTTPS port: // 1. Set in the HttpsRedirectionOptions // 2. HTTPS_PORT environment variable // 3. IServerAddressesFeature - // 4. 443 (or not set) + // 4. Fail if not set + + port = -1; + + if (_portEvaluated) + { + port = _httpsPort ?? port; + return _httpsPort.HasValue; + } + _portEvaluated = true; _httpsPort = _config.GetValue("HTTPS_PORT"); if (_httpsPort.HasValue) { - return; + port = _httpsPort.Value; + _logger.PortLoadedFromConfig(port); + return true; } if (_serverAddressesFeature == null) { - _httpsPort = 443; - return; + _logger.FailedToDeterminePort(); + return false; } int? httpsPort = null; @@ -127,8 +144,8 @@ namespace Microsoft.AspNetCore.HttpsPolicy // If we find multiple different https ports specified, throw if (httpsPort.HasValue && httpsPort != bindingAddress.Port) { - throw new ArgumentException("Cannot determine the https port from IServerAddressesFeature, multiple values were found. " + - "Please set the desired port explicitly on HttpsRedirectionOptions.HttpsPort."); + _logger.FailedMultiplePorts(); + return false; } else { @@ -136,7 +153,17 @@ namespace Microsoft.AspNetCore.HttpsPolicy } } } - _httpsPort = httpsPort ?? 443; + + if (httpsPort.HasValue) + { + _httpsPort = httpsPort; + port = _httpsPort.Value; + _logger.PortFromServer(port); + return true; + } + + _logger.FailedToDeterminePort(); + return false; } } } diff --git a/src/Microsoft.AspNetCore.HttpsPolicy/internal/HttpsLoggingExtensions.cs b/src/Microsoft.AspNetCore.HttpsPolicy/internal/HttpsLoggingExtensions.cs new file mode 100644 index 0000000000..55e65dcbdd --- /dev/null +++ b/src/Microsoft.AspNetCore.HttpsPolicy/internal/HttpsLoggingExtensions.cs @@ -0,0 +1,53 @@ +// 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; +using Microsoft.Extensions.Logging; + +namespace Microsoft.AspNetCore.HttpsPolicy.Internal +{ + internal static class HttpsLoggingExtensions + { + private static readonly Action _redirectingToHttps; + private static readonly Action _portLoadedFromConfig; + private static readonly Action _failedToDeterminePort; + private static readonly Action _failedMultiplePorts; + private static readonly Action _portFromServer; + + static HttpsLoggingExtensions() + { + _redirectingToHttps = LoggerMessage.Define(LogLevel.Debug, 1, "Redirecting to '{redirect}'."); + _portLoadedFromConfig = LoggerMessage.Define(LogLevel.Debug, 2, "Https port '{port}' loaded from configuration."); + _failedToDeterminePort = LoggerMessage.Define(LogLevel.Warning, 3, "Failed to determine the https port for redirect."); + _failedMultiplePorts = LoggerMessage.Define(LogLevel.Warning, 4, + "Cannot determine the https port from IServerAddressesFeature, multiple values were found. " + + "Please set the desired port explicitly on HttpsRedirectionOptions.HttpsPort."); + _portFromServer = LoggerMessage.Define(LogLevel.Debug, 5, "Https port '{httpsPort}' discovered from server endpoints."); + } + + public static void RedirectingToHttps(this ILogger logger, string redirect) + { + _redirectingToHttps(logger, redirect, null); + } + + public static void PortLoadedFromConfig(this ILogger logger, int port) + { + _portLoadedFromConfig(logger, port, null); + } + + public static void FailedToDeterminePort(this ILogger logger) + { + _failedToDeterminePort(logger, null); + } + + public static void FailedMultiplePorts(this ILogger logger) + { + _failedMultiplePorts(logger, null); + } + + public static void PortFromServer(this ILogger logger, int port) + { + _portFromServer(logger, port, null); + } + } +} diff --git a/test/Microsoft.AspNetCore.HttpsPolicy.Tests/HttpsPolicyTests.cs b/test/Microsoft.AspNetCore.HttpsPolicy.Tests/HttpsPolicyTests.cs index aa874fb8cd..2b9b3d3b49 100644 --- a/test/Microsoft.AspNetCore.HttpsPolicy.Tests/HttpsPolicyTests.cs +++ b/test/Microsoft.AspNetCore.HttpsPolicy.Tests/HttpsPolicyTests.cs @@ -21,12 +21,12 @@ namespace Microsoft.AspNetCore.HttpsPolicy.Tests public class HttpsPolicyTests { [Theory] - [InlineData(302, null, 2592000, false, false, "max-age=2592000", "https://localhost/")] + [InlineData(302, 443, 2592000, false, false, "max-age=2592000", "https://localhost/")] [InlineData(301, 5050, 2592000, false, false, "max-age=2592000", "https://localhost:5050/")] [InlineData(301, 443, 2592000, false, false, "max-age=2592000", "https://localhost/")] [InlineData(301, 443, 2592000, true, false, "max-age=2592000; includeSubDomains", "https://localhost/")] [InlineData(301, 443, 2592000, false, true, "max-age=2592000; preload", "https://localhost/")] - [InlineData(301, null, 2592000, true, true, "max-age=2592000; includeSubDomains; preload", "https://localhost/")] + [InlineData(301, 443, 2592000, true, true, "max-age=2592000; includeSubDomains; preload", "https://localhost/")] [InlineData(302, 5050, 2592000, true, true, "max-age=2592000; includeSubDomains; preload", "https://localhost:5050/")] public async Task SetsBothHstsAndHttpsRedirection_RedirectOnFirstRequest_HstsOnSecondRequest(int statusCode, int? tlsPort, int maxAge, bool includeSubDomains, bool preload, string expectedHstsHeader, string expectedUrl) { @@ -71,7 +71,7 @@ namespace Microsoft.AspNetCore.HttpsPolicy.Tests client = server.CreateClient(); client.BaseAddress = new Uri(response.Headers.Location.ToString()); - request = new HttpRequestMessage(HttpMethod.Get, ""); + request = new HttpRequestMessage(HttpMethod.Get, expectedUrl); response = await client.SendAsync(request); Assert.Equal(expectedHstsHeader, response.Headers.GetValues(HeaderNames.StrictTransportSecurity).FirstOrDefault()); diff --git a/test/Microsoft.AspNetCore.HttpsPolicy.Tests/HttpsRedirectionMiddlewareTests.cs b/test/Microsoft.AspNetCore.HttpsPolicy.Tests/HttpsRedirectionMiddlewareTests.cs index b55c195272..ef0b0c3685 100644 --- a/test/Microsoft.AspNetCore.HttpsPolicy.Tests/HttpsRedirectionMiddlewareTests.cs +++ b/test/Microsoft.AspNetCore.HttpsPolicy.Tests/HttpsRedirectionMiddlewareTests.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; +using System.Linq; using System.Net; using System.Net.Http; using System.Threading.Tasks; @@ -12,6 +13,8 @@ using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http.Features; using Microsoft.AspNetCore.TestHost; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Logging.Testing; using Xunit; namespace Microsoft.AspNetCore.HttpsPolicy.Tests @@ -19,9 +22,17 @@ namespace Microsoft.AspNetCore.HttpsPolicy.Tests public class HttpsRedirectionMiddlewareTests { [Fact] - public async Task SetOptions_DefaultsSetCorrectly() + public async Task SetOptions_NotEnabledByDefault() { + var sink = new TestSink( + TestSink.EnableWithTypeName, + TestSink.EnableWithTypeName); + var loggerFactory = new TestLoggerFactory(sink, enabled: true); var builder = new WebHostBuilder() + .ConfigureServices(services => + { + services.AddSingleton(loggerFactory); + }) .Configure(app => { app.UseHttpsRedirection(); @@ -38,23 +49,32 @@ namespace Microsoft.AspNetCore.HttpsPolicy.Tests var response = await client.SendAsync(request); - Assert.Equal(HttpStatusCode.RedirectKeepVerb, response.StatusCode); - Assert.Equal("https://localhost/", response.Headers.Location.ToString()); + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + + var logMessages = sink.Writes.ToList(); + + Assert.Single(logMessages); + var message = logMessages.Single(); + Assert.Equal(LogLevel.Warning, message.LogLevel); + Assert.Equal("Failed to determine the https port for redirect.", message.State.ToString()); } [Theory] - [InlineData(301, null, "https://localhost/")] - [InlineData(302, null, "https://localhost/")] - [InlineData(307, null, "https://localhost/")] - [InlineData(308, null, "https://localhost/")] + [InlineData(302, 5001, "https://localhost:5001/")] + [InlineData(307, 1, "https://localhost:1/")] + [InlineData(308, 3449, "https://localhost:3449/")] [InlineData(301, 5050, "https://localhost:5050/")] [InlineData(301, 443, "https://localhost/")] public async Task SetOptions_SetStatusCodeHttpsPort(int statusCode, int? httpsPort, string expected) { - + var sink = new TestSink( + TestSink.EnableWithTypeName, + TestSink.EnableWithTypeName); + var loggerFactory = new TestLoggerFactory(sink, enabled: true); var builder = new WebHostBuilder() .ConfigureServices(services => { + services.AddSingleton(loggerFactory); services.Configure(options => { options.RedirectStatusCode = statusCode; @@ -79,20 +99,31 @@ namespace Microsoft.AspNetCore.HttpsPolicy.Tests Assert.Equal(statusCode, (int)response.StatusCode); Assert.Equal(expected, response.Headers.Location.ToString()); + + var logMessages = sink.Writes.ToList(); + + Assert.Single(logMessages); + var message = logMessages.Single(); + Assert.Equal(LogLevel.Debug, message.LogLevel); + Assert.Equal($"Redirecting to '{expected}'.", message.State.ToString()); } [Theory] - [InlineData(301, null, "https://localhost/")] - [InlineData(302, null, "https://localhost/")] - [InlineData(307, null, "https://localhost/")] - [InlineData(308, null, "https://localhost/")] + [InlineData(302, 5001, "https://localhost:5001/")] + [InlineData(307, 1, "https://localhost:1/")] + [InlineData(308, 3449, "https://localhost:3449/")] [InlineData(301, 5050, "https://localhost:5050/")] [InlineData(301, 443, "https://localhost/")] public async Task SetOptionsThroughHelperMethod_SetStatusCodeAndHttpsPort(int statusCode, int? httpsPort, string expectedUrl) { + var sink = new TestSink( + TestSink.EnableWithTypeName, + TestSink.EnableWithTypeName); + var loggerFactory = new TestLoggerFactory(sink, enabled: true); var builder = new WebHostBuilder() .ConfigureServices(services => { + services.AddSingleton(loggerFactory); services.AddHttpsRedirection(options => { options.RedirectStatusCode = statusCode; @@ -117,20 +148,26 @@ namespace Microsoft.AspNetCore.HttpsPolicy.Tests Assert.Equal(statusCode, (int)response.StatusCode); Assert.Equal(expectedUrl, response.Headers.Location.ToString()); + + var logMessages = sink.Writes.ToList(); + + Assert.Single(logMessages); + var message = logMessages.Single(); + Assert.Equal(LogLevel.Debug, message.LogLevel); + Assert.Equal($"Redirecting to '{expectedUrl}'.", message.State.ToString()); } [Theory] - [InlineData(null, null, null, "https://localhost/")] [InlineData(null, null, "https://localhost:4444/", "https://localhost:4444/")] [InlineData(null, null, "https://localhost:443/", "https://localhost/")] - [InlineData(null, null, "http://localhost:5044/", "https://localhost/")] [InlineData(null, null, "https://localhost/", "https://localhost/")] [InlineData(null, "5000", "https://localhost:4444/", "https://localhost:5000/")] [InlineData(null, "443", "https://localhost:4444/", "https://localhost/")] [InlineData(443, "5000", "https://localhost:4444/", "https://localhost/")] [InlineData(4000, "5000", "https://localhost:4444/", "https://localhost:4000/")] [InlineData(5000, null, "https://localhost:4444/", "https://localhost:5000/")] - public async Task SetHttpsPortEnvironmentVariableAndServerFeature_ReturnsCorrectStatusCodeOnResponse(int? optionsHttpsPort, string configHttpsPort, string serverAddressFeatureUrl, string expectedUrl) + public async Task SetHttpsPortEnvironmentVariableAndServerFeature_ReturnsCorrectStatusCodeOnResponse( + int? optionsHttpsPort, string configHttpsPort, string serverAddressFeatureUrl, string expectedUrl) { var builder = new WebHostBuilder() .ConfigureServices(services => @@ -172,7 +209,15 @@ namespace Microsoft.AspNetCore.HttpsPolicy.Tests [Fact] public async Task SetServerAddressesFeature_SingleHttpsAddress_Success() { + var sink = new TestSink( + TestSink.EnableWithTypeName, + TestSink.EnableWithTypeName); + var loggerFactory = new TestLoggerFactory(sink, enabled: true); var builder = new WebHostBuilder() + .ConfigureServices(services => + { + services.AddSingleton(loggerFactory); + }) .Configure(app => { app.UseHttpsRedirection(); @@ -194,12 +239,31 @@ namespace Microsoft.AspNetCore.HttpsPolicy.Tests var response = await client.SendAsync(request); Assert.Equal("https://localhost:5050/", response.Headers.Location.ToString()); + + var logMessages = sink.Writes.ToList(); + + Assert.Equal(2, logMessages.Count); + var message = logMessages.First(); + Assert.Equal(LogLevel.Debug, message.LogLevel); + Assert.Equal("Https port '5050' discovered from server endpoints.", message.State.ToString()); + + message = logMessages.Skip(1).First(); + Assert.Equal(LogLevel.Debug, message.LogLevel); + Assert.Equal("Redirecting to 'https://localhost:5050/'.", message.State.ToString()); } [Fact] - public async Task SetServerAddressesFeature_MultipleHttpsAddresses_ThrowInMiddleware() + public async Task SetServerAddressesFeature_MultipleHttpsAddresses_LogsAndFailsToRedirect() { + var sink = new TestSink( + TestSink.EnableWithTypeName, + TestSink.EnableWithTypeName); + var loggerFactory = new TestLoggerFactory(sink, enabled: true); var builder = new WebHostBuilder() + .ConfigureServices(services => + { + services.AddSingleton(loggerFactory); + }) .Configure(app => { app.UseHttpsRedirection(); @@ -220,13 +284,30 @@ namespace Microsoft.AspNetCore.HttpsPolicy.Tests var request = new HttpRequestMessage(HttpMethod.Get, ""); - await Assert.ThrowsAsync(async () => await client.SendAsync(request)); + var response = await client.SendAsync(request); + Assert.Equal(200, (int)response.StatusCode); + + var logMessages = sink.Writes.ToList(); + + Assert.Single(logMessages); + var message = logMessages.First(); + Assert.Equal(LogLevel.Warning, message.LogLevel); + Assert.Equal("Cannot determine the https port from IServerAddressesFeature, multiple values were found. " + + "Please set the desired port explicitly on HttpsRedirectionOptions.HttpsPort.", message.State.ToString()); } [Fact] public async Task SetServerAddressesFeature_MultipleHttpsAddressesWithSamePort_Success() { + var sink = new TestSink( + TestSink.EnableWithTypeName, + TestSink.EnableWithTypeName); + var loggerFactory = new TestLoggerFactory(sink, enabled: true); var builder = new WebHostBuilder() + .ConfigureServices(services => + { + services.AddSingleton(loggerFactory); + }) .Configure(app => { app.UseHttpsRedirection(); @@ -241,7 +322,7 @@ namespace Microsoft.AspNetCore.HttpsPolicy.Tests var server = new TestServer(builder, featureCollection); server.Features.Get().Addresses.Add("https://localhost:5050"); - server.Features.Get().Addresses.Add("https://localhost:5050"); + server.Features.Get().Addresses.Add("https://example.com:5050"); var client = server.CreateClient(); @@ -250,17 +331,30 @@ namespace Microsoft.AspNetCore.HttpsPolicy.Tests var response = await client.SendAsync(request); Assert.Equal("https://localhost:5050/", response.Headers.Location.ToString()); + + var logMessages = sink.Writes.ToList(); + + Assert.Equal(2, logMessages.Count); + var message = logMessages.First(); + Assert.Equal(LogLevel.Debug, message.LogLevel); + Assert.Equal("Https port '5050' discovered from server endpoints.", message.State.ToString()); + + message = logMessages.Skip(1).First(); + Assert.Equal(LogLevel.Debug, message.LogLevel); + Assert.Equal("Redirecting to 'https://localhost:5050/'.", message.State.ToString()); } [Fact] - public async Task NoServerAddressFeature_DoesNotThrow_DefaultsTo443() + public async Task NoServerAddressFeature_DoesNotThrow_DoesNotRedirect() { + var sink = new TestSink( + TestSink.EnableWithTypeName, + TestSink.EnableWithTypeName); + var loggerFactory = new TestLoggerFactory(sink, enabled: true); var builder = new WebHostBuilder() .ConfigureServices(services => { - services.AddHttpsRedirection(options => - { - }); + services.AddSingleton(loggerFactory); }) .Configure(app => { @@ -275,19 +369,27 @@ namespace Microsoft.AspNetCore.HttpsPolicy.Tests var client = server.CreateClient(); var request = new HttpRequestMessage(HttpMethod.Get, ""); var response = await client.SendAsync(request); + Assert.Equal(200, (int)response.StatusCode); - Assert.Equal("https://localhost/", response.Headers.Location.ToString()); + var logMessages = sink.Writes.ToList(); + + Assert.Single(logMessages); + var message = logMessages.First(); + Assert.Equal(LogLevel.Warning, message.LogLevel); + Assert.Equal("Failed to determine the https port for redirect.", message.State.ToString()); } [Fact] public async Task SetNullAddressFeature_DoesNotThrow() { + var sink = new TestSink( + TestSink.EnableWithTypeName, + TestSink.EnableWithTypeName); + var loggerFactory = new TestLoggerFactory(sink, enabled: true); var builder = new WebHostBuilder() .ConfigureServices(services => { - services.AddHttpsRedirection(options => - { - }); + services.AddSingleton(loggerFactory); }) .Configure(app => { @@ -305,8 +407,14 @@ namespace Microsoft.AspNetCore.HttpsPolicy.Tests var client = server.CreateClient(); var request = new HttpRequestMessage(HttpMethod.Get, ""); var response = await client.SendAsync(request); + Assert.Equal(200, (int)response.StatusCode); - Assert.Equal("https://localhost/", response.Headers.Location.ToString()); + var logMessages = sink.Writes.ToList(); + + Assert.Single(logMessages); + var message = logMessages.First(); + Assert.Equal(LogLevel.Warning, message.LogLevel); + Assert.Equal("Failed to determine the https port for redirect.", message.State.ToString()); } } } diff --git a/test/Microsoft.AspNetCore.HttpsPolicy.Tests/Microsoft.AspNetCore.HttpsPolicy.Tests.csproj b/test/Microsoft.AspNetCore.HttpsPolicy.Tests/Microsoft.AspNetCore.HttpsPolicy.Tests.csproj index af610a24a8..e51e3a6640 100644 --- a/test/Microsoft.AspNetCore.HttpsPolicy.Tests/Microsoft.AspNetCore.HttpsPolicy.Tests.csproj +++ b/test/Microsoft.AspNetCore.HttpsPolicy.Tests/Microsoft.AspNetCore.HttpsPolicy.Tests.csproj @@ -1,4 +1,4 @@ - + netcoreapp2.1 @@ -8,4 +8,8 @@ + + + + From f9619367fc989a02f640388c70db8fd5e68e6721 Mon Sep 17 00:00:00 2001 From: Ryan Brandenburg Date: Mon, 16 Apr 2018 16:54:13 -0700 Subject: [PATCH 294/307] Branching for 2.1.0-rc1 --- build/repo.props | 3 ++- korebuild.json | 4 ++-- version.props | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/build/repo.props b/build/repo.props index 78b0ce5879..dab1601c88 100644 --- a/build/repo.props +++ b/build/repo.props @@ -1,9 +1,10 @@ - + Internal.AspNetCore.Universe.Lineup + 2.1.0-rc1-* https://dotnet.myget.org/F/aspnetcore-dev/api/v3/index.json diff --git a/korebuild.json b/korebuild.json index bd5d51a51b..678d8bb948 100644 --- a/korebuild.json +++ b/korebuild.json @@ -1,4 +1,4 @@ { - "$schema": "https://raw.githubusercontent.com/aspnet/BuildTools/dev/tools/korebuild.schema.json", - "channel": "dev" + "$schema": "https://raw.githubusercontent.com/aspnet/BuildTools/release/2.1/tools/korebuild.schema.json", + "channel": "release/2.1" } diff --git a/version.props b/version.props index 9124b26738..6167eb653c 100644 --- a/version.props +++ b/version.props @@ -1,7 +1,7 @@ 2.1.0 - preview3 + rc1 $(VersionPrefix) $(VersionPrefix)-$(VersionSuffix)-final t000 From eb5499acbddc480ac7b4238ac78cef626a790889 Mon Sep 17 00:00:00 2001 From: Nate McMaster Date: Thu, 19 Apr 2018 16:30:44 -0700 Subject: [PATCH 295/307] Set NETStandardImplicitPackageVersion via dependencies.props --- Directory.Build.targets | 1 + build/dependencies.props | 1 + 2 files changed, 2 insertions(+) diff --git a/Directory.Build.targets b/Directory.Build.targets index 894b1d0cf8..53b3f6e1da 100644 --- a/Directory.Build.targets +++ b/Directory.Build.targets @@ -2,5 +2,6 @@ $(MicrosoftNETCoreApp20PackageVersion) $(MicrosoftNETCoreApp21PackageVersion) + $(NETStandardLibrary20PackageVersion) diff --git a/build/dependencies.props b/build/dependencies.props index 7ddd689238..064d84aed7 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -25,6 +25,7 @@ 2.1.0-preview3-26413-05 2.1.0-preview3-32233 15.6.1 + 2.0.1 4.7.49 0.8.0 2.3.1 From 030d5239aebe3cf17f0087542ede4c4df3369384 Mon Sep 17 00:00:00 2001 From: "ASP.NET CI" Date: Thu, 19 Apr 2018 22:14:35 -0700 Subject: [PATCH 296/307] Update dependencies.props [auto-updated: dependencies] --- build/dependencies.props | 42 ++++++++++++++++++++-------------------- korebuild-lock.txt | 4 ++-- 2 files changed, 23 insertions(+), 23 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index 064d84aed7..0e00596e51 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -3,30 +3,30 @@ $(MSBuildAllProjects);$(MSBuildThisFileFullPath) - 2.1.0-preview3-17018 - 2.1.0-preview3-32233 - 2.1.0-preview3-32233 - 2.1.0-preview3-32233 - 2.1.0-preview3-32233 - 2.1.0-preview3-32233 - 2.1.0-preview3-32233 - 2.1.0-preview3-32233 - 2.1.0-preview3-32233 - 2.1.0-preview3-32233 - 2.1.0-preview3-32233 - 2.1.0-preview3-32233 - 2.1.0-preview3-32233 - 2.1.0-preview3-32233 - 2.1.0-preview3-32233 - 2.1.0-preview3-32233 - 2.1.0-preview3-32233 - 2.1.0-preview3-32233 + 2.1.0-rc1-15774 + 2.1.0-rc1-30613 + 2.1.0-rc1-30613 + 2.1.0-rc1-30613 + 2.1.0-rc1-30613 + 2.1.0-rc1-30613 + 2.1.0-rc1-30613 + 2.1.0-rc1-30613 + 2.1.0-rc1-30613 + 2.1.0-rc1-30613 + 2.1.0-rc1-30613 + 2.1.0-rc1-30613 + 2.1.0-rc1-30613 + 2.1.0-rc1-30613 + 2.1.0-rc1-30613 + 2.1.0-rc1-30613 + 2.1.0-rc1-30613 + 2.1.0-rc1-30613 2.0.0 - 2.1.0-preview3-26413-05 - 2.1.0-preview3-32233 + 2.1.0-rc1-26419-02 + 2.1.0-rc1-30613 15.6.1 - 2.0.1 4.7.49 + 2.0.1 0.8.0 2.3.1 2.4.0-beta.1.build3945 diff --git a/korebuild-lock.txt b/korebuild-lock.txt index b419d767b9..9d4ef8c888 100644 --- a/korebuild-lock.txt +++ b/korebuild-lock.txt @@ -1,2 +1,2 @@ -version:2.1.0-preview3-17018 -commithash:af264ca131f212b5ba8aafbc5110fc0fc510a2be +version:2.1.0-rc1-15774 +commithash:ed5ca9de3c652347dbb0158a9a65eff3471d2114 From f0f42cf259c0e0f16125b950bfaba1034bfc54dc Mon Sep 17 00:00:00 2001 From: "Nate McMaster (automated)" Date: Mon, 30 Apr 2018 14:51:37 -0700 Subject: [PATCH 297/307] Bump version to 2.1.0-rtm --- version.props | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/version.props b/version.props index 6167eb653c..c8bf9b67b7 100644 --- a/version.props +++ b/version.props @@ -1,7 +1,7 @@ 2.1.0 - rc1 + rtm $(VersionPrefix) $(VersionPrefix)-$(VersionSuffix)-final t000 @@ -10,7 +10,7 @@ $(VersionSuffix)-$(BuildNumber) 0.4.0 - preview3 + rtm $(ExperimentalVersionPrefix) $(ExperimentalVersionPrefix)-$(ExperimentalVersionSuffix)-final $(ExperimentalVersionSuffix)-$(BuildNumber) From 82f6cd224a0e3c80bba9a0ac3155f9a95f617515 Mon Sep 17 00:00:00 2001 From: "ASP.NET CI" Date: Fri, 4 May 2018 07:27:41 -0700 Subject: [PATCH 298/307] Update dependencies.props [auto-updated: dependencies] --- build/dependencies.props | 42 ++++++++++++++++++++-------------------- korebuild-lock.txt | 4 ++-- 2 files changed, 23 insertions(+), 23 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index 0e00596e51..9e41232006 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -3,30 +3,30 @@ $(MSBuildAllProjects);$(MSBuildThisFileFullPath) - 2.1.0-rc1-15774 - 2.1.0-rc1-30613 - 2.1.0-rc1-30613 - 2.1.0-rc1-30613 - 2.1.0-rc1-30613 - 2.1.0-rc1-30613 - 2.1.0-rc1-30613 - 2.1.0-rc1-30613 - 2.1.0-rc1-30613 - 2.1.0-rc1-30613 - 2.1.0-rc1-30613 - 2.1.0-rc1-30613 - 2.1.0-rc1-30613 - 2.1.0-rc1-30613 - 2.1.0-rc1-30613 - 2.1.0-rc1-30613 - 2.1.0-rc1-30613 - 2.1.0-rc1-30613 + 2.1.0-rtm-15783 + 2.1.0-rtm-30721 + 2.1.0-rtm-30721 + 2.1.0-rtm-30721 + 2.1.0-rtm-30721 + 2.1.0-rtm-30721 + 2.1.0-rtm-30721 + 2.1.0-rtm-30721 + 2.1.0-rtm-30721 + 2.1.0-rtm-30721 + 2.1.0-rtm-30721 + 2.1.0-rtm-30721 + 2.1.0-rtm-30721 + 2.1.0-rtm-30721 + 2.1.0-rtm-30721 + 2.1.0-rtm-30721 + 2.1.0-rtm-30721 + 2.1.0-rtm-30721 2.0.0 - 2.1.0-rc1-26419-02 - 2.1.0-rc1-30613 + 2.1.0-rtm-26502-02 + 2.1.0-rtm-30721 15.6.1 4.7.49 - 2.0.1 + 2.0.3 0.8.0 2.3.1 2.4.0-beta.1.build3945 diff --git a/korebuild-lock.txt b/korebuild-lock.txt index 9d4ef8c888..3673744db9 100644 --- a/korebuild-lock.txt +++ b/korebuild-lock.txt @@ -1,2 +1,2 @@ -version:2.1.0-rc1-15774 -commithash:ed5ca9de3c652347dbb0158a9a65eff3471d2114 +version:2.1.0-rtm-15783 +commithash:5fc2b2f607f542a2ffde11c19825e786fc1a3774 From 901efb04a93f95d33f3257f58b1f0608b02185ba Mon Sep 17 00:00:00 2001 From: "ASP.NET CI" Date: Tue, 29 May 2018 09:30:52 -0700 Subject: [PATCH 299/307] Update dependencies.props [auto-updated: dependencies] --- build/dependencies.props | 40 ++++++++++++++++++++-------------------- korebuild-lock.txt | 4 ++-- 2 files changed, 22 insertions(+), 22 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index 9e41232006..4dee643b01 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -3,27 +3,27 @@ $(MSBuildAllProjects);$(MSBuildThisFileFullPath) - 2.1.0-rtm-15783 - 2.1.0-rtm-30721 - 2.1.0-rtm-30721 - 2.1.0-rtm-30721 - 2.1.0-rtm-30721 - 2.1.0-rtm-30721 - 2.1.0-rtm-30721 - 2.1.0-rtm-30721 - 2.1.0-rtm-30721 - 2.1.0-rtm-30721 - 2.1.0-rtm-30721 - 2.1.0-rtm-30721 - 2.1.0-rtm-30721 - 2.1.0-rtm-30721 - 2.1.0-rtm-30721 - 2.1.0-rtm-30721 - 2.1.0-rtm-30721 - 2.1.0-rtm-30721 + 2.1.1-rtm-15790 + 2.1.0 + 2.1.0 + 2.1.0 + 2.1.0 + 2.1.0 + 2.1.0 + 2.1.0 + 2.1.0 + 2.1.0 + 2.1.0 + 2.1.0 + 2.1.0 + 2.1.0 + 2.1.0 + 2.1.0 + 2.1.0 + 2.1.0 2.0.0 - 2.1.0-rtm-26502-02 - 2.1.0-rtm-30721 + 2.1.0 + 2.1.0 15.6.1 4.7.49 2.0.3 diff --git a/korebuild-lock.txt b/korebuild-lock.txt index 3673744db9..cd5b409a1e 100644 --- a/korebuild-lock.txt +++ b/korebuild-lock.txt @@ -1,2 +1,2 @@ -version:2.1.0-rtm-15783 -commithash:5fc2b2f607f542a2ffde11c19825e786fc1a3774 +version:2.1.1-rtm-15790 +commithash:274c65868e735f29f4078c1884c61c4371ee1fc0 From 999ed531cb25cc4f2c31f84c7144b9e401943aa9 Mon Sep 17 00:00:00 2001 From: Nate McMaster Date: Tue, 5 Jun 2018 09:11:25 -0700 Subject: [PATCH 300/307] Bumping version from 2.1.0 to 2.1.1 --- version.props | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/version.props b/version.props index c8bf9b67b7..6ecf2553b6 100644 --- a/version.props +++ b/version.props @@ -1,6 +1,6 @@ - + - 2.1.0 + 2.1.1 rtm $(VersionPrefix) $(VersionPrefix)-$(VersionSuffix)-final @@ -9,7 +9,7 @@ $(FeatureBranchVersionPrefix)$(VersionSuffix)-$([System.Text.RegularExpressions.Regex]::Replace('$(FeatureBranchVersionSuffix)', '[^\w-]', '-')) $(VersionSuffix)-$(BuildNumber) - 0.4.0 + 0.4.1 rtm $(ExperimentalVersionPrefix) $(ExperimentalVersionPrefix)-$(ExperimentalVersionSuffix)-final From 8c7e7357d40663abd8c82f7e24963d0c857cf117 Mon Sep 17 00:00:00 2001 From: "ASP.NET CI" Date: Tue, 12 Jun 2018 19:12:37 +0000 Subject: [PATCH 301/307] Update dependencies.props [auto-updated: dependencies] --- build/dependencies.props | 40 ++++++++++++++++++++-------------------- korebuild-lock.txt | 4 ++-- 2 files changed, 22 insertions(+), 22 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index 4dee643b01..71133dbd09 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -3,27 +3,27 @@ $(MSBuildAllProjects);$(MSBuildThisFileFullPath) - 2.1.1-rtm-15790 - 2.1.0 - 2.1.0 - 2.1.0 - 2.1.0 - 2.1.0 - 2.1.0 - 2.1.0 - 2.1.0 - 2.1.0 - 2.1.0 - 2.1.0 - 2.1.0 - 2.1.0 - 2.1.0 - 2.1.0 - 2.1.0 - 2.1.0 + 2.1.1-rtm-15793 + 2.1.1 + 2.1.1 + 2.1.1 + 2.1.1 + 2.1.1 + 2.1.1 + 2.1.1 + 2.1.1 + 2.1.1 + 2.1.1 + 2.1.1 + 2.1.1 + 2.1.1 + 2.1.1 + 2.1.1 + 2.1.1 + 2.1.1 2.0.0 - 2.1.0 - 2.1.0 + 2.1.1 + 2.1.1 15.6.1 4.7.49 2.0.3 diff --git a/korebuild-lock.txt b/korebuild-lock.txt index cd5b409a1e..bc84e0cd53 100644 --- a/korebuild-lock.txt +++ b/korebuild-lock.txt @@ -1,2 +1,2 @@ -version:2.1.1-rtm-15790 -commithash:274c65868e735f29f4078c1884c61c4371ee1fc0 +version:2.1.1-rtm-15793 +commithash:988313f4b064d6c69fc6f7b845b6384a6af3447a From 4295027333b19500b87626b0d34553046a3a31c2 Mon Sep 17 00:00:00 2001 From: Ryan Brandenburg Date: Thu, 14 Jun 2018 10:26:01 -0700 Subject: [PATCH 302/307] Set 2.1 baselines --- .../baseline.netcore.json | 184 + .../baseline.netcore.json | 54 +- .../baseline.netcore.json | 378 ++ .../baseline.netcore.json | 2 +- .../baseline.netframework.json | 2 +- .../baseline.netcore.json | 5364 +---------------- 6 files changed, 636 insertions(+), 5348 deletions(-) create mode 100644 src/Microsoft.AspNetCore.HostFiltering/baseline.netcore.json create mode 100644 src/Microsoft.AspNetCore.HttpsPolicy/baseline.netcore.json diff --git a/src/Microsoft.AspNetCore.HostFiltering/baseline.netcore.json b/src/Microsoft.AspNetCore.HostFiltering/baseline.netcore.json new file mode 100644 index 0000000000..18c6e39345 --- /dev/null +++ b/src/Microsoft.AspNetCore.HostFiltering/baseline.netcore.json @@ -0,0 +1,184 @@ +{ + "AssemblyIdentity": "Microsoft.AspNetCore.HostFiltering, Version=2.1.1.0, Culture=neutral, PublicKeyToken=adb9793829ddae60", + "Types": [ + { + "Name": "Microsoft.AspNetCore.HostFiltering.HostFilteringMiddleware", + "Visibility": "Public", + "Kind": "Class", + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Method", + "Name": "Invoke", + "Parameters": [ + { + "Name": "context", + "Type": "Microsoft.AspNetCore.Http.HttpContext" + } + ], + "ReturnType": "System.Threading.Tasks.Task", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [ + { + "Name": "next", + "Type": "Microsoft.AspNetCore.Http.RequestDelegate" + }, + { + "Name": "logger", + "Type": "Microsoft.Extensions.Logging.ILogger" + }, + { + "Name": "optionsMonitor", + "Type": "Microsoft.Extensions.Options.IOptionsMonitor" + } + ], + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.HostFiltering.HostFilteringOptions", + "Visibility": "Public", + "Kind": "Class", + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Method", + "Name": "get_AllowedHosts", + "Parameters": [], + "ReturnType": "System.Collections.Generic.IList", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "set_AllowedHosts", + "Parameters": [ + { + "Name": "value", + "Type": "System.Collections.Generic.IList" + } + ], + "ReturnType": "System.Void", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "get_AllowEmptyHosts", + "Parameters": [], + "ReturnType": "System.Boolean", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "set_AllowEmptyHosts", + "Parameters": [ + { + "Name": "value", + "Type": "System.Boolean" + } + ], + "ReturnType": "System.Void", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "get_IncludeFailureMessage", + "Parameters": [], + "ReturnType": "System.Boolean", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "set_IncludeFailureMessage", + "Parameters": [ + { + "Name": "value", + "Type": "System.Boolean" + } + ], + "ReturnType": "System.Void", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [], + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.Builder.HostFilteringBuilderExtensions", + "Visibility": "Public", + "Kind": "Class", + "Abstract": true, + "Static": true, + "Sealed": true, + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Method", + "Name": "UseHostFiltering", + "Parameters": [ + { + "Name": "app", + "Type": "Microsoft.AspNetCore.Builder.IApplicationBuilder" + } + ], + "ReturnType": "Microsoft.AspNetCore.Builder.IApplicationBuilder", + "Static": true, + "Extension": true, + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.Builder.HostFilteringServicesExtensions", + "Visibility": "Public", + "Kind": "Class", + "Abstract": true, + "Static": true, + "Sealed": true, + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Method", + "Name": "AddHostFiltering", + "Parameters": [ + { + "Name": "services", + "Type": "Microsoft.Extensions.DependencyInjection.IServiceCollection" + }, + { + "Name": "configureOptions", + "Type": "System.Action" + } + ], + "ReturnType": "Microsoft.Extensions.DependencyInjection.IServiceCollection", + "Static": true, + "Extension": true, + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + } + ] +} \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.HttpOverrides/baseline.netcore.json b/src/Microsoft.AspNetCore.HttpOverrides/baseline.netcore.json index d5d1fac25e..7764941a52 100644 --- a/src/Microsoft.AspNetCore.HttpOverrides/baseline.netcore.json +++ b/src/Microsoft.AspNetCore.HttpOverrides/baseline.netcore.json @@ -1,5 +1,5 @@ { - "AssemblyIdentity": "Microsoft.AspNetCore.HttpOverrides, Version=2.0.2.0, Culture=neutral, PublicKeyToken=adb9793829ddae60", + "AssemblyIdentity": "Microsoft.AspNetCore.HttpOverrides, Version=2.1.1.0, Culture=neutral, PublicKeyToken=adb9793829ddae60", "Types": [ { "Name": "Microsoft.AspNetCore.Builder.ForwardedHeadersExtensions", @@ -237,6 +237,27 @@ "Visibility": "Public", "GenericParameter": [] }, + { + "Kind": "Method", + "Name": "get_AllowedHosts", + "Parameters": [], + "ReturnType": "System.Collections.Generic.IList", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "set_AllowedHosts", + "Parameters": [ + { + "Name": "value", + "Type": "System.Collections.Generic.IList" + } + ], + "ReturnType": "System.Void", + "Visibility": "Public", + "GenericParameter": [] + }, { "Kind": "Method", "Name": "get_RequireHeaderSymmetry", @@ -608,37 +629,6 @@ } ], "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.HttpOverrides.Internal.IPEndPointParser", - "Visibility": "Public", - "Kind": "Class", - "Abstract": true, - "Static": true, - "Sealed": true, - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Method", - "Name": "TryParse", - "Parameters": [ - { - "Name": "addressWithPort", - "Type": "System.String" - }, - { - "Name": "endpoint", - "Type": "System.Net.IPEndPoint", - "Direction": "Out" - } - ], - "ReturnType": "System.Boolean", - "Static": true, - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] } ] } \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.HttpsPolicy/baseline.netcore.json b/src/Microsoft.AspNetCore.HttpsPolicy/baseline.netcore.json new file mode 100644 index 0000000000..26f1f412f9 --- /dev/null +++ b/src/Microsoft.AspNetCore.HttpsPolicy/baseline.netcore.json @@ -0,0 +1,378 @@ +{ + "AssemblyIdentity": "Microsoft.AspNetCore.HttpsPolicy, Version=2.1.1.0, Culture=neutral, PublicKeyToken=adb9793829ddae60", + "Types": [ + { + "Name": "Microsoft.AspNetCore.HttpsPolicy.HstsMiddleware", + "Visibility": "Public", + "Kind": "Class", + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Method", + "Name": "Invoke", + "Parameters": [ + { + "Name": "context", + "Type": "Microsoft.AspNetCore.Http.HttpContext" + } + ], + "ReturnType": "System.Threading.Tasks.Task", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [ + { + "Name": "next", + "Type": "Microsoft.AspNetCore.Http.RequestDelegate" + }, + { + "Name": "options", + "Type": "Microsoft.Extensions.Options.IOptions" + } + ], + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.HttpsPolicy.HstsOptions", + "Visibility": "Public", + "Kind": "Class", + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Method", + "Name": "get_MaxAge", + "Parameters": [], + "ReturnType": "System.TimeSpan", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "set_MaxAge", + "Parameters": [ + { + "Name": "value", + "Type": "System.TimeSpan" + } + ], + "ReturnType": "System.Void", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "get_IncludeSubDomains", + "Parameters": [], + "ReturnType": "System.Boolean", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "set_IncludeSubDomains", + "Parameters": [ + { + "Name": "value", + "Type": "System.Boolean" + } + ], + "ReturnType": "System.Void", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "get_Preload", + "Parameters": [], + "ReturnType": "System.Boolean", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "set_Preload", + "Parameters": [ + { + "Name": "value", + "Type": "System.Boolean" + } + ], + "ReturnType": "System.Void", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "get_ExcludedHosts", + "Parameters": [], + "ReturnType": "System.Collections.Generic.IList", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [], + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.HttpsPolicy.HttpsRedirectionMiddleware", + "Visibility": "Public", + "Kind": "Class", + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Method", + "Name": "Invoke", + "Parameters": [ + { + "Name": "context", + "Type": "Microsoft.AspNetCore.Http.HttpContext" + } + ], + "ReturnType": "System.Threading.Tasks.Task", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [ + { + "Name": "next", + "Type": "Microsoft.AspNetCore.Http.RequestDelegate" + }, + { + "Name": "options", + "Type": "Microsoft.Extensions.Options.IOptions" + }, + { + "Name": "config", + "Type": "Microsoft.Extensions.Configuration.IConfiguration" + }, + { + "Name": "loggerFactory", + "Type": "Microsoft.Extensions.Logging.ILoggerFactory" + } + ], + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [ + { + "Name": "next", + "Type": "Microsoft.AspNetCore.Http.RequestDelegate" + }, + { + "Name": "options", + "Type": "Microsoft.Extensions.Options.IOptions" + }, + { + "Name": "config", + "Type": "Microsoft.Extensions.Configuration.IConfiguration" + }, + { + "Name": "loggerFactory", + "Type": "Microsoft.Extensions.Logging.ILoggerFactory" + }, + { + "Name": "serverAddressesFeature", + "Type": "Microsoft.AspNetCore.Hosting.Server.Features.IServerAddressesFeature" + } + ], + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.HttpsPolicy.HttpsRedirectionOptions", + "Visibility": "Public", + "Kind": "Class", + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Method", + "Name": "get_RedirectStatusCode", + "Parameters": [], + "ReturnType": "System.Int32", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "set_RedirectStatusCode", + "Parameters": [ + { + "Name": "value", + "Type": "System.Int32" + } + ], + "ReturnType": "System.Void", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "get_HttpsPort", + "Parameters": [], + "ReturnType": "System.Nullable", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "set_HttpsPort", + "Parameters": [ + { + "Name": "value", + "Type": "System.Nullable" + } + ], + "ReturnType": "System.Void", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [], + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.Builder.HstsBuilderExtensions", + "Visibility": "Public", + "Kind": "Class", + "Abstract": true, + "Static": true, + "Sealed": true, + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Method", + "Name": "UseHsts", + "Parameters": [ + { + "Name": "app", + "Type": "Microsoft.AspNetCore.Builder.IApplicationBuilder" + } + ], + "ReturnType": "Microsoft.AspNetCore.Builder.IApplicationBuilder", + "Static": true, + "Extension": true, + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.Builder.HstsServicesExtensions", + "Visibility": "Public", + "Kind": "Class", + "Abstract": true, + "Static": true, + "Sealed": true, + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Method", + "Name": "AddHsts", + "Parameters": [ + { + "Name": "services", + "Type": "Microsoft.Extensions.DependencyInjection.IServiceCollection" + }, + { + "Name": "configureOptions", + "Type": "System.Action" + } + ], + "ReturnType": "Microsoft.Extensions.DependencyInjection.IServiceCollection", + "Static": true, + "Extension": true, + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.Builder.HttpsPolicyBuilderExtensions", + "Visibility": "Public", + "Kind": "Class", + "Abstract": true, + "Static": true, + "Sealed": true, + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Method", + "Name": "UseHttpsRedirection", + "Parameters": [ + { + "Name": "app", + "Type": "Microsoft.AspNetCore.Builder.IApplicationBuilder" + } + ], + "ReturnType": "Microsoft.AspNetCore.Builder.IApplicationBuilder", + "Static": true, + "Extension": true, + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.Builder.HttpsRedirectionServicesExtensions", + "Visibility": "Public", + "Kind": "Class", + "Abstract": true, + "Static": true, + "Sealed": true, + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Method", + "Name": "AddHttpsRedirection", + "Parameters": [ + { + "Name": "services", + "Type": "Microsoft.Extensions.DependencyInjection.IServiceCollection" + }, + { + "Name": "configureOptions", + "Type": "System.Action" + } + ], + "ReturnType": "Microsoft.Extensions.DependencyInjection.IServiceCollection", + "Static": true, + "Extension": true, + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + } + ] +} \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.ResponseCompression/baseline.netcore.json b/src/Microsoft.AspNetCore.ResponseCompression/baseline.netcore.json index 4677b668c5..b778eaf322 100644 --- a/src/Microsoft.AspNetCore.ResponseCompression/baseline.netcore.json +++ b/src/Microsoft.AspNetCore.ResponseCompression/baseline.netcore.json @@ -1,5 +1,5 @@ { - "AssemblyIdentity": "Microsoft.AspNetCore.ResponseCompression, Version=2.0.2.0, Culture=neutral, PublicKeyToken=adb9793829ddae60", + "AssemblyIdentity": "Microsoft.AspNetCore.ResponseCompression, Version=2.1.1.0, Culture=neutral, PublicKeyToken=adb9793829ddae60", "Types": [ { "Name": "Microsoft.AspNetCore.Builder.ResponseCompressionBuilderExtensions", diff --git a/src/Microsoft.AspNetCore.ResponseCompression/baseline.netframework.json b/src/Microsoft.AspNetCore.ResponseCompression/baseline.netframework.json index 4677b668c5..b778eaf322 100644 --- a/src/Microsoft.AspNetCore.ResponseCompression/baseline.netframework.json +++ b/src/Microsoft.AspNetCore.ResponseCompression/baseline.netframework.json @@ -1,5 +1,5 @@ { - "AssemblyIdentity": "Microsoft.AspNetCore.ResponseCompression, Version=2.0.2.0, Culture=neutral, PublicKeyToken=adb9793829ddae60", + "AssemblyIdentity": "Microsoft.AspNetCore.ResponseCompression, Version=2.1.1.0, Culture=neutral, PublicKeyToken=adb9793829ddae60", "Types": [ { "Name": "Microsoft.AspNetCore.Builder.ResponseCompressionBuilderExtensions", diff --git a/src/Microsoft.AspNetCore.Rewrite/baseline.netcore.json b/src/Microsoft.AspNetCore.Rewrite/baseline.netcore.json index 64ce09c61d..d3f82fd1cd 100644 --- a/src/Microsoft.AspNetCore.Rewrite/baseline.netcore.json +++ b/src/Microsoft.AspNetCore.Rewrite/baseline.netcore.json @@ -1,5 +1,5 @@ { - "AssemblyIdentity": "Microsoft.AspNetCore.Rewrite, Version=2.0.2.0, Culture=neutral, PublicKeyToken=adb9793829ddae60", + "AssemblyIdentity": "Microsoft.AspNetCore.Rewrite, Version=2.1.1.0, Culture=neutral, PublicKeyToken=adb9793829ddae60", "Types": [ { "Name": "Microsoft.AspNetCore.Builder.RewriteBuilderExtensions", @@ -563,6 +563,55 @@ "Extension": true, "Visibility": "Public", "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "AddRedirectToWwwPermanent", + "Parameters": [ + { + "Name": "options", + "Type": "Microsoft.AspNetCore.Rewrite.RewriteOptions" + } + ], + "ReturnType": "Microsoft.AspNetCore.Rewrite.RewriteOptions", + "Static": true, + "Extension": true, + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "AddRedirectToWww", + "Parameters": [ + { + "Name": "options", + "Type": "Microsoft.AspNetCore.Rewrite.RewriteOptions" + } + ], + "ReturnType": "Microsoft.AspNetCore.Rewrite.RewriteOptions", + "Static": true, + "Extension": true, + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "AddRedirectToWww", + "Parameters": [ + { + "Name": "options", + "Type": "Microsoft.AspNetCore.Rewrite.RewriteOptions" + }, + { + "Name": "statusCode", + "Type": "System.Int32" + } + ], + "ReturnType": "Microsoft.AspNetCore.Rewrite.RewriteOptions", + "Static": true, + "Extension": true, + "Visibility": "Public", + "GenericParameter": [] } ], "GenericParameters": [] @@ -597,5319 +646,6 @@ } ], "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Rewrite.Internal.BackReferenceCollection", - "Visibility": "Public", - "Kind": "Class", - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Method", - "Name": "get_Item", - "Parameters": [ - { - "Name": "index", - "Type": "System.Int32" - } - ], - "ReturnType": "System.String", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "Add", - "Parameters": [ - { - "Name": "references", - "Type": "Microsoft.AspNetCore.Rewrite.Internal.BackReferenceCollection" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [ - { - "Name": "references", - "Type": "System.Text.RegularExpressions.GroupCollection" - } - ], - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [ - { - "Name": "reference", - "Type": "System.String" - } - ], - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Rewrite.Internal.DelegateRule", - "Visibility": "Public", - "Kind": "Class", - "ImplementedInterfaces": [ - "Microsoft.AspNetCore.Rewrite.IRule" - ], - "Members": [ - { - "Kind": "Method", - "Name": "ApplyRule", - "Parameters": [ - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Rewrite.RewriteContext" - } - ], - "ReturnType": "System.Void", - "Sealed": true, - "Virtual": true, - "ImplementedInterface": "Microsoft.AspNetCore.Rewrite.IRule", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [ - { - "Name": "onApplyRule", - "Type": "System.Action" - } - ], - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Rewrite.Internal.MatchResults", - "Visibility": "Public", - "Kind": "Class", - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Method", - "Name": "get_Success", - "Parameters": [], - "ReturnType": "System.Boolean", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_Success", - "Parameters": [ - { - "Name": "value", - "Type": "System.Boolean" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_BackReferences", - "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Rewrite.Internal.BackReferenceCollection", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_BackReferences", - "Parameters": [ - { - "Name": "value", - "Type": "Microsoft.AspNetCore.Rewrite.Internal.BackReferenceCollection" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [], - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Field", - "Name": "EmptySuccess", - "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Rewrite.Internal.MatchResults", - "Static": true, - "ReadOnly": true, - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Field", - "Name": "EmptyFailure", - "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Rewrite.Internal.MatchResults", - "Static": true, - "ReadOnly": true, - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Rewrite.Internal.ParserContext", - "Visibility": "Public", - "Kind": "Class", - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Method", - "Name": "get_Index", - "Parameters": [], - "ReturnType": "System.Int32", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_Index", - "Parameters": [ - { - "Name": "value", - "Type": "System.Int32" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_Current", - "Parameters": [], - "ReturnType": "System.Char", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "Back", - "Parameters": [], - "ReturnType": "System.Boolean", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "Next", - "Parameters": [], - "ReturnType": "System.Boolean", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "HasNext", - "Parameters": [], - "ReturnType": "System.Boolean", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "Mark", - "Parameters": [], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "GetIndex", - "Parameters": [], - "ReturnType": "System.Int32", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "Capture", - "Parameters": [], - "ReturnType": "System.String", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [ - { - "Name": "condition", - "Type": "System.String" - } - ], - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Field", - "Name": "Template", - "Parameters": [], - "ReturnType": "System.String", - "ReadOnly": true, - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Rewrite.Internal.Pattern", - "Visibility": "Public", - "Kind": "Class", - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Method", - "Name": "get_PatternSegments", - "Parameters": [], - "ReturnType": "System.Collections.Generic.IList", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "Evaluate", - "Parameters": [ - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Rewrite.RewriteContext" - }, - { - "Name": "ruleBackReferences", - "Type": "Microsoft.AspNetCore.Rewrite.Internal.BackReferenceCollection" - }, - { - "Name": "conditionBackReferences", - "Type": "Microsoft.AspNetCore.Rewrite.Internal.BackReferenceCollection" - } - ], - "ReturnType": "System.String", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [ - { - "Name": "patternSegments", - "Type": "System.Collections.Generic.IList" - } - ], - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Rewrite.Internal.PatternSegment", - "Visibility": "Public", - "Kind": "Class", - "Abstract": true, - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Method", - "Name": "Evaluate", - "Parameters": [ - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Rewrite.RewriteContext" - }, - { - "Name": "ruleBackReferences", - "Type": "Microsoft.AspNetCore.Rewrite.Internal.BackReferenceCollection" - }, - { - "Name": "conditionBackReferences", - "Type": "Microsoft.AspNetCore.Rewrite.Internal.BackReferenceCollection" - } - ], - "ReturnType": "System.String", - "Virtual": true, - "Abstract": true, - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [], - "Visibility": "Protected", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Rewrite.Internal.RedirectRule", - "Visibility": "Public", - "Kind": "Class", - "ImplementedInterfaces": [ - "Microsoft.AspNetCore.Rewrite.IRule" - ], - "Members": [ - { - "Kind": "Method", - "Name": "get_InitialMatch", - "Parameters": [], - "ReturnType": "System.Text.RegularExpressions.Regex", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_Replacement", - "Parameters": [], - "ReturnType": "System.String", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_StatusCode", - "Parameters": [], - "ReturnType": "System.Int32", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "ApplyRule", - "Parameters": [ - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Rewrite.RewriteContext" - } - ], - "ReturnType": "System.Void", - "Virtual": true, - "ImplementedInterface": "Microsoft.AspNetCore.Rewrite.IRule", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [ - { - "Name": "regex", - "Type": "System.String" - }, - { - "Name": "replacement", - "Type": "System.String" - }, - { - "Name": "statusCode", - "Type": "System.Int32" - } - ], - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Rewrite.Internal.RedirectToHttpsRule", - "Visibility": "Public", - "Kind": "Class", - "ImplementedInterfaces": [ - "Microsoft.AspNetCore.Rewrite.IRule" - ], - "Members": [ - { - "Kind": "Method", - "Name": "get_SSLPort", - "Parameters": [], - "ReturnType": "System.Nullable", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_SSLPort", - "Parameters": [ - { - "Name": "value", - "Type": "System.Nullable" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_StatusCode", - "Parameters": [], - "ReturnType": "System.Int32", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_StatusCode", - "Parameters": [ - { - "Name": "value", - "Type": "System.Int32" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "ApplyRule", - "Parameters": [ - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Rewrite.RewriteContext" - } - ], - "ReturnType": "System.Void", - "Virtual": true, - "ImplementedInterface": "Microsoft.AspNetCore.Rewrite.IRule", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [], - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Rewrite.Internal.RewriteRule", - "Visibility": "Public", - "Kind": "Class", - "ImplementedInterfaces": [ - "Microsoft.AspNetCore.Rewrite.IRule" - ], - "Members": [ - { - "Kind": "Method", - "Name": "get_InitialMatch", - "Parameters": [], - "ReturnType": "System.Text.RegularExpressions.Regex", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_Replacement", - "Parameters": [], - "ReturnType": "System.String", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_StopProcessing", - "Parameters": [], - "ReturnType": "System.Boolean", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "ApplyRule", - "Parameters": [ - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Rewrite.RewriteContext" - } - ], - "ReturnType": "System.Void", - "Virtual": true, - "ImplementedInterface": "Microsoft.AspNetCore.Rewrite.IRule", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [ - { - "Name": "regex", - "Type": "System.String" - }, - { - "Name": "replacement", - "Type": "System.String" - }, - { - "Name": "stopProcessing", - "Type": "System.Boolean" - } - ], - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Rewrite.Internal.UrlAction", - "Visibility": "Public", - "Kind": "Class", - "Abstract": true, - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Method", - "Name": "get_Url", - "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Rewrite.Internal.Pattern", - "Visibility": "Protected", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_Url", - "Parameters": [ - { - "Name": "value", - "Type": "Microsoft.AspNetCore.Rewrite.Internal.Pattern" - } - ], - "ReturnType": "System.Void", - "Visibility": "Protected", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "ApplyAction", - "Parameters": [ - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Rewrite.RewriteContext" - }, - { - "Name": "ruleBackReferences", - "Type": "Microsoft.AspNetCore.Rewrite.Internal.BackReferenceCollection" - }, - { - "Name": "conditionBackReferences", - "Type": "Microsoft.AspNetCore.Rewrite.Internal.BackReferenceCollection" - } - ], - "ReturnType": "System.Void", - "Virtual": true, - "Abstract": true, - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [], - "Visibility": "Protected", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Rewrite.Internal.UrlMatch", - "Visibility": "Public", - "Kind": "Class", - "Abstract": true, - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Method", - "Name": "get_Negate", - "Parameters": [], - "ReturnType": "System.Boolean", - "Visibility": "Protected", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_Negate", - "Parameters": [ - { - "Name": "value", - "Type": "System.Boolean" - } - ], - "ReturnType": "System.Void", - "Visibility": "Protected", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "Evaluate", - "Parameters": [ - { - "Name": "input", - "Type": "System.String" - }, - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Rewrite.RewriteContext" - } - ], - "ReturnType": "Microsoft.AspNetCore.Rewrite.Internal.MatchResults", - "Virtual": true, - "Abstract": true, - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [], - "Visibility": "Protected", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Rewrite.Internal.UrlMatches.ExactMatch", - "Visibility": "Public", - "Kind": "Class", - "BaseType": "Microsoft.AspNetCore.Rewrite.Internal.UrlMatch", - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Method", - "Name": "Evaluate", - "Parameters": [ - { - "Name": "pattern", - "Type": "System.String" - }, - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Rewrite.RewriteContext" - } - ], - "ReturnType": "Microsoft.AspNetCore.Rewrite.Internal.MatchResults", - "Virtual": true, - "Override": true, - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [ - { - "Name": "ignoreCase", - "Type": "System.Boolean" - }, - { - "Name": "input", - "Type": "System.String" - }, - { - "Name": "negate", - "Type": "System.Boolean" - } - ], - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Rewrite.Internal.UrlMatches.FileSizeMatch", - "Visibility": "Public", - "Kind": "Class", - "BaseType": "Microsoft.AspNetCore.Rewrite.Internal.UrlMatch", - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Method", - "Name": "Evaluate", - "Parameters": [ - { - "Name": "input", - "Type": "System.String" - }, - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Rewrite.RewriteContext" - } - ], - "ReturnType": "Microsoft.AspNetCore.Rewrite.Internal.MatchResults", - "Virtual": true, - "Override": true, - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [ - { - "Name": "negate", - "Type": "System.Boolean" - } - ], - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Rewrite.Internal.UrlMatches.IntegerMatch", - "Visibility": "Public", - "Kind": "Class", - "BaseType": "Microsoft.AspNetCore.Rewrite.Internal.UrlMatch", - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Method", - "Name": "Evaluate", - "Parameters": [ - { - "Name": "input", - "Type": "System.String" - }, - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Rewrite.RewriteContext" - } - ], - "ReturnType": "Microsoft.AspNetCore.Rewrite.Internal.MatchResults", - "Virtual": true, - "Override": true, - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [ - { - "Name": "value", - "Type": "System.Int32" - }, - { - "Name": "operation", - "Type": "Microsoft.AspNetCore.Rewrite.Internal.UrlMatches.IntegerOperationType" - } - ], - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [ - { - "Name": "value", - "Type": "System.String" - }, - { - "Name": "operation", - "Type": "Microsoft.AspNetCore.Rewrite.Internal.UrlMatches.IntegerOperationType" - } - ], - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Rewrite.Internal.UrlMatches.IntegerOperationType", - "Visibility": "Public", - "Kind": "Enumeration", - "Sealed": true, - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Field", - "Name": "Equal", - "Parameters": [], - "GenericParameter": [], - "Literal": "0" - }, - { - "Kind": "Field", - "Name": "Greater", - "Parameters": [], - "GenericParameter": [], - "Literal": "1" - }, - { - "Kind": "Field", - "Name": "GreaterEqual", - "Parameters": [], - "GenericParameter": [], - "Literal": "2" - }, - { - "Kind": "Field", - "Name": "Less", - "Parameters": [], - "GenericParameter": [], - "Literal": "3" - }, - { - "Kind": "Field", - "Name": "LessEqual", - "Parameters": [], - "GenericParameter": [], - "Literal": "4" - }, - { - "Kind": "Field", - "Name": "NotEqual", - "Parameters": [], - "GenericParameter": [], - "Literal": "5" - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Rewrite.Internal.UrlMatches.IsDirectoryMatch", - "Visibility": "Public", - "Kind": "Class", - "BaseType": "Microsoft.AspNetCore.Rewrite.Internal.UrlMatch", - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Method", - "Name": "Evaluate", - "Parameters": [ - { - "Name": "pattern", - "Type": "System.String" - }, - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Rewrite.RewriteContext" - } - ], - "ReturnType": "Microsoft.AspNetCore.Rewrite.Internal.MatchResults", - "Virtual": true, - "Override": true, - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [ - { - "Name": "negate", - "Type": "System.Boolean" - } - ], - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Rewrite.Internal.UrlMatches.IsFileMatch", - "Visibility": "Public", - "Kind": "Class", - "BaseType": "Microsoft.AspNetCore.Rewrite.Internal.UrlMatch", - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Method", - "Name": "Evaluate", - "Parameters": [ - { - "Name": "pattern", - "Type": "System.String" - }, - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Rewrite.RewriteContext" - } - ], - "ReturnType": "Microsoft.AspNetCore.Rewrite.Internal.MatchResults", - "Virtual": true, - "Override": true, - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [ - { - "Name": "negate", - "Type": "System.Boolean" - } - ], - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Rewrite.Internal.UrlMatches.RegexMatch", - "Visibility": "Public", - "Kind": "Class", - "BaseType": "Microsoft.AspNetCore.Rewrite.Internal.UrlMatch", - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Method", - "Name": "Evaluate", - "Parameters": [ - { - "Name": "pattern", - "Type": "System.String" - }, - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Rewrite.RewriteContext" - } - ], - "ReturnType": "Microsoft.AspNetCore.Rewrite.Internal.MatchResults", - "Virtual": true, - "Override": true, - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [ - { - "Name": "match", - "Type": "System.Text.RegularExpressions.Regex" - }, - { - "Name": "negate", - "Type": "System.Boolean" - } - ], - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Rewrite.Internal.UrlMatches.StringMatch", - "Visibility": "Public", - "Kind": "Class", - "BaseType": "Microsoft.AspNetCore.Rewrite.Internal.UrlMatch", - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Method", - "Name": "Evaluate", - "Parameters": [ - { - "Name": "input", - "Type": "System.String" - }, - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Rewrite.RewriteContext" - } - ], - "ReturnType": "Microsoft.AspNetCore.Rewrite.Internal.MatchResults", - "Virtual": true, - "Override": true, - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [ - { - "Name": "value", - "Type": "System.String" - }, - { - "Name": "operation", - "Type": "Microsoft.AspNetCore.Rewrite.Internal.UrlMatches.StringOperationType" - }, - { - "Name": "ignoreCase", - "Type": "System.Boolean" - } - ], - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Rewrite.Internal.UrlMatches.StringOperationType", - "Visibility": "Public", - "Kind": "Enumeration", - "Sealed": true, - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Field", - "Name": "Equal", - "Parameters": [], - "GenericParameter": [], - "Literal": "0" - }, - { - "Kind": "Field", - "Name": "Greater", - "Parameters": [], - "GenericParameter": [], - "Literal": "1" - }, - { - "Kind": "Field", - "Name": "GreaterEqual", - "Parameters": [], - "GenericParameter": [], - "Literal": "2" - }, - { - "Kind": "Field", - "Name": "Less", - "Parameters": [], - "GenericParameter": [], - "Literal": "3" - }, - { - "Kind": "Field", - "Name": "LessEqual", - "Parameters": [], - "GenericParameter": [], - "Literal": "4" - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Rewrite.Internal.UrlActions.AbortAction", - "Visibility": "Public", - "Kind": "Class", - "BaseType": "Microsoft.AspNetCore.Rewrite.Internal.UrlAction", - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Method", - "Name": "ApplyAction", - "Parameters": [ - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Rewrite.RewriteContext" - }, - { - "Name": "ruleBackReferences", - "Type": "Microsoft.AspNetCore.Rewrite.Internal.BackReferenceCollection" - }, - { - "Name": "conditionBackReferences", - "Type": "Microsoft.AspNetCore.Rewrite.Internal.BackReferenceCollection" - } - ], - "ReturnType": "System.Void", - "Virtual": true, - "Override": true, - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [], - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Rewrite.Internal.UrlActions.ChangeCookieAction", - "Visibility": "Public", - "Kind": "Class", - "BaseType": "Microsoft.AspNetCore.Rewrite.Internal.UrlAction", - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Method", - "Name": "get_Name", - "Parameters": [], - "ReturnType": "System.String", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_Value", - "Parameters": [], - "ReturnType": "System.String", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_Value", - "Parameters": [ - { - "Name": "value", - "Type": "System.String" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_Domain", - "Parameters": [], - "ReturnType": "System.String", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_Domain", - "Parameters": [ - { - "Name": "value", - "Type": "System.String" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_Lifetime", - "Parameters": [], - "ReturnType": "System.TimeSpan", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_Lifetime", - "Parameters": [ - { - "Name": "value", - "Type": "System.TimeSpan" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_Path", - "Parameters": [], - "ReturnType": "System.String", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_Path", - "Parameters": [ - { - "Name": "value", - "Type": "System.String" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_Secure", - "Parameters": [], - "ReturnType": "System.Boolean", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_Secure", - "Parameters": [ - { - "Name": "value", - "Type": "System.Boolean" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_HttpOnly", - "Parameters": [], - "ReturnType": "System.Boolean", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_HttpOnly", - "Parameters": [ - { - "Name": "value", - "Type": "System.Boolean" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "ApplyAction", - "Parameters": [ - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Rewrite.RewriteContext" - }, - { - "Name": "ruleBackReferences", - "Type": "Microsoft.AspNetCore.Rewrite.Internal.BackReferenceCollection" - }, - { - "Name": "conditionBackReferences", - "Type": "Microsoft.AspNetCore.Rewrite.Internal.BackReferenceCollection" - } - ], - "ReturnType": "System.Void", - "Virtual": true, - "Override": true, - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [ - { - "Name": "name", - "Type": "System.String" - } - ], - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Rewrite.Internal.UrlActions.CustomResponseAction", - "Visibility": "Public", - "Kind": "Class", - "BaseType": "Microsoft.AspNetCore.Rewrite.Internal.UrlAction", - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Method", - "Name": "get_StatusCode", - "Parameters": [], - "ReturnType": "System.Int32", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_StatusReason", - "Parameters": [], - "ReturnType": "System.String", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_StatusReason", - "Parameters": [ - { - "Name": "value", - "Type": "System.String" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_StatusDescription", - "Parameters": [], - "ReturnType": "System.String", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_StatusDescription", - "Parameters": [ - { - "Name": "value", - "Type": "System.String" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "ApplyAction", - "Parameters": [ - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Rewrite.RewriteContext" - }, - { - "Name": "ruleBackReferences", - "Type": "Microsoft.AspNetCore.Rewrite.Internal.BackReferenceCollection" - }, - { - "Name": "conditionBackReferences", - "Type": "Microsoft.AspNetCore.Rewrite.Internal.BackReferenceCollection" - } - ], - "ReturnType": "System.Void", - "Virtual": true, - "Override": true, - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [ - { - "Name": "statusCode", - "Type": "System.Int32" - } - ], - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Rewrite.Internal.UrlActions.ForbiddenAction", - "Visibility": "Public", - "Kind": "Class", - "BaseType": "Microsoft.AspNetCore.Rewrite.Internal.UrlAction", - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Method", - "Name": "ApplyAction", - "Parameters": [ - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Rewrite.RewriteContext" - }, - { - "Name": "ruleBackReferences", - "Type": "Microsoft.AspNetCore.Rewrite.Internal.BackReferenceCollection" - }, - { - "Name": "conditionBackReferences", - "Type": "Microsoft.AspNetCore.Rewrite.Internal.BackReferenceCollection" - } - ], - "ReturnType": "System.Void", - "Virtual": true, - "Override": true, - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [], - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Rewrite.Internal.UrlActions.GoneAction", - "Visibility": "Public", - "Kind": "Class", - "BaseType": "Microsoft.AspNetCore.Rewrite.Internal.UrlAction", - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Method", - "Name": "ApplyAction", - "Parameters": [ - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Rewrite.RewriteContext" - }, - { - "Name": "ruleBackReferences", - "Type": "Microsoft.AspNetCore.Rewrite.Internal.BackReferenceCollection" - }, - { - "Name": "conditionBackReferences", - "Type": "Microsoft.AspNetCore.Rewrite.Internal.BackReferenceCollection" - } - ], - "ReturnType": "System.Void", - "Virtual": true, - "Override": true, - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [], - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Rewrite.Internal.UrlActions.NoneAction", - "Visibility": "Public", - "Kind": "Class", - "BaseType": "Microsoft.AspNetCore.Rewrite.Internal.UrlAction", - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Method", - "Name": "get_Result", - "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Rewrite.RuleResult", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "ApplyAction", - "Parameters": [ - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Rewrite.RewriteContext" - }, - { - "Name": "ruleBackReferences", - "Type": "Microsoft.AspNetCore.Rewrite.Internal.BackReferenceCollection" - }, - { - "Name": "conditionBackReferences", - "Type": "Microsoft.AspNetCore.Rewrite.Internal.BackReferenceCollection" - } - ], - "ReturnType": "System.Void", - "Virtual": true, - "Override": true, - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [ - { - "Name": "result", - "Type": "Microsoft.AspNetCore.Rewrite.RuleResult" - } - ], - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Rewrite.Internal.UrlActions.RedirectAction", - "Visibility": "Public", - "Kind": "Class", - "BaseType": "Microsoft.AspNetCore.Rewrite.Internal.UrlAction", - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Method", - "Name": "get_StatusCode", - "Parameters": [], - "ReturnType": "System.Int32", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_QueryStringAppend", - "Parameters": [], - "ReturnType": "System.Boolean", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_QueryStringDelete", - "Parameters": [], - "ReturnType": "System.Boolean", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_EscapeBackReferences", - "Parameters": [], - "ReturnType": "System.Boolean", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "ApplyAction", - "Parameters": [ - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Rewrite.RewriteContext" - }, - { - "Name": "ruleBackReferences", - "Type": "Microsoft.AspNetCore.Rewrite.Internal.BackReferenceCollection" - }, - { - "Name": "conditionBackReferences", - "Type": "Microsoft.AspNetCore.Rewrite.Internal.BackReferenceCollection" - } - ], - "ReturnType": "System.Void", - "Virtual": true, - "Override": true, - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [ - { - "Name": "statusCode", - "Type": "System.Int32" - }, - { - "Name": "pattern", - "Type": "Microsoft.AspNetCore.Rewrite.Internal.Pattern" - }, - { - "Name": "queryStringAppend", - "Type": "System.Boolean" - }, - { - "Name": "queryStringDelete", - "Type": "System.Boolean" - }, - { - "Name": "escapeBackReferences", - "Type": "System.Boolean" - } - ], - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [ - { - "Name": "statusCode", - "Type": "System.Int32" - }, - { - "Name": "pattern", - "Type": "Microsoft.AspNetCore.Rewrite.Internal.Pattern" - }, - { - "Name": "queryStringAppend", - "Type": "System.Boolean" - } - ], - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Rewrite.Internal.UrlActions.RewriteAction", - "Visibility": "Public", - "Kind": "Class", - "BaseType": "Microsoft.AspNetCore.Rewrite.Internal.UrlAction", - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Method", - "Name": "get_Result", - "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Rewrite.RuleResult", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_QueryStringAppend", - "Parameters": [], - "ReturnType": "System.Boolean", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_QueryStringDelete", - "Parameters": [], - "ReturnType": "System.Boolean", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_EscapeBackReferences", - "Parameters": [], - "ReturnType": "System.Boolean", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "ApplyAction", - "Parameters": [ - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Rewrite.RewriteContext" - }, - { - "Name": "ruleBackReferences", - "Type": "Microsoft.AspNetCore.Rewrite.Internal.BackReferenceCollection" - }, - { - "Name": "conditionBackReferences", - "Type": "Microsoft.AspNetCore.Rewrite.Internal.BackReferenceCollection" - } - ], - "ReturnType": "System.Void", - "Virtual": true, - "Override": true, - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [ - { - "Name": "result", - "Type": "Microsoft.AspNetCore.Rewrite.RuleResult" - }, - { - "Name": "pattern", - "Type": "Microsoft.AspNetCore.Rewrite.Internal.Pattern" - }, - { - "Name": "queryStringAppend", - "Type": "System.Boolean" - }, - { - "Name": "queryStringDelete", - "Type": "System.Boolean" - }, - { - "Name": "escapeBackReferences", - "Type": "System.Boolean" - } - ], - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [ - { - "Name": "result", - "Type": "Microsoft.AspNetCore.Rewrite.RuleResult" - }, - { - "Name": "pattern", - "Type": "Microsoft.AspNetCore.Rewrite.Internal.Pattern" - }, - { - "Name": "queryStringAppend", - "Type": "System.Boolean" - } - ], - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Rewrite.Internal.PatternSegments.ConditionMatchSegment", - "Visibility": "Public", - "Kind": "Class", - "BaseType": "Microsoft.AspNetCore.Rewrite.Internal.PatternSegment", - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Method", - "Name": "Evaluate", - "Parameters": [ - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Rewrite.RewriteContext" - }, - { - "Name": "ruleBackReferences", - "Type": "Microsoft.AspNetCore.Rewrite.Internal.BackReferenceCollection" - }, - { - "Name": "conditionBackReferences", - "Type": "Microsoft.AspNetCore.Rewrite.Internal.BackReferenceCollection" - } - ], - "ReturnType": "System.String", - "Virtual": true, - "Override": true, - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [ - { - "Name": "index", - "Type": "System.Int32" - } - ], - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Rewrite.Internal.PatternSegments.DateTimeSegment", - "Visibility": "Public", - "Kind": "Class", - "BaseType": "Microsoft.AspNetCore.Rewrite.Internal.PatternSegment", - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Method", - "Name": "Evaluate", - "Parameters": [ - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Rewrite.RewriteContext" - }, - { - "Name": "ruleBackReferences", - "Type": "Microsoft.AspNetCore.Rewrite.Internal.BackReferenceCollection" - }, - { - "Name": "conditionBackReference", - "Type": "Microsoft.AspNetCore.Rewrite.Internal.BackReferenceCollection" - } - ], - "ReturnType": "System.String", - "Virtual": true, - "Override": true, - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [ - { - "Name": "segment", - "Type": "System.String" - } - ], - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Rewrite.Internal.PatternSegments.HeaderSegment", - "Visibility": "Public", - "Kind": "Class", - "BaseType": "Microsoft.AspNetCore.Rewrite.Internal.PatternSegment", - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Method", - "Name": "Evaluate", - "Parameters": [ - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Rewrite.RewriteContext" - }, - { - "Name": "ruleBackReferences", - "Type": "Microsoft.AspNetCore.Rewrite.Internal.BackReferenceCollection" - }, - { - "Name": "conditionBackReferences", - "Type": "Microsoft.AspNetCore.Rewrite.Internal.BackReferenceCollection" - } - ], - "ReturnType": "System.String", - "Virtual": true, - "Override": true, - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [ - { - "Name": "header", - "Type": "System.String" - } - ], - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Rewrite.Internal.PatternSegments.IsHttpsModSegment", - "Visibility": "Public", - "Kind": "Class", - "BaseType": "Microsoft.AspNetCore.Rewrite.Internal.PatternSegment", - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Method", - "Name": "Evaluate", - "Parameters": [ - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Rewrite.RewriteContext" - }, - { - "Name": "ruleBackReferences", - "Type": "Microsoft.AspNetCore.Rewrite.Internal.BackReferenceCollection" - }, - { - "Name": "conditionBackReferences", - "Type": "Microsoft.AspNetCore.Rewrite.Internal.BackReferenceCollection" - } - ], - "ReturnType": "System.String", - "Virtual": true, - "Override": true, - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [], - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Rewrite.Internal.PatternSegments.IsHttpsUrlSegment", - "Visibility": "Public", - "Kind": "Class", - "BaseType": "Microsoft.AspNetCore.Rewrite.Internal.PatternSegment", - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Method", - "Name": "Evaluate", - "Parameters": [ - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Rewrite.RewriteContext" - }, - { - "Name": "ruleBackReferences", - "Type": "Microsoft.AspNetCore.Rewrite.Internal.BackReferenceCollection" - }, - { - "Name": "conditionBackReferences", - "Type": "Microsoft.AspNetCore.Rewrite.Internal.BackReferenceCollection" - } - ], - "ReturnType": "System.String", - "Virtual": true, - "Override": true, - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [], - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Rewrite.Internal.PatternSegments.IsIPV6Segment", - "Visibility": "Public", - "Kind": "Class", - "BaseType": "Microsoft.AspNetCore.Rewrite.Internal.PatternSegment", - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Method", - "Name": "Evaluate", - "Parameters": [ - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Rewrite.RewriteContext" - }, - { - "Name": "ruleBackReferences", - "Type": "Microsoft.AspNetCore.Rewrite.Internal.BackReferenceCollection" - }, - { - "Name": "conditionBackReferences", - "Type": "Microsoft.AspNetCore.Rewrite.Internal.BackReferenceCollection" - } - ], - "ReturnType": "System.String", - "Virtual": true, - "Override": true, - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [], - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Rewrite.Internal.PatternSegments.LiteralSegment", - "Visibility": "Public", - "Kind": "Class", - "BaseType": "Microsoft.AspNetCore.Rewrite.Internal.PatternSegment", - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Method", - "Name": "Evaluate", - "Parameters": [ - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Rewrite.RewriteContext" - }, - { - "Name": "ruleBackReferences", - "Type": "Microsoft.AspNetCore.Rewrite.Internal.BackReferenceCollection" - }, - { - "Name": "conditionBackReferences", - "Type": "Microsoft.AspNetCore.Rewrite.Internal.BackReferenceCollection" - } - ], - "ReturnType": "System.String", - "Virtual": true, - "Override": true, - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [ - { - "Name": "literal", - "Type": "System.String" - } - ], - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Rewrite.Internal.PatternSegments.LocalAddressSegment", - "Visibility": "Public", - "Kind": "Class", - "BaseType": "Microsoft.AspNetCore.Rewrite.Internal.PatternSegment", - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Method", - "Name": "Evaluate", - "Parameters": [ - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Rewrite.RewriteContext" - }, - { - "Name": "ruleBackReferences", - "Type": "Microsoft.AspNetCore.Rewrite.Internal.BackReferenceCollection" - }, - { - "Name": "conditionBackReferences", - "Type": "Microsoft.AspNetCore.Rewrite.Internal.BackReferenceCollection" - } - ], - "ReturnType": "System.String", - "Virtual": true, - "Override": true, - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [], - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Rewrite.Internal.PatternSegments.LocalPortSegment", - "Visibility": "Public", - "Kind": "Class", - "BaseType": "Microsoft.AspNetCore.Rewrite.Internal.PatternSegment", - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Method", - "Name": "Evaluate", - "Parameters": [ - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Rewrite.RewriteContext" - }, - { - "Name": "ruleBackReferences", - "Type": "Microsoft.AspNetCore.Rewrite.Internal.BackReferenceCollection" - }, - { - "Name": "conditionBackReferences", - "Type": "Microsoft.AspNetCore.Rewrite.Internal.BackReferenceCollection" - } - ], - "ReturnType": "System.String", - "Virtual": true, - "Override": true, - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [], - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Rewrite.Internal.PatternSegments.QueryStringSegment", - "Visibility": "Public", - "Kind": "Class", - "BaseType": "Microsoft.AspNetCore.Rewrite.Internal.PatternSegment", - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Method", - "Name": "Evaluate", - "Parameters": [ - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Rewrite.RewriteContext" - }, - { - "Name": "ruleBackRefernces", - "Type": "Microsoft.AspNetCore.Rewrite.Internal.BackReferenceCollection" - }, - { - "Name": "conditionBackReferences", - "Type": "Microsoft.AspNetCore.Rewrite.Internal.BackReferenceCollection" - } - ], - "ReturnType": "System.String", - "Virtual": true, - "Override": true, - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [], - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Rewrite.Internal.PatternSegments.RemoteAddressSegment", - "Visibility": "Public", - "Kind": "Class", - "BaseType": "Microsoft.AspNetCore.Rewrite.Internal.PatternSegment", - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Method", - "Name": "Evaluate", - "Parameters": [ - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Rewrite.RewriteContext" - }, - { - "Name": "ruleBackReferences", - "Type": "Microsoft.AspNetCore.Rewrite.Internal.BackReferenceCollection" - }, - { - "Name": "conditionBackReferences", - "Type": "Microsoft.AspNetCore.Rewrite.Internal.BackReferenceCollection" - } - ], - "ReturnType": "System.String", - "Virtual": true, - "Override": true, - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [], - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Rewrite.Internal.PatternSegments.RemotePortSegment", - "Visibility": "Public", - "Kind": "Class", - "BaseType": "Microsoft.AspNetCore.Rewrite.Internal.PatternSegment", - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Method", - "Name": "Evaluate", - "Parameters": [ - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Rewrite.RewriteContext" - }, - { - "Name": "ruleBackReferences", - "Type": "Microsoft.AspNetCore.Rewrite.Internal.BackReferenceCollection" - }, - { - "Name": "conditionBackReferences", - "Type": "Microsoft.AspNetCore.Rewrite.Internal.BackReferenceCollection" - } - ], - "ReturnType": "System.String", - "Virtual": true, - "Override": true, - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [], - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Rewrite.Internal.PatternSegments.RequestFileNameSegment", - "Visibility": "Public", - "Kind": "Class", - "BaseType": "Microsoft.AspNetCore.Rewrite.Internal.PatternSegment", - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Method", - "Name": "Evaluate", - "Parameters": [ - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Rewrite.RewriteContext" - }, - { - "Name": "ruleBackReferences", - "Type": "Microsoft.AspNetCore.Rewrite.Internal.BackReferenceCollection" - }, - { - "Name": "conditionBackReferences", - "Type": "Microsoft.AspNetCore.Rewrite.Internal.BackReferenceCollection" - } - ], - "ReturnType": "System.String", - "Virtual": true, - "Override": true, - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [], - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Rewrite.Internal.PatternSegments.RequestMethodSegment", - "Visibility": "Public", - "Kind": "Class", - "BaseType": "Microsoft.AspNetCore.Rewrite.Internal.PatternSegment", - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Method", - "Name": "Evaluate", - "Parameters": [ - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Rewrite.RewriteContext" - }, - { - "Name": "ruleBackReferences", - "Type": "Microsoft.AspNetCore.Rewrite.Internal.BackReferenceCollection" - }, - { - "Name": "conditionBackReferences", - "Type": "Microsoft.AspNetCore.Rewrite.Internal.BackReferenceCollection" - } - ], - "ReturnType": "System.String", - "Virtual": true, - "Override": true, - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [], - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Rewrite.Internal.PatternSegments.RewriteMapSegment", - "Visibility": "Public", - "Kind": "Class", - "BaseType": "Microsoft.AspNetCore.Rewrite.Internal.PatternSegment", - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Method", - "Name": "Evaluate", - "Parameters": [ - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Rewrite.RewriteContext" - }, - { - "Name": "ruleBackReferences", - "Type": "Microsoft.AspNetCore.Rewrite.Internal.BackReferenceCollection" - }, - { - "Name": "conditionBackReferences", - "Type": "Microsoft.AspNetCore.Rewrite.Internal.BackReferenceCollection" - } - ], - "ReturnType": "System.String", - "Virtual": true, - "Override": true, - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [ - { - "Name": "rewriteMap", - "Type": "Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite.IISRewriteMap" - }, - { - "Name": "pattern", - "Type": "Microsoft.AspNetCore.Rewrite.Internal.Pattern" - } - ], - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Rewrite.Internal.PatternSegments.RuleMatchSegment", - "Visibility": "Public", - "Kind": "Class", - "BaseType": "Microsoft.AspNetCore.Rewrite.Internal.PatternSegment", - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Method", - "Name": "Evaluate", - "Parameters": [ - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Rewrite.RewriteContext" - }, - { - "Name": "ruleBackReferences", - "Type": "Microsoft.AspNetCore.Rewrite.Internal.BackReferenceCollection" - }, - { - "Name": "conditionBackReferences", - "Type": "Microsoft.AspNetCore.Rewrite.Internal.BackReferenceCollection" - } - ], - "ReturnType": "System.String", - "Virtual": true, - "Override": true, - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [ - { - "Name": "index", - "Type": "System.Int32" - } - ], - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Rewrite.Internal.PatternSegments.SchemeSegment", - "Visibility": "Public", - "Kind": "Class", - "BaseType": "Microsoft.AspNetCore.Rewrite.Internal.PatternSegment", - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Method", - "Name": "Evaluate", - "Parameters": [ - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Rewrite.RewriteContext" - }, - { - "Name": "ruleBackReferences", - "Type": "Microsoft.AspNetCore.Rewrite.Internal.BackReferenceCollection" - }, - { - "Name": "conditionBackReferences", - "Type": "Microsoft.AspNetCore.Rewrite.Internal.BackReferenceCollection" - } - ], - "ReturnType": "System.String", - "Virtual": true, - "Override": true, - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [], - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Rewrite.Internal.PatternSegments.ServerProtocolSegment", - "Visibility": "Public", - "Kind": "Class", - "BaseType": "Microsoft.AspNetCore.Rewrite.Internal.PatternSegment", - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Method", - "Name": "Evaluate", - "Parameters": [ - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Rewrite.RewriteContext" - }, - { - "Name": "ruleBackReferences", - "Type": "Microsoft.AspNetCore.Rewrite.Internal.BackReferenceCollection" - }, - { - "Name": "conditionBackReferences", - "Type": "Microsoft.AspNetCore.Rewrite.Internal.BackReferenceCollection" - } - ], - "ReturnType": "System.String", - "Virtual": true, - "Override": true, - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [], - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Rewrite.Internal.PatternSegments.ToLowerSegment", - "Visibility": "Public", - "Kind": "Class", - "BaseType": "Microsoft.AspNetCore.Rewrite.Internal.PatternSegment", - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Method", - "Name": "Evaluate", - "Parameters": [ - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Rewrite.RewriteContext" - }, - { - "Name": "ruleBackReferences", - "Type": "Microsoft.AspNetCore.Rewrite.Internal.BackReferenceCollection" - }, - { - "Name": "conditionBackReferences", - "Type": "Microsoft.AspNetCore.Rewrite.Internal.BackReferenceCollection" - } - ], - "ReturnType": "System.String", - "Virtual": true, - "Override": true, - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [ - { - "Name": "pattern", - "Type": "Microsoft.AspNetCore.Rewrite.Internal.Pattern" - } - ], - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Rewrite.Internal.PatternSegments.UrlEncodeSegment", - "Visibility": "Public", - "Kind": "Class", - "BaseType": "Microsoft.AspNetCore.Rewrite.Internal.PatternSegment", - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Method", - "Name": "Evaluate", - "Parameters": [ - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Rewrite.RewriteContext" - }, - { - "Name": "ruleBackReferences", - "Type": "Microsoft.AspNetCore.Rewrite.Internal.BackReferenceCollection" - }, - { - "Name": "conditionBackReferences", - "Type": "Microsoft.AspNetCore.Rewrite.Internal.BackReferenceCollection" - } - ], - "ReturnType": "System.String", - "Virtual": true, - "Override": true, - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [ - { - "Name": "pattern", - "Type": "Microsoft.AspNetCore.Rewrite.Internal.Pattern" - } - ], - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Rewrite.Internal.PatternSegments.UrlSegment", - "Visibility": "Public", - "Kind": "Class", - "BaseType": "Microsoft.AspNetCore.Rewrite.Internal.PatternSegment", - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Method", - "Name": "Evaluate", - "Parameters": [ - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Rewrite.RewriteContext" - }, - { - "Name": "ruleBackReferences", - "Type": "Microsoft.AspNetCore.Rewrite.Internal.BackReferenceCollection" - }, - { - "Name": "conditionBackReferences", - "Type": "Microsoft.AspNetCore.Rewrite.Internal.BackReferenceCollection" - } - ], - "ReturnType": "System.String", - "Virtual": true, - "Override": true, - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [], - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [ - { - "Name": "uriMatchPart", - "Type": "Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite.UriMatchPart" - } - ], - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite.ActionType", - "Visibility": "Public", - "Kind": "Enumeration", - "Sealed": true, - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Field", - "Name": "None", - "Parameters": [], - "GenericParameter": [], - "Literal": "0" - }, - { - "Kind": "Field", - "Name": "Rewrite", - "Parameters": [], - "GenericParameter": [], - "Literal": "1" - }, - { - "Kind": "Field", - "Name": "Redirect", - "Parameters": [], - "GenericParameter": [], - "Literal": "2" - }, - { - "Kind": "Field", - "Name": "CustomResponse", - "Parameters": [], - "GenericParameter": [], - "Literal": "3" - }, - { - "Kind": "Field", - "Name": "AbortRequest", - "Parameters": [], - "GenericParameter": [], - "Literal": "4" - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite.Condition", - "Visibility": "Public", - "Kind": "Class", - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Method", - "Name": "get_Input", - "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Rewrite.Internal.Pattern", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_Input", - "Parameters": [ - { - "Name": "value", - "Type": "Microsoft.AspNetCore.Rewrite.Internal.Pattern" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_Match", - "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Rewrite.Internal.UrlMatch", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_Match", - "Parameters": [ - { - "Name": "value", - "Type": "Microsoft.AspNetCore.Rewrite.Internal.UrlMatch" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "Evaluate", - "Parameters": [ - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Rewrite.RewriteContext" - }, - { - "Name": "ruleBackReferences", - "Type": "Microsoft.AspNetCore.Rewrite.Internal.BackReferenceCollection" - }, - { - "Name": "conditionBackReferences", - "Type": "Microsoft.AspNetCore.Rewrite.Internal.BackReferenceCollection" - } - ], - "ReturnType": "Microsoft.AspNetCore.Rewrite.Internal.MatchResults", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [], - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite.ConditionCollection", - "Visibility": "Public", - "Kind": "Class", - "ImplementedInterfaces": [ - "System.Collections.Generic.IEnumerable" - ], - "Members": [ - { - "Kind": "Method", - "Name": "get_Grouping", - "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite.LogicalGrouping", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_TrackAllCaptures", - "Parameters": [], - "ReturnType": "System.Boolean", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_Count", - "Parameters": [], - "ReturnType": "System.Int32", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_Item", - "Parameters": [ - { - "Name": "index", - "Type": "System.Int32" - } - ], - "ReturnType": "Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite.Condition", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "Add", - "Parameters": [ - { - "Name": "condition", - "Type": "Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite.Condition" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "AddConditions", - "Parameters": [ - { - "Name": "conditions", - "Type": "System.Collections.Generic.IEnumerable" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "GetEnumerator", - "Parameters": [], - "ReturnType": "System.Collections.Generic.IEnumerator", - "Sealed": true, - "Virtual": true, - "ImplementedInterface": "System.Collections.Generic.IEnumerable", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [], - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [ - { - "Name": "grouping", - "Type": "Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite.LogicalGrouping" - }, - { - "Name": "trackAllCaptures", - "Type": "System.Boolean" - } - ], - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite.ConditionEvaluator", - "Visibility": "Public", - "Kind": "Class", - "Abstract": true, - "Static": true, - "Sealed": true, - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Method", - "Name": "Evaluate", - "Parameters": [ - { - "Name": "conditions", - "Type": "Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite.ConditionCollection" - }, - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Rewrite.RewriteContext" - }, - { - "Name": "backReferences", - "Type": "Microsoft.AspNetCore.Rewrite.Internal.BackReferenceCollection" - } - ], - "ReturnType": "Microsoft.AspNetCore.Rewrite.Internal.MatchResults", - "Static": true, - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite.IISRewriteMap", - "Visibility": "Public", - "Kind": "Class", - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Method", - "Name": "get_Name", - "Parameters": [], - "ReturnType": "System.String", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_Item", - "Parameters": [ - { - "Name": "key", - "Type": "System.String" - } - ], - "ReturnType": "System.String", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_Item", - "Parameters": [ - { - "Name": "key", - "Type": "System.String" - }, - { - "Name": "value", - "Type": "System.String" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [ - { - "Name": "name", - "Type": "System.String" - } - ], - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite.IISRewriteMapCollection", - "Visibility": "Public", - "Kind": "Class", - "ImplementedInterfaces": [ - "System.Collections.Generic.IEnumerable" - ], - "Members": [ - { - "Kind": "Method", - "Name": "Add", - "Parameters": [ - { - "Name": "rewriteMap", - "Type": "Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite.IISRewriteMap" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_Count", - "Parameters": [], - "ReturnType": "System.Int32", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_Item", - "Parameters": [ - { - "Name": "key", - "Type": "System.String" - } - ], - "ReturnType": "Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite.IISRewriteMap", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "GetEnumerator", - "Parameters": [], - "ReturnType": "System.Collections.Generic.IEnumerator", - "Sealed": true, - "Virtual": true, - "ImplementedInterface": "System.Collections.Generic.IEnumerable", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [], - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite.IISUrlRewriteRule", - "Visibility": "Public", - "Kind": "Class", - "ImplementedInterfaces": [ - "Microsoft.AspNetCore.Rewrite.IRule" - ], - "Members": [ - { - "Kind": "Method", - "Name": "get_Name", - "Parameters": [], - "ReturnType": "System.String", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_InitialMatch", - "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Rewrite.Internal.UrlMatch", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_Conditions", - "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite.ConditionCollection", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_Action", - "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Rewrite.Internal.UrlAction", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_Global", - "Parameters": [], - "ReturnType": "System.Boolean", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "ApplyRule", - "Parameters": [ - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Rewrite.RewriteContext" - } - ], - "ReturnType": "System.Void", - "Virtual": true, - "ImplementedInterface": "Microsoft.AspNetCore.Rewrite.IRule", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [ - { - "Name": "name", - "Type": "System.String" - }, - { - "Name": "initialMatch", - "Type": "Microsoft.AspNetCore.Rewrite.Internal.UrlMatch" - }, - { - "Name": "conditions", - "Type": "Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite.ConditionCollection" - }, - { - "Name": "action", - "Type": "Microsoft.AspNetCore.Rewrite.Internal.UrlAction" - } - ], - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [ - { - "Name": "name", - "Type": "System.String" - }, - { - "Name": "initialMatch", - "Type": "Microsoft.AspNetCore.Rewrite.Internal.UrlMatch" - }, - { - "Name": "conditions", - "Type": "Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite.ConditionCollection" - }, - { - "Name": "action", - "Type": "Microsoft.AspNetCore.Rewrite.Internal.UrlAction" - }, - { - "Name": "global", - "Type": "System.Boolean" - } - ], - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite.InputParser", - "Visibility": "Public", - "Kind": "Class", - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Method", - "Name": "ParseInputString", - "Parameters": [ - { - "Name": "testString", - "Type": "System.String" - } - ], - "ReturnType": "Microsoft.AspNetCore.Rewrite.Internal.Pattern", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "ParseInputString", - "Parameters": [ - { - "Name": "testString", - "Type": "System.String" - }, - { - "Name": "uriMatchPart", - "Type": "Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite.UriMatchPart" - } - ], - "ReturnType": "Microsoft.AspNetCore.Rewrite.Internal.Pattern", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [], - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [ - { - "Name": "rewriteMaps", - "Type": "Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite.IISRewriteMapCollection" - } - ], - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite.InvalidUrlRewriteFormatException", - "Visibility": "Public", - "Kind": "Class", - "BaseType": "System.FormatException", - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Method", - "Name": "get_LineNumber", - "Parameters": [], - "ReturnType": "System.Int32", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_LinePosition", - "Parameters": [], - "ReturnType": "System.Int32", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [ - { - "Name": "element", - "Type": "System.Xml.Linq.XElement" - }, - { - "Name": "message", - "Type": "System.String" - } - ], - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [ - { - "Name": "element", - "Type": "System.Xml.Linq.XElement" - }, - { - "Name": "message", - "Type": "System.String" - }, - { - "Name": "innerException", - "Type": "System.Exception" - } - ], - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite.LogicalGrouping", - "Visibility": "Public", - "Kind": "Enumeration", - "Sealed": true, - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Field", - "Name": "MatchAll", - "Parameters": [], - "GenericParameter": [], - "Literal": "0" - }, - { - "Kind": "Field", - "Name": "MatchAny", - "Parameters": [], - "GenericParameter": [], - "Literal": "1" - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite.MatchType", - "Visibility": "Public", - "Kind": "Enumeration", - "Sealed": true, - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Field", - "Name": "Pattern", - "Parameters": [], - "GenericParameter": [], - "Literal": "0" - }, - { - "Kind": "Field", - "Name": "IsFile", - "Parameters": [], - "GenericParameter": [], - "Literal": "1" - }, - { - "Kind": "Field", - "Name": "IsDirectory", - "Parameters": [], - "GenericParameter": [], - "Literal": "2" - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite.PatternSyntax", - "Visibility": "Public", - "Kind": "Enumeration", - "Sealed": true, - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Field", - "Name": "ECMAScript", - "Parameters": [], - "GenericParameter": [], - "Literal": "0" - }, - { - "Kind": "Field", - "Name": "Wildcard", - "Parameters": [], - "GenericParameter": [], - "Literal": "1" - }, - { - "Kind": "Field", - "Name": "ExactMatch", - "Parameters": [], - "GenericParameter": [], - "Literal": "2" - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite.RedirectType", - "Visibility": "Public", - "Kind": "Enumeration", - "Sealed": true, - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Field", - "Name": "Permanent", - "Parameters": [], - "GenericParameter": [], - "Literal": "301" - }, - { - "Kind": "Field", - "Name": "Found", - "Parameters": [], - "GenericParameter": [], - "Literal": "302" - }, - { - "Kind": "Field", - "Name": "SeeOther", - "Parameters": [], - "GenericParameter": [], - "Literal": "303" - }, - { - "Kind": "Field", - "Name": "Temporary", - "Parameters": [], - "GenericParameter": [], - "Literal": "307" - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite.RewriteMapParser", - "Visibility": "Public", - "Kind": "Class", - "Abstract": true, - "Static": true, - "Sealed": true, - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Method", - "Name": "Parse", - "Parameters": [ - { - "Name": "xmlRoot", - "Type": "System.Xml.Linq.XElement" - } - ], - "ReturnType": "Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite.IISRewriteMapCollection", - "Static": true, - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite.RewriteTags", - "Visibility": "Public", - "Kind": "Class", - "Abstract": true, - "Static": true, - "Sealed": true, - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Field", - "Name": "Action", - "Parameters": [], - "ReturnType": "System.String", - "Static": true, - "Visibility": "Public", - "GenericParameter": [], - "Constant": true, - "Literal": "\"action\"" - }, - { - "Kind": "Field", - "Name": "Add", - "Parameters": [], - "ReturnType": "System.String", - "Static": true, - "Visibility": "Public", - "GenericParameter": [], - "Constant": true, - "Literal": "\"add\"" - }, - { - "Kind": "Field", - "Name": "AppendQueryString", - "Parameters": [], - "ReturnType": "System.String", - "Static": true, - "Visibility": "Public", - "GenericParameter": [], - "Constant": true, - "Literal": "\"appendQueryString\"" - }, - { - "Kind": "Field", - "Name": "Conditions", - "Parameters": [], - "ReturnType": "System.String", - "Static": true, - "Visibility": "Public", - "GenericParameter": [], - "Constant": true, - "Literal": "\"conditions\"" - }, - { - "Kind": "Field", - "Name": "Enabled", - "Parameters": [], - "ReturnType": "System.String", - "Static": true, - "Visibility": "Public", - "GenericParameter": [], - "Constant": true, - "Literal": "\"enabled\"" - }, - { - "Kind": "Field", - "Name": "GlobalRules", - "Parameters": [], - "ReturnType": "System.String", - "Static": true, - "Visibility": "Public", - "GenericParameter": [], - "Constant": true, - "Literal": "\"globalRules\"" - }, - { - "Kind": "Field", - "Name": "IgnoreCase", - "Parameters": [], - "ReturnType": "System.String", - "Static": true, - "Visibility": "Public", - "GenericParameter": [], - "Constant": true, - "Literal": "\"ignoreCase\"" - }, - { - "Kind": "Field", - "Name": "Input", - "Parameters": [], - "ReturnType": "System.String", - "Static": true, - "Visibility": "Public", - "GenericParameter": [], - "Constant": true, - "Literal": "\"input\"" - }, - { - "Kind": "Field", - "Name": "Key", - "Parameters": [], - "ReturnType": "System.String", - "Static": true, - "Visibility": "Public", - "GenericParameter": [], - "Constant": true, - "Literal": "\"key\"" - }, - { - "Kind": "Field", - "Name": "LogicalGrouping", - "Parameters": [], - "ReturnType": "System.String", - "Static": true, - "Visibility": "Public", - "GenericParameter": [], - "Constant": true, - "Literal": "\"logicalGrouping\"" - }, - { - "Kind": "Field", - "Name": "LogRewrittenUrl", - "Parameters": [], - "ReturnType": "System.String", - "Static": true, - "Visibility": "Public", - "GenericParameter": [], - "Constant": true, - "Literal": "\"logRewrittenUrl\"" - }, - { - "Kind": "Field", - "Name": "Match", - "Parameters": [], - "ReturnType": "System.String", - "Static": true, - "Visibility": "Public", - "GenericParameter": [], - "Constant": true, - "Literal": "\"match\"" - }, - { - "Kind": "Field", - "Name": "MatchPattern", - "Parameters": [], - "ReturnType": "System.String", - "Static": true, - "Visibility": "Public", - "GenericParameter": [], - "Constant": true, - "Literal": "\"matchPattern\"" - }, - { - "Kind": "Field", - "Name": "MatchType", - "Parameters": [], - "ReturnType": "System.String", - "Static": true, - "Visibility": "Public", - "GenericParameter": [], - "Constant": true, - "Literal": "\"matchType\"" - }, - { - "Kind": "Field", - "Name": "Name", - "Parameters": [], - "ReturnType": "System.String", - "Static": true, - "Visibility": "Public", - "GenericParameter": [], - "Constant": true, - "Literal": "\"name\"" - }, - { - "Kind": "Field", - "Name": "Negate", - "Parameters": [], - "ReturnType": "System.String", - "Static": true, - "Visibility": "Public", - "GenericParameter": [], - "Constant": true, - "Literal": "\"negate\"" - }, - { - "Kind": "Field", - "Name": "Pattern", - "Parameters": [], - "ReturnType": "System.String", - "Static": true, - "Visibility": "Public", - "GenericParameter": [], - "Constant": true, - "Literal": "\"pattern\"" - }, - { - "Kind": "Field", - "Name": "PatternSyntax", - "Parameters": [], - "ReturnType": "System.String", - "Static": true, - "Visibility": "Public", - "GenericParameter": [], - "Constant": true, - "Literal": "\"patternSyntax\"" - }, - { - "Kind": "Field", - "Name": "RedirectType", - "Parameters": [], - "ReturnType": "System.String", - "Static": true, - "Visibility": "Public", - "GenericParameter": [], - "Constant": true, - "Literal": "\"redirectType\"" - }, - { - "Kind": "Field", - "Name": "Rewrite", - "Parameters": [], - "ReturnType": "System.String", - "Static": true, - "Visibility": "Public", - "GenericParameter": [], - "Constant": true, - "Literal": "\"rewrite\"" - }, - { - "Kind": "Field", - "Name": "RewriteMap", - "Parameters": [], - "ReturnType": "System.String", - "Static": true, - "Visibility": "Public", - "GenericParameter": [], - "Constant": true, - "Literal": "\"rewriteMap\"" - }, - { - "Kind": "Field", - "Name": "RewriteMaps", - "Parameters": [], - "ReturnType": "System.String", - "Static": true, - "Visibility": "Public", - "GenericParameter": [], - "Constant": true, - "Literal": "\"rewriteMaps\"" - }, - { - "Kind": "Field", - "Name": "Rule", - "Parameters": [], - "ReturnType": "System.String", - "Static": true, - "Visibility": "Public", - "GenericParameter": [], - "Constant": true, - "Literal": "\"rule\"" - }, - { - "Kind": "Field", - "Name": "Rules", - "Parameters": [], - "ReturnType": "System.String", - "Static": true, - "Visibility": "Public", - "GenericParameter": [], - "Constant": true, - "Literal": "\"rules\"" - }, - { - "Kind": "Field", - "Name": "StatusCode", - "Parameters": [], - "ReturnType": "System.String", - "Static": true, - "Visibility": "Public", - "GenericParameter": [], - "Constant": true, - "Literal": "\"statusCode\"" - }, - { - "Kind": "Field", - "Name": "SubStatusCode", - "Parameters": [], - "ReturnType": "System.String", - "Static": true, - "Visibility": "Public", - "GenericParameter": [], - "Constant": true, - "Literal": "\"subStatusCode\"" - }, - { - "Kind": "Field", - "Name": "StatusDescription", - "Parameters": [], - "ReturnType": "System.String", - "Static": true, - "Visibility": "Public", - "GenericParameter": [], - "Constant": true, - "Literal": "\"statusDescription\"" - }, - { - "Kind": "Field", - "Name": "StatusReason", - "Parameters": [], - "ReturnType": "System.String", - "Static": true, - "Visibility": "Public", - "GenericParameter": [], - "Constant": true, - "Literal": "\"statusReason\"" - }, - { - "Kind": "Field", - "Name": "StopProcessing", - "Parameters": [], - "ReturnType": "System.String", - "Static": true, - "Visibility": "Public", - "GenericParameter": [], - "Constant": true, - "Literal": "\"stopProcessing\"" - }, - { - "Kind": "Field", - "Name": "TrackAllCaptures", - "Parameters": [], - "ReturnType": "System.String", - "Static": true, - "Visibility": "Public", - "GenericParameter": [], - "Constant": true, - "Literal": "\"trackAllCaptures\"" - }, - { - "Kind": "Field", - "Name": "Type", - "Parameters": [], - "ReturnType": "System.String", - "Static": true, - "Visibility": "Public", - "GenericParameter": [], - "Constant": true, - "Literal": "\"type\"" - }, - { - "Kind": "Field", - "Name": "Url", - "Parameters": [], - "ReturnType": "System.String", - "Static": true, - "Visibility": "Public", - "GenericParameter": [], - "Constant": true, - "Literal": "\"url\"" - }, - { - "Kind": "Field", - "Name": "Value", - "Parameters": [], - "ReturnType": "System.String", - "Static": true, - "Visibility": "Public", - "GenericParameter": [], - "Constant": true, - "Literal": "\"value\"" - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite.ServerVariables", - "Visibility": "Public", - "Kind": "Class", - "Abstract": true, - "Static": true, - "Sealed": true, - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Method", - "Name": "FindServerVariable", - "Parameters": [ - { - "Name": "serverVariable", - "Type": "System.String" - }, - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Rewrite.Internal.ParserContext" - }, - { - "Name": "uriMatchPart", - "Type": "Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite.UriMatchPart" - } - ], - "ReturnType": "Microsoft.AspNetCore.Rewrite.Internal.PatternSegment", - "Static": true, - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite.UriMatchCondition", - "Visibility": "Public", - "Kind": "Class", - "BaseType": "Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite.Condition", - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [ - { - "Name": "inputParser", - "Type": "Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite.InputParser" - }, - { - "Name": "input", - "Type": "System.String" - }, - { - "Name": "pattern", - "Type": "System.String" - }, - { - "Name": "uriMatchPart", - "Type": "Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite.UriMatchPart" - }, - { - "Name": "ignoreCase", - "Type": "System.Boolean" - }, - { - "Name": "negate", - "Type": "System.Boolean" - } - ], - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite.UriMatchPart", - "Visibility": "Public", - "Kind": "Enumeration", - "Sealed": true, - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Field", - "Name": "Full", - "Parameters": [], - "GenericParameter": [], - "Literal": "0" - }, - { - "Kind": "Field", - "Name": "Path", - "Parameters": [], - "GenericParameter": [], - "Literal": "1" - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite.UrlRewriteFileParser", - "Visibility": "Public", - "Kind": "Class", - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Method", - "Name": "Parse", - "Parameters": [ - { - "Name": "reader", - "Type": "System.IO.TextReader" - } - ], - "ReturnType": "System.Collections.Generic.IList", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [], - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite.UrlRewriteRuleBuilder", - "Visibility": "Public", - "Kind": "Class", - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Method", - "Name": "get_Name", - "Parameters": [], - "ReturnType": "System.String", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_Name", - "Parameters": [ - { - "Name": "value", - "Type": "System.String" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_Enabled", - "Parameters": [], - "ReturnType": "System.Boolean", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_Enabled", - "Parameters": [ - { - "Name": "value", - "Type": "System.Boolean" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_Global", - "Parameters": [], - "ReturnType": "System.Boolean", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_Global", - "Parameters": [ - { - "Name": "value", - "Type": "System.Boolean" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_UriMatchPart", - "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite.UriMatchPart", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "Build", - "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite.IISUrlRewriteRule", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "AddUrlAction", - "Parameters": [ - { - "Name": "action", - "Type": "Microsoft.AspNetCore.Rewrite.Internal.UrlAction" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "AddUrlMatch", - "Parameters": [ - { - "Name": "input", - "Type": "System.String" - }, - { - "Name": "ignoreCase", - "Type": "System.Boolean", - "DefaultValue": "True" - }, - { - "Name": "negate", - "Type": "System.Boolean", - "DefaultValue": "False" - }, - { - "Name": "patternSyntax", - "Type": "Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite.PatternSyntax", - "DefaultValue": "0" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "ConfigureConditionBehavior", - "Parameters": [ - { - "Name": "logicalGrouping", - "Type": "Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite.LogicalGrouping" - }, - { - "Name": "trackAllCaptures", - "Type": "System.Boolean" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "AddUrlCondition", - "Parameters": [ - { - "Name": "condition", - "Type": "Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite.Condition" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "AddUrlConditions", - "Parameters": [ - { - "Name": "conditions", - "Type": "System.Collections.Generic.IEnumerable" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [], - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Rewrite.Internal.ApacheModRewrite.ApacheModRewriteRule", - "Visibility": "Public", - "Kind": "Class", - "ImplementedInterfaces": [ - "Microsoft.AspNetCore.Rewrite.IRule" - ], - "Members": [ - { - "Kind": "Method", - "Name": "get_InitialMatch", - "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Rewrite.Internal.UrlMatch", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_Conditions", - "Parameters": [], - "ReturnType": "System.Collections.Generic.IList", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_Actions", - "Parameters": [], - "ReturnType": "System.Collections.Generic.IList", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "ApplyRule", - "Parameters": [ - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Rewrite.RewriteContext" - } - ], - "ReturnType": "System.Void", - "Virtual": true, - "ImplementedInterface": "Microsoft.AspNetCore.Rewrite.IRule", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [ - { - "Name": "initialMatch", - "Type": "Microsoft.AspNetCore.Rewrite.Internal.UrlMatch" - }, - { - "Name": "conditions", - "Type": "System.Collections.Generic.IList" - }, - { - "Name": "urlActions", - "Type": "System.Collections.Generic.IList" - } - ], - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Rewrite.Internal.ApacheModRewrite.Condition", - "Visibility": "Public", - "Kind": "Class", - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Method", - "Name": "get_Input", - "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Rewrite.Internal.Pattern", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_Input", - "Parameters": [ - { - "Name": "value", - "Type": "Microsoft.AspNetCore.Rewrite.Internal.Pattern" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_Match", - "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Rewrite.Internal.UrlMatch", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_Match", - "Parameters": [ - { - "Name": "value", - "Type": "Microsoft.AspNetCore.Rewrite.Internal.UrlMatch" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_OrNext", - "Parameters": [], - "ReturnType": "System.Boolean", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_OrNext", - "Parameters": [ - { - "Name": "value", - "Type": "System.Boolean" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "Evaluate", - "Parameters": [ - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Rewrite.RewriteContext" - }, - { - "Name": "ruleBackReferences", - "Type": "Microsoft.AspNetCore.Rewrite.Internal.BackReferenceCollection" - }, - { - "Name": "conditionBackReferences", - "Type": "Microsoft.AspNetCore.Rewrite.Internal.BackReferenceCollection" - } - ], - "ReturnType": "Microsoft.AspNetCore.Rewrite.Internal.MatchResults", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [], - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Rewrite.Internal.ApacheModRewrite.ConditionEvaluator", - "Visibility": "Public", - "Kind": "Class", - "Abstract": true, - "Static": true, - "Sealed": true, - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Method", - "Name": "Evaluate", - "Parameters": [ - { - "Name": "conditions", - "Type": "System.Collections.Generic.IEnumerable" - }, - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Rewrite.RewriteContext" - }, - { - "Name": "backReferences", - "Type": "Microsoft.AspNetCore.Rewrite.Internal.BackReferenceCollection" - } - ], - "ReturnType": "Microsoft.AspNetCore.Rewrite.Internal.MatchResults", - "Static": true, - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "Evaluate", - "Parameters": [ - { - "Name": "conditions", - "Type": "System.Collections.Generic.IEnumerable" - }, - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Rewrite.RewriteContext" - }, - { - "Name": "backReferences", - "Type": "Microsoft.AspNetCore.Rewrite.Internal.BackReferenceCollection" - }, - { - "Name": "trackAllCaptures", - "Type": "System.Boolean" - } - ], - "ReturnType": "Microsoft.AspNetCore.Rewrite.Internal.MatchResults", - "Static": true, - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Rewrite.Internal.ApacheModRewrite.ConditionPatternParser", - "Visibility": "Public", - "Kind": "Class", - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Method", - "Name": "ParseActionCondition", - "Parameters": [ - { - "Name": "condition", - "Type": "System.String" - } - ], - "ReturnType": "Microsoft.AspNetCore.Rewrite.Internal.ApacheModRewrite.ParsedModRewriteInput", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [], - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Rewrite.Internal.ApacheModRewrite.ConditionType", - "Visibility": "Public", - "Kind": "Enumeration", - "Sealed": true, - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Field", - "Name": "Regex", - "Parameters": [], - "GenericParameter": [], - "Literal": "0" - }, - { - "Kind": "Field", - "Name": "PropertyTest", - "Parameters": [], - "GenericParameter": [], - "Literal": "1" - }, - { - "Kind": "Field", - "Name": "StringComp", - "Parameters": [], - "GenericParameter": [], - "Literal": "2" - }, - { - "Kind": "Field", - "Name": "IntComp", - "Parameters": [], - "GenericParameter": [], - "Literal": "3" - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Rewrite.Internal.ApacheModRewrite.CookieActionFactory", - "Visibility": "Public", - "Kind": "Class", - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Method", - "Name": "Create", - "Parameters": [ - { - "Name": "flagValue", - "Type": "System.String" - } - ], - "ReturnType": "Microsoft.AspNetCore.Rewrite.Internal.UrlActions.ChangeCookieAction", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [], - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Rewrite.Internal.ApacheModRewrite.FileParser", - "Visibility": "Public", - "Kind": "Class", - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Method", - "Name": "Parse", - "Parameters": [ - { - "Name": "input", - "Type": "System.IO.TextReader" - } - ], - "ReturnType": "System.Collections.Generic.IList", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [], - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Rewrite.Internal.ApacheModRewrite.FlagParser", - "Visibility": "Public", - "Kind": "Class", - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Method", - "Name": "Parse", - "Parameters": [ - { - "Name": "flagString", - "Type": "System.String" - } - ], - "ReturnType": "Microsoft.AspNetCore.Rewrite.Internal.ApacheModRewrite.Flags", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [], - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Rewrite.Internal.ApacheModRewrite.Flags", - "Visibility": "Public", - "Kind": "Class", - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Method", - "Name": "get_FlagDictionary", - "Parameters": [], - "ReturnType": "System.Collections.Generic.IDictionary", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "SetFlag", - "Parameters": [ - { - "Name": "flag", - "Type": "Microsoft.AspNetCore.Rewrite.Internal.ApacheModRewrite.FlagType" - }, - { - "Name": "value", - "Type": "System.String" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "GetValue", - "Parameters": [ - { - "Name": "flag", - "Type": "Microsoft.AspNetCore.Rewrite.Internal.ApacheModRewrite.FlagType" - }, - { - "Name": "value", - "Type": "System.String", - "Direction": "Out" - } - ], - "ReturnType": "System.Boolean", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_Item", - "Parameters": [ - { - "Name": "flag", - "Type": "Microsoft.AspNetCore.Rewrite.Internal.ApacheModRewrite.FlagType" - } - ], - "ReturnType": "System.String", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_Item", - "Parameters": [ - { - "Name": "flag", - "Type": "Microsoft.AspNetCore.Rewrite.Internal.ApacheModRewrite.FlagType" - }, - { - "Name": "value", - "Type": "System.String" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "HasFlag", - "Parameters": [ - { - "Name": "flag", - "Type": "Microsoft.AspNetCore.Rewrite.Internal.ApacheModRewrite.FlagType" - } - ], - "ReturnType": "System.Boolean", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [ - { - "Name": "flags", - "Type": "System.Collections.Generic.IDictionary" - } - ], - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [], - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Rewrite.Internal.ApacheModRewrite.FlagType", - "Visibility": "Public", - "Kind": "Enumeration", - "Sealed": true, - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Field", - "Name": "EscapeBackreference", - "Parameters": [], - "GenericParameter": [], - "Literal": "0" - }, - { - "Kind": "Field", - "Name": "Chain", - "Parameters": [], - "GenericParameter": [], - "Literal": "1" - }, - { - "Kind": "Field", - "Name": "Cookie", - "Parameters": [], - "GenericParameter": [], - "Literal": "2" - }, - { - "Kind": "Field", - "Name": "DiscardPath", - "Parameters": [], - "GenericParameter": [], - "Literal": "3" - }, - { - "Kind": "Field", - "Name": "Env", - "Parameters": [], - "GenericParameter": [], - "Literal": "4" - }, - { - "Kind": "Field", - "Name": "End", - "Parameters": [], - "GenericParameter": [], - "Literal": "5" - }, - { - "Kind": "Field", - "Name": "Forbidden", - "Parameters": [], - "GenericParameter": [], - "Literal": "6" - }, - { - "Kind": "Field", - "Name": "Gone", - "Parameters": [], - "GenericParameter": [], - "Literal": "7" - }, - { - "Kind": "Field", - "Name": "Handler", - "Parameters": [], - "GenericParameter": [], - "Literal": "8" - }, - { - "Kind": "Field", - "Name": "Last", - "Parameters": [], - "GenericParameter": [], - "Literal": "9" - }, - { - "Kind": "Field", - "Name": "Next", - "Parameters": [], - "GenericParameter": [], - "Literal": "10" - }, - { - "Kind": "Field", - "Name": "NoCase", - "Parameters": [], - "GenericParameter": [], - "Literal": "11" - }, - { - "Kind": "Field", - "Name": "NoEscape", - "Parameters": [], - "GenericParameter": [], - "Literal": "12" - }, - { - "Kind": "Field", - "Name": "NoSubReq", - "Parameters": [], - "GenericParameter": [], - "Literal": "13" - }, - { - "Kind": "Field", - "Name": "NoVary", - "Parameters": [], - "GenericParameter": [], - "Literal": "14" - }, - { - "Kind": "Field", - "Name": "Or", - "Parameters": [], - "GenericParameter": [], - "Literal": "15" - }, - { - "Kind": "Field", - "Name": "Proxy", - "Parameters": [], - "GenericParameter": [], - "Literal": "16" - }, - { - "Kind": "Field", - "Name": "PassThrough", - "Parameters": [], - "GenericParameter": [], - "Literal": "17" - }, - { - "Kind": "Field", - "Name": "QSAppend", - "Parameters": [], - "GenericParameter": [], - "Literal": "18" - }, - { - "Kind": "Field", - "Name": "QSDiscard", - "Parameters": [], - "GenericParameter": [], - "Literal": "19" - }, - { - "Kind": "Field", - "Name": "QSLast", - "Parameters": [], - "GenericParameter": [], - "Literal": "20" - }, - { - "Kind": "Field", - "Name": "Redirect", - "Parameters": [], - "GenericParameter": [], - "Literal": "21" - }, - { - "Kind": "Field", - "Name": "Skip", - "Parameters": [], - "GenericParameter": [], - "Literal": "22" - }, - { - "Kind": "Field", - "Name": "Type", - "Parameters": [], - "GenericParameter": [], - "Literal": "23" - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Rewrite.Internal.ApacheModRewrite.OperationType", - "Visibility": "Public", - "Kind": "Enumeration", - "Sealed": true, - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Field", - "Name": "None", - "Parameters": [], - "GenericParameter": [], - "Literal": "0" - }, - { - "Kind": "Field", - "Name": "Equal", - "Parameters": [], - "GenericParameter": [], - "Literal": "1" - }, - { - "Kind": "Field", - "Name": "Greater", - "Parameters": [], - "GenericParameter": [], - "Literal": "2" - }, - { - "Kind": "Field", - "Name": "GreaterEqual", - "Parameters": [], - "GenericParameter": [], - "Literal": "3" - }, - { - "Kind": "Field", - "Name": "Less", - "Parameters": [], - "GenericParameter": [], - "Literal": "4" - }, - { - "Kind": "Field", - "Name": "LessEqual", - "Parameters": [], - "GenericParameter": [], - "Literal": "5" - }, - { - "Kind": "Field", - "Name": "NotEqual", - "Parameters": [], - "GenericParameter": [], - "Literal": "6" - }, - { - "Kind": "Field", - "Name": "Directory", - "Parameters": [], - "GenericParameter": [], - "Literal": "7" - }, - { - "Kind": "Field", - "Name": "RegularFile", - "Parameters": [], - "GenericParameter": [], - "Literal": "8" - }, - { - "Kind": "Field", - "Name": "ExistingFile", - "Parameters": [], - "GenericParameter": [], - "Literal": "9" - }, - { - "Kind": "Field", - "Name": "SymbolicLink", - "Parameters": [], - "GenericParameter": [], - "Literal": "10" - }, - { - "Kind": "Field", - "Name": "Size", - "Parameters": [], - "GenericParameter": [], - "Literal": "11" - }, - { - "Kind": "Field", - "Name": "ExistingUrl", - "Parameters": [], - "GenericParameter": [], - "Literal": "12" - }, - { - "Kind": "Field", - "Name": "Executable", - "Parameters": [], - "GenericParameter": [], - "Literal": "13" - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Rewrite.Internal.ApacheModRewrite.ParsedModRewriteInput", - "Visibility": "Public", - "Kind": "Class", - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Method", - "Name": "get_Invert", - "Parameters": [], - "ReturnType": "System.Boolean", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_Invert", - "Parameters": [ - { - "Name": "value", - "Type": "System.Boolean" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_ConditionType", - "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Rewrite.Internal.ApacheModRewrite.ConditionType", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_ConditionType", - "Parameters": [ - { - "Name": "value", - "Type": "Microsoft.AspNetCore.Rewrite.Internal.ApacheModRewrite.ConditionType" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_OperationType", - "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Rewrite.Internal.ApacheModRewrite.OperationType", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_OperationType", - "Parameters": [ - { - "Name": "value", - "Type": "Microsoft.AspNetCore.Rewrite.Internal.ApacheModRewrite.OperationType" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_Operand", - "Parameters": [], - "ReturnType": "System.String", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_Operand", - "Parameters": [ - { - "Name": "value", - "Type": "System.String" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [], - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [ - { - "Name": "invert", - "Type": "System.Boolean" - }, - { - "Name": "conditionType", - "Type": "Microsoft.AspNetCore.Rewrite.Internal.ApacheModRewrite.ConditionType" - }, - { - "Name": "operationType", - "Type": "Microsoft.AspNetCore.Rewrite.Internal.ApacheModRewrite.OperationType" - }, - { - "Name": "operand", - "Type": "System.String" - } - ], - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Rewrite.Internal.ApacheModRewrite.RuleBuilder", - "Visibility": "Public", - "Kind": "Class", - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Method", - "Name": "Build", - "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Rewrite.Internal.ApacheModRewrite.ApacheModRewriteRule", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "AddRule", - "Parameters": [ - { - "Name": "rule", - "Type": "System.String" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "AddConditionFromParts", - "Parameters": [ - { - "Name": "pattern", - "Type": "Microsoft.AspNetCore.Rewrite.Internal.Pattern" - }, - { - "Name": "input", - "Type": "Microsoft.AspNetCore.Rewrite.Internal.ApacheModRewrite.ParsedModRewriteInput" - }, - { - "Name": "flags", - "Type": "Microsoft.AspNetCore.Rewrite.Internal.ApacheModRewrite.Flags" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "AddMatch", - "Parameters": [ - { - "Name": "input", - "Type": "Microsoft.AspNetCore.Rewrite.Internal.ApacheModRewrite.ParsedModRewriteInput" - }, - { - "Name": "flags", - "Type": "Microsoft.AspNetCore.Rewrite.Internal.ApacheModRewrite.Flags" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "AddAction", - "Parameters": [ - { - "Name": "pattern", - "Type": "Microsoft.AspNetCore.Rewrite.Internal.Pattern" - }, - { - "Name": "flags", - "Type": "Microsoft.AspNetCore.Rewrite.Internal.ApacheModRewrite.Flags" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [], - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Rewrite.Internal.ApacheModRewrite.RuleRegexParser", - "Visibility": "Public", - "Kind": "Class", - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Method", - "Name": "ParseRuleRegex", - "Parameters": [ - { - "Name": "regex", - "Type": "System.String" - } - ], - "ReturnType": "Microsoft.AspNetCore.Rewrite.Internal.ApacheModRewrite.ParsedModRewriteInput", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [], - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Rewrite.Internal.ApacheModRewrite.SegmentType", - "Visibility": "Public", - "Kind": "Enumeration", - "Sealed": true, - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Field", - "Name": "Literal", - "Parameters": [], - "GenericParameter": [], - "Literal": "0" - }, - { - "Kind": "Field", - "Name": "ServerParameter", - "Parameters": [], - "GenericParameter": [], - "Literal": "1" - }, - { - "Kind": "Field", - "Name": "ConditionParameter", - "Parameters": [], - "GenericParameter": [], - "Literal": "2" - }, - { - "Kind": "Field", - "Name": "RuleParameter", - "Parameters": [], - "GenericParameter": [], - "Literal": "3" - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Rewrite.Internal.ApacheModRewrite.ServerVariables", - "Visibility": "Public", - "Kind": "Class", - "Abstract": true, - "Static": true, - "Sealed": true, - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Method", - "Name": "FindServerVariable", - "Parameters": [ - { - "Name": "serverVariable", - "Type": "System.String" - }, - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Rewrite.Internal.ParserContext" - } - ], - "ReturnType": "Microsoft.AspNetCore.Rewrite.Internal.PatternSegment", - "Static": true, - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Rewrite.Internal.ApacheModRewrite.TestStringParser", - "Visibility": "Public", - "Kind": "Class", - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Method", - "Name": "Parse", - "Parameters": [ - { - "Name": "testString", - "Type": "System.String" - } - ], - "ReturnType": "Microsoft.AspNetCore.Rewrite.Internal.Pattern", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [], - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Rewrite.Internal.ApacheModRewrite.Tokenizer", - "Visibility": "Public", - "Kind": "Class", - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Method", - "Name": "Tokenize", - "Parameters": [ - { - "Name": "rule", - "Type": "System.String" - } - ], - "ReturnType": "System.Collections.Generic.IList", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [], - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] } ] } \ No newline at end of file From d6a29161ee5fffd91b3269380325970d42e5d9f0 Mon Sep 17 00:00:00 2001 From: Nate McMaster Date: Wed, 27 Jun 2018 13:39:42 -0700 Subject: [PATCH 303/307] Bumping version from 2.1.1 to 2.1.2 --- version.props | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/version.props b/version.props index 6ecf2553b6..5d8053aaec 100644 --- a/version.props +++ b/version.props @@ -1,6 +1,6 @@  - 2.1.1 + 2.1.2 rtm $(VersionPrefix) $(VersionPrefix)-$(VersionSuffix)-final @@ -9,7 +9,7 @@ $(FeatureBranchVersionPrefix)$(VersionSuffix)-$([System.Text.RegularExpressions.Regex]::Replace('$(FeatureBranchVersionSuffix)', '[^\w-]', '-')) $(VersionSuffix)-$(BuildNumber) - 0.4.1 + 0.4.2 rtm $(ExperimentalVersionPrefix) $(ExperimentalVersionPrefix)-$(ExperimentalVersionSuffix)-final From a8187c1c5ed2847ef4a9ca4f75e4d349a6ffeb2f Mon Sep 17 00:00:00 2001 From: Nate McMaster Date: Wed, 11 Jul 2018 15:06:24 -0700 Subject: [PATCH 304/307] Reverting version from 2.1.2 back to 2.1.1 As a result of changing the way we apply servicing updates to aspnet core, this repo did not need the version bump because there are no planned product changes in this repo. --- version.props | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/version.props b/version.props index 5d8053aaec..6ecf2553b6 100644 --- a/version.props +++ b/version.props @@ -1,6 +1,6 @@  - 2.1.2 + 2.1.1 rtm $(VersionPrefix) $(VersionPrefix)-$(VersionSuffix)-final @@ -9,7 +9,7 @@ $(FeatureBranchVersionPrefix)$(VersionSuffix)-$([System.Text.RegularExpressions.Regex]::Replace('$(FeatureBranchVersionSuffix)', '[^\w-]', '-')) $(VersionSuffix)-$(BuildNumber) - 0.4.2 + 0.4.1 rtm $(ExperimentalVersionPrefix) $(ExperimentalVersionPrefix)-$(ExperimentalVersionSuffix)-final From 5926bc2b4913c7f5fe209d6c2a0e535ce0e623a4 Mon Sep 17 00:00:00 2001 From: Nate McMaster Date: Wed, 11 Jul 2018 18:47:40 -0700 Subject: [PATCH 305/307] Updating dependencies to 2.1.2 and adding a section for pinned variable versions --- build/dependencies.props | 19 +++++++++++++------ korebuild-lock.txt | 4 ++-- 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index 71133dbd09..40fa769398 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -2,15 +2,17 @@ $(MSBuildAllProjects);$(MSBuildThisFileFullPath) - - 2.1.1-rtm-15793 + + + + 2.1.3-rtm-15802 2.1.1 2.1.1 2.1.1 2.1.1 - 2.1.1 - 2.1.1 - 2.1.1 + 2.1.2 + 2.1.2 + 2.1.2 2.1.1 2.1.1 2.1.1 @@ -22,7 +24,7 @@ 2.1.1 2.1.1 2.0.0 - 2.1.1 + 2.1.2 2.1.1 15.6.1 4.7.49 @@ -31,5 +33,10 @@ 2.3.1 2.4.0-beta.1.build3945 + + + + + diff --git a/korebuild-lock.txt b/korebuild-lock.txt index bc84e0cd53..251c227c83 100644 --- a/korebuild-lock.txt +++ b/korebuild-lock.txt @@ -1,2 +1,2 @@ -version:2.1.1-rtm-15793 -commithash:988313f4b064d6c69fc6f7b845b6384a6af3447a +version:2.1.3-rtm-15802 +commithash:a7c08b45b440a7d2058a0aa1eaa3eb6ba811976a From 1de636cd18309070792b68888ca29c8b85fac98b Mon Sep 17 00:00:00 2001 From: Nate McMaster Date: Thu, 12 Jul 2018 11:50:35 -0700 Subject: [PATCH 306/307] Pin version variables to the ASP.NET Core 2.1.2 baseline This reverts our previous policy of cascading versions on all servicing updates. This moves variables into the 'pinned' section, and points them to the latest stable release (versions that were used at the time of the 2.1.2 release). --- build/dependencies.props | 33 +++++++++++++++++---------------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index 40fa769398..8924c74e64 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -4,8 +4,23 @@ - + 2.1.3-rtm-15802 + 2.0.0 + 2.1.2 + 15.6.1 + 4.7.49 + 2.0.3 + 0.8.0 + 2.3.1 + 2.4.0-beta.1.build3945 + + + + + + + 2.1.1 2.1.1 2.1.1 @@ -23,20 +38,6 @@ 2.1.1 2.1.1 2.1.1 - 2.0.0 - 2.1.2 2.1.1 - 15.6.1 - 4.7.49 - 2.0.3 - 0.8.0 - 2.3.1 - 2.4.0-beta.1.build3945 - - - - - - - + \ No newline at end of file From 2f2cec4acec69c09228fb0062c12e96ff4f686c6 Mon Sep 17 00:00:00 2001 From: Nate McMaster Date: Fri, 30 Nov 2018 14:21:50 -0800 Subject: [PATCH 307/307] Reorganize source code in preparation to move into aspnet/AspNetCore Prior to reorganization, this source code was found in https://github.com/aspnet/BasicMiddleware/tree/1de636cd18309070792b68888ca29c8b85fac98b --- .appveyor.yml | 17 - .gitattributes | 51 --- .gitignore | 35 -- .travis.yml | 27 -- BasicMiddleware.sln | 185 ---------- CONTRIBUTING.md | 4 - Directory.Build.props | 21 -- Directory.Build.targets | 7 - LICENSE.txt | 14 - NuGet.config | 7 - NuGetPackageVerifier.json | 7 - README.md | 11 - build.cmd | 2 - build.sh | 8 - build/Key.snk | Bin 596 -> 0 bytes build/dependencies.props | 43 --- build/repo.props | 15 - build/sources.props | 17 - korebuild-lock.txt | 2 - korebuild.json | 4 - run.cmd | 2 - run.ps1 | 196 ----------- run.sh | 231 ------------- .../HostFilteringSample.csproj | 29 -- .../HttpOverridesSample.csproj | 15 - .../HttpsPolicySample.csproj | 18 - .../Properties/launchSettings.json | 25 -- .../ResponseBufferingSample.csproj | 15 - samples/ResponseBufferingSample/Startup.cs | 50 --- .../ResponseCompressionSample.csproj | 20 -- samples/RewriteSample/RewriteSample.csproj | 16 - src/Directory.Build.props | 7 - .../BufferingWriteStream.cs | 218 ------------ .../HttpBufferingFeature.cs | 30 -- .../Microsoft.AspNetCore.Buffering.csproj | 19 -- .../ResponseBufferingMiddleware.cs | 65 ---- .../ResponseBufferingMiddlewareExtensions.cs | 20 -- .../SendFileFeatureWrapper.cs | 28 -- .../Microsoft.AspNetCore.HostFiltering.csproj | 18 - .../Microsoft.AspNetCore.HttpsPolicy.csproj | 20 -- .../Microsoft.AspNetCore.Rewrite.csproj | 23 -- .../sample/HostFilteringSample.csproj | 26 ++ .../HostFiltering/sample}/Program.cs | 0 .../sample}/Properties/launchSettings.json | 0 .../HostFiltering/sample}/Startup.cs | 0 .../sample}/appsettings.Development.json | 0 .../sample}/appsettings.Production.json | 0 .../HostFiltering/sample}/appsettings.json | 0 .../src}/HostFilteringBuilderExtensions.cs | 0 .../src}/HostFilteringMiddleware.cs | 0 .../src}/HostFilteringOptions.cs | 0 .../src}/HostFilteringServicesExtensions.cs | 0 .../Microsoft.AspNetCore.HostFiltering.csproj | 18 + .../HostFiltering/src}/baseline.netcore.json | 0 .../test}/HostFilteringMiddlewareTests.cs | 0 ...soft.AspNetCore.HostFiltering.Tests.csproj | 12 + .../sample/HttpOverridesSample.csproj | 12 + .../sample}/Properties/launchSettings.json | 0 .../HttpOverrides/sample}/Startup.cs | 0 .../HttpOverrides/src}/ForwardedHeaders.cs | 0 .../src}/ForwardedHeadersDefaults.cs | 0 .../src}/ForwardedHeadersExtensions.cs | 0 .../src}/ForwardedHeadersMiddleware.cs | 0 .../src}/ForwardedHeadersOptions.cs | 0 .../src}/HttpMethodOverrideExtensions.cs | 0 .../src}/HttpMethodOverrideMiddleware.cs | 0 .../src}/HttpMethodOverrideOptions.cs | 0 .../HttpOverrides/src}/IPNetwork.cs | 0 .../src}/Internal/IPEndPointParser.cs | 0 .../Microsoft.AspNetCore.HttpOverrides.csproj | 6 +- .../HttpOverrides/src}/baseline.net45.json | 0 .../HttpOverrides/src}/baseline.netcore.json | 0 .../test}/ForwardedHeadersMiddlewareTest.cs | 0 .../test}/HttpMethodOverrideMiddlewareTest.cs | 0 .../test}/IPEndPointParserTest.cs | 0 .../HttpOverrides/test}/IPNetworkTest.cs | 0 ...soft.AspNetCore.HttpOverrides.Tests.csproj | 3 +- .../sample/HttpsPolicySample.csproj | 14 + .../sample}/Properties/launchSettings.json | 0 .../Middleware/HttpsPolicy/sample}/Startup.cs | 0 .../HttpsPolicy/sample}/testCert.pfx | Bin .../HttpsPolicy/src}/HstsBuilderExtensions.cs | 0 .../HttpsPolicy/src}/HstsMiddleware.cs | 0 .../HttpsPolicy/src}/HstsOptions.cs | 0 .../src}/HstsServicesExtensions.cs | 0 .../src}/HttpsRedirectionBuilderExtensions.cs | 0 .../src}/HttpsRedirectionMiddleware.cs | 0 .../src}/HttpsRedirectionOptions.cs | 0 .../HttpsRedirectionServicesExtensions.cs | 0 .../Microsoft.AspNetCore.HttpsPolicy.csproj | 20 ++ .../HttpsPolicy/src}/baseline.netcore.json | 0 .../src}/internal/HttpsLoggingExtensions.cs | 0 .../HttpsPolicy/test}/HstsMiddlewareTests.cs | 0 .../HttpsPolicy/test}/HttpsPolicyTests.cs | 0 .../test}/HttpsRedirectionMiddlewareTests.cs | 0 ...rosoft.AspNetCore.HttpsPolicy.Tests.csproj | 7 +- .../sample}/CustomCompressionProvider.cs | 0 .../ResponseCompression/sample}/LoremIpsum.cs | 0 .../sample}/Properties/launchSettings.json | 0 .../sample/ResponseCompressionSample.csproj | 17 + .../ResponseCompression/sample}/Startup.cs | 0 .../sample}/testfile1kb.txt | 0 .../src}/BodyWrapperStream.cs | 0 .../src}/CompressionProviderCollection.cs | 0 .../src}/CompressionProviderFactory.cs | 0 .../src}/GzipCompressionProvider.cs | 0 .../src}/GzipCompressionProviderOptions.cs | 0 .../src}/ICompressionProvider.cs | 0 .../src}/IResponseCompressionProvider.cs | 0 ...soft.AspNetCore.ResponseCompression.csproj | 4 +- .../src}/Properties/AssemblyInfo.cs | 0 .../ResponseCompressionBuilderExtensions.cs | 0 .../src}/ResponseCompressionDefaults.cs | 0 .../src}/ResponseCompressionMiddleware.cs | 0 .../src}/ResponseCompressionOptions.cs | 0 .../src}/ResponseCompressionProvider.cs | 0 .../ResponseCompressionServicesExtensions.cs | 0 .../src}/baseline.netcore.json | 0 .../src}/baseline.netframework.json | 0 .../test}/BodyWrapperStreamTests.cs | 0 ...spNetCore.ResponseCompression.Tests.csproj | 18 + .../ResponseCompressionMiddlewareTest.cs | 0 .../ResponseCompression/test}/testfile1kb.txt | 0 .../sample}/Properties/launchSettings.json | 0 .../Middleware/Rewrite/sample}/Rewrite.txt | 0 .../Rewrite/sample/RewriteSample.csproj | 13 + .../Middleware/Rewrite/sample}/Startup.cs | 0 .../Middleware/Rewrite/sample}/UrlRewrite.xml | 0 .../Middleware/Rewrite/sample}/testCert.pfx | Bin .../src}/ApacheModRewriteOptionsExtensions.cs | 0 .../RewriteMiddlewareLoggingExtensions.cs | 0 .../src}/IISUrlRewriteOptionsExtensions.cs | 0 .../Rewrite/src}/IRule.cs | 0 .../ApacheModRewrite/ApacheModRewriteRule.cs | 0 .../Internal/ApacheModRewrite/Condition.cs | 0 .../ApacheModRewrite/ConditionEvaluator.cs | 0 .../ConditionPatternParser.cs | 0 .../ApacheModRewrite/ConditionType.cs | 0 .../ApacheModRewrite/CookieActionFactory.cs | 0 .../Internal/ApacheModRewrite/FileParser.cs | 0 .../Internal/ApacheModRewrite/FlagParser.cs | 0 .../Internal/ApacheModRewrite/FlagType.cs | 0 .../src}/Internal/ApacheModRewrite/Flags.cs | 0 .../ApacheModRewrite/OperationType.cs | 0 .../ParsedModRewriteCondition.cs | 0 .../Internal/ApacheModRewrite/RuleBuilder.cs | 0 .../ApacheModRewrite/RuleRegexParser.cs | 0 .../Internal/ApacheModRewrite/SegmentType.cs | 0 .../ApacheModRewrite/ServerVariables.cs | 0 .../ApacheModRewrite/TestStringParser.cs | 0 .../Internal/ApacheModRewrite/Tokenizer.cs | 0 .../src}/Internal/BackReferenceCollection.cs | 0 .../Rewrite/src}/Internal/DelegateRule.cs | 0 .../src}/Internal/IISUrlRewrite/ActionType.cs | 0 .../src}/Internal/IISUrlRewrite/Condition.cs | 0 .../IISUrlRewrite/ConditionCollection.cs | 0 .../IISUrlRewrite/ConditionEvaluator.cs | 0 .../Internal/IISUrlRewrite/IISRewriteMap.cs | 0 .../IISUrlRewrite/IISRewriteMapCollection.cs | 0 .../IISUrlRewrite/IISUrlRewriteRule.cs | 0 .../Internal/IISUrlRewrite/InputParser.cs | 0 .../InvalidUrlRewriteFormatException.cs | 0 .../Internal/IISUrlRewrite/LogicalGrouping.cs | 0 .../src}/Internal/IISUrlRewrite/MatchType.cs | 0 .../Internal/IISUrlRewrite/PatternSyntax.cs | 0 .../Internal/IISUrlRewrite/RedirectType.cs | 0 .../IISUrlRewrite/RewriteMapParser.cs | 0 .../Internal/IISUrlRewrite/RewriteTags.cs | 0 .../Internal/IISUrlRewrite/ServerVariables.cs | 0 .../IISUrlRewrite/UriMatchCondition.cs | 0 .../Internal/IISUrlRewrite/UriMatchPart.cs | 0 .../IISUrlRewrite/UrlRewriteFileParser.cs | 0 .../IISUrlRewrite/UrlRewriteRuleBuilder.cs | 0 .../Rewrite/src}/Internal/MatchResults.cs | 0 .../Rewrite/src}/Internal/ParserContext.cs | 0 .../Rewrite/src}/Internal/Pattern.cs | 0 .../Rewrite/src}/Internal/PatternSegment.cs | 0 .../PatternSegments/ConditionMatchSegment.cs | 0 .../PatternSegments/DateTimeSegment.cs | 0 .../Internal/PatternSegments/HeaderSegment.cs | 0 .../PatternSegments/IsHttpsModSegment.cs | 0 .../PatternSegments/IsHttpsUrlSegment.cs | 0 .../Internal/PatternSegments/IsIPV6Segment.cs | 0 .../PatternSegments/LiteralSegment.cs | 0 .../PatternSegments/LocalAddressSegment.cs | 0 .../PatternSegments/LocalPortSegment.cs | 0 .../PatternSegments/QueryStringSegment.cs | 0 .../PatternSegments/RemoteAddressSegment.cs | 0 .../PatternSegments/RemotePortSegment.cs | 0 .../PatternSegments/RequestFilenameSegment.cs | 0 .../PatternSegments/RequestMethodSegment.cs | 0 .../PatternSegments/RewriteMapSegment.cs | 0 .../PatternSegments/RuleMatchSegment.cs | 0 .../Internal/PatternSegments/SchemeSegment.cs | 0 .../PatternSegments/ServerProtocolSegment.cs | 0 .../PatternSegments/ToLowerSegment.cs | 0 .../PatternSegments/UrlEncodeSegment.cs | 0 .../Internal/PatternSegments/UrlSegment.cs | 0 .../Rewrite/src}/Internal/RedirectRule.cs | 0 .../src}/Internal/RedirectToHttpsRule.cs | 0 .../src}/Internal/RedirectToWwwRule.cs | 0 .../Rewrite/src}/Internal/RewriteRule.cs | 0 .../Rewrite/src}/Internal/UrlAction.cs | 0 .../src}/Internal/UrlActions/AbortAction.cs | 0 .../Internal/UrlActions/ChangeCookieAction.cs | 0 .../UrlActions/CustomResponseAction.cs | 0 .../Internal/UrlActions/ForbiddenAction.cs | 0 .../src}/Internal/UrlActions/GoneAction.cs | 0 .../src}/Internal/UrlActions/NoneAction.cs | 0 .../Internal/UrlActions/RedirectAction.cs | 0 .../src}/Internal/UrlActions/RewriteAction.cs | 0 .../Rewrite/src}/Internal/UrlMatch.cs | 0 .../src}/Internal/UrlMatches/ExactMatch.cs | 0 .../src}/Internal/UrlMatches/FileSizeMatch.cs | 0 .../src}/Internal/UrlMatches/IntegerMatch.cs | 0 .../Internal/UrlMatches/IntegerOperation.cs | 0 .../Internal/UrlMatches/IsDirectoryMatch.cs | 0 .../src}/Internal/UrlMatches/IsFileMatch.cs | 0 .../src}/Internal/UrlMatches/RegexMatch.cs | 0 .../src}/Internal/UrlMatches/StringMatch.cs | 0 .../Internal/UrlMatches/StringOperation.cs | 0 .../src/Microsoft.AspNetCore.Rewrite.csproj | 23 ++ .../Rewrite/src}/Properties/AssemblyInfo.cs | 0 .../src}/Properties/Resources.Designer.cs | 0 .../Rewrite/src}/Resources.resx | 0 .../Rewrite/src}/RewriteBuilderExtensions.cs | 0 .../Rewrite/src}/RewriteContext.cs | 0 .../Rewrite/src}/RewriteMiddleware.cs | 0 .../Rewrite/src}/RewriteOptions.cs | 0 .../Rewrite/src}/RewriteOptionsExtensions.cs | 0 .../Rewrite/src}/RuleResult.cs | 0 .../Rewrite/src}/baseline.netcore.json | 0 .../ConditionPatternParserTest.cs | 0 .../CookieActionFactoryTest.cs | 0 .../test}/ApacheModRewrite/FlagParserTest.cs | 0 .../ApacheModRewrite/FormatExceptionTests.cs | 0 .../ModRewriteMiddlewareTest.cs | 0 .../ApacheModRewrite/RewriteTokenizerTest.cs | 0 .../test}/ApacheModRewrite/RuleBuilderTest.cs | 0 .../ApacheModRewrite/RuleRegexParserTest.cs | 0 .../ApacheModRewrite/TestStringParserTests.cs | 0 .../test}/IISUrlRewrite/FileParserTests.cs | 0 .../FormatExceptionHandlingTests.cs | 0 .../test}/IISUrlRewrite/InputParserTests.cs | 0 ...dUrlRewriteFormatExceptionHandlingTests.cs | 0 .../test}/IISUrlRewrite/MiddleWareTests.cs | 0 .../IISUrlRewrite/RewriteMapParserTests.cs | 0 .../IISUrlRewrite/ServerVariableTests.cs | 0 .../UrlRewriteApplicationTests.cs | 0 .../Microsoft.AspNetCore.Rewrite.Tests.csproj | 2 +- .../Rewrite/test}/MiddlewareTests.cs | 0 .../ConditionMatchSegmentTests.cs | 0 .../PatternSegments/DateTimeSegmentTests.cs | 0 .../PatternSegments/HeaderSegmentTests.cs | 0 .../PatternSegments/IsHttpsModSegmentTests.cs | 0 .../PatternSegments/IsHttpsSegmentTests.cs | 0 .../PatternSegments/IsIPV6SegmentTests.cs | 0 .../PatternSegments/LIteralSegmentTests.cs | 0 .../LocalAddressSegmentTests.cs | 0 .../PatternSegments/LocalPortSegmentTests.cs | 0 .../QueryStringSegmentTests.cs | 0 .../RemoteAddressSegmentTests.cs | 0 .../PatternSegments/RemotePortSegmentTests.cs | 0 .../RequestFilenameSegmentTests.cs | 0 .../RequestMethodSegmentTests.cs | 0 .../PatternSegments/RuleMatchSegmentTests.cs | 0 .../PatternSegments/SchemeSegmentTests.cs | 0 .../ServerProtocolSegmentTests.cs | 0 .../PatternSegments/ToLowerSegmentTests.cs | 0 .../PatternSegments/UrlEncodeSegmentTests.cs | 0 .../test}/PatternSegments/UrlSegmentTests.cs | 0 .../test}/UrlActions/AbortActionTests.cs | 0 .../UrlActions/ChangeCookieActionTests.cs | 0 .../test}/UrlActions/ForbiddenActionTests.cs | 0 .../test}/UrlActions/GoneActionTests.cs | 0 .../test}/UrlMatches/ExactMatchTests.cs | 0 .../test}/UrlMatches/IntegerMatchTests.cs | 0 .../test}/UrlMatches/StringMatchTests.cs | 0 test/Directory.Build.props | 19 -- .../ResponseBufferingMiddlewareTests.cs | 315 ------------------ ...soft.AspNetCore.HostFiltering.Tests.csproj | 12 - ...soft.AspNetCore.HttpOverrides.Tests.csproj | 15 - ...spNetCore.ResponseCompression.Tests.csproj | 21 -- version.props | 18 - 284 files changed, 183 insertions(+), 1954 deletions(-) delete mode 100644 .appveyor.yml delete mode 100644 .gitattributes delete mode 100644 .gitignore delete mode 100644 .travis.yml delete mode 100644 BasicMiddleware.sln delete mode 100644 CONTRIBUTING.md delete mode 100644 Directory.Build.props delete mode 100644 Directory.Build.targets delete mode 100644 LICENSE.txt delete mode 100644 NuGet.config delete mode 100644 NuGetPackageVerifier.json delete mode 100644 README.md delete mode 100644 build.cmd delete mode 100755 build.sh delete mode 100644 build/Key.snk delete mode 100644 build/dependencies.props delete mode 100644 build/repo.props delete mode 100644 build/sources.props delete mode 100644 korebuild-lock.txt delete mode 100644 korebuild.json delete mode 100644 run.cmd delete mode 100644 run.ps1 delete mode 100755 run.sh delete mode 100644 samples/HostFilteringSample/HostFilteringSample.csproj delete mode 100644 samples/HttpOverridesSample/HttpOverridesSample.csproj delete mode 100644 samples/HttpsPolicySample/HttpsPolicySample.csproj delete mode 100644 samples/ResponseBufferingSample/Properties/launchSettings.json delete mode 100644 samples/ResponseBufferingSample/ResponseBufferingSample.csproj delete mode 100644 samples/ResponseBufferingSample/Startup.cs delete mode 100644 samples/ResponseCompressionSample/ResponseCompressionSample.csproj delete mode 100644 samples/RewriteSample/RewriteSample.csproj delete mode 100644 src/Directory.Build.props delete mode 100644 src/Microsoft.AspNetCore.Buffering/BufferingWriteStream.cs delete mode 100644 src/Microsoft.AspNetCore.Buffering/HttpBufferingFeature.cs delete mode 100644 src/Microsoft.AspNetCore.Buffering/Microsoft.AspNetCore.Buffering.csproj delete mode 100644 src/Microsoft.AspNetCore.Buffering/ResponseBufferingMiddleware.cs delete mode 100644 src/Microsoft.AspNetCore.Buffering/ResponseBufferingMiddlewareExtensions.cs delete mode 100644 src/Microsoft.AspNetCore.Buffering/SendFileFeatureWrapper.cs delete mode 100644 src/Microsoft.AspNetCore.HostFiltering/Microsoft.AspNetCore.HostFiltering.csproj delete mode 100644 src/Microsoft.AspNetCore.HttpsPolicy/Microsoft.AspNetCore.HttpsPolicy.csproj delete mode 100644 src/Microsoft.AspNetCore.Rewrite/Microsoft.AspNetCore.Rewrite.csproj create mode 100644 src/Middleware/HostFiltering/sample/HostFilteringSample.csproj rename {samples/HostFilteringSample => src/Middleware/HostFiltering/sample}/Program.cs (100%) rename {samples/HostFilteringSample => src/Middleware/HostFiltering/sample}/Properties/launchSettings.json (100%) rename {samples/HostFilteringSample => src/Middleware/HostFiltering/sample}/Startup.cs (100%) rename {samples/HostFilteringSample => src/Middleware/HostFiltering/sample}/appsettings.Development.json (100%) rename {samples/HostFilteringSample => src/Middleware/HostFiltering/sample}/appsettings.Production.json (100%) rename {samples/HostFilteringSample => src/Middleware/HostFiltering/sample}/appsettings.json (100%) rename src/{Microsoft.AspNetCore.HostFiltering => Middleware/HostFiltering/src}/HostFilteringBuilderExtensions.cs (100%) rename src/{Microsoft.AspNetCore.HostFiltering => Middleware/HostFiltering/src}/HostFilteringMiddleware.cs (100%) rename src/{Microsoft.AspNetCore.HostFiltering => Middleware/HostFiltering/src}/HostFilteringOptions.cs (100%) rename src/{Microsoft.AspNetCore.HostFiltering => Middleware/HostFiltering/src}/HostFilteringServicesExtensions.cs (100%) create mode 100644 src/Middleware/HostFiltering/src/Microsoft.AspNetCore.HostFiltering.csproj rename src/{Microsoft.AspNetCore.HostFiltering => Middleware/HostFiltering/src}/baseline.netcore.json (100%) rename {test/Microsoft.AspNetCore.HostFiltering.Tests => src/Middleware/HostFiltering/test}/HostFilteringMiddlewareTests.cs (100%) create mode 100644 src/Middleware/HostFiltering/test/Microsoft.AspNetCore.HostFiltering.Tests.csproj create mode 100644 src/Middleware/HttpOverrides/sample/HttpOverridesSample.csproj rename {samples/HttpOverridesSample => src/Middleware/HttpOverrides/sample}/Properties/launchSettings.json (100%) rename {samples/HttpOverridesSample => src/Middleware/HttpOverrides/sample}/Startup.cs (100%) rename src/{Microsoft.AspNetCore.HttpOverrides => Middleware/HttpOverrides/src}/ForwardedHeaders.cs (100%) rename src/{Microsoft.AspNetCore.HttpOverrides => Middleware/HttpOverrides/src}/ForwardedHeadersDefaults.cs (100%) rename src/{Microsoft.AspNetCore.HttpOverrides => Middleware/HttpOverrides/src}/ForwardedHeadersExtensions.cs (100%) rename src/{Microsoft.AspNetCore.HttpOverrides => Middleware/HttpOverrides/src}/ForwardedHeadersMiddleware.cs (100%) rename src/{Microsoft.AspNetCore.HttpOverrides => Middleware/HttpOverrides/src}/ForwardedHeadersOptions.cs (100%) rename src/{Microsoft.AspNetCore.HttpOverrides => Middleware/HttpOverrides/src}/HttpMethodOverrideExtensions.cs (100%) rename src/{Microsoft.AspNetCore.HttpOverrides => Middleware/HttpOverrides/src}/HttpMethodOverrideMiddleware.cs (100%) rename src/{Microsoft.AspNetCore.HttpOverrides => Middleware/HttpOverrides/src}/HttpMethodOverrideOptions.cs (100%) rename src/{Microsoft.AspNetCore.HttpOverrides => Middleware/HttpOverrides/src}/IPNetwork.cs (100%) rename src/{Microsoft.AspNetCore.HttpOverrides => Middleware/HttpOverrides/src}/Internal/IPEndPointParser.cs (100%) rename src/{Microsoft.AspNetCore.HttpOverrides => Middleware/HttpOverrides/src}/Microsoft.AspNetCore.HttpOverrides.csproj (57%) rename src/{Microsoft.AspNetCore.HttpOverrides => Middleware/HttpOverrides/src}/baseline.net45.json (100%) rename src/{Microsoft.AspNetCore.HttpOverrides => Middleware/HttpOverrides/src}/baseline.netcore.json (100%) rename {test/Microsoft.AspNetCore.HttpOverrides.Tests => src/Middleware/HttpOverrides/test}/ForwardedHeadersMiddlewareTest.cs (100%) rename {test/Microsoft.AspNetCore.HttpOverrides.Tests => src/Middleware/HttpOverrides/test}/HttpMethodOverrideMiddlewareTest.cs (100%) rename {test/Microsoft.AspNetCore.HttpOverrides.Tests => src/Middleware/HttpOverrides/test}/IPEndPointParserTest.cs (100%) rename {test/Microsoft.AspNetCore.HttpOverrides.Tests => src/Middleware/HttpOverrides/test}/IPNetworkTest.cs (100%) rename test/Microsoft.AspNetCore.Buffering.Tests/Microsoft.AspNetCore.Buffering.Tests.csproj => src/Middleware/HttpOverrides/test/Microsoft.AspNetCore.HttpOverrides.Tests.csproj (58%) create mode 100644 src/Middleware/HttpsPolicy/sample/HttpsPolicySample.csproj rename {samples/HttpsPolicySample => src/Middleware/HttpsPolicy/sample}/Properties/launchSettings.json (100%) rename {samples/HttpsPolicySample => src/Middleware/HttpsPolicy/sample}/Startup.cs (100%) rename {samples/HttpsPolicySample => src/Middleware/HttpsPolicy/sample}/testCert.pfx (100%) rename src/{Microsoft.AspNetCore.HttpsPolicy => Middleware/HttpsPolicy/src}/HstsBuilderExtensions.cs (100%) rename src/{Microsoft.AspNetCore.HttpsPolicy => Middleware/HttpsPolicy/src}/HstsMiddleware.cs (100%) rename src/{Microsoft.AspNetCore.HttpsPolicy => Middleware/HttpsPolicy/src}/HstsOptions.cs (100%) rename src/{Microsoft.AspNetCore.HttpsPolicy => Middleware/HttpsPolicy/src}/HstsServicesExtensions.cs (100%) rename src/{Microsoft.AspNetCore.HttpsPolicy => Middleware/HttpsPolicy/src}/HttpsRedirectionBuilderExtensions.cs (100%) rename src/{Microsoft.AspNetCore.HttpsPolicy => Middleware/HttpsPolicy/src}/HttpsRedirectionMiddleware.cs (100%) rename src/{Microsoft.AspNetCore.HttpsPolicy => Middleware/HttpsPolicy/src}/HttpsRedirectionOptions.cs (100%) rename src/{Microsoft.AspNetCore.HttpsPolicy => Middleware/HttpsPolicy/src}/HttpsRedirectionServicesExtensions.cs (100%) create mode 100644 src/Middleware/HttpsPolicy/src/Microsoft.AspNetCore.HttpsPolicy.csproj rename src/{Microsoft.AspNetCore.HttpsPolicy => Middleware/HttpsPolicy/src}/baseline.netcore.json (100%) rename src/{Microsoft.AspNetCore.HttpsPolicy => Middleware/HttpsPolicy/src}/internal/HttpsLoggingExtensions.cs (100%) rename {test/Microsoft.AspNetCore.HttpsPolicy.Tests => src/Middleware/HttpsPolicy/test}/HstsMiddlewareTests.cs (100%) rename {test/Microsoft.AspNetCore.HttpsPolicy.Tests => src/Middleware/HttpsPolicy/test}/HttpsPolicyTests.cs (100%) rename {test/Microsoft.AspNetCore.HttpsPolicy.Tests => src/Middleware/HttpsPolicy/test}/HttpsRedirectionMiddlewareTests.cs (100%) rename {test/Microsoft.AspNetCore.HttpsPolicy.Tests => src/Middleware/HttpsPolicy/test}/Microsoft.AspNetCore.HttpsPolicy.Tests.csproj (50%) rename {samples/ResponseCompressionSample => src/Middleware/ResponseCompression/sample}/CustomCompressionProvider.cs (100%) rename {samples/ResponseCompressionSample => src/Middleware/ResponseCompression/sample}/LoremIpsum.cs (100%) rename {samples/ResponseCompressionSample => src/Middleware/ResponseCompression/sample}/Properties/launchSettings.json (100%) create mode 100644 src/Middleware/ResponseCompression/sample/ResponseCompressionSample.csproj rename {samples/ResponseCompressionSample => src/Middleware/ResponseCompression/sample}/Startup.cs (100%) rename {samples/ResponseCompressionSample => src/Middleware/ResponseCompression/sample}/testfile1kb.txt (100%) rename src/{Microsoft.AspNetCore.ResponseCompression => Middleware/ResponseCompression/src}/BodyWrapperStream.cs (100%) rename src/{Microsoft.AspNetCore.ResponseCompression => Middleware/ResponseCompression/src}/CompressionProviderCollection.cs (100%) rename src/{Microsoft.AspNetCore.ResponseCompression => Middleware/ResponseCompression/src}/CompressionProviderFactory.cs (100%) rename src/{Microsoft.AspNetCore.ResponseCompression => Middleware/ResponseCompression/src}/GzipCompressionProvider.cs (100%) rename src/{Microsoft.AspNetCore.ResponseCompression => Middleware/ResponseCompression/src}/GzipCompressionProviderOptions.cs (100%) rename src/{Microsoft.AspNetCore.ResponseCompression => Middleware/ResponseCompression/src}/ICompressionProvider.cs (100%) rename src/{Microsoft.AspNetCore.ResponseCompression => Middleware/ResponseCompression/src}/IResponseCompressionProvider.cs (100%) rename src/{Microsoft.AspNetCore.ResponseCompression => Middleware/ResponseCompression/src}/Microsoft.AspNetCore.ResponseCompression.csproj (59%) rename src/{Microsoft.AspNetCore.ResponseCompression => Middleware/ResponseCompression/src}/Properties/AssemblyInfo.cs (100%) rename src/{Microsoft.AspNetCore.ResponseCompression => Middleware/ResponseCompression/src}/ResponseCompressionBuilderExtensions.cs (100%) rename src/{Microsoft.AspNetCore.ResponseCompression => Middleware/ResponseCompression/src}/ResponseCompressionDefaults.cs (100%) rename src/{Microsoft.AspNetCore.ResponseCompression => Middleware/ResponseCompression/src}/ResponseCompressionMiddleware.cs (100%) rename src/{Microsoft.AspNetCore.ResponseCompression => Middleware/ResponseCompression/src}/ResponseCompressionOptions.cs (100%) rename src/{Microsoft.AspNetCore.ResponseCompression => Middleware/ResponseCompression/src}/ResponseCompressionProvider.cs (100%) rename src/{Microsoft.AspNetCore.ResponseCompression => Middleware/ResponseCompression/src}/ResponseCompressionServicesExtensions.cs (100%) rename src/{Microsoft.AspNetCore.ResponseCompression => Middleware/ResponseCompression/src}/baseline.netcore.json (100%) rename src/{Microsoft.AspNetCore.ResponseCompression => Middleware/ResponseCompression/src}/baseline.netframework.json (100%) rename {test/Microsoft.AspNetCore.ResponseCompression.Tests => src/Middleware/ResponseCompression/test}/BodyWrapperStreamTests.cs (100%) create mode 100644 src/Middleware/ResponseCompression/test/Microsoft.AspNetCore.ResponseCompression.Tests.csproj rename {test/Microsoft.AspNetCore.ResponseCompression.Tests => src/Middleware/ResponseCompression/test}/ResponseCompressionMiddlewareTest.cs (100%) rename {test/Microsoft.AspNetCore.ResponseCompression.Tests => src/Middleware/ResponseCompression/test}/testfile1kb.txt (100%) rename {samples/RewriteSample => src/Middleware/Rewrite/sample}/Properties/launchSettings.json (100%) rename {samples/RewriteSample => src/Middleware/Rewrite/sample}/Rewrite.txt (100%) create mode 100644 src/Middleware/Rewrite/sample/RewriteSample.csproj rename {samples/RewriteSample => src/Middleware/Rewrite/sample}/Startup.cs (100%) rename {samples/RewriteSample => src/Middleware/Rewrite/sample}/UrlRewrite.xml (100%) rename {samples/RewriteSample => src/Middleware/Rewrite/sample}/testCert.pfx (100%) rename src/{Microsoft.AspNetCore.Rewrite => Middleware/Rewrite/src}/ApacheModRewriteOptionsExtensions.cs (100%) rename src/{Microsoft.AspNetCore.Rewrite => Middleware/Rewrite/src}/Extensions/RewriteMiddlewareLoggingExtensions.cs (100%) rename src/{Microsoft.AspNetCore.Rewrite => Middleware/Rewrite/src}/IISUrlRewriteOptionsExtensions.cs (100%) rename src/{Microsoft.AspNetCore.Rewrite => Middleware/Rewrite/src}/IRule.cs (100%) rename src/{Microsoft.AspNetCore.Rewrite => Middleware/Rewrite/src}/Internal/ApacheModRewrite/ApacheModRewriteRule.cs (100%) rename src/{Microsoft.AspNetCore.Rewrite => Middleware/Rewrite/src}/Internal/ApacheModRewrite/Condition.cs (100%) rename src/{Microsoft.AspNetCore.Rewrite => Middleware/Rewrite/src}/Internal/ApacheModRewrite/ConditionEvaluator.cs (100%) rename src/{Microsoft.AspNetCore.Rewrite => Middleware/Rewrite/src}/Internal/ApacheModRewrite/ConditionPatternParser.cs (100%) rename src/{Microsoft.AspNetCore.Rewrite => Middleware/Rewrite/src}/Internal/ApacheModRewrite/ConditionType.cs (100%) rename src/{Microsoft.AspNetCore.Rewrite => Middleware/Rewrite/src}/Internal/ApacheModRewrite/CookieActionFactory.cs (100%) rename src/{Microsoft.AspNetCore.Rewrite => Middleware/Rewrite/src}/Internal/ApacheModRewrite/FileParser.cs (100%) rename src/{Microsoft.AspNetCore.Rewrite => Middleware/Rewrite/src}/Internal/ApacheModRewrite/FlagParser.cs (100%) rename src/{Microsoft.AspNetCore.Rewrite => Middleware/Rewrite/src}/Internal/ApacheModRewrite/FlagType.cs (100%) rename src/{Microsoft.AspNetCore.Rewrite => Middleware/Rewrite/src}/Internal/ApacheModRewrite/Flags.cs (100%) rename src/{Microsoft.AspNetCore.Rewrite => Middleware/Rewrite/src}/Internal/ApacheModRewrite/OperationType.cs (100%) rename src/{Microsoft.AspNetCore.Rewrite => Middleware/Rewrite/src}/Internal/ApacheModRewrite/ParsedModRewriteCondition.cs (100%) rename src/{Microsoft.AspNetCore.Rewrite => Middleware/Rewrite/src}/Internal/ApacheModRewrite/RuleBuilder.cs (100%) rename src/{Microsoft.AspNetCore.Rewrite => Middleware/Rewrite/src}/Internal/ApacheModRewrite/RuleRegexParser.cs (100%) rename src/{Microsoft.AspNetCore.Rewrite => Middleware/Rewrite/src}/Internal/ApacheModRewrite/SegmentType.cs (100%) rename src/{Microsoft.AspNetCore.Rewrite => Middleware/Rewrite/src}/Internal/ApacheModRewrite/ServerVariables.cs (100%) rename src/{Microsoft.AspNetCore.Rewrite => Middleware/Rewrite/src}/Internal/ApacheModRewrite/TestStringParser.cs (100%) rename src/{Microsoft.AspNetCore.Rewrite => Middleware/Rewrite/src}/Internal/ApacheModRewrite/Tokenizer.cs (100%) rename src/{Microsoft.AspNetCore.Rewrite => Middleware/Rewrite/src}/Internal/BackReferenceCollection.cs (100%) rename src/{Microsoft.AspNetCore.Rewrite => Middleware/Rewrite/src}/Internal/DelegateRule.cs (100%) rename src/{Microsoft.AspNetCore.Rewrite => Middleware/Rewrite/src}/Internal/IISUrlRewrite/ActionType.cs (100%) rename src/{Microsoft.AspNetCore.Rewrite => Middleware/Rewrite/src}/Internal/IISUrlRewrite/Condition.cs (100%) rename src/{Microsoft.AspNetCore.Rewrite => Middleware/Rewrite/src}/Internal/IISUrlRewrite/ConditionCollection.cs (100%) rename src/{Microsoft.AspNetCore.Rewrite => Middleware/Rewrite/src}/Internal/IISUrlRewrite/ConditionEvaluator.cs (100%) rename src/{Microsoft.AspNetCore.Rewrite => Middleware/Rewrite/src}/Internal/IISUrlRewrite/IISRewriteMap.cs (100%) rename src/{Microsoft.AspNetCore.Rewrite => Middleware/Rewrite/src}/Internal/IISUrlRewrite/IISRewriteMapCollection.cs (100%) rename src/{Microsoft.AspNetCore.Rewrite => Middleware/Rewrite/src}/Internal/IISUrlRewrite/IISUrlRewriteRule.cs (100%) rename src/{Microsoft.AspNetCore.Rewrite => Middleware/Rewrite/src}/Internal/IISUrlRewrite/InputParser.cs (100%) rename src/{Microsoft.AspNetCore.Rewrite => Middleware/Rewrite/src}/Internal/IISUrlRewrite/InvalidUrlRewriteFormatException.cs (100%) rename src/{Microsoft.AspNetCore.Rewrite => Middleware/Rewrite/src}/Internal/IISUrlRewrite/LogicalGrouping.cs (100%) rename src/{Microsoft.AspNetCore.Rewrite => Middleware/Rewrite/src}/Internal/IISUrlRewrite/MatchType.cs (100%) rename src/{Microsoft.AspNetCore.Rewrite => Middleware/Rewrite/src}/Internal/IISUrlRewrite/PatternSyntax.cs (100%) rename src/{Microsoft.AspNetCore.Rewrite => Middleware/Rewrite/src}/Internal/IISUrlRewrite/RedirectType.cs (100%) rename src/{Microsoft.AspNetCore.Rewrite => Middleware/Rewrite/src}/Internal/IISUrlRewrite/RewriteMapParser.cs (100%) rename src/{Microsoft.AspNetCore.Rewrite => Middleware/Rewrite/src}/Internal/IISUrlRewrite/RewriteTags.cs (100%) rename src/{Microsoft.AspNetCore.Rewrite => Middleware/Rewrite/src}/Internal/IISUrlRewrite/ServerVariables.cs (100%) rename src/{Microsoft.AspNetCore.Rewrite => Middleware/Rewrite/src}/Internal/IISUrlRewrite/UriMatchCondition.cs (100%) rename src/{Microsoft.AspNetCore.Rewrite => Middleware/Rewrite/src}/Internal/IISUrlRewrite/UriMatchPart.cs (100%) rename src/{Microsoft.AspNetCore.Rewrite => Middleware/Rewrite/src}/Internal/IISUrlRewrite/UrlRewriteFileParser.cs (100%) rename src/{Microsoft.AspNetCore.Rewrite => Middleware/Rewrite/src}/Internal/IISUrlRewrite/UrlRewriteRuleBuilder.cs (100%) rename src/{Microsoft.AspNetCore.Rewrite => Middleware/Rewrite/src}/Internal/MatchResults.cs (100%) rename src/{Microsoft.AspNetCore.Rewrite => Middleware/Rewrite/src}/Internal/ParserContext.cs (100%) rename src/{Microsoft.AspNetCore.Rewrite => Middleware/Rewrite/src}/Internal/Pattern.cs (100%) rename src/{Microsoft.AspNetCore.Rewrite => Middleware/Rewrite/src}/Internal/PatternSegment.cs (100%) rename src/{Microsoft.AspNetCore.Rewrite => Middleware/Rewrite/src}/Internal/PatternSegments/ConditionMatchSegment.cs (100%) rename src/{Microsoft.AspNetCore.Rewrite => Middleware/Rewrite/src}/Internal/PatternSegments/DateTimeSegment.cs (100%) rename src/{Microsoft.AspNetCore.Rewrite => Middleware/Rewrite/src}/Internal/PatternSegments/HeaderSegment.cs (100%) rename src/{Microsoft.AspNetCore.Rewrite => Middleware/Rewrite/src}/Internal/PatternSegments/IsHttpsModSegment.cs (100%) rename src/{Microsoft.AspNetCore.Rewrite => Middleware/Rewrite/src}/Internal/PatternSegments/IsHttpsUrlSegment.cs (100%) rename src/{Microsoft.AspNetCore.Rewrite => Middleware/Rewrite/src}/Internal/PatternSegments/IsIPV6Segment.cs (100%) rename src/{Microsoft.AspNetCore.Rewrite => Middleware/Rewrite/src}/Internal/PatternSegments/LiteralSegment.cs (100%) rename src/{Microsoft.AspNetCore.Rewrite => Middleware/Rewrite/src}/Internal/PatternSegments/LocalAddressSegment.cs (100%) rename src/{Microsoft.AspNetCore.Rewrite => Middleware/Rewrite/src}/Internal/PatternSegments/LocalPortSegment.cs (100%) rename src/{Microsoft.AspNetCore.Rewrite => Middleware/Rewrite/src}/Internal/PatternSegments/QueryStringSegment.cs (100%) rename src/{Microsoft.AspNetCore.Rewrite => Middleware/Rewrite/src}/Internal/PatternSegments/RemoteAddressSegment.cs (100%) rename src/{Microsoft.AspNetCore.Rewrite => Middleware/Rewrite/src}/Internal/PatternSegments/RemotePortSegment.cs (100%) rename src/{Microsoft.AspNetCore.Rewrite => Middleware/Rewrite/src}/Internal/PatternSegments/RequestFilenameSegment.cs (100%) rename src/{Microsoft.AspNetCore.Rewrite => Middleware/Rewrite/src}/Internal/PatternSegments/RequestMethodSegment.cs (100%) rename src/{Microsoft.AspNetCore.Rewrite => Middleware/Rewrite/src}/Internal/PatternSegments/RewriteMapSegment.cs (100%) rename src/{Microsoft.AspNetCore.Rewrite => Middleware/Rewrite/src}/Internal/PatternSegments/RuleMatchSegment.cs (100%) rename src/{Microsoft.AspNetCore.Rewrite => Middleware/Rewrite/src}/Internal/PatternSegments/SchemeSegment.cs (100%) rename src/{Microsoft.AspNetCore.Rewrite => Middleware/Rewrite/src}/Internal/PatternSegments/ServerProtocolSegment.cs (100%) rename src/{Microsoft.AspNetCore.Rewrite => Middleware/Rewrite/src}/Internal/PatternSegments/ToLowerSegment.cs (100%) rename src/{Microsoft.AspNetCore.Rewrite => Middleware/Rewrite/src}/Internal/PatternSegments/UrlEncodeSegment.cs (100%) rename src/{Microsoft.AspNetCore.Rewrite => Middleware/Rewrite/src}/Internal/PatternSegments/UrlSegment.cs (100%) rename src/{Microsoft.AspNetCore.Rewrite => Middleware/Rewrite/src}/Internal/RedirectRule.cs (100%) rename src/{Microsoft.AspNetCore.Rewrite => Middleware/Rewrite/src}/Internal/RedirectToHttpsRule.cs (100%) rename src/{Microsoft.AspNetCore.Rewrite => Middleware/Rewrite/src}/Internal/RedirectToWwwRule.cs (100%) rename src/{Microsoft.AspNetCore.Rewrite => Middleware/Rewrite/src}/Internal/RewriteRule.cs (100%) rename src/{Microsoft.AspNetCore.Rewrite => Middleware/Rewrite/src}/Internal/UrlAction.cs (100%) rename src/{Microsoft.AspNetCore.Rewrite => Middleware/Rewrite/src}/Internal/UrlActions/AbortAction.cs (100%) rename src/{Microsoft.AspNetCore.Rewrite => Middleware/Rewrite/src}/Internal/UrlActions/ChangeCookieAction.cs (100%) rename src/{Microsoft.AspNetCore.Rewrite => Middleware/Rewrite/src}/Internal/UrlActions/CustomResponseAction.cs (100%) rename src/{Microsoft.AspNetCore.Rewrite => Middleware/Rewrite/src}/Internal/UrlActions/ForbiddenAction.cs (100%) rename src/{Microsoft.AspNetCore.Rewrite => Middleware/Rewrite/src}/Internal/UrlActions/GoneAction.cs (100%) rename src/{Microsoft.AspNetCore.Rewrite => Middleware/Rewrite/src}/Internal/UrlActions/NoneAction.cs (100%) rename src/{Microsoft.AspNetCore.Rewrite => Middleware/Rewrite/src}/Internal/UrlActions/RedirectAction.cs (100%) rename src/{Microsoft.AspNetCore.Rewrite => Middleware/Rewrite/src}/Internal/UrlActions/RewriteAction.cs (100%) rename src/{Microsoft.AspNetCore.Rewrite => Middleware/Rewrite/src}/Internal/UrlMatch.cs (100%) rename src/{Microsoft.AspNetCore.Rewrite => Middleware/Rewrite/src}/Internal/UrlMatches/ExactMatch.cs (100%) rename src/{Microsoft.AspNetCore.Rewrite => Middleware/Rewrite/src}/Internal/UrlMatches/FileSizeMatch.cs (100%) rename src/{Microsoft.AspNetCore.Rewrite => Middleware/Rewrite/src}/Internal/UrlMatches/IntegerMatch.cs (100%) rename src/{Microsoft.AspNetCore.Rewrite => Middleware/Rewrite/src}/Internal/UrlMatches/IntegerOperation.cs (100%) rename src/{Microsoft.AspNetCore.Rewrite => Middleware/Rewrite/src}/Internal/UrlMatches/IsDirectoryMatch.cs (100%) rename src/{Microsoft.AspNetCore.Rewrite => Middleware/Rewrite/src}/Internal/UrlMatches/IsFileMatch.cs (100%) rename src/{Microsoft.AspNetCore.Rewrite => Middleware/Rewrite/src}/Internal/UrlMatches/RegexMatch.cs (100%) rename src/{Microsoft.AspNetCore.Rewrite => Middleware/Rewrite/src}/Internal/UrlMatches/StringMatch.cs (100%) rename src/{Microsoft.AspNetCore.Rewrite => Middleware/Rewrite/src}/Internal/UrlMatches/StringOperation.cs (100%) create mode 100644 src/Middleware/Rewrite/src/Microsoft.AspNetCore.Rewrite.csproj rename src/{Microsoft.AspNetCore.Rewrite => Middleware/Rewrite/src}/Properties/AssemblyInfo.cs (100%) rename src/{Microsoft.AspNetCore.Rewrite => Middleware/Rewrite/src}/Properties/Resources.Designer.cs (100%) rename src/{Microsoft.AspNetCore.Rewrite => Middleware/Rewrite/src}/Resources.resx (100%) rename src/{Microsoft.AspNetCore.Rewrite => Middleware/Rewrite/src}/RewriteBuilderExtensions.cs (100%) rename src/{Microsoft.AspNetCore.Rewrite => Middleware/Rewrite/src}/RewriteContext.cs (100%) rename src/{Microsoft.AspNetCore.Rewrite => Middleware/Rewrite/src}/RewriteMiddleware.cs (100%) rename src/{Microsoft.AspNetCore.Rewrite => Middleware/Rewrite/src}/RewriteOptions.cs (100%) rename src/{Microsoft.AspNetCore.Rewrite => Middleware/Rewrite/src}/RewriteOptionsExtensions.cs (100%) rename src/{Microsoft.AspNetCore.Rewrite => Middleware/Rewrite/src}/RuleResult.cs (100%) rename src/{Microsoft.AspNetCore.Rewrite => Middleware/Rewrite/src}/baseline.netcore.json (100%) rename {test/Microsoft.AspNetCore.Rewrite.Tests => src/Middleware/Rewrite/test}/ApacheModRewrite/ConditionPatternParserTest.cs (100%) rename {test/Microsoft.AspNetCore.Rewrite.Tests => src/Middleware/Rewrite/test}/ApacheModRewrite/CookieActionFactoryTest.cs (100%) rename {test/Microsoft.AspNetCore.Rewrite.Tests => src/Middleware/Rewrite/test}/ApacheModRewrite/FlagParserTest.cs (100%) rename {test/Microsoft.AspNetCore.Rewrite.Tests => src/Middleware/Rewrite/test}/ApacheModRewrite/FormatExceptionTests.cs (100%) rename {test/Microsoft.AspNetCore.Rewrite.Tests => src/Middleware/Rewrite/test}/ApacheModRewrite/ModRewriteMiddlewareTest.cs (100%) rename {test/Microsoft.AspNetCore.Rewrite.Tests => src/Middleware/Rewrite/test}/ApacheModRewrite/RewriteTokenizerTest.cs (100%) rename {test/Microsoft.AspNetCore.Rewrite.Tests => src/Middleware/Rewrite/test}/ApacheModRewrite/RuleBuilderTest.cs (100%) rename {test/Microsoft.AspNetCore.Rewrite.Tests => src/Middleware/Rewrite/test}/ApacheModRewrite/RuleRegexParserTest.cs (100%) rename {test/Microsoft.AspNetCore.Rewrite.Tests => src/Middleware/Rewrite/test}/ApacheModRewrite/TestStringParserTests.cs (100%) rename {test/Microsoft.AspNetCore.Rewrite.Tests => src/Middleware/Rewrite/test}/IISUrlRewrite/FileParserTests.cs (100%) rename {test/Microsoft.AspNetCore.Rewrite.Tests => src/Middleware/Rewrite/test}/IISUrlRewrite/FormatExceptionHandlingTests.cs (100%) rename {test/Microsoft.AspNetCore.Rewrite.Tests => src/Middleware/Rewrite/test}/IISUrlRewrite/InputParserTests.cs (100%) rename {test/Microsoft.AspNetCore.Rewrite.Tests => src/Middleware/Rewrite/test}/IISUrlRewrite/InvalidUrlRewriteFormatExceptionHandlingTests.cs (100%) rename {test/Microsoft.AspNetCore.Rewrite.Tests => src/Middleware/Rewrite/test}/IISUrlRewrite/MiddleWareTests.cs (100%) rename {test/Microsoft.AspNetCore.Rewrite.Tests => src/Middleware/Rewrite/test}/IISUrlRewrite/RewriteMapParserTests.cs (100%) rename {test/Microsoft.AspNetCore.Rewrite.Tests => src/Middleware/Rewrite/test}/IISUrlRewrite/ServerVariableTests.cs (100%) rename {test/Microsoft.AspNetCore.Rewrite.Tests => src/Middleware/Rewrite/test}/IISUrlRewrite/UrlRewriteApplicationTests.cs (100%) rename {test/Microsoft.AspNetCore.Rewrite.Tests => src/Middleware/Rewrite/test}/Microsoft.AspNetCore.Rewrite.Tests.csproj (61%) rename {test/Microsoft.AspNetCore.Rewrite.Tests => src/Middleware/Rewrite/test}/MiddlewareTests.cs (100%) rename {test/Microsoft.AspNetCore.Rewrite.Tests => src/Middleware/Rewrite/test}/PatternSegments/ConditionMatchSegmentTests.cs (100%) rename {test/Microsoft.AspNetCore.Rewrite.Tests => src/Middleware/Rewrite/test}/PatternSegments/DateTimeSegmentTests.cs (100%) rename {test/Microsoft.AspNetCore.Rewrite.Tests => src/Middleware/Rewrite/test}/PatternSegments/HeaderSegmentTests.cs (100%) rename {test/Microsoft.AspNetCore.Rewrite.Tests => src/Middleware/Rewrite/test}/PatternSegments/IsHttpsModSegmentTests.cs (100%) rename {test/Microsoft.AspNetCore.Rewrite.Tests => src/Middleware/Rewrite/test}/PatternSegments/IsHttpsSegmentTests.cs (100%) rename {test/Microsoft.AspNetCore.Rewrite.Tests => src/Middleware/Rewrite/test}/PatternSegments/IsIPV6SegmentTests.cs (100%) rename {test/Microsoft.AspNetCore.Rewrite.Tests => src/Middleware/Rewrite/test}/PatternSegments/LIteralSegmentTests.cs (100%) rename {test/Microsoft.AspNetCore.Rewrite.Tests => src/Middleware/Rewrite/test}/PatternSegments/LocalAddressSegmentTests.cs (100%) rename {test/Microsoft.AspNetCore.Rewrite.Tests => src/Middleware/Rewrite/test}/PatternSegments/LocalPortSegmentTests.cs (100%) rename {test/Microsoft.AspNetCore.Rewrite.Tests => src/Middleware/Rewrite/test}/PatternSegments/QueryStringSegmentTests.cs (100%) rename {test/Microsoft.AspNetCore.Rewrite.Tests => src/Middleware/Rewrite/test}/PatternSegments/RemoteAddressSegmentTests.cs (100%) rename {test/Microsoft.AspNetCore.Rewrite.Tests => src/Middleware/Rewrite/test}/PatternSegments/RemotePortSegmentTests.cs (100%) rename {test/Microsoft.AspNetCore.Rewrite.Tests => src/Middleware/Rewrite/test}/PatternSegments/RequestFilenameSegmentTests.cs (100%) rename {test/Microsoft.AspNetCore.Rewrite.Tests => src/Middleware/Rewrite/test}/PatternSegments/RequestMethodSegmentTests.cs (100%) rename {test/Microsoft.AspNetCore.Rewrite.Tests => src/Middleware/Rewrite/test}/PatternSegments/RuleMatchSegmentTests.cs (100%) rename {test/Microsoft.AspNetCore.Rewrite.Tests => src/Middleware/Rewrite/test}/PatternSegments/SchemeSegmentTests.cs (100%) rename {test/Microsoft.AspNetCore.Rewrite.Tests => src/Middleware/Rewrite/test}/PatternSegments/ServerProtocolSegmentTests.cs (100%) rename {test/Microsoft.AspNetCore.Rewrite.Tests => src/Middleware/Rewrite/test}/PatternSegments/ToLowerSegmentTests.cs (100%) rename {test/Microsoft.AspNetCore.Rewrite.Tests => src/Middleware/Rewrite/test}/PatternSegments/UrlEncodeSegmentTests.cs (100%) rename {test/Microsoft.AspNetCore.Rewrite.Tests => src/Middleware/Rewrite/test}/PatternSegments/UrlSegmentTests.cs (100%) rename {test/Microsoft.AspNetCore.Rewrite.Tests => src/Middleware/Rewrite/test}/UrlActions/AbortActionTests.cs (100%) rename {test/Microsoft.AspNetCore.Rewrite.Tests => src/Middleware/Rewrite/test}/UrlActions/ChangeCookieActionTests.cs (100%) rename {test/Microsoft.AspNetCore.Rewrite.Tests => src/Middleware/Rewrite/test}/UrlActions/ForbiddenActionTests.cs (100%) rename {test/Microsoft.AspNetCore.Rewrite.Tests => src/Middleware/Rewrite/test}/UrlActions/GoneActionTests.cs (100%) rename {test/Microsoft.AspNetCore.Rewrite.Tests => src/Middleware/Rewrite/test}/UrlMatches/ExactMatchTests.cs (100%) rename {test/Microsoft.AspNetCore.Rewrite.Tests => src/Middleware/Rewrite/test}/UrlMatches/IntegerMatchTests.cs (100%) rename {test/Microsoft.AspNetCore.Rewrite.Tests => src/Middleware/Rewrite/test}/UrlMatches/StringMatchTests.cs (100%) delete mode 100644 test/Directory.Build.props delete mode 100644 test/Microsoft.AspNetCore.Buffering.Tests/ResponseBufferingMiddlewareTests.cs delete mode 100644 test/Microsoft.AspNetCore.HostFiltering.Tests/Microsoft.AspNetCore.HostFiltering.Tests.csproj delete mode 100644 test/Microsoft.AspNetCore.HttpOverrides.Tests/Microsoft.AspNetCore.HttpOverrides.Tests.csproj delete mode 100644 test/Microsoft.AspNetCore.ResponseCompression.Tests/Microsoft.AspNetCore.ResponseCompression.Tests.csproj delete mode 100644 version.props diff --git a/.appveyor.yml b/.appveyor.yml deleted file mode 100644 index 4eea96ab69..0000000000 --- a/.appveyor.yml +++ /dev/null @@ -1,17 +0,0 @@ -init: -- git config --global core.autocrlf true -branches: - only: - - dev - - /^release\/.*$/ - - /^(.*\/)?ci-.*$/ -build_script: -- ps: .\run.ps1 default-build -clone_depth: 1 -environment: - global: - DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true - DOTNET_CLI_TELEMETRY_OPTOUT: 1 -test: 'off' -deploy: 'off' -os: Visual Studio 2017 diff --git a/.gitattributes b/.gitattributes deleted file mode 100644 index 66abdf279e..0000000000 --- a/.gitattributes +++ /dev/null @@ -1,51 +0,0 @@ -*.doc diff=astextplain -*.DOC diff=astextplain -*.docx diff=astextplain -*.DOCX diff=astextplain -*.dot diff=astextplain -*.DOT diff=astextplain -*.pdf diff=astextplain -*.PDF diff=astextplain -*.rtf diff=astextplain -*.RTF diff=astextplain - -*.jpg binary -*.png binary -*.gif binary - -*.cs text=auto diff=csharp -*.vb text=auto -*.resx text=auto -*.c text=auto -*.cpp text=auto -*.cxx text=auto -*.h text=auto -*.hxx text=auto -*.py text=auto -*.rb text=auto -*.java text=auto -*.html text=auto -*.htm text=auto -*.css text=auto -*.scss text=auto -*.sass text=auto -*.less text=auto -*.js text=auto -*.lisp text=auto -*.clj text=auto -*.sql text=auto -*.php text=auto -*.lua text=auto -*.m text=auto -*.asm text=auto -*.erl text=auto -*.fs text=auto -*.fsx text=auto -*.hs text=auto - -*.csproj text=auto -*.vbproj text=auto -*.fsproj text=auto -*.dbproj text=auto -*.sln text=auto eol=crlf -*.sh eol=lf \ No newline at end of file diff --git a/.gitignore b/.gitignore deleted file mode 100644 index c8dd6c52d5..0000000000 --- a/.gitignore +++ /dev/null @@ -1,35 +0,0 @@ -[Oo]bj/ -[Bb]in/ -TestResults/ -.nuget/ -*.sln.ide/ -_ReSharper.*/ -packages/ -artifacts/ -PublishProfiles/ -*.user -*.suo -*.cache -*.docstates -_ReSharper.* -nuget.exe -project.lock.json -*net45.csproj -*net451.csproj -*k10.csproj -*.psess -*.vsp -*.pidb -*.userprefs -*DS_Store -*.ncrunchsolution -*.*sdf -*.ipch -.vs/ -.build/ -.testPublish/ -.idea/ -.vscode/ -*.nuget.props -*.nuget.targets -global.json diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 64bdbb4441..0000000000 --- a/.travis.yml +++ /dev/null @@ -1,27 +0,0 @@ -language: csharp -sudo: false -dist: trusty -env: - global: - - DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true - - DOTNET_CLI_TELEMETRY_OPTOUT: 1 -mono: none -os: -- linux -- osx -osx_image: xcode8.2 -addons: - apt: - packages: - - libunwind8 -branches: - only: - - dev - - /^release\/.*$/ - - /^(.*\/)?ci-.*$/ -before_install: -- if test "$TRAVIS_OS_NAME" == "osx"; then brew update; brew install openssl; ln -s - /usr/local/opt/openssl/lib/libcrypto.1.0.0.dylib /usr/local/lib/; ln -s /usr/local/opt/openssl/lib/libssl.1.0.0.dylib - /usr/local/lib/; fi -script: -- ./build.sh diff --git a/BasicMiddleware.sln b/BasicMiddleware.sln deleted file mode 100644 index 8810201f5a..0000000000 --- a/BasicMiddleware.sln +++ /dev/null @@ -1,185 +0,0 @@ -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 15 -VisualStudioVersion = 15.0.27130.2027 -MinimumVisualStudioVersion = 15.0.26730.03 -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.HttpOverrides", "src\Microsoft.AspNetCore.HttpOverrides\Microsoft.AspNetCore.HttpOverrides.csproj", "{517308C3-B477-4B01-B461-CAB9C10B6928}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{A5076D28-FA7E-4606-9410-FEDD0D603527}" - ProjectSection(SolutionItems) = preProject - src\Directory.Build.props = src\Directory.Build.props - EndProjectSection -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{8437B0F3-3894-4828-A945-A9187F37631D}" - ProjectSection(SolutionItems) = preProject - test\Directory.Build.props = test\Directory.Build.props - EndProjectSection -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.HttpOverrides.Tests", "test\Microsoft.AspNetCore.HttpOverrides.Tests\Microsoft.AspNetCore.HttpOverrides.Tests.csproj", "{D6341B92-3416-4F11-8DF4-CB274296175F}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Buffering", "src\Microsoft.AspNetCore.Buffering\Microsoft.AspNetCore.Buffering.csproj", "{2363D0DD-A3BF-437E-9B64-B33AE132D875}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Buffering.Tests", "test\Microsoft.AspNetCore.Buffering.Tests\Microsoft.AspNetCore.Buffering.Tests.csproj", "{F5F1D123-9C81-4A9E-8644-AA46B8E578FB}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "samples", "samples", "{9587FE9F-5A17-42C4-8021-E87F59CECB98}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ResponseBufferingSample", "samples\ResponseBufferingSample\ResponseBufferingSample.csproj", "{E5C55B80-7827-40EB-B661-32B0E0E431CA}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "HttpOverridesSample", "samples\HttpOverridesSample\HttpOverridesSample.csproj", "{7F95478D-E1D4-4A64-BA42-B041591A96EB}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Rewrite", "src\Microsoft.AspNetCore.Rewrite\Microsoft.AspNetCore.Rewrite.csproj", "{0E7CA1A7-1DC3-4CE6-B9C7-1688FE1410F1}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RewriteSample", "samples\RewriteSample\RewriteSample.csproj", "{9E049645-13BC-4598-89E1-5B43D36E5D14}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Rewrite.Tests", "test\Microsoft.AspNetCore.Rewrite.Tests\Microsoft.AspNetCore.Rewrite.Tests.csproj", "{31794F9E-A1AA-4535-B03C-A3233737CD1A}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.ResponseCompression", "src\Microsoft.AspNetCore.ResponseCompression\Microsoft.AspNetCore.ResponseCompression.csproj", "{45308A9D-F4C6-46A8-A24F-E73D995CC223}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.ResponseCompression.Tests", "test\Microsoft.AspNetCore.ResponseCompression.Tests\Microsoft.AspNetCore.ResponseCompression.Tests.csproj", "{3360A5D1-70C0-49EE-9051-04A6A6B836DC}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ResponseCompressionSample", "samples\ResponseCompressionSample\ResponseCompressionSample.csproj", "{B2A3CE38-51B2-4486-982C-98C380AF140E}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{59A9B64C-E9BE-409E-89A2-58D72E2918F5}" - ProjectSection(SolutionItems) = preProject - .appveyor.yml = .appveyor.yml - .gitattributes = .gitattributes - .gitignore = .gitignore - .travis.yml = .travis.yml - build.cmd = build.cmd - build.ps1 = build.ps1 - build.sh = build.sh - CONTRIBUTING.md = CONTRIBUTING.md - Directory.Build.props = Directory.Build.props - Directory.Build.targets = Directory.Build.targets - LICENSE.txt = LICENSE.txt - NuGet.config = NuGet.config - NuGetPackageVerifier.json = NuGetPackageVerifier.json - README.md = README.md - version.xml = version.xml - EndProjectSection -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.HttpsPolicy", "src\Microsoft.AspNetCore.HttpsPolicy\Microsoft.AspNetCore.HttpsPolicy.csproj", "{4D39C29B-4EC8-497C-B411-922DA494D71B}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "HttpsPolicySample", "samples\HttpsPolicySample\HttpsPolicySample.csproj", "{AC424AEE-4883-49C6-945F-2FC916B8CA1C}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.HttpsPolicy.Tests", "test\Microsoft.AspNetCore.HttpsPolicy.Tests\Microsoft.AspNetCore.HttpsPolicy.Tests.csproj", "{1C67B0F1-6E70-449E-A2F1-98B9D5C576CE}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "HostFilteringSample", "samples\HostFilteringSample\HostFilteringSample.csproj", "{368B00A2-992A-4B0E-9085-A8136A22922D}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "build", "build", "{5CEA6F31-A829-4A02-8CD5-EC3DDD4CC1EA}" - ProjectSection(SolutionItems) = preProject - build\dependencies.props = build\dependencies.props - build\repo.props = build\repo.props - build\sources.props = build\sources.props - EndProjectSection -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.HostFiltering.Tests", "test\Microsoft.AspNetCore.HostFiltering.Tests\Microsoft.AspNetCore.HostFiltering.Tests.csproj", "{4BC947ED-13B8-4BE6-82A4-96A48D86980B}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.HostFiltering", "src\Microsoft.AspNetCore.HostFiltering\Microsoft.AspNetCore.HostFiltering.csproj", "{762F7276-C916-4111-A6C0-41668ABB3823}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Release|Any CPU = Release|Any CPU - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {517308C3-B477-4B01-B461-CAB9C10B6928}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {517308C3-B477-4B01-B461-CAB9C10B6928}.Debug|Any CPU.Build.0 = Debug|Any CPU - {517308C3-B477-4B01-B461-CAB9C10B6928}.Release|Any CPU.ActiveCfg = Release|Any CPU - {517308C3-B477-4B01-B461-CAB9C10B6928}.Release|Any CPU.Build.0 = Release|Any CPU - {D6341B92-3416-4F11-8DF4-CB274296175F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {D6341B92-3416-4F11-8DF4-CB274296175F}.Debug|Any CPU.Build.0 = Debug|Any CPU - {D6341B92-3416-4F11-8DF4-CB274296175F}.Release|Any CPU.ActiveCfg = Release|Any CPU - {D6341B92-3416-4F11-8DF4-CB274296175F}.Release|Any CPU.Build.0 = Release|Any CPU - {2363D0DD-A3BF-437E-9B64-B33AE132D875}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {2363D0DD-A3BF-437E-9B64-B33AE132D875}.Debug|Any CPU.Build.0 = Debug|Any CPU - {2363D0DD-A3BF-437E-9B64-B33AE132D875}.Release|Any CPU.ActiveCfg = Release|Any CPU - {2363D0DD-A3BF-437E-9B64-B33AE132D875}.Release|Any CPU.Build.0 = Release|Any CPU - {F5F1D123-9C81-4A9E-8644-AA46B8E578FB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {F5F1D123-9C81-4A9E-8644-AA46B8E578FB}.Debug|Any CPU.Build.0 = Debug|Any CPU - {F5F1D123-9C81-4A9E-8644-AA46B8E578FB}.Release|Any CPU.ActiveCfg = Release|Any CPU - {F5F1D123-9C81-4A9E-8644-AA46B8E578FB}.Release|Any CPU.Build.0 = Release|Any CPU - {E5C55B80-7827-40EB-B661-32B0E0E431CA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {E5C55B80-7827-40EB-B661-32B0E0E431CA}.Debug|Any CPU.Build.0 = Debug|Any CPU - {E5C55B80-7827-40EB-B661-32B0E0E431CA}.Release|Any CPU.ActiveCfg = Release|Any CPU - {E5C55B80-7827-40EB-B661-32B0E0E431CA}.Release|Any CPU.Build.0 = Release|Any CPU - {7F95478D-E1D4-4A64-BA42-B041591A96EB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {7F95478D-E1D4-4A64-BA42-B041591A96EB}.Debug|Any CPU.Build.0 = Debug|Any CPU - {7F95478D-E1D4-4A64-BA42-B041591A96EB}.Release|Any CPU.ActiveCfg = Release|Any CPU - {7F95478D-E1D4-4A64-BA42-B041591A96EB}.Release|Any CPU.Build.0 = Release|Any CPU - {0E7CA1A7-1DC3-4CE6-B9C7-1688FE1410F1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {0E7CA1A7-1DC3-4CE6-B9C7-1688FE1410F1}.Debug|Any CPU.Build.0 = Debug|Any CPU - {0E7CA1A7-1DC3-4CE6-B9C7-1688FE1410F1}.Release|Any CPU.ActiveCfg = Release|Any CPU - {0E7CA1A7-1DC3-4CE6-B9C7-1688FE1410F1}.Release|Any CPU.Build.0 = Release|Any CPU - {9E049645-13BC-4598-89E1-5B43D36E5D14}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {9E049645-13BC-4598-89E1-5B43D36E5D14}.Debug|Any CPU.Build.0 = Debug|Any CPU - {9E049645-13BC-4598-89E1-5B43D36E5D14}.Release|Any CPU.ActiveCfg = Release|Any CPU - {9E049645-13BC-4598-89E1-5B43D36E5D14}.Release|Any CPU.Build.0 = Release|Any CPU - {31794F9E-A1AA-4535-B03C-A3233737CD1A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {31794F9E-A1AA-4535-B03C-A3233737CD1A}.Debug|Any CPU.Build.0 = Debug|Any CPU - {31794F9E-A1AA-4535-B03C-A3233737CD1A}.Release|Any CPU.ActiveCfg = Release|Any CPU - {31794F9E-A1AA-4535-B03C-A3233737CD1A}.Release|Any CPU.Build.0 = Release|Any CPU - {45308A9D-F4C6-46A8-A24F-E73D995CC223}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {45308A9D-F4C6-46A8-A24F-E73D995CC223}.Debug|Any CPU.Build.0 = Debug|Any CPU - {45308A9D-F4C6-46A8-A24F-E73D995CC223}.Release|Any CPU.ActiveCfg = Release|Any CPU - {45308A9D-F4C6-46A8-A24F-E73D995CC223}.Release|Any CPU.Build.0 = Release|Any CPU - {3360A5D1-70C0-49EE-9051-04A6A6B836DC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {3360A5D1-70C0-49EE-9051-04A6A6B836DC}.Debug|Any CPU.Build.0 = Debug|Any CPU - {3360A5D1-70C0-49EE-9051-04A6A6B836DC}.Release|Any CPU.ActiveCfg = Release|Any CPU - {3360A5D1-70C0-49EE-9051-04A6A6B836DC}.Release|Any CPU.Build.0 = Release|Any CPU - {B2A3CE38-51B2-4486-982C-98C380AF140E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {B2A3CE38-51B2-4486-982C-98C380AF140E}.Debug|Any CPU.Build.0 = Debug|Any CPU - {B2A3CE38-51B2-4486-982C-98C380AF140E}.Release|Any CPU.ActiveCfg = Release|Any CPU - {B2A3CE38-51B2-4486-982C-98C380AF140E}.Release|Any CPU.Build.0 = Release|Any CPU - {4D39C29B-4EC8-497C-B411-922DA494D71B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {4D39C29B-4EC8-497C-B411-922DA494D71B}.Debug|Any CPU.Build.0 = Debug|Any CPU - {4D39C29B-4EC8-497C-B411-922DA494D71B}.Release|Any CPU.ActiveCfg = Release|Any CPU - {4D39C29B-4EC8-497C-B411-922DA494D71B}.Release|Any CPU.Build.0 = Release|Any CPU - {AC424AEE-4883-49C6-945F-2FC916B8CA1C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {AC424AEE-4883-49C6-945F-2FC916B8CA1C}.Debug|Any CPU.Build.0 = Debug|Any CPU - {AC424AEE-4883-49C6-945F-2FC916B8CA1C}.Release|Any CPU.ActiveCfg = Release|Any CPU - {AC424AEE-4883-49C6-945F-2FC916B8CA1C}.Release|Any CPU.Build.0 = Release|Any CPU - {1C67B0F1-6E70-449E-A2F1-98B9D5C576CE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {1C67B0F1-6E70-449E-A2F1-98B9D5C576CE}.Debug|Any CPU.Build.0 = Debug|Any CPU - {1C67B0F1-6E70-449E-A2F1-98B9D5C576CE}.Release|Any CPU.ActiveCfg = Release|Any CPU - {1C67B0F1-6E70-449E-A2F1-98B9D5C576CE}.Release|Any CPU.Build.0 = Release|Any CPU - {368B00A2-992A-4B0E-9085-A8136A22922D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {368B00A2-992A-4B0E-9085-A8136A22922D}.Debug|Any CPU.Build.0 = Debug|Any CPU - {368B00A2-992A-4B0E-9085-A8136A22922D}.Release|Any CPU.ActiveCfg = Release|Any CPU - {368B00A2-992A-4B0E-9085-A8136A22922D}.Release|Any CPU.Build.0 = Release|Any CPU - {4BC947ED-13B8-4BE6-82A4-96A48D86980B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {4BC947ED-13B8-4BE6-82A4-96A48D86980B}.Debug|Any CPU.Build.0 = Debug|Any CPU - {4BC947ED-13B8-4BE6-82A4-96A48D86980B}.Release|Any CPU.ActiveCfg = Release|Any CPU - {4BC947ED-13B8-4BE6-82A4-96A48D86980B}.Release|Any CPU.Build.0 = Release|Any CPU - {762F7276-C916-4111-A6C0-41668ABB3823}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {762F7276-C916-4111-A6C0-41668ABB3823}.Debug|Any CPU.Build.0 = Debug|Any CPU - {762F7276-C916-4111-A6C0-41668ABB3823}.Release|Any CPU.ActiveCfg = Release|Any CPU - {762F7276-C916-4111-A6C0-41668ABB3823}.Release|Any CPU.Build.0 = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(NestedProjects) = preSolution - {517308C3-B477-4B01-B461-CAB9C10B6928} = {A5076D28-FA7E-4606-9410-FEDD0D603527} - {D6341B92-3416-4F11-8DF4-CB274296175F} = {8437B0F3-3894-4828-A945-A9187F37631D} - {2363D0DD-A3BF-437E-9B64-B33AE132D875} = {A5076D28-FA7E-4606-9410-FEDD0D603527} - {F5F1D123-9C81-4A9E-8644-AA46B8E578FB} = {8437B0F3-3894-4828-A945-A9187F37631D} - {E5C55B80-7827-40EB-B661-32B0E0E431CA} = {9587FE9F-5A17-42C4-8021-E87F59CECB98} - {7F95478D-E1D4-4A64-BA42-B041591A96EB} = {9587FE9F-5A17-42C4-8021-E87F59CECB98} - {0E7CA1A7-1DC3-4CE6-B9C7-1688FE1410F1} = {A5076D28-FA7E-4606-9410-FEDD0D603527} - {9E049645-13BC-4598-89E1-5B43D36E5D14} = {9587FE9F-5A17-42C4-8021-E87F59CECB98} - {31794F9E-A1AA-4535-B03C-A3233737CD1A} = {8437B0F3-3894-4828-A945-A9187F37631D} - {45308A9D-F4C6-46A8-A24F-E73D995CC223} = {A5076D28-FA7E-4606-9410-FEDD0D603527} - {3360A5D1-70C0-49EE-9051-04A6A6B836DC} = {8437B0F3-3894-4828-A945-A9187F37631D} - {B2A3CE38-51B2-4486-982C-98C380AF140E} = {9587FE9F-5A17-42C4-8021-E87F59CECB98} - {4D39C29B-4EC8-497C-B411-922DA494D71B} = {A5076D28-FA7E-4606-9410-FEDD0D603527} - {AC424AEE-4883-49C6-945F-2FC916B8CA1C} = {9587FE9F-5A17-42C4-8021-E87F59CECB98} - {1C67B0F1-6E70-449E-A2F1-98B9D5C576CE} = {8437B0F3-3894-4828-A945-A9187F37631D} - {368B00A2-992A-4B0E-9085-A8136A22922D} = {9587FE9F-5A17-42C4-8021-E87F59CECB98} - {5CEA6F31-A829-4A02-8CD5-EC3DDD4CC1EA} = {59A9B64C-E9BE-409E-89A2-58D72E2918F5} - {4BC947ED-13B8-4BE6-82A4-96A48D86980B} = {8437B0F3-3894-4828-A945-A9187F37631D} - {762F7276-C916-4111-A6C0-41668ABB3823} = {A5076D28-FA7E-4606-9410-FEDD0D603527} - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {4518E9CE-3680-4E05-9259-B64EA7807158} - EndGlobalSection -EndGlobal diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md deleted file mode 100644 index 64ff041d5c..0000000000 --- a/CONTRIBUTING.md +++ /dev/null @@ -1,4 +0,0 @@ -Contributing -====== - -Information on contributing to this repo is in the [Contributing Guide](https://github.com/aspnet/Home/blob/dev/CONTRIBUTING.md) in the Home repo. diff --git a/Directory.Build.props b/Directory.Build.props deleted file mode 100644 index 0600ee6c34..0000000000 --- a/Directory.Build.props +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - - - Microsoft ASP.NET Core - https://github.com/aspnet/BasicMiddleware - git - $(MSBuildThisFileDirectory) - $(MSBuildThisFileDirectory)build\Key.snk - true - true - true - - - diff --git a/Directory.Build.targets b/Directory.Build.targets deleted file mode 100644 index 53b3f6e1da..0000000000 --- a/Directory.Build.targets +++ /dev/null @@ -1,7 +0,0 @@ - - - $(MicrosoftNETCoreApp20PackageVersion) - $(MicrosoftNETCoreApp21PackageVersion) - $(NETStandardLibrary20PackageVersion) - - diff --git a/LICENSE.txt b/LICENSE.txt deleted file mode 100644 index 7b2956ecee..0000000000 --- a/LICENSE.txt +++ /dev/null @@ -1,14 +0,0 @@ -Copyright (c) .NET Foundation and Contributors - -All rights reserved. - -Licensed under the Apache License, Version 2.0 (the "License"); you may not use -this file except in compliance with the License. You may obtain a copy of the -License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software distributed -under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR -CONDITIONS OF ANY KIND, either express or implied. See the License for the -specific language governing permissions and limitations under the License. diff --git a/NuGet.config b/NuGet.config deleted file mode 100644 index e32bddfd51..0000000000 --- a/NuGet.config +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/NuGetPackageVerifier.json b/NuGetPackageVerifier.json deleted file mode 100644 index b153ab1515..0000000000 --- a/NuGetPackageVerifier.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "Default": { - "rules": [ - "DefaultCompositeRule" - ] - } -} \ No newline at end of file diff --git a/README.md b/README.md deleted file mode 100644 index 1ce333f1b4..0000000000 --- a/README.md +++ /dev/null @@ -1,11 +0,0 @@ -ASP.NET Core Basic Middleware Components -======== - -AppVeyor: [![AppVeyor](https://ci.appveyor.com/api/projects/status/02a73gv9gq02jw0j/branch/dev?svg=true)](https://ci.appveyor.com/project/aspnetci/basicmiddleware/branch/dev) - -Travis: [![Travis](https://travis-ci.org/aspnet/BasicMiddleware.svg?branch=dev)](https://travis-ci.org/aspnet/BasicMiddleware) - -This repo hosts a collection of basic middleware components for ASP.NET Core. This includes Buffering, HTTP Overrides, Response Compression, and URL Rewriting. -The Rewrite middleware can import rules from IIS's UrlRewrite and Apache's mod_rewrite. - -This project is part of ASP.NET Core. You can find samples, documentation and getting started instructions for ASP.NET Core at the [Home](https://github.com/aspnet/home) repo. diff --git a/build.cmd b/build.cmd deleted file mode 100644 index c0050bda12..0000000000 --- a/build.cmd +++ /dev/null @@ -1,2 +0,0 @@ -@ECHO OFF -PowerShell -NoProfile -NoLogo -ExecutionPolicy unrestricted -Command "[System.Threading.Thread]::CurrentThread.CurrentCulture = ''; [System.Threading.Thread]::CurrentThread.CurrentUICulture = '';& '%~dp0run.ps1' default-build %*; exit $LASTEXITCODE" diff --git a/build.sh b/build.sh deleted file mode 100755 index 98a4b22765..0000000000 --- a/build.sh +++ /dev/null @@ -1,8 +0,0 @@ -#!/usr/bin/env bash - -set -euo pipefail -DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" - -# Call "sync" between "chmod" and execution to prevent "text file busy" error in Docker (aufs) -chmod +x "$DIR/run.sh"; sync -"$DIR/run.sh" default-build "$@" diff --git a/build/Key.snk b/build/Key.snk deleted file mode 100644 index e10e4889c125d3120cd9e81582243d70f7cbb806..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 596 zcmV-a0;~N80ssI2Bme+XQ$aES1ONa50098=Iw=HCsnz~#iVhm& zj%TU(_THUee?3yHBjk$37ysB?i5#7WD$={H zV4B!OxRPrb|8)HPg~A}8P>^=#y<)56#=E&NzcjOtPK~<4n6GHt=K$ro*T(lhby_@U zEk(hLzk1H)0yXj{A_5>fk-TgNoP|q6(tP2xo8zt8i%212CWM#AeCd?`hS|4~L({h~Moo(~vy&3Z z1uI}`fd^*>o=rwbAGymj6RM^pZm(*Kfhs+Y1#`-2JPWZMK8@;ZWCk2+9bX4YP);~fj-BU*R zQPvWv$89!{Rl9wM+zR>_TSkn^voYxA?2G iKnV#iZ6Ah`K>b=@=IjYJXrxL124zR(38)nxe+&q_$QXwJ diff --git a/build/dependencies.props b/build/dependencies.props deleted file mode 100644 index 8924c74e64..0000000000 --- a/build/dependencies.props +++ /dev/null @@ -1,43 +0,0 @@ - - - $(MSBuildAllProjects);$(MSBuildThisFileFullPath) - - - - - 2.1.3-rtm-15802 - 2.0.0 - 2.1.2 - 15.6.1 - 4.7.49 - 2.0.3 - 0.8.0 - 2.3.1 - 2.4.0-beta.1.build3945 - - - - - - - - 2.1.1 - 2.1.1 - 2.1.1 - 2.1.1 - 2.1.2 - 2.1.2 - 2.1.2 - 2.1.1 - 2.1.1 - 2.1.1 - 2.1.1 - 2.1.1 - 2.1.1 - 2.1.1 - 2.1.1 - 2.1.1 - 2.1.1 - 2.1.1 - - \ No newline at end of file diff --git a/build/repo.props b/build/repo.props deleted file mode 100644 index dab1601c88..0000000000 --- a/build/repo.props +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - Internal.AspNetCore.Universe.Lineup - 2.1.0-rc1-* - https://dotnet.myget.org/F/aspnetcore-dev/api/v3/index.json - - - - - - - diff --git a/build/sources.props b/build/sources.props deleted file mode 100644 index 9215df9751..0000000000 --- a/build/sources.props +++ /dev/null @@ -1,17 +0,0 @@ - - - - - $(DotNetRestoreSources) - - $(RestoreSources); - https://dotnet.myget.org/F/dotnet-core/api/v3/index.json; - https://dotnet.myget.org/F/aspnetcore-dev/api/v3/index.json; - https://dotnet.myget.org/F/aspnetcore-tools/api/v3/index.json; - - - $(RestoreSources); - https://api.nuget.org/v3/index.json; - - - diff --git a/korebuild-lock.txt b/korebuild-lock.txt deleted file mode 100644 index 251c227c83..0000000000 --- a/korebuild-lock.txt +++ /dev/null @@ -1,2 +0,0 @@ -version:2.1.3-rtm-15802 -commithash:a7c08b45b440a7d2058a0aa1eaa3eb6ba811976a diff --git a/korebuild.json b/korebuild.json deleted file mode 100644 index 678d8bb948..0000000000 --- a/korebuild.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "$schema": "https://raw.githubusercontent.com/aspnet/BuildTools/release/2.1/tools/korebuild.schema.json", - "channel": "release/2.1" -} diff --git a/run.cmd b/run.cmd deleted file mode 100644 index d52d5c7e68..0000000000 --- a/run.cmd +++ /dev/null @@ -1,2 +0,0 @@ -@ECHO OFF -PowerShell -NoProfile -NoLogo -ExecutionPolicy unrestricted -Command "[System.Threading.Thread]::CurrentThread.CurrentCulture = ''; [System.Threading.Thread]::CurrentThread.CurrentUICulture = '';& '%~dp0run.ps1' %*; exit $LASTEXITCODE" diff --git a/run.ps1 b/run.ps1 deleted file mode 100644 index 27dcf848f8..0000000000 --- a/run.ps1 +++ /dev/null @@ -1,196 +0,0 @@ -#!/usr/bin/env powershell -#requires -version 4 - -<# -.SYNOPSIS -Executes KoreBuild commands. - -.DESCRIPTION -Downloads korebuild if required. Then executes the KoreBuild command. To see available commands, execute with `-Command help`. - -.PARAMETER Command -The KoreBuild command to run. - -.PARAMETER Path -The folder to build. Defaults to the folder containing this script. - -.PARAMETER Channel -The channel of KoreBuild to download. Overrides the value from the config file. - -.PARAMETER DotNetHome -The directory where .NET Core tools will be stored. - -.PARAMETER ToolsSource -The base url where build tools can be downloaded. Overrides the value from the config file. - -.PARAMETER Update -Updates KoreBuild to the latest version even if a lock file is present. - -.PARAMETER ConfigFile -The path to the configuration file that stores values. Defaults to korebuild.json. - -.PARAMETER ToolsSourceSuffix -The Suffix to append to the end of the ToolsSource. Useful for query strings in blob stores. - -.PARAMETER Arguments -Arguments to be passed to the command - -.NOTES -This function will create a file $PSScriptRoot/korebuild-lock.txt. This lock file can be committed to source, but does not have to be. -When the lockfile is not present, KoreBuild will create one using latest available version from $Channel. - -The $ConfigFile is expected to be an JSON file. It is optional, and the configuration values in it are optional as well. Any options set -in the file are overridden by command line parameters. - -.EXAMPLE -Example config file: -```json -{ - "$schema": "https://raw.githubusercontent.com/aspnet/BuildTools/dev/tools/korebuild.schema.json", - "channel": "dev", - "toolsSource": "https://aspnetcore.blob.core.windows.net/buildtools" -} -``` -#> -[CmdletBinding(PositionalBinding = $false)] -param( - [Parameter(Mandatory = $true, Position = 0)] - [string]$Command, - [string]$Path = $PSScriptRoot, - [Alias('c')] - [string]$Channel, - [Alias('d')] - [string]$DotNetHome, - [Alias('s')] - [string]$ToolsSource, - [Alias('u')] - [switch]$Update, - [string]$ConfigFile, - [string]$ToolsSourceSuffix, - [Parameter(ValueFromRemainingArguments = $true)] - [string[]]$Arguments -) - -Set-StrictMode -Version 2 -$ErrorActionPreference = 'Stop' - -# -# Functions -# - -function Get-KoreBuild { - - $lockFile = Join-Path $Path 'korebuild-lock.txt' - - if (!(Test-Path $lockFile) -or $Update) { - Get-RemoteFile "$ToolsSource/korebuild/channels/$Channel/latest.txt" $lockFile $ToolsSourceSuffix - } - - $version = Get-Content $lockFile | Where-Object { $_ -like 'version:*' } | Select-Object -first 1 - if (!$version) { - Write-Error "Failed to parse version from $lockFile. Expected a line that begins with 'version:'" - } - $version = $version.TrimStart('version:').Trim() - $korebuildPath = Join-Paths $DotNetHome ('buildtools', 'korebuild', $version) - - if (!(Test-Path $korebuildPath)) { - Write-Host -ForegroundColor Magenta "Downloading KoreBuild $version" - New-Item -ItemType Directory -Path $korebuildPath | Out-Null - $remotePath = "$ToolsSource/korebuild/artifacts/$version/korebuild.$version.zip" - - try { - $tmpfile = Join-Path ([IO.Path]::GetTempPath()) "KoreBuild-$([guid]::NewGuid()).zip" - Get-RemoteFile $remotePath $tmpfile $ToolsSourceSuffix - if (Get-Command -Name 'Expand-Archive' -ErrorAction Ignore) { - # Use built-in commands where possible as they are cross-plat compatible - Expand-Archive -Path $tmpfile -DestinationPath $korebuildPath - } - else { - # Fallback to old approach for old installations of PowerShell - Add-Type -AssemblyName System.IO.Compression.FileSystem - [System.IO.Compression.ZipFile]::ExtractToDirectory($tmpfile, $korebuildPath) - } - } - catch { - Remove-Item -Recurse -Force $korebuildPath -ErrorAction Ignore - throw - } - finally { - Remove-Item $tmpfile -ErrorAction Ignore - } - } - - return $korebuildPath -} - -function Join-Paths([string]$path, [string[]]$childPaths) { - $childPaths | ForEach-Object { $path = Join-Path $path $_ } - return $path -} - -function Get-RemoteFile([string]$RemotePath, [string]$LocalPath, [string]$RemoteSuffix) { - if ($RemotePath -notlike 'http*') { - Copy-Item $RemotePath $LocalPath - return - } - - $retries = 10 - while ($retries -gt 0) { - $retries -= 1 - try { - Invoke-WebRequest -UseBasicParsing -Uri $($RemotePath + $RemoteSuffix) -OutFile $LocalPath - return - } - catch { - Write-Verbose "Request failed. $retries retries remaining" - } - } - - Write-Error "Download failed: '$RemotePath'." -} - -# -# Main -# - -# Load configuration or set defaults - -$Path = Resolve-Path $Path -if (!$ConfigFile) { $ConfigFile = Join-Path $Path 'korebuild.json' } - -if (Test-Path $ConfigFile) { - try { - $config = Get-Content -Raw -Encoding UTF8 -Path $ConfigFile | ConvertFrom-Json - if ($config) { - if (!($Channel) -and (Get-Member -Name 'channel' -InputObject $config)) { [string] $Channel = $config.channel } - if (!($ToolsSource) -and (Get-Member -Name 'toolsSource' -InputObject $config)) { [string] $ToolsSource = $config.toolsSource} - } - } - catch { - Write-Warning "$ConfigFile could not be read. Its settings will be ignored." - Write-Warning $Error[0] - } -} - -if (!$DotNetHome) { - $DotNetHome = if ($env:DOTNET_HOME) { $env:DOTNET_HOME } ` - elseif ($env:USERPROFILE) { Join-Path $env:USERPROFILE '.dotnet'} ` - elseif ($env:HOME) {Join-Path $env:HOME '.dotnet'}` - else { Join-Path $PSScriptRoot '.dotnet'} -} - -if (!$Channel) { $Channel = 'dev' } -if (!$ToolsSource) { $ToolsSource = 'https://aspnetcore.blob.core.windows.net/buildtools' } - -# Execute - -$korebuildPath = Get-KoreBuild -Import-Module -Force -Scope Local (Join-Path $korebuildPath 'KoreBuild.psd1') - -try { - Set-KoreBuildSettings -ToolsSource $ToolsSource -DotNetHome $DotNetHome -RepoPath $Path -ConfigFile $ConfigFile - Invoke-KoreBuildCommand $Command @Arguments -} -finally { - Remove-Module 'KoreBuild' -ErrorAction Ignore -} diff --git a/run.sh b/run.sh deleted file mode 100755 index 834961fc3a..0000000000 --- a/run.sh +++ /dev/null @@ -1,231 +0,0 @@ -#!/usr/bin/env bash - -set -euo pipefail - -# -# variables -# - -RESET="\033[0m" -RED="\033[0;31m" -YELLOW="\033[0;33m" -MAGENTA="\033[0;95m" -DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" -[ -z "${DOTNET_HOME:-}" ] && DOTNET_HOME="$HOME/.dotnet" -verbose=false -update=false -repo_path="$DIR" -channel='' -tools_source='' -tools_source_suffix='' - -# -# Functions -# -__usage() { - echo "Usage: $(basename "${BASH_SOURCE[0]}") command [options] [[--] ...]" - echo "" - echo "Arguments:" - echo " command The command to be run." - echo " ... Arguments passed to the command. Variable number of arguments allowed." - echo "" - echo "Options:" - echo " --verbose Show verbose output." - echo " -c|--channel The channel of KoreBuild to download. Overrides the value from the config file.." - echo " --config-file The path to the configuration file that stores values. Defaults to korebuild.json." - echo " -d|--dotnet-home The directory where .NET Core tools will be stored. Defaults to '\$DOTNET_HOME' or '\$HOME/.dotnet." - echo " --path The directory to build. Defaults to the directory containing the script." - echo " -s|--tools-source|-ToolsSource The base url where build tools can be downloaded. Overrides the value from the config file." - echo " --tools-source-suffix|-ToolsSourceSuffix The suffix to append to tools-source. Useful for query strings." - echo " -u|--update Update to the latest KoreBuild even if the lock file is present." - echo "" - echo "Description:" - echo " This function will create a file \$DIR/korebuild-lock.txt. This lock file can be committed to source, but does not have to be." - echo " When the lockfile is not present, KoreBuild will create one using latest available version from \$channel." - - if [[ "${1:-}" != '--no-exit' ]]; then - exit 2 - fi -} - -get_korebuild() { - local version - local lock_file="$repo_path/korebuild-lock.txt" - if [ ! -f "$lock_file" ] || [ "$update" = true ]; then - __get_remote_file "$tools_source/korebuild/channels/$channel/latest.txt" "$lock_file" "$tools_source_suffix" - fi - version="$(grep 'version:*' -m 1 "$lock_file")" - if [[ "$version" == '' ]]; then - __error "Failed to parse version from $lock_file. Expected a line that begins with 'version:'" - return 1 - fi - version="$(echo "${version#version:}" | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//')" - local korebuild_path="$DOTNET_HOME/buildtools/korebuild/$version" - - { - if [ ! -d "$korebuild_path" ]; then - mkdir -p "$korebuild_path" - local remote_path="$tools_source/korebuild/artifacts/$version/korebuild.$version.zip" - tmpfile="$(mktemp)" - echo -e "${MAGENTA}Downloading KoreBuild ${version}${RESET}" - if __get_remote_file "$remote_path" "$tmpfile" "$tools_source_suffix"; then - unzip -q -d "$korebuild_path" "$tmpfile" - fi - rm "$tmpfile" || true - fi - - source "$korebuild_path/KoreBuild.sh" - } || { - if [ -d "$korebuild_path" ]; then - echo "Cleaning up after failed installation" - rm -rf "$korebuild_path" || true - fi - return 1 - } -} - -__error() { - echo -e "${RED}error: $*${RESET}" 1>&2 -} - -__warn() { - echo -e "${YELLOW}warning: $*${RESET}" -} - -__machine_has() { - hash "$1" > /dev/null 2>&1 - return $? -} - -__get_remote_file() { - local remote_path=$1 - local local_path=$2 - local remote_path_suffix=$3 - - if [[ "$remote_path" != 'http'* ]]; then - cp "$remote_path" "$local_path" - return 0 - fi - - local failed=false - if __machine_has wget; then - wget --tries 10 --quiet -O "$local_path" "${remote_path}${remote_path_suffix}" || failed=true - else - failed=true - fi - - if [ "$failed" = true ] && __machine_has curl; then - failed=false - curl --retry 10 -sSL -f --create-dirs -o "$local_path" "${remote_path}${remote_path_suffix}" || failed=true - fi - - if [ "$failed" = true ]; then - __error "Download failed: $remote_path" 1>&2 - return 1 - fi -} - -# -# main -# - -command="${1:-}" -shift - -while [[ $# -gt 0 ]]; do - case $1 in - -\?|-h|--help) - __usage --no-exit - exit 0 - ;; - -c|--channel|-Channel) - shift - channel="${1:-}" - [ -z "$channel" ] && __usage - ;; - --config-file|-ConfigFile) - shift - config_file="${1:-}" - [ -z "$config_file" ] && __usage - if [ ! -f "$config_file" ]; then - __error "Invalid value for --config-file. $config_file does not exist." - exit 1 - fi - ;; - -d|--dotnet-home|-DotNetHome) - shift - DOTNET_HOME="${1:-}" - [ -z "$DOTNET_HOME" ] && __usage - ;; - --path|-Path) - shift - repo_path="${1:-}" - [ -z "$repo_path" ] && __usage - ;; - -s|--tools-source|-ToolsSource) - shift - tools_source="${1:-}" - [ -z "$tools_source" ] && __usage - ;; - --tools-source-suffix|-ToolsSourceSuffix) - shift - tools_source_suffix="${1:-}" - [ -z "$tools_source_suffix" ] && __usage - ;; - -u|--update|-Update) - update=true - ;; - --verbose|-Verbose) - verbose=true - ;; - --) - shift - break - ;; - *) - break - ;; - esac - shift -done - -if ! __machine_has unzip; then - __error 'Missing required command: unzip' - exit 1 -fi - -if ! __machine_has curl && ! __machine_has wget; then - __error 'Missing required command. Either wget or curl is required.' - exit 1 -fi - -[ -z "${config_file:-}" ] && config_file="$repo_path/korebuild.json" -if [ -f "$config_file" ]; then - if __machine_has jq ; then - if jq '.' "$config_file" >/dev/null ; then - config_channel="$(jq -r 'select(.channel!=null) | .channel' "$config_file")" - config_tools_source="$(jq -r 'select(.toolsSource!=null) | .toolsSource' "$config_file")" - else - __warn "$config_file is invalid JSON. Its settings will be ignored." - fi - elif __machine_has python ; then - if python -c "import json,codecs;obj=json.load(codecs.open('$config_file', 'r', 'utf-8-sig'))" >/dev/null ; then - config_channel="$(python -c "import json,codecs;obj=json.load(codecs.open('$config_file', 'r', 'utf-8-sig'));print(obj['channel'] if 'channel' in obj else '')")" - config_tools_source="$(python -c "import json,codecs;obj=json.load(codecs.open('$config_file', 'r', 'utf-8-sig'));print(obj['toolsSource'] if 'toolsSource' in obj else '')")" - else - __warn "$config_file is invalid JSON. Its settings will be ignored." - fi - else - __warn 'Missing required command: jq or pyton. Could not parse the JSON file. Its settings will be ignored.' - fi - - [ ! -z "${config_channel:-}" ] && channel="$config_channel" - [ ! -z "${config_tools_source:-}" ] && tools_source="$config_tools_source" -fi - -[ -z "$channel" ] && channel='dev' -[ -z "$tools_source" ] && tools_source='https://aspnetcore.blob.core.windows.net/buildtools' - -get_korebuild -set_korebuildsettings "$tools_source" "$DOTNET_HOME" "$repo_path" "$config_file" -invoke_korebuild_command "$command" "$@" diff --git a/samples/HostFilteringSample/HostFilteringSample.csproj b/samples/HostFilteringSample/HostFilteringSample.csproj deleted file mode 100644 index 7818be1fb0..0000000000 --- a/samples/HostFilteringSample/HostFilteringSample.csproj +++ /dev/null @@ -1,29 +0,0 @@ - - - - netcoreapp2.1;net461 - - - - - - - - - - - - - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - - diff --git a/samples/HttpOverridesSample/HttpOverridesSample.csproj b/samples/HttpOverridesSample/HttpOverridesSample.csproj deleted file mode 100644 index e966dd09a7..0000000000 --- a/samples/HttpOverridesSample/HttpOverridesSample.csproj +++ /dev/null @@ -1,15 +0,0 @@ - - - - netcoreapp2.1;net461 - - - - - - - - - - - diff --git a/samples/HttpsPolicySample/HttpsPolicySample.csproj b/samples/HttpsPolicySample/HttpsPolicySample.csproj deleted file mode 100644 index fdfa716478..0000000000 --- a/samples/HttpsPolicySample/HttpsPolicySample.csproj +++ /dev/null @@ -1,18 +0,0 @@ - - - - net461;netcoreapp2.0 - netcoreapp2.0 - - - - - - - - - - - - - diff --git a/samples/ResponseBufferingSample/Properties/launchSettings.json b/samples/ResponseBufferingSample/Properties/launchSettings.json deleted file mode 100644 index 2555984271..0000000000 --- a/samples/ResponseBufferingSample/Properties/launchSettings.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "iisSettings": { - "windowsAuthentication": false, - "anonymousAuthentication": true, - "iisExpress": { - "applicationUrl": "http://localhost:49657/", - "sslPort": 0 - } - }, - "profiles": { - "IIS Express": { - "commandName": "IISExpress", - "launchBrowser": true, - "environmentVariables": { - "ASPNET_ENV": "Development" - } - }, - "web": { - "commandName": "web", - "environmentVariables": { - "Hosting:Environment": "Development" - } - } - } -} \ No newline at end of file diff --git a/samples/ResponseBufferingSample/ResponseBufferingSample.csproj b/samples/ResponseBufferingSample/ResponseBufferingSample.csproj deleted file mode 100644 index b9595a89d8..0000000000 --- a/samples/ResponseBufferingSample/ResponseBufferingSample.csproj +++ /dev/null @@ -1,15 +0,0 @@ - - - - netcoreapp2.1;net461 - - - - - - - - - - - diff --git a/samples/ResponseBufferingSample/Startup.cs b/samples/ResponseBufferingSample/Startup.cs deleted file mode 100644 index c2189ad1ee..0000000000 --- a/samples/ResponseBufferingSample/Startup.cs +++ /dev/null @@ -1,50 +0,0 @@ -using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Hosting; -using Microsoft.AspNetCore.Http; -using Microsoft.Extensions.DependencyInjection; - -namespace ResponseBufferingSample -{ - public class Startup - { - // For more information on how to configure your application, visit http://go.microsoft.com/fwlink/?LinkID=398940 - public void ConfigureServices(IServiceCollection services) - { - } - - public void Configure(IApplicationBuilder app) - { - app.UseResponseBuffering(); - app.Run(async (context) => - { - // Write some stuff - context.Response.ContentType = "text/other"; - await context.Response.WriteAsync("Hello World!"); - - // ... more work ... - - // Something went wrong and we want to replace the response - context.Response.StatusCode = 200; - context.Response.Headers.Clear(); - context.Response.Body.SetLength(0); - - // Try again - context.Response.ContentType = "text/plain"; - await context.Response.WriteAsync("Hi Bob!"); - }); - } - - // Entry point for the application. - public static void Main(string[] args) - { - var host = new WebHostBuilder() - .UseKestrel() - // .UseIIS() // This repo can no longer reference IIS because IISIntegration depends on it. - .UseStartup() - .Build(); - - host.Run(); - } - } -} - diff --git a/samples/ResponseCompressionSample/ResponseCompressionSample.csproj b/samples/ResponseCompressionSample/ResponseCompressionSample.csproj deleted file mode 100644 index 2a7f4cfbb7..0000000000 --- a/samples/ResponseCompressionSample/ResponseCompressionSample.csproj +++ /dev/null @@ -1,20 +0,0 @@ - - - - netcoreapp2.1;net461 - - - - - - - - - - - - - - - - diff --git a/samples/RewriteSample/RewriteSample.csproj b/samples/RewriteSample/RewriteSample.csproj deleted file mode 100644 index a74fc45b85..0000000000 --- a/samples/RewriteSample/RewriteSample.csproj +++ /dev/null @@ -1,16 +0,0 @@ - - - - netcoreapp2.1;net461 - - - - - - - - - - - - diff --git a/src/Directory.Build.props b/src/Directory.Build.props deleted file mode 100644 index 4b89a431e7..0000000000 --- a/src/Directory.Build.props +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/src/Microsoft.AspNetCore.Buffering/BufferingWriteStream.cs b/src/Microsoft.AspNetCore.Buffering/BufferingWriteStream.cs deleted file mode 100644 index db3aacf5dd..0000000000 --- a/src/Microsoft.AspNetCore.Buffering/BufferingWriteStream.cs +++ /dev/null @@ -1,218 +0,0 @@ -// 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; -using System.IO; -using System.Threading; -using System.Threading.Tasks; - -namespace Microsoft.AspNetCore.Buffering -{ - internal class BufferingWriteStream : Stream - { - private readonly Stream _innerStream; - private readonly MemoryStream _buffer = new MemoryStream(); - private bool _isBuffering = true; - - public BufferingWriteStream(Stream innerStream) - { - _innerStream = innerStream; - } - - public override bool CanRead - { - get { return false; } - } - - public override bool CanSeek - { - get { return _isBuffering; } - } - - public override bool CanWrite - { - get { return _innerStream.CanWrite; } - } - - public override long Length - { - get - { - if (_isBuffering) - { - return _buffer.Length; - } - // May throw - return _innerStream.Length; - } - } - - // Clear/Reset the buffer by setting Position, Seek, or SetLength to 0. Random access is not supported. - public override long Position - { - get - { - if (_isBuffering) - { - return _buffer.Position; - } - // May throw - return _innerStream.Position; - } - set - { - if (_isBuffering) - { - if (value != 0) - { - throw new ArgumentOutOfRangeException(nameof(value), value, nameof(Position) + " can only be set to 0."); - } - _buffer.Position = value; - _buffer.SetLength(value); - } - else - { - // May throw - _innerStream.Position = value; - } - } - } - - // Clear/Reset the buffer by setting Position, Seek, or SetLength to 0. Random access is not supported. - public override void SetLength(long value) - { - if (_isBuffering) - { - if (value != 0) - { - throw new ArgumentOutOfRangeException(nameof(value), value, nameof(Length) + " can only be set to 0."); - } - _buffer.Position = value; - _buffer.SetLength(value); - } - else - { - // May throw - _innerStream.SetLength(value); - } - } - - // Clear/Reset the buffer by setting Position, Seek, or SetLength to 0. Random access is not supported. - public override long Seek(long offset, SeekOrigin origin) - { - if (_isBuffering) - { - if (origin != SeekOrigin.Begin) - { - throw new ArgumentException(nameof(origin), nameof(Seek) + " can only be set to " + nameof(SeekOrigin.Begin) + "."); - } - if (offset != 0) - { - throw new ArgumentOutOfRangeException(nameof(offset), offset, nameof(Seek) + " can only be set to 0."); - } - _buffer.SetLength(offset); - return _buffer.Seek(offset, origin); - } - // Try the inner stream instead, but this will usually fail. - return _innerStream.Seek(offset, origin); - } - - internal void DisableBuffering() - { - _isBuffering = false; - if (_buffer.Length > 0) - { - Flush(); - } - } - - internal Task DisableBufferingAsync(CancellationToken cancellationToken) - { - _isBuffering = false; - if (_buffer.Length > 0) - { - return FlushAsync(cancellationToken); - } - return Task.CompletedTask; - } - - public override void Write(byte[] buffer, int offset, int count) - { - if (_isBuffering) - { - _buffer.Write(buffer, offset, count); - } - else - { - _innerStream.Write(buffer, offset, count); - } - } - - public override Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) - { - if (_isBuffering) - { - return _buffer.WriteAsync(buffer, offset, count, cancellationToken); - } - else - { - return _innerStream.WriteAsync(buffer, offset, count, cancellationToken); - } - } - - public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object state) - { - if (_isBuffering) - { - return _buffer.BeginWrite(buffer, offset, count, callback, state); - } - else - { - return _innerStream.BeginWrite(buffer, offset, count, callback, state); - } - } - - public override void EndWrite(IAsyncResult asyncResult) - { - if (_isBuffering) - { - _buffer.EndWrite(asyncResult); - } - else - { - _innerStream.EndWrite(asyncResult); - } - } - - public override void Flush() - { - _isBuffering = false; - if (_buffer.Length > 0) - { - _buffer.Seek(0, SeekOrigin.Begin); - _buffer.CopyTo(_innerStream); - _buffer.Seek(0, SeekOrigin.Begin); - _buffer.SetLength(0); - } - _innerStream.Flush(); - } - - public override async Task FlushAsync(CancellationToken cancellationToken) - { - _isBuffering = false; - if (_buffer.Length > 0) - { - _buffer.Seek(0, SeekOrigin.Begin); - await _buffer.CopyToAsync(_innerStream, 1024 * 16, cancellationToken); - _buffer.Seek(0, SeekOrigin.Begin); - _buffer.SetLength(0); - } - await _innerStream.FlushAsync(cancellationToken); - } - - public override int Read(byte[] buffer, int offset, int count) - { - throw new NotSupportedException("This Stream only supports Write operations."); - } - } -} diff --git a/src/Microsoft.AspNetCore.Buffering/HttpBufferingFeature.cs b/src/Microsoft.AspNetCore.Buffering/HttpBufferingFeature.cs deleted file mode 100644 index 746712f5c8..0000000000 --- a/src/Microsoft.AspNetCore.Buffering/HttpBufferingFeature.cs +++ /dev/null @@ -1,30 +0,0 @@ -// 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 Microsoft.AspNetCore.Http.Features; - -namespace Microsoft.AspNetCore.Buffering -{ - internal class HttpBufferingFeature : IHttpBufferingFeature - { - private readonly BufferingWriteStream _buffer; - private readonly IHttpBufferingFeature _innerFeature; - - internal HttpBufferingFeature(BufferingWriteStream buffer, IHttpBufferingFeature innerFeature) - { - _buffer = buffer; - _innerFeature = innerFeature; - } - - public void DisableRequestBuffering() - { - _innerFeature?.DisableRequestBuffering(); - } - - public void DisableResponseBuffering() - { - _buffer.DisableBuffering(); - _innerFeature?.DisableResponseBuffering(); - } - } -} diff --git a/src/Microsoft.AspNetCore.Buffering/Microsoft.AspNetCore.Buffering.csproj b/src/Microsoft.AspNetCore.Buffering/Microsoft.AspNetCore.Buffering.csproj deleted file mode 100644 index 953716c6c1..0000000000 --- a/src/Microsoft.AspNetCore.Buffering/Microsoft.AspNetCore.Buffering.csproj +++ /dev/null @@ -1,19 +0,0 @@ - - - - $(ExperimentalVersionPrefix) - $(ExperimentalVersionSuffix) - false - $(ExperimentalPackageVersion) - ASP.NET Core middleware for buffering response bodies. - netstandard2.0 - $(NoWarn);CS1591 - true - aspnetcore;buffer;buffering - - - - - - - diff --git a/src/Microsoft.AspNetCore.Buffering/ResponseBufferingMiddleware.cs b/src/Microsoft.AspNetCore.Buffering/ResponseBufferingMiddleware.cs deleted file mode 100644 index bd5b8e1515..0000000000 --- a/src/Microsoft.AspNetCore.Buffering/ResponseBufferingMiddleware.cs +++ /dev/null @@ -1,65 +0,0 @@ -// 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.Threading.Tasks; -using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Http.Features; - -namespace Microsoft.AspNetCore.Buffering -{ - public class ResponseBufferingMiddleware - { - private readonly RequestDelegate _next; - - public ResponseBufferingMiddleware(RequestDelegate next) - { - _next = next; - } - - public async Task Invoke(HttpContext httpContext) - { - var originalResponseBody = httpContext.Response.Body; - - // no-op if buffering is already available. - if (originalResponseBody.CanSeek) - { - await _next(httpContext); - return; - } - - var originalBufferingFeature = httpContext.Features.Get(); - var originalSendFileFeature = httpContext.Features.Get(); - try - { - // Shim the response stream - var bufferStream = new BufferingWriteStream(originalResponseBody); - httpContext.Response.Body = bufferStream; - httpContext.Features.Set(new HttpBufferingFeature(bufferStream, originalBufferingFeature)); - if (originalSendFileFeature != null) - { - httpContext.Features.Set(new SendFileFeatureWrapper(originalSendFileFeature, bufferStream)); - } - - await _next(httpContext); - - // If we're still buffered, set the content-length header and flush the buffer. - // Only if the content-length header is not already set, and some content was buffered. - if (!httpContext.Response.HasStarted && bufferStream.CanSeek && bufferStream.Length > 0) - { - if (!httpContext.Response.ContentLength.HasValue) - { - httpContext.Response.ContentLength = bufferStream.Length; - } - await bufferStream.FlushAsync(); - } - } - finally - { - // undo everything - httpContext.Features.Set(originalBufferingFeature); - httpContext.Features.Set(originalSendFileFeature); - httpContext.Response.Body = originalResponseBody; - } - } - } -} diff --git a/src/Microsoft.AspNetCore.Buffering/ResponseBufferingMiddlewareExtensions.cs b/src/Microsoft.AspNetCore.Buffering/ResponseBufferingMiddlewareExtensions.cs deleted file mode 100644 index 5092dba3c4..0000000000 --- a/src/Microsoft.AspNetCore.Buffering/ResponseBufferingMiddlewareExtensions.cs +++ /dev/null @@ -1,20 +0,0 @@ -// 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 Microsoft.AspNetCore.Buffering; - -namespace Microsoft.AspNetCore.Builder -{ - public static class ResponseBufferingMiddlewareExtensions - { - /// - /// Enables full buffering of response bodies. This can be disabled on a per request basis using IHttpBufferingFeature. - /// - /// - /// - public static IApplicationBuilder UseResponseBuffering(this IApplicationBuilder builder) - { - return builder.UseMiddleware(); - } - } -} diff --git a/src/Microsoft.AspNetCore.Buffering/SendFileFeatureWrapper.cs b/src/Microsoft.AspNetCore.Buffering/SendFileFeatureWrapper.cs deleted file mode 100644 index 346173e315..0000000000 --- a/src/Microsoft.AspNetCore.Buffering/SendFileFeatureWrapper.cs +++ /dev/null @@ -1,28 +0,0 @@ -// 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.Threading; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Http.Features; - -namespace Microsoft.AspNetCore.Buffering -{ - internal class SendFileFeatureWrapper : IHttpSendFileFeature - { - private readonly IHttpSendFileFeature _originalSendFileFeature; - private readonly BufferingWriteStream _bufferStream; - - public SendFileFeatureWrapper(IHttpSendFileFeature originalSendFileFeature, BufferingWriteStream bufferStream) - { - _originalSendFileFeature = originalSendFileFeature; - _bufferStream = bufferStream; - } - - // Flush and disable the buffer if anyone tries to call the SendFile feature. - public async Task SendFileAsync(string path, long offset, long? length, CancellationToken cancellation) - { - await _bufferStream.DisableBufferingAsync(cancellation); - await _originalSendFileFeature.SendFileAsync(path, offset, length, cancellation); - } - } -} \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.HostFiltering/Microsoft.AspNetCore.HostFiltering.csproj b/src/Microsoft.AspNetCore.HostFiltering/Microsoft.AspNetCore.HostFiltering.csproj deleted file mode 100644 index ec6d642340..0000000000 --- a/src/Microsoft.AspNetCore.HostFiltering/Microsoft.AspNetCore.HostFiltering.csproj +++ /dev/null @@ -1,18 +0,0 @@ - - - - - ASP.NET Core middleware for filtering out requests with unknown HTTP host headers. - - netstandard2.0 - true - aspnetcore - - - - - - - - - diff --git a/src/Microsoft.AspNetCore.HttpsPolicy/Microsoft.AspNetCore.HttpsPolicy.csproj b/src/Microsoft.AspNetCore.HttpsPolicy/Microsoft.AspNetCore.HttpsPolicy.csproj deleted file mode 100644 index ee7e611a47..0000000000 --- a/src/Microsoft.AspNetCore.HttpsPolicy/Microsoft.AspNetCore.HttpsPolicy.csproj +++ /dev/null @@ -1,20 +0,0 @@ - - - - - ASP.NET Core basic middleware for supporting HTTPS Redirection and HTTP Strict-Transport-Security. - - netstandard2.0 - $(NoWarn);CS1591 - true - aspnetcore;https;hsts - - - - - - - - - - diff --git a/src/Microsoft.AspNetCore.Rewrite/Microsoft.AspNetCore.Rewrite.csproj b/src/Microsoft.AspNetCore.Rewrite/Microsoft.AspNetCore.Rewrite.csproj deleted file mode 100644 index 03c3e53b64..0000000000 --- a/src/Microsoft.AspNetCore.Rewrite/Microsoft.AspNetCore.Rewrite.csproj +++ /dev/null @@ -1,23 +0,0 @@ - - - - ASP.NET Core basic middleware for rewriting URLs. Includes: -* Support for custom URL rewrite rules -* Support for running IIS URL Rewrite module rules -* Support for running Apache mod_rewrite rules. - netstandard2.0 - $(NoWarn);CS1591 - true - aspnetcore;urlrewrite;mod_rewrite - - - - - - - - - - - - diff --git a/src/Middleware/HostFiltering/sample/HostFilteringSample.csproj b/src/Middleware/HostFiltering/sample/HostFilteringSample.csproj new file mode 100644 index 0000000000..2bf095937a --- /dev/null +++ b/src/Middleware/HostFiltering/sample/HostFilteringSample.csproj @@ -0,0 +1,26 @@ + + + + netcoreapp2.1;net461 + + + + + + + + + + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + + diff --git a/samples/HostFilteringSample/Program.cs b/src/Middleware/HostFiltering/sample/Program.cs similarity index 100% rename from samples/HostFilteringSample/Program.cs rename to src/Middleware/HostFiltering/sample/Program.cs diff --git a/samples/HostFilteringSample/Properties/launchSettings.json b/src/Middleware/HostFiltering/sample/Properties/launchSettings.json similarity index 100% rename from samples/HostFilteringSample/Properties/launchSettings.json rename to src/Middleware/HostFiltering/sample/Properties/launchSettings.json diff --git a/samples/HostFilteringSample/Startup.cs b/src/Middleware/HostFiltering/sample/Startup.cs similarity index 100% rename from samples/HostFilteringSample/Startup.cs rename to src/Middleware/HostFiltering/sample/Startup.cs diff --git a/samples/HostFilteringSample/appsettings.Development.json b/src/Middleware/HostFiltering/sample/appsettings.Development.json similarity index 100% rename from samples/HostFilteringSample/appsettings.Development.json rename to src/Middleware/HostFiltering/sample/appsettings.Development.json diff --git a/samples/HostFilteringSample/appsettings.Production.json b/src/Middleware/HostFiltering/sample/appsettings.Production.json similarity index 100% rename from samples/HostFilteringSample/appsettings.Production.json rename to src/Middleware/HostFiltering/sample/appsettings.Production.json diff --git a/samples/HostFilteringSample/appsettings.json b/src/Middleware/HostFiltering/sample/appsettings.json similarity index 100% rename from samples/HostFilteringSample/appsettings.json rename to src/Middleware/HostFiltering/sample/appsettings.json diff --git a/src/Microsoft.AspNetCore.HostFiltering/HostFilteringBuilderExtensions.cs b/src/Middleware/HostFiltering/src/HostFilteringBuilderExtensions.cs similarity index 100% rename from src/Microsoft.AspNetCore.HostFiltering/HostFilteringBuilderExtensions.cs rename to src/Middleware/HostFiltering/src/HostFilteringBuilderExtensions.cs diff --git a/src/Microsoft.AspNetCore.HostFiltering/HostFilteringMiddleware.cs b/src/Middleware/HostFiltering/src/HostFilteringMiddleware.cs similarity index 100% rename from src/Microsoft.AspNetCore.HostFiltering/HostFilteringMiddleware.cs rename to src/Middleware/HostFiltering/src/HostFilteringMiddleware.cs diff --git a/src/Microsoft.AspNetCore.HostFiltering/HostFilteringOptions.cs b/src/Middleware/HostFiltering/src/HostFilteringOptions.cs similarity index 100% rename from src/Microsoft.AspNetCore.HostFiltering/HostFilteringOptions.cs rename to src/Middleware/HostFiltering/src/HostFilteringOptions.cs diff --git a/src/Microsoft.AspNetCore.HostFiltering/HostFilteringServicesExtensions.cs b/src/Middleware/HostFiltering/src/HostFilteringServicesExtensions.cs similarity index 100% rename from src/Microsoft.AspNetCore.HostFiltering/HostFilteringServicesExtensions.cs rename to src/Middleware/HostFiltering/src/HostFilteringServicesExtensions.cs diff --git a/src/Middleware/HostFiltering/src/Microsoft.AspNetCore.HostFiltering.csproj b/src/Middleware/HostFiltering/src/Microsoft.AspNetCore.HostFiltering.csproj new file mode 100644 index 0000000000..a8eb42bb02 --- /dev/null +++ b/src/Middleware/HostFiltering/src/Microsoft.AspNetCore.HostFiltering.csproj @@ -0,0 +1,18 @@ + + + + + ASP.NET Core middleware for filtering out requests with unknown HTTP host headers. + + netstandard2.0 + true + aspnetcore + + + + + + + + + diff --git a/src/Microsoft.AspNetCore.HostFiltering/baseline.netcore.json b/src/Middleware/HostFiltering/src/baseline.netcore.json similarity index 100% rename from src/Microsoft.AspNetCore.HostFiltering/baseline.netcore.json rename to src/Middleware/HostFiltering/src/baseline.netcore.json diff --git a/test/Microsoft.AspNetCore.HostFiltering.Tests/HostFilteringMiddlewareTests.cs b/src/Middleware/HostFiltering/test/HostFilteringMiddlewareTests.cs similarity index 100% rename from test/Microsoft.AspNetCore.HostFiltering.Tests/HostFilteringMiddlewareTests.cs rename to src/Middleware/HostFiltering/test/HostFilteringMiddlewareTests.cs diff --git a/src/Middleware/HostFiltering/test/Microsoft.AspNetCore.HostFiltering.Tests.csproj b/src/Middleware/HostFiltering/test/Microsoft.AspNetCore.HostFiltering.Tests.csproj new file mode 100644 index 0000000000..a430a2df23 --- /dev/null +++ b/src/Middleware/HostFiltering/test/Microsoft.AspNetCore.HostFiltering.Tests.csproj @@ -0,0 +1,12 @@ + + + + $(StandardTestTfms) + + + + + + + + diff --git a/src/Middleware/HttpOverrides/sample/HttpOverridesSample.csproj b/src/Middleware/HttpOverrides/sample/HttpOverridesSample.csproj new file mode 100644 index 0000000000..1d5cf506c1 --- /dev/null +++ b/src/Middleware/HttpOverrides/sample/HttpOverridesSample.csproj @@ -0,0 +1,12 @@ + + + + netcoreapp2.1;net461 + + + + + + + + diff --git a/samples/HttpOverridesSample/Properties/launchSettings.json b/src/Middleware/HttpOverrides/sample/Properties/launchSettings.json similarity index 100% rename from samples/HttpOverridesSample/Properties/launchSettings.json rename to src/Middleware/HttpOverrides/sample/Properties/launchSettings.json diff --git a/samples/HttpOverridesSample/Startup.cs b/src/Middleware/HttpOverrides/sample/Startup.cs similarity index 100% rename from samples/HttpOverridesSample/Startup.cs rename to src/Middleware/HttpOverrides/sample/Startup.cs diff --git a/src/Microsoft.AspNetCore.HttpOverrides/ForwardedHeaders.cs b/src/Middleware/HttpOverrides/src/ForwardedHeaders.cs similarity index 100% rename from src/Microsoft.AspNetCore.HttpOverrides/ForwardedHeaders.cs rename to src/Middleware/HttpOverrides/src/ForwardedHeaders.cs diff --git a/src/Microsoft.AspNetCore.HttpOverrides/ForwardedHeadersDefaults.cs b/src/Middleware/HttpOverrides/src/ForwardedHeadersDefaults.cs similarity index 100% rename from src/Microsoft.AspNetCore.HttpOverrides/ForwardedHeadersDefaults.cs rename to src/Middleware/HttpOverrides/src/ForwardedHeadersDefaults.cs diff --git a/src/Microsoft.AspNetCore.HttpOverrides/ForwardedHeadersExtensions.cs b/src/Middleware/HttpOverrides/src/ForwardedHeadersExtensions.cs similarity index 100% rename from src/Microsoft.AspNetCore.HttpOverrides/ForwardedHeadersExtensions.cs rename to src/Middleware/HttpOverrides/src/ForwardedHeadersExtensions.cs diff --git a/src/Microsoft.AspNetCore.HttpOverrides/ForwardedHeadersMiddleware.cs b/src/Middleware/HttpOverrides/src/ForwardedHeadersMiddleware.cs similarity index 100% rename from src/Microsoft.AspNetCore.HttpOverrides/ForwardedHeadersMiddleware.cs rename to src/Middleware/HttpOverrides/src/ForwardedHeadersMiddleware.cs diff --git a/src/Microsoft.AspNetCore.HttpOverrides/ForwardedHeadersOptions.cs b/src/Middleware/HttpOverrides/src/ForwardedHeadersOptions.cs similarity index 100% rename from src/Microsoft.AspNetCore.HttpOverrides/ForwardedHeadersOptions.cs rename to src/Middleware/HttpOverrides/src/ForwardedHeadersOptions.cs diff --git a/src/Microsoft.AspNetCore.HttpOverrides/HttpMethodOverrideExtensions.cs b/src/Middleware/HttpOverrides/src/HttpMethodOverrideExtensions.cs similarity index 100% rename from src/Microsoft.AspNetCore.HttpOverrides/HttpMethodOverrideExtensions.cs rename to src/Middleware/HttpOverrides/src/HttpMethodOverrideExtensions.cs diff --git a/src/Microsoft.AspNetCore.HttpOverrides/HttpMethodOverrideMiddleware.cs b/src/Middleware/HttpOverrides/src/HttpMethodOverrideMiddleware.cs similarity index 100% rename from src/Microsoft.AspNetCore.HttpOverrides/HttpMethodOverrideMiddleware.cs rename to src/Middleware/HttpOverrides/src/HttpMethodOverrideMiddleware.cs diff --git a/src/Microsoft.AspNetCore.HttpOverrides/HttpMethodOverrideOptions.cs b/src/Middleware/HttpOverrides/src/HttpMethodOverrideOptions.cs similarity index 100% rename from src/Microsoft.AspNetCore.HttpOverrides/HttpMethodOverrideOptions.cs rename to src/Middleware/HttpOverrides/src/HttpMethodOverrideOptions.cs diff --git a/src/Microsoft.AspNetCore.HttpOverrides/IPNetwork.cs b/src/Middleware/HttpOverrides/src/IPNetwork.cs similarity index 100% rename from src/Microsoft.AspNetCore.HttpOverrides/IPNetwork.cs rename to src/Middleware/HttpOverrides/src/IPNetwork.cs diff --git a/src/Microsoft.AspNetCore.HttpOverrides/Internal/IPEndPointParser.cs b/src/Middleware/HttpOverrides/src/Internal/IPEndPointParser.cs similarity index 100% rename from src/Microsoft.AspNetCore.HttpOverrides/Internal/IPEndPointParser.cs rename to src/Middleware/HttpOverrides/src/Internal/IPEndPointParser.cs diff --git a/src/Microsoft.AspNetCore.HttpOverrides/Microsoft.AspNetCore.HttpOverrides.csproj b/src/Middleware/HttpOverrides/src/Microsoft.AspNetCore.HttpOverrides.csproj similarity index 57% rename from src/Microsoft.AspNetCore.HttpOverrides/Microsoft.AspNetCore.HttpOverrides.csproj rename to src/Middleware/HttpOverrides/src/Microsoft.AspNetCore.HttpOverrides.csproj index c922f7f94f..11b2130693 100644 --- a/src/Microsoft.AspNetCore.HttpOverrides/Microsoft.AspNetCore.HttpOverrides.csproj +++ b/src/Middleware/HttpOverrides/src/Microsoft.AspNetCore.HttpOverrides.csproj @@ -11,9 +11,9 @@ - - - + + + diff --git a/src/Microsoft.AspNetCore.HttpOverrides/baseline.net45.json b/src/Middleware/HttpOverrides/src/baseline.net45.json similarity index 100% rename from src/Microsoft.AspNetCore.HttpOverrides/baseline.net45.json rename to src/Middleware/HttpOverrides/src/baseline.net45.json diff --git a/src/Microsoft.AspNetCore.HttpOverrides/baseline.netcore.json b/src/Middleware/HttpOverrides/src/baseline.netcore.json similarity index 100% rename from src/Microsoft.AspNetCore.HttpOverrides/baseline.netcore.json rename to src/Middleware/HttpOverrides/src/baseline.netcore.json diff --git a/test/Microsoft.AspNetCore.HttpOverrides.Tests/ForwardedHeadersMiddlewareTest.cs b/src/Middleware/HttpOverrides/test/ForwardedHeadersMiddlewareTest.cs similarity index 100% rename from test/Microsoft.AspNetCore.HttpOverrides.Tests/ForwardedHeadersMiddlewareTest.cs rename to src/Middleware/HttpOverrides/test/ForwardedHeadersMiddlewareTest.cs diff --git a/test/Microsoft.AspNetCore.HttpOverrides.Tests/HttpMethodOverrideMiddlewareTest.cs b/src/Middleware/HttpOverrides/test/HttpMethodOverrideMiddlewareTest.cs similarity index 100% rename from test/Microsoft.AspNetCore.HttpOverrides.Tests/HttpMethodOverrideMiddlewareTest.cs rename to src/Middleware/HttpOverrides/test/HttpMethodOverrideMiddlewareTest.cs diff --git a/test/Microsoft.AspNetCore.HttpOverrides.Tests/IPEndPointParserTest.cs b/src/Middleware/HttpOverrides/test/IPEndPointParserTest.cs similarity index 100% rename from test/Microsoft.AspNetCore.HttpOverrides.Tests/IPEndPointParserTest.cs rename to src/Middleware/HttpOverrides/test/IPEndPointParserTest.cs diff --git a/test/Microsoft.AspNetCore.HttpOverrides.Tests/IPNetworkTest.cs b/src/Middleware/HttpOverrides/test/IPNetworkTest.cs similarity index 100% rename from test/Microsoft.AspNetCore.HttpOverrides.Tests/IPNetworkTest.cs rename to src/Middleware/HttpOverrides/test/IPNetworkTest.cs diff --git a/test/Microsoft.AspNetCore.Buffering.Tests/Microsoft.AspNetCore.Buffering.Tests.csproj b/src/Middleware/HttpOverrides/test/Microsoft.AspNetCore.HttpOverrides.Tests.csproj similarity index 58% rename from test/Microsoft.AspNetCore.Buffering.Tests/Microsoft.AspNetCore.Buffering.Tests.csproj rename to src/Middleware/HttpOverrides/test/Microsoft.AspNetCore.HttpOverrides.Tests.csproj index 5f8209ea44..880dffd329 100644 --- a/test/Microsoft.AspNetCore.Buffering.Tests/Microsoft.AspNetCore.Buffering.Tests.csproj +++ b/src/Middleware/HttpOverrides/test/Microsoft.AspNetCore.HttpOverrides.Tests.csproj @@ -5,7 +5,8 @@ - + + diff --git a/src/Middleware/HttpsPolicy/sample/HttpsPolicySample.csproj b/src/Middleware/HttpsPolicy/sample/HttpsPolicySample.csproj new file mode 100644 index 0000000000..3bbe805f9f --- /dev/null +++ b/src/Middleware/HttpsPolicy/sample/HttpsPolicySample.csproj @@ -0,0 +1,14 @@ + + + + net461;netcoreapp2.0 + + + + + + + + + + diff --git a/samples/HttpsPolicySample/Properties/launchSettings.json b/src/Middleware/HttpsPolicy/sample/Properties/launchSettings.json similarity index 100% rename from samples/HttpsPolicySample/Properties/launchSettings.json rename to src/Middleware/HttpsPolicy/sample/Properties/launchSettings.json diff --git a/samples/HttpsPolicySample/Startup.cs b/src/Middleware/HttpsPolicy/sample/Startup.cs similarity index 100% rename from samples/HttpsPolicySample/Startup.cs rename to src/Middleware/HttpsPolicy/sample/Startup.cs diff --git a/samples/HttpsPolicySample/testCert.pfx b/src/Middleware/HttpsPolicy/sample/testCert.pfx similarity index 100% rename from samples/HttpsPolicySample/testCert.pfx rename to src/Middleware/HttpsPolicy/sample/testCert.pfx diff --git a/src/Microsoft.AspNetCore.HttpsPolicy/HstsBuilderExtensions.cs b/src/Middleware/HttpsPolicy/src/HstsBuilderExtensions.cs similarity index 100% rename from src/Microsoft.AspNetCore.HttpsPolicy/HstsBuilderExtensions.cs rename to src/Middleware/HttpsPolicy/src/HstsBuilderExtensions.cs diff --git a/src/Microsoft.AspNetCore.HttpsPolicy/HstsMiddleware.cs b/src/Middleware/HttpsPolicy/src/HstsMiddleware.cs similarity index 100% rename from src/Microsoft.AspNetCore.HttpsPolicy/HstsMiddleware.cs rename to src/Middleware/HttpsPolicy/src/HstsMiddleware.cs diff --git a/src/Microsoft.AspNetCore.HttpsPolicy/HstsOptions.cs b/src/Middleware/HttpsPolicy/src/HstsOptions.cs similarity index 100% rename from src/Microsoft.AspNetCore.HttpsPolicy/HstsOptions.cs rename to src/Middleware/HttpsPolicy/src/HstsOptions.cs diff --git a/src/Microsoft.AspNetCore.HttpsPolicy/HstsServicesExtensions.cs b/src/Middleware/HttpsPolicy/src/HstsServicesExtensions.cs similarity index 100% rename from src/Microsoft.AspNetCore.HttpsPolicy/HstsServicesExtensions.cs rename to src/Middleware/HttpsPolicy/src/HstsServicesExtensions.cs diff --git a/src/Microsoft.AspNetCore.HttpsPolicy/HttpsRedirectionBuilderExtensions.cs b/src/Middleware/HttpsPolicy/src/HttpsRedirectionBuilderExtensions.cs similarity index 100% rename from src/Microsoft.AspNetCore.HttpsPolicy/HttpsRedirectionBuilderExtensions.cs rename to src/Middleware/HttpsPolicy/src/HttpsRedirectionBuilderExtensions.cs diff --git a/src/Microsoft.AspNetCore.HttpsPolicy/HttpsRedirectionMiddleware.cs b/src/Middleware/HttpsPolicy/src/HttpsRedirectionMiddleware.cs similarity index 100% rename from src/Microsoft.AspNetCore.HttpsPolicy/HttpsRedirectionMiddleware.cs rename to src/Middleware/HttpsPolicy/src/HttpsRedirectionMiddleware.cs diff --git a/src/Microsoft.AspNetCore.HttpsPolicy/HttpsRedirectionOptions.cs b/src/Middleware/HttpsPolicy/src/HttpsRedirectionOptions.cs similarity index 100% rename from src/Microsoft.AspNetCore.HttpsPolicy/HttpsRedirectionOptions.cs rename to src/Middleware/HttpsPolicy/src/HttpsRedirectionOptions.cs diff --git a/src/Microsoft.AspNetCore.HttpsPolicy/HttpsRedirectionServicesExtensions.cs b/src/Middleware/HttpsPolicy/src/HttpsRedirectionServicesExtensions.cs similarity index 100% rename from src/Microsoft.AspNetCore.HttpsPolicy/HttpsRedirectionServicesExtensions.cs rename to src/Middleware/HttpsPolicy/src/HttpsRedirectionServicesExtensions.cs diff --git a/src/Middleware/HttpsPolicy/src/Microsoft.AspNetCore.HttpsPolicy.csproj b/src/Middleware/HttpsPolicy/src/Microsoft.AspNetCore.HttpsPolicy.csproj new file mode 100644 index 0000000000..f367ea28cc --- /dev/null +++ b/src/Middleware/HttpsPolicy/src/Microsoft.AspNetCore.HttpsPolicy.csproj @@ -0,0 +1,20 @@ + + + + + ASP.NET Core basic middleware for supporting HTTPS Redirection and HTTP Strict-Transport-Security. + + netstandard2.0 + $(NoWarn);CS1591 + true + aspnetcore;https;hsts + + + + + + + + + + diff --git a/src/Microsoft.AspNetCore.HttpsPolicy/baseline.netcore.json b/src/Middleware/HttpsPolicy/src/baseline.netcore.json similarity index 100% rename from src/Microsoft.AspNetCore.HttpsPolicy/baseline.netcore.json rename to src/Middleware/HttpsPolicy/src/baseline.netcore.json diff --git a/src/Microsoft.AspNetCore.HttpsPolicy/internal/HttpsLoggingExtensions.cs b/src/Middleware/HttpsPolicy/src/internal/HttpsLoggingExtensions.cs similarity index 100% rename from src/Microsoft.AspNetCore.HttpsPolicy/internal/HttpsLoggingExtensions.cs rename to src/Middleware/HttpsPolicy/src/internal/HttpsLoggingExtensions.cs diff --git a/test/Microsoft.AspNetCore.HttpsPolicy.Tests/HstsMiddlewareTests.cs b/src/Middleware/HttpsPolicy/test/HstsMiddlewareTests.cs similarity index 100% rename from test/Microsoft.AspNetCore.HttpsPolicy.Tests/HstsMiddlewareTests.cs rename to src/Middleware/HttpsPolicy/test/HstsMiddlewareTests.cs diff --git a/test/Microsoft.AspNetCore.HttpsPolicy.Tests/HttpsPolicyTests.cs b/src/Middleware/HttpsPolicy/test/HttpsPolicyTests.cs similarity index 100% rename from test/Microsoft.AspNetCore.HttpsPolicy.Tests/HttpsPolicyTests.cs rename to src/Middleware/HttpsPolicy/test/HttpsPolicyTests.cs diff --git a/test/Microsoft.AspNetCore.HttpsPolicy.Tests/HttpsRedirectionMiddlewareTests.cs b/src/Middleware/HttpsPolicy/test/HttpsRedirectionMiddlewareTests.cs similarity index 100% rename from test/Microsoft.AspNetCore.HttpsPolicy.Tests/HttpsRedirectionMiddlewareTests.cs rename to src/Middleware/HttpsPolicy/test/HttpsRedirectionMiddlewareTests.cs diff --git a/test/Microsoft.AspNetCore.HttpsPolicy.Tests/Microsoft.AspNetCore.HttpsPolicy.Tests.csproj b/src/Middleware/HttpsPolicy/test/Microsoft.AspNetCore.HttpsPolicy.Tests.csproj similarity index 50% rename from test/Microsoft.AspNetCore.HttpsPolicy.Tests/Microsoft.AspNetCore.HttpsPolicy.Tests.csproj rename to src/Middleware/HttpsPolicy/test/Microsoft.AspNetCore.HttpsPolicy.Tests.csproj index e51e3a6640..097990a99a 100644 --- a/test/Microsoft.AspNetCore.HttpsPolicy.Tests/Microsoft.AspNetCore.HttpsPolicy.Tests.csproj +++ b/src/Middleware/HttpsPolicy/test/Microsoft.AspNetCore.HttpsPolicy.Tests.csproj @@ -6,10 +6,7 @@ - - - - - + + diff --git a/samples/ResponseCompressionSample/CustomCompressionProvider.cs b/src/Middleware/ResponseCompression/sample/CustomCompressionProvider.cs similarity index 100% rename from samples/ResponseCompressionSample/CustomCompressionProvider.cs rename to src/Middleware/ResponseCompression/sample/CustomCompressionProvider.cs diff --git a/samples/ResponseCompressionSample/LoremIpsum.cs b/src/Middleware/ResponseCompression/sample/LoremIpsum.cs similarity index 100% rename from samples/ResponseCompressionSample/LoremIpsum.cs rename to src/Middleware/ResponseCompression/sample/LoremIpsum.cs diff --git a/samples/ResponseCompressionSample/Properties/launchSettings.json b/src/Middleware/ResponseCompression/sample/Properties/launchSettings.json similarity index 100% rename from samples/ResponseCompressionSample/Properties/launchSettings.json rename to src/Middleware/ResponseCompression/sample/Properties/launchSettings.json diff --git a/src/Middleware/ResponseCompression/sample/ResponseCompressionSample.csproj b/src/Middleware/ResponseCompression/sample/ResponseCompressionSample.csproj new file mode 100644 index 0000000000..c9aa982896 --- /dev/null +++ b/src/Middleware/ResponseCompression/sample/ResponseCompressionSample.csproj @@ -0,0 +1,17 @@ + + + + netcoreapp2.1;net461 + + + + + + + + + + + + + diff --git a/samples/ResponseCompressionSample/Startup.cs b/src/Middleware/ResponseCompression/sample/Startup.cs similarity index 100% rename from samples/ResponseCompressionSample/Startup.cs rename to src/Middleware/ResponseCompression/sample/Startup.cs diff --git a/samples/ResponseCompressionSample/testfile1kb.txt b/src/Middleware/ResponseCompression/sample/testfile1kb.txt similarity index 100% rename from samples/ResponseCompressionSample/testfile1kb.txt rename to src/Middleware/ResponseCompression/sample/testfile1kb.txt diff --git a/src/Microsoft.AspNetCore.ResponseCompression/BodyWrapperStream.cs b/src/Middleware/ResponseCompression/src/BodyWrapperStream.cs similarity index 100% rename from src/Microsoft.AspNetCore.ResponseCompression/BodyWrapperStream.cs rename to src/Middleware/ResponseCompression/src/BodyWrapperStream.cs diff --git a/src/Microsoft.AspNetCore.ResponseCompression/CompressionProviderCollection.cs b/src/Middleware/ResponseCompression/src/CompressionProviderCollection.cs similarity index 100% rename from src/Microsoft.AspNetCore.ResponseCompression/CompressionProviderCollection.cs rename to src/Middleware/ResponseCompression/src/CompressionProviderCollection.cs diff --git a/src/Microsoft.AspNetCore.ResponseCompression/CompressionProviderFactory.cs b/src/Middleware/ResponseCompression/src/CompressionProviderFactory.cs similarity index 100% rename from src/Microsoft.AspNetCore.ResponseCompression/CompressionProviderFactory.cs rename to src/Middleware/ResponseCompression/src/CompressionProviderFactory.cs diff --git a/src/Microsoft.AspNetCore.ResponseCompression/GzipCompressionProvider.cs b/src/Middleware/ResponseCompression/src/GzipCompressionProvider.cs similarity index 100% rename from src/Microsoft.AspNetCore.ResponseCompression/GzipCompressionProvider.cs rename to src/Middleware/ResponseCompression/src/GzipCompressionProvider.cs diff --git a/src/Microsoft.AspNetCore.ResponseCompression/GzipCompressionProviderOptions.cs b/src/Middleware/ResponseCompression/src/GzipCompressionProviderOptions.cs similarity index 100% rename from src/Microsoft.AspNetCore.ResponseCompression/GzipCompressionProviderOptions.cs rename to src/Middleware/ResponseCompression/src/GzipCompressionProviderOptions.cs diff --git a/src/Microsoft.AspNetCore.ResponseCompression/ICompressionProvider.cs b/src/Middleware/ResponseCompression/src/ICompressionProvider.cs similarity index 100% rename from src/Microsoft.AspNetCore.ResponseCompression/ICompressionProvider.cs rename to src/Middleware/ResponseCompression/src/ICompressionProvider.cs diff --git a/src/Microsoft.AspNetCore.ResponseCompression/IResponseCompressionProvider.cs b/src/Middleware/ResponseCompression/src/IResponseCompressionProvider.cs similarity index 100% rename from src/Microsoft.AspNetCore.ResponseCompression/IResponseCompressionProvider.cs rename to src/Middleware/ResponseCompression/src/IResponseCompressionProvider.cs diff --git a/src/Microsoft.AspNetCore.ResponseCompression/Microsoft.AspNetCore.ResponseCompression.csproj b/src/Middleware/ResponseCompression/src/Microsoft.AspNetCore.ResponseCompression.csproj similarity index 59% rename from src/Microsoft.AspNetCore.ResponseCompression/Microsoft.AspNetCore.ResponseCompression.csproj rename to src/Middleware/ResponseCompression/src/Microsoft.AspNetCore.ResponseCompression.csproj index e652961322..1b20b7b4a9 100644 --- a/src/Microsoft.AspNetCore.ResponseCompression/Microsoft.AspNetCore.ResponseCompression.csproj +++ b/src/Middleware/ResponseCompression/src/Microsoft.AspNetCore.ResponseCompression.csproj @@ -8,8 +8,8 @@ - - + + diff --git a/src/Microsoft.AspNetCore.ResponseCompression/Properties/AssemblyInfo.cs b/src/Middleware/ResponseCompression/src/Properties/AssemblyInfo.cs similarity index 100% rename from src/Microsoft.AspNetCore.ResponseCompression/Properties/AssemblyInfo.cs rename to src/Middleware/ResponseCompression/src/Properties/AssemblyInfo.cs diff --git a/src/Microsoft.AspNetCore.ResponseCompression/ResponseCompressionBuilderExtensions.cs b/src/Middleware/ResponseCompression/src/ResponseCompressionBuilderExtensions.cs similarity index 100% rename from src/Microsoft.AspNetCore.ResponseCompression/ResponseCompressionBuilderExtensions.cs rename to src/Middleware/ResponseCompression/src/ResponseCompressionBuilderExtensions.cs diff --git a/src/Microsoft.AspNetCore.ResponseCompression/ResponseCompressionDefaults.cs b/src/Middleware/ResponseCompression/src/ResponseCompressionDefaults.cs similarity index 100% rename from src/Microsoft.AspNetCore.ResponseCompression/ResponseCompressionDefaults.cs rename to src/Middleware/ResponseCompression/src/ResponseCompressionDefaults.cs diff --git a/src/Microsoft.AspNetCore.ResponseCompression/ResponseCompressionMiddleware.cs b/src/Middleware/ResponseCompression/src/ResponseCompressionMiddleware.cs similarity index 100% rename from src/Microsoft.AspNetCore.ResponseCompression/ResponseCompressionMiddleware.cs rename to src/Middleware/ResponseCompression/src/ResponseCompressionMiddleware.cs diff --git a/src/Microsoft.AspNetCore.ResponseCompression/ResponseCompressionOptions.cs b/src/Middleware/ResponseCompression/src/ResponseCompressionOptions.cs similarity index 100% rename from src/Microsoft.AspNetCore.ResponseCompression/ResponseCompressionOptions.cs rename to src/Middleware/ResponseCompression/src/ResponseCompressionOptions.cs diff --git a/src/Microsoft.AspNetCore.ResponseCompression/ResponseCompressionProvider.cs b/src/Middleware/ResponseCompression/src/ResponseCompressionProvider.cs similarity index 100% rename from src/Microsoft.AspNetCore.ResponseCompression/ResponseCompressionProvider.cs rename to src/Middleware/ResponseCompression/src/ResponseCompressionProvider.cs diff --git a/src/Microsoft.AspNetCore.ResponseCompression/ResponseCompressionServicesExtensions.cs b/src/Middleware/ResponseCompression/src/ResponseCompressionServicesExtensions.cs similarity index 100% rename from src/Microsoft.AspNetCore.ResponseCompression/ResponseCompressionServicesExtensions.cs rename to src/Middleware/ResponseCompression/src/ResponseCompressionServicesExtensions.cs diff --git a/src/Microsoft.AspNetCore.ResponseCompression/baseline.netcore.json b/src/Middleware/ResponseCompression/src/baseline.netcore.json similarity index 100% rename from src/Microsoft.AspNetCore.ResponseCompression/baseline.netcore.json rename to src/Middleware/ResponseCompression/src/baseline.netcore.json diff --git a/src/Microsoft.AspNetCore.ResponseCompression/baseline.netframework.json b/src/Middleware/ResponseCompression/src/baseline.netframework.json similarity index 100% rename from src/Microsoft.AspNetCore.ResponseCompression/baseline.netframework.json rename to src/Middleware/ResponseCompression/src/baseline.netframework.json diff --git a/test/Microsoft.AspNetCore.ResponseCompression.Tests/BodyWrapperStreamTests.cs b/src/Middleware/ResponseCompression/test/BodyWrapperStreamTests.cs similarity index 100% rename from test/Microsoft.AspNetCore.ResponseCompression.Tests/BodyWrapperStreamTests.cs rename to src/Middleware/ResponseCompression/test/BodyWrapperStreamTests.cs diff --git a/src/Middleware/ResponseCompression/test/Microsoft.AspNetCore.ResponseCompression.Tests.csproj b/src/Middleware/ResponseCompression/test/Microsoft.AspNetCore.ResponseCompression.Tests.csproj new file mode 100644 index 0000000000..47cadb7eeb --- /dev/null +++ b/src/Middleware/ResponseCompression/test/Microsoft.AspNetCore.ResponseCompression.Tests.csproj @@ -0,0 +1,18 @@ + + + + $(StandardTestTfms) + + + + + + + + + + + + + + diff --git a/test/Microsoft.AspNetCore.ResponseCompression.Tests/ResponseCompressionMiddlewareTest.cs b/src/Middleware/ResponseCompression/test/ResponseCompressionMiddlewareTest.cs similarity index 100% rename from test/Microsoft.AspNetCore.ResponseCompression.Tests/ResponseCompressionMiddlewareTest.cs rename to src/Middleware/ResponseCompression/test/ResponseCompressionMiddlewareTest.cs diff --git a/test/Microsoft.AspNetCore.ResponseCompression.Tests/testfile1kb.txt b/src/Middleware/ResponseCompression/test/testfile1kb.txt similarity index 100% rename from test/Microsoft.AspNetCore.ResponseCompression.Tests/testfile1kb.txt rename to src/Middleware/ResponseCompression/test/testfile1kb.txt diff --git a/samples/RewriteSample/Properties/launchSettings.json b/src/Middleware/Rewrite/sample/Properties/launchSettings.json similarity index 100% rename from samples/RewriteSample/Properties/launchSettings.json rename to src/Middleware/Rewrite/sample/Properties/launchSettings.json diff --git a/samples/RewriteSample/Rewrite.txt b/src/Middleware/Rewrite/sample/Rewrite.txt similarity index 100% rename from samples/RewriteSample/Rewrite.txt rename to src/Middleware/Rewrite/sample/Rewrite.txt diff --git a/src/Middleware/Rewrite/sample/RewriteSample.csproj b/src/Middleware/Rewrite/sample/RewriteSample.csproj new file mode 100644 index 0000000000..310e7d676a --- /dev/null +++ b/src/Middleware/Rewrite/sample/RewriteSample.csproj @@ -0,0 +1,13 @@ + + + + netcoreapp2.1;net461 + + + + + + + + + diff --git a/samples/RewriteSample/Startup.cs b/src/Middleware/Rewrite/sample/Startup.cs similarity index 100% rename from samples/RewriteSample/Startup.cs rename to src/Middleware/Rewrite/sample/Startup.cs diff --git a/samples/RewriteSample/UrlRewrite.xml b/src/Middleware/Rewrite/sample/UrlRewrite.xml similarity index 100% rename from samples/RewriteSample/UrlRewrite.xml rename to src/Middleware/Rewrite/sample/UrlRewrite.xml diff --git a/samples/RewriteSample/testCert.pfx b/src/Middleware/Rewrite/sample/testCert.pfx similarity index 100% rename from samples/RewriteSample/testCert.pfx rename to src/Middleware/Rewrite/sample/testCert.pfx diff --git a/src/Microsoft.AspNetCore.Rewrite/ApacheModRewriteOptionsExtensions.cs b/src/Middleware/Rewrite/src/ApacheModRewriteOptionsExtensions.cs similarity index 100% rename from src/Microsoft.AspNetCore.Rewrite/ApacheModRewriteOptionsExtensions.cs rename to src/Middleware/Rewrite/src/ApacheModRewriteOptionsExtensions.cs diff --git a/src/Microsoft.AspNetCore.Rewrite/Extensions/RewriteMiddlewareLoggingExtensions.cs b/src/Middleware/Rewrite/src/Extensions/RewriteMiddlewareLoggingExtensions.cs similarity index 100% rename from src/Microsoft.AspNetCore.Rewrite/Extensions/RewriteMiddlewareLoggingExtensions.cs rename to src/Middleware/Rewrite/src/Extensions/RewriteMiddlewareLoggingExtensions.cs diff --git a/src/Microsoft.AspNetCore.Rewrite/IISUrlRewriteOptionsExtensions.cs b/src/Middleware/Rewrite/src/IISUrlRewriteOptionsExtensions.cs similarity index 100% rename from src/Microsoft.AspNetCore.Rewrite/IISUrlRewriteOptionsExtensions.cs rename to src/Middleware/Rewrite/src/IISUrlRewriteOptionsExtensions.cs diff --git a/src/Microsoft.AspNetCore.Rewrite/IRule.cs b/src/Middleware/Rewrite/src/IRule.cs similarity index 100% rename from src/Microsoft.AspNetCore.Rewrite/IRule.cs rename to src/Middleware/Rewrite/src/IRule.cs diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/ApacheModRewrite/ApacheModRewriteRule.cs b/src/Middleware/Rewrite/src/Internal/ApacheModRewrite/ApacheModRewriteRule.cs similarity index 100% rename from src/Microsoft.AspNetCore.Rewrite/Internal/ApacheModRewrite/ApacheModRewriteRule.cs rename to src/Middleware/Rewrite/src/Internal/ApacheModRewrite/ApacheModRewriteRule.cs diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/ApacheModRewrite/Condition.cs b/src/Middleware/Rewrite/src/Internal/ApacheModRewrite/Condition.cs similarity index 100% rename from src/Microsoft.AspNetCore.Rewrite/Internal/ApacheModRewrite/Condition.cs rename to src/Middleware/Rewrite/src/Internal/ApacheModRewrite/Condition.cs diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/ApacheModRewrite/ConditionEvaluator.cs b/src/Middleware/Rewrite/src/Internal/ApacheModRewrite/ConditionEvaluator.cs similarity index 100% rename from src/Microsoft.AspNetCore.Rewrite/Internal/ApacheModRewrite/ConditionEvaluator.cs rename to src/Middleware/Rewrite/src/Internal/ApacheModRewrite/ConditionEvaluator.cs diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/ApacheModRewrite/ConditionPatternParser.cs b/src/Middleware/Rewrite/src/Internal/ApacheModRewrite/ConditionPatternParser.cs similarity index 100% rename from src/Microsoft.AspNetCore.Rewrite/Internal/ApacheModRewrite/ConditionPatternParser.cs rename to src/Middleware/Rewrite/src/Internal/ApacheModRewrite/ConditionPatternParser.cs diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/ApacheModRewrite/ConditionType.cs b/src/Middleware/Rewrite/src/Internal/ApacheModRewrite/ConditionType.cs similarity index 100% rename from src/Microsoft.AspNetCore.Rewrite/Internal/ApacheModRewrite/ConditionType.cs rename to src/Middleware/Rewrite/src/Internal/ApacheModRewrite/ConditionType.cs diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/ApacheModRewrite/CookieActionFactory.cs b/src/Middleware/Rewrite/src/Internal/ApacheModRewrite/CookieActionFactory.cs similarity index 100% rename from src/Microsoft.AspNetCore.Rewrite/Internal/ApacheModRewrite/CookieActionFactory.cs rename to src/Middleware/Rewrite/src/Internal/ApacheModRewrite/CookieActionFactory.cs diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/ApacheModRewrite/FileParser.cs b/src/Middleware/Rewrite/src/Internal/ApacheModRewrite/FileParser.cs similarity index 100% rename from src/Microsoft.AspNetCore.Rewrite/Internal/ApacheModRewrite/FileParser.cs rename to src/Middleware/Rewrite/src/Internal/ApacheModRewrite/FileParser.cs diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/ApacheModRewrite/FlagParser.cs b/src/Middleware/Rewrite/src/Internal/ApacheModRewrite/FlagParser.cs similarity index 100% rename from src/Microsoft.AspNetCore.Rewrite/Internal/ApacheModRewrite/FlagParser.cs rename to src/Middleware/Rewrite/src/Internal/ApacheModRewrite/FlagParser.cs diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/ApacheModRewrite/FlagType.cs b/src/Middleware/Rewrite/src/Internal/ApacheModRewrite/FlagType.cs similarity index 100% rename from src/Microsoft.AspNetCore.Rewrite/Internal/ApacheModRewrite/FlagType.cs rename to src/Middleware/Rewrite/src/Internal/ApacheModRewrite/FlagType.cs diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/ApacheModRewrite/Flags.cs b/src/Middleware/Rewrite/src/Internal/ApacheModRewrite/Flags.cs similarity index 100% rename from src/Microsoft.AspNetCore.Rewrite/Internal/ApacheModRewrite/Flags.cs rename to src/Middleware/Rewrite/src/Internal/ApacheModRewrite/Flags.cs diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/ApacheModRewrite/OperationType.cs b/src/Middleware/Rewrite/src/Internal/ApacheModRewrite/OperationType.cs similarity index 100% rename from src/Microsoft.AspNetCore.Rewrite/Internal/ApacheModRewrite/OperationType.cs rename to src/Middleware/Rewrite/src/Internal/ApacheModRewrite/OperationType.cs diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/ApacheModRewrite/ParsedModRewriteCondition.cs b/src/Middleware/Rewrite/src/Internal/ApacheModRewrite/ParsedModRewriteCondition.cs similarity index 100% rename from src/Microsoft.AspNetCore.Rewrite/Internal/ApacheModRewrite/ParsedModRewriteCondition.cs rename to src/Middleware/Rewrite/src/Internal/ApacheModRewrite/ParsedModRewriteCondition.cs diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/ApacheModRewrite/RuleBuilder.cs b/src/Middleware/Rewrite/src/Internal/ApacheModRewrite/RuleBuilder.cs similarity index 100% rename from src/Microsoft.AspNetCore.Rewrite/Internal/ApacheModRewrite/RuleBuilder.cs rename to src/Middleware/Rewrite/src/Internal/ApacheModRewrite/RuleBuilder.cs diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/ApacheModRewrite/RuleRegexParser.cs b/src/Middleware/Rewrite/src/Internal/ApacheModRewrite/RuleRegexParser.cs similarity index 100% rename from src/Microsoft.AspNetCore.Rewrite/Internal/ApacheModRewrite/RuleRegexParser.cs rename to src/Middleware/Rewrite/src/Internal/ApacheModRewrite/RuleRegexParser.cs diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/ApacheModRewrite/SegmentType.cs b/src/Middleware/Rewrite/src/Internal/ApacheModRewrite/SegmentType.cs similarity index 100% rename from src/Microsoft.AspNetCore.Rewrite/Internal/ApacheModRewrite/SegmentType.cs rename to src/Middleware/Rewrite/src/Internal/ApacheModRewrite/SegmentType.cs diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/ApacheModRewrite/ServerVariables.cs b/src/Middleware/Rewrite/src/Internal/ApacheModRewrite/ServerVariables.cs similarity index 100% rename from src/Microsoft.AspNetCore.Rewrite/Internal/ApacheModRewrite/ServerVariables.cs rename to src/Middleware/Rewrite/src/Internal/ApacheModRewrite/ServerVariables.cs diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/ApacheModRewrite/TestStringParser.cs b/src/Middleware/Rewrite/src/Internal/ApacheModRewrite/TestStringParser.cs similarity index 100% rename from src/Microsoft.AspNetCore.Rewrite/Internal/ApacheModRewrite/TestStringParser.cs rename to src/Middleware/Rewrite/src/Internal/ApacheModRewrite/TestStringParser.cs diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/ApacheModRewrite/Tokenizer.cs b/src/Middleware/Rewrite/src/Internal/ApacheModRewrite/Tokenizer.cs similarity index 100% rename from src/Microsoft.AspNetCore.Rewrite/Internal/ApacheModRewrite/Tokenizer.cs rename to src/Middleware/Rewrite/src/Internal/ApacheModRewrite/Tokenizer.cs diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/BackReferenceCollection.cs b/src/Middleware/Rewrite/src/Internal/BackReferenceCollection.cs similarity index 100% rename from src/Microsoft.AspNetCore.Rewrite/Internal/BackReferenceCollection.cs rename to src/Middleware/Rewrite/src/Internal/BackReferenceCollection.cs diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/DelegateRule.cs b/src/Middleware/Rewrite/src/Internal/DelegateRule.cs similarity index 100% rename from src/Microsoft.AspNetCore.Rewrite/Internal/DelegateRule.cs rename to src/Middleware/Rewrite/src/Internal/DelegateRule.cs diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/ActionType.cs b/src/Middleware/Rewrite/src/Internal/IISUrlRewrite/ActionType.cs similarity index 100% rename from src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/ActionType.cs rename to src/Middleware/Rewrite/src/Internal/IISUrlRewrite/ActionType.cs diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/Condition.cs b/src/Middleware/Rewrite/src/Internal/IISUrlRewrite/Condition.cs similarity index 100% rename from src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/Condition.cs rename to src/Middleware/Rewrite/src/Internal/IISUrlRewrite/Condition.cs diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/ConditionCollection.cs b/src/Middleware/Rewrite/src/Internal/IISUrlRewrite/ConditionCollection.cs similarity index 100% rename from src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/ConditionCollection.cs rename to src/Middleware/Rewrite/src/Internal/IISUrlRewrite/ConditionCollection.cs diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/ConditionEvaluator.cs b/src/Middleware/Rewrite/src/Internal/IISUrlRewrite/ConditionEvaluator.cs similarity index 100% rename from src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/ConditionEvaluator.cs rename to src/Middleware/Rewrite/src/Internal/IISUrlRewrite/ConditionEvaluator.cs diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/IISRewriteMap.cs b/src/Middleware/Rewrite/src/Internal/IISUrlRewrite/IISRewriteMap.cs similarity index 100% rename from src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/IISRewriteMap.cs rename to src/Middleware/Rewrite/src/Internal/IISUrlRewrite/IISRewriteMap.cs diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/IISRewriteMapCollection.cs b/src/Middleware/Rewrite/src/Internal/IISUrlRewrite/IISRewriteMapCollection.cs similarity index 100% rename from src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/IISRewriteMapCollection.cs rename to src/Middleware/Rewrite/src/Internal/IISUrlRewrite/IISRewriteMapCollection.cs diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/IISUrlRewriteRule.cs b/src/Middleware/Rewrite/src/Internal/IISUrlRewrite/IISUrlRewriteRule.cs similarity index 100% rename from src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/IISUrlRewriteRule.cs rename to src/Middleware/Rewrite/src/Internal/IISUrlRewrite/IISUrlRewriteRule.cs diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/InputParser.cs b/src/Middleware/Rewrite/src/Internal/IISUrlRewrite/InputParser.cs similarity index 100% rename from src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/InputParser.cs rename to src/Middleware/Rewrite/src/Internal/IISUrlRewrite/InputParser.cs diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/InvalidUrlRewriteFormatException.cs b/src/Middleware/Rewrite/src/Internal/IISUrlRewrite/InvalidUrlRewriteFormatException.cs similarity index 100% rename from src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/InvalidUrlRewriteFormatException.cs rename to src/Middleware/Rewrite/src/Internal/IISUrlRewrite/InvalidUrlRewriteFormatException.cs diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/LogicalGrouping.cs b/src/Middleware/Rewrite/src/Internal/IISUrlRewrite/LogicalGrouping.cs similarity index 100% rename from src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/LogicalGrouping.cs rename to src/Middleware/Rewrite/src/Internal/IISUrlRewrite/LogicalGrouping.cs diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/MatchType.cs b/src/Middleware/Rewrite/src/Internal/IISUrlRewrite/MatchType.cs similarity index 100% rename from src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/MatchType.cs rename to src/Middleware/Rewrite/src/Internal/IISUrlRewrite/MatchType.cs diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/PatternSyntax.cs b/src/Middleware/Rewrite/src/Internal/IISUrlRewrite/PatternSyntax.cs similarity index 100% rename from src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/PatternSyntax.cs rename to src/Middleware/Rewrite/src/Internal/IISUrlRewrite/PatternSyntax.cs diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/RedirectType.cs b/src/Middleware/Rewrite/src/Internal/IISUrlRewrite/RedirectType.cs similarity index 100% rename from src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/RedirectType.cs rename to src/Middleware/Rewrite/src/Internal/IISUrlRewrite/RedirectType.cs diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/RewriteMapParser.cs b/src/Middleware/Rewrite/src/Internal/IISUrlRewrite/RewriteMapParser.cs similarity index 100% rename from src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/RewriteMapParser.cs rename to src/Middleware/Rewrite/src/Internal/IISUrlRewrite/RewriteMapParser.cs diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/RewriteTags.cs b/src/Middleware/Rewrite/src/Internal/IISUrlRewrite/RewriteTags.cs similarity index 100% rename from src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/RewriteTags.cs rename to src/Middleware/Rewrite/src/Internal/IISUrlRewrite/RewriteTags.cs diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/ServerVariables.cs b/src/Middleware/Rewrite/src/Internal/IISUrlRewrite/ServerVariables.cs similarity index 100% rename from src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/ServerVariables.cs rename to src/Middleware/Rewrite/src/Internal/IISUrlRewrite/ServerVariables.cs diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/UriMatchCondition.cs b/src/Middleware/Rewrite/src/Internal/IISUrlRewrite/UriMatchCondition.cs similarity index 100% rename from src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/UriMatchCondition.cs rename to src/Middleware/Rewrite/src/Internal/IISUrlRewrite/UriMatchCondition.cs diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/UriMatchPart.cs b/src/Middleware/Rewrite/src/Internal/IISUrlRewrite/UriMatchPart.cs similarity index 100% rename from src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/UriMatchPart.cs rename to src/Middleware/Rewrite/src/Internal/IISUrlRewrite/UriMatchPart.cs diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/UrlRewriteFileParser.cs b/src/Middleware/Rewrite/src/Internal/IISUrlRewrite/UrlRewriteFileParser.cs similarity index 100% rename from src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/UrlRewriteFileParser.cs rename to src/Middleware/Rewrite/src/Internal/IISUrlRewrite/UrlRewriteFileParser.cs diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/UrlRewriteRuleBuilder.cs b/src/Middleware/Rewrite/src/Internal/IISUrlRewrite/UrlRewriteRuleBuilder.cs similarity index 100% rename from src/Microsoft.AspNetCore.Rewrite/Internal/IISUrlRewrite/UrlRewriteRuleBuilder.cs rename to src/Middleware/Rewrite/src/Internal/IISUrlRewrite/UrlRewriteRuleBuilder.cs diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/MatchResults.cs b/src/Middleware/Rewrite/src/Internal/MatchResults.cs similarity index 100% rename from src/Microsoft.AspNetCore.Rewrite/Internal/MatchResults.cs rename to src/Middleware/Rewrite/src/Internal/MatchResults.cs diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/ParserContext.cs b/src/Middleware/Rewrite/src/Internal/ParserContext.cs similarity index 100% rename from src/Microsoft.AspNetCore.Rewrite/Internal/ParserContext.cs rename to src/Middleware/Rewrite/src/Internal/ParserContext.cs diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/Pattern.cs b/src/Middleware/Rewrite/src/Internal/Pattern.cs similarity index 100% rename from src/Microsoft.AspNetCore.Rewrite/Internal/Pattern.cs rename to src/Middleware/Rewrite/src/Internal/Pattern.cs diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegment.cs b/src/Middleware/Rewrite/src/Internal/PatternSegment.cs similarity index 100% rename from src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegment.cs rename to src/Middleware/Rewrite/src/Internal/PatternSegment.cs diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/ConditionMatchSegment.cs b/src/Middleware/Rewrite/src/Internal/PatternSegments/ConditionMatchSegment.cs similarity index 100% rename from src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/ConditionMatchSegment.cs rename to src/Middleware/Rewrite/src/Internal/PatternSegments/ConditionMatchSegment.cs diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/DateTimeSegment.cs b/src/Middleware/Rewrite/src/Internal/PatternSegments/DateTimeSegment.cs similarity index 100% rename from src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/DateTimeSegment.cs rename to src/Middleware/Rewrite/src/Internal/PatternSegments/DateTimeSegment.cs diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/HeaderSegment.cs b/src/Middleware/Rewrite/src/Internal/PatternSegments/HeaderSegment.cs similarity index 100% rename from src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/HeaderSegment.cs rename to src/Middleware/Rewrite/src/Internal/PatternSegments/HeaderSegment.cs diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/IsHttpsModSegment.cs b/src/Middleware/Rewrite/src/Internal/PatternSegments/IsHttpsModSegment.cs similarity index 100% rename from src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/IsHttpsModSegment.cs rename to src/Middleware/Rewrite/src/Internal/PatternSegments/IsHttpsModSegment.cs diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/IsHttpsUrlSegment.cs b/src/Middleware/Rewrite/src/Internal/PatternSegments/IsHttpsUrlSegment.cs similarity index 100% rename from src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/IsHttpsUrlSegment.cs rename to src/Middleware/Rewrite/src/Internal/PatternSegments/IsHttpsUrlSegment.cs diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/IsIPV6Segment.cs b/src/Middleware/Rewrite/src/Internal/PatternSegments/IsIPV6Segment.cs similarity index 100% rename from src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/IsIPV6Segment.cs rename to src/Middleware/Rewrite/src/Internal/PatternSegments/IsIPV6Segment.cs diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/LiteralSegment.cs b/src/Middleware/Rewrite/src/Internal/PatternSegments/LiteralSegment.cs similarity index 100% rename from src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/LiteralSegment.cs rename to src/Middleware/Rewrite/src/Internal/PatternSegments/LiteralSegment.cs diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/LocalAddressSegment.cs b/src/Middleware/Rewrite/src/Internal/PatternSegments/LocalAddressSegment.cs similarity index 100% rename from src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/LocalAddressSegment.cs rename to src/Middleware/Rewrite/src/Internal/PatternSegments/LocalAddressSegment.cs diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/LocalPortSegment.cs b/src/Middleware/Rewrite/src/Internal/PatternSegments/LocalPortSegment.cs similarity index 100% rename from src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/LocalPortSegment.cs rename to src/Middleware/Rewrite/src/Internal/PatternSegments/LocalPortSegment.cs diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/QueryStringSegment.cs b/src/Middleware/Rewrite/src/Internal/PatternSegments/QueryStringSegment.cs similarity index 100% rename from src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/QueryStringSegment.cs rename to src/Middleware/Rewrite/src/Internal/PatternSegments/QueryStringSegment.cs diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/RemoteAddressSegment.cs b/src/Middleware/Rewrite/src/Internal/PatternSegments/RemoteAddressSegment.cs similarity index 100% rename from src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/RemoteAddressSegment.cs rename to src/Middleware/Rewrite/src/Internal/PatternSegments/RemoteAddressSegment.cs diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/RemotePortSegment.cs b/src/Middleware/Rewrite/src/Internal/PatternSegments/RemotePortSegment.cs similarity index 100% rename from src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/RemotePortSegment.cs rename to src/Middleware/Rewrite/src/Internal/PatternSegments/RemotePortSegment.cs diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/RequestFilenameSegment.cs b/src/Middleware/Rewrite/src/Internal/PatternSegments/RequestFilenameSegment.cs similarity index 100% rename from src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/RequestFilenameSegment.cs rename to src/Middleware/Rewrite/src/Internal/PatternSegments/RequestFilenameSegment.cs diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/RequestMethodSegment.cs b/src/Middleware/Rewrite/src/Internal/PatternSegments/RequestMethodSegment.cs similarity index 100% rename from src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/RequestMethodSegment.cs rename to src/Middleware/Rewrite/src/Internal/PatternSegments/RequestMethodSegment.cs diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/RewriteMapSegment.cs b/src/Middleware/Rewrite/src/Internal/PatternSegments/RewriteMapSegment.cs similarity index 100% rename from src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/RewriteMapSegment.cs rename to src/Middleware/Rewrite/src/Internal/PatternSegments/RewriteMapSegment.cs diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/RuleMatchSegment.cs b/src/Middleware/Rewrite/src/Internal/PatternSegments/RuleMatchSegment.cs similarity index 100% rename from src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/RuleMatchSegment.cs rename to src/Middleware/Rewrite/src/Internal/PatternSegments/RuleMatchSegment.cs diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/SchemeSegment.cs b/src/Middleware/Rewrite/src/Internal/PatternSegments/SchemeSegment.cs similarity index 100% rename from src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/SchemeSegment.cs rename to src/Middleware/Rewrite/src/Internal/PatternSegments/SchemeSegment.cs diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/ServerProtocolSegment.cs b/src/Middleware/Rewrite/src/Internal/PatternSegments/ServerProtocolSegment.cs similarity index 100% rename from src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/ServerProtocolSegment.cs rename to src/Middleware/Rewrite/src/Internal/PatternSegments/ServerProtocolSegment.cs diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/ToLowerSegment.cs b/src/Middleware/Rewrite/src/Internal/PatternSegments/ToLowerSegment.cs similarity index 100% rename from src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/ToLowerSegment.cs rename to src/Middleware/Rewrite/src/Internal/PatternSegments/ToLowerSegment.cs diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/UrlEncodeSegment.cs b/src/Middleware/Rewrite/src/Internal/PatternSegments/UrlEncodeSegment.cs similarity index 100% rename from src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/UrlEncodeSegment.cs rename to src/Middleware/Rewrite/src/Internal/PatternSegments/UrlEncodeSegment.cs diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/UrlSegment.cs b/src/Middleware/Rewrite/src/Internal/PatternSegments/UrlSegment.cs similarity index 100% rename from src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/UrlSegment.cs rename to src/Middleware/Rewrite/src/Internal/PatternSegments/UrlSegment.cs diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/RedirectRule.cs b/src/Middleware/Rewrite/src/Internal/RedirectRule.cs similarity index 100% rename from src/Microsoft.AspNetCore.Rewrite/Internal/RedirectRule.cs rename to src/Middleware/Rewrite/src/Internal/RedirectRule.cs diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/RedirectToHttpsRule.cs b/src/Middleware/Rewrite/src/Internal/RedirectToHttpsRule.cs similarity index 100% rename from src/Microsoft.AspNetCore.Rewrite/Internal/RedirectToHttpsRule.cs rename to src/Middleware/Rewrite/src/Internal/RedirectToHttpsRule.cs diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/RedirectToWwwRule.cs b/src/Middleware/Rewrite/src/Internal/RedirectToWwwRule.cs similarity index 100% rename from src/Microsoft.AspNetCore.Rewrite/Internal/RedirectToWwwRule.cs rename to src/Middleware/Rewrite/src/Internal/RedirectToWwwRule.cs diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/RewriteRule.cs b/src/Middleware/Rewrite/src/Internal/RewriteRule.cs similarity index 100% rename from src/Microsoft.AspNetCore.Rewrite/Internal/RewriteRule.cs rename to src/Middleware/Rewrite/src/Internal/RewriteRule.cs diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlAction.cs b/src/Middleware/Rewrite/src/Internal/UrlAction.cs similarity index 100% rename from src/Microsoft.AspNetCore.Rewrite/Internal/UrlAction.cs rename to src/Middleware/Rewrite/src/Internal/UrlAction.cs diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/AbortAction.cs b/src/Middleware/Rewrite/src/Internal/UrlActions/AbortAction.cs similarity index 100% rename from src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/AbortAction.cs rename to src/Middleware/Rewrite/src/Internal/UrlActions/AbortAction.cs diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/ChangeCookieAction.cs b/src/Middleware/Rewrite/src/Internal/UrlActions/ChangeCookieAction.cs similarity index 100% rename from src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/ChangeCookieAction.cs rename to src/Middleware/Rewrite/src/Internal/UrlActions/ChangeCookieAction.cs diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/CustomResponseAction.cs b/src/Middleware/Rewrite/src/Internal/UrlActions/CustomResponseAction.cs similarity index 100% rename from src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/CustomResponseAction.cs rename to src/Middleware/Rewrite/src/Internal/UrlActions/CustomResponseAction.cs diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/ForbiddenAction.cs b/src/Middleware/Rewrite/src/Internal/UrlActions/ForbiddenAction.cs similarity index 100% rename from src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/ForbiddenAction.cs rename to src/Middleware/Rewrite/src/Internal/UrlActions/ForbiddenAction.cs diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/GoneAction.cs b/src/Middleware/Rewrite/src/Internal/UrlActions/GoneAction.cs similarity index 100% rename from src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/GoneAction.cs rename to src/Middleware/Rewrite/src/Internal/UrlActions/GoneAction.cs diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/NoneAction.cs b/src/Middleware/Rewrite/src/Internal/UrlActions/NoneAction.cs similarity index 100% rename from src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/NoneAction.cs rename to src/Middleware/Rewrite/src/Internal/UrlActions/NoneAction.cs diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/RedirectAction.cs b/src/Middleware/Rewrite/src/Internal/UrlActions/RedirectAction.cs similarity index 100% rename from src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/RedirectAction.cs rename to src/Middleware/Rewrite/src/Internal/UrlActions/RedirectAction.cs diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/RewriteAction.cs b/src/Middleware/Rewrite/src/Internal/UrlActions/RewriteAction.cs similarity index 100% rename from src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/RewriteAction.cs rename to src/Middleware/Rewrite/src/Internal/UrlActions/RewriteAction.cs diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlMatch.cs b/src/Middleware/Rewrite/src/Internal/UrlMatch.cs similarity index 100% rename from src/Microsoft.AspNetCore.Rewrite/Internal/UrlMatch.cs rename to src/Middleware/Rewrite/src/Internal/UrlMatch.cs diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlMatches/ExactMatch.cs b/src/Middleware/Rewrite/src/Internal/UrlMatches/ExactMatch.cs similarity index 100% rename from src/Microsoft.AspNetCore.Rewrite/Internal/UrlMatches/ExactMatch.cs rename to src/Middleware/Rewrite/src/Internal/UrlMatches/ExactMatch.cs diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlMatches/FileSizeMatch.cs b/src/Middleware/Rewrite/src/Internal/UrlMatches/FileSizeMatch.cs similarity index 100% rename from src/Microsoft.AspNetCore.Rewrite/Internal/UrlMatches/FileSizeMatch.cs rename to src/Middleware/Rewrite/src/Internal/UrlMatches/FileSizeMatch.cs diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlMatches/IntegerMatch.cs b/src/Middleware/Rewrite/src/Internal/UrlMatches/IntegerMatch.cs similarity index 100% rename from src/Microsoft.AspNetCore.Rewrite/Internal/UrlMatches/IntegerMatch.cs rename to src/Middleware/Rewrite/src/Internal/UrlMatches/IntegerMatch.cs diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlMatches/IntegerOperation.cs b/src/Middleware/Rewrite/src/Internal/UrlMatches/IntegerOperation.cs similarity index 100% rename from src/Microsoft.AspNetCore.Rewrite/Internal/UrlMatches/IntegerOperation.cs rename to src/Middleware/Rewrite/src/Internal/UrlMatches/IntegerOperation.cs diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlMatches/IsDirectoryMatch.cs b/src/Middleware/Rewrite/src/Internal/UrlMatches/IsDirectoryMatch.cs similarity index 100% rename from src/Microsoft.AspNetCore.Rewrite/Internal/UrlMatches/IsDirectoryMatch.cs rename to src/Middleware/Rewrite/src/Internal/UrlMatches/IsDirectoryMatch.cs diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlMatches/IsFileMatch.cs b/src/Middleware/Rewrite/src/Internal/UrlMatches/IsFileMatch.cs similarity index 100% rename from src/Microsoft.AspNetCore.Rewrite/Internal/UrlMatches/IsFileMatch.cs rename to src/Middleware/Rewrite/src/Internal/UrlMatches/IsFileMatch.cs diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlMatches/RegexMatch.cs b/src/Middleware/Rewrite/src/Internal/UrlMatches/RegexMatch.cs similarity index 100% rename from src/Microsoft.AspNetCore.Rewrite/Internal/UrlMatches/RegexMatch.cs rename to src/Middleware/Rewrite/src/Internal/UrlMatches/RegexMatch.cs diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlMatches/StringMatch.cs b/src/Middleware/Rewrite/src/Internal/UrlMatches/StringMatch.cs similarity index 100% rename from src/Microsoft.AspNetCore.Rewrite/Internal/UrlMatches/StringMatch.cs rename to src/Middleware/Rewrite/src/Internal/UrlMatches/StringMatch.cs diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlMatches/StringOperation.cs b/src/Middleware/Rewrite/src/Internal/UrlMatches/StringOperation.cs similarity index 100% rename from src/Microsoft.AspNetCore.Rewrite/Internal/UrlMatches/StringOperation.cs rename to src/Middleware/Rewrite/src/Internal/UrlMatches/StringOperation.cs diff --git a/src/Middleware/Rewrite/src/Microsoft.AspNetCore.Rewrite.csproj b/src/Middleware/Rewrite/src/Microsoft.AspNetCore.Rewrite.csproj new file mode 100644 index 0000000000..48a6e913f5 --- /dev/null +++ b/src/Middleware/Rewrite/src/Microsoft.AspNetCore.Rewrite.csproj @@ -0,0 +1,23 @@ + + + + ASP.NET Core basic middleware for rewriting URLs. Includes: +* Support for custom URL rewrite rules +* Support for running IIS URL Rewrite module rules +* Support for running Apache mod_rewrite rules. + netstandard2.0 + $(NoWarn);CS1591 + true + aspnetcore;urlrewrite;mod_rewrite + + + + + + + + + + + + diff --git a/src/Microsoft.AspNetCore.Rewrite/Properties/AssemblyInfo.cs b/src/Middleware/Rewrite/src/Properties/AssemblyInfo.cs similarity index 100% rename from src/Microsoft.AspNetCore.Rewrite/Properties/AssemblyInfo.cs rename to src/Middleware/Rewrite/src/Properties/AssemblyInfo.cs diff --git a/src/Microsoft.AspNetCore.Rewrite/Properties/Resources.Designer.cs b/src/Middleware/Rewrite/src/Properties/Resources.Designer.cs similarity index 100% rename from src/Microsoft.AspNetCore.Rewrite/Properties/Resources.Designer.cs rename to src/Middleware/Rewrite/src/Properties/Resources.Designer.cs diff --git a/src/Microsoft.AspNetCore.Rewrite/Resources.resx b/src/Middleware/Rewrite/src/Resources.resx similarity index 100% rename from src/Microsoft.AspNetCore.Rewrite/Resources.resx rename to src/Middleware/Rewrite/src/Resources.resx diff --git a/src/Microsoft.AspNetCore.Rewrite/RewriteBuilderExtensions.cs b/src/Middleware/Rewrite/src/RewriteBuilderExtensions.cs similarity index 100% rename from src/Microsoft.AspNetCore.Rewrite/RewriteBuilderExtensions.cs rename to src/Middleware/Rewrite/src/RewriteBuilderExtensions.cs diff --git a/src/Microsoft.AspNetCore.Rewrite/RewriteContext.cs b/src/Middleware/Rewrite/src/RewriteContext.cs similarity index 100% rename from src/Microsoft.AspNetCore.Rewrite/RewriteContext.cs rename to src/Middleware/Rewrite/src/RewriteContext.cs diff --git a/src/Microsoft.AspNetCore.Rewrite/RewriteMiddleware.cs b/src/Middleware/Rewrite/src/RewriteMiddleware.cs similarity index 100% rename from src/Microsoft.AspNetCore.Rewrite/RewriteMiddleware.cs rename to src/Middleware/Rewrite/src/RewriteMiddleware.cs diff --git a/src/Microsoft.AspNetCore.Rewrite/RewriteOptions.cs b/src/Middleware/Rewrite/src/RewriteOptions.cs similarity index 100% rename from src/Microsoft.AspNetCore.Rewrite/RewriteOptions.cs rename to src/Middleware/Rewrite/src/RewriteOptions.cs diff --git a/src/Microsoft.AspNetCore.Rewrite/RewriteOptionsExtensions.cs b/src/Middleware/Rewrite/src/RewriteOptionsExtensions.cs similarity index 100% rename from src/Microsoft.AspNetCore.Rewrite/RewriteOptionsExtensions.cs rename to src/Middleware/Rewrite/src/RewriteOptionsExtensions.cs diff --git a/src/Microsoft.AspNetCore.Rewrite/RuleResult.cs b/src/Middleware/Rewrite/src/RuleResult.cs similarity index 100% rename from src/Microsoft.AspNetCore.Rewrite/RuleResult.cs rename to src/Middleware/Rewrite/src/RuleResult.cs diff --git a/src/Microsoft.AspNetCore.Rewrite/baseline.netcore.json b/src/Middleware/Rewrite/src/baseline.netcore.json similarity index 100% rename from src/Microsoft.AspNetCore.Rewrite/baseline.netcore.json rename to src/Middleware/Rewrite/src/baseline.netcore.json diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/ApacheModRewrite/ConditionPatternParserTest.cs b/src/Middleware/Rewrite/test/ApacheModRewrite/ConditionPatternParserTest.cs similarity index 100% rename from test/Microsoft.AspNetCore.Rewrite.Tests/ApacheModRewrite/ConditionPatternParserTest.cs rename to src/Middleware/Rewrite/test/ApacheModRewrite/ConditionPatternParserTest.cs diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/ApacheModRewrite/CookieActionFactoryTest.cs b/src/Middleware/Rewrite/test/ApacheModRewrite/CookieActionFactoryTest.cs similarity index 100% rename from test/Microsoft.AspNetCore.Rewrite.Tests/ApacheModRewrite/CookieActionFactoryTest.cs rename to src/Middleware/Rewrite/test/ApacheModRewrite/CookieActionFactoryTest.cs diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/ApacheModRewrite/FlagParserTest.cs b/src/Middleware/Rewrite/test/ApacheModRewrite/FlagParserTest.cs similarity index 100% rename from test/Microsoft.AspNetCore.Rewrite.Tests/ApacheModRewrite/FlagParserTest.cs rename to src/Middleware/Rewrite/test/ApacheModRewrite/FlagParserTest.cs diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/ApacheModRewrite/FormatExceptionTests.cs b/src/Middleware/Rewrite/test/ApacheModRewrite/FormatExceptionTests.cs similarity index 100% rename from test/Microsoft.AspNetCore.Rewrite.Tests/ApacheModRewrite/FormatExceptionTests.cs rename to src/Middleware/Rewrite/test/ApacheModRewrite/FormatExceptionTests.cs diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/ApacheModRewrite/ModRewriteMiddlewareTest.cs b/src/Middleware/Rewrite/test/ApacheModRewrite/ModRewriteMiddlewareTest.cs similarity index 100% rename from test/Microsoft.AspNetCore.Rewrite.Tests/ApacheModRewrite/ModRewriteMiddlewareTest.cs rename to src/Middleware/Rewrite/test/ApacheModRewrite/ModRewriteMiddlewareTest.cs diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/ApacheModRewrite/RewriteTokenizerTest.cs b/src/Middleware/Rewrite/test/ApacheModRewrite/RewriteTokenizerTest.cs similarity index 100% rename from test/Microsoft.AspNetCore.Rewrite.Tests/ApacheModRewrite/RewriteTokenizerTest.cs rename to src/Middleware/Rewrite/test/ApacheModRewrite/RewriteTokenizerTest.cs diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/ApacheModRewrite/RuleBuilderTest.cs b/src/Middleware/Rewrite/test/ApacheModRewrite/RuleBuilderTest.cs similarity index 100% rename from test/Microsoft.AspNetCore.Rewrite.Tests/ApacheModRewrite/RuleBuilderTest.cs rename to src/Middleware/Rewrite/test/ApacheModRewrite/RuleBuilderTest.cs diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/ApacheModRewrite/RuleRegexParserTest.cs b/src/Middleware/Rewrite/test/ApacheModRewrite/RuleRegexParserTest.cs similarity index 100% rename from test/Microsoft.AspNetCore.Rewrite.Tests/ApacheModRewrite/RuleRegexParserTest.cs rename to src/Middleware/Rewrite/test/ApacheModRewrite/RuleRegexParserTest.cs diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/ApacheModRewrite/TestStringParserTests.cs b/src/Middleware/Rewrite/test/ApacheModRewrite/TestStringParserTests.cs similarity index 100% rename from test/Microsoft.AspNetCore.Rewrite.Tests/ApacheModRewrite/TestStringParserTests.cs rename to src/Middleware/Rewrite/test/ApacheModRewrite/TestStringParserTests.cs diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/FileParserTests.cs b/src/Middleware/Rewrite/test/IISUrlRewrite/FileParserTests.cs similarity index 100% rename from test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/FileParserTests.cs rename to src/Middleware/Rewrite/test/IISUrlRewrite/FileParserTests.cs diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/FormatExceptionHandlingTests.cs b/src/Middleware/Rewrite/test/IISUrlRewrite/FormatExceptionHandlingTests.cs similarity index 100% rename from test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/FormatExceptionHandlingTests.cs rename to src/Middleware/Rewrite/test/IISUrlRewrite/FormatExceptionHandlingTests.cs diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/InputParserTests.cs b/src/Middleware/Rewrite/test/IISUrlRewrite/InputParserTests.cs similarity index 100% rename from test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/InputParserTests.cs rename to src/Middleware/Rewrite/test/IISUrlRewrite/InputParserTests.cs diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/InvalidUrlRewriteFormatExceptionHandlingTests.cs b/src/Middleware/Rewrite/test/IISUrlRewrite/InvalidUrlRewriteFormatExceptionHandlingTests.cs similarity index 100% rename from test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/InvalidUrlRewriteFormatExceptionHandlingTests.cs rename to src/Middleware/Rewrite/test/IISUrlRewrite/InvalidUrlRewriteFormatExceptionHandlingTests.cs diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/MiddleWareTests.cs b/src/Middleware/Rewrite/test/IISUrlRewrite/MiddleWareTests.cs similarity index 100% rename from test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/MiddleWareTests.cs rename to src/Middleware/Rewrite/test/IISUrlRewrite/MiddleWareTests.cs diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/RewriteMapParserTests.cs b/src/Middleware/Rewrite/test/IISUrlRewrite/RewriteMapParserTests.cs similarity index 100% rename from test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/RewriteMapParserTests.cs rename to src/Middleware/Rewrite/test/IISUrlRewrite/RewriteMapParserTests.cs diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/ServerVariableTests.cs b/src/Middleware/Rewrite/test/IISUrlRewrite/ServerVariableTests.cs similarity index 100% rename from test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/ServerVariableTests.cs rename to src/Middleware/Rewrite/test/IISUrlRewrite/ServerVariableTests.cs diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/UrlRewriteApplicationTests.cs b/src/Middleware/Rewrite/test/IISUrlRewrite/UrlRewriteApplicationTests.cs similarity index 100% rename from test/Microsoft.AspNetCore.Rewrite.Tests/IISUrlRewrite/UrlRewriteApplicationTests.cs rename to src/Middleware/Rewrite/test/IISUrlRewrite/UrlRewriteApplicationTests.cs diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/Microsoft.AspNetCore.Rewrite.Tests.csproj b/src/Middleware/Rewrite/test/Microsoft.AspNetCore.Rewrite.Tests.csproj similarity index 61% rename from test/Microsoft.AspNetCore.Rewrite.Tests/Microsoft.AspNetCore.Rewrite.Tests.csproj rename to src/Middleware/Rewrite/test/Microsoft.AspNetCore.Rewrite.Tests.csproj index ef02b99631..1593497c61 100644 --- a/test/Microsoft.AspNetCore.Rewrite.Tests/Microsoft.AspNetCore.Rewrite.Tests.csproj +++ b/src/Middleware/Rewrite/test/Microsoft.AspNetCore.Rewrite.Tests.csproj @@ -5,7 +5,7 @@ - + diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/MiddlewareTests.cs b/src/Middleware/Rewrite/test/MiddlewareTests.cs similarity index 100% rename from test/Microsoft.AspNetCore.Rewrite.Tests/MiddlewareTests.cs rename to src/Middleware/Rewrite/test/MiddlewareTests.cs diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/PatternSegments/ConditionMatchSegmentTests.cs b/src/Middleware/Rewrite/test/PatternSegments/ConditionMatchSegmentTests.cs similarity index 100% rename from test/Microsoft.AspNetCore.Rewrite.Tests/PatternSegments/ConditionMatchSegmentTests.cs rename to src/Middleware/Rewrite/test/PatternSegments/ConditionMatchSegmentTests.cs diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/PatternSegments/DateTimeSegmentTests.cs b/src/Middleware/Rewrite/test/PatternSegments/DateTimeSegmentTests.cs similarity index 100% rename from test/Microsoft.AspNetCore.Rewrite.Tests/PatternSegments/DateTimeSegmentTests.cs rename to src/Middleware/Rewrite/test/PatternSegments/DateTimeSegmentTests.cs diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/PatternSegments/HeaderSegmentTests.cs b/src/Middleware/Rewrite/test/PatternSegments/HeaderSegmentTests.cs similarity index 100% rename from test/Microsoft.AspNetCore.Rewrite.Tests/PatternSegments/HeaderSegmentTests.cs rename to src/Middleware/Rewrite/test/PatternSegments/HeaderSegmentTests.cs diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/PatternSegments/IsHttpsModSegmentTests.cs b/src/Middleware/Rewrite/test/PatternSegments/IsHttpsModSegmentTests.cs similarity index 100% rename from test/Microsoft.AspNetCore.Rewrite.Tests/PatternSegments/IsHttpsModSegmentTests.cs rename to src/Middleware/Rewrite/test/PatternSegments/IsHttpsModSegmentTests.cs diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/PatternSegments/IsHttpsSegmentTests.cs b/src/Middleware/Rewrite/test/PatternSegments/IsHttpsSegmentTests.cs similarity index 100% rename from test/Microsoft.AspNetCore.Rewrite.Tests/PatternSegments/IsHttpsSegmentTests.cs rename to src/Middleware/Rewrite/test/PatternSegments/IsHttpsSegmentTests.cs diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/PatternSegments/IsIPV6SegmentTests.cs b/src/Middleware/Rewrite/test/PatternSegments/IsIPV6SegmentTests.cs similarity index 100% rename from test/Microsoft.AspNetCore.Rewrite.Tests/PatternSegments/IsIPV6SegmentTests.cs rename to src/Middleware/Rewrite/test/PatternSegments/IsIPV6SegmentTests.cs diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/PatternSegments/LIteralSegmentTests.cs b/src/Middleware/Rewrite/test/PatternSegments/LIteralSegmentTests.cs similarity index 100% rename from test/Microsoft.AspNetCore.Rewrite.Tests/PatternSegments/LIteralSegmentTests.cs rename to src/Middleware/Rewrite/test/PatternSegments/LIteralSegmentTests.cs diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/PatternSegments/LocalAddressSegmentTests.cs b/src/Middleware/Rewrite/test/PatternSegments/LocalAddressSegmentTests.cs similarity index 100% rename from test/Microsoft.AspNetCore.Rewrite.Tests/PatternSegments/LocalAddressSegmentTests.cs rename to src/Middleware/Rewrite/test/PatternSegments/LocalAddressSegmentTests.cs diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/PatternSegments/LocalPortSegmentTests.cs b/src/Middleware/Rewrite/test/PatternSegments/LocalPortSegmentTests.cs similarity index 100% rename from test/Microsoft.AspNetCore.Rewrite.Tests/PatternSegments/LocalPortSegmentTests.cs rename to src/Middleware/Rewrite/test/PatternSegments/LocalPortSegmentTests.cs diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/PatternSegments/QueryStringSegmentTests.cs b/src/Middleware/Rewrite/test/PatternSegments/QueryStringSegmentTests.cs similarity index 100% rename from test/Microsoft.AspNetCore.Rewrite.Tests/PatternSegments/QueryStringSegmentTests.cs rename to src/Middleware/Rewrite/test/PatternSegments/QueryStringSegmentTests.cs diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/PatternSegments/RemoteAddressSegmentTests.cs b/src/Middleware/Rewrite/test/PatternSegments/RemoteAddressSegmentTests.cs similarity index 100% rename from test/Microsoft.AspNetCore.Rewrite.Tests/PatternSegments/RemoteAddressSegmentTests.cs rename to src/Middleware/Rewrite/test/PatternSegments/RemoteAddressSegmentTests.cs diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/PatternSegments/RemotePortSegmentTests.cs b/src/Middleware/Rewrite/test/PatternSegments/RemotePortSegmentTests.cs similarity index 100% rename from test/Microsoft.AspNetCore.Rewrite.Tests/PatternSegments/RemotePortSegmentTests.cs rename to src/Middleware/Rewrite/test/PatternSegments/RemotePortSegmentTests.cs diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/PatternSegments/RequestFilenameSegmentTests.cs b/src/Middleware/Rewrite/test/PatternSegments/RequestFilenameSegmentTests.cs similarity index 100% rename from test/Microsoft.AspNetCore.Rewrite.Tests/PatternSegments/RequestFilenameSegmentTests.cs rename to src/Middleware/Rewrite/test/PatternSegments/RequestFilenameSegmentTests.cs diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/PatternSegments/RequestMethodSegmentTests.cs b/src/Middleware/Rewrite/test/PatternSegments/RequestMethodSegmentTests.cs similarity index 100% rename from test/Microsoft.AspNetCore.Rewrite.Tests/PatternSegments/RequestMethodSegmentTests.cs rename to src/Middleware/Rewrite/test/PatternSegments/RequestMethodSegmentTests.cs diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/PatternSegments/RuleMatchSegmentTests.cs b/src/Middleware/Rewrite/test/PatternSegments/RuleMatchSegmentTests.cs similarity index 100% rename from test/Microsoft.AspNetCore.Rewrite.Tests/PatternSegments/RuleMatchSegmentTests.cs rename to src/Middleware/Rewrite/test/PatternSegments/RuleMatchSegmentTests.cs diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/PatternSegments/SchemeSegmentTests.cs b/src/Middleware/Rewrite/test/PatternSegments/SchemeSegmentTests.cs similarity index 100% rename from test/Microsoft.AspNetCore.Rewrite.Tests/PatternSegments/SchemeSegmentTests.cs rename to src/Middleware/Rewrite/test/PatternSegments/SchemeSegmentTests.cs diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/PatternSegments/ServerProtocolSegmentTests.cs b/src/Middleware/Rewrite/test/PatternSegments/ServerProtocolSegmentTests.cs similarity index 100% rename from test/Microsoft.AspNetCore.Rewrite.Tests/PatternSegments/ServerProtocolSegmentTests.cs rename to src/Middleware/Rewrite/test/PatternSegments/ServerProtocolSegmentTests.cs diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/PatternSegments/ToLowerSegmentTests.cs b/src/Middleware/Rewrite/test/PatternSegments/ToLowerSegmentTests.cs similarity index 100% rename from test/Microsoft.AspNetCore.Rewrite.Tests/PatternSegments/ToLowerSegmentTests.cs rename to src/Middleware/Rewrite/test/PatternSegments/ToLowerSegmentTests.cs diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/PatternSegments/UrlEncodeSegmentTests.cs b/src/Middleware/Rewrite/test/PatternSegments/UrlEncodeSegmentTests.cs similarity index 100% rename from test/Microsoft.AspNetCore.Rewrite.Tests/PatternSegments/UrlEncodeSegmentTests.cs rename to src/Middleware/Rewrite/test/PatternSegments/UrlEncodeSegmentTests.cs diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/PatternSegments/UrlSegmentTests.cs b/src/Middleware/Rewrite/test/PatternSegments/UrlSegmentTests.cs similarity index 100% rename from test/Microsoft.AspNetCore.Rewrite.Tests/PatternSegments/UrlSegmentTests.cs rename to src/Middleware/Rewrite/test/PatternSegments/UrlSegmentTests.cs diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/UrlActions/AbortActionTests.cs b/src/Middleware/Rewrite/test/UrlActions/AbortActionTests.cs similarity index 100% rename from test/Microsoft.AspNetCore.Rewrite.Tests/UrlActions/AbortActionTests.cs rename to src/Middleware/Rewrite/test/UrlActions/AbortActionTests.cs diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/UrlActions/ChangeCookieActionTests.cs b/src/Middleware/Rewrite/test/UrlActions/ChangeCookieActionTests.cs similarity index 100% rename from test/Microsoft.AspNetCore.Rewrite.Tests/UrlActions/ChangeCookieActionTests.cs rename to src/Middleware/Rewrite/test/UrlActions/ChangeCookieActionTests.cs diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/UrlActions/ForbiddenActionTests.cs b/src/Middleware/Rewrite/test/UrlActions/ForbiddenActionTests.cs similarity index 100% rename from test/Microsoft.AspNetCore.Rewrite.Tests/UrlActions/ForbiddenActionTests.cs rename to src/Middleware/Rewrite/test/UrlActions/ForbiddenActionTests.cs diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/UrlActions/GoneActionTests.cs b/src/Middleware/Rewrite/test/UrlActions/GoneActionTests.cs similarity index 100% rename from test/Microsoft.AspNetCore.Rewrite.Tests/UrlActions/GoneActionTests.cs rename to src/Middleware/Rewrite/test/UrlActions/GoneActionTests.cs diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/UrlMatches/ExactMatchTests.cs b/src/Middleware/Rewrite/test/UrlMatches/ExactMatchTests.cs similarity index 100% rename from test/Microsoft.AspNetCore.Rewrite.Tests/UrlMatches/ExactMatchTests.cs rename to src/Middleware/Rewrite/test/UrlMatches/ExactMatchTests.cs diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/UrlMatches/IntegerMatchTests.cs b/src/Middleware/Rewrite/test/UrlMatches/IntegerMatchTests.cs similarity index 100% rename from test/Microsoft.AspNetCore.Rewrite.Tests/UrlMatches/IntegerMatchTests.cs rename to src/Middleware/Rewrite/test/UrlMatches/IntegerMatchTests.cs diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/UrlMatches/StringMatchTests.cs b/src/Middleware/Rewrite/test/UrlMatches/StringMatchTests.cs similarity index 100% rename from test/Microsoft.AspNetCore.Rewrite.Tests/UrlMatches/StringMatchTests.cs rename to src/Middleware/Rewrite/test/UrlMatches/StringMatchTests.cs diff --git a/test/Directory.Build.props b/test/Directory.Build.props deleted file mode 100644 index b936409242..0000000000 --- a/test/Directory.Build.props +++ /dev/null @@ -1,19 +0,0 @@ - - - - - netcoreapp2.1 - $(DeveloperBuildTestTfms) - netcoreapp2.1;netcoreapp2.0 - $(StandardTestTfms);net461 - - - - - - - - - - - diff --git a/test/Microsoft.AspNetCore.Buffering.Tests/ResponseBufferingMiddlewareTests.cs b/test/Microsoft.AspNetCore.Buffering.Tests/ResponseBufferingMiddlewareTests.cs deleted file mode 100644 index 81aa993e98..0000000000 --- a/test/Microsoft.AspNetCore.Buffering.Tests/ResponseBufferingMiddlewareTests.cs +++ /dev/null @@ -1,315 +0,0 @@ -// 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; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Hosting; -using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Http.Features; -using Microsoft.AspNetCore.TestHost; -using Xunit; - -namespace Microsoft.AspNetCore.Buffering.Tests -{ - public class ResponseBufferingMiddlewareTests - { - [Fact] - public async Task BufferResponse_SetsContentLength() - { - var builder = new WebHostBuilder() - .Configure(app => - { - app.UseResponseBuffering(); - app.Run(async context => - { - Assert.False(context.Response.HasStarted); - Assert.True(context.Response.Body.CanSeek); - await context.Response.WriteAsync("Hello World"); - Assert.False(context.Response.HasStarted); - Assert.True(context.Response.Body.CanSeek); - }); - }); - var server = new TestServer(builder); - - var response = await server.CreateClient().GetAsync(""); - response.EnsureSuccessStatusCode(); - Assert.Equal("Hello World", await response.Content.ReadAsStringAsync()); - - // Set automatically by buffer - IEnumerable values; - Assert.True(response.Content.Headers.TryGetValues("Content-Length", out values)); - Assert.Equal("11", values.FirstOrDefault()); - } - - [Fact] - public async Task BufferResponseWithManualContentLength_NotReplaced() - { - var builder = new WebHostBuilder() - .Configure(app => - { - app.UseResponseBuffering(); - app.Run(async context => - { - context.Response.ContentLength = 12; - Assert.False(context.Response.HasStarted); - Assert.True(context.Response.Body.CanSeek); - await context.Response.WriteAsync("Hello World"); - Assert.False(context.Response.HasStarted); - Assert.True(context.Response.Body.CanSeek); - }); - }); - var server = new TestServer(builder); - - var response = await server.CreateClient().GetAsync(""); - response.EnsureSuccessStatusCode(); - Assert.Equal("Hello World", await response.Content.ReadAsStringAsync()); - - IEnumerable values; - Assert.True(response.Content.Headers.TryGetValues("Content-Length", out values)); - Assert.Equal("12", values.FirstOrDefault()); - } - - [Fact] - public async Task Seek_AllowsResttingBuffer() - { - var builder = new WebHostBuilder() - .Configure(app => - { - app.UseResponseBuffering(); - app.Run(async context => - { - var body = context.Response.Body; - Assert.False(context.Response.HasStarted); - Assert.True(body.CanSeek); - Assert.Equal(0, body.Position); - Assert.Equal(0, body.Length); - - await context.Response.WriteAsync("Hello World"); - Assert.False(context.Response.HasStarted); - Assert.True(context.Response.Body.CanSeek); - Assert.Equal(11, body.Position); - Assert.Equal(11, body.Length); - - Assert.Throws(() => body.Seek(1, SeekOrigin.Begin)); - Assert.Throws(() => body.Seek(0, SeekOrigin.Current)); - Assert.Throws(() => body.Seek(0, SeekOrigin.End)); - - Assert.Equal(0, body.Seek(0, SeekOrigin.Begin)); - Assert.Equal(0, body.Position); - Assert.Equal(0, body.Length); - - await context.Response.WriteAsync("12345"); - Assert.Equal(5, body.Position); - Assert.Equal(5, body.Length); - }); - }); - var server = new TestServer(builder); - - var response = await server.CreateClient().GetAsync(""); - response.EnsureSuccessStatusCode(); - Assert.Equal("12345", await response.Content.ReadAsStringAsync()); - - // Set automatically by buffer - IEnumerable values; - Assert.True(response.Content.Headers.TryGetValues("Content-Length", out values)); - Assert.Equal("5", values.FirstOrDefault()); - } - - [Fact] - public async Task SetPosition_AllowsResttingBuffer() - { - var builder = new WebHostBuilder() - .Configure(app => - { - app.UseResponseBuffering(); - app.Run(async context => - { - var body = context.Response.Body; - Assert.False(context.Response.HasStarted); - Assert.True(body.CanSeek); - Assert.Equal(0, body.Position); - Assert.Equal(0, body.Length); - - await context.Response.WriteAsync("Hello World"); - Assert.False(context.Response.HasStarted); - Assert.True(context.Response.Body.CanSeek); - Assert.Equal(11, body.Position); - Assert.Equal(11, body.Length); - - Assert.Throws(() => body.Position = 1); - - body.Position = 0; - Assert.Equal(0, body.Position); - Assert.Equal(0, body.Length); - - await context.Response.WriteAsync("12345"); - Assert.Equal(5, body.Position); - Assert.Equal(5, body.Length); - }); - }); - var server = new TestServer(builder); - - var response = await server.CreateClient().GetAsync(""); - response.EnsureSuccessStatusCode(); - Assert.Equal("12345", await response.Content.ReadAsStringAsync()); - - // Set automatically by buffer - IEnumerable values; - Assert.True(response.Content.Headers.TryGetValues("Content-Length", out values)); - Assert.Equal("5", values.FirstOrDefault()); - } - - [Fact] - public async Task SetLength_AllowsResttingBuffer() - { - var builder = new WebHostBuilder() - .Configure(app => - { - app.UseResponseBuffering(); - app.Run(async context => - { - var body = context.Response.Body; - Assert.False(context.Response.HasStarted); - Assert.True(body.CanSeek); - Assert.Equal(0, body.Position); - Assert.Equal(0, body.Length); - - await context.Response.WriteAsync("Hello World"); - Assert.False(context.Response.HasStarted); - Assert.True(context.Response.Body.CanSeek); - Assert.Equal(11, body.Position); - Assert.Equal(11, body.Length); - - Assert.Throws(() => body.SetLength(1)); - - body.SetLength(0); - Assert.Equal(0, body.Position); - Assert.Equal(0, body.Length); - - await context.Response.WriteAsync("12345"); - Assert.Equal(5, body.Position); - Assert.Equal(5, body.Length); - }); - }); - var server = new TestServer(builder); - - var response = await server.CreateClient().GetAsync(""); - response.EnsureSuccessStatusCode(); - Assert.Equal("12345", await response.Content.ReadAsStringAsync()); - - // Set automatically by buffer - IEnumerable values; - Assert.True(response.Content.Headers.TryGetValues("Content-Length", out values)); - Assert.Equal("5", values.FirstOrDefault()); - } - - [Fact] - public async Task DisableBufferingViaFeature() - { - var builder = new WebHostBuilder() - .Configure(app => - { - app.UseResponseBuffering(); - app.Run(async context => - { - Assert.False(context.Response.HasStarted); - Assert.True(context.Response.Body.CanSeek); - - var bufferingFeature = context.Features.Get(); - Assert.NotNull(bufferingFeature); - bufferingFeature.DisableResponseBuffering(); - - Assert.False(context.Response.HasStarted); - Assert.False(context.Response.Body.CanSeek); - - await context.Response.WriteAsync("Hello World"); - - Assert.True(context.Response.HasStarted); - Assert.False(context.Response.Body.CanSeek); - }); - }); - var server = new TestServer(builder); - - var response = await server.CreateClient().GetAsync(""); - response.EnsureSuccessStatusCode(); - Assert.Equal("Hello World", await response.Content.ReadAsStringAsync()); - IEnumerable values; - Assert.False(response.Content.Headers.TryGetValues("Content-Length", out values)); - } - - [Fact] - public async Task DisableBufferingViaFeatureAfterFirstWrite_Flushes() - { - var builder = new WebHostBuilder() - .Configure(app => - { - app.UseResponseBuffering(); - app.Run(async context => - { - Assert.False(context.Response.HasStarted); - Assert.True(context.Response.Body.CanSeek); - - await context.Response.WriteAsync("Hello"); - - Assert.False(context.Response.HasStarted); - Assert.True(context.Response.Body.CanSeek); - - var bufferingFeature = context.Features.Get(); - Assert.NotNull(bufferingFeature); - bufferingFeature.DisableResponseBuffering(); - - Assert.True(context.Response.HasStarted); - Assert.False(context.Response.Body.CanSeek); - - await context.Response.WriteAsync(" World"); - - Assert.True(context.Response.HasStarted); - Assert.False(context.Response.Body.CanSeek); - }); - }); - var server = new TestServer(builder); - - var response = await server.CreateClient().GetAsync(""); - response.EnsureSuccessStatusCode(); - Assert.Equal("Hello World", await response.Content.ReadAsStringAsync()); - IEnumerable values; - Assert.False(response.Content.Headers.TryGetValues("Content-Length", out values)); - } - - [Fact] - public async Task FlushDisablesBuffering() - { - var builder = new WebHostBuilder() - .Configure(app => - { - app.UseResponseBuffering(); - app.Run(async context => - { - Assert.False(context.Response.HasStarted); - Assert.True(context.Response.Body.CanSeek); - - context.Response.Body.Flush(); - - Assert.True(context.Response.HasStarted); - Assert.False(context.Response.Body.CanSeek); - - await context.Response.WriteAsync("Hello World"); - - Assert.True(context.Response.HasStarted); - Assert.False(context.Response.Body.CanSeek); - }); - }); - var server = new TestServer(builder); - - var response = await server.CreateClient().GetAsync(""); - response.EnsureSuccessStatusCode(); - Assert.Equal("Hello World", await response.Content.ReadAsStringAsync()); - IEnumerable values; - Assert.False(response.Content.Headers.TryGetValues("Content-Length", out values)); - } - } -} diff --git a/test/Microsoft.AspNetCore.HostFiltering.Tests/Microsoft.AspNetCore.HostFiltering.Tests.csproj b/test/Microsoft.AspNetCore.HostFiltering.Tests/Microsoft.AspNetCore.HostFiltering.Tests.csproj deleted file mode 100644 index 407ecdef0f..0000000000 --- a/test/Microsoft.AspNetCore.HostFiltering.Tests/Microsoft.AspNetCore.HostFiltering.Tests.csproj +++ /dev/null @@ -1,12 +0,0 @@ - - - - $(StandardTestTfms) - - - - - - - - diff --git a/test/Microsoft.AspNetCore.HttpOverrides.Tests/Microsoft.AspNetCore.HttpOverrides.Tests.csproj b/test/Microsoft.AspNetCore.HttpOverrides.Tests/Microsoft.AspNetCore.HttpOverrides.Tests.csproj deleted file mode 100644 index dc9bc780b0..0000000000 --- a/test/Microsoft.AspNetCore.HttpOverrides.Tests/Microsoft.AspNetCore.HttpOverrides.Tests.csproj +++ /dev/null @@ -1,15 +0,0 @@ - - - - $(StandardTestTfms) - - - - - - - - - - - diff --git a/test/Microsoft.AspNetCore.ResponseCompression.Tests/Microsoft.AspNetCore.ResponseCompression.Tests.csproj b/test/Microsoft.AspNetCore.ResponseCompression.Tests/Microsoft.AspNetCore.ResponseCompression.Tests.csproj deleted file mode 100644 index 902449b486..0000000000 --- a/test/Microsoft.AspNetCore.ResponseCompression.Tests/Microsoft.AspNetCore.ResponseCompression.Tests.csproj +++ /dev/null @@ -1,21 +0,0 @@ - - - - $(StandardTestTfms) - - - - - - - - - - - - - - - - - diff --git a/version.props b/version.props deleted file mode 100644 index 6ecf2553b6..0000000000 --- a/version.props +++ /dev/null @@ -1,18 +0,0 @@ - - - 2.1.1 - rtm - $(VersionPrefix) - $(VersionPrefix)-$(VersionSuffix)-final - t000 - a- - $(FeatureBranchVersionPrefix)$(VersionSuffix)-$([System.Text.RegularExpressions.Regex]::Replace('$(FeatureBranchVersionSuffix)', '[^\w-]', '-')) - $(VersionSuffix)-$(BuildNumber) - - 0.4.1 - rtm - $(ExperimentalVersionPrefix) - $(ExperimentalVersionPrefix)-$(ExperimentalVersionSuffix)-final - $(ExperimentalVersionSuffix)-$(BuildNumber) - -