Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

can() function #699

Merged
merged 6 commits into from
Feb 2, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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