HeadersAndCookies.vala 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378
  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 BufferedHttpResult.from_string(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 BufferedHttpResult.from_string(
  32. @"Your User-Agent is: $user_agent"
  33. );
  34. }
  35. }
  36. // Check content type and content length
  37. class ContentInfoHandler : Object, RouteHandler {
  38. public async HttpResult handle_route(HttpContext http_context, RouteContext route_context) throws Error {
  39. var parts = new Series<string>();
  40. parts.add("Content Information:\n");
  41. parts.add("===================\n\n");
  42. parts.add(@"Content-Type: $(http_context.request.content_type)\n");
  43. parts.add(@"Content-Length: $(http_context.request.content_length)\n");
  44. parts.add(@"Content-Encoding: $(http_context.request.content_encoding ?? "none")\n");
  45. var result = parts.to_immutable_buffer()
  46. .aggregate<string>("", (acc, s) => acc + s);
  47. return new BufferedHttpResult.from_string(result);
  48. }
  49. }
  50. // Check if header exists
  51. class CheckHeaderHandler : Object, RouteHandler {
  52. public async HttpResult handle_route(HttpContext http_context, RouteContext route_context) throws Error {
  53. var header_name = http_context.request.get_query_or_default("name", "Accept");
  54. var exists = http_context.request.has_header(header_name);
  55. var value = http_context.request.get_header(header_name);
  56. return new BufferedHttpResult.from_string(
  57. @"Header '$header_name': $(exists ? "EXISTS" : "NOT FOUND")\nValue: $(value ?? "N/A")"
  58. );
  59. }
  60. }
  61. // Set custom response headers
  62. class CustomHeadersHandler : Object, RouteHandler {
  63. public async HttpResult handle_route(HttpContext http_context, RouteContext route_context) throws Error {
  64. var headers = new Catalogue<string, string>();
  65. headers.add("X-Custom-Header", "Custom-Value");
  66. headers.add("X-Request-Id", generate_request_id());
  67. headers.add("X-Powered-By", "Astralis");
  68. headers.add("X-Server-Time", new DateTime.now_local().format_iso8601());
  69. return new BufferedHttpResult.from_string(
  70. "Response with custom headers!",
  71. StatusCode.OK,
  72. headers
  73. );
  74. }
  75. }
  76. // Display all cookies
  77. class CookiesHandler : Object, RouteHandler {
  78. public async HttpResult handle_route(HttpContext http_context, RouteContext route_context) throws Error {
  79. var parts = new Series<string>();
  80. parts.add("Request Cookies:\n");
  81. parts.add("================\n\n");
  82. if (http_context.request.cookies.to_immutable_buffer().count() == 0) {
  83. parts.add("(No cookies sent)\n");
  84. parts.add("\nTry setting a cookie first: /set-cookie?name=test&value=123\n");
  85. } else {
  86. http_context.request.cookies.to_immutable_buffer()
  87. .iterate((grouping) => {
  88. grouping.iterate((value) => {
  89. parts.add(@"$(grouping.key): $value\n");
  90. });
  91. });
  92. }
  93. var result = parts.to_immutable_buffer()
  94. .aggregate<string>("", (acc, s) => acc + s);
  95. return new BufferedHttpResult.from_string(result);
  96. }
  97. }
  98. // Get specific cookie
  99. class GetCookieHandler : Object, RouteHandler {
  100. public async HttpResult handle_route(HttpContext http_context, RouteContext route_context) throws Error {
  101. var name = http_context.request.get_query_or_default("name", "session");
  102. var value = http_context.request.get_cookie(name);
  103. if (value == null) {
  104. return new BufferedHttpResult.from_string(
  105. @"Cookie '$name' not found",
  106. StatusCode.NOT_FOUND
  107. );
  108. }
  109. return new BufferedHttpResult.from_string(
  110. @"Cookie '$name' = '$value'"
  111. );
  112. }
  113. }
  114. // Set a cookie (via Set-Cookie header)
  115. class SetCookieHandler : Object, RouteHandler {
  116. public async HttpResult handle_route(HttpContext http_context, RouteContext route_context) throws Error {
  117. var name = http_context.request.get_query_or_default("name", "test");
  118. var value = http_context.request.get_query_or_default("value", "123");
  119. var max_age = http_context.request.get_query_or_default("max_age", "3600");
  120. var headers = new Catalogue<string, string>();
  121. headers.add("Set-Cookie", @"$name=$value; Max-Age=$max_age; Path=/");
  122. return new BufferedHttpResult.from_string(
  123. @"Cookie '$name' set to '$value'",
  124. StatusCode.OK,
  125. headers
  126. );
  127. }
  128. }
  129. // Set multiple cookies
  130. class SetCookiesHandler : Object, RouteHandler {
  131. public async HttpResult handle_route(HttpContext http_context, RouteContext route_context) throws Error {
  132. var headers = new Catalogue<string, string>();
  133. headers.add("Set-Cookie", "user=john; Max-Age=3600; Path=/");
  134. headers.add("Set-Cookie", "theme=dark; Max-Age=86400; Path=/");
  135. headers.add("Set-Cookie", "lang=en; Max-Age=31536000; Path=/");
  136. return new BufferedHttpResult.from_string(
  137. "Multiple cookies set!",
  138. StatusCode.OK,
  139. headers
  140. );
  141. }
  142. }
  143. // Delete a cookie
  144. class DeleteCookieHandler : Object, RouteHandler {
  145. public async HttpResult handle_route(HttpContext http_context, RouteContext route_context) throws Error {
  146. var name = http_context.request.get_query_or_default("name", "test");
  147. var headers = new Catalogue<string, string>();
  148. headers.add("Set-Cookie", @"$name=; Max-Age=0; Path=/");
  149. return new BufferedHttpResult.from_string(
  150. @"Cookie '$name' deleted",
  151. StatusCode.OK,
  152. headers
  153. );
  154. }
  155. }
  156. // Check if cookie exists
  157. class HasCookieHandler : Object, RouteHandler {
  158. public async HttpResult handle_route(HttpContext http_context, RouteContext route_context) throws Error {
  159. var name = http_context.request.get_query_or_default("name", "session");
  160. var exists = http_context.request.has_cookie(name);
  161. return new BufferedHttpResult.from_string(
  162. @"Cookie '$name': $(exists ? "EXISTS" : "NOT FOUND")"
  163. );
  164. }
  165. }
  166. // Cookie-based session simulation
  167. class SessionHandler : Object, RouteHandler {
  168. public async HttpResult handle_route(HttpContext http_context, RouteContext route_context) throws Error {
  169. var session_id = http_context.request.get_cookie("session_id");
  170. if (session_id == null) {
  171. // Create new session
  172. var new_session_id = generate_session_id();
  173. var headers = new Catalogue<string, string>();
  174. headers.add("Set-Cookie", @"session_id=$new_session_id; Max-Age=3600; Path=/; HttpOnly");
  175. return new BufferedHttpResult.from_string(
  176. @"New session created!
  177. Session ID: $new_session_id
  178. Your session will expire in 1 hour.",
  179. StatusCode.OK,
  180. headers
  181. );
  182. }
  183. // Existing session
  184. return new BufferedHttpResult.from_string(
  185. @"Welcome back!
  186. Session ID: $session_id
  187. Your session is active."
  188. );
  189. }
  190. }
  191. // CORS headers example
  192. class CorsHandler : Object, RouteHandler {
  193. public async HttpResult handle_route(HttpContext http_context, RouteContext route_context) throws Error {
  194. var origin = http_context.request.get_header("Origin") ?? "*";
  195. var headers = new Catalogue<string, string>();
  196. headers.add("Access-Control-Allow-Origin", origin);
  197. headers.add("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
  198. headers.add("Access-Control-Allow-Headers", "Content-Type, Authorization");
  199. headers.add("Access-Control-Max-Age", "86400");
  200. return new BufferedHttpResult.from_string(
  201. @"CORS enabled for origin: $origin",
  202. StatusCode.OK,
  203. headers
  204. );
  205. }
  206. }
  207. // Cache control headers
  208. class CacheHandler : Object, RouteHandler {
  209. public async HttpResult handle_route(HttpContext http_context, RouteContext route_context) throws Error {
  210. var cache_type = http_context.request.get_query_or_default("type", "public");
  211. var headers = new Catalogue<string, string>();
  212. headers.add("Cache-Control", @"$cache_type, max-age=3600");
  213. headers.add("Expires", get_expires_header(3600));
  214. headers.add("ETag", generate_etag());
  215. return new BufferedHttpResult.from_string(
  216. @"This response is cached ($cache_type cache, 1 hour)",
  217. StatusCode.OK,
  218. headers
  219. );
  220. }
  221. }
  222. // Content negotiation
  223. class NegotiateHandler : Object, RouteHandler {
  224. public async HttpResult handle_route(HttpContext http_context, RouteContext route_context) throws Error {
  225. var accept = http_context.request.get_header("Accept") ?? "*/*";
  226. var headers = new Catalogue<string, string>();
  227. if (accept.contains("application/json")) {
  228. headers.add("Content-Type", "application/json");
  229. return new BufferedHttpResult.from_string(
  230. @"{ \"message\": \"JSON response\", \"format\": \"json\" }",
  231. StatusCode.OK,
  232. headers
  233. );
  234. } else if (accept.contains("text/xml")) {
  235. headers.add("Content-Type", "text/xml");
  236. return new BufferedHttpResult.from_string(
  237. @"<?xml version=\"1.0\"?><response><message>XML response</message><format>xml</format></response>",
  238. StatusCode.OK,
  239. headers
  240. );
  241. } else {
  242. headers.add("Content-Type", "text/plain");
  243. return new BufferedHttpResult.from_string(
  244. "Plain text response",
  245. StatusCode.OK,
  246. headers
  247. );
  248. }
  249. }
  250. }
  251. // Security headers
  252. class SecureHandler : Object, RouteHandler {
  253. public async HttpResult handle_route(HttpContext http_context, RouteContext route_context) throws Error {
  254. var headers = new Catalogue<string, string>();
  255. headers.add("X-Content-Type-Options", "nosniff");
  256. headers.add("X-Frame-Options", "DENY");
  257. headers.add("X-XSS-Protection", "1; mode=block");
  258. headers.add("Strict-Transport-Security", "max-age=31536000; includeSubDomains");
  259. headers.add("Content-Security-Policy", "default-src 'self'");
  260. headers.add("Referrer-Policy", "strict-origin-when-cross-origin");
  261. return new BufferedHttpResult.from_string(
  262. "Response with security headers!",
  263. StatusCode.OK,
  264. headers
  265. );
  266. }
  267. }
  268. void main() {
  269. var router = new Router();
  270. var server = new Server(8083, router);
  271. // Register routes
  272. router.get("/headers", new HeadersHandler());
  273. router.get("/user-agent", new UserAgentHandler());
  274. router.get("/content-info", new ContentInfoHandler());
  275. router.get("/check-header", new CheckHeaderHandler());
  276. router.get("/custom-headers", new CustomHeadersHandler());
  277. router.get("/cookies", new CookiesHandler());
  278. router.get("/get-cookie", new GetCookieHandler());
  279. router.get("/set-cookie", new SetCookieHandler());
  280. router.get("/set-cookies", new SetCookiesHandler());
  281. router.get("/delete-cookie", new DeleteCookieHandler());
  282. router.get("/has-cookie", new HasCookieHandler());
  283. router.get("/session", new SessionHandler());
  284. router.get("/cors", new CorsHandler());
  285. router.get("/cache", new CacheHandler());
  286. router.get("/negotiate", new NegotiateHandler());
  287. router.get("/secure", new SecureHandler());
  288. print("Headers and Cookies Example Server running on port 8083\n");
  289. print("Try these endpoints:\n");
  290. print(" - http://localhost:8083/headers\n");
  291. print(" - http://localhost:8083/user-agent\n");
  292. print(" - http://localhost:8083/cookies\n");
  293. print(" - http://localhost:8083/set-cookie?name=test&value=hello\n");
  294. print(" - http://localhost:8083/set-cookies\n");
  295. print(" - http://localhost:8083/session\n");
  296. print(" - http://localhost:8083/cors\n");
  297. print(" - http://localhost:8083/cache\n");
  298. print(" - http://localhost:8083/negotiate\n");
  299. print(" - http://localhost:8083/secure\n");
  300. server.run();
  301. }
  302. // Helper functions
  303. string generate_request_id() {
  304. var timestamp = new DateTime.now_local().to_unix();
  305. var random = Random.next_int();
  306. return @"req-$timestamp-$random";
  307. }
  308. string generate_session_id() {
  309. var timestamp = new DateTime.now_local().to_unix();
  310. var random = Random.next_int();
  311. return @"sess-$timestamp-$random";
  312. }
  313. string generate_etag() {
  314. var timestamp = new DateTime.now_local().to_unix();
  315. return @"\"$timestamp\"";
  316. }
  317. string get_expires_header(int seconds) {
  318. var now = new DateTime.now_local();
  319. var expires = now.add_seconds(seconds);
  320. return expires.format("%a, %d %b %Y %H:%M:%S GMT");
  321. }