chore(lint): upgrade golangci-lint to v1.47.2
- Fix Slowloris attacks on HTTP servers - Force set default of 5 minutes for pprof read timeout - Change `ShutdownTimeout` to time.Duration since it cannot be set to 0
This commit is contained in:
@@ -2,7 +2,7 @@ ARG ALPINE_VERSION=3.16
|
|||||||
ARG GO_ALPINE_VERSION=3.16
|
ARG GO_ALPINE_VERSION=3.16
|
||||||
ARG GO_VERSION=1.17
|
ARG GO_VERSION=1.17
|
||||||
ARG XCPUTRANSLATE_VERSION=v0.6.0
|
ARG XCPUTRANSLATE_VERSION=v0.6.0
|
||||||
ARG GOLANGCI_LINT_VERSION=v1.46.2
|
ARG GOLANGCI_LINT_VERSION=v1.47.2
|
||||||
ARG MOCKGEN_VERSION=v1.6.0
|
ARG MOCKGEN_VERSION=v1.6.0
|
||||||
ARG BUILDPLATFORM=linux/amd64
|
ARG BUILDPLATFORM=linux/amd64
|
||||||
|
|
||||||
|
|||||||
@@ -65,7 +65,7 @@ func (d *DoT) copy() (copied DoT) {
|
|||||||
// unset field of the receiver settings object.
|
// unset field of the receiver settings object.
|
||||||
func (d *DoT) mergeWith(other DoT) {
|
func (d *DoT) mergeWith(other DoT) {
|
||||||
d.Enabled = helpers.MergeWithBool(d.Enabled, other.Enabled)
|
d.Enabled = helpers.MergeWithBool(d.Enabled, other.Enabled)
|
||||||
d.UpdatePeriod = helpers.MergeWithDuration(d.UpdatePeriod, other.UpdatePeriod)
|
d.UpdatePeriod = helpers.MergeWithDurationPtr(d.UpdatePeriod, other.UpdatePeriod)
|
||||||
d.Unbound.mergeWith(other.Unbound)
|
d.Unbound.mergeWith(other.Unbound)
|
||||||
d.Blacklist.mergeWith(other.Blacklist)
|
d.Blacklist.mergeWith(other.Blacklist)
|
||||||
}
|
}
|
||||||
@@ -75,7 +75,7 @@ func (d *DoT) mergeWith(other DoT) {
|
|||||||
// settings.
|
// settings.
|
||||||
func (d *DoT) overrideWith(other DoT) {
|
func (d *DoT) overrideWith(other DoT) {
|
||||||
d.Enabled = helpers.OverrideWithBool(d.Enabled, other.Enabled)
|
d.Enabled = helpers.OverrideWithBool(d.Enabled, other.Enabled)
|
||||||
d.UpdatePeriod = helpers.OverrideWithDuration(d.UpdatePeriod, other.UpdatePeriod)
|
d.UpdatePeriod = helpers.OverrideWithDurationPtr(d.UpdatePeriod, other.UpdatePeriod)
|
||||||
d.Unbound.overrideWith(other.Unbound)
|
d.Unbound.overrideWith(other.Unbound)
|
||||||
d.Blacklist.overrideWith(other.Blacklist)
|
d.Blacklist.overrideWith(other.Blacklist)
|
||||||
}
|
}
|
||||||
@@ -83,7 +83,7 @@ func (d *DoT) overrideWith(other DoT) {
|
|||||||
func (d *DoT) setDefaults() {
|
func (d *DoT) setDefaults() {
|
||||||
d.Enabled = helpers.DefaultBool(d.Enabled, true)
|
d.Enabled = helpers.DefaultBool(d.Enabled, true)
|
||||||
const defaultUpdatePeriod = 24 * time.Hour
|
const defaultUpdatePeriod = 24 * time.Hour
|
||||||
d.UpdatePeriod = helpers.DefaultDuration(d.UpdatePeriod, defaultUpdatePeriod)
|
d.UpdatePeriod = helpers.DefaultDurationPtr(d.UpdatePeriod, defaultUpdatePeriod)
|
||||||
d.Unbound.setDefaults()
|
d.Unbound.setDefaults()
|
||||||
d.Blacklist.setDefaults()
|
d.Blacklist.setDefaults()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package settings
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/qdm12/gluetun/internal/configuration/settings/helpers"
|
"github.com/qdm12/gluetun/internal/configuration/settings/helpers"
|
||||||
"github.com/qdm12/gotree"
|
"github.com/qdm12/gotree"
|
||||||
@@ -15,6 +16,12 @@ type Health struct {
|
|||||||
// for the health check server.
|
// for the health check server.
|
||||||
// It cannot be the empty string in the internal state.
|
// It cannot be the empty string in the internal state.
|
||||||
ServerAddress string
|
ServerAddress string
|
||||||
|
// ReadHeaderTimeout is the HTTP server header read timeout
|
||||||
|
// duration of the HTTP server. It defaults to 100 milliseconds.
|
||||||
|
ReadHeaderTimeout time.Duration
|
||||||
|
// ReadTimeout is the HTTP read timeout duration of the
|
||||||
|
// HTTP server. It defaults to 500 milliseconds.
|
||||||
|
ReadTimeout time.Duration
|
||||||
// TargetAddress is the address (host or host:port)
|
// TargetAddress is the address (host or host:port)
|
||||||
// to TCP dial to periodically for the health check.
|
// to TCP dial to periodically for the health check.
|
||||||
// It cannot be the empty string in the internal state.
|
// It cannot be the empty string in the internal state.
|
||||||
@@ -40,9 +47,11 @@ func (h Health) Validate() (err error) {
|
|||||||
|
|
||||||
func (h *Health) copy() (copied Health) {
|
func (h *Health) copy() (copied Health) {
|
||||||
return Health{
|
return Health{
|
||||||
ServerAddress: h.ServerAddress,
|
ServerAddress: h.ServerAddress,
|
||||||
TargetAddress: h.TargetAddress,
|
ReadHeaderTimeout: h.ReadHeaderTimeout,
|
||||||
VPN: h.VPN.copy(),
|
ReadTimeout: h.ReadTimeout,
|
||||||
|
TargetAddress: h.TargetAddress,
|
||||||
|
VPN: h.VPN.copy(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -50,6 +59,8 @@ func (h *Health) copy() (copied Health) {
|
|||||||
// unset field of the receiver settings object.
|
// unset field of the receiver settings object.
|
||||||
func (h *Health) MergeWith(other Health) {
|
func (h *Health) MergeWith(other Health) {
|
||||||
h.ServerAddress = helpers.MergeWithString(h.ServerAddress, other.ServerAddress)
|
h.ServerAddress = helpers.MergeWithString(h.ServerAddress, other.ServerAddress)
|
||||||
|
h.ReadHeaderTimeout = helpers.MergeWithDuration(h.ReadHeaderTimeout, other.ReadHeaderTimeout)
|
||||||
|
h.ReadTimeout = helpers.MergeWithDuration(h.ReadTimeout, other.ReadTimeout)
|
||||||
h.TargetAddress = helpers.MergeWithString(h.TargetAddress, other.TargetAddress)
|
h.TargetAddress = helpers.MergeWithString(h.TargetAddress, other.TargetAddress)
|
||||||
h.VPN.mergeWith(other.VPN)
|
h.VPN.mergeWith(other.VPN)
|
||||||
}
|
}
|
||||||
@@ -59,12 +70,18 @@ func (h *Health) MergeWith(other Health) {
|
|||||||
// settings.
|
// settings.
|
||||||
func (h *Health) OverrideWith(other Health) {
|
func (h *Health) OverrideWith(other Health) {
|
||||||
h.ServerAddress = helpers.OverrideWithString(h.ServerAddress, other.ServerAddress)
|
h.ServerAddress = helpers.OverrideWithString(h.ServerAddress, other.ServerAddress)
|
||||||
|
h.ReadHeaderTimeout = helpers.OverrideWithDuration(h.ReadHeaderTimeout, other.ReadHeaderTimeout)
|
||||||
|
h.ReadTimeout = helpers.OverrideWithDuration(h.ReadTimeout, other.ReadTimeout)
|
||||||
h.TargetAddress = helpers.OverrideWithString(h.TargetAddress, other.TargetAddress)
|
h.TargetAddress = helpers.OverrideWithString(h.TargetAddress, other.TargetAddress)
|
||||||
h.VPN.overrideWith(other.VPN)
|
h.VPN.overrideWith(other.VPN)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Health) SetDefaults() {
|
func (h *Health) SetDefaults() {
|
||||||
h.ServerAddress = helpers.DefaultString(h.ServerAddress, "127.0.0.1:9999")
|
h.ServerAddress = helpers.DefaultString(h.ServerAddress, "127.0.0.1:9999")
|
||||||
|
const defaultReadHeaderTimeout = 100 * time.Millisecond
|
||||||
|
h.ReadHeaderTimeout = helpers.DefaultDuration(h.ReadHeaderTimeout, defaultReadHeaderTimeout)
|
||||||
|
const defaultReadTimeout = 500 * time.Millisecond
|
||||||
|
h.ReadTimeout = helpers.DefaultDuration(h.ReadTimeout, defaultReadTimeout)
|
||||||
h.TargetAddress = helpers.DefaultString(h.TargetAddress, "cloudflare.com:443")
|
h.TargetAddress = helpers.DefaultString(h.TargetAddress, "cloudflare.com:443")
|
||||||
h.VPN.setDefaults()
|
h.VPN.setDefaults()
|
||||||
}
|
}
|
||||||
@@ -77,6 +94,8 @@ func (h Health) toLinesNode() (node *gotree.Node) {
|
|||||||
node = gotree.New("Health settings:")
|
node = gotree.New("Health settings:")
|
||||||
node.Appendf("Server listening address: %s", h.ServerAddress)
|
node.Appendf("Server listening address: %s", h.ServerAddress)
|
||||||
node.Appendf("Target address: %s", h.TargetAddress)
|
node.Appendf("Target address: %s", h.TargetAddress)
|
||||||
|
node.Appendf("Read header timeout: %s", h.ReadHeaderTimeout)
|
||||||
|
node.Appendf("Read timeout: %s", h.ReadTimeout)
|
||||||
node.AppendNode(h.VPN.toLinesNode("VPN"))
|
node.AppendNode(h.VPN.toLinesNode("VPN"))
|
||||||
return node
|
return node
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,23 +35,23 @@ func (h *HealthyWait) copy() (copied HealthyWait) {
|
|||||||
// mergeWith merges the other settings into any
|
// mergeWith merges the other settings into any
|
||||||
// unset field of the receiver settings object.
|
// unset field of the receiver settings object.
|
||||||
func (h *HealthyWait) mergeWith(other HealthyWait) {
|
func (h *HealthyWait) mergeWith(other HealthyWait) {
|
||||||
h.Initial = helpers.MergeWithDuration(h.Initial, other.Initial)
|
h.Initial = helpers.MergeWithDurationPtr(h.Initial, other.Initial)
|
||||||
h.Addition = helpers.MergeWithDuration(h.Addition, other.Addition)
|
h.Addition = helpers.MergeWithDurationPtr(h.Addition, other.Addition)
|
||||||
}
|
}
|
||||||
|
|
||||||
// overrideWith overrides fields of the receiver
|
// overrideWith overrides fields of the receiver
|
||||||
// settings object with any field set in the other
|
// settings object with any field set in the other
|
||||||
// settings.
|
// settings.
|
||||||
func (h *HealthyWait) overrideWith(other HealthyWait) {
|
func (h *HealthyWait) overrideWith(other HealthyWait) {
|
||||||
h.Initial = helpers.OverrideWithDuration(h.Initial, other.Initial)
|
h.Initial = helpers.OverrideWithDurationPtr(h.Initial, other.Initial)
|
||||||
h.Addition = helpers.OverrideWithDuration(h.Addition, other.Addition)
|
h.Addition = helpers.OverrideWithDurationPtr(h.Addition, other.Addition)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *HealthyWait) setDefaults() {
|
func (h *HealthyWait) setDefaults() {
|
||||||
const initialDurationDefault = 6 * time.Second
|
const initialDurationDefault = 6 * time.Second
|
||||||
const additionDurationDefault = 5 * time.Second
|
const additionDurationDefault = 5 * time.Second
|
||||||
h.Initial = helpers.DefaultDuration(h.Initial, initialDurationDefault)
|
h.Initial = helpers.DefaultDurationPtr(h.Initial, initialDurationDefault)
|
||||||
h.Addition = helpers.DefaultDuration(h.Addition, additionDurationDefault)
|
h.Addition = helpers.DefaultDurationPtr(h.Addition, additionDurationDefault)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h HealthyWait) String() string {
|
func (h HealthyWait) String() string {
|
||||||
|
|||||||
@@ -73,7 +73,15 @@ func DefaultStringPtr(existing *string, defaultValue string) (result *string) {
|
|||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
func DefaultDuration(existing *time.Duration,
|
func DefaultDuration(existing time.Duration,
|
||||||
|
defaultValue time.Duration) (result time.Duration) {
|
||||||
|
if existing != 0 {
|
||||||
|
return existing
|
||||||
|
}
|
||||||
|
return defaultValue
|
||||||
|
}
|
||||||
|
|
||||||
|
func DefaultDurationPtr(existing *time.Duration,
|
||||||
defaultValue time.Duration) (result *time.Duration) {
|
defaultValue time.Duration) (result *time.Duration) {
|
||||||
if existing != nil {
|
if existing != nil {
|
||||||
return existing
|
return existing
|
||||||
|
|||||||
@@ -107,7 +107,14 @@ func MergeWithIP(existing, other net.IP) (result net.IP) {
|
|||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
func MergeWithDuration(existing, other *time.Duration) (result *time.Duration) {
|
func MergeWithDuration(existing, other time.Duration) (result time.Duration) {
|
||||||
|
if existing != 0 {
|
||||||
|
return existing
|
||||||
|
}
|
||||||
|
return other
|
||||||
|
}
|
||||||
|
|
||||||
|
func MergeWithDurationPtr(existing, other *time.Duration) (result *time.Duration) {
|
||||||
if existing != nil {
|
if existing != nil {
|
||||||
return existing
|
return existing
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -93,7 +93,16 @@ func OverrideWithIP(existing, other net.IP) (result net.IP) {
|
|||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
func OverrideWithDuration(existing, other *time.Duration) (result *time.Duration) {
|
func OverrideWithDuration(existing, other time.Duration) (
|
||||||
|
result time.Duration) {
|
||||||
|
if other == 0 {
|
||||||
|
return existing
|
||||||
|
}
|
||||||
|
return other
|
||||||
|
}
|
||||||
|
|
||||||
|
func OverrideWithDurationPtr(existing, other *time.Duration) (
|
||||||
|
result *time.Duration) {
|
||||||
if other == nil {
|
if other == nil {
|
||||||
return existing
|
return existing
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package settings
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/qdm12/gluetun/internal/configuration/settings/helpers"
|
"github.com/qdm12/gluetun/internal/configuration/settings/helpers"
|
||||||
"github.com/qdm12/gotree"
|
"github.com/qdm12/gotree"
|
||||||
@@ -33,6 +34,12 @@ type HTTPProxy struct {
|
|||||||
// each request/response. It cannot be nil in the
|
// each request/response. It cannot be nil in the
|
||||||
// internal state.
|
// internal state.
|
||||||
Log *bool
|
Log *bool
|
||||||
|
// ReadHeaderTimeout is the HTTP header read timeout duration
|
||||||
|
// of the HTTP server. It defaults to 1 second if left unset.
|
||||||
|
ReadHeaderTimeout time.Duration
|
||||||
|
// ReadTimeout is the HTTP read timeout duration
|
||||||
|
// of the HTTP server. It defaults to 3 seconds if left unset.
|
||||||
|
ReadTimeout time.Duration
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h HTTPProxy) validate() (err error) {
|
func (h HTTPProxy) validate() (err error) {
|
||||||
@@ -49,12 +56,14 @@ func (h HTTPProxy) validate() (err error) {
|
|||||||
|
|
||||||
func (h *HTTPProxy) copy() (copied HTTPProxy) {
|
func (h *HTTPProxy) copy() (copied HTTPProxy) {
|
||||||
return HTTPProxy{
|
return HTTPProxy{
|
||||||
User: helpers.CopyStringPtr(h.User),
|
User: helpers.CopyStringPtr(h.User),
|
||||||
Password: helpers.CopyStringPtr(h.Password),
|
Password: helpers.CopyStringPtr(h.Password),
|
||||||
ListeningAddress: h.ListeningAddress,
|
ListeningAddress: h.ListeningAddress,
|
||||||
Enabled: helpers.CopyBoolPtr(h.Enabled),
|
Enabled: helpers.CopyBoolPtr(h.Enabled),
|
||||||
Stealth: helpers.CopyBoolPtr(h.Stealth),
|
Stealth: helpers.CopyBoolPtr(h.Stealth),
|
||||||
Log: helpers.CopyBoolPtr(h.Log),
|
Log: helpers.CopyBoolPtr(h.Log),
|
||||||
|
ReadHeaderTimeout: h.ReadHeaderTimeout,
|
||||||
|
ReadTimeout: h.ReadTimeout,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -67,6 +76,8 @@ func (h *HTTPProxy) mergeWith(other HTTPProxy) {
|
|||||||
h.Enabled = helpers.MergeWithBool(h.Enabled, other.Enabled)
|
h.Enabled = helpers.MergeWithBool(h.Enabled, other.Enabled)
|
||||||
h.Stealth = helpers.MergeWithBool(h.Stealth, other.Stealth)
|
h.Stealth = helpers.MergeWithBool(h.Stealth, other.Stealth)
|
||||||
h.Log = helpers.MergeWithBool(h.Log, other.Log)
|
h.Log = helpers.MergeWithBool(h.Log, other.Log)
|
||||||
|
h.ReadHeaderTimeout = helpers.MergeWithDuration(h.ReadHeaderTimeout, other.ReadHeaderTimeout)
|
||||||
|
h.ReadTimeout = helpers.MergeWithDuration(h.ReadTimeout, other.ReadTimeout)
|
||||||
}
|
}
|
||||||
|
|
||||||
// overrideWith overrides fields of the receiver
|
// overrideWith overrides fields of the receiver
|
||||||
@@ -79,6 +90,8 @@ func (h *HTTPProxy) overrideWith(other HTTPProxy) {
|
|||||||
h.Enabled = helpers.OverrideWithBool(h.Enabled, other.Enabled)
|
h.Enabled = helpers.OverrideWithBool(h.Enabled, other.Enabled)
|
||||||
h.Stealth = helpers.OverrideWithBool(h.Stealth, other.Stealth)
|
h.Stealth = helpers.OverrideWithBool(h.Stealth, other.Stealth)
|
||||||
h.Log = helpers.OverrideWithBool(h.Log, other.Log)
|
h.Log = helpers.OverrideWithBool(h.Log, other.Log)
|
||||||
|
h.ReadHeaderTimeout = helpers.OverrideWithDuration(h.ReadHeaderTimeout, other.ReadHeaderTimeout)
|
||||||
|
h.ReadTimeout = helpers.OverrideWithDuration(h.ReadTimeout, other.ReadTimeout)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *HTTPProxy) setDefaults() {
|
func (h *HTTPProxy) setDefaults() {
|
||||||
@@ -88,6 +101,10 @@ func (h *HTTPProxy) setDefaults() {
|
|||||||
h.Enabled = helpers.DefaultBool(h.Enabled, false)
|
h.Enabled = helpers.DefaultBool(h.Enabled, false)
|
||||||
h.Stealth = helpers.DefaultBool(h.Stealth, false)
|
h.Stealth = helpers.DefaultBool(h.Stealth, false)
|
||||||
h.Log = helpers.DefaultBool(h.Log, false)
|
h.Log = helpers.DefaultBool(h.Log, false)
|
||||||
|
const defaultReadHeaderTimeout = time.Second
|
||||||
|
h.ReadHeaderTimeout = helpers.DefaultDuration(h.ReadHeaderTimeout, defaultReadHeaderTimeout)
|
||||||
|
const defaultReadTimeout = 3 * time.Second
|
||||||
|
h.ReadTimeout = helpers.DefaultDuration(h.ReadTimeout, defaultReadTimeout)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h HTTPProxy) String() string {
|
func (h HTTPProxy) String() string {
|
||||||
@@ -106,6 +123,8 @@ func (h HTTPProxy) toLinesNode() (node *gotree.Node) {
|
|||||||
node.Appendf("Password: %s", helpers.ObfuscatePassword(*h.Password))
|
node.Appendf("Password: %s", helpers.ObfuscatePassword(*h.Password))
|
||||||
node.Appendf("Stealth mode: %s", helpers.BoolPtrToYesNo(h.Stealth))
|
node.Appendf("Stealth mode: %s", helpers.BoolPtrToYesNo(h.Stealth))
|
||||||
node.Appendf("Log: %s", helpers.BoolPtrToYesNo(h.Log))
|
node.Appendf("Log: %s", helpers.BoolPtrToYesNo(h.Log))
|
||||||
|
node.Appendf("Read header timeout: %s", h.ReadHeaderTimeout)
|
||||||
|
node.Appendf("Read timeout: %s", h.ReadTimeout)
|
||||||
|
|
||||||
return node
|
return node
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -48,18 +48,18 @@ func (p *PublicIP) copy() (copied PublicIP) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (p *PublicIP) mergeWith(other PublicIP) {
|
func (p *PublicIP) mergeWith(other PublicIP) {
|
||||||
p.Period = helpers.MergeWithDuration(p.Period, other.Period)
|
p.Period = helpers.MergeWithDurationPtr(p.Period, other.Period)
|
||||||
p.IPFilepath = helpers.MergeWithStringPtr(p.IPFilepath, other.IPFilepath)
|
p.IPFilepath = helpers.MergeWithStringPtr(p.IPFilepath, other.IPFilepath)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *PublicIP) overrideWith(other PublicIP) {
|
func (p *PublicIP) overrideWith(other PublicIP) {
|
||||||
p.Period = helpers.OverrideWithDuration(p.Period, other.Period)
|
p.Period = helpers.OverrideWithDurationPtr(p.Period, other.Period)
|
||||||
p.IPFilepath = helpers.OverrideWithStringPtr(p.IPFilepath, other.IPFilepath)
|
p.IPFilepath = helpers.OverrideWithStringPtr(p.IPFilepath, other.IPFilepath)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *PublicIP) setDefaults() {
|
func (p *PublicIP) setDefaults() {
|
||||||
const defaultPeriod = 12 * time.Hour
|
const defaultPeriod = 12 * time.Hour
|
||||||
p.Period = helpers.DefaultDuration(p.Period, defaultPeriod)
|
p.Period = helpers.DefaultDurationPtr(p.Period, defaultPeriod)
|
||||||
p.IPFilepath = helpers.DefaultStringPtr(p.IPFilepath, "/tmp/gluetun/ip")
|
p.IPFilepath = helpers.DefaultStringPtr(p.IPFilepath, "/tmp/gluetun/ip")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -67,6 +67,8 @@ func Test_Settings_String(t *testing.T) {
|
|||||||
├── Health settings:
|
├── Health settings:
|
||||||
| ├── Server listening address: 127.0.0.1:9999
|
| ├── Server listening address: 127.0.0.1:9999
|
||||||
| ├── Target address: cloudflare.com:443
|
| ├── Target address: cloudflare.com:443
|
||||||
|
| ├── Read header timeout: 100ms
|
||||||
|
| ├── Read timeout: 500ms
|
||||||
| └── VPN wait durations:
|
| └── VPN wait durations:
|
||||||
| ├── Initial duration: 6s
|
| ├── Initial duration: 6s
|
||||||
| └── Additional duration: 5s
|
| └── Additional duration: 5s
|
||||||
|
|||||||
@@ -73,7 +73,7 @@ func (u *Updater) copy() (copied Updater) {
|
|||||||
// mergeWith merges the other settings into any
|
// mergeWith merges the other settings into any
|
||||||
// unset field of the receiver settings object.
|
// unset field of the receiver settings object.
|
||||||
func (u *Updater) mergeWith(other Updater) {
|
func (u *Updater) mergeWith(other Updater) {
|
||||||
u.Period = helpers.MergeWithDuration(u.Period, other.Period)
|
u.Period = helpers.MergeWithDurationPtr(u.Period, other.Period)
|
||||||
u.DNSAddress = helpers.MergeWithString(u.DNSAddress, other.DNSAddress)
|
u.DNSAddress = helpers.MergeWithString(u.DNSAddress, other.DNSAddress)
|
||||||
u.MinRatio = helpers.MergeWithFloat64(u.MinRatio, other.MinRatio)
|
u.MinRatio = helpers.MergeWithFloat64(u.MinRatio, other.MinRatio)
|
||||||
u.Providers = helpers.MergeStringSlices(u.Providers, other.Providers)
|
u.Providers = helpers.MergeStringSlices(u.Providers, other.Providers)
|
||||||
@@ -83,14 +83,14 @@ func (u *Updater) mergeWith(other Updater) {
|
|||||||
// settings object with any field set in the other
|
// settings object with any field set in the other
|
||||||
// settings.
|
// settings.
|
||||||
func (u *Updater) overrideWith(other Updater) {
|
func (u *Updater) overrideWith(other Updater) {
|
||||||
u.Period = helpers.OverrideWithDuration(u.Period, other.Period)
|
u.Period = helpers.OverrideWithDurationPtr(u.Period, other.Period)
|
||||||
u.DNSAddress = helpers.OverrideWithString(u.DNSAddress, other.DNSAddress)
|
u.DNSAddress = helpers.OverrideWithString(u.DNSAddress, other.DNSAddress)
|
||||||
u.MinRatio = helpers.OverrideWithFloat64(u.MinRatio, other.MinRatio)
|
u.MinRatio = helpers.OverrideWithFloat64(u.MinRatio, other.MinRatio)
|
||||||
u.Providers = helpers.OverrideWithStringSlice(u.Providers, other.Providers)
|
u.Providers = helpers.OverrideWithStringSlice(u.Providers, other.Providers)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *Updater) SetDefaults(vpnProvider string) {
|
func (u *Updater) SetDefaults(vpnProvider string) {
|
||||||
u.Period = helpers.DefaultDuration(u.Period, 0)
|
u.Period = helpers.DefaultDurationPtr(u.Period, 0)
|
||||||
u.DNSAddress = helpers.DefaultString(u.DNSAddress, "1.1.1.1:53")
|
u.DNSAddress = helpers.DefaultString(u.DNSAddress, "1.1.1.1:53")
|
||||||
|
|
||||||
if u.MinRatio == 0 {
|
if u.MinRatio == 0 {
|
||||||
|
|||||||
@@ -14,8 +14,10 @@ func (s *Server) Run(ctx context.Context, done chan<- struct{}) {
|
|||||||
go s.runHealthcheckLoop(ctx, loopDone)
|
go s.runHealthcheckLoop(ctx, loopDone)
|
||||||
|
|
||||||
server := http.Server{
|
server := http.Server{
|
||||||
Addr: s.config.ServerAddress,
|
Addr: s.config.ServerAddress,
|
||||||
Handler: s.handler,
|
Handler: s.handler,
|
||||||
|
ReadHeaderTimeout: s.config.ReadHeaderTimeout,
|
||||||
|
ReadTimeout: s.config.ReadTimeout,
|
||||||
}
|
}
|
||||||
serverDone := make(chan struct{})
|
serverDone := make(chan struct{})
|
||||||
go func() {
|
go func() {
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ func (l *Loop) Run(ctx context.Context, done chan<- struct{}) {
|
|||||||
settings := l.state.GetSettings()
|
settings := l.state.GetSettings()
|
||||||
server := New(runCtx, settings.ListeningAddress, l.logger,
|
server := New(runCtx, settings.ListeningAddress, l.logger,
|
||||||
*settings.Stealth, *settings.Log, *settings.User,
|
*settings.Stealth, *settings.Log, *settings.User,
|
||||||
*settings.Password)
|
*settings.Password, settings.ReadHeaderTimeout, settings.ReadTimeout)
|
||||||
|
|
||||||
errorCh := make(chan error)
|
errorCh := make(chan error)
|
||||||
go server.Run(runCtx, errorCh)
|
go server.Run(runCtx, errorCh)
|
||||||
|
|||||||
@@ -8,25 +8,35 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type Server struct {
|
type Server struct {
|
||||||
address string
|
address string
|
||||||
handler http.Handler
|
handler http.Handler
|
||||||
logger infoErrorer
|
logger infoErrorer
|
||||||
internalWG *sync.WaitGroup
|
internalWG *sync.WaitGroup
|
||||||
|
readHeaderTimeout time.Duration
|
||||||
|
readTimeout time.Duration
|
||||||
}
|
}
|
||||||
|
|
||||||
func New(ctx context.Context, address string, logger Logger,
|
func New(ctx context.Context, address string, logger Logger,
|
||||||
stealth, verbose bool, username, password string) *Server {
|
stealth, verbose bool, username, password string,
|
||||||
|
readHeaderTimeout, readTimeout time.Duration) *Server {
|
||||||
wg := &sync.WaitGroup{}
|
wg := &sync.WaitGroup{}
|
||||||
return &Server{
|
return &Server{
|
||||||
address: address,
|
address: address,
|
||||||
handler: newHandler(ctx, wg, logger, stealth, verbose, username, password),
|
handler: newHandler(ctx, wg, logger, stealth, verbose, username, password),
|
||||||
logger: logger,
|
logger: logger,
|
||||||
internalWG: wg,
|
internalWG: wg,
|
||||||
|
readHeaderTimeout: readHeaderTimeout,
|
||||||
|
readTimeout: readTimeout,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) Run(ctx context.Context, errorCh chan<- error) {
|
func (s *Server) Run(ctx context.Context, errorCh chan<- error) {
|
||||||
server := http.Server{Addr: s.address, Handler: s.handler}
|
server := http.Server{
|
||||||
|
Addr: s.address,
|
||||||
|
Handler: s.handler,
|
||||||
|
ReadHeaderTimeout: s.readHeaderTimeout,
|
||||||
|
ReadTimeout: s.readTimeout,
|
||||||
|
}
|
||||||
go func() {
|
go func() {
|
||||||
<-ctx.Done()
|
<-ctx.Done()
|
||||||
const shutdownGraceDuration = 2 * time.Second
|
const shutdownGraceDuration = 2 * time.Second
|
||||||
|
|||||||
@@ -2,13 +2,10 @@ package httpserver
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"regexp"
|
"regexp"
|
||||||
"time"
|
|
||||||
|
|
||||||
gomock "github.com/golang/mock/gomock"
|
gomock "github.com/golang/mock/gomock"
|
||||||
)
|
)
|
||||||
|
|
||||||
func durationPtr(d time.Duration) *time.Duration { return &d }
|
|
||||||
|
|
||||||
var _ Logger = (*testLogger)(nil)
|
var _ Logger = (*testLogger)(nil)
|
||||||
|
|
||||||
type testLogger struct{}
|
type testLogger struct{}
|
||||||
|
|||||||
@@ -11,7 +11,12 @@ import (
|
|||||||
// The done channel has an error written to when the HTTP server
|
// The done channel has an error written to when the HTTP server
|
||||||
// is terminated, and can be nil or not nil.
|
// is terminated, and can be nil or not nil.
|
||||||
func (s *Server) Run(ctx context.Context, ready chan<- struct{}, done chan<- struct{}) {
|
func (s *Server) Run(ctx context.Context, ready chan<- struct{}, done chan<- struct{}) {
|
||||||
server := http.Server{Addr: s.address, Handler: s.handler}
|
server := http.Server{
|
||||||
|
Addr: s.address,
|
||||||
|
Handler: s.handler,
|
||||||
|
ReadHeaderTimeout: s.readHeaderTimeout,
|
||||||
|
ReadTimeout: s.readTimeout,
|
||||||
|
}
|
||||||
|
|
||||||
crashed := make(chan struct{})
|
crashed := make(chan struct{})
|
||||||
shutdownDone := make(chan struct{})
|
shutdownDone := make(chan struct{})
|
||||||
|
|||||||
@@ -9,11 +9,13 @@ import (
|
|||||||
// Server is an HTTP server implementation, which uses
|
// Server is an HTTP server implementation, which uses
|
||||||
// the HTTP handler provided.
|
// the HTTP handler provided.
|
||||||
type Server struct {
|
type Server struct {
|
||||||
address string
|
address string
|
||||||
addressSet chan struct{}
|
addressSet chan struct{}
|
||||||
handler http.Handler
|
handler http.Handler
|
||||||
logger Logger
|
logger Logger
|
||||||
shutdownTimeout time.Duration
|
readHeaderTimeout time.Duration
|
||||||
|
readTimeout time.Duration
|
||||||
|
shutdownTimeout time.Duration
|
||||||
}
|
}
|
||||||
|
|
||||||
// New creates a new HTTP server with the given settings.
|
// New creates a new HTTP server with the given settings.
|
||||||
@@ -26,10 +28,12 @@ func New(settings Settings) (s *Server, err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return &Server{
|
return &Server{
|
||||||
address: settings.Address,
|
address: settings.Address,
|
||||||
addressSet: make(chan struct{}),
|
addressSet: make(chan struct{}),
|
||||||
handler: settings.Handler,
|
handler: settings.Handler,
|
||||||
logger: settings.Logger,
|
logger: settings.Logger,
|
||||||
shutdownTimeout: *settings.ShutdownTimeout,
|
readHeaderTimeout: settings.ReadHeaderTimeout,
|
||||||
|
readTimeout: settings.ReadTimeout,
|
||||||
|
shutdownTimeout: settings.ShutdownTimeout,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,16 +29,20 @@ func Test_New(t *testing.T) {
|
|||||||
},
|
},
|
||||||
"filled settings": {
|
"filled settings": {
|
||||||
settings: Settings{
|
settings: Settings{
|
||||||
Address: ":8001",
|
Address: ":8001",
|
||||||
Handler: someHandler,
|
Handler: someHandler,
|
||||||
Logger: someLogger,
|
Logger: someLogger,
|
||||||
ShutdownTimeout: durationPtr(time.Second),
|
ReadHeaderTimeout: time.Second,
|
||||||
|
ReadTimeout: time.Second,
|
||||||
|
ShutdownTimeout: time.Second,
|
||||||
},
|
},
|
||||||
expected: &Server{
|
expected: &Server{
|
||||||
address: ":8001",
|
address: ":8001",
|
||||||
handler: someHandler,
|
handler: someHandler,
|
||||||
logger: someLogger,
|
logger: someLogger,
|
||||||
shutdownTimeout: time.Second,
|
readHeaderTimeout: time.Second,
|
||||||
|
readTimeout: time.Second,
|
||||||
|
shutdownTimeout: time.Second,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,23 +22,34 @@ type Settings struct {
|
|||||||
// Logger is the logger to use.
|
// Logger is the logger to use.
|
||||||
// It must be set and cannot be left to nil.
|
// It must be set and cannot be left to nil.
|
||||||
Logger Logger
|
Logger Logger
|
||||||
|
// ReadHeaderTimeout is the HTTP header read timeout duration
|
||||||
|
// of the HTTP server. It defaults to 3 seconds if left unset.
|
||||||
|
ReadHeaderTimeout time.Duration
|
||||||
|
// ReadTimeout is the HTTP read timeout duration
|
||||||
|
// of the HTTP server. It defaults to 3 seconds if left unset.
|
||||||
|
ReadTimeout time.Duration
|
||||||
// ShutdownTimeout is the shutdown timeout duration
|
// ShutdownTimeout is the shutdown timeout duration
|
||||||
// of the HTTP server. It defaults to 3 seconds.
|
// of the HTTP server. It defaults to 3 seconds if left unset.
|
||||||
ShutdownTimeout *time.Duration
|
ShutdownTimeout time.Duration
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Settings) SetDefaults() {
|
func (s *Settings) SetDefaults() {
|
||||||
s.Address = helpers.DefaultString(s.Address, ":8000")
|
s.Address = helpers.DefaultString(s.Address, ":8000")
|
||||||
|
const defaultReadTimeout = 3 * time.Second
|
||||||
|
s.ReadHeaderTimeout = helpers.DefaultDuration(s.ReadHeaderTimeout, defaultReadTimeout)
|
||||||
|
s.ReadTimeout = helpers.DefaultDuration(s.ReadTimeout, defaultReadTimeout)
|
||||||
const defaultShutdownTimeout = 3 * time.Second
|
const defaultShutdownTimeout = 3 * time.Second
|
||||||
s.ShutdownTimeout = helpers.DefaultDuration(s.ShutdownTimeout, defaultShutdownTimeout)
|
s.ShutdownTimeout = helpers.DefaultDuration(s.ShutdownTimeout, defaultShutdownTimeout)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s Settings) Copy() Settings {
|
func (s Settings) Copy() Settings {
|
||||||
return Settings{
|
return Settings{
|
||||||
Address: s.Address,
|
Address: s.Address,
|
||||||
Handler: s.Handler,
|
Handler: s.Handler,
|
||||||
Logger: s.Logger,
|
Logger: s.Logger,
|
||||||
ShutdownTimeout: helpers.CopyDurationPtr(s.ShutdownTimeout),
|
ReadHeaderTimeout: s.ReadHeaderTimeout,
|
||||||
|
ReadTimeout: s.ReadTimeout,
|
||||||
|
ShutdownTimeout: s.ShutdownTimeout,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -48,6 +59,8 @@ func (s *Settings) MergeWith(other Settings) {
|
|||||||
if s.Logger == nil {
|
if s.Logger == nil {
|
||||||
s.Logger = other.Logger
|
s.Logger = other.Logger
|
||||||
}
|
}
|
||||||
|
s.ReadHeaderTimeout = helpers.MergeWithDuration(s.ReadHeaderTimeout, other.ReadHeaderTimeout)
|
||||||
|
s.ReadTimeout = helpers.MergeWithDuration(s.ReadTimeout, other.ReadTimeout)
|
||||||
s.ShutdownTimeout = helpers.MergeWithDuration(s.ShutdownTimeout, other.ShutdownTimeout)
|
s.ShutdownTimeout = helpers.MergeWithDuration(s.ShutdownTimeout, other.ShutdownTimeout)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -57,13 +70,17 @@ func (s *Settings) OverrideWith(other Settings) {
|
|||||||
if other.Logger != nil {
|
if other.Logger != nil {
|
||||||
s.Logger = other.Logger
|
s.Logger = other.Logger
|
||||||
}
|
}
|
||||||
|
s.ReadHeaderTimeout = helpers.OverrideWithDuration(s.ReadHeaderTimeout, other.ReadHeaderTimeout)
|
||||||
|
s.ReadTimeout = helpers.OverrideWithDuration(s.ReadTimeout, other.ReadTimeout)
|
||||||
s.ShutdownTimeout = helpers.OverrideWithDuration(s.ShutdownTimeout, other.ShutdownTimeout)
|
s.ShutdownTimeout = helpers.OverrideWithDuration(s.ShutdownTimeout, other.ShutdownTimeout)
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
ErrHandlerIsNotSet = errors.New("HTTP handler cannot be left unset")
|
ErrHandlerIsNotSet = errors.New("HTTP handler cannot be left unset")
|
||||||
ErrLoggerIsNotSet = errors.New("logger cannot be left unset")
|
ErrLoggerIsNotSet = errors.New("logger cannot be left unset")
|
||||||
ErrShutdownTimeoutTooSmall = errors.New("shutdown timeout is too small")
|
ErrReadHeaderTimeoutTooSmall = errors.New("read header timeout is too small")
|
||||||
|
ErrReadTimeoutTooSmall = errors.New("read timeout is too small")
|
||||||
|
ErrShutdownTimeoutTooSmall = errors.New("shutdown timeout is too small")
|
||||||
)
|
)
|
||||||
|
|
||||||
func (s Settings) Validate() (err error) {
|
func (s Settings) Validate() (err error) {
|
||||||
@@ -81,11 +98,24 @@ func (s Settings) Validate() (err error) {
|
|||||||
return ErrLoggerIsNotSet
|
return ErrLoggerIsNotSet
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const minReadTimeout = time.Millisecond
|
||||||
|
if s.ReadHeaderTimeout < minReadTimeout {
|
||||||
|
return fmt.Errorf("%w: %s must be at least %s",
|
||||||
|
ErrReadHeaderTimeoutTooSmall,
|
||||||
|
s.ReadHeaderTimeout, minReadTimeout)
|
||||||
|
}
|
||||||
|
|
||||||
|
if s.ReadTimeout < minReadTimeout {
|
||||||
|
return fmt.Errorf("%w: %s must be at least %s",
|
||||||
|
ErrReadTimeoutTooSmall,
|
||||||
|
s.ReadTimeout, minReadTimeout)
|
||||||
|
}
|
||||||
|
|
||||||
const minShutdownTimeout = 5 * time.Millisecond
|
const minShutdownTimeout = 5 * time.Millisecond
|
||||||
if *s.ShutdownTimeout < minShutdownTimeout {
|
if s.ShutdownTimeout < minShutdownTimeout {
|
||||||
return fmt.Errorf("%w: %s must be at least %s",
|
return fmt.Errorf("%w: %s must be at least %s",
|
||||||
ErrShutdownTimeoutTooSmall,
|
ErrShutdownTimeoutTooSmall,
|
||||||
*s.ShutdownTimeout, minShutdownTimeout)
|
s.ShutdownTimeout, minShutdownTimeout)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
@@ -94,7 +124,9 @@ func (s Settings) Validate() (err error) {
|
|||||||
func (s Settings) ToLinesNode() (node *gotree.Node) {
|
func (s Settings) ToLinesNode() (node *gotree.Node) {
|
||||||
node = gotree.New("HTTP server settings:")
|
node = gotree.New("HTTP server settings:")
|
||||||
node.Appendf("Listening address: %s", s.Address)
|
node.Appendf("Listening address: %s", s.Address)
|
||||||
node.Appendf("Shutdown timeout: %s", *s.ShutdownTimeout)
|
node.Appendf("Read header timeout: %s", s.ReadHeaderTimeout)
|
||||||
|
node.Appendf("Read timeout: %s", s.ReadTimeout)
|
||||||
|
node.Appendf("Shutdown timeout: %s", s.ShutdownTimeout)
|
||||||
return node
|
return node
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -21,18 +21,24 @@ func Test_Settings_SetDefaults(t *testing.T) {
|
|||||||
"empty settings": {
|
"empty settings": {
|
||||||
settings: Settings{},
|
settings: Settings{},
|
||||||
expected: Settings{
|
expected: Settings{
|
||||||
Address: ":8000",
|
Address: ":8000",
|
||||||
ShutdownTimeout: durationPtr(defaultTimeout),
|
ReadHeaderTimeout: defaultTimeout,
|
||||||
|
ReadTimeout: defaultTimeout,
|
||||||
|
ShutdownTimeout: defaultTimeout,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"filled settings": {
|
"filled settings": {
|
||||||
settings: Settings{
|
settings: Settings{
|
||||||
Address: ":8001",
|
Address: ":8001",
|
||||||
ShutdownTimeout: durationPtr(time.Second),
|
ReadHeaderTimeout: time.Second,
|
||||||
|
ReadTimeout: time.Second,
|
||||||
|
ShutdownTimeout: time.Second,
|
||||||
},
|
},
|
||||||
expected: Settings{
|
expected: Settings{
|
||||||
Address: ":8001",
|
Address: ":8001",
|
||||||
ShutdownTimeout: durationPtr(time.Second),
|
ReadHeaderTimeout: time.Second,
|
||||||
|
ReadTimeout: time.Second,
|
||||||
|
ShutdownTimeout: time.Second,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@@ -62,16 +68,20 @@ func Test_Settings_Copy(t *testing.T) {
|
|||||||
"empty settings": {},
|
"empty settings": {},
|
||||||
"filled settings": {
|
"filled settings": {
|
||||||
settings: Settings{
|
settings: Settings{
|
||||||
Address: ":8001",
|
Address: ":8001",
|
||||||
Handler: someHandler,
|
Handler: someHandler,
|
||||||
Logger: someLogger,
|
Logger: someLogger,
|
||||||
ShutdownTimeout: durationPtr(time.Second),
|
ReadHeaderTimeout: time.Second,
|
||||||
|
ReadTimeout: time.Second,
|
||||||
|
ShutdownTimeout: time.Second,
|
||||||
},
|
},
|
||||||
expected: Settings{
|
expected: Settings{
|
||||||
Address: ":8001",
|
Address: ":8001",
|
||||||
Handler: someHandler,
|
Handler: someHandler,
|
||||||
Logger: someLogger,
|
Logger: someLogger,
|
||||||
ShutdownTimeout: durationPtr(time.Second),
|
ReadHeaderTimeout: time.Second,
|
||||||
|
ReadTimeout: time.Second,
|
||||||
|
ShutdownTimeout: time.Second,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@@ -102,30 +112,38 @@ func Test_Settings_MergeWith(t *testing.T) {
|
|||||||
"merge empty with empty": {},
|
"merge empty with empty": {},
|
||||||
"merge empty with filled": {
|
"merge empty with filled": {
|
||||||
other: Settings{
|
other: Settings{
|
||||||
Address: ":8001",
|
Address: ":8001",
|
||||||
Handler: someHandler,
|
Handler: someHandler,
|
||||||
Logger: someLogger,
|
Logger: someLogger,
|
||||||
ShutdownTimeout: durationPtr(time.Second),
|
ReadHeaderTimeout: time.Second,
|
||||||
|
ReadTimeout: time.Second,
|
||||||
|
ShutdownTimeout: time.Second,
|
||||||
},
|
},
|
||||||
expected: Settings{
|
expected: Settings{
|
||||||
Address: ":8001",
|
Address: ":8001",
|
||||||
Handler: someHandler,
|
Handler: someHandler,
|
||||||
Logger: someLogger,
|
Logger: someLogger,
|
||||||
ShutdownTimeout: durationPtr(time.Second),
|
ReadHeaderTimeout: time.Second,
|
||||||
|
ReadTimeout: time.Second,
|
||||||
|
ShutdownTimeout: time.Second,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"merge filled with empty": {
|
"merge filled with empty": {
|
||||||
settings: Settings{
|
settings: Settings{
|
||||||
Address: ":8001",
|
Address: ":8001",
|
||||||
Handler: someHandler,
|
Handler: someHandler,
|
||||||
Logger: someLogger,
|
Logger: someLogger,
|
||||||
ShutdownTimeout: durationPtr(time.Second),
|
ReadHeaderTimeout: time.Second,
|
||||||
|
ReadTimeout: time.Second,
|
||||||
|
ShutdownTimeout: time.Second,
|
||||||
},
|
},
|
||||||
expected: Settings{
|
expected: Settings{
|
||||||
Address: ":8001",
|
Address: ":8001",
|
||||||
Handler: someHandler,
|
Handler: someHandler,
|
||||||
Logger: someLogger,
|
Logger: someLogger,
|
||||||
ShutdownTimeout: durationPtr(time.Second),
|
ReadHeaderTimeout: time.Second,
|
||||||
|
ReadTimeout: time.Second,
|
||||||
|
ShutdownTimeout: time.Second,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@@ -156,48 +174,62 @@ func Test_Settings_OverrideWith(t *testing.T) {
|
|||||||
"override empty with empty": {},
|
"override empty with empty": {},
|
||||||
"override empty with filled": {
|
"override empty with filled": {
|
||||||
other: Settings{
|
other: Settings{
|
||||||
Address: ":8001",
|
Address: ":8001",
|
||||||
Handler: someHandler,
|
Handler: someHandler,
|
||||||
Logger: someLogger,
|
Logger: someLogger,
|
||||||
ShutdownTimeout: durationPtr(time.Second),
|
ReadHeaderTimeout: time.Second,
|
||||||
|
ReadTimeout: time.Second,
|
||||||
|
ShutdownTimeout: time.Second,
|
||||||
},
|
},
|
||||||
expected: Settings{
|
expected: Settings{
|
||||||
Address: ":8001",
|
Address: ":8001",
|
||||||
Handler: someHandler,
|
Handler: someHandler,
|
||||||
Logger: someLogger,
|
Logger: someLogger,
|
||||||
ShutdownTimeout: durationPtr(time.Second),
|
ReadHeaderTimeout: time.Second,
|
||||||
|
ReadTimeout: time.Second,
|
||||||
|
ShutdownTimeout: time.Second,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"override filled with empty": {
|
"override filled with empty": {
|
||||||
settings: Settings{
|
settings: Settings{
|
||||||
Address: ":8001",
|
Address: ":8001",
|
||||||
Handler: someHandler,
|
Handler: someHandler,
|
||||||
Logger: someLogger,
|
Logger: someLogger,
|
||||||
ShutdownTimeout: durationPtr(time.Second),
|
ReadHeaderTimeout: time.Second,
|
||||||
|
ReadTimeout: time.Second,
|
||||||
|
ShutdownTimeout: time.Second,
|
||||||
},
|
},
|
||||||
expected: Settings{
|
expected: Settings{
|
||||||
Address: ":8001",
|
Address: ":8001",
|
||||||
Handler: someHandler,
|
Handler: someHandler,
|
||||||
Logger: someLogger,
|
Logger: someLogger,
|
||||||
ShutdownTimeout: durationPtr(time.Second),
|
ReadHeaderTimeout: time.Second,
|
||||||
|
ReadTimeout: time.Second,
|
||||||
|
ShutdownTimeout: time.Second,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"override filled with filled": {
|
"override filled with filled": {
|
||||||
settings: Settings{
|
settings: Settings{
|
||||||
Address: ":8001",
|
Address: ":8001",
|
||||||
Handler: someHandler,
|
Handler: someHandler,
|
||||||
Logger: someLogger,
|
Logger: someLogger,
|
||||||
ShutdownTimeout: durationPtr(time.Second),
|
ReadHeaderTimeout: time.Second,
|
||||||
|
ReadTimeout: time.Second,
|
||||||
|
ShutdownTimeout: time.Second,
|
||||||
},
|
},
|
||||||
other: Settings{
|
other: Settings{
|
||||||
Address: ":8002",
|
Address: ":8002",
|
||||||
ShutdownTimeout: durationPtr(time.Hour),
|
ReadHeaderTimeout: time.Hour,
|
||||||
|
ReadTimeout: time.Hour,
|
||||||
|
ShutdownTimeout: time.Hour,
|
||||||
},
|
},
|
||||||
expected: Settings{
|
expected: Settings{
|
||||||
Address: ":8002",
|
Address: ":8002",
|
||||||
Handler: someHandler,
|
Handler: someHandler,
|
||||||
Logger: someLogger,
|
Logger: someLogger,
|
||||||
ShutdownTimeout: durationPtr(time.Hour),
|
ReadHeaderTimeout: time.Hour,
|
||||||
|
ReadTimeout: time.Hour,
|
||||||
|
ShutdownTimeout: time.Hour,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@@ -247,22 +279,47 @@ func Test_Settings_Validate(t *testing.T) {
|
|||||||
errWrapped: ErrLoggerIsNotSet,
|
errWrapped: ErrLoggerIsNotSet,
|
||||||
errMessage: ErrLoggerIsNotSet.Error(),
|
errMessage: ErrLoggerIsNotSet.Error(),
|
||||||
},
|
},
|
||||||
|
"read header timeout too small": {
|
||||||
|
settings: Settings{
|
||||||
|
Address: ":8000",
|
||||||
|
Handler: someHandler,
|
||||||
|
Logger: someLogger,
|
||||||
|
ReadHeaderTimeout: time.Nanosecond,
|
||||||
|
},
|
||||||
|
errWrapped: ErrReadHeaderTimeoutTooSmall,
|
||||||
|
errMessage: "read header timeout is too small: 1ns must be at least 1ms",
|
||||||
|
},
|
||||||
|
"read timeout too small": {
|
||||||
|
settings: Settings{
|
||||||
|
Address: ":8000",
|
||||||
|
Handler: someHandler,
|
||||||
|
Logger: someLogger,
|
||||||
|
ReadHeaderTimeout: time.Millisecond,
|
||||||
|
ReadTimeout: time.Nanosecond,
|
||||||
|
},
|
||||||
|
errWrapped: ErrReadTimeoutTooSmall,
|
||||||
|
errMessage: "read timeout is too small: 1ns must be at least 1ms",
|
||||||
|
},
|
||||||
"shutdown timeout too small": {
|
"shutdown timeout too small": {
|
||||||
settings: Settings{
|
settings: Settings{
|
||||||
Address: ":8000",
|
Address: ":8000",
|
||||||
Handler: someHandler,
|
Handler: someHandler,
|
||||||
Logger: someLogger,
|
Logger: someLogger,
|
||||||
ShutdownTimeout: durationPtr(time.Millisecond),
|
ReadHeaderTimeout: time.Millisecond,
|
||||||
|
ReadTimeout: time.Millisecond,
|
||||||
|
ShutdownTimeout: time.Millisecond,
|
||||||
},
|
},
|
||||||
errWrapped: ErrShutdownTimeoutTooSmall,
|
errWrapped: ErrShutdownTimeoutTooSmall,
|
||||||
errMessage: "shutdown timeout is too small: 1ms must be at least 5ms",
|
errMessage: "shutdown timeout is too small: 1ms must be at least 5ms",
|
||||||
},
|
},
|
||||||
"valid settings": {
|
"valid settings": {
|
||||||
settings: Settings{
|
settings: Settings{
|
||||||
Address: ":8000",
|
Address: ":8000",
|
||||||
Handler: someHandler,
|
Handler: someHandler,
|
||||||
Logger: someLogger,
|
Logger: someLogger,
|
||||||
ShutdownTimeout: durationPtr(time.Second),
|
ReadHeaderTimeout: time.Millisecond,
|
||||||
|
ReadTimeout: time.Millisecond,
|
||||||
|
ShutdownTimeout: time.Second,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@@ -291,11 +348,15 @@ func Test_Settings_String(t *testing.T) {
|
|||||||
}{
|
}{
|
||||||
"all values": {
|
"all values": {
|
||||||
settings: Settings{
|
settings: Settings{
|
||||||
Address: ":8000",
|
Address: ":8000",
|
||||||
ShutdownTimeout: durationPtr(time.Second),
|
ReadHeaderTimeout: time.Millisecond,
|
||||||
|
ReadTimeout: time.Millisecond,
|
||||||
|
ShutdownTimeout: time.Second,
|
||||||
},
|
},
|
||||||
s: `HTTP server settings:
|
s: `HTTP server settings:
|
||||||
├── Listening address: :8000
|
├── Listening address: :8000
|
||||||
|
├── Read header timeout: 1ms
|
||||||
|
├── Read timeout: 1ms
|
||||||
└── Shutdown timeout: 1s`,
|
└── Shutdown timeout: 1s`,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,13 +2,11 @@ package pprof
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"regexp"
|
"regexp"
|
||||||
"time"
|
|
||||||
|
|
||||||
gomock "github.com/golang/mock/gomock"
|
gomock "github.com/golang/mock/gomock"
|
||||||
)
|
)
|
||||||
|
|
||||||
func boolPtr(b bool) *bool { return &b }
|
func boolPtr(b bool) *bool { return &b }
|
||||||
func durationPtr(d time.Duration) *time.Duration { return &d }
|
|
||||||
|
|
||||||
var _ gomock.Matcher = (*regexMatcher)(nil)
|
var _ gomock.Matcher = (*regexMatcher)(nil)
|
||||||
|
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ func Test_Server(t *testing.T) {
|
|||||||
HTTPServer: httpserver.Settings{
|
HTTPServer: httpserver.Settings{
|
||||||
Address: address,
|
Address: address,
|
||||||
Logger: logger,
|
Logger: logger,
|
||||||
ShutdownTimeout: durationPtr(httpServerShutdownTimeout),
|
ShutdownTimeout: httpServerShutdownTimeout,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package pprof
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/qdm12/gluetun/internal/configuration/settings/helpers"
|
"github.com/qdm12/gluetun/internal/configuration/settings/helpers"
|
||||||
"github.com/qdm12/gluetun/internal/httpserver"
|
"github.com/qdm12/gluetun/internal/httpserver"
|
||||||
@@ -27,6 +28,8 @@ type Settings struct {
|
|||||||
func (s *Settings) SetDefaults() {
|
func (s *Settings) SetDefaults() {
|
||||||
s.Enabled = helpers.DefaultBool(s.Enabled, false)
|
s.Enabled = helpers.DefaultBool(s.Enabled, false)
|
||||||
s.HTTPServer.Address = helpers.DefaultString(s.HTTPServer.Address, "localhost:6060")
|
s.HTTPServer.Address = helpers.DefaultString(s.HTTPServer.Address, "localhost:6060")
|
||||||
|
const defaultReadTimeout = 5 * time.Minute // for CPU profiling
|
||||||
|
s.HTTPServer.ReadTimeout = helpers.DefaultDuration(s.HTTPServer.ReadTimeout, defaultReadTimeout)
|
||||||
s.HTTPServer.SetDefaults()
|
s.HTTPServer.SetDefaults()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -21,8 +21,10 @@ func Test_Settings_SetDefaults(t *testing.T) {
|
|||||||
expected: Settings{
|
expected: Settings{
|
||||||
Enabled: boolPtr(false),
|
Enabled: boolPtr(false),
|
||||||
HTTPServer: httpserver.Settings{
|
HTTPServer: httpserver.Settings{
|
||||||
Address: "localhost:6060",
|
Address: "localhost:6060",
|
||||||
ShutdownTimeout: durationPtr(3 * time.Second),
|
ReadHeaderTimeout: 3 * time.Second,
|
||||||
|
ReadTimeout: 5 * time.Minute,
|
||||||
|
ShutdownTimeout: 3 * time.Second,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -32,8 +34,10 @@ func Test_Settings_SetDefaults(t *testing.T) {
|
|||||||
BlockProfileRate: 1,
|
BlockProfileRate: 1,
|
||||||
MutexProfileRate: 1,
|
MutexProfileRate: 1,
|
||||||
HTTPServer: httpserver.Settings{
|
HTTPServer: httpserver.Settings{
|
||||||
Address: ":6061",
|
Address: ":6061",
|
||||||
ShutdownTimeout: durationPtr(time.Second),
|
ReadHeaderTimeout: time.Second,
|
||||||
|
ReadTimeout: time.Second,
|
||||||
|
ShutdownTimeout: time.Second,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
expected: Settings{
|
expected: Settings{
|
||||||
@@ -41,8 +45,10 @@ func Test_Settings_SetDefaults(t *testing.T) {
|
|||||||
BlockProfileRate: 1,
|
BlockProfileRate: 1,
|
||||||
MutexProfileRate: 1,
|
MutexProfileRate: 1,
|
||||||
HTTPServer: httpserver.Settings{
|
HTTPServer: httpserver.Settings{
|
||||||
Address: ":6061",
|
Address: ":6061",
|
||||||
ShutdownTimeout: durationPtr(time.Second),
|
ReadHeaderTimeout: time.Second,
|
||||||
|
ReadTimeout: time.Second,
|
||||||
|
ShutdownTimeout: time.Second,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -75,7 +81,7 @@ func Test_Settings_Copy(t *testing.T) {
|
|||||||
MutexProfileRate: 1,
|
MutexProfileRate: 1,
|
||||||
HTTPServer: httpserver.Settings{
|
HTTPServer: httpserver.Settings{
|
||||||
Address: ":6061",
|
Address: ":6061",
|
||||||
ShutdownTimeout: durationPtr(time.Second),
|
ShutdownTimeout: time.Second,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
expected: Settings{
|
expected: Settings{
|
||||||
@@ -84,7 +90,7 @@ func Test_Settings_Copy(t *testing.T) {
|
|||||||
MutexProfileRate: 1,
|
MutexProfileRate: 1,
|
||||||
HTTPServer: httpserver.Settings{
|
HTTPServer: httpserver.Settings{
|
||||||
Address: ":6061",
|
Address: ":6061",
|
||||||
ShutdownTimeout: durationPtr(time.Second),
|
ShutdownTimeout: time.Second,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -278,10 +284,12 @@ func Test_Settings_Validate(t *testing.T) {
|
|||||||
"valid settings": {
|
"valid settings": {
|
||||||
settings: Settings{
|
settings: Settings{
|
||||||
HTTPServer: httpserver.Settings{
|
HTTPServer: httpserver.Settings{
|
||||||
Address: ":8000",
|
Address: ":8000",
|
||||||
Handler: http.NewServeMux(),
|
Handler: http.NewServeMux(),
|
||||||
Logger: &MockLogger{},
|
Logger: &MockLogger{},
|
||||||
ShutdownTimeout: durationPtr(time.Second),
|
ReadHeaderTimeout: time.Second,
|
||||||
|
ReadTimeout: time.Second,
|
||||||
|
ShutdownTimeout: time.Second,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -321,7 +329,7 @@ func Test_Settings_String(t *testing.T) {
|
|||||||
MutexProfileRate: 1,
|
MutexProfileRate: 1,
|
||||||
HTTPServer: httpserver.Settings{
|
HTTPServer: httpserver.Settings{
|
||||||
Address: ":8000",
|
Address: ":8000",
|
||||||
ShutdownTimeout: durationPtr(time.Second),
|
ShutdownTimeout: time.Second,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
s: `Pprof settings:
|
s: `Pprof settings:
|
||||||
@@ -329,6 +337,8 @@ func Test_Settings_String(t *testing.T) {
|
|||||||
├── Mutex profile rate: 1
|
├── Mutex profile rate: 1
|
||||||
└── HTTP server settings:
|
└── HTTP server settings:
|
||||||
├── Listening address: :8000
|
├── Listening address: :8000
|
||||||
|
├── Read header timeout: 0s
|
||||||
|
├── Read timeout: 0s
|
||||||
└── Shutdown timeout: 1s`,
|
└── Shutdown timeout: 1s`,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user