/** * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you 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 org.apache.hadoop.http; import java.io.IOException; import java.text.DateFormat; import java.util.Arrays; import java.util.Date; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.mortbay.jetty.servlet.DefaultServlet; import org.mortbay.resource.Resource; import org.mortbay.util.StringUtil; import org.mortbay.util.URIUtil; /** * Instead of using absolute path in the href link, * we use relative path */ public class StaticServlet extends DefaultServlet { private static final long serialVersionUID = 1L; public static final Log LOG = LogFactory.getLog(StaticServlet.class); protected void sendDirectory(HttpServletRequest request, HttpServletResponse response, Resource resource, boolean parent) throws IOException { byte[] data=null; String base = URIUtil.addPaths(request.getRequestURI(),URIUtil.SLASH); // Use customized getListHTML String dir = getListHTML(resource, base, parent); if (dir==null) { response.sendError(HttpServletResponse.SC_FORBIDDEN, "No directory"); return; } data=dir.getBytes("UTF-8"); response.setContentType("text/html; charset=UTF-8"); response.setContentLength(data.length); response.getOutputStream().write(data); } private static String deTag(String raw) { return StringUtil.replace( StringUtil.replace(raw,"<","<"), ">", ">"); } /** * Defang any characters that could break the URI string in an HREF. * Such as <a href="/path/to;<script>Window.alert("XSS"+'%20'+"here");</script>">Link</a> * * The above example would parse incorrectly on various browsers as the "<" or '"' characters * would end the href attribute value string prematurely. * * @param raw the raw text to defang. * @return the defanged text. */ private static String defangURI(String raw) { StringBuffer buf = null; if (buf==null) { for (int i=0;i<raw.length();i++) { char c=raw.charAt(i); switch(c) { case '\'': case '"': case '<': case '>': buf=new StringBuffer(raw.length()<<1); break; } } if (buf==null) return raw; } for (int i=0;i<raw.length();i++) { char c=raw.charAt(i); switch(c) { case '"': buf.append("%22"); continue; case '\'': buf.append("%27"); continue; case '<': buf.append("%3C"); continue; case '>': buf.append("%3E"); continue; default: buf.append(c); continue; } } return buf.toString(); } public String getListHTML(Resource resource, String base, boolean parent) throws IOException { base=URIUtil.canonicalPath(base); if (base==null || !resource.isDirectory()) return null; String[] ls = resource.list(); if (ls==null) return null; Arrays.sort(ls); String decodedBase = URIUtil.decodePath(base); String title = "Directory: "+deTag(decodedBase); StringBuffer buf=new StringBuffer(4096); buf.append("<HTML><HEAD><TITLE>"); buf.append(title); buf.append("</TITLE></HEAD><BODY>\n<H1>"); buf.append(title); buf.append("</H1>\n<TABLE BORDER=0>\n"); if (parent) { buf.append("<TR><TD><A HREF=\""); buf.append(URIUtil.addPaths(base,"../")); buf.append("\">Parent Directory</A></TD><TD></TD><TD></TD></TR>\n"); } String defangedBase = defangURI(base); DateFormat dfmt=DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.MEDIUM); for (int i=0 ; i< ls.length ; i++) { Resource item = resource.addPath(ls[i]); buf.append("\n<TR><TD><A HREF=\""); String path=URIUtil.addPaths(defangedBase,URIUtil.encodePath(ls[i])); buf.append(URIUtil.encodePath(ls[i])); if (item.isDirectory() && !path.endsWith("/")) buf.append(URIUtil.SLASH); // URIUtil.encodePath(buf,path); buf.append("\">"); buf.append(deTag(ls[i])); buf.append(" "); buf.append("</TD><TD ALIGN=right>"); buf.append(item.length()); buf.append(" bytes </TD><TD>"); buf.append(dfmt.format(new Date(item.lastModified()))); buf.append("</TD></TR>"); } buf.append("</TABLE>\n"); buf.append("</BODY></HTML>\n"); return buf.toString(); } }