Hide keyboard shortcuts

Hot-keys on this page

r m x p   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

1# This file is part of Xpra. 

2# Copyright (C) 2016-2019 Antoine Martin <antoine@xpra.org> 

3# Xpra is released under the terms of the GNU GPL v2, or, at your option, any 

4# later version. See the file COPYING for details. 

5 

6from xpra.util import envbool 

7from xpra.net.websockets.common import make_websocket_accept_hash 

8from xpra.server.http_handler import HTTPRequestHandler 

9from xpra.log import Logger 

10 

11log = Logger("network", "websocket") 

12 

13WEBSOCKET_ONLY_UPGRADE = envbool("XPRA_WEBSOCKET_ONLY_UPGRADE", False) 

14 

15# HyBi-07 report version 7 

16# HyBi-08 - HyBi-12 report version 8 

17# HyBi-13 reports version 13 

18SUPPORT_HyBi_PROTOCOLS = ("7", "8", "13") 

19 

20 

21class WebSocketRequestHandler(HTTPRequestHandler): 

22 

23 server_version = "Xpra-WebSocket-Server" 

24 

25 def __init__(self, sock, addr, new_websocket_client, 

26 web_root="/usr/share/xpra/www/", 

27 http_headers_dir="/etc/xpra/http-headers", script_paths=None): 

28 self.new_websocket_client = new_websocket_client 

29 self.only_upgrade = WEBSOCKET_ONLY_UPGRADE 

30 super().__init__(sock, addr, web_root, http_headers_dir, script_paths) 

31 

32 def handle_websocket(self): 

33 log("handle_websocket() calling %s, request=%s (%s)", 

34 self.new_websocket_client, self.request, type(self.request)) 

35 log("headers:") 

36 for k,v in self.headers.items(): 

37 log(" %s=%s", k, v) 

38 ver = self.headers.get('Sec-WebSocket-Version') 

39 if ver is None: 

40 raise Exception("Missing Sec-WebSocket-Version header") 

41 

42 if ver not in SUPPORT_HyBi_PROTOCOLS: 

43 raise Exception("Unsupported protocol version %s" % ver) 

44 

45 protocols = self.headers.get("Sec-WebSocket-Protocol", "").split(",") 

46 if "binary" not in protocols: 

47 raise Exception("client does not support 'binary' protocol") 

48 

49 key = self.headers.get("Sec-WebSocket-Key") 

50 if key is None: 

51 raise Exception("Missing Sec-WebSocket-Key header") 

52 for upgrade_string in ( 

53 b"HTTP/1.1 101 Switching Protocols", 

54 b"Upgrade: websocket", 

55 b"Connection: Upgrade", 

56 b"Sec-WebSocket-Accept: %s" % make_websocket_accept_hash(key), 

57 b"Sec-WebSocket-Protocol: %s" % b"binary", 

58 b"", 

59 ): 

60 self.wfile.write(b"%s\r\n" % upgrade_string) 

61 self.wfile.flush() 

62 self.new_websocket_client(self) 

63 

64 def do_GET(self): 

65 upgrade_requested = (self.headers.get('upgrade') or "").lower() == 'websocket' 

66 if self.only_upgrade or upgrade_requested: 

67 if not upgrade_requested: 

68 self.send_error(403, "only websocket connections are allowed") 

69 return 

70 try: 

71 self.handle_websocket() 

72 except Exception as e: 

73 log("do_GET()", exc_info=True) 

74 log.error("Error: cannot handle websocket upgrade:") 

75 log.error(" %s", e) 

76 self.send_error(403, "failed to handle websocket: %s" % e) 

77 return 

78 HTTPRequestHandler.do_GET(self) 

79 

80 def do_HEAD(self): 

81 if self.only_upgrade: 

82 self.send_error(405, "Method Not Allowed") 

83 return 

84 HTTPRequestHandler.do_HEAD(self) 

85 

86 def handle_request(self): 

87 if self.only_upgrade: 

88 self.send_error(405, "Method Not Allowed") 

89 return 

90 HTTPRequestHandler.handle_request(self)