You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@openwhisk.apache.org by ma...@apache.org on 2017/08/05 20:14:54 UTC
[incubator-openwhisk] branch master updated: Support multiple
response header values in raw web actions (#2577)
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 <be...@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" <co...@openwhisk.apache.org>'].