Opened 9 months ago
Last modified 9 months ago
#10393 new defect
POST data is lost after redirect
| Reported by: | ejucovy | Owned by: | ejucovy |
|---|---|---|---|
| Priority: | normal | Component: | PermRedirectPlugin |
| Severity: | normal | Keywords: | |
| Cc: | Trac Release: | 1.0 |
Description
The situation is described in comment:ticket:2210:14 and comment:ticket:2210:16 -- if a user has a browser window to a Trac edit screen open for a long enough time before submitting the edit form, their session can expire and they'll be redirected to the login screen. After successful login, they'll be redirected back to the edit screen, but their edits will be lost, which can be very annoying.
Simple way to reproduce in a browser:
- Log in to your trac site
- Open a browser tab to http://trac-site.com/newticket
- Fill in some text to create the new ticket
- Don't submit the form yet!
- Open a second browser tab to http://trac-site.com/logout and then close it
- Back in the first tab, submit the form
If PermRedirectPlugin is installed, you'll be redirected to the login screen; log in, and you'll land back on the "newticket" form. But all your hard work is completely lost.
I think that it's fair to consider this a bug in PermRedirectPlugin. The reason is that, without PermRedirectPlugin installed, Trac's behavior is "safer." If you follow the exact same reproduction steps without the plugin installed, you'll be given an "Error: Forbidden" screen that prompts you to log in.
This screen is actually rendering an HTTP response to the POST request, rather than instructing the browser to issue an immediate GET request like the plugin does. So this actually gives you an opportunity to log back in using a separate tab, and then simply hit "reload" on the first tab. Your browser will warn you that you're resubmitting a form via POST and ask if you really want to resubmit the data. You say yes, and the exact same POST request will be replayed, with your original intent fulfilled and no loss of data.
Attachments (0)
Change History (4)
comment:1 Changed 9 months ago by ejucovy
comment:2 Changed 9 months ago by ejucovy
The session-based approach is problematic because as soon as the user logs in, he's likely to have a different session than the one he had as an anonymous user.
comment:3 Changed 9 months ago by ejucovy
(4c) is problematic because there isn't necessarily a login form (in the case of Trac core HTTP auth)
comment:4 Changed 9 months ago by ejucovy
Hybrid idea:
- In post_process_request, if method==POST, set a (path-scoped?) "saved_post" cookie containing the POST body
- Add javascript to all pages such that on window.load
- Check if "saved_post" cookie is present; if it is, save its value to a Javascript variable and delete the cookie
- Then pop up a modal dialog: "You have unsaved data that you tried to submit earlier. Do you want to resubmit it?"
- If user clicks "Yes", use Javascript to fire a synchronous POST request using the exact request body from the cookie
(This is, obviously, getting pretty convoluted, but it's a fun problem to think about.)


UnwashedMeme outlined a few possible solutions:
Another class of solutions that occurs to me:
I think (1), (2), (4a) and (4c) are worth investigating, but all of these approaches are pretty ugly in one way or another.