Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit b4c893a

Browse files
committed
OpenSSL 1.1.1 introduces a new '.include' directive. Update our config
parser to support that. As mentioned in the referenced GitHub issue, we should use the OpenSSL API instead of implementing the parsing logic ourselves, but it will need backwards-incompatible changes which we can't backport to stable versions. So continue to use the Ruby implementation for now. References: ruby/openssl#208 ruby/openssl#216 The original patch was written by Kazuki Yamaguchi <[email protected]> and the patch for ruby_2_7 branch was prepared by Vít Ondruch.
1 parent a0bb4eb commit b4c893a

File tree

3 files changed

+92
-20
lines changed

3 files changed

+92
-20
lines changed

ext/openssl/lib/openssl/config.rb

+36-18
Original file line numberDiff line numberDiff line change
@@ -77,29 +77,44 @@ def get_key_string(data, section, key) # :nodoc:
7777
def parse_config_lines(io)
7878
section = 'default'
7979
data = {section => {}}
80-
while definition = get_definition(io)
80+
io_stack = [io]
81+
while definition = get_definition(io_stack)
8182
definition = clear_comments(definition)
8283
next if definition.empty?
83-
if definition[0] == ?[
84+
case definition
85+
when /\A\[/
8486
if /\[([^\]]*)\]/ =~ definition
8587
section = $1.strip
8688
data[section] ||= {}
8789
else
8890
raise ConfigError, "missing close square bracket"
8991
end
90-
else
91-
if /\A([^:\s]*)(?:::([^:\s]*))?\s*=(.*)\z/ =~ definition
92-
if $2
93-
section = $1
94-
key = $2
95-
else
96-
key = $1
92+
when /\A\.include (\s*=\s*)?(.+)\z/
93+
path = $2
94+
if File.directory?(path)
95+
files = Dir.glob(File.join(path, "*.{cnf,conf}"), File::FNM_EXTGLOB)
96+
else
97+
files = [path]
98+
end
99+
100+
files.each do |filename|
101+
begin
102+
io_stack << StringIO.new(File.read(filename))
103+
rescue
104+
raise ConfigError, "could not include file '%s'" % filename
97105
end
98-
value = unescape_value(data, section, $3)
99-
(data[section] ||= {})[key] = value.strip
106+
end
107+
when /\A([^:\s]*)(?:::([^:\s]*))?\s*=(.*)\z/
108+
if $2
109+
section = $1
110+
key = $2
100111
else
101-
raise ConfigError, "missing equal sign"
112+
key = $1
102113
end
114+
value = unescape_value(data, section, $3)
115+
(data[section] ||= {})[key] = value.strip
116+
else
117+
raise ConfigError, "missing equal sign"
103118
end
104119
end
105120
data
@@ -212,10 +227,10 @@ def clear_comments(line)
212227
scanned.join
213228
end
214229

215-
def get_definition(io)
216-
if line = get_line(io)
230+
def get_definition(io_stack)
231+
if line = get_line(io_stack)
217232
while /[^\\]\\\z/ =~ line
218-
if extra = get_line(io)
233+
if extra = get_line(io_stack)
219234
line += extra
220235
else
221236
break
@@ -225,9 +240,12 @@ def get_definition(io)
225240
end
226241
end
227242

228-
def get_line(io)
229-
if line = io.gets
230-
line.gsub(/[\r\n]*/, '')
243+
def get_line(io_stack)
244+
while io = io_stack.last
245+
if line = io.gets
246+
return line.gsub(/[\r\n]*/, '')
247+
end
248+
io_stack.pop
231249
end
232250
end
233251
end

test/openssl/test_config.rb

+54
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,49 @@ def test_s_parse_format
120120
assert_equal("error in line 7: missing close square bracket", excn.message)
121121
end
122122

123+
def test_s_parse_include
124+
in_tmpdir("ossl-config-include-test") do |dir|
125+
Dir.mkdir("child")
126+
File.write("child/a.conf", <<~__EOC__)
127+
[default]
128+
file-a = a.conf
129+
[sec-a]
130+
a = 123
131+
__EOC__
132+
File.write("child/b.cnf", <<~__EOC__)
133+
[default]
134+
file-b = b.cnf
135+
[sec-b]
136+
b = 123
137+
__EOC__
138+
File.write("include-child.conf", <<~__EOC__)
139+
key_outside_section = value_a
140+
.include child
141+
__EOC__
142+
143+
include_file = <<~__EOC__
144+
[default]
145+
file-main = unnamed
146+
[sec-main]
147+
main = 123
148+
.include = include-child.conf
149+
__EOC__
150+
151+
# Include a file by relative path
152+
c1 = OpenSSL::Config.parse(include_file)
153+
assert_equal(["default", "sec-a", "sec-b", "sec-main"], c1.sections.sort)
154+
assert_equal(["file-main", "file-a", "file-b"], c1["default"].keys)
155+
assert_equal({"a" => "123"}, c1["sec-a"])
156+
assert_equal({"b" => "123"}, c1["sec-b"])
157+
assert_equal({"main" => "123", "key_outside_section" => "value_a"}, c1["sec-main"])
158+
159+
# Relative paths are from the working directory
160+
assert_raise(OpenSSL::ConfigError) do
161+
Dir.chdir("child") { OpenSSL::Config.parse(include_file) }
162+
end
163+
end
164+
end
165+
123166
def test_s_load
124167
# alias of new
125168
c = OpenSSL::Config.load
@@ -299,6 +342,17 @@ def test_clone
299342
@it['newsection'] = {'a' => 'b'}
300343
assert_not_equal(@it.sections.sort, c.sections.sort)
301344
end
345+
346+
private
347+
348+
def in_tmpdir(*args)
349+
Dir.mktmpdir(*args) do |dir|
350+
dir = File.realpath(dir)
351+
Dir.chdir(dir) do
352+
yield dir
353+
end
354+
end
355+
end
302356
end
303357

304358
end

version.h

+2-2
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,11 @@
22
# define RUBY_VERSION_MINOR RUBY_API_VERSION_MINOR
33
#define RUBY_VERSION_TEENY 1
44
#define RUBY_RELEASE_DATE RUBY_RELEASE_YEAR_STR"-"RUBY_RELEASE_MONTH_STR"-"RUBY_RELEASE_DAY_STR
5-
#define RUBY_PATCHLEVEL 91
5+
#define RUBY_PATCHLEVEL 92
66

77
#define RUBY_RELEASE_YEAR 2020
88
#define RUBY_RELEASE_MONTH 7
9-
#define RUBY_RELEASE_DAY 10
9+
#define RUBY_RELEASE_DAY 11
1010

1111
#include "ruby/version.h"
1212

0 commit comments

Comments
 (0)