mirror of
https://github.com/valyala/fasthttp.git
synced 2026-06-18 16:37:38 +03:00
Added ServeFile and ServeFileUncompressed to be on par with net/http
This commit is contained in:
@@ -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)
|
||||
|
||||
@@ -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
@@ -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: ".",
|
||||
|
||||
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user