async def resolve(self, request: IRequest) -> BaseMatchInfo: ''' Resolve a request ''' # prevent: https://github.com/aio-libs/aiohttp/issues/3335 request.url request.record('start') result = None try: result = await self.real_resolve(request) except (response.Response, aiohttp.web_exceptions.HTTPException) as exc: await abort(request) return BasicMatchInfo(request, exc) except Exception: logger.error("Exception on resolve execution", exc_info=True, request=request) await abort(request) return BasicMatchInfo( request, response.HTTPInternalServerError()) if result is not None: return result else: await abort(request) return BasicMatchInfo(request, response.HTTPNotFound())
async def resolve(self, request: IRequest) -> BaseMatchInfo: # type: ignore ''' Resolve a request ''' # prevent: https://github.com/aio-libs/aiohttp/issues/3335 request.url request.record('start') result = None try: result = await self.real_resolve(request) except (response.Response, aiohttp.web_exceptions.HTTPException) as exc: await abort() return BasicMatchInfo(request, exc) except Exception: logger.error("Exception on resolve execution", exc_info=True, request=request) await abort() return BasicMatchInfo(request, response.HTTPInternalServerError()) if result is not None: return result else: await abort() return BasicMatchInfo(request, response.HTTPNotFound())
async def __call__(self): tm = get_tm() await tm.abort() ws = self.request.get_ws() await ws.prepare() async for msg in ws: try: message = msg.json except WebSocketJsonDecodeError: # We only care about json messages logger.warning( "Invalid websocket payload, ignored: {}".format(msg)) continue if message["op"].lower() == "close": break elif message["op"].lower() == "get": txn = await tm.begin() try: await self.handle_ws_request(ws, message) except Exception: logger.error("Exception on ws", exc_info=True) finally: # only currently support GET requests which are *never* # supposed to be commits await tm.abort(txn=txn) logger.debug("websocket connection closed") await ws.close()
async def __call__(self): tm = get_tm(self.request) await tm.abort(self.request) ws = web.WebSocketResponse() await ws.prepare(self.request) async for msg in ws: if msg.type == aiohttp.WSMsgType.text: try: message = ujson.loads(msg.data) except ValueError: logger.warning('Invalid websocket payload, ignored: {}'.format( msg.data)) continue if message['op'] == 'close': await ws.close() elif message['op'].lower() == 'get': txn = await tm.begin(request=self.request) try: await self.handle_ws_request(ws, message) except Exception: logger.error('Exception on ws', exc_info=True) finally: # only currently support GET requests which are *never* # supposed to be commits await tm.abort(txn=txn) elif msg.type == aiohttp.WSMsgType.error: logger.debug('ws connection closed with exception {0:s}' .format(ws.exception())) logger.debug('websocket connection closed') return {}
async def resolve(self, request: IRequest) -> BaseMatchInfo: # type: ignore """ Resolve a request """ request.record("start") result = None try: result = await self.real_resolve(request) except response.Response as exc: await abort() return BasicMatchInfo(request, exc) except asyncio.CancelledError: logger.info("Request cancelled", request=request) await abort() return BasicMatchInfo(request, response.HTTPClientClosedRequest()) except Exception: logger.error("Exception on resolve execution", exc_info=True, request=request) await abort() return BasicMatchInfo(request, response.HTTPInternalServerError()) if result is not None: return result else: await abort() return BasicMatchInfo(request, response.HTTPNotFound())
async def __call__(self): tm = get_tm() await tm.abort() ws = web.WebSocketResponse() await ws.prepare(self.request) async for msg in ws: if msg.type == aiohttp.WSMsgType.text: try: message = ujson.loads(msg.data) except ValueError: logger.warning( 'Invalid websocket payload, ignored: {}'.format( msg.data)) continue if message['op'] == 'close': await ws.close() elif message['op'].lower() == 'get': txn = await tm.begin() try: await self.handle_ws_request(ws, message) except Exception: logger.error('Exception on ws', exc_info=True) finally: # only currently support GET requests which are *never* # supposed to be commits await tm.abort(txn=txn) elif msg.type == aiohttp.WSMsgType.error: logger.debug( 'ws connection closed with exception {0:s}'.format( ws.exception())) logger.debug('websocket connection closed') return {}
async def handle_ws_request(self, ws, message): method = app_settings['http_methods']['GET'] path = tuple(p for p in message['value'].split('/') if p) # avoid circular import from guillotina.traversal import do_traverse obj, tail = await do_traverse(self.request, self.request.container, path) traverse_to = None if tail and len(tail) == 1: view_name = tail[0] elif tail is None or len(tail) == 0: view_name = '' else: view_name = tail[0] traverse_to = tail[1:] permission = getUtility(IPermission, name='guillotina.AccessContent') allowed = IInteraction(self.request).check_permission( permission.id, obj) if not allowed: response = {'error': 'Not allowed'} ws.send_str(ujson.dumps(response)) try: view = queryMultiAdapter((obj, self.request), method, name=view_name) except AttributeError: view = None if traverse_to is not None: if view is None or not ITraversableView.providedBy(view): response = {'error': 'Not found'} ws.send_str(ujson.dumps(response)) else: try: view = await view.publish_traverse(traverse_to) except Exception as e: logger.error("Exception on view execution", exc_info=e) response = {'error': 'Not found'} ws.send_str(ujson.dumps(response)) view_result = await view() if isinstance(view_result, Response): view_result = view_result.response # Return the value ws.send_str(ujson.dumps(view_result)) # Wait for possible value futures_to_wait = self.request._futures.values() if futures_to_wait: await asyncio.gather(*list(futures_to_wait)) self.request._futures = {}
def generate_unauthorized_response(e, request): # We may need to check the roles of the users to show the real error eid = uuid.uuid4().hex message = _('Not authorized to render operation') + ' ' + eid user = get_authenticated_user_id(request) extra = {'r': _url(request), 'u': user} logger.error(message, exc_info=e, extra=extra) return UnauthorizedResponse(message)
def generate_error_response(e, request, error, status=400): # We may need to check the roles of the users to show the real error eid = uuid.uuid4().hex message = _('Error on execution of view') + ' ' + eid user = get_authenticated_user_id(request) extra = {'r': _url(request), 'u': user} logger.error(message, exc_info=e, extra=extra) return ErrorResponse(error, message, status)
async def traverse( request: IRequest, parent: IBaseObject, path: Tuple[str, ...]) -> Tuple[IBaseObject, Tuple[str, ...]]: """Do not use outside the main router function.""" if IApplication.providedBy(parent): request.application = parent if len(path) == 0: return parent, path assert request is not None # could be used for permissions, etc if not ITraversable.providedBy(parent): # not a traversable context return parent, path try: if path[0][0] == "_" or path[0] in (".", ".."): raise HTTPUnauthorized() if path[0][0] == "@": # shortcut return parent, path if IAsyncContainer.providedBy(parent): context = await parent.async_get(path[0], suppress_events=True) if context is None: return parent, path else: context = parent[path[0]] except (TypeError, KeyError, AttributeError): return parent, path if IDatabase.providedBy(context): task_vars.db.set(context) # Add a transaction Manager to request tm = context.get_transaction_manager() task_vars.tm.set(tm) # Start a transaction txn = await tm.begin( read_only=not app_settings["check_writable_request"](request)) # Get the root of the tree context = await tm.get_root(txn=txn) if IContainer.providedBy(context): task_vars.container.set(context) # make sure to unset before we attempt to load in case # there is an existing registry object set on task_vars task_vars.registry.set(None) registry = await get_registry(context) layers = registry.get(ACTIVE_LAYERS_KEY, []) for layer in layers: try: alsoProvides(request, import_class(layer)) except ModuleNotFoundError: logger.error("Can not apply layer " + layer, request=request) return await traverse(request, context, path[1:])
async def traverse(request, parent, path): """Do not use outside the main router function.""" if IApplication.providedBy(parent): request.application = parent if not path: return parent, path assert request is not None # could be used for permissions, etc if not ITraversable.providedBy(parent): # not a traversable context return parent, path try: if path[0][0] == '_' or path[0] in ('.', '..'): raise HTTPUnauthorized() if path[0][0] == '@': # shortcut return parent, path if IAsyncContainer.providedBy(parent): context = await parent.async_get(path[0], suppress_events=True) if context is None: return parent, path else: context = parent[path[0]] except (TypeError, KeyError, AttributeError): return parent, path if IDatabase.providedBy(context): request._db_write_enabled = app_settings['check_writable_request']( request) request._db_id = context.id # Add a transaction Manager to request tm = request._tm = context.get_transaction_manager() # Start a transaction txn = await tm.begin(request=request) # Get the root of the tree context = await tm.get_root(txn=txn) if IContainer.providedBy(context): request._container_id = context.id request.container = context annotations_container = IAnnotations(request.container) request.container_settings = await annotations_container.async_get( REGISTRY_DATA_KEY) layers = request.container_settings.get(ACTIVE_LAYERS_KEY, []) for layer in layers: try: alsoProvides(request, import_class(layer)) except ModuleNotFoundError: logger.error('Can not apply layer ' + layer, request=request) return await traverse(request, context, path[1:])
async def initialize(self, app=None): # loop self.app = app while True: got_obj = False try: view = await self._queue.get() got_obj = True txn = get_transaction(view.request) tm = get_tm(view.request) if txn is None or (txn.status in ( Status.ABORTED, Status.COMMITTED, Status.CONFLICT) and txn._db_conn is None): txn = await tm.begin(view.request) else: # still finishing current transaction, this connection # will be cut off, so we need to wait until we no longer # have an active transaction on the reqeust... await self.add(view) await asyncio.sleep(1) continue try: aiotask_context.set('request', view.request) view_result = await view() if isinstance(view_result, ErrorResponse): await tm.commit(txn=txn) elif isinstance(view_result, UnauthorizedResponse): await tm.abort(txn=txn) else: await tm.commit(txn=txn) except Unauthorized: await tm.abort(txn=txn) except Exception as e: logger.error( "Exception on writing execution", exc_info=e) await tm.abort(txn=txn) except (KeyboardInterrupt, MemoryError, SystemExit, asyncio.CancelledError, GeneratorExit, RuntimeError): self._exceptions = True raise except Exception as e: # noqa self._exceptions = True logger.error('Worker call failed', exc_info=e) finally: aiotask_context.set('request', None) if got_obj: try: view.request.execute_futures() except AttributeError: pass self._queue.task_done()
async def traverse(request, parent, path): """Do not use outside the main router function.""" if IApplication.providedBy(parent): request.application = parent if not path: return parent, path assert request is not None # could be used for permissions, etc if not ITraversable.providedBy(parent): # not a traversable context return parent, path try: if path[0][0] == '_' or path[0] in ('.', '..'): raise HTTPUnauthorized() if path[0][0] == '@': # shortcut return parent, path if IAsyncContainer.providedBy(parent): context = await parent.async_get(path[0], suppress_events=True) if context is None: return parent, path else: context = parent[path[0]] except (TypeError, KeyError, AttributeError): return parent, path if IDatabase.providedBy(context): request._db_write_enabled = app_settings['check_writable_request'](request) request._db_id = context.id # Add a transaction Manager to request tm = request._tm = context.get_transaction_manager() # Start a transaction txn = await tm.begin(request=request) # Get the root of the tree context = await tm.get_root(txn=txn) if IContainer.providedBy(context): request._container_id = context.id request.container = context annotations_container = IAnnotations(request.container) request.container_settings = await annotations_container.async_get(REGISTRY_DATA_KEY) layers = request.container_settings.get(ACTIVE_LAYERS_KEY, []) for layer in layers: try: alsoProvides(request, import_class(layer)) except ModuleNotFoundError: logger.error('Can not apply layer ' + layer, request=request) return await traverse(request, context, path[1:])
async def resolve(self, request): result = None try: result = await self.real_resolve(request) except Exception as e: logger.error("Exception on resolve execution", exc_info=e, request=request) await abort(request) raise e if result is not None: return result else: await abort(request) raise HTTPNotFound()
async def initialize(self, app=None): # loop self.app = app while True: got_obj = False try: view = await self.queue.get() got_obj = True txn = get_transaction(view.request) tm = get_tm(view.request) if txn is None or (txn.status in ( Status.ABORTED, Status.COMMITTED, Status.CONFLICT) and txn._db_conn is None): txn = await tm.begin(view.request) else: # still finishing current transaction, this connection # will be cut off, so we need to wait until we no longer # have an active transaction on the reqeust... await self.add(view) await asyncio.sleep(1) continue try: aiotask_context.set('request', view.request) await view() await tm.commit(txn=txn) except Exception as e: logger.error( "Exception on writing execution", exc_info=e) await tm.abort(txn=txn) except (RuntimeError, SystemExit, GeneratorExit, KeyboardInterrupt, asyncio.CancelledError, KeyboardInterrupt): # dive, these errors mean we're exit(ing) self._exceptions = True return except Exception as e: # noqa self._exceptions = True logger.error('Worker call failed', exc_info=e) finally: try: aiotask_context.set('request', None) except (RuntimeError, ValueError): pass if got_obj: try: view.request.execute_futures() except AttributeError: pass self.queue.task_done()
def schema_compatible(value, schema_or_field): """The schema_compatible function converts any value to guillotina.schema compatible data when possible, raising a TypeError for unsupported values. This is done by using the ISchemaCompatible converters. """ if value is None: return value try: return getMultiAdapter((value, schema_or_field), IJSONToValue) except ComponentLookupError: logger.error((u'Deserializer not found for field type ' u'"{0:s}" with value "{1:s}" and it was ' u'deserialized to None.').format(schema_or_field, value)) return None
async def initialize(self, app=None): # loop self.app = app while True: got_obj = False try: func, tvars = await self.queue.get() got_obj = True load_task_vars(tvars) txn = get_transaction() tm = get_tm() if txn is None or ( txn.status in (Status.ABORTED, Status.COMMITTED, Status.CONFLICT) and txn._db_conn is None ): txn = await tm.begin() else: # still finishing current transaction, this connection # will be cut off, so we need to wait until we no longer # have an active transaction on the reqeust... await self.add((func, tvars)) await asyncio.sleep(1) continue try: await func() await tm.commit(txn=txn) except Exception as e: logger.error("Exception on writing execution", exc_info=e) await tm.abort(txn=txn) except ( RuntimeError, SystemExit, GeneratorExit, KeyboardInterrupt, asyncio.CancelledError, KeyboardInterrupt, ): # dive, these errors mean we're exit(ing) self._exceptions = True return except Exception as e: # noqa self._exceptions = True logger.error("Worker call failed", exc_info=e) finally: if got_obj: execute.execute_futures() self.queue.task_done()
def generate_error_response(self, e, request, error, status=500): # We may need to check the roles of the users to show the real error eid = uuid.uuid4().hex if isinstance(e, asyncio.CancelledError): # pragma: no cover message = _("Cancelled execution of view") + " " + eid logger.warning(message, exc_info=e, eid=eid, request=request) else: message = _("Error on execution of view") + " " + eid logger.error(message, exc_info=e, eid=eid, request=request) data = { "message": message, "reason": error_reasons.UNKNOWN.name, "details": error_reasons.UNKNOWN.details, "eid": eid, } if app_settings.get("debug"): data["traceback"] = traceback.format_exc() return response.HTTPInternalServerError(content=data)
def generate_error_response(e, request, error, status=500): # We may need to check the roles of the users to show the real error eid = uuid.uuid4().hex http_response = query_adapter( e, IErrorResponseException, kwargs={ 'error': error, 'eid': eid }) if http_response is not None: return http_response message = _('Error on execution of view') + ' ' + eid logger.error(message, exc_info=e, eid=eid, request=request) return response.HTTPInternalServerError(content={ 'message': message, 'reason': error_reasons.UNKNOWN.name, 'details': error_reasons.UNKNOWN.details, 'eid': eid })
async def resolve(self, request: IRequest) -> MatchInfo: ''' Resolve a request ''' request.record('start') result = None try: result = await self.real_resolve(request) except HTTPException as exc: await abort(request) return BasicMatchInfo(request, exc) except Exception as e: logger.error("Exception on resolve execution", exc_info=e, request=request) await abort(request) raise e if result is not None: return result else: await abort(request) return BasicMatchInfo(request, HTTPNotFound())
def generate_error_response(e, request, error, status=500): # We may need to check the roles of the users to show the real error eid = uuid.uuid4().hex http_response = query_adapter(e, IErrorResponseException, kwargs={ "error": error, "eid": eid }) if http_response is not None: return http_response message = _("Error on execution of view") + " " + eid logger.error(message, exc_info=e, eid=eid, request=request) data = { "message": message, "reason": error_reasons.UNKNOWN.name, "details": error_reasons.UNKNOWN.details, "eid": eid, } if app_settings.get("debug"): data["traceback"] = traceback.format_exc() return response.HTTPInternalServerError(content=data)
async def initialize(self, app=None): # loop self.app = app while True: got_obj = False try: priority, view = await self._queue.get() got_obj = True txn = get_transaction(view.request) if txn is None: tm = get_tm(view.request) txn = tm.begin(view.request) try: view_result = await view() if isinstance(view_result, ErrorResponse): await txn.commit() elif isinstance(view_result, UnauthorizedResponse): await txn.abort() else: await txn.commit() except Unauthorized: await txn.abort() except Exception as e: logger.error("Exception on writing execution", exc_info=e) await txn.abort() except KeyboardInterrupt or MemoryError or SystemExit or asyncio.CancelledError: self._exceptions = True raise except Exception as e: # noqa self._exceptions = True logger.error('Worker call failed', exc_info=e) finally: if SHARED_CONNECTION is False and hasattr( view.request, 'conn'): view.request.conn.close() if got_obj: self._queue.task_done()
async def resolve(self, request: IRequest) -> MatchInfo: ''' Resolve a request ''' request.record('start') result = None try: result = await self.real_resolve(request) except (response.Response, aiohttp.web_exceptions.HTTPException) as exc: await abort(request) return BasicMatchInfo(request, exc) except Exception: logger.error("Exception on resolve execution", exc_info=True, request=request) await abort(request) return BasicMatchInfo( request, response.HTTPInternalServerError()) if result is not None: return result else: await abort(request) return BasicMatchInfo(request, response.HTTPNotFound())
async def real_resolve(self, request: IRequest) -> Optional[MatchInfo]: """Main function to resolve a request.""" security = get_adapter(request, IInteraction) if request.method not in app_settings['http_methods']: raise HTTPMethodNotAllowed( method=request.method, allowed_methods=[k for k in app_settings['http_methods'].keys()]) method = app_settings['http_methods'][request.method] try: resource, tail = await self.traverse(request) except ConflictError: # can also happen from connection errors so we bubble this... raise except Exception as _exc: logger.error('Unhandled exception occurred', exc_info=True) request.resource = request.tail = None request.exc = _exc data = { 'success': False, 'exception_message': str(_exc), 'exception_type': getattr(type(_exc), '__name__', str(type(_exc))), # noqa } if app_settings.get('debug'): data['traceback'] = traceback.format_exc() raise HTTPBadRequest(content={ 'reason': data }) request.record('traversed') await notify(ObjectLoadedEvent(resource)) request.resource = resource request.tail = tail if request.resource is None: await notify(TraversalResourceMissEvent(request, tail)) raise HTTPNotFound(content={ "reason": 'Resource not found' }) if tail and len(tail) > 0: # convert match lookups view_name = routes.path_to_view_name(tail) elif not tail: view_name = '' request.record('beforeauthentication') await self.apply_authorization(request) request.record('authentication') for language in get_acceptable_languages(request): translator = query_adapter((resource, request), ILanguage, name=language) if translator is not None: resource = translator.translate() break # Add anonymous participation if len(security.participations) == 0: security.add(AnonymousParticipation(request)) # container registry lookup try: view = query_multi_adapter( (resource, request), method, name=view_name) except AttributeError: view = None if view is None and method == IOPTIONS: view = DefaultOPTIONS(resource, request) # Check security on context to AccessContent unless # is view allows explicit or its OPTIONS permission = get_utility(IPermission, name='guillotina.AccessContent') if not security.check_permission(permission.id, resource): # Check if its a CORS call: if IOPTIONS != method: # Check if the view has permissions explicit if view is None or not view.__allow_access__: logger.info( "No access content {content} with {auths}".format( content=resource, auths=str([x.principal.id for x in security.participations])), request=request) raise HTTPUnauthorized( content={ "reason": "You are not authorized to access content", "content": str(resource), "auths": [x.principal.id for x in security.participations] } ) if not view and len(tail) > 0: # we should have a view in this case because we are matching routes await notify(TraversalViewMissEvent(request, tail)) return None request.found_view = view request.view_name = view_name request.record('viewfound') ViewClass = view.__class__ view_permission = get_view_permission(ViewClass) if not security.check_permission(view_permission, view): if IOPTIONS != method: raise HTTPUnauthorized( content={ "reason": "You are not authorized to view", "content": str(resource), "auths": [x.principal.id for x in security.participations] } ) try: view.__route__.matches(request, tail or []) except (KeyError, IndexError): await notify(TraversalRouteMissEvent(request, tail)) return None except AttributeError: pass if hasattr(view, 'prepare'): view = (await view.prepare()) or view request.record('authorization') return MatchInfo(resource, request, view)
async def real_resolve(self, request: IRequest) -> Optional[MatchInfo]: """Main function to resolve a request.""" if request.method not in app_settings['http_methods']: raise HTTPMethodNotAllowed( method=request.method, allowed_methods=[ k for k in app_settings['http_methods'].keys() ]) method = app_settings['http_methods'][request.method] try: resource, tail = await self.traverse(request) except ConflictError: # can also happen from connection errors so we bubble this... raise except Exception as _exc: logger.error('Unhandled exception occurred', exc_info=True) request.resource = request.tail = None request.exc = _exc data = { 'success': False, 'exception_message': str(_exc), 'exception_type': getattr(type(_exc), '__name__', str(type(_exc))), # noqa } if app_settings.get('debug'): data['traceback'] = traceback.format_exc() raise HTTPBadRequest(content={'reason': data}) request.record('traversed') await notify(ObjectLoadedEvent(resource)) request.resource = resource request.tail = tail if request.resource is None: await notify(TraversalResourceMissEvent(request, tail)) raise HTTPNotFound(content={"reason": 'Resource not found'}) if tail and len(tail) > 0: # convert match lookups view_name = routes.path_to_view_name(tail) elif not tail: view_name = '' request.record('beforeauthentication') authenticated = await authenticate_request(request) # Add anonymous participation if authenticated is None: authenticated = AnonymousUser() set_authenticated_user(authenticated) request.record('authentication') policy = get_security_policy(authenticated) for language in get_acceptable_languages(request): translator = query_adapter((resource, request), ILanguage, name=language) if translator is not None: resource = translator.translate() break # container registry lookup try: view = query_multi_adapter((resource, request), method, name=view_name) except AttributeError: view = None if view is None and method == IOPTIONS: view = DefaultOPTIONS(resource, request) # Check security on context to AccessContent unless # is view allows explicit or its OPTIONS permission = get_utility(IPermission, name='guillotina.AccessContent') if not policy.check_permission(permission.id, resource): # Check if its a CORS call: if IOPTIONS != method: # Check if the view has permissions explicit if view is None or not view.__allow_access__: logger.info( "No access content {content} with {auth}".format( content=resource, auth=authenticated.id), request=request) raise HTTPUnauthorized( content={ "reason": "You are not authorized to access content", "content": str(resource), "auth": authenticated.id }) if not view and len(tail) > 0: # we should have a view in this case because we are matching routes await notify(TraversalViewMissEvent(request, tail)) return None request.found_view = view request.view_name = view_name request.record('viewfound') ViewClass = view.__class__ view_permission = get_view_permission(ViewClass) if view_permission is None: # use default view permission view_permission = app_settings['default_permission'] if not policy.check_permission(view_permission, view): if IOPTIONS != method: raise HTTPUnauthorized( content={ "reason": "You are not authorized to view", "content": str(resource), "auth": authenticated.id }) try: view.__route__.matches(request, tail or []) except (KeyError, IndexError): await notify(TraversalRouteMissEvent(request, tail)) return None except AttributeError: pass if hasattr(view, 'prepare'): view = (await view.prepare()) or view request.record('authorization') return MatchInfo(resource, request, view)
async def real_resolve(self, request): """Main function to resolve a request.""" alsoProvides(request, IRequest) alsoProvides(request, IDefaultLayer) request._futures = {} request.security = IInteraction(request) method = app_settings['http_methods'][request.method] language = language_negotiation(request) language_object = language(request) try: resource, tail = await self.traverse(request) except Exception as _exc: request.resource = request.tail = None request.exc = _exc # XXX should only should traceback if in some sort of dev mode? raise HTTPBadRequest(text=json.dumps({ 'success': False, 'exception_message': str(_exc), 'exception_type': getattr(type(_exc), '__name__', str(type(_exc))), # noqa 'traceback': traceback.format_exc() })) request.resource = resource request.tail = tail if request.resource is None: raise HTTPBadRequest(text='Resource not found') traverse_to = None if tail and len(tail) == 1: view_name = tail[0] elif tail is None or len(tail) == 0: view_name = '' else: view_name = tail[0] traverse_to = tail[1:] await self.apply_authorization(request) translator = queryMultiAdapter((language_object, resource, request), ITranslated) if translator is not None: resource = translator.translate() # Add anonymous participation if len(request.security.participations) == 0: # logger.info("Anonymous User") request.security.add(AnonymousParticipation(request)) # Site registry lookup try: view = queryMultiAdapter((resource, request), method, name=view_name) except AttributeError: view = None # Traverse view if its needed if traverse_to is not None and view is not None: if not ITraversableView.providedBy(view): return None else: try: view = await view.publish_traverse(traverse_to) except Exception as e: logger.error("Exception on view execution", exc_info=e) return None permission = getUtility(IPermission, name='guillotina.AccessContent') interaction = IInteraction(request) allowed = interaction.check_permission(permission.id, resource) if not allowed: # Check if its a CORS call: if IOPTIONS != method or not app_settings['cors']: # Check if the view has permissions explicit if view is None or not view.__allow_access__: logger.warn( "No access content {content} with {auths}".format( content=resource, auths=str([ x.principal.id for x in request.security.participations ]))) raise HTTPUnauthorized() if view is None and method == IOPTIONS: view = DefaultOPTIONS(resource, request) if view: ViewClass = view.__class__ view_permission = get_view_permission(ViewClass) if not interaction.check_permission(view_permission, view): logger.warn("No access for view {content} with {auths}".format( content=resource, auths=str([ x.principal.id for x in request.security.participations ]))) raise HTTPUnauthorized() renderer = content_type_negotiation(request, resource, view) renderer_object = renderer(request) rendered = queryMultiAdapter((renderer_object, view, request), IRendered) if rendered is not None: return MatchInfo(resource, request, view, rendered) else: return None
async def __call__(self): ws = web.WebSocketResponse() await ws.prepare(self.request) async for msg in ws: if msg.tp == aiohttp.MsgType.text: message = ujson.loads(msg.data) if message['op'] == 'close': await ws.close() elif message['op'] == 'GET': method = app_settings['http_methods']['GET'] path = tuple(p for p in message['value'].split('/') if p) # avoid circular import from guillotina.traversal import do_traverse obj, tail = await do_traverse(self.request, self.request.site, path) traverse_to = None if tail and len(tail) == 1: view_name = tail[0] elif tail is None or len(tail) == 0: view_name = '' else: view_name = tail[0] traverse_to = tail[1:] permission = getUtility(IPermission, name='guillotina.AccessContent') allowed = IInteraction(self.request).check_permission( permission.id, obj) if not allowed: response = {'error': 'Not allowed'} ws.send_str(ujson.dumps(response)) try: view = queryMultiAdapter((obj, self.request), method, name=view_name) except AttributeError: view = None if traverse_to is not None: if view is None or not ITraversableView.providedBy( view): response = {'error': 'Not found'} ws.send_str(ujson.dumps(response)) else: try: view = await view.publish_traverse(traverse_to) except Exception as e: logger.error("Exception on view execution", exc_info=e) response = {'error': 'Not found'} ws.send_str(ujson.dumps(response)) view_result = await view() if isinstance(view_result, Response): view_result = view_result.response # Return the value ws.send_str(ujson.dumps(view_result)) # Wait for possible value futures_to_wait = self.request._futures.values() if futures_to_wait: await asyncio.gather(futures_to_wait) self.request._futures = {} else: await ws.close() elif msg.tp == aiohttp.MsgType.error: logger.debug( 'ws connection closed with exception {0:s}'.format( ws.exception())) logger.debug('websocket connection closed') return {}
async def real_resolve(self, request: IRequest) -> MatchInfo: """Main function to resolve a request.""" security = get_adapter(request, IInteraction) if request.method not in app_settings['http_methods']: raise HTTPMethodNotAllowed() method = app_settings['http_methods'][request.method] language = language_negotiation(request) language_object = language(request) try: resource, tail = await self.traverse(request) except ConflictError: # can also happen from connection errors so we bubble this... raise except Exception as _exc: logger.error('Unhandled exception occurred', exc_info=True) request.resource = request.tail = None request.exc = _exc data = { 'success': False, 'exception_message': str(_exc), 'exception_type': getattr(type(_exc), '__name__', str(type(_exc))), # noqa } if app_settings.get('debug'): data['traceback'] = traceback.format_exc() raise HTTPBadRequest(text=ujson.dumps(data)) request.record('traversed') await notify(ObjectLoadedEvent(resource)) request.resource = resource request.tail = tail if request.resource is None: raise HTTPBadRequest(text='Resource not found') traverse_to = None if tail and len(tail) == 1: view_name = tail[0] elif tail is None or len(tail) == 0: view_name = '' else: view_name = tail[0] traverse_to = tail[1:] request.record('beforeauthentication') await self.apply_authorization(request) request.record('authentication') translator = query_adapter(language_object, ITranslated, args=[resource, request]) if translator is not None: resource = translator.translate() # Add anonymous participation if len(security.participations) == 0: security.add(AnonymousParticipation(request)) # container registry lookup try: view = query_multi_adapter((resource, request), method, name=view_name) except AttributeError: view = None request.found_view = view request.view_name = view_name # Traverse view if its needed if traverse_to is not None and view is not None: if not ITraversableView.providedBy(view): return None else: try: view = await view.publish_traverse(traverse_to) except KeyError: return None # not found, it's okay. except Exception as e: logger.error("Exception on view execution", exc_info=e, request=request) return None request.record('viewfound') permission = get_utility(IPermission, name='guillotina.AccessContent') if not security.check_permission(permission.id, resource): # Check if its a CORS call: if IOPTIONS != method: # Check if the view has permissions explicit if view is None or not view.__allow_access__: logger.info( "No access content {content} with {auths}".format( content=resource, auths=str([ x.principal.id for x in security.participations ])), request=request) raise HTTPUnauthorized() if view is None and method == IOPTIONS: view = DefaultOPTIONS(resource, request) if view: ViewClass = view.__class__ view_permission = get_view_permission(ViewClass) if not security.check_permission(view_permission, view): logger.info("No access for view {content} with {auths}".format( content=resource, auths=str( [x.principal.id for x in security.participations])), request=request) raise HTTPUnauthorized() request.record('authorization') renderer = content_type_negotiation(request, resource, view) renderer_object = renderer(request) rendered = query_multi_adapter((renderer_object, view, request), IRendered) request.record('renderer') if rendered is not None: return MatchInfo(resource, request, view, rendered) else: return None
def generate_error_response(e, request, error, status=500): # We may need to check the roles of the users to show the real error eid = uuid.uuid4().hex message = _('Error on execution of view') + ' ' + eid logger.error(message, exc_info=e, eid=eid, request=request) return ErrorResponse(error, message, status)
def generate_unauthorized_response(e, request): # We may need to check the roles of the users to show the real error eid = uuid.uuid4().hex message = _('Not authorized to render operation') + ' ' + eid logger.error(message, exc_info=e, eid=eid, request=request) return UnauthorizedResponse(message)