Skip to content

Commit 3950cea

Browse files
authored
bug: fixed --base-path option to be respected with using embedded file system to serve static files (#367)
* bug: fixed `--base-path` option to be respected with using embedded file system to serve static files * fix issues pointed out by gemini-code-assist
1 parent c112a6f commit 3950cea

3 files changed

Lines changed: 116 additions & 1 deletion

File tree

pkg/server/embedfs.go

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
// Copyright 2025 Google LLC
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package server
16+
17+
import (
18+
"embed"
19+
"io/fs"
20+
"log/slog"
21+
"net/http"
22+
"strings"
23+
24+
"github.com/gin-contrib/static"
25+
)
26+
27+
// embedFileSystem is a gin middleware to serve static files from embedded file system.
28+
// The original implementation in gin-contrib/static somehow didn't consider the prefix thus this implementation just ported them here with replacing the prefix handling.
29+
type embedFileSystem struct {
30+
http.FileSystem
31+
}
32+
33+
func (e embedFileSystem) Exists(prefix string, path string) bool {
34+
if !strings.HasPrefix(path, prefix) {
35+
return false
36+
}
37+
_, err := e.Open(strings.TrimPrefix(path, prefix))
38+
return err == nil
39+
}
40+
41+
func embedFolder(fsEmbed embed.FS, targetPath string) static.ServeFileSystem {
42+
fsys, err := fs.Sub(fsEmbed, targetPath)
43+
if err != nil {
44+
slog.Error("Failed to embed folder",
45+
"targetPath", targetPath,
46+
"error", err,
47+
)
48+
return nil
49+
}
50+
return embedFileSystem{
51+
FileSystem: http.FS(fsys),
52+
}
53+
}

pkg/server/embedfs_test.go

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
// Copyright 2025 Google LLC
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package server
16+
17+
import (
18+
"embed"
19+
"testing"
20+
)
21+
22+
//go:embed dist
23+
var embeddedStaticFolderTest embed.FS
24+
25+
func TestEmbedFolder_Exists(t *testing.T) {
26+
testCases := []struct {
27+
desc string
28+
prefix string
29+
path string
30+
want bool
31+
}{
32+
{
33+
desc: "file exists at root",
34+
prefix: "/",
35+
path: "/index.html",
36+
want: true,
37+
},
38+
{
39+
desc: "file exists at root with prefix",
40+
prefix: "/proxy/foo",
41+
path: "/proxy/foo/index.html",
42+
want: true,
43+
},
44+
{
45+
desc: "file doesn't exists at root with prefix",
46+
prefix: "/proxy/foo",
47+
path: "index.html",
48+
want: false,
49+
},
50+
}
51+
52+
for _, tc := range testCases {
53+
t.Run(tc.desc, func(t *testing.T) {
54+
fs := embedFolder(embeddedStaticFolderTest, "dist")
55+
56+
got := fs.Exists(tc.prefix, tc.path)
57+
if got != tc.want {
58+
t.Errorf("Exists(%q, %q) = %v, want %v", tc.prefix, tc.path, got, tc.want)
59+
}
60+
})
61+
}
62+
}

pkg/server/server.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ func CreateKHIServer(engine *gin.Engine, inspectionServer *coreinspection.Inspec
6868

6969
// By default, use the embedded web files. If the static folder path is set, use the local file system.
7070
appHtmlPath := path.Join(embeddedStaticFolderPath, "/index.html")
71-
webFS := static.EmbedFolder(embeddedStaticFolder, embeddedStaticFolderPath)
71+
webFS := embedFolder(embeddedStaticFolder, embeddedStaticFolderPath)
7272
webFSDebugMessage := "Using embedded static web files."
7373
fileReaderFunc := embeddedStaticFolder.ReadFile
7474
if serverConfig.StaticFolderPath != "" {

0 commit comments

Comments
 (0)