RE: Form Double Submit Detection

2003-10-28 Thread Walker Chris
Tom,

You can also put JavaScript code in the form's onSubmit event code to
disable all the elements in the form.  To make sure this happens after
submission (otherwise nothing gets submitted) use window.setTimeout() to run
the disable script after a short delay.

Another alternative is to put a unique token in a hidden field.  The server
keeps track of these tokens: once one is spent by submitting the form it
can't be reused.  This is more bulletproof but needs more coding (though I
expect you could use a filter to localize it).

Chris


-Original Message-
From: Bill Lunnon [mailto:[EMAIL PROTECTED]
Sent: 27 October 2003 23:26
To: Tomcat Users List
Subject: RE: Form Double Submit Detection


Tom,
Don't know if this is complimentary to your workflow,
try a javascript confirm (ie a client side pop-up, asking the user to click
Ok to continue). This will catch any double clicks on the client side.

Hope this helps

Bill

-Original Message-
From: Tom Parker [mailto:[EMAIL PROTECTED]
Sent: Tuesday, 28 October 2003 10:18 AM
To: [EMAIL PROTECTED]
Subject: Form Double Submit Detection


I've designed my workflows so that they do not need to store anything in
the user's session. This allows the user to conduct more than one
instance of a particular task at the same time without data getting
mixed up. However this presents me with a problem if the user double
clicks the submit button and causes the server to do something twice.

The normal(?) way of detecting this would be to store a unique token in
the session and in the form, and compare them to ensure that the user
has not submitted this form twice. For this to work, you need to store
something in the session for each possible form submission. If the user
never submits the form, then the token will hang around for the life of
the session as we don't know that the user won't submit the form
someday.

Currently I'm thinking of allowing the user to store a finite number of
duplicate check tokens, or to make the tokens expire after an amount of
time. The former doesn't seem very attractive (load a record, view a
bunch of other records such that the first record's token is dropped,
save the first record - no token found), while the latter could lead to
rather a lot of tokens being stored.

Is there a solution to this problem that I'm missing?


-
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]


The information in this e:mail and any attachments or any 
reproduction of this e:mail in whatever manner is confidential 
and for the use of the addressee(s) only.  If you are not the 
addressee then the distribution, use or reproduction of this 
e:mail or the information within it is strictly prohibited and 
may be unlawful.  If received in error please advise the 
sender and delete all record of it from your system.  
Although believed to be virus free, accurate and complete,  
responsibility for any loss or cost arising from its receipt or 
use or its incomplete or inaccurate transmission is hereby 
excluded to the fullest extent possible.


-
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]



Re: Form Double Submit Detection

2003-10-28 Thread Adam Hardy
On 10/28/2003 10:42 AM Walker Chris wrote:
Tom,

You can also put JavaScript code in the form's onSubmit event code to
disable all the elements in the form.  To make sure this happens after
submission (otherwise nothing gets submitted) use window.setTimeout() to run
the disable script after a short delay.
Another alternative is to put a unique token in a hidden field.  The server
keeps track of these tokens: once one is spent by submitting the form it
can't be reused.  This is more bulletproof but needs more coding (though I
expect you could use a filter to localize it).
jakarta struts has some good token creation code in their TokenProcessor 
class.

Struts uses it so: on requesting the form, struts creates the token, 
stores it in a hidden field in the form and in the session. On submit, 
it checks the value of the hidden field against the value in the 
session. If they are not the same or are missing, it means the token in 
the form is invalid.

I suped up this mechanism to overcome the problem that users opening 
multiple windows would invalidate the tokens in the all but the most 
recently opened windows.

I don't store the token in the session. When the form submits, I check 
the session for a hashmap,  if the token is not in the hashmap, I allow 
the transaction and then put the token in the hashmap.

Adam

--
struts 1.1 + tomcat 5.0.12 + java 1.4.2
Linux 2.4.20 RH9
-
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]


Re: Form Double Submit Detection

2003-10-28 Thread Christopher Schultz
Justin,

Agreed.  One word of caution...

We actually synchronized on the session...
You aren't guaranteed to have the same HttpSession object for every 
request -- HttpSession is an interface which is implemented internally 
and wrapped by a facade.  Synchronizing on the actual object you get 
from req.getSession() can potentially leave you synchronizing on totally 
different objects.
Oh, hey. I never really thought of that, although I kinda knew it 
without ever giving it much thought. Does that mean that you can never 
have exclusive access to your own session?

Since the VM is allowed to play memory tricks when it thinks threads 
aren't related (which you can only do using memory barriers via 
synchronization), you can never be sure that the 'session' you're 
working with is in a consistent state or even valid. That's kinda scary. 
I'm guessing that in practical terms, there's rarely any reason to think 
that they're not predictable...

-chris

-
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]


RE: Form Double Submit Detection

2003-10-28 Thread Ralph Einfeldt
Yes you can, but the only safe way is to synchronize
on an object inside the session, not the session itself.
Or to synchronize on a more global object (but this 
is not recommended as this might not scale well for 
sites with many users)

 -Original Message-
 From: Christopher Schultz [mailto:[EMAIL PROTECTED]
 Sent: Tuesday, October 28, 2003 11:56 AM
 To: Tomcat Users List
 Subject: Re: Form Double Submit Detection
 
 
 without ever giving it much thought. Does that mean that you 
 can never have exclusive access to your own session?
 

-
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]



Re: Form Double Submit Detection

2003-10-28 Thread Tom Parker
On Tue, 2003-10-28 at 23:40, Adam Hardy wrote:

 I don't store the token in the session. When the form submits, I check 
 the session for a hashmap,  if the token is not in the hashmap, I allow 
 the transaction and then put the token in the hashmap.

Interesting. You store the successful tokens so they can't be used
again, and ignore the tokens that are never returned to the server. This
would be more efficient for the case where the user views but never
submits more forms than they view and do submit. I'll have to analyse my
traffic some time and see what my users are doing.

Currently I've implemented the opposite, I keep track of all the tokens
and drop those that the user returns. I also drop all tokens older than
2 hours (which means the user has 2 hours to submit any particular form
before the token goes away and they can't). (and obviously I store them
in the session so they all go away when the session does)

I like your solution better than mine.


-
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]



RE: Form Double Submit Detection

2003-10-27 Thread Bill Lunnon
Tom,
Don't know if this is complimentary to your workflow,
try a javascript confirm (ie a client side pop-up, asking the user to click
Ok to continue). This will catch any double clicks on the client side.

Hope this helps

Bill

-Original Message-
From: Tom Parker [mailto:[EMAIL PROTECTED]
Sent: Tuesday, 28 October 2003 10:18 AM
To: [EMAIL PROTECTED]
Subject: Form Double Submit Detection


I've designed my workflows so that they do not need to store anything in
the user's session. This allows the user to conduct more than one
instance of a particular task at the same time without data getting
mixed up. However this presents me with a problem if the user double
clicks the submit button and causes the server to do something twice.

The normal(?) way of detecting this would be to store a unique token in
the session and in the form, and compare them to ensure that the user
has not submitted this form twice. For this to work, you need to store
something in the session for each possible form submission. If the user
never submits the form, then the token will hang around for the life of
the session as we don't know that the user won't submit the form
someday.

Currently I'm thinking of allowing the user to store a finite number of
duplicate check tokens, or to make the tokens expire after an amount of
time. The former doesn't seem very attractive (load a record, view a
bunch of other records such that the first record's token is dropped,
save the first record - no token found), while the latter could lead to
rather a lot of tokens being stored.

Is there a solution to this problem that I'm missing?


-
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]



RE: Form Double Submit Detection

2003-10-27 Thread Tom Parker
On Tue, 2003-10-28 at 12:26, Bill Lunnon wrote:

 Don't know if this is complimentary to your workflow,
 try a javascript confirm (ie a client side pop-up, asking the user to click
 Ok to continue). This will catch any double clicks on the client side.

Unfortunatly I think our users would object to this solution.


-
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]



RE: Form Double Submit Detection

2003-10-27 Thread Justin Ruthenbeck
At 03:34 PM 10/27/2003, you wrote:
On Tue, 2003-10-28 at 12:26, Bill Lunnon wrote:

 Don't know if this is complimentary to your workflow,
 try a javascript confirm (ie a client side pop-up, asking the user to 
click
 Ok to continue). This will catch any double clicks on the client 
side.

Unfortunatly I think our users would object to this solution.
On the client side, how about writing a doOnSubmit() javascript function 
that increments a counter for the number of times it's been called.  If 
the function hasn't submitted the form (counter=0), submit it.  If the 
counter0, notify user of double submission.

Of course, if a user has multiple clients open with the same page open, 
this is no good (and you'd have to keep track on the server).

Server side, instead of putting a token in the session when the page is 
*served*, put a token in the session while the submission is being 
processed (use it like a semaphore).  The token has a finite lifecycle 
(created on form submission, death on submission response 
served).  There's no need to match tokens unless you're worried about 
something other than duplicate submission detection (such as security or 
time-based form relevance).

justin 

-
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]


RE: Form Double Submit Detection

2003-10-27 Thread Tom Parker
On Tue, 2003-10-28 at 12:51, Justin Ruthenbeck wrote:

 Server side, instead of putting a token in the session when the page is 
 *served*, put a token in the session while the submission is being 
 processed (use it like a semaphore).  The token has a finite lifecycle 
 (created on form submission, death on submission response 
 served).  

This only works if processing the two submissions overlaps. If the logic
to process the submission is very fast, or there is a long delay between
submissions, then this won't work.



-
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]



RE: Form Double Submit Detection

2003-10-27 Thread Justin Ruthenbeck
At 04:20 PM 10/27/2003, you wrote:
On Tue, 2003-10-28 at 12:51, Justin Ruthenbeck wrote:

 Server side, instead of putting a token in the session when the page 
is
 *served*, put a token in the session while the submission is being
 processed (use it like a semaphore).  The token has a finite lifecycle
 (created on form submission, death on submission response
 served).

This only works if processing the two submissions overlaps. If the logic
to process the submission is very fast, or there is a long delay between
submissions, then this won't work.
from original post
I've designed my workflows so that they do not need to store anything in
the user's session. This allows the user to conduct more than one
instance of a particular task at the same time without data getting
mixed up. However this presents me with a problem if the user double
clicks the submit button and causes the server to do something twice.
/from original post
If the logic to process the submission is very fast, then presumably your 
client would have a response before clicking the submit button again.  If 
there is a long delay between submissions, then you're dealing with an 
entirely different problem -- ie not user double clicks the submit 
button.

If you're truly worried about multiple submissions over long periods of 
time, then it sounds like your system is more transactional in 
nature.  That is, the system generates an eligible transaction on one 
call (form request), then executes that transaction on another (form 
submit).  In this case, controlling the execution of code should be done 
on the transaction object level (not request level).

justin 

-
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]


RE: Form Double Submit Detection

2003-10-27 Thread Tom Parker
On Tue, 2003-10-28 at 14:18, Justin Ruthenbeck wrote:
 At 04:20 PM 10/27/2003, you wrote:
 On Tue, 2003-10-28 at 12:51, Justin Ruthenbeck wrote:
 
   Server side, instead of putting a token in the session when the page 
  is
   *served*, put a token in the session while the submission is being
   processed (use it like a semaphore).  The token has a finite lifecycle
   (created on form submission, death on submission response
   served).
 
 This only works if processing the two submissions overlaps. If the logic
 to process the submission is very fast, or there is a long delay between
 submissions, then this won't work.
 
 from original post
 I've designed my workflows so that they do not need to store anything in
 the user's session. This allows the user to conduct more than one
 instance of a particular task at the same time without data getting
 mixed up. However this presents me with a problem if the user double
 clicks the submit button and causes the server to do something twice.
 /from original post
 
 If the logic to process the submission is very fast, then presumably your 
 client would have a response before clicking the submit button again.  If 
 there is a long delay between submissions, then you're dealing with an 
 entirely different problem -- ie not user double clicks the submit 
 button.

While the logic on the server is reasonably fast, we can't be sure that
the network latency is so low that the user can't double click, nor that
the server will always be fast all the time. In fact we have several
cases of this actually happening and two records being created on the
server.

 If you're truly worried about multiple submissions over long periods of 
 time, then it sounds like your system is more transactional in 
 nature.  That is, the system generates an eligible transaction on one 
 call (form request), then executes that transaction on another (form 
 submit).  In this case, controlling the execution of code should be done 
 on the transaction object level (not request level).

We do have concurrent update checking which catches this problem in most
cases. However that solution does not work when creating a brand new
record. From the server point of view it appears to be two requests to
create a record, which just happen to have the same details (and in this
case we don't want to prevent the user creating apparently duplicate
records, so that isn't a solution).


-
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]



Re: Form Double Submit Detection

2003-10-27 Thread Christopher Schultz
Tom,

 Don't know if this is complimentary to your workflow,
 try a javascript confirm (ie a client side pop-up, asking the user 
to click
 Ok to continue). This will catch any double clicks on the client 
side.

Unfortunatly I think our users would object to this solution.


Server side, instead of putting a token in the session when the page is 
*served*, put a token in the session while the submission is being 
processed (use it like a semaphore).  The token has a finite lifecycle 
(created on form submission, death on submission response served).  
There's no need to match tokens unless you're worried about something 
other than duplicate submission detection (such as security or 
time-based form relevance).
I've had to do this before when credit card processing was being done. A 
double-click can result in the credit card being charged twice, so 
you've really got to avoid it.

We actually synchronized on the session for the duration of the 
processing, and then set a flag in the session once the processing was 
done. Any subsequent attempts would be flagged as duplicates and you'd 
just get a results screen.

The same could be done for multiple transactions if, as Justin suggests, 
you put a token into the session *during processing*. Just generate the 
token when you serve the page and submit it along with the form to be 
processed. Synchronize on the session to check it and then put the token 
into the session. If the token is already there, then skip the 
transaction. It's nice to show a result screen even for a 
double-submission, so you might want to synchronize on the token itself 
after you have obtained it from the (synchronized) session.

That will allow you to finish the processing from the *first* 
submission, and then show the results in the second submission. The 
browser, having submitted twice, will hang up on the first connection 
and the second one will show the results. You'll have to put the results 
in the session, then, to display them to the browser for the second 
submission.

It's pretty hairy, no doubt.

-chris

-
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]


RE: Form Double Submit Detection

2003-10-27 Thread Justin Ruthenbeck
At 06:02 PM 10/27/2003, you wrote:
On Tue, 2003-10-28 at 14:18, Justin Ruthenbeck wrote:
 At 04:20 PM 10/27/2003, you wrote:
 On Tue, 2003-10-28 at 12:51, Justin Ruthenbeck wrote:
 
   Server side, instead of putting a token in the session when the 
page
  is
   *served*, put a token in the session while the submission is being
   processed (use it like a semaphore).  The token has a finite 
lifecycle
   (created on form submission, death on submission response
   served).
 
 This only works if processing the two submissions overlaps. If the 
logic
 to process the submission is very fast, or there is a long delay 
between
 submissions, then this won't work.

 from original post
 I've designed my workflows so that they do not need to store anything 
in
 the user's session. This allows the user to conduct more than one
 instance of a particular task at the same time without data getting
 mixed up. However this presents me with a problem if the user double
 clicks the submit button and causes the server to do something twice.
 /from original post

 If the logic to process the submission is very fast, then presumably 
your
 client would have a response before clicking the submit button 
again.  If
 there is a long delay between submissions, then you're dealing with an
 entirely different problem -- ie not user double clicks the submit
 button.

While the logic on the server is reasonably fast, we can't be sure that
the network latency is so low that the user can't double click, nor that
the server will always be fast all the time. In fact we have several
cases of this actually happening and two records being created on the
server.
Alright, we're starting to go around in circles.

Here's the situation (correct me if I'm wrong):
  + User fills out a form and clicks submit
  + The browser submits the form and sits in a wait state
  + The server begins processing a request for a new record
  + The user clicks submit once again
  + The browser submits the form and sits in a wait state again
  + The server begins processing a second (identical) request
This is classic double submission where two requests for the same thing 
overlap on the server.  Your server thinks they are independent, but you 
only want one to complete since it's actually a user error.

In this situation, either of the original 2 suggestions (client or server 
side) should work.  Add client side js code that only allows the user to 
click a button once.  To back it up (don't rely on the client to behave), 
only allow one submission of that particular form at a time.  Make sure 
the form does not get cached.  The only way a client will get around this 
is to have two separate copies of the form and submit both of them -- 
presumably this would mean they *intend* to have two copies.

This takes care of accidental double clicking.  If you absolutely must 
guarantee that the form is only submitted once, then you have no choice 
but to create a UID for the form and match it before allowing the 
submission, in one way or another.

And if you're concerned about this affecting your long term memory 
performance, there are ways to mitigate the impact ... you almost surely 
don't need this level of guantees for every request.

Let me know if I'm not understanding what you're trying to get at ... 
doesn't sound like your requirements are any different than general 
double-click defenses, though.

Cheers,
justin 

-
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]


Re: Form Double Submit Detection

2003-10-27 Thread Justin Ruthenbeck
Agreed.  One word of caution...

At 06:46 PM 10/27/2003, you wrote:
I've had to do this before when credit card processing was being done. A 
double-click can result in the credit card being charged twice, so 
you've really got to avoid it.

We actually synchronized on the session for the duration of the 
processing, and then set a flag in the session once the processing was 
done. Any subsequent attempts would be flagged as duplicates and you'd 
just get a results screen.
You aren't guaranteed to have the same HttpSession object for every 
request -- HttpSession is an interface which is implemented internally 
and wrapped by a facade.  Synchronizing on the actual object you get from 
req.getSession() can potentially leave you synchronizing on totally 
different objects.

justin 

-
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]


RE: Form Double Submit Detection

2003-10-27 Thread Tom Parker
On Tue, 2003-10-28 at 15:49, Justin Ruthenbeck wrote:

 Here's the situation (correct me if I'm wrong):
+ User fills out a form and clicks submit
+ The browser submits the form and sits in a wait state
+ The server begins processing a request for a new record
+ The user clicks submit once again
+ The browser submits the form and sits in a wait state again
+ The server begins processing a second (identical) request
 
 This is classic double submission where two requests for the same thing 
 overlap on the server.  Your server thinks they are independent, but you 
 only want one to complete since it's actually a user error.

You understand the situation perfectly.

 And if you're concerned about this affecting your long term memory 
 performance, there are ways to mitigate the impact ... you almost surely 
 don't need this level of guantees for every request.

I did the numbers and found that for our expected workload we couldn't
possibly use more than a couple of megs of memory keeping track of a
unique token for each form served. I'm dropping them after some time (I
haven't decided how long yet, but I think a couple of hours is probably
long enough) which should keep the memory usage under control.

Thanks everyone for your input.


-
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]