Mercurial > jhg
comparison src/org/tmatesoft/hg/internal/remote/HttpConnector.java @ 699:a483b2b68a2e
Provisional APIs and respective implementation for http, https and ssh remote repositories
author | Artem Tikhomirov <tikhomirov.artem@gmail.com> |
---|---|
date | Thu, 08 Aug 2013 19:18:50 +0200 |
parents | 822f3a83ff57 |
children |
comparison
equal
deleted
inserted
replaced
698:822f3a83ff57 | 699:a483b2b68a2e |
---|---|
14 * the terms of a license other than GNU General Public License | 14 * the terms of a license other than GNU General Public License |
15 * contact TMate Software at support@hg4j.com | 15 * contact TMate Software at support@hg4j.com |
16 */ | 16 */ |
17 package org.tmatesoft.hg.internal.remote; | 17 package org.tmatesoft.hg.internal.remote; |
18 | 18 |
19 import static org.tmatesoft.hg.util.LogFacility.Severity.Info; | |
20 | |
21 import java.io.BufferedReader; | 19 import java.io.BufferedReader; |
22 import java.io.ByteArrayInputStream; | 20 import java.io.ByteArrayInputStream; |
23 import java.io.FilterOutputStream; | 21 import java.io.FilterOutputStream; |
24 import java.io.IOException; | 22 import java.io.IOException; |
25 import java.io.InputStream; | 23 import java.io.InputStream; |
26 import java.io.InputStreamReader; | 24 import java.io.InputStreamReader; |
27 import java.io.OutputStream; | 25 import java.io.OutputStream; |
28 import java.io.SequenceInputStream; | 26 import java.io.SequenceInputStream; |
29 import java.net.HttpURLConnection; | 27 import java.net.HttpURLConnection; |
30 import java.net.MalformedURLException; | 28 import java.net.MalformedURLException; |
31 import java.net.URI; | |
32 import java.net.URL; | 29 import java.net.URL; |
33 import java.net.URLConnection; | 30 import java.net.URLConnection; |
34 import java.security.cert.CertificateException; | |
35 import java.security.cert.X509Certificate; | |
36 import java.util.Collection; | 31 import java.util.Collection; |
37 import java.util.List; | 32 import java.util.List; |
38 import java.util.Map; | 33 import java.util.Map; |
39 import java.util.prefs.BackingStoreException; | 34 |
40 import java.util.prefs.Preferences; | 35 import org.tmatesoft.hg.auth.HgAuthFailedException; |
41 | 36 import org.tmatesoft.hg.auth.HgAuthenticator; |
42 import javax.net.ssl.HttpsURLConnection; | |
43 import javax.net.ssl.SSLContext; | |
44 import javax.net.ssl.TrustManager; | |
45 import javax.net.ssl.X509TrustManager; | |
46 | |
47 import org.tmatesoft.hg.core.HgRemoteConnectionException; | 37 import org.tmatesoft.hg.core.HgRemoteConnectionException; |
48 import org.tmatesoft.hg.core.Nodeid; | 38 import org.tmatesoft.hg.core.Nodeid; |
49 import org.tmatesoft.hg.core.SessionContext; | 39 import org.tmatesoft.hg.core.SessionContext; |
50 import org.tmatesoft.hg.internal.PropertyMarshal; | 40 import org.tmatesoft.hg.internal.PropertyMarshal; |
51 import org.tmatesoft.hg.repo.HgRemoteRepository.Range; | 41 import org.tmatesoft.hg.repo.HgRemoteRepository.Range; |
42 import org.tmatesoft.hg.repo.HgRemoteRepository.RemoteDescriptor; | |
52 import org.tmatesoft.hg.repo.HgRuntimeException; | 43 import org.tmatesoft.hg.repo.HgRuntimeException; |
53 | 44 |
54 /** | 45 /** |
55 * | 46 * |
56 * @author Artem Tikhomirov | 47 * @author Artem Tikhomirov |
57 * @author TMate Software Ltd. | 48 * @author TMate Software Ltd. |
58 */ | 49 */ |
59 public class HttpConnector implements Connector { | 50 public class HttpConnector extends ConnectorBase { |
60 private URI uri; | 51 private RemoteDescriptor rd; |
61 private URL url; | 52 private URL url; |
62 private SSLContext sslContext; | |
63 private String authInfo; | |
64 private boolean debug; | 53 private boolean debug; |
65 private SessionContext sessionCtx; | 54 private SessionContext sessionCtx; |
66 // | 55 // |
67 private HttpURLConnection conn; | 56 private HttpURLConnection conn; |
68 | 57 private HttpAuthMethod authMediator; |
69 public void init(URI uri, SessionContext sessionContext, Object globalConfig) throws HgRuntimeException { | 58 |
70 this.uri = uri; | 59 public void init(RemoteDescriptor remote, SessionContext sessionContext, Object globalConfig) throws HgRuntimeException { |
60 rd = remote; | |
61 setURI(remote.getURI()); | |
71 sessionCtx = sessionContext; | 62 sessionCtx = sessionContext; |
72 debug = new PropertyMarshal(sessionCtx).getBoolean("hg4j.remote.debug", false); | 63 debug = new PropertyMarshal(sessionContext).getBoolean("hg4j.remote.debug", false); |
73 if (uri.getUserInfo() != null) { | 64 } |
74 String ai = null; | 65 |
66 public void connect() throws HgAuthFailedException, HgRemoteConnectionException, HgRuntimeException { | |
67 try { | |
68 url = uri.toURL(); | |
69 } catch (MalformedURLException ex) { | |
70 throw new HgRemoteConnectionException("Bad URL", ex); | |
71 } | |
72 authMediator = new HttpAuthMethod(sessionCtx, url); | |
73 authenticateClient(); | |
74 } | |
75 | |
76 private void authenticateClient() throws HgAuthFailedException { | |
77 String userInfo = url.getUserInfo(); | |
78 if (userInfo != null) { | |
75 try { | 79 try { |
76 // Hack to get Base64-encoded credentials | 80 authMediator.tryWithUserInfo(userInfo); |
77 Preferences tempNode = Preferences.userRoot().node("xxx"); | 81 } catch (HgAuthFailedException ex) { |
78 tempNode.putByteArray("xxx", uri.getUserInfo().getBytes()); | 82 // FALL THROUGH to try Authenticator |
79 ai = tempNode.get("xxx", null); | 83 } |
80 tempNode.removeNode(); | 84 } |
81 } catch (BackingStoreException ex) { | 85 HgAuthenticator auth = sessionCtx.getAuthenticator(rd); |
82 sessionContext.getLog().dump(getClass(), Info, ex, null); | 86 auth.authenticate(rd, authMediator); |
83 // IGNORE | |
84 } | |
85 authInfo = ai; | |
86 } else { | |
87 authInfo = null; | |
88 } | |
89 } | |
90 | |
91 public void connect() throws HgRemoteConnectionException, HgRuntimeException { | |
92 try { | |
93 url = uri.toURL(); | |
94 } catch (MalformedURLException ex) { | |
95 throw new HgRemoteConnectionException("Bad URL", ex); | |
96 } | |
97 if ("https".equals(url.getProtocol())) { | |
98 try { | |
99 sslContext = SSLContext.getInstance("SSL"); | |
100 class TrustEveryone implements X509TrustManager { | |
101 public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException { | |
102 if (debug) { | |
103 System.out.println("checkClientTrusted:" + authType); | |
104 } | |
105 } | |
106 public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException { | |
107 if (debug) { | |
108 System.out.println("checkServerTrusted:" + authType); | |
109 } | |
110 } | |
111 public X509Certificate[] getAcceptedIssuers() { | |
112 return new X509Certificate[0]; | |
113 } | |
114 }; | |
115 sslContext.init(null, new TrustManager[] { new TrustEveryone() }, null); | |
116 } catch (Exception ex) { | |
117 throw new HgRemoteConnectionException("Can't initialize secure connection", ex); | |
118 } | |
119 } else { | |
120 sslContext = null; | |
121 } | |
122 } | 87 } |
123 | 88 |
124 public void disconnect() throws HgRemoteConnectionException, HgRuntimeException { | 89 public void disconnect() throws HgRemoteConnectionException, HgRuntimeException { |
125 // TODO Auto-generated method stub | 90 // TODO Auto-generated method stub |
126 | 91 |
136 conn.disconnect(); | 101 conn.disconnect(); |
137 conn = null; | 102 conn = null; |
138 } | 103 } |
139 } | 104 } |
140 | 105 |
141 public String getServerLocation() { | |
142 if (uri.getUserInfo() == null) { | |
143 return uri.toString(); | |
144 } | |
145 if (uri.getPort() != -1) { | |
146 return String.format("%s://%s:%d%s", uri.getScheme(), uri.getHost(), uri.getPort(), uri.getPath()); | |
147 } else { | |
148 return String.format("%s://%s%s", uri.getScheme(), uri.getHost(), uri.getPath()); | |
149 } | |
150 } | |
151 | |
152 public String getCapabilities() throws HgRemoteConnectionException { | 106 public String getCapabilities() throws HgRemoteConnectionException { |
153 // say hello to server, check response | 107 // say hello to server, check response |
154 try { | 108 try { |
155 URL u = new URL(url, url.getPath() + "?cmd=hello"); | 109 URL u = new URL(url, url.getPath() + "?cmd=hello"); |
156 HttpURLConnection c = setupConnection(u.openConnection()); | 110 HttpURLConnection c = setupConnection(u.openConnection()); |
365 } | 319 } |
366 | 320 |
367 private HttpURLConnection setupConnection(URLConnection urlConnection) { | 321 private HttpURLConnection setupConnection(URLConnection urlConnection) { |
368 urlConnection.setRequestProperty("User-Agent", "hg4j/1.0.0"); | 322 urlConnection.setRequestProperty("User-Agent", "hg4j/1.0.0"); |
369 urlConnection.addRequestProperty("Accept", "application/mercurial-0.1"); | 323 urlConnection.addRequestProperty("Accept", "application/mercurial-0.1"); |
370 if (authInfo != null) { | 324 return authMediator.setupConnection((HttpURLConnection) urlConnection); |
371 urlConnection.addRequestProperty("Authorization", "Basic " + authInfo); | |
372 } | |
373 if (sslContext != null) { | |
374 ((HttpsURLConnection) urlConnection).setSSLSocketFactory(sslContext.getSocketFactory()); | |
375 } | |
376 return (HttpURLConnection) urlConnection; | |
377 } | 325 } |
378 | 326 |
379 private StringBuilder appendNodeidListArgument(String key, List<Nodeid> values, StringBuilder sb) { | 327 private StringBuilder appendNodeidListArgument(String key, List<Nodeid> values, StringBuilder sb) { |
380 if (sb == null) { | 328 if (sb == null) { |
381 sb = new StringBuilder(20 + values.size() * 41); | 329 sb = new StringBuilder(20 + values.size() * 41); |