Skip to content

Commit

Permalink
feat(redirect): handle the case of redirect on filedownloader self
Browse files Browse the repository at this point in the history
Closes #611
  • Loading branch information
Jacksgong committed Jun 22, 2017
1 parent f40aebd commit 6325df8
Show file tree
Hide file tree
Showing 3 changed files with 145 additions and 3 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
/*
* Copyright (c) 2015 LingoChamp Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.liulishuo.filedownloader.connection;

import com.liulishuo.filedownloader.download.CustomComponentHolder;
import com.liulishuo.filedownloader.util.FileDownloadLog;
import com.liulishuo.filedownloader.util.FileDownloadUtils;

import java.io.IOException;
import java.net.HttpURLConnection;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
* Handle redirect case.
*/
public class RedirectHandler {

private final static int MAX_REDIRECT_TIMES = 10;

/**
* The target resource resides temporarily under a different URI and the user agent MUST NOT
* change the request method if it performs an automatic redirection to that URI.
*/
private final static int HTTP_TEMPORARY_REDIRECT = 307;
/**
* The target resource has been assigned a new permanent URI and any future references to this
* resource ought to use one of the enclosed URIs.
*/
private final static int HTTP_PERMANENT_REDIRECT = 308;


public static FileDownloadConnection process(final Map<String, List<String>> requestHeaderFields,
final FileDownloadConnection connection,
List<String> redirectedUrlList)
throws IOException, IllegalAccessException {

int code = connection.getResponseCode();
String location = connection.getResponseHeaderField("Location");

List<String> redirectLocationList = new ArrayList<>();
int redirectTimes = 0;
FileDownloadConnection redirectConnection = connection;

while (isRedirect(code)) {
if (location == null) {
throw new IllegalAccessException(FileDownloadUtils.
formatString("receive %d (redirect) but the location is null with response [%s]",
code, redirectConnection.getResponseHeaderFields()));
}

if (FileDownloadLog.NEED_LOG) {
FileDownloadLog.d(RedirectHandler.class, "redirect to %s with %d, %s",
location, code, redirectLocationList);
}

redirectConnection =
buildRedirectConnection(requestHeaderFields, location);
redirectLocationList.add(location);

if (redirectConnection != null) redirectConnection.ending();

redirectConnection.execute();
code = redirectConnection.getResponseCode();
location = redirectConnection.getResponseHeaderField("Location");

if (++redirectTimes >= MAX_REDIRECT_TIMES) {
throw new IllegalAccessException(
FileDownloadUtils.formatString("redirect too many times! %s", redirectLocationList));
}
}

if (redirectedUrlList != null) {
redirectedUrlList.addAll(redirectLocationList);
}

return redirectConnection;
}

private static boolean isRedirect(int code) {
return code == HttpURLConnection.HTTP_MOVED_PERM
|| code == HttpURLConnection.HTTP_MOVED_TEMP
|| code == HttpURLConnection.HTTP_SEE_OTHER
|| code == HttpURLConnection.HTTP_MULT_CHOICE
|| code == HTTP_TEMPORARY_REDIRECT
|| code == HTTP_PERMANENT_REDIRECT;
}

private static FileDownloadConnection buildRedirectConnection(Map<String, List<String>> requestHeaderFields,
String newUrl) throws IOException {
FileDownloadConnection redirectConnection = CustomComponentHolder.getImpl().
createConnection(newUrl);

String name;
List<String> list;

Set<Map.Entry<String, List<String>>> entries = requestHeaderFields.entrySet();
for (Map.Entry<String, List<String>> e : entries) {
name = e.getKey();
list = e.getValue();
if (list != null) {
for (String value : list) {
redirectConnection.addHeader(name, value);
}
}
}

return redirectConnection;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,13 @@
import android.text.TextUtils;

import com.liulishuo.filedownloader.connection.FileDownloadConnection;
import com.liulishuo.filedownloader.connection.RedirectHandler;
import com.liulishuo.filedownloader.model.FileDownloadHeader;
import com.liulishuo.filedownloader.util.FileDownloadLog;
import com.liulishuo.filedownloader.util.FileDownloadUtils;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
Expand All @@ -42,6 +44,7 @@ public class ConnectTask {
private String etag;

private Map<String, List<String>> requestHeader;
private List<String> redirectedUrlList;


private ConnectTask(ConnectionProfile profile,
Expand All @@ -53,8 +56,8 @@ private ConnectTask(ConnectionProfile profile,
this.profile = profile;
}

FileDownloadConnection connect() throws IOException {
final FileDownloadConnection connection = CustomComponentHolder.getImpl().createConnection(url);
FileDownloadConnection connect() throws IOException, IllegalAccessException {
FileDownloadConnection connection = CustomComponentHolder.getImpl().createConnection(url);

addUserRequiredHeader(connection);
addRangeHeader(connection);
Expand All @@ -69,6 +72,8 @@ FileDownloadConnection connect() throws IOException {
}

connection.execute();
redirectedUrlList = new ArrayList<>();
connection = RedirectHandler.process(requestHeader, connection, redirectedUrlList);

return connection;
}
Expand Down Expand Up @@ -123,6 +128,14 @@ boolean isRangeNotFromBeginning(){
return profile.currentOffset > 0;
}

String getFinalRedirectedUrl() {
if (redirectedUrlList != null && !redirectedUrlList.isEmpty()) {
return redirectedUrlList.get(redirectedUrlList.size() - 1);
}

return null;
}

public Map<String, List<String>> getRequestHeader() {
return requestHeader;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,8 @@ public class DownloadLaunchRunnable implements Runnable, ProcessCallback {
private volatile boolean alive;
private volatile boolean paused;

private String redirectedUrl;

private DownloadLaunchRunnable(FileDownloadModel model, FileDownloadHeader header,
IThreadPoolMonitor threadPoolMonitor,
final int minIntervalMillis, int callbackProgressMaxCount,
Expand Down Expand Up @@ -458,6 +460,7 @@ private void handleFirstConnected(Map<String, List<String>> requestHeader,
throw new RetryDirectly();
}

redirectedUrl = connectTask.getFinalRedirectedUrl();
if (acceptPartial || onlyFromBeginning) {
final long contentLength = FileDownloadUtils.findContentLength(id, connection);

Expand Down Expand Up @@ -548,7 +551,7 @@ private void fetchWithMultipleConnectionFromBeginning(final long totalLength, fi
private void fetchWithMultipleConnection(final List<ConnectionModel> connectionModelList) throws InterruptedException {
final int id = model.getId();
final String etag = model.getETag();
final String url = model.getUrl();
final String url = redirectedUrl != null ? redirectedUrl : model.getUrl();
final String path = model.getTempFilePath();

if (FileDownloadLog.NEED_LOG) {
Expand Down

0 comments on commit 6325df8

Please sign in to comment.