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

io.gatling.http.config.HttpProtocol.scala Maven / Gradle / Ivy

/**
 * Copyright 2011-2014 eBusiness Information, Groupe Excilys (www.ebusinessinformation.fr)
 *
 * 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.config

import java.net.InetAddress
import java.util.regex.Pattern

import scala.collection.mutable

import com.ning.http.client._
import com.ning.http.client.providers.netty.NettyAsyncHttpProvider
import com.ning.http.client.providers.netty.channel.pool.ChannelPoolPartitionSelector
import com.typesafe.scalalogging.StrictLogging

import io.gatling.core.akka.GatlingActorSystem
import io.gatling.core.config.GatlingConfiguration.configuration
import io.gatling.core.config.Protocol
import io.gatling.core.filter.Filters
import io.gatling.core.session.{ Session, Expression, ExpressionWrapper }
import io.gatling.core.util.RoundRobin
import io.gatling.http.HeaderNames._
import io.gatling.http.ahc.{ ChannelPoolPartitioning, AsyncHandlerActor, HttpEngine }
import io.gatling.http.check.HttpCheck
import io.gatling.http.request.ExtraInfoExtractor
import io.gatling.http.request.builder.Http
import io.gatling.http.response.Response

/**
 * HttpProtocol class companion
 */
object HttpProtocol {

  val DefaultHttpProtocol = HttpProtocol(
    baseURLs = Nil,
    warmUpUrl = configuration.http.warmUpUrl,
    enginePart = HttpProtocolEnginePart(
      shareClient = true,
      shareConnections = false,
      maxConnectionsPerHost = 6,
      virtualHost = None,
      localAddress = None),
    requestPart = HttpProtocolRequestPart(
      headers = Map.empty,
      realm = None,
      autoReferer = true,
      cache = true,
      disableUrlEncoding = false,
      silentResources = false,
      silentURI = None,
      signatureCalculator = None),
    responsePart = HttpProtocolResponsePart(
      followRedirect = true,
      maxRedirects = None,
      strict302Handling = false,
      discardResponseChunks = true,
      responseTransformer = None,
      checks = Nil,
      extraInfoExtractor = None,
      inferHtmlResources = false,
      htmlResourcesInferringFilters = None),
    wsPart = HttpProtocolWsPart(
      wsBaseURLs = Nil,
      reconnect = false,
      maxReconnects = None),
    proxyPart = HttpProtocolProxyPart(
      proxies = None,
      proxyExceptions = Nil))

  val WarmUpUrls = mutable.Set.empty[String]

  GatlingActorSystem.instanceOpt.foreach(_.registerOnTermination(WarmUpUrls.clear()))

  def nextBaseUrlF(urls: List[String]): () => Option[String] =
    urls match {
      case Nil => () => None
      case url :: Nil => () => Some(url)
      case _ =>
        val roundRobinUrls = RoundRobin(urls.map(Some(_)).toVector)
        () => roundRobinUrls.next()
    }
}

/**
 * Class containing the configuration for the HTTP protocol
 *
 * @param baseURLs the radixes of all the URLs that will be used (eg: http://mywebsite.tld)
 * @param warmUpUrl the url used to load the TCP stack
 * @param enginePart the HTTP engine related configuration
 * @param requestPart the request related configuration
 * @param responsePart the response related configuration
 * @param wsPart the WebSocket related configuration
 * @param proxyPart the Proxy related configuration
 */
case class HttpProtocol(
    baseURLs: List[String],
    warmUpUrl: Option[String],
    enginePart: HttpProtocolEnginePart,
    requestPart: HttpProtocolRequestPart,
    responsePart: HttpProtocolResponsePart,
    wsPart: HttpProtocolWsPart,
    proxyPart: HttpProtocolProxyPart) extends Protocol with StrictLogging {

  import HttpProtocol._

  private val baseURLF = nextBaseUrlF(baseURLs)
  def baseURL: Option[String] = baseURLF()

  override def warmUp(): Unit = {

    logger.info("Start warm up")

    HttpEngine.start()
    AsyncHandlerActor.start()

    warmUpUrl.map { url =>
      if (!WarmUpUrls.contains(url)) {
        WarmUpUrls += url
        val requestBuilder = new RequestBuilder().setUrl(url)
          .setHeader(Accept, "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8")
          .setHeader(AcceptLanguage, "en-US,en;q=0.5")
          .setHeader(AcceptEncoding, "gzip")
          .setHeader(Connection, "keep-alive")
          .setHeader(UserAgent, "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0")
          .setRequestTimeout(2000)

        proxyPart.proxies.foreach {
          case (httpProxy, httpsProxy) =>
            val proxy = if (url.startsWith("https")) httpsProxy else httpProxy
            requestBuilder.setProxyServer(proxy)
        }

        try {
          HttpEngine.instance.DefaultAHC.executeRequest(requestBuilder.build).get
        } catch {
          case e: Exception => logger.info(s"Couldn't execute warm up request $url", e)
        }
      }
    }

    if (WarmUpUrls.isEmpty) {
      val expression = "foo".expression

      new Http(expression)
        .get(expression)
        .header("bar", expression)
        .queryParam(expression, expression)
        .build(DefaultHttpProtocol, throttled = false)

      new Http(expression)
        .post(expression)
        .header("bar", expression)
        .formParam(expression, expression)
        .build(DefaultHttpProtocol, throttled = false)
    }

    logger.info("Warm up done")
  }

  override def userEnd(session: Session): Unit = {
    val (_, ahc) = HttpEngine.instance.httpClient(session, this)
    ahc.getProvider.asInstanceOf[NettyAsyncHttpProvider].flushChannelPoolPartitions(new ChannelPoolPartitionSelector() {

      val userBase = ChannelPoolPartitioning.partitionIdUserBase(session)

      override def select(partitionId: Object): Boolean = partitionId.asInstanceOf[String].startsWith(userBase)
    })
  }
}

case class HttpProtocolEnginePart(
  shareClient: Boolean,
  shareConnections: Boolean,
  maxConnectionsPerHost: Int,
  virtualHost: Option[Expression[String]],
  localAddress: Option[InetAddress])

case class HttpProtocolRequestPart(
  headers: Map[String, Expression[String]],
  realm: Option[Expression[Realm]],
  autoReferer: Boolean,
  cache: Boolean,
  disableUrlEncoding: Boolean,
  silentURI: Option[Pattern],
  silentResources: Boolean,
  signatureCalculator: Option[Expression[SignatureCalculator]])

case class HttpProtocolResponsePart(
  followRedirect: Boolean,
  maxRedirects: Option[Int],
  strict302Handling: Boolean,
  discardResponseChunks: Boolean,
  responseTransformer: Option[PartialFunction[Response, Response]],
  checks: List[HttpCheck],
  extraInfoExtractor: Option[ExtraInfoExtractor],
  inferHtmlResources: Boolean,
  htmlResourcesInferringFilters: Option[Filters])

case class HttpProtocolWsPart(
    wsBaseURLs: List[String],
    reconnect: Boolean,
    maxReconnects: Option[Int]) {

  import HttpProtocol._

  private val wsBaseURLF = nextBaseUrlF(wsBaseURLs)
  def wsBaseURL: Option[String] = wsBaseURLF()
}

case class HttpProtocolProxyPart(
  proxies: Option[(ProxyServer, ProxyServer)],
  proxyExceptions: Seq[String])




© 2015 - 2025 Weber Informatics LLC | Privacy Policy