新增文档根目录处理逻辑
This commit is contained in:
parent
6693cfe68f
commit
4b346afaec
cmd
|
@ -4,6 +4,7 @@ import (
|
|||
"context"
|
||||
"embed"
|
||||
"flag"
|
||||
"net/http"
|
||||
|
||||
"git.nspix.com/golang/kos"
|
||||
)
|
||||
|
@ -15,7 +16,7 @@ type subServer struct {
|
|||
}
|
||||
|
||||
func (s *subServer) Start(ctx context.Context) (err error) {
|
||||
kos.Http().Embed("/ui/web", "web", webDir)
|
||||
kos.Http().Root("/web", http.FS(webDir))
|
||||
return
|
||||
}
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
|
||||
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
||||
<title>Document</title>
|
||||
<link rel="stylesheet" href="css/index.css">
|
||||
<link rel="stylesheet" href="/css/index.css">
|
||||
</head>
|
||||
<body>
|
||||
<h1>Hello</h1>
|
||||
|
|
|
@ -3,6 +3,9 @@ package http
|
|||
import (
|
||||
"io/fs"
|
||||
"net/http"
|
||||
"os"
|
||||
"path"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
|
@ -10,6 +13,9 @@ type (
|
|||
FS struct {
|
||||
fs http.FileSystem
|
||||
modtime time.Time
|
||||
prefix string
|
||||
indexFile string
|
||||
denyDirectory bool
|
||||
}
|
||||
|
||||
File struct {
|
||||
|
@ -74,11 +80,54 @@ func (file *File) Stat() (fs.FileInfo, error) {
|
|||
return newFileInfo(fi, file.modtime), nil
|
||||
}
|
||||
|
||||
func (fs *FS) DenyAccessDirectory() {
|
||||
fs.denyDirectory = true
|
||||
}
|
||||
|
||||
func (fs *FS) SetPrefix(prefix string) {
|
||||
if prefix != "" {
|
||||
if prefix[0] != '/' {
|
||||
prefix = "/" + prefix
|
||||
}
|
||||
prefix = strings.TrimRight(prefix, "/")
|
||||
fs.prefix = prefix
|
||||
}
|
||||
}
|
||||
|
||||
func (fs *FS) SetIndexFile(indexFile string) {
|
||||
fs.indexFile = indexFile
|
||||
}
|
||||
|
||||
func (fs *FS) Open(name string) (http.File, error) {
|
||||
var (
|
||||
needRetry bool
|
||||
)
|
||||
if name == "" || name == "/" {
|
||||
needRetry = true
|
||||
}
|
||||
if fs.prefix != "" {
|
||||
if !strings.HasPrefix(name, fs.prefix) {
|
||||
name = path.Join(fs.prefix, name)
|
||||
}
|
||||
}
|
||||
fp, err := fs.fs.Open(name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if fs.denyDirectory {
|
||||
state, err := fp.Stat()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if state.IsDir() {
|
||||
if needRetry {
|
||||
if fs.indexFile != "" {
|
||||
return fs.Open(path.Join(name, fs.indexFile))
|
||||
}
|
||||
}
|
||||
return nil, os.ErrPermission
|
||||
}
|
||||
}
|
||||
return &File{fp: fp, modtime: fs.modtime}, nil
|
||||
}
|
||||
|
||||
|
|
|
@ -22,6 +22,8 @@ type Server struct {
|
|||
router *router.Router
|
||||
middleware []Middleware
|
||||
uptime time.Time
|
||||
enableDocumentRoot bool
|
||||
fileSystem http.FileSystem
|
||||
anyRequests map[string]http.Handler
|
||||
}
|
||||
|
||||
|
@ -91,6 +93,15 @@ func (svr *Server) Group(prefix string, routes []Route, middleware ...Middleware
|
|||
}
|
||||
}
|
||||
|
||||
func (svr *Server) Root(prefix string, fs http.FileSystem) {
|
||||
svr.enableDocumentRoot = true
|
||||
s := newFS(svr.uptime, fs)
|
||||
s.SetPrefix(prefix)
|
||||
s.DenyAccessDirectory()
|
||||
s.SetIndexFile("/index.html")
|
||||
svr.fileSystem = s
|
||||
}
|
||||
|
||||
func (svr *Server) Embed(prefix string, root string, embedFs embed.FS) {
|
||||
routePath := prefix
|
||||
if !strings.HasSuffix(routePath, "/*filepath") {
|
||||
|
@ -159,12 +170,24 @@ func (svr *Server) handleRequest(res http.ResponseWriter, req *http.Request) {
|
|||
}
|
||||
|
||||
func (svr *Server) ServeHTTP(writer http.ResponseWriter, request *http.Request) {
|
||||
var (
|
||||
err error
|
||||
file http.File
|
||||
)
|
||||
for prefix, handle := range svr.anyRequests {
|
||||
if strings.HasPrefix(request.URL.Path, prefix) {
|
||||
handle.ServeHTTP(writer, request)
|
||||
return
|
||||
}
|
||||
}
|
||||
if svr.enableDocumentRoot && request.Method == http.MethodGet {
|
||||
uri := path.Clean(request.URL.Path)
|
||||
if file, err = svr.fileSystem.Open(uri); err == nil {
|
||||
http.ServeContent(writer, request, path.Base(uri), svr.uptime, file)
|
||||
err = file.Close()
|
||||
return
|
||||
}
|
||||
}
|
||||
switch request.Method {
|
||||
case http.MethodOptions:
|
||||
svr.handleOption(writer, request)
|
||||
|
|
Loading…
Reference in New Issue