Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion lib/fluent/config/basic_parser.rb
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ def initialize(strscan)
SPACING = /(?:[ \t\r\n]|\z|\#.*?(?:\z|[\r\n]))+/
ZERO_OR_MORE_SPACING = /(?:[ \t\r\n]|\z|\#.*?(?:\z|[\r\n]))*/
SPACING_WITHOUT_COMMENT = /(?:[ \t\r\n]|\z)+/
LINE_END_WITHOUT_SPACING_AND_COMMENT = /(?:\z|[\r\n])/

module ClassMethods
def symbol(string)
Expand Down
20 changes: 15 additions & 5 deletions lib/fluent/config/literal_parser.rb
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,15 @@
module Fluent
module Config
class LiteralParser < BasicParser
# A physical line break (LF, CR, or CRLF) inside a quoted string.
# CRLF is normalized to LF so that the same config text does not produce a
# different value depending on whether the file was saved with LF or CRLF.
# A lone CR is kept as-is, and an escaped "\r\n" still produces CRLF.
LINE_BREAK = /\r\n|[\r\n]/
# A backslash immediately followed by a physical line break.
# It works as a line continuation, so both are stripped from the value.
LINE_CONTINUATION = /\\#{LINE_BREAK}/o

def self.unescape_char(c)
case c
when '"'
Expand Down Expand Up @@ -99,11 +108,10 @@ def scan_double_quoted_string
else
return string.join
end
elsif check(/[^"]#{LINE_END_WITHOUT_SPACING_AND_COMMENT}/o)
if s = check(/[^\\]#{LINE_END_WITHOUT_SPACING_AND_COMMENT}/o)
string << s
end
skip(/[^"]#{LINE_END_WITHOUT_SPACING_AND_COMMENT}/o)
elsif skip(LINE_CONTINUATION)
next
elsif s = scan(LINE_BREAK)
string << (s == "\r\n" ? "\n" : s)
elsif s = scan(/\\./)
string << eval_escape_char(s[1,1])
elsif skip(/\#\{/)
Expand All @@ -126,6 +134,8 @@ def scan_single_quoted_string
string << "'"
elsif s = scan(/\\\\/)
string << "\\"
elsif s = scan(LINE_BREAK)
string << (s == "\r\n" ? "\n" : s)
elsif s = scan(/./)
string << s
else
Expand Down
1 change: 1 addition & 0 deletions test/config/test_config_parser.rb
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,7 @@ def parse_text(text)
end

test "support multiline string" do
assert_text_parsed_as(e('ROOT', '', {"k1" => "world\n\n"}), "k1 \"world\n\n\"")
assert_text_parsed_as(e('ROOT', '',
{"k1" => %[line1
line2]
Expand Down
15 changes: 15 additions & 0 deletions test/config/test_literal_parser.rb
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,14 @@ def test_falseX
test('"t') { assert_parse_error('"t') } # non-terminated quoted character
test("\"t\nt\"") { assert_text_parsed_as("t\nt", "\"t\nt\"" ) } # multiline string
test("\"t\\\nt\"") { assert_text_parsed_as("tt", "\"t\\\nt\"" ) } # multiline string
test("\"t\n\nt\"") { assert_text_parsed_as("t\n\nt", "\"t\n\nt\"") }
test("\"\nt\"") { assert_text_parsed_as("\nt", "\"\nt\"") }
test("\"t\\\\\nt\"") { assert_text_parsed_as("t\\\nt", "\"t\\\\\nt\"") }
test("\"t\r\nt\"") { assert_text_parsed_as("t\nt", "\"t\r\nt\"") }
test("\"t\rt\"") { assert_text_parsed_as("t\rt", "\"t\rt\"") }
test("\"t\\\r\nt\"") { assert_text_parsed_as("tt", "\"t\\\r\nt\"") }
test("\"t\n") { assert_parse_error("\"t\n") }
test("\"t\\\n") { assert_parse_error("\"t\\\n") }
test('t"') { assert_text_parsed_as('t"', 't"') }
test('"."') { assert_text_parsed_as('.', '"."') }
test('"*"') { assert_text_parsed_as('*', '"*"') }
Expand Down Expand Up @@ -138,6 +146,13 @@ def test_falseX
test("'\\0'") { assert_text_parsed_as('\0', "'\\0'") }
test("'\\1'") { assert_text_parsed_as('\1', "'\\1'") }
test("'t") { assert_parse_error("'t") } # non-terminated quoted character
test("'t\nt'") { assert_text_parsed_as("t\nt", "'t\nt'") }
test("'t\n\nt'") { assert_text_parsed_as("t\n\nt", "'t\n\nt'") }
test("'\nt'") { assert_text_parsed_as("\nt", "'\nt'") }
test("'t\r\nt'") { assert_text_parsed_as("t\nt", "'t\r\nt'") }
test("'t\rt'") { assert_text_parsed_as("t\rt", "'t\rt'") }
test("'t\\\nt'") { assert_text_parsed_as("t\\\nt", "'t\\\nt'") }
test("'t\n") { assert_parse_error("'t\n") }
test("t'") { assert_text_parsed_as("t'", "t'") }
test("'.'") { assert_text_parsed_as('.', "'.'") }
test("'*'") { assert_text_parsed_as('*', "'*'") }
Expand Down