Chunked responses with Set-Cookie trailers

61 views
Skip to first unread message

Jxtps

unread,
Apr 13, 2015, 8:22:59 PM4/13/15
to play-fr...@googlegroups.com
I'm trying to get some of our most-used actions to use chunked transfer encoding in order to speed up overall page load by telling the browser what CSS / JS to get immediately, then the browser can fetch that while the server is hitting the database for the information needed to actually render the page.

This has led me to something that is in spirit similar to:

class ChunkedAction[A](action: Action[A]) extends ActionWrapper(action) {

val preChunk = "<html><head>...js & css references go here for immediate download by the client... "

override def apply(request: Request[A]): Future[Result] = {
Future.successful(Result(
ResponseHeader(200, Map(CONTENT_TYPE -> MimeTypes.HTML, TRANSFER_ENCODING -> CHUNKED, TRAILER -> SET_COOKIE)),
Enumerator(preChunk.getBytes("utf8")) >>> Enumerator.flatten(action(request).map(_.body)) &> Results.chunk,
HttpConnection.KeepAlive))

}
}

(In reality it's a lot more complex since the Enumerator.flatten(action(request)) executes directly and the preChunk therefore doesn't go out immediately, but it gets the point across a lot better than the mess I have in place to get around that + all the error / redirect handling)

Results.chunk() takes an optional Iteratee to produce the Trailer headers. These are crucial, since otherwise we can't set e.g. cookies (flash, session).

Now, the action(request) returns a Future[Result], which has the headers in it. However, that is deep inside the callstack (and likely in a separate thread), and not available when calling Results.chunk().

How can I fish out the headers from the action(request)-result to inject it into the Results.chunk call?

Jxtps

unread,
Apr 14, 2015, 6:47:06 PM4/14/15
to play-fr...@googlegroups.com
Got the cookie header out by using a var inside the apply()-method - ugly, but workable.

What's less workable is the lack of actual browser support for trailers: http://stackoverflow.com/questions/22033933/using-trailer-header-with-http-chunked-transfer-how-to-set-cookie-using-it

So this will have to be limited to actions that do not set cookies (session, flash), which is a pity.

Well, well.

James Roper

unread,
Apr 14, 2015, 8:12:06 PM4/14/15
to play-framework
You may find this helpful, it's how LinkedIn use Play to implement things similar to what you want to do, including setting cookies etc:


--
You received this message because you are subscribed to the Google Groups "play-framework" group.
To unsubscribe from this group and stop receiving emails from it, send an email to play-framewor...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.



--
James Roper
Software Engineer

Typesafe – Build reactive apps!
Twitter: @jroper

Jxtps

unread,
Apr 15, 2015, 7:04:22 PM4/15/15
to play-fr...@googlegroups.com
Thanks for the link James, that was interesting.

For people who don't want to sit through the 1h presentation: Yevgeniy Brikman at LinkedIn shows how to implement Facebook's BigPipe concept in Play. The sample code from the presentation is available on github. There are slides and the video is also available on youtube (better UX than ustream).

It's an interesting approach - it is way beyond what I was shooting for, as our pages are quite simple in comparison and usually only rely on a single backend server & for better or worse we concat all our js & css into two monolithic files, but for complex dashboards & where you want to be a little more aggressive on what css/js you actually include it makes a lot of sense.

Still no plug-and-play solution to set the cookies. Basically you'll have to hack it together such that you have some javascript set the cookie on the client side if you want to set cookies in your chunked actions, which meshes so-so with e.g. the session and flash cookies since you normally want those to be httpOnly (= not accessible via javascript).

For cookies shared across js & http it could work quite well.

Jxtps

unread,
Apr 16, 2015, 6:53:26 PM4/16/15
to play-fr...@googlegroups.com
For anyone wanting to do this and hosting their site on AWS behind an ELB, you should be aware that the ELB only supports HTTP/1.0 => no chunked transfer encoding for HTTP-mode ELBs. You'll have to switch to a TCP based ELB for it to work, and that will cause you to lose the client IP address (X-Forwarded-For) unless you start using the Proxy protocol as described in:

http://stackoverflow.com/questions/25977791/play-framework-retrieve-the-clients-ip-when-using-tcp-load-balancing (answered by Mr Roper no less)

which references: https://chrislea.com/2014/03/20/using-proxy-protocol-nginx/
Reply all
Reply to author
Forward
0 new messages