Browse Source

Added a number-of-redirects parameter to URL::createInputStream

tags/2021-05-28
jules 10 years ago
parent
commit
268497e8bc
10 changed files with 279 additions and 96 deletions
  1. +88
    -23
      examples/Demo/Builds/Android/src/com/juce/jucedemo/JuceDemo.java
  2. +4
    -0
      examples/Demo/JuceLibraryCode/AppConfig.h
  3. +88
    -23
      modules/juce_core/native/java/JuceAppActivity.java
  4. +1
    -1
      modules/juce_core/native/juce_android_JNIHelpers.h
  5. +3
    -2
      modules/juce_core/native/juce_android_Network.cpp
  6. +35
    -27
      modules/juce_core/native/juce_linux_Network.cpp
  7. +35
    -13
      modules/juce_core/native/juce_mac_Network.mm
  8. +17
    -4
      modules/juce_core/native/juce_win32_Network.cpp
  9. +4
    -2
      modules/juce_core/network/juce_URL.cpp
  10. +4
    -1
      modules/juce_core/network/juce_URL.h

+ 88
- 23
examples/Demo/Builds/Android/src/com/juce/jucedemo/JuceDemo.java View File

@@ -666,38 +666,103 @@ public final class JuceDemo extends Activity
public static final HTTPStream createHTTPStream (String address, public static final HTTPStream createHTTPStream (String address,
boolean isPost, byte[] postData, String headers, boolean isPost, byte[] postData, String headers,
int timeOutMs, int[] statusCode, int timeOutMs, int[] statusCode,
StringBuffer responseHeaders)
StringBuffer responseHeaders,
int numRedirectsToFollow)
{ {
try
// timeout parameter of zero for HttpUrlConnection is a blocking connect (negative value for juce::URL)
if (timeOutMs < 0)
timeOutMs = 0;
else if (timeOutMs == 0)
timeOutMs = 30000;
// headers - if not empty, this string is appended onto the headers that are used for the request. It must therefore be a valid set of HTML header directives, separated by newlines.
// So convert headers string to an array, with an element for each line
String headerLines[] = headers.split("\\n");
for (;;)
{ {
HttpURLConnection connection = (HttpURLConnection) (new URL(address)
.openConnection());
if (connection != null)
try
{ {
try
HttpURLConnection connection = (HttpURLConnection) (new URL(address).openConnection());
if (connection != null)
{ {
if (isPost)
try
{ {
connection.setRequestMethod("POST");
connection.setConnectTimeout(timeOutMs);
connection.setDoOutput(true);
connection.setChunkedStreamingMode(0);
OutputStream out = connection.getOutputStream();
out.write(postData);
out.flush();
}
connection.setInstanceFollowRedirects (false);
connection.setConnectTimeout (timeOutMs);
connection.setReadTimeout (timeOutMs);
return new HTTPStream (connection, statusCode, responseHeaders);
}
catch (Throwable e)
{
connection.disconnect();
// Set request headers
for (int i = 0; i < headerLines.length; ++i)
{
int pos = headerLines[i].indexOf (":");
if (pos > 0 && pos < headerLines[i].length())
{
String field = headerLines[i].substring (0, pos);
String value = headerLines[i].substring (pos + 1);
if (value.length() > 0)
connection.setRequestProperty (field, value);
}
}
if (isPost)
{
connection.setRequestMethod ("POST");
connection.setDoOutput (true);
if (postData != null)
{
OutputStream out = connection.getOutputStream();
out.write(postData);
out.flush();
}
}
HTTPStream httpStream = new HTTPStream (connection, statusCode, responseHeaders);
// Process redirect & continue as necessary
int status = statusCode[0];
if (--numRedirectsToFollow >= 0
&& (status == 301 || status == 302 || status == 303 || status == 307))
{
// Assumes only one occurrence of "Location"
int pos1 = responseHeaders.indexOf ("Location:") + 10;
int pos2 = responseHeaders.indexOf ("\n", pos1);
if (pos2 > pos1)
{
String newLocation = responseHeaders.substring(pos1, pos2);
// Handle newLocation whether it's absolute or relative
URL baseUrl = new URL (address);
URL newUrl = new URL (baseUrl, newLocation);
String transformedNewLocation = newUrl.toString();
if (transformedNewLocation != address)
{
address = transformedNewLocation;
// Clear responseHeaders before next iteration
responseHeaders.delete (0, responseHeaders.length());
continue;
}
}
}
return httpStream;
}
catch (Throwable e)
{
connection.disconnect();
}
} }
} }
}
catch (Throwable e) {}
catch (Throwable e) {}
return null;
return null;
}
} }
public final void launchURL (String url) public final void launchURL (String url)


+ 4
- 0
examples/Demo/JuceLibraryCode/AppConfig.h View File

@@ -53,6 +53,10 @@ extern bool juceDemoRepaintDebuggingActive;
//#define JUCE_WASAPI //#define JUCE_WASAPI
#endif #endif
#ifndef JUCE_WASAPI_EXCLUSIVE
//#define JUCE_WASAPI_EXCLUSIVE
#endif
#ifndef JUCE_DIRECTSOUND #ifndef JUCE_DIRECTSOUND
//#define JUCE_DIRECTSOUND //#define JUCE_DIRECTSOUND
#endif #endif


+ 88
- 23
modules/juce_core/native/java/JuceAppActivity.java View File

@@ -666,38 +666,103 @@ public final class JuceAppActivity extends Activity
public static final HTTPStream createHTTPStream (String address, public static final HTTPStream createHTTPStream (String address,
boolean isPost, byte[] postData, String headers, boolean isPost, byte[] postData, String headers,
int timeOutMs, int[] statusCode, int timeOutMs, int[] statusCode,
StringBuffer responseHeaders)
StringBuffer responseHeaders,
int numRedirectsToFollow)
{ {
try
// timeout parameter of zero for HttpUrlConnection is a blocking connect (negative value for juce::URL)
if (timeOutMs < 0)
timeOutMs = 0;
else if (timeOutMs == 0)
timeOutMs = 30000;
// headers - if not empty, this string is appended onto the headers that are used for the request. It must therefore be a valid set of HTML header directives, separated by newlines.
// So convert headers string to an array, with an element for each line
String headerLines[] = headers.split("\\n");
for (;;)
{ {
HttpURLConnection connection = (HttpURLConnection) (new URL(address)
.openConnection());
if (connection != null)
try
{ {
try
HttpURLConnection connection = (HttpURLConnection) (new URL(address).openConnection());
if (connection != null)
{ {
if (isPost)
try
{ {
connection.setRequestMethod("POST");
connection.setConnectTimeout(timeOutMs);
connection.setDoOutput(true);
connection.setChunkedStreamingMode(0);
OutputStream out = connection.getOutputStream();
out.write(postData);
out.flush();
}
connection.setInstanceFollowRedirects (false);
connection.setConnectTimeout (timeOutMs);
connection.setReadTimeout (timeOutMs);
return new HTTPStream (connection, statusCode, responseHeaders);
}
catch (Throwable e)
{
connection.disconnect();
// Set request headers
for (int i = 0; i < headerLines.length; ++i)
{
int pos = headerLines[i].indexOf (":");
if (pos > 0 && pos < headerLines[i].length())
{
String field = headerLines[i].substring (0, pos);
String value = headerLines[i].substring (pos + 1);
if (value.length() > 0)
connection.setRequestProperty (field, value);
}
}
if (isPost)
{
connection.setRequestMethod ("POST");
connection.setDoOutput (true);
if (postData != null)
{
OutputStream out = connection.getOutputStream();
out.write(postData);
out.flush();
}
}
HTTPStream httpStream = new HTTPStream (connection, statusCode, responseHeaders);
// Process redirect & continue as necessary
int status = statusCode[0];
if (--numRedirectsToFollow >= 0
&& (status == 301 || status == 302 || status == 303 || status == 307))
{
// Assumes only one occurrence of "Location"
int pos1 = responseHeaders.indexOf ("Location:") + 10;
int pos2 = responseHeaders.indexOf ("\n", pos1);
if (pos2 > pos1)
{
String newLocation = responseHeaders.substring(pos1, pos2);
// Handle newLocation whether it's absolute or relative
URL baseUrl = new URL (address);
URL newUrl = new URL (baseUrl, newLocation);
String transformedNewLocation = newUrl.toString();
if (transformedNewLocation != address)
{
address = transformedNewLocation;
// Clear responseHeaders before next iteration
responseHeaders.delete (0, responseHeaders.length());
continue;
}
}
}
return httpStream;
}
catch (Throwable e)
{
connection.disconnect();
}
} }
} }
}
catch (Throwable e) {}
catch (Throwable e) {}
return null;
return null;
}
} }
public final void launchURL (String url) public final void launchURL (String url)


+ 1
- 1
modules/juce_core/native/juce_android_JNIHelpers.h View File

@@ -378,7 +378,7 @@ struct AndroidThreadScope
METHOD (setClipboardContent, "setClipboardContent", "(Ljava/lang/String;)V") \ METHOD (setClipboardContent, "setClipboardContent", "(Ljava/lang/String;)V") \
METHOD (excludeClipRegion, "excludeClipRegion", "(Landroid/graphics/Canvas;FFFF)V") \ METHOD (excludeClipRegion, "excludeClipRegion", "(Landroid/graphics/Canvas;FFFF)V") \
METHOD (renderGlyph, "renderGlyph", "(CLandroid/graphics/Paint;Landroid/graphics/Matrix;Landroid/graphics/Rect;)[I") \ METHOD (renderGlyph, "renderGlyph", "(CLandroid/graphics/Paint;Landroid/graphics/Matrix;Landroid/graphics/Rect;)[I") \
STATICMETHOD (createHTTPStream, "createHTTPStream", "(Ljava/lang/String;Z[BLjava/lang/String;I[ILjava/lang/StringBuffer;)L" JUCE_ANDROID_ACTIVITY_CLASSPATH "$HTTPStream;") \
STATICMETHOD (createHTTPStream, "createHTTPStream", "(Ljava/lang/String;Z[BLjava/lang/String;I[ILjava/lang/StringBuffer;I)L" JUCE_ANDROID_ACTIVITY_CLASSPATH "$HTTPStream;") \
METHOD (launchURL, "launchURL", "(Ljava/lang/String;)V") \ METHOD (launchURL, "launchURL", "(Ljava/lang/String;)V") \
METHOD (showMessageBox, "showMessageBox", "(Ljava/lang/String;Ljava/lang/String;J)V") \ METHOD (showMessageBox, "showMessageBox", "(Ljava/lang/String;Ljava/lang/String;J)V") \
METHOD (showOkCancelBox, "showOkCancelBox", "(Ljava/lang/String;Ljava/lang/String;J)V") \ METHOD (showOkCancelBox, "showOkCancelBox", "(Ljava/lang/String;Ljava/lang/String;J)V") \


+ 3
- 2
modules/juce_core/native/juce_android_Network.cpp View File

@@ -70,7 +70,7 @@ class WebInputStream : public InputStream
public: public:
WebInputStream (String address, bool isPost, const MemoryBlock& postData, WebInputStream (String address, bool isPost, const MemoryBlock& postData,
URL::OpenStreamProgressCallback* progressCallback, void* progressCallbackContext, URL::OpenStreamProgressCallback* progressCallback, void* progressCallbackContext,
const String& headers, int timeOutMs, StringPairArray* responseHeaders)
const String& headers, int timeOutMs, StringPairArray* responseHeaders, const int numRedirectsToFollow)
: statusCode (0) : statusCode (0)
{ {
if (! address.contains ("://")) if (! address.contains ("://"))
@@ -103,7 +103,8 @@ public:
javaString (headers).get(), javaString (headers).get(),
(jint) timeOutMs, (jint) timeOutMs,
statusCodeArray, statusCodeArray,
responseHeaderBuffer.get()));
responseHeaderBuffer.get(),
(jint) numRedirectsToFollow));
jint* const statusCodeElements = env->GetIntArrayElements (statusCodeArray, 0); jint* const statusCodeElements = env->GetIntArrayElements (statusCodeArray, 0);
statusCode = statusCodeElements[0]; statusCode = statusCodeElements[0];


+ 35
- 27
modules/juce_core/native/juce_linux_Network.cpp View File

@@ -74,12 +74,13 @@ class WebInputStream : public InputStream
public: public:
WebInputStream (const String& address_, bool isPost_, const MemoryBlock& postData_, WebInputStream (const String& address_, bool isPost_, const MemoryBlock& postData_,
URL::OpenStreamProgressCallback* progressCallback, void* progressCallbackContext, URL::OpenStreamProgressCallback* progressCallback, void* progressCallbackContext,
const String& headers_, int timeOutMs_, StringPairArray* responseHeaders)
const String& headers_, int timeOutMs_, StringPairArray* responseHeaders,
const int maxRedirects)
: statusCode (0), socketHandle (-1), levelsOfRedirection (0), : statusCode (0), socketHandle (-1), levelsOfRedirection (0),
address (address_), headers (headers_), postData (postData_), position (0), address (address_), headers (headers_), postData (postData_), position (0),
finished (false), isPost (isPost_), timeOutMs (timeOutMs_)
finished (false), isPost (isPost_), timeOutMs (timeOutMs_), numRedirectsToFollow (maxRedirects)
{ {
statusCode = createConnection (progressCallback, progressCallbackContext);
statusCode = createConnection (progressCallback, progressCallbackContext, numRedirectsToFollow);
if (responseHeaders != nullptr && ! isError()) if (responseHeaders != nullptr && ! isError())
{ {
@@ -147,7 +148,7 @@ public:
{ {
closeSocket(); closeSocket();
position = 0; position = 0;
statusCode = createConnection (0, 0);
statusCode = createConnection (0, 0, numRedirectsToFollow);
} }
skipNextBytes (wantedPos - position); skipNextBytes (wantedPos - position);
@@ -168,24 +169,27 @@ private:
bool finished; bool finished;
const bool isPost; const bool isPost;
const int timeOutMs; const int timeOutMs;
const int numRedirectsToFollow;
void closeSocket()
void closeSocket (bool resetLevelsOfRedirection = true)
{ {
if (socketHandle >= 0) if (socketHandle >= 0)
close (socketHandle); close (socketHandle);
socketHandle = -1; socketHandle = -1;
levelsOfRedirection = 0;
if (resetLevelsOfRedirection)
levelsOfRedirection = 0;
} }
int createConnection (URL::OpenStreamProgressCallback* progressCallback, void* progressCallbackContext)
int createConnection (URL::OpenStreamProgressCallback* progressCallback, void* progressCallbackContext,
const int numRedirectsToFollow)
{ {
closeSocket();
closeSocket (false);
uint32 timeOutTime = Time::getMillisecondCounter(); uint32 timeOutTime = Time::getMillisecondCounter();
if (timeOutMs == 0) if (timeOutMs == 0)
timeOutTime += 60000;
timeOutTime += 30000;
else if (timeOutMs < 0) else if (timeOutMs < 0)
timeOutTime = 0xffffffff; timeOutTime = 0xffffffff;
else else
@@ -273,28 +277,28 @@ private:
const int status = responseHeader.fromFirstOccurrenceOf (" ", false, false) const int status = responseHeader.fromFirstOccurrenceOf (" ", false, false)
.substring (0, 3).getIntValue(); .substring (0, 3).getIntValue();
//int contentLength = findHeaderItem (lines, "Content-Length:").getIntValue();
//bool isChunked = findHeaderItem (lines, "Transfer-Encoding:").equalsIgnoreCase ("chunked");
String location (findHeaderItem (headerLines, "Location:")); String location (findHeaderItem (headerLines, "Location:"));
if (status >= 300 && status < 400
if (++levelsOfRedirection <= numRedirectsToFollow
&& status >= 300 && status < 400
&& location.isNotEmpty() && location != address) && location.isNotEmpty() && location != address)
{ {
if (! location.startsWithIgnoreCase ("http://"))
location = "http://" + location;
if (++levelsOfRedirection <= 3)
if (! (location.startsWithIgnoreCase ("http://")
|| location.startsWithIgnoreCase ("https://")
|| location.startsWithIgnoreCase ("ftp://")))
{ {
address = location;
return createConnection (progressCallback, progressCallbackContext);
// The following is a bit dodgy. Ideally, we should do a proper transform of the relative URI to a target URI
if (location.startsWithChar ('/'))
location = URL (address).withNewSubPath (location).toString (true);
else
location = address + "/" + location;
} }
address = location;
return createConnection (progressCallback, progressCallbackContext, numRedirectsToFollow);
} }
else
{
levelsOfRedirection = 0;
return status;
}
return status;
} }
closeSocket(); closeSocket();
@@ -363,10 +367,14 @@ private:
writeValueIfNotPresent (header, userHeaders, "Connection:", "close"); writeValueIfNotPresent (header, userHeaders, "Connection:", "close");
if (isPost) if (isPost)
{
writeValueIfNotPresent (header, userHeaders, "Content-Length:", String ((int) postData.getSize())); writeValueIfNotPresent (header, userHeaders, "Content-Length:", String ((int) postData.getSize()));
header << "\r\n" << userHeaders
<< "\r\n" << postData;
header << userHeaders << "\r\n" << postData;
}
else
{
header << "\r\n" << userHeaders << "\r\n";
}
return header.getMemoryBlock(); return header.getMemoryBlock();
} }


+ 35
- 13
modules/juce_core/native/juce_mac_Network.mm View File

@@ -115,7 +115,7 @@ bool JUCE_CALLTYPE Process::openEmailWithAttachments (const String& targetEmailA
class URLConnectionState : public Thread class URLConnectionState : public Thread
{ {
public: public:
URLConnectionState (NSURLRequest* req)
URLConnectionState (NSURLRequest* req, const int maxRedirects)
: Thread ("http connection"), : Thread ("http connection"),
contentLength (-1), contentLength (-1),
delegate (nil), delegate (nil),
@@ -126,7 +126,9 @@ public:
statusCode (0), statusCode (0),
initialised (false), initialised (false),
hasFailed (false), hasFailed (false),
hasFinished (false)
hasFinished (false),
numRedirectsToFollow (maxRedirects),
numRedirects (0)
{ {
static DelegateClass cls; static DelegateClass cls;
delegate = [cls.createInstance() init]; delegate = [cls.createInstance() init];
@@ -215,6 +217,19 @@ public:
} }
} }
NSURLRequest* willSendRequest (NSURLRequest* newRequest, NSURLResponse* redirectResponse)
{
if (redirectResponse != nullptr)
{
if (numRedirects >= numRedirectsToFollow)
return nil; // Cancel redirect and allow connection to continue
++numRedirects;
}
return newRequest;
}
void didFailWithError (NSError* error) void didFailWithError (NSError* error)
{ {
DBG (nsStringToJuce ([error description])); (void) error; DBG (nsStringToJuce ([error description])); (void) error;
@@ -263,6 +278,8 @@ public:
NSDictionary* headers; NSDictionary* headers;
int statusCode; int statusCode;
bool initialised, hasFailed, hasFinished; bool initialised, hasFailed, hasFinished;
const int numRedirectsToFollow;
int numRedirects;
private: private:
//============================================================================== //==============================================================================
@@ -278,7 +295,7 @@ private:
addMethod (@selector (connection:didSendBodyData:totalBytesWritten:totalBytesExpectedToWrite:), addMethod (@selector (connection:didSendBodyData:totalBytesWritten:totalBytesExpectedToWrite:),
connectionDidSendBodyData, "v@:@iii"); connectionDidSendBodyData, "v@:@iii");
addMethod (@selector (connectionDidFinishLoading:), connectionDidFinishLoading, "v@:@"); addMethod (@selector (connectionDidFinishLoading:), connectionDidFinishLoading, "v@:@");
addMethod (@selector (connection:willSendRequest:redirectResponse:), willSendRequest, "@@:@@");
addMethod (@selector (connection:willSendRequest:redirectResponse:), willSendRequest, "@@:@@@");
registerClass(); registerClass();
} }
@@ -302,9 +319,9 @@ private:
getState (self)->didReceiveData (newData); getState (self)->didReceiveData (newData);
} }
static NSURLRequest* willSendRequest (id, SEL, NSURLConnection*, NSURLRequest* request, NSURLResponse*)
static NSURLRequest* willSendRequest (id self, SEL, NSURLConnection*, NSURLRequest* request, NSURLResponse* response)
{ {
return request;
return getState (self)->willSendRequest (request, response);
} }
static void connectionDidSendBodyData (id self, SEL, NSURLConnection*, NSInteger, NSInteger totalBytesWritten, NSInteger totalBytesExpected) static void connectionDidSendBodyData (id self, SEL, NSURLConnection*, NSInteger, NSInteger totalBytesWritten, NSInteger totalBytesExpected)
@@ -328,23 +345,27 @@ class WebInputStream : public InputStream
public: public:
WebInputStream (const String& address_, bool isPost_, const MemoryBlock& postData_, WebInputStream (const String& address_, bool isPost_, const MemoryBlock& postData_,
URL::OpenStreamProgressCallback* progressCallback, void* progressCallbackContext, URL::OpenStreamProgressCallback* progressCallback, void* progressCallbackContext,
const String& headers_, int timeOutMs_, StringPairArray* responseHeaders)
const String& headers_, int timeOutMs_, StringPairArray* responseHeaders,
const int numRedirectsToFollow_)
: statusCode (0), address (address_), headers (headers_), postData (postData_), position (0), : statusCode (0), address (address_), headers (headers_), postData (postData_), position (0),
finished (false), isPost (isPost_), timeOutMs (timeOutMs_)
finished (false), isPost (isPost_), timeOutMs (timeOutMs_), numRedirectsToFollow (numRedirectsToFollow_)
{ {
JUCE_AUTORELEASEPOOL JUCE_AUTORELEASEPOOL
{ {
createConnection (progressCallback, progressCallbackContext); createConnection (progressCallback, progressCallbackContext);
if (responseHeaders != nullptr && connection != nullptr && connection->headers != nil)
if (connection != nullptr && connection->headers != nil)
{ {
statusCode = connection->statusCode; statusCode = connection->statusCode;
NSEnumerator* enumerator = [connection->headers keyEnumerator];
if (responseHeaders != nullptr)
{
NSEnumerator* enumerator = [connection->headers keyEnumerator];
while (NSString* key = [enumerator nextObject])
responseHeaders->set (nsStringToJuce (key),
nsStringToJuce ((NSString*) [connection->headers objectForKey: key]));
while (NSString* key = [enumerator nextObject])
responseHeaders->set (nsStringToJuce (key),
nsStringToJuce ((NSString*) [connection->headers objectForKey: key]));
}
} }
} }
} }
@@ -403,6 +424,7 @@ private:
bool finished; bool finished;
const bool isPost; const bool isPost;
const int timeOutMs; const int timeOutMs;
const int numRedirectsToFollow;
void createConnection (URL::OpenStreamProgressCallback* progressCallback, void* progressCallbackContext) void createConnection (URL::OpenStreamProgressCallback* progressCallback, void* progressCallbackContext)
{ {
@@ -434,7 +456,7 @@ private:
[req setHTTPBody: [NSData dataWithBytes: postData.getData() [req setHTTPBody: [NSData dataWithBytes: postData.getData()
length: postData.getSize()]]; length: postData.getSize()]];
connection = new URLConnectionState (req);
connection = new URLConnectionState (req, numRedirectsToFollow);
if (! connection->start (progressCallback, progressCallbackContext)) if (! connection->start (progressCallback, progressCallbackContext))
connection = nullptr; connection = nullptr;


+ 17
- 4
modules/juce_core/native/juce_win32_Network.cpp View File

@@ -40,12 +40,12 @@ class WebInputStream : public InputStream
public: public:
WebInputStream (const String& address_, bool isPost_, const MemoryBlock& postData_, WebInputStream (const String& address_, bool isPost_, const MemoryBlock& postData_,
URL::OpenStreamProgressCallback* progressCallback, void* progressCallbackContext, URL::OpenStreamProgressCallback* progressCallback, void* progressCallbackContext,
const String& headers_, int timeOutMs_, StringPairArray* responseHeaders)
const String& headers_, int timeOutMs_, StringPairArray* responseHeaders, int numRedirectsToFollow)
: statusCode (0), connection (0), request (0), : statusCode (0), connection (0), request (0),
address (address_), headers (headers_), postData (postData_), position (0), address (address_), headers (headers_), postData (postData_), position (0),
finished (false), isPost (isPost_), timeOutMs (timeOutMs_) finished (false), isPost (isPost_), timeOutMs (timeOutMs_)
{ {
for (int maxRedirects = 10; --maxRedirects >= 0;)
while (numRedirectsToFollow-- >= 0)
{ {
createConnection (progressCallback, progressCallbackContext); createConnection (progressCallback, progressCallbackContext);
@@ -88,9 +88,22 @@ public:
{ {
statusCode = (int) status; statusCode = (int) status;
if (status == 301 || status == 302 || status == 303 || status == 307)
if (numRedirectsToFollow >= 0
&& (statusCode == 301 || statusCode == 302 || statusCode == 303 || statusCode == 307))
{ {
const String newLocation (headers["Location"]);
String newLocation (headers["Location"]);
// Check whether location is a relative URI - this is an incomplete test for relative path,
// but we'll use it for now (valid protocols for this implementation are http, https & ftp)
if (! (newLocation.startsWithIgnoreCase ("http://")
|| newLocation.startsWithIgnoreCase ("https://")
|| newLocation.startsWithIgnoreCase ("ftp://")))
{
if (newLocation.startsWithChar ('/'))
newLocation = URL (address).withNewSubPath (newLocation).toString (true);
else
newLocation = address + "/" + newLocation;
}
if (newLocation.isNotEmpty() && newLocation != address) if (newLocation.isNotEmpty() && newLocation != address)
{ {


+ 4
- 2
modules/juce_core/network/juce_URL.cpp View File

@@ -334,7 +334,8 @@ InputStream* URL::createInputStream (const bool usePostCommand,
String headers, String headers,
const int timeOutMs, const int timeOutMs,
StringPairArray* const responseHeaders, StringPairArray* const responseHeaders,
int* statusCode) const
int* statusCode,
const int numRedirectsToFollow) const
{ {
MemoryBlock headersAndPostData; MemoryBlock headersAndPostData;
@@ -350,7 +351,8 @@ InputStream* URL::createInputStream (const bool usePostCommand,
ScopedPointer<WebInputStream> wi (new WebInputStream (toString (! usePostCommand), ScopedPointer<WebInputStream> wi (new WebInputStream (toString (! usePostCommand),
usePostCommand, headersAndPostData, usePostCommand, headersAndPostData,
progressCallback, progressCallbackContext, progressCallback, progressCallbackContext,
headers, timeOutMs, responseHeaders));
headers, timeOutMs, responseHeaders,
numRedirectsToFollow));
if (statusCode != nullptr) if (statusCode != nullptr)
*statusCode = wi->statusCode; *statusCode = wi->statusCode;


+ 4
- 1
modules/juce_core/network/juce_URL.h View File

@@ -266,6 +266,8 @@ public:
in the response will be stored in this array 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 @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 is known, or 0 if a code isn't available
@param numRedirectsToFollow specifies the number of redirects that will be followed before
returning a response (ignored for Android which follows up to 5 redirects)
@returns an input stream that the caller must delete, or a null pointer if there was an @returns an input stream that the caller must delete, or a null pointer if there was an
error trying to open it. error trying to open it.
*/ */
@@ -275,7 +277,8 @@ public:
String extraHeaders = String(), String extraHeaders = String(),
int connectionTimeOutMs = 0, int connectionTimeOutMs = 0,
StringPairArray* responseHeaders = nullptr, StringPairArray* responseHeaders = nullptr,
int* statusCode = nullptr) const;
int* statusCode = nullptr,
int numRedirectsToFollow = 5) const;
//============================================================================== //==============================================================================


Loading…
Cancel
Save