1
0
mirror of https://github.com/gofiber/fiber.git synced 2025-02-23 18:43:49 +00:00
fiber/utils.go

199 lines
4.9 KiB
Go
Raw Normal View History

// 🔌 Fiber is an Express.js inspired web framework build on 🚀 Fasthttp.
2020-01-22 05:42:37 +01:00
// 📌 Please open an issue if you got suggestions or found a bug!
2020-01-16 05:58:23 +01:00
// 🖥 https://github.com/gofiber/fiber
2020-01-15 03:07:49 +01:00
2020-01-16 00:24:58 +01:00
// 🦸 Not all heroes wear capes, thank you to some amazing people
2020-01-15 03:07:49 +01:00
// 💖 @valyala, @dgrr, @erikdubbelboer, @savsgio, @julienschmidt
2019-12-30 07:29:42 -05:00
package fiber
import (
2020-02-05 17:37:04 +01:00
"bytes"
"fmt"
"io/ioutil"
"net"
2020-01-06 18:38:39 -05:00
"os"
"path/filepath"
"reflect"
2019-12-30 07:29:42 -05:00
"regexp"
"strings"
2020-02-05 17:37:04 +01:00
"time"
2019-12-30 07:29:42 -05:00
"unsafe"
2020-02-05 17:37:04 +01:00
"github.com/valyala/fasthttp"
2019-12-30 07:29:42 -05:00
)
func getParams(path string) (params []string) {
segments := strings.Split(path, "/")
2020-01-30 23:17:25 -05:00
replacer := strings.NewReplacer(":", "", "?", "")
2019-12-30 07:29:42 -05:00
for _, s := range segments {
if s == "" {
continue
2020-01-30 23:17:25 -05:00
} else if s[0] == ':' {
params = append(params, replacer.Replace(s))
} else if s[0] == '*' {
2019-12-30 07:29:42 -05:00
params = append(params, "*")
}
}
return params
}
2019-12-30 07:29:42 -05:00
func getRegex(path string) (*regexp.Regexp, error) {
pattern := "^"
segments := strings.Split(path, "/")
for _, s := range segments {
if s == "" {
continue
}
2020-01-30 23:17:25 -05:00
if s[0] == ':' {
2019-12-30 07:29:42 -05:00
if strings.Contains(s, "?") {
pattern += "(?:/([^/]+?))?"
} else {
pattern += "/(?:([^/]+?))"
}
2020-01-30 23:17:25 -05:00
} else if s[0] == '*' {
2019-12-30 07:29:42 -05:00
pattern += "/(.*)"
} else {
pattern += "/" + s
}
}
pattern += "/?$"
regex, err := regexp.Compile(pattern)
return regex, err
}
2020-01-30 23:17:25 -05:00
func getFiles(root string) (files []string, isDir bool, err error) {
2020-01-06 18:38:39 -05:00
err = filepath.Walk(root, func(path string, info os.FileInfo, err error) error {
if !info.IsDir() {
2020-01-11 04:59:51 +01:00
files = append(files, path)
2020-01-06 18:38:39 -05:00
} else {
2020-01-11 04:59:51 +01:00
isDir = true
2020-01-06 18:38:39 -05:00
}
2020-01-11 04:59:51 +01:00
return err
2020-01-06 18:38:39 -05:00
})
2020-01-11 04:59:51 +01:00
return files, isDir, err
2020-01-06 18:38:39 -05:00
}
2020-01-30 23:17:25 -05:00
func getType(ext string) (mime string) {
if ext[0] == '.' {
ext = ext[1:]
}
mime = contentTypes[ext]
if mime == "" {
return contentTypeOctetStream
}
return mime
2019-12-30 07:29:42 -05:00
}
2020-01-30 23:17:25 -05:00
func getStatus(status int) (msg string) {
2020-01-31 15:19:57 -05:00
return statusMessages[status]
2019-12-30 07:29:42 -05:00
}
// #nosec G103
// getString converts byte slice to a string without memory allocation.
// See https://groups.google.com/forum/#!msg/Golang-Nuts/ENgbUzYvCuU/90yGx7GUAgAJ .
2020-01-30 23:17:25 -05:00
func getString(b []byte) string {
return *(*string)(unsafe.Pointer(&b))
2020-01-11 04:59:51 +01:00
}
// #nosec G103
// getBytes converts string to a byte slice without memory allocation.
// See https://groups.google.com/forum/#!msg/Golang-Nuts/ENgbUzYvCuU/90yGx7GUAgAJ .
func getBytes(s string) (b []byte) {
// return *(*[]byte)(unsafe.Pointer(&s))
sh := *(*reflect.StringHeader)(unsafe.Pointer(&s))
2020-02-05 11:54:10 +01:00
bh := (*reflect.SliceHeader)(unsafe.Pointer(&b))
bh.Data, bh.Len, bh.Cap = sh.Data, sh.Len, sh.Len
return b
2020-01-11 04:59:51 +01:00
}
2020-02-05 17:37:04 +01:00
// FakeRequest creates a readWriter and calls ServeConn on local servver
func (r *Fiber) FakeRequest(raw string) (string, error) {
server := &fasthttp.Server{
Handler: r.handler,
Name: r.Server,
Concurrency: r.Engine.Concurrency,
DisableKeepalive: r.Engine.DisableKeepAlive,
ReadBufferSize: r.Engine.ReadBufferSize,
WriteBufferSize: r.Engine.WriteBufferSize,
ReadTimeout: r.Engine.ReadTimeout,
WriteTimeout: r.Engine.WriteTimeout,
IdleTimeout: r.Engine.IdleTimeout,
MaxConnsPerIP: r.Engine.MaxConnsPerIP,
MaxRequestsPerConn: r.Engine.MaxRequestsPerConn,
TCPKeepalive: r.Engine.TCPKeepalive,
TCPKeepalivePeriod: r.Engine.TCPKeepalivePeriod,
MaxRequestBodySize: r.Engine.MaxRequestBodySize,
ReduceMemoryUsage: r.Engine.ReduceMemoryUsage,
GetOnly: r.Engine.GetOnly,
DisableHeaderNamesNormalizing: r.Engine.DisableHeaderNamesNormalizing,
SleepWhenConcurrencyLimitsExceeded: r.Engine.SleepWhenConcurrencyLimitsExceeded,
NoDefaultServerHeader: r.Server == "",
NoDefaultContentType: r.Engine.NoDefaultContentType,
KeepHijackedConns: r.Engine.KeepHijackedConns,
}
rw := &readWriter{}
rw.r.WriteString(raw)
ch := make(chan error)
go func() {
ch <- server.ServeConn(rw)
}()
select {
case err := <-ch:
if err != nil {
return "", err
}
case <-time.After(200 * time.Millisecond):
return "", fmt.Errorf("Timeout")
}
err := server.ServeConn(rw)
if err != nil {
return "", err
}
resp, err := ioutil.ReadAll(&rw.w)
if err != nil {
return "", err
}
return getString(resp), nil
}
// Readwriter for test cases
type readWriter struct {
net.Conn
r bytes.Buffer
w bytes.Buffer
}
func (rw *readWriter) Close() error {
return nil
}
func (rw *readWriter) Read(b []byte) (int, error) {
return rw.r.Read(b)
}
func (rw *readWriter) Write(b []byte) (int, error) {
return rw.w.Write(b)
}
func (rw *readWriter) RemoteAddr() net.Addr {
return &net.TCPAddr{
IP: net.IPv4zero,
}
}
func (rw *readWriter) LocalAddr() net.Addr {
return rw.RemoteAddr()
}
func (rw *readWriter) SetReadDeadline(t time.Time) error {
return nil
}
func (rw *readWriter) SetWriteDeadline(t time.Time) error {
return nil
}