Support delete with body in zuul where possible.

The apache http client and ok http client support delete with body, ribbon rest client does not.

fixes gh-949
This commit is contained in:
Spencer Gibb
2016-08-31 11:43:05 -06:00
parent dc26b1efa8
commit 9b550f7293
7 changed files with 64 additions and 23 deletions

View File

@@ -55,9 +55,17 @@ public class RestClientRibbonCommand extends AbstractRibbonCommand<RestClient, H
@Override
protected HttpRequest createRequest() throws Exception {
final InputStream requestEntity;
// ApacheHttpClient4Handler does not support body in delete requests
if (getContext().getMethod().equalsIgnoreCase("DELETE")) {
requestEntity = null;
} else {
requestEntity = this.context.getRequestEntity();
}
HttpRequest.Builder builder = HttpRequest.newBuilder()
.verb(getVerb(this.context.getMethod())).uri(this.context.uri())
.entity(this.context.getRequestEntity());
.entity(requestEntity);
if (this.context.getRetryable() != null) {
builder.setRetriable(this.context.getRetryable());

View File

@@ -176,10 +176,6 @@ public class RibbonRoutingFilter extends ZuulFilter {
protected InputStream getRequestBody(HttpServletRequest request) {
InputStream requestEntity = null;
// ApacheHttpClient4Handler does not support body in delete requests
if (request.getMethod().equals("DELETE")) {
return null;
}
try {
requestEntity = (InputStream) RequestContext.getCurrentContext()
.get("requestEntity");

View File

@@ -21,6 +21,7 @@ import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.notNullValue;
import static org.hamcrest.Matchers.startsWith;
import static org.hamcrest.core.IsNull.nullValue;
import static org.junit.Assert.assertThat;
import java.io.ByteArrayInputStream;
@@ -116,6 +117,12 @@ public class RestClientRibbonCommandTests {
testEntity(entityValue, new ByteArrayInputStream(entityValue.getBytes()), true, "POST");
}
@Test
public void testNonEmptyEntityDelete() throws Exception {
String entityValue = "abcd";
testEntity(entityValue, new ByteArrayInputStream(entityValue.getBytes()), true, "DELETE");
}
void testEntity(String entityValue, ByteArrayInputStream requestEntity, boolean addContentLengthHeader, String method) throws Exception {
String lengthString = String.valueOf(entityValue.length());
Long length = null;
@@ -154,10 +161,14 @@ public class RestClientRibbonCommandTests {
is(equalTo("foo")));
assertThat("entity is missing", request.getEntity(), is(notNullValue()));
assertThat("entity is wrong type", InputStream.class.isAssignableFrom(request.getEntity().getClass()), is(true));
InputStream entity = (InputStream) request.getEntity();
String string = StreamUtils.copyToString(entity, Charset.forName("UTF-8"));
assertThat("content is wrong", string, is(equalTo(entityValue)));
if (method.equalsIgnoreCase("DELETE")) {
assertThat("entity is was non-null", request.getEntity(), is(nullValue()));
} else {
assertThat("entity is missing", request.getEntity(), is(notNullValue()));
assertThat("entity is wrong type", InputStream.class.isAssignableFrom(request.getEntity().getClass()), is(true));
InputStream entity = (InputStream) request.getEntity();
String string = StreamUtils.copyToString(entity, Charset.forName("UTF-8"));
assertThat("content is wrong", string, is(equalTo(entityValue)));
}
}
}

View File

@@ -77,11 +77,6 @@ import com.netflix.loadbalancer.ServerList;
@DirtiesContext
public class HttpClientRibbonCommandIntegrationTests extends ZuulProxyTestBase {
@Override
protected boolean supportsPatch() {
return true;
}
@Before
public void init() {
super.setTestRequestcontext();

View File

@@ -52,11 +52,6 @@ import org.springframework.web.bind.annotation.RestController;
@DirtiesContext
public class OkHttpRibbonCommandIntegrationTests extends ZuulProxyTestBase {
@Override
protected boolean supportsPatch() {
return true;
}
@Before
public void init() {
super.setTestRequestcontext();

View File

@@ -100,6 +100,11 @@ public class RestClientRibbonCommandIntegrationTests extends ZuulProxyTestBase {
return false;
}
@Override
protected boolean supportsDeleteWithBody() {
return false;
}
@Test
public void simpleHostRouteWithTrailingSlash() {
this.routes.addRoute("/self/**", "http://localhost:" + this.port + "/");

View File

@@ -103,6 +103,20 @@ public abstract class ZuulProxyTestBase {
RequestContext.getCurrentContext().unset();
}
/**
* used to disable patch tests if client doesn't support it
*/
protected boolean supportsPatch() {
return true;
}
/**
* used to switch delete tests with a boyd if client doesn't support it
*/
protected boolean supportsDeleteWithBody() {
return true;
}
protected String getRoute(String path) {
for (Route route : this.routes.getRoutes()) {
if (path.equals(route.getFullPath())) {
@@ -192,6 +206,20 @@ public abstract class ZuulProxyTestBase {
assertFalse(myErrorController.wasControllerUsed());
}
@Test
public void ribbonDeleteWithBody() {
this.endpoint.reset();
ResponseEntity<String> result = new TestRestTemplate().exchange(
"http://localhost:" + this.port + "/simple/deletewithbody", HttpMethod.DELETE,
new HttpEntity<>("deleterequestbody"), String.class);
assertEquals(HttpStatus.OK, result.getStatusCode());
if (supportsDeleteWithBody()) {
assertEquals("Deleted deleterequestbody", result.getBody());
} else {
assertEquals("Deleted null", result.getBody());
}
}
@Test
public void ribbonRouteWithNonExistentUri() {
String uri = "/simple/nonExistent";
@@ -272,8 +300,6 @@ public abstract class ZuulProxyTestBase {
assertEquals("Posted [(bar)] and Content-Length was: 13!", result.getBody());
}
protected abstract boolean supportsPatch();
public static abstract class AbstractZuulProxyApplication
extends DelegatingWebMvcConfiguration {
@@ -297,7 +323,12 @@ public abstract class ZuulProxyTestBase {
public String postWithFormParam(HttpServletRequest request,
@RequestBody MultiValueMap<String, String> body) {
return "Posted " + body.get("foo") + " and Content-Length was: " + request.getContentLength() + "!";
}
}
@RequestMapping(value = "/deletewithbody", method = RequestMethod.DELETE)
public String deleteWithBody(@RequestBody(required = false) String body) {
return "Deleted " + body;
}
@RequestMapping(value = "/local/{id}", method = RequestMethod.DELETE)
public String delete(@PathVariable String id) {