Skip to content

Commit 793690d

Browse files
authored
I874162: Fixed issue where the JobStatusResponseCache was not working for HTTPS requests
https://internal.almoctane.com/ui/entity-navigation?p=131002/6001&entityType=work_item&id=874162
1 parent e6f6523 commit 793690d

File tree

5 files changed

+223
-11
lines changed

5 files changed

+223
-11
lines changed

release-notes-8.0.0.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ ${version-number}
1111

1212
#### Bug Fixes
1313
- **I445035**: Workers now attempt to complete all in-progress and pre-fetched tasks before shutting down.
14+
- **I874162**: Fixed issue where the `JobStatusResponseCache` was not working for HTTPS requests.
1415

1516
#### Known Issues
1617

worker-core/src/main/java/com/hpe/caf/worker/core/JobStatusCacheRequest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ public JobStatusCacheRequest(ResponseStreamCache jobStatusCache, final URI uri,
4242
this.jobStatusCache = jobStatusCache;
4343
this.uri = uri;
4444
this.responseStream = new ByteArrayOutputStream();
45-
this.jobStatusCache.put(uri, responseStream, JobStatusResponseCache.getStatusCheckIntervalMillis(connection));
45+
this.jobStatusCache.put(uri, responseStream, JobStatusResponseCache.getStatusCheckIntervalMillis(connection), connection);
4646
LOG.debug("Writing job status request headers to cache for URI={}", uri);
4747
ObjectOutputStream oos = new ObjectOutputStream(this.responseStream);
4848
oos.writeObject(connection.getHeaderFields());

worker-core/src/main/java/com/hpe/caf/worker/core/JobStatusResponseCache.java

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@
1818
import org.slf4j.Logger;
1919
import org.slf4j.LoggerFactory;
2020

21-
import java.io.ByteArrayOutputStream;
2221
import java.io.IOException;
2322
import java.net.*;
2423
import java.util.List;
@@ -47,10 +46,23 @@ public JobStatusResponseCache()
4746
@Override
4847
public CacheResponse get(URI uri, String requestMethod, Map<String, List<String>> requestHeaders) throws IOException
4948
{
50-
ByteArrayOutputStream cachedResponseStream = jobStatusCache.get(uri);
51-
if (cachedResponseStream != null) {
49+
ResponseStreamCache.ResponseStreamCacheEntry responseStreamCacheEntry = jobStatusCache.get(uri);
50+
if (responseStreamCacheEntry != null) {
5251
LOG.debug("Job status response cache hit for URI={}", uri);
53-
return new JobStatusCacheResponse(cachedResponseStream);
52+
if (responseStreamCacheEntry instanceof ResponseStreamCache.SecureResponseStreamCacheEntry) {
53+
ResponseStreamCache.SecureResponseStreamCacheEntry secureResponseStreamCacheEntry =
54+
(ResponseStreamCache.SecureResponseStreamCacheEntry)responseStreamCacheEntry;
55+
56+
return new JobStatusSecureCacheResponse(
57+
secureResponseStreamCacheEntry.getResponseStream(),
58+
secureResponseStreamCacheEntry.getCipherSuite(),
59+
secureResponseStreamCacheEntry.getLocalCertificateChain(),
60+
secureResponseStreamCacheEntry.getServerCertificateChain(),
61+
secureResponseStreamCacheEntry.getPeerPrincipal(),
62+
secureResponseStreamCacheEntry.getLocalPrincipal());
63+
} else {
64+
return new JobStatusCacheResponse(responseStreamCacheEntry.getResponseStream());
65+
}
5466
}
5567
LOG.debug("Job status response cache miss for URI={}", uri);
5668
return null;
@@ -93,7 +105,13 @@ public static long getStatusCheckIntervalMillis(URLConnection connection)
93105
if (maxAgeValueMatcher.find()) {
94106
intervalMillis = 1000 * Integer.parseInt(maxAgeValueMatcher.group(1));
95107
LOG.debug("Returning interval derived from {} header as {}ms", CACHE_CONTROL_HEADER_NAME, intervalMillis);
108+
} else {
109+
LOG.debug("Returning default interval {}ms as {} header did not contain a max-age value",
110+
DEFAULT_JOB_STATUS_CHECK_INTERVAL_MILLIS, CACHE_CONTROL_HEADER_NAME);
96111
}
112+
} else {
113+
LOG.debug("Returning default interval {}ms as {} header was null",
114+
DEFAULT_JOB_STATUS_CHECK_INTERVAL_MILLIS, CACHE_CONTROL_HEADER_NAME);
97115
}
98116
return intervalMillis;
99117
}
Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
/*
2+
* Copyright 2015-2024 Open Text.
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+
package com.hpe.caf.worker.core;
17+
18+
import java.io.ByteArrayInputStream;
19+
import java.io.ByteArrayOutputStream;
20+
import java.io.IOException;
21+
import java.io.InputStream;
22+
import java.io.ObjectInputStream;
23+
import java.net.SecureCacheResponse;
24+
import java.security.Principal;
25+
import java.security.cert.Certificate;
26+
import java.util.Collections;
27+
import java.util.List;
28+
import java.util.Map;
29+
import java.util.Objects;
30+
31+
import org.slf4j.Logger;
32+
import org.slf4j.LoggerFactory;
33+
34+
/**
35+
* An implementation of SecureCacheResponse supporting the caching of job status responses.
36+
*/
37+
public class JobStatusSecureCacheResponse extends SecureCacheResponse
38+
{
39+
private static final Logger LOG = LoggerFactory.getLogger(JobStatusSecureCacheResponse.class);
40+
41+
private ByteArrayInputStream responseBody;
42+
private Map<String, List<String>> responseHeaders;
43+
private String cipherSuite;
44+
private List<Certificate> localCertificateChain;
45+
private List<Certificate> serverCertificateChain;
46+
private Principal peerPrincipal;
47+
private Principal localPrincipal;
48+
49+
public JobStatusSecureCacheResponse(
50+
ByteArrayOutputStream cachedResponseStream,
51+
String cipherSuite,
52+
List<Certificate> localCertificateChain,
53+
List<Certificate> serverCertificateChain,
54+
Principal peerPrincipal,
55+
Principal localPrincipal)
56+
throws IOException
57+
{
58+
Objects.requireNonNull(cachedResponseStream);
59+
responseBody = new ByteArrayInputStream(cachedResponseStream.toByteArray());
60+
ObjectInputStream ois = new ObjectInputStream(responseBody);
61+
try {
62+
responseHeaders = (Map<String, List<String>>) ois.readObject();
63+
} catch (ClassNotFoundException e) {
64+
LOG.error("Failed to read cached job status response headers. ", e);
65+
responseHeaders = Collections.emptyMap();
66+
}
67+
this.cipherSuite = cipherSuite;
68+
this.localCertificateChain = localCertificateChain;
69+
this.serverCertificateChain = serverCertificateChain;
70+
this.peerPrincipal = peerPrincipal;
71+
this.localPrincipal = localPrincipal;
72+
}
73+
74+
@Override
75+
public Map<String, List<String>> getHeaders()
76+
{
77+
return responseHeaders;
78+
}
79+
80+
@Override
81+
public InputStream getBody()
82+
{
83+
return responseBody;
84+
}
85+
86+
@Override
87+
public String getCipherSuite()
88+
{
89+
return cipherSuite;
90+
}
91+
92+
@Override
93+
public List<Certificate> getLocalCertificateChain()
94+
{
95+
return localCertificateChain;
96+
}
97+
98+
@Override
99+
public List<Certificate> getServerCertificateChain()
100+
{
101+
return serverCertificateChain;
102+
}
103+
104+
@Override
105+
public Principal getPeerPrincipal()
106+
{
107+
return peerPrincipal;
108+
}
109+
110+
@Override
111+
public Principal getLocalPrincipal()
112+
{
113+
return localPrincipal;
114+
}
115+
}

worker-core/src/main/java/com/hpe/caf/worker/core/ResponseStreamCache.java

Lines changed: 84 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,17 @@
1919
import com.google.common.cache.CacheBuilder;
2020

2121
import java.io.ByteArrayOutputStream;
22+
import java.io.IOException;
2223
import java.net.URI;
24+
import java.net.URLConnection;
25+
import java.security.Principal;
26+
import java.security.cert.Certificate;
27+
import java.util.Arrays;
28+
import java.util.List;
2329
import java.util.concurrent.TimeUnit;
2430

31+
import javax.net.ssl.HttpsURLConnection;
32+
2533
/**
2634
* Provides in-memory caching of web responses on per-URI basis.
2735
*/
@@ -41,16 +49,35 @@ public ResponseStreamCache()
4149
.build();
4250
}
4351

44-
public void put(final URI uri, ByteArrayOutputStream baos, long lifetimeMillis)
52+
public void put(final URI uri, ByteArrayOutputStream baos, long lifetimeMillis, URLConnection urlConnection) throws IOException
4553
{
46-
cacheImpl.put(uri, new ResponseStreamCacheEntry(System.currentTimeMillis() + lifetimeMillis, baos));
54+
if (urlConnection instanceof HttpsURLConnection) {
55+
HttpsURLConnection httpsURLConnection = (HttpsURLConnection)urlConnection;
56+
Certificate[] localCertificates = httpsURLConnection.getLocalCertificates();
57+
Certificate[] serverCertificates = httpsURLConnection.getServerCertificates();
58+
cacheImpl.put(
59+
uri,
60+
new SecureResponseStreamCacheEntry(
61+
System.currentTimeMillis() + lifetimeMillis,
62+
baos,
63+
httpsURLConnection.getCipherSuite(),
64+
localCertificates == null ? null : Arrays.asList(localCertificates),
65+
serverCertificates == null ? null : Arrays.asList(serverCertificates),
66+
httpsURLConnection.getPeerPrincipal(),
67+
httpsURLConnection.getLocalPrincipal()));
68+
} else {
69+
cacheImpl.put(
70+
uri,
71+
new ResponseStreamCacheEntry(
72+
System.currentTimeMillis() + lifetimeMillis,
73+
baos));
74+
}
4775
}
4876

49-
public ByteArrayOutputStream get(final URI uri)
77+
public ResponseStreamCacheEntry get(final URI uri)
5078
{
5179
checkExpiry(uri);
52-
ResponseStreamCacheEntry cacheEntry = cacheImpl.getIfPresent(uri);
53-
return cacheEntry == null ? null : cacheEntry.getResponseStream();
80+
return cacheImpl.getIfPresent(uri);
5481
}
5582

5683
public void remove(final URI uri)
@@ -66,7 +93,7 @@ private void checkExpiry(final URI uri)
6693
}
6794
}
6895

69-
private static class ResponseStreamCacheEntry
96+
public static class ResponseStreamCacheEntry
7097
{
7198
private long expiryTimeMillis;
7299
private ByteArrayOutputStream responseStream;
@@ -87,4 +114,55 @@ public ByteArrayOutputStream getResponseStream()
87114
return responseStream;
88115
}
89116
}
117+
118+
public static class SecureResponseStreamCacheEntry extends ResponseStreamCacheEntry
119+
{
120+
private String cipherSuite;
121+
private List<Certificate> localCertificateChain;
122+
private List<Certificate> serverCertificateChain;
123+
private Principal peerPrincipal;
124+
private Principal localPrincipal;
125+
126+
public SecureResponseStreamCacheEntry(
127+
long expiryTimeMillis,
128+
ByteArrayOutputStream responseStream,
129+
String cipherSuite,
130+
List<Certificate> localCertificateChain,
131+
List<Certificate> serverCertificateChain,
132+
Principal peerPrincipal,
133+
Principal localPrincipal)
134+
{
135+
super(expiryTimeMillis, responseStream);
136+
this.cipherSuite = cipherSuite;
137+
this.localCertificateChain = localCertificateChain;
138+
this.serverCertificateChain = serverCertificateChain;
139+
this.peerPrincipal = peerPrincipal;
140+
this.localPrincipal = localPrincipal;
141+
}
142+
143+
public String getCipherSuite()
144+
{
145+
return cipherSuite;
146+
}
147+
148+
public List<Certificate> getLocalCertificateChain()
149+
{
150+
return localCertificateChain;
151+
}
152+
153+
public List<Certificate> getServerCertificateChain()
154+
{
155+
return serverCertificateChain;
156+
}
157+
158+
public Principal getPeerPrincipal()
159+
{
160+
return peerPrincipal;
161+
}
162+
163+
public Principal getLocalPrincipal()
164+
{
165+
return localPrincipal;
166+
}
167+
}
90168
}

0 commit comments

Comments
 (0)