secure/precis: add ascii fast path to enforce benchmark old ns/op new ns/op delta BenchmarkAppend/UsernameCaseMapped/ASCII-4 526 85.6 -83.73% BenchmarkBytes/UsernameCaseMapped/ASCII-4 523 114 -78.20% BenchmarkString/UsernameCaseMapped/ASCII-4 593 146 -75.38% BenchmarkAppend/UsernameCasePreserved/ASCII-4 180 82.5 -54.17% BenchmarkBytes/UsernameCasePreserved/ASCII-4 214 110 -48.60% BenchmarkString/UsernameCasePreserved/ASCII-4 247 146 -40.89% BenchmarkAppend/FreeForm/ASCII-4 112 81.4 -27.32% BenchmarkBytes/FreeForm/ASCII-4 143 112 -21.68% BenchmarkString/FreeForm/ASCII-4 170 139 -18.24% BenchmarkAppend/OpaqueString/ASCII-4 242 208 -14.05% BenchmarkBytes/OpaqueString/ASCII-4 276 242 -12.32% BenchmarkString/OpaqueString/ASCII-4 305 270 -11.48% BenchmarkAppend/Nickname/ASCII-4 481 446 -7.28% BenchmarkString/Nickname/ASCII-4 548 512 -6.57% BenchmarkBytes/Nickname/ASCII-4 478 450 -5.86% BenchmarkBytes/OpaqueString/Arabic-4 334 324 -2.99% BenchmarkTransform/UsernameCaseMapped/Arabic-4 516 506 -1.94% BenchmarkString/FreeForm/Hangul-4 671 658 -1.94% BenchmarkBytes/OpaqueString/Hangul-4 760 775 +1.97% BenchmarkString/Nickname/Hangul-4 1016 1036 +1.97% … Updates golang/go#17423 Change-Id: Ia70335212f1089f280653c2b7bea9f769373ae1d Reviewed-on: https://go-review.googlesource.com/33435 Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org> Reviewed-by: Marcel van Lohuizen <mpvl@golang.org>
diff --git a/secure/precis/options.go b/secure/precis/options.go index 4934f8b..488f0b1 100644 --- a/secure/precis/options.go +++ b/secure/precis/options.go
@@ -20,6 +20,7 @@ foldWidth bool // Enforcement options + asciiLower bool cases transform.SpanningTransformer disallow runes.Set norm transform.SpanningTransformer @@ -123,6 +124,7 @@ // provided to determine the type of case folding used. func FoldCase(opts ...cases.Option) Option { return func(o *options) { + o.asciiLower = true o.cases = cases.Fold(opts...) } } @@ -131,6 +133,7 @@ // provided to determine the type of case folding used. func LowerCase(opts ...cases.Option) Option { return func(o *options) { + o.asciiLower = true if len(opts) == 0 { o.cases = cases.Lower(language.Und, cases.HandleFinalSigma(false)) return
diff --git a/secure/precis/profile.go b/secure/precis/profile.go index 081f555..1d7898d 100644 --- a/secure/precis/profile.go +++ b/secure/precis/profile.go
@@ -118,9 +118,49 @@ // TODO: make this a method on profile. func (b *buffers) enforce(p *Profile, src []byte, comparing bool) (str []byte, err error) { - // TODO: ASCII fast path, if options allow. b.src = src + ascii := true + for _, c := range src { + if c >= utf8.RuneSelf { + ascii = false + break + } + } + // ASCII fast path. + if ascii { + for _, f := range p.options.additional { + if err = b.apply(f()); err != nil { + return nil, err + } + } + switch { + case p.options.asciiLower || (comparing && p.options.ignorecase): + for i, c := range b.src { + if 'A' <= c && c <= 'Z' { + b.src[i] = c ^ 1<<5 + } + } + case p.options.cases != nil: + b.apply(p.options.cases) + } + c := checker{p: p} + if _, err := c.span(b.src, true); err != nil { + return nil, err + } + if p.disallow != nil { + for _, c := range b.src { + if p.disallow.Contains(rune(c)) { + return nil, errDisallowedRune + } + } + } + if p.options.disallowEmpty && len(b.src) == 0 { + return nil, errEmptyString + } + return b.src, nil + } + // These transforms are applied in the order defined in // https://tools.ietf.org/html/rfc7564#section-7