Skip to content

Commit

Permalink
✨ Support for redirection
Browse files Browse the repository at this point in the history
  • Loading branch information
Flyge committed Oct 1, 2017
1 parent a216978 commit f54a9d8
Show file tree
Hide file tree
Showing 6 changed files with 84 additions and 12 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ static void decodeSuccess(@NonNull Bitmap bitmap, int outWidth, int outHeight, i
}
}

static void decodeError(LoadRequest loadRequest, DataSource dataSource, String logName, String cause, Throwable tr) {
static void decodeError(LoadRequest request, DataSource dataSource, String logName, String cause, Throwable tr) {
if (tr != null) {
SLog.e(logName, Log.getStackTraceString(tr));
}
Expand All @@ -112,17 +112,17 @@ static void decodeError(LoadRequest loadRequest, DataSource dataSource, String l
DiskCache.Entry diskCacheEntry = ((DiskCacheDataSource) dataSource).getDiskCacheEntry();
File cacheFile = diskCacheEntry.getFile();
if (diskCacheEntry.delete()) {
SLog.e(logName, "Decode failed. %s. Disk cache deleted. fileLength=%d. %s", cause, cacheFile.length(), loadRequest.getKey(), tr);
SLog.e(logName, "Decode failed. %s. Disk cache deleted. fileLength=%d. %s", cause, cacheFile.length(), request.getKey(), tr);
} else {
SLog.e(logName, "Decode failed. %s. Disk cache can not be deleted. fileLength=%d. %s", cause, cacheFile.length(), loadRequest.getKey());
SLog.e(logName, "Decode failed. %s. Disk cache can not be deleted. fileLength=%d. %s", cause, cacheFile.length(), request.getKey());
}
} else if (dataSource instanceof FileDataSource) {
File file = ((FileDataSource) dataSource).getFile(null, null);
//noinspection ConstantConditions
SLog.e(logName, "Decode failed. %s. filePath=%s, fileLength=%d. %s",
cause, file.getPath(), file.exists() ? file.length() : -1);
cause, file.getPath(), file.exists() ? file.length() : -1, request.getKey());
} else {
SLog.e(logName, "Decode failed. %s. %s", cause, loadRequest.getUri());
SLog.e(logName, "Decode failed. %s. %s", cause, request.getUri());
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,11 @@ public DecodeResult decode(@NonNull LoadRequest request) throws DecodeException
}

return result;
} catch (DecodeException e) {
if (result != null) {
result.recycle(request.getConfiguration().getBitmapPool());
}
throw e;
} catch (Throwable tr) {
if (result != null) {
result.recycle(request.getConfiguration().getBitmapPool());
Expand Down
6 changes: 6 additions & 0 deletions sketch/src/main/java/me/xiaopan/sketch/http/HttpStack.java
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,12 @@ interface ImageHttpResponse {
*/
boolean isContentChunked();

/**
* 获取响应头
*/
@Nullable
String getResponseHeader(@NonNull String name);

/**
* 获取所有的响应头
*/
Expand Down
7 changes: 7 additions & 0 deletions sketch/src/main/java/me/xiaopan/sketch/http/HurlStack.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

import android.os.Build;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;

import java.io.IOException;
import java.io.InputStream;
Expand Down Expand Up @@ -243,5 +244,11 @@ public boolean isContentChunked() {
}
return transferEncodingValue != null && "chunked".equalsIgnoreCase(transferEncodingValue);
}

@Nullable
@Override
public String getResponseHeader(@NonNull String name) {
return connection.getHeaderField(name);
}
}
}
36 changes: 29 additions & 7 deletions sketch/src/main/java/me/xiaopan/sketch/http/ImageDownloader.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
package me.xiaopan.sketch.http;

import android.support.annotation.NonNull;
import android.text.TextUtils;

import java.io.BufferedOutputStream;
import java.io.ByteArrayOutputStream;
Expand Down Expand Up @@ -102,9 +103,12 @@ private DownloadResult loopRetryDownload(@NonNull DownloadRequest request, @NonN
HttpStack httpStack = request.getConfiguration().getHttpStack();
int retryCount = 0;
final int maxRetryCount = httpStack.getMaxRetryCount();
String uri = request.getUri();
while (true) {
try {
return doDownload(request, httpStack, diskCache, diskCacheKey);
return doDownload(request, uri, httpStack, diskCache, diskCacheKey);
} catch (RedirectsException e) {
uri = e.getNewUrl();
} catch (Throwable tr) {
request.getConfiguration().getErrorTracker().onDownloadError(request, tr);

Expand Down Expand Up @@ -136,6 +140,7 @@ private DownloadResult loopRetryDownload(@NonNull DownloadRequest request, @NonN
* Real execute download
*
* @param request DownloadRequest
* @param uri image uri
* @param httpStack HttpStack
* @param diskCache DiskCache
* @param diskCacheKey disk cache key
Expand All @@ -145,15 +150,15 @@ private DownloadResult loopRetryDownload(@NonNull DownloadRequest request, @NonN
* @throws DownloadException download failed
*/
@NonNull
private DownloadResult doDownload(@NonNull DownloadRequest request, @NonNull HttpStack httpStack,
private DownloadResult doDownload(@NonNull DownloadRequest request, @NonNull String uri, @NonNull HttpStack httpStack,
@NonNull DiskCache diskCache, @NonNull String diskCacheKey)
throws IOException, CanceledException, DownloadException {
throws IOException, CanceledException, DownloadException, RedirectsException {
// Opening http connection
request.setStatus(BaseRequest.Status.CONNECTING);
HttpStack.ImageHttpResponse httpResponse;
//noinspection CaughtExceptionImmediatelyRethrown
try {
httpResponse = httpStack.getHttpResponse(request.getUri());
httpResponse = httpStack.getHttpResponse(uri);
} catch (IOException e) {
throw e;
}
Expand All @@ -180,6 +185,25 @@ private DownloadResult doDownload(@NonNull DownloadRequest request, @NonNull Htt
}
if (responseCode != 200) {
httpResponse.releaseConnection();

// redirects
if (responseCode == 301 || responseCode == 302) {
String newUri = httpResponse.getResponseHeader("Location");
if (!TextUtils.isEmpty(newUri)) {
// To prevent infinite redirection
if (uri.equals(request.getUri())) {
if (SLog.isLoggable(SLog.LEVEL_DEBUG | SLog.TYPE_FLOW)) {
SLog.d(NAME, "Uri redirects. originUri: %s, newUri: %s. %s", request.getUri(), newUri, request.getKey());
}
throw new RedirectsException(newUri);
} else {
SLog.e(NAME, "Disable unlimited redirects, originUri: %s, redirectsUri=%s, newUri=%s. %s", request.getUri(), uri, newUri, request.getKey());
}
} else {
SLog.w(NAME, "Uri redirects failed. newUri is empty, originUri: %s. %s", request.getUri(), request.getKey());
}
}

String message = String.format("Response code exception. responseHeaders: %s. %s. %s",
httpResponse.getResponseHeadersString(), request.getThreadName(), request.getKey());
SLog.e(NAME, message);
Expand Down Expand Up @@ -236,21 +260,19 @@ private DownloadResult doDownload(@NonNull DownloadRequest request, @NonNull Htt

// Read data
request.setStatus(BaseRequest.Status.READ_DATA);
int completedLength = 0;
int completedLength;
try {
completedLength = readData(request, inputStream, outputStream, (int) contentLength);
} catch (IOException e) {
if (diskCacheEditor != null) {
diskCacheEditor.abort();
diskCacheEditor = null;
}
String message = String.format("Read data exception. %s. %s", request.getThreadName(), request.getKey());
SLog.e(NAME, e, message);
throw new DownloadException(message, e, ErrorCause.DOWNLOAD_READ_DATA_EXCEPTION);
} catch (CanceledException e) {
if (diskCacheEditor != null) {
diskCacheEditor.abort();
diskCacheEditor = null;
}
throw e;
} finally {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/*
* Copyright (C) 2017 Peng fei Pan <sky@xiaopan.me>
*
* 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 me.xiaopan.sketch.http;

import android.support.annotation.NonNull;

public class RedirectsException extends Exception {
private String newUrl;

public RedirectsException(@NonNull String newUrl) {
this.newUrl = newUrl;
}

@NonNull
public String getNewUrl() {
return newUrl;
}
}

0 comments on commit f54a9d8

Please sign in to comment.