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

Networking stack - Technical roadmap #43495

Closed
karelz opened this issue Jun 25, 2017 · 121 comments
Closed

Networking stack - Technical roadmap #43495

karelz opened this issue Jun 25, 2017 · 121 comments
Labels
untriaged New issue has not been triaged by the area owner

Comments

@karelz
Copy link
Member

karelz commented Jun 25, 2017

Summary

Our investment in the .NET networking space will focus in the following areas

Foundation: Sockets, SSL, DNS support.

Primary Goal: Provide near-native performance and rock-solid reliability.

Key investments:

  • Stress testing
  • Regular automated perf runs
  • Improved perf for Task-based APIs
  • Improve Unix performance and reliability

Web Stack: HttpClient, ClientWebSocket

Primary goals: Ease of use; feature-rich; extensible; track emerging standards; match or exceed competitor's performance.

Key investments:

  • Build new pure-managed stack
    • Zero external dependencies -- builds on our Foundation
    • Consistent feature set and behavior across platforms
    • Improved performance
    • Helps drive Foundation investments
  • Enable key customer feature asks and fill feature gaps

Tracking: https://github.com/dotnet/corefx/issues/21452

Emerging Technology

Primary goals: Demonstrate leadership in support for new protocols and capabilities

Key investments:

  • Provide prototypes on corefxlab as appropriate
  • Examples: HTTP/2, RIO, QUIC

Maintenance Components: *WebRequest, Mail, HttpListener

Primary goals: Preserve existing customer investments
Key investments: None.

Details

(1) Foundational

Key components

  • Sockets (System.Net.Sockets)
  • SSL support (System.Net.Security.SslStream)
  • DNS support (System.Net.NameResolution)

Characteristics

  • Tightly integrated with platform OS
  • Provides a platform-neutral abstraction on top of diverse OS APIs
  • Zero external dependencies beyond OS + OpenSSL (OpenSSL just on Linux for now)
  • Public APIs evolve very slowly
  • Few users use this layer directly, but the ones who do are disproportionately high-powered devs and care about the functionality/perf/reliability/etc deeply

Requirements

  • Bulletproof reliability
  • Excellent performance

Current Status

Windows

  • Implementation has existed for many years, with little attention until recently
  • Near-native performance and (mostly) zero-allocation for Sockets, using SocketAsyncEventArgs
    • (key recent improvement: synchronous completion support)
  • Good performance using Task-based APIs
    • (key recent improvement: implement these using cached SocketAsyncEventArgs; this applies to Linux too)
    • More work to be done here.  Unfortunately, we cannot get to truly zero-allocation for Task APIs, but we can try to minimize the overhead relative to SocketAsyncEventArgs
  • Reliability is somewhat questionable
    • Recently learned of and fixed SocketAsyncEventArgs bug that had been known in community for years

Linux

  • Core of implementation is brand new
  • Very good performance for Sockets using SocketAsyncEventArgs
    • Not zero-allocation yet
    • Some known issues (coarse locking, thread serialization)
  • Good performance using Task-based APIs
  • Reliability is mostly unknown at this point

Key investments to make

  • Improved stress testing
  • Regular performance measurement and regression tracking
  • Longer-term:
    • Enhance to support new OS perf-focused capabilities (TCP Fast Open, Windows RIO, etc)
    • Enhance SSL to support new protocol extensions as they gain traction (SNI, ALPN, OCSP)
    • Can Span<T> be a perf win for Sockets?  Ideally, yes, but details are unclear at this point
    • Refactor Sockets code to reduce redundancy between SAEA and non-SAEA paths, with the goal of improving performance and reliability for non-SAEA paths

(2) Web stack

Key components

  • HttpClient (System.Net.Http)
  • ClientWebSocket (System.Net.WebSockets)
  • Server web stack
  • Primarily, ASP.NET, which provides both HTTP and WebSocket listening capabilities
  • Issue: Do we need a server API other than ASP.NET?  This would be a replacement for HttpListener, which is legacy.
  • Not a key component: HttpWebRequest and related (e.g. ServicePoint), which is legacy.

Characteristics

  • Provides simple, powerful, extensible way to communicate using the most popular web-based protocols
  • Used by many, many users, from basic devs to power users

Requirements

  • Easy to learn and use, without limiting advanced capabilities
  • Good performance
  • For the few users who care deeply about maximizing performance at this layer (e.g. http message router/load balancer), an alternative, lower-level approach may be more applicable
  • Very good reliability
  • Consistency across OSes

Current Status

  • Implementations differ across OSes.

Windows

  • HttpClient and ClientWebSocket built on native WinHttp APIs
  • Decent performance
  • Some functionality depends on OS version
  • ClientWebSocket not supported on Win7 due to missing OS support
  • Bug fixes often depend on availability of OS patch

Linux

  • HttpClient built on libcurl
    • Known performance issues that are difficult to solve:
      • On Mike Harder DataIngestion benchmark, Go has higher throughput vs .NET Core 2.0 in high-concurrency scenarios
    • Some compatibility issues with Windows implementation
  • ClientWebSocket implemented in managed code, with hard-wired, websocket-specific HTTP protocol handling
    • ~10% better throughput than WinHttp implementation (both run on Windows); last measurement was over 6 months ago, and should be improved by recent Socket perf improvements
    • Some functionality is not supported due to hard-wired HTTP protocol support

ASP.NET

  • Builds on libuv on both Linux and Windows
    • Some known performance issues, e.g. TechEmpower plaintext; investigation ongoing

Key investments to make

  • Move to managed-only implementation of HttpClient and ClientWebSocket for both Linux and Windows - see https://github.com/dotnet/corefx/issues/21452

    • Avoid dependency/platform version hell; depend ONLY on our Foundational layer above
    • Enable consistent functionality, performance, and reliability across platforms
    • Deliver these first in CoreFxLab (then in CoreFX as optional component) and get user feedback
    • Focus on delivering for Linux first, since the current pain is worst there
    • Eat our own dog food: Building on our Foundational layer helps drives perf and reliability of that layer
    • Simple managed HttpClient prototype:
      • Supports HTTP/1.1 with SSL (no HTTP2, no digest/nego auth)
      • Throughput is ~4x current Linux implementation, ~2x current Windows implementation
      • Mike Harder's HttpClientPerf test using GET method
      • Very raw, so take this with a grain of salt
  • ASP.NET

    • Can we implement ASP.NET on top of our foundational layer (i.e. Sockets)?
      • What are the perf implications?
      • Benefits:
        • Eat our own dog food, drive investments in Foundational layer.
        • Reduced cost to ASP.NET
      • Investigation ongoing.
  • Enhance web stack to enable key customer asks and fill gaps

    • Advanced config options (UseNagleAlgorithm, DnsRefreshTimeout, etc)
    • Http pipelining
    • Caching policies
    • Request/response stream lifetimes (enable web sockets and long polling scenarios)

(3) Legacy/maintenance components

Key components

  • Mail client (System.Net.Mail)
  • Http/Ftp/FileWebRequest (System.Net.Requests, System.Net.ServicePoint)
  • HttpListener (System.Net.HttpListener)

Characteristics

  • Components that we consider legacy because we have provided a replacement (HttpWebRequest => HttpClient)
  • Components that we consider legacy without replacement, and expect users to seek out 3rd party solutions (FtpWebRequest)
  • Components that are in maintenance mode and we expect no significant investment (Mail client => MailKit)

Key investments to make

  • Fix critical bugs as necessary

(4) Future/bleeding edge components

Not covered in this version.

Key Feedback

TODO (@karelz)

Credentials & Status

Author: @geoffkizer

Reviewed by CoreFX team: @stephentoub @davidsh @CIPop @Priya91 @wfurt @DavidGoll @karelz
Reviewed by partner teams experts: @davidfowl (ASP.NET), @Tratcher (ASP.NET), @mikeharder (ASP.NET), @marek-safar (Mono/Xamarin), @mconnew (WCF), Windows networking experts, @tmds (RedHat), @omajid (RedHat)
Reviewed by community networking experts: @benaadams, @NickCraver, @onovotny, @mgravell, @Drawaes

Reviews happened in stages in April. Feedback will be incorporated in updates to this doc.
The delay between original review and publishing the roadmap now is purely lack of time to incorporate feedback into the doc & publish it.

Current status: Community review / feedback

Announcements: Twitter and CoreFX repo

@karelz karelz changed the title Networking APIs - Technical roadmap Networking stack - Technical roadmap Jun 25, 2017
@mgravell
Copy link
Member

Question: is it relevant / appropriate to ask how "pipelines" fits into this picture? does pipelines fit into this picture? or is that a completely separate picture? and if so, how the two pictures (and timescales) interplay with eachother? hmmm... too many picture metaphors, but... whatever - you get the picture dammit!

@galvesribeiro
Copy link
Member

@mgravell was about to ask the same thing... Where does pipelines fit in those cases? In the middle between the foundation and the upper layers?

@Aaronontheweb
Copy link

For RIO: isn't that based on Win32 features? Is there an x-plat story for it?

@Drawaes
Copy link
Contributor

Drawaes commented Jun 25, 2017

I think the idea there would be a pluggable transport layer like kestrel is using, allowing platform optmisations while protocol handling etc staying the same. RIO is a windows only thing.

@galvesribeiro
Copy link
Member

@Aaronontheweb There is RapidIO driver and NIO/MTPL on linux as well which are somehow similar to RIO in some aspects.

@karelz
Copy link
Member Author

karelz commented Jun 25, 2017

Re: Pipelines

I personally view Pipelines and Span<T> as lower-layer primitives. When they are successful and bring non-trivial wins to the networking stack, we will definitely use them. We keep them in mind as we work on the new stack, but the work is happening mostly in parallel at this moment. They are additive improvements (potentially adding more API surface).

Re: RIO

The idea is to first explore how we could use it / surface it. With that comes obviously also exploration of Linux alternatives (e.g. RapidIO mentioned above). We did not do the investigation yet (neither on Windows, nor on Linux alternatives), so we do not have concrete plan in place.

@Aaronontheweb
Copy link

thanks @karelz @galvesribeiro - great to know! Would love to see this make it into DotNetty in the future.

@Tornhoof
Copy link
Contributor

Maybe add the hint that mailkit is the suggested replacement for system.net.mail?

@karelz
Copy link
Member Author

karelz commented Jun 25, 2017

That's a known thing already: https://github.com/terrajobst/platform-compat/blob/master/docs/DE0005.md (from our official under-construction docs)

[UPDATE] Top post updated with the link

@Suchiman
Copy link
Contributor

Suchiman commented Jun 25, 2017

Sounds great 👍
Does the managed HttpClient also solve these issues or at least not make you tap into them by default?
You're using HttpClient wrong and it is destabilizing your software
Singleton HttpClient? Beware of this serious behaviour and how to fix it

@karelz
Copy link
Member Author

karelz commented Jun 25, 2017

The managed HttpClient will try to do its best to keep exactly same API surface as the old one (to ease up migration and to eventually make it the default in .NET Core). If the problems above are caused by the API surface, then it won't change.

If we find that by changing the API surface we can get significant perf wins or usability wins, we could eventually entertain the idea to create new API surface (similar to the old one). However, it will be only last resort solution which would have to be paid by significant wins for developers.

@ewinnington
Copy link

Where does WCF fit into the dotnet networking stack?

@bgever
Copy link

bgever commented Jun 25, 2017

For ASP.NET the single most empowering new feature would be server push with HTTP/2. It significantly enhances performance of SPA apps where critical files can be pushed faster by the developer. A related feature is sending partial files, especially useful to send progressive JPEGs that show an initial low-res preview and then load completely after priority requests have completed. The effects of these two combined can give end-users an incredible perceived performance boost.

I assume that both these features would require support from the networking stack, is this on the roadmap?

Additionally, HTTP/2 support for Azure would be nice, and work on that seems to have started.

@davidfowl
Copy link
Member

I assume that both these features would require support from the networking stack, is this on the roadmap?

HTTP/2 works today with WebListener and when using IIS on Windows 10/Server 2016 (though we don't yet expose the push promise API aspnet/HttpAbstractions#371). Work is happening post 2.0 to support it natively in Kestrel which requires ALPN support from SSL Stream (which is mentioned above).

@Drawaes
Copy link
Contributor

Drawaes commented Jun 26, 2017

I think the Http client is interesting because out of the box it certainly isn't great for service to service communication (max 2 connections etc). But I think if the performance is right then a "wrapped" http client with better default settings would solve most of the problems people hit. It's more a guidance than a missing features problem.

Today I always wrap it for s2s in our environments and pass it to devs with settings tweaked.

@bgever
Copy link

bgever commented Jun 26, 2017

@davidfowl Awesome, thanks for the quick update!

@SteveDesmond-ca
Copy link
Contributor

It would be great to get some xplat consistency here -- I spent quite some time debugging why perf for one app was so different between OSes...turns out CurlHandler is quite a bit faster than WinHttpHandler!

@karelz
Copy link
Member Author

karelz commented Jun 26, 2017

Re: WCF

@ewinnington WCF technology is built on top of Networking stack. The WCF team was involved (@mconnew) in our reviews to make sure we are not dropping important features for WCF. Discussion about WCF client or server is outside of scope here. We think about Networking stack as silent (or at least minimal-work) replacement of current Networking APIs, so all upstack technologies will be able to use it right away (or with minimal effort in the worst case).

Re: HTTP/2

@bgever HTTP/2 is on our list (see Emerging Technologies in top post). We are also aware of ASP.NET HTTP/2 efforts and we plan to reuse code and effort as much as possible.

@SteveDesmond-ca our technical roadmap is primarily motivated by perf and consistency across platforms. Perf is especially needed in HttpClient & SslStream for client and middle-ware scenarios.

@Horusiath
Copy link

@karelz Are there any plans to support transfer file API?

@slang25
Copy link
Contributor

slang25 commented Jun 26, 2017

I'd expect that the recommendation would be to continue to use a single shared instance of HttpClient where possible, would the DNS caching issue outlined below be fixed as a result of this new managed implementation:

@stephentoub
Copy link
Member

Are there any plans to support transfer file API?

@Horusiath, can you elaborate? Are you asking for Socket.SendFile? Or APIs that wrap Windows' background file transfer APIs? Or something else?

@stephentoub
Copy link
Member

would the DNS caching issue outlined below be fixed as a result of this new managed implementation

What change are you hoping for?

@Suchiman
Copy link
Contributor

@stephentoub the summary of the links @slang25 and i posted:

  • HttpClient implements IDisposable but if you Dispose the HttpClient, you'll be leaking it's TCP Connection (at least on windows) by default for 240s due to TIME_WAIT state which makes you run out of available socket connections under high load.
  • If you singleton the HttpClient to workaround this terrible behavior, you become vulnerable to missing DNS Cache Invalidation.
  • On .NET Framework you can limit the impact of the DNS Cache by using the ServicePoint class which is unavailable on .NET Core AFAIK.

The Primary concern is: can we remove this unexpected trap that seems to be both known and nothing done about while also being a luring trap many are not aware about.

@Horusiath
Copy link

@stephentoub I'm talking about the TransmitFile on Windows and sendfile on Linux. Both of them enable sending files from disk directly to socket using a single system call, without need of using user code in the middle.

@stephentoub
Copy link
Member

@stephentoub
Copy link
Member

HttpClient implements IDisposable...
If you singleton the HttpClient to workaround this terrible behavior...

HttpClient was explicitly designed to be used as a singleton, or rather with as few HttpClient instances as possible, reusing them for all operations rather than creating a new one per operation. But it still represents resources, so it implements IDisposable for cleaning up after it if there's a time when you need to do that.

This is inherent to the design. Are you hoping to see that changed somehow, and if so, how? If your concern is around education, helping devs to better understand and employ that design, then I agree, but I'm not sure what could be done about that in the APIs themselves (I could imagine things done external to the APIs, e.g. better documentation, some kind of static analysis, etc.). If you have suggestions, please share.

On .NET Framework you can limit the impact of the DNS Cache by using the ServicePoint class which is unavailable on .NET Core AFAIK.

It's there in .NET Core 2.0, though this particular setting currently isn't respected by either the WinHttp or libcurl implementations, in part because (at least to my knowledge) those underlying providers don't have similar knobs. So, what exactly is the change you're hoping for? Are you asking for new APIs to be added to provide more fine-grained control over the connection pooling? Are you asking for an API to disable connection pooling? Are you asking for an API to timeout connections after some period of time? Are you just asking for the .NET Core implementation to respect ServicePointManager settings related to this? Etc. Since this managed implementation would be managing its own connection pooling, it will have more of an ability to provide fine-grained controls over things, and then the question is if/how such settings should be controllable through API, and such API-level requests should be in a separate issue.

Thanks.

@Horusiath
Copy link

@stephentoub Socket.SendFile exists only on .NET CLR. It doesn't appear in .NET Core.

@stephentoub
Copy link
Member

Socket.SendFile exists only on .NET CLR. It doesn't appear in .NET Core.

It does. It was added for .NET Core 2.0.

@davidfowl
Copy link
Member

davidfowl commented Jun 26, 2017

HttpClient was explicitly designed to be used as a singleton, or rather with as few HttpClient instances as possible, reusing them for all operations rather than creating a new one per operation. But it still represents resources, so it implements IDisposable for cleaning up after it if there's a time when you need to do that.

You can draw a parallel with SqlConnection which is also IDisposable and uses a connection pool under the covers to get reuse but that doesn't bleed into user code. You're never told to keep the SqlConnection around as a singleton and not to dispose it. So one concrete change that could be made would be to drop whatever affinity we have with the HttpClient instance and use an underlying pool/state/store to cache things.

@clrjunkie
Copy link

@roji Your comments here suggest to me that you have a limited understanding of the HTTP Server echo-system and the problem domain and this not the place to extend the discusion beyond what people involved in this space are already aware of. Now while everyone are free to make their point, respond, and challenge others, I ask you not to "declare" what I personaly think or not think! Furthermore, you are not a Microsoft spokes person, roadmaps plans can all be subject to change. Only MS is i the position to talk about it.

@benaadams
Copy link
Member

Actually, this distinction, in the context of .NET, is something that I find hard to understand. Who has the motivation to re-implement the BCL and not reuse Microsoft’s implementation.

Microsoft have reimplemented it many times (part of the problem); Mono, Unity; Xamarin on Mac, iOS, Android, Samsung for Tizen

@roji
Copy link
Member

roji commented Jul 20, 2017

Your comments here suggest to me that you have a limited understanding of the HTTP Server echo-system and the problem domain and this not the place to extend the discusion beyond what people involved in this space are already aware of

My last comment said almost nothing HTTP, but rather about the value of discussing the logic of .NET Standard, and about the pros and cons of bundling vs. unbundling a major component in .NET Standard. If you actually have something concrete to say (as opposed to a very vague accusation of me not knowing what I'm talking about), I'd be glad to hear it.

Now while everyone are free to make their point, respond, and challenge others, I ask you not to "declare" what I personaly think or not think!

I've reread my comment and I have no idea where I declared what you think or don't. I understand what you're saying, it's just that your arguments make little sense to me.

Furthermore, you are not a Microsoft spokes person, roadmaps plans can all be subject to change. Only MS is i the position to talk about it.

Of course. But this is a community, and you've hijacked a thread about the networking stack to vent out your rants about .NET Standard not making sense, and about how things that aren't bundled into it should be bundled into it. You're simply off-topic.

@clrjunkie
Copy link

@benaadams

Microsoft have reimplemented it many times (part of the problem); Mono, Unity; Xamarin on Mac, iOS, Android, Samsung for Tizen

Is'nt the .NET Core shared code base the solution?

@clrjunkie
Copy link

@roji

and you've hijacked a thread about the networking stack to vent out your rants about .NET Standard not making sense,

Well, excuse me ..you know, sometimes thing are closely related, if you don't see it doen't mean there is no place for it. Anyway I haven't noticed you posted anything here on any other networking topic on the list! Nobody is prohibiting you to start a new topic.What’s your problem?

@roji
Copy link
Member

roji commented Jul 20, 2017

As the tone of this discussion is rapidly deteriorating, I'd say it's time for someone from Microsoft to weigh in and decide whether there's value in discussing these proposals, i.e.:

  1. The short-term abolishing of .NET Standard
  2. The inclusion of an HTTP server API in .NET Standard (or into the .NET BCL)

@benaadams
Copy link
Member

benaadams commented Jul 20, 2017

@> What/Where exactly is the Kestrel API Surface? How can one use it without the WebHost abstraction?

It uses the Microsoft.AspNetCore.Hosting.Server.Abstractions interfaces which are the onerous interfaces:

interface IServer : IDisposable
{
    IFeatureCollection Features { get; }
    Task StartAsync<TContext>(IHttpApplication<TContext> application, CancellationToken cancellationToken);
    Task StopAsync(CancellationToken cancellationToken);
}

IHttpApplication and TContext is either defined by you, or WebHost sets it up to be something that creates an HttpContext with Request and Response etc

interface IHttpApplication<TContext>
{
    TContext CreateContext(IFeatureCollection contextFeatures);
    Task ProcessRequestAsync(TContext context);
    void DisposeContext(TContext context, Exception exception);
}

But you can grab the components via the Features collection of IServer with the ones Kestrel implementing directly being IHttpRequestFeature, IHttpResponseFeature, IHttpUpgradeFeature, IHttpConnectionFeature, IHttpRequestLifetimeFeature, IHttpRequestIdentifierFeature, IHttpBodyControlFeature, IHttpMaxRequestBodySizeFeature, IHttpMinRequestBodyDataRateFeature, IHttpMinResponseDataRateFeature. Other things like caching, compression, SSL/TLS, Websockets, IIS integration, logging, authentication, file serving, MVC and even Routing are optional addins further up-stack.

WebHost details with reading stuff from configs; setting up a easy HttpContext api to use, adding instrumentation and diagnostics (if switched on) integrating any of the optional components you've added etc. It also sets up the "middleware pipeline"; which sounds more complex than it is; as its a set of functions that get called in order; e.g. do you want auth to run before file serving, caching to run after then routing?

The middleware part allows them to do a little more than a straight function using their constructors, where they can specify the components they are dependent on e.g. does it need to be provided the common logging method to allow unified logging? However you don't need to specify any middleware (such as authentication, compression, logging etc) and it won't set them up.

How much extra does WebHost and other middleware add? Well the plain text Techempower tests are set up with the MVC tests also, so have the whole shebang set up and configured in the same app and Kestrel still does pretty well.

If you want to do it all without WebHost you can rummage around in Kestrel's tests and go through the steps of setting something up that's very similar to WebHost anyway.

What I and others have pointed out

  1. Its simple to create a wrapper library on WebHost that gives you the api you like; so it only needs to be done once.
  2. You can switch servers in ASP.NET Core while maintaining the same higher level code; so you while its slower you can take advantage of http.sys port sharing, windows auth etc. by using HttpSysServer instead of Kestrel; and the same is same for a 3rd party server (we were working on our own server, before deciding to contribute to Kestrel directly)
  3. How Kestrel implements its parts is componentized and switchable; there's a networking layer for libuv and a newer one only using managed sockets, I've been working on a 3rd that uses Windows Registered I/O and you can choose which one it uses programatically or by configuration. Same with http parsing.
  4. The strong layered contracts mean if you want to add an additional feature; like websockets (middleware) adding it means it works on all possible servers and configurations with no changes and only one implementation.
  5. ASP.NET Core is much faster than HttpListerner; even with every bell and whistle added; which are all completely optional.
  6. ASP.NET Core by being on .NET Standard but not part of .NET Standard means it already works on Core, Full framework and Mono.
  7. Reimplementing HttpListener in pure managed code would break compatibility with historic .NET Framework; and compat with previous versions is King and Queen; so this would be unlikely.
  8. You can drop WebHost if you want, it just means you need to perform some of the work WebHost is doing for you (including constructing the HttpContext from the items provided by the server).
  9. Adding a major component like an entirely new Http server implementation to .NET Standard means it has to come to Full framework at some point; which as I understand it would need Windows approval and would likely take years to integrate and test something so big; as well as meaning it will be force pushed out to 1 billion devices when it happens - so this is a tall ask - especially when
  10. There is already a new fast cross-platform server, you just need to reference it.

What I'm interpreting from your responses is

  1. You really don't like the branding "ASP.NET Core"
  2. You'd would prefer if it was absorbed under System.*
  3. You want a single prescriptive .NET way without any options or choice in setup

@clrjunkie
Copy link

clrjunkie commented Jul 20, 2017

@benaadams Apparently you're holding a parallel discussion on the topic via twitter, therefore I suggest you reach out to your followers for future feedback on this topic as I will not be commenting anymore.

@davidfowl You’re right, my arguments are not “Technical” per-se. They are “Architectural”. But thanks for sharing your thoughts.. saved me precious time!!

Good Luck!

@clrjunkie
Copy link

"The Server APIs project will provide core capabilities in areas such as networking and security so Swift programs no longer need to frequently rely on platform-specific C libraries to provide this functionality. As a result, developers will be able to create frameworks and server applications using pure-Swift code, without the need to also have systems programming skills and knowledge of multiple platforms."

"HTTP and WebSockets: Provide low level HTTP parsing, including HTTP, HTTP/2 and WebSocket support making it possible, in conjunction with the security and networking APIs, to create secure HTTP and WebSocket servers."

https://swift.org/server-apis/

@mconnew
Copy link
Member

mconnew commented Jul 24, 2017

@clrjunkie, there are two reasons I'm aware of why HTTP.SYS (and HttpListener by extension) exists. First is so that different applications on a machine can all service http requests on the same port(s). The second is to offload Windows authentication to HTTP.SYS. As it's a driver, it runs with system privileges. This is important when using Kerberos authentication, as only when running with system privileges can a server use the default HTTP SPN. If you need either of those, using a user mode HTTP stack won't work for you and you need to be using HTTP.SYS. .Net Core is cross platform which means it can't use HTTP.SYS on non Windows platforms. HTTP.SYS also has capabilities that other HTTP stacks won't have, and those stacks will have features that HTTP.SYS doesn't have. This means you can't design an api into netstandard/netcore which exposes those HTTP.SYS specifics. If I were to build an HTTP server on top of swift, it won't be able to authenticate Kerberos users unless I run the whole process as a system user. Sure, you could create a class written in swift which wraps the HTTP.SYS api's and provides this capability, but then you aren't using the built in server.

@clrjunkie
Copy link

@mconnew Interesting point about Kerberos, it's been a while since I've used it.. Nevertheless I think the initial question with respect to that is whether Kerberos Authentication is a .NET Standard requirement?

As far as I recall there is a Kerberos Authentication in HttpWebRequest as well. How is that supported in .NET Standard? How would that be supported by a .NET Standard implementation on Linux?

https://docs.microsoft.com/en-us/dotnet/api/system.net.httplistener?view=netstandard-2.0

Also, since work on HttpListener is fairly new I wonder if the decision to add it was in response to customers asking for the Kerberos support..

BTW, Isn't NegotiateStream supposed to handle this in user mode?

https://msdn.microsoft.com/en-us/library/windows/desktop/aa363764(v=vs.85).aspx

With respect to port share, as I wrote previously it's all about making trade-offs and I believe for those scenarios an IIS Proxy setup is a viable workaround, heck maybe even for Kerberos!!

I would agree in general that API compat is King & Queen.

That is of course until “Winter comes” !

About Transactional NTFS

“[Microsoft strongly recommends developers utilize alternative means to achieve your application’s needs. Many scenarios that TxF was developed for can be achieved through simpler and more readily available techniques. Furthermore, TxF may not be available in future versions of Microsoft Windows. For more information, and alternatives to TxF, please see Alternatives to using Transactional NTFS.]”

https://msdn.microsoft.com/en-us/library/windows/desktop/aa363764(v=vs.85).aspx

So Assuming Kerberos/Port Share an absolute MUST API, I would say .NET FULL FX - ONLY.

@mconnew
Copy link
Member

mconnew commented Jul 25, 2017

@clrjunkie, when using Kerberos authentication, both ends have an identity. The client identity is usually your user account which is the ambient security context when using HttpWebRequest. When HttpWebRequest requests a Kerberos ticket to access a service, it has to provide the identity of the remote system it is communicating with. The ticket it receives is tied to the remote service. When you send that ticket to the remote service, only a process with permissions to the identity used to obtain the ticket can verify it. The default spn (HTTP/hostname in the case of HTTP) isn't usable except by a system account (System or Network Service). This means a user process can't verify a Kerberos token issued for HTTP/hostname as user accounts don't have permission to that SPN. HTTP.SYS allows a user process a way to authenticate via Kerberos as it can do the authentication on your behalf as it's a kernel mode driver. This means swift and any other user mode HTTP implementation can not authenticate using Kerberos unless your process is running as a system account, which is a bad idea. So basically, if you want to authenticate using Kerberos, you either have to have a process running in a system account or use HTTP.SYS. NegotiateStream allows the client to specify an arbitrary SPN for the remote end, which can even be a UPN. So if your service is running as the non-privileged user foo@contoso.com, the client end provides the remote identity UPN of foo@contoso.com to NegotiateStream which in turn obtains a ticket for your current identity which can be verified by foo@contoso.com so everything works.

@Drawaes
Copy link
Contributor

Drawaes commented Jul 25, 2017

Isn't it true though that is the default spn permissions you can of course delegate spn permissions to any account. If that isn't the case I am not sure how 50% of my apps work :)

@mconnew
Copy link
Member

mconnew commented Jul 25, 2017

@Drawaes, I glossed over a few details. The machine account is identified as HOST/hostname, the HTTP service class SPN by default is aliased to HOST/hostname. You can use the setspn commandline tool to change which account the HTTP service class is aliased to. So you can set HTTP/hostname to be an alias of foo@contoso.com which means when the client requests a ticket for HTTP/hostname, it is actually granted a ticket for foo@contoso.com which can then be used by the user process. But this means now only that user is able to authenticate Kerberos authenticated HTTP requests to HTTP/hostname. IIS won't be able to authenticate any requests unless you change the app pool identity to use the same user. If you didn't use setspn, then you might have your app configured to use "Windows Authentication", which means Negotiate. Negotiate goes through (negotiates) a list of authentication mechanisms, which in practice means try Kerberos, if that doesn't work, try NTLM. Often people are falling back to using NTLM without knowing.

@Drawaes
Copy link
Contributor

Drawaes commented Jul 25, 2017

In practice I never use the Http/hostname anyway :) all my apps are behind loadbalancers with a DNS per app anyway.. but yeah it can be an issue if you stop other apps using it. Anyway this isn't my fight as we are moving away from Kerb apart from Client -> frontend web boxes and moving to server/client TLS certs for server to server.

@clrjunkie
Copy link

@mconnew

This means swift and any other user mode HTTP implementation can not authenticate using Kerberos unless your process is running as a system account, which is a bad idea.

That’s not entirely accurate. While I totally agree that running a Server process as “System” is a big NO NO, running it as “Network Service” allows Kerberos communication (as you mentioned) and is a legitimate setup (I would argue that “Network Service” was invented for that purpose). There is a BIG difference between a “System” account and “Network Service” account where the latter has no Administrator privileges. Also, running a process under “Network Service” is a popular configuration choice for many Microsoft Server products, see SQL Database Engine:

https://docs.microsoft.com/en-us/sql/database-engine/configure-windows/register-a-service-principal-name-for-kerberos-connections

Having said that, I would suggest to exclude Swift from this particular discussion so as to not steer away from the central question which is: Assuming we go along with a new implementation for HttpListener, how would we maintain backwards compatibility with respect to Kerberos Authentication.

The way I see it the primary issue is that currently HTTP.SYS calls certain Windows API’s to have Windows do the Kerberos authentication where in a new managed implementation those API's would need to be called directly. So assuming Kerberos Authentication is NOT a .NET Standard requirement (e.g It's a Windows only requirement) and given we really don’t know how many/if any .NET HttpListener application use Kerberos, it may be worth to consider an initial release (.NET Core Only) which does not support it and implement it if there is customer push-back. With respect to sharing the implementation with FULL .NET FX, here it might make sense to have both implementations and allow users to select either one via an App.Config configuration setting.

@Drawaes
Copy link
Contributor

Drawaes commented Jul 26, 2017

The windows Api's in question are Schannel the same as used today for TLS on windows in corefx. They are a piece of cake to implement and I have done so to make Kerberos work with "raw" kestrel. The interface is also very similar to GASPI (I think that is the acronym but on a beach right now so not going to bother looking it up) on *nix and I have support for Kerberos on linux. It's not a windows specific technology.

@clrjunkie
Copy link

Great!!

@clrjunkie
Copy link

Here is an example of what I would like to see as part of the .NET Core BCL, but based on a high-performance user-mode HttpListener.

https://github.com/clrjunkie/Kalinda

@clrjunkie
Copy link

After reading the issue again, I suspect a terminology trap which admittedly I fell into on one or more occasions. I wish to clarify. Windows uses the term “HTTP Server Api” to describe something quite different from what’s commonly referred to by Go, NodeJS and others, hence the trap. What Windows refers to as “HTTP Server Api” are HTTP Request / Response Api's that are not tied to any particular threading pattern where others use the term “HTTP Server” to describe an Api that dispatches incoming HTTP Requests to users code. In familiar terms they offer “Windows HTTP Server Api” style functionality + thread management for dispatching requests to user handlers. So for lack of a better term I call the Go/NodeJS HTTP Server offering: “HTTP Server Handler”.

In .NET the "HttpListener" class simply exposes the “Windows HTTP Server Api” in OOP form, so in essence "HttpListener" IS the "Windows HTTP Server Api” equivalent in .NET

So to summarize: I propose that .NET Core BCL include an “HTTP Server Handler” built on a newly implemented “HttpListener” having the same "Windows HTTP Server API" semantics without any ASP.NET abstractions. I see no reason why this new “HttpListener” not be based on Kestrel internal implementation. However, if good arguments are made against being bound to "HttpListener" existing Api surface I would argue for a new “.NET HTTP Server Api” (also based on Kestrel) to use as the underlying shared-code base for the “Legacy HttpListener” and for a new “HTTP Server Handler”.

Furthermore, I would suggest discussing HttpListener’s Api continued viability for different use cases using the project I linked to. I know beauty is in the eyes of the beholder and I’m not trying to force personal taste on anyone or promote my own abstraction but I do think it can serve as solid reference during a technical debate on what’s good or bad about HttpListener Api surface. With respect to legalities: This is my own work period. I wrote it before knowing anything about NodeJS or Go. I do not want/need any sort of credit or implied credit and I have no problem contributing the project code to the .NET foundation as a sample showing various use-cases around HttpListener, in which case I would prefer having my alias removed from the project source.

With respect to ASP.NET/WebHost, as I mentioned before I have no opinion about that, actually it appears that at least in Java land, Web Frameworks which work with different "HTTP Server Handlers" are a common thing.

@VladimirAkopyan
Copy link

I get where @clrjunkie is coming from.
The idea is that it should be easy to build applications that can talk to each-other, which are not primarily servers - console / gui/ whatever applications.
As it stands, ASP + kestrel carry quite a lot of stuff you have to understand, like kestrel's threadpool, etc.
All the guidance instructs you to use them as frameworks, which means my application is "obeys asp's rules". It's clear that @clrjunkie is a bit lost in ASP + kestrel and does not understand how to peel away layers he does not need, and it's kind of similar for me.

It's not a technical problem, it's a library vs framework and developer understanding problem.
@benaadams the library you linked would be the kind of thing some folks would find helpfull.

@krispenner
Copy link

I'm not sure the format here, is anyone just adding their suggestions to this? In another post @davidsh suggested to post here.

If you would like to raise this as a new design issue/discussion, please contribute to dotnet/designs#9

I would like to comment on #23422 which is now closed - not sure if you will see my comment on there.

Using WebClient or HttpRequest with auto follow redirects enabled throw exceptions when the redirection is considered a security downgrade such as https > http. However this seems to be more common than expected where a user requests http and gets redirected to https and then back to http (Yahoo among others). WebClient was meant to be very simple and quick to download resources from the web and it can't follow some simple redirects in .NET Core due to this restriction even when the user was not asking for https. Would it not possible to store the user's original URL requested and if the scheme was http initially then you can follow any https > http redirects that come up along the redirect pipeline as the user was never wanting https in the first place so I don't see this being a security risk. This would fix a lot of issues dev's are experiencing with this. Thoughts?

Cheers

@alexwiese
Copy link

Are there any plans to support QUIC?

@shaggygi
Copy link
Contributor

shaggygi commented Nov 6, 2017

Referencing https://github.com/dotnet/corefx/issues/24742 since it seems like in the same bucket.

@karelz
Copy link
Member Author

karelz commented Nov 6, 2017

@alexwiese QUIC fits into Emerging Technology section and was brought to our attention earlier, updating top post to list it.

Currently we are focusing on first 2 sections - Foundations (Sockets, SSL) and Web Stack (ManagedHandler). https://github.com/dotnet/corefx/issues/24742 tracks our plans for .NET Core 2.1 milestone (via ZenHub Epics and dependencies).

@Dotnet-GitSync-Bot
Copy link
Collaborator

I couldn't figure out the best area label to add to this issue. If you have write-permissions please help me learn by adding exactly one area label.

@Dotnet-GitSync-Bot Dotnet-GitSync-Bot added the untriaged New issue has not been triaged by the area owner label Oct 16, 2020
@terrajobst terrajobst transferred this issue from dotnet/designs Oct 16, 2020
@ghost ghost locked as resolved and limited conversation to collaborators Dec 22, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
untriaged New issue has not been triaged by the area owner
Projects
None yet
Development

No branches or pull requests