Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Java version of curl request filter #178

Merged
merged 14 commits into from
Jun 14, 2018
Merged
28 changes: 20 additions & 8 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,26 @@ lazy val mimaSettings = mimaDefaultSettings ++ Seq(
mimaBinaryIssueFilters ++= Seq(
ProblemFilters.exclude[DirectMissingMethodProblem]("play.libs.ws.ahc.StandaloneAhcWSResponse.getBodyAsSource"),
ProblemFilters.exclude[MissingClassProblem]("play.api.libs.ws.package$"),
ProblemFilters.exclude[MissingClassProblem]("play.api.libs.ws.package")
ProblemFilters.exclude[MissingClassProblem]("play.api.libs.ws.package"),

// Implemented as a default method at the interface
ProblemFilters.exclude[DirectMissingMethodProblem]("play.libs.ws.ahc.StandaloneAhcWSResponse.getBodyAsSource"),

// Added to have better parity between Java and Scala APIs
ProblemFilters.exclude[ReversedMissingMethodProblem]("play.libs.ws.StandaloneWSRequest.getBody"),
ProblemFilters.exclude[ReversedMissingMethodProblem]("play.libs.ws.StandaloneWSRequest.getAuth"),
ProblemFilters.exclude[ReversedMissingMethodProblem]("play.libs.ws.StandaloneWSRequest.getMethod"),
ProblemFilters.exclude[ReversedMissingMethodProblem]("play.libs.ws.StandaloneWSRequest.setAuth"),

// Now have a default implementation at the interface
ProblemFilters.exclude[DirectMissingMethodProblem]("play.libs.ws.ahc.StandaloneAhcWSRequest.getPassword"),
ProblemFilters.exclude[DirectMissingMethodProblem]("play.libs.ws.ahc.StandaloneAhcWSRequest.getUsername"),
ProblemFilters.exclude[DirectMissingMethodProblem]("play.libs.ws.ahc.StandaloneAhcWSRequest.setAuth"),
ProblemFilters.exclude[DirectMissingMethodProblem]("play.libs.ws.ahc.StandaloneAhcWSRequest.getScheme"),

// Add getUri method
ProblemFilters.exclude[ReversedMissingMethodProblem]("play.libs.ws.StandaloneWSResponse.getUri"),
ProblemFilters.exclude[ReversedMissingMethodProblem]("play.api.libs.ws.StandaloneWSResponse.uri")
)
)

Expand Down Expand Up @@ -269,10 +288,6 @@ lazy val `play-ws-standalone` = project
.in(file("play-ws-standalone"))
.settings(commonSettings ++ Seq(
libraryDependencies ++= standaloneApiWSDependencies,
mimaBinaryIssueFilters ++= Seq(
ProblemFilters.exclude[ReversedMissingMethodProblem]("play.libs.ws.StandaloneWSResponse.getUri"),
ProblemFilters.exclude[ReversedMissingMethodProblem]("play.api.libs.ws.StandaloneWSResponse.uri")
),
mimaPreviousArtifacts := mimaPreviousArtifactFor(scalaVersion.value, "com.typesafe.play" %% "play-ws-standalone" % "1.0.0"))
)
.disablePlugins(sbtassembly.AssemblyPlugin)
Expand Down Expand Up @@ -304,9 +319,6 @@ lazy val `play-ahc-ws-standalone` = project
Tests.Argument(TestFrameworks.JUnit, "-a", "-v")),
libraryDependencies ++= standaloneAhcWSDependencies,
mimaPreviousArtifacts := mimaPreviousArtifactFor(scalaVersion.value, "com.typesafe.play" %% "play-ahc-ws-standalone" % "1.0.0"),
mimaBinaryIssueFilters ++= Seq(
ProblemFilters.exclude[DirectMissingMethodProblem](
"play.libs.ws.ahc.StandaloneAhcWSResponse.getBodyAsSource")),
// This will not work if you do a publishLocal, because that uses ivy...
pomPostProcess := {
(node: xml.Node) => addShadedDeps(List(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
/*
* Copyright (C) 2009-2017 Lightbend Inc. <https://www.lightbend.com>
*/
package play.libs.ws.ahc

import akka.http.scaladsl.server.Route
import org.specs2.concurrent.{ ExecutionEnv, FutureAwait }
import org.specs2.mutable.Specification
import play.AkkaServerProvider
import play.libs.ws.{ DefaultBodyWritables, DefaultWSCookie, WSAuthInfo, WSAuthScheme }
import uk.org.lidalia.slf4jext.Level
import uk.org.lidalia.slf4jtest.{ TestLogger, TestLoggerFactory }

import scala.collection.JavaConverters._
import scala.compat.java8.FutureConverters._

class AhcCurlRequestLoggerSpec(implicit val executionEnv: ExecutionEnv) extends Specification
with AkkaServerProvider
with StandaloneWSClientSupport
with FutureAwait
with DefaultBodyWritables {

override def routes: Route = {
import akka.http.scaladsl.server.Directives._
get {
complete("<h1>Say hello to akka-http</h1>")
} ~
post {
entity(as[String]) { echo =>
complete(echo)
}
}
}

// Level.OFF because we don't want to pollute the test output
def createTestLogger: TestLogger = new TestLoggerFactory(Level.OFF).getLogger("test-logger")

"Logging request as curl" should {

"be verbose" in withClient() { client =>

val testLogger = createTestLogger
val curlRequestLogger = new AhcCurlRequestLogger(testLogger)

client.url(s"http://localhost:$testServerPort/")
.setRequestFilter(curlRequestLogger)
.get()
.toScala
.awaitFor(defaultTimeout)

testLogger.getLoggingEvents.asScala.map(_.getMessage) must containMatch("--verbose")
}

"add all headers" in withClient() { client =>

val testLogger = createTestLogger
val curlRequestLogger = new AhcCurlRequestLogger(testLogger)

client.url(s"http://localhost:$testServerPort/")
.addHeader("My-Header", "My-Header-Value")
.setRequestFilter(curlRequestLogger)
.get()
.toScala
.awaitFor(defaultTimeout)

val messages = testLogger.getLoggingEvents.asScala.map(_.getMessage)

messages must containMatch("--header 'My-Header: My-Header-Value'")
}

"add all cookies" in withClient() { client =>

val testLogger = createTestLogger
val curlRequestLogger = new AhcCurlRequestLogger(testLogger)

client.url(s"http://localhost:$testServerPort/")
.addCookie(new DefaultWSCookie("cookie1", "value1", "localhost", "path", 10L, true, true))
.setRequestFilter(curlRequestLogger)
.get()
.toScala
.awaitFor(defaultTimeout)

val messages = testLogger.getLoggingEvents.asScala.map(_.getMessage)

messages must containMatch("""--cookie 'cookie1=value1'""")
}

"add method" in withClient() { client =>

val testLogger = createTestLogger
val curlRequestLogger = new AhcCurlRequestLogger(testLogger)

client.url(s"http://localhost:$testServerPort/")
.setRequestFilter(curlRequestLogger)
.get()
.toScala
.awaitFor(defaultTimeout)

testLogger.getLoggingEvents.asScala.map(_.getMessage) must containMatch("--request GET")
}

"add authorization header" in withClient() { client =>

val testLogger = createTestLogger
val curlRequestLogger = new AhcCurlRequestLogger(testLogger)

client.url(s"http://localhost:$testServerPort/")
.setAuth(new WSAuthInfo("username", "password", WSAuthScheme.BASIC))
.setRequestFilter(curlRequestLogger)
.get()
.toScala
.awaitFor(defaultTimeout)

testLogger.getLoggingEvents.asScala.map(_.getMessage) must containMatch("""--header 'Authorization: Basic dXNlcm5hbWU6cGFzc3dvcmQ='""")
}

"handle body" in {

"add when in memory" in withClient() { client =>

val testLogger = createTestLogger
val curlRequestLogger = new AhcCurlRequestLogger(testLogger)

client.url(s"http://localhost:$testServerPort/")
.setBody(body("the-body"))
.setRequestFilter(curlRequestLogger)
.get()
.toScala
.awaitFor(defaultTimeout)

testLogger.getLoggingEvents.asScala.map(_.getMessage) must containMatch("the-body")
}

"do nothing for empty bodies" in withClient() { client =>

val testLogger = createTestLogger
val curlRequestLogger = new AhcCurlRequestLogger(testLogger)

// no body setBody, so body is "empty"
client.url(s"http://localhost:$testServerPort/")
.setRequestFilter(curlRequestLogger)
.get()
.toScala
.awaitFor(defaultTimeout)

testLogger.getLoggingEvents.asScala.map(_.getMessage) must not containMatch ("--data")
}
}

"print complete curl command" in withClient() { client =>

val testLogger = createTestLogger
val curlRequestLogger = new AhcCurlRequestLogger(testLogger)

client.url(s"http://localhost:$testServerPort/")
.setBody(body("the-body"))
.addHeader("My-Header", "My-Header-Value")
.setAuth(new WSAuthInfo("username", "password", WSAuthScheme.BASIC))
.setRequestFilter(curlRequestLogger)
.get()
.toScala
.awaitFor(defaultTimeout)

testLogger.getLoggingEvents.get(0).getMessage must beEqualTo(
s"""
|curl \\
| --verbose \\
| --request GET \\
| --header 'Authorization: Basic dXNlcm5hbWU6cGFzc3dvcmQ=' \\
| --header 'My-Header: My-Header-Value' \\
| --header 'Content-Type: text/plain' \\
| --data 'the-body' \\
| 'http://localhost:$testServerPort/'
""".stripMargin.trim)
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/*
* Copyright (C) 2009-2017 Lightbend Inc. <https://www.lightbend.com>
*/
package play.libs.ws.ahc

import akka.stream.Materializer
import org.specs2.execute.Result
import play.api.libs.ws.ahc.{ AhcConfigBuilder, AhcWSClientConfig, AhcWSClientConfigFactory => ScalaAhcWSClientConfigFactory }
import play.shaded.ahc.org.asynchttpclient.DefaultAsyncHttpClient

trait StandaloneWSClientSupport {

def materializer: Materializer

def withClient(config: AhcWSClientConfig = ScalaAhcWSClientConfigFactory.forConfig())(block: StandaloneAhcWSClient => Result): Result = {
val asyncHttpClient = new DefaultAsyncHttpClient(new AhcConfigBuilder(config).build())
val client = new StandaloneAhcWSClient(asyncHttpClient, materializer)
try {
block(client)
} finally {
client.close()
}
}
}
Loading