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) raise e if result is not None: return result else: raise HTTPNotFound()
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 schema_compatible(value, schema_or_field): """The schema_compatible function converts any value to zope.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
def schema_compatible(value, schema_or_field): """The schema_compatible function converts any value to zope.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: priority, view = await self._queue.get() got_obj = True if view.request.conn.transaction_manager is None: # Connection was closed # Open DB db = view.request.application[view.request._db_id] if SHARED_CONNECTION: view.request.conn = db.conn else: # Create a new conection view.request.conn = db.open() view.context = view.request.conn.get(view.context._p_oid) txn = view.request.conn.transaction_manager.begin(view.request) try: view_result = await view() if isinstance(view_result, ErrorResponse): await abort(txn, view.request) elif isinstance(view_result, UnauthorizedResponse): await abort(txn, view.request) else: await commit(txn, view.request) except Unauthorized: await abort(txn, view.request) except Exception as e: logger.error( "Exception on writing execution", exc_info=e) await abort(txn, view.request) 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 initialize(self, app=None): # loop self.app = app while True: got_obj = False try: priority, view = await self._queue.get() got_obj = True if view.request.conn.transaction_manager is None: # Connection was closed # Open DB db = view.request.application[view.request._db_id] if SHARED_CONNECTION: view.request.conn = db.conn else: # Create a new conection view.request.conn = db.open() view.context = view.request.conn.get(view.context._p_oid) txn = view.request.conn.transaction_manager.begin(view.request) try: view_result = await view() if isinstance(view_result, ErrorResponse): await sync(view.request)(txn.abort) elif isinstance(view_result, UnauthorizedResponse): await sync(view.request)(txn.abort) else: await sync(view.request)(txn.commit) except Unauthorized: await sync(view.request)(txn.abort) view_result = UnauthorizedResponse( _('Not authorized to render operation')) except Exception as e: logger.error("Exception on writing execution", exc_info=e) await sync(view.request)(txn.abort) view_result = ErrorResponse( 'ServiceError', _('Error on execution of operation')) 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 got_obj: self._queue.task_done()
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 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 = view.publishTraverse(traverse_to) except Exception as e: logger.error( "Exception on view execution", exc_info=e) return None permission = getUtility(IPermission, name='plone.AccessContent') allowed = request.security.checkPermission(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) checker = getCheckerForInstancesOf(view.__class__) if checker is not None: view = ProxyFactory(view, checker) # We want to check for the content negotiation 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
def make_app(config_file=None, settings=None): app_settings.update(_delayed_default_settings) # Initialize aiohttp app app = web.Application(router=TraversalRouter()) # Create root Application root = ApplicationRoot(config_file) root.app = app provideUtility(root, IApplication, 'root') # Initialize global (threadlocal) ZCA configuration app.config = ConfigurationMachine() registerCommonDirectives(app.config) if config_file is not None: with open(config_file, 'r') as config: settings = json.load(config) elif settings is None: raise Exception('Neither configuration or settings') import plone.server configure.include("zope.component") configure.include("zope.annotation") configure.include("plone.server", "meta.zcml") # bbb configure.scan('plone.server.translation') configure.scan('plone.server.renderers') configure.scan('plone.server.api') configure.scan('plone.server.content') configure.scan('plone.server.security') configure.scan('plone.server.json') configure.scan('plone.server.behaviors') configure.scan('plone.server.languages') configure.scan('plone.server.permissions') configure.scan('plone.server.migrate.migrations') configure.scan('plone.server.auth.participation') configure.scan('plone.server.auth.principalrole') configure.scan('plone.server.catalog.index') configure.scan('plone.server.catalog.catalog') configure.scan('plone.server.framing') configure.scan('plone.server.file') configure.scan('plone.server.types') load_application(plone.server, root, settings) for ep in iter_entry_points('plone.server'): # auto-include applications # What an "app" include consists of... # 1. load zcml if present # 2. load "includeme" module function if present # 3. load app_settings dict if present in the module if ep.module_name not in settings.get('applications', []): continue load_application(ep.load(), root, settings) try: app.config.execute_actions() except ConfigurationConflictError as e: logger.error(str(e._conflicts)) raise e # XXX we clear now to save some memory # it's unclear to me if this is necesary or not but it seems to me that # we don't need things registered in both components AND here. configure.clear() # update *after* plugins loaded update_app_settings(settings) content_type = ContentNegotiatorUtility( 'content_type', app_settings['renderers'].keys()) language = ContentNegotiatorUtility( 'language', app_settings['languages'].keys()) provideUtility(content_type, IContentNegotiation, 'content_type') provideUtility(language, IContentNegotiation, 'language') for database in app_settings['databases']: for key, dbconfig in database.items(): factory = getUtility( IDatabaseConfigurationFactory, name=dbconfig['storage']) root[key] = factory(key, dbconfig) for static in app_settings['static']: for key, file_path in static.items(): root[key] = StaticFile(file_path) root.set_root_user(app_settings['root_user']) if RSA is not None and not app_settings.get('rsa'): key = RSA.generate(2048) pub_jwk = {'k': key.publickey().exportKey('PEM')} priv_jwk = {'k': key.exportKey('PEM')} app_settings['rsa'] = { 'pub': pub_jwk, 'priv': priv_jwk } # Set router root app.router.set_root(root) for utility in getAllUtilitiesRegisteredFor(IAsyncUtility): # In case there is Utilties that are registered from zcml ident = asyncio.ensure_future(utility.initialize(app=app), loop=app.loop) root.add_async_utility(ident, {}) app.on_cleanup.append(close_utilities) for util in app_settings['utilities']: root.add_async_utility(util) # Load cached Schemas load_cached_schema() return app
async def __call__(self): ws = web.WebSocketResponse() await ws.prepare(self.request) async for msg in ws: if msg.tp == aiohttp.WSMsgType.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 plone.server.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='plone.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 = view.publishTraverse(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.WSMsgType.error: logger.debug('ws connection closed with exception {0:s}' .format(ws.exception())) logger.debug('websocket connection closed') return {}
def make_app(config_file=None, settings=None): app_settings.update(_delayed_default_settings) # Initialize aiohttp app app = web.Application( router=TraversalRouter(), **settings.get('aiohttp_settings', {})) # Create root Application root = ApplicationRoot(config_file) root.app = app provideUtility(root, IApplication, 'root') # Initialize global (threadlocal) ZCA configuration app.config = ConfigurationMachine() registerCommonDirectives(app.config) if config_file is not None: with open(config_file, 'r') as config: settings = json.load(config) elif settings is None: raise Exception('Neither configuration or settings') import plone.server configure.include("zope.component") configure.include("zope.annotation") configure.include("plone.server", "meta.zcml") # bbb configure.scan('plone.server.translation') configure.scan('plone.server.renderers') configure.scan('plone.server.api') configure.scan('plone.server.content') configure.scan('plone.server.auth') configure.scan('plone.server.json') configure.scan('plone.server.behaviors') configure.scan('plone.server.languages') configure.scan('plone.server.permissions') configure.scan('plone.server.migrate.migrations') configure.scan('plone.server.auth.checker') configure.scan('plone.server.auth.security_local') configure.scan('plone.server.auth.policy') configure.scan('plone.server.auth.participation') configure.scan('plone.server.catalog.index') configure.scan('plone.server.catalog.catalog') configure.scan('plone.server.framing') configure.scan('plone.server.file') configure.scan('plone.server.types') load_application(plone.server, root, settings) for ep in iter_entry_points('plone.server'): # auto-include applications # What an "app" include consists of... # 1. load zcml if present # 2. load "includeme" module function if present # 3. load app_settings dict if present in the module if ep.module_name not in settings.get('applications', []): continue load_application(ep.load(), root, settings) try: app.config.execute_actions() except ConfigurationConflictError as e: logger.error(str(e._conflicts)) raise e # XXX we clear now to save some memory # it's unclear to me if this is necesary or not but it seems to me that # we don't need things registered in both components AND here. configure.clear() # update *after* plugins loaded update_app_settings(settings) content_type = ContentNegotiatorUtility( 'content_type', app_settings['renderers'].keys()) language = ContentNegotiatorUtility( 'language', app_settings['languages'].keys()) provideUtility(content_type, IContentNegotiation, 'content_type') provideUtility(language, IContentNegotiation, 'language') for database in app_settings['databases']: for key, dbconfig in database.items(): factory = getUtility( IDatabaseConfigurationFactory, name=dbconfig['storage']) root[key] = factory(key, dbconfig) for static in app_settings['static']: for key, file_path in static.items(): path = pathlib.Path(file_path) if path.is_dir(): root[key] = StaticDirectory(path) else: root[key] = StaticFile(path) root.set_root_user(app_settings['root_user']) if RSA is not None and not app_settings.get('rsa'): key = RSA.generate(2048) pub_jwk = {'k': key.publickey().exportKey('PEM')} priv_jwk = {'k': key.exportKey('PEM')} app_settings['rsa'] = { 'pub': pub_jwk, 'priv': priv_jwk } # Set router root app.router.set_root(root) for utility in getAllUtilitiesRegisteredFor(IAsyncUtility): # In case there is Utilties that are registered from zcml ident = asyncio.ensure_future(utility.initialize(app=app), loop=app.loop) root.add_async_utility(ident, {}) app.on_cleanup.append(close_utilities) for util in app_settings['utilities']: root.add_async_utility(util) # Load cached Schemas load_cached_schema() return app
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 plone.server.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='plone.AccessContent') allowed = self.request.security.checkPermission( 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 = view.publishTraverse(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 ws.send_str(ujson.dumps(view_result)) 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 {}