/*
|
* Copyright 2011 gitblit.com.
|
*
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
* you may not use this file except in compliance with the License.
|
* You may obtain a copy of the License at
|
*
|
* http://www.apache.org/licenses/LICENSE-2.0
|
*
|
* Unless required by applicable law or agreed to in writing, software
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* See the License for the specific language governing permissions and
|
* limitations under the License.
|
*/
|
package com.gitblit;
|
|
import java.io.IOException;
|
import java.net.SocketException;
|
import java.text.MessageFormat;
|
import java.text.ParseException;
|
import java.util.Date;
|
|
import javax.servlet.ServletException;
|
import javax.servlet.http.HttpServlet;
|
import javax.servlet.http.HttpServletResponse;
|
|
import org.eclipse.jgit.lib.Repository;
|
import org.eclipse.jgit.revwalk.RevCommit;
|
import org.slf4j.Logger;
|
import org.slf4j.LoggerFactory;
|
|
import com.gitblit.utils.CompressionUtils;
|
import com.gitblit.utils.JGitUtils;
|
import com.gitblit.utils.MarkdownUtils;
|
import com.gitblit.utils.StringUtils;
|
|
/**
|
* Streams out a zip file from the specified repository for any tree path at any
|
* revision.
|
*
|
* @author James Moger
|
*
|
*/
|
public class DownloadZipServlet extends HttpServlet {
|
|
private static final long serialVersionUID = 1L;
|
|
private transient Logger logger = LoggerFactory.getLogger(DownloadZipServlet.class);
|
|
public static enum Format {
|
zip(".zip"), tar(".tar"), gz(".tar.gz"), xz(".tar.xz"), bzip2(".tar.bzip2");
|
|
public final String extension;
|
|
Format(String ext) {
|
this.extension = ext;
|
}
|
|
public static Format fromName(String name) {
|
for (Format format : values()) {
|
if (format.name().equalsIgnoreCase(name)) {
|
return format;
|
}
|
}
|
return zip;
|
}
|
}
|
|
public DownloadZipServlet() {
|
super();
|
}
|
|
/**
|
* Returns an url to this servlet for the specified parameters.
|
*
|
* @param baseURL
|
* @param repository
|
* @param objectId
|
* @param path
|
* @param format
|
* @return an url
|
*/
|
public static String asLink(String baseURL, String repository, String objectId, String path, Format format) {
|
if (baseURL.length() > 0 && baseURL.charAt(baseURL.length() - 1) == '/') {
|
baseURL = baseURL.substring(0, baseURL.length() - 1);
|
}
|
return baseURL + Constants.ZIP_PATH + "?r=" + repository
|
+ (path == null ? "" : ("&p=" + path))
|
+ (objectId == null ? "" : ("&h=" + objectId))
|
+ (format == null ? "" : ("&format=" + format.name()));
|
}
|
|
/**
|
* Creates a zip stream from the repository of the requested data.
|
*
|
* @param request
|
* @param response
|
* @throws javax.servlet.ServletException
|
* @throws java.io.IOException
|
*/
|
private void processRequest(javax.servlet.http.HttpServletRequest request,
|
javax.servlet.http.HttpServletResponse response) throws javax.servlet.ServletException,
|
java.io.IOException {
|
if (!GitBlit.getBoolean(Keys.web.allowZipDownloads, true)) {
|
logger.warn("Zip downloads are disabled");
|
response.sendError(HttpServletResponse.SC_FORBIDDEN);
|
return;
|
}
|
|
Format format = Format.zip;
|
String repository = request.getParameter("r");
|
String basePath = request.getParameter("p");
|
String objectId = request.getParameter("h");
|
String f = request.getParameter("format");
|
if (!StringUtils.isEmpty(f)) {
|
format = Format.fromName(f);
|
}
|
|
try {
|
String name = repository;
|
if (name.indexOf('/') > -1) {
|
name = name.substring(name.lastIndexOf('/') + 1);
|
}
|
name = StringUtils.stripDotGit(name);
|
|
if (!StringUtils.isEmpty(basePath)) {
|
name += "-" + basePath.replace('/', '_');
|
}
|
if (!StringUtils.isEmpty(objectId)) {
|
name += "-" + objectId;
|
}
|
|
Repository r = GitBlit.self().getRepository(repository);
|
if (r == null) {
|
if (GitBlit.self().isCollectingGarbage(repository)) {
|
error(response, MessageFormat.format("# Error\nGitblit is busy collecting garbage in {0}", repository));
|
return;
|
} else {
|
error(response, MessageFormat.format("# Error\nFailed to find repository {0}", repository));
|
return;
|
}
|
}
|
RevCommit commit = JGitUtils.getCommit(r, objectId);
|
if (commit == null) {
|
error(response, MessageFormat.format("# Error\nFailed to find commit {0}", objectId));
|
r.close();
|
return;
|
}
|
Date date = JGitUtils.getCommitDate(commit);
|
|
String contentType = "application/octet-stream";
|
response.setContentType(contentType + "; charset=" + response.getCharacterEncoding());
|
response.setHeader("Content-Disposition", "attachment; filename=\"" + name + format.extension + "\"");
|
response.setDateHeader("Last-Modified", date.getTime());
|
response.setHeader("Cache-Control", "no-cache");
|
response.setHeader("Pragma", "no-cache");
|
response.setDateHeader("Expires", 0);
|
|
try {
|
switch (format) {
|
case zip:
|
CompressionUtils.zip(r, basePath, objectId, response.getOutputStream());
|
break;
|
case tar:
|
CompressionUtils.tar(r, basePath, objectId, response.getOutputStream());
|
break;
|
case gz:
|
CompressionUtils.gz(r, basePath, objectId, response.getOutputStream());
|
break;
|
case xz:
|
CompressionUtils.xz(r, basePath, objectId, response.getOutputStream());
|
break;
|
case bzip2:
|
CompressionUtils.bzip2(r, basePath, objectId, response.getOutputStream());
|
break;
|
}
|
|
response.flushBuffer();
|
} catch (SocketException t) {
|
String message = t.getMessage() == null ? "" : t.getMessage().toLowerCase();
|
if (message.contains("reset") || message.contains("broken pipe")) {
|
logger.error("Client aborted zip download: " + message);
|
} else {
|
logger.error("Failed to write attachment to client", t);
|
}
|
} catch (Throwable t) {
|
logger.error("Failed to write attachment to client", t);
|
}
|
|
// close the repository
|
r.close();
|
} catch (Throwable t) {
|
logger.error("Failed to write attachment to client", t);
|
}
|
}
|
|
private void error(HttpServletResponse response, String mkd) throws ServletException,
|
IOException, ParseException {
|
String content = MarkdownUtils.transformMarkdown(mkd);
|
response.setContentType("text/html; charset=" + Constants.ENCODING);
|
response.getWriter().write(content);
|
}
|
|
@Override
|
protected void doPost(javax.servlet.http.HttpServletRequest request,
|
javax.servlet.http.HttpServletResponse response) throws javax.servlet.ServletException,
|
java.io.IOException {
|
processRequest(request, response);
|
}
|
|
@Override
|
protected void doGet(javax.servlet.http.HttpServletRequest request,
|
javax.servlet.http.HttpServletResponse response) throws javax.servlet.ServletException,
|
java.io.IOException {
|
processRequest(request, response);
|
}
|
}
|