目次

Version 1, last updated by timperrett at Dec 01 10:20 UTC

What follows is a description of the HTTP pipeline within Lift. This process was extracted from the codebase as of Lift 2.2-SNAPSHOT, 20th November 2010 by Tim Perrett.

Bootup

  • Set the servlet context if appropriate
  • Check the filter configuration for the lift bootloader FQCN
  • Touch LiftRules and append the classpath service to the stateless dispatch table so the ResourceServer can do its thing.
  • Boot lift by reflecting on the supplied FCQN. By default this is bootstrap.liftweb.Boot
  • Lift has booted up, so load the internal resource bundles for the Lift core localized stuff based on the value defined in LiftRules.liftCoreResourceName
  • Check the current production mode and if this is “production” and the user has not explicitly set a template cache themselves via LiftRules.templateCache make an in-memory cache that can hold 500 templates.
  • Lift has completed its boot, set the “doneBoot” flag to true
  • Create an instance of LiftServlet and pass it the computed context

Request

  • Check to see if Lift is trying to shutdown, if it is, just pass the request down the filter chain. If not, continue.
  • Increment the LiftRules.reqCnt atomic integer.
  • Execute the functions defined in LiftRules.early, passing them the instance of HTTPRequest as you go.
  • Create the raw Req instance from the plain request
  • Determine the request verb (GET, POST etc)
  • Get the context path (either from the request or LiftRules.calculateContextPath)
  • Generate a ParsePath
  • Apply the statelessRewriting to the incoming request and do so repeatedly until there are no more matches within the partial function LiftRules.statelessRewrite and map the parameters (if any) into a local Map[String, List[String]]
  • Get the content type from the incoming request
  • Parse the incoming paramaters; be that query string, request body etc
  • Check the request to see if it has been defined as “stateless” within LiftRules.statelessTest
  • Create a new Req instance based upon the rewritten request inclusive of any parameters that were parsed from the query string, request body etc and if it should be stateless or statefull.
  • Rewrite the request internally if there are any URL decorators applied via LiftRules.urlDecorate
  • Determine if this request is specifically marked as a Lift request or not via LiftRules.liftRequest. If its not a Lift request explicitly pass it down the filter chain. Otherwise, assume its a Lift request and pass it to the instance of LiftServlet
  • Check the incoming request for request suspension. Determined by the LiftRules.servletAsyncProvider function. The default is to check for Jetty6 continuations.
  • If LiftRules.logServiceRequestTiming is set, start logging the request parts.
  • Execute the LiftRules.onBeginServicing functions
  • Check to see if this request passes the authentication hooks provided by LiftRules.httpAuthProtectedResource if anything is defined there. If something is defined and the request did not pass said authentication, return the response defined at LiftRules.authentication.unauthorizedResponse
  • If this request is either an AJAX or Comet request and as we have no existing session, and LiftRules.redirectAjaxOnSessionLoss is defined as true, send a redirect script back to the browser. The default behaviour is to redirect back to the Referrer if one exists, otherwise back to the site root (/).
  • Look to see if this request is matched in the LiftRules.statelessDispatchTable. If it is, statelessly dispatch this request, otherwise, start to initialise the session.
  • Create a new session via LiftRules.getLiftSession, registering it with the internal SessionMaster actor, then call S.init and hand off the Req instance.
  • With the session initialised, if the request matches LiftRules.dispatchTable, then the request is handled by dispatchTable. Execute the functions defined in LiftSession.onBeginServicing if the request was in dispatchTable.
  • If the request is a Comet request, it’s handled by the Comet handler.
  • If the request is an Ajax request, it’s handled by the Ajax handler. Otherwise, the request is handed off the the LiftSession for further processing.
  • Check this request against the highLevelSessionDispatcher and dispatch it if there is a match. That is, if you have some kind of session-specific dispatch setup goin’ on.
  • Check the incoming request against SiteMap, if there is an issue SiteMap-wise, return the right response, a 404 in production, or a nice helpful message in development mode.
  • Figure out the right template for this request by removing parts of the path that start with ‘.’, ‘_’ or contain ‘-hidden’ and the resource is looked up in LiftSession.findAnyTemplate which is inclusive of the locale calculation and other fancy template lookup.
  • If no file based template is found, then Lift goes looking for classes. That is, LiftViews.
  • Process the surrounds, update the internal function mappings, merge the head and tail elements and handle all the dodgy things needed for browsers like explorer. Finally convert the NodeSeq to a response using LiftRules.convertResponse, passing the default headers defined in LiftRules.defaultHeaders
  • Execute the LiftRules.onEndServicing functions
  • Execute the LiftRules.beforeSend functions and attach LiftRules.supplimentalHeaders to the out-going request.
  • Flush the response
  • Execute LiftRules.afterSend

Shutdown

  • kill off all sessions
  • Wait for the request count to be zero, wait 10 seconds for all requests to finish if some still in progress
  • shutdown the internal actors ActorPing and LAScheduler
  • Run the unload hooks defined by the user.