package main import ( "encoding/json" "fmt" "log" "math/rand/v2" "net/http" "unicode/utf8" ) const charSet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789" const version = "0.0.1" var Table map[string]string = make(map[string]string) type Request struct { URL string } type Response struct { Version string Status string Original string New string } func NewRequest(r *http.Request) (Request, error) { var request Request err := json.NewDecoder(r.Body).Decode(&request) return request, err } func log_header(r *http.Request) { log.Println("Header {") for k, v := range r.Header { log.Printf("\t\"%s\": \"%s\"\n", k, v) } log.Println("}") } func redirect(w http.ResponseWriter, r *http.Request) { log.Println("Request for:", r.URL.String()) log_header(r) _, i := utf8.DecodeRuneInString(r.URL.String()) url := r.URL.String()[i:] original, ok := Table[url] if ok { log.Println("Found:", original) w.Header().Set("location", original) http.Error(w, http.StatusText(301), 301) } else { log.Println("Unable to find website for", url) http.Error(w, http.StatusText(404), 404) } } func FindOrGenerate(url string) string { for key, value := range Table { if value == url { return key } } short := GenerateString(4) _, ok := Table[short] for ok { short = GenerateString(4) _, ok = Table[short] } Table[short] = url return short } func shorten(w http.ResponseWriter, r *http.Request) { log.Println("Request to Shorten") log_header(r) request, err := NewRequest(r) if err != nil { http.Error(w, http.StatusText(500), 500) } url := FindOrGenerate(request.URL) response := Response{version, "ok", request.URL, url} data, err := json.Marshal(response) if err != nil { http.Error(w, http.StatusText(500), 500) } fmt.Fprintf(w, "%s", string(data)) } func GenerateString(size uint) string { buffer := make([]rune, size) for i := uint(0); i < size; i++ { index := rand.Uint() % uint(len(charSet)) buffer[i] = []rune(charSet)[index] } return string(buffer) } func main() { http.HandleFunc("/shorten", shorten) http.HandleFunc("/", redirect) log.Fatal(http.ListenAndServe(":8000", nil)) }