[OLINGO-1416] Better header processing
diff --git a/lib/client-core/src/main/java/org/apache/olingo/client/core/communication/request/AsyncBatchRequestWrapperImpl.java b/lib/client-core/src/main/java/org/apache/olingo/client/core/communication/request/AsyncBatchRequestWrapperImpl.java
index c99e583..0502f3e 100644
--- a/lib/client-core/src/main/java/org/apache/olingo/client/core/communication/request/AsyncBatchRequestWrapperImpl.java
+++ b/lib/client-core/src/main/java/org/apache/olingo/client/core/communication/request/AsyncBatchRequestWrapperImpl.java
@@ -18,7 +18,6 @@
*/
package org.apache.olingo.client.core.communication.request;
-import java.net.URI;
import java.util.Collection;
import org.apache.commons.io.IOUtils;
@@ -95,7 +94,7 @@
if (headers == null || headers.isEmpty()) {
throw new AsyncRequestException("Invalid async request response. Monitor URL not found");
} else {
- this.location = URI.create(headers.iterator().next());
+ this.location = createLocation(headers.iterator().next());
}
headers = res.getHeader(HttpHeader.RETRY_AFTER);
diff --git a/lib/client-core/src/main/java/org/apache/olingo/client/core/communication/request/AsyncRequestWrapperImpl.java b/lib/client-core/src/main/java/org/apache/olingo/client/core/communication/request/AsyncRequestWrapperImpl.java
index 61b2e05..924f47b 100644
--- a/lib/client-core/src/main/java/org/apache/olingo/client/core/communication/request/AsyncRequestWrapperImpl.java
+++ b/lib/client-core/src/main/java/org/apache/olingo/client/core/communication/request/AsyncRequestWrapperImpl.java
@@ -20,6 +20,7 @@
import java.io.IOException;
import java.net.URI;
+import java.util.Objects;
import java.util.logging.Level;
import java.util.logging.Logger;
@@ -86,6 +87,7 @@
// target uri
this.uri = odataRequest.getURI();
+ Objects.requireNonNull(this.uri, "Target URI can't be null");
HttpClient _httpClient = odataClient.getConfiguration().getHttpClientFactory().create(method, this.uri);
if (odataClient.getConfiguration().isGzipCompression()) {
@@ -139,6 +141,19 @@
return executeHttpRequest(httpClient, this.request);
}
+ private URI checkLocation(URI uri) {
+ if (!this.uri.getScheme().equals(uri.getScheme())) {
+ throw new AsyncRequestException("Unexpected scheme in the Location header");
+ }
+ if (!this.uri.getHost().equals(uri.getHost())) {
+ throw new AsyncRequestException("Unexpected host name in the Location header");
+ }
+ if (this.uri.getPort() != uri.getPort()) {
+ throw new AsyncRequestException("Unexpected port in the Location header");
+ }
+ return uri;
+ }
+
public class AsyncResponseWrapperImpl implements AsyncResponseWrapper<R> {
static final int DEFAULT_RETRY_AFTER = 5;
@@ -222,6 +237,10 @@
return response;
}
+ URI createLocation(String string) {
+ return checkLocation(URI.create(string));
+ }
+
int parseReplyAfter(String value) {
if (value == null || value.isEmpty()) {
return DEFAULT_RETRY_AFTER;
@@ -274,7 +293,7 @@
private void retrieveMonitorDetails(final HttpResponse res) {
Header[] headers = res.getHeaders(HttpHeader.LOCATION);
if (ArrayUtils.isNotEmpty(headers)) {
- this.location = URI.create(headers[0].getValue());
+ this.location = createLocation(headers[0].getValue());
} else {
throw new AsyncRequestException(
"Invalid async request response. Monitor URL '" + headers[0].getValue() + "'");
diff --git a/lib/client-core/src/test/java/org/apache/olingo/client/core/communication/request/AsyncRequestWrapperTest.java b/lib/client-core/src/test/java/org/apache/olingo/client/core/communication/request/AsyncRequestWrapperTest.java
index 43b0456..0287e0d 100644
--- a/lib/client-core/src/test/java/org/apache/olingo/client/core/communication/request/AsyncRequestWrapperTest.java
+++ b/lib/client-core/src/test/java/org/apache/olingo/client/core/communication/request/AsyncRequestWrapperTest.java
@@ -29,7 +29,6 @@
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
-
import org.apache.http.HttpResponse;
import org.apache.http.HttpResponseFactory;
import org.apache.http.HttpVersion;
@@ -91,7 +90,7 @@
}
private AsyncRequestWrapperImpl createAsyncRequestWrapperImplWithRetryAfter(int retryAfter)
- throws IOException {
+ throws IOException, URISyntaxException {
HttpClient httpClient = mock(HttpClient.class);
ODataClient oDataClient = mock(ODataClient.class);
@@ -116,13 +115,14 @@
AbstractODataRequest oDataRequest = mock(AbstractODataRequest.class);
ODataResponse oDataResponse = mock(ODataResponse.class);
when(oDataRequest.getResponseTemplate()).thenReturn(oDataResponse);
+ when(oDataRequest.getURI()).thenReturn(new URI("http://localhost/path"));
when(oDataResponse.initFromHttpResponse(any(HttpResponse.class))).thenReturn(null);
return new AsyncRequestWrapperImpl(oDataClient, oDataRequest);
}
@Test
- public void testTooBigRetryAfter() throws IOException {
+ public void testTooBigRetryAfter() throws IOException, URISyntaxException {
AsyncRequestWrapperImpl req = createAsyncRequestWrapperImplWithRetryAfter(Integer.MAX_VALUE);
AsyncResponseWrapper wrappedResponse = req.execute();
@@ -132,7 +132,7 @@
}
@Test
- public void testZeroRetryAfter() throws IOException {
+ public void testZeroRetryAfter() throws IOException, URISyntaxException {
AsyncRequestWrapperImpl req = createAsyncRequestWrapperImplWithRetryAfter(0);
AsyncResponseWrapper wrappedResponse = req.execute();
@@ -142,7 +142,7 @@
}
@Test
- public void testNegativeRetryAfter() throws IOException {
+ public void testNegativeRetryAfter() throws IOException, URISyntaxException {
AsyncRequestWrapperImpl req = createAsyncRequestWrapperImplWithRetryAfter(-1);
AsyncResponseWrapper wrappedResponse = req.execute();
@@ -152,7 +152,7 @@
}
@Test
- public void testRetryAfter() throws IOException {
+ public void testRetryAfter() throws IOException, URISyntaxException {
int retryAfter = 7;
assertNotEquals(retryAfter, AsyncResponseWrapperImpl.DEFAULT_RETRY_AFTER);
@@ -178,4 +178,68 @@
assertEquals("Exception", ex.getMessage());
}
+ private AsyncResponseWrapperImpl createAsyncRequestWrapperImplWithLocation(String target, String location)
+ throws IOException, URISyntaxException {
+
+ HttpClient httpClient = mock(HttpClient.class);
+ ODataClient oDataClient = mock(ODataClient.class);
+ Configuration configuration = mock(Configuration.class);
+ HttpClientFactory httpClientFactory = mock(HttpClientFactory.class);
+ HttpUriRequestFactory httpUriRequestFactory = mock(HttpUriRequestFactory.class);
+ HttpUriRequest httpUriRequest = mock(HttpUriRequest.class);
+
+ when(oDataClient.getConfiguration()).thenReturn(configuration);
+ when(configuration.getHttpClientFactory()).thenReturn(httpClientFactory);
+ when(configuration.getHttpUriRequestFactory()).thenReturn(httpUriRequestFactory);
+ when(httpClientFactory.create(any(), any())).thenReturn(httpClient);
+ when(httpUriRequestFactory.create(any(), any())).thenReturn(httpUriRequest);
+
+ HttpResponseFactory factory = new DefaultHttpResponseFactory();
+ HttpResponse firstResponse = factory.newHttpResponse(
+ new BasicStatusLine(HttpVersion.HTTP_1_1, 202, null), null);
+ firstResponse.addHeader(HttpHeader.LOCATION, location);
+ when(httpClient.execute(any(HttpUriRequest.class))).thenReturn(firstResponse);
+
+ ODataResponse oDataResponse = mock(ODataResponse.class);
+ when(oDataResponse.initFromHttpResponse(any(HttpResponse.class))).thenReturn(null);
+
+ AbstractODataRequest oDataRequest = mock(AbstractODataRequest.class);
+ when(oDataRequest.getURI()).thenReturn(new URI(target));
+ when(oDataRequest.getResponseTemplate()).thenReturn(oDataResponse);
+
+ AsyncRequestWrapperImpl req = new AsyncRequestWrapperImpl(oDataClient, oDataRequest);
+ AsyncResponseWrapper wrappedResponse = req.execute();
+ assertTrue(wrappedResponse instanceof AsyncResponseWrapperImpl);
+ return (AsyncResponseWrapperImpl) wrappedResponse;
+ }
+
+ @Test(expected = AsyncRequestException.class)
+ public void testLocationWithInvalidScheme() throws IOException, URISyntaxException {
+ String target = "https://server/path";
+ String location = "http://server/path";
+ createAsyncRequestWrapperImplWithLocation(target, location);
+ }
+
+ @Test(expected = AsyncRequestException.class)
+ public void testLocationWithInvalidHost() throws IOException, URISyntaxException {
+ String target = "http://server/path";
+ String location = "http://something.else/path";
+ createAsyncRequestWrapperImplWithLocation(target, location);
+ }
+
+ @Test(expected = AsyncRequestException.class)
+ public void testLocationWithInvalidPort() throws IOException, URISyntaxException {
+ String target = "http://server/path";
+ String location = "http://server:8080/path";
+ createAsyncRequestWrapperImplWithLocation(target, location);
+ }
+
+ @Test
+ public void testLocationWithDifferentPaths() throws IOException, URISyntaxException {
+ String target = "http://server/path";
+ String location = "http://server/monitor";
+ AsyncResponseWrapperImpl wrapper = createAsyncRequestWrapperImplWithLocation(target, location);
+ assertEquals(new URI(location), wrapper.location);
+ }
+
}