summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--caddy.go32
-rw-r--r--caddy_test.go74
-rw-r--r--caddyconfig/httpcaddyfile/options.go3
-rw-r--r--caddytest/integration/caddyfile_adapt_test.go50
-rw-r--r--cmd/main.go2
-rw-r--r--modules/caddyhttp/reverseproxy/caddyfile.go21
-rw-r--r--modules/logging/filewriter.go3
7 files changed, 167 insertions, 18 deletions
diff --git a/caddy.go b/caddy.go
index 00a56e7..1184bc9 100644
--- a/caddy.go
+++ b/caddy.go
@@ -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
diff --git a/caddy_test.go b/caddy_test.go
new file mode 100644
index 0000000..adf1435
--- /dev/null
+++ b/caddy_test.go
@@ -0,0 +1,74 @@
+// Copyright 2015 Matthew Holt and The Caddy Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package caddy
+
+import (
+ "testing"
+ "time"
+)
+
+func TestParseDuration(t *testing.T) {
+ const day = 24 * time.Hour
+ for i, tc := range []struct {
+ input string
+ expect time.Duration
+ }{
+ {
+ input: "3h",
+ expect: 3 * time.Hour,
+ },
+ {
+ input: "1d",
+ expect: day,
+ },
+ {
+ input: "1d30m",
+ expect: day + 30*time.Minute,
+ },
+ {
+ input: "1m2d",
+ expect: time.Minute + day*2,
+ },
+ {
+ input: "1m2d30s",
+ expect: time.Minute + day*2 + 30*time.Second,
+ },
+ {
+ input: "1d2d",
+ expect: 3 * day,
+ },
+ {
+ input: "1.5d",
+ expect: time.Duration(1.5 * float64(day)),
+ },
+ {
+ input: "4m1.25d",
+ expect: 4*time.Minute + time.Duration(1.25*float64(day)),
+ },
+ {
+ input: "-1.25d12h",
+ expect: time.Duration(-1.25*float64(day)) - 12*time.Hour,
+ },
+ } {
+ actual, err := ParseDuration(tc.input)
+ if err != nil {
+ t.Errorf("Test %d ('%s'): Got error: %v", i, tc.input, err)
+ continue
+ }
+ if actual != tc.expect {
+ t.Errorf("Test %d ('%s'): Expected=%s Actual=%s", i, tc.input, tc.expect, actual)
+ }
+ }
+}
diff --git a/caddyconfig/httpcaddyfile/options.go b/caddyconfig/httpcaddyfile/options.go
index de288db..49a11f6 100644
--- a/caddyconfig/httpcaddyfile/options.go
+++ b/caddyconfig/httpcaddyfile/options.go
@@ -16,7 +16,6 @@ package httpcaddyfile
import (
"strconv"
- "time"
"github.com/caddyserver/caddy/v2"
"github.com/caddyserver/caddy/v2/caddyconfig/caddyfile"
@@ -227,7 +226,7 @@ func parseOptOnDemand(d *caddyfile.Dispenser) (interface{}, error) {
if !d.NextArg() {
return nil, d.ArgErr()
}
- dur, err := time.ParseDuration(d.Val())
+ dur, err := caddy.ParseDuration(d.Val())
if err != nil {
return nil, err
}
diff --git a/caddytest/integration/caddyfile_adapt_test.go b/caddytest/integration/caddyfile_adapt_test.go
index c2ad892..98c81da 100644
--- a/caddytest/integration/caddyfile_adapt_test.go
+++ b/caddytest/integration/caddyfile_adapt_test.go
@@ -489,3 +489,53 @@ func TestGlobalOptions(t *testing.T) {
}
}`)
}
+
+func TestLogRollDays(t *testing.T) {
+ caddytest.AssertAdapt(t, `
+ :80
+
+ log {
+ output file /var/log/access.log {
+ roll_size 1gb
+ roll_keep 5
+ roll_keep_for 90d
+ }
+ }
+ `, "caddyfile", `{
+ "logging": {
+ "logs": {
+ "default": {
+ "exclude": [
+ "http.log.access.log0"
+ ]
+ },
+ "log0": {
+ "writer": {
+ "filename": "/var/log/access.log",
+ "output": "file",
+ "roll_keep": 5,
+ "roll_keep_days": 90,
+ "roll_size_mb": 954
+ },
+ "include": [
+ "http.log.access.log0"
+ ]
+ }
+ }
+ },
+ "apps": {
+ "http": {
+ "servers": {
+ "srv0": {
+ "listen": [
+ ":80"
+ ],
+ "logs": {
+ "default_logger_name": "log0"
+ }
+ }
+ }
+ }
+ }
+}`)
+}
diff --git a/cmd/main.go b/cmd/main.go
index bdc95a4..fd82b96 100644
--- a/cmd/main.go
+++ b/cmd/main.go
@@ -311,7 +311,7 @@ func (f Flags) Float64(name string) float64 {
// is not a duration type. It panics if the flag is
// not in the flag set.
func (f Flags) Duration(name string) time.Duration {
- val, _ := time.ParseDuration(f.String(name))
+ val, _ := caddy.ParseDuration(f.String(name))
return val
}
diff --git a/modules/caddyhttp/reverseproxy/caddyfile.go b/modules/caddyhttp/reverseproxy/caddyfile.go
index 0a14f09..491b067 100644
--- a/modules/caddyhttp/reverseproxy/caddyfile.go
+++ b/modules/caddyhttp/reverseproxy/caddyfile.go
@@ -21,7 +21,6 @@ import (
"reflect"
"strconv"
"strings"
- "time"
"github.com/caddyserver/caddy/v2"
"github.com/caddyserver/caddy/v2/caddyconfig"
@@ -250,7 +249,7 @@ func (h *Handler) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
if h.LoadBalancing == nil {
h.LoadBalancing = new(LoadBalancing)
}
- dur, err := time.ParseDuration(d.Val())
+ dur, err := caddy.ParseDuration(d.Val())
if err != nil {
return d.Errf("bad duration value %s: %v", d.Val(), err)
}
@@ -263,7 +262,7 @@ func (h *Handler) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
if h.LoadBalancing == nil {
h.LoadBalancing = new(LoadBalancing)
}
- dur, err := time.ParseDuration(d.Val())
+ dur, err := caddy.ParseDuration(d.Val())
if err != nil {
return d.Errf("bad interval value '%s': %v", d.Val(), err)
}
@@ -307,7 +306,7 @@ func (h *Handler) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
if h.HealthChecks.Active == nil {
h.HealthChecks.Active = new(ActiveHealthChecks)
}
- dur, err := time.ParseDuration(d.Val())
+ dur, err := caddy.ParseDuration(d.Val())
if err != nil {
return d.Errf("bad interval value %s: %v", d.Val(), err)
}
@@ -323,7 +322,7 @@ func (h *Handler) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
if h.HealthChecks.Active == nil {
h.HealthChecks.Active = new(ActiveHealthChecks)
}
- dur, err := time.ParseDuration(d.Val())
+ dur, err := caddy.ParseDuration(d.Val())
if err != nil {
return d.Errf("bad timeout value %s: %v", d.Val(), err)
}
@@ -387,7 +386,7 @@ func (h *Handler) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
if h.HealthChecks.Passive == nil {
h.HealthChecks.Passive = new(PassiveHealthChecks)
}
- dur, err := time.ParseDuration(d.Val())
+ dur, err := caddy.ParseDuration(d.Val())
if err != nil {
return d.Errf("bad duration value '%s': %v", d.Val(), err)
}
@@ -441,7 +440,7 @@ func (h *Handler) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
if h.HealthChecks.Passive == nil {
h.HealthChecks.Passive = new(PassiveHealthChecks)
}
- dur, err := time.ParseDuration(d.Val())
+ dur, err := caddy.ParseDuration(d.Val())
if err != nil {
return d.Errf("bad duration value '%s': %v", d.Val(), err)
}
@@ -454,7 +453,7 @@ func (h *Handler) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
if fi, err := strconv.Atoi(d.Val()); err == nil {
h.FlushInterval = caddy.Duration(fi)
} else {
- dur, err := time.ParseDuration(d.Val())
+ dur, err := caddy.ParseDuration(d.Val())
if err != nil {
return d.Errf("bad duration value '%s': %v", d.Val(), err)
}
@@ -606,7 +605,7 @@ func (h *HTTPTransport) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
if !d.NextArg() {
return d.ArgErr()
}
- dur, err := time.ParseDuration(d.Val())
+ dur, err := caddy.ParseDuration(d.Val())
if err != nil {
return d.Errf("bad timeout value '%s': %v", d.Val(), err)
}
@@ -641,7 +640,7 @@ func (h *HTTPTransport) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
if !d.NextArg() {
return d.ArgErr()
}
- dur, err := time.ParseDuration(d.Val())
+ dur, err := caddy.ParseDuration(d.Val())
if err != nil {
return d.Errf("bad timeout value '%s': %v", d.Val(), err)
}
@@ -683,7 +682,7 @@ func (h *HTTPTransport) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
h.KeepAlive.Enabled = &disable
break
}
- dur, err := time.ParseDuration(d.Val())
+ dur, err := caddy.ParseDuration(d.Val())
if err != nil {
return d.Errf("bad duration value '%s': %v", d.Val(), err)
}
diff --git a/modules/logging/filewriter.go b/modules/logging/filewriter.go
index 59f5b2a..376deeb 100644
--- a/modules/logging/filewriter.go
+++ b/modules/logging/filewriter.go
@@ -21,7 +21,6 @@ import (
"os"
"path/filepath"
"strconv"
- "time"
"github.com/caddyserver/caddy/v2"
"github.com/caddyserver/caddy/v2/caddyconfig/caddyfile"
@@ -194,7 +193,7 @@ func (fw *FileWriter) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
if !d.AllArgs(&keepForStr) {
return d.ArgErr()
}
- keepFor, err := time.ParseDuration(keepForStr)
+ keepFor, err := caddy.ParseDuration(keepForStr)
if err != nil {
return d.Errf("parsing roll_keep_for duration: %v", err)
}