Mercurial Hosting > d2o
comparison 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 |
comparison
equal
deleted
inserted
replaced
| 10:560d4103e12e | 11:350589d762a0 |
|---|---|
| 6 "fmt" | 6 "fmt" |
| 7 "io" | 7 "io" |
| 8 "log" | 8 "log" |
| 9 "net" | 9 "net" |
| 10 "net/http" | 10 "net/http" |
| 11 "net/http/cgi" | |
| 11 "net/http/httputil" | 12 "net/http/httputil" |
| 12 "net/textproto" | 13 "net/textproto" |
| 13 "net/url" | 14 "net/url" |
| 14 "os" | 15 "os" |
| 15 "path" | 16 "path" |
| 153 var out []portConfig | 154 var out []portConfig |
| 154 | 155 |
| 155 for _, b := range cfg.Blocks { | 156 for _, b := range cfg.Blocks { |
| 156 dirs := cfg.ResolveBlock(b, nil) | 157 dirs := cfg.ResolveBlock(b, nil) |
| 157 | 158 |
| 158 var cert, key string | |
| 159 for _, d := range dirs { | |
| 160 if d.Key == "tls" { | |
| 161 cert = safeArg(d.Args, 0) | |
| 162 key = safeArg(d.Args, 1) | |
| 163 } | |
| 164 } | |
| 165 | |
| 166 for _, d := range dirs { | 159 for _, d := range dirs { |
| 167 switch d.Key { | 160 switch d.Key { |
| 168 case "port": | 161 case "port": |
| 169 addr := ":" + safeArg(d.Args, 0) | 162 addr := ":" + safeArg(d.Args, 0) |
| 170 if !seen[addr] { | 163 if !seen[addr] { |
| 171 seen[addr] = true | 164 seen[addr] = true |
| 172 out = append(out, portConfig{addr: addr}) | 165 out = append(out, portConfig{addr: addr}) |
| 173 } | 166 } |
| 174 case "port+tls": | 167 case "port+tls": |
| 168 // port+tls <port> <cert> <key> | |
| 175 addr := ":" + safeArg(d.Args, 0) | 169 addr := ":" + safeArg(d.Args, 0) |
| 176 c := safeArg(d.Args, 1) | 170 c := safeArg(d.Args, 1) |
| 177 k := safeArg(d.Args, 2) | 171 k := safeArg(d.Args, 2) |
| 178 if c == "" { | |
| 179 c = cert | |
| 180 } | |
| 181 if k == "" { | |
| 182 k = key | |
| 183 } | |
| 184 if !seen[addr] { | 172 if !seen[addr] { |
| 185 seen[addr] = true | 173 seen[addr] = true |
| 186 out = append(out, portConfig{addr: addr, certFile: c, keyFile: k, isTLS: true}) | 174 out = append(out, portConfig{addr: addr, certFile: c, keyFile: k, isTLS: true}) |
| 187 } | 175 } |
| 188 } | 176 } |
| 225 rootDir string | 213 rootDir string |
| 226 rootShow bool | 214 rootShow bool |
| 227 ndex []string | 215 ndex []string |
| 228 fcgiAddr string | 216 fcgiAddr string |
| 229 fcgiPat string | 217 fcgiPat string |
| 218 cgiExec string | |
| 219 cgiPat string | |
| 230 rprxAddr string | 220 rprxAddr string |
| 231 rdirCode int | 221 rdirCode int |
| 232 rdirURL string | 222 rdirURL string |
| 233 ) | 223 ) |
| 234 | 224 |
| 243 fcgiAddr = safeArg(d.Args, 0) | 233 fcgiAddr = safeArg(d.Args, 0) |
| 244 fcgiPat = safeArg(d.Args, 1) | 234 fcgiPat = safeArg(d.Args, 1) |
| 245 if fcgiPat == "" { | 235 if fcgiPat == "" { |
| 246 fcgiPat = "*" | 236 fcgiPat = "*" |
| 247 } | 237 } |
| 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 } | |
| 248 case "rprx": | 245 case "rprx": |
| 249 rprxAddr = safeArg(d.Args, 0) | 246 rprxAddr = safeArg(d.Args, 0) |
| 250 case "rdir": | 247 case "rdir": |
| 251 rdirCode, _ = strconv.Atoi(safeArg(d.Args, 0)) | 248 rdirCode, _ = strconv.Atoi(safeArg(d.Args, 0)) |
| 252 rdirURL = safeArg(d.Args, 1) | 249 rdirURL = safeArg(d.Args, 1) |
| 270 verbosePrintf("d2o: fcgi -> %s (%s)", fcgiAddr, r.URL.Path) | 267 verbosePrintf("d2o: fcgi -> %s (%s)", fcgiAddr, r.URL.Path) |
| 271 if err := serveFCGI(w, r, fcgiAddr, rootDir); err != nil { | 268 if err := serveFCGI(w, r, fcgiAddr, rootDir); err != nil { |
| 272 verbosePrintf("d2o: fcgi error: %v", err) | 269 verbosePrintf("d2o: fcgi error: %v", err) |
| 273 http.Error(w, "gateway error", http.StatusBadGateway) | 270 http.Error(w, "gateway error", http.StatusBadGateway) |
| 274 } | 271 } |
| 272 return | |
| 273 } | |
| 274 if cgiExec != "" && matchGlob(cgiPat, r.URL.Path) { | |
| 275 verbosePrintf("d2o: cgi -> %s (%s)", cgiExec, r.URL.Path) | |
| 276 serveCGI(w, r, cgiExec, rootDir) | |
| 275 return | 277 return |
| 276 } | 278 } |
| 277 if rootDir != "" { | 279 if rootDir != "" { |
| 278 fsPath := path.Clean(r.URL.Path) | 280 fsPath := path.Clean(r.URL.Path) |
| 279 displayPath := fsPath | 281 displayPath := fsPath |
| 287 fsPath = trimmed | 289 fsPath = trimmed |
| 288 } | 290 } |
| 289 } | 291 } |
| 290 | 292 |
| 291 verbosePrintf("d2o: static -> %s (%s)", rootDir, r.URL.Path) | 293 verbosePrintf("d2o: static -> %s (%s)", rootDir, r.URL.Path) |
| 292 serveStatic(w, r, rootDir, rootShow, ndex, fcgiAddr, fcgiPat, fsPath, displayPath) | 294 serveStatic(w, r, rootDir, rootShow, ndex, fcgiAddr, fcgiPat, cgiExec, cgiPat, fsPath, displayPath) |
| 293 return | 295 return |
| 294 } | 296 } |
| 295 | 297 |
| 296 http.Error(w, "not found", http.StatusNotFound) | 298 http.Error(w, "not found", http.StatusNotFound) |
| 297 } | 299 } |
| 299 // --- Static ----------------------------------------------------------------- | 301 // --- Static ----------------------------------------------------------------- |
| 300 | 302 |
| 301 // serveStatic serves files from rootDir. | 303 // serveStatic serves files from rootDir. |
| 302 // rootIndex == nil: directory listing forbidden (hide). | 304 // rootIndex == nil: directory listing forbidden (hide). |
| 303 // rootIndex != nil: try each as index candidate; if none found, show listing. | 305 // rootIndex != nil: try each as index candidate; if none found, show listing. |
| 304 func serveStatic(w http.ResponseWriter, r *http.Request, rootDir string, show bool, ndex []string, fcgiAddr, fcgiPat string, fsPath, displayPath string) { | 306 func serveStatic(w http.ResponseWriter, r *http.Request, rootDir string, show bool, ndex []string, fcgiAddr, fcgiPat, cgiExec, cgiPat string, fsPath, displayPath string) { |
| 305 fpath := filepath.Join(rootDir, filepath.FromSlash(path.Clean(fsPath))) | 307 fpath := filepath.Join(rootDir, filepath.FromSlash(path.Clean(fsPath))) |
| 306 | 308 |
| 307 info, err := os.Stat(fpath) | 309 info, err := os.Stat(fpath) |
| 308 if os.IsNotExist(err) { | 310 if os.IsNotExist(err) { |
| 309 http.Error(w, "not found", http.StatusNotFound) | 311 http.Error(w, "not found", http.StatusNotFound) |
| 325 log.Printf("d2o: fcgi error: %v", err) | 327 log.Printf("d2o: fcgi error: %v", err) |
| 326 http.Error(w, "gateway error", http.StatusBadGateway) | 328 http.Error(w, "gateway error", http.StatusBadGateway) |
| 327 } | 329 } |
| 328 return | 330 return |
| 329 } | 331 } |
| 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 } | |
| 330 http.ServeFile(w, r, idxPath) | 338 http.ServeFile(w, r, idxPath) |
| 331 return | 339 return |
| 332 } | 340 } |
| 333 } | 341 } |
| 334 if !show { | 342 if !show { |
| 390 proxy.ErrorHandler = func(w http.ResponseWriter, r *http.Request, err error) { | 398 proxy.ErrorHandler = func(w http.ResponseWriter, r *http.Request, err error) { |
| 391 verbosePrintf("d2o: rprx error: %v", err) | 399 verbosePrintf("d2o: rprx error: %v", err) |
| 392 http.Error(w, "bad gateway", http.StatusBadGateway) | 400 http.Error(w, "bad gateway", http.StatusBadGateway) |
| 393 } | 401 } |
| 394 proxy.ServeHTTP(w, r) | 402 proxy.ServeHTTP(w, r) |
| 403 } | |
| 404 | |
| 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) | |
| 395 } | 420 } |
| 396 | 421 |
| 397 // --- FastCGI ---------------------------------------------------------------- | 422 // --- FastCGI ---------------------------------------------------------------- |
| 398 | 423 |
| 399 func serveFCGI(w http.ResponseWriter, r *http.Request, addr, docRoot string) error { | 424 func serveFCGI(w http.ResponseWriter, r *http.Request, addr, docRoot string) error { |
