Skip to content

Instantly share code, notes, and snippets.

@stephenjudkins
Created November 3, 2011 03:57
Show Gist options
  • Save stephenjudkins/1335736 to your computer and use it in GitHub Desktop.
Save stephenjudkins/1335736 to your computer and use it in GitHub Desktop.
Unfiltered matchers and responders working w/ Finagle
import com.twitter.finagle.builder.ServerBuilder
import com.twitter.finagle.http.Http
import com.twitter.finagle.{ClientConnection, Service}
import com.twitter.util.{Promise, Future}
import java.io.{ByteArrayOutputStream, BufferedReader, InputStreamReader}
import java.net.{URLDecoder, InetSocketAddress}
import java.nio.charset.{Charset => JNIOCharset}
import org.jboss.netty.buffer.{ChannelBuffers, ChannelBufferInputStream}
import org.jboss.netty.handler.codec.http.{HttpResponseStatus, DefaultHttpResponse, HttpVersion, CookieDecoder, HttpHeaders, HttpResponse => NHttpResponse, HttpRequest => NHttpRequest}
import unfiltered.Cookie
import unfiltered.netty.HttpConfig
import unfiltered.request._
import unfiltered.response._
import scala.collection.JavaConversions._
object Main {
type Request = HttpRequest[Any]
type Response = ResponseFunction[NHttpResponse]
def urldecode(enc: String) : Map[String, Seq[String]] = {
def decode(raw: String) = URLDecoder.decode(raw, HttpConfig.DEFAULT_CHARSET)
val pairs = enc.split('&').flatMap {
_.split('=') match {
case Array(key, value) => List((decode(key), decode(value)))
case Array(key) if key != "" => List((decode(key), ""))
case _ => Nil
}
}.reverse
(Map.empty[String, List[String]].withDefault {_ => Nil } /: pairs) {
case (m, (k, v)) => m + (k -> (v :: m(k)))
}
}
class NettyRequest(conn: ClientConnection, request: NHttpRequest) extends HttpRequest(request) {
lazy val params = queryParams ++ postParams
def queryParams = request.getUri.split("\\?", 2) match {
case Array(_, qs) => urldecode(qs)
case _ => Map.empty[String,Seq[String]]
}
def postParams = this match {
case POST(RequestContentType(ct)) if ct.contains("application/x-www-form-urlencoded") =>
urldecode(request.getContent.toString(JNIOCharset.forName(charset)))
case _ => Map.empty[String,Seq[String]]
}
def remoteAddr = conn.remoteAddress.toString
def isSecure = false
def cookies = Nil
def headers(name: String) = request.getHeaders(name).iterator
def parameterValues(param: String) = params(param)
def parameterNames = params.keySet.iterator
def uri = request.getUri
def method = request.getMethod.toString.toUpperCase
def protocol = request.getProtocolVersion match {
case HttpVersion.HTTP_1_0 => "HTTP/1.0"
case HttpVersion.HTTP_1_1 => "HTTP/1.1"
}
lazy val inputStream = new ChannelBufferInputStream(request.getContent)
lazy val reader = new BufferedReader(new InputStreamReader(inputStream, charset))
private def charset = this match {
case unfiltered.request.Charset(cs, _) => cs
case _ => HttpConfig.DEFAULT_CHARSET
}
}
def newNettyResponse = new DefaultHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK)
class NettyResponse(val res: NHttpResponse) extends HttpResponse[NHttpResponse](res) {
def cookies(cookies: Seq[Cookie]) {}
def header(name: String, value: String) {
res.setHeader(name, value)
}
def redirect(url: String) {
res.setStatus(HttpResponseStatus.FOUND)
res.setHeader(HttpHeaders.Names.LOCATION, url)
}
lazy val byteOutputStream = new ByteArrayOutputStream
def outputStream = byteOutputStream
def status(statusCode: Int) {
res.setStatus(HttpResponseStatus.valueOf(statusCode))
}
def finish() {
res.setContent(ChannelBuffers.copiedBuffer(byteOutputStream.toByteArray))
}
}
val router:PartialFunction[Request, Future[Response]] = {
case r => Future(Ok ~> ResponseString("hello world: %s" format r.toString))
}
def main(args: Array[String]) {
def service(clientConnection: ClientConnection) = new Service[NHttpRequest, NHttpResponse] {
def apply(request: NHttpRequest) = {
val wrapped = new NettyRequest(clientConnection, request)
router.lift(wrapped).getOrElse(Future.value(NotFound ~> ResponseString("no matching route"))) map { responder =>
val nettyResponse = newNettyResponse
val response = new NettyResponse(nettyResponse)
responder(response)
response.finish()
nettyResponse
}
}
}
val server = ServerBuilder().
codec(Http()).
bindTo(new InetSocketAddress(8080)).
name("Test").
build(service(_))
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment