[FIX] web, base: POST requests handling

POST requests on routes with auth="user" are now correctly handled when
the user is not connected. Request data (form and files) are stored in
the session. Once the user is logged, redirect her to a specific route
that will reprocess the original POST request.
This commit is contained in:
Christophe Simonis
2015-08-05 12:01:12 +02:00
parent 6f4738e298
commit b13553d2b6
2 changed files with 64 additions and 2 deletions
+15
View File
@@ -670,6 +670,21 @@ class Proxy(http.Controller):
base_url = request.httprequest.base_url
return Client(request.httprequest.app, BaseResponse).get(path, base_url=base_url).data
@http.route('/web/proxy/post/<path:path>', type='http', auth='user', methods=['GET'])
def post(self, path):
"""Effectively execute a POST request that was hooked through user login"""
with request.session.load_request_data() as data:
if not data:
raise werkzeug.exceptions.BadRequest()
from werkzeug.test import Client
from werkzeug.wrappers import BaseResponse
base_url = request.httprequest.base_url
query_string = request.httprequest.query_string
client = Client(request.httprequest.app, BaseResponse)
headers = {'X-Openerp-Session-Id': request.session.sid}
return client.post('/' + path, base_url=base_url, query_string=query_string,
headers=headers, data=data)
class Database(http.Controller):
def _render_template(self, **d):
+49 -2
View File
@@ -674,9 +674,16 @@ class HttpRequest(WebRequest):
try:
return super(HttpRequest, self)._handle_exception(exception)
except SessionExpiredException:
if not request.params.get('noredirect'):
redirect = None
req = request.httprequest
if req.method == 'POST':
request.session.save_request_data()
redirect = '/web/proxy/post{r.path}?{r.query_string}'.format(r=req)
elif not request.params.get('noredirect'):
redirect = req.url
if redirect:
query = werkzeug.urls.url_encode({
'redirect': request.httprequest.url,
'redirect': redirect,
})
return werkzeug.utils.redirect('/web/login?%s' % query)
except werkzeug.exceptions.HTTPException, e:
@@ -1170,6 +1177,46 @@ class OpenERPSession(werkzeug.contrib.sessions.Session):
saved_actions = self.get('saved_actions', {})
return saved_actions.get("actions", {}).get(key)
def save_request_data(self):
import uuid
req = request.httprequest
files = werkzeug.datastructures.MultiDict()
# NOTE we do not store files in the session itself to avoid loading them in memory.
# By storing them in the session store, we ensure every worker (even ones on other
# servers) can access them. It also allow stale files to be deleted by `session_gc`.
for f in req.files.values():
storename = 'file-{0}-{1}'.format(self.sid, uuid.uuid4().hex)
path = os.path.join(root.session_store.path, storename)
with open(path, 'w') as fp:
f.save(fp)
files.add(f.name, (storename, f.filename, f.content_type))
self['serialized_request_data'] = {
'form': req.form,
'files': files,
}
@contextlib.contextmanager
def load_request_data(self):
data = self.pop('serialized_request_data', None)
files = werkzeug.datastructures.MultiDict()
try:
if data:
# regenerate files filenames with the current session store
for name, (storename, filename, content_type) in data['files'].iteritems():
path = os.path.join(root.session_store.path, storename)
files.add(name, (path, filename, content_type))
yield werkzeug.datastructures.CombinedMultiDict([data['form'], files])
else:
yield None
finally:
# cleanup files
for f, _, _ in files.values():
try:
os.unlink(f)
except IOError:
pass
def session_gc(session_store):
if random.random() < 0.001:
# we keep session one week