s-savon 0.8.6
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/.gitignore +9 -0
 - data/.rspec +1 -0
 - data/.yardopts +2 -0
 - data/CHANGELOG.md +461 -0
 - data/Gemfile +4 -0
 - data/LICENSE +20 -0
 - data/README.md +37 -0
 - data/Rakefile +40 -0
 - data/lib/savon.rb +14 -0
 - data/lib/savon/client.rb +157 -0
 - data/lib/savon/core_ext/hash.rb +70 -0
 - data/lib/savon/core_ext/object.rb +14 -0
 - data/lib/savon/core_ext/string.rb +51 -0
 - data/lib/savon/core_ext/time.rb +14 -0
 - data/lib/savon/error.rb +6 -0
 - data/lib/savon/global.rb +75 -0
 - data/lib/savon/http/error.rb +42 -0
 - data/lib/savon/soap.rb +24 -0
 - data/lib/savon/soap/fault.rb +59 -0
 - data/lib/savon/soap/request.rb +61 -0
 - data/lib/savon/soap/response.rb +80 -0
 - data/lib/savon/soap/xml.rb +187 -0
 - data/lib/savon/version.rb +5 -0
 - data/lib/savon/wsdl/document.rb +112 -0
 - data/lib/savon/wsdl/parser.rb +102 -0
 - data/lib/savon/wsdl/request.rb +35 -0
 - data/lib/savon/wsse.rb +150 -0
 - data/savon.gemspec +29 -0
 - data/spec/fixtures/gzip/message.gz +0 -0
 - data/spec/fixtures/response/another_soap_fault.xml +14 -0
 - data/spec/fixtures/response/authentication.xml +14 -0
 - data/spec/fixtures/response/header.xml +13 -0
 - data/spec/fixtures/response/list.xml +18 -0
 - data/spec/fixtures/response/multi_ref.xml +39 -0
 - data/spec/fixtures/response/soap_fault.xml +8 -0
 - data/spec/fixtures/response/soap_fault12.xml +18 -0
 - data/spec/fixtures/wsdl/authentication.xml +63 -0
 - data/spec/fixtures/wsdl/geotrust.xml +156 -0
 - data/spec/fixtures/wsdl/namespaced_actions.xml +307 -0
 - data/spec/fixtures/wsdl/no_namespace.xml +115 -0
 - data/spec/fixtures/wsdl/two_bindings.xml +25 -0
 - data/spec/savon/client_spec.rb +346 -0
 - data/spec/savon/core_ext/hash_spec.rb +121 -0
 - data/spec/savon/core_ext/object_spec.rb +19 -0
 - data/spec/savon/core_ext/string_spec.rb +57 -0
 - data/spec/savon/core_ext/time_spec.rb +13 -0
 - data/spec/savon/http/error_spec.rb +52 -0
 - data/spec/savon/savon_spec.rb +85 -0
 - data/spec/savon/soap/fault_spec.rb +89 -0
 - data/spec/savon/soap/request_spec.rb +45 -0
 - data/spec/savon/soap/response_spec.rb +174 -0
 - data/spec/savon/soap/xml_spec.rb +335 -0
 - data/spec/savon/soap_spec.rb +21 -0
 - data/spec/savon/wsdl/document_spec.rb +132 -0
 - data/spec/savon/wsdl/parser_spec.rb +99 -0
 - data/spec/savon/wsdl/request_spec.rb +15 -0
 - data/spec/savon/wsse_spec.rb +213 -0
 - data/spec/spec_helper.rb +14 -0
 - data/spec/support/endpoint.rb +25 -0
 - data/spec/support/fixture.rb +37 -0
 - metadata +251 -0
 
| 
         @@ -0,0 +1,112 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require "rexml/document"
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            require "savon/wsdl/request"
         
     | 
| 
      
 4 
     | 
    
         
            +
            require "savon/wsdl/parser"
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
            module Savon
         
     | 
| 
      
 7 
     | 
    
         
            +
              module WSDL
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
                # = Savon::WSDL::Document
         
     | 
| 
      
 10 
     | 
    
         
            +
                #
         
     | 
| 
      
 11 
     | 
    
         
            +
                # Represents the WSDL of your service, including information like the namespace URI,
         
     | 
| 
      
 12 
     | 
    
         
            +
                # the SOAP endpoint and available SOAP actions.
         
     | 
| 
      
 13 
     | 
    
         
            +
                class Document
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
                  # Accepts an <tt>HTTPI::Request</tt> and a +document+.
         
     | 
| 
      
 16 
     | 
    
         
            +
                  def initialize(request = nil, document = nil)
         
     | 
| 
      
 17 
     | 
    
         
            +
                    self.request = request
         
     | 
| 
      
 18 
     | 
    
         
            +
                    self.document = document
         
     | 
| 
      
 19 
     | 
    
         
            +
                  end
         
     | 
| 
      
 20 
     | 
    
         
            +
             
     | 
| 
      
 21 
     | 
    
         
            +
                  # Accessor for the <tt>HTTPI::Request</tt> to use.
         
     | 
| 
      
 22 
     | 
    
         
            +
                  attr_accessor :request
         
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
      
 24 
     | 
    
         
            +
                  def present?
         
     | 
| 
      
 25 
     | 
    
         
            +
                    !!@document
         
     | 
| 
      
 26 
     | 
    
         
            +
                  end
         
     | 
| 
      
 27 
     | 
    
         
            +
             
     | 
| 
      
 28 
     | 
    
         
            +
                  # Returns the namespace URI of the WSDL.
         
     | 
| 
      
 29 
     | 
    
         
            +
                  def namespace
         
     | 
| 
      
 30 
     | 
    
         
            +
                    @namespace ||= parser.namespace
         
     | 
| 
      
 31 
     | 
    
         
            +
                  end
         
     | 
| 
      
 32 
     | 
    
         
            +
             
     | 
| 
      
 33 
     | 
    
         
            +
                  # Sets the SOAP namespace.
         
     | 
| 
      
 34 
     | 
    
         
            +
                  attr_writer :namespace
         
     | 
| 
      
 35 
     | 
    
         
            +
             
     | 
| 
      
 36 
     | 
    
         
            +
                  # Returns the SOAP endpoint.
         
     | 
| 
      
 37 
     | 
    
         
            +
                  def endpoint
         
     | 
| 
      
 38 
     | 
    
         
            +
                    @endpoint ||= parser.endpoint
         
     | 
| 
      
 39 
     | 
    
         
            +
                  end
         
     | 
| 
      
 40 
     | 
    
         
            +
             
     | 
| 
      
 41 
     | 
    
         
            +
                  # Sets the SOAP endpoint.
         
     | 
| 
      
 42 
     | 
    
         
            +
                  attr_writer :endpoint
         
     | 
| 
      
 43 
     | 
    
         
            +
             
     | 
| 
      
 44 
     | 
    
         
            +
                  # Returns an Array of available SOAP actions.
         
     | 
| 
      
 45 
     | 
    
         
            +
                  def soap_actions
         
     | 
| 
      
 46 
     | 
    
         
            +
                    @soap_actions ||= parser.operations.keys
         
     | 
| 
      
 47 
     | 
    
         
            +
                  end
         
     | 
| 
      
 48 
     | 
    
         
            +
             
     | 
| 
      
 49 
     | 
    
         
            +
                  # Returns the SOAP action for a given +key+.
         
     | 
| 
      
 50 
     | 
    
         
            +
                  def soap_action(key)
         
     | 
| 
      
 51 
     | 
    
         
            +
                    operations[key][:action] if present? && operations[key]
         
     | 
| 
      
 52 
     | 
    
         
            +
                  end
         
     | 
| 
      
 53 
     | 
    
         
            +
             
     | 
| 
      
 54 
     | 
    
         
            +
                  # Returns the SOAP input for a given +key+.
         
     | 
| 
      
 55 
     | 
    
         
            +
                  def soap_input(key)
         
     | 
| 
      
 56 
     | 
    
         
            +
                    operations[key][:input].to_sym if present? && operations[key]
         
     | 
| 
      
 57 
     | 
    
         
            +
                  end
         
     | 
| 
      
 58 
     | 
    
         
            +
             
     | 
| 
      
 59 
     | 
    
         
            +
                  # Returns a Hash of SOAP operations.
         
     | 
| 
      
 60 
     | 
    
         
            +
                  def operations
         
     | 
| 
      
 61 
     | 
    
         
            +
                    @operations ||= parser.operations
         
     | 
| 
      
 62 
     | 
    
         
            +
                  end
         
     | 
| 
      
 63 
     | 
    
         
            +
             
     | 
| 
      
 64 
     | 
    
         
            +
                  # Returns the elementFormDefault value.
         
     | 
| 
      
 65 
     | 
    
         
            +
                  def element_form_default
         
     | 
| 
      
 66 
     | 
    
         
            +
                    @element_form_default ||= parser.element_form_default
         
     | 
| 
      
 67 
     | 
    
         
            +
                  end
         
     | 
| 
      
 68 
     | 
    
         
            +
             
     | 
| 
      
 69 
     | 
    
         
            +
                  # Sets the location of the WSDL document to use. This can either be a URL
         
     | 
| 
      
 70 
     | 
    
         
            +
                  # or a path to a local file.
         
     | 
| 
      
 71 
     | 
    
         
            +
                  attr_writer :document
         
     | 
| 
      
 72 
     | 
    
         
            +
             
     | 
| 
      
 73 
     | 
    
         
            +
                  # Returns the raw WSDL document.
         
     | 
| 
      
 74 
     | 
    
         
            +
                  def document
         
     | 
| 
      
 75 
     | 
    
         
            +
                    @wsdl_document ||= begin
         
     | 
| 
      
 76 
     | 
    
         
            +
                      raise ArgumentError, "No WSDL document given" if @document.blank?
         
     | 
| 
      
 77 
     | 
    
         
            +
                      remote? ? http_request : read_file
         
     | 
| 
      
 78 
     | 
    
         
            +
                    end
         
     | 
| 
      
 79 
     | 
    
         
            +
                  end
         
     | 
| 
      
 80 
     | 
    
         
            +
             
     | 
| 
      
 81 
     | 
    
         
            +
                  alias :to_xml :document
         
     | 
| 
      
 82 
     | 
    
         
            +
             
     | 
| 
      
 83 
     | 
    
         
            +
                private
         
     | 
| 
      
 84 
     | 
    
         
            +
             
     | 
| 
      
 85 
     | 
    
         
            +
                  # Returns whether the WSDL document is located on the Web.
         
     | 
| 
      
 86 
     | 
    
         
            +
                  def remote?
         
     | 
| 
      
 87 
     | 
    
         
            +
                    @document =~ /^http/
         
     | 
| 
      
 88 
     | 
    
         
            +
                  end
         
     | 
| 
      
 89 
     | 
    
         
            +
             
     | 
| 
      
 90 
     | 
    
         
            +
                  # Executes an HTTP GET request to retrieve a remote WSDL document.
         
     | 
| 
      
 91 
     | 
    
         
            +
                  def http_request
         
     | 
| 
      
 92 
     | 
    
         
            +
                    request.url = @document
         
     | 
| 
      
 93 
     | 
    
         
            +
                    Request.new(request).response.body
         
     | 
| 
      
 94 
     | 
    
         
            +
                  end
         
     | 
| 
      
 95 
     | 
    
         
            +
             
     | 
| 
      
 96 
     | 
    
         
            +
                  # Reads the WSDL document from a local file.
         
     | 
| 
      
 97 
     | 
    
         
            +
                  def read_file
         
     | 
| 
      
 98 
     | 
    
         
            +
                    File.read @document
         
     | 
| 
      
 99 
     | 
    
         
            +
                  end
         
     | 
| 
      
 100 
     | 
    
         
            +
             
     | 
| 
      
 101 
     | 
    
         
            +
                  # Parses the WSDL document and returns the <tt>Savon::WSDL::Parser</tt>.
         
     | 
| 
      
 102 
     | 
    
         
            +
                  def parser
         
     | 
| 
      
 103 
     | 
    
         
            +
                    @parser ||= begin
         
     | 
| 
      
 104 
     | 
    
         
            +
                      parser = Parser.new
         
     | 
| 
      
 105 
     | 
    
         
            +
                      REXML::Document.parse_stream document, parser
         
     | 
| 
      
 106 
     | 
    
         
            +
                      parser
         
     | 
| 
      
 107 
     | 
    
         
            +
                    end
         
     | 
| 
      
 108 
     | 
    
         
            +
                  end
         
     | 
| 
      
 109 
     | 
    
         
            +
             
     | 
| 
      
 110 
     | 
    
         
            +
                end
         
     | 
| 
      
 111 
     | 
    
         
            +
              end
         
     | 
| 
      
 112 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,102 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require "savon/core_ext/object"
         
     | 
| 
      
 2 
     | 
    
         
            +
            require "savon/core_ext/string"
         
     | 
| 
      
 3 
     | 
    
         
            +
             
     | 
| 
      
 4 
     | 
    
         
            +
            module Savon
         
     | 
| 
      
 5 
     | 
    
         
            +
              module WSDL
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
                # = Savon::WSDL::Parser
         
     | 
| 
      
 8 
     | 
    
         
            +
                #
         
     | 
| 
      
 9 
     | 
    
         
            +
                # Serves as a stream listener for parsing WSDL documents.
         
     | 
| 
      
 10 
     | 
    
         
            +
                class Parser
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
                  # The main sections of a WSDL document.
         
     | 
| 
      
 13 
     | 
    
         
            +
                  Sections = %w(definitions types message portType binding service)
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
                  def initialize
         
     | 
| 
      
 16 
     | 
    
         
            +
                    @path = []
         
     | 
| 
      
 17 
     | 
    
         
            +
                    @operations = {}
         
     | 
| 
      
 18 
     | 
    
         
            +
                    @namespaces = {}
         
     | 
| 
      
 19 
     | 
    
         
            +
                    @element_form_default = :unqualified
         
     | 
| 
      
 20 
     | 
    
         
            +
                  end
         
     | 
| 
      
 21 
     | 
    
         
            +
             
     | 
| 
      
 22 
     | 
    
         
            +
                  # Returns the namespace URI.
         
     | 
| 
      
 23 
     | 
    
         
            +
                  attr_reader :namespace
         
     | 
| 
      
 24 
     | 
    
         
            +
             
     | 
| 
      
 25 
     | 
    
         
            +
                  # Returns the SOAP operations.
         
     | 
| 
      
 26 
     | 
    
         
            +
                  attr_reader :operations
         
     | 
| 
      
 27 
     | 
    
         
            +
             
     | 
| 
      
 28 
     | 
    
         
            +
                  # Returns the SOAP endpoint.
         
     | 
| 
      
 29 
     | 
    
         
            +
                  attr_reader :endpoint
         
     | 
| 
      
 30 
     | 
    
         
            +
             
     | 
| 
      
 31 
     | 
    
         
            +
                  # Returns the elementFormDefault value.
         
     | 
| 
      
 32 
     | 
    
         
            +
                  attr_reader :element_form_default
         
     | 
| 
      
 33 
     | 
    
         
            +
             
     | 
| 
      
 34 
     | 
    
         
            +
                  # Hook method called when the stream parser encounters a starting tag.
         
     | 
| 
      
 35 
     | 
    
         
            +
                  def tag_start(tag, attrs)
         
     | 
| 
      
 36 
     | 
    
         
            +
                    # read xml namespaces if root element
         
     | 
| 
      
 37 
     | 
    
         
            +
                    read_namespaces(attrs) if @path.empty?
         
     | 
| 
      
 38 
     | 
    
         
            +
             
     | 
| 
      
 39 
     | 
    
         
            +
                    tag, namespace = tag.split(":").reverse
         
     | 
| 
      
 40 
     | 
    
         
            +
                    @path << tag
         
     | 
| 
      
 41 
     | 
    
         
            +
             
     | 
| 
      
 42 
     | 
    
         
            +
                    if @section == :types && tag == "schema"
         
     | 
| 
      
 43 
     | 
    
         
            +
                      @element_form_default = attrs["elementFormDefault"].to_sym if attrs["elementFormDefault"]
         
     | 
| 
      
 44 
     | 
    
         
            +
                    end
         
     | 
| 
      
 45 
     | 
    
         
            +
             
     | 
| 
      
 46 
     | 
    
         
            +
                    if @section == :binding && tag == "binding"
         
     | 
| 
      
 47 
     | 
    
         
            +
                      # ensure that we are in an wsdl/soap namespace
         
     | 
| 
      
 48 
     | 
    
         
            +
                      @section = nil unless @namespaces[namespace].starts_with? "http://schemas.xmlsoap.org/wsdl/soap"
         
     | 
| 
      
 49 
     | 
    
         
            +
                    end
         
     | 
| 
      
 50 
     | 
    
         
            +
             
     | 
| 
      
 51 
     | 
    
         
            +
                    @section = tag.to_sym if Sections.include?(tag) && depth <= 2
         
     | 
| 
      
 52 
     | 
    
         
            +
             
     | 
| 
      
 53 
     | 
    
         
            +
                    @namespace ||= attrs["targetNamespace"] if @section == :definitions
         
     | 
| 
      
 54 
     | 
    
         
            +
                    @endpoint ||= URI(URI.escape(attrs["location"])) if @section == :service && tag == "address"
         
     | 
| 
      
 55 
     | 
    
         
            +
             
     | 
| 
      
 56 
     | 
    
         
            +
                    operation_from tag, attrs if @section == :binding && tag == "operation"
         
     | 
| 
      
 57 
     | 
    
         
            +
                  end
         
     | 
| 
      
 58 
     | 
    
         
            +
             
     | 
| 
      
 59 
     | 
    
         
            +
                  # Returns our current depth in the WSDL document.
         
     | 
| 
      
 60 
     | 
    
         
            +
                  def depth
         
     | 
| 
      
 61 
     | 
    
         
            +
                    @path.size
         
     | 
| 
      
 62 
     | 
    
         
            +
                  end
         
     | 
| 
      
 63 
     | 
    
         
            +
             
     | 
| 
      
 64 
     | 
    
         
            +
                  # Reads namespace definitions from a given +attrs+ Hash.
         
     | 
| 
      
 65 
     | 
    
         
            +
                  def read_namespaces(attrs)
         
     | 
| 
      
 66 
     | 
    
         
            +
                    attrs.each do |key, value|
         
     | 
| 
      
 67 
     | 
    
         
            +
                      @namespaces[key.strip_namespace] = value if key.starts_with? "xmlns:"
         
     | 
| 
      
 68 
     | 
    
         
            +
                    end
         
     | 
| 
      
 69 
     | 
    
         
            +
                  end
         
     | 
| 
      
 70 
     | 
    
         
            +
             
     | 
| 
      
 71 
     | 
    
         
            +
                  # Hook method called when the stream parser encounters a closing tag.
         
     | 
| 
      
 72 
     | 
    
         
            +
                  def tag_end(tag)
         
     | 
| 
      
 73 
     | 
    
         
            +
                    @path.pop
         
     | 
| 
      
 74 
     | 
    
         
            +
             
     | 
| 
      
 75 
     | 
    
         
            +
                    if @section == :binding && @input && tag.strip_namespace == "operation"
         
     | 
| 
      
 76 
     | 
    
         
            +
                      # no soapAction attribute found till now
         
     | 
| 
      
 77 
     | 
    
         
            +
                      operation_from tag, "soapAction" => @input
         
     | 
| 
      
 78 
     | 
    
         
            +
                    end
         
     | 
| 
      
 79 
     | 
    
         
            +
             
     | 
| 
      
 80 
     | 
    
         
            +
                    @section = :definitions if Sections.include?(tag) && depth <= 1
         
     | 
| 
      
 81 
     | 
    
         
            +
                  end
         
     | 
| 
      
 82 
     | 
    
         
            +
             
     | 
| 
      
 83 
     | 
    
         
            +
                  # Stores available operations from a given tag +name+ and +attrs+.
         
     | 
| 
      
 84 
     | 
    
         
            +
                  def operation_from(tag, attrs)
         
     | 
| 
      
 85 
     | 
    
         
            +
                    @input = attrs["name"] if attrs["name"]
         
     | 
| 
      
 86 
     | 
    
         
            +
             
     | 
| 
      
 87 
     | 
    
         
            +
                    if attrs["soapAction"]
         
     | 
| 
      
 88 
     | 
    
         
            +
                      @action = !attrs["soapAction"].blank? ? attrs["soapAction"] : @input
         
     | 
| 
      
 89 
     | 
    
         
            +
                      @input = @action.split("/").last if !@input || @input.empty?
         
     | 
| 
      
 90 
     | 
    
         
            +
             
     | 
| 
      
 91 
     | 
    
         
            +
                      @operations[@input.snakecase.to_sym] = { :action => @action, :input => @input }
         
     | 
| 
      
 92 
     | 
    
         
            +
                      @input, @action = nil, nil
         
     | 
| 
      
 93 
     | 
    
         
            +
                    end
         
     | 
| 
      
 94 
     | 
    
         
            +
                  end
         
     | 
| 
      
 95 
     | 
    
         
            +
             
     | 
| 
      
 96 
     | 
    
         
            +
                  # Catches calls to unimplemented hook methods.
         
     | 
| 
      
 97 
     | 
    
         
            +
                  def method_missing(method, *args)
         
     | 
| 
      
 98 
     | 
    
         
            +
                  end
         
     | 
| 
      
 99 
     | 
    
         
            +
             
     | 
| 
      
 100 
     | 
    
         
            +
                end
         
     | 
| 
      
 101 
     | 
    
         
            +
              end
         
     | 
| 
      
 102 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,35 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require "httpi"
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module Savon
         
     | 
| 
      
 4 
     | 
    
         
            +
              module WSDL
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
                # = Savon::WSDL::Request
         
     | 
| 
      
 7 
     | 
    
         
            +
                #
         
     | 
| 
      
 8 
     | 
    
         
            +
                # Executes WSDL requests.
         
     | 
| 
      
 9 
     | 
    
         
            +
                class Request
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
                  # Expects an <tt>HTTPI::Request</tt>.
         
     | 
| 
      
 12 
     | 
    
         
            +
                  def initialize(request)
         
     | 
| 
      
 13 
     | 
    
         
            +
                    self.request = request
         
     | 
| 
      
 14 
     | 
    
         
            +
                  end
         
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
      
 16 
     | 
    
         
            +
                  # Accessor for the <tt>HTTPI::Request</tt>.
         
     | 
| 
      
 17 
     | 
    
         
            +
                  attr_accessor :request
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
                  # Executes the request and returns the response.
         
     | 
| 
      
 20 
     | 
    
         
            +
                  def response
         
     | 
| 
      
 21 
     | 
    
         
            +
                    @response ||= with_logging { HTTPI.get request }
         
     | 
| 
      
 22 
     | 
    
         
            +
                  end
         
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
      
 24 
     | 
    
         
            +
                private
         
     | 
| 
      
 25 
     | 
    
         
            +
             
     | 
| 
      
 26 
     | 
    
         
            +
                  # Logs the HTTP request and yields to a given +block+.
         
     | 
| 
      
 27 
     | 
    
         
            +
                  def with_logging
         
     | 
| 
      
 28 
     | 
    
         
            +
                    Savon.log "Retrieving WSDL from: #{request.url}"
         
     | 
| 
      
 29 
     | 
    
         
            +
                    Savon.log "Using :#{request.auth.type} authentication" if request.auth?
         
     | 
| 
      
 30 
     | 
    
         
            +
                    yield
         
     | 
| 
      
 31 
     | 
    
         
            +
                  end
         
     | 
| 
      
 32 
     | 
    
         
            +
             
     | 
| 
      
 33 
     | 
    
         
            +
                end
         
     | 
| 
      
 34 
     | 
    
         
            +
              end
         
     | 
| 
      
 35 
     | 
    
         
            +
            end
         
     | 
    
        data/lib/savon/wsse.rb
    ADDED
    
    | 
         @@ -0,0 +1,150 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require "base64"
         
     | 
| 
      
 2 
     | 
    
         
            +
            require "digest/sha1"
         
     | 
| 
      
 3 
     | 
    
         
            +
             
     | 
| 
      
 4 
     | 
    
         
            +
            require "savon/core_ext/string"
         
     | 
| 
      
 5 
     | 
    
         
            +
            require "savon/core_ext/hash"
         
     | 
| 
      
 6 
     | 
    
         
            +
            require "savon/core_ext/time"
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
            module Savon
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
              # = Savon::WSSE
         
     | 
| 
      
 11 
     | 
    
         
            +
              #
         
     | 
| 
      
 12 
     | 
    
         
            +
              # Provides WSSE authentication.
         
     | 
| 
      
 13 
     | 
    
         
            +
              class WSSE
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
                # Namespace for WS Security Secext.
         
     | 
| 
      
 16 
     | 
    
         
            +
                WSENamespace = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"
         
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
      
 18 
     | 
    
         
            +
                # Namespace for WS Security Utility.
         
     | 
| 
      
 19 
     | 
    
         
            +
                WSUNamespace = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"
         
     | 
| 
      
 20 
     | 
    
         
            +
             
     | 
| 
      
 21 
     | 
    
         
            +
                # URI for "wsse:Password/@Type" #PasswordText.
         
     | 
| 
      
 22 
     | 
    
         
            +
                PasswordTextURI = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText"
         
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
      
 24 
     | 
    
         
            +
                # URI for "wsse:Password/@Type" #PasswordDigest.
         
     | 
| 
      
 25 
     | 
    
         
            +
                PasswordDigestURI = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest"
         
     | 
| 
      
 26 
     | 
    
         
            +
             
     | 
| 
      
 27 
     | 
    
         
            +
                # Returns a value from the WSSE Hash.
         
     | 
| 
      
 28 
     | 
    
         
            +
                def [](key)
         
     | 
| 
      
 29 
     | 
    
         
            +
                  hash[key]
         
     | 
| 
      
 30 
     | 
    
         
            +
                end
         
     | 
| 
      
 31 
     | 
    
         
            +
             
     | 
| 
      
 32 
     | 
    
         
            +
                # Sets a value on the WSSE Hash.
         
     | 
| 
      
 33 
     | 
    
         
            +
                def []=(key, value)
         
     | 
| 
      
 34 
     | 
    
         
            +
                  hash[key] = value
         
     | 
| 
      
 35 
     | 
    
         
            +
                end
         
     | 
| 
      
 36 
     | 
    
         
            +
             
     | 
| 
      
 37 
     | 
    
         
            +
                # Sets authentication credentials for a wsse:UsernameToken header.
         
     | 
| 
      
 38 
     | 
    
         
            +
                # Also accepts whether to use WSSE digest authentication.
         
     | 
| 
      
 39 
     | 
    
         
            +
                def credentials(username, password, digest = false)
         
     | 
| 
      
 40 
     | 
    
         
            +
                  self.username = username
         
     | 
| 
      
 41 
     | 
    
         
            +
                  self.password = password
         
     | 
| 
      
 42 
     | 
    
         
            +
                  self.digest = digest
         
     | 
| 
      
 43 
     | 
    
         
            +
                end
         
     | 
| 
      
 44 
     | 
    
         
            +
             
     | 
| 
      
 45 
     | 
    
         
            +
                attr_accessor :username, :password, :created_at, :expires_at
         
     | 
| 
      
 46 
     | 
    
         
            +
             
     | 
| 
      
 47 
     | 
    
         
            +
                # Returns whether to use WSSE digest. Defaults to +false+.
         
     | 
| 
      
 48 
     | 
    
         
            +
                def digest?
         
     | 
| 
      
 49 
     | 
    
         
            +
                  !!@digest
         
     | 
| 
      
 50 
     | 
    
         
            +
                end
         
     | 
| 
      
 51 
     | 
    
         
            +
             
     | 
| 
      
 52 
     | 
    
         
            +
                attr_writer :digest
         
     | 
| 
      
 53 
     | 
    
         
            +
             
     | 
| 
      
 54 
     | 
    
         
            +
                # Returns whether to generate a wsse:UsernameToken header.
         
     | 
| 
      
 55 
     | 
    
         
            +
                def username_token?
         
     | 
| 
      
 56 
     | 
    
         
            +
                  username && password
         
     | 
| 
      
 57 
     | 
    
         
            +
                end
         
     | 
| 
      
 58 
     | 
    
         
            +
             
     | 
| 
      
 59 
     | 
    
         
            +
                # Returns whether to generate a wsse:Timestamp header.
         
     | 
| 
      
 60 
     | 
    
         
            +
                def timestamp?
         
     | 
| 
      
 61 
     | 
    
         
            +
                  created_at || expires_at || @wsse_timestamp
         
     | 
| 
      
 62 
     | 
    
         
            +
                end
         
     | 
| 
      
 63 
     | 
    
         
            +
             
     | 
| 
      
 64 
     | 
    
         
            +
                # Sets whether to generate a wsse:Timestamp header.
         
     | 
| 
      
 65 
     | 
    
         
            +
                def timestamp=(timestamp)
         
     | 
| 
      
 66 
     | 
    
         
            +
                  @wsse_timestamp = timestamp
         
     | 
| 
      
 67 
     | 
    
         
            +
                end
         
     | 
| 
      
 68 
     | 
    
         
            +
             
     | 
| 
      
 69 
     | 
    
         
            +
                # Returns the XML for a WSSE header.
         
     | 
| 
      
 70 
     | 
    
         
            +
                def to_xml
         
     | 
| 
      
 71 
     | 
    
         
            +
                  if username_token?
         
     | 
| 
      
 72 
     | 
    
         
            +
                    Gyoku.xml wsse_username_token.merge!(hash)
         
     | 
| 
      
 73 
     | 
    
         
            +
                  elsif timestamp?
         
     | 
| 
      
 74 
     | 
    
         
            +
                    Gyoku.xml wsse_timestamp.merge!(hash)
         
     | 
| 
      
 75 
     | 
    
         
            +
                  else
         
     | 
| 
      
 76 
     | 
    
         
            +
                    ""
         
     | 
| 
      
 77 
     | 
    
         
            +
                  end
         
     | 
| 
      
 78 
     | 
    
         
            +
                end
         
     | 
| 
      
 79 
     | 
    
         
            +
             
     | 
| 
      
 80 
     | 
    
         
            +
              private
         
     | 
| 
      
 81 
     | 
    
         
            +
             
     | 
| 
      
 82 
     | 
    
         
            +
                # Returns a Hash containing wsse:UsernameToken details.
         
     | 
| 
      
 83 
     | 
    
         
            +
                def wsse_username_token
         
     | 
| 
      
 84 
     | 
    
         
            +
                  if digest?
         
     | 
| 
      
 85 
     | 
    
         
            +
                    wsse_security "UsernameToken",
         
     | 
| 
      
 86 
     | 
    
         
            +
                      "wsse:Username" => username,
         
     | 
| 
      
 87 
     | 
    
         
            +
                      "wsse:Nonce" => nonce,
         
     | 
| 
      
 88 
     | 
    
         
            +
                      "wsu:Created" => timestamp,
         
     | 
| 
      
 89 
     | 
    
         
            +
                      "wsse:Password" => digest_password,
         
     | 
| 
      
 90 
     | 
    
         
            +
                      :attributes! => { "wsse:Password" => { "Type" => PasswordDigestURI } }
         
     | 
| 
      
 91 
     | 
    
         
            +
                  else
         
     | 
| 
      
 92 
     | 
    
         
            +
                    wsse_security "UsernameToken",
         
     | 
| 
      
 93 
     | 
    
         
            +
                      "wsse:Username" => username,
         
     | 
| 
      
 94 
     | 
    
         
            +
                      "wsse:Password" => password,
         
     | 
| 
      
 95 
     | 
    
         
            +
                      :attributes! => { "wsse:Password" => { "Type" => PasswordTextURI } }
         
     | 
| 
      
 96 
     | 
    
         
            +
                  end
         
     | 
| 
      
 97 
     | 
    
         
            +
                end
         
     | 
| 
      
 98 
     | 
    
         
            +
             
     | 
| 
      
 99 
     | 
    
         
            +
                # Returns a Hash containing wsse:Timestamp details.
         
     | 
| 
      
 100 
     | 
    
         
            +
                def wsse_timestamp
         
     | 
| 
      
 101 
     | 
    
         
            +
                  wsse_security "Timestamp",
         
     | 
| 
      
 102 
     | 
    
         
            +
                    "wsu:Created" => (created_at || Time.now).xs_datetime,
         
     | 
| 
      
 103 
     | 
    
         
            +
                    "wsu:Expires" => (expires_at || (created_at || Time.now) + 60).xs_datetime
         
     | 
| 
      
 104 
     | 
    
         
            +
                end
         
     | 
| 
      
 105 
     | 
    
         
            +
             
     | 
| 
      
 106 
     | 
    
         
            +
                # Returns a Hash containing wsse:Security details for a given +tag+ and +hash+.
         
     | 
| 
      
 107 
     | 
    
         
            +
                def wsse_security(tag, hash)
         
     | 
| 
      
 108 
     | 
    
         
            +
                  {
         
     | 
| 
      
 109 
     | 
    
         
            +
                    "wsse:Security" => {
         
     | 
| 
      
 110 
     | 
    
         
            +
                      "wsse:#{tag}" => hash,
         
     | 
| 
      
 111 
     | 
    
         
            +
                      :attributes! => { "wsse:#{tag}" => { "wsu:Id" => "#{tag}-#{count}", "xmlns:wsu" => WSUNamespace } }
         
     | 
| 
      
 112 
     | 
    
         
            +
                    },
         
     | 
| 
      
 113 
     | 
    
         
            +
                    :attributes! => { "wsse:Security" => { "xmlns:wsse" => WSENamespace } }
         
     | 
| 
      
 114 
     | 
    
         
            +
                  }
         
     | 
| 
      
 115 
     | 
    
         
            +
                end
         
     | 
| 
      
 116 
     | 
    
         
            +
             
     | 
| 
      
 117 
     | 
    
         
            +
                # Returns the WSSE password, encrypted for digest authentication.
         
     | 
| 
      
 118 
     | 
    
         
            +
                def digest_password
         
     | 
| 
      
 119 
     | 
    
         
            +
                  token = nonce + timestamp + password
         
     | 
| 
      
 120 
     | 
    
         
            +
                  Base64.encode64(Digest::SHA1.hexdigest(token)).chomp!
         
     | 
| 
      
 121 
     | 
    
         
            +
                end
         
     | 
| 
      
 122 
     | 
    
         
            +
             
     | 
| 
      
 123 
     | 
    
         
            +
                # Returns a WSSE nonce.
         
     | 
| 
      
 124 
     | 
    
         
            +
                def nonce
         
     | 
| 
      
 125 
     | 
    
         
            +
                  @nonce ||= Digest::SHA1.hexdigest random_string + timestamp
         
     | 
| 
      
 126 
     | 
    
         
            +
                end
         
     | 
| 
      
 127 
     | 
    
         
            +
             
     | 
| 
      
 128 
     | 
    
         
            +
                # Returns a random String of 100 characters.
         
     | 
| 
      
 129 
     | 
    
         
            +
                def random_string
         
     | 
| 
      
 130 
     | 
    
         
            +
                  (0...100).map { ("a".."z").to_a[rand(26)] }.join
         
     | 
| 
      
 131 
     | 
    
         
            +
                end
         
     | 
| 
      
 132 
     | 
    
         
            +
             
     | 
| 
      
 133 
     | 
    
         
            +
                # Returns a WSSE timestamp.
         
     | 
| 
      
 134 
     | 
    
         
            +
                def timestamp
         
     | 
| 
      
 135 
     | 
    
         
            +
                  @timestamp ||= Time.now.xs_datetime
         
     | 
| 
      
 136 
     | 
    
         
            +
                end
         
     | 
| 
      
 137 
     | 
    
         
            +
             
     | 
| 
      
 138 
     | 
    
         
            +
                # Returns a new number with every call.
         
     | 
| 
      
 139 
     | 
    
         
            +
                def count
         
     | 
| 
      
 140 
     | 
    
         
            +
                  @count ||= 0
         
     | 
| 
      
 141 
     | 
    
         
            +
                  @count += 1
         
     | 
| 
      
 142 
     | 
    
         
            +
                end
         
     | 
| 
      
 143 
     | 
    
         
            +
             
     | 
| 
      
 144 
     | 
    
         
            +
                # Returns a memoized and autovivificating Hash.
         
     | 
| 
      
 145 
     | 
    
         
            +
                def hash
         
     | 
| 
      
 146 
     | 
    
         
            +
                  @hash ||= Hash.new { |h, k| h[k] = Hash.new(&h.default_proc) }
         
     | 
| 
      
 147 
     | 
    
         
            +
                end
         
     | 
| 
      
 148 
     | 
    
         
            +
             
     | 
| 
      
 149 
     | 
    
         
            +
              end
         
     | 
| 
      
 150 
     | 
    
         
            +
            end
         
     | 
    
        data/savon.gemspec
    ADDED
    
    | 
         @@ -0,0 +1,29 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            lib = File.expand_path("../lib", __FILE__)
         
     | 
| 
      
 2 
     | 
    
         
            +
            $:.unshift lib unless $:.include? lib
         
     | 
| 
      
 3 
     | 
    
         
            +
             
     | 
| 
      
 4 
     | 
    
         
            +
            require "savon/version"
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
            Gem::Specification.new do |s|
         
     | 
| 
      
 7 
     | 
    
         
            +
              s.name = "s-savon"
         
     | 
| 
      
 8 
     | 
    
         
            +
              s.version = Savon::Version
         
     | 
| 
      
 9 
     | 
    
         
            +
              s.authors = "Daniel Harrington"
         
     | 
| 
      
 10 
     | 
    
         
            +
              s.email = "me@rubiii.com"
         
     | 
| 
      
 11 
     | 
    
         
            +
              s.homepage = "http://github.com/rubiii/#{s.name}"
         
     | 
| 
      
 12 
     | 
    
         
            +
              s.summary = "Heavy metal Ruby SOAP client"
         
     | 
| 
      
 13 
     | 
    
         
            +
              s.description = "Savon is the heavy metal Ruby SOAP client."
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
              s.rubyforge_project = s.name
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
              s.add_dependency "builder", ">= 2.1.2"
         
     | 
| 
      
 18 
     | 
    
         
            +
              s.add_dependency "crack", "~> 0.1.8"
         
     | 
| 
      
 19 
     | 
    
         
            +
              s.add_dependency "httpi", ">= 0.7.8"
         
     | 
| 
      
 20 
     | 
    
         
            +
              s.add_dependency "gyoku", ">= 0.3.0"
         
     | 
| 
      
 21 
     | 
    
         
            +
             
     | 
| 
      
 22 
     | 
    
         
            +
              s.add_development_dependency "rspec", "~> 2.4.0"
         
     | 
| 
      
 23 
     | 
    
         
            +
              s.add_development_dependency "autotest"
         
     | 
| 
      
 24 
     | 
    
         
            +
              s.add_development_dependency "mocha", "~> 0.9.8"
         
     | 
| 
      
 25 
     | 
    
         
            +
              s.add_development_dependency "timecop", "~> 0.3.5"
         
     | 
| 
      
 26 
     | 
    
         
            +
             
     | 
| 
      
 27 
     | 
    
         
            +
              s.files = `git ls-files`.split("\n")
         
     | 
| 
      
 28 
     | 
    
         
            +
              s.require_path = "lib"
         
     | 
| 
      
 29 
     | 
    
         
            +
            end
         
     | 
| 
         Binary file 
     | 
| 
         @@ -0,0 +1,14 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            <SOAP-ENV:Envelope SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
         
     | 
| 
      
 2 
     | 
    
         
            +
              xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
         
     | 
| 
      
 3 
     | 
    
         
            +
              xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/"
         
     | 
| 
      
 4 
     | 
    
         
            +
              xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         
     | 
| 
      
 5 
     | 
    
         
            +
              xmlns:xsd="http://www.w3.org/2001/XMLSchema">
         
     | 
| 
      
 6 
     | 
    
         
            +
              <SOAP-ENV:Body>
         
     | 
| 
      
 7 
     | 
    
         
            +
                <SOAP-ENV:Fault>
         
     | 
| 
      
 8 
     | 
    
         
            +
                  <faultcode>ERR_NO_SESSION</faultcode>
         
     | 
| 
      
 9 
     | 
    
         
            +
                  <faultfactor>doGetItemsInfo - Wrong session</faultfactor>
         
     | 
| 
      
 10 
     | 
    
         
            +
                  <faultstring>Wrong session message</faultstring>
         
     | 
| 
      
 11 
     | 
    
         
            +
                  <detail><soapVal><ERRNO xsi:type="xsd:string">80:1289245853:55</ERRNO></soapVal></detail>
         
     | 
| 
      
 12 
     | 
    
         
            +
                </SOAP-ENV:Fault>
         
     | 
| 
      
 13 
     | 
    
         
            +
              </SOAP-ENV:Body>
         
     | 
| 
      
 14 
     | 
    
         
            +
            </SOAP-ENV:Envelope>
         
     |