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,71 +0,0 @@
1
- #!/usr/bin/env ruby
2
-
3
- require 'csv'
4
- require 'json'
5
- require 'net/http'
6
-
7
- require 'protocol/http/header/authorization'
8
-
9
- class RateLimitingError < StandardError; end
10
-
11
- @user = ENV['GITHUB_USER']
12
- @token = ENV['GITHUB_TOKEN']
13
-
14
- unless @user && @token
15
- fail "export GITHUB_USER and GITHUB_TOKEN!"
16
- end
17
-
18
- def fetch_github_license(homepage_uri)
19
- %r{github.com/(?<owner>.+?)/(?<repo>.+)} =~ homepage_uri
20
- return nil unless repo
21
-
22
- url = URI.parse("https://api.github.com/repos/#{owner}/#{repo}/license")
23
- request = Net::HTTP::Get.new(url)
24
-
25
- request['user-agent'] = 'fetch-github-licenses'
26
- request['authorization'] = Protocol::HTTP::Header::Authorization.basic(@user, @token)
27
-
28
- response = Net::HTTP.start(url.hostname) do |http|
29
- http.request(request)
30
- end
31
-
32
- case response
33
- when Net::HTTPOK
34
- JSON.parse(response.body).dig('license', 'spdx_id')
35
- when Net::HTTPNotFound, Net::HTTPMovedPermanently, Net::HTTPForbidden
36
- nil
37
- else
38
- raise response.body
39
- end
40
- end
41
-
42
- def fetch_rubygem_license(name, version)
43
- url = URI.parse("https://rubygems.org/api/v2/rubygems/#{name}/versions/#{version}.json")
44
- response = Net::HTTP.get_response(url)
45
-
46
- case response
47
- when Net::HTTPOK
48
- body = JSON.parse(response.body)
49
- [name, body.dig('licenses', 0) || fetch_github_license(body['homepage_uri'])]
50
- when Net::HTTPNotFound
51
- [name, nil] # from a non rubygems remote
52
- when Net::HTTPTooManyRequests
53
- raise RateLimitingError
54
- else
55
- raise response.body
56
- end
57
- rescue RateLimitingError
58
- sleep 1
59
-
60
- retry
61
- end
62
-
63
- threads = ARGF.map do |line|
64
- if line == "GEM\n" .. line.chomp.empty?
65
- /\A\s{4}(?<name>[a-z].+?) \((?<version>.+)\)\n\z/ =~ line
66
-
67
- Thread.new { fetch_rubygem_license(name, version) } if name
68
- end
69
- end.compact
70
-
71
- puts CSV.generate { |csv| threads.each { csv << _1.value } }
@@ -1,90 +0,0 @@
1
- #!/usr/bin/env ruby
2
-
3
- require 'csv'
4
- require 'json'
5
- require 'async/http/internet'
6
-
7
- class RateLimitingError < StandardError; end
8
-
9
- @internet = Async::HTTP::Internet.new
10
-
11
- @user = ENV['GITHUB_USER']
12
- @token = ENV['GITHUB_TOKEN']
13
-
14
- unless @user && @token
15
- fail "export GITHUB_USER and GITHUB_TOKEN!"
16
- end
17
-
18
- GITHUB_HEADERS = {
19
- 'user-agent' => 'fetch-github-licenses',
20
- 'authorization' => Protocol::HTTP::Header::Authorization.basic(@user, @token)
21
- }
22
-
23
- RUBYGEMS_HEADERS = {
24
- 'user-agent' => 'fetch-github-licenses'
25
- }
26
-
27
- def fetch_github_license(homepage_uri)
28
- %r{github.com/(?<owner>.+?)/(?<repo>.+)} =~ homepage_uri
29
- return nil unless repo
30
-
31
- response = @internet.get("https://api.github.com/repos/#{owner}/#{repo}/license", GITHUB_HEADERS)
32
-
33
- case response.status
34
- when 200
35
- return JSON.parse(response.read).dig('license', 'spdx_id')
36
- when 404
37
- return nil
38
- else
39
- raise response.read
40
- end
41
- ensure
42
- response.finish
43
- end
44
-
45
- def fetch_rubygem_license(name, version)
46
- response = @internet.get("https://rubygems.org/api/v2/rubygems/#{name}/versions/#{version}.json", RUBYGEMS_HEADERS)
47
-
48
- case response.status
49
- when 200
50
- body = JSON.parse(response.read)
51
- [name, body.dig('licenses', 0) || fetch_github_license(body['homepage_uri'])]
52
- when 404
53
- [name, nil] # from a non rubygems remote
54
- when 429
55
- raise RateLimitingError
56
- else
57
- raise response.read
58
- end
59
- rescue RateLimitingError
60
- response.finish
61
-
62
- Async.logger.warn(name) {"Rate limited..."}
63
- Async::Task.current.sleep(1.0)
64
-
65
- retry
66
- ensure
67
- response.finish
68
- end
69
-
70
- Sync do |parent|
71
- output = CSV.new($stdout)
72
-
73
- tasks = ARGF.map do |line|
74
- if line == "GEM\n" .. line.chomp.empty?
75
- /\A\s{4}(?<name>[a-z].+?) \((?<version>.+)\)\n\z/ =~ line
76
-
77
- parent.async do
78
- fetch_rubygem_license(name, version)
79
- end if name
80
- end
81
- end.compact
82
-
83
- tasks.each do |task|
84
- output << task.wait
85
- end
86
-
87
- @internet.instance_variable_get(:@clients).each do |name, client|
88
- puts client.pool
89
- end
90
- end
@@ -1,38 +0,0 @@
1
- #!/usr/bin/env ruby
2
- #
3
- # $LOAD_PATH.unshift(File.expand_path("../lib", __dir__))
4
- # $LOAD_PATH.unshift(File.expand_path("../../http-protocol/lib", __dir__))
5
-
6
- require 'async'
7
- require 'async/logger'
8
- require 'async/http/client'
9
- require 'async/http/endpoint'
10
-
11
- # Async.logger.level = Logger::DEBUG
12
-
13
- Async do |task|
14
- endpoint = Async::HTTP::Endpoint.parse("https://www.google.com")
15
-
16
- client = Async::HTTP::Client.new(endpoint)
17
-
18
- headers = {
19
- 'accept' => 'text/html',
20
- }
21
-
22
- request = Protocol::HTTP::Request.new(client.scheme, "www.google.com", "GET", "/search?q=cats", headers)
23
-
24
- puts "Sending request..."
25
- response = client.call(request)
26
-
27
- puts "Reading response status=#{response.status}..."
28
-
29
- if body = response.body
30
- while chunk = body.read
31
- puts chunk.size
32
- end
33
- end
34
-
35
- response.close
36
-
37
- puts "Finish reading response."
38
- end
@@ -1,28 +0,0 @@
1
- #!/usr/bin/env ruby
2
-
3
- require 'async'
4
- require 'async/http/internet'
5
-
6
- Async do |parent|
7
- internet = Async::HTTP::Internet.new
8
- connection = nil
9
-
10
- child = parent.async do
11
- response = internet.get("https://utopia-falcon-heroku.herokuapp.com/beer/index")
12
- connection = response.connection
13
-
14
- response.each do |chunk|
15
- Async.logger.info(response) {chunk}
16
- end
17
- ensure
18
- Async.logger.info(response) {"Closing response..."}
19
- response&.close
20
- end
21
-
22
- parent.sleep(5)
23
-
24
- Async.logger.info(parent) {"Killing #{child}..."}
25
- child.stop
26
- ensure
27
- internet&.close
28
- end
@@ -1,5 +0,0 @@
1
-
2
- source 'https://rubygems.org'
3
-
4
- gem "trenni"
5
- gem "async-http"
@@ -1,35 +0,0 @@
1
-
2
- require 'trenni/template'
3
-
4
- require 'async'
5
- require 'async/http/body/writable'
6
-
7
- # The template, using inline text. The sleep could be anything - database query, HTTP request, redis, etc.
8
- buffer = Trenni::Buffer.new(<<-EOF)
9
- The "\#{self[:count]} bottles of \#{self[:drink]} on the wall" song!
10
-
11
- <?r self[:count].downto(1) do |index| ?>
12
- \#{index} bottles of \#{self[:drink]} on the wall,
13
- \#{index} bottles of \#{self[:drink]},
14
- take one down, and pass it around,
15
- \#{index - 1} bottles of \#{self[:drink]} on the wall.
16
-
17
- <?r Async::Task.current.sleep(1) ?>
18
- <?r end ?>
19
- EOF
20
-
21
- template = Trenni::Template.new(buffer)
22
-
23
- Async do
24
- body = Async::HTTP::Body::Writable.new
25
-
26
- generator = Async do
27
- template.to_string({count: 100, drink: 'coffee'}, body)
28
- end
29
-
30
- while chunk = body.read
31
- $stdout.write chunk
32
- end
33
-
34
- generator.wait
35
- end.wait
@@ -1,39 +0,0 @@
1
- #!/usr/bin/env ruby
2
-
3
- $LOAD_PATH.unshift File.expand_path("../../lib", __dir__)
4
-
5
- require 'async'
6
- require 'async/http/body/file'
7
- require 'async/http/body/delayed'
8
- require 'async/http/client'
9
- require 'async/http/endpoint'
10
-
11
- Async do
12
- endpoint = Async::HTTP::Endpoint.parse("http://localhost:9222")
13
- client = Async::HTTP::Client.new(endpoint, Async::HTTP::Protocol::HTTP2)
14
-
15
- headers = [
16
- ['accept', 'text/plain'],
17
- ]
18
-
19
- body = Async::HTTP::Body::Delayed.new(Async::HTTP::Body::File.open("data.txt", block_size: 32))
20
-
21
- response = client.post(endpoint.path, headers, body)
22
-
23
- puts response.status
24
-
25
- # response.read -> string
26
- # response.each {|chunk| ...}
27
- # response.close (forcefully ignore data)
28
- # body = response.finish (read and buffer response)
29
- # response.save("echo.txt")
30
-
31
- response.each do |chunk|
32
- puts chunk.inspect
33
- end
34
-
35
- ensure
36
- client.close if client
37
- end
38
-
39
- puts "Done."
@@ -1,41 +0,0 @@
1
- The Parable of the Two Programmers
2
-
3
- Neil W. Rickert
4
-
5
- Once upon a time, unbeknownst to each other, the "Automated Accounting Applications Association" and the "Consolidated Computerized Capital Corporation" decided that they needed the identical program to perform a certain service.
6
-
7
- Automated hired a programmer-analyst, Alan, to solve their problem.
8
-
9
- Meanwhile, Consolidated decided to ask a newly-hired entry-level programmer, Charles, to tackle the job, to see if he was as good as he pretended.
10
-
11
- Alan, having had experience in difficult programming projects, decided to use the PQR structured design methodology. With this in mind he asked his department manager to assign another three programmers as a programming team. Then the team went to work, churning out preliminary reports and problem analyses.
12
-
13
- Back at Consolidated, Charles spent some time thinking about the problem. His fellow employees noticed that Charles often sat with his feet on the desk, drinking coffee. He was occasionally seen at his computer terminal, but his office mate could tell from the rhythmic striking of keys that he was actually playing Space Invaders.
14
-
15
- By now, the team at Automated was starting to write code. The programmers were spending about half their time writing and compiling code, and the rest of their time in conference, discussing the interfaces between the various modules.
16
-
17
- His office mate noticed that Charles had finally given up on Space Invaders. Instead he now divided his time between drinking coffee with his feet on the table, and scribbling on little scraps of paper. His scribbling didn't seem to be Tic-Tac-Toe, but it didn't exactly make much sense, either.
18
-
19
- Two months have gone by. The team at Automated finally releases an implementation timetable. In another two months they will have a test version of the program. Then a two month period of testing and enhancing should yield a completed version.
20
-
21
- The manager of Charles has by now tired of seeing him goof off. He decides to confront him. But as he walks into Charles' office, he is surprised to see Charles busy entering code at his terminal. He decides to postpone the confrontation, so makes some small talk and then leaves. However, he begins to keep a closer watch on Charles, so that when the opportunity presents itself he can confront him. Not looking forward to an unpleasant conversation, he is pleased to notice that Charles seems to be busy most of the time. He has even been seen to delay his lunch, and to stay after work two or three days a week.
22
-
23
- At the end of three months, Charles announces he has completed the project. He submits a 500-line program. The program appears to be clearly written, and when tested it does everything required in the specifications. In fact, it even has a few additional convenience features which might significantly improve the usability of the program. The program is put into test, and except for one quickly corrected oversight, performs well.
24
-
25
- The team at Automated has by now completed two of the four major modules required for their program. These modules are now undergoing testing while the other modules are completed.
26
-
27
- After another three weeks, Alan announces that the preliminary version is ready one week ahead of schedule. He supplies a list of the deficiencies that he expects to correct. The program is placed under test. The users find a number of bugs and deficiencies other than those listed. As Alan explains, this is no surprise. After all, this is a preliminary version in which bugs were expected.
28
-
29
- After about two more months, the team has completed its production version of the program. It consists of about 2,500 lines of code. When tested, it seems to satisfy most of the original specifications. It has omitted one or two features, and is very fussy about the format of its input data. However, the company decides to install the program. They can always train their data-entry staff to enter data in the strict format required. The program is handed over to some maintenance programmers to eventually incorporate the missing features.
30
-
31
- Sequel
32
-
33
- At first Charles' supervisor was impressed. But as he read through the source code, he realized that the project was really much simpler than he had originally thought. It now seemed apparent that this was not much of a challenge even for a beginning programmer.
34
-
35
- Charles did produce about five lines of code per day. This is perhaps a little above average. However, considering the simplicity of the program, it was nothing exceptional. Also, his supervisor remembered his two months of goofing off.
36
-
37
- At his next salary review Charles was given a raise which was about half the inflation over the period. He was not given a promotion. After about a year he became discouraged and left Consolidated.
38
-
39
- At Automated, Alan was complimented for completing his project on schedule. His supervisor looked over the program. Within a few minutes of thumbing through he saw that the company standards about structured programming were being observed. He quickly gave up attempting to read the program; however, it seemed quite incomprehensible. He realized by now that the project was really much more complex than he had originally assumed, and he congratulated Alan again on his achievement.
40
-
41
- The team had produced over three lines of code per programmer per day. This was about average, but considering the complexity of the problem, could be considered to be exceptional. Alan was given a hefty pay raise, and promoted to Systems Analyst as a reward for his achievement.
@@ -1,19 +0,0 @@
1
-
2
- $LOAD_PATH.unshift File.expand_path("../../lib", __dir__)
3
-
4
- require 'async'
5
- require 'async/http/server'
6
- require 'async/http/endpoint'
7
-
8
- protocol = Async::HTTP::Protocol::HTTP2
9
- endpoint = Async::HTTP::Endpoint.parse('http://127.0.0.1:9222', reuse_port: true)
10
-
11
- Async.logger.level = Logger::DEBUG
12
-
13
- Async do
14
- server = Async::HTTP::Server.for(endpoint, protocol) do |request|
15
- Protocol::HTTP::Response[200, {}, request.body]
16
- end
17
-
18
- server.run
19
- end
@@ -1,26 +0,0 @@
1
- #!/usr/bin/env ruby
2
-
3
- require 'async'
4
- require 'async/http/body/file'
5
- require 'async/http/internet'
6
-
7
- Async do
8
- internet = Async::HTTP::Internet.new
9
-
10
- headers = [
11
- ['accept', 'text/plain'],
12
- ]
13
-
14
- body = Async::HTTP::Body::File.open("data.txt")
15
-
16
- response = internet.post("https://www.codeotaku.com/journal/2018-10/async-http-client-for-ruby/echo", headers, body)
17
-
18
- # response.read -> string
19
- # response.each {|chunk| ...}
20
- # response.close (forcefully ignore data)
21
- # body = response.finish (read and buffer response)
22
- response.save("echo.txt")
23
-
24
- ensure
25
- internet.close
26
- end
data/gems.rb DELETED
@@ -1,11 +0,0 @@
1
- source 'https://rubygems.org'
2
-
3
- gemspec
4
-
5
- # gem "async", path: "../async"
6
- # gem "async-io", path: "../async-io"
7
-
8
- # gem "protocol-http", path: "../protocol-http"
9
- # gem "protocol-http1", path: "../protocol-http1"
10
- # gem "protocol-http2", path: "../protocol-http2"
11
- # gem "protocol-hpack", path: "../protocol-hpack"