xref: /JGit/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/SmartServiceInfoRefs.java (revision 5c5f7c6b146b24f2bd4afae1902df85ad6e57ea3)
181fea92eSShawn O. Pearce /*
2*5c5f7c6bSMatthias Sohn  * Copyright (C) 2009-2010, Google Inc. and others
381fea92eSShawn O. Pearce  *
4*5c5f7c6bSMatthias Sohn  * This program and the accompanying materials are made available under the
5*5c5f7c6bSMatthias Sohn  * terms of the Eclipse Distribution License v. 1.0 which is available at
6*5c5f7c6bSMatthias Sohn  * https://www.eclipse.org/org/documents/edl-v10.php.
781fea92eSShawn O. Pearce  *
8*5c5f7c6bSMatthias Sohn  * SPDX-License-Identifier: BSD-3-Clause
981fea92eSShawn O. Pearce  */
1081fea92eSShawn O. Pearce 
1181fea92eSShawn O. Pearce package org.eclipse.jgit.http.server;
1281fea92eSShawn O. Pearce 
1381fea92eSShawn O. Pearce import static javax.servlet.http.HttpServletResponse.SC_FORBIDDEN;
1481fea92eSShawn O. Pearce import static javax.servlet.http.HttpServletResponse.SC_UNAUTHORIZED;
15867087bbSShawn O. Pearce import static org.eclipse.jgit.http.server.GitSmartHttpTools.infoRefsResultType;
16867087bbSShawn O. Pearce import static org.eclipse.jgit.http.server.GitSmartHttpTools.sendError;
17af3562f7SShawn O. Pearce import static org.eclipse.jgit.http.server.ServletUtils.ATTRIBUTE_HANDLER;
1881fea92eSShawn O. Pearce import static org.eclipse.jgit.http.server.ServletUtils.getRepository;
1981fea92eSShawn O. Pearce 
2081fea92eSShawn O. Pearce import java.io.IOException;
21af3562f7SShawn O. Pearce import java.util.List;
2281fea92eSShawn O. Pearce 
2381fea92eSShawn O. Pearce import javax.servlet.Filter;
2481fea92eSShawn O. Pearce import javax.servlet.FilterChain;
2581fea92eSShawn O. Pearce import javax.servlet.FilterConfig;
2681fea92eSShawn O. Pearce import javax.servlet.ServletException;
2781fea92eSShawn O. Pearce import javax.servlet.ServletRequest;
2881fea92eSShawn O. Pearce import javax.servlet.ServletResponse;
2981fea92eSShawn O. Pearce import javax.servlet.http.HttpServletRequest;
3081fea92eSShawn O. Pearce import javax.servlet.http.HttpServletResponse;
3181fea92eSShawn O. Pearce 
3281fea92eSShawn O. Pearce import org.eclipse.jgit.lib.Repository;
3381fea92eSShawn O. Pearce import org.eclipse.jgit.transport.PacketLineOut;
3481fea92eSShawn O. Pearce import org.eclipse.jgit.transport.RefAdvertiser.PacketLineOutRefAdvertiser;
351f2022e3SDave Borowitz import org.eclipse.jgit.transport.ServiceMayNotContinueException;
361b7a5a29SShawn O. Pearce import org.eclipse.jgit.transport.resolver.ServiceNotAuthorizedException;
371b7a5a29SShawn O. Pearce import org.eclipse.jgit.transport.resolver.ServiceNotEnabledException;
3881fea92eSShawn O. Pearce 
3981fea92eSShawn O. Pearce /** Filter in front of {@link InfoRefsServlet} to catch smart service requests. */
4081fea92eSShawn O. Pearce abstract class SmartServiceInfoRefs implements Filter {
4181fea92eSShawn O. Pearce 	private final String svc;
4281fea92eSShawn O. Pearce 
43af3562f7SShawn O. Pearce 	private final Filter[] filters;
44af3562f7SShawn O. Pearce 
SmartServiceInfoRefs(String service, List<Filter> filters)45f3ec7cf3SHan-Wen Nienhuys 	SmartServiceInfoRefs(String service, List<Filter> filters) {
4681fea92eSShawn O. Pearce 		this.svc = service;
472fc00af4SMichael Keppler 		this.filters = filters.toArray(new Filter[0]);
4881fea92eSShawn O. Pearce 	}
4981fea92eSShawn O. Pearce 
503b00041cSMatthias Sohn 	/** {@inheritDoc} */
517ac182f4SDavid Pursehouse 	@Override
init(FilterConfig config)5281fea92eSShawn O. Pearce 	public void init(FilterConfig config) throws ServletException {
5381fea92eSShawn O. Pearce 		// Do nothing.
5481fea92eSShawn O. Pearce 	}
5581fea92eSShawn O. Pearce 
563b00041cSMatthias Sohn 	/** {@inheritDoc} */
577ac182f4SDavid Pursehouse 	@Override
destroy()5881fea92eSShawn O. Pearce 	public void destroy() {
5981fea92eSShawn O. Pearce 		// Do nothing.
6081fea92eSShawn O. Pearce 	}
6181fea92eSShawn O. Pearce 
623b00041cSMatthias Sohn 	/** {@inheritDoc} */
637ac182f4SDavid Pursehouse 	@Override
doFilter(ServletRequest request, ServletResponse response, FilterChain chain)6481fea92eSShawn O. Pearce 	public void doFilter(ServletRequest request, ServletResponse response,
6581fea92eSShawn O. Pearce 			FilterChain chain) throws IOException, ServletException {
6681fea92eSShawn O. Pearce 		final HttpServletRequest req = (HttpServletRequest) request;
67867087bbSShawn O. Pearce 		final HttpServletResponse res = (HttpServletResponse) response;
6881fea92eSShawn O. Pearce 
6981fea92eSShawn O. Pearce 		if (svc.equals(req.getParameter("service"))) {
70af3562f7SShawn O. Pearce 			final Repository db = getRepository(req);
71af3562f7SShawn O. Pearce 			try {
72af3562f7SShawn O. Pearce 				begin(req, db);
73af3562f7SShawn O. Pearce 			} catch (ServiceNotAuthorizedException e) {
74cc4f4f2fSJonathan Nieder 				res.sendError(SC_UNAUTHORIZED, e.getMessage());
75af3562f7SShawn O. Pearce 				return;
76af3562f7SShawn O. Pearce 			} catch (ServiceNotEnabledException e) {
77cbb61760SHector Oswaldo Caballero 				sendError(req, res, SC_FORBIDDEN, e.getMessage());
78af3562f7SShawn O. Pearce 				return;
79af3562f7SShawn O. Pearce 			}
80af3562f7SShawn O. Pearce 
81af3562f7SShawn O. Pearce 			try {
82af3562f7SShawn O. Pearce 				if (filters.length == 0)
83af3562f7SShawn O. Pearce 					service(req, response);
84af3562f7SShawn O. Pearce 				else
85af3562f7SShawn O. Pearce 					new Chain().doFilter(request, response);
86af3562f7SShawn O. Pearce 			} finally {
87af3562f7SShawn O. Pearce 				req.removeAttribute(ATTRIBUTE_HANDLER);
88af3562f7SShawn O. Pearce 			}
89af3562f7SShawn O. Pearce 		} else {
90af3562f7SShawn O. Pearce 			chain.doFilter(request, response);
91af3562f7SShawn O. Pearce 		}
92af3562f7SShawn O. Pearce 	}
93af3562f7SShawn O. Pearce 
service(ServletRequest request, ServletResponse response)94af3562f7SShawn O. Pearce 	private void service(ServletRequest request, ServletResponse response)
95af3562f7SShawn O. Pearce 			throws IOException {
96af3562f7SShawn O. Pearce 		final HttpServletRequest req = (HttpServletRequest) request;
97867087bbSShawn O. Pearce 		final HttpServletResponse res = (HttpServletResponse) response;
98f93a6a72SShawn O. Pearce 		final SmartOutputStream buf = new SmartOutputStream(req, res, true);
9981fea92eSShawn O. Pearce 		try {
100867087bbSShawn O. Pearce 			res.setContentType(infoRefsResultType(svc));
101c0f09389SShawn O. Pearce 
10281fea92eSShawn O. Pearce 			final PacketLineOut out = new PacketLineOut(buf);
103c32a62cdSJonathan Tan 			respond(req, out, svc);
104c0f09389SShawn O. Pearce 			buf.close();
10581fea92eSShawn O. Pearce 		} catch (ServiceNotAuthorizedException e) {
106cc4f4f2fSJonathan Nieder 			res.sendError(SC_UNAUTHORIZED, e.getMessage());
10781fea92eSShawn O. Pearce 		} catch (ServiceNotEnabledException e) {
108cc4f4f2fSJonathan Nieder 			sendError(req, res, SC_FORBIDDEN, e.getMessage());
1091f2022e3SDave Borowitz 		} catch (ServiceMayNotContinueException e) {
11064b524e3SShawn O. Pearce 			if (e.isOutput())
11164b524e3SShawn O. Pearce 				buf.close();
11264b524e3SShawn O. Pearce 			else
113c4e209b2SMasaya Suzuki 				sendError(req, res, e.getStatusCode(), e.getMessage());
11481fea92eSShawn O. Pearce 		}
11581fea92eSShawn O. Pearce 	}
11681fea92eSShawn O. Pearce 
1173b00041cSMatthias Sohn 	/**
1183b00041cSMatthias Sohn 	 * Begin service.
1193b00041cSMatthias Sohn 	 *
1203b00041cSMatthias Sohn 	 * @param req
1213b00041cSMatthias Sohn 	 *            request
1223b00041cSMatthias Sohn 	 * @param db
1233b00041cSMatthias Sohn 	 *            repository
1243b00041cSMatthias Sohn 	 * @throws IOException
1253b00041cSMatthias Sohn 	 * @throws ServiceNotEnabledException
1263b00041cSMatthias Sohn 	 * @throws ServiceNotAuthorizedException
1273b00041cSMatthias Sohn 	 */
begin(HttpServletRequest req, Repository db)128af3562f7SShawn O. Pearce 	protected abstract void begin(HttpServletRequest req, Repository db)
129af3562f7SShawn O. Pearce 			throws IOException, ServiceNotEnabledException,
130af3562f7SShawn O. Pearce 			ServiceNotAuthorizedException;
131af3562f7SShawn O. Pearce 
1323b00041cSMatthias Sohn 	/**
1333b00041cSMatthias Sohn 	 * Advertise.
1343b00041cSMatthias Sohn 	 *
1353b00041cSMatthias Sohn 	 * @param req
1363b00041cSMatthias Sohn 	 *            request
1373b00041cSMatthias Sohn 	 * @param pck
1383b00041cSMatthias Sohn 	 * @throws IOException
1393b00041cSMatthias Sohn 	 * @throws ServiceNotEnabledException
1403b00041cSMatthias Sohn 	 * @throws ServiceNotAuthorizedException
1413b00041cSMatthias Sohn 	 */
advertise(HttpServletRequest req, PacketLineOutRefAdvertiser pck)142af3562f7SShawn O. Pearce 	protected abstract void advertise(HttpServletRequest req,
14381fea92eSShawn O. Pearce 			PacketLineOutRefAdvertiser pck) throws IOException,
14481fea92eSShawn O. Pearce 			ServiceNotEnabledException, ServiceNotAuthorizedException;
145af3562f7SShawn O. Pearce 
146c32a62cdSJonathan Tan 	/**
147c32a62cdSJonathan Tan 	 * Writes the appropriate response to an info/refs request received by
148c32a62cdSJonathan Tan 	 * a smart service. In protocol v0, this starts with "#
149c32a62cdSJonathan Tan 	 * service=serviceName" followed by a flush packet, but this is not
150c32a62cdSJonathan Tan 	 * necessarily the case in other protocol versions.
151c32a62cdSJonathan Tan 	 * <p>
152c32a62cdSJonathan Tan 	 * The default implementation writes "# service=serviceName" and a
153c32a62cdSJonathan Tan 	 * flush packet, then calls {@link #advertise}. Subclasses should
154c32a62cdSJonathan Tan 	 * override this method if they support protocol versions other than
155c32a62cdSJonathan Tan 	 * protocol v0.
156c32a62cdSJonathan Tan 	 *
157c32a62cdSJonathan Tan 	 * @param req
158c32a62cdSJonathan Tan 	 *            request
159c32a62cdSJonathan Tan 	 * @param pckOut
160c32a62cdSJonathan Tan 	 *            destination of response
161c32a62cdSJonathan Tan 	 * @param serviceName
162c32a62cdSJonathan Tan 	 *            service name to be written out in protocol v0; may or may
163c32a62cdSJonathan Tan 	 *            not be used in other versions
164c32a62cdSJonathan Tan 	 * @throws IOException
165c32a62cdSJonathan Tan 	 * @throws ServiceNotEnabledException
166c32a62cdSJonathan Tan 	 * @throws ServiceNotAuthorizedException
167c32a62cdSJonathan Tan 	 */
respond(HttpServletRequest req, PacketLineOut pckOut, String serviceName)168c32a62cdSJonathan Tan 	protected void respond(HttpServletRequest req,
169c32a62cdSJonathan Tan 			PacketLineOut pckOut, String serviceName)
170c32a62cdSJonathan Tan 			throws IOException, ServiceNotEnabledException,
171c32a62cdSJonathan Tan 			ServiceNotAuthorizedException {
172c32a62cdSJonathan Tan 		pckOut.writeString("# service=" + svc + '\n'); //$NON-NLS-1$
173c32a62cdSJonathan Tan 		pckOut.end();
174c32a62cdSJonathan Tan 		advertise(req, new PacketLineOutRefAdvertiser(pckOut));
175c32a62cdSJonathan Tan 	}
176c32a62cdSJonathan Tan 
177af3562f7SShawn O. Pearce 	private class Chain implements FilterChain {
178af3562f7SShawn O. Pearce 		private int filterIdx;
179af3562f7SShawn O. Pearce 
1807ac182f4SDavid Pursehouse 		@Override
doFilter(ServletRequest req, ServletResponse rsp)181af3562f7SShawn O. Pearce 		public void doFilter(ServletRequest req, ServletResponse rsp)
182af3562f7SShawn O. Pearce 				throws IOException, ServletException {
183af3562f7SShawn O. Pearce 			if (filterIdx < filters.length)
184af3562f7SShawn O. Pearce 				filters[filterIdx++].doFilter(req, rsp, this);
185af3562f7SShawn O. Pearce 			else
186af3562f7SShawn O. Pearce 				service(req, rsp);
187af3562f7SShawn O. Pearce 		}
188af3562f7SShawn O. Pearce 	}
18981fea92eSShawn O. Pearce }
190