1
2
3
4
5
6
7
8
9
10
11 package org.eclipse.jgit.http.server;
12
13 import static javax.servlet.http.HttpServletResponse.SC_NOT_FOUND;
14 import static javax.servlet.http.HttpServletResponse.SC_NOT_MODIFIED;
15 import static org.eclipse.jgit.http.server.ServletUtils.getRepository;
16 import static org.eclipse.jgit.util.HttpSupport.HDR_ETAG;
17 import static org.eclipse.jgit.util.HttpSupport.HDR_IF_MODIFIED_SINCE;
18 import static org.eclipse.jgit.util.HttpSupport.HDR_IF_NONE_MATCH;
19 import static org.eclipse.jgit.util.HttpSupport.HDR_LAST_MODIFIED;
20
21 import java.io.File;
22 import java.io.FileNotFoundException;
23 import java.io.IOException;
24 import java.time.Instant;
25
26 import javax.servlet.ServletException;
27 import javax.servlet.http.HttpServlet;
28 import javax.servlet.http.HttpServletRequest;
29 import javax.servlet.http.HttpServletResponse;
30
31 import org.eclipse.jgit.internal.storage.file.ObjectDirectory;
32 import org.eclipse.jgit.lib.Repository;
33
34
35 abstract class ObjectFileServlet extends HttpServlet {
36 private static final long serialVersionUID = 1L;
37
38 static class Loose extends ObjectFileServlet {
39 private static final long serialVersionUID = 1L;
40
41 Loose() {
42 super("application/x-git-loose-object");
43 }
44
45 @Override
46 String etag(FileSender sender) throws IOException {
47 Instant lastModified = sender.getLastModified();
48 return Long.toHexString(lastModified.getEpochSecond())
49 + Long.toHexString(lastModified.getNano());
50 }
51 }
52
53 private abstract static class PackData extends ObjectFileServlet {
54 private static final long serialVersionUID = 1L;
55
56 PackData(String contentType) {
57 super(contentType);
58 }
59
60 @Override
61 String etag(FileSender sender) throws IOException {
62 return sender.getTailChecksum();
63 }
64 }
65
66 static class Pack extends PackData {
67 private static final long serialVersionUID = 1L;
68
69 Pack() {
70 super("application/x-git-packed-objects");
71 }
72 }
73
74 static class PackIdx extends PackData {
75 private static final long serialVersionUID = 1L;
76
77 PackIdx() {
78 super("application/x-git-packed-objects-toc");
79 }
80 }
81
82 private final String contentType;
83
84 ObjectFileServlet(String contentType) {
85 this.contentType = contentType;
86 }
87
88 abstract String etag(FileSender sender) throws IOException;
89
90
91 @Override
92 public void doGet(final HttpServletRequest req,
93 final HttpServletResponse rsp) throws IOException {
94 serve(req, rsp, true);
95 }
96
97
98 @Override
99 protected void doHead(final HttpServletRequest req,
100 final HttpServletResponse rsp) throws ServletException, IOException {
101 serve(req, rsp, false);
102 }
103
104 private void serve(final HttpServletRequest req,
105 final HttpServletResponse rsp, final boolean sendBody)
106 throws IOException {
107 final File obj = new File(objects(req), req.getPathInfo());
108 final FileSender sender;
109 try {
110 sender = new FileSender(obj);
111 } catch (FileNotFoundException e) {
112 rsp.sendError(SC_NOT_FOUND);
113 return;
114 }
115
116 try {
117 final String etag = etag(sender);
118
119
120 final long lastModified = sender.getLastModified().getEpochSecond();
121
122 String ifNoneMatch = req.getHeader(HDR_IF_NONE_MATCH);
123 if (etag != null && etag.equals(ifNoneMatch)) {
124 rsp.sendError(SC_NOT_MODIFIED);
125 return;
126 }
127
128 long ifModifiedSince = req.getDateHeader(HDR_IF_MODIFIED_SINCE);
129 if (0 < lastModified && lastModified < ifModifiedSince) {
130 rsp.sendError(SC_NOT_MODIFIED);
131 return;
132 }
133
134 if (etag != null)
135 rsp.setHeader(HDR_ETAG, etag);
136 if (0 < lastModified)
137 rsp.setDateHeader(HDR_LAST_MODIFIED, lastModified);
138 rsp.setContentType(contentType);
139 sender.serve(req, rsp, sendBody);
140 } finally {
141 sender.close();
142 }
143 }
144
145 private static File objects(HttpServletRequest req) {
146 final Repository db = getRepository(req);
147 return ((ObjectDirectory) db.getObjectDatabase()).getDirectory();
148 }
149 }