From 1946fe76331b37c5a3be97268f0e3b0e58f3bb00 Mon Sep 17 00:00:00 2001
From: James Moger <james.moger@gitblit.com>
Date: Sun, 04 May 2014 17:51:26 -0400
Subject: [PATCH] Refine branch and pages servlets

---
 src/main/java/com/gitblit/servlet/BranchServlet.java |  112 +++++++++++++++++++++++++++++++++++++++++++++++---------
 1 files changed, 94 insertions(+), 18 deletions(-)

diff --git a/src/main/java/com/gitblit/servlet/BranchServlet.java b/src/main/java/com/gitblit/servlet/BranchServlet.java
index d6fbfe5..3380896 100644
--- a/src/main/java/com/gitblit/servlet/BranchServlet.java
+++ b/src/main/java/com/gitblit/servlet/BranchServlet.java
@@ -35,14 +35,22 @@
 
 import org.apache.tika.Tika;
 import org.eclipse.jgit.lib.FileMode;
+import org.eclipse.jgit.lib.MutableObjectId;
+import org.eclipse.jgit.lib.ObjectLoader;
+import org.eclipse.jgit.lib.ObjectReader;
 import org.eclipse.jgit.lib.Repository;
 import org.eclipse.jgit.revwalk.RevCommit;
+import org.eclipse.jgit.revwalk.RevWalk;
+import org.eclipse.jgit.treewalk.TreeWalk;
+import org.eclipse.jgit.treewalk.filter.PathFilter;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import com.gitblit.Constants;
+import com.gitblit.Keys;
 import com.gitblit.dagger.DaggerServlet;
 import com.gitblit.manager.IRepositoryManager;
+import com.gitblit.manager.IRuntimeManager;
 import com.gitblit.models.PathModel;
 import com.gitblit.utils.ByteFormat;
 import com.gitblit.utils.JGitUtils;
@@ -63,10 +71,13 @@
 
 	private transient Logger logger = LoggerFactory.getLogger(BranchServlet.class);
 
+	private IRuntimeManager runtimeManager;
+
 	private IRepositoryManager repositoryManager;
 
 	@Override
 	protected void inject(ObjectGraph dagger) {
+		this.runtimeManager = dagger.get(IRuntimeManager.class);
 		this.repositoryManager = dagger.get(IRepositoryManager.class);
 	}
 
@@ -83,7 +94,12 @@
 		if (baseURL.length() > 0 && baseURL.charAt(baseURL.length() - 1) == '/') {
 			baseURL = baseURL.substring(0, baseURL.length() - 1);
 		}
-		return baseURL + Constants.BRANCH + repository + "/" + (branch == null ? "" : (branch + "/" + (path == null ? "" : (path + "/"))));
+		String encodedPath = path.replace(' ', '-');
+		try {
+			encodedPath = URLEncoder.encode(encodedPath, "UTF-8");
+		} catch (UnsupportedEncodingException e) {
+		}
+		return baseURL + Constants.BRANCH + repository + "/" + (branch == null ? "" : (branch + "/" + (path == null ? "" : (encodedPath + "/"))));
 	}
 
 	protected String getBranch(String repository, HttpServletRequest request) {
@@ -204,9 +220,8 @@
 			List<PathModel> pathEntries = JGitUtils.getFilesInPath(r, requestedPath, commit);
 			if (pathEntries.isEmpty()) {
 				// requested a specific resource
+				String file = StringUtils.getLastPathElement(requestedPath);
 				try {
-					String file = StringUtils.getLastPathElement(requestedPath);
-
 					// query Tika for the content type
 					Tika tika = new Tika();
 					String contentType = tika.detect(file);
@@ -220,16 +235,20 @@
 							contentType = "application/octet-stream";
 						}
 					}
-					response.setContentType(contentType);
 
+					setContentType(response, contentType);
 
-					if (contentType.startsWith("text/")
-							|| "application/json".equals(contentType)
-							|| "application/xml".equals(contentType)) {
+					if (isTextType(contentType)) {
 
-						// serve text content
-						String encoding = commit.getEncoding().name();
-						response.setCharacterEncoding(encoding);
+						// load, interpret, and serve text content as UTF-8
+						String [] encodings = runtimeManager.getSettings().getStrings(Keys.web.blobEncodings).toArray(new String[0]);
+						String content = JGitUtils.getStringContent(r, commit.getTree(), requestedPath, encodings);
+
+						byte [] bytes = content.getBytes(Constants.ENCODING);
+						response.setContentLength(bytes.length);
+						ByteArrayInputStream is = new ByteArrayInputStream(bytes);
+						sendContent(response, JGitUtils.getCommitDate(commit), is);
+
 					} else {
 						// serve binary content
 						String filename = StringUtils.getLastPathElement(requestedPath);
@@ -249,13 +268,10 @@
 						catch (UnsupportedEncodingException e) {
 							response.setHeader("Content-Disposition", "attachment; filename=\"" + filename + "\"");
 						}
+
+						// stream binary content directly from the repository
+						streamFromRepo(response, r, commit, requestedPath);
 					}
-
-					// send content
-					byte [] content = JGitUtils.getByteContent(r, commit.getTree(), requestedPath, false);
-					InputStream is = new ByteArrayInputStream(content);
-					sendContent(response, JGitUtils.getCommitDate(commit), is);
-
 					return;
 				} catch (Exception e) {
 					logger.error(null, e);
@@ -290,8 +306,8 @@
 								fullPath = requestedPath + "/" + fileName;
 							}
 
-							String encoding = commit.getEncoding().name();
-							String stringContent = JGitUtils.getStringContent(r, commit.getTree(), fullPath, encoding);
+							String [] encodings = runtimeManager.getSettings().getStrings(Keys.web.blobEncodings).toArray(new String[0]);
+							String stringContent = JGitUtils.getStringContent(r, commit.getTree(), fullPath, encodings);
 							if (stringContent == null) {
 								continue;
 							}
@@ -303,6 +319,7 @@
 
 					response.setContentType("text/html; charset=" + Constants.ENCODING);
 					byte [] bytes = content.getBytes(Constants.ENCODING);
+					response.setContentLength(bytes.length);
 
 					ByteArrayInputStream is = new ByteArrayInputStream(bytes);
 					sendContent(response, JGitUtils.getCommitDate(commit), is);
@@ -368,6 +385,65 @@
 		}
 	}
 
+	protected boolean isTextType(String contentType) {
+		if (contentType.startsWith("text/")
+				|| "application/json".equals(contentType)
+				|| "application/xml".equals(contentType)) {
+			return true;
+		}
+		return false;
+	}
+
+	/**
+	 * Override all text types to be plain text.
+	 *
+	 * @param response
+	 * @param contentType
+	 */
+	protected void setContentType(HttpServletResponse response, String contentType) {
+		if (isTextType(contentType)) {
+			response.setContentType("text/plain");
+		} else {
+			response.setContentType(contentType);
+		}
+	}
+
+	private void streamFromRepo(HttpServletResponse response, Repository repository,
+			RevCommit commit, String requestedPath) throws IOException {
+
+		response.setDateHeader("Last-Modified", JGitUtils.getCommitDate(commit).getTime());
+		response.setHeader("Cache-Control", "public, max-age=3600, must-revalidate");
+
+		RevWalk rw = new RevWalk(repository);
+		TreeWalk tw = new TreeWalk(repository);
+		try {
+			tw.reset();
+			tw.addTree(commit.getTree());
+			PathFilter f = PathFilter.create(requestedPath);
+			tw.setFilter(f);
+			tw.setRecursive(true);
+			MutableObjectId id = new MutableObjectId();
+			ObjectReader reader = tw.getObjectReader();
+			while (tw.next()) {
+				FileMode mode = tw.getFileMode(0);
+				if (mode == FileMode.GITLINK || mode == FileMode.TREE) {
+					continue;
+				}
+				tw.getObjectId(id, 0);
+
+				long len = reader.getObjectSize(id, org.eclipse.jgit.lib.Constants.OBJ_BLOB);
+				response.setIntHeader("Content-Length", (int) len);
+				ObjectLoader ldr = repository.open(id);
+				ldr.copyTo(response.getOutputStream());
+			}
+		} finally {
+			tw.release();
+			rw.dispose();
+		}
+
+		response.flushBuffer();
+	}
+
 	private void sendContent(HttpServletResponse response, Date date, InputStream is) throws ServletException, IOException {
 		response.setDateHeader("Last-Modified", date.getTime());
 		response.setHeader("Cache-Control", "public, max-age=3600, must-revalidate");

--
Gitblit v1.9.1