зеркало из https://github.com/github/ruby.git
Fix some DRb issues (#2552)
* Handle BasicObject in drb Also fix a bug in rescue clause of any_to_s because sprintf does not handle the %l modifier. Fixes [Bug #7833] * Do not send a reply to the client if there is a connection error This allows for normal TCP shutdown (fin-ack-fin-ack instead of fin-ack-push-rst). Patch from pierre@mouraf.org (Pierre-Alexandre Meyer). Fixes [Bug #2339] * Detect fork and do not reuse forked connections in drb This associates each DRbConn with a pid, and if the pid changes, it closes any DRbConns in the pool with a pid that no longer matches. This fixes DRb servers from sending messages intended for one client to another client after forking. Fixes [Bug #2718] Fixes [Bug #14471]
This commit is contained in:
Родитель
95c420c4a6
Коммит
d0ed935d5b
|
@ -377,7 +377,12 @@ module DRb
|
|||
# This implementation returns the object's __id__ in the local
|
||||
# object space.
|
||||
def to_id(obj)
|
||||
obj.nil? ? nil : obj.__id__
|
||||
case obj
|
||||
when Object
|
||||
obj.nil? ? nil : obj.__id__
|
||||
when BasicObject
|
||||
obj.__id__
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -560,7 +565,14 @@ module DRb
|
|||
end
|
||||
|
||||
def dump(obj, error=false) # :nodoc:
|
||||
obj = make_proxy(obj, error) if obj.kind_of? DRbUndumped
|
||||
case obj
|
||||
when DRbUndumped
|
||||
obj = make_proxy(obj, error)
|
||||
when Object
|
||||
# nothing
|
||||
else
|
||||
obj = make_proxy(obj, error)
|
||||
end
|
||||
begin
|
||||
str = Marshal::dump(obj)
|
||||
rescue
|
||||
|
@ -1092,7 +1104,14 @@ module DRb
|
|||
def initialize(obj, uri=nil)
|
||||
@uri = nil
|
||||
@ref = nil
|
||||
if obj.nil?
|
||||
case obj
|
||||
when Object
|
||||
is_nil = obj.nil?
|
||||
when BasicObject
|
||||
is_nil = false
|
||||
end
|
||||
|
||||
if is_nil
|
||||
return if uri.nil?
|
||||
@uri, option = DRbProtocol.uri_option(uri, DRb.config)
|
||||
@ref = DRbURIOption.new(option) unless option.nil?
|
||||
|
@ -1209,15 +1228,20 @@ module DRb
|
|||
def self.open(remote_uri) # :nodoc:
|
||||
begin
|
||||
conn = nil
|
||||
pid = $$
|
||||
|
||||
@mutex.synchronize do
|
||||
#FIXME
|
||||
new_pool = []
|
||||
@pool.each do |c|
|
||||
if conn.nil? and c.uri == remote_uri
|
||||
conn = c if c.alive?
|
||||
if c.pid == pid
|
||||
if conn.nil? and c.uri == remote_uri
|
||||
conn = c if c.alive?
|
||||
else
|
||||
new_pool.push c
|
||||
end
|
||||
else
|
||||
new_pool.push c
|
||||
c.close
|
||||
end
|
||||
end
|
||||
@pool = new_pool
|
||||
|
@ -1243,9 +1267,11 @@ module DRb
|
|||
|
||||
def initialize(remote_uri) # :nodoc:
|
||||
@uri = remote_uri
|
||||
@pid = $$
|
||||
@protocol = DRbProtocol.open(remote_uri, DRb.config)
|
||||
end
|
||||
attr_reader :uri # :nodoc:
|
||||
attr_reader :pid # :nodoc:
|
||||
|
||||
def send_message(ref, msg_id, arg, block) # :nodoc:
|
||||
@protocol.send_request(ref, msg_id, arg, block)
|
||||
|
@ -1527,7 +1553,13 @@ module DRb
|
|||
def any_to_s(obj)
|
||||
obj.to_s + ":#{obj.class}"
|
||||
rescue
|
||||
sprintf("#<%s:0x%lx>", obj.class, obj.__id__)
|
||||
case obj
|
||||
when Object
|
||||
klass = obj.class
|
||||
else
|
||||
klass = Kernel.instance_method(:class).bind(obj).call
|
||||
end
|
||||
sprintf("#<%s:0x%dx>", klass, obj.__id__)
|
||||
end
|
||||
|
||||
# Check that a method is callable via dRuby.
|
||||
|
@ -1543,14 +1575,27 @@ module DRb
|
|||
raise(ArgumentError, "#{any_to_s(msg_id)} is not a symbol") unless Symbol == msg_id.class
|
||||
raise(SecurityError, "insecure method `#{msg_id}'") if insecure_method?(msg_id)
|
||||
|
||||
if obj.private_methods.include?(msg_id)
|
||||
desc = any_to_s(obj)
|
||||
raise NoMethodError, "private method `#{msg_id}' called for #{desc}"
|
||||
elsif obj.protected_methods.include?(msg_id)
|
||||
desc = any_to_s(obj)
|
||||
raise NoMethodError, "protected method `#{msg_id}' called for #{desc}"
|
||||
case obj
|
||||
when Object
|
||||
if obj.private_methods.include?(msg_id)
|
||||
desc = any_to_s(obj)
|
||||
raise NoMethodError, "private method `#{msg_id}' called for #{desc}"
|
||||
elsif obj.protected_methods.include?(msg_id)
|
||||
desc = any_to_s(obj)
|
||||
raise NoMethodError, "protected method `#{msg_id}' called for #{desc}"
|
||||
else
|
||||
true
|
||||
end
|
||||
else
|
||||
true
|
||||
if Kernel.instance_method(:private_methods).bind(obj).call.include?(msg_id)
|
||||
desc = any_to_s(obj)
|
||||
raise NoMethodError, "private method `#{msg_id}' called for #{desc}"
|
||||
elsif Kernel.instance_method(:protected_methods).bind(obj).call.include?(msg_id)
|
||||
desc = any_to_s(obj)
|
||||
raise NoMethodError, "protected method `#{msg_id}' called for #{desc}"
|
||||
else
|
||||
true
|
||||
end
|
||||
end
|
||||
end
|
||||
public :check_insecure_method
|
||||
|
@ -1596,8 +1641,11 @@ module DRb
|
|||
end
|
||||
end
|
||||
@succ = true
|
||||
if @msg_id == :to_ary && @result.class == Array
|
||||
@result = DRbArray.new(@result)
|
||||
case @result
|
||||
when Array
|
||||
if @msg_id == :to_ary
|
||||
@result = DRbArray.new(@result)
|
||||
end
|
||||
end
|
||||
return @succ, @result
|
||||
rescue StandardError, ScriptError, Interrupt
|
||||
|
@ -1678,7 +1726,9 @@ module DRb
|
|||
invoke_method = InvokeMethod.new(self, client)
|
||||
succ, result = invoke_method.perform
|
||||
error_print(result) if !succ && verbose
|
||||
client.send_reply(succ, result)
|
||||
unless DRbConnError === result && result.message == 'connection closed'
|
||||
client.send_reply(succ, result)
|
||||
end
|
||||
rescue Exception => e
|
||||
error_print(e) if verbose
|
||||
ensure
|
||||
|
|
|
@ -158,6 +158,14 @@ module DRbCore
|
|||
end
|
||||
end
|
||||
|
||||
def test_02_basic_object
|
||||
obj = @there.basic_object
|
||||
assert_kind_of(DRb::DRbObject, obj)
|
||||
assert_equal(1, obj.foo)
|
||||
assert_raise(NoMethodError){obj.prot}
|
||||
assert_raise(NoMethodError){obj.priv}
|
||||
end
|
||||
|
||||
def test_02_unknown
|
||||
obj = @there.unknown_class
|
||||
assert_kind_of(DRb::DRbUnknown, obj)
|
||||
|
|
|
@ -63,6 +63,15 @@ class DRbEx
|
|||
FooBar.new
|
||||
end
|
||||
|
||||
class BO < ::BasicObject
|
||||
def foo; 1 end
|
||||
protected def prot; 2; end
|
||||
private def priv; 3; end
|
||||
end
|
||||
def basic_object
|
||||
BO.new
|
||||
end
|
||||
|
||||
def unknown_class
|
||||
Unknown2.new
|
||||
end
|
||||
|
|
Загрузка…
Ссылка в новой задаче