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

How to read response's body without copying buffer #2869

Closed
marcottedan opened this issue Sep 19, 2016 · 7 comments
Closed

How to read response's body without copying buffer #2869

marcottedan opened this issue Sep 19, 2016 · 7 comments

Comments

@marcottedan
Copy link

marcottedan commented Sep 19, 2016

Hey guys

I had to do something like response.body().bytes() in an Interceptor, then had to recreate a full Response with the fetched byte to return a clean Request that can be parsed again, instead of just switching the Reader Index back to it's beginning. That's a lot of temporary objects to garbage-collect.

Do you have a better solution?

@JakeWharton
Copy link
Member

You can call .peekBody(Long.MAX_VALUE) to buffer the entire response in memory and get a lightweight copy of it. It'll be much less wasteful.

@JakeWharton
Copy link
Member

JakeWharton commented Sep 19, 2016

That's a lot of temporary objects to garbage-collect.

It's only one temporary object, the byte[]. Everything else is pooled automatically.

Switching to peekBody saves that allocation but you still copy the underlying data between pooled objects. To eliminate copying skip peekBody and get the BufferedSource of the response, call request(Long.MAX_VALUE) to buffer the entire response data, and then call .snapshot() to get a read-only copy as a ByteString (which is less convenient to read from incrementally but perfectly fine if you just want raw data). This does no storage allocation (aside from the objects wrapping the data) or data copies.

@marcottedan marcottedan changed the title Netty ByteBuf instead of OKIO? How to read response's body without copying buffer Sep 19, 2016
@marcottedan
Copy link
Author

So basically, it would look like this?

final BufferedSource source = response.body().source();
source.request(Integer.MAX_VALUE);
final byte[] bytes = source.buffer().snapshot().toByteArray();

Will this solution also work with multipart requests?

@JakeWharton
Copy link
Member

Yep! Although your toByteArray() is going to still allocate a byte[] and do a data copy. Can you read what you need directly from ByteString?

@marcottedan
Copy link
Author

marcottedan commented Sep 19, 2016

I'm using Jackson's ObjectMapper readValue that can accepts both a byte[] or a String.

Should I simply call snapshot().utf8() ?

internalArray() is package-protected

@JakeWharton
Copy link
Member

That will give you a read-only view of the bytes without a copy, yes.

@marcottedan
Copy link
Author

Awesome, thanks a lot for your support!

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

2 participants