tomcat-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Konstantin Prei├čer <>
Subject Possible IIS SPDY Redirector for Tomcat
Date Fri, 25 May 2012 16:08:55 GMT
Hello! (this time I hope the e-mail is complete ;-)

Some time ago, I wrote about a possible alternative IIS AJP Connector implementation [1] that
is written in C# and uses the new IIS 7/8 module pipeline, which allows to insert managed
modules (.Net) in the request pipeline.

However, Mladen Turk pointed me to the SPDY protocol which could also be used for server-to-server
communication as a possible replacement for AJP (which was also mentioned in the Thread "SPDY
support" by Costin Manolache).

Since I had some spare time again, I started to try an implementation of an SPDY Client /
Redirector for IIS 7.x/8.x which is also written in C# (using .Net Framework 4.0), which is
based on SPDY Protocol Draft 3 [2]. It is a 3-layered SPDY client with a very basic IIS module
that uses the client to forward requests. You can find the source code at the SVN repo here:
Note that there is a Java part (Eclipse project, it is a workaround to use TLS NPN) and a
.Net part (Microsoft Visual Studio 2010 project). Of course, it still needs a lot of work
to be done (and probably has also a number of bugs ;-) ).

If you like the connector, I would be happy to contribute it to the Apache Software Foundation
(however there currently are some problems which prevent this - see below).

The architecture of that SPDY client / IIS module is the following (each layer has only dependencies
to the layer(s) above):

1. SPDY Connector (protocol)
2. SPDY Processor (multiplexer)
3. SPDY HTTP Processor (HTTP layer)
4. IIS Module (for forwarding requests)

1. "SPDY Connector" implements the SPDY protocol (without HTTP). This means e.g. it has methods
to send specific frames, and it has events that are raised when other specific frames are
received. It does not do any multiplexing. It is intended to be accessed by only 2 different
threads (one for reading and one for writing).

2. "SPDY Processor" uses the SPDY connector and adds multiplexing to it. This means it can
be accessed by several threads to get a SPDY stream and read from it / write to it. The SPDY
Processor serializes these calls to the SPDY Connector.

3. "SPDY HTTP Processsor" adds an HTTP layer to the SPDY processor (e.g. it translates normal
HTTP headers to SPDY ones).

4. "IIS Module" contains a class that implements System.Web.IHttpModule interface so that
it can be inserted into IIS's request pipeline. It is responsible for redirecting HTTP requests
using one or more SPDY HTTP Processors.

This architecture also allows to use the SPDY client as a regular client (without IIS). I
also noticed a "Websockets over SPDY" proposal which I think should not be hard to implement
(IIS 8 supports WebSockets, but I haven't dealt with IIS 8 websockets yet).

However, I got to some problems when I was implementing the SPDY client:

1. .Net has no support for the TLS NPN (next protocol negotiation) extension which is required
by SPDY, and there seems to be no library for supporting it (at least I couldn't find one).
Therefore I had to create a Java TLS tunnel which uses the NPN extension from Jetty [3]. This
is similar to "stunnel" with the addition that it uses NPN to negotiate "spdy/3" as protocol.
You can find it in

2. SPDY uses zlib for header compression. Although .Net has some support for compression in
the System.IO.Compression namespace, it doesn't seem to have support for the operations required
by SPDY (setting a Zlib Dictionary and using SYNC_FLUSH between header frames). (However I
must admit that I don't have much knowledge about these compression technologies, so I might
be wrong).
Therefore I used "ZLIB.NET" [4] which is a managed .Net implementation of zlib. However it
seems to be based on an older version, and I had to hack the code which checks if the correct
dictionary is set (it seemed that the adler32() function computed a wrong value for the dictionary)
for the compression to work. Also, I don't know if the library can be distributed with apache

Note that because of 1., the .Net SPDY client currently doesn't use any SSL/TLS, because it
will connect to the Java NPN tunnel, which negotiates spdy/3 and does the encryption.

I tested the SPDY client with Google servers which use "spdy/3" for some time now. However
I couldn't test it with Tomcat, as it seems that it is currently implementing spdy/2, but
not spdy/3 (please correct me if I'm saying something wrong).

If you would like to test the SPDY client with IIS 7.x (Windows Server 2008 or Windows Server
2008 R2) or IIS 8.x (Windows Server 2012), you would need to do the following:

0. Ensure that the Microsoft .Net Framework 4.0 (Full) is installed. Also ensure that Role
"Webserver (IIS)" with Role Service ".Net Extensibility" is enabled on the server, and that
the IIS application pool which you would like to try the redirector with is using the Framework
4.0 and "Integrated" Managed Pipeline Mode.

1. Compile and run the Java NPN tunnel. When you run it, you need to set the Boot classpath
to the Jetty NPN library, e.g.

2. To use the SPDY IIS module, I recommend to compile it so that the compiled assembly can
be used in IIS. To compile the project, run the following C# Compiler command if the current
directory is the project directory (.../SpdyConnector/.Net/SPDY-Redirector/SPDY_Redirector):

C:\Windows\Microsoft.NET\Framework\v4.0.30319\csc.exe /out:SpdyRedirectorModule.dll /target:library
/define:DEBUG /platform:anycpu /recurse:*.cs

It will generate the assembly "SpdyRedirectorModule.dll" in the current directory. Note that
because .Net is intended to be platform-independent (like Java), the assembly can be used
both on 32 bit and 64 bit environments.

3. Create a "bin" folder in the IIS web application where you would like to use the SPDY client.
E.g. on a default IIS installation, this would be "C:\inetpub\wwwroot". Copy the SpdyRedirectorModule.dll
into that "bin" folder.

4. Open the IIS manager. Navigate to the web application / virtual host where you copied the
file (e.g. "Default Web Site"). Then open the item "Modules".

5. Click on "Add managed module...". In the combobox, type "Preisser.Spdy.SpdyRedirector.IisModule.SpdyHttpIisModule"
(without quotes), and enter a name for it. Make sure "Invoke only for requests to ASP.Net
managed applications etc" is not selected. Then click OK, and when a message appears that
the type could not be found in referenced libraries, click Yes. (Note that on IIS 8, the combobox
should already contain the module, and such a warning should not appear when adding it.)

6. Open a URL like "http://localhost/mail/help/intl/de/tips.html". You should now see a Google
Mail page appear. (It contains several images that are also loaded from localhost).

7. If you close the Java NPN SPDY tunnel and open the URL again, the following text should
HTTP 503
The request could not be served because the remote server was not available.

(when starting the Java NPN Spdy tunnel again, the URL should also work again).

Note that the current SPDY client / redirector supports only basic functionalities (e.g. it
does not support POST requests). The most work probably would need to be done in the IIS module
(to decide which request should be redirected, to also support other HTTP methods besides
GET, etc.). Also, the SPDY client currently doesn't support streams which are initiated by
server, and is not optimized for efficiency.

The .Net SPDY client will connect to "localhost:8443" where it expects the Java NPN SPDY tunnel
to listen. That will establish a connection to "" which supports spdy/3.

Costin Manolache mentioned in the thread "SPDY support" [5] that for SPDY proxy mode to work,
Tomcat would need to read and trust additional information from X- headers, like remote IP
etc. Maybe Tomcat could use a "SPDY proxy mode", that in comparison to "real SPDY mode", allows
to configure if header compression and TLS NPN should be used? (As it would be no real SPDY
used by a Browser, it could be modified in such a way, if the other endpoint (e.g. the IIS
Spdy redirector) also is implemented in that way). This would allow to not require NPN support
so that the IIS SPDY redirector could be used without that Java NPN SPDY tunnel to directly
connect to Tomcat (e.g. using TLS without NPN extension would be supported natively by .Net).

One thing that also came to my mind while experimenting with the SPDY connector, is that the
AJP protocol has a packet "GET_BODY_CHUNK". The server (Tomcat) sends this to the front-end
(Httpd, IIS) so that they send the next request body chunk. If I understood correctly, this
allows Tomcat to send an HTTP response immediately, before reading all the request data. However,
the current SPDY redirector would first send the complete request body to Tomcat/SPDY server,
before reading any response body to send to the client. I guess an additional thread per request
would be needed for that behavior, so that one thread can transfer the request body to the
SPDY server and the other thread can transfer the response body to IIS.

I think when comparing AJP with SPDY as protocol for server-to-server-communication, a major
advantage of SPDY is that only one TCP connection is used for several concurrent HTTP requests.
In AJP, each connection can only serve one request at a time. Also, SPDY allows support for
WebSockets which I don't know if it is possible with AJP.
The SPDY client also supports flow control (which was added in SPDY/3) so that if a slow client
connects to IIS, IIS does not have to buffer the complete request body received by Tomcat
before it can send it to the client, while concurrently serving other HTTP requests over that
SPDY connection (however I didn't test if flow-control correctly works when sending a POST
request to the server).

Note that C# (language) and .Net (Runtime, class libraries) are very similar to Java - so
for anyone who knows Java, it should be easy to follow the C# code of that SPDY client. ;-)

Please let me know what you think.

Konstantin Prei├čer


To unsubscribe, e-mail:
For additional commands, e-mail:

View raw message