-
Notifications
You must be signed in to change notification settings - Fork 54
Expand file tree
/
Copy pathrequestor.rb
More file actions
111 lines (99 loc) · 3.4 KB
/
requestor.rb
File metadata and controls
111 lines (99 loc) · 3.4 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
require "ldclient-rb/impl/model/serialization"
require "ldclient-rb/impl/util"
require "ldclient-rb/impl/data_system/http_config_options"
require "concurrent/atomics"
require "json"
require "uri"
require "http"
module LaunchDarkly
module Impl
module DataSource
class UnexpectedResponseError < StandardError
def initialize(status)
@status = status
super("HTTP error #{status}")
end
def status
@status
end
end
class Requestor
CacheEntry = Struct.new(:etag, :body)
def initialize(sdk_key, config)
@sdk_key = sdk_key
@config = config
@http_config = DataSystem::HttpConfigOptions.new(
base_uri: config.base_uri,
socket_factory: config.socket_factory,
read_timeout: config.read_timeout,
connect_timeout: config.connect_timeout
)
@http_client = Impl::Util.new_http_client(@http_config)
.use(:auto_inflate)
.headers("Accept-Encoding" => "gzip")
@cache = @config.cache_store
end
def request_all_data()
all_data = JSON.parse(make_request("/sdk/latest-all"), symbolize_names: true)
Impl::Model.make_all_store_data(all_data, @config.logger)
end
def stop
begin
@http_client.close
rescue
end
end
private
def make_request(path)
uri = URI(
Util.add_payload_filter_key(@http_config.base_uri + path, @config)
)
headers = {}
Impl::Util.default_http_headers(@sdk_key, @config).each { |k, v| headers[k] = v }
headers["Connection"] = "keep-alive"
cached = @cache.read(uri)
unless cached.nil?
headers["If-None-Match"] = cached.etag
end
response = @http_client.request("GET", uri, headers: headers)
status = response.status.code
# must fully read body for persistent connections
body = response.to_s
@config.logger.debug { "[LDClient] Got response from uri: #{uri}\n\tstatus code: #{status}\n\theaders: #{response.headers.to_h}\n\tbody: #{body}" }
if status == 304 && !cached.nil?
body = cached.body
else
@cache.delete(uri)
if status < 200 || status >= 300
raise UnexpectedResponseError.new(status)
end
body = fix_encoding(body, response.headers["content-type"])
etag = response.headers["etag"]
@cache.write(uri, CacheEntry.new(etag, body)) unless etag.nil?
end
body
end
def fix_encoding(body, content_type)
return body if content_type.nil?
media_type, charset = parse_content_type(content_type)
return body if charset.nil?
body.force_encoding(Encoding::find(charset)).encode(Encoding::UTF_8)
end
def parse_content_type(value)
return [nil, nil] if value.nil? || value == ''
parts = value.split(/; */)
return [value, nil] if parts.count < 2
charset = nil
parts.each do |part|
fields = part.split('=')
if fields.count >= 2 && fields[0] == 'charset'
charset = fields[1]
break
end
end
[parts[0], charset]
end
end
end
end
end