This project has retired. For details please refer to its
Attic page.
BrowseServlet xref
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.chemistry.opencmis.browser;
20
21 import java.io.BufferedInputStream;
22 import java.io.BufferedOutputStream;
23 import java.io.IOException;
24 import java.io.InputStream;
25 import java.io.OutputStream;
26 import java.io.PrintWriter;
27 import java.net.HttpURLConnection;
28 import java.net.URL;
29 import java.net.URLDecoder;
30 import java.util.Enumeration;
31 import java.util.HashMap;
32 import java.util.Map;
33
34 import javax.servlet.ServletConfig;
35 import javax.servlet.ServletException;
36 import javax.servlet.http.HttpServlet;
37 import javax.servlet.http.HttpServletRequest;
38 import javax.servlet.http.HttpServletResponse;
39 import javax.xml.parsers.DocumentBuilder;
40 import javax.xml.parsers.DocumentBuilderFactory;
41 import javax.xml.transform.Result;
42 import javax.xml.transform.Source;
43 import javax.xml.transform.Transformer;
44 import javax.xml.transform.TransformerFactory;
45 import javax.xml.transform.dom.DOMSource;
46 import javax.xml.transform.stream.StreamResult;
47 import javax.xml.transform.stream.StreamSource;
48
49 import org.apache.commons.logging.Log;
50 import org.apache.commons.logging.LogFactory;
51 import org.w3c.dom.Document;
52
53
54
55
56 public class BrowseServlet extends HttpServlet {
57
58 private static final long serialVersionUID = 1L;
59
60 private static final Log log = LogFactory.getLog(BrowseServlet.class);
61
62 private static final String CONTEXT_PREFIX = "{ctx}";
63 private static final String PARAM_URL = "url";
64 private static final String PARAM_OVERRIDE_STYLESHEET = "overrideStylesheet";
65 private static final int PARAM_URL_MIN_LEN = PARAM_URL.length() + "=".length() + "http".length() + "://".length()
66 + 1;
67 private static final String INIT_PARAM_AUXROOT = "auxroot";
68 private static final String INIT_PARAM_ALLOW = "allow";
69 private static final String INIT_PARAM_STYLESHEET = "stylesheet:";
70 private static final String INIT_PARAM_OVERRIDE_STYLESHEET = "override-stylesheet:";
71
72 private static final int BUFFER_SIZE = 64 * 1024;
73
74 private String fAuxRoot = "";
75 private String fAllow = ".*";
76 private Map<String, Source> fStyleSheets;
77 private Map<String, Source> fOverrideStyleSheets;
78
79
80
81
82 @SuppressWarnings("unchecked")
83 @Override
84 public void init(ServletConfig config) throws ServletException {
85 fStyleSheets = new HashMap<String, Source>();
86 fOverrideStyleSheets = new HashMap<String, Source>();
87
88 DocumentBuilder builder = null;
89 try {
90 DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance();
91 builderFactory.setNamespaceAware(true);
92 builder = builderFactory.newDocumentBuilder();
93 } catch (Exception e) {
94 e.printStackTrace();
95 return;
96 }
97
98 Enumeration<String> initParams = config.getInitParameterNames();
99 while (initParams.hasMoreElements()) {
100 String param = initParams.nextElement();
101 String stylesheetKey = null;
102 boolean isOverride = false;
103
104 if (param.startsWith(INIT_PARAM_STYLESHEET)) {
105 stylesheetKey = param.substring(INIT_PARAM_STYLESHEET.length());
106 } else if (param.startsWith(INIT_PARAM_OVERRIDE_STYLESHEET)) {
107 stylesheetKey = param.substring(INIT_PARAM_OVERRIDE_STYLESHEET.length());
108 isOverride = true;
109 }
110
111 if (stylesheetKey != null) {
112 String stylesheetFileName = config.getInitParameter(param);
113 InputStream stream = config.getServletContext().getResourceAsStream(stylesheetFileName);
114 if (stream != null) {
115 try {
116 Document xslDoc = builder.parse(stream);
117 addStylesheet(stylesheetKey, new DOMSource(xslDoc), isOverride);
118
119 log.info("Stylesheet: '" + stylesheetKey + "' -> '" + stylesheetFileName + "'");
120 } catch (Exception e) {
121 e.printStackTrace();
122 }
123 }
124 }
125 }
126
127 String initAuxRoot = config.getInitParameter(INIT_PARAM_AUXROOT);
128 if (initAuxRoot != null) {
129 fAuxRoot = initAuxRoot;
130 log.info("Auxiliary root: " + fAuxRoot);
131 }
132
133 String initAllow = config.getInitParameter(INIT_PARAM_ALLOW);
134 if (initAllow != null) {
135 fAllow = initAllow;
136 log.info("Allow pattern: " + fAllow);
137 }
138 }
139
140
141
142
143 @Override
144 protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
145 String browseUrl = null;
146 String overrideStylesheet = null;
147
148
149 String queryString = req.getQueryString();
150
151 if ((queryString != null) && (queryString.startsWith(PARAM_URL))) {
152 int urlEnd = queryString.indexOf(PARAM_OVERRIDE_STYLESHEET + "=");
153 if (urlEnd == -1) {
154 urlEnd = queryString.length();
155 } else {
156 overrideStylesheet = queryString.substring(urlEnd + PARAM_OVERRIDE_STYLESHEET.length() + 1);
157 --urlEnd;
158 }
159
160 browseUrl = queryString.substring(PARAM_URL.length() + 1, urlEnd);
161
162 if (browseUrl.length() < PARAM_URL_MIN_LEN) {
163 browseUrl = null;
164 }
165 }
166
167 if (browseUrl == null) {
168 printInput(req, resp);
169 return;
170 }
171
172 doBrowse(req, resp, browseUrl, overrideStylesheet);
173 }
174
175
176
177
178 protected void doBrowse(HttpServletRequest req, HttpServletResponse resp, String browseUrl,
179 String overrideStylesheet) throws ServletException, IOException {
180
181
182
183 if (browseUrl.charAt(4) != ':' && browseUrl.charAt(5) != ':') {
184 browseUrl = URLDecoder.decode(browseUrl, "UTF-8");
185 }
186
187
188 if (!browseUrl.matches(fAllow)) {
189 printError(req, resp, "Prohibited URL!", null);
190 return;
191 }
192
193 try {
194
195 URL url = new URL(browseUrl);
196 HttpURLConnection conn = (HttpURLConnection) url.openConnection();
197 conn.setDoInput(true);
198 conn.setDoOutput(false);
199 conn.setRequestMethod("GET");
200 String authHeader = req.getHeader("Authorization");
201 if (authHeader != null) {
202 conn.setRequestProperty("Authorization", authHeader);
203 }
204 conn.connect();
205
206
207 if (conn.getResponseCode() == HttpURLConnection.HTTP_UNAUTHORIZED) {
208 resp.setHeader("WWW-Authenticate", conn.getHeaderField("WWW-Authenticate"));
209 resp.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Authorization Required");
210 return;
211 }
212
213
214 if (log.isDebugEnabled()) {
215 log.debug("'" + browseUrl + "' -> '" + conn.getContentType() + "'");
216 }
217
218
219 Source stylesheet = getStylesheet(conn.getContentType(), overrideStylesheet);
220
221 OutputStream out = null;
222 InputStream in = new BufferedInputStream(conn.getInputStream(), BUFFER_SIZE);
223
224 if (stylesheet == null) {
225
226 resp.setContentType(conn.getContentType());
227 out = new BufferedOutputStream(resp.getOutputStream(), BUFFER_SIZE);
228
229 byte[] buffer = new byte[BUFFER_SIZE];
230 int b;
231 while ((b = in.read(buffer)) > -1) {
232 out.write(buffer, 0, b);
233 }
234 } else {
235
236 TransformerFactory f = TransformerFactory.newInstance();
237 Transformer t = f.newTransformer(stylesheet);
238 t.setParameter("browseUrl", getServletUrl(req) + "?" + PARAM_URL + "=");
239 t.setParameter("auxRoot", getAuxRoot(req, fAuxRoot));
240 t.setParameter("browseOverrideStylesheet", "&" + PARAM_OVERRIDE_STYLESHEET + "=");
241
242 resp.setContentType("text/html");
243 out = new BufferedOutputStream(resp.getOutputStream(), BUFFER_SIZE);
244
245 Source s = new StreamSource(in);
246 Result r = new StreamResult(out);
247 t.transform(s, r);
248 }
249
250 try {
251 out.flush();
252 out.close();
253 } catch (Exception e) {
254 }
255
256 try {
257 in.close();
258 } catch (Exception e) {
259 }
260 } catch (Exception e) {
261 printError(req, resp, e.getMessage(), e);
262 return;
263 }
264 }
265
266
267
268
269
270
271 private void addStylesheet(String contentType, Source source, boolean override) {
272 if ((contentType == null) || (source == null)) {
273 return;
274 }
275
276 if (override) {
277 fOverrideStyleSheets.put(contentType.trim().toLowerCase(), source);
278 } else {
279 fStyleSheets.put(contentType.trim().toLowerCase(), source);
280 }
281 }
282
283
284
285
286
287
288 private Source getStylesheet(String contentType, String overrideStylesheet) {
289 if (contentType == null) {
290 return null;
291 }
292
293 Source source = null;
294
295
296 if (overrideStylesheet != null && overrideStylesheet.length() > 0) {
297 source = fOverrideStyleSheets.get(overrideStylesheet);
298 }
299
300
301 if (source == null) {
302 String[] ctp = contentType.trim().toLowerCase().split(";");
303
304 StringBuilder match = new StringBuilder();
305 int i = 0;
306 while (source == null && i < ctp.length) {
307 if (i > 0) {
308 match.append(";");
309 }
310 match.append(ctp[i]);
311 source = fStyleSheets.get(match.toString());
312 i++;
313 }
314 }
315
316 return source;
317 }
318
319
320
321
322 private String getContextUrl(HttpServletRequest request) {
323 String scheme = request.getScheme();
324 int port = request.getServerPort();
325
326 if ("http".equals(scheme) && (port == 80)) {
327 port = -1;
328 }
329 if ("https".equals(scheme) && (port == 443)) {
330 port = -1;
331 }
332
333 return scheme + "://" + request.getServerName() + (port > 0 ? ":" + port : "") + request.getContextPath();
334 }
335
336
337
338
339 private String getServletUrl(HttpServletRequest request) {
340 return getContextUrl(request) + request.getServletPath();
341 }
342
343
344
345
346 private String getAuxRoot(HttpServletRequest request, String auxRoot) {
347 if (auxRoot == null) {
348 return getContextUrl(request);
349 } else if (auxRoot.startsWith(CONTEXT_PREFIX)) {
350 return getContextUrl(request) + auxRoot.substring(CONTEXT_PREFIX.length());
351 } else {
352 return auxRoot;
353 }
354 }
355
356
357
358
359
360
361 private void printHeader(PrintWriter pw, String title) {
362 pw.print("<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"");
363 pw.println("\"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">");
364 pw.println("<html xmlns=\"http://www.w3.org/1999/xhtml\">");
365 pw.println("<head>");
366 pw.println("<title>" + title + "</title>");
367 pw.println("<meta http-equiv=\"content-type\" content=\"text/html; charset=UTF-8\" />");
368 pw.println("<style type=\"text/css\">");
369 pw.println("body { font-family: arial,sans-serif; font-size: 10pt; }");
370 pw.println("div.box { background-color: #f6f1de; margin-top: 10px;"
371 + " margin-bottom: 10px; margin-left: 0px; margin-right: 0px;"
372 + " padding: 5px; border-style: solid; border-width: 1px; border-color: #888a85; }");
373 pw.println("</style>");
374 pw.println("</head>");
375 pw.println("<body>");
376 }
377
378
379
380
381 private void printFooter(PrintWriter pw) {
382 pw.println("</body>");
383 pw.println("</html>");
384 }
385
386
387
388
389 private void printError(HttpServletRequest req, HttpServletResponse resp, String message, Exception e)
390 throws IOException {
391 resp.setContentType("text/html;charset=utf-8");
392 PrintWriter pw = resp.getWriter();
393
394 printHeader(pw, "Error");
395 pw.println("<div class=\"box\">");
396 pw.println("<h3>" + message + "</h3>");
397
398 if (e != null) {
399 pw.print("<pre>");
400 e.printStackTrace(pw);
401 pw.println("</pre>");
402 }
403
404 pw.println("</div>");
405 printFooter(pw);
406 }
407
408
409
410
411 private void printInput(HttpServletRequest req, HttpServletResponse resp) throws IOException {
412 resp.setContentType("text/html;charset=utf-8");
413 PrintWriter pw = resp.getWriter();
414
415 printHeader(pw, "OpenCMIS Browser");
416 pw.println("<img src=\"" + getAuxRoot(req, fAuxRoot) + "cmis.png\" " + "style=\"float: right;\" />");
417 pw.println("<h1 style=\"font-family: Georgia;\">OpenCMIS Browser</h1>");
418 pw.println("<div class=\"box\">");
419 pw.println("<form action=\"\" method=\"GET\">");
420 pw.println("CMIS AtomPub URL: ");
421 pw.println("<input name=\"url\" type=\"text\" size=\"100\" value=\"\"/>");
422 pw.println("<input type=\"submit\" value=\" GO \"/>");
423 pw.println("</form>");
424 pw.println("</div>");
425 printFooter(pw);
426 }
427 }