views:

206

answers:

4

Hello Everyone,

For the majority of the time, my HTTP Requests work with no problem. However, occasionally they will hang.

The code that I am using is set up so that if the request succeeds (with a response code of 200 or 201), then call screen.requestSucceeded(). If the request fails, then call screen.requestFailed().

When the request hangs, however, it does so before one of the above methods are called. Is there something wrong with my code? Should I be using some sort of best practice to prevent any hanging?

The following is my code. I would appreciate any help. Thanks!

HttpConnection connection = (HttpConnection) Connector.open(url
                    + connectionParameters);

            connection.setRequestMethod(method);
            connection.setRequestProperty("WWW-Authenticate",
                    "OAuth realm=api.netflix.com");
            if (method.equals("POST") && postData != null) {
            connection.setRequestProperty("Content-Type",
                    "application/x-www-form-urlencoded");
            connection.setRequestProperty("Content-Length", Integer
                    .toString(postData.length));
            OutputStream requestOutput = connection.openOutputStream();
            requestOutput.write(postData);
            requestOutput.close();
        }
            int responseCode = connection.getResponseCode();
            System.out.println("RESPONSE CODE: " + responseCode);
            if (connection instanceof HttpsConnection) {
                HttpsConnection secureConnection = (HttpsConnection) connection;
                String issuer = secureConnection.getSecurityInfo()
                        .getServerCertificate().getIssuer();
                UiApplication.getUiApplication().invokeLater(
                        new DialogRunner(
                                "Secure Connection! Certificate issued by: "
                                        + issuer));

            }

            if (responseCode != 200 && responseCode != 201) {
                screen.requestFailed("Unexpected response code: "
                        + responseCode);
                connection.close();
                return;
            }

            String contentType = connection.getHeaderField("Content-type");
            ByteArrayOutputStream baos = new ByteArrayOutputStream();

            InputStream responseData = connection.openInputStream();
            byte[] buffer = new byte[20000];
            int bytesRead = 0;
            while ((bytesRead = responseData.read(buffer)) > 0) {
                baos.write(buffer, 0, bytesRead);
            }
            baos.close();
            connection.close();
            screen.requestSucceeded(baos.toByteArray(), contentType);
        } catch (IOException ex) {
            screen.requestFailed(ex.toString());
        }
+2  A: 

Without any trace, I am just shooting in the dark.

Try to add this 2 calls,

System.setProperty("http.keepAlive", "false");

connection.setRequestProperty("Connection", "close");

Keep-alive is a common cause for stale connections. These calls will disable it.

ZZ Coder
+1 That was also my first thought.
BalusC
Interesting, hadn't thought of this. Good to know. I will add the two calls and see what happens!
behrk2
+2  A: 

I don't see any issues with the code. It could be that your platform has an intermittent bug, or that the website is causing the connection to hang. Changing connection parameters, such as keep alive, may help.

But, even with a timeout set, Sockets can hang indefinitely - a friend aptly demonstrated this to me some years ago by pulling out the network cable - my program just hung there forever, even with a SO_TIMEOUT set to 30 seconds.

As a "best practice", you can avoid hanging your application by moving all network communication to a separate thread. If you wrap up each request as a Runnable and queue these for exeuction, you maintain control over timeouts (synchronization is still in java, rather than a blocking native I/O call). You can interrupt your waiting thread after (say) 30s to avoid stalling your app. You could then either inform the user, or retry the request. Because the request is a Runnable, you can remove it from the stalled thread's queue and schedule it to execute on another thread.

mdma
mdma -The code that I posted above is being executed in a separate thread. However, I will consider your idea about re-scheduling stalled thread's. You make a good point about "pulling out the network cable". Thanks
behrk2
+1  A: 

I see you have code to handle sending a "POST" type request, however there is nothing that writes the POST data in the request. If the connection type is "POST", then you should be doing the following BEFORE the connection.getResponseCode():

  • set the "Content-Length" header
  • set the "Content-Type" header (which you're doing)
  • get an OutputStream from the connection using connection.openOutputStream()
  • write the POST (form) data to the OutputStream
  • close the OutputStream
Marc Novakowski
Hi Marc,I was unsure if I had needed to send POST data or not. I guess the answer is yes. Perhaps that is the reason for the occasional hangs. Is it strange that the connections work most of the time, without sending the POST data? Thanks..
behrk2
I guess it all depends on the service you're accessing and whether or not it requires GET or POST.
Marc Novakowski
Hi Marc, I have changed how my class handles the POST data (see updated code). I am now writing the POST data to the OutputStream. What I was doing before was essentially appending my POST data to the request URL. What is the difference between the two methods? Also, does a PUT HTTP Request require the same configuration as a POST? Thanks for your help.
behrk2
The best documentation is the HTTP spec itself - take a look at http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9
Marc Novakowski