Issue with matching when client uses Host header #256

Closed
opened 2025-12-29 15:19:10 +01:00 by adam · 7 comments
Owner

Originally created by @bellorap on GitHub (Mar 9, 2020).

I'd like to integration test an application that uses the Host header in calls to its dependencies. I'm trying to use WireMock to stub these API dependencies, but the existence of the Host header is causing the mapping not to match. Here's an example of the problem using NUnit and Flurl:

using System;
using Flurl.Http;
using NUnit.Framework;
using WireMock.RequestBuilders;
using WireMock.ResponseBuilders;
using WireMock.Server;
using WireMock.Settings;

namespace Trafi.Vehicles.Tests.Integration.Consumer
{
    public class WireMockTest
    {
        private WireMockServer Server { get; set; }

        [SetUp]
        public void SetUp()
        {
            var wireMockSettings = new FluentMockServerSettings
            {
                Urls = new [] { "http://localhost:5001" }
            };
            Server = WireMockServer.Start(wireMockSettings);
            Server
                .Given(Request.Create()
                    .WithUrl("http://localhost:5001/*")
                    .UsingGet()
                )
                .RespondWith(
                    Response.Create()
                        .WithStatusCode(200)
                        .WithBody(@"{ ""msg"": ""Hello world!"" }")
                );
        }

        [Test]
        public void Test_WithoutHostHeader()
        {
            var result = new FlurlRequest("http://localhost:5001/foo")
                .GetStringAsync()
                .Result;
            Console.WriteLine(result);
        }
        
        [Test]
        public void Test_WithHostHeader()
        {
            var result = new FlurlRequest("http://localhost:5001/foo")
                .WithHeader("Host", "myhost")
                .GetStringAsync()
                .Result;
            Console.WriteLine(result);
        }
        
        [TearDown]
        public void TearDown()
        {
            Server.Stop();
        }
    }
}

Test_WithoutHostHeader succeeds while Test_WithHostHeader throws the following:

System.AggregateException : One or more errors occurred. (Call failed with status code 404 (Not Found): GET http://localhost:5001/foo)
  ----> Flurl.Http.FlurlHttpException : Call failed with status code 404 (Not Found): GET http://localhost:5001/foo
   at System.Threading.Tasks.Task`1.GetResultCore(Boolean waitCompletionNotification)
   at Trafi.Vehicles.Tests.Integration.Consumer.WireMockTest.Test_WithHostHeader() in /Users/pbellora/src/trafi-vehicles-service/Trafi.Vehicles.Tests.Integration/Consumer/WireMockTest.cs:line 45
--FlurlHttpException
   at Flurl.Http.FlurlRequest.HandleExceptionAsync(HttpCall call, Exception ex, CancellationToken token)
   at Flurl.Http.FlurlRequest.SendAsync(HttpMethod verb, HttpContent content, CancellationToken cancellationToken, HttpCompletionOption completionOption)
   at Flurl.Http.FlurlRequest.SendAsync(HttpMethod verb, HttpContent content, CancellationToken cancellationToken, HttpCompletionOption completionOption)
   at Flurl.Http.HttpResponseMessageExtensions.ReceiveString(Task`1 response)

Likewise, curling from the command line during test execution shows a similar outcome:

$ curl -X GET -H 'Host: myhost' -w '\n%{http_code}\n' 'http://localhost:5001/regions/short'
{"Status":"No matching mapping found"}
404

Is there a workaround to this problem? Or do I need to refactor my application to not use the Host header during integration tests?

I'm using WireMock.Net version 1.1.10.

Originally created by @bellorap on GitHub (Mar 9, 2020). I'd like to integration test an application that uses the `Host` header in calls to its dependencies. I'm trying to use WireMock to stub these API dependencies, but the existence of the `Host` header is causing the mapping not to match. Here's an example of the problem using NUnit and Flurl: ```csharp using System; using Flurl.Http; using NUnit.Framework; using WireMock.RequestBuilders; using WireMock.ResponseBuilders; using WireMock.Server; using WireMock.Settings; namespace Trafi.Vehicles.Tests.Integration.Consumer { public class WireMockTest { private WireMockServer Server { get; set; } [SetUp] public void SetUp() { var wireMockSettings = new FluentMockServerSettings { Urls = new [] { "http://localhost:5001" } }; Server = WireMockServer.Start(wireMockSettings); Server .Given(Request.Create() .WithUrl("http://localhost:5001/*") .UsingGet() ) .RespondWith( Response.Create() .WithStatusCode(200) .WithBody(@"{ ""msg"": ""Hello world!"" }") ); } [Test] public void Test_WithoutHostHeader() { var result = new FlurlRequest("http://localhost:5001/foo") .GetStringAsync() .Result; Console.WriteLine(result); } [Test] public void Test_WithHostHeader() { var result = new FlurlRequest("http://localhost:5001/foo") .WithHeader("Host", "myhost") .GetStringAsync() .Result; Console.WriteLine(result); } [TearDown] public void TearDown() { Server.Stop(); } } } ``` `Test_WithoutHostHeader` succeeds while `Test_WithHostHeader` throws the following: ``` System.AggregateException : One or more errors occurred. (Call failed with status code 404 (Not Found): GET http://localhost:5001/foo) ----> Flurl.Http.FlurlHttpException : Call failed with status code 404 (Not Found): GET http://localhost:5001/foo at System.Threading.Tasks.Task`1.GetResultCore(Boolean waitCompletionNotification) at Trafi.Vehicles.Tests.Integration.Consumer.WireMockTest.Test_WithHostHeader() in /Users/pbellora/src/trafi-vehicles-service/Trafi.Vehicles.Tests.Integration/Consumer/WireMockTest.cs:line 45 --FlurlHttpException at Flurl.Http.FlurlRequest.HandleExceptionAsync(HttpCall call, Exception ex, CancellationToken token) at Flurl.Http.FlurlRequest.SendAsync(HttpMethod verb, HttpContent content, CancellationToken cancellationToken, HttpCompletionOption completionOption) at Flurl.Http.FlurlRequest.SendAsync(HttpMethod verb, HttpContent content, CancellationToken cancellationToken, HttpCompletionOption completionOption) at Flurl.Http.HttpResponseMessageExtensions.ReceiveString(Task`1 response) ``` Likewise, curling from the command line during test execution shows a similar outcome: ``` $ curl -X GET -H 'Host: myhost' -w '\n%{http_code}\n' 'http://localhost:5001/regions/short' {"Status":"No matching mapping found"} 404 ``` Is there a workaround to this problem? Or do I need to refactor my application to not use the `Host` header during integration tests? I'm using WireMock.Net version `1.1.10`.
adam added the question label 2025-12-29 15:19:10 +01:00
adam closed this issue 2025-12-29 15:19:10 +01:00
Author
Owner

@StefH commented on GitHub (Mar 9, 2020):

You can just use WithHeader ?
Like

var Server = WireMockServer.Start();
	Server
		.Given(Request.Create()
		.WithHeader("Host", "*") // or .WithHeader("Host", "myhost")
		.UsingGet()
		)
		.RespondWith(
			Response.Create()
				.WithStatusCode(200)
				.WithBody(@"{ ""msg"": ""Hello world!"" }")
		);

	string url = Server.Urls.First() + "/foo";
	var result = new FlurlRequest(url)
			.WithHeader("Host", "myhost")
			.GetStringAsync()
			.Result;
	Console.WriteLine(result);
	
	Server.Stop();
@StefH commented on GitHub (Mar 9, 2020): You can just use `WithHeader` ? Like ``` c# var Server = WireMockServer.Start(); Server .Given(Request.Create() .WithHeader("Host", "*") // or .WithHeader("Host", "myhost") .UsingGet() ) .RespondWith( Response.Create() .WithStatusCode(200) .WithBody(@"{ ""msg"": ""Hello world!"" }") ); string url = Server.Urls.First() + "/foo"; var result = new FlurlRequest(url) .WithHeader("Host", "myhost") .GetStringAsync() .Result; Console.WriteLine(result); Server.Stop(); ```
Author
Owner

@bellorap commented on GitHub (Mar 9, 2020):

Hi @StefH, thanks for the quick response. No, unfortunately adding WithHeader("Host", "*") still results in the 404 from the test case with the Host header.

@bellorap commented on GitHub (Mar 9, 2020): Hi @StefH, thanks for the quick response. No, unfortunately adding `WithHeader("Host", "*")` still results in the 404 from the test case with the Host header.
Author
Owner

@bellorap commented on GitHub (Mar 9, 2020):

Hi @StefH, thanks to your example I believe I narrowed down the problem to WithUrl

For example, this solution works:

using System;
using System.Linq;
using Flurl.Http;
using NUnit.Framework;
using WireMock.RequestBuilders;
using WireMock.ResponseBuilders;
using WireMock.Server;
using WireMock.Settings;

namespace Trafi.Vehicles.Tests.Integration.Consumer
{
    public class AnotherWireMockTest
    {
        private WireMockServer Server { get; set; }

        [SetUp]
        public void SetUp()
        {
            var wireMockSettings = new FluentMockServerSettings
            {
                Urls = new [] { "http://localhost:5001" }
            };
            Server = WireMockServer.Start(wireMockSettings);
            Server
                .Given(Request
                    .Create()
                    .UsingGet()
                )
                .RespondWith(
                    Response.Create()
                        .WithStatusCode(200)
                        .WithBody(@"{ ""msg"": ""Hello world!"" }")
                );
        }

        [Test]
        public void Test()
        {
            string url = Server.Urls.First() + "/foo";
            var result = new FlurlRequest(url)
                .WithHeader("Host", "myhost")
                .GetStringAsync()
                .Result;
            Console.WriteLine(result);
        }

        [TearDown]
        public void TearDown()
        {
            Server.Stop();
        }
    }
}

While this doesn't:

using System;
using System.Linq;
using Flurl.Http;
using NUnit.Framework;
using WireMock.RequestBuilders;
using WireMock.ResponseBuilders;
using WireMock.Server;
using WireMock.Settings;

namespace Trafi.Vehicles.Tests.Integration.Consumer
{
    public class AnotherWireMockTest
    {
        private WireMockServer Server { get; set; }

        [SetUp]
        public void SetUp()
        {
            var wireMockSettings = new FluentMockServerSettings
            {
                Urls = new [] { "http://localhost:5001" }
            };
            Server = WireMockServer.Start(wireMockSettings);
            Server
                .Given(Request
                    .Create()
                    .WithUrl("http://localhost:5001/*") // PROBLEM!
                    .UsingGet()
                )
                .RespondWith(
                    Response.Create()
                        .WithStatusCode(200)
                        .WithBody(@"{ ""msg"": ""Hello world!"" }")
                );
        }

        [Test]
        public void Test()
        {
            string url = Server.Urls.First() + "/foo";
            var result = new FlurlRequest(url)
                .WithHeader("Host", "myhost")
                .GetStringAsync()
                .Result;
            Console.WriteLine(result);
        }

        [TearDown]
        public void TearDown()
        {
            Server.Stop();
        }
    }
}

Am I using WithUrl correctly? In practice, I think I need it to match requests to different ports with different mappings.

@bellorap commented on GitHub (Mar 9, 2020): Hi @StefH, thanks to your example I believe I narrowed down the problem to `WithUrl` For example, this solution works: ``` using System; using System.Linq; using Flurl.Http; using NUnit.Framework; using WireMock.RequestBuilders; using WireMock.ResponseBuilders; using WireMock.Server; using WireMock.Settings; namespace Trafi.Vehicles.Tests.Integration.Consumer { public class AnotherWireMockTest { private WireMockServer Server { get; set; } [SetUp] public void SetUp() { var wireMockSettings = new FluentMockServerSettings { Urls = new [] { "http://localhost:5001" } }; Server = WireMockServer.Start(wireMockSettings); Server .Given(Request .Create() .UsingGet() ) .RespondWith( Response.Create() .WithStatusCode(200) .WithBody(@"{ ""msg"": ""Hello world!"" }") ); } [Test] public void Test() { string url = Server.Urls.First() + "/foo"; var result = new FlurlRequest(url) .WithHeader("Host", "myhost") .GetStringAsync() .Result; Console.WriteLine(result); } [TearDown] public void TearDown() { Server.Stop(); } } } ``` While this doesn't: ``` using System; using System.Linq; using Flurl.Http; using NUnit.Framework; using WireMock.RequestBuilders; using WireMock.ResponseBuilders; using WireMock.Server; using WireMock.Settings; namespace Trafi.Vehicles.Tests.Integration.Consumer { public class AnotherWireMockTest { private WireMockServer Server { get; set; } [SetUp] public void SetUp() { var wireMockSettings = new FluentMockServerSettings { Urls = new [] { "http://localhost:5001" } }; Server = WireMockServer.Start(wireMockSettings); Server .Given(Request .Create() .WithUrl("http://localhost:5001/*") // PROBLEM! .UsingGet() ) .RespondWith( Response.Create() .WithStatusCode(200) .WithBody(@"{ ""msg"": ""Hello world!"" }") ); } [Test] public void Test() { string url = Server.Urls.First() + "/foo"; var result = new FlurlRequest(url) .WithHeader("Host", "myhost") .GetStringAsync() .Result; Console.WriteLine(result); } [TearDown] public void TearDown() { Server.Stop(); } } } ``` Am I using `WithUrl` correctly? In practice, I think I need it to match requests to different ports with different mappings.
Author
Owner

@StefH commented on GitHub (Mar 9, 2020):

WithUrl can be used. However in your case I think that removing WithUrl and/or replacing with WithPath would be better.

Take a look at the Wiki or unit tests for more examples.

@StefH commented on GitHub (Mar 9, 2020): WithUrl can be used. However in your case I think that removing WithUrl and/or replacing with WithPath would be better. Take a look at the Wiki or unit tests for more examples.
Author
Owner

@bellorap commented on GitHub (Mar 9, 2020):

@StefH I'm not sure I understand your answer. Is the last snipped posted above expected to work? If not, can you please explain why? Otherwise, would it make sense to open a bug for this behavior?

@bellorap commented on GitHub (Mar 9, 2020): @StefH I'm not sure I understand your answer. Is the last snipped posted above expected to work? If not, can you please explain why? Otherwise, would it make sense to open a bug for this behavior?
Author
Owner

@StefH commented on GitHub (Mar 10, 2020):

The WithUrl works as expected. However, because you overwrite the host, the url in WireMock is changed to that one.
So you need code like this:

var wireMockSettings = new FluentMockServerSettings
            {
                Urls = new[] { "http://localhost:5001" },
                // AllowPartialMapping = true,
                Logger = new WireMockConsoleLogger()
            };
            var Server = WireMockServer.Start(wireMockSettings);
            Server
                .Given(Request
                    .Create()
                    .WithHeader("host", "*") /// <------ 
                    .WithUrl("http://myhost/*") // <------
                    .UsingGet()
                )
                .RespondWith(
                    Response.Create()
                        .WithStatusCode(200)
                        .WithBody(@"{ ""msg"": ""Hello world!"" }")
                );

            string url = Server.Urls.First() + "/foo";
            var result = new FlurlRequest(url)
                .WithHeader("Host", "myhost")
                .GetStringAsync()
                .Result;
            Console.WriteLine(result);

Note that adding the console logger and setting AllowPartialMapping = true can help you detect why a mapping is not 100% matching.

@StefH commented on GitHub (Mar 10, 2020): The `WithUrl` works as expected. However, because you overwrite the **host**, the url in WireMock is changed to that one. So you need code like this: ``` c# var wireMockSettings = new FluentMockServerSettings { Urls = new[] { "http://localhost:5001" }, // AllowPartialMapping = true, Logger = new WireMockConsoleLogger() }; var Server = WireMockServer.Start(wireMockSettings); Server .Given(Request .Create() .WithHeader("host", "*") /// <------ .WithUrl("http://myhost/*") // <------ .UsingGet() ) .RespondWith( Response.Create() .WithStatusCode(200) .WithBody(@"{ ""msg"": ""Hello world!"" }") ); string url = Server.Urls.First() + "/foo"; var result = new FlurlRequest(url) .WithHeader("Host", "myhost") .GetStringAsync() .Result; Console.WriteLine(result); ``` Note that adding the console logger and setting AllowPartialMapping = true can help you detect why a mapping is not 100% matching.
Author
Owner

@bellorap commented on GitHub (Mar 11, 2020):

@StefH That makes sense, thanks for explaining! I also didn't notice AllowPartialMapping - that's helpful!

@bellorap commented on GitHub (Mar 11, 2020): @StefH That makes sense, thanks for explaining! I also didn't notice `AllowPartialMapping` - that's helpful!
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: starred/WireMock.Net-wiremock#256