activemerchant 1.78.0 → 1.79.0

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.
Files changed (42) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG +49 -0
  3. data/lib/active_merchant.rb +2 -5
  4. data/lib/active_merchant/billing/credit_card_methods.rb +3 -1
  5. data/lib/active_merchant/billing/gateways/adyen.rb +17 -2
  6. data/lib/active_merchant/billing/gateways/authorize_net.rb +16 -11
  7. data/lib/active_merchant/billing/gateways/barclaycard_smartpay.rb +1 -0
  8. data/lib/active_merchant/billing/gateways/borgun.rb +0 -1
  9. data/lib/active_merchant/billing/gateways/braintree/braintree_common.rb +1 -0
  10. data/lib/active_merchant/billing/gateways/braintree_blue.rb +17 -4
  11. data/lib/active_merchant/billing/gateways/checkout_v2.rb +7 -0
  12. data/lib/active_merchant/billing/gateways/clearhaus.rb +0 -2
  13. data/lib/active_merchant/billing/gateways/cyber_source.rb +11 -2
  14. data/lib/active_merchant/billing/gateways/ebanx.rb +3 -3
  15. data/lib/active_merchant/billing/gateways/elavon.rb +1 -1
  16. data/lib/active_merchant/billing/gateways/first_pay.rb +10 -9
  17. data/lib/active_merchant/billing/gateways/merchant_e_solutions.rb +11 -0
  18. data/lib/active_merchant/billing/gateways/merchant_warrior.rb +12 -0
  19. data/lib/active_merchant/billing/gateways/migs.rb +0 -2
  20. data/lib/active_merchant/billing/gateways/mundipagg.rb +291 -0
  21. data/lib/active_merchant/billing/gateways/nab_transact.rb +4 -4
  22. data/lib/active_merchant/billing/gateways/paymentez.rb +6 -13
  23. data/lib/active_merchant/billing/gateways/paypal.rb +0 -12
  24. data/lib/active_merchant/billing/gateways/paypal/paypal_common_api.rb +14 -0
  25. data/lib/active_merchant/billing/gateways/paystation.rb +10 -0
  26. data/lib/active_merchant/billing/gateways/psigate.rb +11 -0
  27. data/lib/active_merchant/billing/gateways/qbms.rb +11 -0
  28. data/lib/active_merchant/billing/gateways/realex.rb +14 -1
  29. data/lib/active_merchant/billing/gateways/redsys.rb +1 -1
  30. data/lib/active_merchant/billing/gateways/safe_charge.rb +8 -4
  31. data/lib/active_merchant/billing/gateways/smart_ps.rb +1 -1
  32. data/lib/active_merchant/billing/gateways/spreedly_core.rb +41 -6
  33. data/lib/active_merchant/billing/gateways/stripe.rb +14 -4
  34. data/lib/active_merchant/billing/gateways/usa_epay_transaction.rb +6 -1
  35. data/lib/active_merchant/billing/gateways/worldpay.rb +45 -14
  36. data/lib/active_merchant/connection.rb +38 -9
  37. data/lib/active_merchant/net_http_ssl_connection.rb +9 -0
  38. data/lib/active_merchant/network_connection_retries.rb +2 -0
  39. data/lib/active_merchant/posts_data.rb +10 -0
  40. data/lib/active_merchant/version.rb +1 -1
  41. data/lib/support/ssl_version.rb +87 -0
  42. metadata +7 -4
@@ -88,6 +88,16 @@ module ActiveMerchant #:nodoc:
88
88
  authorize(0, credit_card, options)
89
89
  end
90
90
 
91
+ def supports_scrubbing?
92
+ true
93
+ end
94
+
95
+ def scrub(transcript)
96
+ transcript.
97
+ gsub(%r((pstn_cn=)\d*), '\1[FILTERED]').
98
+ gsub(%r((pstn_cc=)\d*), '\1[FILTERED]')
99
+ end
100
+
91
101
  private
92
102
 
93
103
  def new_request
@@ -86,6 +86,17 @@ module ActiveMerchant #:nodoc:
86
86
  commit(nil, nil, options)
87
87
  end
88
88
 
89
+ def supports_scrubbing?
90
+ true
91
+ end
92
+
93
+ def scrub(transcript)
94
+ transcript.
95
+ gsub(%r((<Passphrase>)[^<]*(</Passphrase>))i, '\1[FILTERED]\2').
96
+ gsub(%r((<CardNumber>)[^<]*(</CardNumber>))i, '\1[FILTERED]\2').
97
+ gsub(%r((<CardIDNumber>)[^<]*(</CardIDNumber>))i, '\1[FILTERED]\2')
98
+ end
99
+
89
100
  private
90
101
 
91
102
  def commit(money, creditcard, options = {})
@@ -113,6 +113,17 @@ module ActiveMerchant #:nodoc:
113
113
  commit(:query, nil, {})
114
114
  end
115
115
 
116
+ def supports_scrubbing?
117
+ true
118
+ end
119
+
120
+ def scrub(transcript)
121
+ transcript.
122
+ gsub(%r((<ConnectionTicket>)[^<]*(</ConnectionTicket>))i, '\1[FILTERED]\2').
123
+ gsub(%r((<CreditCardNumber>)[^<]*(</CreditCardNumber>))i, '\1[FILTERED]\2').
124
+ gsub(%r((<CardSecurityCode>)[^<]*(</CardSecurityCode>))i, '\1[FILTERED]\2')
125
+ end
126
+
116
127
  private
117
128
 
118
129
  def hosted?
@@ -35,7 +35,7 @@ module ActiveMerchant
35
35
  self.money_format = :cents
36
36
  self.default_currency = 'EUR'
37
37
  self.supported_cardtypes = [ :visa, :master, :american_express, :diners_club, :switch, :solo, :laser ]
38
- self.supported_countries = %w(IE GB FR BE NL LU IT)
38
+ self.supported_countries = %w(IE GB FR BE NL LU IT US CA ES)
39
39
  self.homepage_url = 'http://www.realexpayments.com/'
40
40
  self.display_name = 'Realex'
41
41
 
@@ -140,6 +140,7 @@ module ActiveMerchant
140
140
  add_card(xml, credit_card)
141
141
  xml.tag! 'autosettle', 'flag' => auto_settle_flag(action)
142
142
  add_signed_digest(xml, timestamp, @options[:login], sanitize_order_id(options[:order_id]), amount(money), (options[:currency] || currency(money)), credit_card.number)
143
+ add_network_tokenization_card(xml, credit_card) if credit_card.is_a?(NetworkTokenizationCreditCard)
143
144
  add_comments(xml, options)
144
145
  add_address_and_customer_info(xml, options)
145
146
  end
@@ -251,6 +252,18 @@ module ActiveMerchant
251
252
  end
252
253
  end
253
254
 
255
+ def add_network_tokenization_card(xml, payment)
256
+ xml.tag! 'mpi' do
257
+ xml.tag! 'cavv', payment.payment_cryptogram
258
+ xml.tag! 'eci', payment.eci
259
+ end
260
+ xml.tag! 'supplementarydata' do
261
+ xml.tag! 'item', 'type' => 'mobile' do
262
+ xml.tag! 'field01', payment.source.to_s.gsub('_','-')
263
+ end
264
+ end
265
+ end
266
+
254
267
  def format_address_code(address)
255
268
  code = [address[:zip].to_s, address[:address1].to_s + address[:address2].to_s]
256
269
  code.collect{|e| e.gsub(/\D/, "")}.reject{|e| e.empty?}.join("|")
@@ -75,7 +75,7 @@ module ActiveMerchant #:nodoc:
75
75
  "NOK" => '578',
76
76
  "NZD" => '554',
77
77
  "PEN" => '604',
78
- "PLN" => '616',
78
+ "PLN" => '985',
79
79
  "RUB" => '643',
80
80
  "SAR" => '682',
81
81
  "SEK" => '752',
@@ -25,7 +25,7 @@ module ActiveMerchant #:nodoc:
25
25
  post[:sg_APIType] = 1 if options[:three_d_secure]
26
26
  trans_type = options[:three_d_secure] ? "Sale3D" : "Sale"
27
27
  add_transaction_data(trans_type, post, money, options)
28
- add_payment(post, payment)
28
+ add_payment(post, payment, options)
29
29
  add_customer_details(post, payment, options)
30
30
 
31
31
  commit(post)
@@ -34,7 +34,7 @@ module ActiveMerchant #:nodoc:
34
34
  def authorize(money, payment, options={})
35
35
  post = {}
36
36
  add_transaction_data("Auth", post, money, options)
37
- add_payment(post, payment)
37
+ add_payment(post, payment, options)
38
38
  add_customer_details(post, payment, options)
39
39
 
40
40
  commit(post)
@@ -69,7 +69,7 @@ module ActiveMerchant #:nodoc:
69
69
 
70
70
  def credit(money, payment, options={})
71
71
  post = {}
72
- add_payment(post, payment)
72
+ add_payment(post, payment, options)
73
73
  add_transaction_data("Credit", post, money, options)
74
74
  post[:sg_CreditType] = 1
75
75
 
@@ -125,14 +125,18 @@ module ActiveMerchant #:nodoc:
125
125
  post[:sg_WebsiteID] = options[:website_id] if options[:website_id]
126
126
  post[:sg_IPAddress] = options[:ip] if options[:ip]
127
127
  post[:sg_VendorID] = options[:vendor_id] if options[:vendor_id]
128
+ post[:sg_Descriptor] = options[:merchant_descriptor] if options[:merchant_descriptor]
129
+ post[:sg_MerchantPhoneNumber] = options[:merchant_phone_number] if options[:merchant_phone_number]
130
+ post[:sg_MerchantName] = options[:merchant_name] if options[:merchant_name]
128
131
  end
129
132
 
130
- def add_payment(post, payment)
133
+ def add_payment(post, payment, options={})
131
134
  post[:sg_NameOnCard] = payment.name
132
135
  post[:sg_CardNumber] = payment.number
133
136
  post[:sg_ExpMonth] = format(payment.month, :two_digits)
134
137
  post[:sg_ExpYear] = format(payment.year, :two_digits)
135
138
  post[:sg_CVV2] = payment.verification_value
139
+ post[:sg_StoredCredentialMode] = (options[:stored_credential_mode] == true ? 1 : 0)
136
140
  end
137
141
 
138
142
  def add_customer_details(post, payment, options)
@@ -229,7 +229,7 @@ module ActiveMerchant #:nodoc:
229
229
  end
230
230
 
231
231
  def commit(action, money, parameters)
232
- parameters[:amount] = amount(money) if money
232
+ parameters[:amount] = localized_amount(money, parameters[:currency] || default_currency) if money
233
233
  response = parse( ssl_post(self.live_url, post_data(action,parameters)) )
234
234
  Response.new(response["response"] == "1", message_from(response), response,
235
235
  :authorization => (response["transactionid"] || response["customer_vault_id"]),
@@ -44,7 +44,7 @@ module ActiveMerchant #:nodoc:
44
44
  purchase_with_token(money, payment_method, options)
45
45
  else
46
46
  MultiResponse.run do |r|
47
- r.process { save_card(false, payment_method, options) }
47
+ r.process { save_card(options[:store], payment_method, options) }
48
48
  r.process { purchase_with_token(money, r.authorization, options) }
49
49
  end
50
50
  end
@@ -62,7 +62,7 @@ module ActiveMerchant #:nodoc:
62
62
  authorize_with_token(money, payment_method, options)
63
63
  else
64
64
  MultiResponse.run do |r|
65
- r.process { save_card(false, payment_method, options) }
65
+ r.process { save_card(options[:store], payment_method, options) }
66
66
  r.process { authorize_with_token(money, r.authorization, options) }
67
67
  end
68
68
  end
@@ -88,6 +88,24 @@ module ActiveMerchant #:nodoc:
88
88
  commit("transactions/#{authorization}/void.xml", '')
89
89
  end
90
90
 
91
+
92
+ # Public: Determine whether a credit card is chargeable card and available for purchases.
93
+ #
94
+ # payment_method - The CreditCard or the Spreedly payment method token.
95
+ # options - A hash of options:
96
+ # :store - Retain the payment method if the verify
97
+ # succeeds. Defaults to false. (optional)
98
+ def verify(payment_method, options = {})
99
+ if payment_method.is_a?(String)
100
+ verify_with_token(payment_method, options)
101
+ else
102
+ MultiResponse.run do |r|
103
+ r.process { save_card(options[:store], payment_method, options) }
104
+ r.process { verify_with_token(r.authorization, options) }
105
+ end
106
+ end
107
+ end
108
+
91
109
  # Public: Store a credit card in the Spreedly vault and retain it.
92
110
  #
93
111
  # credit_card - The CreditCard to store
@@ -106,6 +124,13 @@ module ActiveMerchant #:nodoc:
106
124
  commit("payment_methods/#{authorization}/redact.xml", '', :put)
107
125
  end
108
126
 
127
+ # Public: Get the transaction with the given token.
128
+ def find(transaction_token)
129
+ commit("transactions/#{transaction_token}.xml", nil, :get)
130
+ end
131
+
132
+ alias_method :status, :find
133
+
109
134
  def supports_scrubbing?
110
135
  true
111
136
  end
@@ -140,10 +165,20 @@ module ActiveMerchant #:nodoc:
140
165
  commit("gateways/#{@options[:gateway_token]}/authorize.xml", request)
141
166
  end
142
167
 
168
+ def verify_with_token(payment_method_token, options)
169
+ request = build_xml_request('transaction') do |doc|
170
+ add_invoice(doc, nil, options)
171
+ doc.payment_method_token(payment_method_token)
172
+ doc.retain_on_success(true) if options[:store]
173
+ add_extra_options(:gateway_specific_fields, doc, options)
174
+ end
175
+
176
+ commit("gateways/#{@options[:gateway_token]}/verify.xml", request)
177
+ end
178
+
143
179
  def auth_purchase_request(money, payment_method_token, options)
144
180
  build_xml_request('transaction') do |doc|
145
181
  add_invoice(doc, money, options)
146
- doc.ip(options[:ip])
147
182
  add_extra_options(:gateway_specific_fields, doc, options)
148
183
  doc.payment_method_token(payment_method_token)
149
184
  doc.retain_on_success(true) if options[:store]
@@ -151,11 +186,11 @@ module ActiveMerchant #:nodoc:
151
186
  end
152
187
 
153
188
  def add_invoice(doc, money, options)
154
- doc.amount amount(money)
189
+ doc.amount amount(money) unless money.nil?
155
190
  doc.currency_code(options[:currency] || currency(money) || default_currency)
156
191
  doc.order_id(options[:order_id])
157
- doc.ip(options[:ip])
158
- doc.description(options[:description])
192
+ doc.ip(options[:ip]) if options[:ip]
193
+ doc.description(options[:description]) if options[:description]
159
194
  end
160
195
 
161
196
  def add_credit_card(doc, credit_card, options)
@@ -25,7 +25,7 @@ module ActiveMerchant #:nodoc:
25
25
  self.default_currency = 'USD'
26
26
  self.money_format = :cents
27
27
  self.supported_cardtypes = [:visa, :master, :american_express, :discover, :jcb, :diners_club, :maestro]
28
- self.currencies_without_fractions = %w(BIF CLP DJF GNF JPY KMF KRW MGA PYG RWF VND VUV XAF XOF XPF)
28
+ self.currencies_without_fractions = %w(BIF CLP DJF GNF JPY KMF KRW MGA PYG RWF VND VUV XAF XOF XPF UGX)
29
29
 
30
30
  self.homepage_url = 'https://stripe.com/'
31
31
  self.display_name = 'Stripe'
@@ -549,14 +549,14 @@ module ActiveMerchant #:nodoc:
549
549
  add_expand_parameters(parameters, options) if parameters
550
550
  response = api_request(method, url, parameters, options)
551
551
 
552
- success = !response.key?("error")
552
+ success = success_from(response)
553
553
 
554
554
  card = card_from_response(response)
555
555
  avs_code = AVS_CODE_TRANSLATOR["line1: #{card["address_line1_check"]}, zip: #{card["address_zip_check"]}"]
556
556
  cvc_code = CVC_CODE_TRANSLATOR[card["cvc_check"]]
557
557
 
558
558
  Response.new(success,
559
- success ? "Transaction approved" : response["error"]["message"],
559
+ message_from(success, response),
560
560
  response,
561
561
  :test => response_is_test?(response),
562
562
  :authorization => authorization_from(success, url, method, response),
@@ -568,7 +568,7 @@ module ActiveMerchant #:nodoc:
568
568
  end
569
569
 
570
570
  def authorization_from(success, url, method, response)
571
- return response["error"]["charge"] unless success
571
+ return response.fetch("error", {})["charge"] unless success
572
572
 
573
573
  if url == "customers"
574
574
  [response["id"], response["sources"]["data"].first["id"]].join("|")
@@ -579,6 +579,14 @@ module ActiveMerchant #:nodoc:
579
579
  end
580
580
  end
581
581
 
582
+ def message_from(success, response)
583
+ success ? "Transaction approved" : response.fetch("error", {"message" => "No error details"})["message"]
584
+ end
585
+
586
+ def success_from(response)
587
+ !response.key?("error") && response["status"] != "failed"
588
+ end
589
+
582
590
  def response_error(raw_response)
583
591
  begin
584
592
  parse(raw_response)
@@ -626,6 +634,8 @@ module ActiveMerchant #:nodoc:
626
634
  end
627
635
 
628
636
  def error_code_from(response)
637
+ return STANDARD_ERROR_CODE_MAPPING['processing_error'] unless response['error']
638
+
629
639
  code = response['error']['code']
630
640
  decline_code = response['error']['decline_code'] if code == 'card_declined'
631
641
 
@@ -140,7 +140,12 @@ module ActiveMerchant #:nodoc:
140
140
 
141
141
  if options.has_key? :email
142
142
  post[:custemail] = options[:email]
143
- post[:custreceipt] = 'No'
143
+ if options[:cust_receipt]
144
+ post[:custreceipt] = options[:cust_receipt]
145
+ post[:custreceiptname] = options[:cust_receipt_name] if options[:cust_receipt_name]
146
+ else
147
+ post[:custreceipt] = 'No'
148
+ end
144
149
  end
145
150
 
146
151
  if options.has_key? :customer
@@ -6,7 +6,7 @@ module ActiveMerchant #:nodoc:
6
6
 
7
7
  self.default_currency = 'GBP'
8
8
  self.money_format = :cents
9
- self.supported_countries = %w(HK GB AU AD BE CH CY CZ DE DK ES FI FR GI GR HU IE IT LI LU MC MT NL NO NZ PL PT SE SG SI SM TR UM VA)
9
+ self.supported_countries = %w(HK GB AU AD AR BE BR CA CH CN CO CR CY CZ DE DK ES FI FR GI GR HU IE IN IT JP LI LU MC MT MY MX NL NO NZ PA PE PL PT SE SG SI SM TR UM VA)
10
10
  self.supported_cardtypes = [:visa, :master, :american_express, :discover, :jcb, :maestro, :laser, :switch]
11
11
  self.currencies_without_fractions = %w(HUF IDR ISK JPY KRW)
12
12
  self.currencies_with_three_decimal_places = %w(BHD KWD OMR RSD TND)
@@ -55,7 +55,7 @@ module ActiveMerchant #:nodoc:
55
55
 
56
56
  def void(authorization, options = {})
57
57
  MultiResponse.run do |r|
58
- r.process{inquire_request(authorization, options, "AUTHORISED")}
58
+ r.process{inquire_request(authorization, options, "AUTHORISED")} unless options[:authorization_validated]
59
59
  r.process{cancel_request(authorization, options)}
60
60
  end
61
61
  end
@@ -83,7 +83,7 @@ module ActiveMerchant #:nodoc:
83
83
  def verify(credit_card, options={})
84
84
  MultiResponse.run(:use_first_response) do |r|
85
85
  r.process { authorize(100, credit_card, options) }
86
- r.process(:ignore_result) { void(r.authorization, options) }
86
+ r.process(:ignore_result) { void(r.authorization, options.merge(:authorization_validated => true)) }
87
87
  end
88
88
  end
89
89
 
@@ -101,27 +101,27 @@ module ActiveMerchant #:nodoc:
101
101
  private
102
102
 
103
103
  def authorize_request(money, payment_method, options)
104
- commit('authorize', build_authorization_request(money, payment_method, options), "AUTHORISED")
104
+ commit('authorize', build_authorization_request(money, payment_method, options), "AUTHORISED", options)
105
105
  end
106
106
 
107
107
  def capture_request(money, authorization, options)
108
- commit('capture', build_capture_request(money, authorization, options), :ok)
108
+ commit('capture', build_capture_request(money, authorization, options), :ok, options)
109
109
  end
110
110
 
111
111
  def cancel_request(authorization, options)
112
- commit('cancel', build_void_request(authorization, options), :ok)
112
+ commit('cancel', build_void_request(authorization, options), :ok, options)
113
113
  end
114
114
 
115
115
  def inquire_request(authorization, options, *success_criteria)
116
- commit('inquiry', build_order_inquiry_request(authorization, options), *success_criteria)
116
+ commit('inquiry', build_order_inquiry_request(authorization, options), *success_criteria, options)
117
117
  end
118
118
 
119
119
  def refund_request(money, authorization, options)
120
- commit('refund', build_refund_request(money, authorization, options), :ok)
120
+ commit('refund', build_refund_request(money, authorization, options), :ok, options)
121
121
  end
122
122
 
123
123
  def credit_request(money, payment_method, options)
124
- commit('credit', build_authorization_request(money, payment_method, options), :ok)
124
+ commit('credit', build_authorization_request(money, payment_method, options), :ok, options)
125
125
  end
126
126
 
127
127
  def build_request
@@ -252,9 +252,13 @@ module ActiveMerchant #:nodoc:
252
252
  end
253
253
 
254
254
  def add_email(xml, options)
255
- return unless options[:email]
255
+ return unless options[:execute_threed] || options[:email]
256
256
  xml.tag! 'shopper' do
257
- xml.tag! 'shopperEmailAddress', options[:email]
257
+ xml.tag! 'shopperEmailAddress', options[:email] if options[:email]
258
+ xml.tag! 'browser' do
259
+ xml.tag! 'acceptHeader', options[:accept_header]
260
+ xml.tag! 'userAgentHeader', options[:user_agent]
261
+ end
258
262
  end
259
263
  end
260
264
 
@@ -321,9 +325,24 @@ module ActiveMerchant #:nodoc:
321
325
  raw
322
326
  end
323
327
 
324
- def commit(action, request, *success_criteria)
325
- xmr = ssl_post(url, request, 'Content-Type' => 'text/xml', 'Authorization' => encoded_credentials)
326
- raw = parse(action, xmr)
328
+ def headers(options)
329
+ headers = {
330
+ 'Content-Type' => 'text/xml',
331
+ 'Authorization' => encoded_credentials
332
+ }
333
+ if options[:cookie]
334
+ headers.merge!('Set-Cookie' => options[:cookie]) if options[:cookie]
335
+ end
336
+ headers
337
+ end
338
+
339
+ def commit(action, request, *success_criteria, options)
340
+ xml = ssl_post(url, request, headers(options))
341
+ raw = parse(action, xml)
342
+ if options[:execute_threed]
343
+ raw[:cookie] = @cookie
344
+ raw[:session_id] = options[:session_id]
345
+ end
327
346
  success, message = success_and_message_from(raw, success_criteria)
328
347
 
329
348
  Response.new(
@@ -346,6 +365,18 @@ module ActiveMerchant #:nodoc:
346
365
  test? ? self.test_url : self.live_url
347
366
  end
348
367
 
368
+ # Override the regular handle response so we can access the headers
369
+ # Set-Cookie value is needed for 3DS transactions
370
+ def handle_response(response)
371
+ case response.code.to_i
372
+ when 200...300
373
+ @cookie = response.response['Set-Cookie']
374
+ response.body
375
+ else
376
+ raise ResponseError.new(response)
377
+ end
378
+ end
379
+
349
380
  # success_criteria can be:
350
381
  # - a string or an array of strings (if one of many responses)
351
382
  # - An array of strings if one of many responses could be considered a
@@ -5,6 +5,7 @@ require 'benchmark'
5
5
 
6
6
  module ActiveMerchant
7
7
  class Connection
8
+ using NetHttpSslConnection
8
9
  include NetworkConnectionRetries
9
10
 
10
11
  MAX_RETRIES = 3
@@ -21,6 +22,11 @@ module ActiveMerchant
21
22
  attr_accessor :read_timeout
22
23
  attr_accessor :verify_peer
23
24
  attr_accessor :ssl_version
25
+ if Net::HTTP.instance_methods.include?(:min_version=)
26
+ attr_accessor :min_version
27
+ attr_accessor :max_version
28
+ end
29
+ attr_reader :ssl_connection
24
30
  attr_accessor :ca_file
25
31
  attr_accessor :ca_path
26
32
  attr_accessor :pem
@@ -44,7 +50,12 @@ module ActiveMerchant
44
50
  @max_retries = MAX_RETRIES
45
51
  @ignore_http_status = false
46
52
  @ssl_version = nil
47
- @proxy_address = nil
53
+ if Net::HTTP.instance_methods.include?(:min_version=)
54
+ @min_version = nil
55
+ @max_version = nil
56
+ end
57
+ @ssl_connection = {}
58
+ @proxy_address = :ENV
48
59
  @proxy_port = nil
49
60
  end
50
61
 
@@ -63,6 +74,10 @@ module ActiveMerchant
63
74
  result = nil
64
75
 
65
76
  realtime = Benchmark.realtime do
77
+ http.start unless http.started?
78
+ @ssl_connection = http.ssl_connection
79
+ info "connection_ssl_version=#{ssl_connection[:version]} connection_ssl_cipher=#{ssl_connection[:cipher]}", tag
80
+
66
81
  result = case method
67
82
  when :get
68
83
  raise ArgumentError, "GET requests do not support a request body" if body
@@ -80,8 +95,14 @@ module ActiveMerchant
80
95
  # It's kind of ambiguous whether the RFC allows bodies
81
96
  # for DELETE requests. But Net::HTTP's delete method
82
97
  # very unambiguously does not.
83
- raise ArgumentError, "DELETE requests do not support a request body" if body
84
- http.delete(endpoint.request_uri, headers)
98
+ if body
99
+ debug body
100
+ req = Net::HTTP::Delete.new(endpoint.request_uri, headers)
101
+ req.body = body
102
+ http.request(req)
103
+ else
104
+ http.delete(endpoint.request_uri, headers)
105
+ end
85
106
  else
86
107
  raise ArgumentError, "Unsupported request method #{method.to_s.upcase}"
87
108
  end
@@ -95,16 +116,20 @@ module ActiveMerchant
95
116
 
96
117
  ensure
97
118
  info "connection_request_total_time=%.4fs" % [Process.clock_gettime(Process::CLOCK_MONOTONIC) - request_start], tag
119
+ http.finish if http.started?
98
120
  end
99
121
 
100
122
  private
123
+
101
124
  def http
102
- http = Net::HTTP.new(endpoint.host, endpoint.port, proxy_address, proxy_port)
103
- configure_debugging(http)
104
- configure_timeouts(http)
105
- configure_ssl(http)
106
- configure_cert(http)
107
- http
125
+ @http ||= begin
126
+ http = Net::HTTP.new(endpoint.host, endpoint.port, proxy_address, proxy_port)
127
+ configure_debugging(http)
128
+ configure_timeouts(http)
129
+ configure_ssl(http)
130
+ configure_cert(http)
131
+ http
132
+ end
108
133
  end
109
134
 
110
135
  def configure_debugging(http)
@@ -121,6 +146,10 @@ module ActiveMerchant
121
146
 
122
147
  http.use_ssl = true
123
148
  http.ssl_version = ssl_version if ssl_version
149
+ if http.respond_to?(:min_version=)
150
+ http.min_version = min_version if min_version
151
+ http.max_version = max_version if max_version
152
+ end
124
153
 
125
154
  if verify_peer
126
155
  http.verify_mode = OpenSSL::SSL::VERIFY_PEER