Files
aego/app/edit/web_preview.go
sanspie 5eb1832907
ci-platforms / darwin amd64 smoke (push) Skipped
ci / build (amd64, linux, ubuntu-24.04) (push) Failing after 15m28s
ci / release (push) Skipped
ci-platforms / windows amd64 smoke (push) Skipped
ci-platforms / darwin arm64 smoke (push) Skipped
ci / checks (push) Successful in 7m47s
Complete Stage 12 for v0.12.0
2026-11-05 11:46:53 +03:00

74 lines
1.6 KiB
Go

package edit
import (
"io/fs"
"net"
"net/http"
"os"
"sync"
"time"
)
type webPreview struct {
mu sync.Mutex
server *http.Server
root *os.Root
listener net.Listener
dir, url string
cleanup func()
}
func (p *webPreview) stop() {
if p.server != nil {
_ = p.listener.Close()
_ = p.server.Close()
p.server = nil
}
if p.root != nil {
_ = p.root.Close()
p.root = nil
}
if p.cleanup != nil {
p.cleanup()
p.cleanup = nil
}
p.dir, p.url = "", ""
}
func (p *webPreview) close() { p.mu.Lock(); defer p.mu.Unlock(); p.stop() }
func (p *webPreview) serve(dir string, cleanup func(), valid func() bool) (string, error) {
p.mu.Lock()
defer p.mu.Unlock()
if valid != nil && !valid() {
return "", fs.ErrClosed
}
if dir == p.dir {
return p.url, nil
}
root, err := os.OpenRoot(dir)
if err != nil {
return "", err
}
ln, err := net.Listen("tcp", "127.0.0.1:0")
if err != nil {
root.Close()
return "", err
}
files := http.FileServerFS(root.FS())
host := ln.Addr().String()
server := &http.Server{ReadHeaderTimeout: 5 * time.Second, Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.Host != host {
http.Error(w, "invalid preview host", http.StatusForbidden)
return
}
w.Header().Set("Cross-Origin-Opener-Policy", "same-origin")
w.Header().Set("Cross-Origin-Embedder-Policy", "require-corp")
w.Header().Set("Cache-Control", "no-store")
files.ServeHTTP(w, r)
})}
p.stop()
p.server, p.root, p.listener, p.cleanup, p.dir, p.url = server, root, ln, cleanup, dir, "http://"+host+"/"
go server.Serve(ln)
return p.url, nil
}