From eea9510716308f6e028ba309fddbf9d1fb2b3f52 Mon Sep 17 00:00:00 2001 From: Spencer Gibb Date: Tue, 14 Aug 2018 12:58:01 -0400 Subject: [PATCH] Adds option for setting custom content type for modify request body. fixes gh-492 --- ...ModifyRequestBodyGatewayFilterFactory.java | 40 +++++++++++++++++-- .../route/builder/GatewayFilterSpec.java | 15 +++++++ .../sample/GatewaySampleApplication.java | 4 +- 3 files changed, 53 insertions(+), 6 deletions(-) diff --git a/spring-cloud-gateway-core/src/main/java/org/springframework/cloud/gateway/filter/factory/rewrite/ModifyRequestBodyGatewayFilterFactory.java b/spring-cloud-gateway-core/src/main/java/org/springframework/cloud/gateway/filter/factory/rewrite/ModifyRequestBodyGatewayFilterFactory.java index 2ee1f74a..402cea0c 100644 --- a/spring-cloud-gateway-core/src/main/java/org/springframework/cloud/gateway/filter/factory/rewrite/ModifyRequestBodyGatewayFilterFactory.java +++ b/spring-cloud-gateway-core/src/main/java/org/springframework/cloud/gateway/filter/factory/rewrite/ModifyRequestBodyGatewayFilterFactory.java @@ -63,7 +63,18 @@ public class ModifyRequestBodyGatewayFilterFactory .flatMap(o -> config.rewriteFunction.apply(exchange, o)); BodyInserter bodyInserter = BodyInserters.fromPublisher(modifiedBody, config.getOutClass()); - CachedBodyOutputMessage outputMessage = new CachedBodyOutputMessage(exchange, exchange.getRequest().getHeaders()); + HttpHeaders headers = new HttpHeaders(); + headers.putAll(exchange.getRequest().getHeaders()); + + // the new content type will be computed by bodyInserter + // and then set in the request decorator + headers.remove(HttpHeaders.CONTENT_LENGTH); + + // if the body is changing content types, set it here, to the bodyInserter will know about it + if (config.getContentType() != null) { + headers.set(HttpHeaders.CONTENT_TYPE, config.getContentType()); + } + CachedBodyOutputMessage outputMessage = new CachedBodyOutputMessage(exchange, headers); return bodyInserter.insert(outputMessage, new BodyInserterContext()) // .log("modify_request", Level.INFO) .then(Mono.defer(() -> { @@ -71,10 +82,15 @@ public class ModifyRequestBodyGatewayFilterFactory exchange.getRequest()) { @Override public HttpHeaders getHeaders() { + long contentLength = headers.getContentLength(); HttpHeaders httpHeaders = new HttpHeaders(); httpHeaders.putAll(super.getHeaders()); - // TODO: this causes a 'HTTP/1.1 411 Length Required' on httpbin.org - httpHeaders.set(HttpHeaders.TRANSFER_ENCODING, "chunked"); + if (contentLength > 0) { + httpHeaders.setContentLength(contentLength); + } else { + // TODO: this causes a 'HTTP/1.1 411 Length Required' on httpbin.org + httpHeaders.set(HttpHeaders.TRANSFER_ENCODING, "chunked"); + } return httpHeaders; } @@ -92,7 +108,12 @@ public class ModifyRequestBodyGatewayFilterFactory public static class Config { private Class inClass; private Class outClass; + + private String contentType; + + @Deprecated private Map inHints; + @Deprecated private Map outHints; private RewriteFunction rewriteFunction; @@ -115,19 +136,23 @@ public class ModifyRequestBodyGatewayFilterFactory return this; } + @Deprecated public Map getInHints() { return inHints; } + @Deprecated public Config setInHints(Map inHints) { this.inHints = inHints; return this; } + @Deprecated public Map getOutHints() { return outHints; } + @Deprecated public Config setOutHints(Map outHints) { this.outHints = outHints; return this; @@ -149,5 +174,14 @@ public class ModifyRequestBodyGatewayFilterFactory this.rewriteFunction = rewriteFunction; return this; } + + public String getContentType() { + return contentType; + } + + public Config setContentType(String contentType) { + this.contentType = contentType; + return this; + } } } diff --git a/spring-cloud-gateway-core/src/main/java/org/springframework/cloud/gateway/route/builder/GatewayFilterSpec.java b/spring-cloud-gateway-core/src/main/java/org/springframework/cloud/gateway/route/builder/GatewayFilterSpec.java index a64af933..cfa4cc7e 100644 --- a/spring-cloud-gateway-core/src/main/java/org/springframework/cloud/gateway/route/builder/GatewayFilterSpec.java +++ b/spring-cloud-gateway-core/src/main/java/org/springframework/cloud/gateway/route/builder/GatewayFilterSpec.java @@ -206,6 +206,21 @@ public class GatewayFilterSpec extends UriSpec { .apply(c -> c.setRewriteFunction(inClass, outClass, rewriteFunction))); } + /** + * A filter that can be used to modify the request body. + * This filter is BETA and may be subject to change in a future release. + * @param inClass the class to convert the incoming request body to + * @param outClass the class the Gateway will add to the request before it is routed + * @param newContentType the new Content-Type header to be sent + * @param rewriteFunction the {@link RewriteFunction} that transforms the request body + * @param the original request body class + * @param the new request body class + * @return a {@link GatewayFilterSpec} that can be used to apply additional filters + */ + public GatewayFilterSpec modifyRequestBody(Class inClass, Class outClass, String newContentType, RewriteFunction rewriteFunction) { + return filter(getBean(ModifyRequestBodyGatewayFilterFactory.class) + .apply(c -> c.setRewriteFunction(inClass, outClass, rewriteFunction).setContentType(newContentType))); + } /** * A filter that can be used to modify the response body * This filter is BETA and may be subject to change in a future release. diff --git a/spring-cloud-gateway-sample/src/main/java/org/springframework/cloud/gateway/sample/GatewaySampleApplication.java b/spring-cloud-gateway-sample/src/main/java/org/springframework/cloud/gateway/sample/GatewaySampleApplication.java index 7af93e97..06e5d093 100644 --- a/spring-cloud-gateway-sample/src/main/java/org/springframework/cloud/gateway/sample/GatewaySampleApplication.java +++ b/spring-cloud-gateway-sample/src/main/java/org/springframework/cloud/gateway/sample/GatewaySampleApplication.java @@ -70,10 +70,8 @@ public class GatewaySampleApplication { ) .route("rewrite_request_obj", r -> r.host("*.rewriterequestobj.org") .filters(f -> f.prefixPath("/httpbin") - //TODO: add as configuration to modifyRequestBody - .setRequestHeader("Content-Type", MediaType.APPLICATION_JSON_VALUE) .addResponseHeader("X-TestHeader", "rewrite_request") - .modifyRequestBody(String.class, Hello.class, + .modifyRequestBody(String.class, Hello.class, MediaType.APPLICATION_JSON_VALUE, (exchange, s) -> { return Mono.just(new Hello(s.toUpperCase())); })