使用YAML.safe_load(content)
安全加载典型的单个文档YAML文件的常规方法。
YAML文件可以包含多个文档:
---
key: value
---
key: !ruby/struct
foo: bar
使用YAML.safe_load(content)
加载此类YAML文件只会返回第一个文档:
{ 'key' => 'value' }
如果您拆分文件并尝试safe_load第二个文档,您将获得预期的异常:
Psych::DisallowedClass (Tried to load unspecified class: Struct)
要加载多个文档,您可以使用YAML.load_stream(content)
返回一个数组:
[
{ 'key' => 'value' },
{ 'key' => #<struct foo="bar"> }
]
问题是没有YAML.safe_load_stream
会引发非白名单数据类型的异常。
答案 0 :(得分:2)
我写了一个使用YAML.parse_stream
界面的解决方法:
修改:现在为gem yaml-safe_load_stream。另外,Psych的维护者(ruby stdlib中的YAML
)正在调查adding this feature到图书馆。
require 'yaml'
module YAML
def safe_load_stream(yaml, filename = nil, &block)
parse_stream(yaml, filename) do |stream|
raise_if_tags(stream, filename)
if block_given?
yield stream.to_ruby
else
stream.to_ruby
end
end
end
module_function :safe_load_stream
def raise_if_tags(obj, filename = nil, doc_num = 1)
doc_num += 1 if obj.is_a?(Psych::Nodes::Document)
if obj.respond_to?(:tag)
if tag = obj.tag
message = "tag #{tag} encountered on line #{obj.start_line} column #{obj.start_column} of document #{doc_num}"
message << " in file #{filename}" if filename
raise Psych::DisallowedClass, message
end
end
if obj.respond_to?(:children)
Array(obj.children).each do |child|
raise_if_tags(child, filename, doc_num)
end
end
end
module_function :raise_if_tags
private_class_method :raise_if_tags
end
你可以这样做:
YAML.safe_load_stream(content, 'file.txt')
获得例外:
Psych::DisallowedClass (Tried to load unspecified class: tag !ruby/struct
encountered on line 1 column 7 of document 2 in file file.txt)
从.start_line
返回的行号是相对于文档的开头,我没有找到获取文档开头的行号的方法,所以我将文档编号添加到错误消息中。
它没有类和符号白名单以及像YAML.safe_load
那样切换锚点/别名。
此外,还有一些方法可以使用标签,这些标签可能会因为这种简单的unless tag.nil?
检测而产生误报。