media.go
func (m *MediaService) GetURL(ctx context.Context, messageSid string, sid string) (*url.URL, error) {
	uriEnd := strings.Join([]string{mediaPathPart(messageSid), sid}, "/")
	path := m.client.FullPath(uriEnd)
	// We want the media, not the .json representation
	if strings.HasSuffix(path, ".json") {
		path = path[:len(path)-len(".json")]
	}
	urlStr := m.client.Client.Base + path
	count := 0
	for {
		req, err := http.NewRequest("GET", urlStr, nil)
		if err != nil {
			return nil, err
		}
		req = withContext(req, ctx)
		req.SetBasicAuth(m.client.AccountSid, m.client.AuthToken)
		req.Header.Set("User-Agent", userAgent)
		if os.Getenv("DEBUG_HTTP_TRAFFIC") == "true" || os.Getenv("DEBUG_HTTP_REQUEST") == "true" {
			b := new(bytes.Buffer)
			bits, _ := httputil.DumpRequestOut(req, true)
			if len(bits) > 0 && bits[len(bits)-1] != '\n' {
				bits = append(bits, '\n')
			}
			b.Write(bits)
			io.Copy(os.Stderr, b)
		}
		resp, err := MediaClient.Do(req)
		if err != nil {
			return nil, err
		}
		if os.Getenv("DEBUG_HTTP_TRAFFIC") == "true" || os.Getenv("DEBUG_HTTP_RESPONSES") == "true" {
			b := new(bytes.Buffer)
			bits, _ := httputil.DumpResponse(resp, true)
			if len(bits) > 0 && bits[len(bits)-1] != '\n' {
				bits = append(bits, '\n')
			}
			b.Write(bits)
			io.Copy(os.Stderr, b)
		} else {
			io.Copy(ioutil.Discard, resp.Body)
		}

		resp.Body.Close()
		// This is brittle because we need to detect/rewrite the S3 URL.
		// I don't want to hard code a S3 URL but we have to do some
		// substitution.
		location := resp.Header.Get("Location")
		if location == "" {
			return nil, errors.New("twilio: Couldn't follow redirect")
		}
		u, err := url.Parse(location)
		if err != nil {
			return nil, err
		}
		if strings.Contains(u.Host, "amazonaws") && strings.Count(u.Host, ".") == 2 && u.Scheme == "https" {
			return u, nil
		}
		if strings.Contains(u.Host, "media.twiliocdn.com.") && strings.Contains(u.Host, "amazonaws") {
			// This is the URL we can use to download the content. The URL that
			// Twilio gives us back is insecure and uses HTTP. Rewrite it to
			// use the HTTPS path-based URL scheme.
			//
			// https://docs.aws.amazon.com/AmazonS3/latest/dev/UsingBucket.html
			if u.Scheme == "http" {
				u.Host = strings.Replace(u.Host, "media.twiliocdn.com.", "", 1)
				u.Path = "/media.twiliocdn.com" + u.Path
				u.Scheme = "https"
			}
			return u, nil
		}
		count++
		if count > 5 {
			return nil, errors.New("twilio: too many redirects")
		}
		urlStr = location
	}
}
func (m *MediaService) GetURL(ctx context.Context, messageSid string, sid string) (*url.URL, error) {
	uriEnd := strings.Join([]string{mediaPathPart(messageSid), sid}, "/")
	path := m.client.FullPath(uriEnd)
	// We want the media, not the .json representation
	if strings.HasSuffix(path, ".json") {
		path = path[:len(path)-len(".json")]
	}
	urlStr := m.client.Client.Base + path
	count := 0
	for {
		req, err := http.NewRequest("GET", urlStr, nil)
		if err != nil {
			return nil, err
		}
		req = withContext(req, ctx)
		req.SetBasicAuth(m.client.AccountSid, m.client.AuthToken)
		req.Header.Set("User-Agent", userAgent)
		if os.Getenv("DEBUG_HTTP_TRAFFIC") == "true" || os.Getenv("DEBUG_HTTP_REQUEST") == "true" {
			b := new(bytes.Buffer)
			bits, _ := httputil.DumpRequestOut(req, true)
			if len(bits) > 0 && bits[len(bits)-1] != '\n' {
				bits = append(bits, '\n')
			}
			b.Write(bits)
			io.Copy(os.Stderr, b)
		}
		resp, err := MediaClient.Do(req)
		if err != nil {
			return nil, err
		}
		if os.Getenv("DEBUG_HTTP_TRAFFIC") == "true" || os.Getenv("DEBUG_HTTP_RESPONSES") == "true" {
			b := new(bytes.Buffer)
			bits, _ := httputil.DumpResponse(resp, true)
			if len(bits) > 0 && bits[len(bits)-1] != '\n' {
				bits = append(bits, '\n')
			}
			b.Write(bits)
			io.Copy(os.Stderr, b)
		} else {
			io.Copy(ioutil.Discard, resp.Body)
		}

		resp.Body.Close()
		// This is brittle because we need to detect/rewrite the S3 URL.
		// I don't want to hard code a S3 URL but we have to do some
		// substitution.
		location := resp.Header.Get("Location")
		if location == "" {
			return nil, errors.New("twilio: Couldn't follow redirect")
		}
		u, err := url.Parse(location)
		if err != nil {
			return nil, err
		}
		if strings.Contains(u.Host, "amazonaws") && strings.Count(u.Host, ".") == 2 && u.Scheme == "https" {
			return u, nil
		}
		if strings.Contains(u.Host, "media.twiliocdn.com.") && strings.Contains(u.Host, "amazonaws") {
			// This is the URL we can use to download the content. The URL that
			// Twilio gives us back is insecure and uses HTTP. Rewrite it to
			// use the HTTPS path-based URL scheme.
			//
			// https://docs.aws.amazon.com/AmazonS3/latest/dev/UsingBucket.html
			if u.Scheme == "http" {
				u.Host = strings.Replace(u.Host, "media.twiliocdn.com.", "", 1)
				u.Path = "/media.twiliocdn.com" + u.Path
				u.Scheme = "https"
			}
			return u, nil
		}
		count++
		if count > 5 {
			return nil, errors.New("twilio: too many redirects")
		}
		urlStr = location
	}
}
// GetURL returns a URL that can be retrieved to download the given image.