Using Play WS and getting java.net.ConnectExceptio

2019-07-08 10:46发布

问题:

Within my Play application I need to download a large number of files from Amazon Cloudfront. Using SSL I'm getting the following error randomly on a link:

play.api.http.HttpErrorHandlerExceptions$$anon$1: Execution exception[[ConnectException: handshake timed out]]
at play.api.http.HttpErrorHandlerExceptions$.throwableToUsefulException(HttpErrorHandler.scala:280)
at play.api.http.DefaultHttpErrorHandler.onServerError(HttpErrorHandler.scala:206)
at play.api.GlobalSettings$class.onError(GlobalSettings.scala:160)
at play.api.DefaultGlobal$.onError(GlobalSettings.scala:188)
at play.api.http.GlobalSettingsHttpErrorHandler.onServerError(HttpErrorHandler.scala:98)
at play.core.server.netty.PlayRequestHandler$$anonfun$2$$anonfun$apply$1.applyOrElse(PlayRequestHandler.scala:99)
at play.core.server.netty.PlayRequestHandler$$anonfun$2$$anonfun$apply$1.applyOrElse(PlayRequestHandler.scala:98)
at scala.concurrent.Future$$anonfun$recoverWith$1.apply(Future.scala:346)
at scala.concurrent.Future$$anonfun$recoverWith$1.apply(Future.scala:345)
at scala.concurrent.impl.CallbackRunnable.run(Promise.scala:32)
Caused by: java.net.ConnectException: handshake timed out
at org.asynchttpclient.netty.channel.NettyConnectListener.onFailure(NettyConnectListener.java:137)
at org.asynchttpclient.netty.channel.NettyConnectListener$1.onFailure(NettyConnectListener.java:108)
at org.asynchttpclient.netty.SimpleFutureListener.operationComplete(SimpleFutureListener.java:26)
at io.netty.util.concurrent.DefaultPromise.notifyListener0(DefaultPromise.java:514)
at io.netty.util.concurrent.DefaultPromise.notifyListeners0(DefaultPromise.java:507)
at io.netty.util.concurrent.DefaultPromise.notifyListenersNow(DefaultPromise.java:486)
at io.netty.util.concurrent.DefaultPromise.notifyListeners(DefaultPromise.java:427)
at io.netty.util.concurrent.DefaultPromise.tryFailure(DefaultPromise.java:129)
at io.netty.handler.ssl.SslHandler.notifyHandshakeFailure(SslHandler.java:1235)
at io.netty.handler.ssl.SslHandler.access$700(SslHandler.java:160)
Caused by: javax.net.ssl.SSLException: handshake timed out
at io.netty.handler.ssl.SslHandler.handshake(...)(Unknown Source)

Mostly its also only one that fails. The rest still downloads.

So I have an play 2.5.8 application in which I use the default ws client. This Play version uses by default netty-handler 4.0.33-FINAL version. I even update the netty-handler to 4.0.41.Final but this didn't help.

I'm generating the cloudfront url with the aws-java-sdk-cloudfront" % "1.11.39" library using the CloudFrontUrlSigner.getSignedURLWithCustomPolicy(protocol, host, privateKeyFile, path, keyPairId, dateLessThan, dateGreaterThan, ip)

val data = for {
  records <- (onStore(model) withDomain None).list()
  recordsWithData = addBucketData(withCloudFrontUrl(request.remoteAddress))(records)
} yield Future.sequence(recordsWithData)

private def addBucketData(urlGenerator: String => Future[String]): Seq[JsObject] => Seq[Future[JsObject]] = { records =>
  records.map(record => {
    val id = (record \ "id").as[String]

    urlGenerator(id).map(url => {
      val encodedString = ws.url(url).get().map(result =>
         org.apache.commons.codec.binary.Base64.encodeBase64String(result.bodyAsBytes.toArray)
      )

      encodedString.map(data => record ++ Json.obj("data" -> data))
    }).flatMap(x => x)
  })
}

Does anybody have an idea on what the problem is?

After some debugging the (actual) problem seem to be:

%% Invalidated:  [Session-339, TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256]
AsyncHttpClient-2-8, SEND TLSv1.2 ALERT:  fatal, description = internal_error
AsyncHttpClient-2-8, Exception sending alert: java.io.IOException: writer side was already closed.
AsyncHttpClient-2-8, called closeOutbound()
AsyncHttpClient-2-8, closeOutboundInternal()
AsyncHttpClient-2-8, SEND TLSv1.2 ALERT:  warning, description = close_notify
AsyncHttpClient-2-8, WRITE: TLSv1.2 Alert, length = 2
AsyncHttpClient-2-8, called closeInbound()
AsyncHttpClient-2-8, fatal error: 80: Inbound closed before receiving peer's close_notify: possible truncation attack?
javax.net.ssl.SSLException: Inbound closed before receiving peer's close_notify: possible truncation attack?
%% Invalidated:  [Session-340, TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256]
AsyncHttpClient-2-8, SEND TLSv1.2 ALERT:  fatal, description = internal_error
AsyncHttpClient-2-8, Exception sending alert: java.io.IOException: writer side was already closed.
AsyncHttpClient-2-8, called closeOutbound()
AsyncHttpClient-2-8, closeOutboundInternal()
AsyncHttpClient-2-8, SEND TLSv1.2 ALERT:  warning, description = close_notify
AsyncHttpClient-2-8, WRITE: TLSv1.2 Alert, length = 2
AsyncHttpClient-2-8, called closeInbound()
AsyncHttpClient-2-8, fatal error: 80: Inbound closed before receiving peer's close_notify: possible truncation attack?
javax.net.ssl.SSLException: Inbound closed before receiving peer's close_notify: possible truncation attack?
%% Invalidated:  [Session-341, TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256]
AsyncHttpClient-2-8, SEND TLSv1.2 ALERT:  fatal, description = internal_error
AsyncHttpClient-2-8, Exception sending alert: java.io.IOException: writer side was already closed.
[Raw read (bb)]: length = 12899