dotnet / aspnetcore

ASP.NET Core is a cross-platform .NET framework for building modern cloud-based web applications on Windows, Mac, or Linux.
https://asp.net
MIT License
35.43k stars 10.01k forks source link

Unix socket bidding with Owin not working #3122

Closed sterchelen closed 5 years ago

sterchelen commented 6 years ago

Hi,

I'm trying to use unix socket with Owin and Nancy activated. With the ListenUnixSocket() all of my requests return 500 whereas with the standard tcp bidding Listen() everything is fine ! Here is the stack trace, thanks to UseDeveloperExceptionPage():

   at Microsoft.AspNetCore.Owin.OwinEnvironment.<>c.<.ctor>b__2_50(IHttpConnectionFeature feature)
   at Microsoft.AspNetCore.Owin.OwinEnvironment.FeatureMap`1.<>c__DisplayClass2_0.<.ctor>b__0(Object feature)
   at Microsoft.AspNetCore.Owin.OwinEnvironment.FeatureMap.TryGet(HttpContext context, Object& value)
   at Microsoft.AspNetCore.Owin.OwinEnvironment.System.Collections.Generic.IDictionary<System.String,System.Object>.TryGetValue(String key, Object& value)
   at Nancy.Owin.NancyMiddleware.Get[T](IDictionary`2 env, String key)
   at Nancy.Owin.NancyMiddleware.<>c__DisplayClass2_1.<<UseNancy>b__1>d.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.GetResult()
   at Microsoft.AspNetCore.Owin.WebSocketAcceptAdapter.<>c__DisplayClass6_0.<<AdaptWebSockets>b__0>d.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.GetResult()

My code that bind the unix socket :

                var host = new WebHostBuilder()
                    .UseKestrel(k =>
                    {
                        k.Listen(IPAddress.Any, port);
                        if (!string.IsNullOrEmpty(kestrelSocketPath))
                            k.ListenUnixSocket(kestrelSocketPath);
                    })
                    .UseContentRoot(Directory.GetCurrentDirectory())
                    .UseStartup<Startup>()
                    .Build();

Any ideas ?

Dotnet and owin version --> 2.0.2 Nancy --> 2.0.0

Thanks.

khellang commented 6 years ago

What is the actual exception type and message?

sterchelen commented 6 years ago

Type -> NullReferenceException Message -> Object reference not set to an instance of an object Stacktrace ->

   at Microsoft.AspNetCore.Owin.OwinEnvironment.<>c.<.ctor>b__2_50(IHttpConnectionFeature feature)
   at Microsoft.AspNetCore.Owin.OwinEnvironment.FeatureMap`1.<>c__DisplayClass2_0.<.ctor>b__0(Object feature)
   at Microsoft.AspNetCore.Owin.OwinEnvironment.FeatureMap.TryGet(HttpContext context, Object& value)
   at Microsoft.AspNetCore.Owin.OwinEnvironment.System.Collections.Generic.IDictionary<System.String,System.Object>.TryGetValue(String key, Object& value)
   at Nancy.Owin.NancyMiddleware.Get[T](IDictionary`2 env, String key)
   at Nancy.Owin.NancyMiddleware.<>c__DisplayClass2_1.<<UseNancy>b__1>d.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.GetResult()
   at Microsoft.AspNetCore.Owin.WebSocketAcceptAdapter.<>c__DisplayClass6_0.<<AdaptWebSockets>b__0>d.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.GetResult()

Command to test : curl -v --no-buffer -XGET --unix-socket /tmp/sock-test.sock http://localhost/

Tratcher commented 6 years ago

https://github.com/aspnet/HttpAbstractions/blob/816516f193afcb7ce6b564facc2a36d7e86604ea/src/Microsoft.AspNetCore.Owin/OwinEnvironment.cs#L75-L86 Hmm, it assumes IPs and ports are always available.

Workaround: set those fields to dummy values in a middleware prior to your owin components.

khellang commented 6 years ago

Hmm, it assumes IPs and ports are always available.

Yes, looks like the Nancy middleware pulls server.RemoteIpAddress for all requests. This should probably be more resilient.

Not sure if there's anything to do in the OWIN adapter? I guess there could be better error handling there as well, or provide dummy/null values out of the box.

Tratcher commented 6 years ago

The adapter could return null rather than throwing.

khellang commented 6 years ago

Ah, well, Nancy actually uses TryGetValue and falls back to default(T) if the key doesn't exist, so it should handle missing values.

I guess the fix here is to make sure the adapter doesn't throw.

sterchelen commented 6 years ago

In fact ! Setting IPaddresses to dummy values resolve my issue :

context.Connection.LocalIpAddress = new IPAddress(new byte[] {0, 0, 0, 0});
                    context.Connection.RemoteIpAddress = new IPAddress(new byte[] {0, 0, 0, 0});

Thank you.

analogrelay commented 5 years ago

Sounds like there are sufficient workarounds for this scenario. Closing.