Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(81)

Unified Diff: tools/telemetry/third_party/gsutil/third_party/protorpc/protorpc/webapp/service_handlers.py

Issue 1260493004: Revert "Add gsutil 4.13 to telemetry/third_party" (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 5 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: tools/telemetry/third_party/gsutil/third_party/protorpc/protorpc/webapp/service_handlers.py
diff --git a/tools/telemetry/third_party/gsutil/third_party/protorpc/protorpc/webapp/service_handlers.py b/tools/telemetry/third_party/gsutil/third_party/protorpc/protorpc/webapp/service_handlers.py
deleted file mode 100644
index a574b2b4e08016c317e3b62168edcc9347264222..0000000000000000000000000000000000000000
--- a/tools/telemetry/third_party/gsutil/third_party/protorpc/protorpc/webapp/service_handlers.py
+++ /dev/null
@@ -1,834 +0,0 @@
-#!/usr/bin/env python
-#
-# Copyright 2010 Google Inc.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-"""Handlers for remote services.
-
-This module contains classes that may be used to build a service
-on top of the App Engine Webapp framework.
-
-The services request handler can be configured to handle requests in a number
-of different request formats. All different request formats must have a way
-to map the request to the service handlers defined request message.Message
-class. The handler can also send a response in any format that can be mapped
-from the response message.Message class.
-
-Participants in an RPC:
-
- There are four classes involved with the life cycle of an RPC.
-
- Service factory: A user-defined service factory that is responsible for
- instantiating an RPC service. The methods intended for use as RPC
- methods must be decorated by the 'remote' decorator.
-
- RPCMapper: Responsible for determining whether or not a specific request
- matches a particular RPC format and translating between the actual
- request/response and the underlying message types. A single instance of
- an RPCMapper sub-class is required per service configuration. Each
- mapper must be usable across multiple requests.
-
- ServiceHandler: A webapp.RequestHandler sub-class that responds to the
- webapp framework. It mediates between the RPCMapper and service
- implementation class during a request. As determined by the Webapp
- framework, a new ServiceHandler instance is created to handle each
- user request. A handler is never used to handle more than one request.
-
- ServiceHandlerFactory: A class that is responsible for creating new,
- properly configured ServiceHandler instance for each request. The
- factory is configured by providing it with a set of RPCMapper instances.
- When the Webapp framework invokes the service handler, the handler
- creates a new service class instance. The service class instance is
- provided with a reference to the handler. A single instance of an
- RPCMapper sub-class is required to configure each service. Each mapper
- instance must be usable across multiple requests.
-
-RPC mappers:
-
- RPC mappers translate between a single HTTP based RPC protocol and the
- underlying service implementation. Each RPC mapper must configured
- with the following information to determine if it is an appropriate
- mapper for a given request:
-
- http_methods: Set of HTTP methods supported by handler.
-
- content_types: Set of supported content types.
-
- default_content_type: Default content type for handler responses.
-
- Built-in mapper implementations:
-
- URLEncodedRPCMapper: Matches requests that are compatible with post
- forms with the 'application/x-www-form-urlencoded' content-type
- (this content type is the default if none is specified. It
- translates post parameters into request parameters.
-
- ProtobufRPCMapper: Matches requests that are compatible with post
- forms with the 'application/x-google-protobuf' content-type. It
- reads the contents of a binary post request.
-
-Public Exceptions:
- Error: Base class for service handler errors.
- ServiceConfigurationError: Raised when a service not correctly configured.
- RequestError: Raised by RPC mappers when there is an error in its request
- or request format.
- ResponseError: Raised by RPC mappers when there is an error in its response.
-"""
-import six
-
-__author__ = 'rafek@google.com (Rafe Kaplan)'
-
-import six.moves.http_client
-import logging
-
-from .google_imports import webapp
-from .google_imports import webapp_util
-from .. import messages
-from .. import protobuf
-from .. import protojson
-from .. import protourlencode
-from .. import registry
-from .. import remote
-from .. import util
-from . import forms
-
-__all__ = [
- 'Error',
- 'RequestError',
- 'ResponseError',
- 'ServiceConfigurationError',
-
- 'DEFAULT_REGISTRY_PATH',
-
- 'ProtobufRPCMapper',
- 'RPCMapper',
- 'ServiceHandler',
- 'ServiceHandlerFactory',
- 'URLEncodedRPCMapper',
- 'JSONRPCMapper',
- 'service_mapping',
- 'run_services',
-]
-
-
-class Error(Exception):
- """Base class for all errors in service handlers module."""
-
-
-class ServiceConfigurationError(Error):
- """When service configuration is incorrect."""
-
-
-class RequestError(Error):
- """Error occurred when building request."""
-
-
-class ResponseError(Error):
- """Error occurred when building response."""
-
-
-_URLENCODED_CONTENT_TYPE = protourlencode.CONTENT_TYPE
-_PROTOBUF_CONTENT_TYPE = protobuf.CONTENT_TYPE
-_JSON_CONTENT_TYPE = protojson.CONTENT_TYPE
-
-_EXTRA_JSON_CONTENT_TYPES = ['application/x-javascript',
- 'text/javascript',
- 'text/x-javascript',
- 'text/x-json',
- 'text/json',
- ]
-
-# The whole method pattern is an optional regex. It contains a single
-# group used for mapping to the query parameter. This is passed to the
-# parameters of 'get' and 'post' on the ServiceHandler.
-_METHOD_PATTERN = r'(?:\.([^?]*))?'
-
-DEFAULT_REGISTRY_PATH = forms.DEFAULT_REGISTRY_PATH
-
-
-class RPCMapper(object):
- """Interface to mediate between request and service object.
-
- Request mappers are implemented to support various types of
- RPC protocols. It is responsible for identifying whether a
- given request matches a particular protocol, resolve the remote
- method to invoke and mediate between the request and appropriate
- protocol messages for the remote method.
- """
-
- @util.positional(4)
- def __init__(self,
- http_methods,
- default_content_type,
- protocol,
- content_types=None):
- """Constructor.
-
- Args:
- http_methods: Set of HTTP methods supported by mapper.
- default_content_type: Default content type supported by mapper.
- protocol: The protocol implementation. Must implement encode_message and
- decode_message.
- content_types: Set of additionally supported content types.
- """
- self.__http_methods = frozenset(http_methods)
- self.__default_content_type = default_content_type
- self.__protocol = protocol
-
- if content_types is None:
- content_types = []
- self.__content_types = frozenset([self.__default_content_type] +
- content_types)
-
- @property
- def http_methods(self):
- return self.__http_methods
-
- @property
- def default_content_type(self):
- return self.__default_content_type
-
- @property
- def content_types(self):
- return self.__content_types
-
- def build_request(self, handler, request_type):
- """Build request message based on request.
-
- Each request mapper implementation is responsible for converting a
- request to an appropriate message instance.
-
- Args:
- handler: RequestHandler instance that is servicing request.
- Must be initialized with request object and been previously determined
- to matching the protocol of the RPCMapper.
- request_type: Message type to build.
-
- Returns:
- Instance of request_type populated by protocol buffer in request body.
-
- Raises:
- RequestError if the mapper implementation is not able to correctly
- convert the request to the appropriate message.
- """
- try:
- return self.__protocol.decode_message(request_type, handler.request.body)
- except (messages.ValidationError, messages.DecodeError) as err:
- raise RequestError('Unable to parse request content: %s' % err)
-
- def build_response(self, handler, response, pad_string=False):
- """Build response based on service object response message.
-
- Each request mapper implementation is responsible for converting a
- response message to an appropriate handler response.
-
- Args:
- handler: RequestHandler instance that is servicing request.
- Must be initialized with request object and been previously determined
- to matching the protocol of the RPCMapper.
- response: Response message as returned from the service object.
-
- Raises:
- ResponseError if the mapper implementation is not able to correctly
- convert the message to an appropriate response.
- """
- try:
- encoded_message = self.__protocol.encode_message(response)
- except messages.ValidationError as err:
- raise ResponseError('Unable to encode message: %s' % err)
- else:
- handler.response.headers['Content-Type'] = self.default_content_type
- handler.response.out.write(encoded_message)
-
-
-class ServiceHandlerFactory(object):
- """Factory class used for instantiating new service handlers.
-
- Normally a handler class is passed directly to the webapp framework
- so that it can be simply instantiated to handle a single request.
- The service handler, however, must be configured with additional
- information so that it knows how to instantiate a service object.
- This class acts the same as a normal RequestHandler class by
- overriding the __call__ method to correctly configures a ServiceHandler
- instance with a new service object.
-
- The factory must also provide a set of RPCMapper instances which
- examine a request to determine what protocol is being used and mediates
- between the request and the service object.
-
- The mapping of a service handler must have a single group indicating the
- part of the URL path that maps to the request method. This group must
- exist but can be optional for the request (the group may be followed by
- '?' in the regular expression matching the request).
-
- Usage:
-
- stock_factory = ServiceHandlerFactory(StockService)
- ... configure stock_factory by adding RPCMapper instances ...
-
- application = webapp.WSGIApplication(
- [stock_factory.mapping('/stocks')])
-
- Default usage:
-
- application = webapp.WSGIApplication(
- [ServiceHandlerFactory.default(StockService).mapping('/stocks')])
- """
-
- def __init__(self, service_factory):
- """Constructor.
-
- Args:
- service_factory: Service factory to instantiate and provide to
- service handler.
- """
- self.__service_factory = service_factory
- self.__request_mappers = []
-
- def all_request_mappers(self):
- """Get all request mappers.
-
- Returns:
- Iterator of all request mappers used by this service factory.
- """
- return iter(self.__request_mappers)
-
- def add_request_mapper(self, mapper):
- """Add request mapper to end of request mapper list."""
- self.__request_mappers.append(mapper)
-
- def __call__(self):
- """Construct a new service handler instance."""
- return ServiceHandler(self, self.__service_factory())
-
- @property
- def service_factory(self):
- """Service factory associated with this factory."""
- return self.__service_factory
-
- @staticmethod
- def __check_path(path):
- """Check a path parameter.
-
- Make sure a provided path parameter is compatible with the
- webapp URL mapping.
-
- Args:
- path: Path to check. This is a plain path, not a regular expression.
-
- Raises:
- ValueError if path does not start with /, path ends with /.
- """
- if path.endswith('/'):
- raise ValueError('Path %s must not end with /.' % path)
-
- def mapping(self, path):
- """Convenience method to map service to application.
-
- Args:
- path: Path to map service to. It must be a simple path
- with a leading / and no trailing /.
-
- Returns:
- Mapping from service URL to service handler factory.
- """
- self.__check_path(path)
-
- service_url_pattern = r'(%s)%s' % (path, _METHOD_PATTERN)
-
- return service_url_pattern, self
-
- @classmethod
- def default(cls, service_factory, parameter_prefix=''):
- """Convenience method to map default factory configuration to application.
-
- Creates a standardized default service factory configuration that pre-maps
- the URL encoded protocol handler to the factory.
-
- Args:
- service_factory: Service factory to instantiate and provide to
- service handler.
- method_parameter: The name of the form parameter used to determine the
- method to invoke used by the URLEncodedRPCMapper. If None, no
- parameter is used and the mapper will only match against the form
- path-name. Defaults to 'method'.
- parameter_prefix: If provided, all the parameters in the form are
- expected to begin with that prefix by the URLEncodedRPCMapper.
-
- Returns:
- Mapping from service URL to service handler factory.
- """
- factory = cls(service_factory)
-
- factory.add_request_mapper(ProtobufRPCMapper())
- factory.add_request_mapper(JSONRPCMapper())
-
- return factory
-
-
-class ServiceHandler(webapp.RequestHandler):
- """Web handler for RPC service.
-
- Overridden methods:
- get: All requests handled by 'handle' method. HTTP method stored in
- attribute. Takes remote_method parameter as derived from the URL mapping.
- post: All requests handled by 'handle' method. HTTP method stored in
- attribute. Takes remote_method parameter as derived from the URL mapping.
- redirect: Not implemented for this service handler.
-
- New methods:
- handle: Handle request for both GET and POST.
-
- Attributes (in addition to attributes in RequestHandler):
- service: Service instance associated with request being handled.
- method: Method of request. Used by RPCMapper to determine match.
- remote_method: Sub-path as provided to the 'get' and 'post' methods.
- """
-
- def __init__(self, factory, service):
- """Constructor.
-
- Args:
- factory: Instance of ServiceFactory used for constructing new service
- instances used for handling requests.
- service: Service instance used for handling RPC.
- """
- self.__factory = factory
- self.__service = service
-
- @property
- def service(self):
- return self.__service
-
- def __show_info(self, service_path, remote_method):
- self.response.headers['content-type'] = 'text/plain; charset=utf-8'
- response_message = []
- if remote_method:
- response_message.append('%s.%s is a ProtoRPC method.\n\n' %(
- service_path, remote_method))
- else:
- response_message.append('%s is a ProtoRPC service.\n\n' % service_path)
- definition_name_function = getattr(self.__service, 'definition_name', None)
- if definition_name_function:
- definition_name = definition_name_function()
- else:
- definition_name = '%s.%s' % (self.__service.__module__,
- self.__service.__class__.__name__)
-
- response_message.append('Service %s\n\n' % definition_name)
- response_message.append('More about ProtoRPC: ')
-
- response_message.append('http://code.google.com/p/google-protorpc\n')
- self.response.out.write(util.pad_string(''.join(response_message)))
-
- def get(self, service_path, remote_method):
- """Handler method for GET requests.
-
- Args:
- service_path: Service path derived from request URL.
- remote_method: Sub-path after service path has been matched.
- """
- self.handle('GET', service_path, remote_method)
-
- def post(self, service_path, remote_method):
- """Handler method for POST requests.
-
- Args:
- service_path: Service path derived from request URL.
- remote_method: Sub-path after service path has been matched.
- """
- self.handle('POST', service_path, remote_method)
-
- def redirect(self, uri, permanent=False):
- """Not supported for services."""
- raise NotImplementedError('Services do not currently support redirection.')
-
- def __send_error(self,
- http_code,
- status_state,
- error_message,
- mapper,
- error_name=None):
- status = remote.RpcStatus(state=status_state,
- error_message=error_message,
- error_name=error_name)
- mapper.build_response(self, status)
- self.response.headers['content-type'] = mapper.default_content_type
-
- logging.error(error_message)
- response_content = self.response.out.getvalue()
- padding = ' ' * max(0, 512 - len(response_content))
- self.response.out.write(padding)
-
- self.response.set_status(http_code, error_message)
-
- def __send_simple_error(self, code, message, pad=True):
- """Send error to caller without embedded message."""
- self.response.headers['content-type'] = 'text/plain; charset=utf-8'
- logging.error(message)
- self.response.set_status(code, message)
-
- response_message = six.moves.http_client.responses.get(code, 'Unknown Error')
- if pad:
- response_message = util.pad_string(response_message)
- self.response.out.write(response_message)
-
- def __get_content_type(self):
- content_type = self.request.headers.get('content-type', None)
- if not content_type:
- content_type = self.request.environ.get('HTTP_CONTENT_TYPE', None)
- if not content_type:
- return None
-
- # Lop off parameters from the end (for example content-encoding)
- return content_type.split(';', 1)[0].lower()
-
- def __headers(self, content_type):
- for name in self.request.headers:
- name = name.lower()
- if name == 'content-type':
- value = content_type
- elif name == 'content-length':
- value = str(len(self.request.body))
- else:
- value = self.request.headers.get(name, '')
- yield name, value
-
- def handle(self, http_method, service_path, remote_method):
- """Handle a service request.
-
- The handle method will handle either a GET or POST response.
- It is up to the individual mappers from the handler factory to determine
- which request methods they can service.
-
- If the protocol is not recognized, the request does not provide a correct
- request for that protocol or the service object does not support the
- requested RPC method, will return error code 400 in the response.
-
- Args:
- http_method: HTTP method of request.
- service_path: Service path derived from request URL.
- remote_method: Sub-path after service path has been matched.
- """
- self.response.headers['x-content-type-options'] = 'nosniff'
- if not remote_method and http_method == 'GET':
- # Special case a normal get request, presumably via a browser.
- self.error(405)
- self.__show_info(service_path, remote_method)
- return
-
- content_type = self.__get_content_type()
-
- # Provide server state to the service. If the service object does not have
- # an "initialize_request_state" method, will not attempt to assign state.
- try:
- state_initializer = self.service.initialize_request_state
- except AttributeError:
- pass
- else:
- server_port = self.request.environ.get('SERVER_PORT', None)
- if server_port:
- server_port = int(server_port)
-
- request_state = remote.HttpRequestState(
- remote_host=self.request.environ.get('REMOTE_HOST', None),
- remote_address=self.request.environ.get('REMOTE_ADDR', None),
- server_host=self.request.environ.get('SERVER_HOST', None),
- server_port=server_port,
- http_method=http_method,
- service_path=service_path,
- headers=list(self.__headers(content_type)))
- state_initializer(request_state)
-
- if not content_type:
- self.__send_simple_error(400, 'Invalid RPC request: missing content-type')
- return
-
- # Search for mapper to mediate request.
- for mapper in self.__factory.all_request_mappers():
- if content_type in mapper.content_types:
- break
- else:
- if http_method == 'GET':
- self.error(six.moves.http_client.UNSUPPORTED_MEDIA_TYPE)
- self.__show_info(service_path, remote_method)
- else:
- self.__send_simple_error(six.moves.http_client.UNSUPPORTED_MEDIA_TYPE,
- 'Unsupported content-type: %s' % content_type)
- return
-
- try:
- if http_method not in mapper.http_methods:
- if http_method == 'GET':
- self.error(six.moves.http_client.METHOD_NOT_ALLOWED)
- self.__show_info(service_path, remote_method)
- else:
- self.__send_simple_error(six.moves.http_client.METHOD_NOT_ALLOWED,
- 'Unsupported HTTP method: %s' % http_method)
- return
-
- try:
- try:
- method = getattr(self.service, remote_method)
- method_info = method.remote
- except AttributeError as err:
- self.__send_error(
- 400, remote.RpcState.METHOD_NOT_FOUND_ERROR,
- 'Unrecognized RPC method: %s' % remote_method,
- mapper)
- return
-
- request = mapper.build_request(self, method_info.request_type)
- except (RequestError, messages.DecodeError) as err:
- self.__send_error(400,
- remote.RpcState.REQUEST_ERROR,
- 'Error parsing ProtoRPC request (%s)' % err,
- mapper)
- return
-
- try:
- response = method(request)
- except remote.ApplicationError as err:
- self.__send_error(400,
- remote.RpcState.APPLICATION_ERROR,
- err.message,
- mapper,
- err.error_name)
- return
-
- mapper.build_response(self, response)
- except Exception as err:
- logging.error('An unexpected error occured when handling RPC: %s',
- err, exc_info=1)
-
- self.__send_error(500,
- remote.RpcState.SERVER_ERROR,
- 'Internal Server Error',
- mapper)
- return
-
-
-# TODO(rafek): Support tag-id only forms.
-class URLEncodedRPCMapper(RPCMapper):
- """Request mapper for application/x-www-form-urlencoded forms.
-
- This mapper is useful for building forms that can invoke RPC. Many services
- are also configured to work using URL encoded request information because
- of its perceived ease of programming and debugging.
-
- The mapper must be provided with at least method_parameter or
- remote_method_pattern so that it is possible to determine how to determine the
- requests RPC method. If both are provided, the service will respond to both
- method request types, however, only one may be present in a given request.
- If both types are detected, the request will not match.
- """
-
- def __init__(self, parameter_prefix=''):
- """Constructor.
-
- Args:
- parameter_prefix: If provided, all the parameters in the form are
- expected to begin with that prefix.
- """
- # Private attributes:
- # __parameter_prefix: parameter prefix as provided by constructor
- # parameter.
- super(URLEncodedRPCMapper, self).__init__(['POST'],
- _URLENCODED_CONTENT_TYPE,
- self)
- self.__parameter_prefix = parameter_prefix
-
- def encode_message(self, message):
- """Encode a message using parameter prefix.
-
- Args:
- message: Message to URL Encode.
-
- Returns:
- URL encoded message.
- """
- return protourlencode.encode_message(message,
- prefix=self.__parameter_prefix)
-
- @property
- def parameter_prefix(self):
- """Prefix all form parameters are expected to begin with."""
- return self.__parameter_prefix
-
- def build_request(self, handler, request_type):
- """Build request from URL encoded HTTP request.
-
- Constructs message from names of URL encoded parameters. If this service
- handler has a parameter prefix, parameters must begin with it or are
- ignored.
-
- Args:
- handler: RequestHandler instance that is servicing request.
- request_type: Message type to build.
-
- Returns:
- Instance of request_type populated by protocol buffer in request
- parameters.
-
- Raises:
- RequestError if message type contains nested message field or repeated
- message field. Will raise RequestError if there are any repeated
- parameters.
- """
- request = request_type()
- builder = protourlencode.URLEncodedRequestBuilder(
- request, prefix=self.__parameter_prefix)
- for argument in sorted(handler.request.arguments()):
- values = handler.request.get_all(argument)
- try:
- builder.add_parameter(argument, values)
- except messages.DecodeError as err:
- raise RequestError(str(err))
- return request
-
-
-class ProtobufRPCMapper(RPCMapper):
- """Request mapper for application/x-protobuf service requests.
-
- This mapper will parse protocol buffer from a POST body and return the request
- as a protocol buffer.
- """
-
- def __init__(self):
- super(ProtobufRPCMapper, self).__init__(['POST'],
- _PROTOBUF_CONTENT_TYPE,
- protobuf)
-
-
-class JSONRPCMapper(RPCMapper):
- """Request mapper for application/x-protobuf service requests.
-
- This mapper will parse protocol buffer from a POST body and return the request
- as a protocol buffer.
- """
-
- def __init__(self):
- super(JSONRPCMapper, self).__init__(
- ['POST'],
- _JSON_CONTENT_TYPE,
- protojson,
- content_types=_EXTRA_JSON_CONTENT_TYPES)
-
-
-def service_mapping(services,
- registry_path=DEFAULT_REGISTRY_PATH):
- """Create a services mapping for use with webapp.
-
- Creates basic default configuration and registration for ProtoRPC services.
- Each service listed in the service mapping has a standard service handler
- factory created for it.
-
- The list of mappings can either be an explicit path to service mapping or
- just services. If mappings are just services, they will automatically
- be mapped to their default name. For exampel:
-
- package = 'my_package'
-
- class MyService(remote.Service):
- ...
-
- server_mapping([('/my_path', MyService), # Maps to /my_path
- MyService, # Maps to /my_package/MyService
- ])
-
- Specifying a service mapping:
-
- Normally services are mapped to URL paths by specifying a tuple
- (path, service):
- path: The path the service resides on.
- service: The service class or service factory for creating new instances
- of the service. For more information about service factories, please
- see remote.Service.new_factory.
-
- If no tuple is provided, and therefore no path specified, a default path
- is calculated by using the fully qualified service name using a URL path
- separator for each of its components instead of a '.'.
-
- Args:
- services: Can be service type, service factory or string definition name of
- service being mapped or list of tuples (path, service):
- path: Path on server to map service to.
- service: Service type, service factory or string definition name of
- service being mapped.
- Can also be a dict. If so, the keys are treated as the path and values as
- the service.
- registry_path: Path to give to registry service. Use None to disable
- registry service.
-
- Returns:
- List of tuples defining a mapping of request handlers compatible with a
- webapp application.
-
- Raises:
- ServiceConfigurationError when duplicate paths are provided.
- """
- if isinstance(services, dict):
- services = six.iteritems(services)
- mapping = []
- registry_map = {}
-
- if registry_path is not None:
- registry_service = registry.RegistryService.new_factory(registry_map)
- services = list(services) + [(registry_path, registry_service)]
- mapping.append((registry_path + r'/form(?:/)?',
- forms.FormsHandler.new_factory(registry_path)))
- mapping.append((registry_path + r'/form/(.+)', forms.ResourceHandler))
-
- paths = set()
- for service_item in services:
- infer_path = not isinstance(service_item, (list, tuple))
- if infer_path:
- service = service_item
- else:
- service = service_item[1]
-
- service_class = getattr(service, 'service_class', service)
-
- if infer_path:
- path = '/' + service_class.definition_name().replace('.', '/')
- else:
- path = service_item[0]
-
- if path in paths:
- raise ServiceConfigurationError(
- 'Path %r is already defined in service mapping' % path.encode('utf-8'))
- else:
- paths.add(path)
-
- # Create service mapping for webapp.
- new_mapping = ServiceHandlerFactory.default(service).mapping(path)
- mapping.append(new_mapping)
-
- # Update registry with service class.
- registry_map[path] = service_class
-
- return mapping
-
-
-def run_services(services,
- registry_path=DEFAULT_REGISTRY_PATH):
- """Handle CGI request using service mapping.
-
- Args:
- Same as service_mapping.
- """
- mappings = service_mapping(services, registry_path=registry_path)
- application = webapp.WSGIApplication(mappings)
- webapp_util.run_wsgi_app(application)

Powered by Google App Engine
This is Rietveld 408576698