Skip to content

Commit 5a21b0f

Browse files
committed
Merge master into codex/openfeign-2782-builder-clone
Signed-off-by: Marvin Froeder <velo.br@gmail.com>
2 parents 232012f + ffd8667 commit 5a21b0f

47 files changed

Lines changed: 975 additions & 94 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.mvn/extensions.xml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,11 @@
1919
<extension>
2020
<groupId>com.gradle</groupId>
2121
<artifactId>develocity-maven-extension</artifactId>
22-
<version>2.4.2</version>
22+
<version>2.5.0</version>
2323
</extension>
2424
<extension>
2525
<groupId>com.gradle</groupId>
2626
<artifactId>common-custom-user-data-maven-extension</artifactId>
27-
<version>2.2.0</version>
27+
<version>2.3.0</version>
2828
</extension>
2929
</extensions>

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
### Version 13.14
2+
3+
* Add support for the HTTP QUERY method (RFC 10008) — safe, idempotent, and cacheable with a
4+
request body. `HttpCacheInterceptor` includes QUERY in its default cacheable set and
5+
incorporates a body hash into the cache key to reduce cross-body collisions.
6+
17
### Version 13.12
28

39
* `UrlencodedFormContentProcessor` now honors `CollectionFormat` from `@RequestLine`/`RequestTemplate` for array and

benchmark/pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@
3232
<jmh.version>1.37</jmh.version>
3333
<rx.netty.version>0.5.3</rx.netty.version>
3434
<rx.java.version>1.3.8</rx.java.version>
35-
<netty.version>4.2.15.Final</netty.version>
35+
<netty.version>4.2.16.Final</netty.version>
3636
<moditect.skip>true</moditect.skip>
3737
</properties>
3838

core/src/main/java/feign/BaseBuilder.java

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -318,10 +318,21 @@ B enrich() {
318318
// enrich each response interceptor, then enrich the list as a whole
319319
ResponseInterceptor[] responseArray =
320320
clone.responseInterceptors.toArray(new ResponseInterceptor[0]);
321-
for (int i = 0; i < responseArray.length; i++) {
322-
responseArray[i] =
321+
if (responseArray.length == 0) {
322+
ResponseInterceptor defaultResponseInterceptor = (context, chain) -> chain.next(context);
323+
ResponseInterceptor enrichedResponseInterceptor =
323324
(ResponseInterceptor)
324-
Capability.enrich(responseArray[i], ResponseInterceptor.class, capabilities);
325+
Capability.enrich(
326+
defaultResponseInterceptor, ResponseInterceptor.class, capabilities);
327+
if (enrichedResponseInterceptor != defaultResponseInterceptor) {
328+
responseArray = new ResponseInterceptor[] {enrichedResponseInterceptor};
329+
}
330+
} else {
331+
for (int i = 0; i < responseArray.length; i++) {
332+
responseArray[i] =
333+
(ResponseInterceptor)
334+
Capability.enrich(responseArray[i], ResponseInterceptor.class, capabilities);
335+
}
325336
}
326337
ResponseInterceptors responseInterceptors =
327338
(ResponseInterceptors)

core/src/main/java/feign/DefaultClient.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,9 @@ Response convertResponse(HttpURLConnection connection, Request request) throws I
111111
}
112112

113113
Integer length = connection.getContentLength();
114-
if (length == -1) {
114+
if (length < 0) {
115+
// -1 signals unknown or above Integer.MAX_VALUE; any other negative value is a malformed
116+
// header that HttpURLConnection surfaces verbatim
115117
length = null;
116118
}
117119
InputStream stream;
@@ -170,7 +172,6 @@ HttpURLConnection convertAndSend(Request request, Options options) throws IOExce
170172
if (field.equals(CONTENT_LENGTH)) {
171173
if (!gzipEncodedRequest && !deflateEncodedRequest) {
172174
contentLength = Integer.valueOf(value);
173-
connection.addRequestProperty(field, value);
174175
}
175176
}
176177
// Avoid add "Accept-encoding" twice or more when "compression" option is enabled
@@ -189,7 +190,7 @@ else if (field.equals(ACCEPT_ENCODING)) {
189190

190191
byte[] body = request.body();
191192

192-
if (body != null) {
193+
if (body != null && (body.length > 0 || request.httpMethod() != Request.HttpMethod.GET)) {
193194
/*
194195
* Ignore disableRequestBuffering flag if the empty body was set, to ensure that internal
195196
* retry logic applies to such requests.

core/src/main/java/feign/Logger.java

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,14 @@
2121
import static feign.Util.valuesOrEmpty;
2222
import static java.util.Objects.nonNull;
2323

24+
import java.io.Closeable;
2425
import java.io.IOException;
2526
import java.io.PrintWriter;
2627
import java.io.StringWriter;
28+
import java.util.ArrayList;
29+
import java.util.List;
2730
import java.util.logging.FileHandler;
31+
import java.util.logging.Handler;
2832
import java.util.logging.LogRecord;
2933
import java.util.logging.SimpleFormatter;
3034

@@ -182,9 +186,10 @@ protected void log(String configKey, String format, Object... args) {
182186
}
183187

184188
/** Logs to the category {@link Logger} at {@link java.util.logging.Level#FINE}, if loggable. */
185-
public static class JavaLogger extends Logger {
189+
public static class JavaLogger extends Logger implements Closeable {
186190

187191
final java.util.logging.Logger logger;
192+
private final List<Handler> handlers = new ArrayList<>();
188193

189194
/**
190195
* @deprecated Use {@link #JavaLogger(String)} or {@link #JavaLogger(Class)} instead.
@@ -256,11 +261,21 @@ public String format(LogRecord record) {
256261
}
257262
});
258263
logger.addHandler(handler);
264+
handlers.add(handler);
259265
} catch (IOException e) {
260266
throw new IllegalStateException("Could not add file handler.", e);
261267
}
262268
return this;
263269
}
270+
271+
@Override
272+
public void close() {
273+
for (Handler handler : handlers) {
274+
logger.removeHandler(handler);
275+
handler.close();
276+
}
277+
handlers.clear();
278+
}
264279
}
265280

266281
public static class NoOpLogger extends Logger {

core/src/main/java/feign/Request.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,8 @@ public enum HttpMethod {
4444
CONNECT,
4545
OPTIONS,
4646
TRACE,
47-
PATCH(true);
47+
PATCH(true),
48+
QUERY(true);
4849

4950
private final boolean withBody;
5051

@@ -554,7 +555,7 @@ public boolean isBinary() {
554555
}
555556

556557
public static Body create(String data) {
557-
return new Body(data.getBytes());
558+
return create(data, Util.UTF_8);
558559
}
559560

560561
public static Body create(String data, Charset charset) {

core/src/main/java/feign/RequestLine.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,10 @@
3535
*
3636
* <p>The string must begin with a valid {@linkplain feign.Request.HttpMethod HTTP method name}
3737
* (e.g. {@linkplain feign.Request.HttpMethod#GET GET}, {@linkplain feign.Request.HttpMethod#POST
38-
* POST}, {@linkplain feign.Request.HttpMethod#PUT PUT}), followed by a space and a URI template.
39-
* If only the HTTP method is specified (e.g. {@code "DELETE"}), the request will use the base URL
40-
* defined for the client.
38+
* POST}, {@linkplain feign.Request.HttpMethod#PUT PUT}, {@linkplain
39+
* feign.Request.HttpMethod#QUERY QUERY}), followed by a space and a URI template. If only the
40+
* HTTP method is specified (e.g. {@code "DELETE"}), the request will use the base URL defined for
41+
* the client.
4142
*
4243
* <p>Example:
4344
*

core/src/main/java/feign/codec/StringDecoder.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ public Object decode(Response response, Type type) throws IOException {
3131
return null;
3232
}
3333
if (String.class.equals(type)) {
34-
return Util.toString(body.asReader(Util.UTF_8));
34+
return Util.toString(body.asReader(response.charset()));
3535
}
3636
throw new DecodeException(
3737
response.status(),

core/src/main/java/feign/template/HeaderTemplate.java

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,10 @@ private HeaderTemplate(String name, Iterable<String> values, Charset charset, bo
141141

142142
public Collection<String> getValues() {
143143
return Collections.unmodifiableList(
144-
this.values.stream().map(Template::toString).collect(Collectors.toList()));
144+
this.values.stream()
145+
.map(Template::toString)
146+
.map(HeaderTemplate::stripCrlf)
147+
.collect(Collectors.toList()));
145148
}
146149

147150
public List<String> getVariables() {
@@ -167,7 +170,7 @@ public String expand(Map<String, ?> variables) {
167170
continue;
168171
}
169172

170-
expanded.add(result);
173+
expanded.add(stripCrlf(result));
171174
}
172175
}
173176

@@ -178,4 +181,16 @@ public String expand(Map<String, ?> variables) {
178181

179182
return result.toString();
180183
}
184+
185+
/**
186+
* Removes carriage return and line feed characters from a resolved header value. Values are
187+
* written to the header verbatim, so a CR or LF in a value would terminate the header line and
188+
* inject additional headers.
189+
*
190+
* @param value to sanitise.
191+
* @return the value without CR or LF characters.
192+
*/
193+
private static String stripCrlf(String value) {
194+
return value.replace("\r", "").replace("\n", "");
195+
}
181196
}

0 commit comments

Comments
 (0)