Merge pull request #80 from yankay/add-index

feat: Add Show Index
This commit is contained in:
Jeromy Streets 2022-08-11 08:50:33 -07:00 committed by GitHub
commit 0c18d4bd54
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 105 additions and 4 deletions

View File

@ -34,8 +34,11 @@ HOST=
# If assigned, must be a valid port number.
PORT=8080
# Automatically serve the index file for a given directory (default). If set to
# 'false', URLs ending with a '/' will return 'NOT FOUND'.
# When set to 'true' the index.html file in the folder will be served. And
# the file list will not be served.
ALLOW_INDEX=true
# Automatically serve the index of file list for a given directory (default).
SHOW_LISTING=true
# Folder with the content to serve.

View File

@ -61,6 +61,12 @@ ENVIRONMENT VARIABLES
Examples:
REFERRERS='http://localhost,https://some.site,http://other.site:8080'
REFERRERS=',http://localhost,https://some.site,http://other.site:8080'
ALLOW_INDEX
When set to 'true' the index.html file in the folder(not include the
sub folders) will be served. And the file list will not be served.
For example, if the client requests 'http://127.0.0.1/' the 'index.html'
file in the root of the directory being served is returned. Default value
is 'true'.
SHOW_LISTING
Automatically serve the index file for the directory if requested. For
example, if the client requests 'http://127.0.0.1/' the 'index.html'
@ -161,12 +167,22 @@ USAGE
export FOLDER=/var/www
export PORT=80
export ALLOW_INDEX=true # Default behavior
export SHOW_LISTING=true # Default behavior
static-file-server
Retrieve 'index.html' with: wget http://my.machine/
export FOLDER=/var/www
export PORT=80
export ALLOW_INDEX=true # Default behavior
export SHOW_LISTING=false
static-file-server
Retrieve 'index.html' with: wget http://my.machine/
Returns 'NOT FOUND': wget http://my.machine/dir/
export FOLDER=/var/www
export PORT=80
export ALLOW_INDEX=false
export SHOW_LISTING=false
static-file-server
Returns 'NOT FOUND': wget http://my.machine/

View File

@ -59,9 +59,12 @@ func handlerSelector() (handler http.HandlerFunc) {
// Determine whether index files should hidden.
if !config.Get.ShowListing {
handler = handle.IgnoreIndex(handler)
if config.Get.AllowIndex {
handler = handle.PreventListings(handler, config.Get.Folder, config.Get.URLPrefix)
} else {
handler = handle.IgnoreIndex(handler)
}
}
// If configured, apply wildcard CORS support.
if config.Get.Cors {
handler = handle.AddCorsWildcardHeaders(handler)

View File

@ -21,6 +21,7 @@ var (
Folder string `yaml:"folder"`
Host string `yaml:"host"`
Port uint16 `yaml:"port"`
AllowIndex bool `yaml:"allow-index"`
ShowListing bool `yaml:"show-listing"`
TLSCert string `yaml:"tls-cert"`
TLSKey string `yaml:"tls-key"`
@ -39,6 +40,7 @@ const (
hostKey = "HOST"
portKey = "PORT"
referrersKey = "REFERRERS"
allowIndexKey = "ALLOW_INDEX"
showListingKey = "SHOW_LISTING"
tlsCertKey = "TLS_CERT"
tlsKeyKey = "TLS_KEY"
@ -53,6 +55,7 @@ var (
defaultHost = ""
defaultPort = uint16(8080)
defaultReferrers = []string{}
defaultAllowIndex = true
defaultShowListing = true
defaultTLSCert = ""
defaultTLSKey = ""
@ -73,6 +76,7 @@ func setDefaults() {
Get.Host = defaultHost
Get.Port = defaultPort
Get.Referrers = defaultReferrers
Get.AllowIndex = defaultAllowIndex
Get.ShowListing = defaultShowListing
Get.TLSCert = defaultTLSCert
Get.TLSKey = defaultTLSKey
@ -124,6 +128,7 @@ func overrideWithEnvVars() {
Get.Folder = envAsStr(folderKey, Get.Folder)
Get.Host = envAsStr(hostKey, Get.Host)
Get.Port = envAsUint16(portKey, Get.Port)
Get.AllowIndex = envAsBool(allowIndexKey, Get.AllowIndex)
Get.ShowListing = envAsBool(showListingKey, Get.ShowListing)
Get.TLSCert = envAsStr(tlsCertKey, Get.TLSCert)
Get.TLSKey = envAsStr(tlsKeyKey, Get.TLSKey)

View File

@ -82,6 +82,7 @@ func TestOverrideWithEnvvars(t *testing.T) {
testFolder := "/my/directory"
testHost := "apets.life"
testPort := uint16(666)
testAllowIndex := false
testShowListing := false
testTLSCert := "my.pem"
testTLSKey := "my.key"
@ -92,6 +93,7 @@ func TestOverrideWithEnvvars(t *testing.T) {
os.Setenv(folderKey, testFolder)
os.Setenv(hostKey, testHost)
os.Setenv(portKey, strconv.Itoa(int(testPort)))
os.Setenv(allowIndexKey, fmt.Sprintf("%t", testAllowIndex))
os.Setenv(showListingKey, fmt.Sprintf("%t", testShowListing))
os.Setenv(tlsCertKey, testTLSCert)
os.Setenv(tlsKeyKey, testTLSKey)

View File

@ -6,6 +6,8 @@ import (
"fmt"
"log"
"net/http"
"os"
"path"
"strings"
)
@ -130,6 +132,23 @@ func Prefix(serveFile FileServerFunc, folder, urlPrefix string) http.HandlerFunc
}
}
// PreventListings returns a function that prevents listing of directories but
// still allows index.html to be served.
func PreventListings(serve http.HandlerFunc, folder string, urlPrefix string) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
if strings.HasSuffix(r.URL.Path, "/") {
// If the directory does not contain an index.html file, then
// return 'NOT FOUND' to prevent listing of the directory.
stat, err := os.Stat(path.Join(folder, strings.TrimPrefix(r.URL.Path, urlPrefix), "index.html"))
if err != nil || (err == nil && !stat.Mode().IsRegular()) {
http.NotFound(w, r)
return
}
}
serve(w, r)
}
}
// IgnoreIndex wraps an HTTP request. In the event of a folder root request,
// this function will automatically return 'NOT FOUND' as opposed to default
// behavior where the index file for that directory is retrieved.

View File

@ -27,6 +27,8 @@ var (
tmpSubDeepIndexName = "sub/deep/index.html"
tmpSubDeepFileName = "sub/deep/file.txt"
tmpSubDeepBadName = "sub/deep/bad.txt"
tmpNoIndexDir = "noindex/"
tmpNoIndexName = "noindex/noindex.txt"
tmpIndex = "Space: the final frontier"
tmpFile = "These are the voyages of the starship Enterprise."
@ -48,6 +50,7 @@ var (
baseDir + tmpSubFileName: tmpSubFile,
baseDir + tmpSubDeepIndexName: tmpSubDeepIndex,
baseDir + tmpSubDeepFileName: tmpSubDeepFile,
baseDir + tmpNoIndexName: tmpSubDeepFile,
}
serveFileFuncs = []FileServerFunc{
@ -337,6 +340,56 @@ func TestIgnoreIndex(t *testing.T) {
}
}
func TestPreventListings(t *testing.T) {
testCases := []struct {
name string
path string
code int
contents string
}{
{"Good base dir", "", ok, tmpIndex},
{"Good base index", tmpIndexName, redirect, nothing},
{"Good base file", tmpFileName, ok, tmpFile},
{"Bad base file", tmpBadName, missing, notFound},
{"Good subdir dir", subDir, ok, tmpSubIndex},
{"Good subdir index", tmpSubIndexName, redirect, nothing},
{"Good subdir file", tmpSubFileName, ok, tmpSubFile},
{"Dir without index", tmpNoIndexDir, missing, notFound},
}
for _, serveFile := range serveFileFuncs {
handler := PreventListings(Basic(serveFile, baseDir), baseDir, "")
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
fullpath := "http://localhost/" + tc.path
req := httptest.NewRequest("GET", fullpath, nil)
w := httptest.NewRecorder()
handler(w, req)
resp := w.Result()
body, err := ioutil.ReadAll(resp.Body)
if nil != err {
t.Errorf("While reading body got %v", err)
}
contents := string(body)
if tc.code != resp.StatusCode {
t.Errorf(
"While retrieving %s expected status code of %d but got %d",
fullpath, tc.code, resp.StatusCode,
)
}
if tc.contents != contents {
t.Errorf(
"While retrieving %s expected contents '%s' but got '%s'",
fullpath, tc.contents, contents,
)
}
})
}
}
}
func TestAddAccessKey(t *testing.T) {
// Prepare testing data.
accessKey := "my-access-key"