1 /* 2 * Copyright (C) 2009 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package org.apache.harmony.xnet.provider.jsse; 18 19 import java.util.HashMap; 20 import java.util.Map; 21 import javax.net.ssl.SSLSession; 22 23 /** 24 * Caches client sessions. Indexes by host and port. Users are typically 25 * looking to reuse any session for a given host and port. 26 */ 27 public class ClientSessionContext extends AbstractSessionContext { 28 29 /** 30 * Sessions indexed by host and port. Protect from concurrent 31 * access by holding a lock on sessionsByHostAndPort. 32 */ 33 final Map<HostAndPort, SSLSession> sessionsByHostAndPort 34 = new HashMap<HostAndPort, SSLSession>(); 35 36 private SSLClientSessionCache persistentCache; 37 38 public ClientSessionContext() { 39 super(10, 0); 40 } 41 42 public void setPersistentCache(SSLClientSessionCache persistentCache) { 43 this.persistentCache = persistentCache; 44 } 45 46 protected void sessionRemoved(SSLSession session) { 47 String host = session.getPeerHost(); 48 int port = session.getPeerPort(); 49 if (host == null) { 50 return; 51 } 52 HostAndPort hostAndPortKey = new HostAndPort(host, port); 53 synchronized (sessionsByHostAndPort) { 54 sessionsByHostAndPort.remove(hostAndPortKey); 55 } 56 } 57 58 /** 59 * Finds a cached session for the given host name and port. 60 * 61 * @param host of server 62 * @param port of server 63 * @return cached session or null if none found 64 */ 65 public SSLSession getSession(String host, int port) { 66 if (host == null) { 67 return null; 68 } 69 SSLSession session; 70 HostAndPort hostAndPortKey = new HostAndPort(host, port); 71 synchronized (sessionsByHostAndPort) { 72 session = sessionsByHostAndPort.get(hostAndPortKey); 73 } 74 if (session != null && session.isValid()) { 75 return session; 76 } 77 78 // Look in persistent cache. 79 if (persistentCache != null) { 80 byte[] data = persistentCache.getSessionData(host, port); 81 if (data != null) { 82 session = toSession(data, host, port); 83 if (session != null && session.isValid()) { 84 super.putSession(session); 85 synchronized (sessionsByHostAndPort) { 86 sessionsByHostAndPort.put(hostAndPortKey, session); 87 } 88 return session; 89 } 90 } 91 } 92 93 return null; 94 } 95 96 @Override 97 void putSession(SSLSession session) { 98 super.putSession(session); 99 100 String host = session.getPeerHost(); 101 int port = session.getPeerPort(); 102 if (host == null) { 103 return; 104 } 105 106 HostAndPort hostAndPortKey = new HostAndPort(host, port); 107 synchronized (sessionsByHostAndPort) { 108 sessionsByHostAndPort.put(hostAndPortKey, session); 109 } 110 111 // TODO: This in a background thread. 112 if (persistentCache != null) { 113 byte[] data = toBytes(session); 114 if (data != null) { 115 persistentCache.putSessionData(session, data); 116 } 117 } 118 } 119 120 static class HostAndPort { 121 final String host; 122 final int port; 123 124 HostAndPort(String host, int port) { 125 this.host = host; 126 this.port = port; 127 } 128 129 @Override 130 public int hashCode() { 131 return host.hashCode() * 31 + port; 132 } 133 134 @Override 135 @SuppressWarnings("EqualsWhichDoesntCheckParameterClass") 136 public boolean equals(Object o) { 137 HostAndPort other = (HostAndPort) o; 138 return host.equals(other.host) && port == other.port; 139 } 140 } 141 } 142