0
|
1 package nabble.view.web.forum;
|
|
2
|
|
3 import fschmidt.util.java.HtmlUtils;
|
|
4 import fschmidt.util.java.IoUtils;
|
|
5 import fschmidt.util.servlet.AuthorizingServlet;
|
|
6 import fschmidt.util.servlet.JtpContext;
|
|
7 import nabble.model.FileUpload;
|
|
8 import nabble.model.Message;
|
|
9 import nabble.model.Node;
|
|
10 import nabble.model.Site;
|
|
11 import nabble.view.lib.Cache;
|
|
12 import nabble.view.lib.Jtp;
|
|
13 import nabble.view.lib.UrlMappable;
|
|
14
|
|
15 import javax.servlet.ServletException;
|
|
16 import javax.servlet.http.HttpServlet;
|
|
17 import javax.servlet.http.HttpServletRequest;
|
|
18 import javax.servlet.http.HttpServletResponse;
|
|
19 import java.io.IOException;
|
|
20 import java.io.InputStream;
|
|
21 import java.io.OutputStream;
|
|
22 import java.util.Enumeration;
|
|
23 import java.util.HashMap;
|
|
24 import java.util.LinkedHashSet;
|
|
25 import java.util.Map;
|
|
26 import java.util.ResourceBundle;
|
|
27 import java.util.Set;
|
|
28 import java.util.regex.Matcher;
|
|
29 import java.util.regex.Pattern;
|
|
30
|
|
31
|
|
32 public final class FileDownload extends HttpServlet implements UrlMappable, AuthorizingServlet {
|
|
33
|
|
34 private static final Pattern urlPtn = Pattern.compile("/file/(([a-z])(\\d+)/)?([^/]*)$");
|
|
35
|
|
36 public static String url(String filename,Message.Source src) {
|
|
37 return baseUrl(src) + path(filename,src);
|
|
38 }
|
|
39
|
|
40 public static String path(String filename,Message.Source src) {
|
|
41 StringBuilder buf = new StringBuilder();
|
|
42 buf.append( "/file/" );
|
|
43 if (!src.getMessageSourceType().equals(Message.SourceType.SITE)) {
|
|
44 buf.append( src.getMessageSourceType().getCode() );
|
|
45 buf.append( src.getSourceId() );
|
|
46 buf.append( "/" );
|
|
47 }
|
|
48 buf.append( HtmlUtils.urlEncode(filename) );
|
|
49 return buf.toString();
|
|
50 }
|
|
51
|
|
52 private static String baseUrl(Message.Source src) {
|
|
53 return src.getSite().getBaseUrl();
|
|
54 }
|
|
55
|
|
56 public Map<String,String[]> getParameterMapFromUrl(HttpServletRequest request,String mappedUrl) {
|
|
57 Matcher m = urlPtn.matcher(mappedUrl);
|
|
58 if( !m.find() )
|
|
59 throw new RuntimeException();
|
|
60 Map<String,String[]> params = new HashMap<String,String[]>();
|
|
61 if (m.group(1) == null)
|
|
62 params.put("type",new String[]{String.valueOf(Message.SourceType.SITE.getCode())});
|
|
63 else {
|
|
64 String type = m.group(2);
|
|
65 params.put("type",new String[]{type});
|
|
66 String fileId = m.group(3);
|
|
67 params.put("id",new String[]{fileId});
|
|
68 }
|
|
69 String name = m.group(4);
|
|
70 params.put("name",new String[]{name});
|
|
71 return params;
|
|
72 }
|
|
73
|
|
74 public Pattern getUrlPattern() {
|
|
75 return urlPtn;
|
|
76 }
|
|
77
|
|
78 public String getAuthorizationKey(HttpServletRequest request) throws ServletException {
|
|
79 Message.Source src = getSource(request);
|
|
80 return src instanceof Node ? Jtp.getReadAuthorizationKey((Node)src) : null;
|
|
81 }
|
|
82
|
|
83 public boolean authorize(String key,HttpServletRequest request,HttpServletResponse response) throws ServletException, IOException {
|
|
84 return Jtp.authorizeForRead(key,request,response);
|
|
85 }
|
|
86
|
|
87 private static final Map<String,String> mimeMap = new HashMap<String,String>();
|
|
88 static {
|
|
89 ResourceBundle mime = ResourceBundle.getBundle("org/eclipse/jetty/http/mime");
|
|
90 Enumeration<String> i = mime.getKeys();
|
|
91 while( i.hasMoreElements() ) {
|
|
92 String ext = i.nextElement();
|
|
93 String type = mime.getString(ext);
|
|
94 mimeMap.put(ext.toLowerCase(),type);
|
|
95 }
|
|
96 }
|
|
97
|
|
98 static String getMimeByExtension(String fileName) {
|
|
99 return mimeMap.get( fileName.substring(fileName.lastIndexOf('.')+1).toLowerCase() );
|
|
100 }
|
|
101
|
|
102 protected void service(HttpServletRequest request,HttpServletResponse response)
|
|
103 throws ServletException, IOException
|
|
104 {
|
|
105 JtpContext jtpContext = (JtpContext)getServletContext().getAttribute(JtpContext.attrName);
|
|
106 char type = request.getParameter("type").charAt(0);
|
|
107 Message.Source src = getSource(request);
|
|
108 if (src == null) {
|
|
109 response.sendError(HttpServletResponse.SC_NOT_FOUND,"File not found");
|
|
110 return;
|
|
111 }
|
|
112
|
|
113 switch(type) {
|
|
114 case 't':
|
|
115 break;
|
|
116 case 's':
|
|
117 jtpContext.setEtag(request,response, Cache.siteChangeEvent(src.getSite()) );
|
|
118 break;
|
|
119 case 'n':
|
|
120 {
|
|
121 Set<String> events = new LinkedHashSet<String>();
|
|
122 if( src instanceof Node ) {
|
|
123 Node node = (Node)src;
|
|
124 events.add( Cache.nodeFileChangeEvent(node) );
|
|
125 Jtp.addBreadCrumbEvents(events, node);
|
|
126 }
|
|
127 jtpContext.setEtag(request,response, events.toArray(new String[events.size()]) );
|
|
128 }
|
|
129 break;
|
|
130 case 'a':
|
|
131 jtpContext.setEtag(request,response, Cache.userFileChangeEvent(((Message.AvatarSource)src).getUser()) );
|
|
132 break;
|
|
133 default:
|
|
134 if( Jtp.invalidReferer(request) ) {
|
|
135 throw new ServletException("type = '"+type+"'");
|
|
136 } else {
|
|
137 throw new RuntimeException("type = '"+type+"'");
|
|
138 }
|
|
139 }
|
|
140
|
|
141 response.setHeader("Cache-Control",null);
|
|
142 String name = request.getParameter("name");
|
|
143
|
|
144 InputStream in = FileUpload.getFileContent(src,name);
|
|
145 if (in == null) {
|
|
146 name = HtmlUtils.urlDecode(name);
|
|
147 in = FileUpload.getFileContent(src, name);
|
|
148 if (in == null) {
|
|
149 // We have to find a better way to track this down -- the log is too full of missing images [Hugo/Jun-2010]
|
|
150 response.sendError(HttpServletResponse.SC_NOT_FOUND,"File not found");
|
|
151 return;
|
|
152 }
|
|
153 }
|
|
154 OutputStream out = response.getOutputStream();
|
|
155 response.setContentType(getMimeByExtension(name));
|
|
156 try {
|
|
157 IoUtils.copyAll(in,out);
|
|
158 } finally {
|
|
159 in.close();
|
|
160 }
|
|
161 }
|
|
162
|
|
163 private static Message.Source getSource(HttpServletRequest request)
|
|
164 throws ServletException
|
|
165 {
|
|
166 char type = request.getParameter("type").charAt(0);
|
|
167 Message.SourceType sourceType = Message.SourceType.getType(type);
|
|
168 if( sourceType==null )
|
|
169 return null;
|
|
170 Site site = Jtp.getSite(request);
|
|
171 if (site == null)
|
|
172 return null;
|
|
173 if (sourceType.equals(Message.SourceType.SITE))
|
|
174 return site;
|
|
175 long fileId = Jtp.getLong(request,"id");
|
|
176 return sourceType.getSource(site,fileId);
|
|
177 }
|
|
178
|
|
179 }
|