HeadersAndCookies.vala 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305
  1. using Astralis;
  2. using Invercargill;
  3. using Invercargill.DataStructures;
  4. /**
  5. * HeadersAndCookies Example
  6. *
  7. * Demonstrates how to access and manipulate HTTP headers and cookies.
  8. * Uses Invercargill Dictionary and Enumerable for header/cookie processing.
  9. */
  10. // Display all request headers
  11. class HeadersHandler : Object, RouteHandler {
  12. public async HttpResult handle_route(HttpContext http_context, RouteContext route_context) throws Error {
  13. var parts = new Series<string>();
  14. parts.add("Request Headers:\n");
  15. parts.add("================\n\n");
  16. http_context.request.headers.to_immutable_buffer()
  17. .iterate((grouping) => {
  18. grouping.iterate((value) => {
  19. parts.add(@"$(grouping.key): $value\n");
  20. });
  21. });
  22. var result = parts.to_immutable_buffer()
  23. .aggregate<string>("", (acc, s) => acc + s);
  24. return new HttpStringResult(result);
  25. }
  26. }
  27. // Check for user-agent header
  28. class UserAgentHandler : Object, RouteHandler {
  29. public async HttpResult handle_route(HttpContext http_context, RouteContext route_context) throws Error {
  30. var user_agent = http_context.request.user_agent ?? "Unknown";
  31. return new HttpStringResult(@"Your User-Agent is: $user_agent");
  32. }
  33. }
  34. // Check content type and content length
  35. class ContentInfoHandler : Object, RouteHandler {
  36. public async HttpResult handle_route(HttpContext http_context, RouteContext route_context) throws Error {
  37. var parts = new Series<string>();
  38. parts.add("Content Information:\n");
  39. parts.add("===================\n\n");
  40. parts.add(@"Content-Type: $(http_context.request.content_type)\n");
  41. parts.add(@"Content-Length: $(http_context.request.content_length)\n");
  42. parts.add(@"Content-Encoding: $(http_context.request.content_encoding ?? "none")\n");
  43. var result = parts.to_immutable_buffer()
  44. .aggregate<string>("", (acc, s) => acc + s);
  45. return new HttpStringResult(result);
  46. }
  47. }
  48. // Check if header exists
  49. class CheckHeaderHandler : Object, RouteHandler {
  50. public async HttpResult handle_route(HttpContext http_context, RouteContext route_context) throws Error {
  51. var header_name = http_context.request.get_query_or_default("name", "Accept");
  52. var exists = http_context.request.has_header(header_name);
  53. var value = http_context.request.get_header(header_name);
  54. return new HttpStringResult(@"Header '$header_name': $(exists ? "EXISTS" : "NOT FOUND")\nValue: $(value ?? "N/A")");
  55. }
  56. }
  57. // Set custom response headers
  58. class CustomHeadersHandler : Object, RouteHandler {
  59. public async HttpResult handle_route(HttpContext http_context, RouteContext route_context) throws Error {
  60. return new HttpStringResult("Response with custom headers!")
  61. .set_header("X-Custom-Header", "Custom-Value")
  62. .set_header("X-Request-Id", generate_request_id())
  63. .set_header("X-Powered-By", "Astralis")
  64. .set_header("X-Server-Time", new DateTime.now_local().format_iso8601());
  65. }
  66. }
  67. // Display all cookies
  68. class CookiesHandler : Object, RouteHandler {
  69. public async HttpResult handle_route(HttpContext http_context, RouteContext route_context) throws Error {
  70. var parts = new Series<string>();
  71. parts.add("Request Cookies:\n");
  72. parts.add("================\n\n");
  73. if (http_context.request.cookies.to_immutable_buffer().count() == 0) {
  74. parts.add("(No cookies sent)\n");
  75. parts.add("\nTry setting a cookie first: /set-cookie?name=test&value=123\n");
  76. } else {
  77. http_context.request.cookies.to_immutable_buffer()
  78. .iterate((grouping) => {
  79. grouping.iterate((value) => {
  80. parts.add(@"$(grouping.key): $value\n");
  81. });
  82. });
  83. }
  84. var result = parts.to_immutable_buffer()
  85. .aggregate<string>("", (acc, s) => acc + s);
  86. return new HttpStringResult(result);
  87. }
  88. }
  89. // Get specific cookie
  90. class GetCookieHandler : Object, RouteHandler {
  91. public async HttpResult handle_route(HttpContext http_context, RouteContext route_context) throws Error {
  92. var name = http_context.request.get_query_or_default("name", "session");
  93. var value = http_context.request.get_cookie(name);
  94. if (value == null) {
  95. return new HttpStringResult(@"Cookie '$name' not found");
  96. }
  97. return new HttpStringResult(@"Cookie '$name' = '$value'");
  98. }
  99. }
  100. // Set a cookie (via Set-Cookie header)
  101. class SetCookieHandler : Object, RouteHandler {
  102. public async HttpResult handle_route(HttpContext http_context, RouteContext route_context) throws Error {
  103. var name = http_context.request.get_query_or_default("name", "test");
  104. var value = http_context.request.get_query_or_default("value", "123");
  105. var max_age = http_context.request.get_query_or_default("max_age", "3600");
  106. return new HttpStringResult(@"Cookie '$name' set to '$value'")
  107. .set_header("Set-Cookie", @"$name=$value; Max-Age=$max_age; Path=/");
  108. }
  109. }
  110. // Set multiple cookies
  111. class SetCookiesHandler : Object, RouteHandler {
  112. public async HttpResult handle_route(HttpContext http_context, RouteContext route_context) throws Error {
  113. // Note: Setting multiple cookies with the same header name requires
  114. // special handling - this example shows the approach
  115. return new HttpStringResult("Multiple cookies set!")
  116. .set_header("Set-Cookie", "user=john; Max-Age=3600; Path=/");
  117. // Additional cookies would need to be set via multiple Set-Cookie headers
  118. // which requires extending the HttpResult API or using a different approach
  119. }
  120. }
  121. // Delete a cookie
  122. class DeleteCookieHandler : Object, RouteHandler {
  123. public async HttpResult handle_route(HttpContext http_context, RouteContext route_context) throws Error {
  124. var name = http_context.request.get_query_or_default("name", "test");
  125. return new HttpStringResult(@"Cookie '$name' deleted")
  126. .set_header("Set-Cookie", @"$name=; Max-Age=0; Path=/");
  127. }
  128. }
  129. // Check if cookie exists
  130. class HasCookieHandler : Object, RouteHandler {
  131. public async HttpResult handle_route(HttpContext http_context, RouteContext route_context) throws Error {
  132. var name = http_context.request.get_query_or_default("name", "session");
  133. var exists = http_context.request.has_cookie(name);
  134. return new HttpStringResult(@"Cookie '$name': $(exists ? "EXISTS" : "NOT FOUND")");
  135. }
  136. }
  137. // Cookie-based session simulation
  138. class SessionHandler : Object, RouteHandler {
  139. public async HttpResult handle_route(HttpContext http_context, RouteContext route_context) throws Error {
  140. var session_id = http_context.request.get_cookie("session_id");
  141. if (session_id == null) {
  142. // Create new session
  143. var new_session_id = generate_session_id();
  144. return new HttpStringResult(@"New session created!
  145. Session ID: $new_session_id
  146. Your session will expire in 1 hour.")
  147. .set_header("Set-Cookie", @"session_id=$new_session_id; Max-Age=3600; Path=/; HttpOnly");
  148. }
  149. // Existing session
  150. return new HttpStringResult(@"Welcome back!
  151. Session ID: $session_id
  152. Your session is active.");
  153. }
  154. }
  155. // CORS headers example
  156. class CorsHandler : Object, RouteHandler {
  157. public async HttpResult handle_route(HttpContext http_context, RouteContext route_context) throws Error {
  158. var origin = http_context.request.get_header("Origin") ?? "*";
  159. return new HttpStringResult(@"CORS enabled for origin: $origin")
  160. .set_header("Access-Control-Allow-Origin", origin)
  161. .set_header("Access-Control-Allow-Methods", "GET, POST, OPTIONS")
  162. .set_header("Access-Control-Allow-Headers", "Content-Type, Authorization")
  163. .set_header("Access-Control-Max-Age", "86400");
  164. }
  165. }
  166. // Cache control headers
  167. class CacheHandler : Object, RouteHandler {
  168. public async HttpResult handle_route(HttpContext http_context, RouteContext route_context) throws Error {
  169. var cache_type = http_context.request.get_query_or_default("type", "public");
  170. return new HttpStringResult(@"This response is cached ($cache_type cache, 1 hour)")
  171. .set_header("Cache-Control", @"$cache_type, max-age=3600")
  172. .set_header("Expires", get_expires_header(3600))
  173. .set_header("ETag", generate_etag());
  174. }
  175. }
  176. // Content negotiation
  177. class NegotiateHandler : Object, RouteHandler {
  178. public async HttpResult handle_route(HttpContext http_context, RouteContext route_context) throws Error {
  179. var accept = http_context.request.get_header("Accept") ?? "*/*";
  180. if (accept.contains("application/json")) {
  181. return new HttpStringResult(@"{ \"message\": \"JSON response\", \"format\": \"json\" }")
  182. .set_header("Content-Type", "application/json");
  183. } else if (accept.contains("text/xml")) {
  184. return new HttpStringResult(@"<?xml version=\"1.0\"?><response><message>XML response</message><format>xml</format></response>")
  185. .set_header("Content-Type", "text/xml");
  186. } else {
  187. return new HttpStringResult("Plain text response")
  188. .set_header("Content-Type", "text/plain");
  189. }
  190. }
  191. }
  192. // Security headers
  193. class SecureHandler : Object, RouteHandler {
  194. public async HttpResult handle_route(HttpContext http_context, RouteContext route_context) throws Error {
  195. return new HttpStringResult("Response with security headers!")
  196. .set_header("X-Content-Type-Options", "nosniff")
  197. .set_header("X-Frame-Options", "DENY")
  198. .set_header("X-XSS-Protection", "1; mode=block")
  199. .set_header("Strict-Transport-Security", "max-age=31536000; includeSubDomains")
  200. .set_header("Content-Security-Policy", "default-src 'self'")
  201. .set_header("Referrer-Policy", "strict-origin-when-cross-origin");
  202. }
  203. }
  204. void main() {
  205. var router = new Router();
  206. var server = new Server(8083, router);
  207. // Register routes
  208. router.get("/headers", new HeadersHandler());
  209. router.get("/user-agent", new UserAgentHandler());
  210. router.get("/content-info", new ContentInfoHandler());
  211. router.get("/check-header", new CheckHeaderHandler());
  212. router.get("/custom-headers", new CustomHeadersHandler());
  213. router.get("/cookies", new CookiesHandler());
  214. router.get("/get-cookie", new GetCookieHandler());
  215. router.get("/set-cookie", new SetCookieHandler());
  216. router.get("/set-cookies", new SetCookiesHandler());
  217. router.get("/delete-cookie", new DeleteCookieHandler());
  218. router.get("/has-cookie", new HasCookieHandler());
  219. router.get("/session", new SessionHandler());
  220. router.get("/cors", new CorsHandler());
  221. router.get("/cache", new CacheHandler());
  222. router.get("/negotiate", new NegotiateHandler());
  223. router.get("/secure", new SecureHandler());
  224. print("Headers and Cookies Example Server running on port 8083\n");
  225. print("Try these endpoints:\n");
  226. print(" - http://localhost:8083/headers\n");
  227. print(" - http://localhost:8083/user-agent\n");
  228. print(" - http://localhost:8083/cookies\n");
  229. print(" - http://localhost:8083/set-cookie?name=test&value=hello\n");
  230. print(" - http://localhost:8083/set-cookies\n");
  231. print(" - http://localhost:8083/session\n");
  232. print(" - http://localhost:8083/cors\n");
  233. print(" - http://localhost:8083/cache\n");
  234. print(" - http://localhost:8083/negotiate\n");
  235. print(" - http://localhost:8083/secure\n");
  236. server.run();
  237. }
  238. // Helper functions
  239. string generate_request_id() {
  240. var timestamp = new DateTime.now_local().to_unix();
  241. var random = Random.next_int();
  242. return @"req-$timestamp-$random";
  243. }
  244. string generate_session_id() {
  245. var timestamp = new DateTime.now_local().to_unix();
  246. var random = Random.next_int();
  247. return @"sess-$timestamp-$random";
  248. }
  249. string generate_etag() {
  250. var timestamp = new DateTime.now_local().to_unix();
  251. return @"\"$timestamp\"";
  252. }
  253. string get_expires_header(int seconds) {
  254. var now = new DateTime.now_local();
  255. var expires = now.add_seconds(seconds);
  256. return expires.format("%a, %d %b %Y %H:%M:%S GMT");
  257. }