set content-length header on post requests in order to fix issue #701

This commit is contained in:
Sebastian Sdorra
2015-04-13 13:42:39 +02:00
parent 451490e95a
commit 11c8c1994f
2 changed files with 74 additions and 24 deletions

View File

@@ -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

View File

@@ -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<Map.Entry<String, List<String>>> it =
parameters.entrySet().iterator();
while (it.hasNext())
{
Map.Entry<String, List<String>> p = it.next();
List<String> 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<String, List<String>> parameters) throws IOException
{
Iterator<Map.Entry<String, List<String>>> it = parameters.entrySet().iterator();
while (it.hasNext())
{
Map.Entry<String, List<String>> p = it.next();
List<String> 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("&");
}
}
}
}