def get_scope_user(scope):
    if "_cached_user" not in scope:
        # We need to fake a request so the auth code works
        scope['method'] = "FAKE"
        from channels.http import AsgiRequest
        fake_request = AsgiRequest(scope, b'')
        fake_request.session = scope["session"]

        scope["_cached_user"] = _get_user(fake_request)
    return scope["_cached_user"]
示例#2
0
    def connect(self):
        self.service = self.scope["service"]

        scope = dict(self.scope)
        scope["method"] = "get"
        request = AsgiRequest(scope, b"")
        request._request = request
        request.user = self.scope["user"]
        request.session = self.scope["session"]

        if not self.scope["user"].is_authenticated:
            self.authenticate(request)

        if self.check_permissions(request):
            raise AcceptConnection()
        else:
            raise DenyConnection()
示例#3
0
    def from_scope(cls, viewset_action, scope, view_kwargs, query_params):
        """
        "This is the magic."
        (reference: https://github.com/encode/django-rest-framework/blob/1e383f/rest_framework/viewsets.py#L47)

        This method initializes a view properly so that calls to methods like get_queryset() and get_serializer_class(),
        and permission checks have all the properties set, like self.kwargs and self.request, that they would expect.

        The production of a Django HttpRequest object from a base websocket asgi scope, rather than an actual HTTP
        request, is probably the largest "hack" in this project. By inspection of the ASGI spec, however,
        the only difference between websocket and HTTP scopes is the existence of an HTTP method
        (https://asgi.readthedocs.io/en/latest/specs/www.html).

        This is because websocket connections are established over an HTTP connection, and so headers and everything
        else are set just as they would be in a normal HTTP request. Therefore, the base of the request object for
        every broadcast is the initial HTTP request. Subscriptions are retrieval operations, so the method is hard-coded
        as GET.
        """
        self = cls()

        self.format_kwarg = None
        self.action_map = dict()
        self.args = []
        self.kwargs = view_kwargs

        base_request = AsgiRequest(
            {
                **scope, "method": "GET",
                "query_string": urlencode(query_params)
            },
            BytesIO(),
        )
        # TODO: Run other middleware?
        base_request.user = scope.get("user", None)
        base_request.session = scope.get("session", None)

        self.request = self.initialize_request(base_request)
        self.action = viewset_action  # TODO: custom subscription actions?
        return self
示例#4
0
    async def handle(self, body):
        from django_grip import GripMiddleware
        from .eventrequest import EventRequest
        from .eventstream import EventPermissionError
        from .utils import sse_error_response

        self.listener = None

        request = AsgiRequest(self.scope, body)

        gm = GripMiddleware()
        gm.process_request(request)

        if 'user' in self.scope:
            request.user = self.scope['user']

        if 'session' in self.scope:
            request.session = self.scope['session']

        try:
            event_request = await self.parse_request(request)
            response = None
        except EventRequest.ResumeNotAllowedError as e:
            response = HttpResponseBadRequest('Invalid request: %s.\n' %
                                              str(e))
        except EventRequest.GripError as e:
            if request.grip.proxied:
                response = sse_error_response('internal-error',
                                              'Invalid internal request.')
            else:
                response = sse_error_response('bad-request',
                                              'Invalid request: %s.' % str(e))
        except EventRequest.Error as e:
            response = sse_error_response('bad-request',
                                          'Invalid request: %s.' % str(e))

        # for grip requests, prepare immediate response
        if not response and request.grip.proxied:
            try:
                event_response = await self.get_events(event_request)
                response = event_response.to_http_response(request)
            except EventPermissionError as e:
                response = sse_error_response('forbidden', str(e),
                                              {'channels': e.channels})

        extra_headers = {}
        add_default_headers(extra_headers)

        # if this was a grip request or we encountered an error, respond now
        if response:
            response = gm.process_response(request, response)

            headers = []
            for name, value in response.items():
                if isinstance(name, six.text_type):
                    name = name.encode('utf-8')
                if isinstance(value, six.text_type):
                    value = value.encode('utf-8')
                headers.append((name, value))

            for name, value in extra_headers.items():
                if isinstance(name, six.text_type):
                    name = name.encode('utf-8')
                if isinstance(value, six.text_type):
                    value = value.encode('utf-8')
                headers.append((name, value))

            await self.send_response(response.status_code,
                                     response.content,
                                     headers=headers)
            return

        # if we got here then the request was not a grip request, and there
        #   were no errors, so we can begin a local stream response

        headers = [(six.b('Content-Type'), six.b('text/event-stream'))]
        for name, value in extra_headers.items():
            if isinstance(name, six.text_type):
                name = name.encode('utf-8')
            if isinstance(value, six.text_type):
                value = value.encode('utf-8')
            headers.append((name, value))

        await self.send_headers(headers=headers)

        self.listener = Listener()
        self.is_streaming = True

        asyncio.get_event_loop().create_task(self.stream(event_request))