diff --git a/app/_gateway_entities/route.md b/app/_gateway_entities/route.md index 92e9396d5..69d918e4f 100644 --- a/app/_gateway_entities/route.md +++ b/app/_gateway_entities/route.md @@ -4,57 +4,176 @@ content_type: reference entities: - route -description: A route is a path to a resource within an upstream application. +description: | + A Route is a path which defines how (and if) requests are passed to Gateway Services and their respective upstream applications based on a set of configured rules. related_resources: - - text: Services + - text: Gateway Service entity url: /gateway/entities/service/ - - text: Routing in {{site.base_gateway}} - url: /gateway/routing/ - text: Expressions router url: /gateway/routing/expressions/ + - text: Upstream entity + url: /gateway/entities/upstream/ tools: - - admin-api - - konnect-api - - kic - - deck - - terraform + - admin-api + - konnect-api + - kic + - deck + - terraform schema: - api: gateway/admin-ee - path: /schemas/Route + api: gateway/admin-ee + path: /schemas/Route + +faqs: + - q: How can I divert traffic from an old URL to a new one with {{site.base_gateway}}? + a: Create a new route and point it to the existing Gateway Service. The new route will proxy traffic to the existing service at the new URL. --- -## What is a route? +## What is a Route? + +A Route is a path to a resource within an upstream application. In {{site.base_gateway}}, Routes typically map to endpoints exposed through [Gateway Services](/gateway/entities/service/). Routes determine how (and if) requests are sent to their Services after they reach {{site.base_gateway}}. Where a Service represents the backend API, a Route defines what is exposed to clients. + +Routes can also define rules that match requests to associated Services. Because of this, one Route can reference multiple endpoints. Once a Route is matched, {{site.base_gateway}} proxies the request to its associated Service. A basic Route should have a name, path or paths, and reference an existing Service. + +{% mermaid %} +flowchart LR + A(API client) + B("`Route + (/mock)`") + C("`Gateway Service + (example-service)`") + D(Upstream + application) + + A <--requests + responses--> B + subgraph id1 ["` + **KONG GATEWAY**`"] + B <--requests + responses--> C + end + C <--requests + responses--> D + + style id1 rx:10,ry:10 + +{% endmermaid %} + +## Route and Service interaction + +Routes, in conjunction with [Services](/gateway/entities/service/), let you expose your Services to applications with {{site.base_gateway}}. {{site.base_gateway}} abstracts the Service from the applications by using Routes. Since the application always uses the Route to make a request, changes to the Services, like versioning, don’t impact how applications make the request. Routes also allow the same Service to be used by multiple applications and apply different policies based on the Route used. + +For example, say you have an external application and an internal application that need to access the `example_service` Service, but the *external* application should be limited in how often it can query the Service to avoid a denial of service. If you apply a rate limit policy to the Service and the *internal* application calls it, the internal application is also limited. Routes can solve this problem. + +In this example, you can create two Routes to handle the two applications, say `/external` and `/internal`, and point both of them to `example_service`. +You can configure a policy to limit how often the `/external` Route is used. +When the external application tries to access the Service via {{site.base_gateway}} using `/external`, it's rate limited. +But when the internal application accesses the Service using {{site.base_gateway}} using `/internal`, the internal application isn't limited. + +The following diagram illustrates this example: + +{% mermaid %} +flowchart LR + A(External application) + B("`Route (/external)`") + B2(Rate Limiting + plugin) + C("`Service (example-service)`") + D(Upstream application) + E(Internal application) + F("`Route (/internal)`") + + A --request--> B + E --request--> F + + subgraph id1 ["` + **KONG GATEWAY**`"] + B --> B2 --"10 requests + per minute"--> C + F ---> C + end + + C --transformed + and routed + requests--> D + + style id1 rx:10,ry:10 + +{% endmermaid %} + +## Route use cases + +Common use cases for Routes: + +| Use Case | Description | +|--------|----------| +| Rate limiting | Use Routes to set different rate limits for clients accessing the upstream application via specific paths, for example `/internal` or `/external`.

[Enable a rate limiting plugin on Routes attached to the Service](/plugins/rate-limiting-advanced/) | +| Perform a simple URL rewrite | Use the Routes entity to rename an endpoint. For example, you can rename your legacy `/api/old/` upstream endpoint to a publicly accessible API endpoint named `/new/api`. | +| Perform a complex URL rewrite | Use the Routes entity to rewrite a group of paths, such as replacing `/api//old` with `/new/api/`.

[Request Transformer Advanced plugin](/plugins/request-transformer-advanced/) | +| Describe paths as patterns using regular expressions | [Expressions router](/gateway/routing/expressions/) | + +## How routing works + +For each incoming request, {{site.base_gateway}} must determine which Service gets to handle it based on the Routes that are defined. As soon as a Route yields a match, the router stops matching and {{site.base_gateway}} uses the matched Route to [proxy the current request](/gateway/traffic-control/proxying/). + +If multiple Routes match, {{site.base_gateway}} handles routing in the following order: + +1. {{site.base_gateway}} finds Routes that match the request by comparing the defined routing attributes with the attributes in the request. +1. If multiple Routes match, the {{site.base_gateway}} router then orders all defined Routes by their [priority](#priority-matching) and uses the highest priority matching Route to handle a request. + +{{site.base_gateway}} provides two different routers, enabled via the `router_flavor` property in `kong.conf`. The router you should use depends on your use case and {{site.base_gateway}} version: +* **[Expressions router](/gateway/routing/expressions/):** The recommended method for anyone running {{site.base_gateway}} 3.4.x or later. Can be run in both `traditional_compat` and `expressions` modes. Handles complex routing logic and regex in Routes. +* **Traditional compatibility router:** Only recommended for anyone running {{site.base_gateway}} 2.9.x or earlier. The default routing method for {{site.base_gateway}}. Doesn't handle complex routing logic. + +### Path matching + +Keep the following path matching criteria in mind when configuring paths: + +* **Regex in paths:** For a path to be considered a regular expression, it must be prefixed with a `~`. You can avoid creating complex regular expressions using the [Router Expressions language](/gateway/routing/expressions/). +* **Capturing groups:** [Regex capture groups](/gateway/routing/expressions/#example-expressions) are also supported, and the matched group will be extracted from the path and available for plugins consumption. +* **Escaping special characters:** When configuring Routes with regex paths via the Admin API, be sure to URL encode your payload if necessary according to [RFC 3986](https://tools.ietf.org/html/rfc3986). +* **Normalization behavior:** To prevent trivial Route match bypass, the incoming request URI from client +is always normalized according to [RFC 3986](https://tools.ietf.org/html/rfc3986) +before router matching occurs. + + Regex Route paths only use methods 1 and 2. In addition, if the decoded character becomes a regex meta character, it will be escaped with backslash. -{{page.description | liquify}} Services can store collections of objects like plugin configurations, and policies, and they can be associated with routes. In {{site.base_gateway}}, routes typically map to endpoints that are exposed through the {{site.base_gateway}} application. Routes can also define rules that match requests to associated services. Because of this, one route can reference multiple endpoints. A basic route should have a name, path or paths, and reference an existing service. +### Priority matching -You can also configure routes with: +If multiple Routes match, the {{site.base_gateway}} router then orders all defined Routes by their priority and uses the highest priority matching Route to handle a request. How Routes are prioritized depends on the router mode you're using. -* Protocols: The protocol used to communicate with the upstream application. -* Hosts: Lists of domains that match a route -* Methods: HTTP methods that match a route -* Headers: Lists of values that are expected in the header of a request -* Redirect status codes: HTTPS status codes -* Tags: Optional set of strings to group routes with +#### Traditional compatibility mode -## Route and service interaction +In `traditional_compat` mode, the priority of a Route is determined as +follows, by the order of descending significance: -Routes, in conjunction with [services](/gateway/entities/service/), let you expose your services to applications with {{site.base_gateway}}. {{site.base_gateway}} abstracts the service from the applications by using routes. Since the application always uses the route to make a request, changes to the services, like versioning, don’t impact how applications make the request. Routes also allow the same service to be used by multiple applications and apply different policies based on the route used. +1. **Priority points:** A priority point is added for every `methods`, `host`, `headers`, and `snis` value that a Route has. Routes with higher priority point values will be considered before those with lower values. +2. **Wildcard hosts:** Among Routes with the same priority point value, Routes without a wildcard host specified (or no host at all) are prioritized before those that have any wildcard host specification. +3. **Header count:** The resulting groups are sorted so the Routes with a higher number of specified headers have higher priority than those with a lower number of headers. +4. **Regular expressions and prefix paths:** Routes that have a regular expression path are considered first and are ordered by their `regex_priority` value. Routes that have no regular expression path are ordered by the length of their paths. +5. **Creation date:** If all of the above are equal, the router chooses the Route that was created first using the Route's `created_at` value. -For example, if you have an external application and an internal application that need to access the `example_service` service, but the external application should be limited in how often it can query the service to assure no denial of service. If a rate limit policy is configured for the service when the internal application calls the service, the internal application is limited as well. Routes can solve this problem. +When two Routes have the same path, {{site.base_gateway}} uses a tiebreaker. For example, if the rule count for the given request is the same for both Routes `A` and `B`, then the following tiebreaker rules are applied in the order they are listed. Route `A` will be selected over `B` if: + * `A` has only plain Host headers and `B` has one or more wildcard + host headers + * `A` has more non-Host headers than `B` + * `A` has at least one regex path and `B` has only plain paths + * `A`'s longest path is longer than `B`'s longest path + * `A.created_at < B.created_at` -In the example above, two routes can be created, say /external and /internal, and both routes can point to `example_service`. A policy can be configured to limit how often the /external route is used and the route can be communicated to the external client for use. When the external client tries to access the service via {{site.base_gateway}} using /external, they are rate limited. But when the internal client accesses the service using {{site.base_gateway}} using /internal, the internal client will not be limited. +#### Expressions router mode -## Dynamically rewrite request URLs with routes +In [`expressions` mode](/gateway/routing/expressions/), when a request comes in, {{site.base_gateway}} evaluates Routes with a higher `priority` number first. The priority is a positive integer that defines the order of evaluation of the router. The larger the priority integer, the sooner a Route will be evaluated. In the case of duplicate priority values between two Routes in the same router, their order of evaluation is undefined. -Routes can be configured dynamically to rewrite the requested URL to a different URL for the upstream. For example, your legacy upstream endpoint may have a base URI like `/api/old/`. However, you want your publicly accessible API endpoint to now be named `/new/api`. To route the service's upstream endpoint to the new URL, you could set up a service with the path `/api/old/` and a route with the path `/new/api`. +### Routing performance recommendations -{{site.base_gateway}} can also handle more complex URL rewriting cases by using regular expression capture groups in the route path and the [Request Transformer Advanced](/plugins/request-transformer-advanced/) plugin. For example, this can be used when you must replace `/api//old` with `/new/api/`. +You can use the following recommendations to increase routing performance: -{{site.base_gateway}} 3.0.x or later ships with a new router. The new router can use regex expression capture groups to describe routes using a domain-specific language called Expressions. Expressions can describe routes or paths as patterns using regular expressions. For more information about how to configure the router using Expressions, see [How to configure routes using expressions](https://docs.konghq.com/gateway/latest/key-concepts/routes/expressions/). +* In `expressions` mode, we recommend putting more likely matched Routes before (as in, higher priority) those that are less frequently matched. +* Regular expressions in Routes use more resources to evaluate than simple prefixes. In installations with thousands of Routes, replacing a regular expression with simple prefix can improve throughput and latency of {{site.base_gateway}}. If a regex must be used because an exact path match must be performed, using the [expressions router](/gateway/routing/expressions/) will significantly improve {{site.base_gateway}}’s performance in this case. ## Schema diff --git a/app/_includes/components/feature_table.html b/app/_includes/components/feature_table.html index a566f0edf..0d82b2797 100644 --- a/app/_includes/components/feature_table.html +++ b/app/_includes/components/feature_table.html @@ -26,13 +26,13 @@ {% for column in include.columns %} {% assign v = row[column.key] %} - + {% if v == true %} {% include icon_true.html %} {% elsif v == false %} {% include icon_false.html %} {% else %} - {{v}} + {{v | liquify | markdown}} {% endif %} {% endfor %} diff --git a/app/_includes/info_box/concept.html b/app/_includes/info_box/concept.html index 2d3791d77..abe08e1cb 100644 --- a/app/_includes/info_box/concept.html +++ b/app/_includes/info_box/concept.html @@ -8,4 +8,8 @@ {% if page.related_resources %} {% include info_box/sections/related_resources.html %} +{% endif %} + +{% if page.min_version %} +{% include info_box/sections/min_version.html min_version=page.min_version %} {% endif %} \ No newline at end of file diff --git a/app/gateway/routing/expressions.md b/app/gateway/routing/expressions.md index 9edd79471..9a12216b4 100644 --- a/app/gateway/routing/expressions.md +++ b/app/gateway/routing/expressions.md @@ -1,7 +1,7 @@ --- title: Expressions router -description: "{{site.base_gateway}} includes a rule-based engine using a domain-specific expressions language." +description: "The expressions router is a collection of Routes that are all evaluated against incoming requests until a match can be found." content_type: reference layout: reference @@ -12,159 +12,444 @@ products: related_resources: - text: Route entity url: /gateway/entities/route/ - - text: Routing in {{site.base_gateway}} - url: /gateway/routing/ - text: Expressions repository url: https://github.com/Kong/atc-router +min_version: + gateway: '3.0' + breadcrumbs: - /gateway/ - - /gateway/routing/ ---- - -{{ page.description | liquify }} Expressions can be used to perform tasks such as defining -complex routing logic. -This guide is a reference for the expressions language and explains how it can be used. - -## About the expressions language - -The expressions language is a strongly typed Domain-Specific Language (DSL) -that allows you to define comparison operations on various input data. -The results of the comparisons can be combined with logical operations, which allows complex routing logic to be written while ensuring good runtime matching performance. -### Key concepts - -* **Field:** The field contains value extracted from the incoming request. For example, - the request path or the value of a header field. The field value could also be absent - in some cases. An absent field value will always cause the predicate to yield `false` - no matter the operator. The field always displays to the left of the predicate. -* **Constant value:** The constant value is what the field is compared to based on the - provided operator. The constant value always displays to the right of the predicate. -* **Operator:** An operator defines the desired comparison action to be performed on the field - against the provided constant value. The operator always displays in the middle of the predicate, - between the field and constant value. -* **Predicate:** A predicate compares a field against a pre-defined value using the provided operator and - returns `true` if the field passed the comparison or `false` if it didn't. -* **Route:** A route is one or more predicates combined together with logical operators. -* **Router:** A router is a collection of routes that are all evaluated against incoming - requests until a match can be found. -* **Priority:** The priority is a positive integer that defines the order of evaluation of the router. - The bigger the priority, the sooner a route will be evaluated. In the case of duplicate - priority values between two routes in the same router, their order of evaluation is undefined. - -![Structure of a predicate](https://docs.konghq.com/assets/images/products/gateway/reference/expressions-language/predicate.png) - -A predicate is structured like the following: +faqs: + - q: When should I use the expressions router in place of (or alongside) the traditional router? + a: We recommend using the expressions router if you are running {{site.base_gateway}} 3.0.x or later. After enabling expressions, traditional match fields on the Route object (such as `paths` and `methods`) remain configurable. You may specify Expressions in the new `expression` field. However, these cannot be configured simultaneously with traditional match fields. Additionally, a new `priority` field, used in conjunction with the expression field, allows you to specify the order of evaluation for Expression Routes. +--- +The expressions router is a collection of [Routes](/gateway/entities/route/) that are all evaluated against incoming requests until a match can be found. This allows for more complex routing logic than the traditional router and ensures good runtime matching performance. + +You can do the following with the expressions router: +* Prefix-based path matching +* Regex-based path matching that is less of a performance burden than the traditional router +* Case insensitive path matching +* Match by header value +* Regex captures +* Match by source IP and destination port +* Match by SNI (for TLS Routes) + +## Enable the expressions router + +In your `kong.conf` file, set `router_flavor = expressions` and restart your {{site.base_gateway}}. Once the router is enabled, you can use the `expression` parameter when you're creating a Route to specify the Routes. + +## How requests are routed with the expressions router + +At runtime, {{site.base_gateway}} builds two separate routers for the HTTP and Stream (TCP, TLS, UDP) subsystem. When a request/connection comes in, {{site.base_gateway}} looks at which field your configured Routes require, +and supplies the value of these fields to the router execution context. +Routes are inserted into each router with the appropriate `priority` field set. The priority is a positive integer that defines the order of evaluation of the router. The bigger the priority, the sooner a Route will be evaluated. In the case of duplicate priority values between two Routes in the same router, their order of evaluation is undefined. The router is +updated incrementally as configured Routes change. + +As soon as a Route yields a match, the router stops matching and the matched Route is used to process the current request/connection. + +For example, if you have the following three Routes: + +* **Route A** + ``` + expression: http.path ^= "/foo" && http.host == "example.com" + priority: 100 + ``` +* **Route B** + ``` + expression: http.path ^= "/foo" + priority: 50 + ``` +* **Route C** + ``` + expression: http.path ^= "/" + priority: 10 + ``` + +And you have the following incoming request: ``` -http.path ^= "/foo/bar" +http.path:"/foo/bar" +http.post:"konghq.com" ``` -This predicate example has the following structure: -* `http.path`: Field -* `^=`: Operator -* `"/foo/bar"`: Constant value +The router does the following: -## How routes are executed +1. The router checks Route A first because it has the highest priority. It doesn't match the incoming request, so the router checks the Route with the next highest priority. +1. Route B has the next highest priority, so the router checks this one second. It matches the request, so the router doesn't check Route C. -At runtime, {{site.base_gateway}} builds two separate routers for the HTTP and Stream (TCP, TLS, UDP) subsystem. -Routes are inserted into each router with the appropriate `priority` field set. The router is -updated incrementally as configured routes change. +## Performance considerations -When a request/connection comes in, {{site.base_gateway}} looks at which field your configured routes require, -and supplies the value of these fields to the router execution context. This is evaluated against -the configured routes in descending order (routes with a higher `priority` number are evaluated first). +This section explains how to optimize the expressions you write to get the most performance out of the routing engine. -As soon as a route yields a match, the router stops matching and the matched route is used to process the current request/connection. +### Number of routes -![Router matching flow](https://docs.konghq.com/assets/images/products/gateway/reference/expressions-language/router-matching-flow.png) +#### Route matching priority order -> _**Figure 1:**_ Diagram of how {{site.base_gateway}} executes routes. The diagram shows that {{site.base_gateway}} selects the route that both matches the expression and then selects the matching route with the highest priority. +Expressions routes are always evaluated in the descending `priority` order they were defined. +Therefore, it is helpful to put more likely matched routes before (as in, higher priority) +less frequently matched routes. -## Expression router examples (HTTP) -### Prefix based path matching +The following examples show how you would prioritize two routes based on if they were likely to be matched or not. -Prefix based path matching is one of the most commonly used methods for routing. For example, if you want to match HTTP requests that have a path starting with `/foo/bar`, you can write the following route: +Example route 1: +``` +expression: http.path == "/likely/matched/request/path" +priority: 100 +``` +Example route 2: ``` -http.path ^= "/foo/bar" +expression: http.path == "/unlikely/matched/request/path" +priority: 50 ``` -### Regex based path matching +It's also best to reduce the number of `Route` entities created by leveraging the +logical combination capability of the expressions language. + +#### Combining routes -If you prefer to match a HTTP requests path against a regex, you can write the following route: +If multiple routes result in the same `Service` and `Plugin` config being used, +they should be combined into a single expression `Route` with the `||` logical or operator. By combining routes into a single expression, this results in fewer `Route` objects created and better performance. +Example route 1: ``` -http.path ~ r#"/foo/bar/\d+"# +service: example-service +expression: http.path == "/hello" ``` -### Case insensitive path matching +Example route 2: +``` +service: example-service +expression: http.path == "/world" +``` -If you want to ignore case when performing the path match, use the `lower()` modifier on the field -to ensure it always returns a lowercase value: +These two routes can instead be combined as: ``` -lower(http.path) == "/foo/bar" +service: example-service +expression: http.path == "/hello" || http.path == "/world" ``` -This will match requests with a path of `/foo/bar` and `/FOO/bAr`, for example. +### Regular expressions usage -### Match by header value +Regular expressions (regexes) are powerful tool that can be used to match strings based on +very complex criteria. Unfortunately, this has also made them more expensive to +evaluate at runtime and hard to optimize. Therefore, there are some common +scenarios where regex usage can be eliminated, resulting in significantly +better matching performance. -If you want to match incoming requests by the value of header `X-Foo`, do the following: +When performing exact matches (non-prefix matching) of a request path, use the `==` operator +instead of regex. +**Faster performance example:** ``` -http.headers.x_foo ~ r#"bar\d"# +http.path == "/foo/bar" ``` -If there are multiple header values for `X-Foo` and the client sends more than -one `X-Foo` header with different value, the above example will ensure **each** instance of the -value will match the regex `r#"bar\d"#`. This is called "all" style matching, meaning each instance -of the field value must pass the comparison for the predicate to return `true`. This is the default behavior. - -If you do not want this behavior, you can turn on "any" style of matching which returns -`true` for the predicate as soon as any of the values pass the comparison: - +**Slower performance example:** ``` -any(http.headers.x_foo) ~ r#"bar\d"# +http.path ~ r#"^/foo/bar$"# ``` -This will return `true` as soon as any value of `http.headers.x_foo` matches regex `r#"bar\d"#`. - -Different transformations can be chained together. The following is also a valid use case -that performs case-insensitive matching: +When performing exact matches with the `/` optional slash at the end, it is tempting to write +regexes. However, this is completely unnecessary with the expressions language. +**Faster performance example:** ``` -any(lower(http.headers.x_foo)) ~ r#"bar\d"# +http.path == "/foo/bar" || http.path == "/foo/bar/" ``` -### Regex captures - -You can define regex capture groups in any regex operation which will be made available -later for plugins to use. Currently, this is only supported with the `http.path` field: - +**Slower performance example:** ``` -http.path ~ r#"/foo/(?P.+)"# +http.path ~ r#"^/foo/?$"# ``` -The matched value of `component` will be made available later to plugins such as -[Request Transformer Advanced](https://docs.konghq.com/hub/kong-inc/request-transformer-advanced/how-to/templates/). +## Expressions router reference -## Expression router examples (TCP, TLS, UDP) +This reference explains the different configurable entities for the expressions router. -### Match by source IP and destination port +### Expressions formatting -``` -net.src.ip in 192.168.1.0/24 && net.dst.port == 8080 -``` +Each Route contains one or more predicates combined with logical operators, which {{site.base_gateway}} uses to match requests with Routes. -This matches all clients in the `192.168.1.0/24` subnet and the destination port (which is listened to by Kong) -is `8080`. IPv6 addresses are also supported. - -### Match by SNI (for TLS routes) +A predicate is the basic unit of expressions code which takes the following form: ``` -tls.sni =^ ".example.com" +http.path ^= "/foo/bar" ``` -This matches all TLS connections with the `.example.com` SNI ending. +This predicate example has the following structure: +* `http.path`: Field +* `^=`: Operator +* `"/foo/bar"`: Constant value + +Predicates are made up of smaller units that you can configure: + +| Object | Description | Example | +|--------|-------------|---------| +| Field | The field contains value extracted from the incoming request. For example, the request path or the value of a header field. The field value could also be absent in some cases. An absent field value will always cause the predicate to yield `false` no matter the operator. The field always displays to the left of the predicate. | `http.path` | +| Constant value | The constant value is what the field is compared to based on the provided operator. The constant value always displays to the right of the predicate. | `"/foo/bar"` | +| Operator | An operator defines the desired comparison action to be performed on the field against the provided constant value. The operator always displays in the middle of the predicate, between the field and constant value. | `^=` | +| Predicate | A predicate compares a field against a pre-defined value using the provided operator and returns `true` if the field passed the comparison or `false` if it didn't. | `http.path ^= "/foo/bar"` | + +### Field and constant value types + +Types define what you can use for a predicate's field and constant value. Expressions language is strongly typed. Operations are only performed +if such an operation makes sense in regard to the actual type of field and constant. + +Type conversion at runtime is not supported, either explicitly or implicitly. Types +are always known at the time a route is parsed. An error is returned +if the operator cannot be performed on the provided field and constant. + +The expressions language currently supports the following types: + + + +{% feature_table %} +item_title: Object +columns: + - title: Description + key: description + - title: Field type + key: field_type + - title: Constant type + key: constant_type +features: + - title: | + `String` + description: | + A string value, always in valid UTF-8. They can be defined with string literal that looks like `"content"`. You can also use the following escape sequences: + * `\n`: Newline character + * `\r`: Carriage return character + * `\t`: Horizontal tab character + * `\\`: The `\` character + * `\"`: The `"` character + field_type: true + constant_type: true + - title: | + `IpCidr` + description: | + Range of IP addresses in CIDR format. Can be either IPv4 (`net.src.ip in 192.168.1.0/24`) or IPv6 (`net.src.ip in fd00::/8`). The expressions parser rejects any CIDR literal where the host portion contains any non-zero bits. This means that `192.168.0.1/24` won't pass the parser check because the intention of the author is unclear. + field_type: false + constant_type: true + - title: | + `IpAddr` + description: | + A single IP address in IPv4 Dot-decimal notation (`net.src.ip == 192.168.1.1`), or the standard IPv6 Address Format (`net.src.ip == fd00::1`). Can be either IPv4 or IPv6. + field_type: true + constant_type: true + - title: | + `Int` + description: | + A 64-bit signed integer. There is only one integer type in expressions. All integers are signed 64-bit integers. Integer literals can be written as `12345`, `-12345`, or in hexadecimal format, such as `0xab12ff`, or in octet format like `0751`. + field_type: true + constant_type: true + - title: | + `Regex` + description: | + Regex are written as `String` literals, but they are parsed when the `~` regex operator is present and checked for validity according to the [Rust `regex` crate syntax](https://docs.rs/regex/latest/regex/#syntax). For example, in the following predicate, the constant is parsed as a regex: `http.path ~ r#"/foo/bar/.+"#` + field_type: false + constant_type: true +{% endfeature_table %} + + + + +In addition, expressions also supports one composite type, `Array`. Array types are written as `Type[]`. +For example: `String[]`, `Int[]`. Currently, arrays can only be present in field values. They are used in +case one field could contain multiple values. For example, `http.headers.x` or `http.queries.x`. + +#### Matching fields + +The following table describes the available matching fields, as well as their associated type when using an expressions based router. + + + +{% feature_table %} +item_title: Type +columns: + - title: Type + key: type + - title: Available in HTTP Subsystem + key: http_subsystem + - title: Available in Stream Subsystem + key: stream_subsystem + - title: Description + key: description +features: + - title: | + `net.protocol` + type: String + http_subsystem: true + stream_subsystem: true + description: | + Protocol of the route. Roughly equivalent to the `protocols` field on the `Route` entity. **Note:** Configured `protocols` on the `Route` entity are always added to the top level of the generated route but additional constraints can be provided by using the `net.protocol` field directly inside the expression. + - title: | + `tls.sni` + type: String + http_subsystem: true + stream_subsystem: true + description: | + If the connection is over TLS, the `server_name` extension from the ClientHello packet. + - title: | + `http.method` + type: String + http_subsystem: true + stream_subsystem: false + description: | + The method of the incoming HTTP request. (for example, `"GET"` or `"POST"`) + - title: | + `http.host` + type: String + http_subsystem: true + stream_subsystem: false + description: | + The `Host` header of the incoming HTTP request. + - title: | + `http.path` + type: String + http_subsystem: true + stream_subsystem: false + description: | + The normalized request path according to rules defined in [RFC 3986](https://datatracker.ietf.org/doc/html/rfc3986#section-6). This field value does **not** contain any query parameters that might exist. + - title: | + `http.path.segments.` + type: String + http_subsystem: true + stream_subsystem: false + description: | + A path segment extracted from the incoming (normalized) `http.path` with zero-based index. For example, for request path `"/a/b/c/"` or `"/a/b/c"`, `http.path.segments.1` will return `"b"`. + - title: | + `http.path.segments._` + type: String + http_subsystem: true + stream_subsystem: false + description: | + Path segments extracted from the incoming (normalized) `http.path` within the given closed interval joined by `/`. Indexes are zero-based. For example, for request path `"/a/b/c/"` or `"/a/b/c"`, `http.path.segments.0_1` will return `"a/b"`. + - title: | + `http.path.segments.len` + type: Int + http_subsystem: true + stream_subsystem: false + description: | + Number of segments from the incoming (normalized) `http.path`. For example, for request path `"/a/b/c/"` or `"/a/b/c"`, `http.path.segments.len` will return `3`. + - title: | + `http.headers.` + type: String[] + http_subsystem: true + stream_subsystem: false + description: | + The value(s) of request header ``. **Note:** The header name is always normalized to the underscore and lowercase form, so `Foo-Bar`, `Foo_Bar`, and `fOo-BAr` all become values of the `http.headers.foo_bar` field. + - title: | + `http.queries.` + type: String[] + http_subsystem: true + stream_subsystem: false + description: | + The value(s) of query parameter ``. + - title: | + `net.src.ip` + type: IpAddr + http_subsystem: true + stream_subsystem: true + description: | + IP address of the client. + - title: | + `net.src.port` + type: Int + http_subsystem: true + stream_subsystem: true + description: | + The port number used by the client to connect. + - title: | + `net.dst.ip` + type: IpAddr + http_subsystem: true + stream_subsystem: true + description: | + Listening IP address where {{site.base_gateway}} accepts the incoming connection. + - title: | + `net.dst.port` + type: Int + http_subsystem: true + stream_subsystem: true + description: | + Listening port number where {{site.base_gateway}} accepts the incoming connection. +{% endfeature_table %} + + + +### Operators + +An operator defines the desired comparison action to be performed on the field against the provided constant value. The operator always displays in the middle of the predicate, between the field and constant value. + +The expressions language supports a rich set of operators that can be performed on various data types. + +| Operator | Name | Description | +|----------------|-----------------------|--------------------------------------------------------------------------------------| +| `==` | Equals | Field value is equal to the constant value | +| `!=` | Not equals | Field value does not equal the constant value | +| `~` | Regex match | Field value matches regex | +| `^=` | Prefix match | Field value starts with the constant value | +| `=^` | Postfix match | Field value ends with the constant value | +| `>=` | Greater than or equal | Field value is greater than or equal to the constant value | +| `>` | Greater than | Field value is greater than the constant value | +| `<=` | Less than or equal | Field value is less than or equal to the constant value | +| `<` | Less than | Field value is less than the constant value | +| `in` | In | Field value is inside the constant value. This operator is used with `IpAddr` and `IpCidr` types to perform an efficient IP list check. For example, `net.src.ip in 192.168.0.0/24` will only return `true` if the value of `net.src.ip` is within `192.168.0.0/24`. | +| `not in` | Not in | Field value is not inside the constant value. This operator is used with `IpAddr` and `IpCidr` types to perform an efficient IP list check. For example, `net.src.ip in 192.168.0.0/24` will only return `true` if the value of `net.src.ip` is within `192.168.0.0/24`. | +| `contains` | Contains | Field value contains the constant value. This operator is used to check the existence of a string inside another string. For example, `http.path contains "foo"` will return `true` if `foo` can be found anywhere inside `http.path`. This will match a `http.path` that looks like `/foo`, `/abc/foo`, or `/xfooy`, for example. | +| `&&` | And | Returns `true` if **both** expressions on the left and right side evaluates to `true` | +| `||` | Or | Returns `true` if **any** expressions on the left and right side evaluates to `true` | | +| `(Expression)` | Parenthesis | Groups expressions together to be evaluated first | +| `!` | Not | Negates the result of a parenthesized expression. **Note:** The `!` operator can only be used with parenthesized expression like `!(foo == 1)`, it **cannot** be used with a bare predicate like `! foo == 1` | + +### Allowed type and operator combinations + +Depending on the field type, only certain content types and operators are supported. + +| Field type | Supported content types and their supported operators | +|------------|-------------------------------------------------------| +| `String` | * `String`: `==`, `!=`, `~`, `^=`, `=^`, `contains`
* `Regex`: `~` | +| `IpAddr` | * `IpCidr`: `in`, `not in`
* `IpAddr`: `==` | +| `Int` | `Int`: `==`, `!=`, `>=`, `>`, `<=`, `<` | +| `Expression` | `Regex`: `&&`, `||` | + + +{:.note} +> **Notes:** + * The `~` operator is described as supporting both `String ~ String` and `String ~ Regex`. + In reality, `Regex` constant values can only be written as `String` on the right hand side. + The presence of `~` operators treats the string value as a regex. + Even with the `~` operator, `String` escape rules described previously still apply and it + is almost always easier to use raw string literals for the `~` operator. + * The `~` operator does not automatically anchor the regex to the beginning of the input. + Meaning `http.path ~ r#"/foo/\d"#` could match a path like `/foo/1` or `/some/thing/foo/1`. + If you want to match from the beginning of the string (anchoring the regex), then you must + manually specify it with the `^` meta-character. For example, `http.path ~ r#"^/foo/\d"#`. + * When performing IP address-related comparisons with `==`, `in`, or `not in`, different families of + address types for the field and constant value will always cause the predicate to return `false` at + runtime. + +## Example expressions + +### HTTP examples + +| Name | Example expression | Description | +|------|--------------------|-------------| +| Prefix based path matching | `http.path ^= "/foo/bar"` | Matches HTTP requests that have a path starting with `/foo/bar` | +| Regex based path matching | `http.path ~ r#"/foo/bar/\d+"#` | N/A | +| Case insensitive path matching | `lower(http.path) == "/foo/bar"` | Ignores case when performing the path match. | +| Match by header value ("all" style matching) | `http.headers.x_foo ~ r#"bar\d"#` | If there are multiple header values for `X-Foo` and the client sends more than one `X-Foo` header with different values, the above example will ensure **each** instance of the value will match the regex `r#"bar\d"#`. This is called "all" style matching. | +| Match by header value ("any" style matching) | `any(http.headers.x_foo) ~ r#"bar\d"#` | Returns `true` for the predicate as soon as any of the values pass the comparison. Can be combined with other transformations, like `lower()`. | +| Regex captures | `http.path ~ r#"/foo/(?P.+)"#` | You can define regex capture groups in any regex operation which will be made available later for plugins to use. Currently, this is only supported with the `http.path` field. The matched value of `component` will be made available later to plugins such as [Request Transformer Advanced](/plugins/request-transformer-advanced/). | + +### TCP, TLS, and UDP examples + +| Name | Example expression | Description | +|------|--------------------|-------------| +| Match by source IP and destination port | `net.src.ip in 192.168.1.0/24 && net.dst.port == 8080` | This matches all clients in the `192.168.1.0/24` subnet and the destination port (which is listened to by {{site.base_gateway}}) is `8080`. IPv6 addresses are also supported. | +| Match by SNI (for TLS routes) | `tls.sni =^ ".example.com"` | This matches all TLS connections with the `.example.com` SNI ending. | + diff --git a/app/gateway/routing/index.md b/app/gateway/routing/index.md deleted file mode 100644 index 8e5810cc5..000000000 --- a/app/gateway/routing/index.md +++ /dev/null @@ -1,117 +0,0 @@ ---- -title: Routing in {{site.base_gateway}} - -description: This page explains how routing works in {{site.base_gateway}}. - -content_type: reference -layout: reference - -products: - - gateway - -related_resources: - - text: Route entity - url: /gateway/entities/route/ - - text: Expressions router - url: /gateway/routing/expressions/ - -breadcrumbs: - - /gateway/ ---- - -## How requests are routed - -For each incoming request, {{site.base_gateway}} must determine which -service gets to handle it based on the routes that are defined. With -release 3.0, {{site.base_gateway}} introduced a router that can be -running in two modes: the `traditional_compat` mode, which is -configured like prior releases, and the `expressions` mode which uses -a new configuration scheme. We recommend that new deployments use -the expressions router as it is more powerful and expressive. - -The default mode of the router is `traditional_compat` and the -following sections describe how it operates. `traditional_compat` -mode is designed to behave like the router in versions before -{{site.base_gateway}} 3.x. For a description of the `expressions` mode, see -[How to Configure Routes using Expressions](/gateway/routing/expressions/). - -In general, the router orders all defined routes by their priority and -uses the highest priority matching route to handle a request. If there -are multiple matching routes with the same priority, it is not defined -which of the matching routes will be used and {{site.base_gateway}} -will use either of them according to how its internal data structures -are organized. - -If a route contains prefix or regular expression paths, the priority -of the route will be calculated separately for each of the paths and -requests will be routed accordingly. - -In `traditional_compat` mode, the priority of a route is determined as -follows, by the order of descending significance: - -1. Priority points -2. Wildcard hosts -3. Header count -4. Regular expressions and prefix paths - -### Priority points - -For the presence of each of a route's `methods`, `host`, `headers`, -and `snis`, a "priority point" will be added to the route. The number -of "priority points" determines the overall order in which the routes -will be considered. Routes with a higher "priority point" values will -be considered before those with lower values. This means that if one -route has `methods` defined, and second one has `methods` and -`headers` defined, the second one will be considered before the first -one. - -### Wildcard hosts - -Among the routes with the same "priority point" value, those that have -any wildcard host specification will be considered after routes that -don't have any wildcard host (or no host) specified. - -### Header count - -The resulting groups are sorted so the routes with a higher number of -specified headers have higher priority than those with a lower number -of headers. - -## Regular expressions and prefix paths - -Within the resulting groups of routes with equal priority, the router -sorts the routes as follows: - - - Routes that have a regular expression path are considered first and - are ordered by their `regex_priority` value. Routes with a higher - `regex_priority` are considered before routes with lower - `regex_priority` values. - - Routes that have no regular expression path are ordered by the - length of their paths. Routes with longer paths are considered - before routes with shorter paths. - -For a route with multiple paths, each path will be considered -separately for priority determination. Effectively, this means that -separate routes exists for each of the paths. - -## Regular expressions - -Regular expressions used in routes use more resources to evaluate than -simple prefix routes. If many regular expressions must be evaluated -to route a request, the latency introduced by {{site.base_gateway}} -can suffer and its CPU usage can increase. In installations with -thousands of routes, replacing regular expression routes by simple -prefix routes can improve throughput and latency of -{{site.base_gateway}}. If regex must be used because an exact -path match must be performed, using the [expressions router](/gateway/routing/expressions/) -will significantly improve {{site.base_gateway}}'s performance in this case. - -Starting with version 3.0, {{site.base_gateway}} uses the regular -expression engine shipped with the [Rust](https://docs.rs/regex/latest/regex/) programming language if the -router is operating in `expressions` or `traditional_compatible` mode. -Prior versions used the -[PCRE library](https://www.pcre.org/original/doc/html/pcrepattern.html) -to evaluate regular expression. While the two engines are largely -compatible, subtle differences exist between the two. Refer to -the documentation pertinent to the engine that you are using if you -have problems getting regular expression routes to work. diff --git a/app/gateway/traffic-control/proxying.md b/app/gateway/traffic-control/proxying.md new file mode 100644 index 000000000..7b88a6a65 --- /dev/null +++ b/app/gateway/traffic-control/proxying.md @@ -0,0 +1,33 @@ +--- +title: Proxying with {{site.base_gateway}} + +description: "Proxying is when {{site.base_gateway}} matches an HTTP request with a [registered route](/gateway/entities/route/) and forwards the request." + +content_type: reference +layout: reference + +products: + - gateway + +related_resources: + - text: Route entity + url: /gateway/entities/route/ + - text: Router Expressions language + url: /gateway/routing/expressions/ + - text: Expressions repository + url: https://github.com/Kong/atc-router + +breadcrumbs: + - /gateway/ +--- + +@todo + + \ No newline at end of file diff --git a/tools/track-docs-changes/config/sources.yml b/tools/track-docs-changes/config/sources.yml index d856cd68b..e062ef0ad 100644 --- a/tools/track-docs-changes/config/sources.yml +++ b/tools/track-docs-changes/config/sources.yml @@ -46,11 +46,21 @@ app/_gateway_entities/service.md: - app/_src/gateway/key-concepts/services.md app/_gateway_entities/target.md: - app/_src/gateway/key-concepts/services.md + - app/_src/gateway/get-started/load-balancing.md + - app/_src/gateway/key-concepts/upstreams.md + - app/_src/gateway/how-kong-works/load-balancing.md app/_gateway_entities/upstream.md: - app/_src/gateway/key-concepts/upstreams.md + - app/_src/gateway/how-kong-works/load-balancing.md + - app/_src/gateway/how-kong-works/health-checks.md app/_gateway_entities/workspace.md: - app/_src/gateway/kong-manager/workspaces.md - app/_src/gateway/kong-enterprise/workspaces.md +app/_gateway_entities/route.md: + - app/_src/gateway/how-kong-works/routing-traffic.md + - app/_src/gateway/key-concepts/routes/index.md +app/_gateway_entities/upstream.md: + - app/_src/gateway/key-concepts/upstreams.md app/_gateway_entities/event_hooks.md: - app/_src/gateway/latest/kong-enterprise/event-hooks.md @@ -126,8 +136,6 @@ app/gateway/rate-limiting/strategies.md: app/gateway/rate-limiting/window-types.md: - app/_hub/kong-inc/rate-limiting-advanced/overview/_index.md - app/_hub/kong-inc/rate-limiting/overview/_index.md -app/gateway/routing/expressions.md: - - app/_src/gateway/reference/expressions-language/index.md app/gateway/routing/index.md: - app/_src/gateway/key-concepts/routes/index.md app/plugins/deployment-options.md: @@ -136,6 +144,18 @@ app/plugins/protocols.md: - app/hub/plugins/compatibility/index.md app/plugins/scopes.md: - app/hub/plugins/compatibility/index.md + +# traffic control +app/gateway/traffic-control/proxy.md: + - app/_src/gateway/how-kong-works/routing-traffic.md + - app/_includes/md/admin-listen.md +app/gateway/routing/expressions.md: + - app/_src/gateway/reference/expressions-language/index.md + - app/_src/gateway/key-concepts/routes/expressions.md + - app/_src/gateway/reference/expressions-language/language-references.md + - app/_src/gateway/reference/expressions-language/performance.md +app/gateway/routing/expressions-router-examples.md: + - app/_src/gateway/reference/expressions-language/index.md app/gateway/networking/dns-config-reference.md: - app/_src/gateway/production/networking/dns-considerations.md