From 11c8c1994f0d64ac45c8a33de8d876a74dfa48a4 Mon Sep 17 00:00:00 2001 From: Sebastian Sdorra Date: Mon, 13 Apr 2015 13:42:39 +0200 Subject: [PATCH] set content-length header on post requests in order to fix issue #701 --- .../main/java/sonia/scm/util/HttpUtil.java | 6 ++ .../java/sonia/scm/net/URLHttpClient.java | 92 ++++++++++++++----- 2 files changed, 74 insertions(+), 24 deletions(-) diff --git a/scm-core/src/main/java/sonia/scm/util/HttpUtil.java b/scm-core/src/main/java/sonia/scm/util/HttpUtil.java index abe7fdd089..4b40214051 100644 --- a/scm-core/src/main/java/sonia/scm/util/HttpUtil.java +++ b/scm-core/src/main/java/sonia/scm/util/HttpUtil.java @@ -78,6 +78,12 @@ public final class HttpUtil * @since 1.43 */ public static final String HEADER_LOCATION = "Location"; + + /** + * content-length header + * @since 1.46 + */ + public static final String HEADER_CONTENT_LENGTH = "Content-Length"; /** * header for identifying the scm-manager client diff --git a/scm-webapp/src/main/java/sonia/scm/net/URLHttpClient.java b/scm-webapp/src/main/java/sonia/scm/net/URLHttpClient.java index 66c1fb9914..b4e5666952 100644 --- a/scm-webapp/src/main/java/sonia/scm/net/URLHttpClient.java +++ b/scm-webapp/src/main/java/sonia/scm/net/URLHttpClient.java @@ -48,8 +48,10 @@ import sonia.scm.util.Util; //~--- JDK imports ------------------------------------------------------------ import com.sun.jersey.core.util.Base64; +import java.io.ByteArrayOutputStream; import java.io.IOException; +import java.io.OutputStream; import java.io.OutputStreamWriter; import java.net.HttpURLConnection; @@ -67,6 +69,7 @@ import java.util.Map; import javax.net.ssl.HttpsURLConnection; import javax.net.ssl.SSLContext; import javax.net.ssl.TrustManager; +import sonia.scm.util.HttpUtil; /** * @@ -152,6 +155,9 @@ public class URLHttpClient implements HttpClient url); connection.setRequestMethod(METHOD_POST); + // send empty content-length + // see issue #701 http://goo.gl/oyTdrA + setContentLength(connection, 0); return new URLHttpResponse(connection); } @@ -347,41 +353,79 @@ public class URLHttpClient implements HttpClient { if (Util.isNotEmpty(parameters)) { + // use a ByteArrayOutputStream in order to get the final content-length + // see issue #701 http://goo.gl/oyTdrA connection.setDoOutput(true); OutputStreamWriter writer = null; + ByteArrayOutputStream baos = null; try { - writer = new OutputStreamWriter(connection.getOutputStream()); + baos = new ByteArrayOutputStream(); + writer = new OutputStreamWriter(baos); - Iterator>> it = - parameters.entrySet().iterator(); - - while (it.hasNext()) - { - Map.Entry> p = it.next(); - List values = p.getValue(); - - if (Util.isNotEmpty(values)) - { - String key = encode(p.getKey()); - - for (String value : values) - { - writer.append(key).append("=").append(encode(value)); - } - - if (it.hasNext()) - { - writer.write("&"); - } - } - } + appendPostParameters(writer, parameters); } finally { IOUtil.close(writer); + IOUtil.close(baos); + } + + if ( baos != null ){ + byte[] data = baos.toByteArray(); + appendBody(connection, data); + } + } + else + { + setContentLength(connection, 0); + } + } + + private void appendBody(HttpURLConnection connection, byte[] body) throws IOException + { + int length = body.length; + logger.trace("write {} bytes to output", length); + setContentLength(connection, length); + connection.setFixedLengthStreamingMode(length); + OutputStream os = null; + try { + os = connection.getOutputStream(); + os.write(body); + } finally { + IOUtil.close(os); + } + } + + private void setContentLength(HttpURLConnection connection, int length) + { + connection.setRequestProperty(HttpUtil.HEADER_CONTENT_LENGTH, String.valueOf(length)); + } + + private void appendPostParameters(OutputStreamWriter writer, Map> parameters) throws IOException + { + Iterator>> it = parameters.entrySet().iterator(); + + while (it.hasNext()) + { + Map.Entry> p = it.next(); + List values = p.getValue(); + + if (Util.isNotEmpty(values)) + { + String key = encode(p.getKey()); + + for (String value : values) + { + writer.append(key).append("=").append(encode(value)); + } + + if (it.hasNext()) + { + writer.write("&"); + } } } }