From f93eef848ce069322cac917b901c4493abeb14e1 Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Mon, 20 Apr 2015 07:50:47 +0200 Subject: [PATCH] Store QUTE_TEXT/QUTE_HTML in files for userscripts. Fixes #644. --- CHANGELOG.asciidoc | 8 ++++ doc/userscripts.asciidoc | 4 +- qutebrowser/browser/commands.py | 8 ++-- qutebrowser/browser/hints.py | 3 +- qutebrowser/commands/userscripts.py | 60 ++++++++++++++++++++++++----- 5 files changed, 66 insertions(+), 17 deletions(-) diff --git a/CHANGELOG.asciidoc b/CHANGELOG.asciidoc index 4be5cb04f..c9797bfe7 100644 --- a/CHANGELOG.asciidoc +++ b/CHANGELOG.asciidoc @@ -14,6 +14,14 @@ This project adheres to http://semver.org/[Semantic Versioning]. // `Fixed` for any bug fixes. // `Security` to invite users to upgrade in case of vulnerabilities. +v0.3.0 (unreleased) +------------------- + +Changed +~~~~~~~ + +- `QUTE_HTML` and `QUTE_TEXT` for userscripts now don't store the contents directly, and instead contain a filename. + https://github.com/The-Compiler/qutebrowser/releases/tag/v0.2.1[v0.2.1] ----------------------------------------------------------------------- diff --git a/doc/userscripts.asciidoc b/doc/userscripts.asciidoc index 7fd22f914..349f0055a 100644 --- a/doc/userscripts.asciidoc +++ b/doc/userscripts.asciidoc @@ -24,8 +24,8 @@ The following environment variables will be set when an userscript is launched: command or key binding). - `QUTE_USER_AGENT`: The currently set user agent. - `QUTE_FIFO`: The FIFO or file to write commands to. -- `QUTE_HTML`: The HTML source of the current page. -- `QUTE_TEXT`: The plaintext of the current page. +- `QUTE_HTML`: Path of a file containing the HTML source of the current page. +- `QUTE_TEXT`: Path of a file containing the plaintext of the current page. In `command` mode: diff --git a/qutebrowser/browser/commands.py b/qutebrowser/browser/commands.py index 7349e9a03..1addbd8f7 100644 --- a/qutebrowser/browser/commands.py +++ b/qutebrowser/browser/commands.py @@ -876,14 +876,13 @@ class CommandDispatcher: env['QUTE_TITLE'] = tabbed_browser.page_title(idx) webview = tabbed_browser.currentWidget() - if webview is not None: + if webview is None: + mainframe = None + else: if webview.hasSelection(): env['QUTE_SELECTED_TEXT'] = webview.selectedText() env['QUTE_SELECTED_HTML'] = webview.selectedHtml() mainframe = webview.page().mainFrame() - if mainframe is not None: - env['QUTE_HTML'] = mainframe.toHtml() - env['QUTE_TEXT'] = mainframe.toPlainText() try: url = tabbed_browser.current_url() @@ -892,6 +891,7 @@ class CommandDispatcher: else: env['QUTE_URL'] = url.toString(QUrl.FullyEncoded) + env.update(userscripts.store_source(mainframe)) userscripts.run(cmd, *args, win_id=self._win_id, env=env) @cmdutils.register(instance='command-dispatcher', scope='window') diff --git a/qutebrowser/browser/hints.py b/qutebrowser/browser/hints.py index 2a6341b03..ce051228b 100644 --- a/qutebrowser/browser/hints.py +++ b/qutebrowser/browser/hints.py @@ -523,12 +523,11 @@ class HintManager(QObject): 'QUTE_MODE': 'hints', 'QUTE_SELECTED_TEXT': str(elem), 'QUTE_SELECTED_HTML': elem.toOuterXml(), - 'QUTE_HTML': frame.toHtml(), - 'QUTE_TEXT': frame.toPlainText(), } url = self._resolve_url(elem, context.baseurl) if url is not None: env['QUTE_URL'] = url.toString(QUrl.FullyEncoded) + env.update(userscripts.store_source(frame)) userscripts.run(cmd, *args, win_id=self._win_id, env=env) def _spawn(self, url, context): diff --git a/qutebrowser/commands/userscripts.py b/qutebrowser/commands/userscripts.py index 5612263af..85c511165 100644 --- a/qutebrowser/commands/userscripts.py +++ b/qutebrowser/commands/userscripts.py @@ -101,6 +101,7 @@ class _BaseUserscriptRunner(QObject): self._win_id = win_id self._filepath = None self._proc = None + self._env = None def _run_process(self, cmd, *args, env): """Start the given command via QProcess. @@ -110,6 +111,7 @@ class _BaseUserscriptRunner(QObject): *args: The arguments to hand to the command env: A dictionary of environment variables to add. """ + self._env = env self._proc = QProcess(self) procenv = QProcessEnvironment.systemEnvironment() procenv.insert('QUTE_FIFO', self._filepath) @@ -122,17 +124,26 @@ class _BaseUserscriptRunner(QObject): self._proc.start(cmd, args) def _cleanup(self): - """Clean up the temporary file.""" - log.procs.debug("Deleting temporary file {}.".format(self._filepath)) - try: - os.remove(self._filepath) - except OSError as e: - # NOTE: Do not replace this with "raise CommandError" as it's - # executed async. - message.error(self._win_id, - "Failed to delete tempfile... ({})".format(e)) + """Clean up temporary files.""" + tempfiles = [self._filepath] + if self._env is not None: + if 'QUTE_HTML' in self._env: + tempfiles.append(self._env['QUTE_HTML']) + if 'QUTE_TEXT' in self._env: + tempfiles.append(self._env['QUTE_TEXT']) + for fn in tempfiles: + log.procs.debug("Deleting temporary file {}.".format(fn)) + try: + os.remove(fn) + except OSError as e: + # NOTE: Do not replace this with "raise CommandError" as it's + # executed async. + message.error( + self._win_id, "Failed to delete tempfile {} ({})!".format( + fn, e)) self._filepath = None self._proc = None + self._env = None def run(self, cmd, *args, env=None): """Run the userscript given. @@ -305,6 +316,37 @@ else: UserscriptRunner = _DummyUserscriptRunner +def store_source(frame): + """Store HTML/plaintext in files. + + This writes files containing the HTML/plaintext source of the page, and + returns a dict with the paths as QUTE_HTML/QUTE_TEXT. + + Args: + frame: The QWebFrame to get the info from, or None to do nothing. + + Return: + A dictionary with the needed environment variables. + + Warning: + The caller is responsible to delete the files after using them! + """ + if frame is None: + return {} + env = {} + with tempfile.NamedTemporaryFile(mode='w', encoding='utf-8', + suffix='.html', + delete=False) as html_file: + html_file.write(frame.toHtml()) + env['QUTE_HTML'] = html_file.name + with tempfile.NamedTemporaryFile(mode='w', encoding='utf-8', + suffix='.txt', + delete=False) as txt_file: + txt_file.write(frame.toPlainText()) + env['QUTE_TEXT'] = txt_file.name + return env + + def run(cmd, *args, win_id, env): """Convenience method to run an userscript.