Skip to content

Instantly share code, notes, and snippets.

@vbauerster
Last active March 26, 2019 11:55
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save vbauerster/81fb420d4b56d3cda14176817207238a to your computer and use it in GitHub Desktop.
Save vbauerster/81fb420d4b56d3cda14176817207238a to your computer and use it in GitHub Desktop.
package main
import (
"flag"
"fmt"
"log"
"net/http"
"net/url"
"os"
"strings"
)
type trace struct {
URL string
StatusCode int
Location string
}
var maxRedirects int
func init() {
flag.IntVar(&maxRedirects, "m", 10, "max redirects")
flag.Usage = usage
}
func usage() {
fmt.Fprintf(os.Stderr, "Usage: %s [OPTIONS] URL\n\n", os.Args[0])
fmt.Fprintln(os.Stderr, "OPTIONS:")
flag.PrintDefaults()
}
func main() {
flag.Parse()
args := flag.Args()
if len(args) != 1 {
flag.Usage()
os.Exit(2)
}
nextURL := parseURL(args[0]).String()
client := &http.Client{
CheckRedirect: func(req *http.Request, via []*http.Request) error {
return http.ErrUseLastResponse
},
}
for i := 0; i < maxRedirects; i++ {
t, err := visit(client, nextURL)
if err != nil {
log.Println(err)
continue
}
printRedirect(t)
if !isRedirect(t.StatusCode) || t.Location == "" {
break
}
nextURL = t.Location
}
}
func visit(client *http.Client, url string) (*trace, error) {
resp, err := client.Get(url)
if err != nil {
return nil, err
}
defer resp.Body.Close()
t := &trace{URL: url, StatusCode: resp.StatusCode}
if url, err := resp.Location(); err == nil {
t.Location = url.String()
}
return t, nil
}
func parseURL(uri string) *url.URL {
if !strings.Contains(uri, "://") && !strings.HasPrefix(uri, "//") {
uri = "//" + uri
}
url, err := url.Parse(uri)
if err != nil {
log.Fatalf("could not parse url %q: %v", uri, err)
}
if url.Scheme == "" {
url.Scheme = "http"
if !strings.HasSuffix(url.Host, ":80") {
url.Scheme += "s"
}
}
return url
}
func isRedirect(status int) bool {
return status > 299 && status < 400
}
func printRedirect(t *trace) {
fmt.Println()
fmt.Printf("Get: %q\n", t.URL)
fmt.Printf("StatusCode: %d\n", t.StatusCode)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment