savon 1.2.0 → 2.0.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.
- data/CHANGELOG.md +119 -104
- data/README.md +12 -11
- data/Rakefile +0 -6
- data/lib/savon.rb +16 -14
- data/lib/savon/block_interface.rb +26 -0
- data/lib/savon/builder.rb +142 -0
- data/lib/savon/client.rb +36 -135
- data/lib/savon/header.rb +42 -0
- data/lib/savon/http_error.rb +27 -0
- data/lib/savon/log_message.rb +23 -25
- data/lib/savon/message.rb +35 -0
- data/lib/savon/mock.rb +5 -0
- data/lib/savon/mock/expectation.rb +70 -0
- data/lib/savon/mock/spec_helper.rb +62 -0
- data/lib/savon/model.rb +39 -61
- data/lib/savon/operation.rb +62 -0
- data/lib/savon/options.rb +265 -0
- data/lib/savon/qualified_message.rb +49 -0
- data/lib/savon/request.rb +92 -0
- data/lib/savon/response.rb +97 -0
- data/lib/savon/soap_fault.rb +40 -0
- data/lib/savon/version.rb +1 -1
- data/savon.gemspec +10 -8
- data/spec/integration/options_spec.rb +536 -0
- data/spec/integration/request_spec.rb +31 -16
- data/spec/integration/support/application.rb +80 -0
- data/spec/integration/support/server.rb +84 -0
- data/spec/savon/builder_spec.rb +81 -0
- data/spec/savon/client_spec.rb +90 -488
- data/spec/savon/http_error_spec.rb +49 -0
- data/spec/savon/log_message_spec.rb +33 -0
- data/spec/savon/mock_spec.rb +127 -0
- data/spec/savon/model_spec.rb +110 -99
- data/spec/savon/observers_spec.rb +92 -0
- data/spec/savon/operation_spec.rb +49 -0
- data/spec/savon/request_spec.rb +145 -0
- data/spec/savon/{soap/response_spec.rb → response_spec.rb} +22 -59
- data/spec/savon/soap_fault_spec.rb +94 -0
- data/spec/spec_helper.rb +5 -3
- data/spec/support/fixture.rb +5 -1
- metadata +202 -197
- data/lib/savon/config.rb +0 -46
- data/lib/savon/error.rb +0 -6
- data/lib/savon/hooks/group.rb +0 -68
- data/lib/savon/hooks/hook.rb +0 -61
- data/lib/savon/http/error.rb +0 -42
- data/lib/savon/logger.rb +0 -39
- data/lib/savon/null_logger.rb +0 -10
- data/lib/savon/soap.rb +0 -21
- data/lib/savon/soap/fault.rb +0 -59
- data/lib/savon/soap/invalid_response_error.rb +0 -13
- data/lib/savon/soap/request.rb +0 -86
- data/lib/savon/soap/request_builder.rb +0 -205
- data/lib/savon/soap/response.rb +0 -117
- data/lib/savon/soap/xml.rb +0 -257
- data/spec/savon/config_spec.rb +0 -38
- data/spec/savon/hooks/group_spec.rb +0 -71
- data/spec/savon/hooks/hook_spec.rb +0 -16
- data/spec/savon/http/error_spec.rb +0 -52
- data/spec/savon/logger_spec.rb +0 -51
- data/spec/savon/savon_spec.rb +0 -33
- data/spec/savon/soap/fault_spec.rb +0 -89
- data/spec/savon/soap/request_builder_spec.rb +0 -207
- data/spec/savon/soap/request_spec.rb +0 -112
- data/spec/savon/soap/xml_spec.rb +0 -357
- data/spec/savon/soap_spec.rb +0 -16
data/lib/savon/config.rb
DELETED
@@ -1,46 +0,0 @@
|
|
1
|
-
require "savon/logger"
|
2
|
-
require "savon/null_logger"
|
3
|
-
require "savon/hooks/group"
|
4
|
-
require "savon/soap"
|
5
|
-
|
6
|
-
module Savon
|
7
|
-
Config = Struct.new(:_logger, :pretty_print_xml, :raise_errors, :soap_version, :env_namespace, :soap_header) do
|
8
|
-
|
9
|
-
def self.default
|
10
|
-
config = new
|
11
|
-
config._logger = Logger.new
|
12
|
-
config.raise_errors = true
|
13
|
-
config.soap_version = SOAP::DEFAULT_VERSION
|
14
|
-
config
|
15
|
-
end
|
16
|
-
|
17
|
-
alias_method :logger, :_logger
|
18
|
-
|
19
|
-
def logger=(logger)
|
20
|
-
_logger.subject = logger
|
21
|
-
end
|
22
|
-
|
23
|
-
def log_level=(level)
|
24
|
-
_logger.level = level
|
25
|
-
end
|
26
|
-
|
27
|
-
def log=(log)
|
28
|
-
if log == true
|
29
|
-
self._logger = Logger.new
|
30
|
-
else
|
31
|
-
self._logger = NullLogger.new
|
32
|
-
end
|
33
|
-
end
|
34
|
-
|
35
|
-
def hooks
|
36
|
-
@hooks ||= Hooks::Group.new
|
37
|
-
end
|
38
|
-
|
39
|
-
def clone
|
40
|
-
config = super
|
41
|
-
config._logger = config._logger.clone
|
42
|
-
config
|
43
|
-
end
|
44
|
-
|
45
|
-
end
|
46
|
-
end
|
data/lib/savon/error.rb
DELETED
data/lib/savon/hooks/group.rb
DELETED
@@ -1,68 +0,0 @@
|
|
1
|
-
require "savon/hooks/hook"
|
2
|
-
|
3
|
-
module Savon
|
4
|
-
module Hooks
|
5
|
-
|
6
|
-
# = Savon::Hooks::Group
|
7
|
-
#
|
8
|
-
# Manages a list of hooks.
|
9
|
-
class Group
|
10
|
-
|
11
|
-
# Accepts an Array of +hooks+ to start with.
|
12
|
-
def initialize(hooks = [])
|
13
|
-
@hooks = hooks
|
14
|
-
end
|
15
|
-
|
16
|
-
# Returns whether this group contains hooks.
|
17
|
-
def empty?
|
18
|
-
hooks.empty?
|
19
|
-
end
|
20
|
-
|
21
|
-
# Returns the number of hooks in this group.
|
22
|
-
def count
|
23
|
-
hooks.count
|
24
|
-
end
|
25
|
-
|
26
|
-
# Adds a new hook.
|
27
|
-
def define(id, hook, &block)
|
28
|
-
hooks << Hook.new(id, hook, &block)
|
29
|
-
end
|
30
|
-
|
31
|
-
# Removes hooks matching the given +ids+.
|
32
|
-
def reject(*ids)
|
33
|
-
ids = ids.flatten
|
34
|
-
hooks.reject! { |hook| ids.include? hook.id }
|
35
|
-
end
|
36
|
-
|
37
|
-
# Fire a given +hook+ with any given +args+.
|
38
|
-
def fire(hook, *args, &callback)
|
39
|
-
callable = select(hook)
|
40
|
-
|
41
|
-
if callable.empty?
|
42
|
-
callback.call
|
43
|
-
else
|
44
|
-
args.unshift(callback) if callback
|
45
|
-
callable.call(*args)
|
46
|
-
end
|
47
|
-
end
|
48
|
-
|
49
|
-
# Calls the hooks with the given +args+ and returns the
|
50
|
-
# value of the last hooks.
|
51
|
-
def call(*args)
|
52
|
-
hooks.inject(nil) { |memo, hook| hook.call(*args) }
|
53
|
-
end
|
54
|
-
|
55
|
-
private
|
56
|
-
|
57
|
-
def hooks
|
58
|
-
@hooks ||= []
|
59
|
-
end
|
60
|
-
|
61
|
-
# Returns a new group for a given +hook+.
|
62
|
-
def select(hook)
|
63
|
-
Group.new hooks.select { |h| h.hook == hook }
|
64
|
-
end
|
65
|
-
|
66
|
-
end
|
67
|
-
end
|
68
|
-
end
|
data/lib/savon/hooks/hook.rb
DELETED
@@ -1,61 +0,0 @@
|
|
1
|
-
module Savon
|
2
|
-
module Hooks
|
3
|
-
|
4
|
-
# = Savon::Hooks::Hook
|
5
|
-
#
|
6
|
-
# A hook used somewhere in the system.
|
7
|
-
class Hook
|
8
|
-
|
9
|
-
HOOKS = [
|
10
|
-
|
11
|
-
# :soap_request
|
12
|
-
#
|
13
|
-
# Around filter wrapping the POST request executed to call a SOAP service.
|
14
|
-
# See: Savon::SOAP::Request#response
|
15
|
-
#
|
16
|
-
# Arguments
|
17
|
-
#
|
18
|
-
# [callback] A block to execute the SOAP request
|
19
|
-
# [request] The current <tt>Savon::SOAP::Request</tt>
|
20
|
-
#
|
21
|
-
# Examples
|
22
|
-
#
|
23
|
-
# Log the time before and after the SOAP call:
|
24
|
-
#
|
25
|
-
# Savon.config.hooks.define(:my_hook, :soap_request) do |callback, request|
|
26
|
-
# Timer.log(:start, Time.now)
|
27
|
-
# response = callback.call
|
28
|
-
# Timer.log(:end, Time.now)
|
29
|
-
# response
|
30
|
-
# end
|
31
|
-
#
|
32
|
-
# Replace the SOAP call and return a custom response:
|
33
|
-
#
|
34
|
-
# Savon.config.hooks.define(:mock_hook, :soap_request) do |_, request|
|
35
|
-
# HTTPI::Response.new(200, {}, "")
|
36
|
-
# end
|
37
|
-
:soap_request
|
38
|
-
|
39
|
-
]
|
40
|
-
|
41
|
-
# Expects an +id+, the name of the +hook+ to use and a +block+ to be called.
|
42
|
-
def initialize(id, hook, &block)
|
43
|
-
unless HOOKS.include?(hook)
|
44
|
-
raise ArgumentError, "No such hook: #{hook}. Expected one of: #{HOOKS.join(', ')}"
|
45
|
-
end
|
46
|
-
|
47
|
-
self.id = id
|
48
|
-
self.hook = hook
|
49
|
-
self.block = block
|
50
|
-
end
|
51
|
-
|
52
|
-
attr_accessor :id, :hook, :block
|
53
|
-
|
54
|
-
# Calls the +block+ with the given +args+.
|
55
|
-
def call(*args)
|
56
|
-
block.call(*args)
|
57
|
-
end
|
58
|
-
|
59
|
-
end
|
60
|
-
end
|
61
|
-
end
|
data/lib/savon/http/error.rb
DELETED
@@ -1,42 +0,0 @@
|
|
1
|
-
require "savon/error"
|
2
|
-
require "savon/soap/xml"
|
3
|
-
|
4
|
-
module Savon
|
5
|
-
module HTTP
|
6
|
-
|
7
|
-
# = Savon::HTTP::Error
|
8
|
-
#
|
9
|
-
# Represents an HTTP error. Contains the original <tt>HTTPI::Response</tt>.
|
10
|
-
class Error < Error
|
11
|
-
|
12
|
-
# Expects an <tt>HTTPI::Response</tt>.
|
13
|
-
def initialize(http)
|
14
|
-
self.http = http
|
15
|
-
end
|
16
|
-
|
17
|
-
# Accessor for the <tt>HTTPI::Response</tt>.
|
18
|
-
attr_accessor :http
|
19
|
-
|
20
|
-
# Returns whether an HTTP error is present.
|
21
|
-
def present?
|
22
|
-
http.error?
|
23
|
-
end
|
24
|
-
|
25
|
-
# Returns the HTTP error message.
|
26
|
-
def to_s
|
27
|
-
return "" unless present?
|
28
|
-
|
29
|
-
@message ||= begin
|
30
|
-
message = "HTTP error (#{http.code})"
|
31
|
-
message << ": #{http.body}" unless http.body.empty?
|
32
|
-
end
|
33
|
-
end
|
34
|
-
|
35
|
-
# Returns the HTTP response as a Hash.
|
36
|
-
def to_hash
|
37
|
-
@hash = { :code => http.code, :headers => http.headers, :body => http.body }
|
38
|
-
end
|
39
|
-
|
40
|
-
end
|
41
|
-
end
|
42
|
-
end
|
data/lib/savon/logger.rb
DELETED
@@ -1,39 +0,0 @@
|
|
1
|
-
require "logger"
|
2
|
-
require "nokogiri"
|
3
|
-
require "savon/log_message"
|
4
|
-
|
5
|
-
module Savon
|
6
|
-
class Logger
|
7
|
-
|
8
|
-
def initialize(device = $stdout)
|
9
|
-
self.device = device
|
10
|
-
end
|
11
|
-
|
12
|
-
attr_accessor :device
|
13
|
-
|
14
|
-
def log(message, options = {})
|
15
|
-
log_raw LogMessage.new(message, filter, options).to_s
|
16
|
-
end
|
17
|
-
|
18
|
-
attr_writer :subject, :level, :filter
|
19
|
-
|
20
|
-
def subject
|
21
|
-
@subject ||= ::Logger.new(device)
|
22
|
-
end
|
23
|
-
|
24
|
-
def level
|
25
|
-
@level ||= :debug
|
26
|
-
end
|
27
|
-
|
28
|
-
def filter
|
29
|
-
@filter ||= []
|
30
|
-
end
|
31
|
-
|
32
|
-
private
|
33
|
-
|
34
|
-
def log_raw(message)
|
35
|
-
subject.send(level, message)
|
36
|
-
end
|
37
|
-
|
38
|
-
end
|
39
|
-
end
|
data/lib/savon/null_logger.rb
DELETED
data/lib/savon/soap.rb
DELETED
@@ -1,21 +0,0 @@
|
|
1
|
-
module Savon
|
2
|
-
|
3
|
-
# = Savon::SOAP
|
4
|
-
#
|
5
|
-
# Contains various SOAP details.
|
6
|
-
module SOAP
|
7
|
-
|
8
|
-
# Default SOAP version.
|
9
|
-
DEFAULT_VERSION = 1
|
10
|
-
|
11
|
-
# Supported SOAP versions.
|
12
|
-
VERSIONS = 1..2
|
13
|
-
|
14
|
-
# SOAP namespaces by SOAP version.
|
15
|
-
NAMESPACE = {
|
16
|
-
1 => "http://schemas.xmlsoap.org/soap/envelope/",
|
17
|
-
2 => "http://www.w3.org/2003/05/soap-envelope"
|
18
|
-
}
|
19
|
-
|
20
|
-
end
|
21
|
-
end
|
data/lib/savon/soap/fault.rb
DELETED
@@ -1,59 +0,0 @@
|
|
1
|
-
require "savon/error"
|
2
|
-
require "savon/soap/xml"
|
3
|
-
|
4
|
-
module Savon
|
5
|
-
module SOAP
|
6
|
-
|
7
|
-
# = Savon::SOAP::Fault
|
8
|
-
#
|
9
|
-
# Represents a SOAP fault. Contains the original <tt>HTTPI::Response</tt>.
|
10
|
-
class Fault < Error
|
11
|
-
|
12
|
-
# Expects an <tt>HTTPI::Response</tt>.
|
13
|
-
def initialize(http)
|
14
|
-
self.http = http
|
15
|
-
end
|
16
|
-
|
17
|
-
# Accessor for the <tt>HTTPI::Response</tt>.
|
18
|
-
attr_accessor :http
|
19
|
-
|
20
|
-
# Returns whether a SOAP fault is present.
|
21
|
-
def present?
|
22
|
-
@present ||= http.body.include?("Fault>") && (soap1_fault? || soap2_fault?)
|
23
|
-
end
|
24
|
-
|
25
|
-
# Returns the SOAP fault message.
|
26
|
-
def to_s
|
27
|
-
return "" unless present?
|
28
|
-
@message ||= message_by_version to_hash[:fault]
|
29
|
-
end
|
30
|
-
|
31
|
-
# Returns the SOAP response body as a Hash.
|
32
|
-
def to_hash
|
33
|
-
@hash ||= Nori.parse(http.body)[:envelope][:body]
|
34
|
-
end
|
35
|
-
|
36
|
-
private
|
37
|
-
|
38
|
-
# Returns whether the response contains a SOAP 1.1 fault.
|
39
|
-
def soap1_fault?
|
40
|
-
http.body.include?("faultcode>") && http.body.include?("faultstring>")
|
41
|
-
end
|
42
|
-
|
43
|
-
# Returns whether the response contains a SOAP 1.2 fault.
|
44
|
-
def soap2_fault?
|
45
|
-
http.body.include?("Code>") && http.body.include?("Reason>")
|
46
|
-
end
|
47
|
-
|
48
|
-
# Returns the SOAP fault message by version.
|
49
|
-
def message_by_version(fault)
|
50
|
-
if fault[:faultcode]
|
51
|
-
"(#{fault[:faultcode]}) #{fault[:faultstring]}"
|
52
|
-
elsif fault[:code]
|
53
|
-
"(#{fault[:code][:value]}) #{fault[:reason][:text]}"
|
54
|
-
end
|
55
|
-
end
|
56
|
-
|
57
|
-
end
|
58
|
-
end
|
59
|
-
end
|
data/lib/savon/soap/request.rb
DELETED
@@ -1,86 +0,0 @@
|
|
1
|
-
require "httpi"
|
2
|
-
require "savon/soap/response"
|
3
|
-
|
4
|
-
module Savon
|
5
|
-
module SOAP
|
6
|
-
|
7
|
-
# = Savon::SOAP::Request
|
8
|
-
#
|
9
|
-
# Executes SOAP requests.
|
10
|
-
class Request
|
11
|
-
|
12
|
-
# Content-Types by SOAP version.
|
13
|
-
CONTENT_TYPE = { 1 => "text/xml;charset=UTF-8", 2 => "application/soap+xml;charset=UTF-8" }
|
14
|
-
|
15
|
-
# Expects an <tt>HTTPI::Request</tt> and a <tt>Savon::SOAP::XML</tt> object
|
16
|
-
# to execute a SOAP request and returns the response.
|
17
|
-
def self.execute(config, http, soap)
|
18
|
-
new(config, http, soap).response
|
19
|
-
end
|
20
|
-
|
21
|
-
# Expects an <tt>HTTPI::Request</tt>, a <tt>Savon::SOAP::XML</tt> object
|
22
|
-
# and a <tt>Savon::Config</tt>.
|
23
|
-
def initialize(config, http, soap)
|
24
|
-
self.config = config
|
25
|
-
self.soap = soap
|
26
|
-
self.http = configure(http)
|
27
|
-
end
|
28
|
-
|
29
|
-
attr_accessor :soap, :http, :config
|
30
|
-
|
31
|
-
# Executes the request and returns the response.
|
32
|
-
def response
|
33
|
-
@response ||= begin
|
34
|
-
response = config.hooks.fire(:soap_request, self) { with_logging { HTTPI.post(http) } }
|
35
|
-
SOAP::Response.new(config, response)
|
36
|
-
end
|
37
|
-
end
|
38
|
-
|
39
|
-
private
|
40
|
-
|
41
|
-
# Configures a given +http+ from the +soap+ object.
|
42
|
-
def configure(http)
|
43
|
-
http.url = soap.endpoint
|
44
|
-
|
45
|
-
if soap.signature?
|
46
|
-
# First generate the document so that Signature can digest sections
|
47
|
-
soap.wsse.signature.document = soap.to_xml(true)
|
48
|
-
|
49
|
-
# Then re-generate the document so that Signature can sign the digest
|
50
|
-
soap.wsse.signature.document = soap.to_xml(true)
|
51
|
-
|
52
|
-
# The third time we generate the document, we should have a signature
|
53
|
-
http.body = soap.to_xml(true)
|
54
|
-
else
|
55
|
-
http.body = soap.to_xml
|
56
|
-
end
|
57
|
-
|
58
|
-
http.headers["Content-Type"] = CONTENT_TYPE[soap.version]
|
59
|
-
http.headers["Content-Length"] = soap.to_xml.bytesize.to_s
|
60
|
-
http
|
61
|
-
end
|
62
|
-
|
63
|
-
# Logs the HTTP request, yields to a given +block+ and returns a <tt>Savon::SOAP::Response</tt>.
|
64
|
-
def with_logging
|
65
|
-
log_request http.url, http.headers, http.body
|
66
|
-
response = yield
|
67
|
-
log_response response.code, response.body
|
68
|
-
response
|
69
|
-
end
|
70
|
-
|
71
|
-
# Logs the SOAP request +url+, +headers+ and +body+.
|
72
|
-
def log_request(url, headers, body)
|
73
|
-
config.logger.log "SOAP request: #{url}"
|
74
|
-
config.logger.log headers.map { |key, value| "#{key}: #{value}" }.join(", ")
|
75
|
-
config.logger.log body, :pretty => config.pretty_print_xml, :filter => true
|
76
|
-
end
|
77
|
-
|
78
|
-
# Logs the SOAP response +code+ and +body+.
|
79
|
-
def log_response(code, body)
|
80
|
-
config.logger.log "SOAP response (status #{code}):"
|
81
|
-
config.logger.log body, :pretty => config.pretty_print_xml
|
82
|
-
end
|
83
|
-
|
84
|
-
end
|
85
|
-
end
|
86
|
-
end
|