func Send()

in utils/httputil/httputil.go [283:351]


func Send(method, rawurl string, options ...SendOption) (*http.Response, error) {
	u, err := url.Parse(rawurl)
	if err != nil {
		return nil, fmt.Errorf("parse url: %s", err)
	}
	opts := &sendOptions{
		body:                 nil,
		timeout:              60 * time.Second,
		acceptedCodes:        map[int]bool{http.StatusOK: true},
		headers:              map[string]string{},
		retry:                retryOptions{backoff: &backoff.StopBackOff{}},
		transport:            nil, // Use HTTP default.
		ctx:                  context.Background(),
		url:                  u,
		httpFallbackDisabled: true,
	}
	for _, o := range options {
		o(opts)
	}

	req, err := newRequest(method, opts)
	if err != nil {
		return nil, err
	}

	client := &http.Client{
		Timeout:       opts.timeout,
		CheckRedirect: opts.redirect,
		Transport:     opts.transport,
	}

	var resp *http.Response
	for {
		resp, err = client.Do(req)
		// Retry without tls. During migration there would be a time when the
		// component receiving the tls request does not serve https response.
		// TODO (@evelynl): disable retry after tls migration.
		if err != nil && req.URL.Scheme == "https" && !opts.httpFallbackDisabled {
			originalErr := err
			resp, err = fallbackToHTTP(client, method, opts)
			if err != nil {
				// Sometimes the request fails for a reason unrelated to https.
				// To keep this reason visible, we always include the original
				// error.
				err = fmt.Errorf(
					"failed to fallback https to http, original https error: %s,\n"+
						"fallback http error: %s", originalErr, err)
			}
		}
		if err != nil ||
			(isRetryable(resp.StatusCode) && !opts.acceptedCodes[resp.StatusCode]) ||
			(opts.retry.extraCodes[resp.StatusCode]) {
			d := opts.retry.backoff.NextBackOff()
			if d == backoff.Stop {
				break // Backoff timed out.
			}
			time.Sleep(d)
			continue
		}
		break
	}
	if err != nil {
		return nil, NetworkError{err}
	}
	if !opts.acceptedCodes[resp.StatusCode] {
		return nil, NewStatusError(resp)
	}
	return resp, nil
}