annotate main.go @ 11:350589d762a0 default tip

add cgi, remove tls, update docs
author Atarwn Gard <a@qwa.su>
date Thu, 19 Mar 2026 20:00:49 +0500
parents ec97184ea63d
children
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
0
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
1 package main
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
2
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
3 import (
8
2ffb8028ccbb add loggingmodes and fix path matching
Atarwn Gard <a@qwa.su>
parents: 7
diff changeset
4 "bufio"
0
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
5 "crypto/tls"
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
6 "fmt"
3
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 2
diff changeset
7 "io"
0
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
8 "log"
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
9 "net"
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
10 "net/http"
11
350589d762a0 add cgi, remove tls, update docs
Atarwn Gard <a@qwa.su>
parents: 9
diff changeset
11 "net/http/cgi"
0
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
12 "net/http/httputil"
8
2ffb8028ccbb add loggingmodes and fix path matching
Atarwn Gard <a@qwa.su>
parents: 7
diff changeset
13 "net/textproto"
0
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
14 "net/url"
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
15 "os"
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
16 "path"
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
17 "path/filepath"
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
18 "regexp"
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
19 "runtime"
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
20 "strconv"
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
21 "strings"
8
2ffb8028ccbb add loggingmodes and fix path matching
Atarwn Gard <a@qwa.su>
parents: 7
diff changeset
22 "time"
0
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
23
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
24 "d2o/fcgi"
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
25 "d2o/icf"
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
26 )
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
27
8
2ffb8028ccbb add loggingmodes and fix path matching
Atarwn Gard <a@qwa.su>
parents: 7
diff changeset
28 type loggingMode uint8
2ffb8028ccbb add loggingmodes and fix path matching
Atarwn Gard <a@qwa.su>
parents: 7
diff changeset
29
2ffb8028ccbb add loggingmodes and fix path matching
Atarwn Gard <a@qwa.su>
parents: 7
diff changeset
30 const (
2ffb8028ccbb add loggingmodes and fix path matching
Atarwn Gard <a@qwa.su>
parents: 7
diff changeset
31 logNone loggingMode = iota
2ffb8028ccbb add loggingmodes and fix path matching
Atarwn Gard <a@qwa.su>
parents: 7
diff changeset
32 logAccess
2ffb8028ccbb add loggingmodes and fix path matching
Atarwn Gard <a@qwa.su>
parents: 7
diff changeset
33 logVerbose
2ffb8028ccbb add loggingmodes and fix path matching
Atarwn Gard <a@qwa.su>
parents: 7
diff changeset
34 )
2ffb8028ccbb add loggingmodes and fix path matching
Atarwn Gard <a@qwa.su>
parents: 7
diff changeset
35
2ffb8028ccbb add loggingmodes and fix path matching
Atarwn Gard <a@qwa.su>
parents: 7
diff changeset
36 var (
2ffb8028ccbb add loggingmodes and fix path matching
Atarwn Gard <a@qwa.su>
parents: 7
diff changeset
37 curLoggingMode loggingMode = logVerbose
2ffb8028ccbb add loggingmodes and fix path matching
Atarwn Gard <a@qwa.su>
parents: 7
diff changeset
38 accessLogger = log.New(os.Stderr, "", log.LstdFlags)
2ffb8028ccbb add loggingmodes and fix path matching
Atarwn Gard <a@qwa.su>
parents: 7
diff changeset
39 )
2ffb8028ccbb add loggingmodes and fix path matching
Atarwn Gard <a@qwa.su>
parents: 7
diff changeset
40
2ffb8028ccbb add loggingmodes and fix path matching
Atarwn Gard <a@qwa.su>
parents: 7
diff changeset
41 func setLoggingMode(m loggingMode) {
2ffb8028ccbb add loggingmodes and fix path matching
Atarwn Gard <a@qwa.su>
parents: 7
diff changeset
42 curLoggingMode = m
2ffb8028ccbb add loggingmodes and fix path matching
Atarwn Gard <a@qwa.su>
parents: 7
diff changeset
43 switch m {
2ffb8028ccbb add loggingmodes and fix path matching
Atarwn Gard <a@qwa.su>
parents: 7
diff changeset
44 case logNone:
2ffb8028ccbb add loggingmodes and fix path matching
Atarwn Gard <a@qwa.su>
parents: 7
diff changeset
45 log.SetOutput(io.Discard)
2ffb8028ccbb add loggingmodes and fix path matching
Atarwn Gard <a@qwa.su>
parents: 7
diff changeset
46 case logAccess:
2ffb8028ccbb add loggingmodes and fix path matching
Atarwn Gard <a@qwa.su>
parents: 7
diff changeset
47 log.SetOutput(io.Discard)
2ffb8028ccbb add loggingmodes and fix path matching
Atarwn Gard <a@qwa.su>
parents: 7
diff changeset
48 case logVerbose:
2ffb8028ccbb add loggingmodes and fix path matching
Atarwn Gard <a@qwa.su>
parents: 7
diff changeset
49 // keep standard logger output
2ffb8028ccbb add loggingmodes and fix path matching
Atarwn Gard <a@qwa.su>
parents: 7
diff changeset
50 }
2ffb8028ccbb add loggingmodes and fix path matching
Atarwn Gard <a@qwa.su>
parents: 7
diff changeset
51 }
2ffb8028ccbb add loggingmodes and fix path matching
Atarwn Gard <a@qwa.su>
parents: 7
diff changeset
52
2ffb8028ccbb add loggingmodes and fix path matching
Atarwn Gard <a@qwa.su>
parents: 7
diff changeset
53 func accessEnabled() bool { return curLoggingMode == logAccess || curLoggingMode == logVerbose }
2ffb8028ccbb add loggingmodes and fix path matching
Atarwn Gard <a@qwa.su>
parents: 7
diff changeset
54 func verboseEnabled() bool { return curLoggingMode == logVerbose }
2ffb8028ccbb add loggingmodes and fix path matching
Atarwn Gard <a@qwa.su>
parents: 7
diff changeset
55
2ffb8028ccbb add loggingmodes and fix path matching
Atarwn Gard <a@qwa.su>
parents: 7
diff changeset
56 func accessPrintf(format string, args ...any) {
2ffb8028ccbb add loggingmodes and fix path matching
Atarwn Gard <a@qwa.su>
parents: 7
diff changeset
57 if accessEnabled() {
2ffb8028ccbb add loggingmodes and fix path matching
Atarwn Gard <a@qwa.su>
parents: 7
diff changeset
58 accessLogger.Printf(format, args...)
2ffb8028ccbb add loggingmodes and fix path matching
Atarwn Gard <a@qwa.su>
parents: 7
diff changeset
59 }
2ffb8028ccbb add loggingmodes and fix path matching
Atarwn Gard <a@qwa.su>
parents: 7
diff changeset
60 }
2ffb8028ccbb add loggingmodes and fix path matching
Atarwn Gard <a@qwa.su>
parents: 7
diff changeset
61
2ffb8028ccbb add loggingmodes and fix path matching
Atarwn Gard <a@qwa.su>
parents: 7
diff changeset
62 func verbosePrintf(format string, args ...any) {
2ffb8028ccbb add loggingmodes and fix path matching
Atarwn Gard <a@qwa.su>
parents: 7
diff changeset
63 if verboseEnabled() {
2ffb8028ccbb add loggingmodes and fix path matching
Atarwn Gard <a@qwa.su>
parents: 7
diff changeset
64 log.Printf(format, args...)
2ffb8028ccbb add loggingmodes and fix path matching
Atarwn Gard <a@qwa.su>
parents: 7
diff changeset
65 }
2ffb8028ccbb add loggingmodes and fix path matching
Atarwn Gard <a@qwa.su>
parents: 7
diff changeset
66 }
2ffb8028ccbb add loggingmodes and fix path matching
Atarwn Gard <a@qwa.su>
parents: 7
diff changeset
67
0
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
68 func main() {
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
69 cfgPath := "/etc/d2obase"
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
70 if len(os.Args) > 1 {
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
71 cfgPath = os.Args[1]
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
72 }
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
73
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
74 f, err := os.Open(cfgPath)
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
75 if err != nil {
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
76 log.Fatalf("d2o: cannot open config: %v", err)
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
77 }
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
78 cfg, err := icf.Parse(f)
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
79 f.Close()
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
80 if err != nil {
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
81 log.Fatalf("d2o: config error: %v", err)
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
82 }
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
83
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
84 for _, d := range cfg.Abstract("d2o") {
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
85 switch d.Key {
8
2ffb8028ccbb add loggingmodes and fix path matching
Atarwn Gard <a@qwa.su>
parents: 7
diff changeset
86 case "logging":
2ffb8028ccbb add loggingmodes and fix path matching
Atarwn Gard <a@qwa.su>
parents: 7
diff changeset
87 switch strings.ToLower(safeArg(d.Args, 0)) {
2ffb8028ccbb add loggingmodes and fix path matching
Atarwn Gard <a@qwa.su>
parents: 7
diff changeset
88 case "", "verbose":
2ffb8028ccbb add loggingmodes and fix path matching
Atarwn Gard <a@qwa.su>
parents: 7
diff changeset
89 setLoggingMode(logVerbose)
2ffb8028ccbb add loggingmodes and fix path matching
Atarwn Gard <a@qwa.su>
parents: 7
diff changeset
90 case "none":
2ffb8028ccbb add loggingmodes and fix path matching
Atarwn Gard <a@qwa.su>
parents: 7
diff changeset
91 setLoggingMode(logNone)
2ffb8028ccbb add loggingmodes and fix path matching
Atarwn Gard <a@qwa.su>
parents: 7
diff changeset
92 case "access":
2ffb8028ccbb add loggingmodes and fix path matching
Atarwn Gard <a@qwa.su>
parents: 7
diff changeset
93 setLoggingMode(logAccess)
2ffb8028ccbb add loggingmodes and fix path matching
Atarwn Gard <a@qwa.su>
parents: 7
diff changeset
94 default:
2ffb8028ccbb add loggingmodes and fix path matching
Atarwn Gard <a@qwa.su>
parents: 7
diff changeset
95 log.Fatalf("d2o: unknown logging mode %q (expected none|access|verbose)", safeArg(d.Args, 0))
2ffb8028ccbb add loggingmodes and fix path matching
Atarwn Gard <a@qwa.su>
parents: 7
diff changeset
96 }
0
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
97 case "threads":
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
98 n, err := strconv.Atoi(safeArg(d.Args, 0))
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
99 if err == nil && n > 0 {
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
100 runtime.GOMAXPROCS(n)
8
2ffb8028ccbb add loggingmodes and fix path matching
Atarwn Gard <a@qwa.su>
parents: 7
diff changeset
101 verbosePrintf("d2o: GOMAXPROCS = %d", n)
0
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
102 }
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
103 }
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
104 }
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
105
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
106 ports := collectPorts(cfg)
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
107 if len(ports) == 0 {
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
108 log.Fatal("d2o: no port directives found in config")
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
109 }
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
110
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
111 h := &handler{cfg: cfg}
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
112 errCh := make(chan error, len(ports))
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
113
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
114 for _, pc := range ports {
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
115 go func(pc portConfig) {
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
116 errCh <- pc.listen(h)
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
117 }(pc)
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
118 }
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
119
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
120 log.Fatal(<-errCh)
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
121 }
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
122
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
123 // --- Port collection --------------------------------------------------------
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
124
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
125 type portConfig struct {
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
126 addr string
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
127 certFile string
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
128 keyFile string
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
129 isTLS bool
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
130 }
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
131
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
132 func (pc portConfig) listen(h http.Handler) error {
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
133 if !pc.isTLS {
8
2ffb8028ccbb add loggingmodes and fix path matching
Atarwn Gard <a@qwa.su>
parents: 7
diff changeset
134 verbosePrintf("d2o: listening on %s (http)", pc.addr)
0
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
135 return http.ListenAndServe(pc.addr, h)
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
136 }
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
137 cert, err := tls.LoadX509KeyPair(pc.certFile, pc.keyFile)
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
138 if err != nil {
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
139 return fmt.Errorf("d2o: tls: %w", err)
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
140 }
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
141 ln, err := tls.Listen("tcp", pc.addr, &tls.Config{
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
142 Certificates: []tls.Certificate{cert},
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
143 MinVersion: tls.VersionTLS12,
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
144 })
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
145 if err != nil {
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
146 return fmt.Errorf("d2o: listen %s: %w", pc.addr, err)
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
147 }
8
2ffb8028ccbb add loggingmodes and fix path matching
Atarwn Gard <a@qwa.su>
parents: 7
diff changeset
148 verbosePrintf("d2o: listening on %s (https)", pc.addr)
0
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
149 return http.Serve(ln, h)
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
150 }
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
151
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
152 func collectPorts(cfg *icf.Config) []portConfig {
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
153 seen := make(map[string]bool)
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
154 var out []portConfig
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
155
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
156 for _, b := range cfg.Blocks {
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
157 dirs := cfg.ResolveBlock(b, nil)
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
158
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
159 for _, d := range dirs {
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
160 switch d.Key {
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
161 case "port":
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
162 addr := ":" + safeArg(d.Args, 0)
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
163 if !seen[addr] {
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
164 seen[addr] = true
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
165 out = append(out, portConfig{addr: addr})
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
166 }
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
167 case "port+tls":
11
350589d762a0 add cgi, remove tls, update docs
Atarwn Gard <a@qwa.su>
parents: 9
diff changeset
168 // port+tls <port> <cert> <key>
0
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
169 addr := ":" + safeArg(d.Args, 0)
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
170 c := safeArg(d.Args, 1)
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
171 k := safeArg(d.Args, 2)
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
172 if !seen[addr] {
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
173 seen[addr] = true
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
174 out = append(out, portConfig{addr: addr, certFile: c, keyFile: k, isTLS: true})
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
175 }
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
176 }
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
177 }
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
178 }
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
179 return out
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
180 }
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
181
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
182 // --- HTTP Handler -----------------------------------------------------------
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
183
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
184 type handler struct {
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
185 cfg *icf.Config
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
186 }
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
187
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
188 func (h *handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
8
2ffb8028ccbb add loggingmodes and fix path matching
Atarwn Gard <a@qwa.su>
parents: 7
diff changeset
189 start := time.Now()
2ffb8028ccbb add loggingmodes and fix path matching
Atarwn Gard <a@qwa.su>
parents: 7
diff changeset
190 rr := &respRecorder{ResponseWriter: w, status: 0}
2ffb8028ccbb add loggingmodes and fix path matching
Atarwn Gard <a@qwa.su>
parents: 7
diff changeset
191
0
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
192 host := stripPort(r.Host)
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
193 reqPath := path.Clean(r.URL.Path)
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
194
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
195 dirs, caps := h.cfg.Match(host + reqPath)
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
196 if dirs == nil {
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
197 dirs, caps = h.cfg.Match(host)
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
198 }
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
199 if dirs == nil {
8
2ffb8028ccbb add loggingmodes and fix path matching
Atarwn Gard <a@qwa.su>
parents: 7
diff changeset
200 http.Error(rr, "not found", http.StatusNotFound)
2ffb8028ccbb add loggingmodes and fix path matching
Atarwn Gard <a@qwa.su>
parents: 7
diff changeset
201 rr.ensureStatus(http.StatusNotFound)
2ffb8028ccbb add loggingmodes and fix path matching
Atarwn Gard <a@qwa.su>
parents: 7
diff changeset
202 accessPrintf("d2o: %s %s%s -> %d %dB (%s)", r.Method, r.Host, r.URL.RequestURI(), rr.status, rr.bytes, time.Since(start).Truncate(time.Millisecond))
0
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
203 return
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
204 }
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
205
8
2ffb8028ccbb add loggingmodes and fix path matching
Atarwn Gard <a@qwa.su>
parents: 7
diff changeset
206 h.serve(rr, r, dirs, caps)
2ffb8028ccbb add loggingmodes and fix path matching
Atarwn Gard <a@qwa.su>
parents: 7
diff changeset
207 rr.ensureStatus(http.StatusOK)
2ffb8028ccbb add loggingmodes and fix path matching
Atarwn Gard <a@qwa.su>
parents: 7
diff changeset
208 accessPrintf("d2o: %s %s%s -> %d %dB (%s)", r.Method, r.Host, r.URL.RequestURI(), rr.status, rr.bytes, time.Since(start).Truncate(time.Millisecond))
0
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
209 }
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
210
8
2ffb8028ccbb add loggingmodes and fix path matching
Atarwn Gard <a@qwa.su>
parents: 7
diff changeset
211 func (h *handler) serve(w http.ResponseWriter, r *http.Request, dirs []icf.Directive, caps map[string]string) {
0
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
212 var (
5
07b6f06899e0 my tired ass deleted a fix that was partially working
Atarwn Gard <a@qwa.su>
parents: 3
diff changeset
213 rootDir string
07b6f06899e0 my tired ass deleted a fix that was partially working
Atarwn Gard <a@qwa.su>
parents: 3
diff changeset
214 rootShow bool
07b6f06899e0 my tired ass deleted a fix that was partially working
Atarwn Gard <a@qwa.su>
parents: 3
diff changeset
215 ndex []string
07b6f06899e0 my tired ass deleted a fix that was partially working
Atarwn Gard <a@qwa.su>
parents: 3
diff changeset
216 fcgiAddr string
07b6f06899e0 my tired ass deleted a fix that was partially working
Atarwn Gard <a@qwa.su>
parents: 3
diff changeset
217 fcgiPat string
11
350589d762a0 add cgi, remove tls, update docs
Atarwn Gard <a@qwa.su>
parents: 9
diff changeset
218 cgiExec string
350589d762a0 add cgi, remove tls, update docs
Atarwn Gard <a@qwa.su>
parents: 9
diff changeset
219 cgiPat string
5
07b6f06899e0 my tired ass deleted a fix that was partially working
Atarwn Gard <a@qwa.su>
parents: 3
diff changeset
220 rprxAddr string
07b6f06899e0 my tired ass deleted a fix that was partially working
Atarwn Gard <a@qwa.su>
parents: 3
diff changeset
221 rdirCode int
07b6f06899e0 my tired ass deleted a fix that was partially working
Atarwn Gard <a@qwa.su>
parents: 3
diff changeset
222 rdirURL string
0
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
223 )
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
224
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
225 for _, d := range dirs {
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
226 switch d.Key {
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
227 case "root":
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
228 rootDir = safeArg(d.Args, 0)
5
07b6f06899e0 my tired ass deleted a fix that was partially working
Atarwn Gard <a@qwa.su>
parents: 3
diff changeset
229 rootShow = safeArg(d.Args, 1) == "show"
07b6f06899e0 my tired ass deleted a fix that was partially working
Atarwn Gard <a@qwa.su>
parents: 3
diff changeset
230 case "ndex":
07b6f06899e0 my tired ass deleted a fix that was partially working
Atarwn Gard <a@qwa.su>
parents: 3
diff changeset
231 ndex = d.Args
0
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
232 case "fcgi":
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
233 fcgiAddr = safeArg(d.Args, 0)
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
234 fcgiPat = safeArg(d.Args, 1)
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
235 if fcgiPat == "" {
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
236 fcgiPat = "*"
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
237 }
11
350589d762a0 add cgi, remove tls, update docs
Atarwn Gard <a@qwa.su>
parents: 9
diff changeset
238 case "cgi":
350589d762a0 add cgi, remove tls, update docs
Atarwn Gard <a@qwa.su>
parents: 9
diff changeset
239 // cgi <executable> [<glob-pattern>]
350589d762a0 add cgi, remove tls, update docs
Atarwn Gard <a@qwa.su>
parents: 9
diff changeset
240 cgiExec = safeArg(d.Args, 0)
350589d762a0 add cgi, remove tls, update docs
Atarwn Gard <a@qwa.su>
parents: 9
diff changeset
241 cgiPat = safeArg(d.Args, 1)
350589d762a0 add cgi, remove tls, update docs
Atarwn Gard <a@qwa.su>
parents: 9
diff changeset
242 if cgiPat == "" {
350589d762a0 add cgi, remove tls, update docs
Atarwn Gard <a@qwa.su>
parents: 9
diff changeset
243 cgiPat = "*"
350589d762a0 add cgi, remove tls, update docs
Atarwn Gard <a@qwa.su>
parents: 9
diff changeset
244 }
0
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
245 case "rprx":
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
246 rprxAddr = safeArg(d.Args, 0)
5
07b6f06899e0 my tired ass deleted a fix that was partially working
Atarwn Gard <a@qwa.su>
parents: 3
diff changeset
247 case "rdir":
07b6f06899e0 my tired ass deleted a fix that was partially working
Atarwn Gard <a@qwa.su>
parents: 3
diff changeset
248 rdirCode, _ = strconv.Atoi(safeArg(d.Args, 0))
07b6f06899e0 my tired ass deleted a fix that was partially working
Atarwn Gard <a@qwa.su>
parents: 3
diff changeset
249 rdirURL = safeArg(d.Args, 1)
0
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
250 }
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
251 }
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
252
5
07b6f06899e0 my tired ass deleted a fix that was partially working
Atarwn Gard <a@qwa.su>
parents: 3
diff changeset
253 if rdirURL != "" {
07b6f06899e0 my tired ass deleted a fix that was partially working
Atarwn Gard <a@qwa.su>
parents: 3
diff changeset
254 if rdirCode == 0 {
07b6f06899e0 my tired ass deleted a fix that was partially working
Atarwn Gard <a@qwa.su>
parents: 3
diff changeset
255 rdirCode = http.StatusFound
07b6f06899e0 my tired ass deleted a fix that was partially working
Atarwn Gard <a@qwa.su>
parents: 3
diff changeset
256 }
8
2ffb8028ccbb add loggingmodes and fix path matching
Atarwn Gard <a@qwa.su>
parents: 7
diff changeset
257 verbosePrintf("d2o: rdir %d -> %s", rdirCode, rdirURL)
5
07b6f06899e0 my tired ass deleted a fix that was partially working
Atarwn Gard <a@qwa.su>
parents: 3
diff changeset
258 http.Redirect(w, r, rdirURL, rdirCode)
07b6f06899e0 my tired ass deleted a fix that was partially working
Atarwn Gard <a@qwa.su>
parents: 3
diff changeset
259 return
07b6f06899e0 my tired ass deleted a fix that was partially working
Atarwn Gard <a@qwa.su>
parents: 3
diff changeset
260 }
0
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
261 if rprxAddr != "" {
8
2ffb8028ccbb add loggingmodes and fix path matching
Atarwn Gard <a@qwa.su>
parents: 7
diff changeset
262 verbosePrintf("d2o: rprx -> %s", rprxAddr)
0
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
263 serveReverseProxy(w, r, rprxAddr)
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
264 return
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
265 }
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
266 if fcgiAddr != "" && matchGlob(fcgiPat, r.URL.Path) {
8
2ffb8028ccbb add loggingmodes and fix path matching
Atarwn Gard <a@qwa.su>
parents: 7
diff changeset
267 verbosePrintf("d2o: fcgi -> %s (%s)", fcgiAddr, r.URL.Path)
0
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
268 if err := serveFCGI(w, r, fcgiAddr, rootDir); err != nil {
8
2ffb8028ccbb add loggingmodes and fix path matching
Atarwn Gard <a@qwa.su>
parents: 7
diff changeset
269 verbosePrintf("d2o: fcgi error: %v", err)
0
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
270 http.Error(w, "gateway error", http.StatusBadGateway)
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
271 }
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
272 return
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
273 }
11
350589d762a0 add cgi, remove tls, update docs
Atarwn Gard <a@qwa.su>
parents: 9
diff changeset
274 if cgiExec != "" && matchGlob(cgiPat, r.URL.Path) {
350589d762a0 add cgi, remove tls, update docs
Atarwn Gard <a@qwa.su>
parents: 9
diff changeset
275 verbosePrintf("d2o: cgi -> %s (%s)", cgiExec, r.URL.Path)
350589d762a0 add cgi, remove tls, update docs
Atarwn Gard <a@qwa.su>
parents: 9
diff changeset
276 serveCGI(w, r, cgiExec, rootDir)
350589d762a0 add cgi, remove tls, update docs
Atarwn Gard <a@qwa.su>
parents: 9
diff changeset
277 return
350589d762a0 add cgi, remove tls, update docs
Atarwn Gard <a@qwa.su>
parents: 9
diff changeset
278 }
0
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
279 if rootDir != "" {
8
2ffb8028ccbb add loggingmodes and fix path matching
Atarwn Gard <a@qwa.su>
parents: 7
diff changeset
280 fsPath := path.Clean(r.URL.Path)
2ffb8028ccbb add loggingmodes and fix path matching
Atarwn Gard <a@qwa.su>
parents: 7
diff changeset
281 displayPath := fsPath
2ffb8028ccbb add loggingmodes and fix path matching
Atarwn Gard <a@qwa.su>
parents: 7
diff changeset
282 if user, ok := caps["user"]; ok && user != "" {
2ffb8028ccbb add loggingmodes and fix path matching
Atarwn Gard <a@qwa.su>
parents: 7
diff changeset
283 mount := "/~" + user
2ffb8028ccbb add loggingmodes and fix path matching
Atarwn Gard <a@qwa.su>
parents: 7
diff changeset
284 if fsPath == mount || strings.HasPrefix(fsPath, mount+"/") {
2ffb8028ccbb add loggingmodes and fix path matching
Atarwn Gard <a@qwa.su>
parents: 7
diff changeset
285 trimmed := strings.TrimPrefix(fsPath, mount)
2ffb8028ccbb add loggingmodes and fix path matching
Atarwn Gard <a@qwa.su>
parents: 7
diff changeset
286 if trimmed == "" {
2ffb8028ccbb add loggingmodes and fix path matching
Atarwn Gard <a@qwa.su>
parents: 7
diff changeset
287 trimmed = "/"
2ffb8028ccbb add loggingmodes and fix path matching
Atarwn Gard <a@qwa.su>
parents: 7
diff changeset
288 }
2ffb8028ccbb add loggingmodes and fix path matching
Atarwn Gard <a@qwa.su>
parents: 7
diff changeset
289 fsPath = trimmed
2ffb8028ccbb add loggingmodes and fix path matching
Atarwn Gard <a@qwa.su>
parents: 7
diff changeset
290 }
2ffb8028ccbb add loggingmodes and fix path matching
Atarwn Gard <a@qwa.su>
parents: 7
diff changeset
291 }
2ffb8028ccbb add loggingmodes and fix path matching
Atarwn Gard <a@qwa.su>
parents: 7
diff changeset
292
2ffb8028ccbb add loggingmodes and fix path matching
Atarwn Gard <a@qwa.su>
parents: 7
diff changeset
293 verbosePrintf("d2o: static -> %s (%s)", rootDir, r.URL.Path)
11
350589d762a0 add cgi, remove tls, update docs
Atarwn Gard <a@qwa.su>
parents: 9
diff changeset
294 serveStatic(w, r, rootDir, rootShow, ndex, fcgiAddr, fcgiPat, cgiExec, cgiPat, fsPath, displayPath)
0
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
295 return
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
296 }
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
297
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
298 http.Error(w, "not found", http.StatusNotFound)
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
299 }
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
300
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
301 // --- Static -----------------------------------------------------------------
3
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 2
diff changeset
302
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 2
diff changeset
303 // serveStatic serves files from rootDir.
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 2
diff changeset
304 // rootIndex == nil: directory listing forbidden (hide).
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 2
diff changeset
305 // rootIndex != nil: try each as index candidate; if none found, show listing.
11
350589d762a0 add cgi, remove tls, update docs
Atarwn Gard <a@qwa.su>
parents: 9
diff changeset
306 func serveStatic(w http.ResponseWriter, r *http.Request, rootDir string, show bool, ndex []string, fcgiAddr, fcgiPat, cgiExec, cgiPat string, fsPath, displayPath string) {
8
2ffb8028ccbb add loggingmodes and fix path matching
Atarwn Gard <a@qwa.su>
parents: 7
diff changeset
307 fpath := filepath.Join(rootDir, filepath.FromSlash(path.Clean(fsPath)))
0
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
308
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
309 info, err := os.Stat(fpath)
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
310 if os.IsNotExist(err) {
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
311 http.Error(w, "not found", http.StatusNotFound)
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
312 return
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
313 }
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
314 if err != nil {
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
315 http.Error(w, "internal error", http.StatusInternalServerError)
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
316 return
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
317 }
1
3e7247db5c6e show index.html
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
318
0
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
319 if info.IsDir() {
5
07b6f06899e0 my tired ass deleted a fix that was partially working
Atarwn Gard <a@qwa.su>
parents: 3
diff changeset
320 for _, idx := range ndex {
1
3e7247db5c6e show index.html
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
321 idxPath := filepath.Join(fpath, idx)
3e7247db5c6e show index.html
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
322 if _, err := os.Stat(idxPath); err == nil {
5
07b6f06899e0 my tired ass deleted a fix that was partially working
Atarwn Gard <a@qwa.su>
parents: 3
diff changeset
323 if fcgiAddr != "" && matchGlob(fcgiPat, idx) {
07b6f06899e0 my tired ass deleted a fix that was partially working
Atarwn Gard <a@qwa.su>
parents: 3
diff changeset
324 r2 := r.Clone(r.Context())
07b6f06899e0 my tired ass deleted a fix that was partially working
Atarwn Gard <a@qwa.su>
parents: 3
diff changeset
325 r2.URL.Path = path.Join(r.URL.Path, idx)
07b6f06899e0 my tired ass deleted a fix that was partially working
Atarwn Gard <a@qwa.su>
parents: 3
diff changeset
326 if err := serveFCGI(w, r2, fcgiAddr, rootDir); err != nil {
07b6f06899e0 my tired ass deleted a fix that was partially working
Atarwn Gard <a@qwa.su>
parents: 3
diff changeset
327 log.Printf("d2o: fcgi error: %v", err)
07b6f06899e0 my tired ass deleted a fix that was partially working
Atarwn Gard <a@qwa.su>
parents: 3
diff changeset
328 http.Error(w, "gateway error", http.StatusBadGateway)
07b6f06899e0 my tired ass deleted a fix that was partially working
Atarwn Gard <a@qwa.su>
parents: 3
diff changeset
329 }
07b6f06899e0 my tired ass deleted a fix that was partially working
Atarwn Gard <a@qwa.su>
parents: 3
diff changeset
330 return
07b6f06899e0 my tired ass deleted a fix that was partially working
Atarwn Gard <a@qwa.su>
parents: 3
diff changeset
331 }
11
350589d762a0 add cgi, remove tls, update docs
Atarwn Gard <a@qwa.su>
parents: 9
diff changeset
332 if cgiExec != "" && matchGlob(cgiPat, idx) {
350589d762a0 add cgi, remove tls, update docs
Atarwn Gard <a@qwa.su>
parents: 9
diff changeset
333 r2 := r.Clone(r.Context())
350589d762a0 add cgi, remove tls, update docs
Atarwn Gard <a@qwa.su>
parents: 9
diff changeset
334 r2.URL.Path = path.Join(r.URL.Path, idx)
350589d762a0 add cgi, remove tls, update docs
Atarwn Gard <a@qwa.su>
parents: 9
diff changeset
335 serveCGI(w, r2, cgiExec, rootDir)
350589d762a0 add cgi, remove tls, update docs
Atarwn Gard <a@qwa.su>
parents: 9
diff changeset
336 return
350589d762a0 add cgi, remove tls, update docs
Atarwn Gard <a@qwa.su>
parents: 9
diff changeset
337 }
1
3e7247db5c6e show index.html
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
338 http.ServeFile(w, r, idxPath)
3e7247db5c6e show index.html
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
339 return
3e7247db5c6e show index.html
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
340 }
3e7247db5c6e show index.html
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
341 }
5
07b6f06899e0 my tired ass deleted a fix that was partially working
Atarwn Gard <a@qwa.su>
parents: 3
diff changeset
342 if !show {
07b6f06899e0 my tired ass deleted a fix that was partially working
Atarwn Gard <a@qwa.su>
parents: 3
diff changeset
343 http.Error(w, "forbidden", http.StatusForbidden)
07b6f06899e0 my tired ass deleted a fix that was partially working
Atarwn Gard <a@qwa.su>
parents: 3
diff changeset
344 return
07b6f06899e0 my tired ass deleted a fix that was partially working
Atarwn Gard <a@qwa.su>
parents: 3
diff changeset
345 }
8
2ffb8028ccbb add loggingmodes and fix path matching
Atarwn Gard <a@qwa.su>
parents: 7
diff changeset
346 listDir(w, r, fpath, displayPath)
0
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
347 return
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
348 }
1
3e7247db5c6e show index.html
Atarwn Gard <a@qwa.su>
parents: 0
diff changeset
349
0
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
350 http.ServeFile(w, r, fpath)
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
351 }
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
352
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
353 func listDir(w http.ResponseWriter, r *http.Request, dir, urlPath string) {
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
354 entries, err := os.ReadDir(dir)
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
355 if err != nil {
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
356 http.Error(w, "cannot read directory", http.StatusInternalServerError)
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
357 return
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
358 }
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
359 w.Header().Set("Content-Type", "text/html; charset=utf-8")
7
8e4813b4e509 update index style + justfile additions
Atarwn Gard <a@qwa.su>
parents: 5
diff changeset
360 fmt.Fprintf(w, "<html><head><title>Index of %s</title><style>body{font-family:monospace}</style></head><body>\n", urlPath)
8e4813b4e509 update index style + justfile additions
Atarwn Gard <a@qwa.su>
parents: 5
diff changeset
361 fmt.Fprintf(w, "<h2>Index of %s</h2><pre>\n", urlPath)
0
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
362 if urlPath != "/" {
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
363 fmt.Fprintf(w, "<a href=\"..\">..</a>\n")
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
364 }
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
365 for _, e := range entries {
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
366 name := e.Name()
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
367 if e.IsDir() {
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
368 name += "/"
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
369 }
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
370 fmt.Fprintf(w, "<a href=\"%s\">%s</a>\n", path.Join(urlPath, name), name)
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
371 }
7
8e4813b4e509 update index style + justfile additions
Atarwn Gard <a@qwa.su>
parents: 5
diff changeset
372 fmt.Fprintf(w, "</pre><i>d2o webserver</i></body></html>")
0
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
373 }
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
374
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
375 // --- Reverse proxy ----------------------------------------------------------
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
376
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
377 func serveReverseProxy(w http.ResponseWriter, r *http.Request, target string) {
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
378 if !strings.HasPrefix(target, "http://") && !strings.HasPrefix(target, "https://") {
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
379 target = "http://" + target
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
380 }
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
381 u, err := url.Parse(target)
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
382 if err != nil {
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
383 http.Error(w, "bad gateway config", http.StatusInternalServerError)
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
384 return
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
385 }
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
386 proxy := httputil.NewSingleHostReverseProxy(u)
8
2ffb8028ccbb add loggingmodes and fix path matching
Atarwn Gard <a@qwa.su>
parents: 7
diff changeset
387 if verboseEnabled() {
2ffb8028ccbb add loggingmodes and fix path matching
Atarwn Gard <a@qwa.su>
parents: 7
diff changeset
388 origDirector := proxy.Director
2ffb8028ccbb add loggingmodes and fix path matching
Atarwn Gard <a@qwa.su>
parents: 7
diff changeset
389 proxy.Director = func(req *http.Request) {
2ffb8028ccbb add loggingmodes and fix path matching
Atarwn Gard <a@qwa.su>
parents: 7
diff changeset
390 origDirector(req)
2ffb8028ccbb add loggingmodes and fix path matching
Atarwn Gard <a@qwa.su>
parents: 7
diff changeset
391 log.Printf("d2o: rprx upstream request: %s %s", req.Method, req.URL.String())
2ffb8028ccbb add loggingmodes and fix path matching
Atarwn Gard <a@qwa.su>
parents: 7
diff changeset
392 }
2ffb8028ccbb add loggingmodes and fix path matching
Atarwn Gard <a@qwa.su>
parents: 7
diff changeset
393 proxy.ModifyResponse = func(resp *http.Response) error {
2ffb8028ccbb add loggingmodes and fix path matching
Atarwn Gard <a@qwa.su>
parents: 7
diff changeset
394 log.Printf("d2o: rprx upstream response: %d %s", resp.StatusCode, resp.Status)
2ffb8028ccbb add loggingmodes and fix path matching
Atarwn Gard <a@qwa.su>
parents: 7
diff changeset
395 return nil
2ffb8028ccbb add loggingmodes and fix path matching
Atarwn Gard <a@qwa.su>
parents: 7
diff changeset
396 }
2ffb8028ccbb add loggingmodes and fix path matching
Atarwn Gard <a@qwa.su>
parents: 7
diff changeset
397 }
0
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
398 proxy.ErrorHandler = func(w http.ResponseWriter, r *http.Request, err error) {
8
2ffb8028ccbb add loggingmodes and fix path matching
Atarwn Gard <a@qwa.su>
parents: 7
diff changeset
399 verbosePrintf("d2o: rprx error: %v", err)
0
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
400 http.Error(w, "bad gateway", http.StatusBadGateway)
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
401 }
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
402 proxy.ServeHTTP(w, r)
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
403 }
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
404
11
350589d762a0 add cgi, remove tls, update docs
Atarwn Gard <a@qwa.su>
parents: 9
diff changeset
405 // --- CGI --------------------------------------------------------------------
350589d762a0 add cgi, remove tls, update docs
Atarwn Gard <a@qwa.su>
parents: 9
diff changeset
406
350589d762a0 add cgi, remove tls, update docs
Atarwn Gard <a@qwa.su>
parents: 9
diff changeset
407 // serveCGI runs a CGI executable using net/http/cgi.
350589d762a0 add cgi, remove tls, update docs
Atarwn Gard <a@qwa.su>
parents: 9
diff changeset
408 // cgiExec is the path to the executable (e.g. /usr/lib/cgit/cgit.cgi).
350589d762a0 add cgi, remove tls, update docs
Atarwn Gard <a@qwa.su>
parents: 9
diff changeset
409 // docRoot is set as DOCUMENT_ROOT; may be empty.
350589d762a0 add cgi, remove tls, update docs
Atarwn Gard <a@qwa.su>
parents: 9
diff changeset
410 func serveCGI(w http.ResponseWriter, r *http.Request, cgiExec, docRoot string) {
350589d762a0 add cgi, remove tls, update docs
Atarwn Gard <a@qwa.su>
parents: 9
diff changeset
411 h := &cgi.Handler{
350589d762a0 add cgi, remove tls, update docs
Atarwn Gard <a@qwa.su>
parents: 9
diff changeset
412 Path: cgiExec,
350589d762a0 add cgi, remove tls, update docs
Atarwn Gard <a@qwa.su>
parents: 9
diff changeset
413 Dir: docRoot,
350589d762a0 add cgi, remove tls, update docs
Atarwn Gard <a@qwa.su>
parents: 9
diff changeset
414 Env: []string{
350589d762a0 add cgi, remove tls, update docs
Atarwn Gard <a@qwa.su>
parents: 9
diff changeset
415 "DOCUMENT_ROOT=" + docRoot,
350589d762a0 add cgi, remove tls, update docs
Atarwn Gard <a@qwa.su>
parents: 9
diff changeset
416 "SERVER_SOFTWARE=d2o/1.1",
350589d762a0 add cgi, remove tls, update docs
Atarwn Gard <a@qwa.su>
parents: 9
diff changeset
417 },
350589d762a0 add cgi, remove tls, update docs
Atarwn Gard <a@qwa.su>
parents: 9
diff changeset
418 }
350589d762a0 add cgi, remove tls, update docs
Atarwn Gard <a@qwa.su>
parents: 9
diff changeset
419 h.ServeHTTP(w, r)
350589d762a0 add cgi, remove tls, update docs
Atarwn Gard <a@qwa.su>
parents: 9
diff changeset
420 }
350589d762a0 add cgi, remove tls, update docs
Atarwn Gard <a@qwa.su>
parents: 9
diff changeset
421
0
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
422 // --- FastCGI ----------------------------------------------------------------
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
423
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
424 func serveFCGI(w http.ResponseWriter, r *http.Request, addr, docRoot string) error {
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
425 network, address := parseFCGIAddr(addr)
3
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 2
diff changeset
426 client, err := fcgi.Dial(network, address)
0
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
427 if err != nil {
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
428 return fmt.Errorf("connect %s: %w", addr, err)
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
429 }
3
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 2
diff changeset
430 defer client.Close()
0
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
431
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
432 scriptPath := r.URL.Path
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
433 if docRoot != "" {
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
434 scriptPath = filepath.Join(docRoot, filepath.FromSlash(r.URL.Path))
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
435 }
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
436
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
437 params := map[string]string{
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
438 "REQUEST_METHOD": r.Method,
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
439 "SCRIPT_FILENAME": scriptPath,
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
440 "SCRIPT_NAME": r.URL.Path,
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
441 "REQUEST_URI": r.URL.RequestURI(),
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
442 "QUERY_STRING": r.URL.RawQuery,
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
443 "SERVER_PROTOCOL": r.Proto,
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
444 "SERVER_NAME": stripPort(r.Host),
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
445 "DOCUMENT_ROOT": docRoot,
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
446 "GATEWAY_INTERFACE": "CGI/1.1",
9
ec97184ea63d bump version
Atarwn Gard <a@qwa.su>
parents: 8
diff changeset
447 "SERVER_SOFTWARE": "d2o/1.1",
0
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
448 }
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
449 if r.TLS != nil {
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
450 params["HTTPS"] = "on"
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
451 }
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
452 for k, vs := range r.Header {
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
453 key := "HTTP_" + strings.ToUpper(strings.ReplaceAll(k, "-", "_"))
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
454 params[key] = strings.Join(vs, ", ")
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
455 }
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
456 if ct := r.Header.Get("Content-Type"); ct != "" {
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
457 params["CONTENT_TYPE"] = ct
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
458 }
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
459 if r.ContentLength >= 0 {
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
460 params["CONTENT_LENGTH"] = strconv.FormatInt(r.ContentLength, 10)
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
461 }
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
462
3
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 2
diff changeset
463 // Use Do() instead of Request() — php-fpm returns CGI response (no HTTP status line),
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 2
diff changeset
464 // not a full HTTP response. Request() expects "HTTP/1.1 200 OK" and panics on code 0.
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 2
diff changeset
465 cgiReader, err := client.Do(params, r.Body)
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 2
diff changeset
466 if err != nil {
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 2
diff changeset
467 return fmt.Errorf("fcgi request: %w", err)
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 2
diff changeset
468 }
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 2
diff changeset
469
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 2
diff changeset
470 // Parse CGI headers manually
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 2
diff changeset
471 br := bufio.NewReader(cgiReader)
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 2
diff changeset
472 tp := textproto.NewReader(br)
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 2
diff changeset
473 mime, err := tp.ReadMIMEHeader()
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 2
diff changeset
474 if err != nil && len(mime) == 0 {
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 2
diff changeset
475 return fmt.Errorf("fcgi response headers: %w", err)
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 2
diff changeset
476 }
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 2
diff changeset
477
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 2
diff changeset
478 status := http.StatusOK
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 2
diff changeset
479 if s := mime.Get("Status"); s != "" {
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 2
diff changeset
480 code, _, _ := strings.Cut(s, " ")
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 2
diff changeset
481 if n, err := strconv.Atoi(code); err == nil && n > 0 {
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 2
diff changeset
482 status = n
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 2
diff changeset
483 }
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 2
diff changeset
484 mime.Del("Status")
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 2
diff changeset
485 }
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 2
diff changeset
486
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 2
diff changeset
487 for k, vs := range mime {
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 2
diff changeset
488 for _, v := range vs {
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 2
diff changeset
489 w.Header().Add(k, v)
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 2
diff changeset
490 }
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 2
diff changeset
491 }
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 2
diff changeset
492 w.WriteHeader(status)
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 2
diff changeset
493 io.Copy(w, br)
eb705d4cdcd7 fix fcgi
Atarwn Gard <a@qwa.su>
parents: 2
diff changeset
494 return nil
0
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
495 }
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
496
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
497 func parseFCGIAddr(addr string) (network, address string) {
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
498 if strings.HasPrefix(addr, "unix:") {
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
499 return "unix", strings.TrimPrefix(addr, "unix:")
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
500 }
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
501 return "tcp", addr
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
502 }
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
503
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
504 // --- Helpers ----------------------------------------------------------------
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
505
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
506 func stripPort(host string) string {
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
507 if h, _, err := net.SplitHostPort(host); err == nil {
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
508 return h
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
509 }
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
510 return host
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
511 }
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
512
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
513 func safeArg(args []string, i int) string {
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
514 if i < len(args) {
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
515 return args[i]
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
516 }
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
517 return ""
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
518 }
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
519
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
520 func matchGlob(pattern, s string) bool {
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
521 if pattern == "*" {
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
522 return true
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
523 }
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
524 regPat := "^" + strings.ReplaceAll(regexp.QuoteMeta(pattern), regexp.QuoteMeta("*"), ".*") + "$"
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
525 matched, err := regexp.MatchString(regPat, s)
48bdab3eec8a Initial
Atarwn Gard <a@qwa.su>
parents:
diff changeset
526 return err == nil && matched
8
2ffb8028ccbb add loggingmodes and fix path matching
Atarwn Gard <a@qwa.su>
parents: 7
diff changeset
527 }
2ffb8028ccbb add loggingmodes and fix path matching
Atarwn Gard <a@qwa.su>
parents: 7
diff changeset
528
2ffb8028ccbb add loggingmodes and fix path matching
Atarwn Gard <a@qwa.su>
parents: 7
diff changeset
529 type respRecorder struct {
2ffb8028ccbb add loggingmodes and fix path matching
Atarwn Gard <a@qwa.su>
parents: 7
diff changeset
530 http.ResponseWriter
2ffb8028ccbb add loggingmodes and fix path matching
Atarwn Gard <a@qwa.su>
parents: 7
diff changeset
531 status int
2ffb8028ccbb add loggingmodes and fix path matching
Atarwn Gard <a@qwa.su>
parents: 7
diff changeset
532 bytes int64
2ffb8028ccbb add loggingmodes and fix path matching
Atarwn Gard <a@qwa.su>
parents: 7
diff changeset
533 }
2ffb8028ccbb add loggingmodes and fix path matching
Atarwn Gard <a@qwa.su>
parents: 7
diff changeset
534
2ffb8028ccbb add loggingmodes and fix path matching
Atarwn Gard <a@qwa.su>
parents: 7
diff changeset
535 func (rr *respRecorder) Hijack() (net.Conn, *bufio.ReadWriter, error) {
2ffb8028ccbb add loggingmodes and fix path matching
Atarwn Gard <a@qwa.su>
parents: 7
diff changeset
536 h, ok := rr.ResponseWriter.(http.Hijacker)
2ffb8028ccbb add loggingmodes and fix path matching
Atarwn Gard <a@qwa.su>
parents: 7
diff changeset
537 if !ok {
2ffb8028ccbb add loggingmodes and fix path matching
Atarwn Gard <a@qwa.su>
parents: 7
diff changeset
538 return nil, nil, fmt.Errorf("hijack not supported")
2ffb8028ccbb add loggingmodes and fix path matching
Atarwn Gard <a@qwa.su>
parents: 7
diff changeset
539 }
2ffb8028ccbb add loggingmodes and fix path matching
Atarwn Gard <a@qwa.su>
parents: 7
diff changeset
540 return h.Hijack()
2ffb8028ccbb add loggingmodes and fix path matching
Atarwn Gard <a@qwa.su>
parents: 7
diff changeset
541 }
2ffb8028ccbb add loggingmodes and fix path matching
Atarwn Gard <a@qwa.su>
parents: 7
diff changeset
542
2ffb8028ccbb add loggingmodes and fix path matching
Atarwn Gard <a@qwa.su>
parents: 7
diff changeset
543 func (rr *respRecorder) Flush() {
2ffb8028ccbb add loggingmodes and fix path matching
Atarwn Gard <a@qwa.su>
parents: 7
diff changeset
544 if f, ok := rr.ResponseWriter.(http.Flusher); ok {
2ffb8028ccbb add loggingmodes and fix path matching
Atarwn Gard <a@qwa.su>
parents: 7
diff changeset
545 f.Flush()
2ffb8028ccbb add loggingmodes and fix path matching
Atarwn Gard <a@qwa.su>
parents: 7
diff changeset
546 }
2ffb8028ccbb add loggingmodes and fix path matching
Atarwn Gard <a@qwa.su>
parents: 7
diff changeset
547 }
2ffb8028ccbb add loggingmodes and fix path matching
Atarwn Gard <a@qwa.su>
parents: 7
diff changeset
548
2ffb8028ccbb add loggingmodes and fix path matching
Atarwn Gard <a@qwa.su>
parents: 7
diff changeset
549 func (rr *respRecorder) Push(target string, opts *http.PushOptions) error {
2ffb8028ccbb add loggingmodes and fix path matching
Atarwn Gard <a@qwa.su>
parents: 7
diff changeset
550 if p, ok := rr.ResponseWriter.(http.Pusher); ok {
2ffb8028ccbb add loggingmodes and fix path matching
Atarwn Gard <a@qwa.su>
parents: 7
diff changeset
551 return p.Push(target, opts)
2ffb8028ccbb add loggingmodes and fix path matching
Atarwn Gard <a@qwa.su>
parents: 7
diff changeset
552 }
2ffb8028ccbb add loggingmodes and fix path matching
Atarwn Gard <a@qwa.su>
parents: 7
diff changeset
553 return http.ErrNotSupported
2ffb8028ccbb add loggingmodes and fix path matching
Atarwn Gard <a@qwa.su>
parents: 7
diff changeset
554 }
2ffb8028ccbb add loggingmodes and fix path matching
Atarwn Gard <a@qwa.su>
parents: 7
diff changeset
555
2ffb8028ccbb add loggingmodes and fix path matching
Atarwn Gard <a@qwa.su>
parents: 7
diff changeset
556 func (rr *respRecorder) ReadFrom(src io.Reader) (int64, error) {
2ffb8028ccbb add loggingmodes and fix path matching
Atarwn Gard <a@qwa.su>
parents: 7
diff changeset
557 // Preserve io.Copy optimizations and count bytes.
2ffb8028ccbb add loggingmodes and fix path matching
Atarwn Gard <a@qwa.su>
parents: 7
diff changeset
558 rf, ok := rr.ResponseWriter.(io.ReaderFrom)
2ffb8028ccbb add loggingmodes and fix path matching
Atarwn Gard <a@qwa.su>
parents: 7
diff changeset
559 if !ok {
2ffb8028ccbb add loggingmodes and fix path matching
Atarwn Gard <a@qwa.su>
parents: 7
diff changeset
560 return io.Copy(rr, src)
2ffb8028ccbb add loggingmodes and fix path matching
Atarwn Gard <a@qwa.su>
parents: 7
diff changeset
561 }
2ffb8028ccbb add loggingmodes and fix path matching
Atarwn Gard <a@qwa.su>
parents: 7
diff changeset
562 if rr.status == 0 {
2ffb8028ccbb add loggingmodes and fix path matching
Atarwn Gard <a@qwa.su>
parents: 7
diff changeset
563 rr.status = http.StatusOK
2ffb8028ccbb add loggingmodes and fix path matching
Atarwn Gard <a@qwa.su>
parents: 7
diff changeset
564 }
2ffb8028ccbb add loggingmodes and fix path matching
Atarwn Gard <a@qwa.su>
parents: 7
diff changeset
565 n, err := rf.ReadFrom(src)
2ffb8028ccbb add loggingmodes and fix path matching
Atarwn Gard <a@qwa.su>
parents: 7
diff changeset
566 rr.bytes += n
2ffb8028ccbb add loggingmodes and fix path matching
Atarwn Gard <a@qwa.su>
parents: 7
diff changeset
567 return n, err
2ffb8028ccbb add loggingmodes and fix path matching
Atarwn Gard <a@qwa.su>
parents: 7
diff changeset
568 }
2ffb8028ccbb add loggingmodes and fix path matching
Atarwn Gard <a@qwa.su>
parents: 7
diff changeset
569
2ffb8028ccbb add loggingmodes and fix path matching
Atarwn Gard <a@qwa.su>
parents: 7
diff changeset
570 func (rr *respRecorder) WriteHeader(code int) {
2ffb8028ccbb add loggingmodes and fix path matching
Atarwn Gard <a@qwa.su>
parents: 7
diff changeset
571 rr.status = code
2ffb8028ccbb add loggingmodes and fix path matching
Atarwn Gard <a@qwa.su>
parents: 7
diff changeset
572 rr.ResponseWriter.WriteHeader(code)
2ffb8028ccbb add loggingmodes and fix path matching
Atarwn Gard <a@qwa.su>
parents: 7
diff changeset
573 }
2ffb8028ccbb add loggingmodes and fix path matching
Atarwn Gard <a@qwa.su>
parents: 7
diff changeset
574
2ffb8028ccbb add loggingmodes and fix path matching
Atarwn Gard <a@qwa.su>
parents: 7
diff changeset
575 func (rr *respRecorder) Write(p []byte) (int, error) {
2ffb8028ccbb add loggingmodes and fix path matching
Atarwn Gard <a@qwa.su>
parents: 7
diff changeset
576 if rr.status == 0 {
2ffb8028ccbb add loggingmodes and fix path matching
Atarwn Gard <a@qwa.su>
parents: 7
diff changeset
577 rr.status = http.StatusOK
2ffb8028ccbb add loggingmodes and fix path matching
Atarwn Gard <a@qwa.su>
parents: 7
diff changeset
578 }
2ffb8028ccbb add loggingmodes and fix path matching
Atarwn Gard <a@qwa.su>
parents: 7
diff changeset
579 n, err := rr.ResponseWriter.Write(p)
2ffb8028ccbb add loggingmodes and fix path matching
Atarwn Gard <a@qwa.su>
parents: 7
diff changeset
580 rr.bytes += int64(n)
2ffb8028ccbb add loggingmodes and fix path matching
Atarwn Gard <a@qwa.su>
parents: 7
diff changeset
581 return n, err
2ffb8028ccbb add loggingmodes and fix path matching
Atarwn Gard <a@qwa.su>
parents: 7
diff changeset
582 }
2ffb8028ccbb add loggingmodes and fix path matching
Atarwn Gard <a@qwa.su>
parents: 7
diff changeset
583
2ffb8028ccbb add loggingmodes and fix path matching
Atarwn Gard <a@qwa.su>
parents: 7
diff changeset
584 func (rr *respRecorder) ensureStatus(defaultCode int) {
2ffb8028ccbb add loggingmodes and fix path matching
Atarwn Gard <a@qwa.su>
parents: 7
diff changeset
585 if rr.status == 0 {
2ffb8028ccbb add loggingmodes and fix path matching
Atarwn Gard <a@qwa.su>
parents: 7
diff changeset
586 rr.status = defaultCode
2ffb8028ccbb add loggingmodes and fix path matching
Atarwn Gard <a@qwa.su>
parents: 7
diff changeset
587 }
2ffb8028ccbb add loggingmodes and fix path matching
Atarwn Gard <a@qwa.su>
parents: 7
diff changeset
588 }