您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
 
 
 
 

956 行
35 KiB

  1. import pytest
  2. from .._util import LocalProtocolError, RemoteProtocolError
  3. from .._events import *
  4. from .._state import *
  5. from .._connection import (
  6. _keep_alive, _body_framing,
  7. Connection, NEED_DATA, PAUSED
  8. )
  9. from .helpers import ConnectionPair, get_all_events, receive_and_get
  10. def test__keep_alive():
  11. assert _keep_alive(
  12. Request(method="GET", target="/", headers=[("Host", "Example.com")]))
  13. assert not _keep_alive(
  14. Request(method="GET", target="/",
  15. headers=[("Host", "Example.com"), ("Connection", "close")]))
  16. assert not _keep_alive(
  17. Request(method="GET", target="/",
  18. headers=[("Host", "Example.com"),
  19. ("Connection", "a, b, cLOse, foo")]))
  20. assert not _keep_alive(
  21. Request(method="GET", target="/", headers=[], http_version="1.0"))
  22. assert _keep_alive(
  23. Response(status_code=200, headers=[]))
  24. assert not _keep_alive(
  25. Response(status_code=200, headers=[("Connection", "close")]))
  26. assert not _keep_alive(
  27. Response(status_code=200,
  28. headers=[("Connection", "a, b, cLOse, foo")]))
  29. assert not _keep_alive(
  30. Response(status_code=200, headers=[], http_version="1.0"))
  31. def test__body_framing():
  32. def headers(cl, te):
  33. headers = []
  34. if cl is not None:
  35. headers.append(("Content-Length", str(cl)))
  36. if te:
  37. headers.append(("Transfer-Encoding", "chunked"))
  38. return headers
  39. def resp(status_code=200, cl=None, te=False):
  40. return Response(status_code=status_code, headers=headers(cl, te))
  41. def req(cl=None, te=False):
  42. h = headers(cl, te)
  43. h += [("Host", "example.com")]
  44. return Request(method="GET", target="/", headers=h)
  45. # Special cases where the headers are ignored:
  46. for kwargs in [{}, {"cl": 100}, {"te": True}, {"cl": 100, "te": True}]:
  47. for meth, r in [(b"HEAD", resp(**kwargs)),
  48. (b"GET", resp(status_code=204, **kwargs)),
  49. (b"GET", resp(status_code=304, **kwargs))]:
  50. assert _body_framing(meth, r) == ("content-length", (0,))
  51. # Transfer-encoding
  52. for kwargs in [{"te": True}, {"cl": 100, "te": True}]:
  53. for meth, r in [(None, req(**kwargs)), (b"GET", resp(**kwargs))]:
  54. assert _body_framing(meth, r) == ("chunked", ())
  55. # Content-Length
  56. for meth, r in [(None, req(cl=100)), (b"GET", resp(cl=100))]:
  57. assert _body_framing(meth, r) == ("content-length", (100,))
  58. # No headers
  59. assert _body_framing(None, req()) == ("content-length", (0,))
  60. assert _body_framing(b"GET", resp()) == ("http/1.0", ())
  61. def test_Connection_basics_and_content_length():
  62. with pytest.raises(ValueError):
  63. Connection("CLIENT")
  64. p = ConnectionPair()
  65. assert p.conn[CLIENT].our_role is CLIENT
  66. assert p.conn[CLIENT].their_role is SERVER
  67. assert p.conn[SERVER].our_role is SERVER
  68. assert p.conn[SERVER].their_role is CLIENT
  69. data = p.send(CLIENT,
  70. Request(method="GET", target="/",
  71. headers=[("Host", "example.com"),
  72. ("Content-Length", "10")]))
  73. assert data == (
  74. b"GET / HTTP/1.1\r\n"
  75. b"host: example.com\r\n"
  76. b"content-length: 10\r\n\r\n")
  77. for conn in p.conns:
  78. assert conn.states == {CLIENT: SEND_BODY, SERVER: SEND_RESPONSE}
  79. assert p.conn[CLIENT].our_state is SEND_BODY
  80. assert p.conn[CLIENT].their_state is SEND_RESPONSE
  81. assert p.conn[SERVER].our_state is SEND_RESPONSE
  82. assert p.conn[SERVER].their_state is SEND_BODY
  83. assert p.conn[CLIENT].their_http_version is None
  84. assert p.conn[SERVER].their_http_version == b"1.1"
  85. data = p.send(SERVER,
  86. InformationalResponse(status_code=100, headers=[]))
  87. assert data == b"HTTP/1.1 100 \r\n\r\n"
  88. data = p.send(SERVER,
  89. Response(status_code=200,
  90. headers=[("Content-Length", "11")]))
  91. assert data == b"HTTP/1.1 200 \r\ncontent-length: 11\r\n\r\n"
  92. for conn in p.conns:
  93. assert conn.states == {CLIENT: SEND_BODY, SERVER: SEND_BODY}
  94. assert p.conn[CLIENT].their_http_version == b"1.1"
  95. assert p.conn[SERVER].their_http_version == b"1.1"
  96. data = p.send(CLIENT, Data(data=b"12345"))
  97. assert data == b"12345"
  98. data = p.send(CLIENT, Data(data=b"67890"),
  99. expect=[Data(data=b"67890"), EndOfMessage()])
  100. assert data == b"67890"
  101. data = p.send(CLIENT, EndOfMessage(), expect=[])
  102. assert data == b""
  103. for conn in p.conns:
  104. assert conn.states == {CLIENT: DONE, SERVER: SEND_BODY}
  105. data = p.send(SERVER, Data(data=b"1234567890"))
  106. assert data == b"1234567890"
  107. data = p.send(SERVER, Data(data=b"1"),
  108. expect=[Data(data=b"1"), EndOfMessage()])
  109. assert data == b"1"
  110. data = p.send(SERVER, EndOfMessage(), expect=[])
  111. assert data == b""
  112. for conn in p.conns:
  113. assert conn.states == {CLIENT: DONE, SERVER: DONE}
  114. def test_chunked():
  115. p = ConnectionPair()
  116. p.send(CLIENT,
  117. Request(method="GET", target="/",
  118. headers=[("Host", "example.com"),
  119. ("Transfer-Encoding", "chunked")]))
  120. data = p.send(CLIENT,
  121. Data(data=b"1234567890", chunk_start=True, chunk_end=True))
  122. assert data == b"a\r\n1234567890\r\n"
  123. data = p.send(CLIENT,
  124. Data(data=b"abcde", chunk_start=True, chunk_end=True))
  125. assert data == b"5\r\nabcde\r\n"
  126. data = p.send(CLIENT, Data(data=b""), expect=[])
  127. assert data == b""
  128. data = p.send(CLIENT, EndOfMessage(headers=[("hello", "there")]))
  129. assert data == b"0\r\nhello: there\r\n\r\n"
  130. p.send(SERVER,
  131. Response(status_code=200,
  132. headers=[("Transfer-Encoding", "chunked")]))
  133. p.send(SERVER, Data(data=b"54321", chunk_start=True, chunk_end=True))
  134. p.send(SERVER, Data(data=b"12345", chunk_start=True, chunk_end=True))
  135. p.send(SERVER, EndOfMessage())
  136. for conn in p.conns:
  137. assert conn.states == {CLIENT: DONE, SERVER: DONE}
  138. def test_chunk_boundaries():
  139. conn = Connection(our_role=SERVER)
  140. request = (
  141. b'POST / HTTP/1.1\r\n'
  142. b'Host: example.com\r\n'
  143. b'Transfer-Encoding: chunked\r\n'
  144. b'\r\n'
  145. )
  146. conn.receive_data(request)
  147. assert conn.next_event() == Request(
  148. method="POST",
  149. target="/",
  150. headers=[("Host", "example.com"), ("Transfer-Encoding", "chunked")]
  151. )
  152. assert conn.next_event() is NEED_DATA
  153. conn.receive_data(b'5\r\nhello\r\n')
  154. assert conn.next_event() == Data(
  155. data=b'hello', chunk_start=True, chunk_end=True
  156. )
  157. conn.receive_data(b'5\r\nhel')
  158. assert conn.next_event() == Data(
  159. data=b'hel', chunk_start=True, chunk_end=False
  160. )
  161. conn.receive_data(b'l')
  162. assert conn.next_event() == Data(
  163. data=b'l', chunk_start=False, chunk_end=False
  164. )
  165. conn.receive_data(b'o\r\n')
  166. assert conn.next_event() == Data(
  167. data=b'o', chunk_start=False, chunk_end=True
  168. )
  169. conn.receive_data(b'5\r\nhello')
  170. assert conn.next_event() == Data(
  171. data=b'hello', chunk_start=True, chunk_end=True
  172. )
  173. conn.receive_data(b'\r\n')
  174. assert conn.next_event() == NEED_DATA
  175. conn.receive_data(b'0\r\n\r\n')
  176. assert conn.next_event() == EndOfMessage()
  177. def test_client_talking_to_http10_server():
  178. c = Connection(CLIENT)
  179. c.send(Request(method="GET", target="/",
  180. headers=[("Host", "example.com")]))
  181. c.send(EndOfMessage())
  182. assert c.our_state is DONE
  183. # No content-length, so Http10 framing for body
  184. assert (receive_and_get(c, b"HTTP/1.0 200 OK\r\n\r\n")
  185. == [Response(status_code=200, headers=[], http_version="1.0", reason=b"OK")])
  186. assert c.our_state is MUST_CLOSE
  187. assert (receive_and_get(c, b"12345") == [Data(data=b"12345")])
  188. assert (receive_and_get(c, b"67890") == [Data(data=b"67890")])
  189. assert (receive_and_get(c, b"") == [EndOfMessage(), ConnectionClosed()])
  190. assert c.their_state is CLOSED
  191. def test_server_talking_to_http10_client():
  192. c = Connection(SERVER)
  193. # No content-length, so no body
  194. # NB: no host header
  195. assert receive_and_get(c, b"GET / HTTP/1.0\r\n\r\n") == [
  196. Request(method="GET", target="/",
  197. headers=[],
  198. http_version="1.0"),
  199. EndOfMessage(),
  200. ]
  201. assert c.their_state is MUST_CLOSE
  202. # We automatically Connection: close back at them
  203. assert (c.send(Response(status_code=200, headers=[]))
  204. == b"HTTP/1.1 200 \r\nconnection: close\r\n\r\n")
  205. assert c.send(Data(data=b"12345")) == b"12345"
  206. assert c.send(EndOfMessage()) == b""
  207. assert c.our_state is MUST_CLOSE
  208. # Check that it works if they do send Content-Length
  209. c = Connection(SERVER)
  210. # NB: no host header
  211. assert (receive_and_get(c,
  212. b"POST / HTTP/1.0\r\nContent-Length: 10\r\n\r\n1")
  213. == [Request(method="POST", target="/",
  214. headers=[("Content-Length", "10")],
  215. http_version="1.0"),
  216. Data(data=b"1")])
  217. assert (receive_and_get(c, b"234567890")
  218. == [Data(data=b"234567890"), EndOfMessage()])
  219. assert c.their_state is MUST_CLOSE
  220. assert receive_and_get(c, b"") == [ConnectionClosed()]
  221. def test_automatic_transfer_encoding_in_response():
  222. # Check that in responses, the user can specify either Transfer-Encoding:
  223. # chunked or no framing at all, and in both cases we automatically select
  224. # the right option depending on whether the peer speaks HTTP/1.0 or
  225. # HTTP/1.1
  226. for user_headers in [[("Transfer-Encoding", "chunked")],
  227. [],
  228. # In fact, this even works if Content-Length is set,
  229. # because if both are set then Transfer-Encoding wins
  230. [("Transfer-Encoding", "chunked"),
  231. ("Content-Length", "100")]]:
  232. p = ConnectionPair()
  233. p.send(CLIENT, [
  234. Request(method="GET", target="/",
  235. headers=[("Host", "example.com")]),
  236. EndOfMessage(),
  237. ])
  238. # When speaking to HTTP/1.1 client, all of the above cases get
  239. # normalized to Transfer-Encoding: chunked
  240. p.send(SERVER,
  241. Response(status_code=200,
  242. headers=user_headers),
  243. expect=Response(status_code=200,
  244. headers=[("Transfer-Encoding", "chunked")]))
  245. # When speaking to HTTP/1.0 client, all of the above cases get
  246. # normalized to no-framing-headers
  247. c = Connection(SERVER)
  248. receive_and_get(c, b"GET / HTTP/1.0\r\n\r\n")
  249. assert (c.send(Response(status_code=200, headers=user_headers))
  250. == b"HTTP/1.1 200 \r\nconnection: close\r\n\r\n")
  251. assert c.send(Data(data=b"12345")) == b"12345"
  252. def test_automagic_connection_close_handling():
  253. p = ConnectionPair()
  254. # If the user explicitly sets Connection: close, then we notice and
  255. # respect it
  256. p.send(CLIENT,
  257. [Request(method="GET", target="/",
  258. headers=[("Host", "example.com"),
  259. ("Connection", "close")]),
  260. EndOfMessage()])
  261. for conn in p.conns:
  262. assert conn.states[CLIENT] is MUST_CLOSE
  263. # And if the client sets it, the server automatically echoes it back
  264. p.send(SERVER,
  265. # no header here...
  266. [Response(status_code=204, headers=[]),
  267. EndOfMessage()],
  268. # ...but oh look, it arrived anyway
  269. expect=[Response(status_code=204,
  270. headers=[("connection", "close")]),
  271. EndOfMessage()])
  272. for conn in p.conns:
  273. assert conn.states == {CLIENT: MUST_CLOSE, SERVER: MUST_CLOSE}
  274. def test_100_continue():
  275. def setup():
  276. p = ConnectionPair()
  277. p.send(CLIENT,
  278. Request(method="GET", target="/",
  279. headers=[("Host", "example.com"),
  280. ("Content-Length", "100"),
  281. ("Expect", "100-continue")]))
  282. for conn in p.conns:
  283. assert conn.client_is_waiting_for_100_continue
  284. assert not p.conn[CLIENT].they_are_waiting_for_100_continue
  285. assert p.conn[SERVER].they_are_waiting_for_100_continue
  286. return p
  287. # Disabled by 100 Continue
  288. p = setup()
  289. p.send(SERVER,
  290. InformationalResponse(status_code=100, headers=[]))
  291. for conn in p.conns:
  292. assert not conn.client_is_waiting_for_100_continue
  293. assert not conn.they_are_waiting_for_100_continue
  294. # Disabled by a real response
  295. p = setup()
  296. p.send(SERVER,
  297. Response(status_code=200,
  298. headers=[("Transfer-Encoding", "chunked")]))
  299. for conn in p.conns:
  300. assert not conn.client_is_waiting_for_100_continue
  301. assert not conn.they_are_waiting_for_100_continue
  302. # Disabled by the client going ahead and sending stuff anyway
  303. p = setup()
  304. p.send(CLIENT, Data(data=b"12345"))
  305. for conn in p.conns:
  306. assert not conn.client_is_waiting_for_100_continue
  307. assert not conn.they_are_waiting_for_100_continue
  308. def test_max_incomplete_event_size_countermeasure():
  309. # Infinitely long headers are definitely not okay
  310. c = Connection(SERVER)
  311. c.receive_data(b"GET / HTTP/1.0\r\nEndless: ")
  312. assert c.next_event() is NEED_DATA
  313. with pytest.raises(RemoteProtocolError):
  314. while True:
  315. c.receive_data(b"a" * 1024)
  316. c.next_event()
  317. # Checking that the same header is accepted / rejected depending on the
  318. # max_incomplete_event_size setting:
  319. c = Connection(SERVER, max_incomplete_event_size=5000)
  320. c.receive_data(b"GET / HTTP/1.0\r\nBig: ")
  321. c.receive_data(b"a" * 4000)
  322. c.receive_data(b"\r\n\r\n")
  323. assert get_all_events(c) == [
  324. Request(method="GET", target="/", http_version="1.0",
  325. headers=[("big", "a" * 4000)]),
  326. EndOfMessage(),
  327. ]
  328. c = Connection(SERVER, max_incomplete_event_size=4000)
  329. c.receive_data(b"GET / HTTP/1.0\r\nBig: ")
  330. c.receive_data(b"a" * 4000)
  331. with pytest.raises(RemoteProtocolError):
  332. c.next_event()
  333. # Temporarily exceeding the size limit is fine, as long as its done with
  334. # complete events:
  335. c = Connection(SERVER, max_incomplete_event_size=5000)
  336. c.receive_data(b"GET / HTTP/1.0\r\nContent-Length: 10000")
  337. c.receive_data(b"\r\n\r\n" + b"a" * 10000)
  338. assert get_all_events(c) == [
  339. Request(method="GET", target="/", http_version="1.0",
  340. headers=[("Content-Length", "10000")]),
  341. Data(data=b"a" * 10000),
  342. EndOfMessage(),
  343. ]
  344. c = Connection(SERVER, max_incomplete_event_size=100)
  345. # Two pipelined requests to create a way-too-big receive buffer... but
  346. # it's fine because we're not checking
  347. c.receive_data(b"GET /1 HTTP/1.1\r\nHost: a\r\n\r\n"
  348. b"GET /2 HTTP/1.1\r\nHost: b\r\n\r\n"
  349. + b"X" * 1000)
  350. assert get_all_events(c) == [
  351. Request(method="GET", target="/1", headers=[("host", "a")]),
  352. EndOfMessage(),
  353. ]
  354. # Even more data comes in, still no problem
  355. c.receive_data(b"X" * 1000)
  356. # We can respond and reuse to get the second pipelined request
  357. c.send(Response(status_code=200, headers=[]))
  358. c.send(EndOfMessage())
  359. c.start_next_cycle()
  360. assert get_all_events(c) == [
  361. Request(method="GET", target="/2", headers=[("host", "b")]),
  362. EndOfMessage(),
  363. ]
  364. # But once we unpause and try to read the next message, and find that it's
  365. # incomplete and the buffer is *still* way too large, then *that's* a
  366. # problem:
  367. c.send(Response(status_code=200, headers=[]))
  368. c.send(EndOfMessage())
  369. c.start_next_cycle()
  370. with pytest.raises(RemoteProtocolError):
  371. c.next_event()
  372. def test_reuse_simple():
  373. p = ConnectionPair()
  374. p.send(CLIENT,
  375. [Request(method="GET", target="/", headers=[("Host", "a")]),
  376. EndOfMessage()])
  377. p.send(SERVER,
  378. [Response(status_code=200, headers=[]),
  379. EndOfMessage()])
  380. for conn in p.conns:
  381. assert conn.states == {CLIENT: DONE, SERVER: DONE}
  382. conn.start_next_cycle()
  383. p.send(CLIENT,
  384. [Request(method="DELETE", target="/foo", headers=[("Host", "a")]),
  385. EndOfMessage()])
  386. p.send(SERVER,
  387. [Response(status_code=404, headers=[]),
  388. EndOfMessage()])
  389. def test_pipelining():
  390. # Client doesn't support pipelining, so we have to do this by hand
  391. c = Connection(SERVER)
  392. assert c.next_event() is NEED_DATA
  393. # 3 requests all bunched up
  394. c.receive_data(
  395. b"GET /1 HTTP/1.1\r\nHost: a.com\r\nContent-Length: 5\r\n\r\n"
  396. b"12345"
  397. b"GET /2 HTTP/1.1\r\nHost: a.com\r\nContent-Length: 5\r\n\r\n"
  398. b"67890"
  399. b"GET /3 HTTP/1.1\r\nHost: a.com\r\n\r\n")
  400. assert get_all_events(c) == [
  401. Request(method="GET", target="/1",
  402. headers=[("Host", "a.com"), ("Content-Length", "5")]),
  403. Data(data=b"12345"),
  404. EndOfMessage(),
  405. ]
  406. assert c.their_state is DONE
  407. assert c.our_state is SEND_RESPONSE
  408. assert c.next_event() is PAUSED
  409. c.send(Response(status_code=200, headers=[]))
  410. c.send(EndOfMessage())
  411. assert c.their_state is DONE
  412. assert c.our_state is DONE
  413. c.start_next_cycle()
  414. assert get_all_events(c) == [
  415. Request(method="GET", target="/2",
  416. headers=[("Host", "a.com"), ("Content-Length", "5")]),
  417. Data(data=b"67890"),
  418. EndOfMessage(),
  419. ]
  420. assert c.next_event() is PAUSED
  421. c.send(Response(status_code=200, headers=[]))
  422. c.send(EndOfMessage())
  423. c.start_next_cycle()
  424. assert get_all_events(c) == [
  425. Request(method="GET", target="/3",
  426. headers=[("Host", "a.com")]),
  427. EndOfMessage(),
  428. ]
  429. # Doesn't pause this time, no trailing data
  430. assert c.next_event() is NEED_DATA
  431. c.send(Response(status_code=200, headers=[]))
  432. c.send(EndOfMessage())
  433. # Arrival of more data triggers pause
  434. assert c.next_event() is NEED_DATA
  435. c.receive_data(b"SADF")
  436. assert c.next_event() is PAUSED
  437. assert c.trailing_data == (b"SADF", False)
  438. # If EOF arrives while paused, we don't see that either:
  439. c.receive_data(b"")
  440. assert c.trailing_data == (b"SADF", True)
  441. assert c.next_event() is PAUSED
  442. c.receive_data(b"")
  443. assert c.next_event() is PAUSED
  444. # Can't call receive_data with non-empty buf after closing it
  445. with pytest.raises(RuntimeError):
  446. c.receive_data(b"FDSA")
  447. def test_protocol_switch():
  448. for (req, deny, accept) in [
  449. (Request(method="CONNECT", target="example.com:443",
  450. headers=[("Host", "foo"), ("Content-Length", "1")]),
  451. Response(status_code=404, headers=[]),
  452. Response(status_code=200, headers=[])),
  453. (Request(method="GET", target="/",
  454. headers=[("Host", "foo"),
  455. ("Content-Length", "1"),
  456. ("Upgrade", "a, b")]),
  457. Response(status_code=200, headers=[]),
  458. InformationalResponse(status_code=101,
  459. headers=[("Upgrade", "a")])),
  460. (Request(method="CONNECT", target="example.com:443",
  461. headers=[("Host", "foo"),
  462. ("Content-Length", "1"),
  463. ("Upgrade", "a, b")]),
  464. Response(status_code=404, headers=[]),
  465. # Accept CONNECT, not upgrade
  466. Response(status_code=200, headers=[])),
  467. (Request(method="CONNECT", target="example.com:443",
  468. headers=[("Host", "foo"),
  469. ("Content-Length", "1"),
  470. ("Upgrade", "a, b")]),
  471. Response(status_code=404, headers=[]),
  472. # Accept Upgrade, not CONNECT
  473. InformationalResponse(status_code=101,
  474. headers=[("Upgrade", "b")])),
  475. ]:
  476. def setup():
  477. p = ConnectionPair()
  478. p.send(CLIENT, req)
  479. # No switch-related state change stuff yet; the client has to
  480. # finish the request before that kicks in
  481. for conn in p.conns:
  482. assert conn.states[CLIENT] is SEND_BODY
  483. p.send(CLIENT, [Data(data=b"1"), EndOfMessage()])
  484. for conn in p.conns:
  485. assert conn.states[CLIENT] is MIGHT_SWITCH_PROTOCOL
  486. assert p.conn[SERVER].next_event() is PAUSED
  487. return p
  488. # Test deny case
  489. p = setup()
  490. p.send(SERVER, deny)
  491. for conn in p.conns:
  492. assert conn.states == {CLIENT: DONE, SERVER: SEND_BODY}
  493. p.send(SERVER, EndOfMessage())
  494. # Check that re-use is still allowed after a denial
  495. for conn in p.conns:
  496. conn.start_next_cycle()
  497. # Test accept case
  498. p = setup()
  499. p.send(SERVER, accept)
  500. for conn in p.conns:
  501. assert conn.states == {CLIENT: SWITCHED_PROTOCOL,
  502. SERVER: SWITCHED_PROTOCOL}
  503. conn.receive_data(b"123")
  504. assert conn.next_event() is PAUSED
  505. conn.receive_data(b"456")
  506. assert conn.next_event() is PAUSED
  507. assert conn.trailing_data == (b"123456", False)
  508. # Pausing in might-switch, then recovery
  509. # (weird artificial case where the trailing data actually is valid
  510. # HTTP for some reason, because this makes it easier to test the state
  511. # logic)
  512. p = setup()
  513. sc = p.conn[SERVER]
  514. sc.receive_data(b"GET / HTTP/1.0\r\n\r\n")
  515. assert sc.next_event() is PAUSED
  516. assert sc.trailing_data == (b"GET / HTTP/1.0\r\n\r\n", False)
  517. sc.send(deny)
  518. assert sc.next_event() is PAUSED
  519. sc.send(EndOfMessage())
  520. sc.start_next_cycle()
  521. assert get_all_events(sc) == [
  522. Request(method="GET", target="/", headers=[], http_version="1.0"),
  523. EndOfMessage(),
  524. ]
  525. # When we're DONE, have no trailing data, and the connection gets
  526. # closed, we report ConnectionClosed(). When we're in might-switch or
  527. # switched, we don't.
  528. p = setup()
  529. sc = p.conn[SERVER]
  530. sc.receive_data(b"")
  531. assert sc.next_event() is PAUSED
  532. assert sc.trailing_data == (b"", True)
  533. p.send(SERVER, accept)
  534. assert sc.next_event() is PAUSED
  535. p = setup()
  536. sc = p.conn[SERVER]
  537. sc.receive_data(b"") == []
  538. assert sc.next_event() is PAUSED
  539. sc.send(deny)
  540. assert sc.next_event() == ConnectionClosed()
  541. # You can't send after switching protocols, or while waiting for a
  542. # protocol switch
  543. p = setup()
  544. with pytest.raises(LocalProtocolError):
  545. p.conn[CLIENT].send(
  546. Request(method="GET", target="/", headers=[("Host", "a")]))
  547. p = setup()
  548. p.send(SERVER, accept)
  549. with pytest.raises(LocalProtocolError):
  550. p.conn[SERVER].send(Data(data=b"123"))
  551. def test_close_simple():
  552. # Just immediately closing a new connection without anything having
  553. # happened yet.
  554. for (who_shot_first, who_shot_second) in [
  555. (CLIENT, SERVER),
  556. (SERVER, CLIENT),
  557. ]:
  558. def setup():
  559. p = ConnectionPair()
  560. p.send(who_shot_first, ConnectionClosed())
  561. for conn in p.conns:
  562. assert conn.states == {
  563. who_shot_first: CLOSED,
  564. who_shot_second: MUST_CLOSE,
  565. }
  566. return p
  567. # You can keep putting b"" into a closed connection, and you keep
  568. # getting ConnectionClosed() out:
  569. p = setup()
  570. assert p.conn[who_shot_second].next_event() == ConnectionClosed()
  571. assert p.conn[who_shot_second].next_event() == ConnectionClosed()
  572. p.conn[who_shot_second].receive_data(b"")
  573. assert p.conn[who_shot_second].next_event() == ConnectionClosed()
  574. # Second party can close...
  575. p = setup()
  576. p.send(who_shot_second, ConnectionClosed())
  577. for conn in p.conns:
  578. assert conn.our_state is CLOSED
  579. assert conn.their_state is CLOSED
  580. # But trying to receive new data on a closed connection is a
  581. # RuntimeError (not ProtocolError, because the problem here isn't
  582. # violation of HTTP, it's violation of physics)
  583. p = setup()
  584. with pytest.raises(RuntimeError):
  585. p.conn[who_shot_second].receive_data(b"123")
  586. # And receiving new data on a MUST_CLOSE connection is a ProtocolError
  587. p = setup()
  588. p.conn[who_shot_first].receive_data(b"GET")
  589. with pytest.raises(RemoteProtocolError):
  590. p.conn[who_shot_first].next_event()
  591. def test_close_different_states():
  592. req = [Request(method="GET", target="/foo", headers=[("Host", "a")]),
  593. EndOfMessage()]
  594. resp = [Response(status_code=200, headers=[]), EndOfMessage()]
  595. # Client before request
  596. p = ConnectionPair()
  597. p.send(CLIENT, ConnectionClosed())
  598. for conn in p.conns:
  599. assert conn.states == {CLIENT: CLOSED, SERVER: MUST_CLOSE}
  600. # Client after request
  601. p = ConnectionPair()
  602. p.send(CLIENT, req)
  603. p.send(CLIENT, ConnectionClosed())
  604. for conn in p.conns:
  605. assert conn.states == {CLIENT: CLOSED, SERVER: SEND_RESPONSE}
  606. # Server after request -> not allowed
  607. p = ConnectionPair()
  608. p.send(CLIENT, req)
  609. with pytest.raises(LocalProtocolError):
  610. p.conn[SERVER].send(ConnectionClosed())
  611. p.conn[CLIENT].receive_data(b"")
  612. with pytest.raises(RemoteProtocolError):
  613. p.conn[CLIENT].next_event()
  614. # Server after response
  615. p = ConnectionPair()
  616. p.send(CLIENT, req)
  617. p.send(SERVER, resp)
  618. p.send(SERVER, ConnectionClosed())
  619. for conn in p.conns:
  620. assert conn.states == {CLIENT: MUST_CLOSE, SERVER: CLOSED}
  621. # Both after closing (ConnectionClosed() is idempotent)
  622. p = ConnectionPair()
  623. p.send(CLIENT, req)
  624. p.send(SERVER, resp)
  625. p.send(CLIENT, ConnectionClosed())
  626. p.send(SERVER, ConnectionClosed())
  627. p.send(CLIENT, ConnectionClosed())
  628. p.send(SERVER, ConnectionClosed())
  629. # In the middle of sending -> not allowed
  630. p = ConnectionPair()
  631. p.send(CLIENT,
  632. Request(method="GET", target="/",
  633. headers=[("Host", "a"), ("Content-Length", "10")]))
  634. with pytest.raises(LocalProtocolError):
  635. p.conn[CLIENT].send(ConnectionClosed())
  636. p.conn[SERVER].receive_data(b"")
  637. with pytest.raises(RemoteProtocolError):
  638. p.conn[SERVER].next_event()
  639. # Receive several requests and then client shuts down their side of the
  640. # connection; we can respond to each
  641. def test_pipelined_close():
  642. c = Connection(SERVER)
  643. # 2 requests then a close
  644. c.receive_data(
  645. b"GET /1 HTTP/1.1\r\nHost: a.com\r\nContent-Length: 5\r\n\r\n"
  646. b"12345"
  647. b"GET /2 HTTP/1.1\r\nHost: a.com\r\nContent-Length: 5\r\n\r\n"
  648. b"67890")
  649. c.receive_data(b"")
  650. assert get_all_events(c) == [
  651. Request(method="GET", target="/1",
  652. headers=[("host", "a.com"), ("content-length", "5")]),
  653. Data(data=b"12345"),
  654. EndOfMessage(),
  655. ]
  656. assert c.states[CLIENT] is DONE
  657. c.send(Response(status_code=200, headers=[]))
  658. c.send(EndOfMessage())
  659. assert c.states[SERVER] is DONE
  660. c.start_next_cycle()
  661. assert get_all_events(c) == [
  662. Request(method="GET", target="/2",
  663. headers=[("host", "a.com"), ("content-length", "5")]),
  664. Data(data=b"67890"),
  665. EndOfMessage(),
  666. ConnectionClosed(),
  667. ]
  668. assert c.states == {CLIENT: CLOSED, SERVER: SEND_RESPONSE}
  669. c.send(Response(status_code=200, headers=[]))
  670. c.send(EndOfMessage())
  671. assert c.states == {CLIENT: CLOSED, SERVER: MUST_CLOSE}
  672. c.send(ConnectionClosed())
  673. assert c.states == {CLIENT: CLOSED, SERVER: CLOSED}
  674. def test_sendfile():
  675. class SendfilePlaceholder:
  676. def __len__(self):
  677. return 10
  678. placeholder = SendfilePlaceholder()
  679. def setup(header, http_version):
  680. c = Connection(SERVER)
  681. receive_and_get(c,
  682. "GET / HTTP/{}\r\nHost: a\r\n\r\n"
  683. .format(http_version)
  684. .encode("ascii"))
  685. headers = []
  686. if header:
  687. headers.append(header)
  688. c.send(Response(status_code=200, headers=headers))
  689. return c, c.send_with_data_passthrough(Data(data=placeholder))
  690. c, data = setup(("Content-Length", "10"), "1.1")
  691. assert data == [placeholder]
  692. # Raises an error if the connection object doesn't think we've sent
  693. # exactly 10 bytes
  694. c.send(EndOfMessage())
  695. _, data = setup(("Transfer-Encoding", "chunked"), "1.1")
  696. assert placeholder in data
  697. data[data.index(placeholder)] = b"x" * 10
  698. assert b"".join(data) == b"a\r\nxxxxxxxxxx\r\n"
  699. c, data = setup(None, "1.0")
  700. assert data == [placeholder]
  701. assert c.our_state is SEND_BODY
  702. def test_errors():
  703. # After a receive error, you can't receive
  704. for role in [CLIENT, SERVER]:
  705. c = Connection(our_role=role)
  706. c.receive_data(b"gibberish\r\n\r\n")
  707. with pytest.raises(RemoteProtocolError):
  708. c.next_event()
  709. # Now any attempt to receive continues to raise
  710. assert c.their_state is ERROR
  711. assert c.our_state is not ERROR
  712. print(c._cstate.states)
  713. with pytest.raises(RemoteProtocolError):
  714. c.next_event()
  715. # But we can still yell at the client for sending us gibberish
  716. if role is SERVER:
  717. assert (c.send(Response(status_code=400, headers=[]))
  718. == b"HTTP/1.1 400 \r\nconnection: close\r\n\r\n")
  719. # After an error sending, you can no longer send
  720. # (This is especially important for things like content-length errors,
  721. # where there's complex internal state being modified)
  722. def conn(role):
  723. c = Connection(our_role=role)
  724. if role is SERVER:
  725. # Put it into the state where it *could* send a response...
  726. receive_and_get(c, b"GET / HTTP/1.0\r\n\r\n")
  727. assert c.our_state is SEND_RESPONSE
  728. return c
  729. for role in [CLIENT, SERVER]:
  730. if role is CLIENT:
  731. # This HTTP/1.0 request won't be detected as bad until after we go
  732. # through the state machine and hit the writing code
  733. good = Request(method="GET", target="/",
  734. headers=[("Host", "example.com")])
  735. bad = Request(method="GET", target="/",
  736. headers=[("Host", "example.com")],
  737. http_version="1.0")
  738. elif role is SERVER:
  739. good = Response(status_code=200, headers=[])
  740. bad = Response(status_code=200, headers=[], http_version="1.0")
  741. # Make sure 'good' actually is good
  742. c = conn(role)
  743. c.send(good)
  744. assert c.our_state is not ERROR
  745. # Do that again, but this time sending 'bad' first
  746. c = conn(role)
  747. with pytest.raises(LocalProtocolError):
  748. c.send(bad)
  749. assert c.our_state is ERROR
  750. assert c.their_state is not ERROR
  751. # Now 'good' is not so good
  752. with pytest.raises(LocalProtocolError):
  753. c.send(good)
  754. # And check send_failed() too
  755. c = conn(role)
  756. c.send_failed()
  757. assert c.our_state is ERROR
  758. assert c.their_state is not ERROR
  759. # This is idempotent
  760. c.send_failed()
  761. assert c.our_state is ERROR
  762. assert c.their_state is not ERROR
  763. def test_idle_receive_nothing():
  764. # At one point this incorrectly raised an error
  765. for role in [CLIENT, SERVER]:
  766. c = Connection(role)
  767. assert c.next_event() is NEED_DATA
  768. def test_connection_drop():
  769. c = Connection(SERVER)
  770. c.receive_data(b"GET /")
  771. assert c.next_event() is NEED_DATA
  772. c.receive_data(b"")
  773. with pytest.raises(RemoteProtocolError):
  774. c.next_event()
  775. def test_408_request_timeout():
  776. # Should be able to send this spontaneously as a server without seeing
  777. # anything from client
  778. p = ConnectionPair()
  779. p.send(SERVER, Response(status_code=408, headers=[]))
  780. # This used to raise IndexError
  781. def test_empty_request():
  782. c = Connection(SERVER)
  783. c.receive_data(b"\r\n")
  784. with pytest.raises(RemoteProtocolError):
  785. c.next_event()
  786. # This used to raise IndexError
  787. def test_empty_response():
  788. c = Connection(CLIENT)
  789. c.send(Request(method="GET", target="/", headers=[("Host", "a")]))
  790. c.receive_data(b"\r\n")
  791. with pytest.raises(RemoteProtocolError):
  792. c.next_event()
  793. # This used to give different headers for HEAD and GET.
  794. # The correct way to handle HEAD is to put whatever headers we *would* have
  795. # put if it were a GET -- even though we know that for HEAD, those headers
  796. # will be ignored.
  797. def test_HEAD_framing_headers():
  798. def setup(method, http_version):
  799. c = Connection(SERVER)
  800. c.receive_data(method + b" / HTTP/" + http_version + b"\r\n"
  801. + b"Host: example.com\r\n\r\n")
  802. assert type(c.next_event()) is Request
  803. assert type(c.next_event()) is EndOfMessage
  804. return c
  805. for method in [b"GET", b"HEAD"]:
  806. # No Content-Length, HTTP/1.1 peer, should use chunked
  807. c = setup(method, b"1.1")
  808. assert (c.send(Response(status_code=200, headers=[]))
  809. == b"HTTP/1.1 200 \r\n"
  810. b"transfer-encoding: chunked\r\n\r\n")
  811. # No Content-Length, HTTP/1.0 peer, frame with connection: close
  812. c = setup(method, b"1.0")
  813. assert (c.send(Response(status_code=200, headers=[]))
  814. == b"HTTP/1.1 200 \r\n"
  815. b"connection: close\r\n\r\n")
  816. # Content-Length + Transfer-Encoding, TE wins
  817. c = setup(method, b"1.1")
  818. assert (c.send(Response(status_code=200,
  819. headers=[("Content-Length", "100"),
  820. ("Transfer-Encoding", "chunked")]))
  821. == b"HTTP/1.1 200 \r\n"
  822. b"transfer-encoding: chunked\r\n\r\n")
  823. def test_special_exceptions_for_lost_connection_in_message_body():
  824. c = Connection(SERVER)
  825. c.receive_data(b"POST / HTTP/1.1\r\n"
  826. b"Host: example.com\r\n"
  827. b"Content-Length: 100\r\n\r\n")
  828. assert type(c.next_event()) is Request
  829. assert c.next_event() is NEED_DATA
  830. c.receive_data(b"12345")
  831. assert c.next_event() == Data(data=b"12345")
  832. c.receive_data(b"")
  833. with pytest.raises(RemoteProtocolError) as excinfo:
  834. c.next_event()
  835. assert "received 5 bytes" in str(excinfo.value)
  836. assert "expected 100" in str(excinfo.value)
  837. c = Connection(SERVER)
  838. c.receive_data(b"POST / HTTP/1.1\r\n"
  839. b"Host: example.com\r\n"
  840. b"Transfer-Encoding: chunked\r\n\r\n")
  841. assert type(c.next_event()) is Request
  842. assert c.next_event() is NEED_DATA
  843. c.receive_data(b"8\r\n012345")
  844. assert c.next_event().data == b"012345"
  845. c.receive_data(b"")
  846. with pytest.raises(RemoteProtocolError) as excinfo:
  847. c.next_event()
  848. assert "incomplete chunked read" in str(excinfo.value)