code: func fetchJSON(c context.Context, client *http.Client, val interface{}, f func() (*http.Request, error)) error {
  	r, err := f()
  	if err != nil {
  		logging.Errorf(c, "auth: URL fetch failed - %s", err)
  		return err
  	}
  	logging.Infof(c, "auth: %s %s", r.Method, r.URL)
  	resp, err := ctxhttp.Do(c, client, r)
  	if err != nil {
  		logging.Errorf(c, "auth: URL fetch failed, can't connect - %s", err)
  		return transient.Tag.Apply(err)
  	}
  	defer func() {
  		ioutil.ReadAll(resp.Body)
  		resp.Body.Close()
  	}()
  	if resp.StatusCode >= 300 {
  		body, _ := ioutil.ReadAll(resp.Body)
  		// Opportunistically try to unmarshal the response. Works with JSON APIs.
  		if val != nil {
  			json.Unmarshal(body, val)
  		}
  		logging.Errorf(c, "auth: URL fetch failed - HTTP %d - %s", resp.StatusCode, string(body))
  		err := fmt.Errorf("auth: HTTP code (%d) when fetching %s", resp.StatusCode, r.URL)
  		if resp.StatusCode >= 500 {
  			return transient.Tag.Apply(err)
  		}
  		return err
  	}
  	if val != nil {
  		if err = json.NewDecoder(resp.Body).Decode(val); err != nil {
  			logging.Errorf(c, "auth: URL fetch failed, bad JSON - %s", err)
  			return fmt.Errorf("auth: can't deserialize JSON at %q - %s", r.URL, err)
  		}
  	}
  	return nil
  }
docs: // TODO(vadimsh): Add retries on HTTP 500.
  // fetchJSON fetches JSON document by making a request using given client.