summaryrefslogtreecommitdiff
path: root/onionshare/web/share_mode.py
diff options
context:
space:
mode:
Diffstat (limited to 'onionshare/web/share_mode.py')
-rw-r--r--onionshare/web/share_mode.py165
1 files changed, 81 insertions, 84 deletions
diff --git a/onionshare/web/share_mode.py b/onionshare/web/share_mode.py
index 0dfa7e0a..8a3f5969 100644
--- a/onionshare/web/share_mode.py
+++ b/onionshare/web/share_mode.py
@@ -3,55 +3,35 @@ import sys
import tempfile
import zipfile
import mimetypes
-import gzip
from flask import Response, request, render_template, make_response
+from .send_base_mode import SendBaseModeWeb
from .. import strings
-class ShareModeWeb(object):
+class ShareModeWeb(SendBaseModeWeb):
"""
All of the web logic for share mode
"""
- def __init__(self, common, web):
- self.common = common
- self.common.log('ShareModeWeb', '__init__')
-
- self.web = web
-
- # Information about the file to be shared
- self.file_info = []
- self.is_zipped = False
- self.download_filename = None
- self.download_filesize = None
- self.gzip_filename = None
- self.gzip_filesize = None
- self.zip_writer = None
-
- self.download_count = 0
-
- # If "Stop After First Download" is checked (stay_open == False), only allow
- # one download at a time.
- self.download_in_progress = False
-
- # Reset assets path
- self.web.app.static_folder=self.common.get_resource_path('static')
+ def init(self):
+ self.common.log('ShareModeWeb', 'init')
-
- self.define_routes()
+ # Allow downloading individual files if "Stop sharing after files have been sent" is unchecked
+ self.download_individual_files = not self.common.settings.get('close_after_first_download')
def define_routes(self):
"""
The web app routes for sharing files
"""
- @self.web.app.route("/")
- def index():
+ @self.web.app.route('/', defaults={'path': ''})
+ @self.web.app.route('/<path:path>')
+ def index(path):
"""
Render the template for the onionshare landing page.
"""
self.web.add_request(self.web.REQUEST_LOAD, request.path)
- # Deny new downloads if "Stop After First Download" is checked and there is
+ # Deny new downloads if "Stop sharing after files have been sent" is checked and there is
# currently a download
deny_download = not self.web.stay_open and self.download_in_progress
if deny_download:
@@ -65,15 +45,7 @@ class ShareModeWeb(object):
else:
self.filesize = self.download_filesize
- r = make_response(render_template(
- 'send.html',
- file_info=self.file_info,
- filename=os.path.basename(self.download_filename),
- filesize=self.filesize,
- filesize_human=self.common.human_readable_filesize(self.download_filesize),
- is_zipped=self.is_zipped,
- static_url_path=self.web.static_url_path))
- return self.web.add_security_headers(r)
+ return self.render_logic(path)
@self.web.app.route("/download")
def download():
@@ -88,10 +60,6 @@ class ShareModeWeb(object):
static_url_path=self.web.static_url_path))
return self.web.add_security_headers(r)
- # Each download has a unique id
- download_id = self.download_count
- self.download_count += 1
-
# Prepare some variables to use inside generate() function below
# which is outside of the request context
shutdown_func = request.environ.get('werkzeug.server.shutdown')
@@ -109,8 +77,10 @@ class ShareModeWeb(object):
self.filesize = self.download_filesize
# Tell GUI the download started
+ history_id = self.cur_history_id
+ self.cur_history_id += 1
self.web.add_request(self.web.REQUEST_STARTED, path, {
- 'id': download_id,
+ 'id': history_id,
'use_gzip': use_gzip
})
@@ -130,7 +100,7 @@ class ShareModeWeb(object):
# The user has canceled the download, so stop serving the file
if not self.web.stop_q.empty():
self.web.add_request(self.web.REQUEST_CANCELED, path, {
- 'id': download_id
+ 'id': history_id
})
break
@@ -152,7 +122,7 @@ class ShareModeWeb(object):
sys.stdout.flush()
self.web.add_request(self.web.REQUEST_PROGRESS, path, {
- 'id': download_id,
+ 'id': history_id,
'bytes': downloaded_bytes
})
self.web.done = False
@@ -163,7 +133,7 @@ class ShareModeWeb(object):
# tell the GUI the download has canceled
self.web.add_request(self.web.REQUEST_CANCELED, path, {
- 'id': download_id
+ 'id': history_id
})
fp.close()
@@ -198,19 +168,73 @@ class ShareModeWeb(object):
r.headers.set('Content-Type', content_type)
return r
- def set_file_info(self, filenames, processed_size_callback=None):
- """
- Using the list of filenames being shared, fill in details that the web
- page will need to display. This includes zipping up the file in order to
- get the zip file's name and size.
- """
- self.common.log("ShareModeWeb", "set_file_info")
+ def directory_listing_template(self, path, files, dirs, breadcrumbs, breadcrumbs_leaf):
+ return make_response(render_template(
+ 'send.html',
+ file_info=self.file_info,
+ files=files,
+ dirs=dirs,
+ breadcrumbs=breadcrumbs,
+ breadcrumbs_leaf=breadcrumbs_leaf,
+ filename=os.path.basename(self.download_filename),
+ filesize=self.filesize,
+ filesize_human=self.common.human_readable_filesize(self.download_filesize),
+ is_zipped=self.is_zipped,
+ static_url_path=self.web.static_url_path,
+ download_individual_files=self.download_individual_files))
+
+ def set_file_info_custom(self, filenames, processed_size_callback):
+ self.common.log("ShareModeWeb", "set_file_info_custom")
self.web.cancel_compression = False
+ self.build_zipfile_list(filenames, processed_size_callback)
+
+ def render_logic(self, path=''):
+ if path in self.files:
+ filesystem_path = self.files[path]
+
+ # If it's a directory
+ if os.path.isdir(filesystem_path):
+ # Render directory listing
+ filenames = []
+ for filename in os.listdir(filesystem_path):
+ if os.path.isdir(os.path.join(filesystem_path, filename)):
+ filenames.append(filename + '/')
+ else:
+ filenames.append(filename)
+ filenames.sort()
+ return self.directory_listing(filenames, path, filesystem_path)
+
+ # If it's a file
+ elif os.path.isfile(filesystem_path):
+ if self.download_individual_files:
+ return self.stream_individual_file(filesystem_path)
+ else:
+ history_id = self.cur_history_id
+ self.cur_history_id += 1
+ return self.web.error404(history_id)
+
+ # If it's not a directory or file, throw a 404
+ else:
+ history_id = self.cur_history_id
+ self.cur_history_id += 1
+ return self.web.error404(history_id)
+ else:
+ # Special case loading /
- self.cleanup_filenames = []
+ if path == '':
+ # Root directory listing
+ filenames = list(self.root_files)
+ filenames.sort()
+ return self.directory_listing(filenames, path)
- # build file info list
- self.file_info = {'files': [], 'dirs': []}
+ else:
+ # If the path isn't found, throw a 404
+ history_id = self.cur_history_id
+ self.cur_history_id += 1
+ return self.web.error404(history_id)
+
+ def build_zipfile_list(self, filenames, processed_size_callback=None):
+ self.common.log("ShareModeWeb", "build_zipfile_list")
for filename in filenames:
info = {
'filename': filename,
@@ -267,33 +291,6 @@ class ShareModeWeb(object):
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):
- """
- Compress a file with gzip, without loading the whole thing into memory
- Thanks: https://stackoverflow.com/questions/27035296/python-how-to-gzip-a-large-text-file-without-memoryerror
- """
- bytes_processed = 0
- blocksize = 1 << 16 # 64kB
- with open(input_filename, 'rb') as input_file:
- output_file = gzip.open(output_filename, 'wb', level)
- while True:
- if processed_size_callback is not None:
- processed_size_callback(bytes_processed)
-
- block = input_file.read(blocksize)
- if len(block) == 0:
- break
- output_file.write(block)
- bytes_processed += blocksize
-
- output_file.close()
-
class ZipWriter(object):
"""