client.py 9.9 KB

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