ToMiddleware converts StaticConfig to middleware or returns an error for invalid configuration
()
| 175 | |
| 176 | // ToMiddleware converts StaticConfig to middleware or returns an error for invalid configuration |
| 177 | func (config StaticConfig) ToMiddleware() (echo.MiddlewareFunc, error) { |
| 178 | // Defaults |
| 179 | if config.Root == "" { |
| 180 | config.Root = "." // For security we want to restrict to CWD. |
| 181 | } else { |
| 182 | config.Root = path.Clean(config.Root) // fs.Open is very picky about ``, `.`, `..` in paths, so remove some of them up. |
| 183 | } |
| 184 | |
| 185 | if config.Skipper == nil { |
| 186 | config.Skipper = DefaultStaticConfig.Skipper |
| 187 | } |
| 188 | if config.Index == "" { |
| 189 | config.Index = DefaultStaticConfig.Index |
| 190 | } |
| 191 | if config.DirectoryListTemplate == "" { |
| 192 | config.DirectoryListTemplate = directoryListHTMLTemplate |
| 193 | } |
| 194 | |
| 195 | dirListTemplate, tErr := template.New("index").Parse(config.DirectoryListTemplate) |
| 196 | if tErr != nil { |
| 197 | return nil, fmt.Errorf("echo static middleware directory list template parsing error: %w", tErr) |
| 198 | } |
| 199 | |
| 200 | var once *sync.Once |
| 201 | var fsErr error |
| 202 | currentFS := config.Filesystem |
| 203 | if config.Filesystem == nil { |
| 204 | once = &sync.Once{} |
| 205 | } else if config.Root != "." { |
| 206 | tmpFs, fErr := fs.Sub(config.Filesystem, path.Join(".", config.Root)) |
| 207 | if fErr != nil { |
| 208 | return nil, fmt.Errorf("static middleware failed to create sub-filesystem from config.Root, error: %w", fErr) |
| 209 | } |
| 210 | currentFS = tmpFs |
| 211 | } |
| 212 | |
| 213 | return func(next echo.HandlerFunc) echo.HandlerFunc { |
| 214 | return func(c *echo.Context) (err error) { |
| 215 | if config.Skipper(c) { |
| 216 | return next(c) |
| 217 | } |
| 218 | |
| 219 | p := c.Request().URL.Path |
| 220 | if strings.HasSuffix(c.Path(), "*") { // When serving from a group, e.g. `/static*`. |
| 221 | p = c.Param("*") |
| 222 | } |
| 223 | if config.EnablePathUnescaping { |
| 224 | p, err = url.PathUnescape(p) |
| 225 | if err != nil { |
| 226 | return err |
| 227 | } |
| 228 | } |
| 229 | // Security: We use path.Clean() (not filepath.Clean()) because: |
| 230 | // 1. HTTP URLs always use forward slashes, regardless of server OS |
| 231 | // 2. path.Clean() provides platform-independent behavior for URL paths |
| 232 | // 3. The "/" prefix forces absolute path interpretation, removing ".." components |
| 233 | // 4. Backslashes are treated as literal characters (not path separators), preventing traversal |
| 234 | // See static_windows.go for Go 1.20+ filepath.Clean compatibility notes |