Author: toad
Date: 2007-05-23 23:08:25 +0000 (Wed, 23 May 2007)
New Revision: 13348

Modified:
   trunk/freenet/src/freenet/client/HighLevelSimpleClientImpl.java
   trunk/freenet/src/freenet/client/async/ClientGetter.java
   trunk/freenet/src/freenet/client/async/SimpleSingleFileFetcher.java
   trunk/freenet/src/freenet/client/async/SingleFileFetcher.java
   trunk/freenet/src/freenet/client/async/SplitFileFetcherSegment.java
   trunk/freenet/src/freenet/client/async/SplitFileFetcherSubSegment.java
   trunk/freenet/src/freenet/clients/http/NinjaSpider.java
   trunk/freenet/src/freenet/clients/http/Spider.java
   trunk/freenet/src/freenet/keys/CHKBlock.java
   trunk/freenet/src/freenet/keys/KeyBlock.java
   trunk/freenet/src/freenet/keys/SSKBlock.java
   trunk/freenet/src/freenet/node/fcp/ClientGet.java
   trunk/freenet/src/freenet/node/fcp/ClientGetMessage.java
   trunk/freenet/src/freenet/node/updater/NodeUpdater.java
   trunk/freenet/src/freenet/node/updater/RevocationChecker.java
Log:
Binary blobs part 1: The ability to download a freesite as a binary blob file 
(a series of raw keys packed into a file which can be reinserted with part 2).
This will allow for migration of your favourite content between disconnected 
networks, and for update over mandatory.

Modified: trunk/freenet/src/freenet/client/HighLevelSimpleClientImpl.java
===================================================================
--- trunk/freenet/src/freenet/client/HighLevelSimpleClientImpl.java     
2007-05-23 22:40:31 UTC (rev 13347)
+++ trunk/freenet/src/freenet/client/HighLevelSimpleClientImpl.java     
2007-05-23 23:08:25 UTC (rev 13348)
@@ -111,7 +111,7 @@
                if(uri == null) throw new NullPointerException();
                FetchContext context = getFetchContext();
                FetchWaiter fw = new FetchWaiter();
-               ClientGetter get = new ClientGetter(fw, 
core.requestStarters.chkFetchScheduler, core.requestStarters.sskFetchScheduler, 
uri, context, priorityClass, this, null);
+               ClientGetter get = new ClientGetter(fw, 
core.requestStarters.chkFetchScheduler, core.requestStarters.sskFetchScheduler, 
uri, context, priorityClass, this, null, null);
                get.start();
                return fw.waitForCompletion();
        }
@@ -124,7 +124,7 @@
                if(uri == null) throw new NullPointerException();
                FetchWaiter fw = new FetchWaiter();
                FetchContext context = getFetchContext(overrideMaxSize);
-               ClientGetter get = new ClientGetter(fw, 
core.requestStarters.chkFetchScheduler, core.requestStarters.sskFetchScheduler, 
uri, context, priorityClass, clientContext, null);
+               ClientGetter get = new ClientGetter(fw, 
core.requestStarters.chkFetchScheduler, core.requestStarters.sskFetchScheduler, 
uri, context, priorityClass, clientContext, null, null);
                get.start();
                return fw.waitForCompletion();
        }

Modified: trunk/freenet/src/freenet/client/async/ClientGetter.java
===================================================================
--- trunk/freenet/src/freenet/client/async/ClientGetter.java    2007-05-23 
22:40:31 UTC (rev 13347)
+++ trunk/freenet/src/freenet/client/async/ClientGetter.java    2007-05-23 
23:08:25 UTC (rev 13348)
@@ -3,8 +3,10 @@
  * http://www.gnu.org/ for further details of the GPL. */
 package freenet.client.async;

+import java.io.DataOutputStream;
 import java.io.IOException;
 import java.net.MalformedURLException;
+import java.util.HashSet;

 import freenet.client.ArchiveContext;
 import freenet.client.ClientMetadata;
@@ -13,6 +15,8 @@
 import freenet.client.FetchContext;
 import freenet.client.events.SplitfileProgressEvent;
 import freenet.keys.FreenetURI;
+import freenet.keys.Key;
+import freenet.keys.KeyBlock;
 import freenet.support.Logger;
 import freenet.support.api.Bucket;
 import freenet.support.io.BucketTools;
@@ -31,6 +35,11 @@
        private int archiveRestarts;
        /** If not null, Bucket to return the data in */
        final Bucket returnBucket;
+       /** If not null, Bucket to return a binary blob in */
+       final Bucket binaryBlobBucket;
+       /** If not null, HashSet to track keys already added for a binary blob 
*/
+       final HashSet binaryBlobKeysAddedAlready;
+       private DataOutputStream binaryBlobStream;

        /**
         * Fetch a key.
@@ -45,7 +54,7 @@
         * former, obviously!
         */
        public ClientGetter(ClientCallback client, ClientRequestScheduler 
chkSched, ClientRequestScheduler sskSched,
-                           FreenetURI uri, FetchContext ctx, short 
priorityClass, Object clientContext, Bucket returnBucket) {
+                           FreenetURI uri, FetchContext ctx, short 
priorityClass, Object clientContext, Bucket returnBucket, Bucket 
binaryBlobBucket) {
                super(priorityClass, chkSched, sskSched, clientContext);
                this.client = client;
                this.returnBucket = returnBucket;
@@ -53,6 +62,11 @@
                this.ctx = ctx;
                this.finished = false;
                this.actx = new ArchiveContext(ctx.maxArchiveLevels);
+               this.binaryBlobBucket = binaryBlobBucket;
+               if(binaryBlobBucket != null) {
+                       binaryBlobKeysAddedAlready = new HashSet();
+               } else
+                       binaryBlobKeysAddedAlready = null;
                archiveRestarts = 0;
        }

@@ -80,8 +94,17 @@
                                                returnBucket, true);
                        }
                        if(cancelled) cancel();
-                       if(currentState != null && !finished)
+                       if(currentState != null && !finished) {
+                               if(binaryBlobBucket != null) {
+                                       try {
+                                               writeBinaryBlobHeader();
+                                       } catch (IOException e) {
+                                               onFailure(new 
FetchException(FetchException.BUCKET_ERROR, "Failed to open binary blob 
bucket"), null);
+                                               return false;
+                                       }
+                               }
                                currentState.schedule();
+                       }
                        if(cancelled) cancel();
                } catch (MalformedURLException e) {
                        throw new FetchException(FetchException.INVALID_URI, e);
@@ -90,6 +113,7 @@
        }

        public void onSuccess(FetchResult result, ClientGetState state) {
+               if(!closeBinaryBlobStream()) return;
                synchronized(this) {
                        finished = true;
                        currentState = null;
@@ -120,6 +144,7 @@
        }

        public void onFailure(FetchException e, ClientGetState state) {
+               closeBinaryBlobStream();
                while(true) {
                        if(e.mode == FetchException.ARCHIVE_RESTART) {
                                int ar;
@@ -213,4 +238,84 @@
        public String toString() {
                return super.toString()+ ':' +uri;
        }
-}
+       
+       public static final long BINARY_BLOB_MAGIC = 0x6d58249f72d67ed9L;
+       public static final short BINARY_BLOB_OVERALL_VERSION = 0;
+       
+       private void writeBinaryBlobHeader() throws IOException {
+               binaryBlobStream = new 
DataOutputStream(binaryBlobBucket.getOutputStream());
+               binaryBlobStream.writeLong(BINARY_BLOB_MAGIC);
+               binaryBlobStream.writeShort(BINARY_BLOB_OVERALL_VERSION);
+       }
+
+       static final short BLOB_BLOCK = 1;
+       static final short BLOB_BLOCK_VERSION = 0;
+       
+       static final short BLOB_END = 2;
+       static final short BLOB_END_VERSION = 0;
+       
+       void addKeyToBinaryBlob(KeyBlock block) {
+               if(binaryBlobKeysAddedAlready == null) return;
+               Key key = block.getKey();
+               synchronized(binaryBlobKeysAddedAlready) {
+                       if(binaryBlobStream == null) return;
+                       if(binaryBlobKeysAddedAlready.contains(key)) return;
+                       binaryBlobKeysAddedAlready.add(key);
+                       byte[] keyData = key.getRoutingKey();
+                       byte[] headers = block.getRawHeaders();
+                       byte[] data = block.getRawData();
+                       byte[] pubkey = block.getPubkeyBytes();
+                       try {
+                               writeBlobHeader(BLOB_BLOCK, BLOB_BLOCK_VERSION, 
7+keyData.length+headers.length+data.length);
+                               
binaryBlobStream.writeShort(block.getKey().getType());
+                               binaryBlobStream.writeByte(keyData.length);
+                               binaryBlobStream.writeShort(headers.length);
+                               binaryBlobStream.writeShort(data.length);
+                               binaryBlobStream.writeShort(pubkey == null ? 0 
: pubkey.length);
+                               binaryBlobStream.write(keyData);
+                               binaryBlobStream.write(headers);
+                               binaryBlobStream.write(data);
+                               if(pubkey != null)
+                                       binaryBlobStream.write(pubkey);
+                       } catch (IOException e) {
+                               Logger.error(this, "Failed to write key to 
binary blob stream: "+e, e);
+                               onFailure(new 
FetchException(FetchException.BUCKET_ERROR, "Failed to write key to binary blob 
stream: "+e), null);
+                               binaryBlobStream = null;
+                               binaryBlobKeysAddedAlready.clear();
+                       }
+               }
+       }
+       
+       /**
+        * Close the binary blob stream.
+        * @return True unless a failure occurred, in which case we will have 
already
+        * called onFailure() with an appropriate error.
+        */
+       private boolean closeBinaryBlobStream() {
+               if(binaryBlobBucket == null) return true;
+               synchronized(binaryBlobKeysAddedAlready) {
+                       try {
+                               writeBlobHeader(BLOB_END, BLOB_END_VERSION, 0);
+                               binaryBlobStream.close();
+                               return true;
+                       } catch (IOException e) {
+                               Logger.error(this, "Failed to close binary blob 
stream: "+e, e);
+                               onFailure(new 
FetchException(FetchException.BUCKET_ERROR, "Failed to close binary blob 
stream: "+e), null);
+                               return false;
+                       } finally {
+                               binaryBlobStream = null;
+                               binaryBlobKeysAddedAlready.clear();
+                       }
+               }
+       }
+
+       private void writeBlobHeader(short type, short version, int length) 
throws IOException {
+               binaryBlobStream.writeInt(length);
+               binaryBlobStream.writeShort(type);
+               binaryBlobStream.writeShort(version);
+       }
+       
+       boolean collectingBinaryBlob() {
+               return binaryBlobBucket != null;
+       }
+}
\ No newline at end of file

Modified: trunk/freenet/src/freenet/client/async/SimpleSingleFileFetcher.java
===================================================================
--- trunk/freenet/src/freenet/client/async/SimpleSingleFileFetcher.java 
2007-05-23 22:40:31 UTC (rev 13347)
+++ trunk/freenet/src/freenet/client/async/SimpleSingleFileFetcher.java 
2007-05-23 23:08:25 UTC (rev 13348)
@@ -113,6 +113,8 @@
        }

        public void onSuccess(ClientKeyBlock block, boolean fromStore, int 
reqTokenIgnored) {
+               if(parent instanceof ClientGetter)
+                       ((ClientGetter)parent).addKeyToBinaryBlob(block);
                Bucket data = extract(block);
                if(data == null) return; // failed
                if(!block.isMetadata()) {

Modified: trunk/freenet/src/freenet/client/async/SingleFileFetcher.java
===================================================================
--- trunk/freenet/src/freenet/client/async/SingleFileFetcher.java       
2007-05-23 22:40:31 UTC (rev 13347)
+++ trunk/freenet/src/freenet/client/async/SingleFileFetcher.java       
2007-05-23 23:08:25 UTC (rev 13348)
@@ -116,6 +116,8 @@
        // Process the completed data. May result in us going to a
        // splitfile, or another SingleFileFetcher, etc.
        public void onSuccess(ClientKeyBlock block, boolean fromStore, int 
token) {
+               if(parent instanceof ClientGetter)
+                       ((ClientGetter)parent).addKeyToBinaryBlob(block);
                parent.completedBlock(fromStore);
                // Extract data


Modified: trunk/freenet/src/freenet/client/async/SplitFileFetcherSegment.java
===================================================================
--- trunk/freenet/src/freenet/client/async/SplitFileFetcherSegment.java 
2007-05-23 22:40:31 UTC (rev 13347)
+++ trunk/freenet/src/freenet/client/async/SplitFileFetcherSegment.java 
2007-05-23 23:08:25 UTC (rev 13348)
@@ -18,7 +18,10 @@
 import freenet.client.SplitfileBlock;
 import freenet.client.FECCodec.StandardOnionFECCodecEncoderCallback;
 import freenet.keys.CHKBlock;
+import freenet.keys.CHKEncodeException;
 import freenet.keys.ClientCHK;
+import freenet.keys.ClientCHKBlock;
+import freenet.keys.ClientKeyBlock;
 import freenet.support.Logger;
 import freenet.support.api.Bucket;
 import freenet.support.io.BucketTools;
@@ -140,9 +143,11 @@
                return fatallyFailedBlocks;
        }

-       public void onSuccess(Bucket data, int blockNo, boolean dontNotify, 
SplitFileFetcherSubSegment seg) {
+       public void onSuccess(Bucket data, int blockNo, boolean dontNotify, 
SplitFileFetcherSubSegment seg, ClientKeyBlock block) {
                boolean decodeNow = false;
                logMINOR = Logger.shouldLog(Logger.MINOR, this);
+               if(parentFetcher.parent instanceof ClientGetter)
+                       
((ClientGetter)parentFetcher.parent).addKeyToBinaryBlob(block);
                synchronized(this) {
                        if(isFinished()) return;
                        if(blockNo < dataKeys.length) {
@@ -237,14 +242,16 @@
                }
        }

-       public void onEncodedSegment() {                
+       public void onEncodedSegment() {
                // Now insert *ALL* blocks on which we had at least one 
failure, and didn't eventually succeed
                for(int i=0;i<dataBuckets.length;i++) {
                        boolean heal = false;
+                       Bucket data = dataBuckets[i].getData();
+                       maybeAddToBinaryBlob(data, i, false);
                        if(dataRetries[i] > 0)
                                heal = true;
                        if(heal) {
-                               queueHeal(dataBuckets[i].getData());
+                               queueHeal(data);
                        } else {
                                dataBuckets[i].data.free();
                                dataBuckets[i].data = null;
@@ -254,6 +261,8 @@
                }
                for(int i=0;i<checkBuckets.length;i++) {
                        boolean heal = false;
+                       Bucket data = dataBuckets[i].getData();
+                       maybeAddToBinaryBlob(data, i, true);
                        if(checkRetries[i] > 0)
                                heal = true;
                        if(heal) {
@@ -266,6 +275,26 @@
                }
        }

+       private void maybeAddToBinaryBlob(Bucket data, int i, boolean check) {
+               if(parentFetcher.parent instanceof ClientGetter) {
+                       ClientGetter getter = (ClientGetter) 
(parentFetcher.parent);
+                       if(getter.collectingBinaryBlob()) {
+                               try {
+                                       ClientCHKBlock block =
+                                               ClientCHKBlock.encode(data, 
false, true, (short)-1, data.size());
+                                       getter.addKeyToBinaryBlob(block);
+                               } catch (CHKEncodeException e) {
+                                       Logger.error(this, "Failed to encode 
(collecting binary blob) "+(check?"check":"data")+" block "+i+": "+e, e);
+                                       fail(new 
FetchException(FetchException.INTERNAL_ERROR, "Failed to encode for binary 
blob: "+e));
+                                       return;
+                               } catch (IOException e) {
+                                       fail(new 
FetchException(FetchException.BUCKET_ERROR, "Failed to encode for binary blob: 
"+e));
+                                       return;
+                               }
+                       }
+               }
+       }
+
        private void queueHeal(Bucket data) {
                if(logMINOR) Logger.minor(this, "Queueing healing insert");
                fetchContext.healingQueue.queue(data);

Modified: trunk/freenet/src/freenet/client/async/SplitFileFetcherSubSegment.java
===================================================================
--- trunk/freenet/src/freenet/client/async/SplitFileFetcherSubSegment.java      
2007-05-23 22:40:31 UTC (rev 13347)
+++ trunk/freenet/src/freenet/client/async/SplitFileFetcherSubSegment.java      
2007-05-23 23:08:25 UTC (rev 13348)
@@ -158,19 +158,19 @@
                        }
                }
                if(!block.isMetadata()) {
-                       onSuccess(data, fromStore, token);
+                       onSuccess(data, fromStore, token, block);
                } else {
                        onFailure(new 
FetchException(FetchException.INVALID_METADATA, "Metadata where expected 
data"), token);
                }
        }

-       protected void onSuccess(Bucket data, boolean fromStore, int blockNo) {
+       protected void onSuccess(Bucket data, boolean fromStore, int blockNo, 
ClientKeyBlock block) {
                if(parent.isCancelled()) {
                        data.free();
                        onFailure(new FetchException(FetchException.CANCELLED), 
blockNo);
                        return;
                }
-               segment.onSuccess(data, blockNo, fromStore, this);
+               segment.onSuccess(data, blockNo, fromStore, this, block);
        }

        /** Convert a ClientKeyBlock to a Bucket. If an error occurs, report it 
via onFailure

Modified: trunk/freenet/src/freenet/clients/http/NinjaSpider.java
===================================================================
--- trunk/freenet/src/freenet/clients/http/NinjaSpider.java     2007-05-23 
22:40:31 UTC (rev 13347)
+++ trunk/freenet/src/freenet/clients/http/NinjaSpider.java     2007-05-23 
23:08:25 UTC (rev 13348)
@@ -174,7 +174,7 @@
        }

        private ClientGetter makeGetter(FreenetURI uri) {
-               ClientGetter g = new ClientGetter(this, 
core.requestStarters.chkFetchScheduler, core.requestStarters.sskFetchScheduler, 
uri, ctx, PRIORITY_CLASS, this, null);
+               ClientGetter g = new ClientGetter(this, 
core.requestStarters.chkFetchScheduler, core.requestStarters.sskFetchScheduler, 
uri, ctx, PRIORITY_CLASS, this, null, null);
                return g;
        }


Modified: trunk/freenet/src/freenet/clients/http/Spider.java
===================================================================
--- trunk/freenet/src/freenet/clients/http/Spider.java  2007-05-23 22:40:31 UTC 
(rev 13347)
+++ trunk/freenet/src/freenet/clients/http/Spider.java  2007-05-23 23:08:25 UTC 
(rev 13348)
@@ -122,7 +122,7 @@
        }

        private ClientGetter makeGetter(FreenetURI uri) {
-               ClientGetter g = new ClientGetter(this, 
core.requestStarters.chkFetchScheduler, core.requestStarters.sskFetchScheduler, 
uri, ctx, PRIORITY_CLASS, this, null);
+               ClientGetter g = new ClientGetter(this, 
core.requestStarters.chkFetchScheduler, core.requestStarters.sskFetchScheduler, 
uri, ctx, PRIORITY_CLASS, this, null, null);
                return g;
        }


Modified: trunk/freenet/src/freenet/keys/CHKBlock.java
===================================================================
--- trunk/freenet/src/freenet/keys/CHKBlock.java        2007-05-23 22:40:31 UTC 
(rev 13347)
+++ trunk/freenet/src/freenet/keys/CHKBlock.java        2007-05-23 23:08:25 UTC 
(rev 13348)
@@ -105,4 +105,8 @@
        public byte[] getRawData() {
                return data;
        }
+
+       public byte[] getPubkeyBytes() {
+               return null;
+       }
 }

Modified: trunk/freenet/src/freenet/keys/KeyBlock.java
===================================================================
--- trunk/freenet/src/freenet/keys/KeyBlock.java        2007-05-23 22:40:31 UTC 
(rev 13347)
+++ trunk/freenet/src/freenet/keys/KeyBlock.java        2007-05-23 23:08:25 UTC 
(rev 13348)
@@ -13,5 +13,6 @@
     public Key getKey();
     public byte[] getRawHeaders();
     public byte[] getRawData();
+       public byte[] getPubkeyBytes();

 }

Modified: trunk/freenet/src/freenet/keys/SSKBlock.java
===================================================================
--- trunk/freenet/src/freenet/keys/SSKBlock.java        2007-05-23 22:40:31 UTC 
(rev 13347)
+++ trunk/freenet/src/freenet/keys/SSKBlock.java        2007-05-23 23:08:25 UTC 
(rev 13348)
@@ -163,4 +163,8 @@
                return pubKey;
        }

+       public byte[] getPubkeyBytes() {
+               return pubKey.asBytes();
+       }
+
 }

Modified: trunk/freenet/src/freenet/node/fcp/ClientGet.java
===================================================================
--- trunk/freenet/src/freenet/node/fcp/ClientGet.java   2007-05-23 22:40:31 UTC 
(rev 13347)
+++ trunk/freenet/src/freenet/node/fcp/ClientGet.java   2007-05-23 23:08:25 UTC 
(rev 13348)
@@ -41,6 +41,7 @@
        private final File tempFile;
        /** Bucket passed in to the ClientGetter to return data in. Null unless 
returntype=disk */
        private Bucket returnBucket;
+       private final boolean binaryBlob;

        // Verbosity bitmasks
        private int VERBOSITY_SPLITFILE_PROGRESS = 1;
@@ -86,6 +87,7 @@
                fctx.maxTempLength = maxOutputLength;
                Bucket ret = null;
                this.returnType = returnType;
+               binaryBlob = false;
                if(returnType == ClientGetMessage.RETURN_TYPE_DISK) {
                        this.targetFile = returnFilename;
                        this.tempFile = returnTempFilename;
@@ -119,14 +121,13 @@
                                ret.free();
                                throw e;
                        }
-               getter = new ClientGetter(this, 
client.core.requestStarters.chkFetchScheduler, 
client.core.requestStarters.sskFetchScheduler, uri, fctx, priorityClass, 
client.lowLevelClient, returnBucket);
+               getter = new ClientGetter(this, 
client.core.requestStarters.chkFetchScheduler, 
client.core.requestStarters.sskFetchScheduler, uri, fctx, priorityClass, 
client.lowLevelClient, returnBucket, null);
                if(persistenceType != PERSIST_CONNECTION) {
                        FCPMessage msg = persistentTagMessage();
                        client.queueClientRequestMessage(msg, 0);
                }
        }

-
        public ClientGet(FCPConnectionHandler handler, ClientGetMessage 
message) throws IdentifierCollisionException, MessageInvalidException {
                super(message.uri, message.identifier, message.verbosity, 
handler, message.priorityClass,
                                message.persistenceType, message.clientToken, 
message.global);
@@ -144,6 +145,7 @@
                fctx.maxOutputLength = message.maxSize;
                fctx.maxTempLength = message.maxTempSize;
                this.returnType = message.returnType;
+               this.binaryBlob = message.binaryBlob;
                Bucket ret = null;
                if(returnType == ClientGetMessage.RETURN_TYPE_DISK) {
                        this.targetFile = message.diskFile;
@@ -180,7 +182,10 @@
                                ret.free();
                                throw e;
                        }
-               getter = new ClientGetter(this, 
client.core.requestStarters.chkFetchScheduler, 
client.core.requestStarters.sskFetchScheduler, uri, fctx, priorityClass, 
client.lowLevelClient, returnBucket);
+               getter = new ClientGetter(this, 
client.core.requestStarters.chkFetchScheduler, 
+                               client.core.requestStarters.sskFetchScheduler, 
uri, fctx, priorityClass, 
+                               client.lowLevelClient, binaryBlob ? new 
NullBucket() : returnBucket, 
+                                               binaryBlob ? returnBucket : 
null);
                if(persistenceType != PERSIST_CONNECTION) {
                        FCPMessage msg = persistentTagMessage();
                        client.queueClientRequestMessage(msg, 0);
@@ -219,6 +224,7 @@
                fctx.ignoreStore = ignoreDS;
                fctx.maxNonSplitfileRetries = maxRetries;
                fctx.maxSplitfileBlockRetries = maxRetries;
+               binaryBlob = Fields.stringToBool(fs.get("BinaryBlob"), false);
                succeeded = Fields.stringToBool(fs.get("Succeeded"), false);
                if(finished) {
                        if(succeeded) {
@@ -260,7 +266,11 @@
                }
                returnBucket = ret;

-               getter = new ClientGetter(this, 
client.core.requestStarters.chkFetchScheduler, 
client.core.requestStarters.sskFetchScheduler, uri, fctx, priorityClass, 
client.lowLevelClient, returnBucket);
+               getter = new ClientGetter(this, 
client.core.requestStarters.chkFetchScheduler, 
+                               client.core.requestStarters.sskFetchScheduler, 
uri, 
+                               fctx, priorityClass, client.lowLevelClient, 
+                               binaryBlob ? new NullBucket() : returnBucket, 
+                               binaryBlob ? returnBucket : null);

                if(persistenceType != PERSIST_CONNECTION) {
                        FCPMessage msg = persistentTagMessage();
@@ -310,8 +320,12 @@
        public void onSuccess(FetchResult result, ClientGetter state) {
                Logger.minor(this, "Succeeded: "+identifier);
                Bucket data = result.asBucket();
-               if(returnBucket != data)
+               if(returnBucket != data && !binaryBlob) {
                        Logger.error(this, "returnBucket = "+returnBucket+" but 
onSuccess() data = "+data);
+                       // Caller guarantees that data == returnBucket
+                       onFailure(new 
FetchException(FetchException.INTERNAL_ERROR, "Data != returnBucket"), null);
+                       return;
+               }
                boolean dontFree = false;
                // FIXME I don't think this is a problem in this case...? (Disk 
write while locked..)
                AllDataMessage adm = null;
@@ -323,7 +337,7 @@
                        if(returnType == ClientGetMessage.RETURN_TYPE_DIRECT) {
                                // Send all the data at once
                                // FIXME there should be other options
-                               adm = new AllDataMessage(data, identifier, 
global);
+                               adm = new AllDataMessage(returnBucket, 
identifier, global);
                                if(persistenceType == PERSIST_CONNECTION)
                                        adm.setFreeOnSent();
                                dontFree = true;
@@ -335,17 +349,11 @@
                                // Write to temp file, then rename over filename
                                FileOutputStream fos = null;
                                boolean closed = false;
-                                       // Caller guarantees that data == 
returnBucket
-                                       if(data != returnBucket) {
-                                               Logger.error(this, "Data != 
returnBucket for "+this);
-                                               onFailure(new 
FetchException(FetchException.INTERNAL_ERROR, "Data != returnBucket"), null);
-                                               return;
-                                       }
-                                       if(!tempFile.renameTo(targetFile)) {
-                                               postFetchProtocolErrorMessage = 
new ProtocolErrorMessage(ProtocolErrorMessage.COULD_NOT_RENAME_FILE, false, 
null, identifier, global);
-                                               // Don't delete temp file, user 
might want it.
-                                       }
-                                       returnBucket = new 
FileBucket(targetFile, false, true, false, false, false);
+                               if(!tempFile.renameTo(targetFile)) {
+                                       postFetchProtocolErrorMessage = new 
ProtocolErrorMessage(ProtocolErrorMessage.COULD_NOT_RENAME_FILE, false, null, 
identifier, global);
+                                       // Don't delete temp file, user might 
want it.
+                               }
+                               returnBucket = new FileBucket(targetFile, 
false, true, false, false, false);
                                try {
                                        if((fos != null) && !closed)
                                                fos.close();
@@ -354,8 +362,11 @@
                                }
                        }
                        progressPending = null;
-                       this.foundDataLength = data.size();
-                       this.foundDataMimeType = result.getMimeType();
+                       this.foundDataLength = returnBucket.size();
+                       if(!binaryBlob)
+                               this.foundDataMimeType = result.getMimeType();
+                       else
+                               this.foundDataMimeType = 
"application/x-freenet-binary-blob";
                        this.succeeded = true;
                        finished = true;
                }
@@ -533,6 +544,7 @@
                        bucketToFS(fs, "ReturnBucket", false, returnBucket);
                }
                fs.putSingle("Global", Boolean.toString(client.isGlobalQueue));
+               fs.put("BinaryBlob", binaryBlob);
                return fs;
        }


Modified: trunk/freenet/src/freenet/node/fcp/ClientGetMessage.java
===================================================================
--- trunk/freenet/src/freenet/node/fcp/ClientGetMessage.java    2007-05-23 
22:40:31 UTC (rev 13347)
+++ trunk/freenet/src/freenet/node/fcp/ClientGetMessage.java    2007-05-23 
23:08:25 UTC (rev 13348)
@@ -54,6 +54,7 @@
        final File tempFile;
        final String clientToken;
        final boolean global;
+       final boolean binaryBlob;

        // FIXME move these to the actual getter process
        static final short RETURN_TYPE_DIRECT = 0; // over FCP
@@ -189,6 +190,7 @@
                if(global && (persistenceType == 
ClientRequest.PERSIST_CONNECTION)) {
                        throw new 
MessageInvalidException(ProtocolErrorMessage.NOT_SUPPORTED, "Global requests 
must be persistent", identifier, global);
                }
+               binaryBlob = Fields.stringToBool(fs.get("BinaryBlob"), false);
        }

        public SimpleFieldSet getFieldSet() {
@@ -201,6 +203,7 @@
                fs.putSingle("MaxSize", Long.toString(maxSize));
                fs.putSingle("MaxTempSize", Long.toString(maxTempSize));
                fs.putSingle("MaxRetries", Integer.toString(maxRetries));
+               fs.put("BinaryBlob", binaryBlob);
                return fs;
        }


Modified: trunk/freenet/src/freenet/node/updater/NodeUpdater.java
===================================================================
--- trunk/freenet/src/freenet/node/updater/NodeUpdater.java     2007-05-23 
22:40:31 UTC (rev 13347)
+++ trunk/freenet/src/freenet/node/updater/NodeUpdater.java     2007-05-23 
23:08:25 UTC (rev 13348)
@@ -117,7 +117,7 @@
                                        System.err.println("Starting 
"+(extUpdate?"freenet-ext.jar ":"")+"fetch for "+availableVersion);
                                        cg = new ClientGetter(this, 
core.requestStarters.chkFetchScheduler, core.requestStarters.sskFetchScheduler, 
                                                        
URI.setSuggestedEdition(availableVersion), ctx, 
RequestStarter.UPDATE_PRIORITY_CLASS, 
-                                                       this, new 
ArrayBucket());
+                                                       this, new 
ArrayBucket(), null);
                                        toStart = cg;
                                }
                                isFetching = true;

Modified: trunk/freenet/src/freenet/node/updater/RevocationChecker.java
===================================================================
--- trunk/freenet/src/freenet/node/updater/RevocationChecker.java       
2007-05-23 22:40:31 UTC (rev 13347)
+++ trunk/freenet/src/freenet/node/updater/RevocationChecker.java       
2007-05-23 23:08:25 UTC (rev 13348)
@@ -85,7 +85,7 @@
                                        cg = revocationGetter = new 
ClientGetter(this, core.requestStarters.chkFetchScheduler, 
                                                        
core.requestStarters.sskFetchScheduler, manager.revocationURI, ctxRevocation, 
                                                        aggressive ? 
RequestStarter.MAXIMUM_PRIORITY_CLASS : 
RequestStarter.IMMEDIATE_SPLITFILE_PRIORITY_CLASS, 
-                                                       this, null);
+                                                       this, null, null);
                                        if(logMINOR) Logger.minor(this, "Queued 
another revocation fetcher");
                                }
                        }


Reply via email to