View Javadoc

1   //
2   //  ========================================================================
3   //  Copyright (c) 1995-2014 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.http;
21  
22  import java.util.concurrent.Executor;
23  import java.util.concurrent.ScheduledExecutorService;
24  
25  import org.eclipse.jetty.io.AsyncEndPoint;
26  import org.eclipse.jetty.server.Connector;
27  import org.eclipse.jetty.spdy.ByteBufferPool;
28  import org.eclipse.jetty.spdy.EmptyAsyncEndPoint;
29  import org.eclipse.jetty.spdy.SPDYAsyncConnection;
30  import org.eclipse.jetty.spdy.ServerSPDYAsyncConnectionFactory;
31  import org.eclipse.jetty.spdy.api.DataInfo;
32  import org.eclipse.jetty.spdy.api.Headers;
33  import org.eclipse.jetty.spdy.api.HeadersInfo;
34  import org.eclipse.jetty.spdy.api.ReplyInfo;
35  import org.eclipse.jetty.spdy.api.Stream;
36  import org.eclipse.jetty.spdy.api.StreamFrameListener;
37  import org.eclipse.jetty.spdy.api.SynInfo;
38  import org.eclipse.jetty.spdy.api.server.ServerSessionFrameListener;
39  import org.eclipse.jetty.util.log.Log;
40  import org.eclipse.jetty.util.log.Logger;
41  
42  public class ServerHTTPSPDYAsyncConnectionFactory extends ServerSPDYAsyncConnectionFactory
43  {
44      private static final String CONNECTION_ATTRIBUTE = "org.eclipse.jetty.spdy.http.connection";
45      private static final Logger logger = Log.getLogger(ServerHTTPSPDYAsyncConnectionFactory.class);
46  
47      private final Connector connector;
48      private final PushStrategy pushStrategy;
49  
50      public ServerHTTPSPDYAsyncConnectionFactory(short version, ByteBufferPool bufferPool, Executor threadPool, ScheduledExecutorService scheduler, Connector connector, PushStrategy pushStrategy)
51      {
52          super(version, bufferPool, threadPool, scheduler);
53          this.connector = connector;
54          this.pushStrategy = pushStrategy;
55      }
56  
57      @Override
58      protected ServerSessionFrameListener provideServerSessionFrameListener(AsyncEndPoint endPoint, Object attachment)
59      {
60          return new HTTPServerFrameListener(endPoint);
61      }
62  
63      private class HTTPServerFrameListener extends ServerSessionFrameListener.Adapter implements StreamFrameListener
64      {
65          private final AsyncEndPoint endPoint;
66  
67          public HTTPServerFrameListener(AsyncEndPoint endPoint)
68          {
69              this.endPoint = endPoint;
70          }
71  
72          @Override
73          public StreamFrameListener onSyn(final Stream stream, SynInfo synInfo)
74          {
75              // Every time we have a SYN, it maps to a HTTP request.
76              // We can have multiple concurrent SYNs on the same connection,
77              // and this is very different from HTTP, where only one request/response
78              // cycle is processed at a time, so we need to fake an http connection
79              // for each SYN in order to run concurrently.
80  
81              logger.debug("Received {} on {}", synInfo, stream);
82  
83              HTTPSPDYAsyncEndPoint asyncEndPoint = new HTTPSPDYAsyncEndPoint(endPoint, stream);
84              ServerHTTPSPDYAsyncConnection connection = new ServerHTTPSPDYAsyncConnection(connector, asyncEndPoint,
85                      connector.getServer(), getVersion(), (SPDYAsyncConnection)endPoint.getConnection(),
86                      pushStrategy, stream);
87              asyncEndPoint.setConnection(connection);
88              stream.setAttribute(CONNECTION_ATTRIBUTE, connection);
89  
90              Headers headers = synInfo.getHeaders();
91              connection.beginRequest(headers, synInfo.isClose());
92  
93              if (headers.isEmpty())
94              {
95                  // If the SYN has no headers, they may come later in a HEADERS frame
96                  return this;
97              }
98              else
99              {
100                 if (synInfo.isClose())
101                     return null;
102                 else
103                     return this;
104             }
105         }
106 
107         @Override
108         public void onReply(Stream stream, ReplyInfo replyInfo)
109         {
110             // Do nothing, servers cannot get replies
111         }
112 
113         @Override
114         public void onHeaders(Stream stream, HeadersInfo headersInfo)
115         {
116             logger.debug("Received {} on {}", headersInfo, stream);
117             ServerHTTPSPDYAsyncConnection connection = (ServerHTTPSPDYAsyncConnection)stream.getAttribute(CONNECTION_ATTRIBUTE);
118             connection.headers(headersInfo.getHeaders());
119             if (headersInfo.isClose())
120                 connection.endRequest();
121         }
122 
123         @Override
124         public void onData(Stream stream, DataInfo dataInfo)
125         {
126             logger.debug("Received {} on {}", dataInfo, stream);
127             ServerHTTPSPDYAsyncConnection connection = (ServerHTTPSPDYAsyncConnection)stream.getAttribute(CONNECTION_ATTRIBUTE);
128             connection.content(dataInfo, dataInfo.isClose());
129             if (dataInfo.isClose())
130                 connection.endRequest();
131         }
132     }
133 
134     private class HTTPSPDYAsyncEndPoint extends EmptyAsyncEndPoint
135     {
136         private final AsyncEndPoint endPoint;
137         private final Stream stream;
138 
139         private HTTPSPDYAsyncEndPoint(AsyncEndPoint endPoint, Stream stream)
140         {
141             this.endPoint = endPoint;
142             this.stream = stream;
143         }
144 
145         @Override
146         public void asyncDispatch()
147         {
148             ServerHTTPSPDYAsyncConnection connection = (ServerHTTPSPDYAsyncConnection)stream.getAttribute(CONNECTION_ATTRIBUTE);
149             connection.async();
150         }
151 
152         @Override
153         public String getLocalAddr()
154         {
155             return endPoint.getLocalAddr();
156         }
157 
158         @Override
159         public String getLocalHost()
160         {
161             return endPoint.getLocalHost();
162         }
163 
164         @Override
165         public int getLocalPort()
166         {
167             return endPoint.getLocalPort();
168         }
169 
170         @Override
171         public String getRemoteAddr()
172         {
173             return endPoint.getRemoteAddr();
174         }
175 
176         @Override
177         public String getRemoteHost()
178         {
179             return endPoint.getRemoteHost();
180         }
181 
182         @Override
183         public int getRemotePort()
184         {
185             return endPoint.getRemotePort();
186         }
187     }
188 }