Mercurial Hosting > d2o
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 |
| rev | line source |
|---|---|
| 0 | 1 package main |
| 2 | |
| 3 import ( | |
|
8
2ffb8028ccbb
add loggingmodes and fix path matching
Atarwn Gard <a@qwa.su>
parents:
7
diff
changeset
|
4 "bufio" |
| 0 | 5 "crypto/tls" |
| 6 "fmt" | |
| 3 | 7 "io" |
| 0 | 8 "log" |
| 9 "net" | |
| 10 "net/http" | |
| 11 | 11 "net/http/cgi" |
| 0 | 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 | 14 "net/url" |
| 15 "os" | |
| 16 "path" | |
| 17 "path/filepath" | |
| 18 "regexp" | |
| 19 "runtime" | |
| 20 "strconv" | |
| 21 "strings" | |
|
8
2ffb8028ccbb
add loggingmodes and fix path matching
Atarwn Gard <a@qwa.su>
parents:
7
diff
changeset
|
22 "time" |
| 0 | 23 |
| 24 "d2o/fcgi" | |
| 25 "d2o/icf" | |
| 26 ) | |
| 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 | 68 func main() { |
| 69 cfgPath := "/etc/d2obase" | |
| 70 if len(os.Args) > 1 { | |
| 71 cfgPath = os.Args[1] | |
| 72 } | |
| 73 | |
| 74 f, err := os.Open(cfgPath) | |
| 75 if err != nil { | |
| 76 log.Fatalf("d2o: cannot open config: %v", err) | |
| 77 } | |
| 78 cfg, err := icf.Parse(f) | |
| 79 f.Close() | |
| 80 if err != nil { | |
| 81 log.Fatalf("d2o: config error: %v", err) | |
| 82 } | |
| 83 | |
| 84 for _, d := range cfg.Abstract("d2o") { | |
| 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 | 97 case "threads": |
| 98 n, err := strconv.Atoi(safeArg(d.Args, 0)) | |
| 99 if err == nil && n > 0 { | |
| 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 | 102 } |
| 103 } | |
| 104 } | |
| 105 | |
| 106 ports := collectPorts(cfg) | |
| 107 if len(ports) == 0 { | |
| 108 log.Fatal("d2o: no port directives found in config") | |
| 109 } | |
| 110 | |
| 111 h := &handler{cfg: cfg} | |
| 112 errCh := make(chan error, len(ports)) | |
| 113 | |
| 114 for _, pc := range ports { | |
| 115 go func(pc portConfig) { | |
| 116 errCh <- pc.listen(h) | |
| 117 }(pc) | |
| 118 } | |
| 119 | |
| 120 log.Fatal(<-errCh) | |
| 121 } | |
| 122 | |
| 123 // --- Port collection -------------------------------------------------------- | |
| 124 | |
| 125 type portConfig struct { | |
| 126 addr string | |
| 127 certFile string | |
| 128 keyFile string | |
| 129 isTLS bool | |
| 130 } | |
| 131 | |
| 132 func (pc portConfig) listen(h http.Handler) error { | |
| 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 | 135 return http.ListenAndServe(pc.addr, h) |
| 136 } | |
| 137 cert, err := tls.LoadX509KeyPair(pc.certFile, pc.keyFile) | |
| 138 if err != nil { | |
| 139 return fmt.Errorf("d2o: tls: %w", err) | |
| 140 } | |
| 141 ln, err := tls.Listen("tcp", pc.addr, &tls.Config{ | |
| 142 Certificates: []tls.Certificate{cert}, | |
| 143 MinVersion: tls.VersionTLS12, | |
| 144 }) | |
| 145 if err != nil { | |
| 146 return fmt.Errorf("d2o: listen %s: %w", pc.addr, err) | |
| 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 | 149 return http.Serve(ln, h) |
| 150 } | |
| 151 | |
| 152 func collectPorts(cfg *icf.Config) []portConfig { | |
| 153 seen := make(map[string]bool) | |
| 154 var out []portConfig | |
| 155 | |
| 156 for _, b := range cfg.Blocks { | |
| 157 dirs := cfg.ResolveBlock(b, nil) | |
| 158 | |
| 159 for _, d := range dirs { | |
| 160 switch d.Key { | |
| 161 case "port": | |
| 162 addr := ":" + safeArg(d.Args, 0) | |
| 163 if !seen[addr] { | |
| 164 seen[addr] = true | |
| 165 out = append(out, portConfig{addr: addr}) | |
| 166 } | |
| 167 case "port+tls": | |
| 11 | 168 // port+tls <port> <cert> <key> |
| 0 | 169 addr := ":" + safeArg(d.Args, 0) |
| 170 c := safeArg(d.Args, 1) | |
| 171 k := safeArg(d.Args, 2) | |
| 172 if !seen[addr] { | |
| 173 seen[addr] = true | |
| 174 out = append(out, portConfig{addr: addr, certFile: c, keyFile: k, isTLS: true}) | |
| 175 } | |
| 176 } | |
| 177 } | |
| 178 } | |
| 179 return out | |
| 180 } | |
| 181 | |
| 182 // --- HTTP Handler ----------------------------------------------------------- | |
| 183 | |
| 184 type handler struct { | |
| 185 cfg *icf.Config | |
| 186 } | |
| 187 | |
| 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 | 192 host := stripPort(r.Host) |
| 193 reqPath := path.Clean(r.URL.Path) | |
| 194 | |
| 195 dirs, caps := h.cfg.Match(host + reqPath) | |
| 196 if dirs == nil { | |
| 197 dirs, caps = h.cfg.Match(host) | |
| 198 } | |
| 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 | 203 return |
| 204 } | |
| 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 | 209 } |
| 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 | 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 | 218 cgiExec string |
| 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 | 223 ) |
| 224 | |
| 225 for _, d := range dirs { | |
| 226 switch d.Key { | |
| 227 case "root": | |
| 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 | 232 case "fcgi": |
| 233 fcgiAddr = safeArg(d.Args, 0) | |
| 234 fcgiPat = safeArg(d.Args, 1) | |
| 235 if fcgiPat == "" { | |
| 236 fcgiPat = "*" | |
| 237 } | |
| 11 | 238 case "cgi": |
| 239 // cgi <executable> [<glob-pattern>] | |
| 240 cgiExec = safeArg(d.Args, 0) | |
| 241 cgiPat = safeArg(d.Args, 1) | |
| 242 if cgiPat == "" { | |
| 243 cgiPat = "*" | |
| 244 } | |
| 0 | 245 case "rprx": |
| 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 | 250 } |
| 251 } | |
| 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 | 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 | 263 serveReverseProxy(w, r, rprxAddr) |
| 264 return | |
| 265 } | |
| 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 | 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 | 270 http.Error(w, "gateway error", http.StatusBadGateway) |
| 271 } | |
| 272 return | |
| 273 } | |
| 11 | 274 if cgiExec != "" && matchGlob(cgiPat, r.URL.Path) { |
| 275 verbosePrintf("d2o: cgi -> %s (%s)", cgiExec, r.URL.Path) | |
| 276 serveCGI(w, r, cgiExec, rootDir) | |
| 277 return | |
| 278 } | |
| 0 | 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 | 294 serveStatic(w, r, rootDir, rootShow, ndex, fcgiAddr, fcgiPat, cgiExec, cgiPat, fsPath, displayPath) |
| 0 | 295 return |
| 296 } | |
| 297 | |
| 298 http.Error(w, "not found", http.StatusNotFound) | |
| 299 } | |
| 300 | |
| 301 // --- Static ----------------------------------------------------------------- | |
| 3 | 302 |
| 303 // serveStatic serves files from rootDir. | |
| 304 // rootIndex == nil: directory listing forbidden (hide). | |
| 305 // rootIndex != nil: try each as index candidate; if none found, show listing. | |
| 11 | 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 | 308 |
| 309 info, err := os.Stat(fpath) | |
| 310 if os.IsNotExist(err) { | |
| 311 http.Error(w, "not found", http.StatusNotFound) | |
| 312 return | |
| 313 } | |
| 314 if err != nil { | |
| 315 http.Error(w, "internal error", http.StatusInternalServerError) | |
| 316 return | |
| 317 } | |
| 1 | 318 |
| 0 | 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 | 321 idxPath := filepath.Join(fpath, idx) |
| 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 | 332 if cgiExec != "" && matchGlob(cgiPat, idx) { |
| 333 r2 := r.Clone(r.Context()) | |
| 334 r2.URL.Path = path.Join(r.URL.Path, idx) | |
| 335 serveCGI(w, r2, cgiExec, rootDir) | |
| 336 return | |
| 337 } | |
| 1 | 338 http.ServeFile(w, r, idxPath) |
| 339 return | |
| 340 } | |
| 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 | 347 return |
| 348 } | |
| 1 | 349 |
| 0 | 350 http.ServeFile(w, r, fpath) |
| 351 } | |
| 352 | |
| 353 func listDir(w http.ResponseWriter, r *http.Request, dir, urlPath string) { | |
| 354 entries, err := os.ReadDir(dir) | |
| 355 if err != nil { | |
| 356 http.Error(w, "cannot read directory", http.StatusInternalServerError) | |
| 357 return | |
| 358 } | |
| 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 | 362 if urlPath != "/" { |
| 363 fmt.Fprintf(w, "<a href=\"..\">..</a>\n") | |
| 364 } | |
| 365 for _, e := range entries { | |
| 366 name := e.Name() | |
| 367 if e.IsDir() { | |
| 368 name += "/" | |
| 369 } | |
| 370 fmt.Fprintf(w, "<a href=\"%s\">%s</a>\n", path.Join(urlPath, name), name) | |
| 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 | 373 } |
| 374 | |
| 375 // --- Reverse proxy ---------------------------------------------------------- | |
| 376 | |
| 377 func serveReverseProxy(w http.ResponseWriter, r *http.Request, target string) { | |
| 378 if !strings.HasPrefix(target, "http://") && !strings.HasPrefix(target, "https://") { | |
| 379 target = "http://" + target | |
| 380 } | |
| 381 u, err := url.Parse(target) | |
| 382 if err != nil { | |
| 383 http.Error(w, "bad gateway config", http.StatusInternalServerError) | |
| 384 return | |
| 385 } | |
| 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 | 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 | 400 http.Error(w, "bad gateway", http.StatusBadGateway) |
| 401 } | |
| 402 proxy.ServeHTTP(w, r) | |
| 403 } | |
| 404 | |
| 11 | 405 // --- CGI -------------------------------------------------------------------- |
| 406 | |
| 407 // serveCGI runs a CGI executable using net/http/cgi. | |
| 408 // cgiExec is the path to the executable (e.g. /usr/lib/cgit/cgit.cgi). | |
| 409 // docRoot is set as DOCUMENT_ROOT; may be empty. | |
| 410 func serveCGI(w http.ResponseWriter, r *http.Request, cgiExec, docRoot string) { | |
| 411 h := &cgi.Handler{ | |
| 412 Path: cgiExec, | |
| 413 Dir: docRoot, | |
| 414 Env: []string{ | |
| 415 "DOCUMENT_ROOT=" + docRoot, | |
| 416 "SERVER_SOFTWARE=d2o/1.1", | |
| 417 }, | |
| 418 } | |
| 419 h.ServeHTTP(w, r) | |
| 420 } | |
| 421 | |
| 0 | 422 // --- FastCGI ---------------------------------------------------------------- |
| 423 | |
| 424 func serveFCGI(w http.ResponseWriter, r *http.Request, addr, docRoot string) error { | |
| 425 network, address := parseFCGIAddr(addr) | |
| 3 | 426 client, err := fcgi.Dial(network, address) |
| 0 | 427 if err != nil { |
| 428 return fmt.Errorf("connect %s: %w", addr, err) | |
| 429 } | |
| 3 | 430 defer client.Close() |
| 0 | 431 |
| 432 scriptPath := r.URL.Path | |
| 433 if docRoot != "" { | |
| 434 scriptPath = filepath.Join(docRoot, filepath.FromSlash(r.URL.Path)) | |
| 435 } | |
| 436 | |
| 437 params := map[string]string{ | |
| 438 "REQUEST_METHOD": r.Method, | |
| 439 "SCRIPT_FILENAME": scriptPath, | |
| 440 "SCRIPT_NAME": r.URL.Path, | |
| 441 "REQUEST_URI": r.URL.RequestURI(), | |
| 442 "QUERY_STRING": r.URL.RawQuery, | |
| 443 "SERVER_PROTOCOL": r.Proto, | |
| 444 "SERVER_NAME": stripPort(r.Host), | |
| 445 "DOCUMENT_ROOT": docRoot, | |
| 446 "GATEWAY_INTERFACE": "CGI/1.1", | |
| 9 | 447 "SERVER_SOFTWARE": "d2o/1.1", |
| 0 | 448 } |
| 449 if r.TLS != nil { | |
| 450 params["HTTPS"] = "on" | |
| 451 } | |
| 452 for k, vs := range r.Header { | |
| 453 key := "HTTP_" + strings.ToUpper(strings.ReplaceAll(k, "-", "_")) | |
| 454 params[key] = strings.Join(vs, ", ") | |
| 455 } | |
| 456 if ct := r.Header.Get("Content-Type"); ct != "" { | |
| 457 params["CONTENT_TYPE"] = ct | |
| 458 } | |
| 459 if r.ContentLength >= 0 { | |
| 460 params["CONTENT_LENGTH"] = strconv.FormatInt(r.ContentLength, 10) | |
| 461 } | |
| 462 | |
| 3 | 463 // Use Do() instead of Request() — php-fpm returns CGI response (no HTTP status line), |
| 464 // not a full HTTP response. Request() expects "HTTP/1.1 200 OK" and panics on code 0. | |
| 465 cgiReader, err := client.Do(params, r.Body) | |
| 466 if err != nil { | |
| 467 return fmt.Errorf("fcgi request: %w", err) | |
| 468 } | |
| 469 | |
| 470 // Parse CGI headers manually | |
| 471 br := bufio.NewReader(cgiReader) | |
| 472 tp := textproto.NewReader(br) | |
| 473 mime, err := tp.ReadMIMEHeader() | |
| 474 if err != nil && len(mime) == 0 { | |
| 475 return fmt.Errorf("fcgi response headers: %w", err) | |
| 476 } | |
| 477 | |
| 478 status := http.StatusOK | |
| 479 if s := mime.Get("Status"); s != "" { | |
| 480 code, _, _ := strings.Cut(s, " ") | |
| 481 if n, err := strconv.Atoi(code); err == nil && n > 0 { | |
| 482 status = n | |
| 483 } | |
| 484 mime.Del("Status") | |
| 485 } | |
| 486 | |
| 487 for k, vs := range mime { | |
| 488 for _, v := range vs { | |
| 489 w.Header().Add(k, v) | |
| 490 } | |
| 491 } | |
| 492 w.WriteHeader(status) | |
| 493 io.Copy(w, br) | |
| 494 return nil | |
| 0 | 495 } |
| 496 | |
| 497 func parseFCGIAddr(addr string) (network, address string) { | |
| 498 if strings.HasPrefix(addr, "unix:") { | |
| 499 return "unix", strings.TrimPrefix(addr, "unix:") | |
| 500 } | |
| 501 return "tcp", addr | |
| 502 } | |
| 503 | |
| 504 // --- Helpers ---------------------------------------------------------------- | |
| 505 | |
| 506 func stripPort(host string) string { | |
| 507 if h, _, err := net.SplitHostPort(host); err == nil { | |
| 508 return h | |
| 509 } | |
| 510 return host | |
| 511 } | |
| 512 | |
| 513 func safeArg(args []string, i int) string { | |
| 514 if i < len(args) { | |
| 515 return args[i] | |
| 516 } | |
| 517 return "" | |
| 518 } | |
| 519 | |
| 520 func matchGlob(pattern, s string) bool { | |
| 521 if pattern == "*" { | |
| 522 return true | |
| 523 } | |
| 524 regPat := "^" + strings.ReplaceAll(regexp.QuoteMeta(pattern), regexp.QuoteMeta("*"), ".*") + "$" | |
| 525 matched, err := regexp.MatchString(regPat, s) | |
| 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 } |
