From 2d0e1abed98b06ad3a9fb65856aa3820ed26d145 Mon Sep 17 00:00:00 2001 From: Diana <75819066+cloudjumpercat@users.noreply.github.com> Date: Tue, 10 Dec 2024 13:19:29 -0600 Subject: [PATCH 01/34] Start revising routes entity page Signed-off-by: Diana <75819066+cloudjumpercat@users.noreply.github.com> --- app/_gateway_entities/route.md | 84 ++++++++++++++++++++++++---------- 1 file changed, 60 insertions(+), 24 deletions(-) diff --git a/app/_gateway_entities/route.md b/app/_gateway_entities/route.md index 24f0a803c..383a1a89c 100644 --- a/app/_gateway_entities/route.md +++ b/app/_gateway_entities/route.md @@ -15,30 +15,58 @@ related_resources: url: /gateway/routing/expressions/ 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 --- -## What is a route? - -{{page.description}} 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. - -You can also configure routes with: - -* 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 +## What is a route? + +{{page.description}} [Services](/gateway/entities/service/) 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 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. + +When you configure routes, you can also specify the following: + +* **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 + +The following diagram shows how routes work: + +{% mermaid %} +flowchart LR + A(API client) + B("`Route + (/mock)`") + C("`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 @@ -46,15 +74,23 @@ Routes, in conjunction with [services](/gateway/entities/service/), let you expo 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. -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. +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. -## Dynamically rewrite request URLs with routes +## How routing works -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`. +### Proxying? + + + +## Dynamically rewrite request URLs with routes -{{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](https://docs.konghq.com/hub/kong-inc/request-transformer-advanced/) plugin. For example, this can be used when you must replace `/api//old` with `/new/api/`. +Routes can be configured dynamically to rewrite the requested URL to a different URL for the upstream. Depending on your use case, there are several methods you can use: -{{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/). +| You want to... | Then use... | +|--------|----------| +| Perform a simple URL rewrite, such as renaming your legacy `/api/old/` upstream endpoint to a publicly accessible API endpoint that is now named `/new/api`. | [Set up a service with the old path and a route with new path](/) | +| Performa complex URL rewrite, such as replacing `/api//old` with `/new/api/`. | [Request Transformer Advanced plugin](https://docs.konghq.com/hub/kong-inc/request-transformer-advanced/) | +| Describe routes or paths as patterns using regular expressions. | [Expressions router](/gateway/routing/expressions/) | ## Schema From 28045531be178c20f470d1e17652a2914d111eaf Mon Sep 17 00:00:00 2001 From: Diana <75819066+cloudjumpercat@users.noreply.github.com> Date: Tue, 10 Dec 2024 16:00:01 -0600 Subject: [PATCH 02/34] Continue revising routes entity, start drafting the rewrite URLs how to Signed-off-by: Diana <75819066+cloudjumpercat@users.noreply.github.com> --- app/_gateway_entities/route.md | 58 +++++++++- ...rewrite-simple-request-urls-with-routes.md | 102 ++++++++++++++++++ 2 files changed, 158 insertions(+), 2 deletions(-) create mode 100644 app/_how-tos/dynamically-rewrite-simple-request-urls-with-routes.md diff --git a/app/_gateway_entities/route.md b/app/_gateway_entities/route.md index 383a1a89c..edaa1b9c7 100644 --- a/app/_gateway_entities/route.md +++ b/app/_gateway_entities/route.md @@ -78,9 +78,63 @@ In the example above, two routes can be created, say `/external` and `/internal` ## How routing works -### Proxying? +For each incoming request, {{site.base_gateway}} must determine which service gets to handle it based on the routes that are defined. 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. + +{{site.base_gateway}} supports native proxying of HTTP/HTTPS, TCP/TLS, and GRPC/GRPCS protocols. Each of these protocols accept a different set of routing attributes: +- `http`: `methods`, `hosts`, `headers`, `paths` (and `snis`, if `https`) +- `tcp`: `sources`, `destinations` (and `snis`, if `tls`) +- `grpc`: `hosts`, `headers`, `paths` (and `snis`, if `grpcs`) + +Note that all of these fields are **optional**, but at least **one of them** +must be specified. + +For a request to match a route: + +- The request **must** include **all** of the configured fields +- The values of the fields in the request **must** match at least one of the + configured values (While the field configurations accepts one or more values, + a request needs only one of the values to be considered a match) + +The routing method you should use depends on your {{site.base_gateway}} version: + +| {{site.base_gateway}} version | Routing method | Description | +|-------------------------------|----------------|-------------| +| All | Traditional compatibility | Only recommended for anyone running {{site.base_gateway}} 2.9.x or earlier. The original routing method for {{site.base_gateway}}. | +| 3.0.x or later | [Expressions router](/gateway/routing/expressions/) | The recommended method for anyone running {{site.base_gateway}} 3.0.x or later. Can be run in both `traditional_compat` and `expressions` modes. | + +### Traditional compatibility mode + +In `traditional_compat` mode, the priority of a route is determined as +follows, by the order of descending significance: + +1. **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. +2. **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. +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:** 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. + +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](/). + +### Expressions router mode + +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. + +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](/). + +### Routing performance recommendations +You can use the following recommendations to increase routing performance: +* In `expressions` mode, we recommend putting more likely matched routes before (as in, higher priority) less frequently matched routes. +* Regular expressions used in routes use more resources to evaluate than simple prefix routes. In installations with thousands of routes, replacing regular expression routes with 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. ## Dynamically rewrite request URLs with routes @@ -88,7 +142,7 @@ Routes can be configured dynamically to rewrite the requested URL to a different | You want to... | Then use... | |--------|----------| -| Perform a simple URL rewrite, such as renaming your legacy `/api/old/` upstream endpoint to a publicly accessible API endpoint that is now named `/new/api`. | [Set up a service with the old path and a route with new path](/) | +| Perform a simple URL rewrite, such as renaming your legacy `/api/old/` upstream endpoint to a publicly accessible API endpoint that is now named `/new/api`. | [Set up a service with the old path and a route with new path](/how-to/dynamically-rewrite-simple-request-urls-with-routes/) | | Performa complex URL rewrite, such as replacing `/api//old` with `/new/api/`. | [Request Transformer Advanced plugin](https://docs.konghq.com/hub/kong-inc/request-transformer-advanced/) | | Describe routes or paths as patterns using regular expressions. | [Expressions router](/gateway/routing/expressions/) | diff --git a/app/_how-tos/dynamically-rewrite-simple-request-urls-with-routes.md b/app/_how-tos/dynamically-rewrite-simple-request-urls-with-routes.md new file mode 100644 index 000000000..55cd63e4a --- /dev/null +++ b/app/_how-tos/dynamically-rewrite-simple-request-urls-with-routes.md @@ -0,0 +1,102 @@ +--- +title: Dynamically rewrite simple request URLs with {{site.base_gateway}} Routes +content_type: how_to +related_resources: + - text: Routes + url: /gateway/entities/route/ + - text: Services + url: /gateway/entities/service/ + - text: Routing in {{site.base_gateway}} + url: /gateway/routing/ + - text: Expressions router + url: /gateway/routing/expressions/ + +products: + - gateway + +works_on: + - on-prem + - konnect + +tools: + - deck + +prereqs: + entities: + services: + - example-service + routes: + - example-route + +min_version: + gateway: 3.4 + +entities: + - service + - route + +tags: + - routing + - traffic-control + +tldr: + q: things + a: things + +faqs: + - q: My URLs are more complex, what should I use instead to rewrite them? + a: Request transformer plugin or + +cleanup: + inline: + - title: Clean up Konnect environment + include_content: cleanup/platform/konnect + icon_url: /assets/icons/gateway.svg + - title: Destroy the {{site.base_gateway}} container + include_content: cleanup/products/gateway + icon_url: /assets/icons/gateway.svg +--- + +## 1. Set up a service with the path to the old upstream + +In the prerequisites, you created the `example-service` and `example-route` with the `/anything` path. This path, `/anything`, is your old upstream path. You must modify your existing service to contain the old `/anything` path. By doing it this way, traffic can continue to be routed to the old path while you enable the new path. + +{% entity_examples %} +entities: + services: + - name: example-service + url: http://httpbin.konghq.com/anything + path: /anything +{% endentity_examples %} + +## 2. Set up a route with the path to the new upstream + +Now you can create a route with your new path, `/new-path`, that points to the new upstream. + +{% entity_examples %} +entities: + routes: + - name: new-route + paths: + - "/new-path" + service: + name: example-service +{% endentity_examples %} + +## 3. Validate + +To validate that the URL was successfully rewritten and the request is now being matched to the new upstream instead of the old one, run the following: + +```bash +curl -i http://localhost:8000/new-path -H; echo; done +``` +{: data-deployment-topology="on-prem" } + +```bash +curl -i http://{host}/new-path -H; echo; done +``` +{: data-deployment-topology="konnect" } +Replace `{host}` with the proxy URL for this data plane node. +{: data-deployment-topology="konnect" } + +This command should redirect you to the new URL. \ No newline at end of file From 9a845e9c8d6506c25f0a6e220243a75e60445657 Mon Sep 17 00:00:00 2001 From: Diana <75819066+cloudjumpercat@users.noreply.github.com> Date: Wed, 11 Dec 2024 08:30:25 -0600 Subject: [PATCH 03/34] Fix vale spelling error Signed-off-by: Diana <75819066+cloudjumpercat@users.noreply.github.com> --- app/_gateway_entities/route.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/_gateway_entities/route.md b/app/_gateway_entities/route.md index edaa1b9c7..142f8e700 100644 --- a/app/_gateway_entities/route.md +++ b/app/_gateway_entities/route.md @@ -143,7 +143,7 @@ Routes can be configured dynamically to rewrite the requested URL to a different | You want to... | Then use... | |--------|----------| | Perform a simple URL rewrite, such as renaming your legacy `/api/old/` upstream endpoint to a publicly accessible API endpoint that is now named `/new/api`. | [Set up a service with the old path and a route with new path](/how-to/dynamically-rewrite-simple-request-urls-with-routes/) | -| Performa complex URL rewrite, such as replacing `/api//old` with `/new/api/`. | [Request Transformer Advanced plugin](https://docs.konghq.com/hub/kong-inc/request-transformer-advanced/) | +| Perform complex URL rewrite, such as replacing `/api//old` with `/new/api/`. | [Request Transformer Advanced plugin](https://docs.konghq.com/hub/kong-inc/request-transformer-advanced/) | | Describe routes or paths as patterns using regular expressions. | [Expressions router](/gateway/routing/expressions/) | ## Schema From 117daae0ff1968097b74537fa3915f764a556954 Mon Sep 17 00:00:00 2001 From: Diana <75819066+cloudjumpercat@users.noreply.github.com> Date: Wed, 11 Dec 2024 09:01:15 -0600 Subject: [PATCH 04/34] Capitalize entities Signed-off-by: Diana <75819066+cloudjumpercat@users.noreply.github.com> --- app/_gateway_entities/route.md | 72 +++++++++---------- ...rewrite-simple-request-urls-with-routes.md | 10 +-- 2 files changed, 41 insertions(+), 41 deletions(-) diff --git a/app/_gateway_entities/route.md b/app/_gateway_entities/route.md index 142f8e700..7c07355a1 100644 --- a/app/_gateway_entities/route.md +++ b/app/_gateway_entities/route.md @@ -4,10 +4,10 @@ content_type: reference entities: - route -description: A route is a path to a resource within an upstream application. +description: A Route is a path to a resource within an upstream application. related_resources: - - text: Services + - text: Gateway Services url: /gateway/entities/service/ - text: Routing in {{site.base_gateway}} url: /gateway/routing/ @@ -27,22 +27,22 @@ schema: --- -## What is a route? +## What is a Route? -{{page.description}} [Services](/gateway/entities/service/) 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 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. +{{page.description}} [Gateway Services](/gateway/entities/service/) 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 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. +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. -When you configure routes, you can also specify the following: +When you configure Routes, you can also specify the following: * **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 +* **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 +* **Tags:** Optional set of strings to group Routes with -The following diagram shows how routes work: +The following diagram shows how Routes work: {% mermaid %} flowchart LR @@ -68,20 +68,20 @@ flowchart LR {% endmermaid %} -## Route and service interaction +## 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. +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, 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. +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. -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. +In the example above, two Routes can be created, say `/external` and `/internal`, and both of them can point to `example_service`. You can configure a policy to limit how often the `/external` Route is used and it 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're rate limited. But when the internal client accesses the Service using {{site.base_gateway}} using `/internal`, the internal client isn't limited. ## 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. 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}} +For each incoming request, {{site.base_gateway}} must determine which service gets to handle it based on the Routes that are defined. 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. @@ -93,7 +93,7 @@ are organized. Note that all of these fields are **optional**, but at least **one of them** must be specified. -For a request to match a route: +For a request to match a Route: - The request **must** include **all** of the configured fields - The values of the fields in the request **must** match at least one of the @@ -109,42 +109,42 @@ The routing method you should use depends on your {{site.base_gateway}} version: ### Traditional compatibility mode -In `traditional_compat` mode, the priority of a route is determined as +In `traditional_compat` mode, the priority of a Route is determined as follows, by the order of descending significance: -1. **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. -2. **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. -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:** 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. +1. **Priority points:** For the presence of each of a Route's `methods`, `host`, `headers`, and `snis`, a "priority point" is added. 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. +2. **Wildcard hosts:** Among Routes with the same "priority point" value, those that have any wildcard host specification will be considered after those that don't have any wildcard host (or no host) specified. +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:** Within the resulting groups of Routes with equal priority, the router sorts them 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 those 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 those 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. + For a Route with multiple paths, each path will be considered separately for priority determination. Effectively, this means that separate Routes exist for each of the paths. -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](/). +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](/). ### Expressions router mode -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. +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. -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](/). +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](/). ### Routing performance recommendations You can use the following recommendations to increase routing performance: -* In `expressions` mode, we recommend putting more likely matched routes before (as in, higher priority) less frequently matched routes. -* Regular expressions used in routes use more resources to evaluate than simple prefix routes. In installations with thousands of routes, replacing regular expression routes with 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. +* 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 regular expression with simple prefix 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. -## Dynamically rewrite request URLs with routes +## Dynamically rewrite request URLs with Routes -Routes can be configured dynamically to rewrite the requested URL to a different URL for the upstream. Depending on your use case, there are several methods you can use: +Routes can be configured dynamically to rewrite the requested URL to a different URL for the Upstream. Depending on your use case, there are several methods you can use: | You want to... | Then use... | |--------|----------| -| Perform a simple URL rewrite, such as renaming your legacy `/api/old/` upstream endpoint to a publicly accessible API endpoint that is now named `/new/api`. | [Set up a service with the old path and a route with new path](/how-to/dynamically-rewrite-simple-request-urls-with-routes/) | +| Perform a simple URL rewrite, such as renaming your legacy `/api/old/` upstream endpoint to a publicly accessible API endpoint that is now named `/new/api`. | [Set up a Gateway Service with the old path and a Route with new path](/how-to/dynamically-rewrite-simple-request-urls-with-routes/) | | Perform complex URL rewrite, such as replacing `/api//old` with `/new/api/`. | [Request Transformer Advanced plugin](https://docs.konghq.com/hub/kong-inc/request-transformer-advanced/) | -| Describe routes or paths as patterns using regular expressions. | [Expressions router](/gateway/routing/expressions/) | +| Describe Routes or paths as patterns using regular expressions. | [Expressions router](/gateway/routing/expressions/) | ## Schema diff --git a/app/_how-tos/dynamically-rewrite-simple-request-urls-with-routes.md b/app/_how-tos/dynamically-rewrite-simple-request-urls-with-routes.md index 55cd63e4a..849a92ff8 100644 --- a/app/_how-tos/dynamically-rewrite-simple-request-urls-with-routes.md +++ b/app/_how-tos/dynamically-rewrite-simple-request-urls-with-routes.md @@ -57,9 +57,9 @@ cleanup: icon_url: /assets/icons/gateway.svg --- -## 1. Set up a service with the path to the old upstream +## 1. Set up a Service with the path to the old Upstream -In the prerequisites, you created the `example-service` and `example-route` with the `/anything` path. This path, `/anything`, is your old upstream path. You must modify your existing service to contain the old `/anything` path. By doing it this way, traffic can continue to be routed to the old path while you enable the new path. +In the prerequisites, you created the `example-service` and `example-route` with the `/anything` path. This path, `/anything`, is your old upstream path. You must modify your existing Service to contain the old `/anything` path. By doing it this way, traffic can continue to be routed to the old path while you enable the new path. {% entity_examples %} entities: @@ -69,9 +69,9 @@ entities: path: /anything {% endentity_examples %} -## 2. Set up a route with the path to the new upstream +## 2. Set up a Route with the path to the new Upstream -Now you can create a route with your new path, `/new-path`, that points to the new upstream. +Now you can create a Route with your new path, `/new-path`, that points to the new Upstream. {% entity_examples %} entities: @@ -85,7 +85,7 @@ entities: ## 3. Validate -To validate that the URL was successfully rewritten and the request is now being matched to the new upstream instead of the old one, run the following: +To validate that the URL was successfully rewritten and the request is now being matched to the new Upstream instead of the old one, run the following: ```bash curl -i http://localhost:8000/new-path -H; echo; done From c3c8da618adf5f64c88b9aafa4fe09fa4bd56cb9 Mon Sep 17 00:00:00 2001 From: Diana <75819066+cloudjumpercat@users.noreply.github.com> Date: Wed, 11 Dec 2024 15:25:43 -0600 Subject: [PATCH 05/34] Revise how to after testing Signed-off-by: Diana <75819066+cloudjumpercat@users.noreply.github.com> --- app/_gateway_entities/route.md | 27 ++++++++++--------- ...rewrite-simple-request-urls-with-routes.md | 27 +++++++++++-------- 2 files changed, 31 insertions(+), 23 deletions(-) diff --git a/app/_gateway_entities/route.md b/app/_gateway_entities/route.md index 7c07355a1..1b8b49d27 100644 --- a/app/_gateway_entities/route.md +++ b/app/_gateway_entities/route.md @@ -13,6 +13,8 @@ related_resources: url: /gateway/routing/ - text: Expressions router url: /gateway/routing/expressions/ + - text: Upstreams + url: /gateway/entities/upstream/ tools: - admin-api @@ -35,14 +37,18 @@ Routes can also define rules that match requests to associated Services. Because When you configure Routes, you can also specify the following: -* **Protocols:** The protocol used to communicate with the upstream application. +* **Protocols:** The protocol used to communicate with the [upstream application](/gateway/entities/upstream/). * **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 -The following diagram shows how Routes work: +## 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. + +The following diagram shows how Routes interact with other {{site.base_gateway}} entities: {% mermaid %} flowchart LR @@ -68,11 +74,7 @@ flowchart LR {% 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, 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. +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 it, the internal application is limited as well. Routes can solve this problem. In the example above, two Routes can be created, say `/external` and `/internal`, and both of them can point to `example_service`. You can configure a policy to limit how often the `/external` Route is used and it 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're rate limited. But when the internal client accesses the Service using {{site.base_gateway}} using `/internal`, the internal client isn't limited. @@ -102,9 +104,9 @@ For a request to match a Route: The routing method you should use depends on your {{site.base_gateway}} version: -| {{site.base_gateway}} version | Routing method | Description | +| Recommended {{site.base_gateway}} version | Routing method | Description | |-------------------------------|----------------|-------------| -| All | Traditional compatibility | Only recommended for anyone running {{site.base_gateway}} 2.9.x or earlier. The original routing method for {{site.base_gateway}}. | +| 2.9.x or earlier | Traditional compatibility | Only recommended for anyone running {{site.base_gateway}} 2.9.x or earlier. The original routing method for {{site.base_gateway}}. | | 3.0.x or later | [Expressions router](/gateway/routing/expressions/) | The recommended method for anyone running {{site.base_gateway}} 3.0.x or later. Can be run in both `traditional_compat` and `expressions` modes. | ### Traditional compatibility mode @@ -136,14 +138,15 @@ You can use the following recommendations to increase routing performance: * 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 regular expression with simple prefix 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. -## Dynamically rewrite request URLs with Routes +## Route use cases -Routes can be configured dynamically to rewrite the requested URL to a different URL for the Upstream. Depending on your use case, there are several methods you can use: +Use the following table to help you understand how Routes can be configured for different use cases: | You want to... | Then use... | |--------|----------| +| Rate limit internal and external traffic to a service | [Enable a rate limiting plugin on routes attached to the service](/plugins/rate-limiting-advanced/) | | Perform a simple URL rewrite, such as renaming your legacy `/api/old/` upstream endpoint to a publicly accessible API endpoint that is now named `/new/api`. | [Set up a Gateway Service with the old path and a Route with new path](/how-to/dynamically-rewrite-simple-request-urls-with-routes/) | -| Perform complex URL rewrite, such as replacing `/api//old` with `/new/api/`. | [Request Transformer Advanced plugin](https://docs.konghq.com/hub/kong-inc/request-transformer-advanced/) | +| Perform a complex URL rewrite, such as replacing `/api//old` with `/new/api/`. | [Request Transformer Advanced plugin](https://docs.konghq.com/hub/kong-inc/request-transformer-advanced/) | | Describe Routes or paths as patterns using regular expressions. | [Expressions router](/gateway/routing/expressions/) | ## Schema diff --git a/app/_how-tos/dynamically-rewrite-simple-request-urls-with-routes.md b/app/_how-tos/dynamically-rewrite-simple-request-urls-with-routes.md index 849a92ff8..1e8ad9b3c 100644 --- a/app/_how-tos/dynamically-rewrite-simple-request-urls-with-routes.md +++ b/app/_how-tos/dynamically-rewrite-simple-request-urls-with-routes.md @@ -28,9 +28,6 @@ prereqs: routes: - example-route -min_version: - gateway: 3.4 - entities: - service - route @@ -40,12 +37,12 @@ tags: - traffic-control tldr: - q: things - a: things + q: How can I divert traffic from an old URL to a new one with {{site.base_gateway}}? + a: Set up a Gateway Service with the old URL path and create a new a Route with new path.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 can set up a Service with the path `/api/old/` and a Route with the path `/new/api`. faqs: - - q: My URLs are more complex, what should I use instead to rewrite them? - a: Request transformer plugin or + - q: My URLs are more complex, such as replacing `/api//old` with `/new/api/`, what should I use instead to rewrite them? + a: You can use the [Request Transformer plugin](/hub/request-transformer/) for a complex URL rewrite or the [expressions router](/gateway/routing/expressions/) ({{site.base_gateway}} 3.0.x or later) to describe Routes or paths as patterns using regular expressions. cleanup: inline: @@ -67,8 +64,11 @@ entities: - name: example-service url: http://httpbin.konghq.com/anything path: /anything +append_to_existing_section: true {% endentity_examples %} + + ## 2. Set up a Route with the path to the new Upstream Now you can create a Route with your new path, `/new-path`, that points to the new Upstream. @@ -81,22 +81,27 @@ entities: - "/new-path" service: name: example-service +append_to_existing_section: true {% endentity_examples %} -## 3. Validate +## 3. Apply configuration + +{% include how-tos/steps/apply_config.md %} + +## 4. Validate To validate that the URL was successfully rewritten and the request is now being matched to the new Upstream instead of the old one, run the following: ```bash -curl -i http://localhost:8000/new-path -H; echo; done +curl -i http://localhost:8000/new-path ``` {: data-deployment-topology="on-prem" } ```bash -curl -i http://{host}/new-path -H; echo; done +curl -i http://{host}/new-path ``` {: data-deployment-topology="konnect" } Replace `{host}` with the proxy URL for this data plane node. {: data-deployment-topology="konnect" } -This command should redirect you to the new URL. \ No newline at end of file +This command should display a 200 status as you're redirected to the new URL. \ No newline at end of file From ccbd48ed01566981ff4780e8f1ebf3cf503141d9 Mon Sep 17 00:00:00 2001 From: Diana <75819066+cloudjumpercat@users.noreply.github.com> Date: Wed, 11 Dec 2024 16:01:54 -0600 Subject: [PATCH 06/34] Plan out routing section for matching and priority section split Signed-off-by: Diana <75819066+cloudjumpercat@users.noreply.github.com> --- app/_gateway_entities/route.md | 33 +++++++++++++++++++++++++++------ 1 file changed, 27 insertions(+), 6 deletions(-) diff --git a/app/_gateway_entities/route.md b/app/_gateway_entities/route.md index 1b8b49d27..3f63f1d75 100644 --- a/app/_gateway_entities/route.md +++ b/app/_gateway_entities/route.md @@ -80,12 +80,16 @@ In the example above, two Routes can be created, say `/external` and `/internal` ## 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. 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 +For each incoming request, {{site.base_gateway}} must determine which service gets to handle it based on the Routes that are defined. {{site.base_gateway}} first finds Routes that match by comparing the defined routing attributes with the attributes in the request. 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. + +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. +are organized. If two or more Routes are configured with fields containing the same values, {{site.base_gateway}} applies a priority rule. {{site.base_gateway}} first tries to match the routes with the most rules. + +### Matching routing attributes + +When you configure a Route, you must define certain attributes that {{site.base_gateway}} will use to match incoming requests. {{site.base_gateway}} supports native proxying of HTTP/HTTPS, TCP/TLS, and GRPC/GRPCS protocols. Each of these protocols accept a different set of routing attributes: - `http`: `methods`, `hosts`, `headers`, `paths` (and `snis`, if `https`) @@ -102,6 +106,23 @@ For a request to match a Route: configured values (While the field configurations accepts one or more values, a request needs only one of the values to be considered a match) +#### things to cover in some way + +* Headers + * regular hosts (how an array is handled) + * wild card host + * explain preserve_host=true + * other headers (like `version`) +* Paths (the longest paths get evaluated first) + * regex in paths (and `regex_priority`) + * capturing groups? + * note: escaping characters/percent encoding + + +### Routing priority + +If multiple Routes match an incoming request, the {{site.base_gateway}} router then orders all defined Routes by their priority and uses the highest priority matching Route to handle a request. + The routing method you should use depends on your {{site.base_gateway}} version: | Recommended {{site.base_gateway}} version | Routing method | Description | @@ -109,7 +130,7 @@ The routing method you should use depends on your {{site.base_gateway}} version: | 2.9.x or earlier | Traditional compatibility | Only recommended for anyone running {{site.base_gateway}} 2.9.x or earlier. The original routing method for {{site.base_gateway}}. | | 3.0.x or later | [Expressions router](/gateway/routing/expressions/) | The recommended method for anyone running {{site.base_gateway}} 3.0.x or later. Can be run in both `traditional_compat` and `expressions` modes. | -### Traditional compatibility mode +#### Traditional compatibility mode In `traditional_compat` mode, the priority of a Route is determined as follows, by the order of descending significance: @@ -125,7 +146,7 @@ follows, by the order of descending significance: 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](/). -### Expressions router mode +#### Expressions router mode 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. From e9b3935a242ef851bb13665ea1e627be7463a5dd Mon Sep 17 00:00:00 2001 From: Diana <75819066+cloudjumpercat@users.noreply.github.com> Date: Thu, 12 Dec 2024 08:49:08 -0600 Subject: [PATCH 07/34] Apply suggestions from code review Co-authored-by: lena-larionova <54370747+lena-larionova@users.noreply.github.com> --- app/_gateway_entities/route.md | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/app/_gateway_entities/route.md b/app/_gateway_entities/route.md index 3f63f1d75..53ed792b7 100644 --- a/app/_gateway_entities/route.md +++ b/app/_gateway_entities/route.md @@ -46,7 +46,7 @@ When you configure Routes, you can also specify the following: ## 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. +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. The following diagram shows how Routes interact with other {{site.base_gateway}} entities: @@ -74,9 +74,15 @@ flowchart LR {% endmermaid %} -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 it, the internal application is limited as well. Routes can solve this problem. +Routes also allow the same Service to be used by multiple applications and apply different policies based on the Route used. -In the example above, two Routes can be created, say `/external` and `/internal`, and both of them can point to `example_service`. You can configure a policy to limit how often the `/external` Route is used and it 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're rate limited. But when the internal client accesses the Service using {{site.base_gateway}} using `/internal`, the internal client isn't limited. +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`, they're rate limited. +But when the internal application accesses the Service using {{site.base_gateway}} using `/internal`, the internal application isn't limited. ## How routing works From 5a74da6a15e577aae790edacb23c4e840b3cc246 Mon Sep 17 00:00:00 2001 From: Diana <75819066+cloudjumpercat@users.noreply.github.com> Date: Thu, 12 Dec 2024 15:56:33 -0600 Subject: [PATCH 08/34] Edit routes, upstream, add proxy page, update source file with doc links Signed-off-by: Diana <75819066+cloudjumpercat@users.noreply.github.com> --- app/_gateway_entities/route.md | 134 +++++++++-- app/_gateway_entities/upstream.md | 57 ++++- app/gateway/traffic-control/proxy.md | 237 ++++++++++++++++++++ tools/track-docs-changes/config/sources.yml | 18 +- 4 files changed, 426 insertions(+), 20 deletions(-) create mode 100644 app/gateway/traffic-control/proxy.md diff --git a/app/_gateway_entities/route.md b/app/_gateway_entities/route.md index 53ed792b7..f9cf7a805 100644 --- a/app/_gateway_entities/route.md +++ b/app/_gateway_entities/route.md @@ -15,6 +15,8 @@ related_resources: url: /gateway/routing/expressions/ - text: Upstreams url: /gateway/entities/upstream/ + - text: Proxying with {{site.base_gateway}} + url: /gateway/traffic-control/proxy/ tools: - admin-api @@ -37,7 +39,7 @@ Routes can also define rules that match requests to associated Services. Because When you configure Routes, you can also specify the following: -* **Protocols:** The protocol used to communicate with the [upstream application](/gateway/entities/upstream/). +* **Protocols:** The protocol used to communicate with the [upstream](/gateway/entities/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 @@ -112,23 +114,129 @@ For a request to match a Route: configured values (While the field configurations accepts one or more values, a request needs only one of the values to be considered a match) -#### things to cover in some way - -* Headers - * regular hosts (how an array is handled) - * wild card host - * explain preserve_host=true - * other headers (like `version`) -* Paths (the longest paths get evaluated first) - * regex in paths (and `regex_priority`) - * capturing groups? - * note: escaping characters/percent encoding - +#### Request header + +**Supported protocols:** `http`and `grpc` + +Routing a request based on its Host header is the most straightforward way to proxy traffic through Kong Gateway, especially since this is the intended usage of the HTTP Host header. `hosts` accepts multiple values, which must be comma-separated when specifying them via the Admin API, and is represented in a JSON payload. You can also use wildcards in hostnames. Wildcard hostnames must contain only one asterisk at the leftmost or rightmost label of the domain. + +When proxying, Kong Gateway’s default behavior is to set the upstream request’s Host header to the hostname specified in the service’s `host`. The `preserve_host` field accepts a boolean flag instructing Kong Gateway not to do so. + +| Example config | Example routing request matches | +|---------------|--------------------------------| +| `{"hosts":["example.com", "foo-service.com"]}` | `Host: example.com` and `Host: foo-service.com` | +| `headers.region=north` | `Region: North` | +| `"hosts": ["*.example.com", "example.*"]` | `Host: an.example.com` and `Host: example.org` | +| `"hosts": ["service.com"], "preserve_host": true,` | `Host: service.com` | +| `"headers": { "version": ["v1", "v2"] }` | `version: v1` | + +#### Request path + +**Supported protocols:** `http` and `grpc` + +Another way for a route to be matched is via request paths. To satisfy this routing condition, a client request’s normalized path must be prefixed with one of the values of the `paths` attribute. + +Kong Gateway detects that the request's normalized URL path is prefixed with one of the routes’ `paths` values. By default, Kong Gateway would then proxy the request upstream without changing the URL path. + +When proxying with path prefixes, the longest paths get evaluated first. This allow you to define two routes with two paths: `/service` and `/service/resource`, and ensure that the former does not “shadow” the latter. + +* **Regex in paths:** For a path to be considered a regular expression, it must be prefixed with a `~`. For example: `paths: ["~/foo/bar$"]`. +* **Evaluation order:** The router evaluates routes using the `regex_priority` field of the Route where a route is configured. Higher `regex_priority` values mean higher priority. If you have the following paths configured: + ```sh + [ + { + "paths": ["~/status/\d+"], + "regex_priority": 0 + }, + { + "paths": ["~/version/\d+/status/\d+"], + "regex_priority": 6 + }, + { + "paths": /version, + }, + { + "paths": ["~/version/any/"], + } + ] + ``` + They are evaluated in the following order: + 1. `/version/\d+/status/\d+` + 1. `/status/\d+` + 1. `/version/any/` + 1. `/version` +* **Capturing groups:** Capturing groups 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). +* **`strip_path` property:** If you want to specify a path prefix to match a route, but not include it in the upstream request, you can set the `strip_path` boolean property to `true`. +* **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. Specifically, the following normalization techniques are +used for incoming request URIs, which are selected because they generally do not change +semantics of the request URI: + 1. Percent-encoded triplets are converted to uppercase. For example: `/foo%3a` becomes `/foo%3A`. + 2. Percent-encoded triplets of unreserved characters are decoded. For example: `/fo%6F` becomes `/foo`. + 3. Dot segments are removed as necessary. For example: `/foo/./bar/../baz` becomes `/foo/baz`. + 4. Duplicate slashes are merged. For example: `/foo//bar` becomes `/foo/bar`. + + 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. + +Routers with a large number of regexes can consume traffic intended for other rules. Regular expressions are much more expensive to build and execute and can’t be optimized easily. You can avoid creating complex regular expressions using the [Router Expressions language](/gateway/routing/expressions/). + +| Example config | Example routing request matches | +|---------------|--------------------------------| +| `"paths": ["/service", "/hello/world"]` | `GET /service HTTP/1.1 +Host: example.com`, `GET /service/resource?param=value HTTP/1.1 +Host: example.com`, and `GET /hello/world/resource HTTP/1.1 +Host: anything.com` | +| `paths: ["~/foo/bar$"]` | ? | +| `/version/(?\d+)/users/(?\S+)` | `/version/1/users/john` | + +#### Request HTTP method + +**Supported protocols:** `http` + +The `methods` field allows matching the requests depending on their HTTP method. It accepts multiple values. Its default value is empty (the HTTP method is not used for routing). + +#### Request source + +**Supported protocols:** `tcp` and `tls` routes + +The `sources` routing attribute allows matching a route by a list of incoming connection IP and/or port sources. + +#### Request destination + +**Supported protocols:** `tcp` and `tls` routes + +The `destinations` attribute, similarly to `sources`, allows matching a route by a list of incoming connection IP and/or port, but uses the destination of the TCP/TLS connection as routing attribute. + +#### Request SNI + +**Supported protocols:** `https`, `grpcs`, or `tls` + +You can use a [Server Name Indication (SNI)](https://en.wikipedia.org/wiki/Server_Name_Indication) as a routing attribute. + +Incoming requests with a matching hostname set in the TLS connection’s SNI extension would be routed to this route. As mentioned, SNI routing applies not only to TLS, but also to other protocols carried over TLS - such as HTTPS and If multiple SNIs are specified in the route, any of them can match with the incoming request’s SNI. with the incoming request (OR relationship between the names). + +The SNI is indicated at TLS handshake time and cannot be modified after the TLS connection has been established. This means, for example, that multiple requests reusing the same keepalive connection will have the same SNI hostname while performing router match, regardless of the `host` header. has been established. This means keepalive connections that send multiple requests will have the same SNI hostnames while performing router match (regardless of the `host` header). + +Please note that creating a route with mismatched SNI and `host` header matcher is possible, but generally discouraged. + ### Routing priority If multiple Routes match an incoming request, the {{site.base_gateway}} router then orders all defined Routes by their priority and uses the highest priority matching Route to handle a request. +If the rule count for the given request is the same in two routes `A` and +`B`, then the following tiebreaker rules will be 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" paths and `B` has only "plain" paths. +* `A`'s longest path is longer than `B`'s longest path. +* `A.created_at < B.created_at` + The routing method you should use depends on your {{site.base_gateway}} version: | Recommended {{site.base_gateway}} version | Routing method | Description | diff --git a/app/_gateway_entities/upstream.md b/app/_gateway_entities/upstream.md index 1967e6659..7c575260f 100644 --- a/app/_gateway_entities/upstream.md +++ b/app/_gateway_entities/upstream.md @@ -1,9 +1,12 @@ --- -title: Upstreams +title: Upstreams content_type: reference entities: - upstream +products: + - gateway + tools: - admin-api - kic @@ -15,16 +18,58 @@ description: An upstream refers to the service applications sitting behind {{sit schema: api: gateway/admin-ee path: /schemas/Upstream - --- -## What is an upstream? +## What is an Upstream? + +{{page.description}} In {{site.base_gateway}}, an Upstream represents a virtual hostname and can be used to health check, circuit break, and load balance incoming requests over multiple [Gateway Services](/gateway/entities/service/). + +## Upstream and Service interaction + +You can configure a Service to point to an Upstream instead of a host. +For example, if you have a Service called `example_service` and an Upstream called `example_upstream`, you can point `example_service` to `example_upstream` instead of specifying a host. +The `example_upstream` Upstream can then point to two different targets: `httpbin.konghq.com` and `httpbun.com`. +In a real environment, the Upstream points to the same Service running on multiple systems. + +This setup allows you to [load balance](/gateway/{{ page.release }}/how-kong-works/load-balancing) between upstream targets. +For example, if an application is deployed across two different servers or upstream targets, {{site.base_gateway}} needs to load balance across both servers. +This is so that if one of the servers (like `httpbin.konghq.com` in the previous example) is unavailable, it automatically detects the problem and routes all traffic to the working server (`httpbun.com`). + +The following diagram shows how Upstreams interact with other {{site.base_gateway}} entities: + +{% mermaid %} +flowchart LR + A(API client) + B("`Route + (/mock)`") + C("`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 %} -{{page.description}} In {{site.base_gateway}}, an upstream represents a virtual hostname and can be used to health check, circuit break, and load balance incoming requests over multiple [target](/gateway/entities/target/) backend services. +## Use cases for Upstreams -## Use cases for upstreams +The following are examples of common use cases for Upstreams: -The following are examples of common use cases for upstreams: +| You want to... | Then use... | +|----------------|-------------| +| health check | | +| circuit break | | +| load balance | | ## Schema diff --git a/app/gateway/traffic-control/proxy.md b/app/gateway/traffic-control/proxy.md new file mode 100644 index 000000000..2c548da4d --- /dev/null +++ b/app/gateway/traffic-control/proxy.md @@ -0,0 +1,237 @@ +--- +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/ + - /gateway/traffic-control/ +--- + +{{ page.description }} This doc explains how {{site.base_gateway}}'s proxying capabilities works in detail. + + + +{{site.base_gateway}} exposes several interfaces which can be tweaked by the following configuration properties: + +- `proxy_listen`: Defines a list of addresses/ports on which {{site.base_gateway}} will + accept **public HTTP (gRPC, WebSocket, etc) traffic** from clients and proxy + it to your upstream services (`8000` by default). +- `admin_listen`, which also defines a list of addresses and ports, but those + should be restricted to only be accessed by administrators, as they expose + Kong's configuration capabilities: the **Admin API** (`8001` by default). + {:.important} + > **Important**: If you need to expose the `admin_listen` port to the internet in a production environment, + > {% if_version lte:2.8.x %}[secure it with authentication](/gateway/{{include.release}}/admin-api/secure-admin-api/).{% endif_version %}{% if_version gte:3.0.x %}[secure it with authentication](/gateway/{{include.release}}/production/running-kong/secure-admin-api/).{% endif_version %} +- `stream_listen`, which is similar to `proxy_listen` but for Layer 4 (TCP, TLS) + generic proxy. This is turned off by default. + +## Overview + +From a high-level perspective, {{site.base_gateway}} listens for HTTP traffic on its configured +proxy port(s) (`8000` and `8443` by default) and L4 traffic on explicitly configured +`stream_listen` ports. {{site.base_gateway}} will evaluate any incoming +HTTP request or L4 connection against the routes you have configured and try to find a matching +one. If a given request matches the rules of a specific route, {{site.base_gateway}} will +process proxying the request. + +Because each route may be linked to a service, {{site.base_gateway}} will run the plugins you +have configured on your route and its associated service, and then proxy the +request upstream. You can manage routes via {{site.base_gateway}}'s Admin API. Routes have +special attributes that are used for routing, matching incoming HTTP requests. +Routing attributes differ by subsystem (HTTP/HTTPS, gRPC/gRPCS, and TCP/TLS). + +Subsystems and routing attributes: +- `http`: `methods`, `hosts`, `headers`, `paths` (and `snis`, if `https`) +- `tcp`: `sources`, `destinations` (and `snis`, if `tls`) +- `grpc`: `hosts`, `headers`, `paths` (and `snis`, if `grpcs`) + +If you attempt to configure a route with a routing attribute it doesn't support +(e.g., an `http` route with `sources` or `destinations` fields), an error message +is reported: + +``` +HTTP/1.1 400 Bad Request +Content-Type: application/json +Server: kong/ + +{ + "code": 2, + "fields": { + "sources": "cannot set 'sources' when 'protocols' is 'http' or 'https'" + }, + "message": "schema violation (sources: cannot set 'sources' when 'protocols' is 'http' or 'https')", + "name": "schema violation" +} +``` + +If {{site.base_gateway}} receives a request that it cannot match against any of the configured +routes (or if no routes are configured), it will respond with: + +```http +HTTP/1.1 404 Not Found +Content-Type: application/json +Server: kong/ + +{ + "message": "no route and no Service found with those values" +} +``` + +### Load balancing + +{{site.base_gateway}} implements load balancing capabilities to distribute proxied +requests across a pool of instances of an upstream service. + +You can find more information about configuring load balancing by consulting +the [Load Balancing Reference][load-balancing-reference]. + +### Plugins execution + +{{site.base_gateway}} is extensible via "plugins" that hook themselves in the request/response +lifecycle of the proxied requests. Plugins can perform a variety of operations +in your environment and/or transformations on the proxied request. + +Plugins can be configured to run globally (for all proxied traffic) or on +specific routes and services. In both cases, you must create a [plugin +configuration][plugin-configuration-object] via the Admin API. + +Once a route has been matched (and its associated service entity), {{site.base_gateway}} will +run plugins associated to either of those entities. Plugins configured on a +route run before plugins configured on a service, but otherwise, the usual +rules of [plugins association][plugin-association-rules] apply. + +These configured plugins will run their `access` phase, which you can find more +information about in the [Plugin development guide][plugin-development-guide]. + +### Proxying and upstream timeouts + +Once {{site.base_gateway}} has executed all the necessary logic (including plugins), it is ready +to forward the request to your upstream service. This is done via Nginx's +[`ngx_http_proxy_module`][ngx-http-proxy-module]. You can configure the desired +timeouts for the connection between {{site.base_gateway}} and a given upstream, via the following +properties of a service: + +- `connect_timeout`: defines in milliseconds the timeout for + establishing a connection to your upstream service. Defaults to `60000`. +- `write_timeout`: defines in milliseconds a timeout between two + successive write operations for transmitting a request to your upstream + service. Defaults to `60000`. +- `read_timeout`: defines in milliseconds a timeout between two + successive read operations for receiving a request from your upstream + service. Defaults to `60000`. + +{{site.base_gateway}} will send the request over HTTP/1.1, and set the following headers: + + +- `Host: `, as previously described in this document. +- `Connection: keep-alive`, to allow for reusing the upstream connections. +- `X-Real-IP: `, where `$remote_addr` is the variable bearing + the same name provided by + [ngx_http_core_module][ngx-remote-addr-variable]. Please note that the + `$remote_addr` is likely overridden by + [ngx_http_realip_module][ngx-http-realip-module]. +- `X-Forwarded-For:
`, where `
` is the content of + `$realip_remote_addr` provided by + [ngx_http_realip_module][ngx-http-realip-module] appended to the request + header with the same name. +- `X-Forwarded-Proto: `, where `` is the protocol used by + the client. In the case where `$realip_remote_addr` is one of the **trusted** + addresses, the request header with the same name gets forwarded if provided. + Otherwise, the value of the `$scheme` variable provided by + [ngx_http_core_module][ngx-scheme-variable] will be used. +- `X-Forwarded-Host: `, where `` is the host name sent by + the client. In the case where `$realip_remote_addr` is one of the **trusted** + addresses, the request header with the same name gets forwarded if provided. + Otherwise, the value of the `$host` variable provided by + [ngx_http_core_module][ngx-host-variable] will be used. +- `X-Forwarded-Port: `, where `` is the port of the server which + accepted a request. In the case where `$realip_remote_addr` is one of the + **trusted** addresses, the request header with the same name gets forwarded + if provided. Otherwise, the value of the `$server_port` variable provided by + [ngx_http_core_module][ngx-server-port-variable] will be used. +- `X-Forwarded-Prefix: `, where `` is the path of the request which + was accepted by {{site.base_gateway}}. In the case where `$realip_remote_addr` is one of the + **trusted** addresses, the request header with the same name gets forwarded + if provided. Otherwise, the value of the `$request_uri` variable (with + the query string stripped) provided by [ngx_http_core_module][ngx-server-port-variable] + will be used. + + + {:.note} + > **Note**: {{site.base_gateway}} returns `"/"` for an empty path, but it doesn't do any other + > normalization on the request path. + +All the other request headers are forwarded as-is by {{site.base_gateway}}. + +One exception to this is made when using the WebSocket protocol. If so, {{site.base_gateway}} +sets the following headers to allow for upgrading the protocol between the +client and your upstream services: + +- `Connection: Upgrade` +- `Upgrade: websocket` + +More information on this topic is covered in the +[Proxy WebSocket traffic][proxy-websocket] section. + +### Errors and retries + +Whenever an error occurs during proxying, {{site.base_gateway}} uses the underlying +Nginx [retries][ngx-http-proxy-retries] mechanism to pass the request on to +the next upstream. + +There are two configurable elements here: + +1. The number of retries: this can be configured per service using the + `retries` property. See the [Admin API][API] for more details on this. + +2. What exactly constitutes an error: here {{site.base_gateway}} uses the Nginx defaults, which + means an error or timeout occurring while establishing a connection with the + server, passing a request to it, or reading the response headers. + +The second option is based on Nginx's +[`proxy_next_upstream`](https://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_next_upstream) directive. This option is not +directly configurable through {{site.base_gateway}}, but can be added using a custom Nginx +configuration. See the [configuration reference][configuration-reference] for +more details. + +### Response + +{{site.base_gateway}} receives the response from the upstream service and sends it back to the +downstream client in a streaming fashion. At this point, {{site.base_gateway}} executes +subsequent plugins added to the route and/or service that implement a hook in +the `header_filter` phase. + +Once the `header_filter` phase of all registered plugins has been executed, the +following headers are added by {{site.base_gateway}} and the full set of headers be sent to +the client: + +- `Via: kong/x.x.x`, where `x.x.x` is the {{site.base_gateway}} version in use +- `X-Kong-Proxy-Latency: `, where `latency` is the time in milliseconds + between {{site.base_gateway}} receiving the request from the client and sending the request to + your upstream service. +- `X-Kong-Upstream-Latency: `, where `latency` is the time in + milliseconds that {{site.base_gateway}} was waiting for the first byte of the upstream service + response. + +Once the headers are sent to the client, {{site.base_gateway}} starts executing +registered plugins for the route and/or service that implement the +`body_filter` hook. This hook may be called multiple times, due to the +streaming nature of Nginx. Each chunk of the upstream response that is +successfully processed by such `body_filter` hooks is sent back to the client. +You can find more information about the `body_filter` hook in the [Plugin +development guide][plugin-development-guide]. \ 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 6687ea0da..442384d0b 100644 --- a/tools/track-docs-changes/config/sources.yml +++ b/tools/track-docs-changes/config/sources.yml @@ -34,4 +34,20 @@ app/_api/konnect/portal-management/_index.md: app/_api/konnect/runtime-groups/_index.md: - app/_api/konnect/runtime-groups/_index.md app/_api/konnect/ksearch/_index.md: - - app/_api/konnect/search/_index.md \ No newline at end of file + - app/_api/konnect/search/_index.md + +# how tos +app/_how-tos/dynamically-rewrite-simple-request-urls-with-routes.md: + - app/_src/gateway/key-concepts/routes/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 + +# entities +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 From 89adbb644ac382c1084ecdb4dd447f892a70bf6a Mon Sep 17 00:00:00 2001 From: Diana <75819066+cloudjumpercat@users.noreply.github.com> Date: Fri, 13 Dec 2024 11:11:18 -0600 Subject: [PATCH 09/34] Fix broken breadcrumb link Signed-off-by: Diana <75819066+cloudjumpercat@users.noreply.github.com> --- app/gateway/traffic-control/proxy.md | 1 - 1 file changed, 1 deletion(-) diff --git a/app/gateway/traffic-control/proxy.md b/app/gateway/traffic-control/proxy.md index 2c548da4d..31257c04b 100644 --- a/app/gateway/traffic-control/proxy.md +++ b/app/gateway/traffic-control/proxy.md @@ -19,7 +19,6 @@ related_resources: breadcrumbs: - /gateway/ - - /gateway/traffic-control/ --- {{ page.description }} This doc explains how {{site.base_gateway}}'s proxying capabilities works in detail. From 45b8d049f96e0ba0436275569b6ceef78b180ad8 Mon Sep 17 00:00:00 2001 From: Diana <75819066+cloudjumpercat@users.noreply.github.com> Date: Fri, 13 Dec 2024 16:02:13 -0600 Subject: [PATCH 10/34] Revise a whole bunch of pages Signed-off-by: Diana <75819066+cloudjumpercat@users.noreply.github.com> --- app/_gateway_entities/route.md | 27 +++-------- app/_gateway_entities/target.md | 51 +++++++++++++++++++-- app/_gateway_entities/upstream.md | 33 +++++++++---- app/gateway/traffic-control/proxy.md | 14 +++++- tools/track-docs-changes/config/sources.yml | 5 ++ 5 files changed, 97 insertions(+), 33 deletions(-) diff --git a/app/_gateway_entities/route.md b/app/_gateway_entities/route.md index f9cf7a805..79ce92b4f 100644 --- a/app/_gateway_entities/route.md +++ b/app/_gateway_entities/route.md @@ -13,7 +13,7 @@ related_resources: url: /gateway/routing/ - text: Expressions router url: /gateway/routing/expressions/ - - text: Upstreams + - text: Upstreams entity url: /gateway/entities/upstream/ - text: Proxying with {{site.base_gateway}} url: /gateway/traffic-control/proxy/ @@ -46,6 +46,8 @@ When you configure Routes, you can also specify the following: * **Redirect status codes:** HTTPS status codes * **Tags:** Optional set of strings to group Routes with +Use Routes if you don't need to load balance traffic to hosts. If you need to do load balancing between hostnames, configure your hosts in an [Upstream](/gateway/entities/upstream/) instead. + ## 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. @@ -88,7 +90,10 @@ But when the internal application accesses the Service using {{site.base_gateway ## 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. {{site.base_gateway}} first finds Routes that match by comparing the defined routing attributes with the attributes in the request. 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. +For each incoming request, {{site.base_gateway}} must determine which service gets to handle it based on the Routes that are defined. {{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 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}} @@ -191,24 +196,6 @@ Host: anything.com` | | `paths: ["~/foo/bar$"]` | ? | | `/version/(?\d+)/users/(?\S+)` | `/version/1/users/john` | -#### Request HTTP method - -**Supported protocols:** `http` - -The `methods` field allows matching the requests depending on their HTTP method. It accepts multiple values. Its default value is empty (the HTTP method is not used for routing). - -#### Request source - -**Supported protocols:** `tcp` and `tls` routes - -The `sources` routing attribute allows matching a route by a list of incoming connection IP and/or port sources. - -#### Request destination - -**Supported protocols:** `tcp` and `tls` routes - -The `destinations` attribute, similarly to `sources`, allows matching a route by a list of incoming connection IP and/or port, but uses the destination of the TCP/TLS connection as routing attribute. - #### Request SNI **Supported protocols:** `https`, `grpcs`, or `tls` diff --git a/app/_gateway_entities/target.md b/app/_gateway_entities/target.md index d6805be19..6c4321b97 100644 --- a/app/_gateway_entities/target.md +++ b/app/_gateway_entities/target.md @@ -11,7 +11,15 @@ tools: - deck - terraform -description: A target identifies a specific instance of an upstream service. +description: A target is an IP address/hostname with a port that identifies an instance of a backend service. + +related_resources: + - text: Upstreams entity + url: /gateway/entities/upstream/ + - text: Routing in {{site.base_gateway}} + url: /gateway/routing/ + - text: Proxying with {{site.base_gateway}} + url: /gateway/traffic-control/proxy/ schema: api: gateway/admin-ee @@ -21,12 +29,47 @@ schema: ## What is a target? -{{page.description}} +{{page.description}} Each [Upstream](/gateway/entities/upstream/) can have many Targets. Targets are used by Upstreams for [load balancing]. For example, if you have an `example_upstream` upstream, you can point it to two different Targets: `httpbin.konghq.com` and `httpbun.com`. This is so that if one of the servers (like `httpbin.konghq.com`) is unavailable, it automatically detects the problem and routes all traffic to the working server (`httpbun.com`). + +The following diagram illustrates how Targets are used by Upstreams for load balancing: + + + +{% mermaid %} +flowchart LR + A("`Route + (/mock)`") + B("`Service + (example_service)`") + C(Load balancer) + D(httpbin.konghq.com) + E(httpbun.com) + + subgraph id1 ["`**KONG GATEWAY**`"] + A --> B --> C + end -## Use cases for targets + subgraph id2 ["`Targets (example_upstream)`"] + C --> D & E + end -The following are examples of common use cases for targets: + style id1 rx:10,ry:10 + style id2 stroke:none +{% endmermaid %} + + ## Schema {% entity_schema %} + +## Set up a Target + +{% entity_example %} +type: target +data: + upstream: + description: example_upstream + id: 173a6cee-90d1-40a7-89cf-0329eca780a6 + weight: 100 +{% endentity_example %} diff --git a/app/_gateway_entities/upstream.md b/app/_gateway_entities/upstream.md index 7c575260f..c7627294a 100644 --- a/app/_gateway_entities/upstream.md +++ b/app/_gateway_entities/upstream.md @@ -15,6 +15,22 @@ tools: description: An upstream refers to the service applications sitting behind {{site.base_gateway}}, to which client requests are forwarded. +related_resources: + - text: Gateway Services entity + url: /gateway/entities/service/ + - text: Routes entity + url: /gateway/entities/route/ + - text: Targets entity + url: /gateway/entities/target/ + - text: Routing in {{site.base_gateway}} + url: /gateway/routing/ + - text: Expressions router + url: /gateway/routing/expressions/ + - text: Upstreams + url: /gateway/entities/upstream/ + - text: Proxying with {{site.base_gateway}} + url: /gateway/traffic-control/proxy/ + schema: api: gateway/admin-ee path: /schemas/Upstream @@ -22,16 +38,18 @@ schema: ## What is an Upstream? -{{page.description}} In {{site.base_gateway}}, an Upstream represents a virtual hostname and can be used to health check, circuit break, and load balance incoming requests over multiple [Gateway Services](/gateway/entities/service/). +{{page.description}} In {{site.base_gateway}}, an Upstream represents a virtual hostname and can be used to [health check, circuit break], and [load balance] incoming requests over multiple [Gateway Services](/gateway/entities/service/). In addition, the upstream entity has more advanced functionality algorithms like least-connections, consistent-hashing, and lowest-latency. + +If you don't need to load balance hostnames, we recommend using the `host` header on a [Route](/gateway/entities/route/) as the preferred method for routing a request and proxying traffic. ## Upstream and Service interaction You can configure a Service to point to an Upstream instead of a host. For example, if you have a Service called `example_service` and an Upstream called `example_upstream`, you can point `example_service` to `example_upstream` instead of specifying a host. -The `example_upstream` Upstream can then point to two different targets: `httpbin.konghq.com` and `httpbun.com`. +The `example_upstream` Upstream can then point to two different [targets](/gateway/entities/target/): `httpbin.konghq.com` and `httpbun.com`. In a real environment, the Upstream points to the same Service running on multiple systems. -This setup allows you to [load balance](/gateway/{{ page.release }}/how-kong-works/load-balancing) between upstream targets. +This setup allows you to [load balance] between upstream targets. For example, if an application is deployed across two different servers or upstream targets, {{site.base_gateway}} needs to load balance across both servers. This is so that if one of the servers (like `httpbin.konghq.com` in the previous example) is unavailable, it automatically detects the problem and routes all traffic to the working server (`httpbun.com`). @@ -65,11 +83,10 @@ flowchart LR The following are examples of common use cases for Upstreams: -| You want to... | Then use... | -|----------------|-------------| -| health check | | -| circuit break | | -| load balance | | +* **Load balance:** When an Upstream points to multiple upstream targets, you can configure the Upstream entity to load balance traffic between the targets. +* **Health check:** Configure Upstreams to dynamically mark a target as healthy or unhealthy. This is an active check where a specific HTTP or HTTPS endpoint in the target is periodically requested and the health of the target is determined based on its response. +* **Circuit break:** Configure Upstreams to allow {{site.base_gateway}} to passively analyze the ongoing traffic being proxied and determine the health of targets based on their behavior responding to requests. + **Note:** This feature is not supported in hybrid mode. ## Schema diff --git a/app/gateway/traffic-control/proxy.md b/app/gateway/traffic-control/proxy.md index 31257c04b..d9429c7ae 100644 --- a/app/gateway/traffic-control/proxy.md +++ b/app/gateway/traffic-control/proxy.md @@ -21,7 +21,19 @@ breadcrumbs: - /gateway/ --- -{{ page.description }} This doc explains how {{site.base_gateway}}'s proxying capabilities works in detail. +{{ page.description }} This doc details information about how {{site.base_gateway}} handles proxying. For more indepth details about how {{site.base_gateway}} handles routing, see the [Routes entity](/gateway/entities/route/). + +{{site.base_gateway}} handles proxying in the following order: + +1. {{site.base_gateway}} listens for HTTP traffic on its configured +proxy port(s) (`8000` and `8443` by default) and L4 traffic on explicitly configured +`stream_listen` ports. +1. {{site.base_gateway}} will evaluate any incoming HTTP request or L4 connection against the Routes you have configured and try to find a matching one. +1. 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. +1. Because each route may be linked to a service, {{site.base_gateway}} will run the plugins you have configured on your route and its associated service, and then proxy the request upstream. +1. If a given request matches the rules of a specific route, {{site.base_gateway}} will +process proxying the request. When {{site.base_gateway}} proxies a request, the following happens: + 1. diff --git a/tools/track-docs-changes/config/sources.yml b/tools/track-docs-changes/config/sources.yml index 3d917ad37..b12d44929 100644 --- a/tools/track-docs-changes/config/sources.yml +++ b/tools/track-docs-changes/config/sources.yml @@ -46,8 +46,13 @@ 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 From 5cf9492eedfb927469daf813c9f5e659ef471999 Mon Sep 17 00:00:00 2001 From: Diana <75819066+cloudjumpercat@users.noreply.github.com> Date: Mon, 16 Dec 2024 14:28:58 -0600 Subject: [PATCH 11/34] Revise proxy reference and routing Signed-off-by: Diana <75819066+cloudjumpercat@users.noreply.github.com> --- app/_gateway_entities/route.md | 55 ++--- app/_includes/content/how-routing-works.md | 9 + app/gateway/routing/expressions.md | 1 - app/gateway/routing/index.md | 117 ----------- app/gateway/traffic-control/proxy.md | 227 ++++++++------------- 5 files changed, 116 insertions(+), 293 deletions(-) create mode 100644 app/_includes/content/how-routing-works.md delete mode 100644 app/gateway/routing/index.md diff --git a/app/_gateway_entities/route.md b/app/_gateway_entities/route.md index 79ce92b4f..7f40d7fe6 100644 --- a/app/_gateway_entities/route.md +++ b/app/_gateway_entities/route.md @@ -9,8 +9,6 @@ description: A Route is a path to a resource within an upstream application. related_resources: - text: Gateway Services url: /gateway/entities/service/ - - text: Routing in {{site.base_gateway}} - url: /gateway/routing/ - text: Expressions router url: /gateway/routing/expressions/ - text: Upstreams entity @@ -39,7 +37,7 @@ Routes can also define rules that match requests to associated Services. Because When you configure Routes, you can also specify the following: -* **Protocols:** The protocol used to communicate with the [upstream](/gateway/entities/upstream/) application. +* **Protocols:** The protocol used to communicate with the [Upstream](/gateway/entities/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 @@ -90,15 +88,7 @@ But when the internal application accesses the Service using {{site.base_gateway ## 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. {{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 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 two or more Routes are configured with fields containing the same values, {{site.base_gateway}} applies a priority rule. {{site.base_gateway}} first tries to match the routes with the most rules. +{% include_cached /content/how-routing-works.md %} ### Matching routing attributes @@ -119,13 +109,15 @@ For a request to match a Route: configured values (While the field configurations accepts one or more values, a request needs only one of the values to be considered a match) +The following sections describe specifics about the headers, paths, and SNI attributes you can configure. For information about additional attributes you can configure for Route matching, see the [Routes schema](/gateway/entities/route/#schema). + #### Request header **Supported protocols:** `http`and `grpc` Routing a request based on its Host header is the most straightforward way to proxy traffic through Kong Gateway, especially since this is the intended usage of the HTTP Host header. `hosts` accepts multiple values, which must be comma-separated when specifying them via the Admin API, and is represented in a JSON payload. You can also use wildcards in hostnames. Wildcard hostnames must contain only one asterisk at the leftmost or rightmost label of the domain. -When proxying, Kong Gateway’s default behavior is to set the upstream request’s Host header to the hostname specified in the service’s `host`. The `preserve_host` field accepts a boolean flag instructing Kong Gateway not to do so. +When proxying, Kong Gateway’s default behavior is to set the Upstream request’s Host header to the hostname specified in the Service’s `host`. The `preserve_host` field accepts a boolean flag instructing Kong Gateway not to do so. | Example config | Example routing request matches | |---------------|--------------------------------| @@ -139,14 +131,14 @@ When proxying, Kong Gateway’s default behavior is to set the upstream request **Supported protocols:** `http` and `grpc` -Another way for a route to be matched is via request paths. To satisfy this routing condition, a client request’s normalized path must be prefixed with one of the values of the `paths` attribute. +Another way for a Route to be matched is via request paths. To satisfy this routing condition, a client request’s normalized path must be prefixed with one of the values of the `paths` attribute. -Kong Gateway detects that the request's normalized URL path is prefixed with one of the routes’ `paths` values. By default, Kong Gateway would then proxy the request upstream without changing the URL path. +Kong Gateway detects that the request's normalized URL path is prefixed with one of the Routes’ `paths` values. By default, Kong Gateway would then proxy the request Upstream without changing the URL path. -When proxying with path prefixes, the longest paths get evaluated first. This allow you to define two routes with two paths: `/service` and `/service/resource`, and ensure that the former does not “shadow” the latter. +When proxying with path prefixes, the longest paths get evaluated first. This allow you to define two Routes with two paths: `/service` and `/service/resource`, and ensure that the former does not “shadow” the latter. * **Regex in paths:** For a path to be considered a regular expression, it must be prefixed with a `~`. For example: `paths: ["~/foo/bar$"]`. -* **Evaluation order:** The router evaluates routes using the `regex_priority` field of the Route where a route is configured. Higher `regex_priority` values mean higher priority. If you have the following paths configured: +* **Evaluation order:** The router evaluates Routes using the `regex_priority` field of the Route where a Route is configured. Higher `regex_priority` values mean higher priority. If you have the following paths configured: ```sh [ { @@ -171,9 +163,9 @@ When proxying with path prefixes, the longest paths get evaluated first. This al 1. `/version/any/` 1. `/version` * **Capturing groups:** Capturing groups 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). -* **`strip_path` property:** If you want to specify a path prefix to match a route, but not include it in the upstream request, you can set the `strip_path` boolean property to `true`. -* **Normalization behavior:** To prevent trivial route match bypass, the incoming request URI from client +* **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). +* **`strip_path` property:** If you want to specify a path prefix to match a Route, but not include it in the Upstream request, you can set the `strip_path` boolean property to `true`. +* **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. Specifically, the following normalization techniques are used for incoming request URIs, which are selected because they generally do not change @@ -183,17 +175,14 @@ semantics of the request URI: 3. Dot segments are removed as necessary. For example: `/foo/./bar/../baz` becomes `/foo/baz`. 4. Duplicate slashes are merged. For example: `/foo//bar` becomes `/foo/bar`. - 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. + 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. Routers with a large number of regexes can consume traffic intended for other rules. Regular expressions are much more expensive to build and execute and can’t be optimized easily. You can avoid creating complex regular expressions using the [Router Expressions language](/gateway/routing/expressions/). | Example config | Example routing request matches | |---------------|--------------------------------| -| `"paths": ["/service", "/hello/world"]` | `GET /service HTTP/1.1 -Host: example.com`, `GET /service/resource?param=value HTTP/1.1 -Host: example.com`, and `GET /hello/world/resource HTTP/1.1 -Host: anything.com` | -| `paths: ["~/foo/bar$"]` | ? | +| `"paths": ["/service", "/hello/world"]` | `GET /service HTTP/1.1 Host: example.com`, `GET /service/resource?param=value HTTP/1.1 Host: example.com`, and `GET /hello/world/resource HTTP/1.1 Host: anything.com` | +| `paths: ["~/foo/bar$"]` | `GET /foo/bar HTTP/1.1 Host: example.com` | | `/version/(?\d+)/users/(?\S+)` | `/version/1/users/john` | #### Request SNI @@ -202,18 +191,18 @@ Host: anything.com` | You can use a [Server Name Indication (SNI)](https://en.wikipedia.org/wiki/Server_Name_Indication) as a routing attribute. -Incoming requests with a matching hostname set in the TLS connection’s SNI extension would be routed to this route. As mentioned, SNI routing applies not only to TLS, but also to other protocols carried over TLS - such as HTTPS and If multiple SNIs are specified in the route, any of them can match with the incoming request’s SNI. with the incoming request (OR relationship between the names). +Incoming requests with a matching hostname set in the TLS connection’s SNI extension would be Routed to this Route. As mentioned, SNI routing applies not only to TLS, but also to other protocols carried over TLS, such as HTTPS. If multiple SNIs are specified in the Route, any of them can match with the incoming request’s SNI (or relationship between the names). -The SNI is indicated at TLS handshake time and cannot be modified after the TLS connection has been established. This means, for example, that multiple requests reusing the same keepalive connection will have the same SNI hostname while performing router match, regardless of the `host` header. has been established. This means keepalive connections that send multiple requests will have the same SNI hostnames while performing router match (regardless of the `host` header). +The SNI is indicated at TLS handshake time and can't be modified after the TLS connection has been established. This means keepalive connections that send multiple requests will have the same SNI hostnames while performing router match (regardless of the `host` header). -Please note that creating a route with mismatched SNI and `host` header matcher is possible, but generally discouraged. +Creating a Route with a mismatched SNI and `host` header matcher is possible, but generally discouraged. ### Routing priority If multiple Routes match an incoming request, the {{site.base_gateway}} router then orders all defined Routes by their priority and uses the highest priority matching Route to handle a request. -If the rule count for the given request is the same in two routes `A` and +If the rule count for the given request is the same in two Routes `A` and `B`, then the following tiebreaker rules will be applied in the order they are listed. Route `A` will be selected over `B` if: @@ -251,7 +240,7 @@ As soon as a Route yields a match, the router stops matching and {{site.base_gat 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. -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](/). +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/proxy/). ### Routing performance recommendations @@ -266,8 +255,8 @@ Use the following table to help you understand how Routes can be configured for | You want to... | Then use... | |--------|----------| -| Rate limit internal and external traffic to a service | [Enable a rate limiting plugin on routes attached to the service](/plugins/rate-limiting-advanced/) | -| Perform a simple URL rewrite, such as renaming your legacy `/api/old/` upstream endpoint to a publicly accessible API endpoint that is now named `/new/api`. | [Set up a Gateway Service with the old path and a Route with new path](/how-to/dynamically-rewrite-simple-request-urls-with-routes/) | +| Rate limit internal and external traffic to a Service | [Enable a rate limiting plugin on Routes attached to the Service](/plugins/rate-limiting-advanced/) | +| Perform a simple URL rewrite, such as renaming your legacy `/api/old/` Upstream endpoint to a publicly accessible API endpoint that is now named `/new/api`. | [Set up a Gateway Service with the old path and a Route with new path](/how-to/dynamically-rewrite-simple-request-urls-with-routes/) | | Perform a complex URL rewrite, such as replacing `/api//old` with `/new/api/`. | [Request Transformer Advanced plugin](https://docs.konghq.com/hub/kong-inc/request-transformer-advanced/) | | Describe Routes or paths as patterns using regular expressions. | [Expressions router](/gateway/routing/expressions/) | diff --git a/app/_includes/content/how-routing-works.md b/app/_includes/content/how-routing-works.md new file mode 100644 index 000000000..5d7d5f8cd --- /dev/null +++ b/app/_includes/content/how-routing-works.md @@ -0,0 +1,9 @@ +For each incoming request, {{site.base_gateway}} must determine which Service gets to handle it based on the Routes that are defined. {{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 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 two or more Routes are configured with fields containing the same values, {{site.base_gateway}} applies a priority rule. {{site.base_gateway}} first tries to match the Routes with the most rules. \ No newline at end of file diff --git a/app/gateway/routing/expressions.md b/app/gateway/routing/expressions.md index e6be42c30..2f9d407a1 100644 --- a/app/gateway/routing/expressions.md +++ b/app/gateway/routing/expressions.md @@ -19,7 +19,6 @@ related_resources: breadcrumbs: - /gateway/ - - /gateway/routing/ --- {{ page.description }} Expressions can be used to perform tasks such as defining 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/proxy.md b/app/gateway/traffic-control/proxy.md index d9429c7ae..a866ff6c6 100644 --- a/app/gateway/traffic-control/proxy.md +++ b/app/gateway/traffic-control/proxy.md @@ -21,7 +21,29 @@ breadcrumbs: - /gateway/ --- -{{ page.description }} This doc details information about how {{site.base_gateway}} handles proxying. For more indepth details about how {{site.base_gateway}} handles routing, see the [Routes entity](/gateway/entities/route/). +{{ page.description }} This page details information about how {{site.base_gateway}} handles proxying. The following diagram shows how proxying is handled by {{site.base_gateway}}: + +{% mermaid %} +sequenceDiagram + actor Client + participant Gateway as Kong Gateway + participant Router + participant Plugins as Plugins + participant LoadBalancer as Load balancer + participant UpstreamService as Upstream Service + + Client->>Gateway: Sends HTTP request or L4 connection + Gateway->>Router: Evaluates incoming request against Routes + Router->>Router: Orders Routes by priority + Router->>Gateway: Returns highest priority matching Route + Gateway->>Plugins: Executes plugins the `access` phase + Gateway->>LoadBalancer: Implements load balancing capabilities + LoadBalancer->>LoadBalancer: Distributes request across upstream service instances + LoadBalancer->>UpstreamService: Forwards request to selected instance + UpstreamService->>Gateway: Sends response + Gateway->>Plugins: Executes plugins in the `header_filter` phase + Gateway->>Client: Streams response back to client +{% endmermaid %} {{site.base_gateway}} handles proxying in the following order: @@ -30,12 +52,24 @@ proxy port(s) (`8000` and `8443` by default) and L4 traffic on explicitly config `stream_listen` ports. 1. {{site.base_gateway}} will evaluate any incoming HTTP request or L4 connection against the Routes you have configured and try to find a matching one. 1. 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. -1. Because each route may be linked to a service, {{site.base_gateway}} will run the plugins you have configured on your route and its associated service, and then proxy the request upstream. 1. If a given request matches the rules of a specific route, {{site.base_gateway}} will -process proxying the request. When {{site.base_gateway}} proxies a request, the following happens: - 1. +run any global, Route, or Service [plugins]() before it proxies the request. They are run in the following order: Route, Service These configured plugins will run their `access` phase, which you can find more +information about in the [Plugin development guide][plugin-development-guide]. +1. {{site.base_gateway}} implements [load balancing]() capabilities to distribute proxied +requests across a pool of instances of an upstream service. +1. Once {{site.base_gateway}} has executed all the necessary logic (including plugins), it is ready to forward the request to your upstream service. This is done via Nginx's [`ngx_http_proxy_module`][ngx-http-proxy-module]. +1. {{site.base_gateway}} receives the response from the upstream service and sends it back to the +downstream client in a streaming fashion. At this point, {{site.base_gateway}} executes +subsequent plugins added to the route and/or service that implement a hook in +the `header_filter` phase. - +## Listeners + +From a high-level perspective, {{site.base_gateway}} listens for HTTP traffic on its configured +proxy ports: `8000` and `8443` by default and L4 traffic on explicitly configured +`stream_listen` ports. {{site.base_gateway}} will evaluate any incoming +HTTP request or L4 connection against the routes you have configured and try to find a matching +one. {{site.base_gateway}} exposes several interfaces which can be tweaked by the following configuration properties: @@ -51,143 +85,56 @@ process proxying the request. When {{site.base_gateway}} proxies a request, the - `stream_listen`, which is similar to `proxy_listen` but for Layer 4 (TCP, TLS) generic proxy. This is turned off by default. -## Overview - -From a high-level perspective, {{site.base_gateway}} listens for HTTP traffic on its configured -proxy port(s) (`8000` and `8443` by default) and L4 traffic on explicitly configured -`stream_listen` ports. {{site.base_gateway}} will evaluate any incoming -HTTP request or L4 connection against the routes you have configured and try to find a matching -one. If a given request matches the rules of a specific route, {{site.base_gateway}} will -process proxying the request. - -Because each route may be linked to a service, {{site.base_gateway}} will run the plugins you -have configured on your route and its associated service, and then proxy the -request upstream. You can manage routes via {{site.base_gateway}}'s Admin API. Routes have -special attributes that are used for routing, matching incoming HTTP requests. -Routing attributes differ by subsystem (HTTP/HTTPS, gRPC/gRPCS, and TCP/TLS). - -Subsystems and routing attributes: -- `http`: `methods`, `hosts`, `headers`, `paths` (and `snis`, if `https`) -- `tcp`: `sources`, `destinations` (and `snis`, if `tls`) -- `grpc`: `hosts`, `headers`, `paths` (and `snis`, if `grpcs`) - -If you attempt to configure a route with a routing attribute it doesn't support -(e.g., an `http` route with `sources` or `destinations` fields), an error message -is reported: - -``` -HTTP/1.1 400 Bad Request -Content-Type: application/json -Server: kong/ - -{ - "code": 2, - "fields": { - "sources": "cannot set 'sources' when 'protocols' is 'http' or 'https'" - }, - "message": "schema violation (sources: cannot set 'sources' when 'protocols' is 'http' or 'https')", - "name": "schema violation" -} -``` - -If {{site.base_gateway}} receives a request that it cannot match against any of the configured -routes (or if no routes are configured), it will respond with: - -```http -HTTP/1.1 404 Not Found -Content-Type: application/json -Server: kong/ - -{ - "message": "no route and no Service found with those values" -} -``` - -### Load balancing - -{{site.base_gateway}} implements load balancing capabilities to distribute proxied -requests across a pool of instances of an upstream service. +Kong Gateway is a transparent proxy, and it defaults to forwarding the request to your upstream service untouched, with the exception of various headers such as `Connection`, `Date`, and others as required by the HTTP specifications. -You can find more information about configuring load balancing by consulting -the [Load Balancing Reference][load-balancing-reference]. +## Routing -### Plugins execution +{% include_cached /content/how-routing-works.md %} -{{site.base_gateway}} is extensible via "plugins" that hook themselves in the request/response -lifecycle of the proxied requests. Plugins can perform a variety of operations -in your environment and/or transformations on the proxied request. +For more details about how {{site.base_gateway}} handles routing, see the [Routes entity](/gateway/entities/route/). -Plugins can be configured to run globally (for all proxied traffic) or on -specific routes and services. In both cases, you must create a [plugin -configuration][plugin-configuration-object] via the Admin API. +## Load balancing -Once a route has been matched (and its associated service entity), {{site.base_gateway}} will -run plugins associated to either of those entities. Plugins configured on a -route run before plugins configured on a service, but otherwise, the usual -rules of [plugins association][plugin-association-rules] apply. +{{site.base_gateway}} implements load balancing capabilities to distribute proxied +requests across a pool of instances of an upstream service. -These configured plugins will run their `access` phase, which you can find more -information about in the [Plugin development guide][plugin-development-guide]. +You can find more information about load balancing in +the [Load Balancing Reference][]. -### Proxying and upstream timeouts +## Proxying Once {{site.base_gateway}} has executed all the necessary logic (including plugins), it is ready -to forward the request to your upstream service. This is done via Nginx's -[`ngx_http_proxy_module`][ngx-http-proxy-module]. You can configure the desired -timeouts for the connection between {{site.base_gateway}} and a given upstream, via the following -properties of a service: +to forward the request to your upstream service. This is done with Nginx's +[`ngx_http_proxy_module`](https://nginx.org/docs/http/ngx_http_proxy_module.html). + +### Upstream timeouts -- `connect_timeout`: defines in milliseconds the timeout for +You can configure the desired +timeouts for the connection between {{site.base_gateway}} and a given Upstream, using the following properties of a [Service](/gateway/entities/service/): + +- `connect_timeout`: Defines, in milliseconds, the timeout for establishing a connection to your upstream service. Defaults to `60000`. -- `write_timeout`: defines in milliseconds a timeout between two +- `write_timeout`: Defines, in milliseconds, a timeout between two successive write operations for transmitting a request to your upstream service. Defaults to `60000`. -- `read_timeout`: defines in milliseconds a timeout between two +- `read_timeout`: Defines, in milliseconds, a timeout between two successive read operations for receiving a request from your upstream service. Defaults to `60000`. -{{site.base_gateway}} will send the request over HTTP/1.1, and set the following headers: +{{site.base_gateway}} will send the request over HTTP/1.1 and set the following headers: -- `Host: `, as previously described in this document. -- `Connection: keep-alive`, to allow for reusing the upstream connections. -- `X-Real-IP: `, where `$remote_addr` is the variable bearing - the same name provided by - [ngx_http_core_module][ngx-remote-addr-variable]. Please note that the - `$remote_addr` is likely overridden by - [ngx_http_realip_module][ngx-http-realip-module]. -- `X-Forwarded-For:
`, where `
` is the content of - `$realip_remote_addr` provided by - [ngx_http_realip_module][ngx-http-realip-module] appended to the request - header with the same name. -- `X-Forwarded-Proto: `, where `` is the protocol used by - the client. In the case where `$realip_remote_addr` is one of the **trusted** - addresses, the request header with the same name gets forwarded if provided. - Otherwise, the value of the `$scheme` variable provided by - [ngx_http_core_module][ngx-scheme-variable] will be used. -- `X-Forwarded-Host: `, where `` is the host name sent by - the client. In the case where `$realip_remote_addr` is one of the **trusted** - addresses, the request header with the same name gets forwarded if provided. - Otherwise, the value of the `$host` variable provided by - [ngx_http_core_module][ngx-host-variable] will be used. -- `X-Forwarded-Port: `, where `` is the port of the server which - accepted a request. In the case where `$realip_remote_addr` is one of the - **trusted** addresses, the request header with the same name gets forwarded - if provided. Otherwise, the value of the `$server_port` variable provided by - [ngx_http_core_module][ngx-server-port-variable] will be used. -- `X-Forwarded-Prefix: `, where `` is the path of the request which - was accepted by {{site.base_gateway}}. In the case where `$realip_remote_addr` is one of the - **trusted** addresses, the request header with the same name gets forwarded - if provided. Otherwise, the value of the `$request_uri` variable (with - the query string stripped) provided by [ngx_http_core_module][ngx-server-port-variable] - will be used. - - - {:.note} - > **Note**: {{site.base_gateway}} returns `"/"` for an empty path, but it doesn't do any other - > normalization on the request path. - -All the other request headers are forwarded as-is by {{site.base_gateway}}. +| Header | Description | +|-----------------------------------------|-------------| +| `Host: ` | The host of your Upstream. | +| `Connection: keep-alive` | Allows for reusing the Upstream connections. | +| `X-Real-IP: ` | Where `$remote_addr` is the variable bearing the same name provided by [ngx_http_core_module](https://nginx.org/docs/http/ngx_http_core_module.html#var_remote_addr). The `$remote_addr` is likely overridden by [ngx_http_realip_module](https://nginx.org/docs/http/ngx_http_realip_module.html). | +| `X-Forwarded-For:
` | `
` is the content of `$realip_remote_addr` provided by [ngx_http_realip_module](https://nginx.org/docs/http/ngx_http_realip_module.html) appended to the request header with the same name. | +| `X-Forwarded-Proto: ` | `` is the protocol used by the client. If `$realip_remote_addr` is one of the **trusted** addresses, the request header with the same name gets forwarded if provided. Otherwise, the value of the `$scheme` variable provided by [ngx_http_core_module](https://nginx.org/docs/http/ngx_http_core_module.html#var_scheme) will be used. | +| `X-Forwarded-Host: ` | `` is the host name sent by the client. If `$realip_remote_addr` is one of the **trusted** addresses, the request header with the same name gets forwarded if provided. Otherwise, the value of the `$host` variable provided by [ngx_http_core_module](https://nginx.org/docs/http/ngx_http_core_module.html#var_host) will be used. | +| `X-Forwarded-Port: ` | `` is the port of the server which accepted a request. If `$realip_remote_addr` is one of the **trusted** addresses, the request header with the same name gets forwarded if provided. Otherwise, the value of the `$server_port` variable provided by [ngx_http_core_module](https://nginx.org/docs/http/ngx_http_core_module.html#var_server_port) will be used. | +| `X-Forwarded-Prefix: ` | `` is the path of the request which was accepted by {{site.base_gateway}}. If `$realip_remote_addr` is one of the **trusted** addresses, the request header with the same name gets forwarded if provided. Otherwise, the value of the `$request_uri` variable (with the query string stripped) provided by [ngx_http_core_module](https://nginx.org/docs/http/ngx_http_core_module.html#var_server_port) will be used. **Note**: {{site.base_gateway}} returns `"/"` for an empty path, but it doesn't do any other normalization on the request path. | +| All other headers | Forwarded as-is by {{site.base_gateway}} | One exception to this is made when using the WebSocket protocol. If so, {{site.base_gateway}} sets the following headers to allow for upgrading the protocol between the @@ -199,48 +146,44 @@ client and your upstream services: More information on this topic is covered in the [Proxy WebSocket traffic][proxy-websocket] section. -### Errors and retries +### Errors and retries during proxying Whenever an error occurs during proxying, {{site.base_gateway}} uses the underlying -Nginx [retries][ngx-http-proxy-retries] mechanism to pass the request on to +Nginx [retries][https://nginx.org/docs/http/ngx_http_proxy_module.html#proxy_next_upstream_tries] mechanism to pass the request on to the next upstream. -There are two configurable elements here: +There are two configurable elements: -1. The number of retries: this can be configured per service using the +1. The number of retries. This can be configured per Service using the `retries` property. See the [Admin API][API] for more details on this. -2. What exactly constitutes an error: here {{site.base_gateway}} uses the Nginx defaults, which - means an error or timeout occurring while establishing a connection with the - server, passing a request to it, or reading the response headers. +2. What exactly constitutes an error. Here {{site.base_gateway}} uses the Nginx defaults, which means an error or timeout that occurs while establishing a connection with the server, passing a request to it, or reading the response headers. The second option is based on Nginx's -[`proxy_next_upstream`](https://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_next_upstream) directive. This option is not +[`proxy_next_upstream`](https://nginx.org/docs/http/ngx_http_proxy_module.html#proxy_next_upstream) directive. This option is not directly configurable through {{site.base_gateway}}, but can be added using a custom Nginx configuration. See the [configuration reference][configuration-reference] for more details. -### Response +### Response streaming {{site.base_gateway}} receives the response from the upstream service and sends it back to the downstream client in a streaming fashion. At this point, {{site.base_gateway}} executes -subsequent plugins added to the route and/or service that implement a hook in +subsequent plugins added to the route or service that implement a hook in the `header_filter` phase. Once the `header_filter` phase of all registered plugins has been executed, the following headers are added by {{site.base_gateway}} and the full set of headers be sent to the client: -- `Via: kong/x.x.x`, where `x.x.x` is the {{site.base_gateway}} version in use -- `X-Kong-Proxy-Latency: `, where `latency` is the time in milliseconds - between {{site.base_gateway}} receiving the request from the client and sending the request to - your upstream service. -- `X-Kong-Upstream-Latency: `, where `latency` is the time in - milliseconds that {{site.base_gateway}} was waiting for the first byte of the upstream service - response. +| Header | Description | +|---------------------------------------------|-------------| +| `Via: kong/x.x.x` | `x.x.x` is the {{site.base_gateway}} version in use. | +| `X-Kong-Proxy-Latency: ` | `latency` is the time, in milliseconds, between {{site.base_gateway}} receiving the request from the client and sending the request to your upstream service. | +| `X-Kong-Upstream-Latency: ` | `latency` is the time, in milliseconds, that {{site.base_gateway}} was waiting for the first byte of the upstream service response. | Once the headers are sent to the client, {{site.base_gateway}} starts executing -registered plugins for the route and/or service that implement the +registered plugins for the route or service that implement the `body_filter` hook. This hook may be called multiple times, due to the streaming nature of Nginx. Each chunk of the upstream response that is successfully processed by such `body_filter` hooks is sent back to the client. From 6c175cea0281d32d24b4a70d997ad97617a29286 Mon Sep 17 00:00:00 2001 From: Diana <75819066+cloudjumpercat@users.noreply.github.com> Date: Mon, 16 Dec 2024 16:01:19 -0600 Subject: [PATCH 12/34] Start adding the needed expressions router pages Signed-off-by: Diana <75819066+cloudjumpercat@users.noreply.github.com> --- ...plex-routes-with-the-expressions-router.md | 66 ++++++ .../routing/expressions-router-examples.md | 110 +++++++++ .../routing/expressions-router-reference.md | 213 ++++++++++++++++++ app/gateway/routing/expressions.md | 124 +++------- 4 files changed, 418 insertions(+), 95 deletions(-) create mode 100644 app/_how-tos/create-complex-routes-with-the-expressions-router.md create mode 100644 app/gateway/routing/expressions-router-examples.md create mode 100644 app/gateway/routing/expressions-router-reference.md diff --git a/app/_how-tos/create-complex-routes-with-the-expressions-router.md b/app/_how-tos/create-complex-routes-with-the-expressions-router.md new file mode 100644 index 000000000..59aae4abc --- /dev/null +++ b/app/_how-tos/create-complex-routes-with-the-expressions-router.md @@ -0,0 +1,66 @@ +--- +title: How to create rate limiting tiers with {{site.base_gateway}} +content_type: how_to +related_resources: + - text: Consumer Group API documentation + url: /api/gateway/admin-ee/ + - text: Rate Limiting Advanced plugin + url: /plugins/rate-limiting-advanced/ + +products: + - gateway + +works_on: + - on-prem + - konnect + +tools: + - deck + +prereqs: + entities: + services: + - example-service + routes: + - example-route + +min_version: + gateway: 3.4 + +plugins: + - rate-limiting-advanced + - key-auth + +entities: + - consumer + - consumer_group + +tier: enterprise + +tags: + - rate-limiting + +tldr: + q: How do I rate limit different tiers of users, such as free vs. premium subscribers, in my API using {{site.base_gateway}}? + a: To effectively manage API traffic for various user tiers (such as free, basic, and premium subscribers) you can create consumer groups for each tier and assign individual consumers to these groups. Then, configure the Rate Limiting Advanced plugin to apply specific rate limits based on these groups. This setup allows you to enforce customized request limits for each tier, ensuring fair usage and optimizing performance for high-value users. + +faqs: + - q: Why can't I use the regular Rate Limiting plugin to rate limit tiers of consumers? + a: We use the Rate Limiting Advanced plugin because it supports sliding windows, which we use to apply the rate limiting logic while taking into account previous hit rates (from the window that immediately precedes the current) using a dynamic weight. + +cleanup: + inline: + - title: Clean up Konnect environment + include_content: cleanup/platform/konnect + icon_url: /assets/icons/gateway.svg + - title: Destroy the {{site.base_gateway}} container + include_content: cleanup/products/gateway + icon_url: /assets/icons/gateway.svg +--- + +## 1. things + \ No newline at end of file diff --git a/app/gateway/routing/expressions-router-examples.md b/app/gateway/routing/expressions-router-examples.md new file mode 100644 index 000000000..47b5b9bff --- /dev/null +++ b/app/gateway/routing/expressions-router-examples.md @@ -0,0 +1,110 @@ +--- +title: Expressions router examples + +description: "{{site.base_gateway}} includes a rule-based engine using a domain-specific expressions language." + +content_type: reference +layout: reference + +products: + - gateway + +related_resources: + - text: Route entity + url: /gateway/entities/route/ + - text: About the expressions router + url: /gateway/routing/expressions/ + - text: Expressions repository + url: https://github.com/Kong/atc-router + +breadcrumbs: + - /gateway/ +--- + +## Expression router examples (HTTP) +### Prefix based path matching + +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: + +``` +http.path ^= "/foo/bar" +``` + +### Regex based path matching + +If you prefer to match a HTTP requests path against a regex, you can write the following route: + +``` +http.path ~ r#"/foo/bar/\d+"# +``` + +### Case insensitive path matching + +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: + +``` +lower(http.path) == "/foo/bar" +``` + +This will match requests with a path of `/foo/bar` and `/FOO/bAr`, for example. + +### Match by header value + +If you want to match incoming requests by the value of header `X-Foo`, do the following: + +``` +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 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: + +``` +any(http.headers.x_foo) ~ r#"bar\d"# +``` + +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: + +``` +any(lower(http.headers.x_foo)) ~ r#"bar\d"# +``` + +### 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: + +``` +http.path ~ r#"/foo/(?P.+)"# +``` + +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/). + +## Expression router examples (TCP, TLS, UDP) + +### 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 Kong) +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/expressions-router-reference.md b/app/gateway/routing/expressions-router-reference.md new file mode 100644 index 000000000..d3cec1b17 --- /dev/null +++ b/app/gateway/routing/expressions-router-reference.md @@ -0,0 +1,213 @@ +--- +title: Expressions router reference + +description: "{{site.base_gateway}} includes a rule-based engine using a domain-specific expressions language." + +content_type: reference +layout: reference + +products: + - gateway + +related_resources: + - text: Route entity + url: /gateway/entities/route/ + - text: About the expressions router + url: /gateway/routing/expressions/ + - text: Expressions repository + url: https://github.com/Kong/atc-router + +breadcrumbs: + - /gateway/ +--- + + + +This reference explains the parts of the expressions language structure used for the expression router. + +## Predicates + +A predicate is the basic unit of expressions code which takes the following form: + +``` +http.path ^= "/foo/bar" +``` + +This predicate example has the following structure: +* `http.path`: Field +* `^=`: Operator +* `"/foo/bar"`: Constant value + +## Type system + +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 and an error is returned +if the operator cannot be performed on the provided field and constant. + +The expressions language currently supports the following types: + +| Type | Description | Field type | Constant type | +|----------|------------------------------------------------------------------------------------------------------|------------|---------------| +| `String` | A string value, always in valid UTF-8. | ✅ | ✅ | +| `IpCidr` | Range of IP addresses in CIDR format. Can be either IPv4 or IPv6. | ❌ | ✅ | +| `IpAddr` | A single IP address. Can be either IPv4 or IPv6. | ✅ | ✅ | +| `Int` | A 64-bit signed integer. | ✅ | ✅ | +| `Regex` | A regex in [syntax](https://docs.rs/regex/latest/regex/#syntax) specified by the Rust `regex` crate. | ❌ | ✅ | + +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`. + +### String + +Strings are valid UTF-8 sequences. They can be defined with string literal that looks like +`"content"`. The following escape sequences are supported: + +| Escape sequence | Description | +|-----------------|---------------------------| +| `\n` | Newline character | +| `\r` | Carriage return character | +| `\t` | Horizontal tab character | +| `\\` | The `\` character | +| `\"` | The `"` character | + +In addition, expressions support raw string literals, like `r#"content"#`. +This feature is useful if you want to write a regex and repeated escape becomes +tedious to deal with. + +For example, if you want to match `http.path` against `/\d+\-\d+` using the regex `~` operator, the predicate will be written as the following with string literals: + +``` +http.path ~ "/\\d+\\-\\d+" +``` + +With raw string literals, you can write: + +``` +http.path ~ r#"/\d+\-\d+"# +``` + +### IpCidr + +`IpCidr` represents a range of IP addresses in Classless Inter-Domain Routing (CIDR) format. + +The following is an IPv4 example: + +``` +net.src.ip in 192.168.1.0/24 +``` + +The following is an IPv6 example: +``` +net.src.ip in fd00::/8 +``` + +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. + +### IpAddr + +`IpAddr` represents a single IP addresses in IPv4 Dot-decimal notation, +or the standard IPv6 Address Format. + +The following is an IPv4 example: + +``` +net.src.ip == 192.168.1.1 +``` + +The following is an IPv6 example: +``` +net.src.ip == fd00::1 +``` + +### Int + +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`. + +### Regex + +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/.+"# +``` + +## Operators + +Expressions language support 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 | +| `not in` | Not in | Field value is not inside the constant value | +| `contains` | Contains | Field value contains the constant value | +| `&&` | 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 | +{% if_version gte:3.4.x %} +| `!` | 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` | +{% endif_version %} + +### Extended descriptions + +### In and not in + +These operators are 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 + +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. + +### Type and operator semantics + +Here are the allowed combination of field types and constant types with each operator. +In the following table, rows represent field types that display on the left-hand side (LHS) of the predicate, +whereas columns represent constant value types that display on the right-hand side (RHS) of the predicate. + +| Field (LHS)/Constant (RHS) types | `String` | `IpCidr` | `IpAddr` | `Int` | `Regex` | `Expression` | +|----------------------------------|-----------------------------------------|----------------|----------|----------------------------------|---------|--------------| +| `String` | `==`, `!=`, `~`, `^=`, `=^`, `contains` | ❌ | ❌ | ❌ | `~` | ❌ | +| `IpAddr` | ❌ | `in`, `not in` | `==` | ❌ | ❌ | ❌ | +| `Int` | ❌ | ❌ | ❌ | `==`, `!=`, `>=`, `>`, `<=`, `<` | ❌ | ❌ | +| `Expression` | ❌ | ❌ | ❌ | ❌ | ❌ | `&&`, `||`| + + +{:.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 above](#string) still apply and it + is almost always easier to use raw string literals for the `~` operator as described in the [`Regex` section](#regex). + * 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. + diff --git a/app/gateway/routing/expressions.md b/app/gateway/routing/expressions.md index 2f9d407a1..859c83c5a 100644 --- a/app/gateway/routing/expressions.md +++ b/app/gateway/routing/expressions.md @@ -12,26 +12,46 @@ products: related_resources: - text: Route entity url: /gateway/entities/route/ - - text: Routing in {{site.base_gateway}} - url: /gateway/routing/ + - text: Expressions router reference + url: /gateway/routing/expressions-router-reference/ - text: Expressions repository url: https://github.com/Kong/atc-router breadcrumbs: - /gateway/ + +faq: + - q: When should I use the expressions router in place of (or alongside) the traditional compat router? + a: We recommend using the expressions router if you are running {{site.base_gateway}} 3.0.x or later. --- -{{ page.description }} 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 +{{ page.description }} Expressions can be used to perform tasks such as defining +complex routing logic on a [Route](/gateway/entities/route/). 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 +You can enable the expressions router in your [kong.conf] file by setting `router_flavor = expressions` and restarting your {{site.base_gateway}}. + +## Use cases + +Expressions router can help you with the following use cases: + * complex routes with regex + * something else + +## 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 @@ -64,7 +84,7 @@ This predicate example has the following structure: * `^=`: Operator * `"/foo/bar"`: Constant value -## How routes are executed +## 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. Routes are inserted into each router with the appropriate `priority` field set. The router is @@ -80,90 +100,4 @@ As soon as a route yields a match, the router stops matching and the matched rou > _**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. -## Expression router examples (HTTP) -### Prefix based path matching - -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: - -``` -http.path ^= "/foo/bar" -``` - -### Regex based path matching - -If you prefer to match a HTTP requests path against a regex, you can write the following route: - -``` -http.path ~ r#"/foo/bar/\d+"# -``` - -### Case insensitive path matching - -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: - -``` -lower(http.path) == "/foo/bar" -``` - -This will match requests with a path of `/foo/bar` and `/FOO/bAr`, for example. - -### Match by header value - -If you want to match incoming requests by the value of header `X-Foo`, do the following: - -``` -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 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: - -``` -any(http.headers.x_foo) ~ r#"bar\d"# -``` - -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: - -``` -any(lower(http.headers.x_foo)) ~ r#"bar\d"# -``` - -### 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: - -``` -http.path ~ r#"/foo/(?P.+)"# -``` - -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/). - -## Expression router examples (TCP, TLS, UDP) - -### 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 Kong) -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. + \ No newline at end of file +--> + +## 1. Edit the kong.conf to contain the line router_flavor = expressions and restart Kong Gateway. + +## 2. Create complex routes with expressions + +```sh + +curl --request POST \ + --url http://localhost:8001/services/example-service/routes \ + --header 'Content-Type: multipart/form-data' \ + --form-string name=complex_object \ + --form-string 'expression=(net.protocol == "http" || net.protocol == "https") && + (http.method == "GET" || http.method == "POST") && + (http.host == "example.com" || http.host == "example.test") && + (http.path ^= "/mock" || http.path ^= "/mocking") && + http.headers.x_another_header == "example_header" && (http.headers.x_my_header == "example" || http.headers.x_my_header == "example2")' +``` + +## 3. Validate this against a matching regex path \ No newline at end of file diff --git a/app/gateway/routing/expressions-router-examples.md b/app/gateway/routing/expressions-router-examples.md index 47b5b9bff..ae9b74bbc 100644 --- a/app/gateway/routing/expressions-router-examples.md +++ b/app/gateway/routing/expressions-router-examples.md @@ -1,11 +1,14 @@ --- title: Expressions router examples -description: "{{site.base_gateway}} includes a rule-based engine using a domain-specific expressions language." +description: "The expressions router can be used to perform tasks such as defining complex routing logic on a [Route](/gateway/entities/route/)." content_type: reference layout: reference +min_version: + gateway: 3.0 + products: - gateway @@ -14,6 +17,8 @@ related_resources: url: /gateway/entities/route/ - text: About the expressions router url: /gateway/routing/expressions/ + - text: Expressions router reference + url: /gateway/routing/expressions-router-reference/ - text: Expressions repository url: https://github.com/Kong/atc-router @@ -21,7 +26,9 @@ breadcrumbs: - /gateway/ --- -## Expression router examples (HTTP) +{{ page.description }} This page shows some example Routes in the expression language that you can use when you're configuring your own Routes. + +## HTTP examples ### Prefix based path matching 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: @@ -90,7 +97,7 @@ http.path ~ r#"/foo/(?P.+)"# 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/). -## Expression router examples (TCP, TLS, UDP) +## TCP, TLS, and UDP examples ### Match by source IP and destination port diff --git a/app/gateway/routing/expressions-router-reference.md b/app/gateway/routing/expressions-router-reference.md index d3cec1b17..204590d46 100644 --- a/app/gateway/routing/expressions-router-reference.md +++ b/app/gateway/routing/expressions-router-reference.md @@ -6,6 +6,9 @@ description: "{{site.base_gateway}} includes a rule-based engine using a domain- content_type: reference layout: reference +min_version: + gateway: 3.0 + products: - gateway @@ -14,6 +17,8 @@ related_resources: url: /gateway/entities/route/ - text: About the expressions router url: /gateway/routing/expressions/ + - text: Expressions router examples + url: /gateway/routing/expressions-router-examples/ - text: Expressions repository url: https://github.com/Kong/atc-router @@ -27,7 +32,7 @@ Reference: - the pieces are explained, but I need something at the front that explains how the things all work together, what does a completed one look like? and then we get into the bits and pieces. --> -This reference explains the parts of the expressions language structure used for the expression router. +This reference explains the different configurable entities for the [expressions router](/gateway/routing/expressions/). ## Predicates @@ -37,10 +42,14 @@ A predicate is the basic unit of expressions code which takes the following form http.path ^= "/foo/bar" ``` -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"` | ## Type system @@ -158,9 +167,9 @@ Expressions language support a rich set of operators that can be performed on va | `>` | 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 | -| `not in` | Not in | Field value is not inside the constant value | -| `contains` | Contains | Field value contains 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 | @@ -168,21 +177,7 @@ Expressions language support a rich set of operators that can be performed on va | `!` | 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` | {% endif_version %} -### Extended descriptions - -### In and not in - -These operators are 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 - -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. - -### Type and operator semantics +## Allowed type and operator combinations Here are the allowed combination of field types and constant types with each operator. In the following table, rows represent field types that display on the left-hand side (LHS) of the predicate, @@ -211,3 +206,132 @@ whereas columns represent constant value types that display on the right-hand si address types for the field and constant value will always cause the predicate to return `false` at runtime. +## Matching fields + +The following table describes the available matching fields, as well as their associated type when using an expressions based router. + + + +{% if_version gte:3.4.x %} +| Field | Type | Available in HTTP Subsystem | Available in Stream Subsystem | Description | +|------------------------------------------------------|------------|-----------------------------|-------------------------------|-------------| +| `net.protocol` | `String` | ✅ | ✅ | 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.prococol` field directly inside the expression. | +| `tls.sni` | `String` | ✅ | ✅ | If the connection is over TLS, the `server_name` extension from the ClientHello packet. | +| `http.method` | `String` | ✅ | ❌ | The method of the incoming HTTP request. (for example, `"GET"` or `"POST"`) | +| `http.host` | `String` | ✅ | ❌ | The `Host` header of the incoming HTTP request. | +| `http.path` | `String` | ✅ | ❌ | 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. | +| `http.path.segments.` | `String` | ✅ | ❌ | 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"`. | +| `http.path.segments._` | `String` | ✅ | ❌ | 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"`. | +| `http.path.segments.len` | `Int` | ✅ | ❌ | 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`. | +| `http.headers.` | `String[]` | ✅ | ❌ | 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. | +| `http.queries.` | `String[]` | ✅ | ❌ | The value(s) of query parameter ``. | +| `net.src.ip` | `IpAddr` | ✅ | ✅ | IP address of the client. | +| `net.src.port` | `Int` | ✅ | ✅ | The port number used by the client to connect. | +| `net.dst.ip` | `IpAddr` | ✅ | ✅ | Listening IP address where {{site.base_gateway}} accepts the incoming connection. | +| `net.dst.port` | `Int` | ✅ | ✅ | Listening port number where {{site.base_gateway}} accepts the incoming connection. | +{% endif_version %} + +{% if_version lte:3.4.x %} +| Field | Type | Available in HTTP Subsystem | Available in Stream Subsystem | Description | +|------------------------------------------------------|------------|-----------------------------|-------------------------------|-------------| +| `net.protocol` | `String` | ✅ | ✅ | 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.prococol` field directly inside the expression. | +| `tls.sni` | `String` | ✅ | ✅ | If the connection is over TLS, the `server_name` extension from the ClientHello packet. | +| `http.method` | `String` | ✅ | ❌ | The method of the incoming HTTP request. (for example, `"GET"` or `"POST"`) | +| `http.host` | `String` | ✅ | ❌ | The `Host` header of the incoming HTTP request. | +| `http.path` | `String` | ✅ | ❌ | 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. | +| `http.headers.` | `String[]` | ✅ | ❌ | 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. | +| `http.queries.` | `String[]` | ✅ | ❌ | The value(s) of query parameter ``. | +| `net.src.ip` | `IpAddr` | ❌ | ✅ | IP address of the client. | +| `net.src.port` | `Int` | ❌ | ✅ | The port number used by the client to connect. | +| `net.dst.ip` | `IpAddr` | ❌ | ✅ | Listening IP address where {{site.base_gateway}} accepts the incoming connection. | +| `net.dst.port` | `Int` | ❌ | ✅ | Listening port number where {{site.base_gateway}} accepts the incoming connection. | +{% endif_version %} + +## Expressions router performance considerations + +Performance is critical when it comes to proxying API traffic. This guide explains how to optimize the +expressions you write to get the most performance out of the routing engine. + +### Number of routes + +#### Route matching priority order + +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. + +The following examples show how you would prioritize two routes based on if they were likely to be matched or not. + +Example route 1: +``` +expression: http.path == "/likely/matched/request/path" +priority: 100 +``` + +Example route 2: +``` +expression: http.path == "/unlikely/matched/request/path" +priority: 50 +``` + +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 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: +``` +service: example-service +expression: http.path == "/hello" +``` + +Example route 2: +``` +service: example-service +expression: http.path == "/world" +``` + +These two routes can instead be combined as: + +``` +service: example-service +expression: http.path == "/hello" || http.path == "/world" +``` + +### Regular expressions usage + +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 usages can be eliminated, resulting in significantly +better matching performance. + +When performing exact matches (non-prefix matching) of a request path, use the `==` operator +instead of regex. + +**Faster performance example:** +``` +http.path == "/foo/bar" +``` + +**Slower performance example:** +``` +http.path ~ r#"^/foo/bar$"# +``` + +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:** +``` +http.path == "/foo/bar" || http.path == "/foo/bar/" +``` + +**Slower performance example:** +``` +http.path ~ r#"^/foo/?$"# +``` + diff --git a/app/gateway/routing/expressions.md b/app/gateway/routing/expressions.md index 859c83c5a..25f5df88b 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: "{{site.base_gateway}} includes a rule-based engine using a Domain-Specific Expressions Language." content_type: reference layout: reference @@ -17,63 +17,45 @@ related_resources: - text: Expressions repository url: https://github.com/Kong/atc-router +min_version: + gateway: 3.0 + breadcrumbs: - /gateway/ faq: - q: When should I use the expressions router in place of (or alongside) the traditional compat router? - a: We recommend using the expressions router if you are running {{site.base_gateway}} 3.0.x or later. + 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. --- - - {{ page.description }} Expressions can be used to perform tasks such as defining complex routing logic on a [Route](/gateway/entities/route/). -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. - -You can enable the expressions router in your [kong.conf] file by setting `router_flavor = expressions` and restarting your {{site.base_gateway}}. - -## Use cases +The expressions language is a strongly typed [Domain-Specific Language (DSL)](https://developer.mozilla.org/docs/Glossary/DSL/Domain_specific_language) +which allows you to define fields, data, and operators for a Route. This allows for more complex routing logic than the traditional router, while ensuring good runtime matching performance. -Expressions router can help you with the following use cases: - * complex routes with regex - * something else - -## 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) +You can enable the expressions router in your [kong.conf] file by setting `router_flavor = expressions` and restarting your {{site.base_gateway}}. Once it's enabled, you can use the expressions language as you create Routes. + +## Use cases + +Common use cases for the expressions router: -A predicate is structured like the following: +| Use case | Description | +|---------|------------| +| Complex routes | You can define complex Routes with the expressions router that the regular tradidtional compat router can't handle. | +| Routes with regex | Although you can use some regex with the regular tradidtional compat router, it's capabilities aren't as powerful as the expressions router. Additionally, regex in Routes can become a performance burden for {{site.base_gateway}}, but the expressions router can handle the performance load more gracefully. | + +## How expressions are formatted in the expressions router + +To understand how the expressions router routes requests, it's important to how an Route is formatted in expressions. + +The expressions router is a collection of Routes that are all evaluated against incoming requests until a match can be found. Each Route contains one or more predicates combined with logical operators, which {{site.base_gateway}} uses to match requests with Routes. + +A predicate is the basic unit of expressions code which takes the following form: ``` http.path ^= "/foo/bar" @@ -84,20 +66,17 @@ This predicate example has the following structure: * `^=`: Operator * `"/foo/bar"`: Constant value +For more information about each unit of the predicate, see the [Expressions router reference](/gateway/routing/expressions-router-reference/). + ## 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. -Routes are inserted into each router with the appropriate `priority` field set. The router is +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. -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). - As soon as a route yields a match, the router stops matching and the matched route is used to process the current request/connection. ![Router matching flow](https://docs.konghq.com/assets/images/products/gateway/reference/expressions-language/router-matching-flow.png) -> _**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. - - file, by set `router_flavor = expressions` and restart your {{site.base_gateway}}. Once it's enabled, you can use the expressions language as you create Routes. --- -{{ page.description }} Expressions can be used to perform tasks such as defining -complex routing logic on a [Route](/gateway/entities/route/). +{{ page.description }} The expressions language is a strongly typed [Domain-Specific Language (DSL)](https://developer.mozilla.org/docs/Glossary/DSL/Domain_specific_language) -which allows you to define fields, data, and operators for a Route. This allows for more complex routing logic than the traditional router, while ensuring good runtime matching performance. - -* **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. - -You can enable the expressions router in your [kong.conf] file by setting `router_flavor = expressions` and restarting your {{site.base_gateway}}. Once it's enabled, you can use the expressions language as you create Routes. +which allows you to define fields, data, and operators for a Route. This allows for more complex routing logic than the traditional router and ensures good runtime matching performance. ## Use cases @@ -46,7 +43,7 @@ Common use cases for the expressions router: | Use case | Description | |---------|------------| -| Complex routes | You can define complex Routes with the expressions router that the regular tradidtional compat router can't handle. | +| Complex Routes | You can define complex Routes with the expressions router that the regular traditional compat router can't handle. For example, the expressions router allows you to use the following complex routing logic:
* Prefix-based path matching
* Regex-based path matching
* Case insensitive path matching
* Match by header value
* Regex captures
* Match by source IP and destination port
* Match by SNI (for TLS Routes) | | Routes with regex | Although you can use some regex with the regular tradidtional compat router, it's capabilities aren't as powerful as the expressions router. Additionally, regex in Routes can become a performance burden for {{site.base_gateway}}, but the expressions router can handle the performance load more gracefully. | ## How expressions are formatted in the expressions router @@ -68,15 +65,28 @@ This predicate example has the following structure: For more information about each unit of the predicate, see the [Expressions router reference](/gateway/routing/expressions-router-reference/). +A correctly formatted Route with multiple predicates would look like the following: +```sh +curl --request POST \ + --url http://localhost:8001/services/example-service/routes \ + --header 'Content-Type: multipart/form-data' \ + --form-string name=complex_object \ + --form-string 'expression=(net.protocol == "http" || net.protocol == "https") && + (http.method == "GET" || http.method == "POST") && + (http.host == "example.com" || http.host == "example.test") && + (http.path ^= "/mock" || http.path ^= "/mocking") && + http.headers.x_another_header == "example_header" && (http.headers.x_my_header == "example" || http.headers.x_my_header == "example2")' +``` + ## 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, +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. +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. +As soon as a Route yields a match, the router stops matching and the matched Route is used to process the current request/connection. ![Router matching flow](https://docs.konghq.com/assets/images/products/gateway/reference/expressions-language/router-matching-flow.png) -> _**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. \ No newline at end of file +> _**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. \ No newline at end of file From 1f69366018c2776a4692509ec06c3cdf99eda64c Mon Sep 17 00:00:00 2001 From: Diana <75819066+cloudjumpercat@users.noreply.github.com> Date: Wed, 18 Dec 2024 14:23:19 -0600 Subject: [PATCH 15/34] Remove expressions router how to and move enabling info to other pages Signed-off-by: Diana <75819066+cloudjumpercat@users.noreply.github.com> --- ...plex-routes-with-the-expressions-router.md | 86 ------- app/_includes/info_box/concept.html | 4 + .../routing/expressions-router-examples.md | 2 +- .../routing/expressions-router-reference.md | 218 +++++++----------- app/gateway/routing/expressions.md | 18 +- 5 files changed, 101 insertions(+), 227 deletions(-) delete mode 100644 app/_how-tos/create-complex-routes-with-the-expressions-router.md diff --git a/app/_how-tos/create-complex-routes-with-the-expressions-router.md b/app/_how-tos/create-complex-routes-with-the-expressions-router.md deleted file mode 100644 index ae737f56f..000000000 --- a/app/_how-tos/create-complex-routes-with-the-expressions-router.md +++ /dev/null @@ -1,86 +0,0 @@ ---- -title: Create complex routes with regex in {{site.base_gateway}} -content_type: how_to -related_resources: - - text: Route entity - url: /gateway/entities/route/ - - text: About the expressions router - url: /gateway/routing/expressions/ - - text: Expressions router reference - url: /gateway/routing/expressions-router-reference/ - - text: Expressions router examples - url: /gateway/routing/expressions-router-examples/ - - text: Expressions repository - url: https://github.com/Kong/atc-router - -products: - - gateway - -works_on: - - on-prem - - konnect - -tools: - - deck - -prereqs: - entities: - services: - - example-service - -min_version: - gateway: 3.0 - -entities: - - route - -tier: enterprise - -tags: - - routing - - traffic-control - -tldr: - q: lkjblk - a: aksjlkj - -faqs: - - q: asfa - a: asdfa - -cleanup: - inline: - - title: Clean up Konnect environment - include_content: cleanup/platform/konnect - icon_url: /assets/icons/gateway.svg - - title: Destroy the {{site.base_gateway}} container - include_content: cleanup/products/gateway - icon_url: /assets/icons/gateway.svg ---- - - - -## 1. Edit the kong.conf to contain the line router_flavor = expressions and restart Kong Gateway. - -## 2. Create complex routes with expressions - -```sh -curl --request POST \ - --url http://localhost:8001/services/example-service/routes \ - --header 'Content-Type: multipart/form-data' \ - --form-string name=complex_object \ - --form-string 'expression=(net.protocol == "http" || net.protocol == "https") && - (http.method == "GET" || http.method == "POST") && - (http.host == "example.com" || http.host == "example.test") && - (http.path ^= "/mock" || http.path ^= "/mocking") && - http.headers.x_another_header == "example_header" && (http.headers.x_my_header == "example" || http.headers.x_my_header == "example2")' -``` - -## 3. Validate this against a matching regex path \ No newline at end of file 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-router-examples.md b/app/gateway/routing/expressions-router-examples.md index ae9b74bbc..26c7ec0b4 100644 --- a/app/gateway/routing/expressions-router-examples.md +++ b/app/gateway/routing/expressions-router-examples.md @@ -1,7 +1,7 @@ --- title: Expressions router examples -description: "The expressions router can be used to perform tasks such as defining complex routing logic on a [Route](/gateway/entities/route/)." +description: "The [expressions router](/gateway/routing/expressions/) can be used to perform tasks such as defining complex routing logic on a [Route](/gateway/entities/route/)." content_type: reference layout: reference diff --git a/app/gateway/routing/expressions-router-reference.md b/app/gateway/routing/expressions-router-reference.md index 204590d46..6b146787a 100644 --- a/app/gateway/routing/expressions-router-reference.md +++ b/app/gateway/routing/expressions-router-reference.md @@ -1,7 +1,7 @@ --- title: Expressions router reference -description: "{{site.base_gateway}} includes a rule-based engine using a domain-specific expressions language." +description: "The {{site.base_gateway}} [expressions router](/gateway/routing/expressions/) is a rule-based engine that uses a Domain-Specific Expressions Language to define complex routing logic on a [Route](/gateway/entities/route/)." content_type: reference layout: reference @@ -32,7 +32,23 @@ Reference: - the pieces are explained, but I need something at the front that explains how the things all work together, what does a completed one look like? and then we get into the bits and pieces. --> -This reference explains the different configurable entities for the [expressions router](/gateway/routing/expressions/). +{{ page.description }} The expressions router is a collection of Routes that are all evaluated against incoming requests until a match can be found. Each Route contains one or more predicates combined with logical operators, which {{site.base_gateway}} uses to match requests with Routes. + +A correctly formatted Route with multiple predicates would look like the following: +```sh +curl --request POST \ + --url http://localhost:8001/services/example-service/routes \ + --header 'Content-Type: multipart/form-data' \ + --form-string name=complex_object \ + --form-string 'expression=(net.protocol == "http" || net.protocol == "https") && + (http.method == "GET" || http.method == "POST") && + (http.host == "example.com" || http.host == "example.test") && + (http.path ^= "/mock" || http.path ^= "/mocking") && + http.headers.x_another_header == "example_header" && (http.headers.x_my_header == "example" || http.headers.x_my_header == "example2")' +``` + +This reference explains the different configurable entities for the expressions router. To learn more about how to configure a route using the expressions router, see [Create complex routes with regex in {{site.base_gateway}}](/how-to/create-complex-routes-with-the-expressions-router/). + ## Predicates @@ -42,6 +58,11 @@ A predicate is the basic unit of expressions code which takes the following form http.path ^= "/foo/bar" ``` +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 | @@ -51,109 +72,74 @@ Predicates are made up of smaller units that you can configure: | 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"` | -## Type system +## Field and constant value types -Expressions language is strongly typed. Operations are only performed +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 and an error is returned +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: -| Type | Description | Field type | Constant type | -|----------|------------------------------------------------------------------------------------------------------|------------|---------------| -| `String` | A string value, always in valid UTF-8. | ✅ | ✅ | -| `IpCidr` | Range of IP addresses in CIDR format. Can be either IPv4 or IPv6. | ❌ | ✅ | -| `IpAddr` | A single IP address. Can be either IPv4 or IPv6. | ✅ | ✅ | -| `Int` | A 64-bit signed integer. | ✅ | ✅ | -| `Regex` | A regex in [syntax](https://docs.rs/regex/latest/regex/#syntax) specified by the Rust `regex` crate. | ❌ | ✅ | +| Type | Description | Field type | Constant type | +|----------|----------------------|------------|---------------| +| `String` | 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 | ✅ | ✅ | +| `IpCidr` | 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. | ❌ | ✅ | +| `IpAddr` | 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. | ✅ | ✅ | +| `Int` | 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`. | ✅ | ✅ | +| `Regex` | 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/.+"#` | ❌ | ✅ | 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`. -### String - -Strings are valid UTF-8 sequences. They can be defined with string literal that looks like -`"content"`. The following escape sequences are supported: - -| Escape sequence | Description | -|-----------------|---------------------------| -| `\n` | Newline character | -| `\r` | Carriage return character | -| `\t` | Horizontal tab character | -| `\\` | The `\` character | -| `\"` | The `"` character | - -In addition, expressions support raw string literals, like `r#"content"#`. -This feature is useful if you want to write a regex and repeated escape becomes -tedious to deal with. - -For example, if you want to match `http.path` against `/\d+\-\d+` using the regex `~` operator, the predicate will be written as the following with string literals: - -``` -http.path ~ "/\\d+\\-\\d+" -``` - -With raw string literals, you can write: - -``` -http.path ~ r#"/\d+\-\d+"# -``` - -### IpCidr - -`IpCidr` represents a range of IP addresses in Classless Inter-Domain Routing (CIDR) format. - -The following is an IPv4 example: - -``` -net.src.ip in 192.168.1.0/24 -``` - -The following is an IPv6 example: -``` -net.src.ip in fd00::/8 -``` - -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. - -### IpAddr - -`IpAddr` represents a single IP addresses in IPv4 Dot-decimal notation, -or the standard IPv6 Address Format. - -The following is an IPv4 example: +### Matching fields -``` -net.src.ip == 192.168.1.1 -``` - -The following is an IPv6 example: -``` -net.src.ip == fd00::1 -``` - -### Int - -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`. +The following table describes the available matching fields, as well as their associated type when using an expressions based router. -### Regex + -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`: +{% if_version gte:3.4.x %} +| Field | Type | Available in HTTP Subsystem | Available in Stream Subsystem | Description | +|------------------------------------------------------|------------|-----------------------------|-------------------------------|-------------| +| `net.protocol` | `String` | ✅ | ✅ | 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.prococol` field directly inside the expression. | +| `tls.sni` | `String` | ✅ | ✅ | If the connection is over TLS, the `server_name` extension from the ClientHello packet. | +| `http.method` | `String` | ✅ | ❌ | The method of the incoming HTTP request. (for example, `"GET"` or `"POST"`) | +| `http.host` | `String` | ✅ | ❌ | The `Host` header of the incoming HTTP request. | +| `http.path` | `String` | ✅ | ❌ | 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. | +| `http.path.segments.` | `String` | ✅ | ❌ | 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"`. | +| `http.path.segments._` | `String` | ✅ | ❌ | 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"`. | +| `http.path.segments.len` | `Int` | ✅ | ❌ | 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`. | +| `http.headers.` | `String[]` | ✅ | ❌ | 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. | +| `http.queries.` | `String[]` | ✅ | ❌ | The value(s) of query parameter ``. | +| `net.src.ip` | `IpAddr` | ✅ | ✅ | IP address of the client. | +| `net.src.port` | `Int` | ✅ | ✅ | The port number used by the client to connect. | +| `net.dst.ip` | `IpAddr` | ✅ | ✅ | Listening IP address where {{site.base_gateway}} accepts the incoming connection. | +| `net.dst.port` | `Int` | ✅ | ✅ | Listening port number where {{site.base_gateway}} accepts the incoming connection. | +{% endif_version %} -``` -http.path ~ r#"/foo/bar/.+"# -``` +{% if_version lte:3.4.x %} +| Field | Type | Available in HTTP Subsystem | Available in Stream Subsystem | Description | +|------------------------------------------------------|------------|-----------------------------|-------------------------------|-------------| +| `net.protocol` | `String` | ✅ | ✅ | 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.prococol` field directly inside the expression. | +| `tls.sni` | `String` | ✅ | ✅ | If the connection is over TLS, the `server_name` extension from the ClientHello packet. | +| `http.method` | `String` | ✅ | ❌ | The method of the incoming HTTP request. (for example, `"GET"` or `"POST"`) | +| `http.host` | `String` | ✅ | ❌ | The `Host` header of the incoming HTTP request. | +| `http.path` | `String` | ✅ | ❌ | 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. | +| `http.headers.` | `String[]` | ✅ | ❌ | 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. | +| `http.queries.` | `String[]` | ✅ | ❌ | The value(s) of query parameter ``. | +| `net.src.ip` | `IpAddr` | ❌ | ✅ | IP address of the client. | +| `net.src.port` | `Int` | ❌ | ✅ | The port number used by the client to connect. | +| `net.dst.ip` | `IpAddr` | ❌ | ✅ | Listening IP address where {{site.base_gateway}} accepts the incoming connection. | +| `net.dst.port` | `Int` | ❌ | ✅ | Listening port number where {{site.base_gateway}} accepts the incoming connection. | +{% endif_version %} ## 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. + Expressions language support a rich set of operators that can be performed on various data types. | Operator | Name | Description | @@ -173,22 +159,21 @@ Expressions language support a rich set of operators that can be performed on va | `&&` | 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 | + {% if_version gte:3.4.x %} | `!` | 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` | {% endif_version %} ## Allowed type and operator combinations -Here are the allowed combination of field types and constant types with each operator. -In the following table, rows represent field types that display on the left-hand side (LHS) of the predicate, -whereas columns represent constant value types that display on the right-hand side (RHS) of the predicate. +Depending on the field type, only certain content types and operators are supported. -| Field (LHS)/Constant (RHS) types | `String` | `IpCidr` | `IpAddr` | `Int` | `Regex` | `Expression` | -|----------------------------------|-----------------------------------------|----------------|----------|----------------------------------|---------|--------------| -| `String` | `==`, `!=`, `~`, `^=`, `=^`, `contains` | ❌ | ❌ | ❌ | `~` | ❌ | -| `IpAddr` | ❌ | `in`, `not in` | `==` | ❌ | ❌ | ❌ | -| `Int` | ❌ | ❌ | ❌ | `==`, `!=`, `>=`, `>`, `<=`, `<` | ❌ | ❌ | -| `Expression` | ❌ | ❌ | ❌ | ❌ | ❌ | `&&`, `||`| +| Field type | Supported content types and their supported operators | +|------------|-------------------------------------------------------| +| `String` | * `String`: `==`, `!=`, `~`, `^=`, `=^`, `contains`
* `Regex`: `~` | +| `IpAddr` | * `IpCidr`: `in`, `not in`
* `IpAddr`: `==` | +| `Int` | `Int`: `==`, `!=`, `>=`, `>`, `<=`, `<` | +| `Expression` | `Regex`: `&&`, `||` | {:.note} @@ -196,8 +181,8 @@ whereas columns represent constant value types that display on the right-hand si * 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 above](#string) still apply and it - is almost always easier to use raw string literals for the `~` operator as described in the [`Regex` section](#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 @@ -206,47 +191,6 @@ whereas columns represent constant value types that display on the right-hand si address types for the field and constant value will always cause the predicate to return `false` at runtime. -## Matching fields - -The following table describes the available matching fields, as well as their associated type when using an expressions based router. - - - -{% if_version gte:3.4.x %} -| Field | Type | Available in HTTP Subsystem | Available in Stream Subsystem | Description | -|------------------------------------------------------|------------|-----------------------------|-------------------------------|-------------| -| `net.protocol` | `String` | ✅ | ✅ | 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.prococol` field directly inside the expression. | -| `tls.sni` | `String` | ✅ | ✅ | If the connection is over TLS, the `server_name` extension from the ClientHello packet. | -| `http.method` | `String` | ✅ | ❌ | The method of the incoming HTTP request. (for example, `"GET"` or `"POST"`) | -| `http.host` | `String` | ✅ | ❌ | The `Host` header of the incoming HTTP request. | -| `http.path` | `String` | ✅ | ❌ | 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. | -| `http.path.segments.` | `String` | ✅ | ❌ | 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"`. | -| `http.path.segments._` | `String` | ✅ | ❌ | 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"`. | -| `http.path.segments.len` | `Int` | ✅ | ❌ | 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`. | -| `http.headers.` | `String[]` | ✅ | ❌ | 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. | -| `http.queries.` | `String[]` | ✅ | ❌ | The value(s) of query parameter ``. | -| `net.src.ip` | `IpAddr` | ✅ | ✅ | IP address of the client. | -| `net.src.port` | `Int` | ✅ | ✅ | The port number used by the client to connect. | -| `net.dst.ip` | `IpAddr` | ✅ | ✅ | Listening IP address where {{site.base_gateway}} accepts the incoming connection. | -| `net.dst.port` | `Int` | ✅ | ✅ | Listening port number where {{site.base_gateway}} accepts the incoming connection. | -{% endif_version %} - -{% if_version lte:3.4.x %} -| Field | Type | Available in HTTP Subsystem | Available in Stream Subsystem | Description | -|------------------------------------------------------|------------|-----------------------------|-------------------------------|-------------| -| `net.protocol` | `String` | ✅ | ✅ | 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.prococol` field directly inside the expression. | -| `tls.sni` | `String` | ✅ | ✅ | If the connection is over TLS, the `server_name` extension from the ClientHello packet. | -| `http.method` | `String` | ✅ | ❌ | The method of the incoming HTTP request. (for example, `"GET"` or `"POST"`) | -| `http.host` | `String` | ✅ | ❌ | The `Host` header of the incoming HTTP request. | -| `http.path` | `String` | ✅ | ❌ | 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. | -| `http.headers.` | `String[]` | ✅ | ❌ | 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. | -| `http.queries.` | `String[]` | ✅ | ❌ | The value(s) of query parameter ``. | -| `net.src.ip` | `IpAddr` | ❌ | ✅ | IP address of the client. | -| `net.src.port` | `Int` | ❌ | ✅ | The port number used by the client to connect. | -| `net.dst.ip` | `IpAddr` | ❌ | ✅ | Listening IP address where {{site.base_gateway}} accepts the incoming connection. | -| `net.dst.port` | `Int` | ❌ | ✅ | Listening port number where {{site.base_gateway}} accepts the incoming connection. | -{% endif_version %} - ## Expressions router performance considerations Performance is critical when it comes to proxying API traffic. This guide explains how to optimize the diff --git a/app/gateway/routing/expressions.md b/app/gateway/routing/expressions.md index 626db2a42..bd6ee4586 100644 --- a/app/gateway/routing/expressions.md +++ b/app/gateway/routing/expressions.md @@ -3,8 +3,8 @@ title: Expressions router description: "The {{site.base_gateway}} expressions router is a rule-based engine that uses a Domain-Specific Expressions Language to define complex routing logic on a [Route](/gateway/entities/route/)." -content_type: concept -layout: concept +content_type: reference +layout: reference products: - gateway @@ -29,7 +29,19 @@ faqs: - q: When should I use the expressions router in place of (or alongside) the traditional compat 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. - q: How do I enable the expressions router? - a: In your [kong.conf] file, by set `router_flavor = expressions` and restart your {{site.base_gateway}}. Once it's enabled, you can use the expressions language as you create Routes. + a: | + 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. For example: + ```sh + curl --request POST \ + --url http://localhost:8001/services/example-service/routes \ + --header 'Content-Type: multipart/form-data' \ + --form-string name=complex_object \ + --form-string 'expression=(net.protocol == "http" || net.protocol == "https") && + (http.method == "GET" || http.method == "POST") && + (http.host == "example.com" || http.host == "example.test") && + (http.path ^= "/mock" || http.path ^= "/mocking") && + http.headers.x_another_header == "example_header" && (http.headers.x_my_header == "example" || http.headers.x_my_header == "example2")' + ``` --- {{ page.description }} From 7165bbc5667f6993e736a0d1ad5292132702aad7 Mon Sep 17 00:00:00 2001 From: Diana <75819066+cloudjumpercat@users.noreply.github.com> Date: Wed, 18 Dec 2024 14:43:47 -0600 Subject: [PATCH 16/34] Apply suggestions from code review Co-authored-by: Angel --- .../dynamically-rewrite-simple-request-urls-with-routes.md | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/app/_how-tos/dynamically-rewrite-simple-request-urls-with-routes.md b/app/_how-tos/dynamically-rewrite-simple-request-urls-with-routes.md index 1e8ad9b3c..c653d098b 100644 --- a/app/_how-tos/dynamically-rewrite-simple-request-urls-with-routes.md +++ b/app/_how-tos/dynamically-rewrite-simple-request-urls-with-routes.md @@ -1,5 +1,5 @@ --- -title: Dynamically rewrite simple request URLs with {{site.base_gateway}} Routes +title: Rewrite simple request URLs with {{site.base_gateway}} Routes content_type: how_to related_resources: - text: Routes @@ -38,11 +38,11 @@ tags: tldr: q: How can I divert traffic from an old URL to a new one with {{site.base_gateway}}? - a: Set up a Gateway Service with the old URL path and create a new a Route with new path.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 can set up a Service with the path `/api/old/` and a Route with the path `/new/api`. + 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. faqs: - q: My URLs are more complex, such as replacing `/api//old` with `/new/api/`, what should I use instead to rewrite them? - a: You can use the [Request Transformer plugin](/hub/request-transformer/) for a complex URL rewrite or the [expressions router](/gateway/routing/expressions/) ({{site.base_gateway}} 3.0.x or later) to describe Routes or paths as patterns using regular expressions. + a: You can use either the [Request Transformer plugin](/hub/request-transformer/) or the [expressions router](/gateway/routing/expressions/) for complex URLs. cleanup: inline: @@ -63,7 +63,6 @@ entities: services: - name: example-service url: http://httpbin.konghq.com/anything - path: /anything append_to_existing_section: true {% endentity_examples %} From 81e23551cf73a805b1f9e8447526a3a4d7620881 Mon Sep 17 00:00:00 2001 From: Diana <75819066+cloudjumpercat@users.noreply.github.com> Date: Wed, 18 Dec 2024 15:24:32 -0600 Subject: [PATCH 17/34] Apply Angel's remaining feedback to the rewrite urls how to Signed-off-by: Diana <75819066+cloudjumpercat@users.noreply.github.com> --- app/_gateway_entities/route.md | 2 +- ...ewrite-simple-request-urls-with-routes.md} | 29 ++++--------------- 2 files changed, 6 insertions(+), 25 deletions(-) rename app/_how-tos/{dynamically-rewrite-simple-request-urls-with-routes.md => rewrite-simple-request-urls-with-routes.md} (68%) diff --git a/app/_gateway_entities/route.md b/app/_gateway_entities/route.md index 7f40d7fe6..2765a2680 100644 --- a/app/_gateway_entities/route.md +++ b/app/_gateway_entities/route.md @@ -256,7 +256,7 @@ Use the following table to help you understand how Routes can be configured for | You want to... | Then use... | |--------|----------| | Rate limit internal and external traffic to a Service | [Enable a rate limiting plugin on Routes attached to the Service](/plugins/rate-limiting-advanced/) | -| Perform a simple URL rewrite, such as renaming your legacy `/api/old/` Upstream endpoint to a publicly accessible API endpoint that is now named `/new/api`. | [Set up a Gateway Service with the old path and a Route with new path](/how-to/dynamically-rewrite-simple-request-urls-with-routes/) | +| Perform a simple URL rewrite, such as renaming your legacy `/api/old/` Upstream endpoint to a publicly accessible API endpoint that is now named `/new/api`. | [Set up a Gateway Service with the old path and a Route with new path](/how-to/rewrite-simple-request-urls-with-routes/) | | Perform a complex URL rewrite, such as replacing `/api//old` with `/new/api/`. | [Request Transformer Advanced plugin](https://docs.konghq.com/hub/kong-inc/request-transformer-advanced/) | | Describe Routes or paths as patterns using regular expressions. | [Expressions router](/gateway/routing/expressions/) | diff --git a/app/_how-tos/dynamically-rewrite-simple-request-urls-with-routes.md b/app/_how-tos/rewrite-simple-request-urls-with-routes.md similarity index 68% rename from app/_how-tos/dynamically-rewrite-simple-request-urls-with-routes.md rename to app/_how-tos/rewrite-simple-request-urls-with-routes.md index c653d098b..60a3e0255 100644 --- a/app/_how-tos/dynamically-rewrite-simple-request-urls-with-routes.md +++ b/app/_how-tos/rewrite-simple-request-urls-with-routes.md @@ -8,8 +8,6 @@ related_resources: url: /gateway/entities/service/ - text: Routing in {{site.base_gateway}} url: /gateway/routing/ - - text: Expressions router - url: /gateway/routing/expressions/ products: - gateway @@ -25,8 +23,6 @@ prereqs: entities: services: - example-service - routes: - - example-route entities: - service @@ -54,23 +50,9 @@ cleanup: icon_url: /assets/icons/gateway.svg --- -## 1. Set up a Service with the path to the old Upstream +## 1. Set up a Route with the path to the new Upstream -In the prerequisites, you created the `example-service` and `example-route` with the `/anything` path. This path, `/anything`, is your old upstream path. You must modify your existing Service to contain the old `/anything` path. By doing it this way, traffic can continue to be routed to the old path while you enable the new path. - -{% entity_examples %} -entities: - services: - - name: example-service - url: http://httpbin.konghq.com/anything -append_to_existing_section: true -{% endentity_examples %} - - - -## 2. Set up a Route with the path to the new Upstream - -Now you can create a Route with your new path, `/new-path`, that points to the new Upstream. +In the prerequisites, you created the `example-service` pointing to the `/anything` upstream. This path, `/anything`, is your old upstream path. You must create a Route with your new path, `/new-path`, that points to the new Upstream. By doing it this way, traffic can continue to be routed to the old path while you enable the new path. {% entity_examples %} entities: @@ -80,14 +62,13 @@ entities: - "/new-path" service: name: example-service -append_to_existing_section: true {% endentity_examples %} -## 3. Apply configuration +## 2. Apply configuration {% include how-tos/steps/apply_config.md %} -## 4. Validate +## 3. Validate To validate that the URL was successfully rewritten and the request is now being matched to the new Upstream instead of the old one, run the following: @@ -103,4 +84,4 @@ curl -i http://{host}/new-path Replace `{host}` with the proxy URL for this data plane node. {: data-deployment-topology="konnect" } -This command should display a 200 status as you're redirected to the new URL. \ No newline at end of file +This command should display a 200 status as you're redirected to the new URL. In the response, you'll also see that `"Host": "httpbin.konghq.com",` as the request is proxied to the new URL. \ No newline at end of file From 34e2faa695f9a71b3f9b428d65e67d7dc300df68 Mon Sep 17 00:00:00 2001 From: Diana <75819066+cloudjumpercat@users.noreply.github.com> Date: Wed, 18 Dec 2024 15:55:09 -0600 Subject: [PATCH 18/34] Apply suggestions from code review Co-authored-by: Lucie Milan <32450552+lmilan@users.noreply.github.com> Co-authored-by: lena-larionova <54370747+lena-larionova@users.noreply.github.com> --- app/_gateway_entities/route.md | 22 +++++++++---------- app/_gateway_entities/target.md | 16 +++++++------- app/_gateway_entities/upstream.md | 18 +++++++-------- .../routing/expressions-router-examples.md | 4 ++-- .../routing/expressions-router-reference.md | 4 ++-- app/gateway/traffic-control/proxy.md | 4 ++-- 6 files changed, 33 insertions(+), 35 deletions(-) diff --git a/app/_gateway_entities/route.md b/app/_gateway_entities/route.md index 2765a2680..91e3bf624 100644 --- a/app/_gateway_entities/route.md +++ b/app/_gateway_entities/route.md @@ -11,7 +11,7 @@ related_resources: url: /gateway/entities/service/ - text: Expressions router url: /gateway/routing/expressions/ - - text: Upstreams entity + - text: Upstream entity url: /gateway/entities/upstream/ - text: Proxying with {{site.base_gateway}} url: /gateway/traffic-control/proxy/ @@ -31,7 +31,7 @@ schema: ## What is a Route? -{{page.description}} [Gateway Services](/gateway/entities/service/) 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 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. +{{page.description}} [Gateway Services](/gateway/entities/service/) 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 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. @@ -83,7 +83,7 @@ For example, say you have an external application and an internal application th 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`, they're rate limited. +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. ## How routing works @@ -94,7 +94,7 @@ But when the internal application accesses the Service using {{site.base_gateway When you configure a Route, you must define certain attributes that {{site.base_gateway}} will use to match incoming requests. -{{site.base_gateway}} supports native proxying of HTTP/HTTPS, TCP/TLS, and GRPC/GRPCS protocols. Each of these protocols accept a different set of routing attributes: +{{site.base_gateway}} supports native proxying of HTTP/HTTPS, TCP/TLS, and GRPC/GRPCS protocols. Each of these protocols accepts a different set of routing attributes: - `http`: `methods`, `hosts`, `headers`, `paths` (and `snis`, if `https`) - `tcp`: `sources`, `destinations` (and `snis`, if `tls`) - `grpc`: `hosts`, `headers`, `paths` (and `snis`, if `grpcs`) @@ -115,9 +115,9 @@ The following sections describe specifics about the headers, paths, and SNI attr **Supported protocols:** `http`and `grpc` -Routing a request based on its Host header is the most straightforward way to proxy traffic through Kong Gateway, especially since this is the intended usage of the HTTP Host header. `hosts` accepts multiple values, which must be comma-separated when specifying them via the Admin API, and is represented in a JSON payload. You can also use wildcards in hostnames. Wildcard hostnames must contain only one asterisk at the leftmost or rightmost label of the domain. +Routing a request based on its Host header is the most straightforward way to proxy traffic through {{site.base_gateway}}, especially since this is the intended usage of the HTTP Host header. `hosts` accepts multiple values, which must be comma-separated when specifying them via the Admin API, and is represented in a JSON payload. You can also use wildcards in hostnames. Wildcard hostnames must contain only one asterisk at the leftmost or rightmost label of the domain. -When proxying, Kong Gateway’s default behavior is to set the Upstream request’s Host header to the hostname specified in the Service’s `host`. The `preserve_host` field accepts a boolean flag instructing Kong Gateway not to do so. +When proxying, {{site.base_gateway}}’s default behavior is to set the upstream request’s Host header to the hostname specified in the Service’s `host`. The `preserve_host` field accepts a boolean flag instructing {{site.base_gateway}} not to do so. | Example config | Example routing request matches | |---------------|--------------------------------| @@ -133,9 +133,9 @@ When proxying, Kong Gateway’s default behavior is to set the Upstream request Another way for a Route to be matched is via request paths. To satisfy this routing condition, a client request’s normalized path must be prefixed with one of the values of the `paths` attribute. -Kong Gateway detects that the request's normalized URL path is prefixed with one of the Routes’ `paths` values. By default, Kong Gateway would then proxy the request Upstream without changing the URL path. +{{site.base_gateway}} detects that the request's normalized URL path is prefixed with one of the Routes’ `paths` values. By default, {{site.base_gateway}} would then proxy the request Upstream without changing the URL path. -When proxying with path prefixes, the longest paths get evaluated first. This allow you to define two Routes with two paths: `/service` and `/service/resource`, and ensure that the former does not “shadow” the latter. +When proxying with path prefixes, the longest paths get evaluated first. This allows you to define two Routes with two paths: `/service` and `/service/resource`, and ensure that the former doesn't “shadow” the latter. * **Regex in paths:** For a path to be considered a regular expression, it must be prefixed with a `~`. For example: `paths: ["~/foo/bar$"]`. * **Evaluation order:** The router evaluates Routes using the `regex_priority` field of the Route where a Route is configured. Higher `regex_priority` values mean higher priority. If you have the following paths configured: @@ -168,7 +168,7 @@ When proxying with path prefixes, the longest paths get evaluated first. This al * **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. Specifically, the following normalization techniques are -used for incoming request URIs, which are selected because they generally do not change +used for incoming request URIs, which are selected because they generally don't change semantics of the request URI: 1. Percent-encoded triplets are converted to uppercase. For example: `/foo%3a` becomes `/foo%3A`. 2. Percent-encoded triplets of unreserved characters are decoded. For example: `/fo%6F` becomes `/foo`. @@ -191,7 +191,7 @@ Routers with a large number of regexes can consume traffic intended for other ru You can use a [Server Name Indication (SNI)](https://en.wikipedia.org/wiki/Server_Name_Indication) as a routing attribute. -Incoming requests with a matching hostname set in the TLS connection’s SNI extension would be Routed to this Route. As mentioned, SNI routing applies not only to TLS, but also to other protocols carried over TLS, such as HTTPS. If multiple SNIs are specified in the Route, any of them can match with the incoming request’s SNI (or relationship between the names). +Incoming requests with a matching hostname set in the TLS connection’s SNI extension would be routed to this Route. As mentioned, SNI routing applies not only to TLS, but also to other protocols carried over TLS, such as HTTPS. If multiple SNIs are specified in the Route, any of them can match with the incoming request’s SNI (or relationship between the names). The SNI is indicated at TLS handshake time and can't be modified after the TLS connection has been established. This means keepalive connections that send multiple requests will have the same SNI hostnames while performing router match (regardless of the `host` header). @@ -225,7 +225,7 @@ The routing method you should use depends on your {{site.base_gateway}} version: In `traditional_compat` mode, the priority of a Route is determined as follows, by the order of descending significance: -1. **Priority points:** For the presence of each of a Route's `methods`, `host`, `headers`, and `snis`, a "priority point" is added. 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. +1. **Priority points:** For the presence of each of a Route's `methods`, `host`, `headers`, and `snis`, a "priority point" is added. The number of "priority points" determines the overall order in which the Routes will be considered. Routes with 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. 2. **Wildcard hosts:** Among Routes with the same "priority point" value, those that have any wildcard host specification will be considered after those that don't have any wildcard host (or no host) specified. 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:** Within the resulting groups of Routes with equal priority, the router sorts them as follows: diff --git a/app/_gateway_entities/target.md b/app/_gateway_entities/target.md index 6c4321b97..09e5dca2f 100644 --- a/app/_gateway_entities/target.md +++ b/app/_gateway_entities/target.md @@ -11,10 +11,10 @@ tools: - deck - terraform -description: A target is an IP address/hostname with a port that identifies an instance of a backend service. +description: A Target is an IP address/hostname with a port that identifies an instance of a backend service. related_resources: - - text: Upstreams entity + - text: Upstream entity url: /gateway/entities/upstream/ - text: Routing in {{site.base_gateway}} url: /gateway/routing/ @@ -27,9 +27,9 @@ schema: --- -## What is a target? +## What is a Target? -{{page.description}} Each [Upstream](/gateway/entities/upstream/) can have many Targets. Targets are used by Upstreams for [load balancing]. For example, if you have an `example_upstream` upstream, you can point it to two different Targets: `httpbin.konghq.com` and `httpbun.com`. This is so that if one of the servers (like `httpbin.konghq.com`) is unavailable, it automatically detects the problem and routes all traffic to the working server (`httpbun.com`). +{{page.description}} Each [Upstream](/gateway/entities/upstream/) can have many Targets. Targets are used by Upstreams for [load balancing]. For example, if you have an `example_upstream` Upstream, you can point it to two different Targets: `httpbin.konghq.com` and `httpbun.com`. This is so that if one of the servers (like `httpbin.konghq.com`) is unavailable, it automatically detects the problem and routes all traffic to the working server (`httpbun.com`). The following diagram illustrates how Targets are used by Upstreams for load balancing: @@ -68,8 +68,8 @@ flowchart LR {% entity_example %} type: target data: - upstream: - description: example_upstream - id: 173a6cee-90d1-40a7-89cf-0329eca780a6 - weight: 100 + - target: httpbun.com:80 + weight: 100 + - target: httpbin.konghq.com:80 + weight: 100 {% endentity_example %} diff --git a/app/_gateway_entities/upstream.md b/app/_gateway_entities/upstream.md index c7627294a..1df25a322 100644 --- a/app/_gateway_entities/upstream.md +++ b/app/_gateway_entities/upstream.md @@ -16,18 +16,16 @@ tools: description: An upstream refers to the service applications sitting behind {{site.base_gateway}}, to which client requests are forwarded. related_resources: - - text: Gateway Services entity + - text: Gateway Service entity url: /gateway/entities/service/ - - text: Routes entity + - text: Route entity url: /gateway/entities/route/ - - text: Targets entity + - text: Target entity url: /gateway/entities/target/ - text: Routing in {{site.base_gateway}} url: /gateway/routing/ - text: Expressions router url: /gateway/routing/expressions/ - - text: Upstreams - url: /gateway/entities/upstream/ - text: Proxying with {{site.base_gateway}} url: /gateway/traffic-control/proxy/ @@ -38,20 +36,20 @@ schema: ## What is an Upstream? -{{page.description}} In {{site.base_gateway}}, an Upstream represents a virtual hostname and can be used to [health check, circuit break], and [load balance] incoming requests over multiple [Gateway Services](/gateway/entities/service/). In addition, the upstream entity has more advanced functionality algorithms like least-connections, consistent-hashing, and lowest-latency. +{{page.description}} In {{site.base_gateway}}, an Upstream represents a virtual hostname and can be used to [health check, circuit break], and [load balance] incoming requests over multiple [Gateway Services](/gateway/entities/service/). In addition, the Upstream entity has more advanced functionality algorithms like least-connections, consistent-hashing, and lowest-latency. -If you don't need to load balance hostnames, we recommend using the `host` header on a [Route](/gateway/entities/route/) as the preferred method for routing a request and proxying traffic. +If you don't need to load balance, we recommend using the `host` header on a [Route](/gateway/entities/route/) as the preferred method for routing a request and proxying traffic. ## Upstream and Service interaction You can configure a Service to point to an Upstream instead of a host. For example, if you have a Service called `example_service` and an Upstream called `example_upstream`, you can point `example_service` to `example_upstream` instead of specifying a host. -The `example_upstream` Upstream can then point to two different [targets](/gateway/entities/target/): `httpbin.konghq.com` and `httpbun.com`. +The `example_upstream` Upstream can then point to two different [Targets](/gateway/entities/target/): `httpbin.konghq.com` and `httpbun.com`. In a real environment, the Upstream points to the same Service running on multiple systems. -This setup allows you to [load balance] between upstream targets. +This setup allows you to load balance between upstream targets. For example, if an application is deployed across two different servers or upstream targets, {{site.base_gateway}} needs to load balance across both servers. -This is so that if one of the servers (like `httpbin.konghq.com` in the previous example) is unavailable, it automatically detects the problem and routes all traffic to the working server (`httpbun.com`). +If one of the servers (like `httpbin.konghq.com` in the previous example) is unavailable, it automatically detects the problem and routes all traffic to the working server (`httpbun.com`). The following diagram shows how Upstreams interact with other {{site.base_gateway}} entities: diff --git a/app/gateway/routing/expressions-router-examples.md b/app/gateway/routing/expressions-router-examples.md index 26c7ec0b4..d75b632da 100644 --- a/app/gateway/routing/expressions-router-examples.md +++ b/app/gateway/routing/expressions-router-examples.md @@ -39,7 +39,7 @@ http.path ^= "/foo/bar" ### Regex based path matching -If you prefer to match a HTTP requests path against a regex, you can write the following route: +If you prefer to match an HTTP request's path against a regex, you can write the following route: ``` http.path ~ r#"/foo/bar/\d+"# @@ -65,7 +65,7 @@ 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 value, the above example will ensure **each** instance of the +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, meaning each instance of the field value must pass the comparison for the predicate to return `true`. This is the default behavior. diff --git a/app/gateway/routing/expressions-router-reference.md b/app/gateway/routing/expressions-router-reference.md index 6b146787a..c3f57d35b 100644 --- a/app/gateway/routing/expressions-router-reference.md +++ b/app/gateway/routing/expressions-router-reference.md @@ -140,7 +140,7 @@ The following table describes the available matching fields, as well as their as 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. -Expressions language support a rich set of operators that can be performed on various data types. +The expressions language supports a rich set of operators that can be performed on various data types. | Operator | Name | Description | |----------------|-----------------------|--------------------------------------------------------------------------------------| @@ -250,7 +250,7 @@ expression: http.path == "/hello" || http.path == "/world" 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 usages can be eliminated, resulting in significantly +scenarios where regex usage can be eliminated, resulting in significantly better matching performance. When performing exact matches (non-prefix matching) of a request path, use the `==` operator diff --git a/app/gateway/traffic-control/proxy.md b/app/gateway/traffic-control/proxy.md index a866ff6c6..48bb7f33f 100644 --- a/app/gateway/traffic-control/proxy.md +++ b/app/gateway/traffic-control/proxy.md @@ -85,7 +85,7 @@ one. - `stream_listen`, which is similar to `proxy_listen` but for Layer 4 (TCP, TLS) generic proxy. This is turned off by default. -Kong Gateway is a transparent proxy, and it defaults to forwarding the request to your upstream service untouched, with the exception of various headers such as `Connection`, `Date`, and others as required by the HTTP specifications. +{{site.base_gateway}} is a transparent proxy, and it defaults to forwarding the request to your upstream service untouched, with the exception of various headers such as `Connection`, `Date`, and others as required by the HTTP specifications. ## Routing @@ -173,7 +173,7 @@ subsequent plugins added to the route or service that implement a hook in the `header_filter` phase. Once the `header_filter` phase of all registered plugins has been executed, the -following headers are added by {{site.base_gateway}} and the full set of headers be sent to +following headers are added by {{site.base_gateway}} and the full set of headers is sent to the client: | Header | Description | From 586509dde8c0da878204ec7156116d072ccc9e25 Mon Sep 17 00:00:00 2001 From: Diana <75819066+cloudjumpercat@users.noreply.github.com> Date: Wed, 18 Dec 2024 16:01:28 -0600 Subject: [PATCH 19/34] Apply Lena's feedback to Upstream entity page Signed-off-by: Diana <75819066+cloudjumpercat@users.noreply.github.com> --- app/_gateway_entities/upstream.md | 43 +++++++++++++++++-------------- 1 file changed, 23 insertions(+), 20 deletions(-) diff --git a/app/_gateway_entities/upstream.md b/app/_gateway_entities/upstream.md index 1df25a322..bf2c7f399 100644 --- a/app/_gateway_entities/upstream.md +++ b/app/_gateway_entities/upstream.md @@ -53,38 +53,41 @@ If one of the servers (like `httpbin.konghq.com` in the previous example) is una The following diagram shows how Upstreams interact with other {{site.base_gateway}} entities: + + {% mermaid %} flowchart LR - A(API client) - B("`Route + A("`Route (/mock)`") - C("`Service - (example-service)`") - D(Upstream - application) - - A <--requests - responses--> B - subgraph id1 ["` - **KONG GATEWAY**`"] - B <--requests - responses--> C + B("`Service + (example_service)`") + C(Upstream load balancer) + D(httpbin.konghq.com) + E(httpbun.com) + + subgraph id1 ["`**KONG GATEWAY**`"] + A --> B --> C + end + + subgraph id2 ["`Targets (example_upstream)`"] + C --> D & E end - C <--requests - responses--> D style id1 rx:10,ry:10 - + style id2 stroke:none {% endmermaid %} + + ## Use cases for Upstreams The following are examples of common use cases for Upstreams: -* **Load balance:** When an Upstream points to multiple upstream targets, you can configure the Upstream entity to load balance traffic between the targets. -* **Health check:** Configure Upstreams to dynamically mark a target as healthy or unhealthy. This is an active check where a specific HTTP or HTTPS endpoint in the target is periodically requested and the health of the target is determined based on its response. -* **Circuit break:** Configure Upstreams to allow {{site.base_gateway}} to passively analyze the ongoing traffic being proxied and determine the health of targets based on their behavior responding to requests. - **Note:** This feature is not supported in hybrid mode. +| Use case | Description | +|----------|-------------| +| Load balance | When an Upstream points to multiple upstream targets, you can configure the Upstream entity to load balance traffic between the targets. | +| Health check | Configure Upstreams to dynamically mark a target as healthy or unhealthy. This is an active check where a specific HTTP or HTTPS endpoint in the target is periodically requested and the health of the target is determined based on its response. | +| Circuit break | Configure Upstreams to allow {{site.base_gateway}} to passively analyze the ongoing traffic being proxied and determine the health of targets based on their behavior responding to requests. **Note:** This feature is not supported in hybrid mode. | ## Schema From e819205eaf7985a2a64001a06131de2db846b59a Mon Sep 17 00:00:00 2001 From: Diana <75819066+cloudjumpercat@users.noreply.github.com> Date: Wed, 18 Dec 2024 17:45:11 -0600 Subject: [PATCH 20/34] Revise Routes entity based on feedback Signed-off-by: Diana <75819066+cloudjumpercat@users.noreply.github.com> --- app/_gateway_entities/route.md | 192 ++++++--------------- app/_includes/content/how-routing-works.md | 9 - 2 files changed, 51 insertions(+), 150 deletions(-) delete mode 100644 app/_includes/content/how-routing-works.md diff --git a/app/_gateway_entities/route.md b/app/_gateway_entities/route.md index 91e3bf624..9e02836b1 100644 --- a/app/_gateway_entities/route.md +++ b/app/_gateway_entities/route.md @@ -35,15 +35,6 @@ schema: 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. -When you configure Routes, you can also specify the following: - -* **Protocols:** The protocol used to communicate with the [Upstream](/gateway/entities/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 - Use Routes if you don't need to load balance traffic to hosts. If you need to do load balancing between hostnames, configure your hosts in an [Upstream](/gateway/entities/upstream/) instead. ## Route and Service interaction @@ -54,26 +45,33 @@ The following diagram shows how Routes interact with other {{site.base_gateway}} {% mermaid %} flowchart LR - A(API client) - B("`Route - (/mock)`") - C("`Service - (example-service)`") - D(Upstream - application) + A(External application) + B("`Route (/external)`") + C("`Service (example-service)`") + D(Upstream application) + E(Internal application) + F("`Route (/internal)`") - A <--requests - responses--> B subgraph id1 ["` **KONG GATEWAY**`"] B <--requests - responses--> C + responses--> C + F <--requests + responses--> C end + + A <--requests + responses--> B + E <--requests + responses--> F + C <--requests responses--> D + B -.->|Rate Limiting plugin| C + style id1 rx:10,ry:10 - + {% endmermaid %} Routes also allow the same Service to be used by multiple applications and apply different policies based on the Route used. @@ -86,85 +84,51 @@ 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. -## How routing works - -{% include_cached /content/how-routing-works.md %} - -### Matching routing attributes - -When you configure a Route, you must define certain attributes that {{site.base_gateway}} will use to match incoming requests. - -{{site.base_gateway}} supports native proxying of HTTP/HTTPS, TCP/TLS, and GRPC/GRPCS protocols. Each of these protocols accepts a different set of routing attributes: -- `http`: `methods`, `hosts`, `headers`, `paths` (and `snis`, if `https`) -- `tcp`: `sources`, `destinations` (and `snis`, if `tls`) -- `grpc`: `hosts`, `headers`, `paths` (and `snis`, if `grpcs`) - -Note that all of these fields are **optional**, but at least **one of them** -must be specified. - -For a request to match a Route: - -- The request **must** include **all** of the configured fields -- The values of the fields in the request **must** match at least one of the - configured values (While the field configurations accepts one or more values, - a request needs only one of the values to be considered a match) - -The following sections describe specifics about the headers, paths, and SNI attributes you can configure. For information about additional attributes you can configure for Route matching, see the [Routes schema](/gateway/entities/route/#schema). +## Route use cases -#### Request header +Use the following table to help you understand how Routes can be configured for different use cases: -**Supported protocols:** `http`and `grpc` +| You want to... | Then use... | +|--------|----------| +| Rate limit internal and external traffic to a Service | [Enable a rate limiting plugin on Routes attached to the Service](/plugins/rate-limiting-advanced/) | +| Perform a simple URL rewrite, such as renaming your legacy `/api/old/` Upstream endpoint to a publicly accessible API endpoint that is now named `/new/api`. | [Set up a Gateway Service with the old path and a Route with new path](/how-to/rewrite-simple-request-urls-with-routes/) | +| Perform a complex URL rewrite, such as replacing `/api//old` with `/new/api/`. | [Request Transformer Advanced plugin](https://docs.konghq.com/hub/kong-inc/request-transformer-advanced/) | +| Describe Routes or paths as patterns using regular expressions. | [Expressions router](/gateway/routing/expressions/) | -Routing a request based on its Host header is the most straightforward way to proxy traffic through {{site.base_gateway}}, especially since this is the intended usage of the HTTP Host header. `hosts` accepts multiple values, which must be comma-separated when specifying them via the Admin API, and is represented in a JSON payload. You can also use wildcards in hostnames. Wildcard hostnames must contain only one asterisk at the leftmost or rightmost label of the domain. +## How routing works -When proxying, {{site.base_gateway}}’s default behavior is to set the upstream request’s Host header to the hostname specified in the Service’s `host`. The `preserve_host` field accepts a boolean flag instructing {{site.base_gateway}} not to do so. +For each incoming request, {{site.base_gateway}} must determine which Service gets to handle it based on the Routes that are defined. {{site.base_gateway}} handles routing in the following order: -| Example config | Example routing request matches | -|---------------|--------------------------------| -| `{"hosts":["example.com", "foo-service.com"]}` | `Host: example.com` and `Host: foo-service.com` | -| `headers.region=north` | `Region: North` | -| `"hosts": ["*.example.com", "example.*"]` | `Host: an.example.com` and `Host: example.org` | -| `"hosts": ["service.com"], "preserve_host": true,` | `Host: service.com` | -| `"headers": { "version": ["v1", "v2"] }` | `version: v1` | +1. {{site.base_gateway}} finds Routes that match the request by comparing the defined routing attributes with the attributes in the request. -#### Request path + If the rule count for the given request is the same in two Routes `A` and + `B`, then the following tiebreaker rules will be 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" paths and `B` has only "plain" paths. + * `A`'s longest path is longer than `B`'s longest path. + * `A.created_at < B.created_at` +1. 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. +1. 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/proxy/). -**Supported protocols:** `http` and `grpc` +{{site.base_gateway}} uses a router to route requests. There are two different routers you can use. Which you should use depends on your use case and {{site.base_gateway}} version: -Another way for a Route to be matched is via request paths. To satisfy this routing condition, a client request’s normalized path must be prefixed with one of the values of the `paths` attribute. +| Recommended {{site.base_gateway}} version | Routing method | Description | +|-------------------------------|----------------|-------------| +| 2.9.x or earlier | Traditional compatibility | 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. | +| 3.0.x or later | [Expressions router](/gateway/routing/expressions/) | The recommended method for anyone running {{site.base_gateway}} 3.0.x or later. Can be run in both `traditional_compat` and `expressions` modes. Handles complex routing logic and regex in Routes. | -{{site.base_gateway}} detects that the request's normalized URL path is prefixed with one of the Routes’ `paths` values. By default, {{site.base_gateway}} would then proxy the request Upstream without changing the URL path. +### Path matching When proxying with path prefixes, the longest paths get evaluated first. This allows you to define two Routes with two paths: `/service` and `/service/resource`, and ensure that the former doesn't “shadow” the latter. -* **Regex in paths:** For a path to be considered a regular expression, it must be prefixed with a `~`. For example: `paths: ["~/foo/bar$"]`. -* **Evaluation order:** The router evaluates Routes using the `regex_priority` field of the Route where a Route is configured. Higher `regex_priority` values mean higher priority. If you have the following paths configured: - ```sh - [ - { - "paths": ["~/status/\d+"], - "regex_priority": 0 - }, - { - "paths": ["~/version/\d+/status/\d+"], - "regex_priority": 6 - }, - { - "paths": /version, - }, - { - "paths": ["~/version/any/"], - } - ] - ``` - They are evaluated in the following order: - 1. `/version/\d+/status/\d+` - 1. `/status/\d+` - 1. `/version/any/` - 1. `/version` +Keep the following path matching recommendations in mind when configuring paths: + +* **Regex in paths:** For a path to be considered a regular expression, it must be prefixed with a `~`. For example: `paths: ["~/foo/bar$"]`. Routers with a large number of regexes can consume traffic intended for other rules. Regular expressions are much more expensive to build and execute and can’t be optimized easily. You can avoid creating complex regular expressions using the [Router Expressions language](/gateway/routing/expressions/). * **Capturing groups:** Capturing groups 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). -* **`strip_path` property:** If you want to specify a path prefix to match a Route, but not include it in the Upstream request, you can set the `strip_path` boolean property to `true`. * **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. Specifically, the following normalization techniques are @@ -177,48 +141,9 @@ semantics of the request URI: 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. -Routers with a large number of regexes can consume traffic intended for other rules. Regular expressions are much more expensive to build and execute and can’t be optimized easily. You can avoid creating complex regular expressions using the [Router Expressions language](/gateway/routing/expressions/). - -| Example config | Example routing request matches | -|---------------|--------------------------------| -| `"paths": ["/service", "/hello/world"]` | `GET /service HTTP/1.1 Host: example.com`, `GET /service/resource?param=value HTTP/1.1 Host: example.com`, and `GET /hello/world/resource HTTP/1.1 Host: anything.com` | -| `paths: ["~/foo/bar$"]` | `GET /foo/bar HTTP/1.1 Host: example.com` | -| `/version/(?\d+)/users/(?\S+)` | `/version/1/users/john` | - -#### Request SNI - -**Supported protocols:** `https`, `grpcs`, or `tls` - -You can use a [Server Name Indication (SNI)](https://en.wikipedia.org/wiki/Server_Name_Indication) as a routing attribute. - -Incoming requests with a matching hostname set in the TLS connection’s SNI extension would be routed to this Route. As mentioned, SNI routing applies not only to TLS, but also to other protocols carried over TLS, such as HTTPS. If multiple SNIs are specified in the Route, any of them can match with the incoming request’s SNI (or relationship between the names). - -The SNI is indicated at TLS handshake time and can't be modified after the TLS connection has been established. This means keepalive connections that send multiple requests will have the same SNI hostnames while performing router match (regardless of the `host` header). - -Creating a Route with a mismatched SNI and `host` header matcher is possible, but generally discouraged. - - -### Routing priority - -If multiple Routes match an incoming request, the {{site.base_gateway}} router then orders all defined Routes by their priority and uses the highest priority matching Route to handle a request. - -If the rule count for the given request is the same in two Routes `A` and -`B`, then the following tiebreaker rules will be 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" paths and `B` has only "plain" paths. -* `A`'s longest path is longer than `B`'s longest path. -* `A.created_at < B.created_at` - -The routing method you should use depends on your {{site.base_gateway}} version: +### Priority matching -| Recommended {{site.base_gateway}} version | Routing method | Description | -|-------------------------------|----------------|-------------| -| 2.9.x or earlier | Traditional compatibility | Only recommended for anyone running {{site.base_gateway}} 2.9.x or earlier. The original routing method for {{site.base_gateway}}. | -| 3.0.x or later | [Expressions router](/gateway/routing/expressions/) | The recommended method for anyone running {{site.base_gateway}} 3.0.x or later. Can be run in both `traditional_compat` and `expressions` modes. | +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. #### Traditional compatibility mode @@ -234,14 +159,10 @@ follows, by the order of descending significance: For a Route with multiple paths, each path will be considered separately for priority determination. Effectively, this means that separate Routes exist for each of the paths. -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](/). - #### Expressions router mode 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. -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/proxy/). - ### Routing performance recommendations You can use the following recommendations to increase routing performance: @@ -249,17 +170,6 @@ You can use the following recommendations to increase routing performance: * 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 regular expression with simple prefix 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. -## Route use cases - -Use the following table to help you understand how Routes can be configured for different use cases: - -| You want to... | Then use... | -|--------|----------| -| Rate limit internal and external traffic to a Service | [Enable a rate limiting plugin on Routes attached to the Service](/plugins/rate-limiting-advanced/) | -| Perform a simple URL rewrite, such as renaming your legacy `/api/old/` Upstream endpoint to a publicly accessible API endpoint that is now named `/new/api`. | [Set up a Gateway Service with the old path and a Route with new path](/how-to/rewrite-simple-request-urls-with-routes/) | -| Perform a complex URL rewrite, such as replacing `/api//old` with `/new/api/`. | [Request Transformer Advanced plugin](https://docs.konghq.com/hub/kong-inc/request-transformer-advanced/) | -| Describe Routes or paths as patterns using regular expressions. | [Expressions router](/gateway/routing/expressions/) | - ## Schema {% entity_schema %} diff --git a/app/_includes/content/how-routing-works.md b/app/_includes/content/how-routing-works.md deleted file mode 100644 index 5d7d5f8cd..000000000 --- a/app/_includes/content/how-routing-works.md +++ /dev/null @@ -1,9 +0,0 @@ -For each incoming request, {{site.base_gateway}} must determine which Service gets to handle it based on the Routes that are defined. {{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 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 two or more Routes are configured with fields containing the same values, {{site.base_gateway}} applies a priority rule. {{site.base_gateway}} first tries to match the Routes with the most rules. \ No newline at end of file From 1a1733d2089ce606e27d798f1f40b20213b41623 Mon Sep 17 00:00:00 2001 From: Diana <75819066+cloudjumpercat@users.noreply.github.com> Date: Wed, 18 Dec 2024 18:08:48 -0600 Subject: [PATCH 21/34] Revise proxy reference Signed-off-by: Diana <75819066+cloudjumpercat@users.noreply.github.com> --- app/gateway/traffic-control/proxy.md | 25 +++++-------------------- 1 file changed, 5 insertions(+), 20 deletions(-) diff --git a/app/gateway/traffic-control/proxy.md b/app/gateway/traffic-control/proxy.md index 48bb7f33f..bb4519fd2 100644 --- a/app/gateway/traffic-control/proxy.md +++ b/app/gateway/traffic-control/proxy.md @@ -50,14 +50,14 @@ sequenceDiagram 1. {{site.base_gateway}} listens for HTTP traffic on its configured proxy port(s) (`8000` and `8443` by default) and L4 traffic on explicitly configured `stream_listen` ports. -1. {{site.base_gateway}} will evaluate any incoming HTTP request or L4 connection against the Routes you have configured and try to find a matching one. +1. {{site.base_gateway}} will evaluate any incoming HTTP request or L4 connection against the Routes you have configured and try to find a matching one. For more details about how {{site.base_gateway}} handles routing, see the [Routes entity](/gateway/entities/route/). 1. 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. 1. If a given request matches the rules of a specific route, {{site.base_gateway}} will -run any global, Route, or Service [plugins]() before it proxies the request. They are run in the following order: Route, Service These configured plugins will run their `access` phase, which you can find more +run any global, Route, or Service [plugins]() before it proxies the request. Plugins configured on Routes run before those configured on Services. These configured plugins will run their `access` phase, which you can find more information about in the [Plugin development guide][plugin-development-guide]. 1. {{site.base_gateway}} implements [load balancing]() capabilities to distribute proxied requests across a pool of instances of an upstream service. -1. Once {{site.base_gateway}} has executed all the necessary logic (including plugins), it is ready to forward the request to your upstream service. This is done via Nginx's [`ngx_http_proxy_module`][ngx-http-proxy-module]. +1. Once {{site.base_gateway}} has executed all the necessary logic (including plugins), it is ready to forward the request to your upstream service. This is done via Nginx's [`ngx_http_proxy_module`](https://nginx.org/docs/http/ngx_http_proxy_module.html). 1. {{site.base_gateway}} receives the response from the upstream service and sends it back to the downstream client in a streaming fashion. At this point, {{site.base_gateway}} executes subsequent plugins added to the route and/or service that implement a hook in @@ -87,20 +87,6 @@ one. {{site.base_gateway}} is a transparent proxy, and it defaults to forwarding the request to your upstream service untouched, with the exception of various headers such as `Connection`, `Date`, and others as required by the HTTP specifications. -## Routing - -{% include_cached /content/how-routing-works.md %} - -For more details about how {{site.base_gateway}} handles routing, see the [Routes entity](/gateway/entities/route/). - -## Load balancing - -{{site.base_gateway}} implements load balancing capabilities to distribute proxied -requests across a pool of instances of an upstream service. - -You can find more information about load balancing in -the [Load Balancing Reference][]. - ## Proxying Once {{site.base_gateway}} has executed all the necessary logic (including plugins), it is ready @@ -123,7 +109,6 @@ timeouts for the connection between {{site.base_gateway}} and a given Upstream, {{site.base_gateway}} will send the request over HTTP/1.1 and set the following headers: - | Header | Description | |-----------------------------------------|-------------| | `Host: ` | The host of your Upstream. | @@ -136,7 +121,7 @@ timeouts for the connection between {{site.base_gateway}} and a given Upstream, | `X-Forwarded-Prefix: ` | `` is the path of the request which was accepted by {{site.base_gateway}}. If `$realip_remote_addr` is one of the **trusted** addresses, the request header with the same name gets forwarded if provided. Otherwise, the value of the `$request_uri` variable (with the query string stripped) provided by [ngx_http_core_module](https://nginx.org/docs/http/ngx_http_core_module.html#var_server_port) will be used. **Note**: {{site.base_gateway}} returns `"/"` for an empty path, but it doesn't do any other normalization on the request path. | | All other headers | Forwarded as-is by {{site.base_gateway}} | -One exception to this is made when using the WebSocket protocol. If so, {{site.base_gateway}} +One exception to this is made when using the WebSocket protocol. {{site.base_gateway}} sets the following headers to allow for upgrading the protocol between the client and your upstream services: @@ -149,7 +134,7 @@ More information on this topic is covered in the ### Errors and retries during proxying Whenever an error occurs during proxying, {{site.base_gateway}} uses the underlying -Nginx [retries][https://nginx.org/docs/http/ngx_http_proxy_module.html#proxy_next_upstream_tries] mechanism to pass the request on to +Nginx [retries](https://nginx.org/docs/http/ngx_http_proxy_module.html#proxy_next_upstream_tries) mechanism to pass the request on to the next upstream. There are two configurable elements: From 990afc605dfecbb514869d3519e4b88c476eb753 Mon Sep 17 00:00:00 2001 From: Diana <75819066+cloudjumpercat@users.noreply.github.com> Date: Wed, 18 Dec 2024 18:18:58 -0600 Subject: [PATCH 22/34] Minor link fixes, make vale happy again Signed-off-by: Diana <75819066+cloudjumpercat@users.noreply.github.com> --- app/gateway/routing/expressions-router-reference.md | 2 +- app/gateway/routing/expressions.md | 6 +++--- app/gateway/traffic-control/proxy.md | 5 +++++ 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/app/gateway/routing/expressions-router-reference.md b/app/gateway/routing/expressions-router-reference.md index c3f57d35b..dd76af888 100644 --- a/app/gateway/routing/expressions-router-reference.md +++ b/app/gateway/routing/expressions-router-reference.md @@ -47,7 +47,7 @@ curl --request POST \ http.headers.x_another_header == "example_header" && (http.headers.x_my_header == "example" || http.headers.x_my_header == "example2")' ``` -This reference explains the different configurable entities for the expressions router. To learn more about how to configure a route using the expressions router, see [Create complex routes with regex in {{site.base_gateway}}](/how-to/create-complex-routes-with-the-expressions-router/). +This reference explains the different configurable entities for the expressions router. ## Predicates diff --git a/app/gateway/routing/expressions.md b/app/gateway/routing/expressions.md index bd6ee4586..55e7087ea 100644 --- a/app/gateway/routing/expressions.md +++ b/app/gateway/routing/expressions.md @@ -26,7 +26,7 @@ breadcrumbs: - /gateway/ faqs: - - q: When should I use the expressions router in place of (or alongside) the traditional compat router? + - 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. - q: How do I enable the expressions router? a: | @@ -55,8 +55,8 @@ Common use cases for the expressions router: | Use case | Description | |---------|------------| -| Complex Routes | You can define complex Routes with the expressions router that the regular traditional compat router can't handle. For example, the expressions router allows you to use the following complex routing logic:
* Prefix-based path matching
* Regex-based path matching
* Case insensitive path matching
* Match by header value
* Regex captures
* Match by source IP and destination port
* Match by SNI (for TLS Routes) | -| Routes with regex | Although you can use some regex with the regular tradidtional compat router, it's capabilities aren't as powerful as the expressions router. Additionally, regex in Routes can become a performance burden for {{site.base_gateway}}, but the expressions router can handle the performance load more gracefully. | +| Complex Routes | You can define complex Routes with the expressions router that the traditional router can't handle. For example, the expressions router allows you to use the following complex routing logic:
* Prefix-based path matching
* Regex-based path matching
* Case insensitive path matching
* Match by header value
* Regex captures
* Match by source IP and destination port
* Match by SNI (for TLS Routes) | +| Routes with regex | Although you can use some regex with the traditional router, it's capabilities aren't as powerful as the expressions router. Additionally, regex in Routes can become a performance burden for {{site.base_gateway}}, but the expressions router can handle the performance load more gracefully. | ## How expressions are formatted in the expressions router diff --git a/app/gateway/traffic-control/proxy.md b/app/gateway/traffic-control/proxy.md index bb4519fd2..55f5d20a9 100644 --- a/app/gateway/traffic-control/proxy.md +++ b/app/gateway/traffic-control/proxy.md @@ -23,6 +23,7 @@ breadcrumbs: {{ page.description }} This page details information about how {{site.base_gateway}} handles proxying. The following diagram shows how proxying is handled by {{site.base_gateway}}: + {% mermaid %} sequenceDiagram actor Client @@ -44,6 +45,7 @@ sequenceDiagram Gateway->>Plugins: Executes plugins in the `header_filter` phase Gateway->>Client: Streams response back to client {% endmermaid %} + {{site.base_gateway}} handles proxying in the following order: @@ -109,6 +111,8 @@ timeouts for the connection between {{site.base_gateway}} and a given Upstream, {{site.base_gateway}} will send the request over HTTP/1.1 and set the following headers: + + | Header | Description | |-----------------------------------------|-------------| | `Host: ` | The host of your Upstream. | @@ -120,6 +124,7 @@ timeouts for the connection between {{site.base_gateway}} and a given Upstream, | `X-Forwarded-Port: ` | `` is the port of the server which accepted a request. If `$realip_remote_addr` is one of the **trusted** addresses, the request header with the same name gets forwarded if provided. Otherwise, the value of the `$server_port` variable provided by [ngx_http_core_module](https://nginx.org/docs/http/ngx_http_core_module.html#var_server_port) will be used. | | `X-Forwarded-Prefix: ` | `` is the path of the request which was accepted by {{site.base_gateway}}. If `$realip_remote_addr` is one of the **trusted** addresses, the request header with the same name gets forwarded if provided. Otherwise, the value of the `$request_uri` variable (with the query string stripped) provided by [ngx_http_core_module](https://nginx.org/docs/http/ngx_http_core_module.html#var_server_port) will be used. **Note**: {{site.base_gateway}} returns `"/"` for an empty path, but it doesn't do any other normalization on the request path. | | All other headers | Forwarded as-is by {{site.base_gateway}} | + One exception to this is made when using the WebSocket protocol. {{site.base_gateway}} sets the following headers to allow for upgrading the protocol between the From fc92c6f64789b8891ee3853e11808fe7a176bb23 Mon Sep 17 00:00:00 2001 From: Diana <75819066+cloudjumpercat@users.noreply.github.com> Date: Wed, 18 Dec 2024 18:24:56 -0600 Subject: [PATCH 23/34] Fix broken links Signed-off-by: Diana <75819066+cloudjumpercat@users.noreply.github.com> --- app/_gateway_entities/route.md | 2 +- app/_how-tos/rewrite-simple-request-urls-with-routes.md | 2 +- app/gateway/traffic-control/proxy.md | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/_gateway_entities/route.md b/app/_gateway_entities/route.md index 9e02836b1..11f363fff 100644 --- a/app/_gateway_entities/route.md +++ b/app/_gateway_entities/route.md @@ -92,7 +92,7 @@ Use the following table to help you understand how Routes can be configured for |--------|----------| | Rate limit internal and external traffic to a Service | [Enable a rate limiting plugin on Routes attached to the Service](/plugins/rate-limiting-advanced/) | | Perform a simple URL rewrite, such as renaming your legacy `/api/old/` Upstream endpoint to a publicly accessible API endpoint that is now named `/new/api`. | [Set up a Gateway Service with the old path and a Route with new path](/how-to/rewrite-simple-request-urls-with-routes/) | -| Perform a complex URL rewrite, such as replacing `/api//old` with `/new/api/`. | [Request Transformer Advanced plugin](https://docs.konghq.com/hub/kong-inc/request-transformer-advanced/) | +| Perform a complex URL rewrite, such as replacing `/api//old` with `/new/api/`. | [Request Transformer Advanced plugin](/plugins/request-transformer-advanced/) | | Describe Routes or paths as patterns using regular expressions. | [Expressions router](/gateway/routing/expressions/) | ## How routing works diff --git a/app/_how-tos/rewrite-simple-request-urls-with-routes.md b/app/_how-tos/rewrite-simple-request-urls-with-routes.md index 60a3e0255..7d50ef87e 100644 --- a/app/_how-tos/rewrite-simple-request-urls-with-routes.md +++ b/app/_how-tos/rewrite-simple-request-urls-with-routes.md @@ -38,7 +38,7 @@ tldr: faqs: - q: My URLs are more complex, such as replacing `/api//old` with `/new/api/`, what should I use instead to rewrite them? - a: You can use either the [Request Transformer plugin](/hub/request-transformer/) or the [expressions router](/gateway/routing/expressions/) for complex URLs. + a: You can use either the [Request Transformer plugin](/plugins/request-transformer/) or the [expressions router](/gateway/routing/expressions/) for complex URLs. cleanup: inline: diff --git a/app/gateway/traffic-control/proxy.md b/app/gateway/traffic-control/proxy.md index 55f5d20a9..4c19ad53e 100644 --- a/app/gateway/traffic-control/proxy.md +++ b/app/gateway/traffic-control/proxy.md @@ -83,7 +83,7 @@ one. Kong's configuration capabilities: the **Admin API** (`8001` by default). {:.important} > **Important**: If you need to expose the `admin_listen` port to the internet in a production environment, - > {% if_version lte:2.8.x %}[secure it with authentication](/gateway/{{include.release}}/admin-api/secure-admin-api/).{% endif_version %}{% if_version gte:3.0.x %}[secure it with authentication](/gateway/{{include.release}}/production/running-kong/secure-admin-api/).{% endif_version %} + > [secure it with authentication](/api/gateway/admin-ee/). - `stream_listen`, which is similar to `proxy_listen` but for Layer 4 (TCP, TLS) generic proxy. This is turned off by default. From c5eb4b14cd2f64e8ced0372be4a1e9b923e876c9 Mon Sep 17 00:00:00 2001 From: Diana <75819066+cloudjumpercat@users.noreply.github.com> Date: Wed, 18 Dec 2024 18:37:57 -0600 Subject: [PATCH 24/34] Remove upstream and target entity pages since they are now handled in a different PR Signed-off-by: Diana <75819066+cloudjumpercat@users.noreply.github.com> --- app/_gateway_entities/target.md | 75 --------------------- app/_gateway_entities/upstream.md | 106 ------------------------------ 2 files changed, 181 deletions(-) delete mode 100644 app/_gateway_entities/target.md delete mode 100644 app/_gateway_entities/upstream.md diff --git a/app/_gateway_entities/target.md b/app/_gateway_entities/target.md deleted file mode 100644 index 09e5dca2f..000000000 --- a/app/_gateway_entities/target.md +++ /dev/null @@ -1,75 +0,0 @@ ---- -title: Targets -content_type: reference -entities: - - target - -tools: - - admin-api - - konnect-api - - kic - - deck - - terraform - -description: A Target is an IP address/hostname with a port that identifies an instance of a backend service. - -related_resources: - - text: Upstream entity - url: /gateway/entities/upstream/ - - text: Routing in {{site.base_gateway}} - url: /gateway/routing/ - - text: Proxying with {{site.base_gateway}} - url: /gateway/traffic-control/proxy/ - -schema: - api: gateway/admin-ee - path: /schemas/Target - ---- - -## What is a Target? - -{{page.description}} Each [Upstream](/gateway/entities/upstream/) can have many Targets. Targets are used by Upstreams for [load balancing]. For example, if you have an `example_upstream` Upstream, you can point it to two different Targets: `httpbin.konghq.com` and `httpbun.com`. This is so that if one of the servers (like `httpbin.konghq.com`) is unavailable, it automatically detects the problem and routes all traffic to the working server (`httpbun.com`). - -The following diagram illustrates how Targets are used by Upstreams for load balancing: - - - -{% mermaid %} -flowchart LR - A("`Route - (/mock)`") - B("`Service - (example_service)`") - C(Load balancer) - D(httpbin.konghq.com) - E(httpbun.com) - - subgraph id1 ["`**KONG GATEWAY**`"] - A --> B --> C - end - - subgraph id2 ["`Targets (example_upstream)`"] - C --> D & E - end - - style id1 rx:10,ry:10 - style id2 stroke:none -{% endmermaid %} - - - -## Schema - -{% entity_schema %} - -## Set up a Target - -{% entity_example %} -type: target -data: - - target: httpbun.com:80 - weight: 100 - - target: httpbin.konghq.com:80 - weight: 100 -{% endentity_example %} diff --git a/app/_gateway_entities/upstream.md b/app/_gateway_entities/upstream.md deleted file mode 100644 index bf2c7f399..000000000 --- a/app/_gateway_entities/upstream.md +++ /dev/null @@ -1,106 +0,0 @@ ---- -title: Upstreams -content_type: reference -entities: - - upstream - -products: - - gateway - -tools: - - admin-api - - kic - - deck - - terraform - -description: An upstream refers to the service applications sitting behind {{site.base_gateway}}, to which client requests are forwarded. - -related_resources: - - text: Gateway Service entity - url: /gateway/entities/service/ - - text: Route entity - url: /gateway/entities/route/ - - text: Target entity - url: /gateway/entities/target/ - - text: Routing in {{site.base_gateway}} - url: /gateway/routing/ - - text: Expressions router - url: /gateway/routing/expressions/ - - text: Proxying with {{site.base_gateway}} - url: /gateway/traffic-control/proxy/ - -schema: - api: gateway/admin-ee - path: /schemas/Upstream ---- - -## What is an Upstream? - -{{page.description}} In {{site.base_gateway}}, an Upstream represents a virtual hostname and can be used to [health check, circuit break], and [load balance] incoming requests over multiple [Gateway Services](/gateway/entities/service/). In addition, the Upstream entity has more advanced functionality algorithms like least-connections, consistent-hashing, and lowest-latency. - -If you don't need to load balance, we recommend using the `host` header on a [Route](/gateway/entities/route/) as the preferred method for routing a request and proxying traffic. - -## Upstream and Service interaction - -You can configure a Service to point to an Upstream instead of a host. -For example, if you have a Service called `example_service` and an Upstream called `example_upstream`, you can point `example_service` to `example_upstream` instead of specifying a host. -The `example_upstream` Upstream can then point to two different [Targets](/gateway/entities/target/): `httpbin.konghq.com` and `httpbun.com`. -In a real environment, the Upstream points to the same Service running on multiple systems. - -This setup allows you to load balance between upstream targets. -For example, if an application is deployed across two different servers or upstream targets, {{site.base_gateway}} needs to load balance across both servers. -If one of the servers (like `httpbin.konghq.com` in the previous example) is unavailable, it automatically detects the problem and routes all traffic to the working server (`httpbun.com`). - -The following diagram shows how Upstreams interact with other {{site.base_gateway}} entities: - - - -{% mermaid %} -flowchart LR - A("`Route - (/mock)`") - B("`Service - (example_service)`") - C(Upstream load balancer) - D(httpbin.konghq.com) - E(httpbun.com) - - subgraph id1 ["`**KONG GATEWAY**`"] - A --> B --> C - end - - subgraph id2 ["`Targets (example_upstream)`"] - C --> D & E - end - - style id1 rx:10,ry:10 - style id2 stroke:none -{% endmermaid %} - - - -## Use cases for Upstreams - -The following are examples of common use cases for Upstreams: - -| Use case | Description | -|----------|-------------| -| Load balance | When an Upstream points to multiple upstream targets, you can configure the Upstream entity to load balance traffic between the targets. | -| Health check | Configure Upstreams to dynamically mark a target as healthy or unhealthy. This is an active check where a specific HTTP or HTTPS endpoint in the target is periodically requested and the health of the target is determined based on its response. | -| Circuit break | Configure Upstreams to allow {{site.base_gateway}} to passively analyze the ongoing traffic being proxied and determine the health of targets based on their behavior responding to requests. **Note:** This feature is not supported in hybrid mode. | - -## Schema - -{% entity_schema %} - -## Set up an Upstream - -{% entity_example %} -type: upstream -data: - name: api.example.internal - tags: - - user-level - - low-priority - algorithm: round-robin -{% endentity_example %} From 318b8d6339c4c3a3cba204aa093198ca767191fb Mon Sep 17 00:00:00 2001 From: Diana <75819066+cloudjumpercat@users.noreply.github.com> Date: Wed, 18 Dec 2024 19:16:26 -0600 Subject: [PATCH 25/34] Convert expressions router image to mermaid Signed-off-by: Diana <75819066+cloudjumpercat@users.noreply.github.com> --- app/gateway/routing/expressions.md | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/app/gateway/routing/expressions.md b/app/gateway/routing/expressions.md index 55e7087ea..9921252f5 100644 --- a/app/gateway/routing/expressions.md +++ b/app/gateway/routing/expressions.md @@ -99,6 +99,17 @@ 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. -![Router matching flow](https://docs.konghq.com/assets/images/products/gateway/reference/expressions-language/router-matching-flow.png) +{% mermaid %} +flowchart LR + A["Incoming request
http.path:#quot;/foo/bar#quot;
http.post:#quot;konghq.com#quot;"] -->|Checks first, doesn't match| B1 + A --> |Checks second, does match|B2 + + subgraph router[Expressions Router] + direction TB + B1["**Route A:**
*expression:* http.path ^= #quot;/foo#quot; && http.host == #quot;example.com#quot;
*priority:* 100"] + B2["**Route B:**
*expression:* http.path ^= #quot;/foo#quot;
*priority:* 50"] + B3["**Route C:**
*expression:* http.path ^= #quot;/#quot;
*priority:* 10"] + end +{% endmermaid %} > _**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. \ No newline at end of file From 1def0495de3ae3b14887a19af836293f6148a27d Mon Sep 17 00:00:00 2001 From: Diana <75819066+cloudjumpercat@users.noreply.github.com> Date: Thu, 19 Dec 2024 11:32:28 -0600 Subject: [PATCH 26/34] Apply remaining feedback Signed-off-by: Diana <75819066+cloudjumpercat@users.noreply.github.com> --- app/_gateway_entities/route.md | 97 +++++----- .../routing/expressions-router-examples.md | 117 ----------- .../routing/expressions-router-reference.md | 25 ++- app/gateway/routing/expressions.md | 67 ++++--- app/gateway/traffic-control/proxy.md | 181 ------------------ 5 files changed, 106 insertions(+), 381 deletions(-) delete mode 100644 app/gateway/routing/expressions-router-examples.md delete mode 100644 app/gateway/traffic-control/proxy.md diff --git a/app/_gateway_entities/route.md b/app/_gateway_entities/route.md index 11f363fff..c56cbe77b 100644 --- a/app/_gateway_entities/route.md +++ b/app/_gateway_entities/route.md @@ -13,8 +13,6 @@ related_resources: url: /gateway/routing/expressions/ - text: Upstream entity url: /gateway/entities/upstream/ - - text: Proxying with {{site.base_gateway}} - url: /gateway/traffic-control/proxy/ tools: - admin-api @@ -35,13 +33,42 @@ schema: 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. -Use Routes if you don't need to load balance traffic to hosts. If you need to do load balancing between hostnames, configure your hosts in an [Upstream](/gateway/entities/upstream/) instead. +{% 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, 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 shows how Routes interact with other {{site.base_gateway}} entities: +The following diagram illustrates this example: {% mermaid %} flowchart LR @@ -74,16 +101,6 @@ flowchart LR {% endmermaid %} -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. - ## Route use cases Use the following table to help you understand how Routes can be configured for different use cases: @@ -97,47 +114,27 @@ Use the following table to help you understand how Routes can be configured for ## 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. {{site.base_gateway}} handles routing in the following order: +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](https://docs.konghq.com/gateway/latest/how-kong-works/routing-traffic/). -1. {{site.base_gateway}} finds Routes that match the request by comparing the defined routing attributes with the attributes in the request. +If multiple Routes match, {{site.base_gateway}} handles routing in the following order: - If the rule count for the given request is the same in two Routes `A` and - `B`, then the following tiebreaker rules will be 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" paths and `B` has only "plain" paths. - * `A`'s longest path is longer than `B`'s longest path. - * `A.created_at < B.created_at` +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 and uses the highest priority matching Route to handle a request. -1. 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/proxy/). {{site.base_gateway}} uses a router to route requests. There are two different routers you can use. Which you should use depends on your use case and {{site.base_gateway}} version: - -| Recommended {{site.base_gateway}} version | Routing method | Description | -|-------------------------------|----------------|-------------| -| 2.9.x or earlier | Traditional compatibility | 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. | -| 3.0.x or later | [Expressions router](/gateway/routing/expressions/) | The recommended method for anyone running {{site.base_gateway}} 3.0.x or later. Can be run in both `traditional_compat` and `expressions` modes. Handles complex routing logic and regex in Routes. | +* **[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 -When proxying with path prefixes, the longest paths get evaluated first. This allows you to define two Routes with two paths: `/service` and `/service/resource`, and ensure that the former doesn't “shadow” the latter. - Keep the following path matching recommendations in mind when configuring paths: -* **Regex in paths:** For a path to be considered a regular expression, it must be prefixed with a `~`. For example: `paths: ["~/foo/bar$"]`. Routers with a large number of regexes can consume traffic intended for other rules. Regular expressions are much more expensive to build and execute and can’t be optimized easily. You can avoid creating complex regular expressions using the [Router Expressions language](/gateway/routing/expressions/). +* **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:** Capturing groups 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. Specifically, the following normalization techniques are -used for incoming request URIs, which are selected because they generally don't change -semantics of the request URI: - 1. Percent-encoded triplets are converted to uppercase. For example: `/foo%3a` becomes `/foo%3A`. - 2. Percent-encoded triplets of unreserved characters are decoded. For example: `/fo%6F` becomes `/foo`. - 3. Dot segments are removed as necessary. For example: `/foo/./bar/../baz` becomes `/foo/baz`. - 4. Duplicate slashes are merged. For example: `/foo//bar` becomes `/foo/bar`. +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. @@ -150,14 +147,18 @@ If multiple Routes match, the {{site.base_gateway}} router then orders all defin In `traditional_compat` mode, the priority of a Route is determined as follows, by the order of descending significance: -1. **Priority points:** For the presence of each of a Route's `methods`, `host`, `headers`, and `snis`, a "priority point" is added. The number of "priority points" determines the overall order in which the Routes will be considered. Routes with 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. +1. **Priority points:** For the presence of each of a Route's `methods`, `host`, `headers`, and `snis`, a "priority point" is added. 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, those that have any wildcard host specification will be considered after those that don't have any wildcard host (or no host) specified. 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:** Within the resulting groups of Routes with equal priority, the router sorts them 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 those 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 those with shorter paths. - - For a Route with multiple paths, each path will be considered separately for priority determination. Effectively, this means that separate Routes exist for each of the paths. +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. + +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 in two Routes `A` and `B`, then the following tiebreaker rules will be 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" paths and `B` has only "plain" paths. + * `A`'s longest path is longer than `B`'s longest path. + * `A.created_at < B.created_at` #### Expressions router mode diff --git a/app/gateway/routing/expressions-router-examples.md b/app/gateway/routing/expressions-router-examples.md deleted file mode 100644 index d75b632da..000000000 --- a/app/gateway/routing/expressions-router-examples.md +++ /dev/null @@ -1,117 +0,0 @@ ---- -title: Expressions router examples - -description: "The [expressions router](/gateway/routing/expressions/) can be used to perform tasks such as defining complex routing logic on a [Route](/gateway/entities/route/)." - -content_type: reference -layout: reference - -min_version: - gateway: 3.0 - -products: - - gateway - -related_resources: - - text: Route entity - url: /gateway/entities/route/ - - text: About the expressions router - url: /gateway/routing/expressions/ - - text: Expressions router reference - url: /gateway/routing/expressions-router-reference/ - - text: Expressions repository - url: https://github.com/Kong/atc-router - -breadcrumbs: - - /gateway/ ---- - -{{ page.description }} This page shows some example Routes in the expression language that you can use when you're configuring your own Routes. - -## HTTP examples -### Prefix based path matching - -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: - -``` -http.path ^= "/foo/bar" -``` - -### Regex based path matching - -If you prefer to match an HTTP request's path against a regex, you can write the following route: - -``` -http.path ~ r#"/foo/bar/\d+"# -``` - -### Case insensitive path matching - -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: - -``` -lower(http.path) == "/foo/bar" -``` - -This will match requests with a path of `/foo/bar` and `/FOO/bAr`, for example. - -### Match by header value - -If you want to match incoming requests by the value of header `X-Foo`, do the following: - -``` -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, 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: - -``` -any(http.headers.x_foo) ~ r#"bar\d"# -``` - -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: - -``` -any(lower(http.headers.x_foo)) ~ r#"bar\d"# -``` - -### 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: - -``` -http.path ~ r#"/foo/(?P.+)"# -``` - -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/). - -## TCP, TLS, and UDP examples - -### 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 Kong) -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/expressions-router-reference.md b/app/gateway/routing/expressions-router-reference.md index dd76af888..5d94e9b95 100644 --- a/app/gateway/routing/expressions-router-reference.md +++ b/app/gateway/routing/expressions-router-reference.md @@ -17,8 +17,6 @@ related_resources: url: /gateway/entities/route/ - text: About the expressions router url: /gateway/routing/expressions/ - - text: Expressions router examples - url: /gateway/routing/expressions-router-examples/ - text: Expressions repository url: https://github.com/Kong/atc-router @@ -159,10 +157,7 @@ The expressions language supports a rich set of operators that can be performed | `&&` | 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 | - -{% if_version gte:3.4.x %} | `!` | 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` | -{% endif_version %} ## Allowed type and operator combinations @@ -191,6 +186,26 @@ Depending on the field type, only certain content types and operators are suppor 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. | + ## Expressions router performance considerations Performance is critical when it comes to proxying API traffic. This guide explains how to optimize the diff --git a/app/gateway/routing/expressions.md b/app/gateway/routing/expressions.md index 9921252f5..3756e7315 100644 --- a/app/gateway/routing/expressions.md +++ b/app/gateway/routing/expressions.md @@ -1,7 +1,7 @@ --- title: Expressions router -description: "The {{site.base_gateway}} expressions router is a rule-based engine that uses a Domain-Specific Expressions Language to define complex routing logic on a [Route](/gateway/entities/route/)." +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 @@ -14,8 +14,6 @@ related_resources: url: /gateway/entities/route/ - text: Expressions router reference url: /gateway/routing/expressions-router-reference/ - - text: Expressions router examples - url: /gateway/routing/expressions-router-examples/ - text: Expressions repository url: https://github.com/Kong/atc-router @@ -44,25 +42,20 @@ faqs: ``` --- -{{ page.description }} +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. -The expressions language is a strongly typed [Domain-Specific Language (DSL)](https://developer.mozilla.org/docs/Glossary/DSL/Domain_specific_language) -which allows you to define fields, data, and operators for a Route. This allows for more complex routing logic than the traditional router and ensures good runtime matching performance. - -## Use cases - -Common use cases for the expressions router: - -| Use case | Description | -|---------|------------| -| Complex Routes | You can define complex Routes with the expressions router that the traditional router can't handle. For example, the expressions router allows you to use the following complex routing logic:
* Prefix-based path matching
* Regex-based path matching
* Case insensitive path matching
* Match by header value
* Regex captures
* Match by source IP and destination port
* Match by SNI (for TLS Routes) | -| Routes with regex | Although you can use some regex with the traditional router, it's capabilities aren't as powerful as the expressions router. Additionally, regex in Routes can become a performance burden for {{site.base_gateway}}, but the expressions router can handle the performance load more gracefully. | +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) ## How expressions are formatted in the expressions router -To understand how the expressions router routes requests, it's important to how an Route is formatted in expressions. - -The expressions router is a collection of Routes that are all evaluated against incoming requests until a match can be found. Each Route contains one or more predicates combined with logical operators, which {{site.base_gateway}} uses to match requests with Routes. +To understand how the expressions router routes requests, it's important to how an Route is formatted in expressions. Each Route contains one or more predicates combined with logical operators, which {{site.base_gateway}} uses to match requests with Routes. A predicate is the basic unit of expressions code which takes the following form: @@ -99,17 +92,31 @@ 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. -{% mermaid %} -flowchart LR - A["Incoming request
http.path:#quot;/foo/bar#quot;
http.post:#quot;konghq.com#quot;"] -->|Checks first, doesn't match| B1 - A --> |Checks second, does match|B2 +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.post:"konghq.com" +``` - subgraph router[Expressions Router] - direction TB - B1["**Route A:**
*expression:* http.path ^= #quot;/foo#quot; && http.host == #quot;example.com#quot;
*priority:* 100"] - B2["**Route B:**
*expression:* http.path ^= #quot;/foo#quot;
*priority:* 50"] - B3["**Route C:**
*expression:* http.path ^= #quot;/#quot;
*priority:* 10"] - end -{% endmermaid %} +The router does the following: -> _**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. \ No newline at end of file +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. \ No newline at end of file diff --git a/app/gateway/traffic-control/proxy.md b/app/gateway/traffic-control/proxy.md deleted file mode 100644 index 4c19ad53e..000000000 --- a/app/gateway/traffic-control/proxy.md +++ /dev/null @@ -1,181 +0,0 @@ ---- -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/ ---- - -{{ page.description }} This page details information about how {{site.base_gateway}} handles proxying. The following diagram shows how proxying is handled by {{site.base_gateway}}: - - -{% mermaid %} -sequenceDiagram - actor Client - participant Gateway as Kong Gateway - participant Router - participant Plugins as Plugins - participant LoadBalancer as Load balancer - participant UpstreamService as Upstream Service - - Client->>Gateway: Sends HTTP request or L4 connection - Gateway->>Router: Evaluates incoming request against Routes - Router->>Router: Orders Routes by priority - Router->>Gateway: Returns highest priority matching Route - Gateway->>Plugins: Executes plugins the `access` phase - Gateway->>LoadBalancer: Implements load balancing capabilities - LoadBalancer->>LoadBalancer: Distributes request across upstream service instances - LoadBalancer->>UpstreamService: Forwards request to selected instance - UpstreamService->>Gateway: Sends response - Gateway->>Plugins: Executes plugins in the `header_filter` phase - Gateway->>Client: Streams response back to client -{% endmermaid %} - - -{{site.base_gateway}} handles proxying in the following order: - -1. {{site.base_gateway}} listens for HTTP traffic on its configured -proxy port(s) (`8000` and `8443` by default) and L4 traffic on explicitly configured -`stream_listen` ports. -1. {{site.base_gateway}} will evaluate any incoming HTTP request or L4 connection against the Routes you have configured and try to find a matching one. For more details about how {{site.base_gateway}} handles routing, see the [Routes entity](/gateway/entities/route/). -1. 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. -1. If a given request matches the rules of a specific route, {{site.base_gateway}} will -run any global, Route, or Service [plugins]() before it proxies the request. Plugins configured on Routes run before those configured on Services. These configured plugins will run their `access` phase, which you can find more -information about in the [Plugin development guide][plugin-development-guide]. -1. {{site.base_gateway}} implements [load balancing]() capabilities to distribute proxied -requests across a pool of instances of an upstream service. -1. Once {{site.base_gateway}} has executed all the necessary logic (including plugins), it is ready to forward the request to your upstream service. This is done via Nginx's [`ngx_http_proxy_module`](https://nginx.org/docs/http/ngx_http_proxy_module.html). -1. {{site.base_gateway}} receives the response from the upstream service and sends it back to the -downstream client in a streaming fashion. At this point, {{site.base_gateway}} executes -subsequent plugins added to the route and/or service that implement a hook in -the `header_filter` phase. - -## Listeners - -From a high-level perspective, {{site.base_gateway}} listens for HTTP traffic on its configured -proxy ports: `8000` and `8443` by default and L4 traffic on explicitly configured -`stream_listen` ports. {{site.base_gateway}} will evaluate any incoming -HTTP request or L4 connection against the routes you have configured and try to find a matching -one. - -{{site.base_gateway}} exposes several interfaces which can be tweaked by the following configuration properties: - -- `proxy_listen`: Defines a list of addresses/ports on which {{site.base_gateway}} will - accept **public HTTP (gRPC, WebSocket, etc) traffic** from clients and proxy - it to your upstream services (`8000` by default). -- `admin_listen`, which also defines a list of addresses and ports, but those - should be restricted to only be accessed by administrators, as they expose - Kong's configuration capabilities: the **Admin API** (`8001` by default). - {:.important} - > **Important**: If you need to expose the `admin_listen` port to the internet in a production environment, - > [secure it with authentication](/api/gateway/admin-ee/). -- `stream_listen`, which is similar to `proxy_listen` but for Layer 4 (TCP, TLS) - generic proxy. This is turned off by default. - -{{site.base_gateway}} is a transparent proxy, and it defaults to forwarding the request to your upstream service untouched, with the exception of various headers such as `Connection`, `Date`, and others as required by the HTTP specifications. - -## Proxying - -Once {{site.base_gateway}} has executed all the necessary logic (including plugins), it is ready -to forward the request to your upstream service. This is done with Nginx's -[`ngx_http_proxy_module`](https://nginx.org/docs/http/ngx_http_proxy_module.html). - -### Upstream timeouts - -You can configure the desired -timeouts for the connection between {{site.base_gateway}} and a given Upstream, using the following properties of a [Service](/gateway/entities/service/): - -- `connect_timeout`: Defines, in milliseconds, the timeout for - establishing a connection to your upstream service. Defaults to `60000`. -- `write_timeout`: Defines, in milliseconds, a timeout between two - successive write operations for transmitting a request to your upstream - service. Defaults to `60000`. -- `read_timeout`: Defines, in milliseconds, a timeout between two - successive read operations for receiving a request from your upstream - service. Defaults to `60000`. - -{{site.base_gateway}} will send the request over HTTP/1.1 and set the following headers: - - - -| Header | Description | -|-----------------------------------------|-------------| -| `Host: ` | The host of your Upstream. | -| `Connection: keep-alive` | Allows for reusing the Upstream connections. | -| `X-Real-IP: ` | Where `$remote_addr` is the variable bearing the same name provided by [ngx_http_core_module](https://nginx.org/docs/http/ngx_http_core_module.html#var_remote_addr). The `$remote_addr` is likely overridden by [ngx_http_realip_module](https://nginx.org/docs/http/ngx_http_realip_module.html). | -| `X-Forwarded-For:
` | `
` is the content of `$realip_remote_addr` provided by [ngx_http_realip_module](https://nginx.org/docs/http/ngx_http_realip_module.html) appended to the request header with the same name. | -| `X-Forwarded-Proto: ` | `` is the protocol used by the client. If `$realip_remote_addr` is one of the **trusted** addresses, the request header with the same name gets forwarded if provided. Otherwise, the value of the `$scheme` variable provided by [ngx_http_core_module](https://nginx.org/docs/http/ngx_http_core_module.html#var_scheme) will be used. | -| `X-Forwarded-Host: ` | `` is the host name sent by the client. If `$realip_remote_addr` is one of the **trusted** addresses, the request header with the same name gets forwarded if provided. Otherwise, the value of the `$host` variable provided by [ngx_http_core_module](https://nginx.org/docs/http/ngx_http_core_module.html#var_host) will be used. | -| `X-Forwarded-Port: ` | `` is the port of the server which accepted a request. If `$realip_remote_addr` is one of the **trusted** addresses, the request header with the same name gets forwarded if provided. Otherwise, the value of the `$server_port` variable provided by [ngx_http_core_module](https://nginx.org/docs/http/ngx_http_core_module.html#var_server_port) will be used. | -| `X-Forwarded-Prefix: ` | `` is the path of the request which was accepted by {{site.base_gateway}}. If `$realip_remote_addr` is one of the **trusted** addresses, the request header with the same name gets forwarded if provided. Otherwise, the value of the `$request_uri` variable (with the query string stripped) provided by [ngx_http_core_module](https://nginx.org/docs/http/ngx_http_core_module.html#var_server_port) will be used. **Note**: {{site.base_gateway}} returns `"/"` for an empty path, but it doesn't do any other normalization on the request path. | -| All other headers | Forwarded as-is by {{site.base_gateway}} | - - -One exception to this is made when using the WebSocket protocol. {{site.base_gateway}} -sets the following headers to allow for upgrading the protocol between the -client and your upstream services: - -- `Connection: Upgrade` -- `Upgrade: websocket` - -More information on this topic is covered in the -[Proxy WebSocket traffic][proxy-websocket] section. - -### Errors and retries during proxying - -Whenever an error occurs during proxying, {{site.base_gateway}} uses the underlying -Nginx [retries](https://nginx.org/docs/http/ngx_http_proxy_module.html#proxy_next_upstream_tries) mechanism to pass the request on to -the next upstream. - -There are two configurable elements: - -1. The number of retries. This can be configured per Service using the - `retries` property. See the [Admin API][API] for more details on this. - -2. What exactly constitutes an error. Here {{site.base_gateway}} uses the Nginx defaults, which means an error or timeout that occurs while establishing a connection with the server, passing a request to it, or reading the response headers. - -The second option is based on Nginx's -[`proxy_next_upstream`](https://nginx.org/docs/http/ngx_http_proxy_module.html#proxy_next_upstream) directive. This option is not -directly configurable through {{site.base_gateway}}, but can be added using a custom Nginx -configuration. See the [configuration reference][configuration-reference] for -more details. - -### Response streaming - -{{site.base_gateway}} receives the response from the upstream service and sends it back to the -downstream client in a streaming fashion. At this point, {{site.base_gateway}} executes -subsequent plugins added to the route or service that implement a hook in -the `header_filter` phase. - -Once the `header_filter` phase of all registered plugins has been executed, the -following headers are added by {{site.base_gateway}} and the full set of headers is sent to -the client: - -| Header | Description | -|---------------------------------------------|-------------| -| `Via: kong/x.x.x` | `x.x.x` is the {{site.base_gateway}} version in use. | -| `X-Kong-Proxy-Latency: ` | `latency` is the time, in milliseconds, between {{site.base_gateway}} receiving the request from the client and sending the request to your upstream service. | -| `X-Kong-Upstream-Latency: ` | `latency` is the time, in milliseconds, that {{site.base_gateway}} was waiting for the first byte of the upstream service response. | - -Once the headers are sent to the client, {{site.base_gateway}} starts executing -registered plugins for the route or service that implement the -`body_filter` hook. This hook may be called multiple times, due to the -streaming nature of Nginx. Each chunk of the upstream response that is -successfully processed by such `body_filter` hooks is sent back to the client. -You can find more information about the `body_filter` hook in the [Plugin -development guide][plugin-development-guide]. \ No newline at end of file From 5d27dfe2adb59b7c811dfb54b65f7cb1fce7f8c1 Mon Sep 17 00:00:00 2001 From: Diana <75819066+cloudjumpercat@users.noreply.github.com> Date: Mon, 6 Jan 2025 14:35:21 -0600 Subject: [PATCH 27/34] Add proxying ref placeholder page with todo Signed-off-by: Diana <75819066+cloudjumpercat@users.noreply.github.com> --- app/_gateway_entities/route.md | 2 +- app/gateway/traffic-control/proxying.md | 33 +++++++++++++++++++++++++ 2 files changed, 34 insertions(+), 1 deletion(-) create mode 100644 app/gateway/traffic-control/proxying.md diff --git a/app/_gateway_entities/route.md b/app/_gateway_entities/route.md index c56cbe77b..572e93f43 100644 --- a/app/_gateway_entities/route.md +++ b/app/_gateway_entities/route.md @@ -114,7 +114,7 @@ Use the following table to help you understand how Routes can be configured for ## 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](https://docs.konghq.com/gateway/latest/how-kong-works/routing-traffic/). +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: 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 From 3d090cf6fe5d9fdb3ccdc5133fa97f66cc791712 Mon Sep 17 00:00:00 2001 From: Diana <75819066+cloudjumpercat@users.noreply.github.com> Date: Fri, 10 Jan 2025 08:17:23 -0600 Subject: [PATCH 28/34] Apply suggestions from code review Co-authored-by: lena-larionova <54370747+lena-larionova@users.noreply.github.com> --- app/_gateway_entities/route.md | 41 ++++++++++--------- .../routing/expressions-router-reference.md | 8 ++-- app/gateway/routing/expressions.md | 12 ------ 3 files changed, 26 insertions(+), 35 deletions(-) diff --git a/app/_gateway_entities/route.md b/app/_gateway_entities/route.md index 572e93f43..c5569e93e 100644 --- a/app/_gateway_entities/route.md +++ b/app/_gateway_entities/route.md @@ -4,10 +4,11 @@ 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: Gateway Services + - text: Gateway Service entity url: /gateway/entities/service/ - text: Expressions router url: /gateway/routing/expressions/ @@ -29,7 +30,7 @@ schema: ## What is a Route? -{{page.description}} [Gateway Services](/gateway/entities/service/) 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 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. +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. @@ -103,14 +104,14 @@ flowchart LR ## Route use cases -Use the following table to help you understand how Routes can be configured for different use cases: +Common use cases for Routes: | You want to... | Then use... | |--------|----------| -| Rate limit internal and external traffic to a Service | [Enable a rate limiting plugin on Routes attached to the Service](/plugins/rate-limiting-advanced/) | -| Perform a simple URL rewrite, such as renaming your legacy `/api/old/` Upstream endpoint to a publicly accessible API endpoint that is now named `/new/api`. | [Set up a Gateway Service with the old path and a Route with new path](/how-to/rewrite-simple-request-urls-with-routes/) | -| Perform a complex URL rewrite, such as replacing `/api//old` with `/new/api/`. | [Request Transformer Advanced plugin](/plugins/request-transformer-advanced/) | -| Describe Routes or paths as patterns using regular expressions. | [Expressions router](/gateway/routing/expressions/) | +| 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`.

[Set up a Gateway Service with the old path and a Route with new path](/how-to/rewrite-simple-request-urls-with-routes/) | +| 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 @@ -119,15 +120,15 @@ For each incoming request, {{site.base_gateway}} must determine which Service ge 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 and uses the highest priority matching Route to handle a 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}} uses a router to route requests. There are two different routers you can use. Which you should use depends on your use case and {{site.base_gateway}} version: +{{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 recommendations in mind when configuring paths: +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:** Capturing groups are also supported, and the matched group will be extracted from the path and available for plugins consumption. @@ -147,29 +148,29 @@ If multiple Routes match, the {{site.base_gateway}} router then orders all defin In `traditional_compat` mode, the priority of a Route is determined as follows, by the order of descending significance: -1. **Priority points:** For the presence of each of a Route's `methods`, `host`, `headers`, and `snis`, a "priority point" is added. 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, those that have any wildcard host specification will be considered after those that don't have any wildcard host (or no host) specified. +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. -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 in two Routes `A` and `B`, then the following tiebreaker rules will be 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" +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" paths and `B` has only "plain" paths. - * `A`'s longest path is longer than `B`'s longest path. + * `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` #### Expressions router mode -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. +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. ### Routing performance recommendations You can use the following recommendations to increase routing performance: * 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 regular expression with simple prefix 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. +* 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/gateway/routing/expressions-router-reference.md b/app/gateway/routing/expressions-router-reference.md index 5d94e9b95..c85ec561f 100644 --- a/app/gateway/routing/expressions-router-reference.md +++ b/app/gateway/routing/expressions-router-reference.md @@ -1,7 +1,7 @@ --- title: Expressions router reference -description: "The {{site.base_gateway}} [expressions router](/gateway/routing/expressions/) is a rule-based engine that uses a Domain-Specific Expressions Language to define complex routing logic on a [Route](/gateway/entities/route/)." +description: The expressions router is a rule-based engine that uses a Domain-Specific Expressions Language to define complex routing logic on a Route. content_type: reference layout: reference @@ -30,7 +30,9 @@ Reference: - the pieces are explained, but I need something at the front that explains how the things all work together, what does a completed one look like? and then we get into the bits and pieces. --> -{{ page.description }} The expressions router is a collection of Routes that are all evaluated against incoming requests until a match can be found. Each Route contains one or more predicates combined with logical operators, which {{site.base_gateway}} uses to match requests with Routes. +The {{site.base_gateway}} [expressions router](/gateway/routing/expressions/) is a rule-based engine that uses a Domain-Specific Expressions Language to define complex routing logic on a [Route](/gateway/entities/route/). + +A router is a collection of Routes that are all evaluated against incoming requests until a match can be found. Each Route contains one or more predicates combined with logical operators, which {{site.base_gateway}} uses to match requests with Routes. A correctly formatted Route with multiple predicates would look like the following: ```sh @@ -118,7 +120,7 @@ The following table describes the available matching fields, as well as their as | `net.dst.port` | `Int` | ✅ | ✅ | Listening port number where {{site.base_gateway}} accepts the incoming connection. | {% endif_version %} -{% if_version lte:3.4.x %} +{% if_version lte:3.3.x %} | Field | Type | Available in HTTP Subsystem | Available in Stream Subsystem | Description | |------------------------------------------------------|------------|-----------------------------|-------------------------------|-------------| | `net.protocol` | `String` | ✅ | ✅ | 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.prococol` field directly inside the expression. | diff --git a/app/gateway/routing/expressions.md b/app/gateway/routing/expressions.md index 3756e7315..834d2e4d2 100644 --- a/app/gateway/routing/expressions.md +++ b/app/gateway/routing/expressions.md @@ -70,18 +70,6 @@ This predicate example has the following structure: For more information about each unit of the predicate, see the [Expressions router reference](/gateway/routing/expressions-router-reference/). -A correctly formatted Route with multiple predicates would look like the following: -```sh -curl --request POST \ - --url http://localhost:8001/services/example-service/routes \ - --header 'Content-Type: multipart/form-data' \ - --form-string name=complex_object \ - --form-string 'expression=(net.protocol == "http" || net.protocol == "https") && - (http.method == "GET" || http.method == "POST") && - (http.host == "example.com" || http.host == "example.test") && - (http.path ^= "/mock" || http.path ^= "/mocking") && - http.headers.x_another_header == "example_header" && (http.headers.x_my_header == "example" || http.headers.x_my_header == "example2")' -``` ## How requests are routed with the expressions router From 847bb93f90725a1b2e14e3a80d7076ad035cd0b9 Mon Sep 17 00:00:00 2001 From: Diana <75819066+cloudjumpercat@users.noreply.github.com> Date: Fri, 10 Jan 2025 13:26:47 -0600 Subject: [PATCH 29/34] Apply remaining feedback Signed-off-by: Diana <75819066+cloudjumpercat@users.noreply.github.com> --- app/_gateway_entities/route.md | 35 +- ...rewrite-simple-request-urls-with-routes.md | 87 ----- .../routing/expressions-router-reference.md | 298 ------------------ app/gateway/routing/expressions.md | 288 +++++++++++++++-- tools/track-docs-changes/config/sources.yml | 4 - 5 files changed, 274 insertions(+), 438 deletions(-) delete mode 100644 app/_how-tos/rewrite-simple-request-urls-with-routes.md delete mode 100644 app/gateway/routing/expressions-router-reference.md diff --git a/app/_gateway_entities/route.md b/app/_gateway_entities/route.md index c5569e93e..7ebcb51b1 100644 --- a/app/_gateway_entities/route.md +++ b/app/_gateway_entities/route.md @@ -26,6 +26,10 @@ schema: api: gateway/admin-ee path: /schemas/Route +faq: + - 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? @@ -75,28 +79,26 @@ The following diagram illustrates this example: 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 <--requests - responses--> C - F <--requests - responses--> C + B --> B2 --"10 requests + per minute"--> C + F ---> C end - A <--requests - responses--> B - E <--requests - responses--> F - - C <--requests - responses--> D - - B -.->|Rate Limiting plugin| C + C --transformed + and routed + requests--> D style id1 rx:10,ry:10 @@ -109,7 +111,7 @@ Common use cases for Routes: | You want to... | Then use... | |--------|----------| | 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`.

[Set up a Gateway Service with the old path and a Route with new path](/how-to/rewrite-simple-request-urls-with-routes/) | +| 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/) | @@ -131,7 +133,7 @@ If multiple Routes match, {{site.base_gateway}} handles routing in the following 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:** Capturing groups are also supported, and the matched group will be extracted from the path and available for plugins consumption. +* **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) @@ -152,6 +154,7 @@ follows, by the order of descending significance: 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. 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 diff --git a/app/_how-tos/rewrite-simple-request-urls-with-routes.md b/app/_how-tos/rewrite-simple-request-urls-with-routes.md deleted file mode 100644 index 7d50ef87e..000000000 --- a/app/_how-tos/rewrite-simple-request-urls-with-routes.md +++ /dev/null @@ -1,87 +0,0 @@ ---- -title: Rewrite simple request URLs with {{site.base_gateway}} Routes -content_type: how_to -related_resources: - - text: Routes - url: /gateway/entities/route/ - - text: Services - url: /gateway/entities/service/ - - text: Routing in {{site.base_gateway}} - url: /gateway/routing/ - -products: - - gateway - -works_on: - - on-prem - - konnect - -tools: - - deck - -prereqs: - entities: - services: - - example-service - -entities: - - service - - route - -tags: - - routing - - traffic-control - -tldr: - 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. - -faqs: - - q: My URLs are more complex, such as replacing `/api//old` with `/new/api/`, what should I use instead to rewrite them? - a: You can use either the [Request Transformer plugin](/plugins/request-transformer/) or the [expressions router](/gateway/routing/expressions/) for complex URLs. - -cleanup: - inline: - - title: Clean up Konnect environment - include_content: cleanup/platform/konnect - icon_url: /assets/icons/gateway.svg - - title: Destroy the {{site.base_gateway}} container - include_content: cleanup/products/gateway - icon_url: /assets/icons/gateway.svg ---- - -## 1. Set up a Route with the path to the new Upstream - -In the prerequisites, you created the `example-service` pointing to the `/anything` upstream. This path, `/anything`, is your old upstream path. You must create a Route with your new path, `/new-path`, that points to the new Upstream. By doing it this way, traffic can continue to be routed to the old path while you enable the new path. - -{% entity_examples %} -entities: - routes: - - name: new-route - paths: - - "/new-path" - service: - name: example-service -{% endentity_examples %} - -## 2. Apply configuration - -{% include how-tos/steps/apply_config.md %} - -## 3. Validate - -To validate that the URL was successfully rewritten and the request is now being matched to the new Upstream instead of the old one, run the following: - -```bash -curl -i http://localhost:8000/new-path -``` -{: data-deployment-topology="on-prem" } - -```bash -curl -i http://{host}/new-path -``` -{: data-deployment-topology="konnect" } -Replace `{host}` with the proxy URL for this data plane node. -{: data-deployment-topology="konnect" } - -This command should display a 200 status as you're redirected to the new URL. In the response, you'll also see that `"Host": "httpbin.konghq.com",` as the request is proxied to the new URL. \ No newline at end of file diff --git a/app/gateway/routing/expressions-router-reference.md b/app/gateway/routing/expressions-router-reference.md deleted file mode 100644 index c85ec561f..000000000 --- a/app/gateway/routing/expressions-router-reference.md +++ /dev/null @@ -1,298 +0,0 @@ ---- -title: Expressions router reference - -description: The expressions router is a rule-based engine that uses a Domain-Specific Expressions Language to define complex routing logic on a Route. - -content_type: reference -layout: reference - -min_version: - gateway: 3.0 - -products: - - gateway - -related_resources: - - text: Route entity - url: /gateway/entities/route/ - - text: About the expressions router - url: /gateway/routing/expressions/ - - text: Expressions repository - url: https://github.com/Kong/atc-router - -breadcrumbs: - - /gateway/ ---- - - - -The {{site.base_gateway}} [expressions router](/gateway/routing/expressions/) is a rule-based engine that uses a Domain-Specific Expressions Language to define complex routing logic on a [Route](/gateway/entities/route/). - -A router is a collection of Routes that are all evaluated against incoming requests until a match can be found. Each Route contains one or more predicates combined with logical operators, which {{site.base_gateway}} uses to match requests with Routes. - -A correctly formatted Route with multiple predicates would look like the following: -```sh -curl --request POST \ - --url http://localhost:8001/services/example-service/routes \ - --header 'Content-Type: multipart/form-data' \ - --form-string name=complex_object \ - --form-string 'expression=(net.protocol == "http" || net.protocol == "https") && - (http.method == "GET" || http.method == "POST") && - (http.host == "example.com" || http.host == "example.test") && - (http.path ^= "/mock" || http.path ^= "/mocking") && - http.headers.x_another_header == "example_header" && (http.headers.x_my_header == "example" || http.headers.x_my_header == "example2")' -``` - -This reference explains the different configurable entities for the expressions router. - - -## Predicates - -A predicate is the basic unit of expressions code which takes the following form: - -``` -http.path ^= "/foo/bar" -``` - -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: - -| Type | Description | Field type | Constant type | -|----------|----------------------|------------|---------------| -| `String` | 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 | ✅ | ✅ | -| `IpCidr` | 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. | ❌ | ✅ | -| `IpAddr` | 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. | ✅ | ✅ | -| `Int` | 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`. | ✅ | ✅ | -| `Regex` | 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/.+"#` | ❌ | ✅ | - -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. - - - -{% if_version gte:3.4.x %} -| Field | Type | Available in HTTP Subsystem | Available in Stream Subsystem | Description | -|------------------------------------------------------|------------|-----------------------------|-------------------------------|-------------| -| `net.protocol` | `String` | ✅ | ✅ | 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.prococol` field directly inside the expression. | -| `tls.sni` | `String` | ✅ | ✅ | If the connection is over TLS, the `server_name` extension from the ClientHello packet. | -| `http.method` | `String` | ✅ | ❌ | The method of the incoming HTTP request. (for example, `"GET"` or `"POST"`) | -| `http.host` | `String` | ✅ | ❌ | The `Host` header of the incoming HTTP request. | -| `http.path` | `String` | ✅ | ❌ | 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. | -| `http.path.segments.` | `String` | ✅ | ❌ | 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"`. | -| `http.path.segments._` | `String` | ✅ | ❌ | 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"`. | -| `http.path.segments.len` | `Int` | ✅ | ❌ | 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`. | -| `http.headers.` | `String[]` | ✅ | ❌ | 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. | -| `http.queries.` | `String[]` | ✅ | ❌ | The value(s) of query parameter ``. | -| `net.src.ip` | `IpAddr` | ✅ | ✅ | IP address of the client. | -| `net.src.port` | `Int` | ✅ | ✅ | The port number used by the client to connect. | -| `net.dst.ip` | `IpAddr` | ✅ | ✅ | Listening IP address where {{site.base_gateway}} accepts the incoming connection. | -| `net.dst.port` | `Int` | ✅ | ✅ | Listening port number where {{site.base_gateway}} accepts the incoming connection. | -{% endif_version %} - -{% if_version lte:3.3.x %} -| Field | Type | Available in HTTP Subsystem | Available in Stream Subsystem | Description | -|------------------------------------------------------|------------|-----------------------------|-------------------------------|-------------| -| `net.protocol` | `String` | ✅ | ✅ | 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.prococol` field directly inside the expression. | -| `tls.sni` | `String` | ✅ | ✅ | If the connection is over TLS, the `server_name` extension from the ClientHello packet. | -| `http.method` | `String` | ✅ | ❌ | The method of the incoming HTTP request. (for example, `"GET"` or `"POST"`) | -| `http.host` | `String` | ✅ | ❌ | The `Host` header of the incoming HTTP request. | -| `http.path` | `String` | ✅ | ❌ | 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. | -| `http.headers.` | `String[]` | ✅ | ❌ | 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. | -| `http.queries.` | `String[]` | ✅ | ❌ | The value(s) of query parameter ``. | -| `net.src.ip` | `IpAddr` | ❌ | ✅ | IP address of the client. | -| `net.src.port` | `Int` | ❌ | ✅ | The port number used by the client to connect. | -| `net.dst.ip` | `IpAddr` | ❌ | ✅ | Listening IP address where {{site.base_gateway}} accepts the incoming connection. | -| `net.dst.port` | `Int` | ❌ | ✅ | Listening port number where {{site.base_gateway}} accepts the incoming connection. | -{% endif_version %} - -## 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. | - -## Expressions router performance considerations - -Performance is critical when it comes to proxying API traffic. This guide explains how to optimize the -expressions you write to get the most performance out of the routing engine. - -### Number of routes - -#### Route matching priority order - -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. - -The following examples show how you would prioritize two routes based on if they were likely to be matched or not. - -Example route 1: -``` -expression: http.path == "/likely/matched/request/path" -priority: 100 -``` - -Example route 2: -``` -expression: http.path == "/unlikely/matched/request/path" -priority: 50 -``` - -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 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: -``` -service: example-service -expression: http.path == "/hello" -``` - -Example route 2: -``` -service: example-service -expression: http.path == "/world" -``` - -These two routes can instead be combined as: - -``` -service: example-service -expression: http.path == "/hello" || http.path == "/world" -``` - -### Regular expressions usage - -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. - -When performing exact matches (non-prefix matching) of a request path, use the `==` operator -instead of regex. - -**Faster performance example:** -``` -http.path == "/foo/bar" -``` - -**Slower performance example:** -``` -http.path ~ r#"^/foo/bar$"# -``` - -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:** -``` -http.path == "/foo/bar" || http.path == "/foo/bar/" -``` - -**Slower performance example:** -``` -http.path ~ r#"^/foo/?$"# -``` - diff --git a/app/gateway/routing/expressions.md b/app/gateway/routing/expressions.md index 834d2e4d2..c59b63505 100644 --- a/app/gateway/routing/expressions.md +++ b/app/gateway/routing/expressions.md @@ -12,8 +12,6 @@ products: related_resources: - text: Route entity url: /gateway/entities/route/ - - text: Expressions router reference - url: /gateway/routing/expressions-router-reference/ - text: Expressions repository url: https://github.com/Kong/atc-router @@ -26,20 +24,6 @@ breadcrumbs: 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. - - q: How do I enable the expressions router? - a: | - 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. For example: - ```sh - curl --request POST \ - --url http://localhost:8001/services/example-service/routes \ - --header 'Content-Type: multipart/form-data' \ - --form-string name=complex_object \ - --form-string 'expression=(net.protocol == "http" || net.protocol == "https") && - (http.method == "GET" || http.method == "POST") && - (http.host == "example.com" || http.host == "example.test") && - (http.path ^= "/mock" || http.path ^= "/mocking") && - http.headers.x_another_header == "example_header" && (http.headers.x_my_header == "example" || http.headers.x_my_header == "example2")' - ``` --- 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. @@ -53,23 +37,9 @@ You can do the following with the expressions router: * Match by source IP and destination port * Match by SNI (for TLS Routes) -## How expressions are formatted in the expressions router - -To understand how the expressions router routes requests, it's important to how an Route is formatted in expressions. Each Route contains one or more predicates combined with logical operators, which {{site.base_gateway}} uses to match requests with Routes. - -A predicate is the basic unit of expressions code which takes the following form: - -``` -http.path ^= "/foo/bar" -``` - -This predicate example has the following structure: -* `http.path`: Field -* `^=`: Operator -* `"/foo/bar"`: Constant value - -For more information about each unit of the predicate, see the [Expressions router reference](/gateway/routing/expressions-router-reference/). +## 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 @@ -107,4 +77,256 @@ http.post:"konghq.com" The router does the following: 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. \ No newline at end of file +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. + +## Performance considerations + +This section explains how to optimize the expressions you write to get the most performance out of the routing engine. + +### Number of routes + +#### Route matching priority order + +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. + +The following examples show how you would prioritize two routes based on if they were likely to be matched or not. + +Example route 1: +``` +expression: http.path == "/likely/matched/request/path" +priority: 100 +``` + +Example route 2: +``` +expression: http.path == "/unlikely/matched/request/path" +priority: 50 +``` + +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 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: +``` +service: example-service +expression: http.path == "/hello" +``` + +Example route 2: +``` +service: example-service +expression: http.path == "/world" +``` + +These two routes can instead be combined as: + +``` +service: example-service +expression: http.path == "/hello" || http.path == "/world" +``` + +### Regular expressions usage + +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. + +When performing exact matches (non-prefix matching) of a request path, use the `==` operator +instead of regex. + +**Faster performance example:** +``` +http.path == "/foo/bar" +``` + +**Slower performance example:** +``` +http.path ~ r#"^/foo/bar$"# +``` + +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:** +``` +http.path == "/foo/bar" || http.path == "/foo/bar/" +``` + +**Slower performance example:** +``` +http.path ~ r#"^/foo/?$"# +``` + +## Expressions router reference + +This reference explains the different configurable entities for the expressions router. + +### Expressions formatting + +Each Route contains one or more predicates combined with logical operators, which {{site.base_gateway}} uses to match requests with Routes. + +A predicate is the basic unit of expressions code which takes the following form: + +``` +http.path ^= "/foo/bar" +``` + +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: + +| Type | Description | Field type | Constant type | +|----------|----------------------|------------|---------------| +| `String` | 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 | ✅ | ✅ | +| `IpCidr` | 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. | ❌ | ✅ | +| `IpAddr` | 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. | ✅ | ✅ | +| `Int` | 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`. | ✅ | ✅ | +| `Regex` | 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/.+"#` | ❌ | ✅ | + +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. + + + +{% if_version gte:3.4.x %} +| Field | Type | Available in HTTP Subsystem | Available in Stream Subsystem | Description | +|------------------------------------------------------|------------|-----------------------------|-------------------------------|-------------| +| `net.protocol` | `String` | ✅ | ✅ | 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.prococol` field directly inside the expression. | +| `tls.sni` | `String` | ✅ | ✅ | If the connection is over TLS, the `server_name` extension from the ClientHello packet. | +| `http.method` | `String` | ✅ | ❌ | The method of the incoming HTTP request. (for example, `"GET"` or `"POST"`) | +| `http.host` | `String` | ✅ | ❌ | The `Host` header of the incoming HTTP request. | +| `http.path` | `String` | ✅ | ❌ | 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. | +| `http.path.segments.` | `String` | ✅ | ❌ | 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"`. | +| `http.path.segments._` | `String` | ✅ | ❌ | 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"`. | +| `http.path.segments.len` | `Int` | ✅ | ❌ | 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`. | +| `http.headers.` | `String[]` | ✅ | ❌ | 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. | +| `http.queries.` | `String[]` | ✅ | ❌ | The value(s) of query parameter ``. | +| `net.src.ip` | `IpAddr` | ✅ | ✅ | IP address of the client. | +| `net.src.port` | `Int` | ✅ | ✅ | The port number used by the client to connect. | +| `net.dst.ip` | `IpAddr` | ✅ | ✅ | Listening IP address where {{site.base_gateway}} accepts the incoming connection. | +| `net.dst.port` | `Int` | ✅ | ✅ | Listening port number where {{site.base_gateway}} accepts the incoming connection. | +{% endif_version %} + +{% if_version lte:3.3.x %} +| Field | Type | Available in HTTP Subsystem | Available in Stream Subsystem | Description | +|------------------------------------------------------|------------|-----------------------------|-------------------------------|-------------| +| `net.protocol` | `String` | ✅ | ✅ | 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.prococol` field directly inside the expression. | +| `tls.sni` | `String` | ✅ | ✅ | If the connection is over TLS, the `server_name` extension from the ClientHello packet. | +| `http.method` | `String` | ✅ | ❌ | The method of the incoming HTTP request. (for example, `"GET"` or `"POST"`) | +| `http.host` | `String` | ✅ | ❌ | The `Host` header of the incoming HTTP request. | +| `http.path` | `String` | ✅ | ❌ | 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. | +| `http.headers.` | `String[]` | ✅ | ❌ | 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. | +| `http.queries.` | `String[]` | ✅ | ❌ | The value(s) of query parameter ``. | +| `net.src.ip` | `IpAddr` | ❌ | ✅ | IP address of the client. | +| `net.src.port` | `Int` | ❌ | ✅ | The port number used by the client to connect. | +| `net.dst.ip` | `IpAddr` | ❌ | ✅ | Listening IP address where {{site.base_gateway}} accepts the incoming connection. | +| `net.dst.port` | `Int` | ❌ | ✅ | Listening port number where {{site.base_gateway}} accepts the incoming connection. | +{% endif_version %} + +### 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/tools/track-docs-changes/config/sources.yml b/tools/track-docs-changes/config/sources.yml index d39fe040d..e062ef0ad 100644 --- a/tools/track-docs-changes/config/sources.yml +++ b/tools/track-docs-changes/config/sources.yml @@ -78,8 +78,6 @@ app/_how-tos/get-started-with-gateway.md: - app/_src/gateway/get-started/proxy-caching.md - app/_src/gateway/get-started/key-authentication.md - app/_src/gateway/get-started/load-balancing.md -app/_how-tos/dynamically-rewrite-simple-request-urls-with-routes.md: - - app/_src/gateway/key-concepts/routes/index.md app/_how-tos/set-up-ai-proxy-advanced-with-anthropic.md: - app/_hub/kong-inc/ai-proxy-advanced/how-to/llm-provider-integration-guides/_anthropic.md app/_how-tos/set-up-ai-proxy-with-anthropic.md: @@ -154,8 +152,6 @@ app/gateway/traffic-control/proxy.md: app/gateway/routing/expressions.md: - app/_src/gateway/reference/expressions-language/index.md - app/_src/gateway/key-concepts/routes/expressions.md -app/gateway/routing/expressions-router-reference.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: From e0b7bc2782674723f6f7303e01a5f4355923f2d2 Mon Sep 17 00:00:00 2001 From: Diana <75819066+cloudjumpercat@users.noreply.github.com> Date: Fri, 10 Jan 2025 15:03:52 -0600 Subject: [PATCH 30/34] Apply new feature table formatting Signed-off-by: Diana <75819066+cloudjumpercat@users.noreply.github.com> --- app/gateway/routing/expressions.md | 200 ++++++++++++++++++++++------- 1 file changed, 157 insertions(+), 43 deletions(-) diff --git a/app/gateway/routing/expressions.md b/app/gateway/routing/expressions.md index c59b63505..f62df90c6 100644 --- a/app/gateway/routing/expressions.md +++ b/app/gateway/routing/expressions.md @@ -205,13 +205,49 @@ if the operator cannot be performed on the provided field and constant. The expressions language currently supports the following types: -| Type | Description | Field type | Constant type | -|----------|----------------------|------------|---------------| -| `String` | 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 | ✅ | ✅ | -| `IpCidr` | 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. | ❌ | ✅ | -| `IpAddr` | 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. | ✅ | ✅ | -| `Int` | 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`. | ✅ | ✅ | -| `Regex` | 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/.+"#` | ❌ | ✅ | + +{% 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. 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 @@ -221,42 +257,120 @@ case one field could contain multiple values. For example, `http.headers.x` or ` The following table describes the available matching fields, as well as their associated type when using an expressions based router. - - -{% if_version gte:3.4.x %} -| Field | Type | Available in HTTP Subsystem | Available in Stream Subsystem | Description | -|------------------------------------------------------|------------|-----------------------------|-------------------------------|-------------| -| `net.protocol` | `String` | ✅ | ✅ | 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.prococol` field directly inside the expression. | -| `tls.sni` | `String` | ✅ | ✅ | If the connection is over TLS, the `server_name` extension from the ClientHello packet. | -| `http.method` | `String` | ✅ | ❌ | The method of the incoming HTTP request. (for example, `"GET"` or `"POST"`) | -| `http.host` | `String` | ✅ | ❌ | The `Host` header of the incoming HTTP request. | -| `http.path` | `String` | ✅ | ❌ | 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. | -| `http.path.segments.` | `String` | ✅ | ❌ | 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"`. | -| `http.path.segments._` | `String` | ✅ | ❌ | 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"`. | -| `http.path.segments.len` | `Int` | ✅ | ❌ | 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`. | -| `http.headers.` | `String[]` | ✅ | ❌ | 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. | -| `http.queries.` | `String[]` | ✅ | ❌ | The value(s) of query parameter ``. | -| `net.src.ip` | `IpAddr` | ✅ | ✅ | IP address of the client. | -| `net.src.port` | `Int` | ✅ | ✅ | The port number used by the client to connect. | -| `net.dst.ip` | `IpAddr` | ✅ | ✅ | Listening IP address where {{site.base_gateway}} accepts the incoming connection. | -| `net.dst.port` | `Int` | ✅ | ✅ | Listening port number where {{site.base_gateway}} accepts the incoming connection. | -{% endif_version %} - -{% if_version lte:3.3.x %} -| Field | Type | Available in HTTP Subsystem | Available in Stream Subsystem | Description | -|------------------------------------------------------|------------|-----------------------------|-------------------------------|-------------| -| `net.protocol` | `String` | ✅ | ✅ | 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.prococol` field directly inside the expression. | -| `tls.sni` | `String` | ✅ | ✅ | If the connection is over TLS, the `server_name` extension from the ClientHello packet. | -| `http.method` | `String` | ✅ | ❌ | The method of the incoming HTTP request. (for example, `"GET"` or `"POST"`) | -| `http.host` | `String` | ✅ | ❌ | The `Host` header of the incoming HTTP request. | -| `http.path` | `String` | ✅ | ❌ | 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. | -| `http.headers.` | `String[]` | ✅ | ❌ | 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. | -| `http.queries.` | `String[]` | ✅ | ❌ | The value(s) of query parameter ``. | -| `net.src.ip` | `IpAddr` | ❌ | ✅ | IP address of the client. | -| `net.src.port` | `Int` | ❌ | ✅ | The port number used by the client to connect. | -| `net.dst.ip` | `IpAddr` | ❌ | ✅ | Listening IP address where {{site.base_gateway}} accepts the incoming connection. | -| `net.dst.port` | `Int` | ❌ | ✅ | Listening port number where {{site.base_gateway}} accepts the incoming connection. | -{% endif_version %} + +{% 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.prococol 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. 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 <header_name>. 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 <query_parameter_name>. + - 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 From d03b20d6bb888ed97a689a266fc947bd70f11cde Mon Sep 17 00:00:00 2001 From: Diana <75819066+cloudjumpercat@users.noreply.github.com> Date: Fri, 10 Jan 2025 15:32:49 -0600 Subject: [PATCH 31/34] Fix feature table formatting Signed-off-by: Diana <75819066+cloudjumpercat@users.noreply.github.com> --- app/_includes/components/feature_table.html | 2 +- app/gateway/routing/expressions.md | 36 ++++++++++++--------- 2 files changed, 21 insertions(+), 17 deletions(-) diff --git a/app/_includes/components/feature_table.html b/app/_includes/components/feature_table.html index a566f0edf..564e8f005 100644 --- a/app/_includes/components/feature_table.html +++ b/app/_includes/components/feature_table.html @@ -32,7 +32,7 @@ {% elsif v == false %} {% include icon_false.html %} {% else %} - {{v}} + {{v | liquify | markdown}} {% endif %} {% endfor %} diff --git a/app/gateway/routing/expressions.md b/app/gateway/routing/expressions.md index f62df90c6..730fecc2f 100644 --- a/app/gateway/routing/expressions.md +++ b/app/gateway/routing/expressions.md @@ -219,31 +219,36 @@ 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 + 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. + 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. + 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. + 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. For example, in the following predicate, the constant is parsed as a regex: http.path ~ r#"/foo/bar/.+"# + 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 %} @@ -276,70 +281,70 @@ features: 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.prococol field directly inside the expression. + 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. + 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") + 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. + 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. This field value does not contain any query parameters that might exist. + 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". + 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". + 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. + 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 <header_name>. 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. + 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 <query_parameter_name>. + The value(s) of query parameter ``. - title: | `net.src.ip` type: IpAddr @@ -371,7 +376,6 @@ features: {% 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. From e6e72cfc89b8aae98f5d7f940946365e83499051 Mon Sep 17 00:00:00 2001 From: lena-larionova <54370747+lena-larionova@users.noreply.github.com> Date: Fri, 10 Jan 2025 13:48:39 -0800 Subject: [PATCH 32/34] Apply suggestions from code review --- app/_gateway_entities/route.md | 2 +- app/gateway/routing/expressions.md | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/app/_gateway_entities/route.md b/app/_gateway_entities/route.md index 7ebcb51b1..bf44a4057 100644 --- a/app/_gateway_entities/route.md +++ b/app/_gateway_entities/route.md @@ -108,7 +108,7 @@ flowchart LR Common use cases for Routes: -| You want to... | Then use... | +| 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`. | diff --git a/app/gateway/routing/expressions.md b/app/gateway/routing/expressions.md index 730fecc2f..9a12216b4 100644 --- a/app/gateway/routing/expressions.md +++ b/app/gateway/routing/expressions.md @@ -205,6 +205,7 @@ 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 @@ -253,6 +254,8 @@ features: 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 @@ -262,6 +265,7 @@ case one field could contain multiple values. For example, `http.headers.x` or ` 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 @@ -375,6 +379,7 @@ features: Listening port number where {{site.base_gateway}} accepts the incoming connection. {% endfeature_table %} + ### Operators From 446ab46d9f64068785792f5a45d34886277b6151 Mon Sep 17 00:00:00 2001 From: lena-larionova Date: Fri, 10 Jan 2025 13:53:25 -0800 Subject: [PATCH 33/34] fix centering issue in feature tables --- app/_includes/components/feature_table.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/_includes/components/feature_table.html b/app/_includes/components/feature_table.html index 564e8f005..0d82b2797 100644 --- a/app/_includes/components/feature_table.html +++ b/app/_includes/components/feature_table.html @@ -26,7 +26,7 @@ {% for column in include.columns %} {% assign v = row[column.key] %} - + {% if v == true %} {% include icon_true.html %} {% elsif v == false %} From d9cc8f69348bf01dfe13fafa231861279cf5c4ee Mon Sep 17 00:00:00 2001 From: lena-larionova <54370747+lena-larionova@users.noreply.github.com> Date: Fri, 10 Jan 2025 14:00:35 -0800 Subject: [PATCH 34/34] fix faqs key --- app/_gateway_entities/route.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/_gateway_entities/route.md b/app/_gateway_entities/route.md index bf44a4057..69d918e4f 100644 --- a/app/_gateway_entities/route.md +++ b/app/_gateway_entities/route.md @@ -26,7 +26,7 @@ schema: api: gateway/admin-ee path: /schemas/Route -faq: +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.