Commit 6dfac556 authored by Heiko Reese's avatar Heiko Reese
Browse files

search: changed internal search function; now returning certificates that...

search: changed internal search function; now returning certificates that match all tokens in the query (tokens are split on whitespace and may be quoted). Fixes #34.
parent a1de3fa0
......@@ -17,6 +17,7 @@ import (
"strings"
"time"
"unicode"
"unicode/utf8"
)
var (
......@@ -209,25 +210,65 @@ func NeverMatch(c *SearchableCert) bool { return false }
// MakeInternalSearchFilter creates a SCFilter that based on a simple substring match
func MakeInternalSearchFilter(query string) SCFilter {
cleaned := CleanupQueryString(query)
token := tokenizeQuery(cleaned)
// return zero results on empty query
if cleaned == "" {
return NeverMatch
}
// quote RE2-tokens
quoted := regexp.QuoteMeta(cleaned)
fullre := "(?:" + quoted + ")"
r, err := regexp.Compile(fullre)
if err != nil {
log.Printf("Unable to compile search [%s]: %s", query, err)
if len(token) == 0 {
return NeverMatch
}
// check if every token matches a certificate (token are combined with AND)
return func(c *SearchableCert) bool {
if r.FindStringIndex(c.searchablestring) == nil {
numMatches := 0
for _, t := range token {
if strings.Contains(c.searchablestring, t) {
numMatches++
}
}
return numMatches == len(token)
}
}
func tokenizeQuery(query string) []string {
lastQuote := rune(0)
// helper function that remembers the last quotation char (no nesting)
findSingleQuotedToken := func(c rune) bool {
switch {
case c == lastQuote:
lastQuote = rune(0)
return false
} else {
return true
case lastQuote != rune(0):
return false
case unicode.In(c, unicode.Quotation_Mark):
lastQuote = c
return false
default:
return unicode.IsSpace(c)
}
}
// split query into token
token := strings.FieldsFunc(query, findSingleQuotedToken)
var ret []string
for _, t := range token {
// skip empty string
if len(t) == 0 {
continue
}
if len(t) > 1 {
first, lenFirst := utf8.DecodeRuneInString(t)
last, lenLast := utf8.DecodeLastRuneInString(t)
// remove quotes
if unicode.In(first, unicode.Quotation_Mark) && unicode.In(last, unicode.Quotation_Mark) {
t = t[lenFirst : len(t)-lenLast]
}
}
// only append non-empty strings
if len(t) > 0 {
ret = append(ret, t)
}
}
return ret
}
func MakePublicSearchFilter(query string, visibilityWatcher *AttributeState) SCFilter {
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment