Repository: gin-gonic/gin
Pull request #3063 (2022-02-28 22:22:31)

Bump golangci/golangci-lint-action from 2 to 3.1.0
Bumps [golangci/golangci-lint-action](https://github.com/golangci/golangci-lint-action) from 2 to 3.1.0.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a href="https://github.com/golangci/golangci-lint-action/releases">golangci/golangci-lint-action's releases</a>.</em></p>
<blockquote>
<h2>v3.1.0</h2>
<h2>What's Changed</h2>
<h3>New features</h3>
<ul>
<li>Allow to disable caching completely by <a href="https://github.com/tdabasinskas"><code>@​tdabasinskas</code></a> in <a href="https://github-redirect.dependabot.com/golangci/golangci-lint-action/pull/351">golangci/golangci-lint-action#351</a></li>
</ul>
<h3>CI</h3>
<ul>
<li>ci(dep): Add step to commit changes if PR has dependencies label by <a href="https://github.com/sayboras"><code>@​sayboras</code></a> in <a href="https://github-redirect.dependabot.com/golangci/golangci-lint-action/pull/108">golangci/golangci-lint-action#108</a></li>
</ul>
<h3>Dependabot</h3>
<ul>
<li>build(deps-dev): bump eslint from 8.9.0 to 8.10.0 by <a href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a href="https://github-redirect.dependabot.com/golangci/golangci-lint-action/pull/405">golangci/golangci-lint-action#405</a></li>
</ul>
<h3>Misc</h3>
<ul>
<li>Update version to 3.1.0 in package.json by <a href="https://github.com/SVilgelm"><code>@​SVilgelm</code></a> in <a href="https://github-redirect.dependabot.com/golangci/golangci-lint-action/pull/406">golangci/golangci-lint-action#406</a></li>
<li>fix version in package-lock.json by <a href="https://github.com/SVilgelm"><code>@​SVilgelm</code></a> in <a href="https://github-redirect.dependabot.com/golangci/golangci-lint-action/pull/407">golangci/golangci-lint-action#407</a></li>
</ul>
<h2>New Contributors</h2>
<ul>
<li><a href="https://github.com/tdabasinskas"><code>@​tdabasinskas</code></a> made their first contribution in <a href="https://github-redirect.dependabot.com/golangci/golangci-lint-action/pull/351">golangci/golangci-lint-action#351</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a href="https://github.com/golangci/golangci-lint-action/compare/v3...v3.1.0">https://github.com/golangci/golangci-lint-action/compare/v3...v3.1.0</a></p>
<h2>v3.0.0</h2>
<h2>What's Changed</h2>
<ul>
<li>Fix grammar in action.yml by <a href="https://github.com/abennett"><code>@​abennett</code></a> in <a href="https://github-redirect.dependabot.com/golangci/golangci-lint-action/pull/356">golangci/golangci-lint-action#356</a></li>
<li>Add description for permissions settings by <a href="https://github.com/sg0hsmt"><code>@​sg0hsmt</code></a> in <a href="https://github-redirect.dependabot.com/golangci/golangci-lint-action/pull/298">golangci/golangci-lint-action#298</a></li>
<li>Remove Setup-Go by <a href="https://github.com/StevenACoffman"><code>@​StevenACoffman</code></a> in <a href="https://github-redirect.dependabot.com/golangci/golangci-lint-action/pull/403">golangci/golangci-lint-action#403</a></li>
<li>Update all direct dependencies by <a href="https://github.com/SVilgelm"><code>@​SVilgelm</code></a> in <a href="https://github-redirect.dependabot.com/golangci/golangci-lint-action/pull/404">golangci/golangci-lint-action#404</a></li>
<li>139 Dependabot updates</li>
</ul>
<h2>New Contributors</h2>
<ul>
<li><a href="https://github.com/abennett"><code>@​abennett</code></a> made their first contribution in <a href="https://github-redirect.dependabot.com/golangci/golangci-lint-action/pull/356">golangci/golangci-lint-action#356</a></li>
<li><a href="https://github.com/sg0hsmt"><code>@​sg0hsmt</code></a> made their first contribution in <a href="https://github-redirect.dependabot.com/golangci/golangci-lint-action/pull/298">golangci/golangci-lint-action#298</a></li>
<li><a href="https://github.com/StevenACoffman"><code>@​StevenACoffman</code></a> made their first contribution in <a href="https://github-redirect.dependabot.com/golangci/golangci-lint-action/pull/403">golangci/golangci-lint-action#403</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a href="https://github.com/golangci/golangci-lint-action/compare/v2...v3.0.0">https://github.com/golangci/golangci-lint-action/compare/v2...v3.0.0</a></p>
<h2>Bump version v2.5.2</h2>
<h3>Bug fixes</h3>
<ul>
<li>5c56cd6 Extract and don't mangle User Args. (<a href="https://github-redirect.dependabot.com/golangci/golangci-lint-action/issues/200">#200</a>)</li>
</ul>
<h3>Dependencies</h3>
<ul>
<li>e3c53fe bump <code>@​typescript-eslint/eslint-plugin</code> (<a href="https://github-redirect.dependabot.com/golangci/golangci-lint-action/issues/194">#194</a>)</li>
<li>3b9f80e bump <code>@​typescript-eslint/parser</code> from 4.18.0 to 4.19.0 (<a href="https://github-redirect.dependabot.com/golangci/golangci-lint-action/issues/195">#195</a>)</li>
<li>9845713 bump <code>@​types/node</code> from 14.14.35 to 14.14.37 (<a href="https://github-redirect.dependabot.com/golangci/golangci-lint-action/issues/197">#197</a>)</li>
<li>e789ee1 bump eslint from 7.22.0 to 7.23.0 (<a href="https://github-redirect.dependabot.com/golangci/golangci-lint-action/issues/196">#196</a>)</li>
<li>f2e9a96 bump <code>@​typescript-eslint/eslint-plugin</code> (<a href="https://github-redirect.dependabot.com/golangci/golangci-lint-action/issues/188">#188</a>)</li>
<li>818081a bump <code>@​types/node</code> from 14.14.34 to 14.14.35 (<a href="https://github-redirect.dependabot.com/golangci/golangci-lint-action/issues/189">#189</a>)</li>
<li>6671836 bump <code>@​typescript-eslint/parser</code> from 4.17.0 to 4.18.0 (<a href="https://github-redirect.dependabot.com/golangci/golangci-lint-action/issues/190">#190</a>)</li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a href="https://github.com/golangci/golangci-lint-action/commit/b517f99ae23d86ecc4c0dec08dcf48d2336abc29"><code>b517f99</code></a> fix version in package-lock.json (<a href="https://github-redirect.dependabot.com/golangci/golangci-lint-action/issues/407">#407</a>)</li>
<li><a href="https://github.com/golangci/golangci-lint-action/commit/9636c5bc970c0b32ef536af763bb0d8c0ce43d06"><code>9636c5b</code></a> Update version to 3.1.0 in package.json (<a href="https://github-redirect.dependabot.com/golangci/golangci-lint-action/issues/406">#406</a>)</li>
<li><a href="https://github.com/golangci/golangci-lint-action/commit/03e4befc7a48e128bca6688662b6c114c5f15ced"><code>03e4bef</code></a> ci(dep): Add step to commit changes if PR has dependencies label (<a href="https://github-redirect.dependabot.com/golangci/golangci-lint-action/issues/108">#108</a>)</li>
<li><a href="https://github.com/golangci/golangci-lint-action/commit/cdfc708aebd36a8298403ef5d87a954d8fe174f7"><code>cdfc708</code></a> Allow to disable caching completely (<a href="https://github-redirect.dependabot.com/golangci/golangci-lint-action/issues/351">#351</a>)</li>
<li><a href="https://github.com/golangci/golangci-lint-action/commit/7d5614c3ebb18b0b007c796cc4b8d5c10c738cde"><code>7d5614c</code></a> build(deps-dev): bump eslint from 8.9.0 to 8.10.0 (<a href="https://github-redirect.dependabot.com/golangci/golangci-lint-action/issues/405">#405</a>)</li>
<li><a href="https://github.com/golangci/golangci-lint-action/commit/c675eb70db3aa26b496bc4e64da320480338d41b"><code>c675eb7</code></a> Update all direct dependencies (<a href="https://github-redirect.dependabot.com/golangci/golangci-lint-action/issues/404">#404</a>)</li>
<li><a href="https://github.com/golangci/golangci-lint-action/commit/423fbafafc226b312a399e5a5c942041f5d6f24f"><code>423fbaf</code></a> Remove Setup-Go (<a href="https://github-redirect.dependabot.com/golangci/golangci-lint-action/issues/403">#403</a>)</li>
<li><a href="https://github.com/golangci/golangci-lint-action/commit/bcfc6f96bb4349b5b132c5ee5dd004652378de94"><code>bcfc6f9</code></a> build(deps-dev): bump eslint-plugin-import from 2.25.3 to 2.25.4 (<a href="https://github-redirect.dependabot.com/golangci/golangci-lint-action/issues/402">#402</a>)</li>
<li><a href="https://github.com/golangci/golangci-lint-action/commit/d34ac2aef3154747bff6d9bda0e3cf7b3dc06653"><code>d34ac2a</code></a> build(deps): bump setup-go from v2.1.4 to v2.2.0 (<a href="https://github-redirect.dependabot.com/golangci/golangci-lint-action/issues/401">#401</a>)</li>
<li><a href="https://github.com/golangci/golangci-lint-action/commit/e4b538ed37b93de2fd7b5b1f481eee1b634a7c6f"><code>e4b538e</code></a> build(deps-dev): bump <code>@​types/node</code> from 16.11.10 to 17.0.19 (<a href="https://github-redirect.dependabot.com/golangci/golangci-lint-action/issues/400">#400</a>)</li>
<li>Additional commits viewable in <a href="https://github.com/golangci/golangci-lint-action/compare/v2...v3.1.0">compare view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=golangci/golangci-lint-action&package-manager=github_actions&previous-version=2&new-version=3.1.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
- `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)


</details>

codecov[bot]: # [Codecov](https://codecov.io/gh/gin-gonic/gin/pull/3063?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=gin-gonic) Report
> Merging [#3063](https://codecov.io/gh/gin-gonic/gin/pull/3063?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=gin-gonic) (fd4df7e) into [master](https://codecov.io/gh/gin-gonic/gin/commit/375714258462e46df07337b31dae4370d03ab28d?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=gin-gonic) (3757142) will **not change** coverage.
> The diff coverage is `n/a`.

[![Impacted file tree graph](https://codecov.io/gh/gin-gonic/gin/pull/3063/graphs/tree.svg?width=650&height=150&src=pr&token=Qpqxhwery8&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=gin-gonic)](https://codecov.io/gh/gin-gonic/gin/pull/3063?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=gin-gonic)

```diff
@@           Coverage Diff           @@
##           master    #3063   +/-   ##
=======================================
  Coverage   98.77%   98.77%           
=======================================
  Files          41       41           
  Lines        3090     3090           
=======================================
  Hits         3052     3052           
  Misses         26       26           
  Partials       12       12           
```

| Flag | Coverage Δ | |
|---|---|---|
| go-1.13 | `98.77% <ø> (ø)` | |
| go-1.14 | `98.60% <ø> (ø)` | |
| go-1.15 | `98.60% <ø> (ø)` | |
| go-1.16 | `98.60% <ø> (ø)` | |
| go-1.17 | `98.51% <ø> (ø)` | |
| macos-latest | `98.76% <ø> (-0.01%)` | :arrow_down: |
| nomsgpack | `98.75% <ø> (ø)` | |
| ubuntu-latest | `98.77% <ø> (ø)` | |

Flags with carried forward coverage won't be shown. [Click here](https://docs.codecov.io/docs/carryforward-flags?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=gin-gonic#carryforward-flags-in-the-pull-request-comment) to find out more.


------

[Continue to review full report at Codecov](https://codecov.io/gh/gin-gonic/gin/pull/3063?src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=gin-gonic).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=gin-gonic)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/gin-gonic/gin/pull/3063?src=pr&el=footer&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=gin-gonic). Last update [3757142...fd4df7e](https://codecov.io/gh/gin-gonic/gin/pull/3063?src=pr&el=lastupdated&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=gin-gonic). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=gin-gonic).


Patch:
diff --git a/.github/workflows/gin.yml b/.github/workflows/gin.yml
index 5b818a9..1aecda5 100644
--- a/.github/workflows/gin.yml
+++ b/.github/workflows/gin.yml
@@ -19,7 +19,7 @@ jobs:
       - name: Checkout repository
         uses: actions/checkout@v3
       - name: Setup golangci-lint
-        uses: golangci/golangci-lint-action@v2
+        uses: golangci/golangci-lint-action@v3.1.0
         with:
           version: v1.44.0
           args: --verbose
diff --git a/README.md b/README.md
index d3fa075..9a9785e 100644
--- a/README.md
+++ b/README.md
@@ -513,6 +513,7 @@ func main() {
 
 		// nested group
 		testing := authorized.Group("testing")
+		// visit 0.0.0.0:8080/testing/analytics
 		testing.GET("/analytics", analyticsEndpoint)
 	}
 
@@ -1243,7 +1244,8 @@ func main() {
 	router.Static("/assets", "./assets")
 	router.StaticFS("/more_static", http.Dir("my_file_system"))
 	router.StaticFile("/favicon.ico", "./resources/favicon.ico")
-
+	router.StaticFileFS("/more_favicon.ico", "more_favicon.ico", http.Dir("my_file_system"))
+	
 	// Listen and serve on 0.0.0.0:8080
 	router.Run(":8080")
 }
@@ -1409,7 +1411,7 @@ import (
 
 func formatAsDate(t time.Time) string {
     year, month, day := t.Date()
-    return fmt.Sprintf("%d%02d/%02d", year, month, day)
+    return fmt.Sprintf("%d/%02d/%02d", year, month, day)
 }
 
 func main() {
diff --git a/context.go b/context.go
index d69df70..48d7550 100644
--- a/context.go
+++ b/context.go
@@ -6,7 +6,6 @@ package gin
 
 import (
 	"errors"
-	"fmt"
 	"io"
 	"io/ioutil"
 	"log"
@@ -1018,7 +1017,11 @@ func (c *Context) FileFromFS(filepath string, fs http.FileSystem) {
 // FileAttachment writes the specified file into the body stream in an efficient way
 // On the client side, the file will typically be downloaded with the given filename
 func (c *Context) FileAttachment(filepath, filename string) {
-	c.Writer.Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=\"%s\"", filename))
+	if isASCII(filename) {
+		c.Writer.Header().Set("Content-Disposition", `attachment; filename="`+filename+`"`)
+	} else {
+		c.Writer.Header().Set("Content-Disposition", `attachment; filename*=UTF-8''`+url.QueryEscape(filename))
+	}
 	http.ServeFile(c.Writer, c.Request, filepath)
 }
 
diff --git a/routergroup.go b/routergroup.go
index b84fcca..3fba3a9 100644
--- a/routergroup.go
+++ b/routergroup.go
@@ -44,6 +44,7 @@ type IRoutes interface {
 	HEAD(string, ...HandlerFunc) IRoutes
 
 	StaticFile(string, string) IRoutes
+	StaticFileFS(string, string, http.FileSystem) IRoutes
 	Static(string, string) IRoutes
 	StaticFS(string, http.FileSystem) IRoutes
 }
@@ -153,12 +154,24 @@ func (group *RouterGroup) Any(relativePath string, handlers ...HandlerFunc) IRou
 // StaticFile registers a single route in order to serve a single file of the local filesystem.
 // router.StaticFile("favicon.ico", "./resources/favicon.ico")
 func (group *RouterGroup) StaticFile(relativePath, filepath string) IRoutes {
+	return group.staticFileHandler(relativePath, func(c *Context) {
+		c.File(filepath)
+	})
+}
+
+// StaticFileFS works just like `StaticFile` but a custom `http.FileSystem` can be used instead..
+// router.StaticFileFS("favicon.ico", "./resources/favicon.ico", Dir{".", false})
+// Gin by default user: gin.Dir()
+func (group *RouterGroup) StaticFileFS(relativePath, filepath string, fs http.FileSystem) IRoutes {
+	return group.staticFileHandler(relativePath, func(c *Context) {
+		c.FileFromFS(filepath, fs)
+	})
+}
+
+func (group *RouterGroup) staticFileHandler(relativePath string, handler HandlerFunc) IRoutes {
 	if strings.Contains(relativePath, ":") || strings.Contains(relativePath, "*") {
 		panic("URL parameters can not be used when serving a static file")
 	}
-	handler := func(c *Context) {
-		c.File(filepath)
-	}
 	group.GET(relativePath, handler)
 	group.HEAD(relativePath, handler)
 	return group.returnObj()
diff --git a/utils.go b/utils.go
index c32f0ee..e4599ea 100644
--- a/utils.go
+++ b/utils.go
@@ -12,6 +12,7 @@ import (
 	"reflect"
 	"runtime"
 	"strings"
+	"unicode"
 )
 
 // BindKey indicates a default bind key.
@@ -151,3 +152,13 @@ func resolveAddress(addr []string) string {
 		panic("too many parameters")
 	}
 }
+
+// https://stackoverflow.com/questions/53069040/checking-a-string-contains-only-ascii-characters
+func isASCII(s string) bool {
+	for i := 0; i < len(s); i++ {
+		if s[i] > unicode.MaxASCII {
+			return false
+		}
+	}
+	return true
+}


Test patch:
diff --git a/context_test.go b/context_test.go
index 9e02aed..4eed164 100644
--- a/context_test.go
+++ b/context_test.go
@@ -15,6 +15,7 @@ import (
 	"net"
 	"net/http"
 	"net/http/httptest"
+	"net/url"
 	"os"
 	"reflect"
 	"strings"
@@ -1033,6 +1034,19 @@ func TestContextRenderAttachment(t *testing.T) {
 	assert.Equal(t, fmt.Sprintf("attachment; filename=\"%s\"", newFilename), w.Header().Get("Content-Disposition"))
 }
 
+func TestContextRenderUTF8Attachment(t *testing.T) {
+	w := httptest.NewRecorder()
+	c, _ := CreateTestContext(w)
+	newFilename := "new🧡_filename.go"
+
+	c.Request, _ = http.NewRequest("GET", "/", nil)
+	c.FileAttachment("./gin.go", newFilename)
+
+	assert.Equal(t, 200, w.Code)
+	assert.Contains(t, w.Body.String(), "func New() *Engine {")
+	assert.Equal(t, `attachment; filename*=UTF-8''`+url.QueryEscape(newFilename), w.Header().Get("Content-Disposition"))
+}
+
 // TestContextRenderYAML tests that the response is serialized as YAML
 // and Content-Type is set to application/x-yaml
 func TestContextRenderYAML(t *testing.T) {
diff --git a/routergroup_test.go b/routergroup_test.go
index 232f595..c1fad3a 100644
--- a/routergroup_test.go
+++ b/routergroup_test.go
@@ -111,6 +111,17 @@ func TestRouterGroupInvalidStaticFile(t *testing.T) {
 	})
 }
 
+func TestRouterGroupInvalidStaticFileFS(t *testing.T) {
+	router := New()
+	assert.Panics(t, func() {
+		router.StaticFileFS("/path/:param", "favicon.ico", Dir(".", false))
+	})
+
+	assert.Panics(t, func() {
+		router.StaticFileFS("/path/*param", "favicon.ico", Dir(".", false))
+	})
+}
+
 func TestRouterGroupTooManyHandlers(t *testing.T) {
 	const (
 		panicValue = "too many handlers"
@@ -177,6 +188,7 @@ func testRoutesInterface(t *testing.T, r IRoutes) {
 	assert.Equal(t, r, r.HEAD("/", handler))
 
 	assert.Equal(t, r, r.StaticFile("/file", "."))
+	assert.Equal(t, r, r.StaticFileFS("/static2", ".", Dir(".", false)))
 	assert.Equal(t, r, r.Static("/static", "."))
 	assert.Equal(t, r, r.StaticFS("/static2", Dir(".", false)))
 }
diff --git a/routes_test.go b/routes_test.go
index b3f0c47..5643097 100644
--- a/routes_test.go
+++ b/routes_test.go
@@ -325,6 +325,40 @@ func TestRouteStaticFile(t *testing.T) {
 	assert.Equal(t, http.StatusOK, w3.Code)
 }
 
+// TestHandleStaticFile - ensure the static file handles properly
+func TestRouteStaticFileFS(t *testing.T) {
+	// SETUP file
+	testRoot, _ := os.Getwd()
+	f, err := ioutil.TempFile(testRoot, "")
+	if err != nil {
+		t.Error(err)
+	}
+	defer os.Remove(f.Name())
+	_, err = f.WriteString("Gin Web Framework")
+	assert.NoError(t, err)
+	f.Close()
+
+	dir, filename := filepath.Split(f.Name())
+	// SETUP gin
+	router := New()
+	router.Static("/using_static", dir)
+	router.StaticFileFS("/result_fs", filename, Dir(dir, false))
+
+	w := PerformRequest(router, http.MethodGet, "/using_static/"+filename)
+	w2 := PerformRequest(router, http.MethodGet, "/result_fs")
+
+	assert.Equal(t, w, w2)
+	assert.Equal(t, http.StatusOK, w.Code)
+	assert.Equal(t, "Gin Web Framework", w.Body.String())
+	assert.Equal(t, "text/plain; charset=utf-8", w.Header().Get("Content-Type"))
+
+	w3 := PerformRequest(router, http.MethodHead, "/using_static/"+filename)
+	w4 := PerformRequest(router, http.MethodHead, "/result_fs")
+
+	assert.Equal(t, w3, w4)
+	assert.Equal(t, http.StatusOK, w3.Code)
+}
+
 // TestHandleStaticDir - ensure the root/sub dir handles properly
 func TestRouteStaticListingDir(t *testing.T) {
 	router := New()
diff --git a/utils_test.go b/utils_test.go
index b50914f..d2a740b 100644
--- a/utils_test.go
+++ b/utils_test.go
@@ -143,3 +143,8 @@ func TestMarshalXMLforH(t *testing.T) {
 	e := h.MarshalXML(enc, x)
 	assert.Error(t, e)
 }
+
+func TestIsASCII(t *testing.T) {
+	assert.Equal(t, isASCII("test"), true)
+	assert.Equal(t, isASCII("🧡💛💚💙💜"), false)
+}