HttpURLConnection getResponseCode not returning

Issue

I’m trying to POST a file to our server using HttpURLConnection on Android, but the getResponseCode call just hangs and never returns. The issue stems from the file being too big for the server, so the server sends back an HTTP error code of 413 (which I can see in the server logs), but on our device, it seems like this is never received. I have the following code in our app:

public FileUploadUtility(URL requestURL, File uploadFile) throws IOException
{
    file = uploadFile;
    String fileName = uploadFile.getName();

    httpURLConnection = (HttpURLConnection) requestURL.openConnection();
    httpURLConnection.setUseCaches(false);
    httpURLConnection.setDoOutput(true);
    httpURLConnection.setDoInput(true);
    httpURLConnection.setRequestMethod("POST");
    httpURLConnection.setRequestProperty("Content-Type", URLConnection.guessContentTypeFromName(fileName));
    //httpURLConnection.setRequestProperty("Content-Length", Long.toString(fileSize));
    long fileSize = uploadFile.length();
    httpURLConnection.setFixedLengthStreamingMode(fileSize);
    outputStream = httpURLConnection.getOutputStream();
}

/**
 * Completes the request and receives response from the server.
 *
 * @return a list of Strings as response in case the server returned
 * status OK, otherwise an exception is thrown.
 * @throws IOException
 */
public String finish(ProgressListener progressListener) throws IOException, HTTPErrorCodeException
{
    try (FileInputStream inputStream = new FileInputStream(file))
    {
        byte[] buffer = new byte[100 * 1024];
        int bytesRead;

        long fileSize = file.length();
        int total = 0;
        while ((bytesRead = inputStream.read(buffer)) != -1)
        {
            outputStream.write(buffer, 0, bytesRead);

            total += bytesRead;
            if(fileSize > 0)
            {
                progressListener.fileUploadProgress((float)total / (float)fileSize);
            }
        }
        outputStream.flush();
    }
    catch (Exception e)
    {
        e.printStackTrace();
        throw new IOException("Error uploading file: " + e.getMessage());
    }

    String response;

    // Checks server's status code first
    int status = httpURLConnection.getResponseCode();
    if (status == HttpURLConnection.HTTP_OK)
    {
        try (BufferedReader reader = new BufferedReader(new InputStreamReader(httpURLConnection.getInputStream())))
        {
            StringBuilder builder = new StringBuilder();
            String output;
            while ((output = reader.readLine()) != null)
            {
                builder.append(output);
            }
            response = builder.toString();
            Log.i("Server response body", response);
        }
        httpURLConnection.disconnect();
        httpURLConnection = null;
    }
    else
    {

        String serverResponseMessage = httpURLConnection.getResponseMessage();
        Log.i("Server Response Message", serverResponseMessage);

        try (BufferedReader responseReader = new BufferedReader(new InputStreamReader((httpURLConnection.getInputStream()))))
        {
            StringBuilder builder = new StringBuilder();
            String output;
            while ((output = responseReader.readLine()) != null)
            {
                builder.append(output);
            }
            Log.i("Server response body", builder.toString());
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
        try (BufferedReader errorReader = new BufferedReader(new InputStreamReader((httpURLConnection.getErrorStream()))))
        {
            StringBuilder builder = new StringBuilder();
            String output;
            while ((output = errorReader.readLine()) != null)
            {
                builder.append(output);
            }
            Log.i("Server error", builder.toString());
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }

        throw new HTTPErrorCodeException(status);
    }

    return response;
}

Just to reiterate, the issue isn’t ‘why is the server rejecting the upload’, it’s why HttpURLConnection doesn’t seem to pick up the response code. When breaking into the debugger, it looks like HttpURLConnection is stuck trying to write the output buffer, but the server has already sent the response code before the app finishes writing the output buffer (as the server has rejected the POST based on the header). The server is Nginx forwarding to a Node.JS instance if that helps at all, but as I can see the 413 in the logs, I think it’s an issue on the app’s side of things. It hangs on the following line:

int status = httpURLConnection.getResponseCode();

Solution

So it turns out the issue is down HttpURLConnection wanting to upload the whole body before reading any of the response. Nginx is sending the 413 response and closing the connection before the app has sent the body, but HttpURLConnection is still trying to send the body. As the connection is closed at the Nginx end, sending the data is failing, but there’s no default timeout specified by HttpURLConnection. Ideally, HttpURLConnection would check for early response headers while trying to write the output, and it may do this in later Android versions (I’m testing on 4.4, so I’m not sure if this works better in later versions). For now, setting a timeout seems to work:

httpURLConnection.setConnectTimeout(10 * 1000);
httpURLConnection.setReadTimeout(10 * 1000);

Answered By – Andrew Porritt

This Answer collected from stackoverflow, is licensed under cc by-sa 2.5 , cc by-sa 3.0 and cc by-sa 4.0

Leave a Reply

(*) Required, Your email will not be published