Hold a share open if its timer hsa expired but a file is still uploading. Don't allow other uploads during this time

This commit is contained in:
Miguel Jacq 2018-09-17 17:42:04 +10:00
parent 4777c45ad8
commit b06fd8af26
No known key found for this signature in database
GPG Key ID: EEA4341C6D97A0B6
3 changed files with 106 additions and 82 deletions

View File

@ -118,6 +118,7 @@ class Web(object):
self.download_in_progress = False self.download_in_progress = False
self.done = False self.done = False
self.can_upload = True
# If the client closes the OnionShare window while a download is in progress, # If the client closes the OnionShare window while a download is in progress,
# it should immediately stop serving the file. The client_cancel global is # it should immediately stop serving the file. The client_cancel global is
@ -343,96 +344,104 @@ class Web(object):
""" """
Upload files. Upload files.
""" """
# Make sure downloads_dir exists while self.can_upload:
valid = True # Make sure downloads_dir exists
try: valid = True
self.common.validate_downloads_dir() try:
except DownloadsDirErrorCannotCreate: self.common.validate_downloads_dir()
self.add_request(Web.REQUEST_ERROR_DOWNLOADS_DIR_CANNOT_CREATE, request.path) except DownloadsDirErrorCannotCreate:
print(strings._('error_cannot_create_downloads_dir').format(self.common.settings.get('downloads_dir'))) self.add_request(Web.REQUEST_ERROR_DOWNLOADS_DIR_CANNOT_CREATE, request.path)
valid = False print(strings._('error_cannot_create_downloads_dir').format(self.common.settings.get('downloads_dir')))
except DownloadsDirErrorNotWritable: valid = False
self.add_request(Web.REQUEST_ERROR_DOWNLOADS_DIR_NOT_WRITABLE, request.path) except DownloadsDirErrorNotWritable:
print(strings._('error_downloads_dir_not_writable').format(self.common.settings.get('downloads_dir'))) self.add_request(Web.REQUEST_ERROR_DOWNLOADS_DIR_NOT_WRITABLE, request.path)
valid = False print(strings._('error_downloads_dir_not_writable').format(self.common.settings.get('downloads_dir')))
if not valid: valid = False
flash('Error uploading, please inform the OnionShare user', 'error') if not valid:
flash('Error uploading, please inform the OnionShare user', 'error')
if self.common.settings.get('public_mode'):
return redirect('/')
else:
return redirect('/{}'.format(slug_candidate))
files = request.files.getlist('file[]')
filenames = []
print('')
for f in files:
if f.filename != '':
# Automatically rename the file, if a file of the same name already exists
filename = secure_filename(f.filename)
filenames.append(filename)
local_path = os.path.join(self.common.settings.get('downloads_dir'), filename)
if os.path.exists(local_path):
if '.' in filename:
# Add "-i", e.g. change "foo.txt" to "foo-2.txt"
parts = filename.split('.')
name = parts[:-1]
ext = parts[-1]
i = 2
valid = False
while not valid:
new_filename = '{}-{}.{}'.format('.'.join(name), i, ext)
local_path = os.path.join(self.common.settings.get('downloads_dir'), new_filename)
if os.path.exists(local_path):
i += 1
else:
valid = True
else:
# If no extension, just add "-i", e.g. change "foo" to "foo-2"
i = 2
valid = False
while not valid:
new_filename = '{}-{}'.format(filename, i)
local_path = os.path.join(self.common.settings.get('downloads_dir'), new_filename)
if os.path.exists(local_path):
i += 1
else:
valid = True
basename = os.path.basename(local_path)
if f.filename != basename:
# Tell the GUI that the file has changed names
self.add_request(Web.REQUEST_UPLOAD_FILE_RENAMED, request.path, {
'id': request.upload_id,
'old_filename': f.filename,
'new_filename': basename
})
self.common.log('Web', 'receive_routes', '/upload, uploaded {}, saving to {}'.format(f.filename, local_path))
print(strings._('receive_mode_received_file').format(local_path))
f.save(local_path)
# Note that flash strings are on English, and not translated, on purpose,
# to avoid leaking the locale of the OnionShare user
if len(filenames) == 0:
flash('No files uploaded', 'info')
else:
for filename in filenames:
flash('Sent {}'.format(filename), 'info')
# Register that uploads were sent (for shutdown timer)
self.done = True
if self.common.settings.get('public_mode'): if self.common.settings.get('public_mode'):
return redirect('/') return redirect('/')
else: else:
return redirect('/{}'.format(slug_candidate)) return redirect('/{}'.format(slug_candidate))
files = request.files.getlist('file[]')
filenames = []
print('')
for f in files:
if f.filename != '':
# Automatically rename the file, if a file of the same name already exists
filename = secure_filename(f.filename)
filenames.append(filename)
local_path = os.path.join(self.common.settings.get('downloads_dir'), filename)
if os.path.exists(local_path):
if '.' in filename:
# Add "-i", e.g. change "foo.txt" to "foo-2.txt"
parts = filename.split('.')
name = parts[:-1]
ext = parts[-1]
i = 2
valid = False
while not valid:
new_filename = '{}-{}.{}'.format('.'.join(name), i, ext)
local_path = os.path.join(self.common.settings.get('downloads_dir'), new_filename)
if os.path.exists(local_path):
i += 1
else:
valid = True
else:
# If no extension, just add "-i", e.g. change "foo" to "foo-2"
i = 2
valid = False
while not valid:
new_filename = '{}-{}'.format(filename, i)
local_path = os.path.join(self.common.settings.get('downloads_dir'), new_filename)
if os.path.exists(local_path):
i += 1
else:
valid = True
basename = os.path.basename(local_path)
if f.filename != basename:
# Tell the GUI that the file has changed names
self.add_request(Web.REQUEST_UPLOAD_FILE_RENAMED, request.path, {
'id': request.upload_id,
'old_filename': f.filename,
'new_filename': basename
})
self.common.log('Web', 'receive_routes', '/upload, uploaded {}, saving to {}'.format(f.filename, local_path))
print(strings._('receive_mode_received_file').format(local_path))
f.save(local_path)
# Note that flash strings are on English, and not translated, on purpose,
# to avoid leaking the locale of the OnionShare user
if len(filenames) == 0:
flash('No files uploaded', 'info')
else:
for filename in filenames:
flash('Sent {}'.format(filename), 'info')
if self.common.settings.get('public_mode'):
return redirect('/')
else:
return redirect('/{}'.format(slug_candidate))
@self.app.route("/<slug_candidate>/upload", methods=['POST']) @self.app.route("/<slug_candidate>/upload", methods=['POST'])
def upload(slug_candidate): def upload(slug_candidate):
self.check_slug_candidate(slug_candidate) self.check_slug_candidate(slug_candidate)
return upload_logic(slug_candidate) if self.can_upload:
return upload_logic(slug_candidate)
else:
return self.error404()
@self.app.route("/upload", methods=['POST']) @self.app.route("/upload", methods=['POST'])
def upload_public(): def upload_public():
if not self.common.settings.get('public_mode'): if not self.common.settings.get('public_mode') or not self.can_upload:
return self.error404() return self.error404()
return upload_logic() return upload_logic()
@ -449,11 +458,14 @@ class Web(object):
@self.app.route("/<slug_candidate>/close", methods=['POST']) @self.app.route("/<slug_candidate>/close", methods=['POST'])
def close(slug_candidate): def close(slug_candidate):
self.check_slug_candidate(slug_candidate) self.check_slug_candidate(slug_candidate)
return close_logic(slug_candidate) if self.can_upload:
return close_logic(slug_candidate)
else:
return self.error404()
@self.app.route("/close", methods=['POST']) @self.app.route("/close", methods=['POST'])
def close_public(): def close_public():
if not self.common.settings.get('public_mode'): if not self.common.settings.get('public_mode') or not self.can_upload:
return self.error404() return self.error404()
return close_logic() return close_logic()
@ -745,7 +757,7 @@ class ReceiveModeRequest(Request):
# Is this a valid upload request? # Is this a valid upload request?
self.upload_request = False self.upload_request = False
if self.method == 'POST': if self.method == 'POST' and self.web.can_upload:
if self.path == '/{}/upload'.format(self.web.slug): if self.path == '/{}/upload'.format(self.web.slug):
self.upload_request = True self.upload_request = True
else: else:

View File

@ -98,6 +98,17 @@ class ReceiveMode(Mode):
The shutdown timer expired, should we stop the server? Returns a bool The shutdown timer expired, should we stop the server? Returns a bool
""" """
# TODO: wait until the final upload is done before stoppign the server? # TODO: wait until the final upload is done before stoppign the server?
# If there were no attempts to upload files, or all uploads are done, we can stop
if self.web.upload_count == 0 or self.web.done:
self.server_status.stop_server()
self.server_status_label.setText(strings._('close_on_timeout', True))
return True
# An upload is probably still running - hold off on stopping the share, but block new shares.
else:
self.server_status_label.setText(strings._('timeout_upload_still_running', True))
self.web.can_upload = False
return False
return True return True
def start_server_custom(self): def start_server_custom(self):

View File

@ -15,6 +15,7 @@
"close_on_timeout": "Stopped because timer expired", "close_on_timeout": "Stopped because timer expired",
"closing_automatically": "Stopped because download finished", "closing_automatically": "Stopped because download finished",
"timeout_download_still_running": "Waiting for download to complete", "timeout_download_still_running": "Waiting for download to complete",
"timeout_upload_still_running": "Waiting for upload to complete",
"large_filesize": "Warning: Sending large files could take hours", "large_filesize": "Warning: Sending large files could take hours",
"systray_menu_exit": "Quit", "systray_menu_exit": "Quit",
"systray_download_started_title": "OnionShare Download Started", "systray_download_started_title": "OnionShare Download Started",