openfeature-go-feature-flag-provider 0.1.6 → 0.1.7

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: 88b909669520d990cdd3bab857d26fe0aebd5a6d753a311d88b73fd8026cfd49
4
- data.tar.gz: f5ae9b1d0a474a1f547f1dd9b84b0f9c4cee48f938f79e1b2d96ca67acc5380c
3
+ metadata.gz: 0f77c6e14ebd429606e0f754c034e740fa5b201d33a2e060417c06d63ff1200c
4
+ data.tar.gz: c3066c5d408e51eec86d06e288fc461934767815d244a95ad758363e97b9bcbd
5
5
  SHA512:
6
- metadata.gz: 68053f645f8b2ea7d3c48f71e5c22bf6b64308cf4656a3480611bc82f200d38df9d527134e734b51e017bbf96814eb7b9abbb5b86205860eaafc7ff68df3d37c
7
- data.tar.gz: 1f5125e5d8360b48a12282f227dc69ea9302dd273c4bd728ce5c67ff159f11aaa97753a8dcca25a7d36959400e5d40c4af80b39150cb83cd5a514058f1099248
6
+ metadata.gz: f70df57dbf0442f9058aad26a15cb3908022dafb87af3d7b195cb66d82866898579da0f0a771c3ffd793bbe283b796a693912b3ab25e41674ccc86367f023cf1
7
+ data.tar.gz: 44d1b3d4c43eee840b6d6c81f7f665df065a2e3af135d9fd43cece06fa567244991bb9781bdd64c6cdeb34e66a14a044993a3adfd8ff5d42a52785299d27e51b
data/CHANGELOG.md CHANGED
@@ -1,5 +1,12 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.1.7](https://github.com/open-feature/ruby-sdk-contrib/compare/openfeature-go-feature-flag-provider/v0.1.6...openfeature-go-feature-flag-provider/v0.1.7) (2025-11-19)
4
+
5
+
6
+ ### ✨ New Features
7
+
8
+ * **GoFeatureFlag:** unix client ([#66](https://github.com/open-feature/ruby-sdk-contrib/issues/66)) ([3f68ce8](https://github.com/open-feature/ruby-sdk-contrib/commit/3f68ce8691646779755affb2c86edf51ae21b40b))
9
+
3
10
  ## [0.1.6](https://github.com/open-feature/ruby-sdk-contrib/compare/openfeature-go-feature-flag-provider/v0.1.5...openfeature-go-feature-flag-provider/v0.1.6) (2025-11-11)
4
11
 
5
12
 
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- openfeature-go-feature-flag-provider (0.1.6)
4
+ openfeature-go-feature-flag-provider (0.1.7)
5
5
  faraday-net_http_persistent (~> 2.3)
6
6
  openfeature-sdk (~> 0.3.1)
7
7
 
@@ -0,0 +1,127 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "net/http"
4
+ require "json"
5
+ require "open_feature/sdk"
6
+ require_relative "../error/errors"
7
+ require_relative "../model/ofrep_api_response"
8
+
9
+ module OpenFeature
10
+ module GoFeatureFlag
11
+ module Client
12
+ class Common
13
+ def initialize(endpoint: nil, custom_headers: nil)
14
+ raise "This should be overwritten by implementations"
15
+ end
16
+
17
+ def evaluate_ofrep_api(flag_key:, evaluation_context:)
18
+ raise "This should be overwritten by implementations"
19
+ end
20
+
21
+ private
22
+
23
+ def headers
24
+ {"Content-Type" => "application/json"}.merge(@custom_headers || {})
25
+ end
26
+
27
+ def check_retry_after
28
+ unless @retry_after.nil?
29
+ if Time.now < @retry_after
30
+ raise OpenFeature::GoFeatureFlag::RateLimited.new(nil)
31
+ else
32
+ @retry_after = nil
33
+ end
34
+ end
35
+ end
36
+
37
+ def parse_error_response(response)
38
+ required_keys = %w[key error_code]
39
+ parsed = JSON.parse(response.body)
40
+
41
+ missing_keys = required_keys - parsed.keys
42
+ unless missing_keys.empty?
43
+ raise OpenFeature::GoFeatureFlag::ParseError.new(response)
44
+ end
45
+
46
+ OpenFeature::GoFeatureFlag::OfrepApiResponse.new(
47
+ value: nil,
48
+ key: parsed["key"],
49
+ reason: SDK::Provider::Reason::ERROR,
50
+ variant: nil,
51
+ error_code: error_code_mapper(parsed["error_code"]),
52
+ error_details: parsed["error_details"],
53
+ metadata: nil
54
+ )
55
+ end
56
+
57
+ def parse_success_response(response)
58
+ required_keys = %w[key value reason variant]
59
+ parsed = JSON.parse(response.body)
60
+
61
+ missing_keys = required_keys - parsed.keys
62
+ unless missing_keys.empty?
63
+ raise OpenFeature::GoFeatureFlag::ParseError.new(response)
64
+ end
65
+
66
+ OpenFeature::GoFeatureFlag::OfrepApiResponse.new(
67
+ value: parsed["value"],
68
+ key: parsed["key"],
69
+ reason: reason_mapper(parsed["reason"]),
70
+ variant: parsed["variant"],
71
+ error_code: nil,
72
+ error_details: nil,
73
+ metadata: parsed["metadata"]
74
+ )
75
+ end
76
+
77
+ def reason_mapper(reason_str)
78
+ reason_str = reason_str.upcase
79
+ reason_map = {
80
+ "STATIC" => SDK::Provider::Reason::STATIC,
81
+ "DEFAULT" => SDK::Provider::Reason::DEFAULT,
82
+ "TARGETING_MATCH" => SDK::Provider::Reason::TARGETING_MATCH,
83
+ "SPLIT" => SDK::Provider::Reason::SPLIT,
84
+ "CACHED" => SDK::Provider::Reason::CACHED,
85
+ "DISABLED" => SDK::Provider::Reason::DISABLED,
86
+ "UNKNOWN" => SDK::Provider::Reason::UNKNOWN,
87
+ "STALE" => SDK::Provider::Reason::STALE,
88
+ "ERROR" => SDK::Provider::Reason::ERROR
89
+ }
90
+ reason_map[reason_str] || SDK::Provider::Reason::UNKNOWN
91
+ end
92
+
93
+ def error_code_mapper(error_code_str)
94
+ error_code_str = error_code_str.upcase
95
+ error_code_map = {
96
+ "PROVIDER_NOT_READY" => SDK::Provider::ErrorCode::PROVIDER_NOT_READY,
97
+ "FLAG_NOT_FOUND" => SDK::Provider::ErrorCode::FLAG_NOT_FOUND,
98
+ "PARSE_ERROR" => SDK::Provider::ErrorCode::PARSE_ERROR,
99
+ "TYPE_MISMATCH" => SDK::Provider::ErrorCode::TYPE_MISMATCH,
100
+ "TARGETING_KEY_MISSING" => SDK::Provider::ErrorCode::TARGETING_KEY_MISSING,
101
+ "INVALID_CONTEXT" => SDK::Provider::ErrorCode::INVALID_CONTEXT,
102
+ "GENERAL" => SDK::Provider::ErrorCode::GENERAL
103
+ }
104
+ error_code_map[error_code_str] || SDK::Provider::ErrorCode::GENERAL
105
+ end
106
+
107
+ def parse_retry_later_header(response)
108
+ retry_after = response["Retry-After"]
109
+ return nil if retry_after.nil?
110
+
111
+ begin
112
+ @retry_after = if /^\d+$/.match?(retry_after)
113
+ # Retry-After is in seconds
114
+ Time.now + Integer(retry_after)
115
+ else
116
+ # Retry-After is an HTTP-date
117
+ Time.httpdate(retry_after)
118
+ end
119
+ rescue ArgumentError
120
+ # ignore invalid Retry-After header
121
+ nil
122
+ end
123
+ end
124
+ end
125
+ end
126
+ end
127
+ end
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "common"
4
+ require "faraday/net_http_persistent"
5
+
6
+ module OpenFeature
7
+ module GoFeatureFlag
8
+ module Client
9
+ class HttpApi < Common
10
+ def initialize(endpoint: nil, custom_headers: nil, instrumentation: nil)
11
+ @custom_headers = custom_headers
12
+ @faraday_connection = Faraday.new(url: endpoint, headers: headers) do |f|
13
+ f.request :instrumentation, instrumentation if instrumentation
14
+ f.adapter :net_http_persistent do |http|
15
+ http.idle_timeout = 30
16
+ end
17
+ end
18
+ end
19
+
20
+ def evaluate_ofrep_api(flag_key:, evaluation_context:)
21
+ check_retry_after
22
+ evaluation_context = OpenFeature::SDK::EvaluationContext.new if evaluation_context.nil?
23
+ # replace targeting_key by targetingKey
24
+ evaluation_context.fields["targetingKey"] = evaluation_context.targeting_key
25
+ evaluation_context.fields.delete("targeting_key")
26
+
27
+ response = @faraday_connection.post("/ofrep/v1/evaluate/flags/#{flag_key}") do |req|
28
+ req.body = {context: evaluation_context.fields}.to_json
29
+ end
30
+
31
+ case response.status
32
+ when 200
33
+ parse_success_response(response)
34
+ when 400
35
+ parse_error_response(response)
36
+ when 401, 403
37
+ raise OpenFeature::GoFeatureFlag::UnauthorizedError.new(response)
38
+ when 404
39
+ raise OpenFeature::GoFeatureFlag::FlagNotFoundError.new(response, flag_key)
40
+ when 429
41
+ parse_retry_later_header(response)
42
+ raise OpenFeature::GoFeatureFlag::RateLimited.new(response)
43
+ else
44
+ raise OpenFeature::GoFeatureFlag::InternalServerError.new(response)
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "common"
4
+ require_relative "../internal/http_unix"
5
+
6
+ module OpenFeature
7
+ module GoFeatureFlag
8
+ module Client
9
+ class UnixApi < Common
10
+ attr_accessor :socket
11
+
12
+ def initialize(endpoint: nil, custom_headers: nil)
13
+ @custom_headers = custom_headers
14
+ @socket = HttpUnix.new(endpoint)
15
+ end
16
+
17
+ def evaluate_ofrep_api(flag_key:, evaluation_context:)
18
+ check_retry_after
19
+ evaluation_context = OpenFeature::SDK::EvaluationContext.new if evaluation_context.nil?
20
+ # replace targeting_key by targetingKey
21
+ evaluation_context.fields["targetingKey"] = evaluation_context.targeting_key
22
+ evaluation_context.fields.delete("targeting_key")
23
+
24
+ response = @socket.post("/ofrep/v1/evaluate/flags/#{flag_key}", {context: evaluation_context.fields}, headers)
25
+
26
+ case response.code
27
+ when "200"
28
+ parse_success_response(response)
29
+ when "400"
30
+ parse_error_response(response)
31
+ when "401", "403"
32
+ raise OpenFeature::GoFeatureFlag::UnauthorizedError.new(response)
33
+ when "404"
34
+ raise OpenFeature::GoFeatureFlag::FlagNotFoundError.new(response, flag_key)
35
+ when "429"
36
+ parse_retry_later_header(response)
37
+ raise OpenFeature::GoFeatureFlag::RateLimited.new(response)
38
+ else
39
+ raise OpenFeature::GoFeatureFlag::InternalServerError.new(response)
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
@@ -1,16 +1,20 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "openfeature/go-feature-flag/client/http_api"
4
+ require "openfeature/go-feature-flag/client/unix_api"
5
+
3
6
  module OpenFeature
4
7
  module GoFeatureFlag
5
8
  # This class is the entry point for the GoFeatureFlagProvider
6
9
  class Provider
7
10
  PROVIDER_NAME = "GO Feature Flag Provider"
11
+ Client = OpenFeature::GoFeatureFlag::Client
8
12
  attr_reader :metadata, :options
9
13
 
10
14
  def initialize(options: Options.new)
11
15
  @metadata = SDK::Provider::ProviderMetadata.new(name: PROVIDER_NAME)
12
16
  @options = options
13
- @goff_api = GoFeatureFlagApi.new(endpoint: options.endpoint, custom_headers: options.custom_headers, instrumentation: options.instrumentation)
17
+ @goff_api = build_client(options)
14
18
  end
15
19
 
16
20
  def fetch_boolean_value(flag_key:, default_value:, evaluation_context: nil)
@@ -95,6 +99,17 @@ module OpenFeature
95
99
  raise InvalidOptionError.new(SDK::Provider::ErrorCode::GENERAL, "invalid flag key provided")
96
100
  end
97
101
  end
102
+
103
+ def build_client(options)
104
+ case options.type
105
+ when "http"
106
+ Client::HttpApi.new(endpoint: options.endpoint, custom_headers: options.custom_headers, instrumentation: options.instrumentation)
107
+ when "unix"
108
+ Client::UnixApi.new(endpoint: options.endpoint, custom_headers: options.custom_headers)
109
+ else
110
+ raise InvalidOptionError.new(SDK::Provider::ErrorCode::GENERAL, "Invalid client type: '#{options.type}'. Supported types are: 'http', 'unix'")
111
+ end
112
+ end
98
113
  end
99
114
  end
100
115
  end
@@ -0,0 +1,31 @@
1
+ require "net/http"
2
+
3
+ class HttpUnix < Net::HTTP
4
+ BufferedIO = ::Net::BufferedIO
5
+ UNIX_REGEXP = %r{^unix://}i
6
+
7
+ def initialize(address, port = nil)
8
+ super(address, port)
9
+ @socket_type = "unix"
10
+ @socket_path = address.sub(UNIX_REGEXP, "")
11
+
12
+ @host = "localhost"
13
+ @port = 1031
14
+ end
15
+
16
+ def connect
17
+ s = UNIXSocket.open(@socket_path)
18
+ @socket = BufferedIO.new(s,
19
+ read_timeout: @read_timeout,
20
+ continue_timeout: @continue_timeout,
21
+ debug_output: @debug_output)
22
+ on_connect
23
+ end
24
+
25
+ def post(url, body, headers)
26
+ request = Net::HTTP::Post.new(url, headers)
27
+ request["host"] = "localhost" # required to form correct HTTP request
28
+ request.body = body.to_json
29
+ request(request)
30
+ end
31
+ end
@@ -6,11 +6,12 @@ module OpenFeature
6
6
  module GoFeatureFlag
7
7
  # This class is the configuration class for the GoFeatureFlagProvider
8
8
  class Options
9
- attr_accessor :endpoint, :custom_headers, :exporter_metadata, :instrumentation
9
+ attr_accessor :endpoint, :custom_headers, :exporter_metadata, :instrumentation, :type
10
10
 
11
- def initialize(endpoint: nil, headers: {}, exporter_metadata: {}, instrumentation: nil)
12
- validate_endpoint(endpoint: endpoint)
11
+ def initialize(endpoint: nil, headers: {}, exporter_metadata: {}, instrumentation: nil, type: "http")
12
+ validate_endpoint(endpoint, type)
13
13
  validate_instrumentation(instrumentation: instrumentation)
14
+ @type = type
14
15
  @endpoint = endpoint
15
16
  @custom_headers = headers
16
17
  @exporter_metadata = exporter_metadata
@@ -19,11 +20,18 @@ module OpenFeature
19
20
 
20
21
  private
21
22
 
22
- def validate_endpoint(endpoint: nil)
23
+ def validate_endpoint(endpoint, type)
23
24
  return if endpoint.nil?
24
25
 
25
- uri = URI.parse(endpoint)
26
- raise ArgumentError, "Invalid URL for endpoint: #{endpoint}" unless uri.is_a?(URI::HTTP) || uri.is_a?(URI::HTTPS)
26
+ case type
27
+ when "http"
28
+ uri = URI.parse(endpoint)
29
+ raise ArgumentError, "Invalid URL for endpoint: #{endpoint}" unless uri.is_a?(URI::HTTP) || uri.is_a?(URI::HTTPS)
30
+ when "unix"
31
+ raise ArgumentError, "File not found: #{endpoint}" unless File.exist?(endpoint)
32
+ else
33
+ raise ArgumentError, "Invalid Type: #{type}"
34
+ end
27
35
  rescue URI::InvalidURIError
28
36
  raise ArgumentError, "Invalid URL for endpoint: #{endpoint}"
29
37
  end
@@ -1,5 +1,5 @@
1
1
  module OpenFeature
2
2
  module GoFeatureFlag
3
- GO_FEATURE_FLAG_PROVIDER_VERSION = "0.1.6"
3
+ GO_FEATURE_FLAG_PROVIDER_VERSION = "0.1.7"
4
4
  end
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: openfeature-go-feature-flag-provider
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.6
4
+ version: 0.1.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - Thomas Poignant
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2025-11-11 00:00:00.000000000 Z
11
+ date: 2025-11-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: openfeature-sdk
@@ -136,9 +136,12 @@ files:
136
136
  - README.md
137
137
  - Rakefile
138
138
  - bin/rake
139
+ - lib/openfeature/go-feature-flag/client/common.rb
140
+ - lib/openfeature/go-feature-flag/client/http_api.rb
141
+ - lib/openfeature/go-feature-flag/client/unix_api.rb
139
142
  - lib/openfeature/go-feature-flag/error/errors.rb
140
143
  - lib/openfeature/go-feature-flag/go_feature_flag_provider.rb
141
- - lib/openfeature/go-feature-flag/goff_api.rb
144
+ - lib/openfeature/go-feature-flag/internal/http_unix.rb
142
145
  - lib/openfeature/go-feature-flag/model/ofrep_api_response.rb
143
146
  - lib/openfeature/go-feature-flag/options.rb
144
147
  - lib/openfeature/go-feature-flag/version.rb
@@ -1,153 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "open_feature/sdk"
4
- require "net/http"
5
- require "json"
6
- require "faraday/net_http_persistent"
7
- require_relative "error/errors"
8
- require_relative "model/ofrep_api_response"
9
-
10
- module OpenFeature
11
- module GoFeatureFlag
12
- # This class is the entry point for the GoFeatureFlagProvider
13
- class GoFeatureFlagApi
14
- def initialize(endpoint: nil, custom_headers: nil, instrumentation: nil)
15
- @faraday_connection = Faraday.new(url: endpoint, headers: headers(custom_headers)) do |f|
16
- f.request :instrumentation, instrumentation if instrumentation
17
- f.adapter :net_http_persistent do |http|
18
- http.idle_timeout = 30
19
- end
20
- end
21
- end
22
-
23
- def evaluate_ofrep_api(flag_key:, evaluation_context:)
24
- unless @retry_after.nil?
25
- if Time.now < @retry_after
26
- raise OpenFeature::GoFeatureFlag::RateLimited.new(nil)
27
- else
28
- @retry_after = nil
29
- end
30
- end
31
-
32
- evaluation_context = OpenFeature::SDK::EvaluationContext.new if evaluation_context.nil?
33
- # replace targeting_key by targetingKey
34
- evaluation_context.fields["targetingKey"] = evaluation_context.targeting_key
35
- evaluation_context.fields.delete("targeting_key")
36
-
37
- response = @faraday_connection.post("/ofrep/v1/evaluate/flags/#{flag_key}") do |req|
38
- req.body = {context: evaluation_context.fields}.to_json
39
- end
40
-
41
- case response.status
42
- when 200
43
- parse_success_response(response)
44
- when 400
45
- parse_error_response(response)
46
- when 401, 403
47
- raise OpenFeature::GoFeatureFlag::UnauthorizedError.new(response)
48
- when 404
49
- raise OpenFeature::GoFeatureFlag::FlagNotFoundError.new(response, flag_key)
50
- when 429
51
- parse_retry_later_header(response)
52
- raise OpenFeature::GoFeatureFlag::RateLimited.new(response)
53
- else
54
- raise OpenFeature::GoFeatureFlag::InternalServerError.new(response)
55
- end
56
- end
57
-
58
- private
59
-
60
- def headers(custom_headers)
61
- {"Content-Type" => "application/json"}.merge(custom_headers || {})
62
- end
63
-
64
- def parse_error_response(response)
65
- required_keys = %w[key error_code]
66
- parsed = JSON.parse(response.body)
67
-
68
- missing_keys = required_keys - parsed.keys
69
- unless missing_keys.empty?
70
- raise OpenFeature::GoFeatureFlag::ParseError.new(response)
71
- end
72
-
73
- OpenFeature::GoFeatureFlag::OfrepApiResponse.new(
74
- value: nil,
75
- key: parsed["key"],
76
- reason: SDK::Provider::Reason::ERROR,
77
- variant: nil,
78
- error_code: error_code_mapper(parsed["error_code"]),
79
- error_details: parsed["error_details"],
80
- metadata: nil
81
- )
82
- end
83
-
84
- def parse_success_response(response)
85
- required_keys = %w[key value reason variant]
86
- parsed = JSON.parse(response.body)
87
-
88
- missing_keys = required_keys - parsed.keys
89
- unless missing_keys.empty?
90
- raise OpenFeature::GoFeatureFlag::ParseError.new(response)
91
- end
92
-
93
- OpenFeature::GoFeatureFlag::OfrepApiResponse.new(
94
- value: parsed["value"],
95
- key: parsed["key"],
96
- reason: reason_mapper(parsed["reason"]),
97
- variant: parsed["variant"],
98
- error_code: nil,
99
- error_details: nil,
100
- metadata: parsed["metadata"]
101
- )
102
- end
103
-
104
- def reason_mapper(reason_str)
105
- reason_str = reason_str.upcase
106
- reason_map = {
107
- "STATIC" => SDK::Provider::Reason::STATIC,
108
- "DEFAULT" => SDK::Provider::Reason::DEFAULT,
109
- "TARGETING_MATCH" => SDK::Provider::Reason::TARGETING_MATCH,
110
- "SPLIT" => SDK::Provider::Reason::SPLIT,
111
- "CACHED" => SDK::Provider::Reason::CACHED,
112
- "DISABLED" => SDK::Provider::Reason::DISABLED,
113
- "UNKNOWN" => SDK::Provider::Reason::UNKNOWN,
114
- "STALE" => SDK::Provider::Reason::STALE,
115
- "ERROR" => SDK::Provider::Reason::ERROR
116
- }
117
- reason_map[reason_str] || SDK::Provider::Reason::UNKNOWN
118
- end
119
-
120
- def error_code_mapper(error_code_str)
121
- error_code_str = error_code_str.upcase
122
- error_code_map = {
123
- "PROVIDER_NOT_READY" => SDK::Provider::ErrorCode::PROVIDER_NOT_READY,
124
- "FLAG_NOT_FOUND" => SDK::Provider::ErrorCode::FLAG_NOT_FOUND,
125
- "PARSE_ERROR" => SDK::Provider::ErrorCode::PARSE_ERROR,
126
- "TYPE_MISMATCH" => SDK::Provider::ErrorCode::TYPE_MISMATCH,
127
- "TARGETING_KEY_MISSING" => SDK::Provider::ErrorCode::TARGETING_KEY_MISSING,
128
- "INVALID_CONTEXT" => SDK::Provider::ErrorCode::INVALID_CONTEXT,
129
- "GENERAL" => SDK::Provider::ErrorCode::GENERAL
130
- }
131
- error_code_map[error_code_str] || SDK::Provider::ErrorCode::GENERAL
132
- end
133
-
134
- def parse_retry_later_header(response)
135
- retry_after = response["Retry-After"]
136
- return nil if retry_after.nil?
137
-
138
- begin
139
- @retry_after = if /^\d+$/.match?(retry_after)
140
- # Retry-After is in seconds
141
- Time.now + Integer(retry_after)
142
- else
143
- # Retry-After is an HTTP-date
144
- Time.httpdate(retry_after)
145
- end
146
- rescue ArgumentError
147
- # ignore invalid Retry-After header
148
- nil
149
- end
150
- end
151
- end
152
- end
153
- end