diff options
author | adamw <adam@warski.org> | 2017-07-15 19:48:53 +0200 |
---|---|---|
committer | adamw <adam@warski.org> | 2017-07-15 19:48:53 +0200 |
commit | c5e966faed086bc07463246df4be37690431585e (patch) | |
tree | f6aae64919238e815f0d6eb79513dd705be81cfb | |
parent | b053c91551b924100fa8261e4f405bc40ce53147 (diff) | |
download | sttp-c5e966faed086bc07463246df4be37690431585e.tar.gz sttp-c5e966faed086bc07463246df4be37690431585e.tar.bz2 sttp-c5e966faed086bc07463246df4be37690431585e.zip |
Form data
-rw-r--r-- | core/src/main/scala/com/softwaremill/sttp/package.scala | 59 | ||||
-rw-r--r-- | tests/src/test/scala/com/softwaremill/sttp/BasicTests.scala | 34 |
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 = { |