View Javadoc

1   //
2   //  ========================================================================
3   //  Copyright (c) 1995-2016 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  package org.eclipse.jetty.http2.server;
20  
21  import java.util.Objects;
22  
23  import org.eclipse.jetty.http2.BufferingFlowControlStrategy;
24  import org.eclipse.jetty.http2.FlowControlStrategy;
25  import org.eclipse.jetty.http2.HTTP2Connection;
26  import org.eclipse.jetty.http2.api.server.ServerSessionListener;
27  import org.eclipse.jetty.http2.generator.Generator;
28  import org.eclipse.jetty.http2.parser.ServerParser;
29  import org.eclipse.jetty.io.Connection;
30  import org.eclipse.jetty.io.EndPoint;
31  import org.eclipse.jetty.server.AbstractConnectionFactory;
32  import org.eclipse.jetty.server.Connector;
33  import org.eclipse.jetty.server.HttpConfiguration;
34  import org.eclipse.jetty.util.annotation.ManagedAttribute;
35  import org.eclipse.jetty.util.annotation.ManagedObject;
36  import org.eclipse.jetty.util.annotation.Name;
37  import org.eclipse.jetty.util.component.LifeCycle;
38  import org.eclipse.jetty.util.thread.ExecutionStrategy;
39  import org.eclipse.jetty.util.thread.strategy.ProduceExecuteConsume;
40  
41  @ManagedObject
42  public abstract class AbstractHTTP2ServerConnectionFactory extends AbstractConnectionFactory
43  {
44      private final Connection.Listener connectionListener = new ConnectionListener();
45      private final HttpConfiguration httpConfiguration;
46      private int maxDynamicTableSize = 4096;
47      private int initialStreamRecvWindow = FlowControlStrategy.DEFAULT_WINDOW_SIZE;
48      private int initialSessionRecvWindow = FlowControlStrategy.DEFAULT_WINDOW_SIZE;
49      private int maxConcurrentStreams = 128;
50      private int maxHeaderBlockFragment = 0;
51      private FlowControlStrategy.Factory flowControlStrategyFactory = () -> new BufferingFlowControlStrategy(0.5F);
52      private ExecutionStrategy.Factory executionStrategyFactory = new ProduceExecuteConsume.Factory();
53      private long streamIdleTimeout;
54  
55      public AbstractHTTP2ServerConnectionFactory(@Name("config") HttpConfiguration httpConfiguration)
56      {
57          this(httpConfiguration,"h2","h2-17","h2-16","h2-15","h2-14");
58      }
59  
60      protected AbstractHTTP2ServerConnectionFactory(@Name("config") HttpConfiguration httpConfiguration, String... protocols)
61      {
62          super(protocols);
63          this.httpConfiguration = Objects.requireNonNull(httpConfiguration);
64          addBean(httpConfiguration);
65      }
66  
67      @ManagedAttribute("The HPACK dynamic table maximum size")
68      public int getMaxDynamicTableSize()
69      {
70          return maxDynamicTableSize;
71      }
72  
73      public void setMaxDynamicTableSize(int maxDynamicTableSize)
74      {
75          this.maxDynamicTableSize = maxDynamicTableSize;
76      }
77  
78      @ManagedAttribute("The initial size of session's flow control receive window")
79      public int getInitialSessionRecvWindow()
80      {
81          return initialSessionRecvWindow;
82      }
83  
84      public void setInitialSessionRecvWindow(int initialSessionRecvWindow)
85      {
86          this.initialSessionRecvWindow = initialSessionRecvWindow;
87      }
88  
89      @ManagedAttribute("The initial size of stream's flow control receive window")
90      public int getInitialStreamRecvWindow()
91      {
92          return initialStreamRecvWindow;
93      }
94  
95      public void setInitialStreamRecvWindow(int initialStreamRecvWindow)
96      {
97          this.initialStreamRecvWindow = initialStreamRecvWindow;
98      }
99  
100     /**
101      * @deprecated use {@link #getInitialStreamRecvWindow()} instead,
102      * since "send" is meant on the client, but this is the server configuration
103      */
104     @Deprecated
105     public int getInitialStreamSendWindow()
106     {
107         return getInitialStreamRecvWindow();
108     }
109 
110     /**
111      * @deprecated use {@link #setInitialStreamRecvWindow(int)} instead,
112      * since "send" is meant on the client, but this is the server configuration
113      */
114     @Deprecated
115     public void setInitialStreamSendWindow(int initialStreamSendWindow)
116     {
117         setInitialStreamRecvWindow(initialStreamSendWindow);
118     }
119 
120     @ManagedAttribute("The max number of concurrent streams per session")
121     public int getMaxConcurrentStreams()
122     {
123         return maxConcurrentStreams;
124     }
125 
126     public void setMaxConcurrentStreams(int maxConcurrentStreams)
127     {
128         this.maxConcurrentStreams = maxConcurrentStreams;
129     }
130 
131     public int getMaxHeaderBlockFragment()
132     {
133         return maxHeaderBlockFragment;
134     }
135 
136     public void setMaxHeaderBlockFragment(int maxHeaderBlockFragment)
137     {
138         this.maxHeaderBlockFragment = maxHeaderBlockFragment;
139     }
140 
141     public FlowControlStrategy.Factory getFlowControlStrategyFactory()
142     {
143         return flowControlStrategyFactory;
144     }
145 
146     public void setFlowControlStrategyFactory(FlowControlStrategy.Factory flowControlStrategyFactory)
147     {
148         this.flowControlStrategyFactory = flowControlStrategyFactory;
149     }
150 
151     public ExecutionStrategy.Factory getExecutionStrategyFactory()
152     {
153         return executionStrategyFactory;
154     }
155 
156     public void setExecutionStrategyFactory(ExecutionStrategy.Factory executionStrategyFactory)
157     {
158         this.executionStrategyFactory = executionStrategyFactory;
159     }
160 
161     @ManagedAttribute("The stream idle timeout in milliseconds")
162     public long getStreamIdleTimeout()
163     {
164         return streamIdleTimeout;
165     }
166 
167     public void setStreamIdleTimeout(long streamIdleTimeout)
168     {
169         this.streamIdleTimeout = streamIdleTimeout;
170     }
171 
172     public HttpConfiguration getHttpConfiguration()
173     {
174         return httpConfiguration;
175     }
176 
177     @Override
178     public Connection newConnection(Connector connector, EndPoint endPoint)
179     {
180         ServerSessionListener listener = newSessionListener(connector, endPoint);
181 
182         Generator generator = new Generator(connector.getByteBufferPool(), getMaxDynamicTableSize(), getMaxHeaderBlockFragment());
183         FlowControlStrategy flowControl = newFlowControlStrategy();
184         if (flowControl == null)
185             flowControl = getFlowControlStrategyFactory().newFlowControlStrategy();
186         HTTP2ServerSession session = new HTTP2ServerSession(connector.getScheduler(), endPoint, generator, listener, flowControl);
187         session.setMaxLocalStreams(getMaxConcurrentStreams());
188         session.setMaxRemoteStreams(getMaxConcurrentStreams());
189         // For a single stream in a connection, there will be a race between
190         // the stream idle timeout and the connection idle timeout. However,
191         // the typical case is that the connection will be busier and the
192         // stream idle timeout will expire earlier than the connection's.
193         long streamIdleTimeout = getStreamIdleTimeout();
194         if (streamIdleTimeout <= 0)
195             streamIdleTimeout = endPoint.getIdleTimeout();
196         session.setStreamIdleTimeout(streamIdleTimeout);
197         session.setInitialSessionRecvWindow(getInitialSessionRecvWindow());
198 
199         ServerParser parser = newServerParser(connector, session);
200         HTTP2Connection connection = new HTTP2ServerConnection(connector.getByteBufferPool(), connector.getExecutor(),
201                         endPoint, httpConfiguration, parser, session, getInputBufferSize(), getExecutionStrategyFactory(), listener);
202         connection.addListener(connectionListener);
203         return configure(connection, connector, endPoint);
204     }
205 
206     /**
207      * @deprecated use {@link #setFlowControlStrategyFactory(FlowControlStrategy.Factory)} instead
208      */
209     @Deprecated
210     protected FlowControlStrategy newFlowControlStrategy()
211     {
212         return null;
213     }
214 
215     protected abstract ServerSessionListener newSessionListener(Connector connector, EndPoint endPoint);
216 
217     protected ServerParser newServerParser(Connector connector, ServerParser.Listener listener)
218     {
219         return new ServerParser(connector.getByteBufferPool(), listener, getMaxDynamicTableSize(), getHttpConfiguration().getRequestHeaderSize());
220     }
221 
222     private class ConnectionListener implements Connection.Listener
223     {
224         @Override
225         public void onOpened(Connection connection)
226         {
227             addManaged((LifeCycle)((HTTP2Connection)connection).getSession());
228         }
229 
230         @Override
231         public void onClosed(Connection connection)
232         {
233             removeBean(((HTTP2Connection)connection).getSession());
234         }
235     }
236 }