]> git.ipfire.org Git - thirdparty/pdns.git/commitdiff
Add a test parser for SVCB value-lists
authorPieter Lexis <pieter.lexis@powerdns.com>
Mon, 8 Feb 2021 15:55:08 +0000 (16:55 +0100)
committerPieter Lexis <pieter.lexis@powerdns.com>
Mon, 29 Mar 2021 17:10:31 +0000 (19:10 +0200)
pdns/dnslabeltext.rl
pdns/misc.hh
pdns/test-misc_hh.cc

index 393a52172064993068681aeb48958bef333f159a..3eabf7274845cd5f45848705a79412a3aaa08944 100644 (file)
@@ -240,6 +240,81 @@ size_t parseRFC1035CharString(const std::string &in, std::string &val) {
   return counter;
 }
 
+size_t parseSVCBValueList(const std::string &in, std::vector<std::string> &val) {
+  val.clear();
+  const char *p = in.c_str();
+  const char *pe = p + in.size();
+  int cs = 0;
+  uint8_t escaped_octet = 0;
+  // Keeps track of how many chars we read from the source string
+  size_t counter=0;
+
+  // Here we store the parsed value until we hit a comma or are done
+  std::string tmp;
+
+%%{
+  machine dns_text_to_value_list;
+
+  action doEscapedNumber {
+    escaped_octet *= 10;
+    escaped_octet += fc-'0';
+    counter++;
+  }
+
+  action doneEscapedNumber {
+    tmp += escaped_octet;
+    escaped_octet = 0;
+  }
+
+  action addToVal {
+    tmp += fc;
+    counter++;
+  }
+
+  action handleComma {
+    val.push_back(tmp);
+    tmp.clear();
+    counter++;
+  }
+
+  action incrementCounter {
+    counter++;
+  }
+
+  # generated rules, define required actions
+  DIGIT = 0x30..0x39;
+  DQUOTE = "\"";
+  HTAB = "\t";
+  SP = " ";
+  WSP = (SP | HTAB)@addToVal;
+  non_special = "!" | 0x23..0x27 | 0x2a..0x2b | 0x2d..0x3a | 0x3c..0x5b | 0x5d..0x7e;
+  non_digit = 0x21..0x2f | 0x3a..0x7e;
+  dec_octet = ( ( "0" | "1" ) DIGIT{2} ) | ( "2" ( ( 0x30..0x34 DIGIT ) | ( "5" 0x30..0x35 ) ) );
+  escaped = '\\'@incrementCounter ( non_digit$addToVal | dec_octet$doEscapedNumber@doneEscapedNumber );
+  contiguous = ( non_special$addToVal | escaped )+;
+  comma = ',';
+  quoted_sepped = ( contiguous | ('\\'? WSP) )* (comma@handleComma ( contiguous | ('\\'? WSP) )+ )*;
+  unquoted_sepped = (contiguous (comma@handleComma contiguous)*);
+  quoted = DQUOTE@incrementCounter quoted_sepped DQUOTE@incrementCounter;
+  char_string = (quoted | unquoted_sepped);
+
+  # instantiate machine rules
+  main := char_string;
+  write data;
+  write init;
+}%%
+
+  // silence warnings
+  (void) dns_text_to_value_list_first_final;
+  (void) dns_text_to_value_list_error;
+  (void) dns_text_to_value_list_en_main;
+  %% write exec;
+
+  // Add the last-parsed value to val
+  // ideally, we'd use a transition as well, but too many hours were wasted trying that
+  val.push_back(tmp);
+  return counter;
+}
 
 
 #if 0
index 193750446ca2573ba77ebed3fb24dc11c3c7d675..be78521df74dae29ec5655808dbce1df90835f66 100644 (file)
@@ -624,5 +624,6 @@ DNSName reverseNameFromIP(const ComboAddress& ip);
 
 std::string getCarbonHostName();
 size_t parseRFC1035CharString(const std::string &in, std::string &val); // from ragel
+size_t parseSVCBValueList(const std::string &in, vector<std::string> &val); // from ragel
 
 std::string makeLuaString(const std::string& in);
index 52ac44ff74553a72f274f4155cb7d8194237fb76..d53c0770fdfbdcba2fb22fce50c0853a35710c10 100644 (file)
@@ -227,4 +227,79 @@ BOOST_AUTO_TEST_CASE(test_getCarbonHostName)
   BOOST_CHECK_EQUAL(my_hostname.size(), hostname.size());
 }
 
+BOOST_AUTO_TEST_CASE(test_parseSVCBValueList)
+{
+  vector<string> out;
+
+  parseSVCBValueList("foobar123", out);
+  BOOST_CHECK_EQUAL(out.size(), 1);
+  BOOST_CHECK_EQUAL(out[0], "foobar123");
+
+  parseSVCBValueList("h2,h3", out);
+  BOOST_CHECK_EQUAL(out.size(), 2);
+  BOOST_CHECK_EQUAL(out[0], "h2");
+  BOOST_CHECK_EQUAL(out[1], "h3");
+
+  parseSVCBValueList("h2,h3-19,h3-20,h3-22", out);
+  BOOST_CHECK_EQUAL(out.size(), 4);
+  BOOST_CHECK_EQUAL(out[0], "h2");
+  BOOST_CHECK_EQUAL(out[1], "h3-19");
+  BOOST_CHECK_EQUAL(out[2], "h3-20");
+  BOOST_CHECK_EQUAL(out[3], "h3-22");
+
+  parseSVCBValueList("foobar123,bazquux456", out);
+  BOOST_CHECK_EQUAL(out.size(), 2);
+  BOOST_CHECK_EQUAL(out[0], "foobar123");
+  BOOST_CHECK_EQUAL(out[1], "bazquux456");
+
+  parseSVCBValueList("foobar123\\,bazquux456", out);
+  BOOST_CHECK_EQUAL(out.size(), 1);
+  BOOST_CHECK_EQUAL(out[0], "foobar123,bazquux456");
+
+  parseSVCBValueList("foobar123\\044bazquux456", out);
+  BOOST_CHECK_EQUAL(out.size(), 1);
+  BOOST_CHECK_EQUAL(out[0], "foobar123,bazquux456");
+
+  // Again, but quoted
+  parseSVCBValueList("\"foobar123\"", out);
+  BOOST_CHECK_EQUAL(out.size(), 1);
+  BOOST_CHECK_EQUAL(out[0], "foobar123");
+
+  parseSVCBValueList("\"foobar123,bazquux456\"", out);
+  BOOST_CHECK_EQUAL(out.size(), 2);
+  BOOST_CHECK_EQUAL(out[0], "foobar123");
+  BOOST_CHECK_EQUAL(out[1], "bazquux456");
+
+  parseSVCBValueList("\"foobar123\\,bazquux456\"", out);
+  BOOST_CHECK_EQUAL(out.size(), 1);
+  BOOST_CHECK_EQUAL(out[0], "foobar123,bazquux456");
+
+  parseSVCBValueList("\"foobar123\\044bazquux456\"", out);
+  BOOST_CHECK_EQUAL(out.size(), 1);
+  BOOST_CHECK_EQUAL(out[0], "foobar123,bazquux456");
+
+  // Quoted, with some whitespace
+  parseSVCBValueList("\"foobar123 \"", out);
+  BOOST_CHECK_EQUAL(out.size(), 1);
+  BOOST_CHECK_EQUAL(out[0], "foobar123 ");
+
+  parseSVCBValueList("\"foobar123 blabla bla,baz quux456\"", out);
+  BOOST_CHECK_EQUAL(out.size(), 2);
+  BOOST_CHECK_EQUAL(out[0], "foobar123 blabla bla");
+  BOOST_CHECK_EQUAL(out[1], "baz quux456");
+
+  parseSVCBValueList("\"foobar123,baz quux456\"", out);
+  BOOST_CHECK_EQUAL(out.size(), 2);
+  BOOST_CHECK_EQUAL(out[0], "foobar123");
+  BOOST_CHECK_EQUAL(out[1], "baz quux456");
+
+  parseSVCBValueList("\"foobar123 blabla bla\\,baz quux456\"", out);
+  BOOST_CHECK_EQUAL(out.size(), 1);
+  BOOST_CHECK_EQUAL(out[0], "foobar123 blabla bla,baz quux456");
+
+  parseSVCBValueList("\"foobar123 blabla bla\\044baz quux456\"", out);
+  BOOST_CHECK_EQUAL(out.size(), 1);
+  BOOST_CHECK_EQUAL(out[0], "foobar123 blabla bla,baz quux456");
+}
+
 BOOST_AUTO_TEST_SUITE_END()