PackageDownloadEndpoint.vala 1.6 KB

12345678910111213141516171819202122232425262728293031323334353637383940
  1. using Astralis;
  2. namespace UsmWeb {
  3. /**
  4. * `GET /{file}.usmc` — streams a package archive from the repository's
  5. * `public/` directory with an exact content-length, exactly what a USM
  6. * client fetching through this app expects (the bytes match the
  7. * listing's sha512).
  8. *
  9. * The route pattern matches any single segment; requests that do not
  10. * name a `.usmc` inside `public/` answer 404.
  11. */
  12. public class PackageDownloadEndpoint : Object, Endpoint {
  13. private RepositoryService repositories = Inversion.inject<RepositoryService>();
  14. public async HttpResult handle_request(HttpContext http_context, RouteContext route_context) throws Error {
  15. string file = "";
  16. route_context.mapped_parameters.try_get("file", out file);
  17. if (!file.has_suffix(".usmc") || file.contains("/") || file.contains("..")) {
  18. return new HttpStringResult("Not Found", StatusCode.NOT_FOUND);
  19. }
  20. var path = repositories.package_location(file);
  21. var handle = File.new_for_path(path);
  22. if (!handle.query_exists()) {
  23. return new HttpStringResult("No such package", StatusCode.NOT_FOUND);
  24. }
  25. var info = yield handle.query_info_async(
  26. FileAttribute.STANDARD_SIZE, FileQueryInfoFlags.NONE);
  27. var result = new HttpStreamResult(yield handle.read_async(), info.get_size());
  28. result.set_header("Content-Type", "application/octet-stream");
  29. result.set_flag(HttpResultFlag.DO_NOT_COMPRESS);
  30. return result;
  31. }
  32. }
  33. }