Rhizome Java API: negative fetch tests

This commit is contained in:
Andrew Bettison 2014-07-04 17:48:40 +09:30
parent 2aec8f31a4
commit 3715c5bf0b
11 changed files with 548 additions and 129 deletions

View File

@ -1814,6 +1814,7 @@ static const char *httpResultString(int response_code)
switch (response_code) {
case 200: return "OK";
case 201: return "Created";
case 204: return "No Content";
case 206: return "Partial Content";
case 400: return "Bad Request";
case 401: return "Unauthorized";

View File

@ -21,6 +21,9 @@
package org.servalproject.servaldna.rhizome;
import java.lang.StringBuilder;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.InvocationTargetException;
import java.util.Map;
import java.util.List;
@ -45,6 +48,7 @@ public class RhizomeCommon
{
private static class Status {
InputStream input_stream;
public int http_status_code;
public String http_status_message;
RhizomeBundleStatus bundle_status_code;
@ -53,35 +57,45 @@ public class RhizomeCommon
String payload_status_message;
}
protected static InputStream receiveResponse(HttpURLConnection conn, int expected_response_code) throws IOException, ServalDInterfaceException, RhizomeException
protected static Status receiveResponse(HttpURLConnection conn, int expected_response_code) throws IOException, ServalDInterfaceException
{
int[] expected_response_codes = { expected_response_code };
return receiveResponse(conn, expected_response_codes);
}
protected static InputStream receiveResponse(HttpURLConnection conn, int[] expected_response_codes) throws IOException, ServalDInterfaceException, RhizomeException
protected static Status receiveResponse(HttpURLConnection conn, int[] expected_response_codes) throws IOException, ServalDInterfaceException
{
Status status = new Status();
status.http_status_code = conn.getResponseCode();
status.http_status_message = conn.getResponseMessage();
for (int code: expected_response_codes) {
if (conn.getResponseCode() == code)
return conn.getInputStream();
if (status.http_status_code == code) {
status.input_stream = conn.getInputStream();
return status;
}
}
if (!conn.getContentType().equals("application/json"))
throw new ServalDInterfaceException("unexpected HTTP Content-Type: " + conn.getContentType());
if (conn.getResponseCode() == HttpURLConnection.HTTP_FORBIDDEN) {
JSONTokeniser json = new JSONTokeniser(new InputStreamReader(conn.getErrorStream(), "US-ASCII"));
Status status = decodeRestfulStatus(json);
throwRestfulResponseExceptions(status, conn.getURL());
throw new ServalDInterfaceException(
"unexpected Rhizome failure, \"" + status.http_status_message + "\""
+ (status.bundle_status_code == null ? "" : ", " + status.bundle_status_code)
+ (status.bundle_status_message == null ? "" : " \"" + status.bundle_status_message + "\"")
+ (status.payload_status_code == null ? "" : ", " + status.payload_status_code)
+ (status.payload_status_message == null ? "" : ", " + status.payload_status_message + "\"")
);
decodeRestfulStatus(status, json);
return status;
}
throw new ServalDInterfaceException("unexpected HTTP response code: " + conn.getResponseCode());
}
protected static void unexpectedResponse(Status status) throws ServalDInterfaceException
{
throw new ServalDInterfaceException(
"unexpected Rhizome failure, \"" + status.http_status_message + "\""
+ (status.bundle_status_code == null ? "" : ", " + status.bundle_status_code)
+ (status.bundle_status_message == null ? "" : " \"" + status.bundle_status_message + "\"")
+ (status.payload_status_code == null ? "" : ", " + status.payload_status_code)
+ (status.payload_status_message == null ? "" : ", " + status.payload_status_message + "\"")
);
}
/*
protected static void throwRestfulResponseExceptions(Status status, URL url) throws RhizomeException, ServalDFailureException
{
if (status.bundle_status_code != null) {
@ -89,11 +103,15 @@ public class RhizomeCommon
case ERROR:
throw new ServalDFailureException("received rhizome_bundle_status_code=ERROR(-1) from " + url);
case NEW:
throw new RhizomeManifestNotFoundException(url);
case SAME:
throw new RhizomeManifestAlreadyStoredException(url);
case DUPLICATE:
throw new RhizomeDuplicateBundleException(url);
case OLD:
throw new RhizomeOutdatedBundleException(url);
case NO_ROOM:
break;
throw new RhizomeStoreFullException(url);
case INVALID:
throw new RhizomeInvalidManifestException(url);
case FAKE:
@ -102,24 +120,8 @@ public class RhizomeCommon
throw new RhizomeInconsistencyException(url);
}
}
if (status.payload_status_code != null) {
switch (status.payload_status_code) {
case ERROR:
throw new ServalDFailureException("received rhizome_payload_status_code=ERROR(-1) from " + url);
case EMPTY:
case NEW:
case STORED:
case TOO_BIG:
case EVICTED:
break;
case WRONG_SIZE:
case WRONG_HASH:
throw new RhizomeInconsistencyException(url);
case CRYPTO_FAIL:
throw new RhizomeDecryptionException(url);
}
}
}
*/
protected static JSONTokeniser receiveRestfulResponse(HttpURLConnection conn, int expected_response_code) throws IOException, ServalDInterfaceException, RhizomeException
{
@ -129,21 +131,38 @@ public class RhizomeCommon
protected static JSONTokeniser receiveRestfulResponse(HttpURLConnection conn, int[] expected_response_codes) throws IOException, ServalDInterfaceException, RhizomeException
{
InputStream in = receiveResponse(conn, expected_response_codes);
Status status = receiveResponse(conn, expected_response_codes);
if (!conn.getContentType().equals("application/json"))
throw new ServalDInterfaceException("unexpected HTTP Content-Type: " + conn.getContentType());
return new JSONTokeniser(new InputStreamReader(in, "US-ASCII"));
return new JSONTokeniser(new InputStreamReader(status.input_stream, "US-ASCII"));
}
protected static Status decodeRestfulStatus(JSONTokeniser json) throws IOException, ServalDInterfaceException
protected static void decodeHeaderBundleStatus(Status status, HttpURLConnection conn) throws ServalDInterfaceException
{
status.bundle_status_code = header(conn, "Serval-Rhizome-Result-Bundle-Status-Code", RhizomeBundleStatus.class);
status.bundle_status_message = headerString(conn, "Serval-Rhizome-Result-Bundle-Status-Message");
}
protected static void decodeHeaderPayloadStatus(Status status, HttpURLConnection conn) throws ServalDInterfaceException
{
status.payload_status_code = header(conn, "Serval-Rhizome-Result-Payload-Status-Code", RhizomePayloadStatus.class);
status.payload_status_message = headerString(conn, "Serval-Rhizome-Result-Payload-Status-Message");
}
protected static void decodeRestfulStatus(Status status, JSONTokeniser json) throws IOException, ServalDInterfaceException
{
try {
Status status = new Status();
json.consume(JSONTokeniser.Token.START_OBJECT);
json.consume("http_status_code");
json.consume(JSONTokeniser.Token.COLON);
status.http_status_code = json.consume(Integer.class);
int hs = json.consume(Integer.class);
json.consume(JSONTokeniser.Token.COMMA);
if (status.http_status_code == 0)
status.http_status_code = json.consume(Integer.class);
else if (hs != status.http_status_code)
throw new ServalDInterfaceException("JSON/header conflict"
+ ", http_status_code=" + hs
+ " but HTTP response code is " + status.http_status_code);
json.consume("http_status_message");
json.consume(JSONTokeniser.Token.COLON);
status.http_status_message = json.consume(String.class);
@ -151,79 +170,185 @@ public class RhizomeCommon
while (tok == JSONTokeniser.Token.COMMA) {
String label = json.consume(String.class);
json.consume(JSONTokeniser.Token.COLON);
if (label.equals("rhizome_bundle_status_code"))
status.bundle_status_code = RhizomeBundleStatus.fromCode(json.consume(Integer.class));
else if (label.equals("rhizome_bundle_status_message"))
status.bundle_status_message = json.consume(String.class);
else if (label.equals("rhizome_payload_status_code"))
status.payload_status_code = RhizomePayloadStatus.fromCode(json.consume(Integer.class));
else if (label.equals("rhizome_payload_status_message"))
status.payload_status_message = json.consume(String.class);
if (label.equals("rhizome_bundle_status_code")) {
RhizomeBundleStatus bs = RhizomeBundleStatus.fromCode(json.consume(Integer.class));
if (status.bundle_status_code == null)
status.bundle_status_code = bs;
else if (status.bundle_status_code != bs)
throw new ServalDInterfaceException("JSON/header conflict"
+ ", rhizome_bundle_status_code=" + bs.code
+ " but Serval-Rhizome-Result-Bundle-Status-Code: " + status.bundle_status_code.code);
}
else if (label.equals("rhizome_bundle_status_message")) {
String message = json.consume(String.class);
if (status.bundle_status_message == null)
status.bundle_status_message = message;
else if (!status.bundle_status_message.equals(message))
throw new ServalDInterfaceException("JSON/header conflict"
+ ", rhizome_bundle_status_message=" + message
+ " but Serval-Rhizome-Result-Bundle-Status-Message: " + status.bundle_status_message);
}
else if (label.equals("rhizome_payload_status_code")) {
RhizomePayloadStatus bs = RhizomePayloadStatus.fromCode(json.consume(Integer.class));
if (status.payload_status_code == null)
status.payload_status_code = bs;
else if (status.payload_status_code != bs)
throw new ServalDInterfaceException("JSON/header conflict"
+ ", rhizome_payload_status_code=" + bs.code
+ " but Serval-Rhizome-Result-Payload-Status-Code: " + status.payload_status_code.code);
}
else if (label.equals("rhizome_payload_status_message")) {
String message = json.consume(String.class);
if (status.payload_status_message == null)
status.payload_status_message = message;
else if (!status.payload_status_message.equals(message))
throw new ServalDInterfaceException("JSON/header conflict"
+ ", rhizome_payload_status_message=" + message
+ " but Serval-Rhizome-Result-Payload-Status-Code: " + status.payload_status_message);
}
else
json.unexpected(label);
tok = json.nextToken();
}
json.match(tok, JSONTokeniser.Token.END_OBJECT);
json.consume(JSONTokeniser.Token.EOF);
return status;
}
catch (JSONInputException e) {
throw new ServalDInterfaceException("malformed JSON status response", e);
}
}
public static RhizomeManifestBundle rhizomeManifest(ServalDHttpConnectionFactory connector, BundleId bid) throws IOException, ServalDInterfaceException, RhizomeException
public static RhizomeManifestBundle rhizomeManifest(ServalDHttpConnectionFactory connector, BundleId bid)
throws IOException, ServalDInterfaceException
{
HttpURLConnection conn = connector.newServalDHttpConnection("/restful/rhizome/" + bid.toHex() + ".rhm");
conn.connect();
InputStream in = RhizomeCommon.receiveResponse(conn, HttpURLConnection.HTTP_OK);
if (!conn.getContentType().equals("rhizome-manifest/text"))
throw new ServalDInterfaceException("unexpected HTTP Content-Type: " + conn.getContentType());
RhizomeManifest manifest;
Status status = RhizomeCommon.receiveResponse(conn, HttpURLConnection.HTTP_OK);
try {
manifest = RhizomeManifest.fromTextFormat(in);
dumpHeaders(conn, System.err);
decodeHeaderBundleStatus(status, conn);
switch (status.bundle_status_code) {
case NEW:
return null;
case SAME:
if (!conn.getContentType().equals("rhizome-manifest/text"))
throw new ServalDInterfaceException("unexpected HTTP Content-Type: " + conn.getContentType());
RhizomeManifest manifest = RhizomeManifest.fromTextFormat(status.input_stream);
BundleExtra extra = bundleExtraFromHeaders(conn);
return new RhizomeManifestBundle(manifest, extra.insertTime, extra.author, extra.secret);
case ERROR:
throw new ServalDFailureException("received rhizome_bundle_status_code=ERROR(-1) from " + conn.getURL());
}
}
catch (RhizomeManifestParseException e) {
throw new ServalDInterfaceException("malformed manifest from daemon", e);
}
finally {
in.close();
if (status.input_stream != null)
status.input_stream.close();
}
dumpHeaders(conn, System.err);
long insertTime = headerUnsignedLong(conn, "Serval-Rhizome-Bundle-Inserttime");
SubscriberId author = header(conn, "Serval-Rhizome-Bundle-Author", SubscriberId.class);
BundleSecret secret = header(conn, "Serval-Rhizome-Bundle-Secret", BundleSecret.class);
return new RhizomeManifestBundle(manifest, insertTime, author, secret);
unexpectedResponse(status);
return null;
}
public static RhizomePayloadRawBundle rhizomePayloadRaw(ServalDHttpConnectionFactory connector, BundleId bid) throws IOException, ServalDInterfaceException, RhizomeException
public static RhizomePayloadRawBundle rhizomePayloadRaw(ServalDHttpConnectionFactory connector, BundleId bid)
throws IOException, ServalDInterfaceException
{
HttpURLConnection conn = connector.newServalDHttpConnection("/restful/rhizome/" + bid.toHex() + "/raw.bin");
conn.connect();
InputStream in = RhizomeCommon.receiveResponse(conn, HttpURLConnection.HTTP_OK);
if (!conn.getContentType().equals("application/octet-stream"))
throw new ServalDInterfaceException("unexpected HTTP Content-Type: " + conn.getContentType());
dumpHeaders(conn, System.err);
RhizomeManifest manifest = manifestFromHeaders(conn);
long insertTime = headerUnsignedLong(conn, "Serval-Rhizome-Bundle-Inserttime");
SubscriberId author = header(conn, "Serval-Rhizome-Bundle-Author", SubscriberId.class);
BundleSecret secret = header(conn, "Serval-Rhizome-Bundle-Secret", BundleSecret.class);
return new RhizomePayloadRawBundle(manifest, in, insertTime, author, secret);
Status status = RhizomeCommon.receiveResponse(conn, HttpURLConnection.HTTP_OK);
try {
dumpHeaders(conn, System.err);
decodeHeaderBundleStatus(status, conn);
switch (status.bundle_status_code) {
case ERROR:
throw new ServalDFailureException("received rhizome_bundle_status_code=ERROR(-1) from " + conn.getURL());
case NEW: // No manifest
return null;
case SAME:
decodeHeaderPayloadStatus(status, conn);
switch (status.payload_status_code) {
case ERROR:
throw new ServalDFailureException("received rhizome_payload_status_code=ERROR(-1) from " + conn.getURL());
case NEW:
// The manifest is known but the payload is unavailable, so return a bundle
// object with a null input stream.
// FALL THROUGH
case EMPTY:
if (status.input_stream != null) {
status.input_stream.close();
status.input_stream = null;
}
// FALL THROUGH
case STORED: {
if (status.input_stream != null && !conn.getContentType().equals("application/octet-stream"))
throw new ServalDInterfaceException("unexpected HTTP Content-Type: " + conn.getContentType());
RhizomeManifest manifest = manifestFromHeaders(conn);
BundleExtra extra = bundleExtraFromHeaders(conn);
RhizomePayloadRawBundle ret = new RhizomePayloadRawBundle(manifest, status.input_stream, extra.insertTime, extra.author, extra.secret);
status.input_stream = null; // don't close when we return
return ret;
}
}
}
}
finally {
if (status.input_stream != null)
status.input_stream.close();
}
unexpectedResponse(status);
return null;
}
public static RhizomePayloadBundle rhizomePayload(ServalDHttpConnectionFactory connector, BundleId bid) throws IOException, ServalDInterfaceException, RhizomeException
public static RhizomePayloadBundle rhizomePayload(ServalDHttpConnectionFactory connector, BundleId bid)
throws IOException, ServalDInterfaceException, RhizomeDecryptionException
{
HttpURLConnection conn = connector.newServalDHttpConnection("/restful/rhizome/" + bid.toHex() + "/decrypted.bin");
conn.connect();
InputStream in = RhizomeCommon.receiveResponse(conn, HttpURLConnection.HTTP_OK);
if (!conn.getContentType().equals("application/octet-stream"))
throw new ServalDInterfaceException("unexpected HTTP Content-Type: " + conn.getContentType());
dumpHeaders(conn, System.err);
RhizomeManifest manifest = manifestFromHeaders(conn);
long insertTime = headerUnsignedLong(conn, "Serval-Rhizome-Bundle-Inserttime");
SubscriberId author = header(conn, "Serval-Rhizome-Bundle-Author", SubscriberId.class);
BundleSecret secret = header(conn, "Serval-Rhizome-Bundle-Secret", BundleSecret.class);
return new RhizomePayloadBundle(manifest, in, insertTime, author, secret);
Status status = RhizomeCommon.receiveResponse(conn, HttpURLConnection.HTTP_OK);
try {
dumpHeaders(conn, System.err);
decodeHeaderBundleStatus(status, conn);
switch (status.bundle_status_code) {
case ERROR:
throw new ServalDFailureException("received rhizome_bundle_status_code=ERROR(-1) from " + conn.getURL());
case NEW: // No manifest
return null;
case SAME:
decodeHeaderPayloadStatus(status, conn);
switch (status.payload_status_code) {
case ERROR:
throw new ServalDFailureException("received rhizome_payload_status_code=ERROR(-1) from " + conn.getURL());
case CRYPTO_FAIL:
throw new RhizomeDecryptionException(conn.getURL());
case NEW:
// The manifest is known but the payload is unavailable, so return a bundle
// object with a null input stream.
// FALL THROUGH
case EMPTY:
if (status.input_stream != null) {
status.input_stream.close();
status.input_stream = null;
}
// FALL THROUGH
case STORED: {
if (status.input_stream != null && !conn.getContentType().equals("application/octet-stream"))
throw new ServalDInterfaceException("unexpected HTTP Content-Type: " + conn.getContentType());
RhizomeManifest manifest = manifestFromHeaders(conn);
BundleExtra extra = bundleExtraFromHeaders(conn);
RhizomePayloadBundle ret = new RhizomePayloadBundle(manifest, status.input_stream, extra.insertTime, extra.author, extra.secret);
status.input_stream = null; // don't close when we return
return ret;
}
}
}
}
finally {
if (status.input_stream != null)
status.input_stream.close();
}
unexpectedResponse(status);
return null;
}
private static void dumpHeaders(HttpURLConnection conn, PrintStream out)
@ -250,6 +375,21 @@ public class RhizomeCommon
return new RhizomeManifest(id, version, filesize, filehash, sender, recipient, BK, crypt, tail, date, service, name);
}
private static class BundleExtra {
public long insertTime;
public SubscriberId author;
public BundleSecret secret;
}
private static BundleExtra bundleExtraFromHeaders(HttpURLConnection conn) throws ServalDInterfaceException
{
BundleExtra extra = new BundleExtra();
extra.insertTime = headerUnsignedLong(conn, "Serval-Rhizome-Bundle-Inserttime");
extra.author = header(conn, "Serval-Rhizome-Bundle-Author", SubscriberId.class);
extra.secret = header(conn, "Serval-Rhizome-Bundle-Secret", BundleSecret.class);
return extra;
}
private static String headerString(HttpURLConnection conn, String header) throws ServalDInterfaceException
{
String str = conn.getHeaderField(header);
@ -329,10 +469,30 @@ public class RhizomeCommon
private static <T> T headerOrNull(HttpURLConnection conn, String header, Class<T> cls) throws ServalDInterfaceException
{
String str = conn.getHeaderField(header);
if (str == null)
return null;
try {
return (T) cls.getConstructor(String.class).newInstance(str);
try {
Constructor<T> constructor = cls.getConstructor(String.class);
if (str == null)
return null;
return constructor.newInstance(str);
}
catch (NoSuchMethodException e) {
}
try {
Method method = cls.getMethod("fromCode", Integer.TYPE);
if ((method.getModifiers() & Modifier.STATIC) != 0 && method.getReturnType() == cls) {
Integer integer = headerIntegerOrNull(conn, header);
if (integer == null)
return null;
return cls.cast(method.invoke(null, integer));
}
}
catch (NoSuchMethodException e) {
}
throw new ServalDInterfaceException("don't know how to instantiate: " + cls.getName());
}
catch (ServalDInterfaceException e) {
throw e;
}
catch (InvocationTargetException e) {
throw new ServalDInterfaceException("invalid header field: " + header + ": " + str, e.getTargetException());

View File

@ -0,0 +1,36 @@
/**
* Copyright (C) 2014 Serval Project Inc.
*
* This file is part of Serval Software (http://www.servalproject.org)
*
* Serval Software is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This source code is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this source code; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package org.servalproject.servaldna.rhizome;
import java.net.URL;
/**
* Thrown when Rhizome already has a given manifest in the store.
*
* @author Andrew Bettison <andrew@servalproject.com>
*/
public class RhizomeDuplicateBundleException extends RhizomeException
{
public RhizomeDuplicateBundleException(URL url) {
super("duplicate bundle", url);
}
}

View File

@ -0,0 +1,36 @@
/**
* Copyright (C) 2014 Serval Project Inc.
*
* This file is part of Serval Software (http://www.servalproject.org)
*
* Serval Software is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This source code is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this source code; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package org.servalproject.servaldna.rhizome;
import java.net.URL;
/**
* Thrown when Rhizome already has a given manifest in the store.
*
* @author Andrew Bettison <andrew@servalproject.com>
*/
public class RhizomeManifestAlreadyStoredException extends RhizomeException
{
public RhizomeManifestAlreadyStoredException(URL url) {
super("manifest already stored", url);
}
}

View File

@ -0,0 +1,36 @@
/**
* Copyright (C) 2014 Serval Project Inc.
*
* This file is part of Serval Software (http://www.servalproject.org)
*
* Serval Software is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This source code is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this source code; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package org.servalproject.servaldna.rhizome;
import java.net.URL;
/**
* Thrown when Rhizome has no manifest with the given ID.
*
* @author Andrew Bettison <andrew@servalproject.com>
*/
public class RhizomeManifestNotFoundException extends RhizomeException
{
public RhizomeManifestNotFoundException(URL url) {
super("manifest not found", url);
}
}

View File

@ -0,0 +1,37 @@
/**
* Copyright (C) 2014 Serval Project Inc.
*
* This file is part of Serval Software (http://www.servalproject.org)
*
* Serval Software is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This source code is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this source code; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package org.servalproject.servaldna.rhizome;
import java.net.URL;
/**
* Thrown when Rhizome has a newer manifest in the store, ie, same Bundle ID and higher version
* number.
*
* @author Andrew Bettison <andrew@servalproject.com>
*/
public class RhizomeOutdatedBundleException extends RhizomeException
{
public RhizomeOutdatedBundleException(URL url) {
super("outdated bundle", url);
}
}

View File

@ -0,0 +1,36 @@
/**
* Copyright (C) 2014 Serval Project Inc.
*
* This file is part of Serval Software (http://www.servalproject.org)
*
* Serval Software is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This source code is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this source code; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package org.servalproject.servaldna.rhizome;
import java.net.URL;
/**
* Thrown when the Rhizome store is full.
*
* @author Andrew Bettison <andrew@servalproject.com>
*/
public class RhizomeStoreFullException extends RhizomeException
{
public RhizomeStoreFullException(URL url) {
super("store is full", url);
}
}

View File

@ -85,15 +85,19 @@ public class Rhizome {
try {
ServalDClient client = new ServerControl().getRestfulClient();
RhizomeManifestBundle bundle = client.rhizomeManifest(bid);
System.out.println(
"_insertTime=" + bundle.insertTime + "\n" +
"_author=" + bundle.author + "\n" +
"_secret=" + bundle.secret + "\n" +
manifestFields(bundle.manifest, "\n") + "\n"
);
FileOutputStream out = new FileOutputStream(dstpath);
out.write(bundle.manifestText());
out.close();
if (bundle == null)
System.out.println("not found");
else {
System.out.println(
"_insertTime=" + bundle.insertTime + "\n" +
"_author=" + bundle.author + "\n" +
"_secret=" + bundle.secret + "\n" +
manifestFields(bundle.manifest, "\n") + "\n"
);
FileOutputStream out = new FileOutputStream(dstpath);
out.write(bundle.manifestText());
out.close();
}
}
catch (RhizomeException e) {
System.out.println(e.toString());
@ -104,23 +108,32 @@ public class Rhizome {
static void rhizome_payload_raw(BundleId bid, String dstpath) throws ServalDInterfaceException, IOException, InterruptedException
{
ServalDClient client = new ServerControl().getRestfulClient();
FileOutputStream out = new FileOutputStream(dstpath);
FileOutputStream out = null;
try {
RhizomePayloadRawBundle bundle = client.rhizomePayloadRaw(bid);
InputStream in = bundle.rawPayloadInputStream;
byte[] buf = new byte[4096];
int n;
while ((n = in.read(buf)) > 0)
out.write(buf, 0, n);
in.close();
out.close();
out = null;
System.out.println(
"_insertTime=" + bundle.insertTime + "\n" +
"_author=" + bundle.author + "\n" +
"_secret=" + bundle.secret + "\n" +
manifestFields(bundle.manifest, "\n") + "\n"
);
if (bundle == null)
System.out.println("not found");
else {
InputStream in = bundle.rawPayloadInputStream;
if (in == null)
System.out.println("no payload");
else {
out = new FileOutputStream(dstpath);
byte[] buf = new byte[4096];
int n;
while ((n = in.read(buf)) > 0)
out.write(buf, 0, n);
in.close();
out.close();
out = null;
}
System.out.println(
"_insertTime=" + bundle.insertTime + "\n" +
"_author=" + bundle.author + "\n" +
"_secret=" + bundle.secret + "\n" +
manifestFields(bundle.manifest, "\n") + "\n"
);
}
}
catch (RhizomeException e) {
System.out.println(e.toString());
@ -135,23 +148,32 @@ public class Rhizome {
static void rhizome_payload_decrypted(BundleId bid, String dstpath) throws ServalDInterfaceException, IOException, InterruptedException
{
ServalDClient client = new ServerControl().getRestfulClient();
FileOutputStream out = new FileOutputStream(dstpath);
FileOutputStream out = null;
try {
RhizomePayloadBundle bundle = client.rhizomePayload(bid);
InputStream in = bundle.payloadInputStream;
byte[] buf = new byte[4096];
int n;
while ((n = in.read(buf)) > 0)
out.write(buf, 0, n);
in.close();
out.close();
out = null;
System.out.println(
"_insertTime=" + bundle.insertTime + "\n" +
"_author=" + bundle.author + "\n" +
"_secret=" + bundle.secret + "\n" +
manifestFields(bundle.manifest, "\n") + "\n"
);
if (bundle == null)
System.out.println("not found");
else {
InputStream in = bundle.payloadInputStream;
if (in == null)
System.out.println("no payload");
else {
out = new FileOutputStream(dstpath);
byte[] buf = new byte[4096];
int n;
while ((n = in.read(buf)) > 0)
out.write(buf, 0, n);
in.close();
out.close();
out = null;
}
System.out.println(
"_insertTime=" + bundle.insertTime + "\n" +
"_author=" + bundle.author + "\n" +
"_secret=" + bundle.secret + "\n" +
manifestFields(bundle.manifest, "\n") + "\n"
);
}
}
catch (RhizomeException e) {
System.out.println(e.toString());

View File

@ -708,7 +708,7 @@ static int restful_rhizome_bid_rhm(httpd_request *r, const char *remainder)
if (*remainder)
return 404;
if (r->manifest == NULL)
return http_request_rhizome_response(r, 404, NULL, NULL);
return http_request_rhizome_response(r, 403, NULL, NULL);
http_request_response_static(&r->http, 200, "rhizome-manifest/text",
(const char *)r->manifest->manifestdata, r->manifest->manifest_all_bytes
);
@ -720,7 +720,7 @@ static int restful_rhizome_bid_raw_bin(httpd_request *r, const char *remainder)
if (*remainder)
return 404;
if (r->manifest == NULL)
return http_request_rhizome_response(r, 404, NULL, NULL);
return http_request_rhizome_response(r, 403, NULL, NULL);
if (r->manifest->filesize == 0) {
http_request_response_static(&r->http, 200, CONTENT_TYPE_BLOB, "", 0);
return 1;
@ -737,7 +737,7 @@ static int restful_rhizome_bid_decrypted_bin(httpd_request *r, const char *remai
if (*remainder)
return 404;
if (r->manifest == NULL)
return http_request_rhizome_response(r, 404, NULL, NULL);
return http_request_rhizome_response(r, 403, NULL, NULL);
if (r->manifest->filesize == 0) {
// TODO use Content Type from manifest (once it is implemented)
http_request_response_static(&r->http, 200, CONTENT_TYPE_BLOB, "", 0);

View File

@ -31,6 +31,7 @@ setup() {
executeOk_servald config \
set log.console.level debug \
set debug.httpd on
set_extra_config
create_identities 4
start_servald_server
}
@ -169,6 +170,17 @@ test_RhizomeManifest() {
done
}
doc_RhizomeManifestNonexist="Java API fetch non-existent Rhizome manifest"
setup_RhizomeManifestNonexist() {
setup
}
test_RhizomeManifestNonexist() {
executeJavaOk org.servalproject.test.Rhizome rhizome-manifest "$BID_NONEXISTENT" ''
tfw_cat --stdout --stderr
assertStdoutLineCount == 1
assertStdoutGrep --ignore-case '^not found$'
}
doc_RhizomePayloadRaw="Java API fetch Rhizome raw payload"
setup_RhizomePayloadRaw() {
setup
@ -186,6 +198,33 @@ test_RhizomePayloadRaw() {
done
}
doc_RhizomePayloadRawNonexistManifest="Java API fetch Rhizome raw payload for non-existent manifest"
setup_RhizomePayloadRawNonexistManifest() {
setup
}
test_RhizomePayloadRawNonexistManifest() {
executeJavaOk org.servalproject.test.Rhizome rhizome-payload-raw "$BID_NONEXISTENT" ''
tfw_cat --stdout --stderr
assertStdoutLineCount == 1
assertStdoutGrep --ignore-case '^not found$'
}
doc_RhizomePayloadRawNonexistPayload="Java API fetch non-existent Rhizome raw payload"
setup_RhizomePayloadRawNonexistPayload() {
set_extra_config() {
executeOk_servald config set rhizome.max_blob_size 0
}
setup
rhizome_add_bundles $SIDA1 0 0
rhizome_delete_payload_blobs "${HASH[0]}"
}
test_RhizomePayloadRawNonexistPayload() {
executeJavaOk org.servalproject.test.Rhizome rhizome-payload-raw "${BID[0]}" raw.bin
tfw_cat --stdout --stderr
assertStdoutGrep --ignore-case '^no payload$'
assert_metadata 0
}
doc_RhizomePayloadDecrypted="Java API fetch Rhizome decrypted payload"
setup_RhizomePayloadDecrypted() {
setup
@ -203,6 +242,22 @@ test_RhizomePayloadDecrypted() {
done
}
doc_RhizomePayloadDecryptedNonexistManifest="Java API fetch Rhizome decrypted payload for non-existent manifest"
setup_RhizomePayloadDecryptedNonexistManifest() {
set_extra_config() {
executeOk_servald config set rhizome.max_blob_size 0
}
setup
rhizome_add_bundles $SIDA1 0 0
rhizome_delete_payload_blobs "${HASH[0]}"
}
test_RhizomePayloadDecryptedNonexistManifest() {
executeJavaOk org.servalproject.test.Rhizome rhizome-payload-decrypted "${BID[0]}" ''
tfw_cat --stdout --stderr
assertStdoutGrep --ignore-case '^no payload$'
assert_metadata 0
}
doc_RhizomePayloadDecryptedForeign="Java API cannot fetch foreign Rhizome decrypted payload"
setup_RhizomePayloadDecryptedForeign() {
setup

View File

@ -115,7 +115,7 @@ teardown_AuthBasicWrong() {
teardown
}
doc_RhizomeList="HTTP RESTful list Rhizome bundles as JSON"
doc_RhizomeList="HTTP RESTful list 100 Rhizome bundles as JSON"
setup_RhizomeList() {
setup
NBUNDLES=100
@ -274,12 +274,12 @@ test_RhizomeManifestNonexist() {
--basic --user harry:potter \
"http://$addr_localhost:$PORTA/restful/rhizome/$BID_NONEXISTENT.rhm"
tfw_cat http.headers http.content
assertStdoutIs 404
assertStdoutIs 403
assertGrep --matches=1 --ignore-case http.headers$n "^Serval-Rhizome-Result-Bundle-Status-Code: 0$CR\$"
assertGrep --matches=1 --ignore-case http.headers$n "^Serval-Rhizome-Result-Bundle-Status-Message: .*bundle new to store.*$CR\$"
assertGrep --matches=0 --ignore-case http.headers$n "^Serval-Rhizome-Result-Payload-Status-Code:"
assertGrep --matches=0 --ignore-case http.headers$n "^Serval-Rhizome-Result-Payload-Status-Message:"
assertJq http.content 'contains({"http_status_code": 404})'
assertJq http.content 'contains({"http_status_code": 403})'
assertJq http.content 'contains({"rhizome_bundle_status_code": 0})'
assertJqGrep --ignore-case http.content '.rhizome_bundle_status_message' "bundle new to store"
}
@ -322,12 +322,12 @@ test_RhizomePayloadRawNonexistManifest() {
--basic --user harry:potter \
"http://$addr_localhost:$PORTA/restful/rhizome/$BID_NONEXISTENT/raw.bin"
tfw_cat http.headers http.content
assertStdoutIs 404
assertStdoutIs 403
assertGrep --matches=1 --ignore-case http.headers$n "^Serval-Rhizome-Result-Bundle-Status-Code: 0$CR\$"
assertGrep --matches=1 --ignore-case http.headers$n "^Serval-Rhizome-Result-Bundle-Status-Message: .*bundle new to store.*$CR\$"
assertGrep --matches=0 --ignore-case http.headers$n "^Serval-Rhizome-Result-Payload-Status-Code:"
assertGrep --matches=0 --ignore-case http.headers$n "^Serval-Rhizome-Result-Payload-Status-Message:"
assertJq http.content 'contains({"http_status_code": 404})'
assertJq http.content 'contains({"http_status_code": 403})'
assertJq http.content 'contains({"rhizome_bundle_status_code": 0})'
assertJqGrep --ignore-case http.content '.rhizome_bundle_status_message' "bundle new to store"
}
@ -425,12 +425,12 @@ test_RhizomePayloadDecryptedNonexistManifest() {
--basic --user harry:potter \
"http://$addr_localhost:$PORTA/restful/rhizome/$BID_NONEXISTENT/decrypted.bin"
tfw_cat http.headers http.content
assertStdoutIs 404
assertStdoutIs 403
assertGrep --matches=1 --ignore-case http.headers$n "^Serval-Rhizome-Result-Bundle-Status-Code: 0$CR\$"
assertGrep --matches=1 --ignore-case http.headers$n "^Serval-Rhizome-Result-Bundle-Status-Message: .*bundle new to store.*$CR\$"
assertGrep --matches=0 --ignore-case http.headers$n "^Serval-Rhizome-Result-Payload-Status-Code:"
assertGrep --matches=0 --ignore-case http.headers$n "^Serval-Rhizome-Result-Payload-Status-Message:"
assertJq http.content 'contains({"http_status_code": 404})'
assertJq http.content 'contains({"http_status_code": 403})'
assertJq http.content 'contains({"rhizome_bundle_status_code": 0})'
assertJqGrep --ignore-case http.content '.rhizome_bundle_status_message' "bundle new to store"
}