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_FORBIDDEN;
14 import static javax.servlet.http.HttpServletResponse.SC_INTERNAL_SERVER_ERROR;
15 import static javax.servlet.http.HttpServletResponse.SC_UNAUTHORIZED;
16 import static javax.servlet.http.HttpServletResponse.SC_UNSUPPORTED_MEDIA_TYPE;
17 import static org.eclipse.jgit.http.server.GitSmartHttpTools.RECEIVE_PACK;
18 import static org.eclipse.jgit.http.server.GitSmartHttpTools.RECEIVE_PACK_REQUEST_TYPE;
19 import static org.eclipse.jgit.http.server.GitSmartHttpTools.RECEIVE_PACK_RESULT_TYPE;
20 import static org.eclipse.jgit.http.server.GitSmartHttpTools.sendError;
21 import static org.eclipse.jgit.http.server.ServletUtils.ATTRIBUTE_HANDLER;
22 import static org.eclipse.jgit.http.server.ServletUtils.consumeRequestBody;
23 import static org.eclipse.jgit.http.server.ServletUtils.getInputStream;
24 import static org.eclipse.jgit.http.server.ServletUtils.getRepository;
25 import static org.eclipse.jgit.util.HttpSupport.HDR_USER_AGENT;
26
27 import java.io.IOException;
28 import java.text.MessageFormat;
29 import java.util.List;
30
31 import javax.servlet.Filter;
32 import javax.servlet.FilterChain;
33 import javax.servlet.FilterConfig;
34 import javax.servlet.ServletException;
35 import javax.servlet.ServletRequest;
36 import javax.servlet.ServletResponse;
37 import javax.servlet.http.HttpServlet;
38 import javax.servlet.http.HttpServletRequest;
39 import javax.servlet.http.HttpServletResponse;
40
41 import org.eclipse.jgit.annotations.Nullable;
42 import org.eclipse.jgit.errors.CorruptObjectException;
43 import org.eclipse.jgit.errors.PackProtocolException;
44 import org.eclipse.jgit.errors.UnpackException;
45 import org.eclipse.jgit.lib.Repository;
46 import org.eclipse.jgit.transport.InternalHttpServerGlue;
47 import org.eclipse.jgit.transport.ReceivePack;
48 import org.eclipse.jgit.transport.RefAdvertiser.PacketLineOutRefAdvertiser;
49 import org.eclipse.jgit.transport.resolver.ReceivePackFactory;
50 import org.eclipse.jgit.transport.resolver.ServiceNotAuthorizedException;
51 import org.eclipse.jgit.transport.resolver.ServiceNotEnabledException;
52
53
54 class ReceivePackServlet extends HttpServlet {
55 private static final long serialVersionUID = 1L;
56
57 static class InfoRefs extends SmartServiceInfoRefs {
58 private final ReceivePackFactory<HttpServletRequest> receivePackFactory;
59
60 InfoRefs(ReceivePackFactory<HttpServletRequest> receivePackFactory,
61 List<Filter> filters) {
62 super(RECEIVE_PACK, filters);
63 this.receivePackFactory = receivePackFactory;
64 }
65
66 @Override
67 protected void begin(HttpServletRequest req, Repository db)
68 throws IOException, ServiceNotEnabledException,
69 ServiceNotAuthorizedException {
70 ReceivePack rp = receivePackFactory.create(req, db);
71 InternalHttpServerGlue.setPeerUserAgent(
72 rp,
73 req.getHeader(HDR_USER_AGENT));
74 req.setAttribute(ATTRIBUTE_HANDLER, rp);
75 }
76
77 @Override
78 protected void advertise(HttpServletRequest req,
79 PacketLineOutRefAdvertiser pck) throws IOException,
80 ServiceNotEnabledException, ServiceNotAuthorizedException {
81 ReceivePack rp = (ReceivePack) req.getAttribute(ATTRIBUTE_HANDLER);
82 try {
83 rp.sendAdvertisedRefs(pck);
84 } finally {
85 rp.getRevWalk().close();
86 }
87 }
88 }
89
90 static class Factory implements Filter {
91 private final ReceivePackFactory<HttpServletRequest> receivePackFactory;
92
93 Factory(ReceivePackFactory<HttpServletRequest> receivePackFactory) {
94 this.receivePackFactory = receivePackFactory;
95 }
96
97 @Override
98 public void doFilter(ServletRequest request, ServletResponse response,
99 FilterChain chain) throws IOException, ServletException {
100 HttpServletRequest req = (HttpServletRequest) request;
101 HttpServletResponse rsp = (HttpServletResponse) response;
102 ReceivePack rp;
103 try {
104 rp = receivePackFactory.create(req, getRepository(req));
105 } catch (ServiceNotAuthorizedException e) {
106 rsp.sendError(SC_UNAUTHORIZED, e.getMessage());
107 return;
108 } catch (ServiceNotEnabledException e) {
109 sendError(req, rsp, SC_FORBIDDEN, e.getMessage());
110 return;
111 }
112
113 try {
114 req.setAttribute(ATTRIBUTE_HANDLER, rp);
115 chain.doFilter(req, rsp);
116 } finally {
117 req.removeAttribute(ATTRIBUTE_HANDLER);
118 }
119 }
120
121 @Override
122 public void init(FilterConfig filterConfig) throws ServletException {
123
124 }
125
126 @Override
127 public void destroy() {
128
129 }
130 }
131
132 @Nullable
133 private final ReceivePackErrorHandler handler;
134
135 ReceivePackServlet(@Nullable ReceivePackErrorHandler handler) {
136 this.handler = handler;
137 }
138
139
140 @Override
141 public void doPost(final HttpServletRequest req,
142 final HttpServletResponse rsp) throws IOException {
143 if (!RECEIVE_PACK_REQUEST_TYPE.equals(req.getContentType())) {
144 rsp.sendError(SC_UNSUPPORTED_MEDIA_TYPE);
145 return;
146 }
147
148 SmartOutputStream out = new SmartOutputStream(req, rsp, false) {
149 @Override
150 public void flush() throws IOException {
151 doFlush();
152 }
153 };
154
155 ReceivePack rp = (ReceivePack) req.getAttribute(ATTRIBUTE_HANDLER);
156 rp.setBiDirectionalPipe(false);
157 rsp.setContentType(RECEIVE_PACK_RESULT_TYPE);
158
159 if (handler != null) {
160 handler.receive(req, rsp, () -> {
161 rp.receiveWithExceptionPropagation(getInputStream(req), out,
162 null);
163 out.close();
164 });
165 } else {
166 try {
167 rp.receive(getInputStream(req), out, null);
168 out.close();
169 } catch (CorruptObjectException e ) {
170
171 getServletContext().log(MessageFormat.format(
172 HttpServerText.get().receivedCorruptObject,
173 e.getMessage(),
174 ServletUtils.identify(rp.getRepository())));
175 consumeRequestBody(req);
176 out.close();
177
178 } catch (UnpackException | PackProtocolException e) {
179
180 log(rp.getRepository(), e.getCause());
181 consumeRequestBody(req);
182 out.close();
183
184 } catch (Throwable e) {
185 log(rp.getRepository(), e);
186 if (!rsp.isCommitted()) {
187 rsp.reset();
188 sendError(req, rsp, SC_INTERNAL_SERVER_ERROR);
189 }
190 return;
191 }
192 }
193 }
194
195 private void log(Repository git, Throwable e) {
196 getServletContext().log(MessageFormat.format(
197 HttpServerText.get().internalErrorDuringReceivePack,
198 ServletUtils.identify(git)), e);
199 }
200 }