[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:
@@ -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
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user