Package freenet.clients.fcp

Source Code of freenet.clients.fcp.ClientPutComplexDirMessage

/* 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.fcp;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.Map;

import freenet.clients.fcp.ClientRequest.Persistence;
import freenet.node.Node;
import freenet.support.Logger;
import freenet.support.SimpleFieldSet;
import freenet.support.Logger.LogLevel;
import freenet.support.api.BucketFactory;
import freenet.support.api.ManifestElement;
import freenet.support.io.PersistentTempBucketFactory;

/**
* <pre>
* ClientPutComplexDir
* &lt; ... standard ClientPutDir headers ... &gt;
* Files.0.Name=hello.txt
* Files.0.UploadFrom=direct
* Files.0.Metadata.ContentType=text/plain
* Files.0.DataLength=6
*  ( upload the 6 bytes following this message as hello.txt, type plain text)
* Files.1.Name=something.pdf
* Files.1.UploadFrom=disk
* Files.1.Filename=something.pdf
*  ( upload something.pdf, guess the mime type from the filename )
* Files.2.Name=toad.jpeg
* Files.2.UploadFrom=redirect
* Files.2.TargetURI=CHK@...,...,...
* Files.2.Metadata.ContentType=image/jpeg
*  ( not yet supported, but would be really useful! FIXME ! )
* (note that the Files.x must always be a decimal integer. We use these for sort
*  order for UploadFrom=direct. they must be sequential and start at 0).
* ...
* End
* &lt;data from above direct uploads, ***in alphabetical order***&gt;
* </pre>
*/
public class ClientPutComplexDirMessage extends ClientPutDirMessage {

  /** The files attached to this message, in a directory hierarchy */
  private final HashMap<String, Object /* <HashMap || DirPutFile> */> filesByName;
  /** Any files we want to read data from */
  private final LinkedList<DirPutFile> filesToRead;
  /** Total number of bytes of attached data */
  private final long attachedBytes;
 
  public ClientPutComplexDirMessage(SimpleFieldSet fs, BucketFactory bfTemp, PersistentTempBucketFactory bfPersistent) throws MessageInvalidException {
    // Parse the standard ClientPutDir headers - URI, etc.
    super(fs);
   
    filesByName = new HashMap<String, Object>();
    filesToRead = new LinkedList<DirPutFile>();
    long totalBytes = 0;
    // Now parse the meat
    SimpleFieldSet files = fs.subset("Files");
    if(files == null)
      throw new MessageInvalidException(ProtocolErrorMessage.MISSING_FIELD, "Missing Files section", identifier, global);
    boolean logMINOR = Logger.shouldLog(LogLevel.MINOR, this);
    for(int i=0;;i++) {
      SimpleFieldSet subset = files.subset(Integer.toString(i));
      if(subset == null) break;
      DirPutFile f = DirPutFile.create(subset, identifier, global, (persistence == Persistence.FOREVER) ? bfPersistent : bfTemp);
      addFile(f);
      if(logMINOR) Logger.minor(this, "Adding "+f);
      if(f instanceof DirectDirPutFile) {
        totalBytes += ((DirectDirPutFile)f).bytesToRead();
        filesToRead.addLast(f);
        if(logMINOR) Logger.minor(this, "totalBytes now "+totalBytes);
      }
    }
    attachedBytes = totalBytes;
  }
 
  /**
   * Add a file to the filesByName.
   * @throws MessageInvalidException
   */
  private void addFile(DirPutFile f) throws MessageInvalidException {
    addFile(filesByName, f.getName(), f);
  }
 
  @SuppressWarnings("unchecked")
  private void addFile(HashMap<String, Object> byName, String name, DirPutFile f) throws MessageInvalidException {
    int idx = name.indexOf('/');
    if(idx == -1) {
      byName.put(name, f);
    } else {
      String before = name.substring(0, idx);
      String after = name.substring(idx+1);
      Object o = byName.get(before);
      if(o != null) {
        if (o instanceof HashMap) {
          addFile((HashMap<String, Object>) o, after, f);
          return;
        } else {
          throw new MessageInvalidException(ProtocolErrorMessage.INVALID_MESSAGE, "Cannot be both a file and a directory: "+before, identifier, global);
        }
      } else {
        o = new HashMap<Object, Object>();
        byName.put(before, o);
        addFile((HashMap<String, Object>) o, after, f);
      }
    }
  }

  static final String NAME = "ClientPutComplexDir";
 
  @Override
  public String getName() {
    return NAME;
  }

  @Override
  long dataLength() {
    return attachedBytes;
  }

  String getIdentifier() {
    return identifier;
  }

  @Override
  public void readFrom(InputStream is, BucketFactory bf, FCPServer server) throws IOException, MessageInvalidException {
    for(DirPutFile f: filesToRead) {
      ((DirectDirPutFile)f).read(is);
    }
  }

  @Override
  protected void writeData(OutputStream os) throws IOException {
    for(DirPutFile f: filesToRead) {
      ((DirectDirPutFile)f).write(os);
    }
  }

  @Override
  public void run(FCPConnectionHandler handler, Node node) throws MessageInvalidException {
    // Convert the hierarchical hashmap's of DirPutFile's to hierarchical hashmap's
    // of ManifestElement's.
    // Then simply create the ClientPutDir.
    HashMap<String, Object> manifestElements = new HashMap<String, Object>();
    convertFilesByNameToManifestElements(filesByName, manifestElements, node);
    handler.startClientPutDir(this, manifestElements, false);
  }

  /**
   * Convert a hierarchy of HashMap's containing DirPutFile's into a hierarchy of
   * HashMap's containing ManifestElement's.
   */
  @SuppressWarnings("unchecked")
  private void convertFilesByNameToManifestElements(HashMap<String, Object> filesByName,
          HashMap<String, Object> manifestElements, Node node) throws MessageInvalidException {
   
    for (Map.Entry<String, Object> entry : filesByName.entrySet()) {
      String tempName = entry.getKey();
      Object val = entry.getValue();
      if(val instanceof HashMap) {
        HashMap<String, Object> h = (HashMap<String, Object>) val;
        HashMap<String, Object> manifests = new HashMap<String, Object>();
        manifestElements.put(tempName, manifests);
        convertFilesByNameToManifestElements(h, manifests, node);
      } else {
        DirPutFile f = (DirPutFile) val;
        if(f instanceof DiskDirPutFile && !node.clientCore.allowUploadFrom(((DiskDirPutFile)f).getFile()))
          throw new MessageInvalidException(ProtocolErrorMessage.ACCESS_DENIED, "Not allowed to upload "+((DiskDirPutFile) f).getFile(), identifier, global);
        ManifestElement e = f.getElement();
        manifestElements.put(tempName, e);
      }
    }
  }

}
TOP

Related Classes of freenet.clients.fcp.ClientPutComplexDirMessage

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.