[2.0.2-java] Avoiding HTTP chunked encoding with InputStreams

1,301 views
Skip to first unread message

Mikael Nousiainen

unread,
Aug 24, 2012, 3:37:23 AM8/24/12
to play-fr...@googlegroups.com
How can I tell Play not to use chunked encoding when I'm supplying it an InputStream in a result in a controller?

An example for the documentation - this forces chunked encoding:
public static Result index() {
  InputStream is = getDynamicStreamSomewhere();
  return ok(is);
}

I noticed that Play does offer a way to serve files directly, without chunked encoding, by supplying a File object in a result, but in many cases (e.g. with files stored in a relational database) a File may not be available and the content is only accessible through a stream.

I realize that HTTP chunked encoding should be used only when the total size of the response is NOT known, but using an InputStream does not imply that in any way. The size of the content in the stream may be available through some other means (e.g. stored in another column in a database), so that it is possible to manually set the value of the Content-Length header.

James Roper

unread,
Aug 25, 2012, 4:40:19 PM8/25/12
to play-fr...@googlegroups.com
Actually, even when you serve a file using the ok(file) method, Play still serves files using chunked encoding.  In fact, play currently offers no way of sending any streamed content without using chunked encoding.  But my question is, what's wrong with sending it chunked?  By default, play will chunk it into 8kb chunks, the overhead for chunked encoding is about 6 bytes per chunk, so that's less than 0.1% overhead, I see no reason why this would be a problem.  If you know the content length already, there's nothing stopping you from setting the Content-Length header yourself, this will particularly help if you want to offer downloads where the user can see a % complete on the download.  This can be done using:

  response().setHeader("Content-Length", Integer.toString(contentLength));
  return ok(is);

Mikael Nousiainen

unread,
Aug 26, 2012, 4:08:34 PM8/26/12
to play-fr...@googlegroups.com
The main problem for me are buggy/simple/incomplete HTTP clients, which are not able to handle responses in chunked encoding.
Thus, I need the option to not have my responses chunked-encoded.

As I stated before, I think chunked encoding is completely useless in cases where the total size of the response is known -- it only adds overhead in processing in both ends of the connection.

Regarding usage of Content-Length header, I'm not even sure if the HTTP specification allows specifying Content-Length with chunked encoding, and how Content-Length should be interpreted when combined with chunked encoding.

Sadache Aldrobi

unread,
Aug 26, 2012, 4:41:50 PM8/26/12
to play-fr...@googlegroups.com
Take a look at this:

https://groups.google.com/forum/#!msg/play-framework/YunJzgxPKsU/xJfmxyTetawJ

--
You received this message because you are subscribed to the Google Groups "play-framework" group.
To view this discussion on the web visit https://groups.google.com/d/msg/play-framework/-/OaP-K0BlbzUJ.

To post to this group, send email to play-fr...@googlegroups.com.
To unsubscribe from this group, send email to play-framewor...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/play-framework?hl=en.



--
www.sadekdrobi.com
ʎdoɹʇuǝ

Mikael Nousiainen

unread,
Aug 26, 2012, 5:49:32 PM8/26/12
to play-fr...@googlegroups.com
Thanks for the link!

However, I'm not sure if the examples provided in that message thread solve my problem. See comments below:

1) Ok.feed(slowlyStreamedFile).withHeaders(CONTENT_LENGTH -> "1800000", CONTENT_DISPOSITION -> "attachment;filename=filename.ext")

The first example uses the feed-method, which (based on Play Framework scala source code) generates a SimpleResult (I'm assuming this means the response is NOT chunked), but it only accepts enumerators. How would I transform an InputStream into an Enumerator? Can Enumeratees be used here? Could you provide an example of this, as I've just started to learn Scala?

2) Ok.stream(Enumerator.fromStream(is)).withHeaders(CONTENT_LENGTH -> length);

The second example uses the stream-method, which always generates a ChunkedResult, which sounds like it's always generating the response in chunked encoding, so I cannot use it. Am I right?

Sadache Aldrobi

unread,
Aug 26, 2012, 6:28:27 PM8/26/12
to play-fr...@googlegroups.com
Are you using Java or Scala?

To view this discussion on the web visit https://groups.google.com/d/msg/play-framework/-/RG1e_p3l2OYJ.

To post to this group, send email to play-fr...@googlegroups.com.
To unsubscribe from this group, send email to play-framewor...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/play-framework?hl=en.



--
www.sadekdrobi.com
ʎdoɹʇuǝ

Mikael Nousiainen

unread,
Aug 27, 2012, 2:23:59 AM8/27/12
to play-fr...@googlegroups.com
As the topic suggests, I'm using Java. But nothing stops me from writing one controller in Scala, I guess.

Once I understand how this works, I might try to modify the Java API of Play and submit a pull request.

I don't know what you prefer, but enabling/disabling chunked encoding could be implemented as:
a) a boolean value in the returned Result (but this requires adding a number of methods)
b) a global option in application.conf (might be too inflexible)
c) a flag in Http.Response

Also, could you still answer my questions in the previous post, please?

Yann Simon

unread,
Aug 27, 2012, 2:42:44 AM8/27/12
to play-fr...@googlegroups.com
Hi Mikael.

2012/8/26 Mikael Nousiainen <mik...@incompleteopus.net>:
> Thanks for the link!
>
> However, I'm not sure if the examples provided in that message thread solve
> my problem. See comments below:
>
> 1) Ok.feed(slowlyStreamedFile).withHeaders(CONTENT_LENGTH -> "1800000",
> CONTENT_DISPOSITION -> "attachment;filename=filename.ext")
>
> The first example uses the feed-method, which (based on Play Framework scala
> source code) generates a SimpleResult (I'm assuming this means the response
> is NOT chunked), but it only accepts enumerators. How would I transform an
> InputStream into an Enumerator? Can Enumeratees be used here? Could you
> provide an example of this, as I've just started to learn Scala?

You can create an Enumerator for a File of an InputStream:
http://www.playframework.org/documentation/api/2.0/scala/play/api/libs/iteratee/Enumerator$.html
Enumerator.fromFile
Enumerator.fromStream

I do not know if it is possible in Java.

Cheers,
Yann
> https://groups.google.com/d/msg/play-framework/-/RG1e_p3l2OYJ.

Sadache Aldrobi

unread,
Aug 27, 2012, 9:59:48 AM8/27/12
to play-fr...@googlegroups.com
Ok.feed doesn't use chunked, and you can get an Enumerator from an inputStream as Yann showed. For Java, I linked a post that shows an example of implementing that for Java.

To view this discussion on the web visit https://groups.google.com/d/msg/play-framework/-/7CyIT7EfryoJ.

To post to this group, send email to play-fr...@googlegroups.com.
To unsubscribe from this group, send email to play-framewor...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/play-framework?hl=en.



--
www.sadekdrobi.com
ʎdoɹʇuǝ

Mikael Nousiainen

unread,
Aug 27, 2012, 10:33:46 AM8/27/12
to play-fr...@googlegroups.com
Which link are you referring to? I only found Scala examples on the thread you earlier posted here.
Reply all
Reply to author
Forward
0 new messages