| /* | |
| * Copyright 2012 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.text.MessageFormat; | |
| import java.text.ParseException; | |
| import java.util.ArrayList; | |
| import java.util.List; | |
| import javax.servlet.ServletContext; | |
| import javax.servlet.ServletException; | |
| import javax.servlet.http.HttpServlet; | |
| import javax.servlet.http.HttpServletRequest; | |
| import javax.servlet.http.HttpServletResponse; | |
| import org.eclipse.jgit.lib.Repository; | |
| import org.eclipse.jgit.revwalk.RevCommit; | |
| import org.eclipse.jgit.revwalk.RevTree; | |
| import org.slf4j.Logger; | |
| import org.slf4j.LoggerFactory; | |
| import com.gitblit.models.RefModel; | |
| import com.gitblit.utils.ArrayUtils; | |
| import com.gitblit.utils.JGitUtils; | |
| import com.gitblit.utils.MarkdownUtils; | |
| import com.gitblit.utils.StringUtils; | |
| /** | |
| * Serves the content of a gh-pages branch. | |
| * | |
| * @author James Moger | |
| * | |
| */ | |
| public class PagesServlet extends HttpServlet { | |
| private static final long serialVersionUID = 1L; | |
| private transient Logger logger = LoggerFactory.getLogger(PagesServlet.class); | |
| public PagesServlet() { | |
| super(); | |
| } | |
| /** | |
| * Returns an url to this servlet for the specified parameters. | |
| * | |
| * @param baseURL | |
| * @param repository | |
| * @param path | |
| * @return an url | |
| */ | |
| public static String asLink(String baseURL, String repository, String path) { | |
| if (baseURL.length() > 0 && baseURL.charAt(baseURL.length() - 1) == '/') { | |
| baseURL = baseURL.substring(0, baseURL.length() - 1); | |
| } | |
| return baseURL + Constants.PAGES + repository + "/" + (path == null ? "" : ("/" + path)); | |
| } | |
| /** | |
| * Retrieves the specified resource from the gh-pages branch of the | |
| * repository. | |
| * | |
| * @param request | |
| * @param response | |
| * @throws javax.servlet.ServletException | |
| * @throws java.io.IOException | |
| */ | |
| private void processRequest(HttpServletRequest request, HttpServletResponse response) | |
| throws ServletException, IOException { | |
| String path = request.getPathInfo(); | |
| if (path.toLowerCase().endsWith(".git")) { | |
| // forward to url with trailing / | |
| // this is important for relative pages links | |
| response.sendRedirect(request.getServletPath() + path + "/"); | |
| return; | |
| } | |
| if (path.charAt(0) == '/') { | |
| // strip leading / | |
| path = path.substring(1); | |
| } | |
| // determine repository and resource from url | |
| String repository = ""; | |
| String resource = ""; | |
| Repository r = null; | |
| int offset = 0; | |
| while (r == null) { | |
| int slash = path.indexOf('/', offset); | |
| if (slash == -1) { | |
| repository = path; | |
| } else { | |
| repository = path.substring(0, slash); | |
| } | |
| r = GitBlit.self().getRepository(repository, false); | |
| offset = slash + 1; | |
| if (offset > 0) { | |
| resource = path.substring(offset); | |
| } | |
| if (repository.equals(path)) { | |
| // either only repository in url or no repository found | |
| break; | |
| } | |
| } | |
| ServletContext context = request.getSession().getServletContext(); | |
| try { | |
| if (r == null) { | |
| // repository not found! | |
| String mkd = MessageFormat.format( | |
| "# Error\nSorry, no valid **repository** specified in this url: {0}!", | |
| repository); | |
| error(response, mkd); | |
| return; | |
| } | |
| // retrieve the content from the repository | |
| RefModel pages = JGitUtils.getPagesBranch(r); | |
| RevCommit commit = JGitUtils.getCommit(r, pages.getObjectId().getName()); | |
| if (commit == null) { | |
| // branch not found! | |
| String mkd = MessageFormat.format( | |
| "# Error\nSorry, the repository {0} does not have a **gh-pages** branch!", | |
| repository); | |
| error(response, mkd); | |
| r.close(); | |
| return; | |
| } | |
| String [] encodings = GitBlit.getEncodings(); | |
| RevTree tree = commit.getTree(); | |
| byte[] content = null; | |
| if (StringUtils.isEmpty(resource)) { | |
| // find resource | |
| List<String> markdownExtensions = GitBlit.getStrings(Keys.web.markdownExtensions); | |
| List<String> extensions = new ArrayList<String>(markdownExtensions.size() + 2); | |
| extensions.add("html"); | |
| extensions.add("htm"); | |
| extensions.addAll(markdownExtensions); | |
| for (String ext : extensions){ | |
| String file = "index." + ext; | |
| String stringContent = JGitUtils.getStringContent(r, tree, file, encodings); | |
| if(stringContent == null){ | |
| continue; | |
| } | |
| content = stringContent.getBytes(Constants.ENCODING); | |
| if (content != null) { | |
| resource = file; | |
| // assume text/html unless the servlet container | |
| // overrides | |
| response.setContentType("text/html; charset=" + Constants.ENCODING); | |
| break; | |
| } | |
| } | |
| } else { | |
| // specific resource | |
| try { | |
| String contentType = context.getMimeType(resource); | |
| if (contentType == null) { | |
| contentType = "text/plain"; | |
| } | |
| if (contentType.startsWith("text")) { | |
| content = JGitUtils.getStringContent(r, tree, resource, encodings).getBytes( | |
| Constants.ENCODING); | |
| } else { | |
| content = JGitUtils.getByteContent(r, tree, resource, false); | |
| } | |
| response.setContentType(contentType); | |
| } catch (Exception e) { | |
| } | |
| } | |
| // no content, try custom 404 page | |
| if (ArrayUtils.isEmpty(content)) { | |
| String custom404 = JGitUtils.getStringContent(r, tree, "404.html", encodings); | |
| if (!StringUtils.isEmpty(custom404)) { | |
| content = custom404.getBytes(Constants.ENCODING); | |
| } | |
| // still no content | |
| if (ArrayUtils.isEmpty(content)) { | |
| String str = MessageFormat.format( | |
| "# Error\nSorry, the requested resource **{0}** was not found.", | |
| resource); | |
| content = MarkdownUtils.transformMarkdown(str).getBytes(Constants.ENCODING); | |
| } | |
| try { | |
| // output the content | |
| logger.warn("Pages 404: " + resource); | |
| response.setStatus(HttpServletResponse.SC_NOT_FOUND); | |
| response.getOutputStream().write(content); | |
| response.flushBuffer(); | |
| } catch (Throwable t) { | |
| logger.error("Failed to write page to client", t); | |
| } | |
| return; | |
| } | |
| // check to see if we should transform markdown files | |
| for (String ext : GitBlit.getStrings(Keys.web.markdownExtensions)) { | |
| if (resource.endsWith(ext)) { | |
| String mkd = new String(content, Constants.ENCODING); | |
| content = MarkdownUtils.transformMarkdown(mkd).getBytes(Constants.ENCODING); | |
| response.setContentType("text/html; charset=" + Constants.ENCODING); | |
| break; | |
| } | |
| } | |
| try { | |
| // output the content | |
| response.setHeader("Cache-Control", "public, max-age=3600, must-revalidate"); | |
| response.setDateHeader("Last-Modified", JGitUtils.getCommitDate(commit).getTime()); | |
| response.getOutputStream().write(content); | |
| response.flushBuffer(); | |
| } catch (Throwable t) { | |
| logger.error("Failed to write page to client", t); | |
| } | |
| // close the repository | |
| r.close(); | |
| } catch (Throwable t) { | |
| logger.error("Failed to write page 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(HttpServletRequest request, HttpServletResponse response) | |
| throws ServletException, IOException { | |
| processRequest(request, response); | |
| } | |
| @Override | |
| protected void doGet(HttpServletRequest request, HttpServletResponse response) | |
| throws ServletException, IOException { | |
| processRequest(request, response); | |
| } | |
| } |