xref: /aosp_15_r20/external/cronet/net/data/websocket/close-observer_wsh.py (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1# Copyright 2019 The Chromium Authors
2# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5from six.moves.urllib import parse
6from mod_pywebsocket import stream
7import threading
8
9
10cv = threading.Condition()
11connected = False
12close_code = None
13
14
15def get_role(request):
16  """Look up the "role" query parameter in the URL."""
17  query = request.ws_resource.split('?', 1)
18  if len(query) == 1:
19    raise LookupError('No query string found in URL')
20  param = parse.parse_qs(query[1])
21  if 'role' not in param:
22    raise LookupError('No role parameter found in the query string')
23  return param['role'][0]
24
25
26def be_observed(request):
27  global connected
28  with cv:
29    connected = True
30  # Wait for a Close frame
31  try:
32    request.ws_stream.receive_message()
33  except stream.ConnectionTerminatedException:
34    observe_close(1006)  # "Abnormal Closure"
35
36
37def be_observer(request):
38  with cv:
39    if not connected:
40      request.ws_stream.send_message('NOT CONNECTED', binary = False)
41    else:
42      while close_code is None:
43        cv.wait()
44      if close_code == 1001:  # "Going Away"
45        request.ws_stream.send_message('OK', binary = False)
46      else:
47        request.ws_stream.send_message('WRONG CODE %d' % close_code,
48                                       binary = False)
49  request.ws_stream.close_connection()
50
51
52def web_socket_do_extra_handshake(request):
53  pass
54
55
56def web_socket_transfer_data(request):
57  role = get_role(request)
58  if role == 'observed':
59    be_observed(request)
60  elif role == 'observer':
61    be_observer(request)
62  else:
63    raise ValueError('Bad role "%s"' % role)
64
65
66def web_socket_passive_closing_handshake(request):
67  if get_role(request) == 'observed':
68    observe_close(request.ws_close_code)
69  return request.ws_close_code, request.ws_close_reason
70
71
72def observe_close(code):
73  global close_code
74  with cv:
75    close_code = code
76    cv.notify()
77