protocol-http 0.36.0 → 0.38.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (39) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/lib/protocol/http/accept_encoding.rb +7 -7
  4. data/lib/protocol/http/body/buffered.rb +10 -2
  5. data/lib/protocol/http/body/completable.rb +1 -1
  6. data/lib/protocol/http/body/deflate.rb +8 -5
  7. data/lib/protocol/http/body/digestable.rb +2 -2
  8. data/lib/protocol/http/body/file.rb +1 -1
  9. data/lib/protocol/http/body/head.rb +1 -1
  10. data/lib/protocol/http/body/inflate.rb +32 -22
  11. data/lib/protocol/http/body/readable.rb +11 -2
  12. data/lib/protocol/http/body/rewindable.rb +2 -2
  13. data/lib/protocol/http/body/stream.rb +2 -2
  14. data/lib/protocol/http/body/streamable.rb +3 -3
  15. data/lib/protocol/http/body/wrapper.rb +5 -1
  16. data/lib/protocol/http/body/writable.rb +5 -5
  17. data/lib/protocol/http/content_encoding.rb +9 -9
  18. data/lib/protocol/http/cookie.rb +6 -6
  19. data/lib/protocol/http/header/authorization.rb +1 -1
  20. data/lib/protocol/http/header/cache_control.rb +13 -13
  21. data/lib/protocol/http/header/connection.rb +4 -4
  22. data/lib/protocol/http/header/cookie.rb +2 -2
  23. data/lib/protocol/http/header/date.rb +1 -1
  24. data/lib/protocol/http/header/etag.rb +1 -1
  25. data/lib/protocol/http/header/etags.rb +3 -3
  26. data/lib/protocol/http/header/vary.rb +1 -1
  27. data/lib/protocol/http/headers.rb +39 -39
  28. data/lib/protocol/http/methods.rb +9 -9
  29. data/lib/protocol/http/middleware/builder.rb +1 -1
  30. data/lib/protocol/http/middleware.rb +5 -5
  31. data/lib/protocol/http/reference.rb +20 -20
  32. data/lib/protocol/http/request.rb +4 -4
  33. data/lib/protocol/http/response.rb +3 -3
  34. data/lib/protocol/http/url.rb +5 -5
  35. data/lib/protocol/http/version.rb +1 -1
  36. data/lib/protocol/http.rb +4 -4
  37. data.tar.gz.sig +0 -0
  38. metadata +2 -2
  39. metadata.gz.sig +0 -0
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c826c247a1168e14cb7b5e0b216019b622574c801852cda2a4102f0a041d0694
4
- data.tar.gz: 9661992d2f755a4743b8998889e84c3ff3c826769256ccfc8a48f697ddc0463b
3
+ metadata.gz: 95fdcce85b20ee97e54b44068d59f689f040d1c9489b0e2ff8f9e63464d4c7cd
4
+ data.tar.gz: a72f51087a046f2f713208baace1631414e32b1e2eceb82ff69d479b2c2a7eac
5
5
  SHA512:
6
- metadata.gz: 7c37d338e02b8b9dc2540be13bad83d37df2f07a6082f3ace8aadc3f7dd357c0b77bae9508bd7a7f2ff4aecf51ef99efa7a94fa09214a510f1616ca34b9f16c0
7
- data.tar.gz: f3588dde1d19541c9e5ee9e8c3d13d7f42d7976419f7cf3d0af2e7451445619d79c7f897699e1d20fd5569afed5c7cf7ec9b15e6c5d6a05647422dff6a38b508
6
+ metadata.gz: a4e7504cf962c63a5dac26fbd235b50d6796d5c97eb1f4b40be4cf6023fd1e118a8c64254d1199cab94f1086ad608367e1e4932de1836d63986b2548149fb3b7
7
+ data.tar.gz: b88389e903b175e65fa9f1ee2e36b4894d0484475d8f999ab001cf4968c6edbafb1f9a75fbf14f7fad5f1c7d8e2b4b40a55fd2070aa19ac9eb0a4aae785fdbec
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 'middleware'
6
+ require_relative "middleware"
7
7
 
8
- require_relative 'body/buffered'
9
- require_relative 'body/inflate'
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 = 'accept-encoding'.freeze
16
- CONTENT_ENCODING = 'content-encoding'.freeze
15
+ ACCEPT_ENCODING = "accept-encoding".freeze
16
+ CONTENT_ENCODING = "content-encoding".freeze
17
17
 
18
18
  DEFAULT_WRAPPERS = {
19
- 'gzip' => Body::Inflate.method(:for),
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 'readable'
7
+ require_relative "readable"
8
8
 
9
9
  module Protocol
10
10
  module HTTP
@@ -52,6 +52,13 @@ module Protocol
52
52
 
53
53
  attr :chunks
54
54
 
55
+ # A rewindable body wraps some other body. Convert it to a buffered body. The buffered body will share the same chunks as the rewindable body.
56
+ #
57
+ # @returns [Buffered] the buffered body.
58
+ def buffered
59
+ self.class.new(@chunks)
60
+ end
61
+
55
62
  def finish
56
63
  self
57
64
  end
@@ -64,7 +71,7 @@ module Protocol
64
71
  end
65
72
 
66
73
  def clear
67
- @chunks.clear
74
+ @chunks = []
68
75
  @length = 0
69
76
  @index = 0
70
77
  end
@@ -93,6 +100,7 @@ module Protocol
93
100
  end
94
101
 
95
102
  def discard
103
+ # It's safe to call close here because there is no underlying stream to close:
96
104
  self.close
97
105
  end
98
106
 
@@ -3,7 +3,7 @@
3
3
  # Released under the MIT License.
4
4
  # Copyright, 2019-2024, by Samuel Williams.
5
5
 
6
- require_relative 'wrapper'
6
+ require_relative "wrapper"
7
7
 
8
8
  module Protocol
9
9
  module HTTP
@@ -3,9 +3,9 @@
3
3
  # Released under the MIT License.
4
4
  # Copyright, 2019-2024, by Samuel Williams.
5
5
 
6
- require_relative 'wrapper'
6
+ require_relative "wrapper"
7
7
 
8
- require 'zlib'
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
- 'deflate' => DEFLATE,
21
- 'gzip' => GZIP,
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
- @stream.close unless @stream.closed?
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, 2020-2024, by Samuel Williams.
5
5
 
6
- require_relative 'wrapper'
6
+ require_relative "wrapper"
7
7
 
8
- require 'digest/sha2'
8
+ require "digest/sha2"
9
9
 
10
10
  module Protocol
11
11
  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 'readable'
6
+ require_relative "readable"
7
7
 
8
8
  module Protocol
9
9
  module HTTP
@@ -3,7 +3,7 @@
3
3
  # Released under the MIT License.
4
4
  # Copyright, 2020-2023, by Samuel Williams.
5
5
 
6
- require_relative 'readable'
6
+ require_relative "readable"
7
7
 
8
8
  module Protocol
9
9
  module HTTP
@@ -3,9 +3,9 @@
3
3
  # Released under the MIT License.
4
4
  # Copyright, 2019-2024, by Samuel Williams.
5
5
 
6
- require 'zlib'
6
+ require "zlib"
7
7
 
8
- require_relative 'deflate'
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
- return if @stream.finished?
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
- # The stream might have been closed while waiting for the chunk to come in.
22
- while chunk = super
23
- @input_length += chunk.bytesize
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
- # It's possible this triggers the stream to finish.
26
- chunk = @stream.inflate(chunk)
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
- break unless chunk&.empty?
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
@@ -11,9 +11,9 @@ module Protocol
11
11
  #
12
12
  # Typically, you'd override `#read` to return chunks of data.
13
13
  #
14
- # I n general, you read chunks of data from a body until it is empty and returns `nil`. Upon reading `nil`, the body is considered consumed and should not be read from again.
14
+ # In general, you read chunks of data from a body until it is empty and returns `nil`. Upon reading `nil`, the body is considered consumed and should not be read from again.
15
15
  #
16
- # Reading can also fail, for example if the body represents a streaming upload, and the connection is lost. In this case, the body will raise some kind of error.
16
+ # Reading can also fail, for example if the body represents a streaming upload, and the connection is lost. In this case, `#read` will raise some kind of error.
17
17
  #
18
18
  # If you don't want to read from a stream, and instead want to close it immediately, you can call `close` on the body. If the body is already completely consumed, `close` will do nothing, but if there is still data to be read, it will cause the underlying stream to be reset (and possibly closed).
19
19
  class Readable
@@ -50,6 +50,15 @@ module Protocol
50
50
  false
51
51
  end
52
52
 
53
+ # Return a buffered representation of this body.
54
+ #
55
+ # This method must return a buffered body if `#rewindable?`.
56
+ #
57
+ # @returns [Buffered | Nil] The buffered body.
58
+ def buffered
59
+ nil
60
+ end
61
+
53
62
  # The total length of the body, if known.
54
63
  # @returns [Integer | Nil] The total length of the body, or `nil` if the length is unknown.
55
64
  def length
@@ -3,8 +3,8 @@
3
3
  # Released under the MIT License.
4
4
  # Copyright, 2019-2024, by Samuel Williams.
5
5
 
6
- require_relative 'wrapper'
7
- require_relative 'buffered'
6
+ require_relative "wrapper"
7
+ require_relative "buffered"
8
8
 
9
9
  module Protocol
10
10
  module HTTP
@@ -4,7 +4,7 @@
4
4
  # Copyright, 2019-2024, by Samuel Williams.
5
5
  # Copyright, 2023, by Genki Takiuchi.
6
6
 
7
- require_relative 'buffered'
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 '' if length == 0
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 'readable'
7
- require_relative 'writable'
6
+ require_relative "readable"
7
+ require_relative "writable"
8
8
 
9
- require_relative 'stream'
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 'readable'
6
+ require_relative "readable"
7
7
 
8
8
  module Protocol
9
9
  module HTTP
@@ -42,6 +42,10 @@ module Protocol
42
42
  @body.ready?
43
43
  end
44
44
 
45
+ def buffered
46
+ @body.buffered
47
+ end
48
+
45
49
  def rewind
46
50
  @body.rewind
47
51
  end
@@ -3,7 +3,7 @@
3
3
  # Released under the MIT License.
4
4
  # Copyright, 2024, by Samuel Williams.
5
5
 
6
- require_relative 'readable'
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
- 'closed'
140
+ "closed"
141
141
  else
142
- 'waiting'
142
+ "waiting"
143
143
  end
144
144
  else
145
145
  if @queue.closed?
146
- 'closing'
146
+ "closing"
147
147
  else
148
- 'ready'
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 'middleware'
6
+ require_relative "middleware"
7
7
 
8
- require_relative 'body/buffered'
9
- require_relative 'body/deflate'
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
- 'gzip' => Body::Deflate.method(:for)
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['content-encoding']
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('vary', 'accept-encoding')
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['accept-encoding']
42
+ if !response.body.empty? and accept_encoding = request.headers["accept-encoding"]
43
43
 
44
- if content_type = response.headers['content-type'] and @content_types =~ content_type
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['content-encoding'] = name
49
+ response.headers["content-encoding"] = name
50
50
 
51
51
  body = wrapper.call(body)
52
52
 
@@ -4,7 +4,7 @@
4
4
  # Copyright, 2019-2023, by Samuel Williams.
5
5
  # Copyright, 2022, by Herrick Fang.
6
6
 
7
- require_relative 'url'
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 << '=' << encoded_value
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 << '=' << value
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('=', 2)
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('=', 2)
67
+ key, value = string.split("=", 2)
68
68
  [key, value || true]
69
69
  end.to_h
70
70
  end
@@ -20,7 +20,7 @@ module Protocol
20
20
  end
21
21
 
22
22
  def self.basic(username, password)
23
- strict_base64_encoded = ["#{username}:#{password}"].pack('m0')
23
+ strict_base64_encoded = ["#{username}:#{password}"].pack("m0")
24
24
 
25
25
  self.new(
26
26
  "Basic #{strict_base64_encoded}"
@@ -4,25 +4,25 @@
4
4
  # Copyright, 2020-2023, by Samuel Williams.
5
5
  # Copyright, 2023, by Thomas Morgan.
6
6
 
7
- require_relative 'split'
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 = 'private'
14
- PUBLIC = 'public'
15
- NO_CACHE = 'no-cache'
16
- NO_STORE = 'no-store'
17
- MAX_AGE = 'max-age'
18
- S_MAXAGE = '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 = 'static'
21
- DYNAMIC = 'dynamic'
22
- STREAMING = 'streaming'
20
+ STATIC = "static"
21
+ DYNAMIC = "dynamic"
22
+ STREAMING = "streaming"
23
23
 
24
- MUST_REVALIDATE = 'must-revalidate'
25
- PROXY_REVALIDATE = '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('=', 2)
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 'split'
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 = 'keep-alive'
14
- CLOSE = 'close'
15
- UPGRADE = '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)
@@ -3,8 +3,8 @@
3
3
  # Released under the MIT License.
4
4
  # Copyright, 2019-2023, by Samuel Williams.
5
5
 
6
- require_relative 'multiple'
7
- require_relative '../cookie'
6
+ require_relative "multiple"
7
+ require_relative "../cookie"
8
8
 
9
9
  module Protocol
10
10
  module HTTP
@@ -3,7 +3,7 @@
3
3
  # Released under the MIT License.
4
4
  # Copyright, 2023-2024, by Samuel Williams.
5
5
 
6
- require 'time'
6
+ require "time"
7
7
 
8
8
  module Protocol
9
9
  module HTTP
@@ -12,7 +12,7 @@ module Protocol
12
12
  end
13
13
 
14
14
  def weak?
15
- self.start_with?('W/')
15
+ self.start_with?("W/")
16
16
  end
17
17
  end
18
18
  end
@@ -4,14 +4,14 @@
4
4
  # Copyright, 2020-2023, by Samuel Williams.
5
5
  # Copyright, 2023, by Thomas Morgan.
6
6
 
7
- require_relative 'split'
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? 'W/'
39
+ tag&.start_with? "W/"
40
40
  end
41
41
  end
42
42
  end
@@ -3,7 +3,7 @@
3
3
  # Released under the MIT License.
4
4
  # Copyright, 2020-2023, by Samuel Williams.
5
5
 
6
- require_relative 'split'
6
+ require_relative "split"
7
7
 
8
8
  module Protocol
9
9
  module HTTP
@@ -3,16 +3,16 @@
3
3
  # Released under the MIT License.
4
4
  # Copyright, 2018-2024, by Samuel Williams.
5
5
 
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'
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 = '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
- '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,
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
- 'connection' => Header::Connection,
218
- 'cache-control' => Header::CacheControl,
219
- 'vary' => Header::Vary,
217
+ "connection" => Header::Connection,
218
+ "cache-control" => Header::CacheControl,
219
+ "vary" => Header::Vary,
220
220
 
221
221
  # Headers specifically for proxies:
222
- 'via' => Split,
223
- 'x-forwarded-for' => Split,
222
+ "via" => Split,
223
+ "x-forwarded-for" => Split,
224
224
 
225
225
  # Authorization headers:
226
- 'authorization' => Header::Authorization,
227
- 'proxy-authorization' => Header::Authorization,
226
+ "authorization" => Header::Authorization,
227
+ "proxy-authorization" => Header::Authorization,
228
228
 
229
229
  # Cache validations:
230
- 'etag' => Header::ETag,
231
- 'if-match' => Header::ETags,
232
- 'if-none-match' => Header::ETags,
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
- 'www-authenticate' => Multiple,
236
- 'proxy-authenticate' => Multiple,
235
+ "www-authenticate" => Multiple,
236
+ "proxy-authenticate" => Multiple,
237
237
 
238
238
  # Custom headers:
239
- 'set-cookie' => Header::SetCookie,
240
- 'cookie' => Header::Cookie,
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
- 'date' => Header::Date,
245
- 'expires' => Header::Date,
246
- 'last-modified' => Header::Date,
247
- 'if-modified-since' => Header::Date,
248
- 'if-unmodified-since' => Header::Date,
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 = '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 = '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 = '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 = 'PUT'
36
+ PUT = "PUT"
37
37
 
38
38
  # The DELETE method deletes the specified resource.
39
- DELETE = 'DELETE'
39
+ DELETE = "DELETE"
40
40
 
41
41
  # The CONNECT method establishes a tunnel to the server identified by the target resource.
42
- CONNECT = 'CONNECT'
42
+ CONNECT = "CONNECT"
43
43
 
44
44
  # The OPTIONS method describes the communication options for the target resource.
45
- OPTIONS = '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 = 'TRACE'
48
+ TRACE = "TRACE"
49
49
 
50
50
  # The PATCH method applies partial modifications to a resource.
51
- PATCH = 'PATCH'
51
+ PATCH = "PATCH"
52
52
 
53
53
  def self.valid?(name)
54
54
  const_defined?(name)
@@ -3,7 +3,7 @@
3
3
  # Released under the MIT License.
4
4
  # Copyright, 2019-2024, by Samuel Williams.
5
5
 
6
- require_relative '../middleware'
6
+ require_relative "../middleware"
7
7
 
8
8
  module Protocol
9
9
  module HTTP
@@ -3,10 +3,10 @@
3
3
  # Released under the MIT License.
4
4
  # Copyright, 2019-2023, by Samuel Williams.
5
5
 
6
- require_relative 'methods'
7
- require_relative 'headers'
8
- require_relative 'request'
9
- require_relative 'response'
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['content-type' => 'text/plain'], ["Hello World!"]]
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 'url'
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 = '/', parameters = nil)
16
- base, fragment = path.split('#', 2)
17
- path, query = base.split('?', 2)
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 = '/', query = nil, fragment = nil, parameters = nil)
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) << '?' << @query
83
- buffer << '&' << URL.encode(@parameters) if parameters?
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 << '?' << URL.encode(@parameters) if parameters?
86
+ buffer << "?" << URL.encode(@parameters) if parameters?
87
87
  end
88
88
 
89
89
  if fragment?
90
- buffer << '#' << URL.escape(@fragment)
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('/', -1)
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 == '..' and path.any?
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 'body/buffered'
7
- require_relative 'body/reader'
6
+ require_relative "body/buffered"
7
+ require_relative "body/reader"
8
8
 
9
- require_relative 'headers'
10
- require_relative 'methods'
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 'body/buffered'
7
- require_relative 'body/reader'
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['content-type' => 'text/plain'], ["#{exception.class}: #{exception.message}"]]
144
+ Response[500, Headers["content-type" => "text/plain"], ["#{exception.class}: #{exception.message}"]]
145
145
  end
146
146
 
147
147
  def as_json(...)
@@ -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
- '%' + m.unpack('H2' * m.bytesize).join('%').upcase
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
- '%' + m.unpack('H2' * m.bytesize).join('%').upcase
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('&') do |assignment|
60
+ string.split("&") do |assignment|
61
61
  next if assignment.empty?
62
62
 
63
- key, value = assignment.split('=', 2)
63
+ key, value = assignment.split("=", 2)
64
64
 
65
65
  yield unescape(key), value.nil? ? value : unescape(value)
66
66
  end
@@ -5,6 +5,6 @@
5
5
 
6
6
  module Protocol
7
7
  module HTTP
8
- VERSION = "0.36.0"
8
+ VERSION = "0.38.0"
9
9
  end
10
10
  end
data/lib/protocol/http.rb CHANGED
@@ -5,10 +5,10 @@
5
5
 
6
6
  require_relative "http/version"
7
7
 
8
- require_relative 'http/headers'
9
- require_relative 'http/request'
10
- require_relative 'http/response'
11
- require_relative 'http/middleware'
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.36.0
4
+ version: 0.38.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-17 00:00:00.000000000 Z
50
+ date: 2024-10-14 00:00:00.000000000 Z
51
51
  dependencies: []
52
52
  description:
53
53
  email:
metadata.gz.sig CHANGED
Binary file