mzabani / Fos

FastCgi Server designed to run Owin applications side by side with a FastCgi enabled web server.
BSD 2-Clause "Simplified" License
62 stars 12 forks source link

FOS is not compatible with IIS #10

Open mikdav opened 6 years ago

mikdav commented 6 years ago

IIS has two options for FastCGI - named pipes and TCP. FOS supports unix named pipes and TCP. However, the way that IIS uses TCP is not compatible with the way that FOS uses TCP.

In the case of named pipes, IIS creates a named pipe and passes it to the FastCGI process as StdIn. The FastCGI process is then expected to duplicate the handle and use the pipe for reading/writing.

In the case of TCP, IIS opens a transient port and then passes a handle to the FastCGI process also as StdIn. The FastCGI process is then expected to duplicate the handle and use it for read/writing. IIS will not connect to a FastCGI process listening on a specific port.

A possible fix would be to add a BindToIisStdIn method to SocketListener that would pull the correct handle/socket from StdIn in order to communicate with IIS.

mzabani commented 6 years ago

I once searched for ways to make Fos/FastCgi work with IIS, but I honestly can't remember finding any good info on this; you seem to be much more aware of how it works. Do you have any links to some good reading material on this?

mikdav commented 6 years ago

I have been working on this one for the last couple of days since our organization generally prefers IIS. We're a mostly Windows shop so nginx/mono isn't really our thing, though I currently have my changes working with nginx. We have an external component that is not thread-safe and needs to be used in a web application. So unfortunately ASP.NET doesn't work for us--which is how I landed on your project.

It appears the best way to do this in C# is to P/Invoke to get the handle from StdIn and use that to open a FileSteam because unfortunately the .Net Socket API doesn't allow creating sockets from a handle. I see the .net core team has a work item to allow this, but it hasn't moved for a while. So I've been reading through the Fos/FastCGI code trying to decide what the most surgical change would be to support this. However, the approaches I have tried so far I do not like because they will require a lot of code churn. There are two problems:

  1. The Fos/FastCGI code is very socket oriented. It appears to expect to accept connections for each new record. It maintains a dictionary of open sockets to records and reads them all in a loop. A FileStream would not have this mapping of connections to records.

  2. A FileStream would be a continuous stream and would require logic to split the incoming records from each other.

mzabani commented 6 years ago

Wow, IIS seems really strange! However, I'd certainly love to get it working with Fos. The main difference - and you said it yourself - is that Fos does one Socket per Request (that's how the servers I worked with do it anyways), while with IIS we'd have to multiplex connections over a single communication channel.

Before we delve into this we must really understand how IIS does this, because if multiple requests are multiplexed over a single channel, any FastCGI record may come in anytime, so we'd have to parse incoming FastCGI records and index our Requests by their Ids. This should probably work with Sockets as well, with just one possible exception: Maybe data comes through the sockets in chunks so small (or so fragmented) that it's not even possible to obtain the RequestId of the next Record, so we don't know which request it belongs to, leading to a big problem.

This problem is most likely the reason (although I can't remember for sure) why I indexed Requests per Socket. I believe I even have unit tests that feed the main loop byte per byte to test if this works.