Jetty Logo
Contact the core Jetty developers at www.webtide.com

private support for your internal/customer projects ... custom extensions and distributions ... versioned snapshots for indefinite support ... scalability guidance for your apps and Ajax/Comet projects ... development services from 1 day to full product delivery

Configuring SPDY Proxy

Configuring SPDY by Example
An Example Configuration for a SPDY to HTTP Proxy

Configuring SPDY by Example

spdy-jetty-http provides a fully functional SPDY proxy server out of the box. Jetty's SPDY proxy can receive SPDY (currently v2/v3) and HTTP requests, and proxy those requests to other SPDY servers. If necessary, an implementation of the Proxy Engine class translates the incoming protocol to a protocol the target host understands. Currently we provide a SPDYProxyEngine that can talk SPDY v2 and SPDY v3. We plan to support other protocols soon. As always, contributions are welcome.

Configuring SPDY is straightforward, as the following example shows. The example server has a plain SPDY connector listening on port 9090 and a SPDY proxy connector listening on port 8080. Incoming requests to port 8080 are proxied and translated to the connector listening on port 9090. In real world scenarios you more likely proxy to a different host.

                

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure.dtd">

    <Configure id="Server" class="org.eclipse.jetty.server.Server">

        <New id="sslContextFactory" class="org.eclipse.jetty.util.ssl.SslContextFactory">
            <Set name="keyStorePath">src/main/resources/keystore.jks</Set>
            <Set name="keyStorePassword">storepwd</Set>
            <Set name="trustStore">src/main/resources/truststore.jks</Set>
            <Set name="trustStorePassword">storepwd</Set>
            <Set name="protocol">TLSv1</Set>
        </New>

        <!--
        <Set class="org.eclipse.jetty.npn.NextProtoNego" name="debug" type="boolean">
    true</Set>
        -->

        <!--
        This is the upstream server connector. It speaks non-SSL SPDY/2(HTTP) on port 9090.
        -->
        <Call name="addConnector">
            <Arg>
                <New class="org.eclipse.jetty.spdy.http.HTTPSPDYServerConnector">
                    <Set name="Port">9090</Set>
                    <Set name="defaultAsyncConnectionFactory">
                        <Call name="getAsyncConnectionFactory">
                            <Arg>spdy/2</Arg>
                        </Call>
                    </Set>
                </New>
            </Arg>
        </Call>

        <!--
        This ProxyEngine translates the incoming SPDY/x(HTTP) request to SPDY/2(HTTP)
        -->
        <New id="spdyProxyEngine" class="org.eclipse.jetty.spdy.proxy.SPDYProxyEngine">
            <Arg>spdy/2</Arg>
            <Arg>
                <New class="org.eclipse.jetty.spdy.SPDYClient$Factory">
                    <Call name="start"/>
                </New>
            </Arg>
        </New>

        <!--
        The ProxyEngineSelector receives SPDY/x(HTTP) requests from proxy connectors below
        and is configured to process requests for host "localhost".
        Such requests are converted from SPDY/x(HTTP) to SPDY/2(HTTP) by the configured ProxyEngine
        and forwarded to 127.0.0.1:9090, where they are served by the upstream server above.
        -->
        <New id="proxyEngineSelector" class="org.eclipse.jetty.spdy.proxy.ProxyEngineSelector">
            <Call name="putProxyEngine">
                <Arg>
                    <Ref id="spdyProxyEngine"/>
                </Arg>
            </Call>
            <Set name="proxyServerInfos">
                <Map>
                    <Entry>
                        <Item>localhost</Item>
                        <Item>
                            <New class="org.eclipse.jetty.spdy.proxy.ProxyEngineSelector$ProxyServerInfo">
                                <Arg type="String">spdy/2</Arg>
                                <Arg>127.0.0.1</Arg>
                                <Arg type="int">9090</Arg>
                            </New>
                        </Item>
                    </Entry>
                </Map>
            </Set>
        </New>

        <!--
        These are the reverse proxy connectors accepting requests from clients.
        They accept non-SSL (on port 8080) and SSL (on port 8443) HTTP,
        SPDY/2(HTTP) and SPDY/3(HTTP).
        Non-SPDY HTTP requests are converted to SPDY internally and passed to the
        ProxyEngine above.
        -->
        <Call name="addConnector">
            <Arg>
                <New class="org.eclipse.jetty.spdy.proxy.HTTPSPDYProxyConnector">
                    <Arg>
                        <Ref id="proxyEngineSelector"/>
                    </Arg>
                    <Set name="Port">8080</Set>
                </New>
            </Arg>
        </Call>
        <Call name="addConnector">
            <Arg>
                <New class="org.eclipse.jetty.spdy.proxy.HTTPSPDYProxyConnector">
                    <Arg>
                        <Ref id="proxyEngineSelector"/>
                    </Arg>
                    <Arg>
                        <Ref id="sslContextFactory"/>
                    </Arg>
                    <Set name="Port">8443</Set>
                </New>
            </Arg>
        </Call>

    </Configure>
  
            

Let's take this apart:

                
    <!--
    This ProxyEngine translates the incoming SPDY/x(HTTP) request to SPDY/2(HTTP)
    -->
    <New id="spdyProxyEngine" class="org.eclipse.jetty.spdy.proxy.SPDYProxyEngine">
        <Arg>spdy/2</Arg>
        <Arg>
            <New class="org.eclipse.jetty.spdy.SPDYClient$Factory">
                <Call name="start"/>
            </New>
        </Arg>
    </New>

    This is the ProxyEngine configuration. It is a SPDYProxyEngine that can translate to SPDY v2 as
    configured above. If your target host is capable of speaking SPDY v3, you change the first constructor argument
    to <code>spdy/3.</code> If you have different target hosts speaking different protocols, you configure multiple proxy
    engines and feed them to the ProxyEngineSelector as follows.

    <!--
    The ProxyEngineSelector receives SPDY/x(HTTP) requests from proxy connectors below
    and is configured to process requests for host "localhost".
    Such requests are converted from SPDY/x(HTTP) to SPDY/2(HTTP) by the configured ProxyEngine
    and forwarded to 127.0.0.1:9090, where they are served by the upstream server above.
    -->
    <New id="proxyEngineSelector" class="org.eclipse.jetty.spdy.proxy.ProxyEngineSelector">
        <Call name="putProxyEngine">
            <Arg>
                <Ref id="spdyProxyEngine"/>
            </Arg>
        </Call>
        <Set name="proxyServerInfos">
            <Map>
                <Entry>
                    <Item>localhost</Item>
                    <Item>
                        <New class="org.eclipse.jetty.spdy.proxy.ProxyEngineSelector$ProxyServerInfo">
                            <Arg type="String">spdy/2</Arg>
                            <Arg>127.0.0.1</Arg>
                            <Arg type="int">9090</Arg>
                        </New>
                    </Item>
                </Entry>
            </Map>
        </Set>
    </New>
  
            

This is the ProxyEngineSelector. The ProxyEngineSelector keeps the configurations for the known target hosts and also chooses the right ProxyEngine for the protocol the target host speaks.

Let's take even smaller parts of the snipplet above to explain them in detail:

                
    <Call name="putProxyEngine">
        <Arg>
            <Ref id="spdyProxyEngine"/>
        </Arg>
    </Call>
  
            

This adds the SPDYProxyEngine configured above to the ProxyEngineSelector. The SPDYProxyEngine is configured to translate to spdy/2. By adding it to the Selector, it now knows how to translate to spdy/2.

                
    <Set name="proxyServerInfos">
        <Map>
            <Entry>
                <Item>localhost</Item>
                <Item>
                    <New class="org.eclipse.jetty.spdy.proxy.ProxyEngineSelector$ProxyServerInfo">
                        <Arg type="String">spdy/2</Arg>
                        <Arg>127.0.0.1</Arg>
                        <Arg type="int">9090</Arg>
                    </New>
                </Item>
            </Entry>
        </Map>
    </Set>
  
            

You configure target hosts and the protocol you want to communicate with them by adding so-called ProxyServerInfos. Key for the map is the hostname. You configure protocol, host, and port for the ProxyServerInfo.

Request flow with the proxy given above:

  • Incoming SPDY Request to https://localhost:8443/ reaches the HTTPSPDYProxyConnector listening on port 8443.

  • HTTPSPDYProxyConnector forwards the request to the ProxyEngineSelector.

  • ProxyEngineSelector reads the Host header's host portion: "localhost".

  • ProxyEngineSelector looks up the host in its ProxyServerInfo mappings. It finds the matching entry, "localhost". (If there is no matching entry it rst the stream).

  • ProxyEngineSelector looks up a ProxyEngine that matches the protocol configured in the ProxyServerInfo it found in the last step and forwards the request to that ProxyEngine.

  • The ProxyEngine translates the request to the given target protocol and proxies it to the target host.

  • All responses are forwarded to the client.

An Example Configuration for a SPDY to HTTP Proxy

spdy-jetty-http provides full proxy functionality as described above. Here's another example configuration for a SPDY to HTTP proxy. This proxy accepts SPDY requests and proxies them to an HTTP server.

This is a very common use case, for example to terminate SPDY on a frontend server when you need to talk plain HTTP to your backend, because either your network hardware needs to inspect HTTP content or your backend is unable to talk SPDY. You have the performance advantages of SPDY over the slow internet with high latencies, and you talk HTTP to your backend as needed.

                

  <?xml version="1.0" encoding="UTF-8"?>
  <!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd">

  <!-- ============================================================= -->
  <!-- Configure the Jetty Server instance with an ID "Server"       -->
  <!-- by adding a SPDY connector.                                   -->
  <!-- This configuration must be used in conjunction with jetty.xml -->
  <!-- It should not be used with jetty-https.xml as this connector  -->
  <!-- can provide both HTTPS and SPDY connections                   -->
  <!-- ============================================================= -->
  <Configure id="Server" class="org.eclipse.jetty.server.Server">

    <!-- =========================================================== -->
    <!-- Set up the SSL Context factory used to establish all TLS     -->
    <!-- Connections and session.                                    -->
    <!--                                                             -->
    <!-- Consult the javadoc of o.e.j.util.ssl.SslContextFactory     -->
    <!-- o.e.j.server.HttpConnectionFactory for all configuration    -->
    <!-- that may be set here.                                       -->
    <!-- =========================================================== -->
    <New id="sslContextFactory" class="org.eclipse.jetty.util.ssl.SslContextFactory">
      <Set name="KeyStorePath"><Property name="jetty.home" default="." />/etc/keystore</Set>
      <Set name="KeyStorePassword">OBF:1vny1zlo1x8e1vnw1vn61x8g1zlu1vn4</Set>
      <Set name="KeyManagerPassword">OBF:1u2u1wml1z7s1z7a1wnl1u2g</Set>
      <Set name="TrustStorePath"><Property name="jetty.home" default="." />/etc/keystore</Set>
      <Set name="TrustStorePassword">OBF:1vny1zlo1x8e1vnw1vn61x8g1zlu1vn4</Set>
    </New>

    <!-- =========================================================== -->
    <!-- Enables NPN debugging on System.err                         -->
    <!-- ===========================================================
    <Set class="org.eclipse.jetty.npn.NextProtoNego" name="debug" type="boolean">true</Set>
    -->

    <!-- =========================================================== -->
    <!-- Create a TLS specific HttpConfiguration based on the        -->
    <!-- common HttpConfiguration defined in jetty.xml               -->
    <!-- Add a SecureRequestCustomizer to extract certificate and    -->
    <!-- session information                                         -->
    <!-- =========================================================== -->
    <New id="tlsHttpConfig" class="org.eclipse.jetty.server.HttpConfiguration">
      <Arg><Ref refid="httpConfig"/></Arg>
      <Call name="addCustomizer">
        <Arg><New class="org.eclipse.jetty.server.SecureRequestCustomizer"/></Arg>
      </Call>
    </New>

    <!-- =========================================================== -->
    <!-- This is the upstream server connector.                      -->
    <!-- It speaks HTTP on port 9090.                                -->
    <!-- =========================================================== -->
    <Call name="addConnector">
      <Arg>
        <New class="org.eclipse.jetty.server.ServerConnector">
          <Arg name="server"><Ref id="Server" /></Arg>
          <Arg name="factories">
            <Array type="org.eclipse.jetty.server.ConnectionFactory">
              <Item>
                <New class="org.eclipse.jetty.server.HttpConnectionFactory">
                  <Arg name="config"><Ref id="httpConfig" /></Arg>
                </New>
              </Item>
            </Array>
          </Arg>
          <Set name="host"><Property name="jetty.host" /></Set>
          <Set name="port"><Property name="jetty.port" default="9090" /></Set>
          <Set name="idleTimeout">30000</Set>
        </New>
      </Arg>
    </Call>

  <!-- =========================================================== -->
  <!-- This ProxyEngine translates the incoming SPDY/x(HTTP)       -->
  <!-- requests to HTTP                                            -->
  <!-- =========================================================== -->
  <New id="httpProxyEngine" class="org.eclipse.jetty.spdy.server.proxy.HTTPProxyEngine">
    <Arg>
      <New class="org.eclipse.jetty.client.HttpClient">
        <Call name="start"/>
      </New>
    </Arg>
  </New>

  <!-- =========================================================== -->
  <!-- The ProxyEngineSelector receives SPDY/x(HTTP) requests      -->
  <!-- from proxy connectors below and is configured to process    -->
  <!-- requests for host "localhost".                              -->
  <!-- Such requests are converted from SPDY/x(HTTP) to            -->
  <!-- HTTP by the configured ProxyEngine and forwarded            -->
  <!-- to 127.0.0.1:9090, where they are served by the upstream    -->
  <!-- server above.                                               -->
  <!-- =========================================================== -->
  <New id="proxyEngineSelector" class="org.eclipse.jetty.spdy.server.proxy.ProxyEngineSelector">
    <Call name="putProxyEngine">
      <Arg>http/1.1</Arg>
      <Arg>
        <Ref refid="httpProxyEngine"/>
      </Arg>
    </Call>
    <Set name="proxyServerInfos">
      <Map>
        <Entry>
          <Item>localhost</Item>
          <Item>
            <New class="org.eclipse.jetty.spdy.server.proxy.ProxyEngineSelector$ProxyServerInfo">
              <Arg type="String">http/1.1</Arg>
              <Arg>127.0.0.1</Arg>
              <Arg type="int">9090</Arg>
            </New>
          </Item>
        </Entry>
      </Map>
    </Set>
  </New>

  <!-- =========================================================== -->
  <!-- These are the reverse proxy connectors accepting requests   -->
  <!-- from clients.                                               -->
  <!-- They accept non-SSL (on port 8080) and SSL (on port 8443)   -->
  <!-- HTTP, SPDY/2(HTTP) and SPDY/3(HTTP).                        -->
  <!-- Non-SPDY HTTP requests are converted to SPDY internally     -->
  <!-- and passed to the ProxyEngine above.                        -->
  <!-- =========================================================== -->
  <Call name="addConnector">
    <Arg>
      <New class="org.eclipse.jetty.spdy.server.proxy.HTTPSPDYProxyServerConnector">
        <Arg>
          <Ref refid="Server"/>
        </Arg>
        <Arg>
          <Ref refid="proxyEngineSelector"/>
        </Arg>
        <Set name="Port">8080</Set>
      </New>
    </Arg>
  </Call>
  <Call name="addConnector">
    <Arg>
      <New class="org.eclipse.jetty.spdy.server.proxy.HTTPSPDYProxyServerConnector">
        <Arg>
          <Ref refid="Server"/>
        </Arg>
        <Arg>
          <Ref refid="sslContextFactory"/>
        </Arg>
        <Arg>
          <Ref refid="proxyEngineSelector"/>
        </Arg>
        <Set name="Port">8443</Set>
      </New>
    </Arg>
  </Call>
</Configure>
  
            

See an error or something missing? Contribute to this documentation at Github!