Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

📚 Doc: Clarify SendFile Docs #3172

Merged
merged 7 commits into from
Oct 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added .github/testdata/fs/img/fiberpng
Binary file not shown.
Binary file added .github/testdata/fs/img/fiberpng.jpeg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added .github/testdata/fs/img/fiberpng.notvalidext
Binary file not shown.
2 changes: 1 addition & 1 deletion app.go
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ type Config struct { //nolint:govet // Aligning the struct fields is not necessa
// Default: false
StrictRouting bool `json:"strict_routing"`

// When set to true, enables case sensitive routing.
// When set to true, enables case-sensitive routing.
// E.g. "/FoO" and "/foo" are treated as different routes.
// By default this is disabled and both "/FoO" and "/foo" will execute the same handler.
//
Expand Down
4 changes: 2 additions & 2 deletions app_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -451,9 +451,9 @@ func Test_App_Use_CaseSensitive(t *testing.T) {
require.NoError(t, err, "app.Test(req)")
require.Equal(t, StatusOK, resp.StatusCode, "Status code")

// check the detected path when the case insensitive recognition is activated
// check the detected path when the case-insensitive recognition is activated
app.config.CaseSensitive = false
// check the case sensitive feature
// check the case-sensitive feature
gaby marked this conversation as resolved.
Show resolved Hide resolved
resp, err = app.Test(httptest.NewRequest(MethodGet, "/AbC", nil))
require.NoError(t, err, "app.Test(req)")
require.Equal(t, StatusOK, resp.StatusCode, "Status code")
Expand Down
17 changes: 9 additions & 8 deletions ctx.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,29 +83,29 @@ type SendFile struct {
// You have to set Content-Encoding header to compress the file.
// Available compression methods are gzip, br, and zstd.
//
// Optional. Default value false
// Optional. Default: false
Compress bool `json:"compress"`

// When set to true, enables byte range requests.
//
// Optional. Default value false
// Optional. Default: false
ByteRange bool `json:"byte_range"`

// When set to true, enables direct download.
//
// Optional. Default: false.
// Optional. Default: false
Download bool `json:"download"`

// Expiration duration for inactive file handlers.
// Use a negative time.Duration to disable it.
//
// Optional. Default value 10 * time.Second.
// Optional. Default: 10 * time.Second
CacheDuration time.Duration `json:"cache_duration"`

// The value for the Cache-Control HTTP-header
// that is set on the file response. MaxAge is defined in seconds.
//
// Optional. Default value 0.
// Optional. Default: 0
MaxAge int `json:"max_age"`
}

Expand Down Expand Up @@ -1496,9 +1496,10 @@ func (c *DefaultCtx) Send(body []byte) error {
return nil
}

// SendFile transfers the file from the given path.
// The file is not compressed by default, enable this by passing a 'true' argument
// Sets the Content-Type response HTTP header field based on the filenames extension.
// SendFile transfers the file from the specified path.
// By default, the file is not compressed. To enable compression, set SendFile.Compress to true.
// The Content-Type response HTTP header field is set based on the file's extension.
// If the file extension is missing or invalid, the Content-Type is detected from the file's format.
func (c *DefaultCtx) SendFile(file string, config ...SendFile) error {
// Save the filename, we will need it in the error message if the file isn't found
filename := file
Expand Down
7 changes: 4 additions & 3 deletions ctx_interface_gen.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

43 changes: 43 additions & 0 deletions ctx_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3122,6 +3122,49 @@ func Test_Ctx_SendFile(t *testing.T) {
app.ReleaseCtx(c)
}

// go test -race -run Test_Ctx_SendFile_ContentType
func Test_Ctx_SendFile_ContentType(t *testing.T) {
t.Parallel()
app := New()

// 1) simple case
c := app.AcquireCtx(&fasthttp.RequestCtx{})
err := c.SendFile("./.github/testdata/fs/img/fiber.png")
// check expectation
require.NoError(t, err)
require.Equal(t, StatusOK, c.Response().StatusCode())
require.Equal(t, "image/png", string(c.Response().Header.Peek(HeaderContentType)))
app.ReleaseCtx(c)

// 2) set by valid file extension, not file header
// see: https://github.com/valyala/fasthttp/blob/d795f13985f16622a949ea9fc3459cf54dc78b3e/fs.go#L1638
c = app.AcquireCtx(&fasthttp.RequestCtx{})
err = c.SendFile("./.github/testdata/fs/img/fiberpng.jpeg")
// check expectation
require.NoError(t, err)
require.Equal(t, StatusOK, c.Response().StatusCode())
require.Equal(t, "image/jpeg", string(c.Response().Header.Peek(HeaderContentType)))
app.ReleaseCtx(c)

// 3) set by file header if extension is invalid
c = app.AcquireCtx(&fasthttp.RequestCtx{})
err = c.SendFile("./.github/testdata/fs/img/fiberpng.notvalidext")
// check expectation
require.NoError(t, err)
require.Equal(t, StatusOK, c.Response().StatusCode())
require.Equal(t, "image/png", string(c.Response().Header.Peek(HeaderContentType)))
app.ReleaseCtx(c)

// 4) set by file header if extension is missing
c = app.AcquireCtx(&fasthttp.RequestCtx{})
err = c.SendFile("./.github/testdata/fs/img/fiberpng")
// check expectation
require.NoError(t, err)
require.Equal(t, StatusOK, c.Response().StatusCode())
require.Equal(t, "image/png", string(c.Response().Header.Peek(HeaderContentType)))
app.ReleaseCtx(c)
}

func Test_Ctx_SendFile_Download(t *testing.T) {
t.Parallel()
app := New()
Expand Down
22 changes: 11 additions & 11 deletions docs/api/ctx.md
Original file line number Diff line number Diff line change
Expand Up @@ -1709,7 +1709,7 @@ app.Get("/", func(c fiber.Ctx) error {

## SendFile

Transfers the file from the given path. Sets the [Content-Type](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Type) response HTTP header field based on the **filenames** extension.
Transfers the file from the given path. Sets the [Content-Type](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Type) response HTTP header field based on the **file** extension or format.

```go title="Config" title="Config"
// SendFile defines configuration options when to transfer file with SendFile.
Expand All @@ -1725,29 +1725,29 @@ type SendFile struct {
// You have to set Content-Encoding header to compress the file.
// Available compression methods are gzip, br, and zstd.
//
// Optional. Default value false
// Optional. Default: false
Compress bool `json:"compress"`

// When set to true, enables byte range requests.
//
// Optional. Default value false
// Optional. Default: false
ByteRange bool `json:"byte_range"`

// When set to true, enables direct download.
//
// Optional. Default: false.
// Optional. Default: false
Download bool `json:"download"`

// Expiration duration for inactive file handlers.
// Use a negative time.Duration to disable it.
//
// Optional. Default value 10 * time.Second.
// Optional. Default: 10 * time.Second
CacheDuration time.Duration `json:"cache_duration"`

// The value for the Cache-Control HTTP-header
// that is set on the file response. MaxAge is defined in seconds.
//
// Optional. Default value 0.
// Optional. Default: 0
MaxAge int `json:"max_age"`
}
```
Expand All @@ -1761,7 +1761,7 @@ app.Get("/not-found", func(c fiber.Ctx) error {
return c.SendFile("./public/404.html");

// Disable compression
return c.SendFile("./static/index.html", SendFile{
return c.SendFile("./static/index.html", fiber.SendFile{
Compress: false,
});
})
Expand All @@ -1783,7 +1783,7 @@ You can set `CacheDuration` config property to `-1` to disable caching.

```go title="Example"
app.Get("/file", func(c fiber.Ctx) error {
return c.SendFile("style.css", SendFile{
return c.SendFile("style.css", fiber.SendFile{
CacheDuration: -1,
})
})
Expand All @@ -1797,16 +1797,16 @@ You can use multiple SendFile with different configurations in single route. Fib
app.Get("/file", func(c fiber.Ctx) error {
switch c.Query("config") {
case "filesystem":
return c.SendFile("style.css", SendFile{
return c.SendFile("style.css", fiber.SendFile{
FS: os.DirFS(".")
})
case "filesystem-compress":
return c.SendFile("style.css", SendFile{
return c.SendFile("style.css", fiber.SendFile{
FS: os.DirFS("."),
Compress: true,
})
case "compress":
return c.SendFile("style.css", SendFile{
return c.SendFile("style.css", fiber.SendFile{
Compress: true,
})
default:
Expand Down
4 changes: 2 additions & 2 deletions router.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ type Route struct {
Name string `json:"name"` // Route's name
//nolint:revive // Having both a Path (uppercase) and a path (lowercase) is fine
Path string `json:"path"` // Original registered route path
Params []string `json:"params"` // Case sensitive param keys
Params []string `json:"params"` // Case-sensitive param keys
Handlers []Handler `json:"-"` // Ctx handlers
routeParser routeParser // Parameter parser
// Data for routing
Expand Down Expand Up @@ -316,7 +316,7 @@ func (app *App) register(methods []string, pathRaw string, group *Group, handler
if pathRaw[0] != '/' {
pathRaw = "/" + pathRaw
}
// Create a stripped path in-case sensitive / trailing slashes
// Create a stripped path in case-sensitive / trailing slashes
pathPretty := pathRaw
// Case-sensitive routing, all to lowercase
if !app.config.CaseSensitive {
Expand Down
Loading