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-*"
+ }
+ }
+ }
+}