title: Go lang Capture Redirect urls and status codes with timeouts
body: <p>I am trying to make a request to a given url, and capture the redirect urls and their status codes that were followed.</p>
  
  <p>I've tried looking for an answer to my specific question - <a href="https://stackoverflow.com/questions/24577494/how-to-get-the-http-redirect-status-codes-in-golang">this</a> came close .</p>
  
  <p>However, I need to also add proxy, user agent and timeouts on the entire connection i.e. No matter how many redirects / proxy latency etc, the amount of time should not exceed X seconds.</p>
  
  <p>I've handled user-agent by setting request header, and proxy by adding it to the Transport struct.
  I tried exploring CheckRedirect for redirects - but that gives me only Url, I needed the status code as well, so I had to implement the RoundTrip function.</p>
  
  <p>Everything works well as of now - except for the Timeout.
  Heres what I have so far - <a href="http://play.golang.org/p/m6-ukzykSQ" rel="nofollow noreferrer">playground link</a>
  I've pasted the relevant code here as well - the playground has a full version with a mock redirect server in place - Unfortunately it panics saying connection refused possibly because of playground restrictions - It works completely locally though.</p>
  
  <pre><code>type Redirect struct {
      StatusCode int
      URL string
  }
  
  type TransportWrapper struct {
      Transport http.RoundTripper
      Url string
      Proxy string
      UserAgent string
      TimeoutInSeconds int
      FinalUrl string
      RedirectUrls []Redirect
  }
  // Implementing Round Tripper to capture intermediate urls
  func (t *TransportWrapper) RoundTrip(req *http.Request) (*http.Response, error) {
      transport := t.Transport
      if transport == nil {
          transport = http.DefaultTransport
      }
  
      resp, err := transport.RoundTrip(req)
      if err != nil {
          return resp, err
      }
  
      // Remember redirects
      if resp.StatusCode &gt;= 300 &amp;&amp; resp.StatusCode &lt;= 399 {
          t.RedirectUrls = append(
              t.RedirectUrls, Redirect{resp.StatusCode, req.URL.String()},
          )
      }
      return resp, err
  }
  
  func (t *TransportWrapper) Do() (*http.Response, error) {
      t.Transport = &amp;http.Transport{}
      if t.Proxy != "" {
          proxyUrl, err := url.Parse(t.Proxy)
          if err != nil {
              return nil, err
          }
  
          t.Transport = &amp;http.Transport{Proxy:http.ProxyURL(proxyUrl)}
          // HELP
          // Why does this fail
          // t.Transport.Proxy = http.ProxyUrl(proxyUrl)
      }
  
      client := &amp;http.Client{
          Transport: t, // Since I've implemented RoundTrip I can pass this
          // Timeout: t.TimeoutInSeconds * time.Second, // This Fails 
      }
  
      req, err := http.NewRequest("GET", t.Url, nil)
      if err != nil {
          return nil, err
      }
  
      if t.UserAgent != "" {
          req.Header.Set("User-Agent", t.UserAgent)
      }
  
      resp, err := client.Do(req)
      if err != nil {
          return nil, err
      }
  
      t.FinalUrl = resp.Request.URL.String()
      return resp, nil
  }
  
  func startClient() {
      t := &amp;TransportWrapper {
          Url: "http://127.0.0.1:8080/temporary/redirect?num=5",
          // Proxy
          // UserAgent
          // Timeout
      }
  
      _, err := t.Do()
      if err != nil {
          panic(err)
      }
  
      fmt.Printf("Intermediate Urls: \n")
      for i, v := range t.RedirectUrls {
          fmt.Printf("[%d] %s\n", i, v)
      }
  
  }
  </code></pre>
  
  <p>Question 1 : How do I Add the timeout ? </p>
  
  <p>Attempt #1 :  </p>
  
  <pre><code>client := &amp;http.Client{ Transport: t, Timeout: myTimeout }
  </code></pre>
  
  <p>But Go complains saying " *main.TransportWrapper doesn't support CancelRequest; Timeout not supported "</p>
  
  <p>Attempt #2 :</p>
  
  <pre><code>// Adding a CancelRequest
  func (t *TransportWrapper) CancelRequest(req *http.Request) {
      dt := http.DefaultTransport
      dt.CancelRequest(req)
  }
  </code></pre>
  
  <p>But Go complains saying "dt.CancelRequest undefined (type http.RoundTripper has no field or method CancelRequest)"</p>
  
  <p>How do I implement this CancelRequest without doing too much and just let default CancelRequest take over ?</p>
  
  <p>Question 2 : Have I gone down a bad path and is there an alternative to solving the problem , </p>
  
  <p>Given a Url, Proxy, UserAgent and Timeout - return the response along with the redirect urls and their status codes followed to get there.</p>
  
  <p>I hope I've worded this appropriately.</p>
  
  <p>Thanks</p>