You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cxf.apache.org by se...@apache.org on 2014/12/12 13:12:21 UTC
cxf git commit: [CXF-6149] Fixing ContainerRequestContext and
ClientResponseContext hasEntity implementations
Repository: cxf
Updated Branches:
refs/heads/master b18a2bad6 -> 3f1a3c7e8
[CXF-6149] Fixing ContainerRequestContext and ClientResponseContext hasEntity implementations
Project: http://git-wip-us.apache.org/repos/asf/cxf/repo
Commit: http://git-wip-us.apache.org/repos/asf/cxf/commit/3f1a3c7e
Tree: http://git-wip-us.apache.org/repos/asf/cxf/tree/3f1a3c7e
Diff: http://git-wip-us.apache.org/repos/asf/cxf/diff/3f1a3c7e
Branch: refs/heads/master
Commit: 3f1a3c7e8317536e7e486fe79271c78e78a72b3b
Parents: b18a2ba
Author: Sergey Beryozkin <sb...@talend.com>
Authored: Fri Dec 12 12:12:05 2014 +0000
Committer: Sergey Beryozkin <sb...@talend.com>
Committed: Fri Dec 12 12:12:05 2014 +0000
----------------------------------------------------------------------
.../java/org/apache/cxf/helpers/IOUtils.java | 35 ++++++++++++++++++++
.../jaxrs/impl/ContainerRequestContextImpl.java | 11 ++++--
.../client/spec/ClientResponseContextImpl.java | 9 ++++-
.../apache/cxf/transport/http/HTTPConduit.java | 8 ++---
.../org/apache/cxf/transport/http/Headers.java | 8 ++++-
.../apache/cxf/systest/jaxrs/BookServer20.java | 15 +++++++--
.../org/apache/cxf/systest/jaxrs/BookStore.java | 8 +++--
.../jaxrs/JAXRS20ClientServerBookTest.java | 30 +++++++++++++----
8 files changed, 102 insertions(+), 22 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/cxf/blob/3f1a3c7e/core/src/main/java/org/apache/cxf/helpers/IOUtils.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/cxf/helpers/IOUtils.java b/core/src/main/java/org/apache/cxf/helpers/IOUtils.java
index 56c26c0..aab3ab9 100644
--- a/core/src/main/java/org/apache/cxf/helpers/IOUtils.java
+++ b/core/src/main/java/org/apache/cxf/helpers/IOUtils.java
@@ -27,6 +27,7 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
+import java.io.PushbackInputStream;
import java.io.Reader;
import java.io.UnsupportedEncodingException;
import java.io.Writer;
@@ -43,6 +44,40 @@ public final class IOUtils {
}
+ public static boolean isEmpty(InputStream is) throws IOException {
+ if (is == null) {
+ return true;
+ }
+ final byte[] bytes = new byte[1];
+ try {
+ if (is.markSupported()) {
+ is.mark(1);
+ try {
+ return isEof(is.read(bytes));
+ } finally {
+ is.reset();
+ }
+ }
+ // if available is 0 it does not mean it is empty; it can also throw IOException
+ if (is.available() > 0) {
+ return false;
+ }
+ } catch (IOException ex) {
+ // ignore
+ }
+ // it may be an attachment stream
+ @SuppressWarnings("resource")
+ PushbackInputStream pbStream =
+ is instanceof PushbackInputStream ? (PushbackInputStream)is : new PushbackInputStream(is);
+ boolean isEmpty = isEof(pbStream.read(bytes));
+ if (!isEmpty) {
+ pbStream.unread(bytes);
+ }
+ return isEmpty;
+ }
+ private static boolean isEof(int result) {
+ return result == -1;
+ }
/**
* Use this function instead of new String(byte[], String) to avoid surprises from
* non-standard default encodings.
http://git-wip-us.apache.org/repos/asf/cxf/blob/3f1a3c7e/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/impl/ContainerRequestContextImpl.java
----------------------------------------------------------------------
diff --git a/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/impl/ContainerRequestContextImpl.java b/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/impl/ContainerRequestContextImpl.java
index 3bdc167..039b68c 100644
--- a/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/impl/ContainerRequestContextImpl.java
+++ b/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/impl/ContainerRequestContextImpl.java
@@ -18,16 +18,18 @@
*/
package org.apache.cxf.jaxrs.impl;
+import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
-import javax.ws.rs.HttpMethod;
import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.core.Request;
import javax.ws.rs.core.SecurityContext;
import javax.ws.rs.core.UriInfo;
+import org.apache.cxf.helpers.IOUtils;
+import org.apache.cxf.jaxrs.utils.ExceptionUtils;
import org.apache.cxf.jaxrs.utils.HttpUtils;
import org.apache.cxf.message.Message;
@@ -66,8 +68,11 @@ public class ContainerRequestContextImpl extends AbstractRequestContextImpl
@Override
public boolean hasEntity() {
- InputStream is = getEntityStream();
- return is != null && !HttpMethod.GET.equals(getMethod());
+ try {
+ return !IOUtils.isEmpty(getEntityStream());
+ } catch (IOException ex) {
+ throw ExceptionUtils.toInternalServerErrorException(ex, null);
+ }
}
@Override
http://git-wip-us.apache.org/repos/asf/cxf/blob/3f1a3c7e/rt/rs/client/src/main/java/org/apache/cxf/jaxrs/client/spec/ClientResponseContextImpl.java
----------------------------------------------------------------------
diff --git a/rt/rs/client/src/main/java/org/apache/cxf/jaxrs/client/spec/ClientResponseContextImpl.java b/rt/rs/client/src/main/java/org/apache/cxf/jaxrs/client/spec/ClientResponseContextImpl.java
index 57c7391..e32c46f 100644
--- a/rt/rs/client/src/main/java/org/apache/cxf/jaxrs/client/spec/ClientResponseContextImpl.java
+++ b/rt/rs/client/src/main/java/org/apache/cxf/jaxrs/client/spec/ClientResponseContextImpl.java
@@ -18,13 +18,16 @@
*/
package org.apache.cxf.jaxrs.client.spec;
+import java.io.IOException;
import java.io.InputStream;
import javax.ws.rs.client.ClientResponseContext;
import javax.ws.rs.core.MultivaluedMap;
+import org.apache.cxf.helpers.IOUtils;
import org.apache.cxf.jaxrs.impl.AbstractResponseContextImpl;
import org.apache.cxf.jaxrs.impl.ResponseImpl;
+import org.apache.cxf.jaxrs.utils.ExceptionUtils;
import org.apache.cxf.jaxrs.utils.HttpUtils;
import org.apache.cxf.message.Message;
@@ -59,6 +62,10 @@ public class ClientResponseContextImpl extends AbstractResponseContextImpl
@Override
public boolean hasEntity() {
- return getEntityStream() != null;
+ try {
+ return !IOUtils.isEmpty(getEntityStream());
+ } catch (IOException ex) {
+ throw ExceptionUtils.toInternalServerErrorException(ex, null);
+ }
}
}
http://git-wip-us.apache.org/repos/asf/cxf/blob/3f1a3c7e/rt/transports/http/src/main/java/org/apache/cxf/transport/http/HTTPConduit.java
----------------------------------------------------------------------
diff --git a/rt/transports/http/src/main/java/org/apache/cxf/transport/http/HTTPConduit.java b/rt/transports/http/src/main/java/org/apache/cxf/transport/http/HTTPConduit.java
index da1a31e..7664525 100644
--- a/rt/transports/http/src/main/java/org/apache/cxf/transport/http/HTTPConduit.java
+++ b/rt/transports/http/src/main/java/org/apache/cxf/transport/http/HTTPConduit.java
@@ -1290,12 +1290,8 @@ public abstract class HTTPConduit
// Trust is okay, set up for writing the request.
String method = getMethod();
- if (KNOWN_HTTP_VERBS_WITH_NO_CONTENT.contains(method)) {
- handleNoOutput();
- return;
- }
-
- if (outMessage.get("org.apache.cxf.empty.request") != null) {
+ if (KNOWN_HTTP_VERBS_WITH_NO_CONTENT.contains(method)
+ || PropertyUtils.isTrue(outMessage.get(Headers.EMPTY_REQUEST_PROPERTY))) {
handleNoOutput();
return;
}
http://git-wip-us.apache.org/repos/asf/cxf/blob/3f1a3c7e/rt/transports/http/src/main/java/org/apache/cxf/transport/http/Headers.java
----------------------------------------------------------------------
diff --git a/rt/transports/http/src/main/java/org/apache/cxf/transport/http/Headers.java b/rt/transports/http/src/main/java/org/apache/cxf/transport/http/Headers.java
index 620deb1..baf8b71 100644
--- a/rt/transports/http/src/main/java/org/apache/cxf/transport/http/Headers.java
+++ b/rt/transports/http/src/main/java/org/apache/cxf/transport/http/Headers.java
@@ -43,6 +43,7 @@ import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.cxf.common.logging.LogUtils;
+import org.apache.cxf.common.util.PropertyUtils;
import org.apache.cxf.helpers.CastUtils;
import org.apache.cxf.helpers.HttpHeaderHelper;
import org.apache.cxf.message.Message;
@@ -66,6 +67,7 @@ public class Headers {
public static final String PROTOCOL_HEADERS_CONTENT_TYPE = Message.CONTENT_TYPE.toLowerCase();
public static final String HTTP_HEADERS_SETCOOKIE = "Set-Cookie";
public static final String HTTP_HEADERS_LINK = "Link";
+ public static final String EMPTY_REQUEST_PROPERTY = "org.apache.cxf.empty.request";
private static final TimeZone TIME_ZONE_GMT = TimeZone.getTimeZone("GMT");
private static final Logger LOG = LogUtils.getL7dLogger(Headers.class);
@@ -293,8 +295,12 @@ public class Headers {
* @throws IOException
*/
public void setProtocolHeadersInConnection(HttpURLConnection connection) throws IOException {
- String ct = determineContentType();
+ boolean emptyRequest = PropertyUtils.isTrue(message.get(EMPTY_REQUEST_PROPERTY));
+ // Apparently HttpUrlConnection sets a form Content-Type
+ // if no Content-Type is set even for empty requests
+ String ct = emptyRequest ? "*/*" : determineContentType();
connection.setRequestProperty(HttpHeaderHelper.CONTENT_TYPE, ct);
+
transferProtocolHeadersToURLConnection(connection);
logProtocolHeaders(Level.FINE);
}
http://git-wip-us.apache.org/repos/asf/cxf/blob/3f1a3c7e/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/BookServer20.java
----------------------------------------------------------------------
diff --git a/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/BookServer20.java b/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/BookServer20.java
index 15870bf..8fed831 100644
--- a/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/BookServer20.java
+++ b/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/BookServer20.java
@@ -50,6 +50,7 @@ import javax.ws.rs.container.PreMatching;
import javax.ws.rs.container.ResourceInfo;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.FeatureContext;
+import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriInfo;
@@ -60,6 +61,7 @@ import javax.ws.rs.ext.WriterInterceptorContext;
import org.apache.cxf.Bus;
import org.apache.cxf.BusFactory;
+import org.apache.cxf.common.util.StringUtils;
import org.apache.cxf.helpers.IOUtils;
import org.apache.cxf.jaxrs.JAXRSServerFactoryBean;
import org.apache.cxf.jaxrs.lifecycle.SingletonResourceProvider;
@@ -126,13 +128,22 @@ public class BookServer20 extends AbstractBusTestServerBase {
@Override
public void filter(ContainerRequestContext context) throws IOException {
+ UriInfo ui = context.getUriInfo();
+ String path = ui.getPath(false);
+
+ if (context.getMethod().equals("POST")
+ && "bookstore/bookheaders/simple".equals(path) && !context.hasEntity()) {
+ byte[] bytes = StringUtils.toBytesUTF8("<Book><name>Book</name><id>126</id></Book>");
+ context.getHeaders().putSingle(HttpHeaders.CONTENT_LENGTH, Integer.toString(bytes.length));
+ context.getHeaders().putSingle("Content-Type", "application/xml");
+ context.getHeaders().putSingle("EmptyRequestStreamDetected", "true");
+ context.setEntityStream(new ByteArrayInputStream(bytes));
+ }
if ("true".equals(context.getProperty("DynamicPrematchingFilter"))) {
throw new RuntimeException();
}
context.setProperty("FirstPrematchingFilter", "true");
- UriInfo ui = context.getUriInfo();
- String path = ui.getPath(false);
if ("wrongpath".equals(path)) {
context.setRequestUri(URI.create("/bookstore/bookheaders/simple"));
} else if ("throwException".equals(path)) {
http://git-wip-us.apache.org/repos/asf/cxf/blob/3f1a3c7e/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/BookStore.java
----------------------------------------------------------------------
diff --git a/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/BookStore.java b/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/BookStore.java
index 299afd8..418f484 100644
--- a/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/BookStore.java
+++ b/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/BookStore.java
@@ -720,7 +720,8 @@ public class BookStore {
@HeaderParam("BOOK") String headerBook,
@HeaderParam("Simple") String headerSimple,
@HeaderParam("ServerReaderInterceptor") String serverInterceptorHeader,
- @HeaderParam("ClientWriterInterceptor") String clientInterceptorHeader) throws Exception {
+ @HeaderParam("ClientWriterInterceptor") String clientInterceptorHeader,
+ @HeaderParam("EmptyRequestStreamDetected") String emptyStreamHeader) throws Exception {
if (!"application/xml".equals(ct)) {
throw new RuntimeException();
}
@@ -731,6 +732,9 @@ public class BookStore {
if (clientInterceptorHeader != null) {
builder.header("ClientWriterInterceptor", clientInterceptorHeader);
}
+ if (emptyStreamHeader != null) {
+ builder.header("EmptyRequestStreamDetected", emptyStreamHeader);
+ }
return builder.build();
}
@@ -773,7 +777,7 @@ public class BookStore {
throws Exception {
return echoBookByHeaderSimple(book, ct, headerBook, headerSimple, serverInterceptorHeader,
- clientInterceptorHeader);
+ clientInterceptorHeader, null);
}
private ResponseBuilder getBookByHeaderSimpleBuilder(@HeaderParam("BOOK") String headerBook,
http://git-wip-us.apache.org/repos/asf/cxf/blob/3f1a3c7e/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/JAXRS20ClientServerBookTest.java
----------------------------------------------------------------------
diff --git a/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/JAXRS20ClientServerBookTest.java b/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/JAXRS20ClientServerBookTest.java
index 1cfccf4..d8f5cc6 100644
--- a/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/JAXRS20ClientServerBookTest.java
+++ b/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/JAXRS20ClientServerBookTest.java
@@ -525,7 +525,7 @@ public class JAXRS20ClientServerBookTest extends AbstractBusClientServerTestBase
Book book = future.get();
assertSame(book, holder.value);
assertEquals(124L, book.getId());
- validatePostResponse(wc, true);
+ validatePostResponse(wc, true, false);
}
private void doTestGetBookAsyncResponse(String address, boolean asyncInvoker)
@@ -562,12 +562,16 @@ public class JAXRS20ClientServerBookTest extends AbstractBusClientServerTestBase
assertEquals("http://localhost/redirect", response.getHeaderString(HttpHeaders.LOCATION));
}
- private void validatePostResponse(WebClient wc, boolean async) {
+ private void validatePostResponse(WebClient wc, boolean async, boolean bodyEmpty) {
validateResponse(wc);
Response response = wc.getResponse();
assertEquals(!async ? "serverRead" : "serverReadAsync",
response.getHeaderString("ServerReaderInterceptor"));
- assertEquals("clientWrite", response.getHeaderString("ClientWriterInterceptor"));
+ if (!bodyEmpty) {
+ assertEquals("clientWrite", response.getHeaderString("ClientWriterInterceptor"));
+ } else {
+ assertEquals("true", response.getHeaderString("EmptyRequestStreamDetected"));
+ }
assertEquals("clientRead", response.getHeaderString("ClientReaderInterceptor"));
}
@@ -592,7 +596,17 @@ public class JAXRS20ClientServerBookTest extends AbstractBusClientServerTestBase
WebClient wc = createWebClientPost(address);
Book book = wc.post(new Book("Book", 126L), Book.class);
assertEquals(124L, book.getId());
- validatePostResponse(wc, false);
+ validatePostResponse(wc, false, false);
+ }
+
+ @Test
+ public void testPostEmptyBook() {
+ String address = "http://localhost:" + PORT + "/bookstore/bookheaders/simple";
+ WebClient wc = createWebClientPost(address);
+ WebClient.getConfig(wc).getHttpConduit().getClient().setReceiveTimeout(1000000);
+ Book book = wc.post(null, Book.class);
+ assertEquals(124L, book.getId());
+ validatePostResponse(wc, false, true);
}
@Test
@@ -602,7 +616,7 @@ public class JAXRS20ClientServerBookTest extends AbstractBusClientServerTestBase
wc.header("newmediatype", "application/v1+xml");
Book book = wc.post(new Book("Book", 126L), Book.class);
assertEquals(124L, book.getId());
- validatePostResponse(wc, false);
+ validatePostResponse(wc, false, false);
assertEquals("application/v1+xml", wc.getResponse().getHeaderString("newmediatypeused"));
}
@@ -628,7 +642,7 @@ public class JAXRS20ClientServerBookTest extends AbstractBusClientServerTestBase
WebClient wc = createWebClientPost(address);
Future<Book> future = wc.async().post(Entity.xml(new Book("Book", 126L)), Book.class);
assertEquals(124L, future.get().getId());
- validatePostResponse(wc, true);
+ validatePostResponse(wc, true, false);
}
@Test
@@ -717,7 +731,9 @@ public class JAXRS20ClientServerBookTest extends AbstractBusClientServerTestBase
@Override
public void filter(ClientRequestContext context) throws IOException {
context.getHeaders().putSingle("Simple", "simple");
- context.getHeaders().putSingle("Content-Type", MediaType.APPLICATION_XML_TYPE);
+ if (context.hasEntity()) {
+ context.getHeaders().putSingle("Content-Type", MediaType.APPLICATION_XML_TYPE);
+ }
}
}