1
2
3
4
5
6
7
8
9
10 package org.eclipse.jgit.transport.http.apache;
11
12 import static org.eclipse.jgit.util.HttpSupport.METHOD_GET;
13 import static org.eclipse.jgit.util.HttpSupport.METHOD_HEAD;
14 import static org.eclipse.jgit.util.HttpSupport.METHOD_POST;
15 import static org.eclipse.jgit.util.HttpSupport.METHOD_PUT;
16
17 import java.io.IOException;
18 import java.io.InputStream;
19 import java.io.OutputStream;
20 import java.net.InetSocketAddress;
21 import java.net.MalformedURLException;
22 import java.net.ProtocolException;
23 import java.net.Proxy;
24 import java.net.URL;
25 import java.security.KeyManagementException;
26 import java.security.NoSuchAlgorithmException;
27 import java.security.SecureRandom;
28 import java.util.Arrays;
29 import java.util.Collections;
30 import java.util.HashMap;
31 import java.util.LinkedList;
32 import java.util.List;
33 import java.util.Map;
34 import java.util.stream.Collectors;
35
36 import javax.net.ssl.HostnameVerifier;
37 import javax.net.ssl.KeyManager;
38 import javax.net.ssl.SSLContext;
39 import javax.net.ssl.SSLSocket;
40 import javax.net.ssl.TrustManager;
41
42 import org.apache.http.Header;
43 import org.apache.http.HeaderElement;
44 import org.apache.http.HttpEntity;
45 import org.apache.http.HttpEntityEnclosingRequest;
46 import org.apache.http.HttpHost;
47 import org.apache.http.HttpResponse;
48 import org.apache.http.client.ClientProtocolException;
49 import org.apache.http.client.HttpClient;
50 import org.apache.http.client.config.RequestConfig;
51 import org.apache.http.client.methods.HttpGet;
52 import org.apache.http.client.methods.HttpHead;
53 import org.apache.http.client.methods.HttpPost;
54 import org.apache.http.client.methods.HttpPut;
55 import org.apache.http.client.methods.HttpUriRequest;
56 import org.apache.http.config.Registry;
57 import org.apache.http.config.RegistryBuilder;
58 import org.apache.http.conn.socket.ConnectionSocketFactory;
59 import org.apache.http.conn.socket.PlainConnectionSocketFactory;
60 import org.apache.http.conn.ssl.DefaultHostnameVerifier;
61 import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
62 import org.apache.http.conn.util.PublicSuffixMatcherLoader;
63 import org.apache.http.impl.client.HttpClientBuilder;
64 import org.apache.http.impl.client.HttpClients;
65 import org.apache.http.impl.client.SystemDefaultCredentialsProvider;
66 import org.apache.http.impl.conn.BasicHttpClientConnectionManager;
67 import org.apache.http.ssl.SSLContexts;
68 import org.eclipse.jgit.annotations.NonNull;
69 import org.eclipse.jgit.transport.http.HttpConnection;
70 import org.eclipse.jgit.transport.http.apache.internal.HttpApacheText;
71 import org.eclipse.jgit.util.HttpSupport;
72 import org.eclipse.jgit.util.TemporaryBuffer;
73 import org.eclipse.jgit.util.TemporaryBuffer.LocalFile;
74
75
76
77
78
79
80
81 public class HttpClientConnection implements HttpConnection {
82 HttpClient client;
83
84 URL url;
85
86 HttpUriRequest req;
87
88 HttpResponse resp = null;
89
90 String method = "GET";
91
92 private TemporaryBufferEntity entity;
93
94 private boolean isUsingProxy = false;
95
96 private Proxy proxy;
97
98 private Integer timeout = null;
99
100 private Integer readTimeout;
101
102 private Boolean followRedirects;
103
104 private HostnameVerifier hostnameverifier;
105
106 SSLContext ctx;
107
108 private HttpClient getClient() {
109 if (client == null) {
110 HttpClientBuilder clientBuilder = HttpClients.custom();
111 RequestConfig.Builder configBuilder = RequestConfig.custom();
112 if (proxy != null && !Proxy.NO_PROXY.equals(proxy)) {
113 isUsingProxy = true;
114 InetSocketAddress adr = (InetSocketAddress) proxy.address();
115 clientBuilder.setProxy(
116 new HttpHost(adr.getHostName(), adr.getPort()));
117 }
118 if (timeout != null) {
119 configBuilder.setConnectTimeout(timeout.intValue());
120 }
121 if (readTimeout != null) {
122 configBuilder.setSocketTimeout(readTimeout.intValue());
123 }
124 if (followRedirects != null) {
125 configBuilder
126 .setRedirectsEnabled(followRedirects.booleanValue());
127 }
128 SSLConnectionSocketFactory sslConnectionFactory = getSSLSocketFactory();
129 clientBuilder.setSSLSocketFactory(sslConnectionFactory);
130 if (hostnameverifier != null) {
131
132
133 Registry<ConnectionSocketFactory> registry = RegistryBuilder
134 .<ConnectionSocketFactory> create()
135 .register("https", sslConnectionFactory)
136 .register("http", PlainConnectionSocketFactory.INSTANCE)
137 .build();
138 clientBuilder.setConnectionManager(
139 new BasicHttpClientConnectionManager(registry));
140 }
141 clientBuilder.setDefaultRequestConfig(configBuilder.build());
142 clientBuilder.setDefaultCredentialsProvider(
143 new SystemDefaultCredentialsProvider());
144 client = clientBuilder.build();
145 }
146
147 return client;
148 }
149
150 private SSLConnectionSocketFactory getSSLSocketFactory() {
151 HostnameVerifier verifier = hostnameverifier;
152 SSLContext context;
153 if (verifier == null) {
154
155 context = SSLContexts.createDefault();
156 verifier = new DefaultHostnameVerifier(
157 PublicSuffixMatcherLoader.getDefault());
158 } else {
159
160
161
162
163
164 context = getSSLContext();
165 }
166 return new SSLConnectionSocketFactory(context, verifier) {
167
168 @Override
169 protected void prepareSocket(SSLSocket socket) throws IOException {
170 super.prepareSocket(socket);
171 HttpSupport.configureTLS(socket);
172 }
173 };
174 }
175
176 private SSLContext getSSLContext() {
177 if (ctx == null) {
178 try {
179 ctx = SSLContext.getInstance("TLS");
180 } catch (NoSuchAlgorithmException e) {
181 throw new IllegalStateException(
182 HttpApacheText.get().unexpectedSSLContextException, e);
183 }
184 }
185 return ctx;
186 }
187
188
189
190
191
192
193 public void setBuffer(TemporaryBuffer buffer) {
194 this.entity = new TemporaryBufferEntity(buffer);
195 }
196
197
198
199
200
201
202
203 public HttpClientConnection(String urlStr) throws MalformedURLException {
204 this(urlStr, null);
205 }
206
207
208
209
210
211
212
213
214 public HttpClientConnection(String urlStr, Proxy proxy)
215 throws MalformedURLException {
216 this(urlStr, proxy, null);
217 }
218
219
220
221
222
223
224
225
226
227 public HttpClientConnection(String urlStr, Proxy proxy, HttpClient cl)
228 throws MalformedURLException {
229 this.client = cl;
230 this.url = new URL(urlStr);
231 this.proxy = proxy;
232 }
233
234
235 @Override
236 public int getResponseCode() throws IOException {
237 execute();
238 return resp.getStatusLine().getStatusCode();
239 }
240
241
242 @Override
243 public URL getURL() {
244 return url;
245 }
246
247
248 @Override
249 public String getResponseMessage() throws IOException {
250 execute();
251 return resp.getStatusLine().getReasonPhrase();
252 }
253
254 private void execute() throws IOException, ClientProtocolException {
255 if (resp != null) {
256 return;
257 }
258
259 if (entity == null) {
260 resp = getClient().execute(req);
261 return;
262 }
263
264 try {
265 if (req instanceof HttpEntityEnclosingRequest) {
266 HttpEntityEnclosingRequest eReq = (HttpEntityEnclosingRequest) req;
267 eReq.setEntity(entity);
268 }
269 resp = getClient().execute(req);
270 } finally {
271 entity.close();
272 entity = null;
273 }
274 }
275
276
277 @Override
278 public Map<String, List<String>> getHeaderFields() {
279 Map<String, List<String>> ret = new HashMap<>();
280 for (Header hdr : resp.getAllHeaders()) {
281 List<String> list = ret.get(hdr.getName());
282 if (list == null) {
283 list = new LinkedList<>();
284 ret.put(hdr.getName(), list);
285 }
286 for (HeaderElement hdrElem : hdr.getElements()) {
287 list.add(hdrElem.toString());
288 }
289 }
290 return ret;
291 }
292
293
294 @Override
295 public void setRequestProperty(String name, String value) {
296 req.addHeader(name, value);
297 }
298
299
300 @Override
301 public void setRequestMethod(String method) throws ProtocolException {
302 this.method = method;
303 if (METHOD_GET.equalsIgnoreCase(method)) {
304 req = new HttpGet(url.toString());
305 } else if (METHOD_HEAD.equalsIgnoreCase(method)) {
306 req = new HttpHead(url.toString());
307 } else if (METHOD_PUT.equalsIgnoreCase(method)) {
308 req = new HttpPut(url.toString());
309 } else if (METHOD_POST.equalsIgnoreCase(method)) {
310 req = new HttpPost(url.toString());
311 } else {
312 this.method = null;
313 throw new UnsupportedOperationException();
314 }
315 }
316
317
318 @Override
319 public void setUseCaches(boolean usecaches) {
320
321 }
322
323
324 @Override
325 public void setConnectTimeout(int timeout) {
326 this.timeout = Integer.valueOf(timeout);
327 }
328
329
330 @Override
331 public void setReadTimeout(int readTimeout) {
332 this.readTimeout = Integer.valueOf(readTimeout);
333 }
334
335
336 @Override
337 public String getContentType() {
338 HttpEntity responseEntity = resp.getEntity();
339 if (responseEntity != null) {
340 Header contentType = responseEntity.getContentType();
341 if (contentType != null)
342 return contentType.getValue();
343 }
344 return null;
345 }
346
347
348 @Override
349 public InputStream getInputStream() throws IOException {
350 execute();
351 return resp.getEntity().getContent();
352 }
353
354
355
356 @Override
357 public String getHeaderField(@NonNull String name) {
358 Header header = resp.getFirstHeader(name);
359 return (header == null) ? null : header.getValue();
360 }
361
362 @Override
363 public List<String> getHeaderFields(@NonNull String name) {
364 return Collections.unmodifiableList(Arrays.asList(resp.getHeaders(name))
365 .stream().map(Header::getValue).collect(Collectors.toList()));
366 }
367
368
369 @Override
370 public int getContentLength() {
371 Header contentLength = resp.getFirstHeader("content-length");
372 if (contentLength == null) {
373 return -1;
374 }
375
376 try {
377 int l = Integer.parseInt(contentLength.getValue());
378 return l < 0 ? -1 : l;
379 } catch (NumberFormatException e) {
380 return -1;
381 }
382 }
383
384
385 @Override
386 public void setInstanceFollowRedirects(boolean followRedirects) {
387 this.followRedirects = Boolean.valueOf(followRedirects);
388 }
389
390
391 @Override
392 public void setDoOutput(boolean dooutput) {
393
394 }
395
396
397 @Override
398 public void setFixedLengthStreamingMode(int contentLength) {
399 if (entity != null)
400 throw new IllegalArgumentException();
401 entity = new TemporaryBufferEntity(new LocalFile(null));
402 entity.setContentLength(contentLength);
403 }
404
405
406 @Override
407 public OutputStream getOutputStream() throws IOException {
408 if (entity == null)
409 entity = new TemporaryBufferEntity(new LocalFile(null));
410 return entity.getBuffer();
411 }
412
413
414 @Override
415 public void setChunkedStreamingMode(int chunklen) {
416 if (entity == null)
417 entity = new TemporaryBufferEntity(new LocalFile(null));
418 entity.setChunked(true);
419 }
420
421
422 @Override
423 public String getRequestMethod() {
424 return method;
425 }
426
427
428 @Override
429 public boolean usingProxy() {
430 return isUsingProxy;
431 }
432
433
434 @Override
435 public void connect() throws IOException {
436 execute();
437 }
438
439
440 @Override
441 public void setHostnameVerifier(HostnameVerifier hostnameverifier) {
442 this.hostnameverifier = hostnameverifier;
443 }
444
445
446 @Override
447 public void configure(KeyManager[] km, TrustManager[] tm,
448 SecureRandom random) throws KeyManagementException {
449 getSSLContext().init(km, tm, random);
450 }
451 }