Package freenet.clients.http

Source Code of freenet.clients.http.LocalFileBrowserToadlet

/* This code is part of Freenet. It is distributed under the GNU General
* Public License, version 2 (or at your option any later version). See
* http://www.gnu.org/ for further details of the GPL. */
package freenet.clients.http;

import freenet.client.HighLevelSimpleClient;
import freenet.l10n.NodeL10n;
import freenet.node.NodeClientCore;
import freenet.support.HTMLNode;
import freenet.support.api.HTTPRequest;

import java.io.File;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Arrays;
import java.util.Comparator;
import java.util.Hashtable;
import java.util.Map;

/**
* @author David 'Bombe' Roden <bombe@freenetproject.org>
* @version $Id$
*/
public abstract class LocalFileBrowserToadlet extends Toadlet
  protected final NodeClientCore core;
  private static final int MAX_POST_SIZE = 1024*1024;

  public LocalFileBrowserToadlet (NodeClientCore core, HighLevelSimpleClient highLevelSimpleClient) {
    super(highLevelSimpleClient);
    this.core = core;
  }
 
  @Override
  public abstract String path();
 
  protected abstract String postTo();
 
  /**
   * Last directory from which an action was performed. If accessible, this is used instead of the fallback
   * default directory.
   */
  private File lastSuccessful;

  /**
   * Part set when a directory is selected.
   */
  public static final String selectDir = "select-dir";

  /**
   * Part set when a file is selected.
   */
  public static final String selectFile = "select-file";

  /**
   * Part set when a directory is changed.
   */
  public static final String changeDir = "change-dir";

  /**
   * @return Part which contains selected directory or file.
   */
  protected String filenameField() {
    return "filename";
  }

  /**
   * Whether the directory is allowed for the purposes of the specific browser. For example, do the node settings
   * allow downloading to the given directory?
   * @param path The path to check permissions for.
   * @return Whether browsing that directory is allowed. If it is not, the LocalFileBrowserToadlet will not render
   * a selection button or directory-changing button for it.
   */
  protected abstract boolean allowedDir(File path);
 
  /**
   * Performs sanity checks and generates parameter persistence fields.
   * @param set page parts/parameters
   * @return fieldPairs correct fields to persist for this browser type
   */
  protected abstract Hashtable<String, String> persistenceFields (Hashtable<String, String> set);

  /**
   * Determines the appropriate directory to start out in for the given browser. If a path is not already
   * specified, the browser will attempt to display this directory.
   * @return path to directory
   */
  protected abstract String startingDir();

  /**
   * Determines the appropriate directory to start out in if browsing for something to upload.
   * @return If all directories or no directories are allowed, returns the user's home directory.
   * Otherwise, returns the first allowed directory.
   */
  protected String defaultUploadDir() {
    if ((core.getAllowedUploadDirs().length == 1 && core.getAllowedUploadDirs()[0].toString().equals("all"))
            || core.getAllowedUploadDirs().length == 0) {
      /* If all directories are allowed, or none are, go for the home directory.
       * If none are allowed, any directory will result in an error anyway.
       */
      return System.getProperty("user.home");
    }
    //If locations are explicitly specified take the first one.
    return core.getAllowedUploadDirs()[0].getAbsolutePath();
  }

  /**
   * Determines the appropriate directory to start out in if browsing for something to download.
   * @return If all directories or no directories are allowed, the default downloads directory is returned.
   * Otherwise, returns the first allowed directory.
   */
  protected String defaultDownloadDir() {
    if ((core.getAllowedDownloadDirs().length == 1 && core.getAllowedDownloadDirs()[0].toString().equals("all"))
            || core.getAllowedDownloadDirs().length == 0) {
      /* If all directories are allowed, or none are, go for the default download directory.
       * If none are allowed, any directory will result in an error anyway.
       */
      return core.getDownloadsDir().getAbsolutePath();
    }
    //If locations are explicitly specified take the first one.
    return core.getAllowedDownloadDirs()[0].getAbsolutePath();
  }

  /**
   * Renders directory selection button with selectDir and filenameField() set.
   * @param node Node to add the button to.
   * @param absolutePath Path to set the filenameField() field to.
   * @param persistence Additional persistence fields to include.
   */
  protected void createSelectDirectoryButton (HTMLNode node, String absolutePath, HTMLNode persistence) {
    node.addChild("input",
            new String[]{"type", "name", "value"},
            new String[]{"submit", selectDir, l10n("insert")});
    node.addChild("input",
            new String[]{"type", "name", "value"},
            new String[]{"hidden", filenameField(), absolutePath});
    node.addChild(persistence);
  }

  /**
   * Renders file selection button with selectFile and filenameField() set.
   * @param node Node to add the button to.
   * @param absolutePath Path to set the filenameField() field to.
   * @param persistence Additional persistence fields to include.
   */
  protected void createSelectFileButton (HTMLNode node, String absolutePath, HTMLNode persistence) {
    node.addChild("input",
            new String[]{"type", "name", "value"},
            new String[]{"submit", selectFile, l10n("insert")});
    node.addChild("input",
            new String[]{"type", "name", "value"},
            new String[]{"hidden", filenameField(), absolutePath});
    node.addChild(persistence);
  }

  /**
   * Renders directory changing button with changeDir and filenameField() set.
   * @param node Node to add the button to.
   * @param path Path to set the "path" field to.
   * @param persistence Additional persistence fields to include.
   */
  private void createChangeDirButton (HTMLNode node, String buttonText, String path, HTMLNode persistence) {
    node.addChild("input",
            new String[]{"type", "name", "value"},
            new String[]{"submit", changeDir, buttonText});
    node.addChild("input",
            new String[]{"type", "name", "value"},
            new String[]{"hidden", "path", path});
    node.addChild(persistence);
  }
 
  /**
   * Returns a Hashtable of all URL parameters.
   * @param request contains URL parameters
   * @return Hashtable of all GET params.
   */
  private Hashtable<String, String> readGET (HTTPRequest request) {
    Hashtable<String, String> set = new Hashtable<String, String>();
    for (String key : request.getParameterNames()) {
      set.put(key, request.getParam(key));
    }
    return set;
  }
 
  /**
   * Returns a Hashtable of all POST parts up to a length of 1024*1024 characters.
   * @param request contains POST parts
   * @return set a Hashtable of all POST parts.
   */
  private Hashtable<String, String> readPOST (HTTPRequest request) {
    Hashtable<String, String> set = new Hashtable<String, String>();
    for (String key : request.getParts()) {
      set.put(key, request.getPartAsStringFailsafe(key, MAX_POST_SIZE));
    }
    return set;
  }
 
  /**
   * Renders hidden fields.
   * @param fieldPairs Pairs of values to be rendered
   * @return result HTMLNode containing hidden persistence fields
   */
  private HTMLNode renderPersistenceFields (Hashtable<String, String> fieldPairs) {
    HTMLNode result = new HTMLNode("div", "id", "persistenceFields");
    for (Map.Entry<String,String> entry : fieldPairs.entrySet()) {
      result.addChild("input",
              new String[] { "type", "name", "value" },
              new String[] { "hidden", entry.getKey(), entry.getValue() });
    }
    return result;
  }

  private String selectedValue(HTTPRequest request) {
    if (request.isParameterSet(filenameField()) &&
        (request.isParameterSet(selectDir) || request.isParameterSet(selectFile))) {
      //Request is a GET.
      return request.getParam(filenameField());
    } else if (request.isPartSet(filenameField()) &&
               (request.isPartSet(selectDir) || request.isPartSet(selectFile))) {
      //Request is a POST.
      return request.getPartAsStringFailsafe(filenameField(), MAX_POST_SIZE);
    }
    return null;
  }

  /**
   * @param uri is unused,
   * @param request contains parameters.
   * @param ctx allows page rendering and permissions checks.
   * @exception ToadletContextClosedException Access is denied: uploading might be disabled overall.
   *                                                            The user might be denied access to this directory,
   *                                                            which could be their home directory.
   * @exception IOException Something file-related went wrong.
   * @see <a href="freenet/clients/http/Toadlet#findSupportedMethods()">findSupportedMethods</a>
   * @see "java.net.URI"
   * @see "<a href="freenet/clients/http/ToadletContext.html">ToadletContext</a>
   */
  public void handleMethodGET (URI uri, HTTPRequest request, final ToadletContext ctx)
          throws ToadletContextClosedException, IOException, RedirectException {
    renderPage(persistenceFields(readGET(request)), request.getParam("path"), ctx, selectedValue(request));
  }

  public void handleMethodPOST (URI uri, HTTPRequest request, final ToadletContext ctx)
          throws ToadletContextClosedException, IOException, RedirectException {
    renderPage(persistenceFields(readPOST(request)), request.getPartAsStringFailsafe("path", MAX_POST_SIZE),
               ctx, selectedValue(request));
  }

  /**
   * Presents a file selection screen, or a something has been selected notes its directory and redirects to the
   * POST target.
   * @param fieldPairs fields which are to be persisted between views
   * @param path current path to display
   * @param ctx context used for rendering
   * @param filename a filename if a file or directory is selected, NULL if not.
   * @throws ToadletContextClosedException
   * @throws IOException
   * @throws RedirectException
   */
  private void renderPage (Hashtable<String, String> fieldPairs, String path, final ToadletContext ctx, String filename)
          throws ToadletContextClosedException, IOException, RedirectException {
    HTMLNode persistenceFields = renderPersistenceFields(fieldPairs);

    if (filename != null) {
      File file = new File(filename);
      if (file.isDirectory()) lastSuccessful = file.getAbsoluteFile();
      else lastSuccessful = file.getParentFile().getAbsoluteFile();

      try {
        throw new RedirectException(postTo());
      } catch (URISyntaxException e) {
        sendErrorPage(ctx, 500, NodeL10n.getBase().getString("Toadlet.internalErrorPleaseReport"),
                      e.getMessage());
      }
    }

    if (path.length() == 0) {
      if (lastSuccessful != null && lastSuccessful.isDirectory() && allowedDir(lastSuccessful)) {
        path = lastSuccessful.getAbsolutePath();
      } else {
        path = startingDir();
      }
    }

    File currentPath = new File(path).getCanonicalFile();
    //For use in error messages.
    String attemptedPath = currentPath == null ? "null" : currentPath.getAbsolutePath();

    PageMaker pageMaker = ctx.getPageMaker();

    if (currentPath != null && !allowedDir(currentPath)) {
      PageNode page = pageMaker.getPageNode(l10n("listingTitle", "path", attemptedPath), ctx);
      pageMaker.getInfobox("infobox-error""Forbidden", page.content, "access-denied", true).
              addChild("#", l10n("dirAccessDenied"));

      sendErrorPage(ctx, 403, "Forbidden", l10n("dirAccessDenied"));
      return;
    }
   
    HTMLNode pageNode;

    if (currentPath != null && currentPath.exists() && currentPath.isDirectory() && currentPath.canRead()) {
      PageNode page = pageMaker.getPageNode(l10n("listingTitle", "path",
              currentPath.getAbsolutePath()), ctx);
      pageNode = page.outer;
      HTMLNode contentNode = page.content;
      if (ctx.isAllowedFullAccess()) contentNode.addChild(ctx.getAlertManager().createSummary());
     
      HTMLNode infoboxDiv = contentNode.addChild("div", "class", "infobox");
      infoboxDiv.addChild("div", "class", "infobox-header", l10n("listing", "path",
              currentPath.getAbsolutePath()));
      HTMLNode listingDiv = infoboxDiv.addChild("div", "class", "infobox-content");
     
      File[] files = currentPath.listFiles();
     
      if (files == null) {
        sendErrorPage(ctx, 403, "Forbidden", l10n("dirAccessDenied"));
        return;
      }
     
      Arrays.sort(files, new Comparator<File>() {
        @Override
        public int compare(File firstFile, File secondFile) {
          /* Put directories above files, sorting each alphabetically and
           * case-insensitively.
           */
          if (firstFile.isDirectory() && !secondFile.isDirectory()) {
            return -1;
          }
          if (!firstFile.isDirectory() && secondFile.isDirectory()) {
            return 1;
          }
          return firstFile.getName().compareToIgnoreCase(secondFile.getName());
        }
      });
      HTMLNode listingTable = listingDiv.addChild("table");
      HTMLNode headerRow = listingTable.addChild("tr");
      headerRow.addChild("th");
      headerRow.addChild("th", l10n("fileHeader"));
      headerRow.addChild("th", l10n("sizeHeader"));
      /* add filesystem roots (fsck windows) */
      for (File currentRoot : File.listRoots()) {
        if (allowedDir(currentRoot)) {
        HTMLNode rootRow = listingTable.addChild("tr");
        rootRow.addChild("td");
        HTMLNode rootLinkCellNode = rootRow.addChild("td");
        HTMLNode rootLinkFormNode = ctx.addFormChild(rootLinkCellNode, path(),
                "insertLocalFileForm");
          createChangeDirButton(rootLinkFormNode, currentRoot.getCanonicalPath(),
                  currentRoot.getAbsolutePath(), persistenceFields);
        rootRow.addChild("td");
        }
      }
      /* add back link */
      if (currentPath.getParent() != null) {
        if (allowedDir(currentPath.getParentFile())) {
        HTMLNode backlinkRow = listingTable.addChild("tr");
        backlinkRow.addChild("td");
        HTMLNode backLinkCellNode = backlinkRow.addChild("td");
        HTMLNode backLinkFormNode = ctx.addFormChild(backLinkCellNode, path(),
                "insertLocalFileForm");
          createChangeDirButton(backLinkFormNode, "..", currentPath.getParent(), persistenceFields);
        backlinkRow.addChild("td");
        }
      }
      for (File currentFile : files) {
        if(currentFile.isHidden()) {
          // It won't be inserted if we insert the whole folder.
          // So lets just ignore it, less confusing.
          // FIXME in advanced mode, show them, and have a different style, and a toggle for whether to include them in a folder insert.
          continue;
        }
        HTMLNode fileRow = listingTable.addChild("tr");
        if (currentFile.isDirectory()) {
          if (currentFile.canRead()) {
            // Select directory
            if (allowedDir(currentFile)) {
            HTMLNode cellNode = fileRow.addChild("td");
            HTMLNode formNode = ctx.addFormChild(cellNode, path(),
                    "insertLocalFileForm");

              createSelectDirectoryButton(formNode, currentFile.getAbsolutePath(),
                      persistenceFields);

            // Change directory
            HTMLNode directoryCellNode = fileRow.addChild("td");
            HTMLNode directoryFormNode = ctx.addFormChild(directoryCellNode, path(),
                    "insertLocalFileForm");
              createChangeDirButton(directoryFormNode, currentFile.getName(),
                      currentFile.getAbsolutePath(), persistenceFields);
            }
          } else {
            fileRow.addChild("td");
            fileRow.addChild("td", "class", "unreadable-file",
                    currentFile.getName());
          }
          fileRow.addChild("td");
        } else {
          if (currentFile.canRead()) {
            //Select file
            HTMLNode cellNode = fileRow.addChild("td");
            HTMLNode formNode = ctx.addFormChild(cellNode, path(),
                    "insertLocalFileForm");
            createSelectFileButton(formNode, currentFile.getAbsolutePath(),
                    persistenceFields);
           
            fileRow.addChild("td", currentFile.getName());
            fileRow.addChild("td", "class", "right-align",
                    String.valueOf(currentFile.length()));
          } else {
            fileRow.addChild("td");
            fileRow.addChild("td", "class", "unreadable-file",
                    currentFile.getName());
            fileRow.addChild("td", "class", "right-align",
                    String.valueOf(currentFile.length()));
          }
        }
      }
    } else {
      PageNode page = pageMaker.getPageNode(l10n("listingTitle", "path", attemptedPath), ctx);
      pageNode = page.outer;
      HTMLNode contentNode = page.content;
      if (ctx.isAllowedFullAccess()) contentNode.addChild(ctx.getAlertManager().createSummary());
     
      HTMLNode infoboxDiv = contentNode.addChild("div", "class", "infobox");
      infoboxDiv.addChild("div", "class", "infobox-header", l10n("listing", "path", attemptedPath));
      HTMLNode listingDiv = infoboxDiv.addChild("div", "class", "infobox-content");

      listingDiv.addChild("#", l10n("dirCannotBeRead", "path", attemptedPath));
      HTMLNode ulNode = listingDiv.addChild("ul");
      ulNode.addChild("li", l10n("checkPathExist"));
      ulNode.addChild("li", l10n("checkPathIsDir"));
      ulNode.addChild("li", l10n("checkPathReadable"));
    }
    writeHTMLReply(ctx, 200, "OK", pageNode.generate());
  }

  private String l10n (String key, String pattern, String value) {
    return NodeL10n.getBase().getString("LocalFileInsertToadlet."+key,
            new String[] { pattern },
            new String[] { value });
  }

  private String l10n(String msg) {
    return NodeL10n.getBase().getString("LocalFileInsertToadlet."+msg);
  }
}
TOP

Related Classes of freenet.clients.http.LocalFileBrowserToadlet

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.