Fix proxy headers handling (#60)

* Fix proxy headers handling

* Small refactor and moved proxy tests to new test-file.
This commit is contained in:
Oleksandr Liakhevych
2017-10-28 19:59:34 +03:00
committed by Stef Heyenrath
parent d134684bcb
commit c8c9ab99c5
9 changed files with 248 additions and 134 deletions

View File

@@ -1,7 +1,7 @@
Microsoft Visual Studio Solution File, Format Version 12.00 Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15 # Visual Studio 15
VisualStudioVersion = 15.0.27004.2002 VisualStudioVersion = 15.0.27004.2005
MinimumVisualStudioVersion = 10.0.40219.1 MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{EF242EDF-7133-4277-9A0C-18744DE08707}" Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{EF242EDF-7133-4277-9A0C-18744DE08707}"
EndProject EndProject
@@ -14,6 +14,9 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
EndProjectSection EndProjectSection
EndProject EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "examples", "examples", "{F0C22C47-DF71-463C-9B04-B4E0F3B8708A}" 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 EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{890A1DED-C229-4FA1-969E-AAC3BBFC05E5}" Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{890A1DED-C229-4FA1-969E-AAC3BBFC05E5}"
EndProject EndProject

View File

@@ -15,4 +15,8 @@
<PackageReference Include="Newtonsoft.Json" Version="10.0.1" /> <PackageReference Include="Newtonsoft.Json" Version="10.0.1" />
</ItemGroup> </ItemGroup>
<ItemGroup>
<Folder Include="__admin\mappings\" />
</ItemGroup>
</Project> </Project>

View File

@@ -1,36 +0,0 @@
{
"Guid": "791a3f31-6946-4ce7-8e6f-0237c7443275",
"Title": "",
"Priority": 0,
"Request": {
"Path": {
"Matchers": [
{
"Name": "WildcardMatcher",
"Pattern": "/proxy-google-test-post"
}
]
},
"Methods": [
"post"
],
"Body": {}
},
"Response": {
"StatusCode": 404,
"Body": "<!DOCTYPE html>\n<html lang=en>\n <meta charset=utf-8>\n <meta name=viewport content=\"initial-scale=1, minimum-scale=1, width=device-width\">\n <title>Error 404 (Not Found)!!1</title>\n <style>\n *{margin:0;padding:0}html,code{font:15px/22px arial,sans-serif}html{background:#fff;color:#222;padding:15px}body{margin:7% auto 0;max-width:390px;min-height:180px;padding:30px 0 15px}* > body{background:url(//www.google.com/images/errors/robot.png) 100% 5px no-repeat;padding-right:205px}p{margin:11px 0 22px;overflow:hidden}ins{color:#777;text-decoration:none}a img{border:0}@media screen and (max-width:772px){body{background:none;margin-top:0;max-width:none;padding-right:0}}#logo{background:url(//www.google.com/images/branding/googlelogo/1x/googlelogo_color_150x54dp.png) no-repeat;margin-left:-5px}@media only screen and (min-resolution:192dpi){#logo{background:url(//www.google.com/images/branding/googlelogo/2x/googlelogo_color_150x54dp.png) no-repeat 0% 0%/100% 100%;-moz-border-image:url(//www.google.com/images/branding/googlelogo/2x/googlelogo_color_150x54dp.png) 0}}@media only screen and (-webkit-min-device-pixel-ratio:2){#logo{background:url(//www.google.com/images/branding/googlelogo/2x/googlelogo_color_150x54dp.png) no-repeat;-webkit-background-size:100% 100%}}#logo{display:inline-block;height:54px;width:150px}\n </style>\n <a href=//www.google.com/><span id=logo aria-label=Google></span></a>\n <p><b>404.</b> <ins>Thats an error.</ins>\n <p>The requested URL <code>/proxy-google-test-post</code> was not found on this server. <ins>Thats all we know.</ins>\n",
"BodyAsBytes": "PCFET0NUWVBFIGh0bWw+CjxodG1sIGxhbmc9ZW4+CiAgPG1ldGEgY2hhcnNldD11dGYtOD4KICA8bWV0YSBuYW1lPXZpZXdwb3J0IGNvbnRlbnQ9ImluaXRpYWwtc2NhbGU9MSwgbWluaW11bS1zY2FsZT0xLCB3aWR0aD1kZXZpY2Utd2lkdGgiPgogIDx0aXRsZT5FcnJvciA0MDQgKE5vdCBGb3VuZCkhITE8L3RpdGxlPgogIDxzdHlsZT4KICAgICp7bWFyZ2luOjA7cGFkZGluZzowfWh0bWwsY29kZXtmb250OjE1cHgvMjJweCBhcmlhbCxzYW5zLXNlcmlmfWh0bWx7YmFja2dyb3VuZDojZmZmO2NvbG9yOiMyMjI7cGFkZGluZzoxNXB4fWJvZHl7bWFyZ2luOjclIGF1dG8gMDttYXgtd2lkdGg6MzkwcHg7bWluLWhlaWdodDoxODBweDtwYWRkaW5nOjMwcHggMCAxNXB4fSogPiBib2R5e2JhY2tncm91bmQ6dXJsKC8vd3d3Lmdvb2dsZS5jb20vaW1hZ2VzL2Vycm9ycy9yb2JvdC5wbmcpIDEwMCUgNXB4IG5vLXJlcGVhdDtwYWRkaW5nLXJpZ2h0OjIwNXB4fXB7bWFyZ2luOjExcHggMCAyMnB4O292ZXJmbG93OmhpZGRlbn1pbnN7Y29sb3I6Izc3Nzt0ZXh0LWRlY29yYXRpb246bm9uZX1hIGltZ3tib3JkZXI6MH1AbWVkaWEgc2NyZWVuIGFuZCAobWF4LXdpZHRoOjc3MnB4KXtib2R5e2JhY2tncm91bmQ6bm9uZTttYXJnaW4tdG9wOjA7bWF4LXdpZHRoOm5vbmU7cGFkZGluZy1yaWdodDowfX0jbG9nb3tiYWNrZ3JvdW5kOnVybCgvL3d3dy5nb29nbGUuY29tL2ltYWdlcy9icmFuZGluZy9nb29nbGVsb2dvLzF4L2dvb2dsZWxvZ29fY29sb3JfMTUweDU0ZHAucG5nKSBuby1yZXBlYXQ7bWFyZ2luLWxlZnQ6LTVweH1AbWVkaWEgb25seSBzY3JlZW4gYW5kIChtaW4tcmVzb2x1dGlvbjoxOTJkcGkpeyNsb2dve2JhY2tncm91bmQ6dXJsKC8vd3d3Lmdvb2dsZS5jb20vaW1hZ2VzL2JyYW5kaW5nL2dvb2dsZWxvZ28vMngvZ29vZ2xlbG9nb19jb2xvcl8xNTB4NTRkcC5wbmcpIG5vLXJlcGVhdCAwJSAwJS8xMDAlIDEwMCU7LW1vei1ib3JkZXItaW1hZ2U6dXJsKC8vd3d3Lmdvb2dsZS5jb20vaW1hZ2VzL2JyYW5kaW5nL2dvb2dsZWxvZ28vMngvZ29vZ2xlbG9nb19jb2xvcl8xNTB4NTRkcC5wbmcpIDB9fUBtZWRpYSBvbmx5IHNjcmVlbiBhbmQgKC13ZWJraXQtbWluLWRldmljZS1waXhlbC1yYXRpbzoyKXsjbG9nb3tiYWNrZ3JvdW5kOnVybCgvL3d3dy5nb29nbGUuY29tL2ltYWdlcy9icmFuZGluZy9nb29nbGVsb2dvLzJ4L2dvb2dsZWxvZ29fY29sb3JfMTUweDU0ZHAucG5nKSBuby1yZXBlYXQ7LXdlYmtpdC1iYWNrZ3JvdW5kLXNpemU6MTAwJSAxMDAlfX0jbG9nb3tkaXNwbGF5OmlubGluZS1ibG9jaztoZWlnaHQ6NTRweDt3aWR0aDoxNTBweH0KICA8L3N0eWxlPgogIDxhIGhyZWY9Ly93d3cuZ29vZ2xlLmNvbS8+PHNwYW4gaWQ9bG9nbyBhcmlhLWxhYmVsPUdvb2dsZT48L3NwYW4+PC9hPgogIDxwPjxiPjQwNC48L2I+IDxpbnM+VGhhdOKAmXMgYW4gZXJyb3IuPC9pbnM+CiAgPHA+VGhlIHJlcXVlc3RlZCBVUkwgPGNvZGU+L3Byb3h5LWdvb2dsZS10ZXN0LXBvc3Q8L2NvZGU+IHdhcyBub3QgZm91bmQgb24gdGhpcyBzZXJ2ZXIuICA8aW5zPlRoYXTigJlzIGFsbCB3ZSBrbm93LjwvaW5zPgo=",
"BodyEncoding": {
"CodePage": 65001,
"EncodingName": "Unicode (UTF-8)",
"WebName": "utf-8"
},
"UseTransformer": false,
"Headers": {
"Date": "Wed, 25 Oct 2017 18:57:40 GMT",
"Alt-Svc": "quic=\":443\"; ma=2592000; v=\"39,38,37,35\"",
"Referrer-Policy": "no-referrer",
"Connection": "close"
}
}
}

View File

@@ -2,17 +2,24 @@
using System.Linq; using System.Linq;
using System.Net.Http; using System.Net.Http;
using System.Threading.Tasks; using System.Threading.Tasks;
using WireMock.Validation;
namespace WireMock.Http namespace WireMock.Http
{ {
internal static class HttpClientHelper 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 #if NETSTANDARD || NET46
var handler = new HttpClientHandler handler = new HttpClientHandler
{ {
ClientCertificateOptions = ClientCertificateOption.Manual, ClientCertificateOptions = ClientCertificateOption.Manual,
SslProtocols = System.Security.Authentication.SslProtocols.Tls12 | System.Security.Authentication.SslProtocols.Tls11 | System.Security.Authentication.SslProtocols.Tls, SslProtocols = System.Security.Authentication.SslProtocols.Tls12 | System.Security.Authentication.SslProtocols.Tls11 | System.Security.Authentication.SslProtocols.Tls,
@@ -22,7 +29,8 @@ namespace WireMock.Http
var x509Certificate2 = CertificateUtil.GetCertificate(clientX509Certificate2ThumbprintOrSubjectName); var x509Certificate2 = CertificateUtil.GetCertificate(clientX509Certificate2ThumbprintOrSubjectName);
handler.ClientCertificates.Add(x509Certificate2); handler.ClientCertificates.Add(x509Certificate2);
#else #else
var handler = new WebRequestHandler
var webRequestHandler = new WebRequestHandler
{ {
ClientCertificateOptions = ClientCertificateOption.Manual, ClientCertificateOptions = ClientCertificateOption.Manual,
ServerCertificateValidationCallback = (sender, certificate, chain, errors) => true, ServerCertificateValidationCallback = (sender, certificate, chain, errors) => true,
@@ -30,38 +38,51 @@ namespace WireMock.Http
}; };
var x509Certificate2 = CertificateUtil.GetCertificate(clientX509Certificate2ThumbprintOrSubjectName); var x509Certificate2 = CertificateUtil.GetCertificate(clientX509Certificate2ThumbprintOrSubjectName);
handler.ClientCertificates.Add(x509Certificate2); webRequestHandler.ClientCertificates.Add(x509Certificate2);
return new HttpClient(handler); handler = webRequestHandler;
#endif #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); var httpRequestMessage = new HttpRequestMessage(new HttpMethod(requestMessage.Method), url);
// Overwrite the host header
httpRequestMessage.Headers.Host = new Uri(url).Authority;
// Set headers if present
if (requestMessage.Headers != null)
{
foreach (var headerName in requestMessage.Headers.Keys.Where(k => k.ToUpper() != "HOST"))
{
httpRequestMessage.Headers.TryAddWithoutValidation(headerName, requestMessage.Headers[headerName]);
}
}
// Set Body if present // Set Body if present
if (requestMessage.BodyAsBytes != null && requestMessage.BodyAsBytes.Length > 0) if (requestMessage.BodyAsBytes != null && requestMessage.BodyAsBytes.Length > 0)
{ {
httpRequestMessage.Content = new ByteArrayContent(requestMessage.BodyAsBytes); httpRequestMessage.Content = new ByteArrayContent(requestMessage.BodyAsBytes);
} }
// Overwrite the host header
httpRequestMessage.Headers.Host = requiredUri.Authority;
// Set headers if present
if (requestMessage.Headers != null)
{
foreach (var header in requestMessage.Headers.Where(header => !string.Equals(header.Key, "HOST", StringComparison.OrdinalIgnoreCase)))
{
// 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);
}
}
}
// Call the URL // Call the URL
var httpResponseMessage = await client.SendAsync(httpRequestMessage, HttpCompletionOption.ResponseContentRead); var httpResponseMessage = await client.SendAsync(httpRequestMessage, HttpCompletionOption.ResponseContentRead);
@@ -74,9 +95,24 @@ namespace WireMock.Http
Body = await httpResponseMessage.Content.ReadAsStringAsync() 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; return responseMessage;

View File

@@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Net; using System.Net;
using System.Net.Http;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using JetBrains.Annotations; using JetBrains.Annotations;
@@ -19,6 +20,8 @@ namespace WireMock.ResponseBuilders
/// </summary> /// </summary>
public class Response : IResponseBuilder public class Response : IResponseBuilder
{ {
private HttpClient httpClientForProxy;
/// <summary> /// <summary>
/// The delay /// The delay
/// </summary> /// </summary>
@@ -317,6 +320,7 @@ namespace WireMock.ResponseBuilders
ProxyUrl = proxyUrl; ProxyUrl = proxyUrl;
X509Certificate2ThumbprintOrSubjectName = clientX509Certificate2ThumbprintOrSubjectName; X509Certificate2ThumbprintOrSubjectName = clientX509Certificate2ThumbprintOrSubjectName;
httpClientForProxy = HttpClientHelper.CreateHttpClient(clientX509Certificate2ThumbprintOrSubjectName);
return this; return this;
} }
@@ -332,12 +336,12 @@ namespace WireMock.ResponseBuilders
if (Delay != null) if (Delay != null)
await Task.Delay(Delay.Value); await Task.Delay(Delay.Value);
if (ProxyUrl != null) if (ProxyUrl != null && httpClientForProxy != null)
{ {
var requestUri = new Uri(requestMessage.Url); var requestUri = new Uri(requestMessage.Url);
var proxyUri = new Uri(ProxyUrl); var proxyUri = new Uri(ProxyUrl);
var proxyUriWithRequestPathAndQuery = new Uri(proxyUri, requestUri.PathAndQuery); 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) if (UseTransformer)

View File

@@ -2,6 +2,7 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Net.Http;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using JetBrains.Annotations; using JetBrains.Annotations;
@@ -129,8 +130,11 @@ namespace WireMock.Server
} }
#region Proxy and Record #region Proxy and Record
private HttpClient httpClientForProxy;
private void InitProxyAndRecord(ProxyAndRecordSettings settings) private void InitProxyAndRecord(ProxyAndRecordSettings settings)
{ {
httpClientForProxy = HttpClientHelper.CreateHttpClient(settings.X509Certificate2ThumbprintOrSubjectName);
Given(Request.Create().WithPath("/*").UsingAnyVerb()).RespondWith(new ProxyAsyncResponseProvider(ProxyAndRecordAsync, settings)); Given(Request.Create().WithPath("/*").UsingAnyVerb()).RespondWith(new ProxyAsyncResponseProvider(ProxyAndRecordAsync, settings));
} }
@@ -140,7 +144,7 @@ namespace WireMock.Server
var proxyUri = new Uri(settings.Url); var proxyUri = new Uri(settings.Url);
var proxyUriWithRequestPathAndQuery = new Uri(proxyUri, requestUri.PathAndQuery); 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) if (settings.SaveMapping)
{ {

View File

@@ -0,0 +1,157 @@
using System;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading.Tasks;
using NFluent;
using WireMock.RequestBuilders;
using WireMock.ResponseBuilders;
using WireMock.Server;
using Xunit;
namespace WireMock.Net.Tests
{
public partial class FluentMockServerTests
{
private FluentMockServer _serverForProxyForwarding;
[Fact]
public async Task FluentMockServer_Should_proxy_responses()
{
// given
_server = FluentMockServer.Start();
_server
.Given(Request.Create().WithPath("/*"))
.RespondWith(Response.Create().WithProxy("http://www.google.com"));
// when
var result = await new HttpClient().GetStringAsync("http://localhost:" + _server.Ports[0] + "/search?q=test");
// then
Check.That(result).Contains("google");
}
[Fact]
public async Task FluentMockServer_Should_preserve_content_header_in_proxied_request()
{
// given
_serverForProxyForwarding = FluentMockServer.Start();
_serverForProxyForwarding
.Given(Request.Create().WithPath("/*"))
.RespondWith(Response.Create());
_server = FluentMockServer.Start();
_server
.Given(Request.Create().WithPath("/*"))
.RespondWith(Response.Create().WithProxy(_serverForProxyForwarding.Urls[0]));
// when
var requestMessage = new HttpRequestMessage
{
Method = HttpMethod.Post,
RequestUri = new Uri(_server.Urls[0]),
Content = new StringContent("stringContent")
};
requestMessage.Content.Headers.ContentType = new MediaTypeHeaderValue("text/plain");
await new HttpClient().SendAsync(requestMessage);
// then
var receivedRequest = _serverForProxyForwarding.LogEntries.First().RequestMessage;
Check.That(receivedRequest.Body).IsEqualTo("stringContent");
Check.That(receivedRequest.Headers).ContainsKey("Content-Type");
Check.That(receivedRequest.Headers["Content-Type"]).ContainsExactly("text/plain");
}
[Fact]
public async Task FluentMockServer_Should_preserve_content_header_in_proxied_response()
{
// given
_serverForProxyForwarding = FluentMockServer.Start();
_serverForProxyForwarding
.Given(Request.Create().WithPath("/*"))
.RespondWith(Response.Create()
.WithBody("body")
.WithHeader("Content-Type", "text/plain"));
_server = FluentMockServer.Start();
_server
.Given(Request.Create().WithPath("/*"))
.RespondWith(Response.Create().WithProxy(_serverForProxyForwarding.Urls[0]));
// when
var requestMessage = new HttpRequestMessage
{
Method = HttpMethod.Get,
RequestUri = new Uri(_server.Urls[0])
};
var response = await new HttpClient().SendAsync(requestMessage);
// then
Check.That(await response.Content.ReadAsStringAsync()).IsEqualTo("body");
Check.That(response.Content.Headers.Contains("Content-Type")).IsTrue();
Check.That(response.Content.Headers.GetValues("Content-Type")).ContainsExactly("text/plain");
}
[Fact]
public async Task FluentMockServer_Should_change_absolute_location_header_in_proxied_response()
{
// given
_serverForProxyForwarding = FluentMockServer.Start();
_serverForProxyForwarding
.Given(Request.Create().WithPath("/*"))
.RespondWith(Response.Create()
.WithStatusCode(HttpStatusCode.Redirect)
.WithHeader("Location", _serverForProxyForwarding.Urls[0] + "testpath"));
_server = FluentMockServer.Start();
_server
.Given(Request.Create().WithPath("/*"))
.RespondWith(Response.Create().WithProxy(_serverForProxyForwarding.Urls[0]));
// when
var requestMessage = new HttpRequestMessage
{
Method = HttpMethod.Get,
RequestUri = new Uri(_server.Urls[0])
};
var httpClientHandler = new HttpClientHandler { AllowAutoRedirect = false };
var response = await new HttpClient(httpClientHandler).SendAsync(requestMessage);
// then
Check.That(response.Headers.Contains("Location")).IsTrue();
Check.That(response.Headers.GetValues("Location")).ContainsExactly(_server.Urls[0] + "testpath");
}
[Fact]
public async Task FluentMockServer_Should_preserve_cookie_header_in_proxied_request()
{
// given
_serverForProxyForwarding = FluentMockServer.Start();
_serverForProxyForwarding
.Given(Request.Create().WithPath("/*"))
.RespondWith(Response.Create());
_server = FluentMockServer.Start();
_server
.Given(Request.Create().WithPath("/*"))
.RespondWith(Response.Create().WithProxy(_serverForProxyForwarding.Urls[0]));
// when
var requestUri = new Uri(_server.Urls[0]);
var requestMessage = new HttpRequestMessage
{
Method = HttpMethod.Get,
RequestUri = requestUri
};
var clientHandler = new HttpClientHandler();
clientHandler.CookieContainer.Add(requestUri, new Cookie("name", "value"));
await new HttpClient(clientHandler).SendAsync(requestMessage);
// then
var receivedRequest = _serverForProxyForwarding.LogEntries.First().RequestMessage;
Check.That(receivedRequest.Cookies).IsNotNull();
Check.That(receivedRequest.Cookies).ContainsPair("name", "value");
}
}
}

View File

@@ -6,17 +6,15 @@ using System.Net;
using System.Net.Http; using System.Net.Http;
using System.Threading.Tasks; using System.Threading.Tasks;
using NFluent; using NFluent;
using Xunit;
using WireMock.Matchers; using WireMock.Matchers;
using WireMock.RequestBuilders; using WireMock.RequestBuilders;
using WireMock.ResponseBuilders; using WireMock.ResponseBuilders;
using WireMock.Server; using WireMock.Server;
using Xunit;
namespace WireMock.Net.Tests namespace WireMock.Net.Tests
{ {
//[TestFixture] public partial class FluentMockServerTests : IDisposable
//[Timeout(5000)]
public class FluentMockServerTests : IDisposable
{ {
private FluentMockServer _server; private FluentMockServer _server;
@@ -178,7 +176,7 @@ namespace WireMock.Net.Tests
} }
[Fact] [Fact]
public async Task Should_respond_to_request_bodyAsString() public async Task FluentMockServer_Should_respond_to_request_bodyAsString()
{ {
// given // given
_server = FluentMockServer.Start(); _server = FluentMockServer.Start();
@@ -199,7 +197,7 @@ namespace WireMock.Net.Tests
} }
[Fact] [Fact]
public async Task Should_respond_to_request_bodyAsBase64() public async Task FluentMockServer_Should_respond_to_request_bodyAsBase64()
{ {
// given // given
_server = FluentMockServer.Start(); _server = FluentMockServer.Start();
@@ -214,7 +212,7 @@ namespace WireMock.Net.Tests
} }
[Fact] [Fact]
public async Task Should_respond_to_request_bodyAsBytes() public async Task FluentMockServer_Should_respond_to_request_bodyAsBytes()
{ {
// given // given
_server = FluentMockServer.Start(); _server = FluentMockServer.Start();
@@ -231,7 +229,7 @@ namespace WireMock.Net.Tests
} }
[Fact] [Fact]
public async Task Should_respond_404_for_unexpected_request() public async Task FluentMockServer_Should_respond_404_for_unexpected_request()
{ {
// given // given
_server = FluentMockServer.Start(); _server = FluentMockServer.Start();
@@ -245,7 +243,7 @@ namespace WireMock.Net.Tests
} }
[Fact] [Fact]
public async Task Should_find_a_request_satisfying_a_request_spec() public async Task FluentMockServer_Should_find_a_request_satisfying_a_request_spec()
{ {
// given // given
_server = FluentMockServer.Start(); _server = FluentMockServer.Start();
@@ -264,7 +262,7 @@ namespace WireMock.Net.Tests
} }
[Fact] [Fact]
public async Task Should_reset_requestlogs() public async Task FluentMockServer_Should_reset_requestlogs()
{ {
// given // given
_server = FluentMockServer.Start(); _server = FluentMockServer.Start();
@@ -278,7 +276,7 @@ namespace WireMock.Net.Tests
} }
[Fact] [Fact]
public void Should_reset_mappings() public void FluentMockServer_Should_reset_mappings()
{ {
// given // given
_server = FluentMockServer.Start(); _server = FluentMockServer.Start();
@@ -300,7 +298,7 @@ namespace WireMock.Net.Tests
} }
[Fact] [Fact]
public async Task Should_respond_a_redirect_without_body() public async Task FluentMockServer_Should_respond_a_redirect_without_body()
{ {
// given // given
_server = FluentMockServer.Start(); _server = FluentMockServer.Start();
@@ -328,7 +326,7 @@ namespace WireMock.Net.Tests
} }
[Fact] [Fact]
public async Task Should_delay_responses_for_a_given_route() public async Task FluentMockServer_Should_delay_responses_for_a_given_route()
{ {
// given // given
_server = FluentMockServer.Start(); _server = FluentMockServer.Start();
@@ -351,7 +349,7 @@ namespace WireMock.Net.Tests
} }
[Fact] [Fact]
public async Task Should_delay_responses() public async Task FluentMockServer_Should_delay_responses()
{ {
// given // given
_server = FluentMockServer.Start(); _server = FluentMockServer.Start();
@@ -370,22 +368,6 @@ namespace WireMock.Net.Tests
Check.That(watch.ElapsedMilliseconds).IsStrictlyGreaterThan(200); Check.That(watch.ElapsedMilliseconds).IsStrictlyGreaterThan(200);
} }
[Fact]
public async Task Should_proxy_responses()
{
// given
_server = FluentMockServer.Start();
_server
.Given(Request.Create().WithPath("/*"))
.RespondWith(Response.Create().WithProxy("http://www.google.com"));
// when
var result = await new HttpClient().GetStringAsync("http://localhost:" + _server.Ports[0] + "/search?q=test");
// then
Check.That(result).Contains("google");
}
//Leaving commented as this requires an actual certificate with password, along with a service that expects a client certificate //Leaving commented as this requires an actual certificate with password, along with a service that expects a client certificate
//[Fact] //[Fact]
//public async Task Should_proxy_responses_with_client_certificate() //public async Task Should_proxy_responses_with_client_certificate()
@@ -429,6 +411,7 @@ namespace WireMock.Net.Tests
public void Dispose() public void Dispose()
{ {
_server?.Stop(); _server?.Stop();
_serverForProxyForwarding?.Stop();
} }
} }
} }