openwhisk-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From markusthoem...@apache.org
Subject [incubator-openwhisk] branch master updated: Support multiple response header values in raw web actions (#2577)
Date Sat, 05 Aug 2017 20:14:54 GMT
This is an automated email from the ASF dual-hosted git repository.

markusthoemmes 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 c59ef2a  Support multiple response header values in raw web actions (#2577)
c59ef2a is described below

commit c59ef2a5621e1d2362801ce91b9eff1c3cf885e1
Author: Ben Browning <ben324@gmail.com>
AuthorDate: Sat Aug 5 16:14:52 2017 -0400

    Support multiple response header values in raw web actions (#2577)
    
    This change allows multiple response header values to be set in raw
    web actions by using a JSON array as the header value. For example:
    
    ```
    function main() {
      return {
        headers: {
          "Set-Cookie": ["a=b", "c=d"]
        },
        code: 200
      }
    }
    ```
---
 .../scala/whisk/core/controller/WebActions.scala   | 15 +++++++++-----
 docs/webactions.md                                 | 18 ++++++++++++++++-
 tests/dat/actions/multipleHeaders.js               |  8 ++++++++
 .../whisk/core/cli/test/WskWebActionsTests.scala   | 23 ++++++++++++++++++++++
 .../core/controller/test/WebActionsApiTests.scala  | 20 +++++++++++++++++++
 5 files changed, 78 insertions(+), 6 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 9ac63ff..138bea9 100644
--- a/core/controller/src/main/scala/whisk/core/controller/WebActions.scala
+++ b/core/controller/src/main/scala/whisk/core/controller/WebActions.scala
@@ -215,11 +215,8 @@ protected[core] object WhiskWebActionsApi extends Directives {
         Try {
             val JsObject(fields) = result
             val headers = fields.get("headers").map {
-                case JsObject(hs) => hs.map {
-                    case (k, JsString(v))  => RawHeader(k, v)
-                    case (k, JsBoolean(v)) => RawHeader(k, v.toString)
-                    case (k, JsNumber(v))  => RawHeader(k, v.toString)
-                    case _                 => throw new Throwable("Invalid header")
+                case JsObject(hs) => hs.flatMap {
+                    case (k, v) => headersFromJson(k, v)
                 }.toList
 
                 case _ => throw new Throwable("Invalid header")
@@ -251,6 +248,14 @@ protected[core] object WhiskWebActionsApi extends Directives {
         }
     }
 
+    private def headersFromJson(k: String, v: JsValue) : Seq[RawHeader] = v match {
+        case JsString(v)  => Seq(RawHeader(k, v))
+        case JsBoolean(v) => Seq(RawHeader(k, v.toString))
+        case JsNumber(v)  => Seq(RawHeader(k, v.toString))
+        case JsArray(v)   => v.flatMap(inner => headersFromJson(k, inner))
+        case _            => throw new Throwable("Invalid header")
+    }
+
     private def interpretHttpResponse(code: StatusCode, headers: List[RawHeader], str: String,
transid: TransactionId): RequestContext => Unit = {
         val parsedHeader: Try[MediaType] = headers.find(_.lowercaseName == `Content-Type`.lowercaseName)
match {
             case Some(header) =>
diff --git a/docs/webactions.md b/docs/webactions.md
index 28b5449..c597a98 100644
--- a/docs/webactions.md
+++ b/docs/webactions.md
@@ -70,6 +70,22 @@ function main() {
 }
 ```
 
+Or sets multiple cookies:
+```javascript
+function main() {
+  return { 
+    headers: { 
+      'Set-Cookie': [
+        'UserID=Jane; Max-Age=3600; Version=',
+        'SessionID=asdfgh123456; Path = /'
+      ],
+      'Content-Type': 'text/html'
+    }, 
+    statusCode: 200,
+    body: '<html><body><h3>hello</h3></body></html>'
}
+}
+```
+
 Or returns an `image/png`:
 ```javascript
 function main() {
@@ -97,7 +113,7 @@ It is important to be aware of the [response size limit](reference.md)
for actio
 
 An OpenWhisk action that is not a web action requires both authentication and must respond
with a JSON object. In contrast, web actions may be invoked without authentication, and may
be used to implement HTTP handlers that respond with _headers_, _statusCode_, and _body_ content
of different types. The web action must still return a JSON object, but the OpenWhisk system
(namely the `controller`) will treat a web action differently if its result includes one or
more of the following as to [...]
 
-1. `headers`: a JSON object where the keys are header-names and the values are string values
for those headers (default is no headers).
+1. `headers`: a JSON object where the keys are header-names and the values are string, number,
or boolean values for those headers (default is no headers). To send multiple values for a
single header, the header's value should be a JSON array of values.
 2. `statusCode`: a valid HTTP status code (default is 200 OK).
 3. `body`: a string which is either plain text or a base64 encoded string for binary data
(default is empty response).
 
diff --git a/tests/dat/actions/multipleHeaders.js b/tests/dat/actions/multipleHeaders.js
new file mode 100644
index 0000000..06712c1
--- /dev/null
+++ b/tests/dat/actions/multipleHeaders.js
@@ -0,0 +1,8 @@
+function main() {
+    return {
+        headers: {
+            "Set-Cookie": ["a=b", "c=d"]
+        },
+        code: 200
+    }
+}
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 52f8d8b..517371c 100644
--- a/tests/src/test/scala/whisk/core/cli/test/WskWebActionsTests.scala
+++ b/tests/src/test/scala/whisk/core/cli/test/WskWebActionsTests.scala
@@ -27,6 +27,7 @@ import org.scalatest.BeforeAndAfterAll
 import org.scalatest.junit.JUnitRunner
 
 import com.jayway.restassured.RestAssured
+import com.jayway.restassured.response.Header
 
 import common.TestHelpers
 import common.TestUtils
@@ -296,4 +297,26 @@ trait WskWebActionsTests
             response.statusCode shouldBe 406
             response.body.asString should include("Resource representation is only available
with these Content-Types:\\ntext/html")
     }
+
+    it should "support multiple response header values" in withAssetCleaner(wskprops) {
+        (wp, assetHelper) =>
+            val name = "webaction"
+            val file = Some(TestUtils.getTestActionFilename("multipleHeaders.js"))
+            val host = getServiceURL()
+            val url = host + s"$testRoutePath/$namespace/default/webaction.http"
+
+            assetHelper.withCleaner(wsk.action, name) {
+                (action, _) =>
+                    action.create(name, file, web = Some("true"), annotations = Map("web-custom-options"
-> true.toJson))
+            }
+
+            val response = RestAssured.given().config(sslconfig).options(url)
+
+            response.statusCode shouldBe 200
+            val cookieHeaders = response.headers.getList("Set-Cookie")
+            cookieHeaders should contain allOf (
+                new Header("Set-Cookie", "a=b"),
+                new Header("Set-Cookie", "c=d")
+            )
+    }
 }
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 d7c0511..3a7722a 100644
--- a/tests/src/test/scala/whisk/core/controller/test/WebActionsApiTests.scala
+++ b/tests/src/test/scala/whisk/core/controller/test/WebActionsApiTests.scala
@@ -1127,6 +1127,26 @@ trait WebActionsApiTests extends ControllerTestCommon with BeforeAndAfterEach
wi
                 }
         }
 
+        it should s"support multiple values for headers (auth? ${creds.isDefined})" in {
+            implicit val tid = transid()
+
+            Seq(s"$systemId/proxy/export_c.http").
+                foreach { path =>
+                    invocationsAllowed += 1
+                    actionResult = Some(
+                        JsObject(
+                            "headers" -> JsObject(
+                                "Set-Cookie" -> JsArray(JsString("a=b"), JsString("c=d;
Path = /")))))
+
+                    Options(s"$testRoutePath/$path") ~> sealRoute(routes(creds)) ~>
check {
+                        headers should contain allOf (
+                            HttpHeaders.RawHeader("Set-Cookie", "a=b"),
+                            HttpHeaders.RawHeader("Set-Cookie", "c=d; Path = /")
+                        )
+                    }
+                }
+        }
+
         it should s"invoke action with options verb without custom options (auth? ${creds.isDefined})"
in {
             implicit val tid = transid()
             customOptions = false

-- 
To stop receiving notification emails like this one, please contact
['"commits@openwhisk.apache.org" <commits@openwhisk.apache.org>'].

Mime
View raw message