/
Config - Locations

Config - Locations

A "Location" is a part of the site which matches specific attributes in the incoming request - it can be e.g. a specific hostname (virtual host), it can be based upon URL path, or even user ID or group.

For a particular location you specify how the gateway should react - should it modify the request or responses ? should it add/remove headers or cookies, and should it forward/proxy the request to one of the configured Destinations or should it respond with a specific response or a dynamic one created by a script.

Refer to Locations in the concepts guide for more information about what locations are.

Locations

Locations are stored as separate JSON objects in the locationsarray in the gateway JSON configuration.

Example locations:

{
  "session": {},
  "destinations": ],
  "locations": [
    {
      "location.enabled": true,
      "location.enabled": true,
      "plugin": {},
      "session.needed": false,
      "response.compress": true,
      "response.redirect": "https://%{HTTP_HOST}:8443%{PATH_WITH_QUERY}",
      "name": "Unsecured requests",
      "action": "respond",
      "description": "Redirect http to https",
      "conditions": [
        {
          "values": ["http"],
          "type": "scheme"
        },
        {
          "deny": true,
          "values": [
            "127.0.0.1",
            "localhost",
            "::1",
            "0:0:0:0:0:0:0:1"
          ],
          "type": "remoteip"
        }
      ],
      "response.status": 307,
      "cookiesnapper": {}
    },
    {
      "name": "OpenID Connect Google",
      "description": "OpenID Connect authorization code flow example using Google",
      "conditions": [{
        "deny": false,
        "values": ["/openid"],
        "type": "path"
      }],
      "authentication": {
        "plugins": ["io.ceptor.authentication.AuthenticatorOpenIDConnect"],
        "openidconnect": {
          "response.contenttype": "text/html",
          "identityprovider.name": "google",
          "authenticationplugin": 48,
          "redirecturl": "https://%{HTTP_HOST}/openid",
          "scope": "openid email profile",
          "authorize.url": "https://accounts.google.com/o/oauth2/auth",
          "response.status": 200,
          "response.content": "<html>\n<head><title>Success<\/title>\n<body>\n<h1>Success<\/h1>\nWelcome %{statevariable:email} - authentication succeeded using google.\n<\/body>\n<\/html>",
          "parameters": "access_type=online",
          "client.id": "371213948273-79eceu24cm64ft69pln0hk2lfapok1bq.apps.googleusercontent.com"
        }
      }
    },
    {
      "name": "OpenID Connect Microsoft",
      "description": "OpenID Connect authorization code flow example using Microsoft",
      "conditions": [{
        "deny": false,
        "values": ["/openidmicrosoft"],
        "type": "path"
      }],
      "authentication": {
        "plugins": ["io.ceptor.authentication.AuthenticatorOpenIDConnect"],
        "openidconnect": {
          "response.contenttype": "text/html",
          "identityprovider.name": "microsoft",
          "authenticationplugin": 48,
          "redirecturl": "https://%{HTTP_HOST}/openidmicrosoft",
          "scope": "openid email profile",
          "authorize.url": "https://login.microsoftonline.com/common/oauth2/v2.0/authorize",
          "response.status": 200,
          "response.content": "<html>\n<head><title>Success<\/title>\n<body>\n<h1>Success<\/h1>\nWelcome %{REMOTE_USER} - authentication succeeded using Microsoft Online.\n<\/body>\n<\/html>",
          "client.id": "317190f9-efec-4307-beb9-7f8380a8ae16"
        }
      }
    },
    {
      "authorization": {
        "roles": [],
        "authorization.script": "state.agent.logoff(state.id);\ntrue;"
      },
      "response.contenttype": "text/html",
      "content.preload": false,
      "plugin": {},
      "session.needed": true,
      "session.afterconditionsmatch": false,
      "name": "Logoff",
      "description": "Logs off the session",
      "action": "respond",
      "conditions": [{
        "deny": false,
        "values": ["/logoff"],
        "type": "path"
      }],
      "response.status": 200,
      "response.content": "<html><body>You are now logged off.<\/body><\/html>",
      "cookiesnapper": {}
    },
    {
      "response.contenttype": "text/html",
      "plugin": {},
      "session.needed": true,
      "name": "WebSSO",
      "description": "WebSSO / ADFS Example",
      "action": "respond",
      "response.reason": "OK",
      "response.status": 200,
      "response.content": "<html>\n<body>Hello... %{REMOTE_USER}\n<\/body>\n<\/html>",
      "cookiesnapper": {},
      "conditions": [{
        "deny": false,
        "values": ["/adfs"],
        "type": "path"
      }],
      "authentication": {
        "websso": {
          "response.contenttype": "text/html",
          "identityprovider.name": "%{script}var name=state.getQueryOrPostParam(\"idpname\");\nif (name === null) name = 'microsoft';\nname;",
          "redirecturl": "%{REQUEST_URL}",
          "serviceprovider.name": "%{script}state.getQueryOrPostParam(\"spname\");",
          "failure": {
            "response.contenttype": "text/html",
            "action": "respond",
            "response.status": 403,
            "response.content": "<html><body>Authentication failed<p/>\nDetails:<\/br>\n<pre>\n%{htmlencode:EXCEPTION_LOG}\n<\/pre>\n<\/body><\/html>"
          },
          "response.status": 200,
          "response.content": "<html><body>Success %{REMOTE_USER}<\/body><\/html>",
          "federation.enabled": true
        },
        "plugins": ["io.ceptor.authentication.AuthenticatorWebSSO"]
      }
    },
    {
      "content.preload": false,
      "description": "Every single request",
      "request.concurrent.max": 0,
      "cookiesnapper": {
        "classifier": "%{HTTP_HOST}",
        "pattern": "JSESSIONID"
      },
      "request.queue.size": 10000,
      "valid.methods": "GET|POST|OPTIONS|HEAD",
      "noauthentication.for.options": false,
      "authorization": {
        "noauthorization.for.options": false,
        "roles": [],
        "server.identifier": "none"
      },
      "proxy.destination": "demoapp",
      "request.headers": [
        {
          "name": "X-Forwarded-Proto",
          "value": "%{HTTP_SCHEME}"
        },
        {
          "name": "X-Forwarded-For",
          "value": "%{REMOTE_ADDR}"
        },
        {
          "name": "X-Forwarded-Port",
          "value": "%{REMOTE_PORT}"
        },
        {
          "name": "X-Forwarded-Server",
          "value": "%{SERVER_NAME}"
        }
      ],
      "plugin": {"classifier": "%{HTTP_HOST}"},
      "request.persecond.max": 0,
      "response.maxbytes.persecond": 0,
      "urlrewrite": [{
        "newurl": "/secret/$1",
        "last": true,
        "pattern.flags": "CASE_INSENSITIVE",
        "decode.before.match": true,
        "name": "TOPSECRET to secret",
        "pattern": "^/TOPSECRET/(.*)",
        "redirect": false,
        "clear.query.params": false,
        "conditions": [{
          "deny": false,
          "values": [
            "localhost*",
            "{regex:IGNORE_CASE}LoCaLhOsT.*"
          ],
          "type": "host"
        }]
      }],
      "session.needed": false,
      "response.compress": true,
      "name": "All requests",
      "response.cookies": [{
        "path": "/stuff",
        "discard": false,
        "name": "IWasHere",
        "httponly": true,
		"samesite": lax,
        "secure": true,
        "value": "%{GEOIP_ISP}"
      }],
      "action": "continue",
      "response.headers": [
        {
          "name": "Via",
          "value": "ceptor.io"
        },
        {
          "name": "Server",
          "value": null
        },
        {
          "name": "Location",
          "value": "%{rewrite:responseheader:location;\"http\\:\\/\\/(.*)$\";\"CASE_INSENSITIVE\";\"https://$1\"}"
        }
      ],
      "conditions": [],
      "request.cookies": [
        {
          "name": "sessionid",
          "value": null
        },
        {
          "name": "sslsessionid",
          "value": null
        }
      ]
    },
    {
      "request.attributes": [{
        "name": "NotAGif",
        "value": "true"
      }],
      "plugin": {},
      "response.hooks": [
        {
          "expected.response.status": "404",
          "respond": true,
          "response.headers": [{
            "name": "X-Content",
            "value": "WasNotFound"
          }],
          "response.status": 404,
          "response.reason": "Sorry, not found",
          "response.contenttype": "text/plain",
          "response.content": "Oh no, I did not find that"
        },
        {
          "expected.response.status": "401",
          "respond": false,
          "response.status": 302,
          "response.redirect": "https://somewhere.else",
          "script": "%{script}// Example javascript that simply sends the response configured in the response hook\r\n\r\ncontext.gateway.sendResponse(context, context.currentResponseHook.response);"
        }
      ],
      "session.notvalid.action": "continue",
      "url.validator": {
        "verify.encoding": true,
        "verify.fullurl": true,
        "maxlength": 32768,
        "query.key.maxlength": 1024,
        "query.value.maxlength": 8192,
        "enabled": true,
        "authority.regex": null
      },
      "session.needed": false,
      "name": "All requests except jpg,png,gif,css",
      "action": "continue",
      "conditions": [
        {
          "values": ["*"],
          "type": "path"
        },
        {
          "deny": true,
          "values": ["*.jpg|*.png|*.gif|*.css"],
          "type": "path"
        }
      ],
      "param.validator": {
        "verify.pathparams": true,
        "verify.params": [{
          "value.lowercase": true,
          "key.lowercase": true,
          "value": "*abc*1",
          "key": "test*"
        }],
        "failure": {
          "response.contenttype": "text/html",
          "action": "respond",
          "response.headers": [],
          "response.reason": "Invalid parameter",
          "response.status": 400,
          "response.content": "<html><body><h1>Invalid parameter<\/h1><\/body><\/html>"
        },
        "verify.postparams": false,
        "verify.params.required": true,
        "verify.params.extra.allowed": true,
        "verify.queryparams": true
      },
      "cookiesnapper": {},
      "authentication": {
        "ntlm": {
          "authenticationplugin": 35,
          "failure": {
            "response.contenttype": "%{script:if (state.httpExchange.getRequestHeaders().getFirst('Content-Type') == 'application/json') 'application/json'; else 'text/html';}",
            "action": "respond",
            "response.reason": "Invalid userid/password",
            "response.status": 403,
            "response.content": "%{script:if (state.httpExchange.getRequestHeaders().getFirst('Content-Type') == 'application/json') '{\"error\":\"access.denied\"\\}'; else '<html><head><title>No access<\/title><body><h1>Invalid userid/password<\/h1><\/body><\/html>';}"
          },
          "required": false,
          "allow.anonymous": true
        },
        "plugins": [
          "io.ceptor.authentication.AuthenticatorSSLClientCert",
          "io.ceptor.authentication.AuthenticatorBasicAuth"
        ],
        "spnego": {
          "authenticationplugin": 26,
          "failure": {
            "response.contenttype": "%{script:if (state.httpExchange.getRequestHeaders().getFirst('Content-Type') == 'application/json') 'application/json'; else 'text/html';}",
            "action": "respond",
            "response.reason": "Invalid userid/password",
            "response.status": 403,
            "response.content": "%{script:if (state.httpExchange.getRequestHeaders().getFirst('Content-Type') == 'application/json') '{\"error\":\"access.denied\"\\}'; else '<html><head><title>No access<\/title><body><h1>Invalid userid/password<\/h1><\/body><\/html>';}"
          },
          "allow.ntlm.fallback": true
        },
        "basicauth": {
          "authenticationplugin": 9,
          "failure": {
            "response.contenttype": "%{script:if (state.httpExchange.getRequestHeaders().getFirst('Content-Type') == 'application/json') 'application/json'; else 'text/html';}",
            "action": "respond",
            "response.headers": [{
              "name": "WWW-Authenticate",
              "value": "Basic realm=\"ceptor.io\""
            }],
            "response.reason": "Invalid userid/password",
            "response.status": 401,
            "response.content": "%{script:if (state.httpExchange.getRequestHeaders().getFirst('Content-Type') == 'application/json') '{\"error\":\"access.denied\"\\}'; else '<html><head><title>No access<\/title><body><h1>Invalid userid/password<\/h1><\/body><\/html>';}"
          },
          "realm": "ceptor.io",
          "required": false
        },
        "ssl": {
          "authenticationplugin": 18,
          "failure": {
            "response.contenttype": "%{script:if (state.httpExchange.getRequestHeaders().getFirst('Content-Type') == 'application/json') 'application/json'; else 'text/html';}",
            "action": "respond",
            "response.reason": "Invalid client cert",
            "response.status": 401,
            "response.content": "%{script:if (state.httpExchange.getRequestHeaders().getFirst('Content-Type') == 'application/json') '{\"error\":\"access.denied\"\\}'; else '<html><head><title>No access<\/title><body><h1>Invalid client certificate<\/h1><\/body><\/html>';}"
          },
          "required": false
        }
      },
      "ip.restriction": {
        "ranges": [
          {
            "values": [
              "127.0.0.1-127.0.0.255",
              "::1"
            ],
            "name": "local"
          },
          {
            "values": ["192.168.1.0/24"],
            "name": "intranet"
          },
          {
            "values": ["{file}${portalprotect.home}/config/iprange1.txt"],
            "name": "range1"
          }
        ],
        "allowchange": true,
        "action.invalid": {
          "response.redirect": "/invalid?originalUrl=%{urlencode:REQUEST_URL}",
          "action": "respond",
          "response.reason": "Invalid IP",
          "response.status": 302
        },
        "ip.address.maxcount": 32,
        "geoip.type": "complex",
        "geoip.distance": 100,
        "geoip.complexrules": [
          "ip1=ip2",
          "country1=country2&country2=\"DK\"",
          "distance=300"
        ],
        "script": "if (input == '127.0.0.1') true; else false;"
      }
    },
    {
      "plugin": {
        "response.wrapper.script": "%{file}/responsedumper.js",
        "response.wrapper.class": "io.ceptor.gateway.plugin.ResponseDumper",
        "request.wrapper.class": "io.ceptor.gateway.plugin.RequestDumper",
        "XXXrequest.wrapper.script": "%{file}/requestdumper.js"
      },
      "session.needed": false,
      "name": "JSP response dumper",
      "conditions": [{
        "values": ["*.jsp"],
        "type": "path"
      }],
      "cookiesnapper": {}
    },
    {
      "proxy.destination": "google",
      "plugin": {},
      "urlrewrite": [{
        "newurl": "https://www.google.com/search?q=$1",
        "last": true,
        "decode.before.match": true,
        "name": "googl",
        "pattern": "^/search/(.*)$"
      }],
      "session.needed": false,
      "roles": ["pp_everyone"],
      "name": "Google",
      "action": "proxy",
      "conditions": [{
        "values": ["/search*"],
        "type": "path"
      }],
      "cookiesnapper": {}
    },
    {
      "authorization": {
        "failure": {
          "response.contenttype": "%{script:if (state.httpExchange.getRequestHeaders().getFirst('Content-Type') == 'application/json') 'application/json'; else 'text/html';}",
          "action": "respond",
          "response.reason": "No access",
          "response.status": 403,
          "response.content": "%{script:if (state.httpExchange.getRequestHeaders().getFirst('Content-Type') == 'application/json') '{\"error\":\"access.denied\"\\}'; else '<html><head><title>No access<\/title><body><h1>403 No Access<\/h1><\/body><\/html>';}"
        },
        "roles": [
          "staff",
          "pp_identifiedusers"
        ],
        "server.identifier": "default"
      },
      "request.headers": [
        {
          "name": "authorization",
          "value": null
        },
        {
          "name": "x-user",
          "value": null
        },
        {
          "name": "x-forwarded-server",
          "value": null
        },
        {
          "name": "user-agent",
          "value": null
        },
        {
          "name": "Host",
          "value": "ekstrabladet.dk"
        },
        {
          "name": "Referer",
          "value": null
        }
      ],
      "name": "Secret Destination",
      "action": "continue",
      "locations": [
        {
          "proxy.destination": "ekstrabladet",
          "name": "EB",
          "action": "proxy",
          "conditions": [{
            "values": ["localhost*"],
            "type": "host"
          }]
        },
        {
          "proxy.destination": "google",
          "name": "Google",
          "action": "proxy",
          "conditions": []
        }
      ],
      "conditions": [
        {
          "ignorecase": true,
          "values": [
            "/secret/*",
            "/secret",
            "{regex}^/verysecret.*$"
          ],
          "type": "path"
        },
        {
          "values": ["*"],
          "type": "host"
        }
      ],
      "request.cookies": [{
        "name": "pp_jsessionid",
        "value": null
      }],
      "ip.restriction": {
        "ranges": [{
          "values": ["192.168.1.0/30"],
          "name": "Internal"
        }],
        "allowchange": false
      },
      "authentication": {
        "plugins": [
          "io.ceptor.authentication.AuthenticatorScript",
          "io.ceptor.authentication.AuthenticatorForms",
          "io.ceptor.authentication.AuthenticatorBasicAuth"
        ],
        "basicauth": {
          "realm": "ceptor",
          "required": false
        },
        "forms": {
          "redirect": {
            "response.redirect": "/login.jsp",
            "action": "respond"
          },
          "authenticationplugin": 9,
          "failure": {
            "response.contenttype": "%{script:if (state.httpExchange.getRequestHeaders().getFirst('Content-Type') == 'application/json') 'application/json'; else 'text/html';}",
            "action": "respond",
            "response.reason": "Invalid userid/password",
            "response.status": 403,
            "response.content": "%{script:if (state.httpExchange.getRequestHeaders().getFirst('Content-Type') == 'application/json') '{\"error\":\"access.denied\"\\}'; else '<html><head><title>No access<\/title><body><h1>Invalid userid/password<\/h1><\/body><\/html>';}"
          },
          "required": false
        },
        "script": {
          "content.preload": false,
          "authentication.script": "authenticate();\r\n\r\nfunction authenticate() {\r\n   // If already authenticated, just continue\r\n   if (state.agent.isLoggedOn(state.id))\r\n      return 'CONTINUE';\r\n      \r\n   try {\r\n        var user = state.httpExchange.getRequestHeaders().getFirst('X-User');\r\n        var pass = state.httpExchange.getRequestHeaders().getFirst('X-Password');\r\n        if (user === null) {\r\n            user = state.httpExchange.getQueryParameters().get('X-User').getFirst();\r\n        }\r\n        if (pass === null) {\r\n            pass = state.httpExchange.getQueryParameters().get('X-Password').getFirst();\r\n        }\r\n        \r\n        if (user === null || pass === null) {\r\n            // Ignore if user or password is not supplied - making this type of authentication optional\r\n            return 'CONTINUE';\r\n        } else {\r\n            state.trace.trace('About to logon from script with user: ' + user);\r\n            // 9 is authentication plugin type\r\n            state.agent.logon(state.id, 9, user, pass, null);\r\n            return 'SUCCESS';\r\n        }\r\n    } catch(err) {\r\n        state.gateway.sendAndLogError(state, 401, 'Authentication Required', err);\r\n        return 'RESPOND';\r\n    }\r\n}"
        }
      }
    },
    {
      "proxy.destination": "demoapp",
      "roles": ["pp_everyone"],
      "name": "Local",
      "action": "proxy",
      "conditions": [{
        "values": ["/*"],
        "type": "path"
      }],
      "request.cookies": [{
        "name": "ppSessionId",
        "value": "%{REQUEST_ID}"
      }]
    },
    {
      "response.contenttype": "text/html",
      "#description": "Deny access to everything, by default if no other rule is matching",
      "name": "Default",
      "action": "respond",
      "response.headers": [{
        "name": "X-Access",
        "value": "Denied"
      }],
      "response.reason": "No access",
      "conditions": [{
        "values": ["/*"],
        "type": "path"
      }],
      "response.status": 403,
      "response.content": "<html><head><title>No access<\/title><body><h1>403 No Access<\/h1><\/body><\/html>"
    }
  ],
  "gateway": {},
  "listen": []
}


Locations configuration

Each location is stored in its own JSON object within the locations array.

You can add/remove and reorder Locations - they are processed in the order they appear. When the conditions for a location matches the request, the location will be processed - if its action is RESPOND or PROXY no further locations will be processed.

If a matched location has any nested locations defined, they will be processed before going down to the next location in the list.

When you press Add to add a new location, you get this prompt:

You should enter the unique name of the location, and optionally a description of it - it is often useful to enter a reason for its existence here - even if it might be obvious at first it is likely not so obvious in a few years.

Configuration for Each Specific Location

The configuration for each specific location looks like the screenshot below.

It has many sections below it - note that they are marked with a blank circle if no values are defined for that particular section, and a cog if something is defined for this section. This makes it easy to see if you need to look at a particular session when going through the configuration to view the settings for a particular location.

Location configuration

Name

Name of location - used for logging/tracing and diagnostics

Default: none, a unique name is required
JSON key: name 

Description

Description of this location

Default: blank
JSON key: description 

Location is enabled

If unchecked, This location is ignored and not processed - it is treated like it did not exist.

Default: true
JSON key: location.enabled

Session is needed

If unchecked, no session is needed, so no request ID, session ID etc. will be available for this location unless a previous location has retrieved the session. Note that authentication and IP checking will not be done if there is no session present.

You can turn this off if you want anonymous, unauthenticated access to parts of your site, e.g. if you have a publicly available static part that you have no interest in authenticating users, doing IP checking etc. - this will ensure as fast performance as possible, since the overhead is kept to a bare minimum.

JSON key: session.needed 
Default: true

Session will only be established if conditions match

If checked, and if session is needed, a session will not be established before conditions are checked, so it will only be done if conditions match. Note that some conditions, such as those on user or group or some scripts/macros require a session so they will not work.

Default: false
JSON key: session.afterconditionsmatch

Override global session settings

If checked, this allows you to override the session settings per location - in that case, you will get a new screen as child of the location where you can specify session resolvers and settings. Note that unless "Session is needed" is checked, this option will not have any effect.

Also, bear in mind that once a location has obtained a session once during request processing, any subsequent resolvers are ignored since the session is already available.

JSON key: session.override
Default: false

Preload request content

If checked, request content will be preloaded into memory before processing this location this is required (and automatically enabled if conditions contain postparam values) for processing POST'ed request content.

Using this allows you to access request body in plugins / scripts for this or subsequently processed locations. Note that it affects performance slightly, and it requires increased memory use to store the request contents until the request is done.

Default: false
JSON key: content.preload 

Valid HTTP Methods

Valid HTTP methods - default is OPTIONS|HEAD|GET|POST, you can specify a pattern with wildcards or use {regex} prefix to create regular expression match. If the request method does not match this pattern, HTTP error 405 is immediately sent back.

Default: OPTIONS|HEAD|GET|POST
JSON key: valid.methods 

Action

Action to take for this location, can continue to next location, respond by writing a response back to the browser, proxy to a destination server or serve static resources.

Default: continue
JSON key: action 

Proxy Destination

Destination to forward request to, if action is proxy.

Default: blank
JSON key: proxy.destination 

Compress proxied responses

If set, and client indicates support for it (gzip/deflate) then responses sent to the client are compressed unless the destination server has already done so itself.

Default: true
JSON key: response.compress 

Limits

Can be used to limit the number of concurrent requests, or requests per second for this location.

Limit Qualifier

Qualifier for limiting requests per second or concurrent requests - if not set, those limits apply for all requests for the given location, but if set, limits can be specified per IP address, per client ID or any other parameter you wish to use as a qualifier.

As an example, you can use %{REMOTE_ADDR} to limit requests per client IP, or e.g. %{statevariable:client_id} to apply limits to the client_id attribute within the session.
Note that limits and qualifiers are per location, so any expression you choose will only affect this location and not others.

Default: Blank, no value
JSON key: requestlimit.qualifier

Max requests per second

Maximum number of requests per second, set to 0 for no limit.

Default: 0 (no limit)
JSON key: request.persecond.max 

Maximum concurrent requests

Maximum number of concurrent requests for this location - any additional requests will be queued up, or 0 for no limit.

Default: 0 (no limit)
JSON key: request.concurrent.max 

Request queue size

If too many concurrent requests, this is the maximum number of requests that can be queued up.

If number of requests in the queue exceeds this limit, new ones will be denied with HTTP 513 to indicate to the client that the server is overloaded with concurrent requests and its queue is full.

Default: 1000
JSON key: request.queue.size 

Max response bytes/s

If set to nonzero, limits the number of response bytes sent per second (per connection) to the client.

Default: 0
JSON key: response.maxsize.persecond 

Location Script

Script

Script to execute when this location is triggered.

Whenever this location is hit, this script will be executed which provides a simple method of adding functionality you would otherwise need to do in a pipeline or authorization/authentication script.

This is a useful place to e.g. manipulate with the contents of the users' session and/or the request before further processing is done.

Default: none
JSON key: location.script

Pipeline Settings

See Pipelines and Tasks for more information about pipelines.

Pipeline

Specify pipeline name. A pipeline allows advanced functionality, such as calling multiple remote services, validating JSON, running scripts etc. If a name of an existing pipeline is specified here, it is called immediately after processing limits.

A task within a pipeline might elect to send a response, or proxy a request - and in that case the action in this location has no effect - request processing will then never be given back to this location.

JSON key: pipeline
Default: none.

Response settings (when action is "respond")

If action is set to RESPOND, then a response will be sent to the client with the information below. Note that the HTTP Response headers and cookies will also be added, if any are configured.

Note that Scripts and Macros can be used to specify these values dynamically based upon request content.

Canned Response

Specify the name of a "canned" response here to reuse it - when set, the response sent back will be the one defined in the canned response - if any other values are specified here, HTTP response code, reason etc. then these values overwrite what was specified in the canned response. Any headers defined will complement the ones specified for the canned response.

Default: none
JSON key: response.name 

HTTP Response code

HTTP Response code to send back to client.

Default: 500
JSON key: response.status 

HTTP Response reason

HTTP response reason text

Default: No additional information
JSON key: response.reason 

Redirect Location

Response Redirect Location URL - if set, a redirect will be sent instead of a normal response, the Location header in the response will be set to this value.

Default: none
JSON key: response.redirect

Content-Type

HTTP Response content-type

Default: none
JSON key: response.contenttype

Response Body

Response body contents

Default: none
JSON key: response.body 

CookieSnapper

Configuration is stored in the JSON object cookiesnapper.

Note that CookieSnappers can be configured both for locations and destinations - they serve the exact same functionality, but in some cases it is easier to define them on destinations so they have effect for all locations proxying to a certain destination - in other cases you only want this enabled for some locations - e.g. if you only want this for certain browsers or other things your location conditions can decide upon.

Cookies to snap

Pattern defining which cookies to remove from the response and place into the session. Any cookies matching this pattern will be moved from the response to the session, and added on future requests.

Default value: blank
JSON key: pattern

Classifier

Classifier to use - here you can use %{} variables, such as %{HTTP_HOST} or %{script:xxxx} to specify the classifier or scope to restrict these cookies too.
The classifier can ensure that the cookies are not forwarded on all requests, but only where the next request has the same classifier - so if it is e.g. set to %{HTTP_HOST} then the cookie will only be added to future requests, if these request has the exact same hostname as this one.
If the classifier is left as "default" then if the next request has a different hostname, e.g. app2.mydomain.com then the cookie will be added to the request again, which is usually what you want. 

Default value: "default"
JSON key: classifier

Plugins

Plugins are java or script code that can process request or response bodies - they can e.g. transform contents from one format to another, e.g. add encryption, verify signatures etc.

Plugin configuration is stored in the JSON Object plugin within the location JSON Object.

Request wrapper java class

Java class implementing ConduitWrapper<StreamSourceConduit> to process request body - see Plugins#JavaRequestWrapper for more information.

Default: none
JSON key: request.wrapper.class 

Response wrapper java class

Java class implementing ConduitWrapper<StreamSinkConduit> to process response body - see Plugins#JavaResponseWrapper for more information.

Default: none
JSON key: response.wrapper.class 

Request wrapper script

Script that processes request body - see Plugins#ScriptRequestWrapper for more information.

Default: none
JSON key: response.wrapper.script

Response wrapper script

Script that processes response body see Plugins#ScriptResponseWrapper for more information.

Default: none
JSON key: response.wrapper.script

Session

If "Override global session settings" is checked, you can configure the session settings specifically for this location. The same fields as in the global session configuration are available. JSON configuration is stored in a JSON Object called "session" inside the location JSON.

Invalid Session Action

If a session is not valid, you can specify what action to take - and decide to either respond/redirect to another page, or continue with a new anonymous session.

These configuration entries are stored in the JSON Object action.session.notvalid within the location.

Action if request contained invalid or timed out session ID

Action

Action to take for this location, if request had an invalid or timed out session ID. continue=go on without authenticating, respond=respond with configured response or redirect

If action is set to RESPOND, then a response will be sent to the client with the information below.
Note that Scripts and Macros can be used to specify these values dynamically based upon request content.

Canned Response

Specify the name of a "canned" response here to reuse it - when set, the response sent back will be the one defined in the canned response - if any other values are specified here, HTTP response code, reason etc. then these values overwrite what was specified in the canned response. Any headers defined will complement the ones specified for the canned response.

Default: none
JSON key: response.name 

HTTP Response code

HTTP Response code to send back to client.

Default: 500
JSON key: response.status 

HTTP Response reason

HTTP response reason text

Default: No additional information
JSON key: response.reason 

Redirect Location

Response Redirect Location URL - if set, a redirect will be sent instead of a normal response, the Location header in the response will be set to this value.

Default: none
JSON key: response.redirect

Content-Type

HTTP Response content-type

Default: none
JSON key: response.contenttype

Response Body

Response body contents

Default: none
JSON key: response.body 

Response Headers

Response headers can also be added to the response, if any are specified, they are in an JSON array called response.headers within the action.session.notvalid JSON object.

You can add headers by clicking "Add", then you get a popup where you can set the name and value of the header.

Once created, they are added to the JSON Array response.headers within the action.session.notvalid JSON object, as a new object with the attributes name and value set to the entered name and value.

Conditions

List of conditions required to match for this location - if no conditions, all requests will match.

You can add/remove and move conditions up and down - they will be checked in the order listed.

Conditions are stored in the JSON array conditions within the location object.

When you add a new condition, you need to fill out this dialog:

When you edit each specific condition, you do it in this dialog:

Here, you can edit the type, name and add/remove/edit values - a condition can have multiple values.

Condition match

Type

Type of condition.

You can select between these types:

  • path
    Request URI / Path - e.g. /*, /secret/* or *.png 
  • host
    Hostname  of the request, e.g. app.*, *.my.domain or login.ceptor.io
  • cookie
    Request cookie value (name must contain the name of cookie).
  • query
    Request query parameter - /?param=value (name must be query parameter name).
  • postparam
    A request POST parameter sent in a URL form-encoded POST request.  (name must be post parameter name).
  • pathparam
    A request path parameter - similar to query parameters, but separated with semicolon instead of question mark - e.g. /somepath;param=value;param2=value2 (name must be path parameter name).
  • method
    Request HTTP method, e.g. GET, HEAD, POST, PUT etc. 
  • scheme
    Request scheme - either http or https.
  • header
    The value of a specific HTTP request header, e.g. the Accept header (name must be HTTP request header name).
  • remoteip
    The remote IP address the request originated from.
  • attribute
    A request attribute - not part of the request, but can be the result of an earlier location - request attributes can be created by a location and reused in conditions for later locations. (name must contain the name of the attribute).
  • geoip
    A specific Geo IP attribute, such as a country, ISP or city. (name must be set to isp, organization, countrycode, countryname, city, postalcode or region).
  • userid
    A specific user ID (note that for this information to be available, the location needs to have the "Session is needed" flag set).
  • usergroup
    A specific user group (note that for this information to be available, the location needs to have the "Session is needed" flag set).
  • script
    This allows you to create a script which can use any means to decide what conditions are required to match, it could, for example, check a time interval or do complex validation of multiple session attributes and request content.
  • macro
    Allows you to check the value of a macro, e.g. check if %{SERVER_ADDR} matches a specific IP address.
  • probability
    Specify a percentage probability of match - this enables a condition that matches a percentage of the requests, e.g. 10% - use this to send e.g. 10 or 20% of requests to a different version than the rest to allow gradual upgrades that do not affect all users.

Default: none - must be selected.
JSON key: type 

Name

For some types, a name is required. For query/pathparam/postparam it is the name of the query parameter. For header, it is the name of the request header. For attribute it is the name of the request attribute. For GeoIP, it is one of [isp, organization, countrycode, countryname, city, postalcode, region]

Default: none
JSON key: name 

Values must NOT match

Reverse the check, so if one of the values match, the condition is NOT met.

Default: false
JSON key: deny<