protocol-http 0.35.0 → 0.37.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/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
|