async-http 0.60.0 → 0.60.2
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
 - checksums.yaml.gz.sig +0 -0
 - data/bake/async/http/h2spec.rb +4 -0
 - data/bake/async/http.rb +4 -0
 - data/lib/async/http/body/delayed.rb +4 -20
 - data/lib/async/http/body/hijack.rb +3 -20
 - data/lib/async/http/body/pipe.rb +4 -20
 - data/lib/async/http/body/slowloris.rb +3 -20
 - data/lib/async/http/body/writable.rb +3 -20
 - data/lib/async/http/body.rb +3 -20
 - data/lib/async/http/client.rb +6 -22
 - data/lib/async/http/endpoint.rb +8 -20
 - data/lib/async/http/internet/instance.rb +3 -20
 - data/lib/async/http/internet.rb +3 -20
 - data/lib/async/http/protocol/http1/client.rb +3 -20
 - data/lib/async/http/protocol/http1/connection.rb +3 -20
 - data/lib/async/http/protocol/http1/request.rb +3 -20
 - data/lib/async/http/protocol/http1/response.rb +3 -20
 - data/lib/async/http/protocol/http1/server.rb +4 -20
 - data/lib/async/http/protocol/http1.rb +3 -20
 - data/lib/async/http/protocol/http10.rb +3 -20
 - data/lib/async/http/protocol/http11.rb +4 -20
 - data/lib/async/http/protocol/http2/client.rb +3 -20
 - data/lib/async/http/protocol/http2/connection.rb +11 -22
 - data/lib/async/http/protocol/http2/input.rb +3 -20
 - data/lib/async/http/protocol/http2/output.rb +3 -20
 - data/lib/async/http/protocol/http2/request.rb +3 -20
 - data/lib/async/http/protocol/http2/response.rb +3 -20
 - data/lib/async/http/protocol/http2/server.rb +3 -20
 - data/lib/async/http/protocol/http2/stream.rb +4 -20
 - data/lib/async/http/protocol/http2.rb +3 -20
 - data/lib/async/http/protocol/https.rb +4 -20
 - data/lib/async/http/protocol/request.rb +3 -20
 - data/lib/async/http/protocol/response.rb +3 -20
 - data/lib/async/http/protocol.rb +3 -20
 - data/lib/async/http/proxy.rb +3 -20
 - data/lib/async/http/reference.rb +3 -20
 - data/lib/async/http/relative_location.rb +5 -19
 - data/lib/async/http/server.rb +6 -22
 - data/lib/async/http/statistics.rb +3 -20
 - data/lib/async/http/version.rb +4 -21
 - data/lib/async/http.rb +3 -20
 - data/license.md +37 -0
 - data/readme.md +376 -0
 - data.tar.gz.sig +0 -0
 - metadata +10 -7
 - metadata.gz.sig +0 -0
 
    
        data/readme.md
    ADDED
    
    | 
         @@ -0,0 +1,376 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # Async::HTTP
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            An asynchronous client and server implementation of HTTP/1.0, HTTP/1.1 and HTTP/2 including TLS. Support for streaming requests and responses. Built on top of [async](https://github.com/socketry/async) and [async-io](https://github.com/socketry/async-io). [falcon](https://github.com/socketry/falcon) provides a rack-compatible server.
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
            [](https://github.com/socketry/async-http/actions?workflow=Test)
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
            ## Installation
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
            Add this line to your application's Gemfile:
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
            ``` ruby
         
     | 
| 
      
 12 
     | 
    
         
            +
            gem 'async-http'
         
     | 
| 
      
 13 
     | 
    
         
            +
            ```
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
            And then execute:
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
                $ bundle
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
            Or install it yourself as:
         
     | 
| 
      
 20 
     | 
    
         
            +
             
     | 
| 
      
 21 
     | 
    
         
            +
                $ gem install async-http
         
     | 
| 
      
 22 
     | 
    
         
            +
             
     | 
| 
      
 23 
     | 
    
         
            +
            ## Usage
         
     | 
| 
      
 24 
     | 
    
         
            +
             
     | 
| 
      
 25 
     | 
    
         
            +
            Please see the [project documentation](https://socketry.github.io/async-http/) or serve it locally using `bake utopia:project:serve`.
         
     | 
| 
      
 26 
     | 
    
         
            +
             
     | 
| 
      
 27 
     | 
    
         
            +
            ### Post JSON data
         
     | 
| 
      
 28 
     | 
    
         
            +
             
     | 
| 
      
 29 
     | 
    
         
            +
            Here is an example showing how to post a data structure as JSON to a remote resource:
         
     | 
| 
      
 30 
     | 
    
         
            +
             
     | 
| 
      
 31 
     | 
    
         
            +
            ``` ruby
         
     | 
| 
      
 32 
     | 
    
         
            +
            #!/usr/bin/env ruby
         
     | 
| 
      
 33 
     | 
    
         
            +
             
     | 
| 
      
 34 
     | 
    
         
            +
            require 'json'
         
     | 
| 
      
 35 
     | 
    
         
            +
            require 'async'
         
     | 
| 
      
 36 
     | 
    
         
            +
            require 'async/http/internet'
         
     | 
| 
      
 37 
     | 
    
         
            +
             
     | 
| 
      
 38 
     | 
    
         
            +
            data = {'life' => 42}
         
     | 
| 
      
 39 
     | 
    
         
            +
             
     | 
| 
      
 40 
     | 
    
         
            +
            Async do
         
     | 
| 
      
 41 
     | 
    
         
            +
            	# Make a new internet:
         
     | 
| 
      
 42 
     | 
    
         
            +
            	internet = Async::HTTP::Internet.new
         
     | 
| 
      
 43 
     | 
    
         
            +
            	
         
     | 
| 
      
 44 
     | 
    
         
            +
            	# Prepare the request:
         
     | 
| 
      
 45 
     | 
    
         
            +
            	headers = [['accept', 'application/json']]
         
     | 
| 
      
 46 
     | 
    
         
            +
            	body = [JSON.dump(data)]
         
     | 
| 
      
 47 
     | 
    
         
            +
            	
         
     | 
| 
      
 48 
     | 
    
         
            +
            	# Issues a POST request:
         
     | 
| 
      
 49 
     | 
    
         
            +
            	response = internet.post("https://httpbin.org/anything", headers, body)
         
     | 
| 
      
 50 
     | 
    
         
            +
            	
         
     | 
| 
      
 51 
     | 
    
         
            +
            	# Save the response body to a local file:
         
     | 
| 
      
 52 
     | 
    
         
            +
            	pp JSON.parse(response.read)
         
     | 
| 
      
 53 
     | 
    
         
            +
            ensure
         
     | 
| 
      
 54 
     | 
    
         
            +
            	# The internet is closed for business:
         
     | 
| 
      
 55 
     | 
    
         
            +
            	internet.close
         
     | 
| 
      
 56 
     | 
    
         
            +
            end
         
     | 
| 
      
 57 
     | 
    
         
            +
            ```
         
     | 
| 
      
 58 
     | 
    
         
            +
             
     | 
| 
      
 59 
     | 
    
         
            +
            Consider using [async-rest](https://github.com/socketry/async-rest) instead.
         
     | 
| 
      
 60 
     | 
    
         
            +
             
     | 
| 
      
 61 
     | 
    
         
            +
            ### Multiple Requests
         
     | 
| 
      
 62 
     | 
    
         
            +
             
     | 
| 
      
 63 
     | 
    
         
            +
            To issue multiple requests concurrently, you should use a barrier, e.g.
         
     | 
| 
      
 64 
     | 
    
         
            +
             
     | 
| 
      
 65 
     | 
    
         
            +
            ``` ruby
         
     | 
| 
      
 66 
     | 
    
         
            +
            #!/usr/bin/env ruby
         
     | 
| 
      
 67 
     | 
    
         
            +
             
     | 
| 
      
 68 
     | 
    
         
            +
            require 'async'
         
     | 
| 
      
 69 
     | 
    
         
            +
            require 'async/barrier'
         
     | 
| 
      
 70 
     | 
    
         
            +
            require 'async/http/internet'
         
     | 
| 
      
 71 
     | 
    
         
            +
             
     | 
| 
      
 72 
     | 
    
         
            +
            TOPICS = ["ruby", "python", "rust"]
         
     | 
| 
      
 73 
     | 
    
         
            +
             
     | 
| 
      
 74 
     | 
    
         
            +
            Async do
         
     | 
| 
      
 75 
     | 
    
         
            +
            	internet = Async::HTTP::Internet.new
         
     | 
| 
      
 76 
     | 
    
         
            +
            	barrier = Async::Barrier.new
         
     | 
| 
      
 77 
     | 
    
         
            +
            	
         
     | 
| 
      
 78 
     | 
    
         
            +
            	# Spawn an asynchronous task for each topic:
         
     | 
| 
      
 79 
     | 
    
         
            +
            	TOPICS.each do |topic|
         
     | 
| 
      
 80 
     | 
    
         
            +
            		barrier.async do
         
     | 
| 
      
 81 
     | 
    
         
            +
            			response = internet.get "https://www.google.com/search?q=#{topic}"
         
     | 
| 
      
 82 
     | 
    
         
            +
            			puts "Found #{topic}: #{response.read.scan(topic).size} times."
         
     | 
| 
      
 83 
     | 
    
         
            +
            		end
         
     | 
| 
      
 84 
     | 
    
         
            +
            	end
         
     | 
| 
      
 85 
     | 
    
         
            +
            	
         
     | 
| 
      
 86 
     | 
    
         
            +
            	# Ensure we wait for all requests to complete before continuing:
         
     | 
| 
      
 87 
     | 
    
         
            +
            	barrier.wait
         
     | 
| 
      
 88 
     | 
    
         
            +
            ensure
         
     | 
| 
      
 89 
     | 
    
         
            +
            	internet&.close
         
     | 
| 
      
 90 
     | 
    
         
            +
            end
         
     | 
| 
      
 91 
     | 
    
         
            +
            ```
         
     | 
| 
      
 92 
     | 
    
         
            +
             
     | 
| 
      
 93 
     | 
    
         
            +
            #### Limiting Requests
         
     | 
| 
      
 94 
     | 
    
         
            +
             
     | 
| 
      
 95 
     | 
    
         
            +
            If you need to limit the number of simultaneous requests, use a semaphore.
         
     | 
| 
      
 96 
     | 
    
         
            +
             
     | 
| 
      
 97 
     | 
    
         
            +
            ``` ruby
         
     | 
| 
      
 98 
     | 
    
         
            +
            #!/usr/bin/env ruby
         
     | 
| 
      
 99 
     | 
    
         
            +
             
     | 
| 
      
 100 
     | 
    
         
            +
            require 'async'
         
     | 
| 
      
 101 
     | 
    
         
            +
            require 'async/barrier'
         
     | 
| 
      
 102 
     | 
    
         
            +
            require 'async/semaphore'
         
     | 
| 
      
 103 
     | 
    
         
            +
            require 'async/http/internet'
         
     | 
| 
      
 104 
     | 
    
         
            +
             
     | 
| 
      
 105 
     | 
    
         
            +
            TOPICS = ["ruby", "python", "rust"]
         
     | 
| 
      
 106 
     | 
    
         
            +
             
     | 
| 
      
 107 
     | 
    
         
            +
            Async do
         
     | 
| 
      
 108 
     | 
    
         
            +
            	internet = Async::HTTP::Internet.new
         
     | 
| 
      
 109 
     | 
    
         
            +
            	barrier = Async::Barrier.new
         
     | 
| 
      
 110 
     | 
    
         
            +
            	semaphore = Async::Semaphore.new(2, parent: barrier)
         
     | 
| 
      
 111 
     | 
    
         
            +
            	
         
     | 
| 
      
 112 
     | 
    
         
            +
            	# Spawn an asynchronous task for each topic:
         
     | 
| 
      
 113 
     | 
    
         
            +
            	TOPICS.each do |topic|
         
     | 
| 
      
 114 
     | 
    
         
            +
            		semaphore.async do
         
     | 
| 
      
 115 
     | 
    
         
            +
            			response = internet.get "https://www.google.com/search?q=#{topic}"
         
     | 
| 
      
 116 
     | 
    
         
            +
            			puts "Found #{topic}: #{response.read.scan(topic).size} times."
         
     | 
| 
      
 117 
     | 
    
         
            +
            		end
         
     | 
| 
      
 118 
     | 
    
         
            +
            	end
         
     | 
| 
      
 119 
     | 
    
         
            +
            	
         
     | 
| 
      
 120 
     | 
    
         
            +
            	# Ensure we wait for all requests to complete before continuing:
         
     | 
| 
      
 121 
     | 
    
         
            +
            	barrier.wait
         
     | 
| 
      
 122 
     | 
    
         
            +
            ensure
         
     | 
| 
      
 123 
     | 
    
         
            +
            	internet&.close
         
     | 
| 
      
 124 
     | 
    
         
            +
            end
         
     | 
| 
      
 125 
     | 
    
         
            +
            ```
         
     | 
| 
      
 126 
     | 
    
         
            +
             
     | 
| 
      
 127 
     | 
    
         
            +
            ### Persistent Connections
         
     | 
| 
      
 128 
     | 
    
         
            +
             
     | 
| 
      
 129 
     | 
    
         
            +
            To keep connections alive, install the `thread-local` gem,
         
     | 
| 
      
 130 
     | 
    
         
            +
            require `async/http/internet/instance`, and use the `instance`, e.g.
         
     | 
| 
      
 131 
     | 
    
         
            +
             
     | 
| 
      
 132 
     | 
    
         
            +
            ``` ruby
         
     | 
| 
      
 133 
     | 
    
         
            +
            #!/usr/bin/env ruby
         
     | 
| 
      
 134 
     | 
    
         
            +
             
     | 
| 
      
 135 
     | 
    
         
            +
            require 'async'
         
     | 
| 
      
 136 
     | 
    
         
            +
            require 'async/http/internet/instance'
         
     | 
| 
      
 137 
     | 
    
         
            +
             
     | 
| 
      
 138 
     | 
    
         
            +
            Async do
         
     | 
| 
      
 139 
     | 
    
         
            +
              internet = Async::HTTP::Internet.instance
         
     | 
| 
      
 140 
     | 
    
         
            +
            	response = internet.get "https://www.google.com/search?q=test"
         
     | 
| 
      
 141 
     | 
    
         
            +
            	puts "Found #{response.read.size} results."
         
     | 
| 
      
 142 
     | 
    
         
            +
            end
         
     | 
| 
      
 143 
     | 
    
         
            +
            ```
         
     | 
| 
      
 144 
     | 
    
         
            +
             
     | 
| 
      
 145 
     | 
    
         
            +
            ### Downloading a File
         
     | 
| 
      
 146 
     | 
    
         
            +
             
     | 
| 
      
 147 
     | 
    
         
            +
            Here is an example showing how to download a file and save it to a local path:
         
     | 
| 
      
 148 
     | 
    
         
            +
             
     | 
| 
      
 149 
     | 
    
         
            +
            ``` ruby
         
     | 
| 
      
 150 
     | 
    
         
            +
            #!/usr/bin/env ruby
         
     | 
| 
      
 151 
     | 
    
         
            +
             
     | 
| 
      
 152 
     | 
    
         
            +
            require 'async'
         
     | 
| 
      
 153 
     | 
    
         
            +
            require 'async/http/internet'
         
     | 
| 
      
 154 
     | 
    
         
            +
             
     | 
| 
      
 155 
     | 
    
         
            +
            Async do
         
     | 
| 
      
 156 
     | 
    
         
            +
            	# Make a new internet:
         
     | 
| 
      
 157 
     | 
    
         
            +
            	internet = Async::HTTP::Internet.new
         
     | 
| 
      
 158 
     | 
    
         
            +
            	
         
     | 
| 
      
 159 
     | 
    
         
            +
            	# Issues a GET request to Google:
         
     | 
| 
      
 160 
     | 
    
         
            +
            	response = internet.get("https://www.google.com/search?q=kittens")
         
     | 
| 
      
 161 
     | 
    
         
            +
            	
         
     | 
| 
      
 162 
     | 
    
         
            +
            	# Save the response body to a local file:
         
     | 
| 
      
 163 
     | 
    
         
            +
            	response.save("/tmp/search.html")
         
     | 
| 
      
 164 
     | 
    
         
            +
            ensure
         
     | 
| 
      
 165 
     | 
    
         
            +
            	# The internet is closed for business:
         
     | 
| 
      
 166 
     | 
    
         
            +
            	internet.close
         
     | 
| 
      
 167 
     | 
    
         
            +
            end
         
     | 
| 
      
 168 
     | 
    
         
            +
            ```
         
     | 
| 
      
 169 
     | 
    
         
            +
             
     | 
| 
      
 170 
     | 
    
         
            +
            ### Basic Client/Server
         
     | 
| 
      
 171 
     | 
    
         
            +
             
     | 
| 
      
 172 
     | 
    
         
            +
            Here is a basic example of a client/server running in the same reactor:
         
     | 
| 
      
 173 
     | 
    
         
            +
             
     | 
| 
      
 174 
     | 
    
         
            +
            ``` ruby
         
     | 
| 
      
 175 
     | 
    
         
            +
            #!/usr/bin/env ruby
         
     | 
| 
      
 176 
     | 
    
         
            +
             
     | 
| 
      
 177 
     | 
    
         
            +
            require 'async'
         
     | 
| 
      
 178 
     | 
    
         
            +
            require 'async/http/server'
         
     | 
| 
      
 179 
     | 
    
         
            +
            require 'async/http/client'
         
     | 
| 
      
 180 
     | 
    
         
            +
            require 'async/http/endpoint'
         
     | 
| 
      
 181 
     | 
    
         
            +
            require 'async/http/protocol/response'
         
     | 
| 
      
 182 
     | 
    
         
            +
             
     | 
| 
      
 183 
     | 
    
         
            +
            endpoint = Async::HTTP::Endpoint.parse('http://127.0.0.1:9294')
         
     | 
| 
      
 184 
     | 
    
         
            +
             
     | 
| 
      
 185 
     | 
    
         
            +
            app = lambda do |request|
         
     | 
| 
      
 186 
     | 
    
         
            +
            	Protocol::HTTP::Response[200, {}, ["Hello World"]]
         
     | 
| 
      
 187 
     | 
    
         
            +
            end
         
     | 
| 
      
 188 
     | 
    
         
            +
             
     | 
| 
      
 189 
     | 
    
         
            +
            server = Async::HTTP::Server.new(app, endpoint)
         
     | 
| 
      
 190 
     | 
    
         
            +
            client = Async::HTTP::Client.new(endpoint)
         
     | 
| 
      
 191 
     | 
    
         
            +
            	
         
     | 
| 
      
 192 
     | 
    
         
            +
            Async do |task|
         
     | 
| 
      
 193 
     | 
    
         
            +
            	server_task = task.async do
         
     | 
| 
      
 194 
     | 
    
         
            +
            		server.run
         
     | 
| 
      
 195 
     | 
    
         
            +
            	end
         
     | 
| 
      
 196 
     | 
    
         
            +
            	
         
     | 
| 
      
 197 
     | 
    
         
            +
            	response = client.get("/")
         
     | 
| 
      
 198 
     | 
    
         
            +
            	
         
     | 
| 
      
 199 
     | 
    
         
            +
            	puts response.status
         
     | 
| 
      
 200 
     | 
    
         
            +
            	puts response.read
         
     | 
| 
      
 201 
     | 
    
         
            +
            	
         
     | 
| 
      
 202 
     | 
    
         
            +
            	server_task.stop
         
     | 
| 
      
 203 
     | 
    
         
            +
            end
         
     | 
| 
      
 204 
     | 
    
         
            +
            ```
         
     | 
| 
      
 205 
     | 
    
         
            +
             
     | 
| 
      
 206 
     | 
    
         
            +
            ### Advanced Verification
         
     | 
| 
      
 207 
     | 
    
         
            +
             
     | 
| 
      
 208 
     | 
    
         
            +
            You can hook into SSL certificate verification to improve server verification.
         
     | 
| 
      
 209 
     | 
    
         
            +
             
     | 
| 
      
 210 
     | 
    
         
            +
            ``` ruby
         
     | 
| 
      
 211 
     | 
    
         
            +
            require 'async'
         
     | 
| 
      
 212 
     | 
    
         
            +
            require 'async/http'
         
     | 
| 
      
 213 
     | 
    
         
            +
             
     | 
| 
      
 214 
     | 
    
         
            +
            # These are generated from the certificate chain that the server presented.
         
     | 
| 
      
 215 
     | 
    
         
            +
            trusted_fingerprints = {
         
     | 
| 
      
 216 
     | 
    
         
            +
            	"dac9024f54d8f6df94935fb1732638ca6ad77c13" => true,
         
     | 
| 
      
 217 
     | 
    
         
            +
            	"e6a3b45b062d509b3382282d196efe97d5956ccb" => true,
         
     | 
| 
      
 218 
     | 
    
         
            +
            	"07d63f4c05a03f1c306f9941b8ebf57598719ea2" => true,
         
     | 
| 
      
 219 
     | 
    
         
            +
            	"e8d994f44ff20dc78dbff4e59d7da93900572bbf" => true,
         
     | 
| 
      
 220 
     | 
    
         
            +
            }
         
     | 
| 
      
 221 
     | 
    
         
            +
             
     | 
| 
      
 222 
     | 
    
         
            +
            Async do
         
     | 
| 
      
 223 
     | 
    
         
            +
            	endpoint = Async::HTTP::Endpoint.parse("https://www.codeotaku.com/index")
         
     | 
| 
      
 224 
     | 
    
         
            +
            	
         
     | 
| 
      
 225 
     | 
    
         
            +
            	# This is a quick hack/POC:
         
     | 
| 
      
 226 
     | 
    
         
            +
            	ssl_context = endpoint.ssl_context
         
     | 
| 
      
 227 
     | 
    
         
            +
            	
         
     | 
| 
      
 228 
     | 
    
         
            +
            	ssl_context.verify_callback = proc do |verified, store_context|
         
     | 
| 
      
 229 
     | 
    
         
            +
            		certificate = store_context.current_cert
         
     | 
| 
      
 230 
     | 
    
         
            +
            		fingerprint = OpenSSL::Digest::SHA1.new(certificate.to_der).to_s
         
     | 
| 
      
 231 
     | 
    
         
            +
            		
         
     | 
| 
      
 232 
     | 
    
         
            +
            		if trusted_fingerprints.include? fingerprint
         
     | 
| 
      
 233 
     | 
    
         
            +
            			true
         
     | 
| 
      
 234 
     | 
    
         
            +
            		else
         
     | 
| 
      
 235 
     | 
    
         
            +
            			Console.logger.warn("Untrusted Certificate Fingerprint"){fingerprint}
         
     | 
| 
      
 236 
     | 
    
         
            +
            			false
         
     | 
| 
      
 237 
     | 
    
         
            +
            		end
         
     | 
| 
      
 238 
     | 
    
         
            +
            	end
         
     | 
| 
      
 239 
     | 
    
         
            +
            	
         
     | 
| 
      
 240 
     | 
    
         
            +
            	endpoint = endpoint.with(ssl_context: ssl_context)
         
     | 
| 
      
 241 
     | 
    
         
            +
            	
         
     | 
| 
      
 242 
     | 
    
         
            +
            	client = Async::HTTP::Client.new(endpoint)
         
     | 
| 
      
 243 
     | 
    
         
            +
            	
         
     | 
| 
      
 244 
     | 
    
         
            +
            	response = client.get(endpoint.path)
         
     | 
| 
      
 245 
     | 
    
         
            +
            	
         
     | 
| 
      
 246 
     | 
    
         
            +
            	pp response.status, response.headers.fields, response.read
         
     | 
| 
      
 247 
     | 
    
         
            +
            end
         
     | 
| 
      
 248 
     | 
    
         
            +
            ```
         
     | 
| 
      
 249 
     | 
    
         
            +
             
     | 
| 
      
 250 
     | 
    
         
            +
            ### Timeouts
         
     | 
| 
      
 251 
     | 
    
         
            +
             
     | 
| 
      
 252 
     | 
    
         
            +
            Here's a basic example with a timeout:
         
     | 
| 
      
 253 
     | 
    
         
            +
             
     | 
| 
      
 254 
     | 
    
         
            +
            ``` ruby
         
     | 
| 
      
 255 
     | 
    
         
            +
            #!/usr/bin/env ruby
         
     | 
| 
      
 256 
     | 
    
         
            +
             
     | 
| 
      
 257 
     | 
    
         
            +
            require 'async/http/internet'
         
     | 
| 
      
 258 
     | 
    
         
            +
             
     | 
| 
      
 259 
     | 
    
         
            +
            Async do |task|
         
     | 
| 
      
 260 
     | 
    
         
            +
            	internet = Async::HTTP::Internet.new
         
     | 
| 
      
 261 
     | 
    
         
            +
            	
         
     | 
| 
      
 262 
     | 
    
         
            +
            	# Request will timeout after 2 seconds
         
     | 
| 
      
 263 
     | 
    
         
            +
            	task.with_timeout(2) do
         
     | 
| 
      
 264 
     | 
    
         
            +
            		response = internet.get "https://httpbin.org/delay/10"
         
     | 
| 
      
 265 
     | 
    
         
            +
            	end
         
     | 
| 
      
 266 
     | 
    
         
            +
            rescue Async::TimeoutError
         
     | 
| 
      
 267 
     | 
    
         
            +
            	puts "The request timed out"
         
     | 
| 
      
 268 
     | 
    
         
            +
            ensure
         
     | 
| 
      
 269 
     | 
    
         
            +
            	internet&.close
         
     | 
| 
      
 270 
     | 
    
         
            +
            end
         
     | 
| 
      
 271 
     | 
    
         
            +
            ```
         
     | 
| 
      
 272 
     | 
    
         
            +
             
     | 
| 
      
 273 
     | 
    
         
            +
            ## Performance
         
     | 
| 
      
 274 
     | 
    
         
            +
             
     | 
| 
      
 275 
     | 
    
         
            +
            On a 4-core 8-thread i7, running `ab` which uses discrete (non-keep-alive) connections:
         
     | 
| 
      
 276 
     | 
    
         
            +
             
     | 
| 
      
 277 
     | 
    
         
            +
                $ ab -c 8 -t 10 http://127.0.0.1:9294/
         
     | 
| 
      
 278 
     | 
    
         
            +
                This is ApacheBench, Version 2.3 <$Revision: 1757674 $>
         
     | 
| 
      
 279 
     | 
    
         
            +
                Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
         
     | 
| 
      
 280 
     | 
    
         
            +
                Licensed to The Apache Software Foundation, http://www.apache.org/
         
     | 
| 
      
 281 
     | 
    
         
            +
                
         
     | 
| 
      
 282 
     | 
    
         
            +
                Benchmarking 127.0.0.1 (be patient)
         
     | 
| 
      
 283 
     | 
    
         
            +
                Completed 5000 requests
         
     | 
| 
      
 284 
     | 
    
         
            +
                Completed 10000 requests
         
     | 
| 
      
 285 
     | 
    
         
            +
                Completed 15000 requests
         
     | 
| 
      
 286 
     | 
    
         
            +
                Completed 20000 requests
         
     | 
| 
      
 287 
     | 
    
         
            +
                Completed 25000 requests
         
     | 
| 
      
 288 
     | 
    
         
            +
                Completed 30000 requests
         
     | 
| 
      
 289 
     | 
    
         
            +
                Completed 35000 requests
         
     | 
| 
      
 290 
     | 
    
         
            +
                Completed 40000 requests
         
     | 
| 
      
 291 
     | 
    
         
            +
                Completed 45000 requests
         
     | 
| 
      
 292 
     | 
    
         
            +
                Completed 50000 requests
         
     | 
| 
      
 293 
     | 
    
         
            +
                Finished 50000 requests
         
     | 
| 
      
 294 
     | 
    
         
            +
                
         
     | 
| 
      
 295 
     | 
    
         
            +
                
         
     | 
| 
      
 296 
     | 
    
         
            +
                Server Software:        
         
     | 
| 
      
 297 
     | 
    
         
            +
                Server Hostname:        127.0.0.1
         
     | 
| 
      
 298 
     | 
    
         
            +
                Server Port:            9294
         
     | 
| 
      
 299 
     | 
    
         
            +
                
         
     | 
| 
      
 300 
     | 
    
         
            +
                Document Path:          /
         
     | 
| 
      
 301 
     | 
    
         
            +
                Document Length:        13 bytes
         
     | 
| 
      
 302 
     | 
    
         
            +
                
         
     | 
| 
      
 303 
     | 
    
         
            +
                Concurrency Level:      8
         
     | 
| 
      
 304 
     | 
    
         
            +
                Time taken for tests:   1.869 seconds
         
     | 
| 
      
 305 
     | 
    
         
            +
                Complete requests:      50000
         
     | 
| 
      
 306 
     | 
    
         
            +
                Failed requests:        0
         
     | 
| 
      
 307 
     | 
    
         
            +
                Total transferred:      2450000 bytes
         
     | 
| 
      
 308 
     | 
    
         
            +
                HTML transferred:       650000 bytes
         
     | 
| 
      
 309 
     | 
    
         
            +
                Requests per second:    26755.55 [#/sec] (mean)
         
     | 
| 
      
 310 
     | 
    
         
            +
                Time per request:       0.299 [ms] (mean)
         
     | 
| 
      
 311 
     | 
    
         
            +
                Time per request:       0.037 [ms] (mean, across all concurrent requests)
         
     | 
| 
      
 312 
     | 
    
         
            +
                Transfer rate:          1280.29 [Kbytes/sec] received
         
     | 
| 
      
 313 
     | 
    
         
            +
                
         
     | 
| 
      
 314 
     | 
    
         
            +
                Connection Times (ms)
         
     | 
| 
      
 315 
     | 
    
         
            +
                              min  mean[+/-sd] median   max
         
     | 
| 
      
 316 
     | 
    
         
            +
                Connect:        0    0   0.0      0       0
         
     | 
| 
      
 317 
     | 
    
         
            +
                Processing:     0    0   0.2      0       6
         
     | 
| 
      
 318 
     | 
    
         
            +
                Waiting:        0    0   0.2      0       6
         
     | 
| 
      
 319 
     | 
    
         
            +
                Total:          0    0   0.2      0       6
         
     | 
| 
      
 320 
     | 
    
         
            +
                
         
     | 
| 
      
 321 
     | 
    
         
            +
                Percentage of the requests served within a certain time (ms)
         
     | 
| 
      
 322 
     | 
    
         
            +
                  50%      0
         
     | 
| 
      
 323 
     | 
    
         
            +
                  66%      0
         
     | 
| 
      
 324 
     | 
    
         
            +
                  75%      0
         
     | 
| 
      
 325 
     | 
    
         
            +
                  80%      0
         
     | 
| 
      
 326 
     | 
    
         
            +
                  90%      0
         
     | 
| 
      
 327 
     | 
    
         
            +
                  95%      1
         
     | 
| 
      
 328 
     | 
    
         
            +
                  98%      1
         
     | 
| 
      
 329 
     | 
    
         
            +
                  99%      1
         
     | 
| 
      
 330 
     | 
    
         
            +
                 100%      6 (longest request)
         
     | 
| 
      
 331 
     | 
    
         
            +
             
     | 
| 
      
 332 
     | 
    
         
            +
            On a 4-core 8-thread i7, running `wrk`, which uses 8 keep-alive connections:
         
     | 
| 
      
 333 
     | 
    
         
            +
             
     | 
| 
      
 334 
     | 
    
         
            +
                $ wrk -c 8 -d 10 -t 8 http://127.0.0.1:9294/
         
     | 
| 
      
 335 
     | 
    
         
            +
                Running 10s test @ http://127.0.0.1:9294/
         
     | 
| 
      
 336 
     | 
    
         
            +
                  8 threads and 8 connections
         
     | 
| 
      
 337 
     | 
    
         
            +
                  Thread Stats   Avg      Stdev     Max   +/- Stdev
         
     | 
| 
      
 338 
     | 
    
         
            +
                    Latency   217.69us    0.99ms  23.21ms   97.39%
         
     | 
| 
      
 339 
     | 
    
         
            +
                    Req/Sec    12.18k     1.58k   17.67k    83.21%
         
     | 
| 
      
 340 
     | 
    
         
            +
                  974480 requests in 10.10s, 60.41MB read
         
     | 
| 
      
 341 
     | 
    
         
            +
                Requests/sec:  96485.00
         
     | 
| 
      
 342 
     | 
    
         
            +
                Transfer/sec:      5.98MB
         
     | 
| 
      
 343 
     | 
    
         
            +
             
     | 
| 
      
 344 
     | 
    
         
            +
            According to these results, the cost of handling connections is quite high, while general throughput seems pretty decent.
         
     | 
| 
      
 345 
     | 
    
         
            +
             
     | 
| 
      
 346 
     | 
    
         
            +
            ## Semantic Model
         
     | 
| 
      
 347 
     | 
    
         
            +
             
     | 
| 
      
 348 
     | 
    
         
            +
            ### Scheme
         
     | 
| 
      
 349 
     | 
    
         
            +
             
     | 
| 
      
 350 
     | 
    
         
            +
            HTTP/1 has an implicit scheme determined by the kind of connection made to the server (either `http` or `https`), while HTTP/2 models this explicitly and the client indicates this in the request using the `:scheme` pseudo-header (typically `https`). To normalize this, `Async::HTTP::Client` and `Async::HTTP::Server` have a default scheme which is used if none is supplied.
         
     | 
| 
      
 351 
     | 
    
         
            +
             
     | 
| 
      
 352 
     | 
    
         
            +
            ### Version
         
     | 
| 
      
 353 
     | 
    
         
            +
             
     | 
| 
      
 354 
     | 
    
         
            +
            HTTP/1 has an explicit version while HTTP/2 does not expose the version in any way.
         
     | 
| 
      
 355 
     | 
    
         
            +
             
     | 
| 
      
 356 
     | 
    
         
            +
            ### Reason
         
     | 
| 
      
 357 
     | 
    
         
            +
             
     | 
| 
      
 358 
     | 
    
         
            +
            HTTP/1 responses contain a reason field which is largely irrelevant. HTTP/2 does not support this field.
         
     | 
| 
      
 359 
     | 
    
         
            +
             
     | 
| 
      
 360 
     | 
    
         
            +
            ## Contributing
         
     | 
| 
      
 361 
     | 
    
         
            +
             
     | 
| 
      
 362 
     | 
    
         
            +
            We welcome contributions to this project.
         
     | 
| 
      
 363 
     | 
    
         
            +
             
     | 
| 
      
 364 
     | 
    
         
            +
            1.  Fork it.
         
     | 
| 
      
 365 
     | 
    
         
            +
            2.  Create your feature branch (`git checkout -b my-new-feature`).
         
     | 
| 
      
 366 
     | 
    
         
            +
            3.  Commit your changes (`git commit -am 'Add some feature'`).
         
     | 
| 
      
 367 
     | 
    
         
            +
            4.  Push to the branch (`git push origin my-new-feature`).
         
     | 
| 
      
 368 
     | 
    
         
            +
            5.  Create new Pull Request.
         
     | 
| 
      
 369 
     | 
    
         
            +
             
     | 
| 
      
 370 
     | 
    
         
            +
            ## See Also
         
     | 
| 
      
 371 
     | 
    
         
            +
             
     | 
| 
      
 372 
     | 
    
         
            +
              - [benchmark-http](https://github.com/socketry/benchmark-http) — A benchmarking tool to report on web server concurrency.
         
     | 
| 
      
 373 
     | 
    
         
            +
              - [falcon](https://github.com/socketry/falcon) — A rack compatible server built on top of `async-http`.
         
     | 
| 
      
 374 
     | 
    
         
            +
              - [async-websocket](https://github.com/socketry/async-websocket) — Asynchronous client and server websockets.
         
     | 
| 
      
 375 
     | 
    
         
            +
              - [async-rest](https://github.com/socketry/async-rest) — A RESTful resource layer built on top of `async-http`.
         
     | 
| 
      
 376 
     | 
    
         
            +
              - [async-http-faraday](https://github.com/socketry/async-http-faraday) — A faraday adapter to use `async-http`.
         
     | 
    
        data.tar.gz.sig
    CHANGED
    
    | 
         Binary file 
     | 
    
        metadata
    CHANGED
    
    | 
         @@ -1,7 +1,7 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            --- !ruby/object:Gem::Specification
         
     | 
| 
       2 
2 
     | 
    
         
             
            name: async-http
         
     | 
| 
       3 
3 
     | 
    
         
             
            version: !ruby/object:Gem::Version
         
     | 
| 
       4 
     | 
    
         
            -
              version: 0.60. 
     | 
| 
      
 4 
     | 
    
         
            +
              version: 0.60.2
         
     | 
| 
       5 
5 
     | 
    
         
             
            platform: ruby
         
     | 
| 
       6 
6 
     | 
    
         
             
            authors:
         
     | 
| 
       7 
7 
     | 
    
         
             
            - Samuel Williams
         
     | 
| 
         @@ -16,10 +16,11 @@ authors: 
     | 
|
| 
       16 
16 
     | 
    
         
             
            - Marco Concetto Rudilosso
         
     | 
| 
       17 
17 
     | 
    
         
             
            - Olle Jonsson
         
     | 
| 
       18 
18 
     | 
    
         
             
            - Orgad Shaneh
         
     | 
| 
      
 19 
     | 
    
         
            +
            - Sam Shadwell
         
     | 
| 
       19 
20 
     | 
    
         
             
            - Stefan Wrobel
         
     | 
| 
       20 
     | 
    
         
            -
            -  
     | 
| 
      
 21 
     | 
    
         
            +
            - Tim Meusel
         
     | 
| 
       21 
22 
     | 
    
         
             
            - Trevor Turk
         
     | 
| 
       22 
     | 
    
         
            -
            -  
     | 
| 
      
 23 
     | 
    
         
            +
            - Viacheslav Koval
         
     | 
| 
       23 
24 
     | 
    
         
             
            autorequire:
         
     | 
| 
       24 
25 
     | 
    
         
             
            bindir: bin
         
     | 
| 
       25 
26 
     | 
    
         
             
            cert_chain:
         
     | 
| 
         @@ -52,7 +53,7 @@ cert_chain: 
     | 
|
| 
       52 
53 
     | 
    
         
             
              Q2K9NVun/S785AP05vKkXZEFYxqG6EW012U4oLcFl5MySFajYXRYbuUpH6AY+HP8
         
     | 
| 
       53 
54 
     | 
    
         
             
              voD0MPg1DssDLKwXyt1eKD/+Fq0bFWhwVM/1XiAXL7lyYUyOq24KHgQ2Csg=
         
     | 
| 
       54 
55 
     | 
    
         
             
              -----END CERTIFICATE-----
         
     | 
| 
       55 
     | 
    
         
            -
            date: 2023- 
     | 
| 
      
 56 
     | 
    
         
            +
            date: 2023-06-19 00:00:00.000000000 Z
         
     | 
| 
       56 
57 
     | 
    
         
             
            dependencies:
         
     | 
| 
       57 
58 
     | 
    
         
             
            - !ruby/object:Gem::Dependency
         
     | 
| 
       58 
59 
     | 
    
         
             
              name: async
         
     | 
| 
         @@ -144,14 +145,14 @@ dependencies: 
     | 
|
| 
       144 
145 
     | 
    
         
             
                requirements:
         
     | 
| 
       145 
146 
     | 
    
         
             
                - - ">="
         
     | 
| 
       146 
147 
     | 
    
         
             
                  - !ruby/object:Gem::Version
         
     | 
| 
       147 
     | 
    
         
            -
                    version: 0. 
     | 
| 
      
 148 
     | 
    
         
            +
                    version: 0.10.0
         
     | 
| 
       148 
149 
     | 
    
         
             
              type: :runtime
         
     | 
| 
       149 
150 
     | 
    
         
             
              prerelease: false
         
     | 
| 
       150 
151 
     | 
    
         
             
              version_requirements: !ruby/object:Gem::Requirement
         
     | 
| 
       151 
152 
     | 
    
         
             
                requirements:
         
     | 
| 
       152 
153 
     | 
    
         
             
                - - ">="
         
     | 
| 
       153 
154 
     | 
    
         
             
                  - !ruby/object:Gem::Version
         
     | 
| 
       154 
     | 
    
         
            -
                    version: 0. 
     | 
| 
      
 155 
     | 
    
         
            +
                    version: 0.10.0
         
     | 
| 
       155 
156 
     | 
    
         
             
            - !ruby/object:Gem::Dependency
         
     | 
| 
       156 
157 
     | 
    
         
             
              name: async-container
         
     | 
| 
       157 
158 
     | 
    
         
             
              requirement: !ruby/object:Gem::Requirement
         
     | 
| 
         @@ -282,6 +283,8 @@ files: 
     | 
|
| 
       282 
283 
     | 
    
         
             
            - lib/async/http/server.rb
         
     | 
| 
       283 
284 
     | 
    
         
             
            - lib/async/http/statistics.rb
         
     | 
| 
       284 
285 
     | 
    
         
             
            - lib/async/http/version.rb
         
     | 
| 
      
 286 
     | 
    
         
            +
            - license.md
         
     | 
| 
      
 287 
     | 
    
         
            +
            - readme.md
         
     | 
| 
       285 
288 
     | 
    
         
             
            homepage: https://github.com/socketry/async-http
         
     | 
| 
       286 
289 
     | 
    
         
             
            licenses:
         
     | 
| 
       287 
290 
     | 
    
         
             
            - MIT
         
     | 
| 
         @@ -301,7 +304,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement 
     | 
|
| 
       301 
304 
     | 
    
         
             
                - !ruby/object:Gem::Version
         
     | 
| 
       302 
305 
     | 
    
         
             
                  version: '0'
         
     | 
| 
       303 
306 
     | 
    
         
             
            requirements: []
         
     | 
| 
       304 
     | 
    
         
            -
            rubygems_version: 3.4. 
     | 
| 
      
 307 
     | 
    
         
            +
            rubygems_version: 3.4.7
         
     | 
| 
       305 
308 
     | 
    
         
             
            signing_key:
         
     | 
| 
       306 
309 
     | 
    
         
             
            specification_version: 4
         
     | 
| 
       307 
310 
     | 
    
         
             
            summary: A HTTP client and server library.
         
     | 
    
        metadata.gz.sig
    CHANGED
    
    | 
         Binary file 
     |