Fast and extensible multi-platform HTTP/1-2-3 web server with automatic HTTPS
Mirrored from https://github.com/Slazee/caddy.git
Synced Nov 11, 01:00 UTC
| 1 | package caddyfs |
| 2 | |
| 3 | import ( |
| 4 | "encoding/json" |
| 5 | "fmt" |
| 6 | "io/fs" |
| 7 | |
| 8 | "go.uber.org/zap" |
| 9 | |
| 10 | "github.com/caddyserver/caddy/v2" |
| 11 | "github.com/caddyserver/caddy/v2/caddyconfig" |
| 12 | "github.com/caddyserver/caddy/v2/caddyconfig/caddyfile" |
| 13 | "github.com/caddyserver/caddy/v2/caddyconfig/httpcaddyfile" |
| 14 | ) |
| 15 | |
| 16 | func init() { |
| 17 | caddy.RegisterModule(Filesystems{}) |
| 18 | httpcaddyfile.RegisterGlobalOption("filesystem", parseFilesystems) |
| 19 | } |
| 20 | |
| 21 | type moduleEntry struct { |
| 22 | Key string `json:"name,omitempty"` |
| 23 | FileSystemRaw json.RawMessage `json:"file_system,omitempty" caddy:"namespace=caddy.fs inline_key=backend"` |
| 24 | fileSystem fs.FS |
| 25 | } |
| 26 | |
| 27 | // Filesystems loads caddy.fs modules into the global filesystem map |
| 28 | type Filesystems struct { |
| 29 | Filesystems []*moduleEntry `json:"filesystems"` |
| 30 | |
| 31 | defers []func() |
| 32 | } |
| 33 | |
| 34 | func parseFilesystems(d *caddyfile.Dispenser, existingVal any) (any, error) { |
| 35 | p := &Filesystems{} |
| 36 | current, ok := existingVal.(*Filesystems) |
| 37 | if ok { |
| 38 | p = current |
| 39 | } |
| 40 | x := &moduleEntry{} |
| 41 | err := x.UnmarshalCaddyfile(d) |
| 42 | if err != nil { |
| 43 | return nil, err |
| 44 | } |
| 45 | p.Filesystems = append(p.Filesystems, x) |
| 46 | return p, nil |
| 47 | } |
| 48 | |
| 49 | // CaddyModule returns the Caddy module information. |
| 50 | func (Filesystems) CaddyModule() caddy.ModuleInfo { |
| 51 | return caddy.ModuleInfo{ |
| 52 | ID: "caddy.filesystems", |
| 53 | New: func() caddy.Module { return new(Filesystems) }, |
| 54 | } |
| 55 | } |
| 56 | |
| 57 | func (xs *Filesystems) Start() error { return nil } |
| 58 | func (xs *Filesystems) Stop() error { return nil } |
| 59 | |
| 60 | func (xs *Filesystems) Provision(ctx caddy.Context) error { |
| 61 | // load the filesystem module |
| 62 | for _, f := range xs.Filesystems { |
| 63 | if len(f.FileSystemRaw) > 0 { |
| 64 | mod, err := ctx.LoadModule(f, "FileSystemRaw") |
| 65 | if err != nil { |
| 66 | return fmt.Errorf("loading file system module: %v", err) |
| 67 | } |
| 68 | f.fileSystem = mod.(fs.FS) |
| 69 | } |
| 70 | // register that module |
| 71 | ctx.Logger().Debug("registering fs", zap.String("fs", f.Key)) |
| 72 | ctx.FileSystems().Register(f.Key, f.fileSystem) |
| 73 | // remember to unregister the module when we are done |
| 74 | xs.defers = append(xs.defers, func() { |
| 75 | ctx.Logger().Debug("unregistering fs", zap.String("fs", f.Key)) |
| 76 | ctx.FileSystems().Unregister(f.Key) |
| 77 | }) |
| 78 | } |
| 79 | return nil |
| 80 | } |
| 81 | |
| 82 | func (f *Filesystems) Cleanup() error { |
| 83 | for _, v := range f.defers { |
| 84 | v() |
| 85 | } |
| 86 | return nil |
| 87 | } |
| 88 | |
| 89 | func (f *moduleEntry) UnmarshalCaddyfile(d *caddyfile.Dispenser) error { |
| 90 | for d.Next() { |
| 91 | // key required for now |
| 92 | if !d.Args(&f.Key) { |
| 93 | return d.ArgErr() |
| 94 | } |
| 95 | // get the module json |
| 96 | if !d.NextArg() { |
| 97 | return d.ArgErr() |
| 98 | } |
| 99 | name := d.Val() |
| 100 | modID := "caddy.fs." + name |
| 101 | unm, err := caddyfile.UnmarshalModule(d, modID) |
| 102 | if err != nil { |
| 103 | return err |
| 104 | } |
| 105 | fsys, ok := unm.(fs.FS) |
| 106 | if !ok { |
| 107 | return d.Errf("module %s (%T) is not a supported file system implementation (requires fs.FS)", modID, unm) |
| 108 | } |
| 109 | f.FileSystemRaw = caddyconfig.JSONModuleObject(fsys, "backend", name, nil) |
| 110 | } |
| 111 | return nil |
| 112 | } |