This is an automated email from the ASF dual-hosted git repository. davsclaus pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/camel.git
The following commit(s) were added to refs/heads/master by this push: new 2e63c0f CAMEL-14029 Change HTTP Status code to 204 when no content exists (Undertow) (#3239) 2e63c0f is described below commit 2e63c0f4cf41fcc2d243eded2fe60099eaed6cb3 Author: Mike Barlotta <codesm...@users.noreply.github.com> AuthorDate: Tue Oct 15 23:48:52 2019 -0400 CAMEL-14029 Change HTTP Status code to 204 when no content exists (Undertow) (#3239) * CAMEL-14029 Change HTTP Status code to 204 when no content exists (Undertow) * cleanup undertow code for 204 switch * cleanup * move code to check content based on PR comments * remove unused imports * remove extra line * minor tweak * revamp methods so has a single starting point * update approach: no longer check body for specific values * Moved all of status code setting into one method * revamp method to determine and return the status code instead of changing it * remove commented out older method * checksource = remove () --- .../undertow/DefaultUndertowHttpBinding.java | 48 +++++-- .../camel/component/undertow/UndertowConsumer.java | 10 +- .../undertow/UndertowConsumerUnregisterTest.java | 29 ++-- .../undertow/UndertowSwitchingStatus204Test.java | 154 +++++++++++++++++++++ 4 files changed, 209 insertions(+), 32 deletions(-) diff --git a/components/camel-undertow/src/main/java/org/apache/camel/component/undertow/DefaultUndertowHttpBinding.java b/components/camel-undertow/src/main/java/org/apache/camel/component/undertow/DefaultUndertowHttpBinding.java index 778e6a2..328a80c 100644 --- a/components/camel-undertow/src/main/java/org/apache/camel/component/undertow/DefaultUndertowHttpBinding.java +++ b/components/camel-undertow/src/main/java/org/apache/camel/component/undertow/DefaultUndertowHttpBinding.java @@ -42,6 +42,8 @@ import io.undertow.util.HeaderMap; import io.undertow.util.Headers; import io.undertow.util.HttpString; import io.undertow.util.Methods; +import io.undertow.util.StatusCodes; + import org.apache.camel.Exchange; import org.apache.camel.Message; import org.apache.camel.TypeConverter; @@ -319,16 +321,16 @@ public class DefaultUndertowHttpBinding implements UndertowHttpBinding { @Override public Object toHttpResponse(HttpServerExchange httpExchange, Message message) throws IOException { - boolean failed = message.getExchange().isFailed(); - int defaultCode = failed ? 500 : 200; - - int code = message.getHeader(Exchange.HTTP_RESPONSE_CODE, defaultCode, int.class); - + Exchange camelExchange = message.getExchange(); + Object body = message.getBody(); + Exception exception = camelExchange.getException(); + + int code = determineResponseCode(camelExchange, body); + message.getHeaders().put(Exchange.HTTP_RESPONSE_CODE, code); httpExchange.setStatusCode(code); - TypeConverter tc = message.getExchange().getContext().getTypeConverter(); - //copy headers from Message to Response + TypeConverter tc = message.getExchange().getContext().getTypeConverter(); for (Map.Entry<String, Object> entry : message.getHeaders().entrySet()) { String key = entry.getKey(); Object value = entry.getValue(); @@ -337,16 +339,13 @@ public class DefaultUndertowHttpBinding implements UndertowHttpBinding { while (it.hasNext()) { String headerValue = tc.convertTo(String.class, it.next()); if (headerValue != null && headerFilterStrategy != null - && !headerFilterStrategy.applyFilterToCamelHeaders(key, headerValue, message.getExchange())) { + && !headerFilterStrategy.applyFilterToCamelHeaders(key, headerValue, camelExchange)) { LOG.trace("HTTP-Header: {}={}", key, headerValue); httpExchange.getResponseHeaders().add(new HttpString(key), headerValue); } } } - Object body = message.getBody(); - Exception exception = message.getExchange().getException(); - if (exception != null && !isMuteException()) { if (isTransferException()) { // we failed due an exception, and transfer it as java serialized object @@ -373,12 +372,12 @@ public class DefaultUndertowHttpBinding implements UndertowHttpBinding { } // and mark the exception as failure handled, as we handled it by returning it as the response - ExchangeHelper.setFailureHandled(message.getExchange()); + ExchangeHelper.setFailureHandled(camelExchange); } else if (exception != null && isMuteException()) { // mark the exception as failure handled, as we handled it by actively muting it - ExchangeHelper.setFailureHandled(message.getExchange()); + ExchangeHelper.setFailureHandled(camelExchange); } - + // set the content type in the response. String contentType = MessageHelper.getContentType(message); if (contentType != null) { @@ -389,6 +388,27 @@ public class DefaultUndertowHttpBinding implements UndertowHttpBinding { return body; } + /* + * set the HTTP status code + */ + private int determineResponseCode(Exchange camelExchange, Object body) { + boolean failed = camelExchange.isFailed(); + int defaultCode = failed ? 500 : 200; + + Message message = camelExchange.getMessage(); + Integer currentCode = message.getHeader(Exchange.HTTP_RESPONSE_CODE, Integer.class); + int codeToUse = currentCode == null ? defaultCode : currentCode; + + if (codeToUse != 500) { + if ((body == null) || (body instanceof String && ((String) body).trim().isEmpty())) { + // no content + codeToUse = currentCode == null ? 204 : currentCode; + } + } + + return codeToUse; + } + @Override public Object toHttpRequest(ClientRequest clientRequest, Message message) { diff --git a/components/camel-undertow/src/main/java/org/apache/camel/component/undertow/UndertowConsumer.java b/components/camel-undertow/src/main/java/org/apache/camel/component/undertow/UndertowConsumer.java index 6e2d129..6ec1981 100644 --- a/components/camel-undertow/src/main/java/org/apache/camel/component/undertow/UndertowConsumer.java +++ b/components/camel-undertow/src/main/java/org/apache/camel/component/undertow/UndertowConsumer.java @@ -202,7 +202,7 @@ public class UndertowConsumer extends DefaultConsumer implements HttpHandler { httpExchange.getResponseSender().send(bodyAsByteBuffer); } } - + /** * Create an {@link Exchange} from the associated {@link UndertowEndpoint} and set the {@code in} {@link Message}'s * body to the given {@code message} and {@link UndertowConstants#CONNECTION_KEY} header to the given @@ -266,13 +266,7 @@ public class UndertowConsumer extends DefaultConsumer implements HttpHandler { } private Object getResponseBody(HttpServerExchange httpExchange, Exchange camelExchange) throws IOException { - Object result; - if (camelExchange.hasOut()) { - result = getEndpoint().getUndertowHttpBinding().toHttpResponse(httpExchange, camelExchange.getOut()); - } else { - result = getEndpoint().getUndertowHttpBinding().toHttpResponse(httpExchange, camelExchange.getIn()); - } - return result; + return getEndpoint().getUndertowHttpBinding().toHttpResponse(httpExchange, camelExchange.getMessage()); } private HttpHandler wrapHandler(HttpHandler handler, UndertowEndpoint endpoint) { diff --git a/components/camel-undertow/src/test/java/org/apache/camel/component/undertow/UndertowConsumerUnregisterTest.java b/components/camel-undertow/src/test/java/org/apache/camel/component/undertow/UndertowConsumerUnregisterTest.java index 4f8943f..cf1c46c 100644 --- a/components/camel-undertow/src/test/java/org/apache/camel/component/undertow/UndertowConsumerUnregisterTest.java +++ b/components/camel-undertow/src/test/java/org/apache/camel/component/undertow/UndertowConsumerUnregisterTest.java @@ -59,22 +59,24 @@ public class UndertowConsumerUnregisterTest extends BaseUndertowTest { } }; Exchange ret = template.request("undertow:http://localhost:{{port}}/foo", sender); - Assert.assertEquals(200, ret.getOut().getHeader(Exchange.HTTP_RESPONSE_CODE)); - Assert.assertEquals("test", ret.getOut().getBody(String.class)); + Assert.assertEquals(200, ret.getMessage().getHeader(Exchange.HTTP_RESPONSE_CODE)); + Assert.assertEquals("test", ret.getMessage().getBody(String.class)); + ret = template.request("undertow:http://localhost:{{port}}/bar", sender); - Assert.assertEquals(200, ret.getOut().getHeader(Exchange.HTTP_RESPONSE_CODE)); - Assert.assertEquals("test", ret.getOut().getBody(String.class)); + Assert.assertEquals(200, ret.getMessage().getHeader(Exchange.HTTP_RESPONSE_CODE)); + Assert.assertEquals("test", ret.getMessage().getBody(String.class)); UndertowComponent component = context.getComponent("undertow", UndertowComponent.class); UndertowConsumer consumerFoo = (UndertowConsumer) context.getRoute("route-foo").getConsumer(); component.unregisterEndpoint(consumerFoo.getEndpoint().getHttpHandlerRegistrationInfo(), consumerFoo.getEndpoint().getSslContext()); ret = template.request("undertow:http://localhost:{{port}}/foo", sender); - Assert.assertEquals(404, ret.getOut().getHeader(Exchange.HTTP_RESPONSE_CODE)); - Assert.assertEquals("No matching path found", ret.getOut().getBody(String.class)); + Assert.assertEquals(404, ret.getMessage().getHeader(Exchange.HTTP_RESPONSE_CODE)); + Assert.assertEquals("No matching path found", ret.getMessage().getBody(String.class)); + ret = template.request("undertow:http://localhost:{{port}}/bar", sender); - Assert.assertEquals(200, ret.getOut().getHeader(Exchange.HTTP_RESPONSE_CODE)); - Assert.assertEquals("test", ret.getOut().getBody(String.class)); + Assert.assertEquals(200, ret.getMessage().getHeader(Exchange.HTTP_RESPONSE_CODE)); + Assert.assertEquals("test", ret.getMessage().getBody(String.class)); mockFoo.assertIsSatisfied(); mockBar.assertIsSatisfied(); @@ -84,8 +86,15 @@ public class UndertowConsumerUnregisterTest extends BaseUndertowTest { protected RouteBuilder createRouteBuilder() throws Exception { return new RouteBuilder() { public void configure() { - from("undertow:http://localhost:{{port}}/foo").id("route-foo").to("mock:foo"); - from("undertow:http://localhost:{{port}}/bar").id("route-bar").to("mock:bar"); + from("undertow:http://localhost:{{port}}/foo") + .id("route-foo") + .setBody().constant("test") + .to("mock:foo"); + + from("undertow:http://localhost:{{port}}/bar") + .id("route-bar") + .setBody().constant("test") + .to("mock:bar"); } }; } diff --git a/components/camel-undertow/src/test/java/org/apache/camel/component/undertow/UndertowSwitchingStatus204Test.java b/components/camel-undertow/src/test/java/org/apache/camel/component/undertow/UndertowSwitchingStatus204Test.java new file mode 100644 index 0000000..a6f20e9 --- /dev/null +++ b/components/camel-undertow/src/test/java/org/apache/camel/component/undertow/UndertowSwitchingStatus204Test.java @@ -0,0 +1,154 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.camel.component.undertow; + +import org.apache.camel.Exchange; +import org.apache.camel.Message; +import org.apache.camel.builder.RouteBuilder; +import org.apache.http.HttpResponse; +import org.apache.http.client.HttpClient; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.client.methods.HttpUriRequest; +import org.apache.http.impl.client.HttpClientBuilder; +import org.apache.http.util.EntityUtils; +import org.junit.Test; + +public class UndertowSwitchingStatus204Test extends BaseUndertowTest { + + @Test + public void testSwitchNoBodyTo204ViaHttpEmptyBody() throws Exception { + HttpUriRequest request = new HttpGet("http://localhost:" + getPort() + "/foo"); + HttpClient httpClient = HttpClientBuilder.create().build(); + HttpResponse httpResponse = httpClient.execute(request); + + assertEquals(204, httpResponse.getStatusLine().getStatusCode()); + assertNull(httpResponse.getEntity()); + } + + @Test + public void testSwitchingNoBodyTo204NettyHttpViaCamelEmptyBody() throws Exception { + Exchange inExchange = this.createExchangeWithBody("Hello World"); + Exchange outExchange = template.send("undertow:http://localhost:{{port}}/foo", inExchange); + + Message msg = outExchange.getMessage(); + assertEquals(204, msg.getHeader(Exchange.HTTP_RESPONSE_CODE)); + assertEquals("", msg.getBody(String.class)); + } + + @Test + public void testSwitchingNoBodyTo204ViaCamelRouteEmptyBody() throws Exception { + Exchange inExchange = this.createExchangeWithBody("Hello World"); + Exchange outExchange = template.send("direct:foo", inExchange); + + Message msg = outExchange.getMessage(); + assertEquals(204, msg.getHeader(Exchange.HTTP_RESPONSE_CODE)); + assertEquals("", msg.getBody(String.class)); + } + + @Test + public void testNoSwitchingHasBodyViaHttpNoContent() throws Exception { + HttpUriRequest request = new HttpGet("http://localhost:" + getPort() + "/bar"); + HttpClient httpClient = HttpClientBuilder.create().build(); + HttpResponse httpResponse = httpClient.execute(request); + + assertEquals(200, httpResponse.getStatusLine().getStatusCode()); + assertNotNull(httpResponse.getEntity()); + assertEquals("No Content", EntityUtils.toString(httpResponse.getEntity())); + } + + @Test + public void testNoSwitchingHasBodyNettyHttpViaCamelNoContent() throws Exception { + Exchange inExchange = this.createExchangeWithBody("Hello World"); + Exchange outExchange = template.send("undertow:http://localhost:{{port}}/bar", inExchange); + + Message msg = outExchange.getMessage(); + assertEquals(200, msg.getHeader(Exchange.HTTP_RESPONSE_CODE)); + assertEquals("No Content", msg.getBody(String.class)); + } + + @Test + public void testNoSwitchingHasBodyViaCamelRouteNoContent() throws Exception { + Exchange inExchange = this.createExchangeWithBody("Hello World"); + Exchange outExchange = template.send("direct:bar", inExchange); + + Message msg = outExchange.getMessage(); + assertEquals(200, msg.getHeader(Exchange.HTTP_RESPONSE_CODE)); + assertEquals("No Content", msg.getBody(String.class)); + } + + @Test + public void testNoSwitchingHasCodeViaHttpNoContent() throws Exception { + HttpUriRequest request = new HttpGet("http://localhost:" + getPort() + "/foobar"); + HttpClient httpClient = HttpClientBuilder.create().build(); + HttpResponse httpResponse = httpClient.execute(request); + + assertEquals(200, httpResponse.getStatusLine().getStatusCode()); + assertNotNull(httpResponse.getEntity()); + assertEquals("", EntityUtils.toString(httpResponse.getEntity())); + } + + @Test + public void testNoSwitchingHasCodeNettyHttpViaCamelNoContent() throws Exception { + Exchange inExchange = this.createExchangeWithBody("Hello World"); + Exchange outExchange = template.send("undertow:http://localhost:{{port}}/foobar", inExchange); + + Message msg = outExchange.getMessage(); + assertEquals(200, msg.getHeader(Exchange.HTTP_RESPONSE_CODE)); + assertEquals("", msg.getBody(String.class)); + } + + @Test + public void testNoSwitchingHasCodeViaCamelRouteNoContent() throws Exception { + Exchange inExchange = this.createExchangeWithBody("Hello World"); + Exchange outExchange = template.send("direct:foobar", inExchange); + + Message msg = outExchange.getMessage(); + assertEquals(200, msg.getHeader(Exchange.HTTP_RESPONSE_CODE)); + assertEquals("", msg.getBody(String.class)); + } + + @Override + protected RouteBuilder createRouteBuilder() throws Exception { + return new RouteBuilder() { + @Override + public void configure() throws Exception { + + from("undertow:http://localhost:{{port}}/foo") + .setBody().constant(""); + + from("direct:foo") + .to("undertow:http://localhost:{{port}}/foo"); + + + from("undertow:http://localhost:{{port}}/bar") + .setBody().constant("No Content"); + + from("direct:bar") + .to("undertow:http://localhost:{{port}}/bar"); + + + from("undertow:http://localhost:{{port}}/foobar") + .setHeader(Exchange.HTTP_RESPONSE_CODE, constant(200)) + .setBody().constant(""); + + from("direct:foobar") + .to("undertow:http://localhost:{{port}}/foobar"); + + } + }; + } +}