using Astralis; using Invercargill; using Invercargill.DataStructures; /** * HeadersAndCookies Example * * Demonstrates how to access and manipulate HTTP headers and cookies. * Uses Invercargill Dictionary and Enumerable for header/cookie processing. */ void main() { var router = new Router(); var server = new Server(8083, router); // Display all request headers router.map_func("/headers", (context) => { var parts = new Series(); parts.add("Request Headers:\n"); parts.add("================\n\n"); context.request.headers.to_immutable_buffer() .iterate((grouping) => { grouping.iterate((value) => { parts.add(@"$(grouping.key): $value\n"); }); }); var result = parts.to_immutable_buffer() .aggregate("", (acc, s) => acc + s); return new BufferedHttpResult.from_string(result); }); // Check for specific header router.map_func("/user-agent", (context) => { var user_agent = context.request.user_agent ?? "Unknown"; return new BufferedHttpResult.from_string( @"Your User-Agent is: $user_agent" ); }); // Check content type and content length router.map_func("/content-info", (context) => { var parts = new Series(); parts.add("Content Information:\n"); parts.add("===================\n\n"); parts.add(@"Content-Type: $(context.request.content_type)\n"); parts.add(@"Content-Length: $(context.request.content_length)\n"); parts.add(@"Content-Encoding: $(context.request.content_encoding ?? "none")\n"); // parts.add(@"Has Body: $(context.request.has_body())\n"); var result = parts.to_immutable_buffer() .aggregate("", (acc, s) => acc + s); return new BufferedHttpResult.from_string(result); }); // Check if header exists router.map_func("/check-header", (context) => { var header_name = context.request.get_query_or_default("name", "Accept"); var exists = context.request.has_header(header_name); var value = context.request.get_header(header_name); return new BufferedHttpResult.from_string( @"Header '$header_name': $(exists ? "EXISTS" : "NOT FOUND")\nValue: $(value ?? "N/A")" ); }); // Set custom response headers router.map_func("/custom-headers", (context) => { var headers = new Catalogue(); headers.add("X-Custom-Header", "Custom-Value"); headers.add("X-Request-Id", generate_request_id()); headers.add("X-Powered-By", "Astralis"); headers.add("X-Server-Time", new DateTime.now_local().format_iso8601()); return new BufferedHttpResult.from_string( "Response with custom headers!", StatusCode.OK, headers ); }); // Display all cookies router.map_func("/cookies", (context) => { var parts = new Series(); parts.add("Request Cookies:\n"); parts.add("================\n\n"); if (context.request.cookies.to_immutable_buffer().count() == 0) { parts.add("(No cookies sent)\n"); parts.add("\nTry setting a cookie first: /set-cookie?name=test&value=123\n"); } else { context.request.cookies.to_immutable_buffer() .iterate((grouping) => { grouping.iterate((value) => { parts.add(@"$(grouping.key): $value\n"); }); }); } var result = parts.to_immutable_buffer() .aggregate("", (acc, s) => acc + s); return new BufferedHttpResult.from_string(result); }); // Get specific cookie router.map_func("/get-cookie", (context) => { var name = context.request.get_query_or_default("name", "session"); var value = context.request.get_cookie(name); if (value == null) { return new BufferedHttpResult.from_string( @"Cookie '$name' not found", StatusCode.NOT_FOUND ); } return new BufferedHttpResult.from_string( @"Cookie '$name' = '$value'" ); }); // Set a cookie (via Set-Cookie header) router.map_func("/set-cookie", (context) => { var name = context.request.get_query_or_default("name", "test"); var value = context.request.get_query_or_default("value", "123"); var max_age = context.request.get_query_or_default("max_age", "3600"); var headers = new Catalogue(); headers.add("Set-Cookie", @"$name=$value; Max-Age=$max_age; Path=/"); return new BufferedHttpResult.from_string( @"Cookie '$name' set to '$value'", StatusCode.OK, headers ); }); // Set multiple cookies router.map_func("/set-cookies", (context) => { var headers = new Catalogue(); headers.add("Set-Cookie", "user=john; Max-Age=3600; Path=/"); headers.add("Set-Cookie", "theme=dark; Max-Age=86400; Path=/"); headers.add("Set-Cookie", "lang=en; Max-Age=31536000; Path=/"); return new BufferedHttpResult.from_string( "Multiple cookies set!", StatusCode.OK, headers ); }); // Delete a cookie router.map_func("/delete-cookie", (context) => { var name = context.request.get_query_or_default("name", "test"); var headers = new Catalogue(); headers.add("Set-Cookie", @"$name=; Max-Age=0; Path=/"); return new BufferedHttpResult.from_string( @"Cookie '$name' deleted", StatusCode.OK, headers ); }); // Check if cookie exists router.map_func("/has-cookie", (context) => { var name = context.request.get_query_or_default("name", "session"); var exists = context.request.has_cookie(name); return new BufferedHttpResult.from_string( @"Cookie '$name': $(exists ? "EXISTS" : "NOT FOUND")" ); }); // Cookie-based session simulation router.map_func("/session", (context) => { var session_id = context.request.get_cookie("session_id"); if (session_id == null) { // Create new session var new_session_id = generate_session_id(); var headers = new Catalogue(); headers.add("Set-Cookie", @"session_id=$new_session_id; Max-Age=3600; Path=/; HttpOnly"); return new BufferedHttpResult.from_string( @"New session created! Session ID: $new_session_id Your session will expire in 1 hour.", StatusCode.OK, headers ); } // Existing session return new BufferedHttpResult.from_string( @"Welcome back! Session ID: $session_id Your session is active." ); }); // CORS headers example router.map_func("/cors", (context) => { var origin = context.request.get_header("Origin") ?? "*"; var headers = new Catalogue(); headers.add("Access-Control-Allow-Origin", origin); headers.add("Access-Control-Allow-Methods", "GET, POST, OPTIONS"); headers.add("Access-Control-Allow-Headers", "Content-Type, Authorization"); headers.add("Access-Control-Max-Age", "86400"); return new BufferedHttpResult.from_string( @"CORS enabled for origin: $origin", StatusCode.OK, headers ); }); // OPTIONS method for CORS preflight router.map_func("/cors", (context) => { var origin = context.request.get_header("Origin") ?? "*"; var headers = new Catalogue(); headers.add("Access-Control-Allow-Origin", origin); headers.add("Access-Control-Allow-Methods", "GET, POST, OPTIONS"); headers.add("Access-Control-Allow-Headers", "Content-Type, Authorization"); headers.add("Access-Control-Max-Age", "86400"); headers.add("Content-Length", "0"); return new BufferedHttpResult.from_string( "", StatusCode.NO_CONTENT, headers ); }); // Cache control headers router.map_func("/cache", (context) => { var cache_type = context.request.get_query_or_default("type", "public"); var headers = new Catalogue(); headers.add("Cache-Control", @"$cache_type, max-age=3600"); headers.add("Expires", get_expires_header(3600)); headers.add("ETag", generate_etag()); return new BufferedHttpResult.from_string( @"This response is cached ($cache_type cache, 1 hour)", StatusCode.OK, headers ); }); // Content negotiation router.map_func("/negotiate", (context) => { var accept = context.request.get_header("Accept") ?? "*/*"; var headers = new Catalogue(); if (accept.contains("application/json")) { headers.add("Content-Type", "application/json"); return new BufferedHttpResult.from_string( @"{ \"message\": \"JSON response\", \"format\": \"json\" }", StatusCode.OK, headers ); } else if (accept.contains("text/xml")) { headers.add("Content-Type", "text/xml"); return new BufferedHttpResult.from_string( @"XML responsexml", StatusCode.OK, headers ); } else { headers.add("Content-Type", "text/plain"); return new BufferedHttpResult.from_string( "Plain text response", StatusCode.OK, headers ); } }); // Security headers router.map_func("/secure", (context) => { var headers = new Catalogue(); headers.add("X-Content-Type-Options", "nosniff"); headers.add("X-Frame-Options", "DENY"); headers.add("X-XSS-Protection", "1; mode=block"); headers.add("Strict-Transport-Security", "max-age=31536000; includeSubDomains"); headers.add("Content-Security-Policy", "default-src 'self'"); headers.add("Referrer-Policy", "strict-origin-when-cross-origin"); return new BufferedHttpResult.from_string( "Response with security headers!", StatusCode.OK, headers ); }); print("Headers and Cookies Example Server running on port 8083\n"); print("Try these endpoints:\n"); print(" - http://localhost:8083/headers\n"); print(" - http://localhost:8083/user-agent\n"); print(" - http://localhost:8083/cookies\n"); print(" - http://localhost:8083/set-cookie?name=test&value=hello\n"); print(" - http://localhost:8083/set-cookies\n"); print(" - http://localhost:8083/session\n"); print(" - http://localhost:8083/cors\n"); print(" - http://localhost:8083/cache\n"); print(" - http://localhost:8083/negotiate\n"); print(" - http://localhost:8083/secure\n"); server.run(); } // Helper functions string generate_request_id() { var timestamp = new DateTime.now_local().to_unix(); var random = Random.next_int(); return @"req-$timestamp-$random"; } string generate_session_id() { var timestamp = new DateTime.now_local().to_unix(); var random = Random.next_int(); return @"sess-$timestamp-$random"; } string generate_etag() { var timestamp = new DateTime.now_local().to_unix(); return @"\"$timestamp\""; } string get_expires_header(int seconds) { var now = new DateTime.now_local(); var expires = now.add_seconds(seconds); return expires.format("%a, %d %b %Y %H:%M:%S GMT"); }