package web import ( "fmt" "net/http" "time" "code.osinet.fr/fgm/kurz/domain" "github.com/gorilla/mux" ) /* Template variables: - FullyQualifiedAssetsBaseURL http://plusvite-cdn.osinet.eu - FullyQualifiedShortURL (short string) - FullyQualifiedSiteURL http://plusvite.net/ - FullyQualifiedTargetURL (target string) - RefreshDelay (seconds int) - SiteName PlusVite */ type bytes = []byte func build403(w http.ResponseWriter, short string) (bytes, error) { type Short403Data struct { FullyQualifiedAssetsBaseURL string FullyQualifiedShortURL string FullyQualifiedSiteURL string RefreshDelay time.Duration SiteName string } data := Short403Data{} tmpl.Execute(w, data) return bytes(""), nil } func build404(w http.ResponseWriter, short string) (bytes, error) { type Short404Data struct { AssetsVersion int FullyQualifiedAssetsBaseURL string FullyQualifiedShortURL string FullyQualifiedSiteURL string FullyQualifiedTargetURL string RefreshDelay time.Duration SiteName string } data := Short404Data{} err := tmpl.Execute(w, data) if err != nil { fmt.Println(err) } return bytes(""), nil } func build451(w http.ResponseWriter, short string) (bytes, error) { return nil, nil } // handleGetShort handles path / func handleGetShort(w http.ResponseWriter, r *http.Request) { short, ok := mux.Vars(r)["short"] if !ok { w.WriteHeader(http.StatusBadRequest) return } target, err := domain.GetTargetURL(short) // Happy path. if err == nil { w.Header().Set("Location", target) w.WriteHeader(http.StatusTemporaryRedirect) return } // Very sad path. domainErr, ok := err.(domain.Error) if !ok { // All errors return by the API should be domain-specific errors. w.WriteHeader(http.StatusInternalServerError) return } // Normal sad paths. // TODO improve UX: build pages instead of just HTTP 4xx. var status int switch domainErr.Kind { case domain.ShortNotFound: status = http.StatusNotFound if page, err := build404(w, short); err != nil { status = http.StatusInternalServerError w.WriteHeader(status) } else { w.WriteHeader(status) w.Write(page) } case domain.TargetBlockedError: status = http.StatusForbidden if page, err := build403(w, short); err != nil { status = http.StatusInternalServerError w.WriteHeader(status) } else { w.WriteHeader(status) w.Write(page) } case domain.TargetCensoredError: status = http.StatusUnavailableForLegalReasons if page, err := build451(w, short); err != nil { status = http.StatusInternalServerError w.WriteHeader(status) } else { w.WriteHeader(status) w.Write(page) } default: // TargetInvalid is not supposed to happen in this case, so it is an internal error too. status = http.StatusInternalServerError w.WriteHeader(status) } }