4

I am trying to do a POST request using HttpsURLConnection, and get

java.net.ProtocolException: Connection already established

on setRequestMethod Weirdly, conn.connected returns false just before.

What am I missing?

URL url = new URL("https://ws.audioscrobbler.com/2.0/");
HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
conn.setReadTimeout(15000);
conn.setConnectTimeout(15000);
// here conn.connected is false
conn.setRequestMethod("POST"); // here I get java.net.ProtocolException: Connection already established
conn.setDoInput(true);

EDIT

I tried DefaultHttpClient and it works, so I'll use it instead.

jul
  • 36,404
  • 64
  • 191
  • 318
  • Works in Java. What is `conn.connected`? Are you sure that's all the code? – user207421 Aug 01 '13 at 02:48
  • http://developer.android.com/reference/java/net/URLConnection.html#connected. There is more code, but after the line that returns the exception. This works when it's `HttpURLConnection` (not https) and this work with https using `DefaultHttpClient`. – jul Aug 01 '13 at 02:50
  • Can you explain how you manage to use `conn.connected`? As far as I know, the moment you do `url.openConnection()`, you have already established the connection. Note the fact that `url.openConnection()` returns `URLConnection` instead of `HttpsURLConnection`. – LightYearsBehind Aug 01 '13 at 02:55
  • I set a breakpoint on `conn.setRequestMethod("POST");` and check the members of conn. – jul Aug 01 '13 at 03:06
  • @haike00 No. The TCP connection is established when you first call one of `getOutputStream(),` `getInputStream(),` or `getResponseCode(),` unless it's a pooled connection already established. – user207421 Aug 01 '13 at 03:29
  • So this `Connection already established` when calling `setRequestMethod` does not make sense. Anyway, I'll use `DefaultHttpClient`, which works perfectly for what I'm trying to do. – jul Aug 02 '13 at 07:25

2 Answers2

1

For anyone else who runs into this problem, I had an order of operations issue that only affected me when I was doing an HTTP POST that had content in the request body. It's not entirely clear in all scenarios when HttpURLConnection is actually initiating the connection to the server.

My initial request looked like this:

        HttpURLConnection conn = null;
        try
        {
            conn = (HttpURLConnection) baseUrl.openConnection();  
            conn.setConnectTimeout(connectTimeoutMillis);
            conn.setReadTimeout(requestTimeoutMillis);

            //required for reading a response body
            conn.setDoInput(true);

            //Not all request types have a body (e.g. GET usually doesn't)
            if(requestBody != null && requestBody.length > 0)
            {
                conn.setDoOutput(true);
                conn.setFixedLengthStreamingMode(requestBody.length);
                conn.getOutputStream().write(requestBody);
                conn.getOutputStream().flush();
                conn.getOutputStream().close();
            }

            try
            {
                conn.setRequestMethod(verb.toUpperCase());
            }
            catch (final ProtocolException e)
            {
                response.setError("Invalid HTTP verb \"" + verb + "\" received.","");
                Log.e(TAG, response.errorMessage, e);
                return response;
            }

It turns out that you cannot call "conn.setRequestMethod(...)" after you've called "conn.getOutputStream()", so in my case, the simple fix was the call "conn.setRequestMethod(...)" before dealing with writing to the request body. The working code is:

HttpURLConnection conn = null;
        try
        {
            conn = (HttpURLConnection) baseUrl.openConnection();  
            conn.setConnectTimeout(connectTimeoutMillis);
            conn.setReadTimeout(requestTimeoutMillis);

            //required for reading a response body
            conn.setDoInput(true);

            try
            {
                conn.setRequestMethod(verb.toUpperCase());
            }
            catch (final ProtocolException e)
            {
                response.setError("Invalid HTTP verb \"" + verb + "\" received.","");
                Log.e(TAG, response.errorMessage, e);
                return response;
            }

            //Not all request types have a body (e.g. GET usually doesn't)
            if(requestBody != null && requestBody.length > 0)
            {
                conn.setDoOutput(true);
                conn.setFixedLengthStreamingMode(requestBody.length);
                conn.getOutputStream().write(requestBody);
                conn.getOutputStream().flush();
                conn.getOutputStream().close();
            }

The only real change was just switching the ordering of calls and that got rid of the exception. Hopefully that fixes the issue for anyone else who had this problem.

Brent Writes Code
  • 19,075
  • 7
  • 52
  • 56
  • How you can assign post get without - > conn.setRequestMethod("POST/GET"); ??? –  Dec 15 '15 at 13:44
  • @delive Isn't that what the line `conn.setRequestMethod(verb.toUpperCase());` is doing? – Brent Writes Code Dec 15 '15 at 17:16
  • if you put "setRequestMethod" says : connection already open, crash app !! –  Dec 16 '15 at 08:55
  • @delive Are you sure you're not using the incorrect first example instead of the correct second example? If you've done anything with the OutputStream object, even just calling `getOutputStream()`, it's too late to set the request method. – Brent Writes Code Dec 16 '15 at 17:31
0

I tried DefaultHttpClient and it works, so I'll use it instead.

jul
  • 36,404
  • 64
  • 191
  • 318