Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix proxy headers handling #60

Merged
merged 2 commits into from
Oct 28, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion WireMock.Net Solution.sln
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.27004.2002
VisualStudioVersion = 15.0.27004.2005
MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{EF242EDF-7133-4277-9A0C-18744DE08707}"
EndProject
Expand All @@ -14,6 +14,9 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "examples", "examples", "{F0C22C47-DF71-463C-9B04-B4E0F3B8708A}"
ProjectSection(SolutionItems) = preProject
examples\WireMock.Net.Console.Record.NETCoreApp\__admin\mappings\ab38efae-4e4d-4f20-8afe-635533ec2535.json = examples\WireMock.Net.Console.Record.NETCoreApp\__admin\mappings\ab38efae-4e4d-4f20-8afe-635533ec2535.json
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{890A1DED-C229-4FA1-969E-AAC3BBFC05E5}"
EndProject
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,8 @@
<PackageReference Include="Newtonsoft.Json" Version="10.0.1" />
</ItemGroup>

<ItemGroup>
<Folder Include="__admin\mappings\" />
</ItemGroup>

</Project>

This file was deleted.

This file was deleted.

76 changes: 56 additions & 20 deletions src/WireMock.Net/Http/HttpClientHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,24 @@
using System.Linq;
using System.Net.Http;
using System.Threading.Tasks;
using WireMock.Validation;

namespace WireMock.Http
{
internal static class HttpClientHelper
{
private static HttpClient CreateHttpClient(string clientX509Certificate2ThumbprintOrSubjectName = null)
public static HttpClient CreateHttpClient(string clientX509Certificate2ThumbprintOrSubjectName = null)
{
if (!string.IsNullOrEmpty(clientX509Certificate2ThumbprintOrSubjectName))
HttpClientHandler handler;

if (string.IsNullOrEmpty(clientX509Certificate2ThumbprintOrSubjectName))
{
handler = new HttpClientHandler();
}
else
{
#if NETSTANDARD || NET46
var handler = new HttpClientHandler
handler = new HttpClientHandler
{
ClientCertificateOptions = ClientCertificateOption.Manual,
SslProtocols = System.Security.Authentication.SslProtocols.Tls12 | System.Security.Authentication.SslProtocols.Tls11 | System.Security.Authentication.SslProtocols.Tls,
Expand All @@ -22,46 +29,60 @@ private static HttpClient CreateHttpClient(string clientX509Certificate2Thumbpri
var x509Certificate2 = CertificateUtil.GetCertificate(clientX509Certificate2ThumbprintOrSubjectName);
handler.ClientCertificates.Add(x509Certificate2);
#else
var handler = new WebRequestHandler

var webRequestHandler = new WebRequestHandler
{
ClientCertificateOptions = ClientCertificateOption.Manual,
ServerCertificateValidationCallback = (sender, certificate, chain, errors) => true,
AutomaticDecompression = System.Net.DecompressionMethods.GZip | System.Net.DecompressionMethods.Deflate
};

var x509Certificate2 = CertificateUtil.GetCertificate(clientX509Certificate2ThumbprintOrSubjectName);
handler.ClientCertificates.Add(x509Certificate2);
return new HttpClient(handler);
webRequestHandler.ClientCertificates.Add(x509Certificate2);
handler = webRequestHandler;
#endif
}

return new HttpClient();
// For proxy we shouldn't follow auto redirects
handler.AllowAutoRedirect = false;

// If UseCookies enabled, httpClient ignores Cookie header
handler.UseCookies = false;

return new HttpClient(handler);
}

public static async Task<ResponseMessage> SendAsync(RequestMessage requestMessage, string url, string clientX509Certificate2ThumbprintOrSubjectName = null)
public static async Task<ResponseMessage> SendAsync(HttpClient client, RequestMessage requestMessage, string url)
{
var client = CreateHttpClient(clientX509Certificate2ThumbprintOrSubjectName);
Check.NotNull(client, nameof(client));

var originalUri = new Uri(requestMessage.Url);
var requiredUri = new Uri(url);

var httpRequestMessage = new HttpRequestMessage(new HttpMethod(requestMessage.Method), url);

// Set Body if present
if (requestMessage.BodyAsBytes != null && requestMessage.BodyAsBytes.Length > 0)
{
httpRequestMessage.Content = new ByteArrayContent(requestMessage.BodyAsBytes);
}

// Overwrite the host header
httpRequestMessage.Headers.Host = new Uri(url).Authority;
httpRequestMessage.Headers.Host = requiredUri.Authority;

// Set headers if present
if (requestMessage.Headers != null)
{
foreach (var headerName in requestMessage.Headers.Keys.Where(k => k.ToUpper() != "HOST"))
foreach (var header in requestMessage.Headers.Where(header => !string.Equals(header.Key, "HOST", StringComparison.OrdinalIgnoreCase)))
{
httpRequestMessage.Headers.TryAddWithoutValidation(headerName, requestMessage.Headers[headerName]);
// Try to add to request headers. If failed - try to add to content headers
if (!httpRequestMessage.Headers.TryAddWithoutValidation(header.Key, header.Value))
{
httpRequestMessage.Content?.Headers.TryAddWithoutValidation(header.Key, header.Value);
}
}
}

// Set Body if present
if (requestMessage.BodyAsBytes != null && requestMessage.BodyAsBytes.Length > 0)
{
httpRequestMessage.Content = new ByteArrayContent(requestMessage.BodyAsBytes);
}

// Call the URL
var httpResponseMessage = await client.SendAsync(httpRequestMessage, HttpCompletionOption.ResponseContentRead);

Expand All @@ -74,9 +95,24 @@ public static async Task<ResponseMessage> SendAsync(RequestMessage requestMessag
Body = await httpResponseMessage.Content.ReadAsStringAsync()
};

foreach (var header in httpResponseMessage.Headers)
// Set both content and response headers, replacing URLs in values
var headers = httpResponseMessage.Content?.Headers.Union(httpResponseMessage.Headers);

foreach (var header in headers)
{
responseMessage.AddHeader(header.Key, header.Value.FirstOrDefault());
// if Location header contains absolute redirect URL, and base URL is one that we proxy to,
// we need to replace it to original one.
if (string.Equals(header.Key, "Location", StringComparison.OrdinalIgnoreCase)
&& Uri.TryCreate(header.Value.First(), UriKind.Absolute, out Uri absoluteLocationUri)
&& string.Equals(absoluteLocationUri.Host, requiredUri.Host, StringComparison.OrdinalIgnoreCase))
{
var replacedLocationUri = new Uri(originalUri, absoluteLocationUri.PathAndQuery);
responseMessage.AddHeader(header.Key, replacedLocationUri.ToString());
}
else
{
responseMessage.AddHeader(header.Key, header.Value.ToArray());
}
}

return responseMessage;
Expand Down
8 changes: 6 additions & 2 deletions src/WireMock.Net/ResponseBuilders/Response.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using JetBrains.Annotations;
Expand All @@ -19,6 +20,8 @@ namespace WireMock.ResponseBuilders
/// </summary>
public class Response : IResponseBuilder
{
private HttpClient httpClientForProxy;

/// <summary>
/// The delay
/// </summary>
Expand Down Expand Up @@ -317,6 +320,7 @@ public IResponseBuilder WithProxy(string proxyUrl, string clientX509Certificate2

ProxyUrl = proxyUrl;
X509Certificate2ThumbprintOrSubjectName = clientX509Certificate2ThumbprintOrSubjectName;
httpClientForProxy = HttpClientHelper.CreateHttpClient(clientX509Certificate2ThumbprintOrSubjectName);
return this;
}

Expand All @@ -332,12 +336,12 @@ public async Task<ResponseMessage> ProvideResponseAsync(RequestMessage requestMe
if (Delay != null)
await Task.Delay(Delay.Value);

if (ProxyUrl != null)
if (ProxyUrl != null && httpClientForProxy != null)
{
var requestUri = new Uri(requestMessage.Url);
var proxyUri = new Uri(ProxyUrl);
var proxyUriWithRequestPathAndQuery = new Uri(proxyUri, requestUri.PathAndQuery);
return await HttpClientHelper.SendAsync(requestMessage, proxyUriWithRequestPathAndQuery.AbsoluteUri, X509Certificate2ThumbprintOrSubjectName);
return await HttpClientHelper.SendAsync(httpClientForProxy, requestMessage, proxyUriWithRequestPathAndQuery.AbsoluteUri);
}

if (UseTransformer)
Expand Down
6 changes: 5 additions & 1 deletion src/WireMock.Net/Server/FluentMockServer.Admin.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using JetBrains.Annotations;
Expand Down Expand Up @@ -129,8 +130,11 @@ private void InitAdmin()
}

#region Proxy and Record
private HttpClient httpClientForProxy;

private void InitProxyAndRecord(ProxyAndRecordSettings settings)
{
httpClientForProxy = HttpClientHelper.CreateHttpClient(settings.X509Certificate2ThumbprintOrSubjectName);
Given(Request.Create().WithPath("/*").UsingAnyVerb()).RespondWith(new ProxyAsyncResponseProvider(ProxyAndRecordAsync, settings));
}

Expand All @@ -140,7 +144,7 @@ private async Task<ResponseMessage> ProxyAndRecordAsync(RequestMessage requestMe
var proxyUri = new Uri(settings.Url);
var proxyUriWithRequestPathAndQuery = new Uri(proxyUri, requestUri.PathAndQuery);

var responseMessage = await HttpClientHelper.SendAsync(requestMessage, proxyUriWithRequestPathAndQuery.AbsoluteUri, settings.X509Certificate2ThumbprintOrSubjectName);
var responseMessage = await HttpClientHelper.SendAsync(httpClientForProxy, requestMessage, proxyUriWithRequestPathAndQuery.AbsoluteUri);

if (settings.SaveMapping)
{
Expand Down
Loading