Nancy icon indicating copy to clipboard operation
Nancy copied to clipboard

Headers added in AfterRequest pipeline are ignored when handler returns 404 status

Open klym1 opened this issue 6 years ago • 13 comments

Prerequisites

  • [x] I have written a descriptive issue title
  • [x] I have verified if the problem exist in both DEBUG and RELEASE mode
  • [x] I have verified that I am running the latest version of Nancy
  • [x] I have searched open and closed issues to ensure it has not already been reported

Description

When handler returns something with 404 status (NotFound) any custom headers added in pipelines.AfterRequest are ignored.

Steps to Reproduce

Enable custom headers in a bootstrapper as usual:

protected override void ApplicationStartup(TinyIoCContainer container, IPipelines pipelines)
{
    pipelines.AfterRequest.AddItemToEndOfPipeline(x =>
    {
         x.Response.WithHeader("Access-Control-Allow-Origin", "*");
         x.Response.WithHeader("Access-Control-Allow-Headers", "Authorization, Origin, Content-Type, Accept");
         x.Response.WithHeader("Access-Control-Allow-Methods", "GET, HEAD, POST, PUT, DELETE, OPTIONS, PATCH");
         x.Response.WithHeader("Access-Control-Expose-Headers", "Location, Content-Disposition, Content-Type");
    });
}

Create test handler:

public class TestModule : NancyModule
{
    public TestModule()
    {
        Get["/test"] = _ => HttpStatusCode.NotFound;
        Get["/test2"] = _ => HttpStatusCode.Forbidden;
    }
}
GET /test

Transfer-Encoding: chunked
Content-Type: application/json; charset=utf-8
Vary: Accept
Server: Microsoft-HTTPAPI/2.0
Date: Fri, 03 Aug 2018 12:07:14 GMT
GET /test2

Transfer-Encoding: chunked
Content-Type: text/html
Server: Microsoft-HTTPAPI/2.0
Access-Control-Allow-Origin: *
Access-Control-Allow-Headers: Authorization, Origin, Content-Type, Accept
Access-Control-Allow-Methods: GET, HEAD, POST, PUT, DELETE, OPTIONS, PATCH
Access-Control-Expose-Headers: Location, Content-Disposition, Content-Type
Date: Fri, 03 Aug 2018 12:07:57 GMT

GET /test should return 'Access-Control-*' headers as GET /test2 does

System Configuration

  • Nancy version:

    • 1.4.4.0
  • Nancy host

    • Nancy.Hosting.Self
  • Environment:

    • Windows 10 x64
  • .NET Framework version:

    • 4.7.1

klym1 avatar Aug 03 '18 12:08 klym1

Guys, someone, anyone? This is a quite important question for me

klym1 avatar Aug 18 '18 17:08 klym1

Same thing for me. My cors headers are not in the 404 response.

ronnieoverby avatar Oct 12 '18 03:10 ronnieoverby

I've tried various approaches, but can not reproduce this issue. Using Nancyfx v1.4.4 and the below file code, I still get the cross origin headers

using Nancy; using Nancy.Bootstrapper; using Nancy.Hosting.Self; using Nancy.TinyIoc; using System;

namespace TestAfterPipeline { class Program { static void Main(string[] args) { HostConfiguration config = new HostConfiguration() { RewriteLocalhost = false, UrlReservations = new UrlReservations() { CreateAutomatically = false } }; INancyBootstrapper strapper = new SimpleBootStrapper();

  using (NancyHost host = new NancyHost(strapper, config, new Uri("

http://localhost:80"))) { host.Start(); Console.ReadLine(); host.Stop(); } } }

public class SimpleModule : NancyModule { public SimpleModule() { Get["400"] = _ => { return Nancy.HttpStatusCode.BadRequest; };

  Get["404"] = _ =>
  {
    return Nancy.HttpStatusCode.NotFound;
  };

  Get["500"] = _ =>
  {
    return Nancy.HttpStatusCode.InternalServerError;
  };
}

}

public class SimpleBootStrapper : DefaultNancyBootstrapper { protected override void ApplicationStartup(TinyIoCContainer container, IPipelines pipelines) { base.ApplicationStartup(container, pipelines); pipelines.AfterRequest.AddItemToEndOfPipeline(c => { c.Response.WithHeader("Access-Control-Allow-Origin", "*"); }); } } }

On Thu, Oct 11, 2018 at 9:21 PM Ronnie Overby [email protected] wrote:

Same thing for me. My cors headers are not in the 404 response.

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/NancyFx/Nancy/issues/2920#issuecomment-429191626, or mute the thread https://github.com/notifications/unsubscribe-auth/AEEilkQYIhB9POHqJBoYEgKOPyneMJJGks5ukAq_gaJpZM4Vt4GP .

-- Jonathon Koyle

cloudhunter89 avatar Oct 12 '18 21:10 cloudhunter89

I will post repro.

ronnieoverby avatar Oct 15 '18 13:10 ronnieoverby

Here's my bootstrapper:

public class BS : DefaultNancyBootstrapper
{
	protected override void ApplicationStartup(TinyIoCContainer container, IPipelines pipelines)
	{
		pipelines.AfterRequest += ctx =>
		{
			ctx.Response.WithHeader("Access-Control-Allow-Origin", "*")
						.WithHeader("Access-Control-Allow-Methods", "POST, GET, DELETE, PUT, OPTIONS, PATCH")
						.WithHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept, Authorization")
						.WithHeader("Access-Control-Max-Age", "3600");
		};
	}
}

I see a difference. pipelines.AfterRequest vs pipelines.AfterRequest.AddItemToEndOfPipeline. I can't test at the moment, but I'm assuming that would probably be the fix.

ronnieoverby avatar Oct 15 '18 13:10 ronnieoverby

So, I tried to use pipelines.AfterRequest instead of pipelines.AfterRequest.AddItemToEndOfPipeline, also I tried to call base method base.ApplicationStartup(container, pipelines); as @cloudhunter89 did, but with no apparent success. Here's full code, that I was using and which doesn't work for me:

    class Program
    {
        static void Main()
        {
            new NancyHost(new Uri("http://127.0.0.1:8000"), new Boot()).Start();
            Console.ReadKey();
        }
    }

    public class TestModule : NancyModule
    {
        public TestModule()
        {
            Get["/test"] = _ => HttpStatusCode.NotFound;
            Get["/test2"] = _ => HttpStatusCode.Forbidden;
        }
    }

    public class Boot : DefaultNancyBootstrapper
    {
        protected override void ApplicationStartup(TinyIoCContainer container, IPipelines pipelines)
        {
            base.ApplicationStartup(container, pipelines);

            pipelines.AfterRequest +=  x =>
            {
                x.Response.WithHeader("Access-Control-Allow-Origin", "*");
                x.Response.WithHeader("Access-Control-Allow-Headers", "Authorization, Origin, Content-Type, Accept");
                x.Response.WithHeader("Access-Control-Allow-Methods", "GET, HEAD, POST, PUT, DELETE, OPTIONS, PATCH");
                x.Response.WithHeader("Access-Control-Expose-Headers", "Location, Content-Disposition, Content-Type");
            };
        }
    }

UPD For the record - I was using Postman and Insomnia as REST clients

klym1 avatar Oct 16 '18 08:10 klym1

@cloudhunter89 Can you please provide actual headers returned for each of your handlers? (400, 404, 500)

klym1 avatar Oct 16 '18 08:10 klym1

404

ronnieoverby avatar Oct 16 '18 11:10 ronnieoverby

Using your file (with my hostname instead of 127.0.0.1 which should not be a significant difference), I get the following:

$ curl -I http://c01622:8080/test
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                             Dload  Upload   Total   Spent    Left  Speed
  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0HTTP/1.1 404 Not Found
Transfer-Encoding: chunked
Content-Type: text/html
Server: Microsoft-HTTPAPI/2.0
Access-Control-Allow-Origin: *
Access-Control-Allow-Headers: Authorization, Origin, Content-Type, Accept
Access-Control-Allow-Methods: GET, HEAD, POST, PUT, DELETE, OPTIONS, PATCH
Access-Control-Expose-Headers: Location, Content-Disposition, Content-Type
Date: Tue, 16 Oct 2018 13:20:31 GMT

and

$ curl -I http://c01622:8080/test2
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                             Dload  Upload   Total   Spent    Left  Speed
  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0HTTP/1.1 403 Forbidden
Transfer-Encoding: chunked
Content-Type: text/html
Server: Microsoft-HTTPAPI/2.0
Access-Control-Allow-Origin: *
Access-Control-Allow-Headers: Authorization, Origin, Content-Type, Accept
Access-Control-Allow-Methods: GET, HEAD, POST, PUT, DELETE, OPTIONS, PATCH
Access-Control-Expose-Headers: Location, Content-Disposition, Content-Type
Date: Tue, 16 Oct 2018 13:27:20 GMT

However, if I hit my machine at the listening IP Address instead of the host name, I get the following:

$ curl -I http://192.168.56.1:8080/test
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                             Dload  Upload   Total   Spent    Left  Speed
  0   334    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0HTTP/1.1 400 Bad Request
Content-Length: 334
Content-Type: text/html; charset=us-ascii
Server: Microsoft-HTTPAPI/2.0
Date: Tue, 16 Oct 2018 13:20:58 GMT
Connection: close

cloudhunter89 avatar Oct 16 '18 13:10 cloudhunter89

I'm encountering the same issue - did you ever get a solution?

kendolondon avatar Jun 20 '19 18:06 kendolondon

@kendoglasgow Are you also using Postman to test the endpoint? I just tried it today and I see this: image

cloudhunter89 avatar Jun 21 '19 15:06 cloudhunter89

Well that's bizarre! I'm seeing the same thing using Postman vs Chrome. It seems to be related to the request "Accept" header - I was able to make it work in Postman by changing the default "/" to the same one sent by Chrome. I then removed the header list items one by one till I found the one that breaks it - I ended up with "text/html,/" - so adding text/html to the Accept header list makes it work from Postman.

My ultimate problem, however, is that this issue is also causing my code to fail a test in a Python authored protocol test suite and I can't change the tests so any ideas what could be causing this on the Nancy side and how to fix it?

kendolondon avatar Jun 23 '19 10:06 kendolondon

1 year since this issue was open, no solution yet?

matias-quezada avatar Oct 10 '19 17:10 matias-quezada