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
58 import javax.servlet.ServletException;
59 import javax.servlet.http.HttpServlet;
60 import javax.servlet.http.HttpServletRequest;
61 import javax.servlet.http.HttpServletResponse;
62
63 import org.eclipse.jgit.internal.storage.file.ObjectDirectory;
64 import org.eclipse.jgit.lib.Repository;
65
66
67 abstract class ObjectFileServlet extends HttpServlet {
68 private static final long serialVersionUID = 1L;
69
70 static class Loose extends ObjectFileServlet {
71 private static final long serialVersionUID = 1L;
72
73 Loose() {
74 super("application/x-git-loose-object");
75 }
76
77 @Override
78 String etag(FileSender sender) throws IOException {
79 return Long.toHexString(sender.getLastModified());
80 }
81 }
82
83 private static abstract class PackData extends ObjectFileServlet {
84 private static final long serialVersionUID = 1L;
85
86 PackData(String contentType) {
87 super(contentType);
88 }
89
90 @Override
91 String etag(FileSender sender) throws IOException {
92 return sender.getTailChecksum();
93 }
94 }
95
96 static class Pack extends PackData {
97 private static final long serialVersionUID = 1L;
98
99 Pack() {
100 super("application/x-git-packed-objects");
101 }
102 }
103
104 static class PackIdx extends PackData {
105 private static final long serialVersionUID = 1L;
106
107 PackIdx() {
108 super("application/x-git-packed-objects-toc");
109 }
110 }
111
112 private final String contentType;
113
114 ObjectFileServlet(String contentType) {
115 this.contentType = contentType;
116 }
117
118 abstract String etag(FileSender sender) throws IOException;
119
120
121 @Override
122 public void doGet(final HttpServletRequest req,
123 final HttpServletResponse rsp) throws IOException {
124 serve(req, rsp, true);
125 }
126
127
128 @Override
129 protected void doHead(final HttpServletRequest req,
130 final HttpServletResponse rsp) throws ServletException, IOException {
131 serve(req, rsp, false);
132 }
133
134 private void serve(final HttpServletRequest req,
135 final HttpServletResponse rsp, final boolean sendBody)
136 throws IOException {
137 final File obj = new File(objects(req), req.getPathInfo());
138 final FileSender sender;
139 try {
140 sender = new FileSender(obj);
141 } catch (FileNotFoundException e) {
142 rsp.sendError(SC_NOT_FOUND);
143 return;
144 }
145
146 try {
147 final String etag = etag(sender);
148 final long lastModified = (sender.getLastModified() / 1000) * 1000;
149
150 String ifNoneMatch = req.getHeader(HDR_IF_NONE_MATCH);
151 if (etag != null && etag.equals(ifNoneMatch)) {
152 rsp.sendError(SC_NOT_MODIFIED);
153 return;
154 }
155
156 long ifModifiedSince = req.getDateHeader(HDR_IF_MODIFIED_SINCE);
157 if (0 < lastModified && lastModified < ifModifiedSince) {
158 rsp.sendError(SC_NOT_MODIFIED);
159 return;
160 }
161
162 if (etag != null)
163 rsp.setHeader(HDR_ETAG, etag);
164 if (0 < lastModified)
165 rsp.setDateHeader(HDR_LAST_MODIFIED, lastModified);
166 rsp.setContentType(contentType);
167 sender.serve(req, rsp, sendBody);
168 } finally {
169 sender.close();
170 }
171 }
172
173 private static File objects(HttpServletRequest req) {
174 final Repository db = getRepository(req);
175 return ((ObjectDirectory) db.getObjectDatabase()).getDirectory();
176 }
177 }