From 2ef7e05f4b1e7f7cf33e801ac91713237517e500 Mon Sep 17 00:00:00 2001 From: httpjamesm <51917118+httpjamesm@users.noreply.github.com> Date: Mon, 21 Aug 2023 02:01:56 -0400 Subject: [PATCH] Redirect-short-links (#50) * feat: redirect shortened URLs * feat: accept shortened URLs in converter * fix: tell resty not to follow redirect * fix: remove log --- .gitignore | 2 +- main.go | 2 ++ src/routes/home.go | 8 ++++++-- src/routes/shortened.go | 44 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 53 insertions(+), 3 deletions(-) create mode 100644 src/routes/shortened.go diff --git a/.gitignore b/.gitignore index b0675a0..314373c 100644 --- a/.gitignore +++ b/.gitignore @@ -2,4 +2,4 @@ docker-compose.yml .DS_Store *bin -/tmp \ No newline at end of file +/tmp diff --git a/main.go b/main.go index b7bb84f..8b16302 100644 --- a/main.go +++ b/main.go @@ -50,6 +50,8 @@ func main() { r.GET("/", routes.GetHome) r.POST("/", routes.PostHome) + r.GET("/a/:id", routes.RedirectShortenedOverflowURL) + r.GET("/questions/:id", func(c *gin.Context) { // redirect user to the question with the title c.Redirect(302, fmt.Sprintf("/questions/%s/placeholder", c.Param("id"))) diff --git a/src/routes/home.go b/src/routes/home.go index c129e2f..27b511a 100644 --- a/src/routes/home.go +++ b/src/routes/home.go @@ -35,10 +35,14 @@ func PostHome(c *gin.Context) { soLink := body.URL + // remove the www. + soLink = strings.ReplaceAll(soLink, "www.", "") + // validate URL isStackOverflow := strings.HasPrefix(soLink, "https://stackoverflow.com/questions/") + isShortenedStackOverflow := strings.HasPrefix(soLink, "https://stackoverflow.com/a/") isStackExchange := stackExchangeRegex.MatchString(soLink) - if !isStackExchange && !isStackOverflow { + if !isStackExchange && !isStackOverflow && !isShortenedStackOverflow { c.HTML(400, "home.html", gin.H{ "errorMessage": "Invalid stack overflow/exchange URL", "theme": c.MustGet("theme").(string), @@ -47,7 +51,7 @@ func PostHome(c *gin.Context) { } // if stack overflow, trim https://stackoverflow.com - if isStackOverflow { + if isStackOverflow || isShortenedStackOverflow { c.Redirect(302, strings.TrimPrefix(soLink, "https://stackoverflow.com")) return } diff --git a/src/routes/shortened.go b/src/routes/shortened.go new file mode 100644 index 0000000..ed1ad1e --- /dev/null +++ b/src/routes/shortened.go @@ -0,0 +1,44 @@ +package routes + +import ( + "fmt" + "net/http" + "os" + + "github.com/gin-gonic/gin" + "github.com/go-resty/resty/v2" +) + +func RedirectShortenedOverflowURL(c *gin.Context) { + id := c.Param("id") + + // fetch the stack overflow URL + client := resty.New() + client.SetRedirectPolicy( + resty.RedirectPolicyFunc(func(req *http.Request, via []*http.Request) error { + return http.ErrUseLastResponse + }), + ) + + resp, err := client.R().Get(fmt.Sprintf("https://www.stackoverflow.com/a/%s", id)) + if err != nil { + c.HTML(400, "home.html", gin.H{ + "errorMessage": "Unable to fetch stack overflow URL", + "theme": c.MustGet("theme").(string), + }) + return + } + + if resp.StatusCode() != 302 { + c.HTML(400, "home.html", gin.H{ + "errorMessage": fmt.Sprintf("Unexpected HTTP status from origin: %d", resp.StatusCode()), + "theme": c.MustGet("theme").(string), + }) + return + } + + // get the redirect URL + location := resp.Header().Get("Location") + + c.Redirect(302, fmt.Sprintf("%s%s", os.Getenv("APP_URL"), location)) +}