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

io.gatling.http.ahc.AhcFactory.scala Maven / Gradle / Ivy

There is a newer version: 3.13.1
Show newest version
/**
 * Copyright 2011-2016 GatlingCorp (http://gatling.io)
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package io.gatling.http.ahc

import java.util.concurrent.TimeUnit

import io.gatling.commons.util.SystemProps._
import io.gatling.core.{ ConfigKeys, CoreComponents }
import io.gatling.core.session.Session
import io.gatling.http.resolver.ExtendedDnsNameResolver
import io.gatling.http.util.SslHelper._

import akka.actor.ActorSystem
import com.typesafe.scalalogging.StrictLogging
import io.netty.channel.EventLoopGroup
import io.netty.channel.nio.NioEventLoopGroup
import io.netty.util.concurrent.DefaultThreadFactory
import io.netty.util.internal.logging.{ InternalLoggerFactory, Slf4JLoggerFactory }
import io.netty.util.{ HashedWheelTimer, Timer }
import org.asynchttpclient.AsyncHttpClientConfig._
import org.asynchttpclient._

private[gatling] object AhcFactory {

  def apply(system: ActorSystem, coreComponents: CoreComponents): AhcFactory =
    coreComponents.configuration.resolve(
      // [fl]
      //
      //
      //
      //
      //
      // [fl]
      new DefaultAhcFactory(system, coreComponents)
    )
}

private[gatling] trait AhcFactory {

  def defaultAhc: AsyncHttpClient

  def newAhc(session: Session): AsyncHttpClient

  def newNameResolver(): ExtendedDnsNameResolver
}

private[gatling] class DefaultAhcFactory(system: ActorSystem, coreComponents: CoreComponents) extends AhcFactory with StrictLogging {

  val configuration = coreComponents.configuration
  val ahcConfig = configuration.http.ahc
  setSystemPropertyIfUndefined("io.netty.allocator.type", configuration.http.ahc.allocator)
  setSystemPropertyIfUndefined("io.netty.maxThreadLocalCharBufferSize", configuration.http.ahc.maxThreadLocalCharBufferSize)

  // set up Netty LoggerFactory for slf4j instead of default JDK
  InternalLoggerFactory.setDefaultFactory(Slf4JLoggerFactory.INSTANCE)

  private[this] def newEventLoopGroup(poolName: String): EventLoopGroup = {
    val eventLoopGroup = new NioEventLoopGroup(0, new DefaultThreadFactory(poolName))
    system.registerOnTermination(eventLoopGroup.shutdownGracefully(0, 5, TimeUnit.SECONDS))
    eventLoopGroup
  }

  private[this] def newTimer: Timer = {
    val timer = new HashedWheelTimer(10, TimeUnit.MILLISECONDS)
    timer.start()
    system.registerOnTermination(timer.stop())
    timer
  }

  private[gatling] def newAhcConfigBuilder(eventLoopGroup: EventLoopGroup, timer: Timer) = {
    val ahcConfigBuilder = new DefaultAsyncHttpClientConfig.Builder()
      .setKeepAlive(ahcConfig.keepAlive)
      .setConnectTimeout(ahcConfig.connectTimeout)
      .setHandshakeTimeout(ahcConfig.handshakeTimeout)
      .setPooledConnectionIdleTimeout(ahcConfig.pooledConnectionIdleTimeout)
      .setReadTimeout(ahcConfig.readTimeout)
      .setMaxRequestRetry(ahcConfig.maxRetry)
      .setRequestTimeout(ahcConfig.requestTimeOut)
      .setUseProxyProperties(false)
      .setUserAgent(null)
      .setEventLoopGroup(eventLoopGroup)
      .setNettyTimer(timer)
      .setResponseBodyPartFactory(ResponseBodyPartFactory.LAZY)
      .setAcceptAnyCertificate(ahcConfig.acceptAnyCertificate)
      .setEnabledProtocols(ahcConfig.sslEnabledProtocols match {
        case Nil => null
        case ps  => ps.toArray
      })
      .setSslSessionCacheSize(ahcConfig.sslSessionCacheSize)
      .setSslSessionTimeout(ahcConfig.sslSessionTimeout)
      .setHttpClientCodecMaxInitialLineLength(ahcConfig.httpClientCodecMaxInitialLineLength)
      .setHttpClientCodecMaxHeaderSize(ahcConfig.httpClientCodecMaxHeaderSize)
      .setHttpClientCodecMaxChunkSize(ahcConfig.httpClientCodecMaxChunkSize)
      .setKeepEncodingHeader(true)
      .setWebSocketMaxFrameSize(ahcConfig.webSocketMaxFrameSize)
      .setUseOpenSsl(ahcConfig.useOpenSsl)
      .setUseNativeTransport(ahcConfig.useNativeTransport)
      .setValidateResponseHeaders(false)
      .setTcpNoDelay(ahcConfig.tcpNoDelay)
      .setSoReuseAddress(ahcConfig.soReuseAddress)
      .setSoLinger(ahcConfig.soLinger)
      .setSoSndBuf(ahcConfig.soSndBuf)
      .setSoRcvBuf(ahcConfig.soRcvBuf)

    if (ahcConfig.sslEnabledCipherSuites.nonEmpty) {
      ahcConfigBuilder.setEnabledCipherSuites(ahcConfig.sslEnabledCipherSuites.toArray)
    }

    val keyManagerFactory = configuration.http.ssl.keyStore
      .map(config => newKeyManagerFactory(config.storeType, config.file, config.password, config.algorithm))

    val trustManagerFactory = configuration.http.ssl.trustStore
      .map(config => newTrustManagerFactory(config.storeType, config.file, config.password, config.algorithm))

    if (keyManagerFactory.isDefined || trustManagerFactory.isDefined)
      ahcConfigBuilder.setSslContext(ahcConfig, keyManagerFactory, trustManagerFactory)

    ahcConfigBuilder
  }

  private[this] val defaultAhcConfig = {
    val eventLoopGroup = newEventLoopGroup("gatling-http-thread")
    val timer = newTimer
    val ahcConfigBuilder = newAhcConfigBuilder(eventLoopGroup, timer)
    ahcConfigBuilder.build
  }

  override val defaultAhc = newAhc(None)

  override def newAhc(session: Session): AsyncHttpClient = newAhc(Some(session))

  private[this] def newAhc(session: Option[Session]) = {
    val config = session.flatMap { session =>

      val keyManagerFactory = for {
        file <- session(ConfigKeys.http.ssl.keyStore.File).asOption[String]
        password <- session(ConfigKeys.http.ssl.keyStore.Password).asOption[String]
      } yield {
        val storeType = session(ConfigKeys.http.ssl.keyStore.Type).asOption[String]
        val algorithm = session(ConfigKeys.http.ssl.keyStore.Algorithm).asOption[String]
        newKeyManagerFactory(storeType, file, password, algorithm)
      }

      val trustManagerFactory = for {
        file <- session(ConfigKeys.http.ssl.trustStore.File).asOption[String]
        password <- session(ConfigKeys.http.ssl.trustStore.Password).asOption[String]
      } yield {
        val storeType = session(ConfigKeys.http.ssl.trustStore.Type).asOption[String]
        val algorithm = session(ConfigKeys.http.ssl.trustStore.Algorithm).asOption[String]
        newTrustManagerFactory(storeType, file, password, algorithm)
      }

      trustManagerFactory.orElse(keyManagerFactory).map { _ =>
        logger.info(s"Setting a custom SslContext for user ${session.userId}")
        new DefaultAsyncHttpClientConfig.Builder(defaultAhcConfig).setSslContext(ahcConfig, keyManagerFactory, trustManagerFactory).build
      }

    }.getOrElse(defaultAhcConfig)

    val client = new DefaultAsyncHttpClient(config)
    system.registerOnTermination(client.close())
    client
  }

  def newNameResolver(): ExtendedDnsNameResolver = {
    val executor = newEventLoopGroup("gatling-dns-thread")
    val resolver = new ExtendedDnsNameResolver(executor.next(), configuration)
    system.registerOnTermination(resolver.close())
    resolver
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy