diff options
author | Kazuki Yamaguchi <k@rhe.jp> | 2020-02-17 18:30:08 +0900 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-02-17 18:30:08 +0900 |
commit | 9907de589939d71687670df653cca7f7654fe4cc (patch) | |
tree | 0028d12198d6b14efd434dc7ac447798861e13f0 | |
parent | 1b7e5e49265a88faa30791f8d677ae0a3b4c54f6 (diff) | |
parent | 2ad65b5f673f0bb8741bc0d5a737bd0a3cccb65e (diff) | |
download | ruby-openssl-9907de589939d71687670df653cca7f7654fe4cc.tar.gz |
Merge pull request #216 from rhenium/ky/config-include-directive
config: support .include directive
-rw-r--r-- | lib/openssl/config.rb | 54 | ||||
-rw-r--r-- | test/test_config.rb | 54 |
2 files changed, 90 insertions, 18 deletions
diff --git a/lib/openssl/config.rb b/lib/openssl/config.rb index 88225451..569d9b01 100644 --- a/lib/openssl/config.rb +++ b/lib/openssl/config.rb @@ -76,29 +76,44 @@ module OpenSSL def parse_config_lines(io) section = 'default' data = {section => {}} - while definition = get_definition(io) + io_stack = [io] + while definition = get_definition(io_stack) definition = clear_comments(definition) next if definition.empty? - if definition[0] == ?[ + case definition + when /\A\[/ if /\[([^\]]*)\]/ =~ definition section = $1.strip data[section] ||= {} else raise ConfigError, "missing close square bracket" end - else - if /\A([^:\s]*)(?:::([^:\s]*))?\s*=(.*)\z/ =~ definition - if $2 - section = $1 - key = $2 - else - key = $1 + when /\A\.include (\s*=\s*)?(.+)\z/ + path = $2 + if File.directory?(path) + files = Dir.glob(File.join(path, "*.{cnf,conf}"), File::FNM_EXTGLOB) + else + files = [path] + end + + files.each do |filename| + begin + io_stack << StringIO.new(File.read(filename)) + rescue + raise ConfigError, "could not include file '%s'" % filename end - value = unescape_value(data, section, $3) - (data[section] ||= {})[key] = value.strip + end + when /\A([^:\s]*)(?:::([^:\s]*))?\s*=(.*)\z/ + if $2 + section = $1 + key = $2 else - raise ConfigError, "missing equal sign" + key = $1 end + value = unescape_value(data, section, $3) + (data[section] ||= {})[key] = value.strip + else + raise ConfigError, "missing equal sign" end end data @@ -211,10 +226,10 @@ module OpenSSL scanned.join end - def get_definition(io) - if line = get_line(io) + def get_definition(io_stack) + if line = get_line(io_stack) while /[^\\]\\\z/ =~ line - if extra = get_line(io) + if extra = get_line(io_stack) line += extra else break @@ -224,9 +239,12 @@ module OpenSSL end end - def get_line(io) - if line = io.gets - line.gsub(/[\r\n]*/, '') + def get_line(io_stack) + while io = io_stack.last + if line = io.gets + return line.gsub(/[\r\n]*/, '') + end + io_stack.pop end end end diff --git a/test/test_config.rb b/test/test_config.rb index 99dcc497..d8010ae0 100644 --- a/test/test_config.rb +++ b/test/test_config.rb @@ -120,6 +120,49 @@ __EOC__ assert_equal("error in line 7: missing close square bracket", excn.message) end + def test_s_parse_include + in_tmpdir("ossl-config-include-test") do |dir| + Dir.mkdir("child") + File.write("child/a.conf", <<~__EOC__) + [default] + file-a = a.conf + [sec-a] + a = 123 + __EOC__ + File.write("child/b.cnf", <<~__EOC__) + [default] + file-b = b.cnf + [sec-b] + b = 123 + __EOC__ + File.write("include-child.conf", <<~__EOC__) + key_outside_section = value_a + .include child + __EOC__ + + include_file = <<~__EOC__ + [default] + file-main = unnamed + [sec-main] + main = 123 + .include = include-child.conf + __EOC__ + + # Include a file by relative path + c1 = OpenSSL::Config.parse(include_file) + assert_equal(["default", "sec-a", "sec-b", "sec-main"], c1.sections.sort) + assert_equal(["file-main", "file-a", "file-b"], c1["default"].keys) + assert_equal({"a" => "123"}, c1["sec-a"]) + assert_equal({"b" => "123"}, c1["sec-b"]) + assert_equal({"main" => "123", "key_outside_section" => "value_a"}, c1["sec-main"]) + + # Relative paths are from the working directory + assert_raise(OpenSSL::ConfigError) do + Dir.chdir("child") { OpenSSL::Config.parse(include_file) } + end + end + end + def test_s_load # alias of new c = OpenSSL::Config.load @@ -299,6 +342,17 @@ __EOC__ @it['newsection'] = {'a' => 'b'} assert_not_equal(@it.sections.sort, c.sections.sort) end + + private + + def in_tmpdir(*args) + Dir.mktmpdir(*args) do |dir| + dir = File.realpath(dir) + Dir.chdir(dir) do + yield dir + end + end + end end end |