protocol-http 0.26.5 → 0.26.7
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/lib/protocol/http/body/buffered.rb +6 -2
- data/lib/protocol/http/body/readable.rb +11 -10
- data/lib/protocol/http/methods.rb +3 -3
- data/lib/protocol/http/request.rb +34 -14
- data/lib/protocol/http/response.rb +40 -0
- data/lib/protocol/http/url.rb +10 -2
- data/lib/protocol/http/version.rb +1 -1
- data/lib/protocol/http.rb +6 -1
- data/readme.md +3 -3
- data.tar.gz.sig +0 -0
- metadata +3 -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: 5821a26af6f718626313da18d47d4aba2e33f0f4ce3809551c91e1a57e10bfbd
|
4
|
+
data.tar.gz: a432928361e31ca78408e444dd05622dd6853e56f40b3581a19fe97d8dac8dcc
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 025540a24e4e72ea76257cee2c3bd4039854d6bd5f0f446553ffb5843aa2a41f278860d3f047b3c0861d8b15b120cbd03e1f54c2714583aabe7556451e6df728
|
7
|
+
data.tar.gz: e5b69ddfe8c874b00f6e36d03f48b71bb985f2c529df5aed4b4417ba1f10c258c768456897fdad1b63a9f257f4271472a3e56f7649664935e56ebb4a1136faf1
|
checksums.yaml.gz.sig
CHANGED
Binary file
|
@@ -1,7 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
# Released under the MIT License.
|
4
|
-
# Copyright, 2019-
|
4
|
+
# Copyright, 2019-2024, by Samuel Williams.
|
5
5
|
# Copyright, 2020, by Bryan Powell.
|
6
6
|
|
7
7
|
require_relative 'readable'
|
@@ -12,7 +12,11 @@ module Protocol
|
|
12
12
|
# A body which buffers all it's contents.
|
13
13
|
class Buffered < Readable
|
14
14
|
# Wraps an array into a buffered body.
|
15
|
-
#
|
15
|
+
#
|
16
|
+
# For compatibility, also accepts anything that behaves like an `Array(String)`.
|
17
|
+
#
|
18
|
+
# @parameter body [String | Array(String) | Readable | nil] the body to wrap.
|
19
|
+
# @returns [Readable | nil] the wrapped body or nil if nil was given.
|
16
20
|
def self.wrap(body)
|
17
21
|
if body.is_a?(Readable)
|
18
22
|
return body
|
@@ -7,17 +7,11 @@
|
|
7
7
|
module Protocol
|
8
8
|
module HTTP
|
9
9
|
module Body
|
10
|
-
#
|
11
|
-
#
|
12
|
-
#
|
13
|
-
# def read -> String | nil
|
14
|
-
# def join -> String
|
15
|
-
|
16
|
-
# def finish -> buffer the stream and close it.
|
17
|
-
# def close(error = nil) -> close the stream immediately.
|
18
|
-
# end
|
10
|
+
# An interface for reading data from a body.
|
11
|
+
#
|
12
|
+
# Typically, you'd override `#read` to return chunks of data.
|
19
13
|
class Readable
|
20
|
-
#
|
14
|
+
# Close the stream immediately.
|
21
15
|
def close(error = nil)
|
22
16
|
end
|
23
17
|
|
@@ -40,6 +34,7 @@ module Protocol
|
|
40
34
|
end
|
41
35
|
|
42
36
|
# Read the next available chunk.
|
37
|
+
# @returns [String | Nil] The chunk of data, or `nil` if the stream has finished.
|
43
38
|
def read
|
44
39
|
nil
|
45
40
|
end
|
@@ -60,12 +55,16 @@ module Protocol
|
|
60
55
|
end
|
61
56
|
|
62
57
|
# Read all remaining chunks into a buffered body and close the underlying input.
|
58
|
+
# @returns [Buffered] The buffered body.
|
63
59
|
def finish
|
64
60
|
# Internally, this invokes `self.each` which then invokes `self.close`.
|
65
61
|
Buffered.for(self)
|
66
62
|
end
|
67
63
|
|
68
64
|
# Enumerate all chunks until finished, then invoke `#close`.
|
65
|
+
#
|
66
|
+
# @yields {|chunk| ...} The block to call with each chunk of data.
|
67
|
+
# @parameter chunk [String | Nil] The chunk of data, or `nil` if the stream has finished.
|
69
68
|
def each
|
70
69
|
return to_enum(:each) unless block_given?
|
71
70
|
|
@@ -79,6 +78,8 @@ module Protocol
|
|
79
78
|
end
|
80
79
|
|
81
80
|
# Read all remaining chunks into a single binary string using `#each`.
|
81
|
+
#
|
82
|
+
# @returns [String | Nil] The binary string containing all chunks of data, or `nil` if the stream has finished (or did not contain any data).
|
82
83
|
def join
|
83
84
|
buffer = String.new.force_encoding(Encoding::BINARY)
|
84
85
|
|
@@ -1,7 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
# Released under the MIT License.
|
4
|
-
# Copyright, 2018-
|
4
|
+
# Copyright, 2018-2024, by Samuel Williams.
|
5
5
|
|
6
6
|
module Protocol
|
7
7
|
module HTTP
|
@@ -65,12 +65,12 @@ module Protocol
|
|
65
65
|
return to_enum(:each) unless block_given?
|
66
66
|
|
67
67
|
constants.each do |name|
|
68
|
-
yield name, const_get(name)
|
68
|
+
yield name.downcase, const_get(name)
|
69
69
|
end
|
70
70
|
end
|
71
71
|
|
72
72
|
self.each do |name, value|
|
73
|
-
define_method(name
|
73
|
+
define_method(name) do |location, headers = nil, body = nil|
|
74
74
|
self.call(
|
75
75
|
Request[value, location.to_s, Headers[headers], body]
|
76
76
|
)
|
@@ -11,6 +11,17 @@ require_relative 'methods'
|
|
11
11
|
|
12
12
|
module Protocol
|
13
13
|
module HTTP
|
14
|
+
# Represents an HTTP request which can be used both server and client-side.
|
15
|
+
#
|
16
|
+
# ~~~ ruby
|
17
|
+
# require 'protocol/http'
|
18
|
+
#
|
19
|
+
# # Long form:
|
20
|
+
# Protocol::HTTP::Request.new("http", "example.com", "GET", "/index.html", "HTTP/1.1", Protocol::HTTP::Headers[["accept", "text/html"]])
|
21
|
+
#
|
22
|
+
# # Short form:
|
23
|
+
# Protocol::HTTP::Request["GET", "/index.html", {"accept" => "text/html"}]
|
24
|
+
# ~~~
|
14
25
|
class Request
|
15
26
|
prepend Body::Reader
|
16
27
|
|
@@ -25,28 +36,28 @@ module Protocol
|
|
25
36
|
@protocol = protocol
|
26
37
|
end
|
27
38
|
|
28
|
-
#
|
39
|
+
# @attribute [String] the request scheme, usually `"http"` or `"https"`.
|
29
40
|
attr_accessor :scheme
|
30
|
-
|
31
|
-
#
|
41
|
+
|
42
|
+
# @attribute [String] the request authority, usually a hostname and port number, e.g. `"example.com:80"`.
|
32
43
|
attr_accessor :authority
|
33
|
-
|
34
|
-
#
|
44
|
+
|
45
|
+
# @attribute [String] the request method, usually one of `"GET"`, `"HEAD"`, `"POST"`, `"PUT"`, `"DELETE"`, `"CONNECT"` or `"OPTIONS"`, etc.
|
35
46
|
attr_accessor :method
|
36
|
-
|
37
|
-
#
|
47
|
+
|
48
|
+
# @attribute [String] the request path, usually a path and query string, e.g. `"/index.html"`, `"/search?q=hello"`, however it can be any [valid request target](https://www.rfc-editor.org/rfc/rfc9110#target.resource).
|
38
49
|
attr_accessor :path
|
39
|
-
|
40
|
-
#
|
50
|
+
|
51
|
+
# @attribute [String] the request version, usually `"http/1.0"`, `"http/1.1"`, `"h2"`, or `"h3"`.
|
41
52
|
attr_accessor :version
|
42
|
-
|
43
|
-
#
|
53
|
+
|
54
|
+
# @attribute [Headers] the request headers, usually containing metadata associated with the request such as the `"user-agent"`, `"accept"` (content type), `"accept-language"`, etc.
|
44
55
|
attr_accessor :headers
|
45
|
-
|
46
|
-
#
|
56
|
+
|
57
|
+
# @attribute [Body::Readable] the request body. It should only be read once (it may not be idempotent).
|
47
58
|
attr_accessor :body
|
48
59
|
|
49
|
-
#
|
60
|
+
# @attribute [String | Array(String) | Nil] the request protocol, usually empty, but occasionally `"websocket"` or `"webtransport"`. In HTTP/1, it is used to request a connection upgrade, and in HTTP/2 it is used to indicate a specfic protocol for the stream.
|
50
61
|
attr_accessor :protocol
|
51
62
|
|
52
63
|
# Send the request to the given connection.
|
@@ -54,14 +65,22 @@ module Protocol
|
|
54
65
|
connection.call(self)
|
55
66
|
end
|
56
67
|
|
68
|
+
# Whether this is a HEAD request: no body is expected in the response.
|
57
69
|
def head?
|
58
70
|
@method == Methods::HEAD
|
59
71
|
end
|
60
72
|
|
73
|
+
# Whether this is a CONNECT request: typically used to establish a tunnel.
|
61
74
|
def connect?
|
62
75
|
@method == Methods::CONNECT
|
63
76
|
end
|
64
77
|
|
78
|
+
# A short-cut method which exposes the main request variables that you'd typically care about.
|
79
|
+
#
|
80
|
+
# @parameter method [String] The HTTP method, e.g. `"GET"`, `"POST"`, etc.
|
81
|
+
# @parameter path [String] The path, e.g. `"/index.html"`, `"/search?q=hello"`, etc.
|
82
|
+
# @parameter headers [Hash] The headers, e.g. `{"accept" => "text/html"}`, etc.
|
83
|
+
# @parameter body [String | Array(String) | Body::Readable] The body, e.g. `"Hello, World!"`, etc. See {Body::Buffered.wrap} for more information about .
|
65
84
|
def self.[](method, path, headers = nil, body = nil)
|
66
85
|
body = Body::Buffered.wrap(body)
|
67
86
|
headers = ::Protocol::HTTP::Headers[headers]
|
@@ -69,6 +88,7 @@ module Protocol
|
|
69
88
|
self.new(nil, nil, method, path, nil, headers, body)
|
70
89
|
end
|
71
90
|
|
91
|
+
# Whether the request can be replayed without side-effects.
|
72
92
|
def idempotent?
|
73
93
|
@method != Methods::POST && (@body.nil? || @body.empty?)
|
74
94
|
end
|
@@ -8,9 +8,27 @@ require_relative 'body/reader'
|
|
8
8
|
|
9
9
|
module Protocol
|
10
10
|
module HTTP
|
11
|
+
# Represents an HTTP response which can be used both server and client-side.
|
12
|
+
#
|
13
|
+
# ~~~ ruby
|
14
|
+
# require 'protocol/http'
|
15
|
+
#
|
16
|
+
# # Long form:
|
17
|
+
# Protocol::HTTP::Response.new("http/1.1", 200, Protocol::HTTP::Headers[["content-type", "text/html"]], Protocol::HTTP::Body::Buffered.wrap("Hello, World!"))
|
18
|
+
#
|
19
|
+
# # Short form:
|
20
|
+
# Protocol::HTTP::Response[200, {"content-type" => "text/html"}, ["Hello, World!"]]
|
21
|
+
# ~~~
|
11
22
|
class Response
|
12
23
|
prepend Body::Reader
|
13
24
|
|
25
|
+
# Create a new response.
|
26
|
+
#
|
27
|
+
# @parameter version [String | Nil] The HTTP version, e.g. `"HTTP/1.1"`. If `nil`, the version may be provided by the server sending the response.
|
28
|
+
# @parameter status [Integer] The HTTP status code, e.g. `200`, `404`, etc.
|
29
|
+
# @parameter headers [Hash] The headers, e.g. `{"content-type" => "text/html"}`, etc.
|
30
|
+
# @parameter body [Body::Readable] The body, e.g. `"Hello, World!"`, etc.
|
31
|
+
# @parameter protocol [String | Array(String)] The protocol, e.g. `"websocket"`, etc.
|
14
32
|
def initialize(version = nil, status = 200, headers = Headers.new, body = nil, protocol = nil)
|
15
33
|
@version = version
|
16
34
|
@status = status
|
@@ -19,12 +37,22 @@ module Protocol
|
|
19
37
|
@protocol = protocol
|
20
38
|
end
|
21
39
|
|
40
|
+
# @attribute [String | Nil] The HTTP version, usually one of `"HTTP/1.1"`, `"HTTP/2"`, etc.
|
22
41
|
attr_accessor :version
|
42
|
+
|
43
|
+
# @attribute [Integer] The HTTP status code, e.g. `200`, `404`, etc.
|
23
44
|
attr_accessor :status
|
45
|
+
|
46
|
+
# @attribute [Hash] The headers, e.g. `{"content-type" => "text/html"}`, etc.
|
24
47
|
attr_accessor :headers
|
48
|
+
|
49
|
+
# @attribute [Body::Readable] The body, e.g. `"Hello, World!"`, etc.
|
25
50
|
attr_accessor :body
|
51
|
+
|
52
|
+
# @attribute [String | Array(String) | Nil] The protocol, e.g. `"websocket"`, etc.
|
26
53
|
attr_accessor :protocol
|
27
54
|
|
55
|
+
# Whether the response is considered a hijack: the connection has been taken over by the application and the server should not send any more data.
|
28
56
|
def hijack?
|
29
57
|
false
|
30
58
|
end
|
@@ -93,6 +121,15 @@ module Protocol
|
|
93
121
|
# @deprecated Use {#internal_server_error?} instead.
|
94
122
|
alias server_failure? internal_server_error?
|
95
123
|
|
124
|
+
# A short-cut method which exposes the main response variables that you'd typically care about. It follows the same order as the `Rack` response tuple, but also includes the protocol.
|
125
|
+
#
|
126
|
+
# ~~~ ruby
|
127
|
+
# Response[200, {"content-type" => "text/html"}, ["Hello, World!"]]
|
128
|
+
# ~~~
|
129
|
+
#
|
130
|
+
# @parameter status [Integer] The HTTP status code, e.g. `200`, `404`, etc.
|
131
|
+
# @parameter headers [Hash] The headers, e.g. `{"content-type" => "text/html"}`, etc.
|
132
|
+
# @parameter body [String | Array(String) | Body::Readable] The body, e.g. `"Hello, World!"`, etc. See {Body::Buffered.wrap} for more information about .
|
96
133
|
def self.[](status, headers = nil, body = nil, protocol = nil)
|
97
134
|
body = Body::Buffered.wrap(body)
|
98
135
|
headers = ::Protocol::HTTP::Headers[headers]
|
@@ -100,6 +137,9 @@ module Protocol
|
|
100
137
|
self.new(nil, status, headers, body, protocol)
|
101
138
|
end
|
102
139
|
|
140
|
+
# Create a response for the given exception.
|
141
|
+
#
|
142
|
+
# @parameter exception [Exception] The exception to generate the response for.
|
103
143
|
def self.for_exception(exception)
|
104
144
|
Response[500, Headers['content-type' => 'text/plain'], ["#{exception.class}: #{exception.message}"]]
|
105
145
|
end
|
data/lib/protocol/http/url.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
# Released under the MIT License.
|
4
|
-
# Copyright, 2019-
|
4
|
+
# Copyright, 2019-2024, by Samuel Williams.
|
5
5
|
# Copyright, 2022, by Herrick Fang.
|
6
6
|
|
7
7
|
module Protocol
|
@@ -65,9 +65,13 @@ module Protocol
|
|
65
65
|
end
|
66
66
|
|
67
67
|
def self.split(name)
|
68
|
-
name.scan(/([^\[]+)|(?:\[(.*?)\])/)
|
68
|
+
name.scan(/([^\[]+)|(?:\[(.*?)\])/)&.tap do |parts|
|
69
|
+
parts.flatten!
|
70
|
+
parts.compact!
|
71
|
+
end
|
69
72
|
end
|
70
73
|
|
74
|
+
# Assign a value to a nested hash.
|
71
75
|
def self.assign(keys, value, parent)
|
72
76
|
top, *middle = keys
|
73
77
|
|
@@ -95,6 +99,10 @@ module Protocol
|
|
95
99
|
self.scan(string) do |name, value|
|
96
100
|
keys = self.split(name)
|
97
101
|
|
102
|
+
if keys.empty?
|
103
|
+
raise ArgumentError, "Invalid key path: #{name.inspect}!"
|
104
|
+
end
|
105
|
+
|
98
106
|
if keys.size > maximum
|
99
107
|
raise ArgumentError, "Key length exceeded limit!"
|
100
108
|
end
|
data/lib/protocol/http.rb
CHANGED
@@ -1,6 +1,11 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
# Released under the MIT License.
|
4
|
-
# Copyright, 2018-
|
4
|
+
# Copyright, 2018-2024, by Samuel Williams.
|
5
5
|
|
6
6
|
require_relative "http/version"
|
7
|
+
|
8
|
+
require_relative 'http/headers'
|
9
|
+
require_relative 'http/request'
|
10
|
+
require_relative 'http/response'
|
11
|
+
require_relative 'http/middleware'
|
data/readme.md
CHANGED
@@ -30,11 +30,11 @@ We welcome contributions to this project.
|
|
30
30
|
|
31
31
|
### Developer Certificate of Origin
|
32
32
|
|
33
|
-
|
33
|
+
In order to protect users of this project, we require all contributors to comply with the [Developer Certificate of Origin](https://developercertificate.org/). This ensures that all contributions are properly licensed and attributed.
|
34
34
|
|
35
|
-
###
|
35
|
+
### Community Guidelines
|
36
36
|
|
37
|
-
This project is
|
37
|
+
This project is best served by a collaborative and respectful environment. Treat each other professionally, respect differing viewpoints, and engage constructively. Harassment, discrimination, or harmful behavior is not tolerated. Communicate clearly, listen actively, and support one another. If any issues arise, please inform the project maintainers.
|
38
38
|
|
39
39
|
## See Also
|
40
40
|
|
data.tar.gz.sig
CHANGED
Binary file
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: protocol-http
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.26.
|
4
|
+
version: 0.26.7
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Samuel Williams
|
@@ -47,7 +47,7 @@ cert_chain:
|
|
47
47
|
Q2K9NVun/S785AP05vKkXZEFYxqG6EW012U4oLcFl5MySFajYXRYbuUpH6AY+HP8
|
48
48
|
voD0MPg1DssDLKwXyt1eKD/+Fq0bFWhwVM/1XiAXL7lyYUyOq24KHgQ2Csg=
|
49
49
|
-----END CERTIFICATE-----
|
50
|
-
date: 2024-
|
50
|
+
date: 2024-07-07 00:00:00.000000000 Z
|
51
51
|
dependencies: []
|
52
52
|
description:
|
53
53
|
email:
|
@@ -114,7 +114,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
114
114
|
- !ruby/object:Gem::Version
|
115
115
|
version: '0'
|
116
116
|
requirements: []
|
117
|
-
rubygems_version: 3.5.
|
117
|
+
rubygems_version: 3.5.11
|
118
118
|
signing_key:
|
119
119
|
specification_version: 4
|
120
120
|
summary: Provides abstractions to handle HTTP protocols.
|
metadata.gz.sig
CHANGED
Binary file
|