Permalink
Browse files

! can: replace InetSocketAddress in HostConnectorSetup with hostname/…

…port pair, fixes #394

Since two `InetSocketAddress` instances are equal if their hostnames resolve to the same IP/port (i.e. the address for "www.spray.io" and "spray.io" compare equal) the HTTP layer wasn't distinguishing properly between them.
This patch fixes this problem.
If you were relying on constructing an `HostConnectorSetup` with an `InetSocketAddress` you need to change your code to provide a host and port explicitly.
  • Loading branch information...
sirthias committed Jul 25, 2013
1 parent 99d24be commit a47f3b0d0c7e8a173aeda5aa7c7615db8c44f55f
@@ -104,6 +104,15 @@ class SprayCanClientSpec extends Specification {
hostConnector1 === hostConnector2
}
"return the different HostConnectors for setup requests with differing hostnames" in new TestSetup {
val probe = TestProbe()
probe.send(IO(Http), Http.HostConnectorSetup("www.spray.io"))
val Http.HostConnectorInfo(hostConnector1, _) = probe.expectMsgType[Http.HostConnectorInfo]
probe.send(IO(Http), Http.HostConnectorSetup("spray.io"))
val Http.HostConnectorInfo(hostConnector2, _) = probe.expectMsgType[Http.HostConnectorInfo]
hostConnector1 !== hostConnector2
}
"properly complete a simple request/response cycle with a Host-header request" in new TestSetup {
val (probe, hostConnector) = sendViaHostConnector(Get("/hij") ~> Host(hostname, port) ~> Date(DateTime.now))
verifyServerSideRequestAndReply(s"http://$hostname:$port/hij", probe)
@@ -53,18 +53,14 @@ object Http extends ExtensionKey[HttpExt] {
apply(listener, new InetSocketAddress(interface, port), backlog, options, settings)
}
case class HostConnectorSetup(remoteAddress: InetSocketAddress,
options: immutable.Traversable[Inet.SocketOption],
settings: Option[HostConnectorSettings])(implicit val sslEngineProvider: ClientSSLEngineProvider) extends Command {
case class HostConnectorSetup(host: String, port: Int = 80,
options: immutable.Traversable[Inet.SocketOption] = Nil,
settings: Option[HostConnectorSettings] = None)(implicit val sslEngineProvider: ClientSSLEngineProvider) extends Command {
private[can] def normalized(implicit refFactory: ActorRefFactory) =
if (settings.isDefined) this
else copy(settings = Some(HostConnectorSettings(actorSystem)))
}
object HostConnectorSetup {
def apply(host: String, port: Int = 80, options: immutable.Traversable[Inet.SocketOption] = Nil,
settings: Option[HostConnectorSettings] = None)(implicit sslEngineProvider: ClientSSLEngineProvider): HostConnectorSetup =
apply(new InetSocketAddress(host, port), options, settings)
def apply(host: String, port: Int, sslEncryption: Boolean)(implicit refFactory: ActorRefFactory, sslEngineProvider: ClientSSLEngineProvider): HostConnectorSetup = {
val connectionSettings = ClientConnectionSettings(actorSystem).copy(sslEncryption = sslEncryption)
apply(host, port, settings = Some(HostConnectorSettings(actorSystem).copy(connectionSettings = connectionSettings)))
@@ -16,7 +16,6 @@
package spray.can.client
import java.net.InetSocketAddress
import scala.collection.immutable
import scala.collection.immutable.Queue
import scala.concurrent.duration.Duration
@@ -28,7 +27,7 @@ import spray.can.Http
import spray.io.ClientSSLEngineProvider
import spray.http._
private[client] class HttpHostConnectionSlot(remoteAddress: InetSocketAddress,
private[client] class HttpHostConnectionSlot(host: String, port: Int,
options: immutable.Traversable[Inet.SocketOption],
idleTimeout: Duration,
clientConnectionSettingsGroup: ActorRef)(implicit sslEngineProvider: ClientSSLEngineProvider)
@@ -44,8 +43,8 @@ private[client] class HttpHostConnectionSlot(remoteAddress: InetSocketAddress,
{
case ctx: RequestContext
log.debug("Attempting new connection to {}", remoteAddress)
clientConnectionSettingsGroup ! Http.Connect(remoteAddress, None, options, None)
log.debug("Attempting new connection to {}:{}", host, port)
clientConnectionSettingsGroup ! Http.Connect(host, port, None, options, None)
context.setReceiveTimeout(Duration.Undefined)
context.become(connecting(Queue(ctx)))
@@ -72,7 +71,7 @@ private[client] class HttpHostConnectionSlot(remoteAddress: InetSocketAddress,
context.become(terminating(context.watch(sender)))
case _: Http.Connected
log.debug("Connection to {} established, dispatching {} pending requests", remoteAddress, openRequests.size)
log.debug("Connection to {}:{} established, dispatching {} pending requests", host, port, openRequests.size)
openRequests foreach dispatchToServer(sender)
context.become(connected(context.watch(sender), openRequests))
@@ -34,12 +34,12 @@ private[can] class HttpHostConnector(normalizedSetup: Http.HostConnectorSetup, c
private[this] var openRequestCounts = Map.empty[ActorRef, Int] // open requests per child, holds -1 if unconnected
private[this] val hostHeader = {
val encrypted = settings.connectionSettings.sslEncryption
val port = normalizedSetup.remoteAddress.getPort match {
val port = normalizedSetup.port match {
case 443 if encrypted 0
case 80 if !encrypted 0
case x x
}
HttpHeaders.Host(normalizedSetup.remoteAddress.getHostName, port)
HttpHeaders.Host(normalizedSetup.host, port)
}
context.setReceiveTimeout(settings.idleTimeout)
@@ -122,7 +122,7 @@ private[can] class HttpHostConnector(normalizedSetup: Http.HostConnectorSetup, c
def newConnectionChild(): ActorRef = {
val child = context.watch {
context.actorOf(
props = Props(new HttpHostConnectionSlot(remoteAddress, options, settings.idleTimeout,
props = Props(new HttpHostConnectionSlot(host, port, options, settings.idleTimeout,
clientConnectionSettingsGroup)),
name = counter.next().toString)
}

0 comments on commit a47f3b0

Please sign in to comment.