Permalink
Browse files

filling out NettyHttpResponse

- keep alive connections
- cookies
- headers
  • Loading branch information...
1 parent cd63189 commit 189d8e57ebc7b4561cadb4dfae28e7b2e178ef90 @jrwest committed Feb 24, 2012
@@ -51,6 +51,7 @@ class LiftChannelHandler(val nettyContext: HTTPNettyContext,
override def messageReceived(ctx: ChannelHandlerContext, e: MessageEvent) {
val request = e.getMessage.asInstanceOf[HttpRequest]
+ val keepAlive = HttpHeaders.isKeepAlive(request)
if (HttpHeaders.is100ContinueExpected(request)) {
send100Continue(e);
@@ -65,7 +66,7 @@ class LiftChannelHandler(val nettyContext: HTTPNettyContext,
val httpRequest: HTTPRequest = new NettyHttpRequest(request, ctx, nettyContext, this)
- val httpResponse = new NettyHttpResponse(ctx)
+ val httpResponse = new NettyHttpResponse(ctx, keepAlive)
handleLoanWrappers(service(httpRequest, httpResponse) {
doNotHandled()
@@ -1,10 +1,11 @@
package com.something.lift
-import org.jboss.netty.handler.codec.http.{HttpResponseStatus, HttpVersion, DefaultHttpResponse, HttpResponse}
import org.jboss.netty.buffer.ChannelBuffers
import net.liftweb.http.provider.{HTTPParam, HTTPCookie, HTTPResponse}
import java.io.OutputStream
import org.jboss.netty.channel.{ChannelHandlerContext, ChannelFutureListener}
+import org.jboss.netty.handler.codec.http._
+import net.liftweb.http.LiftRules
/**
* Created by IntelliJ IDEA.
@@ -13,40 +14,83 @@ import org.jboss.netty.channel.{ChannelHandlerContext, ChannelFutureListener}
* Time: 8:41 PM
*/
-class NettyHttpResponse(ctx: ChannelHandlerContext) extends HTTPResponse {
+/**
+ * Representation of the HTTPResponseStatus
+ *
+ * @param ctx - the netty channel handler context
+ * @param keepAlive - if true the channel's connection will remain open after response is written, otherwise it will be closed.
+ *
+ */
+class NettyHttpResponse(ctx: ChannelHandlerContext, keepAlive: Boolean) extends HTTPResponse {
lazy val nettyResponse: HttpResponse = {
val r = new DefaultHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK)
r.setContent(ChannelBuffers.dynamicBuffer(1024)) // TODO this is just some random choice, do something more intelligent?
r
}
+
+ private var cookies = List[HTTPCookie]()
- // FIXME actually add cookies to the response
- def addCookies(cookies: List[HTTPCookie]) {}
+ def addCookies(cks: List[HTTPCookie]) {
+ cookies ++= cks
+ }
- // FIXME add session id if/when sessions are supported?
+ // FIXME should add session id to url if/when sessions are supported but session id not set in cookies
def encodeUrl(url: String): String = url
- // FIXME actually set headers
- def addHeaders(headers: List[HTTPParam]) {}
+ def addHeaders(headers: List[HTTPParam]) {
+ val appearOnce = Set(LiftRules.overwrittenReponseHeaders.vend.map(_.toLowerCase):_*)
+ for (h <- headers;
+ value <- h.values) {
+ if (appearOnce.contains(h.name.toLowerCase)) nettyResponse.setHeader(h.name, value)
+ else nettyResponse.addHeader(h.name, value)
+ }
+ }
- def setStatus(status: Int) = nettyResponse.setStatus(HttpResponseStatus.valueOf(status))
+ def setStatus(status: Int) {
+ nettyResponse.setStatus(HttpResponseStatus.valueOf(status))
+ }
def getStatus: Int = nettyResponse.getStatus.getCode
- // FIXME
- def setStatusWithReason(status: Int, reason: String) = throw new Exception("Implement me")
+ // TODO: it is possible to implement this method although netty has no equiv. but more intelligent content buffer management is needed
+ def setStatusWithReason(status: Int, reason: String) = throw new Exception("not implemented, there is no equivalent in netty")
- // TODO make better: override other write methods, better flush
+ // TODO better flush
def outputStream: OutputStream = new OutputStream {
- // TODO: there is a probably a better impl, by override the other write methods.
+
def write(i: Int) {
nettyResponse.getContent.writeByte(i)
}
+ override def write(bytes: Array[Byte]) {
+ nettyResponse.getContent.writeBytes(bytes)
+ }
+
+ override def write(bytes: Array[Byte], offset: Int, len: Int) {
+ nettyResponse.getContent.writeBytes(bytes, offset, len)
+ }
+
override def flush() {
+ if (cookies.length > 0) writeCookiesToResponse()
val future = ctx.getChannel.write(nettyResponse)
- future.addListener(ChannelFutureListener.CLOSE)
+ if (!keepAlive) future.addListener(ChannelFutureListener.CLOSE)
}
}
+
+ private def writeCookiesToResponse() {
+ val encoder = new CookieEncoder(true)
+
+ for (c <- cookies) {
+ val cookie = new DefaultCookie(c.name, c.value openOr null)
+ c.domain foreach (cookie.setDomain(_))
+ c.path foreach (cookie.setPath(_))
+ c.maxAge foreach (cookie.setMaxAge(_))
+ c.version foreach (cookie.setVersion(_))
+ c.secure_? foreach (cookie.setSecure(_))
+ c.httpOnly foreach (cookie.setHttpOnly(_))
+ }
+
+ addHeaders(HTTPParam(HttpHeaders.Names.SET_COOKIE, encoder.encode) :: Nil)
+ }
}

0 comments on commit 189d8e5

Please sign in to comment.