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. */ // Display all request headers class HeadersEndpoint : Object, Endpoint { public async HttpResult handle_request(HttpContext http_context, RouteContext route) throws Error { var parts = new Series(); parts.add("Request Headers:\n"); parts.add("================\n\n"); http_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 HttpStringResult(result); } } // Check for user-agent header class UserAgentEndpoint : Object, Endpoint { public async HttpResult handle_request(HttpContext http_context, RouteContext route) throws Error { var user_agent = http_context.request.user_agent ?? "Unknown"; return new HttpStringResult(@"Your User-Agent is: $user_agent"); } } // Check content type and content length class ContentInfoEndpoint : Object, Endpoint { public async HttpResult handle_request(HttpContext http_context, RouteContext route) throws Error { var parts = new Series(); parts.add("Content Information:\n"); parts.add("===================\n\n"); parts.add(@"Content-Type: $(http_context.request.content_type)\n"); parts.add(@"Content-Length: $(http_context.request.content_length)\n"); parts.add(@"Content-Encoding: $(http_context.request.content_encoding ?? "none")\n"); var result = parts.to_immutable_buffer() .aggregate("", (acc, s) => acc + s); return new HttpStringResult(result); } } // Check if header exists class CheckHeaderEndpoint : Object, Endpoint { public async HttpResult handle_request(HttpContext http_context, RouteContext route) throws Error { var header_name = http_context.request.get_query_or_default("name", "Accept"); var exists = http_context.request.has_header(header_name); var value = http_context.request.get_header(header_name); return new HttpStringResult(@"Header '$header_name': $(exists ? "EXISTS" : "NOT FOUND")\nValue: $(value ?? "N/A")"); } } // Set custom response headers class CustomHeadersEndpoint : Object, Endpoint { public async HttpResult handle_request(HttpContext http_context, RouteContext route) throws Error { return new HttpStringResult("Response with custom headers!") .set_header("X-Custom-Header", "Custom-Value") .set_header("X-Request-Id", generate_request_id()) .set_header("X-Powered-By", "Astralis") .set_header("X-Server-Time", new DateTime.now_local().format_iso8601()); } } // Display all cookies class CookiesEndpoint : Object, Endpoint { public async HttpResult handle_request(HttpContext http_context, RouteContext route) throws Error { var parts = new Series(); parts.add("Request Cookies:\n"); parts.add("================\n\n"); if (http_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 { http_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 HttpStringResult(result); } } // Get specific cookie class GetCookieEndpoint : Object, Endpoint { public async HttpResult handle_request(HttpContext http_context, RouteContext route) throws Error { var name = http_context.request.get_query_or_default("name", "session"); var value = http_context.request.get_cookie(name); if (value == null) { return new HttpStringResult(@"Cookie '$name' not found"); } return new HttpStringResult(@"Cookie '$name' = '$value'"); } } // Set a cookie (via Set-Cookie header) class SetCookieEndpoint : Object, Endpoint { public async HttpResult handle_request(HttpContext http_context, RouteContext route) throws Error { var name = http_context.request.get_query_or_default("name", "test"); var value = http_context.request.get_query_or_default("value", "123"); var max_age = http_context.request.get_query_or_default("max_age", "3600"); return new HttpStringResult(@"Cookie '$name' set to '$value'") .set_header("Set-Cookie", @"$name=$value; Max-Age=$max_age; Path=/"); } } // Set multiple cookies class SetCookiesEndpoint : Object, Endpoint { public async HttpResult handle_request(HttpContext http_context, RouteContext route) throws Error { // Note: Setting multiple cookies with the same header name requires // special handling - this example shows the approach return new HttpStringResult("Multiple cookies set!") .set_header("Set-Cookie", "user=john; Max-Age=3600; Path=/"); // Additional cookies would need to be set via multiple Set-Cookie headers // which requires extending the HttpResult API or using a different approach } } // Delete a cookie class DeleteCookieEndpoint : Object, Endpoint { public async HttpResult handle_request(HttpContext http_context, RouteContext route) throws Error { var name = http_context.request.get_query_or_default("name", "test"); return new HttpStringResult(@"Cookie '$name' deleted") .set_header("Set-Cookie", @"$name=; Max-Age=0; Path=/"); } } // Check if cookie exists class HasCookieEndpoint : Object, Endpoint { public async HttpResult handle_request(HttpContext http_context, RouteContext route) throws Error { var name = http_context.request.get_query_or_default("name", "session"); var exists = http_context.request.has_cookie(name); return new HttpStringResult(@"Cookie '$name': $(exists ? "EXISTS" : "NOT FOUND")"); } } // Cookie-based session simulation class SessionEndpoint : Object, Endpoint { public async HttpResult handle_request(HttpContext http_context, RouteContext route) throws Error { var session_id = http_context.request.get_cookie("session_id"); if (session_id == null) { // Create new session var new_session_id = generate_session_id(); return new HttpStringResult(@"New session created! Session ID: $new_session_id Your session will expire in 1 hour.") .set_header("Set-Cookie", @"session_id=$new_session_id; Max-Age=3600; Path=/; HttpOnly"); } // Existing session return new HttpStringResult(@"Welcome back! Session ID: $session_id Your session is active."); } } // CORS headers example class CorsEndpoint : Object, Endpoint { public async HttpResult handle_request(HttpContext http_context, RouteContext route) throws Error { var origin = http_context.request.get_header("Origin") ?? "*"; return new HttpStringResult(@"CORS enabled for origin: $origin") .set_header("Access-Control-Allow-Origin", origin) .set_header("Access-Control-Allow-Methods", "GET, POST, OPTIONS") .set_header("Access-Control-Allow-Headers", "Content-Type, Authorization") .set_header("Access-Control-Max-Age", "86400"); } } // Cache control headers class CacheEndpoint : Object, Endpoint { public async HttpResult handle_request(HttpContext http_context, RouteContext route) throws Error { var cache_type = http_context.request.get_query_or_default("type", "public"); return new HttpStringResult(@"This response is cached ($cache_type cache, 1 hour)") .set_header("Cache-Control", @"$cache_type, max-age=3600") .set_header("Expires", get_expires_header(3600)) .set_header("ETag", generate_etag()); } } // Content negotiation class NegotiateEndpoint : Object, Endpoint { public async HttpResult handle_request(HttpContext http_context, RouteContext route) throws Error { var accept = http_context.request.get_header("Accept") ?? "*/*"; if (accept.contains("application/json")) { return new HttpStringResult(@"{ \"message\": \"JSON response\", \"format\": \"json\" }") .set_header("Content-Type", "application/json"); } else if (accept.contains("text/xml")) { return new HttpStringResult(@"XML responsexml") .set_header("Content-Type", "text/xml"); } else { return new HttpStringResult("Plain text response") .set_header("Content-Type", "text/plain"); } } } // Security headers class SecureEndpoint : Object, Endpoint { public async HttpResult handle_request(HttpContext http_context, RouteContext route) throws Error { return new HttpStringResult("Response with security headers!") .set_header("X-Content-Type-Options", "nosniff") .set_header("X-Frame-Options", "DENY") .set_header("X-XSS-Protection", "1; mode=block") .set_header("Strict-Transport-Security", "max-age=31536000; includeSubDomains") .set_header("Content-Security-Policy", "default-src 'self'") .set_header("Referrer-Policy", "strict-origin-when-cross-origin"); } } void main() { var application = new WebApplication(8083); application.container.register_scoped(() => new HeadersEndpoint()) .with_metadata(new EndpointRoute("/headers")); application.container.register_scoped(() => new UserAgentEndpoint()) .with_metadata(new EndpointRoute("/user-agent")); application.container.register_scoped(() => new ContentInfoEndpoint()) .with_metadata(new EndpointRoute("/content-info")); application.container.register_scoped(() => new CheckHeaderEndpoint()) .with_metadata(new EndpointRoute("/check-header")); application.container.register_scoped(() => new CustomHeadersEndpoint()) .with_metadata(new EndpointRoute("/custom-headers")); application.container.register_scoped(() => new CookiesEndpoint()) .with_metadata(new EndpointRoute("/cookies")); application.container.register_scoped(() => new GetCookieEndpoint()) .with_metadata(new EndpointRoute("/get-cookie")); application.container.register_scoped(() => new SetCookieEndpoint()) .with_metadata(new EndpointRoute("/set-cookie")); application.container.register_scoped(() => new SetCookiesEndpoint()) .with_metadata(new EndpointRoute("/set-cookies")); application.container.register_scoped(() => new DeleteCookieEndpoint()) .with_metadata(new EndpointRoute("/delete-cookie")); application.container.register_scoped(() => new HasCookieEndpoint()) .with_metadata(new EndpointRoute("/has-cookie")); application.container.register_scoped(() => new SessionEndpoint()) .with_metadata(new EndpointRoute("/session")); application.container.register_scoped(() => new CorsEndpoint()) .with_metadata(new EndpointRoute("/cors")); application.container.register_scoped(() => new CacheEndpoint()) .with_metadata(new EndpointRoute("/cache")); application.container.register_scoped(() => new NegotiateEndpoint()) .with_metadata(new EndpointRoute("/negotiate")); application.container.register_scoped(() => new SecureEndpoint()) .with_metadata(new EndpointRoute("/secure")); 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"); application.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"); }