
org.http4s.client.blaze.Http1Support.scala Maven / Gradle / Ivy
package org.http4s
package client
package blaze
import java.net.InetSocketAddress
import java.nio.ByteBuffer
import java.util.concurrent.ExecutorService
import org.http4s.Uri.Scheme
import org.http4s.blaze.channel.nio2.ClientChannelFactory
import org.http4s.util.task
import org.http4s.blaze.pipeline.LeafBuilder
import org.http4s.blaze.pipeline.stages.SSLStage
import org.http4s.util.CaseInsensitiveString._
import scala.concurrent.ExecutionContext
import scala.concurrent.Future
import scalaz.concurrent.Task
import scalaz.{-\/, \/, \/-}
private object Http1Support {
/** Create a new [[ConnectionBuilder]]
*
* @param config The client configuration object
*/
def apply(config: BlazeClientConfig, executor: ExecutorService): ConnectionBuilder[BlazeConnection] = {
val builder = new Http1Support(config, executor)
builder.makeClient
}
private val Https: Scheme = "https".ci
private val Http: Scheme = "http".ci
}
/** Provides basic HTTP1 pipeline building
*/
final private class Http1Support(config: BlazeClientConfig, executor: ExecutorService) {
import Http1Support._
private val ec = ExecutionContext.fromExecutorService(executor)
private val sslContext = config.sslContext.getOrElse(bits.sslContext)
private val connectionManager = new ClientChannelFactory(config.bufferSize, config.group.orNull)
////////////////////////////////////////////////////
def makeClient(requestKey: RequestKey): Task[BlazeConnection] = getAddress(requestKey) match {
case \/-(a) => task.futureToTask(buildPipeline(requestKey, a))(ec)
case -\/(t) => Task.fail(t)
}
private def buildPipeline(requestKey: RequestKey, addr: InetSocketAddress): Future[BlazeConnection] = {
connectionManager.connect(addr, config.bufferSize).map { head =>
val (builder, t) = buildStages(requestKey)
builder.base(head)
t
}(ec)
}
private def buildStages(requestKey: RequestKey): (LeafBuilder[ByteBuffer], BlazeConnection) = {
val t = new Http1Connection(requestKey, config, executor, ec)
val builder = LeafBuilder(t)
requestKey match {
case RequestKey(Https, auth) =>
val eng = sslContext.createSSLEngine(auth.host.value, auth.port getOrElse 443)
eng.setUseClientMode(true)
if (config.endpointAuthentication) {
val sslParams = eng.getSSLParameters
sslParams.setEndpointIdentificationAlgorithm("HTTPS")
eng.setSSLParameters(sslParams)
}
(builder.prepend(new SSLStage(eng)),t)
case _ => (builder, t)
}
}
private def getAddress(requestKey: RequestKey): Throwable \/ InetSocketAddress = {
requestKey match {
case RequestKey(s, auth) =>
val port = auth.port getOrElse { if (s == Https) 443 else 80 }
val host = auth.host.value
\/.fromTryCatchNonFatal(new InetSocketAddress(host, port))
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy