Skip to content
Open
Show file tree
Hide file tree
Changes from 9 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,5 @@
.idea/
.rvmrc
*.swp*.gem
Gemfile.lock
Gemfile.lock
.ruby-version
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
before_install:
- gem install bundler
rvm:
- 1.9.3
- 2.0.0
- 2.4.0

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why would you like to drop supporting for 1.9 branch without major release? Only major release should make breaking API changes

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably updating major version will be right. 1.9 support ended 2 years ago, do you know if anyone still using it? I haven't seen it for years

https://www.ruby-lang.org/en/news/2014/01/10/ruby-1-9-3-will-end-on-2015/

2 changes: 2 additions & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,5 @@ source 'https://rubygems.org'

# Specify your gem's dependencies in sinatra-soap.gemspec
gemspec

gem 'sinatra', '2.0.0.rc2'

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess this should be moved into gemspec (well it's there).

75 changes: 72 additions & 3 deletions lib/sinatra/soap/helper_methods.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,84 @@ def soap_views()
File.join(File.dirname(__FILE__), "..", "views")
end

def hash_to_xml(xml, hash)

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess this should be rewritten. Too long method with huge complexity.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep. But what you think about this idea in general? (@.. for xml attributes, @@content to create tag with attributes and simple content, converting array list of singularized tags)

hash.each do |key, value|
if value.is_a?(Hash)
attrs = {}
content = {}
content_str = nil
value.each do |key, value|
if key.to_s == "@@content"
content_str = value
elsif key.to_s.start_with?("@")
attrs[key.to_s[1..-1]] = value
else
content[key] = value
end
end
if content_str
xml.tag!(key, attrs, content_str)
else
xml.tag!(key, attrs) do
hash_to_xml(xml, content)
end
end
elsif value.is_a?(Array)
parent_tag = singularize(key)

if parent_tag == key.to_s
value.each do |value|
hash_to_xml(xml, parent_tag => value)
end
else
xml.tag!(key) do
value.each do |value|
hash_to_xml(xml, parent_tag => value)
end
end
end
else
xml.tag! key, value
end
end
end

# Try to use activesupport's singularize, failback to simplified implementation
def singularize(word)
word = word.to_s
if word.respond_to?(:singularize)
word.singularize
else
if word =~ /(c|s|x)es$/
word.sub(/(c|s|x)es$/, '\1')
else
word.sub(/s$/, '')
end
end
end

def call_action_block
request = Soap::Request.new(env, request, params)
if defined?(logger) && logger

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like Soap::Request should know about logging and log request while/before/after execution.

logger.info "SOAP Request: #{request.action}"
end
response = request.execute
builder :response, locals: {wsdl: response.wsdl, params: response.params}, :views => self.soap_views
builder :response, views: self.soap_views, locals: {
wsdl: response.wsdl,
params: response.params,
soap_headers: response.headers
}
rescue Soap::Error => e
builder :error, locals: {e: e}, :views => self.soap_views
if defined?(logger) && logger
logger.info "SOAP Request: #{env['HTTP_SOAPACTION']} - Undefined Soap Action"

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's not correct. If we catch error that does not mean we catch Undefined Soap Action.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right, thanks for point it

end
builder :error, locals: {e: e}, views: self.soap_views
end

def get_wsdl
if defined?(logger) && logger
logger.info "SOAP: wsdl request"

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thats it? seriously? Just log that wsdl request?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it was useful in my case to verify if client working correctly or not. Probably just standard sinatra's logging will be enough

end
if defined?(settings.wsdl_path)
path = File.join(settings.public_folder, settings.wsdl_path)
if File.exist?(path)
Expand All @@ -26,7 +95,7 @@ def get_wsdl
raise "No wsdl file"
end
else
builder :wsdl, locals: {wsdl: Soap::Wsdl.actions}, :views => self.soap_views
builder :wsdl, locals: {wsdl: Soap::Wsdl.actions}, views: self.soap_views
end
end

Expand Down
28 changes: 24 additions & 4 deletions lib/sinatra/soap/request.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,33 @@ module Sinatra
module Soap
class Request

attr_reader :wsdl, :action, :env, :request, :params
attr_reader :wsdl, :action, :env, :request, :params, :response

alias_method :body, :params

def initialize(env, request, params)
@env = env
@request = request
@params = params
@header = {}
parse_request
end


def execute
request_block = wsdl.block
@response = Soap::Response.new(wsdl, nil)
response_hash = self.instance_eval(&request_block)
Soap::Response.new(wsdl, response_hash)

if @response.params == nil
if response_hash.is_a?(Array)
@response.params, @response.headers = response_hash
else
@response.params = response_hash
end
end

@response
end

alias_method :orig_params, :params
Expand All @@ -27,14 +40,21 @@ def action
orig_params[:action] = env['HTTP_SOAPACTION'].to_s.gsub(/^"(.*)"$/, '\1').to_sym
end


def params
def params
return orig_params[:soap] unless orig_params[:soap].nil?
rack_input = env["rack.input"].read
env["rack.input"].rewind
orig_params[:soap] = nori.parse(rack_input)[:Envelope][:Body][action]
end

def header
return orig_params[:soap_header] unless orig_params[:soap_header].nil?
rack_input = env["rack.input"].read
env["rack.input"].rewind

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Prefer single quotes (rubocop)

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

never understood the point of this rule, afaik now days compiler is smart enough to determine if have interpolations or not...
Will update it when code is production ready

orig_params[:soap_header] = nori.parse(rack_input)[:Envelope][:Header]
end

alias_method :soap_header, :header

def wsdl
@wsdl = Soap::Wsdl.new(action)
Expand Down
9 changes: 7 additions & 2 deletions lib/sinatra/soap/response.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,16 @@ module Sinatra
module Soap
class Response

attr_reader :wsdl, :params
attr_reader :wsdl
attr_accessor :params, :headers

def initialize(wsdl, params)
alias_method :body, :params
alias_method :body=, :params=

def initialize(wsdl, params, headers = nil)
@wsdl = wsdl
@params = params
@headers = headers
end
end
end
Expand Down
3 changes: 2 additions & 1 deletion lib/sinatra/soap/wsdl.rb
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,14 @@ def self.register(name, *args, &block)
def self.generate
end

attr_accessor :action, :block, :arguments
attr_accessor :action, :block, :arguments, :reply_name

def initialize(action)
data = all[action]
raise Soap::Error, "Undefined Soap Action" if data.nil?
@action = action
@block = data[:block]
@reply_name = data[:reply_name]
@arguments = data.select {|k,v| k != :block}
end

Expand Down
13 changes: 8 additions & 5 deletions lib/sinatra/views/response.builder
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
xml.instruct!
xml.tag! 'soap:Envelope', 'xmlns:soap' => 'http://schemas.xmlsoap.org/soap/envelope/',
'xmlns:xsi' => 'http://www.w3.org/2001/XMLSchema-instance' do
if soap_headers
xml.tag! 'soap:Header' do
hash_to_xml(xml, soap_headers)
end
end
xml.tag! 'soap:Body' do
xml.tag! "soap:#{wsdl.action}Response" do
params.each do |key, value|
xml.tag! key, value
end
xml.tag! "soap:#{wsdl.reply_name || "#{wsdl.action}Response"}" do
hash_to_xml(xml, params)
end
end
end
end
10 changes: 6 additions & 4 deletions lib/sinatra/views/wsdl.builder
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ xml.definitions 'xmlns' => 'http://schemas.xmlsoap.org/wsdl/',
xml.tag! "schema", :targetNamespace => settings.namespace, :xmlns => 'http://www.w3.org/2001/XMLSchema' do
defined = []
wsdl.each do |operation, formats|
formats[:in]||={}
formats[:out]||={}
formats[:in] ||= {}
formats[:out] ||= {}
formats[:in].each do |p|
wsdl_type xml, p, defined
end
Expand All @@ -28,7 +28,8 @@ xml.definitions 'xmlns' => 'http://schemas.xmlsoap.org/wsdl/',
wsdl.keys.each do |operation|
xml.operation :name => operation do
xml.input :message => "tns:#{operation}"
xml.output :message => "tns:#{operation}Response"
response_name = wsdl[operation][:reply_name] || "#{operation}Response"
xml.output :message => "tns:#{response_name}"
end
end
end
Expand Down Expand Up @@ -66,7 +67,8 @@ xml.definitions 'xmlns' => 'http://schemas.xmlsoap.org/wsdl/',
#, :name => param.name, :type => param.namespaced_type)
end
end
xml.message :name => "#{operation}Response" do
response_name = wsdl[operation][:reply_name] || "#{operation}Response"
xml.message :name => response_name do
formats[:out] ||= []
formats[:out].each do |p|
xml.part wsdl_occurence(p, false)
Expand Down
2 changes: 1 addition & 1 deletion sinatra-soap.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ Gem::Specification.new do |spec|
spec.add_development_dependency "rspec"
spec.add_development_dependency "rake"
spec.add_development_dependency "rack-test"
spec.add_development_dependency "debugger"
#spec.add_development_dependency "debugger"

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why would you remove debugger out of development dependencies?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's only for ruby 1.9.*, I think there was some installation issues with ruby 2.4



spec.add_runtime_dependency "builder"
Expand Down
49 changes: 49 additions & 0 deletions spec/render_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
require 'spec_helper'

describe "Request" do
def app
SoapApp
end

it "should render xml with params" do
headers = {"HTTP_SOAPACTION" => 'test_render'}
message = '<?xml version="1.0" encoding="UTF-8"?><env:Envelope xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:wsdl="any" xmlns:env="http://schemas.xmlsoap.org/soap/envelope/"><env:Body><wsdl:test></wsdl:test></env:Body></env:Envelope>'
post '/action', message, headers

response = %{
<?xml version="1.0" encoding="UTF-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<soap:Body>
<soap:TestRenderReply>
<top>
<child attr1="attr_value">
<value>content</value>
</child>
</top>
</soap:TestRenderReply>
</soap:Body>
</soap:Envelope>}.strip

expect(last_response.body).to eq(response + "\n")
end

it "should render xml with params and single content" do
headers = {"HTTP_SOAPACTION" => 'test_render2'}
message = '<?xml version="1.0" encoding="UTF-8"?><env:Envelope xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:wsdl="any" xmlns:env="http://schemas.xmlsoap.org/soap/envelope/"><env:Body><wsdl:test></wsdl:test></env:Body></env:Envelope>'
post '/action', message, headers

response = %{
<?xml version="1.0" encoding="UTF-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<soap:Body>
<soap:test_render2Response>
<result status="success">
<foo active="true">bar</foo>
</result>
</soap:test_render2Response>
</soap:Body>
</soap:Envelope>}.strip

expect(last_response.body).to eq(response + "\n")
end
end
17 changes: 10 additions & 7 deletions spec/request_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,29 +2,32 @@

describe "Request" do
def app
SoapApp
SoapApp
end

before :each do
headers = {"HTTP_SOAPACTION" => 'test'}
message = '<?xml version="1.0" encoding="UTF-8"?><env:Envelope xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:wsdl="any" xmlns:env="http://schemas.xmlsoap.org/soap/envelope/"><env:Body><wsdl:test><par>one</par><par2>bar</par2><foo>wat</foo></wsdl:test></env:Body></env:Envelope>'
message = '<?xml version="1.0" encoding="UTF-8"?>' +
'<env:Envelope xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" ' +
'xmlns:wsdl="any" xmlns:env="http://schemas.xmlsoap.org/soap/envelope/">' +
'<env:Body><wsdl:test><par>one</par><par2>bar</par2><foo>wat</foo></wsdl:test></env:Body></env:Envelope>'
post '/action', message, headers
@request = Sinatra::Soap::Request.new(last_request.env, last_request, last_request.params)
end

it "should get soap_action" do
it "should get soap_action" do
expect(@request.action).to eq(:test)
end

it "should get soap arguments" do
it "should get soap arguments" do
expect(@request.params).to eq({par: "one", par2: "bar", foo: "wat"})
end

it "should build response" do
it "should build response" do
expect(@request.execute).to be_an_instance_of(Sinatra::Soap::Response)
end

it "should validate input with WSDL" do
pending
it "should validate input with WSDL" do
skip
end
end
2 changes: 1 addition & 1 deletion spec/soap_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

describe 'A default soap sinatra application' do
def app
SoapApp
SoapApp
end

it "should parse soap request and send response" do
Expand Down
Loading