Get the response code from an HTTP connection


#1

Hi there,

I'm using the URL class to do some request, but i do not know how to get the status code. There is any callback or something that can help mi with this??

Thanks in advance!


#2

If you use URL::createInputStream and get the response headers, that should contain the code.


#3

The response code is not there on macOS an android, in android is completly empty


#4

hmm.. well android uses the same code as linux.. Looks like it'd work to me - have you tried debugging into it to see how far it gets?


#5

This is what I found on MacOS:

In the didReceiveResponse function in the juce_Mac_network.mm I print the NSURLResponse* response object and I get the following:

(lldb) po response
<NSHTTPURLResponse: 0x600000226880> { URL: http://example.com/test?param1=value1&param2=value2&param3=value3&param4=value4&param5=value5 } { status code: 403, headers {
    "Content-Length" = 34;
    "Content-Type" = "text/html; charset=iso-8859-1";
    Date = "Fri, 28 Feb 2014 09:53:25 GMT";
    "Proxy-Connection" = "Keep-alive";
    Server = nginx;
} }

the status code is not in the headers section (it belongs to the "Status line" see: RFC http://www.w3.org/Protocols/rfc2616/rfc2616-sec6.html#sec6), I guess that's why it is not stored in the header c++ object.

I would like to propose a solution for this issue. When whe use the createInputStream I would like to see there also the status code, something like this:

int statusCode;

InputStream* inputStream = url.createInputStream (false,
                                                  staticProgressCallback,
                                                  this,
                                                  String(),
                                                  timeOut,
                                                  &statusCode, // a reference to the status code
                                                  &responseHeaders );

Then in the didReceiveResponse it just need to call [((NSHTTPURLResponse*) response) statusCode] to store de value. What do you think?


#6

Yes.. that seems like the right approach.


#7

I’m fixing the issue, for now I have Android and MacOS, I’m expecting to finish iOS on Monday and then I’ll send you The code. I also found a bug on the Android Javanese code for some new Android devices, let’s see how it goes :slight_smile:


#8

Awesome, much appreciated!


#9


I uploaded the changes on dropbox. here there are: https://dl.dropboxusercontent.com/u/1242513/juce_core.zip


On the android activity .java I changed some code to be able to get the headers and the response code:


    // ==============================================================================
    public static class HTTPStream
    {
        public HTTPStream(HttpURLConnection connection_, int[] statusCode_, StringBuffer responseHeaders_) throws IOException
        {
            connection = connection_;
            try {
                inputStream = new BufferedInputStream(connection.getInputStream());
            } catch (IOException e) {
                if (connection.getResponseCode() < HttpStatus.SC_BAD_REQUEST)
                    throw e;
            }
            finally
            {
                statusCode_[0] = connection.getResponseCode();
            }
            
            // On android 4.x it is possible to get an exception when the server return an status code >= 400
            if (statusCode_[0] >= HttpStatus.SC_BAD_REQUEST)
                inputStream = connection.getErrorStream();
            else
                inputStream = connection.getInputStream();
            
            Map<String, List<String>> map = connection_.getHeaderFields();
            for (Map.Entry<String, List<String>> entry : map.entrySet())
            {
                if ( entry.getKey() == null) continue;
                StringBuilder value = new StringBuilder();
                for (String subVal : entry.getValue())
                    value.append(subVal + ",") ;
                
                if (value.length() > 0)
                    value.deleteCharAt (value.length() - 1); // remove the last ','
                
                responseHeaders_.append (entry.getKey() + ": " + value.toString() + "\n");
            }
        }
        public final void release()
        {
            try
            {
                inputStream.close();
            } catch (IOException e)
            {
            }
            connection.disconnect();
        }
        public final int read(byte[] buffer, int numBytes)
        {
            int num = 0;
            try
            {
                num = inputStream.read(buffer, 0, numBytes);
            } catch (IOException e)
            {
            }
            if (num > 0)
                position += num;
            return num;
        }
        public final long getPosition()
        {
            return position;
        }
        public final long getTotalLength()
        {
            return -1;
        }
        public final boolean isExhausted()
        {
            return false;
        }
        public final boolean setPosition(long newPos)
        {
            return false;
        }
        private HttpURLConnection connection;
        private InputStream inputStream;
        private long position;
    }
    public static final HTTPStream createHTTPStream(String address,
            boolean isPost, byte[] postData, String headers, int timeOutMs, int[] statusCode,
            StringBuffer responseHeaders)
    {
        try
        {
            HttpURLConnection connection = (HttpURLConnection) (new URL(address)
                    .openConnection());
            if (connection != null)
            {
                try
                {
                    if (isPost)
                    {
                        connection.setRequestMethod("POST");
                        connection.setConnectTimeout(timeOutMs);
                        connection.setDoOutput(true);
                        connection.setChunkedStreamingMode(0);
                        OutputStream out = connection.getOutputStream();
                        out.write(postData);
                        out.flush();
                    }
                    return new HTTPStream(connection, statusCode, responseHeaders);
                } catch (Throwable e)
                {
                    connection.disconnect();
                }
            }
        } catch (Throwable e)
        {
        }
        return null;
    }
    public final void launchURL(String url)
    {
        startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(url)));
    }
    public static final String getLocaleValue(boolean isRegion)
    {
        java.util.Locale locale = java.util.Locale.getDefault();
        return isRegion ? locale.getDisplayCountry(java.util.Locale.US)
                : locale.getDisplayLanguage(java.util.Locale.US);
    }
    // ==============================================================================

I hope this will helps. It works on Android, MacOS and iOS, I did not fix it for the rest of the platforms.


#10

Did you accepted that solution?


#11

Sorry, didn't have chance to look at the android stuff yet, but I did implement it for the other platforms, didn't I?


#12

nice!! :) I also see that it is also implemented for android: https://github.com/julianstorer/JUCE/commit/4889822eaf7d7d45f9f0c02fe5c298efff764bd5