feat(smalltrip,multiplexer): pattern options and rules multiplexer
This commit is contained in:
168
multiplexer/patterns.go
Normal file
168
multiplexer/patterns.go
Normal file
@@ -0,0 +1,168 @@
|
||||
// Copyright 2025-present Gustavo "Guz" L. de Mello
|
||||
// Copyright 2025-present The Lored.dev Contributors
|
||||
//
|
||||
// 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 multiplexer
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"slices"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func WithPatternsOptions(mux Multiplexer, opts ...PatternOption) Multiplexer {
|
||||
return &patternsMux{opts: opts, Multiplexer: mux}
|
||||
}
|
||||
|
||||
func AddTrailingSlash() PatternOption {
|
||||
return func(s string) string {
|
||||
if strings.HasSuffix(s, "...}") {
|
||||
return s
|
||||
}
|
||||
// If the pattern is /image.html{$}, we modify it to be /image.html/{$}
|
||||
if strings.HasSuffix(s, "{$}") && !strings.HasSuffix(s, "/{$}") {
|
||||
return strings.TrimSuffix(s, "{$}") + "/{$}"
|
||||
}
|
||||
if !strings.HasSuffix(s, "/") {
|
||||
return s + "/"
|
||||
}
|
||||
return s
|
||||
}
|
||||
}
|
||||
|
||||
func RemoveTrailingSlash() PatternOption {
|
||||
return func(s string) string {
|
||||
s = strings.TrimSuffix(s, "/")
|
||||
if strings.HasSuffix(s, "/{$}") {
|
||||
return strings.TrimSuffix(s, "/{$}") + "{$}"
|
||||
}
|
||||
return s
|
||||
}
|
||||
}
|
||||
|
||||
func AddStrictEnd() PatternOption {
|
||||
return func(s string) string {
|
||||
if strings.HasSuffix(s, "{$}") {
|
||||
return s
|
||||
}
|
||||
return s + "{$}"
|
||||
}
|
||||
}
|
||||
|
||||
func RemoteStrictEnd() PatternOption {
|
||||
return func(s string) string {
|
||||
return strings.TrimSuffix(s, "{$}")
|
||||
}
|
||||
}
|
||||
|
||||
type PatternOption func(string) string
|
||||
|
||||
func WithPatternRules(mux Multiplexer, rules ...PatternRule) Multiplexer {
|
||||
opts := make([]PatternOption, len(rules))
|
||||
for i, r := range rules {
|
||||
opts[i] = func(s string) string { r(s); return s }
|
||||
}
|
||||
return &patternsMux{Multiplexer: mux, opts: opts}
|
||||
}
|
||||
|
||||
func NoTrailingSlash() PatternRule {
|
||||
return func(s string) {
|
||||
if strings.HasSuffix(s, "/") || strings.HasSuffix(s, "/{$}") {
|
||||
panic(fmt.Sprintf("no-trailing-slash: pattern %q has trailing slash", s))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func EnsureTrailingSlash() PatternRule {
|
||||
return func(s string) {
|
||||
if !strings.HasSuffix(s, "/{$}") && !strings.HasSuffix(s, "/") && !strings.HasSuffix(s, "...}") {
|
||||
panic(fmt.Sprintf("trailing-slash: pattern %q doesn't has a trailing slash", s))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func NoMethod() PatternRule {
|
||||
return func(s string) {
|
||||
if len(strings.Split(s, " ")) > 1 {
|
||||
panic(fmt.Sprintf("no-method: pattern %q has a method", s))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func EnsureMethod(methods ...string) PatternRule {
|
||||
if len(methods) == 0 && methods != nil {
|
||||
methods = DefaultMethods
|
||||
}
|
||||
return func(s string) {
|
||||
sp := strings.Split(s, " ")
|
||||
if len(sp) <= 0 {
|
||||
panic(fmt.Sprintf("method: pattern %q doesn't has a method", s))
|
||||
}
|
||||
if methods != nil {
|
||||
if slices.Contains(methods, sp[0]) {
|
||||
panic(fmt.Sprintf("method: pattern %q doesn't has a valid method, valid methods are: %s", s, strings.Join(methods, ", ")))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var DefaultMethods = []string{
|
||||
http.MethodConnect,
|
||||
http.MethodDelete,
|
||||
http.MethodGet,
|
||||
http.MethodHead,
|
||||
http.MethodOptions,
|
||||
http.MethodPatch,
|
||||
http.MethodPost,
|
||||
http.MethodPut,
|
||||
http.MethodTrace,
|
||||
}
|
||||
|
||||
func EnsureStrictEnd() PatternRule {
|
||||
return func(s string) {
|
||||
if !strings.HasSuffix(s, "{$}") && !strings.HasSuffix(s, "...}") {
|
||||
panic(fmt.Sprintf(`strict-end: pattern %q doesn't end with "{$}"`, s))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func NoStrictEnd() PatternRule {
|
||||
return func(s string) {
|
||||
if strings.HasSuffix(s, "{$}") {
|
||||
panic(fmt.Sprintf(`no-strict-end: pattern %q ends with "{$}"`, s))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type PatternRule func(string)
|
||||
|
||||
type patternsMux struct {
|
||||
opts []PatternOption
|
||||
Multiplexer
|
||||
}
|
||||
|
||||
func (pm *patternsMux) HandleFunc(p string, h func(http.ResponseWriter, *http.Request)) {
|
||||
for _, po := range pm.opts {
|
||||
p = po(p)
|
||||
}
|
||||
pm.Multiplexer.HandleFunc(p, h)
|
||||
}
|
||||
|
||||
func (pm *patternsMux) Handle(p string, h http.Handler) {
|
||||
for _, po := range pm.opts {
|
||||
p = po(p)
|
||||
}
|
||||
pm.Multiplexer.Handle(p, h)
|
||||
}
|
||||
Reference in New Issue
Block a user