From e3b26b76f6b2d319c276ef14d8266099c44d9a97 Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Tue, 7 Aug 2018 23:32:46 +0200 Subject: [PATCH] make swap webserver never support HTTP Connection Keep-Alive NanoHTTPD has issues with HTTP Keep-Alive, especially when other requests are mixed in, like the /request-swap POST or perhaps the F-Droid HEAD to fetch the ETag before the GET. This disables gzip encoding and sets a Content Security Policy while I'm at it. APKs, PNGs, and JARs are already compressed, so gzip would only ever cause problems. And the index page is meant to be viewed by browsers, so having a CSP will limit potential malicious swap activity. --- .../org/fdroid/fdroid/net/LocalHTTPD.java | 36 ++++++++++++++----- 1 file changed, 28 insertions(+), 8 deletions(-) diff --git a/app/src/full/java/org/fdroid/fdroid/net/LocalHTTPD.java b/app/src/full/java/org/fdroid/fdroid/net/LocalHTTPD.java index 4d4aade69..b7a522261 100644 --- a/app/src/full/java/org/fdroid/fdroid/net/LocalHTTPD.java +++ b/app/src/full/java/org/fdroid/fdroid/net/LocalHTTPD.java @@ -47,6 +47,7 @@ import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FilenameFilter; import java.io.IOException; +import java.io.InputStream; import java.io.UnsupportedEncodingException; import java.net.URLEncoder; import java.util.Arrays; @@ -218,8 +219,32 @@ public class LocalHTTPD extends NanoHTTPD { return msg.toString(); } + /** + * {@link Response#setKeepAlive(boolean)} alone does not seem to stop + * setting the {@code Connection} header to {@code keep-alive}, so also + * just directly set that header. + */ + public static Response addResponseHeaders(Response response) { + response.setKeepAlive(false); + response.setGzipEncoding(false); + response.addHeader("Connection", "close"); + response.addHeader("Content-Security-Policy", + "default-src 'none'; img-src 'self'; style-src 'self' 'unsafe-inline';"); + return response; + } + + public static Response newFixedLengthResponse(String msg) { + return addResponseHeaders(NanoHTTPD.newFixedLengthResponse(msg)); + } + + public static Response newFixedLengthResponse(Response.IStatus status, String mimeType, + InputStream data, long totalBytes) { + return addResponseHeaders(NanoHTTPD.newFixedLengthResponse(status, mimeType, data, totalBytes)); + } + public static Response newFixedLengthResponse(IStatus status, String mimeType, String message) { Response response = NanoHTTPD.newFixedLengthResponse(status, mimeType, message); + addResponseHeaders(response); response.addHeader("Accept-Ranges", "bytes"); return response; } @@ -377,6 +402,7 @@ public class LocalHTTPD extends NanoHTTPD { // Change return code and add Content-Range header when skipping is // requested long fileLen = file.length(); + if (headerIfRangeMissingOrMatching && range != null && startFrom >= 0 && startFrom < fileLen) { // range request that matches current etag // and the startFrom of the range is satisfiable @@ -437,12 +463,13 @@ public class LocalHTTPD extends NanoHTTPD { res = getForbiddenResponse("Reading file failed."); } - return res; + return addResponseHeaders(res); } private Response newFixedFileResponse(File file, String mime) throws FileNotFoundException { Response res; res = newFixedLengthResponse(Response.Status.OK, mime, new FileInputStream(file), (int) file.length()); + addResponseHeaders(res); res.addHeader("Accept-Ranges", "bytes"); return res; } @@ -458,11 +485,4 @@ public class LocalHTTPD extends NanoHTTPD { e.printStackTrace(); } } - - protected Response addCORSHeaders(Map queryHeaders, Response resp, String cors) { - resp.addHeader("Access-Control-Allow-Credentials", "false"); - resp.addHeader("Access-Control-Allow-Methods", "GET, POST, HEAD"); - // TODO add HTTP Content Security Policy headers - return resp; - } }