def _WaitImpl(self):

        try:
            already_finishing = False
            with self.lock:

                if self._state == apiproxy_rpc.RPC.FINISHING:
                    already_finishing = True
                else:
                    self._state = apiproxy_rpc.RPC.FINISHING
            if already_finishing:
                self.event.wait()
                return True

            try:

                response = self._result_future.get()

                if response.status_code != requests.codes.ok:
                    raise apiproxy_errors.RPCFailedError(
                        'Proxy returned HTTP status %s %s' %
                        (response.status_code, response.reason))
            except requests.exceptions.Timeout:

                raise self._ErrorException(*_DEADLINE_EXCEEDED_EXCEPTION)
            except requests.exceptions.RequestException:

                raise self._ErrorException(*_DEFAULT_EXCEPTION)

            parsed_response = remote_api_pb.Response(response.content)

            if (parsed_response.has_application_error()
                    or parsed_response.has_rpc_error()):

                raise self._TranslateToError(parsed_response)

            self.response.ParseFromString(parsed_response.response())

        except Exception:

            _, exc, tb = sys.exc_info()
            self._exception = exc
            self._traceback = tb

        try:
            self._Callback()
            return True
        finally:

            self.event.set()
    def _SendRequest(self, **kwargs):
        try:
            response = self.stub.http.request(**kwargs)

            if response.status != 200:
                raise apiproxy_errors.RPCFailedError(
                    'Proxy returned HTTP status %s %s' %
                    (response.status, response.reason))
        except urllib3.exceptions.TimeoutError:
            raise self._ErrorException(*_DEADLINE_EXCEEDED_EXCEPTION)
        except (urllib3.exceptions.RequestError,
                urllib3.exceptions.ConnectionError):

            raise self._ErrorException(*_DEFAULT_EXCEPTION)

        parsed_response = remote_api_pb2.Response.FromString(response.data)

        if (parsed_response.HasField('application_error')
                or parsed_response.HasField('rpc_error')):
            raise self._TranslateToError(parsed_response)

        self.response.ParseFromString(parsed_response.response)
    def _MakeCallImpl(self):
        """Makes an asynchronous API call over the service bridge.

    For this to work the following must be set:
      self.package: the API package name;
      self.call: the name of the API call/method to invoke;
      self.request: the API request body as a serialized protocol buffer.

    The actual API call is made by urllib3.request via a thread pool
    (multiprocessing.dummy.Pool). The thread pool restricts the number of
    concurrent requests to MAX_CONCURRENT_API_CALLS, so this method will
    block if that limit is exceeded, until other asynchronous calls resolve.

    If the main thread holds the import lock, waiting on thread work can cause
    a deadlock:
    https://docs.python.org/2/library/threading.html#importing-in-threaded-code

    Therefore, we try to detect this error case and fall back to sync calls.
    """
        assert self._state == apiproxy_rpc.RPC.IDLE, self._state

        ticket = None
        if VMStub.ShouldUseRequestSecurityTicketForThread():

            ticket = os.environ.get(TICKET_HEADER,
                                    os.environ.get(DEV_TICKET_HEADER))

        if not ticket:
            raise apiproxy_errors.RPCFailedError(
                'Attempted RPC call without active security ticket')

        request = remote_api_pb2.Request(
            service_name=self.package,
            method=self.call,
            request_id=ticket,
            request=self.request.SerializeToString())

        deadline = self.deadline or DEFAULT_TIMEOUT

        body_data = request.SerializeToString()
        headers = {
            SERVICE_DEADLINE_HEADER: str(deadline),
            SERVICE_ENDPOINT_HEADER: SERVICE_ENDPOINT_NAME,
            SERVICE_METHOD_HEADER: APIHOST_METHOD,
            'Content-type': RPC_CONTENT_TYPE,
        }

        dapper_header_value = os.environ.get(DAPPER_ENV_KEY)
        if dapper_header_value:
            headers[DAPPER_HEADER] = dapper_header_value

        api_host = os.environ.get('API_HOST', SERVICE_BRIDGE_HOST)
        api_port = os.environ.get('API_PORT', API_PORT)

        if ':' in api_host:
            api_host = '[{}]'.format(api_host)
        endpoint_url = six.moves.urllib.parse.urlunparse(
            ('http', '%s:%s' % (api_host, api_port), PROXY_PATH, '', '', ''))

        self._state = apiproxy_rpc.RPC.RUNNING

        request_kwargs = dict(url=endpoint_url,
                              method='POST',
                              timeout=DEADLINE_DELTA_SECONDS + deadline,
                              headers=headers,
                              body=body_data)

        if six.PY2 and imp.lock_held():
            self.future = futures.Future()
            self.future.set_result(
                self._SendRequestAndFinish(**request_kwargs))

        else:

            self.future = self.stub.thread_pool.submit(
                self._SendRequestAndFinish, **request_kwargs)