Skip to content

Commit

Permalink
replace bool with once
Browse files Browse the repository at this point in the history
  • Loading branch information
csucu committed Aug 30, 2023
1 parent b1f3f8c commit 3946aba
Show file tree
Hide file tree
Showing 3 changed files with 31 additions and 32 deletions.
2 changes: 1 addition & 1 deletion listener.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,6 @@ type Listener interface {
Directive(unused bool, qualifier, mechanism, value, effectiveValue string)
NonMatch(qualifier, mechanism, value string, result Result, err error)
Match(qualifier, mechanism, value string, result Result, explanation string, ttl time.Duration, err error)
FireFirstMatch(r Result, err error)
FirstMatch(r Result, err error)
MatchingIP(qualifier, mechanism, value string, fqdn string, ipn net.IPNet, host string, ip net.IP)
}
59 changes: 29 additions & 30 deletions parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"net"
"strconv"
"strings"
"sync"
"time"
)

Expand Down Expand Up @@ -90,44 +91,42 @@ func (e SyntaxError) TokenString() string {
// level CheckHost method as well as tokenized terms from TXT RR. One should
// call parser.Parse() for a proper SPF evaluation.
type parser struct {
sender string
domain string
heloDomain string
ip net.IP
query string
resolver Resolver
listener Listener
ignoreMatches bool
options []Option
visited *stringsStack
evaluatedOn time.Time
receivingFQDN string
stopAtError func(error) bool
partialMacros bool
// flag to indicate we have already called fireFirstMatch(..)
firstMatchFound *bool
sender string
domain string
heloDomain string
ip net.IP
query string
resolver Resolver
listener Listener
ignoreMatches bool
options []Option
visited *stringsStack
evaluatedOn time.Time
receivingFQDN string
stopAtError func(error) bool
partialMacros bool
fireFirstMatchOnce *sync.Once
}

// newParser creates new Parser objects and returns its reference.
// It accepts CheckHost() parameters as well as SPF query (fetched from TXT RR
// during initial DNS lookup.
func newParser(opts ...Option) *parser {
var firstMatchFound = false
return newParserWithVisited(newStringsStack(), &firstMatchFound, opts...)
return newParserWithVisited(newStringsStack(), new(sync.Once), opts...)
}

// newParserWithVisited creates new Parser objects with prepopulated map of visited domains and returns its reference.
// It accepts CheckHost() parameters as well as SPF query (fetched from TXT RR
// during initial DNS lookup.
func newParserWithVisited(visited *stringsStack, firstMatchFound *bool, opts ...Option) *parser {
func newParserWithVisited(visited *stringsStack, fireFirstMatchOnce *sync.Once, opts ...Option) *parser {
p := &parser{
// mechanisms: make([]*token, 0, 10),
resolver: NewLimitedResolver(&DNSResolver{}, 10, 10),
options: opts,
visited: visited,
receivingFQDN: "unknown",
evaluatedOn: time.Now().UTC(),
firstMatchFound: firstMatchFound,
resolver: NewLimitedResolver(&DNSResolver{}, 10, 10),
options: opts,
visited: visited,
receivingFQDN: "unknown",
evaluatedOn: time.Now().UTC(),
fireFirstMatchOnce: fireFirstMatchOnce,
}
for _, opt := range opts {
opt(p)
Expand Down Expand Up @@ -190,7 +189,7 @@ func (p *parser) checkHost(ip net.IP, domain, sender string) (r Result, expl str
return None, "", "", ErrSPFNotFound
}

r, expl, u, err = newParserWithVisited(p.visited, p.firstMatchFound, p.options...).with(spf, sender, domain, ip).check()
r, expl, u, err = newParserWithVisited(p.visited, p.fireFirstMatchOnce, p.options...).with(spf, sender, domain, ip).check()
return
}

Expand Down Expand Up @@ -268,9 +267,7 @@ func (p *parser) check() (Result, string, unused, error) {
}

// Store the first match result if not already set
if p.ignoreMatches && matches && !*p.firstMatchFound {
*p.firstMatchFound = true
// should only be called once
if p.ignoreMatches && matches {
p.fireFirstMatch(result, err)
}

Expand Down Expand Up @@ -356,7 +353,9 @@ func (p *parser) fireFirstMatch(r Result, e error) {
if p.listener == nil {
return
}
p.listener.FireFirstMatch(r, e)
p.fireFirstMatchOnce.Do(func() {
p.listener.FirstMatch(r, e)
})
}

func sortTokens(tokens []*token) (mechanisms []*token, redirect, explanation *token, err error) {
Expand Down
2 changes: 1 addition & 1 deletion printer/printer.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ func (p *Printer) Match(qualifier, mechanism, value string, result spf.Result, e
// fmt.Fprintf(p.w, "%sMATCH: %s, %q, %v\n", strings.Repeat(" ", p.c), result, explanation, err)
}

func (p *Printer) FireFirstMatch(r spf.Result, err error) {
func (p *Printer) FirstMatch(r spf.Result, err error) {
fmt.Fprintf(p.w, "%sFIRST-MATCH: %s, %v\n", strings.Repeat(" ", p.c), r, err)
}

Expand Down

0 comments on commit 3946aba

Please sign in to comment.