pyramid_cubicweb/handler.py
author Christophe de Vienne <christophe@unlish.com>
Wed, 09 Jul 2014 17:14:32 +0200
changeset 11484 39768d122f97
child 11485 3905c9f06d0e
permissions -rw-r--r--
Isolate the default handler and extend its role The handler now does the job of CubicWebPublisher.main_handle_request() and calls CubicWebPublisher.core_handle(). Instead of using config.add_notfound_view, a catchall route is defined and the handler plugged to it. Related to #4291173

from pyramid import security
from pyramid.httpexceptions import HTTPSeeOther

from cubicweb.web.application import CubicWebPublisher

from cubicweb.web import (
    StatusResponse, DirectResponse, Redirect, NotFound, LogOut,
    RemoteCallFailed, InvalidSession, RequestError, PublishException)


class PyramidSessionHandler(object):
    """A CW Session handler that rely on the pyramid API to fetch the needed
    informations"""

    def __init__(self, appli):
        self.appli = appli

    def get_session(self, req):
        return req._request.cw_session

    def logout(self, req, goto_url):
        raise LogOut(url=goto_url)


class CubicWebPyramidHandler(object):
    def __init__(self, appli):
        self.appli = appli

    def __call__(self, request):
        """
        Handler that mimics what CubicWebPublisher.main_handle_request does and
        call CubicWebPyramidHandler.core_handle.

        """
        # XXX In a later version of this handler, we need to by-pass
        # core_handle and CubicWebPublisher altogether so that the various CW
        # exceptions are converted to their pyramid equivalent.

        req = request.cw_request()
        req.set_cnx(request.cw_cnx)

        # XXX The main handler of CW forbid anonymous https connections
        # I guess we can drop this "feature" but in doubt I leave this comment
        # so we don't forget about it. (cdevienne)

        try:
            content = self.appli.core_handle(req, req.path)

            if content is not None:
                request.response.body = content
            request.response.headers.clear()
            for k, v in req.headers_out.getAllRawHeaders():
                for item in v:
                    request.response.headers.add(k, item)
        except LogOut as ex:
            # The actual 'logging out' logic should be in separated function
            # that is accessible by the pyramid views
            del req._request.session['cubicweb.sessionid']
            if not req.session.closed:
                req.session.repo.close(req.session.sessionid)
            headers = security.forget(request)
            raise HTTPSeeOther(ex.url, headers=headers)
        except Redirect as ex:
            raise HTTPSeeOther(ex.url)
        # except AuthenticationError:
        # XXX I don't think it makes sens to catch this ex here (cdevienne)

        return request.response


def includeme(config):
    # Set up a defaut route to handle non-catched urls.
    # This is to keep legacy compatibility for cubes that makes use of the
    # cubicweb controllers.
    cwconfig = config.registry['cubicweb.config']
    repository = config.registry['cubicweb.repository']
    cwappli = CubicWebPublisher(
        repository, cwconfig,
        session_handler_fact=PyramidSessionHandler)
    handler = CubicWebPyramidHandler(cwappli)

    config.registry['cubicweb.appli'] = cwappli
    config.registry['cubicweb.handler'] = handler

    config.add_route('catchall', pattern='*path')
    config.add_view(handler, route_name='catchall')