Esempio n. 1
0
 def parse_headers(self, h, expect_content_type=None, expect_accept=None):
     res = headers.parse_headers(collections.OrderedDict(h))
     if expect_content_type is not None:
         self.assertEqual(res.content_type, expect_content_type)
     if expect_accept is not None:
         self.assertEqual(res.accept, expect_accept)
     return res
Esempio n. 2
0
      def _handle(self, context, service, method):
        """Generates the response content and sets the context appropriately.

        Sets context._request_encoding and context._response_encoding.

        Args:
          context: a context.ServicerContext.
          service: the service being targeted by this pRPC call.
          method: the method being invoked by this pRPC call.

        Returns:
          content: the binary or textual content of the RPC response. Note
            that this may be None in the event that an error occurs.
        """
        try:
          parsed_headers = headers.parse_headers(self.request.headers)
          context._request_encoding = parsed_headers.content_type
          context._response_encoding = parsed_headers.accept
        except ValueError as e:
          logging.warning('Error parsing headers: %s', e)
          context.set_code(StatusCode.INVALID_ARGUMENT)
          context.set_details(e.message)
          return None

        if service not in server._services:
          context.set_code(StatusCode.UNIMPLEMENTED)
          context.set_details('Service %s does not exist' % service)
          return None
        rpc_handler = server._services[service].methods.get(method)
        if rpc_handler is None:
          context.set_code(StatusCode.UNIMPLEMENTED)
          context.set_details('Method %s does not exist' % method)
          return None
        request_message, response_message, handler = rpc_handler

        request = request_message()
        try:
          decoder = encoding.get_decoder(parsed_headers.content_type)
          decoder(self.request.body, request)
        except Exception as e:
          logging.warning('Failed to decode request: %s', e, exc_info=True)
          context.set_code(StatusCode.INVALID_ARGUMENT)
          context.set_details('Error parsing request: %s' % e.message)
          return None

        context._timeout = parsed_headers.timeout
        context._invocation_metadata = parsed_headers.invocation_metadata

        # Only ipv6 addresses have ':' in them. Assume everything else is ipv4.
        if ':' in self.request.remote_addr:
          context._peer = 'ipv6:[%s]' % self.request.remote_addr
        else:
          context._peer = 'ipv4:%s' % self.request.remote_addr

        call_details = HandlerCallDetails(
            method='%s.%s' % (service, method),
            invocation_metadata=context.invocation_metadata())

        try:
          # TODO(nodir,mknyszek): Poll for context to hit timeout or be
          # canceled.
          response = server._run_interceptors(
              request, context, call_details, handler, 0)
        except Exception:
          logging.exception('Service implementation threw an exception')
          context.set_code(StatusCode.INTERNAL)
          context.set_details('Service implementation threw an exception')
          return None

        if response is None:
          if context._code == StatusCode.OK:
            context.set_code(StatusCode.INTERNAL)
            context.set_details(
                'Service implementation didn\'t return a response')
          return None

        if not isinstance(response, response_message):
          logging.error('Service implementation response has incorrect type')
          context.set_code(StatusCode.INTERNAL)
          context.set_details('Service implementation returned invalid value')
          return None

        try:
          encoder = encoding.get_encoder(parsed_headers.accept)
          content = encoder(response)
        except Exception:
          logging.exception('Failed to encode response')
          context.set_code(StatusCode.INTERNAL)
          context.set_details('Error serializing response')
          return None

        return content