com.twitter.finagle.SimpleFilter Scala Examples

The following examples show how to use com.twitter.finagle.SimpleFilter. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example.
Example 1
Source File: FinagleRetryFilter.scala    From airframe   with Apache License 2.0 5 votes vote down vote up
package wvlet.airframe.http.finagle

import com.twitter.finagle.http.{Request, Response, Status}
import com.twitter.finagle.util.DefaultTimer
import com.twitter.finagle.{Service, SimpleFilter, http}
import com.twitter.util._
import wvlet.airframe.control.ResultClass
import wvlet.airframe.control.Retry.{MaxRetryException, RetryContext}
import wvlet.airframe.http.{HttpClientException, HttpClientMaxRetryException}
import wvlet.log.LogSupport


class FinagleRetryFilter(retry: RetryContext, timer: Timer = DefaultTimer)
    extends SimpleFilter[http.Request, http.Response]
    with LogSupport {
  import com.twitter.conversions.DurationOps._

  private[this] def schedule(d: Duration)(f: => Future[Response]) = {
    if (d > 0.seconds) {
      val promise = new Promise[Response]
      timer.schedule(Time.now + d) {
        promise.become(f)
      }
      promise
    } else {
      f
    }
  }

  private def dispatch(
      retryContext: RetryContext,
      request: Request,
      service: Service[Request, Response]
  ): Future[Response] = {
    val rep = service(request)
    rep.transform { x =>
      val classifier = x match {
        case Throw(e) =>
          retryContext.errorClassifier(e)
        case Return(r) =>
          retryContext.resultClassifier(r)
      }

      classifier match {
        case ResultClass.Succeeded =>
          rep
        case ResultClass.Failed(isRetryable, cause, extraWait) => {
          if (!retryContext.canContinue) {
            // Reached the max retry
            rep.flatMap { r =>
              Future.exception(HttpClientMaxRetryException(FinagleHttpResponseWrapper(r), retryContext, cause))
            }
          } else if (!isRetryable) {
            // Non-retryable failure
            Future.exception(cause)
          } else {
            Future
              .value {
                // Update the retry count
                retryContext.withExtraWait(extraWait).nextRetry(cause)
              }.flatMap { nextRetryContext =>
                // Wait until the next retry
                schedule(nextRetryContext.nextWaitMillis.millis) {
                  // Run the same request again
                  dispatch(nextRetryContext, request, service)
                }
              }
          }
        }
      }
    }
  }

  override def apply(request: Request, service: Service[Request, Response]): Future[Response] = {
    val retryContext = retry.init(Option(request))
    dispatch(retryContext, request, service)
  }
} 
Example 2
Source File: FinagleFilter.scala    From airframe   with Apache License 2.0 5 votes vote down vote up
package wvlet.airframe.http.finagle

import com.twitter.finagle.http.{Request, Response}
import com.twitter.finagle.{Service, SimpleFilter}
import com.twitter.util.Future
import wvlet.airframe.Session
import wvlet.airframe.codec.MessageCodecFactory
import wvlet.airframe.http.{HttpBackend, HttpFilter}
import wvlet.airframe.http.router.HttpRequestDispatcher


abstract class FinagleFilter extends HttpFilter[Request, Response, Future] {
  override def backend: HttpBackend[Request, Response, Future] = FinagleBackend
}

class FinagleRouter(session: Session, private[finagle] val config: FinagleServerConfig)
    extends SimpleFilter[Request, Response] {
  private val dispatcher =
    HttpRequestDispatcher.newDispatcher(
      session,
      config.router,
      config.controllerProvider,
      FinagleBackend,
      config.responseHandler,
      MessageCodecFactory.defaultFactory.orElse(MessageCodecFactory.newFactory(config.customCodec))
    )

  override def apply(request: Request, service: Service[Request, Response]): Future[Response] = {
    dispatcher.apply(request, FinagleBackend.newContext { request: Request => service(request) })
  }
} 
Example 3
Source File: CorsFilterTest.scala    From airframe   with Apache License 2.0 5 votes vote down vote up
package wvlet.airframe.http.finagle
import com.twitter.finagle.{Service, SimpleFilter}
import com.twitter.finagle.http.{Request, Response}
import com.twitter.util.Future
import wvlet.airframe.Design
import wvlet.airframe.http.Router
import wvlet.airframe.http.finagle.CorsFilterTest.{CheckFilter, LogFilter, SimpleFilter}
import wvlet.airframe.http.finagle.filter.CorsFilter
import wvlet.airspec.AirSpec
import wvlet.log.LogSupport

object CorsFilterTest {

  // Test SimpleFilter of Finagle
  object CheckFilter extends SimpleFilter[Request, Response] with LogSupport {
    override def apply(request: Request, service: Service[Request, Response]): Future[Response] = {
      info(s"checking request: ${request}")
      service(request)
    }
  }

  object LogFilter extends FinagleFilter with LogSupport {
    override def apply(
        request: Request,
        context: LogFilter.Context
    ): Future[Response] = {
      info(s"logging request: ${request}")
      context(request)
    }
  }

  object SimpleFilter extends FinagleFilter with LogSupport {
    override def apply(
        request: Request,
        context: SimpleFilter.Context
    ): Future[Response] = {
      toFuture {
        info(s"handling request: ${request}")
        val r = Response()
        r.contentString = request.headerMap.mkString(", ")
        r
      }
    }
  }
}


class CorsFilterTest extends AirSpec {

  override protected def design: Design = {
    val r = Router
      .add(LogFilter)
      .andThen(FinagleBackend.wrapFilter(CheckFilter))
      .andThen(CorsFilter.unsafePermissiveFilter)
      .andThen(SimpleFilter)

    debug(r)

    newFinagleServerDesign(router = r)
      .add(finagleSyncClientDesign)
  }

  def `support CORS filter`(client: FinagleSyncClient): Unit = {
    val resp = client.get[String]("/")
    debug(resp)
  }

} 
Example 4
Source File: QueryCacheFilter.scala    From the-finagle-docs   with MIT License 5 votes vote down vote up
package net.gutefrage.filter

import com.redis._
import com.redis.serialization.Parse.Implicits._
import com.twitter.finagle.{Service, SimpleFilter}
import com.twitter.util.Future
import net.gutefrage.filter.ThriftByteArray._

class QueryCacheFilter(val methodsToCache: Option[Seq[String]] = None, redisClient: RedisClient) extends SimpleFilter[Array[Byte], Array[Byte]] {

  def bytesToInt(bytes: Array[Byte]): Int = java.nio.ByteBuffer.wrap(bytes).getInt

  def apply(request: Array[Byte], service: Service[Array[Byte], Array[Byte]]): Future[Array[Byte]] = {
    val (methodName, seqId) = request.binaryProtocolMethodNameSeqId

    if (methodsToCache.isEmpty || methodsToCache.get.contains(methodName)) {
      println(s"Incoming request with method: $methodName -> Try to serve it from cache.")
      val redisKey = request.binaryProtocolChangeSeqId(Array[Byte](0, 0, 0, 0)).requestHashKey

      redisClient.get[Array[Byte]](redisKey) match {
        case Some(response) => {
          println("Data in redis found, returning from cache")
          Future.value(response)
        }
        case None => {
          println("data not in cache yet")
          service(request) map { result =>
            redisClient.setex(redisKey, 15, result)
            result
          }
        }
      }

    } else {
      println(s"Incoming request with method: $methodName -> Don't serve it from cache.")
      service(request)
    }

  }

} 
Example 5
Source File: HttpMonitoringFilter.scala    From finagle-prometheus   with MIT License 5 votes vote down vote up
package com.samstarling.prometheusfinagle.filter

import com.samstarling.prometheusfinagle.metrics.Telemetry
import com.twitter.finagle.http.{Request, Response}
import com.twitter.finagle.{Service, SimpleFilter}
import com.twitter.util.Future

class HttpMonitoringFilter(telemetry: Telemetry,
                           labeller: ServiceLabeller[Request, Response] =
                             new HttpServiceLabeller)
    extends SimpleFilter[Request, Response] {

  private val counter = telemetry.counter(
    name = "incoming_http_requests_total",
    help = "The number of incoming HTTP requests",
    labelNames = labeller.keys
  )

  override def apply(request: Request,
                     service: Service[Request, Response]): Future[Response] = {
    service(request) onSuccess { response =>
      counter.labels(labeller.labelsFor(request, response): _*).inc()
    }
  }
} 
Example 6
Source File: HttpLatencyMonitoringFilter.scala    From finagle-prometheus   with MIT License 5 votes vote down vote up
package com.samstarling.prometheusfinagle.filter

import com.samstarling.prometheusfinagle.metrics.Telemetry
import com.twitter.finagle.http.{Request, Response}
import com.twitter.finagle.{Service, SimpleFilter}
import com.twitter.util.{Future, Stopwatch}

class HttpLatencyMonitoringFilter(telemetry: Telemetry,
                                  buckets: Seq[Double],
                                  labeller: ServiceLabeller[Request, Response] =
                                    new HttpServiceLabeller)
    extends SimpleFilter[Request, Response] {

  private val histogram = telemetry.histogram(
    name = "incoming_http_request_latency_seconds",
    help = "A histogram of the response latency for HTTP requests",
    labelNames = labeller.keys,
    buckets = buckets
  )

  override def apply(request: Request,
                     service: Service[Request, Response]): Future[Response] = {
    val stopwatch = Stopwatch.start()
    service(request) onSuccess { response =>
      histogram
        .labels(labeller.labelsFor(request, response): _*)
        .observe(stopwatch().inMilliseconds / 1000.0)
    }
  }
} 
Example 7
Source File: AssetsFilter.scala    From peregrine   with Apache License 2.0 5 votes vote down vote up
package io.peregrine

import com.twitter.finagle.http.{Request => FinagleRequest, Response => FinagleResponse}
import com.twitter.finagle.{Service, SimpleFilter}
import com.twitter.util._

class AssetsFilter extends SimpleFilter[FinagleRequest, FinagleResponse] with LoggingFilterHelper {
  val logger = PeregrineLogger.logger()
  def apply(req: FinagleRequest, service: Service[FinagleRequest, FinagleResponse]): Future[FinagleResponse] = {
    if (req.path.startsWith("/__peregrine__/")) {
      return if (config.debugAssets()){
        applyLogging(req, request => Future(render.internal(req.path.replace("/__peregrine__", "__peregrine__"), 200).build))
      } else {
        Future(render.internal(req.path.replace("/__peregrine__", "__peregrine__"), 200).build)
      }
    }

    if (req.path.startsWith(config.assetsPathPrefix())) {
      if (config.debugAssets()) {
        applyLogging(req, request => applyAssets(request))
      } else {
        applyAssets(req)
      }
    } else {
      service(req)
    }
  }

  private[this] def applyAssets(req: FinagleRequest) = {
    val path = req.path.replace(config.assetsPathPrefix(), "")
    Try(render.static(path).build) match {
      case Return(resp) => Future(resp)
      case Throw(t)     => Future(render.notFound.build)
    }
  }

  protected def render = new ResponseBuilder()
} 
Example 8
Source File: CsrfFilter.scala    From peregrine   with Apache License 2.0 5 votes vote down vote up
package io.peregrine

import com.twitter.finagle.http.{Request => FinagleRequest, Response => FinagleResponse}
import com.twitter.finagle.{Service, SimpleFilter}
import com.twitter.util.{Future,Await}
import org.jboss.netty.handler.codec.http.HttpMethod

class CsrfFilter extends SimpleFilter[FinagleRequest, FinagleResponse] with Sessions {

  def apply(req: FinagleRequest, service: Service[FinagleRequest, FinagleResponse]): Future[FinagleResponse] = {
    // we bypass on assets requests
    if (req.path.startsWith(config.assetsPathPrefix())) {
      service(req)
    } else {
      _applyCsrfProtection(req, service)
    }
  }

  private def _applyCsrfProtection(req: FinagleRequest, service: Service[FinagleRequest, FinagleResponse]) = {
    if (req.method == HttpMethod.GET) {
      for {
        _           <- _addCsrfToken(req)
        res         <- service(req)
      } yield res
    } else {
      for {
        csrfToken   <- _addCsrfToken(req)
        authToken   <- Future(req.cookies.getOrElse("_authenticity_token", buildVoidCookie).value)
        paramToken  <- Future(req.params.getOrElse("_csrf_token", ""))
        res         <- if (csrfToken == paramToken && csrfToken == authToken) service(req)
                       else Future(new ResponseBuilder().status(403).body("CSRF failed").build)
      } yield res
    }
  }

  private def _addCsrfToken(req: FinagleRequest) = {
    for {
      session     <- session(new Request(req))
      csrfToken   <- session.getOrElseUpdate[String]("_csrf_token", generateToken)
      _           <- Future(req.response.addCookie(buildCsrfCookie(csrfToken)))
    } yield csrfToken
  }

  protected def generateToken = IdGenerator.hexString(32)

  private def buildVoidCookie = new CookieBuilder().name("_authenticity_token").value("").build()
  private def buildCsrfCookie(value: String) = {
    new CookieBuilder().name("_authenticity_token")
      .value(value)
      .httpOnly(httpOnly = true)
      // enables cookies for secure session if cert and key are provided
      .secure(!config.certificatePath().isEmpty && !config.keyPath().isEmpty)
      .build()
  }
} 
Example 9
Source File: LoggingFilter.scala    From peregrine   with Apache License 2.0 5 votes vote down vote up
package io.peregrine

import com.twitter.finagle.http.{Request => FinagleRequest, Response => FinagleResponse}
import com.twitter.finagle.{Service, SimpleFilter}
import com.twitter.logging.Logger
import com.twitter.util._
import com.twitter.conversions.time._

class LoggingFilter extends SimpleFilter[FinagleRequest, FinagleResponse] with LoggingFilterHelper {
  def apply(request: FinagleRequest, service: Service[FinagleRequest, FinagleResponse]): Future[FinagleResponse] = {
    applyLogging(request, req => service(req))
  }
}

trait LoggingFilterHelper extends LoggerColors {
  private val logger: Logger = PeregrineLogger.logger()

  private[peregrine] def applyLogging(request: FinagleRequest,
                                      func: FinagleRequest => Future[FinagleResponse]): Future[FinagleResponse] = {
    val elapsed = Stopwatch.start()
    func(request) map { response =>

      val duration = elapsed().inMicroseconds/1000.0
      val mColor = methodColor(response.statusCode)
      logger.info("[%s%s] %s%s %s\"%s\" %s%d %sin %s%.3fms%s",
          ANSI_RESET, request.remoteHost,
          ANSI_PURPLE, request.method,
          ANSI_BLUE, request.uri,
          mColor, response.statusCode,
          ANSI_RESET,
          ANSI_GREEN, duration,
          ANSI_RESET
      )
      response
    }
  }

  private[this] def methodColor(statusCode: Int) = statusCode match {
    case code if code >= 200 && code < 300 => ANSI_GREEN
    case code if code >= 400 && code < 500 => ANSI_YELLOW
    case code if code >= 500 && code < 600 => ANSI_RED
    case _                                 => ANSI_RESET
  }
}