-
Notifications
You must be signed in to change notification settings - Fork 24.4k
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
Add responseType as a concept to RCTNetworking, send binary data as base64 #8324
Conversation
By analyzing the blame information on this pull request, we identified @davidaurelio and @nicklockwood to be potential reviewers. |
ecec829
to
54ab996
Compare
(args) => this.__didReceiveData(...args) | ||
(args) => this.__didReceiveData(...args) | ||
)); | ||
this._subscriptions.push(RCTNetworking.addListener( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not super familiar with all of this code: does this mean we always send all the incremental data chunks and the complete response when the request finishes? That seems wasteful.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A valid question! But rest assured, we definitely don't send data twice to JS.
Edge case question: what happens if the |
Ah, good point. I failed to address that, both in code and the PR comments. I know the spec says that it's legal until request headers are received, but how useful is that really? I think we should make it illegal to change after the request has been sent -- this PR here would fail horribly otherwise anyway. Supporting the narrow gap between request sent and headers received seems very little benefit for a whole lot of code complexity... |
Yeah, I agree that it’s not worth implementing this. Just throw, or print a warning, that should be enough |
54ab996
to
e676c28
Compare
Done. Who else should we get to review this so we can get it landed? |
Ping? |
@davidaurelio By assigning the PR it will show up in Pieter's diff queue - more visibility for this PR from our core contributor Philipp. |
responseType: 'text' | 'base64', | ||
incrementalUpdates: boolean, | ||
timeout: number, | ||
callback: (requestId: number) => any |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Objective-C and JS changes LGTM, maybe @andreicoman11 or @foghina can help out with the native Android changes. |
lgtm, let’s wait for @foghina or @andreicoman11 |
e676c28
to
8c9e4dd
Compare
Thanks for the review, @javache! Addressed your comments. |
public Response intercept(Interceptor.Chain chain) throws IOException { | ||
Response originalResponse = chain.proceed(chain.request()); | ||
ProgressResponseBody responseBody = new ProgressResponseBody( | ||
originalResponse.body(), new ProgressListener() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Formatting around here seems wrong. Should either be:
... = new ProgressResponseBody(..., ... {
long last = ...
if it doesn't exceed 100 chars width, or
... = new ProgressResponseBody(
...,
... {
long last = ...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, I can fix that.
My comments are mostly questions because apparently our networking module is now a commentless monstrosity and I don't get how things work. Code looks good though. Please make sure to test uploading with progress as well (I think that was supported?). |
:( I can try and help document things some time.
Yep. Still works. UIExplorer examples FTW :) |
…ase64 In preparation for Blob support (wherein binary XHR and WebSocket responses can be retained as native data blobs on the native side and JS receives a web-like opaque Blob object), this change makes RCTNetworking aware of the responseType that JS requests. A `xhr.responseType` of `''` or `'text'` translates to a native response type of `'text'`. A `xhr.responseType` of `arraybuffer` translates to a native response type of `base64`, as we currently lack an API to transmit TypedArrays directly to JS. This is analogous to how the WebSocket module already works, and it's a lot more versatile and much less brittle than converting a JS *string* back to a TypedArray, which is what's currently going on. Now that we don't always send text down to JS, JS consumers might still want to get progress updates about a binary download. This is what the `'progress'` event is designed for, so this change also implements that. This change also follows the XHR spec with regards to `xhr.response` and `xhr.responseText`: - if the response type is `'text'`, `xhr.responseText` can be peeked at by the JS consumer. It will be updated periodically as the download progresses, so long as there's either an `onreadystatechange` or `onprogress` handler on the XHR. - if the response type is not `'text'`, `xhr.responseText` can't be access and `xhr.response` remains `null` until the response is fully received. `'progress'` events containing response details (total bytes, downloaded so far) are dispatched if there's an `onprogress` handler. Once Blobs are landed, `xhr.responseType` of `'blob'` will correspond to the same native response type, which will cause RCTNetworking to only send a blob ID down to JS, which can then create a `Blob` object from that for consumers. **Test Plan:** This change comes with extensive changes and expansions to the XHRExamples in UIExplorer. `onprogress` handler, `onreadystatechange` handler, and `responseType = 'arraybuffer'` can be switched on independently. I tested all combinations on both iOS and Android.
8c9e4dd
to
8eba055
Compare
Thanks for the reviews and questions, everyone. Really appreciate it. If there are no more concerns or questions, would love it if somebody could pull the trigger and import it. |
@facebook-github-bot import |
Thanks for importing. If you are an FB employee go to Phabricator to review. |
private BufferedSource mBufferedSource; | ||
private long mTotalBytesRead; | ||
|
||
public ProgressResponseBody(ResponseBody responseBody, ProgressListener progressListener) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I get an Infer warning here:
There may be a Field Not Initialized: Field ProgressResponseBody.mBufferedSource is not initialized in the constructor and is not declared @Nullable
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah yeah, guess we should mark it @Nullable
.
I can amend the commit here on github, but it seems @davidaurelio is already amending the diff in FB land. If David doesn't add it while he's in there, I can send a trivial PR after this lands.
@philikon I’m on the internal failures. Making progress. |
Eeek ok. Thanks! You know how to reach me if I can help with anything :) |
@davidaurelio any updates? anything i can help with? |
I’ve added a comment here: #8324 (comment) hard to spot, as it didn’t show up at the bottom. Any idea what could cause that? |
@philikon any idea what the underlying issue might be? @foghina can you take a look? --> #8324 (comment) |
Thanks @davidaurelio! I replied to the comment. |
Thank you for your pull request. As you may know, we require contributors to sign our Contributor License Agreement, and we don't seem to have you on file and listed as active anymore. In order for us to review and merge your code, please email cla@fb.com with your details so we can update your status. |
08c375f
…ase64 Summary: In preparation for Blob support (wherein binary XHR and WebSocket responses can be retained as native data blobs on the native side and JS receives a web-like opaque Blob object), this change makes RCTNetworking aware of the responseType that JS requests. A `xhr.responseType` of `''` or `'text'` translates to a native response type of `'text'`. A `xhr.responseType` of `arraybuffer` translates to a native response type of `base64`, as we currently lack an API to transmit TypedArrays directly to JS. This is analogous to how the WebSocket module already works, and it's a lot more versatile and much less brittle than converting a JS *string* back to a TypedArray, which is what's currently going on. Now that we don't always send text down to JS, JS consumers might still want to get progress updates about a binary download. This is what the `'progress'` event is designed for, so this change also implements that. This change also follows the XHR spec with regards to `xhr.response` and `xhr.responseText`: - if the response type is `'text'`, `xhr.responseText` can be peeked at by the JS consumer. It will be updated periodically as the download progresses, so long as there's either an `onreadystatechange` or `onprogress` handler on the XHR. - if the response type is not `'text'`, `xhr.responseText` can't be accessed and `xhr.response` remains `null` until the response is fully received. `'progress'` events containing response details (total bytes, downloaded so far) are dispatched if there's an `onprogress` handler. Once Blobs are landed, `xhr.responseType` of `'blob'` will correspond to the same native response type, which will cause RCTNetworking to only send a blob ID down to JS, which can then create a `Blob` object from that for consumers. Closes facebook/react-native#8324 Reviewed By: javache Differential Revision: D3508822 Pulled By: davidaurelio fbshipit-source-id: 441b2d4d40265b6036559c3ccb9fa962999fa5df
…ase64 Summary: In preparation for Blob support (wherein binary XHR and WebSocket responses can be retained as native data blobs on the native side and JS receives a web-like opaque Blob object), this change makes RCTNetworking aware of the responseType that JS requests. A `xhr.responseType` of `''` or `'text'` translates to a native response type of `'text'`. A `xhr.responseType` of `arraybuffer` translates to a native response type of `base64`, as we currently lack an API to transmit TypedArrays directly to JS. This is analogous to how the WebSocket module already works, and it's a lot more versatile and much less brittle than converting a JS *string* back to a TypedArray, which is what's currently going on. Now that we don't always send text down to JS, JS consumers might still want to get progress updates about a binary download. This is what the `'progress'` event is designed for, so this change also implements that. This change also follows the XHR spec with regards to `xhr.response` and `xhr.responseText`: - if the response type is `'text'`, `xhr.responseText` can be peeked at by the JS consumer. It will be updated periodically as the download progresses, so long as there's either an `onreadystatechange` or `onprogress` handler on the XHR. - if the response type is not `'text'`, `xhr.responseText` can't be accessed and `xhr.response` remains `null` until the response is fully received. `'progress'` events containing response details (total bytes, downloaded so far) are dispatched if there's an `onprogress` handler. Once Blobs are landed, `xhr.responseType` of `'blob'` will correspond to the same native response type, which will cause RCTNetworking to only send a blob ID down to JS, which can then create a `Blob` object from that for consumers. Closes facebook#8324 Reviewed By: javache Differential Revision: D3508822 Pulled By: davidaurelio fbshipit-source-id: 441b2d4d40265b6036559c3ccb9fa962999fa5df
…ase64 Summary: In preparation for Blob support (wherein binary XHR and WebSocket responses can be retained as native data blobs on the native side and JS receives a web-like opaque Blob object), this change makes RCTNetworking aware of the responseType that JS requests. A `xhr.responseType` of `''` or `'text'` translates to a native response type of `'text'`. A `xhr.responseType` of `arraybuffer` translates to a native response type of `base64`, as we currently lack an API to transmit TypedArrays directly to JS. This is analogous to how the WebSocket module already works, and it's a lot more versatile and much less brittle than converting a JS *string* back to a TypedArray, which is what's currently going on. Now that we don't always send text down to JS, JS consumers might still want to get progress updates about a binary download. This is what the `'progress'` event is designed for, so this change also implements that. This change also follows the XHR spec with regards to `xhr.response` and `xhr.responseText`: - if the response type is `'text'`, `xhr.responseText` can be peeked at by the JS consumer. It will be updated periodically as the download progresses, so long as there's either an `onreadystatechange` or `onprogress` handler on the XHR. - if the response type is not `'text'`, `xhr.responseText` can't be accessed and `xhr.response` remains `null` until the response is fully received. `'progress'` events containing response details (total bytes, downloaded so far) are dispatched if there's an `onprogress` handler. Once Blobs are landed, `xhr.responseType` of `'blob'` will correspond to the same native response type, which will cause RCTNetworking to only send a blob ID down to JS, which can then create a `Blob` object from that for consumers. Closes facebook#8324 Reviewed By: javache Differential Revision: D3508822 Pulled By: davidaurelio fbshipit-source-id: 441b2d4d40265b6036559c3ccb9fa962999fa5df
…ase64 Summary: In preparation for Blob support (wherein binary XHR and WebSocket responses can be retained as native data blobs on the native side and JS receives a web-like opaque Blob object), this change makes RCTNetworking aware of the responseType that JS requests. A `xhr.responseType` of `''` or `'text'` translates to a native response type of `'text'`. A `xhr.responseType` of `arraybuffer` translates to a native response type of `base64`, as we currently lack an API to transmit TypedArrays directly to JS. This is analogous to how the WebSocket module already works, and it's a lot more versatile and much less brittle than converting a JS *string* back to a TypedArray, which is what's currently going on. Now that we don't always send text down to JS, JS consumers might still want to get progress updates about a binary download. This is what the `'progress'` event is designed for, so this change also implements that. This change also follows the XHR spec with regards to `xhr.response` and `xhr.responseText`: - if the response type is `'text'`, `xhr.responseText` can be peeked at by the JS consumer. It will be updated periodically as the download progresses, so long as there's either an `onreadystatechange` or `onprogress` handler on the XHR. - if the response type is not `'text'`, `xhr.responseText` can't be accessed and `xhr.response` remains `null` until the response is fully received. `'progress'` events containing response details (total bytes, downloaded so far) are dispatched if there's an `onprogress` handler. Once Blobs are landed, `xhr.responseType` of `'blob'` will correspond to the same native response type, which will cause RCTNetworking to only send a blob ID down to JS, which can then create a `Blob` object from that for consumers. Closes facebook/react-native#8324 Reviewed By: javache Differential Revision: D3508822 Pulled By: davidaurelio fbshipit-source-id: 441b2d4d40265b6036559c3ccb9fa962999fa5df
In preparation for Blob support (wherein binary XHR and WebSocket responses can be retained as native data blobs on the native side and JS receives a web-like opaque Blob object), this change makes RCTNetworking aware of the responseType that JS requests. A
xhr.responseType
of''
or'text'
translates to a native response type of'text'
. Axhr.responseType
ofarraybuffer
translates to a native response type ofbase64
, as we currently lack an API to transmit TypedArrays directly to JS. This is analogous to how the WebSocket module already works, and it's a lot more versatile and much less brittle than converting a JS string back to a TypedArray, which is what's currently going on.Now that we don't always send text down to JS, JS consumers might still want to get progress updates about a binary download. This is what the
'progress'
event is designed for, so this change also implements that. This change also follows the XHR spec with regards toxhr.response
andxhr.responseText
:'text'
,xhr.responseText
can be peeked at by the JS consumer. It will be updated periodically as the download progresses, so long as there's either anonreadystatechange
oronprogress
handler on the XHR.'text'
,xhr.responseText
can't be accessed andxhr.response
remainsnull
until the response is fully received.'progress'
events containing response details (total bytes, downloaded so far) are dispatched if there's anonprogress
handler.Once Blobs are landed,
xhr.responseType
of'blob'
will correspond to the same native response type, which will cause RCTNetworking to only send a blob ID down to JS, which can then create aBlob
object from that for consumers.Test Plan: This change comes with extensive changes and expansions to the XHRExamples in UIExplorer.
onprogress
handler,onreadystatechange
handler, andresponseType = 'arraybuffer'
can be switched on independently. I tested all combinations on both iOS and Android.