client.py 9.6 KB

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