66 lines
1.9 KiB
Go
66 lines
1.9 KiB
Go
package server
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"net"
|
|
"net/http"
|
|
"strings"
|
|
|
|
"proxy-pool/internal/domain/routing"
|
|
"proxy-pool/internal/gateway/dispatch"
|
|
)
|
|
|
|
var (
|
|
ErrRouteNotFound = errors.New("no gateway routing rule matched")
|
|
ErrRouteRejected = errors.New("gateway routing rule rejected the request")
|
|
ErrDirectRouteUnsupported = errors.New("direct gateway routing is not implemented")
|
|
)
|
|
|
|
type RulesRouter struct {
|
|
rules *routing.RuleSet
|
|
}
|
|
|
|
func NewRulesRouter(rules *routing.RuleSet) *RulesRouter {
|
|
return &RulesRouter{rules: rules}
|
|
}
|
|
|
|
func (router *RulesRouter) Route(request *http.Request) (dispatch.Request, error) {
|
|
if router == nil || router.rules == nil || request == nil {
|
|
return dispatch.Request{}, ErrRouteNotFound
|
|
}
|
|
host := request.Host
|
|
if request.URL != nil && request.URL.Hostname() != "" {
|
|
host = request.URL.Hostname()
|
|
} else if parsed, _, err := net.SplitHostPort(host); err == nil {
|
|
host = parsed
|
|
}
|
|
path := "/"
|
|
if request.URL != nil && request.URL.Path != "" {
|
|
path = request.URL.Path
|
|
}
|
|
headers := make(map[string]string, len(request.Header))
|
|
for name := range request.Header {
|
|
headers[name] = request.Header.Get(name)
|
|
}
|
|
matched, ok := router.rules.Match(routing.Request{
|
|
Host: strings.ToLower(strings.TrimSuffix(host, ".")),
|
|
Method: request.Method,
|
|
Path: path,
|
|
Headers: headers,
|
|
})
|
|
if !ok {
|
|
return dispatch.Request{}, ErrRouteNotFound
|
|
}
|
|
switch matched.Action {
|
|
case routing.ActionProxy:
|
|
return dispatch.Request{Upstreams: append([]string(nil), matched.Upstreams...)}, nil
|
|
case routing.ActionReject:
|
|
return dispatch.Request{}, fmt.Errorf("%w: %s", ErrRouteRejected, matched.Name)
|
|
case routing.ActionDirect:
|
|
return dispatch.Request{}, fmt.Errorf("%w: %s", ErrDirectRouteUnsupported, matched.Name)
|
|
default:
|
|
return dispatch.Request{}, fmt.Errorf("%w: %s has action %q", ErrRouteRejected, matched.Name, matched.Action)
|
|
}
|
|
}
|