### Configure C++ Example Build with CMake Source: https://github.com/fastly/compute-sdk-cpp/blob/main/examples/CMakeLists.txt This CMake script sets up the build environment for a C++ example. It defines the project name, executable, compiler flags, and optimization settings. It also handles the output file suffix and includes necessary directories and libraries for the Fastly Compute SDK. ```cmake cmake_minimum_required(VERSION 3.15) if(!EXAMPLE_NAME) set(EXAMPLE_NAME "echo") endif() if (CMAKE_BUILD_TYPE STREQUAL "Debug") set(TARGET_DIR "debug") else () set(TARGET_DIR "release") endif () project(cxx_example) add_link_options(-L${WASI_SDK_PREFIX}/share/wasi-sysroot/lib/wasm32-wasi) add_subdirectory(.. ../../target) add_executable(${EXAMPLE_NAME} ${EXAMPLE_NAME}.cpp) target_compile_options(${EXAMPLE_NAME} PRIVATE -Wall -Wextra -Werror -fno-exceptions) option(ENABLE_LTO "Enable cross language linking time optimization" OFF) if(ENABLE_LTO) include(CheckIPOSupported) check_ipo_supported(RESULT supported OUTPUT error) if(supported) message(STATUS "IPO / LTO enabled") set_target_properties(${EXAMPLE_NAME} PROPERTIES CMAKE_INTERPROCEDURAL_OPTIMIZATION TRUE) target_link_options(${EXAMPLE_NAME} PRIVATE -fuse-ld=lld) else() message(STATUS "IPO / LTO not supported: <${error}>") endif() endif() set_target_properties(${EXAMPLE_NAME} PROPERTIES SUFFIX .wasm) target_include_directories(${EXAMPLE_NAME} PUBLIC ${CMAKE_CURRENT_BINARY_DIR}/../../${TARGET_DIR}) target_link_libraries(${EXAMPLE_NAME} fastly::thin) ``` -------------------------------- ### Curl Compute App Locally Source: https://github.com/fastly/compute-sdk-cpp/blob/main/quickstart/README.md This command sends a POST request with 'hello, world!' as the body to the locally running Compute application. The application is expected to be listening on port 7676. ```shell curl -d "hello, world!" http://127.0.0.1:7676/ ``` -------------------------------- ### Serve Compute App Locally with Fastly CLI Source: https://github.com/fastly/compute-sdk-cpp/blob/main/quickstart/README.md This command uses the Fastly CLI to serve the Compute application locally. It watches for file changes and automatically rebuilds the application. This relies on the `scripts.build` configuration in `fastly.toml`. ```shell fastly compute serve --watch ``` -------------------------------- ### CMake Project Setup and Versioning Source: https://github.com/fastly/compute-sdk-cpp/blob/main/CMakeLists.txt Initializes the CMake build system, sets the project name to 'compute-sdk-cpp', and specifies the project version. It also defines the minimum required CMake version. ```cmake cmake_minimum_required(VERSION 3.29) project(compute-sdk-cpp VERSION 0.5.0 LANGUAGES CXX) ``` -------------------------------- ### Create and Send Backend HTTP Requests using Fastly Compute C++ SDK Source: https://context7.com/fastly/compute-sdk-cpp/llms.txt Programmatically creates HTTP requests (e.g., GET, POST) using convenience constructors and sends them to backend servers. Supports synchronous `send()` and asynchronous `send_async()` methods. Includes error handling for backend communication. ```cpp #include "fastly/sdk.h" #include int main() { // Create a GET request with builder-style chaining auto resp = fastly::Request::get("https://httpbin.org/get") .with_header("X-Custom-Header", "hello") .with_header("Accept", "application/json") .send("httpbin_backend"); if (!resp) { std::cerr << "Backend request failed: " << resp.error().error_msg(); fastly::Response::from_status(502).send_to_client(); return 1; } // Create a POST request with body auto post_resp = fastly::Request::post("https://httpbin.org/post") .with_body_text_plain("Hello from Fastly!") .value() .with_header("Content-Type", "text/plain") .value() .send("httpbin_backend"); // Forward successful response to client resp->send_to_client(); } ``` -------------------------------- ### CMake Build Configuration for Fastly Compute SDK C++ Source: https://github.com/fastly/compute-sdk-cpp/blob/main/quickstart/CMakeLists.txt This CMake script configures the build for a C++ Fastly Compute project. It requires a specific WASI SDK toolchain file, finds the Fastly package, and sets up compilation flags, C++ standard, and output suffix. It also includes optional Link-Time Optimization (LTO) support. ```cmake cmake_minimum_required(VERSION 3.15) project(quickstart) if("${WASI_SDK_PREFIX}" STREQUAL "") message(FATAL_ERROR "You must supply a CMAKE_TOOLCHAIN_FILE argument to CMake, pointing to the wasi-sdk-p1.cmake file in your WASI SDK installation.") endif() find_package(fastly REQUIRED) add_executable(main main.cpp) option(ENABLE_LTO "Enable cross language linking time optimization" ON) if(ENABLE_LTO) include(CheckIPOSupported) check_ipo_supported(RESULT supported OUTPUT error) if(supported) message(STATUS "IPO / LTO enabled") set_target_properties(main PROPERTIES INTERPROCEDURAL_OPTIMIZATION TRUE) target_link_options(main PRIVATE -fuse-ld=lld) else() message(STATUS "IPO / LTO not supported: <${error}>") endif() endif() target_compile_options(main PRIVATE -Wall -Wextra -Werror -fno-exceptions) target_compile_features(main PRIVATE cxx_std_20) set_target_properties(main PROPERTIES SUFFIX .wasm) target_link_libraries(main PRIVATE fastly::fastly) target_link_options(main PRIVATE "-L${WASI_SDK_PREFIX}/share/wasi-sysroot/lib/wasm32-wasi") ``` -------------------------------- ### Strip WASM Binary for Size Reduction Source: https://github.com/fastly/compute-sdk-cpp/blob/main/quickstart/README.md This command uses the `strip` binary from the wasi-sdk to remove debug symbols from the compiled WebAssembly (WASM) binary. This can significantly reduce the file size of the WASM module, though it makes debugging more difficult. This can be added to the `fastly.toml` build script. ```shell /opt/wasi-sdk/bin/strip bin/main.wasm ``` -------------------------------- ### Get Client Request using Fastly Compute C++ SDK Source: https://context7.com/fastly/compute-sdk-cpp/llms.txt Retrieves the incoming HTTP request from the client using `fastly::Request::from_client()`. This method allows access to request details like method, URL, headers, body, and client metadata. It returns a `fastly::Request` object for further processing. ```cpp #include "fastly/sdk.h" #include int main() { // Get the incoming client request auto req{fastly::Request::from_client()}; // Access request properties std::string method = req.get_method() == fastly::http::Method::GET ? "GET" : "OTHER"; std::string url = req.get_url(); std::string path = req.get_path(); // Get optional query parameter auto param = req.get_query_parameter("id"); // Get header value auto user_agent = req.get_header("User-Agent"); if (user_agent.has_value() && *user_agent != std::nullopt) { std::cout << "User-Agent: " << **user_agent << std::endl; } // Get client IP address auto client_ip = req.get_client_ip_addr(); if (client_ip) { std::cout << "Client IP: " << *client_ip << std::endl; } // Read the request body as a string std::string body_text = req.into_body_string(); fastly::Response::from_body("Request processed").send_to_client(); } ``` -------------------------------- ### Get Client IP Geolocation Data with Fastly Compute SDK C++ Source: https://context7.com/fastly/compute-sdk-cpp/llms.txt This snippet shows how to retrieve geographic information for a client's IP address using the Fastly Compute SDK for C++. It includes dependencies on the 'fastly/sdk.h' header and standard C++ libraries. The function takes no explicit input but uses the client's IP address implicitly. It outputs country, city, coordinates, timezone, ISP, and connection type data. Limitations include potential failures if the client IP is unavailable or the geo lookup service encounters an issue. ```cpp #include "fastly/sdk.h" #include int main() { auto req = fastly::Request::from_client(); auto client_ip = req.get_client_ip_addr(); if (!client_ip) { fastly::Response::from_body("No client IP available").send_to_client(); return 0; } auto geo_result = fastly::geo::geo_lookup(*client_ip); if (!geo_result || *geo_result == std::nullopt) { fastly::Response::from_body("Geo lookup failed").send_to_client(); return 0; } auto geo = std::move(**geo_result); fastly::Body body; body << "Client Geolocation:\n" << "Country: " << geo.country_name() << " (" << geo.country_code() << ")\n" << "City: " << geo.city() << "\n" << "Latitude: " << geo.latitude() << "\n" << "Longitude: " << geo.longitude() << "\n" << "Postal Code: " << geo.postal_code() << "\n" << "AS Name: " << geo.as_name() << "\n" << "AS Number: " << geo.as_number() << "\n"; // Check connection type if (geo.conn_type() == fastly::geo::ConnType::Satellite) { body << "Connection: Satellite\n"; } else if (geo.conn_type() == fastly::geo::ConnType::Mobile) { body << "Connection: Mobile\n"; } // Check region if (auto region = geo.region()) { body << "Region: " << geo.country_code() << "-" << *region << "\n"; } // Get UTC offset if (auto offset = geo.utc_offset()) { body << "UTC Offset: " << offset->whole_hours() << " hours\n"; } fastly::Response::from_body(std::move(body)).send_to_client(); } ``` -------------------------------- ### Initialize UI Components (JavaScript) Source: https://github.com/fastly/compute-sdk-cpp/blob/main/vendor/doxygen-awesome/header.html Initializes various UI components for the documentation site, including dark mode toggle, fragment copy button, paragraph link, and interactive table of contents. These scripts enhance user experience by providing interactive features. ```javascript var page_layout = 1; DoxygenAwesomeDarkModeToggle.init(); DoxygenAwesomeFragmentCopyButton.init(); DoxygenAwesomeParagraphLink.init(); DoxygenAwesomeInteractiveToc.init(); ``` -------------------------------- ### Dynamically Configure Backends with Fastly Compute SDK (C++) Source: https://context7.com/fastly/compute-sdk-cpp/llms.txt Demonstrates dynamic backend configuration at runtime using `fastly::backend::BackendBuilder`. This allows customization of timeouts, SSL settings, host overrides, and connection pooling for backend requests. ```cpp #include "fastly/sdk.h" #include int main() { // Create dynamic backend with custom configuration auto backend = fastly::backend::BackendBuilder("my_dynamic_backend", "api.example.com:443") .enable_ssl() .connect_timeout(std::chrono::milliseconds(5000)) .first_byte_timeout(std::chrono::milliseconds(15000)) .between_bytes_timeout(std::chrono::milliseconds(10000)) .override_host("api.example.com") .sni_hostname("api.example.com") .enable_pooling(true) .http_keepalive_time(std::chrono::milliseconds(60000)) .tcp_keepalive_enable(true) .finish(); if (!backend) { fastly::Response::from_status(500) .with_body("Failed to create backend") .send_to_client(); return 1; } // Use the dynamic backend auto resp = fastly::Request::get("https://api.example.com/data") .send(*backend); if (resp) { resp->send_to_client(); } // Get backend from name (for pre-configured backends) auto named_backend = fastly::backend::Backend::from_name("my_backend"); if (named_backend) { std::cout << "Backend host: " << named_backend->get_host() << std::endl; std::cout << "Backend port: " << named_backend->get_port() << std::endl; std::cout << "SSL enabled: " << named_backend->is_ssl() << std::endl; } } ``` -------------------------------- ### Read Configuration Values from Fastly Config Store using C++ Source: https://context7.com/fastly/compute-sdk-cpp/llms.txt Demonstrates how to open a Fastly Config Store and retrieve configuration values by key. It includes error handling for store opening and value retrieval, as well as checking for key existence. ```cpp #include "fastly/sdk.h" #include int main() { fastly::log::init_simple("logs"); // Open a config store auto store = fastly::ConfigStore::open("my-config-store"); if (!store) { fastly::log::error("Failed to open config store: {}", store.error().error_msg()); fastly::Response::from_status(500).send_to_client(); return 1; } // Get a value from the store auto value = store->get("api_key"); if (!value) { fastly::log::error("Failed to get value: {}", value.error().error_msg()); } else if (*value == std::nullopt) { fastly::log::warn("Key 'api_key' not found in config store"); } else { fastly::log::info("Got API key: {}", **value); } // Check if key exists auto exists = store->contains("feature_flag"); if (exists && *exists) { auto flag = store->get("feature_flag"); fastly::Body body; body << "Feature enabled: " << flag->value(); fastly::Response::from_body(std::move(body)).send_to_client(); } } ``` -------------------------------- ### Create and Send HTTP Responses with Fastly Compute SDK (C++) Source: https://context7.com/fastly/compute-sdk-cpp/llms.txt Demonstrates creating various HTTP responses including simple text, status codes with headers, redirects, and error responses using the `fastly::Response` class. Responses are sent to the client using `send_to_client()`. ```cpp #include "fastly/sdk.h" int main() { // Simple text response fastly::Response::from_body("Hello, World!").send_to_client(); // Response with status code and headers fastly::Response::from_status(fastly::http::StatusCode::OK) .with_header("Content-Type", "application/json") .value() .with_header("X-Custom", "value") .value() .with_body_text_plain("{\"message\": \"success\"}") .value() .send_to_client(); // Redirect responses fastly::Response::redirect("https://www.fastly.com").send_to_client(); fastly::Response::temporary_redirect("/new-path").send_to_client(); fastly::Response::see_other("/other-resource").send_to_client(); // Error response fastly::Response::from_status(404) .with_body("Not Found") .send_to_client(); } ``` -------------------------------- ### Route Requests Using URL Patterns in C++ Source: https://context7.com/fastly/compute-sdk-cpp/llms.txt This C++ code snippet demonstrates how to parse and manipulate request URLs for routing in a Fastly Compute application. It uses regular expressions to match URL paths and conditionally rewrites or redirects requests to different backends or external URLs based on the matched patterns. Dependencies include the Fastly Compute SDK for C++ and the standard C++ regex library. ```cpp #include "fastly/sdk.h" #include const std::regex API_V1("^/api/v1/(.+)$"); const std::regex API_V2("^/api/v2/(.+)$"); const std::regex STATIC_ASSETS("^/static/(.+)$"); int main() { auto req = fastly::Request::from_client(); // Get URL components std::string full_url = req.get_url(); std::string path = req.get_path(); auto query_string = req.get_query_string(); // Get specific query parameter auto page = req.get_query_parameter("page"); auto limit = req.get_query_parameter("limit"); std::smatch match; fastly::http::Body body; // Route based on path patterns if (std::regex_match(path, match, API_V1)) { // Rewrite to backend API auto backend_req = req.clone_without_body(); backend_req.set_path("/legacy/" + match[1].str()); auto resp = backend_req.send("api_v1_backend"); if (resp) resp->send_to_client(); return 0; } if (std::regex_match(path, match, API_V2)) { auto backend_req = req.clone_without_body(); backend_req.set_url("https://api-v2.example.com/" + match[1].str()); if (query_string) { backend_req.set_query_string(*query_string); } auto resp = backend_req.send("api_v2_backend"); if (resp) resp->send_to_client(); return 0; } if (std::regex_match(path, match, STATIC_ASSETS)) { // Serve static assets with long cache auto resp = fastly::Request::get("https://cdn.example.com/assets/" + match[1].str()) .with_ttl(86400 * 30) // Cache for 30 days .send("cdn_backend"); if (resp) resp->send_to_client(); return 0; } // Default: 404 Not Found fastly::Response::from_status(404) .with_body("Route not found: " + path) .send_to_client(); } ``` -------------------------------- ### Stream HTTP Responses with Fastly Compute SDK (C++) Source: https://context7.com/fastly/compute-sdk-cpp/llms.txt Illustrates how to stream responses to the client using `stream_to_client()`. This is useful for large responses as it avoids buffering the entire body in memory. It involves fetching from a backend, processing line by line, and forwarding to the client. ```cpp #include "fastly/sdk.h" #include int main() { // Fetch from backend auto backend_resp = fastly::Request::get("https://www.wikipedia.org/") .send("wikipedia"); if (!backend_resp) { std::cerr << backend_resp.error().error_msg(); fastly::Response::from_status(500).send_to_client(); return 1; } // Take the body for line-by-line processing auto backend_body = backend_resp->take_body(); // Start streaming to client immediately auto client_body = backend_resp->stream_to_client(); // Process and forward each line size_t line_count = 0; for (std::string line; std::getline(backend_body, line);) { line_count++; client_body << line << std::endl; } // Must call finish() to close the client connection if (client_body.finish()) { std::cout << "Streamed " << line_count << " lines" << std::endl; } } ``` -------------------------------- ### Perform Key-Value Operations on Fastly KV Store using C++ Source: https://context7.com/fastly/compute-sdk-cpp/llms.txt Illustrates CRUD operations on Fastly KV Stores, including opening a store, looking up values, inserting data with TTL and metadata, deleting entries, and listing keys with pagination. ```cpp #include "fastly/sdk.h" #include int main() { // Open a KV store auto store_result = fastly::kv_store::KVStore::open("my-kv-store"); if (!store_result || !*store_result) { fastly::Response::from_status(500) .with_body("Failed to open KV store") .send_to_client(); return 1; } auto store = std::move(**store_result); // Lookup a value auto lookup = store.lookup("user:123"); if (lookup) { std::string data = lookup->take_body().take_body_string(); auto metadata = lookup->metadata(); auto generation = lookup->current_generation(); } // Insert a value with TTL and metadata auto insert_result = store.build_insert() .time_to_live(std::chrono::milliseconds(3600000)) // 1 hour TTL .metadata("{\"version\": 1}") .mode(fastly::kv_store::InsertMode::Overwrite) .execute("session:abc", fastly::Body{"session data"}); if (!insert_result) { std::cerr << "Insert failed: " << insert_result.error().error_msg(); } // Delete a value auto erase_result = store.erase("old-key"); // List keys with pagination auto list_result = store.build_list() .prefix("user:") .limit(100) .execute(); if (list_result) { for (const auto& key : list_result->keys()) { std::cout << "Key: " << key << std::endl; } // Get next page cursor if available if (auto cursor = list_result->next_cursor()) { // Use cursor for next page } } fastly::Response::from_body("KV operations complete").send_to_client(); } ``` -------------------------------- ### Analyze Device from User-Agent with Fastly Compute SDK C++ Source: https://context7.com/fastly/compute-sdk-cpp/llms.txt This C++ code snippet demonstrates how to parse a User-Agent string to identify device characteristics using the Fastly Compute SDK. It requires the 'fastly/sdk.h' header. The function retrieves the 'User-Agent' header from the client's request and uses it to look up device details such as type, brand, model, and capabilities. Potential issues include missing User-Agent headers or device detection failures. ```cpp #include "fastly/sdk.h" #include int main() { auto req = fastly::Request::from_client(); auto ua_result = req.get_header("User-Agent"); if (!ua_result || *ua_result == std::nullopt) { fastly::Response::from_body("No User-Agent header").send_to_client(); return 0; } auto device_result = fastly::device_detection::lookup(**ua_result); if (!device_result || *device_result == std::nullopt) { fastly::Response::from_body("Device detection failed").send_to_client(); return 0; } auto device = std::move(**device_result); fastly::Body body; body << "Device Information:\n" << "Name: " << device.device_name().value_or("Unknown") << "\n" << "Brand: " << device.brand().value_or("Unknown") << "\n" << "Model: " << device.model().value_or("Unknown") << "\n" << "Hardware Type: " << device.hwtype().value_or("Unknown") << "\n\n" << "Device Types:\n" << "Mobile: " << (device.is_mobile().value_or(false) ? "Yes" : "No") << "\n" << "Tablet: " << (device.is_tablet().value_or(false) ? "Yes" : "No") << "\n" << "Desktop: " << (device.is_desktop().value_or(false) ? "Yes" : "No") << "\n" << "Smart TV: " << (device.is_smarttv().value_or(false) ? "Yes" : "No") << "\n" << "Game Console: " << (device.is_gameconsole().value_or(false) ? "Yes" : "No") << "\n" << "Touchscreen: " << (device.is_touchscreen().value_or(false) ? "Yes" : "No") << "\n"; // Serve different content based on device if (device.is_mobile().value_or(false)) { body << "\nServing mobile-optimized content"; } else if (device.is_tablet().value_or(false)) { body << "\nServing tablet-optimized content"; } else { body << "\nServing desktop content"; } fastly::Response::from_body(std::move(body)).send_to_client(); } ``` -------------------------------- ### Caching - Request Cache Control with C++ Source: https://context7.com/fastly/compute-sdk-cpp/llms.txt Control caching behavior for backend requests, including Time-To-Live (TTL), stale-while-revalidate, surrogate keys, and PCI-compliant caching. Demonstrates building requests with various caching directives and checking cache status from responses. ```cpp #include "fastly/sdk.h" int main() { auto client_req = fastly::Request::from_client(); // Build request with caching directives auto backend_req = fastly::Request::get("https://api.example.com/data") .with_ttl(3600) // Cache for 1 hour .with_stale_while_revalidate(86400) // Serve stale for 24h while revalidating .with_surrogate_key("api-data user-123") // Surrogate keys for purging .value() .with_cache_key("custom-cache-key-v1"); // Custom cache key // Check if request is cacheable if (backend_req.is_cacheable()) { fastly::log::info("Request is cacheable"); } // Force bypass cache (pass mode) auto uncached_req = fastly::Request::get("https://api.example.com/dynamic") .with_pass(true); // Enable PCI-compliant caching auto pci_req = fastly::Request::get("https://api.example.com/secure") .with_pci(true) .with_ttl(300); // Send and check cache status from response auto resp = backend_req.send("api_backend"); if (resp) { // Check cache information if (auto ttl = resp->get_ttl()) { fastly::log::info("Response TTL: {}ms", ttl->count()); } if (auto age = resp->get_age()) { fastly::log::info("Response age: {}ms", age->count()); } if (auto swr = resp->get_stale_while_revalidate()) { fastly::log::info("SWR window: {}ms", swr->count()); } resp->send_to_client(); } } ``` -------------------------------- ### Logging - Real-Time Log Streaming with C++ Source: https://context7.com/fastly/compute-sdk-cpp/llms.txt Configure and send log messages to Fastly's Real-Time Log Streaming endpoints. Supports multiple log levels and C++20 format string syntax. Initializes logging with simple or builder patterns and allows logging to specific endpoints. ```cpp #include "fastly/sdk.h" int main() { // Simple initialization with single endpoint fastly::log::init_simple("my_log_endpoint", fastly::log::LogLevelFilter::Info); // Or use builder for advanced configuration fastly::log::LoggerBuilder() .max_level(fastly::log::LogLevelFilter::Debug) .default_endpoint("main_logs") .endpoint_level("error_logs", fastly::log::LogLevelFilter::Error) .default_level_endpoint("error_logs", fastly::log::LogLevel::Error) .echo_stdout(true) // Also output to stdout for log tailing .init(); // Log at different levels with format strings fastly::log::trace("Detailed trace: {} = {}", "variable", 42); fastly::log::debug("Debug info: processing request"); fastly::log::info("Request received from {}", "client"); fastly::log::warn("Warning: rate limit approaching for user {}", "user123"); fastly::log::error("Error occurred: {}", "connection timeout"); // Log to specific endpoint fastly::log::info_to("main_logs", "Processing started"); fastly::log::error_to("error_logs", "Critical failure in {}", "auth module"); // Check and set log level auto current_level = fastly::log::max_level(); fastly::log::set_max_level(fastly::log::LogLevelFilter::Warn); // Direct endpoint access auto endpoint = fastly::log::Endpoint::from_name("my_log_endpoint"); if (endpoint) { // Use endpoint name std::cout << "Endpoint: " << endpoint->name() << std::endl; } fastly::Response::from_body("Logged").send_to_client(); } ``` -------------------------------- ### Configure C++ Test Executables with Fastly SDK and Catch2 (CMake) Source: https://github.com/fastly/compute-sdk-cpp/blob/main/test/CMakeLists.txt This CMake script discovers all .cpp files in the current directory, compiles them into individual executables, and links them against the Fastly SDK and Catch2. It sets up test launchers using 'viceroy' and configures include paths, compile options, and registers tests. ```cmake file(GLOB_RECURSE TEST_SRC "${CMAKE_CURRENT_SOURCE_DIR}/*.cpp") foreach(t ${TEST_SRC}) get_filename_component(testname ${t} NAME_WE) add_executable(${testname} ${t}) set_property(TARGET ${testname} PROPERTY TEST_LAUNCHER viceroy run -C fastly.toml) target_link_libraries(${testname} PRIVATE fastly::thin Catch2::Catch2) target_include_directories(${testname} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include ${CMAKE_CURRENT_BINARY_DIR}/include) target_compile_options(${testname} PRIVATE -Wall -Wextra -Werror ${FASTLY_CXXFLAGS}) add_test(NAME ${testname} COMMAND ${testname} WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) endforeach() ``` -------------------------------- ### Asynchronous Requests and Select with Fastly Compute C++ SDK Source: https://context7.com/fastly/compute-sdk-cpp/llms.txt Enables sending multiple HTTP requests concurrently using `send_async()` and efficiently retrieving the first completed response with `fastly::http::request::select()`. This pattern is useful for optimizing latency by not waiting for all requests to finish. ```cpp #include "fastly/sdk.h" #include #include int main() { fastly::log::init_simple("logs"); // Build a vector of pending requests std::vector pending; pending.push_back(fastly::Request::get("https://www.fastly.com/") .send_async("fastly") .value()); pending.push_back(fastly::Request::get("https://en.wikipedia.org/wiki/Fastly") .send_async("wikipedia") .value()); // Race the requests - return whichever finishes first auto [resp, remaining] = fastly::http::request::select(pending); if (!resp) { std::cerr << resp.error().error_msg(); fastly::Response::from_status(500).send_to_client(); return 1; } fastly::log::info("Request from {} won.", resp->get_backend_name().value()); // Append info about which backend responded fastly::Body tail; tail << "\n\nResponse from: " << resp->get_backend_name().value(); resp->append_body(std::move(tail)); resp->send_to_client(); } ``` -------------------------------- ### Process ESI Tags with Fastly Compute SDK C++ Source: https://context7.com/fastly/compute-sdk-cpp/llms.txt This snippet demonstrates how to process Edge Side Includes (ESI) tags within an HTTP response. It fetches a main document, configures an ESI processor, and dispatches/processes fragments to assemble the final page at the edge. It requires the 'fastly/sdk.h' header. ```cpp #include "fastly/sdk.h" int main() { fastly::log::init_simple("logs", fastly::log::LogLevelFilter::Debug); // Fetch the main document containing ESI tags auto bereq = fastly::http::Request(fastly::http::Method::GET, "https://example.com/page-with-esi") .with_auto_decompress_gzip(true); auto beresp = bereq.clone_without_body().send("origin_backend").value(); // Create ESI processor with custom configuration fastly::esi::Configuration config("esi", true); // namespace, escaped content fastly::esi::Processor processor(std::move(bereq), config); // Define fragment request dispatcher auto dispatch_fragment = [](fastly::http::Request req) -> std::optional { auto pending = req.send_async("origin_backend"); if (pending) { return fastly::esi::PendingFragmentContent{std::move(*pending)}; } return std::nullopt; }; // Define optional fragment response processor auto process_fragment = [](fastly::http::Request& req, fastly::http::Response resp) -> std::optional { // Optionally modify fragment responses resp.set_header("X-Fragment", "processed"); return resp; }; // Process the response, resolving ESI includes auto result = processor.process_response( beresp, std::nullopt, // optional client response metadata dispatch_fragment, // fragment request dispatcher process_fragment // fragment response processor ); if (!result) { fastly::log::error("ESI processing failed"); fastly::Response::from_status(500).send_to_client(); } } ``` -------------------------------- ### Read and Write HTTP Bodies with Fastly Compute SDK (C++) Source: https://context7.com/fastly/compute-sdk-cpp/llms.txt Shows how to interact with HTTP request and response bodies using the `fastly::http::Body` class. It covers appending data using iostream operators, creating bodies from strings and byte vectors, and combining bodies. ```cpp #include "fastly/sdk.h" #include int main() { auto req = fastly::Request::from_client(); // Get body and append to it using iostream operators auto body = req.into_body(); body << " - Processed by Fastly Compute"; // Create new body with content fastly::http::Body new_body; new_body << "Line 1\n"; new_body << "Line 2\n"; new_body << "Counter: " << 42; // Read body as string std::string content = new_body.take_body_string(); // Create body from string directly fastly::Body string_body{"Hello from constructor"}; // Create body from vector std::vector bytes = {0x48, 0x65, 0x6c, 0x6c, 0x6f}; fastly::Body byte_body{bytes}; // Append bodies together fastly::Body combined; combined << "Part 1: "; combined.append(std::move(string_body)); fastly::Response::from_body(std::move(combined)).send_to_client(); } ``` -------------------------------- ### Access Secrets from Fastly Secret Store using C++ Source: https://context7.com/fastly/compute-sdk-cpp/llms.txt Shows how to securely access sensitive data like API tokens and passwords from Fastly Secret Stores. It covers opening a store, retrieving secrets, checking for existence, and using secrets in backend requests. ```cpp #include "fastly/sdk.h" #include int main() { // Open a secret store auto store = fastly::secret_store::SecretStore::open("my-secrets"); if (!store) { std::cerr << "Failed to open secret store: " << store.error().error_msg(); fastly::Response::from_status(500).send_to_client(); return 1; } // Get a secret auto secret = store->get("api_token"); if (!secret) { std::cerr << "Failed to get secret: " << secret.error().error_msg(); return 1; } if (*secret == std::nullopt) { std::cerr << "Secret 'api_token' not found"; return 1; } // Access the plaintext value std::string token = (*secret)->plaintext(); // Check if a secret exists auto exists = store->contains("database_password"); if (exists && *exists) { auto db_secret = store->get("database_password"); // Use secret for database connection } // Use secret in backend request header auto req = fastly::Request::get("https://api.example.com/data") .with_header("Authorization", "Bearer " + token) .value(); auto resp = req.send("api_backend"); if (resp) { resp->send_to_client(); } } ``` -------------------------------- ### Inspect Requests with Fastly NGWAF C++ SDK Source: https://context7.com/fastly/compute-sdk-cpp/llms.txt This C++ snippet shows how to inspect incoming client requests using Fastly's Next-Gen WAF (NGWAF). It configures inspection parameters like corporation and workspace, then analyzes the request for security threats. The snippet handles different security verdicts (Block, Unauthorized) and potential buffer size errors, requiring 'fastly/sdk.h'. ```cpp #include "fastly/sdk.h" int main() { fastly::log::init_simple("logs"); auto req = fastly::Request::from_client(); // Configure inspection auto config = fastly::security::InspectConfig() .with_corp("my_corporation") .with_workspace("production") .with_buffer_size(32768); // Inspect the request auto inspect_result = fastly::security::inspect(req, std::move(config)); if (!inspect_result) { auto err = inspect_result.error(); if (err.error_code() == fastly::security::InspectErrorCode::BufferSizeError) { // Retry with larger buffer auto required_size = err.required_buffer_size(); fastly::log::warn("Buffer too small, need {} bytes", *required_size); } fastly::Response::from_status(500).send_to_client(); return 1; } auto verdict = inspect_result->verdict(); // Handle different verdicts if (verdict == fastly::security::InspectVerdict::Block) { fastly::log::warn("Request blocked by NGWAF"); fastly::Response::from_status(403) .with_body("Request blocked for security reasons") .send_to_client(); return 0; } if (verdict == fastly::security::InspectVerdict::Unauthorized) { fastly::Response::from_status(401).send_to_client(); return 0; } // Check for redirect response if (inspect_result->is_redirect()) { if (auto redirect_resp = inspect_result->into_redirect()) { redirect_resp->send_to_client(); return 0; } } // Log security tags for (const auto& tag : inspect_result->tags()) { fastly::log::info("Security tag: {}", tag); } fastly::log::info("Request allowed, decision took {}ms", inspect_result->decision_ms().count()); // Continue processing allowed request fastly::Response::from_body("Request allowed").send_to_client(); } ``` -------------------------------- ### Custom Command for Building Rust and Generating C++ Bindings Source: https://github.com/fastly/compute-sdk-cpp/blob/main/CMakeLists.txt Defines a custom CMake command that is executed during the build process. This command invokes `cargo build` to compile Rust code, copies generated C++ bridge files, creates necessary include directories, and copies header files. ```cmake add_custom_command( OUTPUT ${FASTLY_SYS_CXX} ${FASTLY_SYS_LIB} ${CMAKE_CURRENT_BINARY_DIR}/include/fastly/sdk-sys.h COMMAND CARGO_TARGET_DIR=${CMAKE_CURRENT_BINARY_DIR} CC="${CMAKE_C_COMPILER}" CXX="${CMAKE_CXX_COMPILER}" CFLAGS="${FASTLY_CFLAGS}" CXXFLAGS="${FASTLY_CXXFLAGS}" RUSTFLAGS="${FASTLY_RUST_FLAGS}" ${CARGO_CMD} COMMAND cp ${CMAKE_CURRENT_BINARY_DIR}/cxxbridge/fastly-sys/src/lib.rs.cc ${FASTLY_SYS_CXX} COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_CURRENT_BINARY_DIR}/include/fastly COMMAND cp ${CMAKE_CURRENT_BINARY_DIR}/cxxbridge/fastly-sys/src/lib.rs.h ${CMAKE_CURRENT_BINARY_DIR}/include/fastly/sdk-sys.h COMMAND cp ${CMAKE_CURRENT_SOURCE_DIR}/vendor/tl/expected.h ${CMAKE_CURRENT_BINARY_DIR}/include/fastly/expected.h WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} DEPENDS ${RUST_SRC} ) ``` -------------------------------- ### Creating 'fastly-thin' Library Target Source: https://github.com/fastly/compute-sdk-cpp/blob/main/CMakeLists.txt Creates a static library target named `fastly-thin` using the C++ source files found by `GLOB_RECURSE`. It defines an alias `fastly::thin`, sets LTO properties, and applies linker options privately. Compile options and features (C++20) are also configured. ```cmake add_library(fastly-thin STATIC ${FASTLY_CXX}) add_library(fastly::thin ALIAS fastly-thin) target_include_directories(fastly-thin PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/vendor/tl) set_target_properties(fastly-thin PROPERTIES INTERPROCEDURAL_OPTIMIZATION ${LTO_SUPPORTED}) target_link_options(fastly-thin PRIVATE ${FASTLY_LDFLAGS}) target_compile_options(fastly-thin PRIVATE -Wall -Wextra -Werror ${FASTLY_CXXFLAGS}) target_compile_features(fastly-thin PUBLIC cxx_std_20) ``` -------------------------------- ### Finding Rust Source Files Source: https://github.com/fastly/compute-sdk-cpp/blob/main/CMakeLists.txt Uses `file(GLOB_RECURSE)` to find all Rust source files (`.rs`) within the `src` directory and its subdirectories, storing the list in the `RUST_SRC` variable. ```cmake file(GLOB_RECURSE RUST_SRC "${CMAKE_CURRENT_SOURCE_DIR}/src/**/*.rs" "${CMAKE_CURRENT_SOURCE_DIR}/src/*.rs") ``` -------------------------------- ### Setting Include Directories for Libraries Source: https://github.com/fastly/compute-sdk-cpp/blob/main/CMakeLists.txt Configures the include directories for the `fastly-thin` and `fastly-sys` targets. This ensures that the compiler can find necessary header files, including those in the project's `include` directory and the build output directory. ```cmake target_include_directories(fastly-thin PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include ${CMAKE_CURRENT_BINARY_DIR}/include) target_include_directories(fastly-sys PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include ${CMAKE_CURRENT_BINARY_DIR}/include) ``` -------------------------------- ### Purge - Cache Invalidation with C++ Source: https://context7.com/fastly/compute-sdk-cpp/llms.txt Invalidate cached content using surrogate keys for granular cache control. Supports both hard purge (immediate invalidation) and soft purge (marking content as stale). Requires valid Fastly-Key authentication. ```cpp #include "fastly/sdk.h" int main() { fastly::log::init_simple("logs"); auto req = fastly::Request::from_client(); // Check for valid purge authentication if (!req.fastly_key_is_valid()) { fastly::Response::from_status(401) .with_body("Invalid Fastly-Key") .send_to_client(); return 0; } auto key = req.get_query_parameter("surrogate_key"); if (!key) { fastly::Response::from_status(400) .with_body("Missing surrogate_key parameter") .send_to_client(); return 0; } // Hard purge - immediately invalidates cached content auto purge_result = fastly::http::purge::purge_surrogate_key(*key); if (!purge_result) { fastly::log::error("Hard purge failed: {}", purge_result.error().error_msg()); fastly::Response::from_status(500).send_to_client(); return 1; } // Soft purge - marks content as stale, allows stale-while-revalidate auto soft_result = fastly::http::purge::soft_purge_surrogate_key(*key); if (!soft_result) { fastly::log::error("Soft purge failed: {}", soft_result.error().error_msg()); } fastly::log::info("Purged surrogate key: {}", *key); // Set surrogate key on backend request for future purging auto backend_resp = fastly::Request::get("https://api.example.com/content") .with_surrogate_key("content-v1 page-home") .value() .send("api_backend"); if (backend_resp) { backend_resp->send_to_client(); } } ``` -------------------------------- ### Link Time Optimization (LTO) Configuration Source: https://github.com/fastly/compute-sdk-cpp/blob/main/CMakeLists.txt Handles the configuration for Link Time Optimization (LTO). It checks for LTO support using `CheckIPOSupported`, and if supported, sets specific compiler and linker flags for LTO. If not supported, it defines fallback flags. ```cmake option(ENABLE_LTO "Enable cross language linking time optimization" ON) set(LTO_SUPPORTED FALSE) if(ENABLE_LTO) include(CheckIPOSupported) check_ipo_supported(RESULT supported OUTPUT error) if(supported) message(STATUS "IPO / LTO enabled") set(LTO_SUPPORTED TRUE) set(FASTLY_LDFLAGS -fuse-ld=lld) set(FASTLY_CFLAGS -flto=thin -Oz) set(FASTLY_CXXFLAGS -flto=thin -Oz "--sysroot=${WASI_SDK_PREFIX}/share/wasi-sysroot" -DRUST_CXX_NO_EXCEPTIONS -fno-exceptions) set(FASTLY_RUST_FLAGS -Clinker-plugin-lto "-Clinker=${CMAKE_CURRENT_SOURCE_DIR}/build-workaround.sh" "-Clink-arg=-fuse-ld=lld" "-L${WASI_SDK_PREFIX}/share/wasi-sysroot/lib/wasm32-wasi" "-lstatic=c++" "-lstatic=c++abi") else() message(STATUS "IPO / LTO not supported: <${error}>") set(FASTLY_CXXFLAGS "--sysroot=${WASI_SDK_PREFIX}/share/wasi-sysroot -DRUST_CXX_NO_EXCEPTIONS -fno-exceptions") set(FASTLY_RUST_FLAGS "-L${WASI_SDK_PREFIX}/share/wasi-sysroot/lib/wasm32-wasi" "-lstatic=c++" "-lstatic=c++abi") endif() else() set(FASTLY_CXXFLAGS "-sysroot=${WASI_SDK_PREFIX}/share/wasi-sysroot -DRUST_CXX_NO_EXCEPTIONS -fno-exceptions") set(FASTLY_RUST_FLAGS "-L${WASI_SDK_PREFIX}/share/wasi-sysroot/lib/wasm32-wasi" "-lstatic=c++" "-lstatic=c++abi") endif() ```