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

Akka-HTTP backend #208

Closed
wants to merge 40 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
843a076
A prototype of Akka Http backend
2m Dec 11, 2017
c3a19f1
Cleanup integration tests
2m Dec 11, 2017
90a0903
Implement request filters
2m Dec 11, 2017
4e14d8a
Add missing type annotations
2m Dec 11, 2017
fb866dc
Add test cases from Java api integration tests
2m Dec 12, 2017
93adff4
All http methods
2m Dec 13, 2017
0f1a115
Authentication support
2m Dec 13, 2017
d044a86
Virtualhost support
2m Dec 13, 2017
ef39d98
Request timeout support
2m Dec 13, 2017
0b4ff08
First part of the Java API implementation
2m Dec 14, 2017
726039f
Ported all scala integration tests over java implementation
2m Dec 14, 2017
fe481c9
Java API implementation using javadsl Akka Http API
2m Dec 15, 2017
c5b3bd7
Port RequestFilter spec to Java backends
2m Dec 18, 2017
7315488
Refactor Scala API RequestFilter tests
2m Dec 18, 2017
8065f62
Add missing copyright headers
2m Dec 18, 2017
d26cb84
Implement
2m Dec 18, 2017
57f33b7
Mark unimplemented features as FIXMEs
2m Dec 18, 2017
cdc2704
Implement get status text
2m Dec 18, 2017
2f80e22
Save strict response if response is unmarshalled
2m Dec 18, 2017
13dbf85
Fix dependencies
2m Dec 18, 2017
5b4c495
Use Http Method name constants
2m Dec 18, 2017
13dc162
Fix race condition in test setup
2m Dec 19, 2017
036fd4b
Remove api converters from a failed previous attempt
2m Dec 19, 2017
e0a88ae
Fix Scala 2.11 compilation
2m Dec 19, 2017
875ad53
Implement cookies
2m Dec 19, 2017
4d6d517
Complete request timeout support
2m Dec 19, 2017
c10f727
Complete virtual host support
2m Dec 19, 2017
082b787
Implement auth getters
2m Dec 20, 2017
e03db58
Implement getters for url, method, content type and body
2m Dec 20, 2017
62de06d
Fix content type spec
2m Dec 20, 2017
bc19089
Typo fix
2m Dec 20, 2017
311bd62
Implement content type getter on response
2m Dec 20, 2017
0f16eac
Port AHC unit tests as integration tests for all APIs and backends
2m Dec 20, 2017
9c81700
Remove unnecessary dependency
2m Dec 20, 2017
d248fa4
Remove unused imports
2m Dec 20, 2017
526042c
Https tests and context parameter
2m Dec 22, 2017
766ae0b
Disable AHC HTTPS test while AHC backend is not configured
2m Dec 22, 2017
9ce489b
Formatting changes after rebase
2m Jan 23, 2018
58323ad
Remove deprecated formatting settings after rebase
2m Jan 23, 2018
814d633
Provide custom dns records via akka dns resolver
2m Jan 23, 2018
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -319,6 +319,27 @@ lazy val `play-ahc-ws-standalone` = project
`shaded`
).disablePlugins(sbtassembly.AssemblyPlugin)

//---------------------------------------------------------------
// Akka Http implementation of WS
//---------------------------------------------------------------

lazy val `play-akka-http-ws-standalone` = project
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it might be worth naming play-akka-http-ws-experimental, since this is still in development and we could possibly change APIs. WDYT @marcospereira?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agree.

It would be consistent with the way we changed from Netty to Akka HTTP on the server backend. It is also easier to set users expectations.

.in(file("play-akka-http-ws-standalone"))
.settings(commonSettings)
.settings(formattingSettings)
.settings(
fork in Test := true,
testOptions in Test := Seq(Tests.Argument(TestFrameworks.JUnit, "-a", "-v"))
)
.settings(
// The scaladoc generation
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this a TODO?

)
.settings(libraryDependencies ++= standaloneAkkaHttpWSDependencies)
.dependsOn(
`play-ws-standalone`
)
.disablePlugins(sbtassembly.AssemblyPlugin)

//---------------------------------------------------------------
// JSON Readables and Writables
//---------------------------------------------------------------
Expand Down Expand Up @@ -380,6 +401,7 @@ lazy val `integration-tests` = project.in(file("integration-tests"))
.settings(shadedOAuthSettings)
.dependsOn(
`play-ahc-ws-standalone`,
`play-akka-http-ws-standalone`,
`play-ws-standalone-json`,
`play-ws-standalone-xml`
)
Expand All @@ -402,6 +424,7 @@ lazy val root = project
`play-ws-standalone-json`,
`play-ws-standalone-xml`,
`play-ahc-ws-standalone`,
`play-akka-http-ws-standalone`,
`integration-tests`
)
.disablePlugins(sbtassembly.AssemblyPlugin)
Expand Down
1 change: 1 addition & 0 deletions integration-tests/src/test/resources/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
The `rootCA.crt` and `server.p12` have been taken from [Akka Http Tls Tests Keys](https://github.com/akka/akka-http/tree/v10.0.11/akka-http-core/src/test/resources/keys).
21 changes: 21 additions & 0 deletions integration-tests/src/test/resources/rootCA.crt
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
-----BEGIN CERTIFICATE-----
MIIDXTCCAkWgAwIBAgIJANYwx08wP3STMA0GCSqGSIb3DQEBCwUAMEUxCzAJBgNV
BAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBX
aWRnaXRzIFB0eSBMdGQwHhcNMTUwNzIzMDk0ODI2WhcNMjUwNDIxMDk0ODI2WjBF
MQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50
ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB
CgKCAQEArk0K/Rn7uND2YGFBks5Sok1WvNdHQccPESEw2hNVF32ExAhbBXCrFaIl
Io0q4eYSbypeauEjDXB/NJXurEefL8ONXK62erJDKKQ0aTTYqsVifoNYA9ORWoGE
XhtAfOx4xvzr6vF1e3kz0PB/A4ftn0vvVygYnf/2E2bQZgaw8dXP5lIGasEzzigB
LX/qTEW/vBOL98Rxp6JvjwvYMbPSZGwNwSz+tI5W2psdE1Mga2Qnsv3j+STWlD9v
+JlgdN8r3PyR1sl3jC7gCj3AaOhv4RbAbqjwnZ9nrckx16PFiMtJiVRea7CQXN7g
191EVujQnlg1LOhiSMKwVsuoXr08ywIDAQABo1AwTjAdBgNVHQ4EFgQU2THI/ilU
M0xds3vZlV4CvhAZ1d8wHwYDVR0jBBgwFoAU2THI/ilUM0xds3vZlV4CvhAZ1d8w
DAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAK9LO0HyIi0xbTISsc+A5
LQyZowgRAGqsNNmni7NKDXauPLZrCfDVhvo/FPP1XSFShXo7ARvro9lul4AJlkNN
VgX0gbWtkiAx0uLqlbMsC6imj2L9boRse7mzI/Ymem5SNTn9GUnlMiZ74rca9UT4
Dk9YytrT4FSpomiL6z8Xj604W3RuLSdEfpfcn3Jh2tFSZ9hyLwB7ATUTA/yuj1SU
G1gmoPMvlnPzNj2lIqyIdQxGdxt+L3mFO20CxBkeieWqQuNptpjwptliFjkZJJZP
wQlx9qLLvs/eFC2AUWj+hbsl37PuARR9hoeqbKRcUjwGtaXOqikrvX1qzPc2+ij9
/w==
-----END CERTIFICATE-----
Binary file added integration-tests/src/test/resources/server.p12
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package akka.io
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any reason to have this inside akka.io package instead of play.api.ws?


import java.net.InetAddress

import scala.concurrent.duration._

class AkkaExampleOrgToLocalhostDnsProvider extends DnsProvider {
override def cache: Dns = {
val cache = new SimpleDnsCache()
cache.put(Dns.Resolved("akka.example.org", Seq(InetAddress.getByName("127.0.0.1"))), 1.hour.toMillis)
cache
}
override def actorClass = classOf[InetAddressDnsResolver]
override def managerClass = classOf[SimpleDnsManager]
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

good :)

79 changes: 68 additions & 11 deletions integration-tests/src/test/scala/play/AkkaServerProvider.scala
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,17 @@
*/
package play

import java.io.InputStream
import java.net.{ InetAddress, UnknownHostException }
import java.security.cert.CertificateFactory
import java.security.{ KeyStore, SecureRandom }
import javax.net.ssl.{ KeyManagerFactory, SSLContext, SSLParameters, TrustManagerFactory }

import akka.actor.ActorSystem
import akka.http.scaladsl.Http
import akka.http.scaladsl.{ Http, HttpsConnectionContext }
import akka.http.scaladsl.server.Route
import akka.stream.ActorMaterializer
import com.typesafe.config.ConfigFactory
import org.specs2.concurrent.ExecutionEnv
import org.specs2.specification.BeforeAfterAll

Expand All @@ -26,29 +33,79 @@ trait AkkaServerProvider extends BeforeAfterAll {
def executionEnv: ExecutionEnv

var testServerPort: Int = _
var testServerPortHttps: Int = _
val defaultTimeout: FiniteDuration = 5.seconds

// Create Akka system for thread and streaming management
implicit val system = ActorSystem()
implicit val system = ActorSystem("AkkaServerProvider", ConfigFactory.parseString(
s"""
|akka.io.dns.inet-address.provider-object = ${classOf[akka.io.AkkaExampleOrgToLocalhostDnsProvider].getName}
""".stripMargin).withFallback(ConfigFactory.load()))
implicit val materializer = ActorMaterializer()

lazy val futureServer: Future[Http.ServerBinding] = {
lazy val futureServer: Future[Seq[Http.ServerBinding]] = {
implicit val ec = executionEnv.executionContext

// Using 0 (zero) means that a random free port will be used.
// So our tests can run in parallel and won't mess with each other.
Http().bindAndHandle(routes, "localhost", 0)
val httpBinding = Http().bindAndHandle(routes, "localhost", 0)
.map { b => testServerPort = b.localAddress.getPort; b }
val httpsBinding = Http().bindAndHandle(routes, "localhost", 0, connectionContext = serverHttpContext())
.map { b => testServerPortHttps = b.localAddress.getPort; b }

Future.sequence(Seq(httpBinding, httpBinding))
}

override def beforeAll(): Unit = {
val portFuture = futureServer.map(_.localAddress.getPort)(executionEnv.executionContext)
portFuture.onSuccess {
case port => testServerPort = port
}(executionEnv.executionContext)
Await.ready(portFuture, defaultTimeout)
implicit val ec = executionEnv.executionContext
Await.ready(futureServer, defaultTimeout)
}

override def afterAll(): Unit = {
futureServer.foreach(_.unbind())(executionEnv.executionContext)
futureServer.foreach(_.foreach(_.unbind()))(executionEnv.executionContext)
val terminate = system.terminate()
Await.ready(terminate, defaultTimeout)
}
}

private def serverHttpContext() = {
// never put passwords into code!
val password = "abcdef".toCharArray

val ks = KeyStore.getInstance("PKCS12")
ks.load(resourceStream("server.p12"), password)

val keyManagerFactory = KeyManagerFactory.getInstance("SunX509")
keyManagerFactory.init(ks, password)

val context = SSLContext.getInstance("TLS")
context.init(keyManagerFactory.getKeyManagers, null, new SecureRandom)

new HttpsConnectionContext(context)
}

def clientHttpsContext() = {
val certStore = KeyStore.getInstance(KeyStore.getDefaultType)
certStore.load(null, null)
// only do this if you want to accept a custom root CA. Understand what you are doing!
certStore.setCertificateEntry("ca", loadX509Certificate("rootCA.crt"))

val certManagerFactory = TrustManagerFactory.getInstance("SunX509")
certManagerFactory.init(certStore)

val context = SSLContext.getInstance("TLS")
context.init(null, certManagerFactory.getTrustManagers, new SecureRandom)

val params = new SSLParameters()
params.setEndpointIdentificationAlgorithm("https")
new HttpsConnectionContext(context, sslParameters = Some(params))
}

private def resourceStream(resourceName: String): InputStream = {
val is = getClass.getClassLoader.getResourceAsStream(resourceName)
require(is ne null, s"Resource $resourceName not found")
is
}

private def loadX509Certificate(resourceName: String) =
CertificateFactory.getInstance("X.509").generateCertificate(resourceStream(resourceName))
}
Loading