Skip to content

Instantly share code, notes, and snippets.

@justinholmes
Created February 12, 2012 02:14
Show Gist options
  • Save justinholmes/1805815 to your computer and use it in GitHub Desktop.
Save justinholmes/1805815 to your computer and use it in GitHub Desktop.
finagle reverse proxy - do not use in production
package com.nascency.incipit
import com.twitter.finagle.{Service, SimpleFilter}
import org.jboss.netty.handler.codec.http._
import org.jboss.netty.handler.codec.http.HttpResponseStatus._
import org.jboss.netty.handler.codec.http.HttpVersion.HTTP_1_1
import org.jboss.netty.buffer.ChannelBuffers.copiedBuffer
import org.jboss.netty.util.CharsetUtil.UTF_8
import com.twitter.util.Future
import java.net.InetSocketAddress
import com.twitter.finagle.builder.{Server, ServerBuilder}
import com.twitter.finagle.http.Http
import com.twitter.finagle.builder.ClientBuilder
import org.jboss.netty.util.CharsetUtil
import scala.collection.JavaConverters._
import com.google.common.collect.HashMultimap
import com.google.common.collect.Multimap
import com.google.common.collect.Multimaps
object LoadBalancer {
def main(args: Array[String]) = {
val respond = new Respond
// compose the Filters and Service together:
val myService: Service[HttpRequest, HttpResponse] = respond
val server: Server = ServerBuilder()
.codec(Http())
.bindTo(new InetSocketAddress(8080))
.name("httpserver")
.build(myService)
}
val mappings : Multimap[String,String] = Multimaps.synchronizedMultimap(HashMultimap.create());
List(("localhost:8080", "localhost:9000"),("localhost","localhost:9001")).map(e => mappings.put(e._1, e._2))
class Respond extends Service[HttpRequest, HttpResponse] {
def apply(request: HttpRequest) = {
val hostname = request.containsHeader("Host") match{case true => request.getHeader("Host").toString() ; case false => { val response = new DefaultHttpResponse(HTTP_1_1, OK)
response.setContent(copiedBuffer( "LB server error", UTF_8))
Future.value(response)}}
var returns = ""
val searchForDestination = mappings.get(hostname.toString())
searchForDestination.asScala.toList.foreach{d=>returns += d+","}
//println(returns)
val hosts = returns
val method = request.getMethod()
val path = request.getUri()
try{
val clientWithoutErrorHandling: Service[HttpRequest, HttpResponse] = ClientBuilder()
.codec(Http())
.hosts(hosts)
.hostConnectionLimit(1)
.retries(2)
.build()
val authorizedRequest = new DefaultHttpRequest(
HttpVersion.HTTP_1_1, method, path)
for (req <- request.getHeaders().asScala.toList){
//println(req.getKey(),req.getValue())
if (! "Connection".equals(req.getKey())) {
authorizedRequest.setHeader(req.getKey(),req.getValue())
}
}
authorizedRequest.addHeader("Host",request.getHeader("Host"))
// if(request.getHeader("Cookie") != null) authorizedRequest.addHeader("Cookie",request.getHeader("Cookie"))
authorizedRequest.setMethod(method)
if (request.isChunked()) {
println("Chunked")
}
authorizedRequest.setChunked(false)
authorizedRequest.setContent(request.getContent())
authorizedRequest.setUri(path)
clientWithoutErrorHandling(authorizedRequest) onSuccess {
response =>
val client: Service[HttpRequest, HttpResponse] = clientWithoutErrorHandling
val response2 = new DefaultHttpResponse(HTTP_1_1, response.getStatus())
for (req <- response.getHeaders().asScala.toList){
response2.setHeader(req.getKey(),req.getValue())
}
response2.setContent(response.getContent())
response2.setStatus(response.getStatus())
response2.setHeader("Server","Incipit LB")
response2.setChunked(true)
if(response.getHeader("Cookie") != null)response2.setHeader("Cookie",response.getHeader("Cookie"))
Future.value(response2)
}}catch {
case e => {
//e.printStackTrace()
val response = new DefaultHttpResponse(HTTP_1_1, HttpResponseStatus.INTERNAL_SERVER_ERROR)
response.setContent(copiedBuffer( """
The application could not route your request
""", UTF_8))
Future.value(response)
}
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment