Fix for Issue 35 that doesn't allow renaming of a file name when the new file name...
[pithos] / src / gr / ebs / gss / server / rest / FilesHandler.java
index 8e841c9..bf74bb6 100644 (file)
  */
 package gr.ebs.gss.server.rest;
 
+import static gr.ebs.gss.server.configuration.GSSConfigurationFactory.getConfiguration;
 import gr.ebs.gss.client.exceptions.DuplicateNameException;
 import gr.ebs.gss.client.exceptions.GSSIOException;
 import gr.ebs.gss.client.exceptions.InsufficientPermissionsException;
 import gr.ebs.gss.client.exceptions.ObjectNotFoundException;
 import gr.ebs.gss.client.exceptions.QuotaExceededException;
 import gr.ebs.gss.client.exceptions.RpcException;
+import gr.ebs.gss.server.Login;
 import gr.ebs.gss.server.domain.FileUploadStatus;
 import gr.ebs.gss.server.domain.User;
 import gr.ebs.gss.server.domain.dto.FileBodyDTO;
@@ -34,6 +36,7 @@ import gr.ebs.gss.server.domain.dto.PermissionDTO;
 import gr.ebs.gss.server.ejb.ExternalAPI;
 import gr.ebs.gss.server.ejb.TransactionHelper;
 import gr.ebs.gss.server.webdav.Range;
+import gr.ebs.gss.server.webdav.RequestUtil;
 
 import java.io.BufferedReader;
 import java.io.ByteArrayInputStream;
@@ -52,9 +55,11 @@ import java.net.URISyntaxException;
 import java.net.URLDecoder;
 import java.net.URLEncoder;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collection;
 import java.util.Date;
 import java.util.HashSet;
+import java.util.Iterator;
 import java.util.List;
 import java.util.Set;
 import java.util.StringTokenizer;
@@ -63,9 +68,11 @@ import java.util.concurrent.Callable;
 import javax.servlet.ServletContext;
 import javax.servlet.ServletException;
 import javax.servlet.ServletOutputStream;
+import javax.servlet.http.Cookie;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
+import org.apache.commons.codec.binary.Base64;
 import org.apache.commons.fileupload.FileItemIterator;
 import org.apache.commons.fileupload.FileItemStream;
 import org.apache.commons.fileupload.FileUploadException;
@@ -131,6 +138,12 @@ public class FilesHandler extends RequestHandler {
        private ServletContext context;
 
        /**
+        * The style sheet for displaying the directory listings.
+        */
+       private static final String GSS_CSS = "H1 {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;font-size:22px;} " + "H2 {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;font-size:16px;} " + "H3 {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;font-size:14px;} " + "BODY {font-family:Tahoma,Arial,sans-serif;color:black;background-color:white;} " + "B {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;} " + "P {font-family:Tahoma,Arial,sans-serif;background:white;color:black;font-size:12px;}" + "A {color : black;}" + "A.name {color : black;}" + "HR {color : #525D76;}";
+
+
+       /**
         * @param servletContext
         */
        public FilesHandler(ServletContext servletContext) {
@@ -172,6 +185,10 @@ public class FilesHandler extends RequestHandler {
                throws IOException, ServletException {
                boolean authDeferred = getAuthDeferred(req);
         String path = getInnerPath(req, PATH_FILES);
+//        if (!isValidResourceName(name)) {
+//             resp.sendError(HttpServletResponse.SC_BAD_REQUEST);
+//             return;
+//     }
                if (path.equals(""))
                        path = "/";
                try {
@@ -190,7 +207,6 @@ public class FilesHandler extends RequestHandler {
 
        User user = getUser(req);
        User owner = getOwner(req);
-       if (user == null) user = owner;
         boolean exists = true;
         Object resource = null;
         FileHeaderDTO file = null;
@@ -204,27 +220,17 @@ public class FilesHandler extends RequestHandler {
                        return;
                }
 
-       if (!exists) {
-                       if (authDeferred) {
-                               // We do not want to leak information if the request
-                               // was not authenticated.
-                               resp.sendError(HttpServletResponse.SC_FORBIDDEN);
-                               return;
-                       }
-               // A request for upload progress.
-               if (progress != null && content) {
-                       serveProgress(req, resp, progress, user, null);
-                               return;
-               }
-
-               resp.sendError(HttpServletResponse.SC_NOT_FOUND, req.getRequestURI());
+       if (!exists && authDeferred) {
+               // We do not want to leak information if the request
+               // was not authenticated.
+               resp.sendError(HttpServletResponse.SC_FORBIDDEN);
                return;
        }
 
        if (resource instanceof FolderDTO)
                folder = (FolderDTO) resource;
        else
-               file = (FileHeaderDTO) resource;
+               file = (FileHeaderDTO) resource;        // Note that file will be null, if (!exists).
 
        // Now it's time to perform the deferred authentication check.
                // Since regular signature checking was already performed,
@@ -235,58 +241,109 @@ public class FilesHandler extends RequestHandler {
                                String auth = req.getParameter(AUTHORIZATION_PARAMETER);
                                String dateParam = req.getParameter(DATE_PARAMETER);
                                if (auth == null || dateParam == null) {
-                                       resp.sendError(HttpServletResponse.SC_FORBIDDEN);
-                                       return;
-                               }
+                                       // Check for a valid authentication cookie.
+                                       if (req.getCookies() != null) {
+                                               boolean found = false;
+                                               for (Cookie cookie : req.getCookies())
+                                                       if (Login.AUTH_COOKIE.equals(cookie.getName())) {
+                                                               String cookieauth = cookie.getValue();
+                                                               int sepIndex = cookieauth.indexOf(Login.COOKIE_SEPARATOR);
+                                                               if (sepIndex == -1) {
+                                                                       handleAuthFailure(req, resp);
+                                                                       return;
+                                                               }
+                                                               String username = URLDecoder.decode(cookieauth.substring(0, sepIndex), "US-ASCII");
+                                                               user = null;
+                                                               try {
+                                                                       user = getService().findUser(username);
+                                                               } catch (RpcException e) {
+                                                               resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, path);
+                                                                       return;
+                                                               }
+                                                               if (user == null) {
+                                                               resp.sendError(HttpServletResponse.SC_FORBIDDEN);
+                                                               return;
+                                                       }
+                                                               req.setAttribute(USER_ATTRIBUTE, user);
+                                                               String token = cookieauth.substring(sepIndex + 1);
+                                                               if (user.getAuthToken() == null) {
+                                                                       resp.sendError(HttpServletResponse.SC_FORBIDDEN);
+                                                                       return;
+                                                               }
+                                                               if (!Arrays.equals(user.getAuthToken(), Base64.decodeBase64(token))) {
+                                                                       resp.sendError(HttpServletResponse.SC_FORBIDDEN);
+                                                                       return;
+                                                               }
+                                                               found = true;
+                                                               break;
+                                                       }
+                                               if (!found) {
+                                                       handleAuthFailure(req, resp);
+                                                       return;
+                                               }
+                                       } else {
+                                               handleAuthFailure(req, resp);
+                                               return;
+                                       }
+                               } else {
+                               long timestamp;
+                                       try {
+                                               timestamp = DateUtil.parseDate(dateParam).getTime();
+                                       } catch (DateParseException e) {
+                                       resp.sendError(HttpServletResponse.SC_FORBIDDEN, e.getMessage());
+                                       return;
+                                       }
+                               if (!isTimeValid(timestamp)) {
+                                       resp.sendError(HttpServletResponse.SC_FORBIDDEN);
+                                       return;
+                               }
 
-                       long timestamp;
-                               try {
-                                       timestamp = DateUtil.parseDate(dateParam).getTime();
-                               } catch (DateParseException e) {
-                               resp.sendError(HttpServletResponse.SC_FORBIDDEN, e.getMessage());
-                               return;
-                               }
-                       if (!isTimeValid(timestamp)) {
-                               resp.sendError(HttpServletResponse.SC_FORBIDDEN);
-                               return;
-                       }
-
-                               // Fetch the Authorization parameter and find the user specified in it.
-                               String[] authParts = auth.split(" ");
-                               if (authParts.length != 2) {
-                               resp.sendError(HttpServletResponse.SC_FORBIDDEN);
-                               return;
-                       }
-                               String username = authParts[0];
-                               String signature = authParts[1];
-                               user = null;
-                               try {
-                                       user = getService().findUser(username);
-                               } catch (RpcException e) {
-                               resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, path);
-                                       return;
+                                       // Fetch the Authorization parameter and find the user specified in it.
+                                       String[] authParts = auth.split(" ");
+                                       if (authParts.length != 2) {
+                                       resp.sendError(HttpServletResponse.SC_FORBIDDEN);
+                                       return;
+                               }
+                                       String username = authParts[0];
+                                       String signature = authParts[1];
+                                       user = null;
+                                       try {
+                                               user = getService().findUser(username);
+                                       } catch (RpcException e) {
+                                       resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, path);
+                                               return;
+                                       }
+                                       if (user == null) {
+                                       resp.sendError(HttpServletResponse.SC_FORBIDDEN);
+                                       return;
+                               }
+                                       req.setAttribute(USER_ATTRIBUTE, user);
+
+                                       // Remove the servlet path from the request URI.
+                                       String p = req.getRequestURI();
+                                       String servletPath = req.getContextPath() + req.getServletPath();
+                                       p = p.substring(servletPath.length());
+                                       // Validate the signature in the Authorization parameter.
+                                       String data = req.getMethod() + dateParam + p;
+                                       if (!isSignatureValid(signature, user, data)) {
+                                       resp.sendError(HttpServletResponse.SC_FORBIDDEN);
+                                       return;
+                               }
                                }
-                               if (user == null) {
-                               resp.sendError(HttpServletResponse.SC_FORBIDDEN);
-                               return;
-                       }
-                               req.setAttribute(USER_ATTRIBUTE, user);
-
-                               // Remove the servlet path from the request URI.
-                               String p = req.getRequestURI();
-                               String servletPath = req.getContextPath() + req.getServletPath();
-                               p = p.substring(servletPath.length());
-                               // Validate the signature in the Authorization parameter.
-                               String data = req.getMethod() + dateParam + p;
-                               if (!isSignatureValid(signature, user, data)) {
-                               resp.sendError(HttpServletResponse.SC_FORBIDDEN);
-                               return;
-                       }
-                       } else if (file != null && !file.isReadForAll() || file == null) {
-                               // Check for a read-for-all file request.
-                               resp.sendError(HttpServletResponse.SC_FORBIDDEN);
-                               return;
                        }
+               else if(folder != null && folder.isReadForAll() || file != null && file.isReadForAll()){
+                       //This case refers to a folder or file with public privileges
+                       //For a read-for-all folder request, pretend the owner is making it.
+                       user = owner;
+                       req.setAttribute(USER_ATTRIBUTE, user);
+               }else if(folder != null && !folder.isReadForAll()){
+                       resp.sendError(HttpServletResponse.SC_FORBIDDEN);
+                       return;
+               }
+               else{
+                       resp.sendError(HttpServletResponse.SC_FORBIDDEN);
+                       return;
+               }
 
        // If the resource is not a collection, and the resource path
        // ends with "/" or "\", return NOT FOUND.
@@ -303,8 +360,8 @@ public class FilesHandler extends RequestHandler {
        // A request for upload progress.
        if (progress != null && content) {
                if (file == null) {
-                       resp.sendError(HttpServletResponse.SC_BAD_REQUEST);
-                       return;
+                       resp.sendError(HttpServletResponse.SC_NOT_FOUND, req.getRequestURI());
+                       return;
                }
                serveProgress(req, resp, progress, user, file);
                        return;
@@ -349,14 +406,33 @@ public class FilesHandler extends RequestHandler {
 
        // Find content type.
        String contentType = null;
+       boolean isContentHtml = false;
+       boolean expectJSON = false;
+
        if (file != null) {
                contentType = version>0 ? oldBody.getMimeType() : file.getMimeType();
                if (contentType == null) {
                        contentType = context.getMimeType(file.getName());
                        file.setMimeType(contentType);
                }
-       } else
-                       contentType = "application/json;charset=UTF-8";
+       } else { // folder != null
+               String accept = req.getHeader("Accept");
+               // The order in this conditional pessimizes the common API case,
+               // but is important for backwards compatibility with existing
+               // clients who send no accept header and expect a JSON response.
+               if (accept != null && accept.contains("text/html")) {
+                       contentType = "text/html;charset=UTF-8";
+                       isContentHtml = true;
+                       //this is the case when clients send the appropriate headers, the contentType is "text/html"
+                       //and expect a JSON response. The above check applies to FireGSS client
+                       expectJSON = !authDeferred ? true : false;
+               }
+               else {
+                       contentType = "application/json;charset=UTF-8";
+                       expectJSON = true;
+               }
+               }
+
 
        ArrayList ranges = null;
        long contentLength = -1L;
@@ -409,11 +485,7 @@ public class FilesHandler extends RequestHandler {
                                else
                                        throw e;
                }
-
-       if (folder != null
-                               || (ranges == null || ranges.isEmpty())
-                                                       && req.getHeader("Range") == null
-                                                       || ranges == FULL) {
+       if (folder != null || (ranges == null || ranges.isEmpty()) && req.getHeader("Range") == null || ranges == FULL) {
                // Set the appropriate output headers
                if (contentType != null) {
                        if (logger.isDebugEnabled())
@@ -425,21 +497,31 @@ public class FilesHandler extends RequestHandler {
                                logger.debug("contentLength=" + contentLength);
                        if (contentLength < Integer.MAX_VALUE)
                                        resp.setContentLength((int) contentLength);
+
                                else
                                        // Set the content-length as String to be able to use a long
                                resp.setHeader("content-length", "" + contentLength);
                }
 
                InputStream renderResult = null;
-               if (folder != null)
-                               if (content)
-                                       // Serve the directory browser
+               String relativePath = getRelativePath(req);
+               String contextPath = req.getContextPath();
+               String servletPath = req.getServletPath();
+               String contextServletPath = contextPath + servletPath;
+               if (folder != null && content)
+                       // Serve the directory browser for a public folder
+                       if (isContentHtml && !expectJSON)
+                               renderResult = renderHtml(contextServletPath, relativePath, folder,user);
+                       // Serve the directory for an ordinary folder or for fireGSS client
+                       else
                                try {
-                                               renderResult = renderJson(user, folder);
-                                       } catch (InsufficientPermissionsException e) {
-                                               resp.setStatus(HttpServletResponse.SC_METHOD_NOT_ALLOWED);
-                                       return;
-                                       }
+                                       renderResult = renderJson(user, folder);
+                                       } catch (InsufficientPermissionsException e) {
+                                               resp.setStatus(HttpServletResponse.SC_METHOD_NOT_ALLOWED);
+                                               return;
+                                       }
+
+
                // Copy the input stream to our output stream (if requested)
                if (content) {
                        try {
@@ -547,6 +629,25 @@ public class FilesHandler extends RequestHandler {
     }
 
        /**
+        * Handles an authentication failure. If no Authorization or Date request
+        * parameters and no Authorization, Date or X-GSS-Date headers were present,
+        * this is a browser request, so redirect to login and then let the user get
+        * back to the file. Otherwise it's a bogus client request and Forbidden is
+        * returned.
+        */
+       private void handleAuthFailure(HttpServletRequest req, HttpServletResponse resp) throws IOException {
+               if (req.getParameter(AUTHORIZATION_PARAMETER) == null &&
+                               req.getParameter(DATE_PARAMETER) == null &&
+                               req.getHeader(AUTHORIZATION_HEADER) == null &&
+                               req.getDateHeader(DATE_HEADER) == -1 &&
+                               req.getDateHeader(GSS_DATE_HEADER) == -1)
+                       resp.sendRedirect(getConfiguration().getString("loginUrl") +
+                                       "?next=" + req.getRequestURL().toString());
+               else
+                       resp.sendError(HttpServletResponse.SC_FORBIDDEN);
+       }
+
+       /**
         * Return the filename of the specified file properly formatted for
         * including in the Content-Disposition header.
         */
@@ -640,6 +741,7 @@ public class FilesHandler extends RequestHandler {
                }
 
        String newName = req.getParameter(NEW_FOLDER_PARAMETER);
+
        boolean hasUpdateParam = req.getParameterMap().containsKey(RESOURCE_UPDATE_PARAMETER);
        boolean hasTrashParam = req.getParameterMap().containsKey(RESOURCE_TRASH_PARAMETER);
        boolean hasRestoreParam = req.getParameterMap().containsKey(RESOURCE_RESTORE_PARAMETER);
@@ -647,8 +749,13 @@ public class FilesHandler extends RequestHandler {
        String moveTo = req.getParameter(RESOURCE_MOVE_PARAMETER);
        String restoreVersion = req.getParameter(RESTORE_VERSION_PARAMETER);
 
-       if (newName != null)
+       if (newName != null){
+               if (!isValidResourceName(newName)) {
+                       resp.sendError(HttpServletResponse.SC_BAD_REQUEST);
+                       return;
+               }
                        createFolder(req, resp, path, newName);
+       }
        else if (hasUpdateParam)
                        updateResource(req, resp, path);
                else if (hasTrashParam)
@@ -1294,6 +1401,7 @@ public class FilesHandler extends RequestHandler {
                final User user = getUser(req);
                User owner = getOwner(req);
                Object resource = null;
+
                try {
                        resource = getService().getResourceAtPath(owner.getId(), path, false);
                } catch (ObjectNotFoundException e) {
@@ -1303,14 +1411,18 @@ public class FilesHandler extends RequestHandler {
                        resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, path);
                        return;
                }
-               //use utf-8 encoding for reading request
-               BufferedReader reader = new BufferedReader(new InputStreamReader(req.getInputStream(),"UTF-8"));
                StringBuffer input = new StringBuffer();
-               String line = null;
                JSONObject json = null;
-               while ((line = reader.readLine()) != null)
-                       input.append(line);
-               reader.close();
+               if (req.getContentType() != null && req.getContentType().startsWith("application/x-www-form-urlencoded"))
+                       input.append(req.getParameter(RESOURCE_UPDATE_PARAMETER));
+               else {
+                       // Assume application/json
+                       BufferedReader reader = new BufferedReader(new InputStreamReader(req.getInputStream(),"UTF-8"));
+                       String line = null;
+                       while ((line = reader.readLine()) != null)
+                               input.append(line);
+                       reader.close();
+               }
                try {
                        json = new JSONObject(input.toString());
                        if (logger.isDebugEnabled())
@@ -1318,24 +1430,25 @@ public class FilesHandler extends RequestHandler {
                        if (resource instanceof FolderDTO) {
                                final FolderDTO folder = (FolderDTO) resource;
                                String name = json.optString("name");
-                               if (!name.isEmpty())
-                                       try {
-                                               name = URLDecoder.decode(name, "UTF-8");
-                                       } catch (IllegalArgumentException e) {
-                                               resp.sendError(HttpServletResponse.SC_BAD_REQUEST, e.getMessage());
-                                               return;
-                                       }
+                               if (!isValidResourceName(name)) {
+                               resp.sendError(HttpServletResponse.SC_BAD_REQUEST);
+                               return;
+                       }
                                JSONArray permissions = json.optJSONArray("permissions");
                                Set<PermissionDTO> perms = null;
                                if (permissions != null)
                                        perms = parsePermissions(user, permissions);
-                               if (!name.isEmpty() || permissions != null) {
+                               Boolean readForAll = null;
+                               if (json.opt("readForAll") != null)
+                                       readForAll = json.optBoolean("readForAll");
+                               if (!name.isEmpty() || permissions != null || readForAll != null) {
                                        final String fName = name.isEmpty()? null: name;
+                                       final Boolean freadForAll =  readForAll;
                                        final Set<PermissionDTO> fPerms = perms;
                                        FolderDTO folderUpdated = new TransactionHelper<FolderDTO>().tryExecute(new Callable<FolderDTO>() {
                                                @Override
                                                public FolderDTO call() throws Exception {
-                                                       return getService().updateFolder(user.getId(), folder.getId(), fName, fPerms);
+                                                       return getService().updateFolder(user.getId(), folder.getId(), fName, freadForAll, fPerms);
                                                }
 
                                        });
@@ -1346,6 +1459,10 @@ public class FilesHandler extends RequestHandler {
                                String name = null;
                                if (json.opt("name") != null)
                                        name = json.optString("name");
+                               if (!isValidResourceName(name)) {
+                               resp.sendError(HttpServletResponse.SC_BAD_REQUEST);
+                               return;
+                       }
                                Long modificationDate = null;
                                if (json.optLong("modificationDate") != 0)
                                        modificationDate = json.optLong("modificationDate");
@@ -1408,8 +1525,8 @@ public class FilesHandler extends RequestHandler {
         * Returns the new URL of an updated folder.
         */
        private String getNewUrl(HttpServletRequest req, FolderDTO folder) throws UnsupportedEncodingException {
-               String parentUrl =URLDecoder.decode(getContextPath(req, true),"UTF-8");
-               String fpath = URLDecoder.decode(req.getPathInfo(), "UTF-8");
+               String parentUrl = URLDecoder.decode(getContextPath(req, true),"UTF-8");
+               String fpath = URLDecoder.decode(getRelativePath(req), "UTF-8");
                if (parentUrl.indexOf(fpath) != -1)
                        parentUrl = parentUrl.substring(0, parentUrl.indexOf(fpath));
                if(!parentUrl.endsWith("/"))
@@ -1800,7 +1917,9 @@ public class FilesHandler extends RequestHandler {
                                        put("owner", folder.getOwner().getUsername()).
                                        put("createdBy", folder.getAuditInfo().getCreatedBy().getUsername()).
                                        put("creationDate", folder.getAuditInfo().getCreationDate().getTime()).
-                                       put("deleted", folder.isDeleted());
+                                       put("deleted", folder.isDeleted()).
+                                       put("readForAll", folder.isReadForAll());
+
                        if (folder.getAuditInfo().getModifiedBy() != null)
                                json.put("modifiedBy", folder.getAuditInfo().getModifiedBy().getUsername()).
                                                put("modificationDate", folder.getAuditInfo().getModificationDate().getTime());
@@ -2045,6 +2164,7 @@ public class FilesHandler extends RequestHandler {
                        filename = aFilename;
                }
 
+               @Override
                public void update(long bytesRead, long contentLength, int items) {
                        //monitoring per percent of bytes uploaded
                        bytesTransferred = bytesRead;
@@ -2065,4 +2185,172 @@ public class FilesHandler extends RequestHandler {
                                }
                }
        }
+
+       /**
+        * Return an InputStream to an HTML representation of the contents of this
+        * directory.
+        *
+        * @param contextPath Context path to which our internal paths are relative
+        * @param path the requested path to the resource
+        * @param folder the specified directory
+        * @param user the specified user
+        * @return an input stream with the rendered contents
+        * @throws IOException
+        * @throws ServletException
+        */
+       private InputStream renderHtml(String contextPath, String path, FolderDTO folder, User user)
+               throws IOException, ServletException {
+               String name = folder.getName();
+               // Prepare a writer to a buffered area
+               ByteArrayOutputStream stream = new ByteArrayOutputStream();
+               OutputStreamWriter osWriter = new OutputStreamWriter(stream, "UTF8");
+               PrintWriter writer = new PrintWriter(osWriter);
+               StringBuffer sb = new StringBuffer();
+               // rewriteUrl(contextPath) is expensive. cache result for later reuse
+               String rewrittenContextPath = rewriteUrl(contextPath);
+               // Render the page header
+               sb.append("<html>\r\n");
+               sb.append("<head>\r\n");
+               sb.append("<title>");
+               sb.append("Index of " + name);
+               sb.append("</title>\r\n");
+               sb.append("<STYLE><!--");
+               sb.append(GSS_CSS);
+               sb.append("--></STYLE> ");
+               sb.append("</head>\r\n");
+               sb.append("<body>");
+               sb.append("<h1>");
+               sb.append("Index of " + name);
+
+               // Render the link to our parent (if required)
+               String parentDirectory = path;
+               if (parentDirectory.endsWith("/"))
+                       parentDirectory = parentDirectory.substring(0, parentDirectory.length() - 1);
+               int slash = parentDirectory.lastIndexOf('/');
+               if (slash >= 0) {
+                       String parent = path.substring(0, slash);
+                       sb.append(" - <a href=\"");
+                       sb.append(rewrittenContextPath);
+                       if (parent.equals(""))
+                               parent = "/";
+                       sb.append(parent);
+                       if (!parent.endsWith("/"))
+                               sb.append("/");
+                       sb.append("\">");
+                       sb.append("<b>");
+                       sb.append("Up To " + parent);
+                       sb.append("</b>");
+                       sb.append("</a>");
+               }
+
+               sb.append("</h1>");
+               sb.append("<HR size=\"1\" noshade=\"noshade\">");
+
+               sb.append("<table width=\"100%\" cellspacing=\"0\"" + " cellpadding=\"5\" align=\"center\">\r\n");
+
+               // Render the column headings
+               sb.append("<tr>\r\n");
+               sb.append("<td align=\"left\"><font size=\"+1\"><strong>");
+               sb.append("Name");
+               sb.append("</strong></font></td>\r\n");
+               sb.append("<td align=\"center\"><font size=\"+1\"><strong>");
+               sb.append("Size");
+               sb.append("</strong></font></td>\r\n");
+               sb.append("<td align=\"right\"><font size=\"+1\"><strong>");
+               sb.append("Last modified");
+               sb.append("</strong></font></td>\r\n");
+               sb.append("</tr>");
+               // Render the directory entries within this directory
+               boolean shade = false;
+               Iterator iter = folder.getSubfolders().iterator();
+               while (iter.hasNext()) {
+                       FolderDTO subf = (FolderDTO) iter.next();
+                       if(subf.isReadForAll() && !subf.isDeleted()){
+                               String resourceName = subf.getName();
+                               if (resourceName.equalsIgnoreCase("WEB-INF") || resourceName.equalsIgnoreCase("META-INF"))
+                                       continue;
+
+                               sb.append("<tr");
+                               if (shade)
+                                       sb.append(" bgcolor=\"#eeeeee\"");
+                               sb.append(">\r\n");
+                               shade = !shade;
+
+                               sb.append("<td align=\"left\">&nbsp;&nbsp;\r\n");
+                               sb.append("<a href=\"");
+                               sb.append(rewrittenContextPath+path);
+                               sb.append(rewriteUrl(resourceName));
+                               sb.append("/");
+                               sb.append("\"><tt>");
+                               sb.append(RequestUtil.filter(resourceName));
+                               sb.append("/");
+                               sb.append("</tt></a></td>\r\n");
+
+                               sb.append("<td align=\"right\"><tt>");
+                               sb.append("&nbsp;");
+                               sb.append("</tt></td>\r\n");
+
+                               sb.append("<td align=\"right\"><tt>");
+                               sb.append(getLastModifiedHttp(folder.getAuditInfo()));
+                               sb.append("</tt></td>\r\n");
+
+                               sb.append("</tr>\r\n");
+
+                       }
+               }
+               List<FileHeaderDTO> files;
+               try {
+                       files = getService().getFiles(user.getId(), folder.getId(), true);
+               } catch (ObjectNotFoundException e) {
+                       throw new ServletException(e.getMessage());
+               } catch (InsufficientPermissionsException e) {
+                       throw new ServletException(e.getMessage());
+               } catch (RpcException e) {
+                       throw new ServletException(e.getMessage());
+               }
+               for (FileHeaderDTO file : files)
+               //Display only file resources that are marked as public and are not deleted
+                       if(file.isReadForAll() && !file.isDeleted()){
+                               String resourceName = file.getName();
+                               if (resourceName.equalsIgnoreCase("WEB-INF") || resourceName.equalsIgnoreCase("META-INF"))
+                                       continue;
+
+                               sb.append("<tr");
+                               if (shade)
+                                       sb.append(" bgcolor=\"#eeeeee\"");
+                               sb.append(">\r\n");
+                               shade = !shade;
+
+                               sb.append("<td align=\"left\">&nbsp;&nbsp;\r\n");
+                               sb.append("<a href=\"");
+                               sb.append(rewrittenContextPath + path);
+                               sb.append(rewriteUrl(resourceName));
+                               sb.append("\"><tt>");
+                               sb.append(RequestUtil.filter(resourceName));
+                               sb.append("</tt></a></td>\r\n");
+
+                               sb.append("<td align=\"right\"><tt>");
+                               sb.append(renderSize(file.getFileSize()));
+                               sb.append("</tt></td>\r\n");
+
+                               sb.append("<td align=\"right\"><tt>");
+                               sb.append(getLastModifiedHttp(file.getAuditInfo()));
+                               sb.append("</tt></td>\r\n");
+
+                               sb.append("</tr>\r\n");
+                       }
+
+               // Render the page footer
+               sb.append("</table>\r\n");
+
+               sb.append("<HR size=\"1\" noshade=\"noshade\">");
+               sb.append("</body>\r\n");
+               sb.append("</html>\r\n");
+
+               // Return an input stream to the underlying bytes
+               writer.write(sb.toString());
+               writer.flush();
+               return new ByteArrayInputStream(stream.toByteArray());
+
+       }
 }