Skip to content

Commit

Permalink
Support for X-Forwarded headers
Browse files Browse the repository at this point in the history
Support has been added for X-Forwarded-Port and X-Forwarded-Proto.
This will enable reverse proxy servers to feed the public port
and protocol to eventstore. These values will be used in generating
URLs in responses.
  • Loading branch information
adbrowne committed Sep 20, 2014
1 parent 003272d commit 0747bb9
Show file tree
Hide file tree
Showing 6 changed files with 98 additions and 2 deletions.
1 change: 1 addition & 0 deletions src/EventStore.Core.Tests/EventStore.Core.Tests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -417,6 +417,7 @@
<Compile Include="Services\Transport\Http\PortableServer.cs" />
<Compile Include="Services\Transport\Http\ping_controller_should.cs" />
<Compile Include="MightyMooseIgnoreAttribute.cs" />
<Compile Include="Services\Transport\Http\proxy_headers.cs" />
<Compile Include="Services\Transport\Http\speed_test.cs" />
<Compile Include="Services\Transport\Http\uri_router_should.cs" />
<Compile Include="Services\Transport\Tcp\ssl_connection.cs" />
Expand Down
55 changes: 55 additions & 0 deletions src/EventStore.Core.Tests/Services/Transport/Http/proxy_headers.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
using System;
using System.Collections.Specialized;
using EventStore.Transport.Http.EntityManagement;
using NUnit.Framework;

namespace EventStore.Core.Tests.Services.Transport.Http
{
[TestFixture]
class proxy_headers
{
[Test]
public void with_no_headers_uri_is_unchanged()
{
var inputUri = new Uri("http://www.example.com:1234/path/?key=value#anchor");
var requestedUri =
HttpEntity.BuildRequestedUrl(inputUri,
new NameValueCollection());

Assert.AreEqual(inputUri, requestedUri);
}

[Test]
public void with_port_forward_header_only_port_is_changed()
{
var inputUri = new Uri("http://www.example.com:1234/path/?key=value#anchor");
var headers = new NameValueCollection { { "X-Forwarded-Port", "4321" } };
var requestedUri =
HttpEntity.BuildRequestedUrl(inputUri, headers);

Assert.AreEqual(new Uri("http://www.example.com:4321/path/?key=value#anchor"), requestedUri);
}

[Test]
public void non_integer_port_forward_header_is_ignored()
{
var inputUri = new Uri("http://www.example.com:1234/path/?key=value#anchor");
var headers = new NameValueCollection { { "X-Forwarded-Port", "abc" } };
var requestedUri =
HttpEntity.BuildRequestedUrl(inputUri, headers);

Assert.AreEqual(inputUri, requestedUri);
}

[Test]
public void with_proto_forward_header_only_scheme_is_changed()
{
var inputUri = new Uri("http://www.example.com:1234/path/?key=value#anchor");
var headers = new NameValueCollection { { "X-Forwarded-Proto", "https" } };
var requestedUri =
HttpEntity.BuildRequestedUrl(inputUri, headers);

Assert.AreEqual(new Uri("https://www.example.com:1234/path/?key=value#anchor"), requestedUri);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ private static void RegisterRedirectAction(IHttpService service, string fromUrl,
new[]
{
new KeyValuePair<string, string>(
"Location", new Uri(match.BaseUri, toUrl).AbsoluteUri)
"Location", new Uri(http.HttpEntity.RequestedUrl, toUrl).AbsoluteUri)
}, Console.WriteLine));
}
}
Expand Down
27 changes: 26 additions & 1 deletion src/EventStore.Transport.Http/EntityManagement/HttpEntity.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using System.Collections.Specialized;
using System.Net;
using System.Security.Principal;
using EventStore.Common.Utils;
Expand All @@ -19,12 +20,36 @@ public HttpEntity(HttpListenerRequest request, HttpListenerResponse response, IP
Ensure.NotNull(request, "request");
Ensure.NotNull(response, "response");

RequestedUrl = request.Url;
RequestedUrl = BuildRequestedUrl(request.Url, request.Headers);
Request = request;
Response = response;
User = user;
}

public static Uri BuildRequestedUrl(Uri requestUrl, NameValueCollection requestHeaders)
{
var uriBuilder = new UriBuilder(requestUrl);

var forwardedPortHeaderValue = requestHeaders[ProxyHeaders.XForwardedPort];

if (!string.IsNullOrEmpty(forwardedPortHeaderValue))
{
int requestPort;
if (Int32.TryParse(forwardedPortHeaderValue, out requestPort))
{
uriBuilder.Port = requestPort;
}
}

var forwardedProtoHeaderValue = requestHeaders[ProxyHeaders.XForwardedProto];
if (!string.IsNullOrEmpty(forwardedProtoHeaderValue))
{
uriBuilder.Scheme = forwardedProtoHeaderValue;
}

return uriBuilder.Uri;
}

private HttpEntity(IPrincipal user)
{
RequestedUrl = null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@
<Compile Include="ICodec.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="HttpStatusCode.cs" />
<Compile Include="ProxyHeaders.cs" />
<Compile Include="Server\HttpAsyncServer.cs" />
<Compile Include="WebRequestExtensions.cs" />
</ItemGroup>
Expand Down
14 changes: 14 additions & 0 deletions src/EventStore.Transport.Http/ProxyHeaders.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
namespace EventStore.Transport.Http
{
public static class ProxyHeaders
{
public const string XForwardedPort = "X-Forwarded-Port";
public const string XForwardedProto = "X-Forwarded-Proto";
}

public static class ProxyHeaderValues
{
public const string XForwardedProtoHttp = "http";
public const string XForwardedProtoHttps = "https";
}
}

0 comments on commit 0747bb9

Please sign in to comment.