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