202 lines
3.7 KiB
Go
202 lines
3.7 KiB
Go
package engine
|
|
|
|
import (
|
|
"net"
|
|
"path"
|
|
"reflect"
|
|
"runtime"
|
|
"strings"
|
|
"unicode"
|
|
)
|
|
|
|
/*
|
|
解析一个 IP 的字符串表示并返回一个 net.IP
|
|
最小字节表示,如果输入无效,则为零。
|
|
*/
|
|
func parseIP(ip string) net.IP {
|
|
parsedIP := net.ParseIP(ip)
|
|
if ipv4 := parsedIP.To4(); ipv4 != nil {
|
|
return ipv4
|
|
}
|
|
return parsedIP
|
|
}
|
|
|
|
func lastChar(str string) uint8 {
|
|
if str == "" {
|
|
panic("The length of the string can't be 0")
|
|
}
|
|
return str[len(str)-1]
|
|
}
|
|
|
|
func assert1(guard bool, text string) {
|
|
if !guard {
|
|
panic(text)
|
|
}
|
|
}
|
|
|
|
func nameOfFunction(f interface{}) string {
|
|
return runtime.FuncForPC(reflect.ValueOf(f).Pointer()).Name()
|
|
}
|
|
|
|
func joinPaths(absolutePath, relativePath string) string {
|
|
if relativePath == "" {
|
|
return absolutePath
|
|
}
|
|
|
|
finalPath := path.Join(absolutePath, relativePath)
|
|
if lastChar(relativePath) == '/' && lastChar(finalPath) != '/' {
|
|
return finalPath + "/"
|
|
}
|
|
return finalPath
|
|
}
|
|
|
|
func iterate(path, method string, routes RoutesInfo, root *node) RoutesInfo {
|
|
path += root.path
|
|
if len(root.handlers) > 0 {
|
|
handlerFunc := root.handlers.Last()
|
|
routes = append(routes, RouteInfo{
|
|
Method: method,
|
|
Path: path,
|
|
Handler: nameOfFunction(handlerFunc),
|
|
HandlerFunc: handlerFunc,
|
|
})
|
|
}
|
|
for _, child := range root.children {
|
|
routes = iterate(path, method, routes, child)
|
|
}
|
|
return routes
|
|
}
|
|
func filterFlags(content string) string {
|
|
for i, char := range content {
|
|
if char == ' ' || char == ';' {
|
|
return content[:i]
|
|
}
|
|
}
|
|
return content
|
|
}
|
|
|
|
func cleanPath(p string) string {
|
|
const stackBufSize = 128
|
|
if p == "" {
|
|
return "/"
|
|
}
|
|
buf := make([]byte, 0, stackBufSize)
|
|
n := len(p)
|
|
r := 1
|
|
w := 1
|
|
if p[0] != '/' {
|
|
r = 0
|
|
if n+1 > stackBufSize {
|
|
buf = make([]byte, n+1)
|
|
} else {
|
|
buf = buf[:n+1]
|
|
}
|
|
buf[0] = '/'
|
|
}
|
|
|
|
trailing := n > 1 && p[n-1] == '/'
|
|
|
|
for r < n {
|
|
switch {
|
|
case p[r] == '/':
|
|
r++
|
|
case p[r] == '.' && r+1 == n:
|
|
trailing = true
|
|
r++
|
|
case p[r] == '.' && p[r+1] == '/':
|
|
r += 2
|
|
|
|
case p[r] == '.' && p[r+1] == '.' && (r+2 == n || p[r+2] == '/'):
|
|
r += 3
|
|
if w > 1 {
|
|
w--
|
|
if len(buf) == 0 {
|
|
for w > 1 && p[w] != '/' {
|
|
w--
|
|
}
|
|
} else {
|
|
for w > 1 && buf[w] != '/' {
|
|
w--
|
|
}
|
|
}
|
|
}
|
|
default:
|
|
if w > 1 {
|
|
bufApp(&buf, p, w, '/')
|
|
w++
|
|
}
|
|
for r < n && p[r] != '/' {
|
|
bufApp(&buf, p, w, p[r])
|
|
w++
|
|
r++
|
|
}
|
|
}
|
|
}
|
|
if trailing && w > 1 {
|
|
bufApp(&buf, p, w, '/')
|
|
w++
|
|
}
|
|
if len(buf) == 0 {
|
|
return p[:w]
|
|
}
|
|
return string(buf[:w])
|
|
}
|
|
|
|
func bufApp(buf *[]byte, s string, w int, c byte) {
|
|
b := *buf
|
|
if len(b) == 0 {
|
|
// No modification of the original string so far.
|
|
// If the next character is the same as in the original string, we do
|
|
// not yet have to allocate a buffer.
|
|
if s[w] == c {
|
|
return
|
|
}
|
|
|
|
// Otherwise use either the stack buffer, if it is large enough, or
|
|
// allocate a new buffer on the heap, and copy all previous characters.
|
|
length := len(s)
|
|
if length > cap(b) {
|
|
*buf = make([]byte, length)
|
|
} else {
|
|
*buf = (*buf)[:length]
|
|
}
|
|
b = *buf
|
|
|
|
copy(b, s[:w])
|
|
}
|
|
b[w] = c
|
|
}
|
|
|
|
func parseAccept(acceptHeader string) []string {
|
|
parts := strings.Split(acceptHeader, ",")
|
|
out := make([]string, 0, len(parts))
|
|
for _, part := range parts {
|
|
if i := strings.IndexByte(part, ';'); i > 0 {
|
|
part = part[:i]
|
|
}
|
|
if part = strings.TrimSpace(part); part != "" {
|
|
out = append(out, part)
|
|
}
|
|
}
|
|
return out
|
|
}
|
|
|
|
func chooseData(custom, wildcard interface{}) interface{} {
|
|
if custom != nil {
|
|
return custom
|
|
}
|
|
if wildcard != nil {
|
|
return wildcard
|
|
}
|
|
panic("negotiation config is invalid")
|
|
}
|
|
|
|
func isASCII(s string) bool {
|
|
for i := 0; i < len(s); i++ {
|
|
if s[i] > unicode.MaxASCII {
|
|
return false
|
|
}
|
|
}
|
|
return true
|
|
}
|