Writing Facebook applications in Lift (cookies, Javascript GC, example code)

20 views
Skip to first unread message

Steven Murdoch

unread,
Jun 28, 2009, 3:52:35 PM6/28/09
to Lift
Hi,

I've been looking at Scala and Lift recently, and so far have been
generally impressed. I'd like to write a Facebook application, both
because I need one, and so I can learn more about Lift and Scala. I do
have a few questions though, and I haven't been able to find answers
in the documentation or mailing list.

The first is about cookies and state. Facebook canvas applications
return pages which are re-written by the Facebook servers, so the
JSESSIONID cookie will not be present. As I understand it, that means
I'll need to manage state myself. I was therefore thinking about
returning pages from LiftRules.statelessDispatchTable (as described in
the Lift book, 3.13).

The problem here is that I'd need to return a LiftResponse directly,
and wouldn't be able to use most of the Lift infrastructure. Is this
the right way to do things? Is there some other way to suppress
cookies
and/or use Lift without them in the Facebook application context?

My second question is also because Facebook suppresses Javascript when
it processes web pages written in FBML. This means that the
client-side code to do garbage collection of widgets won't run. I can
disable the insertion using LiftRules.enableLiftGC, but will this
trigger other problems?

Finally, is there example code available for lift-facebook? It's great
that Lift supports Facebook, but other than a small mention in the
Lift book, I haven't been able to find any documentation. Some example
code would be very useful in getting started. Is there any available?

Thanks in advance,
Steven Murdoch.

--
http://www.cl.cam.ac.uk/users/sjm217/

Timothy Perrett

unread,
Jun 29, 2009, 6:13:04 AM6/29/09
to Lift
Steven,

Welcome to lift.

Lift doesn't use the JSESSIONID in the URL... that is, lift does not
require it (at least this is my understanding, if im wrong please
correct me someone) - so you should have no problems with the requests
being re-written.

Regarding the GC stuff, it was added to improve memory usage of
applications that run over a long period and to keep the heap size
down. Marius or DPP would probably be able to give you more specifics
but I think if your users are moving from page to page and you can
cope with a slightly larger heap size then it shouldn't be too much of
a problem. We did after all do without the GC stuff for quite sometime
as it was only added recently.

Hope that helps

Tim

marius d.

unread,
Jun 29, 2009, 6:58:19 AM6/29/09
to Lift


On Jun 29, 1:13 pm, Timothy Perrett <timo...@getintheloop.eu> wrote:
> Steven,
>
> Welcome to lift.
>
> Lift doesn't use the JSESSIONID in the URL... that is, lift does not
> require it (at least this is my understanding, if im wrong please
> correct me someone) - so you should have no problems with the requests
> being re-written.

Actaully Lift is no different then a regular JEE web app. If you turn
off cookies from the container you'll witness URL rewriting and
JSESSIONID will be part of the URL.

>
> Regarding the GC stuff, it was added to improve memory usage of
> applications that run over a long period and to keep the heap size
> down. Marius or DPP would probably be able to give you more specifics
> but I think if your users are moving from page to page and you can
> cope with a slightly larger heap size then it shouldn't be too much of
> a problem. We did after all do without the GC stuff for quite sometime
> as it was only added recently.

Essentially Lift GC is about de-referencing unseen bound functions if
a certain period of time exceeds. There is a lightweight heart beat
mechanism where Ajax requests are sent to keep functions alive. Of
course bound function are associated with a generated page-id.

jon

unread,
Jul 13, 2009, 1:30:31 AM7/13/09
to Lift
Hi Steven,

Have you done any more research into this problem?

I am also exploring this area-- by creating your application as an
iframe rather than fbml, which seems to be the recommended approach
(http://stackoverflow.com/questions/219804/new-facebook-app-fbml-or-
iframe), you should be able to use all the lift goodies out of the
box.

- Jon
> > > generally impressed. I'd like to write aFacebookapplication, both
> > > because I need one, and so I can learn more about Lift and Scala. I do
> > > have a few questions though, and I haven't been able to find answers
> > > in the documentation or mailing list.
>
> > > The first is about cookies and state.Facebookcanvas applications
> > > return pages which are re-written by theFacebookservers, so the
> > > JSESSIONID cookie will not be present. As I understand it, that means
> > > I'll need to manage state myself. I was therefore thinking about
> > > returning pages from LiftRules.statelessDispatchTable (as described in
> > > the Lift book, 3.13).
>
> > > The problem here is that I'd need to return a LiftResponse directly,
> > > and wouldn't be able to use most of the Lift infrastructure. Is this
> > > the right way to do things? Is there some other way to suppress
> > > cookies
> > > and/or use Lift without them in theFacebookapplication context?
>
> > > My second question is also becauseFacebooksuppresses Javascript when
> > > it processes web pages written in FBML. This means that the
> > > client-side code to do garbage collection of widgets won't run. I can
> > > disable the insertion using LiftRules.enableLiftGC, but will this
> > > trigger other problems?
>
> > > Finally, is there example code available for lift-facebook? It's great
> > > that Lift supportsFacebook, but other than a small mention in the

Steven Murdoch

unread,
Jul 19, 2009, 2:49:17 PM7/19/09
to lif...@googlegroups.com
Hi Jon,

On Sun, Jul 12, 2009 at 10:30:31PM -0700, jon wrote:
> Have you done any more research into this problem?

Yes, I tried a few of the suggestions on the list. Thanks to everyone
for their helpful responses. I haven't had time to progress the
application very far, but the basics are working.

Here are a few of my notes:

Javascript
==========

I disabled the addition of Javascript by adding to
bootstrap/liftweb/Boot.scala:

+ // Do not insert Javascript-based GC
+ LiftRules.enableLiftGC = false;
+
+ // Do not include Ajax include
+ LiftRules.autoIncludeAjax = _ => false;

Logging
=======

Liftweb sends stack traces to the browser, when running in development
mode. This isn't good for Facebook applications, because the content
of 500 error responses is not shown. So I changed to logging to a file
by adding to bootstrap/liftweb/Boot.scala:

+ // Send exceptions to log, not the browser
+ LiftRules.exceptionHandler.prepend {
+ case (_, r, e) =>
+ Log.error("Exception being returned to browser when processing "+r, e)
+ XhtmlResponse((<html>Something unexpected happened while serving the page at {r.uri}
+ </html>),ResponseInfo.docType(r), List("Content-Type" -> "text/html"), Nil, 500, S.ieMode)
+ }

Input validation
================

It appears that the current version of the Lift Facebook API does not
verify the signature on the Facebook POST variables. This would allow
someone to spoof a different Facebook user to the application. I care
about this in my application, so I wrote the following method to
validate parameters:

+ /**
+ * Confirm that the parameters really came from Facebook
+ */
+ def validateParameters: Boolean = {
+ // Check that the right parameters are present
+ if (S.request.isEmpty)
+ return false
+
+ val actualSignature = S.param("fb_sig")
+ if (actualSignature.isEmpty)
+ return false
+
+ // Format parameters for hashing, and append the secret
+ val params = S.request.open_!.params
+ val signedParams = for ((k,v) <- params if k.startsWith("fb_sig_")) yield k.substring(7) + "=" + v.mkString("")
+ val signedParamStr = signedParams.toList.sort(_ < _).mkString("") + FacebookRestApi.secret
+
+ // Hash the string and convert to hex
+ val md = _root_.java.security.MessageDigest.getInstance("MD5")
+ def byteToHex(b: Byte): String = Integer.toHexString((b & 0xf0) >>> 4) + Integer.toHexString(b & 0x0f)
+ val expectedSignature = md.digest((signedParamStr).getBytes).map(byteToHex(_)).mkString("")
+
+ // Verify the signature
+ return expectedSignature == actualSignature.open_!
+ }

Maybe this should go into the Facebook API. I haven't tried this.

Templates
=========

To keep the Lift XML parser happy, I added a namespace declaration for
the Facebook namespace. I also had to add a top level element. I found
that Facebook removes an <html> element before rendering FBML, so that
is a good choice.

This creates a template like the following:

+ <html xmlns:fb="http://apps.facebook.com/ns/1.0">
+ <fb:explanation> <fb:message>Explanation message</fb:message> This is the explanation message text. </fb:explanation>
+ </html>



> I am also exploring this area-- by creating your application as an
> iframe rather than fbml, which seems to be the recommended approach
> (http://stackoverflow.com/questions/219804/new-facebook-app-fbml-or-
> iframe), you should be able to use all the lift goodies out of the
> box.

Yes, I looked into this too, but it seems that opinions are split as
to what is better. For another set of ideas, see the Facebook wiki:
http://wiki.developers.facebook.com/index.php/Choosing_between_an_FBML_or_IFrame_Application

I went for FBML because it seemed simpler, and I've done one of these
before using Python and Pylons. I switched to Scala because I really
miss the lack of static type checking there.

Regarding cookies, it turns out that they are supported by the
Facebook API, although are a beta feature:
http://wiki.developers.facebook.com/index.php/Cookies

This will hopefully mean that session-based things in Lift will still
work.

I hope this helps. I would be very interested in hearing your
experience too.

Steven.

--
http://www.cl.cam.ac.uk/users/sjm217/

Reply all
Reply to author
Forward
0 new messages