From 1db9b465d74c3b9c2dbc3bcddd95a1030f61b9c1 Mon Sep 17 00:00:00 2001 From: httpjamesm Date: Mon, 21 Aug 2023 00:50:29 -0400 Subject: [PATCH 1/4] feat: redirect shortened URLs --- main.go | 2 ++ src/routes/shortened.go | 38 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+) create mode 100644 src/routes/shortened.go 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/shortened.go b/src/routes/shortened.go new file mode 100644 index 0000000..73e1b34 --- /dev/null +++ b/src/routes/shortened.go @@ -0,0 +1,38 @@ +package routes + +import ( + "fmt" + "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() + + resp, err := client.R().Get(fmt.Sprintf("https://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": "Unexpected HTTP status from origin", + "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)) +} From 6c7f8248e7bb865c616b0b7e2653ba70ef67a748 Mon Sep 17 00:00:00 2001 From: httpjamesm Date: Mon, 21 Aug 2023 00:51:38 -0400 Subject: [PATCH 2/4] feat: accept shortened URLs in converter --- src/routes/home.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/routes/home.go b/src/routes/home.go index c129e2f..1eb3fb0 100644 --- a/src/routes/home.go +++ b/src/routes/home.go @@ -37,8 +37,9 @@ func PostHome(c *gin.Context) { // 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), @@ -50,6 +51,9 @@ func PostHome(c *gin.Context) { if isStackOverflow { c.Redirect(302, strings.TrimPrefix(soLink, "https://stackoverflow.com")) return + } else if isShortenedStackOverflow { + c.Redirect(302, strings.TrimPrefix(soLink, "https://stackoverflow.com/a/")) + return } // if stack exchange, extract the subdomain From 7fa26139bc12b71763260c943218235e4921932b Mon Sep 17 00:00:00 2001 From: httpjamesm Date: Mon, 21 Aug 2023 00:56:39 -0400 Subject: [PATCH 3/4] fix: tell resty not to follow redirect --- .gitignore | 3 ++- src/routes/home.go | 8 ++++---- src/routes/shortened.go | 13 +++++++++++-- 3 files changed, 17 insertions(+), 7 deletions(-) diff --git a/.gitignore b/.gitignore index 2531ed9..a2dfaeb 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ .env docker-compose.yml .DS_Store -*bin \ No newline at end of file +*bin +main \ No newline at end of file diff --git a/src/routes/home.go b/src/routes/home.go index 1eb3fb0..27b511a 100644 --- a/src/routes/home.go +++ b/src/routes/home.go @@ -35,6 +35,9 @@ 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/") @@ -48,12 +51,9 @@ 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 - } else if isShortenedStackOverflow { - c.Redirect(302, strings.TrimPrefix(soLink, "https://stackoverflow.com/a/")) - return } // if stack exchange, extract the subdomain diff --git a/src/routes/shortened.go b/src/routes/shortened.go index 73e1b34..7e38e29 100644 --- a/src/routes/shortened.go +++ b/src/routes/shortened.go @@ -2,6 +2,8 @@ package routes import ( "fmt" + "log" + "net/http" "os" "github.com/gin-gonic/gin" @@ -13,8 +15,13 @@ func RedirectShortenedOverflowURL(c *gin.Context) { // 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://stackoverflow.com/a/%s", id)) + 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", @@ -23,9 +30,11 @@ func RedirectShortenedOverflowURL(c *gin.Context) { return } + log.Println(resp.String()) + if resp.StatusCode() != 302 { c.HTML(400, "home.html", gin.H{ - "errorMessage": "Unexpected HTTP status from origin", + "errorMessage": fmt.Sprintf("Unexpected HTTP status from origin: %d", resp.StatusCode()), "theme": c.MustGet("theme").(string), }) return From 1d8feea29058e4b4a473cd0aeaac9cb17a13672f Mon Sep 17 00:00:00 2001 From: httpjamesm Date: Mon, 21 Aug 2023 00:56:53 -0400 Subject: [PATCH 4/4] fix: remove log --- src/routes/shortened.go | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/routes/shortened.go b/src/routes/shortened.go index 7e38e29..ed1ad1e 100644 --- a/src/routes/shortened.go +++ b/src/routes/shortened.go @@ -2,7 +2,6 @@ package routes import ( "fmt" - "log" "net/http" "os" @@ -30,8 +29,6 @@ func RedirectShortenedOverflowURL(c *gin.Context) { return } - log.Println(resp.String()) - if resp.StatusCode() != 302 { c.HTML(400, "home.html", gin.H{ "errorMessage": fmt.Sprintf("Unexpected HTTP status from origin: %d", resp.StatusCode()),