diff --git a/linkchecker.go b/linkchecker.go index 2a0651a..7a7c6da 100644 --- a/linkchecker.go +++ b/linkchecker.go @@ -23,10 +23,16 @@ func NewLinkChecker() *LinkChecker { } } +type RedirectInfo struct { + FromURL string + ToURL string +} + type BrokenLink struct { URL string StatusCode int Error string + Redirect *RedirectInfo } func (lc *LinkChecker) normalizeURL(rawURL string) string { @@ -81,7 +87,8 @@ func (lc *LinkChecker) checkLinksRecursive(pageURL string, brokenLinks []BrokenL } for _, link := range links { - if status, err := lc.isLinkValid(link); status >= 400 || err != nil { + status, redirect, err := lc.isLinkValid(link) + if status >= 400 || err != nil { broken := BrokenLink{URL: link} if err != nil { broken.Error = err.Error() @@ -89,6 +96,13 @@ func (lc *LinkChecker) checkLinksRecursive(pageURL string, brokenLinks []BrokenL broken.StatusCode = status } brokenLinks = append(brokenLinks, broken) + } else if redirect != nil { + broken := BrokenLink{ + URL: link, + StatusCode: status, + Redirect: redirect, + } + brokenLinks = append(brokenLinks, broken) } // Recursively check links from the same domain @@ -154,12 +168,35 @@ func (lc *LinkChecker) getLinks(pageURL string) ([]string, error) { return links, nil } -func (lc *LinkChecker) isLinkValid(link string) (int, error) { - resp, err := lc.client.Get(link) +func (lc *LinkChecker) isLinkValid(link string) (int, *RedirectInfo, error) { + client := &http.Client{ + CheckRedirect: func(req *http.Request, via []*http.Request) error { + return http.ErrUseLastResponse + }, + } + + resp, err := client.Get(link) if err != nil { - return 0, err + return 0, nil, err } defer resp.Body.Close() - return resp.StatusCode, nil + if resp.StatusCode >= 300 && resp.StatusCode < 400 { + location := resp.Header.Get("Location") + if location != "" { + redirectURL := location + if !strings.HasPrefix(location, "http") { + baseURL, _ := url.Parse(link) + if relative, err := baseURL.Parse(location); err == nil { + redirectURL = relative.String() + } + } + return resp.StatusCode, &RedirectInfo{ + FromURL: link, + ToURL: redirectURL, + }, nil + } + } + + return resp.StatusCode, nil, nil } diff --git a/main.go b/main.go index f44a3dc..8de7c76 100644 --- a/main.go +++ b/main.go @@ -27,10 +27,12 @@ func main() { return } - fmt.Printf("Found %d broken links:\n", len(brokenLinks)) + fmt.Printf("Found %d issues:\n", len(brokenLinks)) for _, link := range brokenLinks { if link.Error != "" { fmt.Printf("- %s (Error: %s)\n", link.URL, link.Error) + } else if link.Redirect != nil { + fmt.Printf("- %s (Redirect %d -> %s)\n", link.URL, link.StatusCode, link.Redirect.ToURL) } else { fmt.Printf("- %s (Status: %d)\n", link.URL, link.StatusCode) }