core: Add support for d duration unit (#3323)

* caddy: Add support for `d` duration unit

* Improvements to ParseDuration; add unit tests

Co-authored-by: Matthew Holt <mholt@users.noreply.github.com>
This commit is contained in:
Francis Lavoie
2020-05-11 18:41:11 -04:00
committed by GitHub
parent 35e1d92d58
commit ef6e53bb5f
7 changed files with 167 additions and 18 deletions

View File

@ -486,7 +486,7 @@ func Validate(cfg *Config) error {
// Duration can be an integer or a string. An integer is
// interpreted as nanoseconds. If a string, it is a Go
// time.Duration value such as `300ms`, `1.5h`, or `2h45m`;
// valid units are `ns`, `us`/`µs`, `ms`, `s`, `m`, and `h`.
// valid units are `ns`, `us`/`µs`, `ms`, `s`, `m`, `h`, and `d`.
type Duration time.Duration
// UnmarshalJSON satisfies json.Unmarshaler.
@ -497,7 +497,7 @@ func (d *Duration) UnmarshalJSON(b []byte) error {
var dur time.Duration
var err error
if b[0] == byte('"') && b[len(b)-1] == byte('"') {
dur, err = time.ParseDuration(strings.Trim(string(b), `"`))
dur, err = ParseDuration(strings.Trim(string(b), `"`))
} else {
err = json.Unmarshal(b, &dur)
}
@ -505,6 +505,34 @@ func (d *Duration) UnmarshalJSON(b []byte) error {
return err
}
// ParseDuration parses a duration string, adding
// support for the "d" unit meaning number of days,
// where a day is assumed to be 24h.
func ParseDuration(s string) (time.Duration, error) {
var inNumber bool
var numStart int
for i := 0; i < len(s); i++ {
ch := s[i]
if ch == 'd' {
daysStr := s[numStart:i]
days, err := strconv.ParseFloat(daysStr, 64)
if err != nil {
return 0, err
}
hours := days * 24.0
hoursStr := strconv.FormatFloat(hours, 'f', -1, 64)
s = s[:numStart] + hoursStr + "h" + s[i+1:]
i--
continue
}
if !inNumber {
numStart = i
}
inNumber = (ch >= '0' && ch <= '9') || ch == '.' || ch == '-' || ch == '+'
}
return time.ParseDuration(s)
}
// GoModule returns the build info of this Caddy
// build from debug.BuildInfo (requires Go modules).
// If no version information is available, a non-nil