def __init__(self, msg_handler_map, provider_config): """ Initialize WsgiApplication :type msg_handler_map: :class:`dict` of :class:`str` and :class:`vmware.vapi.protocol.server.api_handler.ApiHandler` :param msg_handler_map: Map of content type to the message handler for that content type """ self._msg_handler_map = msg_handler_map jsonrpc_prefix = provider_config.get_jsonrpc_prefix() if jsonrpc_prefix: routing_rules = [Rule(jsonrpc_prefix, endpoint=JSONRPC)] else: # No prefix specified, use path converter rule, that matches # any prefix. # This is used for backcompat as previously, specifying # jsonrpc prefix was not required for wsgi applications. routing_rules = [Rule('/<path:path>', endpoint=JSONRPC)] if provider_config.enable_rest(): json_msg_handler = self._msg_handler_map.get(JSON_CONTENT_TYPE) allow_cookies = provider_config.are_cookies_supported() self._rest_handler = RESTHandler(json_msg_handler.provider, allow_cookies, provider_config) self._rest_prefix = provider_config.get_rest_prefix() routing_rules += self._rest_handler.rest_rules self.rule_map = Map(routing_rules) logger.info(self.rule_map)
def __init__(self, msg_handler_map, provider_config): """ Initialize WsgiApplication :type msg_handler_map: :class:`dict` of :class:`str` and :class:`vmware.vapi.protocol.server.api_handler.ApiHandler` :param msg_handler_map: Map of content type to the message handler for that content type """ self._msg_handler_map = msg_handler_map jsonrpc_prefix = provider_config.get_jsonrpc_prefix() if jsonrpc_prefix: routing_rules = [Rule(jsonrpc_prefix, endpoint=JSONRPC)] else: # No prefix specified, use path converter rule, that matches # any prefix. # This is used for backcompat as previously, specifying # jsonrpc prefix was not required for wsgi applications. routing_rules = [Rule('/<path:path>', endpoint=JSONRPC)] if provider_config.enable_rest(): json_msg_handler = self._msg_handler_map.get(JSON_CONTENT_TYPE) allow_cookies = provider_config.are_cookies_supported() self._rest_handler = RESTHandler(json_msg_handler.provider, allow_cookies, provider_config) self._rest_prefix = provider_config.get_rest_prefix() routing_rules += self._rest_handler.rest_rules # There are some request mapping arguments that has '-' in them which # is not allowed by werkzeug so change the dashes with '__' dash_pattern = re.compile(r'-(?=[^<>]*>)') for rule in routing_rules: rule.rule = dash_pattern.sub(r'__', rule.rule) self.rule_map = Map(routing_rules) logger.info(self.rule_map)
class WsgiApplication(object): """ Python WSGI application. For more details about WSGI specification, see PEP 333. """ def __init__(self, msg_handler_map, provider_config): """ Initialize WsgiApplication :type msg_handler_map: :class:`dict` of :class:`str` and :class:`vmware.vapi.protocol.server.api_handler.ApiHandler` :param msg_handler_map: Map of content type to the message handler for that content type """ self._msg_handler_map = msg_handler_map jsonrpc_prefix = provider_config.get_jsonrpc_prefix() if jsonrpc_prefix: routing_rules = [Rule(jsonrpc_prefix, endpoint=JSONRPC)] else: # No prefix specified, use path converter rule, that matches # any prefix. # This is used for backcompat as previously, specifying # jsonrpc prefix was not required for wsgi applications. routing_rules = [Rule('/<path:path>', endpoint=JSONRPC)] if provider_config.enable_rest(): json_msg_handler = self._msg_handler_map.get(JSON_CONTENT_TYPE) allow_cookies = provider_config.are_cookies_supported() self._rest_handler = RESTHandler(json_msg_handler.provider, allow_cookies, provider_config) self._rest_prefix = provider_config.get_rest_prefix() routing_rules += self._rest_handler.rest_rules self.rule_map = Map(routing_rules) logger.info(self.rule_map) def _handle_jsonrpc_call(self, request): """ Handle a JSONRPC protocol request :type request: :class:`werkzeug.wrappers.Request` :param request: Request object :rtype: :class:`str` :return: output string """ content_type, _ = werkzeug.http.parse_options_header( request.content_type) handler = self._msg_handler_map.get(content_type) if handler is None: raise werkzeug.exceptions.BadRequest( 'Content-Type %s is not supported' % (content_type)) else: try: result, headers = handler.handle_request( request.get_data(), request.headers) except Exception as e: logger.exception(e) raise werkzeug.exceptions.InternalServerError( 'Unexpected error. See server logs for more details.') return result, headers def _handle_rest_call(self, request, endpoint, args): """ Handle HTTP REST call :type request: :class:`werkzeug.wrappers.Request` :param request: Request object :type endpoint: :class:`str` :param endpoint: Tuple of service ID and operation ID :type args: :class:`dict` of :class:`str` and :class:`object` :param args: Arguments parsed from the HTTP URL :rtype: :class:`tuple` of :class:`str` and :class:`str` :return: HTTP status string and output """ # Accept only json content type if request.content_length: content_type, _ = werkzeug.http.parse_options_header( request.content_type) if content_type != JSON_CONTENT_TYPE and request.method in [ 'POST', 'PATCH', 'PUT' ]: raise werkzeug.exceptions.UnsupportedMediaType( '%s content type is not supported' % content_type) try: output = self._rest_handler.invoke(request, endpoint, args) except werkzeug.exceptions.BadRequest as e: raise e except werkzeug.exceptions.NotFound as e: raise e except Exception as e: logger.exception(e) raise werkzeug.exceptions.InternalServerError( 'Unexpected error. See server logs for more details.') return output @Request.application def __call__(self, request): """ The implementation of WsgiApplication :type request: :class:`werkzeug.wrappers.Request` :param request: Request object :rtype: :class:`werkzeug.wrappers.Response` :return: Response object """ try: urls = self.rule_map.bind_to_environ(request.environ) endpoint, args = urls.match() if provider_wire_logger.isEnabledFor(logging.DEBUG): provider_wire_logger.debug('HTTP %s %s ', request.method, request.url) provider_wire_logger.debug('REQUEST HEADERS: %s', request.headers) provider_wire_logger.debug('REQUEST BODY: %s', request.get_data()) if endpoint == JSONRPC: result, headers = self._handle_jsonrpc_call(request) response = Response(result) if headers: response.headers = headers else: status, result, cookies, headers = self._handle_rest_call( request, endpoint, args) response = Response(result) response.status_code = status if headers: response.headers = headers if cookies: path = self._rest_prefix for k, v in six.iteritems(cookies): response.set_cookie(k, v, path=path) response.content_type = JSON_CONTENT_TYPE if provider_wire_logger.isEnabledFor(logging.DEBUG): provider_wire_logger.debug('RESPONSE STATUS: %s', response.status_code) provider_wire_logger.debug('RESPONSE HEADERS: %s', response.headers) provider_wire_logger.debug('RESPONSE BODY: %s', response.response) return response except HTTPException as e: return e