108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project/* 208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project * Copyright (C) 2009 The Android Open Source Project 308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project * 408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License"); 508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project * you may not use this file except in compliance with the License. 608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project * You may obtain a copy of the License at 708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project * 808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project * http://www.apache.org/licenses/LICENSE-2.0 908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project * 1008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project * Unless required by applicable law or agreed to in writing, software 1108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS, 1208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project * See the License for the specific language governing permissions and 1408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project * limitations under the License. 1508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project */ 1608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project 17860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Rootpackage org.conscrypt; 1808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project 194a91f8a9c955b7cd64fbdf36233295ac3dd515d3Brian Carlstromimport java.util.HashMap; 2008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Projectimport java.util.Map; 2108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Projectimport javax.net.ssl.SSLSession; 2208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project 2308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project/** 2408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project * Caches client sessions. Indexes by host and port. Users are typically 2561b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom * looking to reuse any session for a given host and port. 2608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project */ 2708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Projectpublic class ClientSessionContext extends AbstractSessionContext { 2808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project 2908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project /** 3061b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom * Sessions indexed by host and port. Protect from concurrent 3161b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom * access by holding a lock on sessionsByHostAndPort. 3208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project */ 3361b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom final Map<HostAndPort, SSLSession> sessionsByHostAndPort 3461b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom = new HashMap<HostAndPort, SSLSession>(); 3508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project 362785b7f916644f939b599cf6b01a3df6fae1eca5Brian Carlstrom private SSLClientSessionCache persistentCache; 3708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project 382785b7f916644f939b599cf6b01a3df6fae1eca5Brian Carlstrom public ClientSessionContext() { 394314dcb6f5eb0484f17d9096e45e8ae9c3bb1f72Alex Klyubin super(10); 402785b7f916644f939b599cf6b01a3df6fae1eca5Brian Carlstrom } 412785b7f916644f939b599cf6b01a3df6fae1eca5Brian Carlstrom 4267ca2b30455d027e830bd09f62cbc03669f08e1aJesse Wilson public int size() { 4367ca2b30455d027e830bd09f62cbc03669f08e1aJesse Wilson return sessionsByHostAndPort.size(); 4467ca2b30455d027e830bd09f62cbc03669f08e1aJesse Wilson } 4567ca2b30455d027e830bd09f62cbc03669f08e1aJesse Wilson 462785b7f916644f939b599cf6b01a3df6fae1eca5Brian Carlstrom public void setPersistentCache(SSLClientSessionCache persistentCache) { 4708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project this.persistentCache = persistentCache; 4808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project } 4908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project 50f06338c01394610174fe2b3532beac56d61d9e26Kenny Root @Override 5161b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom protected void sessionRemoved(SSLSession session) { 52c7eac25a7d55812eaaecd8a8a5cdaac3a28b2bf5Brian Carlstrom String host = session.getPeerHost(); 53c7eac25a7d55812eaaecd8a8a5cdaac3a28b2bf5Brian Carlstrom int port = session.getPeerPort(); 54c7eac25a7d55812eaaecd8a8a5cdaac3a28b2bf5Brian Carlstrom if (host == null) { 55c7eac25a7d55812eaaecd8a8a5cdaac3a28b2bf5Brian Carlstrom return; 56c7eac25a7d55812eaaecd8a8a5cdaac3a28b2bf5Brian Carlstrom } 57c7eac25a7d55812eaaecd8a8a5cdaac3a28b2bf5Brian Carlstrom HostAndPort hostAndPortKey = new HostAndPort(host, port); 5861b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom synchronized (sessionsByHostAndPort) { 5961b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom sessionsByHostAndPort.remove(hostAndPortKey); 6008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project } 6108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project } 6208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project 6308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project /** 6408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project * Finds a cached session for the given host name and port. 6508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project * 6608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project * @param host of server 6708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project * @param port of server 6808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project * @return cached session or null if none found 6908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project */ 7008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project public SSLSession getSession(String host, int port) { 71c7eac25a7d55812eaaecd8a8a5cdaac3a28b2bf5Brian Carlstrom if (host == null) { 72c7eac25a7d55812eaaecd8a8a5cdaac3a28b2bf5Brian Carlstrom return null; 73c7eac25a7d55812eaaecd8a8a5cdaac3a28b2bf5Brian Carlstrom } 744a91f8a9c955b7cd64fbdf36233295ac3dd515d3Brian Carlstrom SSLSession session; 7561b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom HostAndPort hostAndPortKey = new HostAndPort(host, port); 7661b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom synchronized (sessionsByHostAndPort) { 7761b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom session = sessionsByHostAndPort.get(hostAndPortKey); 784a91f8a9c955b7cd64fbdf36233295ac3dd515d3Brian Carlstrom } 794a91f8a9c955b7cd64fbdf36233295ac3dd515d3Brian Carlstrom if (session != null && session.isValid()) { 804a91f8a9c955b7cd64fbdf36233295ac3dd515d3Brian Carlstrom return session; 8108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project } 8208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project 8308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project // Look in persistent cache. 8408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project if (persistentCache != null) { 8508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project byte[] data = persistentCache.getSessionData(host, port); 8608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project if (data != null) { 874a91f8a9c955b7cd64fbdf36233295ac3dd515d3Brian Carlstrom session = toSession(data, host, port); 884a91f8a9c955b7cd64fbdf36233295ac3dd515d3Brian Carlstrom if (session != null && session.isValid()) { 8961b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom super.putSession(session); 9061b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom synchronized (sessionsByHostAndPort) { 9161b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom sessionsByHostAndPort.put(hostAndPortKey, session); 9208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project } 9308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project return session; 9408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project } 9508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project } 9608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project } 9708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project 9808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project return null; 9908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project } 10008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project 101f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom @Override 10267ca2b30455d027e830bd09f62cbc03669f08e1aJesse Wilson public void putSession(SSLSession session) { 10361b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom super.putSession(session); 10461b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom 105c7eac25a7d55812eaaecd8a8a5cdaac3a28b2bf5Brian Carlstrom String host = session.getPeerHost(); 106c7eac25a7d55812eaaecd8a8a5cdaac3a28b2bf5Brian Carlstrom int port = session.getPeerPort(); 107c7eac25a7d55812eaaecd8a8a5cdaac3a28b2bf5Brian Carlstrom if (host == null) { 108c7eac25a7d55812eaaecd8a8a5cdaac3a28b2bf5Brian Carlstrom return; 109c7eac25a7d55812eaaecd8a8a5cdaac3a28b2bf5Brian Carlstrom } 110c7eac25a7d55812eaaecd8a8a5cdaac3a28b2bf5Brian Carlstrom 111c7eac25a7d55812eaaecd8a8a5cdaac3a28b2bf5Brian Carlstrom HostAndPort hostAndPortKey = new HostAndPort(host, port); 11261b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom synchronized (sessionsByHostAndPort) { 11361b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom sessionsByHostAndPort.put(hostAndPortKey, session); 11408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project } 11508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project 11608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project // TODO: This in a background thread. 11708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project if (persistentCache != null) { 11808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project byte[] data = toBytes(session); 11908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project if (data != null) { 12008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project persistentCache.putSessionData(session, data); 12108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project } 12208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project } 12308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project } 12408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project 12508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project static class HostAndPort { 12608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project final String host; 12708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project final int port; 12808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project 12908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project HostAndPort(String host, int port) { 13008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project this.host = host; 13108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project this.port = port; 13208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project } 13308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project 134f06338c01394610174fe2b3532beac56d61d9e26Kenny Root @Override 135f06338c01394610174fe2b3532beac56d61d9e26Kenny Root public int hashCode() { 13608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project return host.hashCode() * 31 + port; 13708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project } 13808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project 139f06338c01394610174fe2b3532beac56d61d9e26Kenny Root @Override 140f06338c01394610174fe2b3532beac56d61d9e26Kenny Root public boolean equals(Object o) { 141adf18db1513055012dd49c9b5fd0518afa21f9c3Elliott Hughes if (!(o instanceof HostAndPort)) { 142adf18db1513055012dd49c9b5fd0518afa21f9c3Elliott Hughes return false; 143adf18db1513055012dd49c9b5fd0518afa21f9c3Elliott Hughes } 144adf18db1513055012dd49c9b5fd0518afa21f9c3Elliott Hughes HostAndPort lhs = (HostAndPort) o; 145adf18db1513055012dd49c9b5fd0518afa21f9c3Elliott Hughes return host.equals(lhs.host) && port == lhs.port; 14608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project } 14708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project } 14808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project} 149