This is an automated email from the ASF dual-hosted git repository. rabbah pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/incubator-openwhisk.git
The following commit(s) were added to refs/heads/master by this push: new b15a52e Fix handing of binary content-types in webactions (#2683) b15a52e is described below commit b15a52e103540dab64f2c06c8787eb92b55ae7eb Author: James Dubee <jwdu...@us.ibm.com> AuthorDate: Thu Aug 31 21:34:57 2017 -0400 Fix handing of binary content-types in webactions (#2683) --- .../scala/whisk/core/controller/WebActions.scala | 19 ++++++++------- tests/dat/actions/pngWeb.js | 13 ++++++++++ .../whisk/core/cli/test/WskWebActionsTests.scala | 25 +++++++++++++++++++ .../core/controller/test/WebActionsApiTests.scala | 28 +++++++++++++++++++++- 4 files changed, 75 insertions(+), 10 deletions(-) diff --git a/core/controller/src/main/scala/whisk/core/controller/WebActions.scala b/core/controller/src/main/scala/whisk/core/controller/WebActions.scala index a009ed2..ea704ab 100644 --- a/core/controller/src/main/scala/whisk/core/controller/WebActions.scala +++ b/core/controller/src/main/scala/whisk/core/controller/WebActions.scala @@ -17,7 +17,6 @@ package whisk.core.controller -import java.nio.charset.StandardCharsets import java.util.Base64 import scala.concurrent.Future @@ -60,7 +59,7 @@ import whisk.http.ErrorResponse.terminate import whisk.http.Messages import whisk.utils.JsHelpers._ -protected[controller] sealed class WebApiDirectives (prefix: String = "__ow_") { +protected[controller] sealed class WebApiDirectives(prefix: String = "__ow_") { // enforce the presence of an extension (e.g., .http) in the URI path val enforceExtension = false @@ -285,16 +284,18 @@ protected[core] object WhiskWebActionsApi extends Directives { private def interpretHttpResponse(code: StatusCode, headers: List[RawHeader], str: String, transid: TransactionId) = { findContentTypeInHeader(headers, transid, `text/html`).flatMap { mediaType => - // base64 encoded json response supported for legacy reasons - if (mediaType.binary || mediaType == `application/json`) { - Try(new String(Base64.getDecoder().decode(str), StandardCharsets.UTF_8)).map((mediaType, _)) - } else { - Success(mediaType, str) + val ct = ContentType(mediaType, () => HttpCharsets.`UTF-8`) + ct match { + case _: ContentType.Binary | ContentType(`application/json`, _) => + // base64 encoded json response supported for legacy reasons + Try(Base64.getDecoder().decode(str)).map(HttpEntity(ct, _)) + + case nonbinary: ContentType.NonBinary => Success(HttpEntity(nonbinary, str)) } } match { - case Success((mediaType, data: String)) => + case Success(entity) => respondWithHeaders(removeContentTypeHeader(headers)) { - complete(code, HttpEntity(ContentType(MediaType.customWithFixedCharset(mediaType.mainType, mediaType.subType, HttpCharsets.`UTF-8`)), data)) + complete(code, entity) } case Failure(RejectRequest(code, message)) => diff --git a/tests/dat/actions/pngWeb.js b/tests/dat/actions/pngWeb.js new file mode 100644 index 0000000..3a644b0 --- /dev/null +++ b/tests/dat/actions/pngWeb.js @@ -0,0 +1,13 @@ +function main() { + var png = "iVBORw0KGgoAAAANSUhEUgAAAAoAAAAGCAYAAAD68A/GAAAA/klEQVQYGWNgAAEHBxaG//+ZQMyyn581Pfas+cRQnf1LfF" + + "Ljf+62smUgcUbt0FA2Zh7drf/ffMy9vLn3RurrW9e5hCU11i2azfD4zu1/DHz8TAy/foUxsXBrFzHzC7r8+M9S1vn1qxQT07" + + "dDjL9fdemrqKxlYGT6z8AIMo6hgeUfA0PUvy9fGFh5GWK3z7vNxSWt++jX99+8SoyiGQwsW38w8PJEM7x5v5SJ8f+/xv8MDA" + + "zffv9hevfkWjiXBGMpMx+j2awovjcMjFztDO8+7GF49LkbZDCDeXLTWnZO7qDfn1/+5jbw/8pjYWS4wZLztXnuEuYTk2M+Mz" + + "Iw/AcA36VewaD6fzsAAAAASUVORK5CYII=" + + return { + statusCode: 200, + headers: {'content-type': 'image/png'}, + body: png + } +} diff --git a/tests/src/test/scala/whisk/core/cli/test/WskWebActionsTests.scala b/tests/src/test/scala/whisk/core/cli/test/WskWebActionsTests.scala index 14daf1a..3e94e36 100644 --- a/tests/src/test/scala/whisk/core/cli/test/WskWebActionsTests.scala +++ b/tests/src/test/scala/whisk/core/cli/test/WskWebActionsTests.scala @@ -18,6 +18,7 @@ package whisk.core.cli.test import java.nio.charset.StandardCharsets +import java.util.Base64 import scala.util.Failure import scala.util.Try @@ -249,6 +250,30 @@ class WskWebActionsTests extends TestHelpers with WskTestHelpers with RestUtil w response.body.asString.parseJson.asJsObject shouldBe JsObject("status" -> "success".toJson) } + it should "handle http web action with base64 encoded binary response" in withAssetCleaner(wskprops) { + (wp, assetHelper) => + val name = "binaryWeb" + val file = Some(TestUtils.getTestActionFilename("pngWeb.js")) + val host = getServiceURL + val url = host + s"$testRoutePath/$namespace/default/$name.http" + val png = "iVBORw0KGgoAAAANSUhEUgAAAAoAAAAGCAYAAAD68A/GAAAA/klEQVQYGWNgAAEHBxaG//+ZQMyyn581Pfas+cRQnf1LfF" + + "Ljf+62smUgcUbt0FA2Zh7drf/ffMy9vLn3RurrW9e5hCU11i2azfD4zu1/DHz8TAy/foUxsXBrFzHzC7r8+M9S1vn1qxQT07dDjL" + + "9fdemrqKxlYGT6z8AIMo6hgeUfA0PUvy9fGFh5GWK3z7vNxSWt++jX99+8SoyiGQwsW38w8PJEM7x5v5SJ8f+/xv8MDAzffv9hev" + + "fkWjiXBGMpMx+j2awovjcMjFztDO8+7GF49LkbZDCDeXLTWnZO7qDfn1/+5jbw/8pjYWS4wZLztXnuEuYTk2M+MzIw/AcA36Vewa" + + "D6fzsAAAAASUVORK5CYII=" + + assetHelper.withCleaner(wsk.action, name) { + (action, _) => + action.create(name, file, web = Some("true")) + } + + val response = RestAssured.given().config(sslconfig).get(url) + + response.statusCode shouldBe 200 + response.header("Content-type") shouldBe "image/png" + response.body.asByteArray shouldBe Base64.getDecoder().decode(png) + } + private val subdomainRegex = Seq.fill(WhiskProperties.getPartsInVanitySubdomain)("[a-zA-Z0-9]+").mkString("-") private val (vanitySubdomain, vanityNamespace, makeTestSubject) = { diff --git a/tests/src/test/scala/whisk/core/controller/test/WebActionsApiTests.scala b/tests/src/test/scala/whisk/core/controller/test/WebActionsApiTests.scala index fac5076..f73c71d 100644 --- a/tests/src/test/scala/whisk/core/controller/test/WebActionsApiTests.scala +++ b/tests/src/test/scala/whisk/core/controller/test/WebActionsApiTests.scala @@ -44,6 +44,7 @@ import akka.http.scaladsl.model.HttpMethods import akka.http.scaladsl.model.headers.`Content-Type` import akka.http.scaladsl.model.ContentTypes import akka.http.scaladsl.model.headers.RawHeader +import akka.http.scaladsl.model.ContentType import spray.json._ import spray.json.DefaultJsonProtocol._ @@ -811,6 +812,31 @@ trait WebActionsApiTests extends ControllerTestCommon with BeforeAndAfterEach wi } } + it should s"handle http web action with base64 encoded binary response (auth? ${creds.isDefined})" in { + implicit val tid = transid() + val png = "iVBORw0KGgoAAAANSUhEUgAAAAoAAAAGCAYAAAD68A/GAAAA/klEQVQYGWNgAAEHBxaG//+ZQMyyn581Pfas+cRQnf1LfF" + + "Ljf+62smUgcUbt0FA2Zh7drf/ffMy9vLn3RurrW9e5hCU11i2azfD4zu1/DHz8TAy/foUxsXBrFzHzC7r8+M9S1vn1qxQT07dDjL" + + "9fdemrqKxlYGT6z8AIMo6hgeUfA0PUvy9fGFh5GWK3z7vNxSWt++jX99+8SoyiGQwsW38w8PJEM7x5v5SJ8f+/xv8MDAzffv9hev" + + "fkWjiXBGMpMx+j2awovjcMjFztDO8+7GF49LkbZDCDeXLTWnZO7qDfn1/+5jbw/8pjYWS4wZLztXnuEuYTk2M+MzIw/AcA36Vewa" + + "D6fzsAAAAASUVORK5CYII=" + val expectedEntity = HttpEntity(ContentType(MediaTypes.`image/png`), Base64.getDecoder().decode(png)) + + Seq(s"$systemId/proxy/export_c.http"). + foreach { path => + allowedMethods.foreach { m => + invocationsAllowed += 1 + actionResult = Some(JsObject( + "headers" -> JsObject(`Content-Type`.lowercaseName -> MediaTypes.`image/png`.toString.toJson), + "body" -> png.toJson)) + + m(s"$testRoutePath/$path") ~> Route.seal(routes(creds)) ~> check { + status should be(OK) + response.entity shouldBe expectedEntity + } + } + } + } + it should s"handle http web action with html/text response (auth? ${creds.isDefined})" in { implicit val tid = transid() @@ -1303,7 +1329,7 @@ trait WebActionsApiTests extends ControllerTestCommon with BeforeAndAfterEach wi Get(s"$testRoutePath/$path") ~> addHeader("Accept", "application/json") ~> Route.seal(routes(creds)) ~> check { status should be(NotAcceptable) - response shouldBe HttpResponse(NotAcceptable, entity = "Resource representation is only available with these types:\ntext/html") + response shouldBe HttpResponse(NotAcceptable, entity = "Resource representation is only available with these types:\ntext/html; charset=UTF-8") } } } -- To stop receiving notification emails like this one, please contact ['"commits@openwhisk.apache.org" <commits@openwhisk.apache.org>'].