go_dreamfactory/lego/sys/gin/engine/utils.go
2022-06-07 20:18:22 +08:00

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
}