James Moger
2013-10-01 4360b3af73e5e9e575adee9f8d8b462a20445553
commit | author | age
11924d 1 /*
JM 2  * Copyright 2012 gitblit.com.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package com.gitblit;
17
18 import java.io.IOException;
19 import java.text.MessageFormat;
20 import java.text.ParseException;
7eb982 21 import java.util.ArrayList;
YI 22 import java.util.List;
11924d 23
JM 24 import javax.servlet.ServletContext;
25 import javax.servlet.ServletException;
26 import javax.servlet.http.HttpServlet;
27 import javax.servlet.http.HttpServletRequest;
28 import javax.servlet.http.HttpServletResponse;
29
30 import org.eclipse.jgit.lib.Repository;
31 import org.eclipse.jgit.revwalk.RevCommit;
32 import org.eclipse.jgit.revwalk.RevTree;
33 import org.slf4j.Logger;
34 import org.slf4j.LoggerFactory;
35
36 import com.gitblit.models.RefModel;
37 import com.gitblit.utils.ArrayUtils;
38 import com.gitblit.utils.JGitUtils;
39 import com.gitblit.utils.MarkdownUtils;
40 import com.gitblit.utils.StringUtils;
41
42 /**
43  * Serves the content of a gh-pages branch.
699e71 44  *
11924d 45  * @author James Moger
699e71 46  *
11924d 47  */
JM 48 public class PagesServlet extends HttpServlet {
49
50     private static final long serialVersionUID = 1L;
51
52     private transient Logger logger = LoggerFactory.getLogger(PagesServlet.class);
53
54     public PagesServlet() {
55         super();
56     }
57
58     /**
59      * Returns an url to this servlet for the specified parameters.
699e71 60      *
11924d 61      * @param baseURL
JM 62      * @param repository
63      * @param path
64      * @return an url
65      */
66     public static String asLink(String baseURL, String repository, String path) {
67         if (baseURL.length() > 0 && baseURL.charAt(baseURL.length() - 1) == '/') {
68             baseURL = baseURL.substring(0, baseURL.length() - 1);
69         }
70         return baseURL + Constants.PAGES + repository + "/" + (path == null ? "" : ("/" + path));
71     }
72
73     /**
74      * Retrieves the specified resource from the gh-pages branch of the
75      * repository.
699e71 76      *
11924d 77      * @param request
JM 78      * @param response
79      * @throws javax.servlet.ServletException
80      * @throws java.io.IOException
81      */
82     private void processRequest(HttpServletRequest request, HttpServletResponse response)
83             throws ServletException, IOException {
84         String path = request.getPathInfo();
85         if (path.toLowerCase().endsWith(".git")) {
86             // forward to url with trailing /
87             // this is important for relative pages links
88             response.sendRedirect(request.getServletPath() + path + "/");
89             return;
90         }
91         if (path.charAt(0) == '/') {
92             // strip leading /
93             path = path.substring(1);
94         }
95
96         // determine repository and resource from url
97         String repository = "";
98         String resource = "";
99         Repository r = null;
100         int offset = 0;
101         while (r == null) {
102             int slash = path.indexOf('/', offset);
103             if (slash == -1) {
104                 repository = path;
105             } else {
106                 repository = path.substring(0, slash);
107             }
108             r = GitBlit.self().getRepository(repository, false);
109             offset = slash + 1;
110             if (offset > 0) {
111                 resource = path.substring(offset);
112             }
113             if (repository.equals(path)) {
114                 // either only repository in url or no repository found
115                 break;
116             }
117         }
118
119         ServletContext context = request.getSession().getServletContext();
120
121         try {
122             if (r == null) {
123                 // repository not found!
124                 String mkd = MessageFormat.format(
125                         "# Error\nSorry, no valid **repository** specified in this url: {0}!",
126                         repository);
127                 error(response, mkd);
128                 return;
129             }
130
131             // retrieve the content from the repository
132             RefModel pages = JGitUtils.getPagesBranch(r);
133             RevCommit commit = JGitUtils.getCommit(r, pages.getObjectId().getName());
134
135             if (commit == null) {
136                 // branch not found!
137                 String mkd = MessageFormat.format(
138                         "# Error\nSorry, the repository {0} does not have a **gh-pages** branch!",
139                         repository);
140                 error(response, mkd);
141                 r.close();
142                 return;
143             }
144
ae9e15 145             String [] encodings = GitBlit.getEncodings();
JM 146
11924d 147             RevTree tree = commit.getTree();
JM 148             byte[] content = null;
149             if (StringUtils.isEmpty(resource)) {
150                 // find resource
7eb982 151                 List<String> markdownExtensions = GitBlit.getStrings(Keys.web.markdownExtensions);
d6bbb2 152                 List<String> extensions = new ArrayList<String>(markdownExtensions.size() + 2);
7eb982 153                 extensions.add("html");
d6bbb2 154                 extensions.add("htm");
7eb982 155                 extensions.addAll(markdownExtensions);
YI 156                 for (String ext : extensions){
157                     String file = "index." + ext;
1dcfd2 158                     String stringContent = JGitUtils.getStringContent(r, tree, file, encodings);
YI 159                     if(stringContent == null){
160                         continue;
161                     }
162                     content = stringContent.getBytes(Constants.ENCODING);
11924d 163                     if (content != null) {
JM 164                         resource = file;
165                         // assume text/html unless the servlet container
166                         // overrides
167                         response.setContentType("text/html; charset=" + Constants.ENCODING);
168                         break;
169                     }
170                 }
171             } else {
172                 // specific resource
d35134 173                 try {
JM 174                     String contentType = context.getMimeType(resource);
175                     if (contentType == null) {
176                         contentType = "text/plain";
177                     }
178                     if (contentType.startsWith("text")) {
ae9e15 179                         content = JGitUtils.getStringContent(r, tree, resource, encodings).getBytes(
d35134 180                                 Constants.ENCODING);
JM 181                     } else {
e4e682 182                         content = JGitUtils.getByteContent(r, tree, resource, false);
d35134 183                     }
JM 184                     response.setContentType(contentType);
185                 } catch (Exception e) {
11924d 186                 }
JM 187             }
188
189             // no content, try custom 404 page
190             if (ArrayUtils.isEmpty(content)) {
ae9e15 191                 String custom404 = JGitUtils.getStringContent(r, tree, "404.html", encodings);
d35134 192                 if (!StringUtils.isEmpty(custom404)) {
JM 193                     content = custom404.getBytes(Constants.ENCODING);
194                 }
195
11924d 196                 // still no content
JM 197                 if (ArrayUtils.isEmpty(content)) {
d35134 198                     String str = MessageFormat.format(
11924d 199                             "# Error\nSorry, the requested resource **{0}** was not found.",
d35134 200                             resource);
JM 201                     content = MarkdownUtils.transformMarkdown(str).getBytes(Constants.ENCODING);
11924d 202                 }
d35134 203
JM 204                 try {
205                     // output the content
206                     logger.warn("Pages 404: " + resource);
207                     response.setStatus(HttpServletResponse.SC_NOT_FOUND);
208                     response.getOutputStream().write(content);
209                     response.flushBuffer();
210                 } catch (Throwable t) {
211                     logger.error("Failed to write page to client", t);
212                 }
213                 return;
11924d 214             }
JM 215
216             // check to see if we should transform markdown files
217             for (String ext : GitBlit.getStrings(Keys.web.markdownExtensions)) {
218                 if (resource.endsWith(ext)) {
219                     String mkd = new String(content, Constants.ENCODING);
220                     content = MarkdownUtils.transformMarkdown(mkd).getBytes(Constants.ENCODING);
94e0bf 221                     response.setContentType("text/html; charset=" + Constants.ENCODING);
11924d 222                     break;
JM 223                 }
224             }
225
226             try {
227                 // output the content
a7db57 228                 response.setHeader("Cache-Control", "public, max-age=3600, must-revalidate");
JM 229                 response.setDateHeader("Last-Modified", JGitUtils.getCommitDate(commit).getTime());
11924d 230                 response.getOutputStream().write(content);
JM 231                 response.flushBuffer();
232             } catch (Throwable t) {
233                 logger.error("Failed to write page to client", t);
234             }
235
236             // close the repository
237             r.close();
238         } catch (Throwable t) {
239             logger.error("Failed to write page to client", t);
240         }
241     }
242
243     private void error(HttpServletResponse response, String mkd) throws ServletException,
244             IOException, ParseException {
245         String content = MarkdownUtils.transformMarkdown(mkd);
246         response.setContentType("text/html; charset=" + Constants.ENCODING);
247         response.getWriter().write(content);
248     }
249
250     @Override
251     protected void doPost(HttpServletRequest request, HttpServletResponse response)
252             throws ServletException, IOException {
253         processRequest(request, response);
254     }
255
256     @Override
257     protected void doGet(HttpServletRequest request, HttpServletResponse response)
258             throws ServletException, IOException {
259         processRequest(request, response);
260     }
261 }