Added ServeFile and ServeFileUncompressed to be on par with net/http

This commit is contained in:
Aliaksandr Valialkin
2016-01-17 23:12:38 +02:00
parent 7320fe3bd7
commit 764a74e2ec
4 changed files with 119 additions and 6 deletions
+1 -1
View File
@@ -308,7 +308,7 @@ fastttp.ListenAndServe(":80", m)
* http.Error() -> [ctx.Error()](https://godoc.org/github.com/valyala/fasthttp#RequestCtx.Error)
* http.FileServer() -> [fasthttp.FSHandler()](https://godoc.org/github.com/valyala/fasthttp#FSHandler),
[fasthttp.FS](https://godoc.org/github.com/valyala/fasthttp#FS)
* http.ServeFile() -> [ctx.SendFile()](https://godoc.org/github.com/valyala/fasthttp#RequestCtx.SendFile)
* http.ServeFile() -> [ctx.ServeFile()](https://godoc.org/github.com/valyala/fasthttp#ServeFile)
* http.Redirect() -> [ctx.Redirect()](https://godoc.org/github.com/valyala/fasthttp#RequestCtx.Redirect)
* http.NotFound() -> [ctx.NotFound()](https://godoc.org/github.com/valyala/fasthttp#RequestCtx.NotFound)
* http.StripPrefix() -> [fasthttp.PathRewriteFunc](https://godoc.org/github.com/valyala/fasthttp#PathRewriteFunc)
+58 -5
View File
@@ -18,6 +18,59 @@ import (
"time"
)
// ServeFileUncompressed returns HTTP response containing file contents
// from the given path.
//
// Directory contents is returned if path points to directory.
//
// ServeFile may be used for saving network traffic when serving files
// with good compression ratio.
//
// See also RequestCtx.SendFile.
func ServeFileUncompressed(ctx *RequestCtx, path string) {
ctx.Request.Header.DelBytes(strAcceptEncoding)
ServeFile(ctx, path)
}
// ServeFile returns HTTP response containing compressed file contents
// from the given path.
//
// HTTP response may contain uncompressed file contents in the following cases:
//
// * Missing 'Accept-Encoding: gzip' request header.
// * No write access to directory containing the file.
//
// Directory contents is returned if path points to directory.
//
// Use ServeFileUncompressed is you don't need serving compressed file contents.
//
// See also RequestCtx.SendFile.
func ServeFile(ctx *RequestCtx, path string) {
rootFSOnce.Do(func() {
rootFSHandler = rootFS.NewRequestHandler()
})
if len(path) == 0 || path[0] != '/' {
// extend relative path to absolute path
var err error
if path, err = filepath.Abs(path); err != nil {
ctx.Logger().Printf("cannot resolve path %q to absolute file path: %s", path, err)
}
}
ctx.Request.SetRequestURI(path)
rootFSHandler(ctx)
}
var (
rootFSOnce sync.Once
rootFS = &FS{
Root: "/",
GenerateIndexPages: true,
Compress: true,
AcceptByteRange: true,
}
rootFSHandler RequestHandler
)
// PathRewriteFunc must return new request path based on arbitrary ctx
// info such as ctx.Path().
//
@@ -178,16 +231,16 @@ func (fs *FS) NewRequestHandler() RequestHandler {
root := fs.Root
// strip trailing slashes from the root path
for len(root) > 0 && root[len(root)-1] == '/' {
root = root[:len(root)-1]
}
// serve files from the current working directory if root is empty
if len(root) == 0 {
root = "."
}
// strip trailing slashes from the root path
for len(root) > 0 && root[len(root)-1] == '/' {
root = root[:len(root)-1]
}
cacheDuration := fs.CacheDuration
if cacheDuration <= 0 {
cacheDuration = FSHandlerCacheDuration
+58
View File
@@ -12,6 +12,64 @@ import (
"time"
)
func TestFSServeFileCompressed(t *testing.T) {
var ctx RequestCtx
var req Request
req.SetRequestURI("http://foobar.com/baz")
req.Header.Set("Accept-Encoding", "gzip")
ctx.Init(&req, nil, nil)
ServeFile(&ctx, "fs.go")
var resp Response
s := ctx.Response.String()
br := bufio.NewReader(bytes.NewBufferString(s))
if err := resp.Read(br); err != nil {
t.Fatalf("unexpected error: %s", err)
}
if string(resp.Header.Peek("Content-Encoding")) != "gzip" {
t.Fatalf("Unexpected 'Content-Encoding' %q. Expecting %q", resp.Header.Peek("Content-Encoding"), "gzip")
}
body, err := resp.BodyGunzip()
if err != nil {
t.Fatalf("unexpected error: %s", err)
}
expectedBody, err := getFileContents("/fs.go")
if err != nil {
t.Fatalf("unexpected error: %s", err)
}
if !bytes.Equal(body, expectedBody) {
t.Fatalf("unexpected body %q. expecting %q", body, expectedBody)
}
}
func TestFSServeFileUncompressed(t *testing.T) {
var ctx RequestCtx
var req Request
req.SetRequestURI("http://foobar.com/baz")
ctx.Init(&req, nil, nil)
ServeFileUncompressed(&ctx, "fs.go")
var resp Response
s := ctx.Response.String()
br := bufio.NewReader(bytes.NewBufferString(s))
if err := resp.Read(br); err != nil {
t.Fatalf("unexpected error: %s", err)
}
body := resp.Body()
expectedBody, err := getFileContents("/fs.go")
if err != nil {
t.Fatalf("unexpected error: %s", err)
}
if !bytes.Equal(body, expectedBody) {
t.Fatalf("unexpected body %q. expecting %q", body, expectedBody)
}
}
func TestFSByteRangeConcurrent(t *testing.T) {
fs := &FS{
Root: ".",
+2
View File
@@ -810,6 +810,8 @@ func (ctx *RequestCtx) ResetBody() {
// Note that SendFile doesn't set Content-Type for the response body,
// so set it yourself with SetContentType() before returning
// from RequestHandler.
//
// See also ServeFile, FSHandler and FS.
func (ctx *RequestCtx) SendFile(path string) error {
ifModStr := ctx.Request.Header.peek(strIfModifiedSince)
if len(ifModStr) > 0 {