)). You can only create
((*one*)) (({XMLRPC::CGIServer})) instance, because more than one makes
no sense.
== Instance Methods
--- XMLRPC::CGIServer#serve
Call this after you have added all you handlers to the server.
This method processes a XML-RPC methodCall and sends the answer
back to the client.
Make sure that you don't write to standard-output in a handler, or in
any other part of your program, this would case a CGI-based server to fail!
=end
class CGIServer < BasicServer
@@obj = nil
def CGIServer.new(*a)
@@obj = super(*a) if @@obj.nil?
@@obj
end
def initialize(*a)
super(*a)
end
def serve
catch(:exit_serve) {
length = ENV['CONTENT_LENGTH'].to_i
http_error(405, "Method Not Allowed") unless ENV['REQUEST_METHOD'] == "POST"
http_error(400, "Bad Request") unless parse_content_type(ENV['CONTENT_TYPE']).first == "text/xml"
http_error(411, "Length Required") unless length > 0
# TODO: do we need a call to binmode?
$stdin.binmode if $stdin.respond_to? :binmode
data = $stdin.read(length)
http_error(400, "Bad Request") if data.nil? or data.bytesize != length
http_write(process(data), "Content-type" => "text/xml; charset=utf-8")
}
end
private
def http_error(status, message)
err = "#{status} #{message}"
msg = <<-"MSGEND"
#{err}
#{err}
Unexpected error occured while processing XML-RPC request!
MSGEND
http_write(msg, "Status" => err, "Content-type" => "text/html")
throw :exit_serve # exit from the #serve method
end
def http_write(body, header)
h = {}
header.each {|key, value| h[key.to_s.capitalize] = value}
h['Status'] ||= "200 OK"
h['Content-length'] ||= body.bytesize.to_s
str = ""
h.each {|key, value| str << "#{key}: #{value}\r\n"}
str << "\r\n#{body}"
print str
end
end
=begin
= XMLRPC::ModRubyServer
== Description
Implements a XML-RPC server, which works with Apache mod_ruby.
Use it in the same way as CGIServer!
== Superclass
(())
=end
class ModRubyServer < BasicServer
def initialize(*a)
@ap = Apache::request
super(*a)
end
def serve
catch(:exit_serve) {
header = {}
@ap.headers_in.each {|key, value| header[key.capitalize] = value}
length = header['Content-length'].to_i
http_error(405, "Method Not Allowed") unless @ap.request_method == "POST"
http_error(400, "Bad Request") unless parse_content_type(header['Content-type']).first == "text/xml"
http_error(411, "Length Required") unless length > 0
# TODO: do we need a call to binmode?
@ap.binmode
data = @ap.read(length)
http_error(400, "Bad Request") if data.nil? or data.bytesize != length
http_write(process(data), 200, "Content-type" => "text/xml; charset=utf-8")
}
end
private
def http_error(status, message)
err = "#{status} #{message}"
msg = <<-"MSGEND"
#{err}
#{err}
Unexpected error occured while processing XML-RPC request!
MSGEND
http_write(msg, status, "Status" => err, "Content-type" => "text/html")
throw :exit_serve # exit from the #serve method
end
def http_write(body, status, header)
h = {}
header.each {|key, value| h[key.to_s.capitalize] = value}
h['Status'] ||= "200 OK"
h['Content-length'] ||= body.bytesize.to_s
h.each {|key, value| @ap.headers_out[key] = value }
@ap.content_type = h["Content-type"]
@ap.status = status.to_i
@ap.send_http_header
@ap.print body
end
end
=begin
= XMLRPC::Server
== Synopsis
require "xmlrpc/server"
s = XMLRPC::Server.new(8080)
s.add_handler("michael.add") do |a,b|
a + b
end
s.add_handler("michael.div") do |a,b|
if b == 0
raise XMLRPC::FaultException.new(1, "division by zero")
else
a / b
end
end
s.set_default_handler do |name, *args|
raise XMLRPC::FaultException.new(-99, "Method #{name} missing" +
" or wrong number of parameters!")
end
s.serve
== Description
Implements a standalone XML-RPC server. The method (({serve}))) is left if a SIGHUP is sent to the
program.
== Superclass
(())
== Class Methods
--- XMLRPC::Server.new( port=8080, host="127.0.0.1", maxConnections=4, stdlog=$stdout, audit=true, debug=true, *a )
Creates a new (({XMLRPC::Server})) instance, which is a XML-RPC server listening on
port ((|port|)) and accepts requests for the host ((|host|)), which is by default only the localhost.
The server is not started, to start it you have to call (()).
Parameters ((|audit|)) and ((|debug|)) are obsolete!
All additionally given parameters in ((|*a|)) are by-passed to (()).
== Instance Methods
--- XMLRPC::Server#serve
Call this after you have added all you handlers to the server.
This method starts the server to listen for XML-RPC requests and answer them.
--- XMLRPC::Server#shutdown
Stops and shuts the server down.
=end
class WEBrickServlet < BasicServer; end # forward declaration
class Server < WEBrickServlet
def initialize(port=8080, host="127.0.0.1", maxConnections=4, stdlog=$stdout, audit=true, debug=true, *a)
super(*a)
require 'webrick'
@server = WEBrick::HTTPServer.new(:Port => port, :BindAddress => host, :MaxClients => maxConnections,
:Logger => WEBrick::Log.new(stdlog))
@server.mount("/", self)
end
def serve
signals = %w[INT TERM HUP] & Signal.list.keys
signals.each { |signal| trap(signal) { @server.shutdown } }
@server.start
end
def shutdown
@server.shutdown
end
end
=begin
= XMLRPC::WEBrickServlet
== Synopsis
require "webrick"
require "xmlrpc/server"
s = XMLRPC::WEBrickServlet.new
s.add_handler("michael.add") do |a,b|
a + b
end
s.add_handler("michael.div") do |a,b|
if b == 0
raise XMLRPC::FaultException.new(1, "division by zero")
else
a / b
end
end
s.set_default_handler do |name, *args|
raise XMLRPC::FaultException.new(-99, "Method #{name} missing" +
" or wrong number of parameters!")
end
httpserver = WEBrick::HTTPServer.new(:Port => 8080)
httpserver.mount("/RPC2", s)
trap("HUP") { httpserver.shutdown } # use 1 instead of "HUP" on Windows
httpserver.start
== Instance Methods
--- XMLRPC::WEBrickServlet#set_valid_ip( *ip_addr )
Specifies the valid IP addresses that are allowed to connect to the server.
Each IP is either a (({String})) or a (({Regexp})).
--- XMLRPC::WEBrickServlet#get_valid_ip
Return the via method (()) specified
valid IP addresses.
== Description
Implements a servlet for use with WEBrick, a pure Ruby (HTTP-) server framework.
== Superclass
(())
=end
class WEBrickServlet < BasicServer
def initialize(*a)
super
require "webrick/httpstatus"
@valid_ip = nil
end
# deprecated from WEBrick/1.2.2.
# but does not break anything.
def require_path_info?
false
end
def get_instance(config, *options)
# TODO: set config & options
self
end
def set_valid_ip(*ip_addr)
if ip_addr.size == 1 and ip_addr[0].nil?
@valid_ip = nil
else
@valid_ip = ip_addr
end
end
def get_valid_ip
@valid_ip
end
def service(request, response)
if @valid_ip
raise WEBrick::HTTPStatus::Forbidden unless @valid_ip.any? { |ip| request.peeraddr[3] =~ ip }
end
if request.request_method != "POST"
raise WEBrick::HTTPStatus::MethodNotAllowed,
"unsupported method `#{request.request_method}'."
end
if parse_content_type(request['Content-type']).first != "text/xml"
raise WEBrick::HTTPStatus::BadRequest
end
length = (request['Content-length'] || 0).to_i
raise WEBrick::HTTPStatus::LengthRequired unless length > 0
data = request.body
if data.nil? or data.bytesize != length
raise WEBrick::HTTPStatus::BadRequest
end
resp = process(data)
if resp.nil? or resp.bytesize <= 0
raise WEBrick::HTTPStatus::InternalServerError
end
response.status = 200
response['Content-Length'] = resp.bytesize
response['Content-Type'] = "text/xml; charset=utf-8"
response.body = resp
end
end
end # module XMLRPC
=begin
= History
$Id: server.rb 32947 2011-08-12 08:06:49Z shugo $
=end