Call handlers directly / redirect with parameters ?

2,035 views
Skip to first unread message

Romy

unread,
Oct 20, 2010, 11:58:38 PM10/20/10
to Tornado Web Server
Hey boys,

So I have a handler that creates a verification email, at the end of
which I want the users to be redirected to a thank-you URL (so they
can't resubmit) that says something along the lines of "Thanks, email
will be sent to {{ email }}".

I'm not too happy with any of the solutions I've come up with so far.

- Passing the email in GET form is kinda ugly and unnecessarily
exposes functionality details.
- Passing cookies / session data around and then deleting after
consumption would work, but doesn't seem elegant
- A POST submission would work, though there's no native mechanism for
it and it's kinda hacky

That said, it'd be nice to be able to redirect with parameters, much
in the same way that application handlers are defined with an optional
dictionary as the 3rd param (URLSpec). This way I could do redirect("/
here", dict(email=addy)), and maybe have access to it via
initialize() ?

Thanks.

Japhy Bartlett

unread,
Oct 21, 2010, 1:32:26 AM10/21/10
to python-...@googlegroups.com
> That said, it'd be nice to be able to redirect with parameters, much

well, one easy way to redirect with parameters is to use.. GET parameters.

self.redirect( '/thankyou?email=' +email )

or if you redirect a POST to the same handler as the GET, you can do:

return self.get( param=param)

or....

> - A POST submission would work, though there's no native mechanism for
> it and it's kinda hacky

this makes me think you don't know what you're doing. there's no
"native mechanism" for POST? you're overthinking it- just render a
template from your POST handler:

def post(self):
email = self.get_argument("email")
verify( email)
self.render( 'thankyou.html', email=email)


maybe it's just me, but this makes no sense at all:

Romy

unread,
Oct 21, 2010, 8:45:52 PM10/21/10
to Tornado Web Server
On Oct 20, 10:32 pm, Japhy Bartlett <japhy.bartl...@gmail.com> wrote:
> well, one easy way to redirect with parameters is to use.. GET parameters.
>
> self.redirect( '/thankyou?email=' +email )

That's the first solution I listed in my original post, stating that I
wasn't happy with it and why.

> > - A POST submission would work, though there's no native mechanism for
> > it and it's kinda hacky
>
> this makes me think you don't know what you're doing.  there's no
> "native mechanism" for POST?  you're overthinking it- just render a
> template from your POST handler:
>
> def post(self):
>     email = self.get_argument("email")
>     verify( email)
>     self.render( 'thankyou.html', email=email)

I also said that I wanted to use a redirect to prevent resubmission.

> maybe it's just me, but this makes no sense at all:
>
> > in the same way that application handlers are defined with an optional
> > dictionary as the 3rd param (URLSpec). This way I could do redirect("/
> > here", dict(email=addy)), and maybe have access to it via
> > initialize() ?

You're probably right, when writing that I don't think I've yet
realized that redirecting without get-params or cookies is guaranteed
to lose state.

Will probably just use cookies for this.

Japhy Bartlett

unread,
Oct 22, 2010, 12:18:41 AM10/22/10
to python-...@googlegroups.com
> That's the first solution I listed in my original post, stating that I
> wasn't happy with it and why.

Just pointing out, you're rejecting the simplest solutions for kind of
silly reasons.

> I also said that I wanted to use a redirect to prevent resubmission.

What about redirects prevents resubmission? It's not like your POST
method has to use the same template as your GET method- just don't put
the form in the template rendered by post().

and if you're trying to really prevent resubmission you're going to
need to check serverside anyhow, because your user can go back to the
form almost as easily as they can hit F5.


> Will probably just use cookies for this.

KISS, man

Gavin M. Roy

unread,
Oct 22, 2010, 8:04:13 AM10/22/10
to python-...@googlegroups.com
If you're using cookies, why not maintain session state and save the data on the post to your session for that user and then redirect cleanly pulling the data from there?

Romy

unread,
Oct 23, 2010, 5:51:43 AM10/23/10
to Tornado Web Server
Yeah, I already use sessions. Silly as it might be, I chose cookies
here to avoid storing extra crap in the db.

Romy

unread,
Oct 24, 2010, 3:20:52 AM10/24/10
to Tornado Web Server
Doh, hit 'reply to author' last time, so allow me to reply to the
list.

On Oct 21, 9:18 pm, Japhy Bartlett <japhy.bartl...@gmail.com> wrote:
> Just pointing out, you're rejecting the simplest solutions for kind of
> silly reasons.

Point taken, but what if the data's sensitive ?

> What about redirects prevents resubmission?  It's not like your POST
> method has to use the same template as your GET method- just don't put
> the form in the template rendered by post().

I meant inadvertent resubmission, or more specifically the annoying
behaviors that come with it -- the kind that break page refresh and
browser history. In that case, redirects solve the problem in a Post-
Redirect-Get sort of way, while your suggestion does nothing to
mitigate it.

> and if you're trying to really prevent resubmission you're going to
> need to check serverside anyhow, because your user can go back to the
> form almost as easily as they can hit F5.

Agreed, this wasn't for security purposes.

> > Will probably just use cookies for this.
>
> KISS, man

Cookies are one-liners, pretty simple IMO.

Jyrki Pulliainen

unread,
Oct 25, 2010, 2:05:20 AM10/25/10
to python-...@googlegroups.com
On 24 October 2010 10:20, Romy <romy.m...@gmail.com> wrote:
> Doh, hit 'reply to author' last time, so allow me to reply to the
> list.
>
> On Oct 21, 9:18 pm, Japhy Bartlett <japhy.bartl...@gmail.com> wrote:
>> Just pointing out, you're rejecting the simplest solutions for kind of
>> silly reasons.
>
> Point taken, but what if the data's sensitive ?

If it's sensitive, you really should be using encrypted transport
layer like HTTPS. Anyway, I thought it might be good to point out that
HTTP1.1 standard states that in case of 3xx status code "The action
required MAY be carried out by the user agent without interaction with
the user if and only if the method used in the second request is GET
or HEAD". Afaik all the major browser follow this guideline and none
of the browsers provide any non-standard resubmission of POST data.

I'd go for session or cookies.

- Jyrki

Romy

unread,
Oct 26, 2010, 3:56:46 AM10/26/10
to Tornado Web Server
Good points, thanks.

大房

unread,
Oct 26, 2010, 7:39:51 AM10/26/10
to python-...@googlegroups.com
Hi, I have one multprocess demo here, and I met some problems with it.
Researched for a night, I cannot resolve the reason.
Any one can help me?

I want to have one parent process acts as producer, when there are tasks
come, the parent can fork some children to consume these tasks. The parent
monitors the child, if any one exits with exception, it can be restarted by
parent.

#!/usr/bin/env python
# -*- coding: utf-8 -*-

from multiprocessing import Process, Queue
from Queue import Empty
import sys, signal, os, random, time
import traceback

child_process = []
child_process_num = 4
queue = Queue(0)

def work(queue):
signal.signal(signal.SIGINT, signal.SIG_DFL)
signal.signal(signal.SIGTERM, signal.SIG_DFL)
signal.signal(signal.SIGCHLD, signal.SIG_DFL)

time.sleep(10) #demo sleep

def kill_child_processes(signum, frame):
#terminate all children
pass

def restart_child_process(signum, frame):
global child_process

for i in xrange(len(child_process)):
child = child_process[i]

try:
if child.is_alive():
continue
except OSError, e:
pass

child.join() #join this process to make sure there is no zombie
process

new_child = Process(target=work, args=(queue,))
new_child.start()
child_process[i] = new_child #restart one new process

child = None
return

if __name__ == '__main__':
reload(sys)
sys.setdefaultencoding("utf-8")

for i in xrange(child_process_num):
child = Process(target=work, args=(queue,))
child.start()
child_process.append(child)

signal.signal(signal.SIGINT, kill_child_processes)
signal.signal(signal.SIGTERM, kill_child_processes) #hook the SIGTERM
signal.signal(signal.SIGCHLD, restart_child_process)
signal.signal(signal.SIGPIPE, signal.SIG_DFL)

When this program runs, there will be errors as below:

Error in atexit._run_exitfuncs:
Error in sys.exitfunc:
Traceback (most recent call last):
File "/usr/local/python/lib/python2.6/atexit.py", line 30, in
_run_exitfuncs
traceback.print_exc()
File "/usr/local/python/lib/python2.6/traceback.py", line 227, in
print_exc
print_exception(etype, value, tb, limit, file)
File "/usr/local/python/lib/python2.6/traceback.py", line 124, in
print_exception
_print(file, 'Traceback (most recent call last):')
File "/usr/local/python/lib/python2.6/traceback.py", line 12, in _print
def _print(file, str='', terminator='\n'):
File "test.py", line 42, in restart_child_process
new_child.start()
File "/usr/local/python/lib/python2.6/multiprocessing/process.py", line
99, in start
_cleanup()
File "/usr/local/python/lib/python2.6/multiprocessing/process.py", line
53, in _cleanup
if p._popen.poll() is not None:
File "/usr/local/python/lib/python2.6/multiprocessing/forking.py", line
106, in poll
pid, sts = os.waitpid(self.pid, flag)
OSError: [Errno 10] No child processes

If I send signal to one child:kill –SIGINT {child_pid}
I will get:

[root@mail1 mail]# kill -SIGINT 32545
[root@mail1 mail]# Error in atexit._run_exitfuncs:
Traceback (most recent call last):
File "/usr/local/python/lib/python2.6/atexit.py", line 24, in
_run_exitfuncs
func(*targs, **kargs)
File "/usr/local/python/lib/python2.6/multiprocessing/util.py", line 269,
in _exit_function
p.join()
File "/usr/local/python/lib/python2.6/multiprocessing/process.py", line
119, in join
res = self._popen.wait(timeout)
File "/usr/local/python/lib/python2.6/multiprocessing/forking.py", line
117, in wait
return self.poll(0)
File "/usr/local/python/lib/python2.6/multiprocessing/forking.py", line
106, in poll
pid, sts = os.waitpid(self.pid, flag)
OSError: [Errno 4] Interrupted system call
Error in sys.exitfunc:
Traceback (most recent call last):
File "/usr/local/python/lib/python2.6/atexit.py", line 24, in
_run_exitfuncs
func(*targs, **kargs)
File "/usr/local/python/lib/python2.6/multiprocessing/util.py", line 269,
in _exit_function
p.join()
File "/usr/local/python/lib/python2.6/multiprocessing/process.py", line
119, in join
res = self._popen.wait(timeout)
File "/usr/local/python/lib/python2.6/multiprocessing/forking.py", line
117, in wait
return self.poll(0)
File "/usr/local/python/lib/python2.6/multiprocessing/forking.py", line
106, in poll
pid, sts = os.waitpid(self.pid, flag)
OSError: [Errno 4] Interrupted system call

Thanks
Wyatt Fang

Reply all
Reply to author
Forward
0 new messages