diff options
| author | 2024-04-02 12:12:26 +0100 | |
|---|---|---|
| committer | 2024-04-02 13:12:26 +0200 | |
| commit | d61d5c8a6ad045fe7779fe8d0efe2fd06f691fba (patch) | |
| tree | 12b1f1ed8e2cee3875c74347e0f034bbb8f57134 /internal/httpclient | |
| parent | [chore] Try to parse public key as both Actor + bare key (#2710) (diff) | |
| download | gotosocial-d61d5c8a6ad045fe7779fe8d0efe2fd06f691fba.tar.xz | |
[bugfix] httpclient not signing subsequent redirect requests (#2798)
* move http request signing to transport
* actually hook up the http roundtripper ...
* add code comments for the new gtscontext functions
Diffstat (limited to 'internal/httpclient')
| -rw-r--r-- | internal/httpclient/client.go | 25 | ||||
| -rw-r--r-- | internal/httpclient/sign.go | 41 |
2 files changed, 42 insertions, 24 deletions
diff --git a/internal/httpclient/client.go b/internal/httpclient/client.go index 7adea7459..6c2427372 100644 --- a/internal/httpclient/client.go +++ b/internal/httpclient/client.go @@ -32,7 +32,6 @@ import ( "time" "codeberg.org/gruf/go-bytesize" - "codeberg.org/gruf/go-byteutil" "codeberg.org/gruf/go-cache/v3" errorsv2 "codeberg.org/gruf/go-errors/v2" "codeberg.org/gruf/go-iotools" @@ -163,7 +162,7 @@ func New(cfg Config) *Client { } // Set underlying HTTP client roundtripper. - c.client.Transport = &http.Transport{ + c.client.Transport = &signingtransport{http.Transport{ Proxy: http.ProxyFromEnvironment, ForceAttemptHTTP2: true, DialContext: d.DialContext, @@ -175,7 +174,7 @@ func New(cfg Config) *Client { ReadBufferSize: cfg.ReadBufferSize, WriteBufferSize: cfg.WriteBufferSize, DisableCompression: cfg.DisableCompression, - } + }} // Initiate outgoing bad hosts lookup cache. c.badHosts = cache.NewTTL[string, struct{}](0, 1000, 0) @@ -239,23 +238,6 @@ func (c *Client) DoSigned(r *http.Request, sign SignFunc) (rsp *http.Response, e for i := 0; i < maxRetries; i++ { var backoff time.Duration - // Reset signing header fields - now := time.Now().UTC() - r.Header.Set("Date", now.Format("Mon, 02 Jan 2006 15:04:05")+" GMT") - r.Header.Del("Signature") - r.Header.Del("Digest") - - // Rewind body reader and content-length if set. - if rc, ok := r.Body.(*byteutil.ReadNopCloser); ok { - rc.Rewind() // set len AFTER rewind - r.ContentLength = int64(rc.Len()) - } - - // Sign the outgoing request. - if err := sign(r); err != nil { - return nil, err - } - l.Info("performing request") // Perform the request. @@ -276,6 +258,9 @@ func (c *Client) DoSigned(r *http.Request, sign SignFunc) (rsp *http.Response, e // Search for a provided "Retry-After" header value. if after := rsp.Header.Get("Retry-After"); after != "" { + // Get current time. + now := time.Now() + if u, _ := strconv.ParseUint(after, 10, 32); u != 0 { // An integer number of backoff seconds was provided. backoff = time.Duration(u) * time.Second diff --git a/internal/httpclient/sign.go b/internal/httpclient/sign.go index 78046aa28..8e66d1bda 100644 --- a/internal/httpclient/sign.go +++ b/internal/httpclient/sign.go @@ -17,12 +17,45 @@ package httpclient -import "net/http" +import ( + "net/http" + "time" + + "codeberg.org/gruf/go-byteutil" + "github.com/superseriousbusiness/gotosocial/internal/gtscontext" +) // SignFunc is a function signature that provides request signing. type SignFunc func(r *http.Request) error -type SigningClient interface { - Do(r *http.Request) (*http.Response, error) - DoSigned(r *http.Request, sign SignFunc) (*http.Response, error) +// signingtransport wraps an http.Transport{} +// (RoundTripper implementer) to check request +// context for a signing function and using for +// all subsequent trips through RoundTrip(). +type signingtransport struct { + http.Transport // underlying transport +} + +func (t *signingtransport) RoundTrip(r *http.Request) (*http.Response, error) { + if sign := gtscontext.HTTPClientSignFunc(r.Context()); sign != nil { + // Reset signing header fields + now := time.Now().UTC() + r.Header.Set("Date", now.Format("Mon, 02 Jan 2006 15:04:05")+" GMT") + r.Header.Del("Signature") + r.Header.Del("Digest") + + // Rewind body reader and content-length if set. + if rc, ok := r.Body.(*byteutil.ReadNopCloser); ok { + rc.Rewind() // set len AFTER rewind + r.ContentLength = int64(rc.Len()) + } + + // Sign the outgoing request. + if err := sign(r); err != nil { + return nil, err + } + } + + // Pass to underlying transport. + return t.Transport.RoundTrip(r) } |
