Skip to content

Commit 871fde9

Browse files
committed
Use :path: instead of {path}
{path} gets escaped in URL parsing and makes round-tripping awkward.
1 parent 37fac6a commit 871fde9

File tree

5 files changed

+66
-29
lines changed

5 files changed

+66
-29
lines changed

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,14 @@ module github.com/chriskuehl/fluffy
33
go 1.23.0
44

55
require (
6+
github.com/BurntSushi/toml v1.4.0
67
github.com/adrg/xdg v0.5.0
78
github.com/google/go-cmp v0.6.0
89
github.com/spf13/cobra v1.8.1
910
golang.org/x/term v0.23.0
1011
)
1112

1213
require (
13-
github.com/BurntSushi/toml v1.4.0 // indirect
1414
github.com/inconshreveable/mousetrap v1.1.0 // indirect
1515
github.com/spf13/pflag v1.0.5 // indirect
1616
golang.org/x/sys v0.24.0 // indirect

server/assets/assets.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ func AssetURL(conf *config.Config, path string) (string, error) {
8080
return "", fmt.Errorf("asset not found: %s", path)
8181
}
8282
url := conf.ObjectURLPattern
83-
url.Path = strings.Replace(url.Path, "{path}", assetObjectPath(path, hash), -1)
83+
url.Path = strings.Replace(url.Path, ":path:", assetObjectPath(path, hash), -1)
8484
return url.String(), nil
8585
}
8686

server/config/config.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -52,11 +52,11 @@ func (conf *Config) Validate() []string {
5252
if strings.HasSuffix(conf.HomeURL.Path, "/") {
5353
errs = append(errs, "HomeURL must not end with a slash")
5454
}
55-
if !strings.Contains(conf.ObjectURLPattern.Path, "{path}") {
56-
errs = append(errs, "ObjectURLPattern must contain a '{path}' placeholder")
55+
if !strings.Contains(conf.ObjectURLPattern.Path, ":path:") {
56+
errs = append(errs, "ObjectURLPattern must contain a ':path:' placeholder")
5757
}
58-
if !strings.Contains(conf.HTMLURLPattern.Path, "{path}") {
59-
errs = append(errs, "HTMLURLPattern must contain a '{path}' placeholder")
58+
if !strings.Contains(conf.HTMLURLPattern.Path, ":path:") {
59+
errs = append(errs, "HTMLURLPattern must contain a ':path:' placeholder")
6060
}
6161
if conf.ForbiddenFileExtensions == nil {
6262
errs = append(errs, "ForbiddenFileExtensions must not be nil")

server/config/loader/loader_test.go

Lines changed: 58 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,24 @@ import (
1212
"github.com/chriskuehl/fluffy/testfunc"
1313
)
1414

15+
var configWithEverything = []byte(`
16+
branding = "foo"
17+
custom_footer_html = "<p>foo</p>"
18+
abuse_contact_email = "[email protected]"
19+
max_upload_bytes = 123
20+
max_multipart_memory_bytes = 456
21+
home_url = "http://foo.com"
22+
object_url_pattern = "http://i.foo.com/o/:path:"
23+
html_url_pattern = "http://i.foo.com/h/:path:"
24+
forbidden_file_extensions = ["foo", "bar"]
25+
host = "192.168.1.100"
26+
port = 5555
27+
28+
[filesystem_storage_backend]
29+
object_root = "/tmp/objects"
30+
html_root = "/tmp/html"
31+
`)
32+
1533
func TestLoadConfigTOMLEmptyFile(t *testing.T) {
1634
configPath := t.TempDir() + "/config.toml"
1735
if err := os.WriteFile(configPath, []byte(""), 0644); err != nil {
@@ -30,31 +48,13 @@ func TestLoadConfigTOMLEmptyFile(t *testing.T) {
3048

3149
func TestLoadConfigTOMLWithEverything(t *testing.T) {
3250
configPath := t.TempDir() + "/config.toml"
33-
if err := os.WriteFile(configPath, []byte(`
34-
branding = "foo"
35-
custom_footer_html = "<p>foo</p>"
36-
abuse_contact_email = "[email protected]"
37-
max_upload_bytes = 123
38-
max_multipart_memory_bytes = 456
39-
home_url = "http://foo.com"
40-
object_url_pattern = "http://i.foo.com/o/{path}"
41-
html_url_pattern = "http://i.foo.com/h/{path}"
42-
forbidden_file_extensions = ["foo", "bar"]
43-
host = "192.168.1.100"
44-
port = 5555
45-
46-
[filesystem_storage_backend]
47-
object_root = "/tmp/objects"
48-
html_root = "/tmp/html"
49-
`), 0644); err != nil {
51+
if err := os.WriteFile(configPath, configWithEverything, 0644); err != nil {
5052
t.Fatalf("failed to write file: %v", err)
5153
}
52-
5354
conf := testfunc.NewConfig()
5455
if err := LoadConfigTOML(conf, configPath); err != nil {
5556
t.Fatalf("failed to load config: %v", err)
5657
}
57-
5858
errs := conf.Validate()
5959
if len(errs) != 0 {
6060
t.Fatalf("config validation failed: %v", errs)
@@ -67,8 +67,8 @@ html_root = "/tmp/html"
6767
MaxUploadBytes: 123,
6868
MaxMultipartMemoryBytes: 456,
6969
HomeURL: url.URL{Scheme: "http", Host: "foo.com"},
70-
ObjectURLPattern: url.URL{Scheme: "http", Host: "i.foo.com", Path: "/o/{path}", RawPath: "/o/{path}"},
71-
HTMLURLPattern: url.URL{Scheme: "http", Host: "i.foo.com", Path: "/h/{path}", RawPath: "/h/{path}"},
70+
ObjectURLPattern: url.URL{Scheme: "http", Host: "i.foo.com", Path: "/o/:path:"},
71+
HTMLURLPattern: url.URL{Scheme: "http", Host: "i.foo.com", Path: "/h/:path:"},
7272
ForbiddenFileExtensions: map[string]struct{}{"foo": {}, "bar": {}},
7373
Host: "192.168.1.100",
7474
Port: 5555,
@@ -82,3 +82,40 @@ html_root = "/tmp/html"
8282
t.Fatalf("config mismatch (-want +got):\n%s", diff)
8383
}
8484
}
85+
86+
func TestRoundtripDumpLoadConfigTOML(t *testing.T) {
87+
configPath := t.TempDir() + "/config.toml"
88+
if err := os.WriteFile(configPath, configWithEverything, 0644); err != nil {
89+
t.Fatalf("failed to write file: %v", err)
90+
}
91+
conf := testfunc.NewConfig()
92+
if err := LoadConfigTOML(conf, configPath); err != nil {
93+
t.Fatalf("failed to load config: %v", err)
94+
}
95+
errs := conf.Validate()
96+
if len(errs) != 0 {
97+
t.Fatalf("config validation failed: %v", errs)
98+
}
99+
100+
newConfigPath := t.TempDir() + "/new_config.toml"
101+
configText, err := DumpConfigTOML(conf)
102+
if err != nil {
103+
t.Fatalf("failed to dump config: %v", err)
104+
}
105+
if err := os.WriteFile(newConfigPath, []byte(configText), 0644); err != nil {
106+
t.Fatalf("failed to write file: %v", err)
107+
}
108+
109+
newConf := testfunc.NewConfig()
110+
if err := LoadConfigTOML(newConf, newConfigPath); err != nil {
111+
t.Fatalf("failed to load config: %v", err)
112+
}
113+
errs = newConf.Validate()
114+
if len(errs) != 0 {
115+
t.Fatalf("config validation failed: %v", errs)
116+
}
117+
118+
if diff := cmp.Diff(conf, newConf); diff != "" {
119+
t.Fatalf("config mismatch (-want +got):\n%s", diff)
120+
}
121+
}

server/server.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,8 @@ func NewConfig() *config.Config {
2929
MaxUploadBytes: 1024 * 1024 * 10, // 10 MiB
3030
MaxMultipartMemoryBytes: 1024 * 1024 * 10, // 10 MiB
3131
HomeURL: url.URL{Scheme: "http", Host: "localhost:8080"},
32-
ObjectURLPattern: url.URL{Scheme: "http", Host: "localhost:8080", Path: "/dev/object/{path}"},
33-
HTMLURLPattern: url.URL{Scheme: "http", Host: "localhost:8080", Path: "/dev/html/{path}"},
32+
ObjectURLPattern: url.URL{Scheme: "http", Host: "localhost:8080", Path: "/dev/object/:path:"},
33+
HTMLURLPattern: url.URL{Scheme: "http", Host: "localhost:8080", Path: "/dev/html/:path:"},
3434
ForbiddenFileExtensions: make(map[string]struct{}),
3535
Host: "127.0.0.1",
3636
Port: 8080,

0 commit comments

Comments
 (0)