= Groovy policy

ifdef::env-github[]
image:https://ci.gravitee.io/buildStatus/icon?job=gravitee-io/gravitee-policy-groovy/master["Build status", link="https://ci.gravitee.io/job/gravitee-io/job/gravitee-policy-groovy/"]
image:https://badges.gitter.im/Join Chat.svg["Gitter", link="https://gitter.im/gravitee-io/gravitee-io?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge"]
endif::[]

== Phase

|===
|onRequest|onResponse|onRequestContent|onResponseContent
|X|X|X|X
|===

== Description

You can use the http://www.groovy-lang.org/[Groovy^] policy to run Groovy scripts at any stage of request processing through the gateway.

The following example Groovy script is executed during the OnResponse phase to change HTTP headers:

[source, groovy]
----
response.headers.remove 'X-Powered-By'
response.headers.'X-Gravitee-Gateway-Version' = '0.14.0'
----

== Configuration

[source, json]
"groovy": {
    "onRequestScript": "request.headers.'X-Gravitee-Gateway' = '0.14.0'",
    "onResponseScript": "response.headers.remove 'X-Powered-By'",
    "onRequestContentScript": "" // Not executed if empty
    "onResponseContentScript": "" // Not executed if empty
}

== Usage and examples

=== onRequest / onResponse

Some variables are automatically bound to the Groovy script to allow users to use them and define the policy behavior.

[width="100%",cols="2,10",options="header"]
.List of groovy script variables
|===
| Name | Description

| `request` | Inbound HTTP request
| `response` | Outbound HTTP response
| `context` | `PolicyContext` used to access external components such as services and resources
| `result` | Groovy script result

|===

You can interrupt request or response processing by setting the result state to `FAILURE`, providing an HTTP
status code and a message (this is not mandatory, as the default status is `500 - internal server error`).

[source, groovy]
----
import io.gravitee.policy.groovy.PolicyResult.State

if (request.headers.containsKey('X-Gravitee-Break')) {
    result.state = State.FAILURE;
    result.code = 500
    result.error = 'Stop request processing due to X-Gravitee-Break header'
} else {
    request.headers.'X-Groovy-Policy' = 'ok'
}
----

To customize the error sent by the policy:

[source, groovy]
----
import io.gravitee.policy.groovy.PolicyResult.State
result.state = State.FAILURE;
result.code = 400
result.error = '{"error":"My specific error message","code":"MY_ERROR_CODE"}'
result.contentType = 'application/json'
----

=== OnRequestContent / OnResponseContent

You can also transform request or response body content by applying a Groovy script on
the `OnRequestContent` phase or the `OnResponseContent` phase.

The following example shows you how to use the Groovy policy to transform JSON content:

==== Input body content
[source, json]
----
[
    {
        "age": 32,
        "firstname": "John",
        "lastname": "Doe"
    }
]
----

==== Groovy script
[source, groovy]
----
import groovy.json.JsonSlurper
import groovy.json.JsonOutput

def jsonSlurper = new JsonSlurper()
def content = jsonSlurper.parseText(response.content)
content[0].firstname = 'Hacked ' + content[0].firstname
content[0].country = 'US'
return JsonOutput.toJson(content)
----

==== Output body content
[source, json]
----
[
    {
        "age": 32,
        "firstname": "Hacked John",
        "lastname": "Doe",
        "country": "US"
    }
]
----

== Errors

=== Sandbox

Groovy policy comes with a native sandbox feature allowing to safely run Groovy scripts. The sandbox is based on a
predefined list of allowed methods, fields, constructors, and annotations.

The complete whitelist can be found here : https://raw.githubusercontent.com/gravitee-io/gravitee-policy-groovy/master/src/main/resources/groovy-whitelist[gravitee groovy whitelist]

This whitelist should be enough for almost all possible use cases. If you have specific needs which are not allowed by the built-in whitelist, you can extend (or even replace) the list with your own declarations.
For that, you can configure the gravitee.yml by specifying:

 * `groovy.whitelist.mode`: `append` or `replace`. This allows you to just append some new whitelisted definitions to the built-in list or completely replace it. We recommend you to always choose `append` unless you absolutely know what you are doing.
 * `groovy.whitelist.list`: allows declaring other methods, constructors, fields or annotations to the whitelist.
 ** start with `method` to allow a specific method (complete signature).
 ** start with `class` to allow a complete class. All methods, constructors and fields of the class will then be accessible.
 ** start with `new` to allow a specific constructor (complete signature).
 ** start with `field` to allow access to a specific field of a class.
 ** start with `annotation` to allow use of a specific annotation.

Example:
[source, yaml]
groovy:
  whitelist:
    mode: append
    list:
        - method java.time.format.DateTimeFormatter ofLocalizedDate java.time.format.FormatStyle
        - class java.time.format.DateTimeFormatter

*Note*: the `DateTimeFormatter` class is already part of the build-in whitelist.

*WARNING*: be care when you allow use of classes or methods. In some cases, giving access to all methods of a classes may allow access by transitivity to unwanted methods and may open security breaches.

=== Policy configuration

=== HTTP status code

|===
|Code |Message

| ```500```
| The Groovy script cannot be parsed/compiled or executed (mainly due to a syntax error)

|===
