Skip to content

Commit

Permalink
Initialize an internal CA store
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
brandur-stripe committed Mar 14, 2016
1 parent c3c5413 commit 5ea3c26
Showing 1 changed file with 22 additions and 1 deletion.
23 changes: 22 additions & 1 deletion lib/stripe.rb
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ module Stripe
@initial_network_retry_delay = 0.5

@ca_bundle_path = DEFAULT_CA_BUNDLE_PATH
@ca_store = nil
@verify_ssl_certs = true

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

if verify_ssl_certs
request_opts = {:verify_ssl => OpenSSL::SSL::VERIFY_PEER,
:ssl_ca_file => @ca_bundle_path}
:ssl_cert_store => ca_store}
else
request_opts = {:verify_ssl => false}
unless @verify_ssl_warned
Expand Down Expand Up @@ -155,6 +156,26 @@ def self.ca_bundle_path

def self.ca_bundle_path=(path)
@ca_bundle_path = path

# empty this field so a new store is initialized
@ca_store = nil
end

# A certificate store initialized from the the bundle in #ca_bundle_path and
# which is used to validate TLS on every request.
#
# This was added to the give the gem "pseudo thread safety" in that it seems
# when initiating many parallel requests marshaling the certificate store is
# the most likely point of failure (see issue #382). Any program attempting
# to leverage this pseudo safety should make a call to this method (i.e.
# `Stripe.ca_store`) in their initialization code because it marshals lazily
# and is itself not thread safe.
def self.ca_store
@ca_store ||= begin
store = OpenSSL::X509::Store.new
store.add_file(ca_bundle_path)
store
end
end

def self.max_network_retries
Expand Down

0 comments on commit 5ea3c26

Please sign in to comment.