ResourceEndpoint.vala 2.0 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455
  1. using Invercargill;
  2. using Invercargill.DataStructures;
  3. using Inversion;
  4. using Astralis;
  5. namespace Statum {
  6. /**
  7. * `GET /_statum/resource/{name}` — serves precompressed {@link StatumResource}s.
  8. *
  9. * Mirrors the old Spry 0.1 `StaticResourceProvider` (removed in Spry
  10. * 0.2): all registered
  11. * {@link StatumResource}s are collected at construction, the `{name}` segment
  12. * selects one, the best encoding is chosen from `Accept-Encoding`, and
  13. * `ETag`/`If-None-Match` is honoured.
  14. */
  15. public class ResourceEndpoint : Object, Endpoint {
  16. private Dictionary<string, StatumResource> resource_map = inject_all<StatumResource>().to_dictionary<string>(r => r.name);
  17. public async HttpResult handle_request(HttpContext http_context, RouteContext route_context) throws GLib.Error {
  18. var name = route_context.mapped_parameters.get_or_default("name");
  19. if (name == null) {
  20. return new HttpStringResult("No such resource.", StatusCode.NOT_FOUND);
  21. }
  22. StatumResource resource;
  23. if (!resource_map.try_get((!)name, out resource)) {
  24. return new HttpStringResult(@"No such resource \"$((!)name)\".", StatusCode.NOT_FOUND);
  25. }
  26. var accepts = new HashSet<string>();
  27. foreach (var header in http_context.request.headers.get_or_empty("Accept-Encoding")) {
  28. foreach (var token in header.split(",")) {
  29. var encoding = token.strip();
  30. if (encoding.length > 0) {
  31. accepts.add(encoding);
  32. }
  33. }
  34. }
  35. var best = resource.get_best_encoding(accepts);
  36. var etag = resource.get_etag_for(best);
  37. foreach (var header in http_context.request.headers.get_or_empty("If-None-Match")) {
  38. if (header.contains(etag)) {
  39. return new HttpEmptyResult(StatusCode.NOT_MODIFIED);
  40. }
  41. }
  42. return resource.to_result(best);
  43. }
  44. }
  45. }