Funktionierender Prototyp des Serious Games zur Vermittlung von Wissen zu Software-Engineering-Arbeitsmodellen.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

test_http.py 9.4KB

1 year ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176
  1. # -*- coding: utf-8 -*-
  2. #
  3. import os
  4. import os.path
  5. import websocket as ws
  6. from websocket._http import proxy_info, read_headers, _start_proxied_socket, _tunnel, _get_addrinfo_list, connect
  7. import unittest
  8. import ssl
  9. import websocket
  10. import socket
  11. """
  12. test_http.py
  13. websocket - WebSocket client library for Python
  14. Copyright 2023 engn33r
  15. Licensed under the Apache License, Version 2.0 (the "License");
  16. you may not use this file except in compliance with the License.
  17. You may obtain a copy of the License at
  18. http://www.apache.org/licenses/LICENSE-2.0
  19. Unless required by applicable law or agreed to in writing, software
  20. distributed under the License is distributed on an "AS IS" BASIS,
  21. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  22. See the License for the specific language governing permissions and
  23. limitations under the License.
  24. """
  25. try:
  26. from python_socks._errors import ProxyError, ProxyTimeoutError, ProxyConnectionError
  27. except:
  28. from websocket._http import ProxyError, ProxyTimeoutError, ProxyConnectionError
  29. # Skip test to access the internet unless TEST_WITH_INTERNET == 1
  30. TEST_WITH_INTERNET = os.environ.get('TEST_WITH_INTERNET', '0') == '1'
  31. TEST_WITH_PROXY = os.environ.get('TEST_WITH_PROXY', '0') == '1'
  32. # Skip tests relying on local websockets server unless LOCAL_WS_SERVER_PORT != -1
  33. LOCAL_WS_SERVER_PORT = os.environ.get('LOCAL_WS_SERVER_PORT', '-1')
  34. TEST_WITH_LOCAL_SERVER = LOCAL_WS_SERVER_PORT != '-1'
  35. class SockMock:
  36. def __init__(self):
  37. self.data = []
  38. self.sent = []
  39. def add_packet(self, data):
  40. self.data.append(data)
  41. def gettimeout(self):
  42. return None
  43. def recv(self, bufsize):
  44. if self.data:
  45. e = self.data.pop(0)
  46. if isinstance(e, Exception):
  47. raise e
  48. if len(e) > bufsize:
  49. self.data.insert(0, e[bufsize:])
  50. return e[:bufsize]
  51. def send(self, data):
  52. self.sent.append(data)
  53. return len(data)
  54. def close(self):
  55. pass
  56. class HeaderSockMock(SockMock):
  57. def __init__(self, fname):
  58. SockMock.__init__(self)
  59. path = os.path.join(os.path.dirname(__file__), fname)
  60. with open(path, "rb") as f:
  61. self.add_packet(f.read())
  62. class OptsList():
  63. def __init__(self):
  64. self.timeout = 1
  65. self.sockopt = []
  66. self.sslopt = {"cert_reqs": ssl.CERT_NONE}
  67. class HttpTest(unittest.TestCase):
  68. def testReadHeader(self):
  69. status, header, status_message = read_headers(HeaderSockMock("data/header01.txt"))
  70. self.assertEqual(status, 101)
  71. self.assertEqual(header["connection"], "Upgrade")
  72. # header02.txt is intentionally malformed
  73. self.assertRaises(ws.WebSocketException, read_headers, HeaderSockMock("data/header02.txt"))
  74. def testTunnel(self):
  75. self.assertRaises(ws.WebSocketProxyException, _tunnel, HeaderSockMock("data/header01.txt"), "example.com", 80, ("username", "password"))
  76. self.assertRaises(ws.WebSocketProxyException, _tunnel, HeaderSockMock("data/header02.txt"), "example.com", 80, ("username", "password"))
  77. @unittest.skipUnless(TEST_WITH_INTERNET, "Internet-requiring tests are disabled")
  78. def testConnect(self):
  79. # Not currently testing an actual proxy connection, so just check whether proxy errors are raised. This requires internet for a DNS lookup
  80. if ws._http.HAVE_PYTHON_SOCKS:
  81. # Need this check, otherwise case where python_socks is not installed triggers
  82. # websocket._exceptions.WebSocketException: Python Socks is needed for SOCKS proxying but is not available
  83. self.assertRaises((ProxyTimeoutError, OSError), _start_proxied_socket, "wss://example.com", OptsList(), proxy_info(http_proxy_host="example.com", http_proxy_port="8080", proxy_type="socks4", http_proxy_timeout=1))
  84. self.assertRaises((ProxyTimeoutError, OSError), _start_proxied_socket, "wss://example.com", OptsList(), proxy_info(http_proxy_host="example.com", http_proxy_port="8080", proxy_type="socks4a", http_proxy_timeout=1))
  85. self.assertRaises((ProxyTimeoutError, OSError), _start_proxied_socket, "wss://example.com", OptsList(), proxy_info(http_proxy_host="example.com", http_proxy_port="8080", proxy_type="socks5", http_proxy_timeout=1))
  86. self.assertRaises((ProxyTimeoutError, OSError), _start_proxied_socket, "wss://example.com", OptsList(), proxy_info(http_proxy_host="example.com", http_proxy_port="8080", proxy_type="socks5h", http_proxy_timeout=1))
  87. self.assertRaises(ProxyConnectionError, connect, "wss://example.com", OptsList(), proxy_info(http_proxy_host="127.0.0.1", http_proxy_port=9999, proxy_type="socks4", http_proxy_timeout=1), None)
  88. self.assertRaises(TypeError, _get_addrinfo_list, None, 80, True, proxy_info(http_proxy_host="127.0.0.1", http_proxy_port="9999", proxy_type="http"))
  89. self.assertRaises(TypeError, _get_addrinfo_list, None, 80, True, proxy_info(http_proxy_host="127.0.0.1", http_proxy_port="9999", proxy_type="http"))
  90. self.assertRaises(socket.timeout, connect, "wss://google.com", OptsList(), proxy_info(http_proxy_host="8.8.8.8", http_proxy_port=9999, proxy_type="http", http_proxy_timeout=1), None)
  91. self.assertEqual(
  92. connect("wss://google.com", OptsList(), proxy_info(http_proxy_host="8.8.8.8", http_proxy_port=8080, proxy_type="http"), True),
  93. (True, ("google.com", 443, "/")))
  94. # The following test fails on Mac OS with a gaierror, not an OverflowError
  95. # self.assertRaises(OverflowError, connect, "wss://example.com", OptsList(), proxy_info(http_proxy_host="127.0.0.1", http_proxy_port=99999, proxy_type="socks4", timeout=2), False)
  96. @unittest.skipUnless(TEST_WITH_INTERNET, "Internet-requiring tests are disabled")
  97. @unittest.skipUnless(TEST_WITH_PROXY, "This test requires a HTTP proxy to be running on port 8899")
  98. @unittest.skipUnless(TEST_WITH_LOCAL_SERVER, "Tests using local websocket server are disabled")
  99. def testProxyConnect(self):
  100. ws = websocket.WebSocket()
  101. ws.connect("ws://127.0.0.1:" + LOCAL_WS_SERVER_PORT, http_proxy_host="127.0.0.1", http_proxy_port="8899", proxy_type="http")
  102. ws.send("Hello, Server")
  103. server_response = ws.recv()
  104. self.assertEqual(server_response, "Hello, Server")
  105. # self.assertEqual(_start_proxied_socket("wss://api.bitfinex.com/ws/2", OptsList(), proxy_info(http_proxy_host="127.0.0.1", http_proxy_port="8899", proxy_type="http"))[1], ("api.bitfinex.com", 443, '/ws/2'))
  106. self.assertEqual(_get_addrinfo_list("api.bitfinex.com", 443, True, proxy_info(http_proxy_host="127.0.0.1", http_proxy_port="8899", proxy_type="http")),
  107. (socket.getaddrinfo("127.0.0.1", 8899, 0, socket.SOCK_STREAM, socket.SOL_TCP), True, None))
  108. self.assertEqual(connect("wss://api.bitfinex.com/ws/2", OptsList(), proxy_info(http_proxy_host="127.0.0.1", http_proxy_port=8899, proxy_type="http"), None)[1], ("api.bitfinex.com", 443, '/ws/2'))
  109. # TODO: Test SOCKS4 and SOCK5 proxies with unit tests
  110. @unittest.skipUnless(TEST_WITH_INTERNET, "Internet-requiring tests are disabled")
  111. def testSSLopt(self):
  112. ssloptions = {
  113. "check_hostname": False,
  114. "server_hostname": "ServerName",
  115. "ssl_version": ssl.PROTOCOL_TLS_CLIENT,
  116. "ciphers": "TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:\
  117. TLS_AES_128_GCM_SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:\
  118. ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384:\
  119. ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:\
  120. DHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:\
  121. ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES128-GCM-SHA256:\
  122. ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:\
  123. DHE-RSA-AES256-SHA256:ECDHE-ECDSA-AES128-SHA256:\
  124. ECDHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA256:\
  125. ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA",
  126. "ecdh_curve": "prime256v1"
  127. }
  128. ws_ssl1 = websocket.WebSocket(sslopt=ssloptions)
  129. ws_ssl1.connect("wss://api.bitfinex.com/ws/2")
  130. ws_ssl1.send("Hello")
  131. ws_ssl1.close()
  132. ws_ssl2 = websocket.WebSocket(sslopt={"check_hostname": True})
  133. ws_ssl2.connect("wss://api.bitfinex.com/ws/2")
  134. ws_ssl2.close
  135. def testProxyInfo(self):
  136. self.assertEqual(proxy_info(http_proxy_host="127.0.0.1", http_proxy_port="8080", proxy_type="http").proxy_protocol, "http")
  137. self.assertRaises(ProxyError, proxy_info, http_proxy_host="127.0.0.1", http_proxy_port="8080", proxy_type="badval")
  138. self.assertEqual(proxy_info(http_proxy_host="example.com", http_proxy_port="8080", proxy_type="http").proxy_host, "example.com")
  139. self.assertEqual(proxy_info(http_proxy_host="127.0.0.1", http_proxy_port="8080", proxy_type="http").proxy_port, "8080")
  140. self.assertEqual(proxy_info(http_proxy_host="127.0.0.1", http_proxy_port="8080", proxy_type="http").auth, None)
  141. self.assertEqual(proxy_info(http_proxy_host="127.0.0.1", http_proxy_port="8080", proxy_type="http", http_proxy_auth=("my_username123", "my_pass321")).auth[0], "my_username123")
  142. self.assertEqual(proxy_info(http_proxy_host="127.0.0.1", http_proxy_port="8080", proxy_type="http", http_proxy_auth=("my_username123", "my_pass321")).auth[1], "my_pass321")
  143. if __name__ == "__main__":
  144. unittest.main()