And where exactly does the "user experience" fit in to all of this cool server side trickery? I mean, even in a basic swing application I would disable input on things people aren't allowed to use when I'm doing something that will potentially take a long time to complete.
The browser is your friend, not a place where scary hacks happen. It's your UI, embrace it. ;) On 11/15/06, Nick Westgate <[EMAIL PROTECTED]> wrote:
IMO, disabling a submit with javascript is a hack. The problem is common, and a natural consequence of using Tapestry to develop a web application. Tapestry should be taking care of it for us. In any case, this can be solved in the same way that the old "locked after a commit()" errors in T3 were. I think T4 (via hivemind?) has fixed that particular incarnation. (It happened with all kinds of requests, and when using frames etc.) Use a filter to queue requests from the same client, or discard new ones: http://www.onjava.com/pub/a/onjava/2004/03/24/loadcontrol.html Use a Flow Synchronizer to handle form reposts: http://www.junlu.com/msg/85270.html I find the Flow Synchronizer particularly useful, as I put the bean in my border component and add handling methods to my base page class. Methods such as a simple isRepost() allow special casing the request - to avoid repeating a delete, for instance, but allowing other reposts to proceed. You'll find plenty of posts on the above topics in the list archives. Cheers, Nick. John Menke wrote: > The filter solution does use a unique token on the form and you can disable > the filter by not including the token on a form. I did have to add > logic to > the posted solution to handle errors but even with that code included the > code seems to be non-invasive -- all it does is check for form variable and > continues normal processing or blocks duplicate requests while "caching" > the > response (sounds more complicated than it is) > > i do see what you mean about the security concern and someone being able to > manipulate a post to get past the filter, trying to think of solutions to > this problem > > maybe something where the form included a secure key in a hidden variable > and having some sort of check which could determine if a key had been used > already > > if form is secure > -- check for valid and unique key > -- if key is valid then process the form and expire the key > -- don't let another request pass through after key is expired or absent > > above solution does require the ability to mark certain forms as secure on > the server side. > > with security in place i think the filter solution could be a complete > server side solution. I know you mentioned possible side effects did you > have anything specific in mind? > > Bottom line is that there should be a server side solution to this problem > in tapestry that is secure and non-invasive. I encourage others to post > their ideas in an effort to come to some sort of agreement on best way to > accomplish this. > > -john > > > > On 11/15/06, Sam Gendler <[EMAIL PROTECTED]> wrote: >> >> That seems like a complex solution to the problem which does things in >> a filter, where it might be difficult to predict side effects or >> override the behaviour in certain circumstances. I'd be more inclined >> to implement a unique token solution in a base page class so that I >> could overload it in certain pages, if necessary. Simplest solution, >> but not entirely error proof, would be to stick a unique token in the >> form (I'm not use you can use a session persistent property in the >> page, as I don't know when those get written into the session - >> possibly only after the page is finished processing). Then, when >> processing any form, check the session location for a token, if it >> matches, just send back a page saying "don't do that." If it isn't >> found, assume that this is the first time you've seen the form and go >> ahead and process it. You can add increasing complexity to such a >> solution depending on what kind of user experience you want and how >> error-proof you want it. The filter trick is cute, since you can >> actually serve the same response to multiple requests, but that is >> often not necessary and sometimes not even desired and it takes too >> much logic out of the core application for my own comfort level. >> >> But disabling a button can be pretty effective against all but an >> actually malicious user (does anyone build javascript-free web apps >> these days, especially in tapestry?), and a malicious user can >> override a unique token all too easily, anyway. If there is a true >> security or data integrity concern, you'll have to do something that >> is entirely on the server side in order to prevent manipulation by >> someone with the smarts to interpret an html file and manually send a >> post. >> >> --sam >> >> On 11/15/06, John Menke <[EMAIL PROTECTED]> wrote: >> > Is there a non-javascript solution to this problem? I have been >> > experimenting with code based on the forum post below. Has anyone >> developed >> > a solution for Tapestry? I propose some sort of consensus should >> > be reached as to what the best method is to handle double submits and a >> > patch should be made for Tapestry. Any comments? Ideas? >> > >> > <quote from Forum Post> >> > There is a server-side solution for this problem. Here is the concept: >> > Build a way to identify each form from which a request (or multiple >> > requests, if the form button is clicked several times) arrives. This >> can >> be >> > done by having a hidden input element included in the form, whose value >> is a >> > unique number (typically using the time in milliseconds). >> > >> > Write a filter implementing the javax.servlet.Filter interface, with >> the >> > following logic in the doFilter() method: >> > Synchronize a code block on a session-scoped object. Inside this block, >> > check if the form-id received through the current request is same as >> the >> one >> > received previously. >> > If different, this is the first request received from the form (i.e. >> the >> > request originated as a result of the first click). If same, this is a >> > subsequent request, generated as a result of multiple clicks. >> > >> > In the first case, invoke FilterChain.doFilter() by passing a >> > ResponseWrapper object instead of the original response object. This >> > ResponseWrapper object should be built with a ByteArrayOutputStream >> object, >> > so that the response content can be extracted as a String. When the >> > FilterChain.doFilter() method returns, save the response content and >> the >> > current form-id in session-scope, for subsequent requests and leave the >> > synchronized block. >> > >> > Then outside the synchronized block, forward all the requests >> (including >> the >> > first one) to a "LoopBackServlet" with the original "request" and >> "response" >> > objects. The whole purpose of this "LoopBackServlet" is to write the >> saved >> > response content into the response object. >> > >> > In this way, when multiple requests arrive from the same form as a >> result of >> > multiple clicks, we let the first request thread proceed, with a >> > response-wrapper and block all the other threads. When the first thread >> > returns with the response ready, the response content is stored in >> session >> > and the same is written to all the blocked threads when they become >> > unblocked. >> > >> > If anybody wants more details, please email me at >> [EMAIL PROTECTED], I >> can >> > send the working code. >> > >> > >> > </quote from Forum Post> >> > >> > http://forum.java.sun.com/thread.jspa?threadID=665472&start=15&tstart=0 >> > >> > >> > >> > On 11/15/06, Denis McCarthy <[EMAIL PROTECTED]> wrote: >> > > >> > > I was looking for a sledgehammer to crack a nut. That's how I >> ended up >> > > doing it (after spending the day looking for an enterprisey >> solution!) >> > > Thanks >> > > Denis >> > > >> > > Jesse Kuhnert wrote: >> > > > Why don't you just disable the submit buttons in question when they >> > > submit? >> > > > (set the disabled attribute to true) >> > > > >> > > > On 11/15/06, Denis McCarthy <[EMAIL PROTECTED]> wrote: >> > > >> >> > > >> Hi, >> > > >> I'm encountering a problem in my app where users are double >> submitting >> > > a >> > > >> form, creating a hibernate exception in the back end where two >> > > >> sessions are attempting to update the same collection. I've read >> some >> > > >> posts about preventing form resubmission by using a unique >> token in >> the >> > > >> form to detect a double submit. >> > > >> >> > > >> If a double submit is detected, the second and subsequent submits >> wait >> > > >> until the original one returns and then report the outcome of that >> > > >> transaction (if I understand correctly, it's the last submit that >> > > issues >> > > >> the response to the user, and the first one does the updating). >> > > >> >> > > >> I'm wondering >> > > >> a) is this indeed the right approach to stop users who are >> > > >> over-enthusiastic in their button clicking from encountering >> errors, >> > > and >> > > >> b) does anyone have an actual example of code that implements this >> > > >> pattern? >> > > >> Thanks very much >> > > >> Denis Mc. >> > > >> >> > > >> >> --------------------------------------------------------------------- >> > > >> To unsubscribe, e-mail: [EMAIL PROTECTED] >> > > >> For additional commands, e-mail: [EMAIL PROTECTED] >> > > >> >> > > >> >> > > > >> > > > >> > > >> > > --------------------------------------------------------------------- >> > > To unsubscribe, e-mail: [EMAIL PROTECTED] >> > > For additional commands, e-mail: [EMAIL PROTECTED] >> > > >> > > >> > >> > >> >> --------------------------------------------------------------------- >> To unsubscribe, e-mail: [EMAIL PROTECTED] >> For additional commands, e-mail: [EMAIL PROTECTED] >> >> > --------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]
-- Jesse Kuhnert Tapestry/Dojo/(and a dash of TestNG), team member/developer Open source based consulting work centered around dojo/tapestry/tacos/hivemind. http://blog.opencomponentry.com