Author: toad
Date: 2005-10-24 17:08:08 +0000 (Mon, 24 Oct 2005)
New Revision: 7450
Added:
trunk/freenet/src/freenet/keys/KeyDecodeException.java
Modified:
trunk/freenet/src/freenet/client/ArchiveElement.java
trunk/freenet/src/freenet/client/ArchiveFailureException.java
trunk/freenet/src/freenet/client/ArchiveHandler.java
trunk/freenet/src/freenet/client/ArchiveManager.java
trunk/freenet/src/freenet/client/ArchiveRestartException.java
trunk/freenet/src/freenet/client/FetchException.java
trunk/freenet/src/freenet/client/Fetcher.java
trunk/freenet/src/freenet/client/FetcherContext.java
trunk/freenet/src/freenet/client/HighLevelSimpleClientImpl.java
trunk/freenet/src/freenet/client/Metadata.java
trunk/freenet/src/freenet/keys/CHKBlock.java
trunk/freenet/src/freenet/keys/CHKDecodeException.java
trunk/freenet/src/freenet/keys/KeyBlock.java
Log:
More work, mostly on archives.
Modified: trunk/freenet/src/freenet/client/ArchiveElement.java
===================================================================
--- trunk/freenet/src/freenet/client/ArchiveElement.java 2005-10-22
20:57:25 UTC (rev 7449)
+++ trunk/freenet/src/freenet/client/ArchiveElement.java 2005-10-24
17:08:08 UTC (rev 7450)
@@ -12,23 +12,26 @@
*/
public class ArchiveElement {
- ArchiveElement(ArchiveManager manager, FreenetURI uri, ClientKey ckey,
String filename) {
+ ArchiveElement(ArchiveManager manager, FreenetURI uri, ClientKey ckey,
String filename, short archiveType) {
this.manager = manager;
this.key = uri;
this.ckey = ckey;
this.filename = filename;
+ this.archiveType = archiveType;
}
final ArchiveManager manager;
final FreenetURI key;
final ClientKey ckey;
final String filename;
+ final short archiveType;
/**
* Fetch the element.
+ * If fetchContext is null, return null unless the data is cached.
* @throws ArchiveFailureException
*/
- public Bucket get(ArchiveContext archiveContext, FetcherContext
fetchContext) throws ArchiveFailureException {
+ public Bucket get(ArchiveContext archiveContext, FetcherContext
fetchContext, boolean inSplitZipManifest) throws ArchiveFailureException {
archiveContext.doLoopDetection(ckey);
// AFTER the loop check (possible deadlocks)
@@ -36,9 +39,13 @@
// Synchronized during I/O to avoid doing it twice
Bucket cached = manager.getCached(key, filename);
if(cached != null) return cached;
+ if(fetchContext == null) return null;
Fetcher fetcher = new Fetcher(key, fetchContext,
archiveContext);
- fetcher.realRun();
- manager.extractToCache(key, archiveContext);
+ FetchResult result =
fetcher.realRun(inSplitZipManifest);
+ if(result.succeeded())
+ manager.extractToCache(key, archiveType,
result.data, archiveContext);
+ else
+ throw new ArchiveFailureException("Fetch
failed");
}
}
}
Modified: trunk/freenet/src/freenet/client/ArchiveFailureException.java
===================================================================
--- trunk/freenet/src/freenet/client/ArchiveFailureException.java
2005-10-22 20:57:25 UTC (rev 7449)
+++ trunk/freenet/src/freenet/client/ArchiveFailureException.java
2005-10-24 17:08:08 UTC (rev 7450)
@@ -1,14 +1,23 @@
package freenet.client;
+import java.io.IOException;
+
/**
* Thrown when an archive operation fails.
*/
public class ArchiveFailureException extends Exception {
+ private static final long serialVersionUID = -5915105120222575469L;
+
public static final String TOO_MANY_LEVELS = "Too many archive levels";
public ArchiveFailureException(String message) {
super(message);
}
+ public ArchiveFailureException(String message, IOException e) {
+ super(message);
+ initCause(e);
+ }
+
}
Modified: trunk/freenet/src/freenet/client/ArchiveHandler.java
===================================================================
--- trunk/freenet/src/freenet/client/ArchiveHandler.java 2005-10-22
20:57:25 UTC (rev 7449)
+++ trunk/freenet/src/freenet/client/ArchiveHandler.java 2005-10-24
17:08:08 UTC (rev 7450)
@@ -10,10 +10,12 @@
private ArchiveManager manager;
private ClientKey key;
+ private short archiveType;
public ArchiveHandler(ArchiveManager manager, ClientKey key, short
archiveType) {
this.manager = manager;
this.key = key;
+ this.archiveType = archiveType;
}
public void finalize() {
@@ -24,17 +26,20 @@
* Get the metadata for this ZIP manifest, as a Bucket.
*/
public Bucket getMetadata(ArchiveContext archiveContext, FetcherContext
fetchContext) throws ArchiveFailureException, ArchiveRestartException {
- return get(".metadata", archiveContext, fetchContext);
+ return get(".metadata", archiveContext, fetchContext, false);
}
/**
* Get a file from this ZIP manifest, as a Bucket.
* If possible, read it from cache. If necessary, refetch the
* container and extract it. If that fails, throw.
+ * @param inSplitZipManifest If true, indicates that the key points to
a splitfile zip manifest,
+ * which means that we need to pass a flag to the fetcher to tell it to
pretend it was a straight
+ * splitfile.
*/
- public synchronized Bucket get(String internalName, ArchiveContext
archiveContext, FetcherContext fetchContext) throws ArchiveFailureException,
ArchiveRestartException {
+ public synchronized Bucket get(String internalName, ArchiveContext
archiveContext, FetcherContext fetchContext, boolean inSplitZipManifest) throws
ArchiveFailureException, ArchiveRestartException {
ArchiveElement element =
- manager.makeElement(key, internalName);
- return element.get(archiveContext, fetchContext);
+ manager.makeElement(key, internalName, archiveType);
+ return element.get(archiveContext, fetchContext,
inSplitZipManifest);
}
}
Modified: trunk/freenet/src/freenet/client/ArchiveManager.java
===================================================================
--- trunk/freenet/src/freenet/client/ArchiveManager.java 2005-10-22
20:57:25 UTC (rev 7449)
+++ trunk/freenet/src/freenet/client/ArchiveManager.java 2005-10-24
17:08:08 UTC (rev 7450)
@@ -1,13 +1,19 @@
package freenet.client;
import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
import java.util.LinkedHashMap;
import java.util.Set;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipInputStream;
import freenet.keys.ClientKey;
import freenet.keys.FreenetURI;
import freenet.support.Bucket;
import freenet.support.LRUHashtable;
+import freenet.support.Logger;
/**
* Cache of recently decoded archives:
@@ -18,14 +24,19 @@
*/
public class ArchiveManager {
- ArchiveManager(int maxHandlers, long maxCachedData, File cacheDir) {
+ ArchiveManager(int maxHandlers, long maxCachedData, long
maxArchiveSize, long maxArchivedFileSize, File cacheDir) {
maxArchiveHandlers = maxHandlers;
archiveHandlers = new LRUHashtable();
this.maxCachedData = maxCachedData;
this.cacheDir = cacheDir;
storedData = new LRUHashtable();
+ this.maxArchiveSize = maxArchiveSize;
+ this.maxArchivedFileSize = maxArchivedFileSize;
}
+ final long maxArchiveSize;
+ final long maxArchivedFileSize;
+
// ArchiveHandler's
final int maxArchiveHandlers;
@@ -97,7 +108,7 @@
MyKey key;
boolean finalized;
// FIXME implement
-
+
public Bucket dataAsBucket() {
// FIXME implement
}
@@ -108,4 +119,60 @@
}
}
+ /**
+ * Extract data to cache.
+ * @param key The key the data was fetched from.
+ * @param archiveType The archive type. Must be Metadata.ARCHIVE_ZIP.
+ * @param data The actual data fetched.
+ * @param archiveContext The context for the whole fetch process.
+ * @throws ArchiveFailureException
+ */
+ public void extractToCache(FreenetURI key, short archiveType, Bucket
data, ArchiveContext archiveContext) throws ArchiveFailureException {
+ if(data.size() > maxArchiveSize)
+ throw new ArchiveFailureException("Archive too big");
+ if(archiveType != Metadata.ARCHIVE_ZIP)
+ throw new ArchiveFailureException("Unknown or
unsupported archive algorithm "+archiveType);
+ InputStream is = null;
+ try {
+ is = data.getInputStream();
+ ZipInputStream zis = new ZipInputStream(is);
+ ZipEntry entry = zis.getNextEntry();
+ byte[] buf = new byte[4096];
+outer: while(entry != null) {
+ entry = zis.getNextEntry();
+ String name = entry.getName();
+ long size = entry.getSize();
+ if(size > maxArchivedFileSize) {
+ addErrorElement(key, name);
+ } else {
+ // Read the element
+ long realLen = 0;
+ Bucket output =
makeTempStoreBucket(size);
+ OutputStream out =
output.getOutputStream();
+ int readBytes;
+inner: while((readBytes = zis.read(buf)) > 0) {
+ out.write(buf, 0, readBytes);
+ readBytes += realLen;
+ if(readBytes >
maxArchivedFileSize) {
+ addErrorElement(key,
name);
+ out.close();
+
dumpTempStoreBucket(output);
+ continue outer;
+ }
+ }
+ out.close();
+ addStoreElement(key, name, output);
+ }
+ }
+ } catch (IOException e) {
+ throw new ArchiveFailureException("Error reading
archive: "+e.getMessage(), e);
+ } finally {
+ if(is != null)
+ try {
+ is.close();
+ } catch (IOException e) {
+ Logger.error(this, "Failed to close
stream: "+e, e);
+ }
+ }
+ }
}
Modified: trunk/freenet/src/freenet/client/ArchiveRestartException.java
===================================================================
--- trunk/freenet/src/freenet/client/ArchiveRestartException.java
2005-10-22 20:57:25 UTC (rev 7449)
+++ trunk/freenet/src/freenet/client/ArchiveRestartException.java
2005-10-24 17:08:08 UTC (rev 7450)
@@ -7,4 +7,8 @@
*/
public class ArchiveRestartException extends Exception {
+ public ArchiveRestartException(String msg) {
+ super(msg);
+ }
+
}
Modified: trunk/freenet/src/freenet/client/FetchException.java
===================================================================
--- trunk/freenet/src/freenet/client/FetchException.java 2005-10-22
20:57:25 UTC (rev 7449)
+++ trunk/freenet/src/freenet/client/FetchException.java 2005-10-24
17:08:08 UTC (rev 7450)
@@ -30,5 +30,10 @@
static final int INVALID_METADATA = 4;
/** Got an ArchiveFailureException */
static final int ARCHIVE_FAILURE = 5;
-
+ /** Failed to decode a block */
+ static final int BLOCK_DECODE_ERROR = 6;
+ /** Too many split metadata levels */
+ static final int TOO_MANY_METADATA_LEVELS = 7;
+ /** Too many archive restarts */
+ static final int TOO_MANY_ARCHIVE_RESTARTS = 8;
}
Modified: trunk/freenet/src/freenet/client/Fetcher.java
===================================================================
--- trunk/freenet/src/freenet/client/Fetcher.java 2005-10-22 20:57:25 UTC
(rev 7449)
+++ trunk/freenet/src/freenet/client/Fetcher.java 2005-10-24 17:08:08 UTC
(rev 7450)
@@ -5,6 +5,7 @@
import freenet.keys.ClientKey;
import freenet.keys.FreenetURI;
import freenet.keys.KeyBlock;
+import freenet.keys.KeyDecodeException;
import freenet.support.Bucket;
import freenet.support.Logger;
@@ -15,7 +16,7 @@
final FreenetURI origURI;
final FetcherContext ctx;
- final ArchiveContext archiveContext;
+ ArchiveContext archiveContext;
public Fetcher(FreenetURI uri, FetcherContext ctx, ArchiveContext
archiveContext) {
this.origURI = uri;
@@ -24,10 +25,11 @@
}
public FetchResult run() throws FetchException {
- while(true) {
+ for(int i=0;i<ctx.maxArchiveRestarts;i++) {
try {
- return realRun();
+ return realRun(false);
} catch (ArchiveRestartException e) {
+ archiveContext = new ArchiveContext();
continue;
} catch (MetadataParseException e) {
throw new FetchException(e);
@@ -37,16 +39,18 @@
throw new FetchException(e);
}
}
+ throw new
FetchException(FetchException.TOO_MANY_ARCHIVE_RESTARTS);
}
/**
* Run the actual fetch.
+ * @param overrideZipManifest
* @return The result of the fetch - successful or not.
* @throws FetchException
* @throws MetadataParseException
* @throws ArchiveFailureException
*/
- public FetchResult realRun() throws FetchException,
ArchiveRestartException, MetadataParseException, ArchiveFailureException {
+ public FetchResult realRun(boolean overrideZipManifest) throws
FetchException, ArchiveRestartException, MetadataParseException,
ArchiveFailureException {
FreenetURI uri = origURI;
ClientKey key = ClientKey.get(origURI);
ClientMetadata dm = new ClientMetadata();
@@ -59,7 +63,12 @@
// Fetch the first key
KeyBlock block = ctx.client.getKey(key);
- byte[] data = block.decode(key);
+ byte[] data;
+ try {
+ data = block.decode(key);
+ } catch (KeyDecodeException e1) {
+ throw new
FetchException(FetchException.BLOCK_DECODE_ERROR);
+ }
if(!key.isMetadata()) {
// Just return the data
@@ -74,8 +83,17 @@
// This will throw if it finds an error, including
semi-errors
// such as too-big-indirect-metadata
Metadata metadata = Metadata.construct(data);
+ if(overrideZipManifest) {
+ if(metadata.isArchiveManifest())
+ metadata.setSimpleRedirect();
+ else
+ throw new
ArchiveRestartException("Override zip manifest set but not a zip manifest!");
+ }
while(true) {
+
+ /** Is set false every time we get a new key. */
+ boolean inSplitZipManifest = false;
if(metadata == null && key != null) {
// Try next key
@@ -114,11 +132,23 @@
*
* Now, retreive the data
*/
- Bucket result =
zip.get(metadata.getZIPInternalName(), archiveContext, ctx);
+ Bucket result =
zip.get(metadata.getZIPInternalName(), archiveContext, ctx, inSplitZipManifest);
dm.mergeNoOverwrite(metadata.getClientMetadata());
return new FetchResult(dm, result);
} else if(metadata.isSplitfile()) {
+ if(metadata.isArchiveManifest()) {
+ // Check the cache first
+ zip =
ctx.archiveManager.makeHandler(key, metadata.getArchiveType());
+ // Future
ArchiveInternalRedirects will point to *self*
+ inSplitZipManifest = true;
+ Bucket metadataBucket =
zip.getMetadata(archiveContext, null);
+ if(metadataBucket != null) {
+ metadata =
Metadata.construct(metadataBucket);
+ continue;
+ }
+ }
+
int j;
for(j=0;j<ctx.maxLevels;j++) {
SplitFetcher sf = new
SplitFetcher(metadata, ctx.maxTempLength, archiveContext, ctx);
@@ -131,7 +161,8 @@
if(!metadata.isMultiLevelMetadata())
break; // try
the new metadata
} else
if(metadata.isArchiveManifest()) {
- zip =
ctx.archiveManager.makeHandler(key, metadata.getArchiveType());
+ // Use the new metadata
+ // ZIP points to
current key
Bucket metadataBucket =
zip.getMetadata(archiveContext, ctx);
metadata =
Metadata.construct(metadataBucket);
break;
@@ -140,6 +171,7 @@
}
} // loop (splitfile levels)
if(j>=ctx.maxLevels) {
+ throw new
FetchException(FetchException.TOO_MANY_METADATA_LEVELS);
// Too many levels
// FIXME: throw something
}
Modified: trunk/freenet/src/freenet/client/FetcherContext.java
===================================================================
--- trunk/freenet/src/freenet/client/FetcherContext.java 2005-10-22
20:57:25 UTC (rev 7449)
+++ trunk/freenet/src/freenet/client/FetcherContext.java 2005-10-24
17:08:08 UTC (rev 7450)
@@ -14,16 +14,19 @@
final int maxArchiveRecursionLevel;
final ArchiveManager archiveManager;
final BucketFactory bucketFactory;
+ final int maxArchiveRestarts;
public FetcherContext(SimpleLowLevelClient client, long curMaxLength,
- long curMaxTempLength, int maxRedirects, int maxLevels,
int maxArchives,
- ArchiveManager archiveManager, BucketFactory
bucketFactory) {
+ long curMaxTempLength, int maxRedirects, int maxLevels,
int maxArchives,
+ int maxArchiveRestarts, ArchiveManager archiveManager,
+ BucketFactory bucketFactory) {
this.client = client;
this.maxOutputLength = curMaxLength;
this.maxTempLength = curMaxTempLength;
this.maxRedirects = maxRedirects;
this.maxLevels = maxLevels;
this.maxArchiveRecursionLevel = maxArchives;
+ this.maxArchiveRestarts = maxArchiveRestarts;
this.archiveManager = archiveManager;
this.bucketFactory = bucketFactory;
}
Modified: trunk/freenet/src/freenet/client/HighLevelSimpleClientImpl.java
===================================================================
--- trunk/freenet/src/freenet/client/HighLevelSimpleClientImpl.java
2005-10-22 20:57:25 UTC (rev 7449)
+++ trunk/freenet/src/freenet/client/HighLevelSimpleClientImpl.java
2005-10-24 17:08:08 UTC (rev 7450)
@@ -11,9 +11,10 @@
private final BucketFactory bucketFactory;
private long curMaxLength;
private long curMaxTempLength;
- public static final int MAX_REDIRECTS = 10;
- public static final int MAX_METADATA_LEVELS = 5;
- public static final int MAX_ARCHIVE_LEVELS = 5;
+ static final int MAX_REDIRECTS = 10;
+ static final int MAX_METADATA_LEVELS = 5;
+ static final int MAX_ARCHIVE_LEVELS = 5;
+ static final int MAX_ARCHIVE_RESTARTS = 2;
public HighLevelSimpleClientImpl(SimpleLowLevelClient client,
ArchiveManager mgr, BucketFactory bf) {
this.client = client;
@@ -31,7 +32,7 @@
public FetchResult fetch(FreenetURI uri) throws FetchException {
FetcherContext context = new FetcherContext(client,
curMaxLength, curMaxLength,
- MAX_REDIRECTS, MAX_METADATA_LEVELS,
MAX_ARCHIVE_LEVELS, archiveManager, bucketFactory);
+ MAX_REDIRECTS, MAX_METADATA_LEVELS,
MAX_ARCHIVE_LEVELS, MAX_ARCHIVE_RESTARTS, archiveManager, bucketFactory);
Fetcher f = new Fetcher(uri, context, new ArchiveContext());
return f.run();
}
Modified: trunk/freenet/src/freenet/client/Metadata.java
===================================================================
--- trunk/freenet/src/freenet/client/Metadata.java 2005-10-22 20:57:25 UTC
(rev 7449)
+++ trunk/freenet/src/freenet/client/Metadata.java 2005-10-24 17:08:08 UTC
(rev 7450)
@@ -405,4 +405,11 @@
public short getArchiveType() {
return archiveType;
}
+
+ /** Change the document type to a simple redirect. Used by the archive
code
+ * to fetch split ZIP manifests.
+ */
+ public void setSimpleRedirect() {
+ documentType = SIMPLE_REDIRECT;
+ }
}
Modified: trunk/freenet/src/freenet/keys/CHKBlock.java
===================================================================
--- trunk/freenet/src/freenet/keys/CHKBlock.java 2005-10-22 20:57:25 UTC
(rev 7449)
+++ trunk/freenet/src/freenet/keys/CHKBlock.java 2005-10-24 17:08:08 UTC
(rev 7450)
@@ -79,6 +79,12 @@
// Otherwise it checks out
}
+ public byte[] decode(ClientKey key) throws KeyDecodeException {
+ if(!(key instanceof ClientCHK))
+ throw new KeyDecodeException("Not a CHK!: "+key);
+ return decode((ClientCHK)key);
+ }
+
/**
* Decode the CHK and recover the original data
* @return the original data
Modified: trunk/freenet/src/freenet/keys/CHKDecodeException.java
===================================================================
--- trunk/freenet/src/freenet/keys/CHKDecodeException.java 2005-10-22
20:57:25 UTC (rev 7449)
+++ trunk/freenet/src/freenet/keys/CHKDecodeException.java 2005-10-24
17:08:08 UTC (rev 7450)
@@ -5,7 +5,7 @@
*
* Exception thrown when decode fails.
*/
-public class CHKDecodeException extends Exception {
+public class CHKDecodeException extends KeyDecodeException {
/**
*
Modified: trunk/freenet/src/freenet/keys/KeyBlock.java
===================================================================
--- trunk/freenet/src/freenet/keys/KeyBlock.java 2005-10-22 20:57:25 UTC
(rev 7449)
+++ trunk/freenet/src/freenet/keys/KeyBlock.java 2005-10-24 17:08:08 UTC
(rev 7450)
@@ -6,6 +6,6 @@
public interface KeyBlock {
/** Decode with the key */
- byte[] decode(ClientKey key);
+ byte[] decode(ClientKey key) throws KeyDecodeException;
}
Added: trunk/freenet/src/freenet/keys/KeyDecodeException.java
===================================================================
--- trunk/freenet/src/freenet/keys/KeyDecodeException.java 2005-10-22
20:57:25 UTC (rev 7449)
+++ trunk/freenet/src/freenet/keys/KeyDecodeException.java 2005-10-24
17:08:08 UTC (rev 7450)
@@ -0,0 +1,24 @@
+package freenet.keys;
+
+/**
+ * Base class for decode exceptions.
+ */
+public class KeyDecodeException extends Exception {
+
+ public KeyDecodeException(String message) {
+ super(message);
+ }
+
+ public KeyDecodeException() {
+ super();
+ }
+
+ public KeyDecodeException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+ public KeyDecodeException(Throwable cause) {
+ super(cause);
+ }
+
+}
_______________________________________________
cvs mailing list
[email protected]
http://emu.freenetproject.org/cgi-bin/mailman/listinfo/cvs