0

I have the following code:

        HttpURLConnection conn = null;
        BufferedReader in = null;
        StringBuilder sb = null;
        InputStream is = null;
        conn = (HttpURLConnection) url.openConnection();
        // Break-point A
        conn.setDoInput(true);
        conn.setDoOutput(true);
        conn.setRequestMethod("POST");
        // Break-point B
        conn.setRequestProperty("X-TP-APP", Constants.X_TP_APP);
        conn.setRequestProperty("X-TP-DEVICE", Constants.X_TP_DEVICE);
        conn.setRequestProperty("X-TP-LOCALE", Constants.X_TP_LOCALE);
        conn.setRequestProperty("Content-Type", contentType);
        conn.setRequestProperty("Accept", accept);
        conn.setRequestProperty("Authorization", SystemApi.TOKEN_STR);
        conn.setUseCaches(false);
        conn.setConnectTimeout(30000);
        conn.getOutputStream().write(req.getBytes("UTF-8"));
        conn.getOutputStream().flush();
        conn.getOutputStream().close();
        is = conn.getInputStream();
        in = new BufferedReader(new InputStreamReader(is));
        int statusCode = conn.getResponseCode();
        // Break-point C

The code is running fine without problem (when breakpoint(A,B) is disabled)

I tried to find out when does HttpURLConnection really call the request and place breakpoint(A) after conn = getConnection(strURL); and continue the code, but then at the end, at breakpoint(C), server would return me 401 - Unauthorized, which mean my Authorization header is not in the request.

It seem like that we are trying to open a connection first, and then set the header as fast as we can. If we are not fast enough, then the request is called anyway, which doesn't seem right.

My question and concern:

  1. When does HttpURLConnection really call the request?

  2. Is this what is actually happening? Is this the correct way to do so?

  3. Is there a better way to make sure the header is set before calling the request?

Shing
  • 1,255
  • 1
  • 10
  • 18

3 Answers3

2

Per the docs, the actual connection is made when the connect() method is invoked on the [Http]UrlConnection. That may be done manually, or it may be done implicitly by certain other methods. The Javadocs for UrlConnection.connect() say, in part:

URLConnection objects go through two phases: first they are created, then they are connected. After being created, and before being connected, various options can be specified (e.g., doInput and UseCaches). After connecting, it is an error to try to set them. Operations that depend on being connected, like getContentLength, will implicitly perform the connection, if necessary.

Note in particular the last sentence. I don't see anything in your code that would require the connection to be established until the first conn.getOutputStream(), and I read the docs as saying that the connection object will not enter the "connected" state until some method is invoked on it that requires that. Until such a time, it is ok to set connection properties.

Moreover, the docs definitely state that methods that set properties on the connection (and setRequestProperty() in particular) will throw an IllegalStateException if invoked when the connection object is already connected.

It is possible that your Java library is buggy in the manner you describe, but that would certainly be in conflict with the API specification. I think it's more likely that the explanation for the behavior you observe is different, and I recommend you capture and analyze the actual HTTP traffic to determine what's really going on.

John Bollinger
  • 160,171
  • 8
  • 81
  • 157
0

Actually what really happened is, in the debug mode, I used conn.getResponseCode() in the expressions, which force the conn.getResponseCode() to run.

When it is not connected yet, getResponseCode() would calls connect() before the request is prepared.

Hence it would return me 401.

Shing
  • 1,255
  • 1
  • 10
  • 18
0

Since Android using the same HttpURLConnection, I did some capture the packet exchange to see what is happening under the hood.

I detailed my experiment in this post Can you explain the HttpURLConnection connection process?

To outline the network activity for your program.

At Breakpoint A No physical connection is made to the remote server. You get a logical handle to a local connection object.

At Breakpoint B You just configure the local connection object, nothing more.

conn.getOutputStream() Network connection starts here, but no payload is transferred to the server.

conn.getInputStream() Payload (http headers, content) are sent to the server, and you get the response (buffered into input stream, and also the response code etc.)

To Answer your question

When does HttpURLConnection really call the request?

getInputStream() triggers network layer to send out application payload and got responses.

Is this what is actually happening? Is this the correct way to do so?

No. openConnection() does not initiate network activity. You are getting back a local handle for future connection, not an active connection.

Is there a better way to make sure the header is set before calling the request?

You don't need to make sure header is set. The header payload isn't sent to the server until you ask for response (such as getting the response code, or opening a inputStream )

HarryQ
  • 1,281
  • 2
  • 10
  • 25