Skip to content

Commit

Permalink
fileserver: Implement caddyfile.Unmarshaler interface (#5850)
Browse files Browse the repository at this point in the history
  • Loading branch information
francislavoie committed Jan 13, 2024
1 parent f658fd0 commit f3e849e
Showing 1 changed file with 114 additions and 85 deletions.
199 changes: 114 additions & 85 deletions modules/caddyhttp/fileserver/caddyfile.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (

"github.com/caddyserver/caddy/v2"
"github.com/caddyserver/caddy/v2/caddyconfig"
"github.com/caddyserver/caddy/v2/caddyconfig/caddyfile"
"github.com/caddyserver/caddy/v2/caddyconfig/httpcaddyfile"
"github.com/caddyserver/caddy/v2/modules/caddyhttp"
"github.com/caddyserver/caddy/v2/modules/caddyhttp/encode"
Expand All @@ -31,8 +32,23 @@ func init() {
httpcaddyfile.RegisterDirective("try_files", parseTryFiles)
}

// parseCaddyfile parses the file_server directive. It enables the static file
// server and configures it with this syntax:
// parseCaddyfile parses the file_server directive.
// See UnmarshalCaddyfile for the syntax.
func parseCaddyfile(h httpcaddyfile.Helper) (caddyhttp.MiddlewareHandler, error) {
fsrv := new(FileServer)
err := fsrv.UnmarshalCaddyfile(h.Dispenser)
if err != nil {
return fsrv, err
}
err = fsrv.FinalizeUnmarshalCaddyfile(h)
if err != nil {
return nil, err
}
return fsrv, err
}

// UnmarshalCaddyfile parses the file_server directive. It enables
// the static file server and configures it with this syntax:
//
// file_server [<matcher>] [browse] {
// fs <filesystem>
Expand All @@ -44,103 +60,115 @@ func init() {
// status <status>
// disable_canonical_uris
// }
func parseCaddyfile(h httpcaddyfile.Helper) (caddyhttp.MiddlewareHandler, error) {
var fsrv FileServer
//
// The FinalizeUnmarshalCaddyfile method should be called after this
// to finalize setup of hidden Caddyfiles.
func (fsrv *FileServer) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
d.Next() // consume directive name

for h.Next() {
args := h.RemainingArgs()
switch len(args) {
case 0:
case 1:
if args[0] != "browse" {
return nil, h.ArgErr()
}
fsrv.Browse = new(Browse)
default:
return nil, h.ArgErr()
args := d.RemainingArgs()
switch len(args) {
case 0:
case 1:
if args[0] != "browse" {
return d.ArgErr()
}
fsrv.Browse = new(Browse)
default:
return d.ArgErr()
}

for h.NextBlock(0) {
switch h.Val() {
case "fs":
if !h.NextArg() {
return nil, h.ArgErr()
}
if fsrv.FileSystem != "" {
return nil, h.Err("file system already specified")
}
fsrv.FileSystem = h.Val()
case "hide":
fsrv.Hide = h.RemainingArgs()
if len(fsrv.Hide) == 0 {
return nil, h.ArgErr()
}
for d.NextBlock(0) {
switch d.Val() {
case "fs":
if !d.NextArg() {
return d.ArgErr()
}
if fsrv.FileSystem != "" {
return d.Err("file system already specified")
}
fsrv.FileSystem = d.Val()

case "index":
fsrv.IndexNames = h.RemainingArgs()
if len(fsrv.IndexNames) == 0 {
return nil, h.ArgErr()
}
case "hide":
fsrv.Hide = d.RemainingArgs()
if len(fsrv.Hide) == 0 {
return d.ArgErr()
}

case "root":
if !h.Args(&fsrv.Root) {
return nil, h.ArgErr()
}
case "index":
fsrv.IndexNames = d.RemainingArgs()
if len(fsrv.IndexNames) == 0 {
return d.ArgErr()
}

case "browse":
if fsrv.Browse != nil {
return nil, h.Err("browsing is already configured")
}
fsrv.Browse = new(Browse)
h.Args(&fsrv.Browse.TemplateFile)
case "root":
if !d.Args(&fsrv.Root) {
return d.ArgErr()
}

case "precompressed":
var order []string
for h.NextArg() {
modID := "http.precompressed." + h.Val()
mod, err := caddy.GetModule(modID)
if err != nil {
return nil, h.Errf("getting module named '%s': %v", modID, err)
}
inst := mod.New()
precompress, ok := inst.(encode.Precompressed)
if !ok {
return nil, h.Errf("module %s is not a precompressor; is %T", modID, inst)
}
if fsrv.PrecompressedRaw == nil {
fsrv.PrecompressedRaw = make(caddy.ModuleMap)
}
fsrv.PrecompressedRaw[h.Val()] = caddyconfig.JSON(precompress, nil)
order = append(order, h.Val())
}
fsrv.PrecompressedOrder = order
case "browse":
if fsrv.Browse != nil {
return d.Err("browsing is already configured")
}
fsrv.Browse = new(Browse)
d.Args(&fsrv.Browse.TemplateFile)

case "status":
if !h.NextArg() {
return nil, h.ArgErr()
case "precompressed":
var order []string
for d.NextArg() {
modID := "http.precompressed." + d.Val()
mod, err := caddy.GetModule(modID)
if err != nil {
return d.Errf("getting module named '%s': %v", modID, err)
}
fsrv.StatusCode = caddyhttp.WeakString(h.Val())

case "disable_canonical_uris":
if h.NextArg() {
return nil, h.ArgErr()
inst := mod.New()
precompress, ok := inst.(encode.Precompressed)
if !ok {
return d.Errf("module %s is not a precompressor; is %T", modID, inst)
}
falseBool := false
fsrv.CanonicalURIs = &falseBool

case "pass_thru":
if h.NextArg() {
return nil, h.ArgErr()
if fsrv.PrecompressedRaw == nil {
fsrv.PrecompressedRaw = make(caddy.ModuleMap)
}
fsrv.PassThru = true
fsrv.PrecompressedRaw[d.Val()] = caddyconfig.JSON(precompress, nil)
order = append(order, d.Val())
}
fsrv.PrecompressedOrder = order

default:
return nil, h.Errf("unknown subdirective '%s'", h.Val())
case "status":
if !d.NextArg() {
return d.ArgErr()
}
fsrv.StatusCode = caddyhttp.WeakString(d.Val())

case "disable_canonical_uris":
if d.NextArg() {
return d.ArgErr()
}
falseBool := false
fsrv.CanonicalURIs = &falseBool

case "pass_thru":
if d.NextArg() {
return d.ArgErr()
}
fsrv.PassThru = true

default:
return d.Errf("unknown subdirective '%s'", d.Val())
}
}

// hide the Caddyfile (and any imported Caddyfiles)
return nil
}

// FinalizeUnmarshalCaddyfile finalizes the Caddyfile parsing which
// requires having an httpcaddyfile.Helper to function, to setup hidden Caddyfiles.
func (fsrv *FileServer) FinalizeUnmarshalCaddyfile(h httpcaddyfile.Helper) error {
// Hide the Caddyfile (and any imported Caddyfiles).
// This needs to be done in here instead of UnmarshalCaddyfile
// because UnmarshalCaddyfile only has access to the dispenser
// and not the helper, and only the helper has access to the
// Caddyfiles function.
if configFiles := h.Caddyfiles(); len(configFiles) > 0 {
for _, file := range configFiles {
file = filepath.Clean(file)
Expand All @@ -155,8 +183,7 @@ func parseCaddyfile(h httpcaddyfile.Helper) (caddyhttp.MiddlewareHandler, error)
}
}
}

return &fsrv, nil
return nil
}

// parseTryFiles parses the try_files directive. It combines a file matcher
Expand Down Expand Up @@ -257,3 +284,5 @@ func parseTryFiles(h httpcaddyfile.Helper) ([]httpcaddyfile.ConfigValue, error)

return result, nil
}

var _ caddyfile.Unmarshaler = (*FileServer)(nil)

0 comments on commit f3e849e

Please sign in to comment.