Ejemplo n.º 1
0
        def test_invoke_request_id_sequences(self):
            """
            make sure each session independently generates sequential IDs
            """
            handler0 = ApplicationSession()
            handler1 = ApplicationSession()
            trans0 = MockTransport(handler0)
            trans1 = MockTransport(handler1)

            # the ID sequences for each session should both start at 0
            # (the register) and then increment for the call()
            def verify_seq_id(orig, msg):
                if isinstance(msg, message.Register):
                    self.assertEqual(msg.request, 1)
                elif isinstance(msg, message.Call):
                    self.assertEqual(msg.request, 2)
                return orig(msg)
            orig0 = trans0.send
            orig1 = trans1.send
            trans0.send = lambda msg: verify_seq_id(orig0, msg)
            trans1.send = lambda msg: verify_seq_id(orig1, msg)

            def myproc1():
                return 23

            yield handler0.register(myproc1, u'com.myapp.myproc1')
            yield handler1.register(myproc1, u'com.myapp.myproc1')

            d0 = handler0.call(u'com.myapp.myproc1')
            d1 = handler1.call(u'com.myapp.myproc1')
            res = yield DeferredList([d0, d1])
            self.assertEqual(res, [(True, 23), (True, 23)])
Ejemplo n.º 2
0
        def test_call(self):
            handler = ApplicationSession()
            MockTransport(handler)

            res = yield handler.call(u'com.myapp.procedure1')
            self.assertEqual(res, 100)

            res = yield handler.call(u'com.myapp.procedure1', 1, 2, 3)
            self.assertEqual(res, 100)

            res = yield handler.call(u'com.myapp.procedure1',
                                     1,
                                     2,
                                     3,
                                     foo=23,
                                     bar='hello')
            self.assertEqual(res, 100)

            res = yield handler.call(u'com.myapp.procedure1',
                                     options=types.CallOptions(timeout=10000))
            self.assertEqual(res, 100)

            res = yield handler.call(u'com.myapp.procedure1',
                                     1,
                                     2,
                                     3,
                                     foo=23,
                                     bar='hello',
                                     options=types.CallOptions(timeout=10000))
            self.assertEqual(res, 100)
Ejemplo n.º 3
0
        def test_invoke_request_id_sequences(self):
            """
            make sure each session independently generates sequential IDs
            """
            handler0 = ApplicationSession()
            handler1 = ApplicationSession()
            trans0 = MockTransport(handler0)
            trans1 = MockTransport(handler1)

            # the ID sequences for each session should both start at 0
            # (the register) and then increment for the call()
            def verify_seq_id(orig, msg):
                if isinstance(msg, message.Register):
                    self.assertEqual(msg.request, 0)
                elif isinstance(msg, message.Call):
                    self.assertEqual(msg.request, 1)
                return orig(msg)

            orig0 = trans0.send
            orig1 = trans1.send
            trans0.send = lambda msg: verify_seq_id(orig0, msg)
            trans1.send = lambda msg: verify_seq_id(orig1, msg)

            def myproc1():
                return 23

            yield handler0.register(myproc1, u'com.myapp.myproc1')
            yield handler1.register(myproc1, u'com.myapp.myproc1')

            d0 = handler0.call(u'com.myapp.myproc1')
            d1 = handler1.call(u'com.myapp.myproc1')
            res = yield DeferredList([d0, d1])
            self.assertEqual(res, [(True, 23), (True, 23)])
Ejemplo n.º 4
0
        def test_call_with_complex_result(self):
            handler = ApplicationSession()
            MockTransport(handler)

            res = yield handler.call(u'com.myapp.procedure2')
            self.assertIsInstance(res, types.CallResult)
            self.assertEqual(res.results, (1, 2, 3))
            self.assertEqual(res.kwresults, {})

            res = yield handler.call(u'com.myapp.procedure3')
            self.assertIsInstance(res, types.CallResult)
            self.assertEqual(res.results, (1, 2, 3))
            self.assertEqual(res.kwresults, {'foo': 'bar', 'baz': 23})
Ejemplo n.º 5
0
        def test_call_with_complex_result(self):
            handler = ApplicationSession()
            MockTransport(handler)

            res = yield handler.call(u'com.myapp.procedure2')
            self.assertIsInstance(res, types.CallResult)
            self.assertEqual(res.results, (1, 2, 3))
            self.assertEqual(res.kwresults, {})

            res = yield handler.call(u'com.myapp.procedure3')
            self.assertIsInstance(res, types.CallResult)
            self.assertEqual(res.results, (1, 2, 3))
            self.assertEqual(res.kwresults, {'foo': 'bar', 'baz': 23})
Ejemplo n.º 6
0
        def test_invoke_progressive_result_just_kwargs(self):
            handler = ApplicationSession()
            MockTransport(handler)

            @inlineCallbacks
            def bing(details=None):
                self.assertTrue(details is not None)
                self.assertTrue(details.progress is not None)
                details.progress(key='word')
                yield succeed(True)
                returnValue(42)

            got_progress = Deferred()

            def progress(key=None):
                got_progress.callback(key)

            # see MockTransport, must start with "com.myapp.myproc"
            yield handler.register(
                bing,
                u'com.myapp.myproc2',
                types.RegisterOptions(details_arg='details'),
            )

            res = yield handler.call(
                u'com.myapp.myproc2',
                options=types.CallOptions(on_progress=progress),
            )
            self.assertEqual(42, res)
            self.assertTrue(got_progress.called)
            self.assertEqual('word', got_progress.result)
Ejemplo n.º 7
0
        def test_invoke_user_raises(self):
            handler = ApplicationSession()
            handler.traceback_app = True
            MockTransport(handler)
            errors = []

            def log_error(e, msg):
                errors.append((e.value, msg))
            handler.onUserError = log_error

            name_error = NameError('foo')

            def bing():
                raise name_error

            # see MockTransport, must start with "com.myapp.myproc"
            yield handler.register(bing, u'com.myapp.myproc99')

            try:
                yield handler.call(u'com.myapp.myproc99')
                self.fail("Expected an error")
            except Exception as e:
                # XXX should/could we export all the builtin types?
                # right now, we always get ApplicationError
                # self.assertTrue(isinstance(e, NameError))
                self.assertTrue(isinstance(e, RuntimeError))

            # also, we should have logged the real NameError to
            # Twisted.
            self.assertEqual(1, len(errors))
            self.assertEqual(name_error, errors[0][0])
Ejemplo n.º 8
0
        def test_invoke_progressive_result(self):
            handler = ApplicationSession()
            MockTransport(handler)

            @inlineCallbacks
            def bing(details=None):
                self.assertTrue(details is not None)
                self.assertTrue(details.progress is not None)
                for i in range(10):
                    details.progress(i)
                    yield succeed(i)
                returnValue(42)

            progressive = list(map(lambda _: Deferred(), range(10)))

            def progress(arg):
                progressive[arg].callback(arg)

            # see MockTransport, must start with "com.myapp.myproc"
            yield handler.register(
                bing,
                u'com.myapp.myproc2',
                types.RegisterOptions(details_arg='details'),
            )
            res = yield handler.call(
                u'com.myapp.myproc2',
                options=types.CallOptions(on_progress=progress),
            )
            self.assertEqual(42, res)
            # make sure we got *all* our progressive results
            for i in range(10):
                self.assertTrue(progressive[i].called)
                self.assertEqual(i, progressive[i].result)
Ejemplo n.º 9
0
        def test_invoke_user_raises(self):
            handler = ApplicationSession()
            handler.traceback_app = True
            MockTransport(handler)

            name_error = NameError('foo')

            def bing():
                raise name_error

            # see MockTransport, must start with "com.myapp.myproc"
            yield handler.register(bing, u'com.myapp.myproc99')

            try:
                yield handler.call(u'com.myapp.myproc99')
                self.fail("Expected an error")
            except Exception as e:
                # XXX should/could we export all the builtin types?
                # right now, we always get ApplicationError
                # self.assertTrue(isinstance(e, NameError))
                self.assertTrue(isinstance(e, RuntimeError))

            # also, we should have logged the real NameError to
            # Twisted.
            errs = self.flushLoggedErrors()
            self.assertEqual(1, len(errs))
            self.assertEqual(name_error, errs[0].value)
Ejemplo n.º 10
0
        def test_invoke_progressive_result_just_kwargs(self):
            handler = ApplicationSession()
            MockTransport(handler)

            @inlineCallbacks
            def bing(details=None):
                self.assertTrue(details is not None)
                self.assertTrue(details.progress is not None)
                details.progress(key='word')
                yield succeed(True)
                returnValue(42)

            got_progress = Deferred()

            def progress(key=None):
                got_progress.callback(key)

            # see MockTransport, must start with "com.myapp.myproc"
            yield handler.register(
                bing,
                u'com.myapp.myproc2',
                types.RegisterOptions(details_arg='details'),
            )

            res = yield handler.call(
                u'com.myapp.myproc2',
                options=types.CallOptions(on_progress=progress),
            )
            self.assertEqual(42, res)
            self.assertTrue(got_progress.called)
            self.assertEqual('word', got_progress.result)
Ejemplo n.º 11
0
        def test_invoke_progressive_result(self):
            handler = ApplicationSession()
            MockTransport(handler)

            @inlineCallbacks
            def bing(details=None):
                self.assertTrue(details is not None)
                self.assertTrue(details.progress is not None)
                for i in range(10):
                    details.progress(i)
                    yield succeed(i)
                returnValue(42)

            progressive = list(map(lambda _: Deferred(), range(10)))

            def progress(arg):
                progressive[arg].callback(arg)

            # see MockTransport, must start with "com.myapp.myproc"
            yield handler.register(
                bing,
                u'com.myapp.myproc2',
                types.RegisterOptions(details_arg='details'),
            )
            res = yield handler.call(
                u'com.myapp.myproc2',
                options=types.CallOptions(on_progress=progress),
            )
            self.assertEqual(42, res)
            # make sure we got *all* our progressive results
            for i in range(10):
                self.assertTrue(progressive[i].called)
                self.assertEqual(i, progressive[i].result)
Ejemplo n.º 12
0
        def test_call(self):
            handler = ApplicationSession()
            MockTransport(handler)

            res = yield handler.call(u'com.myapp.procedure1')
            self.assertEqual(res, 100)

            res = yield handler.call(u'com.myapp.procedure1', 1, 2, 3)
            self.assertEqual(res, 100)

            res = yield handler.call(u'com.myapp.procedure1', 1, 2, 3, foo=23, bar='hello')
            self.assertEqual(res, 100)

            res = yield handler.call(u'com.myapp.procedure1', options=types.CallOptions(timeout=10000))
            self.assertEqual(res, 100)

            res = yield handler.call(u'com.myapp.procedure1', 1, 2, 3, foo=23, bar='hello', options=types.CallOptions(timeout=10000))
            self.assertEqual(res, 100)
Ejemplo n.º 13
0
        def test_invoke(self):
            handler = ApplicationSession()
            MockTransport(handler)

            def myproc1():
                return 23

            yield handler.register(myproc1, u'com.myapp.myproc1')

            res = yield handler.call(u'com.myapp.myproc1')
            self.assertEqual(res, 23)
Ejemplo n.º 14
0
        def test_invoke(self):
            handler = ApplicationSession()
            MockTransport(handler)

            def myproc1():
                return 23

            yield handler.register(myproc1, u'com.myapp.myproc1')

            res = yield handler.call(u'com.myapp.myproc1')
            self.assertEqual(res, 23)
Ejemplo n.º 15
0
        def test_invoke_twice(self):
            handler = ApplicationSession()
            MockTransport(handler)

            def myproc1():
                return 23

            yield handler.register(myproc1, u'com.myapp.myproc1')

            d0 = handler.call(u'com.myapp.myproc1')
            d1 = handler.call(u'com.myapp.myproc1')
            res = yield DeferredList([d0, d1])
            self.assertEqual(res, [(True, 23), (True, 23)])
Ejemplo n.º 16
0
        def test_invoke_twice(self):
            handler = ApplicationSession()
            MockTransport(handler)

            def myproc1():
                return 23

            yield handler.register(myproc1, u'com.myapp.myproc1')

            d0 = handler.call(u'com.myapp.myproc1')
            d1 = handler.call(u'com.myapp.myproc1')
            res = yield DeferredList([d0, d1])
            self.assertEqual(res, [(True, 23), (True, 23)])
Ejemplo n.º 17
0
        def test_invoke_progressive_result_error(self):
            handler = ApplicationSession()
            MockTransport(handler)

            @inlineCallbacks
            def bing(arg, details=None, key=None):
                self.assertTrue(details is not None)
                self.assertTrue(details.progress is not None)
                self.assertEqual(key, 'word')
                self.assertEqual('arg', arg)
                details.progress('life', something='nothing')
                yield succeed('meaning of')
                returnValue(42)

            got_progress = Deferred()
            progress_error = NameError('foo')
            logged_errors = []

            def got_error(e, msg):
                logged_errors.append((e.value, msg))

            handler.onUserError = got_error

            def progress(arg, something=None):
                self.assertEqual('nothing', something)
                got_progress.callback(arg)
                raise progress_error

            # see MockTransport, must start with "com.myapp.myproc"
            yield handler.register(
                bing,
                u'com.myapp.myproc2',
                types.RegisterOptions(details_arg='details'),
            )

            res = yield handler.call(
                u'com.myapp.myproc2',
                'arg',
                options=types.CallOptions(on_progress=progress),
                key='word',
            )

            self.assertEqual(42, res)
            # our progress handler raised an error, but not before
            # recording success.
            self.assertTrue(got_progress.called)
            self.assertEqual('life', got_progress.result)
            # make sure our progress-handler error was logged
            self.assertEqual(1, len(logged_errors))
            self.assertEqual(progress_error, logged_errors[0][0])
Ejemplo n.º 18
0
        def test_invoke_progressive_result_error(self):
            handler = ApplicationSession()
            MockTransport(handler)

            @inlineCallbacks
            def bing(arg, details=None, key=None):
                self.assertTrue(details is not None)
                self.assertTrue(details.progress is not None)
                self.assertEqual(key, 'word')
                self.assertEqual('arg', arg)
                details.progress('life', something='nothing')
                yield succeed('meaning of')
                returnValue(42)

            got_progress = Deferred()
            progress_error = NameError('foo')
            logged_errors = []

            def got_error(e, msg):
                logged_errors.append((e.value, msg))
            handler.onUserError = got_error

            def progress(arg, something=None):
                self.assertEqual('nothing', something)
                got_progress.callback(arg)
                raise progress_error

            # see MockTransport, must start with "com.myapp.myproc"
            yield handler.register(
                bing,
                u'com.myapp.myproc2',
                types.RegisterOptions(details_arg='details'),
            )

            res = yield handler.call(
                u'com.myapp.myproc2',
                'arg',
                options=types.CallOptions(on_progress=progress),
                key='word',
            )

            self.assertEqual(42, res)
            # our progress handler raised an error, but not before
            # recording success.
            self.assertTrue(got_progress.called)
            self.assertEqual('life', got_progress.result)
            # make sure our progress-handler error was logged
            self.assertEqual(1, len(logged_errors))
            self.assertEqual(progress_error, logged_errors[0][0])
        def test_call_exception_bare(self):
            handler = ApplicationSession()
            MockTransport(handler)
            exception = Exception()

            def raiser():
                raise exception

            registration0 = yield handler.register(raiser, "com.myapp.myproc_error")
            try:
                yield handler.call('com.myapp.myproc_error')
                self.fail()
            except Exception as e:
                self.assertIsInstance(e, ApplicationError)
            finally:
                yield registration0.unregister()
Ejemplo n.º 20
0
        def test_call_exception_bare(self):
            handler = ApplicationSession()
            MockTransport(handler)
            exception = Exception()

            def raiser():
                raise exception

            registration0 = yield handler.register(raiser, u"com.myapp.myproc_error")
            try:
                yield handler.call(u'com.myapp.myproc_error')
                self.fail()
            except Exception as e:
                self.assertIsInstance(e, ApplicationError)
            finally:
                yield registration0.unregister()
Ejemplo n.º 21
0
        def test_call_exception_runtimeerror(self):
            handler = ApplicationSession()
            MockTransport(handler)
            exception = RuntimeError("a simple error")

            def raiser():
                raise exception

            registration0 = yield handler.register(raiser, u"com.myapp.myproc_error")
            try:
                yield handler.call(u'com.myapp.myproc_error')
                self.fail()
            except Exception as e:
                self.assertIsInstance(e, ApplicationError)
                self.assertEqual(e.error_message(), "wamp.error.runtime_error: a simple error")
            finally:
                yield registration0.unregister()
        def test_call_exception_runtimeerror(self):
            handler = ApplicationSession()
            MockTransport(handler)
            exception = RuntimeError("a simple error")

            def raiser():
                raise exception

            registration0 = yield handler.register(raiser, "com.myapp.myproc_error")
            try:
                yield handler.call('com.myapp.myproc_error')
                self.fail()
            except Exception as e:
                self.assertIsInstance(e, ApplicationError)
                self.assertEqual(e.error_message(), "wamp.error.runtime_error: a simple error")
            finally:
                yield registration0.unregister()
Ejemplo n.º 23
0
        def test_invoke_progressive_result_no_args(self):
            handler = ApplicationSession()
            MockTransport(handler)

            @inlineCallbacks
            def bing(details=None):
                self.assertTrue(details is not None)
                self.assertTrue(details.progress is not None)
                details.progress()
                yield succeed(True)
                returnValue(42)

            got_progress = Deferred()

            def progress():
                got_progress.callback("intentionally left blank")

            # see MockTransport, must start with "com.myapp.myproc"
            yield handler.register(bing, u"com.myapp.myproc2", types.RegisterOptions(details_arg="details"))

            res = yield handler.call(u"com.myapp.myproc2", options=types.CallOptions(on_progress=progress))
            self.assertEqual(42, res)
            self.assertTrue(got_progress.called)
Ejemplo n.º 24
0
 def stockCall(self, pdid, procedure, *args, **kwargs):
     out.info('cxbr: (%s) calling (%s)' % (self.pdid, procedure,))
     return ApplicationSession.call(self, procedure, *args, **kwargs)
Ejemplo n.º 25
0
 def stockCall(self, procedure, *args, **kwargs):
     return ApplicationSession.call(self, u''+procedure, *args, **kwargs)
Ejemplo n.º 26
0
    def render_GET(self, request):
        """
        Initiate the rendering of a HTTP/GET request by calling a WAMP procedure, the
        resulting ``dict`` is rendered together with the specified Jinja2 template
        for this URL.

        :param request: The HTTP request.
        :returns: server.NOT_DONE_YET (special)
        """
        cookie = request.received_cookies.get(b'session_cookie')
        self.log.debug('Session Cookie is ({})'.format(cookie))
        if cookie:
            session = self._session_cache.get(cookie)
            if not session:
                # FIXME: lookup role for current session
                self.log.debug('Creating a new session for cookie ({})'.format(cookie))
                authrole = 'anonymous'
                session = ApplicationSession(ComponentConfig(realm=self._realm_name, extra=None))
                self._worker._router_session_factory.add(session, authrole=authrole)
                self._session_cache[cookie] = session
            else:
                self.log.debug('Using a cached session for ({})'.format(cookie))
        else:
            self.log.debug('No session cookie, falling back on default session')
            session = self._default_session

        if not session:
            self.log.error('could not call procedure - no session')
            return self._render_error('could not call procedure - no session', request)

        full_path = request.uri.decode('utf-8')
        try:
            # werkzeug.routing.MapAdapter
            # http://werkzeug.pocoo.org/docs/dev/routing/#werkzeug.routing.MapAdapter.match
            (procedure, request.template), kwargs = self._map_adapter.match(full_path)

            self.log.debug(
                'WapResource HTTP/GET "{full_path}" mapped to procedure "{procedure}"',
                full_path=full_path,
                procedure=procedure)

            # FIXME: how do we allow calling WAMP procedures with positional args?
            if kwargs:
                d = session.call(procedure, **kwargs)
            else:
                d = session.call(procedure)

            # d.addCallback(self._after_call_success, request)
            # d.addErrback(self._after_call_error, request)
            d.addCallbacks(
                self._after_call_success,
                self._after_call_error,
                callbackArgs=[request],
                errbackArgs=[request])

            return server.NOT_DONE_YET

        except NotFound:
            request.setResponseCode(404)
            return self._render_error('path not found [werkzeug.routing.MapAdapter.match]', request)

        except MethodNotAllowed:
            request.setResponseCode(511)
            return self._render_error('method not allowed [werkzeug.routing.MapAdapter.match]', request)

        except Exception:
            request.setResponseCode(500)
            request.write(self._render_error('unknown error [werkzeug.routing.MapAdapter.match]', request))
            raise
Ejemplo n.º 27
0
 def call(self, procedure, *args, **kwargs):
     # kwargs['options'] = CallOptions(disclose_me=True)
     args = (self.pdid, ) + args
     procedure = _prepend(self.pdid, procedure)
     # out.info('cxbr: (%s) calling (%s)' % (self.pdid, procedure,))
     return ApplicationSession.call(self, procedure, *args, **kwargs)
Ejemplo n.º 28
0
 def stockCall(self, procedure, *args, **kwargs):
     return ApplicationSession.call(self, u'' + procedure, *args, **kwargs)
Ejemplo n.º 29
0
 def call(self, pdid, procedure, *args, **kwargs):
     # kwargs['options'] = CallOptions(disclose_me=True)
     args = (self.pdid,) + args
     procedure = _prepend(pdid, procedure)
     #out.info('riff: (%s) calling (%s)' % (self.pdid, procedure,))
     return ApplicationSession.call(self, procedure, *args, **kwargs)
Ejemplo n.º 30
0
 def absCall(self, procedure, *args, **kwargs):
     #out.info('riff: (%s) calling (%s)' % (self.pdid, procedure,))
     return ApplicationSession.call(self, u'' + procedure, *args, **kwargs)
Ejemplo n.º 31
0
    def render(self, request):
        """
        Initiate the rendering of a HTTP/GET request by calling a WAMP procedure, the
        resulting ``dict`` is rendered together with the specified Jinja2 template
        for this URL.

        :param request: The HTTP request.
        :returns: server.NOT_DONE_YET (special)
        """
        # https://twistedmatrix.com/documents/current/api/twisted.web.resource.Resource.html#render
        # The encoded path of the request URI (_not_ (!) including query arguments),
        full_path = request.path.decode('utf-8')

        # HTTP request method (GET, POST, ..)
        http_method = request.method.decode()
        if http_method not in ['GET', 'POST']:
            request.setResponseCode(511)
            return self._render_error(
                'Method not allowed on path "{full_path}" [werkzeug.routing.MapAdapter.match]'
                .format(full_path=full_path), request)

        # in case of HTTP/POST, read request body as one binary string
        if http_method == 'POST' and request.content:
            content_type = request.getAllHeaders().get(
                b'content-type', b'application/octet-stream').decode()

            # https://stackoverflow.com/a/11549600/884770
            # http://marianoiglesias.com.ar/python/file-uploading-with-multi-part-encoding-using-twisted/
            body_data = request.content.read()
            self.log.info('POST data len = {newdata_len}',
                          newdata_len=len(body_data))
        else:
            content_type = None
            body_data = None

        # parse and decode any query parameters
        query_args = {}
        if request.args:
            for key, values in request.args.items():
                key = key.decode()
                # we only process the first header value per key (!)
                value = values[0].decode()
                query_args[key] = value
            self.log.info('Parsed query parameters: {query_args}',
                          query_args=query_args)

        # parse client announced accept header
        client_accept = request.getAllHeaders().get(b'accept', None)
        if client_accept:
            client_accept = client_accept.decode()

        # flag indicating the client wants to get plain JSON results (not rendered HTML)
        client_return_json = client_accept == 'application/json'

        # client cookie processing
        cookie = request.received_cookies.get(b'session_cookie')
        self.log.debug('Session Cookie is ({})'.format(cookie))
        if cookie:
            session = self._session_cache.get(cookie)
            if not session:
                # FIXME: lookup role for current session
                self.log.debug(
                    'Creating a new session for cookie ({})'.format(cookie))
                authrole = 'anonymous'
                session = ApplicationSession(
                    ComponentConfig(realm=self._realm_name, extra=None))
                self._worker._router_session_factory.add(session,
                                                         authrole=authrole)
                self._session_cache[cookie] = session
            else:
                self.log.debug(
                    'Using a cached session for ({})'.format(cookie))
        else:
            self.log.debug(
                'No session cookie, falling back on default session')
            session = self._default_session

        try:
            # werkzeug.routing.MapAdapter
            # http://werkzeug.pocoo.org/docs/dev/routing/#werkzeug.routing.MapAdapter.match
            (procedure, request.template), kwargs = self._map_adapter.match(
                full_path, method=http_method, query_args=query_args)
            if kwargs and query_args:
                kwargs.update(query_args)
            else:
                kwargs = query_args
            self.log.info(
                'WapResource on path "{full_path}" mapped to procedure "{procedure}"',
                full_path=full_path,
                procedure=procedure)

            # FIXME: how do we allow calling WAMP procedures with positional args?
            if procedure:
                self.log.info(
                    'calling procedure "{procedure}" with kwargs={kwargs} and body_data_len={body_data_len}',
                    procedure=procedure,
                    kwargs=kwargs,
                    body_data_len=len(body_data) if body_data else 0)

                # we need a session to call
                if not session:
                    self.log.error('could not call procedure - no session')
                    return self._render_error(
                        'could not call procedure - no session', request)

                if body_data:
                    if kwargs:
                        d = session.call(procedure,
                                         **kwargs,
                                         data=body_data,
                                         data_type=content_type)
                    else:
                        d = session.call(procedure,
                                         data=body_data,
                                         data_type=content_type)
                else:
                    if kwargs:
                        d = session.call(procedure, **kwargs)
                    else:
                        d = session.call(procedure)
            else:
                d = succeed({})

            d.addCallbacks(self._after_call_success,
                           self._after_call_error,
                           callbackArgs=[request, client_return_json],
                           errbackArgs=[request, client_return_json])

            return server.NOT_DONE_YET

        except NotFound:
            self.log.info('URL "{url}" not found (method={method})',
                          url=full_path,
                          method=http_method)
            request.setResponseCode(404)
            return self._render_error(
                'Path "{full_path}" not found [werkzeug.routing.MapAdapter.match]'
                .format(full_path=full_path), request)

        except MethodNotAllowed:
            self.log.info('method={method} not allowed on URL "{url}"',
                          url=full_path,
                          method=http_method)
            request.setResponseCode(511)
            return self._render_error(
                'Method not allowed on path "{full_path}" [werkzeug.routing.MapAdapter.match]'
                .format(full_path=full_path), request)

        except Exception as e:
            self.log.info(
                'error while processing method={method} on URL "{url}": {e}',
                url=full_path,
                method=http_method,
                e=e)
            request.setResponseCode(500)
            request.write(
                self._render_error(
                    'Unknown error with path "{full_path}" [werkzeug.routing.MapAdapter.match]'
                    .format(full_path=full_path), request))
            raise