Skip to content

Commit

Permalink
Merge pull request #23 from tschaub/prefix
Browse files Browse the repository at this point in the history
Support a prefix for URL paths
  • Loading branch information
tschaub authored Aug 8, 2024
2 parents ca96206 + 7d0813f commit 9755e5c
Show file tree
Hide file tree
Showing 2 changed files with 259 additions and 18 deletions.
45 changes: 36 additions & 9 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"html/template"
"io"
"net/http"
"net/url"
"os"
"path"
"path/filepath"
Expand All @@ -26,25 +27,46 @@ func main() {
type Serve struct {
Port int `help:"Listen on this port." default:"4000"`
Dir string `help:"Serve files from this directory." arg:"" type:"existingdir"`
Prefix string `help:"Prefix all URL paths with this value." default:"/"`
Cors bool `help:"Include CORS support (on by default)." default:"true" negatable:""`
Dot bool `help:"Serve dot files (files prefixed with a '.')." default:"false"`
ExplicitIndex bool `help:"Only serve index.html files if URL path includes it." default:"false"`
}

func normalizePrefix(base string, prefix string) (string, error) {
joined, err := url.JoinPath(base, prefix, "/")
if err != nil {
return "", err
}

u, err := url.Parse(joined)
if err != nil {
return "", err
}

return u.Path, nil
}

func (s *Serve) Run() error {
handler := s.handler()
base := fmt.Sprintf("http://localhost:%d", s.Port)
prefix, err := normalizePrefix(base, s.Prefix)
if err != nil {
return fmt.Errorf("trouble creating URL prefix: %w", err)
}
s.Prefix = prefix

fmt.Printf("Serving %s on http://localhost:%d/\n", s.Dir, s.Port)
handler := s.handler()
fmt.Printf("Serving %s on %s%s\n", s.Dir, base, s.Prefix)
return http.ListenAndServe(fmt.Sprintf(":%d", s.Port), handler)
}

func (s *Serve) handler() http.Handler {
mux := http.NewServeMux()

dir := http.Dir(s.Dir)
mux.Handle("/", http.FileServer(dir))
mux.Handle(s.Prefix, http.StripPrefix(s.Prefix, http.FileServer(dir)))

handler := withIndex(string(dir), s.Dot, s.ExplicitIndex, http.Handler(mux))
handler := withIndex(string(dir), s.Prefix, s.Dot, s.ExplicitIndex, http.Handler(mux))
if !s.Dot {
handler = excludeDot(handler)
}
Expand Down Expand Up @@ -88,11 +110,16 @@ const (
//go:embed index.html
var indexHtml string

func withIndex(dir string, dot bool, explicitIndex bool, handler http.Handler) http.Handler {
func withIndex(dir string, prefix string, dot bool, explicitIndex bool, handler http.Handler) http.Handler {
indexTemplate := template.Must(template.New("index").Parse(indexHtml))
base := filepath.Base(dir)
return http.HandlerFunc(func(response http.ResponseWriter, request *http.Request) {
urlPath := request.URL.Path
if !strings.HasPrefix(request.URL.Path, prefix) {
http.NotFound(response, request)
return
}

urlPath := "/" + strings.TrimPrefix(request.URL.Path, prefix)

if strings.HasSuffix(urlPath, "/index.html") && explicitIndex {
// we need to avoid the built-in redirect
Expand Down Expand Up @@ -142,7 +169,7 @@ func withIndex(dir string, dot bool, explicitIndex bool, handler http.Handler) h
}
entry := &Entry{
Name: name,
Path: path.Join(urlPath, name),
Path: path.Join(prefix, urlPath, name),
}
if item.IsDir() {
entry.Type = folderType
Expand Down Expand Up @@ -179,7 +206,7 @@ func withIndex(dir string, dot bool, explicitIndex bool, handler http.Handler) h
if urlPath != "/" {
parentEntry := &Entry{
Name: "..",
Path: path.Join(urlPath, ".."),
Path: path.Join(prefix, urlPath, ".."),
Type: folderType,
}
entries = append([]*Entry{parentEntry}, entries...)
Expand All @@ -191,7 +218,7 @@ func withIndex(dir string, dot bool, explicitIndex bool, handler http.Handler) h
for i, part := range parentParts {
entry := &Entry{
Name: part,
Path: strings.Join(parentParts[:i+1], "/") + "/",
Path: path.Join(prefix, strings.Join(parentParts[:i+1], "/")) + "/",
Type: folderType,
}
if part == "" {
Expand Down
Loading

0 comments on commit 9755e5c

Please sign in to comment.