Merge branch 'etag-fix' into 'master'

switch etag cache check to purely client-side

Closes #562

See merge request !574
This commit is contained in:
Peter Serwylo 2017-09-04 20:22:02 +00:00
commit aa2d791531
6 changed files with 23 additions and 74 deletions

View File

@ -89,11 +89,6 @@ public class IndexV1Updater extends RepoUpdater {
if (downloader.isNotFound()) { if (downloader.isNotFound()) {
return false; return false;
} }
if (downloader.isCached()) {
// The index is unchanged since we last read it. We just mark
// everything that came from this repo as being updated.
Utils.debugLog(TAG, "Repo index for " + dataUri + " is up to date (by etag)");
}
hasChanged = downloader.hasChanged(); hasChanged = downloader.hasChanged();
if (!hasChanged) { if (!hasChanged) {

View File

@ -132,12 +132,6 @@ public class RepoUpdater {
downloader.setListener(downloadListener); downloader.setListener(downloadListener);
downloader.download(); downloader.download();
if (downloader.isCached()) {
// The index is unchanged since we last read it. We just mark
// everything that came from this repo as being updated.
Utils.debugLog(TAG, "Repo index for " + indexUrl + " is up to date (by etag)");
}
} catch (IOException e) { } catch (IOException e) {
if (downloader != null && downloader.outputFile != null) { if (downloader != null && downloader.outputFile != null) {
if (!downloader.outputFile.delete()) { if (!downloader.outputFile.delete()) {

View File

@ -84,14 +84,6 @@ public class BluetoothDownloader extends Downloader {
connection.closeQuietly(); connection.closeQuietly();
} }
@Override
public boolean isCached() {
FileDetails details = getFileDetails();
return details != null &&
details.getCacheTag() != null &&
details.getCacheTag().equals(getCacheTag());
}
@Override @Override
protected void close() { protected void close() {
if (connection != null) { if (connection != null) {

View File

@ -75,18 +75,12 @@ public abstract class Downloader {
this.cacheTag = cacheTag; this.cacheTag = cacheTag;
} }
boolean wantToCheckCache() {
return cacheTag != null;
}
public abstract boolean hasChanged(); public abstract boolean hasChanged();
protected abstract int totalDownloadSize(); protected abstract int totalDownloadSize();
public abstract void download() throws IOException, InterruptedException; public abstract void download() throws IOException, InterruptedException;
public abstract boolean isCached();
/** /**
* @return whether the requested file was not found in the repo (e.g. HTTP 404 Not Found) * @return whether the requested file was not found in the repo (e.g. HTTP 404 Not Found)
*/ */

View File

@ -1,7 +1,8 @@
package org.fdroid.fdroid.net; package org.fdroid.fdroid.net;
import android.text.TextUtils;
import com.nostra13.universalimageloader.core.download.BaseImageDownloader; import com.nostra13.universalimageloader.core.download.BaseImageDownloader;
import info.guardianproject.netcipher.NetCipher;
import org.apache.commons.io.FileUtils; import org.apache.commons.io.FileUtils;
import org.fdroid.fdroid.BuildConfig; import org.fdroid.fdroid.BuildConfig;
import org.fdroid.fdroid.FDroidApp; import org.fdroid.fdroid.FDroidApp;
@ -17,18 +18,15 @@ import java.net.HttpURLConnection;
import java.net.MalformedURLException; import java.net.MalformedURLException;
import java.net.URL; import java.net.URL;
import info.guardianproject.netcipher.NetCipher;
public class HttpDownloader extends Downloader { public class HttpDownloader extends Downloader {
private static final String TAG = "HttpDownloader"; private static final String TAG = "HttpDownloader";
private static final String HEADER_IF_NONE_MATCH = "If-None-Match";
private static final String HEADER_FIELD_ETAG = "ETag"; private static final String HEADER_FIELD_ETAG = "ETag";
private final String username; private final String username;
private final String password; private final String password;
private HttpURLConnection connection; private HttpURLConnection connection;
private int statusCode = -1; private boolean newFileAvailableOnServer;
HttpDownloader(URL url, File destFile) HttpDownloader(URL url, File destFile)
throws FileNotFoundException, MalformedURLException { throws FileNotFoundException, MalformedURLException {
@ -70,24 +68,33 @@ public class HttpDownloader extends Downloader {
} }
/** /**
* Get a remote file, checking the HTTP response code. If 'etag' is not * Get a remote file, checking the HTTP response code and the {@code etag}.
* {@code null}, it's passed to the server as an If-None-Match header, in * In order to prevent the {@code etag} from being used as a form of tracking
* which case expect a 304 response if nothing changed. In the event of a * cookie, this code never sends the {@code etag} to the server. Instead, it
* 200 response ONLY, 'retag' (which should be passed empty) may contain * uses a {@code HEAD} request to get the {@code etag} from the server, then
* an etag value for the response, or it may be left empty if none was * only issues a {@code GET} if the {@code etag} has changed.
* available. *
* @see <a href="http://lucb1e.com/rp/cookielesscookies">Cookieless cookies</a>
*/ */
@Override @Override
public void download() throws IOException, InterruptedException { public void download() throws IOException, InterruptedException {
// get the file size from the server // get the file size from the server
HttpURLConnection tmpConn = getConnection(); HttpURLConnection tmpConn = getConnection();
tmpConn.setRequestMethod("HEAD"); tmpConn.setRequestMethod("HEAD");
String etag = tmpConn.getHeaderField(HEADER_FIELD_ETAG);
int contentLength = -1; int contentLength = -1;
int statusCode = tmpConn.getResponseCode(); int statusCode = tmpConn.getResponseCode();
tmpConn.disconnect(); tmpConn.disconnect();
newFileAvailableOnServer = false;
switch (statusCode) { switch (statusCode) {
case 200: case 200:
contentLength = tmpConn.getContentLength(); contentLength = tmpConn.getContentLength();
if (!TextUtils.isEmpty(etag) && etag.equals(cacheTag)) {
Utils.debugLog(TAG, sourceUrl + " is cached, not downloading");
return;
}
newFileAvailableOnServer = true;
break; break;
case 404: case 404:
notFound = true; notFound = true;
@ -96,6 +103,7 @@ public class HttpDownloader extends Downloader {
Utils.debugLog(TAG, "HEAD check of " + sourceUrl + " returned " + statusCode + ": " Utils.debugLog(TAG, "HEAD check of " + sourceUrl + " returned " + statusCode + ": "
+ tmpConn.getResponseMessage()); + tmpConn.getResponseMessage());
} }
boolean resumable = false; boolean resumable = false;
long fileLength = outputFile.length(); long fileLength = outputFile.length();
if (fileLength > contentLength) { if (fileLength > contentLength) {
@ -106,7 +114,9 @@ public class HttpDownloader extends Downloader {
resumable = true; resumable = true;
} }
setupConnection(resumable); setupConnection(resumable);
doDownload(resumable); Utils.debugLog(TAG, "downloading " + sourceUrl + " (is resumable: " + resumable + ")");
downloadFromStream(8192, resumable);
cacheTag = connection.getHeaderField(HEADER_FIELD_ETAG);
} }
private boolean isSwapUrl() { private boolean isSwapUrl() {
@ -147,37 +157,6 @@ public class HttpDownloader extends Downloader {
} }
} }
private void doDownload(boolean resumable) throws IOException, InterruptedException {
if (wantToCheckCache()) {
setupCacheCheck();
Utils.debugLog(TAG, "Checking cached status of " + sourceUrl);
statusCode = connection.getResponseCode();
}
if (isCached()) {
Utils.debugLog(TAG, sourceUrl + " is cached, so not downloading (HTTP " + statusCode + ")");
} else {
Utils.debugLog(TAG, "Need to download " + sourceUrl + " (is resumable: " + resumable + ")");
downloadFromStream(8192, resumable);
updateCacheCheck();
}
}
@Override
public boolean isCached() {
return wantToCheckCache() && statusCode == 304;
}
private void setupCacheCheck() {
if (cacheTag != null) {
connection.setRequestProperty(HEADER_IF_NONE_MATCH, cacheTag);
}
}
private void updateCacheCheck() {
cacheTag = connection.getHeaderField(HEADER_FIELD_ETAG);
}
// Testing in the emulator for me, showed that figuring out the // Testing in the emulator for me, showed that figuring out the
// filesize took about 1 to 1.5 seconds. // filesize took about 1 to 1.5 seconds.
// To put this in context, downloading a repo of: // To put this in context, downloading a repo of:
@ -193,7 +172,7 @@ public class HttpDownloader extends Downloader {
@Override @Override
public boolean hasChanged() { public boolean hasChanged() {
return this.statusCode != 304; return newFileAvailableOnServer;
} }
@Override @Override

View File

@ -49,9 +49,4 @@ public class LocalFileDownloader extends Downloader {
notFound = true; notFound = true;
} }
} }
@Override
public boolean isCached() {
return false;
}
} }