savon_with_adapter 2.4.1

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 (87) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +14 -0
  3. data/.travis.yml +11 -0
  4. data/.yardopts +6 -0
  5. data/CHANGELOG.md +1042 -0
  6. data/CONTRIBUTING.md +46 -0
  7. data/Gemfile +18 -0
  8. data/LICENSE +20 -0
  9. data/README.md +81 -0
  10. data/Rakefile +14 -0
  11. data/donate.png +0 -0
  12. data/lib/savon.rb +27 -0
  13. data/lib/savon/block_interface.rb +26 -0
  14. data/lib/savon/builder.rb +166 -0
  15. data/lib/savon/client.rb +89 -0
  16. data/lib/savon/core_ext/string.rb +29 -0
  17. data/lib/savon/header.rb +70 -0
  18. data/lib/savon/http_error.rb +27 -0
  19. data/lib/savon/log_message.rb +48 -0
  20. data/lib/savon/message.rb +35 -0
  21. data/lib/savon/mock.rb +5 -0
  22. data/lib/savon/mock/expectation.rb +71 -0
  23. data/lib/savon/mock/spec_helper.rb +62 -0
  24. data/lib/savon/model.rb +80 -0
  25. data/lib/savon/operation.rb +127 -0
  26. data/lib/savon/options.rb +336 -0
  27. data/lib/savon/qualified_message.rb +49 -0
  28. data/lib/savon/request.rb +89 -0
  29. data/lib/savon/request_logger.rb +48 -0
  30. data/lib/savon/response.rb +112 -0
  31. data/lib/savon/soap_fault.rb +48 -0
  32. data/lib/savon/version.rb +3 -0
  33. data/savon.gemspec +52 -0
  34. data/spec/fixtures/gzip/message.gz +0 -0
  35. data/spec/fixtures/response/another_soap_fault.xml +14 -0
  36. data/spec/fixtures/response/authentication.xml +14 -0
  37. data/spec/fixtures/response/header.xml +13 -0
  38. data/spec/fixtures/response/list.xml +18 -0
  39. data/spec/fixtures/response/multi_ref.xml +39 -0
  40. data/spec/fixtures/response/soap_fault.xml +8 -0
  41. data/spec/fixtures/response/soap_fault12.xml +18 -0
  42. data/spec/fixtures/response/taxcloud.xml +1 -0
  43. data/spec/fixtures/ssl/client_cert.pem +16 -0
  44. data/spec/fixtures/ssl/client_encrypted_key.pem +30 -0
  45. data/spec/fixtures/ssl/client_encrypted_key_cert.pem +24 -0
  46. data/spec/fixtures/ssl/client_key.pem +15 -0
  47. data/spec/fixtures/wsdl/authentication.xml +63 -0
  48. data/spec/fixtures/wsdl/betfair.xml +2981 -0
  49. data/spec/fixtures/wsdl/edialog.xml +15416 -0
  50. data/spec/fixtures/wsdl/interhome.xml +2137 -0
  51. data/spec/fixtures/wsdl/lower_camel.xml +52 -0
  52. data/spec/fixtures/wsdl/multiple_namespaces.xml +92 -0
  53. data/spec/fixtures/wsdl/multiple_types.xml +60 -0
  54. data/spec/fixtures/wsdl/taxcloud.xml +934 -0
  55. data/spec/fixtures/wsdl/team_software.xml +1 -0
  56. data/spec/fixtures/wsdl/vies.xml +176 -0
  57. data/spec/fixtures/wsdl/wasmuth.xml +153 -0
  58. data/spec/integration/centra_spec.rb +72 -0
  59. data/spec/integration/email_example_spec.rb +32 -0
  60. data/spec/integration/random_quote_spec.rb +23 -0
  61. data/spec/integration/ratp_example_spec.rb +28 -0
  62. data/spec/integration/stockquote_example_spec.rb +28 -0
  63. data/spec/integration/support/application.rb +82 -0
  64. data/spec/integration/support/server.rb +84 -0
  65. data/spec/integration/temperature_example_spec.rb +46 -0
  66. data/spec/integration/zipcode_example_spec.rb +42 -0
  67. data/spec/savon/builder_spec.rb +86 -0
  68. data/spec/savon/client_spec.rb +198 -0
  69. data/spec/savon/core_ext/string_spec.rb +37 -0
  70. data/spec/savon/features/message_tag_spec.rb +61 -0
  71. data/spec/savon/http_error_spec.rb +49 -0
  72. data/spec/savon/log_message_spec.rb +33 -0
  73. data/spec/savon/message_spec.rb +40 -0
  74. data/spec/savon/mock_spec.rb +157 -0
  75. data/spec/savon/model_spec.rb +154 -0
  76. data/spec/savon/observers_spec.rb +92 -0
  77. data/spec/savon/operation_spec.rb +211 -0
  78. data/spec/savon/options_spec.rb +772 -0
  79. data/spec/savon/request_spec.rb +493 -0
  80. data/spec/savon/response_spec.rb +258 -0
  81. data/spec/savon/soap_fault_spec.rb +126 -0
  82. data/spec/spec_helper.rb +30 -0
  83. data/spec/support/endpoint.rb +25 -0
  84. data/spec/support/fixture.rb +39 -0
  85. data/spec/support/integration.rb +9 -0
  86. data/spec/support/stdout.rb +25 -0
  87. metadata +310 -0
@@ -0,0 +1,336 @@
1
+ require "logger"
2
+ require "httpi"
3
+
4
+ module Savon
5
+ class Options
6
+
7
+ def initialize(options = {})
8
+ @options = {}
9
+ assign options
10
+ end
11
+
12
+ attr_reader :option_type
13
+
14
+ def [](option)
15
+ @options[option]
16
+ end
17
+
18
+ def []=(option, value)
19
+ value = [value].flatten
20
+ self.send(option, *value)
21
+ end
22
+
23
+ def include?(option)
24
+ @options.key? option
25
+ end
26
+
27
+ private
28
+
29
+ def assign(options)
30
+ options.each do |option, value|
31
+ self.send(option, value)
32
+ end
33
+ end
34
+
35
+ def method_missing(option, _)
36
+ raise UnknownOptionError, "Unknown #{option_type} option: #{option.inspect}"
37
+ end
38
+
39
+ end
40
+
41
+ class GlobalOptions < Options
42
+
43
+ def initialize(options = {})
44
+ @option_type = :global
45
+
46
+ defaults = {
47
+ :encoding => "UTF-8",
48
+ :soap_version => 1,
49
+ :namespaces => {},
50
+ :logger => Logger.new($stdout),
51
+ :log => false,
52
+ :filters => [],
53
+ :pretty_print_xml => false,
54
+ :raise_errors => true,
55
+ :strip_namespaces => true,
56
+ :convert_response_tags_to => lambda { |tag| tag.snakecase.to_sym},
57
+ :multipart => false,
58
+ :adapter => nil,
59
+ }
60
+
61
+ options = defaults.merge(options)
62
+
63
+ # this option is a shortcut on the logger which needs to be set
64
+ # before it can be modified to set the option.
65
+ delayed_level = options.delete(:log_level)
66
+
67
+ super(options)
68
+
69
+ log_level(delayed_level) unless delayed_level.nil?
70
+ end
71
+
72
+ # Location of the local or remote WSDL document.
73
+ def wsdl(wsdl_address)
74
+ @options[:wsdl] = wsdl_address
75
+ end
76
+
77
+ # SOAP endpoint.
78
+ def endpoint(endpoint)
79
+ @options[:endpoint] = endpoint
80
+ end
81
+
82
+ # Target namespace.
83
+ def namespace(namespace)
84
+ @options[:namespace] = namespace
85
+ end
86
+
87
+ # The namespace identifer.
88
+ def namespace_identifier(identifier)
89
+ @options[:namespace_identifier] = identifier
90
+ end
91
+
92
+ # Namespaces for the SOAP envelope.
93
+ def namespaces(namespaces)
94
+ @options[:namespaces] = namespaces
95
+ end
96
+
97
+ # Proxy server to use for all requests.
98
+ def proxy(proxy)
99
+ @options[:proxy] = proxy
100
+ end
101
+
102
+ # A Hash of HTTP headers.
103
+ def headers(headers)
104
+ @options[:headers] = headers
105
+ end
106
+
107
+ # Open timeout in seconds.
108
+ def open_timeout(open_timeout)
109
+ @options[:open_timeout] = open_timeout
110
+ end
111
+
112
+ # Read timeout in seconds.
113
+ def read_timeout(read_timeout)
114
+ @options[:read_timeout] = read_timeout
115
+ end
116
+
117
+ # The encoding to use. Defaults to "UTF-8".
118
+ def encoding(encoding)
119
+ @options[:encoding] = encoding
120
+ end
121
+
122
+ # The global SOAP header. Expected to be a Hash or responding to #to_s.
123
+ def soap_header(header)
124
+ @options[:soap_header] = header
125
+ end
126
+
127
+ # Sets whether elements should be :qualified or unqualified.
128
+ # If you need to use this option, please open an issue and make
129
+ # sure to add your WSDL document for debugging.
130
+ def element_form_default(element_form_default)
131
+ @options[:element_form_default] = element_form_default
132
+ end
133
+
134
+ # Can be used to change the SOAP envelope namespace identifier.
135
+ # If you need to use this option, please open an issue and make
136
+ # sure to add your WSDL document for debugging.
137
+ def env_namespace(env_namespace)
138
+ @options[:env_namespace] = env_namespace
139
+ end
140
+
141
+ # Changes the SOAP version to 1 or 2.
142
+ def soap_version(soap_version)
143
+ @options[:soap_version] = soap_version
144
+ end
145
+
146
+ # Whether or not to raise SOAP fault and HTTP errors.
147
+ def raise_errors(raise_errors)
148
+ @options[:raise_errors] = raise_errors
149
+ end
150
+
151
+ # Whether or not to log.
152
+ def log(log)
153
+ HTTPI.log = log
154
+ @options[:log] = log
155
+ end
156
+
157
+ # The logger to use. Defaults to a Savon::Logger instance.
158
+ def logger(logger)
159
+ @options[:logger] = logger
160
+ end
161
+
162
+ # Changes the Logger's log level.
163
+ def log_level(level)
164
+ levels = { :debug => 0, :info => 1, :warn => 2, :error => 3, :fatal => 4 }
165
+
166
+ unless levels.include? level
167
+ raise ArgumentError, "Invalid log level: #{level.inspect}\n" \
168
+ "Expected one of: #{levels.keys.inspect}"
169
+ end
170
+
171
+ @options[:logger].level = levels[level]
172
+ end
173
+
174
+ # A list of XML tags to filter from logged SOAP messages.
175
+ def filters(*filters)
176
+ @options[:filters] = filters.flatten
177
+ end
178
+
179
+ # Whether to pretty print request and response XML log messages.
180
+ def pretty_print_xml(pretty_print_xml)
181
+ @options[:pretty_print_xml] = pretty_print_xml
182
+ end
183
+
184
+ # Specifies the SSL version to use.
185
+ def ssl_version(version)
186
+ @options[:ssl_version] = version
187
+ end
188
+
189
+ # Whether and how to to verify the connection.
190
+ def ssl_verify_mode(verify_mode)
191
+ @options[:ssl_verify_mode] = verify_mode
192
+ end
193
+
194
+ # Sets the cert key file to use.
195
+ def ssl_cert_key_file(file)
196
+ @options[:ssl_cert_key_file] = file
197
+ end
198
+
199
+ # Sets the cert key password to use.
200
+ def ssl_cert_key_password(password)
201
+ @options[:ssl_cert_key_password] = password
202
+ end
203
+
204
+ # Sets the cert file to use.
205
+ def ssl_cert_file(file)
206
+ @options[:ssl_cert_file] = file
207
+ end
208
+
209
+ # Sets the ca cert file to use.
210
+ def ssl_ca_cert_file(file)
211
+ @options[:ssl_ca_cert_file] = file
212
+ end
213
+
214
+ # HTTP basic auth credentials.
215
+ def basic_auth(*credentials)
216
+ @options[:basic_auth] = credentials.flatten
217
+ end
218
+
219
+ # HTTP digest auth credentials.
220
+ def digest_auth(*credentials)
221
+ @options[:digest_auth] = credentials.flatten
222
+ end
223
+
224
+ # NTLM auth credentials.
225
+ def ntlm(*credentials)
226
+ @options[:ntlm] = credentials.flatten
227
+ end
228
+
229
+ # WSSE auth credentials for Akami.
230
+ def wsse_auth(*credentials)
231
+ @options[:wsse_auth] = credentials.flatten
232
+ end
233
+
234
+ # Instruct Akami to enable wsu:Timestamp headers.
235
+ def wsse_timestamp(*timestamp)
236
+ @options[:wsse_timestamp] = timestamp.flatten
237
+ end
238
+
239
+ # Instruct Nori whether to strip namespaces from XML nodes.
240
+ def strip_namespaces(strip_namespaces)
241
+ @options[:strip_namespaces] = strip_namespaces
242
+ end
243
+
244
+ # Tell Gyoku how to convert Hash key Symbols to XML tags.
245
+ # Accepts one of :lower_camelcase, :camelcase, :upcase, or :none.
246
+ def convert_request_keys_to(converter)
247
+ @options[:convert_request_keys_to] = converter
248
+ end
249
+
250
+ # Tell Nori how to convert XML tags from the SOAP response into Hash keys.
251
+ # Accepts a lambda or a block which receives an XML tag and returns a Hash key.
252
+ # Defaults to convert tags to snakecase Symbols.
253
+ def convert_response_tags_to(converter = nil, &block)
254
+ @options[:convert_response_tags_to] = block || converter
255
+ end
256
+
257
+ # Instruct Savon to create a multipart response if available.
258
+ def multipart(multipart)
259
+ @options[:multipart] = multipart
260
+ end
261
+
262
+ # Instruct Savon what HTTPI adapter it should use instead of default
263
+ def adapter(adapter)
264
+ @options[:adapter] = adapter
265
+ end
266
+ end
267
+
268
+ class LocalOptions < Options
269
+
270
+ def initialize(options = {})
271
+ @option_type = :local
272
+
273
+ defaults = {
274
+ :advanced_typecasting => true,
275
+ :response_parser => :nokogiri,
276
+ :multipart => false
277
+ }
278
+
279
+ super defaults.merge(options)
280
+ end
281
+
282
+ # The local SOAP header. Expected to be a Hash or respond to #to_s.
283
+ # Will be merged with the global SOAP header if both are Hashes.
284
+ # Otherwise the local option will be prefered.
285
+ def soap_header(header)
286
+ @options[:soap_header] = header
287
+ end
288
+
289
+ # The SOAP message to send. Expected to be a Hash or a String.
290
+ def message(message)
291
+ @options[:message] = message
292
+ end
293
+
294
+ # SOAP message tag (formerly known as SOAP input tag). If it's not set, Savon retrieves the name from
295
+ # the WSDL document (if available). Otherwise, Gyoku converts the operation name into an XML element.
296
+ def message_tag(message_tag)
297
+ @options[:message_tag] = message_tag
298
+ end
299
+
300
+ # Attributes for the SOAP message tag.
301
+ def attributes(attributes)
302
+ @options[:attributes] = attributes
303
+ end
304
+
305
+ # Value of the SOAPAction HTTP header.
306
+ def soap_action(soap_action)
307
+ @options[:soap_action] = soap_action
308
+ end
309
+
310
+ # Cookies to be used for the next request.
311
+ def cookies(cookies)
312
+ @options[:cookies] = cookies
313
+ end
314
+
315
+ # The SOAP request XML to send. Expected to be a String.
316
+ def xml(xml)
317
+ @options[:xml] = xml
318
+ end
319
+
320
+ # Instruct Nori to use advanced typecasting.
321
+ def advanced_typecasting(advanced)
322
+ @options[:advanced_typecasting] = advanced
323
+ end
324
+
325
+ # Instruct Nori to use :rexml or :nokogiri to parse the response.
326
+ def response_parser(parser)
327
+ @options[:response_parser] = parser
328
+ end
329
+
330
+ # Instruct Savon to create a multipart response if available.
331
+ def multipart(multipart)
332
+ @options[:multipart] = multipart
333
+ end
334
+
335
+ end
336
+ end
@@ -0,0 +1,49 @@
1
+ require "gyoku"
2
+
3
+ module Savon
4
+ class QualifiedMessage
5
+
6
+ def initialize(types, used_namespaces, key_converter)
7
+ @types = types
8
+ @used_namespaces = used_namespaces
9
+ @key_converter = key_converter
10
+ end
11
+
12
+ def to_hash(hash, path)
13
+ return unless hash
14
+ return hash.map { |value| to_hash(value, path) } if hash.kind_of?(Array)
15
+ return hash.to_s unless hash.kind_of? Hash
16
+
17
+ hash.inject({}) do |newhash, (key, value)|
18
+ if key == :order!
19
+ add_namespaces_to_values(value, path)
20
+ newhash.merge(key => value)
21
+ else
22
+ translated_key = Gyoku.xml_tag(key, :key_converter => @key_converter).to_s
23
+ newpath = path + [translated_key]
24
+
25
+ if @used_namespaces[newpath]
26
+ newhash.merge(
27
+ "#{@used_namespaces[newpath]}:#{translated_key}" =>
28
+ to_hash(value, @types[newpath] ? [@types[newpath]] : newpath)
29
+ )
30
+ else
31
+ newhash.merge(translated_key => value)
32
+ end
33
+ end
34
+ end
35
+ end
36
+
37
+ private
38
+
39
+ def add_namespaces_to_values(values, path)
40
+ values.collect! { |value|
41
+ camelcased_value = Gyoku.xml_tag(value, :key_converter => @key_converter)
42
+ namespace_path = path + [camelcased_value.to_s]
43
+ namespace = @used_namespaces[namespace_path]
44
+ "#{namespace.blank? ? '' : namespace + ":"}#{camelcased_value}"
45
+ }
46
+ end
47
+
48
+ end
49
+ end
@@ -0,0 +1,89 @@
1
+ require "httpi"
2
+
3
+ module Savon
4
+ class HTTPRequest
5
+
6
+ def initialize(globals, http_request = nil)
7
+ @globals = globals
8
+ @http_request = http_request || HTTPI::Request.new
9
+ end
10
+
11
+ def build
12
+ @http_request
13
+ end
14
+
15
+ private
16
+
17
+ def configure_proxy
18
+ @http_request.proxy = @globals[:proxy] if @globals.include? :proxy
19
+ end
20
+
21
+ def configure_timeouts
22
+ @http_request.open_timeout = @globals[:open_timeout] if @globals.include? :open_timeout
23
+ @http_request.read_timeout = @globals[:read_timeout] if @globals.include? :read_timeout
24
+ end
25
+
26
+ def configure_ssl
27
+ @http_request.auth.ssl.ssl_version = @globals[:ssl_version] if @globals.include? :ssl_version
28
+ @http_request.auth.ssl.verify_mode = @globals[:ssl_verify_mode] if @globals.include? :ssl_verify_mode
29
+
30
+ @http_request.auth.ssl.cert_key_file = @globals[:ssl_cert_key_file] if @globals.include? :ssl_cert_key_file
31
+ @http_request.auth.ssl.cert_file = @globals[:ssl_cert_file] if @globals.include? :ssl_cert_file
32
+ @http_request.auth.ssl.ca_cert_file = @globals[:ssl_ca_cert_file] if @globals.include? :ssl_ca_cert_file
33
+
34
+ @http_request.auth.ssl.cert_key_password = @globals[:ssl_cert_key_password] if @globals.include? :ssl_cert_key_password
35
+ end
36
+
37
+ def configure_auth
38
+ @http_request.auth.basic(*@globals[:basic_auth]) if @globals.include? :basic_auth
39
+ @http_request.auth.digest(*@globals[:digest_auth]) if @globals.include? :digest_auth
40
+ @http_request.auth.ntlm(*@globals[:ntlm]) if @globals.include? :ntlm
41
+ end
42
+
43
+ end
44
+
45
+ class WSDLRequest < HTTPRequest
46
+
47
+ def build
48
+ configure_proxy
49
+ configure_timeouts
50
+ configure_ssl
51
+ configure_auth
52
+
53
+ @http_request
54
+ end
55
+
56
+ end
57
+
58
+ class SOAPRequest < HTTPRequest
59
+
60
+ CONTENT_TYPE = {
61
+ 1 => "text/xml;charset=%s",
62
+ 2 => "application/soap+xml;charset=%s"
63
+ }
64
+
65
+ def build(options = {})
66
+ configure_proxy
67
+ configure_cookies options[:cookies]
68
+ configure_timeouts
69
+ configure_headers options[:soap_action]
70
+ configure_ssl
71
+ configure_auth
72
+
73
+ @http_request
74
+ end
75
+
76
+ private
77
+
78
+ def configure_cookies(cookies)
79
+ @http_request.set_cookies(cookies) if cookies
80
+ end
81
+
82
+ def configure_headers(soap_action)
83
+ @http_request.headers = @globals[:headers] if @globals.include? :headers
84
+ @http_request.headers["SOAPAction"] ||= %{"#{soap_action}"} if soap_action
85
+ @http_request.headers["Content-Type"] ||= CONTENT_TYPE[@globals[:soap_version]] % @globals[:encoding]
86
+ end
87
+
88
+ end
89
+ end