mirror of
https://github.com/halverneus/static-file-server.git
synced 2024-11-24 09:05:30 +00:00
Added command-line utility packages and integrated.
This commit is contained in:
parent
755e0114f1
commit
055f1621cb
@ -1,182 +1,13 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/halverneus/static-file-server/config"
|
||||
"github.com/halverneus/static-file-server/handle"
|
||||
)
|
||||
|
||||
var (
|
||||
version = "Version 1.3"
|
||||
|
||||
help = `
|
||||
NAME
|
||||
static-file-server
|
||||
|
||||
SYNOPSIS
|
||||
static-file-server
|
||||
static-file-server [ help | -help | --help ]
|
||||
static-file-server [ version | -version | --version ]
|
||||
|
||||
DESCRIPTION
|
||||
The Static File Server is intended to be a tiny, fast and simple solution
|
||||
for serving files over HTTP. The features included are limited to make to
|
||||
binding to a host name and port, selecting a folder to serve, choosing a
|
||||
URL path prefix and selecting TLS certificates. If you want really awesome
|
||||
reverse proxy features, I recommend Nginx.
|
||||
|
||||
DEPENDENCIES
|
||||
None... not even libc!
|
||||
|
||||
ENVIRONMENT VARIABLES
|
||||
FOLDER
|
||||
The path to the folder containing the contents to be served over
|
||||
HTTP(s). If not supplied, defaults to '/web' (for Docker reasons).
|
||||
HOST
|
||||
The hostname used for binding. If not supplied, contents will be served
|
||||
to a client without regard for the hostname.
|
||||
PORT
|
||||
The port used for binding. If not supplied, defaults to port '8080'.
|
||||
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'
|
||||
file in the root of the directory being served is returned. If the value
|
||||
is set to 'false', the same request will return a 'NOT FOUND'. Default
|
||||
value is 'true'.
|
||||
TLS_CERT
|
||||
Path to the TLS certificate file to serve files using HTTPS. If supplied
|
||||
then TLS_KEY must also be supplied. If not supplied, contents will be
|
||||
served via HTTP.
|
||||
TLS_KEY
|
||||
Path to the TLS key file to serve files using HTTPS. If supplied then
|
||||
TLS_CERT must also be supplied. If not supplied, contents will be served
|
||||
via HTTPS
|
||||
URL_PREFIX
|
||||
The prefix to use in the URL path. If supplied, then the prefix must
|
||||
start with a forward-slash and NOT end with a forward-slash. If not
|
||||
supplied then no prefix is used.
|
||||
|
||||
USAGE
|
||||
FILE LAYOUT
|
||||
/var/www/sub/my.file
|
||||
/var/www/index.html
|
||||
|
||||
COMMAND
|
||||
export FOLDER=/var/www/sub
|
||||
static-file-server
|
||||
Retrieve with: wget http://localhost:8080/my.file
|
||||
wget http://my.machine:8080/my.file
|
||||
|
||||
export FOLDER=/var/www
|
||||
export HOST=my.machine
|
||||
export PORT=80
|
||||
static-file-server
|
||||
Retrieve with: wget http://my.machine/sub/my.file
|
||||
|
||||
export FOLDER=/var/www/sub
|
||||
export HOST=my.machine
|
||||
export PORT=80
|
||||
export URL_PREFIX=/my/stuff
|
||||
static-file-server
|
||||
Retrieve with: wget http://my.machine/my/stuff/my.file
|
||||
|
||||
export FOLDER=/var/www/sub
|
||||
export TLS_CERT=/etc/server/my.machine.crt
|
||||
export TLS_KEY=/etc/server/my.machine.key
|
||||
static-file-server
|
||||
Retrieve with: wget https://my.machine:8080/my.file
|
||||
|
||||
export FOLDER=/var/www/sub
|
||||
export PORT=443
|
||||
export TLS_CERT=/etc/server/my.machine.crt
|
||||
export TLS_KEY=/etc/server/my.machine.key
|
||||
static-file-server
|
||||
Retrieve with: wget https://my.machine/my.file
|
||||
|
||||
export FOLDER=/var/www
|
||||
export PORT=80
|
||||
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 SHOW_LISTING=false
|
||||
static-file-server
|
||||
Returns 'NOT FOUND': wget http://my.machine/
|
||||
`
|
||||
"github.com/halverneus/static-file-server/cli"
|
||||
)
|
||||
|
||||
func main() {
|
||||
// Evaluate and execute subcommand if supplied.
|
||||
if 1 < len(os.Args) {
|
||||
arg := os.Args[1]
|
||||
switch {
|
||||
case strings.Contains(arg, "help"):
|
||||
fmt.Println(help)
|
||||
case strings.Contains(arg, "version"):
|
||||
fmt.Println(version)
|
||||
default:
|
||||
name := os.Args[0]
|
||||
log.Fatalf("Unknown argument: %s. Try '%s help'.", arg, name)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Collect environment variables.
|
||||
if err := config.Load(""); nil != err {
|
||||
log.Fatalf("While loading configuration got %v", err)
|
||||
}
|
||||
|
||||
// If HTTPS is to be used, verify both TLS_* environment variables are set.
|
||||
if 0 < len(config.Get.TLSCert) || 0 < len(config.Get.TLSKey) {
|
||||
if 0 == len(config.Get.TLSCert) || 0 == len(config.Get.TLSKey) {
|
||||
log.Fatalln(
|
||||
"If value for environment variable 'TLS_CERT' or 'TLS_KEY' is set " +
|
||||
"then value for environment variable 'TLS_KEY' or 'TLS_CERT' must " +
|
||||
"also be set.",
|
||||
)
|
||||
if err := cli.Execute(); nil != err {
|
||||
log.Fatalf("Error: %v\n", err)
|
||||
}
|
||||
}
|
||||
|
||||
// If the URL path prefix is to be used, verify it is properly formatted.
|
||||
if 0 < len(config.Get.URLPrefix) &&
|
||||
(!strings.HasPrefix(config.Get.URLPrefix, "/") || strings.HasSuffix(config.Get.URLPrefix, "/")) {
|
||||
log.Fatalln(
|
||||
"Value for environment variable 'URL_PREFIX' must start " +
|
||||
"with '/' and not end with '/'. Example: '/my/prefix'",
|
||||
)
|
||||
}
|
||||
|
||||
// Choose and set the appropriate, optimized static file serving function.
|
||||
var handler http.HandlerFunc
|
||||
if 0 == len(config.Get.URLPrefix) {
|
||||
handler = handle.Basic(config.Get.Folder)
|
||||
} else {
|
||||
handler = handle.Prefix(config.Get.Folder, config.Get.URLPrefix)
|
||||
}
|
||||
|
||||
// Determine whether index files should hidden.
|
||||
if !config.Get.ShowListing {
|
||||
handler = handle.IgnoreIndex(handler)
|
||||
}
|
||||
|
||||
// Serve files over HTTP or HTTPS based on paths to TLS files being provided.
|
||||
var listener handle.ListenerFunc
|
||||
if 0 < len(config.Get.TLSCert) {
|
||||
listener = handle.TLSListening(
|
||||
config.Get.TLSCert,
|
||||
config.Get.TLSKey,
|
||||
)
|
||||
} else {
|
||||
listener = handle.Listening()
|
||||
}
|
||||
|
||||
binding := fmt.Sprintf("%s:%d", config.Get.Host, config.Get.Port)
|
||||
log.Fatalln(listener(binding, handler))
|
||||
}
|
||||
|
27
cli/args.go
Normal file
27
cli/args.go
Normal file
@ -0,0 +1,27 @@
|
||||
package cli
|
||||
|
||||
// Args parsed from the command-line.
|
||||
type Args []string
|
||||
|
||||
// Parse command-line arguments into Args. Value is returned to support daisy
|
||||
// chaining.
|
||||
func Parse(values []string) Args {
|
||||
args := Args(values)
|
||||
return args
|
||||
}
|
||||
|
||||
// Matches is used to determine if the arguments match the provided pattern.
|
||||
func (args Args) Matches(pattern ...string) bool {
|
||||
// If lengths don't match then nothing does.
|
||||
if len(pattern) != len(args) {
|
||||
return false
|
||||
}
|
||||
|
||||
// Compare slices using '*' as a wildcard.
|
||||
for index, value := range pattern {
|
||||
if "*" != value && value != args[index] {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
81
cli/args_test.go
Normal file
81
cli/args_test.go
Normal file
@ -0,0 +1,81 @@
|
||||
package cli
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestParse(t *testing.T) {
|
||||
matches := func(args Args, orig []string) bool {
|
||||
if nil == orig {
|
||||
return nil == args
|
||||
}
|
||||
if len(orig) != len(args) {
|
||||
return false
|
||||
}
|
||||
for index, value := range args {
|
||||
if orig[index] != value {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
value []string
|
||||
}{
|
||||
{"Nil arguments", nil},
|
||||
{"No arguments", []string{}},
|
||||
{"Arguments", []string{"first", "second", "*"}},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
if args := Parse(tc.value); !matches(args, tc.value) {
|
||||
t.Errorf("Expected [%v] but got [%v]", tc.value, args)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestMatches(t *testing.T) {
|
||||
testCases := []struct {
|
||||
name string
|
||||
value []string
|
||||
pattern []string
|
||||
result bool
|
||||
}{
|
||||
{"Nil args and nil pattern", nil, nil, true},
|
||||
{"No args and nil pattern", []string{}, nil, true},
|
||||
{"Nil args and no pattern", nil, []string{}, true},
|
||||
{"No args and no pattern", []string{}, []string{}, true},
|
||||
{"Nil args and pattern", nil, []string{"test"}, false},
|
||||
{"No args and pattern", []string{}, []string{"test"}, false},
|
||||
{"Args and nil pattern", []string{"test"}, nil, false},
|
||||
{"Args and no pattern", []string{"test"}, []string{}, false},
|
||||
{"Simple single compare", []string{"test"}, []string{"test"}, true},
|
||||
{"Simple double compare", []string{"one", "two"}, []string{"one", "two"}, true},
|
||||
{"Bad single", []string{"one"}, []string{"two"}, false},
|
||||
{"Bad double", []string{"one", "two"}, []string{"one", "owt"}, false},
|
||||
{"Count mismatch", []string{"one", "two"}, []string{"one"}, false},
|
||||
{"Nil args and wild", nil, []string{"*"}, false},
|
||||
{"No args and wild", []string{}, []string{"*"}, false},
|
||||
{"Single arg and wild", []string{"one"}, []string{"*"}, true},
|
||||
{"Double arg and first wild", []string{"one", "two"}, []string{"*", "two"}, true},
|
||||
{"Double arg and second wild", []string{"one", "two"}, []string{"one", "*"}, true},
|
||||
{"Double arg and first wild mismatched", []string{"one", "two"}, []string{"*", "owt"}, false},
|
||||
{"Double arg and second wild mismatched", []string{"one", "two"}, []string{"eno", "*"}, false},
|
||||
{"Double arg and double wild", []string{"one", "two"}, []string{"*", "*"}, true},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
args := Parse(tc.value)
|
||||
if resp := args.Matches(tc.pattern...); tc.result != resp {
|
||||
msg := "For arguments [%v] matched to pattern [%v] expected " +
|
||||
"%b but got %b"
|
||||
t.Errorf(msg, tc.value, tc.pattern, tc.result, resp)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
95
cli/execute.go
Normal file
95
cli/execute.go
Normal file
@ -0,0 +1,95 @@
|
||||
package cli
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
|
||||
"github.com/halverneus/static-file-server/cli/help"
|
||||
"github.com/halverneus/static-file-server/cli/server"
|
||||
"github.com/halverneus/static-file-server/cli/version"
|
||||
"github.com/halverneus/static-file-server/config"
|
||||
)
|
||||
|
||||
var (
|
||||
option struct {
|
||||
configFile string
|
||||
helpFlag bool
|
||||
versionFlag bool
|
||||
}
|
||||
)
|
||||
|
||||
// Assignments used to simplify testing.
|
||||
var (
|
||||
selectRoutine = selectionRoutine
|
||||
unknownArgsFunc = unknownArgs
|
||||
runServerFunc = server.Run
|
||||
runHelpFunc = help.Run
|
||||
runVersionFunc = version.Run
|
||||
loadConfig = config.Load
|
||||
)
|
||||
|
||||
func init() {
|
||||
setupFlags()
|
||||
}
|
||||
|
||||
func setupFlags() {
|
||||
flag.StringVar(&option.configFile, "config", "", "")
|
||||
flag.StringVar(&option.configFile, "c", "", "")
|
||||
flag.BoolVar(&option.helpFlag, "help", false, "")
|
||||
flag.BoolVar(&option.helpFlag, "h", false, "")
|
||||
flag.BoolVar(&option.versionFlag, "version", false, "")
|
||||
flag.BoolVar(&option.versionFlag, "v", false, "")
|
||||
}
|
||||
|
||||
// Execute CLI arguments.
|
||||
func Execute() (err error) {
|
||||
// Parse flag options, then parse commands arguments.
|
||||
flag.Parse()
|
||||
args := Parse(flag.Args())
|
||||
|
||||
job := selectRoutine(args)
|
||||
return job()
|
||||
}
|
||||
|
||||
func selectionRoutine(args Args) func() error {
|
||||
switch {
|
||||
|
||||
// serve help
|
||||
// serve --help
|
||||
// serve -h
|
||||
case args.Matches("help") || option.helpFlag:
|
||||
return runHelpFunc
|
||||
|
||||
// serve version
|
||||
// serve --version
|
||||
// serve -v
|
||||
case args.Matches("version") || option.versionFlag:
|
||||
return runVersionFunc
|
||||
|
||||
// serve
|
||||
case args.Matches():
|
||||
return withConfig(runServerFunc)
|
||||
|
||||
// Unknown arguments.
|
||||
default:
|
||||
return unknownArgsFunc(args)
|
||||
}
|
||||
}
|
||||
|
||||
func unknownArgs(args Args) func() error {
|
||||
return func() error {
|
||||
return fmt.Errorf(
|
||||
"unknown arguments provided [%v], try: 'help'",
|
||||
args,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
func withConfig(routine func() error) func() error {
|
||||
return func() (err error) {
|
||||
if err = loadConfig(option.configFile); nil != err {
|
||||
return
|
||||
}
|
||||
return routine()
|
||||
}
|
||||
}
|
162
cli/execute_test.go
Normal file
162
cli/execute_test.go
Normal file
@ -0,0 +1,162 @@
|
||||
package cli
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"flag"
|
||||
"os"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestSetupFlags(t *testing.T) {
|
||||
app := os.Args[0]
|
||||
|
||||
file := "file.txt"
|
||||
wConfig := "Config (file.txt)"
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
args []string
|
||||
config string
|
||||
help bool
|
||||
version bool
|
||||
}{
|
||||
{"Empty args", []string{app}, "", false, false},
|
||||
{"Help (--help)", []string{app, "--help"}, "", true, false},
|
||||
{"Help (-help)", []string{app, "-help"}, "", true, false},
|
||||
{"Help (-h)", []string{app, "-h"}, "", true, false},
|
||||
{"Version (--version)", []string{app, "--version"}, "", false, true},
|
||||
{"Version (-version)", []string{app, "-version"}, "", false, true},
|
||||
{"Version (-v)", []string{app, "-v"}, "", false, true},
|
||||
{"Config ()", []string{app, "--config", ""}, "", false, false},
|
||||
{wConfig, []string{app, "--config", file}, file, false, false},
|
||||
{wConfig, []string{app, "--config=file.txt"}, file, false, false},
|
||||
{wConfig, []string{app, "-config", file}, file, false, false},
|
||||
{wConfig, []string{app, "-config=file.txt"}, file, false, false},
|
||||
{wConfig, []string{app, "-c", file}, file, false, false},
|
||||
{"All set", []string{app, "-h", "-v", "-c", file}, file, true, true},
|
||||
}
|
||||
|
||||
reset := func() {
|
||||
option.configFile = ""
|
||||
option.helpFlag = false
|
||||
option.versionFlag = false
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
reset()
|
||||
os.Args = tc.args
|
||||
flag.Parse()
|
||||
|
||||
if option.configFile != tc.config {
|
||||
t.Errorf(
|
||||
"For options [%v] expected a config file of %s but got %s",
|
||||
tc.args, tc.config, option.configFile,
|
||||
)
|
||||
}
|
||||
if option.helpFlag != tc.help {
|
||||
t.Errorf(
|
||||
"For options [%v] expected help flag of %t but got %t",
|
||||
tc.args, tc.help, option.helpFlag,
|
||||
)
|
||||
}
|
||||
if option.versionFlag != tc.version {
|
||||
t.Errorf(
|
||||
"For options [%v] expected version flag of %t but got %t",
|
||||
tc.args, tc.version, option.versionFlag,
|
||||
)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestExecuteAndSelection(t *testing.T) {
|
||||
app := os.Args[0]
|
||||
|
||||
runHelpFuncError := errors.New("help")
|
||||
runHelpFunc = func() error {
|
||||
return runHelpFuncError
|
||||
}
|
||||
runVersionFuncError := errors.New("version")
|
||||
runVersionFunc = func() error {
|
||||
return runVersionFuncError
|
||||
}
|
||||
runServerFuncError := errors.New("server")
|
||||
runServerFunc = func() error {
|
||||
return runServerFuncError
|
||||
}
|
||||
unknownArgsFuncError := errors.New("unknown")
|
||||
unknownArgsFunc = func(Args) func() error {
|
||||
return func() error {
|
||||
return unknownArgsFuncError
|
||||
}
|
||||
}
|
||||
|
||||
reset := func() {
|
||||
option.configFile = ""
|
||||
option.helpFlag = false
|
||||
option.versionFlag = false
|
||||
}
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
args []string
|
||||
result error
|
||||
}{
|
||||
{"Help", []string{app, "help"}, runHelpFuncError},
|
||||
{"Help", []string{app, "--help"}, runHelpFuncError},
|
||||
{"Version", []string{app, "version"}, runVersionFuncError},
|
||||
{"Version", []string{app, "--version"}, runVersionFuncError},
|
||||
{"Serve", []string{app}, runServerFuncError},
|
||||
{"Unknown", []string{app, "unknown"}, unknownArgsFuncError},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
reset()
|
||||
os.Args = tc.args
|
||||
|
||||
if err := Execute(); tc.result != err {
|
||||
t.Errorf(
|
||||
"Expected error for %v but got %v",
|
||||
tc.result, err,
|
||||
)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestUnknownArgs(t *testing.T) {
|
||||
errFunc := unknownArgs(Args{"unknown"})
|
||||
if err := errFunc(); nil == err {
|
||||
t.Errorf(
|
||||
"Expected a given unknown argument error but got %v",
|
||||
err,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
func TestWithConfig(t *testing.T) {
|
||||
configError := errors.New("config")
|
||||
routineError := errors.New("routine")
|
||||
routine := func() error { return routineError }
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
loadConfig func(string) error
|
||||
result error
|
||||
}{
|
||||
{"Config error", func(string) error { return configError }, configError},
|
||||
{"Routine error", func(string) error { return nil }, routineError},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
loadConfig = tc.loadConfig
|
||||
errFunc := withConfig(routine)
|
||||
if err := errFunc(); tc.result != err {
|
||||
t.Errorf("Expected error %v but got %v", tc.result, err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
111
cli/help/help.go
Normal file
111
cli/help/help.go
Normal file
@ -0,0 +1,111 @@
|
||||
package help
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// Run print operation.
|
||||
func Run() error {
|
||||
fmt.Println(Text)
|
||||
return nil
|
||||
}
|
||||
|
||||
var (
|
||||
// Text for directly accessing help.
|
||||
Text = `
|
||||
NAME
|
||||
static-file-server
|
||||
|
||||
SYNOPSIS
|
||||
static-file-server
|
||||
static-file-server [ help | -help | --help ]
|
||||
static-file-server [ version | -version | --version ]
|
||||
|
||||
DESCRIPTION
|
||||
The Static File Server is intended to be a tiny, fast and simple solution
|
||||
for serving files over HTTP. The features included are limited to make to
|
||||
binding to a host name and port, selecting a folder to serve, choosing a
|
||||
URL path prefix and selecting TLS certificates. If you want really awesome
|
||||
reverse proxy features, I recommend Nginx.
|
||||
|
||||
DEPENDENCIES
|
||||
None... not even libc!
|
||||
|
||||
ENVIRONMENT VARIABLES
|
||||
FOLDER
|
||||
The path to the folder containing the contents to be served over
|
||||
HTTP(s). If not supplied, defaults to '/web' (for Docker reasons).
|
||||
HOST
|
||||
The hostname used for binding. If not supplied, contents will be served
|
||||
to a client without regard for the hostname.
|
||||
PORT
|
||||
The port used for binding. If not supplied, defaults to port '8080'.
|
||||
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'
|
||||
file in the root of the directory being served is returned. If the value
|
||||
is set to 'false', the same request will return a 'NOT FOUND'. Default
|
||||
value is 'true'.
|
||||
TLS_CERT
|
||||
Path to the TLS certificate file to serve files using HTTPS. If supplied
|
||||
then TLS_KEY must also be supplied. If not supplied, contents will be
|
||||
served via HTTP.
|
||||
TLS_KEY
|
||||
Path to the TLS key file to serve files using HTTPS. If supplied then
|
||||
TLS_CERT must also be supplied. If not supplied, contents will be served
|
||||
via HTTPS
|
||||
URL_PREFIX
|
||||
The prefix to use in the URL path. If supplied, then the prefix must
|
||||
start with a forward-slash and NOT end with a forward-slash. If not
|
||||
supplied then no prefix is used.
|
||||
|
||||
USAGE
|
||||
FILE LAYOUT
|
||||
/var/www/sub/my.file
|
||||
/var/www/index.html
|
||||
|
||||
COMMAND
|
||||
export FOLDER=/var/www/sub
|
||||
static-file-server
|
||||
Retrieve with: wget http://localhost:8080/my.file
|
||||
wget http://my.machine:8080/my.file
|
||||
|
||||
export FOLDER=/var/www
|
||||
export HOST=my.machine
|
||||
export PORT=80
|
||||
static-file-server
|
||||
Retrieve with: wget http://my.machine/sub/my.file
|
||||
|
||||
export FOLDER=/var/www/sub
|
||||
export HOST=my.machine
|
||||
export PORT=80
|
||||
export URL_PREFIX=/my/stuff
|
||||
static-file-server
|
||||
Retrieve with: wget http://my.machine/my/stuff/my.file
|
||||
|
||||
export FOLDER=/var/www/sub
|
||||
export TLS_CERT=/etc/server/my.machine.crt
|
||||
export TLS_KEY=/etc/server/my.machine.key
|
||||
static-file-server
|
||||
Retrieve with: wget https://my.machine:8080/my.file
|
||||
|
||||
export FOLDER=/var/www/sub
|
||||
export PORT=443
|
||||
export TLS_CERT=/etc/server/my.machine.crt
|
||||
export TLS_KEY=/etc/server/my.machine.key
|
||||
static-file-server
|
||||
Retrieve with: wget https://my.machine/my.file
|
||||
|
||||
export FOLDER=/var/www
|
||||
export PORT=80
|
||||
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 SHOW_LISTING=false
|
||||
static-file-server
|
||||
Returns 'NOT FOUND': wget http://my.machine/
|
||||
`
|
||||
)
|
9
cli/help/help_test.go
Normal file
9
cli/help/help_test.go
Normal file
@ -0,0 +1,9 @@
|
||||
package help
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestRun(t *testing.T) {
|
||||
if err := Run(); nil != err {
|
||||
t.Errorf("While running help got %v", err)
|
||||
}
|
||||
}
|
39
cli/server/server.go
Normal file
39
cli/server/server.go
Normal file
@ -0,0 +1,39 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/halverneus/static-file-server/config"
|
||||
"github.com/halverneus/static-file-server/handle"
|
||||
)
|
||||
|
||||
// Run server.
|
||||
func Run() error {
|
||||
// Choose and set the appropriate, optimized static file serving function.
|
||||
var handler http.HandlerFunc
|
||||
if 0 == len(config.Get.URLPrefix) {
|
||||
handler = handle.Basic(config.Get.Folder)
|
||||
} else {
|
||||
handler = handle.Prefix(config.Get.Folder, config.Get.URLPrefix)
|
||||
}
|
||||
|
||||
// Determine whether index files should hidden.
|
||||
if !config.Get.ShowListing {
|
||||
handler = handle.IgnoreIndex(handler)
|
||||
}
|
||||
|
||||
// Serve files over HTTP or HTTPS based on paths to TLS files being provided.
|
||||
var listener handle.ListenerFunc
|
||||
if 0 < len(config.Get.TLSCert) {
|
||||
listener = handle.TLSListening(
|
||||
config.Get.TLSCert,
|
||||
config.Get.TLSKey,
|
||||
)
|
||||
} else {
|
||||
listener = handle.Listening()
|
||||
}
|
||||
|
||||
binding := fmt.Sprintf("%s:%d", config.Get.Host, config.Get.Port)
|
||||
return listener(binding, handler)
|
||||
}
|
35
cli/version/version.go
Normal file
35
cli/version/version.go
Normal file
@ -0,0 +1,35 @@
|
||||
package version
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"runtime"
|
||||
)
|
||||
|
||||
// Run print operation.
|
||||
func Run() error {
|
||||
fmt.Printf("%s\n%s\n", Text, GoVersionText)
|
||||
return nil
|
||||
}
|
||||
|
||||
var (
|
||||
// MajorVersion of static-file-server.
|
||||
MajorVersion = 1
|
||||
|
||||
// MinorVersion of static-file-server.
|
||||
MinorVersion = 3
|
||||
|
||||
// FixVersion of static-file-server.
|
||||
FixVersion = 0
|
||||
|
||||
// Text for directly accessing the static-file-server version.
|
||||
Text = fmt.Sprintf(
|
||||
"Version %d.%d.%d",
|
||||
MajorVersion,
|
||||
MinorVersion,
|
||||
FixVersion,
|
||||
)
|
||||
|
||||
// GoVersionText for directly accessing the version of the Go runtime
|
||||
// compiled with the static-file-server.
|
||||
GoVersionText = runtime.Version()
|
||||
)
|
9
cli/version/version_test.go
Normal file
9
cli/version/version_test.go
Normal file
@ -0,0 +1,9 @@
|
||||
package version
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestVersion(t *testing.T) {
|
||||
if err := Run(); nil != err {
|
||||
t.Errorf("While running version got %v", err)
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user