annotate main.go @ 8:2ffb8028ccbb

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