mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
168 lines
4.4 KiB
Ruby
168 lines
4.4 KiB
Ruby
|
=begin
|
||
|
SOAP4R - SOAP handler servlet for WEBrick
|
||
|
Copyright (C) 2001, 2002, 2003 NAKAMURA, Hiroshi.
|
||
|
|
||
|
This program is free software; you can redistribute it and/or modify it under
|
||
|
the terms of the GNU General Public License as published by the Free Software
|
||
|
Foundation; either version 2 of the License, or (at your option) any later
|
||
|
version.
|
||
|
|
||
|
This program is distributed in the hope that it will be useful, but WITHOUT ANY
|
||
|
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
||
|
PRATICULAR PURPOSE. See the GNU General Public License for more details.
|
||
|
|
||
|
You should have received a copy of the GNU General Public License along with
|
||
|
this program; if not, write to the Free Software Foundation, Inc., 675 Mass
|
||
|
Ave, Cambridge, MA 02139, USA.
|
||
|
=end
|
||
|
|
||
|
|
||
|
require 'webrick/httpservlet/abstract'
|
||
|
require 'webrick/httpstatus'
|
||
|
require 'soap/rpc/router'
|
||
|
require 'soap/streamHandler'
|
||
|
|
||
|
module SOAP
|
||
|
module RPC
|
||
|
|
||
|
|
||
|
class SOAPlet < WEBrick::HTTPServlet::AbstractServlet
|
||
|
public
|
||
|
attr_reader :app_scope_router
|
||
|
|
||
|
def initialize
|
||
|
@router_map = {}
|
||
|
@app_scope_router = ::SOAP::RPC::Router.new(self.class.name)
|
||
|
end
|
||
|
|
||
|
# Add servant klass whose object has request scope. A servant object is
|
||
|
# instanciated for each request.
|
||
|
#
|
||
|
# Bare in mind that servant klasses 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 klass.
|
||
|
# I mean, use Driver#add_method_with_soapaction instead of Driver#add_method
|
||
|
# at client side.
|
||
|
#
|
||
|
def add_rpc_request_servant(klass, namespace, mapping_registry = nil)
|
||
|
router = RequestRouter.new(klass, namespace, mapping_registry)
|
||
|
add_router(namespace, router)
|
||
|
end
|
||
|
|
||
|
# Add servant object which has application scope.
|
||
|
def add_rpc_servant(obj, namespace)
|
||
|
router = @app_scope_router
|
||
|
SOAPlet.add_servant_to_router(router, obj, namespace)
|
||
|
add_router(namespace, router)
|
||
|
end
|
||
|
alias add_servant add_rpc_servant
|
||
|
|
||
|
|
||
|
###
|
||
|
## Servlet interfaces for WEBrick.
|
||
|
#
|
||
|
def get_instance(config, *options)
|
||
|
@config = config
|
||
|
self
|
||
|
end
|
||
|
|
||
|
def require_path_info?
|
||
|
false
|
||
|
end
|
||
|
|
||
|
def do_GET(req, res)
|
||
|
res.header['Allow'] = 'POST'
|
||
|
raise WEBrick::HTTPStatus::MethodNotAllowed, "GET request not allowed."
|
||
|
end
|
||
|
|
||
|
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)
|
||
|
rescue Exception => e
|
||
|
response_stream = router.create_fault_response(e)
|
||
|
is_fault = true
|
||
|
end
|
||
|
|
||
|
res.body = response_stream
|
||
|
res['content-type'] = "text/xml; charset=\"#{charset}\""
|
||
|
if response_stream.is_a?(IO)
|
||
|
res.chunked = true
|
||
|
end
|
||
|
|
||
|
if is_fault
|
||
|
res.status = WEBrick::HTTPStatus::RC_INTERNAL_SERVER_ERROR
|
||
|
end
|
||
|
end
|
||
|
|
||
|
private
|
||
|
|
||
|
class RequestRouter < ::SOAP::RPC::Router
|
||
|
def initialize(klass, namespace, mapping_registry = nil)
|
||
|
super(namespace)
|
||
|
if mapping_registry
|
||
|
self.mapping_registry = mapping_registry
|
||
|
end
|
||
|
@klass = klass
|
||
|
@namespace = namespace
|
||
|
end
|
||
|
|
||
|
def route(soap_string)
|
||
|
obj = @klass.new
|
||
|
namespace = self.actor
|
||
|
router = ::SOAP::RPC::Router.new(@namespace)
|
||
|
SOAPlet.add_servant_to_router(router, obj, namespace)
|
||
|
router.route(soap_string)
|
||
|
end
|
||
|
end
|
||
|
|
||
|
def add_router(namespace, router)
|
||
|
@router_map[namespace] = router
|
||
|
end
|
||
|
|
||
|
def parse_soapaction(soapaction)
|
||
|
if /^"(.*)"$/ =~ soapaction
|
||
|
soapaction = $1
|
||
|
end
|
||
|
if soapaction.empty?
|
||
|
return nil
|
||
|
end
|
||
|
soapaction
|
||
|
end
|
||
|
|
||
|
def lookup_router(namespace)
|
||
|
if namespace
|
||
|
@router_map[namespace] || @app_scope_router
|
||
|
else
|
||
|
@app_scope_router
|
||
|
end
|
||
|
end
|
||
|
|
||
|
class << self
|
||
|
public
|
||
|
def add_servant_to_router(router, obj, namespace)
|
||
|
::SOAP::RPC.defined_methods(obj).each do |name|
|
||
|
add_servant_method_to_router(router, obj, namespace, name)
|
||
|
end
|
||
|
end
|
||
|
|
||
|
def add_servant_method_to_router(router, obj, namespace, name)
|
||
|
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 }" })
|
||
|
router.add_method(obj, qname, soapaction, name, param_def)
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
|
||
|
|
||
|
end
|
||
|
end
|