Skip to content

Commit 425cc81

Browse files
authored
cap Content-Length before narrowing to int in Http2Client (#3431)
1 parent bb48cea commit 425cc81

2 files changed

Lines changed: 118 additions & 1 deletion

File tree

java11/src/main/java/feign/http2client/Http2Client.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,10 @@ public CompletableFuture<Response> execute(
130130

131131
protected Response toFeignResponse(Request request, HttpResponse<InputStream> httpResponse) {
132132
final OptionalLong length = httpResponse.headers().firstValueAsLong("Content-Length");
133+
final Integer contentLength =
134+
length.isPresent() && length.getAsLong() >= 0 && length.getAsLong() <= Integer.MAX_VALUE
135+
? (int) length.getAsLong()
136+
: null;
133137

134138
InputStream body = httpResponse.body();
135139

@@ -144,7 +148,7 @@ protected Response toFeignResponse(Request request, HttpResponse<InputStream> ht
144148

145149
return Response.builder()
146150
.protocolVersion(enumForName(ProtocolVersion.class, httpResponse.version()))
147-
.body(body, length.isPresent() ? (int) length.getAsLong() : null)
151+
.body(body, contentLength)
148152
.reason(httpResponse.headers().firstValue("Reason-Phrase").orElse(null))
149153
.request(request)
150154
.status(httpResponse.statusCode())
Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
/*
2+
* Copyright © 2012 The Feign Authors ([email protected])
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 feign.http2client;
17+
18+
import static org.assertj.core.api.Assertions.assertThat;
19+
20+
import feign.Request;
21+
import feign.Request.HttpMethod;
22+
import feign.Response;
23+
import java.io.ByteArrayInputStream;
24+
import java.io.InputStream;
25+
import java.net.URI;
26+
import java.net.http.HttpClient.Version;
27+
import java.net.http.HttpHeaders;
28+
import java.net.http.HttpRequest;
29+
import java.net.http.HttpResponse;
30+
import java.nio.charset.StandardCharsets;
31+
import java.util.Collections;
32+
import java.util.List;
33+
import java.util.Map;
34+
import java.util.Optional;
35+
import javax.net.ssl.SSLSession;
36+
import org.junit.jupiter.api.Test;
37+
38+
class Http2ClientContentLengthTest {
39+
40+
private static HttpResponse<InputStream> responseWithContentLength(String contentLength) {
41+
final HttpHeaders headers =
42+
HttpHeaders.of(Map.of("Content-Length", List.of(contentLength)), (name, value) -> true);
43+
return new HttpResponse<>() {
44+
@Override
45+
public int statusCode() {
46+
return 200;
47+
}
48+
49+
@Override
50+
public HttpRequest request() {
51+
return null;
52+
}
53+
54+
@Override
55+
public Optional<HttpResponse<InputStream>> previousResponse() {
56+
return Optional.empty();
57+
}
58+
59+
@Override
60+
public HttpHeaders headers() {
61+
return headers;
62+
}
63+
64+
@Override
65+
public InputStream body() {
66+
return new ByteArrayInputStream(new byte[0]);
67+
}
68+
69+
@Override
70+
public Optional<SSLSession> sslSession() {
71+
return Optional.empty();
72+
}
73+
74+
@Override
75+
public URI uri() {
76+
return URI.create("http://localhost");
77+
}
78+
79+
@Override
80+
public Version version() {
81+
return Version.HTTP_2;
82+
}
83+
};
84+
}
85+
86+
private static Response decode(String contentLength) {
87+
final Request request =
88+
Request.create(
89+
HttpMethod.GET,
90+
"http://localhost",
91+
Collections.emptyMap(),
92+
null,
93+
StandardCharsets.UTF_8,
94+
null);
95+
return new Http2Client().toFeignResponse(request, responseWithContentLength(contentLength));
96+
}
97+
98+
@Test
99+
void contentLengthAboveIntMaxIsReportedAsUnknown() {
100+
// 2^31, a valid Content-Length larger than Integer.MAX_VALUE
101+
assertThat(decode("2147483648").body().length()).isNull();
102+
}
103+
104+
@Test
105+
void negativeContentLengthIsReportedAsUnknown() {
106+
assertThat(decode("-1").body().length()).isNull();
107+
}
108+
109+
@Test
110+
void contentLengthWithinIntRangeIsPreserved() {
111+
assertThat(decode("1024").body().length()).isEqualTo(1024);
112+
}
113+
}

0 commit comments

Comments
 (0)