protocol-http 0.23.11 → 0.24.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data/design.md +167 -0
- data/lib/protocol/http/accept_encoding.rb +5 -20
- data/lib/protocol/http/body/buffered.rb +3 -19
- data/lib/protocol/http/body/completable.rb +2 -19
- data/lib/protocol/http/body/deflate.rb +9 -30
- data/lib/protocol/http/body/digestable.rb +13 -21
- data/lib/protocol/http/body/file.rb +8 -21
- data/lib/protocol/http/body/head.rb +3 -20
- data/lib/protocol/http/body/inflate.rb +12 -22
- data/lib/protocol/http/body/readable.rb +6 -23
- data/lib/protocol/http/body/reader.rb +5 -21
- data/lib/protocol/http/body/rewindable.rb +6 -19
- data/lib/protocol/http/body/stream.rb +7 -24
- data/lib/protocol/http/body/wrapper.rb +2 -19
- data/lib/protocol/http/content_encoding.rb +2 -19
- data/lib/protocol/http/cookie.rb +3 -19
- data/lib/protocol/http/error.rb +2 -19
- data/lib/protocol/http/header/authorization.rb +2 -19
- data/lib/protocol/http/header/cache_control.rb +4 -21
- data/lib/protocol/http/header/connection.rb +4 -21
- data/lib/protocol/http/header/cookie.rb +2 -19
- data/lib/protocol/http/header/etag.rb +3 -20
- data/lib/protocol/http/header/etags.rb +2 -19
- data/lib/protocol/http/header/multiple.rb +2 -19
- data/lib/protocol/http/header/split.rb +8 -21
- data/lib/protocol/http/header/vary.rb +2 -19
- data/lib/protocol/http/headers.rb +12 -19
- data/lib/protocol/http/methods.rb +2 -19
- data/lib/protocol/http/middleware/builder.rb +2 -28
- data/lib/protocol/http/middleware.rb +7 -24
- data/lib/protocol/http/reference.rb +77 -69
- data/lib/protocol/http/request.rb +3 -20
- data/lib/protocol/http/response.rb +10 -20
- data/lib/protocol/http/url.rb +4 -20
- data/lib/protocol/http/version.rb +3 -20
- data/lib/protocol/http.rb +2 -19
- data/license.md +27 -0
- data/readme.md +32 -0
- data.tar.gz.sig +0 -0
- metadata +8 -3
- metadata.gz.sig +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9090658dcddc6852ae0af81355da65f40b615ca912fa2886cab18664e7a65b73
|
4
|
+
data.tar.gz: c853953e6e736c2c31b37211c42c7080de71926f2bf5d7eedf5457c1872a2777
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: db77e79eac214ede13bdc19cfb19c1b6cca8d3b0473f4414049cfa2ad7fb84bfdf888a1ce0169a97a3966f7a5d3b0d7a9e194a79e6466ae52b4deb266870bd73
|
7
|
+
data.tar.gz: b44a52164ac2d7ea6fd89746757d524651a07b10eaf509db734b23dc9af5a5d11d7295fe46669c000aa31a935792632ccd2acc2b2b7a3d8c6413bd89fab1d686
|
checksums.yaml.gz.sig
CHANGED
Binary file
|
data/design.md
ADDED
@@ -0,0 +1,167 @@
|
|
1
|
+
# Middleware Design
|
2
|
+
|
3
|
+
`Body::Writable` is a queue of String chunks.
|
4
|
+
|
5
|
+
## Request Response Model
|
6
|
+
|
7
|
+
~~~ruby
|
8
|
+
class Request
|
9
|
+
attr :verb
|
10
|
+
attr :target
|
11
|
+
attr :body
|
12
|
+
end
|
13
|
+
|
14
|
+
class Response
|
15
|
+
attr :status
|
16
|
+
attr :headers
|
17
|
+
attr :body
|
18
|
+
end
|
19
|
+
|
20
|
+
def call(request)
|
21
|
+
return response
|
22
|
+
end
|
23
|
+
|
24
|
+
def call(request)
|
25
|
+
return @app.call(request)
|
26
|
+
end
|
27
|
+
~~~
|
28
|
+
|
29
|
+
## Stream Model
|
30
|
+
|
31
|
+
~~~ruby
|
32
|
+
class Stream
|
33
|
+
attr :verb
|
34
|
+
attr :target
|
35
|
+
|
36
|
+
def respond(status, headers) = ...
|
37
|
+
|
38
|
+
attr_accessor :input
|
39
|
+
attr_accessor :output
|
40
|
+
end
|
41
|
+
|
42
|
+
class Response
|
43
|
+
def initialize(verb, target)
|
44
|
+
@input = Body::Writable.new
|
45
|
+
@output = Body::Writable.new
|
46
|
+
end
|
47
|
+
|
48
|
+
def request(verb, target)
|
49
|
+
# Create a request stream suitable for writing into the buffered response:
|
50
|
+
Stream.new(verb, target, @input, @output)
|
51
|
+
end
|
52
|
+
|
53
|
+
def write(...)
|
54
|
+
@input.write(...)
|
55
|
+
end
|
56
|
+
|
57
|
+
def read
|
58
|
+
@output.read
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def call(stream)
|
63
|
+
# nothing. maybe error
|
64
|
+
end
|
65
|
+
|
66
|
+
def call(stream)
|
67
|
+
@app.call(stream)
|
68
|
+
end
|
69
|
+
~~~
|
70
|
+
|
71
|
+
# Client Design
|
72
|
+
|
73
|
+
## Request Response Model
|
74
|
+
|
75
|
+
~~~ruby
|
76
|
+
request = Request.new("GET", url)
|
77
|
+
response = call(request)
|
78
|
+
|
79
|
+
response.headers
|
80
|
+
response.read
|
81
|
+
~~~
|
82
|
+
|
83
|
+
## Stream Model
|
84
|
+
|
85
|
+
~~~ruby
|
86
|
+
response = Response.new
|
87
|
+
call(response.request("GET", url))
|
88
|
+
|
89
|
+
response.headers
|
90
|
+
response.read
|
91
|
+
~~~
|
92
|
+
|
93
|
+
## Differences
|
94
|
+
|
95
|
+
The request/response model has a symmetrical design which naturally uses the return value for the result of executing the request. The result encapsulates the behaviour of how to read the response status, headers and body. Because of that, streaming input and output becomes a function of the result object itself. As in:
|
96
|
+
|
97
|
+
~~~ruby
|
98
|
+
def call(request)
|
99
|
+
body = Body::Writable.new
|
100
|
+
|
101
|
+
Fiber.schedule do
|
102
|
+
while chunk = request.input.read
|
103
|
+
body.write(chunk.reverse)
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
return Response[200, [], body]
|
108
|
+
end
|
109
|
+
|
110
|
+
input = Body::Writable.new
|
111
|
+
response = call(... body ...)
|
112
|
+
|
113
|
+
input.write("Hello World")
|
114
|
+
input.close
|
115
|
+
response.read -> "dlroW olleH"
|
116
|
+
~~~
|
117
|
+
|
118
|
+
The streaming model does not have the same symmetry, and instead opts for a uni-directional flow of information.
|
119
|
+
|
120
|
+
~~~ruby
|
121
|
+
def call(stream)
|
122
|
+
Fiber.schedule do
|
123
|
+
while chunk = stream.read
|
124
|
+
stream.write(chunk.reverse)
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
input = Body::Writable.new
|
130
|
+
response = Response.new(...input...)
|
131
|
+
call(response.stream)
|
132
|
+
|
133
|
+
input.write("Hello World")
|
134
|
+
input.close
|
135
|
+
response.read -> "dlroW olleH"
|
136
|
+
~~~
|
137
|
+
|
138
|
+
The value of this uni-directional flow is that it is natural for the stream to be taken out of the scope imposed by the nested `call(request)` model. However, the user must explicitly close the stream, since it's no longer scoped to the client and/or server.
|
139
|
+
|
140
|
+
## Connection Upgrade
|
141
|
+
|
142
|
+
### HTTP/1
|
143
|
+
|
144
|
+
```
|
145
|
+
GET /path/to/websocket HTTP/1.1
|
146
|
+
connection: upgrade
|
147
|
+
upgrade: websocket
|
148
|
+
```
|
149
|
+
|
150
|
+
Request.new(GET, ..., protocol = websocket)
|
151
|
+
-> Response.new(101, ..., protocol = websocket)
|
152
|
+
|
153
|
+
```
|
154
|
+
101 Switching Protocols
|
155
|
+
upgrade: websocket
|
156
|
+
```
|
157
|
+
|
158
|
+
### HTTP/2
|
159
|
+
|
160
|
+
```
|
161
|
+
:method CONNECT
|
162
|
+
:path /path/to/websocket
|
163
|
+
:protocol websocket
|
164
|
+
```
|
165
|
+
|
166
|
+
Request.new(CONNECT, ..., protocol = websocket)
|
167
|
+
-> Response.new(200, ..., protocol = websocket)
|
@@ -1,24 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
#
|
4
|
-
#
|
5
|
-
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
-
# of this software and associated documentation files (the "Software"), to deal
|
7
|
-
# in the Software without restriction, including without limitation the rights
|
8
|
-
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
-
# copies of the Software, and to permit persons to whom the Software is
|
10
|
-
# furnished to do so, subject to the following conditions:
|
11
|
-
#
|
12
|
-
# The above copyright notice and this permission notice shall be included in
|
13
|
-
# all copies or substantial portions of the Software.
|
14
|
-
#
|
15
|
-
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
-
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
-
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
-
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
-
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
-
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
-
# THE SOFTWARE.
|
3
|
+
# Released under the MIT License.
|
4
|
+
# Copyright, 2019-2023, by Samuel Williams.
|
22
5
|
|
23
6
|
require_relative 'middleware'
|
24
7
|
|
@@ -34,7 +17,9 @@ module Protocol
|
|
34
17
|
|
35
18
|
DEFAULT_WRAPPERS = {
|
36
19
|
'gzip' => Body::Inflate.method(:for),
|
37
|
-
|
20
|
+
|
21
|
+
# There is no point including this:
|
22
|
+
# 'identity' => ->(body){body},
|
38
23
|
}
|
39
24
|
|
40
25
|
def initialize(app, wrappers = DEFAULT_WRAPPERS)
|
@@ -1,24 +1,8 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
#
|
4
|
-
#
|
5
|
-
#
|
6
|
-
# of this software and associated documentation files (the "Software"), to deal
|
7
|
-
# in the Software without restriction, including without limitation the rights
|
8
|
-
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
-
# copies of the Software, and to permit persons to whom the Software is
|
10
|
-
# furnished to do so, subject to the following conditions:
|
11
|
-
#
|
12
|
-
# The above copyright notice and this permission notice shall be included in
|
13
|
-
# all copies or substantial portions of the Software.
|
14
|
-
#
|
15
|
-
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
-
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
-
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
-
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
-
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
-
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
-
# THE SOFTWARE.
|
3
|
+
# Released under the MIT License.
|
4
|
+
# Copyright, 2019-2023, by Samuel Williams.
|
5
|
+
# Copyright, 2020, by Bryan Powell.
|
22
6
|
|
23
7
|
require_relative 'readable'
|
24
8
|
|
@@ -1,24 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
#
|
4
|
-
#
|
5
|
-
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
-
# of this software and associated documentation files (the "Software"), to deal
|
7
|
-
# in the Software without restriction, including without limitation the rights
|
8
|
-
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
-
# copies of the Software, and to permit persons to whom the Software is
|
10
|
-
# furnished to do so, subject to the following conditions:
|
11
|
-
#
|
12
|
-
# The above copyright notice and this permission notice shall be included in
|
13
|
-
# all copies or substantial portions of the Software.
|
14
|
-
#
|
15
|
-
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
-
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
-
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
-
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
-
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
-
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
-
# THE SOFTWARE.
|
3
|
+
# Released under the MIT License.
|
4
|
+
# Copyright, 2019-2023, by Samuel Williams.
|
22
5
|
|
23
6
|
require_relative 'wrapper'
|
24
7
|
|
@@ -1,24 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
#
|
4
|
-
#
|
5
|
-
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
-
# of this software and associated documentation files (the "Software"), to deal
|
7
|
-
# in the Software without restriction, including without limitation the rights
|
8
|
-
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
-
# copies of the Software, and to permit persons to whom the Software is
|
10
|
-
# furnished to do so, subject to the following conditions:
|
11
|
-
#
|
12
|
-
# The above copyright notice and this permission notice shall be included in
|
13
|
-
# all copies or substantial portions of the Software.
|
14
|
-
#
|
15
|
-
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
-
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
-
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
-
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
-
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
-
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
-
# THE SOFTWARE.
|
3
|
+
# Released under the MIT License.
|
4
|
+
# Copyright, 2019-2023, by Samuel Williams.
|
22
5
|
|
23
6
|
require_relative 'wrapper'
|
24
7
|
|
@@ -38,16 +21,6 @@ module Protocol
|
|
38
21
|
'gzip' => GZIP,
|
39
22
|
}
|
40
23
|
|
41
|
-
def self.encoding_name(window_size)
|
42
|
-
if window_size <= -8
|
43
|
-
return 'deflate'
|
44
|
-
elsif window_size >= 16
|
45
|
-
return 'gzip'
|
46
|
-
else
|
47
|
-
return 'compress'
|
48
|
-
end
|
49
|
-
end
|
50
|
-
|
51
24
|
def initialize(body, stream)
|
52
25
|
super(body)
|
53
26
|
|
@@ -89,6 +62,12 @@ module Protocol
|
|
89
62
|
self.new(body, Zlib::Deflate.new(level, window_size))
|
90
63
|
end
|
91
64
|
|
65
|
+
def stream?
|
66
|
+
# We might want to revisit this design choice.
|
67
|
+
# We could wrap the streaming body in a Deflate stream, but that would require an extra stream wrapper which we don't have right now. See also `Digestable#stream?`.
|
68
|
+
false
|
69
|
+
end
|
70
|
+
|
92
71
|
def read
|
93
72
|
return if @stream.finished?
|
94
73
|
|
@@ -112,4 +91,4 @@ module Protocol
|
|
112
91
|
end
|
113
92
|
end
|
114
93
|
end
|
115
|
-
end
|
94
|
+
end
|
@@ -1,24 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
#
|
4
|
-
#
|
5
|
-
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
-
# of this software and associated documentation files (the "Software"), to deal
|
7
|
-
# in the Software without restriction, including without limitation the rights
|
8
|
-
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
-
# copies of the Software, and to permit persons to whom the Software is
|
10
|
-
# furnished to do so, subject to the following conditions:
|
11
|
-
#
|
12
|
-
# The above copyright notice and this permission notice shall be included in
|
13
|
-
# all copies or substantial portions of the Software.
|
14
|
-
#
|
15
|
-
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
-
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
-
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
-
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
-
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
-
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
-
# THE SOFTWARE.
|
3
|
+
# Released under the MIT License.
|
4
|
+
# Copyright, 2020-2023, by Samuel Williams.
|
22
5
|
|
23
6
|
require_relative 'wrapper'
|
24
7
|
|
@@ -35,6 +18,7 @@ module Protocol
|
|
35
18
|
end
|
36
19
|
end
|
37
20
|
|
21
|
+
# @parameter callback [Block] The callback is invoked when the digest is complete.
|
38
22
|
def initialize(body, digest = Digest::SHA256.new, callback = nil)
|
39
23
|
super(body)
|
40
24
|
|
@@ -46,8 +30,16 @@ module Protocol
|
|
46
30
|
@digest
|
47
31
|
end
|
48
32
|
|
49
|
-
def etag
|
50
|
-
|
33
|
+
def etag(weak: false)
|
34
|
+
if weak
|
35
|
+
"W/\"#{digest.hexdigest}\""
|
36
|
+
else
|
37
|
+
"\"#{digest.hexdigest}\""
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def stream?
|
42
|
+
false
|
51
43
|
end
|
52
44
|
|
53
45
|
def read
|
@@ -1,33 +1,15 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
#
|
4
|
-
#
|
5
|
-
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
-
# of this software and associated documentation files (the "Software"), to deal
|
7
|
-
# in the Software without restriction, including without limitation the rights
|
8
|
-
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
-
# copies of the Software, and to permit persons to whom the Software is
|
10
|
-
# furnished to do so, subject to the following conditions:
|
11
|
-
#
|
12
|
-
# The above copyright notice and this permission notice shall be included in
|
13
|
-
# all copies or substantial portions of the Software.
|
14
|
-
#
|
15
|
-
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
-
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
-
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
-
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
-
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
-
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
-
# THE SOFTWARE.
|
3
|
+
# Released under the MIT License.
|
4
|
+
# Copyright, 2019-2023, by Samuel Williams.
|
22
5
|
|
23
6
|
require_relative 'readable'
|
24
|
-
require 'async/io/stream'
|
25
7
|
|
26
8
|
module Protocol
|
27
9
|
module HTTP
|
28
10
|
module Body
|
29
11
|
class File < Readable
|
30
|
-
BLOCK_SIZE =
|
12
|
+
BLOCK_SIZE = 4096
|
31
13
|
MODE = ::File::RDONLY | ::File::BINARY
|
32
14
|
|
33
15
|
def self.open(path, *arguments, **options)
|
@@ -71,6 +53,11 @@ module Protocol
|
|
71
53
|
|
72
54
|
def rewind
|
73
55
|
@file.seek(@offset)
|
56
|
+
@remaining = @length
|
57
|
+
end
|
58
|
+
|
59
|
+
def stream?
|
60
|
+
false
|
74
61
|
end
|
75
62
|
|
76
63
|
def read
|
@@ -1,24 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
#
|
4
|
-
#
|
5
|
-
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
-
# of this software and associated documentation files (the "Software"), to deal
|
7
|
-
# in the Software without restriction, including without limitation the rights
|
8
|
-
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
-
# copies of the Software, and to permit persons to whom the Software is
|
10
|
-
# furnished to do so, subject to the following conditions:
|
11
|
-
#
|
12
|
-
# The above copyright notice and this permission notice shall be included in
|
13
|
-
# all copies or substantial portions of the Software.
|
14
|
-
#
|
15
|
-
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
-
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
-
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
-
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
-
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
-
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
-
# THE SOFTWARE.
|
3
|
+
# Released under the MIT License.
|
4
|
+
# Copyright, 2020-2023, by Samuel Williams.
|
22
5
|
|
23
6
|
require_relative 'readable'
|
24
7
|
|
@@ -52,4 +35,4 @@ module Protocol
|
|
52
35
|
end
|
53
36
|
end
|
54
37
|
end
|
55
|
-
end
|
38
|
+
end
|
@@ -1,24 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
#
|
4
|
-
#
|
5
|
-
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
-
# of this software and associated documentation files (the "Software"), to deal
|
7
|
-
# in the Software without restriction, including without limitation the rights
|
8
|
-
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
-
# copies of the Software, and to permit persons to whom the Software is
|
10
|
-
# furnished to do so, subject to the following conditions:
|
11
|
-
#
|
12
|
-
# The above copyright notice and this permission notice shall be included in
|
13
|
-
# all copies or substantial portions of the Software.
|
14
|
-
#
|
15
|
-
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
-
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
-
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
-
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
-
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
-
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
-
# THE SOFTWARE.
|
3
|
+
# Released under the MIT License.
|
4
|
+
# Copyright, 2019-2023, by Samuel Williams.
|
22
5
|
|
23
6
|
require 'zlib'
|
24
7
|
|
@@ -32,20 +15,27 @@ module Protocol
|
|
32
15
|
self.new(body, Zlib::Inflate.new(encoding))
|
33
16
|
end
|
34
17
|
|
18
|
+
def stream?
|
19
|
+
false
|
20
|
+
end
|
21
|
+
|
35
22
|
def read
|
36
23
|
return if @stream.finished?
|
37
24
|
|
38
25
|
# The stream might have been closed while waiting for the chunk to come in.
|
39
|
-
|
26
|
+
while chunk = super
|
40
27
|
@input_length += chunk.bytesize
|
41
28
|
|
42
29
|
# It's possible this triggers the stream to finish.
|
43
30
|
chunk = @stream.inflate(chunk)
|
44
31
|
|
32
|
+
break unless chunk&.empty?
|
33
|
+
end
|
34
|
+
|
35
|
+
if chunk
|
45
36
|
@output_length += chunk.bytesize
|
46
37
|
elsif !@stream.closed?
|
47
38
|
chunk = @stream.finish
|
48
|
-
|
49
39
|
@output_length += chunk.bytesize
|
50
40
|
end
|
51
41
|
|
@@ -58,4 +48,4 @@ module Protocol
|
|
58
48
|
end
|
59
49
|
end
|
60
50
|
end
|
61
|
-
end
|
51
|
+
end
|
@@ -1,26 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
#
|
4
|
-
#
|
5
|
-
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
-
# of this software and associated documentation files (the "Software"), to deal
|
7
|
-
# in the Software without restriction, including without limitation the rights
|
8
|
-
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
-
# copies of the Software, and to permit persons to whom the Software is
|
10
|
-
# furnished to do so, subject to the following conditions:
|
11
|
-
#
|
12
|
-
# The above copyright notice and this permission notice shall be included in
|
13
|
-
# all copies or substantial portions of the Software.
|
14
|
-
#
|
15
|
-
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
-
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
-
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
-
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
-
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
-
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
-
# THE SOFTWARE.
|
22
|
-
|
23
|
-
require 'async/io/buffer'
|
3
|
+
# Released under the MIT License.
|
4
|
+
# Copyright, 2019-2023, by Samuel Williams.
|
24
5
|
|
25
6
|
module Protocol
|
26
7
|
module HTTP
|
@@ -39,12 +20,14 @@ module Protocol
|
|
39
20
|
def close(error = nil)
|
40
21
|
end
|
41
22
|
|
42
|
-
#
|
23
|
+
# Optimistically determine whether read (may) return any data.
|
24
|
+
# If this returns true, then calling read will definitely return nil.
|
25
|
+
# If this returns false, then calling read may return nil.
|
43
26
|
def empty?
|
44
27
|
false
|
45
28
|
end
|
46
29
|
|
47
|
-
# Whether calling read will
|
30
|
+
# Whether calling read will return a chunk of data without blocking.
|
48
31
|
# We prefer pessimistic implementation, and thus default to `false`.
|
49
32
|
# @return [Boolean]
|
50
33
|
def ready?
|
@@ -1,24 +1,8 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
#
|
4
|
-
#
|
5
|
-
#
|
6
|
-
# of this software and associated documentation files (the "Software"), to deal
|
7
|
-
# in the Software without restriction, including without limitation the rights
|
8
|
-
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
-
# copies of the Software, and to permit persons to whom the Software is
|
10
|
-
# furnished to do so, subject to the following conditions:
|
11
|
-
#
|
12
|
-
# The above copyright notice and this permission notice shall be included in
|
13
|
-
# all copies or substantial portions of the Software.
|
14
|
-
#
|
15
|
-
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
-
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
-
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
-
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
-
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
-
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
-
# THE SOFTWARE.
|
3
|
+
# Released under the MIT License.
|
4
|
+
# Copyright, 2019-2023, by Samuel Williams.
|
5
|
+
# Copyright, 2022, by Dan Olson.
|
22
6
|
|
23
7
|
module Protocol
|
24
8
|
module HTTP
|
@@ -57,9 +41,9 @@ module Protocol
|
|
57
41
|
end
|
58
42
|
|
59
43
|
# Write the body of the response to the given file path.
|
60
|
-
def save(path, mode = ::File::WRONLY|::File::CREAT,
|
44
|
+
def save(path, mode = ::File::WRONLY|::File::CREAT, **options)
|
61
45
|
if @body
|
62
|
-
::File.open(path, mode,
|
46
|
+
::File.open(path, mode, **options) do |file|
|
63
47
|
self.each do |chunk|
|
64
48
|
file.write(chunk)
|
65
49
|
end
|
@@ -1,24 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
#
|
4
|
-
#
|
5
|
-
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
-
# of this software and associated documentation files (the "Software"), to deal
|
7
|
-
# in the Software without restriction, including without limitation the rights
|
8
|
-
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
-
# copies of the Software, and to permit persons to whom the Software is
|
10
|
-
# furnished to do so, subject to the following conditions:
|
11
|
-
#
|
12
|
-
# The above copyright notice and this permission notice shall be included in
|
13
|
-
# all copies or substantial portions of the Software.
|
14
|
-
#
|
15
|
-
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
-
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
-
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
-
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
-
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
-
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
-
# THE SOFTWARE.
|
3
|
+
# Released under the MIT License.
|
4
|
+
# Copyright, 2019-2023, by Samuel Williams.
|
22
5
|
|
23
6
|
require_relative 'wrapper'
|
24
7
|
require_relative 'buffered'
|
@@ -48,6 +31,10 @@ module Protocol
|
|
48
31
|
Buffered.new(@chunks)
|
49
32
|
end
|
50
33
|
|
34
|
+
def stream?
|
35
|
+
false
|
36
|
+
end
|
37
|
+
|
51
38
|
def read
|
52
39
|
if @index < @chunks.size
|
53
40
|
chunk = @chunks[@index]
|