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