PageRenderTime 26ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 0ms

/external/okhttp/src/main/java/libcore/net/http/HttpConnection.java

https://gitlab.com/brian0218/rk3188_r-box_android4.2.2_sdk
Java | 373 lines | 239 code | 39 blank | 95 comment | 54 complexity | 17b6d98df786dea4380f029ed7b210f5 MD5 | raw file
  1. /*
  2. * Licensed to the Apache Software Foundation (ASF) under one or more
  3. * contributor license agreements. See the NOTICE file distributed with
  4. * this work for additional information regarding copyright ownership.
  5. * The ASF licenses this file to You under the Apache License, Version 2.0
  6. * (the "License"); you may not use this file except in compliance with
  7. * the License. You may obtain a copy of the License at
  8. *
  9. * http://www.apache.org/licenses/LICENSE-2.0
  10. *
  11. * Unless required by applicable law or agreed to in writing, software
  12. * distributed under the License is distributed on an "AS IS" BASIS,
  13. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. * See the License for the specific language governing permissions and
  15. * limitations under the License.
  16. */
  17. package libcore.net.http;
  18. import java.io.BufferedInputStream;
  19. import java.io.IOException;
  20. import java.io.InputStream;
  21. import java.io.OutputStream;
  22. import java.net.InetAddress;
  23. import java.net.InetSocketAddress;
  24. import java.net.Proxy;
  25. import java.net.ProxySelector;
  26. import java.net.Socket;
  27. import java.net.SocketAddress;
  28. import java.net.SocketException;
  29. import java.net.URI;
  30. import java.net.UnknownHostException;
  31. import java.util.Arrays;
  32. import java.util.List;
  33. import javax.net.ssl.HostnameVerifier;
  34. import javax.net.ssl.SSLSocket;
  35. import javax.net.ssl.SSLSocketFactory;
  36. import libcore.io.IoUtils;
  37. import libcore.net.spdy.SpdyConnection;
  38. import libcore.util.Libcore;
  39. import libcore.util.Objects;
  40. /**
  41. * Holds the sockets and streams of an HTTP, HTTPS, or HTTPS+SPDY connection,
  42. * which may be used for multiple HTTP request/response exchanges. Connections
  43. * may be direct to the origin server or via a proxy. Create an instance using
  44. * the {@link Address} inner class.
  45. *
  46. * <p>Do not confuse this class with the misnamed {@code HttpURLConnection},
  47. * which isn't so much a connection as a single request/response pair.
  48. */
  49. final class HttpConnection {
  50. private static final byte[] NPN_PROTOCOLS = new byte[] {
  51. 6, 's', 'p', 'd', 'y', '/', '2',
  52. 8, 'h', 't', 't', 'p', '/', '1', '.', '1',
  53. };
  54. private static final byte[] SPDY2 = new byte[] {
  55. 's', 'p', 'd', 'y', '/', '2',
  56. };
  57. private static final byte[] HTTP_11 = new byte[] {
  58. 'h', 't', 't', 'p', '/', '1', '.', '1',
  59. };
  60. private final Address address;
  61. private final Socket socket;
  62. private InputStream inputStream;
  63. private OutputStream outputStream;
  64. private SSLSocket sslSocket;
  65. private InputStream sslInputStream;
  66. private OutputStream sslOutputStream;
  67. private boolean recycled = false;
  68. private SpdyConnection spdyConnection;
  69. /**
  70. * The version this client will use. Either 0 for HTTP/1.0, or 1 for
  71. * HTTP/1.1. Upon receiving a non-HTTP/1.1 response, this client
  72. * automatically sets its version to HTTP/1.0.
  73. */
  74. int httpMinorVersion = 1; // Assume HTTP/1.1
  75. private HttpConnection(Address config, int connectTimeout) throws IOException {
  76. this.address = config;
  77. /*
  78. * Try each of the host's addresses for best behavior in mixed IPv4/IPv6
  79. * environments. See http://b/2876927
  80. * TODO: add a hidden method so that Socket.tryAllAddresses can does this for us
  81. */
  82. Socket socketCandidate = null;
  83. InetAddress[] addresses = InetAddress.getAllByName(config.socketHost);
  84. for (int i = 0; i < addresses.length; i++) {
  85. socketCandidate = (config.proxy != null && config.proxy.type() != Proxy.Type.HTTP)
  86. ? new Socket(config.proxy)
  87. : new Socket();
  88. try {
  89. socketCandidate.connect(
  90. new InetSocketAddress(addresses[i], config.socketPort), connectTimeout);
  91. break;
  92. } catch (IOException e) {
  93. if (i == addresses.length - 1) {
  94. throw e;
  95. }
  96. }
  97. }
  98. if (socketCandidate == null) {
  99. throw new IOException();
  100. }
  101. this.socket = socketCandidate;
  102. /*
  103. * Buffer the socket stream to permit efficient parsing of HTTP headers
  104. * and chunk sizes. Benchmarks suggest 128 is sufficient. We cannot
  105. * buffer when setting up a tunnel because we may consume bytes intended
  106. * for the SSL socket.
  107. */
  108. int bufferSize = 128;
  109. inputStream = address.requiresTunnel
  110. ? socket.getInputStream()
  111. : new BufferedInputStream(socket.getInputStream(), bufferSize);
  112. outputStream = socket.getOutputStream();
  113. }
  114. public static HttpConnection connect(URI uri, SSLSocketFactory sslSocketFactory,
  115. Proxy proxy, boolean requiresTunnel, int connectTimeout) throws IOException {
  116. /*
  117. * Try an explicitly-specified proxy.
  118. */
  119. if (proxy != null) {
  120. Address address = (proxy.type() == Proxy.Type.DIRECT)
  121. ? new Address(uri, sslSocketFactory)
  122. : new Address(uri, sslSocketFactory, proxy, requiresTunnel);
  123. return HttpConnectionPool.INSTANCE.get(address, connectTimeout);
  124. }
  125. /*
  126. * Try connecting to each of the proxies provided by the ProxySelector
  127. * until a connection succeeds.
  128. */
  129. ProxySelector selector = ProxySelector.getDefault();
  130. List<Proxy> proxyList = selector.select(uri);
  131. if (proxyList != null) {
  132. for (Proxy selectedProxy : proxyList) {
  133. if (selectedProxy.type() == Proxy.Type.DIRECT) {
  134. // the same as NO_PROXY
  135. // TODO: if the selector recommends a direct connection, attempt that?
  136. continue;
  137. }
  138. try {
  139. Address address = new Address(uri, sslSocketFactory,
  140. selectedProxy, requiresTunnel);
  141. return HttpConnectionPool.INSTANCE.get(address, connectTimeout);
  142. } catch (IOException e) {
  143. // failed to connect, tell it to the selector
  144. selector.connectFailed(uri, selectedProxy.address(), e);
  145. }
  146. }
  147. }
  148. /*
  149. * Try a direct connection. If this fails, this method will throw.
  150. */
  151. return HttpConnectionPool.INSTANCE.get(new Address(uri, sslSocketFactory), connectTimeout);
  152. }
  153. public void closeSocketAndStreams() {
  154. IoUtils.closeQuietly(sslOutputStream);
  155. IoUtils.closeQuietly(sslInputStream);
  156. IoUtils.closeQuietly(sslSocket);
  157. IoUtils.closeQuietly(outputStream);
  158. IoUtils.closeQuietly(inputStream);
  159. IoUtils.closeQuietly(socket);
  160. }
  161. public void setSoTimeout(int readTimeout) throws SocketException {
  162. socket.setSoTimeout(readTimeout);
  163. }
  164. Socket getSocket() {
  165. return sslSocket != null ? sslSocket : socket;
  166. }
  167. public Address getAddress() {
  168. return address;
  169. }
  170. /**
  171. * Create an {@code SSLSocket} and perform the SSL handshake
  172. * (performing certificate validation.
  173. *
  174. * @param sslSocketFactory Source of new {@code SSLSocket} instances.
  175. * @param tlsTolerant If true, assume server can handle common
  176. */
  177. public SSLSocket setupSecureSocket(SSLSocketFactory sslSocketFactory,
  178. HostnameVerifier hostnameVerifier, boolean tlsTolerant) throws IOException {
  179. if (spdyConnection != null || sslOutputStream != null || sslInputStream != null) {
  180. throw new IllegalStateException();
  181. }
  182. // Create the wrapper over connected socket.
  183. sslSocket = (SSLSocket) sslSocketFactory.createSocket(socket,
  184. address.uriHost, address.uriPort, true /* autoClose */);
  185. Libcore.makeTlsTolerant(sslSocket, address.socketHost, tlsTolerant);
  186. if (tlsTolerant) {
  187. Libcore.setNpnProtocols(sslSocket, NPN_PROTOCOLS);
  188. }
  189. // Force handshake. This can throw!
  190. sslSocket.startHandshake();
  191. // Verify that the socket's certificates are acceptable for the target host.
  192. if (!hostnameVerifier.verify(address.uriHost, sslSocket.getSession())) {
  193. throw new IOException("Hostname '" + address.uriHost + "' was not verified");
  194. }
  195. // SSL success. Prepare to hand out Transport instances.
  196. sslOutputStream = sslSocket.getOutputStream();
  197. sslInputStream = sslSocket.getInputStream();
  198. byte[] selectedProtocol;
  199. if (tlsTolerant
  200. && (selectedProtocol = Libcore.getNpnSelectedProtocol(sslSocket)) != null) {
  201. if (Arrays.equals(selectedProtocol, SPDY2)) {
  202. spdyConnection = new SpdyConnection.Builder(
  203. true, sslInputStream, sslOutputStream).build();
  204. HttpConnectionPool.INSTANCE.share(this);
  205. } else if (!Arrays.equals(selectedProtocol, HTTP_11)) {
  206. throw new IOException("Unexpected NPN transport "
  207. + new String(selectedProtocol, "ISO-8859-1"));
  208. }
  209. }
  210. return sslSocket;
  211. }
  212. /**
  213. * Return an {@code SSLSocket} if already connected, otherwise null.
  214. */
  215. public SSLSocket getSecureSocketIfConnected() {
  216. return sslSocket;
  217. }
  218. /**
  219. * Returns true if this connection has been used to satisfy an earlier
  220. * HTTP request/response pair.
  221. */
  222. public boolean isRecycled() {
  223. return recycled;
  224. }
  225. public void setRecycled() {
  226. this.recycled = true;
  227. }
  228. /**
  229. * Returns true if this connection is eligible to be reused for another
  230. * request/response pair.
  231. */
  232. protected boolean isEligibleForRecycling() {
  233. return !socket.isClosed()
  234. && !socket.isInputShutdown()
  235. && !socket.isOutputShutdown();
  236. }
  237. /**
  238. * Returns the transport appropriate for this connection.
  239. */
  240. public Transport newTransport(HttpEngine httpEngine) throws IOException {
  241. if (spdyConnection != null) {
  242. return new SpdyTransport(httpEngine, spdyConnection);
  243. } else if (sslSocket != null) {
  244. return new HttpTransport(httpEngine, sslOutputStream, sslInputStream);
  245. } else {
  246. return new HttpTransport(httpEngine, outputStream, inputStream);
  247. }
  248. }
  249. /**
  250. * Returns true if this is a SPDY connection. Such connections can be used
  251. * in multiple HTTP requests simultaneously.
  252. */
  253. public boolean isSpdy() {
  254. return spdyConnection != null;
  255. }
  256. /**
  257. * This address has two parts: the address we connect to directly and the
  258. * origin address of the resource. These are the same unless a proxy is
  259. * being used. It also includes the SSL socket factory so that a socket will
  260. * not be reused if its SSL configuration is different.
  261. */
  262. public static final class Address {
  263. private final Proxy proxy;
  264. private final boolean requiresTunnel;
  265. private final String uriHost;
  266. private final int uriPort;
  267. private final String socketHost;
  268. private final int socketPort;
  269. private final SSLSocketFactory sslSocketFactory;
  270. public Address(URI uri, SSLSocketFactory sslSocketFactory) throws UnknownHostException {
  271. this.proxy = null;
  272. this.requiresTunnel = false;
  273. this.uriHost = uri.getHost();
  274. this.uriPort = Libcore.getEffectivePort(uri);
  275. this.sslSocketFactory = sslSocketFactory;
  276. this.socketHost = uriHost;
  277. this.socketPort = uriPort;
  278. if (uriHost == null) {
  279. throw new UnknownHostException(uri.toString());
  280. }
  281. }
  282. /**
  283. * @param requiresTunnel true if the HTTP connection needs to tunnel one
  284. * protocol over another, such as when using HTTPS through an HTTP
  285. * proxy. When doing so, we must avoid buffering bytes intended for
  286. * the higher-level protocol.
  287. */
  288. public Address(URI uri, SSLSocketFactory sslSocketFactory,
  289. Proxy proxy, boolean requiresTunnel) throws UnknownHostException {
  290. this.proxy = proxy;
  291. this.requiresTunnel = requiresTunnel;
  292. this.uriHost = uri.getHost();
  293. this.uriPort = Libcore.getEffectivePort(uri);
  294. this.sslSocketFactory = sslSocketFactory;
  295. SocketAddress proxyAddress = proxy.address();
  296. if (!(proxyAddress instanceof InetSocketAddress)) {
  297. throw new IllegalArgumentException("Proxy.address() is not an InetSocketAddress: "
  298. + proxyAddress.getClass());
  299. }
  300. InetSocketAddress proxySocketAddress = (InetSocketAddress) proxyAddress;
  301. this.socketHost = proxySocketAddress.getHostName();
  302. this.socketPort = proxySocketAddress.getPort();
  303. if (uriHost == null) {
  304. throw new UnknownHostException(uri.toString());
  305. }
  306. }
  307. public Proxy getProxy() {
  308. return proxy;
  309. }
  310. @Override public boolean equals(Object other) {
  311. if (other instanceof Address) {
  312. Address that = (Address) other;
  313. return Objects.equal(this.proxy, that.proxy)
  314. && this.uriHost.equals(that.uriHost)
  315. && this.uriPort == that.uriPort
  316. && Objects.equal(this.sslSocketFactory, that.sslSocketFactory)
  317. && this.requiresTunnel == that.requiresTunnel;
  318. }
  319. return false;
  320. }
  321. @Override public int hashCode() {
  322. int result = 17;
  323. result = 31 * result + uriHost.hashCode();
  324. result = 31 * result + uriPort;
  325. result = 31 * result + (sslSocketFactory != null ? sslSocketFactory.hashCode() : 0);
  326. result = 31 * result + (proxy != null ? proxy.hashCode() : 0);
  327. result = 31 * result + (requiresTunnel ? 1 : 0);
  328. return result;
  329. }
  330. public HttpConnection connect(int connectTimeout) throws IOException {
  331. return new HttpConnection(this, connectTimeout);
  332. }
  333. }
  334. }