1
0
Fork 0
mirror of https://github.com/juce-framework/JUCE.git synced 2026-01-26 02:14:22 +00:00

Android: fix HTTP redirect.

This commit is contained in:
Lukasz Kozakiewicz 2017-08-30 18:03:57 +01:00
parent 7316128918
commit 8e7b29b3ee
2 changed files with 163 additions and 94 deletions

View file

@ -899,13 +899,74 @@ public class JuceAppActivity extends Activity
//==============================================================================
public static class HTTPStream
{
public HTTPStream (HttpURLConnection connection_,
int[] statusCode_,
StringBuffer responseHeaders_)
public HTTPStream (String address, boolean isPostToUse, byte[] postDataToUse,
String headersToUse, int timeOutMsToUse,
int[] statusCodeToUse, StringBuffer responseHeadersToUse,
int numRedirectsToFollowToUse, String httpRequestCmdToUse) throws IOException
{
connection = connection_;
statusCode = statusCode_;
responseHeaders = responseHeaders_;
isPost = isPostToUse;
postData = postDataToUse;
headers = headersToUse;
timeOutMs = timeOutMsToUse;
statusCode = statusCodeToUse;
responseHeaders = responseHeadersToUse;
numRedirectsToFollow = numRedirectsToFollowToUse;
httpRequestCmd = httpRequestCmdToUse;
connection = createConnection (address, isPost, postData, headers, timeOutMs, httpRequestCmd);
}
private final HttpURLConnection createConnection (String address, boolean isPost, byte[] postData,
String headers, int timeOutMs, String httpRequestCmdToUse) throws IOException
{
HttpURLConnection newConnection = (HttpURLConnection) (new URL(address).openConnection());
try
{
newConnection.setInstanceFollowRedirects (false);
newConnection.setConnectTimeout (timeOutMs);
newConnection.setReadTimeout (timeOutMs);
// 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");
// 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)
newConnection.setRequestProperty (field, value);
}
}
newConnection.setRequestMethod (httpRequestCmd);
if (isPost)
{
newConnection.setDoOutput (true);
if (postData != null)
{
OutputStream out = newConnection.getOutputStream();
out.write(postData);
out.flush();
}
}
return newConnection;
}
catch (Throwable e)
{
newConnection.disconnect();
throw new IOException ("Connection error");
}
}
private final InputStream getCancellableStream (final boolean isInput) throws ExecutionException
@ -928,19 +989,12 @@ public class JuceAppActivity extends Activity
try
{
if (connection.getConnectTimeout() > 0)
return streamFuture.get (connection.getConnectTimeout(), TimeUnit.MILLISECONDS);
else
return streamFuture.get();
return streamFuture.get();
}
catch (InterruptedException e)
{
return null;
}
catch (TimeoutException e)
{
return null;
}
catch (CancellationException e)
{
return null;
@ -948,6 +1002,89 @@ public class JuceAppActivity extends Activity
}
public final boolean connect()
{
boolean result = false;
int numFollowedRedirects = 0;
while (true)
{
result = doConnect();
if (! result)
return false;
if (++numFollowedRedirects > numRedirectsToFollow)
break;
int status = statusCode[0];
if (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 currentLocation = connection.getURL().toString();
String newLocation = responseHeaders.substring (pos1, pos2);
try
{
// Handle newLocation whether it's absolute or relative
URL baseUrl = new URL (currentLocation);
URL newUrl = new URL (baseUrl, newLocation);
String transformedNewLocation = newUrl.toString();
if (transformedNewLocation != currentLocation)
{
// Clear responseHeaders before next iteration
responseHeaders.delete (0, responseHeaders.length());
synchronized (createStreamLock)
{
if (hasBeenCancelled.get())
return false;
connection.disconnect();
try
{
connection = createConnection (transformedNewLocation, isPost,
postData, headers, timeOutMs,
httpRequestCmd);
}
catch (Throwable e)
{
return false;
}
}
}
else
{
break;
}
}
catch (Throwable e)
{
return false;
}
}
else
{
break;
}
}
else
{
break;
}
}
return result;
}
private final boolean doConnect()
{
synchronized (createStreamLock)
{
@ -1094,9 +1231,15 @@ public class JuceAppActivity extends Activity
public final boolean isExhausted() { return false; }
public final boolean setPosition (long newPos) { return false; }
private boolean isPost;
private byte[] postData;
private String headers;
private int timeOutMs;
String httpRequestCmd;
private HttpURLConnection connection;
private int[] statusCode;
private StringBuffer responseHeaders;
private int numRedirectsToFollow;
private InputStream inputStream;
private long position;
private final ReentrantLock createStreamLock = new ReentrantLock();
@ -1118,89 +1261,15 @@ public class JuceAppActivity extends Activity
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 (;;)
{
try
{
HttpURLConnection connection = (HttpURLConnection) (new URL(address).openConnection());
HTTPStream httpStream = new HTTPStream (address, isPost, postData, headers,
timeOutMs, statusCode, responseHeaders,
numRedirectsToFollow, httpRequestCmd);
if (connection != null)
{
try
{
connection.setInstanceFollowRedirects (false);
connection.setConnectTimeout (timeOutMs);
connection.setReadTimeout (timeOutMs);
// 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);
}
}
connection.setRequestMethod (httpRequestCmd);
if (isPost)
{
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();
}
}
return httpStream;
}
catch (Throwable e) {}