Dynamically figure out the total size of the download based on the whether or not the client making the http request accepts gzip

This commit is contained in:
Micah Lee 2018-09-21 16:22:37 -07:00
parent 2a309af680
commit 09ccbf4a60
No known key found for this signature in database
GPG Key ID: 403C2657CD994F73
2 changed files with 25 additions and 6 deletions

View File

@ -25,6 +25,7 @@ class ShareModeWeb(object):
self.download_filename = None self.download_filename = None
self.download_filesize = None self.download_filesize = None
self.gzip_filename = None self.gzip_filename = None
self.gzip_filesize = None
self.zip_writer = None self.zip_writer = None
self.download_count = 0 self.download_count = 0
@ -69,13 +70,18 @@ class ShareModeWeb(object):
return self.web.add_security_headers(r) return self.web.add_security_headers(r)
# If download is allowed to continue, serve download page # If download is allowed to continue, serve download page
if self.should_use_gzip():
filesize = self.gzip_filesize
else:
filesize = self.download_filesize
if self.web.slug: if self.web.slug:
r = make_response(render_template( r = make_response(render_template(
'send.html', 'send.html',
slug=self.web.slug, slug=self.web.slug,
file_info=self.file_info, file_info=self.file_info,
filename=os.path.basename(self.download_filename), filename=os.path.basename(self.download_filename),
filesize=self.download_filesize, filesize=filesize,
filesize_human=self.common.human_readable_filesize(self.download_filesize), filesize_human=self.common.human_readable_filesize(self.download_filesize),
is_zipped=self.is_zipped)) is_zipped=self.is_zipped))
else: else:
@ -84,7 +90,7 @@ class ShareModeWeb(object):
'send.html', 'send.html',
file_info=self.file_info, file_info=self.file_info,
filename=os.path.basename(self.download_filename), filename=os.path.basename(self.download_filename),
filesize=self.download_filesize, filesize=filesize,
filesize_human=self.common.human_readable_filesize(self.download_filesize), filesize_human=self.common.human_readable_filesize(self.download_filesize),
is_zipped=self.is_zipped)) is_zipped=self.is_zipped))
return self.web.add_security_headers(r) return self.web.add_security_headers(r)
@ -123,7 +129,7 @@ class ShareModeWeb(object):
# If this is a zipped file, then serve as-is. If it's not zipped, then, # If this is a zipped file, then serve as-is. If it's not zipped, then,
# if the http client supports gzip compression, gzip the file first # if the http client supports gzip compression, gzip the file first
# and serve that # and serve that
use_gzip = (not self.is_zipped) and ('gzip' in request.headers.get('Accept-Encoding', '').lower()) use_gzip = self.should_use_gzip()
if use_gzip: if use_gzip:
file_to_download = self.gzip_filename file_to_download = self.gzip_filename
else: else:
@ -131,7 +137,8 @@ class ShareModeWeb(object):
# Tell GUI the download started # Tell GUI the download started
self.web.add_request(self.web.REQUEST_STARTED, path, { self.web.add_request(self.web.REQUEST_STARTED, path, {
'id': download_id 'id': download_id,
'use_gzip': use_gzip
}) })
basename = os.path.basename(self.download_filename) basename = os.path.basename(self.download_filename)
@ -212,7 +219,7 @@ class ShareModeWeb(object):
r = Response(generate()) r = Response(generate())
if use_gzip: if use_gzip:
r.headers.set('Content-Encoding', 'gzip') r.headers.set('Content-Encoding', 'gzip')
r.headers.set('Content-Length', os.path.getsize(self.gzip_filename)) r.headers.set('Content-Length', self.gzip_filesize)
else: else:
r.headers.set('Content-Length', self.download_filesize) r.headers.set('Content-Length', self.download_filesize)
r.headers.set('Content-Disposition', 'attachment', filename=basename) r.headers.set('Content-Disposition', 'attachment', filename=basename)
@ -260,6 +267,7 @@ class ShareModeWeb(object):
# Compress the file with gzip now, so we don't have to do it on each request # Compress the file with gzip now, so we don't have to do it on each request
self.gzip_filename = tempfile.mkstemp('wb+')[1] self.gzip_filename = tempfile.mkstemp('wb+')[1]
self._gzip_compress(self.download_filename, self.gzip_filename, 6, processed_size_callback) self._gzip_compress(self.download_filename, self.gzip_filename, 6, processed_size_callback)
self.gzip_filesize = os.path.getsize(self.gzip_filename)
# Make sure the gzip file gets cleaned up when onionshare stops # Make sure the gzip file gets cleaned up when onionshare stops
self.cleanup_filenames.append(self.gzip_filename) self.cleanup_filenames.append(self.gzip_filename)
@ -291,6 +299,12 @@ class ShareModeWeb(object):
return True return True
def should_use_gzip(self):
"""
Should we use gzip for this browser?
"""
return (not self.is_zipped) and ('gzip' in request.headers.get('Accept-Encoding', '').lower())
def _gzip_compress(self, input_filename, output_filename, level, processed_size_callback=None): def _gzip_compress(self, input_filename, output_filename, level, processed_size_callback=None):
""" """
Compress a file with gzip, without loading the whole thing into memory Compress a file with gzip, without loading the whole thing into memory

View File

@ -229,7 +229,11 @@ class ShareMode(Mode):
""" """
Handle REQUEST_STARTED event. Handle REQUEST_STARTED event.
""" """
self.downloads.add(event["data"]["id"], self.web.share_mode.download_filesize) if event["data"]["use_gzip"]:
filesize = self.web.share_mode.gzip_filesize
else:
filesize = self.web.share_mode.download_filesize
self.downloads.add(event["data"]["id"], filesize)
self.downloads_in_progress += 1 self.downloads_in_progress += 1
self.update_downloads_in_progress() self.update_downloads_in_progress()
@ -388,6 +392,7 @@ class ZipProgressBar(QtWidgets.QProgressBar):
def update_processed_size(self, val): def update_processed_size(self, val):
self._processed_size = val self._processed_size = val
if self.processed_size < self.total_files_size: if self.processed_size < self.total_files_size:
self.setValue(int((self.processed_size * 100) / self.total_files_size)) self.setValue(int((self.processed_size * 100) / self.total_files_size))
elif self.total_files_size != 0: elif self.total_files_size != 0: