diff --git a/source/java/org/alfresco/web/app/servlet/UploadContentServlet.java b/source/java/org/alfresco/web/app/servlet/UploadContentServlet.java new file mode 100644 index 0000000000..8ff7890c52 --- /dev/null +++ b/source/java/org/alfresco/web/app/servlet/UploadContentServlet.java @@ -0,0 +1,237 @@ +/* + * Copyright (C) 2005 Alfresco, Inc. + * + * Licensed under the Mozilla Public License version 1.1 + * with a permitted attribution clause. You may obtain a + * copy of the License at + * + * http://www.alfresco.org/legal/license.txt + * + * 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.alfresco.web.app.servlet; + +import java.io.IOException; +import java.util.StringTokenizer; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.alfresco.model.ContentModel; +import org.alfresco.service.ServiceRegistry; +import org.alfresco.service.cmr.repository.ContentService; +import org.alfresco.service.cmr.repository.ContentWriter; +import org.alfresco.service.cmr.repository.MimetypeService; +import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.cmr.repository.StoreRef; +import org.alfresco.service.cmr.security.AccessStatus; +import org.alfresco.service.cmr.security.PermissionService; +import org.alfresco.service.namespace.QName; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +/** + * Servlet responsible for streaming content directly into the repository from the PUT request. + * The appropriate mimetype is calculated based on filename extension. + *

+ * The URL to the servlet should be generated thus: + *

/alfresco/upload/workspace/SpacesStore/0000-0000-0000-0000/myfile.pdf
+ * or + *
/alfresco/upload/myfile.pdf
+ *

+ * If the store and node id are specified in the URL then the content provided will be streamed onto the node + * using an updating writer, updating the content property value accordingly. + *

+ * If only the file name is specified the content will be streamed into the content store and the content data + * will be returned in the reposonse. This can then be used to update the value of a content property manually. + * Any used content will be cleared up in the usual manner. + *

+ * By default, the download assumes that the content is on the + * {@link org.alfresco.model.ContentModel#PROP_CONTENT content property}.
+ * To set the content of a specific model property, use a 'property' arg, providing the qualified name of the property. + *

+ * Like most Alfresco servlets, the URL may be followed by a valid 'ticket' argument for authentication: + * ?ticket=1234567890 + *

+ * Guest access is currently disabled for this servlet. + * + * @author Roy Wetherall + */ +public class UploadContentServlet extends BaseServlet +{ + /** Serial version UID */ + private static final long serialVersionUID = 1055960980867420355L; + + /** Logger */ + private static Log logger = LogFactory.getLog(UploadContentServlet.class); + + /** Default mime type */ + protected static final String MIMETYPE_OCTET_STREAM = "application/octet-stream"; + + /** Argument properties */ + protected static final String ARG_PROPERTY = "property"; + protected static final String ARG_MIMETYPE = "mimetype"; + protected static final String ARG_ENCODING = "encoding"; + + /** + * @see javax.servlet.http.HttpServlet#doPut(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse) + */ + protected void doPut(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException + { + if (logger.isDebugEnabled() == true) + { + String queryString = req.getQueryString(); + logger.debug("Authenticating request to URL: " + req.getRequestURI() + + ((queryString != null && queryString.length() > 0) ? ("?" + queryString) : "")); + } + + AuthenticationStatus status = servletAuthenticate(req, res, false); + if (status == AuthenticationStatus.Failure || status == AuthenticationStatus.Guest) + { + res.sendError(HttpServletResponse.SC_UNAUTHORIZED); + return; + } + + // Tokenise the URI + String uri = req.getRequestURI(); + uri = uri.substring(req.getContextPath().length()); + StringTokenizer t = new StringTokenizer(uri, "/"); + int tokenCount = t.countTokens(); + + t.nextToken(); // skip servlet name + + // get or calculate the noderef and filename to download as + NodeRef nodeRef = null; + String filename = null; + QName propertyQName = null; + + if (tokenCount == 2) + { + // filename is the only token + filename = t.nextToken(); + } + else if (tokenCount == 4 || tokenCount == 5) + { + // assume 'workspace' or other NodeRef based protocol for remaining URL + // elements + StoreRef storeRef = new StoreRef(t.nextToken(), t.nextToken()); + String id = t.nextToken(); + // build noderef from the appropriate URL elements + nodeRef = new NodeRef(storeRef, id); + + if (tokenCount == 5) + { + // filename is last remaining token + filename = t.nextToken(); + } + + // get qualified of the property to get content from - default to + // ContentModel.PROP_CONTENT + propertyQName = ContentModel.PROP_CONTENT; + String property = req.getParameter(ARG_PROPERTY); + if (property != null && property.length() != 0) + { + propertyQName = QName.createQName(property); + } + } + else + { + logger.debug("Upload URL did not contain all required args: " + uri); + res.sendError(HttpServletResponse.SC_EXPECTATION_FAILED); + return; + } + + // Get the encoding + String encoding = req.getParameter(ARG_ENCODING); + if (encoding == null || encoding.length() == 0) + { + encoding = "UTF-8"; + } + + // get the services we need to retrieve the content + ServiceRegistry serviceRegistry = getServiceRegistry(getServletContext()); + ContentService contentService = serviceRegistry.getContentService(); + PermissionService permissionService = serviceRegistry.getPermissionService(); + + // Sort out the mimetype + String mimetype = req.getParameter(ARG_MIMETYPE); + if (mimetype == null || mimetype.length() == 0) + { + mimetype = MIMETYPE_OCTET_STREAM; + if (filename != null) + { + MimetypeService mimetypeMap = serviceRegistry.getMimetypeService(); + int extIndex = filename.lastIndexOf('.'); + if (extIndex != -1) + { + String ext = filename.substring(extIndex + 1); + String mt = mimetypeMap.getMimetypesByExtension().get(ext); + if (mt != null) + { + mimetype = mt; + } + } + } + } + + if (logger.isDebugEnabled()) + { + if (nodeRef != null) {logger.debug("Found NodeRef: " + nodeRef.toString());} + logger.debug("For property: " + propertyQName); + logger.debug("File name: " + filename); + logger.debug("Mimetype: " + mimetype); + logger.debug("Encoding: " + encoding); + } + + // Check that the user has the permissions to write the content + if (permissionService.hasPermission(nodeRef, PermissionService.WRITE_CONTENT) == AccessStatus.DENIED) + { + if (logger.isDebugEnabled() == true) + { + logger.debug("User does not have permissions to wrtie content for NodeRef: " + nodeRef.toString()); + } + + if (logger.isDebugEnabled()) + { + logger.debug("Returning 403 Forbidden error..."); + } + + res.sendError(HttpServletResponse.SC_FORBIDDEN); + return; + } + + // Try and get the content writer + ContentWriter writer = contentService.getWriter(nodeRef, propertyQName, true); + if (writer == null) + { + if (logger.isDebugEnabled() == true) + { + logger.debug("Content writer cannot be obtained for NodeRef: " + nodeRef.toString()); + } + res.sendError(HttpServletResponse.SC_EXPECTATION_FAILED); + return; + } + + // Set the mimetype and encoding + writer.setMimetype(mimetype); + writer.setEncoding(encoding); + + // Stream the content into the repository + writer.putContent(req.getInputStream()); + + if (logger.isDebugEnabled() == true) + { + logger.debug("Content details: " + writer.getContentData().toString()); + } + + // Set return status + res.getWriter().write(writer.getContentData().toString()); + res.flushBuffer(); + } +} diff --git a/source/java/org/alfresco/web/app/servlet/UploadFileServlet.java b/source/java/org/alfresco/web/app/servlet/UploadFileServlet.java index 96e8beb5f4..51cc5487ac 100644 --- a/source/java/org/alfresco/web/app/servlet/UploadFileServlet.java +++ b/source/java/org/alfresco/web/app/servlet/UploadFileServlet.java @@ -106,8 +106,10 @@ public class UploadFileServlet extends BaseServlet String filename = item.getName(); if (filename != null && filename.length() != 0) { - if (logger.isDebugEnabled()) + if (logger.isDebugEnabled() == true) + { logger.debug("Processing uploaded file: " + filename); + } // workaround a bug in IE where the full path is returned // IE is only available for Windows so only check for the Windows path separator @@ -130,9 +132,11 @@ public class UploadFileServlet extends BaseServlet bean.setFileName(filename); bean.setFilePath(tempFile.getAbsolutePath()); session.setAttribute(FileUploadBean.getKey(uploadId), bean); - if (logger.isDebugEnabled()) + if (logger.isDebugEnabled() == true) + { logger.debug("Temp file: " + tempFile.getAbsolutePath() + " created from upload filename: " + filename); + } } } } @@ -143,8 +147,10 @@ public class UploadFileServlet extends BaseServlet } // finally redirect - if (logger.isDebugEnabled()) + if (logger.isDebugEnabled() == true) + { logger.debug("Upload servicing complete, redirecting to: " + returnPage); + } response.sendRedirect(returnPage); } diff --git a/source/web/WEB-INF/web.xml b/source/web/WEB-INF/web.xml index 4c66617c19..cb908365ba 100644 --- a/source/web/WEB-INF/web.xml +++ b/source/web/WEB-INF/web.xml @@ -175,6 +175,11 @@ org.alfresco.web.app.servlet.DownloadContentServlet + + uploadContent + org.alfresco.web.app.servlet.UploadContentServlet + + guestDownloadContent org.alfresco.web.app.servlet.GuestDownloadContentServlet @@ -245,6 +250,11 @@ /download/* + + uploadContent + /upload/* + + guestDownloadContent /guestDownload/*