From bb7abc189d9a5f079caa47a4508b5ae585dc8bcf Mon Sep 17 00:00:00 2001 From: adamw Date: Fri, 6 Oct 2017 14:19:44 +0200 Subject: #10: add proxy support --- README.md | 20 +++++++++- .../sttp/akkahttp/AkkaHttpBackend.scala | 33 +++++++++------- .../cats/AsyncHttpClientCatsBackend.scala | 11 +++--- .../fs2/AsyncHttpClientFs2Backend.scala | 11 +++--- .../future/AsyncHttpClientFutureBackend.scala | 16 ++++---- .../monix/AsyncHttpClientMonixBackend.scala | 10 ++--- .../scalaz/AsyncHttpClientScalazBackend.scala | 12 +++--- .../asynchttpclient/AsyncHttpClientBackend.scala | 23 +++++++---- .../sttp/HttpURLConnectionBackend.scala | 27 ++++++++----- .../scala/com/softwaremill/sttp/SttpBackend.scala | 5 --- .../com/softwaremill/sttp/SttpBackendOptions.scala | 45 ++++++++++++++++++++++ .../sttp/okhttp/monix/OkHttpMonixBackend.scala | 9 ++--- .../sttp/okhttp/OkHttpClientHandler.scala | 36 +++++++++-------- 13 files changed, 170 insertions(+), 88 deletions(-) create mode 100644 core/src/main/scala/com/softwaremill/sttp/SttpBackendOptions.scala diff --git a/README.md b/README.md index 2429332..f998283 100644 --- a/README.md +++ b/README.md @@ -489,8 +489,9 @@ How to use: import com.softwaremill.sttp._ import scala.concurrent.duration._ -// all backends provide a constructor that allows users to specify connection timeout -implicit val backend = HttpURLConnectionBackend(connectionTimeout = 1.minute) +// all backends provide a constructor that allows users to specify backend options +implicit val backend = HttpURLConnectionBackend( + options = SttpBackendOptions.connectionTimeout(1.minute)) sttp .get(uri"...") @@ -498,6 +499,21 @@ sttp .send() ``` +## Proxy + +A proxy can be specified when creating a backend: + +```scala +import com.softwaremill.sttp._ + +implicit val backend = HttpURLConnectionBackend( + options = SttpBackendOptions.httpProxy("some.host", 8080)) + +sttp + .get(uri"...") + .send() // uses the proxy +``` + ## SSL SSL handling can be customized (or disabled) when creating a backend and is diff --git a/akka-http-backend/src/main/scala/com/softwaremill/sttp/akkahttp/AkkaHttpBackend.scala b/akka-http-backend/src/main/scala/com/softwaremill/sttp/akkahttp/AkkaHttpBackend.scala index 897692c..373c970 100644 --- a/akka-http-backend/src/main/scala/com/softwaremill/sttp/akkahttp/AkkaHttpBackend.scala +++ b/akka-http-backend/src/main/scala/com/softwaremill/sttp/akkahttp/AkkaHttpBackend.scala @@ -1,10 +1,11 @@ package com.softwaremill.sttp.akkahttp import java.io.{File, IOException, UnsupportedEncodingException} +import java.net.InetSocketAddress import akka.actor.ActorSystem import akka.event.LoggingAdapter -import akka.http.scaladsl.{Http, HttpsConnectionContext} +import akka.http.scaladsl.{ClientTransport, Http, HttpsConnectionContext} import akka.http.scaladsl.coding.{Deflate, Gzip, NoCoding} import akka.http.scaladsl.model.ContentTypes.`application/octet-stream` import akka.http.scaladsl.model.HttpHeader.ParsingResult @@ -30,7 +31,7 @@ class AkkaHttpBackend private ( actorSystem: ActorSystem, ec: ExecutionContext, terminateActorSystemOnClose: Boolean, - connectionTimeout: FiniteDuration, + opts: SttpBackendOptions, customHttpsContext: Option[HttpsConnectionContext], customConnectionPoolSettings: Option[ConnectionPoolSettings], customLog: Option[LoggingAdapter]) @@ -45,10 +46,17 @@ class AkkaHttpBackend private ( private val http = Http() private val connectionSettings = ClientConnectionSettings(actorSystem) - .withConnectingTimeout(connectionTimeout) - - private val connectionPoolSettings = - customConnectionPoolSettings.getOrElse(ConnectionPoolSettings(actorSystem)) + .withConnectingTimeout(opts.connectionTimeout) + + private val connectionPoolSettings = { + val base = customConnectionPoolSettings.getOrElse( + ConnectionPoolSettings(actorSystem)) + opts.proxy match { + case None => base + case Some(p) => + base.withTransport(ClientTransport.httpsProxy(p.inetSocketAddress)) + } + } override def send[T](r: Request[T, S]): Future[Response[T]] = { implicit val ec: ExecutionContext = this.ec @@ -300,7 +308,7 @@ object AkkaHttpBackend { actorSystem: ActorSystem, ec: ExecutionContext, terminateActorSystemOnClose: Boolean, - connectionTimeout: FiniteDuration, + options: SttpBackendOptions, customHttpsContext: Option[HttpsConnectionContext], customConnectionPoolSettings: Option[ConnectionPoolSettings], customLog: Option[LoggingAdapter]) @@ -309,7 +317,7 @@ object AkkaHttpBackend { new AkkaHttpBackend(actorSystem, ec, terminateActorSystemOnClose, - connectionTimeout, + options, customHttpsContext, customConnectionPoolSettings, customLog)) @@ -319,8 +327,7 @@ object AkkaHttpBackend { * e.g. mapping responses. Defaults to the global execution * context. */ - def apply(connectionTimeout: FiniteDuration = - SttpBackend.DefaultConnectionTimeout, + def apply(options: SttpBackendOptions = SttpBackendOptions.Default, customHttpsContext: Option[HttpsConnectionContext] = None, customConnectionPoolSettings: Option[ConnectionPoolSettings] = None, customLog: Option[LoggingAdapter] = None)( @@ -329,7 +336,7 @@ object AkkaHttpBackend { AkkaHttpBackend(ActorSystem("sttp"), ec, terminateActorSystemOnClose = true, - connectionTimeout, + options, customHttpsContext, customConnectionPoolSettings, customLog) @@ -343,7 +350,7 @@ object AkkaHttpBackend { */ def usingActorSystem( actorSystem: ActorSystem, - connectionTimeout: FiniteDuration = SttpBackend.DefaultConnectionTimeout, + options: SttpBackendOptions = SttpBackendOptions.Default, customHttpsContext: Option[HttpsConnectionContext] = None, customConnectionPoolSettings: Option[ConnectionPoolSettings] = None, customLog: Option[LoggingAdapter] = None)( @@ -352,7 +359,7 @@ object AkkaHttpBackend { AkkaHttpBackend(actorSystem, ec, terminateActorSystemOnClose = false, - connectionTimeout, + options, customHttpsContext, customConnectionPoolSettings, customLog) diff --git a/async-http-client-backend/cats/src/main/scala/com/softwaremill/sttp/asynchttpclient/cats/AsyncHttpClientCatsBackend.scala b/async-http-client-backend/cats/src/main/scala/com/softwaremill/sttp/asynchttpclient/cats/AsyncHttpClientCatsBackend.scala index b5beb75..a38e08b 100644 --- a/async-http-client-backend/cats/src/main/scala/com/softwaremill/sttp/asynchttpclient/cats/AsyncHttpClientCatsBackend.scala +++ b/async-http-client-backend/cats/src/main/scala/com/softwaremill/sttp/asynchttpclient/cats/AsyncHttpClientCatsBackend.scala @@ -7,7 +7,8 @@ import com.softwaremill.sttp.asynchttpclient.AsyncHttpClientBackend import com.softwaremill.sttp.{ FollowRedirectsBackend, MonadAsyncError, - SttpBackend + SttpBackend, + SttpBackendOptions } import org.asynchttpclient.{ AsyncHttpClient, @@ -16,7 +17,6 @@ import org.asynchttpclient.{ } import org.reactivestreams.Publisher -import scala.concurrent.duration.FiniteDuration import scala.language.higherKinds class AsyncHttpClientCatsBackend[F[_]: Async] private ( @@ -48,11 +48,10 @@ object AsyncHttpClientCatsBackend { new AsyncHttpClientCatsBackend(asyncHttpClient, closeClient)) def apply[F[_]: Async]( - connectionTimeout: FiniteDuration = SttpBackend.DefaultConnectionTimeout) + options: SttpBackendOptions = SttpBackendOptions.Default) : SttpBackend[F, Nothing] = - AsyncHttpClientCatsBackend( - AsyncHttpClientBackend.defaultClient(connectionTimeout.toMillis.toInt), - closeClient = true) + AsyncHttpClientCatsBackend(AsyncHttpClientBackend.defaultClient(options), + closeClient = true) def usingConfig[F[_]: Async]( cfg: AsyncHttpClientConfig): SttpBackend[F, Nothing] = diff --git a/async-http-client-backend/fs2/src/main/scala/com/softwaremill/sttp/asynchttpclient/fs2/AsyncHttpClientFs2Backend.scala b/async-http-client-backend/fs2/src/main/scala/com/softwaremill/sttp/asynchttpclient/fs2/AsyncHttpClientFs2Backend.scala index 90db69c..4dfc1da 100644 --- a/async-http-client-backend/fs2/src/main/scala/com/softwaremill/sttp/asynchttpclient/fs2/AsyncHttpClientFs2Backend.scala +++ b/async-http-client-backend/fs2/src/main/scala/com/softwaremill/sttp/asynchttpclient/fs2/AsyncHttpClientFs2Backend.scala @@ -8,6 +8,7 @@ import com.softwaremill.sttp.{ FollowRedirectsBackend, MonadAsyncError, SttpBackend, + SttpBackendOptions, Utf8, concatByteBuffers } @@ -21,7 +22,6 @@ import org.asynchttpclient.{ import org.reactivestreams.Publisher import scala.concurrent.ExecutionContext -import scala.concurrent.duration.FiniteDuration import scala.language.higherKinds class AsyncHttpClientFs2Backend[F[_]: Effect] private ( @@ -64,13 +64,12 @@ object AsyncHttpClientFs2Backend { * e.g. mapping responses. Defaults to the global execution * context. */ - def apply[F[_]: Effect](connectionTimeout: FiniteDuration = - SttpBackend.DefaultConnectionTimeout)( + def apply[F[_]: Effect](options: SttpBackendOptions = + SttpBackendOptions.Default)( implicit ec: ExecutionContext = ExecutionContext.Implicits.global) : SttpBackend[F, Stream[F, ByteBuffer]] = - AsyncHttpClientFs2Backend[F]( - AsyncHttpClientBackend.defaultClient(connectionTimeout.toMillis.toInt), - closeClient = true) + AsyncHttpClientFs2Backend[F](AsyncHttpClientBackend.defaultClient(options), + closeClient = true) /** * @param ec The execution context for running non-network related operations, diff --git a/async-http-client-backend/future/src/main/scala/com/softwaremill/sttp/asynchttpclient/future/AsyncHttpClientFutureBackend.scala b/async-http-client-backend/future/src/main/scala/com/softwaremill/sttp/asynchttpclient/future/AsyncHttpClientFutureBackend.scala index a46ed0d..6778fa0 100644 --- a/async-http-client-backend/future/src/main/scala/com/softwaremill/sttp/asynchttpclient/future/AsyncHttpClientFutureBackend.scala +++ b/async-http-client-backend/future/src/main/scala/com/softwaremill/sttp/asynchttpclient/future/AsyncHttpClientFutureBackend.scala @@ -3,7 +3,12 @@ package com.softwaremill.sttp.asynchttpclient.future import java.nio.ByteBuffer import com.softwaremill.sttp.asynchttpclient.AsyncHttpClientBackend -import com.softwaremill.sttp.{FollowRedirectsBackend, FutureMonad, SttpBackend} +import com.softwaremill.sttp.{ + FollowRedirectsBackend, + FutureMonad, + SttpBackend, + SttpBackendOptions +} import org.asynchttpclient.{ AsyncHttpClient, AsyncHttpClientConfig, @@ -11,7 +16,6 @@ import org.asynchttpclient.{ } import org.reactivestreams.Publisher -import scala.concurrent.duration.FiniteDuration import scala.concurrent.{ExecutionContext, Future} class AsyncHttpClientFutureBackend private ( @@ -45,13 +49,11 @@ object AsyncHttpClientFutureBackend { * e.g. mapping responses. Defaults to the global execution * context. */ - def apply(connectionTimeout: FiniteDuration = - SttpBackend.DefaultConnectionTimeout)( + def apply(options: SttpBackendOptions = SttpBackendOptions.Default)( implicit ec: ExecutionContext = ExecutionContext.Implicits.global) : SttpBackend[Future, Nothing] = - AsyncHttpClientFutureBackend( - AsyncHttpClientBackend.defaultClient(connectionTimeout.toMillis.toInt), - closeClient = true) + AsyncHttpClientFutureBackend(AsyncHttpClientBackend.defaultClient(options), + closeClient = true) /** * @param ec The execution context for running non-network related operations, diff --git a/async-http-client-backend/monix/src/main/scala/com/softwaremill/sttp/asynchttpclient/monix/AsyncHttpClientMonixBackend.scala b/async-http-client-backend/monix/src/main/scala/com/softwaremill/sttp/asynchttpclient/monix/AsyncHttpClientMonixBackend.scala index c08c244..9cb44f2 100644 --- a/async-http-client-backend/monix/src/main/scala/com/softwaremill/sttp/asynchttpclient/monix/AsyncHttpClientMonixBackend.scala +++ b/async-http-client-backend/monix/src/main/scala/com/softwaremill/sttp/asynchttpclient/monix/AsyncHttpClientMonixBackend.scala @@ -6,6 +6,7 @@ import com.softwaremill.sttp.{ FollowRedirectsBackend, MonadAsyncError, SttpBackend, + SttpBackendOptions, Utf8, concatByteBuffers } @@ -20,7 +21,6 @@ import org.asynchttpclient.{ } import org.reactivestreams.Publisher -import scala.concurrent.duration.FiniteDuration import scala.util.{Failure, Success} class AsyncHttpClientMonixBackend private ( @@ -62,13 +62,11 @@ object AsyncHttpClientMonixBackend { * @param s The scheduler used for streaming request bodies. Defaults to the * global scheduler. */ - def apply(connectionTimeout: FiniteDuration = - SttpBackend.DefaultConnectionTimeout)( + def apply(options: SttpBackendOptions = SttpBackendOptions.Default)( implicit s: Scheduler = Scheduler.Implicits.global) : SttpBackend[Task, Observable[ByteBuffer]] = - AsyncHttpClientMonixBackend( - AsyncHttpClientBackend.defaultClient(connectionTimeout.toMillis.toInt), - closeClient = true) + AsyncHttpClientMonixBackend(AsyncHttpClientBackend.defaultClient(options), + closeClient = true) /** * @param s The scheduler used for streaming request bodies. Defaults to the diff --git a/async-http-client-backend/scalaz/src/main/scala/com/softwaremill/sttp/asynchttpclient/scalaz/AsyncHttpClientScalazBackend.scala b/async-http-client-backend/scalaz/src/main/scala/com/softwaremill/sttp/asynchttpclient/scalaz/AsyncHttpClientScalazBackend.scala index 12e217b..57e9577 100644 --- a/async-http-client-backend/scalaz/src/main/scala/com/softwaremill/sttp/asynchttpclient/scalaz/AsyncHttpClientScalazBackend.scala +++ b/async-http-client-backend/scalaz/src/main/scala/com/softwaremill/sttp/asynchttpclient/scalaz/AsyncHttpClientScalazBackend.scala @@ -5,7 +5,8 @@ import java.nio.ByteBuffer import com.softwaremill.sttp.{ FollowRedirectsBackend, MonadAsyncError, - SttpBackend + SttpBackend, + SttpBackendOptions } import com.softwaremill.sttp.asynchttpclient.AsyncHttpClientBackend import org.asynchttpclient.{ @@ -15,7 +16,6 @@ import org.asynchttpclient.{ } import org.reactivestreams.Publisher -import scala.concurrent.duration.FiniteDuration import scalaz.{-\/, \/-} import scalaz.concurrent.Task @@ -43,12 +43,10 @@ object AsyncHttpClientScalazBackend { new FollowRedirectsBackend[Task, Nothing]( new AsyncHttpClientScalazBackend(asyncHttpClient, closeClient)) - def apply( - connectionTimeout: FiniteDuration = SttpBackend.DefaultConnectionTimeout) + def apply(options: SttpBackendOptions = SttpBackendOptions.Default) : SttpBackend[Task, Nothing] = - AsyncHttpClientScalazBackend( - AsyncHttpClientBackend.defaultClient(connectionTimeout.toMillis.toInt), - closeClient = true) + AsyncHttpClientScalazBackend(AsyncHttpClientBackend.defaultClient(options), + closeClient = true) def usingConfig(cfg: AsyncHttpClientConfig): SttpBackend[Task, Nothing] = AsyncHttpClientScalazBackend(new DefaultAsyncHttpClient(cfg), diff --git a/async-http-client-backend/src/main/scala/com/softwaremill/sttp/asynchttpclient/AsyncHttpClientBackend.scala b/async-http-client-backend/src/main/scala/com/softwaremill/sttp/asynchttpclient/AsyncHttpClientBackend.scala index 87a3965..a19dc1a 100644 --- a/async-http-client-backend/src/main/scala/com/softwaremill/sttp/asynchttpclient/AsyncHttpClientBackend.scala +++ b/async-http-client-backend/src/main/scala/com/softwaremill/sttp/asynchttpclient/AsyncHttpClientBackend.scala @@ -8,6 +8,7 @@ import com.softwaremill.sttp.ResponseAs.EagerResponseHandler import com.softwaremill.sttp._ import org.asynchttpclient.AsyncHandler.State import org.asynchttpclient.handler.StreamedAsyncHandler +import org.asynchttpclient.proxy.ProxyServer import org.asynchttpclient.request.body.multipart.{ ByteArrayPart, FilePart, @@ -17,8 +18,8 @@ import org.asynchttpclient.{ AsyncCompletionHandler, AsyncHandler, AsyncHttpClient, - DefaultAsyncHttpClientConfig, DefaultAsyncHttpClient, + DefaultAsyncHttpClientConfig, HttpResponseBodyPart, HttpResponseHeaders, HttpResponseStatus, @@ -298,12 +299,20 @@ abstract class AsyncHttpClientBackend[R[_], S](asyncHttpClient: AsyncHttpClient, object AsyncHttpClientBackend { private[asynchttpclient] def defaultClient( - connectionTimeout: Int): AsyncHttpClient = - new DefaultAsyncHttpClient( - new DefaultAsyncHttpClientConfig.Builder() - .setConnectTimeout(connectionTimeout) - .build() - ) + options: SttpBackendOptions): AsyncHttpClient = { + + var configBuilder = new DefaultAsyncHttpClientConfig.Builder() + .setConnectTimeout(options.connectionTimeout.toMillis.toInt) + + configBuilder = options.proxy match { + case None => configBuilder + case Some(p) => + configBuilder.setProxyServer( + new ProxyServer.Builder(p.host, p.port).build()) + } + + new DefaultAsyncHttpClient(configBuilder.build()) + } } object EmptyPublisher extends Publisher[ByteBuffer] { diff --git a/core/src/main/scala/com/softwaremill/sttp/HttpURLConnectionBackend.scala b/core/src/main/scala/com/softwaremill/sttp/HttpURLConnectionBackend.scala index 7e87795..3d6921b 100644 --- a/core/src/main/scala/com/softwaremill/sttp/HttpURLConnectionBackend.scala +++ b/core/src/main/scala/com/softwaremill/sttp/HttpURLConnectionBackend.scala @@ -9,22 +9,21 @@ import java.util.concurrent.ThreadLocalRandom import java.util.zip.{GZIPInputStream, InflaterInputStream} import scala.annotation.tailrec -import scala.io.Source import scala.collection.JavaConverters._ -import scala.concurrent.duration.{Duration, FiniteDuration} +import scala.concurrent.duration.Duration +import scala.io.Source class HttpURLConnectionBackend private ( - connectionTimeout: FiniteDuration, + opts: SttpBackendOptions, customizeConnection: HttpURLConnection => Unit) extends SttpBackend[Id, Nothing] { override def send[T](r: Request[T, Nothing]): Response[T] = { - val c = - new URL(r.uri.toString).openConnection().asInstanceOf[HttpURLConnection] + val c = openConnection(r.uri) c.setRequestMethod(r.method.m) r.headers.foreach { case (k, v) => c.setRequestProperty(k, v) } c.setDoInput(true) c.setReadTimeout(timeout(r.options.readTimeout)) - c.setConnectTimeout(timeout(connectionTimeout)) + c.setConnectTimeout(timeout(opts.connectionTimeout)) // redirects are handled by FollowRedirectsBackend c.setInstanceFollowRedirects(false) @@ -55,6 +54,17 @@ class HttpURLConnectionBackend private ( override def responseMonad: MonadError[Id] = IdMonad + private def openConnection(uri: Uri): HttpURLConnection = { + val url = new URL(uri.toString) + val conn = opts.proxy match { + case None => url.openConnection() + case Some(p) => + url.openConnection(p.asJava) + } + + conn.asInstanceOf[HttpURLConnection] + } + private def writeBody(body: RequestBody[Nothing], c: HttpURLConnection): Option[OutputStream] = { body match { @@ -268,11 +278,10 @@ class HttpURLConnectionBackend private ( object HttpURLConnectionBackend { - def apply(connectionTimeout: FiniteDuration = - SttpBackend.DefaultConnectionTimeout, + def apply(options: SttpBackendOptions = SttpBackendOptions.Default, customizeConnection: HttpURLConnection => Unit = { _ => () }): SttpBackend[Id, Nothing] = new FollowRedirectsBackend[Id, Nothing]( - new HttpURLConnectionBackend(connectionTimeout, customizeConnection)) + new HttpURLConnectionBackend(options, customizeConnection)) } diff --git a/core/src/main/scala/com/softwaremill/sttp/SttpBackend.scala b/core/src/main/scala/com/softwaremill/sttp/SttpBackend.scala index 6eb312f..e3d5399 100644 --- a/core/src/main/scala/com/softwaremill/sttp/SttpBackend.scala +++ b/core/src/main/scala/com/softwaremill/sttp/SttpBackend.scala @@ -1,7 +1,6 @@ package com.softwaremill.sttp import scala.language.higherKinds -import scala.concurrent.duration._ /** * @tparam R The type constructor in which responses are wrapped. E.g. `Id` @@ -20,7 +19,3 @@ trait SttpBackend[R[_], -S] { */ def responseMonad: MonadError[R] } - -object SttpBackend { - private[sttp] val DefaultConnectionTimeout = 30.seconds -} diff --git a/core/src/main/scala/com/softwaremill/sttp/SttpBackendOptions.scala b/core/src/main/scala/com/softwaremill/sttp/SttpBackendOptions.scala new file mode 100644 index 0000000..e515173 --- /dev/null +++ b/core/src/main/scala/com/softwaremill/sttp/SttpBackendOptions.scala @@ -0,0 +1,45 @@ +package com.softwaremill.sttp + +import java.net.InetSocketAddress + +import scala.concurrent.duration._ +import com.softwaremill.sttp.SttpBackendOptions._ + +case class SttpBackendOptions( + connectionTimeout: FiniteDuration, + proxy: Option[Proxy] +) { + + def connectionTimeout(ct: FiniteDuration): SttpBackendOptions = + this.copy(connectionTimeout = ct) + def httpProxy(host: String, port: Int): SttpBackendOptions = + this.copy(proxy = Some(Proxy(host, port, ProxyType.Http))) + def socksProxy(host: String, port: Int): SttpBackendOptions = + this.copy(proxy = Some(Proxy(host, port, ProxyType.Socks))) +} + +object SttpBackendOptions { + case class Proxy(host: String, port: Int, proxyType: ProxyType) { + def asJava = new java.net.Proxy(proxyType.asJava, inetSocketAddress) + def inetSocketAddress: InetSocketAddress = + InetSocketAddress.createUnresolved(host, port) + } + + sealed trait ProxyType { + def asJava: java.net.Proxy.Type + } + object ProxyType { + case object Http extends ProxyType { + override def asJava: java.net.Proxy.Type = java.net.Proxy.Type.HTTP + } + case object Socks extends ProxyType { + override def asJava: java.net.Proxy.Type = java.net.Proxy.Type.SOCKS + } + } + + val Default: SttpBackendOptions = SttpBackendOptions(30.seconds, None) + + def connectionTimeout(ct: FiniteDuration): SttpBackendOptions = Default.connectionTimeout(ct) + def httpProxy(host: String, port: Int): SttpBackendOptions = Default.httpProxy(host, port) + def socksProxy(host: String, port: Int): SttpBackendOptions = Default.socksProxy(host, port) +} diff --git a/okhttp-backend/monix/src/main/scala/com/softwaremill/sttp/okhttp/monix/OkHttpMonixBackend.scala b/okhttp-backend/monix/src/main/scala/com/softwaremill/sttp/okhttp/monix/OkHttpMonixBackend.scala index 4b24e65..db36f32 100644 --- a/okhttp-backend/monix/src/main/scala/com/softwaremill/sttp/okhttp/monix/OkHttpMonixBackend.scala +++ b/okhttp-backend/monix/src/main/scala/com/softwaremill/sttp/okhttp/monix/OkHttpMonixBackend.scala @@ -85,13 +85,12 @@ object OkHttpMonixBackend { implicit s: Scheduler): SttpBackend[Task, Observable[ByteBuffer]] = new FollowRedirectsBackend(new OkHttpMonixBackend(client, closeClient)(s)) - def apply(connectionTimeout: FiniteDuration = - SttpBackend.DefaultConnectionTimeout)( + def apply(options: SttpBackendOptions = SttpBackendOptions.Default)( implicit s: Scheduler = Scheduler.Implicits.global) : SttpBackend[Task, Observable[ByteBuffer]] = - OkHttpMonixBackend(OkHttpBackend.defaultClient(DefaultReadTimeout.toMillis, - connectionTimeout.toMillis), - closeClient = true)(s) + OkHttpMonixBackend( + OkHttpBackend.defaultClient(DefaultReadTimeout.toMillis, options), + closeClient = true)(s) def usingClient(client: OkHttpClient)(implicit s: Scheduler = Scheduler.Implicits.global) diff --git a/okhttp-backend/src/main/scala/com/softwaremill/sttp/okhttp/OkHttpClientHandler.scala b/okhttp-backend/src/main/scala/com/softwaremill/sttp/okhttp/OkHttpClientHandler.scala index 116878f..bebecac 100644 --- a/okhttp-backend/src/main/scala/com/softwaremill/sttp/okhttp/OkHttpClientHandler.scala +++ b/okhttp-backend/src/main/scala/com/softwaremill/sttp/okhttp/OkHttpClientHandler.scala @@ -148,14 +148,22 @@ abstract class OkHttpBackend[R[_], S](client: OkHttpClient, object OkHttpBackend { - private[okhttp] def defaultClient(readTimeout: Long, - connectionTimeout: Long): OkHttpClient = - new OkHttpClient.Builder() + private[okhttp] def defaultClient( + readTimeout: Long, + options: SttpBackendOptions): OkHttpClient = { + var clientBuilder = new OkHttpClient.Builder() .followRedirects(false) .followSslRedirects(false) - .connectTimeout(connectionTimeout, TimeUnit.MILLISECONDS) + .connectTimeout(options.connectionTimeout.toMillis, TimeUnit.MILLISECONDS) .readTimeout(readTimeout, TimeUnit.MILLISECONDS) - .build() + + clientBuilder = options.proxy match { + case None => clientBuilder + case Some(p) => clientBuilder.proxy(p.asJava) + } + + clientBuilder.build() + } private[okhttp] def updateClientIfCustomReadTimeout[T, S]( r: Request[T, S], @@ -192,12 +200,11 @@ object OkHttpSyncBackend { new FollowRedirectsBackend[Id, Nothing]( new OkHttpSyncBackend(client, closeClient)) - def apply( - connectionTimeout: FiniteDuration = SttpBackend.DefaultConnectionTimeout) + def apply(options: SttpBackendOptions = SttpBackendOptions.Default) : SttpBackend[Id, Nothing] = - OkHttpSyncBackend(OkHttpBackend.defaultClient(DefaultReadTimeout.toMillis, - connectionTimeout.toMillis), - closeClient = true) + OkHttpSyncBackend( + OkHttpBackend.defaultClient(DefaultReadTimeout.toMillis, options), + closeClient = true) def usingClient(client: OkHttpClient): SttpBackend[Id, Nothing] = OkHttpSyncBackend(client, closeClient = false) @@ -243,13 +250,12 @@ object OkHttpFutureBackend { new FollowRedirectsBackend[Future, Nothing]( new OkHttpFutureBackend(client, closeClient)) - def apply(connectionTimeout: FiniteDuration = - SttpBackend.DefaultConnectionTimeout)( + def apply(options: SttpBackendOptions = SttpBackendOptions.Default)( implicit ec: ExecutionContext = ExecutionContext.Implicits.global) : SttpBackend[Future, Nothing] = - OkHttpFutureBackend(OkHttpBackend.defaultClient(DefaultReadTimeout.toMillis, - connectionTimeout.toMillis), - closeClient = true) + OkHttpFutureBackend( + OkHttpBackend.defaultClient(DefaultReadTimeout.toMillis, options), + closeClient = true) def usingClient(client: OkHttpClient)(implicit ec: ExecutionContext = ExecutionContext.Implicits.global) -- cgit v1.2.3