[FIX] lock accesses to session file

bzr revid: chs@openerp.com-20111115161251-wntoqdx42jbh7k0e
This commit is contained in:
Christophe Simonis
2011-11-15 17:12:51 +01:00
parent fafa6b2d91
commit bc9149f5b6
+35 -30
View File
@@ -9,8 +9,9 @@ import logging
import urllib
import os
import pprint
import re
#import re
import sys
import threading
import traceback
import uuid
import xmlrpclib
@@ -176,7 +177,7 @@ class JsonRequest(WebRequest):
try:
self.jsonrequest = simplejson.loads(direct_json_request, object_hook=nonliterals.non_literal_decoder)
except Exception, e:
_logger.error(e)
_logger.exception(e)
return werkzeug.exceptions.BadRequest(e)
else:
# no direct json request, try to get it from jsonp POST request
@@ -352,17 +353,19 @@ STORES = {}
@contextlib.contextmanager
def session_context(request, storage_path, session_cookie='sessionid'):
session_store = STORES.get(storage_path)
session_store, session_lock = STORES.get(storage_path, (None, None))
if not session_store:
session_store = werkzeug.contrib.sessions.FilesystemSessionStore(
storage_path)
STORES[storage_path] = session_store
session_lock = threading.Lock()
STORES[storage_path] = session_store, session_lock
sid = request.cookies.get(session_cookie)
if sid:
request.session = session_store.get(sid)
else:
request.session = session_store.new()
with session_lock:
if sid:
request.session = session_store.get(sid)
else:
request.session = session_store.new()
try:
yield request.session
@@ -375,29 +378,31 @@ def session_context(request, storage_path, session_cookie='sessionid'):
_logger.info('remove session %s: %r', key, value.jsonp_requests)
del request.session[key]
# FIXME: remove this when non-literals disappear
if sid:
# Re-load sessions from storage and merge non-literal
# contexts and domains (they're indexed by hash of the
# content so conflicts should auto-resolve), otherwise if
# two requests alter those concurrently the last to finish
# will overwrite the previous one, leading to loss of data
# (a non-literal is lost even though it was sent to the
# client and client errors)
#
# note that domains_store and contexts_store are append-only (we
# only ever add items to them), so we can just update one with the
# other to get the right result, if we want to merge the
# ``context`` dict we'll need something smarter
in_store = session_store.get(sid)
for k, v in request.session.iteritems():
stored = in_store.get(k)
if stored and isinstance(v, session.OpenERPSession)\
and v != stored:
v.contexts_store.update(stored.contexts_store)
v.domains_store.update(stored.domains_store)
with session_lock:
# FIXME: remove this when non-literals disappear
if sid:
# Re-load sessions from storage and merge non-literal
# contexts and domains (they're indexed by hash of the
# content so conflicts should auto-resolve), otherwise if
# two requests alter those concurrently the last to finish
# will overwrite the previous one, leading to loss of data
# (a non-literal is lost even though it was sent to the
# client and client errors)
#
# note that domains_store and contexts_store are append-only (we
# only ever add items to them), so we can just update one with the
# other to get the right result, if we want to merge the
# ``context`` dict we'll need something smarter
in_store = session_store.get(sid)
for k, v in request.session.iteritems():
stored = in_store.get(k)
if stored and isinstance(v, session.OpenERPSession)\
and v != stored:
v.contexts_store.update(stored.contexts_store)
v.domains_store.update(stored.domains_store)
v.jsonp_requests.update(stored.jsonp_requests)
session_store.save(request.session)
session_store.save(request.session)
#----------------------------------------------------------
# OpenERP Web Module/Controller Loading and URL Routing