Skip to content

Commit 5ea3c26

Browse files
Initialize an internal CA store
This attempts to give some semblance of thread safety to parallel library requests by pre-assigning a certificate store, the initialization of which seems to be a weak point for thread safety. Note that while this does seem to empirically improve the situation, it doesn't guarantee actual thread safety. A longer term solution to the problem is probably to assign a per-thread HTTP client for much stronger guarantees, but this is a little further out. More discussion on that topic in #313. Fixes #382.
1 parent c3c5413 commit 5ea3c26

File tree

1 file changed

+22
-1
lines changed

1 file changed

+22
-1
lines changed

lib/stripe.rb

+22-1
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ module Stripe
7474
@initial_network_retry_delay = 0.5
7575

7676
@ca_bundle_path = DEFAULT_CA_BUNDLE_PATH
77+
@ca_store = nil
7778
@verify_ssl_certs = true
7879

7980
@open_timeout = 30
@@ -110,7 +111,7 @@ def self.request(method, url, api_key, params={}, headers={}, api_base_url=nil)
110111

111112
if verify_ssl_certs
112113
request_opts = {:verify_ssl => OpenSSL::SSL::VERIFY_PEER,
113-
:ssl_ca_file => @ca_bundle_path}
114+
:ssl_cert_store => ca_store}
114115
else
115116
request_opts = {:verify_ssl => false}
116117
unless @verify_ssl_warned
@@ -155,6 +156,26 @@ def self.ca_bundle_path
155156

156157
def self.ca_bundle_path=(path)
157158
@ca_bundle_path = path
159+
160+
# empty this field so a new store is initialized
161+
@ca_store = nil
162+
end
163+
164+
# A certificate store initialized from the the bundle in #ca_bundle_path and
165+
# which is used to validate TLS on every request.
166+
#
167+
# This was added to the give the gem "pseudo thread safety" in that it seems
168+
# when initiating many parallel requests marshaling the certificate store is
169+
# the most likely point of failure (see issue #382). Any program attempting
170+
# to leverage this pseudo safety should make a call to this method (i.e.
171+
# `Stripe.ca_store`) in their initialization code because it marshals lazily
172+
# and is itself not thread safe.
173+
def self.ca_store
174+
@ca_store ||= begin
175+
store = OpenSSL::X509::Store.new
176+
store.add_file(ca_bundle_path)
177+
store
178+
end
158179
end
159180

160181
def self.max_network_retries

0 commit comments

Comments
 (0)