polyphony 0.13 → 0.14
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/.gitbook.yaml +5 -0
- data/.gitignore +55 -0
- data/.rubocop.yml +49 -0
- data/CHANGELOG.md +13 -2
- data/Gemfile +3 -0
- data/Gemfile.lock +31 -0
- data/LICENSE +21 -0
- data/README.md +35 -18
- data/Rakefile +20 -0
- data/TODO.md +49 -0
- data/docs/getting-started/getting-started.md +10 -0
- data/docs/getting-started/tutorial.md +2 -0
- data/docs/summary.md +9 -0
- data/examples/core/cancel.rb +10 -0
- data/examples/core/channel_echo.rb +43 -0
- data/examples/core/enumerator.rb +14 -0
- data/examples/core/fork.rb +22 -0
- data/examples/core/genserver.rb +74 -0
- data/examples/core/lock.rb +20 -0
- data/examples/core/move_on.rb +11 -0
- data/examples/core/move_on_twice.rb +17 -0
- data/examples/core/move_on_with_ensure.rb +17 -0
- data/examples/core/multiple_async.rb +17 -0
- data/examples/core/nested_async.rb +18 -0
- data/examples/core/nested_cancel.rb +41 -0
- data/examples/core/nested_multiple_async.rb +19 -0
- data/examples/core/next_tick.rb +13 -0
- data/examples/core/pulse.rb +13 -0
- data/examples/core/resource.rb +29 -0
- data/examples/core/resource_cancel.rb +34 -0
- data/examples/core/resource_delegate.rb +32 -0
- data/examples/core/sleep.rb +9 -0
- data/examples/core/sleep2.rb +13 -0
- data/examples/core/spawn.rb +15 -0
- data/examples/core/spawn_cancel.rb +19 -0
- data/examples/core/spawn_error.rb +28 -0
- data/examples/core/supervisor.rb +22 -0
- data/examples/core/supervisor_with_cancel_scope.rb +24 -0
- data/examples/core/supervisor_with_error.rb +23 -0
- data/examples/core/supervisor_with_manual_move_on.rb +25 -0
- data/examples/core/thread.rb +30 -0
- data/examples/core/thread_cancel.rb +30 -0
- data/examples/core/thread_pool.rb +60 -0
- data/examples/core/throttle.rb +17 -0
- data/examples/fs/read.rb +37 -0
- data/examples/interfaces/pg_client.rb +38 -0
- data/examples/interfaces/pg_pool.rb +37 -0
- data/examples/interfaces/pg_query.rb +32 -0
- data/examples/interfaces/redis_channels.rb +119 -0
- data/examples/interfaces/redis_client.rb +21 -0
- data/examples/interfaces/redis_pubsub.rb +26 -0
- data/examples/interfaces/redis_pubsub_perf.rb +65 -0
- data/examples/io/config.ru +3 -0
- data/examples/io/echo_client.rb +22 -0
- data/examples/io/echo_server.rb +14 -0
- data/examples/io/echo_server_with_timeout.rb +33 -0
- data/examples/io/echo_stdin.rb +15 -0
- data/examples/io/happy_eyeballs.rb +32 -0
- data/examples/io/http_client.rb +19 -0
- data/examples/io/http_server.js +24 -0
- data/examples/io/http_server.rb +16 -0
- data/examples/io/http_server_forked.rb +27 -0
- data/examples/io/http_server_throttled.rb +16 -0
- data/examples/io/http_ws_server.rb +42 -0
- data/examples/io/https_client.rb +17 -0
- data/examples/io/https_server.rb +23 -0
- data/examples/io/https_wss_server.rb +46 -0
- data/examples/io/rack_server.rb +19 -0
- data/examples/io/rack_server_https.rb +24 -0
- data/examples/io/rack_server_https_forked.rb +32 -0
- data/examples/io/websocket_server.rb +33 -0
- data/examples/io/ws_page.html +34 -0
- data/examples/io/wss_page.html +34 -0
- data/examples/performance/perf_multi_snooze.rb +21 -0
- data/examples/performance/perf_snooze.rb +30 -0
- data/examples/performance/thread-vs-fiber/polyphony_server.rb +63 -0
- data/examples/performance/thread-vs-fiber/threaded_server.rb +27 -0
- data/examples/streams/lines.rb +27 -0
- data/examples/streams/stdio.rb +18 -0
- data/ext/ev/async.c +168 -0
- data/ext/ev/child.c +169 -0
- data/ext/ev/ev.h +32 -0
- data/ext/ev/ev_ext.c +20 -0
- data/ext/ev/ev_module.c +222 -0
- data/ext/ev/io.c +405 -0
- data/ext/ev/libev.h +9 -0
- data/ext/ev/signal.c +119 -0
- data/ext/ev/timer.c +197 -0
- data/ext/libev/Changes +513 -0
- data/ext/libev/LICENSE +37 -0
- data/ext/libev/README +58 -0
- data/ext/libev/README.embed +3 -0
- data/ext/libev/ev.c +5214 -0
- data/ext/libev/ev.h +849 -0
- data/ext/libev/ev_epoll.c +285 -0
- data/ext/libev/ev_kqueue.c +218 -0
- data/ext/libev/ev_poll.c +151 -0
- data/ext/libev/ev_port.c +189 -0
- data/ext/libev/ev_select.c +316 -0
- data/ext/libev/ev_vars.h +204 -0
- data/ext/libev/ev_win32.c +162 -0
- data/ext/libev/ev_wrap.h +200 -0
- data/ext/libev/test_libev_win32.c +123 -0
- data/lib/polyphony.rb +7 -2
- data/lib/polyphony/core.rb +1 -1
- data/lib/polyphony/core/{coroutine.rb → coprocess.rb} +10 -10
- data/lib/polyphony/core/exceptions.rb +5 -5
- data/lib/polyphony/core/supervisor.rb +16 -16
- data/lib/polyphony/core/thread.rb +1 -1
- data/lib/polyphony/extensions/io.rb +43 -42
- data/lib/polyphony/extensions/kernel.rb +10 -34
- data/lib/polyphony/extensions/postgres.rb +3 -2
- data/lib/polyphony/extensions/redis.rb +1 -1
- data/lib/polyphony/extensions/socket.rb +8 -4
- data/lib/polyphony/extensions/ssl.rb +0 -54
- data/lib/polyphony/http/agent.rb +4 -10
- data/lib/polyphony/http/http1.rb +25 -25
- data/lib/polyphony/http/http1_request.rb +38 -26
- data/lib/polyphony/http/http2.rb +4 -5
- data/lib/polyphony/http/http2_request.rb +12 -18
- data/lib/polyphony/http/rack.rb +1 -3
- data/lib/polyphony/http/server.rb +9 -9
- data/lib/polyphony/net.rb +2 -2
- data/lib/polyphony/resource_pool.rb +5 -1
- data/lib/polyphony/version.rb +1 -1
- data/lib/polyphony/websocket.rb +52 -0
- data/polyphony.gemspec +31 -0
- data/test/test_coprocess.rb +131 -0
- data/test/test_core.rb +274 -0
- data/test/test_ev.rb +117 -0
- data/test/test_io.rb +38 -0
- metadata +113 -7
- data/lib/polyphony/core/async.rb +0 -36
- data/lib/polyphony/net_old.rb +0 -299
|
@@ -56,9 +56,10 @@ class ::PG::Connection
|
|
|
56
56
|
alias_method :orig_async_exec, :async_exec
|
|
57
57
|
def async_exec(*args, &block)
|
|
58
58
|
send_query(*args)
|
|
59
|
-
|
|
59
|
+
get_result(&block)
|
|
60
|
+
ensure
|
|
61
|
+
# cleanup result in order to allow next query
|
|
60
62
|
while get_result; end
|
|
61
|
-
result
|
|
62
63
|
end
|
|
63
64
|
|
|
64
65
|
def block(timeout = 0)
|
|
@@ -5,9 +5,11 @@ require 'socket'
|
|
|
5
5
|
import('./io')
|
|
6
6
|
|
|
7
7
|
class ::Socket
|
|
8
|
+
NO_EXCEPTION = { exception: false }.freeze
|
|
9
|
+
|
|
8
10
|
def accept
|
|
9
11
|
loop do
|
|
10
|
-
result, client_addr = accept_nonblock(
|
|
12
|
+
result, client_addr = accept_nonblock(NO_EXCEPTION)
|
|
11
13
|
case result
|
|
12
14
|
when Socket then return result
|
|
13
15
|
when :wait_readable then read_watcher.await
|
|
@@ -21,7 +23,7 @@ class ::Socket
|
|
|
21
23
|
|
|
22
24
|
def connect(remotesockaddr)
|
|
23
25
|
loop do
|
|
24
|
-
result = connect_nonblock(remotesockaddr,
|
|
26
|
+
result = connect_nonblock(remotesockaddr, NO_EXCEPTION)
|
|
25
27
|
case result
|
|
26
28
|
when 0 then return
|
|
27
29
|
when :wait_writable then write_watcher.await
|
|
@@ -35,7 +37,7 @@ class ::Socket
|
|
|
35
37
|
def recvfrom(maxlen, flags = 0)
|
|
36
38
|
@read_buffer ||= +''
|
|
37
39
|
loop do
|
|
38
|
-
result = recvfrom_nonblock(maxlen, flags, @read_buffer,
|
|
40
|
+
result = recvfrom_nonblock(maxlen, flags, @read_buffer, NO_EXCEPTION)
|
|
39
41
|
case result
|
|
40
42
|
when nil then raise IOError
|
|
41
43
|
when :wait_readable then read_watcher.await
|
|
@@ -69,9 +71,11 @@ class ::Socket
|
|
|
69
71
|
end
|
|
70
72
|
|
|
71
73
|
class ::TCPServer
|
|
74
|
+
NO_EXCEPTION = { exception: false }.freeze
|
|
75
|
+
|
|
72
76
|
def accept
|
|
73
77
|
loop do
|
|
74
|
-
result, client_addr = accept_nonblock(
|
|
78
|
+
result, client_addr = accept_nonblock(NO_EXCEPTION)
|
|
75
79
|
case result
|
|
76
80
|
when TCPSocket then return result
|
|
77
81
|
when :wait_readable then read_watcher.await
|
|
@@ -5,60 +5,6 @@ require 'openssl'
|
|
|
5
5
|
import('./socket')
|
|
6
6
|
|
|
7
7
|
class ::OpenSSL::SSL::SSLSocket
|
|
8
|
-
def accept
|
|
9
|
-
loop do
|
|
10
|
-
result = accept_nonblock(::IO::NO_EXCEPTION)
|
|
11
|
-
case result
|
|
12
|
-
when :wait_readable then io.read_watcher.await
|
|
13
|
-
when :wait_writable then io.write_watcher.await
|
|
14
|
-
else return true
|
|
15
|
-
end
|
|
16
|
-
end
|
|
17
|
-
ensure
|
|
18
|
-
io.stop_watchers
|
|
19
|
-
end
|
|
20
|
-
|
|
21
|
-
def connect
|
|
22
|
-
loop do
|
|
23
|
-
result = connect_nonblock(::IO::NO_EXCEPTION)
|
|
24
|
-
case result
|
|
25
|
-
when :wait_readable then io.read_watcher.await
|
|
26
|
-
when :wait_writable then io.write_watcher.await
|
|
27
|
-
else return true
|
|
28
|
-
end
|
|
29
|
-
end
|
|
30
|
-
ensure
|
|
31
|
-
io.stop_watchers
|
|
32
|
-
end
|
|
33
|
-
|
|
34
|
-
def read(max = 8192)
|
|
35
|
-
@read_buffer ||= +''
|
|
36
|
-
loop do
|
|
37
|
-
result = read_nonblock(max, @read_buffer, ::IO::NO_EXCEPTION)
|
|
38
|
-
case result
|
|
39
|
-
when nil then raise ::IOError
|
|
40
|
-
when :wait_readable then io.read_watcher.await
|
|
41
|
-
else return result
|
|
42
|
-
end
|
|
43
|
-
end
|
|
44
|
-
ensure
|
|
45
|
-
io.stop_watchers
|
|
46
|
-
end
|
|
47
|
-
|
|
48
|
-
def write(data)
|
|
49
|
-
loop do
|
|
50
|
-
result = write_nonblock(data, ::IO::NO_EXCEPTION)
|
|
51
|
-
case result
|
|
52
|
-
when nil then raise ::IOError
|
|
53
|
-
when :wait_writable then io.write_watcher.await
|
|
54
|
-
else
|
|
55
|
-
(result == data.bytesize) ? (return result) : (data = data[result..-1])
|
|
56
|
-
end
|
|
57
|
-
end
|
|
58
|
-
ensure
|
|
59
|
-
io.stop_watchers
|
|
60
|
-
end
|
|
61
|
-
|
|
62
8
|
def dont_linger
|
|
63
9
|
io.dont_linger
|
|
64
10
|
end
|
data/lib/polyphony/http/agent.rb
CHANGED
|
@@ -47,8 +47,6 @@ class Agent
|
|
|
47
47
|
request(url, method: :POST, query: query)
|
|
48
48
|
end
|
|
49
49
|
|
|
50
|
-
S_LOCATION = 'Location'
|
|
51
|
-
|
|
52
50
|
OPTS_DEFAULT = {}.freeze
|
|
53
51
|
|
|
54
52
|
def request(url, opts = OPTS_DEFAULT)
|
|
@@ -57,7 +55,7 @@ class Agent
|
|
|
57
55
|
|
|
58
56
|
case response[:status_code]
|
|
59
57
|
when 301, 302
|
|
60
|
-
request(response[:headers][
|
|
58
|
+
request(response[:headers]['Location'])
|
|
61
59
|
when 200, 204
|
|
62
60
|
response.extend(ResponseMixin)
|
|
63
61
|
else
|
|
@@ -99,10 +97,8 @@ class Agent
|
|
|
99
97
|
end
|
|
100
98
|
end
|
|
101
99
|
|
|
102
|
-
S_H2 = 'h2'
|
|
103
|
-
|
|
104
100
|
def protocol_method(socket, ctx)
|
|
105
|
-
if socket.is_a?(::OpenSSL::SSL::SSLSocket) && (socket.alpn_protocol ==
|
|
101
|
+
if socket.is_a?(::OpenSSL::SSL::SSLSocket) && (socket.alpn_protocol == 'h2')
|
|
106
102
|
:do_http2
|
|
107
103
|
else
|
|
108
104
|
:do_http1
|
|
@@ -195,15 +191,13 @@ class Agent
|
|
|
195
191
|
}
|
|
196
192
|
end
|
|
197
193
|
|
|
198
|
-
S_HTTP = 'http'
|
|
199
|
-
S_HTTPS = 'https'
|
|
200
194
|
SECURE_OPTS = { secure: true, alpn_protocols: ['h2', 'http/1.1'] }
|
|
201
195
|
|
|
202
196
|
def connect(key)
|
|
203
197
|
case key[:scheme]
|
|
204
|
-
when
|
|
198
|
+
when 'http'
|
|
205
199
|
Polyphony::Net.tcp_connect(key[:host], key[:port])
|
|
206
|
-
when
|
|
200
|
+
when 'https'
|
|
207
201
|
Polyphony::Net.tcp_connect(key[:host], key[:port], SECURE_OPTS).tap do |socket|
|
|
208
202
|
socket.post_connection_check(key[:host])
|
|
209
203
|
end
|
data/lib/polyphony/http/http1.rb
CHANGED
|
@@ -26,12 +26,13 @@ end
|
|
|
26
26
|
# @param socket [Net::Socket] socket
|
|
27
27
|
# @param handler [Proc] request handler
|
|
28
28
|
# @return [void]
|
|
29
|
-
def run(socket, handler)
|
|
30
|
-
ctx = connection_context(socket, handler)
|
|
29
|
+
def run(socket, opts, handler)
|
|
30
|
+
ctx = connection_context(socket, opts, handler)
|
|
31
31
|
ctx[:parser].on_body = proc { |chunk| handle_body_chunk(ctx, chunk) }
|
|
32
32
|
|
|
33
33
|
loop do
|
|
34
|
-
data = socket.
|
|
34
|
+
data = socket.readpartial(8192)
|
|
35
|
+
break unless data
|
|
35
36
|
if ctx[:parser].parse(data)
|
|
36
37
|
break unless handle_request(ctx)
|
|
37
38
|
EV.snooze
|
|
@@ -48,15 +49,15 @@ end
|
|
|
48
49
|
# @param socket [Net::Socket] socket
|
|
49
50
|
# @param handler [Proc] request handler
|
|
50
51
|
# @return [Hash]
|
|
51
|
-
def connection_context(socket, handler)
|
|
52
|
+
def connection_context(socket, opts, handler)
|
|
52
53
|
{
|
|
53
54
|
can_upgrade: true,
|
|
55
|
+
upgrade: opts[:upgrade],
|
|
54
56
|
count: 0,
|
|
55
57
|
socket: socket,
|
|
56
58
|
handler: handler,
|
|
57
59
|
parser: Http::Parser.new.async!,
|
|
58
|
-
body: nil
|
|
59
|
-
request: Request.new
|
|
60
|
+
body: nil
|
|
60
61
|
}
|
|
61
62
|
end
|
|
62
63
|
|
|
@@ -77,8 +78,8 @@ def handle_request(ctx)
|
|
|
77
78
|
|
|
78
79
|
# allow upgrading the connection only on first request
|
|
79
80
|
ctx[:can_upgrade] = false
|
|
80
|
-
|
|
81
|
-
ctx[:handler].(
|
|
81
|
+
request = Request.new(ctx[:socket], ctx[:parser], ctx[:body])
|
|
82
|
+
ctx[:handler].(request)
|
|
82
83
|
|
|
83
84
|
if ctx[:parser].keep_alive?
|
|
84
85
|
ctx[:body] = nil
|
|
@@ -88,24 +89,23 @@ def handle_request(ctx)
|
|
|
88
89
|
end
|
|
89
90
|
end
|
|
90
91
|
|
|
91
|
-
|
|
92
|
-
S_UPGRADE = 'Upgrade'
|
|
93
|
-
S_H2C = 'h2c'
|
|
94
|
-
S_SCHEME = ':scheme'
|
|
95
|
-
S_METHOD = ':method'
|
|
96
|
-
S_AUTHORITY = ':authority'
|
|
97
|
-
S_PATH = ':path'
|
|
98
|
-
S_HTTP = 'http'
|
|
99
|
-
S_HOST = 'Host'
|
|
100
|
-
|
|
101
|
-
# Upgrades an HTTP 1 connection to HTTP 2 on client request
|
|
92
|
+
# Upgrades an HTTP 1 connection to HTTP/2 or other protocol on client request
|
|
102
93
|
# @param ctx [Hash] connection context
|
|
103
94
|
# @return [Boolean] true if connection was upgraded
|
|
104
95
|
def upgrade_connection(ctx)
|
|
105
|
-
|
|
96
|
+
upgrade_protocol = ctx[:parser].headers['Upgrade']
|
|
97
|
+
return false unless upgrade_protocol
|
|
106
98
|
|
|
99
|
+
if ctx[:upgrade] && ctx[:upgrade][upgrade_protocol.to_sym]
|
|
100
|
+
ctx[:upgrade][upgrade_protocol.to_sym].(ctx[:socket], ctx[:parser].headers)
|
|
101
|
+
return true
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
return false unless upgrade_protocol == 'h2c'
|
|
105
|
+
|
|
106
|
+
# upgrade to HTTP/2
|
|
107
107
|
request = http2_upgraded_request(ctx)
|
|
108
|
-
body = ctx[:body] ||
|
|
108
|
+
body = ctx[:body] || ''
|
|
109
109
|
HTTP2.upgrade(ctx[:socket], ctx[:handler], request, body)
|
|
110
110
|
true
|
|
111
111
|
end
|
|
@@ -116,9 +116,9 @@ end
|
|
|
116
116
|
def http2_upgraded_request(ctx)
|
|
117
117
|
headers = ctx[:parser].headers
|
|
118
118
|
headers.merge(
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
119
|
+
':scheme' => 'http',
|
|
120
|
+
':method' => ctx[:parser].http_method,
|
|
121
|
+
':authority' => headers['Host'],
|
|
122
|
+
':path' => ctx[:parser].request_url
|
|
123
123
|
)
|
|
124
124
|
end
|
|
@@ -5,35 +5,34 @@ export_default :Request
|
|
|
5
5
|
require 'uri'
|
|
6
6
|
|
|
7
7
|
class Request
|
|
8
|
-
def
|
|
8
|
+
def initialize(conn, parser, body)
|
|
9
9
|
@conn = conn
|
|
10
|
-
@parser
|
|
10
|
+
@parser = parser
|
|
11
11
|
@method = parser.http_method
|
|
12
12
|
@request_url = parser.request_url
|
|
13
13
|
@body = body
|
|
14
14
|
end
|
|
15
15
|
|
|
16
|
+
def http_version
|
|
17
|
+
1
|
|
18
|
+
end
|
|
19
|
+
|
|
16
20
|
def method
|
|
17
21
|
@method ||= @parser.http_method
|
|
18
22
|
end
|
|
19
23
|
|
|
20
|
-
S_EMPTY = ''
|
|
21
|
-
|
|
22
24
|
def path
|
|
23
|
-
@uri ||= URI.parse(@parser.request_url ||
|
|
25
|
+
@uri ||= URI.parse(@parser.request_url || '')
|
|
24
26
|
@path ||= @uri.path
|
|
25
27
|
end
|
|
26
28
|
|
|
27
|
-
S_AMPERSAND = '&'
|
|
28
|
-
S_EQUAL = '='
|
|
29
|
-
|
|
30
29
|
def query
|
|
31
|
-
@uri ||= URI.parse(@parser.request_url ||
|
|
30
|
+
@uri ||= URI.parse(@parser.request_url || '')
|
|
32
31
|
return @query if @query
|
|
33
32
|
|
|
34
|
-
if (q =
|
|
35
|
-
@query = q.split(
|
|
36
|
-
k, v = kv.split(
|
|
33
|
+
if (q = @uri.query)
|
|
34
|
+
@query = q.split('&').each_with_object({}) do |kv, h|
|
|
35
|
+
k, v = kv.split('=')
|
|
37
36
|
h[k.to_sym] = URI.decode_www_form_component(v)
|
|
38
37
|
end
|
|
39
38
|
else
|
|
@@ -45,27 +44,40 @@ class Request
|
|
|
45
44
|
@headers ||= @parser.headers
|
|
46
45
|
end
|
|
47
46
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
47
|
+
EMPTY_HASH = {}
|
|
48
|
+
|
|
49
|
+
def respond(chunk, headers = EMPTY_HASH)
|
|
50
|
+
status = headers.delete(':status') || 200
|
|
51
|
+
data = format_head(headers)
|
|
52
|
+
if chunk
|
|
53
|
+
data << "#{chunk.bytesize.to_s(16)}\r\n#{chunk}\r\n0\r\n\r\n"
|
|
54
|
+
end
|
|
55
|
+
@conn << data
|
|
56
|
+
end
|
|
51
57
|
|
|
52
|
-
def
|
|
53
|
-
status = headers
|
|
54
|
-
data = +"HTTP/1.1 #{status}\r\n"
|
|
55
|
-
headers[S_CONTENT_LENGTH] = body.bytesize if body
|
|
58
|
+
def format_head(headers)
|
|
59
|
+
status = headers[':status'] || 200
|
|
60
|
+
data = +"HTTP/1.1 #{status}\r\nTransfer-Encoding: chunked\r\n"
|
|
56
61
|
headers.each do |k, v|
|
|
62
|
+
next if k =~ /^:/
|
|
57
63
|
if v.is_a?(Array)
|
|
58
|
-
v.each { |
|
|
64
|
+
v.each { |o| data << "#{k}: #{o}\r\n" }
|
|
59
65
|
else
|
|
60
66
|
data << "#{k}: #{v}\r\n"
|
|
61
67
|
end
|
|
62
68
|
end
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
else
|
|
66
|
-
data << EMPTY_LINE
|
|
67
|
-
end
|
|
69
|
+
data << "\r\n"
|
|
70
|
+
end
|
|
68
71
|
|
|
69
|
-
|
|
72
|
+
def write_head(headers = EMPTY_HASH)
|
|
73
|
+
@conn << format_head(headers)
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def write(chunk)
|
|
77
|
+
data = +"#{chunk.bytesize.to_s(16)}\r\n#{chunk}\r\n"
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def finish
|
|
81
|
+
@conn << "0\r\n\r\n"
|
|
70
82
|
end
|
|
71
83
|
end
|
data/lib/polyphony/http/http2.rb
CHANGED
|
@@ -6,8 +6,6 @@ require 'http/2'
|
|
|
6
6
|
|
|
7
7
|
Request = import('./http2_request')
|
|
8
8
|
|
|
9
|
-
S_HTTP2_SETTINGS = 'HTTP2-Settings'
|
|
10
|
-
|
|
11
9
|
UPGRADE_MESSAGE = <<~HTTP.gsub("\n", "\r\n")
|
|
12
10
|
HTTP/1.1 101 Switching Protocols
|
|
13
11
|
Connection: Upgrade
|
|
@@ -17,7 +15,7 @@ HTTP
|
|
|
17
15
|
|
|
18
16
|
def upgrade(socket, handler, request, body)
|
|
19
17
|
interface = prepare(socket, handler)
|
|
20
|
-
settings = request[
|
|
18
|
+
settings = request['HTTP2-Settings']
|
|
21
19
|
socket.write(UPGRADE_MESSAGE)
|
|
22
20
|
interface.upgrade(settings, request, body)
|
|
23
21
|
client_loop(socket, interface)
|
|
@@ -30,14 +28,15 @@ def prepare(socket, handler)
|
|
|
30
28
|
end
|
|
31
29
|
end
|
|
32
30
|
|
|
33
|
-
def run(socket, handler)
|
|
31
|
+
def run(socket, opts, handler)
|
|
34
32
|
interface = prepare(socket, handler)
|
|
35
33
|
client_loop(socket, interface)
|
|
36
34
|
end
|
|
37
35
|
|
|
38
36
|
def client_loop(socket, interface)
|
|
39
37
|
loop do
|
|
40
|
-
data = socket.
|
|
38
|
+
data = socket.readpartial(8192)
|
|
39
|
+
break unless data
|
|
41
40
|
interface << data
|
|
42
41
|
EV.snooze
|
|
43
42
|
end
|
|
@@ -9,6 +9,10 @@ class Request
|
|
|
9
9
|
@stream = stream
|
|
10
10
|
end
|
|
11
11
|
|
|
12
|
+
def http_version
|
|
13
|
+
2
|
|
14
|
+
end
|
|
15
|
+
|
|
12
16
|
def set_headers(headers)
|
|
13
17
|
@headers = Hash[*headers.flatten]
|
|
14
18
|
end
|
|
@@ -21,33 +25,26 @@ class Request
|
|
|
21
25
|
end
|
|
22
26
|
end
|
|
23
27
|
|
|
24
|
-
S_METHOD = ':method'
|
|
25
|
-
|
|
26
28
|
def method
|
|
27
|
-
@method ||= @headers[
|
|
29
|
+
@method ||= @headers[':method']
|
|
28
30
|
end
|
|
29
31
|
|
|
30
32
|
def scheme
|
|
31
33
|
@scheme ||= @headers[':scheme']
|
|
32
34
|
end
|
|
33
35
|
|
|
34
|
-
S_EMPTY = ''
|
|
35
|
-
|
|
36
36
|
def path
|
|
37
|
-
@uri ||= URI.parse(@headers[':path'] ||
|
|
37
|
+
@uri ||= URI.parse(@headers[':path'] || '')
|
|
38
38
|
@path ||= @uri.path
|
|
39
39
|
end
|
|
40
40
|
|
|
41
|
-
S_AMPERSAND = '&'
|
|
42
|
-
S_EQUAL = '='
|
|
43
|
-
|
|
44
41
|
def query
|
|
45
|
-
@uri ||= URI.parse(@headers[':path'] ||
|
|
42
|
+
@uri ||= URI.parse(@headers[':path'] || '')
|
|
46
43
|
return @query if @query
|
|
47
44
|
|
|
48
45
|
if (q = u.query)
|
|
49
|
-
@query = q.split(
|
|
50
|
-
k, v = kv.split(
|
|
46
|
+
@query = q.split('&').each_with_object({}) do |kv, h|
|
|
47
|
+
k, v = kv.split('=')
|
|
51
48
|
h[k.to_sym] = URI.decode_www_form_component(v)
|
|
52
49
|
end
|
|
53
50
|
else
|
|
@@ -55,13 +52,10 @@ class Request
|
|
|
55
52
|
end
|
|
56
53
|
end
|
|
57
54
|
|
|
58
|
-
|
|
59
|
-
S_STATUS = ':status'
|
|
60
|
-
S_STATUS_200 = '200'
|
|
61
|
-
EMPTY_LINE = "\r\n"
|
|
55
|
+
EMPTY_HASH = {}
|
|
62
56
|
|
|
63
|
-
def respond(body, headers =
|
|
64
|
-
headers[
|
|
57
|
+
def respond(body, headers = EMPTY_HASH)
|
|
58
|
+
headers[':status'] ||= '200'
|
|
65
59
|
|
|
66
60
|
@stream.headers(headers, end_stream: false)
|
|
67
61
|
@stream.data(body, end_stream: true)
|