client.py 9.4 KB

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