class_docstr: Handles a WebSocket connection from the browser
code: def on_message(self, payload: Union[str, bytes]) -> None:
      if not self._session_id:
          return
  
      try:
          if isinstance(payload, str):
              # Sanity check. (The frontend should only be sending us bytes;
              # Protobuf.ParseFromString does not accept str input.)
              raise RuntimeError(
                  "WebSocket received an unexpected `str` message. "
                  "(We expect `bytes` only.)"
              )
  
          msg = BackMsg()
          msg.ParseFromString(payload)
          _LOGGER.debug("Received the following back message:\n%s", msg)
  
      except Exception as ex:
          _LOGGER.error(ex)
          self._runtime.handle_backmsg_deserialization_exception(
              self._session_id, ex
          )
          return
  
      # "debug_disconnect_websocket" and "debug_shutdown_runtime" are special
      # developmentMode-only messages used in e2e tests to test reconnect handling and
      # disabling widgets.
      if msg.WhichOneof("type") == "debug_disconnect_websocket":
          if config.get_option("global.developmentMode"):
              self.close()
          else:
              _LOGGER.warning(
                  "Client tried to disconnect websocket when not in development mode."
              )
      elif msg.WhichOneof("type") == "debug_shutdown_runtime":
          if config.get_option("global.developmentMode"):
              self._runtime.stop()
          else:
              _LOGGER.warning(
                  "Client tried to shut down runtime when not in development mode."
              )
      else:
          # AppSession handles all other BackMsg types.
          self._runtime.handle_backmsg(self._session_id, msg)
  
imports: import base64
  import binascii
  import json
  from typing import Any, Awaitable, Dict, List, Optional, Union
  import tornado.concurrent
  import tornado.locks
  import tornado.netutil
  import tornado.web
  import tornado.websocket
  from tornado.websocket import WebSocketHandler
  from typing_extensions import Final
  from streamlit import config
  from streamlit.logger import get_logger
  from streamlit.proto.BackMsg_pb2 import BackMsg
  from streamlit.proto.ForwardMsg_pb2 import ForwardMsg
  from streamlit.runtime import Runtime, SessionClient, SessionClientDisconnectedError
  from streamlit.runtime.runtime_util import serialize_forward_msg
  from streamlit.web.server.server_util import is_url_from_allowed_origins
label_desc: Use image node_id 8 for calling the BrowserWebSocketHandler obj's underlying member method code with example usage: obj.on_message(payload) without return types