refactor: remove ParseZone and parseZone (#1099)
This commit is contained in:
parent
5bfe94bb6e
commit
d128d10d17
@ -62,22 +62,23 @@ $GENERATE 0-1/0 dhcp-${0,4,d} A 10.0.0.$
|
||||
{`@ IN SOA ns.test. hostmaster.test. ( 1 8h 2h 7d 1d )
|
||||
$GENERATE 0-1 $$INCLUDE ` + tmpdir + string(filepath.Separator) + `${0,4,d}.conf
|
||||
`, false},
|
||||
{`@ IN SOA ns.test. hostmaster.test. ( 1 8h 2h 7d 1d )
|
||||
{`@ IN SOA ns.test. hostmaster.test. ( 1 8h 2h 7d 1d )
|
||||
$GENERATE 0-1 dhcp-${0,4,d} A 10.0.0.$
|
||||
$GENERATE 0-2 dhcp-${0,4,d} A 10.1.0.$
|
||||
`, false},
|
||||
}
|
||||
Outer:
|
||||
|
||||
for i := range tests {
|
||||
for tok := range ParseZone(strings.NewReader(tests[i].zone), "test.", "test") {
|
||||
if tok.Error != nil {
|
||||
if !tests[i].fail {
|
||||
t.Errorf("expected \n\n%s\nto be parsed, but got %v", tests[i].zone, tok.Error)
|
||||
}
|
||||
continue Outer
|
||||
}
|
||||
z := NewZoneParser(strings.NewReader(tests[i].zone), "test.", "test")
|
||||
z.SetIncludeAllowed(true)
|
||||
|
||||
for _, ok := z.Next(); ok; _, ok = z.Next() {
|
||||
}
|
||||
if tests[i].fail {
|
||||
|
||||
err := z.Err()
|
||||
if err != nil && !tests[i].fail {
|
||||
t.Errorf("expected \n\n%s\nto be parsed, but got %v", tests[i].zone, err)
|
||||
} else if err == nil && tests[i].fail {
|
||||
t.Errorf("expected \n\n%s\nto fail, but got no error", tests[i].zone)
|
||||
}
|
||||
}
|
||||
|
@ -546,25 +546,25 @@ $TTL 314
|
||||
example.com. DNAME 10 ; TTL=314 after second $TTL
|
||||
`
|
||||
reCaseFromComment := regexp.MustCompile(`TTL=(\d+)\s+(.*)`)
|
||||
records := ParseZone(strings.NewReader(zone), "", "")
|
||||
z := NewZoneParser(strings.NewReader(zone), "", "")
|
||||
var i int
|
||||
for record := range records {
|
||||
|
||||
for rr, ok := z.Next(); ok; rr, ok = z.Next() {
|
||||
i++
|
||||
if record.Error != nil {
|
||||
t.Error(record.Error)
|
||||
continue
|
||||
}
|
||||
expected := reCaseFromComment.FindStringSubmatch(record.Comment)
|
||||
expected := reCaseFromComment.FindStringSubmatch(z.Comment())
|
||||
if len(expected) != 3 {
|
||||
t.Errorf("regexp didn't match for record %d", i)
|
||||
continue
|
||||
}
|
||||
expectedTTL, _ := strconv.ParseUint(expected[1], 10, 32)
|
||||
ttl := record.RR.Header().Ttl
|
||||
ttl := rr.Header().Ttl
|
||||
if ttl != uint32(expectedTTL) {
|
||||
t.Errorf("%s: expected TTL %d, got %d", expected[2], expectedTTL, ttl)
|
||||
}
|
||||
}
|
||||
if err := z.Err(); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
if i != 10 {
|
||||
t.Errorf("expected %d records, got %d", 5, i)
|
||||
}
|
||||
@ -603,16 +603,12 @@ func TestRelativeNameErrors(t *testing.T) {
|
||||
},
|
||||
}
|
||||
for _, errorCase := range badZones {
|
||||
entries := ParseZone(strings.NewReader(errorCase.zoneContents), "", "")
|
||||
for entry := range entries {
|
||||
if entry.Error == nil {
|
||||
t.Errorf("%s: expected error, got nil", errorCase.label)
|
||||
continue
|
||||
}
|
||||
err := entry.Error.err
|
||||
if err != errorCase.expectedErr {
|
||||
t.Errorf("%s: expected error `%s`, got `%s`", errorCase.label, errorCase.expectedErr, err)
|
||||
}
|
||||
z := NewZoneParser(strings.NewReader(errorCase.zoneContents), "", "")
|
||||
z.Next()
|
||||
if err := z.Err(); err == nil {
|
||||
t.Errorf("%s: expected error, got nil", errorCase.label)
|
||||
} else if !strings.Contains(err.Error(), errorCase.expectedErr) {
|
||||
t.Errorf("%s: expected error `%s`, got `%s`", errorCase.label, errorCase.expectedErr, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -719,9 +715,13 @@ func TestRfc1982(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestEmpty(t *testing.T) {
|
||||
for range ParseZone(strings.NewReader(""), "", "") {
|
||||
z := NewZoneParser(strings.NewReader(""), "", "")
|
||||
for _, ok := z.Next(); ok; _, ok = z.Next() {
|
||||
t.Errorf("should be empty")
|
||||
}
|
||||
if err := z.Err(); err != nil {
|
||||
t.Error("got an error when it shouldn't")
|
||||
}
|
||||
}
|
||||
|
||||
func TestLowercaseTokens(t *testing.T) {
|
||||
@ -889,18 +889,20 @@ foo. IN DNSKEY 256 3 5 AwEAAb+8l ; this is comment 6
|
||||
foo. IN NSEC miek.nl. TXT RRSIG NSEC; this is comment 7
|
||||
foo. IN TXT "THIS IS TEXT MAN"; this is comment 8
|
||||
`
|
||||
for x := range ParseZone(strings.NewReader(zone), ".", "") {
|
||||
if x.Error == nil {
|
||||
if x.Comment != "" {
|
||||
if _, ok := comments[x.Comment]; !ok {
|
||||
t.Errorf("wrong comment %q", x.Comment)
|
||||
}
|
||||
z := NewZoneParser(strings.NewReader(zone), ".", "")
|
||||
for _, ok := z.Next(); ok; _, ok = z.Next() {
|
||||
if z.Comment() != "" {
|
||||
if _, okC := comments[z.Comment()]; !okC {
|
||||
t.Errorf("wrong comment %q", z.Comment())
|
||||
}
|
||||
}
|
||||
}
|
||||
if err := z.Err(); err != nil {
|
||||
t.Error("got an error when it shouldn't")
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseZoneComments(t *testing.T) {
|
||||
func TestZoneParserComments(t *testing.T) {
|
||||
for i, test := range []struct {
|
||||
zone string
|
||||
comments []string
|
||||
@ -975,24 +977,25 @@ func TestParseZoneComments(t *testing.T) {
|
||||
r := strings.NewReader(test.zone)
|
||||
|
||||
var j int
|
||||
for r := range ParseZone(r, "", "") {
|
||||
if r.Error != nil {
|
||||
t.Fatal(r.Error)
|
||||
}
|
||||
|
||||
z := NewZoneParser(r, "", "")
|
||||
for rr, ok := z.Next(); ok; rr, ok = z.Next() {
|
||||
if j >= len(test.comments) {
|
||||
t.Fatalf("too many records for zone %d at %d record, expected %d", i, j+1, len(test.comments))
|
||||
}
|
||||
|
||||
if r.Comment != test.comments[j] {
|
||||
t.Errorf("invalid comment for record %d:%d %v / %v", i, j, r.RR, r.Error)
|
||||
if z.Comment() != test.comments[j] {
|
||||
t.Errorf("invalid comment for record %d:%d %v", i, j, rr)
|
||||
t.Logf("expected %q", test.comments[j])
|
||||
t.Logf("got %q", r.Comment)
|
||||
t.Logf("got %q", z.Comment())
|
||||
}
|
||||
|
||||
j++
|
||||
}
|
||||
|
||||
if err := z.Err(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if j != len(test.comments) {
|
||||
t.Errorf("too few records for zone %d, got %d, expected %d", i, j, len(test.comments))
|
||||
}
|
||||
|
@ -158,9 +158,11 @@ func TestPrivateZoneParser(t *testing.T) {
|
||||
defer dns.PrivateHandleRemove(TypeVERSION)
|
||||
|
||||
r := strings.NewReader(smallzone)
|
||||
for x := range dns.ParseZone(r, ".", "") {
|
||||
if err := x.Error; err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
z := dns.NewZoneParser(r, ".", "")
|
||||
|
||||
for _, ok := z.Next(); ok; _, ok = z.Next() {
|
||||
}
|
||||
if err := z.Err(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
74
scan.go
74
scan.go
@ -87,16 +87,6 @@ type lex struct {
|
||||
column int // column in the file
|
||||
}
|
||||
|
||||
// Token holds the token that are returned when a zone file is parsed.
|
||||
type Token struct {
|
||||
// The scanned resource record when error is not nil.
|
||||
RR
|
||||
// When an error occurred, this has the error specifics.
|
||||
Error *ParseError
|
||||
// A potential comment positioned after the RR and on the same line.
|
||||
Comment string
|
||||
}
|
||||
|
||||
// ttlState describes the state necessary to fill in an omitted RR TTL
|
||||
type ttlState struct {
|
||||
ttl uint32 // ttl is the current default TTL
|
||||
@ -130,70 +120,6 @@ func ReadRR(r io.Reader, file string) (RR, error) {
|
||||
return rr, zp.Err()
|
||||
}
|
||||
|
||||
// ParseZone reads a RFC 1035 style zonefile from r. It returns
|
||||
// Tokens on the returned channel, each consisting of either a
|
||||
// parsed RR and optional comment or a nil RR and an error. The
|
||||
// channel is closed by ParseZone when the end of r is reached.
|
||||
//
|
||||
// The string file is used in error reporting and to resolve relative
|
||||
// $INCLUDE directives. The string origin is used as the initial
|
||||
// origin, as if the file would start with an $ORIGIN directive.
|
||||
//
|
||||
// The directives $INCLUDE, $ORIGIN, $TTL and $GENERATE are all
|
||||
// supported. Note that $GENERATE's range support up to a maximum of
|
||||
// of 65535 steps.
|
||||
//
|
||||
// Basic usage pattern when reading from a string (z) containing the
|
||||
// zone data:
|
||||
//
|
||||
// for x := range dns.ParseZone(strings.NewReader(z), "", "") {
|
||||
// if x.Error != nil {
|
||||
// // log.Println(x.Error)
|
||||
// } else {
|
||||
// // Do something with x.RR
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// Comments specified after an RR (and on the same line!) are
|
||||
// returned too:
|
||||
//
|
||||
// foo. IN A 10.0.0.1 ; this is a comment
|
||||
//
|
||||
// The text "; this is comment" is returned in Token.Comment.
|
||||
// Comments inside the RR are returned concatenated along with the
|
||||
// RR. Comments on a line by themselves are discarded.
|
||||
//
|
||||
// To prevent memory leaks it is important to always fully drain the
|
||||
// returned channel. If an error occurs, it will always be the last
|
||||
// Token sent on the channel.
|
||||
//
|
||||
// Deprecated: New users should prefer the ZoneParser API.
|
||||
func ParseZone(r io.Reader, origin, file string) chan *Token {
|
||||
t := make(chan *Token, 10000)
|
||||
go parseZone(r, origin, file, t)
|
||||
return t
|
||||
}
|
||||
|
||||
func parseZone(r io.Reader, origin, file string, t chan *Token) {
|
||||
defer close(t)
|
||||
|
||||
zp := NewZoneParser(r, origin, file)
|
||||
zp.SetIncludeAllowed(true)
|
||||
|
||||
for rr, ok := zp.Next(); ok; rr, ok = zp.Next() {
|
||||
t <- &Token{RR: rr, Comment: zp.Comment()}
|
||||
}
|
||||
|
||||
if err := zp.Err(); err != nil {
|
||||
pe, ok := err.(*ParseError)
|
||||
if !ok {
|
||||
pe = &ParseError{file: file, err: err.Error()}
|
||||
}
|
||||
|
||||
t <- &Token{Error: pe}
|
||||
}
|
||||
}
|
||||
|
||||
// ZoneParser is a parser for an RFC 1035 style zonefile.
|
||||
//
|
||||
// Each parsed RR in the zone is returned sequentially from Next. An
|
||||
|
70
scan_test.go
70
scan_test.go
@ -9,7 +9,7 @@ import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestParseZoneGenerate(t *testing.T) {
|
||||
func TestZoneParserGenerate(t *testing.T) {
|
||||
zone := "$ORIGIN example.org.\n$GENERATE 10-12 foo${2,3,d} IN A 127.0.0.$"
|
||||
|
||||
wantRRs := []RR{
|
||||
@ -17,22 +17,21 @@ func TestParseZoneGenerate(t *testing.T) {
|
||||
&A{Hdr: RR_Header{Name: "foo013.example.org."}, A: net.ParseIP("127.0.0.11")},
|
||||
&A{Hdr: RR_Header{Name: "foo014.example.org."}, A: net.ParseIP("127.0.0.12")},
|
||||
}
|
||||
|
||||
wantIdx := 0
|
||||
|
||||
tok := ParseZone(strings.NewReader(zone), "", "")
|
||||
for x := range tok {
|
||||
z := NewZoneParser(strings.NewReader(zone), "", "")
|
||||
|
||||
for rr, ok := z.Next(); ok; rr, ok = z.Next() {
|
||||
if wantIdx >= len(wantRRs) {
|
||||
t.Fatalf("expected %d RRs, but got more", len(wantRRs))
|
||||
}
|
||||
if x.Error != nil {
|
||||
t.Fatalf("expected no error, but got %s", x.Error)
|
||||
}
|
||||
if got, want := x.RR.Header().Name, wantRRs[wantIdx].Header().Name; got != want {
|
||||
if got, want := rr.Header().Name, wantRRs[wantIdx].Header().Name; got != want {
|
||||
t.Fatalf("expected name %s, but got %s", want, got)
|
||||
}
|
||||
a, ok := x.RR.(*A)
|
||||
if !ok {
|
||||
t.Fatalf("expected *A RR, but got %T", x.RR)
|
||||
a, okA := rr.(*A)
|
||||
if !okA {
|
||||
t.Fatalf("expected *A RR, but got %T", rr)
|
||||
}
|
||||
if got, want := a.A, wantRRs[wantIdx].(*A).A; !got.Equal(want) {
|
||||
t.Fatalf("expected A with IP %v, but got %v", got, want)
|
||||
@ -40,12 +39,16 @@ func TestParseZoneGenerate(t *testing.T) {
|
||||
wantIdx++
|
||||
}
|
||||
|
||||
if err := z.Err(); err != nil {
|
||||
t.Fatalf("expected no error, but got %s", err)
|
||||
}
|
||||
|
||||
if wantIdx != len(wantRRs) {
|
||||
t.Errorf("too few records, expected %d, got %d", len(wantRRs), wantIdx)
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseZoneInclude(t *testing.T) {
|
||||
func TestZoneParserInclude(t *testing.T) {
|
||||
|
||||
tmpfile, err := ioutil.TempFile("", "dns")
|
||||
if err != nil {
|
||||
@ -63,18 +66,19 @@ func TestParseZoneInclude(t *testing.T) {
|
||||
zone := "$ORIGIN example.org.\n$INCLUDE " + tmpfile.Name() + "\nbar\tIN\tA\t127.0.0.2"
|
||||
|
||||
var got int
|
||||
tok := ParseZone(strings.NewReader(zone), "", "")
|
||||
for x := range tok {
|
||||
if x.Error != nil {
|
||||
t.Fatalf("expected no error, but got %s", x.Error)
|
||||
}
|
||||
switch x.RR.Header().Name {
|
||||
z := NewZoneParser(strings.NewReader(zone), "", "")
|
||||
z.SetIncludeAllowed(true)
|
||||
for rr, ok := z.Next(); ok; _, ok = z.Next() {
|
||||
switch rr.Header().Name {
|
||||
case "foo.example.org.", "bar.example.org.":
|
||||
default:
|
||||
t.Fatalf("expected foo.example.org. or bar.example.org., but got %s", x.RR.Header().Name)
|
||||
t.Fatalf("expected foo.example.org. or bar.example.org., but got %s", rr.Header().Name)
|
||||
}
|
||||
got++
|
||||
}
|
||||
if err := z.Err(); err != nil {
|
||||
t.Fatalf("expected no error, but got %s", err)
|
||||
}
|
||||
|
||||
if expected := 2; got != expected {
|
||||
t.Errorf("failed to parse zone after include, expected %d records, got %d", expected, got)
|
||||
@ -82,17 +86,15 @@ func TestParseZoneInclude(t *testing.T) {
|
||||
|
||||
os.Remove(tmpfile.Name())
|
||||
|
||||
tok = ParseZone(strings.NewReader(zone), "", "")
|
||||
for x := range tok {
|
||||
if x.Error == nil {
|
||||
t.Fatalf("expected first token to contain an error but it didn't")
|
||||
}
|
||||
if !strings.Contains(x.Error.Error(), "failed to open") ||
|
||||
!strings.Contains(x.Error.Error(), tmpfile.Name()) ||
|
||||
!strings.Contains(x.Error.Error(), "no such file or directory") {
|
||||
t.Fatalf(`expected error to contain: "failed to open", %q and "no such file or directory" but got: %s`,
|
||||
tmpfile.Name(), x.Error)
|
||||
}
|
||||
z = NewZoneParser(strings.NewReader(zone), "", "")
|
||||
z.SetIncludeAllowed(true)
|
||||
z.Next()
|
||||
if err := z.Err(); err == nil ||
|
||||
!strings.Contains(err.Error(), "failed to open") ||
|
||||
!strings.Contains(err.Error(), tmpfile.Name()) ||
|
||||
!strings.Contains(err.Error(), "no such file or directory") {
|
||||
t.Fatalf(`expected error to contain: "failed to open", %q and "no such file or directory" but got: %s`,
|
||||
tmpfile.Name(), err)
|
||||
}
|
||||
}
|
||||
|
||||
@ -274,16 +276,6 @@ foo. IN NSEC miek.nl. TXT RRSIG NSEC; this is comment 7
|
||||
foo. IN TXT "THIS IS TEXT MAN"; this is comment 8
|
||||
`
|
||||
|
||||
func BenchmarkParseZone(b *testing.B) {
|
||||
for n := 0; n < b.N; n++ {
|
||||
for tok := range ParseZone(strings.NewReader(benchZone), "example.org.", "") {
|
||||
if tok.Error != nil {
|
||||
b.Fatal(tok.Error)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkZoneParser(b *testing.B) {
|
||||
for n := 0; n < b.N; n++ {
|
||||
zp := NewZoneParser(strings.NewReader(benchZone), "example.org.", "")
|
||||
|
Loading…
x
Reference in New Issue
Block a user