Skip to content

Commit e8e7fbb

Browse files
committed
Polishing contribution and fix failing test
The failing test is for Apache HttpComponents where we cannot apply the Content-Length together with other headers, and must pass it instead explicitly to ReactiveEntityProducer when writing at which point it gets set in the native headers. Closes gh-27768
1 parent bd1f34e commit e8e7fbb

File tree

4 files changed

+36
-30
lines changed

4 files changed

+36
-30
lines changed

spring-web/src/main/java/org/springframework/http/client/reactive/AbstractClientHttpRequest.java

+12-9
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2020 the original author or authors.
2+
* Copyright 2002-2022 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -74,6 +74,7 @@ public AbstractClientHttpRequest(HttpHeaders headers) {
7474
this.cookies = new LinkedMultiValueMap<>();
7575
}
7676

77+
7778
@Override
7879
public HttpHeaders getHeaders() {
7980
if (this.readOnlyHeaders != null) {
@@ -88,6 +89,16 @@ else if (State.COMMITTED.equals(this.state.get())) {
8889
}
8990
}
9091

92+
/**
93+
* Initialize the read-only headers after the request is committed.
94+
* <p>By default, this method simply applies a read-only wrapper.
95+
* Subclasses can do the same for headers from the native request.
96+
* @since 5.3.15
97+
*/
98+
protected HttpHeaders initReadOnlyHeaders() {
99+
return HttpHeaders.readOnlyHttpHeaders(this.headers);
100+
}
101+
91102
@Override
92103
public MultiValueMap<String, HttpCookie> getCookies() {
93104
if (State.COMMITTED.equals(this.state.get())) {
@@ -143,14 +154,6 @@ protected Mono<Void> doCommit(@Nullable Supplier<? extends Publisher<Void>> writ
143154
return Flux.concat(actions).then();
144155
}
145156

146-
/**
147-
* Initialize read-only headers with underlying request headers.
148-
* @return read-only headers
149-
*/
150-
protected HttpHeaders initReadOnlyHeaders() {
151-
return HttpHeaders.readOnlyHttpHeaders(this.headers);
152-
}
153-
154157

155158
/**
156159
* Apply header changes from {@link #getHeaders()} to the underlying request.

spring-web/src/main/java/org/springframework/http/client/reactive/HttpComponentsClientHttpRequest.java

+12-8
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2020 the original author or authors.
2+
* Copyright 2002-2022 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -62,6 +62,8 @@ class HttpComponentsClientHttpRequest extends AbstractClientHttpRequest {
6262
@Nullable
6363
private Flux<ByteBuffer> byteBufferFlux;
6464

65+
private transient long contentLength = -1;
66+
6567

6668
public HttpComponentsClientHttpRequest(HttpMethod method, URI uri, HttpClientContext context,
6769
DataBufferFactory dataBufferFactory) {
@@ -118,11 +120,6 @@ public Mono<Void> setComplete() {
118120
return doCommit();
119121
}
120122

121-
@Override
122-
protected HttpHeaders initReadOnlyHeaders() {
123-
return HttpHeaders.readOnlyHttpHeaders(new HttpComponentsHeadersAdapter(this.httpRequest));
124-
}
125-
126123
@Override
127124
protected void applyHeaders() {
128125
HttpHeaders headers = getHeaders();
@@ -135,6 +132,8 @@ protected void applyHeaders() {
135132
if (!this.httpRequest.containsHeader(HttpHeaders.ACCEPT)) {
136133
this.httpRequest.addHeader(HttpHeaders.ACCEPT, ALL_VALUE);
137134
}
135+
136+
this.contentLength = headers.getContentLength();
138137
}
139138

140139
@Override
@@ -156,6 +155,11 @@ protected void applyCookies() {
156155
});
157156
}
158157

158+
@Override
159+
protected HttpHeaders initReadOnlyHeaders() {
160+
return HttpHeaders.readOnlyHttpHeaders(new HttpComponentsHeadersAdapter(this.httpRequest));
161+
}
162+
159163
public AsyncRequestProducer toRequestProducer() {
160164
ReactiveEntityProducer reactiveEntityProducer = null;
161165

@@ -165,8 +169,8 @@ public AsyncRequestProducer toRequestProducer() {
165169
if (getHeaders().getContentType() != null) {
166170
contentType = ContentType.parse(getHeaders().getContentType().toString());
167171
}
168-
reactiveEntityProducer = new ReactiveEntityProducer(this.byteBufferFlux, getHeaders().getContentLength(),
169-
contentType, contentEncoding);
172+
reactiveEntityProducer = new ReactiveEntityProducer(
173+
this.byteBufferFlux, this.contentLength, contentType, contentEncoding);
170174
}
171175

172176
return new BasicRequestProducer(this.httpRequest, reactiveEntityProducer);

spring-web/src/main/java/org/springframework/http/client/reactive/JettyClientHttpRequest.java

+6-7
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2021 the original author or authors.
2+
* Copyright 2002-2022 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -126,11 +126,6 @@ public void failed(Throwable t) {
126126
});
127127
}
128128

129-
@Override
130-
protected HttpHeaders initReadOnlyHeaders() {
131-
return HttpHeaders.readOnlyHttpHeaders(new JettyHeadersAdapter(this.jettyRequest.getHeaders()));
132-
}
133-
134129
@Override
135130
protected void applyCookies() {
136131
getCookies().values().stream().flatMap(Collection::stream)
@@ -147,9 +142,13 @@ protected void applyHeaders() {
147142
}
148143
}
149144

145+
@Override
146+
protected HttpHeaders initReadOnlyHeaders() {
147+
return HttpHeaders.readOnlyHttpHeaders(new JettyHeadersAdapter(this.jettyRequest.getHeaders()));
148+
}
149+
150150
public ReactiveRequest toReactiveRequest() {
151151
return this.builder.build();
152152
}
153153

154-
155154
}

spring-web/src/main/java/org/springframework/http/client/reactive/ReactorClientHttpRequest.java

+6-6
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2020 the original author or authors.
2+
* Copyright 2002-2022 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -122,11 +122,6 @@ public Mono<Void> setComplete() {
122122
return doCommit(this.outbound::then);
123123
}
124124

125-
@Override
126-
protected HttpHeaders initReadOnlyHeaders() {
127-
return HttpHeaders.readOnlyHttpHeaders(new NettyHeadersAdapter(this.request.requestHeaders()));
128-
}
129-
130125
@Override
131126
protected void applyHeaders() {
132127
getHeaders().forEach((key, value) -> this.request.requestHeaders().set(key, value));
@@ -139,4 +134,9 @@ protected void applyCookies() {
139134
.forEach(this.request::addCookie);
140135
}
141136

137+
@Override
138+
protected HttpHeaders initReadOnlyHeaders() {
139+
return HttpHeaders.readOnlyHttpHeaders(new NettyHeadersAdapter(this.request.requestHeaders()));
140+
}
141+
142142
}

0 commit comments

Comments
 (0)