-
Notifications
You must be signed in to change notification settings - Fork 8.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Allow routes to specify the idle socket timeout in addition to the payload timeout #73730
Conversation
src/core/server/http/http_server.ts
Outdated
if (timeout?.idleSocket) { | ||
socketTimeout = timeout.idleSocket; | ||
} else if (payloadTimeout) { | ||
// Hapi server requires the socket to be greater than payload settings so we add 1 millisecond |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's rather confusing that socketTimeout
is completely ignored. a couple of options:
- use a higher value
Math.max(socketTimeout, payloadTimeout + 1)
- do not rely on Hapi and set
socket.setTimeout(...)
in a request interceptor manually
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's rather confusing that socketTimeout is completely ignored
If the route specifies the timeout.idleSocket
it will always be used. Even if it leads to an error being thrown if it's smaller than the payload timeout...
use a higher value Math.max(socketTimeout, payloadTimeout + 1)
If the route definition tries to explicitly set the idle socket timeout to be smaller than the payload timeout, it feels less surprising to consumers to just throw an explicit error.
do not rely on Hapi and set socket.setTimeout(...) in a request interceptor manually
I'm hopeful that this will be a temporary requirement, and hapijs/hapi#4123 will merge shortly. The only route that I'm aware of that will need to set the idle socket timeout is Fleet, which is adjusting the timeout to be super long to support long-polling, so they won't hit us leaking HapiJS constraints.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you know if hapijs/hapi#4123 is going to be backported to Hapi v17?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you know if hapijs/hapi#4123 is going to be backported to Hapi v17?
I don't... I just asked for clarification in hapijs/hapi#4123 (comment).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Per hapijs/hapi#4123 (comment)
If this lands, it will only be for v20. If you need support for an older version, you'll have to check on a commercial license - #4114.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
3d8901a works around the HapiJS constraints by setting a socket timeout on the route definition when a payload timeout is specified, and then uses the onPreAuth
lifecycle event to set the actual socket timeout... It's not possible to do so in the onRequest
lifecycle event because the route hasn't been looked up yet per https://hapi.dev/api/?v=19.2.0#request-lifecycle
src/core/server/http/http_server.ts
Outdated
@@ -164,7 +164,16 @@ export class HttpServer { | |||
const { authRequired, tags, body = {}, timeout } = route.options; | |||
const { accepts: allow, maxBytes, output, parse } = body; | |||
// Hapi does not allow timeouts on payloads to be specified for 'head' or 'get' requests | |||
const payloadTimeout = isSafeMethod(route.method) || timeout == null ? undefined : timeout; | |||
const payloadTimeout = isSafeMethod(route.method) ? undefined : timeout?.payload; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's rename payload
--> payloadParsing
maybe?
/** | ||
* Milliseconds to receive the payload | ||
*/ | ||
payload?: Method extends 'get' | 'options' ? undefined : number; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Per #73730 (comment), were you suggesting that we rename payload
to payloadParsing
? I don't think just calling this the payload
timeout is super expressive, but I'm afraid of reusing "parsing" here as that might make users think it relates to
kibana/src/core/server/http/router/route.ts
Line 110 in 2c939ea
parse?: boolean | 'gunzip'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
+1 to payloadParsing
not being correct and maybe confusing since this timeout does not have to do with parsing. I actually prefer the current naming, though if I had my way, we'd stop using the word payload
and always use body
since that is what the HTTP spec calls it.
@elasticmachine merge upstream |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since there is some differing behavior in the socket behavior when using 'fake requests', I think it would be good to have at least 1-2 functional tests that use real HTTP connections.
/** | ||
* Milliseconds to receive the payload | ||
*/ | ||
payload?: Method extends 'get' | 'options' ? undefined : number; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
+1 to payloadParsing
not being correct and maybe confusing since this timeout does not have to do with parsing. I actually prefer the current naming, though if I had my way, we'd stop using the word payload
and always use body
since that is what the HTTP spec calls it.
payload: [allow, maxBytes, output, parse, timeout?.payload].some( | ||
(v) => typeof v !== 'undefined' | ||
) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(slightly out of scope) Do we really need this .some
check to return undefined
instead of an object of undefined values? I would expect Hapi is using Joi under the hood to populate the defaults here anyways.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is... per #50783 (comment) HapiJS doesn't let us set the payload
option for a GET
or HEAD
route definition...
Co-authored-by: Josh Dover <me@joshdover.com>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looked over the changes to security solutions and this looks good to me 👍
@elasticmachine merge upstream |
@elasticmachine merge upstream |
💚 Build SucceededBuild metrics
History
To update your PR or re-run it, just comment with: |
thank you for working on this! |
* master: (112 commits) [Ingest Manager] Fix agent config rollout rate limit to use constants (elastic#75364) Update Node.js to version 10.22.0 (elastic#75254) [ML] Anomaly Explorer / Single Metric Viewer: Fix error reporting for annotations. (elastic#74953) [Discover] Fix histogram cloud tests (elastic#75268) Uiactions to navigate to visualize or maps (elastic#74121) Use prefix search invis editor field/agg combo box (elastic#75290) Fix docs in trigger alerting UI (elastic#75363) [SIEM] Fixes search bar Cypress test (elastic#74833) Add libnss3.so to Dockerfile template (reporting) (elastic#75370) [Discover] Create field_button and add popovers to sidebar (elastic#73226) [Reporting] Network Policy: Do not throw from the intercept handler (elastic#75105) [Reporting] Increase capture.timeouts.openUrl to 1 minute (elastic#75207) Allow routes to specify the idle socket timeout in addition to the payload timeout (elastic#73730) [src/dev/build] remove node-version from snapshots (elastic#75303) [ENDPOINT] Reintroduced tabs to endpoint management and migrated pages to use common security components (elastic#74886) [Canvas] Remove dependency on legacy expressions APIs (elastic#74885) Skip failing test in CI (elastic#75266) [Task Manager] time out work when it overruns in poller (elastic#74980) [Drilldowns] misc improvements & fixes (elastic#75276) Small README note on bumping memory for builds (elastic#75247) ...
…yload timeout (#73730) (#75350) * Route options timeout -> timeout.payload * timeout.idleSocket can now be specified per route * Removing nested ternary * Fixing integration tests * Trying to actually fix the integration tests. Existing tests are hitting idle socket timeout, not the payload timeout * Fixing payload post timeout integration test * Fixing PUT and DELETE payload sending too long tests * Fixing type-script errors * GET routes can't specify the payload timeout, they can't accept payloads * Removing some redundancy in the tests * Adding 'Transfer-Encoding: chunked' to the POST test * Fixing POST/GET/PUT quick tests * Adding idleSocket timeout test * Removing unnecessary `isSafeMethod` call * Updating documentation * Removing PUT/DELETE integration tests * Working around the HapiJS bug * Deleting unused type import * The socket can be undefined... This occurs when using @hapi/shot directly or indirectly via Server.inject. In these scenarios, there isn't a socket. This can also occur when a "fake request" is used by the hacky background jobs: Reporting and Alerting... * Update src/core/server/http/http_server.ts Co-authored-by: Josh Dover <me@joshdover.com> * Adding payload timeout functional tests * Adding idle socket timeout functional tests * Adding better comments, using ?? instead of || * Fixing the plugin fixture TS * Fixing some typescript errors * Fixing plugin fixture tsconfig.json Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com> Co-authored-by: Josh Dover <me@joshdover.com> Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com> Co-authored-by: Josh Dover <me@joshdover.com>
Summary
An attempt to make #72362 work with #73103.
Route definitions can now specify the
idleSocket
timeout and thepayload
timeout.There are still a few "hazards" to this interface until hapijs/hapi#4123 merges, which is exercised by the unit tests.This PR works around hapijs/hapi#4123 by specifying a socket timeout in the route definition when the payload timeout is specified, and then uses theonPreAuth
lifecycle event of the route to set the real timeouts.Dev Docs
Route definitions can now specify the
idleSocket
timeout in addition to thepayload
timeout.Resolves #73557