diff --git a/pom.xml b/pom.xml index 764152684..0afb83db0 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.mashape.unirest unirest-java jar - 1.4.10-SNAPSHOT + 1.4.10-CE-0.3 unirest-java Simplified, lightweight HTTP client library http://unirest.io/ @@ -24,9 +24,9 @@ - https://github.com/Mashape/unirest-java - scm:git:git@github.com:Mashape/unirest-java.git - scm:git:git@github.com:Mashape/unirest-java.git + https://github.com/cloud-elements/unirest-java + scm:git:git@github.com:cloud-elements/unirest-java.git + scm:git:git@github.com:cloud-elements/unirest-java.git @@ -46,6 +46,14 @@ 2.6.0 + + + unirest-java-cloud-elements-github + unirest-java Github package repository + https://maven.pkg.github.com/cloud-elements/unirest-java + + + @@ -88,6 +96,11 @@ org.apache.maven.plugins maven-javadoc-plugin 2.9.1 + + -Xdoclint:none + -Xdoclint:none + -Xdoclint:none + attach-javadocs @@ -98,6 +111,14 @@ + + + + org.apache.maven.wagon + wagon-ssh + 3.0.0 + + diff --git a/src/main/java/com/mashape/unirest/http/HttpClientHelper.java b/src/main/java/com/mashape/unirest/http/HttpClientHelper.java index bc84b9ab7..ecc277ba4 100644 --- a/src/main/java/com/mashape/unirest/http/HttpClientHelper.java +++ b/src/main/java/com/mashape/unirest/http/HttpClientHelper.java @@ -169,8 +169,8 @@ private static HttpRequestBase prepareRequest(HttpRequest request, boolean async String urlToRequest = null; try { URL url = new URL(request.getUrl()); - URI uri = new URI(url.getProtocol(), url.getUserInfo(), url.getHost(), url.getPort(), URLDecoder.decode(url.getPath(), "UTF-8"), "", url.getRef()); - urlToRequest = uri.toURL().toString(); + URI uri = new URI(url.getProtocol(), url.getUserInfo(), url.getHost(), url.getPort(), url.getPath(), "", url.getRef()); + urlToRequest = uri.toASCIIString(); if (url.getQuery() != null && !url.getQuery().trim().equals("")) { if (!urlToRequest.substring(urlToRequest.length() - 1).equals("?")) { urlToRequest += "?"; diff --git a/src/main/java/com/mashape/unirest/http/HttpResponse.java b/src/main/java/com/mashape/unirest/http/HttpResponse.java index e0800d227..d261573a5 100644 --- a/src/main/java/com/mashape/unirest/http/HttpResponse.java +++ b/src/main/java/com/mashape/unirest/http/HttpResponse.java @@ -25,6 +25,7 @@ a copy of this software and associated documentation files (the package com.mashape.unirest.http; +import com.mashape.unirest.http.exceptions.UnirestException; import com.mashape.unirest.http.options.Option; import com.mashape.unirest.http.options.Options; import com.mashape.unirest.http.utils.ResponseUtils; @@ -79,12 +80,18 @@ public HttpResponse(org.apache.http.HttpResponse response, Class responseClas try { byte[] rawBody; + Long contentLength = responseEntity.getContentLength(); + + if (!ResponseUtils.isMultipartContentType(contentType)) { + ResponseUtils.checkResponseSize(contentLength); + } + try { InputStream responseInputStream = responseEntity.getContent(); - if (ResponseUtils.isGzipped(responseEntity.getContentEncoding())) { + if (ResponseUtils.isGzipped(responseEntity.getContentEncoding()) && contentLength > 0) { responseInputStream = new GZIPInputStream(responseEntity.getContent()); } - rawBody = ResponseUtils.getBytes(responseInputStream); + rawBody = ResponseUtils.getBytes(responseInputStream, !ResponseUtils.isMultipartContentType(contentType)); } catch (IOException e2) { throw new RuntimeException(e2); } diff --git a/src/main/java/com/mashape/unirest/http/Unirest.java b/src/main/java/com/mashape/unirest/http/Unirest.java index 6aba57782..1f5cd8e17 100644 --- a/src/main/java/com/mashape/unirest/http/Unirest.java +++ b/src/main/java/com/mashape/unirest/http/Unirest.java @@ -108,6 +108,19 @@ public static void setConcurrency(int maxTotal, int maxPerRoute) { Options.refresh(); } + /** + * Set the max response size. + * + * @param maxResponseSize Defines the maximum response size for non-multipart responses. (Multipart responses, which + * include file downloads, will have no size limit). + */ + public static void setMaxResponseSize(long maxResponseSize) { + Options.setOption(Option.MAX_RESPONSE_SIZE, maxResponseSize); + + // Reload the client implementations + Options.refresh(); + } + /** * Clear default headers */ diff --git a/src/main/java/com/mashape/unirest/http/options/Option.java b/src/main/java/com/mashape/unirest/http/options/Option.java index a146ce2b1..8ccf4a985 100644 --- a/src/main/java/com/mashape/unirest/http/options/Option.java +++ b/src/main/java/com/mashape/unirest/http/options/Option.java @@ -1,5 +1,6 @@ package com.mashape.unirest.http.options; public enum Option { - HTTPCLIENT, ASYNCHTTPCLIENT, CONNECTION_TIMEOUT, SOCKET_TIMEOUT, DEFAULT_HEADERS, SYNC_MONITOR, ASYNC_MONITOR, MAX_TOTAL, MAX_PER_ROUTE, PROXY, OBJECT_MAPPER + HTTPCLIENT, ASYNCHTTPCLIENT, CONNECTION_TIMEOUT, SOCKET_TIMEOUT, DEFAULT_HEADERS, SYNC_MONITOR, ASYNC_MONITOR, + MAX_TOTAL, MAX_PER_ROUTE, PROXY, OBJECT_MAPPER, MAX_RESPONSE_SIZE } diff --git a/src/main/java/com/mashape/unirest/http/utils/ResponseUtils.java b/src/main/java/com/mashape/unirest/http/utils/ResponseUtils.java index 7fb7d0891..a8679e291 100644 --- a/src/main/java/com/mashape/unirest/http/utils/ResponseUtils.java +++ b/src/main/java/com/mashape/unirest/http/utils/ResponseUtils.java @@ -7,7 +7,11 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; +import com.mashape.unirest.http.exceptions.UnirestException; +import com.mashape.unirest.http.options.Option; +import com.mashape.unirest.http.options.Options; import org.apache.http.Header; +import org.apache.http.HeaderElement; public class ResponseUtils { @@ -30,20 +34,74 @@ public static String getCharsetFromContentType(String contentType) { return null; } - public static byte[] getBytes(InputStream is) throws IOException { + public static boolean isMultipartContentType(Header contentType) { + if (contentType == null) + return false; + + if (contentType.getValue().toLowerCase().contains("multipart")) { + return true; + } + + HeaderElement[] elements = contentType.getElements(); + if (elements == null) { + return false; + } + for (HeaderElement element : elements) { + if (element == null || element.getValue() == null) { continue; } + if (element.getValue().toLowerCase().contains("multipart")) { + return true; + } + } + + return false; + } + + public static void checkResponseSize(Long contentLength) throws IOException { + checkMaxResponseSize(contentLength, getMaxResponseAsLong()); + } + + public static void checkMaxResponseSize(Long contentLength, long maxResponse) throws IOException { + if (contentLength == null) { + return; + } + if (maxResponse > -1 && maxResponse < contentLength) { + throw new IOException("Response content too large: " + maxResponse + " < " + contentLength); + } + } + + public static long getMaxResponseAsLong() { + Number maxResponse = (Number) Options.getOption(Option.MAX_RESPONSE_SIZE); + if (maxResponse == null) return -1; + return maxResponse.longValue(); + } + + public static byte[] getBytes(InputStream is, boolean checkSize) throws IOException { int len; int size = 1024; byte[] buf; + checkSize = checkSize && Options.getOption(Option.MAX_RESPONSE_SIZE) != null; if (is instanceof ByteArrayInputStream) { size = is.available(); + if (checkSize) { + ResponseUtils.checkResponseSize((long) size); + } buf = new byte[size]; len = is.read(buf, 0, size); } else { + long maxResponse = getMaxResponseAsLong(); + long total = 0; ByteArrayOutputStream bos = new ByteArrayOutputStream(); buf = new byte[size]; - while ((len = is.read(buf, 0, size)) != -1) + // For efficiency, allow single page overflows past maxResponseSize + // (i.e., don't limit `size = maxResponse - total` or anything like that). + while ((len = is.read(buf, 0, size)) != -1) { + total += len; + if (checkSize) { + ResponseUtils.checkMaxResponseSize(total, maxResponse); + } bos.write(buf, 0, len); + } buf = bos.toByteArray(); } return buf; diff --git a/src/main/java/com/mashape/unirest/request/HttpRequest.java b/src/main/java/com/mashape/unirest/request/HttpRequest.java index e0bc52f1b..203eb4a4a 100644 --- a/src/main/java/com/mashape/unirest/request/HttpRequest.java +++ b/src/main/java/com/mashape/unirest/request/HttpRequest.java @@ -123,7 +123,9 @@ public HttpRequest queryString(Map parameters) { for (Entry param : parameters.entrySet()) { if (param.getValue() instanceof String || param.getValue() instanceof Number || param.getValue() instanceof Boolean) { queryString(param.getKey(), param.getValue()); - } else { + } else if (param.getValue() instanceof Collection) { + queryString(param.getKey(), (Collection) param.getValue()); + } else { throw new RuntimeException("Parameter \"" + param.getKey() + "\" can't be sent with a GET request because of type: " + param.getValue().getClass().getName()); } } diff --git a/src/main/java/com/mashape/unirest/request/body/MultipartBody.java b/src/main/java/com/mashape/unirest/request/body/MultipartBody.java index 4d88df1f4..8080ed2f3 100644 --- a/src/main/java/com/mashape/unirest/request/body/MultipartBody.java +++ b/src/main/java/com/mashape/unirest/request/body/MultipartBody.java @@ -150,8 +150,11 @@ public HttpEntity getEntity() { if (hasFile) { MultipartEntityBuilder builder = MultipartEntityBuilder.create(); if (mode != null) { + builder.setMode(mode); + } else { builder.setMode(HttpMultipartMode.BROWSER_COMPATIBLE); } + builder.setCharset(java.nio.charset.StandardCharsets.UTF_8); for (String key : parameters.keySet()) { List value = parameters.get(key); ContentType contentType = contentTypes.get(key); diff --git a/src/test/java/com/mashape/unirest/test/http/UnirestTest.java b/src/test/java/com/mashape/unirest/test/http/UnirestTest.java index e7145a705..ea92ae2d1 100644 --- a/src/test/java/com/mashape/unirest/test/http/UnirestTest.java +++ b/src/test/java/com/mashape/unirest/test/http/UnirestTest.java @@ -28,6 +28,7 @@ a copy of this software and associated documentation files (the import com.mashape.unirest.http.*; import com.mashape.unirest.http.async.Callback; import com.mashape.unirest.http.exceptions.UnirestException; +import com.mashape.unirest.http.options.Option; import com.mashape.unirest.http.options.Options; import com.mashape.unirest.request.GetRequest; import com.mashape.unirest.request.HttpRequest; @@ -63,6 +64,7 @@ public class UnirestTest { public void setUp() { lock = new CountDownLatch(1); status = false; + Options.setOption(Option.MAX_RESPONSE_SIZE, -1); } private String findAvailableIpAddress() throws UnknownHostException, IOException { @@ -815,4 +817,18 @@ public void testHeaderNamesCaseSensitive() { assertEquals("Only header \"Content-Type\" should exist", null, headers.getFirst("content-type")); assertEquals("Only header \"Content-Type\" should exist", "application/json", headers.getFirst("Content-Type")); } + + @Test(expected = UnirestException.class) + public void testGetLargeResponse() throws JSONException, UnirestException { + Options.setOption(Option.MAX_RESPONSE_SIZE, 3); + HttpResponse response = Unirest.get("http://httpbin.org/get?name=mark").asString(); + response.getBody(); + } + + @Test + public void testGetLargeResponseOk() throws JSONException, UnirestException { + Options.setOption(Option.MAX_RESPONSE_SIZE, 3000); + HttpResponse response = Unirest.get("http://httpbin.org/get?name=mark").asString(); + response.getBody(); + } } diff --git a/src/test/resources/image.png b/src/test/resources/image.png new file mode 100644 index 000000000..9c6817953 Binary files /dev/null and b/src/test/resources/image.png differ