From 20fa0df5cd7f297b1694b75b776516b51460ba55 Mon Sep 17 00:00:00 2001 From: nahi Date: Thu, 4 Dec 2003 04:05:51 +0000 Subject: [PATCH] * lib/soap/soap.rb: add SOAP::Env module for environment repository such as HTTP_PROXY. * lib/soap/property.rb: property implementation. * lib/soap/streamHandler.rb, lib/soap/wsdlDriver.rb, lib/soap/rpc/driver.rb: use soap/property.rb. * lib/wsdl/importer.rb, lib/soap/wsdlDriver.rb, lib/soap/rpc/driver.rb: use SOAP::Env. * lib/soap/netHttpClient.rb: add basic_auth, ssl_config, and cookie management interface, but ignored for now. * lib/xsd/charset.rb: add XSD::Charset.encoding= interface to set wiredump charset explicitly. it was fixed to 'utf-8' when iconv or uconv module was found. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@5104 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- ChangeLog | 20 ++ MANIFEST | 1 + lib/soap/netHttpClient.rb | 60 +++--- lib/soap/property.rb | 232 +++++++++++++++++++++ lib/soap/rpc/driver.rb | 297 ++++++++++++++++----------- lib/soap/soap.rb | 14 +- lib/soap/streamHandler.rb | 87 ++++++-- lib/soap/wsdlDriver.rb | 300 +++++++++++++++------------- lib/wsdl/importer.rb | 11 +- lib/xsd/charset.rb | 20 +- test/soap/marshal/test_marshal.rb | 2 +- test/wsdl/datetime/test_datetime.rb | 11 +- 12 files changed, 735 insertions(+), 320 deletions(-) create mode 100644 lib/soap/property.rb diff --git a/ChangeLog b/ChangeLog index adbecd3f23..e57888f2b9 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,23 @@ +Thu Dec 4 13:04:44 2003 NAKAMURA, Hiroshi + + * lib/soap/soap.rb: add SOAP::Env module for environment repository + such as HTTP_PROXY. + + * lib/soap/property.rb: property implementation. + + * lib/soap/streamHandler.rb, lib/soap/wsdlDriver.rb, + lib/soap/rpc/driver.rb: use soap/property.rb. + + * lib/wsdl/importer.rb, lib/soap/wsdlDriver.rb, lib/soap/rpc/driver.rb: + use SOAP::Env. + + * lib/soap/netHttpClient.rb: add basic_auth, ssl_config, and cookie + management interface, but ignored for now. + + * lib/xsd/charset.rb: add XSD::Charset.encoding= interface to set + wiredump charset explicitly. it was fixed to 'utf-8' when iconv or + uconv module was found. + Thu Dec 4 10:43:58 2003 NAKAMURA Usaku * ext/dl/sym.c (rb_dlsym_guardcall): __declspec(noinline) is VC7 diff --git a/MANIFEST b/MANIFEST index 4dbe016ba7..54d55d2ff7 100644 --- a/MANIFEST +++ b/MANIFEST @@ -349,6 +349,7 @@ lib/soap/marshal.rb lib/soap/netHttpClient.rb lib/soap/parser.rb lib/soap/processor.rb +lib/soap/property.rb lib/soap/rpc/cgistub.rb lib/soap/rpc/driver.rb lib/soap/rpc/element.rb diff --git a/lib/soap/netHttpClient.rb b/lib/soap/netHttpClient.rb index 04d1937133..3eacdad69d 100644 --- a/lib/soap/netHttpClient.rb +++ b/lib/soap/netHttpClient.rb @@ -24,39 +24,31 @@ class NetHttpClient attr_accessor :proxy attr_accessor :no_proxy attr_accessor :debug_dev - attr_reader :session_manager - - class SessionManager - attr_accessor :connect_timeout - attr_accessor :send_timeout - attr_accessor :receive_timeout - end - - class Response - attr_reader :content - attr_reader :status - attr_reader :reason - attr_reader :contenttype - - def initialize(res) - @status = res.code.to_i - @reason = res.message - @contenttype = res['content-type'] - @content = res.body - end - end + attr_accessor :ssl_config # ignored for now. + attr_accessor :protocol_version # ignored for now. def initialize(proxy = nil, agent = nil) @proxy = proxy ? URI.parse(proxy) : nil @agent = agent @debug_dev = nil @session_manager = SessionManager.new - name = 'no_proxy' - @no_proxy = ENV[name] || ENV[name.upcase] + @no_proxy = nil + end + + def set_basic_auth(uri, user_id, passwd) + # ignored for now. + end + + def set_cookie_store(filename) + # ignored for now. end def reset(url) - # ignored. + # ignored for now. + end + + def reset_all + # ignored for now. end def post(url, req_body, header = {}) @@ -134,6 +126,26 @@ private false end end + + class SessionManager + attr_accessor :connect_timeout + attr_accessor :send_timeout + attr_accessor :receive_timeout + end + + class Response + attr_reader :content + attr_reader :status + attr_reader :reason + attr_reader :contenttype + + def initialize(res) + @status = res.code.to_i + @reason = res.message + @contenttype = res['content-type'] + @content = res.body + end + end end diff --git a/lib/soap/property.rb b/lib/soap/property.rb new file mode 100644 index 0000000000..84fa876cae --- /dev/null +++ b/lib/soap/property.rb @@ -0,0 +1,232 @@ +# soap/property.rb: SOAP4R - Property implementation. +# Copyright (C) 2003 NAKAMURA, Hiroshi . + +# This program is copyrighted free software by NAKAMURA, Hiroshi. You can +# redistribute it and/or modify it under the same terms of Ruby's license; +# either the dual license version in 2003, or any later version. + + +module SOAP + + +class Property + include Enumerable + + def initialize + @store = Hash.new + @hook = Hash.new + @self_hook = Array.new + @locked = false + end + + # name: a Symbol, String or an Array + def [](name) + referent(name_to_a(name)) + end + + # name: a Symbol, String or an Array + # value: an Object + def []=(name, value) + hooks = assign(name_to_a(name), value) + normalized_name = normalize_name(name) + hooks.each do |hook| + hook.call(normalized_name, value) + end + value + end + + # value: an Object + # key is generated by property + def <<(value) + self[generate_new_key] = value + end + + # name: a Symbol, String or an Array. nil means hook to the root. + # hook: block which will be called with 2 args, name and value + def add_hook(name = nil, &hook) + if name.nil? + assign_self_hook(hook) + else + assign_hook(name_to_a(name), hook) + end + end + + def each + @store.each do |key, value| + yield(key, value) + end + end + + def empty? + @store.empty? + end + + def keys + @store.keys + end + + def values + @store.values + end + + def lock(cascade = false) + if cascade + each_key do |key| + key.lock(cascade) + end + end + @locked = true + self + end + + def unlock(cascade = false) + @locked = false + if cascade + each_key do |key| + key.unlock(cascade) + end + end + self + end + + def locked? + @locked + end + +protected + + def referent(ary) + key, rest = location_pair(ary) + if rest.empty? + local_referent(key) + else + deref_key(key).referent(rest) + end + end + + def assign(ary, value) + key, rest = location_pair(ary) + if rest.empty? + local_assign(key, value) + local_hook(key) + else + local_hook(key) + deref_key(key).assign(rest, value) + end + end + + def assign_hook(ary, hook) + key, rest = location_pair(ary) + if rest.empty? + local_assign_hook(key, hook) + else + deref_key(key).assign_hook(rest, hook) + end + end + + def assign_self_hook(hook) + check_lock(nil) + @self_hook << hook + end + +private + + def each_key + self.each do |key, value| + if propkey?(value) + yield(value) + end + end + end + + def deref_key(key) + check_lock(key) + ref = @store[key] ||= self.class.new + unless propkey?(ref) + raise ArgumentError.new("key `#{key}' already defined as a value") + end + ref + end + + def local_referent(key) + check_lock(key) + if propkey?(@store[key]) and @store[key].locked? + raise TypeError.new("cannot split any key from locked property") + end + @store[key] + end + + def local_assign(key, value) + check_lock(key) + if @locked + if propkey?(value) + raise TypeError.new("cannot add any key to locked property") + elsif propkey?(@store[key]) + raise TypeError.new("cannot override any key in locked property") + end + end + @store[key] = value + end + + def local_assign_hook(key, hook) + check_lock(key) + @store[key] ||= nil + (@hook[key] ||= []) << hook + end + + NO_HOOK = [].freeze + def local_hook(key) + @self_hook + (@hook[key] || NO_HOOK) + end + + def check_lock(key) + if @locked and (key.nil? or !@store.key?(key)) + raise TypeError.new("cannot add any key to locked property") + end + end + + def propkey?(value) + value.is_a?(::SOAP::Property) + end + + def name_to_a(name) + case name + when Symbol + [name] + when String + name.split(/\./) + when Array + name + else + raise ArgumentError.new("Unknown name #{name}(#{name.class})") + end + end + + def location_pair(ary) + name, *rest = *ary + key = to_key(name) + return key, rest + end + + def normalize_name(name) + name_to_a(name).collect { |key| to_key(key) }.join('.') + end + + def to_key(name) + name.to_s.downcase.intern + end + + def generate_new_key + if @store.empty? + "0" + else + (key_max + 1).to_s + end + end + + def key_max + (@store.keys.max { |l, r| l.to_s.to_i <=> r.to_s.to_i }).to_s.to_i + end +end + + +end diff --git a/lib/soap/rpc/driver.rb b/lib/soap/rpc/driver.rb index 739c8774d4..e6ca3f39d3 100644 --- a/lib/soap/rpc/driver.rb +++ b/lib/soap/rpc/driver.rb @@ -12,6 +12,7 @@ require 'soap/rpc/rpc' require 'soap/rpc/proxy' require 'soap/rpc/element' require 'soap/streamHandler' +require 'soap/property' module SOAP @@ -19,91 +20,86 @@ module RPC class Driver -public class EmptyResponseError < Error; end - attr_accessor :mapping_registry - attr_accessor :soapaction - attr_reader :wiredump_dev - attr_reader :wiredump_file_base - attr_reader :streamhandler - - def initialize(endpoint_url, namespace, soapaction = nil) - @namespace = namespace - @mapping_registry = nil # for unmarshal - @soapaction = soapaction - @wiredump_dev = nil - @wiredump_file_base = nil - name = 'http_proxy' - @httpproxy = ENV[name] || ENV[name.upcase] - @streamhandler = HTTPPostStreamHandler.new(endpoint_url, @httpproxy, - XSD::Charset.encoding_label) - @proxy = Proxy.new(@streamhandler, @soapaction) - @proxy.allow_unqualified_element = true + class << self + def __attr_proxy(symbol, assignable = false) + name = symbol.to_s + module_eval <<-EOD + def #{name} + @servant.#{name} + end + EOD + if assignable + module_eval <<-EOD + def #{name}=(rhs) + @servant.#{name} = rhs + end + EOD + end + end end - def inspect - "#<#{self.class}:#{@streamhandler.inspect}>" - end - - def endpoint_url - @streamhandler.endpoint_url - end - - def endpoint_url=(endpoint_url) - @streamhandler.endpoint_url = endpoint_url - @streamhandler.reset - end - - def wiredump_dev=(dev) - @wiredump_dev = dev - @streamhandler.wiredump_dev = @wiredump_dev - @streamhandler.reset - end - - def wiredump_file_base=(base) - @wiredump_file_base = base - end + __attr_proxy :options + __attr_proxy :endpoint_url, true + __attr_proxy :mapping_registry, true + __attr_proxy :soapaction, true + __attr_proxy :default_encodingstyle, true def httpproxy - @httpproxy + @servant.options["protocol.http.proxy"] end def httpproxy=(httpproxy) - @httpproxy = httpproxy - @streamhandler.proxy = @httpproxy - @streamhandler.reset + @servant.options["protocol.http.proxy"] = httpproxy + end + + def wiredump_dev + @servant.options["protocol.http.wiredump_dev"] + end + + def wiredump_dev=(wiredump_dev) + @servant.options["protocol.http.wiredump_dev"] = wiredump_dev end def mandatorycharset - @proxy.mandatorycharset + @servant.options["protocol.mandatorycharset"] end def mandatorycharset=(mandatorycharset) - @proxy.mandatorycharset = mandatorycharset + @servant.options["protocol.mandatorycharset"] = mandatorycharset end - def default_encodingstyle - @proxy.default_encodingstyle + def wiredump_file_base + @servant.options["protocol.wiredump_file_base"] end - def default_encodingstyle=(encodingstyle) - @proxy.default_encodingstyle = encodingstyle + def wiredump_file_base=(wiredump_file_base) + @servant.options["protocol.wiredump_file_base"] = wiredump_file_base end + def initialize(endpoint_url, namespace, soapaction = nil) + @servant = Servant__.new(self, endpoint_url, namespace) + @servant.soapaction = soapaction + @proxy = @servant.proxy + if env_httpproxy = ::SOAP::Env::HTTP_PROXY + @servant.options["protocol.http.proxy"] = env_httpproxy + end + if env_no_proxy = ::SOAP::Env::NO_PROXY + @servant.options["protocol.http.no_proxy"] = env_no_proxy + end + end - ### - ## Method definition interfaces. - # - # params: [[param_def...]] or [paramname, paramname, ...] - # param_def: See proxy.rb. Sorry. + def inspect + "#<#{self.class}:#{@servant.streamhandler.inspect}>" + end def add_method(name, *params) - add_method_with_soapaction_as(name, name, @soapaction, *params) + add_method_with_soapaction_as(name, name, @servant.soapaction, *params) end def add_method_as(name, name_as, *params) - add_method_with_soapaction_as(name, name_as, @soapaction, *params) + add_method_with_soapaction_as(name, name_as, @servant.soapaction, *params) end def add_method_with_soapaction(name, soapaction, *params) @@ -116,72 +112,147 @@ public else SOAPMethod.create_param_def(params) end - qname = XSD::QName.new(@namespace, name_as) - @proxy.add_method(qname, soapaction, name, param_def) - add_rpc_method_interface(name, param_def) - end - - - ### - ## Driving interface. - # - def invoke(headers, body) - if @wiredump_file_base - @streamhandler.wiredump_file_base = - @wiredump_file_base + '_' << body.elename.name - end - @proxy.invoke(headers, body) - end - - def call(name, *params) - # Convert parameters: params array => SOAPArray => members array - params = Mapping.obj2soap(params, @mapping_registry).to_a - if @wiredump_file_base - @streamhandler.wiredump_file_base = @wiredump_file_base + '_' << name - end - - # Then, call @proxy.call like the following. - header, body = @proxy.call(nil, name, *params) - unless body - raise EmptyResponseError.new("Empty response.") - end - - begin - @proxy.check_fault(body) - rescue SOAP::FaultError => e - Mapping.fault2exception(e) - end - - ret = body.response ? Mapping.soap2obj(body.response, @mapping_registry) : nil - if body.outparams - outparams = body.outparams.collect { |outparam| Mapping.soap2obj(outparam) } - return [ret].concat(outparams) - else - return ret - end + @servant.add_method(name_as, soapaction, name, param_def) end def reset_stream - @streamhandler.reset + @servant.streamhandler.reset + end + + def invoke(headers, body) + @servant.invoke(headers, body) + end + + def call(name, *params) + @servant.call(name, *params) end private def add_rpc_method_interface(name, param_def) - param_names = [] - i = 0 - @proxy.method[name].each_param_name(RPC::SOAPMethod::IN, - RPC::SOAPMethod::INOUT) do |param_name| - i += 1 - param_names << "arg#{ i }" + @servant.add_rpc_method_interface(name, param_def) + end + + class Servant__ + attr_reader :options + attr_reader :streamhandler + attr_reader :proxy + + def initialize(host, endpoint_url, namespace) + @host = host + @namespace = namespace + @mapping_registry = nil + @soapaction = nil + @wiredump_file_base = nil + @options = ::SOAP::Property.new + set_options + @streamhandler = HTTPPostStreamHandler.new(endpoint_url, + @options["protocol.http"] ||= ::SOAP::Property.new) + @proxy = Proxy.new(@streamhandler, @soapaction) + @proxy.allow_unqualified_element = true end - callparam = (param_names.collect { |pname| ", " + pname }).join - self.instance_eval <<-EOS - def #{ name }(#{ param_names.join(", ") }) - call("#{ name }"#{ callparam }) + def endpoint_url + @streamhandler.endpoint_url + end + + def endpoint_url=(endpoint_url) + @streamhandler.endpoint_url = endpoint_url + @streamhandler.reset + end + + def mapping_registry + @mapping_registry + end + + def mapping_registry=(mapping_registry) + @mapping_registry = mapping_registry + end + + def soapaction + @soapaction + end + + def soapaction=(soapaction) + @soapaction = soapaction + end + + def default_encodingstyle + @proxy.default_encodingstyle + end + + def default_encodingstyle=(encodingstyle) + @proxy.default_encodingstyle = encodingstyle + end + + def invoke(headers, body) + set_wiredump_file_base(body.elename.name) + @proxy.invoke(headers, body) + 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 + begin + @proxy.check_fault(body) + rescue SOAP::FaultError => e + Mapping.fault2exception(e) end - EOS + + ret = body.response ? + Mapping.soap2obj(body.response, @mapping_registry) : nil + if body.outparams + outparams = body.outparams.collect { |outparam| + Mapping.soap2obj(outparam) + } + return [ret].concat(outparams) + else + return ret + end + end + + def add_method(name_as, soapaction, name, param_def) + qname = XSD::QName.new(@namespace, name_as) + @proxy.add_method(qname, soapaction, name, param_def) + add_rpc_method_interface(name, param_def) + end + + def add_rpc_method_interface(name, param_def) + param_names = [] + i = 0 + @proxy.method[name].each_param_name(RPC::SOAPMethod::IN, + RPC::SOAPMethod::INOUT) do |param_name| + i += 1 + param_names << "arg#{ i }" + end + callparam = (param_names.collect { |pname| ", " + pname }).join + @host.instance_eval <<-EOS + def #{ name }(#{ param_names.join(", ") }) + @servant.call(#{ name.dump }#{ callparam }) + end + EOS + end + + private + + def set_wiredump_file_base(name) + if @wiredump_file_base + @streamhandler.wiredump_file_base = @wiredump_file_base + "_#{ name }" + end + end + + def set_options + @options.add_hook("protocol.mandatorycharset") do |key, value| + @proxy.mandatorycharset = value + end + @options.add_hook("protocol.wiredump_file_base") do |key, value| + @wiredump_file_base = value + end + @options["protocol.http.charset"] = XSD::Charset.encoding_label + end end end diff --git a/lib/soap/soap.rb b/lib/soap/soap.rb index fcfbb2ef2b..b082823181 100644 --- a/lib/soap/soap.rb +++ b/lib/soap/soap.rb @@ -13,7 +13,7 @@ require 'xsd/charset' module SOAP -Version = '1.5.1' +Version = '1.5.2' EnvelopeNamespace = 'http://schemas.xmlsoap.org/soap/envelope/' EncodingNamespace = 'http://schemas.xmlsoap.org/soap/encoding/' @@ -90,12 +90,22 @@ class FaultError < Error def to_s str = nil - if @faultstring && @faultstring.respond_to?('data') + if @faultstring and @faultstring.respond_to?('data') str = @faultstring.data end str || '(No faultstring)' end end +module Env + def self.getenv(name) + ENV[name.downcase] || ENV[name] + end + + use_proxy = getenv('soap_use_proxy') == 'on' + HTTP_PROXY = use_proxy ? getenv('http_proxy') : nil + NO_PROXY = use_proxy ? getenv('no_proxy') : nil +end + end diff --git a/lib/soap/streamHandler.rb b/lib/soap/streamHandler.rb index c5c0661455..7cf6ce53ee 100644 --- a/lib/soap/streamHandler.rb +++ b/lib/soap/streamHandler.rb @@ -7,6 +7,7 @@ require 'soap/soap' +require 'soap/property' module SOAP @@ -76,31 +77,25 @@ class HTTPPostStreamHandler < StreamHandler public - attr_accessor :wiredump_dev - attr_accessor :wiredump_file_base - attr_accessor :charset attr_reader :client + attr_accessor :wiredump_file_base NofRetry = 10 # [times] - def initialize(endpoint_url, proxy = nil, charset = nil) + def initialize(endpoint_url, options) super(endpoint_url) - @proxy = proxy || ENV['http_proxy'] || ENV['HTTP_PROXY'] - @charset = charset || XSD::Charset.charset_label($KCODE) - @wiredump_dev = nil # Set an IO to get wiredump. + @client = Client.new(nil, "SOAP4R/#{ Version }") @wiredump_file_base = nil - @client = Client.new(@proxy, "SOAP4R/#{ Version }") + @charset = @wiredump_dev = nil + @options = options + set_options + @client.debug_dev = @wiredump_dev end def inspect "#<#{self.class}:#{endpoint_url}>" end - def proxy=(proxy) - @proxy = proxy - @client.proxy = @proxy - end - def send(soap_string, soapaction = nil, charset = @charset) send_post(soap_string, soapaction, charset) end @@ -111,18 +106,66 @@ public private + def set_options + @client.proxy = @options["proxy"] + @options.add_hook("proxy") do |key, value| + @client.proxy = value + end + @client.no_proxy = @options["no_proxy"] + @options.add_hook("no_proxy") do |key, value| + @client.no_proxy = value + end + @client.protocol_version = @options["protocol_version"] + @options.add_hook("protocol_version") do |key, value| + @client.protocol_version = value + end + set_cookie_store_file(@options["cookie_store_file"]) + @options.add_hook("cookie_store_file") do |key, value| + set_cookie_store_file(value) + end + set_ssl_config(@options["ssl_config"]) + @options.add_hook("ssl_config") do |key, value| + set_ssl_config(@options["ssl_config"]) + end + @charset = @options["charset"] || XSD::Charset.charset_label($KCODE) + @options.add_hook("charset") do |key, value| + @charset = value + end + @wiredump_dev = @options["wiredump_dev"] + @options.add_hook("wiredump_dev") do |key, value| + @wiredump_dev = value + @client.debug_dev = @wiredump_dev + end + basic_auth = @options["basic_auth"] ||= ::SOAP::Property.new + set_basic_auth(basic_auth) + basic_auth.add_hook do |key, value| + set_basic_auth(basic_auth) + end + @options.lock(true) + basic_auth.unlock + end + + def set_basic_auth(basic_auth) + basic_auth.values.each do |url, userid, passwd| + @client.set_basic_auth(url, userid, passwd) + end + end + + def set_cookie_store_file(value) + return unless value + raise NotImplementedError.new + end + + def set_ssl_config(value) + return unless value + raise NotImplementedError.new + end + def send_post(soap_string, soapaction, charset) data = ConnectionData.new data.send_string = soap_string data.send_contenttype = StreamHandler.create_media_type(charset) - wiredump_dev = if @wiredump_dev && @wiredump_dev.respond_to?("<<") - @wiredump_dev - else - nil - end - @client.debug_dev = wiredump_dev - if @wiredump_file_base filename = @wiredump_file_base + '_request.xml' f = File.open(filename, "w") @@ -134,14 +177,14 @@ private extra['Content-Type'] = data.send_contenttype extra['SOAPAction'] = "\"#{ soapaction }\"" - wiredump_dev << "Wire dump:\n\n" if wiredump_dev + @wiredump_dev << "Wire dump:\n\n" if @wiredump_dev begin res = @client.post(@endpoint_url, soap_string, extra) rescue @client.reset(@endpoint_url) raise end - wiredump_dev << "\n\n" if wiredump_dev + @wiredump_dev << "\n\n" if @wiredump_dev receive_string = res.content diff --git a/lib/soap/wsdlDriver.rb b/lib/soap/wsdlDriver.rb index d629aa12ce..3931c7c514 100644 --- a/lib/soap/wsdlDriver.rb +++ b/lib/soap/wsdlDriver.rb @@ -37,7 +37,7 @@ class WSDLDriverFactory "#<#{self.class}:#{@wsdl.name}>" end - def create_driver(servicename = nil, portname = nil, opt = {}) + def create_driver(servicename = nil, portname = nil) service = if servicename @wsdl.service(XSD::QName.new(@wsdl.targetnamespace, servicename)) else @@ -57,7 +57,7 @@ class WSDLDriverFactory if port.soap_address.nil? raise FactoryError.new("soap:address element not found in WSDL.") end - WSDLDriver.new(@wsdl, port, @logdev, opt) + WSDLDriver.new(@wsdl, port, @logdev) end # Backward compatibility. @@ -90,22 +90,62 @@ class WSDLDriver end end - __attr_proxy :opt - __attr_proxy :logdev, true + __attr_proxy :options + __attr_proxy :endpoint_url, true __attr_proxy :mapping_registry, true # for RPC unmarshal __attr_proxy :wsdl_mapping_registry, true # for RPC marshal - __attr_proxy :endpoint_url, true - __attr_proxy :wiredump_dev, true - __attr_proxy :wiredump_file_base, true - __attr_proxy :httpproxy, true - __attr_proxy :mandatorycharset, true # force using charset - __attr_proxy :default_encodingstyle, true __attr_proxy :allow_unqualified_element, true __attr_proxy :generate_explicit_type, true + def httpproxy + @servant.options["protocol.http.proxy"] + end + + def httpproxy=(httpproxy) + @servant.options["protocol.http.proxy"] = httpproxy + end + + def wiredump_dev + @servant.options["protocol.http.wiredump_dev"] + end + + def wiredump_dev=(wiredump_dev) + @servant.options["protocol.http.wiredump_dev"] = wiredump_dev + end + + def mandatorycharset + @servant.options["protocol.mandatorycharset"] + end + + def mandatorycharset=(mandatorycharset) + @servant.options["protocol.mandatorycharset"] = mandatorycharset + end + + def wiredump_file_base + @servant.options["protocol.wiredump_file_base"] + end + + def wiredump_file_base=(wiredump_file_base) + @servant.options["protocol.wiredump_file_base"] = wiredump_file_base + end + + def initialize(wsdl, port, logdev) + @servant = Servant__.new(self, wsdl, port, logdev) + if env_httpproxy = ::SOAP::Env::HTTP_PROXY + @servant.options["protocol.http.proxy"] = env_httpproxy + end + if env_httpproxy = ::SOAP::Env::NO_PROXY + @servant.options["protocol.http.no_proxy"] = env_httpproxy + end + end + + def inspect + "#<#{self.class}:#{@servant.port.name}>" + end + def reset_stream - @servant.reset_stream + @servant.streamhandler.reset end # Backward compatibility. @@ -115,124 +155,43 @@ class WSDLDriver include Logger::Severity include SOAP - attr_reader :wsdl + attr_reader :options + attr_reader :streamhandler attr_reader :port - attr_reader :opt - attr_accessor :logdev + attr_accessor :mapping_registry attr_accessor :wsdl_mapping_registry - attr_reader :wiredump_dev - attr_reader :wiredump_file_base - attr_reader :httpproxy - attr_accessor :mandatorycharset - attr_accessor :default_encodingstyle attr_accessor :allow_unqualified_element attr_accessor :generate_explicit_type - class Mapper - def initialize(elements, types) - @elements = elements - @types = types - end - - def obj2ele(obj, name) - if ele = @elements[name] - _obj2ele(obj, ele) - elsif type = @types[name] - obj2type(obj, type) - else - raise RuntimeError.new("Cannot find name #{name} in schema.") - end - end - - def ele2obj(ele, *arg) - raise NotImplementedError.new - end - - private - - def _obj2ele(obj, ele) - o = nil - if ele.type - if type = @types[ele.type] - o = obj2type(obj, type) - elsif type = TypeMap[ele.type] - o = base2soap(obj, type) - else - raise RuntimeError.new("Cannot find type #{ele.type}.") - end - o.elename = ele.name - elsif ele.local_complextype - o = SOAPElement.new(ele.name) - ele.local_complextype.each_element do |child_name, child_ele| - o.add(_obj2ele(find_attribute(obj, child_name.name), child_ele)) - end - else - raise RuntimeError.new("Illegal schema?") - end - o - end - - def obj2type(obj, type) - o = SOAPElement.new(type.name) - type.each_element do |child_name, child_ele| - o.add(_obj2ele(find_attribute(obj, child_name.name), child_ele)) - end - o - end - - def _ele2obj(ele) - raise NotImplementedError.new - end - - def base2soap(obj, type) - soap_obj = nil - if type <= XSD::XSDString - soap_obj = type.new(XSD::Charset.is_ces(obj, $KCODE) ? - XSD::Charset.encoding_conv(obj, $KCODE, XSD::Charset.encoding) : obj) - else - soap_obj = type.new(obj) - end - soap_obj - end - - def find_attribute(obj, attr_name) - if obj.respond_to?(attr_name) - obj.__send__(attr_name) - elsif obj.is_a?(Hash) - obj[attr_name] || obj[attr_name.intern] - else - obj.instance_eval("@#{ attr_name }") - end - end - end - - def initialize(host, wsdl, port, logdev, opt) + def initialize(host, wsdl, port, logdev) @host = host @wsdl = wsdl @port = port @logdev = logdev - @opt = opt.dup + + @options = ::SOAP::Property.new + set_options @mapping_registry = nil # for rpc unmarshal @wsdl_mapping_registry = nil # for rpc marshal - @wiredump_dev = nil + @default_encodingstyle = EncodingNamespace + @allow_unqualified_element = true + @generate_explicit_type = false @wiredump_file_base = nil @mandatorycharset = nil @wsdl_elements = @wsdl.collect_elements @wsdl_types = @wsdl.collect_complextypes - @rpc_decode_typemap = @wsdl_types + @wsdl.soap_rpc_complextypes(port.find_binding) + @rpc_decode_typemap = @wsdl_types + + @wsdl.soap_rpc_complextypes(port.find_binding) @wsdl_mapping_registry = Mapping::WSDLRegistry.new(@rpc_decode_typemap) @doc_mapper = Mapper.new(@wsdl_elements, @wsdl_types) - @default_encodingstyle = EncodingNamespace - @allow_unqualified_element = true - @generate_explicit_type = false - - create_streamhandler(@port.soap_address.location, - ENV['http_proxy'] || ENV['HTTP_PROXY']) - @operations = {} + endpoint_url = @port.soap_address.location + @streamhandler = HTTPPostStreamHandler.new(endpoint_url, + @options["protocol.http"] ||= ::SOAP::Property.new) # Convert a map which key is QName, to a Hash which key is String. + @operations = {} @port.inputoperation_map.each do |op_name, op_info| @operations[op_name.name] = op_info add_method_interface(op_info) @@ -246,27 +205,6 @@ class WSDLDriver def endpoint_url=(endpoint_url) @streamhandler.endpoint_url = endpoint_url @streamhandler.reset - log(DEBUG) { "endpoint_url=: set endpoint_url #{ endpoint_url }." } - end - - def wiredump_dev=(dev) - @wiredump_dev = dev - @streamhandler.wiredump_dev = @wiredump_dev - @streamhandler.reset - end - - def wiredump_file_base=(base) - @wiredump_file_base = base - end - - def httpproxy=(httpproxy) - @streamhandler.proxy = httpproxy - @streamhandler.reset - log(DEBUG) { "httpproxy=: set httpproxy #{ httpproxy }." } - end - - def reset_stream - @streamhandler.reset end def rpc_send(method_name, *params) @@ -330,12 +268,6 @@ class WSDLDriver private - def create_streamhandler(endpoint_url, httpproxy) - @streamhandler = HTTPPostStreamHandler.new(endpoint_url, httpproxy, - XSD::Charset.encoding_label) - @streamhandler.wiredump_dev = @wiredump_dev - end - def create_method_obj(names, params) o = Object.new for idx in 0 ... params.length @@ -450,16 +382,16 @@ class WSDLDriver def add_rpc_method_interface(name, parts_names) i = 0 param_names = parts_names.collect { |orgname| i += 1; "arg#{ i }" } - callparam_str = (param_names.collect { |pname| ", " + pname }).join + callparam = (param_names.collect { |pname| ", " + pname }).join @host.instance_eval <<-EOS def #{ name }(#{ param_names.join(", ") }) - @servant.rpc_send(#{ name.dump }#{ callparam_str }) + @servant.rpc_send(#{ name.dump }#{ callparam }) end EOS end def create_options - opt = @opt.dup + opt = {} opt[:default_encodingstyle] = @default_encodingstyle opt[:allow_unqualified_element] = @allow_unqualified_element opt[:generate_explicit_type] = @generate_explicit_type @@ -469,14 +401,94 @@ class WSDLDriver def log(sev) @logdev.add(sev, nil, self.class) { yield } if @logdev end - end - def initialize(wsdl, port, logdev, opt) - @servant = Servant__.new(self, wsdl, port, logdev, opt) - end + def set_options + @options.add_hook("protocol.mandatorycharset") do |key, value| + @mandatorycharset = value + end + @options.add_hook("protocol.wiredump_file_base") do |key, value| + @wiredump_file_base = value + end + @options["protocol.http.charset"] = XSD::Charset.encoding_label + end - def inspect - "#<#{self.class}:#{@servant.port.name}>" + class Mapper + def initialize(elements, types) + @elements = elements + @types = types + end + + def obj2ele(obj, name) + if ele = @elements[name] + _obj2ele(obj, ele) + elsif type = @types[name] + obj2type(obj, type) + else + raise RuntimeError.new("Cannot find name #{name} in schema.") + end + end + + def ele2obj(ele, *arg) + raise NotImplementedError.new + end + + private + + def _obj2ele(obj, ele) + o = nil + if ele.type + if type = @types[ele.type] + o = obj2type(obj, type) + elsif type = TypeMap[ele.type] + o = base2soap(obj, type) + else + raise RuntimeError.new("Cannot find type #{ele.type}.") + end + o.elename = ele.name + elsif ele.local_complextype + o = SOAPElement.new(ele.name) + ele.local_complextype.each_element do |child_name, child_ele| + o.add(_obj2ele(find_attribute(obj, child_name.name), child_ele)) + end + else + raise RuntimeError.new("Illegal schema?") + end + o + end + + def obj2type(obj, type) + o = SOAPElement.new(type.name) + type.each_element do |child_name, child_ele| + o.add(_obj2ele(find_attribute(obj, child_name.name), child_ele)) + end + o + end + + def _ele2obj(ele) + raise NotImplementedError.new + end + + def base2soap(obj, type) + soap_obj = nil + if type <= XSD::XSDString + soap_obj = type.new(XSD::Charset.is_ces(obj, $KCODE) ? + XSD::Charset.encoding_conv(obj, $KCODE, XSD::Charset.encoding) : obj) + else + soap_obj = type.new(obj) + end + soap_obj + end + + def find_attribute(obj, attr_name) + if obj.respond_to?(attr_name) + obj.__send__(attr_name) + elsif obj.is_a?(Hash) + obj[attr_name] || obj[attr_name.intern] + else + obj.instance_eval("@#{ attr_name }") + end + end + end end end diff --git a/lib/wsdl/importer.rb b/lib/wsdl/importer.rb index d35ed5d698..df354311a1 100644 --- a/lib/wsdl/importer.rb +++ b/lib/wsdl/importer.rb @@ -8,6 +8,7 @@ require 'wsdl/info' require 'wsdl/parser' +require 'soap/soap' module WSDL @@ -27,8 +28,14 @@ class Importer if FileTest.exist?(location) content = File.open(location).read else - proxy = ENV['http_proxy'] || ENV['HTTP_PROXY'] - content = web_client.new(proxy, "WSDL4R").get_content(location) + client = web_client.new(nil, "WSDL4R") + if env_httpproxy = ::SOAP::Env::HTTP_PROXY + client.proxy = env_httpproxy + end + if env_no_proxy = ::SOAP::Env::NO_PROXY + client.no_proxy = env_no_proxy + end + content = client.get_content(location) end opt = {} # charset? begin diff --git a/lib/xsd/charset.rb b/lib/xsd/charset.rb index fc8d48e439..362f13edfc 100644 --- a/lib/xsd/charset.rb +++ b/lib/xsd/charset.rb @@ -27,18 +27,13 @@ public begin require 'xsd/iconvcharset' @encoding = 'UTF8' + sjtag = (/(mswin|bccwin|mingw|cygwin|emx)/ =~ RUBY_PLATFORM) ? 'cp932' : 'shift_jis' EncodingConvertMap[['UTF8', 'EUC' ]] = Proc.new { |str| IconvCharset.safe_iconv("euc-jp", "utf-8", str) } EncodingConvertMap[['EUC' , 'UTF8']] = Proc.new { |str| IconvCharset.safe_iconv("utf-8", "euc-jp", str) } - EncodingConvertMap[['EUC' , 'SJIS']] = Proc.new { |str| IconvCharset.safe_iconv("shift_jis", "euc-jp", str) } - if /(mswin|bccwin|mingw|cygwin|emx)/ =~ RUBY_PLATFORM - EncodingConvertMap[['UTF8', 'SJIS']] = Proc.new { |str| IconvCharset.safe_iconv("cp932", "utf-8", str) } - EncodingConvertMap[['SJIS', 'UTF8']] = Proc.new { |str| IconvCharset.safe_iconv("utf-8", "cp932", str) } - EncodingConvertMap[['SJIS', 'EUC' ]] = Proc.new { |str| IconvCharset.safe_iconv("euc-jp", "cp932", str) } - else - EncodingConvertMap[['UTF8', 'SJIS']] = Proc.new { |str| IconvCharset.safe_iconv("shift_jis", "utf-8", str) } - EncodingConvertMap[['SJIS', 'UTF8']] = Proc.new { |str| IconvCharset.safe_iconv("utf-8", "shift_jis", str) } - EncodingConvertMap[['SJIS', 'EUC' ]] = Proc.new { |str| IconvCharset.safe_iconv("euc-jp", "shift_jis", str) } - end + EncodingConvertMap[['EUC' , 'SJIS']] = Proc.new { |str| IconvCharset.safe_iconv(sjtag, "euc-jp", str) } + EncodingConvertMap[['UTF8', 'SJIS']] = Proc.new { |str| IconvCharset.safe_iconv(sjtag, "utf-8", str) } + EncodingConvertMap[['SJIS', 'UTF8']] = Proc.new { |str| IconvCharset.safe_iconv("utf-8", sjtag, str) } + EncodingConvertMap[['SJIS', 'EUC' ]] = Proc.new { |str| IconvCharset.safe_iconv("euc-jp", sjtag, str) } rescue LoadError begin require 'nkf' @@ -75,6 +70,11 @@ public @encoding end + def Charset.encoding=(encoding) + STDERR.puts("xsd charset is set to #{encoding}") if $DEBUG + @encoding = encoding + end + def Charset.encoding_label charset_label(@encoding) end diff --git a/test/soap/marshal/test_marshal.rb b/test/soap/marshal/test_marshal.rb index 9d5b706d41..9ae08c68d8 100644 --- a/test/soap/marshal/test_marshal.rb +++ b/test/soap/marshal/test_marshal.rb @@ -369,7 +369,7 @@ module MarshalTestLib class MyTime < Time; def initialize(v, *args) super(*args); @v = v; end end def test_time # once there was a bug caused by usec overflow. try a little harder. - 100.times do + 10.times do t = Time.now marshal_equal(t, t.usec.to_s) end diff --git a/test/wsdl/datetime/test_datetime.rb b/test/wsdl/datetime/test_datetime.rb index a60d9b70a0..5ac3fdc5bc 100644 --- a/test/wsdl/datetime/test_datetime.rb +++ b/test/wsdl/datetime/test_datetime.rb @@ -58,8 +58,15 @@ class TestDatetime < Test::Unit::TestCase end def test_datetime - d = DateTime.now - assert_equal(d + 1, @client.now(d)) + d1 = DateTime.now + d2 = @client.now(d1) + assert_equal(d2.year, d1.year) + assert_equal(d2.month, d1.month) + assert_equal(d2.day, d1.day + 1) + assert_equal(d2.hour, d1.hour) + assert_equal(d2.min, d1.min) + assert_equal(d2.sec, d1.sec) + assert_equal(d2.sec, d1.sec) end def test_time