You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

ObjectFileServlet.java 4.2KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149
  1. /*
  2. * Copyright (C) 2009-2010, Google Inc. and others
  3. *
  4. * This program and the accompanying materials are made available under the
  5. * terms of the Eclipse Distribution License v. 1.0 which is available at
  6. * https://www.eclipse.org/org/documents/edl-v10.php.
  7. *
  8. * SPDX-License-Identifier: BSD-3-Clause
  9. */
  10. package org.eclipse.jgit.http.server;
  11. import static javax.servlet.http.HttpServletResponse.SC_NOT_FOUND;
  12. import static javax.servlet.http.HttpServletResponse.SC_NOT_MODIFIED;
  13. import static org.eclipse.jgit.http.server.ServletUtils.getRepository;
  14. import static org.eclipse.jgit.util.HttpSupport.HDR_ETAG;
  15. import static org.eclipse.jgit.util.HttpSupport.HDR_IF_MODIFIED_SINCE;
  16. import static org.eclipse.jgit.util.HttpSupport.HDR_IF_NONE_MATCH;
  17. import static org.eclipse.jgit.util.HttpSupport.HDR_LAST_MODIFIED;
  18. import java.io.File;
  19. import java.io.FileNotFoundException;
  20. import java.io.IOException;
  21. import java.time.Instant;
  22. import javax.servlet.ServletException;
  23. import javax.servlet.http.HttpServlet;
  24. import javax.servlet.http.HttpServletRequest;
  25. import javax.servlet.http.HttpServletResponse;
  26. import org.eclipse.jgit.internal.storage.file.ObjectDirectory;
  27. import org.eclipse.jgit.lib.Repository;
  28. /** Sends any object from {@code GIT_DIR/objects/??/0 38}, or any pack file. */
  29. abstract class ObjectFileServlet extends HttpServlet {
  30. private static final long serialVersionUID = 1L;
  31. static class Loose extends ObjectFileServlet {
  32. private static final long serialVersionUID = 1L;
  33. Loose() {
  34. super("application/x-git-loose-object");
  35. }
  36. @Override
  37. String etag(FileSender sender) throws IOException {
  38. Instant lastModified = sender.getLastModified();
  39. return Long.toHexString(lastModified.getEpochSecond())
  40. + Long.toHexString(lastModified.getNano());
  41. }
  42. }
  43. private static abstract class PackData extends ObjectFileServlet {
  44. private static final long serialVersionUID = 1L;
  45. PackData(String contentType) {
  46. super(contentType);
  47. }
  48. @Override
  49. String etag(FileSender sender) throws IOException {
  50. return sender.getTailChecksum();
  51. }
  52. }
  53. static class Pack extends PackData {
  54. private static final long serialVersionUID = 1L;
  55. Pack() {
  56. super("application/x-git-packed-objects");
  57. }
  58. }
  59. static class PackIdx extends PackData {
  60. private static final long serialVersionUID = 1L;
  61. PackIdx() {
  62. super("application/x-git-packed-objects-toc");
  63. }
  64. }
  65. private final String contentType;
  66. ObjectFileServlet(String contentType) {
  67. this.contentType = contentType;
  68. }
  69. abstract String etag(FileSender sender) throws IOException;
  70. /** {@inheritDoc} */
  71. @Override
  72. public void doGet(final HttpServletRequest req,
  73. final HttpServletResponse rsp) throws IOException {
  74. serve(req, rsp, true);
  75. }
  76. /** {@inheritDoc} */
  77. @Override
  78. protected void doHead(final HttpServletRequest req,
  79. final HttpServletResponse rsp) throws ServletException, IOException {
  80. serve(req, rsp, false);
  81. }
  82. private void serve(final HttpServletRequest req,
  83. final HttpServletResponse rsp, final boolean sendBody)
  84. throws IOException {
  85. final File obj = new File(objects(req), req.getPathInfo());
  86. final FileSender sender;
  87. try {
  88. sender = new FileSender(obj);
  89. } catch (FileNotFoundException e) {
  90. rsp.sendError(SC_NOT_FOUND);
  91. return;
  92. }
  93. try {
  94. final String etag = etag(sender);
  95. // HTTP header Last-Modified header has a resolution of 1 sec, see
  96. // https://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.29
  97. final long lastModified = sender.getLastModified().getEpochSecond();
  98. String ifNoneMatch = req.getHeader(HDR_IF_NONE_MATCH);
  99. if (etag != null && etag.equals(ifNoneMatch)) {
  100. rsp.sendError(SC_NOT_MODIFIED);
  101. return;
  102. }
  103. long ifModifiedSince = req.getDateHeader(HDR_IF_MODIFIED_SINCE);
  104. if (0 < lastModified && lastModified < ifModifiedSince) {
  105. rsp.sendError(SC_NOT_MODIFIED);
  106. return;
  107. }
  108. if (etag != null)
  109. rsp.setHeader(HDR_ETAG, etag);
  110. if (0 < lastModified)
  111. rsp.setDateHeader(HDR_LAST_MODIFIED, lastModified);
  112. rsp.setContentType(contentType);
  113. sender.serve(req, rsp, sendBody);
  114. } finally {
  115. sender.close();
  116. }
  117. }
  118. private static File objects(HttpServletRequest req) {
  119. final Repository db = getRepository(req);
  120. return ((ObjectDirectory) db.getObjectDatabase()).getDirectory();
  121. }
  122. }