diff --git a/src/content/docs/rules/snippets/examples/custom-cache.mdx b/src/content/docs/rules/snippets/examples/custom-cache.mdx new file mode 100644 index 00000000000000..a38df5964988bf --- /dev/null +++ b/src/content/docs/rules/snippets/examples/custom-cache.mdx @@ -0,0 +1,100 @@ +--- +type: example +summary: Control cache programmatically. Use this template to optimize performance and implement custom caching strategies. +goal: + - Other +operation: + - Cache +products: + - Snippets +pcx_content_type: example +title: Custom cache +description: Store, retrieve, and remove assets from cache programmatically. Use this template to optimize performance and implement custom caching strategies. +--- + +```js +// Define configurable cache duration in seconds (default: 30 days) +const CACHE_DURATION_SECONDS = 30 * 24 * 60 * 60; + +// Define which parts of the request to include in the cache key +const USE_PATH = true; // Include path in the cache key +const USE_QUERY_STRING = true; // Include query string in the cache key +const INCLUDE_HEADERS = ["User-Agent"]; // Headers to include in the cache key + +export default { + async fetch(request, env, ctx) { + // Generate a custom cache key based on user preferences + const cacheKey = createCacheKey(request); + console.log(`Retrieving cache for: ${cacheKey.url}.`) + + // Access the default Cache API + const cache = caches.default; + + // Attempt to retrieve the cached response + let response = await cache.match(cacheKey); + + if (!response) { + // Cache miss: Fetch the asset from the origin + console.log(`Cache miss for: ${cacheKey.url}. Fetching from origin...`); + response = await fetch(request); + + // Wrap the origin response for caching + response = new Response(response.body, response); + + // Set Cache-Control headers to define the TTL + response.headers.set("Cache-Control", `s-maxage=${CACHE_DURATION_SECONDS}`); + response.headers.set("x-snippets-cache", "stored"); + + // Store the response in the cache + await cache.put(cacheKey, response.clone()); + } else { + // Cache hit: Return the cached response + console.log(`Cache hit for: ${cacheKey.url}.`); + response = new Response(response.body, response); + response.headers.set("x-snippets-cache", "hit"); + + // Optionally check if the cache should expire based on age + const ageHeader = response.headers.get("Age"); + if (ageHeader && parseInt(ageHeader, 10) > CACHE_DURATION_SECONDS) { + console.log(`Cache expired for: ${cacheKey.url}. Deleting cached response...`); + await cache.delete(cacheKey); + response.headers.set("x-snippets-cache", "deleted"); + } + } + + // Return the response to the client + return response; + }, +}; + +/** + * Function to create a custom cache key based on request properties + * @param {Request} request - The incoming request object + * @returns {Request} - A valid cache key based on the URL + */ +function createCacheKey(request) { + const url = new URL(request.url); // Use the request's base URL + const cacheKey = new URL(url.origin); // Start with the origin (scheme + hostname) + + // Optionally include the path + if (USE_PATH) { + cacheKey.pathname = url.pathname; + } + + // Optionally include the query string + if (USE_QUERY_STRING) { + cacheKey.search = url.search; + } + + // Optionally include specific headers + if (INCLUDE_HEADERS.length > 0) { + const headerParts = INCLUDE_HEADERS.map(header => `${header}=${request.headers.get(header) || ""}`).join("&"); + cacheKey.searchParams.append("headers", headerParts); + } + + // Return the constructed URL as the cache key + return new Request(cacheKey.toString(), { + method: "GET" + }); +} +``` diff --git a/src/content/docs/rules/snippets/examples/hex-timestamp.mdx b/src/content/docs/rules/snippets/examples/hex-timestamp.mdx new file mode 100644 index 00000000000000..f985c281d081bc --- /dev/null +++ b/src/content/docs/rules/snippets/examples/hex-timestamp.mdx @@ -0,0 +1,39 @@ +--- +type: example +summary: Add a custom header to requests sent to the origin server with the current timestamp in hexadecimal format. +goal: + - Manage headers +operation: + - Request modification +products: + - Snippets +pcx_content_type: example +title: Add HEX timestamp to a request header +description: Add a custom header to requests sent to the origin server with the current timestamp in hexadecimal format for debugging, tracking, or custom routing purposes. +--- + +```js +export default { + async fetch(request) { + // Get the current timestamp + const timestamp = Date.now(); + + // Convert the timestamp to hexadecimal format + const hexTimestamp = timestamp.toString(16); + + // Clone the request and add the custom header + const modifiedRequest = new Request(request, { + headers: new Headers(request.headers) + }); + modifiedRequest.headers.set("X-Hex-Timestamp", hexTimestamp); + + // Log the custom header for debugging + console.log(`X-Hex-Timestamp: ${hexTimestamp}`); + + // Pass the modified request to the origin + const response = await fetch(modifiedRequest); + + return response; + }, +}; +``` \ No newline at end of file diff --git a/src/content/docs/rules/snippets/examples/maintenance.mdx b/src/content/docs/rules/snippets/examples/maintenance.mdx new file mode 100644 index 00000000000000..eacba1ec4e915f --- /dev/null +++ b/src/content/docs/rules/snippets/examples/maintenance.mdx @@ -0,0 +1,102 @@ +--- +type: example +summary: Serve a custom maintenance page. Ideal for downtime notifications, planned maintenance, or emergency messages. +goal: + - Routing +operation: + - Redirect +products: + - Snippets +pcx_content_type: example +title: Maintenance page +description: Serve a custom maintenance page instead of fetching content from the origin server or cache. Ideal for downtime notifications, planned maintenance, or emergency messages. +--- + +```js +// Define your customizable inputs +const title = "We'll Be Right Back!"; +const message = "Our site is currently undergoing scheduled maintenance. We’re working hard to bring you a better experience. Thank you for your patience and understanding."; +const estimatedTime = "1 hour"; +const contactEmail = "support@example.com"; +const contactPhone = "+1 234 567 89"; + +export default { + async fetch(request) { + // Serve the maintenance page as a response + return new Response(generateMaintenancePage(), { + headers: { "Content-Type": "text/html" }, + }); + }, +}; + +function generateMaintenancePage() { + return ` + + + + + + ${title} + + + +
+

${title}

+

${message}

+

If all goes to plan, we'll be back online in ${estimatedTime}. 🚀

+

+ Need help? Reach out to us at ${contactEmail} + or call us at ${contactPhone}. +

+
+ + + `; +} +``` diff --git a/src/content/docs/rules/snippets/examples/redirect-forbidden-status.mdx b/src/content/docs/rules/snippets/examples/redirect-forbidden-status.mdx index 21fe7d33bd08b1..d4b8c1808aa2f4 100644 --- a/src/content/docs/rules/snippets/examples/redirect-forbidden-status.mdx +++ b/src/content/docs/rules/snippets/examples/redirect-forbidden-status.mdx @@ -9,7 +9,7 @@ operation: products: - Snippets pcx_content_type: example -title: Redirect `403 Forbidden` to a different page +title: Redirect 403 Forbidden to a different page description: If origin responded with `403 Forbidden` error code, redirect to different page. --- diff --git a/src/content/docs/rules/snippets/examples/rewrite-site-links.mdx b/src/content/docs/rules/snippets/examples/rewrite-site-links.mdx new file mode 100644 index 00000000000000..78a7063352ccc0 --- /dev/null +++ b/src/content/docs/rules/snippets/examples/rewrite-site-links.mdx @@ -0,0 +1,54 @@ +--- +type: example +summary: Dynamically rewrite links in HTML responses. +goal: + - Other +operation: + - Response modification +products: + - Snippets +pcx_content_type: example +title: Rewrite links on HTML pages +description: Dynamically rewrite links in HTML responses. This is useful for site migrations and branding updates. +--- + +```js +export default { + async fetch(request) { + // Define the old hostname here. + const OLD_URL = "oldsite.com"; + // Then add your new hostname that should replace the old one. + const NEW_URL = "newsite.com"; + + class AttributeRewriter { + constructor(attributeName) { + this.attributeName = attributeName; + } + element(element) { + const attribute = element.getAttribute(this.attributeName); + if (attribute) { + element.setAttribute( + this.attributeName, + attribute.replace(OLD_URL, NEW_URL), + ); + } + } + } + + const rewriter = new HTMLRewriter() + .on("a", new AttributeRewriter("href")) + .on("img", new AttributeRewriter("src")); + + const res = await fetch(request); + const contentType = res.headers.get("Content-Type"); + + // If the response is HTML, it can be transformed with + // HTMLRewriter -- otherwise, it should pass through + if (contentType.startsWith("text/html")) { + return rewriter.transform(res); + } else { + return res; + } + }, +}; +``` \ No newline at end of file diff --git a/src/content/docs/rules/transform/examples/rewrite-moved-section.mdx b/src/content/docs/rules/transform/examples/rewrite-moved-section.mdx index e936abc947db0d..41d6c1672a94a6 100644 --- a/src/content/docs/rules/transform/examples/rewrite-moved-section.mdx +++ b/src/content/docs/rules/transform/examples/rewrite-moved-section.mdx @@ -13,22 +13,19 @@ description: Create a rewrite URL rule (part of Transform Rules) to rewrite import { Example } from "~/components"; -To rewrite everything under `/blog/` to `/marketing/` you must modify the first component of the path (`/blog/`). Create a rewrite URL rule and use the [`regex_replace()`](/ruleset-engine/rules-language/functions/#regex_replace) function for this purpose: +To rewrite everything under `/blog/` to `/marketing/`, create a new rewrite URL rule and define a dynamic URL path rewrite using [wildcard pattern parameters](/rules/transform/url-rewrite/create-dashboard/#wildcard-pattern-parameters): -Text in **Expression Editor**: +**When incoming requests match** -```txt -starts_with(http.request.uri.path, "/blog/") -``` +- **Wildcard pattern** + - **Request URL**: `https:///blog/*` -Text after **Path** > **Rewrite to...** > _Dynamic_: - -```txt -regex_replace(http.request.uri.path, "^/blog/", "/marketing/") -``` +**Then rewrite the path and/or query** +- **Target path**: `/blog/*` +- **Rewrite to**: `/marketing/${1}` -The `regex_replace()` function matches the path component on a regular expression (`^/blog/`) and then provides a replacement for that match (`/marketing/`). +Make sure to replace `` with your actual hostname and adjust the example paths according to your setup. \ No newline at end of file diff --git a/src/content/docs/rules/transform/examples/rewrite-path-archived-posts.mdx b/src/content/docs/rules/transform/examples/rewrite-path-archived-posts.mdx index 918f319f9b6f01..3111e09025af89 100644 --- a/src/content/docs/rules/transform/examples/rewrite-path-archived-posts.mdx +++ b/src/content/docs/rules/transform/examples/rewrite-path-archived-posts.mdx @@ -13,22 +13,19 @@ description: Create a rewrite URL rule (part of Transform Rules) to rewrite any import { Example } from "~/components"; -To rewrite all requests to `/news/2012/...` to `/archive/news/2012/...` you must add a reference to the content of the original URL. Create a new rewrite URL rule and define a dynamic URL path rewrite using an expression: +To rewrite all requests to `/news/2012/...` to `/archive/news/2012/...` you must add a reference to the content of the original URL. Create a new rewrite URL rule and define a dynamic URL path rewrite using [wildcard pattern parameters](/rules/transform/url-rewrite/create-dashboard/#wildcard-pattern-parameters): -Text in **Expression Editor**: +**When incoming requests match** -```txt -starts_with(http.request.uri.path, "/news/2012/") -``` +- **Wildcard pattern** + - **Request URL**: `https:///news/2012/*` -Text after **Path** > **Rewrite to...** > _Dynamic_: - -```txt -concat("/archive", http.request.uri.path) -``` +**Then rewrite the path and/or query** +- **Target path**: `/news/2012/*` +- **Rewrite to**: `/archive/news/2012/${1}` -The filter uses the [`starts_with()`](/ruleset-engine/rules-language/functions/#starts_with) function all paths starting with `/news/2012/`. The dynamic path rewrite uses the [`concat()`](/ruleset-engine/rules-language/functions/#concat) function to concatenate a prefix to the original URL path of the HTTP request. +Make sure to replace `` with your actual hostname and adjust the example paths according to your setup. \ No newline at end of file diff --git a/src/content/docs/rules/transform/examples/rewrite-path-object-storage.mdx b/src/content/docs/rules/transform/examples/rewrite-path-object-storage.mdx new file mode 100644 index 00000000000000..babe5d640833a2 --- /dev/null +++ b/src/content/docs/rules/transform/examples/rewrite-path-object-storage.mdx @@ -0,0 +1,32 @@ +--- +pcx_content_type: example +summary: Create a rewrite URL rule (part of Transform Rules) to remove + `/files/` from URI paths before routing request to your object storage bucket. +products: + - Transform Rules +operation: + - Rewrite URL +title: Rewrite path for object storage bucket +description: Create a rewrite URL rule (part of Transform Rules) to rewrite any + requests for `/files/...` URI paths to `/...`. +--- + +import { Example } from "~/components"; + +To remove `/files/` from URI paths before routing request to your object storage bucket, create a new rewrite URL rule and define a dynamic URL path rewrite using [wildcard pattern parameters](/rules/transform/url-rewrite/create-dashboard/#wildcard-pattern-parameters): + + + +**When incoming requests match** + +- **Wildcard pattern** + - **Request URL**: `https:///files/*` + +**Then rewrite the path and/or query** +- **Target path**: `/files/*` +- **Rewrite to**: `/${1}` + + + +Make sure to replace `` with your actual hostname and adjust the example paths according to your setup. +Then, use [Cloud Connector](/rules/cloud-connector/) to route traffic to an object storage bucket. \ No newline at end of file