wisski-cloud-distillery/internal/component/control/self.go
Tom Wiesing f19619ef9f
Add 'environment' package
This commit adds a new environment package that manages all calls to the
underlying operating system.
2022-09-18 14:24:22 +02:00

133 lines
3.5 KiB
Go

package control
import (
"encoding/json"
"fmt"
"net/http"
"strings"
"github.com/tkw1536/goprogram/stream"
)
// self returns the handler for the self overrides
func (control Control) self(io stream.IOStream) (redirect Redirect, err error) {
// open the overrides file
overrides, err := control.Environment.Open(control.Config.SelfOverridesFile)
io.Printf("loading overrides from %q\n", control.Config.SelfOverridesFile)
if err != nil {
return redirect, err
}
defer overrides.Close()
// decode the overrides file
if err := json.NewDecoder(overrides).Decode(&redirect.Overrides); err != nil {
return redirect, err
}
if redirect.Overrides == nil {
redirect.Overrides = make(map[string]string)
}
redirect.Overrides[""] = control.Config.SelfRedirect.String()
// create a redirect server
redirect.Fallback, err = control.selfFallback()
if err != nil {
return redirect, err
}
redirect.Absolute = false
redirect.Permanent = false
// and return!
return redirect, nil
}
func (control *Control) selfFallback() (http.Handler, error) {
return http.HandlerFunc(control.serveFallback), nil
}
var notFoundText = []byte("not found")
func (control *Control) serveFallback(w http.ResponseWriter, r *http.Request) {
slug := control.Config.SlugFromHost(r.Host)
if slug == "" {
w.WriteHeader(http.StatusNotFound)
w.Write(notFoundText)
return
}
if ok, _ := control.Instances.Has(slug); !ok {
w.WriteHeader(http.StatusNotFound)
fmt.Fprintf(w, "WissKI %q not found\n", slug)
return
}
w.WriteHeader(http.StatusBadGateway)
fmt.Fprintf(w, "WissKI %q is currently offline\n", slug)
}
// Redirect implements a redirect server that redirects all requests.
// It implements http.Handler.
type Redirect struct {
// Target is the target URL to redirect to.
Target string
// Fallback is used when target is the empty string.
Fallback http.Handler
// Absolute determines if the request path should be appended to the target URL when redirecting.
// By default this path is always appended, set Absolute to true to prevent this.
Absolute bool
// Overrides is a map from paths to URLs that should override the default target.
Overrides map[string]string
// Permanent determines if the redirect responses issued should return
// Permanent Redirect (Status Code 308) or Temporary Redirect (Status Code 307).
Permanent bool
}
// Redirect determines the redirect URL for a specific incoming request
// If it returns the empty string, the fallback is used.
func (redirect Redirect) Redirect(r *http.Request) string {
// if we have an override for this URL, use it immediatly
url := strings.TrimSuffix(r.URL.Path, "/")
if override, ok := redirect.Overrides[url]; ok {
return override
}
if redirect.Target == "" {
return ""
}
// if we are in absolute redirect mode, always return the absolute URL
if redirect.Absolute {
return redirect.Target
}
// return the target + the redirected URL
dest := strings.TrimSuffix(redirect.Target, "/") + r.URL.Path
if len(r.URL.RawQuery) > 0 {
dest += "?" + r.URL.RawQuery
}
return dest
}
// ServeHTTP implements the http.Handler interface and redirects a single request to redirect.Target.
func (redirect Redirect) ServeHTTP(w http.ResponseWriter, r *http.Request) {
dest := redirect.Redirect(r)
if dest == "" {
redirect.Fallback.ServeHTTP(w, r)
return
}
// determine if we are temporary or permanent redirect
status := http.StatusTemporaryRedirect
if redirect.Permanent {
status = http.StatusPermanentRedirect
}
// and do the redirect
http.Redirect(w, r, dest, status)
}