Skip to content

Commit

Permalink
decoding response body if content-encoding is gzip
Browse files Browse the repository at this point in the history
  • Loading branch information
lucascs authored and rubiii committed Mar 27, 2010
1 parent 3d29657 commit e297208
Show file tree
Hide file tree
Showing 4 changed files with 62 additions and 14 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Expand Up @@ -4,4 +4,5 @@ pkg
doc
coverage
.loadpath
.project
.project
*~
25 changes: 22 additions & 3 deletions lib/savon/response.rb
@@ -1,3 +1,6 @@
require 'stringio'
require 'zlib'

module Savon

# = Savon::Response
Expand Down Expand Up @@ -100,12 +103,12 @@ def http_error?

# Returns the SOAP response body as a Hash.
def to_hash
@body ||= (Crack::XML.parse(@http.body) rescue {}).find_soap_body
@hash ||= (Crack::XML.parse(body) rescue {}).find_soap_body
end

# Returns the SOAP response XML.
def to_xml
@http.body
body
end

# Returns the HTTP response object.
Expand All @@ -115,6 +118,21 @@ def to_xml

private

def body
@body || body_is_gzipped? ? decoded_body : @http.body
end

def body_is_gzipped?
@http['content-encoding'] == 'gzip'
end

def decoded_body
gz = Zlib::GzipReader.new(StringIO.new(@http.body))
gz.read
ensure
gz.close
end

# Handles SOAP faults. Raises a Savon::SOAPFault unless the default behavior of raising errors
# was turned off.
def handle_soap_fault
Expand Down Expand Up @@ -146,10 +164,11 @@ def soap_fault_message_by_version(soap_fault)
def handle_http_error
if @http.code.to_i > MaxNonErrorResponseCode
@http_error = "#{@http.message} (#{@http.code})"
@http_error << ": #{@http.body}" unless @http.body.empty?
@http_error << ": #{body}" unless body.empty?
raise Savon::HTTPError, http_error if self.class.raise_errors?
end
end

end
end

35 changes: 31 additions & 4 deletions spec/savon/response_spec.rb
@@ -1,5 +1,8 @@
require "spec_helper"

require 'zlib'
require 'stringio'

describe Savon::Response do
before { @response = Savon::Response.new http_response_mock }

Expand All @@ -21,13 +24,13 @@
it "raises a Savon::SOAPFault in case of a SOAP fault" do
lambda { savon_response_with :soap_fault }.should raise_error(Savon::SOAPFault)
end

it "does not raise a Savon::SOAPFault in case the default is turned off" do
Savon::Response.raise_errors = false
savon_response_with :soap_fault
Savon::Response.raise_errors = true
end

it "raises a Savon::HTTPError in case of an HTTP error" do
lambda { savon_response_with :http_error }.should raise_error(Savon::HTTPError)
end
Expand Down Expand Up @@ -102,7 +105,7 @@
@response = Savon::Response.new http_response_mock(200, ResponseFixture.multi_ref, "OK")

@response.to_hash[:list_response].should be_a(Hash)
@response.to_hash[:multi_ref].should be_an(Array)
@response.to_hash[:multi_ref].should be_an(Array)
end

it "should return the raw SOAP response body" do
Expand All @@ -117,6 +120,23 @@
@response.http.should respond_to(:body)
end

it "should decode gzip request if Content-encoding header is gzip" do
@response = Savon::Response.new http_response_mock(200, body = "Encoded", "OK", 'content-encoding' => 'gzip')

should_decode_body body

@response.to_xml
end

def should_decode_body body
StringIO.expects(:new).with(body).returns(stream = mock('StringIO'))

Zlib::GzipReader.expects(:new).with(stream).returns(mock('Zlib::GzipReader') do
expects(:read)
expects(:close)
end)
end

def savon_response_with(error_type)
mock = case error_type
when :soap_fault then http_response_mock 200, ResponseFixture.soap_fault
Expand All @@ -126,12 +146,19 @@ def savon_response_with(error_type)
Savon::Response.new mock
end

def http_response_mock(code = 200, body = nil, message = "OK")
def http_response_mock(code = 200, body = nil, message = "OK", headers = {})
body ||= ResponseFixture.authentication
mock = mock "Net::HTTPResponse"
mock.stubs :code => code.to_s, :message => message,
:content_type => "text/html", :body => body

mock.stubs('[]').with(anything).returns(nil)
headers.each do |k, v|
mock.stubs('[]').with(k).returns(v)
end

mock
end

end

13 changes: 7 additions & 6 deletions spec/savon/soap_spec.rb
Expand Up @@ -49,7 +49,7 @@
@namespace = { "xmlns:ns" => "http://example.com" }
@namespace_string = 'xmlns:ns="http://example.com"'
@namespaces = { "xmlns:ns" => "http://ns.example.com", "xmlns:ns2" => "http://ns2.example.com" }

# reset to defaults
Savon::SOAP.version = 1
Savon::SOAP.header = {}
Expand Down Expand Up @@ -137,15 +137,15 @@
it "should merge global and per request headers defined as Hashes" do
Savon::SOAP.header = { :key => "value", :key2 => "global value" }
@soap.header[:key2] = "request value"
@soap.to_xml.should include(
"<env:Header><key>value</key><key2>request value</key2></env:Header>"
@soap.to_xml.should match(
/<env:Header>(<key>value<\/key><key2>request value<\/key2>|<key2>request value<\/key2><key>value<\/key>)<\/env:Header>/
)
end

it "should use the :header method from a given WSSE object to include a WSSE header" do
wsse = "some compliant object"
wsse.stubs(:header).returns("<wsse>authentication</wsse>")

@soap.wsse = wsse
@soap.to_xml.should include("<env:Header><wsse>authentication</wsse></env:Header>")
end
Expand Down Expand Up @@ -195,7 +195,8 @@
'<env:Envelope xmlns:env="http://schemas.xmlsoap.org/soap/envelope/">' <<
'<env:Body><wsdl:authenticate></wsdl:authenticate></env:Body>' <<
'</env:Envelope>'
)
)
end
end
end
end

0 comments on commit e297208

Please sign in to comment.