mirror of
https://github.com/yusing/godoxy.git
synced 2026-04-20 23:41:23 +02:00
migrated from logrus to zerolog, improved error formatting, fixed concurrent map write, fixed crash on rapid page refresh for idle containers, fixed infinite recursion on gotfiy error, fixed websocket connection problem when using idlewatcher
This commit is contained in:
@@ -1,6 +1,3 @@
|
||||
package fields
|
||||
|
||||
type (
|
||||
Alias string
|
||||
NewAlias = Alias
|
||||
)
|
||||
type Alias string
|
||||
|
||||
@@ -1,14 +1,10 @@
|
||||
package fields
|
||||
|
||||
import (
|
||||
E "github.com/yusing/go-proxy/internal/error"
|
||||
)
|
||||
|
||||
type (
|
||||
Host string
|
||||
Subdomain = Alias
|
||||
)
|
||||
|
||||
func ValidateHost[String ~string](s String) (Host, E.Error) {
|
||||
func ValidateHost[String ~string](s String) (Host, error) {
|
||||
return Host(s), nil
|
||||
}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
package fields
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"regexp"
|
||||
|
||||
E "github.com/yusing/go-proxy/internal/error"
|
||||
@@ -13,12 +15,17 @@ type (
|
||||
|
||||
var pathPattern = regexp.MustCompile(`^(/[-\w./]*({\$\})?|((GET|POST|DELETE|PUT|HEAD|OPTION) /[-\w./]*({\$\})?))$`)
|
||||
|
||||
func ValidatePathPattern(s string) (PathPattern, E.Error) {
|
||||
var (
|
||||
ErrEmptyPathPattern = errors.New("path must not be empty")
|
||||
ErrInvalidPathPattern = errors.New("invalid path pattern")
|
||||
)
|
||||
|
||||
func ValidatePathPattern(s string) (PathPattern, error) {
|
||||
if len(s) == 0 {
|
||||
return "", E.Invalid("path", "must not be empty")
|
||||
return "", ErrEmptyPathPattern
|
||||
}
|
||||
if !pathPattern.MatchString(s) {
|
||||
return "", E.Invalid("path pattern", s)
|
||||
return "", fmt.Errorf("%w %q", ErrInvalidPathPattern, s)
|
||||
}
|
||||
return PathPattern(s), nil
|
||||
}
|
||||
@@ -27,13 +34,15 @@ func ValidatePathPatterns(s []string) (PathPatterns, E.Error) {
|
||||
if len(s) == 0 {
|
||||
return []PathPattern{"/"}, nil
|
||||
}
|
||||
errs := E.NewBuilder("invalid path patterns")
|
||||
pp := make(PathPatterns, len(s))
|
||||
for i, v := range s {
|
||||
pattern, err := ValidatePathPattern(v)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
errs.Add(err)
|
||||
} else {
|
||||
pp[i] = pattern
|
||||
}
|
||||
pp[i] = pattern
|
||||
}
|
||||
return pp, nil
|
||||
return pp, errs.Error()
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
package fields
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"testing"
|
||||
|
||||
E "github.com/yusing/go-proxy/internal/error"
|
||||
U "github.com/yusing/go-proxy/internal/utils/testing"
|
||||
)
|
||||
|
||||
@@ -38,10 +38,10 @@ var invalidPatterns = []string{
|
||||
func TestPathPatternRegex(t *testing.T) {
|
||||
for _, pattern := range validPatterns {
|
||||
_, err := ValidatePathPattern(pattern)
|
||||
U.ExpectNoError(t, err.Error())
|
||||
U.ExpectNoError(t, err)
|
||||
}
|
||||
for _, pattern := range invalidPatterns {
|
||||
_, err := ValidatePathPattern(pattern)
|
||||
U.ExpectError2(t, pattern, E.ErrInvalid, err.Error())
|
||||
U.ExpectTrue(t, errors.Is(err, ErrInvalidPathPattern))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,22 +4,25 @@ import (
|
||||
"strconv"
|
||||
|
||||
E "github.com/yusing/go-proxy/internal/error"
|
||||
"github.com/yusing/go-proxy/internal/utils/strutils"
|
||||
)
|
||||
|
||||
type Port int
|
||||
|
||||
func ValidatePort[String ~string](v String) (Port, E.Error) {
|
||||
p, err := strconv.Atoi(string(v))
|
||||
var ErrPortOutOfRange = E.New("port out of range")
|
||||
|
||||
func ValidatePort[String ~string](v String) (Port, error) {
|
||||
p, err := strutils.Atoi(string(v))
|
||||
if err != nil {
|
||||
return ErrPort, E.Invalid("port number", v).With(err)
|
||||
return ErrPort, err
|
||||
}
|
||||
return ValidatePortInt(p)
|
||||
}
|
||||
|
||||
func ValidatePortInt[Int int | uint16](v Int) (Port, E.Error) {
|
||||
func ValidatePortInt[Int int | uint16](v Int) (Port, error) {
|
||||
p := Port(v)
|
||||
if !p.inBound() {
|
||||
return ErrPort, E.OutOfRange("port", p)
|
||||
return ErrPort, ErrPortOutOfRange.Subject(strconv.Itoa(int(p)))
|
||||
}
|
||||
return p, nil
|
||||
}
|
||||
|
||||
@@ -6,12 +6,14 @@ import (
|
||||
|
||||
type Scheme string
|
||||
|
||||
func NewScheme[String ~string](s String) (Scheme, E.Error) {
|
||||
var ErrInvalidScheme = E.New("invalid scheme")
|
||||
|
||||
func NewScheme(s string) (Scheme, error) {
|
||||
switch s {
|
||||
case "http", "https", "tcp", "udp":
|
||||
return Scheme(s), nil
|
||||
}
|
||||
return "", E.Invalid("scheme", s)
|
||||
return "", ErrInvalidScheme.Subject(s)
|
||||
}
|
||||
|
||||
func (s Scheme) IsHTTP() bool { return s == "http" }
|
||||
|
||||
@@ -3,7 +3,6 @@ package fields
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/yusing/go-proxy/internal/common"
|
||||
E "github.com/yusing/go-proxy/internal/error"
|
||||
)
|
||||
|
||||
@@ -12,7 +11,9 @@ type StreamPort struct {
|
||||
ProxyPort Port `json:"proxy"`
|
||||
}
|
||||
|
||||
func ValidateStreamPort(p string) (_ StreamPort, err E.Error) {
|
||||
var ErrStreamPortTooManyColons = E.New("too many colons")
|
||||
|
||||
func ValidateStreamPort(p string) (StreamPort, error) {
|
||||
split := strings.Split(p, ":")
|
||||
|
||||
switch len(split) {
|
||||
@@ -21,36 +22,14 @@ func ValidateStreamPort(p string) (_ StreamPort, err E.Error) {
|
||||
case 2:
|
||||
break
|
||||
default:
|
||||
err = E.Invalid("stream port", p).With("too many colons")
|
||||
return
|
||||
return StreamPort{}, ErrStreamPortTooManyColons.Subject(p)
|
||||
}
|
||||
|
||||
listeningPort, err := ValidatePort(split[0])
|
||||
if err != nil {
|
||||
err = err.Subject("listening port")
|
||||
return
|
||||
}
|
||||
|
||||
proxyPort, err := ValidatePort(split[1])
|
||||
|
||||
if err.Is(E.ErrOutOfRange) {
|
||||
err = err.Subject("proxy port")
|
||||
return
|
||||
} else if err != nil {
|
||||
proxyPort, err = parseNameToPort(split[1])
|
||||
if err != nil {
|
||||
err = E.Invalid("proxy port", proxyPort)
|
||||
return
|
||||
}
|
||||
listeningPort, lErr := ValidatePort(split[0])
|
||||
proxyPort, pErr := ValidatePort(split[1])
|
||||
if err := E.Join(lErr, pErr); err != nil {
|
||||
return StreamPort{}, err
|
||||
}
|
||||
|
||||
return StreamPort{listeningPort, proxyPort}, nil
|
||||
}
|
||||
|
||||
func parseNameToPort(name string) (Port, E.Error) {
|
||||
port, ok := common.ServiceNamePortMapTCP[name]
|
||||
if !ok {
|
||||
return ErrPort, E.Invalid("service", name)
|
||||
}
|
||||
return Port(port), nil
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
package fields
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"testing"
|
||||
|
||||
E "github.com/yusing/go-proxy/internal/error"
|
||||
. "github.com/yusing/go-proxy/internal/utils/testing"
|
||||
)
|
||||
|
||||
@@ -11,7 +11,6 @@ var validPorts = []string{
|
||||
"1234:5678",
|
||||
"0:2345",
|
||||
"2345",
|
||||
"1234:postgres",
|
||||
}
|
||||
|
||||
var invalidPorts = []string{
|
||||
@@ -19,7 +18,6 @@ var invalidPorts = []string{
|
||||
"123:",
|
||||
"0:",
|
||||
":1234",
|
||||
"1234:1234:1234",
|
||||
"qwerty",
|
||||
"asdfgh:asdfgh",
|
||||
"1234:asdfgh",
|
||||
@@ -32,17 +30,25 @@ var outOfRangePorts = []string{
|
||||
"0:65536",
|
||||
}
|
||||
|
||||
var tooManyColonsPorts = []string{
|
||||
"1234:1234:1234",
|
||||
}
|
||||
|
||||
func TestStreamPort(t *testing.T) {
|
||||
for _, port := range validPorts {
|
||||
_, err := ValidateStreamPort(port)
|
||||
ExpectNoError(t, err.Error())
|
||||
ExpectNoError(t, err)
|
||||
}
|
||||
for _, port := range invalidPorts {
|
||||
_, err := ValidateStreamPort(port)
|
||||
ExpectError2(t, port, E.ErrInvalid, err.Error())
|
||||
ExpectError2(t, port, strconv.ErrSyntax, err)
|
||||
}
|
||||
for _, port := range outOfRangePorts {
|
||||
_, err := ValidateStreamPort(port)
|
||||
ExpectError2(t, port, E.ErrOutOfRange, err.Error())
|
||||
ExpectError2(t, port, ErrPortOutOfRange, err)
|
||||
}
|
||||
for _, port := range tooManyColonsPorts {
|
||||
_, err := ValidateStreamPort(port)
|
||||
ExpectError2(t, port, ErrStreamPortTooManyColons, err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,22 +12,23 @@ type StreamScheme struct {
|
||||
ProxyScheme Scheme `json:"proxy"`
|
||||
}
|
||||
|
||||
func ValidateStreamScheme(s string) (ss *StreamScheme, err E.Error) {
|
||||
ss = &StreamScheme{}
|
||||
func ValidateStreamScheme(s string) (*StreamScheme, error) {
|
||||
ss := &StreamScheme{}
|
||||
parts := strings.Split(s, ":")
|
||||
if len(parts) == 1 {
|
||||
parts = []string{s, s}
|
||||
} else if len(parts) != 2 {
|
||||
return nil, E.Invalid("stream scheme", s)
|
||||
return nil, ErrInvalidScheme.Subject(s)
|
||||
}
|
||||
ss.ListeningScheme, err = NewScheme(parts[0])
|
||||
if err.HasError() {
|
||||
return nil, err
|
||||
}
|
||||
ss.ProxyScheme, err = NewScheme(parts[1])
|
||||
if err.HasError() {
|
||||
|
||||
var lErr, pErr error
|
||||
ss.ListeningScheme, lErr = NewScheme(parts[0])
|
||||
ss.ProxyScheme, pErr = NewScheme(parts[1])
|
||||
|
||||
if err := E.Join(lErr, pErr); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return ss, nil
|
||||
}
|
||||
|
||||
|
||||
37
internal/proxy/fields/stream_scheme_test.go
Normal file
37
internal/proxy/fields/stream_scheme_test.go
Normal file
@@ -0,0 +1,37 @@
|
||||
package fields
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
. "github.com/yusing/go-proxy/internal/utils/testing"
|
||||
)
|
||||
|
||||
var (
|
||||
validStreamSchemes = []string{
|
||||
"tcp:tcp",
|
||||
"tcp:udp",
|
||||
"udp:tcp",
|
||||
"udp:udp",
|
||||
"tcp",
|
||||
"udp",
|
||||
}
|
||||
|
||||
invalidStreamSchemes = []string{
|
||||
"tcp:tcp:",
|
||||
"tcp:",
|
||||
":udp:",
|
||||
":udp",
|
||||
"top",
|
||||
}
|
||||
)
|
||||
|
||||
func TestNewStreamScheme(t *testing.T) {
|
||||
for _, s := range validStreamSchemes {
|
||||
_, err := ValidateStreamScheme(s)
|
||||
ExpectNoError(t, err)
|
||||
}
|
||||
for _, s := range invalidStreamSchemes {
|
||||
_, err := ValidateStreamScheme(s)
|
||||
ExpectError(t, ErrInvalidScheme, err)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user