Mercurial Hosting > nabble
diff src/nabble/view/web/forum/FileDownload.java @ 0:7ecd1a4ef557
add content
author | Franklin Schmidt <fschmidt@gmail.com> |
---|---|
date | Thu, 21 Mar 2019 19:15:52 -0600 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/nabble/view/web/forum/FileDownload.java Thu Mar 21 19:15:52 2019 -0600 @@ -0,0 +1,179 @@ +package nabble.view.web.forum; + +import fschmidt.util.java.HtmlUtils; +import fschmidt.util.java.IoUtils; +import fschmidt.util.servlet.AuthorizingServlet; +import fschmidt.util.servlet.JtpContext; +import nabble.model.FileUpload; +import nabble.model.Message; +import nabble.model.Node; +import nabble.model.Site; +import nabble.view.lib.Cache; +import nabble.view.lib.Jtp; +import nabble.view.lib.UrlMappable; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.LinkedHashSet; +import java.util.Map; +import java.util.ResourceBundle; +import java.util.Set; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + + +public final class FileDownload extends HttpServlet implements UrlMappable, AuthorizingServlet { + + private static final Pattern urlPtn = Pattern.compile("/file/(([a-z])(\\d+)/)?([^/]*)$"); + + public static String url(String filename,Message.Source src) { + return baseUrl(src) + path(filename,src); + } + + public static String path(String filename,Message.Source src) { + StringBuilder buf = new StringBuilder(); + buf.append( "/file/" ); + if (!src.getMessageSourceType().equals(Message.SourceType.SITE)) { + buf.append( src.getMessageSourceType().getCode() ); + buf.append( src.getSourceId() ); + buf.append( "/" ); + } + buf.append( HtmlUtils.urlEncode(filename) ); + return buf.toString(); + } + + private static String baseUrl(Message.Source src) { + return src.getSite().getBaseUrl(); + } + + public Map<String,String[]> getParameterMapFromUrl(HttpServletRequest request,String mappedUrl) { + Matcher m = urlPtn.matcher(mappedUrl); + if( !m.find() ) + throw new RuntimeException(); + Map<String,String[]> params = new HashMap<String,String[]>(); + if (m.group(1) == null) + params.put("type",new String[]{String.valueOf(Message.SourceType.SITE.getCode())}); + else { + String type = m.group(2); + params.put("type",new String[]{type}); + String fileId = m.group(3); + params.put("id",new String[]{fileId}); + } + String name = m.group(4); + params.put("name",new String[]{name}); + return params; + } + + public Pattern getUrlPattern() { + return urlPtn; + } + + public String getAuthorizationKey(HttpServletRequest request) throws ServletException { + Message.Source src = getSource(request); + return src instanceof Node ? Jtp.getReadAuthorizationKey((Node)src) : null; + } + + public boolean authorize(String key,HttpServletRequest request,HttpServletResponse response) throws ServletException, IOException { + return Jtp.authorizeForRead(key,request,response); + } + + private static final Map<String,String> mimeMap = new HashMap<String,String>(); + static { + ResourceBundle mime = ResourceBundle.getBundle("org/eclipse/jetty/http/mime"); + Enumeration<String> i = mime.getKeys(); + while( i.hasMoreElements() ) { + String ext = i.nextElement(); + String type = mime.getString(ext); + mimeMap.put(ext.toLowerCase(),type); + } + } + + static String getMimeByExtension(String fileName) { + return mimeMap.get( fileName.substring(fileName.lastIndexOf('.')+1).toLowerCase() ); + } + + protected void service(HttpServletRequest request,HttpServletResponse response) + throws ServletException, IOException + { + JtpContext jtpContext = (JtpContext)getServletContext().getAttribute(JtpContext.attrName); + char type = request.getParameter("type").charAt(0); + Message.Source src = getSource(request); + if (src == null) { + response.sendError(HttpServletResponse.SC_NOT_FOUND,"File not found"); + return; + } + + switch(type) { + case 't': + break; + case 's': + jtpContext.setEtag(request,response, Cache.siteChangeEvent(src.getSite()) ); + break; + case 'n': + { + Set<String> events = new LinkedHashSet<String>(); + if( src instanceof Node ) { + Node node = (Node)src; + events.add( Cache.nodeFileChangeEvent(node) ); + Jtp.addBreadCrumbEvents(events, node); + } + jtpContext.setEtag(request,response, events.toArray(new String[events.size()]) ); + } + break; + case 'a': + jtpContext.setEtag(request,response, Cache.userFileChangeEvent(((Message.AvatarSource)src).getUser()) ); + break; + default: + if( Jtp.invalidReferer(request) ) { + throw new ServletException("type = '"+type+"'"); + } else { + throw new RuntimeException("type = '"+type+"'"); + } + } + + response.setHeader("Cache-Control",null); + String name = request.getParameter("name"); + + InputStream in = FileUpload.getFileContent(src,name); + if (in == null) { + name = HtmlUtils.urlDecode(name); + in = FileUpload.getFileContent(src, name); + if (in == null) { + // We have to find a better way to track this down -- the log is too full of missing images [Hugo/Jun-2010] + response.sendError(HttpServletResponse.SC_NOT_FOUND,"File not found"); + return; + } + } + OutputStream out = response.getOutputStream(); + response.setContentType(getMimeByExtension(name)); + try { + IoUtils.copyAll(in,out); + } finally { + in.close(); + } + } + + private static Message.Source getSource(HttpServletRequest request) + throws ServletException + { + char type = request.getParameter("type").charAt(0); + Message.SourceType sourceType = Message.SourceType.getType(type); + if( sourceType==null ) + return null; + Site site = Jtp.getSite(request); + if (site == null) + return null; + if (sourceType.equals(Message.SourceType.SITE)) + return site; + long fileId = Jtp.getLong(request,"id"); + return sourceType.getSource(site,fileId); + } + +}