plum 0.1.3 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|