protocol-http 0.35.0 → 0.37.0
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.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data/lib/protocol/http/accept_encoding.rb +7 -7
- data/lib/protocol/http/body/buffered.rb +8 -1
- data/lib/protocol/http/body/completable.rb +1 -1
- data/lib/protocol/http/body/deflate.rb +8 -5
- data/lib/protocol/http/body/digestable.rb +2 -2
- data/lib/protocol/http/body/file.rb +1 -1
- data/lib/protocol/http/body/head.rb +1 -1
- data/lib/protocol/http/body/inflate.rb +32 -22
- data/lib/protocol/http/body/readable.rb +10 -0
- data/lib/protocol/http/body/reader.rb +8 -0
- data/lib/protocol/http/body/rewindable.rb +2 -2
- data/lib/protocol/http/body/stream.rb +2 -2
- data/lib/protocol/http/body/streamable.rb +3 -3
- data/lib/protocol/http/body/wrapper.rb +5 -1
- data/lib/protocol/http/body/writable.rb +5 -5
- data/lib/protocol/http/content_encoding.rb +9 -9
- data/lib/protocol/http/cookie.rb +6 -6
- data/lib/protocol/http/header/authorization.rb +1 -1
- data/lib/protocol/http/header/cache_control.rb +13 -13
- data/lib/protocol/http/header/connection.rb +4 -4
- data/lib/protocol/http/header/cookie.rb +2 -2
- data/lib/protocol/http/header/date.rb +1 -1
- data/lib/protocol/http/header/etag.rb +1 -1
- data/lib/protocol/http/header/etags.rb +3 -3
- data/lib/protocol/http/header/vary.rb +1 -1
- data/lib/protocol/http/headers.rb +39 -39
- data/lib/protocol/http/methods.rb +9 -9
- data/lib/protocol/http/middleware/builder.rb +1 -1
- data/lib/protocol/http/middleware.rb +5 -5
- data/lib/protocol/http/reference.rb +20 -20
- data/lib/protocol/http/request.rb +4 -4
- data/lib/protocol/http/response.rb +3 -3
- data/lib/protocol/http/url.rb +5 -5
- data/lib/protocol/http/version.rb +1 -1
- data/lib/protocol/http.rb +4 -4
- data.tar.gz.sig +0 -0
- metadata +2 -2
- 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: 077e5dedb752c1fcbaf9cd4385815019bb17b9bf6d1e47943b39f90dc5d09025
|
4
|
+
data.tar.gz: 543a8f7b47ea5216d5753e97f90d02a787b21e38613ba431119f648cf7571694
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: bd1b08154595e4d417e3121bd7e7d0da704de64c54228da39a82c875dc19c1c06924cc8eb43ed710086bf9a2c2c404e79fe7191c360f23fa671c85ac4d995b64
|
7
|
+
data.tar.gz: 38700f2f25e04f633afdae9146ce3e135631618dd9dee9acf79953bdfad5487f7f7915cadc3c0d65f77aba646a6b68c80f33457f71c34009ffed257b49e4dd3a
|
checksums.yaml.gz.sig
CHANGED
Binary file
|
@@ -3,20 +3,20 @@
|
|
3
3
|
# Released under the MIT License.
|
4
4
|
# Copyright, 2019-2023, by Samuel Williams.
|
5
5
|
|
6
|
-
require_relative
|
6
|
+
require_relative "middleware"
|
7
7
|
|
8
|
-
require_relative
|
9
|
-
require_relative
|
8
|
+
require_relative "body/buffered"
|
9
|
+
require_relative "body/inflate"
|
10
10
|
|
11
11
|
module Protocol
|
12
12
|
module HTTP
|
13
13
|
# Set a valid accept-encoding header and decode the response.
|
14
14
|
class AcceptEncoding < Middleware
|
15
|
-
ACCEPT_ENCODING =
|
16
|
-
CONTENT_ENCODING =
|
15
|
+
ACCEPT_ENCODING = "accept-encoding".freeze
|
16
|
+
CONTENT_ENCODING = "content-encoding".freeze
|
17
17
|
|
18
18
|
DEFAULT_WRAPPERS = {
|
19
|
-
|
19
|
+
"gzip" => Body::Inflate.method(:for),
|
20
20
|
|
21
21
|
# There is no point including this:
|
22
22
|
# 'identity' => ->(body){body},
|
@@ -25,7 +25,7 @@ module Protocol
|
|
25
25
|
def initialize(app, wrappers = DEFAULT_WRAPPERS)
|
26
26
|
super(app)
|
27
27
|
|
28
|
-
@accept_encoding = wrappers.keys.join(
|
28
|
+
@accept_encoding = wrappers.keys.join(", ")
|
29
29
|
@wrappers = wrappers
|
30
30
|
end
|
31
31
|
|
@@ -4,7 +4,7 @@
|
|
4
4
|
# Copyright, 2019-2024, by Samuel Williams.
|
5
5
|
# Copyright, 2020, by Bryan Powell.
|
6
6
|
|
7
|
-
require_relative
|
7
|
+
require_relative "readable"
|
8
8
|
|
9
9
|
module Protocol
|
10
10
|
module HTTP
|
@@ -59,6 +59,8 @@ module Protocol
|
|
59
59
|
# Ensure that future reads return nil, but allow for rewinding.
|
60
60
|
def close(error = nil)
|
61
61
|
@index = @chunks.length
|
62
|
+
|
63
|
+
return nil
|
62
64
|
end
|
63
65
|
|
64
66
|
def clear
|
@@ -90,6 +92,11 @@ module Protocol
|
|
90
92
|
end
|
91
93
|
end
|
92
94
|
|
95
|
+
def discard
|
96
|
+
# It's safe to call close here because there is no underlying stream to close:
|
97
|
+
self.close
|
98
|
+
end
|
99
|
+
|
93
100
|
def write(chunk)
|
94
101
|
@chunks << chunk
|
95
102
|
end
|
@@ -3,9 +3,9 @@
|
|
3
3
|
# Released under the MIT License.
|
4
4
|
# Copyright, 2019-2024, by Samuel Williams.
|
5
5
|
|
6
|
-
require_relative
|
6
|
+
require_relative "wrapper"
|
7
7
|
|
8
|
-
require
|
8
|
+
require "zlib"
|
9
9
|
|
10
10
|
module Protocol
|
11
11
|
module HTTP
|
@@ -17,8 +17,8 @@ module Protocol
|
|
17
17
|
GZIP = Zlib::MAX_WBITS | 16
|
18
18
|
|
19
19
|
ENCODINGS = {
|
20
|
-
|
21
|
-
|
20
|
+
"deflate" => DEFLATE,
|
21
|
+
"gzip" => GZIP,
|
22
22
|
}
|
23
23
|
|
24
24
|
def initialize(body, stream)
|
@@ -31,7 +31,10 @@ module Protocol
|
|
31
31
|
end
|
32
32
|
|
33
33
|
def close(error = nil)
|
34
|
-
|
34
|
+
if stream = @stream
|
35
|
+
@stream = nil
|
36
|
+
stream.close unless stream.closed?
|
37
|
+
end
|
35
38
|
|
36
39
|
super
|
37
40
|
end
|
@@ -3,9 +3,9 @@
|
|
3
3
|
# Released under the MIT License.
|
4
4
|
# Copyright, 2019-2024, by Samuel Williams.
|
5
5
|
|
6
|
-
require
|
6
|
+
require "zlib"
|
7
7
|
|
8
|
-
require_relative
|
8
|
+
require_relative "deflate"
|
9
9
|
|
10
10
|
module Protocol
|
11
11
|
module HTTP
|
@@ -16,30 +16,40 @@ module Protocol
|
|
16
16
|
end
|
17
17
|
|
18
18
|
def read
|
19
|
-
|
19
|
+
if stream = @stream
|
20
|
+
# Read from the underlying stream and inflate it:
|
21
|
+
while chunk = super
|
22
|
+
@input_length += chunk.bytesize
|
23
|
+
|
24
|
+
# It's possible this triggers the stream to finish.
|
25
|
+
chunk = stream.inflate(chunk)
|
26
|
+
|
27
|
+
break unless chunk&.empty?
|
28
|
+
end
|
20
29
|
|
21
|
-
|
22
|
-
|
23
|
-
|
30
|
+
if chunk
|
31
|
+
@output_length += chunk.bytesize
|
32
|
+
elsif !stream.closed?
|
33
|
+
chunk = stream.finish
|
34
|
+
@output_length += chunk.bytesize
|
35
|
+
end
|
24
36
|
|
25
|
-
#
|
26
|
-
|
37
|
+
# If the stream is finished, we need to close it and potentially return nil:
|
38
|
+
if stream.finished?
|
39
|
+
@stream = nil
|
40
|
+
stream.close
|
41
|
+
|
42
|
+
while super
|
43
|
+
# There is data left in the stream, so we need to keep reading until it's all consumed.
|
44
|
+
end
|
45
|
+
|
46
|
+
if chunk.empty?
|
47
|
+
return nil
|
48
|
+
end
|
49
|
+
end
|
27
50
|
|
28
|
-
|
51
|
+
return chunk
|
29
52
|
end
|
30
|
-
|
31
|
-
if chunk
|
32
|
-
@output_length += chunk.bytesize
|
33
|
-
elsif !@stream.closed?
|
34
|
-
chunk = @stream.finish
|
35
|
-
@output_length += chunk.bytesize
|
36
|
-
end
|
37
|
-
|
38
|
-
if chunk.empty? and @stream.finished?
|
39
|
-
return nil
|
40
|
-
end
|
41
|
-
|
42
|
-
return chunk
|
43
53
|
end
|
44
54
|
end
|
45
55
|
end
|
@@ -133,6 +133,16 @@ module Protocol
|
|
133
133
|
Buffered.read(self)
|
134
134
|
end
|
135
135
|
|
136
|
+
# Discard the body as efficiently as possible.
|
137
|
+
#
|
138
|
+
# The default implementation simply reads all chunks until the body is empty.
|
139
|
+
#
|
140
|
+
# Useful for discarding the body when it is not needed, but preserving the underlying connection.
|
141
|
+
def discard
|
142
|
+
while chunk = self.read
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
136
146
|
def as_json(...)
|
137
147
|
{
|
138
148
|
class: self.class.name,
|
@@ -40,6 +40,14 @@ module Protocol
|
|
40
40
|
end
|
41
41
|
end
|
42
42
|
|
43
|
+
# Discard the body as efficiently as possible.
|
44
|
+
def discard
|
45
|
+
if body = @body
|
46
|
+
@body = nil
|
47
|
+
body.discard
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
43
51
|
# Buffer the entire request/response body.
|
44
52
|
# @returns [Reader] itself.
|
45
53
|
def buffered!
|
@@ -4,7 +4,7 @@
|
|
4
4
|
# Copyright, 2019-2024, by Samuel Williams.
|
5
5
|
# Copyright, 2023, by Genki Takiuchi.
|
6
6
|
|
7
|
-
require_relative
|
7
|
+
require_relative "buffered"
|
8
8
|
|
9
9
|
module Protocol
|
10
10
|
module HTTP
|
@@ -43,7 +43,7 @@ module Protocol
|
|
43
43
|
# @param buffer [String] the buffer which will receive the data
|
44
44
|
# @return a buffer containing the data
|
45
45
|
def read(length = nil, buffer = nil)
|
46
|
-
return
|
46
|
+
return "" if length == 0
|
47
47
|
|
48
48
|
buffer ||= String.new.force_encoding(Encoding::BINARY)
|
49
49
|
|
@@ -3,10 +3,10 @@
|
|
3
3
|
# Released under the MIT License.
|
4
4
|
# Copyright, 2019-2024, by Samuel Williams.
|
5
5
|
|
6
|
-
require_relative
|
7
|
-
require_relative
|
6
|
+
require_relative "readable"
|
7
|
+
require_relative "writable"
|
8
8
|
|
9
|
-
require_relative
|
9
|
+
require_relative "stream"
|
10
10
|
|
11
11
|
module Protocol
|
12
12
|
module HTTP
|
@@ -3,7 +3,7 @@
|
|
3
3
|
# Released under the MIT License.
|
4
4
|
# Copyright, 2019-2024, by Samuel Williams.
|
5
5
|
|
6
|
-
require_relative
|
6
|
+
require_relative "readable"
|
7
7
|
|
8
8
|
module Protocol
|
9
9
|
module HTTP
|
@@ -59,6 +59,10 @@ module Protocol
|
|
59
59
|
@body.read
|
60
60
|
end
|
61
61
|
|
62
|
+
def discard
|
63
|
+
@body.discard
|
64
|
+
end
|
65
|
+
|
62
66
|
def as_json(...)
|
63
67
|
{
|
64
68
|
class: self.class.name,
|
@@ -3,7 +3,7 @@
|
|
3
3
|
# Released under the MIT License.
|
4
4
|
# Copyright, 2024, by Samuel Williams.
|
5
5
|
|
6
|
-
require_relative
|
6
|
+
require_relative "readable"
|
7
7
|
|
8
8
|
module Protocol
|
9
9
|
module HTTP
|
@@ -137,15 +137,15 @@ module Protocol
|
|
137
137
|
def status
|
138
138
|
if @queue.empty?
|
139
139
|
if @queue.closed?
|
140
|
-
|
140
|
+
"closed"
|
141
141
|
else
|
142
|
-
|
142
|
+
"waiting"
|
143
143
|
end
|
144
144
|
else
|
145
145
|
if @queue.closed?
|
146
|
-
|
146
|
+
"closing"
|
147
147
|
else
|
148
|
-
|
148
|
+
"ready"
|
149
149
|
end
|
150
150
|
end
|
151
151
|
end
|
@@ -3,17 +3,17 @@
|
|
3
3
|
# Released under the MIT License.
|
4
4
|
# Copyright, 2019-2023, by Samuel Williams.
|
5
5
|
|
6
|
-
require_relative
|
6
|
+
require_relative "middleware"
|
7
7
|
|
8
|
-
require_relative
|
9
|
-
require_relative
|
8
|
+
require_relative "body/buffered"
|
9
|
+
require_relative "body/deflate"
|
10
10
|
|
11
11
|
module Protocol
|
12
12
|
module HTTP
|
13
13
|
# Encode a response according the the request's acceptable encodings.
|
14
14
|
class ContentEncoding < Middleware
|
15
15
|
DEFAULT_WRAPPERS = {
|
16
|
-
|
16
|
+
"gzip" => Body::Deflate.method(:for)
|
17
17
|
}
|
18
18
|
|
19
19
|
DEFAULT_CONTENT_TYPES = %r{^(text/.*?)|(.*?/json)|(.*?/javascript)$}
|
@@ -29,24 +29,24 @@ module Protocol
|
|
29
29
|
response = super
|
30
30
|
|
31
31
|
# Early exit if the response has already specified a content-encoding.
|
32
|
-
return response if response.headers[
|
32
|
+
return response if response.headers["content-encoding"]
|
33
33
|
|
34
34
|
# This is a very tricky issue, so we avoid it entirely.
|
35
35
|
# https://lists.w3.org/Archives/Public/ietf-http-wg/2014JanMar/1179.html
|
36
36
|
return response if response.partial?
|
37
37
|
|
38
38
|
# Ensure that caches are aware we are varying the response based on the accept-encoding request header:
|
39
|
-
response.headers.add(
|
39
|
+
response.headers.add("vary", "accept-encoding")
|
40
40
|
|
41
41
|
# TODO use http-accept and sort by priority
|
42
|
-
if !response.body.empty? and accept_encoding = request.headers[
|
42
|
+
if !response.body.empty? and accept_encoding = request.headers["accept-encoding"]
|
43
43
|
|
44
|
-
if content_type = response.headers[
|
44
|
+
if content_type = response.headers["content-type"] and @content_types =~ content_type
|
45
45
|
body = response.body
|
46
46
|
|
47
47
|
accept_encoding.each do |name|
|
48
48
|
if wrapper = @wrappers[name]
|
49
|
-
response.headers[
|
49
|
+
response.headers["content-encoding"] = name
|
50
50
|
|
51
51
|
body = wrapper.call(body)
|
52
52
|
|
data/lib/protocol/http/cookie.rb
CHANGED
@@ -4,7 +4,7 @@
|
|
4
4
|
# Copyright, 2019-2023, by Samuel Williams.
|
5
5
|
# Copyright, 2022, by Herrick Fang.
|
6
6
|
|
7
|
-
require_relative
|
7
|
+
require_relative "url"
|
8
8
|
|
9
9
|
module Protocol
|
10
10
|
module HTTP
|
@@ -31,15 +31,15 @@ module Protocol
|
|
31
31
|
def to_s
|
32
32
|
buffer = String.new.b
|
33
33
|
|
34
|
-
buffer << encoded_name <<
|
34
|
+
buffer << encoded_name << "=" << encoded_value
|
35
35
|
|
36
36
|
if @directives
|
37
37
|
@directives.collect do |key, value|
|
38
|
-
buffer <<
|
38
|
+
buffer << ";"
|
39
39
|
|
40
40
|
case value
|
41
41
|
when String
|
42
|
-
buffer << key <<
|
42
|
+
buffer << key << "=" << value
|
43
43
|
when TrueClass
|
44
44
|
buffer << key
|
45
45
|
end
|
@@ -52,7 +52,7 @@ module Protocol
|
|
52
52
|
def self.parse(string)
|
53
53
|
head, *directives = string.split(/\s*;\s*/)
|
54
54
|
|
55
|
-
key, value = head.split(
|
55
|
+
key, value = head.split("=", 2)
|
56
56
|
directives = self.parse_directives(directives)
|
57
57
|
|
58
58
|
self.new(
|
@@ -64,7 +64,7 @@ module Protocol
|
|
64
64
|
|
65
65
|
def self.parse_directives(strings)
|
66
66
|
strings.collect do |string|
|
67
|
-
key, value = string.split(
|
67
|
+
key, value = string.split("=", 2)
|
68
68
|
[key, value || true]
|
69
69
|
end.to_h
|
70
70
|
end
|
@@ -4,25 +4,25 @@
|
|
4
4
|
# Copyright, 2020-2023, by Samuel Williams.
|
5
5
|
# Copyright, 2023, by Thomas Morgan.
|
6
6
|
|
7
|
-
require_relative
|
7
|
+
require_relative "split"
|
8
8
|
|
9
9
|
module Protocol
|
10
10
|
module HTTP
|
11
11
|
module Header
|
12
12
|
class CacheControl < Split
|
13
|
-
PRIVATE =
|
14
|
-
PUBLIC =
|
15
|
-
NO_CACHE =
|
16
|
-
NO_STORE =
|
17
|
-
MAX_AGE =
|
18
|
-
S_MAXAGE =
|
13
|
+
PRIVATE = "private"
|
14
|
+
PUBLIC = "public"
|
15
|
+
NO_CACHE = "no-cache"
|
16
|
+
NO_STORE = "no-store"
|
17
|
+
MAX_AGE = "max-age"
|
18
|
+
S_MAXAGE = "s-maxage"
|
19
19
|
|
20
|
-
STATIC =
|
21
|
-
DYNAMIC =
|
22
|
-
STREAMING =
|
20
|
+
STATIC = "static"
|
21
|
+
DYNAMIC = "dynamic"
|
22
|
+
STREAMING = "streaming"
|
23
23
|
|
24
|
-
MUST_REVALIDATE =
|
25
|
-
PROXY_REVALIDATE =
|
24
|
+
MUST_REVALIDATE = "must-revalidate"
|
25
|
+
PROXY_REVALIDATE = "proxy-revalidate"
|
26
26
|
|
27
27
|
def initialize(value = nil)
|
28
28
|
super(value&.downcase)
|
@@ -89,7 +89,7 @@ module Protocol
|
|
89
89
|
|
90
90
|
def find_integer_value(value_name)
|
91
91
|
if value = self.find{|value| value.start_with?(value_name)}
|
92
|
-
_, age = value.split(
|
92
|
+
_, age = value.split("=", 2)
|
93
93
|
|
94
94
|
if age =~ /\A[0-9]+\z/
|
95
95
|
return Integer(age)
|
@@ -4,15 +4,15 @@
|
|
4
4
|
# Copyright, 2019-2024, by Samuel Williams.
|
5
5
|
# Copyright, 2024, by Thomas Morgan.
|
6
6
|
|
7
|
-
require_relative
|
7
|
+
require_relative "split"
|
8
8
|
|
9
9
|
module Protocol
|
10
10
|
module HTTP
|
11
11
|
module Header
|
12
12
|
class Connection < Split
|
13
|
-
KEEP_ALIVE =
|
14
|
-
CLOSE =
|
15
|
-
UPGRADE =
|
13
|
+
KEEP_ALIVE = "keep-alive"
|
14
|
+
CLOSE = "close"
|
15
|
+
UPGRADE = "upgrade"
|
16
16
|
|
17
17
|
def initialize(value = nil)
|
18
18
|
super(value&.downcase)
|
@@ -4,14 +4,14 @@
|
|
4
4
|
# Copyright, 2020-2023, by Samuel Williams.
|
5
5
|
# Copyright, 2023, by Thomas Morgan.
|
6
6
|
|
7
|
-
require_relative
|
7
|
+
require_relative "split"
|
8
8
|
|
9
9
|
module Protocol
|
10
10
|
module HTTP
|
11
11
|
module Header
|
12
12
|
class ETags < Split
|
13
13
|
def wildcard?
|
14
|
-
self.include?(
|
14
|
+
self.include?("*")
|
15
15
|
end
|
16
16
|
|
17
17
|
# This implementation is not strictly correct according to the RFC-specified format.
|
@@ -36,7 +36,7 @@ module Protocol
|
|
36
36
|
end
|
37
37
|
|
38
38
|
def weak_tag?(tag)
|
39
|
-
tag&.start_with?
|
39
|
+
tag&.start_with? "W/"
|
40
40
|
end
|
41
41
|
end
|
42
42
|
end
|
@@ -3,16 +3,16 @@
|
|
3
3
|
# Released under the MIT License.
|
4
4
|
# Copyright, 2018-2024, by Samuel Williams.
|
5
5
|
|
6
|
-
require_relative
|
7
|
-
require_relative
|
8
|
-
require_relative
|
9
|
-
require_relative
|
10
|
-
require_relative
|
11
|
-
require_relative
|
12
|
-
require_relative
|
13
|
-
require_relative
|
14
|
-
require_relative
|
15
|
-
require_relative
|
6
|
+
require_relative "header/split"
|
7
|
+
require_relative "header/multiple"
|
8
|
+
require_relative "header/cookie"
|
9
|
+
require_relative "header/connection"
|
10
|
+
require_relative "header/cache_control"
|
11
|
+
require_relative "header/etag"
|
12
|
+
require_relative "header/etags"
|
13
|
+
require_relative "header/vary"
|
14
|
+
require_relative "header/authorization"
|
15
|
+
require_relative "header/date"
|
16
16
|
|
17
17
|
module Protocol
|
18
18
|
module HTTP
|
@@ -21,7 +21,7 @@ module Protocol
|
|
21
21
|
Split = Header::Split
|
22
22
|
Multiple = Header::Multiple
|
23
23
|
|
24
|
-
TRAILER =
|
24
|
+
TRAILER = "trailer"
|
25
25
|
|
26
26
|
# 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.
|
27
27
|
# @return [Headers] an instance of headers.
|
@@ -203,49 +203,49 @@ module Protocol
|
|
203
203
|
|
204
204
|
POLICY = {
|
205
205
|
# Headers which may only be specified once.
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
206
|
+
"content-type" => false,
|
207
|
+
"content-disposition" => false,
|
208
|
+
"content-length" => false,
|
209
|
+
"user-agent" => false,
|
210
|
+
"referer" => false,
|
211
|
+
"host" => false,
|
212
|
+
"from" => false,
|
213
|
+
"location" => false,
|
214
|
+
"max-forwards" => false,
|
215
215
|
|
216
216
|
# Custom headers:
|
217
|
-
|
218
|
-
|
219
|
-
|
217
|
+
"connection" => Header::Connection,
|
218
|
+
"cache-control" => Header::CacheControl,
|
219
|
+
"vary" => Header::Vary,
|
220
220
|
|
221
221
|
# Headers specifically for proxies:
|
222
|
-
|
223
|
-
|
222
|
+
"via" => Split,
|
223
|
+
"x-forwarded-for" => Split,
|
224
224
|
|
225
225
|
# Authorization headers:
|
226
|
-
|
227
|
-
|
226
|
+
"authorization" => Header::Authorization,
|
227
|
+
"proxy-authorization" => Header::Authorization,
|
228
228
|
|
229
229
|
# Cache validations:
|
230
|
-
|
231
|
-
|
232
|
-
|
230
|
+
"etag" => Header::ETag,
|
231
|
+
"if-match" => Header::ETags,
|
232
|
+
"if-none-match" => Header::ETags,
|
233
233
|
|
234
234
|
# Headers which may be specified multiple times, but which can't be concatenated:
|
235
|
-
|
236
|
-
|
235
|
+
"www-authenticate" => Multiple,
|
236
|
+
"proxy-authenticate" => Multiple,
|
237
237
|
|
238
238
|
# Custom headers:
|
239
|
-
|
240
|
-
|
239
|
+
"set-cookie" => Header::SetCookie,
|
240
|
+
"cookie" => Header::Cookie,
|
241
241
|
|
242
242
|
# Date headers:
|
243
243
|
# These headers include a comma as part of the formatting so they can't be concatenated.
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
244
|
+
"date" => Header::Date,
|
245
|
+
"expires" => Header::Date,
|
246
|
+
"last-modified" => Header::Date,
|
247
|
+
"if-modified-since" => Header::Date,
|
248
|
+
"if-unmodified-since" => Header::Date,
|
249
249
|
}.tap{|hash| hash.default = Split}
|
250
250
|
|
251
251
|
# Delete all headers with the given key, and return the merged value.
|
@@ -24,31 +24,31 @@ module Protocol
|
|
24
24
|
# See <https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods> for more details.
|
25
25
|
class Methods
|
26
26
|
# The GET method requests a representation of the specified resource. Requests using GET should only retrieve data.
|
27
|
-
GET =
|
27
|
+
GET = "GET"
|
28
28
|
|
29
29
|
# The HEAD method asks for a response identical to a GET request, but without the response body.
|
30
|
-
HEAD =
|
30
|
+
HEAD = "HEAD"
|
31
31
|
|
32
32
|
# The POST method submits an entity to the specified resource, often causing a change in state or side effects on the server.
|
33
|
-
POST =
|
33
|
+
POST = "POST"
|
34
34
|
|
35
35
|
# The PUT method replaces all current representations of the target resource with the request payload.
|
36
|
-
PUT =
|
36
|
+
PUT = "PUT"
|
37
37
|
|
38
38
|
# The DELETE method deletes the specified resource.
|
39
|
-
DELETE =
|
39
|
+
DELETE = "DELETE"
|
40
40
|
|
41
41
|
# The CONNECT method establishes a tunnel to the server identified by the target resource.
|
42
|
-
CONNECT =
|
42
|
+
CONNECT = "CONNECT"
|
43
43
|
|
44
44
|
# The OPTIONS method describes the communication options for the target resource.
|
45
|
-
OPTIONS =
|
45
|
+
OPTIONS = "OPTIONS"
|
46
46
|
|
47
47
|
# The TRACE method performs a message loop-back test along the path to the target resource.
|
48
|
-
TRACE =
|
48
|
+
TRACE = "TRACE"
|
49
49
|
|
50
50
|
# The PATCH method applies partial modifications to a resource.
|
51
|
-
PATCH =
|
51
|
+
PATCH = "PATCH"
|
52
52
|
|
53
53
|
def self.valid?(name)
|
54
54
|
const_defined?(name)
|
@@ -3,10 +3,10 @@
|
|
3
3
|
# Released under the MIT License.
|
4
4
|
# Copyright, 2019-2023, by Samuel Williams.
|
5
5
|
|
6
|
-
require_relative
|
7
|
-
require_relative
|
8
|
-
require_relative
|
9
|
-
require_relative
|
6
|
+
require_relative "methods"
|
7
|
+
require_relative "headers"
|
8
|
+
require_relative "request"
|
9
|
+
require_relative "response"
|
10
10
|
|
11
11
|
module Protocol
|
12
12
|
module HTTP
|
@@ -66,7 +66,7 @@ module Protocol
|
|
66
66
|
end
|
67
67
|
|
68
68
|
def self.call(request)
|
69
|
-
Response[200, Headers[
|
69
|
+
Response[200, Headers["content-type" => "text/plain"], ["Hello World!"]]
|
70
70
|
end
|
71
71
|
end
|
72
72
|
end
|
@@ -3,7 +3,7 @@
|
|
3
3
|
# Released under the MIT License.
|
4
4
|
# Copyright, 2018-2023, by Samuel Williams.
|
5
5
|
|
6
|
-
require_relative
|
6
|
+
require_relative "url"
|
7
7
|
|
8
8
|
module Protocol
|
9
9
|
module HTTP
|
@@ -12,14 +12,14 @@ module Protocol
|
|
12
12
|
include Comparable
|
13
13
|
|
14
14
|
# Generate a reference from a path and user parameters. The path may contain a `#fragment` or `?query=parameters`.
|
15
|
-
def self.parse(path =
|
16
|
-
base, fragment = path.split(
|
17
|
-
path, query = base.split(
|
15
|
+
def self.parse(path = "/", parameters = nil)
|
16
|
+
base, fragment = path.split("#", 2)
|
17
|
+
path, query = base.split("?", 2)
|
18
18
|
|
19
19
|
self.new(path, query, fragment, parameters)
|
20
20
|
end
|
21
21
|
|
22
|
-
def initialize(path =
|
22
|
+
def initialize(path = "/", query = nil, fragment = nil, parameters = nil)
|
23
23
|
@path = path
|
24
24
|
@query = query
|
25
25
|
@fragment = fragment
|
@@ -79,15 +79,15 @@ module Protocol
|
|
79
79
|
|
80
80
|
def append(buffer)
|
81
81
|
if query?
|
82
|
-
buffer << URL.escape_path(@path) <<
|
83
|
-
buffer <<
|
82
|
+
buffer << URL.escape_path(@path) << "?" << @query
|
83
|
+
buffer << "&" << URL.encode(@parameters) if parameters?
|
84
84
|
else
|
85
85
|
buffer << URL.escape_path(@path)
|
86
|
-
buffer <<
|
86
|
+
buffer << "?" << URL.encode(@parameters) if parameters?
|
87
87
|
end
|
88
88
|
|
89
89
|
if fragment?
|
90
|
-
buffer <<
|
90
|
+
buffer << "#" << URL.escape(@fragment)
|
91
91
|
end
|
92
92
|
|
93
93
|
return buffer
|
@@ -150,31 +150,31 @@ module Protocol
|
|
150
150
|
if path.empty?
|
151
151
|
[path]
|
152
152
|
else
|
153
|
-
path.split(
|
153
|
+
path.split("/", -1)
|
154
154
|
end
|
155
155
|
end
|
156
156
|
|
157
157
|
def expand_absolute_path(path, parts)
|
158
158
|
parts.each do |part|
|
159
|
-
if part ==
|
159
|
+
if part == ".."
|
160
160
|
path.pop
|
161
|
-
elsif part ==
|
161
|
+
elsif part == "."
|
162
162
|
# Do nothing.
|
163
163
|
else
|
164
164
|
path << part
|
165
165
|
end
|
166
166
|
end
|
167
167
|
|
168
|
-
if path.first !=
|
169
|
-
path.unshift(
|
168
|
+
if path.first != ""
|
169
|
+
path.unshift("")
|
170
170
|
end
|
171
171
|
end
|
172
172
|
|
173
173
|
def expand_relative_path(path, parts)
|
174
174
|
parts.each do |part|
|
175
|
-
if part ==
|
175
|
+
if part == ".." and path.any?
|
176
176
|
path.pop
|
177
|
-
elsif part ==
|
177
|
+
elsif part == "."
|
178
178
|
# Do nothing.
|
179
179
|
else
|
180
180
|
path << part
|
@@ -184,7 +184,7 @@ module Protocol
|
|
184
184
|
|
185
185
|
# @param pop [Boolean] whether to remove the last path component of the base path, to conform to URI merging behaviour, as defined by RFC2396.
|
186
186
|
def expand_path(base, relative, pop = true)
|
187
|
-
if relative.start_with?
|
187
|
+
if relative.start_with? "/"
|
188
188
|
return relative
|
189
189
|
end
|
190
190
|
|
@@ -194,18 +194,18 @@ module Protocol
|
|
194
194
|
# 6) a) All but the last segment of the base URI's path component is
|
195
195
|
# copied to the buffer. In other words, any characters after the
|
196
196
|
# last (right-most) slash character, if any, are excluded.
|
197
|
-
path.pop if pop or path.last ==
|
197
|
+
path.pop if pop or path.last == ""
|
198
198
|
|
199
199
|
parts = split(relative)
|
200
200
|
|
201
201
|
# Absolute path:
|
202
|
-
if path.first ==
|
202
|
+
if path.first == ""
|
203
203
|
expand_absolute_path(path, parts)
|
204
204
|
else
|
205
205
|
expand_relative_path(path, parts)
|
206
206
|
end
|
207
207
|
|
208
|
-
return path.join(
|
208
|
+
return path.join("/")
|
209
209
|
end
|
210
210
|
end
|
211
211
|
end
|
@@ -3,11 +3,11 @@
|
|
3
3
|
# Released under the MIT License.
|
4
4
|
# Copyright, 2019-2024, by Samuel Williams.
|
5
5
|
|
6
|
-
require_relative
|
7
|
-
require_relative
|
6
|
+
require_relative "body/buffered"
|
7
|
+
require_relative "body/reader"
|
8
8
|
|
9
|
-
require_relative
|
10
|
-
require_relative
|
9
|
+
require_relative "headers"
|
10
|
+
require_relative "methods"
|
11
11
|
|
12
12
|
module Protocol
|
13
13
|
module HTTP
|
@@ -3,8 +3,8 @@
|
|
3
3
|
# Released under the MIT License.
|
4
4
|
# Copyright, 2019-2024, by Samuel Williams.
|
5
5
|
|
6
|
-
require_relative
|
7
|
-
require_relative
|
6
|
+
require_relative "body/buffered"
|
7
|
+
require_relative "body/reader"
|
8
8
|
|
9
9
|
module Protocol
|
10
10
|
module HTTP
|
@@ -141,7 +141,7 @@ module Protocol
|
|
141
141
|
#
|
142
142
|
# @parameter exception [Exception] The exception to generate the response for.
|
143
143
|
def self.for_exception(exception)
|
144
|
-
Response[500, Headers[
|
144
|
+
Response[500, Headers["content-type" => "text/plain"], ["#{exception.class}: #{exception.message}"]]
|
145
145
|
end
|
146
146
|
|
147
147
|
def as_json(...)
|
data/lib/protocol/http/url.rb
CHANGED
@@ -10,7 +10,7 @@ module Protocol
|
|
10
10
|
# Escapes a string using percent encoding.
|
11
11
|
def self.escape(string, encoding = string.encoding)
|
12
12
|
string.b.gsub(/([^a-zA-Z0-9_.\-]+)/) do |m|
|
13
|
-
|
13
|
+
"%" + m.unpack("H2" * m.bytesize).join("%").upcase
|
14
14
|
end.force_encoding(encoding)
|
15
15
|
end
|
16
16
|
|
@@ -28,7 +28,7 @@ module Protocol
|
|
28
28
|
def self.escape_path(path)
|
29
29
|
encoding = path.encoding
|
30
30
|
path.b.gsub(NON_PCHAR) do |m|
|
31
|
-
|
31
|
+
"%" + m.unpack("H2" * m.bytesize).join("%").upcase
|
32
32
|
end.force_encoding(encoding)
|
33
33
|
end
|
34
34
|
|
@@ -42,7 +42,7 @@ module Protocol
|
|
42
42
|
when Hash
|
43
43
|
return value.map {|k, v|
|
44
44
|
self.encode(v, prefix ? "#{prefix}[#{escape(k.to_s)}]" : escape(k.to_s))
|
45
|
-
}.reject(&:empty?).join(
|
45
|
+
}.reject(&:empty?).join("&")
|
46
46
|
when nil
|
47
47
|
return prefix
|
48
48
|
else
|
@@ -57,10 +57,10 @@ module Protocol
|
|
57
57
|
# @parameter key [String] The unescaped key.
|
58
58
|
# @parameter value [String] The unescaped key.
|
59
59
|
def self.scan(string)
|
60
|
-
string.split(
|
60
|
+
string.split("&") do |assignment|
|
61
61
|
next if assignment.empty?
|
62
62
|
|
63
|
-
key, value = assignment.split(
|
63
|
+
key, value = assignment.split("=", 2)
|
64
64
|
|
65
65
|
yield unescape(key), value.nil? ? value : unescape(value)
|
66
66
|
end
|
data/lib/protocol/http.rb
CHANGED
@@ -5,10 +5,10 @@
|
|
5
5
|
|
6
6
|
require_relative "http/version"
|
7
7
|
|
8
|
-
require_relative
|
9
|
-
require_relative
|
10
|
-
require_relative
|
11
|
-
require_relative
|
8
|
+
require_relative "http/headers"
|
9
|
+
require_relative "http/request"
|
10
|
+
require_relative "http/response"
|
11
|
+
require_relative "http/middleware"
|
12
12
|
|
13
13
|
# @namespace
|
14
14
|
module Protocol
|
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.
|
4
|
+
version: 0.37.0
|
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-09-
|
50
|
+
date: 2024-09-18 00:00:00.000000000 Z
|
51
51
|
dependencies: []
|
52
52
|
description:
|
53
53
|
email:
|
metadata.gz.sig
CHANGED
Binary file
|