diff --git a/core/src/main/scalajvm/sttp/client3/HttpClientAsyncBackend.scala b/core/src/main/scalajvm/sttp/client3/HttpClientAsyncBackend.scala index cc9e4c41e9..d34176cb96 100644 --- a/core/src/main/scalajvm/sttp/client3/HttpClientAsyncBackend.scala +++ b/core/src/main/scalajvm/sttp/client3/HttpClientAsyncBackend.scala @@ -54,7 +54,12 @@ abstract class HttpClientAsyncBackend[F[_], S, P, BH, B]( val consumer = toJavaBiConsumer((t: HttpResponse[BH], u: Throwable) => { if (t != null) { - try success(readResponse(t, Left(bodyHandlerBodyToBody(t.body())), request)) + // sometimes body returned by HttpClient can be null, we handle this by returning empty body to prevent NPE + val body = Option(t.body()) + .map(bodyHandlerBodyToBody) + .getOrElse(emptyBody()) + + try success(readResponse(t, Left(body), request)) catch { case e: Exception => error(e) } diff --git a/core/src/main/scalajvm/sttp/client3/HttpClientBackend.scala b/core/src/main/scalajvm/sttp/client3/HttpClientBackend.scala index 7b0b37cebb..d93ee8ccd1 100644 --- a/core/src/main/scalajvm/sttp/client3/HttpClientBackend.scala +++ b/core/src/main/scalajvm/sttp/client3/HttpClientBackend.scala @@ -10,6 +10,7 @@ import sttp.monad.MonadError import sttp.monad.syntax._ import sttp.ws.WebSocket +import java.net.Authenticator.RequestorType import java.net.http.{HttpClient, HttpRequest, HttpResponse} import java.net.{Authenticator, PasswordAuthentication} import java.time.{Duration => JDuration} @@ -123,10 +124,12 @@ abstract class HttpClientBackend[F[_], S, P, B]( object HttpClientBackend { type EncodingHandler[B] = PartialFunction[(B, String), B] - // TODO not sure if it works + private class ProxyAuthenticator(auth: SttpBackendOptions.ProxyAuth) extends Authenticator { override def getPasswordAuthentication: PasswordAuthentication = { - new PasswordAuthentication(auth.username, auth.password.toCharArray) + if (getRequestorType == RequestorType.PROXY) { + new PasswordAuthentication(auth.username, auth.password.toCharArray) + } else null } } diff --git a/docs/conf/proxy.md b/docs/conf/proxy.md index e4b1272edc..01c3d01bf1 100644 --- a/docs/conf/proxy.md +++ b/docs/conf/proxy.md @@ -31,6 +31,16 @@ import sttp.client3._ SttpBackendOptions.httpProxy("some.host", 8080, "username", "password") ``` +if you use a HttpClient-based backend (e.g. `HttpClientBackend`) and your proxy server requires Basic authentication, you will need to enable it by +removing Basic from the `jdk.http.auth.tunneling.disabledSchemes` networking property, or by setting a system property of the same name to "". + +```scala mdoc:compile-only +System.setProperty("jdk.http.auth.tunneling.disabledSchemes", "") +``` + +Please be aware that enabling Basic authentication for HTTP tunneling can expose your credentials to interception, so it +should only be done if you understand the risks and your network is secure. This behaviour is described in https://www.oracle.com/java/technologies/javase/8u111-relnotes.html. + ## Ignoring and allowing specific hosts There are two additional settings that can be provided to via `SttpBackendOptions`: