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
First request to a CredentialsAuthenticator or AsyncCredentialsAuthenticator fails if the body is too large #2735
Comments
@owainhunt Just to confirm the non-async version works fine? |
@0xTim I'd not looked at the non-async version, but in a quick test the below code behaves in exactly the same way - with a body above a certain size, the first request fails but subsequent requests succeed. class DummyAuthFuture: CredentialsAuthenticator {
typealias Credentials = String
func authenticate(credentials: Credentials, for request: Request) -> EventLoopFuture<Void> {
request.auth.login(credentials)
return request.eventLoop.makeSucceededFuture(())
}
} |
I wonder if this is related to #2494 and that over a certain size (probably the size of the ByteBuffer) it fails to decode the entire body. Does adding |
These seem to work in some basic testing: extension AsyncCredentialsAuthenticator {
public func authenticate(request: Request) async throws {
_ = try await request.body.collect(max: nil).get()
let credentials: Credentials
do {
credentials = try request.content.decode(Credentials.self)
} catch {
return
}
return try await self.authenticate(credentials: credentials, for: request)
}
} extension CredentialsAuthenticator {
public func authenticate(request: Request) -> EventLoopFuture<Void> {
return request.body.collect(max: nil).flatMap { _ -> EventLoopFuture<Void> in
let credentials: Credentials
do {
credentials = try request.content.decode(Credentials.self)
} catch {
return request.eventLoop.makeSucceededFuture(())
}
return self.authenticate(credentials: credentials, for: request)
}
}
} Still not sure why it would previously fail the first time and then work on subsequent requests, though. |
My guess would be the event loop buffer would be increased after the decode or something like that. It would have to be something specific to the event loop and not the request. Whatever it is it's definitely a bug |
I have also seen this problem, with somewhat different symptoms because I am not using an authenticated route. The first request with a large post body (in my case, ~600KB) will often hang (like 1 in 10 times) because my route handler is never called. So the incoming request is logged and then it just seems to get dropped. Note that my middleware handlers are called as normal. This happens on both macOS and Linux (Heroku). It's not always the first request - it does happen on subsequent requests, but very much more rarely. After reading this issue, I tried using this as the first middleware as a workaround, and it did indeed fix the problem - no more dropped requests, on any os:
|
The underlying issue is #2742, will close it in favour of that one. It's being looked at |
@owainhunt @grennis can you still reproduce this (when skipping the |
Describe the bug
When using a route protected by an AsyncCredentialsAuthenticator, the first request to the route fails if the body is too large (in my testing, above 1795 bytes). Subsequent requests to the same route succeed as expected.
It appears to fail at the point the authenticator attempts to decode the request body - see
Authentication+Concurrency.swift:AsyncCredentialsAuthenticator.authenticate(request:)
:vapor/Sources/Vapor/Concurrency/Authentication+Concurrency.swift
Line 87 in 8075031
The error message suggests the request body is empty. Indeed if you put a breakpoint at that line,
po request.body.string
returns nil.Error message is as follows:
To Reproduce
Define an AsyncCredentialsAuthenticator:
Protect a route with an instance of that authenticator:
Run the app and make two requests, with a body length of greater than 1795 bytes.
Expected behavior
Both requests will succeed with a 200 response.
Actual behaviour
First request fails with a 401:
Second request succeeds with a 200.
Environment
The text was updated successfully, but these errors were encountered: