lib/shapewear/request.rb in shapewear-0.1.0 vs lib/shapewear/request.rb in shapewear-0.1.1

- old
+ new

@@ -1,81 +1,130 @@ # encoding: UTF-8 +require 'forwardable' + module Shapewear::Request # @param request [Rack::Request, Hash] def serve(request) - op_node = find_soap_operation_node(request) - - begin - call_soap_operation(op_node) - rescue => e - serialize_soap_fault e - end + RequestHandler.new(self, request).serve end - private + class RequestHandler + extend Forwardable - def find_soap_operation_node(request) - body ||= request.body if request.respond_to? :body - body ||= request[:body] if request.is_a?(Hash) - body ||= request.to_s + attr_reader :soap_version, :op_node, :clazz + def_delegators :@clazz, :namespaces, :operations, :logger - raise "Request body could not be found" if body.nil? + def initialize(clazz, request) + @clazz = clazz - doc = Nokogiri::XML(body) { |c| c.strict } rescue raise("Request body is not a valid XML") + body ||= request.body if request.respond_to? :body + body ||= request[:body] if request.is_a?(Hash) + body ||= request.to_s - raise "Request is not a SOAP::Envelope: #{body}" if doc.at('/env:Envelope', namespaces).nil? + raise "Request body could not be found" if body.nil? - # find the operation element, or raise if not found - doc.at("/env:Envelope/env:Body/tns:*", namespaces) or raise "Operation not found" - end + doc = Nokogiri::XML(body) { |c| c.strict } rescue raise("Request body is not a valid XML") - def call_soap_operation(node) - operations.each do |k, v| - if v[:public_name] == node.name - params = extract_parameters(node) - logger.debug "Calling #{k} with args: #{params.map(&:inspect) * ', '}" - r = self.new.send(k, *params) - logger.debug "Result: #{r.inspect}" - return serialize_soap_result v, r + # detect the SOAP version from the envelope, and find the operation element, or raise if not found + if doc.at('/env:Envelope', namespaces) + @soap_version = :soap11 + @op_node = doc.at("/env:Envelope/env:Body/tns:*", namespaces) + elsif doc.at('/env12:Envelope', namespaces) + @soap_version = :soap12 + @op_node = doc.at("/env12:Envelope/env12:Body/tns:*", namespaces) + else + raise "Request is not a SOAP 1.1 nor SOAP 1.2 Envelope: #{body}" end end - raise "Operation not found: #{node.name}" - end + def serve + call_soap_operation + end - def extract_parameters(node) - # TODO: use the metadata collected from the DSL to reoder the parameters and perform the appropriate conversions - node.children.map { |n| n.text } - end + private - #noinspection RubyArgCount - def serialize_soap_result(op_options, r) - xb = Builder::XmlMarkup.new - xb.instruct! + def call_soap_operation + raise "Operation node not found" if op_node.nil? - xb.Envelope :xmlns => namespaces['env'] do |xenv| - xenv.Body do |xbody| - xbody.tag! "#{op_options[:public_name]}Response", :xmlns => namespaces['tns'] do |xres| - xres.body r + operations.each do |k, v| + if v[:public_name] == op_node.name + logger.debug "Extracting parameters from operation node..." + params = extract_parameters(@op_node) + logger.debug "Creating new instance of #{clazz}..." + obj = clazz.new + logger.debug "Calling #{k} with args: #{params.map(&:inspect) * ', '}" + begin + r = obj.send(k, *params) + logger.debug "Result: #{r.inspect}" + return serialize_soap_result v, r + rescue => e + logger.debug "Exception: #{e.inspect}" + return serialize_soap_fault e + end end end + + raise "Operation not found: #{@op_node.name}" end - end - #noinspection RubyArgCount - def serialize_soap_fault(ex) - logger.debug "Serializing SOAP Fault: #{ex.inspect}" + def extract_parameters(node) + # TODO: use the metadata collected from the DSL to reoder the parameters and perform the appropriate conversions + node.children.map { |n| n.text } + end - xb = Builder::XmlMarkup.new - xb.instruct! + #noinspection RubyArgCount + def serialize_soap_result(op_options, r) + xb = Builder::XmlMarkup.new + xb.instruct! - xb.Envelope :xmlns => namespaces['env'] do |xenv| - xenv.Body do |xbody| - xbody.Fault do |xf| - xf.faultcode ex.class.name - xf.faultstring ex.message + xb.Envelope :xmlns => soap_env_ns do |xenv| + xenv.Body do |xbody| + xbody.tag! "#{op_options[:public_name]}Response", :xmlns => namespaces['tns'] do |xres| + xres.body r + end end + end + end + + #noinspection RubyArgCount + def serialize_soap_fault(ex) + logger.debug "Serializing SOAP Fault: #{ex.inspect}" + + xb = Builder::XmlMarkup.new + xb.instruct! + + xb.Envelope 'xmlns:e' => soap_env_ns do |xenv| + xenv.tag! 'e:Body' do |xbody| + xbody.tag! 'e:Fault' do |xf| + case soap_version + when :soap11 + xf.faultcode "e:Server.#{ex.class.name}" + xf.faultstring ex.message + when :soap12 + xf.tag! 'e:Code' do |xcode| + xcode.tag! 'e:Value', 'e:Receiver' + xcode.tag! 'e:Subcode' do |xsubcode| + xsubcode.tag! 'e:Value', ex.class.name + end + end + xf.tag! 'e:Reason', ex.message + else + raise "Unsupported SOAP version: #{soap_version}" + end + end + end + end + end + + def soap_env_ns + case soap_version + when :soap11 + namespaces['env'] + when :soap12 + namespaces['env12'] + else + raise "Unrecognized SOAP version: #{soap_version}" end end end end