polyphony-http 0.24

Sign up to get free protection for your applications and to get access to all the features.
Files changed (58) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +56 -0
  3. data/CHANGELOG.md +6 -0
  4. data/Gemfile +3 -0
  5. data/Gemfile.lock +51 -0
  6. data/LICENSE +21 -0
  7. data/README.md +47 -0
  8. data/Rakefile +20 -0
  9. data/TODO.md +59 -0
  10. data/bin/poly +11 -0
  11. data/docs/README.md +38 -0
  12. data/docs/summary.md +60 -0
  13. data/examples/cuba.ru +22 -0
  14. data/examples/happy_eyeballs.rb +37 -0
  15. data/examples/http2_raw.rb +135 -0
  16. data/examples/http_client.rb +28 -0
  17. data/examples/http_get.rb +33 -0
  18. data/examples/http_parse_experiment.rb +123 -0
  19. data/examples/http_proxy.rb +83 -0
  20. data/examples/http_server.js +24 -0
  21. data/examples/http_server.rb +21 -0
  22. data/examples/http_server_forked.rb +29 -0
  23. data/examples/http_server_graceful.rb +27 -0
  24. data/examples/http_server_simple.rb +11 -0
  25. data/examples/http_server_throttled.rb +15 -0
  26. data/examples/http_server_timeout.rb +35 -0
  27. data/examples/http_ws_server.rb +37 -0
  28. data/examples/https_raw_client.rb +12 -0
  29. data/examples/https_server.rb +22 -0
  30. data/examples/https_wss_server.rb +39 -0
  31. data/examples/rack_server.rb +12 -0
  32. data/examples/rack_server_https.rb +19 -0
  33. data/examples/rack_server_https_forked.rb +27 -0
  34. data/examples/websocket_secure_server.rb +27 -0
  35. data/examples/websocket_server.rb +24 -0
  36. data/examples/ws_page.html +34 -0
  37. data/examples/wss_page.html +34 -0
  38. data/lib/polyphony/http.rb +16 -0
  39. data/lib/polyphony/http/client/agent.rb +131 -0
  40. data/lib/polyphony/http/client/http1.rb +129 -0
  41. data/lib/polyphony/http/client/http2.rb +180 -0
  42. data/lib/polyphony/http/client/response.rb +32 -0
  43. data/lib/polyphony/http/client/site_connection_manager.rb +109 -0
  44. data/lib/polyphony/http/server.rb +49 -0
  45. data/lib/polyphony/http/server/http1.rb +267 -0
  46. data/lib/polyphony/http/server/http2.rb +78 -0
  47. data/lib/polyphony/http/server/http2_stream.rb +135 -0
  48. data/lib/polyphony/http/server/rack.rb +64 -0
  49. data/lib/polyphony/http/server/request.rb +118 -0
  50. data/lib/polyphony/http/version.rb +7 -0
  51. data/lib/polyphony/websocket.rb +59 -0
  52. data/polyphony-http.gemspec +34 -0
  53. data/test/coverage.rb +45 -0
  54. data/test/eg.rb +27 -0
  55. data/test/helper.rb +35 -0
  56. data/test/run.rb +5 -0
  57. data/test/test_http_server.rb +313 -0
  58. 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,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/setup'
4
+ require 'polyphony/http'
5
+
6
+ puts "pid: #{Process.pid}"
7
+ puts 'Listening on port 1234...'
8
+
9
+ Polyphony::HTTP::Server.serve('0.0.0.0', 1234) do |req|
10
+ req.respond("Hello world!\n")
11
+ end
@@ -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