Package freenet.clients.fcp

Source Code of freenet.clients.fcp.ClientPutMessage

/* 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.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.util.HashMap;
import java.util.Map;

import freenet.client.HighLevelSimpleClientImpl;
import freenet.client.InsertContext;
import freenet.client.async.PersistenceDisabledException;
import freenet.clients.fcp.ClientPutBase.UploadFrom;
import freenet.clients.fcp.ClientRequest.Persistence;
import freenet.keys.FreenetURI;
import freenet.node.Node;
import freenet.node.RequestStarter;
import freenet.support.HexUtil;
import freenet.support.Logger;
import freenet.support.SimpleFieldSet;
import freenet.support.api.BucketFactory;
import freenet.support.api.RandomAccessBucket;
import freenet.support.compress.Compressor.COMPRESSOR_TYPE;
import freenet.support.compress.InvalidCompressionCodecException;
import freenet.support.io.FileBucket;

/**
*
* ClientPut
* URI=CHK@ // could as easily be an insertable SSK URI
* Metadata.ContentType=text/html
* Identifier=Insert-1 // identifier, as always
* Verbosity=0 // just report when complete
* MaxRetries=999999 // lots of retries
* PriorityClass=1 // FProxy priority level
*
* UploadFrom=direct // attached directly to this message
* DataLength=100 // 100kB
* or
* UploadFrom=disk // upload a file from disk
* Filename=/home/toad/something.html
* FileHash=021349568329403123
* Data
*
* Neither IgnoreDS nor DSOnly make sense for inserts.
*/
public class ClientPutMessage extends DataCarryingMessage {

  public final static String NAME = "ClientPut";
 
  final FreenetURI uri;
  final String contentType;
  final long dataLength;
  final String identifier;
  final int verbosity;
  final int maxRetries;
  final boolean getCHKOnly;
  final short priorityClass;
  final Persistence persistence;
  final UploadFrom uploadFromType;
  /** The hash of the file you want the node to deal with.
   *  it is MANDATORY to do DDA operations and should be computed like that:
   * 
   *  Base64Encode(SHA256( Handler.connectionIdentifer + ClientPutMessage.identifier + content))
   */
  final String fileHash;
  final boolean dontCompress;
  final String clientToken;
  final File origFilename;
  final boolean global;
  final FreenetURI redirectTarget;
  /** Filename (hint for the final filename) */
  final String targetFilename;
  final boolean earlyEncode;
  final boolean binaryBlob;
  final boolean canWriteClientCache;
  final String compressorDescriptor;
  final boolean forkOnCacheable;
  final int extraInsertsSingleBlock;
  final int extraInsertsSplitfileHeaderBlock;
  final InsertContext.CompatibilityMode compatibilityMode;
  final byte[] overrideSplitfileCryptoKey;
  final boolean localRequestOnly;
  final boolean realTimeFlag;
  final long metadataThreshold;
  final boolean ignoreUSKDatehints;
 
  public ClientPutMessage(SimpleFieldSet fs) throws MessageInvalidException {
    String fnam = null;
    identifier = fs.get("Identifier");
    binaryBlob = fs.getBoolean("BinaryBlob", false);
    global = fs.getBoolean("Global", false);
    localRequestOnly = fs.getBoolean("LocalRequestOnly", false);
    String s = fs.get("CompatibilityMode");
    InsertContext.CompatibilityMode cmode = null;
    if(s == null)
      cmode = InsertContext.CompatibilityMode.COMPAT_DEFAULT;
    else {
      try {
        cmode = InsertContext.CompatibilityMode.valueOf(s);
      } catch (IllegalArgumentException e) {
        try {
          cmode = InsertContext.CompatibilityMode.values()[Integer.parseInt(s)];
        } catch (NumberFormatException e1) {
          throw new MessageInvalidException(ProtocolErrorMessage.INVALID_FIELD, "Invalid CompatibilityMode (not a name and not a number)", identifier, global);
        } catch (ArrayIndexOutOfBoundsException e1) {
          throw new MessageInvalidException(ProtocolErrorMessage.INVALID_FIELD, "Invalid CompatibilityMode (not a valid number)", identifier, global);
        }
      }
    }
    compatibilityMode = cmode.intern();
    s = fs.get("OverrideSplitfileCryptoKey");
    if(s == null)
      overrideSplitfileCryptoKey = null;
    else
      try {
        overrideSplitfileCryptoKey = HexUtil.hexToBytes(s);
      } catch (NumberFormatException e1) {
        throw new MessageInvalidException(ProtocolErrorMessage.INVALID_FIELD, "Invalid splitfile crypto key (not hex)", identifier, global);
      } catch (IndexOutOfBoundsException e1) {
        throw new MessageInvalidException(ProtocolErrorMessage.INVALID_FIELD, "Invalid splitfile crypto key (too short)", identifier, global);
      }
    if(identifier == null)
      throw new MessageInvalidException(ProtocolErrorMessage.MISSING_FIELD, "No Identifier", null, global);
    try {
      if(binaryBlob)
        uri = new FreenetURI("CHK@");
      else {
        String u = fs.get("URI");
        if(u == null)
          throw new MessageInvalidException(ProtocolErrorMessage.MISSING_FIELD, "No URI", identifier, global);
        FreenetURI uu = new FreenetURI(u);
        String[] metas = uu.getAllMetaStrings();
        if(metas != null && metas.length == 1) {
          fnam = metas[0];
          uu = uu.setMetaString(null);
        } // if >1, will fail later
        uri = uu;
      }
    } catch (MalformedURLException e) {
      throw new MessageInvalidException(ProtocolErrorMessage.FREENET_URI_PARSE_ERROR, e.getMessage(), identifier, global);
    }
    String verbosityString = fs.get("Verbosity");
    if(verbosityString == null)
      verbosity = 0;
    else {
      try {
        verbosity = Integer.parseInt(verbosityString, 10);
      } catch (NumberFormatException e) {
        throw new MessageInvalidException(ProtocolErrorMessage.ERROR_PARSING_NUMBER, "Error parsing Verbosity field: "+e.getMessage(), identifier, global);
      }
    }
    contentType = fs.get("Metadata.ContentType");
    String maxRetriesString = fs.get("MaxRetries");
    if(maxRetriesString == null)
      // default to 0
      maxRetries = 0;
    else {
      try {
        maxRetries = Integer.parseInt(maxRetriesString, 10);
      } catch (NumberFormatException e) {
        throw new MessageInvalidException(ProtocolErrorMessage.ERROR_PARSING_NUMBER, "Error parsing MaxSize field: "+e.getMessage(), identifier, global);
      }
    }
    getCHKOnly = fs.getBoolean("GetCHKOnly", false);
    String priorityString = fs.get("PriorityClass");
    if(priorityString == null) {
      // defaults to the one just below FProxy
      priorityClass = RequestStarter.IMMEDIATE_SPLITFILE_PRIORITY_CLASS;
    } else {
      try {
        priorityClass = Short.parseShort(priorityString);
        if(!RequestStarter.isValidPriorityClass(priorityClass))
          throw new MessageInvalidException(ProtocolErrorMessage.INVALID_FIELD, "Invalid priority class "+priorityClass+" - range is "+RequestStarter.PAUSED_PRIORITY_CLASS+" to "+RequestStarter.MAXIMUM_PRIORITY_CLASS, identifier, global);
      } catch (NumberFormatException e) {
        throw new MessageInvalidException(ProtocolErrorMessage.ERROR_PARSING_NUMBER, "Error parsing PriorityClass field: "+e.getMessage(), identifier, global);
      }
    }
    // We do *NOT* check that FileHash is valid here for backward compatibility... and to make the override work
    this.fileHash = fs.get(ClientPutBase.FILE_HASH);
    String uploadFrom = fs.get("UploadFrom");
    if((uploadFrom == null) || uploadFrom.equalsIgnoreCase("direct")) {
      uploadFromType = UploadFrom.DIRECT;
      String dataLengthString = fs.get("DataLength");
      if(dataLengthString == null)
        throw new MessageInvalidException(ProtocolErrorMessage.MISSING_FIELD, "Need DataLength on a ClientPut", identifier, global);
      try {
        dataLength = Long.parseLong(dataLengthString, 10);
      } catch (NumberFormatException e) {
        throw new MessageInvalidException(ProtocolErrorMessage.ERROR_PARSING_NUMBER, "Error parsing DataLength field: "+e.getMessage(), identifier, global);
      }
      this.origFilename = null;
      redirectTarget = null;
    } else if(uploadFrom.equalsIgnoreCase("disk")) {
      uploadFromType = UploadFrom.DISK;
      String filename = fs.get("Filename");
      if(filename == null)
        throw new MessageInvalidException(ProtocolErrorMessage.MISSING_FIELD, "Missing field Filename", identifier, global);
      File f = new File(filename);
      if(!(f.exists() && f.isFile() && f.canRead()))
        throw new MessageInvalidException(ProtocolErrorMessage.FILE_NOT_FOUND, null, identifier, global);
      dataLength = f.length();
      FileBucket fileBucket = new FileBucket(f, true, false, false, false);
      this.bucket = fileBucket;
      this.origFilename = f;
      redirectTarget = null;
      if(fnam == null)
        fnam = origFilename.getName();
    } else if(uploadFrom.equalsIgnoreCase("redirect")) {
      uploadFromType = UploadFrom.REDIRECT;
      String target = fs.get("TargetURI");
      if(target == null)
        throw new MessageInvalidException(ProtocolErrorMessage.MISSING_FIELD, "TargetURI missing but UploadFrom=redirect", identifier, global);
      try {
        redirectTarget = new FreenetURI(target);
      } catch (MalformedURLException e) {
        throw new MessageInvalidException(ProtocolErrorMessage.INVALID_FIELD, "Invalid TargetURI: "+e, identifier, global);
      }
      dataLength = 0;
      origFilename = null;
      bucket = null;
    } else
      throw new MessageInvalidException(ProtocolErrorMessage.INVALID_FIELD, "UploadFrom invalid or unrecognized: "+uploadFrom, identifier, global);
    dontCompress = fs.getBoolean("DontCompress", false);
    String persistenceString = fs.get("Persistence");
    persistence = Persistence.parseOrThrow(persistenceString, identifier, global);
    canWriteClientCache = fs.getBoolean("WriteToClientCache", false);
    clientToken = fs.get("ClientToken");
    String f = fs.get("TargetFilename");
    if(f != null)
      fnam = f;
    if(fnam != null && fnam.indexOf('/') > -1) {
      throw new MessageInvalidException(ProtocolErrorMessage.INVALID_FIELD, "TargetFilename must not contain slashes", identifier, global);
    }
    if(fnam != null && fnam.length() == 0) {
      fnam = null; // Deliberate override to tell us not to create one.
    }
    if(uri.getRoutingKey() == null && !uri.isKSK())
      targetFilename = fnam;
    else
      targetFilename = null;
    earlyEncode = fs.getBoolean("EarlyEncode", false);
    String codecs = fs.get("Codecs");
    if (codecs != null) {
      COMPRESSOR_TYPE[] ca;
      try {
        ca = COMPRESSOR_TYPE.getCompressorsArrayNoDefault(codecs);
      } catch (InvalidCompressionCodecException e) {
        throw new MessageInvalidException(ProtocolErrorMessage.INVALID_FIELD, e.getMessage(), identifier, global);
      }
      if (ca == null)
        codecs = null;
    }
    compressorDescriptor = codecs;
    if(fs.get("ForkOnCacheable") != null)
      forkOnCacheable = fs.getBoolean("ForkOnCacheable", false);
    else
      forkOnCacheable = Node.FORK_ON_CACHEABLE_DEFAULT;
    extraInsertsSingleBlock = fs.getInt("ExtraInsertsSingleBlock", HighLevelSimpleClientImpl.EXTRA_INSERTS_SINGLE_BLOCK);
    extraInsertsSplitfileHeaderBlock = fs.getInt("ExtraInsertsSplitfileHeaderBlock", HighLevelSimpleClientImpl.EXTRA_INSERTS_SPLITFILE_HEADER);
    realTimeFlag = fs.getBoolean("RealTimeFlag", false);
    metadataThreshold = fs.getLong("MetadataThreshold", -1);
    ignoreUSKDatehints = fs.getBoolean("IgnoreUSKDatehints", false);
  }

  @Override
  public SimpleFieldSet getFieldSet() {
    SimpleFieldSet sfs = new SimpleFieldSet(true);
    sfs.putSingle("URI", uri.toString());
    sfs.putSingle("Identifier", identifier);
    sfs.put("Verbosity", verbosity);
    sfs.put("MaxRetries", maxRetries);
    sfs.putSingle("Metadata.ContentType", contentType);
    sfs.putSingle("ClientToken", clientToken);
    switch(uploadFromType) {
    case DIRECT:
            sfs.putSingle("UploadFrom", "direct");
            sfs.put("DataLength", dataLength);
        break;
    case DISK:
            sfs.putSingle("UploadFrom", "disk");
            sfs.putSingle("Filename", origFilename.getAbsolutePath());
            sfs.put("DataLength", dataLength);
            break;
    case REDIRECT:
            sfs.putSingle("UploadFrom", "redirect");
            sfs.putSingle("TargetURI", redirectTarget.toString());
            break;
    }
    sfs.put("GetCHKOnly", getCHKOnly);
    sfs.put("PriorityClass", priorityClass);
    sfs.putSingle("Persistence", persistence.toString().toLowerCase());
    sfs.put("DontCompress", dontCompress);
    if (compressorDescriptor != null)
      sfs.putSingle("Codecs", compressorDescriptor);
    sfs.put("Global", global);
    sfs.put("BinaryBlob", binaryBlob);
    return sfs;
  }

  @Override
  public String getName() {
    return NAME;
  }

  @Override
  public void run(FCPConnectionHandler handler, Node node)
      throws MessageInvalidException {
    handler.startClientPut(this);
  }

  /**
   * Get the length of the trailing field.
   */
  @Override
  long dataLength() {
    if(uploadFromType == UploadFrom.DIRECT)
      return dataLength;
    else return -1;
  }

  @Override
  String getIdentifier() {
    return identifier;
  }

  @Override
  RandomAccessBucket createBucket(BucketFactory bf, long length, FCPServer server) throws IOException, PersistenceDisabledException {
    if(persistence == Persistence.FOREVER) {
        if(server.core.killedDatabase()) throw new PersistenceDisabledException();
      return server.core.persistentTempBucketFactory.makeBucket(length);
    } else {
      return super.createBucket(bf, length, server);
    }
  }

  @Override
  boolean isGlobal() {
    return global;
  }

  public void freeData() {
    if(bucket == null) {
      if(dataLength() <= 0)
        return; // Okay.
      Logger.error(this, "bucket is null on "+this+" - freed twice?", new Exception("error"));
      return;
    }
    bucket.free();
  }

}
TOP

Related Classes of freenet.clients.fcp.ClientPutMessage

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.