Skip to content
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

[Android] Unexpected End of Stream Error when retrying after Connection closed by server #137

Closed
mmathewsTableau opened this issue Mar 29, 2022 · 3 comments

Comments

@mmathewsTableau
Copy link

mmathewsTableau commented Mar 29, 2022

The issue:

When the connection is closed to the server, okhttp will try to reconnect and retry the request. This is expected because React Native Blob Util sets retryOnConnectionFailure to true on okhttp client. To re-create the request, okhttp client will call ReactNativeBlobUtilBody. writeTo(@nonnull BufferedSink sink) at which point ReactNativeBlobUtilBody will use the private variable requestStream to write into the BufferedSink. The problem is that the requestStream has already been used and closed when okhttp was making the first request. So this results in the requestStream not writing anything into the BufferedSink and okhttp will throw an error because the content length does not match the length of what was written into the BufferdSink (ie 0).

This started happening in our app when okhttp upgraded versions when we upgraded react-native. We would intermittently see "Unexpected End of Stream"

We have created an internal repro using an express mock server:

app.get('/connectionWillBeDestroyed', (req, res) => {
  res.send('Whats up?', { root: '.' });
  res.socket.destroy();
});

And then requesting it twice via React-Native-Blob-Util:

import RNFetchBlob from 'react-native-blob-util';
...
const headers = {
  Connection: 'keep-alive',
};

await RNFetchBlob.config({
  timeout: 3000,
}).fetch('POST', mockServerUrl + 'connectionWillBeDestroyed', headers, 'request body');

// wait to allow the mock server to close the connection. Anything less than 5 seconds did not suffice 
await wait(5000);

// we expect this to fail internally within okhttp, at which point, okhttp will retry by recreating a request, which will fail
await RNFetchBlob.config({
  timeout: 3000,
}).fetch('POST', mockServerUrl + 'connectionWillBeDestroyed', headers, 'request body');

I have a patch for my app that fixes this issue for us. I will submit a PR.

RonRadtke added a commit that referenced this issue Mar 30, 2022
A fix for "unexpected end of stream error" issue #137
@RonRadtke
Copy link
Owner

Thank you very much for the detailed explanation and fix!

@enagorny
Copy link

enagorny commented Apr 5, 2022

@RonRadtke what are the plans for releasing a new version?

@RonRadtke
Copy link
Owner

@enagorny Sorry I wasn't able to do anything due to private reasons the last two weeks. I will make a new release this week.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants