async-http 0.52.4 → 0.54.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (51) hide show
  1. checksums.yaml +4 -4
  2. data/bake/async/http/h2spec.rb +1 -1
  3. data/lib/async/http/body/delayed.rb +2 -2
  4. data/lib/async/http/body/hijack.rb +5 -0
  5. data/lib/async/http/body/pipe.rb +15 -7
  6. data/lib/async/http/body/stream.rb +1 -1
  7. data/lib/async/http/client.rb +3 -3
  8. data/lib/async/http/protocol/http1.rb +2 -2
  9. data/lib/async/http/protocol/http1/connection.rb +0 -5
  10. data/lib/async/http/protocol/http1/server.rb +1 -1
  11. data/lib/async/http/protocol/http10.rb +2 -2
  12. data/lib/async/http/protocol/http11.rb +2 -2
  13. data/lib/async/http/protocol/http2.rb +0 -18
  14. data/lib/async/http/protocol/http2/connection.rb +7 -0
  15. data/lib/async/http/protocol/http2/output.rb +1 -1
  16. data/lib/async/http/protocol/http2/request.rb +0 -38
  17. data/lib/async/http/protocol/http2/response.rb +6 -13
  18. data/lib/async/http/protocol/request.rb +0 -4
  19. data/lib/async/http/proxy.rb +24 -8
  20. data/lib/async/http/server.rb +3 -3
  21. data/lib/async/http/version.rb +1 -1
  22. metadata +22 -66
  23. data/.editorconfig +0 -6
  24. data/.github/workflows/development.yml +0 -52
  25. data/.gitignore +0 -15
  26. data/.rspec +0 -3
  27. data/.travis.yml +0 -35
  28. data/README.md +0 -365
  29. data/async-http.gemspec +0 -39
  30. data/bake.rb +0 -0
  31. data/examples/compare/Gemfile +0 -9
  32. data/examples/compare/benchmark.rb +0 -78
  33. data/examples/download/chunked.rb +0 -86
  34. data/examples/fetch/Gemfile +0 -3
  35. data/examples/fetch/Gemfile.lock +0 -74
  36. data/examples/fetch/README.md +0 -3
  37. data/examples/fetch/config.ru +0 -28
  38. data/examples/fetch/public/index.html +0 -23
  39. data/examples/fetch/public/stream.js +0 -56
  40. data/examples/google/search.rb +0 -47
  41. data/examples/licenses/gemspect.rb +0 -71
  42. data/examples/licenses/list.rb +0 -90
  43. data/examples/request.rb +0 -38
  44. data/examples/stream/stop.rb +0 -28
  45. data/examples/trenni/Gemfile +0 -5
  46. data/examples/trenni/streaming.rb +0 -35
  47. data/examples/upload/client.rb +0 -39
  48. data/examples/upload/data.txt +0 -41
  49. data/examples/upload/server.rb +0 -19
  50. data/examples/upload/upload.rb +0 -26
  51. data/gems.rb +0 -11
@@ -1,39 +0,0 @@
1
-
2
- require_relative 'lib/async/http/version'
3
-
4
- Gem::Specification.new do |spec|
5
- spec.name = "async-http"
6
- spec.version = Async::HTTP::VERSION
7
- spec.licenses = ["MIT"]
8
- spec.authors = ["Samuel Williams"]
9
- spec.email = ["samuel.williams@oriontransfer.co.nz"]
10
-
11
- spec.summary = "A HTTP client and server library."
12
- spec.homepage = "https://github.com/socketry/async-http"
13
-
14
- spec.files = `git ls-files -z`.split("\x0").reject do |f|
15
- f.match(%r{^(test|spec|features)/})
16
- end
17
- spec.executables = spec.files.grep(%r{^bin/}) {|f| File.basename(f)}
18
- spec.require_paths = ["lib"]
19
-
20
- spec.add_dependency("async", "~> 1.25")
21
- spec.add_dependency("async-io", "~> 1.28")
22
- spec.add_dependency("async-pool", "~> 0.2")
23
-
24
- spec.add_dependency("protocol-http", "~> 0.20.0")
25
- spec.add_dependency("protocol-http1", "~> 0.13.0")
26
- spec.add_dependency("protocol-http2", "~> 0.14.0")
27
-
28
- # spec.add_dependency("openssl")
29
-
30
- spec.add_development_dependency "async-rspec", "~> 1.10"
31
- spec.add_development_dependency "async-container", "~> 0.14.0"
32
-
33
- spec.add_development_dependency "rack-test"
34
-
35
- spec.add_development_dependency "covered"
36
- spec.add_development_dependency "bundler"
37
- spec.add_development_dependency "bake-bundler"
38
- spec.add_development_dependency "rspec", "~> 3.6"
39
- end
data/bake.rb DELETED
File without changes
@@ -1,9 +0,0 @@
1
-
2
- source "https://rubygems.org"
3
-
4
- gem "benchmark-ips"
5
-
6
- gem "async"
7
- gem "async-http"
8
-
9
- gem "httpx"
@@ -1,78 +0,0 @@
1
- #!/usr/bin/env ruby
2
-
3
- require 'benchmark'
4
-
5
- require 'httpx'
6
-
7
- require 'async'
8
- require 'async/barrier'
9
- require 'async/semaphore'
10
- require 'async/http/internet'
11
-
12
- URL = "https://www.codeotaku.com/index"
13
- REPEATS = 10
14
-
15
- Benchmark.bmbm do |x|
16
- x.report("async-http") do
17
- Async do
18
- internet = Async::HTTP::Internet.new
19
-
20
- i = 0
21
- while i < REPEATS
22
- response = internet.get(URL)
23
- response.read
24
-
25
- i += 1
26
- end
27
- ensure
28
- internet&.close
29
- end
30
- end
31
-
32
- x.report("async-http (pipelined)") do
33
- Async do |task|
34
- internet = Async::HTTP::Internet.new
35
- semaphore = Async::Semaphore.new(100, parent: task)
36
- barrier = Async::Barrier.new(parent: semaphore)
37
-
38
- # Warm up the connection pool...
39
- response = internet.get(URL)
40
- response.read
41
-
42
- i = 0
43
- while i < REPEATS
44
- barrier.async do
45
- response = internet.get(URL)
46
-
47
- response.read
48
- end
49
-
50
- i += 1
51
- end
52
-
53
- barrier.wait
54
- ensure
55
- internet&.close
56
- end
57
- end
58
-
59
- x.report("httpx") do
60
- i = 0
61
- while i < REPEATS
62
- response = HTTPX.get(URL)
63
-
64
- response.read
65
-
66
- i += 1
67
- end
68
- end
69
-
70
- x.report("httpx (pipelined)") do
71
- urls = [URL] * REPEATS
72
- responses = HTTPX.get(*urls)
73
-
74
- responses.each do |response|
75
- response.read
76
- end
77
- end
78
- end
@@ -1,86 +0,0 @@
1
- #!/usr/bin/env ruby
2
-
3
- require 'async'
4
- require 'async/clock'
5
- require 'async/barrier'
6
- require 'async/semaphore'
7
- require_relative '../../lib/async/http/endpoint'
8
- require_relative '../../lib/async/http/client'
9
-
10
- Async do
11
- url = "https://static.openfoodfacts.org/data/en.openfoodfacts.org.products.csv"
12
-
13
- endpoint = Async::HTTP::Endpoint.parse(url)
14
- client = Async::HTTP::Client.new(endpoint)
15
-
16
- headers = {'user-agent' => 'curl/7.69.1', 'accept' => '*/*'}
17
-
18
- file = File.open("products.csv", "w")
19
- Async.logger.info(self) {"Saving download to #{Dir.pwd}"}
20
-
21
- begin
22
- response = client.head(endpoint.path, headers)
23
- content_length = nil
24
-
25
- if response.success?
26
- unless response.headers['accept-ranges'].include?('bytes')
27
- raise "Does not advertise support for accept-ranges: bytes!"
28
- end
29
-
30
- unless content_length = response.body&.length
31
- raise "Could not determine length of response!"
32
- end
33
- end
34
- ensure
35
- response&.close
36
- end
37
-
38
- Async.logger.info(self) {"Content length: #{content_length/(1024**2)}MiB"}
39
-
40
- parts = []
41
- offset = 0
42
- chunk_size = 1024*1024
43
-
44
- start_time = Async::Clock.now
45
- amount = 0
46
-
47
- while offset < content_length
48
- byte_range_start = offset
49
- byte_range_end = [offset + chunk_size, content_length].min
50
- parts << (byte_range_start...byte_range_end)
51
-
52
- offset += chunk_size
53
- end
54
-
55
- Async.logger.info(self) {"Breaking download into #{parts.size} parts..."}
56
-
57
- semaphore = Async::Semaphore.new(8)
58
- barrier = Async::Barrier.new(parent: semaphore)
59
-
60
- while !parts.empty?
61
- barrier.async do
62
- part = parts.shift
63
-
64
- Async.logger.info(self) {"Issuing range request range: bytes=#{part.min}-#{part.max}"}
65
-
66
- response = client.get(endpoint.path, [
67
- ["range", "bytes=#{part.min}-#{part.max-1}"],
68
- *headers
69
- ])
70
-
71
- if response.success?
72
- Async.logger.info(self) {"Got response: #{response}... writing data for #{part}."}
73
- written = file.pwrite(response.read, part.min)
74
-
75
- amount += written
76
-
77
- duration = Async::Clock.now - start_time
78
- Async.logger.info(self) {"Rate: #{((amount.to_f/(1024**2))/duration).round(2)}MiB/s"}
79
- end
80
- end
81
- end
82
-
83
- barrier.wait
84
- ensure
85
- client&.close
86
- end
@@ -1,3 +0,0 @@
1
-
2
- gem 'rack'
3
- gem 'falcon'
@@ -1,74 +0,0 @@
1
- GEM
2
- specs:
3
- async (1.24.2)
4
- console (~> 1.0)
5
- nio4r (~> 2.3)
6
- timers (~> 4.1)
7
- async-container (0.16.2)
8
- async (~> 1.0)
9
- async-io (~> 1.26)
10
- process-group
11
- async-http (0.50.5)
12
- async (~> 1.23)
13
- async-io (~> 1.27.0)
14
- async-pool (~> 0.2)
15
- protocol-http (~> 0.14.1)
16
- protocol-http1 (~> 0.10.0)
17
- protocol-http2 (~> 0.11.0)
18
- async-http-cache (0.1.2)
19
- async-http
20
- protocol-http (~> 0.14.4)
21
- async-io (1.27.4)
22
- async (~> 1.14)
23
- async-pool (0.2.0)
24
- async (~> 1.8)
25
- build-environment (1.13.0)
26
- coderay (1.1.2)
27
- console (1.8.2)
28
- falcon (0.35.6)
29
- async (~> 1.13)
30
- async-container (~> 0.16.0)
31
- async-http (~> 0.50.4)
32
- async-http-cache (~> 0.1.0)
33
- async-io (~> 1.22)
34
- build-environment (~> 1.13)
35
- localhost (~> 1.1)
36
- process-metrics (~> 0.1.0)
37
- rack (>= 1.0)
38
- samovar (~> 2.1)
39
- ffi (1.12.2)
40
- localhost (1.1.6)
41
- mapping (1.1.1)
42
- method_source (0.9.2)
43
- nio4r (2.5.2)
44
- process-group (1.2.1)
45
- process-terminal (~> 0.2.0)
46
- process-metrics (0.1.1)
47
- process-terminal (0.2.0)
48
- ffi
49
- protocol-hpack (1.4.2)
50
- protocol-http (0.14.4)
51
- protocol-http1 (0.10.2)
52
- protocol-http (~> 0.13)
53
- protocol-http2 (0.11.1)
54
- protocol-hpack (~> 1.4)
55
- protocol-http (~> 0.2)
56
- pry (0.12.2)
57
- coderay (~> 1.1.0)
58
- method_source (~> 0.9.0)
59
- rack (2.2.2)
60
- samovar (2.1.4)
61
- console (~> 1.0)
62
- mapping (~> 1.0)
63
- timers (4.3.0)
64
-
65
- PLATFORMS
66
- ruby
67
-
68
- DEPENDENCIES
69
- falcon
70
- pry
71
- rack
72
-
73
- BUNDLED WITH
74
- 1.17.3
@@ -1,3 +0,0 @@
1
- # Fetch
2
-
3
- This was an experiment to see how browsers handle bi-directional streaming.
@@ -1,28 +0,0 @@
1
-
2
- require 'rack'
3
-
4
- class Echo
5
- def initialize(app)
6
- @app = app
7
- end
8
-
9
- def call(env)
10
- request = Rack::Request.new(env)
11
-
12
- if request.path_info == "/echo"
13
- if output = request.body
14
- return [200, {}, output.body]
15
- else
16
- return [200, {}, ["Hello World?"]]
17
- end
18
- else
19
- return @app.call(env)
20
- end
21
- end
22
- end
23
-
24
- use Echo
25
-
26
- use Rack::Static, :urls => [''], :root => 'public', :index => 'index.html'
27
-
28
- run lambda{|env| [404, {}, []]}
@@ -1,23 +0,0 @@
1
- <!DOCTYPE html>
2
- <html>
3
- <head>
4
- <title>Streaming Fetch</title>
5
- </head>
6
- <body>
7
- <h1>Streams</h1>
8
-
9
- <button id="stopButton">Start</button>
10
-
11
- <h2>Sent</h2>
12
-
13
- <ul id="sent">
14
- </ul>
15
-
16
- <h2>Received</h2>
17
-
18
- <ul id="received">
19
- </ul>
20
-
21
- <script src="stream.js"></script>
22
- </body>
23
- </html>
@@ -1,56 +0,0 @@
1
- const inputStream = new ReadableStream({
2
- start(controller) {
3
- interval = setInterval(() => {
4
- let string = "Hello World!";
5
-
6
- // Add the string to the stream
7
- controller.enqueue(string);
8
-
9
- // show it on the screen
10
- let listItem = document.createElement('li');
11
- listItem.textContent = string;
12
- sent.appendChild(listItem);
13
- }, 10000);
14
-
15
- stopButton.addEventListener('click', function() {
16
- clearInterval(interval);
17
- controller.close();
18
- })
19
- },
20
- pull(controller) {
21
- // We don't really need a pull in this example
22
- },
23
- cancel() {
24
- // This is called if the reader cancels,
25
- // so we should stop generating strings
26
- clearInterval(interval);
27
- }
28
- });
29
-
30
- fetch("/echo", {method: 'POST', body: inputStream})
31
- .then(response => {
32
- const reader = response.body.getReader();
33
- const decoder = new TextDecoder("utf-8");
34
-
35
- function push() {
36
- reader.read().then(({done, value}) => {
37
- console.log("done:", done, "value:", value);
38
- const string = decoder.decode(value);
39
-
40
- // show it on the screen
41
- let listItem = document.createElement('li');
42
-
43
- if (done)
44
- listItem.textContent = "<EOF>"
45
- else
46
- listItem.textContent = string;
47
-
48
- received.appendChild(listItem);
49
-
50
- if (done) return;
51
- else push();
52
- });
53
- };
54
-
55
- push();
56
- });
@@ -1,47 +0,0 @@
1
- #!/usr/bin/env ruby
2
-
3
- require "async"
4
- require "async/clock"
5
- require "protocol/http/middleware"
6
- require_relative "../../lib/async/http"
7
-
8
- URL = "https://www.google.com/search"
9
- ENDPOINT = Async::HTTP::Endpoint.parse(URL)
10
-
11
- # Console.logger.enable(Async::IO::Stream, Console::Logger::DEBUG)
12
-
13
- class Google < Protocol::HTTP::Middleware
14
- def search(term)
15
- Async.logger.info(self) {"Searching for #{term}..."}
16
-
17
- self.get("/search?q=#{term}", {"user-agent" => "Hi Google!"})
18
- end
19
- end
20
-
21
- terms = %w{thoughtful fear size payment lethal modern recognise face morning sulky mountainous contain science snow uncle skirt truthful door travel snails closed rotten halting creator teeny-tiny beautiful cherries unruly level follow strip team things suggest pretty warm end cannon bad pig consider airport strengthen youthful fog three walk furry pickle moaning fax book ruddy sigh plate cakes shame stem faulty bushes dislike train sleet one colour behavior bitter suit count loutish squeak learn watery orange idiotic seat wholesale omniscient nostalgic arithmetic instruct committee puffy program cream cake whistle rely encourage war flagrant amusing fluffy prick utter wacky occur daily son check}
22
-
23
- if count = ENV.fetch('COUNT', 20)&.to_i
24
- terms = terms.first(count)
25
- end
26
-
27
- Async do |task|
28
- client = Async::HTTP::Client.new(ENDPOINT)
29
- google = Google.new(client)
30
-
31
- google.search("null").finish
32
-
33
- duration = Async::Clock.measure do
34
- counts = terms.map do |term|
35
- task.async do
36
- response = google.search(term)
37
- [term, response.read.scan(term).count]
38
- end
39
- end.map(&:wait).to_h
40
-
41
- Async.logger.info(self, name: 'counts') {counts}
42
- end
43
-
44
- Async.logger.info(self, name: 'duration') {duration}
45
- ensure
46
- google.close
47
- end