-
Notifications
You must be signed in to change notification settings - Fork 48
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Remove thread-unsafe runtime requires #43
base: master
Are you sure you want to change the base?
Changes from all commits
bf6391b
48ce295
20d9927
401a002
e8dcdb4
5a71a8b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,31 +1,10 @@ | ||
# :markup: markdown | ||
require 'http/cookie' | ||
|
||
## | ||
# This class is used to manage the Cookies that have been returned from | ||
# any particular website. | ||
|
||
class HTTP::CookieJar | ||
class << self | ||
def const_missing(name) | ||
case name.to_s | ||
when /\A([A-Za-z]+)Store\z/ | ||
file = 'http/cookie_jar/%s_store' % $1.downcase | ||
when /\A([A-Za-z]+)Saver\z/ | ||
file = 'http/cookie_jar/%s_saver' % $1.downcase | ||
end | ||
begin | ||
require file | ||
rescue LoadError | ||
raise NameError, 'can\'t resolve constant %s; failed to load %s' % [name, file] | ||
end | ||
if const_defined?(name) | ||
const_get(name) | ||
else | ||
raise NameError, 'can\'t resolve constant %s after loading %s' % [name, file] | ||
end | ||
end | ||
end | ||
|
||
attr_reader :store | ||
|
||
|
@@ -342,3 +321,6 @@ def cleanup(session = false) | |
self | ||
end | ||
end | ||
|
||
require 'http/cookie_jar/abstract_store' | ||
require 'http/cookie_jar/abstract_saver' | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. these could be There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Agreed, although after trying that I am still trying to understand why this rake task sometimes indicates thread safety issues under recent versions of truffleruby. autoloading is atomic in ruby, but only with respect to the individual constant being autoloaded. I thought I removed any mutation of other classes during autoloading but I might have missed something. Will dig further. |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -6,29 +6,18 @@ class HTTP::CookieJar::AbstractStore | |
include MonitorMixin | ||
|
||
class << self | ||
@@class_map = {} | ||
|
||
# Gets an implementation class by the name, optionally trying to | ||
# load "http/cookie_jar/*_store" if not found. If loading fails, | ||
# IndexError is raised. | ||
# Gets an implementation class by the name. | ||
def implementation(symbol) | ||
@@class_map.fetch(symbol) | ||
rescue IndexError | ||
begin | ||
require 'http/cookie_jar/%s_store' % symbol | ||
@@class_map.fetch(symbol) | ||
rescue LoadError, IndexError => e | ||
raise IndexError, 'cookie store unavailable: %s, error: %s' % symbol.inspect, e.message | ||
case symbol | ||
when :hash | ||
HTTP::CookieJar::HashStore | ||
when :mozilla | ||
HTTP::CookieJar::MozillaStore | ||
else | ||
raise IndexError, 'cookie store unavailable: %s' % symbol.inspect | ||
end | ||
end | ||
|
||
def inherited(subclass) # :nodoc: | ||
@@class_map[class_to_symbol(subclass)] = subclass | ||
end | ||
|
||
def class_to_symbol(klass) # :nodoc: | ||
klass.name[/[^:]+?(?=Store$|$)/].downcase.to_sym | ||
end | ||
end | ||
|
||
# Defines options and their default values. | ||
|
@@ -122,3 +111,16 @@ def cleanup(session = false) | |
# self | ||
end | ||
end | ||
|
||
require 'http/cookie_jar/hash_store' | ||
|
||
# Skip loading MozillaStore on JRuby. | ||
if defined?(JRUBY_VERSION) | ||
class HTTP::CookieJar::MozillaStore | ||
def initialize(*) | ||
raise ArgumentError, "MozillaStore is not supported on JRuby" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this isn't that of a nice "idiomatic" Ruby approach. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I agree. Change this to just |
||
end | ||
end | ||
else | ||
require 'http/cookie_jar/mozilla_store' | ||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,5 @@ | ||
# :markup: markdown | ||
require 'http/cookie_jar' | ||
require 'psych' if !defined?(YAML) && RUBY_VERSION == "1.9.2" | ||
require 'yaml' | ||
autoload :YAML, 'yaml' | ||
|
||
# YAMLSaver saves and loads cookies in the YAML format. It can load a | ||
# YAML file saved by Mechanize, but the saving format is not | ||
|
@@ -74,13 +72,9 @@ def default_options | |
{} | ||
end | ||
|
||
if YAML.name == 'Psych' && Psych::VERSION >= '3.1' | ||
def load_yaml(yaml) | ||
YAML.safe_load(yaml, :permitted_classes => %w[Time HTTP::Cookie Mechanize::Cookie DomainName], :aliases => true) | ||
end | ||
else | ||
def load_yaml(yaml) | ||
YAML.load(yaml) | ||
end | ||
def load_yaml(yaml) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I rewrote this method to avoid negating the requested introduction of |
||
YAML.safe_load(yaml, :permitted_classes => %w[Time HTTP::Cookie Mechanize::Cookie DomainName], :aliases => true) | ||
rescue NoMethodError # ruby < 2.0, no safe_load | ||
YAML.load(yaml) | ||
end | ||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
autoload
is fine - there should be no need to change thisThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I thought so too, but I tested the first commit (which left autoload in) on all truffleruby versions and older jrubies and it still exhibited thread unsafety. Here's a repro:
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
that would be related to other changes I do not see this reproducing in 9.2/9.3/9.4,
what I did on top of the PR:
again I am fine with the require here given there isn't a lot going on
but maybe the
autoload
should be kept (due compatibility) at the nested level for these:There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I took another look and found that I had a bug in the initial implementation. 2d5b65a (on another branch for now) is a commit on top of bf6391b that should work properly by making all six classes under
HTTP::CookieJar
autoloaded. I thought that addressed everything but in my testing truffleruby still has a (much rarer) issue with it. I added a task to verify safety automatically in 99dd9e4 and I get inconsistent results for truffle sometimes with the autoload approach.OTOH 2d5b65a does fix this for all jrubies I've tried. I've been unable to reproduce the issue with MRI anywhere even though internally we have encountered this issue with it in real workloads.