From ff1b89a96d0f103ff0c917c458ddd3e36e9b3718 Mon Sep 17 00:00:00 2001 From: nahi Date: Tue, 6 Jan 2004 02:20:51 +0000 Subject: * import soap4r/1.5.2; * lib/soap/{attachment.rb,baseData.rb,encodingstyle/soapHandler.rb}: introduce SOAPExternalReference class as a referenct to SOAPEnvelope external content. * lib/soap/{attachment.rb,mimemessage.rb}: great SwA (SOAP messages with Attachments) support code by Jamie Herre. * lib/soap/{element.rb,marshal.rb,parser.rb,processor.rb, streamHandler.rb,wsdlDriver.rb}: SwA support. * lib/soap/rpc/{cgistub.rb,driver.rb,element.rb,proxy.rb,router.rb, soaplet.rb}: SwA support and refactoring. * lib/soap/generator.rb, lib/soap/mapping/mapping.rb: follow SOAPReference#initialize signature change. * lib/soap/mapping/factory.rb: deleted unused methods. * lib/soap/mapping/rubytypeFactory.rb: do no ignore case while xsi:type string <-> Ruby class name matching. * lib/xsd/datatypes.rb: check the smallest positive non-zero single-precision float exactly instead of packing with "f". [ruby-talk:88822] * test/soap/test_basetype.rb, test/xsd/test_xsd.rb: use 1.402e-45, not 1.4e-45. 1.4e-45 is smaller than 2 ** -149... * test/soap/test_basetype.rb, test/soap/marshal/test_marshal.rb, test/xsd/test_xsd.rb: use "(-1.0 / (1.0 / 0.0))" instead of "-0.0". * test/soap/test_streamhandler.rb: revert to the previous test that warns "basic_auth unsupported under net/http". git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@5384 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- lib/soap/rpc/cgistub.rb | 40 +++++++++++------------- lib/soap/rpc/driver.rb | 12 ++++++-- lib/soap/rpc/element.rb | 5 ++- lib/soap/rpc/proxy.rb | 52 +++++++++++++++++++++++++------ lib/soap/rpc/router.rb | 82 +++++++++++++++++++++++++++++++++++++++++-------- lib/soap/rpc/soaplet.rb | 28 ++++++++--------- 6 files changed, 156 insertions(+), 63 deletions(-) (limited to 'lib/soap/rpc') diff --git a/lib/soap/rpc/cgistub.rb b/lib/soap/rpc/cgistub.rb index 2377f343b5..4fc8b98cee 100644 --- a/lib/soap/rpc/cgistub.rb +++ b/lib/soap/rpc/cgistub.rb @@ -40,7 +40,6 @@ class CGIStub < Logger::Application @method = ENV['REQUEST_METHOD'] @size = ENV['CONTENT_LENGTH'].to_i || 0 @contenttype = ENV['CONTENT_TYPE'] - @charset = nil @soapaction = ENV['HTTP_SOAPAction'] @source = stream @body = nil @@ -48,7 +47,6 @@ class CGIStub < Logger::Application def init validate - @charset = StreamHandler.parse_media_type(@contenttype) @body = @source.read(@size) self end @@ -61,8 +59,8 @@ class CGIStub < Logger::Application @soapaction end - def charset - @charset + def contenttype + @contenttype end def to_s @@ -142,8 +140,8 @@ class CGIStub < Logger::Application @router.add_method(receiver, qname, nil, name, param_def) end - def route(request_string, charset) - @router.route(request_string, charset) + def route(conn_data) + @router.route(conn_data) end def create_fault_response(e) @@ -157,32 +155,30 @@ private httpversion = WEBrick::HTTPVersion.new('1.0') @response = WEBrick::HTTPResponse.new({:HTTPVersion => httpversion}) + conn_data = nil begin log(INFO) { "Received a request from '#{ @remote_user }@#{ @remote_host }'." } # SOAP request parsing. @request = SOAPRequest.new.init @response['Status'] = 200 - req_charset = @request.charset - req_string = @request.dump - log(DEBUG) { "XML Request: #{req_string}" } - res_string, is_fault = route(req_string, req_charset) - log(DEBUG) { "XML Response: #{res_string}" } - - @response['Cache-Control'] = 'private' - if req_charset - @response['content-type'] = "#{@mediatype}; charset=\"#{req_charset}\"" - else - @response['content-type'] = @mediatype - end - if is_fault + conn_data = ::SOAP::StreamHandler::ConnectionData.new + conn_data.receive_string = @request.dump + conn_data.receive_contenttype = @request.contenttype + log(DEBUG) { "XML Request: #{conn_data.receive_string}" } + conn_data = route(conn_data) + log(DEBUG) { "XML Response: #{conn_data.send_string}" } + if conn_data.is_fault @response['Status'] = 500 end - @response.body = res_string + @response['Cache-Control'] = 'private' + @response.body = conn_data.send_string + @response['content-type'] = conn_data.send_contenttype rescue Exception - res_string = create_fault_response($!) + conn_data = create_fault_response($!) @response['Cache-Control'] = 'private' - @response['content-type'] = @mediatype @response['Status'] = 500 + @response.body = conn_data.send_string + @response['content-type'] = conn_data.send_contenttype || @mediatype ensure buf = '' @response.send_response(buf) diff --git a/lib/soap/rpc/driver.rb b/lib/soap/rpc/driver.rb index dd433ca33f..655174cf33 100644 --- a/lib/soap/rpc/driver.rb +++ b/lib/soap/rpc/driver.rb @@ -180,15 +180,21 @@ private def invoke(headers, body) set_wiredump_file_base(body.elename.name) - @proxy.invoke(headers, body) + env = @proxy.invoke(headers, body) + if env.nil? + return nil, nil + else + return env.header, env.body + end end def call(name, *params) set_wiredump_file_base(name) # Convert parameters: params array => SOAPArray => members array params = Mapping.obj2soap(params, @mapping_registry).to_a - header, body = @proxy.call(nil, name, *params) - raise EmptyResponseError.new("Empty response.") unless body + env = @proxy.call(nil, name, *params) + raise EmptyResponseError.new("Empty response.") unless env + header, body = env.header, env.body begin @proxy.check_fault(body) rescue SOAP::FaultError => e diff --git a/lib/soap/rpc/element.rb b/lib/soap/rpc/element.rb index 395823ab00..8a2f319293 100644 --- a/lib/soap/rpc/element.rb +++ b/lib/soap/rpc/element.rb @@ -43,7 +43,7 @@ class SOAPBody < SOAPStruct end def void? - root_node.nil? # || root_node.is_a?(SOAPNil) + root_node.nil? end def fault @@ -113,6 +113,7 @@ class SOAPMethod < SOAPStruct params.each do |param, data| @inparam[param] = data data.elename.name = param + data.parent = self end end @@ -226,6 +227,8 @@ class SOAPMethodResponse < SOAPMethod def retval=(retval) @retval = retval @retval.elename = @retval.elename.dup_name(@retval_name || 'return') + retval.parent = self + retval end def each diff --git a/lib/soap/rpc/proxy.rb b/lib/soap/rpc/proxy.rb index 5825a27138..7d9dbe519e 100644 --- a/lib/soap/rpc/proxy.rb +++ b/lib/soap/rpc/proxy.rb @@ -12,6 +12,7 @@ require 'soap/mapping' require 'soap/rpc/rpc' require 'soap/rpc/element' require 'soap/streamHandler' +require 'soap/mimemessage' module SOAP @@ -79,7 +80,6 @@ public raise SOAP::RPC::MethodDefinitionError.new( "Method: #{ name } not defined.") end - Request.new(method, values) end @@ -91,21 +91,30 @@ public req_body = SOAPBody.new(req_body) end opt = create_options - send_string = Processor.marshal(req_header, req_body, opt) - data = @streamhandler.send(send_string, soapaction) - if data.receive_string.empty? + opt[:external_content] = nil + req_env = SOAPEnvelope.new(req_header, req_body) + send_string = Processor.marshal(req_env, opt) + conn_data = StreamHandler::ConnectionData.new(send_string) + if ext = opt[:external_content] + mime = MIMEMessage.new + ext.each do |k, v| + mime.add_attachment(v.data) + end + mime.add_part(conn_data.send_string + "\r\n") + mime.close + conn_data.send_string = mime.content_str + conn_data.send_contenttype = mime.headers['content-type'].str + end + conn_data = @streamhandler.send(conn_data, soapaction) + if conn_data.receive_string.empty? return nil, nil end - opt = create_options - opt[:charset] = @mandatorycharset || - StreamHandler.parse_media_type(data.receive_contenttype) - res_header, res_body = Processor.unmarshal(data.receive_string, opt) - return res_header, res_body + unmarshal(conn_data, opt) end def call(headers, name, *values) req = create_request(name, *values) - return invoke(headers, req.method, req.method.soapaction || @soapaction) + invoke(headers, req.method, req.method.soapaction || @soapaction) end def check_fault(body) @@ -116,6 +125,29 @@ public private + def unmarshal(conn_data, opt) + contenttype = conn_data.receive_contenttype + if /#{MIMEMessage::MultipartContentType}/i =~ contenttype + opt[:external_content] = {} + mime = MIMEMessage.parse("Content-Type: " + contenttype, + conn_data.receive_string) + mime.parts.each do |part| + value = Attachment.new(part.content) + value.contentid = part.contentid + obj = SOAPAttachment.new(value) + opt[:external_content][value.contentid] = obj if value.contentid + end + opt[:charset] = @mandatorycharset || + StreamHandler.parse_media_type(mime.root.headers['content-type'].str) + env = Processor.unmarshal(mime.root.content, opt) + else + opt[:charset] = @mandatorycharset || + ::SOAP::StreamHandler.parse_media_type(contenttype) + env = Processor.unmarshal(conn_data.receive_string, opt) + end + env + end + def create_header(headers) header = SOAPHeader.new() headers.each do |content, mustunderstand, encodingstyle| diff --git a/lib/soap/rpc/router.rb b/lib/soap/rpc/router.rb index 527ec05768..12622c72b1 100644 --- a/lib/soap/rpc/router.rb +++ b/lib/soap/rpc/router.rb @@ -11,6 +11,8 @@ require 'soap/processor' require 'soap/mapping' require 'soap/rpc/rpc' require 'soap/rpc/element' +require 'soap/streamHandler' +require 'soap/mimemessage' module SOAP @@ -47,42 +49,96 @@ class Router end # Routing... - def route(soap_string, charset = nil) - opt = options - opt[:charset] = charset - is_fault = false + #def route(soap_string, charset = nil) + def route(conn_data) + soap_response = nil begin - header, body = Processor.unmarshal(soap_string, opt) + env = unmarshal(conn_data) + if env.nil? + raise ArgumentError.new("Illegal SOAP marshal format.") + end # So far, header is omitted... - soap_request = body.request + soap_request = env.body.request unless soap_request.is_a?(SOAPStruct) raise RPCRoutingError.new("Not an RPC style.") end soap_response = dispatch(soap_request) rescue Exception soap_response = fault($!) - is_fault = true + conn_data.is_fault = true end + opt = options + opt[:external_content] = nil header = SOAPHeader.new body = SOAPBody.new(soap_response) - response_string = Processor.marshal(header, body, opt) - - return response_string, is_fault + env = SOAPEnvelope.new(header, body) + response_string = Processor.marshal(env, opt) + conn_data.send_string = response_string + if ext = opt[:external_content] + mime = MIMEMessage.new + ext.each do |k, v| + mime.add_attachment(v.data) + end + mime.add_part(conn_data.send_string + "\r\n") + mime.close + conn_data.send_string = mime.content_str + conn_data.send_contenttype = mime.headers['content-type'].str + end + conn_data end # Create fault response string. def create_fault_response(e, charset = nil) header = SOAPHeader.new - soap_response = fault(e) - body = SOAPBody.new(soap_response) + body = SOAPBody.new(fault(e)) + env = SOAPEnvelope.new(header, body) opt = options + opt[:external_content] = nil opt[:charset] = charset - Processor.marshal(header, body, opt) + response_string = Processor.marshal(env, opt) + conn_data = StreamHandler::ConnectionData.new(response_string) + conn_data.is_fault = true + if ext = opt[:external_content] + mime = MIMEMessage.new + ext.each do |k, v| + mime.add_attachment(v.data) + end + mime.add_part(conn_data.send_string + "\r\n") + mime.close + conn_data.send_string = mime.content_str + conn_data.send_contenttype = mime.headers['content-type'].str + end + conn_data end private + def unmarshal(conn_data) + opt = options + contenttype = conn_data.receive_contenttype + if /#{MIMEMessage::MultipartContentType}/i =~ contenttype + opt[:external_content] = {} + mime = MIMEMessage.parse("Content-Type: " + contenttype, + conn_data.receive_string) + mime.parts.each do |part| + value = Attachment.new(part.content) + value.contentid = part.contentid + obj = SOAPAttachment.new(value) + opt[:external_content][value.contentid] = obj if value.contentid + end + opt[:charset] = + StreamHandler.parse_media_type(mime.root.headers['content-type'].str) + env = Processor.unmarshal(mime.root.content, opt) + else + opt[:charset] = ::SOAP::StreamHandler.parse_media_type(contenttype) + env = Processor.unmarshal(conn_data.receive_string, opt) + end + charset = opt[:charset] + conn_data.send_contenttype = "text/xml; charset=\"#{charset}\"" + env + end + # Create new response. def create_response(qname, result) name = fqname(qname) diff --git a/lib/soap/rpc/soaplet.rb b/lib/soap/rpc/soaplet.rb index 4b25c68161..e67593210d 100644 --- a/lib/soap/rpc/soaplet.rb +++ b/lib/soap/rpc/soaplet.rb @@ -67,26 +67,26 @@ public def do_POST(req, res) namespace = parse_soapaction(req.meta_vars['HTTP_SOAPACTION']) router = lookup_router(namespace) - - is_fault = false - - charset = ::SOAP::StreamHandler.parse_media_type(req['content-type']) begin - response_stream, is_fault = router.route(req.body, charset) + conn_data = ::SOAP::StreamHandler::ConnectionData.new + conn_data.receive_string = req.body + conn_data.receive_contenttype = req['content-type'] + conn_data = router.route(conn_data) + if conn_data.is_fault + res.status = WEBrick::HTTPStatus::RC_INTERNAL_SERVER_ERROR + end + res.body = conn_data.send_string + res['content-type'] = conn_data.send_contenttype rescue Exception => e - response_stream = router.create_fault_response(e) - is_fault = true + conn_data = router.create_fault_response(e) + res.status = WEBrick::HTTPStatus::RC_INTERNAL_SERVER_ERROR + res.body = conn_data.send_string + res['content-type'] = conn_data.send_contenttype || "text/xml" end - res.body = response_stream - res['content-type'] = "text/xml; charset=\"#{charset}\"" - if response_stream.is_a?(IO) + if res.body.is_a?(IO) res.chunked = true end - - if is_fault - res.status = WEBrick::HTTPStatus::RC_INTERNAL_SERVER_ERROR - end end private -- cgit v1.2.3