From 4b4a6c3ffcf27f6afb4d53a6af1ccfec5ea2a5ff Mon Sep 17 00:00:00 2001 From: David Connelly Date: Mon, 16 Nov 2015 15:39:55 -0800 Subject: [PATCH 1/2] Fix HttpClientWebRequest so that it supports both GET and POST requests. Should fix #452 --- .../core/request/HttpClientWebRequest.java | 54 ++++++++++++------- 1 file changed, 36 insertions(+), 18 deletions(-) diff --git a/src/main/java/microsoft/exchange/webservices/data/core/request/HttpClientWebRequest.java b/src/main/java/microsoft/exchange/webservices/data/core/request/HttpClientWebRequest.java index 8cd6ccb8f..cd156425a 100644 --- a/src/main/java/microsoft/exchange/webservices/data/core/request/HttpClientWebRequest.java +++ b/src/main/java/microsoft/exchange/webservices/data/core/request/HttpClientWebRequest.java @@ -26,6 +26,7 @@ import microsoft.exchange.webservices.data.core.WebProxy; import microsoft.exchange.webservices.data.core.exception.http.EWSHttpException; import org.apache.http.Header; +import org.apache.http.HttpEntityEnclosingRequest; import org.apache.http.HttpHost; import org.apache.http.auth.AuthScope; import org.apache.http.auth.NTCredentials; @@ -33,7 +34,9 @@ import org.apache.http.client.config.AuthSchemes; import org.apache.http.client.config.RequestConfig; import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpPost; +import org.apache.http.client.methods.HttpRequestBase; import org.apache.http.client.protocol.HttpClientContext; import org.apache.http.impl.client.BasicCredentialsProvider; import org.apache.http.impl.client.CloseableHttpClient; @@ -44,6 +47,7 @@ import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import java.net.URI; import java.util.Arrays; import java.util.HashMap; import java.util.Map; @@ -58,7 +62,7 @@ public class HttpClientWebRequest extends HttpWebRequest { /** * The Http Method. */ - private HttpPost httpPost = null; + private HttpRequestBase request = null; private CloseableHttpResponse response = null; private final CloseableHttpClient httpClient; @@ -83,38 +87,40 @@ public void close() throws IOException { // If that is not possible, we simply cleanup the whole connection if (response != null && response.getEntity() != null) { EntityUtils.consume(response.getEntity()); - } else if (httpPost != null) { - httpPost.releaseConnection(); + } else if (request != null) { + request.releaseConnection(); } // We set httpPost to null to prevent the connection from being closed again by an accidental // second call to close() // The response is kept, in case something in the library still wants to read something from it, // like response code or headers - httpPost = null; + request = null; } + /** * Prepares the request by setting appropriate headers, authentication, timeouts, etc. */ @Override public void prepareConnection() { - httpPost = new HttpPost(getUrl().toString()); + request = newRequest(getRequestMethod()); + request.setURI(URI.create(getUrl().toString())); // Populate headers. - httpPost.addHeader("Content-type", getContentType()); - httpPost.addHeader("User-Agent", getUserAgent()); - httpPost.addHeader("Accept", getAccept()); - httpPost.addHeader("Keep-Alive", "300"); - httpPost.addHeader("Connection", "Keep-Alive"); + request.addHeader("Content-type", getContentType()); + request.addHeader("User-Agent", getUserAgent()); + request.addHeader("Accept", getAccept()); + request.addHeader("Keep-Alive", "300"); + request.addHeader("Connection", "Keep-Alive"); if (isAcceptGzipEncoding()) { - httpPost.addHeader("Accept-Encoding", "gzip,deflate"); + request.addHeader("Accept-Encoding", "gzip,deflate"); } if (getHeaders() != null) { for (Map.Entry httpHeader : getHeaders().entrySet()) { - httpPost.addHeader(httpHeader.getKey(), httpHeader.getValue()); + request.addHeader(httpHeader.getKey(), httpHeader.getValue()); } } @@ -154,7 +160,17 @@ public void prepareConnection() { httpContext.setCredentialsProvider(credentialsProvider); - httpPost.setConfig(requestConfigBuilder.build()); + request.setConfig(requestConfigBuilder.build()); + } + + private static HttpRequestBase newRequest(String method) { + if (method.equals(HttpPost.METHOD_NAME)) { + return new HttpPost(); + } else if (method.equals(HttpGet.METHOD_NAME)) { + return new HttpGet(); + } else { + throw new IllegalStateException("Unsupported request method: " + method); + } } /** @@ -204,8 +220,10 @@ public OutputStream getOutputStream() throws EWSHttpException { OutputStream os = null; throwIfRequestIsNull(); os = new ByteArrayOutputStream(); - - httpPost.setEntity(new ByteArrayOSRequestEntity(os)); + if (!(request instanceof HttpEntityEnclosingRequest)) { + throw new IllegalStateException("Not an entity enclosing request"); + } + ((HttpEntityEnclosingRequest) request).setEntity(new ByteArrayOSRequestEntity(os)); return os; } @@ -289,7 +307,7 @@ public String getResponseContentType() throws EWSHttpException { @Override public int executeRequest() throws EWSHttpException, IOException { throwIfRequestIsNull(); - response = httpClient.execute(httpPost, httpContext); + response = httpClient.execute(request, httpContext); return response.getStatusLine().getStatusCode(); // ?? don't know what is wanted in return } @@ -322,7 +340,7 @@ public String getResponseText() throws EWSHttpException { * @throws EWSHttpException the EWS http exception */ private void throwIfRequestIsNull() throws EWSHttpException { - if (null == httpPost) { + if (null == request) { throw new EWSHttpException("Connection not established"); } } @@ -343,7 +361,7 @@ public Map getRequestProperty() throws EWSHttpException { throwIfRequestIsNull(); Map map = new HashMap(); - Header[] hM = httpPost.getAllHeaders(); + Header[] hM = request.getAllHeaders(); for (Header header : hM) { map.put(header.getName(), header.getValue()); } From b8860ae9ff2c82c630e86e92c49d26f979b783ee Mon Sep 17 00:00:00 2001 From: David Connelly Date: Sun, 14 Feb 2016 19:22:06 -0800 Subject: [PATCH 2/2] Add some unit test coverage for HttpClientWebRequest. --- .../data/core/HttpClientWebRequestTest.java | 42 +++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 src/test/java/microsoft/exchange/webservices/data/core/HttpClientWebRequestTest.java diff --git a/src/test/java/microsoft/exchange/webservices/data/core/HttpClientWebRequestTest.java b/src/test/java/microsoft/exchange/webservices/data/core/HttpClientWebRequestTest.java new file mode 100644 index 000000000..443f1001f --- /dev/null +++ b/src/test/java/microsoft/exchange/webservices/data/core/HttpClientWebRequestTest.java @@ -0,0 +1,42 @@ +package microsoft.exchange.webservices.data.core; + +import microsoft.exchange.webservices.base.BaseTest; +import microsoft.exchange.webservices.data.core.request.HttpClientWebRequest; +import org.junit.Assert; +import org.junit.Test; + +import java.net.URL; + +public class HttpClientWebRequestTest extends BaseTest { + @Test + public void testGet() throws Exception { + HttpClientWebRequest request = new HttpClientWebRequest( + exchangeServiceMock.httpClient, exchangeServiceMock.httpContext); + request.setUrl(new URL("http://localhost")); + request.setRequestMethod("GET"); + request.prepareConnection(); + } + + @Test + public void testPost() throws Exception { + HttpClientWebRequest request = new HttpClientWebRequest( + exchangeServiceMock.httpClient, exchangeServiceMock.httpContext); + request.setUrl(new URL("http://localhost")); + request.setRequestMethod("POST"); + request.prepareConnection(); + } + + @Test + public void testUnsupported() throws Exception { + HttpClientWebRequest request = new HttpClientWebRequest( + exchangeServiceMock.httpClient, exchangeServiceMock.httpContext); + request.setUrl(new URL("http://localhost")); + request.setRequestMethod("PUT"); + try { + request.prepareConnection(); + Assert.fail("Should not have been able to prepare connection with unsupported method"); + } catch (IllegalStateException e) { + // Fall through... + } + } +}