1 package software.amazon.awssdk.crt.http;
2 
3 import java.util.List;
4 import java.util.ArrayList;
5 
6 /**
7  * Contains all the configuration options for a Http2StreamManager
8  * instance
9  */
10 public class Http2StreamManagerOptions {
11     public static final int DEFAULT_MAX_WINDOW_SIZE = Integer.MAX_VALUE;
12     public static final int DEFAULT_MAX = Integer.MAX_VALUE;
13     public static final int DEFAULT_MAX_CONNECTIONS = 2;
14     public static final int DEFAULT_CONNECTION_PING_TIMEOUT_MS = 3000;
15 
16     private HttpClientConnectionManagerOptions connectionManagerOptions;
17 
18     private int idealConcurrentStreamsPerConnection = 100;
19     private boolean connectionManualWindowManagement = false;
20     private int maxConcurrentStreamsPerConnection = DEFAULT_MAX;
21 
22     private boolean priorKnowledge = false;
23     private boolean closeConnectionOnServerError = false;
24     private int connectionPingPeriodMs = 0;
25     private int connectionPingTimeoutMs = 0;
26 
27     private List<Http2ConnectionSetting> initialSettingsList = new ArrayList<Http2ConnectionSetting>();
28 
29     /**
30      * Default constructor
31      */
Http2StreamManagerOptions()32     public Http2StreamManagerOptions() {
33     }
34 
35     /**
36      * For HTTP/2 stream manager only.
37      *
38      * The initial settings for the HTTP/2 connections made by stream manger.
39      * `Http2ConnectionSettingListBuilder` can help to build the settings list.
40      *
41      * To control the initial stream-level flow-control window, set the
42      * INITIAL_WINDOW_SIZE setting in the initial settings.
43      *
44      * @param initialSettingsList The List of initial settings
45      * @return this
46      */
withInitialSettingsList(List<Http2ConnectionSetting> initialSettingsList)47     public Http2StreamManagerOptions withInitialSettingsList(List<Http2ConnectionSetting> initialSettingsList) {
48         this.initialSettingsList.addAll(initialSettingsList);
49         return this;
50     }
51 
52     /**
53      * @return The List of initial settings
54      */
getInitialSettingsList()55     public List<Http2ConnectionSetting> getInitialSettingsList() {
56         return this.initialSettingsList;
57     }
58 
59     /**
60      * For HTTP/2 stream manager only.
61      *
62      * The ideal number of concurrent streams for a connection. Stream manager will
63      * try to create a new connection if one connection reaches this number. But, if
64      * the max connections reaches, manager will reuse connections to create the
65      * acquired steams as much as possible.
66      *
67      * @param idealConcurrentStreamsPerConnection The ideal number of concurrent
68      *                                            streams for a connection
69      * @return this
70      */
withIdealConcurrentStreamsPerConnection(int idealConcurrentStreamsPerConnection)71     public Http2StreamManagerOptions withIdealConcurrentStreamsPerConnection(int idealConcurrentStreamsPerConnection) {
72         this.idealConcurrentStreamsPerConnection = idealConcurrentStreamsPerConnection;
73         return this;
74     }
75 
76     /**
77      * @return The ideal number of concurrent streams for a connection used for
78      *         manager
79      */
getIdealConcurrentStreamsPerConnection()80     public int getIdealConcurrentStreamsPerConnection() {
81         return idealConcurrentStreamsPerConnection;
82     }
83 
84     /**
85      * Default is no limit, which will use the limit from the server. 0 will be
86      * considered as using the default value.
87      * The real number of concurrent streams per connection will be controlled by
88      * the minimal value of the setting from other end and the value here.
89      *
90      * @param maxConcurrentStreamsPerConnection The max number of concurrent
91      *                                          streams for a connection
92      * @return this
93      */
withMaxConcurrentStreamsPerConnection(int maxConcurrentStreamsPerConnection)94     public Http2StreamManagerOptions withMaxConcurrentStreamsPerConnection(int maxConcurrentStreamsPerConnection) {
95         this.maxConcurrentStreamsPerConnection = maxConcurrentStreamsPerConnection;
96         return this;
97     }
98 
99     /**
100      * @return The max number of concurrent streams for a connection set for
101      *         manager.
102      *         It could be different than the real limits, which is the minimal set
103      *         for manager and the settings from the other side.
104      */
getMaxConcurrentStreamsPerConnection()105     public int getMaxConcurrentStreamsPerConnection() {
106         return maxConcurrentStreamsPerConnection;
107     }
108 
109     /**
110      * @return The connection level manual flow control enabled or not.
111      */
isConnectionManualWindowManagement()112     public boolean isConnectionManualWindowManagement() {
113         return connectionManualWindowManagement;
114     }
115 
116     /**
117      * Set to true to manually manage the flow-control window of whole HTTP/2
118      * connection.
119      * The stream level flow-control window is controlled by the
120      * manualWindowManagement in connectionManagerOptions.
121      *
122      * @param connectionManualWindowManagement Enable connection level manual flow
123      *                                         control or not.
124      * @return this
125      */
withConnectionManualWindowManagement(boolean connectionManualWindowManagement)126     public Http2StreamManagerOptions withConnectionManualWindowManagement(boolean connectionManualWindowManagement) {
127         this.connectionManualWindowManagement = connectionManualWindowManagement;
128         return this;
129     }
130 
131     /**
132      * @return The connection manager options for the underlying connection manager.
133      */
getConnectionManagerOptions()134     public HttpClientConnectionManagerOptions getConnectionManagerOptions() {
135         return connectionManagerOptions;
136     }
137 
138     /**
139      * Required.
140      *
141      * The configuration options for the connection manager under the hood.
142      * It controls the connection specific thing for the stream manager. See
143      * `HttpClientConnectionManagerOptions` for details.
144      *
145      * Note:
146      * 1. the windowSize of connection manager will be ignored, as the initial
147      * flow-control window size for HTTP/2 stream
148      * is controlled by the initial settings.
149      * 2. The expectedHttpVersion will also be ignored.
150      *
151      * @param connectionManagerOptions The connection manager options for the
152      *                                 underlying connection manager
153      * @return this
154      */
withConnectionManagerOptions( HttpClientConnectionManagerOptions connectionManagerOptions)155     public Http2StreamManagerOptions withConnectionManagerOptions(
156             HttpClientConnectionManagerOptions connectionManagerOptions) {
157         this.connectionManagerOptions = connectionManagerOptions;
158         return this;
159     }
160 
161     /**
162      * @return Prior knowledge is used or not
163      */
hasPriorKnowledge()164     public boolean hasPriorKnowledge() {
165         return priorKnowledge;
166     }
167 
168     /**
169      * Set to true to use prior knowledge to setup connection.
170      * If any TLS was set, exception will be raised if prior knowledge is set during
171      * validation.
172      * If NO TLS was set, exception will be raised if prior knowledge is NOT set
173      * during validation.
174      *
175      * @param priorKnowledge Prior knowledge used or not.
176      * @return this
177      */
withPriorKnowledge(boolean priorKnowledge)178     public Http2StreamManagerOptions withPriorKnowledge(boolean priorKnowledge) {
179         this.priorKnowledge = priorKnowledge;
180         return this;
181     }
182 
183     /**
184      * @return Connection closed or not when server error happened (500/502/503/504
185      *         response status code received).
186      */
shouldCloseConnectionOnServerError()187     public boolean shouldCloseConnectionOnServerError() {
188         return closeConnectionOnServerError;
189     }
190 
191     /**
192      * Set to true to inform stream manager to close connection when response with
193      * 500/502/503/504 received.
194      * Stream manager will stop using the connection with server error will start a
195      * new connection for other streams.
196      *
197      * @param closeConnectionOnServerError Connection closed or not when server
198      *                                     error happened.
199      * @return this
200      */
withCloseConnectionOnServerError(boolean closeConnectionOnServerError)201     public Http2StreamManagerOptions withCloseConnectionOnServerError(boolean closeConnectionOnServerError) {
202         this.closeConnectionOnServerError = closeConnectionOnServerError;
203         return this;
204     }
205 
206     /**
207      * Settings to control the period ping to be sent for connections held by stream
208      * manager.
209      *
210      * @param periodMs  The period for all the connections held by stream manager to
211      *                  send a PING in milliseconds. If you specify 0, manager will
212      *                  NOT send any PING.
213      * @param timeoutMs Network connection will be closed if a ping response is not
214      *                  received within this amount of time (milliseconds). If you
215      *                  specify 0, a default value will be used. If this is larger
216      *                  than periodMs, it will be capped to be equal.
217      * @return this
218      */
withConnectionPing(int periodMs, int timeoutMs)219     public Http2StreamManagerOptions withConnectionPing(int periodMs, int timeoutMs) {
220         this.connectionPingPeriodMs = periodMs;
221         this.connectionPingTimeoutMs = timeoutMs == 0 ? DEFAULT_CONNECTION_PING_TIMEOUT_MS
222                 : timeoutMs;
223         this.connectionPingTimeoutMs = Math.min(this.connectionPingPeriodMs, this.connectionPingTimeoutMs);
224         return this;
225     }
226 
227     /**
228      * @return The period for all the connections held by stream manager to send a
229      *         PING in milliseconds.
230      */
getConnectionPingPeriodMs()231     public int getConnectionPingPeriodMs() {
232         return connectionPingPeriodMs;
233     }
234 
235     /**
236      * @return The time for closing connection if ping not received within this
237      *         amount of time in milliseconds
238      */
getConnectionPingTimeoutMs()239     public int getConnectionPingTimeoutMs() {
240         return connectionPingTimeoutMs;
241     }
242 
243     /**
244      * Validate the stream manager options are valid to use. Throw exceptions if
245      * not.
246      */
validateOptions()247     public void validateOptions() {
248         if (connectionManagerOptions == null) {
249             throw new IllegalArgumentException("Connection manager options are required.");
250         }
251         connectionManagerOptions.validateOptions();
252         if ((connectionManagerOptions.getTlsConnectionOptions() != null
253                 || connectionManagerOptions.getTlsContext() != null) && priorKnowledge) {
254             throw new IllegalArgumentException("HTTP/2 prior knowledge cannot be set when TLS is used.");
255         }
256         if ((connectionManagerOptions.getTlsConnectionOptions() == null
257                 && connectionManagerOptions.getTlsContext() == null) && !priorKnowledge) {
258             throw new IllegalArgumentException(
259                     "Prior knowledge must be used for cleartext HTTP/2 connections. Upgrade from HTTP/1.1 is not supported.");
260         }
261         if (maxConcurrentStreamsPerConnection <= 0) {
262             throw new IllegalArgumentException("Max Concurrent Streams Per Connection must be greater than zero.");
263         }
264         if (idealConcurrentStreamsPerConnection <= 0
265                 || idealConcurrentStreamsPerConnection > maxConcurrentStreamsPerConnection) {
266             throw new IllegalArgumentException(
267                     "Ideal Concurrent Streams Per Connection must be greater than zero and smaller than max.");
268         }
269     }
270 }
271