mirror of
https://github.com/servalproject/serval-dna.git
synced 2025-01-18 02:39:44 +00:00
Improve Rhizome HTTP RESTful interface
Add RHIZOME_BUNDLE_STATUS_READONLY enum value Tighten up switch statements on bundle and payload status enums (no default labels) Rename some recently added enum entries Return bundle status and payload status in HTTP responses Add test for failing to decrypt a foreign encrypted bundle payload, fix bug that caused an assertion failure Add tests for fetching a non-existent manifest and fetching bundles whose payload blob is not in the store
This commit is contained in:
parent
34b6ff48bf
commit
cf43635789
@ -1761,9 +1761,9 @@ int app_rhizome_add_file(const struct cli_parsed *parsed, struct cli_context *co
|
||||
case RHIZOME_PAYLOAD_STATUS_NEW:
|
||||
break;
|
||||
case RHIZOME_PAYLOAD_STATUS_TOO_BIG:
|
||||
case RHIZOME_PAYLOAD_STATUS_UNINITERESTING:
|
||||
status = RHIZOME_BUNDLE_STATUS_DONOTWANT;
|
||||
WHY("Insufficient space to store payload");
|
||||
case RHIZOME_PAYLOAD_STATUS_EVICTED:
|
||||
status = RHIZOME_BUNDLE_STATUS_NO_ROOM;
|
||||
INFO("Insufficient space to store payload");
|
||||
break;
|
||||
case RHIZOME_PAYLOAD_STATUS_ERROR:
|
||||
status = RHIZOME_BUNDLE_STATUS_ERROR;
|
||||
@ -1773,12 +1773,12 @@ int app_rhizome_add_file(const struct cli_parsed *parsed, struct cli_context *co
|
||||
status = RHIZOME_BUNDLE_STATUS_INCONSISTENT;
|
||||
break;
|
||||
case RHIZOME_PAYLOAD_STATUS_CRYPTO_FAIL:
|
||||
status = RHIZOME_BUNDLE_STATUS_FAKE;
|
||||
status = RHIZOME_BUNDLE_STATUS_READONLY;
|
||||
break;
|
||||
default:
|
||||
FATALF("pstatus = %d", pstatus);
|
||||
}
|
||||
rhizome_manifest *mout = m;
|
||||
rhizome_manifest *mout = NULL;
|
||||
if (status == RHIZOME_BUNDLE_STATUS_NEW) {
|
||||
if (!rhizome_manifest_validate(m) || m->malformed)
|
||||
status = RHIZOME_BUNDLE_STATUS_INVALID;
|
||||
@ -1790,6 +1790,7 @@ int app_rhizome_add_file(const struct cli_parsed *parsed, struct cli_context *co
|
||||
}
|
||||
}
|
||||
}
|
||||
int status_valid = 0;
|
||||
switch (status) {
|
||||
case RHIZOME_BUNDLE_STATUS_NEW:
|
||||
if (mout && mout != m)
|
||||
@ -1799,25 +1800,30 @@ int app_rhizome_add_file(const struct cli_parsed *parsed, struct cli_context *co
|
||||
case RHIZOME_BUNDLE_STATUS_SAME:
|
||||
case RHIZOME_BUNDLE_STATUS_DUPLICATE:
|
||||
case RHIZOME_BUNDLE_STATUS_OLD:
|
||||
assert(mout != NULL);
|
||||
cli_put_manifest(context, mout);
|
||||
if ( manifestpath && *manifestpath
|
||||
&& rhizome_write_manifest_file(mout, manifestpath, 0) == -1
|
||||
)
|
||||
WHYF("Could not write manifest to %s", alloca_str_toprint(manifestpath));
|
||||
status_valid = 1;
|
||||
break;
|
||||
case RHIZOME_BUNDLE_STATUS_READONLY:
|
||||
case RHIZOME_BUNDLE_STATUS_INCONSISTENT:
|
||||
case RHIZOME_BUNDLE_STATUS_ERROR:
|
||||
case RHIZOME_BUNDLE_STATUS_INVALID:
|
||||
case RHIZOME_BUNDLE_STATUS_FAKE:
|
||||
case RHIZOME_BUNDLE_STATUS_DONOTWANT:
|
||||
case RHIZOME_BUNDLE_STATUS_NO_ROOM:
|
||||
status_valid = 1;
|
||||
break;
|
||||
default:
|
||||
FATALF("status=%d", status);
|
||||
// Do not use a default: label! With no default, if a new value is added to the enum, then the
|
||||
// compiler will issue a warning on switch statements that do not cover all the values, which is
|
||||
// a valuable tool for the developer.
|
||||
}
|
||||
if (mout && mout != m) {
|
||||
if (!status_valid)
|
||||
FATALF("status=%d", status);
|
||||
if (mout && mout != m)
|
||||
rhizome_manifest_free(mout);
|
||||
m = NULL;
|
||||
}
|
||||
rhizome_manifest_free(m);
|
||||
keyring_free(keyring);
|
||||
keyring = NULL;
|
||||
|
@ -1840,12 +1840,14 @@ static strbuf strbuf_status_body(strbuf sb, struct http_response *hr, const char
|
||||
) {
|
||||
hr->header.content_type = CONTENT_TYPE_TEXT;
|
||||
strbuf_sprintf(sb, "%03u %s", hr->result_code, message);
|
||||
if (hr->result_extra_label) {
|
||||
strbuf_puts(sb, "\r\n");
|
||||
strbuf_puts(sb, hr->result_extra_label);
|
||||
strbuf_puts(sb, "=");
|
||||
strbuf_json_atom_as_text(sb, &hr->result_extra_value);
|
||||
}
|
||||
unsigned i;
|
||||
for (i = 0; i < NELS(hr->result_extra); ++i)
|
||||
if (hr->result_extra[i].label) {
|
||||
strbuf_puts(sb, "\r\n");
|
||||
strbuf_puts(sb, hr->result_extra[i].label);
|
||||
strbuf_puts(sb, "=");
|
||||
strbuf_json_atom_as_text(sb, &hr->result_extra[i].value);
|
||||
}
|
||||
strbuf_puts(sb, "\r\n");
|
||||
}
|
||||
else if ( hr->header.content_type == CONTENT_TYPE_JSON
|
||||
@ -1854,24 +1856,28 @@ static strbuf strbuf_status_body(strbuf sb, struct http_response *hr, const char
|
||||
hr->header.content_type = CONTENT_TYPE_JSON;
|
||||
strbuf_sprintf(sb, "{\n \"http_status_code\": %u,\n \"http_status_message\": ", hr->result_code);
|
||||
strbuf_json_string(sb, message);
|
||||
if (hr->result_extra_label) {
|
||||
strbuf_puts(sb, ",\n ");
|
||||
strbuf_json_string(sb, hr->result_extra_label);
|
||||
strbuf_puts(sb, ": ");
|
||||
strbuf_json_atom_as_html(sb, &hr->result_extra_value);
|
||||
}
|
||||
unsigned i;
|
||||
for (i = 0; i < NELS(hr->result_extra); ++i)
|
||||
if (hr->result_extra[i].label) {
|
||||
strbuf_puts(sb, ",\n ");
|
||||
strbuf_json_string(sb, hr->result_extra[i].label);
|
||||
strbuf_puts(sb, ": ");
|
||||
strbuf_json_atom(sb, &hr->result_extra[i].value);
|
||||
}
|
||||
strbuf_puts(sb, "\n}");
|
||||
}
|
||||
else {
|
||||
hr->header.content_type = CONTENT_TYPE_HTML;
|
||||
strbuf_sprintf(sb, "<html>\n<h1>%03u %s</h1>", hr->result_code, message);
|
||||
if (hr->result_extra_label) {
|
||||
strbuf_puts(sb, "\n<dl><dt>");
|
||||
strbuf_html_escape(sb, hr->result_extra_label, strlen(hr->result_extra_label));
|
||||
strbuf_puts(sb, "</dt><dd>");
|
||||
strbuf_json_atom_as_html(sb, &hr->result_extra_value);
|
||||
strbuf_puts(sb, "</dd></dl>");
|
||||
}
|
||||
unsigned i;
|
||||
for (i = 0; i < NELS(hr->result_extra); ++i)
|
||||
if (hr->result_extra[i].label) {
|
||||
strbuf_puts(sb, "\n<dl><dt>");
|
||||
strbuf_html_escape(sb, hr->result_extra[i].label, strlen(hr->result_extra[i].label));
|
||||
strbuf_puts(sb, "</dt><dd>");
|
||||
strbuf_json_atom_as_html(sb, &hr->result_extra[i].value);
|
||||
strbuf_puts(sb, "</dd></dl>");
|
||||
}
|
||||
strbuf_puts(sb, "\n</html>");
|
||||
}
|
||||
return sb;
|
||||
|
@ -111,8 +111,10 @@ typedef int (HTTP_CONTENT_GENERATOR)(struct http_request *, unsigned char *, siz
|
||||
|
||||
struct http_response {
|
||||
uint16_t result_code;
|
||||
const char *result_extra_label;
|
||||
struct json_atom result_extra_value;
|
||||
struct {
|
||||
const char *label;
|
||||
struct json_atom value;
|
||||
} result_extra[4];
|
||||
struct http_response_headers header;
|
||||
const char *content;
|
||||
HTTP_CONTENT_GENERATOR *content_generator; // callback to produce more content
|
||||
|
2
httpd.c
2
httpd.c
@ -276,6 +276,8 @@ void httpd_server_poll(struct sched_ent *alarm)
|
||||
} else {
|
||||
++httpd_request_count;
|
||||
request->uuid = http_request_uuid_counter++;
|
||||
request->payload_status = INVALID_RHIZOME_PAYLOAD_STATUS;
|
||||
request->bundle_status = INVALID_RHIZOME_BUNDLE_STATUS;
|
||||
if (peerip)
|
||||
request->http.client_sockaddr_in = *peerip;
|
||||
request->http.handle_headers = httpd_dispatch;
|
||||
|
3
httpd.h
3
httpd.h
@ -60,6 +60,8 @@ typedef struct httpd_request
|
||||
/* For requests/responses that pertain to a single manifest.
|
||||
*/
|
||||
rhizome_manifest *manifest;
|
||||
enum rhizome_payload_status payload_status;
|
||||
enum rhizome_bundle_status bundle_status;
|
||||
|
||||
/* For requests/responses that contain one or two SIDs.
|
||||
*/
|
||||
@ -123,7 +125,6 @@ typedef struct httpd_request
|
||||
// For storing the manifest text (malloc/realloc) as we receive it
|
||||
struct form_buf_malloc manifest;
|
||||
// For receiving the payload
|
||||
enum rhizome_payload_status payload_status;
|
||||
uint64_t payload_size;
|
||||
struct rhizome_write write;
|
||||
}
|
||||
|
@ -66,43 +66,40 @@ static int strn_to_meshms_token(const char *str, rhizome_bid_t *bidp, uint64_t *
|
||||
|
||||
static int http_request_meshms_response(struct httpd_request *r, uint16_t result, const char *message, enum meshms_status status)
|
||||
{
|
||||
r->http.response.result_extra_label = "meshms_status_code";
|
||||
r->http.response.result_extra_value.type = JSON_INTEGER;
|
||||
r->http.response.result_extra_value.u.integer = status;
|
||||
r->http.response.result_extra[0].label = "meshms_status_code";
|
||||
r->http.response.result_extra[0].value.type = JSON_INTEGER;
|
||||
r->http.response.result_extra[0].value.u.integer = status;
|
||||
uint16_t meshms_result = 0;
|
||||
const char *meshms_message = NULL;
|
||||
switch (status) {
|
||||
case MESHMS_STATUS_OK:
|
||||
if (!result)
|
||||
result = 200;
|
||||
if (!message)
|
||||
message = "OK";
|
||||
meshms_result = 200;
|
||||
meshms_message = "OK";
|
||||
break;
|
||||
case MESHMS_STATUS_UPDATED:
|
||||
if (!result)
|
||||
result = 201;
|
||||
if (!message)
|
||||
message = "Updated";
|
||||
meshms_result = 201;
|
||||
meshms_message = "Updated";
|
||||
break;
|
||||
case MESHMS_STATUS_SID_LOCKED:
|
||||
if (!result)
|
||||
result = 403;
|
||||
if (!message)
|
||||
message = "Identity unknown";
|
||||
meshms_result = 403;
|
||||
meshms_message = "Identity unknown";
|
||||
break;
|
||||
case MESHMS_STATUS_PROTOCOL_FAULT:
|
||||
if (!result)
|
||||
result = 403;
|
||||
if (!message)
|
||||
message = "MeshMS protocol fault";
|
||||
meshms_result = 403;
|
||||
meshms_message = "MeshMS protocol fault";
|
||||
break;
|
||||
case MESHMS_STATUS_ERROR:
|
||||
if (!result)
|
||||
result = 500;
|
||||
break;
|
||||
default:
|
||||
WHYF("Invalid MeshMS status code %d", status);
|
||||
result = 500;
|
||||
meshms_result = 500;
|
||||
break;
|
||||
}
|
||||
if (!meshms_result) {
|
||||
WHYF("Invalid MeshMS status code %d", status);
|
||||
result = 500;
|
||||
} else if (!result) {
|
||||
result = meshms_result;
|
||||
if (message == NULL)
|
||||
message = meshms_message;
|
||||
}
|
||||
assert(result != 0);
|
||||
http_request_simple_response(&r->http, result, message);
|
||||
return result;
|
||||
|
83
rhizome.c
83
rhizome.c
@ -158,31 +158,27 @@ enum rhizome_bundle_status rhizome_bundle_import_files(rhizome_manifest *m, rhiz
|
||||
)
|
||||
return RHIZOME_BUNDLE_STATUS_INVALID;
|
||||
enum rhizome_bundle_status status = rhizome_manifest_check_stored(m, mout);
|
||||
if (status == RHIZOME_BUNDLE_STATUS_NEW) {
|
||||
enum rhizome_payload_status pstatus = rhizome_import_payload_from_file(m, filepath);
|
||||
switch (pstatus) {
|
||||
case RHIZOME_PAYLOAD_STATUS_EMPTY:
|
||||
case RHIZOME_PAYLOAD_STATUS_STORED:
|
||||
case RHIZOME_PAYLOAD_STATUS_NEW:
|
||||
if (rhizome_store_manifest(m) == -1)
|
||||
return -1;
|
||||
break;
|
||||
case RHIZOME_PAYLOAD_STATUS_TOO_BIG:
|
||||
case RHIZOME_PAYLOAD_STATUS_UNINITERESTING:
|
||||
status = RHIZOME_BUNDLE_STATUS_DONOTWANT;
|
||||
break;
|
||||
case RHIZOME_PAYLOAD_STATUS_ERROR:
|
||||
case RHIZOME_PAYLOAD_STATUS_CRYPTO_FAIL:
|
||||
if (status != RHIZOME_BUNDLE_STATUS_NEW)
|
||||
return status;
|
||||
enum rhizome_payload_status pstatus = rhizome_import_payload_from_file(m, filepath);
|
||||
switch (pstatus) {
|
||||
case RHIZOME_PAYLOAD_STATUS_EMPTY:
|
||||
case RHIZOME_PAYLOAD_STATUS_STORED:
|
||||
case RHIZOME_PAYLOAD_STATUS_NEW:
|
||||
if (rhizome_store_manifest(m) == -1)
|
||||
return -1;
|
||||
case RHIZOME_PAYLOAD_STATUS_WRONG_SIZE:
|
||||
case RHIZOME_PAYLOAD_STATUS_WRONG_HASH:
|
||||
status = RHIZOME_BUNDLE_STATUS_INCONSISTENT;
|
||||
break;
|
||||
default:
|
||||
FATALF("pstatus = %d", pstatus);
|
||||
}
|
||||
return status;
|
||||
case RHIZOME_PAYLOAD_STATUS_TOO_BIG:
|
||||
case RHIZOME_PAYLOAD_STATUS_EVICTED:
|
||||
return RHIZOME_BUNDLE_STATUS_NO_ROOM;
|
||||
case RHIZOME_PAYLOAD_STATUS_ERROR:
|
||||
case RHIZOME_PAYLOAD_STATUS_CRYPTO_FAIL:
|
||||
return -1;
|
||||
case RHIZOME_PAYLOAD_STATUS_WRONG_SIZE:
|
||||
case RHIZOME_PAYLOAD_STATUS_WRONG_HASH:
|
||||
return RHIZOME_BUNDLE_STATUS_INCONSISTENT;
|
||||
}
|
||||
return status;
|
||||
FATALF("rhizome_import_payload_from_file() returned status = %d", pstatus);
|
||||
}
|
||||
|
||||
/* Sets the bundle key "BK" field of a manifest. Returns 1 if the field was set, 0 if not.
|
||||
@ -325,8 +321,12 @@ enum rhizome_bundle_status rhizome_manifest_check_stored(rhizome_manifest *m, rh
|
||||
|
||||
enum rhizome_bundle_status rhizome_add_manifest(rhizome_manifest *m, rhizome_manifest **mout)
|
||||
{
|
||||
if (config.debug.rhizome)
|
||||
DEBUGF("rhizome_add_manifest(m=manifest[%d](%p), mout=%p)", m->manifest_record_number, m, mout);
|
||||
if (config.debug.rhizome) {
|
||||
if (mout == NULL)
|
||||
DEBUGF("rhizome_add_manifest(m=manifest[%d](%p), mout=NULL)", m->manifest_record_number, m);
|
||||
else
|
||||
DEBUGF("rhizome_add_manifest(m=manifest[%d](%p), *mout=manifest[%d](%p))", m->manifest_record_number, m, *mout ? (*mout)->manifest_record_number : -1, *mout);
|
||||
}
|
||||
if (!m->finalised && !rhizome_manifest_validate(m))
|
||||
return RHIZOME_BUNDLE_STATUS_INVALID;
|
||||
assert(m->finalised);
|
||||
@ -351,3 +351,36 @@ int rhizome_saw_voice_traffic()
|
||||
rhizome_voice_timeout=gettime_ms()+1000;
|
||||
return 0;
|
||||
}
|
||||
|
||||
const char *rhizome_bundle_status_message(enum rhizome_bundle_status status)
|
||||
{
|
||||
switch (status) {
|
||||
case RHIZOME_BUNDLE_STATUS_NEW: return "Bundle new to store";
|
||||
case RHIZOME_BUNDLE_STATUS_SAME: return "Bundle already in store";
|
||||
case RHIZOME_BUNDLE_STATUS_DUPLICATE: return "Duplicate bundle already in store";
|
||||
case RHIZOME_BUNDLE_STATUS_OLD: return "Newer bundle already in store";
|
||||
case RHIZOME_BUNDLE_STATUS_INVALID: return "Invalid manifest";
|
||||
case RHIZOME_BUNDLE_STATUS_FAKE: return "Manifest signature does not verify";
|
||||
case RHIZOME_BUNDLE_STATUS_INCONSISTENT: return "Manifest inconsistent with supplied payload";
|
||||
case RHIZOME_BUNDLE_STATUS_NO_ROOM: return "No room in store for bundle";
|
||||
case RHIZOME_BUNDLE_STATUS_READONLY: return "Bundle is read-only";
|
||||
case RHIZOME_BUNDLE_STATUS_ERROR: return "Internal error";
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const char *rhizome_payload_status_message(enum rhizome_payload_status status)
|
||||
{
|
||||
switch (status) {
|
||||
case RHIZOME_PAYLOAD_STATUS_NEW: return "Payload new to store";
|
||||
case RHIZOME_PAYLOAD_STATUS_STORED: return "Payload already in store";
|
||||
case RHIZOME_PAYLOAD_STATUS_EMPTY: return "Payload empty";
|
||||
case RHIZOME_PAYLOAD_STATUS_TOO_BIG: return "Payload size exceeds store";
|
||||
case RHIZOME_PAYLOAD_STATUS_EVICTED: return "Payload evicted";
|
||||
case RHIZOME_PAYLOAD_STATUS_WRONG_SIZE: return "Payload size contradicts manifest";
|
||||
case RHIZOME_PAYLOAD_STATUS_WRONG_HASH: return "Payload hash contradicts manifest";
|
||||
case RHIZOME_PAYLOAD_STATUS_CRYPTO_FAIL: return "Incorrect bundle secret";
|
||||
case RHIZOME_PAYLOAD_STATUS_ERROR: return "Internal error";
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
15
rhizome.h
15
rhizome.h
@ -362,21 +362,30 @@ enum rhizome_bundle_status {
|
||||
RHIZOME_BUNDLE_STATUS_INVALID = 4, // manifest is invalid
|
||||
RHIZOME_BUNDLE_STATUS_FAKE = 5, // manifest signature not valid
|
||||
RHIZOME_BUNDLE_STATUS_INCONSISTENT = 6, // manifest filesize/filehash does not match supplied payload
|
||||
RHIZOME_BUNDLE_STATUS_DONOTWANT = 7, // Wont fit or we already have more important bundles
|
||||
RHIZOME_BUNDLE_STATUS_NO_ROOM = 7, // doesn't fit; store may contain more important bundles
|
||||
RHIZOME_BUNDLE_STATUS_READONLY = 8, // cannot modify manifest; secret unknown
|
||||
};
|
||||
|
||||
#define INVALID_RHIZOME_BUNDLE_STATUS ((enum rhizome_bundle_status)-2)
|
||||
|
||||
const char *rhizome_bundle_status_message(enum rhizome_bundle_status);
|
||||
|
||||
enum rhizome_payload_status {
|
||||
RHIZOME_PAYLOAD_STATUS_ERROR = -1,
|
||||
RHIZOME_PAYLOAD_STATUS_EMPTY = 0, // payload is empty (zero length)
|
||||
RHIZOME_PAYLOAD_STATUS_NEW = 1, // payload is not yet in store
|
||||
RHIZOME_PAYLOAD_STATUS_NEW = 1, // payload is not yet in store (added)
|
||||
RHIZOME_PAYLOAD_STATUS_STORED = 2, // payload is already in store
|
||||
RHIZOME_PAYLOAD_STATUS_WRONG_SIZE = 3, // payload's size does not match manifest
|
||||
RHIZOME_PAYLOAD_STATUS_WRONG_HASH = 4, // payload's hash does not match manifest
|
||||
RHIZOME_PAYLOAD_STATUS_CRYPTO_FAIL = 5, // cannot encrypt/decrypt (payload key unknown)
|
||||
RHIZOME_PAYLOAD_STATUS_TOO_BIG = 6, // payload will never fit in our store
|
||||
RHIZOME_PAYLOAD_STATUS_UNINITERESTING = 7, // other payloads in our store are more interesting
|
||||
RHIZOME_PAYLOAD_STATUS_EVICTED = 7, // other payloads in our store are more important
|
||||
};
|
||||
|
||||
#define INVALID_RHIZOME_PAYLOAD_STATUS ((enum rhizome_bundle_status)-2)
|
||||
|
||||
const char *rhizome_payload_status_message(enum rhizome_payload_status);
|
||||
|
||||
int rhizome_write_manifest_file(rhizome_manifest *m, const char *filename, char append);
|
||||
int rhizome_manifest_selfsign(rhizome_manifest *m);
|
||||
int rhizome_read_manifest_from_file(rhizome_manifest *m, const char *filename);
|
||||
|
@ -1086,17 +1086,23 @@ int rhizome_manifest_dump(rhizome_manifest *m, const char *msg)
|
||||
enum rhizome_bundle_status rhizome_manifest_finalise(rhizome_manifest *m, rhizome_manifest **mout, int deduplicate)
|
||||
{
|
||||
IN();
|
||||
|
||||
assert(*mout == NULL);
|
||||
if (!m->finalised && !rhizome_manifest_validate(m))
|
||||
RETURN(RHIZOME_BUNDLE_STATUS_INVALID);
|
||||
|
||||
// if a manifest was supplied with an ID, don't bother to check for a duplicate.
|
||||
// we only want to filter out added files with no existing manifest.
|
||||
if (deduplicate && m->haveSecret != EXISTING_BUNDLE_ID) {
|
||||
enum rhizome_bundle_status status = rhizome_find_duplicate(m, mout);
|
||||
switch (status) {
|
||||
case RHIZOME_BUNDLE_STATUS_DUPLICATE:
|
||||
assert(*mout != NULL);
|
||||
assert(*mout != m);
|
||||
RETURN(status);
|
||||
case RHIZOME_BUNDLE_STATUS_ERROR:
|
||||
if (*mout != NULL && *mout != m) {
|
||||
rhizome_manifest_free(*mout);
|
||||
*mout = NULL;
|
||||
}
|
||||
RETURN(status);
|
||||
case RHIZOME_BUNDLE_STATUS_NEW:
|
||||
break;
|
||||
@ -1104,6 +1110,7 @@ enum rhizome_bundle_status rhizome_manifest_finalise(rhizome_manifest *m, rhizom
|
||||
FATALF("rhizome_find_duplicate() returned %d", status);
|
||||
}
|
||||
}
|
||||
assert(*mout == NULL);
|
||||
*mout = m;
|
||||
|
||||
/* Convert to final form for signing and writing to disk */
|
||||
|
@ -600,7 +600,6 @@ int rhizome_crypt_xor_block(unsigned char *buffer, size_t buffer_size, uint64_t
|
||||
*/
|
||||
int rhizome_derive_payload_key(rhizome_manifest *m)
|
||||
{
|
||||
// don't do anything if the manifest isn't flagged as being encrypted
|
||||
assert(m->payloadEncryption == PAYLOAD_ENCRYPTED);
|
||||
unsigned char hash[crypto_hash_sha512_BYTES];
|
||||
if (m->has_sender && m->has_recipient) {
|
||||
|
@ -1272,10 +1272,7 @@ int rhizome_cleanup(struct rhizome_cleanup_report *report)
|
||||
int rhizome_store_manifest(rhizome_manifest *m)
|
||||
{
|
||||
assert(m->finalised);
|
||||
|
||||
// If we don't have the secret for this manifest, only store it if its self-signature is valid
|
||||
if (!m->haveSecret && !m->selfSigned)
|
||||
return WHY("Manifest is not signed, and I don't have the key. Manifest might be forged or corrupt.");
|
||||
assert(m->haveSecret || m->selfSigned); // should not store an invalid or fake manifest
|
||||
|
||||
/* Bind BAR to data field */
|
||||
rhizome_bar_t bar;
|
||||
|
@ -119,9 +119,10 @@ static int rhizome_direct_import_end(struct http_request *hr)
|
||||
case RHIZOME_BUNDLE_STATUS_FAKE:
|
||||
http_request_simple_response(&r->http, 403, "Manifest not signed");
|
||||
return 0;
|
||||
case RHIZOME_BUNDLE_STATUS_DONOTWANT:
|
||||
case RHIZOME_BUNDLE_STATUS_NO_ROOM:
|
||||
http_request_simple_response(&r->http, 403, "Not enough space");
|
||||
return 0;
|
||||
case RHIZOME_BUNDLE_STATUS_READONLY:
|
||||
case RHIZOME_BUNDLE_STATUS_DUPLICATE:
|
||||
case RHIZOME_BUNDLE_STATUS_ERROR:
|
||||
break;
|
||||
@ -729,17 +730,20 @@ void rhizome_direct_http_dispatch(rhizome_direct_sync_request *r)
|
||||
switch (pstatus) {
|
||||
case RHIZOME_PAYLOAD_STATUS_EMPTY:
|
||||
case RHIZOME_PAYLOAD_STATUS_STORED:
|
||||
break;
|
||||
goto pstatus_ok;
|
||||
case RHIZOME_PAYLOAD_STATUS_NEW:
|
||||
case RHIZOME_PAYLOAD_STATUS_ERROR:
|
||||
case RHIZOME_PAYLOAD_STATUS_WRONG_SIZE:
|
||||
case RHIZOME_PAYLOAD_STATUS_WRONG_HASH:
|
||||
case RHIZOME_PAYLOAD_STATUS_CRYPTO_FAIL:
|
||||
case RHIZOME_PAYLOAD_STATUS_TOO_BIG:
|
||||
case RHIZOME_PAYLOAD_STATUS_EVICTED:
|
||||
goto closeit;
|
||||
default:
|
||||
FATALF("pstatus = %d", pstatus);
|
||||
// No "default" label, so the compiler will warn us if a case is not handled.
|
||||
}
|
||||
|
||||
FATALF("pstatus = %d", pstatus);
|
||||
pstatus_ok:
|
||||
;
|
||||
uint64_t read_ofs;
|
||||
for(read_ofs=0;read_ofs<m->filesize;){
|
||||
unsigned char buffer[4096];
|
||||
|
@ -553,10 +553,10 @@ schedule_fetch(struct rhizome_fetch_slot *slot)
|
||||
case RHIZOME_PAYLOAD_STATUS_STORED:
|
||||
RETURN(IMPORTED);
|
||||
case RHIZOME_PAYLOAD_STATUS_TOO_BIG:
|
||||
case RHIZOME_PAYLOAD_STATUS_UNINITERESTING:
|
||||
case RHIZOME_PAYLOAD_STATUS_EVICTED:
|
||||
RETURN(DONOTWANT);
|
||||
case RHIZOME_PAYLOAD_STATUS_NEW:
|
||||
break;
|
||||
goto status_ok;
|
||||
case RHIZOME_PAYLOAD_STATUS_ERROR:
|
||||
RETURN(WHY("error writing new payload"));
|
||||
case RHIZOME_PAYLOAD_STATUS_WRONG_SIZE:
|
||||
@ -565,9 +565,11 @@ schedule_fetch(struct rhizome_fetch_slot *slot)
|
||||
RETURN(WHY("payload hash does not match"));
|
||||
case RHIZOME_PAYLOAD_STATUS_CRYPTO_FAIL:
|
||||
RETURN(WHY("payload cannot be encrypted"));
|
||||
default:
|
||||
FATALF("status = %d", status);
|
||||
// No "default" label, so the compiler will warn if a case is not handled.
|
||||
}
|
||||
FATALF("status = %d", status);
|
||||
status_ok:
|
||||
;
|
||||
} else {
|
||||
strbuf r = strbuf_local(slot->request, sizeof slot->request);
|
||||
strbuf_sprintf(r, "GET /rhizome/manifestbyprefix/%s HTTP/1.0\r\n\r\n", alloca_tohex(slot->bid.binary, slot->prefix_length));
|
||||
|
@ -63,11 +63,93 @@ static int strn_to_list_token(const char *str, uint64_t *rowidp, const char **af
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int http_request_rhizome_response(struct httpd_request *r, uint16_t result, const char *message, const char *payload_status_message)
|
||||
{
|
||||
uint16_t rhizome_result = 0;
|
||||
switch (r->bundle_status) {
|
||||
case RHIZOME_BUNDLE_STATUS_NEW:
|
||||
rhizome_result = 201;
|
||||
break;
|
||||
case RHIZOME_BUNDLE_STATUS_SAME:
|
||||
case RHIZOME_BUNDLE_STATUS_DUPLICATE:
|
||||
case RHIZOME_BUNDLE_STATUS_OLD:
|
||||
case RHIZOME_BUNDLE_STATUS_NO_ROOM:
|
||||
rhizome_result = 200;
|
||||
break;
|
||||
case RHIZOME_BUNDLE_STATUS_INVALID:
|
||||
case RHIZOME_BUNDLE_STATUS_FAKE:
|
||||
case RHIZOME_BUNDLE_STATUS_INCONSISTENT:
|
||||
case RHIZOME_BUNDLE_STATUS_READONLY:
|
||||
rhizome_result = 403;
|
||||
break;
|
||||
case RHIZOME_BUNDLE_STATUS_ERROR:
|
||||
rhizome_result = 500;
|
||||
break;
|
||||
}
|
||||
if (rhizome_result) {
|
||||
r->http.response.result_extra[0].label = "rhizome_bundle_status_code";
|
||||
r->http.response.result_extra[0].value.type = JSON_INTEGER;
|
||||
r->http.response.result_extra[0].value.u.integer = r->bundle_status;
|
||||
const char *status_message = rhizome_bundle_status_message(r->bundle_status);
|
||||
if (status_message) {
|
||||
r->http.response.result_extra[1].label = "rhizome_bundle_status_message";
|
||||
r->http.response.result_extra[1].value.type = JSON_STRING_NULTERM;
|
||||
r->http.response.result_extra[1].value.u.string.content = status_message;
|
||||
}
|
||||
if (rhizome_result > result) {
|
||||
result = rhizome_result;
|
||||
message = NULL;
|
||||
}
|
||||
}
|
||||
rhizome_result = 0;
|
||||
switch (r->payload_status) {
|
||||
case RHIZOME_PAYLOAD_STATUS_NEW:
|
||||
rhizome_result = 201;
|
||||
break;
|
||||
case RHIZOME_PAYLOAD_STATUS_STORED:
|
||||
case RHIZOME_PAYLOAD_STATUS_EMPTY:
|
||||
case RHIZOME_PAYLOAD_STATUS_TOO_BIG:
|
||||
case RHIZOME_PAYLOAD_STATUS_EVICTED:
|
||||
rhizome_result = 200;
|
||||
break;
|
||||
case RHIZOME_PAYLOAD_STATUS_WRONG_SIZE:
|
||||
case RHIZOME_PAYLOAD_STATUS_WRONG_HASH:
|
||||
case RHIZOME_PAYLOAD_STATUS_CRYPTO_FAIL:
|
||||
rhizome_result = 403;
|
||||
break;
|
||||
case RHIZOME_PAYLOAD_STATUS_ERROR:
|
||||
rhizome_result = 500;
|
||||
break;
|
||||
}
|
||||
if (rhizome_result) {
|
||||
r->http.response.result_extra[2].label = "rhizome_payload_status_code";
|
||||
r->http.response.result_extra[2].value.type = JSON_INTEGER;
|
||||
r->http.response.result_extra[2].value.u.integer = r->payload_status;
|
||||
const char *status_message = payload_status_message ? payload_status_message : rhizome_payload_status_message(r->payload_status);
|
||||
if (status_message) {
|
||||
r->http.response.result_extra[3].label = "rhizome_payload_status_message";
|
||||
r->http.response.result_extra[3].value.type = JSON_STRING_NULTERM;
|
||||
r->http.response.result_extra[3].value.u.string.content = status_message;
|
||||
}
|
||||
if (rhizome_result > result) {
|
||||
result = rhizome_result;
|
||||
message = NULL;
|
||||
}
|
||||
}
|
||||
if (result == 0) {
|
||||
result = 500;
|
||||
message = NULL;
|
||||
}
|
||||
http_request_simple_response(&r->http, result, message ? message : result == 403 ? "Rhizome operation failed" : NULL);
|
||||
return result;
|
||||
}
|
||||
|
||||
static HTTP_CONTENT_GENERATOR restful_rhizome_bundlelist_json_content;
|
||||
|
||||
int restful_rhizome_bundlelist_json(httpd_request *r, const char *remainder)
|
||||
{
|
||||
r->http.response.header.content_type = CONTENT_TYPE_JSON;
|
||||
r->http.render_extra_headers = render_manifest_headers;
|
||||
if (!is_rhizome_http_enabled())
|
||||
return 403;
|
||||
if (*remainder)
|
||||
@ -242,6 +324,7 @@ static int insert_mime_part_body(struct http_request *, char *, size_t);
|
||||
int restful_rhizome_insert(httpd_request *r, const char *remainder)
|
||||
{
|
||||
r->http.response.header.content_type = CONTENT_TYPE_JSON;
|
||||
r->http.render_extra_headers = render_manifest_headers;
|
||||
if (*remainder)
|
||||
return 404;
|
||||
if (!is_rhizome_http_enabled())
|
||||
@ -300,8 +383,7 @@ static int insert_make_manifest(httpd_request *r)
|
||||
return 0;
|
||||
// fall through
|
||||
case 1:
|
||||
http_request_simple_response(&r->http, 403, "Malformed manifest");
|
||||
return 403;
|
||||
return http_request_rhizome_response(r, 403, "Malformed manifest", NULL);
|
||||
default:
|
||||
WHYF("rhizome_manifest_parse() returned %d", n);
|
||||
break;
|
||||
@ -355,17 +437,17 @@ static int insert_mime_part_header(struct http_request *hr, const struct mime_pa
|
||||
rhizome_manifest_set_name_from_path(r->manifest, h->content_disposition.filename);
|
||||
// Start writing the payload content into the Rhizome store. Note: r->manifest->filesize can be
|
||||
// RHIZOME_SIZE_UNSET at this point, if the manifest did not contain a 'filesize' field.
|
||||
r->u.insert.payload_status = rhizome_write_open_manifest(&r->u.insert.write, r->manifest);
|
||||
r->payload_status = rhizome_write_open_manifest(&r->u.insert.write, r->manifest);
|
||||
r->u.insert.payload_size = 0;
|
||||
switch (r->u.insert.payload_status) {
|
||||
switch (r->payload_status) {
|
||||
case RHIZOME_PAYLOAD_STATUS_ERROR:
|
||||
WHYF("rhizome_write_open_manifest() returned %d", r->u.insert.payload_status);
|
||||
WHYF("rhizome_write_open_manifest() returned %d", r->payload_status);
|
||||
return 500;
|
||||
case RHIZOME_PAYLOAD_STATUS_STORED:
|
||||
// TODO: initialise payload hash so it can be compared with stored payload
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
break; // r->payload_status gets dealt with later
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -395,7 +477,7 @@ static int insert_mime_part_body(struct http_request *hr, char *buf, size_t len)
|
||||
}
|
||||
else if (r->u.insert.current_part == PART_PAYLOAD) {
|
||||
r->u.insert.payload_size += len;
|
||||
switch (r->u.insert.payload_status) {
|
||||
switch (r->payload_status) {
|
||||
case RHIZOME_PAYLOAD_STATUS_NEW:
|
||||
if (rhizome_write_buffer(&r->u.insert.write, (unsigned char *)buf, len) == -1)
|
||||
return 500;
|
||||
@ -445,19 +527,25 @@ static int insert_mime_part_end(struct http_request *hr)
|
||||
WHY("rhizome_fill_manifest() failed");
|
||||
return 500;
|
||||
}
|
||||
if (r->manifest->is_journal) {
|
||||
http_request_simple_response(&r->http, 403, "Insert not supported for journals");
|
||||
return 403;
|
||||
}
|
||||
if (r->manifest->is_journal)
|
||||
return http_request_rhizome_response(r, 403, "Insert not supported for journals", NULL);
|
||||
assert(r->manifest != NULL);
|
||||
}
|
||||
else if (r->u.insert.current_part == PART_PAYLOAD) {
|
||||
r->u.insert.received_payload = 1;
|
||||
if (r->u.insert.payload_status == RHIZOME_PAYLOAD_STATUS_NEW)
|
||||
r->u.insert.payload_status = rhizome_finish_write(&r->u.insert.write);
|
||||
if (r->u.insert.payload_status == RHIZOME_PAYLOAD_STATUS_ERROR) {
|
||||
WHYF("rhizome_finish_write() returned status = %d", r->u.insert.payload_status);
|
||||
return 500;
|
||||
switch (r->payload_status) {
|
||||
case RHIZOME_PAYLOAD_STATUS_NEW:
|
||||
r->payload_status = rhizome_finish_write(&r->u.insert.write);
|
||||
if (r->payload_status == RHIZOME_PAYLOAD_STATUS_ERROR) {
|
||||
WHYF("rhizome_finish_write() returned status = %d", r->payload_status);
|
||||
return 500;
|
||||
}
|
||||
break;
|
||||
case RHIZOME_PAYLOAD_STATUS_STORED:
|
||||
// TODO: finish calculating payload hash and compare it with stored payload
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} else
|
||||
FATALF("current_part = %s", alloca_str_toprint(r->u.insert.current_part));
|
||||
@ -475,40 +563,40 @@ static int restful_rhizome_insert_end(struct http_request *hr)
|
||||
// Fill in the missing manifest fields and ensure payload and manifest are consistent.
|
||||
assert(r->manifest != NULL);
|
||||
assert(r->u.insert.write.file_length != RHIZOME_SIZE_UNSET);
|
||||
switch (r->u.insert.payload_status) {
|
||||
case RHIZOME_PAYLOAD_STATUS_ERROR:
|
||||
return 500;
|
||||
int status_valid = 0;
|
||||
switch (r->payload_status) {
|
||||
case RHIZOME_PAYLOAD_STATUS_NEW:
|
||||
status_valid = 1;
|
||||
if (r->manifest->filesize == RHIZOME_SIZE_UNSET)
|
||||
rhizome_manifest_set_filesize(r->manifest, r->u.insert.write.file_length);
|
||||
// fall through
|
||||
case RHIZOME_PAYLOAD_STATUS_STORED:
|
||||
status_valid = 1;
|
||||
// TODO: check that stored hash matches received payload's hash
|
||||
// fall through
|
||||
case RHIZOME_PAYLOAD_STATUS_EMPTY:
|
||||
status_valid = 1;
|
||||
assert(r->manifest->filesize != RHIZOME_SIZE_UNSET);
|
||||
if (r->u.insert.payload_size == r->manifest->filesize)
|
||||
break;
|
||||
// fall through
|
||||
case RHIZOME_PAYLOAD_STATUS_WRONG_SIZE:
|
||||
r->payload_status = RHIZOME_PAYLOAD_STATUS_WRONG_SIZE;
|
||||
status_valid = 1;
|
||||
{
|
||||
strbuf msg = strbuf_alloca(200);
|
||||
strbuf_sprintf(msg, "Payload size (%"PRIu64") contradicts manifest (filesize=%"PRIu64")", r->u.insert.payload_size, r->manifest->filesize);
|
||||
http_request_simple_response(&r->http, 403, strbuf_str(msg));
|
||||
return 403;
|
||||
return http_request_rhizome_response(r, 403, NULL, strbuf_str(msg));
|
||||
}
|
||||
case RHIZOME_PAYLOAD_STATUS_TOO_BIG:
|
||||
case RHIZOME_PAYLOAD_STATUS_UNINITERESTING:
|
||||
http_request_simple_response(&r->http, 403, "Not enough space");
|
||||
return 403;
|
||||
case RHIZOME_PAYLOAD_STATUS_EVICTED:
|
||||
case RHIZOME_PAYLOAD_STATUS_WRONG_HASH:
|
||||
http_request_simple_response(&r->http, 403, "Payload hash contradicts manifest");
|
||||
return 403;
|
||||
case RHIZOME_PAYLOAD_STATUS_CRYPTO_FAIL:
|
||||
http_request_simple_response(&r->http, 403, "Missing bundle secret");
|
||||
return 403;
|
||||
default:
|
||||
FATALF("payload_status = %d", r->u.insert.payload_status);
|
||||
case RHIZOME_PAYLOAD_STATUS_ERROR:
|
||||
return http_request_rhizome_response(r, 403, NULL, NULL);
|
||||
}
|
||||
if (!status_valid) {
|
||||
WHYF("r->payload_status = %d", r->payload_status);
|
||||
return http_request_rhizome_response(r, 500, NULL, NULL);
|
||||
}
|
||||
// Finalise the manifest and add it to the store.
|
||||
if (r->manifest->filesize) {
|
||||
@ -526,35 +614,36 @@ static int restful_rhizome_insert_end(struct http_request *hr)
|
||||
return 403;
|
||||
}
|
||||
rhizome_manifest *mout = NULL;
|
||||
int result;
|
||||
switch (rhizome_manifest_finalise(r->manifest, &mout, !r->u.insert.force_new)) {
|
||||
r->bundle_status = rhizome_manifest_finalise(r->manifest, &mout, !r->u.insert.force_new);
|
||||
int result = 500;
|
||||
switch (r->bundle_status) {
|
||||
case RHIZOME_BUNDLE_STATUS_NEW:
|
||||
result = 201;
|
||||
if (mout && mout != r->manifest)
|
||||
rhizome_manifest_free(mout);
|
||||
mout = NULL;
|
||||
result = 201;
|
||||
break;
|
||||
case RHIZOME_BUNDLE_STATUS_SAME:
|
||||
case RHIZOME_BUNDLE_STATUS_OLD:
|
||||
case RHIZOME_BUNDLE_STATUS_DUPLICATE:
|
||||
if (mout && mout != r->manifest) {
|
||||
rhizome_manifest_free(r->manifest);
|
||||
r->manifest = mout;
|
||||
}
|
||||
result = 200;
|
||||
break;
|
||||
case RHIZOME_BUNDLE_STATUS_INVALID:
|
||||
result = 403;
|
||||
break;
|
||||
case RHIZOME_BUNDLE_STATUS_FAKE:
|
||||
case RHIZOME_BUNDLE_STATUS_INCONSISTENT:
|
||||
case RHIZOME_BUNDLE_STATUS_NO_ROOM:
|
||||
case RHIZOME_BUNDLE_STATUS_READONLY:
|
||||
case RHIZOME_BUNDLE_STATUS_ERROR:
|
||||
default:
|
||||
result = 500;
|
||||
break;
|
||||
if (mout && mout != r->manifest)
|
||||
rhizome_manifest_free(mout);
|
||||
return http_request_rhizome_response(r, 0, NULL, NULL);
|
||||
}
|
||||
if (mout && mout != r->manifest) {
|
||||
rhizome_manifest_free(r->manifest);
|
||||
r->manifest = mout;
|
||||
}
|
||||
if (result >= 400)
|
||||
return result;
|
||||
if (result == 500)
|
||||
FATALF("rhizome_manifest_finalise() returned status = %d", r->bundle_status);
|
||||
rhizome_authenticate_author(r->manifest);
|
||||
r->http.render_extra_headers = render_manifest_headers;
|
||||
http_request_response_static(&r->http, result, "rhizome-manifest/text",
|
||||
(const char *)r->manifest->manifestdata, r->manifest->manifest_all_bytes
|
||||
);
|
||||
@ -568,6 +657,7 @@ static HTTP_HANDLER restful_rhizome_bid_decrypted_bin;
|
||||
int restful_rhizome_(httpd_request *r, const char *remainder)
|
||||
{
|
||||
r->http.response.header.content_type = CONTENT_TYPE_JSON;
|
||||
r->http.render_extra_headers = render_manifest_headers;
|
||||
if (!is_rhizome_http_enabled())
|
||||
return 403;
|
||||
HTTP_HANDLER *handler = NULL;
|
||||
@ -598,15 +688,16 @@ int restful_rhizome_(httpd_request *r, const char *remainder)
|
||||
if (ret == -1) {
|
||||
rhizome_manifest_free(r->manifest);
|
||||
r->manifest = NULL;
|
||||
r->bundle_status = RHIZOME_BUNDLE_STATUS_ERROR;
|
||||
return 500;
|
||||
}
|
||||
if (ret == 0) {
|
||||
rhizome_authenticate_author(r->manifest);
|
||||
r->http.render_extra_headers = render_manifest_headers;
|
||||
r->bundle_status = RHIZOME_BUNDLE_STATUS_SAME;
|
||||
} else {
|
||||
r->bundle_status = RHIZOME_BUNDLE_STATUS_NEW;
|
||||
rhizome_manifest_free(r->manifest);
|
||||
r->manifest = NULL;
|
||||
assert(r->http.render_extra_headers == NULL);
|
||||
}
|
||||
ret = handler(r, remainder);
|
||||
return ret;
|
||||
@ -614,8 +705,10 @@ int restful_rhizome_(httpd_request *r, const char *remainder)
|
||||
|
||||
static int restful_rhizome_bid_rhm(httpd_request *r, const char *remainder)
|
||||
{
|
||||
if (*remainder || r->manifest == NULL)
|
||||
if (*remainder)
|
||||
return 404;
|
||||
if (r->manifest == NULL)
|
||||
return http_request_rhizome_response(r, 404, NULL, NULL);
|
||||
http_request_response_static(&r->http, 200, "rhizome-manifest/text",
|
||||
(const char *)r->manifest->manifestdata, r->manifest->manifest_all_bytes
|
||||
);
|
||||
@ -624,8 +717,10 @@ static int restful_rhizome_bid_rhm(httpd_request *r, const char *remainder)
|
||||
|
||||
static int restful_rhizome_bid_raw_bin(httpd_request *r, const char *remainder)
|
||||
{
|
||||
if (*remainder || r->manifest == NULL)
|
||||
if (*remainder)
|
||||
return 404;
|
||||
if (r->manifest == NULL)
|
||||
return http_request_rhizome_response(r, 404, NULL, NULL);
|
||||
if (r->manifest->filesize == 0) {
|
||||
http_request_response_static(&r->http, 200, CONTENT_TYPE_BLOB, "", 0);
|
||||
return 1;
|
||||
@ -639,8 +734,10 @@ static int restful_rhizome_bid_raw_bin(httpd_request *r, const char *remainder)
|
||||
|
||||
static int restful_rhizome_bid_decrypted_bin(httpd_request *r, const char *remainder)
|
||||
{
|
||||
if (*remainder || r->manifest == NULL)
|
||||
if (*remainder)
|
||||
return 404;
|
||||
if (r->manifest == NULL)
|
||||
return http_request_rhizome_response(r, 404, 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);
|
||||
@ -685,22 +782,22 @@ int rhizome_response_content_init_filehash(httpd_request *r, const rhizome_fileh
|
||||
r->u.read_state.blob_fd = -1;
|
||||
assert(r->finalise_union == NULL);
|
||||
r->finalise_union = finalise_union_read_state;
|
||||
enum rhizome_payload_status status = rhizome_open_read(&r->u.read_state, hash);
|
||||
switch (status) {
|
||||
r->payload_status = rhizome_open_read(&r->u.read_state, hash);
|
||||
switch (r->payload_status) {
|
||||
case RHIZOME_PAYLOAD_STATUS_EMPTY:
|
||||
case RHIZOME_PAYLOAD_STATUS_STORED:
|
||||
break;
|
||||
return rhizome_response_content_init_read_state(r);
|
||||
case RHIZOME_PAYLOAD_STATUS_NEW:
|
||||
return 404;
|
||||
return 403;
|
||||
case RHIZOME_PAYLOAD_STATUS_ERROR:
|
||||
case RHIZOME_PAYLOAD_STATUS_WRONG_SIZE:
|
||||
case RHIZOME_PAYLOAD_STATUS_WRONG_HASH:
|
||||
case RHIZOME_PAYLOAD_STATUS_CRYPTO_FAIL:
|
||||
case RHIZOME_PAYLOAD_STATUS_TOO_BIG:
|
||||
case RHIZOME_PAYLOAD_STATUS_EVICTED:
|
||||
return -1;
|
||||
default:
|
||||
FATALF("status = %d", status);
|
||||
}
|
||||
return rhizome_response_content_init_read_state(r);
|
||||
FATALF("rhizome_open_read() returned status = %d", r->payload_status);
|
||||
}
|
||||
|
||||
int rhizome_response_content_init_payload(httpd_request *r, rhizome_manifest *m)
|
||||
@ -709,22 +806,22 @@ int rhizome_response_content_init_payload(httpd_request *r, rhizome_manifest *m)
|
||||
r->u.read_state.blob_fd = -1;
|
||||
assert(r->finalise_union == NULL);
|
||||
r->finalise_union = finalise_union_read_state;
|
||||
enum rhizome_payload_status status = rhizome_open_decrypt_read(m, &r->u.read_state);
|
||||
switch (status) {
|
||||
r->payload_status = rhizome_open_decrypt_read(m, &r->u.read_state);
|
||||
switch (r->payload_status) {
|
||||
case RHIZOME_PAYLOAD_STATUS_EMPTY:
|
||||
case RHIZOME_PAYLOAD_STATUS_STORED:
|
||||
break;
|
||||
return rhizome_response_content_init_read_state(r);
|
||||
case RHIZOME_PAYLOAD_STATUS_NEW:
|
||||
return 404;
|
||||
case RHIZOME_PAYLOAD_STATUS_CRYPTO_FAIL:
|
||||
return 403;
|
||||
case RHIZOME_PAYLOAD_STATUS_ERROR:
|
||||
case RHIZOME_PAYLOAD_STATUS_WRONG_SIZE:
|
||||
case RHIZOME_PAYLOAD_STATUS_WRONG_HASH:
|
||||
case RHIZOME_PAYLOAD_STATUS_CRYPTO_FAIL:
|
||||
case RHIZOME_PAYLOAD_STATUS_TOO_BIG:
|
||||
case RHIZOME_PAYLOAD_STATUS_EVICTED:
|
||||
return -1;
|
||||
default:
|
||||
FATALF("status = %d", status);
|
||||
}
|
||||
return rhizome_response_content_init_read_state(r);
|
||||
FATALF("rhizome_open_decrypt_read() returned status = %d", r->payload_status);
|
||||
}
|
||||
|
||||
int rhizome_payload_content(struct http_request *hr, unsigned char *buf, size_t bufsz, struct http_content_generator_result *result)
|
||||
@ -758,49 +855,58 @@ int rhizome_payload_content(struct http_request *hr, unsigned char *buf, size_t
|
||||
static void render_manifest_headers(struct http_request *hr, strbuf sb)
|
||||
{
|
||||
httpd_request *r = (httpd_request *) hr;
|
||||
const char *status_message;
|
||||
if ((status_message = rhizome_bundle_status_message(r->bundle_status))) {
|
||||
strbuf_sprintf(sb, "Serval-Rhizome-Result-Bundle-Status-Code: %d\r\n", r->bundle_status);
|
||||
strbuf_sprintf(sb, "Serval-Rhizome-Result-Bundle-Status-Message: %s\r\n", status_message);
|
||||
}
|
||||
if ((status_message = rhizome_payload_status_message(r->payload_status))) {
|
||||
strbuf_sprintf(sb, "Serval-Rhizome-Result-Payload-Status-Code: %d\r\n", r->payload_status);
|
||||
strbuf_sprintf(sb, "Serval-Rhizome-Result-Payload-Status-Message: %s\r\n", status_message);
|
||||
}
|
||||
rhizome_manifest *m = r->manifest;
|
||||
strbuf_sprintf(sb, "Serval-Rhizome-Bundle-Id: %s\r\n", alloca_tohex_rhizome_bid_t(m->cryptoSignPublic));
|
||||
strbuf_sprintf(sb, "Serval-Rhizome-Bundle-Version: %"PRIu64"\r\n", m->version);
|
||||
strbuf_sprintf(sb, "Serval-Rhizome-Bundle-Filesize: %"PRIu64"\r\n", m->filesize);
|
||||
if (m->filesize != 0)
|
||||
strbuf_sprintf(sb, "Serval-Rhizome-Bundle-Filehash: %s\r\n", alloca_tohex_rhizome_filehash_t(m->filehash));
|
||||
if (m->has_sender)
|
||||
strbuf_sprintf(sb, "Serval-Rhizome-Bundle-Sender: %s\r\n", alloca_tohex_sid_t(m->sender));
|
||||
if (m->has_recipient)
|
||||
strbuf_sprintf(sb, "Serval-Rhizome-Bundle-Recipient: %s\r\n", alloca_tohex_sid_t(m->recipient));
|
||||
if (m->has_bundle_key)
|
||||
strbuf_sprintf(sb, "Serval-Rhizome-Bundle-BK: %s\r\n", alloca_tohex_rhizome_bk_t(m->bundle_key));
|
||||
switch (m->payloadEncryption) {
|
||||
case PAYLOAD_CRYPT_UNKNOWN:
|
||||
break;
|
||||
case PAYLOAD_CLEAR:
|
||||
strbuf_sprintf(sb, "Serval-Rhizome-Bundle-Crypt: 0\r\n");
|
||||
break;
|
||||
case PAYLOAD_ENCRYPTED:
|
||||
strbuf_sprintf(sb, "Serval-Rhizome-Bundle-Crypt: 1\r\n");
|
||||
break;
|
||||
if (m) {
|
||||
strbuf_sprintf(sb, "Serval-Rhizome-Bundle-Id: %s\r\n", alloca_tohex_rhizome_bid_t(m->cryptoSignPublic));
|
||||
strbuf_sprintf(sb, "Serval-Rhizome-Bundle-Version: %"PRIu64"\r\n", m->version);
|
||||
strbuf_sprintf(sb, "Serval-Rhizome-Bundle-Filesize: %"PRIu64"\r\n", m->filesize);
|
||||
if (m->filesize != 0)
|
||||
strbuf_sprintf(sb, "Serval-Rhizome-Bundle-Filehash: %s\r\n", alloca_tohex_rhizome_filehash_t(m->filehash));
|
||||
if (m->has_sender)
|
||||
strbuf_sprintf(sb, "Serval-Rhizome-Bundle-Sender: %s\r\n", alloca_tohex_sid_t(m->sender));
|
||||
if (m->has_recipient)
|
||||
strbuf_sprintf(sb, "Serval-Rhizome-Bundle-Recipient: %s\r\n", alloca_tohex_sid_t(m->recipient));
|
||||
if (m->has_bundle_key)
|
||||
strbuf_sprintf(sb, "Serval-Rhizome-Bundle-BK: %s\r\n", alloca_tohex_rhizome_bk_t(m->bundle_key));
|
||||
switch (m->payloadEncryption) {
|
||||
case PAYLOAD_CRYPT_UNKNOWN:
|
||||
break;
|
||||
case PAYLOAD_CLEAR:
|
||||
strbuf_sprintf(sb, "Serval-Rhizome-Bundle-Crypt: 0\r\n");
|
||||
break;
|
||||
case PAYLOAD_ENCRYPTED:
|
||||
strbuf_sprintf(sb, "Serval-Rhizome-Bundle-Crypt: 1\r\n");
|
||||
break;
|
||||
}
|
||||
if (m->is_journal)
|
||||
strbuf_sprintf(sb, "Serval-Rhizome-Bundle-Tail: %"PRIu64"\r\n", m->tail);
|
||||
if (m->has_date)
|
||||
strbuf_sprintf(sb, "Serval-Rhizome-Bundle-Date: %"PRIu64"\r\n", m->date);
|
||||
if (m->name) {
|
||||
strbuf_puts(sb, "Serval-Rhizome-Bundle-Name: ");
|
||||
strbuf_append_quoted_string(sb, m->name);
|
||||
strbuf_puts(sb, "\r\n");
|
||||
}
|
||||
if (m->service)
|
||||
strbuf_sprintf(sb, "Serval-Rhizome-Bundle-Service: %s\r\n", m->service);
|
||||
assert(m->authorship != AUTHOR_LOCAL);
|
||||
if (m->authorship == AUTHOR_AUTHENTIC)
|
||||
strbuf_sprintf(sb, "Serval-Rhizome-Bundle-Author: %s\r\n", alloca_tohex_sid_t(m->author));
|
||||
if (m->haveSecret) {
|
||||
char secret[RHIZOME_BUNDLE_KEY_STRLEN + 1];
|
||||
rhizome_bytes_to_hex_upper(m->cryptoSignSecret, secret, RHIZOME_BUNDLE_KEY_BYTES);
|
||||
strbuf_sprintf(sb, "Serval-Rhizome-Bundle-Secret: %s\r\n", secret);
|
||||
}
|
||||
strbuf_sprintf(sb, "Serval-Rhizome-Bundle-Rowid: %"PRIu64"\r\n", m->rowid);
|
||||
strbuf_sprintf(sb, "Serval-Rhizome-Bundle-Inserttime: %"PRIu64"\r\n", m->inserttime);
|
||||
}
|
||||
if (m->is_journal)
|
||||
strbuf_sprintf(sb, "Serval-Rhizome-Bundle-Tail: %"PRIu64"\r\n", m->tail);
|
||||
if (m->has_date)
|
||||
strbuf_sprintf(sb, "Serval-Rhizome-Bundle-Date: %"PRIu64"\r\n", m->date);
|
||||
if (m->name) {
|
||||
strbuf_puts(sb, "Serval-Rhizome-Bundle-Name: ");
|
||||
strbuf_append_quoted_string(sb, m->name);
|
||||
strbuf_puts(sb, "\r\n");
|
||||
}
|
||||
if (m->service)
|
||||
strbuf_sprintf(sb, "Serval-Rhizome-Bundle-Service: %s\r\n", m->service);
|
||||
assert(m->authorship != AUTHOR_LOCAL);
|
||||
if (m->authorship == AUTHOR_AUTHENTIC)
|
||||
strbuf_sprintf(sb, "Serval-Rhizome-Bundle-Author: %s\r\n", alloca_tohex_sid_t(m->author));
|
||||
assert(m->haveSecret);
|
||||
{
|
||||
char secret[RHIZOME_BUNDLE_KEY_STRLEN + 1];
|
||||
rhizome_bytes_to_hex_upper(m->cryptoSignSecret, secret, RHIZOME_BUNDLE_KEY_BYTES);
|
||||
strbuf_sprintf(sb, "Serval-Rhizome-Bundle-Secret: %s\r\n", secret);
|
||||
}
|
||||
strbuf_sprintf(sb, "Serval-Rhizome-Bundle-Rowid: %"PRIu64"\r\n", m->rowid);
|
||||
strbuf_sprintf(sb, "Serval-Rhizome-Bundle-Inserttime: %"PRIu64"\r\n", m->inserttime);
|
||||
}
|
||||
|
||||
|
@ -296,7 +296,7 @@ static enum rhizome_payload_status store_make_space(uint64_t bytes, struct rhizo
|
||||
DEBUGF("Not enough space for %"PRIu64". Used; %"PRIu64" = %"PRIu64" + %"PRIu64" * (%"PRIu64" - %"PRIu64"), Limit; %"PRIu64,
|
||||
bytes, db_used, external_bytes, db_page_size, db_page_count, db_free_page_count, limit);
|
||||
|
||||
return RHIZOME_PAYLOAD_STATUS_UNINITERESTING;
|
||||
return RHIZOME_PAYLOAD_STATUS_EVICTED;
|
||||
}
|
||||
|
||||
int rhizome_store_cleanup(struct rhizome_cleanup_report *report)
|
||||
@ -963,21 +963,23 @@ enum rhizome_payload_status rhizome_store_payload_file(rhizome_manifest *m, cons
|
||||
struct rhizome_write write;
|
||||
bzero(&write, sizeof(write));
|
||||
enum rhizome_payload_status status = rhizome_write_open_manifest(&write, m);
|
||||
int status_ok = 0;
|
||||
switch (status) {
|
||||
case RHIZOME_PAYLOAD_STATUS_EMPTY:
|
||||
case RHIZOME_PAYLOAD_STATUS_NEW:
|
||||
status_ok = 1;
|
||||
break;
|
||||
case RHIZOME_PAYLOAD_STATUS_STORED:
|
||||
case RHIZOME_PAYLOAD_STATUS_TOO_BIG:
|
||||
case RHIZOME_PAYLOAD_STATUS_UNINITERESTING:
|
||||
case RHIZOME_PAYLOAD_STATUS_EVICTED:
|
||||
case RHIZOME_PAYLOAD_STATUS_ERROR:
|
||||
case RHIZOME_PAYLOAD_STATUS_WRONG_SIZE:
|
||||
case RHIZOME_PAYLOAD_STATUS_WRONG_HASH:
|
||||
case RHIZOME_PAYLOAD_STATUS_CRYPTO_FAIL:
|
||||
return status;
|
||||
default:
|
||||
FATALF("status = %d", status);
|
||||
}
|
||||
if (!status_ok)
|
||||
FATALF("rhizome_write_open_manifest() returned status = %d", status);
|
||||
if (rhizome_write_file(&write, filepath) == -1) {
|
||||
rhizome_fail_write(&write);
|
||||
return RHIZOME_PAYLOAD_STATUS_ERROR;
|
||||
@ -987,26 +989,24 @@ enum rhizome_payload_status rhizome_store_payload_file(rhizome_manifest *m, cons
|
||||
case RHIZOME_PAYLOAD_STATUS_EMPTY:
|
||||
assert(write.file_length == 0);
|
||||
assert(m->filesize == 0);
|
||||
break;
|
||||
return status;
|
||||
case RHIZOME_PAYLOAD_STATUS_NEW:
|
||||
assert(m->filesize == write.file_length);
|
||||
if (m->has_filehash)
|
||||
assert(cmp_rhizome_filehash_t(&m->filehash, &write.id) == 0);
|
||||
else
|
||||
rhizome_manifest_set_filehash(m, &write.id);
|
||||
break;
|
||||
return status;
|
||||
case RHIZOME_PAYLOAD_STATUS_ERROR:
|
||||
case RHIZOME_PAYLOAD_STATUS_STORED:
|
||||
case RHIZOME_PAYLOAD_STATUS_WRONG_SIZE:
|
||||
case RHIZOME_PAYLOAD_STATUS_WRONG_HASH:
|
||||
case RHIZOME_PAYLOAD_STATUS_CRYPTO_FAIL:
|
||||
case RHIZOME_PAYLOAD_STATUS_TOO_BIG:
|
||||
case RHIZOME_PAYLOAD_STATUS_UNINITERESTING:
|
||||
break;
|
||||
default:
|
||||
FATALF("status = %d", status);
|
||||
case RHIZOME_PAYLOAD_STATUS_EVICTED:
|
||||
return status;
|
||||
}
|
||||
return status;
|
||||
FATALF("rhizome_finish_write() returned status = %d", status);
|
||||
}
|
||||
|
||||
/* Return RHIZOME_PAYLOAD_STATUS_STORED if file blob found, RHIZOME_PAYLOAD_STATUS_NEW if not found.
|
||||
|
@ -28,6 +28,8 @@ rexp_crypt='[01]'
|
||||
rexp_date='[0-9]\{1,\}'
|
||||
rexp_rowid='[0-9]\{1,\}'
|
||||
|
||||
BID_NONEXISTENT=0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF
|
||||
|
||||
assert_manifest_complete() {
|
||||
local manifest="$1"
|
||||
tfw_cat -v "$manifest"
|
||||
@ -552,3 +554,11 @@ rhizome_add_bundles() {
|
||||
[ "${ROWID[$n]}" -gt "${ROWID_MAX:-0}" ] && ROWID_MAX=${ROWID[$n]}
|
||||
done
|
||||
}
|
||||
|
||||
rhizome_delete_payload_blobs() {
|
||||
local filehash
|
||||
for filehash; do
|
||||
assert --message="Rhizome external blob file exists, filehash=$filehash" [ -e "$SERVALINSTANCE_PATH/blob/$filehash" ]
|
||||
rm -f "$SERVALINSTANCE_PATH/blob/$filehash"
|
||||
done
|
||||
}
|
||||
|
@ -225,19 +225,19 @@ test_RhizomeNewSince() {
|
||||
}
|
||||
|
||||
assert_http_response_headers() {
|
||||
local n=$1
|
||||
assertGrep --matches=1 http.headers$n "^Serval-Rhizome-Bundle-Id: ${BID[$n]}$CR\$"
|
||||
assertGrep --matches=1 http.headers$n "^Serval-Rhizome-Bundle-Version: ${VERSION[$n]}$CR\$"
|
||||
assertGrep --matches=1 http.headers$n "^Serval-Rhizome-Bundle-Filesize: ${SIZE[$n]}$CR\$"
|
||||
assertGrep --matches=1 http.headers$n "^Serval-Rhizome-Bundle-Filehash: ${HASH[$n]}$CR\$"
|
||||
assertGrep --matches=1 http.headers$n "^Serval-Rhizome-Bundle-BK: ${BK[$n]}$CR\$"
|
||||
assertGrep --matches=1 http.headers$n "^Serval-Rhizome-Bundle-Date: ${DATE[$n]}$CR\$"
|
||||
assertGrep --matches=1 http.headers$n "^Serval-Rhizome-Bundle-Name: \"${NAME[$n]}\"$CR\$"
|
||||
assertGrep --matches=1 http.headers$n "^Serval-Rhizome-Bundle-Service: file$CR\$"
|
||||
assertGrep --matches=1 http.headers$n "^Serval-Rhizome-Bundle-Author: ${AUTHOR[$n]}$CR\$"
|
||||
assertGrep --matches=1 http.headers$n "^Serval-Rhizome-Bundle-Secret: ${SECRET[$n]}$CR\$"
|
||||
assertGrep --matches=1 http.headers$n "^Serval-Rhizome-Bundle-Inserttime: ${INSERTTIME[$n]}$CR\$"
|
||||
assertGrep --matches=1 http.headers$n "^Serval-Rhizome-Bundle-Rowid: ${ROWID[$n]}$CR\$"
|
||||
local file="$1"
|
||||
assertGrep --matches=1 "$file" "^Serval-Rhizome-Bundle-Id: ${BID[$n]}$CR\$"
|
||||
assertGrep --matches=1 "$file" "^Serval-Rhizome-Bundle-Version: ${VERSION[$n]}$CR\$"
|
||||
assertGrep --matches=1 "$file" "^Serval-Rhizome-Bundle-Filesize: ${SIZE[$n]}$CR\$"
|
||||
assertGrep --matches=1 "$file" "^Serval-Rhizome-Bundle-Filehash: ${HASH[$n]}$CR\$"
|
||||
assertGrep --matches=1 "$file" "^Serval-Rhizome-Bundle-BK: ${BK[$n]}$CR\$"
|
||||
assertGrep --matches=1 "$file" "^Serval-Rhizome-Bundle-Date: ${DATE[$n]}$CR\$"
|
||||
assertGrep --matches=1 "$file" "^Serval-Rhizome-Bundle-Name: \"${NAME[$n]}\"$CR\$"
|
||||
assertGrep --matches=1 "$file" "^Serval-Rhizome-Bundle-Service: file$CR\$"
|
||||
assertGrep --matches=1 "$file" "^Serval-Rhizome-Bundle-Author: ${AUTHOR[$n]}$CR\$"
|
||||
assertGrep --matches=1 "$file" "^Serval-Rhizome-Bundle-Secret: ${SECRET[$n]}$CR\$"
|
||||
assertGrep --matches=1 "$file" "^Serval-Rhizome-Bundle-Inserttime: ${INSERTTIME[$n]}$CR\$"
|
||||
assertGrep --matches=1 "$file" "^Serval-Rhizome-Bundle-Rowid: ${ROWID[$n]}$CR\$"
|
||||
}
|
||||
|
||||
doc_RhizomeManifest="HTTP RESTful fetch Rhizome manifest"
|
||||
@ -258,10 +258,32 @@ test_RhizomeManifest() {
|
||||
done
|
||||
for n in 0 1 2; do
|
||||
assert diff file$n.manifest bundle$n.rhm
|
||||
assert_http_response_headers $n
|
||||
assert_http_response_headers http.headers$n
|
||||
done
|
||||
}
|
||||
|
||||
doc_RhizomeManifestNonexist="HTTP RESTful fetch non-existent Rhizome manifest"
|
||||
setup_RhizomeManifestNonexist() {
|
||||
setup
|
||||
}
|
||||
test_RhizomeManifestNonexist() {
|
||||
executeOk curl \
|
||||
--silent --show-error --write-out '%{http_code}' \
|
||||
--output http.content \
|
||||
--dump-header http.headers \
|
||||
--basic --user harry:potter \
|
||||
"http://$addr_localhost:$PORTA/restful/rhizome/$BID_NONEXISTENT.rhm"
|
||||
tfw_cat http.headers http.content
|
||||
assertStdoutIs 404
|
||||
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({"rhizome_bundle_status_code": 0})'
|
||||
assertJqGrep --ignore-case http.content '.rhizome_bundle_status_message' "bundle new to store"
|
||||
}
|
||||
|
||||
doc_RhizomePayloadRaw="HTTP RESTful fetch Rhizome raw payload"
|
||||
setup_RhizomePayloadRaw() {
|
||||
setup
|
||||
@ -280,10 +302,65 @@ test_RhizomePayloadRaw() {
|
||||
done
|
||||
for n in 0 1 2 3; do
|
||||
assert cmp raw$n raw.bin$n
|
||||
assert_http_response_headers $n
|
||||
assertGrep --matches=1 --ignore-case http.headers$n "^Serval-Rhizome-Result-Bundle-Status-Code: 1$CR\$"
|
||||
assertGrep --matches=1 --ignore-case http.headers$n "^Serval-Rhizome-Result-Bundle-Status-Message: .*bundle already in store.*$CR\$"
|
||||
assertGrep --matches=1 --ignore-case http.headers$n "^Serval-Rhizome-Result-Payload-Status-Code: 2$CR\$"
|
||||
assertGrep --matches=1 --ignore-case http.headers$n "^Serval-Rhizome-Result-Payload-Status-Message: .*payload already in store.*$CR\$"
|
||||
assert_http_response_headers http.headers$n
|
||||
done
|
||||
}
|
||||
|
||||
doc_RhizomePayloadRawNonexistManifest="HTTP RESTful fetch Rhizome raw payload for non-existent manifest"
|
||||
setup_RhizomePayloadRawNonexistManifest() {
|
||||
setup
|
||||
}
|
||||
test_RhizomePayloadRawNonexistManifest() {
|
||||
executeOk curl \
|
||||
--silent --show-error --write-out '%{http_code}' \
|
||||
--output http.content \
|
||||
--dump-header http.headers \
|
||||
--basic --user harry:potter \
|
||||
"http://$addr_localhost:$PORTA/restful/rhizome/$BID_NONEXISTENT/raw.bin"
|
||||
tfw_cat http.headers http.content
|
||||
assertStdoutIs 404
|
||||
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({"rhizome_bundle_status_code": 0})'
|
||||
assertJqGrep --ignore-case http.content '.rhizome_bundle_status_message' "bundle new to store"
|
||||
}
|
||||
|
||||
doc_RhizomePayloadRawNonexistPayload="HTTP RESTful fetch non-existent Rhizome raw payload"
|
||||
setup_RhizomePayloadRawNonexistPayload() {
|
||||
set_extra_config() {
|
||||
executeOk_servald config set rhizome.max_blob_size 0
|
||||
}
|
||||
setup
|
||||
rhizome_add_bundles $SIDA 0 0
|
||||
rhizome_delete_payload_blobs "${HASH[0]}"
|
||||
}
|
||||
test_RhizomePayloadRawNonexistPayload() {
|
||||
executeOk curl \
|
||||
--silent --show-error --write-out '%{http_code}' \
|
||||
--output http.content \
|
||||
--dump-header http.headers \
|
||||
--basic --user harry:potter \
|
||||
"http://$addr_localhost:$PORTA/restful/rhizome/${BID[0]}/raw.bin"
|
||||
tfw_cat http.headers http.content
|
||||
assertStdoutIs 403
|
||||
assertGrep --matches=1 --ignore-case http.headers$n "^Serval-Rhizome-Result-Bundle-Status-Code: 1$CR\$"
|
||||
assertGrep --matches=1 --ignore-case http.headers$n "^Serval-Rhizome-Result-Bundle-Status-Message: .*bundle already in store.*$CR\$"
|
||||
assertGrep --matches=1 --ignore-case http.headers$n "^Serval-Rhizome-Result-Payload-Status-Code: 1$CR\$"
|
||||
assertGrep --matches=1 --ignore-case http.headers$n "^Serval-Rhizome-Result-Payload-Status-Message: .*payload new to store.*$CR\$"
|
||||
assertJq http.content 'contains({"http_status_code": 403})'
|
||||
assertJq http.content 'contains({"rhizome_bundle_status_code": 1})'
|
||||
assertJqGrep --ignore-case http.content '.rhizome_bundle_status_message' "bundle already in store"
|
||||
assertJq http.content 'contains({"rhizome_payload_status_code": 1})'
|
||||
assertJqGrep --ignore-case http.content '.rhizome_payload_status_message' "payload new to store"
|
||||
}
|
||||
|
||||
doc_RhizomePayloadDecrypted="HTTP RESTful fetch Rhizome decrypted payload"
|
||||
setup_RhizomePayloadDecrypted() {
|
||||
setup
|
||||
@ -302,10 +379,91 @@ test_RhizomePayloadDecrypted() {
|
||||
done
|
||||
for n in 0 1 2 3; do
|
||||
assert cmp file$n decrypted.bin$n
|
||||
assert_http_response_headers $n
|
||||
assertGrep --matches=1 --ignore-case http.headers$n "^Serval-Rhizome-Result-Bundle-Status-Code: 1$CR\$"
|
||||
assertGrep --matches=1 --ignore-case http.headers$n "^Serval-Rhizome-Result-Bundle-Status-Message: .*bundle already in store.*$CR\$"
|
||||
assertGrep --matches=1 --ignore-case http.headers$n "^Serval-Rhizome-Result-Payload-Status-Code: 2$CR\$"
|
||||
assertGrep --matches=1 --ignore-case http.headers$n "^Serval-Rhizome-Result-Payload-Status-Message: .*payload already in store.*$CR\$"
|
||||
assert_http_response_headers http.headers$n
|
||||
done
|
||||
}
|
||||
|
||||
doc_RhizomePayloadDecryptedForeign="HTTP RESTful cannot fetch foreign Rhizome decrypted payload"
|
||||
setup_RhizomePayloadDecryptedForeign() {
|
||||
setup
|
||||
rhizome_add_bundles --encrypted $SIDA 0 0
|
||||
set_instance +B
|
||||
create_single_identity
|
||||
rhizome_add_bundles --encrypted $SIDB 1 1
|
||||
executeOk_servald rhizome export manifest "${BID[1]}" file1.manifest
|
||||
set_instance +A
|
||||
executeOk_servald rhizome import bundle raw1 file1.manifest
|
||||
}
|
||||
test_RhizomePayloadDecryptedForeign() {
|
||||
executeOk curl \
|
||||
--silent --show-error --write-out '%{http_code}' \
|
||||
--output decrypted.bin$n \
|
||||
--dump-header http.headers$n \
|
||||
--basic --user harry:potter \
|
||||
"http://$addr_localhost:$PORTA/restful/rhizome/${BID[1]}/decrypted.bin"
|
||||
tfw_cat http.headers$n decrypted.bin$n
|
||||
assertStdoutIs 403
|
||||
assertGrep --matches=1 --ignore-case http.headers$n "^Serval-Rhizome-Result-Bundle-Status-Code: 1$CR\$"
|
||||
assertGrep --matches=1 --ignore-case http.headers$n "^Serval-Rhizome-Result-Bundle-Status-Message: .*bundle already in store.*$CR\$"
|
||||
assertGrep --matches=1 --ignore-case http.headers$n "^Serval-Rhizome-Result-Payload-Status-Code: 5$CR\$"
|
||||
assertGrep --matches=1 --ignore-case http.headers$n "^Serval-Rhizome-Result-Payload-Status-Message: .*incorrect bundle secret*$CR\$"
|
||||
}
|
||||
|
||||
doc_RhizomePayloadDecryptedNonexistManifest="HTTP RESTful fetch Rhizome decrypted payload for non-existent manifest"
|
||||
setup_RhizomePayloadDecryptedNonexistManifest() {
|
||||
setup
|
||||
}
|
||||
test_RhizomePayloadDecryptedNonexistManifest() {
|
||||
executeOk curl \
|
||||
--silent --show-error --write-out '%{http_code}' \
|
||||
--output http.content \
|
||||
--dump-header http.headers \
|
||||
--basic --user harry:potter \
|
||||
"http://$addr_localhost:$PORTA/restful/rhizome/$BID_NONEXISTENT/decrypted.bin"
|
||||
tfw_cat http.headers http.content
|
||||
assertStdoutIs 404
|
||||
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({"rhizome_bundle_status_code": 0})'
|
||||
assertJqGrep --ignore-case http.content '.rhizome_bundle_status_message' "bundle new to store"
|
||||
}
|
||||
|
||||
doc_RhizomePayloadDecryptedNonexistPayload="HTTP RESTful fetch non-existent Rhizome decrypted payload"
|
||||
setup_RhizomePayloadDecryptedNonexistPayload() {
|
||||
set_extra_config() {
|
||||
executeOk_servald config set rhizome.max_blob_size 0
|
||||
}
|
||||
setup
|
||||
rhizome_add_bundles $SIDA 0 0
|
||||
rhizome_delete_payload_blobs "${HASH[0]}"
|
||||
}
|
||||
test_RhizomePayloadDecryptedNonexistPayload() {
|
||||
executeOk curl \
|
||||
--silent --show-error --write-out '%{http_code}' \
|
||||
--output http.content \
|
||||
--dump-header http.headers \
|
||||
--basic --user harry:potter \
|
||||
"http://$addr_localhost:$PORTA/restful/rhizome/${BID[0]}/decrypted.bin"
|
||||
tfw_cat http.headers http.content
|
||||
assertStdoutIs 403
|
||||
assertGrep --matches=1 --ignore-case http.headers$n "^Serval-Rhizome-Result-Bundle-Status-Code: 1$CR\$"
|
||||
assertGrep --matches=1 --ignore-case http.headers$n "^Serval-Rhizome-Result-Bundle-Status-Message: .*bundle already in store.*$CR\$"
|
||||
assertGrep --matches=1 --ignore-case http.headers$n "^Serval-Rhizome-Result-Payload-Status-Code: 1$CR\$"
|
||||
assertGrep --matches=1 --ignore-case http.headers$n "^Serval-Rhizome-Result-Payload-Status-Message: .*payload new to store.*$CR\$"
|
||||
assertJq http.content 'contains({"http_status_code": 403})'
|
||||
assertJq http.content 'contains({"rhizome_bundle_status_code": 1})'
|
||||
assertJqGrep --ignore-case http.content '.rhizome_bundle_status_message' "bundle already in store"
|
||||
assertJq http.content 'contains({"rhizome_payload_status_code": 1})'
|
||||
assertJqGrep --ignore-case http.content '.rhizome_payload_status_message' "payload new to store"
|
||||
}
|
||||
|
||||
extract_http_header() {
|
||||
local __var="$1"
|
||||
local __headerfile="$2"
|
||||
@ -419,15 +577,19 @@ test_RhizomeInsert() {
|
||||
execute curl \
|
||||
--silent --show-error --write-out '%{http_code}' \
|
||||
--output nfile$n.manifest \
|
||||
--dump-header http.header$n \
|
||||
--dump-header http.headers$n \
|
||||
--basic --user harry:potter \
|
||||
--form "manifest=@nmanifest$n;type=rhizome-manifest/text" \
|
||||
--form "payload=@nfile$n;filename=\"nfile$n\"" \
|
||||
"http://$addr_localhost:$PORTA/restful/rhizome/insert"
|
||||
tfw_cat http.header$n nfile$n.manifest
|
||||
tfw_cat http.headers$n nfile$n.manifest
|
||||
assertExitStatus == 0
|
||||
if [ -n "${author[$n]}" ]; then
|
||||
assertStdoutIs 201
|
||||
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=1 --ignore-case http.headers$n "^Serval-Rhizome-Result-Payload-Status-Code: 1$CR\$"
|
||||
assertGrep --matches=1 --ignore-case http.headers$n "^Serval-Rhizome-Result-Payload-Status-Message: .*payload new to store.*$CR\$"
|
||||
else
|
||||
assertStdoutIs 403
|
||||
assertJq nfile$n.manifest 'contains({"http_status_code": 403})'
|
||||
@ -460,6 +622,10 @@ test_RhizomeInsertAnon() {
|
||||
tfw_cat http.header ifile2.manifest
|
||||
assertExitStatus == 0
|
||||
assertStdoutIs 201
|
||||
assertGrep --matches=1 --ignore-case http.header "^Serval-Rhizome-Result-Bundle-Status-Code: 0$CR\$"
|
||||
assertGrep --matches=1 --ignore-case http.header "^Serval-Rhizome-Result-Bundle-Status-Message: .*bundle new to store.*$CR\$"
|
||||
assertGrep --matches=1 --ignore-case http.header "^Serval-Rhizome-Result-Payload-Status-Code: 1$CR\$"
|
||||
assertGrep --matches=1 --ignore-case http.header "^Serval-Rhizome-Result-Payload-Status-Message: .*payload new to store.*$CR\$"
|
||||
executeOk_servald rhizome list
|
||||
assert_rhizome_list --fromhere=0 --manifest=ifile2.manifest file2
|
||||
}
|
||||
@ -482,6 +648,10 @@ test_RhizomeInsertEmpty() {
|
||||
tfw_cat http.header empty.manifest
|
||||
assertExitStatus == 0
|
||||
assertStdoutIs 201
|
||||
assertGrep --matches=1 --ignore-case http.header "^Serval-Rhizome-Result-Bundle-Status-Code: 0$CR\$"
|
||||
assertGrep --matches=1 --ignore-case http.header "^Serval-Rhizome-Result-Bundle-Status-Message: .*bundle new to store.*$CR\$"
|
||||
assertGrep --matches=1 --ignore-case http.header "^Serval-Rhizome-Result-Payload-Status-Code: 1$CR\$"
|
||||
assertGrep --matches=1 --ignore-case http.header "^Serval-Rhizome-Result-Payload-Status-Message: .*payload new to store.*$CR\$"
|
||||
extract_manifest_id BID empty.manifest
|
||||
executeOk_servald rhizome list
|
||||
assert_rhizome_list empty
|
||||
@ -504,9 +674,13 @@ test_RhizomeInsertLarge() {
|
||||
--form "manifest=;type=rhizome-manifest/text" \
|
||||
--form "payload=@file1" \
|
||||
"http://$addr_localhost:$PORTA/restful/rhizome/insert"
|
||||
tfw_cat http.header file1.manifest
|
||||
tfw_cat http.header -v file1.manifest
|
||||
assertExitStatus == 0
|
||||
assertStdoutIs 201
|
||||
assertGrep --matches=1 --ignore-case http.header "^Serval-Rhizome-Result-Bundle-Status-Code: 0$CR\$"
|
||||
assertGrep --matches=1 --ignore-case http.header "^Serval-Rhizome-Result-Bundle-Status-Message: .*bundle new to store.*$CR\$"
|
||||
assertGrep --matches=1 --ignore-case http.header "^Serval-Rhizome-Result-Payload-Status-Code: 1$CR\$"
|
||||
assertGrep --matches=1 --ignore-case http.header "^Serval-Rhizome-Result-Payload-Status-Message: .*payload new to store.*$CR\$"
|
||||
extract_manifest_id BID file1.manifest
|
||||
executeOk_servald rhizome list
|
||||
assert_rhizome_list file1
|
||||
@ -730,7 +904,8 @@ test_RhizomeInsertIncorrectFilesize() {
|
||||
assertExitStatus == 0
|
||||
assertStdoutIs 403
|
||||
assertJq http.body 'contains({"http_status_code": 403})'
|
||||
assertJqGrep --ignore-case http.body '.http_status_message' 'payload size.*contradicts manifest'
|
||||
assertJq http.body 'contains({"rhizome_payload_status_code": 3})'
|
||||
assertJqGrep --ignore-case http.body '.rhizome_payload_status_message' 'payload size.*contradicts manifest'
|
||||
execute curl \
|
||||
--silent --show-error --write-out '%{http_code}' \
|
||||
--output http.body \
|
||||
@ -742,7 +917,9 @@ test_RhizomeInsertIncorrectFilesize() {
|
||||
tfw_cat http.header http.body
|
||||
assertExitStatus == 0
|
||||
assertStdoutIs 403
|
||||
assertGrep --ignore-case http.body 'payload size.*contradicts manifest'
|
||||
assertJq http.body 'contains({"http_status_code": 403})'
|
||||
assertJq http.body 'contains({"rhizome_payload_status_code": 3})'
|
||||
assertJqGrep --ignore-case http.body '.rhizome_payload_status_message' 'payload size.*contradicts manifest'
|
||||
executeOk_servald rhizome list
|
||||
assert_rhizome_list
|
||||
}
|
||||
@ -766,7 +943,8 @@ test_RhizomeInsertIncorrectFilehash() {
|
||||
assertExitStatus == 0
|
||||
assertStdoutIs 403
|
||||
assertJq http.body 'contains({"http_status_code": 403})'
|
||||
assertJqGrep --ignore-case http.body '.http_status_message' 'payload hash.*contradicts manifest'
|
||||
assertJq http.body 'contains({"rhizome_payload_status_code": 4})'
|
||||
assertJqGrep --ignore-case http.body '.rhizome_payload_status_message' 'payload hash.*contradicts manifest'
|
||||
executeOk_servald rhizome list
|
||||
assert_rhizome_list
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user