Background

Currently, response-rewrite plugin only supports set / delete headers.
The limitation makes some operations impossible. For example, we can't
add a Set-Cookie header in APISIX as it may override the Set-Cookie
header from the upstream.
Therefore, we need a way to add a header without overriding the existing one.

Solution

We can enrich the headers field and add the operation name to it. Here
is the new configuration schema:

headers = {
    description = "new headers for response",
    anyOf = {
        {
            type = "object",
            minProperties = 1,
            patternProperties = {
                ["^[^:]+$"] = {
                    oneOf = {
                        {type = "string"},
                        {type = "number"},
                    }
                }
            },
        },
        {
            properties = {
                add = {
                    type = "array",
                    minItems = 1,
                    items = {
                        type = "string",
                        -- "Set-Cookie: <cookie-name>=<cookie-value>;
Max-Age=<number>"
                        pattern = "^[^:]+:[^:]+$"
                    }
                },
                set = {
                    type = "object",
                    minProperties = 1,
                    patternProperties = {
                        ["^[^:]+$"] = {
                            oneOf = {
                                {type = "string"},
                                {type = "number"},
                            }
                        }
                    },
                },
                remove = {
                    type = "array",
                    minItems = 1,
                    items = {
                        type = "string",
                        -- "Set-Cookie"
                        pattern = "^[^:]+$"
                    }
                },
            }
        }
    }
},

set means rewriting the headers,
remove means removing the headers,
addmeans appending the new headers.
For set and add, the header format is "name: value", while for remove,
the format is "name".
We use array to represent multiple headers, so the same header can be
used multiple times in the add. For example,

add = {
    "Cache-Control: no-cache",
    "Cache-Control: max-age=0, must-revalidate"
}

The previous configuration can be migrated as part of the new configuration.
The execution order among those operations are ["add", "set", "remove"].

Inspired by:
https://istio.io/latest/docs/reference/config/networking/virtual-service/#Headers-HeaderOperations
https://docs.konghq.com/hub/kong-inc/response-transformer/

Reply via email to