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