1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.eclipse.jetty.http2.client.http;
20
21 import java.io.IOException;
22 import java.net.InetSocketAddress;
23 import java.util.Map;
24
25 import org.eclipse.jetty.alpn.client.ALPNClientConnectionFactory;
26 import org.eclipse.jetty.client.HttpClient;
27 import org.eclipse.jetty.client.HttpClientTransport;
28 import org.eclipse.jetty.client.HttpDestination;
29 import org.eclipse.jetty.client.Origin;
30 import org.eclipse.jetty.client.api.Connection;
31 import org.eclipse.jetty.http.HttpScheme;
32 import org.eclipse.jetty.http2.api.Session;
33 import org.eclipse.jetty.http2.client.HTTP2Client;
34 import org.eclipse.jetty.http2.client.HTTP2ClientConnectionFactory;
35 import org.eclipse.jetty.io.ClientConnectionFactory;
36 import org.eclipse.jetty.io.EndPoint;
37 import org.eclipse.jetty.io.ssl.SslClientConnectionFactory;
38 import org.eclipse.jetty.util.Promise;
39 import org.eclipse.jetty.util.annotation.ManagedAttribute;
40 import org.eclipse.jetty.util.annotation.ManagedObject;
41 import org.eclipse.jetty.util.component.ContainerLifeCycle;
42 import org.eclipse.jetty.util.ssl.SslContextFactory;
43
44 @ManagedObject("The HTTP/2 client transport")
45 public class HttpClientTransportOverHTTP2 extends ContainerLifeCycle implements HttpClientTransport
46 {
47 private final HTTP2Client client;
48 private ClientConnectionFactory connectionFactory;
49 private HttpClient httpClient;
50
51 public HttpClientTransportOverHTTP2(HTTP2Client client)
52 {
53 this.client = client;
54 }
55
56 @ManagedAttribute(value = "The number of selectors", readonly = true)
57 public int getSelectors()
58 {
59 return client.getSelectors();
60 }
61
62 @Override
63 protected void doStart() throws Exception
64 {
65 if (!client.isStarted())
66 {
67 client.setExecutor(httpClient.getExecutor());
68 client.setScheduler(httpClient.getScheduler());
69 client.setByteBufferPool(httpClient.getByteBufferPool());
70 client.setConnectTimeout(httpClient.getConnectTimeout());
71 client.setIdleTimeout(httpClient.getIdleTimeout());
72 }
73 addBean(client);
74 super.doStart();
75
76 this.connectionFactory = new HTTP2ClientConnectionFactory();
77 client.setClientConnectionFactory((endPoint, context) ->
78 {
79 HttpDestination destination = (HttpDestination)context.get(HTTP_DESTINATION_CONTEXT_KEY);
80 return destination.getClientConnectionFactory().newConnection(endPoint, context);
81 });
82 }
83
84 @Override
85 protected void doStop() throws Exception
86 {
87 super.doStop();
88 removeBean(client);
89 }
90
91 @Override
92 public void setHttpClient(HttpClient client)
93 {
94 httpClient = client;
95 }
96
97 @Override
98 public HttpDestination newHttpDestination(Origin origin)
99 {
100 return new HttpDestinationOverHTTP2(httpClient, origin);
101 }
102
103 @Override
104 public void connect(InetSocketAddress address, Map<String, Object> context)
105 {
106 client.setConnectTimeout(httpClient.getConnectTimeout());
107
108 final HttpDestination destination = (HttpDestination)context.get(HTTP_DESTINATION_CONTEXT_KEY);
109 @SuppressWarnings("unchecked")
110 final Promise<Connection> connection = (Promise<Connection>)context.get(HTTP_CONNECTION_PROMISE_CONTEXT_KEY);
111
112 Session.Listener listener = new Session.Listener.Adapter()
113 {
114 @Override
115 public void onFailure(Session session, Throwable failure)
116 {
117 destination.abort(failure);
118 }
119 };
120
121 final Promise<Session> promise = new Promise<Session>()
122 {
123 @Override
124 public void succeeded(Session session)
125 {
126 connection.succeeded(newHttpConnection(destination, session));
127 }
128
129 @Override
130 public void failed(Throwable failure)
131 {
132 connection.failed(failure);
133 }
134 };
135
136 SslContextFactory sslContextFactory = null;
137 if (HttpScheme.HTTPS.is(destination.getScheme()))
138 sslContextFactory = httpClient.getSslContextFactory();
139
140 client.connect(sslContextFactory, address, listener, promise, context);
141 }
142
143 @Override
144 public org.eclipse.jetty.io.Connection newConnection(EndPoint endPoint, Map<String, Object> context) throws IOException
145 {
146 ClientConnectionFactory factory = connectionFactory;
147 SslContextFactory sslContextFactory = (SslContextFactory)context.get(SslClientConnectionFactory.SSL_CONTEXT_FACTORY_CONTEXT_KEY);
148 if (sslContextFactory != null)
149 factory = new ALPNClientConnectionFactory(client.getExecutor(), factory, client.getProtocols());
150 return factory.newConnection(endPoint, context);
151 }
152
153 protected HttpConnectionOverHTTP2 newHttpConnection(HttpDestination destination, Session session)
154 {
155 return new HttpConnectionOverHTTP2(destination, session);
156 }
157 }