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 68c3fd5  Support "+json" content-types as WebAction input. (#3609)
68c3fd5 is described below

commit 68c3fd598d819f4e1795acbf9fb5c9686d1917e7
Author: Markus Thömmes <[email protected]>
AuthorDate: Tue May 8 17:29:30 2018 +0200

    Support "+json" content-types as WebAction input. (#3609)
    
    WebActions support various different input formats (like FormData). Only 
allowing application/json to be parsed and handled as JSON is an unnecessary 
limitation since there are many "+json" custom formats out there which boil 
down to JSON as well.
---
 .../scala/whisk/http/LenientSprayJsonSupport.scala | 29 ++++++++++++++++++++++
 .../scala/whisk/core/controller/WebActions.scala   | 10 +++-----
 .../core/controller/test/WebActionsApiTests.scala  | 18 ++++++++++++++
 3 files changed, 50 insertions(+), 7 deletions(-)

diff --git 
a/common/scala/src/main/scala/whisk/http/LenientSprayJsonSupport.scala 
b/common/scala/src/main/scala/whisk/http/LenientSprayJsonSupport.scala
new file mode 100644
index 0000000..596058b
--- /dev/null
+++ b/common/scala/src/main/scala/whisk/http/LenientSprayJsonSupport.scala
@@ -0,0 +1,29 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package whisk.http
+
+import akka.http.scaladsl.marshallers.sprayjson.SprayJsonSupport
+import akka.http.scaladsl.unmarshalling.{FromEntityUnmarshaller, Unmarshaller}
+import spray.json.JsValue
+
+object LenientSprayJsonSupport extends SprayJsonSupport {
+  // Removes the mandatory application/json content-type for unmarshalling
+  override implicit def sprayJsValueUnmarshaller: 
FromEntityUnmarshaller[JsValue] =
+    Unmarshaller.byteStringUnmarshaller
+      .andThen(sprayJsValueByteStringUnmarshaller)
+}
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 708ad71..d74815c 100644
--- a/core/controller/src/main/scala/whisk/core/controller/WebActions.scala
+++ b/core/controller/src/main/scala/whisk/core/controller/WebActions.scala
@@ -21,7 +21,6 @@ import java.util.Base64
 
 import scala.concurrent.Future
 import scala.util.{Failure, Success, Try}
-
 import akka.http.scaladsl.model.HttpEntity.Empty
 import akka.http.scaladsl.server.Directives
 import akka.http.scaladsl.model.HttpMethod
@@ -36,7 +35,6 @@ import akka.http.scaladsl.model.headers._
 import akka.http.scaladsl.model.Uri.Query
 import akka.http.scaladsl.model.HttpEntity
 import akka.http.scaladsl.server.Route
-import akka.http.scaladsl.marshallers.sprayjson.SprayJsonSupport._
 import akka.http.scaladsl.model.headers.`Content-Type`
 import akka.http.scaladsl.model.headers.`Timeout-Access`
 import akka.http.scaladsl.model.ContentType
@@ -45,13 +43,10 @@ import akka.http.scaladsl.model.FormData
 import akka.http.scaladsl.model.HttpMethods.{DELETE, GET, HEAD, OPTIONS, 
PATCH, POST, PUT}
 import akka.http.scaladsl.model.HttpCharsets
 import akka.http.scaladsl.model.HttpResponse
-
 import spray.json._
 import spray.json.DefaultJsonProtocol._
-
 import WhiskWebActionsApi.MediaExtension
 import RestApiCommons.{jsonPrettyResponsePrinter => jsonPrettyPrinter}
-
 import whisk.common.TransactionId
 import whisk.core.controller.actions.PostActionActivation
 import whisk.core.database._
@@ -59,6 +54,7 @@ import whisk.core.entity._
 import whisk.core.entity.types._
 import whisk.http.ErrorResponse.terminate
 import whisk.http.Messages
+import whisk.http.LenientSprayJsonSupport._
 import whisk.utils.JsHelpers._
 
 protected[controller] sealed class WebApiDirectives(prefix: String = "__ow_") {
@@ -290,7 +286,7 @@ protected[core] object WhiskWebActionsApi extends 
Directives {
     }
   }
 
-  private def isJsonFamily(mt: MediaType) = {
+  def isJsonFamily(mt: MediaType): Boolean = {
     mt == `application/json` || mt.value.endsWith("+json")
   }
 
@@ -574,7 +570,7 @@ trait WhiskWebActionsApi extends Directives with 
ValidateRequestSize with PostAc
         case Empty =>
           process(None, isRawHttpAction)
 
-        case HttpEntity.Strict(ContentTypes.`application/json`, json) if 
!isRawHttpAction =>
+        case HttpEntity.Strict(ct, json) if 
WhiskWebActionsApi.isJsonFamily(ct.mediaType) && !isRawHttpAction =>
           if (json.nonEmpty) {
             entity(as[JsValue]) { body =>
               process(Some(body), isRawHttpAction)
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 0dd5848..7f8cde0 100644
--- a/tests/src/test/scala/whisk/core/controller/test/WebActionsApiTests.scala
+++ b/tests/src/test/scala/whisk/core/controller/test/WebActionsApiTests.scala
@@ -41,6 +41,7 @@ import akka.http.scaladsl.model.HttpMethods
 import akka.http.scaladsl.model.headers.{`Access-Control-Request-Headers`, 
`Content-Type`, RawHeader}
 import akka.http.scaladsl.model.ContentTypes
 import akka.http.scaladsl.model.ContentType
+import akka.http.scaladsl.model.MediaType
 import spray.json._
 import spray.json.DefaultJsonProtocol._
 import whisk.common.TransactionId
@@ -1726,6 +1727,23 @@ trait WebActionsApiBaseTests extends 
ControllerTestCommon with BeforeAndAfterEac
         status should be(BadRequest)
       }
     }
+
+    it should s"support json (including +json subtypes) (auth? 
${creds.isDefined})" in {
+      implicit val tid = transid()
+
+      val path = s"$systemId/proxy/export_c.text/content/field1"
+      val entity = JsObject("field1" -> "value1".toJson)
+
+      Seq(
+        ContentType(MediaType.applicationWithFixedCharset("cloudevents+json", 
HttpCharsets.`UTF-8`)),
+        ContentTypes.`application/json`).foreach { ct =>
+        invocationsAllowed += 1
+        Post(s"$testRoutePath/$path", HttpEntity(ct, entity.compactPrint)) ~> 
Route.seal(routes(creds)) ~> check {
+          status should be(OK)
+          responseAs[String] shouldBe "value1"
+        }
+      }
+    }
   }
 
   class TestingEntitlementProvider(config: WhiskConfig, loadBalancer: 
LoadBalancer)

-- 
To stop receiving notification emails like this one, please contact
[email protected].

Reply via email to