diff --git a/lib/dns/zone/rr/txt.rb b/lib/dns/zone/rr/txt.rb index 841b7ac..a1ddb52 100644 --- a/lib/dns/zone/rr/txt.rb +++ b/lib/dns/zone/rr/txt.rb @@ -7,7 +7,7 @@ class DNS::Zone::RR::TXT < DNS::Zone::RR::Record def dump parts = general_prefix - parts << %Q{"#{text}"} + parts << quote_text(text) parts.join(' ') end @@ -19,4 +19,17 @@ def load(string, options = {}) self end + protected + + # Quotes the given text, e.g. the content of a TXT or SPF record. + # Respects the rule that a single string may contain at most 255 chars, but + # multiple strings can be used to produce longer content. See also RFC 4408, + # section 3.1.3. + # + # @param text [String] the (potentially long) text + # @return [String] the quoted string or, if needed, several quoted strings + def quote_text(text) + text.chars.each_slice(200).map(&:join).map { |chunk| %Q{"#{chunk}"} }.join(' ') + end + end diff --git a/test/rr/txt_test.rb b/test/rr/txt_test.rb index 77a78e5..69343bf 100644 --- a/test/rr/txt_test.rb +++ b/test/rr/txt_test.rb @@ -18,6 +18,19 @@ def test_build_rr__txt assert_equal 'labelname 2w IN TXT "test text"', rr.dump end + def test_build_multiple_quoted_strings + rr = DNS::Zone::RR::TXT.new + + # set a long text with 300 characters + rr.text = '(10 chars)' * 30 + + # we expect chunks of at most 200 characters + # (but actually implementations leading to at most 255 chars would also be fine) + chunk1 = %Q{"#{'(10 chars)' * 20}"} + chunk2 = %Q{"#{'(10 chars)' * 10}"} + assert_equal "@ IN TXT #{chunk1} #{chunk2}", rr.dump + end + def test_load_rr__txt rr = DNS::Zone::RR::TXT.new.load('txtrecord IN TXT "test text"') assert_equal 'txtrecord', rr.label