diff options
| -rw-r--r-- | go.mod | 3 | ||||
| -rw-r--r-- | main.go | 105 | ||||
| -rwxr-xr-x | test.sh | 9 |
3 files changed, 117 insertions, 0 deletions
@@ -0,0 +1,3 @@ +module mcdonnell.dev/url-shortener + +go 1.26.1 @@ -0,0 +1,105 @@ +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 { + w.Header().Set("location", original) + http.Error(w, http.StatusText(301), 301) + } else { + http.Error(w, http.StatusText(404), 404) + } +} + +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 := GenerateString(4) + _, ok := Table[url] + + for ok { + url = GenerateString(4) + _, ok = Table[url] + } + + Table[url] = 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)) +} @@ -0,0 +1,9 @@ +#!/usr/bin/env bash + +RES=$(curl -X 'POST' \ + -H 'accept: application/json' \ + -H 'Content-Type: application/json' \ + --data '{ "URL": "https://git.mcdonnell.dev/" }' \ + http://localhost:8000/shorten 2>/dev/null) +printf '%s\n' "$(echo "$RES" | json_pp)" + |
