plum 0.1.3 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +84 -12
- data/circle.yml +27 -0
- data/examples/client/large.rb +20 -0
- data/examples/client/twitter.rb +51 -0
- data/examples/non_tls_server.rb +15 -9
- data/examples/static_server.rb +30 -23
- data/lib/plum.rb +9 -2
- data/lib/plum/client.rb +198 -0
- data/lib/plum/client/client_session.rb +91 -0
- data/lib/plum/client/connection.rb +19 -0
- data/lib/plum/client/legacy_client_session.rb +118 -0
- data/lib/plum/client/response.rb +100 -0
- data/lib/plum/client/upgrade_client_session.rb +46 -0
- data/lib/plum/connection.rb +58 -65
- data/lib/plum/connection_utils.rb +1 -1
- data/lib/plum/errors.rb +7 -3
- data/lib/plum/flow_control.rb +3 -3
- data/lib/plum/rack/listener.rb +3 -3
- data/lib/plum/rack/server.rb +1 -0
- data/lib/plum/rack/session.rb +5 -2
- data/lib/plum/server/connection.rb +42 -0
- data/lib/plum/{http_connection.rb → server/http_connection.rb} +7 -14
- data/lib/plum/{https_connection.rb → server/https_connection.rb} +2 -9
- data/lib/plum/stream.rb +54 -24
- data/lib/plum/stream_utils.rb +0 -12
- data/lib/plum/version.rb +1 -1
- data/plum.gemspec +2 -2
- data/test/plum/client/test_client.rb +152 -0
- data/test/plum/client/test_connection.rb +11 -0
- data/test/plum/client/test_legacy_client_session.rb +90 -0
- data/test/plum/client/test_response.rb +74 -0
- data/test/plum/client/test_upgrade_client_session.rb +45 -0
- data/test/plum/connection/test_handle_frame.rb +4 -1
- data/test/plum/{test_http_connection.rb → server/test_http_connection.rb} +4 -4
- data/test/plum/{test_https_connection.rb → server/test_https_connection.rb} +14 -8
- data/test/plum/test_connection.rb +9 -2
- data/test/plum/test_connection_utils.rb +9 -0
- data/test/plum/test_error.rb +1 -2
- data/test/plum/test_frame_factory.rb +37 -0
- data/test/plum/test_stream.rb +24 -4
- data/test/plum/test_stream_utils.rb +0 -1
- data/test/test_helper.rb +5 -2
- data/test/utils/assertions.rb +9 -9
- data/test/utils/client.rb +19 -0
- data/test/utils/server.rb +6 -6
- data/test/utils/string_socket.rb +15 -0
- metadata +36 -12
@@ -0,0 +1,152 @@
|
|
1
|
+
require "test_helper"
|
2
|
+
|
3
|
+
using Plum::BinaryString
|
4
|
+
class ClientTest < Minitest::Test
|
5
|
+
def test_request_sync
|
6
|
+
server_thread = start_tls_server
|
7
|
+
client = Client.start("127.0.0.1", LISTEN_PORT, https: true, verify_mode: OpenSSL::SSL::VERIFY_NONE)
|
8
|
+
res1 = client.put!("/", "aaa", headers: { "header" => "ccc" })
|
9
|
+
assert_equal("PUTcccaaa", res1.body)
|
10
|
+
client.close
|
11
|
+
ensure
|
12
|
+
server_thread.join if server_thread
|
13
|
+
end
|
14
|
+
|
15
|
+
def test_request_async
|
16
|
+
res2 = nil
|
17
|
+
client = nil
|
18
|
+
server_thread = start_tls_server
|
19
|
+
Client.start("127.0.0.1", LISTEN_PORT, https: true, verify_mode: OpenSSL::SSL::VERIFY_NONE) { |c|
|
20
|
+
client = c
|
21
|
+
res1 = client.request({ ":path" => "/", ":method" => "GET", ":scheme" => "https", "header" => "ccc" }, nil) { |res1|
|
22
|
+
assert(res1.headers)
|
23
|
+
}
|
24
|
+
assert_nil(res1.headers)
|
25
|
+
|
26
|
+
res2 = client.get("/", headers: { "header" => "ccc" })
|
27
|
+
assert_nil(res2.headers)
|
28
|
+
}
|
29
|
+
assert(res2.headers)
|
30
|
+
assert_equal("GETccc", res2.body)
|
31
|
+
ensure
|
32
|
+
server_thread.join if server_thread
|
33
|
+
end
|
34
|
+
|
35
|
+
def test_verify
|
36
|
+
client = nil
|
37
|
+
server_thread = start_tls_server
|
38
|
+
assert_raises(OpenSSL::SSL::SSLError) {
|
39
|
+
client = Client.start("127.0.0.1", LISTEN_PORT, https: true, verify_mode: OpenSSL::SSL::VERIFY_PEER)
|
40
|
+
}
|
41
|
+
ensure
|
42
|
+
server_thread.join if server_thread
|
43
|
+
end
|
44
|
+
|
45
|
+
def test_raise_error_sync
|
46
|
+
client = nil
|
47
|
+
server_thread = start_tls_server
|
48
|
+
Client.start("127.0.0.1", LISTEN_PORT, https: true, verify_mode: OpenSSL::SSL::VERIFY_NONE) { |c|
|
49
|
+
client = c
|
50
|
+
assert_raises(LocalConnectionError) {
|
51
|
+
client.get!("/connection_error")
|
52
|
+
}
|
53
|
+
}
|
54
|
+
ensure
|
55
|
+
server_thread.join if server_thread
|
56
|
+
end
|
57
|
+
|
58
|
+
def test_raise_error_async_seq_resume
|
59
|
+
server_thread = start_tls_server
|
60
|
+
client = Client.start("127.0.0.1", LISTEN_PORT, https: true, verify_mode: OpenSSL::SSL::VERIFY_NONE)
|
61
|
+
res = client.get("/error_in_data")
|
62
|
+
assert_raises(LocalConnectionError) {
|
63
|
+
client.resume(res)
|
64
|
+
}
|
65
|
+
client.close
|
66
|
+
ensure
|
67
|
+
server_thread.join if server_thread
|
68
|
+
end
|
69
|
+
|
70
|
+
def test_raise_error_async_block
|
71
|
+
client = nil
|
72
|
+
server_thread = start_tls_server
|
73
|
+
assert_raises(LocalConnectionError) {
|
74
|
+
Client.start("127.0.0.1", LISTEN_PORT, https: true, verify_mode: OpenSSL::SSL::VERIFY_NONE) { |c|
|
75
|
+
client = c
|
76
|
+
client.get("/connection_error") { |res| flunk "success??" }
|
77
|
+
} # resume
|
78
|
+
}
|
79
|
+
ensure
|
80
|
+
server_thread.join if server_thread
|
81
|
+
end
|
82
|
+
|
83
|
+
def test_session_socket_http2_https
|
84
|
+
sock = StringSocket.new
|
85
|
+
client = Client.start(sock, nil, http2: true, scheme: "https")
|
86
|
+
assert(client.session.class == ClientSession)
|
87
|
+
end
|
88
|
+
|
89
|
+
def test_session_socket_http2_http
|
90
|
+
sock = StringSocket.new("HTTP/1.1 100\r\n\r\n")
|
91
|
+
client = Client.start(sock, nil, http2: true, scheme: "http")
|
92
|
+
assert(client.session.class == UpgradeClientSession)
|
93
|
+
end
|
94
|
+
|
95
|
+
def test_session_socket_http1
|
96
|
+
sock = StringSocket.new
|
97
|
+
client = Client.start(sock, nil, http2: false)
|
98
|
+
assert(client.session.class == LegacyClientSession)
|
99
|
+
end
|
100
|
+
|
101
|
+
private
|
102
|
+
def start_tls_server(&block)
|
103
|
+
ctx = OpenSSL::SSL::SSLContext.new
|
104
|
+
ctx.alpn_select_cb = -> protocols { "h2" }
|
105
|
+
ctx.cert = TLS_CERT
|
106
|
+
ctx.key = TLS_KEY
|
107
|
+
tcp_server = TCPServer.new("127.0.0.1", LISTEN_PORT)
|
108
|
+
ssl_server = OpenSSL::SSL::SSLServer.new(tcp_server, ctx)
|
109
|
+
|
110
|
+
server_thread = Thread.new {
|
111
|
+
plum = nil
|
112
|
+
begin
|
113
|
+
Timeout.timeout(1) {
|
114
|
+
sock = ssl_server.accept
|
115
|
+
plum = HTTPSServerConnection.new(sock)
|
116
|
+
|
117
|
+
plum.on(:stream) { |stream|
|
118
|
+
headers = data = nil
|
119
|
+
stream.on(:headers) { |h|
|
120
|
+
headers = h.to_h }
|
121
|
+
stream.on(:data) { |d|
|
122
|
+
data = d }
|
123
|
+
stream.on(:end_stream) {
|
124
|
+
case headers[":path"]
|
125
|
+
when "/connection_error"
|
126
|
+
plum.goaway(:protocol_error)
|
127
|
+
when "/error_in_data"
|
128
|
+
stream.send_headers({ ":status" => 200 }, end_stream: false)
|
129
|
+
stream.send_data("a", end_stream: false)
|
130
|
+
raise ExampleError, "example error"
|
131
|
+
else
|
132
|
+
stream.send_headers({ ":status" => 200 }, end_stream: false)
|
133
|
+
stream.send_data(headers.to_h[":method"] + headers.to_h["header"].to_s + data.to_s, end_stream: true)
|
134
|
+
end } }
|
135
|
+
|
136
|
+
yield plum if block_given?
|
137
|
+
|
138
|
+
while !sock.closed? && !sock.eof?
|
139
|
+
plum << sock.readpartial(1024)
|
140
|
+
end
|
141
|
+
}
|
142
|
+
rescue OpenSSL::SSL::SSLError
|
143
|
+
rescue Timeout::Error
|
144
|
+
flunk "server timeout"
|
145
|
+
rescue ExampleError => e
|
146
|
+
plum.goaway(:internal_error) if plum
|
147
|
+
ensure
|
148
|
+
tcp_server.close
|
149
|
+
end
|
150
|
+
}
|
151
|
+
end
|
152
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
require "test_helper"
|
2
|
+
|
3
|
+
using Plum::BinaryString
|
4
|
+
class ClientConnectionTest < Minitest::Test
|
5
|
+
def test_open_stream
|
6
|
+
con = open_client_connection
|
7
|
+
stream = con.open_stream
|
8
|
+
assert(stream.id % 2 == 1, "Stream ID is not odd")
|
9
|
+
assert_equal(:idle, stream.state)
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,90 @@
|
|
1
|
+
require "test_helper"
|
2
|
+
|
3
|
+
using Plum::BinaryString
|
4
|
+
class LegacyClientSessionTest < Minitest::Test
|
5
|
+
def test_empty?
|
6
|
+
io = StringIO.new
|
7
|
+
session = LegacyClientSession.new(io, Client::DEFAULT_CONFIG)
|
8
|
+
assert(session.empty?)
|
9
|
+
res = session.request({}, "aa", {})
|
10
|
+
assert(!session.empty?)
|
11
|
+
io.string << "HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n"
|
12
|
+
session.succ
|
13
|
+
assert(res.finished?)
|
14
|
+
assert(session.empty?)
|
15
|
+
end
|
16
|
+
|
17
|
+
def test_close_fails_req
|
18
|
+
session = LegacyClientSession.new(StringIO.new, Client::DEFAULT_CONFIG)
|
19
|
+
res = session.request({}, nil, {})
|
20
|
+
assert(!res.failed?)
|
21
|
+
session.close
|
22
|
+
assert(res.failed?)
|
23
|
+
end
|
24
|
+
|
25
|
+
def test_fail
|
26
|
+
io = StringIO.new
|
27
|
+
session = LegacyClientSession.new(io, Client::DEFAULT_CONFIG)
|
28
|
+
res = session.request({}, "aa", {})
|
29
|
+
assert_raises {
|
30
|
+
session.succ
|
31
|
+
}
|
32
|
+
assert(!res.finished?)
|
33
|
+
assert(res.failed?)
|
34
|
+
end
|
35
|
+
|
36
|
+
def test_request
|
37
|
+
io = StringIO.new
|
38
|
+
session = LegacyClientSession.new(io, Client::DEFAULT_CONFIG.merge(hostname: "aa"))
|
39
|
+
res = session.request({ ":method" => "GET", ":path" => "/aa" }, "aa", {})
|
40
|
+
assert_equal("GET /aa HTTP/1.1\r\nhost: aa\r\ntransfer-encoding: chunked\r\n\r\n2\r\naa\r\n", io.string)
|
41
|
+
io.string << "HTTP/1.1 200 OK\r\nContent-Length: 3\r\n\r\naaa"
|
42
|
+
session.succ until res.finished?
|
43
|
+
assert(res.finished?)
|
44
|
+
assert_equal("aaa", res.body)
|
45
|
+
assert_equal({ ":status" => "200", "content-length" => "3" }, res.headers)
|
46
|
+
end
|
47
|
+
|
48
|
+
def test_chunked_chunked_string
|
49
|
+
io = StringIO.new
|
50
|
+
session = LegacyClientSession.new(io, Client::DEFAULT_CONFIG.merge(hostname: "hostname"))
|
51
|
+
res = session.request({ ":method" => "GET", ":path" => "/aa" }, "a" * 1025, {})
|
52
|
+
assert_equal(<<-EOR, io.string)
|
53
|
+
GET /aa HTTP/1.1\r
|
54
|
+
host: hostname\r
|
55
|
+
transfer-encoding: chunked\r
|
56
|
+
\r
|
57
|
+
401\r
|
58
|
+
#{"a"*1025}\r
|
59
|
+
EOR
|
60
|
+
end
|
61
|
+
|
62
|
+
def test_chunked_chunked_io
|
63
|
+
io = StringIO.new
|
64
|
+
session = LegacyClientSession.new(io, Client::DEFAULT_CONFIG.merge(hostname: "hostname"))
|
65
|
+
res = session.request({ ":method" => "GET", ":path" => "/aa" }, StringIO.new("a" * 1025), {})
|
66
|
+
assert_equal(<<-EOR, io.string)
|
67
|
+
GET /aa HTTP/1.1\r
|
68
|
+
host: hostname\r
|
69
|
+
transfer-encoding: chunked\r
|
70
|
+
\r
|
71
|
+
400\r
|
72
|
+
#{"a"*1024}\r
|
73
|
+
1\r
|
74
|
+
a\r
|
75
|
+
EOR
|
76
|
+
end
|
77
|
+
|
78
|
+
def test_chunked_sized
|
79
|
+
io = StringIO.new
|
80
|
+
session = LegacyClientSession.new(io, Client::DEFAULT_CONFIG.merge(hostname: "hostname"))
|
81
|
+
res = session.request({ ":method" => "GET", ":path" => "/aa", "content-length" => 1025 }, StringIO.new("a" * 1025), {})
|
82
|
+
assert_equal((<<-EOR).chomp, io.string)
|
83
|
+
GET /aa HTTP/1.1\r
|
84
|
+
content-length: 1025\r
|
85
|
+
host: hostname\r
|
86
|
+
\r
|
87
|
+
#{"a"*1025}
|
88
|
+
EOR
|
89
|
+
end
|
90
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
require "test_helper"
|
2
|
+
|
3
|
+
using Plum::BinaryString
|
4
|
+
class ResponseTest < Minitest::Test
|
5
|
+
def test_finished
|
6
|
+
resp = Response.new
|
7
|
+
assert_equal(false, resp.finished?)
|
8
|
+
resp._finish
|
9
|
+
assert_equal(true, resp.finished?)
|
10
|
+
end
|
11
|
+
|
12
|
+
def test_fail
|
13
|
+
resp = Response.new
|
14
|
+
resp._fail
|
15
|
+
assert(true, resp.failed?)
|
16
|
+
end
|
17
|
+
|
18
|
+
def test_status
|
19
|
+
resp = Response.new
|
20
|
+
resp._headers([
|
21
|
+
[":status", "200"]
|
22
|
+
])
|
23
|
+
assert_equal("200", resp.status)
|
24
|
+
end
|
25
|
+
|
26
|
+
def test_headers
|
27
|
+
resp = Response.new
|
28
|
+
resp._headers([
|
29
|
+
[":status", "200"],
|
30
|
+
["header", "abc"]
|
31
|
+
])
|
32
|
+
assert_equal("abc", resp[:HEADER])
|
33
|
+
end
|
34
|
+
|
35
|
+
def test_body
|
36
|
+
resp = Response.new
|
37
|
+
resp._chunk("a")
|
38
|
+
resp._chunk("b")
|
39
|
+
resp._finish
|
40
|
+
assert_equal("ab", resp.body)
|
41
|
+
end
|
42
|
+
|
43
|
+
def test_body_not_finished
|
44
|
+
resp = Response.new
|
45
|
+
resp._chunk("a")
|
46
|
+
resp._chunk("b")
|
47
|
+
assert_raises { # TODO
|
48
|
+
resp.body
|
49
|
+
}
|
50
|
+
end
|
51
|
+
|
52
|
+
def test_on_chunk
|
53
|
+
resp = Response.new
|
54
|
+
res = []
|
55
|
+
resp._chunk("a")
|
56
|
+
resp._chunk("b")
|
57
|
+
resp._finish
|
58
|
+
resp.on_chunk { |chunk| res << chunk }
|
59
|
+
assert_equal(["a", "b"], res)
|
60
|
+
resp._chunk("c")
|
61
|
+
assert_equal(["a", "b", "c"], res)
|
62
|
+
end
|
63
|
+
|
64
|
+
def test_on_finish
|
65
|
+
resp = Response.new
|
66
|
+
ran = false
|
67
|
+
resp.on_finish { ran = true }
|
68
|
+
resp._finish
|
69
|
+
assert(ran)
|
70
|
+
ran = false
|
71
|
+
resp.on_finish { ran = true }
|
72
|
+
assert(ran)
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require "test_helper"
|
2
|
+
|
3
|
+
using Plum::BinaryString
|
4
|
+
class UpgradeClientSessionTest < Minitest::Test
|
5
|
+
def test_empty?
|
6
|
+
sock = StringSocket.new("HTTP/1.1 101\r\n\r\n")
|
7
|
+
session = UpgradeClientSession.new(sock, Client::DEFAULT_CONFIG)
|
8
|
+
assert(sock.wio.string.start_with?("OPTIONS * HTTP/1.1\r\n"), "sends options request")
|
9
|
+
assert(session.empty?)
|
10
|
+
end
|
11
|
+
|
12
|
+
def test_close
|
13
|
+
sock = StringSocket.new("HTTP/1.1 101\r\n\r\n")
|
14
|
+
session = UpgradeClientSession.new(sock, Client::DEFAULT_CONFIG)
|
15
|
+
res = session.request({}, nil, {})
|
16
|
+
assert(!res.failed?)
|
17
|
+
session.close
|
18
|
+
assert(res.failed?)
|
19
|
+
end
|
20
|
+
|
21
|
+
def test_request
|
22
|
+
sock = StringSocket.new("HTTP/1.1 101\r\n\r\n")
|
23
|
+
session = UpgradeClientSession.new(sock, Client::DEFAULT_CONFIG)
|
24
|
+
sock.rio.string << Frame.settings().assemble
|
25
|
+
sock.rio.string << Frame.settings(:ack).assemble
|
26
|
+
res = session.request({ ":method" => "GET", ":path" => "/aa" }, "aa", {})
|
27
|
+
sock.rio.string << Frame.headers(3, HPACK::Encoder.new(3).encode(":status" => "200", "content-length" => "3"), :end_headers).assemble
|
28
|
+
sock.rio.string << Frame.data(3, "aaa", :end_stream).assemble
|
29
|
+
session.succ until res.finished?
|
30
|
+
assert(res.finished?)
|
31
|
+
assert_equal("aaa", res.body)
|
32
|
+
assert_equal({ ":status" => "200", "content-length" => "3" }, res.headers)
|
33
|
+
end
|
34
|
+
|
35
|
+
def test_request_legacy
|
36
|
+
sock = StringSocket.new("HTTP/1.1 200\r\nContent-Length: 0\r\n\r\n")
|
37
|
+
session = UpgradeClientSession.new(sock, Client::DEFAULT_CONFIG)
|
38
|
+
res = session.request({ ":method" => "GET", ":path" => "/aa" }, "aa", {})
|
39
|
+
sock.rio.string << "HTTP/1.1 200 OK\r\nContent-Length: 3\r\n\r\naaaHTTP/1.1 400\r\nnext-response"
|
40
|
+
session.succ until res.finished?
|
41
|
+
assert(res.finished?)
|
42
|
+
assert_equal("aaa", res.body)
|
43
|
+
assert_equal({ ":status" => "200", "content-length" => "3" }, res.headers)
|
44
|
+
end
|
45
|
+
end
|
@@ -62,7 +62,10 @@ class ServerConnectionHandleFrameTest < Minitest::Test
|
|
62
62
|
def test_server_handle_goaway_reply
|
63
63
|
open_server_connection {|con|
|
64
64
|
assert_no_error {
|
65
|
-
|
65
|
+
begin
|
66
|
+
con << Frame.goaway(1, :stream_closed).assemble
|
67
|
+
rescue LocalHTTPError
|
68
|
+
end
|
66
69
|
}
|
67
70
|
assert_equal(:goaway, sent_frames.last.type)
|
68
71
|
}
|
@@ -5,7 +5,7 @@ using Plum::BinaryString
|
|
5
5
|
class HTTPConnectionNegotiationTest < Minitest::Test
|
6
6
|
## with Prior Knowledge (same as over TLS)
|
7
7
|
def test_server_must_raise_cprotocol_error_non_settings_after_magic
|
8
|
-
con =
|
8
|
+
con = HTTPServerConnection.new(StringIO.new)
|
9
9
|
con << Connection::CLIENT_CONNECTION_PREFACE
|
10
10
|
assert_connection_error(:protocol_error) {
|
11
11
|
con << Frame.new(type: :window_update, stream_id: 0, payload: "".push_uint32(1)).assemble
|
@@ -14,7 +14,7 @@ class HTTPConnectionNegotiationTest < Minitest::Test
|
|
14
14
|
|
15
15
|
def test_server_accept_fragmented_magic
|
16
16
|
magic = Connection::CLIENT_CONNECTION_PREFACE
|
17
|
-
con =
|
17
|
+
con = HTTPServerConnection.new(StringIO.new)
|
18
18
|
assert_no_error {
|
19
19
|
con << magic[0...5]
|
20
20
|
con << magic[5..-1]
|
@@ -25,7 +25,7 @@ class HTTPConnectionNegotiationTest < Minitest::Test
|
|
25
25
|
## with HTTP/1.1 Upgrade
|
26
26
|
def test_server_accept_upgrade
|
27
27
|
io = StringIO.new
|
28
|
-
con =
|
28
|
+
con = HTTPServerConnection.new(io)
|
29
29
|
heads = nil
|
30
30
|
con.on(:headers) {|_, _h| heads = _h.to_h }
|
31
31
|
req = "GET / HTTP/1.1\r\n" <<
|
@@ -47,7 +47,7 @@ class HTTPConnectionNegotiationTest < Minitest::Test
|
|
47
47
|
|
48
48
|
def test_server_deny_non_upgrade
|
49
49
|
io = StringIO.new
|
50
|
-
con =
|
50
|
+
con = HTTPServerConnection.new(io)
|
51
51
|
req = "GET / HTTP/1.1\r\n" <<
|
52
52
|
"Host: rhe.jp\r\n" <<
|
53
53
|
"User-Agent: nya\r\n" <<
|
@@ -4,21 +4,21 @@ using Plum::BinaryString
|
|
4
4
|
|
5
5
|
class HTTPSConnectionNegotiationTest < Minitest::Test
|
6
6
|
def test_server_must_raise_cprotocol_error_invalid_magic_short
|
7
|
-
con =
|
7
|
+
con = HTTPSServerConnection.new(StringIO.new)
|
8
8
|
assert_connection_error(:protocol_error) {
|
9
9
|
con << "HELLO"
|
10
10
|
}
|
11
11
|
end
|
12
12
|
|
13
13
|
def test_server_must_raise_cprotocol_error_invalid_magic_long
|
14
|
-
con =
|
14
|
+
con = HTTPSServerConnection.new(StringIO.new)
|
15
15
|
assert_connection_error(:protocol_error) {
|
16
16
|
con << ("HELLO" * 100) # over 24
|
17
17
|
}
|
18
18
|
end
|
19
19
|
|
20
20
|
def test_server_must_raise_cprotocol_error_non_settings_after_magic
|
21
|
-
con =
|
21
|
+
con = HTTPSServerConnection.new(StringIO.new)
|
22
22
|
con << Connection::CLIENT_CONNECTION_PREFACE
|
23
23
|
assert_connection_error(:protocol_error) {
|
24
24
|
con << Frame.new(type: :window_update, stream_id: 0, payload: "".push_uint32(1)).assemble
|
@@ -27,7 +27,7 @@ class HTTPSConnectionNegotiationTest < Minitest::Test
|
|
27
27
|
|
28
28
|
def test_server_accept_fragmented_magic
|
29
29
|
magic = Connection::CLIENT_CONNECTION_PREFACE
|
30
|
-
con =
|
30
|
+
con = HTTPSServerConnection.new(StringIO.new)
|
31
31
|
assert_no_error {
|
32
32
|
con << magic[0...5]
|
33
33
|
con << magic[5..-1]
|
@@ -40,8 +40,8 @@ class HTTPSConnectionNegotiationTest < Minitest::Test
|
|
40
40
|
|
41
41
|
ctx = OpenSSL::SSL::SSLContext.new
|
42
42
|
ctx.alpn_select_cb = -> protocols { "h2" }
|
43
|
-
ctx.cert =
|
44
|
-
ctx.key =
|
43
|
+
ctx.cert = TLS_CERT
|
44
|
+
ctx.key = TLS_KEY
|
45
45
|
tcp_server = TCPServer.new("127.0.0.1", LISTEN_PORT)
|
46
46
|
ssl_server = OpenSSL::SSL::SSLServer.new(tcp_server, ctx)
|
47
47
|
|
@@ -49,14 +49,18 @@ class HTTPSConnectionNegotiationTest < Minitest::Test
|
|
49
49
|
begin
|
50
50
|
Timeout.timeout(3) {
|
51
51
|
sock = ssl_server.accept
|
52
|
-
plum =
|
52
|
+
plum = HTTPSServerConnection.new(sock)
|
53
53
|
assert_connection_error(:inadequate_security) {
|
54
54
|
run = true
|
55
|
-
|
55
|
+
while !sock.closed? && !sock.eof?
|
56
|
+
plum << sock.readpartial(1024)
|
57
|
+
end
|
56
58
|
}
|
57
59
|
}
|
58
60
|
rescue Timeout::Error
|
59
61
|
flunk "server timeout"
|
62
|
+
rescue => e
|
63
|
+
flunk e
|
60
64
|
ensure
|
61
65
|
tcp_server.close
|
62
66
|
end
|
@@ -73,6 +77,8 @@ class HTTPSConnectionNegotiationTest < Minitest::Test
|
|
73
77
|
ssl.write Connection::CLIENT_CONNECTION_PREFACE
|
74
78
|
ssl.write Frame.settings.assemble
|
75
79
|
sleep
|
80
|
+
rescue => e
|
81
|
+
flunk e
|
76
82
|
ensure
|
77
83
|
sock.close
|
78
84
|
end
|