aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/src/main/scala/com/softwaremill/sttp/package.scala59
-rw-r--r--tests/src/test/scala/com/softwaremill/sttp/BasicTests.scala34
2 files changed, 79 insertions, 14 deletions
diff --git a/core/src/main/scala/com/softwaremill/sttp/package.scala b/core/src/main/scala/com/softwaremill/sttp/package.scala
index 9061f5f..dfd1e3e 100644
--- a/core/src/main/scala/com/softwaremill/sttp/package.scala
+++ b/core/src/main/scala/com/softwaremill/sttp/package.scala
@@ -1,7 +1,7 @@
package com.softwaremill
import java.io.{File, InputStream}
-import java.net.URI
+import java.net.{URI, URLEncoder}
import java.nio.ByteBuffer
import java.nio.file.Path
import java.util.Base64
@@ -152,6 +152,7 @@ package object sttp {
new SpecifyAuthScheme[U](ProxyAuthorizationHeader, this)
/**
+ * Uses the `utf-8` encoding.
* If content type is not yet specified, will be set to `text/plain` with `utf-8` encoding.
*/
def body(b: String): RequestTemplate[U] = body(b, Utf8)
@@ -198,22 +199,41 @@ package object sttp {
body = PathBody(b))
/**
+ * Encodes the given parameters as form data using `utf-8`.
+ * If content type is not yet specified, will be set to `application/x-www-form-urlencoded`.
+ */
+ def body(fs: Map[String, String]): RequestTemplate[U] =
+ formDataBody(fs.toList, Utf8)
+
+ /**
+ * Encodes the given parameters as form data.
+ * If content type is not yet specified, will be set to `application/x-www-form-urlencoded`.
+ */
+ def body(fs: Map[String, String], encoding: String): RequestTemplate[U] =
+ formDataBody(fs.toList, encoding)
+
+ /**
+ * Encodes the given parameters as form data using `utf-8`.
+ * If content type is not yet specified, will be set to `application/x-www-form-urlencoded`.
+ */
+ def body(fs: (String, String)*): RequestTemplate[U] =
+ formDataBody(fs.toList, Utf8)
+
+ /**
+ * Encodes the given parameters as form data.
+ * If content type is not yet specified, will be set to `application/x-www-form-urlencoded`.
+ */
+ def body(fs: Seq[(String, String)], encoding: String): RequestTemplate[U] =
+ formDataBody(fs, encoding)
+
+ /**
* If content type is not yet specified, will be set to `application/octet-stream`.
*/
def body[T: BodySerializer](b: T): RequestTemplate[U] =
setContentTypeIfMissing(ApplicationOctetStreamContentType).copy(
body = SerializableBody(implicitly[BodySerializer[T]], b))
- private def hasContentType: Boolean =
- headers.exists(_._1.toLowerCase.contains(ContentTypeHeader))
- private def setContentTypeIfMissing(ct: String): RequestTemplate[U] =
- if (hasContentType) this else contentType(ct)
-
- //def formData(fs: Map[String, Seq[String]]): RequestTemplate[U] = ???
- def formData(fs: Map[String, String]): RequestTemplate[U] = ???
- def formData(fs: (String, String)*): RequestTemplate[U] = ???
-
- def multipartData(parts: MultiPart*): RequestTemplate[U] = ???
+ //def multipartData(parts: MultiPart*): RequestTemplate[U] = ???
/**
* @param responseAs What's the target type to which the response should be read. Needs to be specified upfront
@@ -227,6 +247,23 @@ package object sttp {
handler.send(this, responseAs)
}
+
+ private def hasContentType: Boolean =
+ headers.exists(_._1.toLowerCase.contains(ContentTypeHeader))
+ private def setContentTypeIfMissing(ct: String): RequestTemplate[U] =
+ if (hasContentType) this else contentType(ct)
+
+ private def formDataBody(fs: Seq[(String, String)],
+ encoding: String): RequestTemplate[U] = {
+ val b = fs
+ .map(
+ p =>
+ URLEncoder.encode(p._1, encoding) + "=" + URLEncoder
+ .encode(p._2, encoding))
+ .mkString("&")
+ setContentTypeIfMissing(ApplicationFormContentType).copy(
+ body = StringBody(b, encoding))
+ }
}
class SpecifyAuthScheme[U[_]](hn: String, rt: RequestTemplate[U]) {
diff --git a/tests/src/test/scala/com/softwaremill/sttp/BasicTests.scala b/tests/src/test/scala/com/softwaremill/sttp/BasicTests.scala
index 1ad5fc0..8cfaec8 100644
--- a/tests/src/test/scala/com/softwaremill/sttp/BasicTests.scala
+++ b/tests/src/test/scala/com/softwaremill/sttp/BasicTests.scala
@@ -1,6 +1,7 @@
package com.softwaremill.sttp
import java.io.ByteArrayInputStream
+import java.nio.ByteBuffer
import java.time.{ZoneId, ZonedDateTime}
import akka.stream.ActorMaterializer
@@ -31,8 +32,12 @@ class BasicTests
m.toList.sortBy(_._1).map(p => s"${p._1}=${p._2}").mkString(" ")
private val serverRoutes =
- path("echo") {
- get {
+ pathPrefix("echo") {
+ path("form_params") {
+ formFieldMap { params =>
+ complete(paramsToString(params))
+ }
+ } ~ get {
parameterMap { params =>
complete(
List("GET", "/echo", paramsToString(params))
@@ -188,7 +193,12 @@ class BasicTests
fc should be(expectedPostEchoResponse)
}
- name should "post a byte buffer" in {}
+ name should "post a byte buffer" in {
+ val response =
+ postEcho.body(ByteBuffer.wrap(testBodyBytes)).send(responseAsString)
+ val fc = forceResponse.force(response).body
+ fc should be(expectedPostEchoResponse)
+ }
name should "post a file" in {
val f = File.newTemporaryFile().write(testBody)
@@ -207,6 +217,24 @@ class BasicTests
fc should be(expectedPostEchoResponse)
} finally f.delete()
}
+
+ name should "post form data" in {
+ val response = sttp
+ .post(uri"$endpoint/echo/form_params")
+ .body("a" -> "b", "c" -> "d")
+ .send(responseAsString)
+ val fc = forceResponse.force(response).body
+ fc should be("a=b c=d")
+ }
+
+ name should "post form data with special characters" in {
+ val response = sttp
+ .post(uri"$endpoint/echo/form_params")
+ .body("a=" -> "/b", "c:" -> "/d")
+ .send(responseAsString)
+ val fc = forceResponse.force(response).body
+ fc should be("a==/b c:=/d")
+ }
}
def headerTests(): Unit = {