From 4889822eaf7d7d45f9f0c02fe5c298efff764bd5 Mon Sep 17 00:00:00 2001 From: jules Date: Thu, 6 Mar 2014 22:26:58 +0000 Subject: [PATCH] Added http status code access for URL::createInputStream(). Also added threading + header display to the demo's http page. --- .../src/com/juce/jucedemo/JuceDemo.java | 54 ++++++++++++----- extras/Demo/Source/Demos/NetworkingDemo.cpp | 45 +++++++++++--- modules/juce_core/juce_core.cpp | 2 +- .../native/java/JuceAppActivity.java | 54 ++++++++++++----- .../native/juce_android_JNIHelpers.h | 2 +- .../juce_core/native/juce_android_Network.cpp | 24 ++++---- .../juce_core/native/juce_linux_Network.cpp | 45 ++++++-------- modules/juce_core/native/juce_mac_Network.mm | 25 ++++---- .../juce_core/native/juce_win32_Network.cpp | 60 +++++++++---------- modules/juce_core/network/juce_URL.cpp | 15 +++-- modules/juce_core/network/juce_URL.h | 11 ++-- 11 files changed, 205 insertions(+), 132 deletions(-) diff --git a/extras/Demo/Builds/Android/src/com/juce/jucedemo/JuceDemo.java b/extras/Demo/Builds/Android/src/com/juce/jucedemo/JuceDemo.java index bd3fd9c7dd..13ba3d0d72 100644 --- a/extras/Demo/Builds/Android/src/com/juce/jucedemo/JuceDemo.java +++ b/extras/Demo/Builds/Android/src/com/juce/jucedemo/JuceDemo.java @@ -589,10 +589,34 @@ public final class JuceDemo extends Activity //============================================================================== public static class HTTPStream { - public HTTPStream (HttpURLConnection connection_) throws IOException + public HTTPStream (HttpURLConnection connection_, + int[] statusCode, StringBuffer responseHeaders) throws IOException { connection = connection_; - inputStream = new BufferedInputStream (connection.getInputStream()); + + try + { + inputStream = new BufferedInputStream (connection.getInputStream()); + } + catch (IOException e) + { + if (connection.getResponseCode() < org.apache.http.HttpStatus.SC_BAD_REQUEST) + throw e; + } + finally + { + statusCode[0] = connection.getResponseCode(); + } + + if (statusCode[0] >= org.apache.http.HttpStatus.SC_BAD_REQUEST) + inputStream = connection.getErrorStream(); + else + inputStream = connection.getInputStream(); + + for (java.util.Map.Entry> entry : connection.getHeaderFields().entrySet()) + if (entry.getKey() != null && entry.getValue() != null) + responseHeaders.append (entry.getKey() + ": " + + android.text.TextUtils.join (",", entry.getValue()) + "\n"); } public final void release() @@ -634,30 +658,31 @@ public final class JuceDemo extends Activity private long position; } - public static final HTTPStream createHTTPStream (String address, boolean isPost, byte[] postData, - String headers, int timeOutMs, - java.lang.StringBuffer responseHeaders) + 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()); - + HttpURLConnection connection = (HttpURLConnection) (new URL(address) + .openConnection()); if (connection != null) { try { if (isPost) { - connection.setConnectTimeout (timeOutMs); - connection.setDoOutput (true); - connection.setChunkedStreamingMode (0); - + connection.setRequestMethod("POST"); + connection.setConnectTimeout(timeOutMs); + connection.setDoOutput(true); + connection.setChunkedStreamingMode(0); OutputStream out = connection.getOutputStream(); - out.write (postData); + out.write(postData); out.flush(); } - return new HTTPStream (connection); + return new HTTPStream (connection, statusCode, responseHeaders); } catch (Throwable e) { @@ -665,8 +690,7 @@ public final class JuceDemo extends Activity } } } - catch (Throwable e) - {} + catch (Throwable e) {} return null; } diff --git a/extras/Demo/Source/Demos/NetworkingDemo.cpp b/extras/Demo/Source/Demos/NetworkingDemo.cpp index a3f9d7de5c..d0c7a471e2 100644 --- a/extras/Demo/Source/Demos/NetworkingDemo.cpp +++ b/extras/Demo/Source/Demos/NetworkingDemo.cpp @@ -28,11 +28,13 @@ //============================================================================== class NetworkingDemo : public Component, - private Button::Listener + private Button::Listener, + private Thread { public: NetworkingDemo() - : resultsBox (resultsDocument, nullptr) + : Thread ("Network Demo"), + resultsBox (resultsDocument, nullptr) { setOpaque (true); @@ -69,6 +71,37 @@ public: resultsBox.setBounds (area.reduced (8)); } + void run() override + { + String result (getResultText (urlBox.getText())); + + MessageManagerLock mml (this); + + if (mml.lockWasGained()) + resultsBox.loadContent (result); + } + + String getResultText (const URL& url) + { + StringPairArray responseHeaders; + int statusCode = 0; + + ScopedPointer stream (url.createInputStream (false, nullptr, nullptr, String(), + 10000, // timeout in millisecs + &responseHeaders, &statusCode)); + if (stream != nullptr) + return (statusCode != 0 ? "Status code: " + String (statusCode) + newLine : String()) + + "Response headers: " + newLine + + responseHeaders.getDescription() + newLine + + "----------------------------------------------------" + newLine + + stream->readEntireStreamAsString(); + + if (statusCode != 0) + return "Failed to connect, status code = " + String (statusCode); + + return "Failed to connect!"; + } + private: TextEditor urlBox; TextButton fetchButton; @@ -76,16 +109,10 @@ private: CodeDocument resultsDocument; CodeEditorComponent resultsBox; - void downloadUrl() - { - URL url (urlBox.getText()); - resultsBox.loadContent (url.readEntireTextStream()); - } - void buttonClicked (Button* button) override { if (button == &fetchButton) - downloadUrl(); + startThread(); } JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (NetworkingDemo) diff --git a/modules/juce_core/juce_core.cpp b/modules/juce_core/juce_core.cpp index be6b6ebf5c..c992d50896 100644 --- a/modules/juce_core/juce_core.cpp +++ b/modules/juce_core/juce_core.cpp @@ -133,7 +133,6 @@ namespace juce #include "network/juce_MACAddress.cpp" #include "network/juce_NamedPipe.cpp" #include "network/juce_Socket.cpp" -#include "network/juce_URL.cpp" #include "network/juce_IPAddress.cpp" #include "streams/juce_BufferedInputStream.cpp" #include "streams/juce_FileInputSource.cpp" @@ -219,5 +218,6 @@ namespace juce #include "threads/juce_ChildProcess.cpp" #include "threads/juce_HighResolutionTimer.cpp" +#include "network/juce_URL.cpp" } diff --git a/modules/juce_core/native/java/JuceAppActivity.java b/modules/juce_core/native/java/JuceAppActivity.java index c7ba17891f..418b032a48 100644 --- a/modules/juce_core/native/java/JuceAppActivity.java +++ b/modules/juce_core/native/java/JuceAppActivity.java @@ -589,10 +589,34 @@ public final class JuceAppActivity extends Activity //============================================================================== public static class HTTPStream { - public HTTPStream (HttpURLConnection connection_) throws IOException + public HTTPStream (HttpURLConnection connection_, + int[] statusCode, StringBuffer responseHeaders) throws IOException { connection = connection_; - inputStream = new BufferedInputStream (connection.getInputStream()); + + try + { + inputStream = new BufferedInputStream (connection.getInputStream()); + } + catch (IOException e) + { + if (connection.getResponseCode() < org.apache.http.HttpStatus.SC_BAD_REQUEST) + throw e; + } + finally + { + statusCode[0] = connection.getResponseCode(); + } + + if (statusCode[0] >= org.apache.http.HttpStatus.SC_BAD_REQUEST) + inputStream = connection.getErrorStream(); + else + inputStream = connection.getInputStream(); + + for (java.util.Map.Entry> entry : connection.getHeaderFields().entrySet()) + if (entry.getKey() != null && entry.getValue() != null) + responseHeaders.append (entry.getKey() + ": " + + android.text.TextUtils.join (",", entry.getValue()) + "\n"); } public final void release() @@ -634,30 +658,31 @@ public final class JuceAppActivity extends Activity private long position; } - public static final HTTPStream createHTTPStream (String address, boolean isPost, byte[] postData, - String headers, int timeOutMs, - java.lang.StringBuffer responseHeaders) + 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()); - + HttpURLConnection connection = (HttpURLConnection) (new URL(address) + .openConnection()); if (connection != null) { try { if (isPost) { - connection.setConnectTimeout (timeOutMs); - connection.setDoOutput (true); - connection.setChunkedStreamingMode (0); - + connection.setRequestMethod("POST"); + connection.setConnectTimeout(timeOutMs); + connection.setDoOutput(true); + connection.setChunkedStreamingMode(0); OutputStream out = connection.getOutputStream(); - out.write (postData); + out.write(postData); out.flush(); } - return new HTTPStream (connection); + return new HTTPStream (connection, statusCode, responseHeaders); } catch (Throwable e) { @@ -665,8 +690,7 @@ public final class JuceAppActivity extends Activity } } } - catch (Throwable e) - {} + catch (Throwable e) {} return null; } diff --git a/modules/juce_core/native/juce_android_JNIHelpers.h b/modules/juce_core/native/juce_android_JNIHelpers.h index 9a4b5f8391..044679e740 100644 --- a/modules/juce_core/native/juce_android_JNIHelpers.h +++ b/modules/juce_core/native/juce_android_JNIHelpers.h @@ -365,7 +365,7 @@ extern ThreadLocalJNIEnvHolder threadLocalJNIEnvHolder; METHOD (setClipboardContent, "setClipboardContent", "(Ljava/lang/String;)V") \ METHOD (excludeClipRegion, "excludeClipRegion", "(Landroid/graphics/Canvas;FFFF)V") \ METHOD (renderGlyph, "renderGlyph", "(CLandroid/graphics/Paint;Landroid/graphics/Matrix;Landroid/graphics/Rect;)[I") \ - STATICMETHOD (createHTTPStream, "createHTTPStream", "(Ljava/lang/String;Z[BLjava/lang/String;ILjava/lang/StringBuffer;)L" JUCE_ANDROID_ACTIVITY_CLASSPATH "$HTTPStream;") \ + STATICMETHOD (createHTTPStream, "createHTTPStream", "(Ljava/lang/String;Z[BLjava/lang/String;I[ILjava/lang/StringBuffer;)L" JUCE_ANDROID_ACTIVITY_CLASSPATH "$HTTPStream;") \ METHOD (launchURL, "launchURL", "(Ljava/lang/String;)V") \ METHOD (showMessageBox, "showMessageBox", "(Ljava/lang/String;Ljava/lang/String;J)V") \ METHOD (showOkCancelBox, "showOkCancelBox", "(Ljava/lang/String;Ljava/lang/String;J)V") \ diff --git a/modules/juce_core/native/juce_android_Network.cpp b/modules/juce_core/native/juce_android_Network.cpp index 40478d4b63..1b86deeeef 100644 --- a/modules/juce_core/native/juce_android_Network.cpp +++ b/modules/juce_core/native/juce_android_Network.cpp @@ -71,6 +71,7 @@ public: WebInputStream (String address, bool isPost, const MemoryBlock& postData, URL::OpenStreamProgressCallback* progressCallback, void* progressCallbackContext, const String& headers, int timeOutMs, StringPairArray* responseHeaders) + : statusCode (0) { if (! address.contains ("://")) address = "http://" + address; @@ -91,6 +92,9 @@ public: // thread. You'll need to move your networking code to a background thread to keep it happy.. jassert (Thread::getCurrentThread() != nullptr); + jintArray statusCodeArray = env->NewIntArray (1); + jassert (statusCodeArray != 0); + stream = GlobalRef (env->CallStaticObjectMethod (JuceAppActivity, JuceAppActivity.createHTTPStream, javaString (address).get(), @@ -98,8 +102,14 @@ public: postDataArray, javaString (headers).get(), (jint) timeOutMs, + statusCodeArray, responseHeaderBuffer.get())); + jint* const statusCodeElements = env->GetIntArrayElements (statusCodeArray, 0); + statusCode = statusCodeElements[0]; + env->ReleaseIntArrayElements (statusCodeArray, statusCodeElements, 0); + env->DeleteLocalRef (statusCodeArray); + if (postDataArray != 0) env->DeleteLocalRef (postDataArray); @@ -135,6 +145,8 @@ public: } //============================================================================== + bool isError() const { return stream == nullptr; } + bool isExhausted() override { return stream != nullptr && stream.callBooleanMethod (HTTPStream.isExhausted); } int64 getTotalLength() override { return stream != nullptr ? stream.callLongMethod (HTTPStream.getTotalLength) : 0; } int64 getPosition() override { return stream != nullptr ? stream.callLongMethod (HTTPStream.getPosition) : 0; } @@ -162,18 +174,8 @@ public: //============================================================================== GlobalRef stream; + int statusCode; private: JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (WebInputStream) }; - -InputStream* URL::createNativeStream (const String& address, bool isPost, const MemoryBlock& postData, - OpenStreamProgressCallback* progressCallback, void* progressCallbackContext, - const String& headers, const int timeOutMs, StringPairArray* responseHeaders) -{ - ScopedPointer wi (new WebInputStream (address, isPost, postData, - progressCallback, progressCallbackContext, - headers, timeOutMs, responseHeaders)); - - return wi->stream != 0 ? wi.release() : nullptr; -} diff --git a/modules/juce_core/native/juce_linux_Network.cpp b/modules/juce_core/native/juce_linux_Network.cpp index a052b2c216..36aeeb8079 100644 --- a/modules/juce_core/native/juce_linux_Network.cpp +++ b/modules/juce_core/native/juce_linux_Network.cpp @@ -72,11 +72,11 @@ public: WebInputStream (const String& address_, bool isPost_, const MemoryBlock& postData_, URL::OpenStreamProgressCallback* progressCallback, void* progressCallbackContext, const String& headers_, int timeOutMs_, StringPairArray* responseHeaders) - : socketHandle (-1), levelsOfRedirection (0), + : statusCode (0), socketHandle (-1), levelsOfRedirection (0), address (address_), headers (headers_), postData (postData_), position (0), finished (false), isPost (isPost_), timeOutMs (timeOutMs_) { - createConnection (progressCallback, progressCallbackContext); + statusCode = createConnection (progressCallback, progressCallbackContext); if (responseHeaders != nullptr && ! isError()) { @@ -144,7 +144,7 @@ public: { closeSocket(); position = 0; - createConnection (0, 0); + statusCode = createConnection (0, 0); } skipNextBytes (wantedPos - position); @@ -154,6 +154,8 @@ public: } //============================================================================== + int statusCode; + private: int socketHandle, levelsOfRedirection; StringArray headerLines; @@ -173,7 +175,7 @@ private: levelsOfRedirection = 0; } - void createConnection (URL::OpenStreamProgressCallback* progressCallback, void* progressCallbackContext) + int createConnection (URL::OpenStreamProgressCallback* progressCallback, void* progressCallbackContext) { closeSocket(); @@ -189,7 +191,7 @@ private: String hostName, hostPath; int hostPort; if (! decomposeURL (address, hostName, hostPath, hostPort)) - return; + return 0; String serverName, proxyName, proxyPath; int proxyPort = 0; @@ -199,7 +201,7 @@ private: if (proxyURL.startsWithIgnoreCase ("http://")) { if (! decomposeURL (proxyURL, proxyName, proxyPath, proxyPort)) - return; + return 0; serverName = proxyName; port = proxyPort; @@ -219,14 +221,14 @@ private: struct addrinfo* result = nullptr; if (getaddrinfo (serverName.toUTF8(), String (port).toUTF8(), &hints, &result) != 0 || result == 0) - return; + return 0; socketHandle = socket (result->ai_family, result->ai_socktype, 0); if (socketHandle == -1) { freeaddrinfo (result); - return; + return 0; } int receiveBufferSize = 16384; @@ -241,7 +243,7 @@ private: { closeSocket(); freeaddrinfo (result); - return; + return 0; } freeaddrinfo (result); @@ -254,7 +256,7 @@ private: progressCallback, progressCallbackContext)) { closeSocket(); - return; + return 0; } } @@ -265,15 +267,15 @@ private: { headerLines = StringArray::fromLines (responseHeader); - const int statusCode = responseHeader.fromFirstOccurrenceOf (" ", false, false) - .substring (0, 3).getIntValue(); + const int status = responseHeader.fromFirstOccurrenceOf (" ", false, false) + .substring (0, 3).getIntValue(); //int contentLength = findHeaderItem (lines, "Content-Length:").getIntValue(); //bool isChunked = findHeaderItem (lines, "Transfer-Encoding:").equalsIgnoreCase ("chunked"); String location (findHeaderItem (headerLines, "Location:")); - if (statusCode >= 300 && statusCode < 400 + if (status >= 300 && status < 400 && location.isNotEmpty() && location != address) { if (! location.startsWithIgnoreCase ("http://")) @@ -282,18 +284,18 @@ private: if (++levelsOfRedirection <= 3) { address = location; - createConnection (progressCallback, progressCallbackContext); - return; + return createConnection (progressCallback, progressCallbackContext); } } else { levelsOfRedirection = 0; - return; + return status; } } closeSocket(); + return 0; } //============================================================================== @@ -437,14 +439,3 @@ private: JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (WebInputStream) }; - -InputStream* URL::createNativeStream (const String& address, bool isPost, const MemoryBlock& postData, - OpenStreamProgressCallback* progressCallback, void* progressCallbackContext, - const String& headers, const int timeOutMs, StringPairArray* responseHeaders) -{ - ScopedPointer wi (new WebInputStream (address, isPost, postData, - progressCallback, progressCallbackContext, - headers, timeOutMs, responseHeaders)); - - return wi->isError() ? nullptr : wi.release(); -} diff --git a/modules/juce_core/native/juce_mac_Network.mm b/modules/juce_core/native/juce_mac_Network.mm index 75c9ce19a2..cfb75e8e26 100644 --- a/modules/juce_core/native/juce_mac_Network.mm +++ b/modules/juce_core/native/juce_mac_Network.mm @@ -118,6 +118,7 @@ public: connection (nil), data ([[NSMutableData data] retain]), headers (nil), + statusCode (0), initialised (false), hasFailed (false), hasFinished (false) @@ -202,7 +203,11 @@ public: headers = nil; if ([response isKindOfClass: [NSHTTPURLResponse class]]) - headers = [[((NSHTTPURLResponse*) response) allHeaderFields] retain]; + { + NSHTTPURLResponse* httpResponse = (NSHTTPURLResponse*) response; + headers = [[httpResponse allHeaderFields] retain]; + statusCode = (int) [httpResponse statusCode]; + } } void didFailWithError (NSError* error) @@ -251,6 +256,7 @@ public: NSURLConnection* connection; NSMutableData* data; NSDictionary* headers; + int statusCode; bool initialised, hasFailed, hasFinished; private: @@ -318,7 +324,7 @@ public: WebInputStream (const String& address_, bool isPost_, const MemoryBlock& postData_, URL::OpenStreamProgressCallback* progressCallback, void* progressCallbackContext, const String& headers_, int timeOutMs_, StringPairArray* responseHeaders) - : address (address_), headers (headers_), postData (postData_), position (0), + : statusCode (0), address (address_), headers (headers_), postData (postData_), position (0), finished (false), isPost (isPost_), timeOutMs (timeOutMs_) { JUCE_AUTORELEASEPOOL @@ -327,6 +333,8 @@ public: if (responseHeaders != nullptr && connection != nullptr && connection->headers != nil) { + statusCode = connection->statusCode; + NSEnumerator* enumerator = [connection->headers keyEnumerator]; while (NSString* key = [enumerator nextObject]) @@ -380,6 +388,8 @@ public: return true; } + int statusCode; + private: ScopedPointer connection; String address, headers; @@ -428,14 +438,3 @@ private: JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (WebInputStream) }; - -InputStream* URL::createNativeStream (const String& address, bool isPost, const MemoryBlock& postData, - OpenStreamProgressCallback* progressCallback, void* progressCallbackContext, - const String& headers, const int timeOutMs, StringPairArray* responseHeaders) -{ - ScopedPointer wi (new WebInputStream (address, isPost, postData, - progressCallback, progressCallbackContext, - headers, timeOutMs, responseHeaders)); - - return wi->isError() ? nullptr : wi.release(); -} diff --git a/modules/juce_core/native/juce_win32_Network.cpp b/modules/juce_core/native/juce_win32_Network.cpp index ef31c02190..22e502795f 100644 --- a/modules/juce_core/native/juce_win32_Network.cpp +++ b/modules/juce_core/native/juce_win32_Network.cpp @@ -41,41 +41,50 @@ public: WebInputStream (const String& address_, bool isPost_, const MemoryBlock& postData_, URL::OpenStreamProgressCallback* progressCallback, void* progressCallbackContext, const String& headers_, int timeOutMs_, StringPairArray* responseHeaders) - : connection (0), request (0), + : statusCode (0), connection (0), request (0), address (address_), headers (headers_), postData (postData_), position (0), finished (false), isPost (isPost_), timeOutMs (timeOutMs_) { createConnection (progressCallback, progressCallbackContext); - if (responseHeaders != nullptr && ! isError()) + if (! isError()) { - DWORD bufferSizeBytes = 4096; - - for (;;) + if (responseHeaders != nullptr) { - HeapBlock buffer ((size_t) bufferSizeBytes); + DWORD bufferSizeBytes = 4096; - if (HttpQueryInfo (request, HTTP_QUERY_RAW_HEADERS_CRLF, buffer.getData(), &bufferSizeBytes, 0)) + for (;;) { - StringArray headersArray; - headersArray.addLines (String (reinterpret_cast (buffer.getData()))); + HeapBlock buffer ((size_t) bufferSizeBytes); - for (int i = 0; i < headersArray.size(); ++i) + if (HttpQueryInfo (request, HTTP_QUERY_RAW_HEADERS_CRLF, buffer.getData(), &bufferSizeBytes, 0)) { - const String& header = headersArray[i]; - const String key (header.upToFirstOccurrenceOf (": ", false, false)); - const String value (header.fromFirstOccurrenceOf (": ", false, false)); - const String previousValue ((*responseHeaders) [key]); + StringArray headersArray; + headersArray.addLines (String (reinterpret_cast (buffer.getData()))); - responseHeaders->set (key, previousValue.isEmpty() ? value : (previousValue + "," + value)); + for (int i = 0; i < headersArray.size(); ++i) + { + const String& header = headersArray[i]; + const String key (header.upToFirstOccurrenceOf (": ", false, false)); + const String value (header.fromFirstOccurrenceOf (": ", false, false)); + const String previousValue ((*responseHeaders) [key]); + + responseHeaders->set (key, previousValue.isEmpty() ? value : (previousValue + "," + value)); + } + + break; } - break; + if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) + break; } - - if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) - break; } + + DWORD status = 0; + DWORD statusSize = sizeof (status); + + if (HttpQueryInfo (request, HTTP_QUERY_STATUS_CODE | HTTP_QUERY_FLAG_NUMBER, &status, &statusSize, 0)) + statusCode = (int) status; } } @@ -145,6 +154,8 @@ public: return true; } + int statusCode; + private: //============================================================================== HINTERNET connection, request; @@ -305,17 +316,6 @@ private: JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (WebInputStream) }; -InputStream* URL::createNativeStream (const String& address, bool isPost, const MemoryBlock& postData, - OpenStreamProgressCallback* progressCallback, void* progressCallbackContext, - const String& headers, const int timeOutMs, StringPairArray* responseHeaders) -{ - ScopedPointer wi (new WebInputStream (address, isPost, postData, - progressCallback, progressCallbackContext, - headers, timeOutMs, responseHeaders)); - - return wi->isError() ? nullptr : wi.release(); -} - //============================================================================== struct GetAdaptersInfoHelper diff --git a/modules/juce_core/network/juce_URL.cpp b/modules/juce_core/network/juce_URL.cpp index 535fe81680..c957e91a68 100644 --- a/modules/juce_core/network/juce_URL.cpp +++ b/modules/juce_core/network/juce_URL.cpp @@ -330,7 +330,8 @@ InputStream* URL::createInputStream (const bool usePostCommand, void* const progressCallbackContext, String headers, const int timeOutMs, - StringPairArray* const responseHeaders) const + StringPairArray* const responseHeaders, + int* statusCode) const { MemoryBlock headersAndPostData; @@ -343,9 +344,15 @@ InputStream* URL::createInputStream (const bool usePostCommand, if (! headers.endsWithChar ('\n')) headers << "\r\n"; - return createNativeStream (toString (! usePostCommand), usePostCommand, headersAndPostData, - progressCallback, progressCallbackContext, - headers, timeOutMs, responseHeaders); + ScopedPointer wi (new WebInputStream (toString (! usePostCommand), + usePostCommand, headersAndPostData, + progressCallback, progressCallbackContext, + headers, timeOutMs, responseHeaders)); + + if (statusCode != nullptr) + *statusCode = wi->statusCode; + + return wi->isError() ? nullptr : wi.release(); } //============================================================================== diff --git a/modules/juce_core/network/juce_URL.h b/modules/juce_core/network/juce_URL.h index 8b8db265c1..ce7676b275 100644 --- a/modules/juce_core/network/juce_URL.h +++ b/modules/juce_core/network/juce_URL.h @@ -247,8 +247,10 @@ public: @param connectionTimeOutMs if 0, this will use whatever default setting the OS chooses. If a negative number, it will be infinite. Otherwise it specifies a time in milliseconds. - @param responseHeaders if this is non-zero, all the (key, value) pairs received as headers + @param responseHeaders if this is non-null, all the (key, value) pairs received as headers in the response will be stored in this array + @param statusCode if this is non-null, it will get set to the http status code, if one + is known, or 0 if a code isn't available @returns an input stream that the caller must delete, or a null pointer if there was an error trying to open it. */ @@ -257,7 +259,8 @@ public: void* progressCallbackContext = nullptr, String extraHeaders = String(), int connectionTimeOutMs = 0, - StringPairArray* responseHeaders = nullptr) const; + StringPairArray* responseHeaders = nullptr, + int* statusCode = nullptr) const; //============================================================================== @@ -345,10 +348,6 @@ private: URL (const String&, int); void addParameter (const String&, const String&); - static InputStream* createNativeStream (const String& address, bool isPost, const MemoryBlock& postData, - OpenStreamProgressCallback* progressCallback, - void* progressCallbackContext, const String& headers, - const int timeOutMs, StringPairArray* responseHeaders); JUCE_LEAK_DETECTOR (URL) };