1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28 package org.apache.hc.client5.http.impl.io;
29
30 import java.net.ConnectException;
31 import java.net.InetAddress;
32 import java.net.InetSocketAddress;
33 import java.net.Socket;
34 import java.net.SocketTimeoutException;
35 import java.util.concurrent.TimeUnit;
36
37 import org.apache.hc.client5.http.ConnectTimeoutException;
38 import org.apache.hc.client5.http.DnsResolver;
39 import org.apache.hc.client5.http.HttpHostConnectException;
40 import org.apache.hc.client5.http.SchemePortResolver;
41 import org.apache.hc.client5.http.UnsupportedSchemeException;
42 import org.apache.hc.client5.http.io.ManagedHttpClientConnection;
43 import org.apache.hc.client5.http.socket.ConnectionSocketFactory;
44 import org.apache.hc.client5.http.socket.LayeredConnectionSocketFactory;
45 import org.apache.hc.core5.http.HttpHost;
46 import org.apache.hc.core5.http.config.Lookup;
47 import org.apache.hc.core5.http.io.SocketConfig;
48 import org.apache.hc.core5.http.protocol.BasicHttpContext;
49 import org.apache.hc.core5.http.protocol.HttpContext;
50 import org.apache.hc.core5.util.TimeValue;
51 import org.junit.Before;
52 import org.junit.Test;
53 import org.mockito.Mockito;
54
55 @SuppressWarnings({"boxing","static-access"})
56 public class TestHttpClientConnectionOperator {
57
58 private ManagedHttpClientConnection conn;
59 private Socket socket;
60 private ConnectionSocketFactory plainSocketFactory;
61 private LayeredConnectionSocketFactory sslSocketFactory;
62 private Lookup<ConnectionSocketFactory> socketFactoryRegistry;
63 private SchemePortResolver schemePortResolver;
64 private DnsResolver dnsResolver;
65 private DefaultHttpClientConnectionOperator connectionOperator;
66
67 @Before
68 public void setup() throws Exception {
69 conn = Mockito.mock(ManagedHttpClientConnection.class);
70 socket = Mockito.mock(Socket.class);
71 plainSocketFactory = Mockito.mock(ConnectionSocketFactory.class);
72 sslSocketFactory = Mockito.mock(LayeredConnectionSocketFactory.class);
73 socketFactoryRegistry = Mockito.mock(Lookup.class);
74 schemePortResolver = Mockito.mock(SchemePortResolver.class);
75 dnsResolver = Mockito.mock(DnsResolver.class);
76 connectionOperator = new DefaultHttpClientConnectionOperator(
77 socketFactoryRegistry, schemePortResolver, dnsResolver);
78 }
79
80 @Test
81 public void testConnect() throws Exception {
82 final HttpContext context = new BasicHttpContext();
83 final HttpHost host = new HttpHost("somehost");
84 final InetAddress local = InetAddress.getByAddress(new byte[] {127, 0, 0, 0});
85 final InetAddress ip1 = InetAddress.getByAddress(new byte[] {127, 0, 0, 1});
86 final InetAddress ip2 = InetAddress.getByAddress(new byte[] {127, 0, 0, 2});
87
88 Mockito.when(dnsResolver.resolve("somehost")).thenReturn(new InetAddress[] { ip1, ip2 });
89 Mockito.when(socketFactoryRegistry.lookup("http")).thenReturn(plainSocketFactory);
90 Mockito.when(schemePortResolver.resolve(host)).thenReturn(80);
91 Mockito.when(plainSocketFactory.createSocket(Mockito.<HttpContext>any())).thenReturn(socket);
92 Mockito.when(plainSocketFactory.connectSocket(
93 Mockito.<TimeValue>any(),
94 Mockito.<Socket>any(),
95 Mockito.<HttpHost>any(),
96 Mockito.<InetSocketAddress>any(),
97 Mockito.<InetSocketAddress>any(),
98 Mockito.<HttpContext>any())).thenReturn(socket);
99
100 final SocketConfig socketConfig = SocketConfig.custom()
101 .setSoKeepAlive(true)
102 .setSoReuseAddress(true)
103 .setSoTimeout(5000, TimeUnit.MILLISECONDS)
104 .setTcpNoDelay(true)
105 .setSoLinger(50, TimeUnit.MILLISECONDS)
106 .build();
107 final InetSocketAddress localAddress = new InetSocketAddress(local, 0);
108 connectionOperator.connect(conn, host, localAddress, TimeValue.ofMilliseconds(1000), socketConfig, context);
109
110 Mockito.verify(socket).setKeepAlive(true);
111 Mockito.verify(socket).setReuseAddress(true);
112 Mockito.verify(socket).setSoTimeout(5000);
113 Mockito.verify(socket).setSoLinger(true, 50);
114 Mockito.verify(socket).setTcpNoDelay(true);
115
116 Mockito.verify(plainSocketFactory).connectSocket(
117 TimeValue.ofMilliseconds(1000),
118 socket,
119 host,
120 new InetSocketAddress(ip1, 80),
121 localAddress,
122 context);
123 Mockito.verify(conn, Mockito.times(2)).bind(socket);
124 }
125
126 @Test(expected=ConnectTimeoutException.class)
127 public void testConnectTimeout() throws Exception {
128 final HttpContext context = new BasicHttpContext();
129 final HttpHost host = new HttpHost("somehost");
130 final InetAddress ip1 = InetAddress.getByAddress(new byte[] {10, 0, 0, 1});
131 final InetAddress ip2 = InetAddress.getByAddress(new byte[] {10, 0, 0, 2});
132
133 Mockito.when(dnsResolver.resolve("somehost")).thenReturn(new InetAddress[] { ip1, ip2 });
134 Mockito.when(socketFactoryRegistry.lookup("http")).thenReturn(plainSocketFactory);
135 Mockito.when(schemePortResolver.resolve(host)).thenReturn(80);
136 Mockito.when(plainSocketFactory.createSocket(Mockito.<HttpContext>any())).thenReturn(socket);
137 Mockito.when(plainSocketFactory.connectSocket(
138 Mockito.<TimeValue>any(),
139 Mockito.<Socket>any(),
140 Mockito.<HttpHost>any(),
141 Mockito.<InetSocketAddress>any(),
142 Mockito.<InetSocketAddress>any(),
143 Mockito.<HttpContext>any())).thenThrow(new SocketTimeoutException());
144
145 connectionOperator.connect(conn, host, null, TimeValue.ofMilliseconds(1000), SocketConfig.DEFAULT, context);
146 }
147
148 @Test(expected=HttpHostConnectException.class)
149 public void testConnectFailure() throws Exception {
150 final HttpContext context = new BasicHttpContext();
151 final HttpHost host = new HttpHost("somehost");
152 final InetAddress ip1 = InetAddress.getByAddress(new byte[] {10, 0, 0, 1});
153 final InetAddress ip2 = InetAddress.getByAddress(new byte[] {10, 0, 0, 2});
154
155 Mockito.when(dnsResolver.resolve("somehost")).thenReturn(new InetAddress[] { ip1, ip2 });
156 Mockito.when(socketFactoryRegistry.lookup("http")).thenReturn(plainSocketFactory);
157 Mockito.when(schemePortResolver.resolve(host)).thenReturn(80);
158 Mockito.when(plainSocketFactory.createSocket(Mockito.<HttpContext>any())).thenReturn(socket);
159 Mockito.when(plainSocketFactory.connectSocket(
160 Mockito.<TimeValue>any(),
161 Mockito.<Socket>any(),
162 Mockito.<HttpHost>any(),
163 Mockito.<InetSocketAddress>any(),
164 Mockito.<InetSocketAddress>any(),
165 Mockito.<HttpContext>any())).thenThrow(new ConnectException());
166
167 connectionOperator.connect(conn, host, null, TimeValue.ofMilliseconds(1000), SocketConfig.DEFAULT, context);
168 }
169
170 @Test
171 public void testConnectFailover() throws Exception {
172 final HttpContext context = new BasicHttpContext();
173 final HttpHost host = new HttpHost("somehost");
174 final InetAddress local = InetAddress.getByAddress(new byte[] {127, 0, 0, 0});
175 final InetAddress ip1 = InetAddress.getByAddress(new byte[] {10, 0, 0, 1});
176 final InetAddress ip2 = InetAddress.getByAddress(new byte[] {10, 0, 0, 2});
177
178 Mockito.when(dnsResolver.resolve("somehost")).thenReturn(new InetAddress[] { ip1, ip2 });
179 Mockito.when(socketFactoryRegistry.lookup("http")).thenReturn(plainSocketFactory);
180 Mockito.when(schemePortResolver.resolve(host)).thenReturn(80);
181 Mockito.when(plainSocketFactory.createSocket(Mockito.<HttpContext>any())).thenReturn(socket);
182 Mockito.when(plainSocketFactory.connectSocket(
183 Mockito.<TimeValue>any(),
184 Mockito.<Socket>any(),
185 Mockito.<HttpHost>any(),
186 Mockito.eq(new InetSocketAddress(ip1, 80)),
187 Mockito.<InetSocketAddress>any(),
188 Mockito.<HttpContext>any())).thenThrow(new ConnectException());
189 Mockito.when(plainSocketFactory.connectSocket(
190 Mockito.<TimeValue>any(),
191 Mockito.<Socket>any(),
192 Mockito.<HttpHost>any(),
193 Mockito.eq(new InetSocketAddress(ip2, 80)),
194 Mockito.<InetSocketAddress>any(),
195 Mockito.<HttpContext>any())).thenReturn(socket);
196
197 final InetSocketAddress localAddress = new InetSocketAddress(local, 0);
198 connectionOperator.connect(conn, host, localAddress, TimeValue.ofMilliseconds(1000), SocketConfig.DEFAULT, context);
199
200 Mockito.verify(plainSocketFactory).connectSocket(
201 TimeValue.ofMilliseconds(1000),
202 socket,
203 host,
204 new InetSocketAddress(ip2, 80),
205 localAddress,
206 context);
207 Mockito.verify(conn, Mockito.times(3)).bind(socket);
208 }
209
210 @Test
211 public void testConnectExplicitAddress() throws Exception {
212 final HttpContext context = new BasicHttpContext();
213 final InetAddress local = InetAddress.getByAddress(new byte[] {127, 0, 0, 0});
214 final InetAddress ip = InetAddress.getByAddress(new byte[] {127, 0, 0, 23});
215 final HttpHost host = new HttpHost(ip);
216
217 Mockito.when(socketFactoryRegistry.lookup("http")).thenReturn(plainSocketFactory);
218 Mockito.when(schemePortResolver.resolve(host)).thenReturn(80);
219 Mockito.when(plainSocketFactory.createSocket(Mockito.<HttpContext>any())).thenReturn(socket);
220 Mockito.when(plainSocketFactory.connectSocket(
221 Mockito.<TimeValue>any(),
222 Mockito.<Socket>any(),
223 Mockito.<HttpHost>any(),
224 Mockito.<InetSocketAddress>any(),
225 Mockito.<InetSocketAddress>any(),
226 Mockito.<HttpContext>any())).thenReturn(socket);
227
228 final InetSocketAddress localAddress = new InetSocketAddress(local, 0);
229 connectionOperator.connect(conn, host, localAddress, TimeValue.ofMilliseconds(1000), SocketConfig.DEFAULT, context);
230
231 Mockito.verify(plainSocketFactory).connectSocket(
232 TimeValue.ofMilliseconds(1000),
233 socket,
234 host,
235 new InetSocketAddress(ip, 80),
236 localAddress,
237 context);
238 Mockito.verify(dnsResolver, Mockito.never()).resolve(Mockito.anyString());
239 Mockito.verify(conn, Mockito.times(2)).bind(socket);
240 }
241
242 @Test
243 public void testUpgrade() throws Exception {
244 final HttpContext context = new BasicHttpContext();
245 final HttpHost host = new HttpHost("https", "somehost", -1);
246
247 Mockito.when(conn.isOpen()).thenReturn(true);
248 Mockito.when(conn.getSocket()).thenReturn(socket);
249 Mockito.when(socketFactoryRegistry.lookup("https")).thenReturn(sslSocketFactory);
250 Mockito.when(schemePortResolver.resolve(host)).thenReturn(443);
251 Mockito.when(sslSocketFactory.createSocket(Mockito.<HttpContext>any())).thenReturn(socket);
252 Mockito.when(sslSocketFactory.createLayeredSocket(
253 Mockito.<Socket>any(),
254 Mockito.eq("somehost"),
255 Mockito.eq(443),
256 Mockito.<HttpContext>any())).thenReturn(socket);
257
258 connectionOperator.upgrade(conn, host, context);
259
260 Mockito.verify(conn).bind(socket);
261 }
262
263 @Test(expected=UnsupportedSchemeException.class)
264 public void testUpgradeUpsupportedScheme() throws Exception {
265 final HttpContext context = new BasicHttpContext();
266 final HttpHost host = new HttpHost("httpsssss", "somehost", -1);
267 Mockito.when(socketFactoryRegistry.lookup("http")).thenReturn(plainSocketFactory);
268
269 connectionOperator.upgrade(conn, host, context);
270 }
271
272 @Test(expected=UnsupportedSchemeException.class)
273 public void testUpgradeNonLayeringScheme() throws Exception {
274 final HttpContext context = new BasicHttpContext();
275 final HttpHost host = new HttpHost("http", "somehost", -1);
276 Mockito.when(socketFactoryRegistry.lookup("http")).thenReturn(plainSocketFactory);
277
278 connectionOperator.upgrade(conn, host, context);
279 }
280
281 }