Created
November 3, 2011 03:57
-
-
Save stephenjudkins/1335736 to your computer and use it in GitHub Desktop.
Unfiltered matchers and responders working w/ Finagle
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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