/* * 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.repo.webdav; import java.io.IOException; import java.io.Writer; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import java.util.List; import java.util.StringTokenizer; import javax.servlet.http.HttpServletResponse; import org.alfresco.service.cmr.model.FileFolderService; import org.alfresco.service.cmr.model.FileInfo; import org.alfresco.service.cmr.model.FileNotFoundException; import org.alfresco.service.cmr.repository.ContentReader; import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.datatype.DefaultTypeConverter; import org.alfresco.service.cmr.repository.datatype.TypeConverter; /** * Implements the WebDAV GET method * * @author gavinc */ public class GetMethod extends WebDAVMethod { // Request parameters private ArrayList ifMatchTags = null; private ArrayList ifNoneMatchTags = null; private Date m_ifModifiedSince = null; private Date m_ifUnModifiedSince = null; protected boolean m_returnContent = true; /** * Default constructor */ public GetMethod() { } /** * Parse the request headers * * @exception WebDAVServerException */ protected void parseRequestHeaders() throws WebDAVServerException { // If the range header is present output a warning, add support later String strRange = m_request.getHeader(WebDAV.HEADER_RANGE); if (strRange != null && strRange.length() > 0) { logger.warn("Range header (" + strRange + ") not supported"); } // Capture all the If headers, process later String strIfMatch = m_request.getHeader(WebDAV.HEADER_IF_MATCH); if (strIfMatch != null && strIfMatch.length() > 0) { ifMatchTags = parseETags(strIfMatch); } String strIfNoneMatch = m_request.getHeader(WebDAV.HEADER_IF_NONE_MATCH); if (strIfNoneMatch != null && strIfNoneMatch.length() > 0) { ifNoneMatchTags = parseETags(strIfNoneMatch); } // Parse the dates SimpleDateFormat dateFormat = new SimpleDateFormat(WebDAV.HEADER_IF_DATE_FORMAT); String strIfModifiedSince = m_request.getHeader(WebDAV.HEADER_IF_MODIFIED_SINCE); if (strIfModifiedSince != null && strIfModifiedSince.length() > 0) { try { m_ifModifiedSince = dateFormat.parse(strIfModifiedSince); } catch (ParseException e) { logger.warn("Failed to parse If-Modified-Since date of " + strIfModifiedSince); } } String strIfUnModifiedSince = m_request.getHeader(WebDAV.HEADER_IF_UNMODIFIED_SINCE); if (strIfUnModifiedSince != null && strIfUnModifiedSince.length() > 0) { try { m_ifUnModifiedSince = dateFormat.parse(strIfUnModifiedSince); } catch (ParseException e) { logger.warn("Failed to parse If-Unmodified-Since date of " + strIfUnModifiedSince); } } } /** * Parse the request body * * @exception WebDAVServerException */ protected void parseRequestBody() throws WebDAVServerException { // Nothing to do in this method } /** * Exceute the WebDAV request * * @exception WebDAVServerException */ protected void executeImpl() throws WebDAVServerException, Exception { FileFolderService fileFolderService = getFileFolderService(); NodeRef rootNodeRef = getRootNodeRef(); String path = getPath(); String servletPath = getServletPath(); FileInfo nodeInfo = null; try { nodeInfo = getDAVHelper().getNodeForPath(rootNodeRef, path, servletPath); } catch (FileNotFoundException e) { throw new WebDAVServerException(HttpServletResponse.SC_NOT_FOUND); } // Check if the node is a folder if (nodeInfo.isFolder()) { // is content required if (!m_returnContent) { // it is a folder and no content is required throw new WebDAVServerException(HttpServletResponse.SC_BAD_REQUEST); } // Generate a folder listing generateDirectoryListing(nodeInfo); } else { NodeRef pathNodeRef = nodeInfo.getNodeRef(); // Return the node details, and content if requested, check that the node passes the pre-conditions checkPreConditions(nodeInfo); // Build the response header m_response.setHeader(WebDAV.HEADER_ETAG, getDAVHelper().makeQuotedETag(pathNodeRef)); Date modifiedDate = nodeInfo.getModifiedDate(); if (modifiedDate != null) { long modDate = DefaultTypeConverter.INSTANCE.longValue(modifiedDate); m_response.setHeader(WebDAV.HEADER_LAST_MODIFIED, WebDAV.formatHeaderDate(modDate)); } ContentReader reader = fileFolderService.getReader(nodeInfo.getNodeRef()); if (reader != null) { // there is content associated with the node m_response.setHeader(WebDAV.HEADER_CONTENT_LENGTH, "" + reader.getSize()); m_response.setHeader(WebDAV.HEADER_CONTENT_TYPE, reader.getMimetype()); if (m_returnContent) { // copy the content to the response output stream reader.getContent(m_response.getOutputStream()); } } } } /** * Checks the If header conditions * * @param nodeInfo the node to check * @throws WebDAVServerException if a pre-condition is not met */ private void checkPreConditions(FileInfo nodeInfo) throws WebDAVServerException { // Make an etag for the node String strETag = getDAVHelper().makeQuotedETag(nodeInfo.getNodeRef()); TypeConverter typeConv = DefaultTypeConverter.INSTANCE; // Check the If-Match header, don't send any content back if none of the tags in // the list match the etag, and the wildcard is not present if (ifMatchTags != null) { if (ifMatchTags.contains(WebDAV.ASTERISK) == false && ifMatchTags.contains(strETag) == false) { throw new WebDAVServerException(HttpServletResponse.SC_PRECONDITION_FAILED); } } // Check the If-None-Match header, don't send any content back if any of the tags // in the list match the etag, or the wildcard is present if (ifNoneMatchTags != null) { if (ifNoneMatchTags.contains(WebDAV.ASTERISK) || ifNoneMatchTags.contains(strETag)) { throw new WebDAVServerException(HttpServletResponse.SC_NOT_MODIFIED); } } // Check the modified since list, if the If-None-Match header was not specified if (m_ifModifiedSince != null && ifNoneMatchTags == null) { Date lastModifiedDate = nodeInfo.getModifiedDate(); long fileLastModified = lastModifiedDate != null ? typeConv.longValue(lastModifiedDate) : 0L; long modifiedSince = m_ifModifiedSince.getTime(); if (fileLastModified != 0L && fileLastModified <= modifiedSince) { throw new WebDAVServerException(HttpServletResponse.SC_NOT_MODIFIED); } } // Check the un-modified since list if (m_ifUnModifiedSince != null) { Date lastModifiedDate = nodeInfo.getModifiedDate(); long fileLastModified = lastModifiedDate != null ? typeConv.longValue(lastModifiedDate) : 0L; long unModifiedSince = m_ifUnModifiedSince.getTime(); if (fileLastModified >= unModifiedSince) { throw new WebDAVServerException(HttpServletResponse.SC_PRECONDITION_FAILED); } } } /** * Parses the given ETag header into a list of separate ETags * * @param strETagHeader The header to parse * @return A list of ETags */ private ArrayList parseETags(String strETagHeader) { ArrayList list = new ArrayList(); StringTokenizer tokenizer = new StringTokenizer(strETagHeader, WebDAV.HEADER_VALUE_SEPARATOR); while (tokenizer.hasMoreTokens()) { list.add(tokenizer.nextToken().trim()); } return list; } /** * Generates a HTML representation of the contents of the path represented by the given node * * @param fileInfo the file to use */ private void generateDirectoryListing(FileInfo fileInfo) { FileFolderService fileFolderService = getFileFolderService(); Writer writer = null; try { writer = m_response.getWriter(); // Get the list of child nodes for the parent node List childNodeInfos = fileFolderService.list(fileInfo.getNodeRef()); // Send back the start of the HTML writer.write("Alfresco Content Repository"); writer.write("\n"); writer.flush(); // Send back the table heading writer.write("\n"); writer.write("\n"); writer.write("\n"); writer.write("
Directory listing for "); writer.write(getPath()); writer.write("
"); writer.write("\n"); writer.write(""); writer.write(""); writer.write(""); writer.write(""); // Get the URL for the root path String rootURL = WebDAV.getURLForPath(m_request, getPath(), true); if (rootURL.endsWith(WebDAVHelper.PathSeperator) == false) rootURL = rootURL + WebDAVHelper.PathSeperator; // Start with a link to the parent folder so we can navigate back up, unless we are at the root level if (fileInfo.getNodeRef().equals(getRootNodeRef()) == false) { writer.write(""); writer.write("\n"); } // Send back what we have generated so far writer.flush(); int rowId = 0; for (FileInfo childNodeInfo : childNodeInfos) { // Output the details for the current node writer.write(""); writer.write("\n"); writer.flush(); } } catch (Throwable e) { logger.error(e); if (writer != null) { try { writer.write("
NameSizeModified
"); writer.write("[Up a level]"); writer.write("
"); writer.write(fname); writer.write(""); writer.write(""); if (fileInfo.isFolder()) { writer.write(formatSize("0")); } else { ContentReader reader = fileFolderService.getReader(childNodeInfo.getNodeRef()); long fsize = 0L; if ( reader != null) { fsize = reader.getSize(); } writer.write(formatSize("" + fsize)); } writer.write(""); Date modifiedDate = childNodeInfo.getModifiedDate(); if (modifiedDate != null) { writer.write(WebDAV.formatHeaderDate(DefaultTypeConverter.INSTANCE.longValue(modifiedDate))); } else { writer.write(""); } writer.write("
"); writer.write("An error occurred whilst generating the directory listing, "); writer.write("please contact the system administrator.
"); writer.flush(); } catch (IOException ioe) { } } } } /** * Formats the given size for display in a directory listing * * @param strSize The content size * @return The formatted size */ private String formatSize(String strSize) { String strFormattedSize = strSize; int length = strSize.length(); if (length < 4) { strFormattedSize = strSize + " bytes"; } else if (length >= 4 && length < 7) { String strLeft = strSize.substring(0, length - 3); String strRight = strSize.substring(length - 3, length - 2); StringBuffer buffer = new StringBuffer(strLeft); if (!strRight.equals("0")) { buffer.append("."); buffer.append(strRight); } buffer.append(" Kb"); strFormattedSize = buffer.toString(); } else { String strLeft = strSize.substring(0, length - 6); String strRight = strSize.substring(length - 6, length - 5); StringBuffer buffer = new StringBuffer(strLeft); if (!strRight.equals("0")) { buffer.append("."); buffer.append(strRight); } buffer.append(" Mb"); strFormattedSize = buffer.toString(); } return strFormattedSize; } }