Skip to content

Commit

Permalink
Fix onprogress not firing when Content-Length is not available for XM…
Browse files Browse the repository at this point in the history
…LHttpRequest (#44899)

Summary:
When an XMLHttpRequest is performed, the `onprogress` event it is not invoked when the `Content-Length` header is missing in the response. This is the case when we are calling an endpoint that responds with `transfer-encoding: chunked` (https://tools.ietf.org/html/rfc9112#section-7.1), preventing the user to keep track of the progress while the server is sending chunks. Despite we will never know the total length of the content (because it will not be known due to the RFC specification, so it will be always `-1`), we will now be able to keep track of the loaded data.

Note that in Android, this is the current default behaviour.

To address this issue:
- I removed the condition where the `downloadProgressBlock` was dispatched only when  `response.expectedContentLength` was greater than 0
- I created a new test case for `XMLHttpRequest` in the tester app to download a chunked file

## Changelog:

[IOS] [CHANGED] - fire `onprogress` event for `XMLHttpRequest` even when the `Content-Length` header is missing in the response headers

Pull Request resolved: #44899

Test Plan:
|before|after|
|----------|:-------------:|
|https://github.com/facebook/react-native/assets/37150312/6da3518f-eed3-4808-a2f8-abe26e5c7487|https://github.com/facebook/react-native/assets/37150312/ed1da300-dcf7-4874-a941-a2289f1cb777

Reviewed By: cortinico

Differential Revision: D58562088

Pulled By: NickGerleman

fbshipit-source-id: 23a1cafa49ddcd25fa0db7d04fae845126771425
  • Loading branch information
alicata authored and facebook-github-bot committed Jun 14, 2024
1 parent 9d637e4 commit 457d14b
Show file tree
Hide file tree
Showing 2 changed files with 27 additions and 8 deletions.
2 changes: 1 addition & 1 deletion packages/react-native/Libraries/Network/RCTNetworkTask.mm
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,7 @@ - (void)URLRequest:(id)requestToken didReceiveData:(NSData *)data
incrementalDataBlock(data, length, total);
}];
}
if (_downloadProgressBlock && total > 0) {
if (_downloadProgressBlock) {
RCTURLRequestProgressBlock downloadProgressBlock = _downloadProgressBlock;
[self dispatchCallback:^{
downloadProgressBlock(length, total);
Expand Down
33 changes: 26 additions & 7 deletions packages/rn-tester/js/examples/XHR/XHRExampleDownload.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ class XHRExampleDownload extends React.Component<{...}, Object> {
readystateHandler: false,
progressHandler: true,
arraybuffer: false,
chunked: false,
};

xhr: ?XMLHttpRequest = null;
Expand Down Expand Up @@ -107,12 +108,19 @@ class XHRExampleDownload extends React.Component<{...}, Object> {
Alert.alert('Error', xhr.responseText);
}
};
xhr.open(
'GET',
'http://aleph.gutenberg.org/cache/epub/100/pg100-images.html.utf8',
);
// Avoid gzip so we can actually show progress
xhr.setRequestHeader('Accept-Encoding', '');
if (this.state.chunked) {
xhr.open(
'GET',
'https://filesamples.com/samples/ebook/azw3/Around%20the%20World%20in%2028%20Languages.azw3',
);
} else {
xhr.open(
'GET',
'http://aleph.gutenberg.org/cache/epub/100/pg100-images.html.utf8',
);
// Avoid gzip so we can actually show progress
xhr.setRequestHeader('Accept-Encoding', '');
}
xhr.send();

this.setState({downloading: true});
Expand All @@ -133,7 +141,11 @@ class XHRExampleDownload extends React.Component<{...}, Object> {
) : (
<TouchableHighlight style={styles.wrapper} onPress={this._download}>
<View style={styles.button}>
<Text>Download 7MB Text File</Text>
<Text>
{this.state.chunked
? 'Download 10MB File'
: 'Download 19KB pdf File'}
</Text>
</View>
</TouchableHighlight>
);
Expand Down Expand Up @@ -188,6 +200,13 @@ class XHRExampleDownload extends React.Component<{...}, Object> {
onValueChange={arraybuffer => this.setState({arraybuffer})}
/>
</View>
<View style={styles.configRow}>
<Text>transfer-encoding: chunked</Text>
<Switch
value={this.state.chunked}
onValueChange={chunked => this.setState({chunked})}
/>
</View>
{button}
{readystate}
{progress}
Expand Down

0 comments on commit 457d14b

Please sign in to comment.