def handle_api_static_request(self, request, start_response):
    """Handler for requests to {base_path}/static/.*.

    This calls start_response and returns the response body.

    Args:
      request: An ApiRequest, the request from the user.
      start_response: A function with semantics defined in PEP-333.

    Returns:
      A string containing the response body.
    """
    discovery_api = discovery_api_proxy.DiscoveryApiProxy()
    response, body = discovery_api.get_static_file(request.relative_url)
    status_string = '%d %s' % (response.status, response.reason)
    if response.status == 200:
      # Some of the headers that come back from the server can't be passed
      # along in our response.  Specifically, the response from the server has
      # transfer-encoding: chunked, which doesn't apply to the response that
      # we're forwarding.  There may be other problematic headers, so we strip
      # off everything but Content-Type.
      return util.send_wsgi_response(status_string,
                                     [('Content-Type',
                                       response.getheader('Content-Type'))],
                                     body, start_response)
    else:
      logging.error('Discovery API proxy failed on %s with %d. Details: %s',
                    request.relative_url, response.status, body)
      return util.send_wsgi_response(status_string, response.getheaders(), body,
                                     start_response)
  def handle_api_static_request(self, request, start_response):
    """Handler for requests to {base_path}/static/.*.

    This calls start_response and returns the response body.

    Args:
      request: An ApiRequest, the request from the user.
      start_response: A function with semantics defined in PEP-333.

    Returns:
      A string containing the response body.
    """
    discovery_api = discovery_api_proxy.DiscoveryApiProxy()
    response, body = discovery_api.get_static_file(request.relative_url)
    status_string = '%d %s' % (response.status, response.reason)
    if response.status == 200:
      # Some of the headers that come back from the server can't be passed
      # along in our response.  Specifically, the response from the server has
      # transfer-encoding: chunked, which doesn't apply to the response that
      # we're forwarding.  There may be other problematic headers, so we strip
      # off everything but Content-Type.
      return util.send_wsgi_response(status_string,
                                     [('Content-Type',
                                       response.getheader('Content-Type'))],
                                     body, start_response)
    else:
      logging.error('Discovery API proxy failed on %s with %d. Details: %s',
                    request.relative_url, response.status, body)
      return util.send_wsgi_response(status_string, response.getheaders(), body,
                                     start_response)
    def _handle_request_error(self, orig_request, error, start_response):
        """Handle a request error, converting it to a WSGI response.

    Args:
      orig_request: An ApiRequest, the original request from the user.
      error: A RequestError containing information about the error.
      start_response: A function with semantics defined in PEP-333.

    Returns:
      A string containing the response body.
    """
        headers = [('Content-Type', 'application/json')]
        if orig_request.is_rpc():
            # JSON RPC errors are returned with status 200 OK and the
            # error details in the body.
            status_code = 200
            body = self._finish_rpc_response(orig_request.body_json.get('id'),
                                             orig_request.is_batch(),
                                             error.rpc_error())
        else:
            status_code = error.status_code()
            body = error.rest_error()

        response_status = '%d %s' % (
            status_code, httplib.responses.get(status_code, 'Unknown Error'))
        cors_handler = self._create_cors_handler(orig_request)
        return util.send_wsgi_response(response_status,
                                       headers,
                                       body,
                                       start_response,
                                       cors_handler=cors_handler)
    def dispatch_non_api_requests(self, request, start_response):
        """Dispatch this request if this is a request to a reserved URL.

    If the request matches one of our reserved URLs, this calls
    start_response and returns the response body.  This also handles OPTIONS
    CORS requests.

    Args:
      request: An ApiRequest, the request from the user.
      start_response: A function with semantics defined in PEP-333.

    Returns:
      None if the request doesn't match one of the reserved URLs this
      handles.  Otherwise, returns the response body.
    """
        for path_regex, dispatch_function in self._dispatchers:
            if path_regex.match(request.relative_url):
                return dispatch_function(request, start_response)

        if request.http_method == 'OPTIONS':
            cors_handler = self._create_cors_handler(request)
            if cors_handler.allow_cors_request:
                # The server returns 200 rather than 204, for some reason.
                return util.send_wsgi_response('200', [], '', start_response,
                                               cors_handler)

        return None
  def _handle_request_error(self, orig_request, error, start_response):
    """Handle a request error, converting it to a WSGI response.

    Args:
      orig_request: An ApiRequest, the original request from the user.
      error: A RequestError containing information about the error.
      start_response: A function with semantics defined in PEP-333.

    Returns:
      A string containing the response body.
    """
    headers = [('Content-Type', 'application/json')]
    if orig_request.is_rpc():
      # JSON RPC errors are returned with status 200 OK and the
      # error details in the body.
      status_code = 200
      body = self._finish_rpc_response(orig_request.body_json.get('id'),
                                       orig_request.is_batch(),
                                       error.rpc_error())
    else:
      status_code = error.status_code()
      body = error.rest_error()

    response_status = '%d %s' % (status_code,
                                 httplib.responses.get(status_code,
                                                       'Unknown Error'))
    cors_handler = self._create_cors_handler(orig_request)
    return util.send_wsgi_response(response_status, headers, body,
                                   start_response, cors_handler=cors_handler)
  def dispatch_non_api_requests(self, request, start_response):
    """Dispatch this request if this is a request to a reserved URL.

    If the request matches one of our reserved URLs, this calls
    start_response and returns the response body.  This also handles OPTIONS
    CORS requests.

    Args:
      request: An ApiRequest, the request from the user.
      start_response: A function with semantics defined in PEP-333.

    Returns:
      None if the request doesn't match one of the reserved URLs this
      handles.  Otherwise, returns the response body.
    """
    for path_regex, dispatch_function in self._dispatchers:
      if path_regex.match(request.relative_url):
        return dispatch_function(request, start_response)

    if request.http_method == 'OPTIONS':
      cors_handler = self._create_cors_handler(request)
      if cors_handler.allow_cors_request:
        # The server returns 200 rather than 204, for some reason.
        return util.send_wsgi_response('200', [], '', start_response,
                                       cors_handler)

    return None
    def handle_backend_response(self, orig_request, backend_request,
                                response_status, response_headers,
                                response_body, method_config, start_response):
        """Handle backend response, transforming output as needed.

    This calls start_response and returns the response body.

    Args:
      orig_request: An ApiRequest, the original request from the user.
      backend_request: An ApiRequest, the transformed request that was
                       sent to the backend handler.
      response_status: A string, the status from the response.
      response_headers: A dict, the headers from the response.
      response_body: A string, the body of the response.
      method_config: A dict, the API config of the method to be called.
      start_response: A function with semantics defined in PEP-333.

    Returns:
      A string containing the response body.
    """
        # Verify that the response is json.  If it isn't treat, the body as an
        # error message and wrap it in a json error response.
        for header, value in response_headers:
            if (header.lower() == 'content-type'
                    and not value.lower().startswith('application/json')):
                return self.fail_request(orig_request,
                                         'Non-JSON reply: %s' % response_body,
                                         start_response)

        self.check_error_response(response_body, response_status)

        # Need to check is_rpc() against the original request, because the
        # incoming request here has had its path modified.
        if orig_request.is_rpc():
            body = self.transform_jsonrpc_response(backend_request,
                                                   response_body)
        else:
            # Check if the response from the API was empty.  Empty REST responses
            # generate a HTTP 204.
            empty_response = self.check_empty_response(orig_request,
                                                       method_config,
                                                       start_response)
            if empty_response is not None:
                return empty_response

            body = self.transform_rest_response(response_body)

        cors_handler = self._create_cors_handler(orig_request)
        return util.send_wsgi_response(response_status,
                                       response_headers,
                                       body,
                                       start_response,
                                       cors_handler=cors_handler)
    def handle_api_static_request(self, request, start_response):
        """Handler for requests to {base_path}/static/.*.

    This calls start_response and returns the response body.

    Args:
      request: An ApiRequest, the request from the user.
      start_response: A function with semantics defined in PEP-333.

    Returns:
      A string containing the response body.
    """
        if request.path == PROXY_PATH:
            return util.send_wsgi_response('200 OK',
                                           [('Content-Type', 'text/html')],
                                           PROXY_HTML, start_response)
        else:
            logging.error('Unknown static url requested: %s',
                          request.relative_url)
            return util.send_wsgi_response('404 Not Found',
                                           [('Content-Type', 'text/plain')],
                                           'Not Found', start_response)
  def _send_success_response(self, response, start_response):
    """Sends an HTTP 200 json success response.

    This calls start_response and returns the response body.

    Args:
      response: A string containing the response body to return.
      start_response: A function with semantics defined in PEP-333.

    Returns:
      A string, the response body.
    """
    headers = [('Content-Type', 'application/json; charset=UTF-8')]
    return util.send_wsgi_response('200', headers, response, start_response)
  def handle_backend_response(self, orig_request, backend_request,
                              response_status, response_headers,
                              response_body, method_config, start_response):
    """Handle backend response, transforming output as needed.

    This calls start_response and returns the response body.

    Args:
      orig_request: An ApiRequest, the original request from the user.
      backend_request: An ApiRequest, the transformed request that was
                       sent to the backend handler.
      response_status: A string, the status from the response.
      response_headers: A dict, the headers from the response.
      response_body: A string, the body of the response.
      method_config: A dict, the API config of the method to be called.
      start_response: A function with semantics defined in PEP-333.

    Returns:
      A string containing the response body.
    """
    # Verify that the response is json.  If it isn't treat, the body as an
    # error message and wrap it in a json error response.
    for header, value in response_headers:
      if (header.lower() == 'content-type' and
          not value.lower().startswith('application/json')):
        return self.fail_request(orig_request,
                                 'Non-JSON reply: %s' % response_body,
                                 start_response)

    self.check_error_response(response_body, response_status)

    # Need to check is_rpc() against the original request, because the
    # incoming request here has had its path modified.
    if orig_request.is_rpc():
      body = self.transform_jsonrpc_response(backend_request, response_body)
    else:
      # Check if the response from the API was empty.  Empty REST responses
      # generate a HTTP 204.
      empty_response = self.check_empty_response(orig_request, method_config,
                                                 start_response)
      if empty_response is not None:
        return empty_response

      body = self.transform_rest_response(response_body)

    cors_handler = self._create_cors_handler(orig_request)
    return util.send_wsgi_response(response_status, response_headers, body,
                                   start_response, cors_handler=cors_handler)