I use HttpURLConnection to do HTTP POST but I dont always get back the full response. I wanted to debug the problem, but when I step through each line it worked. I thought it must be a timing issue so I added Thread.sleep and it really made my code work, but this is only a temporary workaround. I wonder why is this happening and how to solve. Here is my code:
public static InputStream doPOST(String input, String inputMimeType, String url, Map<String, String> httpHeaders, String expectedMimeType) throws MalformedURLException, IOException {
URL u = new URL(url);
URLConnection c = u.openConnection();
InputStream in = null;
String mediaType = null;
if (c instanceof HttpURLConnection) {
//c.setConnectTimeout(1000000);
//c.setReadTimeout(1000000);
HttpURLConnection h = (HttpURLConnection)c;
h.setRequestMethod("POST");
//h.setChunkedStreamingMode(-1);
setAccept(h, expectedMimeType);
h.setRequestProperty("Content-Type", inputMimeType);
for(String key: httpHeaders.keySet()) {
h.setRequestProperty(key, httpHeaders.get(key));
if (logger.isDebugEnabled()) {
logger.debug("Request property key : " + key + " / value : " + httpHeaders.get(key));
}
}
h.setDoOutput(true);
h.connect();
OutputStream out = h.getOutputStream();
out.write(input.getBytes());
out.close();
mediaType = h.getContentType();
logger.debug(" ------------------ sleep ------------------ START");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
logger.debug(" ------------------ sleep ------------------ END");
if (h.getResponseCode() < 400) {
in = h.getInputStream();
} else {
in = h.getErrorStream();
}
}
return in;
}
later I do the following to read the input stream
ByteArrayOutputStream bos = new ByteArrayOutputStream();
while (is.available() > 0) {
bos.write(is.read());
}
is.close();
//is.read(bytes);
if (logger.isDebugEnabled()) {
logger.debug(" Response lenght is : " + is.available());
//logger.debug("RAW response is " + new String(bytes));
logger.debug("RAW response is " + new String(bos.toByteArray()));
}
It genearates the following HTTP headers
POST /emailauthentication/ HTTP/1.1
Accept: application/xml
Content-Type: application/xml
Authorization: OAuth oauth_consumer_key="b465472b-d872-42b9-030e-4e74b9b60e39",oauth_nonce="YnDb5eepuLm%2Fbs",oauth_signature="dbN%2FWeWs2G00mk%2BX6uIi3thJxlM%3D", oauth_signature_method="HMAC-SHA1", oauth_timestamp="1276524919", oauth_token="", oauth_version="1.0"
User-Agent: Java/1.6.0_20
Host: test:6580
Connection: keep-alive
Content-Length: 1107
In other posts it was suggested to turn off keep-alive by using the
http.keepAlive=false
system property, I tried that and the headers changed to
POST /emailauthentication/ HTTP/1.1
Accept: application/xml
Content-Type: application/xml
Authorization: OAuth oauth_consumer_key="b465472b-d872-42b9-030e-4e74b9b60e39", oauth_nonce="Eaiezrj6X4Ttt0", oauth_signature="ND9fAdZMqbYPR2j%2FXUCZmI90rSI%3D", oauth_signature_method="HMAC-SHA1", oauth_timestamp="1276526608", oauth_token="", oauth_version="1.0"
User-Agent: Java/1.6.0_20
Host: test:6580
Connection: close
Content-Length: 1107
the Connection header is "close" but I still cannot read the whole response. Any idea what do I do wrong?
I think your problem is in this line:
while (is.available() > 0) {
According to the javadoc, available does not block and wait until all data is available, so you might get the first packet and then it will return false. The proper way to read from an InputStream is like this:
int len;
byte[] buffer = new byte[4096];
while (-1 != (len = in.read(buffer))) {
bos.write(buffer, 0, len);
}
Read will return -1 when there nothing left in the inputstream or the connection is closed, and it will block and wait for the network while doing so. Reading arrays is also much more performant than using single bytes.
Maybe I missed it, but what's the datatype of "input" in your code? Something that's strange about InputStreams in general is that the read( ... ) methods tend to block until data is available, then return only that data. You'll actually need to keep reading from your InputStream and appending to a ByteArrayInputStream or some other structure until you explicitly force a EOFException.
If you are reading the whole Message at once you can compare the isr.available() to the expected content lenght. This is how I did it:
public byte[] readData(HttpURLConnection conn)
throws IOException, InterruptedException {
String _connlen = conn.getHeaderField("Content-Length");
int connlen = Integer.parseInt(_connlen);
InputStream isr = null;
byte[] bytes = new byte[connlen];
try {
isr = conn.getInputStream();
//security count that it doesn't begin to hang
int maxcounter = 0;
//wait till all data is avalibal, max 5sec
while((isr.available() != connlen) && (maxcounter < 5000)){
Thread.sleep(1);
maxcounter++;
}
//Throw if not all data could be read
if(maxcounter >= 5000)
throw new IllegalAccessError();
//read the data
if(isr.read(bytes, 0, connlen) < 0)
throw new IllegalAccessError();
} finally {
if (isr != null)
isr.close();
}
return bytes;
}
Related
I'm messing around with HTTP and sockets in Java and was hoping you could shed some light on this:
When my HTTP server written in Java SE 11 does not read the entire request and then responds, the client does not get it or gets an error. Why is that? Is the client unable to read the response before the server has read the entire request? If the call to readBody is executed in the snippet below, this works fine. It also works fine if the response has the Content-Length header and a text body. That is actually more puzzling to me.
My example request is a POST with the data fds. Postman says "Could not get any request" and curl says "curl: (56) Recv failure: Connection reset by peer".
import java.io.*;
import java.net.Socket;
import java.util.*;
class Handler {
public synchronized void read(Socket incoming) {
try (incoming;
OutputStream outputStream = incoming.getOutputStream();
InputStream inputStream = incoming.getInputStream();
PrintWriter pw = new PrintWriter(outputStream)) {
writeRequest(inputStream);
pw.print("HTTP/1.1 200 OK\r\n");
pw.print("\r\n");
pw.flush();
} catch (IOException e) {
System.out.println("ERROR: " + e.getMessage());
e.printStackTrace();
}
}
private void writeRequest(InputStream inputStream) throws IOException {
String verbLine = readLine(inputStream);
Map<String, String> headers = readHeaders(inputStream);
//readBody(inputStream, headers);
}
private void readBody(InputStream inputStream, Map<String, String> headers) throws IOException {
Optional<String> optKey = headers.keySet().stream()
.filter(k -> k.equalsIgnoreCase("Content-Length"))
.findFirst();
if (optKey.isPresent()) {
int contentLength = Integer.parseInt(headers.get(optKey.get()));
byte[] bytes = inputStream.readNBytes(contentLength);
}
}
private Map<String, String> readHeaders(InputStream inputStream) throws IOException {
Map<String, String> headers = new HashMap<>();
while (true) {
String line = readLine(inputStream);
if (line == null || line.isEmpty()) {
return headers;
}
String key = line.split(":")[0].trim();
String value = line.split(":")[1].trim();
headers.put(key, value);
}
}
private String readLine(InputStream inputStream) throws IOException {
byte[] buf = new byte[200];
int offset = 0;
while (true) {
int read = inputStream.read();
if (read == -1) {
return null;
}
buf[offset] = (byte) read;
if (buf[0] == '\n' || (buf[0] == '\r' && buf[1] == '\n')) {
return "";
}
if (buf[offset] == 0x0A) {
int endOfLine = buf[offset - 1] == 0x0D ? offset - 1 : offset;
return new String(buf, 0, endOfLine);
} else {
offset++;
}
}
}
}
If you close a socket at the server while there are still unread data it will result in a connection reset error at the client. This happens here since you don't read the full request. This error will be exposed to the user if the full response from the server was not read yet.
If you send the response with a content-length and then the full body then the client will have read the full response and thus the error will be ignored. If instead you send neither content-length nor use chunked encoding the client will expect the response to end with a proper close of the TCP connection. In this case the connection reset will be propagated to the user since the full response from the server was not (properly) read yet.
Your response needs to have either a Content-Length header or a Transfer-Encoding header - which tells the client how the response will be transmitted and allows it to figure out when all the bytes have been received. Without that it will need to wait for EOF and assume that the response body is terminated by EOF (this for compatibility with HTTP/1.0). It is possible that your client doesn't support that.
It might help to know which client you are using.
In the following code, EntityUtils.toString is going into IOException. When I paste 'EntityUtils.toString(entity)' on eclipse watch window, it showing me the value which is DISABLED
private String triggerRestApiCalls(String url){
HttpClient httpClient = new DefaultHttpClient();
HttpGet getRequest = new HttpGet(url);
getRequest.setHeader(
new BasicHeader("Accept", "application/json"));
try {
HttpResponse response = httpClient.execute(getRequest);
HttpEntity entity = response.getEntity();
String value = EntityUtils.toString(entity);
return value;
} catch (ClientProtocolException e) {
log.debug(e.getCause());
} catch (IOException e) {
log.debug(e.getCause());
}
log.debug("Status Unknown");
return "UNKNOWN";
}
The content value lenght is 8. The string expected is DISABLED, which is exactly of the length. The HTTP status is 200 (OK).
I used curl with same URL.
curl -i -H {Accept: application/json} http://127.0.0.1:9031/test/test.html?someDetails
HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
Set-Cookie: JSESSIONID=D35C61744F4FB3A47B624FF3D0BEB026; Path=/mics/; Secure; HttpOnly
Content-Type: text/plain;charset=ISO-8859-1
Content-Length: 8
Date: Wed, 26 Nov 2014 13:23:30 GMT
DISABLED.
Any help is appreciated ! Is there any angle to encoding ?
FIRST EDIT
The Stack Trace mentions this.
java.io.IOException: Attempted read from closed stream.
The code that is executed by EntityUtils.toString()
public static String toString(
final HttpEntity entity, final Charset defaultCharset) throws IOException, ParseException {
if (entity == null) {
throw new IllegalArgumentException("HTTP entity may not be null");
}
InputStream instream = entity.getContent();
if (instream == null) {
return null;
}
try {
if (entity.getContentLength() > Integer.MAX_VALUE) {
throw new IllegalArgumentException("HTTP entity too large to be buffered in memory");
}
int i = (int)entity.getContentLength();
if (i < 0) {
i = 4096;
}
ContentType contentType = ContentType.getOrDefault(entity);
Charset charset = contentType.getCharset();
if (charset == null) {
charset = defaultCharset;
}
if (charset == null) {
charset = HTTP.DEF_CONTENT_CHARSET;
}
Reader reader = new InputStreamReader(instream, charset);
CharArrayBuffer buffer = new CharArrayBuffer(i);
char[] tmp = new char[1024];
int l;
while((l = reader.read(tmp)) != -1) {
buffer.append(tmp, 0, l);
}
return buffer.toString();
} finally {
instream.close();
}
}
I have stepped through this and there are not errors However, it closes the stream before it returns.
But the actual value that is returned is CharArrayBuffer which is not linked to the stream. The same code works in some other java file. Strange !! I am using spring.. is there a spring angle to this ?
The HttpEntity can only be read once and it seems something else is intercepting and reading the response so that when you attempt to apply EntityUtils.toString() you get this exception. I can't see why this would be happening, though you did mention there could be a Spring angle so there could be a Spring interceptor applied here.
You could try
String value = httpClient.execute(getRequest, new BasicResponseHandler());
Although from what I can see this should be fairly equivalent to the above code.
I'm trying to parse an HTTP request using the apache httpcore components and want to grab the body of the request. It looks like the default DefaultHttpRequestParser doesn't parse the body/entity from its input stream. Is there a class that will do this?
Unfortunately I can't use the entire stack and need to pull the request straight from this input stream.
My parsing code is below. Looking at some of the other answers it appears that the body of the request should be available as an entity. However, every time I try to get at the entity it is null.
Debugging I see that the buffer has read but not used the body and that DefaultHttpRequestParser seems to just read the header. Is there a parse I should be using to parse the entire input?
InputStream is = socket.getInputStream();
HttpTransportMetricsImpl metrics = new HttpTransportMetricsImpl();
SessionInputBufferImpl buf = new SessionInputBufferImpl(metrics, 2048);
buf.bind(is);
DefaultHttpRequestParser reqParser = new DefaultHttpRequestParser(buf);
HttpRequest req = reqParser.parse();
if (req instanceof HttpEntityEnclosingRequest) {
entity = ((HttpEntityEnclosingRequest)query).getEntity();
//... entity is always null
If I read the input stream I end up with:
POST / HTTP/1.1
User-Agent: curl/Q.XX.0 (linux-gnu) libcurl/Q.XX.0 OpenSSL/X.Y.Z zlib/A.B.C.D libidn/E.FF librtmp/G.H
Host: localhost:8088
Accept: */*
Content-Length: 333
Content-Type: multipart/form-data; boundary=----------------------------39203c7982df
------------------------------39203c7982df
Content-Disposition: form-data; name="fileupload"; filename="grun.sh"
Content-Type: application/octet-stream
#!/bin/bash -x
java -classpath lib/antlr-4.4-complete.jar:build/classes org.antlr.v4.runtime.misc.TestRig Typegroup "AHI" -tree
------------------------------39203c7982df--
[Update] Oleg has a good answer, but can I associate the body with the request or do
I now need to pass two things around, the body and the stream? I'll be looking into
I got the following to work, but it's deprecated in the latest release.
...
HttpEntityEnclosingRequest ereq = (HttpEntityEnclosingRequest) req;
#SuppressWarnings("deprecation")
EntityDeserializer ed =
new EntityDeserializer(new LaxContentLengthStrategy());
#SuppressWarnings("deprecation")//ack!
HttpEntity ent = ed.deserialize(buf, req);
ereq.setEntity(ent);
return ereq;
Combining Oleg's solution with the above I ended up with:
HttpEntityEnclosingRequest ereq = (HttpEntityEnclosingRequest) req;
ContentLengthStrategy contentLengthStrategy =
StrictContentLengthStrategy.INSTANCE;
long len = contentLengthStrategy.determineLength(req);
InputStream contentStream = null;
if (len == ContentLengthStrategy.CHUNKED) {
contentStream = new ChunkedInputStream(buf);
} else if (len == ContentLengthStrategy.IDENTITY) {
contentStream = new IdentityInputStream(buf);
} else {
contentStream = new ContentLengthInputStream(buf, len);
}
BasicHttpEntity ent = new BasicHttpEntity();
ent.setContent(contentStream);
ereq.setEntity(ent);
return ereq;
InputStream is = socket.getInputStream();
HttpTransportMetricsImpl metrics = new HttpTransportMetricsImpl();
SessionInputBufferImpl buf = new SessionInputBufferImpl(metrics, 2048);
buf.bind(is);
DefaultHttpRequestParser reqParser = new DefaultHttpRequestParser(buf);
HttpRequest req = reqParser.parse();
InputStream contentStream = null;
if (req instanceof HttpEntityEnclosingRequest) {
ContentLengthStrategy contentLengthStrategy = StrictContentLengthStrategy.INSTANCE;
long len = contentLengthStrategy.determineLength(req);
if (len == ContentLengthStrategy.CHUNKED) {
contentStream = new ChunkedInputStream(buf);
} else if (len == ContentLengthStrategy.IDENTITY) {
contentStream = new IdentityInputStream(buf);
} else {
contentStream = new ContentLengthInputStream(buf, len);
}
}
// Do something useful with the content stream (if non null)
Message parsers in HttpCore parse message heads only. However, one can proceed reading from the session input buffer and read message body content until the end of message (depending on the delineator used)
As an assignment, I am allowed to use ServerSocket and Socket class only. Also it should be single-threaded as well.
I'm implementing a HTTP proxy server in Java, first it fetches request from client and then pushes to server, and then pushes the response back to the client.
The problem
The problem is, I have successfully get the request, send it to the end-server and get the proper HTTP response. I also can do print out the response in console. But it got stuck when I send the response to clientServer.outputstream. Firefox (requested to use, HTTP 1.0, no keep-alive requested) seems to load forever and nothing shows, and no response Firefox received from my program as well.
What I inspect when debug
Everytime a page start to load (FF request), there are always 2 client sockets. First socket contains null request, and second socket contains proper request. What I expect was that only one proper HTTP request from Firefox. Is that a weird behavior?
example:
/0:0:0:0:0:0:0:1:65194
[null request]
/0:0:0:0:0:0:0:1:65195
GET http://www.microsoft.com/ HTTP/1.0
Host: www.microsoft.com
User-Agent: Mozilla/5.0 (Windows NT 6.2; WOW64; rv:15.0) Gecko/20100101 Firefox/15.0.1
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip, deflate
Connection: close
Proxy-Connection: close
Cookie: viewkey=lightweight; WT_FPC=id=269eb0e7618962f93a81347585923074:lv=1349229942007:ss=1349229580158; WT_NVR_RU=0=technet|msdn:1=:2=; omniID=c736269c_f430_4e9b_a42a_23a0c965c60a; MUID=212A1766CFE761423CD014BDCBE76158&TUID=1; MC1=GUID=08600fba7f5c5f409e67980d8a027593&HASH=ba0f&LV=20129&V=4&LU=1347643534618; A=I&I=AxUFAAAAAADGBwAA8ezRtqBBHjk3++mP1Bwj9w!!&V=4&CS=119EQ5002j10100; msdn=L=en-US
Code
ServerSocket serverSocket;
try {
serverSocket = new ServerSocket(60000);
while (true) {
clientSocket = serverSocket.accept();
[...]
// Extract request, and push to end-server
// Fetch response from end-server to client, using flush() already
// Close all input, output
// Close all sockets
} catch {[...]}
Any help is welcomed, thank you!
Full code as requested, I use PrintWriter, but before that using Byte makes no difference (not care efficiency)
import java.io.*;
import java.net.*;
import java.util.*;
public class Proxy {
static String separator = System.getProperty("line.separator");
public static void main(String args[]) {
//int port = Integer.parseInt(args[0]);
start(60000);
}
public static void start(int port) {
ServerSocket serverSocket;
try {
serverSocket = new ServerSocket(port);
Socket clientSocket = null;
while (true) {
clientSocket = serverSocket.accept();
System.out.println(clientSocket.getRemoteSocketAddress() + "\n" + clientSocket.getLocalSocketAddress() + "\n" + clientSocket.getInetAddress());
BufferedReader inStreamFromClient = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
String inLine;
Vector<String> clientRequestHeader = new Vector<String>();
String rawRequest = "";
while ((inLine = inStreamFromClient.readLine()) != null) {
if (!inLine.isEmpty()) {
clientRequestHeader.add(inLine);
rawRequest = rawRequest.concat(inLine + separator);
} else break;
}
while ((inLine = inStreamFromClient.readLine()) != null)
rawRequest = rawRequest.concat(inLine + separator);
System.out.println(rawRequest);
if (!rawRequest.isEmpty()) {
handleRequest(clientSocket, clientRequestHeader, rawRequest);
} else {
//clientSocket.close();
// Not sure how to handle null request
}
}
} catch (Exception e) {e.printStackTrace();}
}
public static void handleRequest(Socket clientSocket, Vector<String> clientRequestHeader, String rawRequest) {
HTTPRequest request = new HTTPRequest(clientRequestHeader, rawRequest);
try {
//System.out.println(rawRequest);
// Send request to end-server
Socket endServerSocket = new Socket(request.getHost(), 80);
PrintWriter outStreamToEndServer = new PrintWriter(new BufferedWriter(new OutputStreamWriter(endServerSocket.getOutputStream())));
BufferedReader stringReader = new BufferedReader(new StringReader(rawRequest));
String inLine;
while ((inLine = stringReader.readLine())!= null) {
outStreamToEndServer.println(inLine);
}
outStreamToEndServer.println();
outStreamToEndServer.flush();
// Read response header from end-server
String responseHeader = "";
BufferedReader inStreamFromEndServer = new BufferedReader(new InputStreamReader(endServerSocket.getInputStream()));
while (!(inLine = inStreamFromEndServer.readLine()).isEmpty()) {
responseHeader = responseHeader.concat(inLine + separator);
}
// Send response header to client
PrintWriter outStreamToClient = new PrintWriter(new BufferedWriter(new OutputStreamWriter(clientSocket.getOutputStream())));
outStreamToClient.println(responseHeader);
outStreamToClient.flush();
// Send response body to client
String responseBody = "";
while ((inLine = inStreamFromEndServer.readLine()) != null) {
responseBody = responseBody.concat(inLine + separator);
}
outStreamToClient.println(responseBody);
outStreamToClient.flush();
endServerSocket.shutdownInput();
clientSocket.shutdownOutput();
clientSocket.close();
endServerSocket.close();
//endServerSocket = null;
} catch (Exception e) {
e.printStackTrace();
}
}
}
first you should not use PrintWriter to transfer the Data, because the HTTP protocol isn't a pure text protocol the body can contain some raw data like images.
Replace your response transfer code with the code below.
InputStream in = endServerSocket.getInputStream();
OutputStream out = clientSocket.getOutputStream();
byte[] buffer = new byte[1024];
int bytesRead;
while ((bytesRead = in.read(buffer)) != -1)
{
out.write(buffer, 0, bytesRead);
}
in.close();
out.close();
Second point, you add always as line break the
static String separator = System.getProperty("line.separator");
This is the System specific line seperator. HTTP defines for the HTTP header and for the http header and body separation the ctrl line break charaters, so change this.
static String separator = "\r\n";
With this changes you will get your response to your browser.
Last Point you should change your client request read code also, because it will not always work if you want POST some data. Sometimes this data will transfered as raw data, by example file uploads.
Good Luck
I seem to be running into a peculiar problem on Android 1.5 when a library I'm using (signpost 1.1-SNAPSHOT), makes two consecutive connections to a remote server. The second connection always fails with a HttpURLConnection.getResponseCode() of -1
Here's a testcase that exposes the problem:
// BROKEN
public void testDefaultOAuthConsumerAndroidBug() throws Exception {
for (int i = 0; i < 2; ++i) {
final HttpURLConnection c = (HttpURLConnection) new URL("https://api.tripit.com/oauth/request_token").openConnection();
final DefaultOAuthConsumer consumer = new DefaultOAuthConsumer(api_key, api_secret, SignatureMethod.HMAC_SHA1);
consumer.sign(c); // This line...
final InputStream is = c.getInputStream();
while( is.read() >= 0 ) ; // ... in combination with this line causes responseCode -1 for i==1 when using api.tripit.com but not mail.google.com
assertTrue(c.getResponseCode() > 0);
}
}
Basically, if I sign the request and then consume the entire input stream, the next request will fail with a resultcode of -1. The failure doesn't seem to happen if I just read one character from the input stream.
Note that this doesn't happen for any url -- just specific urls such as the one above.
Also, if I switch to using HttpClient instead of HttpURLConnection, everything works fine:
// WORKS
public void testCommonsHttpOAuthConsumerAndroidBug() throws Exception {
for (int i = 0; i < 2; ++i) {
final HttpGet c = new HttpGet("https://api.tripit.com/oauth/request_token");
final CommonsHttpOAuthConsumer consumer = new CommonsHttpOAuthConsumer(api_key, api_secret, SignatureMethod.HMAC_SHA1);
consumer.sign(c);
final HttpResponse response = new DefaultHttpClient().execute(c);
final InputStream is = response.getEntity().getContent();
while( is.read() >= 0 ) ;
assertTrue( response.getStatusLine().getStatusCode() == 200);
}
}
I've found references to what seems to be a similar problem elsewhere, but so far no solutions. If they're truly the same problem, then the problem probably isn't with signpost since the other references make no reference to it.
Any ideas?
Try set this property to see if it helps,
http.keepAlive=false
I saw similar problems when server response is not understood by UrlConnection and client/server gets out of sync.
If this solves your problem, you have to get a HTTP trace to see exactly what's special about the response.
EDIT: This change just confirms my suspicion. It doesn't solve your problem. It just hides the symptom.
If the response from first request is 200, we need a trace. I normally use Ethereal/Wireshark to get the TCP trace.
If your first response is not 200, I do see a problem in your code. With OAuth, the error response (401) actually returns data, which includes ProblemAdvice, Signature Base String etc to help you debug. You need to read everything from error stream. Otherwise, it's going to confuse next connection and that's the cause of -1. Following example shows you how to handle errors correctly,
public static String get(String url) throws IOException {
ByteArrayOutputStream os = new ByteArrayOutputStream();
URLConnection conn=null;
byte[] buf = new byte[4096];
try {
URL a = new URL(url);
conn = a.openConnection();
InputStream is = conn.getInputStream();
int ret = 0;
while ((ret = is.read(buf)) > 0) {
os.write(buf, 0, ret);
}
// close the inputstream
is.close();
return new String(os.toByteArray());
} catch (IOException e) {
try {
int respCode = ((HttpURLConnection)conn).getResponseCode();
InputStream es = ((HttpURLConnection)conn).getErrorStream();
int ret = 0;
// read the response body
while ((ret = es.read(buf)) > 0) {
os.write(buf, 0, ret);
}
// close the errorstream
es.close();
return "Error response " + respCode + ": " +
new String(os.toByteArray());
} catch(IOException ex) {
throw ex;
}
}
}
I've encountered the same problem when I did not read in all the data from the InputStream before closing it and opening a second connection. It was also fixed either with System.setProperty("http.keepAlive", "false"); or simply just looping until I've read the rest of the InputStream.
Not completely related to your issue, but hope this helps anyone else with a similar problem.
Google provided an elegant workaround since it's only happening prior to Froyo:
private void disableConnectionReuseIfNecessary() {
// HTTP connection reuse which was buggy pre-froyo
if (Integer.parseInt(Build.VERSION.SDK) < Build.VERSION_CODES.FROYO) {
System.setProperty("http.keepAlive", "false");
}
}
Cf. http://android-developers.blogspot.ca/2011/09/androids-http-clients.html
Or, you can set HTTP header in the connection (HttpUrlConnection):
conn.setRequestProperty("Connection", "close");
Can you verify that the connection is not getting closed before you finish reading the response? Maybe HttpClient parses the response code right away, and saves it for future queries, however HttpURLConnection could be returning -1 once the connection is closed?