Ah, thanks for that info -- glad somebody is reading the docs ... :-) Seems like you're well ahead of me here. I'd be interested to hear what others have done, or what you end up with. -Ben
On Wed, Oct 27, 2021 at 12:18 PM mi...@ubo.ro <mi...@ubo.ro> wrote: > 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 a topic in the > Google Groups "golang-nuts" group. > To unsubscribe from this topic, visit > https://groups.google.com/d/topic/golang-nuts/nTQ7F4b_wvI/unsubscribe. > To unsubscribe from this group and all its topics, 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 > <https://groups.google.com/d/msgid/golang-nuts/a9a6f788-6a45-49cf-9381-4abb98888864n%40googlegroups.com?utm_medium=email&utm_source=footer> > . > -- 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/CAL9jXCFxM%3DpdcYqceBv4gJ-GZOeYfEN2nkSqvY4yOSD8bDdkGg%40mail.gmail.com.