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.
Files changed (47) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/bake/async/http/h2spec.rb +4 -0
  4. data/bake/async/http.rb +4 -0
  5. data/lib/async/http/body/delayed.rb +4 -20
  6. data/lib/async/http/body/hijack.rb +3 -20
  7. data/lib/async/http/body/pipe.rb +4 -20
  8. data/lib/async/http/body/slowloris.rb +3 -20
  9. data/lib/async/http/body/writable.rb +3 -20
  10. data/lib/async/http/body.rb +3 -20
  11. data/lib/async/http/client.rb +6 -22
  12. data/lib/async/http/endpoint.rb +8 -20
  13. data/lib/async/http/internet/instance.rb +3 -20
  14. data/lib/async/http/internet.rb +3 -20
  15. data/lib/async/http/protocol/http1/client.rb +3 -20
  16. data/lib/async/http/protocol/http1/connection.rb +3 -20
  17. data/lib/async/http/protocol/http1/request.rb +3 -20
  18. data/lib/async/http/protocol/http1/response.rb +3 -20
  19. data/lib/async/http/protocol/http1/server.rb +4 -20
  20. data/lib/async/http/protocol/http1.rb +3 -20
  21. data/lib/async/http/protocol/http10.rb +3 -20
  22. data/lib/async/http/protocol/http11.rb +4 -20
  23. data/lib/async/http/protocol/http2/client.rb +3 -20
  24. data/lib/async/http/protocol/http2/connection.rb +11 -22
  25. data/lib/async/http/protocol/http2/input.rb +3 -20
  26. data/lib/async/http/protocol/http2/output.rb +3 -20
  27. data/lib/async/http/protocol/http2/request.rb +3 -20
  28. data/lib/async/http/protocol/http2/response.rb +3 -20
  29. data/lib/async/http/protocol/http2/server.rb +3 -20
  30. data/lib/async/http/protocol/http2/stream.rb +4 -20
  31. data/lib/async/http/protocol/http2.rb +3 -20
  32. data/lib/async/http/protocol/https.rb +4 -20
  33. data/lib/async/http/protocol/request.rb +3 -20
  34. data/lib/async/http/protocol/response.rb +3 -20
  35. data/lib/async/http/protocol.rb +3 -20
  36. data/lib/async/http/proxy.rb +3 -20
  37. data/lib/async/http/reference.rb +3 -20
  38. data/lib/async/http/relative_location.rb +5 -19
  39. data/lib/async/http/server.rb +6 -22
  40. data/lib/async/http/statistics.rb +3 -20
  41. data/lib/async/http/version.rb +4 -21
  42. data/lib/async/http.rb +3 -20
  43. data/license.md +37 -0
  44. data/readme.md +376 -0
  45. data.tar.gz.sig +0 -0
  46. metadata +10 -7
  47. 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
+ [![Development Status](https://github.com/socketry/async-http/workflows/Test/badge.svg)](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.0
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
- - TheAthlete
21
+ - Tim Meusel
21
22
  - Trevor Turk
22
- - samshadwell
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-02-02 00:00:00.000000000 Z
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.8.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.8.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.1
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