1
0
mirror of https://github.com/umputun/reproxy.git synced 2025-09-16 08:46:17 +02:00

support size units #71

This commit is contained in:
Umputun
2021-05-14 22:01:27 -05:00
parent aee7e8a57e
commit b79a9faf3c
3 changed files with 84 additions and 11 deletions

View File

@@ -210,6 +210,8 @@ Reproxy returns 502 (Bad Gateway) error in case if request doesn't match to any
Each option can be provided in two forms: command line or environment key:value. Some command line options have a short form, like `-l localhost:8080` and all of them have the long form, i.e `--listen=localhost:8080`. The environment key (name) listed for each option as a suffix, i.e. `[$LISTEN]`.
All size options support unit suffixes, i.e. 10K (or 10k) for kilobytes, 16M (or 16m) for megabytes, 10G (or 10g) for gigabytes. LAck of any suffix (i.e. 1024) means bytes.
Some options are repeatable, in this case you may pass it multiple times with command line, or comma-separated in env. For example `--ssl.fqdn` is such an option and can be passed as `--ssl.fqdn=a1.example.com --ssl.fqdn=a2.example.com` or as env `SSL_ACME_FQDN=a1.example.com,a2.example.com`
This is the list of all options supporting multiple elements:
@@ -219,12 +221,13 @@ This is the list of all options supporting multiple elements:
- `docker.exclude` (`DOCKER_EXCLUDE`)
- `static.rule` (`$STATIC_RULES`)
## All Application Options
```
Application Options:
-l, --listen= listen on host:port (default: 0.0.0.0:8080/8443 under docker, 127.0.0.1:80/443 without) [$LISTEN]
-m, --max= max request size (default: 64000) [$MAX_SIZE]
-m, --max= max request size (default: 64K) [$MAX_SIZE]
-g, --gzip enable gz compression [$GZIP]
-x, --header= proxy headers [$HEADER]
--signature enable reproxy signature headers [$SIGNATURE]
@@ -248,7 +251,7 @@ logger:
--logger.stdout enable stdout logging [$LOGGER_STDOUT]
--logger.enabled enable access and error rotated logs [$LOGGER_ENABLED]
--logger.file= location of access log (default: access.log) [$LOGGER_FILE]
--logger.max-size= maximum size in megabytes before it gets rotated (default: 100) [$LOGGER_MAX_SIZE]
--logger.max-size= maximum size in megabytes before it gets rotated (default: 100M) [$LOGGER_MAX_SIZE]
--logger.max-backups= maximum number of old log files to retain (default: 10) [$LOGGER_MAX_BACKUPS]
docker:

View File

@@ -6,9 +6,11 @@ import (
"fmt"
"io"
"io/ioutil"
"math"
"net/http"
"os"
"os/signal"
"strconv"
"strings"
"syscall"
"time"
@@ -26,7 +28,7 @@ import (
var opts struct {
Listen string `short:"l" long:"listen" env:"LISTEN" description:"listen on host:port (default: 0.0.0.0:8080/8443 under docker, 127.0.0.1:80/443 without)"`
MaxSize int64 `short:"m" long:"max" env:"MAX_SIZE" default:"64000" description:"max request size"`
MaxSize string `short:"m" long:"max" env:"MAX_SIZE" default:"64K" description:"max request size"`
GzipEnabled bool `short:"g" long:"gzip" env:"GZIP" description:"enable gz compression"`
ProxyHeaders []string `short:"x" long:"header" env:"HEADER" description:"proxy headers" env-delim:","`
@@ -50,7 +52,7 @@ var opts struct {
StdOut bool `long:"stdout" env:"STDOUT" description:"enable stdout logging"`
Enabled bool `long:"enabled" env:"ENABLED" description:"enable access and error rotated logs"`
FileName string `long:"file" env:"FILE" default:"access.log" description:"location of access log"`
MaxSize int `long:"max-size" env:"MAX_SIZE" default:"100" description:"maximum size in megabytes before it gets rotated"`
MaxSize string `long:"max-size" env:"MAX_SIZE" default:"100M" description:"maximum size before it gets rotated"`
MaxBackups int `long:"max-backups" env:"MAX_BACKUPS" default:"10" description:"maximum number of old log files to retain"`
} `group:"logger" namespace:"logger" env-namespace:"LOGGER"`
@@ -167,7 +169,11 @@ func run() error {
return fmt.Errorf("failed to make config of ssl server params: %w", sslErr)
}
accessLog := makeAccessLogWriter()
accessLog, alErr := makeAccessLogWriter()
if alErr != nil {
return fmt.Errorf("failed to access log: %w", sslErr)
}
defer func() {
if logErr := accessLog.Close(); logErr != nil {
log.Printf("[WARN] can't close access log, %v", logErr)
@@ -204,11 +210,16 @@ func run() error {
addr := listenAddress(opts.Listen, opts.SSL.Type)
log.Printf("[DEBUG] listen address %s", addr)
maxBodySize, perr := sizeParse(opts.MaxSize)
if perr != nil {
return fmt.Errorf("failed to convert MaxSize: %w", err)
}
px := &proxy.Http{
Version: revision,
Matcher: svc,
Address: addr,
MaxBodySize: opts.MaxSize,
MaxBodySize: int64(maxBodySize),
AssetsLocation: opts.Assets.Location,
AssetsWebRoot: opts.Assets.WebRoot,
CacheControl: cacheControl,
@@ -326,18 +337,26 @@ func makeErrorReporter() (proxy.Reporter, error) {
return result, nil
}
func makeAccessLogWriter() (accessLog io.WriteCloser) {
func makeAccessLogWriter() (accessLog io.WriteCloser, err error) {
if !opts.Logger.Enabled {
return nopWriteCloser{ioutil.Discard}
return nopWriteCloser{ioutil.Discard}, nil
}
log.Printf("[INFO] logger enabled for %s", opts.Logger.FileName)
maxSize, perr := sizeParse(opts.Logger.MaxSize)
if perr != nil {
return nil, fmt.Errorf("can't parse logger MaxSize: %w", perr)
}
maxSize = maxSize / 1048576
log.Printf("[INFO] logger enabled for %s, max size %dM", opts.Logger.FileName, maxSize)
return &lumberjack.Logger{
Filename: opts.Logger.FileName,
MaxSize: opts.Logger.MaxSize,
MaxSize: int(maxSize), // in MB
MaxBackups: opts.Logger.MaxBackups,
Compress: true,
LocalTime: true,
}
}, nil
}
// listenAddress sets default to 127.0.0.0:8080/80443 and, if detected REPROXY_IN_DOCKER env, to 0.0.0.0:80/443
@@ -374,6 +393,22 @@ func redirHTTPPort(port int) int {
return 80
}
func sizeParse(inp string) (uint64, error) {
if inp == "" {
return 0, errors.New("empty value")
}
for i, sfx := range []string{"k", "m", "g", "t"} {
if strings.HasSuffix(inp, strings.ToUpper(sfx)) || strings.HasSuffix(inp, strings.ToLower(sfx)) {
val, err := strconv.Atoi(inp[:len(inp)-1])
if err != nil {
return 0, fmt.Errorf("can't parse %s: %w", inp, err)
}
return uint64(float64(val) * math.Pow(float64(1024), float64(i+1))), nil
}
}
return strconv.ParseUint(inp, 10, 64)
}
type nopWriteCloser struct{ io.Writer }
func (n nopWriteCloser) Close() error { return nil }

View File

@@ -233,3 +233,38 @@ func Test_redirHTTPPort(t *testing.T) {
})
}
}
func Test_sizeParse(t *testing.T) {
tbl := []struct {
inp string
res uint64
err bool
}{
{"1000", 1000, false},
{"0", 0, false},
{"", 0, true},
{"10K", 10240, false},
{"1k", 1024, false},
{"14m", 14 * 1024 * 1024, false},
{"7G", 7 * 1024 * 1024 * 1024, false},
{"170g", 170 * 1024 * 1024 * 1024, false},
{"17T", 17 * 1024 * 1024 * 1024 * 1024, false},
{"123aT", 0, true},
{"123a", 0, true},
{"123.45", 0, true},
}
for i, tt := range tbl {
t.Run(strconv.Itoa(i), func(t *testing.T) {
res, err := sizeParse(tt.inp)
if tt.err {
require.Error(t, err)
return
}
require.NoError(t, err)
assert.Equal(t, tt.res, res)
})
}
}