| 
					
				 | 
			
			
				@@ -1,9 +1,9 @@ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 package web 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 import ( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	"fmt" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	"io" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	"net/http" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	"time" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	"strings" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	"code.osinet.fr/fgm/kurz/domain" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	"github.com/gorilla/mux" 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -22,41 +22,49 @@ Template variables: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 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 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+func build403(w http.ResponseWriter, short string) error { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	data := struct { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		FullyQualifiedShortURL string 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		Globals 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	}{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		short, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		globals, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	data := Short403Data{} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	tmpl.Execute(w, data) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	return bytes(""), nil 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	sw := &strings.Builder{} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	err := tmpl.ExecuteTemplate(sw, "403", data) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	if err != nil { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		w.WriteHeader(http.StatusInternalServerError) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	} else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		w.WriteHeader(http.StatusForbidden) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		io.Copy(w, strings.NewReader(sw.String())) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	return err 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-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 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+func build404(w http.ResponseWriter, short string) error { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	data := struct { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		FullyQualifiedShortURL string 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		Globals 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	}{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		short, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		globals, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	data := Short404Data{} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	err := tmpl.Execute(w, data) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	sw := &strings.Builder{} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	err := tmpl.ExecuteTemplate(sw, "404", data) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	if err != nil { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-		fmt.Println(err) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		w.WriteHeader(http.StatusInternalServerError) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	} else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		w.WriteHeader(http.StatusNotFound) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		io.Copy(w, strings.NewReader(sw.String())) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	return bytes(""), nil 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	return err 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-func build451(w http.ResponseWriter, short string) (bytes, error) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	return nil, nil 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+func build451(w http.ResponseWriter, short string) error { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	return nil 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 // handleGetShort handles path /<short> 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -84,42 +92,18 @@ func handleGetShort(w http.ResponseWriter, r *http.Request) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	// 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) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-		} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		build404(w, short) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	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) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-		} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		build403(w, short) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	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) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-		} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		build451(w, short) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	default: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 		// TargetInvalid is not supposed to happen in this case, so it is an internal error too. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-		status = http.StatusInternalServerError 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-		w.WriteHeader(status) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		w.WriteHeader(http.StatusInternalServerError) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 |