# If web.authenticate=false, any user can execute the aforementioned functions. | # If web.authenticate=false, any user can execute the aforementioned functions. | ||||
web.allowAdministration = true | web.allowAdministration = true | ||||
# Allow dyanamic zip downloads. | |||||
web.allowZipDownloads = true | |||||
# This is the message display above the repositories table. | # This is the message display above the repositories table. | ||||
# This can point to a file with Markdown content. | # This can point to a file with Markdown content. | ||||
# Specifying "gitblit" uses the internal welcome message. | # Specifying "gitblit" uses the internal welcome message. |
public final static String ADMIN_ROLE = "#admin"; | public final static String ADMIN_ROLE = "#admin"; | ||||
public final static String PROPERTIES_FILE = "gitblit.properties"; | public final static String PROPERTIES_FILE = "gitblit.properties"; | ||||
public final static String GIT_SERVLET_PATH = "/git/"; | |||||
public final static String ZIP_SERVLET_PATH = "/zip/"; | |||||
public static enum AccessRestrictionType { | public static enum AccessRestrictionType { | ||||
NONE, PUSH, CLONE, VIEW; | NONE, PUSH, CLONE, VIEW; |
package com.gitblit; | |||||
import java.util.Date; | |||||
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.Constants.AccessRestrictionType; | |||||
import com.gitblit.utils.JGitUtils; | |||||
import com.gitblit.utils.StringUtils; | |||||
import com.gitblit.wicket.models.RepositoryModel; | |||||
public class DownloadZipServlet extends HttpServlet { | |||||
public static String asLink(String baseURL, String repository, String objectId, String path) { | |||||
return baseURL + (baseURL.endsWith("/") ? "" : "/") + "zip?r=" + repository + (path == null ? "" : ("&p=" + path)) + (objectId == null ? "" : ("&h=" + objectId)); | |||||
} | |||||
private static final long serialVersionUID = 1L; | |||||
private final static Logger logger = LoggerFactory.getLogger(DownloadZipServlet.class); | |||||
public DownloadZipServlet() { | |||||
super(); | |||||
} | |||||
@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); | |||||
} | |||||
private void processRequest(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response) throws javax.servlet.ServletException, java.io.IOException { | |||||
if (!GitBlit.self().settings().getBoolean(Keys.web.allowZipDownloads, true)) { | |||||
logger.warn("Zip downloads are disabled"); | |||||
response.sendError(HttpServletResponse.SC_FORBIDDEN); | |||||
return; | |||||
} | |||||
String repository = request.getParameter("r"); | |||||
String basePath = request.getParameter("p"); | |||||
String objectId = request.getParameter("h"); | |||||
try { | |||||
String name = repository; | |||||
if (name.indexOf('/') > -1) { | |||||
name = name.substring(name.lastIndexOf('/') + 1); | |||||
} | |||||
// check roles first | |||||
boolean authorized = request.isUserInRole(Constants.ADMIN_ROLE); | |||||
authorized |= request.isUserInRole(repository); | |||||
if (!authorized) { | |||||
RepositoryModel model = GitBlit.self().getRepositoryModel(repository); | |||||
if (model.accessRestriction.atLeast(AccessRestrictionType.VIEW)) { | |||||
logger.warn("Unauthorized access via zip servlet for " + model.name); | |||||
response.sendError(HttpServletResponse.SC_FORBIDDEN); | |||||
return; | |||||
} | |||||
} | |||||
if (!StringUtils.isEmpty(basePath)) { | |||||
name += "-" + basePath.replace('/', '_'); | |||||
} | |||||
if (!StringUtils.isEmpty(objectId)) { | |||||
name += "-" + objectId; | |||||
} | |||||
Repository r = GitBlit.self().getRepository(repository); | |||||
RevCommit commit = JGitUtils.getCommit(r, objectId); | |||||
Date date = JGitUtils.getCommitDate(commit); | |||||
String contentType = "application/octet-stream"; | |||||
response.setContentType(contentType + "; charset=" + response.getCharacterEncoding()); | |||||
// response.setContentLength(attachment.getFileSize()); | |||||
response.setHeader("Content-Disposition", "attachment; filename=\"" + name + ".zip" + "\""); | |||||
response.setDateHeader("Last-Modified", date.getTime()); | |||||
response.setHeader("Cache-Control", "no-cache"); | |||||
response.setHeader("Pragma", "no-cache"); | |||||
response.setDateHeader("Expires", 0); | |||||
try { | |||||
JGitUtils.zip(r, basePath, objectId, response.getOutputStream()); | |||||
response.flushBuffer(); | |||||
} catch (Throwable t) { | |||||
logger.error("Failed to write attachment to client", t); | |||||
} | |||||
} catch (Throwable t) { | |||||
logger.error("Failed to write attachment to client", t); | |||||
} | |||||
} | |||||
} |
wicketFilter.setInitParameter(WicketFilter.FILTER_MAPPING_PARAM, wicketPathSpec); | wicketFilter.setInitParameter(WicketFilter.FILTER_MAPPING_PARAM, wicketPathSpec); | ||||
wicketFilter.setInitParameter(WicketFilter.IGNORE_PATHS_PARAM, "git/"); | wicketFilter.setInitParameter(WicketFilter.IGNORE_PATHS_PARAM, "git/"); | ||||
rootContext.addFilter(wicketFilter, wicketPathSpec, FilterMapping.DEFAULT); | rootContext.addFilter(wicketFilter, wicketPathSpec, FilterMapping.DEFAULT); | ||||
// Zip Servlet | |||||
rootContext.addServlet(DownloadZipServlet.class, Constants.ZIP_SERVLET_PATH + "*"); | |||||
// Git Servlet | // Git Servlet | ||||
ServletHolder gitServlet = null; | ServletHolder gitServlet = null; | ||||
String gitServletPathSpec = "/git/*"; | |||||
String gitServletPathSpec = Constants.GIT_SERVLET_PATH + "*"; | |||||
if (fileSettings.getBoolean(Keys.git.enableGitServlet, true)) { | if (fileSettings.getBoolean(Keys.git.enableGitServlet, true)) { | ||||
gitServlet = rootContext.addServlet(GitBlitServlet.class, gitServletPathSpec); | gitServlet = rootContext.addServlet(GitBlitServlet.class, gitServletPathSpec); | ||||
gitServlet.setInitParameter("base-path", params.repositoriesFolder); | gitServlet.setInitParameter("base-path", params.repositoriesFolder); |
package com.gitblit.tests; | package com.gitblit.tests; | ||||
import java.io.File; | import java.io.File; | ||||
import java.io.FileOutputStream; | |||||
import java.util.Date; | import java.util.Date; | ||||
import java.util.List; | import java.util.List; | ||||
r.close(); | r.close(); | ||||
System.out.println(diff); | System.out.println(diff); | ||||
} | } | ||||
public void testZip() throws Exception { | |||||
Repository r = new FileRepository(new File(repositoriesFolder, "gitblit.git/" + Constants.DOT_GIT)); | |||||
FileOutputStream fos = null; | |||||
try { | |||||
File zipFile = new File("c:/output.zip"); | |||||
zipFile.delete(); | |||||
fos = new FileOutputStream(zipFile); | |||||
if (JGitUtils.zip(r, "src", Constants.HEAD, fos)) { | |||||
System.out.println("zip = " + zipFile.length() + " bytes"); | |||||
} else { | |||||
System.err.println("failed to generate zip file?!"); | |||||
} | |||||
} finally { | |||||
if (fos != null) { | |||||
try { | |||||
fos.close(); | |||||
} catch (Throwable t) { | |||||
} | |||||
} | |||||
} | |||||
} | |||||
} | } |
import java.io.File; | import java.io.File; | ||||
import java.io.IOException; | import java.io.IOException; | ||||
import java.io.InputStream; | import java.io.InputStream; | ||||
import java.io.OutputStream; | |||||
import java.nio.charset.Charset; | import java.nio.charset.Charset; | ||||
import java.text.DateFormat; | import java.text.DateFormat; | ||||
import java.text.ParseException; | import java.text.ParseException; | ||||
import java.util.Map; | import java.util.Map; | ||||
import java.util.Set; | import java.util.Set; | ||||
import java.util.concurrent.atomic.AtomicInteger; | import java.util.concurrent.atomic.AtomicInteger; | ||||
import java.util.zip.ZipEntry; | |||||
import java.util.zip.ZipOutputStream; | |||||
import org.eclipse.jgit.api.Git; | import org.eclipse.jgit.api.Git; | ||||
import org.eclipse.jgit.diff.DiffEntry; | import org.eclipse.jgit.diff.DiffEntry; | ||||
return null; | return null; | ||||
} | } | ||||
public static boolean zip(Repository r, String basePath, String objectId, OutputStream os) throws Exception { | |||||
RevCommit commit = getCommit(r, objectId); | |||||
if (commit == null) { | |||||
return false; | |||||
} | |||||
final RevWalk rw = new RevWalk(r); | |||||
final TreeWalk walk = new TreeWalk(r); | |||||
try { | |||||
walk.addTree(commit.getTree()); | |||||
ZipOutputStream zos = new ZipOutputStream(os); | |||||
zos.setComment("Generated by Git:Blit"); | |||||
if (basePath != null && basePath.length() > 0) { | |||||
PathFilter f = PathFilter.create(basePath); | |||||
walk.setFilter(f); | |||||
} | |||||
walk.setRecursive(true); | |||||
while (walk.next()) { | |||||
ZipEntry entry = new ZipEntry(walk.getPathString()); | |||||
entry.setSize(walk.getObjectReader().getObjectSize(walk.getObjectId(0), Constants.OBJ_BLOB)); | |||||
entry.setComment(commit.getName()); | |||||
zos.putNextEntry(entry); | |||||
ObjectId entid = walk.getObjectId(0); | |||||
FileMode entmode = walk.getFileMode(0); | |||||
RevBlob blob = (RevBlob) rw.lookupAny(entid, entmode.getObjectType()); | |||||
rw.parseBody(blob); | |||||
ObjectLoader ldr = r.open(blob.getId(), Constants.OBJ_BLOB); | |||||
byte[] tmp = new byte[4096]; | |||||
InputStream in = ldr.openStream(); | |||||
int n; | |||||
while ((n = in.read(tmp)) > 0) { | |||||
zos.write(tmp, 0, n); | |||||
} | |||||
in.close(); | |||||
} | |||||
zos.finish(); | |||||
return true; | |||||
} catch (IOException e) { | |||||
LOGGER.error("Failed to zip files from commit " + commit.getName(), e); | |||||
} finally { | |||||
walk.release(); | |||||
rw.dispose(); | |||||
} | |||||
return false; | |||||
} | |||||
public static List<Metric> getDateMetrics(Repository r) { | public static List<Metric> getDateMetrics(Repository r) { | ||||
Metric total = new Metric("TOTAL"); | Metric total = new Metric("TOTAL"); | ||||
final Map<String, Metric> metricMap = new HashMap<String, Metric>(); | final Map<String, Metric> metricMap = new HashMap<String, Metric>(); | ||||
if (hasCommits(r)) { | if (hasCommits(r)) { | ||||
final List<RefModel> tags = getTags(r, -1); | final List<RefModel> tags = getTags(r, -1); | ||||
final Map<ObjectId, RefModel> tagMap = new HashMap<ObjectId, RefModel>(); | final Map<ObjectId, RefModel> tagMap = new HashMap<ObjectId, RefModel>(); |
gb.canAdminDescription = can administer Git:Blit server | gb.canAdminDescription = can administer Git:Blit server | ||||
gb.permittedUsers = permitted users | gb.permittedUsers = permitted users | ||||
gb.isFrozen = is frozen | gb.isFrozen = is frozen | ||||
gb.isFrozenDescription = deny push operations | |||||
gb.isFrozenDescription = deny push operations | |||||
gb.zip = zip |
<tr><th><wicket:message key="gb.committer">committer</wicket:message></th><td><span class="sha1" wicket:id="commitCommitter">[committer]</span></td></tr> | <tr><th><wicket:message key="gb.committer">committer</wicket:message></th><td><span class="sha1" wicket:id="commitCommitter">[committer]</span></td></tr> | ||||
<tr><th></th><td><span class="sha1" wicket:id="commitCommitterDate">[commit date]</span></td></tr> | <tr><th></th><td><span class="sha1" wicket:id="commitCommitterDate">[commit date]</span></td></tr> | ||||
<tr><th><wicket:message key="gb.commit">commit</wicket:message></th><td><span class="sha1" wicket:id="commitId">[commit id]</span></td></tr> | <tr><th><wicket:message key="gb.commit">commit</wicket:message></th><td><span class="sha1" wicket:id="commitId">[commit id]</span></td></tr> | ||||
<tr><th><wicket:message key="gb.tree">tree</wicket:message></th><td><span class="sha1" wicket:id="commitTree">[commit tree]</span></td></tr> | |||||
<tr><th><wicket:message key="gb.tree">tree</wicket:message></th> | |||||
<td><span class="sha1" wicket:id="commitTree">[commit tree]</span> | |||||
<span class="link"> | |||||
<a wicket:id="treeLink"><wicket:message key="gb.tree"></wicket:message></a> | <a wicket:id="zipLink"><wicket:message key="gb.zip"></wicket:message></a> | |||||
</span> | |||||
</td></tr> | |||||
<tr><th valign="top"><wicket:message key="gb.parent">parent</wicket:message></th> | <tr><th valign="top"><wicket:message key="gb.parent">parent</wicket:message></th> | ||||
<td> | <td> | ||||
<span wicket:id="commitParents"> | <span wicket:id="commitParents"> |
import org.apache.wicket.PageParameters; | import org.apache.wicket.PageParameters; | ||||
import org.apache.wicket.markup.html.basic.Label; | import org.apache.wicket.markup.html.basic.Label; | ||||
import org.apache.wicket.markup.html.link.BookmarkablePageLink; | import org.apache.wicket.markup.html.link.BookmarkablePageLink; | ||||
import org.apache.wicket.markup.html.link.ExternalLink; | |||||
import org.apache.wicket.markup.repeater.Item; | import org.apache.wicket.markup.repeater.Item; | ||||
import org.apache.wicket.markup.repeater.data.DataView; | import org.apache.wicket.markup.repeater.data.DataView; | ||||
import org.apache.wicket.markup.repeater.data.ListDataProvider; | import org.apache.wicket.markup.repeater.data.ListDataProvider; | ||||
import org.eclipse.jgit.lib.Repository; | import org.eclipse.jgit.lib.Repository; | ||||
import org.eclipse.jgit.revwalk.RevCommit; | import org.eclipse.jgit.revwalk.RevCommit; | ||||
import com.gitblit.DownloadZipServlet; | |||||
import com.gitblit.GitBlit; | |||||
import com.gitblit.Keys; | |||||
import com.gitblit.utils.JGitUtils; | import com.gitblit.utils.JGitUtils; | ||||
import com.gitblit.utils.JGitUtils.SearchType; | import com.gitblit.utils.JGitUtils.SearchType; | ||||
import com.gitblit.wicket.LinkPanel; | import com.gitblit.wicket.LinkPanel; | ||||
add(new Label("commitId", c.getName())); | add(new Label("commitId", c.getName())); | ||||
add(new LinkPanel("commitTree", "list", c.getTree().getName(), TreePage.class, newCommitParameter())); | add(new LinkPanel("commitTree", "list", c.getTree().getName(), TreePage.class, newCommitParameter())); | ||||
add(new BookmarkablePageLink<Void>("treeLink", TreePage.class, newCommitParameter())); | |||||
add(new ExternalLink("zipLink", DownloadZipServlet.asLink(getRequest().getRelativePathPrefixToContextRoot(), repositoryName, objectId, null)).setVisible(GitBlit.self().settings().getBoolean(Keys.web.allowZipDownloads, true))); | |||||
// Parent Commits | // Parent Commits | ||||
ListDataProvider<String> parentsDp = new ListDataProvider<String>(parents); | ListDataProvider<String> parentsDp = new ListDataProvider<String>(parents); |
<!-- blob nav links --> | <!-- blob nav links --> | ||||
<div class="page_nav2"> | <div class="page_nav2"> | ||||
<a wicket:id="historyLink"><wicket:message key="gb.history"></wicket:message></a> | <a wicket:id="headLink"><wicket:message key="gb.head"></wicket:message></a> | |||||
<a wicket:id="historyLink"><wicket:message key="gb.history"></wicket:message></a> | <a wicket:id="headLink"><wicket:message key="gb.head"></wicket:message></a> | <a wicket:id="zipLink"><wicket:message key="gb.zip"></wicket:message></a> | |||||
</div> | </div> | ||||
<!-- commit header --> | <!-- commit header --> | ||||
<!-- tree links --> | <!-- tree links --> | ||||
<wicket:fragment wicket:id="treeLinks"> | <wicket:fragment wicket:id="treeLinks"> | ||||
<span class="link"> | <span class="link"> | ||||
<a wicket:id="tree"><wicket:message key="gb.tree"></wicket:message></a> | <a wicket:id="history"><wicket:message key="gb.history"></wicket:message></a> | |||||
<a wicket:id="tree"><wicket:message key="gb.tree"></wicket:message></a> | <a wicket:id="history"><wicket:message key="gb.history"></wicket:message></a> | <a wicket:id="zip"><wicket:message key="gb.zip"></wicket:message></a> | |||||
</span> | </span> | ||||
</wicket:fragment> | </wicket:fragment> | ||||
import org.apache.wicket.PageParameters; | import org.apache.wicket.PageParameters; | ||||
import org.apache.wicket.markup.html.basic.Label; | import org.apache.wicket.markup.html.basic.Label; | ||||
import org.apache.wicket.markup.html.link.BookmarkablePageLink; | import org.apache.wicket.markup.html.link.BookmarkablePageLink; | ||||
import org.apache.wicket.markup.html.link.ExternalLink; | |||||
import org.apache.wicket.markup.html.panel.Fragment; | import org.apache.wicket.markup.html.panel.Fragment; | ||||
import org.apache.wicket.markup.repeater.Item; | import org.apache.wicket.markup.repeater.Item; | ||||
import org.apache.wicket.markup.repeater.data.DataView; | import org.apache.wicket.markup.repeater.data.DataView; | ||||
import org.eclipse.jgit.lib.Repository; | import org.eclipse.jgit.lib.Repository; | ||||
import org.eclipse.jgit.revwalk.RevCommit; | import org.eclipse.jgit.revwalk.RevCommit; | ||||
import com.gitblit.DownloadZipServlet; | |||||
import com.gitblit.GitBlit; | |||||
import com.gitblit.Keys; | |||||
import com.gitblit.utils.ByteFormat; | import com.gitblit.utils.ByteFormat; | ||||
import com.gitblit.utils.JGitUtils; | import com.gitblit.utils.JGitUtils; | ||||
import com.gitblit.wicket.LinkPanel; | import com.gitblit.wicket.LinkPanel; | ||||
// tree page links | // tree page links | ||||
add(new BookmarkablePageLink<Void>("historyLink", HistoryPage.class, WicketUtils.newPathParameter(repositoryName, objectId, path))); | add(new BookmarkablePageLink<Void>("historyLink", HistoryPage.class, WicketUtils.newPathParameter(repositoryName, objectId, path))); | ||||
add(new BookmarkablePageLink<Void>("headLink", TreePage.class, WicketUtils.newPathParameter(repositoryName, Constants.HEAD, path))); | add(new BookmarkablePageLink<Void>("headLink", TreePage.class, WicketUtils.newPathParameter(repositoryName, Constants.HEAD, path))); | ||||
add(new ExternalLink("zipLink", DownloadZipServlet.asLink(getRequest().getRelativePathPrefixToContextRoot(), repositoryName, objectId, path)).setVisible(GitBlit.self().settings().getBoolean(Keys.web.allowZipDownloads, true))); | |||||
add(new CommitHeaderPanel("commitHeader", repositoryName, commit)); | add(new CommitHeaderPanel("commitHeader", repositoryName, commit)); | ||||
Fragment links = new Fragment("pathLinks", "treeLinks", this); | Fragment links = new Fragment("pathLinks", "treeLinks", this); | ||||
links.add(new BookmarkablePageLink<Void>("tree", TreePage.class, WicketUtils.newPathParameter(repositoryName, entry.commitId, entry.path))); | links.add(new BookmarkablePageLink<Void>("tree", TreePage.class, WicketUtils.newPathParameter(repositoryName, entry.commitId, entry.path))); | ||||
links.add(new BookmarkablePageLink<Void>("history", HistoryPage.class, WicketUtils.newPathParameter(repositoryName, entry.commitId, entry.path))); | links.add(new BookmarkablePageLink<Void>("history", HistoryPage.class, WicketUtils.newPathParameter(repositoryName, entry.commitId, entry.path))); | ||||
links.add(new ExternalLink("zip", DownloadZipServlet.asLink(getRequest().getRelativePathPrefixToContextRoot(), repositoryName, objectId, entry.path)).setVisible(GitBlit.self().settings().getBoolean(Keys.web.allowZipDownloads, true))); | |||||
item.add(links); | item.add(links); | ||||
} else { | } else { | ||||
// blob link | // blob link |
color: #008000; | color: #008000; | ||||
} | } | ||||
span.link { | |||||
color: #888; | |||||
} | |||||
span.link, span.link a { | span.link, span.link a { | ||||
font-family: sans-serif; | font-family: sans-serif; | ||||
font-size: 11px; | |||||
font-size: 11px; | |||||
} | } | ||||
span.link em, div.link span em { | span.link em, div.link span em { | ||||
font-style: normal; | font-style: normal; | ||||
font-family: sans-serif; | font-family: sans-serif; | ||||
font-size: 11px; | |||||
font-size: 11px; | |||||
} | } | ||||
div.page_header { | div.page_header { |