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

Create default entity decoder for InputStream #634

Closed
balatbn opened this issue Jun 10, 2016 · 10 comments
Closed

Create default entity decoder for InputStream #634

balatbn opened this issue Jun 10, 2016 · 10 comments
Labels
support User support questions

Comments

@balatbn
Copy link

balatbn commented Jun 10, 2016

If we want to retrieved Inputstream directly from HTTP client (we want to decompress stream with BZIP), currently we have to write our own EntityDecoder.

It would be nice to have this support by default.

@balatbn
Copy link
Author

balatbn commented Jun 10, 2016

We have this implementation for input stream. Is this the correct way to get Inputstream from response?

  implicit val inputStreamDecoder: EntityDecoder[InputStream] = EntityDecoder.decodeBy(MediaRange.`*/*`) { msg =>
    val inputStream = new PipedInputStream()
    DecodeResult.success(msg.body.to(io.chunkW(new PipedOutputStream(inputStream))).run).map(_ => inputStream)
  }

If this is correct and can be added to main branch, please let me know. I'll create a Pull request.

@aryairani
Copy link
Contributor

How would you feel about decoding the Process[Task, ByteVector] body directly instead of going through InputStream? Or about writing a middleware for bzipped content, similar to org.http4s.server.middleware.GZip?

@aryairani
Copy link
Contributor

Oops, that GZip middleware is for output, not input; sorry.

@balatbn
Copy link
Author

balatbn commented Jun 13, 2016

Bzip2 is an external dependency in Java. So, we didn't want to implement it as a middleware in the client.

@rossabaker rossabaker added the support User support questions label Jun 15, 2016
@rossabaker
Copy link
Member

scalaz.stream.io.toInputStream(response.body) gets you an InputStream without the deadlock issues that tend to come with piped streams.

Note that client methods like fetch dispose of the HTTP connection as soon as the Task returns, such that the body can't be read. You would want to use something like client.toHttpService(req).map(resp => scalaz.stream.io.toInputStream(resp.body)). Be sure to close the InputStream, or you will leak a connection.

@balatbn
Copy link
Author

balatbn commented Jun 15, 2016

Our code didn't work(probably because of some deadlock issue). We solved it with the same technique given in the above response.

@balatbn balatbn closed this as completed Jun 15, 2016
@rossabaker
Copy link
Member

The PipedOutputStream and PipedInputStream need to operate on different threads, or else one can starve the other. The joys of blocking I/O. :)

@mkeshav
Copy link

mkeshav commented Dec 18, 2017

Is there any easy way to get the body of the request as String. Due to reasons not in my control, I would like to parse the json body into Map[String, Any] which circe does not allow (I understand why). If I can get the body as a string then I can use something like Jackson which uses reflection to parse.

Really appreciate some guidance

@rossabaker
Copy link
Member

req.as[String] gets you an F[String] (or Task[String] before 0.18). You can then (flat)Map that with your Jackson parser to get JSON.

The toInputStream advice above is still valid, if Jackson prefers that.

@mkeshav
Copy link

mkeshav commented Dec 18, 2017

Thank you so much

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

No branches or pull requests

4 participants