View Javadoc
1   /*
2    * Copyright (C) 2013, 2020 Christian Halstrick <christian.halstrick@sap.com> and others
3    *
4    * This program and the accompanying materials are made available under the
5    * terms of the Eclipse Distribution License v. 1.0 which is available at
6    * https://www.eclipse.org/org/documents/edl-v10.php.
7    *
8    * SPDX-License-Identifier: BSD-3-Clause
9    */
10  package org.eclipse.jgit.transport.http;
11  
12  import java.io.IOException;
13  import java.io.InputStream;
14  import java.io.OutputStream;
15  import java.net.HttpURLConnection;
16  import java.net.MalformedURLException;
17  import java.net.ProtocolException;
18  import java.net.Proxy;
19  import java.net.URL;
20  import java.security.KeyManagementException;
21  import java.security.NoSuchAlgorithmException;
22  import java.security.SecureRandom;
23  import java.util.LinkedList;
24  import java.util.List;
25  import java.util.Map;
26  
27  import javax.net.ssl.HostnameVerifier;
28  import javax.net.ssl.HttpsURLConnection;
29  import javax.net.ssl.KeyManager;
30  import javax.net.ssl.SSLContext;
31  import javax.net.ssl.SSLSocket;
32  import javax.net.ssl.TrustManager;
33  
34  import org.eclipse.jgit.annotations.NonNull;
35  import org.eclipse.jgit.internal.transport.http.DelegatingSSLSocketFactory;
36  import org.eclipse.jgit.util.HttpSupport;
37  /**
38   * A {@link org.eclipse.jgit.transport.http.HttpConnection} which simply
39   * delegates every call to a {@link java.net.HttpURLConnection}. This is the
40   * default implementation used by JGit
41   *
42   * @since 3.3
43   */
44  public class JDKHttpConnection implements HttpConnection {
45  	HttpURLConnection wrappedUrlConnection;
46  
47  	// used for mock testing
48  	JDKHttpConnection(HttpURLConnection urlConnection) {
49  		this.wrappedUrlConnection = urlConnection;
50  	}
51  
52  	/**
53  	 * Constructor for JDKHttpConnection.
54  	 *
55  	 * @param url
56  	 *            a {@link java.net.URL} object.
57  	 * @throws java.net.MalformedURLException
58  	 * @throws java.io.IOException
59  	 */
60  	protected JDKHttpConnection(URL url)
61  			throws MalformedURLException,
62  			IOException {
63  		this.wrappedUrlConnection = (HttpURLConnection) url.openConnection();
64  	}
65  
66  	/**
67  	 * Constructor for JDKHttpConnection.
68  	 *
69  	 * @param url
70  	 *            a {@link java.net.URL} object.
71  	 * @param proxy
72  	 *            a {@link java.net.Proxy} object.
73  	 * @throws java.net.MalformedURLException
74  	 * @throws java.io.IOException
75  	 */
76  	protected JDKHttpConnection(URL url, Proxy proxy)
77  			throws MalformedURLException, IOException {
78  		this.wrappedUrlConnection = (HttpURLConnection) url
79  				.openConnection(proxy);
80  	}
81  
82  	/** {@inheritDoc} */
83  	@Override
84  	public int getResponseCode() throws IOException {
85  		return wrappedUrlConnection.getResponseCode();
86  	}
87  
88  	/** {@inheritDoc} */
89  	@Override
90  	public URL getURL() {
91  		return wrappedUrlConnection.getURL();
92  	}
93  
94  	/** {@inheritDoc} */
95  	@Override
96  	public String getResponseMessage() throws IOException {
97  		return wrappedUrlConnection.getResponseMessage();
98  	}
99  
100 	/** {@inheritDoc} */
101 	@Override
102 	public Map<String, List<String>> getHeaderFields() {
103 		return wrappedUrlConnection.getHeaderFields();
104 	}
105 
106 	/** {@inheritDoc} */
107 	@Override
108 	public void setRequestProperty(String key, String value) {
109 		wrappedUrlConnection.setRequestProperty(key, value);
110 	}
111 
112 	/** {@inheritDoc} */
113 	@Override
114 	public void setRequestMethod(String method) throws ProtocolException {
115 		wrappedUrlConnection.setRequestMethod(method);
116 	}
117 
118 	/** {@inheritDoc} */
119 	@Override
120 	public void setUseCaches(boolean usecaches) {
121 		wrappedUrlConnection.setUseCaches(usecaches);
122 	}
123 
124 	/** {@inheritDoc} */
125 	@Override
126 	public void setConnectTimeout(int timeout) {
127 		wrappedUrlConnection.setConnectTimeout(timeout);
128 	}
129 
130 	/** {@inheritDoc} */
131 	@Override
132 	public void setReadTimeout(int timeout) {
133 		wrappedUrlConnection.setReadTimeout(timeout);
134 	}
135 
136 	/** {@inheritDoc} */
137 	@Override
138 	public String getContentType() {
139 		return wrappedUrlConnection.getContentType();
140 	}
141 
142 	/** {@inheritDoc} */
143 	@Override
144 	public InputStream getInputStream() throws IOException {
145 		return wrappedUrlConnection.getInputStream();
146 	}
147 
148 	/** {@inheritDoc} */
149 	@Override
150 	public String getHeaderField(@NonNull String name) {
151 		return wrappedUrlConnection.getHeaderField(name);
152 	}
153 
154 	@Override
155 	public List<String> getHeaderFields(@NonNull String name) {
156 		Map<String, List<String>> m = wrappedUrlConnection.getHeaderFields();
157 		List<String> fields = mapValuesToListIgnoreCase(name, m);
158 		return fields;
159 	}
160 
161 	private static List<String> mapValuesToListIgnoreCase(String keyName,
162 			Map<String, List<String>> m) {
163 		List<String> fields = new LinkedList<>();
164 		m.entrySet().stream().filter(e -> keyName.equalsIgnoreCase(e.getKey()))
165 				.filter(e -> e.getValue() != null)
166 				.forEach(e -> fields.addAll(e.getValue()));
167 		return fields;
168 	}
169 
170 	/** {@inheritDoc} */
171 	@Override
172 	public int getContentLength() {
173 		return wrappedUrlConnection.getContentLength();
174 	}
175 
176 	/** {@inheritDoc} */
177 	@Override
178 	public void setInstanceFollowRedirects(boolean followRedirects) {
179 		wrappedUrlConnection.setInstanceFollowRedirects(followRedirects);
180 	}
181 
182 	/** {@inheritDoc} */
183 	@Override
184 	public void setDoOutput(boolean dooutput) {
185 		wrappedUrlConnection.setDoOutput(dooutput);
186 	}
187 
188 	/** {@inheritDoc} */
189 	@Override
190 	public void setFixedLengthStreamingMode(int contentLength) {
191 		wrappedUrlConnection.setFixedLengthStreamingMode(contentLength);
192 	}
193 
194 	/** {@inheritDoc} */
195 	@Override
196 	public OutputStream getOutputStream() throws IOException {
197 		return wrappedUrlConnection.getOutputStream();
198 	}
199 
200 	/** {@inheritDoc} */
201 	@Override
202 	public void setChunkedStreamingMode(int chunklen) {
203 		wrappedUrlConnection.setChunkedStreamingMode(chunklen);
204 	}
205 
206 	/** {@inheritDoc} */
207 	@Override
208 	public String getRequestMethod() {
209 		return wrappedUrlConnection.getRequestMethod();
210 	}
211 
212 	/** {@inheritDoc} */
213 	@Override
214 	public boolean usingProxy() {
215 		return wrappedUrlConnection.usingProxy();
216 	}
217 
218 	/** {@inheritDoc} */
219 	@Override
220 	public void connect() throws IOException {
221 		wrappedUrlConnection.connect();
222 	}
223 
224 	/** {@inheritDoc} */
225 	@Override
226 	public void setHostnameVerifier(HostnameVerifier hostnameverifier) {
227 		((HttpsURLConnection) wrappedUrlConnection)
228 				.setHostnameVerifier(hostnameverifier);
229 	}
230 
231 	/** {@inheritDoc} */
232 	@Override
233 	public void configure(KeyManager[] km, TrustManager[] tm,
234 			SecureRandom random) throws NoSuchAlgorithmException,
235 			KeyManagementException {
236 		SSLContext ctx = SSLContext.getInstance("TLS"); //$NON-NLS-1$
237 		ctx.init(km, tm, random);
238 		((HttpsURLConnection) wrappedUrlConnection).setSSLSocketFactory(
239 				new DelegatingSSLSocketFactory(ctx.getSocketFactory()) {
240 
241 					@Override
242 					protected void configure(SSLSocket socket)
243 							throws IOException {
244 						HttpSupport.configureTLS(socket);
245 					}
246 				});
247 	}
248 
249 }