1 /*
2 * Copyright (C) 2010, Google Inc.
3 * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org>
4 * and other copyright owners as documented in the project's IP log.
5 *
6 * This program and the accompanying materials are made available
7 * under the terms of the Eclipse Distribution License v1.0 which
8 * accompanies this distribution, is reproduced below, and is
9 * available at http://www.eclipse.org/org/documents/edl-v10.php
10 *
11 * All rights reserved.
12 *
13 * Redistribution and use in source and binary forms, with or
14 * without modification, are permitted provided that the following
15 * conditions are met:
16 *
17 * - Redistributions of source code must retain the above copyright
18 * notice, this list of conditions and the following disclaimer.
19 *
20 * - Redistributions in binary form must reproduce the above
21 * copyright notice, this list of conditions and the following
22 * disclaimer in the documentation and/or other materials provided
23 * with the distribution.
24 *
25 * - Neither the name of the Eclipse Foundation, Inc. nor the
26 * names of its contributors may be used to endorse or promote
27 * products derived from this software without specific prior
28 * written permission.
29 *
30 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
31 * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
32 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
33 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
34 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
35 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
36 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
37 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
38 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
39 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
40 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
41 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
42 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
43 */
44
45 package org.eclipse.jgit.util;
46
47 import java.io.IOException;
48 import java.io.UnsupportedEncodingException;
49 import java.net.ConnectException;
50 import java.net.Proxy;
51 import java.net.ProxySelector;
52 import java.net.URISyntaxException;
53 import java.net.URL;
54 import java.net.URLEncoder;
55 import java.security.KeyManagementException;
56 import java.security.NoSuchAlgorithmException;
57 import java.security.cert.X509Certificate;
58 import java.text.MessageFormat;
59
60 import javax.net.ssl.HostnameVerifier;
61 import javax.net.ssl.SSLSession;
62 import javax.net.ssl.TrustManager;
63 import javax.net.ssl.X509TrustManager;
64
65 import org.eclipse.jgit.internal.JGitText;
66 import org.eclipse.jgit.transport.http.HttpConnection;
67
68 /** Extra utilities to support usage of HTTP. */
69 public class HttpSupport {
70 /** The {@code GET} HTTP method. */
71 public static final String METHOD_GET = "GET"; //$NON-NLS-1$
72
73 /** The {@code HEAD} HTTP method.
74 * @since 4.3 */
75 public static final String METHOD_HEAD = "HEAD"; //$NON-NLS-1$
76
77 /** The {@code POST} HTTP method.
78 * @since 4.3 */
79 public static final String METHOD_PUT = "PUT"; //$NON-NLS-1$
80
81 /** The {@code POST} HTTP method. */
82 public static final String METHOD_POST = "POST"; //$NON-NLS-1$
83
84 /** The {@code Cache-Control} header. */
85 public static final String HDR_CACHE_CONTROL = "Cache-Control"; //$NON-NLS-1$
86
87 /** The {@code Pragma} header. */
88 public static final String HDR_PRAGMA = "Pragma"; //$NON-NLS-1$
89
90 /** The {@code User-Agent} header. */
91 public static final String HDR_USER_AGENT = "User-Agent"; //$NON-NLS-1$
92
93 /**
94 * The {@code Server} header.
95 * @since 4.0
96 */
97 public static final String HDR_SERVER = "Server"; //$NON-NLS-1$
98
99 /** The {@code Date} header. */
100 public static final String HDR_DATE = "Date"; //$NON-NLS-1$
101
102 /** The {@code Expires} header. */
103 public static final String HDR_EXPIRES = "Expires"; //$NON-NLS-1$
104
105 /** The {@code ETag} header. */
106 public static final String HDR_ETAG = "ETag"; //$NON-NLS-1$
107
108 /** The {@code If-None-Match} header. */
109 public static final String HDR_IF_NONE_MATCH = "If-None-Match"; //$NON-NLS-1$
110
111 /** The {@code Last-Modified} header. */
112 public static final String HDR_LAST_MODIFIED = "Last-Modified"; //$NON-NLS-1$
113
114 /** The {@code If-Modified-Since} header. */
115 public static final String HDR_IF_MODIFIED_SINCE = "If-Modified-Since"; //$NON-NLS-1$
116
117 /** The {@code Accept} header. */
118 public static final String HDR_ACCEPT = "Accept"; //$NON-NLS-1$
119
120 /** The {@code Content-Type} header. */
121 public static final String HDR_CONTENT_TYPE = "Content-Type"; //$NON-NLS-1$
122
123 /** The {@code Content-Length} header. */
124 public static final String HDR_CONTENT_LENGTH = "Content-Length"; //$NON-NLS-1$
125
126 /** The {@code Content-Encoding} header. */
127 public static final String HDR_CONTENT_ENCODING = "Content-Encoding"; //$NON-NLS-1$
128
129 /** The {@code Content-Range} header. */
130 public static final String HDR_CONTENT_RANGE = "Content-Range"; //$NON-NLS-1$
131
132 /** The {@code Accept-Ranges} header. */
133 public static final String HDR_ACCEPT_RANGES = "Accept-Ranges"; //$NON-NLS-1$
134
135 /** The {@code If-Range} header. */
136 public static final String HDR_IF_RANGE = "If-Range"; //$NON-NLS-1$
137
138 /** The {@code Range} header. */
139 public static final String HDR_RANGE = "Range"; //$NON-NLS-1$
140
141 /** The {@code Accept-Encoding} header. */
142 public static final String HDR_ACCEPT_ENCODING = "Accept-Encoding"; //$NON-NLS-1$
143
144 /** The {@code gzip} encoding value for {@link #HDR_ACCEPT_ENCODING}. */
145 public static final String ENCODING_GZIP = "gzip"; //$NON-NLS-1$
146
147 /** The standard {@code text/plain} MIME type. */
148 public static final String TEXT_PLAIN = "text/plain"; //$NON-NLS-1$
149
150 /** The {@code Authorization} header. */
151 public static final String HDR_AUTHORIZATION = "Authorization"; //$NON-NLS-1$
152
153 /** The {@code WWW-Authenticate} header. */
154 public static final String HDR_WWW_AUTHENTICATE = "WWW-Authenticate"; //$NON-NLS-1$
155
156 /**
157 * URL encode a value string into an output buffer.
158 *
159 * @param urlstr
160 * the output buffer.
161 * @param key
162 * value which must be encoded to protected special characters.
163 */
164 public static void encode(final StringBuilder urlstr, final String key) {
165 if (key == null || key.length() == 0)
166 return;
167 try {
168 urlstr.append(URLEncoder.encode(key, "UTF-8")); //$NON-NLS-1$
169 } catch (UnsupportedEncodingException e) {
170 throw new RuntimeException(JGitText.get().couldNotURLEncodeToUTF8, e);
171 }
172 }
173
174 /**
175 * Get the HTTP response code from the request.
176 * <p>
177 * Roughly the same as <code>c.getResponseCode()</code> but the
178 * ConnectException is translated to be more understandable.
179 *
180 * @param c
181 * connection the code should be obtained from.
182 * @return r HTTP status code, usually 200 to indicate success. See
183 * {@link HttpConnection} for other defined constants.
184 * @throws IOException
185 * communications error prevented obtaining the response code.
186 * @since 3.3
187 */
188 public static int response(final HttpConnection c) throws IOException {
189 try {
190 return c.getResponseCode();
191 } catch (ConnectException ce) {
192 final URL url = c.getURL();
193 final String host = (url == null) ? "<null>" : url.getHost(); //$NON-NLS-1$
194 // The standard J2SE error message is not very useful.
195 //
196 if ("Connection timed out: connect".equals(ce.getMessage())) //$NON-NLS-1$
197 throw new ConnectException(MessageFormat.format(JGitText.get().connectionTimeOut, host));
198 throw new ConnectException(ce.getMessage() + " " + host); //$NON-NLS-1$
199 }
200 }
201
202 /**
203 * Get the HTTP response code from the request.
204 * <p>
205 * Roughly the same as <code>c.getResponseCode()</code> but the
206 * ConnectException is translated to be more understandable.
207 *
208 * @param c
209 * connection the code should be obtained from.
210 * @return r HTTP status code, usually 200 to indicate success. See
211 * {@link HttpConnection} for other defined constants.
212 * @throws IOException
213 * communications error prevented obtaining the response code.
214 */
215 public static int response(final java.net.HttpURLConnection c)
216 throws IOException {
217 try {
218 return c.getResponseCode();
219 } catch (ConnectException ce) {
220 final URL url = c.getURL();
221 final String host = (url == null) ? "<null>" : url.getHost(); //$NON-NLS-1$
222 // The standard J2SE error message is not very useful.
223 //
224 if ("Connection timed out: connect".equals(ce.getMessage())) //$NON-NLS-1$
225 throw new ConnectException(MessageFormat.format(
226 JGitText.get().connectionTimeOut, host));
227 throw new ConnectException(ce.getMessage() + " " + host); //$NON-NLS-1$
228 }
229 }
230
231 /**
232 * Determine the proxy server (if any) needed to obtain a URL.
233 *
234 * @param proxySelector
235 * proxy support for the caller.
236 * @param u
237 * location of the server caller wants to talk to.
238 * @return proxy to communicate with the supplied URL.
239 * @throws ConnectException
240 * the proxy could not be computed as the supplied URL could not
241 * be read. This failure should never occur.
242 */
243 public static Proxy proxyFor(final ProxySelector proxySelector, final URL u)
244 throws ConnectException {
245 try {
246 return proxySelector.select(u.toURI()).get(0);
247 } catch (URISyntaxException e) {
248 final ConnectException err;
249 err = new ConnectException(MessageFormat.format(JGitText.get().cannotDetermineProxyFor, u));
250 err.initCause(e);
251 throw err;
252 }
253 }
254
255 /**
256 * Disable SSL and hostname verification for given HTTP connection
257 *
258 * @param conn
259 * @throws IOException
260 * @since 4.3
261 */
262 public static void disableSslVerify(HttpConnection conn)
263 throws IOException {
264 final TrustManager[] trustAllCerts = new TrustManager[] {
265 new DummyX509TrustManager() };
266 try {
267 conn.configure(null, trustAllCerts, null);
268 conn.setHostnameVerifier(new DummyHostnameVerifier());
269 } catch (KeyManagementException e) {
270 throw new IOException(e.getMessage());
271 } catch (NoSuchAlgorithmException e) {
272 throw new IOException(e.getMessage());
273 }
274 }
275
276 private static class DummyX509TrustManager implements X509TrustManager {
277 public X509Certificate[] getAcceptedIssuers() {
278 return null;
279 }
280
281 public void checkClientTrusted(X509Certificate[] certs,
282 String authType) {
283 // no check
284 }
285
286 public void checkServerTrusted(X509Certificate[] certs,
287 String authType) {
288 // no check
289 }
290 }
291
292 private static class DummyHostnameVerifier implements HostnameVerifier {
293 public boolean verify(String hostname, SSLSession session) {
294 // always accept
295 return true;
296 }
297 }
298
299 private HttpSupport() {
300 // Utility class only.
301 }
302 }