pull/189/head
Fenny 2020-02-26 19:31:43 -05:00
parent 63353cac7b
commit 2eeb40273c
8 changed files with 287 additions and 413 deletions

122
app.go
View File

@ -23,7 +23,7 @@ import (
)
// Version of Fiber
const Version = "1.7.1"
const Version = "1.8.0"
type (
// App denotes the Fiber application.
@ -46,6 +46,8 @@ type (
CaseSensitive bool `default:"false"`
// Enables the "Server: value" HTTP header.
ServerHeader string `default:""`
// Enables handler values to be immutable even if you return from handler
Immutable bool `default:"false"`
// fasthttp settings
GETOnly bool `default:"false"`
IdleTimeout time.Duration `default:"0"`
@ -72,19 +74,34 @@ type (
}
)
var prefork = flag.Bool("fiber-prefork", false, "use prefork")
var child = flag.Bool("fiber-child", false, "is child process")
func init() {
flag.Bool("prefork", false, "Use prefork")
flag.Bool("child", false, "Is a child process")
}
// New ...
// New : https://fiber.wiki/application#new
func New(settings ...*Settings) (app *App) {
flag.Parse()
var prefork bool
var child bool
for _, arg := range os.Args[1:] {
if arg == "-prefork" {
prefork = true
} else if arg == "-child" {
child = true
}
}
app = &App{
child: *child,
child: child,
}
if len(settings) > 0 {
opt := settings[0]
if !opt.Prefork {
opt.Prefork = *prefork
opt.Prefork = prefork
}
if opt.Immutable {
getString = func(b []byte) string {
return string(b)
}
}
if opt.Concurrency == 0 {
opt.Concurrency = 256 * 1024
@ -102,7 +119,7 @@ func New(settings ...*Settings) (app *App) {
return
}
app.Settings = &Settings{
Prefork: *prefork,
Prefork: prefork,
Concurrency: 256 * 1024,
ReadBufferSize: 4096,
WriteBufferSize: 4096,
@ -111,89 +128,89 @@ func New(settings ...*Settings) (app *App) {
return
}
// Recover
func (app *App) Recover(cb func(*Ctx)) {
app.recover = cb
// Recover : https://fiber.wiki/application#recover
func (app *App) Recover(callback func(*Ctx)) {
app.recover = callback
}
// Recover
func (grp *Group) Recover(cb func(*Ctx)) {
grp.app.recover = cb
// Recover : https://fiber.wiki/application#recover
func (grp *Group) Recover(callback func(*Ctx)) {
grp.app.recover = callback
}
// Static ...
// Static : https://fiber.wiki/application#static
func (app *App) Static(args ...string) *App {
app.registerStatic("/", args...)
return app
}
// WebSocket ...
// WebSocket : https://fiber.wiki/application#websocket
func (app *App) WebSocket(args ...interface{}) *App {
app.register("GET", "", args...)
app.register(http.MethodGet, "", args...)
return app
}
// Connect ...
// Connect : https://fiber.wiki/application#http-methods
func (app *App) Connect(args ...interface{}) *App {
app.register("CONNECT", "", args...)
app.register(http.MethodConnect, "", args...)
return app
}
// Put ...
// Put : https://fiber.wiki/application#http-methods
func (app *App) Put(args ...interface{}) *App {
app.register("PUT", "", args...)
app.register(http.MethodPut, "", args...)
return app
}
// Post ...
// Post : https://fiber.wiki/application#http-methods
func (app *App) Post(args ...interface{}) *App {
app.register("POST", "", args...)
app.register(http.MethodPost, "", args...)
return app
}
// Delete ...
// Delete : https://fiber.wiki/application#http-methods
func (app *App) Delete(args ...interface{}) *App {
app.register("DELETE", "", args...)
app.register(http.MethodDelete, "", args...)
return app
}
// Head ...
// Head : https://fiber.wiki/application#http-methods
func (app *App) Head(args ...interface{}) *App {
app.register("HEAD", "", args...)
app.register(http.MethodHead, "", args...)
return app
}
// Patch ...
// Patch : https://fiber.wiki/application#http-methods
func (app *App) Patch(args ...interface{}) *App {
app.register("PATCH", "", args...)
app.register(http.MethodPatch, "", args...)
return app
}
// Options ...
// Options : https://fiber.wiki/application#http-methods
func (app *App) Options(args ...interface{}) *App {
app.register("OPTIONS", "", args...)
app.register(http.MethodOptions, "", args...)
return app
}
// Trace ...
// Trace : https://fiber.wiki/application#http-methods
func (app *App) Trace(args ...interface{}) *App {
app.register("TRACE", "", args...)
app.register(http.MethodOptions, "", args...)
return app
}
// Get ...
// Get : https://fiber.wiki/application#http-methods
func (app *App) Get(args ...interface{}) *App {
app.register("GET", "", args...)
app.register(http.MethodGet, "", args...)
return app
}
// All ...
// All : https://fiber.wiki/application#http-methods
func (app *App) All(args ...interface{}) *App {
app.register("ALL", "", args...)
return app
}
// Use ...
// Use : https://fiber.wiki/application#http-methods
func (app *App) Use(args ...interface{}) *App {
app.register("USE", "", args...)
return app
@ -214,10 +231,10 @@ func (app *App) Listen(address interface{}, tls ...string) error {
}
// Create fasthttp server
app.server = app.newServer()
// Print banner
// if app.Settings.Banner && !app.child {
// fmt.Printf("Fiber-%s is listening on %s\n", Version, addr)
// }
// Print listening message
if !app.child {
fmt.Printf("Fiber v%s listening on %s\n", Version, addr)
}
var ln net.Listener
var err error
// Prefork enabled
@ -238,7 +255,8 @@ func (app *App) Listen(address interface{}, tls ...string) error {
return app.server.Serve(ln)
}
// Shutdown server gracefully
// Shutdown : TODO: Docs
// Shutsdown the server gracefully
func (app *App) Shutdown() error {
if app.server == nil {
return fmt.Errorf("Server is not running")
@ -246,11 +264,10 @@ func (app *App) Shutdown() error {
return app.server.Shutdown()
}
// Test takes a http.Request and execute a fake connection to the application
// It returns a http.Response when the connection was successful
func (app *App) Test(req *http.Request) (*http.Response, error) {
// Test : https://fiber.wiki/application#test
func (app *App) Test(request *http.Request) (*http.Response, error) {
// Get raw http request
reqRaw, err := httputil.DumpRequest(req, true)
reqRaw, err := httputil.DumpRequest(request, true)
if err != nil {
return nil, err
}
@ -287,7 +304,7 @@ func (app *App) Test(req *http.Request) (*http.Response, error) {
reader := strings.NewReader(getString(respRaw))
buffer := bufio.NewReader(reader)
// Convert raw HTTP response to http.Response
resp, err := http.ReadResponse(buffer, req)
resp, err := http.ReadResponse(buffer, request)
if err != nil {
return nil, err
}
@ -299,11 +316,11 @@ func (app *App) Test(req *http.Request) (*http.Response, error) {
func (app *App) prefork(address string) (ln net.Listener, err error) {
// Master proc
if !app.child {
addr, err := net.ResolveTCPAddr("tcp", address)
addr, err := net.ResolveTCPAddr("tcp4", address)
if err != nil {
return ln, err
}
tcplistener, err := net.ListenTCP("tcp", addr)
tcplistener, err := net.ListenTCP("tcp4", addr)
if err != nil {
return ln, err
}
@ -311,14 +328,14 @@ func (app *App) prefork(address string) (ln net.Listener, err error) {
if err != nil {
return ln, err
}
files := []*os.File{fl}
childs := make([]*exec.Cmd, runtime.NumCPU()/2)
// #nosec G204
for i := range childs {
childs[i] = exec.Command(os.Args[0], "-fiber-prefork", "-fiber-child")
childs[i] = exec.Command(os.Args[0], append(os.Args[1:], "-prefork", "-child")...)
childs[i].Stdout = os.Stdout
childs[i].Stderr = os.Stderr
childs[i].ExtraFiles = []*os.File{fl}
childs[i].ExtraFiles = files
if err := childs[i].Start(); err != nil {
return ln, err
}
@ -331,6 +348,7 @@ func (app *App) prefork(address string) (ln net.Listener, err error) {
}
os.Exit(0)
} else {
runtime.GOMAXPROCS(1)
ln, err = net.FileListener(os.NewFile(3, ""))
}
return ln, err

View File

@ -5,10 +5,8 @@
package fiber
import (
"bytes"
"encoding/xml"
"fmt"
"html/template"
"io/ioutil"
"log"
"mime"
@ -19,14 +17,8 @@ import (
"sync"
"time"
// templates
pug "github.com/Joker/jade"
handlebars "github.com/aymerick/raymond"
mustache "github.com/cbroglie/mustache"
amber "github.com/eknkc/amber"
// core
websocket "github.com/fasthttp/websocket"
template "github.com/gofiber/template"
jsoniter "github.com/json-iterator/go"
fasthttp "github.com/valyala/fasthttp"
)
@ -42,7 +34,6 @@ type Ctx struct {
params *[]string
values []string
Fasthttp *fasthttp.RequestCtx
Socket *websocket.Conn
}
// Ctx pool
@ -67,7 +58,6 @@ func releaseCtx(ctx *Ctx) {
ctx.params = nil
ctx.values = nil
ctx.Fasthttp = nil
ctx.Socket = nil
poolCtx.Put(ctx)
}
@ -115,18 +105,17 @@ func releaseConn(conn *Conn) {
// Cookie : struct
type Cookie struct {
Expire int // time.Unix(1578981376, 0)
MaxAge int
Domain string
Path string
HTTPOnly bool
Name string
Value string
Path string
Domain string
Expires time.Time
Secure bool
SameSite string
HTTPOnly bool
}
// Accepts : https://fiber.wiki/context#accepts
func (ctx *Ctx) Accepts(offers ...string) string {
func (ctx *Ctx) Accepts(offers ...string) (offer string) {
if len(offers) == 0 {
return ""
}
@ -136,8 +125,8 @@ func (ctx *Ctx) Accepts(offers ...string) string {
}
specs := strings.Split(h, ",")
for _, offer := range offers {
mimetype := getType(offer)
for _, value := range offers {
mimetype := getType(value)
// if mimetype != "" {
// mimetype = strings.Split(mimetype, ";")[0]
// } else {
@ -146,16 +135,16 @@ func (ctx *Ctx) Accepts(offers ...string) string {
for _, spec := range specs {
spec = strings.TrimSpace(spec)
if strings.HasPrefix(spec, "*/*") {
return offer
return value
}
if strings.HasPrefix(spec, mimetype) {
return offer
return value
}
if strings.Contains(spec, "/*") {
if strings.HasPrefix(spec, strings.Split(mimetype, "/")[0]) {
return offer
return value
}
}
}
@ -164,7 +153,7 @@ func (ctx *Ctx) Accepts(offers ...string) string {
}
// AcceptsCharsets : https://fiber.wiki/context#acceptscharsets
func (ctx *Ctx) AcceptsCharsets(offers ...string) string {
func (ctx *Ctx) AcceptsCharsets(offers ...string) (offer string) {
if len(offers) == 0 {
return ""
}
@ -175,14 +164,14 @@ func (ctx *Ctx) AcceptsCharsets(offers ...string) string {
}
specs := strings.Split(h, ",")
for _, offer := range offers {
for _, value := range offers {
for _, spec := range specs {
spec = strings.TrimSpace(spec)
if strings.HasPrefix(spec, "*") {
return offer
return value
}
if strings.HasPrefix(spec, offer) {
return offer
if strings.HasPrefix(spec, value) {
return value
}
}
}
@ -190,7 +179,7 @@ func (ctx *Ctx) AcceptsCharsets(offers ...string) string {
}
// AcceptsEncodings : https://fiber.wiki/context#acceptsencodings
func (ctx *Ctx) AcceptsEncodings(offers ...string) string {
func (ctx *Ctx) AcceptsEncodings(offers ...string) (offer string) {
if len(offers) == 0 {
return ""
}
@ -201,14 +190,14 @@ func (ctx *Ctx) AcceptsEncodings(offers ...string) string {
}
specs := strings.Split(h, ",")
for _, offer := range offers {
for _, value := range offers {
for _, spec := range specs {
spec = strings.TrimSpace(spec)
if strings.HasPrefix(spec, "*") {
return offer
return value
}
if strings.HasPrefix(spec, offer) {
return offer
if strings.HasPrefix(spec, value) {
return value
}
}
}
@ -216,7 +205,7 @@ func (ctx *Ctx) AcceptsEncodings(offers ...string) string {
}
// AcceptsLanguages : https://fiber.wiki/context#acceptslanguages
func (ctx *Ctx) AcceptsLanguages(offers ...string) string {
func (ctx *Ctx) AcceptsLanguages(offers ...string) (offer string) {
if len(offers) == 0 {
return ""
}
@ -226,14 +215,14 @@ func (ctx *Ctx) AcceptsLanguages(offers ...string) string {
}
specs := strings.Split(h, ",")
for _, offer := range offers {
for _, value := range offers {
for _, spec := range specs {
spec = strings.TrimSpace(spec)
if strings.HasPrefix(spec, "*") {
return offer
return value
}
if strings.HasPrefix(spec, offer) {
return offer
if strings.HasPrefix(spec, value) {
return value
}
}
}
@ -273,38 +262,29 @@ func (ctx *Ctx) BaseURL() string {
}
// Body : https://fiber.wiki/context#body
func (ctx *Ctx) Body(args ...interface{}) string {
if len(args) == 0 {
func (ctx *Ctx) Body(key ...string) string {
// Return request body
if len(key) == 0 {
return getString(ctx.Fasthttp.Request.Body())
}
if len(args) == 1 {
switch arg := args[0].(type) {
case string:
return getString(ctx.Fasthttp.Request.PostArgs().Peek(arg))
case []byte:
return getString(ctx.Fasthttp.Request.PostArgs().PeekBytes(arg))
case func(string, string):
ctx.Fasthttp.Request.PostArgs().VisitAll(func(k []byte, v []byte) {
arg(getString(k), getString(v))
})
default:
return getString(ctx.Fasthttp.Request.Body())
}
// Return post value by key
if len(key) > 0 {
return getString(ctx.Fasthttp.Request.PostArgs().Peek(key[0]))
}
return ""
}
// BodyParser : https://fiber.wiki/context#bodyparser
func (ctx *Ctx) BodyParser(v interface{}) error {
func (ctx *Ctx) BodyParser(out interface{}) error {
// TODO : Query Params
ctype := getString(ctx.Fasthttp.Request.Header.ContentType())
// application/json
if strings.HasPrefix(ctype, MIMEApplicationJSON) {
return jsoniter.Unmarshal(ctx.Fasthttp.Request.Body(), v)
return jsoniter.Unmarshal(ctx.Fasthttp.Request.Body(), out)
}
// application/xml text/xml
if strings.HasPrefix(ctype, MIMEApplicationXML) || strings.HasPrefix(ctype, MIMETextXML) {
return xml.Unmarshal(ctx.Fasthttp.Request.Body(), v)
return xml.Unmarshal(ctx.Fasthttp.Request.Body(), out)
}
// application/x-www-form-urlencoded
if strings.HasPrefix(ctype, MIMEApplicationForm) {
@ -312,7 +292,7 @@ func (ctx *Ctx) BodyParser(v interface{}) error {
if err != nil {
return err
}
return schemaDecoder.Decode(v, data)
return schemaDecoder.Decode(out, data)
}
// multipart/form-data
if strings.HasPrefix(ctype, MIMEMultipartForm) {
@ -320,18 +300,18 @@ func (ctx *Ctx) BodyParser(v interface{}) error {
if err != nil {
return err
}
return schemaDecoder.Decode(v, data.Value)
return schemaDecoder.Decode(out, data.Value)
}
return fmt.Errorf("cannot parse content-type: %v", ctype)
return fmt.Errorf("BodyParser: cannot parse content-type: %v", ctype)
}
// ClearCookie : https://fiber.wiki/context#clearcookie
func (ctx *Ctx) ClearCookie(name ...string) {
if len(name) > 0 {
for i := range name {
func (ctx *Ctx) ClearCookie(key ...string) {
if len(key) > 0 {
for i := range key {
//ctx.Fasthttp.Request.Header.DelAllCookies()
ctx.Fasthttp.Response.Header.DelClientCookie(name[i])
ctx.Fasthttp.Response.Header.DelClientCookie(key[i])
}
return
}
@ -342,75 +322,24 @@ func (ctx *Ctx) ClearCookie(name ...string) {
}
// Cookie : https://fiber.wiki/context#cookie
func (ctx *Ctx) Cookie(key, value string, options ...interface{}) {
cook := &fasthttp.Cookie{}
cook.SetKey(key)
cook.SetValue(value)
if len(options) > 0 {
switch opt := options[0].(type) {
case *Cookie:
if opt.Expire > 0 {
cook.SetExpire(time.Unix(int64(opt.Expire), 0))
}
if opt.MaxAge > 0 {
cook.SetMaxAge(opt.MaxAge)
}
if opt.Domain != "" {
cook.SetDomain(opt.Domain)
}
if opt.Path != "" {
cook.SetPath(opt.Path)
}
if opt.HTTPOnly {
cook.SetHTTPOnly(opt.HTTPOnly)
}
if opt.Secure {
cook.SetSecure(opt.Secure)
}
if opt.SameSite != "" {
sameSite := fasthttp.CookieSameSiteDefaultMode
if strings.EqualFold(opt.SameSite, "lax") {
sameSite = fasthttp.CookieSameSiteLaxMode
} else if strings.EqualFold(opt.SameSite, "strict") {
sameSite = fasthttp.CookieSameSiteStrictMode
} else if strings.EqualFold(opt.SameSite, "none") {
sameSite = fasthttp.CookieSameSiteNoneMode
}
// } else {
// sameSite = fasthttp.CookieSameSiteDisabled
// }
cook.SetSameSite(sameSite)
}
default:
log.Println("Cookie: Invalid &Cookie{} struct")
}
}
ctx.Fasthttp.Response.Header.SetCookie(cook)
func (ctx *Ctx) Cookie(cookie *Cookie) {
fcookie := &fasthttp.Cookie{}
fcookie.SetKey(cookie.Name)
fcookie.SetValue(cookie.Value)
fcookie.SetPath(cookie.Path)
fcookie.SetDomain(cookie.Domain)
fcookie.SetExpire(cookie.Expires)
fcookie.SetSecure(cookie.Secure)
fcookie.SetHTTPOnly(cookie.HTTPOnly)
ctx.Fasthttp.Response.Header.SetCookie(fcookie)
}
// Cookies : https://fiber.wiki/context#cookies
func (ctx *Ctx) Cookies(args ...interface{}) string {
if len(args) == 0 {
func (ctx *Ctx) Cookies(key ...string) (value string) {
if len(key) == 0 {
return ctx.Get(fasthttp.HeaderCookie)
}
switch arg := args[0].(type) {
case string:
return getString(ctx.Fasthttp.Request.Header.Cookie(arg))
case []byte:
return getString(ctx.Fasthttp.Request.Header.CookieBytes(arg))
case func(string, string):
ctx.Fasthttp.Request.Header.VisitAllCookie(func(k, v []byte) {
arg(getString(k), getString(v))
})
default:
return ctx.Get(fasthttp.HeaderCookie)
}
return ""
return getString(ctx.Fasthttp.Request.Header.Cookie(key[0]))
}
// Download : https://fiber.wiki/context#download
@ -431,30 +360,27 @@ func (ctx *Ctx) Error() error {
}
// Format : https://fiber.wiki/context#format
func (ctx *Ctx) Format(args ...interface{}) {
var body string
func (ctx *Ctx) Format(body interface{}) {
var b string
accept := ctx.Accepts("html", "json")
for i := range args {
switch arg := args[i].(type) {
case string:
body = arg
case []byte:
body = getString(arg)
default:
body = fmt.Sprintf("%v", arg)
}
switch accept {
case "html":
ctx.SendString("<p>" + body + "</p>")
case "json":
if err := ctx.JSON(body); err != nil {
log.Println("Format: error serializing json ", err)
}
default:
ctx.SendString(body)
switch val := body.(type) {
case string:
b = val
case []byte:
b = getString(val)
default:
b = fmt.Sprintf("%v", val)
}
switch accept {
case "html":
ctx.SendString("<p>" + b + "</p>")
case "json":
if err := ctx.JSON(body); err != nil {
log.Println("Format: error serializing json ", err)
}
default:
ctx.SendString(b)
}
}
@ -464,7 +390,7 @@ func (ctx *Ctx) FormFile(key string) (*multipart.FileHeader, error) {
}
// FormValue : https://fiber.wiki/context#formvalue
func (ctx *Ctx) FormValue(key string) string {
func (ctx *Ctx) FormValue(key string) (value string) {
return getString(ctx.Fasthttp.FormValue(key))
}
@ -474,7 +400,7 @@ func (ctx *Ctx) Fresh() bool {
}
// Get : https://fiber.wiki/context#get
func (ctx *Ctx) Get(key string) string {
func (ctx *Ctx) Get(key string) (value string) {
if key == "referrer" {
key = "referer"
}
@ -501,26 +427,26 @@ func (ctx *Ctx) IPs() []string {
}
// Is : https://fiber.wiki/context#is
func (ctx *Ctx) Is(ext string) bool {
if ext[0] != '.' {
ext = "." + ext
func (ctx *Ctx) Is(extension string) (match bool) {
if extension[0] != '.' {
extension = "." + extension
}
exts, _ := mime.ExtensionsByType(ctx.Get(fasthttp.HeaderContentType))
if len(exts) > 0 {
for _, item := range exts {
if item == ext {
if item == extension {
return true
}
}
}
return false
return
}
// JSON : https://fiber.wiki/context#json
func (ctx *Ctx) JSON(v interface{}) error {
func (ctx *Ctx) JSON(json interface{}) error {
ctx.Fasthttp.Response.Header.SetContentType(MIMEApplicationJSON)
raw, err := jsoniter.Marshal(&v)
raw, err := jsoniter.Marshal(&json)
if err != nil {
ctx.Fasthttp.Response.SetBodyString("")
return err
@ -531,15 +457,15 @@ func (ctx *Ctx) JSON(v interface{}) error {
}
// JSONP : https://fiber.wiki/context#jsonp
func (ctx *Ctx) JSONP(v interface{}, cb ...string) error {
raw, err := jsoniter.Marshal(&v)
func (ctx *Ctx) JSONP(json interface{}, callback ...string) error {
raw, err := jsoniter.Marshal(&json)
if err != nil {
return err
}
str := "callback("
if len(cb) > 0 {
str = cb[0] + "("
if len(callback) > 0 {
str = callback[0] + "("
}
str += getString(raw) + ");"
@ -568,12 +494,12 @@ func (ctx *Ctx) Links(link ...string) {
}
// Locals : https://fiber.wiki/context#locals
func (ctx *Ctx) Locals(key string, val ...interface{}) interface{} {
if len(val) == 0 {
func (ctx *Ctx) Locals(key string, value ...interface{}) (val interface{}) {
if len(value) == 0 {
return ctx.Fasthttp.UserValue(key)
}
ctx.Fasthttp.SetUserValue(key, val[0])
return nil
ctx.Fasthttp.SetUserValue(key, value[0])
return value[0]
}
// Location : https://fiber.wiki/context#location
@ -608,16 +534,16 @@ func (ctx *Ctx) OriginalURL() string {
}
// Params : https://fiber.wiki/context#params
func (ctx *Ctx) Params(key string) string {
func (ctx *Ctx) Params(key string) (value string) {
if ctx.params == nil {
return ""
return
}
for i := 0; i < len(*ctx.params); i++ {
if (*ctx.params)[i] == key {
return ctx.values[i]
}
}
return ""
return
}
// Path : https://fiber.wiki/context#path
@ -634,7 +560,7 @@ func (ctx *Ctx) Protocol() string {
}
// Query : https://fiber.wiki/context#query
func (ctx *Ctx) Query(key string) string {
func (ctx *Ctx) Query(key string) (value string) {
return getString(ctx.Fasthttp.QueryArgs().Peek(key))
}
@ -642,7 +568,7 @@ func (ctx *Ctx) Query(key string) string {
func (ctx *Ctx) Range() {
// https://expressjs.com/en/api.html#req.range
// https://github.com/jshttp/range-parser/blob/master/index.js
// r := ctx.Fasthttp.Request.Header.Peek(fasthttp.HeaderRange)
// r := ctx.Fasthttp.Request.Header.Peek(HeaderRange)
// *magic*
}
@ -658,18 +584,18 @@ func (ctx *Ctx) Redirect(path string, status ...int) {
}
// Render : https://fiber.wiki/context#render
func (ctx *Ctx) Render(file string, data interface{}, e ...string) error {
func (ctx *Ctx) Render(file string, bind interface{}, engine ...string) error {
var err error
var raw []byte
var html string
var engine string
var e string
if len(e) > 0 {
engine = e[0]
if len(engine) > 0 {
e = engine[0]
} else if ctx.app.Settings.ViewEngine != "" {
engine = ctx.app.Settings.ViewEngine
e = ctx.app.Settings.ViewEngine
} else {
engine = filepath.Ext(file)[1:]
e = filepath.Ext(file)[1:]
}
if ctx.app.Settings.ViewFolder != "" {
file = filepath.Join(ctx.app.Settings.ViewFolder, file)
@ -681,53 +607,27 @@ func (ctx *Ctx) Render(file string, data interface{}, e ...string) error {
return err
}
switch engine {
switch e {
case "amber": // https://github.com/eknkc/amber
var buf bytes.Buffer
var tmpl *template.Template
if tmpl, err = amber.Compile(getString(raw), amber.DefaultOptions); err != nil {
if html, err = template.Amber(getString(raw), bind); err != nil {
return err
}
if err = tmpl.Execute(&buf, data); err != nil {
return err
}
html = buf.String()
case "handlebars": // https://github.com/aymerick/raymond
if html, err = handlebars.Render(getString(raw), data); err != nil {
if html, err = template.Handlebars(getString(raw), bind); err != nil {
return err
}
case "mustache": // https://github.com/cbroglie/mustache
if html, err = mustache.Render(getString(raw), data); err != nil {
if html, err = template.Mustache(getString(raw), bind); err != nil {
return err
}
case "pug": // https://github.com/Joker/jade
var parsed string
var buf bytes.Buffer
var tmpl *template.Template
if parsed, err = pug.Parse("", raw); err != nil {
if html, err = template.Pug(getString(raw), bind); err != nil {
return err
}
if tmpl, err = template.New("").Parse(parsed); err != nil {
return err
}
if err = tmpl.Execute(&buf, data); err != nil {
return err
}
html = buf.String()
default: // https://golang.org/pkg/text/template/
var buf bytes.Buffer
var tmpl *template.Template
if tmpl, err = template.New("").Parse(getString(raw)); err != nil {
if html, err = template.HTML(getString(raw), bind); err != nil {
return err
}
if err = tmpl.Execute(&buf, data); err != nil {
return err
}
html = buf.String()
}
ctx.Set("Content-Type", "text/html")
ctx.SendString(html)
@ -740,8 +640,8 @@ func (ctx *Ctx) Route() *Route {
}
// SaveFile : https://fiber.wiki/context#secure
func (ctx *Ctx) SaveFile(fh *multipart.FileHeader, path string) error {
return fasthttp.SaveMultipartFile(fh, path)
func (ctx *Ctx) SaveFile(fileheader *multipart.FileHeader, path string) error {
return fasthttp.SaveMultipartFile(fileheader, path)
}
// Secure : https://fiber.wiki/context#secure
@ -750,18 +650,19 @@ func (ctx *Ctx) Secure() bool {
}
// Send : https://fiber.wiki/context#send
func (ctx *Ctx) Send(args ...interface{}) {
if len(args) == 0 {
return
}
switch body := args[0].(type) {
case string:
ctx.Fasthttp.Response.SetBodyString(body)
case []byte:
ctx.Fasthttp.Response.SetBodyString(getString(body))
default:
ctx.Fasthttp.Response.SetBodyString(fmt.Sprintf("%v", body))
func (ctx *Ctx) Send(bodies ...interface{}) {
// if len(bodies) > 0 {
// ctx.Fasthttp.Response.SetBodyString("")
// }
for i := range bodies {
switch body := bodies[i].(type) {
case string:
ctx.Fasthttp.Response.AppendBodyString(body)
case []byte:
ctx.Fasthttp.Response.AppendBodyString(getString(body))
default:
ctx.Fasthttp.Response.AppendBodyString(fmt.Sprintf("%v", body))
}
}
}
@ -803,19 +704,14 @@ func (ctx *Ctx) Set(key string, val string) {
}
// Subdomains : https://fiber.wiki/context#subdomains
func (ctx *Ctx) Subdomains(offset ...int) (subs []string) {
func (ctx *Ctx) Subdomains(offset ...int) []string {
o := 2
if len(offset) > 0 {
o = offset[0]
}
subs = strings.Split(ctx.Hostname(), ".")
subs = subs[:len(subs)-o]
return subs
}
// SignedCookies : https://fiber.wiki/context#signedcookies
func (ctx *Ctx) SignedCookies() {
subdomains := strings.Split(ctx.Hostname(), ".")
subdomains = subdomains[:len(subdomains)-o]
return subdomains
}
// Stale : https://fiber.wiki/context#stale
@ -854,9 +750,9 @@ func (ctx *Ctx) Vary(fields ...string) {
}
// Write : https://fiber.wiki/context#write
func (ctx *Ctx) Write(args ...interface{}) {
for i := range args {
switch body := args[i].(type) {
func (ctx *Ctx) Write(bodies ...interface{}) {
for i := range bodies {
switch body := bodies[i].(type) {
case string:
ctx.Fasthttp.Response.AppendBodyString(body)
case []byte:

View File

@ -15,6 +15,7 @@ import (
"strconv"
"strings"
"testing"
"time"
)
func Test_Accepts(t *testing.T) {
@ -129,7 +130,6 @@ func Test_BaseURL(t *testing.T) {
func Test_Body(t *testing.T) {
app := New()
app.Post("/test", func(c *Ctx) {
c.Body(1)
expect := "john=doe"
result := c.Body()
if result != expect {
@ -140,21 +140,6 @@ func Test_Body(t *testing.T) {
if result != expect {
t.Fatalf(`%s: Expecting %s, got %s`, t.Name(), expect, result)
}
expect = "doe"
result = c.Body([]byte("john"))
if result != expect {
t.Fatalf(`%s: Expecting %s, got %s`, t.Name(), expect, result)
}
c.Body(func(k, v string) {
expect = "john"
if k != "john" {
t.Fatalf(`%s: Expecting %s, got %s`, t.Name(), expect, k)
}
expect = "doe"
if v != "doe" {
t.Fatalf(`%s: Expecting %s, got %s`, t.Name(), expect, v)
}
})
})
data := url.Values{}
data.Set("john", "doe")
@ -196,7 +181,6 @@ func Test_BodyParser(t *testing.T) {
func Test_Cookies(t *testing.T) {
app := New()
app.Get("/test", func(c *Ctx) {
c.Cookies(1)
expect := "john=doe"
result := c.Cookies()
if result != expect {
@ -207,21 +191,6 @@ func Test_Cookies(t *testing.T) {
if result != expect {
t.Fatalf(`%s: Expecting %s, got %s`, t.Name(), expect, result)
}
expect = "doe"
result = c.Cookies([]byte("john"))
if result != expect {
t.Fatalf(`%s: Expecting %s, got %s`, t.Name(), expect, result)
}
c.Cookies(func(k, v string) {
expect = "john"
if k != "john" {
t.Fatalf(`%s: Expecting %s, got %s`, t.Name(), expect, k)
}
expect = "doe"
if v != "doe" {
t.Fatalf(`%s: Expecting %s, got %s`, t.Name(), expect, v)
}
})
})
req, _ := http.NewRequest("GET", "/test", nil)
@ -621,20 +590,6 @@ func Test_Secure(t *testing.T) {
t.Fatalf(`%s: StatusCode %v`, t.Name(), resp.StatusCode)
}
}
func Test_SignedCookies(t *testing.T) {
app := New()
app.Get("/test", func(c *Ctx) {
c.SignedCookies()
})
req, _ := http.NewRequest("GET", "/test", nil)
resp, err := app.Test(req)
if err != nil {
t.Fatalf(`%s: %s`, t.Name(), err)
}
if resp.StatusCode != 200 {
t.Fatalf(`%s: StatusCode %v`, t.Name(), resp.StatusCode)
}
}
func Test_Stale(t *testing.T) {
app := New()
app.Get("/test", func(c *Ctx) {
@ -758,16 +713,16 @@ func Test_ClearCookie(t *testing.T) {
}
func Test_Cookie(t *testing.T) {
app := New()
expire := time.Now().Add(24 * time.Hour)
var dst []byte
dst = expire.In(time.UTC).AppendFormat(dst, time.RFC1123)
httpdate := strings.Replace(string(dst), "UTC", "GMT", -1)
app.Get("/test", func(c *Ctx) {
options := &Cookie{
MaxAge: 60,
Domain: "example.com",
Path: "/",
HTTPOnly: true,
Secure: false,
SameSite: "lax",
}
c.Cookie("name", "john", options)
cookie := new(Cookie)
cookie.Name = "username"
cookie.Value = "jon"
cookie.Expires = expire
c.Cookie(cookie)
})
req, _ := http.NewRequest("GET", "http://example.com/test", nil)
resp, err := app.Test(req)
@ -777,8 +732,8 @@ func Test_Cookie(t *testing.T) {
if resp.StatusCode != 200 {
t.Fatalf(`%s: StatusCode %v`, t.Name(), resp.StatusCode)
}
if !strings.Contains(resp.Header.Get("Set-Cookie"), "name=john; max-age=60; domain=example.com; path=/; HttpOnly; SameSite=Lax") {
t.Fatalf(`%s: Expecting %s`, t.Name(), "name=john; max-age=60; domain=example.com; path=/; HttpOnly; SameSite=Lax")
if !strings.Contains(resp.Header.Get("Set-Cookie"), "username=jon; expires="+string(httpdate)+"; path=/") {
t.Fatalf(`%s: Expecting %s`, t.Name(), "username=jon; expires="+string(httpdate)+"; path=/")
}
}
func Test_Download(t *testing.T) {

3
go.mod
View File

@ -3,8 +3,9 @@ module github.com/gofiber/fiber
go 1.11
require (
github.com/fasthttp/websocket v1.4.1
github.com/gorilla/schema v1.1.0
github.com/gofiber/template v1.0.0
github.com/json-iterator/go v1.1.9
github.com/valyala/fasthttp v1.9.0
github.com/fasthttp/websocket v1.4.2
)

15
go.sum
View File

@ -1,7 +1,6 @@
github.com/Joker/hpp v0.0.0-20180418125244-6893e659854a/go.mod h1:MzD2WMdSxvbHw5fM/OXOFily/lipJWRc9C1px0Mt0ZE=
github.com/Joker/jade v1.0.0 h1:lOCEPvTAtWfLpSZYMOv/g44MGQFAolbKh2khHHGu0Kc=
github.com/Joker/jade v1.0.0/go.mod h1:efZIdO0py/LtcJRSa/j2WEklMSAw84WV0zZVMxNToB8=
github.com/aymerick/raymond v1.1.0 h1:phuNN2s67eI/HtO8CrvqFcdR2JP+BtkGJZ9n692Hr2Y=
github.com/aymerick/raymond v2.0.2+incompatible h1:VEp3GpgdAnv9B2GFyTvqgcKvY+mfKMjPOA3SbKLtnU0=
github.com/aymerick/raymond v2.0.2+incompatible/go.mod h1:osfaiScAUVup+UC9Nfq76eWqDhXlp+4UYaA8uhTBO6g=
github.com/cbroglie/mustache v1.0.1 h1:ivMg8MguXq/rrz2eu3tw6g3b16+PQhoTn6EZAhst2mw=
@ -10,17 +9,17 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/eknkc/amber v0.0.0-20171010120322-cdade1c07385 h1:clC1lXBpe2kTj2VHdaIu9ajZQe4kcEY9j0NsnDDBZ3o=
github.com/eknkc/amber v0.0.0-20171010120322-cdade1c07385/go.mod h1:0vRUJqYpeSZifjYj7uP3BG/gKcuzL9xWVV/Y+cK33KM=
github.com/fasthttp/websocket v1.4.1 h1:fisgNMCNCbIPM5GRRRTAckRrynbSzf76fevcJYJYnSM=
github.com/fasthttp/websocket v1.4.1/go.mod h1:toetUvZ3KISxtZERe0wzPPpnaN8GZCKHCowWctwA50o=
github.com/fasthttp/websocket v1.4.2 h1:AU/zSiIIAuJjBMf5o+vO0syGOnEfvZRu40xIhW/3RuM=
github.com/fasthttp/websocket v1.4.2/go.mod h1:smsv/h4PBEBaU0XDTY5UwJTpZv69fQ0FfcLJr21mA6Y=
github.com/gofiber/template v1.0.0 h1:Vf4Fby9zUWVQyY2y69KKyRHsEYlIE+Pxb25M+jiaEL0=
github.com/gofiber/template v1.0.0/go.mod h1:+bij+R0NI6urTg2jtQvPj5wb2uWMxW9eYGsAN3QhnP0=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/gorilla/schema v1.1.0 h1:CamqUDOFUBqzrvxuz2vEwo8+SUdwsluFh7IlzJh30LY=
github.com/gorilla/schema v1.1.0/go.mod h1:kgLaKoK1FELgZqMAVxx/5cbj0kT+57qxUrAlIO2eleU=
github.com/json-iterator/go v1.1.9 h1:9yzud/Ht36ygwatGx56VwCZtlI/2AD15T1X2sjSuGns=
github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/klauspost/compress v1.4.0/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
github.com/klauspost/compress v1.8.2 h1:Bx0qjetmNjdFXASH02NSAREKpiaDwkO1DRZ3dV2KCcs=
github.com/klauspost/compress v1.8.2/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
github.com/klauspost/cpuid v0.0.0-20180405133222-e7e905edc00e/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
github.com/klauspost/cpuid v1.2.1 h1:vJi+O/nMdFt0vqm8NZBI6wzALWdA2X+egi0ogNyrC/w=
github.com/klauspost/cpuid v1.2.1/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 h1:ZqeYNhU3OHLH3mGKHDcjJRFFRrJa6eAM5H+CtDdOsPc=
@ -28,18 +27,16 @@ github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJ
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742 h1:Esafd1046DLDQ0W1YjYsBW+p8U2u7vzgW2SQVmlNazg=
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/savsgio/gotils v0.0.0-20190714152828-365999d0a274 h1:F52t1X2ziOrMcQMVHo8ZxwOrDTMAq6MrlKtL1Atu2wU=
github.com/savsgio/gotils v0.0.0-20190714152828-365999d0a274/go.mod h1:w803/Fg1m0hrp1ZT9KNfQe4E4+WOMMFLcgzPvOcye10=
github.com/savsgio/gotils v0.0.0-20200117113501-90175b0fbe3f h1:PgA+Olipyj258EIEYnpFFONrrCcAIWNUNoFhUfMqAGY=
github.com/savsgio/gotils v0.0.0-20200117113501-90175b0fbe3f/go.mod h1:lHhJedqxCoHN+zMtwGNTXWmF0u9Jt363FYRhV6g0CdY=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
github.com/valyala/fasthttp v1.4.0/go.mod h1:4vX61m6KN+xDduDNwXrhIAVZaZaZiQ1luJk8LWSxF3s=
github.com/valyala/fasthttp v1.9.0 h1:hNpmUdy/+ZXYpGy0OBfm7K0UQTzb73W0T0U4iJIVrMw=
github.com/valyala/fasthttp v1.9.0/go.mod h1:FstJa9V+Pj9vQ7OJie2qMHdwemEDaDiSdBnvPM1Su9w=
github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/net v0.0.0-20180911220305-26e67e76b6c3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=

View File

@ -4,7 +4,10 @@
package fiber
import "strings"
import (
"net/http"
"strings"
)
// Group ...
type Group struct {
@ -12,10 +15,10 @@ type Group struct {
app *App
}
// Group ...
func (app *App) Group(prefix string, args ...interface{}) *Group {
if len(args) > 0 {
app.register("USE", prefix, args...)
// Group : https://fiber.wiki/application#group
func (app *App) Group(prefix string, handlers ...interface{}) *Group {
if len(handlers) > 0 {
app.register("USE", prefix, handlers...)
}
return &Group{
prefix: prefix,
@ -23,102 +26,102 @@ func (app *App) Group(prefix string, args ...interface{}) *Group {
}
}
// Group ...
func (grp *Group) Group(newPrfx string, args ...interface{}) *Group {
var prefix = grp.prefix
if len(newPrfx) > 0 && newPrfx[0] != '/' && newPrfx[0] != '*' {
newPrfx = "/" + newPrfx
// Group : https://fiber.wiki/application#group
func (grp *Group) Group(prefix string, handlers ...interface{}) *Group {
var oldPrefix = grp.prefix
if len(prefix) > 0 && prefix[0] != '/' && prefix[0] != '*' {
prefix = "/" + prefix
}
// When grouping, always remove single slash
if len(prefix) > 0 && newPrfx == "/" {
newPrfx = ""
if len(oldPrefix) > 0 && prefix == "/" {
prefix = ""
}
// Prepent group prefix if exist
prefix = prefix + newPrfx
newPrefix := oldPrefix + prefix
// Clean path by removing double "//" => "/"
prefix = strings.Replace(prefix, "//", "/", -1)
if len(args) > 0 {
grp.app.register("USE", prefix, args...)
newPrefix = strings.Replace(newPrefix, "//", "/", -1)
if len(handlers) > 0 {
grp.app.register("USE", newPrefix, handlers...)
}
return &Group{
prefix: prefix,
prefix: newPrefix,
app: grp.app,
}
}
// Static ...
// Static : https://fiber.wiki/application#static
func (grp *Group) Static(args ...string) *Group {
grp.app.registerStatic(grp.prefix, args...)
return grp
}
// WebSocket ...
// WebSocket : https://fiber.wiki/application#websocket
func (grp *Group) WebSocket(args ...interface{}) *Group {
grp.app.register("GET", grp.prefix, args...)
grp.app.register(http.MethodGet, grp.prefix, args...)
return grp
}
// Connect ...
// Connect : https://fiber.wiki/application#http-methods
func (grp *Group) Connect(args ...interface{}) *Group {
grp.app.register("CONNECT", grp.prefix, args...)
grp.app.register(http.MethodConnect, grp.prefix, args...)
return grp
}
// Put ...
// Put : https://fiber.wiki/application#http-methods
func (grp *Group) Put(args ...interface{}) *Group {
grp.app.register("PUT", grp.prefix, args...)
grp.app.register(http.MethodPut, grp.prefix, args...)
return grp
}
// Post ...
// Post : https://fiber.wiki/application#http-methods
func (grp *Group) Post(args ...interface{}) *Group {
grp.app.register("POST", grp.prefix, args...)
grp.app.register(http.MethodPost, grp.prefix, args...)
return grp
}
// Delete ...
// Delete : https://fiber.wiki/application#http-methods
func (grp *Group) Delete(args ...interface{}) *Group {
grp.app.register("DELETE", grp.prefix, args...)
grp.app.register(http.MethodDelete, grp.prefix, args...)
return grp
}
// Head ...
// Head : https://fiber.wiki/application#http-methods
func (grp *Group) Head(args ...interface{}) *Group {
grp.app.register("HEAD", grp.prefix, args...)
grp.app.register(http.MethodHead, grp.prefix, args...)
return grp
}
// Patch ...
// Patch : https://fiber.wiki/application#http-methods
func (grp *Group) Patch(args ...interface{}) *Group {
grp.app.register("PATCH", grp.prefix, args...)
grp.app.register(http.MethodPatch, grp.prefix, args...)
return grp
}
// Options ...
// Options : https://fiber.wiki/application#http-methods
func (grp *Group) Options(args ...interface{}) *Group {
grp.app.register("OPTIONS", grp.prefix, args...)
grp.app.register(http.MethodOptions, grp.prefix, args...)
return grp
}
// Trace ...
// Trace : https://fiber.wiki/application#http-methods
func (grp *Group) Trace(args ...interface{}) *Group {
grp.app.register("TRACE", grp.prefix, args...)
grp.app.register(http.MethodTrace, grp.prefix, args...)
return grp
}
// Get ...
// Get : https://fiber.wiki/application#http-methods
func (grp *Group) Get(args ...interface{}) *Group {
grp.app.register("GET", grp.prefix, args...)
grp.app.register(http.MethodGet, grp.prefix, args...)
return grp
}
// All ...
// All : https://fiber.wiki/application#http-methods
func (grp *Group) All(args ...interface{}) *Group {
grp.app.register("ALL", grp.prefix, args...)
return grp
}
// Use ...
// Use : https://fiber.wiki/application#http-methods
func (grp *Group) Use(args ...interface{}) *Group {
grp.app.register("USE", grp.prefix, args...)
return grp

View File

@ -278,7 +278,11 @@ func (app *App) handler(fctx *fasthttp.RequestCtx) {
if app.recover != nil {
defer func() {
if r := recover(); r != nil {
ctx.error = fmt.Errorf("panic: %v", r)
err, ok := r.(error)
if !ok {
err = fmt.Errorf("%v", r)
}
ctx.error = err
app.recover(ctx)
}
}()

View File

@ -29,21 +29,6 @@ var socketUpgrade = websocket.FastHTTPUpgrader{
},
}
// MIME types
const (
MIMEApplicationJSON = "application/json"
MIMEApplicationJavaScript = "application/javascript"
MIMEApplicationXML = "application/xml"
MIMETextXML = "text/xml"
MIMEApplicationForm = "application/x-www-form-urlencoded"
MIMEApplicationProtobuf = "application/protobuf"
MIMEApplicationMsgpack = "application/msgpack"
MIMETextHTML = "text/html"
MIMETextPlain = "text/plain"
MIMEMultipartForm = "multipart/form-data"
MIMEOctetStream = "application/octet-stream"
)
func getParams(path string) (params []string) {
if len(path) < 1 {
return
@ -125,7 +110,7 @@ func getStatus(status int) (msg string) {
// #nosec G103
// getString converts byte slice to a string without memory allocation.
// See https://groups.google.com/forum/#!msg/Golang-Nuts/ENgbUzYvCuU/90yGx7GUAgAJ .
func getString(b []byte) string {
var getString = func(b []byte) string {
return *(*string)(unsafe.Pointer(&b))
}
@ -157,6 +142,21 @@ func (c *testConn) SetDeadline(t time.Time) error { return nil }
func (c *testConn) SetReadDeadline(t time.Time) error { return nil }
func (c *testConn) SetWriteDeadline(t time.Time) error { return nil }
// MIME types
const (
MIMEApplicationJSON = "application/json"
MIMEApplicationJavaScript = "application/javascript"
MIMEApplicationXML = "application/xml"
MIMETextXML = "text/xml"
MIMEApplicationForm = "application/x-www-form-urlencoded"
MIMEApplicationProtobuf = "application/protobuf"
MIMEApplicationMsgpack = "application/msgpack"
MIMETextHTML = "text/html"
MIMETextPlain = "text/plain"
MIMEMultipartForm = "multipart/form-data"
MIMEOctetStream = "application/octet-stream"
)
// HTTP status codes
var statusMessage = map[int]string{
100: "Continue",
@ -221,7 +221,7 @@ var statusMessage = map[int]string{
511: "Network Authentication Required",
}
// MIME types for file extensions
// File extensions MIME types
var extensionMIME = map[string]string{
"html": "text/html",
"htm": "text/html",