# Buggy code
def define_routes(self):
    """
    The web app routes for sharing files
    """

    @self.web.app.route("/<slug_candidate>")
    def index(slug_candidate):
        self.web.check_slug_candidate(slug_candidate)
        return index_logic()

    @self.web.app.route("/")
    def index_public():
        if not self.common.settings.get("public_mode"):
            return self.web.error404()
        return index_logic()

    def index_logic(slug_candidate=""):
        """
        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
        # currently a download
        deny_download = not self.web.stay_open and self.download_in_progress
        if deny_download:
            r = make_response(render_template("denied.html"))
            return self.web.add_security_headers(r)

        # If download is allowed to continue, serve download page
        if self.should_use_gzip():
            self.filesize = self.gzip_filesize
        else:
            self.filesize = self.download_filesize

        if self.web.slug:
            r = make_response(
                render_template(
                    "send.html",
                    slug=self.web.slug,
                    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,
                )
            )
        else:
            # If download is allowed to continue, serve download page
            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,
                )
            )
        return self.web.add_security_headers(r)

    @self.web.app.route("/<slug_candidate>/download")
    def download(slug_candidate):
        self.web.check_slug_candidate(slug_candidate)
        return download_logic()

    @self.web.app.route("/download")
    def download_public():
        if not self.common.settings.get("public_mode"):
            return self.web.error404()
        return download_logic()

    def download_logic(slug_candidate=""):
        """
        Download the zip file.
        """
        # Deny new downloads if "Stop After First Download" is checked and there is
        # currently a download
        deny_download = not self.web.stay_open and self.download_in_progress
        if deny_download:
            r = make_response(render_template("denied.html"))
            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")
        path = request.path

        # 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
        # and serve that
        use_gzip = self.should_use_gzip()
        if use_gzip:
            file_to_download = self.gzip_filename
            self.filesize = self.gzip_filesize
        else:
            file_to_download = self.download_filename
            self.filesize = self.download_filesize

        # Tell GUI the download started
        self.web.add_request(
            self.web.REQUEST_STARTED, path, {"id": download_id, "use_gzip": use_gzip}
        )

        basename = os.path.basename(self.download_filename)

        def generate():
            # The user hasn't canceled the download
            self.client_cancel = False

            # Starting a new download
            if not self.web.stay_open:
                self.download_in_progress = True

            chunk_size = 102400  # 100kb

            fp = open(file_to_download, "rb")
            self.web.done = False
            canceled = False
            while not self.web.done:
                # The user has canceled the download, so stop serving the file
                if self.client_cancel:
                    self.web.add_request(
                        self.web.REQUEST_CANCELED, path, {"id": download_id}
                    )
                    break

                chunk = fp.read(chunk_size)
                if chunk == b"":
                    self.web.done = True
                else:
                    try:
                        yield chunk

                        # tell GUI the progress
                        downloaded_bytes = fp.tell()
                        percent = (1.0 * downloaded_bytes / self.filesize) * 100

                        # only output to stdout if running onionshare in CLI mode, or if using Linux (#203, #304)
                        if (
                            not self.web.is_gui
                            or self.common.platform == "Linux"
                            or self.common.platform == "BSD"
                        ):
                            sys.stdout.write(
                                "\r{0:s}, {1:.2f}%          ".format(
                                    self.common.human_readable_filesize(
                                        downloaded_bytes
                                    ),
                                    percent,
                                )
                            )
                            sys.stdout.flush()

                        self.web.add_request(
                            self.web.REQUEST_PROGRESS,
                            path,
                            {"id": download_id, "bytes": downloaded_bytes},
                        )
                        self.web.done = False
                    except:
                        # looks like the download was canceled
                        self.web.done = True
                        canceled = True

                        # tell the GUI the download has canceled
                        self.web.add_request(
                            self.web.REQUEST_CANCELED, path, {"id": download_id}
                        )

            fp.close()

            if self.common.platform != "Darwin":
                sys.stdout.write("\n")

            # Download is finished
            if not self.web.stay_open:
                self.download_in_progress = False

            # Close the server, if necessary
            if not self.web.stay_open and not canceled:
                print(strings._("closing_automatically"))
                self.web.running = False
                try:
                    if shutdown_func is None:
                        raise RuntimeError("Not running with the Werkzeug Server")
                    shutdown_func()
                except:
                    pass

        r = Response(generate())
        if use_gzip:
            r.headers.set("Content-Encoding", "gzip")
        r.headers.set("Content-Length", self.filesize)
        r.headers.set("Content-Disposition", "attachment", filename=basename)
        r = self.web.add_security_headers(r)
        # guess content type
        (content_type, _) = mimetypes.guess_type(basename, strict=False)
        if content_type is not None:
            r.headers.set("Content-Type", content_type)
        return r


# Traceback (KeyError)
[Jan 07 2019 20:58:37] Onion.cleanup: trying to remove onion 5yym6w3kg4tof56umfy6a632nvtoc5dkkpkhj4zd2slqzp5wuiwml7yd
=> 2.4 MiB         video 1.mov[Jan 07 2019 20:58:37] ReceiveMode.update_primary_action
Traceback (most recent call last):
File "onionshare_gui/onionshare_gui.py", line 382, in timer_callback
mode.handle_request_progress(event)
File "onionshare_gui/mode/receive_mode/__init__.py", line 159, in handle_request_progress
'progress': event["data"]["progress"]
File "onionshare_gui/mode/history.py", line 451, in update
self.item_list.update(id, data)
File "onionshare_gui/mode/history.py", line 347, in update
self.items[id].update(data)
KeyError: 0
=> 2.4 MiB         video 1.movAbort trap: 6

# Fixed code
def define_routes(self):
    """
    The web app routes for sharing files
    """

    @self.web.app.route("/<slug_candidate>")
    def index(slug_candidate):
        self.web.check_slug_candidate(slug_candidate)
        return index_logic()

    @self.web.app.route("/")
    def index_public():
        if not self.common.settings.get("public_mode"):
            return self.web.error404()
        return index_logic()

    def index_logic(slug_candidate=""):
        """
        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
        # currently a download
        deny_download = not self.web.stay_open and self.download_in_progress
        if deny_download:
            r = make_response(render_template("denied.html"))
            return self.web.add_security_headers(r)

        # If download is allowed to continue, serve download page
        if self.should_use_gzip():
            self.filesize = self.gzip_filesize
        else:
            self.filesize = self.download_filesize

        if self.web.slug:
            r = make_response(
                render_template(
                    "send.html",
                    slug=self.web.slug,
                    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,
                )
            )
        else:
            # If download is allowed to continue, serve download page
            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,
                )
            )
        return self.web.add_security_headers(r)

    @self.web.app.route("/<slug_candidate>/download")
    def download(slug_candidate):
        self.web.check_slug_candidate(slug_candidate)
        return download_logic()

    @self.web.app.route("/download")
    def download_public():
        if not self.common.settings.get("public_mode"):
            return self.web.error404()
        return download_logic()

    def download_logic(slug_candidate=""):
        """
        Download the zip file.
        """
        # Deny new downloads if "Stop After First Download" is checked and there is
        # currently a download
        deny_download = not self.web.stay_open and self.download_in_progress
        if deny_download:
            r = make_response(render_template("denied.html"))
            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")
        path = request.path

        # 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
        # and serve that
        use_gzip = self.should_use_gzip()
        if use_gzip:
            file_to_download = self.gzip_filename
            self.filesize = self.gzip_filesize
        else:
            file_to_download = self.download_filename
            self.filesize = self.download_filesize

        # Tell GUI the download started
        self.web.add_request(
            self.web.REQUEST_STARTED, path, {"id": download_id, "use_gzip": use_gzip}
        )

        basename = os.path.basename(self.download_filename)

        def generate():
            # Starting a new download
            if not self.web.stay_open:
                self.download_in_progress = True

            chunk_size = 102400  # 100kb

            fp = open(file_to_download, "rb")
            self.web.done = False
            canceled = False
            while not self.web.done:
                # 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}
                    )
                    break

                chunk = fp.read(chunk_size)
                if chunk == b"":
                    self.web.done = True
                else:
                    try:
                        yield chunk

                        # tell GUI the progress
                        downloaded_bytes = fp.tell()
                        percent = (1.0 * downloaded_bytes / self.filesize) * 100

                        # only output to stdout if running onionshare in CLI mode, or if using Linux (#203, #304)
                        if (
                            not self.web.is_gui
                            or self.common.platform == "Linux"
                            or self.common.platform == "BSD"
                        ):
                            sys.stdout.write(
                                "\r{0:s}, {1:.2f}%          ".format(
                                    self.common.human_readable_filesize(
                                        downloaded_bytes
                                    ),
                                    percent,
                                )
                            )
                            sys.stdout.flush()

                        self.web.add_request(
                            self.web.REQUEST_PROGRESS,
                            path,
                            {"id": download_id, "bytes": downloaded_bytes},
                        )
                        self.web.done = False
                    except:
                        # looks like the download was canceled
                        self.web.done = True
                        canceled = True

                        # tell the GUI the download has canceled
                        self.web.add_request(
                            self.web.REQUEST_CANCELED, path, {"id": download_id}
                        )

            fp.close()

            if self.common.platform != "Darwin":
                sys.stdout.write("\n")

            # Download is finished
            if not self.web.stay_open:
                self.download_in_progress = False

            # Close the server, if necessary
            if not self.web.stay_open and not canceled:
                print(strings._("closing_automatically"))
                self.web.running = False
                try:
                    if shutdown_func is None:
                        raise RuntimeError("Not running with the Werkzeug Server")
                    shutdown_func()
                except:
                    pass

        r = Response(generate())
        if use_gzip:
            r.headers.set("Content-Encoding", "gzip")
        r.headers.set("Content-Length", self.filesize)
        r.headers.set("Content-Disposition", "attachment", filename=basename)
        r = self.web.add_security_headers(r)
        # guess content type
        (content_type, _) = mimetypes.guess_type(basename, strict=False)
        if content_type is not None:
            r.headers.set("Content-Type", content_type)
        return r