async def view_graphiql(self, request: HttpRequest) -> HttpResponse: """Render the Graphiql view Args: request (HttpRequest): The request. Returns: HttpResponse: The response. """ try: host = get_host(request) scheme = get_scheme(request) query_path = f'{scheme}://{host}{self.path_prefix}/graphql' ws_scheme = 'ws' if scheme == 'http' else 'wss' subscription_path = f'{ws_scheme}://{host}{self.path_prefix}/subscriptions' body = make_template(host, query_path, subscription_path) headers = [(b'content-type', b'text/html'), (b'content-length', str(len(body)).encode())] return HttpResponse(response_code.OK, headers, text_writer(body)) # pylint: disable=bare-except except: LOGGER.exception("Failed to handle grahphiql request") text = 'Internal server error' headers = [(b'content-type', b'text/plain'), (b'content-length', str(len(text)).encode())] return HttpResponse(response_code.INTERNAL_SERVER_ERROR, headers, text_writer(text))
async def handle_subscription_post(self, request: HttpRequest) -> HttpResponse: """Handle a streaming subscription Args: request (HttpRequest): The request Returns: HttpResponse: A stream response """ try: LOGGER.debug( "Received POST streaming subscription request: http_version='%s'.", request.scope['http_version']) text = await text_reader(request.body) body = self.loads(text) query: str = body['query'] variables: Optional[Dict[str, Any]] = body.get('variables') operation_name: Optional[str] = body.get('operationName') return await self._handle_streaming_subscription( request, query, variables, operation_name) # pylint: disable=bare-except except: LOGGER.exception("Failed to handle graphql POST subscription") text = 'Internal server error' headers = [(b'content-type', b'text/plain'), (b'content-length', str(len(text)).encode())] return HttpResponse(response_code.INTERNAL_SERVER_ERROR, headers, text_writer(text))
async def graphql_handler(request: HttpRequest) -> HttpResponse: """Handle a graphql request""" host = header.find(b'host', request.scope['headers']).decode() sse_url = f"{request.scope['scheme']}://{host}/sysmon/graphql" html = request.info['page_template'].substitute(sse_url=sse_url) return HttpResponse(200, [(b'content-type', b'text/html')], text_writer(html))
async def __call__(self, request: HttpRequest) -> HttpResponse: if request.scope["method"] not in ("GET", "HEAD"): return HttpResponse(response_code.METHOD_NOT_ALLOWED, [(b'content-type', b'text/plain')], text_writer("Method Not Allowed")) try: # Get the path from the scope or the route match. path: str = '/' + \ request.matches.get( self.path_variable, '') if self.path_variable else request.scope["path"] if (path == '' or path.endswith('/')) and self.index_filename: path += self.index_filename relative_path = os.path.normpath(os.path.join(*path.split("/"))) if relative_path.startswith(".."): raise FileNotFoundError() rooted_path = os.path.join(self.source_folder, relative_path) if self.config_checked: check_directory = None else: check_directory = self.source_folder self.config_checked = True if check_directory is not None: stat_result = await aio_stat(check_directory) if not (stat.S_ISDIR(stat_result.st_mode) or stat.S_ISLNK(stat_result.st_mode)): raise FileNotFoundError() stat_result = await aio_stat(rooted_path) mode = stat_result.st_mode if not stat.S_ISREG(mode): raise FileNotFoundError() return await file_response(request, 200, rooted_path, check_modified=True) except FileNotFoundError: return HttpResponse(response_code.NOT_FOUND, [(b'content-type', b'text/plain')], text_writer("Not Found"))
def _make_error_response(error: HTTPError) -> HttpResponse: if isinstance(error.reason, str): content: Optional[Content] = text_writer(error.reason) elif isinstance(error.reason, bytes): content = bytes_writer(error.reason) else: content = None return error.code, cast(Optional[Headers], error.headers), content, None
async def _read(self, _scope: Scope, _info: Info, matches: RouteMatches, _content: Content) -> HttpResponse: try: id_: Optional[int] = matches.get('id') if id_ is None: raise RuntimeError('Invalid id') entry = await self._repository.read_by_id(id_, None) if entry is None: return 404 return (200, [(b'content-type', b'application/json')], text_writer(json.dumps(entry, cls=DateEncoder))) except: # pylint: disable=bare-except return 500
async def _handle_query_or_mutation( self, request: HttpRequest, query: str, variables: Optional[Dict[str, Any]], operation_name: Optional[str]) -> HttpResponse: LOGGER.debug("Processing a query or mutation.") result = await self.query(request, query, variables, operation_name) response: Dict[str, Any] = {'data': result.data} if result.errors: response['errors'] = [error.formatted for error in result.errors] text = self.dumps(response) headers = [(b'content-type', b'application/json'), (b'content-length', str(len(text)).encode())] return HttpResponse(response_code.OK, headers, text_writer(text))
async def _read_between(self, scope: Scope, _info: Info, _matches: RouteMatches, _content: Content) -> HttpResponse: try: query = dict(parse_qsl(scope['query_string'] or b'')) end_date = _parse_date(query.get(b'to'), datetime.utcnow()) start_date = _parse_date(query.get(b'from'), end_date - timedelta(5)) limit = _parse_int(query.get(b'limit'), 20) entries = await self._repository.read_between( start_date, end_date, ['title', 'description'], limit) return (200, [(b'content-type', b'application/json')], text_writer(json.dumps(entries, cls=DateEncoder))) except: # pylint: disable=bare-except return 500
async def _create(self, scope: Scope, _info: Info, _matches: RouteMatches, content: Content) -> HttpResponse: try: if not _is_form_data(scope): raise RuntimeError("Invalid content type") text = await text_reader(content) args = dict(parse_qsl(text)) id_ = await self._repository.create(**args) return (200, [(b'content-type', b'application/json')], text_writer( json.dumps({ 'id': id_, 'read': f'{self._path}/{id_}' }))) except: # pylint: disable=bare-except return 500
async def handle_graphql(self, request: HttpRequest) -> HttpResponse: """A request handler for graphql queries Args: scope (Scope): The Request Returns: HttpResponse: The HTTP response to the query request """ try: body = await self._get_query_document(request) query: str = body['query'] variables: Optional[Dict[str, Any]] = body.get('variables') operation_name: Optional[str] = body.get('operationName') query_document = graphql.parse(query) if not has_subscription(query_document): return await self._handle_query_or_mutation( request, query, variables, operation_name) # The subscription method is determined by the `allow` header. allow = header.find(b'allow', request.scope['headers'], b'GET') if allow == b'GET': return self._handle_subscription_redirect(request, body) return await self._handle_streaming_subscription( request, query, variables, operation_name) # pylint: disable=bare-except except: LOGGER.exception("Failed to handle graphql query request") text = 'Internal server error' headers = [(b'content-type', b'text/plain'), (b'content-length', str(len(text)).encode())] return HttpResponse(response_code.INTERNAL_SERVER_ERROR, headers, text_writer(text))
async def handle_subscription_get(self, request: HttpRequest) -> HttpResponse: """Handle a streaming subscription Args: request (HttpRequest): The request Returns: HttpResponse: The streaming response """ try: LOGGER.debug( "Received GET streaming subscription request: http_version='%s'.", request.scope['http_version']) body = { name.decode('utf-8'): self.loads(value[0].decode('utf-8')) for name, value in cast( Dict[bytes, List[bytes]], parse_qs(request.scope['query_string'])).items() } query: str = body['query'] variables: Optional[Dict[str, Any]] = body.get('variables') operation_name: Optional[str] = body.get('operationName') return await self._handle_streaming_subscription( request, query, variables, operation_name) # pylint: disable=bare-except except: LOGGER.exception("Failed to handle graphql GET subscription") text = 'Internal server error' headers = [(b'content-type', b'text/plain'), (b'content-length', str(len(text)).encode())] return HttpResponse(response_code.INTERNAL_SERVER_ERROR, headers, text_writer(text))
async def get_info(request: HttpRequest) -> HttpResponse: text = json.dumps(request.info) return HttpResponse(200, [(b'content-type', b'application/json')], text_writer(text))
async def file_response( request: HttpRequest, status: int, path: str, headers: Optional[List[Tuple[bytes, bytes]]] = None, content_type: Optional[str] = None, filename: Optional[str] = None, check_modified: Optional[bool] = False) -> HttpResponse: """A utility method to create a file response. Args: scope (Scope): The ASGI scope. status (int): The HTTP status code. path (str): The path to the file. headers (Optional[Headers], optional): The headers. Defaults to None. content_type (Optional[str], optional): The content type.. Defaults to None. filename (Optional[str], optional): The filename. Defaults to None. check_modified (Optional[bool], optional): If True check for modifications to the file. Defaults to False. Raises: RuntimeError: If the path was not a file. Returns: HttpResponse: The HTTP response """ try: stat_result = await aiofiles.os.stat(path) mode = stat_result.st_mode if not stat.S_ISREG(mode): raise RuntimeError(f"File at path {path} is not a file.") if not headers: headers = [] if content_type is None: content_type = guess_type(filename or path)[0] or "text/plain" headers.append((b'content-type', content_type.encode())) headers.append((b'content-length', str(stat_result.st_size).encode())) headers.append( (b'last-modified', formatdate(stat_result.st_mtime, usegmt=True).encode())) headers.append((b'etag', _stat_to_etag(stat_result).encode())) if filename is not None: content_disposition = f'attachment; filename="{filename}"' headers.append( (b"content-disposition", content_disposition.encode())) if check_modified and _is_not_modified(request.scope['headers'], headers): return HttpResponse( response_code.NOT_MODIFIED, [(name, value) for name, value in headers if name in NOT_MODIFIED_HEADERS], None) return HttpResponse( status, headers, None if request.scope['method'] == 'HEAD' else file_writer(path)) except FileNotFoundError: return HttpResponse( response_code.INTERNAL_SERVER_ERROR, [(b'content-type', b'text/plain')], text_writer(f"File at path {path} does not exist.")) except RuntimeError: return HttpResponse(response_code.INTERNAL_SERVER_ERROR)