cubicweb/web/application.py
changeset 11725 904ee9cd0cf9
parent 11699 b48020a80dc3
child 11767 432f87a63057
equal deleted inserted replaced
11724:0fe3cf5c06b3 11725:904ee9cd0cf9
    18 """CubicWeb web client application object"""
    18 """CubicWeb web client application object"""
    19 
    19 
    20 __docformat__ = "restructuredtext en"
    20 __docformat__ = "restructuredtext en"
    21 
    21 
    22 import contextlib
    22 import contextlib
       
    23 from functools import wraps
    23 import json
    24 import json
    24 import sys
    25 import sys
    25 from time import clock, time
    26 from time import clock, time
    26 from contextlib import contextmanager
    27 from contextlib import contextmanager
    27 from warnings import warn
    28 from warnings import warn
    28 
    29 
    29 from six import text_type, binary_type
    30 from six import PY2, text_type, binary_type
    30 from six.moves import http_client
    31 from six.moves import http_client
    31 
    32 
    32 from rql import BadRQLQuery
    33 from rql import BadRQLQuery
    33 
    34 
    34 from cubicweb import set_log_methods
    35 from cubicweb import set_log_methods
    43 from cubicweb.web.request import CubicWebRequestBase
    44 from cubicweb.web.request import CubicWebRequestBase
    44 
    45 
    45 # make session manager available through a global variable so the debug view can
    46 # make session manager available through a global variable so the debug view can
    46 # print information about web session
    47 # print information about web session
    47 SESSION_MANAGER = None
    48 SESSION_MANAGER = None
       
    49 
       
    50 
       
    51 def _deprecated_path_arg(func):
       
    52     @wraps(func)
       
    53     def wrapper(self, req, *args, **kwargs):
       
    54         if args or 'path' in kwargs:
       
    55             func_name = func.func_name if PY2 else func.__name__
       
    56             warn('[3.24] path argument got removed from "%s" parameters' % func_name,
       
    57                  DeprecationWarning)
       
    58         return func(self, req)
       
    59     return wrapper
       
    60 
       
    61 
       
    62 def _deprecated_req_path_swapped(func):
       
    63     @wraps(func)
       
    64     def wrapper(self, req, *args, **kwargs):
       
    65         if not isinstance(req, CubicWebRequestBase):
       
    66             warn('[3.15] Application entry point arguments are now (req, path) '
       
    67                  'not (path, req)', DeprecationWarning, 2)
       
    68             path = req
       
    69             req = args[0] if args else kwargs.pop('req')
       
    70             args = (path, ) + args[1:]
       
    71         return func(self, req, *args, **kwargs)
       
    72     return wrapper
    48 
    73 
    49 
    74 
    50 @contextmanager
    75 @contextmanager
    51 def anonymized_request(req):
    76 def anonymized_request(req):
    52     orig_cnx = req.cnx
    77     orig_cnx = req.cnx
   196         """
   221         """
   197         return self.session_handler.get_session(req)
   222         return self.session_handler.get_session(req)
   198 
   223 
   199     # publish methods #########################################################
   224     # publish methods #########################################################
   200 
   225 
   201     def log_handle_request(self, req, path):
   226     @_deprecated_path_arg
       
   227     def log_handle_request(self, req):
   202         """wrapper around _publish to log all queries executed for a given
   228         """wrapper around _publish to log all queries executed for a given
   203         accessed path
   229         accessed path
   204         """
   230         """
   205         def wrap_set_cnx(func):
   231         def wrap_set_cnx(func):
   206 
   232 
   222 
   248 
   223             return set_cnx
   249             return set_cnx
   224 
   250 
   225         req.set_cnx = wrap_set_cnx(req.set_cnx)
   251         req.set_cnx = wrap_set_cnx(req.set_cnx)
   226         try:
   252         try:
   227             return self.main_handle_request(req, path)
   253             return self.main_handle_request(req)
   228         finally:
   254         finally:
   229             cnx = req.cnx
   255             cnx = req.cnx
   230             if cnx:
   256             if cnx:
   231                 with self._logfile_lock:
   257                 with self._logfile_lock:
   232                     try:
   258                     try:
   238                         self._query_log.write('\n'.join(result))
   264                         self._query_log.write('\n'.join(result))
   239                         self._query_log.flush()
   265                         self._query_log.flush()
   240                     except Exception:
   266                     except Exception:
   241                         self.exception('error while logging queries')
   267                         self.exception('error while logging queries')
   242 
   268 
   243     def main_handle_request(self, req, path):
   269     @_deprecated_req_path_swapped
   244         """Process an http request
   270     @_deprecated_path_arg
   245 
   271     def main_handle_request(self, req):
   246         Arguments are:
   272         """Process an HTTP request `req`
   247         - a Request object
   273 
   248         - path of the request object
   274         :type req: `web.Request`
       
   275         :param req: the request object
   249 
   276 
   250         It returns the content of the http response. HTTP header and status are
   277         It returns the content of the http response. HTTP header and status are
   251         set on the Request object.
   278         set on the Request object.
   252         """
   279         """
   253         if not isinstance(req, CubicWebRequestBase):
       
   254             warn('[3.15] Application entry point arguments are now (req, path) '
       
   255                  'not (path, req)', DeprecationWarning, 2)
       
   256             req, path = path, req
       
   257         if req.authmode == 'http':
   280         if req.authmode == 'http':
   258             # activate realm-based auth
   281             # activate realm-based auth
   259             realm = self.vreg.config['realm']
   282             realm = self.vreg.config['realm']
   260             req.set_header('WWW-Authenticate', [('Basic', {'realm': realm})], raw=False)
   283             req.set_header('WWW-Authenticate', [('Basic', {'realm': realm})], raw=False)
   261         content = b''
   284         content = b''
   278             # nested try to allow LogOut to delegate logic to AuthenticationError
   301             # nested try to allow LogOut to delegate logic to AuthenticationError
   279             # handler
   302             # handler
   280             try:
   303             try:
   281                 # Try to generate the actual request content
   304                 # Try to generate the actual request content
   282                 with cnx:
   305                 with cnx:
   283                     content = self.core_handle(req, path)
   306                     content = self.core_handle(req)
   284             # Handle user log-out
   307             # Handle user log-out
   285             except LogOut as ex:
   308             except LogOut as ex:
   286                 # When authentification is handled by cookie the code that
   309                 # When authentification is handled by cookie the code that
   287                 # raised LogOut must has invalidated the cookie. We can just
   310                 # raised LogOut must has invalidated the cookie. We can just
   288                 # reload the original url without authentification
   311                 # reload the original url without authentification
   327                 if not content:
   350                 if not content:
   328                     content = self.need_login_content(req)
   351                     content = self.need_login_content(req)
   329         assert isinstance(content, binary_type)
   352         assert isinstance(content, binary_type)
   330         return content
   353         return content
   331 
   354 
   332     def core_handle(self, req, path):
   355     @_deprecated_path_arg
   333         """method called by the main publisher to process <path>
   356     def core_handle(self, req):
       
   357         """method called by the main publisher to process <req> relative path
   334 
   358 
   335         should return a string containing the resulting page or raise a
   359         should return a string containing the resulting page or raise a
   336         `NotFound` exception
   360         `NotFound` exception
   337 
   361 
   338         :type path: str
       
   339         :param path: the path part of the url to publish
       
   340 
       
   341         :type req: `web.Request`
   362         :type req: `web.Request`
   342         :param req: the request object
   363         :param req: the request object
   343 
   364 
   344         :rtype: str
   365         :rtype: str
   345         :return: the result of the pusblished url
   366         :return: the result of the pusblished url
   346         """
   367         """
       
   368         path = req.relative_path(False)
   347         # don't log form values they may contains sensitive information
   369         # don't log form values they may contains sensitive information
   348         self.debug('publish "%s" (%s, form params: %s)',
   370         self.debug('publish "%s" (%s, form params: %s)', path,
   349                    path, req.session.sessionid, list(req.form))
   371                    req.session.sessionid, list(req.form))
   350         # remove user callbacks on a new request (except for json controllers
   372         # remove user callbacks on a new request (except for json controllers
   351         # to avoid callbacks being unregistered before they could be called)
   373         # to avoid callbacks being unregistered before they could be called)
   352         tstart = clock()
   374         tstart = clock()
   353         commited = False
   375         commited = False
   354         try:
   376         try:
   421                 try:
   443                 try:
   422                     req.cnx.rollback()
   444                     req.cnx.rollback()
   423                 except Exception:
   445                 except Exception:
   424                     pass  # ignore rollback error at this point
   446                     pass  # ignore rollback error at this point
   425         self.add_undo_link_to_msg(req)
   447         self.add_undo_link_to_msg(req)
   426         self.debug('query %s executed in %s sec', req.relative_path(), clock() - tstart)
   448         self.debug('query %s executed in %s sec', path, clock() - tstart)
   427         return result
   449         return result
   428 
   450 
   429     # Error handlers
   451     # Error handlers
   430 
   452 
   431     def redirect_handler(self, req, ex):
   453     def redirect_handler(self, req, ex):