1
0
Fork 0
mirror of https://github.com/moby/moby.git synced 2022-11-09 12:21:53 -05:00

Merge pull request #42673 from thaJeztah/regex_optimisation

volume/mounts: pre-compile regular expressions
This commit is contained in:
Akihiro Suda 2021-08-19 19:00:19 +09:00 committed by GitHub
commit 8360de9955
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 63 additions and 50 deletions

View file

@ -2,7 +2,10 @@ package mounts // import "github.com/docker/docker/volume/mounts"
import (
"errors"
"fmt"
"path"
"regexp"
"strings"
"github.com/docker/docker/api/types/mount"
)
@ -24,13 +27,21 @@ func NewLCOWParser() Parser {
// - Drive cannot be c: (explicitly checked in code, not RegEx)
const rxLCOWDestination = `(?P<destination>/(?:[^\\/:*?"<>\r\n]+[/]?)*)`
var lcowSpecificValidators mountValidator = func(m *mount.Mount) error {
var (
lcowMountDestinationRegex = regexp.MustCompile(`^` + rxLCOWDestination + `$`)
lcowSplitRawSpec = regexp.MustCompile(`^` + rxSource + rxLCOWDestination + rxMode + `$`)
)
var lcowValidators mountValidator = func(m *mount.Mount) error {
if path.Clean(m.Target) == "/" {
return ErrVolumeTargetIsRoot
}
if m.Type == mount.TypeNamedPipe {
return errors.New("Linux containers on Windows do not support named pipe mounts")
}
if !lcowMountDestinationRegex.MatchString(strings.ToLower(m.Target)) {
return fmt.Errorf("invalid mount path: '%s'", m.Target)
}
return nil
}
@ -39,13 +50,17 @@ type lcowParser struct {
}
func (p *lcowParser) ValidateMountConfig(mnt *mount.Mount) error {
return p.validateMountConfigReg(mnt, rxLCOWDestination, lcowSpecificValidators)
return p.validateMountConfigReg(mnt, lcowValidators)
}
func (p *lcowParser) ParseMountRaw(raw, volumeDriver string) (*MountPoint, error) {
return p.parseMountRaw(raw, volumeDriver, rxLCOWDestination, false, lcowSpecificValidators)
arr, err := p.splitRawSpec(raw, lcowSplitRawSpec)
if err != nil {
return nil, err
}
return p.parseMount(arr, raw, volumeDriver, false, lcowValidators)
}
func (p *lcowParser) ParseMountSpec(cfg mount.Mount) (*MountPoint, error) {
return p.parseMountSpec(cfg, rxLCOWDestination, false, lcowSpecificValidators)
return p.parseMountSpec(cfg, false, lcowValidators)
}

View file

@ -78,13 +78,18 @@ const (
rxMode = `(:(?P<mode>(?i)ro|rw))?`
)
var (
volumeNameRegexp = regexp.MustCompile(`^` + rxName + `$`)
reservedNameRegexp = regexp.MustCompile(`^` + rxReservedNames + `$`)
hostDirRegexp = regexp.MustCompile(`^` + rxHostDir + `$`)
mountDestinationRegexp = regexp.MustCompile(`^` + rxDestination + `$`)
windowsSplitRawSpecRegexp = regexp.MustCompile(`^` + rxSource + rxDestination + rxMode + `$`)
)
type mountValidator func(mnt *mount.Mount) error
func (p *windowsParser) windowsSplitRawSpec(raw, destRegex string) ([]string, error) {
specExp := regexp.MustCompile(`^` + rxSource + destRegex + rxMode + `$`)
match := specExp.FindStringSubmatch(strings.ToLower(raw))
// Must have something back
func (p *windowsParser) splitRawSpec(raw string, splitRegexp *regexp.Regexp) ([]string, error) {
match := splitRegexp.FindStringSubmatch(strings.ToLower(raw))
if len(match) == 0 {
return nil, errInvalidSpec(raw)
}
@ -92,7 +97,7 @@ func (p *windowsParser) windowsSplitRawSpec(raw, destRegex string) ([]string, er
var split []string
matchgroups := make(map[string]string)
// Pull out the sub expressions from the named capture groups
for i, name := range specExp.SubexpNames() {
for i, name := range splitRegexp.SubexpNames() {
matchgroups[name] = strings.ToLower(match[i])
}
if source, exists := matchgroups["source"]; exists {
@ -115,11 +120,8 @@ func (p *windowsParser) windowsSplitRawSpec(raw, destRegex string) ([]string, er
// situation where the user intention was to map a file into a container through
// a local volume, but this is not supported by the platform.
if matchgroups["source"] == "" && matchgroups["destination"] != "" {
volExp := regexp.MustCompile(`^` + rxName + `$`)
reservedNameExp := regexp.MustCompile(`^` + rxReservedNames + `$`)
if volExp.MatchString(matchgroups["destination"]) {
if reservedNameExp.MatchString(matchgroups["destination"]) {
if volumeNameRegexp.MatchString(matchgroups["destination"]) {
if reservedNameRegexp.MatchString(matchgroups["destination"]) {
return nil, fmt.Errorf("volume name %q cannot be a reserved word for Windows filenames", matchgroups["destination"])
}
} else {
@ -149,18 +151,18 @@ func windowsValidateNotRoot(p string) error {
return nil
}
var windowsSpecificValidators mountValidator = func(mnt *mount.Mount) error {
return windowsValidateNotRoot(mnt.Target)
var windowsValidators mountValidator = func(m *mount.Mount) error {
if err := windowsValidateNotRoot(m.Target); err != nil {
return err
}
if !mountDestinationRegexp.MatchString(strings.ToLower(m.Target)) {
return fmt.Errorf("invalid mount path: '%s'", m.Target)
}
return nil
}
func windowsValidateRegex(p, r string) error {
if regexp.MustCompile(`^` + r + `$`).MatchString(strings.ToLower(p)) {
return nil
}
return fmt.Errorf("invalid mount path: '%s'", p)
}
func windowsValidateAbsolute(p string) error {
if err := windowsValidateRegex(p, rxDestination); err != nil {
if !mountDestinationRegexp.MatchString(strings.ToLower(p)) {
return fmt.Errorf("invalid mount path: '%s' mount path must be absolute", p)
}
return nil
@ -169,7 +171,7 @@ func windowsValidateAbsolute(p string) error {
func windowsDetectMountType(p string) mount.Type {
if strings.HasPrefix(p, `\\.\pipe\`) {
return mount.TypeNamedPipe
} else if regexp.MustCompile(`^` + rxHostDir + `$`).MatchString(p) {
} else if hostDirRegexp.MatchString(p) {
return mount.TypeBind
} else {
return mount.TypeVolume
@ -182,18 +184,16 @@ func (p *windowsParser) ReadWrite(mode string) bool {
// ValidateVolumeName checks a volume name in a platform specific manner.
func (p *windowsParser) ValidateVolumeName(name string) error {
nameExp := regexp.MustCompile(`^` + rxName + `$`)
if !nameExp.MatchString(name) {
if !volumeNameRegexp.MatchString(name) {
return errors.New("invalid volume name")
}
nameExp = regexp.MustCompile(`^` + rxReservedNames + `$`)
if nameExp.MatchString(name) {
if reservedNameRegexp.MatchString(name) {
return fmt.Errorf("volume name %q cannot be a reserved word for Windows filenames", name)
}
return nil
}
func (p *windowsParser) ValidateMountConfig(mnt *mount.Mount) error {
return p.validateMountConfigReg(mnt, rxDestination, windowsSpecificValidators)
return p.validateMountConfigReg(mnt, windowsValidators)
}
type fileInfoProvider interface {
@ -214,20 +214,15 @@ func (defaultFileInfoProvider) fileInfo(path string) (exist, isDir bool, err err
return true, fi.IsDir(), nil
}
func (p *windowsParser) validateMountConfigReg(mnt *mount.Mount, destRegex string, additionalValidators ...mountValidator) error {
func (p *windowsParser) validateMountConfigReg(mnt *mount.Mount, additionalValidators ...mountValidator) error {
if len(mnt.Target) == 0 {
return &errMountConfig{mnt, errMissingField("Target")}
}
for _, v := range additionalValidators {
if err := v(mnt); err != nil {
return &errMountConfig{mnt, err}
}
}
if len(mnt.Target) == 0 {
return &errMountConfig{mnt, errMissingField("Target")}
}
if err := windowsValidateRegex(mnt.Target, destRegex); err != nil {
return &errMountConfig{mnt, err}
}
switch mnt.Type {
case mount.TypeBind:
@ -298,16 +293,16 @@ func (p *windowsParser) validateMountConfigReg(mnt *mount.Mount, destRegex strin
}
return nil
}
func (p *windowsParser) ParseMountRaw(raw, volumeDriver string) (*MountPoint, error) {
return p.parseMountRaw(raw, volumeDriver, rxDestination, true, windowsSpecificValidators)
}
func (p *windowsParser) parseMountRaw(raw, volumeDriver, destRegex string, convertTargetToBackslash bool, additionalValidators ...mountValidator) (*MountPoint, error) {
arr, err := p.windowsSplitRawSpec(raw, destRegex)
func (p *windowsParser) ParseMountRaw(raw, volumeDriver string) (*MountPoint, error) {
arr, err := p.splitRawSpec(raw, windowsSplitRawSpecRegexp)
if err != nil {
return nil, err
}
return p.parseMount(arr, raw, volumeDriver, true, windowsValidators)
}
func (p *windowsParser) parseMount(arr []string, raw, volumeDriver string, convertTargetToBackslash bool, additionalValidators ...mountValidator) (*MountPoint, error) {
var spec mount.Mount
var mode string
switch len(arr) {
@ -356,7 +351,7 @@ func (p *windowsParser) parseMountRaw(raw, volumeDriver, destRegex string, conve
spec.VolumeOptions.NoCopy = !copyData
}
mp, err := p.parseMountSpec(spec, destRegex, convertTargetToBackslash, additionalValidators...)
mp, err := p.parseMountSpec(spec, convertTargetToBackslash, additionalValidators...)
if mp != nil {
mp.Mode = mode
}
@ -367,10 +362,11 @@ func (p *windowsParser) parseMountRaw(raw, volumeDriver, destRegex string, conve
}
func (p *windowsParser) ParseMountSpec(cfg mount.Mount) (*MountPoint, error) {
return p.parseMountSpec(cfg, rxDestination, true, windowsSpecificValidators)
return p.parseMountSpec(cfg, true, windowsValidators)
}
func (p *windowsParser) parseMountSpec(cfg mount.Mount, destRegex string, convertTargetToBackslash bool, additionalValidators ...mountValidator) (*MountPoint, error) {
if err := p.validateMountConfigReg(&cfg, destRegex, additionalValidators...); err != nil {
func (p *windowsParser) parseMountSpec(cfg mount.Mount, convertTargetToBackslash bool, additionalValidators ...mountValidator) (*MountPoint, error) {
if err := p.validateMountConfigReg(&cfg, additionalValidators...); err != nil {
return nil, err
}
mp := &MountPoint{
@ -439,21 +435,23 @@ func (p *windowsParser) ParseVolumesFrom(spec string) (string, string, error) {
}
func (p *windowsParser) DefaultPropagationMode() mount.Propagation {
return mount.Propagation("")
return ""
}
func (p *windowsParser) ConvertTmpfsOptions(opt *mount.TmpfsOptions, readOnly bool) (string, error) {
return "", fmt.Errorf("%s does not support tmpfs", runtime.GOOS)
}
func (p *windowsParser) DefaultCopyMode() bool {
return false
}
func (p *windowsParser) IsBackwardCompatible(m *MountPoint) bool {
return false
}
func (p *windowsParser) ValidateTmpfsMountDestination(dest string) error {
return errors.New("Platform does not support tmpfs")
return errors.New("platform does not support tmpfs")
}
func (p *windowsParser) HasResource(m *MountPoint, absolutePath string) bool {