async-http 0.18.0 → 0.19.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 283dedfc7cd41922f947682aa3f542ccd5368497a6380602de87c6e38eadd4e0
4
- data.tar.gz: cb1671a0bd33170eae0c826f081ccf5581135cc07724fd45cc9930186fc83d89
3
+ metadata.gz: dd03fb46876ed4121fa2232b18de6ec00e7176a6c224adf8d5001ec53cf89f1c
4
+ data.tar.gz: c42bf8f085ad74ee4fbc6b15c47bcb06915a41f42d3a48d58d39a43f695b267d
5
5
  SHA512:
6
- metadata.gz: 01a9422366d59623c93e7a3e17969bfb8d66b2e6213a54f4ef14bbb81d9a23de7e90f8e16dde950630ee2053bf8f7533ea47fcd404cece57de51ee3027e872cb
7
- data.tar.gz: c20d43c98c4febc062c3e94d0accb04df7a0dc8ddd08b2a83c45d1042b6229bb210f674288cca4f437d57f210255f0fd9ef720c8f2cfedd24c8886625a7193fb
6
+ metadata.gz: 7be71154d37d575a6c7b19c7d2c5b81b98e513d260a5d15c9d4c8e0a7fbaf3285d99ca7dc4030e9567af159ff73f4dc25c6144dd55e1745ae307898d0f6c8c9f
7
+ data.tar.gz: bb5748a2d385ce8528b218246a5a701d1c8fb1b45d1b40c2d9ce8e559b023c9c032c1ef396cc930c101278e56ddd2a57280e9e16d77df4eca1bfbc09c99e4caf
data/async-http.gemspec CHANGED
@@ -16,7 +16,7 @@ Gem::Specification.new do |spec|
16
16
  spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
17
17
  spec.require_paths = ["lib"]
18
18
 
19
- spec.add_dependency("async", "~> 1.5")
19
+ spec.add_dependency("async", "~> 1.6")
20
20
  spec.add_dependency("async-io", "~> 1.7")
21
21
 
22
22
  spec.add_dependency("http-2", "~> 0.8")
@@ -0,0 +1,65 @@
1
+ # Copyright, 2017, by Samuel G. D. Williams. <http://www.codeotaku.com>
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ # of this software and associated documentation files (the "Software"), to deal
5
+ # in the Software without restriction, including without limitation the rights
6
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ # copies of the Software, and to permit persons to whom the Software is
8
+ # furnished to do so, subject to the following conditions:
9
+ #
10
+ # The above copyright notice and this permission notice shall be included in
11
+ # all copies or substantial portions of the Software.
12
+ #
13
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ # THE SOFTWARE.
20
+
21
+ require_relative 'middleware'
22
+
23
+ require_relative 'body/buffered'
24
+ require_relative 'body/inflate'
25
+
26
+ module Async
27
+ module HTTP
28
+ # Set a valid accept-encoding header and decode the response.
29
+ class AcceptEncoding < Middleware
30
+ DEFAULT_WRAPPERS = {
31
+ 'gzip' => Body::Inflate.method(:for)
32
+ }
33
+
34
+ def initialize(app, wrappers = DEFAULT_WRAPPERS)
35
+ super(app)
36
+
37
+ @accept_encoding = wrappers.keys.join(', ')
38
+ @wrappers = wrappers
39
+ end
40
+
41
+ def call(request, *)
42
+ request.headers['accept-encoding'] = @accept_encoding
43
+
44
+ response = super
45
+
46
+ if !response.body.empty? and content_encoding = response.headers['content-encoding']
47
+ encodings = content_encoding.split(/\s*,\s*/)
48
+
49
+ body = response.body
50
+
51
+ # We want to unwrap all encodings
52
+ encodings.reverse_each do |name|
53
+ if wrapper = @wrappers[name]
54
+ body = wrapper.call(body)
55
+ end
56
+ end
57
+
58
+ response.body = body
59
+ end
60
+
61
+ return response
62
+ end
63
+ end
64
+ end
65
+ end
@@ -18,247 +18,5 @@
18
18
  # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
19
  # THE SOFTWARE.
20
20
 
21
- require 'async/queue'
22
-
23
- module Async
24
- module HTTP
25
- class Body
26
- def initialize
27
- @queue = Async::Queue.new
28
-
29
- @finished = false
30
- @stopped = false
31
- end
32
-
33
- # Read all chunks until the stream is closed.
34
- def close
35
- BufferedBody.for(self)
36
- end
37
-
38
- # Have all chunks been read?
39
- def finished?
40
- @finished
41
- end
42
-
43
- # Enumerate all chunks until finished.
44
- def each
45
- return to_enum unless block_given?
46
-
47
- return if @finished
48
-
49
- while chunk = @queue.dequeue
50
- yield chunk
51
- end
52
- rescue
53
- # Stop the stream because the remote end is no longer reading from it. Any attempt to write to the stream will fail.
54
- @stopped = $!
55
-
56
- raise
57
- ensure
58
- @finished = true
59
- end
60
-
61
- # Read the next available chunk.
62
- def read
63
- return if @finished
64
-
65
- unless chunk = @queue.dequeue
66
- @finished = true
67
- end
68
-
69
- return chunk
70
- end
71
-
72
- # Read all remaining chunks into a single binary string.
73
- def join
74
- buffer = Async::IO::BinaryString.new
75
-
76
- self.each do |chunk|
77
- buffer << chunk
78
- end
79
-
80
- return buffer
81
- end
82
-
83
- # Write a single chunk to the body. Signal completion by calling `#finish`.
84
- def write(chunk)
85
- if @stopped
86
- raise @stopped
87
- end
88
-
89
- # TODO should this yield if the queue is full?
90
-
91
- @queue.enqueue(chunk)
92
- end
93
-
94
- # Signal that output has finished.
95
- def finish
96
- @queue.enqueue(nil)
97
- end
98
- end
99
-
100
- class BufferedBody
101
- def self.for(body)
102
- chunks = []
103
-
104
- body.each do |chunk|
105
- chunks << chunk
106
- end
107
-
108
- self.new(chunks)
109
- end
110
-
111
- def initialize(chunks)
112
- @chunks = chunks
113
- @index = 0
114
- end
115
-
116
- def close
117
- self
118
- end
119
-
120
- def each(&block)
121
- while @index < @chunks.count
122
- yield @chunks[@index]
123
- @index += 1
124
- end
125
- end
126
-
127
- def read
128
- if chunk = @chunks[@index]
129
- @index += 1
130
- end
131
-
132
- return chunk
133
- end
134
-
135
- def join
136
- buffer = Async::IO::BinaryString.new
137
-
138
- self.each do |chunk|
139
- buffer << chunk
140
- end
141
-
142
- return buffer
143
- end
144
-
145
- def rewind
146
- @index = 0
147
- end
148
-
149
- def finished?
150
- true
151
- end
152
-
153
- module Reader
154
- def read
155
- self.body ? self.body.join : nil
156
- end
157
-
158
- def finish
159
- return if self.body.nil?
160
-
161
- self.body = self.body.close
162
- end
163
- end
164
- end
165
-
166
- class ChunkedBody
167
- def initialize(protocol)
168
- @protocol = protocol
169
- @finished = false
170
- end
171
-
172
- def close
173
- BufferedBody.for(self)
174
- end
175
-
176
- def finished?
177
- @finished
178
- end
179
-
180
- def read
181
- return nil if @finished
182
-
183
- size = @protocol.read_line.to_i(16)
184
-
185
- if size == 0
186
- @protocol.read_line
187
-
188
- @finished = true
189
-
190
- return nil
191
- end
192
-
193
- chunk = @protocol.stream.read(size)
194
- @protocol.read_line # Consume the trailing CRLF
195
-
196
- return chunk
197
- end
198
-
199
- def each
200
- while chunk = self.read
201
- yield chunk
202
- end
203
- end
204
-
205
- def join
206
- buffer = Async::IO::BinaryString.new
207
-
208
- self.each do |chunk|
209
- buffer << chunk
210
- end
211
-
212
- return buffer
213
- end
214
-
215
- def finish
216
- self.each {}
217
- end
218
- end
219
-
220
- class FixedBody
221
- def initialize(length, stream)
222
- @length = length
223
- @remaining = length
224
- @stream = stream
225
- end
226
-
227
- def close
228
- BufferedBody.for(self)
229
- end
230
-
231
- def finished?
232
- @remaining == 0
233
- end
234
-
235
- def each
236
- while chunk = self.read
237
- yield chunk
238
- end
239
- end
240
-
241
- def read
242
- if @remaining > 0
243
- if chunk = @stream.read(@remaining)
244
- @remaining -= chunk.bytesize
245
-
246
- return chunk
247
- end
248
- end
249
- end
250
-
251
- def join
252
- buffer = @stream.read(@remaining)
253
-
254
- @remaining = 0
255
-
256
- return buffer
257
- end
258
-
259
- def finish
260
- read
261
- end
262
- end
263
- end
264
- end
21
+ require_relative 'body/writable'
22
+ require_relative 'body/buffered'
@@ -0,0 +1,107 @@
1
+ # Copyright, 2018, by Samuel G. D. Williams. <http://www.codeotaku.com>
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ # of this software and associated documentation files (the "Software"), to deal
5
+ # in the Software without restriction, including without limitation the rights
6
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ # copies of the Software, and to permit persons to whom the Software is
8
+ # furnished to do so, subject to the following conditions:
9
+ #
10
+ # The above copyright notice and this permission notice shall be included in
11
+ # all copies or substantial portions of the Software.
12
+ #
13
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ # THE SOFTWARE.
20
+
21
+ require_relative 'readable'
22
+
23
+ module Async
24
+ module HTTP
25
+ module Body
26
+ # A body which buffers all it's contents.
27
+ class Buffered < Readable
28
+ # Wraps an array into a buffered body.
29
+ def self.wrap(body)
30
+ if body.is_a? Async::HTTP::Body::Readable
31
+ return body
32
+ elsif body.is_a? Array
33
+ return self.new(body)
34
+ else
35
+ return self.for(body)
36
+ end
37
+ end
38
+
39
+ def self.for(body)
40
+ chunks = []
41
+
42
+ body.each do |chunk|
43
+ chunks << chunk
44
+ end
45
+
46
+ self.new(chunks)
47
+ end
48
+
49
+ def initialize(chunks)
50
+ @chunks = chunks
51
+ @bytesize = nil
52
+
53
+ @index = 0
54
+ end
55
+
56
+ def bytesize
57
+ @bytesize ||= @chunks.inject(0) {|sum, chunk| sum + chunk.bytesize}
58
+ end
59
+
60
+ def empty?
61
+ @chunks.empty?
62
+ end
63
+
64
+ def close
65
+ self
66
+ end
67
+
68
+ def each
69
+ return to_enum unless block_given?
70
+
71
+ while @index < @chunks.count
72
+ yield @chunks[@index]
73
+ @index += 1
74
+ end
75
+ end
76
+
77
+ def read
78
+ if chunk = @chunks[@index]
79
+ @index += 1
80
+ end
81
+
82
+ return chunk
83
+ end
84
+
85
+ def rewind
86
+ @index = 0
87
+ end
88
+
89
+ def inspect
90
+ "\#<#{self.class} #{@chunks.count} chunks, #{self.bytesize} bytes>"
91
+ end
92
+
93
+ module Reader
94
+ def read
95
+ self.body ? self.body.join : nil
96
+ end
97
+
98
+ def finish
99
+ return if self.body.nil?
100
+
101
+ self.body = self.body.close
102
+ end
103
+ end
104
+ end
105
+ end
106
+ end
107
+ end
@@ -0,0 +1,67 @@
1
+ # Copyright, 2018, by Samuel G. D. Williams. <http://www.codeotaku.com>
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ # of this software and associated documentation files (the "Software"), to deal
5
+ # in the Software without restriction, including without limitation the rights
6
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ # copies of the Software, and to permit persons to whom the Software is
8
+ # furnished to do so, subject to the following conditions:
9
+ #
10
+ # The above copyright notice and this permission notice shall be included in
11
+ # all copies or substantial portions of the Software.
12
+ #
13
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ # THE SOFTWARE.
20
+
21
+ require_relative 'readable'
22
+
23
+ module Async
24
+ module HTTP
25
+ module Body
26
+ class Chunked < Readable
27
+ def initialize(protocol)
28
+ @protocol = protocol
29
+ @finished = false
30
+
31
+ @bytesize = 0
32
+ @count = 0
33
+ end
34
+
35
+ def empty?
36
+ @finished
37
+ end
38
+
39
+ def read
40
+ return nil if @finished
41
+
42
+ size = @protocol.read_line.to_i(16)
43
+
44
+ if size == 0
45
+ @protocol.read_line
46
+
47
+ @finished = true
48
+
49
+ return nil
50
+ end
51
+
52
+ chunk = @protocol.stream.read(size)
53
+ @protocol.read_line # Consume the trailing CRLF
54
+
55
+ @bytesize += size
56
+ @count += 1
57
+
58
+ return chunk
59
+ end
60
+
61
+ def inspect
62
+ "\#<#{self.class} #{@bytesize} bytes read in #{@count} chunks>"
63
+ end
64
+ end
65
+ end
66
+ end
67
+ end