Home > other >  Ruby Savon 2 error: Savon::SOAPFault ((SOAP-ENV:Server) The namespace prefix is not allowed to start
Ruby Savon 2 error: Savon::SOAPFault ((SOAP-ENV:Server) The namespace prefix is not allowed to start

Time:12-01

I am trying to connect to a company that uses SOAP remote procedure calls so I am using the Savon Gem. Here is what I have to setup the authentication:

require 'savon'

client = Savon.client(
  wsdl: 'https://customdomain.companydomain.com:port/wsdlcode/wsdl/xmlBridge',
  endpoint: 'https://customdomain.companydomain.com:port/endpointcode/soap/xmlBridge',
  basic_auth: ["username", "password"],
  env_namespace: :soapenv,
  namespace_identifier: :web, 
  logger: Rails.logger, 
  log_level: :debug, 
  log: true, 
  :pretty_print_xml => true, 
  encoding: 'UTF-8'
)

This seems to work. I can even call "client.operations" to get a list of the functions that can be called. When I run

response = client.call(:get_active_employees) 

to try to get an employee list, I get the error message:

Savon::SOAPFault ((SOAP-ENV:Server) The namespace prefix is not allowed to start with the reserved string "xml".)

Does anyone know how to fix this?

CodePudding user response:

The issue here is that the wsdl is likely including incorrect namespaces that Savon is automatically adding into the xml that you are sending back in the request. If you look at the lib/savon/builder.rb file in the Savon Gem by using: gem which savon

to determine where your salon gem is located and then opening the enclosing gem folder in your IDE. Which should be something along the lines of /Users/username/.rvm/gems/ruby-2.5.1/gems/savon-2.13.0/ if your on a mac

Open the builder.rb file lib/savon/builder.rb

Here you'll see a method namespaces which unfortunately includes all the parsed namespaces from the wsdl:

          @wsdl.parser.namespaces.each do |identifier, path|
            next if namespaces.key?("xmlns:#{identifier}")

            namespaces["xmlns:#{identifier}"] = path
          end
        end

If that wsdl includes an invalid namespace it will be included right back in the output when you perform your call.

To fix this you need to add a new file in config/initializers/savon_monkey_patch.rb that contains the attached code:

Savon::Builder.class_eval do
  private

  def namespaces
    @namespaces ||= begin
                      namespaces = Savon::Builder::SCHEMA_TYPES.dup

                      # check namespace_identifier
                      namespaces["xmlns#{namespace_identifier.nil? ? '' : ":#{namespace_identifier}"}"] =
                        @globals[:namespace] || @wsdl.namespace
                      # check env_namespace
                      namespaces["xmlns#{env_namespace && env_namespace != "" ? ":#{env_namespace}" : ''}"] =
                        Savon::Builder::SOAP_NAMESPACE[@globals[:soap_version]]

                      if @wsdl&.document
                        @wsdl.parser.namespaces.each do |identifier, path|
                          # this is to get rid of the xml namespaces that are invalid in a soap document
                          next if namespaces.key?("xmlns:#{identifier}") || identifier.match?(/^xml/)

                          namespaces["xmlns:#{identifier}"] = path
                        end
                      end

                      namespaces
                    end
  end
end

The key line being identifier.match?(/^xml/) which will exclude any namespaces that begin with xml from your outgoing request. I hope this helps.

  • Related