Prechádzať zdrojové kódy

volume/mounts: pre-compile regular expressions

Compile the regular expression, instead of 'ad-hoc'. For this to work, I moved
the splitting was moved out of parseMountRaw() into ParseMountRaw(), and the
former was renamed to parseMount(). This function still receives the 'raw' string,
as it's used to include the "raw" spec for inclusion in error messages.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
Sebastiaan van Stijn 4 rokov pred
rodič
commit
efb87ad106
2 zmenil súbory, kde vykonal 40 pridanie a 30 odobranie
  1. 13 3
      volume/mounts/lcow_parser.go
  2. 27 27
      volume/mounts/windows_parser.go

+ 13 - 3
volume/mounts/lcow_parser.go

@@ -3,6 +3,7 @@ package mounts // import "github.com/docker/docker/volume/mounts"
 import (
 import (
 	"errors"
 	"errors"
 	"path"
 	"path"
+	"regexp"
 
 
 	"github.com/docker/docker/api/types/mount"
 	"github.com/docker/docker/api/types/mount"
 )
 )
@@ -24,6 +25,11 @@ func NewLCOWParser() Parser {
 //    -  Drive cannot be c: (explicitly checked in code, not RegEx)
 //    -  Drive cannot be c: (explicitly checked in code, not RegEx)
 const rxLCOWDestination = `(?P<destination>/(?:[^\\/:*?"<>\r\n]+[/]?)*)`
 const rxLCOWDestination = `(?P<destination>/(?:[^\\/:*?"<>\r\n]+[/]?)*)`
 
 
+var (
+	lcowMountDestinationRegex = regexp.MustCompile(`^` + rxLCOWDestination + `$`)
+	lcowSplitRawSpec          = regexp.MustCompile(`^` + rxSource + rxLCOWDestination + rxMode + `$`)
+)
+
 var lcowSpecificValidators mountValidator = func(m *mount.Mount) error {
 var lcowSpecificValidators mountValidator = func(m *mount.Mount) error {
 	if path.Clean(m.Target) == "/" {
 	if path.Clean(m.Target) == "/" {
 		return ErrVolumeTargetIsRoot
 		return ErrVolumeTargetIsRoot
@@ -39,13 +45,17 @@ type lcowParser struct {
 }
 }
 
 
 func (p *lcowParser) ValidateMountConfig(mnt *mount.Mount) error {
 func (p *lcowParser) ValidateMountConfig(mnt *mount.Mount) error {
-	return p.validateMountConfigReg(mnt, rxLCOWDestination, lcowSpecificValidators)
+	return p.validateMountConfigReg(mnt, lcowMountDestinationRegex, lcowSpecificValidators)
 }
 }
 
 
 func (p *lcowParser) ParseMountRaw(raw, volumeDriver string) (*MountPoint, error) {
 func (p *lcowParser) ParseMountRaw(raw, volumeDriver string) (*MountPoint, error) {
-	return p.parseMountRaw(raw, volumeDriver, rxLCOWDestination, false, lcowSpecificValidators)
+	arr, err := p.windowsSplitRawSpec(raw, lcowSplitRawSpec)
+	if err != nil {
+		return nil, err
+	}
+	return p.parseMount(arr, raw, volumeDriver, lcowMountDestinationRegex, false, lcowSpecificValidators)
 }
 }
 
 
 func (p *lcowParser) ParseMountSpec(cfg mount.Mount) (*MountPoint, error) {
 func (p *lcowParser) ParseMountSpec(cfg mount.Mount) (*MountPoint, error) {
-	return p.parseMountSpec(cfg, rxLCOWDestination, false, lcowSpecificValidators)
+	return p.parseMountSpec(cfg, lcowMountDestinationRegex, false, lcowSpecificValidators)
 }
 }

+ 27 - 27
volume/mounts/windows_parser.go

@@ -78,12 +78,18 @@ const (
 	rxMode = `(:(?P<mode>(?i)ro|rw))?`
 	rxMode = `(:(?P<mode>(?i)ro|rw))?`
 )
 )
 
 
-type mountValidator func(mnt *mount.Mount) error
+var (
+	volumeNameRegexp          = regexp.MustCompile(`^` + rxName + `$`)
+	reservedNameRegexp        = regexp.MustCompile(`^` + rxReservedNames + `$`)
+	hostDirRegexp             = regexp.MustCompile(`^` + rxHostDir + `$`)
+	mountDestinationRegexp    = regexp.MustCompile(`^` + rxDestination + `$`)
+	windowsSplitRawSpecRegexp = regexp.MustCompile(`^` + rxSource + rxDestination + rxMode + `$`)
+)
 
 
-func (p *windowsParser) windowsSplitRawSpec(raw, destRegex string) ([]string, error) {
-	specExp := regexp.MustCompile(`^` + rxSource + destRegex + rxMode + `$`)
-	match := specExp.FindStringSubmatch(strings.ToLower(raw))
+type mountValidator func(mnt *mount.Mount) error
 
 
+func (p *windowsParser) windowsSplitRawSpec(raw string, splitRegexp *regexp.Regexp) ([]string, error) {
+	match := splitRegexp.FindStringSubmatch(strings.ToLower(raw))
 	// Must have something back
 	// Must have something back
 	if len(match) == 0 {
 	if len(match) == 0 {
 		return nil, errInvalidSpec(raw)
 		return nil, errInvalidSpec(raw)
@@ -92,7 +98,7 @@ func (p *windowsParser) windowsSplitRawSpec(raw, destRegex string) ([]string, er
 	var split []string
 	var split []string
 	matchgroups := make(map[string]string)
 	matchgroups := make(map[string]string)
 	// Pull out the sub expressions from the named capture groups
 	// 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])
 		matchgroups[name] = strings.ToLower(match[i])
 	}
 	}
 	if source, exists := matchgroups["source"]; exists {
 	if source, exists := matchgroups["source"]; exists {
@@ -115,11 +121,8 @@ func (p *windowsParser) windowsSplitRawSpec(raw, destRegex string) ([]string, er
 	// situation where the user intention was to map a file into a container through
 	// 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.
 	// a local volume, but this is not supported by the platform.
 	if matchgroups["source"] == "" && matchgroups["destination"] != "" {
 	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"])
 				return nil, fmt.Errorf("volume name %q cannot be a reserved word for Windows filenames", matchgroups["destination"])
 			}
 			}
 		} else {
 		} else {
@@ -153,14 +156,14 @@ var windowsSpecificValidators mountValidator = func(mnt *mount.Mount) error {
 	return windowsValidateNotRoot(mnt.Target)
 	return windowsValidateNotRoot(mnt.Target)
 }
 }
 
 
-func windowsValidateRegex(p, r string) error {
-	if regexp.MustCompile(`^` + r + `$`).MatchString(strings.ToLower(p)) {
+func windowsValidateRegex(p string, r *regexp.Regexp) error {
+	if r.MatchString(strings.ToLower(p)) {
 		return nil
 		return nil
 	}
 	}
 	return fmt.Errorf("invalid mount path: '%s'", p)
 	return fmt.Errorf("invalid mount path: '%s'", p)
 }
 }
 func windowsValidateAbsolute(p string) error {
 func windowsValidateAbsolute(p string) error {
-	if err := windowsValidateRegex(p, rxDestination); err != nil {
+	if err := windowsValidateRegex(p, mountDestinationRegexp); err != nil {
 		return fmt.Errorf("invalid mount path: '%s' mount path must be absolute", p)
 		return fmt.Errorf("invalid mount path: '%s' mount path must be absolute", p)
 	}
 	}
 	return nil
 	return nil
@@ -169,7 +172,7 @@ func windowsValidateAbsolute(p string) error {
 func windowsDetectMountType(p string) mount.Type {
 func windowsDetectMountType(p string) mount.Type {
 	if strings.HasPrefix(p, `\\.\pipe\`) {
 	if strings.HasPrefix(p, `\\.\pipe\`) {
 		return mount.TypeNamedPipe
 		return mount.TypeNamedPipe
-	} else if regexp.MustCompile(`^` + rxHostDir + `$`).MatchString(p) {
+	} else if hostDirRegexp.MatchString(p) {
 		return mount.TypeBind
 		return mount.TypeBind
 	} else {
 	} else {
 		return mount.TypeVolume
 		return mount.TypeVolume
@@ -182,18 +185,16 @@ func (p *windowsParser) ReadWrite(mode string) bool {
 
 
 // ValidateVolumeName checks a volume name in a platform specific manner.
 // ValidateVolumeName checks a volume name in a platform specific manner.
 func (p *windowsParser) ValidateVolumeName(name string) error {
 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")
 		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 fmt.Errorf("volume name %q cannot be a reserved word for Windows filenames", name)
 	}
 	}
 	return nil
 	return nil
 }
 }
 func (p *windowsParser) ValidateMountConfig(mnt *mount.Mount) error {
 func (p *windowsParser) ValidateMountConfig(mnt *mount.Mount) error {
-	return p.validateMountConfigReg(mnt, rxDestination, windowsSpecificValidators)
+	return p.validateMountConfigReg(mnt, mountDestinationRegexp, windowsSpecificValidators)
 }
 }
 
 
 type fileInfoProvider interface {
 type fileInfoProvider interface {
@@ -214,7 +215,7 @@ func (defaultFileInfoProvider) fileInfo(path string) (exist, isDir bool, err err
 	return true, fi.IsDir(), nil
 	return true, fi.IsDir(), nil
 }
 }
 
 
-func (p *windowsParser) validateMountConfigReg(mnt *mount.Mount, destRegex string, additionalValidators ...mountValidator) error {
+func (p *windowsParser) validateMountConfigReg(mnt *mount.Mount, destRegex *regexp.Regexp, additionalValidators ...mountValidator) error {
 
 
 	for _, v := range additionalValidators {
 	for _, v := range additionalValidators {
 		if err := v(mnt); err != nil {
 		if err := v(mnt); err != nil {
@@ -299,15 +300,14 @@ func (p *windowsParser) validateMountConfigReg(mnt *mount.Mount, destRegex strin
 	return nil
 	return nil
 }
 }
 func (p *windowsParser) ParseMountRaw(raw, volumeDriver string) (*MountPoint, error) {
 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)
+	arr, err := p.windowsSplitRawSpec(raw, windowsSplitRawSpecRegexp)
 	if err != nil {
 	if err != nil {
 		return nil, err
 		return nil, err
 	}
 	}
+	return p.parseMount(arr, raw, volumeDriver, mountDestinationRegexp, true, windowsSpecificValidators)
+}
 
 
+func (p *windowsParser) parseMount(arr []string, raw, volumeDriver string, destRegex *regexp.Regexp, convertTargetToBackslash bool, additionalValidators ...mountValidator) (*MountPoint, error) {
 	var spec mount.Mount
 	var spec mount.Mount
 	var mode string
 	var mode string
 	switch len(arr) {
 	switch len(arr) {
@@ -367,9 +367,9 @@ func (p *windowsParser) parseMountRaw(raw, volumeDriver, destRegex string, conve
 }
 }
 
 
 func (p *windowsParser) ParseMountSpec(cfg mount.Mount) (*MountPoint, error) {
 func (p *windowsParser) ParseMountSpec(cfg mount.Mount) (*MountPoint, error) {
-	return p.parseMountSpec(cfg, rxDestination, true, windowsSpecificValidators)
+	return p.parseMountSpec(cfg, mountDestinationRegexp, true, windowsSpecificValidators)
 }
 }
-func (p *windowsParser) parseMountSpec(cfg mount.Mount, destRegex string, convertTargetToBackslash bool, additionalValidators ...mountValidator) (*MountPoint, error) {
+func (p *windowsParser) parseMountSpec(cfg mount.Mount, destRegex *regexp.Regexp, convertTargetToBackslash bool, additionalValidators ...mountValidator) (*MountPoint, error) {
 	if err := p.validateMountConfigReg(&cfg, destRegex, additionalValidators...); err != nil {
 	if err := p.validateMountConfigReg(&cfg, destRegex, additionalValidators...); err != nil {
 		return nil, err
 		return nil, err
 	}
 	}