Can someone please explain "Readdir" and "Open" wrapper methods

Issue

I’m new to Golang. Can someone please explain, how "Readdir" and "Open" wrapper methods are working?

This example is from Golang documentation.
https://pkg.go.dev/net/http#example-FileServer-DotFileHiding

More specifically, in the "Readdir" method, the statement files, err := f.File.Readdir(n) has n int value but from where it’s passed and how it is working. "Readdir" method isn’t called anywhere in the program.

Similarly in "Open" wrapper file, err := fsys.FileSystem.Open(name)

package main

import (
    "io/fs"
    "log"
    "net/http"
    "strings"
)

// containsDotFile reports whether name contains a path element starting with a period.
// The name is assumed to be a delimited by forward slashes, as guaranteed
// by the http.FileSystem interface.
func containsDotFile(name string) bool {
    parts := strings.Split(name, "/")
    for _, part := range parts {
        if strings.HasPrefix(part, ".") {
            return true
        }
    }
    return false
}

// dotFileHidingFile is the http.File use in dotFileHidingFileSystem.
// It is used to wrap the Readdir method of http.File so that we can
// remove files and directories that start with a period from its output.
type dotFileHidingFile struct {
    http.File
}
f
// Readdir is a wrapper around the Readdir method of the embedded File
// that filters out all files that start with a period in their name.
func (f dotFileHidingFile) Readdir(n int) (fis []fs.FileInfo, err error) {
    files, err := f.File.Readdir(n)
    for _, file := range files { // Filters out the dot files
        if !strings.HasPrefix(file.Name(), ".") {
            fis = append(fis, file)
        }
    }
    return
}

// dotFileHidingFileSystem is an http.FileSystem that hides
// hidden "dot files" from being served.
type dotFileHidingFileSystem struct {
    http.FileSystem
}

// Open is a wrapper around the Open method of the embedded FileSystem
// that serves a 403 permission error when name has a file or directory
// with whose name starts with a period in its path.
func (fsys dotFileHidingFileSystem) Open(name string) (http.File, error) {
    if containsDotFile(name) { // If dot file, return 403 response
        return nil, fs.ErrPermission
    }

    file, err := fsys.FileSystem.Open(name)
    if err != nil {
        return nil, err
    }
    return dotFileHidingFile{file}, err
}

func main() {
    fsys := dotFileHidingFileSystem{http.Dir(".")}
    http.Handle("/", http.FileServer(fsys))
    log.Fatal(http.ListenAndServe(":8080", nil))
}

Solution

The dotFileHidingFileSystem type wraps an http.FileSystem and is itself an http.FileSystem.

The dotFileHidingFile type wraps an http.File and is itself an http.File.

Because these two struct types embed the wrapped value, all of the methods on the wrapped value are promoted to methods on the wrapper type unless the wrapper type itself implements the method. Read the Effective Go section on embedding if you are not familiar with the embedding concept.

The net/http FileServer calls the methods on the http.FileSystem and http.File interfaces.

The file server calls the file system Open method to open a file. The dotFileHidingFileSystem implementation of that method calls through to the wrapped file system to open the file and returns a dotFileHidingFile wrapper around that file.

If the file is a directory, the file server calls the file Readdir method to get a listing of the files in the directory. The file server specifies the value of n. The dotFileHidingFile implementation of the Readdir method calls through the the wrapped file Readdir method and filters dot files out of the result.

See the ReadDirFile documentation for documentation on the n argument to Readdir.

Answered By – RedBlue

Answer Checked By – Willingham (GoLangFix Volunteer)

Leave a Reply

Your email address will not be published.