All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.twitter.finatra.http.internal.server.BaseHttpServer.scala Maven / Gradle / Ivy

The newest version!
package com.twitter.finatra.http.internal.server

import com.twitter.app.Flag
import com.twitter.conversions.storage._
import com.twitter.conversions.time._
import com.twitter.finagle.{ListeningServer, Http, Service}
import com.twitter.finagle.http.service.NullService
import com.twitter.finagle.http.{Request, Response}
import com.twitter.finagle.stats.StatsReceiver
import com.twitter.finatra.conversions.string._
import com.twitter.inject.server.{PortUtils, TwitterServer}
import com.twitter.util._
import java.net.InetSocketAddress

trait BaseHttpServer extends TwitterServer {

  protected def defaultFinatraHttpPort: String = ":8888"
  private val httpPortFlag = flag("http.port", defaultFinatraHttpPort, "External HTTP server port")

  protected def defaultMaxRequestSize: StorageUnit = 5.megabytes
  private val maxRequestSizeFlag = flag("maxRequestSize", defaultMaxRequestSize, "HTTP(s) Max Request Size")

  protected def defaultHttpsPort: String = ""
  private val httpsPortFlag = flag("https.port", defaultHttpsPort, "HTTPs Port")

  protected def defaultCertificatePath: String = ""
  private val certificatePathFlag = flag("cert.path", defaultCertificatePath, "path to SSL certificate")

  protected def defaultKeyPath: String = ""
  private val keyPathFlag = flag("key.path", defaultKeyPath, "path to SSL key")

  protected def defaultShutdownTimeout: Duration = 1.minute
  private val shutdownTimeoutFlag = flag("shutdown.time", defaultShutdownTimeout, "Maximum amount of time to wait for pending requests to complete on shutdown")

  private val httpAnnounceFlag = flag[String]("http.announce", "Address for announcing HTTP server")

  private val httpsAnnounceFlag = flag[String]("https.announce", "Address for announcing HTTPS server")

  protected def defaultHttpServerName: String = "http"
  private val httpServerNameFlag = flag("http.name", defaultHttpServerName, "Http server name")

  protected def defaultHttpsServerName: String = "https"
  private val httpsServerNameFlag = flag("https.name", defaultHttpsServerName, "Https server name")

  /* Private Mutable State */

  private var httpServer: ListeningServer = _
  private var httpsServer: ListeningServer = _

  private lazy val baseHttpServer: Http.Server = {
    Http.server
      .withMaxRequestSize(maxRequestSizeFlag())
      .withStreaming(streamRequest)
  }

  /* Protected */

  protected def httpService: Service[Request, Response] = {
    NullService
  }

  /**
   * If false, the underlying Netty pipeline collects HttpChunks into the body of each Request
   * Set to true if you wish to stream parse requests using request.reader.read
   */
  protected def streamRequest: Boolean = false

  protected def configureHttpServer(server: Http.Server): Http.Server = {
    server
  }

  protected def configureHttpsServer(server: Http.Server): Http.Server = {
    server
  }

  /* Lifecycle */

  override protected def postWarmup() {
    super.postWarmup()

    startHttpServer()
    startHttpsServer()
  }

  override def waitForServer() {
    if (httpServer != null) {
      Await.ready(httpServer)
    } else {
      Await.ready(httpsServer)
    }
  }

  /* Overrides */

  override def httpExternalPort = Option(httpServer) map PortUtils.getPort

  override def httpsExternalPort = Option(httpsServer) map PortUtils.getPort

  /* Private */

  /* We parse the port as a string, so that clients can
     set the port to "" to prevent a http server from being started */
  private def parsePort(port: Flag[String]): Option[InetSocketAddress] = {
    port().toOption map PortUtils.parseAddr
  }

  private def startHttpServer() {
    for (port <- parsePort(httpPortFlag)) {
      val serverBuilder =
        configureHttpServer(
          baseHttpServer
            .withLabel(httpServerNameFlag())
            .withStatsReceiver(injector.instance[StatsReceiver]))

      httpServer = serverBuilder.serve(port, httpService)
      onExit {
        Await.result(
          close(httpServer, shutdownTimeoutFlag().fromNow))
      }
      for (addr <- httpAnnounceFlag.get) httpServer.announce(addr)
      info("http server started on port: " + httpExternalPort.get)
    }
  }

  private def startHttpsServer() {
    for (port <- parsePort(httpsPortFlag)) {
      val serverBuilder =
        configureHttpsServer(
          baseHttpServer
            .withLabel(httpsServerNameFlag())
            .withStatsReceiver(injector.instance[StatsReceiver])
            .withTransport.tls(
              certificatePathFlag(),
              keyPathFlag(),
              None, None, None))

      httpsServer = serverBuilder.serve(port, httpService)
      onExit {
        Await.result(
          close(httpsServer, shutdownTimeoutFlag().fromNow))
      }
      for (addr <- httpsAnnounceFlag.get) httpsServer.announce(addr)
      info("https server started on port: " + httpsExternalPort)
    }
  }

  private def close(server: ListeningServer, deadline: Time) = {
    if (server != null)
      server.close(deadline)
    else
      Future.Unit
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy