client.py 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258
  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. import socket
  17. import argparse
  18. class Session:
  19. def __init__(self, addr, port):
  20. self.client = socket.create_connection((addr, int(port)))
  21. self.target = addr
  22. def send_get(self, path, headers=None):
  23. request = "GET " + path + " HTTP/1.1\r\nHost: " + self.target
  24. if headers:
  25. for field, value in headers.iteritems():
  26. request += "\r\n"+field+": "+value
  27. request += "\r\n\r\n"
  28. self.client.send(request);
  29. def send_put(self, path, data, headers=None):
  30. request = "PUT " + path + " HTTP/1.1\r\nHost: " + self.target
  31. if headers:
  32. for field, value in headers.iteritems():
  33. request += "\r\n"+field+": "+value
  34. request += "\r\nContent-Length: " + str(len(data)) +"\r\n\r\n"
  35. self.client.send(request)
  36. self.client.send(data)
  37. def send_post(self, path, data, headers=None):
  38. request = "POST " + path + " HTTP/1.1\r\nHost: " + self.target
  39. if headers:
  40. for field, value in headers.iteritems():
  41. request += "\r\n"+field+": "+value
  42. request += "\r\nContent-Length: " + str(len(data)) +"\r\n\r\n"
  43. self.client.send(request)
  44. self.client.send(data)
  45. def read_resp_hdrs(self):
  46. state = 'nothing'
  47. resp_read = ''
  48. while True:
  49. char = self.client.recv(1)
  50. if char == '\r' and state == 'nothing':
  51. state = 'first_cr'
  52. elif char == '\n' and state == 'first_cr':
  53. state = 'first_lf'
  54. elif char == '\r' and state == 'first_lf':
  55. state = 'second_cr'
  56. elif char == '\n' and state == 'second_cr':
  57. state = 'second_lf'
  58. else:
  59. state = 'nothing'
  60. resp_read += char
  61. if state == 'second_lf':
  62. break;
  63. # Handle first line
  64. line_hdrs = resp_read.splitlines()
  65. line_comp = line_hdrs[0].split()
  66. self.status = line_comp[1]
  67. del line_hdrs[0]
  68. self.encoding = ''
  69. self.content_type = ''
  70. headers = dict()
  71. # Process other headers
  72. for h in range(len(line_hdrs)):
  73. line_comp = line_hdrs[h].split(':')
  74. if line_comp[0] == 'Content-Length':
  75. self.content_len = int(line_comp[1])
  76. if line_comp[0] == 'Content-Type':
  77. self.content_type = line_comp[1].lstrip()
  78. if line_comp[0] == 'Transfer-Encoding':
  79. self.encoding = line_comp[1].lstrip()
  80. if len(line_comp) == 2:
  81. headers[line_comp[0]] = line_comp[1].lstrip()
  82. return headers
  83. def read_resp_data(self):
  84. read_data = ''
  85. if self.encoding != 'chunked':
  86. while len(read_data) != self.content_len:
  87. read_data += self.client.recv(self.content_len)
  88. self.content_len = 0
  89. else:
  90. chunk_data_buf = ''
  91. while (True):
  92. # Read one character into temp buffer
  93. read_ch = self.client.recv(1)
  94. # Check CRLF
  95. if (read_ch == '\r'):
  96. read_ch = self.client.recv(1)
  97. if (read_ch == '\n'):
  98. # If CRLF decode length of chunk
  99. chunk_len = int(chunk_data_buf, 16)
  100. # Keep adding to contents
  101. self.content_len += chunk_len
  102. read_data += self.client.recv(chunk_len)
  103. chunk_data_buf = ''
  104. # Fetch remaining CRLF
  105. if self.client.recv(2) != "\r\n":
  106. # Error in packet
  107. return None
  108. if not chunk_len:
  109. # If last chunk
  110. break
  111. continue
  112. chunk_data_buf += '\r'
  113. # If not CRLF continue appending
  114. # character to chunked data buffer
  115. chunk_data_buf += read_ch
  116. return read_data
  117. def close(self):
  118. self.client.close()
  119. def verbose_print(verbosity, *args):
  120. if (verbosity):
  121. print ''.join(str(elems) for elems in args)
  122. def test_get_handler(ip, port, verbosity = False):
  123. verbose_print(verbosity, "======== GET HANDLER TEST =============")
  124. # Establish HTTP connection
  125. verbose_print(verbosity, "Connecting to => " + ip + ":" + port)
  126. sess = Session(ip, port)
  127. uri = "/hello?query1=value1&query2=value2&query3=value3"
  128. # GET hello response
  129. test_headers = {"Test-Header-1":"Test-Value-1", "Test-Header-2":"Test-Value-2"}
  130. verbose_print(verbosity, "Sending GET to URI : ", uri)
  131. verbose_print(verbosity, "Sending additional headers : ")
  132. for k, v in test_headers.iteritems():
  133. verbose_print(verbosity, "\t", k, ": ", v)
  134. sess.send_get(uri, test_headers)
  135. resp_hdrs = sess.read_resp_hdrs()
  136. resp_data = sess.read_resp_data()
  137. try:
  138. if resp_hdrs["Custom-Header-1"] != "Custom-Value-1":
  139. return False
  140. if resp_hdrs["Custom-Header-2"] != "Custom-Value-2":
  141. return False
  142. except:
  143. return False
  144. verbose_print(verbosity, "vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv")
  145. verbose_print(verbosity, "Server response to GET /hello")
  146. verbose_print(verbosity, "Response Headers : ")
  147. for k, v in resp_hdrs.iteritems():
  148. verbose_print(verbosity, "\t", k, ": ", v)
  149. verbose_print(verbosity, "Response Data : " + resp_data)
  150. verbose_print(verbosity, "========================================\n")
  151. # Close HTTP connection
  152. sess.close()
  153. return (resp_data == "Hello World!")
  154. def test_post_handler(ip, port, msg, verbosity = False):
  155. verbose_print(verbosity, "======== POST HANDLER TEST ============")
  156. # Establish HTTP connection
  157. verbose_print(verbosity, "Connecting to => " + ip + ":" + port)
  158. sess = Session(ip, port)
  159. # POST message to /echo and get back response
  160. sess.send_post("/echo", msg)
  161. resp_hdrs = sess.read_resp_hdrs()
  162. resp_data = sess.read_resp_data()
  163. verbose_print(verbosity, "Server response to POST /echo (" + msg + ")")
  164. verbose_print(verbosity, "vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv")
  165. verbose_print(verbosity, resp_data)
  166. verbose_print(verbosity, "========================================\n")
  167. # Close HTTP connection
  168. sess.close()
  169. return (resp_data == msg)
  170. def test_put_handler(ip, port, verbosity = False):
  171. verbose_print(verbosity, "======== PUT HANDLER TEST =============")
  172. # Establish HTTP connection
  173. verbose_print(verbosity, "Connecting to => " + ip + ":" + port)
  174. sess = Session(ip, port)
  175. # PUT message to /ctrl to disable /hello URI handler
  176. verbose_print(verbosity, "Disabling /hello handler")
  177. sess.send_put("/ctrl", "0")
  178. sess.read_resp_hdrs()
  179. if sess.content_len:
  180. sess.read_resp_data()
  181. sess.send_get("/hello")
  182. sess.read_resp_hdrs()
  183. resp_data1 = sess.read_resp_data()
  184. verbose_print(verbosity, "Response on GET /hello : " + resp_data1)
  185. # PUT message to /ctrl to enable /hello URI handler
  186. verbose_print(verbosity, "Enabling /hello handler")
  187. sess.send_put("/ctrl", "1")
  188. sess.read_resp_hdrs()
  189. if sess.content_len:
  190. sess.read_resp_data()
  191. sess.send_get("/hello")
  192. sess.read_resp_hdrs()
  193. resp_data2 = sess.read_resp_data()
  194. verbose_print(verbosity, "Response on GET /hello : " + resp_data2)
  195. # Close HTTP connection
  196. sess.close()
  197. return ((resp_data2 == "Hello World!") and (resp_data1 == "This URI doesn't exist"))
  198. def test_custom_uri_query(ip, port, query, verbosity = False):
  199. verbose_print(verbosity, "======== GET HANDLER TEST =============")
  200. # Establish HTTP connection
  201. verbose_print(verbosity, "Connecting to => " + ip + ":" + port)
  202. sess = Session(ip, port)
  203. uri = "/hello?" + query
  204. # GET hello response
  205. verbose_print(verbosity, "Sending GET to URI : ", uri)
  206. sess.send_get(uri, {})
  207. resp_hdrs = sess.read_resp_hdrs()
  208. resp_data = sess.read_resp_data()
  209. verbose_print(verbosity, "vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv")
  210. verbose_print(verbosity, "Server response to GET /hello")
  211. verbose_print(verbosity, "Response Data : " + resp_data)
  212. verbose_print(verbosity, "========================================\n")
  213. # Close HTTP connection
  214. sess.close()
  215. return (resp_data == "Hello World!")
  216. if __name__ == '__main__':
  217. # Configure argument parser
  218. parser = argparse.ArgumentParser(description='Run HTTPd Test')
  219. parser.add_argument('IP' , metavar='IP' , type=str, help='Server IP')
  220. parser.add_argument('port', metavar='port', type=str, help='Server port')
  221. parser.add_argument('msg', metavar='message', type=str, help='Message to be sent to server')
  222. args = vars(parser.parse_args())
  223. # Get arguments
  224. ip = args['IP']
  225. port = args['port']
  226. msg = args['msg']
  227. test_get_handler (ip, port, True)
  228. test_post_handler(ip, port, msg, True)
  229. test_put_handler (ip, port, True)