Skip to content

Commit

Permalink
Add MTOM support for SOAP attachments (previously no support)
Browse files Browse the repository at this point in the history
Fix request logging when message containt non-ascii characters (log writing failure occured)
Fix using attachments together with 'xml' option (when xml option was provided, attachments option was ignored)
  • Loading branch information
ekzobrain authored and pcai committed Jul 15, 2024
1 parent b1b738c commit 201d799
Show file tree
Hide file tree
Showing 4 changed files with 52 additions and 21 deletions.
41 changes: 29 additions & 12 deletions lib/savon/builder.rb
Original file line number Diff line number Diff line change
Expand Up @@ -38,18 +38,23 @@ def pretty
end

def build_document
xml_result = build_xml
# check if xml was already provided
if @locals.include? :xml
xml_result = @locals[:xml]
else
xml_result = build_xml

# if we have a signature sign the document
if @signature
@signature.document = xml_result
# if we have a signature sign the document
if @signature
@signature.document = xml_result

2.times do
@header = nil
@signature.document = build_xml
end
2.times do
@header = nil
@signature.document = build_xml
end

xml_result = @signature.document
xml_result = @signature.document
end
end

# if there are attachments for the request, we should build a multipart message according to
Expand All @@ -70,7 +75,6 @@ def body_attributes
end

def to_s
return @locals[:xml] if @locals.include? :xml
build_document
end

Expand Down Expand Up @@ -254,15 +258,28 @@ def build_multipart_message(message_xml)

# the mail.body.encoded algorithm reorders the parts, default order is [ "text/plain", "text/enriched", "text/html" ]
# should redefine the sort order, because the soap request xml should be the first
multipart_message.body.set_sort_order [ "text/xml" ]
multipart_message.body.set_sort_order ['application/xop+xml', 'text/xml']

multipart_message.body.encoded(multipart_message.content_transfer_encoding)
end

def init_multipart_message(message_xml)
multipart_message = Mail.new

# MTOM differs from general SOAP attachments:
# 1. binary encoding
# 2. application/xop+xml mime type
if @locals[:mtom]
type = "application/xop+xml; charset=#{@globals[:encoding]}; type=\"text/xml\""

multipart_message.transport_encoding = 'binary'
message_xml.force_encoding('BINARY')
else
type = 'text/xml'
end

xml_part = Mail::Part.new do
content_type 'text/xml'
content_type type
body message_xml
# in Content-Type the start parameter is recommended (RFC 2387)
content_id '<soap-request-body@soap>'
Expand Down
22 changes: 15 additions & 7 deletions lib/savon/operation.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ class Operation
1 => "text/xml",
2 => "application/soap+xml"
}
SOAP_REQUEST_TYPE_MTOM = "application/xop+xml"

def self.create(operation_name, wsdl, globals)
if wsdl.document?
Expand Down Expand Up @@ -118,18 +119,25 @@ def build_connection(builder)
:headers => @locals[:headers]
) do |connection|
if builder.multipart
connection.request :gzip
connection.headers["Content-Type"] = %W[multipart/related
type="#{SOAP_REQUEST_TYPE[@globals[:soap_version]]}",
start="#{builder.multipart[:start]}",
boundary="#{builder.multipart[:multipart_boundary]}"].join("; ")
ctype_headers = ["multipart/related"]
if @locals[:mtom]
ctype_headers << "type=\"#{SOAP_REQUEST_TYPE_MTOM}\""
ctype_headers << "start-info=\"text/xml\""
else
ctype_headers << "type=\"#{SOAP_REQUEST_TYPE[@globals[:soap_version]]}\""
connection.request :gzip
end
connection.headers["Content-Type"] = (ctype_headers + ["start=\"#{builder.multipart[:start]}\"",
"boundary=\"#{builder.multipart[:multipart_boundary]}\""]).join("; ")
# request.headers["Content-Type"] = ["multipart/related",
# "type=\"#{SOAP_REQUEST_TYPE[@globals[:soap_version]]}\"",
# "start=\"#{builder.multipart[:start]}\"",
# "boundary=\"#{builder.multipart[:multipart_boundary]}\""].join("; ")
connection.headers["MIME-Version"] = "1.0"
end

connection.headers["Content-Length"] = @locals[:body].bytesize.to_s
end


end

def soap_action
Expand Down
8 changes: 7 additions & 1 deletion lib/savon/options.rb
Original file line number Diff line number Diff line change
Expand Up @@ -397,7 +397,8 @@ def initialize(options = {})
:advanced_typecasting => true,
:response_parser => :nokogiri,
:multipart => false,
:body => false
:body => false,
:mtom => false
}

super defaults.merge(options)
Expand Down Expand Up @@ -460,6 +461,11 @@ def attachments(attachments)
@options[:attachments] = attachments
end

# Instruct Savon to send attachments using MTOM https://www.w3.org/TR/soap12-mtom/
def mtom(mtom)
@options[:mtom] = mtom
end

# Value of the SOAPAction HTTP header.
def soap_action(soap_action)
@options[:soap_action] = soap_action
Expand Down
2 changes: 1 addition & 1 deletion lib/savon/request_logger.rb
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ def headers_to_log(headers)
end

def body_to_log(body)
LogMessage.new(body, @globals[:filters], @globals[:pretty_print_xml]).to_s
LogMessage.new(body, @globals[:filters], @globals[:pretty_print_xml]).to_s.force_encoding(@globals[:encoding])
end

end
Expand Down

0 comments on commit 201d799

Please sign in to comment.