diff options
author | nahi <nahi@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2005-05-22 13:03:38 +0000 |
---|---|---|
committer | nahi <nahi@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2005-05-22 13:03:38 +0000 |
commit | eb3f829be932514064a983eb98fa7f840137f985 (patch) | |
tree | c17440206af25b52f47b1c391f818e126a994d0a /lib/soap/rpc/soaplet.rb | |
parent | 7aea792d3bdf42c349170e710953d7de29de57ab (diff) |
* lib/{soap,wsdl,xsd}, test/{soap,wsdl,xsd}: imported soap4r/1.5.4.
== SOAP client and server ==
=== for both client side and server side ===
* improved document/literal service support.
style(rpc,document)/use(encoding, literal) combination are all
supported. for the detail about combination, see
test/soap/test_style.rb.
* let WSDLEncodedRegistry#soap2obj map SOAP/OM to Ruby according to
WSDL as well as obj2soap. closes #70.
* let SOAP::Mapping::Object handle XML attribute for doc/lit service.
you can set/get XML attribute via accessor methods which as a name
'xmlattr_' prefixed (<foo name="bar"/> -> Foo#xmlattr_name).
=== client side ===
* WSDLDriver capitalized name operation bug fixed. from
1.5.3-ruby1.8.2, operation which has capitalized name (such as
KeywordSearchRequest in AWS) is defined as a method having
uncapitalized name. (converted with GenSupport.safemethodname
to handle operation name 'foo-bar'). it introduced serious
incompatibility; in the past, it was defined as a capitalized.
define capitalized method as well under that circumstance.
* added new factory interface 'WSDLDriverFactory#create_rpc_driver'
to create RPC::Driver, not WSDLDriver (RPC::Driver and WSDLDriver
are merged). 'WSDLDriverFactory#create_driver' still creates
WSDLDriver for compatibility but it warns that the method is
deprecated. please use create_rpc_driver instead of create_driver.
* allow to use an URI object as an endpoint_url even with net/http,
not http-access2.
=== server side ===
* added mod_ruby support to SOAP::CGIStub. rename a CGI script
server.cgi to server.rb and let mod_ruby's RubyHandler handles the
script. CGIStub detects if it's running under mod_ruby environment
or not.
* added fcgi support to SOAP::CGIStub. see the sample at
sample/soap/calc/server.fcgi. (almost same as server.cgi but has
fcgi handler at the bottom.)
* allow to return a SOAPFault object to respond customized SOAP fault.
* added the interface 'generate_explicit_type' for server side
(CGIStub, HTTPServer). call 'self.generate_explicit_type = true'
if you want to return simplified XML even if it's rpc/encoded
service.
== WSDL ==
=== WSDL definition ===
* improved XML Schema support such as extension, restriction,
simpleType, complexType + simpleContent, ref, length, import,
include.
* reduced "unknown element/attribute" warnings (warn only 1 time for
each QName).
* importing XSD file at schemaLocation with xsd:import.
=== code generation from WSDL ===
* generator crashed when there's '-' in defined element/attribute
name.
* added ApacheMap WSDL definition.
* sample/{soap,wsdl}: removed.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@8500 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'lib/soap/rpc/soaplet.rb')
-rw-r--r-- | lib/soap/rpc/soaplet.rb | 219 |
1 files changed, 64 insertions, 155 deletions
diff --git a/lib/soap/rpc/soaplet.rb b/lib/soap/rpc/soaplet.rb index 8f18c53d3a..4d2538f0b3 100644 --- a/lib/soap/rpc/soaplet.rb +++ b/lib/soap/rpc/soaplet.rb @@ -1,5 +1,5 @@ # SOAP4R - SOAP handler servlet for WEBrick -# Copyright (C) 2001, 2002, 2003, 2004 NAKAMURA, Hiroshi <[email protected]>. +# Copyright (C) 2001-2005 NAKAMURA, Hiroshi <[email protected]>. # 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; @@ -14,7 +14,23 @@ begin require 'stringio' require 'zlib' rescue LoadError - STDERR.puts "Loading stringio or zlib failed. No gzipped response support." if $DEBUG + warn("Loading stringio or zlib failed. No gzipped response supported.") if $DEBUG +end + + +warn("Overriding WEBrick::Log#debug") if $DEBUG +require 'webrick/log' +module WEBrick + class Log < BasicLog + alias __debug debug + def debug(msg = nil) + if block_given? and msg.nil? + __debug(yield) + else + __debug(msg) + end + end + end end @@ -24,60 +40,27 @@ module RPC class SOAPlet < WEBrick::HTTPServlet::AbstractServlet public - attr_reader :app_scope_router attr_reader :options - def initialize - @rpc_router_map = {} - @app_scope_router = ::SOAP::RPC::Router.new(self.class.name) - @headerhandlerfactory = [] - @app_scope_headerhandler = nil + def initialize(router = nil) + @router = router || ::SOAP::RPC::Router.new(self.class.name) @options = {} + @config = {} end - def allow_content_encoding_gzip=(allow) - @options[:allow_content_encoding_gzip] = allow - end - - # Add servant factory whose object has request scope. A servant object is - # instanciated for each request. - # - # Bear in mind that servant factories are distinguished by HTTP SOAPAction - # header in request. Client which calls request-scoped servant must have a - # SOAPAction header which is a namespace of the servant factory. - # I mean, use Driver#add_method_with_soapaction instead of Driver#add_method - # at client side. - # - # A factory must respond to :create. - # - def add_rpc_request_servant(factory, namespace, mapping_registry = nil) - unless factory.respond_to?(:create) - raise TypeError.new("factory must respond to 'create'") - end - router = setup_rpc_request_router(namespace) - router.factory = factory - router.mapping_registry = mapping_registry - end - - # Add servant object which has application scope. - def add_rpc_servant(obj, namespace) - router = @app_scope_router - SOAPlet.add_rpc_servant_to_router(router, obj, namespace) - add_rpc_router(namespace, router) + # for backward compatibility + def app_scope_router + @router end - alias add_servant add_rpc_servant - def add_rpc_request_headerhandler(factory) - unless factory.respond_to?(:create) - raise TypeError.new("factory must respond to 'create'") - end - @headerhandlerfactory << factory + # for backward compatibility + def add_servant(obj, namespace) + @router.add_rpc_servant(obj, namespace) end - def add_rpc_headerhandler(obj) - @app_scope_headerhandler = obj + def allow_content_encoding_gzip=(allow) + @options[:allow_content_encoding_gzip] = allow end - alias add_headerhandler add_rpc_headerhandler ### ## Servlet interfaces for WEBrick. @@ -93,111 +76,63 @@ public def do_GET(req, res) res.header['Allow'] = 'POST' - raise WEBrick::HTTPStatus::MethodNotAllowed, "GET request not allowed." + raise WEBrick::HTTPStatus::MethodNotAllowed, "GET request not allowed" end def do_POST(req, res) - @config[:Logger].debug { "SOAP request: " + req.body } - soapaction = parse_soapaction(req.meta_vars['HTTP_SOAPACTION']) - router = lookup_router(soapaction) - with_headerhandler(router) do |router| - begin - 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) - res['content-type'] = conn_data.send_contenttype - if conn_data.is_fault - res.status = WEBrick::HTTPStatus::RC_INTERNAL_SERVER_ERROR - end - if outstring = encode_gzip(req, conn_data.send_string) - res['content-encoding'] = 'gzip' - res['content-length'] = outstring.size - res.body = outstring - else - res.body = conn_data.send_string - end - rescue Exception => e - 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 + logger.debug { "SOAP request: " + req.body } if logger + begin + conn_data = ::SOAP::StreamHandler::ConnectionData.new + setup_req(conn_data, req) + conn_data = @router.route(conn_data) + setup_res(conn_data, req, res) + rescue Exception => e + 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 - if res.body.is_a?(IO) res.chunked = true - @config[:Logger].debug { "SOAP response: (chunked response not logged)" } + logger.debug { "SOAP response: (chunked response not logged)" } if logger else - @config[:Logger].debug { "SOAP response: " + res.body } + logger.debug { "SOAP response: " + res.body } if logger end end private - class RequestRouter < ::SOAP::RPC::Router - attr_accessor :factory - - def initialize(style = :rpc, namespace = nil) - super(namespace) - @style = style - @namespace = namespace - @factory = nil - end - - def route(soap_string) - obj = @factory.create - namespace = self.actor - router = ::SOAP::RPC::Router.new(@namespace) - if @style == :rpc - SOAPlet.add_rpc_servant_to_router(router, obj, namespace) - else - raise RuntimeError.new("'document' style not supported.") - end - router.route(soap_string) - end - end - - def setup_rpc_request_router(namespace) - router = @rpc_router_map[namespace] || RequestRouter.new(:rpc, namespace) - add_rpc_router(namespace, router) - router + def logger + @config[:Logger] end - def add_rpc_router(namespace, router) - @rpc_router_map[namespace] = router + def setup_req(conn_data, req) + conn_data.receive_string = req.body + conn_data.receive_contenttype = req['content-type'] + conn_data.soapaction = parse_soapaction(req.meta_vars['HTTP_SOAPACTION']) end - def parse_soapaction(soapaction) - if /^"(.*)"$/ =~ soapaction - soapaction = $1 - end - if soapaction.empty? - return nil + def setup_res(conn_data, req, res) + res['content-type'] = conn_data.send_contenttype + if conn_data.is_fault + res.status = WEBrick::HTTPStatus::RC_INTERNAL_SERVER_ERROR end - soapaction - end - - def lookup_router(namespace) - if namespace - @rpc_router_map[namespace] || @app_scope_router + if outstring = encode_gzip(req, conn_data.send_string) + res['content-encoding'] = 'gzip' + res['content-length'] = outstring.size + res.body = outstring else - @app_scope_router + res.body = conn_data.send_string end end - def with_headerhandler(router) - if @app_scope_headerhandler and - !router.headerhandler.include?(@app_scope_headerhandler) - router.headerhandler.add(@app_scope_headerhandler) - end - handlers = @headerhandlerfactory.collect { |f| f.create } - begin - handlers.each { |h| router.headerhandler.add(h) } - yield(router) - ensure - handlers.each { |h| router.headerhandler.delete(h) } + def parse_soapaction(soapaction) + if !soapaction.nil? and !soapaction.empty? + if /^"(.+)"$/ =~ soapaction + return $1 + end end + nil end def encode_gzip(req, outstring) @@ -219,32 +154,6 @@ private req['accept-encoding'] and req['accept-encoding'].split(/,\s*/).include?('gzip') end - - class << self - public - def add_rpc_servant_to_router(router, obj, namespace) - ::SOAP::RPC.defined_methods(obj).each do |name| - begin - add_rpc_servant_method_to_router(router, obj, namespace, name) - rescue SOAP::RPC::MethodDefinitionError => e - p e if $DEBUG - end - end - end - - def add_rpc_servant_method_to_router(router, obj, namespace, name, - style = :rpc, use = :encoded) - qname = XSD::QName.new(namespace, name) - soapaction = nil - method = obj.method(name) - param_def = ::SOAP::RPC::SOAPMethod.create_param_def( - (1..method.arity.abs).collect { |i| "p#{ i }" }) - opt = {} - opt[:request_style] = opt[:response_style] = style - opt[:request_use] = opt[:response_use] = use - router.add_operation(qname, soapaction, obj, name, param_def, opt) - end - end end |