view 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 source

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);
	}

}