示例#1
0
  def __init__(
      self, url, headers, ignore_certs, proxy_info, on_data, on_close):
    self._on_data = on_data
    self._on_close = on_close
    self._proxy_info = proxy_info
    self._receiving_thread = None

    ca_certs = utils.CheckCACertsFile(ignore_certs)
    self._sslopt = {'cert_reqs': ssl.CERT_REQUIRED,
                    'ca_certs': ca_certs}
    if ignore_certs:
      self._sslopt['cert_reqs'] = ssl.CERT_NONE
      self._sslopt['check_hostname'] = False

    caa_config = context_aware.Config()
    if caa_config:
      cert_path = caa_config.encrypted_client_cert_path
      log.debug('Using client certificate %s', cert_path)
      self._sslopt['certfile'] = cert_path
      self._sslopt['password'] = caa_config.encrypted_client_cert_password

    # Disable most of random logging in websocket library itself except in DEBUG
    if log.GetVerbosity() != logging.DEBUG:
      logging.getLogger('websocket').setLevel(logging.CRITICAL)

    self._is_closed = False
    self._error_msg = ''
    self._websocket = websocket.WebSocketApp(
        url, header=headers, on_close=self._OnClose, on_data=self._OnData,
        on_error=self._OnError, subprotocols=[utils.SUBPROTOCOL_NAME])
示例#2
0
 def __str__(self):
     error_format = self.error_format
     if error_format is None:
         error_format = '{message}{details?\n{?}}'
         if log.GetVerbosity() <= logging.DEBUG:
             error_format += '{.debugInfo?\n{?}}'
     return _Expand(self.payload.format(_Escape(error_format)))  # pytype: disable=wrong-arg-types
示例#3
0
 def __str__(self):
     error_format = self.error_format
     if error_format is None:
         error_format = '{message}'
         if log.GetVerbosity() <= logging.DEBUG:
             error_format += '{.debugInfo?\n{?}}'
     return self.payload.format(unicode(error_format))
    def InitiateConnection(self):
        """Initiate the WebSocket connection."""
        utils.CheckPythonVersion(self._ignore_certs)
        utils.ValidateParameters(self._tunnel_target)
        self._ca_certs = utils.CheckCACertsFile(self._ignore_certs)

        self._connect_url = utils.CreateWebSocketUrl(CONNECT_ENDPOINT,
                                                     self._tunnel_target)
        headers = [
            'User-Agent: ' + http.MakeUserAgentString(),
            'Sec-WebSocket-Protocol: ' + utils.SUBPROTOCOL_NAME
        ]
        if self._access_token:
            headers += ['Authorization: Bearer ' + self._access_token]
        log.info('Connecting to with URL %r', self._connect_url)
        self._websocket_errors = []
        self._connection_sid = None

        if log.GetVerbosity() == logging.DEBUG:
            websocket.enableTrace(True)
        else:
            websocket_logger = logging.getLogger('websocket')
            websocket_logger.setLevel(logging.CRITICAL)

        self._websocket = websocket.WebSocketApp(self._connect_url,
                                                 header=headers,
                                                 on_error=self._OnError,
                                                 on_close=self._OnClose,
                                                 on_data=self._OnData)
        log.info('Starting WebSocket receive thread.')
        self._websocket_thread = threading.Thread(
            target=self._ReceiveFromWebSocket)
        self._websocket_thread.daemon = True
        self._websocket_thread.start()
示例#5
0
 def __str__(self):
     error_format = self.error_format
     if error_format is None:
         error_format = '{message}'
         if log.GetVerbosity() <= logging.DEBUG:
             error_format += '{.debugInfo?\n{?}}'
     return self.payload.format(
         unicode(error_format).replace(':', '{' + _ESCAPED_COLON + '}'))
示例#6
0
    def _HandleSubprotocolAck(self, binary_data):
        """Handle Subprotocol ACK Frame."""
        if not self._HasConnected():
            self._StopConnectionAsync()
            raise SubprotocolEarlyAckError('Received ACK before connected.')

        bytes_confirmed, bytes_left = utils.ExtractSubprotocolAck(binary_data)
        self._ConfirmData(bytes_confirmed)
        if bytes_left and log.GetVerbosity() == logging.DEBUG:
            log.info('Discarding [%d] extra bytes after processing ACK',
                     len(bytes_left))
示例#7
0
 def _EnqueueBytesWithWaitForReconnect(self, bytes_to_send):
     """Add bytes to the queue; sleep waiting for reconnect if queue is full."""
     end_time = time.time() + MAX_RECONNECT_WAIT_TIME_MS / 1000.0
     while time.time() < end_time:
         if len(self._unsent_data) < MAX_UNSENT_QUEUE_LENGTH:
             self._unsent_data.append(bytes_to_send)
             if log.GetVerbosity() == logging.DEBUG:
                 log.info('ENQUEUE data_len [%d] bytes_to_send[:20] [%r]',
                          len(bytes_to_send), bytes_to_send[:20])
             return
         time.sleep(0.01)
     raise ConnectionReconnectTimeout()
示例#8
0
 def SendClose(self):
   """Send WebSocket Close message."""
   try:
     if log.GetVerbosity() == logging.DEBUG:
       log.info('CLOSE')
     self._websocket.sock.send_close()
   except (EnvironmentError,
           websocket.WebSocketConnectionClosedException) as e:
     log.info('Unable to send WebSocket Close message [%s].', str(e))
     self.Close()
   except:  # pylint: disable=bare-except
     log.info('Error during WebSocket send of Close message.', exc_info=True)
     self.Close()
示例#9
0
    def _HandleSubprotocolConnectSuccessSid(self, binary_data):
        """Handle Subprotocol CONNECT_SUCCESS_SID Frame."""
        if self._HasConnected():
            self._StopConnectionAsync()
            raise SubprotocolExtraConnectSuccessSid(
                'Received CONNECT_SUCCESS_SID after already connected.')

        data, bytes_left = utils.ExtractSubprotocolConnectSuccessSid(
            binary_data)
        self._connection_sid = data
        self._connect_msg_received = True
        if bytes_left and log.GetVerbosity() == logging.DEBUG:
            log.info(
                'Discarding [%d] extra bytes after processing CONNECT_SUCCESS_SID',
                len(bytes_left))
示例#10
0
def FormatRpcError(error):
    """Returns a printable representation of a failed Google API's status.proto.

  Args:
    error: the failed Status to print.

  Returns:
    A ready-to-print string representation of the error.
  """
    log.debug('Error:\n' + encoding.MessageToJson(error))
    formatted_error = error.message
    # Only display details if the log level is INFO or finer.
    if error.details and log.GetVerbosity() <= log.info:
        formatted_error += ('\nDetails:\n' +
                            encoding.MessageToJson(error.details))
    return formatted_error
示例#11
0
    def _HandleSubprotocolData(self, binary_data):
        """Handle Subprotocol DATA Frame."""
        if not self._HasConnected():
            self._StopConnectionAsync()
            raise SubprotocolEarlyDataError('Received DATA before connected.')

        data, bytes_left = utils.ExtractSubprotocolData(binary_data)
        self._total_bytes_received += len(data)
        try:
            self._data_handler_callback(data)
        except:  # pylint: disable=bare-except
            self._StopConnectionAsync()
            raise
        if bytes_left and log.GetVerbosity() == logging.DEBUG:
            log.info('Discarding [%d] extra bytes after processing DATA',
                     len(bytes_left))
示例#12
0
 def _OnData(self, binary_data):
     """Receive a single message from the server."""
     tag, bytes_left = utils.ExtractSubprotocolTag(binary_data)
     # In order of decreasing usage during connection:
     if tag == utils.SUBPROTOCOL_TAG_DATA:
         self._HandleSubprotocolData(bytes_left)
     elif tag == utils.SUBPROTOCOL_TAG_ACK:
         self._HandleSubprotocolAck(bytes_left)
     elif tag == utils.SUBPROTOCOL_TAG_CONNECT_SUCCESS_SID:
         self._HandleSubprotocolConnectSuccessSid(bytes_left)
     elif tag == utils.SUBPROTOCOL_TAG_RECONNECT_SUCCESS_ACK:
         self._HandleSubprotocolReconnectSuccessAck(bytes_left)
     elif log.GetVerbosity() == logging.DEBUG:
         # TODO(b/119130796): update debug logging to std log.debug()
         log.info(
             'Unsupported subprotocol tag [%r], discarding the message',
             tag)
示例#13
0
    def _HandleSubprotocolReconnectSuccessAck(self, binary_data):
        """Handle Subprotocol RECONNECT_SUCCESS_ACK Frame."""
        if self._HasConnected():
            self._StopConnectionAsync()
            raise SubprotocolExtraReconnectSuccessAck(
                'Received RECONNECT_SUCCESS_ACK after already connected.')

        bytes_confirmed, bytes_left = (
            utils.ExtractSubprotocolReconnectSuccessAck(binary_data))
        bytes_being_confirmed = bytes_confirmed - self._total_bytes_confirmed
        self._ConfirmData(bytes_confirmed)
        log.info(
            'Reconnecting: confirming [%d] bytes and resending [%d] messages.',
            bytes_being_confirmed, len(self._unconfirmed_data))
        self._unsent_data.extendleft(reversed(self._unconfirmed_data))
        self._unconfirmed_data = deque()
        self._connect_msg_received = True
        if bytes_left and log.GetVerbosity() == logging.DEBUG:
            log.info(
                'Discarding [%d] extra bytes after processing RECONNECT_SUCCESS_ACK',
                len(bytes_left))
示例#14
0
 def Send(self, send_data):
   """Send data on WebSocket connection."""
   try:
     if log.GetVerbosity() == logging.DEBUG:
       log.info('SEND data_len [%d] send_data[:20] %r', len(send_data),
                send_data[:20])
     self._websocket.send(send_data, opcode=websocket.ABNF.OPCODE_BINARY)
   except EnvironmentError:
     self.Close()
     raise
   except websocket.WebSocketConnectionClosedException:
     self.Close()
     raise WebSocketConnectionClosed()
   except Exception as e:  # pylint: disable=broad-except
     # Convert websocket library errors and any others into one based on
     # exceptions.Error
     tb = sys.exc_info()[2]
     self.Close()
     exceptions.reraise(
         WebSocketSendError(traceback.format_exception_only(type(e), e),
                            tb=tb))
示例#15
0
 def _OnData(self, unused_websocket_app, binary_data, opcode, unused_finished):
   """Callback for WebSocket Data messages."""
   if log.GetVerbosity() == logging.DEBUG:
     log.info('RECV opcode [%r] data_len [%d] binary_data[:20] [%r]', opcode,
              len(binary_data), binary_data[:20])
   try:
     # Even though we will only be processing BINARY messages, a bug in the
     # underlying websocket library will report the last opcode in a
     # multi-frame message instead of the first opcode - so CONT instead of
     # BINARY.
     if opcode not in (websocket.ABNF.OPCODE_CONT,
                       websocket.ABNF.OPCODE_BINARY):
       raise WebSocketInvalidOpcodeError('Unexpected WebSocket opcode [%r].' %
                                         opcode)
     self._on_data(binary_data)
   except EnvironmentError as e:
     log.info('Error [%s] while sending to client.', str(e))
     self.Close()
     raise
   except:  # pylint: disable=bare-except
     log.info('Error while processing Data message.', exc_info=True)
     self.Close()
     raise
示例#16
0
    def _SendDataAndReconnectWebSocket(self):
        """Main function for send_and_reconnect_thread."""
        def Reconnect():
            if not self._stopping:
                self._StartNewWebSocket()
                self._WaitForOpenOrRaiseError()

        try:
            while not self._stopping:
                if self._IsClosed():
                    self._AttemptReconnect(Reconnect)

                elif self._HasConnected():
                    self._SendQueuedData()
                    if not self._IsClosed():
                        self._SendAck()

                if not self._stopping:
                    time.sleep(0.01)
        except:  # pylint: disable=bare-except
            if log.GetVerbosity() == logging.DEBUG:
                log.info('Error from WebSocket while sending data.',
                         exc_info=True)
        self.Close()
示例#17
0
 def SetUp(self):
   self.original_verbosity = log.GetVerbosity()