polyphony-http 0.24
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +56 -0
- data/CHANGELOG.md +6 -0
- data/Gemfile +3 -0
- data/Gemfile.lock +51 -0
- data/LICENSE +21 -0
- data/README.md +47 -0
- data/Rakefile +20 -0
- data/TODO.md +59 -0
- data/bin/poly +11 -0
- data/docs/README.md +38 -0
- data/docs/summary.md +60 -0
- data/examples/cuba.ru +22 -0
- data/examples/happy_eyeballs.rb +37 -0
- data/examples/http2_raw.rb +135 -0
- data/examples/http_client.rb +28 -0
- data/examples/http_get.rb +33 -0
- data/examples/http_parse_experiment.rb +123 -0
- data/examples/http_proxy.rb +83 -0
- data/examples/http_server.js +24 -0
- data/examples/http_server.rb +21 -0
- data/examples/http_server_forked.rb +29 -0
- data/examples/http_server_graceful.rb +27 -0
- data/examples/http_server_simple.rb +11 -0
- data/examples/http_server_throttled.rb +15 -0
- data/examples/http_server_timeout.rb +35 -0
- data/examples/http_ws_server.rb +37 -0
- data/examples/https_raw_client.rb +12 -0
- data/examples/https_server.rb +22 -0
- data/examples/https_wss_server.rb +39 -0
- data/examples/rack_server.rb +12 -0
- data/examples/rack_server_https.rb +19 -0
- data/examples/rack_server_https_forked.rb +27 -0
- data/examples/websocket_secure_server.rb +27 -0
- data/examples/websocket_server.rb +24 -0
- data/examples/ws_page.html +34 -0
- data/examples/wss_page.html +34 -0
- data/lib/polyphony/http.rb +16 -0
- data/lib/polyphony/http/client/agent.rb +131 -0
- data/lib/polyphony/http/client/http1.rb +129 -0
- data/lib/polyphony/http/client/http2.rb +180 -0
- data/lib/polyphony/http/client/response.rb +32 -0
- data/lib/polyphony/http/client/site_connection_manager.rb +109 -0
- data/lib/polyphony/http/server.rb +49 -0
- data/lib/polyphony/http/server/http1.rb +267 -0
- data/lib/polyphony/http/server/http2.rb +78 -0
- data/lib/polyphony/http/server/http2_stream.rb +135 -0
- data/lib/polyphony/http/server/rack.rb +64 -0
- data/lib/polyphony/http/server/request.rb +118 -0
- data/lib/polyphony/http/version.rb +7 -0
- data/lib/polyphony/websocket.rb +59 -0
- data/polyphony-http.gemspec +34 -0
- data/test/coverage.rb +45 -0
- data/test/eg.rb +27 -0
- data/test/helper.rb +35 -0
- data/test/run.rb +5 -0
- data/test/test_http_server.rb +313 -0
- metadata +245 -0
@@ -0,0 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'bundler/setup'
|
4
|
+
require 'polyphony/http'
|
5
|
+
|
6
|
+
::Exception.__disable_sanitized_backtrace__ = true
|
7
|
+
|
8
|
+
opts = {
|
9
|
+
reuse_addr: true,
|
10
|
+
dont_linger: true
|
11
|
+
}
|
12
|
+
|
13
|
+
server = Polyphony::HTTP::Server.listen('0.0.0.0', 1234, opts)
|
14
|
+
|
15
|
+
puts 'Listening on port 1234'
|
16
|
+
|
17
|
+
child_pids = []
|
18
|
+
4.times do
|
19
|
+
pid = Polyphony.fork do
|
20
|
+
puts "forked pid: #{Process.pid}"
|
21
|
+
server.each do |req|
|
22
|
+
req.respond("Hello world! from pid: #{Process.pid}\n")
|
23
|
+
end
|
24
|
+
rescue Interrupt
|
25
|
+
end
|
26
|
+
child_pids << pid
|
27
|
+
end
|
28
|
+
|
29
|
+
child_pids.each { |pid| Gyro::Child.new(pid).await }
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'bundler/setup'
|
4
|
+
require 'polyphony'
|
5
|
+
require 'polyphony/http'
|
6
|
+
|
7
|
+
opts = {
|
8
|
+
reuse_addr: true,
|
9
|
+
dont_linger: true
|
10
|
+
}
|
11
|
+
|
12
|
+
server = spin do
|
13
|
+
Polyphony::HTTP::Server.serve('0.0.0.0', 1234, opts) do |req|
|
14
|
+
req.respond("Hello world!\n")
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
trap('SIGHUP') do
|
19
|
+
puts 'got hup'
|
20
|
+
server.interrupt
|
21
|
+
end
|
22
|
+
|
23
|
+
puts "pid: #{Process.pid}"
|
24
|
+
puts 'Send HUP to stop gracefully'
|
25
|
+
puts 'Listening on port 1234...'
|
26
|
+
|
27
|
+
suspend
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'bundler/setup'
|
4
|
+
require 'polyphony/http'
|
5
|
+
|
6
|
+
$throttler = throttle(1000)
|
7
|
+
opts = { reuse_addr: true, dont_linger: true }
|
8
|
+
spin do
|
9
|
+
Polyphony::HTTP::Server.serve('0.0.0.0', 1234, opts) do |req|
|
10
|
+
$throttler.call { req.respond("Hello world!\n") }
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
puts "pid: #{Process.pid}"
|
15
|
+
puts 'Listening on port 1234...'
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'bundler/setup'
|
4
|
+
require 'polyphony/http'
|
5
|
+
|
6
|
+
opts = {
|
7
|
+
reuse_addr: true,
|
8
|
+
dont_linger: true
|
9
|
+
}
|
10
|
+
|
11
|
+
def timeout_handler(timeout, &handler)
|
12
|
+
->(req) do
|
13
|
+
cancel_after(timeout) { handler.(req) }
|
14
|
+
rescue Polyphony::Cancel
|
15
|
+
req.respond("timeout\n", ':status' => 502)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
sleep 0
|
20
|
+
|
21
|
+
spin do
|
22
|
+
Polyphony::HTTP::Server.serve(
|
23
|
+
'0.0.0.0',
|
24
|
+
1234,
|
25
|
+
opts,
|
26
|
+
&timeout_handler(0.1) do |req|
|
27
|
+
sleep rand(0.01..0.2)
|
28
|
+
req.respond("Hello timeout world!\n")
|
29
|
+
end
|
30
|
+
)
|
31
|
+
end
|
32
|
+
|
33
|
+
puts "pid: #{Process.pid}"
|
34
|
+
puts 'Listening on port 1234...'
|
35
|
+
suspend
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'bundler/setup'
|
4
|
+
require 'polyphony/http'
|
5
|
+
require 'polyphony/websocket'
|
6
|
+
|
7
|
+
def ws_handler(conn)
|
8
|
+
timer = spin do
|
9
|
+
throttled_loop(1) do
|
10
|
+
conn << Time.now.to_s
|
11
|
+
end
|
12
|
+
end
|
13
|
+
while (msg = conn.recv)
|
14
|
+
conn << "you said: #{msg}"
|
15
|
+
end
|
16
|
+
ensure
|
17
|
+
timer.stop
|
18
|
+
end
|
19
|
+
|
20
|
+
opts = {
|
21
|
+
reuse_addr: true,
|
22
|
+
dont_linger: true,
|
23
|
+
upgrade: {
|
24
|
+
websocket: Polyphony::Websocket.handler(&method(:ws_handler))
|
25
|
+
}
|
26
|
+
}
|
27
|
+
|
28
|
+
HTML = IO.read(File.join(__dir__, 'ws_page.html'))
|
29
|
+
|
30
|
+
spin do
|
31
|
+
Polyphony::HTTP::Server.serve('0.0.0.0', 1234, opts) do |req|
|
32
|
+
req.respond(HTML, 'Content-Type' => 'text/html')
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
puts "pid: #{Process.pid}"
|
37
|
+
puts 'Listening on port 1234...'
|
@@ -0,0 +1,12 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'bundler/setup'
|
4
|
+
require 'polyphony/http'
|
5
|
+
|
6
|
+
t0 = Time.now
|
7
|
+
io = Polyphony::Net.tcp_connect('google.com', 443, secure: true)
|
8
|
+
io.write("GET / HTTP/1.0\r\nHost: realiteq.net\r\n\r\n")
|
9
|
+
reply = io.read
|
10
|
+
puts "time: #{Time.now - t0}"
|
11
|
+
puts
|
12
|
+
puts reply
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'bundler/setup'
|
4
|
+
require 'polyphony/http'
|
5
|
+
require 'localhost/authority'
|
6
|
+
|
7
|
+
authority = Localhost::Authority.fetch
|
8
|
+
opts = {
|
9
|
+
reuse_addr: true,
|
10
|
+
dont_linger: true,
|
11
|
+
secure_context: authority.server_context
|
12
|
+
}
|
13
|
+
|
14
|
+
puts "pid: #{Process.pid}"
|
15
|
+
puts 'Listening on port 1234...'
|
16
|
+
Polyphony::HTTP::Server.serve('0.0.0.0', 1234, opts) do |req|
|
17
|
+
req.respond("Hello world!\n")
|
18
|
+
# req.send_headers
|
19
|
+
# req.send_chunk("Method: #{req.method}\n")
|
20
|
+
# req.send_chunk("Path: #{req.path}\n")
|
21
|
+
# req.send_chunk("Query: #{req.query.inspect}\n", done: true)
|
22
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'bundler/setup'
|
4
|
+
require 'polyphony/http'
|
5
|
+
require 'localhost/authority'
|
6
|
+
|
7
|
+
def ws_handler(conn)
|
8
|
+
timer = spin do
|
9
|
+
throttled_loop(1) do
|
10
|
+
conn << Time.now.to_s
|
11
|
+
rescue StandardError
|
12
|
+
nil
|
13
|
+
end
|
14
|
+
end
|
15
|
+
while (msg = conn.recv)
|
16
|
+
puts "msg: #{msg}"
|
17
|
+
# conn << "you said: #{msg}"
|
18
|
+
end
|
19
|
+
ensure
|
20
|
+
timer.stop
|
21
|
+
end
|
22
|
+
|
23
|
+
authority = Localhost::Authority.fetch
|
24
|
+
opts = {
|
25
|
+
reuse_addr: true,
|
26
|
+
dont_linger: true,
|
27
|
+
secure_context: authority.server_context,
|
28
|
+
upgrade: {
|
29
|
+
websocket: Polyphony::Websocket.handler(&method(:ws_handler))
|
30
|
+
}
|
31
|
+
}
|
32
|
+
|
33
|
+
HTML = IO.read(File.join(__dir__, 'wss_page.html'))
|
34
|
+
|
35
|
+
puts "pid: #{Process.pid}"
|
36
|
+
puts 'Listening on port 1234...'
|
37
|
+
Polyphony::HTTP::Server.serve('0.0.0.0', 1234, opts) do |req|
|
38
|
+
req.respond(HTML, 'Content-Type' => 'text/html')
|
39
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'bundler/setup'
|
4
|
+
require 'polyphony/http'
|
5
|
+
|
6
|
+
app_path = ARGV.first || File.expand_path('./config.ru', __dir__)
|
7
|
+
app = Polyphony::HTTP::Rack.load(app_path)
|
8
|
+
opts = { reuse_addr: true, dont_linger: true }
|
9
|
+
|
10
|
+
puts 'listening on port 1234'
|
11
|
+
puts "pid: #{Process.pid}"
|
12
|
+
Polyphony::HTTP::Server.serve('0.0.0.0', 1234, opts, &app)
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'bundler/setup'
|
4
|
+
require 'polyphony/http'
|
5
|
+
require 'localhost/authority'
|
6
|
+
|
7
|
+
app_path = ARGV.first || File.expand_path('./config.ru', __dir__)
|
8
|
+
app = Polyphony::HTTP::Rack.load(app_path)
|
9
|
+
|
10
|
+
authority = Localhost::Authority.fetch
|
11
|
+
opts = {
|
12
|
+
reuse_addr: true,
|
13
|
+
dont_linger: true,
|
14
|
+
secure_context: authority.server_context
|
15
|
+
}
|
16
|
+
|
17
|
+
puts 'listening on port 1234'
|
18
|
+
puts "pid: #{Process.pid}"
|
19
|
+
Polyphony::HTTP::Server.serve('0.0.0.0', 1234, opts, &app)
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'bundler/setup'
|
4
|
+
require 'polyphony/http'
|
5
|
+
require 'localhost/authority'
|
6
|
+
|
7
|
+
app_path = ARGV.first || File.expand_path('./config.ru', __dir__)
|
8
|
+
app = Polyphony::HTTP::Rack.load(app_path)
|
9
|
+
|
10
|
+
authority = Localhost::Authority.fetch
|
11
|
+
opts = {
|
12
|
+
reuse_addr: true,
|
13
|
+
dont_linger: true,
|
14
|
+
secure_context: authority.server_context
|
15
|
+
}
|
16
|
+
server = Polyphony::HTTP::Server.listen('0.0.0.0', 1234, opts)
|
17
|
+
puts 'Listening on port 1234'
|
18
|
+
|
19
|
+
child_pids = []
|
20
|
+
4.times do
|
21
|
+
child_pids << Polyphony.fork do
|
22
|
+
puts "forked pid: #{Process.pid}"
|
23
|
+
server.each(&app)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
child_pids.each { |pid| EV::Child.new(pid).await }
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'bundler/setup'
|
4
|
+
require 'polyphony/http'
|
5
|
+
require 'localhost/authority'
|
6
|
+
|
7
|
+
def ws_handler(conn)
|
8
|
+
while (msg = conn.recv)
|
9
|
+
conn << "you said: #{msg}"
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
authority = Localhost::Authority.fetch
|
14
|
+
opts = {
|
15
|
+
reuse_addr: true,
|
16
|
+
dont_linger: true,
|
17
|
+
upgrade: {
|
18
|
+
websocket: Polyphony::Websocket.handler(&method(:ws_handler))
|
19
|
+
},
|
20
|
+
secure_context: authority.server_context
|
21
|
+
}
|
22
|
+
|
23
|
+
puts "pid: #{Process.pid}"
|
24
|
+
puts 'Listening on port 1234...'
|
25
|
+
Polyphony::HTTP::Server.serve('0.0.0.0', 1234, opts) do |req|
|
26
|
+
req.respond("Hello world!\n")
|
27
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'bundler/setup'
|
4
|
+
require 'polyphony/http'
|
5
|
+
|
6
|
+
def ws_handler(conn)
|
7
|
+
while (msg = conn.recv)
|
8
|
+
conn << "you said: #{msg}"
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
opts = {
|
13
|
+
reuse_addr: true,
|
14
|
+
dont_linger: true,
|
15
|
+
upgrade: {
|
16
|
+
websocket: Polyphony::Websocket.handler(&method(:ws_handler))
|
17
|
+
}
|
18
|
+
}
|
19
|
+
|
20
|
+
puts "pid: #{Process.pid}"
|
21
|
+
puts 'Listening on port 1234...'
|
22
|
+
Polyphony::HTTP::Server.serve('0.0.0.0', 1234, opts) do |req|
|
23
|
+
req.respond("Hello world!\n")
|
24
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
<!doctype html>
|
2
|
+
<html lang="en">
|
3
|
+
<head>
|
4
|
+
<title>Websocket Client</title>
|
5
|
+
</head>
|
6
|
+
<body>
|
7
|
+
<script>
|
8
|
+
var connect = function () {
|
9
|
+
var exampleSocket = new WebSocket("ws://localhost:1234");
|
10
|
+
|
11
|
+
exampleSocket.onopen = function (event) {
|
12
|
+
document.querySelector('#status').innerText = 'connected';
|
13
|
+
exampleSocket.send("Can you hear me?");
|
14
|
+
};
|
15
|
+
exampleSocket.onclose = function (event) {
|
16
|
+
console.log('onclose');
|
17
|
+
document.querySelector('#status').innerText = 'disconnected';
|
18
|
+
setTimeout(function () {
|
19
|
+
// exampleSocket.removeAllListeners();
|
20
|
+
connect();
|
21
|
+
}, 1000);
|
22
|
+
}
|
23
|
+
exampleSocket.onmessage = function (event) {
|
24
|
+
document.querySelector('#msg').innerText = event.data;
|
25
|
+
console.log(event.data);
|
26
|
+
}
|
27
|
+
};
|
28
|
+
|
29
|
+
connect();
|
30
|
+
</script>
|
31
|
+
<h1 id="status">disconnected</h1>
|
32
|
+
<h1 id="msg"></h1>
|
33
|
+
</body>
|
34
|
+
</html>
|
@@ -0,0 +1,34 @@
|
|
1
|
+
<!doctype html>
|
2
|
+
<html lang="en">
|
3
|
+
<head>
|
4
|
+
<title>Websocket Client</title>
|
5
|
+
</head>
|
6
|
+
<body>
|
7
|
+
<script>
|
8
|
+
var connect = function () {
|
9
|
+
var exampleSocket = new WebSocket("/");
|
10
|
+
|
11
|
+
exampleSocket.onopen = function (event) {
|
12
|
+
document.querySelector('#status').innerText = 'connected';
|
13
|
+
exampleSocket.send("Can you hear me?");
|
14
|
+
};
|
15
|
+
exampleSocket.onclose = function (event) {
|
16
|
+
console.log('onclose');
|
17
|
+
document.querySelector('#status').innerText = 'disconnected';
|
18
|
+
setTimeout(function () {
|
19
|
+
// exampleSocket.removeAllListeners();
|
20
|
+
connect();
|
21
|
+
}, 1000);
|
22
|
+
}
|
23
|
+
exampleSocket.onmessage = function (event) {
|
24
|
+
document.querySelector('#msg').innerText = event.data;
|
25
|
+
console.log(event.data);
|
26
|
+
}
|
27
|
+
};
|
28
|
+
|
29
|
+
connect();
|
30
|
+
</script>
|
31
|
+
<h1 id="status">disconnected</h1>
|
32
|
+
<h1 id="msg"></h1>
|
33
|
+
</body>
|
34
|
+
</html>
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'polyphony'
|
4
|
+
|
5
|
+
module Polyphony
|
6
|
+
# HTTP imports (loaded dynamically)
|
7
|
+
module HTTP
|
8
|
+
auto_import(
|
9
|
+
Agent: './http/client/agent',
|
10
|
+
Rack: './http/server/rack',
|
11
|
+
Server: './http/server'
|
12
|
+
)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
export_default Polyphony::HTTP
|