Skip to content

Commit

Permalink
can() function (#699)
Browse files Browse the repository at this point in the history
* Test for can() function

* Add can() function

* Document can() function

* format table

* changelog entry

---------

Co-authored-by: Alex Schneider <alex.schneider@avenga.com>
  • Loading branch information
johakoch and Alex Schneider authored Feb 2, 2023
1 parent 563e4a5 commit a9d4aa9
Show file tree
Hide file tree
Showing 8 changed files with 216 additions and 4 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@

Unreleased changes are available as `avenga/couper:edge` container.

* **Added**
* [`can()` function](https://docs.couper.io/configuration/functions) ([#699](https://github.com/avenga/couper/pull/699))

* **Fixed**
* Erroneously sending an empty [`Server-Timing` header](https://docs.couper.io/configuration/command-line#oberservation-options) ([#700](https://github.com/avenga/couper/pull/700))

Expand Down
9 changes: 5 additions & 4 deletions docs/website/content/2.configuration/6.functions.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,20 +12,21 @@ This functions can be used and combined as standalone call with all kind of hcl
|:---------------------------|:----------------|:--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|:----------------------------------------------------------------|:----------------------------------------------------------------------------------------------------|
| `base64_decode` | string | Decodes Base64 data, as specified in RFC 4648. | `encoded` (string) | `base64_decode("Zm9v")` |
| `base64_encode` | string | Encodes Base64 data, as specified in RFC 4648. | `decoded` (string) | `base64_encode("foo")` |
| `can` | bool | Tries to evaluate the expression given in its first argument. | `expression` (expression) | `{ for k in ["not_there", "method", "path"] : k => request[k] if can(request[k]) }` |
| `contains` | bool | Determines whether a given list contains a given single value as one of its elements. | `list` (tuple or list), `value` (various) | `contains([1,2,3], 2)` |
| `default` | string | Returns the first of the given arguments that is not null or an empty string. If no argument matches, the last argument is returned. | `arg...` (various) | `default(request.cookies.foo, "bar")` |
| `join` | string | Concatenates together the string elements of one or more lists with a given separator. | `sep` (string), `lists...` (tuples or lists) | `join("-", [0,1,2,3])` |
| `json_decode` | various | Parses the given JSON string and, if it is valid, returns the value it represents. | `encoded` (string) | `json_decode("{\"foo\": 1}")` |
| `json_encode` | string | Returns a JSON serialization of the given value. | `val` (various) | `json_encode(request.context.myJWT)` |
| `jwt_sign` | string | Creates and signs a JSON Web Token (JWT) from information from a referenced [JWT Signing Profile Block](/configuration/block/jwt_signing_profile) (or [JWT Block](/configuration/block/jwt) with `signing_ttl`) and additional claims provided as a function parameter. | `label` (string), `claims` (object) | `jwt_sign("myJWT")` |
| `jwt_sign` | string | Creates and signs a JSON Web Token (JWT) from information from a referenced [JWT Signing Profile Block](/configuration/block/jwt_signing_profile) (or [JWT Block](/configuration/block/jwt) with `signing_ttl`) and additional claims provided as a function parameter. | `label` (string), `claims` (object) | `jwt_sign("myJWT")` |
| `keys` | list | Takes a map and returns a sorted list of the map keys. | `inputMap` (object or map) | `keys(request.headers)` |
| `length` | integer | Returns the number of elements in the given collection. | `collection` (tuple, list or map; **no object**) | `length([0,1,2,3])` |
| `lookup` | various | Performs a dynamic lookup into a map. The default (third argument) is returned if the key (second argument) is not found in the inputMap (first argument). | `inputMap` (object or map), `key` (string), `default` (various) | `lookup({a = 1}, "b", "def")` |
| `merge` | object or tuple | Deep-merges two or more of either objects or tuples. `null` arguments are ignored. An attribute value with a different type than the current value is set as the new value. `merge()` with no parameters returns `null`. | `arg...` (object or tuple) | `merge(request.headers, { x-additional = "myval" })` |
| `oauth2_authorization_url` | string | Creates an OAuth2 authorization URL from a referenced [OAuth2 AC (Beta) Block](/configuration/block/beta_oauth2) or [OIDC Block](/configuration/block/oidc). | `label` (string) | `oauth2_authorization_url("myOAuth2")` |
| `oauth2_authorization_url` | string | Creates an OAuth2 authorization URL from a referenced [OAuth2 AC (Beta) Block](/configuration/block/beta_oauth2) or [OIDC Block](/configuration/block/oidc). | `label` (string) | `oauth2_authorization_url("myOAuth2")` |
| `oauth2_verifier` | string | Creates a cryptographically random key as specified in RFC 7636, applicable for all verifier methods; e.g. to be set as a cookie and read into `verifier_value`. Multiple calls of this function in the same client request context return the same value. | | `oauth2_verifier()` |
| `relative_url` | string | Returns a relative URL by retaining `path`, `query` and `fragment` components. The input URL `s` must begin with `/<path>`, `//<authority>`, `http://` or `https://`, otherwise an error is thrown. | s (string) | `relative_url("https://httpbin.org/anything?query#fragment") // returns "/anything?query#fragment"` |
| `saml_sso_url` | string | Creates a SAML SingleSignOn URL (including the `SAMLRequest` parameter) from a referenced [SAML Block](/configuration/block/saml). | `label` (string) | `saml_sso_url("mySAML")` |
| `relative_url` | string | Returns a relative URL by retaining `path`, `query` and `fragment` components. The input URL `s` must begin with `/<path>`, `//<authority>`, `http://` or `https://`, otherwise an error is thrown. | `s` (string) | `relative_url("https://httpbin.org/anything?query#fragment") // returns "/anything?query#fragment"` |
| `saml_sso_url` | string | Creates a SAML SingleSignOn URL (including the `SAMLRequest` parameter) from a referenced [SAML Block](/configuration/block/saml). | `label` (string) | `saml_sso_url("mySAML")` |
| `set_intersection` | list or tuple | Returns a new set containing the elements that exist in all of the given sets. | `sets...` (tuple or list) | `set_intersection(["A", "B", "C"], ["B", D"])` |
| `split` | tuple | Divides a given string by a given separator, returning a list of strings containing the characters between the separator sequences. | `sep` (string), `str` (string) | `split(" ", "foo bar qux")` |
| `substr` | string | Extracts a sequence of characters from another string and creates a new string. The "`offset`" index may be negative, in which case it is relative to the end of the given string. The "`length`" may be `-1`, in which case the remainder of the string after the given offset will be returned. | `str` (string), `offset` (integer), `length` (integer) | `substr("abcdef", 3, -1)` |
Expand Down
2 changes: 2 additions & 0 deletions eval/context.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (
"time"

"github.com/hashicorp/hcl/v2"
"github.com/hashicorp/hcl/v2/ext/tryfunc"
"github.com/hashicorp/hcl/v2/hclsyntax"
pkce "github.com/jimlambrt/go-oauth-pkce-code-verifier"
"github.com/zclconf/go-cty/cty"
Expand Down Expand Up @@ -663,6 +664,7 @@ func newFunctionsMap() map[string]function.Function {
return map[string]function.Function{
"base64_decode": lib.Base64DecodeFunc,
"base64_encode": lib.Base64EncodeFunc,
"can": tryfunc.CanFunc,
"coalesce": lib.DefaultFunc,
"contains": stdlib.ContainsFunc,
"default": lib.DefaultFunc,
Expand Down
3 changes: 3 additions & 0 deletions server/http_integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4215,6 +4215,9 @@ func TestFunctions(t *testing.T) {
{"trim", "/v1/trim", map[string]string{
"X-Trim": "foo \tbar",
}, http.StatusOK},
{"can", "/v1/can", map[string]string{
"X-Can": `{"method":"GET","path":"/v1/can"}`,
}, http.StatusOK},
} {
t.Run(tc.path[1:], func(subT *testing.T) {
helper := test.New(subT)
Expand Down
8 changes: 8 additions & 0 deletions server/testdata/integration/functions/01_couper.hcl
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,14 @@ server "api" {
}
}
}

endpoint "/can" {
response {
headers = {
x-can = json_encode({ for k in ["not_there", "method", "path"] : k => request[k] if can(request[k]) })
}
}
}
}
}

Expand Down
44 changes: 44 additions & 0 deletions vendor/github.com/hashicorp/hcl/v2/ext/tryfunc/README.md

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit a9d4aa9

Please sign in to comment.