Rafael Cavazin
2013-07-21 f66e89662c091e082bd1d2feb6ac91513ccff273
src/main/java/com/gitblit/PagesServlet.java
New file
@@ -0,0 +1,261 @@
/*
 * 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);
   }
}