1 /*
2 * Copyright 2018 The Netty Project
3 *
4 * The Netty Project licenses this file to you under the Apache License,
5 * version 2.0 (the "License"); you may not use this file except in compliance
6 * with the License. You may obtain a copy of the License at:
7 *
8 * https://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, WITHOUT
12 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13 * License for the specific language governing permissions and limitations
14 * under the License.
15 */
16 package io.netty.handler.ssl;
17
18 import io.netty.buffer.ByteBufAllocator;
19
20 import javax.net.ssl.X509KeyManager;
21 import java.util.Iterator;
22 import java.util.concurrent.ConcurrentHashMap;
23 import java.util.concurrent.ConcurrentMap;
24
25 /**
26 * {@link OpenSslKeyMaterialProvider} that will cache the {@link OpenSslKeyMaterial} to reduce the overhead
27 * of parsing the chain and the key for generation of the material.
28 */
29 final class OpenSslCachingKeyMaterialProvider extends OpenSslKeyMaterialProvider {
30
31 private final int maxCachedEntries;
32 private volatile boolean full;
33 private final ConcurrentMap<String, OpenSslKeyMaterial> cache = new ConcurrentHashMap<String, OpenSslKeyMaterial>();
34
35 OpenSslCachingKeyMaterialProvider(X509KeyManager keyManager, String password, int maxCachedEntries) {
36 super(keyManager, password);
37 this.maxCachedEntries = maxCachedEntries;
38 }
39
40 @Override
41 OpenSslKeyMaterial chooseKeyMaterial(ByteBufAllocator allocator, String alias) throws Exception {
42 OpenSslKeyMaterial material = cache.get(alias);
43 if (material == null) {
44 material = super.chooseKeyMaterial(allocator, alias);
45 if (material == null) {
46 // No keymaterial should be used.
47 return null;
48 }
49
50 if (full) {
51 return material;
52 }
53 if (cache.size() > maxCachedEntries) {
54 full = true;
55 // Do not cache...
56 return material;
57 }
58 OpenSslKeyMaterial old = cache.putIfAbsent(alias, material);
59 if (old != null) {
60 material.release();
61 material = old;
62 }
63 }
64 // We need to call retain() as we want to always have at least a refCnt() of 1 before destroy() was called.
65 return material.retain();
66 }
67
68 @Override
69 void destroy() {
70 // Remove and release all entries.
71 do {
72 Iterator<OpenSslKeyMaterial> iterator = cache.values().iterator();
73 while (iterator.hasNext()) {
74 iterator.next().release();
75 iterator.remove();
76 }
77 } while (!cache.isEmpty());
78 }
79 }