protocol-http 0.17.0 → 0.21.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.editorconfig +0 -1
- data/.github/workflows/development.yml +44 -0
- data/.gitignore +2 -1
- data/README.md +13 -13
- data/STREAMING.md +69 -0
- data/bake.rb +37 -0
- data/{Gemfile → gems.rb} +5 -0
- data/lib/protocol/http/body/buffered.rb +6 -0
- data/lib/protocol/http/body/{streamable.rb → completable.rb} +3 -3
- data/lib/protocol/http/body/file.rb +4 -0
- data/lib/protocol/http/body/head.rb +4 -0
- data/lib/protocol/http/body/readable.rb +22 -0
- data/lib/protocol/http/body/rewindable.rb +4 -0
- data/lib/protocol/http/body/wrapper.rb +12 -0
- data/lib/protocol/http/cookie.rb +1 -1
- data/lib/protocol/http/header/authorization.rb +15 -13
- data/lib/protocol/http/header/etag.rb +0 -2
- data/lib/protocol/http/headers.rb +51 -15
- data/lib/protocol/http/methods.rb +2 -2
- data/lib/protocol/http/reference.rb +1 -3
- data/lib/protocol/http/request.rb +1 -7
- data/lib/protocol/http/response.rb +2 -8
- data/lib/protocol/http/version.rb +1 -1
- data/protocol-http.gemspec +1 -2
- metadata +12 -24
- data/.travis.yml +0 -22
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 01dc23ef2870a6572cc986fd3dac2de5902ec3283fb5a380d9f24b1193516d68
|
4
|
+
data.tar.gz: ca6bf9694e01884a6d2c2e9ab5e85c54d64c4f150881cf57fb2ba1ed80fa0b9c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d71145aa0b55861140b181c2351501cd9eec840b747abd4d5d48841a4e8d2df0bb5d2e5fa0c0c83be98a51775e92160cd52690806c5b1443808f7d6386cdc568
|
7
|
+
data.tar.gz: f2f603776458e27ed0b2148fce7c9f9ac419417c001e2ea42270248df651c34f524b6646926847a8aa93139509b8bd72d86c875a3b341e9c16eb0a124ecfd6a5
|
data/.editorconfig
CHANGED
@@ -0,0 +1,44 @@
|
|
1
|
+
name: Development
|
2
|
+
|
3
|
+
on: [push, pull_request]
|
4
|
+
|
5
|
+
jobs:
|
6
|
+
test:
|
7
|
+
runs-on: ${{matrix.os}}-latest
|
8
|
+
continue-on-error: ${{matrix.experimental}}
|
9
|
+
|
10
|
+
strategy:
|
11
|
+
matrix:
|
12
|
+
os:
|
13
|
+
- ubuntu
|
14
|
+
- macos
|
15
|
+
|
16
|
+
ruby:
|
17
|
+
- 2.5
|
18
|
+
- 2.6
|
19
|
+
- 2.7
|
20
|
+
|
21
|
+
experimental: [false]
|
22
|
+
env: [""]
|
23
|
+
|
24
|
+
include:
|
25
|
+
- os: ubuntu
|
26
|
+
ruby: truffleruby
|
27
|
+
experimental: true
|
28
|
+
- os: ubuntu
|
29
|
+
ruby: jruby
|
30
|
+
experimental: true
|
31
|
+
- os: ubuntu
|
32
|
+
ruby: head
|
33
|
+
experimental: true
|
34
|
+
|
35
|
+
steps:
|
36
|
+
- uses: actions/checkout@v2
|
37
|
+
- uses: ioquatix/setup-ruby@master
|
38
|
+
with:
|
39
|
+
ruby-version: ${{matrix.ruby}}
|
40
|
+
bundler-cache: true
|
41
|
+
|
42
|
+
- name: Run tests
|
43
|
+
timeout-minutes: 5
|
44
|
+
run: ${{matrix.env}} bundle exec rspec
|
data/.gitignore
CHANGED
data/README.md
CHANGED
@@ -2,29 +2,29 @@
|
|
2
2
|
|
3
3
|
Provides abstractions for working with the HTTP protocol.
|
4
4
|
|
5
|
-
[![
|
5
|
+
[![Development Status](https://github.com/socketry/protocol-http/workflows/Development/badge.svg)](https://github.com/socketry/protocol-http/actions?workflow=Development)
|
6
6
|
|
7
7
|
## Installation
|
8
8
|
|
9
9
|
Add this line to your application's Gemfile:
|
10
10
|
|
11
|
-
```ruby
|
11
|
+
``` ruby
|
12
12
|
gem 'protocol-http'
|
13
13
|
```
|
14
14
|
|
15
15
|
And then execute:
|
16
16
|
|
17
|
-
|
17
|
+
$ bundle
|
18
18
|
|
19
19
|
Or install it yourself as:
|
20
20
|
|
21
|
-
|
21
|
+
$ gem install protocol-http
|
22
22
|
|
23
23
|
## Usage
|
24
24
|
|
25
25
|
### Headers
|
26
26
|
|
27
|
-
```ruby
|
27
|
+
``` ruby
|
28
28
|
require 'protocol/http/headers'
|
29
29
|
|
30
30
|
headers = Protocol::HTTP::Headers.new
|
@@ -37,7 +37,7 @@ headers['content-type']
|
|
37
37
|
|
38
38
|
### Reference
|
39
39
|
|
40
|
-
```ruby
|
40
|
+
``` ruby
|
41
41
|
require 'protocol/http/reference'
|
42
42
|
|
43
43
|
reference = Protocol::HTTP::Reference.new("/search", q: 'kittens')
|
@@ -48,7 +48,7 @@ reference.to_s
|
|
48
48
|
|
49
49
|
### URL
|
50
50
|
|
51
|
-
```ruby
|
51
|
+
``` ruby
|
52
52
|
require 'protocol/http/url'
|
53
53
|
|
54
54
|
reference = Protocol::HTTP::Reference.parse("/search?q=kittens")
|
@@ -59,17 +59,17 @@ parameters = Protocol::HTTP::URL.decode(reference.query_string)
|
|
59
59
|
|
60
60
|
## Contributing
|
61
61
|
|
62
|
-
1.
|
63
|
-
2.
|
64
|
-
3.
|
65
|
-
4.
|
66
|
-
5.
|
62
|
+
1. Fork it
|
63
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
64
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
65
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
66
|
+
5. Create new Pull Request
|
67
67
|
|
68
68
|
## License
|
69
69
|
|
70
70
|
Released under the MIT license.
|
71
71
|
|
72
|
-
Copyright, 2019, by [Samuel G. D. Williams](http://www.codeotaku.com/samuel-williams).
|
72
|
+
Copyright, 2019, by [Samuel G. D. Williams](http://www.codeotaku.com/samuel-williams).
|
73
73
|
|
74
74
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
75
75
|
of this software and associated documentation files (the "Software"), to deal
|
data/STREAMING.md
ADDED
@@ -0,0 +1,69 @@
|
|
1
|
+
# Streaming
|
2
|
+
|
3
|
+
Streaming is a complex topic given that most server's are not scalable in this respect. A variety of solutions exist to work around limited server implementations, but they impose significant burden on the implementation and are generally incompatible with implementations of HTTP which are not request per connection. We propose to simplify the current Rack implementation to support streaming in a consistent way, but also allow for backwards compatibility with existing servers.
|
4
|
+
|
5
|
+
## Current Implementation
|
6
|
+
|
7
|
+
Rack currently supports streaming using `rack.hijack`. There are two ways to hijack the underlying socket for a given request: a partial hijack and a full hijack. Not all servers support both modes of operation and neither method is fully compatible with HTTP/2.
|
8
|
+
|
9
|
+
### Partial Hijack
|
10
|
+
|
11
|
+
A partial hijack allows the web server to respond with the response status, headers, and then yields the stream back to the application code. It does this by using a special `rack.hijack` header:
|
12
|
+
|
13
|
+
``` ruby
|
14
|
+
def call(env)
|
15
|
+
body = proc do |stream|
|
16
|
+
stream.write("Hello World")
|
17
|
+
stream.close
|
18
|
+
end
|
19
|
+
|
20
|
+
if env['rack.hijack?']
|
21
|
+
return [200, {'rack.hijack' => body}, nil]
|
22
|
+
end
|
23
|
+
end
|
24
|
+
```
|
25
|
+
|
26
|
+
- It is not clear whether the body needs to handle the formatting of the response, i.e. chunked encoding, compression, transfer encoding, etc.
|
27
|
+
- It mixes `rack.` specific headers with normal HTTP headers which is computationally expensive for the server to detect.
|
28
|
+
- It's not clear what the returned body should be.
|
29
|
+
|
30
|
+
### Full Hijack
|
31
|
+
|
32
|
+
A full hijack allows the web server to completely take control of the underlying socket. This occurs at the point the `rack.hijack` is invoked.
|
33
|
+
|
34
|
+
``` ruby
|
35
|
+
def call(env)
|
36
|
+
if hijack = env['rack.hijack']
|
37
|
+
socket = hijack.call
|
38
|
+
|
39
|
+
Thread.new do
|
40
|
+
socket.write("Hello World")
|
41
|
+
socket.close
|
42
|
+
end
|
43
|
+
|
44
|
+
return nil # ???
|
45
|
+
end
|
46
|
+
end
|
47
|
+
```
|
48
|
+
|
49
|
+
- The socket might not actually be a raw socket, if the server is using TLS.
|
50
|
+
- Extreme care is required in order to handle the protocol correctly.
|
51
|
+
- It's not clear if such a design can work with anything other than HTTP/1.
|
52
|
+
- The user code **must** return from the `call(env)` method in order for the server continue handling requests.
|
53
|
+
- It's not clear what the response should be.
|
54
|
+
|
55
|
+
## Typical Scenarios
|
56
|
+
|
57
|
+
There are several typical scenarios where `rack.hijack` has been used.
|
58
|
+
|
59
|
+
### ActionCable
|
60
|
+
|
61
|
+
ActionCable uses full hijack in order to negotiate and communicate using WebSocket protocol. Such a design requires the ActionCable server to run in the same process as the web server.
|
62
|
+
|
63
|
+
### MessageBus
|
64
|
+
|
65
|
+
MessageBus uses full hijack in order to keep the socket alive and feed messages occasionally.
|
66
|
+
|
67
|
+
## Supporting HTTP/2
|
68
|
+
|
69
|
+
It is possible to support partial hijack in HTTP/2. The hijacked stream is multiplexed the same as any other connection. However, such a design cannot be thread safe without significant design trade-offs.
|
data/bake.rb
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
def external
|
4
|
+
require 'bundler'
|
5
|
+
|
6
|
+
Bundler.with_unbundled_env do
|
7
|
+
clone_and_test("protocol-http1")
|
8
|
+
clone_and_test("protocol-http2")
|
9
|
+
clone_and_test("async-websocket")
|
10
|
+
clone_and_test("async-http")
|
11
|
+
clone_and_test("async-rest")
|
12
|
+
clone_and_test("falcon")
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def clone_and_test(name)
|
19
|
+
path = "external/#{name}"
|
20
|
+
|
21
|
+
unless File.exist?(path)
|
22
|
+
system("git", "clone", "https://git@github.com/socketry/#{name}", path)
|
23
|
+
end
|
24
|
+
|
25
|
+
gemfile = [
|
26
|
+
File.join(path, "gems.rb"),
|
27
|
+
File.join(path, "Gemfile"),
|
28
|
+
].find{|path| File.exist?(path)}
|
29
|
+
|
30
|
+
system("git", "checkout", "-f", File.basename(gemfile), chdir: path)
|
31
|
+
|
32
|
+
File.open(gemfile, "a") do |file|
|
33
|
+
file.puts('', 'gem "protocol-http", path: "../../"')
|
34
|
+
end
|
35
|
+
|
36
|
+
system("bundle install && bundle exec rspec", chdir: path)
|
37
|
+
end
|
data/{Gemfile → gems.rb}
RENAMED
@@ -56,6 +56,7 @@ module Protocol
|
|
56
56
|
@length = length
|
57
57
|
|
58
58
|
@index = 0
|
59
|
+
@digest = nil
|
59
60
|
end
|
60
61
|
|
61
62
|
attr :chunks
|
@@ -72,6 +73,11 @@ module Protocol
|
|
72
73
|
@index >= @chunks.length
|
73
74
|
end
|
74
75
|
|
76
|
+
# A buffered response is always ready.
|
77
|
+
def ready?
|
78
|
+
true
|
79
|
+
end
|
80
|
+
|
75
81
|
def read
|
76
82
|
if chunk = @chunks[@index]
|
77
83
|
@index += 1
|
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
# Copyright,
|
3
|
+
# Copyright, 2020, by Samuel G. D. Williams. <http://www.codeotaku.com>
|
4
4
|
#
|
5
5
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
6
|
# of this software and associated documentation files (the "Software"), to deal
|
@@ -25,8 +25,8 @@ require_relative 'wrapper'
|
|
25
25
|
module Protocol
|
26
26
|
module HTTP
|
27
27
|
module Body
|
28
|
-
# Invokes a callback once the body has
|
29
|
-
class
|
28
|
+
# Invokes a callback once the body has completed, either successfully or due to an error.
|
29
|
+
class Completable < Wrapper
|
30
30
|
def self.wrap(message, &block)
|
31
31
|
if body = message&.body and !body.empty?
|
32
32
|
message.body = self.new(message.body, block)
|
@@ -44,6 +44,13 @@ module Protocol
|
|
44
44
|
false
|
45
45
|
end
|
46
46
|
|
47
|
+
# Whether calling read will block.
|
48
|
+
# We prefer pessimistic implementation, and thus default to `false`.
|
49
|
+
# @return [Boolean]
|
50
|
+
def ready?
|
51
|
+
false
|
52
|
+
end
|
53
|
+
|
47
54
|
def length
|
48
55
|
nil
|
49
56
|
end
|
@@ -53,6 +60,21 @@ module Protocol
|
|
53
60
|
nil
|
54
61
|
end
|
55
62
|
|
63
|
+
# Should the internal mechanism prefer to use {call}?
|
64
|
+
# @returns [Boolean]
|
65
|
+
def stream?
|
66
|
+
false
|
67
|
+
end
|
68
|
+
|
69
|
+
# Write the body to the given stream.
|
70
|
+
def call(stream)
|
71
|
+
while chunk = self.read
|
72
|
+
stream.write(chunk)
|
73
|
+
end
|
74
|
+
ensure
|
75
|
+
stream.close($!)
|
76
|
+
end
|
77
|
+
|
56
78
|
# Read all remaining chunks into a buffered body and close the underlying input.
|
57
79
|
def finish
|
58
80
|
# Internally, this invokes `self.each` which then invokes `self.close`.
|
@@ -55,6 +55,10 @@ module Protocol
|
|
55
55
|
@body.empty?
|
56
56
|
end
|
57
57
|
|
58
|
+
def ready?
|
59
|
+
@body.ready?
|
60
|
+
end
|
61
|
+
|
58
62
|
def length
|
59
63
|
@body.length
|
60
64
|
end
|
@@ -67,6 +71,14 @@ module Protocol
|
|
67
71
|
def inspect
|
68
72
|
@body.inspect
|
69
73
|
end
|
74
|
+
|
75
|
+
def stream?
|
76
|
+
@body.stream?
|
77
|
+
end
|
78
|
+
|
79
|
+
def call(stream)
|
80
|
+
@body.call(stream)
|
81
|
+
end
|
70
82
|
end
|
71
83
|
end
|
72
84
|
end
|
data/lib/protocol/http/cookie.rb
CHANGED
@@ -26,21 +26,23 @@ module Protocol
|
|
26
26
|
module HTTP
|
27
27
|
module Header
|
28
28
|
# Used for basic authorization.
|
29
|
-
#
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
def encoded
|
39
|
-
"#{@username}:#{@password}"
|
29
|
+
#
|
30
|
+
# ~~~ ruby
|
31
|
+
# headers.add('authorization', Authorization.basic("my_username", "my_password"))
|
32
|
+
# ~~~
|
33
|
+
class Authorization < String
|
34
|
+
# Splits the header and
|
35
|
+
# @return [Tuple(String, String)]
|
36
|
+
def credentials
|
37
|
+
self.split(/\s+/, 2)
|
40
38
|
end
|
41
39
|
|
42
|
-
def
|
43
|
-
|
40
|
+
def self.basic(username, password)
|
41
|
+
encoded = "#{username}:#{password}"
|
42
|
+
|
43
|
+
self.new(
|
44
|
+
"Basic #{Base64.strict_encode64(encoded)}"
|
45
|
+
)
|
44
46
|
end
|
45
47
|
end
|
46
48
|
end
|
@@ -28,6 +28,7 @@ require_relative 'header/cache_control'
|
|
28
28
|
require_relative 'header/etag'
|
29
29
|
require_relative 'header/etags'
|
30
30
|
require_relative 'header/vary'
|
31
|
+
require_relative 'header/authorization'
|
31
32
|
|
32
33
|
module Protocol
|
33
34
|
module HTTP
|
@@ -35,16 +36,31 @@ module Protocol
|
|
35
36
|
class Headers
|
36
37
|
Split = Header::Split
|
37
38
|
Multiple = Header::Multiple
|
39
|
+
|
38
40
|
TRAILERS = 'trailers'
|
39
41
|
|
40
|
-
# Construct an instance from a headers Array or Hash. No-op if already an instance of `Headers`.
|
42
|
+
# Construct an instance from a headers Array or Hash. No-op if already an instance of `Headers`. If the underlying array is frozen, it will be duped.
|
41
43
|
# @return [Headers] an instance of headers.
|
42
44
|
def self.[] headers
|
45
|
+
if headers.nil?
|
46
|
+
return self.new
|
47
|
+
end
|
48
|
+
|
43
49
|
if headers.is_a?(self)
|
44
|
-
headers
|
45
|
-
|
46
|
-
|
50
|
+
if headers.frozen?
|
51
|
+
return headers.dup
|
52
|
+
else
|
53
|
+
return headers
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
fields = headers.to_a
|
58
|
+
|
59
|
+
if fields.frozen?
|
60
|
+
fields = fields.dup
|
47
61
|
end
|
62
|
+
|
63
|
+
return self.new(fields)
|
48
64
|
end
|
49
65
|
|
50
66
|
def initialize(fields = [], indexed = nil)
|
@@ -60,7 +76,6 @@ module Protocol
|
|
60
76
|
|
61
77
|
@fields = @fields.dup
|
62
78
|
@indexed = @indexed.dup
|
63
|
-
@tail = nil
|
64
79
|
end
|
65
80
|
|
66
81
|
def clear
|
@@ -69,25 +84,43 @@ module Protocol
|
|
69
84
|
@tail = nil
|
70
85
|
end
|
71
86
|
|
72
|
-
#
|
73
|
-
|
87
|
+
# Flatten trailers into the headers.
|
88
|
+
def flatten!
|
89
|
+
if @tail
|
90
|
+
self.delete(TRAILERS)
|
91
|
+
@tail = nil
|
92
|
+
end
|
93
|
+
|
94
|
+
return self
|
95
|
+
end
|
74
96
|
|
75
|
-
|
76
|
-
|
77
|
-
@tail ||= @fields.size
|
97
|
+
def flatten
|
98
|
+
self.dup.flatten!
|
78
99
|
end
|
79
100
|
|
101
|
+
# An array of `[key, value]` pairs.
|
102
|
+
attr :fields
|
103
|
+
|
80
104
|
# @return the trailers if there are any.
|
81
105
|
def trailers?
|
82
106
|
@tail != nil
|
83
107
|
end
|
84
108
|
|
85
|
-
#
|
86
|
-
def trailers(&block)
|
109
|
+
# Record the current headers, and prepare to receive trailers.
|
110
|
+
def trailers!(&block)
|
87
111
|
return nil unless self.include?(TRAILERS)
|
88
112
|
|
89
|
-
|
113
|
+
@tail ||= @fields.size
|
114
|
+
|
115
|
+
return to_enum(:trailers!) unless block_given?
|
90
116
|
|
117
|
+
if @tail
|
118
|
+
@fields.drop(@tail).each(&block)
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
# Enumerate all trailers, if there are any.
|
123
|
+
def trailers(&block)
|
91
124
|
return to_enum(:trailers) unless block_given?
|
92
125
|
|
93
126
|
if @tail
|
@@ -138,6 +171,7 @@ module Protocol
|
|
138
171
|
end
|
139
172
|
|
140
173
|
# Add the specified header key value pair.
|
174
|
+
#
|
141
175
|
# @param key [String] the header key.
|
142
176
|
# @param value [String] the header value to assign.
|
143
177
|
def add(key, value)
|
@@ -184,8 +218,6 @@ module Protocol
|
|
184
218
|
'user-agent' => false,
|
185
219
|
'referer' => false,
|
186
220
|
'host' => false,
|
187
|
-
'authorization' => false,
|
188
|
-
'proxy-authorization' => false,
|
189
221
|
'if-modified-since' => false,
|
190
222
|
'if-unmodified-since' => false,
|
191
223
|
'from' => false,
|
@@ -201,6 +233,10 @@ module Protocol
|
|
201
233
|
'via' => Split,
|
202
234
|
'x-forwarded-for' => Split,
|
203
235
|
|
236
|
+
# Authorization headers:
|
237
|
+
'authorization' => Header::Authorization,
|
238
|
+
'proxy-authorization' => Header::Authorization,
|
239
|
+
|
204
240
|
# Cache validations:
|
205
241
|
'etag' => Header::ETag,
|
206
242
|
'if-match' => Header::ETags,
|
@@ -51,9 +51,9 @@ module Protocol
|
|
51
51
|
|
52
52
|
# Use Methods.constants to get all constants.
|
53
53
|
self.each do |name, value|
|
54
|
-
define_method(name.downcase) do |location, headers =
|
54
|
+
define_method(name.downcase) do |location, headers = nil, body = nil|
|
55
55
|
self.call(
|
56
|
-
Request[value, location.
|
56
|
+
Request[value, location.to_s, Headers[headers], body]
|
57
57
|
)
|
58
58
|
end
|
59
59
|
end
|
@@ -110,12 +110,10 @@ module Protocol
|
|
110
110
|
return buffer
|
111
111
|
end
|
112
112
|
|
113
|
-
def
|
113
|
+
def to_s
|
114
114
|
append(String.new)
|
115
115
|
end
|
116
116
|
|
117
|
-
alias to_s to_str
|
118
|
-
|
119
117
|
# Merges two references as specified by RFC2396, similar to `URI.join`.
|
120
118
|
def + other
|
121
119
|
other = self.class[other]
|
@@ -28,7 +28,7 @@ module Protocol
|
|
28
28
|
class Request
|
29
29
|
prepend Body::Reader
|
30
30
|
|
31
|
-
def initialize(scheme = nil, authority = nil, method = nil, path = nil, version = nil, headers =
|
31
|
+
def initialize(scheme = nil, authority = nil, method = nil, path = nil, version = nil, headers = Headers.new, body = nil, protocol = nil)
|
32
32
|
@scheme = scheme
|
33
33
|
@authority = authority
|
34
34
|
@method = method
|
@@ -48,12 +48,6 @@ module Protocol
|
|
48
48
|
attr_accessor :body
|
49
49
|
attr_accessor :protocol
|
50
50
|
|
51
|
-
def trailers
|
52
|
-
if @headers.respond_to?(:trailers)
|
53
|
-
@headers.trailers
|
54
|
-
end
|
55
|
-
end
|
56
|
-
|
57
51
|
# Send the request to the given connection.
|
58
52
|
def call(connection)
|
59
53
|
connection.call(self)
|
@@ -28,7 +28,7 @@ module Protocol
|
|
28
28
|
class Response
|
29
29
|
prepend Body::Reader
|
30
30
|
|
31
|
-
def initialize(version = nil, status = 200, headers =
|
31
|
+
def initialize(version = nil, status = 200, headers = Headers.new, body = nil, protocol = nil)
|
32
32
|
@version = version
|
33
33
|
@status = status
|
34
34
|
@headers = headers
|
@@ -42,12 +42,6 @@ module Protocol
|
|
42
42
|
attr_accessor :body
|
43
43
|
attr_accessor :protocol
|
44
44
|
|
45
|
-
def trailers
|
46
|
-
if @headers.respond_to?(:trailers)
|
47
|
-
@headers.trailers
|
48
|
-
end
|
49
|
-
end
|
50
|
-
|
51
45
|
def hijack?
|
52
46
|
false
|
53
47
|
end
|
@@ -88,7 +82,7 @@ module Protocol
|
|
88
82
|
@status == 500
|
89
83
|
end
|
90
84
|
|
91
|
-
def self.[](status, headers =
|
85
|
+
def self.[](status, headers = nil, body = nil, protocol = nil)
|
92
86
|
body = Body::Buffered.wrap(body)
|
93
87
|
headers = ::Protocol::HTTP::Headers[headers]
|
94
88
|
|
data/protocol-http.gemspec
CHANGED
@@ -15,12 +15,11 @@ Gem::Specification.new do |spec|
|
|
15
15
|
f.match(%r{^(test|spec|features)/})
|
16
16
|
end
|
17
17
|
|
18
|
-
spec.required_ruby_version = '
|
18
|
+
spec.required_ruby_version = '>= 2.5'
|
19
19
|
|
20
20
|
spec.require_paths = ["lib"]
|
21
21
|
|
22
22
|
spec.add_development_dependency "covered"
|
23
23
|
spec.add_development_dependency "bundler"
|
24
|
-
spec.add_development_dependency "bake-bundler"
|
25
24
|
spec.add_development_dependency "rspec"
|
26
25
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: protocol-http
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.21.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Samuel Williams
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-
|
11
|
+
date: 2020-11-14 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: covered
|
@@ -38,20 +38,6 @@ dependencies:
|
|
38
38
|
- - ">="
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '0'
|
41
|
-
- !ruby/object:Gem::Dependency
|
42
|
-
name: bake-bundler
|
43
|
-
requirement: !ruby/object:Gem::Requirement
|
44
|
-
requirements:
|
45
|
-
- - ">="
|
46
|
-
- !ruby/object:Gem::Version
|
47
|
-
version: '0'
|
48
|
-
type: :development
|
49
|
-
prerelease: false
|
50
|
-
version_requirements: !ruby/object:Gem::Requirement
|
51
|
-
requirements:
|
52
|
-
- - ">="
|
53
|
-
- !ruby/object:Gem::Version
|
54
|
-
version: '0'
|
55
41
|
- !ruby/object:Gem::Dependency
|
56
42
|
name: rspec
|
57
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -66,7 +52,7 @@ dependencies:
|
|
66
52
|
- - ">="
|
67
53
|
- !ruby/object:Gem::Version
|
68
54
|
version: '0'
|
69
|
-
description:
|
55
|
+
description:
|
70
56
|
email:
|
71
57
|
- samuel.williams@oriontransfer.co.nz
|
72
58
|
executables: []
|
@@ -74,14 +60,17 @@ extensions: []
|
|
74
60
|
extra_rdoc_files: []
|
75
61
|
files:
|
76
62
|
- ".editorconfig"
|
63
|
+
- ".github/workflows/development.yml"
|
77
64
|
- ".gitignore"
|
78
65
|
- ".rspec"
|
79
|
-
- ".travis.yml"
|
80
|
-
- Gemfile
|
81
66
|
- README.md
|
67
|
+
- STREAMING.md
|
68
|
+
- bake.rb
|
69
|
+
- gems.rb
|
82
70
|
- lib/protocol/http.rb
|
83
71
|
- lib/protocol/http/accept_encoding.rb
|
84
72
|
- lib/protocol/http/body/buffered.rb
|
73
|
+
- lib/protocol/http/body/completable.rb
|
85
74
|
- lib/protocol/http/body/deflate.rb
|
86
75
|
- lib/protocol/http/body/digestable.rb
|
87
76
|
- lib/protocol/http/body/file.rb
|
@@ -91,7 +80,6 @@ files:
|
|
91
80
|
- lib/protocol/http/body/reader.rb
|
92
81
|
- lib/protocol/http/body/rewindable.rb
|
93
82
|
- lib/protocol/http/body/stream.rb
|
94
|
-
- lib/protocol/http/body/streamable.rb
|
95
83
|
- lib/protocol/http/body/wrapper.rb
|
96
84
|
- lib/protocol/http/content_encoding.rb
|
97
85
|
- lib/protocol/http/cookie.rb
|
@@ -119,13 +107,13 @@ homepage: https://github.com/socketry/protocol-http
|
|
119
107
|
licenses:
|
120
108
|
- MIT
|
121
109
|
metadata: {}
|
122
|
-
post_install_message:
|
110
|
+
post_install_message:
|
123
111
|
rdoc_options: []
|
124
112
|
require_paths:
|
125
113
|
- lib
|
126
114
|
required_ruby_version: !ruby/object:Gem::Requirement
|
127
115
|
requirements:
|
128
|
-
- - "
|
116
|
+
- - ">="
|
129
117
|
- !ruby/object:Gem::Version
|
130
118
|
version: '2.5'
|
131
119
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
@@ -135,7 +123,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
135
123
|
version: '0'
|
136
124
|
requirements: []
|
137
125
|
rubygems_version: 3.1.2
|
138
|
-
signing_key:
|
126
|
+
signing_key:
|
139
127
|
specification_version: 4
|
140
128
|
summary: Provides abstractions to handle HTTP protocols.
|
141
129
|
test_files: []
|
data/.travis.yml
DELETED
@@ -1,22 +0,0 @@
|
|
1
|
-
language: ruby
|
2
|
-
dist: xenial
|
3
|
-
cache: bundler
|
4
|
-
|
5
|
-
script: bundle exec rspec
|
6
|
-
|
7
|
-
matrix:
|
8
|
-
include:
|
9
|
-
- rvm: 2.5
|
10
|
-
- rvm: 2.6
|
11
|
-
- rvm: 2.7
|
12
|
-
- rvm: 2.6
|
13
|
-
env: COVERAGE=PartialSummary,Coveralls
|
14
|
-
- rvm: 2.7
|
15
|
-
- rvm: truffleruby
|
16
|
-
- rvm: jruby-head
|
17
|
-
env: JRUBY_OPTS="--debug -X+O"
|
18
|
-
- rvm: ruby-head
|
19
|
-
allow_failures:
|
20
|
-
- rvm: truffleruby
|
21
|
-
- rvm: ruby-head
|
22
|
-
- rvm: jruby-head
|