Redirect Logic and Flow
Relevant source files
The following files were used as context for generating this wiki page:The core function of gr8hopper is to provide a lightweight, high-performance URL redirection service. It is designed to handle complex, parameter-driven routing logic, allowing dynamic rewriting of URLs based on query parameters and path segments. This system is built to be deployed on edge platforms like Cloudflare Workers for minimal latency or as a standalone service on any VPS.
The redirect logic is centralized, stateless, and prioritizes performance through aggressive caching. It supports simple key-based lookups, powerful path-based pattern matching, and flexible template substitution to construct the final destination URL.
Sources: README.md:10-16, src/handlers/redirect.ts
High-Level Request Flow
An incoming request is handled by the main application entry point, which can be either for Cloudflare Workers (src/index.ts) or a Node.js server (src/server.ts). The entry point initializes the storage adapter and routes the request to the appropriate handler. All non-admin requests are forwarded to the redirectHandler.
Sources: src/index.ts:25-30, 83-85, src/server.ts:133-136
The following diagram shows the sequence of events for a typical redirect request.
This diagram illustrates the caching-first approach described in the project documentation.
Sources: README.md:83-107, src/handlers/redirect.ts:271-348
Route Matching Logic
The system attempts to find a matching route in a specific order of precedence. The first active route found is used.
Sources: src/handlers/redirect.ts:271-348
This flowchart shows the prioritized logic for resolving a redirect request.
1. Query Parameter Match
The system first checks for a route identifier in a specific query parameter. The name of this parameter is defined in the global settings (route_param), which defaults to r.
- Example:
https://your-domain.com/?r=my-route&id=123 - The system will look for a route with the ID
my-route.
If a route is found via this method, the system immediately proceeds to build the redirect and does not attempt path matching.
Sources: src/handlers/redirect.ts:275-284, README.md:200-206
2. Path Match (Exact & Pattern)
If no route is identified via the query parameter, the system attempts to match the request's URL path.
Sources: src/handlers/redirect.ts:287-348
Exact Match
The system first attempts to find a route whose ID is an exact match for the sanitized request path.
- Example: A request to
https://your-domain.com/exact-matchwill look for a route with the IDexact-match.
Sources: src/handlers/redirect.ts:295-302
Pattern Match
If no exact match is found, the system evaluates a cached list of pattern routes. These routes use special tokens to capture parts of the URL.
- Patterns are sorted by specificity to ensure the most precise match is evaluated first. The scoring is determined by the
getPatternScorefunction. - The first active pattern that matches the request path and query parameters is used.
Sources: src/handlers/redirect.ts:305-348, README.md:148-164
The supported pattern tokens are:
| Token | Description | Example Pattern | Matches |
|---|---|---|---|
:param | Required path parameter. | shop/:category/:id | /shop/shoes/42 |
{param} | Required path parameter (alternative syntax). | shop/{category} | /shop/shoes |
{param?} | Optional path parameter. | blog/{year?}/{slug} | /blog/2024/post or /blog/post |
* | Wildcard for exactly one path segment. | */details/* | /shoes/details/42 |
** | Globstar for zero or more path segments. | files/** | /files/a/b/c |
?key={val} | Query parameter match. | product/{id}?lang={lang} | /product/123?lang=en |
Sources: README.md:149-164, src/handlers/redirect.ts:311-340
3. Fallback Handling
If no route is found after all matching attempts, the request is redirected to the fallback_url defined in the global settings.
- The default
fallback_urlis/not-found. - Placeholders in the
fallback_urlcan be substituted with query parameters from the original request. - Fallback redirects are cached for a shorter duration (max 30 minutes) to allow newly created routes to become effective more quickly.
Sources: src/handlers/redirect.ts:370-415, README.md:195-197
Template Substitution
Once a route is matched, its template URL is used to construct the final destination. The template can contain placeholders in the format {placeholder} which are replaced with values from the request.
Sources: src/handlers/redirect.ts:13-22, README.md:136-146
| Placeholder | Source | Example |
|---|---|---|
{route} | The matched Route ID (URL-encoded). | my-route |
{anyParam} | Value from a URL query parameter (?anyParam=value). | ?id=123 provides value for {id}. |
{param} | Value from a captured path parameter in a pattern route. | Route shop/:category with path /shop/shoes provides value for {category}. |
Sources: README.md:139-146, src/handlers/redirect.ts:205-212
The substitution logic is implemented in the substituteTemplate function. If a parameter for a placeholder is not found in the request, the placeholder is left as-is in the final URL (e.g., {id} remains {id}).
Sources: src/handlers/redirect.ts:13-22
Query Parameter Passthrough
If a route has passthrough: true, query parameters from the source URL (like utm_ tags) are automatically appended to the destination URL.
This logic is handled by the mergePassthroughParams function and follows these rules:
- Parameters explicitly defined in the destination
templatetake precedence. - The
route_param(e.g.,r) is always excluded. - Parameters captured by a pattern route (e.g.,
idinproduct/{id}) are excluded. - All other source query parameters are appended to the destination URL.
Sources: src/handlers/redirect.ts:130-192, README.md:183-220
The following diagram illustrates the passthrough decision logic:
Sources: src/handlers/redirect.ts:175-185
URL Protocol & Security
To ensure valid and secure redirects, all destination URLs are processed by the ensureProtocol function.
- It blocks dangerous schemes like
javascript:,data:, andfile:. - If a URL has no protocol but looks like a domain (e.g.,
example.com/path), it prependshttps://. - It leaves absolute paths (e.g.,
/some/page) and relative paths untouched for the browser to resolve. - Protocol-relative URLs (e.g.,
//example.com) are blocked for security.
Sources: src/handlers/redirect.ts:29-106, SECURITY.md:52-54
Caching
Performance is achieved through aggressive caching. The buildCacheHeaders function generates the necessary headers.
Cache-Control:public, max-age=...tells browsers and intermediate caches to store the redirect. The default TTL is604800seconds (1 week).CDN-Cache-Control: A separate header for CDNs, typically with a much longer TTL (7x the browser TTL by default). This ensures subsequent requests are served from the edge without invoking the application logic.
This strategy means that for any unique URL, the application logic runs only once, and all subsequent requests are served from a cache.
Sources: src/handlers/redirect.ts:197-202, README.md:270-282