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.

ReceivePackServlet.java 6.4KB

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