mirror of
https://github.com/halverneus/static-file-server.git
synced 2024-11-24 09:05:30 +00:00
Extracted file handlers. Unit tests required.
This commit is contained in:
parent
3700c31599
commit
755e0114f1
@ -2,9 +2,10 @@ FROM golang:1.10.3 as builder
|
||||
|
||||
ENV BUILD_DIR /go/src/github.com/halverneus/static-file-server
|
||||
ENV MAIN github.com/halverneus/static-file-server/bin/serve
|
||||
ENV DEP_VERSION v0.4.1
|
||||
|
||||
RUN curl -fsSL -o /usr/local/bin/dep \
|
||||
https://github.com/golang/dep/releases/download/v0.4.1/dep-linux-amd64 && \
|
||||
https://github.com/golang/dep/releases/download/$DEP_VERSION/dep-linux-amd64 && \
|
||||
chmod +x /usr/local/bin/dep
|
||||
|
||||
RUN mkdir -p ${BUILD_DIR}
|
||||
@ -12,7 +13,7 @@ WORKDIR ${BUILD_DIR}
|
||||
COPY . .
|
||||
|
||||
RUN dep ensure -vendor-only
|
||||
RUN go test ./...
|
||||
RUN go test -race -cover ./...
|
||||
RUN CGO_ENABLED=0 go build -a -installsuffix cgo -o /serve ${MAIN}
|
||||
|
||||
FROM scratch
|
||||
|
@ -8,6 +8,7 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/halverneus/static-file-server/config"
|
||||
"github.com/halverneus/static-file-server/handle"
|
||||
)
|
||||
|
||||
var (
|
||||
@ -155,95 +156,27 @@ func main() {
|
||||
// Choose and set the appropriate, optimized static file serving function.
|
||||
var handler http.HandlerFunc
|
||||
if 0 == len(config.Get.URLPrefix) {
|
||||
handler = handleListing(config.Get.ShowListing, basicHandler(config.Get.Folder))
|
||||
handler = handle.Basic(config.Get.Folder)
|
||||
} else {
|
||||
handler = handleListing(config.Get.ShowListing, prefixHandler(config.Get.Folder, config.Get.URLPrefix))
|
||||
handler = handle.Prefix(config.Get.Folder, config.Get.URLPrefix)
|
||||
}
|
||||
|
||||
// Determine whether index files should hidden.
|
||||
if !config.Get.ShowListing {
|
||||
handler = handle.IgnoreIndex(handler)
|
||||
}
|
||||
http.HandleFunc("/", handler)
|
||||
|
||||
// Serve files over HTTP or HTTPS based on paths to TLS files being provided.
|
||||
binding := fmt.Sprintf("%s:%d", config.Get.Host, config.Get.Port)
|
||||
if 0 == len(config.Get.TLSCert) {
|
||||
log.Fatalln(http.ListenAndServe(binding, nil))
|
||||
} else {
|
||||
log.Fatalln(http.ListenAndServeTLS(
|
||||
binding,
|
||||
var listener handle.ListenerFunc
|
||||
if 0 < len(config.Get.TLSCert) {
|
||||
listener = handle.TLSListening(
|
||||
config.Get.TLSCert,
|
||||
config.Get.TLSKey,
|
||||
nil,
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
// handleListing wraps an HTTP request. In the event of a folder root request,
|
||||
// setting 'show' to false will automatically return 'NOT FOUND' whereas true
|
||||
// will attempt to retrieve the index file of that directory.
|
||||
func handleListing(show bool, serve http.HandlerFunc) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
if !show && strings.HasSuffix(r.URL.Path, "/") {
|
||||
http.NotFound(w, r)
|
||||
return
|
||||
}
|
||||
serve(w, r)
|
||||
}
|
||||
}
|
||||
|
||||
// basicHandler serves files from the folder passed.
|
||||
func basicHandler(folder string) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
http.ServeFile(w, r, folder+r.URL.Path)
|
||||
}
|
||||
}
|
||||
|
||||
// prefixHandler removes the URL path prefix before serving files from the
|
||||
// folder passed.
|
||||
func prefixHandler(folder, urlPrefix string) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
if !strings.HasPrefix(r.URL.Path, urlPrefix) {
|
||||
http.NotFound(w, r)
|
||||
return
|
||||
}
|
||||
http.ServeFile(w, r, folder+strings.TrimPrefix(r.URL.Path, urlPrefix))
|
||||
}
|
||||
}
|
||||
|
||||
// env returns the value for an environment variable or, if not set, a fallback
|
||||
// value.
|
||||
func env(key, fallback string) string {
|
||||
if value := os.Getenv(key); 0 < len(value) {
|
||||
return value
|
||||
}
|
||||
return fallback
|
||||
}
|
||||
|
||||
// strAsBool converts the intent of the passed value into a boolean
|
||||
// representation.
|
||||
func strAsBool(value string) (result bool, err error) {
|
||||
lvalue := strings.ToLower(value)
|
||||
switch lvalue {
|
||||
case "0", "false", "f", "no", "n":
|
||||
result = false
|
||||
case "1", "true", "t", "yes", "y":
|
||||
result = true
|
||||
default:
|
||||
result = false
|
||||
msg := "Unknown conversion from string to bool for value '%s'"
|
||||
err = fmt.Errorf(msg, value)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// envAsBool returns the value for an environment variable or, if not set, a
|
||||
// fallback value as a boolean.
|
||||
func envAsBool(key string, fallback bool) bool {
|
||||
value := env(key, fmt.Sprintf("%t", fallback))
|
||||
result, err := strAsBool(value)
|
||||
if nil != err {
|
||||
log.Printf(
|
||||
"Invalid value for '%s': %v\nUsing fallback: %t",
|
||||
key, err, fallback,
|
||||
)
|
||||
return fallback
|
||||
} else {
|
||||
listener = handle.Listening()
|
||||
}
|
||||
return result
|
||||
|
||||
binding := fmt.Sprintf("%s:%d", config.Get.Host, config.Get.Port)
|
||||
log.Fatalln(listener(binding, handler))
|
||||
}
|
||||
|
57
handle/handle.go
Normal file
57
handle/handle.go
Normal file
@ -0,0 +1,57 @@
|
||||
package handle
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type ListenerFunc func(string, http.HandlerFunc) error
|
||||
|
||||
// Basic file handler servers files from the passed folder.
|
||||
func Basic(folder string) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
http.ServeFile(w, r, folder+r.URL.Path)
|
||||
}
|
||||
}
|
||||
|
||||
// Prefix file handler is an alternative to Basic where a URL prefix is removed
|
||||
// prior to serving a file (http://my.machine/prefix/file.txt will serve
|
||||
// file.txt from the root of the folder being served (ignoring 'prefix')).
|
||||
func Prefix(folder, urlPrefix string) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
if !strings.HasPrefix(r.URL.Path, urlPrefix) {
|
||||
http.NotFound(w, r)
|
||||
return
|
||||
}
|
||||
http.ServeFile(w, r, folder+strings.TrimPrefix(r.URL.Path, urlPrefix))
|
||||
}
|
||||
}
|
||||
|
||||
// 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.
|
||||
func IgnoreIndex(serve http.HandlerFunc) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
if strings.HasSuffix(r.URL.Path, "/") {
|
||||
http.NotFound(w, r)
|
||||
return
|
||||
}
|
||||
serve(w, r)
|
||||
}
|
||||
}
|
||||
|
||||
// Listening function for serving the handler function.
|
||||
func Listening() ListenerFunc {
|
||||
return func(binding string, handler http.HandlerFunc) error {
|
||||
http.HandleFunc("/", handler)
|
||||
return http.ListenAndServe(binding, nil)
|
||||
}
|
||||
}
|
||||
|
||||
// TLSListening function for serving the handler function with encryption.
|
||||
func TLSListening(tlsCert, tlsKey string) ListenerFunc {
|
||||
return func(binding string, handler http.HandlerFunc) error {
|
||||
http.HandleFunc("/", handler)
|
||||
return http.ListenAndServeTLS(binding, tlsCert, tlsKey, nil)
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user