- */
-
-package play.libs.oauth;
-
-import play.shaded.oauth.oauth.signpost.OAuthConsumer;
-import play.shaded.oauth.oauth.signpost.OAuthProvider;
-import play.shaded.oauth.oauth.signpost.basic.DefaultOAuthConsumer;
-import play.shaded.oauth.oauth.signpost.basic.DefaultOAuthProvider;
-import play.shaded.oauth.oauth.signpost.exception.OAuthException;
-import play.shaded.ahc.org.asynchttpclient.oauth.OAuthSignatureCalculator;
-import play.libs.ws.WSSignatureCalculator;
-
-public class OAuth {
-
- private ServiceInfo info;
- private OAuthProvider provider;
-
- public OAuth(ServiceInfo info) {
- this(info, true);
- }
-
- public OAuth(ServiceInfo info, boolean use10a) {
- this.info = info;
- this.provider = new DefaultOAuthProvider(info.requestTokenURL, info.accessTokenURL, info.authorizationURL);
- this.provider.setOAuth10a(use10a);
- }
-
- public ServiceInfo getInfo() {
- return info;
- }
-
- public OAuthProvider getProvider() {
- return provider;
- }
-
- /**
- * Request the request token and secret.
- *
- * @param callbackURL the URL where the provider should redirect to (usually a URL on the current app)
- * @return A Right(RequestToken) in case of success, Left(OAuthException) otherwise
- */
- public RequestToken retrieveRequestToken(String callbackURL) {
- OAuthConsumer consumer = new DefaultOAuthConsumer(info.key.key, info.key.secret);
- try {
- provider.retrieveRequestToken(consumer, callbackURL);
- return new RequestToken(consumer.getToken(), consumer.getTokenSecret());
- } catch (OAuthException ex) {
- throw new RuntimeException(ex);
- }
- }
-
- /**
- * Exchange a request token for an access token.
- *
- * @param token the token/secret pair obtained from a previous call
- * @param verifier a string you got through your user, with redirection
- * @return A Right(RequestToken) in case of success, Left(OAuthException) otherwise
- */
- public RequestToken retrieveAccessToken(RequestToken token, String verifier) {
- OAuthConsumer consumer = new DefaultOAuthConsumer(info.key.key, info.key.secret);
- consumer.setTokenWithSecret(token.token, token.secret);
- try {
- provider.retrieveAccessToken(consumer, verifier);
- return new RequestToken(consumer.getToken(), consumer.getTokenSecret());
- } catch (OAuthException ex) {
- throw new RuntimeException(ex);
- }
- }
-
- /**
- * The URL where the user needs to be redirected to grant authorization to your application.
- *
- * @param token request token
- * @return the url
- */
- public String redirectUrl(String token) {
- return play.shaded.oauth.oauth.signpost.OAuth.addQueryParameters(
- provider.getAuthorizationWebsiteUrl(),
- play.shaded.oauth.oauth.signpost.OAuth.OAUTH_TOKEN,
- token
- );
- }
-
- /**
- * A consumer key / consumer secret pair that the OAuth provider gave you, to identify your application.
- */
- public static class ConsumerKey {
- public String key;
- public String secret;
-
- public ConsumerKey(String key, String secret) {
- this.key = key;
- this.secret = secret;
- }
- }
-
- /**
- * A request token / token secret pair, to be used for a specific user.
- */
- public static class RequestToken {
- public String token;
- public String secret;
-
- public RequestToken(String token, String secret) {
- this.token = token;
- this.secret = secret;
- }
- }
-
- /**
- * The information identifying a oauth provider: URLs and the consumer key / consumer secret pair.
- */
- public static class ServiceInfo {
- public String requestTokenURL;
- public String accessTokenURL;
- public String authorizationURL;
- public ConsumerKey key;
-
- public ServiceInfo(String requestTokenURL, String accessTokenURL, String authorizationURL, ConsumerKey key) {
- this.requestTokenURL = requestTokenURL;
- this.accessTokenURL = accessTokenURL;
- this.authorizationURL = authorizationURL;
- this.key = key;
- }
- }
-
- /**
- * A signature calculator for the Play WS API.
- *
- * Example:
- * {{{
- * WS.url("http://example.com/protected").sign(OAuthCalculator(service, token)).get()
- * }}}
- */
- public static class OAuthCalculator implements WSSignatureCalculator {
-
- private OAuthSignatureCalculator calculator;
-
- public OAuthCalculator(ConsumerKey consumerKey, RequestToken token) {
- play.shaded.ahc.org.asynchttpclient.oauth.ConsumerKey ahcConsumerKey = new play.shaded.ahc.org.asynchttpclient.oauth.ConsumerKey(consumerKey.key, consumerKey.secret);
- play.shaded.ahc.org.asynchttpclient.oauth.RequestToken ahcRequestToken = new play.shaded.ahc.org.asynchttpclient.oauth.RequestToken(token.token, token.secret);
- calculator = new OAuthSignatureCalculator(ahcConsumerKey, ahcRequestToken);
- }
-
- public OAuthSignatureCalculator getCalculator() {
- return calculator;
- }
- }
-
-}
diff --git a/play-ahc-ws-standalone/src/main/java/play/libs/ws/ahc/StandaloneAhcWSClient.java b/play-ahc-ws-standalone/src/main/java/play/libs/ws/ahc/StandaloneAhcWSClient.java
index 355bb4f4..b479503d 100644
--- a/play-ahc-ws-standalone/src/main/java/play/libs/ws/ahc/StandaloneAhcWSClient.java
+++ b/play-ahc-ws-standalone/src/main/java/play/libs/ws/ahc/StandaloneAhcWSClient.java
@@ -4,38 +4,28 @@
package play.libs.ws.ahc;
-import org.apache.pekko.Done;
+import com.typesafe.sslconfig.ssl.SystemConfiguration;
+import jakarta.inject.Inject;
import org.apache.pekko.stream.Materializer;
import org.apache.pekko.stream.javadsl.Source;
import org.apache.pekko.util.ByteString;
import org.apache.pekko.util.ByteStringBuilder;
-import com.typesafe.sslconfig.ssl.SystemConfiguration;
-import org.reactivestreams.Publisher;
-import org.reactivestreams.Subscriber;
-import org.reactivestreams.Subscription;
import org.slf4j.LoggerFactory;
-import play.api.libs.ws.ahc.*;
+import play.api.libs.ws.ahc.AhcConfigBuilder;
+import play.api.libs.ws.ahc.AhcLoggerFactory;
+import play.api.libs.ws.ahc.AhcWSClientConfig;
import play.api.libs.ws.ahc.cache.AhcHttpCache;
import play.api.libs.ws.ahc.cache.CachingAsyncHttpClient;
import play.libs.ws.StandaloneWSClient;
import play.libs.ws.StandaloneWSResponse;
-import play.shaded.ahc.org.asynchttpclient.AsyncCompletionHandler;
-import play.shaded.ahc.org.asynchttpclient.AsyncHttpClient;
-import play.shaded.ahc.org.asynchttpclient.DefaultAsyncHttpClient;
-import play.shaded.ahc.org.asynchttpclient.DefaultAsyncHttpClientConfig;
-import play.shaded.ahc.org.asynchttpclient.Request;
-import play.shaded.ahc.org.asynchttpclient.Response;
import play.shaded.ahc.org.asynchttpclient.*;
-import scala.jdk.javaapi.FutureConverters;
-import scala.concurrent.ExecutionContext;
import scala.concurrent.Future;
import scala.concurrent.Promise;
+import scala.jdk.javaapi.FutureConverters;
-import jakarta.inject.Inject;
import java.io.IOException;
import java.util.concurrent.CompletionStage;
import java.util.concurrent.ExecutionException;
-import java.util.function.Function;
/**
* A WS asyncHttpClient backed by an AsyncHttpClient instance.
@@ -86,62 +76,6 @@ CompletionStage execute(Request request) {
return FutureConverters.asJava(future);
}
- CompletionStage executeStream(Request request, ExecutionContext ec) {
- final Promise streamStarted = scala.concurrent.Promise$.MODULE$.apply();
- final Promise streamCompletion = scala.concurrent.Promise$.MODULE$.apply();
-
- Function f = state -> {
- Publisher publisher = state.publisher();
- Publisher wrap = new Publisher() {
- @Override
- public void subscribe(Subscriber super HttpResponseBodyPart> s) {
- publisher.subscribe(
- new Subscriber() {
- @Override
- public void onSubscribe(Subscription sub) {
- s.onSubscribe(sub);
- }
-
- @Override
- public void onNext(HttpResponseBodyPart httpResponseBodyPart) {
- s.onNext(httpResponseBodyPart);
- }
-
- @Override
- public void onError(Throwable t) {
- s.onError(t);
- }
-
- @Override
- public void onComplete() {
- FutureConverters.asJava(streamCompletion.future())
- .handle((d, t) -> {
- if (d != null) s.onComplete();
- else s.onError(t);
- return null;
- });
- }
- }
- );
- }
- };
-
- return new StreamedResponse(this,
- state.statusCode(),
- state.statusText(),
- state.uriOption().get(),
- state.responseHeaders(),
- wrap,
- asyncHttpClient.getConfig().isUseLaxCookieEncoder());
- };
-
- asyncHttpClient.executeRequest(request, new DefaultStreamedAsyncHandler<>(f,
- streamStarted,
- streamCompletion
- ));
- return FutureConverters.asJava(streamStarted.future());
- }
-
/**
* A convenience method for creating a StandaloneAhcWSClient from configuration.
*
diff --git a/play-ahc-ws-standalone/src/main/java/play/libs/ws/ahc/StandaloneAhcWSRequest.java b/play-ahc-ws-standalone/src/main/java/play/libs/ws/ahc/StandaloneAhcWSRequest.java
index 591aafe9..dfd97837 100644
--- a/play-ahc-ws-standalone/src/main/java/play/libs/ws/ahc/StandaloneAhcWSRequest.java
+++ b/play-ahc-ws-standalone/src/main/java/play/libs/ws/ahc/StandaloneAhcWSRequest.java
@@ -6,12 +6,10 @@
import org.apache.pekko.stream.Materializer;
import org.apache.pekko.stream.javadsl.AsPublisher;
-import org.apache.pekko.stream.javadsl.Sink;
import org.apache.pekko.stream.javadsl.Source;
import org.apache.pekko.util.ByteString;
import org.reactivestreams.Publisher;
import play.api.libs.ws.ahc.FormUrlEncodedParser;
-import play.libs.oauth.OAuth;
import play.libs.ws.*;
import play.shaded.ahc.io.netty.buffer.ByteBuf;
import play.shaded.ahc.io.netty.buffer.Unpooled;
@@ -20,12 +18,7 @@
import play.shaded.ahc.io.netty.handler.codec.http.HttpHeaders;
import play.shaded.ahc.io.netty.handler.codec.http.cookie.Cookie;
import play.shaded.ahc.io.netty.handler.codec.http.cookie.DefaultCookie;
-import play.shaded.ahc.org.asynchttpclient.AsyncHttpClient;
-import play.shaded.ahc.org.asynchttpclient.Realm;
-import play.shaded.ahc.org.asynchttpclient.Request;
-import play.shaded.ahc.org.asynchttpclient.RequestBuilder;
-import play.shaded.ahc.org.asynchttpclient.SignatureCalculator;
-
+import play.shaded.ahc.org.asynchttpclient.*;
import play.shaded.ahc.org.asynchttpclient.util.HttpUtils;
import java.net.MalformedURLException;
@@ -33,15 +26,7 @@
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.time.Duration;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Optional;
+import java.util.*;
import java.util.concurrent.CompletionStage;
import static java.util.Collections.singletonList;
@@ -399,16 +384,6 @@ public CompletionStage extends StandaloneWSResponse> execute() {
return executor.apply(this);
}
- @Override
- public CompletionStage extends StandaloneWSResponse> stream() {
- WSRequestExecutor executor = foldRight(r -> {
- StandaloneAhcWSRequest ahcWsRequest = (StandaloneAhcWSRequest) r;
- Request ahcRequest = ahcWsRequest.buildRequest();
- return client.executeStream(ahcRequest, materializer.executionContext());
- }, filters.iterator());
- return executor.apply(this);
- }
-
private WSRequestExecutor foldRight(WSRequestExecutor executor, Iterator iterator) {
if (!iterator.hasNext()) {
return executor;
@@ -471,19 +446,6 @@ Request buildRequest() {
builder.setBody(stringBody);
}
}
- } else if (bodyWritable instanceof SourceBodyWritable) {
- // If the bodyWritable has a streaming interface it should be up to the user to provide a manual Content-Length
- // else every content would be Transfer-Encoding: chunked
- // If the Content-Length is -1 Async-Http-Client sets a Transfer-Encoding: chunked
- // If the Content-Length is great than -1 Async-Http-Client will use the correct Content-Length
- long contentLength = Optional.ofNullable(possiblyModifiedHeaders.get(CONTENT_LENGTH.toString()))
- .map(Long::valueOf).orElse(-1L);
- possiblyModifiedHeaders.remove(CONTENT_LENGTH.toString());
-
- @SuppressWarnings("unchecked") Source sourceBody = ((SourceBodyWritable) bodyWritable).body().get();
- Publisher publisher = sourceBody.map(bs -> Unpooled.wrappedBuffer(bs.toByteBuffer()))
- .runWith(Sink.asPublisher(AsPublisher.WITHOUT_FANOUT), materializer);
- builder.setBody(publisher, contentLength);
} else {
throw new IllegalStateException("Unknown body writable: " + bodyWritable);
}
@@ -492,9 +454,9 @@ Request buildRequest() {
builder.setHeaders(possiblyModifiedHeaders);
if (this.timeout.isNegative()) {
- builder.setRequestTimeout(((int) INFINITE.toMillis()));
+ builder.setRequestTimeout(INFINITE);
} else if (this.timeout.compareTo(Duration.ZERO) > 0) {
- builder.setRequestTimeout(((int) this.timeout.toMillis()));
+ builder.setRequestTimeout(this.timeout);
}
getFollowRedirects().ifPresent(builder::setFollowRedirect);
@@ -504,14 +466,11 @@ Request buildRequest() {
this.getAuth().ifPresent(auth -> builder.setRealm(auth(auth.getUsername(), auth.getPassword(), auth.getScheme())));
if (this.calculator != null) {
- if (this.calculator instanceof OAuth.OAuthCalculator) {
- SignatureCalculator calc = ((OAuth.OAuthCalculator) this.calculator).getCalculator();
- builder.setSignatureCalculator(calc);
- } else if (this.calculator instanceof SignatureCalculator) {
+ if (this.calculator instanceof SignatureCalculator) {
SignatureCalculator calc = ((SignatureCalculator) this.calculator);
builder.setSignatureCalculator(calc);
} else {
- throw new IllegalStateException("Use OAuth.OAuthCalculator");
+ throw new IllegalStateException("Unsupported signature calculator provided.");
}
}
diff --git a/play-ahc-ws-standalone/src/main/scala/play/api/libs/oauth/OAuth.scala b/play-ahc-ws-standalone/src/main/scala/play/api/libs/oauth/OAuth.scala
deleted file mode 100644
index 3c76155e..00000000
--- a/play-ahc-ws-standalone/src/main/scala/play/api/libs/oauth/OAuth.scala
+++ /dev/null
@@ -1,144 +0,0 @@
-/*
- * Copyright (C) from 2022 The Play Framework Contributors , 2011-2021 Lightbend Inc.
- */
-
-package play.api.libs.oauth
-
-import play.shaded.oauth.oauth.signpost.basic.DefaultOAuthConsumer
-import play.shaded.oauth.oauth.signpost.basic.DefaultOAuthProvider
-import play.shaded.oauth.oauth.signpost.exception.OAuthException
-import play.shaded.ahc.org.asynchttpclient.oauth.OAuthSignatureCalculator
-import play.shaded.ahc.org.asynchttpclient.Request
-import play.shaded.ahc.org.asynchttpclient.RequestBuilderBase
-import play.shaded.ahc.org.asynchttpclient.SignatureCalculator
-import play.api.libs.ws.WSSignatureCalculator
-
-import play.shaded.ahc.org.asynchttpclient.oauth.{ ConsumerKey => AHCConsumerKey }
-import play.shaded.ahc.org.asynchttpclient.oauth.{ RequestToken => AHCRequestToken }
-
-/**
- * Library to access resources protected by OAuth 1.0a.
- *
- * @param info the service information, including the required URLs and the application id and secret
- * @param use10a whether the service should use the 1.0 version of the spec, or the 1.0a version fixing a security issue.
- * You must use the version corresponding to the
- */
-case class OAuth(info: ServiceInfo, use10a: Boolean = true) {
-
- private val provider = {
- val p = new DefaultOAuthProvider(info.requestTokenURL, info.accessTokenURL, info.authorizationURL)
- p.setOAuth10a(use10a)
- p
- }
-
- /**
- * Request the request token and secret.
- *
- * @param callbackURL the URL where the provider should redirect to (usually a URL on the current app)
- * @return A Right(RequestToken) in case of success, Left(OAuthException) otherwise
- */
- def retrieveRequestToken(callbackURL: String): Either[OAuthException, RequestToken] = {
- val consumer = new DefaultOAuthConsumer(info.key.key, info.key.secret)
- try {
- provider.retrieveRequestToken(consumer, callbackURL)
- Right(RequestToken(consumer.getToken(), consumer.getTokenSecret()))
- } catch {
- case e: OAuthException => Left(e)
- }
- }
-
- /**
- * Exchange a request token for an access token.
- *
- * @param token the token/secret pair obtained from a previous call
- * @param verifier a string you got through your user, with redirection
- * @return A Right(RequestToken) in case of success, Left(OAuthException) otherwise
- */
- def retrieveAccessToken(token: RequestToken, verifier: String): Either[OAuthException, RequestToken] = {
- val consumer = new DefaultOAuthConsumer(info.key.key, info.key.secret)
- consumer.setTokenWithSecret(token.token, token.secret)
- try {
- provider.retrieveAccessToken(consumer, verifier)
- Right(RequestToken(consumer.getToken(), consumer.getTokenSecret()))
- } catch {
- case e: OAuthException => Left(e)
- }
- }
-
- /**
- * The URL where the user needs to be redirected to grant authorization to your application.
- *
- * @param token request token
- */
- def redirectUrl(token: String): String = {
- import play.shaded.oauth.oauth.signpost.{ OAuth => O }
- O.addQueryParameters(
- provider.getAuthorizationWebsiteUrl(),
- O.OAUTH_TOKEN,
- token
- )
- }
-
-}
-
-/**
- * A consumer key / consumer secret pair that the OAuth provider gave you, to identify your application.
- */
-case class ConsumerKey(key: String, secret: String)
-
-/**
- * A request token / token secret pair, to be used for a specific user.
- */
-case class RequestToken(token: String, secret: String)
-
-/**
- * The information identifying a oauth provider: URLs and the consumer key / consumer secret pair.
- */
-case class ServiceInfo(requestTokenURL: String, accessTokenURL: String, authorizationURL: String, key: ConsumerKey)
-
-/**
- * The public AsyncHttpClient implementation of WSSignatureCalculator.
- */
-class OAuthCalculator(consumerKey: ConsumerKey, requestToken: RequestToken)
- extends WSSignatureCalculator
- with SignatureCalculator {
-
- private val ahcConsumerKey = new AHCConsumerKey(consumerKey.key, consumerKey.secret)
- private val ahcRequestToken = new AHCRequestToken(requestToken.token, requestToken.secret)
- private val calculator = new OAuthSignatureCalculator(ahcConsumerKey, ahcRequestToken)
-
- override def calculateAndAddSignature(request: Request, requestBuilder: RequestBuilderBase[?]): Unit = {
- calculator.calculateAndAddSignature(request, requestBuilder)
- }
-}
-
-/**
- * Object for creating signature calculator for the Play WS API.
- *
- * Example:
- * {{{
- * import play.api.libs.oauth.{ ConsumerKey, OAuthCalculator, RequestToken }
- * import play.api.libs.ws.ahc.StandaloneAhcWSClient
- *
- * def example(
- * twitterConsumerKey: String,
- * twitterConsumerSecret: String,
- * accessTokenKey: String,
- * accessTokenSecret: String,
- * ws: StandaloneAhcWSClient) = {
- * val consumerKey: ConsumerKey =
- * ConsumerKey(twitterConsumerKey, twitterConsumerSecret)
- *
- * val requestToken: RequestToken =
- * RequestToken(accessTokenKey, accessTokenSecret)
- *
- * ws.url("http://example.com/protected").
- * sign(OAuthCalculator(consumerKey, requestToken)).get()
- * }
- * }}}
- */
-object OAuthCalculator {
- def apply(consumerKey: ConsumerKey, token: RequestToken): WSSignatureCalculator = {
- new OAuthCalculator(consumerKey, token)
- }
-}
diff --git a/play-ahc-ws-standalone/src/main/scala/play/api/libs/ws/ahc/AhcConfig.scala b/play-ahc-ws-standalone/src/main/scala/play/api/libs/ws/ahc/AhcConfig.scala
index de0795fb..f1af15ea 100644
--- a/play-ahc-ws-standalone/src/main/scala/play/api/libs/ws/ahc/AhcConfig.scala
+++ b/play-ahc-ws-standalone/src/main/scala/play/api/libs/ws/ahc/AhcConfig.scala
@@ -4,25 +4,25 @@
package play.api.libs.ws.ahc
-import jakarta.inject.Inject
-import jakarta.inject.Provider
-import jakarta.inject.Singleton
-import javax.net.ssl._
-
import com.typesafe.config.Config
import com.typesafe.config.ConfigException
import com.typesafe.config.ConfigFactory
import com.typesafe.sslconfig.ssl._
+import jakarta.inject.Inject
+import jakarta.inject.Provider
+import jakarta.inject.Singleton
import org.slf4j.LoggerFactory
import play.api.libs.ws.WSClientConfig
import play.api.libs.ws.WSConfigParser
import play.shaded.ahc.io.netty.handler.ssl.SslContextBuilder
import play.shaded.ahc.io.netty.handler.ssl.util.InsecureTrustManagerFactory
-import play.shaded.ahc.org.asynchttpclient.netty.ssl.JsseSslEngineFactory
import play.shaded.ahc.org.asynchttpclient.AsyncHttpClientConfig
import play.shaded.ahc.org.asynchttpclient.DefaultAsyncHttpClientConfig
+import play.shaded.ahc.org.asynchttpclient.netty.ssl.JsseSslEngineFactory
+import javax.net.ssl._
import scala.concurrent.duration._
+import scala.jdk.javaapi.DurationConverters.toJava
/**
* Ahc client config.
@@ -194,15 +194,17 @@ class AhcConfigBuilder(ahcConfig: AhcWSClientConfig = AhcWSClientConfig()) {
def configureWS(ahcConfig: AhcWSClientConfig): Unit = {
val config = ahcConfig.wsClientConfig
- def toMillis(duration: Duration): Int = {
- if (duration.isFinite) duration.toMillis.toInt
- else -1
+ def toJavaDuration(duration: Duration): java.time.Duration = {
+ if (duration.isFinite)
+ toJava(Duration.fromNanos(duration.toNanos))
+ else
+ java.time.Duration.ZERO
}
builder
- .setConnectTimeout(toMillis(config.connectionTimeout))
- .setReadTimeout(toMillis(config.idleTimeout))
- .setRequestTimeout(toMillis(config.requestTimeout))
+ .setConnectTimeout(toJavaDuration(config.connectionTimeout))
+ .setReadTimeout(toJavaDuration(config.idleTimeout))
+ .setRequestTimeout(toJavaDuration(config.requestTimeout))
.setFollowRedirect(config.followRedirects)
.setUseProxyProperties(config.useProxyProperties)
.setCompressionEnforced(config.compressionEnabled)
@@ -211,9 +213,9 @@ class AhcConfigBuilder(ahcConfig: AhcWSClientConfig = AhcWSClientConfig()) {
builder.setMaxConnectionsPerHost(ahcConfig.maxConnectionsPerHost)
builder.setMaxConnections(ahcConfig.maxConnectionsTotal)
- builder.setConnectionTtl(toMillis(ahcConfig.maxConnectionLifetime))
- builder.setPooledConnectionIdleTimeout(toMillis(ahcConfig.idleConnectionInPoolTimeout))
- builder.setConnectionPoolCleanerPeriod(toMillis(ahcConfig.connectionPoolCleanerPeriod))
+ builder.setConnectionTtl(toJavaDuration(ahcConfig.maxConnectionLifetime))
+ builder.setPooledConnectionIdleTimeout(toJavaDuration(ahcConfig.idleConnectionInPoolTimeout))
+ builder.setConnectionPoolCleanerPeriod(toJavaDuration(ahcConfig.connectionPoolCleanerPeriod))
builder.setMaxRedirects(ahcConfig.maxNumberOfRedirects)
builder.setMaxRequestRetry(ahcConfig.maxRequestRetry)
builder.setDisableUrlEncodingForBoundRequests(ahcConfig.disableUrlEncoding)
@@ -225,8 +227,8 @@ class AhcConfigBuilder(ahcConfig: AhcWSClientConfig = AhcWSClientConfig()) {
// The proper solution is to make these parameters configurable, so that they can be set
// to 0 when running tests, and keep sensible defaults otherwise. AHC defaults are
// shutdownQuiet=2000 (milliseconds) and shutdownTimeout=15000 (milliseconds).
- builder.setShutdownQuietPeriod(0)
- builder.setShutdownTimeout(0)
+ builder.setShutdownQuietPeriod(java.time.Duration.ZERO)
+ builder.setShutdownTimeout(java.time.Duration.ZERO)
builder.setUseLaxCookieEncoder(ahcConfig.useLaxCookieEncoder)
if (!ahcConfig.useCookieStore) {
diff --git a/play-ahc-ws-standalone/src/main/scala/play/api/libs/ws/ahc/StandaloneAhcWSClient.scala b/play-ahc-ws-standalone/src/main/scala/play/api/libs/ws/ahc/StandaloneAhcWSClient.scala
index a931c36d..0dfe5f1f 100644
--- a/play-ahc-ws-standalone/src/main/scala/play/api/libs/ws/ahc/StandaloneAhcWSClient.scala
+++ b/play-ahc-ws-standalone/src/main/scala/play/api/libs/ws/ahc/StandaloneAhcWSClient.scala
@@ -4,31 +4,22 @@
package play.api.libs.ws.ahc
-import org.apache.pekko.Done
+import com.typesafe.sslconfig.ssl.SystemConfiguration
import jakarta.inject.Inject
import org.apache.pekko.stream.Materializer
import org.apache.pekko.stream.scaladsl.Source
import org.apache.pekko.util.ByteString
-import com.typesafe.sslconfig.ssl.SystemConfiguration
-import org.reactivestreams.Publisher
-import org.reactivestreams.Subscriber
-import org.reactivestreams.Subscription
-import play.api.libs.ws.ahc.cache._
import play.api.libs.ws.EmptyBody
import play.api.libs.ws.StandaloneWSClient
import play.api.libs.ws.StandaloneWSRequest
+import play.api.libs.ws.ahc.cache._
import play.shaded.ahc.org.asynchttpclient.uri.Uri
-import play.shaded.ahc.org.asynchttpclient.{ Response => AHCResponse }
-import play.shaded.ahc.org.asynchttpclient._
-import java.util.function.{ Function => JFunction }
+import play.shaded.ahc.org.asynchttpclient.{ Response => AHCResponse, _ }
import scala.collection.immutable.TreeMap
-import scala.jdk.FunctionConverters._
import scala.concurrent.Await
import scala.concurrent.Future
import scala.concurrent.Promise
-import scala.util.Failure
-import scala.util.Success
/**
* A WS client backed by an AsyncHttpClient.
@@ -102,59 +93,6 @@ class StandaloneAhcWSClient @Inject() (asyncHttpClient: AsyncHttpClient)(implici
}
}
- private[ahc] def executeStream(request: Request): Future[StreamedResponse] = {
- val streamStarted = Promise[StreamedResponse]()
- val streamCompletion = Promise[Done]()
-
- val client = this
-
- val function: JFunction[StreamedState, StreamedResponse] = { (state: StreamedState) =>
- val publisher = state.publisher
-
- val wrap = new Publisher[HttpResponseBodyPart]() {
- override def subscribe(
- s: Subscriber[? >: HttpResponseBodyPart]
- ): Unit = {
- publisher.subscribe(new Subscriber[HttpResponseBodyPart] {
- override def onSubscribe(sub: Subscription): Unit =
- s.onSubscribe(sub)
-
- override def onNext(t: HttpResponseBodyPart): Unit = s.onNext(t)
-
- override def onError(t: Throwable): Unit = s.onError(t)
-
- override def onComplete(): Unit = {
- streamCompletion.future.onComplete {
- case Success(_) => s.onComplete()
- case Failure(t) => s.onError(t)
- }(materializer.executionContext)
- }
- })
- }
-
- }
- new StreamedResponse(
- client,
- state.statusCode,
- state.statusText,
- state.uriOption.get,
- state.responseHeaders,
- wrap,
- asyncHttpClient.getConfig.isUseLaxCookieEncoder
- )
-
- }.asJava
- asyncHttpClient.executeRequest(
- request,
- new DefaultStreamedAsyncHandler[StreamedResponse](
- function,
- streamStarted,
- streamCompletion
- )
- )
- streamStarted.future
- }
-
private[ahc] def blockingToByteString(bodyAsSource: Source[ByteString, ?]) = {
StandaloneAhcWSClient.logger.warn(
s"blockingToByteString is a blocking and unsafe operation!"
diff --git a/play-ahc-ws-standalone/src/main/scala/play/api/libs/ws/ahc/StandaloneAhcWSRequest.scala b/play-ahc-ws-standalone/src/main/scala/play/api/libs/ws/ahc/StandaloneAhcWSRequest.scala
index fc1250f0..6e0d9f6b 100644
--- a/play-ahc-ws-standalone/src/main/scala/play/api/libs/ws/ahc/StandaloneAhcWSRequest.scala
+++ b/play-ahc-ws-standalone/src/main/scala/play/api/libs/ws/ahc/StandaloneAhcWSRequest.scala
@@ -4,14 +4,8 @@
package play.api.libs.ws.ahc
-import java.io.UnsupportedEncodingException
-import java.net.URI
-import java.nio.charset.Charset
-import java.nio.charset.StandardCharsets
-
import org.apache.pekko.stream.Materializer
import org.apache.pekko.stream.scaladsl.Sink
-import play.api.libs.ws.StandaloneWSRequest
import play.api.libs.ws._
import play.shaded.ahc.io.netty.buffer.Unpooled
import play.shaded.ahc.io.netty.handler.codec.http.HttpHeaders
@@ -20,10 +14,15 @@ import play.shaded.ahc.org.asynchttpclient._
import play.shaded.ahc.org.asynchttpclient.proxy.{ ProxyServer => AHCProxyServer }
import play.shaded.ahc.org.asynchttpclient.util.HttpUtils
-import scala.jdk.CollectionConverters._
+import java.io.UnsupportedEncodingException
+import java.net.URI
+import java.nio.charset.Charset
+import java.nio.charset.StandardCharsets
import scala.collection.immutable.TreeMap
import scala.concurrent.Future
import scala.concurrent.duration.Duration
+import scala.jdk.CollectionConverters._
+import scala.jdk.javaapi.DurationConverters.toJava
/**
* A Ahc WS Request.
@@ -242,14 +241,6 @@ case class StandaloneAhcWSRequest(
filters.foldRight(next)((filter, executor) => filter.apply(executor))
}
- override def stream(): Future[Response] = {
- val executor = filterWSRequestExecutor(WSRequestExecutor { request =>
- client.executeStream(request.asInstanceOf[StandaloneAhcWSRequest].buildRequest())
- })
-
- executor(this)
- }
-
/**
* Returns the HTTP header given by name, using the request builder. This may be signed,
* so may return extra headers that were not directly input.
@@ -311,9 +302,9 @@ case class StandaloneAhcWSRequest(
proxyServer.foreach(p => builder.setProxyServer(createProxy(p)))
requestTimeout.foreach {
case d if d == Duration.Inf =>
- builder.setRequestTimeout(-1)
+ builder.setRequestTimeout(java.time.Duration.ZERO)
case d =>
- builder.setRequestTimeout(d.toMillis.toInt)
+ builder.setRequestTimeout(toJava(Duration.fromNanos(d.toNanos)))
}
val (builderWithBody, updatedHeaders) = body match {
@@ -360,25 +351,6 @@ case class StandaloneAhcWSRequest(
}
(builder, h)
- case SourceBody(source) =>
- // If the body has a streaming interface it should be up to the user to provide a manual Content-Length
- // else every content would be Transfer-Encoding: chunked
- // If the Content-Length is -1 Async-Http-Client sets a Transfer-Encoding: chunked
- // If the Content-Length is great than -1 Async-Http-Client will use the correct Content-Length
- val filteredHeaders = this.headers.filterNot { case (k, v) =>
- k.equalsIgnoreCase(HttpHeaders.Names.CONTENT_LENGTH)
- }
- val contentLength = this.headers
- .find { case (k, _) => k.equalsIgnoreCase(HttpHeaders.Names.CONTENT_LENGTH) }
- .map(_._2.head.toLong)
-
- (
- builder.setBody(
- source.map(bs => Unpooled.wrappedBuffer(bs.toByteBuffer)).runWith(Sink.asPublisher(false)),
- contentLength.getOrElse(-1L)
- ),
- filteredHeaders
- )
}
// headers
diff --git a/play-ahc-ws-standalone/src/main/scala/play/api/libs/ws/ahc/Streamed.scala b/play-ahc-ws-standalone/src/main/scala/play/api/libs/ws/ahc/Streamed.scala
deleted file mode 100644
index 850dfcdf..00000000
--- a/play-ahc-ws-standalone/src/main/scala/play/api/libs/ws/ahc/Streamed.scala
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * Copyright (C) from 2022 The Play Framework Contributors , 2011-2021 Lightbend Inc.
- */
-
-package play.api.libs.ws.ahc
-
-import java.net.URI
-
-import org.reactivestreams.Subscriber
-import org.reactivestreams.Subscription
-import org.reactivestreams.Publisher
-import play.shaded.ahc.io.netty.handler.codec.http.HttpHeaders
-import org.apache.pekko.Done
-import play.shaded.ahc.org.asynchttpclient.AsyncHandler.State
-import play.shaded.ahc.org.asynchttpclient._
-import play.shaded.ahc.org.asynchttpclient.handler.StreamedAsyncHandler
-
-import scala.concurrent.Promise
-
-case class StreamedState(
- statusCode: Int = -1,
- statusText: String = "",
- uriOption: Option[URI] = None,
- responseHeaders: Map[String, scala.collection.Seq[String]] = Map.empty,
- publisher: Publisher[HttpResponseBodyPart] = EmptyPublisher
-)
-
-class DefaultStreamedAsyncHandler[T](
- f: java.util.function.Function[StreamedState, T],
- streamStarted: Promise[T],
- streamDone: Promise[Done]
-) extends StreamedAsyncHandler[Unit]
- with AhcUtilities {
- private var state = StreamedState()
-
- def onStream(publisher: Publisher[HttpResponseBodyPart]): State = {
- if (this.state.publisher != EmptyPublisher) State.ABORT
- else {
- this.state = state.copy(publisher = publisher)
- streamStarted.success(f(state))
- State.CONTINUE
- }
- }
-
- override def onStatusReceived(status: HttpResponseStatus): State = {
- if (this.state.publisher != EmptyPublisher) State.ABORT
- else {
- state = state.copy(
- statusCode = status.getStatusCode,
- statusText = status.getStatusText,
- uriOption = Option(status.getUri.toJavaNetURI)
- )
- State.CONTINUE
- }
- }
-
- override def onHeadersReceived(h: HttpHeaders): State = {
- if (this.state.publisher != EmptyPublisher) State.ABORT
- else {
- state = state.copy(responseHeaders = headersToMap(h))
- State.CONTINUE
- }
- }
-
- override def onBodyPartReceived(bodyPart: HttpResponseBodyPart): State =
- throw new IllegalStateException("Should not have received bodypart")
-
- override def onCompleted(): Unit = {
- // EmptyPublisher can be replaces with `Source.empty` when we carry out the refactoring
- // mentioned in the `execute2` method.
- streamStarted.trySuccess(f(state.copy(publisher = EmptyPublisher)))
- streamDone.trySuccess(Done)
- }
-
- override def onThrowable(t: Throwable): Unit = {
- streamStarted.tryFailure(t)
- streamDone.tryFailure(t)
- }
-}
-
-private case object EmptyPublisher extends Publisher[HttpResponseBodyPart] {
- def subscribe(s: Subscriber[? >: HttpResponseBodyPart]): Unit = {
- if (s eq null)
- throw new NullPointerException("Subscriber must not be null, rule 1.9")
- s.onSubscribe(CancelledSubscription)
- s.onComplete()
- }
- private case object CancelledSubscription extends Subscription {
- override def request(elements: Long): Unit = ()
- override def cancel(): Unit = ()
- }
-}
diff --git a/play-ahc-ws-standalone/src/main/scala/play/api/libs/ws/ahc/StreamedResponse.scala b/play-ahc-ws-standalone/src/main/scala/play/api/libs/ws/ahc/StreamedResponse.scala
deleted file mode 100644
index 1001a535..00000000
--- a/play-ahc-ws-standalone/src/main/scala/play/api/libs/ws/ahc/StreamedResponse.scala
+++ /dev/null
@@ -1,124 +0,0 @@
-/*
- * Copyright (C) from 2022 The Play Framework Contributors , 2011-2021 Lightbend Inc.
- */
-
-package play.api.libs.ws.ahc
-
-import org.apache.pekko.stream.scaladsl.Source
-import org.apache.pekko.util.ByteString
-import org.reactivestreams.Publisher
-import play.api.libs.ws.StandaloneWSResponse
-import play.api.libs.ws.WSCookie
-import play.shaded.ahc.org.asynchttpclient.HttpResponseBodyPart
-
-import scala.collection.immutable.TreeMap
-import scala.collection.mutable
-
-/**
- * A streamed response containing a response header and a streamable body.
- *
- * Note that this is only usable with a stream call, i.e.
- *
- * {{{
- * import scala.concurrent.{ ExecutionContext, Future }
- *
- * import org.apache.pekko.util.ByteString
- * import org.apache.pekko.stream.scaladsl.Source
- *
- * import play.api.libs.ws.DefaultBodyReadables._
- * import play.api.libs.ws.ahc.StandaloneAhcWSClient
- *
- * class MyClass(ws: StandaloneAhcWSClient) {
- * def doIt(implicit ec: ExecutionContext): Future[String] =
- * ws.url("http://example.com").stream().map { response =>
- * val _ = response.body[Source[ByteString, _]]
- * ??? // process source to String
- * }
- * }
- * }}}
- */
-class StreamedResponse(
- client: StandaloneAhcWSClient,
- val status: Int,
- val statusText: String,
- val uri: java.net.URI,
- publisher: Publisher[HttpResponseBodyPart],
- val useLaxCookieEncoder: Boolean
-) extends StandaloneWSResponse
- with CookieBuilder {
-
- def this(
- client: StandaloneAhcWSClient,
- status: Int,
- statusText: String,
- uri: java.net.URI,
- headers: Map[String, scala.collection.Seq[String]],
- publisher: Publisher[HttpResponseBodyPart],
- useLaxCookieEncoder: Boolean
- ) = {
- this(
- client,
- status,
- statusText,
- uri,
- publisher,
- useLaxCookieEncoder
- )
- origHeaders = headers
- }
-
- private var origHeaders: Map[String, scala.collection.Seq[String]] = Map.empty
-
- /**
- * Get the underlying response object.
- */
- override def underlying[T]: T = publisher.asInstanceOf[T]
-
- override lazy val headers: Map[String, scala.collection.Seq[String]] = {
- val mutableMap = mutable.TreeMap[String, scala.collection.Seq[String]]()(CaseInsensitiveOrdered)
- origHeaders.keys.foreach { name =>
- mutableMap.updateWith(name) {
- case Some(value) => Some(value ++ origHeaders.getOrElse(name, Seq.empty))
- case None => Some(origHeaders.getOrElse(name, Seq.empty))
- }
- }
- TreeMap[String, scala.collection.Seq[String]]()(CaseInsensitiveOrdered) ++ mutableMap
- }
-
- /**
- * Get all the cookies.
- */
- override lazy val cookies: scala.collection.Seq[WSCookie] = buildCookies(headers)
-
- /**
- * Get only one cookie, using the cookie name.
- */
- override def cookie(name: String): Option[WSCookie] = cookies.find(_.name == name)
-
- /**
- * THIS IS A BLOCKING OPERATION. It should not be used in production.
- *
- * Note that this is not a charset aware operation, as the stream does not have access to the underlying machinery
- * that disambiguates responses.
- *
- * @return the body as a String
- */
- override lazy val body: String = bodyAsBytes.decodeString(AhcWSUtils.getCharset(contentType))
-
- /**
- * THIS IS A BLOCKING OPERATION. It should not be used in production.
- *
- * Note that this is not a charset aware operation, as the stream does not have access to the underlying machinery
- * that disambiguates responses.
- *
- * @return the body as a ByteString
- */
- override lazy val bodyAsBytes: ByteString = client.blockingToByteString(bodyAsSource)
-
- override lazy val bodyAsSource: Source[ByteString, ?] = {
- Source
- .fromPublisher(publisher)
- .map((bodyPart: HttpResponseBodyPart) => ByteString.fromArray(bodyPart.getBodyPartBytes))
- }
-
-}
diff --git a/play-ahc-ws-standalone/src/main/scala/play/api/libs/ws/ahc/cache/CacheableResponse.scala b/play-ahc-ws-standalone/src/main/scala/play/api/libs/ws/ahc/cache/CacheableResponse.scala
index 16603ed0..64171a8b 100644
--- a/play-ahc-ws-standalone/src/main/scala/play/api/libs/ws/ahc/cache/CacheableResponse.scala
+++ b/play-ahc-ws-standalone/src/main/scala/play/api/libs/ws/ahc/cache/CacheableResponse.scala
@@ -4,6 +4,17 @@
package play.api.libs.ws.ahc.cache
+import org.slf4j.LoggerFactory
+import play.shaded.ahc.io.netty.buffer.ByteBuf
+import play.shaded.ahc.io.netty.buffer.Unpooled
+import play.shaded.ahc.io.netty.handler.codec.http.DefaultHttpHeaders
+import play.shaded.ahc.io.netty.handler.codec.http.HttpHeaders
+import play.shaded.ahc.io.netty.handler.codec.http.HttpHeaders.Names._
+import play.shaded.ahc.io.netty.handler.codec.http.cookie.Cookie
+import play.shaded.ahc.org.asynchttpclient._
+import play.shaded.ahc.org.asynchttpclient.uri.Uri
+import play.shaded.ahc.org.asynchttpclient.util.HttpUtils._
+
import java.io.ByteArrayInputStream
import java.io.IOException
import java.io.InputStream
@@ -14,15 +25,6 @@ import java.nio.charset.Charset
import java.nio.charset.StandardCharsets
import java.util
-import org.slf4j.LoggerFactory
-import play.shaded.ahc.io.netty.handler.codec.http.HttpHeaders.Names._
-import play.shaded.ahc.io.netty.handler.codec.http.cookie.Cookie
-import play.shaded.ahc.io.netty.handler.codec.http.DefaultHttpHeaders
-import play.shaded.ahc.io.netty.handler.codec.http.HttpHeaders
-import play.shaded.ahc.org.asynchttpclient._
-import play.shaded.ahc.org.asynchttpclient.uri.Uri
-import play.shaded.ahc.org.asynchttpclient.util.HttpUtils._
-
class CacheableResponseBuilder(ahcConfig: AsyncHttpClientConfig) {
private var bodyParts: List[CacheableHttpResponseBodyPart] = Nil
@@ -203,8 +205,9 @@ case class CacheableResponse(
}
private def buildCookies: util.List[Cookie] = {
- import play.shaded.ahc.org.asynchttpclient.util.MiscUtils.isNonEmpty
import play.shaded.ahc.io.netty.handler.codec.http.cookie.ClientCookieDecoder
+ import play.shaded.ahc.org.asynchttpclient.util.MiscUtils.isNonEmpty
+
import java.util.Collections
var setCookieHeaders = headers.getAll(SET_COOKIE2)
@@ -230,6 +233,8 @@ case class CacheableResponse(
override def getLocalAddress: SocketAddress = status.getLocalAddress
override def getRemoteAddress: SocketAddress = status.getRemoteAddress
+
+ override def getResponseBodyAsByteBuf: ByteBuf = Unpooled.wrappedBuffer(getResponseBodyAsByteBuffer())
}
object CacheableResponse {
@@ -290,6 +295,8 @@ class CacheableHttpResponseBodyPart(chunk: Array[Byte], last: Boolean) extends H
override def getBodyByteBuffer: ByteBuffer = ByteBuffer.wrap(chunk)
+ override def getBodyByteBuf: ByteBuf = Unpooled.wrappedBuffer(getBodyByteBuffer())
+
override def isLast: Boolean = super.isLast
override def length(): Int = if (chunk != null) chunk.length else 0
diff --git a/play-ahc-ws-standalone/src/main/scala/play/api/libs/ws/ahc/cache/CachingAsyncHttpClient.scala b/play-ahc-ws-standalone/src/main/scala/play/api/libs/ws/ahc/cache/CachingAsyncHttpClient.scala
index 5f59775b..b15bcc6f 100644
--- a/play-ahc-ws-standalone/src/main/scala/play/api/libs/ws/ahc/cache/CachingAsyncHttpClient.scala
+++ b/play-ahc-ws-standalone/src/main/scala/play/api/libs/ws/ahc/cache/CachingAsyncHttpClient.scala
@@ -4,15 +4,13 @@
package play.api.libs.ws.ahc.cache
-import java.io._
-import java.util.function.Predicate
-import java.time.ZonedDateTime
-
import org.slf4j.LoggerFactory
import play.shaded.ahc.io.netty.handler.codec.http.DefaultHttpHeaders
-import play.shaded.ahc.org.asynchttpclient.handler.StreamedAsyncHandler
import play.shaded.ahc.org.asynchttpclient.{ Response => AHCResponse, _ }
+import java.io._
+import java.time.ZonedDateTime
+import java.util.function.Predicate
import scala.concurrent.Await
import scala.concurrent.ExecutionContext
@@ -53,10 +51,6 @@ class CachingAsyncHttpClient(underlying: AsyncHttpClient, ahcHttpCache: AhcHttpC
case asyncCompletionHandler: AsyncCompletionHandler[T] =>
execute(request, asyncCompletionHandler, null)(ahcHttpCache.executionContext)
- case streamedHandler: StreamedAsyncHandler[T] =>
- // Streamed requests don't go through the cache
- underlying.executeRequest(request, streamedHandler)
-
case other =>
throw new IllegalStateException(s"Unknown handler type ${other.getClass.getName}")
}
diff --git a/play-ahc-ws-standalone/src/test/scala/play/api/libs/oauth/OAuthSpec.scala b/play-ahc-ws-standalone/src/test/scala/play/api/libs/oauth/OAuthSpec.scala
deleted file mode 100644
index cbe5f748..00000000
--- a/play-ahc-ws-standalone/src/test/scala/play/api/libs/oauth/OAuthSpec.scala
+++ /dev/null
@@ -1,15 +0,0 @@
-/*
- * Copyright (C) from 2022 The Play Framework Contributors , 2011-2021 Lightbend Inc.
- */
-
-package play.api.libs.oauth
-
-import org.specs2.mutable.Specification
-
-class OAuthSpec extends Specification {
- "OAuth" should {
- "be able to use signpost OAuth" in {
- Class.forName("play.shaded.oauth.oauth.signpost.OAuth") must not(throwA[ClassNotFoundException])
- }
- }
-}
diff --git a/play-ahc-ws-standalone/src/test/scala/play/api/libs/ws/ahc/AhcConfigBuilderSpec.scala b/play-ahc-ws-standalone/src/test/scala/play/api/libs/ws/ahc/AhcConfigBuilderSpec.scala
index c597fcdb..776d5934 100644
--- a/play-ahc-ws-standalone/src/test/scala/play/api/libs/ws/ahc/AhcConfigBuilderSpec.scala
+++ b/play-ahc-ws-standalone/src/test/scala/play/api/libs/ws/ahc/AhcConfigBuilderSpec.scala
@@ -4,17 +4,16 @@
package play.api.libs.ws.ahc
-import com.typesafe.config.Config
-import com.typesafe.config.ConfigFactory
-import com.typesafe.sslconfig.ssl.Protocols
-import com.typesafe.sslconfig.ssl.SSLConfigFactory
-import com.typesafe.sslconfig.ssl.SSLConfigSettings
+import com.typesafe.config.{Config, ConfigFactory}
+import com.typesafe.sslconfig.ssl.{Protocols, SSLConfigFactory, SSLConfigSettings}
import org.specs2.mutable.Specification
import play.api.libs.ws.WSClientConfig
import play.shaded.ahc.org.asynchttpclient.proxy.ProxyServerSelector
import play.shaded.ahc.org.asynchttpclient.util.ProxyUtils
+import java.time.temporal.ChronoUnit
import scala.concurrent.duration._
+import scala.jdk.javaapi.DurationConverters.toJava
/**
*/
@@ -37,9 +36,9 @@ class AhcConfigBuilderSpec extends Specification {
.build()
ahcConfig.isCompressionEnforced must beFalse
ahcConfig.isFollowRedirect must beFalse
- ahcConfig.getConnectTimeout must_== 120000
- ahcConfig.getRequestTimeout must_== 120000
- ahcConfig.getReadTimeout must_== 120000
+ ahcConfig.getConnectTimeout must_== java.time.Duration.of(120000, ChronoUnit.MILLIS)
+ ahcConfig.getRequestTimeout must_== java.time.Duration.of(120000, ChronoUnit.MILLIS)
+ ahcConfig.getReadTimeout must_== java.time.Duration.of(120000, ChronoUnit.MILLIS)
}
"with basic options" should {
@@ -49,9 +48,9 @@ class AhcConfigBuilderSpec extends Specification {
val builder = new AhcConfigBuilder(config)
val actual = builder.build()
- actual.getReadTimeout must_== defaultWsConfig.idleTimeout.toMillis
- actual.getRequestTimeout must_== defaultWsConfig.requestTimeout.toMillis
- actual.getConnectTimeout must_== defaultWsConfig.connectionTimeout.toMillis
+ actual.getReadTimeout must_== toJava(Duration.fromNanos(defaultWsConfig.idleTimeout.toNanos))
+ actual.getRequestTimeout must_== toJava(Duration.fromNanos(defaultWsConfig.requestTimeout.toNanos))
+ actual.getConnectTimeout must_== toJava(Duration.fromNanos(defaultWsConfig.connectionTimeout.toNanos))
actual.isFollowRedirect must_== defaultWsConfig.followRedirects
actual.getCookieStore must_== null
@@ -64,7 +63,7 @@ class AhcConfigBuilderSpec extends Specification {
val builder = new AhcConfigBuilder(config)
val actual = builder.build()
- actual.getReadTimeout must_== 42L
+ actual.getReadTimeout must_== java.time.Duration.of(42, ChronoUnit.MILLIS)
}
"use an explicit request timeout" in {
@@ -73,7 +72,7 @@ class AhcConfigBuilderSpec extends Specification {
val builder = new AhcConfigBuilder(config)
val actual = builder.build()
- actual.getRequestTimeout must_== 47L
+ actual.getRequestTimeout must_== java.time.Duration.of(47, ChronoUnit.MILLIS)
}
"use an explicit connection timeout" in {
@@ -82,7 +81,7 @@ class AhcConfigBuilderSpec extends Specification {
val builder = new AhcConfigBuilder(config)
val actual = builder.build()
- actual.getConnectTimeout must_== 99L
+ actual.getConnectTimeout must_== java.time.Duration.of(99, ChronoUnit.MILLIS)
}
"use an explicit followRedirects option" in {
diff --git a/play-ahc-ws-standalone/src/test/scala/play/api/libs/ws/ahc/AhcWSRequestSpec.scala b/play-ahc-ws-standalone/src/test/scala/play/api/libs/ws/ahc/AhcWSRequestSpec.scala
index 6dc7d9b4..8efc0296 100644
--- a/play-ahc-ws-standalone/src/test/scala/play/api/libs/ws/ahc/AhcWSRequestSpec.scala
+++ b/play-ahc-ws-standalone/src/test/scala/play/api/libs/ws/ahc/AhcWSRequestSpec.scala
@@ -4,28 +4,21 @@
package play.api.libs.ws.ahc
-import scala.jdk.CollectionConverters._
-import scala.concurrent.duration._
-
import org.apache.pekko.actor.ActorSystem
import org.apache.pekko.stream.Materializer
import org.apache.pekko.util.ByteString
-
import org.mockito.Mockito
import org.specs2.execute.Result
import org.specs2.mutable.Specification
import org.specs2.specification.AfterAll
-
-import play.api.libs.oauth.ConsumerKey
-import play.api.libs.oauth.RequestToken
-import play.api.libs.oauth.OAuthCalculator
import play.api.libs.ws._
import play.shaded.ahc.io.netty.handler.codec.http.HttpHeaderNames
import play.shaded.ahc.org.asynchttpclient.Realm.AuthScheme
-import play.shaded.ahc.org.asynchttpclient.SignatureCalculator
-import play.shaded.ahc.org.asynchttpclient.Param
-import play.shaded.ahc.org.asynchttpclient.{ Request => AHCRequest }
+import play.shaded.ahc.org.asynchttpclient.{Param, SignatureCalculator, Request => AHCRequest}
+import java.time.temporal.ChronoUnit
+import scala.concurrent.duration._
+import scala.jdk.CollectionConverters._
import scala.reflect.ClassTag
class AhcWSRequestSpec extends Specification with AfterAll with DefaultBodyReadables with DefaultBodyWritables {
@@ -356,45 +349,6 @@ class AhcWSRequestSpec extends Specification with AfterAll with DefaultBodyReada
}
}
- "Have form params for content type application/x-www-form-urlencoded when signed" in {
- withClient { client =>
- import scala.jdk.CollectionConverters._
- val consumerKey = ConsumerKey("key", "secret")
- val requestToken = RequestToken("token", "secret")
- val calc = OAuthCalculator(consumerKey, requestToken)
- val req: AHCRequest = client
- .url("http://playframework.com/")
- .withBody(Map("param1" -> Seq("value1")))
- .sign(calc)
- .asInstanceOf[StandaloneAhcWSRequest]
- .buildRequest()
- // Note we use getFormParams instead of getByteData here.
- req.getFormParams.asScala must containTheSameElementsAs(
- List(new play.shaded.ahc.org.asynchttpclient.Param("param1", "value1"))
- )
- req.getByteData must beNull // should NOT result in byte data.
-
- val headers = req.getHeaders
- headers.get("Content-Length") must beNull
- }
- }
-
- "Parse no params for empty params map" in {
- withClient { client =>
- val consumerKey = ConsumerKey("key", "secret")
- val requestToken = RequestToken("token", "secret")
- val calc = OAuthCalculator(consumerKey, requestToken)
- val reqEmptyParams: AHCRequest = client
- .url("http://playframework.com/")
- .withBody(Map.empty[String, Seq[String]])
- .sign(calc)
- .asInstanceOf[StandaloneAhcWSRequest]
- .buildRequest()
-
- reqEmptyParams.getFormParams.asScala must beEmpty
- }
- }
-
"Have form body for content type text/plain" in {
withClient { client =>
val req: AHCRequest = client
@@ -595,7 +549,7 @@ class AhcWSRequestSpec extends Specification with AfterAll with DefaultBodyReada
.withRequestTimeout(1000.millis)
.asInstanceOf[StandaloneAhcWSRequest]
.buildRequest()
- (req.getRequestTimeout must be).equalTo(1000)
+ (req.getRequestTimeout must be).equalTo(java.time.Duration.of(1000, ChronoUnit.MILLIS))
}
"infinite timeout" in withClient { client =>
@@ -604,7 +558,7 @@ class AhcWSRequestSpec extends Specification with AfterAll with DefaultBodyReada
.withRequestTimeout(Duration.Inf)
.asInstanceOf[StandaloneAhcWSRequest]
.buildRequest()
- (req.getRequestTimeout must be).equalTo(-1)
+ (req.getRequestTimeout must be).equalTo(java.time.Duration.ZERO)
}
"no negative timeout" in withClient { client =>
@@ -652,27 +606,6 @@ class AhcWSRequestSpec extends Specification with AfterAll with DefaultBodyReada
headers.get("Content-Length") must_== "9001"
}
- "Remove a user defined content length header if we are parsing body explicitly when signed" in withClient { client =>
- import scala.jdk.CollectionConverters._
- val consumerKey = ConsumerKey("key", "secret")
- val requestToken = RequestToken("token", "secret")
- val calc = OAuthCalculator(consumerKey, requestToken)
- val req: AHCRequest = client
- .url("http://playframework.com/")
- .withBody(Map("param1" -> Seq("value1")))
- .withHttpHeaders("Content-Length" -> "9001") // add a meaningless content length here...
- .sign(calc) // this is signed, so content length is no longer valid per #5221
- .asInstanceOf[StandaloneAhcWSRequest]
- .buildRequest()
-
- val headers = req.getHeaders
- req.getByteData must beNull // should NOT result in byte data.
- req.getFormParams.asScala must containTheSameElementsAs(
- List(new play.shaded.ahc.org.asynchttpclient.Param("param1", "value1"))
- )
- headers.get("Content-Length") must beNull // no content length!
- }
-
"Verify Content-Type header is passed through correctly" in withClient { client =>
import scala.jdk.CollectionConverters._
val req: AHCRequest = client
@@ -683,5 +616,4 @@ class AhcWSRequestSpec extends Specification with AfterAll with DefaultBodyReada
.buildRequest()
req.getHeaders.getAll(HttpHeaderNames.CONTENT_TYPE.toString()).asScala must_== Seq("text/plain; charset=US-ASCII")
}
-
}
diff --git a/play-ahc-ws-standalone/src/test/scala/play/api/libs/ws/ahc/AhcWSResponseSpec.scala b/play-ahc-ws-standalone/src/test/scala/play/api/libs/ws/ahc/AhcWSResponseSpec.scala
index c3ad346d..b58561f7 100644
--- a/play-ahc-ws-standalone/src/test/scala/play/api/libs/ws/ahc/AhcWSResponseSpec.scala
+++ b/play-ahc-ws-standalone/src/test/scala/play/api/libs/ws/ahc/AhcWSResponseSpec.scala
@@ -4,19 +4,17 @@
package play.api.libs.ws.ahc
-import java.nio.charset.StandardCharsets
-import java.util
-
import org.apache.pekko.util.ByteString
-import org.mockito.Mockito.when
import org.mockito.Mockito
+import org.mockito.Mockito.when
import org.specs2.mutable.Specification
import play.api.libs.ws._
import play.shaded.ahc.io.netty.handler.codec.http.DefaultHttpHeaders
-import play.shaded.ahc.io.netty.handler.codec.http.cookie.DefaultCookie
-import play.shaded.ahc.io.netty.handler.codec.http.cookie.{ Cookie => AHCCookie }
-import play.shaded.ahc.org.asynchttpclient.{ Response => AHCResponse }
+import play.shaded.ahc.io.netty.handler.codec.http.cookie.{DefaultCookie, Cookie => AHCCookie}
+import play.shaded.ahc.org.asynchttpclient.{Response => AHCResponse}
+import java.nio.charset.StandardCharsets
+import java.util
import scala.reflect.ClassTag
class AhcWSResponseSpec extends Specification with DefaultBodyReadables with DefaultBodyWritables {
@@ -128,14 +126,6 @@ class AhcWSResponseSpec extends Specification with DefaultBodyReadables with Def
headers.contains("Bar") must beTrue
}
- "get headers map which retrieves headers case insensitively (for streamed responses)" in {
- val srcHeaders = Map("Foo" -> Seq("a"), "foo" -> Seq("b"), "FOO" -> Seq("b"), "Bar" -> Seq("baz"))
- val response = new StreamedResponse(null, 200, "", null, srcHeaders, null, true)
- val headers = response.headers
- headers("foo") must_== Seq("a", "b", "b")
- headers("BAR") must_== Seq("baz")
- }
-
"get a single header" in {
val ahcResponse: AHCResponse = mock[AHCResponse]
val ahcHeaders = new DefaultHttpHeaders(true)
diff --git a/play-ahc-ws-standalone/src/test/scala/play/libs/ws/ahc/AhcWSRequestSpec.scala b/play-ahc-ws-standalone/src/test/scala/play/libs/ws/ahc/AhcWSRequestSpec.scala
index fa27a44d..4aad13fe 100644
--- a/play-ahc-ws-standalone/src/test/scala/play/libs/ws/ahc/AhcWSRequestSpec.scala
+++ b/play-ahc-ws-standalone/src/test/scala/play/libs/ws/ahc/AhcWSRequestSpec.scala
@@ -5,20 +5,15 @@
package play.libs.ws.ahc
import com.typesafe.config.ConfigFactory
-
-import java.time.Duration
-import java.util.Collections
-
import org.specs2.mutable._
-import play.libs.oauth.OAuth
import play.libs.ws._
import play.shaded.ahc.io.netty.handler.codec.http.HttpHeaderNames
-import play.shaded.ahc.org.asynchttpclient.Request
-import play.shaded.ahc.org.asynchttpclient.RequestBuilderBase
-import play.shaded.ahc.org.asynchttpclient.SignatureCalculator
+import play.shaded.ahc.org.asynchttpclient.{Request, RequestBuilderBase, SignatureCalculator}
-import scala.jdk.CollectionConverters._
+import java.time.Duration
+import java.util.Collections
import scala.collection.mutable
+import scala.jdk.CollectionConverters._
import scala.jdk.OptionConverters._
class AhcWSRequestSpec extends Specification with DefaultBodyReadables with DefaultBodyWritables {
@@ -129,50 +124,6 @@ class AhcWSRequestSpec extends Specification with DefaultBodyReadables with Defa
List(new play.shaded.ahc.org.asynchttpclient.Param("param1", "value1"))
)
}
-
- "have form params when content-type application/x-www-form-urlencoded and signed" in {
- import scala.jdk.CollectionConverters._
- val client = StandaloneAhcWSClient.create(
- AhcWSClientConfigFactory.forConfig(ConfigFactory.load(), this.getClass.getClassLoader), /*materializer*/ null
- )
- val consumerKey = new OAuth.ConsumerKey("key", "secret")
- val token = new OAuth.RequestToken("token", "secret")
- val calc = new OAuth.OAuthCalculator(consumerKey, token)
- val req = new StandaloneAhcWSRequest(client, "http://playframework.com/", null)
- .setContentType("application/x-www-form-urlencoded") // set content type by hand
- .setBody(body("param1=value1"))
- .sign(calc)
- .asInstanceOf[StandaloneAhcWSRequest]
- .buildRequest()
- // Note we use getFormParams instead of getByteData here.
- req.getFormParams.asScala must containTheSameElementsAs(
- List(new play.shaded.ahc.org.asynchttpclient.Param("param1", "value1"))
- )
- }
-
- "remove a user defined content length header if we are parsing body explicitly when signed" in {
- import scala.jdk.CollectionConverters._
- val client = StandaloneAhcWSClient.create(
- AhcWSClientConfigFactory.forConfig(ConfigFactory.load(), this.getClass.getClassLoader), /*materializer*/ null
- )
- val consumerKey = new OAuth.ConsumerKey("key", "secret")
- val token = new OAuth.RequestToken("token", "secret")
- val calc = new OAuth.OAuthCalculator(consumerKey, token)
- val req = new StandaloneAhcWSRequest(client, "http://playframework.com/", null)
- .setContentType("application/x-www-form-urlencoded") // set content type by hand
- .setBody(body("param1=value1"))
- .addHeader("Content-Length", "9001") // add a meaningless content length here...
- .sign(calc)
- .asInstanceOf[StandaloneAhcWSRequest]
- .buildRequest()
-
- val headers = req.getHeaders
- req.getFormParams.asScala must containTheSameElementsAs(
- List(new play.shaded.ahc.org.asynchttpclient.Param("param1", "value1"))
- )
- headers.get("Content-Length") must beNull // no content length!
- }
-
}
"Use a custom signature calculator" in {
@@ -194,22 +145,24 @@ class AhcWSRequestSpec extends Specification with DefaultBodyReadables with Defa
"setRequestTimeout(java.time.Duration)" should {
"support setting a request timeout to a duration" in {
- requestWithTimeout(Duration.ofSeconds(1)) must beEqualTo(1000)
+ requestWithTimeout(Duration.ofSeconds(1)) must beEqualTo(Duration.ofSeconds(1))
}
"support setting a request timeout duration to infinite using -1" in {
- requestWithTimeout(Duration.ofMillis(-1)) must beEqualTo(-1)
+ requestWithTimeout(Duration.ofMillis(-1)) must beEqualTo(Duration.ofMillis(-1))
}
"support setting a request timeout duration to infinite using any negative duration" in {
- requestWithTimeout(Duration.ofMillis(-2)) must beEqualTo(-1)
- requestWithTimeout(Duration.ofMillis(-15)) must beEqualTo(-1)
- requestWithTimeout(Duration.ofSeconds(-1)) must beEqualTo(-1)
- requestWithTimeout(Duration.ofMillis(java.lang.Integer.MIN_VALUE)) must beEqualTo(-1)
+ requestWithTimeout(Duration.ofMillis(-2)) must beEqualTo(Duration.ofMillis(-1))
+ requestWithTimeout(Duration.ofMillis(-15)) must beEqualTo(Duration.ofMillis(-1))
+ requestWithTimeout(Duration.ofSeconds(-1)) must beEqualTo(Duration.ofMillis(-1))
+ requestWithTimeout(Duration.ofMillis(java.lang.Integer.MIN_VALUE)) must beEqualTo(Duration.ofMillis(-1))
}
"support setting a request timeout duration to Long.MAX_VALUE as infinite" in {
- requestWithTimeout(Duration.ofMillis(java.lang.Long.MAX_VALUE)) must beEqualTo(-1)
+ requestWithTimeout(Duration.ofMillis(java.lang.Long.MAX_VALUE)) must beEqualTo(
+ Duration.ofMillis(java.lang.Long.MAX_VALUE)
+ )
}
"not support setting a request timeout to null" in {
diff --git a/play-ws-standalone/src/main/java/play/libs/ws/StandaloneWSRequest.java b/play-ws-standalone/src/main/java/play/libs/ws/StandaloneWSRequest.java
index 7e06af07..8e22c70f 100644
--- a/play-ws-standalone/src/main/java/play/libs/ws/StandaloneWSRequest.java
+++ b/play-ws-standalone/src/main/java/play/libs/ws/StandaloneWSRequest.java
@@ -122,15 +122,6 @@ public interface StandaloneWSRequest {
*/
CompletionStage extends StandaloneWSResponse> execute();
- /**
- * Executes this request and streams the response body.
- *
- * Use {@code response.bodyAsSource()} with this method.
- *
- * @return a promise to the response
- */
- CompletionStage extends StandaloneWSResponse> stream();
-
//-------------------------------------------------------------------------
// Setters
//-------------------------------------------------------------------------
diff --git a/play-ws-standalone/src/main/scala/play/api/libs/ws/StandaloneWSRequest.scala b/play-ws-standalone/src/main/scala/play/api/libs/ws/StandaloneWSRequest.scala
index 2f835956..e4826b8c 100644
--- a/play-ws-standalone/src/main/scala/play/api/libs/ws/StandaloneWSRequest.scala
+++ b/play-ws-standalone/src/main/scala/play/api/libs/ws/StandaloneWSRequest.scala
@@ -5,7 +5,6 @@
package play.api.libs.ws
import java.net.URI
-
import scala.concurrent.Future
import scala.concurrent.duration.Duration
@@ -275,9 +274,4 @@ trait StandaloneWSRequest {
*/
def execute(): Future[Response]
- /**
- * Execute this request and stream the response body.
- */
- def stream(): Future[Response]
-
}
diff --git a/project/Dependencies.scala b/project/Dependencies.scala
index 65eaa815..470b2a60 100644
--- a/project/Dependencies.scala
+++ b/project/Dependencies.scala
@@ -1,7 +1,7 @@
/*
* Copyright (C) from 2022 The Play Framework Contributors , 2011-2021 Lightbend Inc.
*/
-import sbt._
+import sbt.*
object Dependencies {
@@ -40,11 +40,7 @@ object Dependencies {
val cachecontrol = Seq("org.playframework" %% "cachecontrol" % "3.1.0-M2")
- val asyncHttpClient = Seq(
- ("org.asynchttpclient" % "async-http-client" % "2.12.4") // 2.12.x comes with outdated netty-reactive-streams, so we ...
- .exclude("com.typesafe.netty", "netty-reactive-streams"), // ... exclude it and pull in ...
- "com.typesafe.netty" % "netty-reactive-streams" % "2.0.14", // ... a newer version ourselves (ahc v3 will drop that dependency)
- )
+ val asyncHttpClient = Seq("org.asynchttpclient" % "async-http-client" % "3.0.2")
val pekkoVersion = "1.0.3"