Bug 265331 - Can not determine disconnected vs finished/completed chunked response body with ReadableStream
Summary: Can not determine disconnected vs finished/completed chunked response body wi...
Status: NEW
Alias: None
Product: WebKit
Classification: Unclassified
Component: Page Loading (show other bugs)
Version: Safari 15
Hardware: Mac (Intel) macOS 12
: P2 Blocker
Assignee: Nobody
URL:
Keywords: BrowserCompat, InRadar
Depends on:
Blocks:
 
Reported: 2023-11-24 18:40 PST by Benjamin Hindman
Modified: 2024-03-10 14:16 PDT (History)
7 users (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Benjamin Hindman 2023-11-24 18:40:30 PST
It does not appear to be possible to differentiate between a disconnected stream and a finished/completed stream.

Consider:

---------------------------------------------

const response = await fetch(...);

const reader = response.body.getReader();

try {
  while (true) {
    const { done, value } = await reader.read();
    if (done) {
      // Safari always goes here if the server crashes.
      break;
    } else {
      // ...
    }
  }
} catch (e) {
  // Chrome and Firefox always goes here if the server crashes.
  console.log(e);
}

---------------------------------------------

If the server crashes while reading from the `ReadableStream` reader, Safari will tell us that we are done while Chrome and Firefox will correctly tell us that the connection was disconnected. Safari should only tell us that we are done if it has received '0\r\n\r\n', which it most definitely has not.

Or is there some other way to differentiate this case that is cross-browser?
Comment 1 Radar WebKit Bug Importer 2023-12-01 18:41:14 PST
<rdar://problem/119059764>
Comment 2 youenn fablet 2024-03-10 14:12:02 PDT
https://wpt.fyi/results/fetch/api/basic/error-after-response.any.html is an example with bad chunck encoding where the error mechanism is correctly implemented.
I would think CFNetwork detects the issue, sends it to WebKit level which error the response body stream.

I did a try with WPT server with chunk encoding and it indeed seems like we do not receive an error. I would guess CFNetwork might not always detect this error case.
Comment 3 youenn fablet 2024-03-10 14:16:34 PDT
Repro steps:
1. Run Tools/Scripts/run-webkit-httpd
2. Add LayoutTests/imported/w3c/web-platform-tests/trickle-chunk-encoding.py file as follows
-----
import time

def main(request, response):
    delay = float(request.GET.first(b"ms", 500)) / 1E3
    count = int(request.GET.first(b"count", 50))
    # Read request body
    request.body
    time.sleep(delay)
    if not b"notype" in request.GET:
        response.headers.set(b"Content-type", b"text/plain")
    response.headers.set(b"Transfer-Encoding", b"chunked")
    response.write_status_headers()
    time.sleep(delay)
    for i in range(count):
        response.writer.write_content(b"a\r\nTEST_CHUNK\r\n")
        time.sleep(delay)
-----
3. Go to http://localhost:8800 and open web inspector
4. Paste the following code in the web inspector:
----
test = async (url) => {
  const response = await fetch(url);
  const reader = response.body.getReader();
  try {
    while (true) {
      const { done, value } = await reader.read();
      if (done) {
        // Safari always goes here if the server crashes.
        console.log('done');
        break;
    }
  } catch (e) {
    console.warn(e);
  }
}
----
5. Run `test("trickle-chunk-encoding.py")`
6. Stop abruptly the WPT server
7. Observe whether the web inspector console shows done or an error

Chrome shows an error, Safari shows done.

It might be good to check what happens at CFNetwork level.