1818
1919import android .os .SystemProperties ;
2020import android .util .Log ;
21-
2221import java .io .IOException ;
2322import java .net .InetAddress ;
2423import java .net .Socket ;
2524import java .security .KeyManagementException ;
2625import java .security .cert .X509Certificate ;
27-
2826import javax .net .SocketFactory ;
2927import javax .net .ssl .HostnameVerifier ;
3028import javax .net .ssl .HttpsURLConnection ;
3634import javax .net .ssl .SSLSocketFactory ;
3735import javax .net .ssl .TrustManager ;
3836import javax .net .ssl .X509TrustManager ;
39-
4037import org .apache .harmony .xnet .provider .jsse .OpenSSLContextImpl ;
4138import org .apache .harmony .xnet .provider .jsse .OpenSSLSocketImpl ;
4239import org .apache .harmony .xnet .provider .jsse .SSLClientSessionCache ;
@@ -89,6 +86,7 @@ public void checkServerTrusted(X509Certificate[] certs, String authType) { }
8986 private SSLSocketFactory mSecureFactory = null ;
9087 private TrustManager [] mTrustManagers = null ;
9188 private KeyManager [] mKeyManagers = null ;
89+ private byte [] mNpnProtocols = null ;
9290
9391 private final int mHandshakeTimeoutMillis ;
9492 private final SSLClientSessionCache mSessionCache ;
@@ -250,6 +248,60 @@ public void setTrustManagers(TrustManager[] trustManager) {
250248 // be cleared out here.
251249 }
252250
251+ /**
252+ * Sets the <a href="http://technotes.googlecode.com/git/nextprotoneg.html">Next
253+ * Protocol Negotiation (NPN)</a> protocols that this peer is interested in.
254+ *
255+ * <p>For servers this is the sequence of protocols to advertise as
256+ * supported, in order of preference. This list is sent unencrypted to
257+ * all clients that support NPN.
258+ *
259+ * <p>For clients this is a list of supported protocols to match against the
260+ * server's list. If there is no protocol supported by both client and
261+ * server then the first protocol in the client's list will be selected.
262+ * The order of the client's protocols is otherwise insignificant.
263+ *
264+ * @param npnProtocols a possibly-empty list of protocol byte arrays. All
265+ * arrays must be non-empty and of length less than 256.
266+ */
267+ public void setNpnProtocols (byte [][] npnProtocols ) {
268+ this .mNpnProtocols = toNpnProtocolsList (npnProtocols );
269+ }
270+
271+ /**
272+ * Returns an array containing the concatenation of length-prefixed byte
273+ * strings.
274+ */
275+ static byte [] toNpnProtocolsList (byte []... npnProtocols ) {
276+ int totalLength = 0 ;
277+ for (byte [] s : npnProtocols ) {
278+ if (s .length == 0 || s .length > 255 ) {
279+ throw new IllegalArgumentException ("s.length == 0 || s.length > 255: " + s .length );
280+ }
281+ totalLength += 1 + s .length ;
282+ }
283+ byte [] result = new byte [totalLength ];
284+ int pos = 0 ;
285+ for (byte [] s : npnProtocols ) {
286+ result [pos ++] = (byte ) s .length ;
287+ for (byte b : s ) {
288+ result [pos ++] = b ;
289+ }
290+ }
291+ return result ;
292+ }
293+
294+ /**
295+ * Returns the <a href="http://technotes.googlecode.com/git/nextprotoneg.html">Next
296+ * Protocol Negotiation (NPN)</a> protocol selected by client and server, or
297+ * null if no protocol was negotiated.
298+ *
299+ * @param socket a socket created by this factory.
300+ */
301+ public byte [] getNpnSelectedProtocol (Socket socket ) {
302+ return ((OpenSSLSocketImpl ) socket ).getNpnSelectedProtocol ();
303+ }
304+
253305 /**
254306 * Sets the {@link KeyManager}s to be used for connections made by this factory.
255307 */
@@ -271,6 +323,7 @@ public void setKeyManagers(KeyManager[] keyManagers) {
271323 @ Override
272324 public Socket createSocket (Socket k , String host , int port , boolean close ) throws IOException {
273325 OpenSSLSocketImpl s = (OpenSSLSocketImpl ) getDelegate ().createSocket (k , host , port , close );
326+ s .setNpnProtocols (mNpnProtocols );
274327 s .setHandshakeTimeout (mHandshakeTimeoutMillis );
275328 if (mSecure ) {
276329 verifyHostname (s , host );
@@ -289,6 +342,7 @@ public Socket createSocket(Socket k, String host, int port, boolean close) throw
289342 @ Override
290343 public Socket createSocket () throws IOException {
291344 OpenSSLSocketImpl s = (OpenSSLSocketImpl ) getDelegate ().createSocket ();
345+ s .setNpnProtocols (mNpnProtocols );
292346 s .setHandshakeTimeout (mHandshakeTimeoutMillis );
293347 return s ;
294348 }
@@ -305,6 +359,7 @@ public Socket createSocket(InetAddress addr, int port, InetAddress localAddr, in
305359 throws IOException {
306360 OpenSSLSocketImpl s = (OpenSSLSocketImpl ) getDelegate ().createSocket (
307361 addr , port , localAddr , localPort );
362+ s .setNpnProtocols (mNpnProtocols );
308363 s .setHandshakeTimeout (mHandshakeTimeoutMillis );
309364 return s ;
310365 }
@@ -319,6 +374,7 @@ public Socket createSocket(InetAddress addr, int port, InetAddress localAddr, in
319374 @ Override
320375 public Socket createSocket (InetAddress addr , int port ) throws IOException {
321376 OpenSSLSocketImpl s = (OpenSSLSocketImpl ) getDelegate ().createSocket (addr , port );
377+ s .setNpnProtocols (mNpnProtocols );
322378 s .setHandshakeTimeout (mHandshakeTimeoutMillis );
323379 return s ;
324380 }
@@ -334,6 +390,7 @@ public Socket createSocket(String host, int port, InetAddress localAddr, int loc
334390 throws IOException {
335391 OpenSSLSocketImpl s = (OpenSSLSocketImpl ) getDelegate ().createSocket (
336392 host , port , localAddr , localPort );
393+ s .setNpnProtocols (mNpnProtocols );
337394 s .setHandshakeTimeout (mHandshakeTimeoutMillis );
338395 if (mSecure ) {
339396 verifyHostname (s , host );
@@ -350,6 +407,7 @@ public Socket createSocket(String host, int port, InetAddress localAddr, int loc
350407 @ Override
351408 public Socket createSocket (String host , int port ) throws IOException {
352409 OpenSSLSocketImpl s = (OpenSSLSocketImpl ) getDelegate ().createSocket (host , port );
410+ s .setNpnProtocols (mNpnProtocols );
353411 s .setHandshakeTimeout (mHandshakeTimeoutMillis );
354412 if (mSecure ) {
355413 verifyHostname (s , host );
0 commit comments