Conversation
These tests verify that a client can send a 1Mb request body to a server and receive a 1Mb response body from a server.
This test reads only 1 byte out of a 1Mb response body from the server. The "user" does not care about the rest of the body. This caused a hang in URLSession and a precondition crash in AHC. The fix for URLSession is also in this commit: After running the response handler, the "after response" delegate callback processor should close the callback stream and stop accepting new callbacks. Otherwise, the stream will never be finished in this case because the URLSession data task has been suspended, due to receiving more data than the high watermark.
…large-body # Conflicts: # Sources/HTTPClientConformance/HTTPClientConformance.swift
Also let the server gracefully fail to write the 1Mb body, because the client closed the socket early.
| ) | ||
|
|
||
| // Read only a single byte from the body. We do not care about the rest of the 1Mb. | ||
| try await client.perform( |
There was a problem hiding this comment.
Does this throw? I'm wondering if we should always throw if the entire response body wasn't read
There was a problem hiding this comment.
No, it doesn't throw for reading less. I don't think it should? It's valid for a client to just want to read an initial portion of the response before moving on. Real-world examples would be things like:
- Content probing (media players reading only the initial bit of the file to get metadata)
- Search/grep in large remote files
There was a problem hiding this comment.
I'm worried about truncation issues where people only call read once, and usually get the entire body when it's small, but the code fails randomly when the body is bigger. Cancellation throws an error and this is a cancellation.
There was a problem hiding this comment.
I see how that can happen.
Here are my concerns:
- If we're talking about
CancellationErrorspecifically, that is strictly about a task being cancelled. There was no task that was cancelled here explicitly by the user. - Throwing an error in this case can encourage a pattern where the user wraps their call in a do-catch that does nothing in the catch, because they intended to stop halfway. That is awkward IMO.
- From the "socket-is-a-file" philosophy, there isn't a file API I know of that throws an error because we closed the file halfway through and didn't read it entirely, even if the close is implicit like in Python:
with open("myfile.txt") as f:
f.read(1024)
That being said, python also makes it convenient to read "everything" by just omitting the size parameter. Maybe what we want here is some convenience functions to read until EOF, so users don't accidentally reach for the POSIX-y socket best-effort read?
There was a problem hiding this comment.
collect is supposed to be that. Honestly I think this is somewhat a bug in collect because it's returning nil as trailer which might be incorrect since we wouldn't have read the trailers before the end of the body. This is somewhat related to #52
There was a problem hiding this comment.
In URLSession at least, you have to cancel the task and receive a -999 error, otherwise we would keep delivering the body.
Motivation
For our definition of a large body (1Mb), ensure that clients can:
Modifications
Wrote 2 conformance tests:
test1MbBodywrites a 1Mb body in a request to the/echoendpoint. The server echos the response back and the client verifies that it got back the exact same data.testUnderReadmakes a request to the new/1mb_bodyendpoint and only reads 1 byte in the response handler.Unfortunately,
testUnderReaddid not pass on URLSession or AHC.On AHC, attempting to under-read causes a precondition assertion failure here which needs more investigation.
For URLSession, the bug is that an under-read puts the state machine into a situation where:
A fix for this bug in URLSession is also included in this PR. The solution is to cancel the URLSessionTask once the response handler has executed. If the request is not already complete, this will cause the
completeWithErrorhandler to be triggered which will unblock the callback stream.Result
These tests both pass with the URLSession client.
test1MbBodypasses with AHC and we will investigate why under-read is failing on AHC.Test Plan
The raw requests and responses were verified manually with Wireshark.