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 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'", |
||||
) |
||||
if err := cli.Execute(); nil != err { |
||||
log.Fatalf("Error: %v\n", err) |
||||
} |
||||
|
||||
// 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)) |
||||
} |
||||
|
@ -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 |
||||
} |
@ -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) |
||||
} |
||||
}) |
||||
} |
||||
} |
@ -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() |
||||
} |
||||
} |
@ -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) |
||||
} |
||||
}) |
||||
} |
||||
} |
@ -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/
|
||||
` |
||||
) |
@ -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) |
||||
} |
||||
} |
@ -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) |
||||
} |
@ -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() |
||||
) |
@ -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