162 lines
3.4 KiB
Go
162 lines
3.4 KiB
Go
package main
|
|
|
|
import (
|
|
"bufio"
|
|
"net/http"
|
|
"net/url"
|
|
"os"
|
|
"os/exec"
|
|
"os/signal"
|
|
"strings"
|
|
"syscall"
|
|
"time"
|
|
)
|
|
|
|
const junkaddr = "localhost:18012"
|
|
const proxybufsize = 4 << 10
|
|
|
|
type JunkConf struct {
|
|
Proxy string
|
|
Cmd *exec.Cmd
|
|
}
|
|
|
|
func main() {
|
|
status := cmain(len(os.Args), os.Args)
|
|
os.Setenv("status", status)
|
|
if status != "" {
|
|
os.Exit(1)
|
|
}
|
|
}
|
|
|
|
func proxy(w http.ResponseWriter, r *http.Request, proxy_path string) {
|
|
var err error
|
|
r.RequestURI = ""
|
|
r.URL, err = url.Parse(proxy_path)
|
|
if err != nil {
|
|
w.WriteHeader(http.StatusBadRequest)
|
|
w.Write([]byte(err.Error()))
|
|
return
|
|
}
|
|
resp, err := http.DefaultClient.Do(r)
|
|
if err != nil {
|
|
w.WriteHeader(http.StatusInternalServerError)
|
|
w.Write([]byte(err.Error()))
|
|
return
|
|
}
|
|
for k, v := range resp.Header {
|
|
for _, x := range v {
|
|
w.Header().Add(k, x)
|
|
}
|
|
}
|
|
w.WriteHeader(resp.StatusCode)
|
|
buf := make([]byte, proxybufsize)
|
|
for {
|
|
n, err := resp.Body.Read(buf)
|
|
w.Write(buf[:n])
|
|
if err != nil {
|
|
break
|
|
}
|
|
}
|
|
}
|
|
|
|
func cmain(argc int, argv []string) string {
|
|
fileserver := http.FileServer(http.Dir(""))
|
|
cmdmap := map[string]JunkConf{}
|
|
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
|
p1 := r.URL.Path
|
|
p := strings.Split(p1, "/")[1:]
|
|
seg := p[0]
|
|
if seg == "" {
|
|
fileserver.ServeHTTP(w, r)
|
|
return
|
|
}
|
|
vc, err := r.Cookie("view")
|
|
if err == nil && seg != vc.Value {
|
|
w.Header().Add("Location", "/"+vc.Value+p1)
|
|
w.WriteHeader(http.StatusFound)
|
|
return
|
|
}
|
|
if conf, ok := cmdmap[seg]; ok {
|
|
proxy_path := conf.Proxy + "/" + strings.Join(p[1:], "/")
|
|
proxy(w, r, proxy_path)
|
|
return
|
|
}
|
|
if f, err := os.Open(seg + "/junkrc"); err == nil {
|
|
// info, err := f.Stat()
|
|
s := bufio.NewScanner(f)
|
|
conf := JunkConf{}
|
|
for s.Scan() {
|
|
line := s.Text()
|
|
if len(line) > 2 && line[0:2] == "#;" {
|
|
note := line[2:]
|
|
i := strings.IndexByte(note, '=')
|
|
if i == -1 {
|
|
continue
|
|
}
|
|
key, value := note[:i], note[i+1:]
|
|
switch key {
|
|
case "proxy":
|
|
conf.Proxy = value
|
|
}
|
|
}
|
|
}
|
|
f.Close()
|
|
println("exec:", seg+"/junkrc")
|
|
cmd := exec.Command("./junkrc")
|
|
cmd.Dir = seg
|
|
// cmd.Stdout = os.Stdout
|
|
conf.Cmd = cmd
|
|
err = cmd.Start()
|
|
if err != nil {
|
|
w.WriteHeader(http.StatusServiceUnavailable)
|
|
w.Write([]byte(err.Error()))
|
|
return
|
|
}
|
|
waits := 0
|
|
for {
|
|
_, err := http.Head(conf.Proxy)
|
|
if err != nil {
|
|
if cmd.ProcessState != nil {
|
|
cmd.Wait()
|
|
w.WriteHeader(http.StatusServiceUnavailable)
|
|
w.Write([]byte("process exited early: " + cmd.ProcessState.String()))
|
|
return
|
|
} else {
|
|
waits++
|
|
time.Sleep(500 * time.Millisecond)
|
|
if waits > 10 {
|
|
w.WriteHeader(http.StatusServiceUnavailable)
|
|
w.Write([]byte("starting process: timeout"))
|
|
cmd.Process.Kill()
|
|
cmd.Wait()
|
|
return
|
|
}
|
|
continue
|
|
}
|
|
}
|
|
cmdmap[seg] = conf
|
|
break
|
|
}
|
|
w.Header().Add("Set-Cookie", "view="+seg+"; Path=/; SameSite=Strict; HttpOnly")
|
|
w.Header().Add("Location", p1)
|
|
w.WriteHeader(http.StatusFound)
|
|
// proxy_path := conf.Proxy + "/" + strings.Join(p[1:], "/")
|
|
// proxy(w, r, proxy_path)
|
|
return
|
|
}
|
|
fileserver.ServeHTTP(w, r)
|
|
})
|
|
lock := make(chan os.Signal, 1)
|
|
signal.Notify(lock, os.Interrupt, syscall.SIGTERM)
|
|
go func() {
|
|
println("started:", "http://"+junkaddr+"/")
|
|
http.ListenAndServe(junkaddr, nil)
|
|
}()
|
|
<-lock
|
|
for k, v := range cmdmap {
|
|
println("killing:", k)
|
|
v.Cmd.Process.Kill()
|
|
v.Cmd.Wait()
|
|
}
|
|
return ""
|
|
}
|