Exemple #1
0
def rpc_async(req):
    """Sends an asynchronous pRPC request.

  This API is low level. Most users should use Client class instead.

  Args:
    req (Request): a pRPC request.

  Returns the response message if the RPC status code is OK.
  Otherwise raises an Error.
  """

    # The protocol is documented in
    # https://godoc.org/go.chromium.org/luci/grpc/prpc#hdr-Protocol

    # Ensure timeout is set, such that we use same values for deadline
    # parameter in net.request_async and X-Prpc-Timeout value are same.
    # Default to 10s, which is the default used in net.request_async.
    timeout = req.timeout or 10

    headers = (req.metadata or {}).copy()
    headers['Content-Type'] = _BINARY_MEDIA_TYPE
    headers['Accept'] = _BINARY_MEDIA_TYPE
    headers['X-Prpc-Timeout'] = '%dS' % timeout

    try:
        res_bytes = yield net.request_async(
            url='http%s://%s/prpc/%s/%s' % (
                '' if req.insecure else 's',
                req.hostname,
                req.service_name,
                req.method_name,
            ),
            method='POST',
            payload=req.request_message.SerializeToString(),
            headers=headers,
            scopes=req.scopes,
            service_account_key=req.service_account_key,
            delegation_token=req.delegation_token,
            deadline=timeout,
            max_attempts=req.max_attempts or 4,
        )
        # Unfortunately, net module does not expose headers of HTTP 200
        # responses.
        # Assume (HTTP OK => pRPC OK).
    except net.Error as ex:
        # net.Error means HTTP status code was not 200.
        try:
            code = codes.INT_TO_CODE[int(ex.headers['X-Prpc-Grpc-Code'])]
        except (ValueError, KeyError, TypeError):
            raise ProtocolError(
                'response does not contain a valid X-Prpc-Grpc-Code header')
        msg = ex.response.decode('utf-8', 'ignore')
        raise RpcError(msg, code, ex.headers)

    # Status code is OK.
    # Parse the response and return it.
    res = req.response_message
    res.ParseFromString(res_bytes)
    raise ndb.Return(res)
Exemple #2
0
def _load_docs_async(locs, rev):
  """Loads rendered .md files from Gitiles as a list of search.Documents.

  Args:
    locs (list of gitiles.Location): locations of files to import.
    rev (str): revision of files to import.
  """
  fixed_locs = [l._replace(treeish=rev) for l in locs]
  headers = {
    'User-Agent': app_identity.get_default_version_hostname(),
  }
  htmls = yield [
    net.request_async(str(l), headers=headers, scopes=gerrit.AUTH_SCOPE)
    for l in fixed_locs
  ]
  raise ndb.Return([
    create(loc, html) for loc, html in zip(locs, htmls)
  ])
Exemple #3
0
def fetch_file_async(url, oauth_scopes):
    """Fetches a file optionally using OAuth2 for authentication.

  Args:
    url: url to a file to fetch.
    oauth_scopes: list of OAuth scopes to use when generating access_token for
        accessing |url|, if not set or empty - do not use OAuth.

  Returns:
    Byte buffer with file's body.

  Raises:
    BundleImportError on fetch errors.
  """
    try:
        data = yield net.request_async(url, scopes=oauth_scopes, deadline=60)
        raise ndb.Return(data)
    except net.Error as e:
        raise BundleFetchError(url, e.status_code, e.response)
Exemple #4
0
def fetch_file_async(url, oauth_scopes):
  """Fetches a file optionally using OAuth2 for authentication.

  Args:
    url: url to a file to fetch.
    oauth_scopes: list of OAuth scopes to use when generating access_token for
        accessing |url|, if not set or empty - do not use OAuth.

  Returns:
    Byte buffer with file's body.

  Raises:
    BundleImportError on fetch errors.
  """
  try:
    data = yield net.request_async(url, scopes=oauth_scopes, deadline=60)
    raise ndb.Return(data)
  except net.Error as e:
    raise BundleFetchError(url, e.status_code, e.content)
Exemple #5
0
def fetch_async(hostname, path, **kwargs):
    """Sends request to Gerrit, returns raw response.

  See 'net.request_async' for list of accepted kwargs.

  Returns:
    Response body on success.
    None on 404 response.

  Raises:
    net.Error on communication errors.
  """
    assert not path.startswith('/'), path
    assert 'scopes' not in kwargs, kwargs['scopes']
    try:
        url = urlparse.urljoin('https://' + hostname, 'a/' + path)
        result = yield net.request_async(url, scopes=[AUTH_SCOPE], **kwargs)
        raise ndb.Return(result)
    except net.NotFoundError:
        raise ndb.Return(None)
Exemple #6
0
def fetch_async(hostname, path, **kwargs):
  """Sends request to Gerrit, returns raw response.

  See 'net.request_async' for list of accepted kwargs.

  Returns:
    Response body on success.
    None on 404 response.

  Raises:
    net.Error on communication errors.
  """
  assert not path.startswith('/'), path
  assert 'scopes' not in kwargs, kwargs['scopes']
  try:
    url = urlparse.urljoin('https://' + hostname, 'a/' + path)
    result = yield net.request_async(url, scopes=[AUTH_SCOPE], **kwargs)
    raise ndb.Return(result)
  except net.NotFoundError:
    raise ndb.Return(None)
Exemple #7
0
def rpc_async(req, response_metadata=None):
    """Sends an asynchronous pRPC request.

  This API is low level. Most users should use Client class instead.

  Args:
    req (Request): a pRPC request.
    response_metadata (dict): a dict to populate with the response's metadata.

  Returns the response message if the RPC status code is OK, if given,
  populates response_metadata with the response's headers.
  Otherwise raises an Error.
  """

    # The protocol is documented in
    # https://godoc.org/go.chromium.org/luci/grpc/prpc#hdr-Protocol

    # Ensure timeout is set, such that we use same values for deadline
    # parameter in net.request_async and X-Prpc-Timeout value are same.
    # Default to 10s, which is the default used in net.request_async.
    timeout = req.timeout or 10

    headers = (req.metadata or {}).copy()
    encoding.encode_bin_metadata(headers)
    headers['Content-Type'] = _BINARY_MEDIA_TYPE
    headers['Accept'] = _BINARY_MEDIA_TYPE
    headers['X-Prpc-Timeout'] = '%dS' % timeout

    try:
        res_bytes = yield net.request_async(
            url='http%s://%s/prpc/%s/%s' % (
                '' if req.insecure else 's',
                req.hostname,
                req.service_name,
                req.method_name,
            ),
            method='POST',
            payload=req.request_message.SerializeToString(),
            headers=headers,
            scopes=req.scopes,
            service_account_key=req.service_account_key,
            delegation_token=req.delegation_token,
            deadline=timeout,
            max_attempts=req.max_attempts or 4,
            response_headers=response_metadata,
            project_id=req.project_id,
        )
        # Unfortunately, net module does not expose headers of HTTP 200
        # responses.
        # Assume (HTTP OK => pRPC OK).
    except net.Error as ex:
        msg = (ex.response or '<empty>').decode('utf-8', 'ignore')

        # Sometime requests fail before reaching the pRPC server. We recognize few
        # such cases.
        if 'X-Prpc-Grpc-Code' not in ex.headers:
            if ex.status_code == 500:
                raise RpcError(msg, codes.StatusCode.INTERNAL, ex.headers)
            if ex.status_code == 503:
                raise RpcError(msg, codes.StatusCode.UNAVAILABLE, ex.headers)

        # Otherwise it must be a reply from the server with a valid code header.
        try:
            code = codes.INT_TO_CODE[int(ex.headers['X-Prpc-Grpc-Code'])]
        except (ValueError, KeyError, TypeError):
            raise ProtocolError(
                'response does not contain a valid X-Prpc-Grpc-Code header, '
                'its body: %r' % msg)
        raise RpcError(msg, code, ex.headers)

    # Status code is OK.
    # Parse the response and return it.
    res = req.response_message
    res.ParseFromString(res_bytes)
    try:
        encoding.decode_bin_metadata(response_metadata)
    except ValueError as ve:
        raise ProtocolError(ve.message)
    raise ndb.Return(res)