Skip to content

Commit 2675998

Browse files
Malandrilmanusa
andauthored
fix: HTTP headers are case insensitive (6924)
fix: Make vertx request header case insensitive --- review:fix: headers are case-insensitive Signed-off-by: Marc Nuri <marc@marcnuri.com> Co-authored-by: Marc Nuri <marc@marcnuri.com>
1 parent 2024d02 commit 2675998

File tree

6 files changed

+87
-37
lines changed

6 files changed

+87
-37
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
* Fix #6906: Knative VolatileTime should be serialized as String
99
* Fix #6930: Add support for Boolean enums in the java-generator
1010
* Fix #6886: Remove invalid JUnit 4 references
11+
* Fix #6917: Client does not authenticate correctly on OpenShift if the returned Location header is lower-case
1112

1213
#### Improvements
1314
* Fix #6863: ensuring SerialExecutor does not throw RejectedExecutionException to prevent unnecessary error logs

httpclient-vertx/src/main/java/io/fabric8/kubernetes/client/vertx/VertxHttpRequest.java

Lines changed: 0 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,7 @@
1616
package io.fabric8.kubernetes.client.vertx;
1717

1818
import io.fabric8.kubernetes.client.http.AsyncBody;
19-
import io.fabric8.kubernetes.client.http.HttpRequest;
2019
import io.fabric8.kubernetes.client.http.HttpResponse;
21-
import io.fabric8.kubernetes.client.http.StandardHttpHeaders;
2220
import io.fabric8.kubernetes.client.http.StandardHttpRequest;
2321
import io.fabric8.kubernetes.client.http.StandardHttpRequest.BodyContent;
2422
import io.vertx.core.Future;
@@ -35,45 +33,11 @@
3533
import java.util.LinkedHashMap;
3634
import java.util.List;
3735
import java.util.Map;
38-
import java.util.Optional;
3936
import java.util.concurrent.CompletableFuture;
4037
import java.util.function.Function;
4138

4239
class VertxHttpRequest {
4340

44-
private static final class VertxHttpResponse extends StandardHttpHeaders implements HttpResponse<AsyncBody> {
45-
private final AsyncBody result;
46-
private final HttpClientResponse resp;
47-
private final HttpRequest request;
48-
49-
private VertxHttpResponse(AsyncBody result, HttpClientResponse resp, HttpRequest request) {
50-
super(toHeadersMap(resp.headers()));
51-
this.result = result;
52-
this.resp = resp;
53-
this.request = request;
54-
}
55-
56-
@Override
57-
public int code() {
58-
return resp.statusCode();
59-
}
60-
61-
@Override
62-
public AsyncBody body() {
63-
return result;
64-
}
65-
66-
@Override
67-
public HttpRequest request() {
68-
return request;
69-
}
70-
71-
@Override
72-
public Optional<HttpResponse<?>> previousResponse() {
73-
return Optional.empty();
74-
}
75-
}
76-
7741
final Vertx vertx;
7842
private final RequestOptions options;
7943
private final StandardHttpRequest request;
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
/*
2+
* Copyright (C) 2015 Red Hat, Inc.
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 io.fabric8.kubernetes.client.vertx;
17+
18+
import io.fabric8.kubernetes.client.http.AsyncBody;
19+
import io.fabric8.kubernetes.client.http.HttpRequest;
20+
import io.fabric8.kubernetes.client.http.HttpResponse;
21+
import io.fabric8.kubernetes.client.http.StandardHttpHeaders;
22+
import io.vertx.core.http.HttpClientResponse;
23+
24+
import java.util.Optional;
25+
26+
public class VertxHttpResponse extends StandardHttpHeaders implements HttpResponse<AsyncBody> {
27+
private final AsyncBody result;
28+
private final HttpClientResponse resp;
29+
private final HttpRequest request;
30+
31+
VertxHttpResponse(AsyncBody result, HttpClientResponse resp, HttpRequest request) {
32+
super(VertxHttpRequest.toHeadersMap(resp.headers()));
33+
this.result = result;
34+
this.resp = resp;
35+
this.request = request;
36+
}
37+
38+
@Override
39+
public int code() {
40+
return resp.statusCode();
41+
}
42+
43+
@Override
44+
public AsyncBody body() {
45+
return result;
46+
}
47+
48+
@Override
49+
public HttpRequest request() {
50+
return request;
51+
}
52+
53+
@Override
54+
public Optional<HttpResponse<?>> previousResponse() {
55+
return Optional.empty();
56+
}
57+
58+
}

kubernetes-client-api/src/main/java/io/fabric8/kubernetes/client/http/HttpHeaders.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,12 @@ public interface HttpHeaders {
2323

2424
/**
2525
* Returns a List of all the Header String values for the provided key/name.
26+
* <p>
27+
* key is case-insensitive as defined in RFC 2616.
2628
*
2729
* @param key The header key/name for which to provide the values.
2830
* @return the List of header values for the provided key.
31+
* @see <a href="https://datatracker.ietf.org/doc/html/rfc2616#section-4.2">RFC 2616 Section 4.2</a>
2932
*/
3033
List<String> headers(String key);
3134

kubernetes-client-api/src/main/java/io/fabric8/kubernetes/client/http/StandardHttpHeaders.java

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
*/
1616
package io.fabric8.kubernetes.client.http;
1717

18+
import java.util.ArrayList;
1819
import java.util.Collections;
1920
import java.util.LinkedHashMap;
2021
import java.util.List;
@@ -41,7 +42,13 @@ public StandardHttpHeaders(Map<String, List<String>> headers) {
4142

4243
@Override
4344
public List<String> headers(String key) {
44-
return Collections.unmodifiableList(headers.getOrDefault(key, Collections.emptyList()));
45+
final List<String> values = new ArrayList<>();
46+
for (Map.Entry<String, List<String>> entry : headers.entrySet()) {
47+
if (entry.getKey().equalsIgnoreCase(key)) {
48+
values.addAll(entry.getValue());
49+
}
50+
}
51+
return Collections.unmodifiableList(values);
4552
}
4653

4754
@Override

kubernetes-client-api/src/test/java/io/fabric8/kubernetes/client/http/AbstractHttpGetTest.java

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,23 @@ public void unsupportedResponseType() {
7979
}
8080
}
8181

82+
@Test
83+
@DisplayName("Test that headers are case insensitive")
84+
public void caseInsensitiveHeaders() throws Exception {
85+
final var value = "values";
86+
server.expect().withPath("/header").andReturn(200, value)
87+
.withHeader("fakeheader", "firstvalue")
88+
.withHeader("FAKEHEADER", "secondvalue")
89+
.always();
90+
// When
91+
try (HttpClient client = getHttpClientFactory().newBuilder().build()) {
92+
final var request = client.newHttpRequestBuilder().uri(server.url("/header")).build();
93+
final var result = client.sendAsync(request, String.class).get(10, TimeUnit.SECONDS);
94+
assertThat(result)
95+
.satisfies(r -> assertThat(r.headers("FakeHeader")).isNotEmpty().containsExactly("firstvalue", "secondvalue"));
96+
}
97+
}
98+
8299
@DisplayName("Supported response body types")
83100
@ParameterizedTest(name = "{index}: {0}")
84101
@ValueSource(classes = { String.class, byte[].class, Reader.class, InputStream.class })

0 commit comments

Comments
 (0)