From 2a5b81a6eafda5b9d78ad282f351c289f0847c45 Mon Sep 17 00:00:00 2001 From: Tianhua Ran Date: Sun, 11 Mar 2018 13:38:32 +0800 Subject: [PATCH 1/3] fix: cannot get content length during download connections should get content length from Content-Range if there is no Content-Length in the response during download connections close #967 --- .../com/liulishuo/filedownloader/util/FileDownloadUtils.java | 1 + 1 file changed, 1 insertion(+) diff --git a/library/src/main/java/com/liulishuo/filedownloader/util/FileDownloadUtils.java b/library/src/main/java/com/liulishuo/filedownloader/util/FileDownloadUtils.java index 9cc88193..97703478 100644 --- a/library/src/main/java/com/liulishuo/filedownloader/util/FileDownloadUtils.java +++ b/library/src/main/java/com/liulishuo/filedownloader/util/FileDownloadUtils.java @@ -578,6 +578,7 @@ public static long findInstanceLengthFromContentRange(FileDownloadConnection con public static long findContentLength(final int id, FileDownloadConnection connection) { long contentLength = FileDownloadUtils .convertContentLengthString(connection.getResponseHeaderField("Content-Length")); + if (contentLength < 0) contentLength = findInstanceLengthFromContentRange(connection); final String transferEncoding = connection.getResponseHeaderField("Transfer-Encoding"); if (contentLength < 0) { From d8f6cf16448321a8188e800de59f9e556b80aebb Mon Sep 17 00:00:00 2001 From: Tianhua Ran Date: Sun, 11 Mar 2018 15:05:55 +0800 Subject: [PATCH 2/3] fix: correct getting content length method and add unit test the length in Content-Range header is the whole length of the file instead of the current connection, so correct it by calculating the difference value between start range and end range, add unit tests for this method in the meantime --- .../download/DownloadLaunchRunnable.java | 2 +- .../util/FileDownloadUtils.java | 42 +++++++++++++++---- .../util/FileDownloadUtilsTest.java | 24 +++++++++++ 3 files changed, 60 insertions(+), 8 deletions(-) diff --git a/library/src/main/java/com/liulishuo/filedownloader/download/DownloadLaunchRunnable.java b/library/src/main/java/com/liulishuo/filedownloader/download/DownloadLaunchRunnable.java index 7f955995..e4d523bb 100644 --- a/library/src/main/java/com/liulishuo/filedownloader/download/DownloadLaunchRunnable.java +++ b/library/src/main/java/com/liulishuo/filedownloader/download/DownloadLaunchRunnable.java @@ -537,7 +537,7 @@ private void handleTrialConnectResult(Map> requestHeader, redirectedUrl = connectTask.getFinalRedirectedUrl(); if (acceptPartial || onlyFromBeginning) { - final long totalLength = FileDownloadUtils.findInstanceLengthForTrial(id, connection); + final long totalLength = FileDownloadUtils.findInstanceLengthForTrial(connection); // update model String fileName = null; diff --git a/library/src/main/java/com/liulishuo/filedownloader/util/FileDownloadUtils.java b/library/src/main/java/com/liulishuo/filedownloader/util/FileDownloadUtils.java index 97703478..09d8fa24 100644 --- a/library/src/main/java/com/liulishuo/filedownloader/util/FileDownloadUtils.java +++ b/library/src/main/java/com/liulishuo/filedownloader/util/FileDownloadUtils.java @@ -555,9 +555,9 @@ public static boolean isAcceptRange(int responseCode, FileDownloadConnection con // because of we using one of two HEAD method to request or using range:0-0 to trial connection // only if connection api not support, so we test content-range first and then test // content-length. - public static long findInstanceLengthForTrial(int id, FileDownloadConnection connection) { + public static long findInstanceLengthForTrial(FileDownloadConnection connection) { long length = findInstanceLengthFromContentRange(connection); - if (length < 0) length = findContentLength(id, connection); + if (length < 0) length = findInstanceLengthFromContentLength(connection); if (length < 0) length = TOTAL_VALUE_IN_CHUNKED_RESOURCE; // the response of HEAD method is not very canonical sometimes(it depends on server // implementation) @@ -571,14 +571,24 @@ public static long findInstanceLengthForTrial(int id, FileDownloadConnection con } public static long findInstanceLengthFromContentRange(FileDownloadConnection connection) { - return parseContentRangeFoInstanceLength( - connection.getResponseHeaderField("Content-Range")); + return parseContentRangeFoInstanceLength(getContentRangeHeader(connection)); + } + + private static String getContentRangeHeader(FileDownloadConnection connection) { + return connection.getResponseHeaderField("Content-Range"); + } + + public static long findInstanceLengthFromContentLength(FileDownloadConnection connection) { + return convertContentLengthString(connection.getResponseHeaderField("Content-Length")); } public static long findContentLength(final int id, FileDownloadConnection connection) { - long contentLength = FileDownloadUtils - .convertContentLengthString(connection.getResponseHeaderField("Content-Length")); - if (contentLength < 0) contentLength = findInstanceLengthFromContentRange(connection); + long contentLength = findInstanceLengthFromContentLength(connection); + if (contentLength < 0) { + final String contentRange = getContentRangeHeader(connection); + contentLength = parseContentLengthFromContentRange(contentRange); + } + final String transferEncoding = connection.getResponseHeaderField("Transfer-Encoding"); if (contentLength < 0) { @@ -610,6 +620,24 @@ public static long findContentLength(final int id, FileDownloadConnection connec return contentLength; } + public static long parseContentLengthFromContentRange(String contentRange) { + if (contentRange == null || contentRange.length() == 0) return -1; + final String pattern = "bytes (\\d+)-(\\d+)/\\d+"; + try { + final Pattern r = Pattern.compile(pattern); + final Matcher m = r.matcher(contentRange); + if (m.find()) { + final long rangeStart = Long.parseLong(m.group(1)); + final long rangeEnd = Long.parseLong(m.group(2)); + return rangeEnd - rangeStart + 1; + } + }catch (Exception e) { + FileDownloadLog.e(FileDownloadUtils.class, e, "parse content length" + + " from content range error"); + } + return -1; + } + public static String findFilename(FileDownloadConnection connection, String url) { String filename = FileDownloadUtils.parseContentDisposition(connection. getResponseHeaderField("Content-Disposition")); diff --git a/library/src/test/java/com/liulishuo/filedownloader/util/FileDownloadUtilsTest.java b/library/src/test/java/com/liulishuo/filedownloader/util/FileDownloadUtilsTest.java index 933493a9..8c06f59f 100644 --- a/library/src/test/java/com/liulishuo/filedownloader/util/FileDownloadUtilsTest.java +++ b/library/src/test/java/com/liulishuo/filedownloader/util/FileDownloadUtilsTest.java @@ -35,4 +35,28 @@ public void parseContentDisposition() { assertThat(filename).isEqualTo("genome.jpeg"); } + @Test + public void parseContentLengthFromContentRange_withNullContentRange() { + long length = FileDownloadUtils.parseContentLengthFromContentRange(null); + assertThat(length).isEqualTo(-1); + } + + @Test + public void parseContentLengthFromContentRange_withEmptyContentRange() { + long length = FileDownloadUtils.parseContentLengthFromContentRange(""); + assertThat(length).isEqualTo(-1); + } + + @Test + public void parseContentLengthFromContentRange_withStartToEndRange() { + long length = FileDownloadUtils.parseContentLengthFromContentRange("bytes 25086300-37629450/37629451"); + assertThat(length).isEqualTo(12543151); + } + + @Test + public void parseContentLengthFromContentRange_withUnavailableContentRange() { + long length = FileDownloadUtils.parseContentLengthFromContentRange("bytes 0-/37629451"); + assertThat(length).isEqualTo(-1); + } + } \ No newline at end of file From 1442f8cb10f4c543891c8e61d3dd24913863de89 Mon Sep 17 00:00:00 2001 From: Tianhua Ran Date: Sun, 11 Mar 2018 17:08:57 +0800 Subject: [PATCH 3/3] fix: correct two methods correct the method of getting total length for trail connection and correct the method of getting content length for real download connection --- .../download/FetchDataTask.java | 5 ++- .../util/FileDownloadUtils.java | 34 ++++++++++--------- .../util/FileDownloadUtilsTest.java | 3 +- 3 files changed, 24 insertions(+), 18 deletions(-) diff --git a/library/src/main/java/com/liulishuo/filedownloader/download/FetchDataTask.java b/library/src/main/java/com/liulishuo/filedownloader/download/FetchDataTask.java index 3cf03971..2e69cf3f 100644 --- a/library/src/main/java/com/liulishuo/filedownloader/download/FetchDataTask.java +++ b/library/src/main/java/com/liulishuo/filedownloader/download/FetchDataTask.java @@ -82,7 +82,10 @@ public void run() throws IOException, IllegalAccessException, IllegalArgumentExc if (paused) return; - final long contentLength = FileDownloadUtils.findContentLength(connectionIndex, connection); + long contentLength = FileDownloadUtils.findContentLength(connectionIndex, connection); + if (contentLength == TOTAL_VALUE_IN_CHUNKED_RESOURCE) { + contentLength = FileDownloadUtils.findContentLengthFromContentRange(connection); + } if (contentLength == 0) { throw new FileDownloadGiveUpRetryException(FileDownloadUtils. formatString( diff --git a/library/src/main/java/com/liulishuo/filedownloader/util/FileDownloadUtils.java b/library/src/main/java/com/liulishuo/filedownloader/util/FileDownloadUtils.java index 09d8fa24..2e7057ee 100644 --- a/library/src/main/java/com/liulishuo/filedownloader/util/FileDownloadUtils.java +++ b/library/src/main/java/com/liulishuo/filedownloader/util/FileDownloadUtils.java @@ -557,8 +557,11 @@ public static boolean isAcceptRange(int responseCode, FileDownloadConnection con // content-length. public static long findInstanceLengthForTrial(FileDownloadConnection connection) { long length = findInstanceLengthFromContentRange(connection); - if (length < 0) length = findInstanceLengthFromContentLength(connection); - if (length < 0) length = TOTAL_VALUE_IN_CHUNKED_RESOURCE; + if (length < 0) { + length = TOTAL_VALUE_IN_CHUNKED_RESOURCE; + FileDownloadLog.w(FileDownloadUtils.class, "don't get instance length from" + + "Content-Range header"); + } // the response of HEAD method is not very canonical sometimes(it depends on server // implementation) // so that it's uncertain the content-length is the same as the response of GET method if @@ -575,20 +578,12 @@ public static long findInstanceLengthFromContentRange(FileDownloadConnection con } private static String getContentRangeHeader(FileDownloadConnection connection) { - return connection.getResponseHeaderField("Content-Range"); - } - - public static long findInstanceLengthFromContentLength(FileDownloadConnection connection) { - return convertContentLengthString(connection.getResponseHeaderField("Content-Length")); + return connection.getResponseHeaderField("Content-Range"); } public static long findContentLength(final int id, FileDownloadConnection connection) { - long contentLength = findInstanceLengthFromContentLength(connection); - if (contentLength < 0) { - final String contentRange = getContentRangeHeader(connection); - contentLength = parseContentLengthFromContentRange(contentRange); - } - + long contentLength = convertContentLengthString( + connection.getResponseHeaderField("Content-Length")); final String transferEncoding = connection.getResponseHeaderField("Transfer-Encoding"); if (contentLength < 0) { @@ -620,6 +615,13 @@ public static long findContentLength(final int id, FileDownloadConnection connec return contentLength; } + public static long findContentLengthFromContentRange(FileDownloadConnection connection) { + final String contentRange = getContentRangeHeader(connection); + long contentLength = parseContentLengthFromContentRange(contentRange); + if (contentLength < 0) contentLength = TOTAL_VALUE_IN_CHUNKED_RESOURCE; + return contentLength; + } + public static long parseContentLengthFromContentRange(String contentRange) { if (contentRange == null || contentRange.length() == 0) return -1; final String pattern = "bytes (\\d+)-(\\d+)/\\d+"; @@ -631,9 +633,9 @@ public static long parseContentLengthFromContentRange(String contentRange) { final long rangeEnd = Long.parseLong(m.group(2)); return rangeEnd - rangeStart + 1; } - }catch (Exception e) { - FileDownloadLog.e(FileDownloadUtils.class, e, "parse content length" + - " from content range error"); + } catch (Exception e) { + FileDownloadLog.e(FileDownloadUtils.class, e, "parse content length" + + " from content range error"); } return -1; } diff --git a/library/src/test/java/com/liulishuo/filedownloader/util/FileDownloadUtilsTest.java b/library/src/test/java/com/liulishuo/filedownloader/util/FileDownloadUtilsTest.java index 8c06f59f..06ca48b4 100644 --- a/library/src/test/java/com/liulishuo/filedownloader/util/FileDownloadUtilsTest.java +++ b/library/src/test/java/com/liulishuo/filedownloader/util/FileDownloadUtilsTest.java @@ -49,7 +49,8 @@ public void parseContentLengthFromContentRange_withEmptyContentRange() { @Test public void parseContentLengthFromContentRange_withStartToEndRange() { - long length = FileDownloadUtils.parseContentLengthFromContentRange("bytes 25086300-37629450/37629451"); + long length = FileDownloadUtils + .parseContentLengthFromContentRange("bytes 25086300-37629450/37629451"); assertThat(length).isEqualTo(12543151); }