diff options
author | 2023-11-13 19:48:51 +0100 | |
---|---|---|
committer | 2023-11-13 19:48:51 +0100 | |
commit | 8d0c017cf205bcf57630c91b53079001deed4d36 (patch) | |
tree | cf2240e3dff137df2871c9b93548a885833e9a52 /internal/api | |
parent | [chore] update otel -> v1.20.0 (#2358) (diff) | |
download | gotosocial-8d0c017cf205bcf57630c91b53079001deed4d36.tar.xz |
[feature/performance] Wrap incoming HTTP requests in timeout handler (#2353)
* deinterface router, start messing about with deadlines
* weeeee
* thanks linter (thinter)
* write Connection: close when timing out requests
* update wording
* don't replace req
* don't bother with fancy Cause functions (I'll use them one day...)
Diffstat (limited to 'internal/api')
-rw-r--r-- | internal/api/activitypub.go | 4 | ||||
-rw-r--r-- | internal/api/auth.go | 2 | ||||
-rw-r--r-- | internal/api/client.go | 2 | ||||
-rw-r--r-- | internal/api/fileserver.go | 2 | ||||
-rw-r--r-- | internal/api/nodeinfo.go | 2 | ||||
-rw-r--r-- | internal/api/util/errorhandling.go | 46 | ||||
-rw-r--r-- | internal/api/wellknown.go | 2 |
7 files changed, 41 insertions, 19 deletions
diff --git a/internal/api/activitypub.go b/internal/api/activitypub.go index 02ae0767c..0c0222d1c 100644 --- a/internal/api/activitypub.go +++ b/internal/api/activitypub.go @@ -35,7 +35,7 @@ type ActivityPub struct { signatureCheckMiddleware gin.HandlerFunc } -func (a *ActivityPub) Route(r router.Router, m ...gin.HandlerFunc) { +func (a *ActivityPub) Route(r *router.Router, m ...gin.HandlerFunc) { // create groupings for the 'emoji' and 'users' prefixes emojiGroup := r.AttachGroup("emoji") usersGroup := r.AttachGroup("users") @@ -54,7 +54,7 @@ func (a *ActivityPub) Route(r router.Router, m ...gin.HandlerFunc) { } // Public key endpoint requires different middleware + cache policies from other AP endpoints. -func (a *ActivityPub) RoutePublicKey(r router.Router, m ...gin.HandlerFunc) { +func (a *ActivityPub) RoutePublicKey(r *router.Router, m ...gin.HandlerFunc) { // Create grouping for the 'users/[username]/main-key' prefix. publicKeyGroup := r.AttachGroup(publickey.PublicKeyPath) diff --git a/internal/api/auth.go b/internal/api/auth.go index 961caa981..8d7808a3a 100644 --- a/internal/api/auth.go +++ b/internal/api/auth.go @@ -36,7 +36,7 @@ type Auth struct { } // Route attaches 'auth' and 'oauth' groups to the given router. -func (a *Auth) Route(r router.Router, m ...gin.HandlerFunc) { +func (a *Auth) Route(r *router.Router, m ...gin.HandlerFunc) { // create groupings for the 'auth' and 'oauth' prefixes authGroup := r.AttachGroup("auth") oauthGroup := r.AttachGroup("oauth") diff --git a/internal/api/client.go b/internal/api/client.go index ec8fa6034..1112efa31 100644 --- a/internal/api/client.go +++ b/internal/api/client.go @@ -79,7 +79,7 @@ type Client struct { user *user.Module // api/v1/user } -func (c *Client) Route(r router.Router, m ...gin.HandlerFunc) { +func (c *Client) Route(r *router.Router, m ...gin.HandlerFunc) { // create a new group on the top level client 'api' prefix apiGroup := r.AttachGroup("api") diff --git a/internal/api/fileserver.go b/internal/api/fileserver.go index 8f1e60b82..59f38c362 100644 --- a/internal/api/fileserver.go +++ b/internal/api/fileserver.go @@ -30,7 +30,7 @@ type Fileserver struct { fileserver *fileserver.Module } -func (f *Fileserver) Route(r router.Router, m ...gin.HandlerFunc) { +func (f *Fileserver) Route(r *router.Router, m ...gin.HandlerFunc) { fileserverGroup := r.AttachGroup("fileserver") // Attach middlewares appropriate for this group. diff --git a/internal/api/nodeinfo.go b/internal/api/nodeinfo.go index 22d314033..fb7918edc 100644 --- a/internal/api/nodeinfo.go +++ b/internal/api/nodeinfo.go @@ -29,7 +29,7 @@ type NodeInfo struct { nodeInfo *nodeinfo.Module } -func (w *NodeInfo) Route(r router.Router, m ...gin.HandlerFunc) { +func (w *NodeInfo) Route(r *router.Router, m ...gin.HandlerFunc) { // group nodeinfo endpoints together nodeInfoGroup := r.AttachGroup("nodeinfo") diff --git a/internal/api/util/errorhandling.go b/internal/api/util/errorhandling.go index 33f501474..4fa544ffd 100644 --- a/internal/api/util/errorhandling.go +++ b/internal/api/util/errorhandling.go @@ -19,6 +19,7 @@ package util import ( "context" + "errors" "net/http" "codeberg.org/gruf/go-kv" @@ -90,19 +91,40 @@ func genericErrorHandler(c *gin.Context, instanceGet func(ctx context.Context) ( // try to serve an appropriate application/json content-type error. // To override the default response type, specify `offers`. // -// If the requester already hung up on the request, ErrorHandler -// will overwrite the given errWithCode with a 499 error to indicate -// that the failure wasn't due to something we did, and will avoid -// trying to write extensive bytes to the caller by just aborting. +// If the requester already hung up on the request, or the server +// timed out a very slow request, ErrorHandler will overwrite the +// given errWithCode with a 408 or 499 error to indicate that the +// failure wasn't due to something we did, and will avoid trying +// to write extensive bytes to the caller by just aborting. // -// See: https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#nginx. -func ErrorHandler(c *gin.Context, errWithCode gtserror.WithCode, instanceGet func(ctx context.Context) (*apimodel.InstanceV1, gtserror.WithCode), offers ...MIME) { - if c.Request.Context().Err() != nil { - // Context error means requester probably left already. - // Wrap original error with a less alarming one. Then - // we can return early, because it doesn't matter what - // we send to the client at this point; they're gone. - errWithCode = gtserror.NewErrorClientClosedRequest(errWithCode.Unwrap()) +// For 499, see https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#nginx. +func ErrorHandler( + c *gin.Context, + errWithCode gtserror.WithCode, + instanceGet func(ctx context.Context) (*apimodel.InstanceV1, gtserror.WithCode), + offers ...MIME, +) { + if ctxErr := c.Request.Context().Err(); ctxErr != nil { + // Context error means either client has left already, + // or server has timed out a very slow request. + // + // Rewrap the error with something less scary, + // and just abort the request gracelessly. + err := errWithCode.Unwrap() + + if errors.Is(ctxErr, context.DeadlineExceeded) { + // We timed out the request. + errWithCode = gtserror.NewErrorRequestTimeout(err) + + // Be correct and write "close". + // See: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Connection#close + // and: https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/408 + c.Header("Connection", "close") + } else { + // Client timed out the request. + errWithCode = gtserror.NewErrorClientClosedRequest(err) + } + c.AbortWithStatus(errWithCode.Code()) return } diff --git a/internal/api/wellknown.go b/internal/api/wellknown.go index 63ca48ef7..90e18d637 100644 --- a/internal/api/wellknown.go +++ b/internal/api/wellknown.go @@ -33,7 +33,7 @@ type WellKnown struct { hostMeta *hostmeta.Module } -func (w *WellKnown) Route(r router.Router, m ...gin.HandlerFunc) { +func (w *WellKnown) Route(r *router.Router, m ...gin.HandlerFunc) { // group .well-known endpoints together wellKnownGroup := r.AttachGroup(".well-known") |