docs: def parse_frame(buf):
      """Return the next frame from the socket."""
      # read header
      while buf.available < 2:
          yield
  
      data = buf.read(2)
      first_byte, second_byte = struct.unpack('!BB', data)
  
      fin = (first_byte >> 7) & 1
      rsv1 = (first_byte >> 6) & 1
      rsv2 = (first_byte >> 5) & 1
      rsv3 = (first_byte >> 4) & 1
      opcode = first_byte & 0xf
  
      # frame-fin = %x0 ; more frames of this message follow
      #           / %x1 ; final frame of this message
      # frame-rsv1 = %x0 ; 1 bit, MUST be 0 unless negotiated otherwise
      # frame-rsv2 = %x0 ; 1 bit, MUST be 0 unless negotiated otherwise
      # frame-rsv3 = %x0 ; 1 bit, MUST be 0 unless negotiated otherwise
      if rsv1 or rsv2 or rsv3:
          raise WebSocketError('Received frame with non-zero reserved bits')
  
      if opcode > 0x7 and fin == 0:
          raise WebSocketError('Received fragmented control frame')
  
      if fin == 0 and opcode == OPCODE_CONTINUATION:
          raise WebSocketError(
              'Received new fragment frame with non-zero opcode')
  
      has_mask = (second_byte >> 7) & 1
      length = (second_byte) & 0x7f
  
      # Control frames MUST have a payload length of 125 bytes or less
      if opcode > 0x7 and length > 125:
          raise WebSocketError(
              "Control frame payload cannot be larger than 125 bytes")
  
      # read payload
      if length == 126:
          while buf.available < 2:
              yield
  
          length = struct.unpack_from('!H', buf.read(2))[0]
      elif length > 126:
          while buf.available < 4:
              yield
  
          length = struct.unpack_from('!Q', buf.read(4))[0]
  
      if has_mask:
          while buf.available < 4:
              yield
  
          mask = buf.read(4)
  
      if length:
          while buf.available < length:
              yield
  
          payload = buf.read(length)
      else:
          payload = b''
  
      if has_mask:
          mask = [ord(i) for i in mask]
          payload = [chr(ord(b) ^ mask[i % 4]) for i, b in enumerate(payload)]
  
      yield fin, opcode, payload