That would work great but the documentation on RoundTriper specifically forbids it[0]. Unless I get it wrong(do I?) you are not allowed to read the response within RoundTrip. The request needs to be .Clone-ed as well but that's not an issue.
[0] https://pkg.go.dev/net/http#RoundTripper // RoundTrip should not attempt to interpret the response. In // particular, RoundTrip must return err == nil if it obtained // a response, regardless of the response's HTTP status code. // A non-nil err should be reserved for failure to obtain a // response. Similarly, RoundTrip should not attempt to // handle higher-level protocol details such as redirects, // authentication, or cookies. // RoundTrip should not modify the request *On 27/10/2021 02:09, Ben Hoyt wrote:* *Oh, I see. An "ExecuteHTTP" function seems reasonable, but yeah, if you need an *http.Client, I think you have to customize the Transport/Roundtripper. You mention in your initial email that RoundTripper "forbids you from even reading the response headers", but I don't think that's the case, right?* *For example, here's a custom "AuthTransport":* *type AuthTransport struct { AuthHeader string}func (t *AuthTransport) RoundTrip(request *http.Request) (*http.Response, error) { request.Header.Set("X-My-Auth", t.AuthHeader) response, err := http.DefaultTransport.RoundTrip(request) if err != nil { return nil, err } if response.StatusCode == 403 || response.Header.Get("WWW-Authenticate") != "" { fmt.Println("Would retry here") } return response, nil}* *and then you'd instantiate your http.Client like so:* *client := &http.Client{ Timeout: 5 * time.Second, Transport: &AuthTransport{AuthHeader: "abcd1234"},}* *Did that not work for you?* *-Ben* On Wednesday, October 27, 2021 at 1:52:18 AM UTC+3 mi...@ubo.ro wrote: > Thanks for your help. I'm aware I can set the headers that way but the > authentication transport also needs to inspect the response headers and > optionally re-submit the request based on the headers received. That's part > of the "negotiation" mechanism. That's because we don;t know what > authentication scheme is supported by the remote party until we receive the > actual response/headers from a blind request. > > Below is a simple use case: > > - the http client executes a reques with no authentication. > > - we receive a status code 403 along with a www-header indicating that > oauth2 authentication is supported. > > - we resend the request with appropriate oauth2 headers. > > Note that we had to read the response code and response headers so that we > can re-send the request. This is the part that I wish I could automate > using the http.RoundTripper. > > The alternative is to either handle the response manually after each > request or create a custom endpoint < i.e. func ExecuteHTTP(*http.Client, > *http.Request)(*http.Response, error) > that handles the response headers > and retries the requests using the proper authentication headers. > > In both cases you loose the flexibility to use a http client that does all > this in the background. > > Some packages (i.e ElasticSearch package) support configuration using your > own http client. However you cannot pass a custom `ExecuteHTTP` function to > ElasticSearch so it becomes quite hard to hack the > authentication/negotiation. > > - Mihai. > > On Wednesday, October 27, 2021 at 1:32:24 AM UTC+3 ben...@gmail.com wrote: > >> I'm not sure what these proprietary auth schemes look like (and don't >> know much about oauth2 or NTLM), but for many kinds of auth you'd just set >> headers in the request and read them in the body. For example: >> >> request, err := http.NewRequest("GET", "https://httpbin.org/get", >> nil) >> // handle err >> request.Header.Set("X-My-Auth", "abcd1234") >> response, err := client.Do(request) >> // handle err >> // handle response >> >> Runnable code example here: >> https://play.golang.org/p/cocv1avzNCo >> >> And of course you can roll your own function to create a new request with >> auth headers already applied. Would this kind of thing work for you? >> >> -Ben >> >> On Tuesday, October 26, 2021 at 2:05:15 PM UTC+13 mi...@ubo.ro wrote: >> >>> I find myself in need to handle various authentication schemes such >>> "proprietary" oauth2 schemes and NTLM. The easy and clean way to do it (API >>> wise) would be using a http.RoundTripper but looks like it forbids you from >>> even reading the response headers. >>> >>> In the end I just made a ``func >>> DoHTTPRequestWithAuthenticationHandling(cl *http.Client, req >>> *http.Request)(*http.Response, error)`` function that just wraps net/ >>> http.Client.Do(), clones the request and response if it's necessary and >>> negotiates the authentication scheme. It's basically what I wanted to do >>> within http.RoundTripper except now the user of the http.Client needs to >>> always remember to execute the requests the right way (i.e. using a >>> different function) instead of http.Do. >>> >>> Is there a better way to do it? Would it be a good idea in Go 2.0 make >>> http.Client an interface to prevent this kind of limitation/workarounds? >>> >> -- You received this message because you are subscribed to the Google Groups "golang-nuts" group. To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscr...@googlegroups.com. To view this discussion on the web visit https://groups.google.com/d/msgid/golang-nuts/a9a6f788-6a45-49cf-9381-4abb98888864n%40googlegroups.com.