Repository: qutebrowser/qutebrowser

Issue:
ValueError: fileobj was already set! (opening downloads twice)
Report on v0.9.1 with QtWebKit and Qt 5.5.1, on Windows:

> I think I hit ctrl+x twice and before the prompt opened..

```
11:17:56 DEBUG    downloads  qtnetworkdownloads:fetch:464 fetch: PyQt5.QtCore.QUrl('http://sharepoint/sites/esec/it/IT Documentation/Network/Cham Switches Inventory.xlsx') -> Cham Switches Inventory.xlsx
11:17:56 DEBUG    downloads  downloads:_on_begin_insert_row:837 _on_begin_insert_row with idx 1, webengine False
11:17:56 DEBUG    misc       standarddir:_writable_location:143 writable location for DownloadLocation: C:/Users/emp8120192/Downloads
11:17:56 DEBUG    prompt     prompt:ask_question:151 Asking question <qutebrowser.utils.usertypes.Question default='C:\\Users\\emp8120192\\Downloads\\' mode=<PromptMode.download: 5> text='Please enter a location for <b>http://sharepoint/sites/esec/it/IT Documentation/Network/Cham Switches Inventory.xlsx</b>' title='Save file to:'>, blocking False, loops [], queue deque([])
11:17:56 DEBUG    prompt     prompt:_on_show_prompts:311 Displaying prompt qutebrowser.mainwindow.prompt.DownloadFilenamePrompt(question=<qutebrowser.utils.usertypes.Question default='C:\\Users\\emp8120192\\Downloads\\' mode=<PromptMode.download: 5> text='Please enter a location for <b>http://sharepoint/sites/esec/it/IT Documentation/Network/Cham Switches Inventory.xlsx</b>' title='Save file to:'>)
11:17:56 DEBUG    modes      modeman:enter:237 Entering mode KeyMode.prompt (reason: question asked)
11:17:56 DEBUG    statusbar  text:set_text:55 Setting normal text to '-- PROMPT MODE --'.
11:17:56 DEBUG    statusbar  bar:set_mode_active:239 Setting prompt_active to True
11:17:56 DEBUG    webview    webview:on_mode_entered:168 Ignoring focus because mode KeyMode.prompt was entered.
11:17:56 DEBUG    webview    webview:on_mode_entered:168 Ignoring focus because mode KeyMode.prompt was entered.
11:17:56 DEBUG    misc       app:on_focus_object_changed:768 Focus object changed: <qutebrowser.mainwindow.prompt.LineEdit>
11:17:56 DEBUG    misc       mainwindow:_update_overlay_geometry:255 new geometry for <qutebrowser.mainwindow.prompt.PromptContainer win_id=0>: PyQt5.QtCore.QRect(10, 786, 1901, 377)
11:17:56 DEBUG    webview    browsertab:_set_load_status:587 load status for <qutebrowser.browser.webkit.webkittab.WebKitTab tab_id=8 url='http://sharepoint/sites/esec/it/IT Documentation/Forms/AllItems.aspx?RootFolder=%2Fsites%2Fesec%2Fi…'>: LoadStatus.success
11:17:56 DEBUG    signals    signalfilter:_filter_signals:86 emitting: cur_load_status_changed('success') (tab 1)
11:17:56 DEBUG    signals    signalfilter:_filter_signals:86 emitting: cur_load_finished(True) (tab 1)
11:17:56 DEBUG    downloads  qtnetworkdownloads:_on_reply_finished:261 Reply finished, fileobj None
11:17:57 DEBUG    modes      modeman:_eventFilter_keypress:166 got keypress in mode KeyMode.prompt - delegating to <qutebrowser.keyinput.keyparser.PassthroughKeyParser mode='prompt' warn=False>
11:17:57 DEBUG    modes      modeman:_eventFilter_keypress:191 handled: False, forward-unbound-keys: auto, passthrough: True, is_non_alnum: True --> filter: False (focused: <qutebrowser.mainwindow.prompt.LineEdit>)
11:17:57 DEBUG    modes      modeman:_eventFilter_keypress:166 got keypress in mode KeyMode.prompt - delegating to <qutebrowser.keyinput.keyparser.PassthroughKeyParser mode='prompt' warn=False>
11:17:57 DEBUG    commands   command:run:509 command called: prompt-open-download
11:17:57 DEBUG    commands   command:run:524 Calling qutebrowser.mainwindow.prompt.PromptContainer.prompt_open_download(<qutebrowser.mainwindow.prompt.PromptContainer win_id=0>, None)
11:17:57 DEBUG    downloads  qtnetworkdownloads:_set_fileobj:211 buffer: 0 bytes
11:17:57 DEBUG    downloads  qtnetworkdownloads:_on_reply_finished:261 Reply finished, fileobj <tempfile._TemporaryFileWrapper object at 0x0000000050586E80>
11:17:57 DEBUG    downloads  qtnetworkdownloads:_finish_download:232 Finishing download...
11:17:57 DEBUG    downloads  downloads:open_file:532 Opening C:\Users\EMP812~1\AppData\Local\Temp\qutebrowser-downloads-wijpoh6e\tmp7nwfm1snCham Switches Inventory.xlsx with the system application
11:17:57 DEBUG    modes      modeman:_eventFilter_keyrelease:211 filter: False
11:17:57 DEBUG    modes      modeman:_eventFilter_keyrelease:211 filter: True
11:17:59 DEBUG    modes      modeman:_eventFilter_keypress:166 got keypress in mode KeyMode.prompt - delegating to <qutebrowser.keyinput.keyparser.PassthroughKeyParser mode='prompt' warn=False>
11:17:59 DEBUG    modes      modeman:_eventFilter_keypress:191 handled: False, forward-unbound-keys: auto, passthrough: True, is_non_alnum: True --> filter: False (focused: <qutebrowser.mainwindow.prompt.LineEdit>)
11:18:00 DEBUG    modes      modeman:_eventFilter_keypress:166 got keypress in mode KeyMode.prompt - delegating to <qutebrowser.keyinput.keyparser.PassthroughKeyParser mode='prompt' warn=False>
11:18:00 DEBUG    commands   command:run:509 command called: prompt-open-download
11:18:00 DEBUG    commands   command:run:524 Calling qutebrowser.mainwindow.prompt.PromptContainer.prompt_open_download(<qutebrowser.mainwindow.prompt.PromptContainer win_id=0>, None)
11:18:00 ERROR    misc       crashsignal:exception_hook:205 Uncaught exception
Traceback (most recent call last):
  File "scripts/dev\..\..\scripts\..\qutebrowser\browser\downloads.py", line 668, in set_target
  File "scripts/dev\..\..\scripts\..\qutebrowser\browser\qtnetworkdownloads.py", line 228, in _set_tempfile
  File "scripts/dev\..\..\scripts\..\qutebrowser\browser\qtnetworkdownloads.py", line 206, in _set_fileobj
ValueError: fileobj was already set! Old: <tempfile._TemporaryFileWrapper object at 0x0000000050586E80>, new: <tempfile._TemporaryFileWrapper object at 0x000000005058B160>
```

Haven't been able to reproduce so far. One for @Kingdread? :wink:


Discussion:
Strange... Shouldn't `prompt-open-download` do nothing when not in prompt mode? So is the second keypress handled while *still* being somehow in prompt mode? 🤔 

Unfortunately I'm still a bit busy with a university project (and the deadline is approaching), so it's going to take me a bit of time until I can take a look at it :smirk:
Yeah, from the log it looks like prompt mode was never left. I know that feeling, take your time!
Just got another one:

```
02:31:31 DEBUG    webview    webpage:acceptNavigationRequest:478 navigation request: url https://www.nyaa.se/?page=download&tid=568486, type NavigationTypeLinkClicked, target ClickTarget.normal override None
[...]
02:31:37 DEBUG    downloads  qtnetworkdownloads:fetch:464 fetch: PyQt5.QtCore.QUrl('https://www.nyaa.se/?page=download&tid=568486') -> 6b641af6a467f05580163464c3802b97d801e089.torrent
02:31:37 DEBUG    downloads  downloads:_on_begin_insert_row:837 _on_begin_insert_row with idx 0, webengine False
02:31:37 DEBUG    misc       standarddir:_writable_location:143 writable location for DownloadLocation: E:/lithrein/Downloads
02:31:37 DEBUG    prompt     prompt:ask_question:151 Asking question <qutebrowser.utils.usertypes.Question default='E:\\lithrein\\Downloads\\' mode=<PromptMode.download: 5> text='Please enter a location for <b>https://www.nyaa.se/?page=download&amp;tid=568486</b>' title='Save file to:'>, blocking False, loops [], queue deque([])
02:31:37 DEBUG    prompt     prompt:_on_show_prompts:311 Displaying prompt qutebrowser.mainwindow.prompt.DownloadFilenamePrompt(question=<qutebrowser.utils.usertypes.Question default='E:\\lithrein\\Downloads\\' mode=<PromptMode.download: 5> text='Please enter a location for <b>https://www.nyaa.se/?page=download&amp;tid=568486</b>' title='Save file to:'>)
[...]
02:31:37 DEBUG    webview    browsertab:_set_load_status:587 load status for <qutebrowser.browser.webkit.webkittab.WebKitTab tab_id=1 url='https://www.nyaa.se/?page=view&tid=568486&showfiles=c997685f'>: LoadStatus.success_https
02:31:37 DEBUG    signals    signalfilter:_filter_signals:86 emitting: cur_load_status_changed('success_https') (tab 2)
02:31:37 DEBUG    signals    signalfilter:_filter_signals:86 emitting: cur_load_finished(True) (tab 2)
02:31:38 DEBUG    downloads  qtnetworkdownloads:_on_reply_finished:261 Reply finished, fileobj None
[...]
02:31:40 DEBUG    commands   command:run:509 command called: prompt-open-download
02:31:40 DEBUG    commands   command:run:524 Calling qutebrowser.mainwindow.prompt.PromptContainer.prompt_open_download(<qutebrowser.mainwindow.prompt.PromptContainer win_id=0>, None)
02:31:40 DEBUG    downloads  qtnetworkdownloads:_set_fileobj:211 buffer: 0 bytes
02:31:40 DEBUG    downloads  qtnetworkdownloads:_on_reply_finished:261 Reply finished, fileobj <tempfile._TemporaryFileWrapper object at 0x00000000008B8940>
02:31:40 DEBUG    downloads  qtnetworkdownloads:_finish_download:232 Finishing download...
02:31:40 DEBUG    downloads  downloads:open_file:532 Opening C:\Users\lithrein\AppData\Local\Temp\qutebrowser-downloads-kvyrtc5j\tmpp92lw45d6b641af6a467f05580163464c3802b97d801e089.torrent with the system application
02:31:40 DEBUG    modes      modeman:_eventFilter_keyrelease:211 filter: False
02:31:40 DEBUG    modes      modeman:_eventFilter_keyrelease:211 filter: True
02:31:42 DEBUG    modes      modeman:_eventFilter_keypress:166 got keypress in mode KeyMode.prompt - delegating to <qutebrowser.keyinput.keyparser.PassthroughKeyParser mode='prompt' warn=False>
02:31:42 DEBUG    commands   command:run:509 command called: prompt-accept
02:31:42 DEBUG    commands   command:run:524 Calling qutebrowser.mainwindow.prompt.PromptContainer.prompt_accept(<qutebrowser.mainwindow.prompt.PromptContainer win_id=0>, None)
02:31:42 DEBUG    modes      modeman:leave:289 Leaving mode KeyMode.prompt (reason: :prompt-accept)
[...]
02:31:42 ERROR    misc       crashsignal:exception_hook:205 Uncaught exception
Traceback (most recent call last):
  File "scripts/dev\..\..\scripts\..\qutebrowser\browser\downloads.py", line 657, in set_target
  File "scripts/dev\..\..\scripts\..\qutebrowser\browser\downloads.py", line 589, in _set_filename
  File "scripts/dev\..\..\scripts\..\qutebrowser\browser\qtnetworkdownloads.py", line 186, in _ensure_can_set_filename
ValueError: fileobj was already set! filename: E:\lithrein\Downloads\, existing: None, fileobj <tempfile._TemporaryFileWrapper object at 0x00000000008B8940>
```
Was able to reproduce it. Simply open download prompt twice and then press `ctrl+x ctrl+x`
I still can't reproduce it. Opened two downloads with QtWebKit, pressed that, but it all seems to work fine.
Ah the crash is only happening with Microsoft Office Products (Tested Word, Excel 2010 & Visio 2013) and only if `2x ctrl+x` is pressed before the first instance of Office opens.

I could reproduce it. It worked when downloading a PDF and pressing `Ctrl+x` very fast in the download window. After some analysis, I'd guess that it happens because the subprocess takes too long to start, blocking the prompt window and giving us more time for another `Ctrl+x`. This probably explains why it's easier on Windows (process creation takes longer), only works with an uncached application (I could only reproduce it after clearing the cache), and probably doesn't work on SDDs.

```
10:05:18 DEBUG    commands   command:run:509 command called: prompt-open-download
10:05:18 DEBUG    commands   command:run:524 Calling qutebrowser.mainwindow.prompt.PromptContainer.prompt_open_download(<qutebrowser.mainwindow.prompt.PromptContainer win_id=0>, None)
10:05:18 DEBUG    downloads  qtnetworkdownloads:_set_fileobj:211 buffer: 1024 bytes
10:05:18 DEBUG    downloads  qtnetworkdownloads:_on_reply_finished:261 Reply finished, fileobj <tempfile._TemporaryFileWrapper object at 0x0000000008959978>
10:05:18 DEBUG    downloads  qtnetworkdownloads:_finish_download:232 Finishing download...
10:05:18 DEBUG    misc       utils:open_file:858 Opening C:\Users\Daniel\AppData\Local\Temp\qutebrowser-downloads-bi6hzy0a\tmp2mai8b22IEEEtran_HOWTO.pdf with the system application
10:05:18 DEBUG    modes      modeman:_eventFilter_keyrelease:212 filter: True
10:05:18 DEBUG    modes      modeman:_eventFilter_keypress:167 got keypress in mode KeyMode.prompt - delegating to <qutebrowser.keyinput.keyparser.PassthroughKeyParser mode='prompt' warn=False>
10:05:18 DEBUG    commands   command:run:509 command called: prompt-open-download
10:05:18 DEBUG    commands   command:run:524 Calling qutebrowser.mainwindow.prompt.PromptContainer.prompt_open_download(<qutebrowser.mainwindow.prompt.PromptContainer win_id=0>, None)
10:05:18 ERROR    misc       crashsignal:exception_hook:205 Uncaught exception
Traceback (most recent call last):
  File "I:\Daniel\Downloads\qutebrowser\qutebrowser\browser\downloads.py", line 653, in set_target
    self._set_tempfile(fobj)
  File "I:\Daniel\Downloads\qutebrowser\qutebrowser\browser\qtnetworkdownloads.py", line 228, in _set_tempfile
    self._set_fileobj(fileobj)
  File "I:\Daniel\Downloads\qutebrowser\qutebrowser\browser\qtnetworkdownloads.py", line 206, in _set_fileobj
    "{}".format(self.fileobj, fileobj))
ValueError: fileobj was already set! Old: <tempfile._TemporaryFileWrapper object at 0x0000000008959978>, new: <tempfile._TemporaryFileWrapper object at 0x0000000008959D68>
```

Resolving patch:
diff --git a/qutebrowser/browser/downloads.py b/qutebrowser/browser/downloads.py
--- a/qutebrowser/browser/downloads.py
+++ b/qutebrowser/browser/downloads.py
@@ -529,7 +529,11 @@ def open_file(self, cmdline=None):
         if filename is None:  # pragma: no cover
             log.downloads.error("No filename to open the download!")
             return
-        utils.open_file(filename, cmdline)
+        # By using a singleshot timer, we ensure that we return fast. This
+        # is important on systems where process creation takes long, as
+        # otherwise the prompt might hang around and cause bugs
+        # (see issue #2296)
+        QTimer.singleShot(0, lambda: utils.open_file(filename, cmdline))
 
     def _ensure_can_set_filename(self, filename):
         """Make sure we can still set a filename."""


Test patch: