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;
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;
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) {
}
String progress = req.getParameter(PROGRESS_PARAMETER);
- if (logger.isDebugEnabled())
+ if (logger.isDebugEnabled())
if (content)
logger.debug("Serving resource '" + path + "' headers and data");
else
User user = getUser(req);
User owner = getOwner(req);
- if (user == null) user = owner;
boolean exists = true;
Object resource = null;
FileHeaderDTO file = null;
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,
// we need to check the read-all flag or the signature-in-parameters.
if (authDeferred)
if (file != null && !file.isReadForAll() && content) {
+ logger.debug("this case refers to a file with no public privileges");
// Check for GET with the signature in the request parameters.
String auth = req.getParameter(AUTHORIZATION_PARAMETER);
String dateParam = req.getParameter(DATE_PARAMETER);
return;
}
}
- } else if (file != null && !file.isReadForAll() || folder != null && !folder.isReadForAll()) {
- // 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.
+ logger.debug("*********this case refers to a folder or file with public privileges");
+ user = owner;
+ req.setAttribute(USER_ATTRIBUTE, user);
+ }else if(folder != null && !folder.isReadForAll()){
+ //this case refers to a folder with no public privileges
+ logger.debug("*********this case refers to a folder with no public privileges");
+ resp.sendError(HttpServletResponse.SC_FORBIDDEN);
+ return;
+ }
+ else{
+ logger.debug("*********ANY other case");
+ resp.sendError(HttpServletResponse.SC_FORBIDDEN);
+ return;
+ }
// If the resource is not a collection, and the resource path
// ends with "/" or "\", return NOT FOUND.
// 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;
// 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;
+ }else if (accept != null && accept.contains("text/html") && !authDeferred){
+ //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
+ contentType = "text/html;charset=UTF-8";
+ isContentHtml = true;
+ expectJSON = true;
+ }
+ else{
+ contentType = "application/json;charset=UTF-8";
+ expectJSON = true;
+ }
+ }
+
ArrayList ranges = null;
long contentLength = -1L;
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())
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 {
}
String newName = req.getParameter(NEW_FOLDER_PARAMETER);
+ if (!isValidResourceName(newName)) {
+ resp.sendError(HttpServletResponse.SC_BAD_REQUEST);
+ return;
+ }
boolean hasUpdateParam = req.getParameterMap().containsKey(RESOURCE_UPDATE_PARAMETER);
boolean hasTrashParam = req.getParameterMap().containsKey(RESOURCE_TRASH_PARAMETER);
boolean hasRestoreParam = req.getParameterMap().containsKey(RESOURCE_RESTORE_PARAMETER);
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;
- }
JSONArray permissions = json.optJSONArray("permissions");
Set<PermissionDTO> perms = null;
if (permissions != null)
* 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("/"))
}
}
}
+ /**
+ * 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 relativePath the requested relative path to the resource
+ * @param folder the specified directory
+ * @param req the HTTP request
+ * @return an input stream with the rendered contents
+ * @throws IOException
+ * @throws ServletException
+ */
+ private InputStream renderHtml(String contextPath, String relativePath, 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 folderPath = folder.getPath();
+ int indexFolderPath = relativePath.indexOf(folderPath);
+ String relativePathNoFolderName = null;
+ if(indexFolderPath != 0)
+ relativePathNoFolderName = relativePath.substring(0, indexFolderPath);
+ else
+ relativePathNoFolderName = relativePath;
+ String parentDirectory = folderPath;
+ //To-do: further search in encoding folder names with special characters
+ //String rewrittenParentDirectory = rewriteUrl(parentDirectory);
+ if (parentDirectory.endsWith("/"))
+ parentDirectory = parentDirectory.substring(0, parentDirectory.length() - 1);
+ int slash = parentDirectory.lastIndexOf('/');
+ parentDirectory = parentDirectory.substring(0,slash);
+ if (slash >= 0) {
+ sb.append(" - <a href=\"");
+ sb.append(rewrittenContextPath);
+ sb.append(relativePathNoFolderName);
+ sb.append(parentDirectory);
+ if (!parentDirectory.endsWith("/"))
+ sb.append("/");
+ sb.append("\">");
+ sb.append("<b>");
+ sb.append("Up To ");
+ if (parentDirectory.equals(""))
+ parentDirectory = "/";
+ sb.append(parentDirectory);
+ 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();
+ 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\"> \r\n");
+ sb.append("<a href=\"");
+ sb.append(rewrittenContextPath);
+ sb.append(relativePathNoFolderName);
+ sb.append(folderPath + 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(" ");
+ 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
+ if(file.isReadForAll()){
+ 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\"> \r\n");
+ sb.append("<a href=\"");
+ sb.append(rewrittenContextPath);
+ sb.append(relativePath);
+ if(!relativePath.endsWith("/"))
+ sb.append("/");
+ 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("<h3>").append(getServletContext().getServerInfo()).append("</h3>");
+ 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());
+
+ }
}