async-http 0.59.3 → 0.59.4

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ccef95a0cce84077c1782720ea14a582822ef0431d60fa98303b88437d072636
4
- data.tar.gz: 397a5e8ed0cb1d4ed5ca58190e1c7ab344cabfff040d90df57fe1c49c1ca5360
3
+ metadata.gz: bdec9955ffb3564757b70e1745e2cea19a63961da0431e38eca773c22b2c6008
4
+ data.tar.gz: 2d005a43f0e8b43f25834566cbed86fbccc7cfebd6e27a64fdc69c65d0fec700
5
5
  SHA512:
6
- metadata.gz: 8e0194004b779c0107157cae272fbd9f3c75a050736b2c682d82507a26a88c7dd15e74dc1f3ca1e513ba8f2c1d0697103acf5a5edf172e617c5833cb11094dde
7
- data.tar.gz: 3c19cffb3030cf3b6b88091ef6818cf0339f01f5f52e6e35c704d9228d2b961af47f51d74995a7f83c19f1aa8405979d93cd612f8cd67d70492c71b02207c945
6
+ metadata.gz: 23a2d571edf0bb0fb73277057c84f7469648dba7f0afccf24ac2e3c15f0d1d11658e831fe3ef8a11b4dd4f28469be0c94a330bbd009aeb6a3e661f5323a2cb09
7
+ data.tar.gz: da57464924efd79a5dba6b7c5366ac883d012a1aed10492a11911137cd55b809e24a757ec4481e83a45092f2bd7286aca6852376075e5b07564fdca2ae56ed99
checksums.yaml.gz.sig CHANGED
Binary file
@@ -23,6 +23,7 @@ require_relative 'endpoint'
23
23
  require_relative 'reference'
24
24
 
25
25
  require 'protocol/http/middleware'
26
+ require 'protocol/http/body/rewindable'
26
27
 
27
28
  module Async
28
29
  module HTTP
@@ -30,8 +31,28 @@ module Async
30
31
  end
31
32
 
32
33
  # A client wrapper which transparently handles both relative and absolute redirects to a given maximum number of hops.
34
+ #
35
+ # The best reference for these semantics is defined by the [Fetch specification](https://fetch.spec.whatwg.org/#http-redirect-fetch).
36
+ #
37
+ # | Redirect using GET | Permanent | Temporary |
38
+ # |:-----------------------------------------:|:---------:|:---------:|
39
+ # | Allowed | 301 | 302 |
40
+ # | Preserve original method | 308 | 307 |
41
+ #
42
+ # For the specific details of the redirect handling, see:
43
+ # - <https://datatracker.ietf.org/doc/html/rfc7231#section-6-4-2> 301 Moved Permanently.
44
+ # - <https://datatracker.ietf.org/doc/html/rfc7231#section-6-4-3> 302 Found.
45
+ # - <https://datatracker.ietf.org/doc/html/rfc7538 308 Permanent Redirect.
46
+ # - <https://datatracker.ietf.org/doc/html/rfc7231#section-6-4-7> 307 Temporary Redirect.
47
+ #
33
48
  class RelativeLocation < ::Protocol::HTTP::Middleware
34
- DEFAULT_METHOD = GET
49
+ # Header keys which should be deleted when changing a request from a POST to a GET as defined by <https://fetch.spec.whatwg.org/#request-body-header-name>.
50
+ PROHIBITED_GET_HEADERS = [
51
+ 'content-encoding',
52
+ 'content-language',
53
+ 'content-location',
54
+ 'content-type',
55
+ ]
35
56
 
36
57
  # maximum_hops is the max number of redirects. Set to 0 to allow 1 request with no redirects.
37
58
  def initialize(app, maximum_hops = 3)
@@ -43,20 +64,39 @@ module Async
43
64
  # The maximum number of hops which will limit the number of redirects until an error is thrown.
44
65
  attr :maximum_hops
45
66
 
67
+ def redirect_with_get?(request, response)
68
+ # We only want to switch to GET if the request method is something other than get, e.g. POST.
69
+ if request.method != GET
70
+ # According to the RFC, we should only switch to GET if the response is a 301 or 302:
71
+ return response.status == 301 || response.status == 302
72
+ end
73
+ end
74
+
46
75
  def call(request)
47
- hops = 0
76
+ # We don't want to follow redirects for HEAD requests:
77
+ return super if request.head?
78
+
79
+ if body = request.body
80
+ # We need to cache the body as it might be submitted multiple times if we get a response status of 307 or 308:
81
+ body = ::Protocol::HTTP::Body::Rewindable.new(body)
82
+ request.body = body
83
+ end
48
84
 
49
- # We need to cache the body as it might be submitted multiple times.
50
- request.finish
85
+ hops = 0
51
86
 
52
87
  while hops <= @maximum_hops
53
88
  response = super(request)
54
89
 
55
90
  if response.redirection?
56
91
  hops += 1
92
+
93
+ # Get the redirect location:
94
+ unless location = response.headers['location']
95
+ return response
96
+ end
97
+
57
98
  response.finish
58
99
 
59
- location = response.headers['location']
60
100
  uri = URI.parse(location)
61
101
 
62
102
  if uri.absolute?
@@ -65,8 +105,21 @@ module Async
65
105
  request.path = Reference[request.path] + location
66
106
  end
67
107
 
68
- unless response.preserve_method?
69
- request.method = DEFAULT_METHOD
108
+ if request.method == GET or response.preserve_method?
109
+ # We (might) need to rewind the body so that it can be submitted again:
110
+ body&.rewind
111
+ else
112
+ # We are changing the method to GET:
113
+ request.method = GET
114
+
115
+ # Clear the request body:
116
+ request.finish
117
+ body = nil
118
+
119
+ # Remove any headers which are not allowed in a GET request:
120
+ PROHIBITED_GET_HEADERS.each do |header|
121
+ request.headers.delete(header)
122
+ end
70
123
  end
71
124
  else
72
125
  return response
@@ -22,6 +22,6 @@
22
22
 
23
23
  module Async
24
24
  module HTTP
25
- VERSION = "0.59.3"
25
+ VERSION = "0.59.4"
26
26
  end
27
27
  end
data.tar.gz.sig CHANGED
Binary file
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: async-http
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.59.3
4
+ version: 0.59.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Samuel Williams
@@ -52,7 +52,7 @@ cert_chain:
52
52
  Q2K9NVun/S785AP05vKkXZEFYxqG6EW012U4oLcFl5MySFajYXRYbuUpH6AY+HP8
53
53
  voD0MPg1DssDLKwXyt1eKD/+Fq0bFWhwVM/1XiAXL7lyYUyOq24KHgQ2Csg=
54
54
  -----END CERTIFICATE-----
55
- date: 2022-11-10 00:00:00.000000000 Z
55
+ date: 2022-12-13 00:00:00.000000000 Z
56
56
  dependencies:
57
57
  - !ruby/object:Gem::Dependency
58
58
  name: async
metadata.gz.sig CHANGED
Binary file