mirror of
https://github.com/halverneus/static-file-server.git
synced 2024-11-24 09:05:30 +00:00
feat: add-show-index
This commit is contained in:
parent
0364e4a184
commit
a975f33b21
@ -34,8 +34,11 @@ HOST=
|
|||||||
# If assigned, must be a valid port number.
|
# If assigned, must be a valid port number.
|
||||||
PORT=8080
|
PORT=8080
|
||||||
|
|
||||||
# Automatically serve the index file for a given directory (default). If set to
|
# When set to 'true' the index.html file in the folder will be served. And
|
||||||
# 'false', URLs ending with a '/' will return 'NOT FOUND'.
|
# 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
|
SHOW_LISTING=true
|
||||||
|
|
||||||
# Folder with the content to serve.
|
# Folder with the content to serve.
|
||||||
|
@ -61,6 +61,12 @@ ENVIRONMENT VARIABLES
|
|||||||
Examples:
|
Examples:
|
||||||
REFERRERS='http://localhost,https://some.site,http://other.site:8080'
|
REFERRERS='http://localhost,https://some.site,http://other.site:8080'
|
||||||
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
|
SHOW_LISTING
|
||||||
Automatically serve the index file for the directory if requested. For
|
Automatically serve the index file for the directory if requested. For
|
||||||
example, if the client requests 'http://127.0.0.1/' the 'index.html'
|
example, if the client requests 'http://127.0.0.1/' the 'index.html'
|
||||||
@ -161,12 +167,22 @@ USAGE
|
|||||||
|
|
||||||
export FOLDER=/var/www
|
export FOLDER=/var/www
|
||||||
export PORT=80
|
export PORT=80
|
||||||
|
export ALLOW_INDEX=true # Default behavior
|
||||||
export SHOW_LISTING=true # Default behavior
|
export SHOW_LISTING=true # Default behavior
|
||||||
static-file-server
|
static-file-server
|
||||||
Retrieve 'index.html' with: wget http://my.machine/
|
Retrieve 'index.html' with: wget http://my.machine/
|
||||||
|
|
||||||
export FOLDER=/var/www
|
export FOLDER=/var/www
|
||||||
export PORT=80
|
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
|
export SHOW_LISTING=false
|
||||||
static-file-server
|
static-file-server
|
||||||
Returns 'NOT FOUND': wget http://my.machine/
|
Returns 'NOT FOUND': wget http://my.machine/
|
||||||
|
@ -59,9 +59,12 @@ func handlerSelector() (handler http.HandlerFunc) {
|
|||||||
|
|
||||||
// Determine whether index files should hidden.
|
// Determine whether index files should hidden.
|
||||||
if !config.Get.ShowListing {
|
if !config.Get.ShowListing {
|
||||||
|
if config.Get.AllowIndex {
|
||||||
|
handler = handle.PreventListings(handler, config.Get.Folder, config.Get.URLPrefix)
|
||||||
|
} else {
|
||||||
handler = handle.IgnoreIndex(handler)
|
handler = handle.IgnoreIndex(handler)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
// If configured, apply wildcard CORS support.
|
// If configured, apply wildcard CORS support.
|
||||||
if config.Get.Cors {
|
if config.Get.Cors {
|
||||||
handler = handle.AddCorsWildcardHeaders(handler)
|
handler = handle.AddCorsWildcardHeaders(handler)
|
||||||
|
@ -21,6 +21,7 @@ var (
|
|||||||
Folder string `yaml:"folder"`
|
Folder string `yaml:"folder"`
|
||||||
Host string `yaml:"host"`
|
Host string `yaml:"host"`
|
||||||
Port uint16 `yaml:"port"`
|
Port uint16 `yaml:"port"`
|
||||||
|
AllowIndex bool `yaml:"allow-index"`
|
||||||
ShowListing bool `yaml:"show-listing"`
|
ShowListing bool `yaml:"show-listing"`
|
||||||
TLSCert string `yaml:"tls-cert"`
|
TLSCert string `yaml:"tls-cert"`
|
||||||
TLSKey string `yaml:"tls-key"`
|
TLSKey string `yaml:"tls-key"`
|
||||||
@ -39,6 +40,7 @@ const (
|
|||||||
hostKey = "HOST"
|
hostKey = "HOST"
|
||||||
portKey = "PORT"
|
portKey = "PORT"
|
||||||
referrersKey = "REFERRERS"
|
referrersKey = "REFERRERS"
|
||||||
|
allowIndexKey = "ALLOW_INDEX"
|
||||||
showListingKey = "SHOW_LISTING"
|
showListingKey = "SHOW_LISTING"
|
||||||
tlsCertKey = "TLS_CERT"
|
tlsCertKey = "TLS_CERT"
|
||||||
tlsKeyKey = "TLS_KEY"
|
tlsKeyKey = "TLS_KEY"
|
||||||
@ -53,6 +55,7 @@ var (
|
|||||||
defaultHost = ""
|
defaultHost = ""
|
||||||
defaultPort = uint16(8080)
|
defaultPort = uint16(8080)
|
||||||
defaultReferrers = []string{}
|
defaultReferrers = []string{}
|
||||||
|
defaultAllowIndex = true
|
||||||
defaultShowListing = true
|
defaultShowListing = true
|
||||||
defaultTLSCert = ""
|
defaultTLSCert = ""
|
||||||
defaultTLSKey = ""
|
defaultTLSKey = ""
|
||||||
@ -73,6 +76,7 @@ func setDefaults() {
|
|||||||
Get.Host = defaultHost
|
Get.Host = defaultHost
|
||||||
Get.Port = defaultPort
|
Get.Port = defaultPort
|
||||||
Get.Referrers = defaultReferrers
|
Get.Referrers = defaultReferrers
|
||||||
|
Get.AllowIndex = defaultAllowIndex
|
||||||
Get.ShowListing = defaultShowListing
|
Get.ShowListing = defaultShowListing
|
||||||
Get.TLSCert = defaultTLSCert
|
Get.TLSCert = defaultTLSCert
|
||||||
Get.TLSKey = defaultTLSKey
|
Get.TLSKey = defaultTLSKey
|
||||||
@ -124,6 +128,7 @@ func overrideWithEnvVars() {
|
|||||||
Get.Folder = envAsStr(folderKey, Get.Folder)
|
Get.Folder = envAsStr(folderKey, Get.Folder)
|
||||||
Get.Host = envAsStr(hostKey, Get.Host)
|
Get.Host = envAsStr(hostKey, Get.Host)
|
||||||
Get.Port = envAsUint16(portKey, Get.Port)
|
Get.Port = envAsUint16(portKey, Get.Port)
|
||||||
|
Get.AllowIndex = envAsBool(allowIndexKey, Get.AllowIndex)
|
||||||
Get.ShowListing = envAsBool(showListingKey, Get.ShowListing)
|
Get.ShowListing = envAsBool(showListingKey, Get.ShowListing)
|
||||||
Get.TLSCert = envAsStr(tlsCertKey, Get.TLSCert)
|
Get.TLSCert = envAsStr(tlsCertKey, Get.TLSCert)
|
||||||
Get.TLSKey = envAsStr(tlsKeyKey, Get.TLSKey)
|
Get.TLSKey = envAsStr(tlsKeyKey, Get.TLSKey)
|
||||||
|
@ -82,6 +82,7 @@ func TestOverrideWithEnvvars(t *testing.T) {
|
|||||||
testFolder := "/my/directory"
|
testFolder := "/my/directory"
|
||||||
testHost := "apets.life"
|
testHost := "apets.life"
|
||||||
testPort := uint16(666)
|
testPort := uint16(666)
|
||||||
|
testAllowIndex := false
|
||||||
testShowListing := false
|
testShowListing := false
|
||||||
testTLSCert := "my.pem"
|
testTLSCert := "my.pem"
|
||||||
testTLSKey := "my.key"
|
testTLSKey := "my.key"
|
||||||
@ -92,6 +93,7 @@ func TestOverrideWithEnvvars(t *testing.T) {
|
|||||||
os.Setenv(folderKey, testFolder)
|
os.Setenv(folderKey, testFolder)
|
||||||
os.Setenv(hostKey, testHost)
|
os.Setenv(hostKey, testHost)
|
||||||
os.Setenv(portKey, strconv.Itoa(int(testPort)))
|
os.Setenv(portKey, strconv.Itoa(int(testPort)))
|
||||||
|
os.Setenv(allowIndexKey, fmt.Sprintf("%t", testAllowIndex))
|
||||||
os.Setenv(showListingKey, fmt.Sprintf("%t", testShowListing))
|
os.Setenv(showListingKey, fmt.Sprintf("%t", testShowListing))
|
||||||
os.Setenv(tlsCertKey, testTLSCert)
|
os.Setenv(tlsCertKey, testTLSCert)
|
||||||
os.Setenv(tlsKeyKey, testTLSKey)
|
os.Setenv(tlsKeyKey, testTLSKey)
|
||||||
|
@ -6,6 +6,8 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"os"
|
||||||
|
"path"
|
||||||
"strings"
|
"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,
|
// IgnoreIndex wraps an HTTP request. In the event of a folder root request,
|
||||||
// this function will automatically return 'NOT FOUND' as opposed to default
|
// this function will automatically return 'NOT FOUND' as opposed to default
|
||||||
// behavior where the index file for that directory is retrieved.
|
// behavior where the index file for that directory is retrieved.
|
||||||
|
@ -27,6 +27,8 @@ var (
|
|||||||
tmpSubDeepIndexName = "sub/deep/index.html"
|
tmpSubDeepIndexName = "sub/deep/index.html"
|
||||||
tmpSubDeepFileName = "sub/deep/file.txt"
|
tmpSubDeepFileName = "sub/deep/file.txt"
|
||||||
tmpSubDeepBadName = "sub/deep/bad.txt"
|
tmpSubDeepBadName = "sub/deep/bad.txt"
|
||||||
|
tmpNoIndexDir = "noindex/"
|
||||||
|
tmpNoIndexName = "noindex/noindex.txt"
|
||||||
|
|
||||||
tmpIndex = "Space: the final frontier"
|
tmpIndex = "Space: the final frontier"
|
||||||
tmpFile = "These are the voyages of the starship Enterprise."
|
tmpFile = "These are the voyages of the starship Enterprise."
|
||||||
@ -48,6 +50,7 @@ var (
|
|||||||
baseDir + tmpSubFileName: tmpSubFile,
|
baseDir + tmpSubFileName: tmpSubFile,
|
||||||
baseDir + tmpSubDeepIndexName: tmpSubDeepIndex,
|
baseDir + tmpSubDeepIndexName: tmpSubDeepIndex,
|
||||||
baseDir + tmpSubDeepFileName: tmpSubDeepFile,
|
baseDir + tmpSubDeepFileName: tmpSubDeepFile,
|
||||||
|
baseDir + tmpNoIndexName: tmpSubDeepFile,
|
||||||
}
|
}
|
||||||
|
|
||||||
serveFileFuncs = []FileServerFunc{
|
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) {
|
func TestAddAccessKey(t *testing.T) {
|
||||||
// Prepare testing data.
|
// Prepare testing data.
|
||||||
accessKey := "my-access-key"
|
accessKey := "my-access-key"
|
||||||
|
Loading…
Reference in New Issue
Block a user