async-http 0.52.3 → 0.54.0
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/bake/async/http/h2spec.rb +1 -1
- data/lib/async/http/body/delayed.rb +2 -2
- data/lib/async/http/body/hijack.rb +5 -0
- data/lib/async/http/body/pipe.rb +15 -7
- data/lib/async/http/body/slowloris.rb +2 -2
- data/lib/async/http/body/stream.rb +1 -1
- data/lib/async/http/client.rb +3 -3
- data/lib/async/http/endpoint.rb +2 -2
- data/lib/async/http/internet.rb +4 -0
- data/lib/async/http/protocol/http1/connection.rb +0 -5
- data/lib/async/http/protocol/http1/server.rb +4 -3
- data/lib/async/http/protocol/http2.rb +0 -18
- data/lib/async/http/protocol/http2/output.rb +1 -1
- data/lib/async/http/protocol/http2/request.rb +0 -38
- data/lib/async/http/protocol/http2/response.rb +6 -13
- data/lib/async/http/protocol/request.rb +0 -4
- data/lib/async/http/proxy.rb +24 -8
- data/lib/async/http/server.rb +3 -3
- data/lib/async/http/version.rb +1 -1
- metadata +23 -65
- data/.editorconfig +0 -6
- data/.github/workflows/development.yml +0 -52
- data/.gitignore +0 -15
- data/.rspec +0 -3
- data/.travis.yml +0 -35
- data/README.md +0 -365
- data/async-http.gemspec +0 -39
- data/bake.rb +0 -0
- data/examples/compare/Gemfile +0 -9
- data/examples/compare/benchmark.rb +0 -78
- data/examples/download/chunked.rb +0 -86
- data/examples/fetch/Gemfile +0 -3
- data/examples/fetch/Gemfile.lock +0 -74
- data/examples/fetch/README.md +0 -3
- data/examples/fetch/config.ru +0 -28
- data/examples/fetch/public/index.html +0 -23
- data/examples/fetch/public/stream.js +0 -56
- data/examples/google/search.rb +0 -47
- data/examples/request.rb +0 -38
- data/examples/stream/stop.rb +0 -28
- data/examples/trenni/Gemfile +0 -5
- data/examples/trenni/streaming.rb +0 -35
- data/examples/upload/client.rb +0 -39
- data/examples/upload/data.txt +0 -41
- data/examples/upload/server.rb +0 -19
- data/examples/upload/upload.rb +0 -26
- data/gems.rb +0 -11
    
        data/async-http.gemspec
    DELETED
    
    | @@ -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
         | 
    
        data/examples/compare/Gemfile
    DELETED
    
    
| @@ -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
         | 
    
        data/examples/fetch/Gemfile
    DELETED
    
    
    
        data/examples/fetch/Gemfile.lock
    DELETED
    
    | @@ -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
         | 
    
        data/examples/fetch/README.md
    DELETED
    
    
    
        data/examples/fetch/config.ru
    DELETED
    
    | @@ -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 | 
            -
            	});
         | 
    
        data/examples/google/search.rb
    DELETED
    
    | @@ -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
         |