View Javadoc

1   //
2   //  ========================================================================
3   //  Copyright (c) 1995-2012 Mort Bay Consulting Pty. Ltd.
4   //  ------------------------------------------------------------------------
5   //  All rights reserved. This program and the accompanying materials
6   //  are made available under the terms of the Eclipse Public License v1.0
7   //  and Apache License v2.0 which accompanies this distribution.
8   //
9   //      The Eclipse Public License is available at
10  //      http://www.eclipse.org/legal/epl-v10.html
11  //
12  //      The Apache License v2.0 is available at
13  //      http://www.opensource.org/licenses/apache2.0.php
14  //
15  //  You may elect to redistribute this code under either of these licenses.
16  //  ========================================================================
17  //
18  
19  
20  package org.eclipse.jetty.spdy.server.http;
21  
22  import org.eclipse.jetty.io.EndPoint;
23  import org.eclipse.jetty.server.Connector;
24  import org.eclipse.jetty.server.HttpChannelConfig;
25  import org.eclipse.jetty.spdy.api.DataInfo;
26  import org.eclipse.jetty.spdy.api.HeadersInfo;
27  import org.eclipse.jetty.spdy.api.ReplyInfo;
28  import org.eclipse.jetty.spdy.api.Stream;
29  import org.eclipse.jetty.spdy.api.StreamFrameListener;
30  import org.eclipse.jetty.spdy.api.SynInfo;
31  import org.eclipse.jetty.spdy.api.server.ServerSessionFrameListener;
32  import org.eclipse.jetty.spdy.server.SPDYServerConnectionFactory;
33  import org.eclipse.jetty.util.Fields;
34  import org.eclipse.jetty.util.annotation.Name;
35  import org.eclipse.jetty.util.log.Log;
36  import org.eclipse.jetty.util.log.Logger;
37  
38  public class HTTPSPDYServerConnectionFactory extends SPDYServerConnectionFactory implements HttpChannelConfig.ConnectionFactory
39  {
40      private static final String CHANNEL_ATTRIBUTE = "org.eclipse.jetty.spdy.server.http.HTTPChannelOverSPDY";
41      private static final Logger logger = Log.getLogger(HTTPSPDYServerConnectionFactory.class);
42  
43      private final PushStrategy pushStrategy;
44      private final HttpChannelConfig httpChannelConfig;
45  
46      public HTTPSPDYServerConnectionFactory(
47          @Name("version") int version,
48          @Name("config") HttpChannelConfig config)
49      {
50          this(version,config,new PushStrategy.None());
51      }
52  
53      public HTTPSPDYServerConnectionFactory(
54          @Name("version") int version,
55          @Name("config") HttpChannelConfig config,
56          @Name("pushStrategy") PushStrategy pushStrategy)
57      {
58          super(version);
59          this.pushStrategy = pushStrategy;
60          httpChannelConfig = config;
61          addBean(httpChannelConfig);
62      }
63  
64      @Override
65      public HttpChannelConfig getHttpChannelConfig()
66      {
67          return httpChannelConfig;
68      }
69  
70      @Override
71      protected ServerSessionFrameListener provideServerSessionFrameListener(Connector connector, EndPoint endPoint)
72      {
73          return new HTTPServerFrameListener(connector,endPoint);
74      }
75  
76      private class HTTPServerFrameListener extends ServerSessionFrameListener.Adapter implements StreamFrameListener
77      {
78          private final Connector connector;
79          private final EndPoint endPoint;
80  
81          public HTTPServerFrameListener(Connector connector,EndPoint endPoint)
82          {
83              this.endPoint = endPoint;
84              this.connector=connector;
85          }
86  
87          @Override
88          public StreamFrameListener onSyn(final Stream stream, SynInfo synInfo)
89          {
90              // Every time we have a SYN, it maps to a HTTP request.
91              // We can have multiple concurrent SYNs on the same connection,
92              // and this is very different from HTTP, where only one request
93              // can arrive on the same connection, so we need to create an
94              // HttpChannel for each SYN in order to run concurrently.
95  
96              logger.debug("Received {} on {}", synInfo, stream);
97  
98              Fields headers = synInfo.getHeaders();
99              HttpTransportOverSPDY transport = new HttpTransportOverSPDY(connector, httpChannelConfig, endPoint, pushStrategy, stream, headers);
100             HttpInputOverSPDY input = new HttpInputOverSPDY();
101             HttpChannelOverSPDY channel = new HttpChannelOverSPDY(connector, httpChannelConfig, endPoint, transport, input, stream);
102             stream.setAttribute(CHANNEL_ATTRIBUTE, channel);
103 
104             channel.requestStart(headers, synInfo.isClose());
105 
106             if (headers.isEmpty())
107             {
108                 // If the SYN has no headers, they may come later in a HEADERS frame
109                 return this;
110             }
111             else
112             {
113                 if (synInfo.isClose())
114                     return null;
115                 else
116                     return this;
117             }
118         }
119 
120         @Override
121         public void onReply(Stream stream, ReplyInfo replyInfo)
122         {
123             // Do nothing, servers cannot get replies
124         }
125 
126         @Override
127         public void onHeaders(Stream stream, HeadersInfo headersInfo)
128         {
129             logger.debug("Received {} on {}", headersInfo, stream);
130             HttpChannelOverSPDY channel = (HttpChannelOverSPDY)stream.getAttribute(CHANNEL_ATTRIBUTE);
131             channel.requestHeaders(headersInfo.getHeaders(), headersInfo.isClose());
132         }
133 
134         @Override
135         public void onData(Stream stream, final DataInfo dataInfo)
136         {
137             logger.debug("Received {} on {}", dataInfo, stream);
138             HttpChannelOverSPDY channel = (HttpChannelOverSPDY)stream.getAttribute(CHANNEL_ATTRIBUTE);
139             channel.requestContent(dataInfo, dataInfo.isClose());
140         }
141     }
142 }