001: /**
002: * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE, version 2.1, dated February 1999.
003: *
004: * This program is free software; you can redistribute it and/or modify
005: * it under the terms of the latest version of the GNU Lesser General
006: * Public License as published by the Free Software Foundation;
007: *
008: * This program is distributed in the hope that it will be useful,
009: * but WITHOUT ANY WARRANTY; without even the implied warranty of
010: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
011: * GNU Lesser General Public License for more details.
012: *
013: * You should have received a copy of the GNU Lesser General Public License
014: * along with this program (LICENSE.txt); if not, write to the Free Software
015: * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
016: */package org.jamwiki.servlets;
017:
018: import java.io.File;
019: import java.util.Calendar;
020: import java.util.GregorianCalendar;
021: import java.util.Iterator;
022: import java.util.List;
023: import javax.servlet.http.HttpServletRequest;
024: import javax.servlet.http.HttpServletResponse;
025: import org.apache.commons.fileupload.FileItem;
026: import org.apache.commons.io.FilenameUtils;
027: import org.apache.commons.lang.StringUtils;
028: import org.jamwiki.Environment;
029: import org.jamwiki.WikiBase;
030: import org.jamwiki.WikiException;
031: import org.jamwiki.WikiMessage;
032: import org.jamwiki.model.Topic;
033: import org.jamwiki.model.TopicVersion;
034: import org.jamwiki.model.WikiFile;
035: import org.jamwiki.model.WikiFileVersion;
036: import org.jamwiki.model.WikiUser;
037: import org.jamwiki.parser.ParserOutput;
038: import org.jamwiki.parser.ParserUtil;
039: import org.jamwiki.utils.ImageUtil;
040: import org.jamwiki.utils.NamespaceHandler;
041: import org.jamwiki.utils.Utilities;
042: import org.jamwiki.utils.WikiLogger;
043: import org.jamwiki.utils.WikiUtil;
044: import org.springframework.web.servlet.ModelAndView;
045:
046: /**
047: * Used to handle file uploads.
048: */
049: public class UploadServlet extends JAMWikiServlet {
050:
051: private static final WikiLogger logger = WikiLogger
052: .getLogger(UploadServlet.class.getName());
053: protected static final String JSP_UPLOAD = "upload.jsp";
054:
055: /**
056: *
057: */
058: protected ModelAndView handleJAMWikiRequest(
059: HttpServletRequest request, HttpServletResponse response,
060: ModelAndView next, WikiPageInfo pageInfo) throws Exception {
061: String contentType = ((request.getContentType() != null) ? request
062: .getContentType().toLowerCase()
063: : "");
064: if (contentType.indexOf("multipart") == -1) {
065: view(request, next, pageInfo);
066: } else {
067: upload(request, next, pageInfo);
068: }
069: return next;
070: }
071:
072: /**
073: *
074: */
075: private static String buildFileSubdirectory() {
076: // subdirectory is composed of year/month
077: GregorianCalendar cal = new GregorianCalendar();
078: String year = Integer.toString(cal.get(Calendar.YEAR));
079: String month = Integer.toString(cal.get(Calendar.MONTH) + 1);
080: return "/" + year + "/" + month;
081: }
082:
083: /**
084: *
085: */
086: private static String buildUniqueFileName(String fileName) {
087: if (StringUtils.isBlank(fileName)) {
088: return null;
089: }
090: // file is appended with a timestamp of DDHHMMSS
091: GregorianCalendar cal = new GregorianCalendar();
092: String day = Integer.toString(cal.get(Calendar.DAY_OF_MONTH));
093: if (day.length() == 1) {
094: day = "0" + day;
095: }
096: String hour = Integer.toString(cal.get(Calendar.HOUR_OF_DAY));
097: if (hour.length() == 1) {
098: hour = "0" + hour;
099: }
100: String minute = Integer.toString(cal.get(Calendar.MINUTE));
101: if (minute.length() == 1) {
102: minute = "0" + minute;
103: }
104: String second = Integer.toString(cal.get(Calendar.SECOND));
105: if (second.length() == 1) {
106: second = "0" + second;
107: }
108: String suffix = "-" + day + hour + minute + second;
109: int pos = fileName.lastIndexOf('.');
110: if (pos == -1) {
111: fileName = fileName + suffix;
112: } else {
113: fileName = fileName.substring(0, pos) + suffix
114: + fileName.substring(pos);
115: }
116: return fileName;
117: }
118:
119: /**
120: *
121: */
122: private boolean handleSpam(HttpServletRequest request,
123: ModelAndView next, WikiPageInfo pageInfo, String topicName,
124: String contents) throws Exception {
125: String result = ServletUtil.checkForSpam(request, topicName,
126: contents);
127: if (result == null) {
128: return false;
129: }
130: WikiMessage spam = new WikiMessage("edit.exception.spam",
131: result);
132: next.addObject("spam", spam);
133: next.addObject("contents", contents);
134: next.addObject("uploadSpam", "true");
135: return true;
136: }
137:
138: /**
139: *
140: */
141: private boolean isFileTypeAllowed(String extension) {
142: int blacklistType = Environment
143: .getIntValue(Environment.PROP_FILE_BLACKLIST_TYPE);
144: if (blacklistType == WikiBase.UPLOAD_ALL) {
145: return true;
146: }
147: if (blacklistType == WikiBase.UPLOAD_NONE) {
148: return false;
149: }
150: if (StringUtils.isBlank(extension)) {
151: // FIXME - should non-extensions be represented in the whitelist/blacklist?
152: return true;
153: }
154: extension = extension.toLowerCase();
155: List list = WikiUtil.retrieveUploadFileList();
156: if (blacklistType == WikiBase.UPLOAD_BLACKLIST) {
157: return !list.contains(extension);
158: }
159: if (blacklistType == WikiBase.UPLOAD_WHITELIST) {
160: return list.contains(extension);
161: }
162: return false;
163: }
164:
165: /**
166: *
167: */
168: private static String sanitizeFilename(String filename) {
169: if (StringUtils.isBlank(filename)) {
170: return null;
171: }
172: // some browsers set the full path, so strip to just the file name
173: filename = FilenameUtils.getName(filename);
174: filename = StringUtils.replace(filename.trim(), " ", "_");
175: return filename;
176: }
177:
178: /**
179: *
180: */
181: private void upload(HttpServletRequest request, ModelAndView next,
182: WikiPageInfo pageInfo) throws Exception {
183: // FIXME - this method is a mess and needs to be split up.
184: File file = new File(Environment
185: .getValue(Environment.PROP_FILE_DIR_FULL_PATH));
186: if (!file.exists()) {
187: throw new WikiException(new WikiMessage(
188: "upload.error.nodirectory"));
189: }
190: Iterator iterator = ServletUtil
191: .processMultipartRequest(
192: request,
193: Environment
194: .getValue(Environment.PROP_FILE_DIR_FULL_PATH),
195: Environment
196: .getLongValue(Environment.PROP_FILE_MAX_FILE_SIZE));
197: String fileName = null;
198: String url = null;
199: String contentType = null;
200: long fileSize = 0;
201: String contents = null;
202: boolean isImage = true;
203: while (iterator.hasNext()) {
204: FileItem item = (FileItem) iterator.next();
205: String fieldName = item.getFieldName();
206: if (item.isFormField()) {
207: if (fieldName.equals("description")) {
208: // FIXME - these should be parsed
209: contents = item.getString("UTF-8");
210: }
211: } else {
212: // file name can have encoding issues, so manually convert
213: fileName = item.getName();
214: if (fileName == null) {
215: throw new WikiException(new WikiMessage(
216: "upload.error.filename"));
217: }
218: fileName = UploadServlet.sanitizeFilename(fileName);
219: String extension = FilenameUtils.getExtension(fileName);
220: if (!isFileTypeAllowed(extension)) {
221: throw new WikiException(new WikiMessage(
222: "upload.error.filetype", extension));
223: }
224: url = UploadServlet.buildUniqueFileName(fileName);
225: String subdirectory = UploadServlet
226: .buildFileSubdirectory();
227: fileSize = item.getSize();
228: File directory = new File(Environment
229: .getValue(Environment.PROP_FILE_DIR_FULL_PATH),
230: subdirectory);
231: if (!directory.exists() && !directory.mkdirs()) {
232: throw new WikiException(new WikiMessage(
233: "upload.error.directorycreate", directory
234: .getAbsolutePath()));
235: }
236: contentType = item.getContentType();
237: url = subdirectory + "/" + url;
238: File uploadedFile = new File(Environment
239: .getValue(Environment.PROP_FILE_DIR_FULL_PATH),
240: url);
241: item.write(uploadedFile);
242: isImage = ImageUtil.isImage(uploadedFile);
243: }
244: }
245: String virtualWiki = WikiUtil.getVirtualWikiFromURI(request);
246: String topicName = NamespaceHandler.NAMESPACE_IMAGE
247: + NamespaceHandler.NAMESPACE_SEPARATOR
248: + Utilities.decodeFromURL(fileName, true);
249: if (this .handleSpam(request, next, pageInfo, topicName,
250: contents)) {
251: // FIXME - the uploaded content should be deleted
252: this .view(request, next, pageInfo);
253: return;
254: }
255: Topic topic = WikiBase.getDataHandler().lookupTopic(
256: virtualWiki, topicName, false, null);
257: if (topic == null) {
258: topic = new Topic();
259: topic.setVirtualWiki(virtualWiki);
260: topic.setName(topicName);
261: topic.setTopicContent(contents);
262: }
263: if (isImage) {
264: topic.setTopicType(Topic.TYPE_IMAGE);
265: } else {
266: topic.setTopicType(Topic.TYPE_FILE);
267: }
268: WikiFileVersion wikiFileVersion = new WikiFileVersion();
269: wikiFileVersion.setUploadComment(contents);
270: wikiFileVersion.setAuthorIpAddress(ServletUtil
271: .getIpAddress(request));
272: WikiUser user = ServletUtil.currentUser();
273: Integer authorId = null;
274: if (user.getUserId() > 0) {
275: authorId = new Integer(user.getUserId());
276: }
277: wikiFileVersion.setAuthorId(authorId);
278: TopicVersion topicVersion = new TopicVersion(user, ServletUtil
279: .getIpAddress(request), contents, topic
280: .getTopicContent());
281: if (fileName == null) {
282: throw new WikiException(new WikiMessage(
283: "upload.error.filenotfound"));
284: }
285: WikiFile wikiFile = WikiBase.getDataHandler().lookupWikiFile(
286: virtualWiki, topicName);
287: if (wikiFile == null) {
288: wikiFile = new WikiFile();
289: wikiFile.setVirtualWiki(virtualWiki);
290: }
291: wikiFile.setFileName(fileName);
292: wikiFile.setUrl(url);
293: wikiFileVersion.setUrl(url);
294: wikiFileVersion.setMimeType(contentType);
295: wikiFile.setMimeType(contentType);
296: wikiFileVersion.setFileSize(fileSize);
297: wikiFile.setFileSize(fileSize);
298: ParserOutput parserOutput = ParserUtil.parserOutput(topic
299: .getTopicContent(), virtualWiki, topicName);
300: WikiBase.getDataHandler().writeTopic(topic, topicVersion,
301: parserOutput.getCategories(), parserOutput.getLinks(),
302: true, null);
303: wikiFile.setTopicId(topic.getTopicId());
304: WikiBase.getDataHandler().writeFile(wikiFile, wikiFileVersion,
305: null);
306: ServletUtil.redirect(next, virtualWiki, topicName);
307: }
308:
309: /**
310: *
311: */
312: private void view(HttpServletRequest request, ModelAndView next,
313: WikiPageInfo pageInfo) throws Exception {
314: pageInfo.setPageTitle(new WikiMessage("upload.title"));
315: pageInfo.setContentJsp(JSP_UPLOAD);
316: pageInfo.setSpecial(true);
317: }
318: }
|