client.py 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268
  1. #!/usr/bin/env python
  2. #
  3. # Copyright 2018 Espressif Systems (Shanghai) PTE LTD
  4. #
  5. # Licensed under the Apache License, Version 2.0 (the "License");
  6. # you may not use this file except in compliance with the License.
  7. # You may obtain a copy of the License at
  8. #
  9. # http://www.apache.org/licenses/LICENSE-2.0
  10. #
  11. # Unless required by applicable law or agreed to in writing, software
  12. # distributed under the License is distributed on an "AS IS" BASIS,
  13. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. # See the License for the specific language governing permissions and
  15. # limitations under the License.
  16. from __future__ import print_function
  17. from __future__ import unicode_literals
  18. from builtins import str
  19. import http.client
  20. import argparse
  21. from tiny_test_fw import Utility
  22. def verbose_print(verbosity, *args):
  23. if (verbosity):
  24. Utility.console_log(''.join(str(elems) for elems in args))
  25. def test_val(text, expected, received):
  26. if expected != received:
  27. Utility.console_log(" Fail!")
  28. Utility.console_log(" [reason] " + text + ":")
  29. Utility.console_log(" expected: " + str(expected))
  30. Utility.console_log(" received: " + str(received))
  31. return False
  32. return True
  33. def test_get_handler(ip, port, verbosity=False):
  34. verbose_print(verbosity, "======== GET HANDLER TEST =============")
  35. # Establish HTTP connection
  36. verbose_print(verbosity, "Connecting to => " + ip + ":" + port)
  37. sess = http.client.HTTPConnection(ip + ":" + port, timeout=15)
  38. uri = "/hello?query1=value1&query2=value2&query3=value3"
  39. # GET hello response
  40. test_headers = {"Test-Header-1":"Test-Value-1", "Test-Header-2":"Test-Value-2"}
  41. verbose_print(verbosity, "Sending GET to URI : ", uri)
  42. verbose_print(verbosity, "Sending additional headers : ")
  43. for k, v in test_headers.items():
  44. verbose_print(verbosity, "\t", k, ": ", v)
  45. sess.request("GET", url=uri, headers=test_headers)
  46. resp = sess.getresponse()
  47. resp_hdrs = resp.getheaders()
  48. resp_data = resp.read().decode()
  49. # Close HTTP connection
  50. sess.close()
  51. if not (
  52. test_val("Status code mismatch", 200, resp.status) and
  53. test_val("Response mismatch", "Custom-Value-1", resp.getheader("Custom-Header-1")) and
  54. test_val("Response mismatch", "Custom-Value-2", resp.getheader("Custom-Header-2")) and
  55. test_val("Response mismatch", "Hello World!", resp_data)
  56. ):
  57. return False
  58. verbose_print(verbosity, "vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv")
  59. verbose_print(verbosity, "Server response to GET /hello")
  60. verbose_print(verbosity, "Response Headers : ")
  61. for k, v in resp_hdrs:
  62. verbose_print(verbosity, "\t", k, ": ", v)
  63. verbose_print(verbosity, "Response Data : " + resp_data)
  64. verbose_print(verbosity, "========================================\n")
  65. return True
  66. def test_post_handler(ip, port, msg, verbosity=False):
  67. verbose_print(verbosity, "======== POST HANDLER TEST ============")
  68. # Establish HTTP connection
  69. verbose_print(verbosity, "Connecting to => " + ip + ":" + port)
  70. sess = http.client.HTTPConnection(ip + ":" + port, timeout=15)
  71. # POST message to /echo and get back response
  72. sess.request("POST", url="/echo", body=msg)
  73. resp = sess.getresponse()
  74. resp_data = resp.read().decode()
  75. verbose_print(verbosity, "Server response to POST /echo (" + msg + ")")
  76. verbose_print(verbosity, "vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv")
  77. verbose_print(verbosity, resp_data)
  78. verbose_print(verbosity, "========================================\n")
  79. # Close HTTP connection
  80. sess.close()
  81. return test_val("Response mismatch", msg, resp_data)
  82. def test_put_handler(ip, port, verbosity=False):
  83. verbose_print(verbosity, "======== PUT HANDLER TEST =============")
  84. # Establish HTTP connection
  85. verbose_print(verbosity, "Connecting to => " + ip + ":" + port)
  86. sess = http.client.HTTPConnection(ip + ":" + port, timeout=15)
  87. # PUT message to /ctrl to disable /hello and /echo URI handlers
  88. # and set 404 error handler to custom http_404_error_handler()
  89. verbose_print(verbosity, "Disabling /hello and /echo handlers")
  90. sess.request("PUT", url="/ctrl", body="0")
  91. resp = sess.getresponse()
  92. resp.read()
  93. try:
  94. # Send HTTP request to /hello URI
  95. sess.request("GET", url="/hello")
  96. resp = sess.getresponse()
  97. resp_data = resp.read().decode()
  98. # 404 Error must be returned from server as URI /hello is no longer available.
  99. # But the custom error handler http_404_error_handler() will not close the
  100. # session if the requested URI is /hello
  101. if not test_val("Status code mismatch", 404, resp.status):
  102. raise AssertionError
  103. # Compare error response string with expectation
  104. verbose_print(verbosity, "Response on GET /hello : " + resp_data)
  105. if not test_val("Response mismatch", "/hello URI is not available", resp_data):
  106. raise AssertionError
  107. # Using same session for sending an HTTP request to /echo, as it is expected
  108. # that the custom error handler http_404_error_handler() would not have closed
  109. # the session
  110. sess.request("POST", url="/echo", body="Some content")
  111. resp = sess.getresponse()
  112. resp_data = resp.read().decode()
  113. # 404 Error must be returned from server as URI /hello is no longer available.
  114. # The custom error handler http_404_error_handler() will close the session
  115. # this time as the requested URI is /echo
  116. if not test_val("Status code mismatch", 404, resp.status):
  117. raise AssertionError
  118. # Compare error response string with expectation
  119. verbose_print(verbosity, "Response on POST /echo : " + resp_data)
  120. if not test_val("Response mismatch", "/echo URI is not available", resp_data):
  121. raise AssertionError
  122. try:
  123. # Using same session should fail as by now the session would have closed
  124. sess.request("POST", url="/hello", body="Some content")
  125. resp = sess.getresponse()
  126. resp.read().decode()
  127. # If control reaches this point then the socket was not closed.
  128. # This is not expected
  129. verbose_print(verbosity, "Socket not closed by server")
  130. raise AssertionError
  131. except http.client.HTTPException:
  132. # Catch socket error as we tried to communicate with an already closed socket
  133. pass
  134. except http.client.HTTPException:
  135. verbose_print(verbosity, "Socket closed by server")
  136. return False
  137. except AssertionError:
  138. return False
  139. finally:
  140. # Close HTTP connection
  141. sess.close()
  142. verbose_print(verbosity, "Enabling /hello handler")
  143. # Create new connection
  144. sess = http.client.HTTPConnection(ip + ":" + port, timeout=15)
  145. # PUT message to /ctrl to enable /hello URI handler
  146. # and restore 404 error handler to default
  147. sess.request("PUT", url="/ctrl", body="1")
  148. resp = sess.getresponse()
  149. resp.read()
  150. # Close HTTP connection
  151. sess.close()
  152. # Create new connection
  153. sess = http.client.HTTPConnection(ip + ":" + port, timeout=15)
  154. try:
  155. # Sending HTTP request to /hello should work now
  156. sess.request("GET", url="/hello")
  157. resp = sess.getresponse()
  158. resp_data = resp.read().decode()
  159. if not test_val("Status code mismatch", 200, resp.status):
  160. raise AssertionError
  161. verbose_print(verbosity, "Response on GET /hello : " + resp_data)
  162. if not test_val("Response mismatch", "Hello World!", resp_data):
  163. raise AssertionError
  164. # 404 Error handler should have been restored to default
  165. sess.request("GET", url="/invalid")
  166. resp = sess.getresponse()
  167. resp_data = resp.read().decode()
  168. if not test_val("Status code mismatch", 404, resp.status):
  169. raise AssertionError
  170. verbose_print(verbosity, "Response on GET /invalid : " + resp_data)
  171. if not test_val("Response mismatch", "This URI does not exist", resp_data):
  172. raise AssertionError
  173. except http.client.HTTPException:
  174. verbose_print(verbosity, "Socket closed by server")
  175. return False
  176. except AssertionError:
  177. return False
  178. finally:
  179. # Close HTTP connection
  180. sess.close()
  181. return True
  182. def test_custom_uri_query(ip, port, query, verbosity=False):
  183. verbose_print(verbosity, "======== GET HANDLER TEST =============")
  184. # Establish HTTP connection
  185. verbose_print(verbosity, "Connecting to => " + ip + ":" + port)
  186. sess = http.client.HTTPConnection(ip + ":" + port, timeout=15)
  187. uri = "/hello?" + query
  188. # GET hello response
  189. verbose_print(verbosity, "Sending GET to URI : ", uri)
  190. sess.request("GET", url=uri, headers={})
  191. resp = sess.getresponse()
  192. resp_data = resp.read().decode()
  193. verbose_print(verbosity, "vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv")
  194. verbose_print(verbosity, "Server response to GET /hello")
  195. verbose_print(verbosity, "Response Data : " + resp_data)
  196. verbose_print(verbosity, "========================================\n")
  197. # Close HTTP connection
  198. sess.close()
  199. return "Hello World!" == resp_data
  200. if __name__ == '__main__':
  201. # Configure argument parser
  202. parser = argparse.ArgumentParser(description='Run HTTPd Test')
  203. parser.add_argument('IP', metavar='IP', type=str, help='Server IP')
  204. parser.add_argument('port', metavar='port', type=str, help='Server port')
  205. parser.add_argument('msg', metavar='message', type=str, help='Message to be sent to server')
  206. args = vars(parser.parse_args())
  207. # Get arguments
  208. ip = args['IP']
  209. port = args['port']
  210. msg = args['msg']
  211. if not (
  212. test_get_handler(ip, port, True) and
  213. test_put_handler(ip, port, True) and
  214. test_post_handler(ip, port, msg, True)
  215. ):
  216. Utility.console_log("Failed!")