aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoradamw <adam@warski.org>2017-07-15 12:14:27 +0200
committeradamw <adam@warski.org>2017-07-15 12:14:27 +0200
commitaeea53b49309cbfcbfcdf8a466c3cde418bd58df (patch)
treedd1546ffabc80185118ce445089ba5ebdb8e8e16
parent8d9145a04cdd21a471fba61fc19203759b95514d (diff)
downloadsttp-aeea53b49309cbfcbfcdf8a466c3cde418bd58df.tar.gz
sttp-aeea53b49309cbfcbfcdf8a466c3cde418bd58df.tar.bz2
sttp-aeea53b49309cbfcbfcdf8a466c3cde418bd58df.zip
Better URI interpolator
-rw-r--r--README.md2
-rw-r--r--core/src/main/scala/com/softwaremill/sttp/UriInterpolator.scala16
-rw-r--r--tests/src/test/scala/com/softwaremill/sttp/BasicTests.scala13
-rw-r--r--tests/src/test/scala/com/softwaremill/sttp/UriInterpolatorTests.scala8
4 files changed, 31 insertions, 8 deletions
diff --git a/README.md b/README.md
index 0a391e6..c9444ee 100644
--- a/README.md
+++ b/README.md
@@ -75,6 +75,8 @@ query parameters. Maps and sequences of tuples can also contain optional values,
if `None`.
* optional values in the host part will be expanded to a subdomain if `Some`, removed if `None`
* sequences in the host part will be expanded to a subdomain sequence
+* if a string contains the protocol is embedded *as the first element*, it will not be escaped, allowing to specialize
+entire addresses, e.g.: `uri"$endpoint/login"`, where `val endpoint = "http://example.com/api"`.
A fully-featured example:
diff --git a/core/src/main/scala/com/softwaremill/sttp/UriInterpolator.scala b/core/src/main/scala/com/softwaremill/sttp/UriInterpolator.scala
index d00619d..1216a1e 100644
--- a/core/src/main/scala/com/softwaremill/sttp/UriInterpolator.scala
+++ b/core/src/main/scala/com/softwaremill/sttp/UriInterpolator.scala
@@ -52,7 +52,21 @@ object UriInterpolator {
}
}
- override def parseE(e: Any): UriBuilder = parseE_asEncodedS_skipNone(e)
+ override def parseE(e: Any): UriBuilder = {
+ def encodeIfNotInitialEndpoint(s: String) = {
+ // special case: when this is the first expression, contains a complete schema with :// and nothing is yet parsed
+ // not escaping the contents
+ if (v.isEmpty && s.contains("://")) s else encode(s)
+ }
+
+ e match {
+ case s: String => parseS(encodeIfNotInitialEndpoint(s))
+ case None => this
+ case null => this
+ case Some(x) => parseE(x)
+ case x => parseS(encodeIfNotInitialEndpoint(x.toString))
+ }
+ }
private def append(x: String): Scheme = Scheme(v + x)
diff --git a/tests/src/test/scala/com/softwaremill/sttp/BasicTests.scala b/tests/src/test/scala/com/softwaremill/sttp/BasicTests.scala
index 5d21d6f..a0f1cba 100644
--- a/tests/src/test/scala/com/softwaremill/sttp/BasicTests.scala
+++ b/tests/src/test/scala/com/softwaremill/sttp/BasicTests.scala
@@ -1,7 +1,6 @@
package com.softwaremill.sttp
import java.io.ByteArrayInputStream
-import java.net.URI
import java.time.{ZoneId, ZonedDateTime}
import akka.stream.ActorMaterializer
@@ -120,7 +119,7 @@ class BasicTests
forceResponse: ForceWrappedValue[R]): Unit = {
implicit val h = handler
- val postEcho = sttp.post(new URI(endpoint + "/echo"))
+ val postEcho = sttp.post(uri"$endpoint/echo")
val testBody = "this is the body"
val testBodyBytes = testBody.getBytes("UTF-8")
val expectedPostEchoResponse = "POST /echo this is the body"
@@ -149,7 +148,7 @@ class BasicTests
def parameterTests(): Unit = {
name should "make a get request with parameters" in {
val response = sttp
- .get(new URI(endpoint + "/echo?p2=v2&p1=v1"))
+ .get(uri"$endpoint/echo?p2=v2&p1=v1")
.send(responseAsString)
val fc = forceResponse.force(response).body
@@ -200,7 +199,7 @@ class BasicTests
}
def headerTests(): Unit = {
- val getHeaders = sttp.get(new URI(endpoint + "/set_headers"))
+ val getHeaders = sttp.get(uri"$endpoint/set_headers")
name should "read response headers" in {
val wrappedResponse = getHeaders.send(ignoreResponse)
@@ -217,7 +216,7 @@ class BasicTests
}
def errorsTests(): Unit = {
- val getHeaders = sttp.post(new URI(endpoint + "/set_headers"))
+ val getHeaders = sttp.post(uri"$endpoint/set_headers")
name should "return 405 when method not allowed" in {
val response = getHeaders.send(ignoreResponse)
@@ -230,7 +229,7 @@ class BasicTests
def cookiesTests(): Unit = {
name should "read response cookies" in {
val wrappedResponse =
- sttp.get(new URI(endpoint + "/set_cookies")).send(ignoreResponse)
+ sttp.get(uri"$endpoint/set_cookies").send(ignoreResponse)
val response = forceResponse.force(wrappedResponse)
response.cookies should have length (3)
response.cookies.toSet should be(
@@ -247,7 +246,7 @@ class BasicTests
name should "read response cookies with the expires attribute" in {
val wrappedResponse = sttp
- .get(new URI(endpoint + "/set_cookies/with_expires"))
+ .get(uri"$endpoint/set_cookies/with_expires")
.send(ignoreResponse)
val response = forceResponse.force(wrappedResponse)
response.cookies should have length (1)
diff --git a/tests/src/test/scala/com/softwaremill/sttp/UriInterpolatorTests.scala b/tests/src/test/scala/com/softwaremill/sttp/UriInterpolatorTests.scala
index df26f66..85348e6 100644
--- a/tests/src/test/scala/com/softwaremill/sttp/UriInterpolatorTests.scala
+++ b/tests/src/test/scala/com/softwaremill/sttp/UriInterpolatorTests.scala
@@ -47,6 +47,11 @@ class UriInterpolatorTests extends FunSuite with Matchers {
"authority with parameters" -> List(
(uri"http://$v1.com?x=$v2", s"http://$v1.com?x=$v2queryEncoded")
),
+ "ports" -> List(
+ (uri"http://example.com:8080", s"http://example.com:8080"),
+ (uri"http://example.com:${8080}", s"http://example.com:8080"),
+ (uri"http://example.com:${8080}/x", s"http://example.com:8080/x")
+ ),
"path" -> List(
(uri"http://example.com/$v1", s"http://example.com/$v1"),
(uri"http://example.com/$v1/", s"http://example.com/$v1/"),
@@ -99,6 +104,9 @@ class UriInterpolatorTests extends FunSuite with Matchers {
"everything" -> List(
(uri"${"http"}://$v1.$v2.com/$v1/$v2?$v1=$v2&$v3=$v4#$v1",
s"http://$v1.$v2encoded.com/$v1/$v2encoded?$v1=$v2queryEncoded&$v3encoded=$v4encoded#$v1")
+ ),
+ "embed whole url" -> List(
+ (uri"${"http://example.com:123/a"}/b/c", "http://example.com:123/a/b/c")
)
)