Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why HttpURLConnection does not send data unless I try to receive something

I cannot comprehend why doesn't the following code does not put a packet onto wire (confirmed via wireshark). It is a fairly standard method of sending an HTTP POST request, as I believe. I don't intend to read anything just POST.

private void sendRequest() throws IOException {
    String params = "param=value";
    URL url = new URL(otherUrl.toString());
    HttpURLConnection con = (HttpURLConnection)url.openConnection();
    con.setDoOutput(true);
    con.setDoInput(true);    //setting this to `false` does not help
    con.setRequestMethod("POST");
    con.setRequestProperty("Content-Type", "text/plain");
    con.setRequestProperty("Content-Length", "" + Integer.toString(params.getBytes().length));
    con.setRequestProperty("Accept", "text/plain");
    con.setUseCaches(false);
    con.connect();
    DataOutputStream wr = new DataOutputStream(con.getOutputStream());
    wr.writeBytes(params);
    wr.flush();
    wr.close();
    //Logger.getLogger("log").info("URL: "+url+", response: "+con.getResponseCode());
    con.disconnect();
}

What happens is... actually nothing, unless I try to read anything. For example by uncommenting the above log line which reads the response code. Trying to read a response via con.getInputStream(); also works. There is no movement of packets. When I uncomment the getResponseCode, I can see that http POST is sent, and then 200 OK is sent back. The order is proper. I.e. I don't get some wild response before sending POST. Everything else looks exactly the same (I can attach wireshark screenshots if needed.). In the debugger the code executes (i.e. does not block anywhere).

I don't understand under what circumstances this can be happening. I belive it should be possible, to send a POST request with con.setDoInput(false);. Currently it doesn't send anything or fails (when trying to execute con.getResponseCode()) with an exception because I obviously promised I won't read anything.

It might be relevant, that before sendRequest I do request some data from the same site, but I trust I close everything properly. I.e:

public static String getData(String urlAddress) throws MalformedURLException, IOException {
    URL url = new URL(urlAddress);
    HttpURLConnection con = (HttpURLConnection)url.openConnection();
    con.setDoOutput(false);
    InputStream in = con.getInputStream(); 
    BufferedReader reader = new BufferedReader(new InputStreamReader(in));
    StringBuilder data = new StringBuilder();
    String line;
    while((line = reader.readLine()) != null) {
        data.append(line);
    }
    reader.close();
    in.close();
    con.getResponseCode();
    con.disconnect();
    return data.toString();
}

The server for url in both cases is the same, port also, so I believe it is possible to use the same socket for communication. The above code works and retrieves the data properly.

I am not sure, maybe I don't clean something, and it gets cached, so with out an explicit read the POST gets delayed. There is no other traffic on the socket.

like image 606
luk32 Avatar asked Nov 07 '14 18:11

luk32


1 Answers

Unless you're using fixed-length or chunked transfer mode, HttpURLConnection will buffer all your output until you call getInputStream() or getResponseCode(), so that it can send a correct Content-length header.

If you call getResponseCode() you should have a look at its value.

like image 181
user207421 Avatar answered Nov 14 '22 00:11

user207421