12231db3e6bb54447a9b14cf004a6cb03c373651cjwilson/* 22231db3e6bb54447a9b14cf004a6cb03c373651cjwilson * Copyright (C) 2012 Square, Inc. 32231db3e6bb54447a9b14cf004a6cb03c373651cjwilson * Copyright (C) 2012 The Android Open Source Project 42231db3e6bb54447a9b14cf004a6cb03c373651cjwilson * 52231db3e6bb54447a9b14cf004a6cb03c373651cjwilson * Licensed under the Apache License, Version 2.0 (the "License"); 62231db3e6bb54447a9b14cf004a6cb03c373651cjwilson * you may not use this file except in compliance with the License. 72231db3e6bb54447a9b14cf004a6cb03c373651cjwilson * You may obtain a copy of the License at 82231db3e6bb54447a9b14cf004a6cb03c373651cjwilson * 92231db3e6bb54447a9b14cf004a6cb03c373651cjwilson * http://www.apache.org/licenses/LICENSE-2.0 102231db3e6bb54447a9b14cf004a6cb03c373651cjwilson * 112231db3e6bb54447a9b14cf004a6cb03c373651cjwilson * Unless required by applicable law or agreed to in writing, software 122231db3e6bb54447a9b14cf004a6cb03c373651cjwilson * distributed under the License is distributed on an "AS IS" BASIS, 132231db3e6bb54447a9b14cf004a6cb03c373651cjwilson * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 142231db3e6bb54447a9b14cf004a6cb03c373651cjwilson * See the License for the specific language governing permissions and 152231db3e6bb54447a9b14cf004a6cb03c373651cjwilson * limitations under the License. 162231db3e6bb54447a9b14cf004a6cb03c373651cjwilson */ 172231db3e6bb54447a9b14cf004a6cb03c373651cjwilsonpackage com.squareup.okhttp.internal; 182231db3e6bb54447a9b14cf004a6cb03c373651cjwilson 192231db3e6bb54447a9b14cf004a6cb03c373651cjwilsonimport dalvik.system.SocketTagger; 20a82f42bbeedd0b07f3892f3b0efaa8122dc8f264Narayan Kamathimport java.io.IOException; 212231db3e6bb54447a9b14cf004a6cb03c373651cjwilsonimport java.io.OutputStream; 22a82f42bbeedd0b07f3892f3b0efaa8122dc8f264Narayan Kamathimport java.net.InetSocketAddress; 232231db3e6bb54447a9b14cf004a6cb03c373651cjwilsonimport java.net.Socket; 242231db3e6bb54447a9b14cf004a6cb03c373651cjwilsonimport java.net.SocketException; 252231db3e6bb54447a9b14cf004a6cb03c373651cjwilsonimport java.net.URI; 262231db3e6bb54447a9b14cf004a6cb03c373651cjwilsonimport java.net.URISyntaxException; 272231db3e6bb54447a9b14cf004a6cb03c373651cjwilsonimport java.net.URL; 283c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fullerimport java.util.List; 292231db3e6bb54447a9b14cf004a6cb03c373651cjwilsonimport javax.net.ssl.SSLSocket; 303c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 313c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fullerimport com.squareup.okhttp.Protocol; 32565c2ad69684ef7c23b5aaa3b7f0c7363cef6bd7Neil Fuller 33e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fullerimport okio.Buffer; 342231db3e6bb54447a9b14cf004a6cb03c373651cjwilson 352231db3e6bb54447a9b14cf004a6cb03c373651cjwilson/** 362231db3e6bb54447a9b14cf004a6cb03c373651cjwilson * Access to proprietary Android APIs. Doesn't use reflection. 372231db3e6bb54447a9b14cf004a6cb03c373651cjwilson */ 382231db3e6bb54447a9b14cf004a6cb03c373651cjwilsonpublic final class Platform { 392231db3e6bb54447a9b14cf004a6cb03c373651cjwilson private static final Platform PLATFORM = new Platform(); 402231db3e6bb54447a9b14cf004a6cb03c373651cjwilson 412231db3e6bb54447a9b14cf004a6cb03c373651cjwilson public static Platform get() { 422231db3e6bb54447a9b14cf004a6cb03c373651cjwilson return PLATFORM; 432231db3e6bb54447a9b14cf004a6cb03c373651cjwilson } 442231db3e6bb54447a9b14cf004a6cb03c373651cjwilson 45565c2ad69684ef7c23b5aaa3b7f0c7363cef6bd7Neil Fuller /** setUseSessionTickets(boolean) */ 46565c2ad69684ef7c23b5aaa3b7f0c7363cef6bd7Neil Fuller private static final OptionalMethod<Socket> SET_USE_SESSION_TICKETS = 47565c2ad69684ef7c23b5aaa3b7f0c7363cef6bd7Neil Fuller new OptionalMethod<Socket>(null, "setUseSessionTickets", Boolean.TYPE); 48565c2ad69684ef7c23b5aaa3b7f0c7363cef6bd7Neil Fuller /** setHostname(String) */ 49565c2ad69684ef7c23b5aaa3b7f0c7363cef6bd7Neil Fuller private static final OptionalMethod<Socket> SET_HOSTNAME = 50565c2ad69684ef7c23b5aaa3b7f0c7363cef6bd7Neil Fuller new OptionalMethod<Socket>(null, "setHostname", String.class); 51565c2ad69684ef7c23b5aaa3b7f0c7363cef6bd7Neil Fuller /** byte[] getAlpnSelectedProtocol() */ 52565c2ad69684ef7c23b5aaa3b7f0c7363cef6bd7Neil Fuller private static final OptionalMethod<Socket> GET_ALPN_SELECTED_PROTOCOL = 53565c2ad69684ef7c23b5aaa3b7f0c7363cef6bd7Neil Fuller new OptionalMethod<Socket>(byte[].class, "getAlpnSelectedProtocol"); 54565c2ad69684ef7c23b5aaa3b7f0c7363cef6bd7Neil Fuller /** setAlpnSelectedProtocol(byte[]) */ 55565c2ad69684ef7c23b5aaa3b7f0c7363cef6bd7Neil Fuller private static final OptionalMethod<Socket> SET_ALPN_PROTOCOLS = 56565c2ad69684ef7c23b5aaa3b7f0c7363cef6bd7Neil Fuller new OptionalMethod<Socket>(null, "setAlpnProtocols", byte[].class ); 57565c2ad69684ef7c23b5aaa3b7f0c7363cef6bd7Neil Fuller 582231db3e6bb54447a9b14cf004a6cb03c373651cjwilson public void logW(String warning) { 592231db3e6bb54447a9b14cf004a6cb03c373651cjwilson System.logW(warning); 602231db3e6bb54447a9b14cf004a6cb03c373651cjwilson } 612231db3e6bb54447a9b14cf004a6cb03c373651cjwilson 622231db3e6bb54447a9b14cf004a6cb03c373651cjwilson public void tagSocket(Socket socket) throws SocketException { 632231db3e6bb54447a9b14cf004a6cb03c373651cjwilson SocketTagger.get().tag(socket); 642231db3e6bb54447a9b14cf004a6cb03c373651cjwilson } 652231db3e6bb54447a9b14cf004a6cb03c373651cjwilson 662231db3e6bb54447a9b14cf004a6cb03c373651cjwilson public void untagSocket(Socket socket) throws SocketException { 672231db3e6bb54447a9b14cf004a6cb03c373651cjwilson SocketTagger.get().untag(socket); 682231db3e6bb54447a9b14cf004a6cb03c373651cjwilson } 692231db3e6bb54447a9b14cf004a6cb03c373651cjwilson 702231db3e6bb54447a9b14cf004a6cb03c373651cjwilson public URI toUriLenient(URL url) throws URISyntaxException { 712231db3e6bb54447a9b14cf004a6cb03c373651cjwilson return url.toURILenient(); 722231db3e6bb54447a9b14cf004a6cb03c373651cjwilson } 732231db3e6bb54447a9b14cf004a6cb03c373651cjwilson 74e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller public void configureTlsExtensions( 75e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller SSLSocket sslSocket, String hostname, List<Protocol> protocols) { 76e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller // Enable SNI and session tickets. 77e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller if (hostname != null) { 78e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller SET_USE_SESSION_TICKETS.invokeOptionalWithoutCheckedException(sslSocket, true); 79e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller SET_HOSTNAME.invokeOptionalWithoutCheckedException(sslSocket, hostname); 80e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 81e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 8266d489eeddae6aafbbcdf9cda71e16b4a9a33a0fNeil Fuller // Enable ALPN. 83e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller boolean alpnSupported = SET_ALPN_PROTOCOLS.isSupported(sslSocket); 84e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller if (!alpnSupported) { 85e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller return; 86e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 87e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 88e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller Object[] parameters = { concatLengthPrefixed(protocols) }; 89e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller if (alpnSupported) { 90e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller SET_ALPN_PROTOCOLS.invokeWithoutCheckedException(sslSocket, parameters); 919da11daf5d24272fe8733de3e1d9587425d17c6eNeil Fuller } 922231db3e6bb54447a9b14cf004a6cb03c373651cjwilson } 932231db3e6bb54447a9b14cf004a6cb03c373651cjwilson 942231db3e6bb54447a9b14cf004a6cb03c373651cjwilson /** 95e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller * Called after the TLS handshake to release resources allocated by {@link 96e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller * #configureTlsExtensions}. 972231db3e6bb54447a9b14cf004a6cb03c373651cjwilson */ 98e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller public void afterHandshake(SSLSocket sslSocket) { 99e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 100e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 101e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller public String getSelectedProtocol(SSLSocket socket) { 102565c2ad69684ef7c23b5aaa3b7f0c7363cef6bd7Neil Fuller boolean alpnSupported = GET_ALPN_SELECTED_PROTOCOL.isSupported(socket); 1031fa00b75f644dc81c627fdb75c898f4f8ad48cc1Neil Fuller if (!alpnSupported) { 1043c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller return null; 1053c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 1063c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 1071fa00b75f644dc81c627fdb75c898f4f8ad48cc1Neil Fuller byte[] alpnResult = 108e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller (byte[]) GET_ALPN_SELECTED_PROTOCOL.invokeWithoutCheckedException(socket); 1091fa00b75f644dc81c627fdb75c898f4f8ad48cc1Neil Fuller if (alpnResult != null) { 110e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller return new String(alpnResult, Util.UTF_8); 111565c2ad69684ef7c23b5aaa3b7f0c7363cef6bd7Neil Fuller } 112565c2ad69684ef7c23b5aaa3b7f0c7363cef6bd7Neil Fuller return null; 1132231db3e6bb54447a9b14cf004a6cb03c373651cjwilson } 1142231db3e6bb54447a9b14cf004a6cb03c373651cjwilson 115a82f42bbeedd0b07f3892f3b0efaa8122dc8f264Narayan Kamath public void connectSocket(Socket socket, InetSocketAddress address, 116a82f42bbeedd0b07f3892f3b0efaa8122dc8f264Narayan Kamath int connectTimeout) throws IOException { 117a82f42bbeedd0b07f3892f3b0efaa8122dc8f264Narayan Kamath socket.connect(address, connectTimeout); 118a82f42bbeedd0b07f3892f3b0efaa8122dc8f264Narayan Kamath } 119a82f42bbeedd0b07f3892f3b0efaa8122dc8f264Narayan Kamath 120a82f42bbeedd0b07f3892f3b0efaa8122dc8f264Narayan Kamath /** Prefix used on custom headers. */ 121a82f42bbeedd0b07f3892f3b0efaa8122dc8f264Narayan Kamath public String getPrefix() { 122a82f42bbeedd0b07f3892f3b0efaa8122dc8f264Narayan Kamath return "X-Android"; 123a82f42bbeedd0b07f3892f3b0efaa8122dc8f264Narayan Kamath } 1243c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 1253c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller /** 126e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller * Returns the concatenation of 8-bit, length prefixed protocol names. 1273c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller * http://tools.ietf.org/html/draft-agl-tls-nextprotoneg-04#page-4 1283c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller */ 1293c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller static byte[] concatLengthPrefixed(List<Protocol> protocols) { 130e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller Buffer result = new Buffer(); 131e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller for (int i = 0, size = protocols.size(); i < size; i++) { 132e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller Protocol protocol = protocols.get(i); 13366d489eeddae6aafbbcdf9cda71e16b4a9a33a0fNeil Fuller if (protocol == Protocol.HTTP_1_0) continue; // No HTTP/1.0 for ALPN. 134e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller result.writeByte(protocol.toString().length()); 135e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller result.writeUtf8(protocol.toString()); 1363c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 137e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller return result.readByteArray(); 1383c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 1392231db3e6bb54447a9b14cf004a6cb03c373651cjwilson} 140